parent
4eacb6dd8c
commit
4cd4327bc8
@ -37,38 +37,58 @@ const include = [
|
|||||||
'element-plus/es',
|
'element-plus/es',
|
||||||
'element-plus/es/locale/lang/zh-cn',
|
'element-plus/es/locale/lang/zh-cn',
|
||||||
'element-plus/es/locale/lang/en',
|
'element-plus/es/locale/lang/en',
|
||||||
'element-plus/es/components/backtop/style/index',
|
'element-plus/es/components/backtop/style/css',
|
||||||
'element-plus/es/components/form/style/index',
|
'element-plus/es/components/form/style/css',
|
||||||
'element-plus/es/components/radio-group/style/index',
|
'element-plus/es/components/radio-group/style/css',
|
||||||
'element-plus/es/components/radio/style/index',
|
'element-plus/es/components/radio/style/css',
|
||||||
'element-plus/es/components/checkbox/style/index',
|
'element-plus/es/components/checkbox/style/css',
|
||||||
'element-plus/es/components/checkbox-group/style/index',
|
'element-plus/es/components/checkbox-group/style/css',
|
||||||
'element-plus/es/components/switch/style/index',
|
'element-plus/es/components/switch/style/css',
|
||||||
'element-plus/es/components/time-picker/style/index',
|
'element-plus/es/components/time-picker/style/css',
|
||||||
'element-plus/es/components/date-picker/style/index',
|
'element-plus/es/components/date-picker/style/css',
|
||||||
'element-plus/es/components/col/style/index',
|
'element-plus/es/components/descriptions/style/css',
|
||||||
'element-plus/es/components/form-item/style/index',
|
'element-plus/es/components/descriptions-item/style/css',
|
||||||
'element-plus/es/components/alert/style/index',
|
'element-plus/es/components/link/style/css',
|
||||||
'element-plus/es/components/breadcrumb/style/index',
|
'element-plus/es/components/tooltip/style/css',
|
||||||
'element-plus/es/components/select/style/index',
|
'element-plus/es/components/drawer/style/css',
|
||||||
'element-plus/es/components/input/style/index',
|
'element-plus/es/components/dialog/style/css',
|
||||||
'element-plus/es/components/breadcrumb-item/style/index',
|
'element-plus/es/components/checkbox-button/style/css',
|
||||||
'element-plus/es/components/tag/style/index',
|
'element-plus/es/components/option-group/style/css',
|
||||||
'element-plus/es/components/pagination/style/index',
|
'element-plus/es/components/radio-button/style/css',
|
||||||
'element-plus/es/components/table/style/index',
|
'element-plus/es/components/cascader/style/css',
|
||||||
'element-plus/es/components/table-column/style/index',
|
'element-plus/es/components/color-picker/style/css',
|
||||||
'element-plus/es/components/card/style/index',
|
'element-plus/es/components/input-number/style/css',
|
||||||
'element-plus/es/components/row/style/index',
|
'element-plus/es/components/rate/style/css',
|
||||||
'element-plus/es/components/button/style/index',
|
'element-plus/es/components/select-v2/style/css',
|
||||||
'element-plus/es/components/menu/style/index',
|
'element-plus/es/components/tree-select/style/css',
|
||||||
'element-plus/es/components/sub-menu/style/index',
|
'element-plus/es/components/slider/style/css',
|
||||||
'element-plus/es/components/menu-item/style/index',
|
'element-plus/es/components/time-select/style/css',
|
||||||
'element-plus/es/components/option/style/index',
|
'element-plus/es/components/autocomplete/style/css',
|
||||||
'element-plus/es/components/dropdown/style/index',
|
'element-plus/es/components/image-viewer/style/css',
|
||||||
'element-plus/es/components/dropdown-menu/style/index',
|
'element-plus/es/components/upload/style/css',
|
||||||
'element-plus/es/components/dropdown-item/style/index',
|
'element-plus/es/components/col/style/css',
|
||||||
'element-plus/es/components/skeleton/style/index',
|
'element-plus/es/components/form-item/style/css',
|
||||||
|
'element-plus/es/components/alert/style/css',
|
||||||
|
'element-plus/es/components/breadcrumb/style/css',
|
||||||
|
'element-plus/es/components/select/style/css',
|
||||||
|
'element-plus/es/components/input/style/css',
|
||||||
|
'element-plus/es/components/breadcrumb-item/style/css',
|
||||||
|
'element-plus/es/components/tag/style/css',
|
||||||
|
'element-plus/es/components/pagination/style/css',
|
||||||
|
'element-plus/es/components/table/style/css',
|
||||||
|
'element-plus/es/components/table-v2/style/css',
|
||||||
|
'element-plus/es/components/table-column/style/css',
|
||||||
|
'element-plus/es/components/card/style/css',
|
||||||
|
'element-plus/es/components/row/style/css',
|
||||||
|
'element-plus/es/components/button/style/css',
|
||||||
|
'element-plus/es/components/menu/style/css',
|
||||||
|
'element-plus/es/components/sub-menu/style/css',
|
||||||
|
'element-plus/es/components/menu-item/style/css',
|
||||||
|
'element-plus/es/components/option/style/css',
|
||||||
|
'element-plus/es/components/dropdown/style/css',
|
||||||
|
'element-plus/es/components/dropdown-menu/style/css',
|
||||||
|
'element-plus/es/components/dropdown-item/style/css',
|
||||||
|
'element-plus/es/components/skeleton/style/css',
|
||||||
'element-plus/es/components/skeleton/style/css',
|
'element-plus/es/components/skeleton/style/css',
|
||||||
'element-plus/es/components/backtop/style/css',
|
'element-plus/es/components/backtop/style/css',
|
||||||
'element-plus/es/components/menu/style/css',
|
'element-plus/es/components/menu/style/css',
|
||||||
@ -82,20 +102,13 @@ const include = [
|
|||||||
'element-plus/es/components/breadcrumb/style/css',
|
'element-plus/es/components/breadcrumb/style/css',
|
||||||
'element-plus/es/components/breadcrumb-item/style/css',
|
'element-plus/es/components/breadcrumb-item/style/css',
|
||||||
'element-plus/es/components/image/style/css',
|
'element-plus/es/components/image/style/css',
|
||||||
'element-plus/es/components/tag/style/css',
|
'element-plus/es/components/collapse-transition/style/css',
|
||||||
'element-plus/es/components/dialog/style/css',
|
'element-plus/es/components/timeline/style/css',
|
||||||
'element-plus/es/components/form/style/css',
|
'element-plus/es/components/timeline-item/style/css',
|
||||||
'element-plus/es/components/form-item/style/css',
|
'element-plus/es/components/collapse/style/css',
|
||||||
'element-plus/es/components/card/style/css',
|
'element-plus/es/components/collapse-item/style/css',
|
||||||
'element-plus/es/components/tooltip/style/css',
|
'element-plus/es/components/button-group/style/css',
|
||||||
'element-plus/es/components/radio-group/style/css',
|
'element-plus/es/components/text/style/css'
|
||||||
'element-plus/es/components/radio/style/css',
|
|
||||||
'element-plus/es/components/input-number/style/css',
|
|
||||||
'element-plus/es/components/tree-select/style/css',
|
|
||||||
'element-plus/es/components/drawer/style/css',
|
|
||||||
'element-plus/es/components/image-viewer/style/css',
|
|
||||||
'element-plus/es/components/upload/style/css',
|
|
||||||
'element-plus/es/components/switch/style/css'
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const exclude = ['@iconify/json']
|
const exclude = ['@iconify/json']
|
||||||
|
@ -7,6 +7,7 @@ export interface Property {
|
|||||||
valueName?: string // 属性值名称
|
valueName?: string // 属性值名称
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO puhui999:是不是直接叫 Sku 更简洁一点哈。type 待后面,总感觉有个类型?
|
||||||
export interface SkuType {
|
export interface SkuType {
|
||||||
id?: number // 商品 SKU 编号
|
id?: number // 商品 SKU 编号
|
||||||
spuId?: number // SPU 编号
|
spuId?: number // SPU 编号
|
||||||
@ -24,6 +25,7 @@ export interface SkuType {
|
|||||||
salesCount?: number // 商品销量
|
salesCount?: number // 商品销量
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO puhui999:是不是直接叫 Spu 更简洁一点哈。type 待后面,总感觉有个类型?
|
||||||
export interface SpuType {
|
export interface SpuType {
|
||||||
id?: number
|
id?: number
|
||||||
name?: string // 商品名称
|
name?: string // 商品名称
|
||||||
|
@ -174,6 +174,7 @@ export const copyValueToTarget = (target, source) => {
|
|||||||
Object.assign(target, newObj)
|
Object.assign(target, newObj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO @puhui999:返回要带上 .00 哈.例如说 1.00
|
||||||
/**
|
/**
|
||||||
* 将一个整数转换为分数保留两位小数
|
* 将一个整数转换为分数保留两位小数
|
||||||
* @param num
|
* @param num
|
||||||
|
@ -146,7 +146,6 @@ const submitForm = async () => {
|
|||||||
const newSliderPicUrls = []
|
const newSliderPicUrls = []
|
||||||
deepCopyFormData.sliderPicUrls.forEach((item) => {
|
deepCopyFormData.sliderPicUrls.forEach((item) => {
|
||||||
// 如果是前端选的图
|
// 如果是前端选的图
|
||||||
// TODO @puhui999:疑问哈,为啥会是 object 呀?fix
|
|
||||||
typeof item === 'object' ? newSliderPicUrls.push(item.url) : newSliderPicUrls.push(item)
|
typeof item === 'object' ? newSliderPicUrls.push(item.url) : newSliderPicUrls.push(item)
|
||||||
})
|
})
|
||||||
deepCopyFormData.sliderPicUrls = newSliderPicUrls
|
deepCopyFormData.sliderPicUrls = newSliderPicUrls
|
||||||
|
@ -96,7 +96,6 @@
|
|||||||
<!-- 多规格添加-->
|
<!-- 多规格添加-->
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item v-if="formData.specType" label="商品属性">
|
<el-form-item v-if="formData.specType" label="商品属性">
|
||||||
<!-- TODO @puhui999:参考 https://admin.java.crmeb.net/store/list/creatProduct 添加规格好做么?添加的时候,不用输入备注哈 fix-->
|
|
||||||
<el-button class="mr-15px mb-10px" @click="attributesAddFormRef.open">添加规格</el-button>
|
<el-button class="mr-15px mb-10px" @click="attributesAddFormRef.open">添加规格</el-button>
|
||||||
<ProductAttributes :propertyList="propertyList" @success="generateSkus" />
|
<ProductAttributes :propertyList="propertyList" @success="generateSkus" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -137,9 +136,8 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
activeName: propTypes.string.def('')
|
activeName: propTypes.string.def('')
|
||||||
})
|
})
|
||||||
const attributesAddFormRef = ref() // 添加商品属性表单 TODO @puhui999:小写开头哈 fix
|
const attributesAddFormRef = ref() // 添加商品属性表单
|
||||||
const productSpuBasicInfoRef = ref() // 表单Ref TODO @puhui999:小写开头哈 fix
|
const productSpuBasicInfoRef = ref() // 表单 Ref
|
||||||
// TODO @puhui999:attributeList 改成 propertyList,会更统一一点 fix
|
|
||||||
const propertyList = ref([]) // 商品属性列表
|
const propertyList = ref([]) // 商品属性列表
|
||||||
const skuListRef = ref() // 商品属性列表Ref
|
const skuListRef = ref() // 商品属性列表Ref
|
||||||
/** 调用 SkuList generateTableData 方法*/
|
/** 调用 SkuList generateTableData 方法*/
|
||||||
@ -180,17 +178,17 @@ const rules = reactive({
|
|||||||
watch(
|
watch(
|
||||||
() => props.propFormData,
|
() => props.propFormData,
|
||||||
(data) => {
|
(data) => {
|
||||||
if (!data) return
|
if (!data) {
|
||||||
// fix:三个表单组件监听赋值必须使用 copyValueToTarget 使用 formData.value = data 会监听非常多次
|
return
|
||||||
|
}
|
||||||
copyValueToTarget(formData, data)
|
copyValueToTarget(formData, data)
|
||||||
// fix: 多图上传组件需要一个包含url属性的对象才能正常回显
|
|
||||||
formData.sliderPicUrls = data['sliderPicUrls'].map((item) => ({
|
formData.sliderPicUrls = data['sliderPicUrls'].map((item) => ({
|
||||||
url: item
|
url: item
|
||||||
}))
|
}))
|
||||||
|
// TODO @puhui999:if return,减少嵌套层级
|
||||||
// 只有是多规格才处理
|
// 只有是多规格才处理
|
||||||
if (formData.specType) {
|
if (formData.specType) {
|
||||||
// TODO @puhui999:可以直接拿 propertyName 拼接处规格 id + 属性,可以看下商品 uniapp 详情的做法
|
// 直接拿返回的 skus 属性逆向生成出 propertyList
|
||||||
// fix: 直接拿返回的 skus 属性逆向生成出 propertyList
|
|
||||||
const properties = []
|
const properties = []
|
||||||
formData.skus.forEach((sku) => {
|
formData.skus.forEach((sku) => {
|
||||||
sku.properties.forEach(({ propertyId, propertyName, valueId, valueName }) => {
|
sku.properties.forEach(({ propertyId, propertyName, valueId, valueName }) => {
|
||||||
@ -209,7 +207,6 @@ watch(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// fix: 去掉深度监听只有对象引用发生改变的时候才执行,解决改一动多的问题
|
|
||||||
immediate: true
|
immediate: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-form ref="otherSettingsFormRef" :model="formData" :rules="rules" label-width="120px">
|
<el-form ref="otherSettingsFormRef" :model="formData" :rules="rules" label-width="120px">
|
||||||
<el-row>
|
<el-row>
|
||||||
<!-- TODO @puhui999:横着三个哈 fix-->
|
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
@ -86,7 +85,6 @@ const rules = reactive({
|
|||||||
giveIntegral: [required],
|
giveIntegral: [required],
|
||||||
virtualSalesCount: [required]
|
virtualSalesCount: [required]
|
||||||
})
|
})
|
||||||
// TODO @puhui999:这种叫 recommendOptions 会更合适哈 fix
|
|
||||||
const recommendOptions = [
|
const recommendOptions = [
|
||||||
{ name: '是否热卖', value: 'recommendHot' },
|
{ name: '是否热卖', value: 'recommendHot' },
|
||||||
{ name: '是否优惠', value: 'recommendBenefit' },
|
{ name: '是否优惠', value: 'recommendBenefit' },
|
||||||
@ -98,7 +96,6 @@ const checkboxGroup = ref<string[]>([]) // 选中的推荐选项
|
|||||||
|
|
||||||
/** 选择商品后赋值 */
|
/** 选择商品后赋值 */
|
||||||
const onChangeGroup = () => {
|
const onChangeGroup = () => {
|
||||||
// TODO @puhui999:是不是可以遍历 recommend,然后进行是否选中;fix
|
|
||||||
recommendOptions.forEach(({ value }) => {
|
recommendOptions.forEach(({ value }) => {
|
||||||
formData.value[value] = checkboxGroup.value.includes(value)
|
formData.value[value] = checkboxGroup.value.includes(value)
|
||||||
})
|
})
|
||||||
@ -110,21 +107,21 @@ const onChangeGroup = () => {
|
|||||||
watch(
|
watch(
|
||||||
() => props.propFormData,
|
() => props.propFormData,
|
||||||
(data) => {
|
(data) => {
|
||||||
if (!data) return
|
if (!data) {
|
||||||
// fix:三个表单组件监听赋值必须使用 copyValueToTarget 使用 formData.value = data 会监听非常多次
|
return
|
||||||
|
}
|
||||||
copyValueToTarget(formData.value, data)
|
copyValueToTarget(formData.value, data)
|
||||||
recommendOptions.forEach(({ value }) => {
|
recommendOptions.forEach(({ value }) => {
|
||||||
// TODO 如果先修改其他设置的值,再改变商品详情或是商品信息会重置其他设置页面中的相关值 fix:已修复
|
|
||||||
if (formData.value[value] && !checkboxGroup.value.includes(value)) {
|
if (formData.value[value] && !checkboxGroup.value.includes(value)) {
|
||||||
checkboxGroup.value.push(value)
|
checkboxGroup.value.push(value)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// fix: 去掉深度监听只有对象引用发生改变的时候才执行,解决改一动多的问题
|
|
||||||
immediate: true
|
immediate: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表单校验
|
* 表单校验
|
||||||
*/
|
*/
|
||||||
|
@ -21,17 +21,16 @@
|
|||||||
min-width="120"
|
min-width="120"
|
||||||
>
|
>
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
|
<!-- TODO puhui999:展示成蓝色,有点区分度哈 -->
|
||||||
{{ row.properties[index]?.valueName }}
|
{{ row.properties[index]?.valueName }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</template>
|
</template>
|
||||||
<!-- TODO @puhui999: controls-position=" " 可以去掉哈,不然太长了,手动输入更方便 fix -->
|
|
||||||
<el-table-column align="center" label="商品条码" min-width="168">
|
<el-table-column align="center" label="商品条码" min-width="168">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-input v-model="row.barCode" class="w-100%" />
|
<el-input v-model="row.barCode" class="w-100%" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<!-- TODO @puhui999:用户输入的时候,是按照元;分主要是我们自己用;fix -->
|
|
||||||
<el-table-column align="center" label="销售价(元)" min-width="168">
|
<el-table-column align="center" label="销售价(元)" min-width="168">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-input-number v-model="row.price" :min="0" :precision="2" :step="0.1" class="w-100%" />
|
<el-input-number v-model="row.price" :min="0" :precision="2" :step="0.1" class="w-100%" />
|
||||||
@ -141,6 +140,7 @@ const skuList = ref<SkuType[]>([
|
|||||||
subCommissionSecondPrice: 0 // 二级分销的佣金
|
subCommissionSecondPrice: 0 // 二级分销的佣金
|
||||||
}
|
}
|
||||||
]) // 批量添加时的临时数据
|
]) // 批量添加时的临时数据
|
||||||
|
// TODO @puhui999:保存时,每个商品规格的表单要校验下。例如说,销售金额最低是 0.01 这种。
|
||||||
|
|
||||||
/** 批量添加 */
|
/** 批量添加 */
|
||||||
const batchAdd = () => {
|
const batchAdd = () => {
|
||||||
@ -148,6 +148,7 @@ const batchAdd = () => {
|
|||||||
copyValueToTarget(item, skuList.value[0])
|
copyValueToTarget(item, skuList.value[0])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 删除 sku */
|
/** 删除 sku */
|
||||||
const deleteSku = (row) => {
|
const deleteSku = (row) => {
|
||||||
const index = formData.value.skus.findIndex(
|
const index = formData.value.skus.findIndex(
|
||||||
@ -173,11 +174,10 @@ watch(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO @芋艿:看看 chatgpt 可以进一步下面几个方法的实现不 fix: 添加相关处理逻辑解决编辑表单时或查看详情时数据回显问题
|
|
||||||
/** 生成表数据 */
|
/** 生成表数据 */
|
||||||
const generateTableData = (propertyList: any[]) => {
|
const generateTableData = (propertyList: any[]) => {
|
||||||
// 构建数据结构 fix: 使用map替换多重for循环
|
// 构建数据结构
|
||||||
const propertiesItemList = propertyList.map((item) =>
|
const propertyValues = propertyList.map((item) =>
|
||||||
item.values.map((v) => ({
|
item.values.map((v) => ({
|
||||||
propertyId: item.id,
|
propertyId: item.id,
|
||||||
propertyName: item.name,
|
propertyName: item.name,
|
||||||
@ -185,7 +185,8 @@ const generateTableData = (propertyList: any[]) => {
|
|||||||
valueName: v.name
|
valueName: v.name
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
const buildList = build(propertiesItemList)
|
// TODO @puhui:是不是 buildSkuList,这样容易理解一点哈。item 改成 sku
|
||||||
|
const buildList = build(propertyValues)
|
||||||
// 如果回显的 sku 属性和添加的属性不一致则重置 skus 列表
|
// 如果回显的 sku 属性和添加的属性不一致则重置 skus 列表
|
||||||
if (!validateData(propertyList)) {
|
if (!validateData(propertyList)) {
|
||||||
// 如果不一致则重置表数据,默认添加新的属性重新生成 sku 列表
|
// 如果不一致则重置表数据,默认添加新的属性重新生成 sku 列表
|
||||||
@ -205,16 +206,17 @@ const generateTableData = (propertyList: any[]) => {
|
|||||||
subCommissionFirstPrice: 0,
|
subCommissionFirstPrice: 0,
|
||||||
subCommissionSecondPrice: 0
|
subCommissionSecondPrice: 0
|
||||||
}
|
}
|
||||||
|
// 如果存在属性相同的 sku 则不做处理
|
||||||
const index = formData.value!.skus.findIndex(
|
const index = formData.value!.skus.findIndex(
|
||||||
(sku) => JSON.stringify(sku.properties) === JSON.stringify(row.properties)
|
(sku) => JSON.stringify(sku.properties) === JSON.stringify(row.properties)
|
||||||
)
|
)
|
||||||
// 如果存在属性相同的 sku 则不做处理
|
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
formData.value.skus.push(row)
|
formData.value.skus.push(row)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成 skus 前置校验
|
* 生成 skus 前置校验
|
||||||
*/
|
*/
|
||||||
@ -232,6 +234,7 @@ const validateData = (propertyList: any[]) => {
|
|||||||
const propertyIds = propertyList.map((item) => item.id)
|
const propertyIds = propertyList.map((item) => item.id)
|
||||||
return skuPropertyIds.length === propertyIds.length
|
return skuPropertyIds.length === propertyIds.length
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 构建所有排列组合 */
|
/** 构建所有排列组合 */
|
||||||
const build = (propertyValuesList: Property[][]) => {
|
const build = (propertyValuesList: Property[][]) => {
|
||||||
if (propertyValuesList.length === 0) {
|
if (propertyValuesList.length === 0) {
|
||||||
@ -255,13 +258,15 @@ const build = (propertyValuesList: Property[][]) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 监听属性列表生成相关参数和表头 */
|
/** 监听属性列表,生成相关参数和表头 */
|
||||||
watch(
|
watch(
|
||||||
() => props.propertyList,
|
() => props.propertyList,
|
||||||
(propertyList) => {
|
(propertyList) => {
|
||||||
// 如果不是多规格则结束
|
// 如果不是多规格则结束
|
||||||
if (!formData.value.specType) return
|
if (!formData.value.specType) {
|
||||||
// 如果当前组件作为批量添加数据使用则重置表数据
|
return
|
||||||
|
}
|
||||||
|
// 如果当前组件作为批量添加数据使用,则重置表数据
|
||||||
if (props.isBatch) {
|
if (props.isBatch) {
|
||||||
skuList.value = [
|
skuList.value = [
|
||||||
{
|
{
|
||||||
@ -278,8 +283,11 @@ watch(
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断代理对象是否为空
|
// 判断代理对象是否为空
|
||||||
if (JSON.stringify(propertyList) === '[]') return
|
if (JSON.stringify(propertyList) === '[]') {
|
||||||
|
return
|
||||||
|
}
|
||||||
// 重置表头
|
// 重置表头
|
||||||
tableHeaders.value = []
|
tableHeaders.value = []
|
||||||
// 生成表头
|
// 生成表头
|
||||||
@ -287,10 +295,16 @@ watch(
|
|||||||
// name加属性项index区分属性值
|
// name加属性项index区分属性值
|
||||||
tableHeaders.value.push({ prop: `name${index}`, label: item.name })
|
tableHeaders.value.push({ prop: `name${index}`, label: item.name })
|
||||||
})
|
})
|
||||||
|
|
||||||
// 如果回显的 sku 属性和添加的属性一致则不处理
|
// 如果回显的 sku 属性和添加的属性一致则不处理
|
||||||
if (validateData(propertyList)) return
|
if (validateData(propertyList)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
// 添加新属性没有属性值也不做处理
|
// 添加新属性没有属性值也不做处理
|
||||||
if (propertyList.some((item) => item.values.length === 0)) return
|
if (propertyList.some((item) => item.values.length === 0)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 生成 table 数据,即 sku 列表
|
||||||
generateTableData(propertyList)
|
generateTableData(propertyList)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -298,6 +312,6 @@ watch(
|
|||||||
immediate: true
|
immediate: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
// 暴露出生成 sku 方法给添加属性成功时调用 fix: 为了在只有一个属性下 spu 回显 skus 属性和和商品属性个数一致的情况下 添加属性值时添加 sku
|
// 暴露出生成 sku 方法,给添加属性成功时调用
|
||||||
defineExpose({ generateTableData })
|
defineExpose({ generateTableData })
|
||||||
</script>
|
</script>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
class="-mb-15px"
|
class="-mb-15px"
|
||||||
label-width="68px"
|
label-width="68px"
|
||||||
>
|
>
|
||||||
<!-- TODO @puhui999:https://admin.java.crmeb.net/store/index,参考,使用分类 + 标题搜索 fix-->
|
<!-- TODO @puhui999:品牌应该是数据下拉哈 -->
|
||||||
<el-form-item label="品牌名称" prop="name">
|
<el-form-item label="品牌名称" prop="name">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="queryParams.name"
|
v-model="queryParams.name"
|
||||||
@ -19,6 +19,7 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- TODO 分类只能选择二级分类目前还没做,还是先以联调通顺为主 -->
|
<!-- TODO 分类只能选择二级分类目前还没做,还是先以联调通顺为主 -->
|
||||||
|
<!-- TODO puhui999:我们要不改成支持选择一级。如果选择一级,后端要递归查询下子分类,然后去 in? -->
|
||||||
<el-form-item label="商品分类" prop="categoryId">
|
<el-form-item label="商品分类" prop="categoryId">
|
||||||
<el-tree-select
|
<el-tree-select
|
||||||
v-model="queryParams.categoryId"
|
v-model="queryParams.categoryId"
|
||||||
@ -50,21 +51,11 @@
|
|||||||
<Icon class="mr-5px" icon="ep:refresh" />
|
<Icon class="mr-5px" icon="ep:refresh" />
|
||||||
重置
|
重置
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button v-hasPermi="['product:spu:create']" plain type="primary" @click="openForm">
|
<el-button v-hasPermi="['product:brand:create']" plain type="primary" @click="openForm">
|
||||||
<Icon class="mr-5px" icon="ep:plus" />
|
<Icon class="mr-5px" icon="ep:plus" />
|
||||||
新增
|
新增
|
||||||
</el-button>
|
</el-button>
|
||||||
<!-- TODO @puhui999:增加一个【导出】操作 -->
|
<!-- TODO @puhui999:增加一个【导出】操作 -->
|
||||||
<el-button
|
|
||||||
v-hasPermi="['product:spu:export']"
|
|
||||||
:loading="exportLoading"
|
|
||||||
plain
|
|
||||||
type="success"
|
|
||||||
@click="handleExport"
|
|
||||||
>
|
|
||||||
<Icon class="mr-5px" icon="ep:download" />
|
|
||||||
导出
|
|
||||||
</el-button>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</ContentWrap>
|
</ContentWrap>
|
||||||
@ -80,7 +71,12 @@
|
|||||||
/>
|
/>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
<el-table v-loading="loading" :data="list">
|
<el-table v-loading="loading" :data="list">
|
||||||
<!-- TODO 折叠数据按需增加暂定以下三个 -->
|
<!-- TODO puhui:这几个属性哈,一行三个
|
||||||
|
商品分类:服装鞋包/箱包
|
||||||
|
商品市场价格:100.00
|
||||||
|
成本价:0.00
|
||||||
|
收藏:5
|
||||||
|
虚拟销量:999 -->
|
||||||
<el-table-column type="expand" width="30">
|
<el-table-column type="expand" width="30">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-form class="demo-table-expand" inline label-position="left">
|
<el-form class="demo-table-expand" inline label-position="left">
|
||||||
@ -96,19 +92,13 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<!-- TODO puhui999: ID 编号的展示 fix-->
|
|
||||||
<el-table-column key="id" align="center" label="商品编号" prop="id" />
|
<el-table-column key="id" align="center" label="商品编号" prop="id" />
|
||||||
<el-table-column label="商品图" min-width="80">
|
<el-table-column label="商品图" min-width="80">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-image
|
<el-image :src="row.picUrl" @click="imagePreview(row.picUrl)" class="w-30px h-30px" />
|
||||||
:src="row.picUrl"
|
|
||||||
style="width: 30px; height: 30px"
|
|
||||||
@click="imagePreview(row.picUrl)"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :show-overflow-tooltip="true" label="商品名称" min-width="300" prop="name" />
|
<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 }">
|
<template #default="{ row }">
|
||||||
{{ formatToFraction(row.price) }}
|
{{ formatToFraction(row.price) }}
|
||||||
@ -126,7 +116,6 @@
|
|||||||
/>
|
/>
|
||||||
<el-table-column align="center" label="状态" min-width="80">
|
<el-table-column align="center" label="状态" min-width="80">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<!-- fix: 修复打开回收站时商品误触改变商品状态的事件,因为el-switch只用0和1没有-1所以当商品状态为-1时状态使用el-tag显示 -->
|
|
||||||
<template v-if="row.status >= 0">
|
<template v-if="row.status >= 0">
|
||||||
<el-switch
|
<el-switch
|
||||||
v-model="row.status"
|
v-model="row.status"
|
||||||
@ -206,17 +195,15 @@ import { createImageViewer } from '@/components/ImageViewer'
|
|||||||
import { dateFormatter } from '@/utils/formatTime'
|
import { dateFormatter } from '@/utils/formatTime'
|
||||||
import { defaultProps, handleTree } from '@/utils/tree'
|
import { defaultProps, handleTree } from '@/utils/tree'
|
||||||
import { ProductSpuStatusEnum } from '@/utils/constants'
|
import { ProductSpuStatusEnum } from '@/utils/constants'
|
||||||
import { formatToFraction } from '@/utils'
|
|
||||||
import download from '@/utils/download'
|
|
||||||
import * as ProductSpuApi from '@/api/mall/product/spu'
|
import * as ProductSpuApi from '@/api/mall/product/spu'
|
||||||
import * as ProductCategoryApi from '@/api/mall/product/category'
|
import * as ProductCategoryApi from '@/api/mall/product/category'
|
||||||
|
import { formatToFraction } from '@/utils'
|
||||||
|
|
||||||
const message = useMessage() // 消息弹窗
|
const message = useMessage() // 消息弹窗
|
||||||
const { t } = useI18n() // 国际化
|
const { t } = useI18n() // 国际化
|
||||||
const { currentRoute, push } = useRouter() // 路由跳转
|
const { currentRoute, push } = useRouter() // 路由跳转
|
||||||
|
|
||||||
const loading = ref(false) // 列表的加载中
|
const loading = ref(false) // 列表的加载中
|
||||||
const exportLoading = ref(false) // 导出的加载中
|
|
||||||
const total = ref(0) // 列表的总页数
|
const total = ref(0) // 列表的总页数
|
||||||
const list = ref<any[]>([]) // 列表的数据
|
const list = ref<any[]>([]) // 列表的数据
|
||||||
// tabs 数据
|
// tabs 数据
|
||||||
@ -250,7 +237,6 @@ const tabsData = ref([
|
|||||||
|
|
||||||
/** 获得每个 Tab 的数量 */
|
/** 获得每个 Tab 的数量 */
|
||||||
const getTabsCount = async () => {
|
const getTabsCount = async () => {
|
||||||
// TODO @puhui999:这里是不是可以不要 try catch 哈 fix
|
|
||||||
const res = await ProductSpuApi.getTabsCount()
|
const res = await ProductSpuApi.getTabsCount()
|
||||||
for (let objName in res) {
|
for (let objName in res) {
|
||||||
tabsData.value[Number(objName)].count = res[objName]
|
tabsData.value[Number(objName)].count = res[objName]
|
||||||
@ -263,7 +249,6 @@ const queryParams = ref({
|
|||||||
}) // 查询参数
|
}) // 查询参数
|
||||||
const queryFormRef = ref() // 搜索的表单Ref
|
const queryFormRef = ref() // 搜索的表单Ref
|
||||||
|
|
||||||
// TODO @puhui999:可以改成 handleTabClick:更准确一点;fix
|
|
||||||
const handleTabClick = (tab: TabsPaneContext) => {
|
const handleTabClick = (tab: TabsPaneContext) => {
|
||||||
queryParams.value.tabType = tab.paneName
|
queryParams.value.tabType = tab.paneName
|
||||||
getList()
|
getList()
|
||||||
@ -281,7 +266,6 @@ const getList = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO @puhui999:是不是 changeStatus 和 addToTrash 调用一个统一的方法,去更新状态。这样逻辑会更干净一些。fix
|
|
||||||
/**
|
/**
|
||||||
* 更改 SPU 状态
|
* 更改 SPU 状态
|
||||||
*
|
*
|
||||||
@ -289,7 +273,6 @@ const getList = async () => {
|
|||||||
* @param status 更改前的值
|
* @param status 更改前的值
|
||||||
*/
|
*/
|
||||||
const changeStatus = async (row, status?: number) => {
|
const changeStatus = async (row, status?: number) => {
|
||||||
// fix: 将加入回收站功能合并到changeStatus并优化
|
|
||||||
const deepCopyValue = cloneDeep(unref(row))
|
const deepCopyValue = cloneDeep(unref(row))
|
||||||
if (typeof status !== 'undefined') deepCopyValue.status = status
|
if (typeof status !== 'undefined') deepCopyValue.status = status
|
||||||
try {
|
try {
|
||||||
@ -305,7 +288,6 @@ const changeStatus = async (row, status?: number) => {
|
|||||||
text = `加入${ProductSpuStatusEnum.RECYCLE.name}`
|
text = `加入${ProductSpuStatusEnum.RECYCLE.name}`
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// fix: 修复恢复到仓库的信息提示
|
|
||||||
await message.confirm(
|
await message.confirm(
|
||||||
deepCopyValue.status === -1
|
deepCopyValue.status === -1
|
||||||
? `确认要将[${row.name}]${text}吗?`
|
? `确认要将[${row.name}]${text}吗?`
|
||||||
@ -343,12 +325,8 @@ const handleDelete = async (id: number) => {
|
|||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** 商品图预览 */
|
||||||
* 商品图预览
|
|
||||||
* @param imgUrl
|
|
||||||
*/
|
|
||||||
const imagePreview = (imgUrl: string) => {
|
const imagePreview = (imgUrl: string) => {
|
||||||
// fix: 改用https://kailong110120130.gitee.io/vue-element-plus-admin-doc/components/image-viewer.html 预览图片
|
|
||||||
createImageViewer({
|
createImageViewer({
|
||||||
urlList: [imgUrl]
|
urlList: [imgUrl]
|
||||||
})
|
})
|
||||||
@ -379,6 +357,7 @@ const openForm = (id?: number) => {
|
|||||||
// 新增
|
// 新增
|
||||||
push('/product/productSpuAdd')
|
push('/product/productSpuAdd')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查看商品详情
|
* 查看商品详情
|
||||||
*/
|
*/
|
||||||
@ -386,28 +365,14 @@ const openDetail = () => {
|
|||||||
message.alert('查看详情未完善!!!')
|
message.alert('查看详情未完善!!!')
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 导出按钮操作 */
|
// 监听路由变化更新列表,解决商品保存后,列表不刷新的问题。
|
||||||
const handleExport = async () => {
|
|
||||||
try {
|
|
||||||
// 导出的二次确认
|
|
||||||
await message.exportConfirm()
|
|
||||||
// 发起导出
|
|
||||||
exportLoading.value = true
|
|
||||||
const data = await ProductSpuApi.exportSpu(queryParams)
|
|
||||||
download.excel(data, '商品spu.xls')
|
|
||||||
} catch {
|
|
||||||
} finally {
|
|
||||||
exportLoading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 监听路由变化更新列表 TODO @puhui999:这个是必须加的么?fix: 因为编辑表单是以路由的方式打开,保存表单后列表不会刷新
|
|
||||||
watch(
|
watch(
|
||||||
() => currentRoute.value,
|
() => currentRoute.value,
|
||||||
() => {
|
() => {
|
||||||
getList()
|
getList()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const categoryList = ref() // 分类树
|
const categoryList = ref() // 分类树
|
||||||
/** 初始化 **/
|
/** 初始化 **/
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
Loading…
Reference in New Issue
Block a user