addForm.vue 6.5 KB

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