diff --git a/src/api/mall/product/category.ts b/src/api/mall/product/category.ts index 7ae81285..8158fc0f 100644 --- a/src/api/mall/product/category.ts +++ b/src/api/mall/product/category.ts @@ -17,17 +17,17 @@ export interface CategoryVO { */ name: string /** - * 分类图片 + * 移动端分类图 */ picUrl: string + /** + * PC 端分类图 + */ + bigPicUrl?: string /** * 分类排序 */ - sort?: number - /** - * 分类描述 - */ - description?: string + sort: number /** * 开启状态 */ diff --git a/src/api/mall/product/management/spu.ts b/src/api/mall/product/management/spu.ts new file mode 100644 index 00000000..07d7103e --- /dev/null +++ b/src/api/mall/product/management/spu.ts @@ -0,0 +1,39 @@ +import request from '@/config/axios' +import type { SpuType } from './type/spuType' // TODO @puhui999: type 和 api 一起放,简单一点哈~ + +// TODO @puhui999:中英文之间有空格 + +// 获得spu列表 TODO @puhui999:这个是 getSpuPage 哈 +export const getSpuList = (params: PageParam) => { + 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 }) +} + +// 更新商品spu +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/api/mall/product/management/type/skuType.ts b/src/api/mall/product/management/type/skuType.ts new file mode 100644 index 00000000..42889dc4 --- /dev/null +++ b/src/api/mall/product/management/type/skuType.ts @@ -0,0 +1,79 @@ +export interface Property { + /** + * 属性编号 + * + * 关联 {@link ProductPropertyDO#getId()} + */ + propertyId?: number + /** + * 属性值编号 + * + * 关联 {@link ProductPropertyValueDO#getId()} + */ + valueId?: number + /** + * 属性值名称 + */ + valueName?: string +} + +export interface SkuType { + /** + * 商品 SKU 编号,自增 + */ + id?: number + /** + * SPU 编号 + */ + spuId?: number + /** + * 属性数组,JSON 格式 + */ + properties?: Property[] + /** + * 商品价格,单位:分 + */ + price?: number + /** + * 市场价,单位:分 + */ + marketPrice?: number + /** + * 成本价,单位:分 + */ + costPrice?: number + /** + * 商品条码 + */ + barCode?: string + /** + * 图片地址 + */ + picUrl?: string + /** + * 库存 + */ + stock?: number + /** + * 商品重量,单位:kg 千克 + */ + weight?: number + /** + * 商品体积,单位:m^3 平米 + */ + volume?: number + + /** + * 一级分销的佣金,单位:分 + */ + subCommissionFirstPrice?: number + /** + * 二级分销的佣金,单位:分 + */ + subCommissionSecondPrice?: number + + /** + * 商品销量 + */ + salesCount?: number +} diff --git a/src/api/mall/product/management/type/spuType.ts b/src/api/mall/product/management/type/spuType.ts new file mode 100644 index 00000000..11c3c888 --- /dev/null +++ b/src/api/mall/product/management/type/spuType.ts @@ -0,0 +1,25 @@ +import { SkuType } from './skuType' + +export interface SpuType { + id?: number + name?: string // 商品名称 + categoryId?: number | null // 商品分类 + keyword?: string // 关键字 + unit?: number | null // 单位 + picUrl?: string // 商品封面图 + sliderPicUrls?: string[] // 商品轮播图 + introduction?: string // 商品简介 + deliveryTemplateId?: number // 运费模版 + specType?: boolean // 商品规格 + subCommissionType?: boolean // 分销类型 + skus: SkuType[] // sku数组 + description?: string // 商品详情 + sort?: string // 商品排序 + giveIntegral?: number // 赠送积分 + virtualSalesCount?: number // 虚拟销量 + recommendHot?: boolean // 是否热卖 + recommendBenefit?: boolean // 是否优惠 + recommendBest?: boolean // 是否精品 + recommendNew?: boolean // 是否新品 + recommendGood?: boolean // 是否优品 +} diff --git a/src/api/mall/product/property.ts b/src/api/mall/product/property.ts index 01c79f9f..ac8bac59 100644 --- a/src/api/mall/product/property.ts +++ b/src/api/mall/product/property.ts @@ -71,8 +71,8 @@ export const getPropertyList = (params: any) => { } // 获得属性项列表 -export const getPropertyListAndValue = (params: any) => { - return request.get({ url: '/product/property/get-value-list', params }) +export const getPropertyListAndValue = (data: any) => { + return request.post({ url: '/product/property/get-value-list', data }) } // ------------------------ 属性值 ------------------- diff --git a/src/api/mp/account/index.ts b/src/api/mp/account/index.ts index d641ef3c..e973cda3 100644 --- a/src/api/mp/account/index.ts +++ b/src/api/mp/account/index.ts @@ -1,7 +1,7 @@ import request from '@/config/axios' export interface AccountVO { - id?: number + id: number name: string } diff --git a/src/components/Form/src/helper.ts b/src/components/Form/src/helper.ts index 9cab8ff1..cdfc8caa 100644 --- a/src/components/Form/src/helper.ts +++ b/src/components/Form/src/helper.ts @@ -1,6 +1,6 @@ import type { Slots } from 'vue' import { getSlot } from '@/utils/tsxHelper' -import { PlaceholderMoel } from './types' +import { PlaceholderModel } from './types' import { FormSchema } from '@/types/form' import { ColProps } from '@/types/components' @@ -10,7 +10,7 @@ import { ColProps } from '@/types/components' * @returns 返回提示信息对象 * @description 用于自动设置placeholder */ -export const setTextPlaceholder = (schema: FormSchema): PlaceholderMoel => { +export const setTextPlaceholder = (schema: FormSchema): PlaceholderModel => { const { t } = useI18n() const textMap = ['Input', 'Autocomplete', 'InputNumber', 'InputPassword'] const selectMap = ['Select', 'SelectV2', 'TimePicker', 'DatePicker', 'TimeSelect', 'TimeSelect'] @@ -108,8 +108,8 @@ export const setItemComponentSlots = ( /** * * @param schema Form表单结构化数组 - * @param formModel FormMoel - * @returns FormMoel + * @param formModel FormModel + * @returns FormModel * @description 生成对应的formModel */ export const initModel = (schema: FormSchema[], formModel: Recordable) => { diff --git a/src/components/Form/src/types.ts b/src/components/Form/src/types.ts index 92a49d85..dcd01e78 100644 --- a/src/components/Form/src/types.ts +++ b/src/components/Form/src/types.ts @@ -1,6 +1,6 @@ import { FormSchema } from '@/types/form' -export interface PlaceholderMoel { +export interface PlaceholderModel { placeholder?: string startPlaceholder?: string endPlaceholder?: string diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts index 55e933ed..4f5a16bd 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', // TODO @puhui999:最好拆成 add 和 edit 两个路由;添加商品;修改商品 + component: () => import('@/views/mall/product/spu/addForm.vue'), + name: 'ProductManagementAdd', + meta: { + noCache: true, + hidden: true, + canTo: true, + icon: 'ep:edit', + title: '添加商品', + activeMenu: '/product/product-management' + } + } + ] } ] diff --git a/src/styles/index.scss b/src/styles/index.scss index 2781c12e..33d29123 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -10,6 +10,12 @@ width: 100% !important; } +// 解决表格内容超过表格总宽度后,横向滚动条前端顶不到表格边缘的问题 +.el-scrollbar__bar { + display: flex; + justify-content: flex-start; +} + /* nprogress 适配 element-plus 的主题色 */ #nprogress { & .bar { diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 5cda391f..e37b6abc 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -220,3 +220,21 @@ export const PayRefundStatusEnum = { name: '退款关闭' } } + +/** + * 商品SPU枚举类 + */ +export const ProductSpuStatusEnum = { + RECYCLE: { + status: -1, + name: '回收站' + }, + DISABLE: { + status: 0, + name: '下架' + }, + ENABLE: { + status: 1, + name: '上架' + } +} diff --git a/src/utils/dict.ts b/src/utils/dict.ts index 03e17e75..d11debc9 100644 --- a/src/utils/dict.ts +++ b/src/utils/dict.ts @@ -144,5 +144,9 @@ export enum DICT_TYPE { // ========== MP 模块 ========== MP_AUTO_REPLY_REQUEST_MATCH = 'mp_auto_reply_request_match', // 自动回复请求匹配类型 - MP_MESSAGE_TYPE = 'mp_message_type' // 消息类型 + MP_MESSAGE_TYPE = 'mp_message_type', // 消息类型 + + // ========== MALL 模块 ========== + PRODUCT_UNIT = 'product_unit', // 商品单位 + PRODUCT_SPU_STATUS = 'product_spu_status' //商品状态 } diff --git a/src/utils/object.ts b/src/utils/object.ts new file mode 100644 index 00000000..6612da74 --- /dev/null +++ b/src/utils/object.ts @@ -0,0 +1,18 @@ +// TODO @puhui999:这个方法,可以考虑放到 index.js +/** + * 将值复制到目标对象,且以目标对象属性为准,例: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/infra/redis/index.vue b/src/views/infra/redis/index.vue index 8315a207..011f8e59 100644 --- a/src/views/infra/redis/index.vue +++ b/src/views/infra/redis/index.vue @@ -1,7 +1,6 @@ - diff --git a/src/views/mall/product/category/CategoryForm.vue b/src/views/mall/product/category/CategoryForm.vue index 19bce872..dfe81333 100644 --- a/src/views/mall/product/category/CategoryForm.vue +++ b/src/views/mall/product/category/CategoryForm.vue @@ -4,27 +4,30 @@ ref="formRef" :model="formData" :rules="formRules" - label-width="80px" + label-width="120px" v-loading="formLoading" > - + + + + - + -
推荐 200x100 图片分辨率
-
推荐 100x100 图片分辨率
+
推荐 180x180 图片分辨率
+
+ + +
推荐 468x340 图片分辨率
@@ -40,9 +43,6 @@ - - - -