BargainActivityForm.vue 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. <template>
  2. <Dialog v-model="dialogVisible" :title="dialogTitle" width="65%">
  3. <Form
  4. ref="formRef"
  5. v-loading="formLoading"
  6. :is-col="true"
  7. :rules="rules"
  8. :schema="allSchemas.formSchema"
  9. class="mt-10px"
  10. >
  11. <template #spuId>
  12. <el-button @click="spuSelectRef.open()">选择商品</el-button>
  13. <SpuAndSkuList
  14. ref="spuAndSkuListRef"
  15. :rule-config="ruleConfig"
  16. :spu-list="spuList"
  17. :spu-property-list-p="spuPropertyList"
  18. >
  19. <el-table-column align="center" label="砍价起始价格(元)" min-width="168">
  20. <template #default="{ row: sku }">
  21. <el-input-number
  22. v-model="sku.productConfig.bargainFirstPrice"
  23. :min="0"
  24. :precision="2"
  25. :step="0.1"
  26. class="w-100%"
  27. />
  28. </template>
  29. </el-table-column>
  30. <el-table-column align="center" label="砍价底价(元)" min-width="168">
  31. <template #default="{ row: sku }">
  32. <el-input-number
  33. v-model="sku.productConfig.bargainPrice"
  34. :min="0"
  35. :precision="2"
  36. :step="0.1"
  37. class="w-100%"
  38. />
  39. </template>
  40. </el-table-column>
  41. <el-table-column align="center" label="活动库存" min-width="168">
  42. <template #default="{ row: sku }">
  43. <el-input-number v-model="sku.productConfig.stock" class="w-100%" />
  44. </template>
  45. </el-table-column>
  46. </SpuAndSkuList>
  47. </template>
  48. </Form>
  49. <template #footer>
  50. <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
  51. <el-button @click="dialogVisible = false">取 消</el-button>
  52. </template>
  53. </Dialog>
  54. <SpuSelect ref="spuSelectRef" :isSelectSku="true" :radio="true" @confirm="selectSpu" />
  55. </template>
  56. <script lang="ts" setup>
  57. import * as BargainActivityApi from '@/api/mall/promotion/bargain/bargainActivity'
  58. import { BargainProductVO } from '@/api/mall/promotion/bargain/bargainActivity'
  59. import { allSchemas, rules } from './bargainActivity.data'
  60. import { SpuAndSkuList, SpuProperty, SpuSelect } from '@/views/mall/promotion/components'
  61. import { getPropertyList, RuleConfig } from '@/views/mall/product/spu/components'
  62. import * as ProductSpuApi from '@/api/mall/product/spu'
  63. import { convertToInteger, formatToFraction } from '@/utils'
  64. defineOptions({ name: 'PromotionBargainActivityForm' })
  65. const { t } = useI18n() // 国际化
  66. const message = useMessage() // 消息弹窗
  67. const dialogVisible = ref(false) // 弹窗的是否展示
  68. const dialogTitle = ref('') // 弹窗的标题
  69. const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
  70. const formType = ref('') // 表单的类型:create - 新增;update - 修改
  71. const formRef = ref() // 表单 Ref
  72. // ================= 商品选择相关 =================
  73. const spuSelectRef = ref() // 商品和属性选择 Ref
  74. const spuAndSkuListRef = ref() // sku 秒杀配置组件Ref
  75. const spuList = ref<BargainActivityApi.SpuExtension[]>([]) // 选择的 spu
  76. const spuPropertyList = ref<SpuProperty<BargainActivityApi.SpuExtension>[]>([])
  77. const ruleConfig: RuleConfig[] = [
  78. {
  79. name: 'productConfig.bargainFirstPrice',
  80. rule: (arg) => arg > 0,
  81. message: '商品砍价起始价格不能小于 0 !!!'
  82. },
  83. {
  84. name: 'productConfig.bargainPrice',
  85. rule: (arg) => arg >= 0,
  86. message: '商品砍价底价不能小于 0 !!!'
  87. },
  88. {
  89. name: 'productConfig.stock',
  90. rule: (arg) => arg >= 1,
  91. message: '商品活动库存不能小于 1 !!!'
  92. }
  93. ]
  94. const selectSpu = (spuId: number, skuIds: number[]) => {
  95. formRef.value.setValues({ spuId })
  96. getSpuDetails(spuId, skuIds)
  97. }
  98. /**
  99. * 获取 SPU 详情
  100. */
  101. const getSpuDetails = async (
  102. spuId: number,
  103. skuIds: number[] | undefined,
  104. products?: BargainProductVO[]
  105. ) => {
  106. const spuProperties: SpuProperty<BargainActivityApi.SpuExtension>[] = []
  107. const res = (await ProductSpuApi.getSpuDetailList([spuId])) as BargainActivityApi.SpuExtension[]
  108. if (res.length == 0) {
  109. return
  110. }
  111. spuList.value = []
  112. // 因为只能选择一个
  113. const spu = res[0]
  114. const selectSkus =
  115. typeof skuIds === 'undefined' ? spu?.skus : spu?.skus?.filter((sku) => skuIds.includes(sku.id!))
  116. selectSkus?.forEach((sku) => {
  117. let config: BargainProductVO = {
  118. spuId: spu.id!,
  119. skuId: sku.id!,
  120. bargainFirstPrice: 1,
  121. bargainPrice: 1,
  122. stock: 1
  123. }
  124. if (typeof products !== 'undefined') {
  125. const product = products.find((item) => item.skuId === sku.id)
  126. if (product) {
  127. product.bargainFirstPrice = formatToFraction(product.bargainFirstPrice)
  128. product.bargainPrice = formatToFraction(product.bargainPrice)
  129. }
  130. config = product || config
  131. }
  132. sku.productConfig = config
  133. })
  134. spu.skus = selectSkus as BargainActivityApi.SkuExtension[]
  135. spuProperties.push({
  136. spuId: spu.id!,
  137. spuDetail: spu,
  138. propertyList: getPropertyList(spu)
  139. })
  140. spuList.value.push(spu)
  141. spuPropertyList.value = spuProperties
  142. }
  143. // ================= end =================
  144. /** 打开弹窗 */
  145. const open = async (type: string, id?: number) => {
  146. dialogVisible.value = true
  147. dialogTitle.value = t('action.' + type)
  148. formType.value = type
  149. await resetForm()
  150. // 修改时,设置数据
  151. if (id) {
  152. formLoading.value = true
  153. try {
  154. const data = (await BargainActivityApi.getBargainActivity(
  155. id
  156. )) as BargainActivityApi.BargainActivityVO
  157. // 用户每次砍价金额分转元, 分转元
  158. data.randomMinPrice = formatToFraction(data.randomMinPrice)
  159. data.randomMaxPrice = formatToFraction(data.randomMaxPrice)
  160. // 对齐活动商品处理结构
  161. await getSpuDetails(
  162. data.spuId!,
  163. [data.skuId],
  164. [
  165. {
  166. spuId: data.spuId!,
  167. skuId: data.skuId,
  168. bargainFirstPrice: data.bargainFirstPrice, // 砍价起始价格,单位分
  169. bargainPrice: data.bargainPrice, // 砍价底价
  170. stock: data.stock // 活动库存
  171. }
  172. ]
  173. )
  174. formRef.value.setValues(data)
  175. } finally {
  176. formLoading.value = false
  177. }
  178. }
  179. }
  180. defineExpose({ open }) // 提供 open 方法,用于打开弹窗
  181. /** 重置表单 */
  182. const resetForm = async () => {
  183. spuList.value = []
  184. spuPropertyList.value = []
  185. await nextTick()
  186. formRef.value.getElFormRef().resetFields()
  187. }
  188. /** 提交表单 */
  189. const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
  190. const submitForm = async () => {
  191. // 校验表单
  192. if (!formRef) return
  193. const valid = await formRef.value.getElFormRef().validate()
  194. if (!valid) return
  195. // 提交请求
  196. formLoading.value = true
  197. try {
  198. const data = formRef.value.formModel as BargainActivityApi.BargainActivityVO
  199. const products = spuAndSkuListRef.value.getSkuConfigs('productConfig')
  200. products.forEach((item: BargainProductVO) => {
  201. // 砍价价格元转分
  202. item.bargainFirstPrice = convertToInteger(item.bargainFirstPrice)
  203. item.bargainPrice = convertToInteger(item.bargainPrice)
  204. })
  205. // 用户每次砍价金额分转元, 元转分
  206. data.randomMinPrice = convertToInteger(data.randomMinPrice)
  207. data.randomMaxPrice = convertToInteger(data.randomMaxPrice)
  208. const formData = { ...data, ...products[0] }
  209. if (formType.value === 'create') {
  210. await BargainActivityApi.createBargainActivity(formData)
  211. message.success(t('common.createSuccess'))
  212. } else {
  213. await BargainActivityApi.updateBargainActivity(formData)
  214. message.success(t('common.updateSuccess'))
  215. }
  216. dialogVisible.value = false
  217. // 发送操作成功的事件
  218. emit('success')
  219. } finally {
  220. formLoading.value = false
  221. }
  222. }
  223. </script>