index.vue 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. <template>
  2. <ContentWrap v-loading="formLoading">
  3. <el-tabs v-model="activeName">
  4. <el-tab-pane label="基础设置" name="info">
  5. <InfoForm
  6. ref="infoRef"
  7. v-model:activeName="activeName"
  8. :is-detail="isDetail"
  9. :propFormData="formData"
  10. />
  11. </el-tab-pane>
  12. <el-tab-pane label="价格库存" name="sku">
  13. <SkuForm
  14. ref="skuRef"
  15. v-model:activeName="activeName"
  16. :is-detail="isDetail"
  17. :propFormData="formData"
  18. />
  19. </el-tab-pane>
  20. <el-tab-pane label="物流设置" name="delivery">
  21. <DeliveryForm
  22. ref="deliveryRef"
  23. v-model:activeName="activeName"
  24. :is-detail="isDetail"
  25. :propFormData="formData"
  26. />
  27. </el-tab-pane>
  28. <el-tab-pane label="产品详情" name="description">
  29. <DescriptionForm
  30. ref="descriptionRef"
  31. v-model:activeName="activeName"
  32. :is-detail="isDetail"
  33. :propFormData="formData"
  34. />
  35. </el-tab-pane>
  36. <el-tab-pane label="其它设置" name="other">
  37. <OtherForm
  38. ref="otherRef"
  39. v-model:activeName="activeName"
  40. :is-detail="isDetail"
  41. :propFormData="formData"
  42. />
  43. </el-tab-pane>
  44. </el-tabs>
  45. <el-form>
  46. <el-form-item style="float: right">
  47. <el-button v-if="!isDetail" :loading="formLoading" type="primary" @click="submitForm">
  48. 保存
  49. </el-button>
  50. <el-button @click="close">返回</el-button>
  51. </el-form-item>
  52. </el-form>
  53. </ContentWrap>
  54. </template>
  55. <script lang="ts" setup>
  56. import { cloneDeep } from 'lodash-es'
  57. import { useTagsViewStore } from '@/store/modules/tagsView'
  58. import * as ProductSpuApi from '@/api/mall/product/spu'
  59. import InfoForm from './InfoForm.vue'
  60. import DescriptionForm from './DescriptionForm.vue'
  61. import OtherForm from './OtherForm.vue'
  62. import SkuForm from './SkuForm.vue'
  63. import DeliveryForm from './DeliveryForm.vue'
  64. import { convertToInteger, floatToFixed2, formatToFraction } from '@/utils'
  65. defineOptions({ name: 'ProductSpuAdd' })
  66. const { t } = useI18n() // 国际化
  67. const message = useMessage() // 消息弹窗
  68. const { push, currentRoute } = useRouter() // 路由
  69. const { params, name } = useRoute() // 查询参数
  70. const { delView } = useTagsViewStore() // 视图操作
  71. const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
  72. const activeName = ref('info') // Tag 激活的窗口
  73. const isDetail = ref(false) // 是否查看详情
  74. const infoRef = ref() // 产品信息 Ref
  75. const skuRef = ref() // 产品规格 Ref
  76. const deliveryRef = ref() // 物流设置 Ref
  77. const descriptionRef = ref() // 产品详情 Ref
  78. const otherRef = ref() // 其他设置 Ref
  79. // SPU 表单数据
  80. const formData = ref<ProductSpuApi.Spu>({
  81. name: '', // 产品名称
  82. categoryId: undefined, // 产品分类
  83. keyword: '', // 关键字
  84. picUrl: '', // 产品封面图
  85. sliderPicUrls: [], // 产品轮播图
  86. introduction: '', // 产品简介
  87. deliveryTypes: [], // 配送方式数组
  88. deliveryTemplateId: undefined, // 运费模版
  89. brandId: undefined, // 产品品牌
  90. specType: false, // 产品规格
  91. subCommissionType: false, // 分销类型
  92. skus: [
  93. {
  94. price: 0, // 产品价格
  95. marketPrice: 0, // 市场价
  96. costPrice: 0, // 成本价
  97. barCode: '', // 产品条码
  98. picUrl: '', // 图片地址
  99. stock: 0, // 库存
  100. weight: 0, // 产品重量
  101. volume: 0, // 产品体积
  102. firstBrokeragePrice: 0, // 一级分销的佣金
  103. secondBrokeragePrice: 0 // 二级分销的佣金
  104. }
  105. ],
  106. description: '', // 产品详情
  107. sort: 0, // 产品排序
  108. giveIntegral: 0, // 赠送积分
  109. virtualSalesCount: 0 // 虚拟销量
  110. })
  111. /** 获得详情 */
  112. const getDetail = async () => {
  113. if ('ProductSpuDetail' === name) {
  114. isDetail.value = true
  115. }
  116. const id = params.id as unknown as number
  117. if (id) {
  118. formLoading.value = true
  119. try {
  120. const res = (await ProductSpuApi.getSpu(id)) as ProductSpuApi.Spu
  121. res.skus?.forEach((item) => {
  122. if (isDetail.value) {
  123. item.price = floatToFixed2(item.price)
  124. item.marketPrice = floatToFixed2(item.marketPrice)
  125. item.costPrice = floatToFixed2(item.costPrice)
  126. item.firstBrokeragePrice = floatToFixed2(item.firstBrokeragePrice)
  127. item.secondBrokeragePrice = floatToFixed2(item.secondBrokeragePrice)
  128. } else {
  129. // 回显价格分转元
  130. item.price = formatToFraction(item.price)
  131. item.marketPrice = formatToFraction(item.marketPrice)
  132. item.costPrice = formatToFraction(item.costPrice)
  133. item.firstBrokeragePrice = formatToFraction(item.firstBrokeragePrice)
  134. item.secondBrokeragePrice = formatToFraction(item.secondBrokeragePrice)
  135. }
  136. })
  137. formData.value = res
  138. } finally {
  139. formLoading.value = false
  140. }
  141. }
  142. }
  143. /** 提交按钮 */
  144. const submitForm = async () => {
  145. // 提交请求
  146. formLoading.value = true
  147. try {
  148. // 校验各表单
  149. await unref(infoRef)?.validate()
  150. await unref(skuRef)?.validate()
  151. await unref(deliveryRef)?.validate()
  152. await unref(descriptionRef)?.validate()
  153. await unref(otherRef)?.validate()
  154. // 深拷贝一份, 这样最终 server 端不满足,不需要影响原始数据
  155. const deepCopyFormData = cloneDeep(unref(formData.value)) as ProductSpuApi.Spu
  156. deepCopyFormData.skus!.forEach((item) => {
  157. // 给sku name赋值
  158. item.name = deepCopyFormData.name
  159. // sku相关价格元转分
  160. item.price = convertToInteger(item.price)
  161. item.marketPrice = convertToInteger(item.marketPrice)
  162. item.costPrice = convertToInteger(item.costPrice)
  163. item.firstBrokeragePrice = convertToInteger(item.firstBrokeragePrice)
  164. item.secondBrokeragePrice = convertToInteger(item.secondBrokeragePrice)
  165. })
  166. // 处理轮播图列表
  167. const newSliderPicUrls: any[] = []
  168. deepCopyFormData.sliderPicUrls!.forEach((item: any) => {
  169. // 如果是前端选的图
  170. typeof item === 'object' ? newSliderPicUrls.push(item.url) : newSliderPicUrls.push(item)
  171. })
  172. deepCopyFormData.sliderPicUrls = newSliderPicUrls
  173. // 校验都通过后提交表单
  174. const data = deepCopyFormData as ProductSpuApi.Spu
  175. const id = params.id as unknown as number
  176. if (!id) {
  177. await ProductSpuApi.createSpu(data)
  178. message.success(t('common.createSuccess'))
  179. } else {
  180. await ProductSpuApi.updateSpu(data)
  181. message.success(t('common.updateSuccess'))
  182. }
  183. close()
  184. } finally {
  185. formLoading.value = false
  186. }
  187. }
  188. /** 关闭按钮 */
  189. const close = () => {
  190. delView(unref(currentRoute))
  191. push({ name: 'ProductSpu' })
  192. }
  193. /** 初始化 */
  194. onMounted(async () => {
  195. await getDetail()
  196. })
  197. </script>