mirror of
				https://gitee.com/hhyykk/ipms-sjy-ui.git
				synced 2025-11-04 04:08:44 +08:00 
			
		
		
		
	fix:解决商品上一版遗留的各种小bug关键部分已添加fix注释。完成的TODO也已添加fix标记
This commit is contained in:
		@@ -54,3 +54,8 @@ export const getBrand = (id: number) => {
 | 
			
		||||
export const getBrandParam = (params: PageParam) => {
 | 
			
		||||
  return request.get({ url: '/product/brand/page', params })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 获得商品品牌精简信息列表
 | 
			
		||||
export const getSimpleBrandList = () => {
 | 
			
		||||
  return request.get({ url: '/product/brand/list-all-simple' })
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,7 @@ export interface SpuType {
 | 
			
		||||
  sliderPicUrls?: string[] // 商品轮播图
 | 
			
		||||
  introduction?: string // 商品简介
 | 
			
		||||
  deliveryTemplateId?: number | null // 运费模版
 | 
			
		||||
  brandId?: number | null // 商品品牌编号
 | 
			
		||||
  specType?: boolean // 商品规格
 | 
			
		||||
  subCommissionType?: boolean // 分销类型
 | 
			
		||||
  skus: SkuType[] // sku数组
 | 
			
		||||
 
 | 
			
		||||
@@ -173,3 +173,24 @@ export const copyValueToTarget = (target, source) => {
 | 
			
		||||
  // 更新目标对象值
 | 
			
		||||
  Object.assign(target, newObj)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 将一个整数转换为分数保留两位小数
 | 
			
		||||
 * @param num
 | 
			
		||||
 */
 | 
			
		||||
export const formatToFraction = (num: number | string | undefined): number => {
 | 
			
		||||
  if (typeof num === 'undefined') return 0
 | 
			
		||||
  const parsedNumber = typeof num === 'string' ? parseFloat(num) : num
 | 
			
		||||
  return parseFloat((parsedNumber / 100).toFixed(2))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 将一个分数转换为整数
 | 
			
		||||
 * @param num
 | 
			
		||||
 */
 | 
			
		||||
export const convertToInteger = (num: number | string | undefined): number => {
 | 
			
		||||
  if (typeof num === 'undefined') return 0
 | 
			
		||||
  const parsedNumber = typeof num === 'string' ? parseFloat(num) : num
 | 
			
		||||
  // TODO 分转元后还有小数则四舍五入
 | 
			
		||||
  return Math.round(parsedNumber * 100)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -38,6 +38,7 @@ import { BasicInfoForm, DescriptionForm, OtherSettingsForm } from './components'
 | 
			
		||||
// 业务api
 | 
			
		||||
import * as ProductSpuApi from '@/api/mall/product/spu'
 | 
			
		||||
import * as PropertyApi from '@/api/mall/product/property'
 | 
			
		||||
import { convertToInteger, formatToFraction } from '@/utils'
 | 
			
		||||
 | 
			
		||||
const { t } = useI18n() // 国际化
 | 
			
		||||
const message = useMessage() // 消息弹窗
 | 
			
		||||
@@ -60,6 +61,7 @@ const formData = ref<ProductSpuApi.SpuType>({
 | 
			
		||||
  sliderPicUrls: [], // 商品轮播图
 | 
			
		||||
  introduction: '', // 商品简介
 | 
			
		||||
  deliveryTemplateId: 1, // 运费模版
 | 
			
		||||
  brandId: null, // 商品品牌
 | 
			
		||||
  specType: false, // 商品规格
 | 
			
		||||
  subCommissionType: false, // 分销类型
 | 
			
		||||
  skus: [
 | 
			
		||||
@@ -94,14 +96,34 @@ const getDetail = async () => {
 | 
			
		||||
    formLoading.value = true
 | 
			
		||||
    try {
 | 
			
		||||
      const res = (await ProductSpuApi.getSpu(id)) as ProductSpuApi.SpuType
 | 
			
		||||
      res.skus.forEach((item) => {
 | 
			
		||||
        // 回显价格分转元
 | 
			
		||||
        item.price = formatToFraction(item.price)
 | 
			
		||||
        item.marketPrice = formatToFraction(item.marketPrice)
 | 
			
		||||
        item.costPrice = formatToFraction(item.costPrice)
 | 
			
		||||
        item.subCommissionFirstPrice = formatToFraction(item.subCommissionFirstPrice)
 | 
			
		||||
        item.subCommissionSecondPrice = formatToFraction(item.subCommissionSecondPrice)
 | 
			
		||||
      })
 | 
			
		||||
      formData.value = res
 | 
			
		||||
      // 直接取第一个值就能得到所有属性的id
 | 
			
		||||
      // TODO @puhui999:可以直接拿 propertyName 拼接处规格 id + 属性,可以看下商品 uniapp 详情的做法
 | 
			
		||||
      const propertyIds = res.skus[0]?.properties.map((item) => item.propertyId)
 | 
			
		||||
      const PropertyS = await PropertyApi.getPropertyListAndValue({ propertyIds })
 | 
			
		||||
      await nextTick()
 | 
			
		||||
      // 回显商品属性
 | 
			
		||||
      basicInfoRef.value.addAttribute(PropertyS)
 | 
			
		||||
      // 只有是多规格才处理
 | 
			
		||||
      if (res.specType) {
 | 
			
		||||
        // TODO @puhui999:可以直接拿 propertyName 拼接处规格 id + 属性,可以看下商品 uniapp 详情的做法
 | 
			
		||||
        // fix: 考虑到 sku 数量和通过属性算出来的sku不一致的情况
 | 
			
		||||
        const propertyIds = []
 | 
			
		||||
        res.skus.forEach((sku) =>
 | 
			
		||||
          sku.properties
 | 
			
		||||
            ?.map((property) => property.propertyId)
 | 
			
		||||
            .forEach((propertyId) => {
 | 
			
		||||
              if (propertyIds.indexOf(propertyId) === -1) {
 | 
			
		||||
                propertyIds.push(propertyId)
 | 
			
		||||
              }
 | 
			
		||||
            })
 | 
			
		||||
        )
 | 
			
		||||
        const properties = await PropertyApi.getPropertyListAndValue({ propertyIds })
 | 
			
		||||
        await nextTick()
 | 
			
		||||
        // 回显商品属性
 | 
			
		||||
        basicInfoRef.value.addAttribute(properties)
 | 
			
		||||
      }
 | 
			
		||||
    } finally {
 | 
			
		||||
      formLoading.value = false
 | 
			
		||||
    }
 | 
			
		||||
@@ -119,10 +141,26 @@ const submitForm = async () => {
 | 
			
		||||
    await unref(descriptionRef)?.validate()
 | 
			
		||||
    await unref(otherSettingsRef)?.validate()
 | 
			
		||||
    const deepCopyFormData = cloneDeep(unref(formData.value)) // 深拷贝一份 fix:这样最终 server 端不满足,不需要恢复,
 | 
			
		||||
    // 处理掉一些无关数据
 | 
			
		||||
    // TODO 兜底处理 sku 空数据详见 SkuList TODO
 | 
			
		||||
    formData.value.skus.forEach((sku) => {
 | 
			
		||||
      // 因为是空数据这里判断一下商品条码是否为空就行
 | 
			
		||||
      if (sku.barCode === '') {
 | 
			
		||||
        const index = deepCopyFormData.skus.findIndex(
 | 
			
		||||
          (item) => JSON.stringify(item.properties) === JSON.stringify(sku.properties)
 | 
			
		||||
        )
 | 
			
		||||
        // 删除这条 sku
 | 
			
		||||
        deepCopyFormData.skus.splice(index, 1)
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
    deepCopyFormData.skus.forEach((item) => {
 | 
			
		||||
      // 给sku name赋值
 | 
			
		||||
      item.name = deepCopyFormData.name
 | 
			
		||||
      // sku相关价格元转分
 | 
			
		||||
      item.price = convertToInteger(item.price)
 | 
			
		||||
      item.marketPrice = convertToInteger(item.marketPrice)
 | 
			
		||||
      item.costPrice = convertToInteger(item.costPrice)
 | 
			
		||||
      item.subCommissionFirstPrice = convertToInteger(item.subCommissionFirstPrice)
 | 
			
		||||
      item.subCommissionSecondPrice = convertToInteger(item.subCommissionSecondPrice)
 | 
			
		||||
    })
 | 
			
		||||
    // 处理轮播图列表
 | 
			
		||||
    const newSliderPicUrls = []
 | 
			
		||||
@@ -148,34 +186,6 @@ const submitForm = async () => {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 重置表单
 | 
			
		||||
 * fix:先注释保留,如果后期没有使用到则移除
 | 
			
		||||
 */
 | 
			
		||||
// const resetForm = async () => {
 | 
			
		||||
//   formData.value = {
 | 
			
		||||
//     name: '', // 商品名称
 | 
			
		||||
//     categoryId: 0, // 商品分类
 | 
			
		||||
//     keyword: '', // 关键字
 | 
			
		||||
//     unit: '', // 单位
 | 
			
		||||
//     picUrl: '', // 商品封面图
 | 
			
		||||
//     sliderPicUrls: [], // 商品轮播图
 | 
			
		||||
//     introduction: '', // 商品简介
 | 
			
		||||
//     deliveryTemplateId: 0, // 运费模版
 | 
			
		||||
//     selectRule: '',
 | 
			
		||||
//     specType: false, // 商品规格
 | 
			
		||||
//     subCommissionType: false, // 分销类型
 | 
			
		||||
//     description: '', // 商品详情
 | 
			
		||||
//     sort: 1, // 商品排序
 | 
			
		||||
//     giveIntegral: 1, // 赠送积分
 | 
			
		||||
//     virtualSalesCount: 1, // 虚拟销量
 | 
			
		||||
//     recommendHot: false, // 是否热卖
 | 
			
		||||
//     recommendBenefit: false, // 是否优惠
 | 
			
		||||
//     recommendBest: false, // 是否精品
 | 
			
		||||
//     recommendNew: false, // 是否新品
 | 
			
		||||
//     recommendGood: false // 是否优品
 | 
			
		||||
//   }
 | 
			
		||||
// }
 | 
			
		||||
/** 关闭按钮 */
 | 
			
		||||
const close = () => {
 | 
			
		||||
  delView(unref(currentRoute))
 | 
			
		||||
 
 | 
			
		||||
@@ -59,13 +59,23 @@
 | 
			
		||||
      </el-col>
 | 
			
		||||
      <el-col :span="12">
 | 
			
		||||
        <el-form-item label="运费模板" prop="deliveryTemplateId">
 | 
			
		||||
          <el-select v-model="formData.deliveryTemplateId" class="w-1/1" placeholder="请选择">
 | 
			
		||||
          <el-select v-model="formData.deliveryTemplateId" placeholder="请选择">
 | 
			
		||||
            <el-option v-for="item in []" :key="item.id" :label="item.name" :value="item.id" />
 | 
			
		||||
          </el-select>
 | 
			
		||||
          <el-button class="ml-20px">运费模板</el-button>
 | 
			
		||||
        </el-form-item>
 | 
			
		||||
      </el-col>
 | 
			
		||||
      <el-col :span="12">
 | 
			
		||||
        <el-button class="ml-20px">运费模板</el-button>
 | 
			
		||||
        <el-form-item label="品牌" prop="brandId">
 | 
			
		||||
          <el-select v-model="formData.brandId" placeholder="请选择">
 | 
			
		||||
            <el-option
 | 
			
		||||
              v-for="item in brandList"
 | 
			
		||||
              :key="item.id"
 | 
			
		||||
              :label="item.name"
 | 
			
		||||
              :value="item.id"
 | 
			
		||||
            />
 | 
			
		||||
          </el-select>
 | 
			
		||||
        </el-form-item>
 | 
			
		||||
      </el-col>
 | 
			
		||||
      <el-col :span="12">
 | 
			
		||||
        <el-form-item label="商品规格" props="specType">
 | 
			
		||||
@@ -108,14 +118,15 @@
 | 
			
		||||
</template>
 | 
			
		||||
<script lang="ts" name="ProductSpuBasicInfoForm" setup>
 | 
			
		||||
import { PropType } from 'vue'
 | 
			
		||||
import { copyValueToTarget } from '@/utils'
 | 
			
		||||
import { propTypes } from '@/utils/propTypes'
 | 
			
		||||
import { defaultProps, handleTree } from '@/utils/tree'
 | 
			
		||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 | 
			
		||||
import type { SpuType } from '@/api/mall/product/spu'
 | 
			
		||||
import { UploadImg, UploadImgs } from '@/components/UploadFile'
 | 
			
		||||
import { ProductAttributes, ProductAttributesAddForm, SkuList } from './index'
 | 
			
		||||
import * as ProductCategoryApi from '@/api/mall/product/category'
 | 
			
		||||
import { propTypes } from '@/utils/propTypes'
 | 
			
		||||
import { copyValueToTarget } from '@/utils'
 | 
			
		||||
import { getSimpleBrandList } from '@/api/mall/product/brand'
 | 
			
		||||
 | 
			
		||||
const message = useMessage() // 消息弹窗
 | 
			
		||||
 | 
			
		||||
@@ -135,15 +146,20 @@ const propertyList = ref([]) // 商品属性列表
 | 
			
		||||
const addAttribute = (property: any) => {
 | 
			
		||||
  Array.isArray(property) ? (propertyList.value = property) : propertyList.value.push(property)
 | 
			
		||||
}
 | 
			
		||||
/** 调用 SkuList generateTableData 方法*/
 | 
			
		||||
// const generateSkus(propertyList){
 | 
			
		||||
//   skuList.value.generateTableData()
 | 
			
		||||
// }
 | 
			
		||||
const formData = reactive<SpuType>({
 | 
			
		||||
  name: '', // 商品名称
 | 
			
		||||
  categoryId: undefined, // 商品分类
 | 
			
		||||
  categoryId: null, // 商品分类
 | 
			
		||||
  keyword: '', // 关键字
 | 
			
		||||
  unit: '', // 单位
 | 
			
		||||
  picUrl: '', // 商品封面图
 | 
			
		||||
  sliderPicUrls: [], // 商品轮播图
 | 
			
		||||
  introduction: '', // 商品简介
 | 
			
		||||
  deliveryTemplateId: 1, // 运费模版
 | 
			
		||||
  brandId: null, // 商品品牌
 | 
			
		||||
  specType: false, // 商品规格
 | 
			
		||||
  subCommissionType: false, // 分销类型
 | 
			
		||||
  skus: []
 | 
			
		||||
@@ -157,6 +173,7 @@ const rules = reactive({
 | 
			
		||||
  picUrl: [required],
 | 
			
		||||
  sliderPicUrls: [required],
 | 
			
		||||
  // deliveryTemplateId: [required],
 | 
			
		||||
  brandId: [required],
 | 
			
		||||
  specType: [required],
 | 
			
		||||
  subCommissionType: [required]
 | 
			
		||||
})
 | 
			
		||||
@@ -232,10 +249,13 @@ const onChangeSpec = () => {
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const categoryList = ref() // 分类树
 | 
			
		||||
const categoryList = ref([]) // 分类树
 | 
			
		||||
const brandList = ref([]) // 精简商品品牌列表
 | 
			
		||||
onMounted(async () => {
 | 
			
		||||
  // 获得分类树
 | 
			
		||||
  const data = await ProductCategoryApi.getCategoryList({})
 | 
			
		||||
  categoryList.value = handleTree(data, 'id', 'parentId')
 | 
			
		||||
  // 获取商品品牌列表
 | 
			
		||||
  brandList.value = await getSimpleBrandList()
 | 
			
		||||
})
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -34,17 +34,29 @@
 | 
			
		||||
    <!-- TODO @puhui999:用户输入的时候,是按照元;分主要是我们自己用;fix -->
 | 
			
		||||
    <el-table-column align="center" label="销售价(元)" min-width="168">
 | 
			
		||||
      <template #default="{ row }">
 | 
			
		||||
        <el-input-number v-model="row.price" :min="0" class="w-100%" />
 | 
			
		||||
        <el-input-number v-model="row.price" :min="0" :precision="2" :step="0.1" class="w-100%" />
 | 
			
		||||
      </template>
 | 
			
		||||
    </el-table-column>
 | 
			
		||||
    <el-table-column align="center" label="市场价(元)" min-width="168">
 | 
			
		||||
      <template #default="{ row }">
 | 
			
		||||
        <el-input-number v-model="row.marketPrice" :min="0" class="w-100%" />
 | 
			
		||||
        <el-input-number
 | 
			
		||||
          v-model="row.marketPrice"
 | 
			
		||||
          :min="0"
 | 
			
		||||
          :precision="2"
 | 
			
		||||
          :step="0.1"
 | 
			
		||||
          class="w-100%"
 | 
			
		||||
        />
 | 
			
		||||
      </template>
 | 
			
		||||
    </el-table-column>
 | 
			
		||||
    <el-table-column align="center" label="成本价(元)" min-width="168">
 | 
			
		||||
      <template #default="{ row }">
 | 
			
		||||
        <el-input-number v-model="row.costPrice" :min="0" class="w-100%" />
 | 
			
		||||
        <el-input-number
 | 
			
		||||
          v-model="row.costPrice"
 | 
			
		||||
          :min="0"
 | 
			
		||||
          :precision="2"
 | 
			
		||||
          :step="0.1"
 | 
			
		||||
          class="w-100%"
 | 
			
		||||
        />
 | 
			
		||||
      </template>
 | 
			
		||||
    </el-table-column>
 | 
			
		||||
    <el-table-column align="center" label="库存" min-width="168">
 | 
			
		||||
@@ -54,42 +66,54 @@
 | 
			
		||||
    </el-table-column>
 | 
			
		||||
    <el-table-column align="center" label="重量(kg)" min-width="168">
 | 
			
		||||
      <template #default="{ row }">
 | 
			
		||||
        <el-input-number v-model="row.weight" :min="0" class="w-100%" />
 | 
			
		||||
        <el-input-number v-model="row.weight" :min="0" :precision="2" :step="0.1" class="w-100%" />
 | 
			
		||||
      </template>
 | 
			
		||||
    </el-table-column>
 | 
			
		||||
    <el-table-column align="center" label="体积(m^3)" min-width="168">
 | 
			
		||||
      <template #default="{ row }">
 | 
			
		||||
        <el-input-number v-model="row.volume" :min="0" class="w-100%" />
 | 
			
		||||
        <el-input-number v-model="row.volume" :min="0" :precision="2" :step="0.1" class="w-100%" />
 | 
			
		||||
      </template>
 | 
			
		||||
    </el-table-column>
 | 
			
		||||
    <template v-if="formData.subCommissionType">
 | 
			
		||||
      <el-table-column align="center" label="一级返佣(元)" min-width="168">
 | 
			
		||||
        <template #default="{ row }">
 | 
			
		||||
          <el-input-number v-model="row.subCommissionFirstPrice" :min="0" class="w-100%" />
 | 
			
		||||
          <el-input-number
 | 
			
		||||
            v-model="row.subCommissionFirstPrice"
 | 
			
		||||
            :min="0"
 | 
			
		||||
            :precision="2"
 | 
			
		||||
            :step="0.1"
 | 
			
		||||
            class="w-100%"
 | 
			
		||||
          />
 | 
			
		||||
        </template>
 | 
			
		||||
      </el-table-column>
 | 
			
		||||
      <el-table-column align="center" label="二级返佣(元)" min-width="168">
 | 
			
		||||
        <template #default="{ row }">
 | 
			
		||||
          <el-input-number v-model="row.subCommissionSecondPrice" :min="0" class="w-100%" />
 | 
			
		||||
          <el-input-number
 | 
			
		||||
            v-model="row.subCommissionSecondPrice"
 | 
			
		||||
            :min="0"
 | 
			
		||||
            :precision="2"
 | 
			
		||||
            :step="0.1"
 | 
			
		||||
            class="w-100%"
 | 
			
		||||
          />
 | 
			
		||||
        </template>
 | 
			
		||||
      </el-table-column>
 | 
			
		||||
    </template>
 | 
			
		||||
    <el-table-column v-if="formData.specType" align="center" fixed="right" label="操作" width="80">
 | 
			
		||||
      <template #default>
 | 
			
		||||
      <template #default="{ row }">
 | 
			
		||||
        <el-button v-if="isBatch" link size="small" type="primary" @click="batchAdd">
 | 
			
		||||
          批量添加
 | 
			
		||||
        </el-button>
 | 
			
		||||
        <el-button v-else link size="small" type="primary">删除</el-button>
 | 
			
		||||
        <el-button v-else link size="small" type="primary" @click="deleteSku(row)">删除</el-button>
 | 
			
		||||
      </template>
 | 
			
		||||
    </el-table-column>
 | 
			
		||||
  </el-table>
 | 
			
		||||
</template>
 | 
			
		||||
<script lang="ts" name="SkuList" setup>
 | 
			
		||||
import { UploadImg } from '@/components/UploadFile'
 | 
			
		||||
import { PropType } from 'vue'
 | 
			
		||||
import type { Property, SkuType, SpuType } from '@/api/mall/product/spu'
 | 
			
		||||
import { propTypes } from '@/utils/propTypes'
 | 
			
		||||
import { copyValueToTarget } from '@/utils'
 | 
			
		||||
import { propTypes } from '@/utils/propTypes'
 | 
			
		||||
import { UploadImg } from '@/components/UploadFile'
 | 
			
		||||
import type { Property, SkuType, SpuType } from '@/api/mall/product/spu'
 | 
			
		||||
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
  propFormData: {
 | 
			
		||||
@@ -124,7 +148,14 @@ const batchAdd = () => {
 | 
			
		||||
    copyValueToTarget(item, skuList.value[0])
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 删除 sku */
 | 
			
		||||
const deleteSku = (row) => {
 | 
			
		||||
  const index = formData.value.skus.findIndex(
 | 
			
		||||
    // 直接把列表转成字符串比较
 | 
			
		||||
    (sku) => JSON.stringify(sku.properties) === JSON.stringify(row.properties)
 | 
			
		||||
  )
 | 
			
		||||
  formData.value.skus.splice(index, 1)
 | 
			
		||||
}
 | 
			
		||||
const tableHeaders = ref<{ prop: string; label: string }[]>([]) // 多属性表头
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -142,11 +173,11 @@ watch(
 | 
			
		||||
  }
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// TODO @芋艿:看看 chatgpt 可以进一步下面几个方法的实现不 fix
 | 
			
		||||
// TODO @芋艿:看看 chatgpt 可以进一步下面几个方法的实现不 fix: 添加相关处理逻辑解决编辑表单时或查看详情时数据回显问题
 | 
			
		||||
/** 生成表数据 */
 | 
			
		||||
const generateTableData = (data: any[]) => {
 | 
			
		||||
const generateTableData = (propertyList: any[]) => {
 | 
			
		||||
  // 构建数据结构 fix: 使用map替换多重for循环
 | 
			
		||||
  const propertiesItemList = data.map((item) =>
 | 
			
		||||
  const propertiesItemList = propertyList.map((item) =>
 | 
			
		||||
    item.values.map((v) => ({
 | 
			
		||||
      propertyId: item.id,
 | 
			
		||||
      propertyName: item.name,
 | 
			
		||||
@@ -155,19 +186,14 @@ const generateTableData = (data: any[]) => {
 | 
			
		||||
    }))
 | 
			
		||||
  )
 | 
			
		||||
  const buildList = build(propertiesItemList)
 | 
			
		||||
  // 如果构建后的组合数跟sku数量一样的话则不用处理,添加新属性没有属性值也不做处理
 | 
			
		||||
  // fix: 解决编辑表单时或查看详情时数据回显问题
 | 
			
		||||
  if (
 | 
			
		||||
    buildList.length === formData.value.skus.length ||
 | 
			
		||||
    data.some((item) => item.values.length === 0)
 | 
			
		||||
  ) {
 | 
			
		||||
    return
 | 
			
		||||
  // 如果回显的 sku 属性和添加的属性不一致则重置 skus 列表
 | 
			
		||||
  if (!validateData(propertyList)) {
 | 
			
		||||
    // 如果不一致则重置表数据,默认添加新的属性重新生成sku列表
 | 
			
		||||
    formData.value!.skus = []
 | 
			
		||||
  }
 | 
			
		||||
  // 重置表数据
 | 
			
		||||
  formData.value!.skus = []
 | 
			
		||||
  buildList.forEach((item) => {
 | 
			
		||||
  for (const item of buildList) {
 | 
			
		||||
    const row = {
 | 
			
		||||
      properties: Array.isArray(item) ? item : [item],
 | 
			
		||||
      properties: Array.isArray(item) ? item : [item], // 如果只有一个属性的话返回的是一个property对象
 | 
			
		||||
      price: 0,
 | 
			
		||||
      marketPrice: 0,
 | 
			
		||||
      costPrice: 0,
 | 
			
		||||
@@ -179,8 +205,36 @@ const generateTableData = (data: any[]) => {
 | 
			
		||||
      subCommissionFirstPrice: 0,
 | 
			
		||||
      subCommissionSecondPrice: 0
 | 
			
		||||
    }
 | 
			
		||||
    const index = formData.value!.skus.findIndex(
 | 
			
		||||
      (sku) => JSON.stringify(sku.properties) === JSON.stringify(row.properties)
 | 
			
		||||
    )
 | 
			
		||||
    // 如果存在属性相同的 sku 则不做处理
 | 
			
		||||
    if (index !== -1) {
 | 
			
		||||
      continue
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * TODO 嗯。。有一个问题回显数据时已删除的 sku 会被重新添加暂时没想到好办法,保存时先手动重新删除一下因为是一条空数据很好辨别 不手动删也没是提交表单时会检测删除空sku来兜底
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
    formData.value.skus.push(row)
 | 
			
		||||
  })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
/**
 | 
			
		||||
 * 生成 skus 前置校验
 | 
			
		||||
 */
 | 
			
		||||
const validateData = (propertyList: any[]) => {
 | 
			
		||||
  const skuPropertyIds = []
 | 
			
		||||
  formData.value.skus.forEach((sku) =>
 | 
			
		||||
    sku.properties
 | 
			
		||||
      ?.map((property) => property.propertyId)
 | 
			
		||||
      .forEach((propertyId) => {
 | 
			
		||||
        if (skuPropertyIds.indexOf(propertyId) === -1) {
 | 
			
		||||
          skuPropertyIds.push(propertyId)
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
  )
 | 
			
		||||
  const propertyIds = propertyList.map((item) => item.id)
 | 
			
		||||
  return skuPropertyIds.length === propertyIds.length
 | 
			
		||||
}
 | 
			
		||||
/** 构建所有排列组合 */
 | 
			
		||||
const build = (propertyValuesList: Property[][]) => {
 | 
			
		||||
@@ -237,6 +291,10 @@ watch(
 | 
			
		||||
      // name加属性项index区分属性值
 | 
			
		||||
      tableHeaders.value.push({ prop: `name${index}`, label: item.name })
 | 
			
		||||
    })
 | 
			
		||||
    // 如果回显的 sku 属性和添加的属性一致则不处理
 | 
			
		||||
    if (validateData(propertyList)) return
 | 
			
		||||
    // 添加新属性没有属性值也不做处理
 | 
			
		||||
    if (propertyList.some((item) => item.values.length === 0)) return
 | 
			
		||||
    generateTableData(propertyList)
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
 
 | 
			
		||||
@@ -75,10 +75,10 @@
 | 
			
		||||
        <template #default="{ row }">
 | 
			
		||||
          <el-form class="demo-table-expand" inline label-position="left">
 | 
			
		||||
            <el-form-item label="市场价:">
 | 
			
		||||
              <span>{{ row.marketPrice }}</span>
 | 
			
		||||
              <span>{{ formatToFraction(row.marketPrice) }}</span>
 | 
			
		||||
            </el-form-item>
 | 
			
		||||
            <el-form-item label="成本价:">
 | 
			
		||||
              <span>{{ row.costPrice }}</span>
 | 
			
		||||
              <span>{{ formatToFraction(row.costPrice) }}</span>
 | 
			
		||||
            </el-form-item>
 | 
			
		||||
            <el-form-item label="虚拟销量:">
 | 
			
		||||
              <span>{{ row.virtualSalesCount }}</span>
 | 
			
		||||
@@ -99,7 +99,11 @@
 | 
			
		||||
      </el-table-column>
 | 
			
		||||
      <el-table-column :show-overflow-tooltip="true" label="商品名称" min-width="300" prop="name" />
 | 
			
		||||
      <!-- TODO 价格 / 100.0 -->
 | 
			
		||||
      <el-table-column align="center" label="商品售价" min-width="90" prop="price" />
 | 
			
		||||
      <el-table-column align="center" label="商品售价" min-width="90" prop="price">
 | 
			
		||||
        <template #default="{ row }">
 | 
			
		||||
          {{ formatToFraction(row.price) }}
 | 
			
		||||
        </template>
 | 
			
		||||
      </el-table-column>
 | 
			
		||||
      <el-table-column align="center" label="销量" min-width="90" prop="salesCount" />
 | 
			
		||||
      <el-table-column align="center" label="库存" min-width="90" prop="stock" />
 | 
			
		||||
      <el-table-column align="center" label="排序" min-width="70" prop="sort" />
 | 
			
		||||
@@ -129,9 +133,12 @@
 | 
			
		||||
          </template>
 | 
			
		||||
        </template>
 | 
			
		||||
      </el-table-column>
 | 
			
		||||
      <el-table-column align="center" fixed="right" label="操作" min-width="150">
 | 
			
		||||
      <el-table-column align="center" fixed="right" label="操作" min-width="200">
 | 
			
		||||
        <template #default="{ row }">
 | 
			
		||||
          <!-- TODO @puhui999:【详情】,可以后面点做哈 -->
 | 
			
		||||
          <el-button v-hasPermi="['product:spu:update']" link type="primary" @click="openDetail">
 | 
			
		||||
            详情
 | 
			
		||||
          </el-button>
 | 
			
		||||
          <template v-if="queryParams.tabType === 4">
 | 
			
		||||
            <el-button
 | 
			
		||||
              v-hasPermi="['product:spu:delete']"
 | 
			
		||||
@@ -151,7 +158,9 @@
 | 
			
		||||
            </el-button>
 | 
			
		||||
          </template>
 | 
			
		||||
          <template v-else>
 | 
			
		||||
            <!-- 只有不是上架和回收站的商品可以编辑 -->
 | 
			
		||||
            <el-button
 | 
			
		||||
              v-if="queryParams.tabType !== 0"
 | 
			
		||||
              v-hasPermi="['product:spu:update']"
 | 
			
		||||
              link
 | 
			
		||||
              type="primary"
 | 
			
		||||
@@ -189,6 +198,7 @@ import { defaultProps, handleTree } from '@/utils/tree'
 | 
			
		||||
import { ProductSpuStatusEnum } from '@/utils/constants'
 | 
			
		||||
import * as ProductSpuApi from '@/api/mall/product/spu'
 | 
			
		||||
import * as ProductCategoryApi from '@/api/mall/product/category'
 | 
			
		||||
import { formatToFraction } from '@/utils'
 | 
			
		||||
 | 
			
		||||
const message = useMessage() // 消息弹窗
 | 
			
		||||
const { t } = useI18n() // 国际化
 | 
			
		||||
@@ -357,7 +367,12 @@ const openForm = (id?: number) => {
 | 
			
		||||
  // 新增
 | 
			
		||||
  push('/product/productSpuAdd')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 查看商品详情
 | 
			
		||||
 */
 | 
			
		||||
const openDetail = () => {
 | 
			
		||||
  message.alert('查看详情未完善!!!')
 | 
			
		||||
}
 | 
			
		||||
// 监听路由变化更新列表 TODO @puhui999:这个是必须加的么?fix: 因为编辑表单是以路由的方式打开,保存表单后列表不会刷新
 | 
			
		||||
watch(
 | 
			
		||||
  () => currentRoute.value,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user