addForm.vue 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. <template>
  2. <ContentWrap v-loading="formLoading">
  3. <el-tabs v-model="activeName">
  4. <el-tab-pane label="商品信息" name="basicInfo">
  5. <BasicInfoForm
  6. ref="basicInfoRef"
  7. v-model:activeName="activeName"
  8. :is-detail="isDetail"
  9. :propFormData="formData"
  10. />
  11. </el-tab-pane>
  12. <el-tab-pane label="商品详情" name="description">
  13. <DescriptionForm
  14. ref="descriptionRef"
  15. v-model:activeName="activeName"
  16. :is-detail="isDetail"
  17. :propFormData="formData"
  18. />
  19. </el-tab-pane>
  20. <el-tab-pane label="其他设置" name="otherSettings">
  21. <OtherSettingsForm
  22. ref="otherSettingsRef"
  23. v-model:activeName="activeName"
  24. :is-detail="isDetail"
  25. :propFormData="formData"
  26. />
  27. </el-tab-pane>
  28. </el-tabs>
  29. <el-form>
  30. <el-form-item style="float: right">
  31. <el-button :loading="formLoading" type="primary" @click="submitForm">保存</el-button>
  32. <el-button @click="close">返回</el-button>
  33. </el-form-item>
  34. </el-form>
  35. </ContentWrap>
  36. </template>
  37. <script lang="ts" name="ProductSpuForm" setup>
  38. import { cloneDeep } from 'lodash-es'
  39. import { useTagsViewStore } from '@/store/modules/tagsView'
  40. import { BasicInfoForm, DescriptionForm, OtherSettingsForm } from './components'
  41. // 业务api
  42. import * as ProductSpuApi from '@/api/mall/product/spu'
  43. import { convertToInteger, formatToFraction } from '@/utils'
  44. const { t } = useI18n() // 国际化
  45. const message = useMessage() // 消息弹窗
  46. const { push, currentRoute } = useRouter() // 路由
  47. const { params, name } = useRoute() // 查询参数
  48. const { delView } = useTagsViewStore() // 视图操作
  49. const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
  50. const activeName = ref('basicInfo') // Tag 激活的窗口
  51. const isDetail = ref(false) // 是否查看详情
  52. const basicInfoRef = ref<ComponentRef<typeof BasicInfoForm>>() // 商品信息Ref
  53. const descriptionRef = ref<ComponentRef<typeof DescriptionForm>>() // 商品详情Ref
  54. const otherSettingsRef = ref<ComponentRef<typeof OtherSettingsForm>>() // 其他设置Ref
  55. // spu 表单数据
  56. const formData = ref<ProductSpuApi.Spu>({
  57. name: '', // 商品名称
  58. categoryId: null, // 商品分类
  59. keyword: '', // 关键字
  60. unit: null, // 单位
  61. picUrl: '', // 商品封面图
  62. sliderPicUrls: [''], // 商品轮播图
  63. introduction: '', // 商品简介
  64. deliveryTemplateId: null, // 运费模版
  65. brandId: null, // 商品品牌
  66. specType: false, // 商品规格
  67. subCommissionType: false, // 分销类型
  68. skus: [
  69. {
  70. price: 0, // 商品价格
  71. marketPrice: 0, // 市场价
  72. costPrice: 0, // 成本价
  73. barCode: '', // 商品条码
  74. picUrl: '', // 图片地址
  75. stock: 0, // 库存
  76. weight: 0, // 商品重量
  77. volume: 0, // 商品体积
  78. subCommissionFirstPrice: 0, // 一级分销的佣金
  79. subCommissionSecondPrice: 0 // 二级分销的佣金
  80. }
  81. ],
  82. description: '', // 商品详情
  83. sort: 0, // 商品排序
  84. giveIntegral: 0, // 赠送积分
  85. virtualSalesCount: 0, // 虚拟销量
  86. recommendHot: false, // 是否热卖
  87. recommendBenefit: false, // 是否优惠
  88. recommendBest: false, // 是否精品
  89. recommendNew: false, // 是否新品
  90. recommendGood: false // 是否优品
  91. })
  92. /** 获得详情 */
  93. const getDetail = async () => {
  94. console.log(name)
  95. const id = params.spuId as number
  96. if (id) {
  97. formLoading.value = true
  98. try {
  99. const res = (await ProductSpuApi.getSpu(id)) as ProductSpuApi.Spu
  100. res.skus!.forEach((item) => {
  101. // 回显价格分转元
  102. item.price = formatToFraction(item.price)
  103. item.marketPrice = formatToFraction(item.marketPrice)
  104. item.costPrice = formatToFraction(item.costPrice)
  105. item.subCommissionFirstPrice = formatToFraction(item.subCommissionFirstPrice)
  106. item.subCommissionSecondPrice = formatToFraction(item.subCommissionSecondPrice)
  107. })
  108. formData.value = res
  109. } finally {
  110. formLoading.value = false
  111. }
  112. }
  113. }
  114. /** 提交按钮 */
  115. const submitForm = async () => {
  116. // 提交请求
  117. formLoading.value = true
  118. // 三个表单逐一校验,如果有一个表单校验不通过则切换到对应表单,如果有两个及以上的情况则切换到最前面的一个并弹出提示消息
  119. // 校验各表单
  120. try {
  121. await unref(basicInfoRef)?.validate()
  122. await unref(descriptionRef)?.validate()
  123. await unref(otherSettingsRef)?.validate()
  124. // 深拷贝一份, 这样最终 server 端不满足,不需要恢复,
  125. const deepCopyFormData = cloneDeep(unref(formData.value))
  126. // 兜底处理 sku 空数据
  127. formData.value.skus!.forEach((sku) => {
  128. // 因为是空数据这里判断一下商品条码是否为空就行
  129. if (sku.barCode === '') {
  130. const index = deepCopyFormData.skus.findIndex(
  131. (item) => JSON.stringify(item.properties) === JSON.stringify(sku.properties)
  132. )
  133. // 删除这条 sku
  134. deepCopyFormData.skus.splice(index, 1)
  135. }
  136. })
  137. deepCopyFormData.skus.forEach((item) => {
  138. // 给sku name赋值
  139. item.name = deepCopyFormData.name
  140. // sku相关价格元转分
  141. item.price = convertToInteger(item.price)
  142. item.marketPrice = convertToInteger(item.marketPrice)
  143. item.costPrice = convertToInteger(item.costPrice)
  144. item.subCommissionFirstPrice = convertToInteger(item.subCommissionFirstPrice)
  145. item.subCommissionSecondPrice = convertToInteger(item.subCommissionSecondPrice)
  146. })
  147. // 处理轮播图列表
  148. const newSliderPicUrls = []
  149. deepCopyFormData.sliderPicUrls.forEach((item) => {
  150. // 如果是前端选的图
  151. typeof item === 'object' ? newSliderPicUrls.push(item.url) : newSliderPicUrls.push(item)
  152. })
  153. deepCopyFormData.sliderPicUrls = newSliderPicUrls
  154. // 校验都通过后提交表单
  155. const data = deepCopyFormData as ProductSpuApi.Spu
  156. const id = params.spuId as number
  157. if (!id) {
  158. await ProductSpuApi.createSpu(data)
  159. message.success(t('common.createSuccess'))
  160. } else {
  161. await ProductSpuApi.updateSpu(data)
  162. message.success(t('common.updateSuccess'))
  163. }
  164. close()
  165. } finally {
  166. formLoading.value = false
  167. }
  168. }
  169. /** 关闭按钮 */
  170. const close = () => {
  171. delView(unref(currentRoute))
  172. push('/product/product-spu')
  173. }
  174. /** 初始化 */
  175. onMounted(async () => {
  176. await getDetail()
  177. })
  178. </script>