From a0014bed6529b15e07cf96413d4702c9904682a8 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Mon, 24 Apr 2023 11:42:44 +0800 Subject: [PATCH 01/13] =?UTF-8?q?=E5=95=86=E5=93=81=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E7=95=8C=E9=9D=A2=E7=BB=93=E6=9E=84=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/router/modules/remaining.ts | 31 ++- src/views/mall/product/management/addForm.vue | 53 +++++ .../management/components/BasicInfoForm.vue | 191 +++++++++++++++ .../management/components/DescriptionForm.vue | 13 + .../components/OtherSettingsForm.vue | 94 ++++++++ .../product/management/components/index.ts | 5 + src/views/mall/product/management/index.vue | 225 ++++++++++++++++++ 7 files changed, 608 insertions(+), 4 deletions(-) create mode 100644 src/views/mall/product/management/addForm.vue create mode 100644 src/views/mall/product/management/components/BasicInfoForm.vue create mode 100644 src/views/mall/product/management/components/DescriptionForm.vue create mode 100644 src/views/mall/product/management/components/OtherSettingsForm.vue create mode 100644 src/views/mall/product/management/components/index.ts create mode 100644 src/views/mall/product/management/index.vue diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts index 55e933ed..32848b9a 100644 --- a/src/router/modules/remaining.ts +++ b/src/router/modules/remaining.ts @@ -2,9 +2,9 @@ import { Layout } from '@/utils/routerHelper' const { t } = useI18n() /** -* redirect: noredirect 当设置 noredirect 的时候该路由在面包屑导航中不可被点击 -* name:'router-name' 设定路由的名字,一定要填写不然使用时会出现各种问题 -* meta : { + * redirect: noredirect 当设置 noredirect 的时候该路由在面包屑导航中不可被点击 + * name:'router-name' 设定路由的名字,一定要填写不然使用时会出现各种问题 + * meta : { hidden: true 当设置 true 的时候该路由不会再侧边栏出现 如404,login等页面(默认 false) alwaysShow: true 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式, @@ -31,7 +31,7 @@ const { t } = useI18n() canTo: true 设置为true即使hidden为true,也依然可以进行路由跳转(默认 false) } -**/ + **/ const remainingRouter: AppRouteRecordRaw[] = [ { path: '/redirect', @@ -345,6 +345,29 @@ const remainingRouter: AppRouteRecordRaw[] = [ meta: { title: '商品属性值', icon: '', activeMenu: '/product/property' } } ] + }, + { + path: '/product', + component: Layout, + name: 'ProductManagementEdit', + meta: { + hidden: true + }, + children: [ + { + path: 'productManagementAdd', + component: () => import('@/views/mall/product/management/addForm.vue'), + name: 'ProductManagementAdd', + meta: { + noCache: true, + hidden: true, + canTo: true, + icon: 'ep:edit', + title: '添加商品', + activeMenu: '/product/product-management' + } + } + ] } ] diff --git a/src/views/mall/product/management/addForm.vue b/src/views/mall/product/management/addForm.vue new file mode 100644 index 00000000..d077df5b --- /dev/null +++ b/src/views/mall/product/management/addForm.vue @@ -0,0 +1,53 @@ + + diff --git a/src/views/mall/product/management/components/BasicInfoForm.vue b/src/views/mall/product/management/components/BasicInfoForm.vue new file mode 100644 index 00000000..1b33e9eb --- /dev/null +++ b/src/views/mall/product/management/components/BasicInfoForm.vue @@ -0,0 +1,191 @@ + + + diff --git a/src/views/mall/product/management/components/DescriptionForm.vue b/src/views/mall/product/management/components/DescriptionForm.vue new file mode 100644 index 00000000..53609705 --- /dev/null +++ b/src/views/mall/product/management/components/DescriptionForm.vue @@ -0,0 +1,13 @@ + + diff --git a/src/views/mall/product/management/components/OtherSettingsForm.vue b/src/views/mall/product/management/components/OtherSettingsForm.vue new file mode 100644 index 00000000..e8152883 --- /dev/null +++ b/src/views/mall/product/management/components/OtherSettingsForm.vue @@ -0,0 +1,94 @@ + + diff --git a/src/views/mall/product/management/components/index.ts b/src/views/mall/product/management/components/index.ts new file mode 100644 index 00000000..04e6f74d --- /dev/null +++ b/src/views/mall/product/management/components/index.ts @@ -0,0 +1,5 @@ +import BasicInfoForm from './BasicInfoForm.vue' +import DescriptionForm from './DescriptionForm.vue' +import OtherSettingsForm from './OtherSettingsForm.vue' + +export { BasicInfoForm, DescriptionForm, OtherSettingsForm } diff --git a/src/views/mall/product/management/index.vue b/src/views/mall/product/management/index.vue new file mode 100644 index 00000000..4fdfed1b --- /dev/null +++ b/src/views/mall/product/management/index.vue @@ -0,0 +1,225 @@ + + From c38abc365c779528d5ea5d2926a895aa1211eaf9 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Wed, 26 Apr 2023 17:17:39 +0800 Subject: [PATCH 02/13] =?UTF-8?q?=E5=95=86=E5=93=81=E7=AE=A1=E7=90=86:=20?= =?UTF-8?q?=E5=AE=8C=E5=96=84=E8=A1=A8=E5=8D=95=E6=A0=A1=E9=AA=8C=EF=BC=8C?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BF=A1=E6=81=AF=E6=8F=90=E7=A4=BA=EF=BC=8C?= =?UTF-8?q?=E5=AE=8C=E6=88=90=E6=96=B0=E5=BB=BA=E3=80=81=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E3=80=81=E6=8F=90=E4=BA=A4=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/mall/product/management/type/index.ts | 22 ++++ src/utils/object.ts | 17 +++ src/views/mall/product/management/addForm.vue | 90 +++++++++++-- .../management/components/BasicInfoForm.vue | 118 +++++++++--------- .../management/components/DescriptionForm.vue | 82 ++++++++++-- .../components/OtherSettingsForm.vue | 87 ++++++++++--- src/views/system/dict/index.vue | 91 ++++++++------ 7 files changed, 374 insertions(+), 133 deletions(-) create mode 100644 src/api/mall/product/management/type/index.ts create mode 100644 src/utils/object.ts diff --git a/src/api/mall/product/management/type/index.ts b/src/api/mall/product/management/type/index.ts new file mode 100644 index 00000000..3d372c45 --- /dev/null +++ b/src/api/mall/product/management/type/index.ts @@ -0,0 +1,22 @@ +export interface SpuType { + name?: string // 商品名称 + categoryId?: number // 商品分类 + keyword?: string // 关键字 + unit?: string // 单位 + picUrl?: string // 商品封面图 + sliderPicUrls?: string[] // 商品轮播图 + introduction?: string // 商品简介 + deliveryTemplateId?: number // 运费模版 + selectRule?: string // 选择规格 TODO 暂时定义 + specType?: boolean // 商品规格 + subCommissionType?: boolean // 分销类型 + description?: string // 商品详情 + sort?: string // 商品排序 + giveIntegral?: number // 赠送积分 + virtualSalesCount?: number // 虚拟销量 + recommendHot?: boolean // 是否热卖 + recommendBenefit?: boolean // 是否优惠 + recommendBest?: boolean // 是否精品 + recommendNew?: boolean // 是否新品 + recommendGood?: boolean // 是否优品 +} diff --git a/src/utils/object.ts b/src/utils/object.ts new file mode 100644 index 00000000..8edd1888 --- /dev/null +++ b/src/utils/object.ts @@ -0,0 +1,17 @@ +/** + * 将值复制到目标对象,且以目标对象属性为准,例:target: {a:1} source:{a:2,b:3} 结果为:{a:2} + * @param target 目标对象 + * @param source 源对象 + */ +export const copyValueToTarget = (target, source) => { + const newObj = Object.assign({}, target, source) + // 删除多余属性 + Object.keys(newObj).forEach((key) => { + // 如果不是target中的属性则删除 + if (Object.keys(target).indexOf(key) === -1) { + delete newObj[key] + } + }) + // 更新目标对象值 + Object.assign(target, newObj) +} diff --git a/src/views/mall/product/management/addForm.vue b/src/views/mall/product/management/addForm.vue index d077df5b..f915b204 100644 --- a/src/views/mall/product/management/addForm.vue +++ b/src/views/mall/product/management/addForm.vue @@ -2,13 +2,25 @@ - + - + - + @@ -22,6 +34,7 @@ - diff --git a/src/views/mall/product/management/components/DescriptionForm.vue b/src/views/mall/product/management/components/DescriptionForm.vue index 53609705..f29f29b4 100644 --- a/src/views/mall/product/management/components/DescriptionForm.vue +++ b/src/views/mall/product/management/components/DescriptionForm.vue @@ -1,13 +1,79 @@ diff --git a/src/views/mall/product/management/components/OtherSettingsForm.vue b/src/views/mall/product/management/components/OtherSettingsForm.vue index e8152883..155a0aba 100644 --- a/src/views/mall/product/management/components/OtherSettingsForm.vue +++ b/src/views/mall/product/management/components/OtherSettingsForm.vue @@ -1,19 +1,19 @@ diff --git a/src/views/mall/product/management/components/ProductAttributesAddForm.vue b/src/views/mall/product/management/components/ProductAttributesAddForm.vue index 70fd2824..f498b7dd 100644 --- a/src/views/mall/product/management/components/ProductAttributesAddForm.vue +++ b/src/views/mall/product/management/components/ProductAttributesAddForm.vue @@ -62,7 +62,7 @@ const submitForm = async () => { const propertyId = await PropertyApi.createProperty(data) emit('success', { id: propertyId, ...formData.value, values: [] }) } else { - emit(res[0]) // 因为只用一个 + emit('success', res[0]) // 因为只用一个 } message.success(t('common.createSuccess')) dialogVisible.value = false From 538d1e0b6cc997e701a6c7cc22b6550ddf21cd42 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sun, 30 Apr 2023 02:26:35 +0800 Subject: [PATCH 06/13] =?UTF-8?q?=E5=95=86=E5=93=81=E7=AE=A1=E7=90=86:=20f?= =?UTF-8?q?ix:=E6=A0=B9=E6=8D=AE=E5=95=86=E5=93=81=E5=B1=9E=E6=80=A7?= =?UTF-8?q?=E5=8A=A8=E6=80=81=E7=94=9F=E6=88=90=E8=A1=A8=E6=A0=BC=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mall/product/management/type/spuType.ts | 1 - .../management/components/BasicInfoForm.vue | 39 +++--- .../components/ProductAttributes.vue | 4 +- .../components/ProductAttributesAddForm.vue | 3 + .../management/components/SkuList/index.vue | 129 ++++++++++++++++-- 5 files changed, 140 insertions(+), 36 deletions(-) diff --git a/src/api/mall/product/management/type/spuType.ts b/src/api/mall/product/management/type/spuType.ts index f51bc526..5d9b65ef 100644 --- a/src/api/mall/product/management/type/spuType.ts +++ b/src/api/mall/product/management/type/spuType.ts @@ -9,7 +9,6 @@ export interface SpuType { sliderPicUrls?: string[] // 商品轮播图 introduction?: string // 商品简介 deliveryTemplateId?: number // 运费模版 - selectRule?: string // 选择规格 TODO 暂时定义 specType?: boolean // 商品规格 subCommissionType?: boolean // 分销类型 skus?: SkuType[] // sku数组 diff --git a/src/views/mall/product/management/components/BasicInfoForm.vue b/src/views/mall/product/management/components/BasicInfoForm.vue index 90f7c0df..d06a787d 100644 --- a/src/views/mall/product/management/components/BasicInfoForm.vue +++ b/src/views/mall/product/management/components/BasicInfoForm.vue @@ -60,7 +60,7 @@ - + 单规格 多规格 @@ -76,12 +76,17 @@ - - 添加规格 + + 添加规格 + + + + - + @@ -110,14 +115,8 @@ const props = defineProps({ }) const AttributesAddFormRef = ref() // 添加商品属性表单 const ProductManagementBasicInfoRef = ref() // 表单Ref -// 属性列表 -const attributeList = ref([ - { - id: 1, - name: '颜色', - values: [{ id: 1, name: '白色' }] - } -]) +const attributeList = ref([]) // 商品属性列表 +/** 添加商品属性 */ const addAttribute = (property: any) => { attributeList.value.push(property) } @@ -176,10 +175,10 @@ const rules = reactive({ unit: [required], introduction: [required], picUrl: [required], - sliderPicUrls: [required] + sliderPicUrls: [required], // deliveryTemplateId: [required], - // specType: [required], - // subCommissionType: [required], + specType: [required], + subCommissionType: [required] }) /** * 将传进来的值赋值给formData @@ -215,10 +214,7 @@ const validate = async () => { }) } defineExpose({ validate }) -// 选择规格 -const changeSpecType = (specType) => { - console.log(specType) -} + // 分销类型 const changeSubCommissionType = () => { // 默认为零,类型切换后也要重置为零 @@ -227,10 +223,7 @@ const changeSubCommissionType = () => { item.subCommissionSecondPrice = 0 } } -// 选择属性确认 -// const confirm = () => {} -// 添加规格 -// const addRule = () => {} + const categoryList = ref() // 分类树 onMounted(async () => { // 获得分类树 diff --git a/src/views/mall/product/management/components/ProductAttributes.vue b/src/views/mall/product/management/components/ProductAttributes.vue index 120ffd36..ea9b311a 100644 --- a/src/views/mall/product/management/components/ProductAttributes.vue +++ b/src/views/mall/product/management/components/ProductAttributes.vue @@ -49,10 +49,10 @@ const inputVisible = computed(() => (index) => { if (attributeIndex.value === index) return true }) const InputRef = ref() //标签输入框Ref -const attributeList = ref([]) +const attributeList = ref([]) // 商品属性列表 const props = defineProps({ attributeData: { - type: Object, + type: Array, default: () => {} } }) diff --git a/src/views/mall/product/management/components/ProductAttributesAddForm.vue b/src/views/mall/product/management/components/ProductAttributesAddForm.vue index f498b7dd..bd715dde 100644 --- a/src/views/mall/product/management/components/ProductAttributesAddForm.vue +++ b/src/views/mall/product/management/components/ProductAttributesAddForm.vue @@ -62,6 +62,9 @@ const submitForm = async () => { const propertyId = await PropertyApi.createProperty(data) emit('success', { id: propertyId, ...formData.value, values: [] }) } else { + if (res[0].values === null) { + res[0].values = [] + } emit('success', res[0]) // 因为只用一个 } message.success(t('common.createSuccess')) diff --git a/src/views/mall/product/management/components/SkuList/index.vue b/src/views/mall/product/management/components/SkuList/index.vue index fd148126..a3ecd9dd 100644 --- a/src/views/mall/product/management/components/SkuList/index.vue +++ b/src/views/mall/product/management/components/SkuList/index.vue @@ -1,10 +1,21 @@ - @@ -166,7 +191,8 @@ const headerNum = ref([ type: 5 } ]) -const imgViewVisible = ref(false) +const imgViewVisible = ref(false) // 商品图预览 +const imageViewerList = ref([]) // 商品图预览列表 const queryParams = reactive({ pageNo: 1, pageSize: 10 @@ -184,7 +210,21 @@ const getList = async () => { loading.value = false } } - +/** + * 更改SPU状态 + * @param row + */ +const changeStatus = (row) => { + console.log(row) +} +/** + * 商品图预览 + * @param imgUrl + */ +const imagePreview = (imgUrl: string) => { + imageViewerList.value = [imgUrl] + imgViewVisible.value = true +} /** 搜索按钮操作 */ const handleQuery = () => { getList() @@ -196,26 +236,18 @@ const resetQuery = () => { handleQuery() } +/** + * 新增或修改 + * @param id + */ const openForm = (id?: number) => { if (typeof id === 'number') { push('/product/productManagementAdd?id=' + id) + return } push('/product/productManagementAdd') } -/** 删除按钮操作 */ -// const handleDelete = async (id: number) => { -// try { -// // 删除的二次确认 -// await message.delConfirm() -// // 发起删除 -// await ProductBrandApi.deleteBrand(id) -// message.success(t('common.delSuccess')) -// // 刷新列表 -// await getList() -// } catch {} -// } - /** 初始化 **/ onMounted(() => { getList() From 0c6e3a39c95190bb54538d548c4df4f0ff4d57b4 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Thu, 4 May 2023 01:38:53 +0800 Subject: [PATCH 13/13] =?UTF-8?q?=E5=95=86=E5=93=81=E7=AE=A1=E7=90=86:=20?= =?UTF-8?q?=E6=89=93=E9=80=9A=E6=89=80=E6=9C=89=E6=8E=A5=E5=8F=A3=EF=BC=88?= =?UTF-8?q?=E7=AC=AC=E4=B8=80=E7=89=88=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/mall/product/management/spu.ts | 12 + src/utils/constants.ts | 17 ++ src/views/mall/product/management/addForm.vue | 9 +- .../components/OtherSettingsForm.vue | 1 + .../product/management/components/SkuList.vue | 3 - src/views/mall/product/management/index.vue | 234 +++++++++++++----- 6 files changed, 206 insertions(+), 70 deletions(-) diff --git a/src/api/mall/product/management/spu.ts b/src/api/mall/product/management/spu.ts index 007963bb..2aa83e7a 100644 --- a/src/api/mall/product/management/spu.ts +++ b/src/api/mall/product/management/spu.ts @@ -5,6 +5,10 @@ import type { SpuType } from './type/spuType' export const getSpuList = (params: any) => { return request.get({ url: '/product/spu/page', params }) } +// 获得spu列表tabsCount +export const getTabsCount = () => { + return request.get({ url: '/product/spu/tabsCount' }) +} // 创建商品spu export const createSpu = (data: SpuType) => { return request.post({ url: '/product/spu/create', data }) @@ -13,7 +17,15 @@ export const createSpu = (data: SpuType) => { export const updateSpu = (data: SpuType) => { return request.put({ url: '/product/spu/update', data }) } +// 更新商品spu status +export const updateStatus = (data: { id: number; status: number }) => { + return request.put({ url: '/product/spu/updateStatus', data }) +} // 获得商品spu export const getSpu = (id: number) => { return request.get({ url: `/product/spu/get-detail?id=${id}` }) } +// 删除商品Spu +export const deleteSpu = (id: number) => { + return request.delete({ url: `/product/spu/delete?id=${id}` }) +} diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 5cda391f..597064ee 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -220,3 +220,20 @@ export const PayRefundStatusEnum = { name: '退款关闭' } } +/** + * 商品SPU枚举类 + */ +export const ProductSpuStatusEnum = { + RECYCLE: { + status: -1, + name: '回收站' + }, + DISABLE: { + status: 0, + name: '下架' + }, + ENABLE: { + status: 1, + name: '上架' + } +} diff --git a/src/views/mall/product/management/addForm.vue b/src/views/mall/product/management/addForm.vue index 27f8a8ae..7f31871f 100644 --- a/src/views/mall/product/management/addForm.vue +++ b/src/views/mall/product/management/addForm.vue @@ -144,7 +144,7 @@ const getDetail = async () => { const submitForm = async () => { // 提交请求 formLoading.value = true - const newSkus = [...formData.value.skus] //复制一份skus保存失败时使用 + const newSkus = JSON.parse(JSON.stringify(formData.value.skus)) //深拷贝一份skus保存失败时使用 // TODO 三个表单逐一校验,如果有一个表单校验不通过则切换到对应表单,如果有两个及以上的情况则切换到最前面的一个并弹出提示消息 // 校验各表单 try { @@ -184,9 +184,12 @@ const submitForm = async () => { await managementApi.updateSpu(data) message.success(t('common.updateSuccess')) } + close() } catch (e) { - console.log(e) - console.log(newSkus) + // 如果是后端校验失败,恢复skus数据 + if (typeof e === 'string') { + formData.value.skus = newSkus + } } finally { formLoading.value = false } diff --git a/src/views/mall/product/management/components/OtherSettingsForm.vue b/src/views/mall/product/management/components/OtherSettingsForm.vue index 4469962d..bd0ca26d 100644 --- a/src/views/mall/product/management/components/OtherSettingsForm.vue +++ b/src/views/mall/product/management/components/OtherSettingsForm.vue @@ -117,6 +117,7 @@ watch( (data) => { if (!data) return copyValueToTarget(formData.value, data) + // TODO 如果先修改其他设置的值,再改变商品详情或是商品信息会重置其他设置页面中的相关值 下一个版本修复 checkboxGroup.value = [] formData.value.recommendHot ? checkboxGroup.value.push('recommendHot') : '' formData.value.recommendBenefit ? checkboxGroup.value.push('recommendBenefit') : '' diff --git a/src/views/mall/product/management/components/SkuList.vue b/src/views/mall/product/management/components/SkuList.vue index 2a7441cc..3311202a 100644 --- a/src/views/mall/product/management/components/SkuList.vue +++ b/src/views/mall/product/management/components/SkuList.vue @@ -206,9 +206,6 @@ const generateTableData = (data: any[]) => { } const buildList = build(propertiesItemList) // 如果构建后的组合数跟sku数量一样的话则不用处理,添加新属性没有属性值也不做处理 (解决编辑表单时或查看详情时数据回显问题) - console.log( - buildList.length === formData.value.skus.length || data.some((item) => item.values.length === 0) - ) if ( buildList.length === formData.value.skus.length || data.some((item) => item.values.length === 0) diff --git a/src/views/mall/product/management/index.vue b/src/views/mall/product/management/index.vue index f2e480f5..7b5fb0c1 100644 --- a/src/views/mall/product/management/index.vue +++ b/src/views/mall/product/management/index.vue @@ -57,39 +57,38 @@ - + - - - + + + + + + + + + + + + + + + + @@ -108,9 +107,9 @@