refactor(shop): 更新商品管理模块的数据类型和界面显示

- 将商品模型中的 isShow 字段从 number 类型改为 boolean 类型
- 在导航组件中同时显示模型名称和编号信息
- 将商品状态标签从"出售中"改为"已上架"以保持一致性
- 移除经销商提现表单中的微信账户输入字段并更新描述信息
- 调整商品编辑页面的表单项顺序和布局结构
- 新增商品详情编辑功能,支持富文本和 Markdown 编辑器
- 添加商品排序号字段和分销设置相关功能
- 优化佣金百分比计算逻辑,统一数值转换处理
- 修复分佣金额验证规则,将最大值从 1 调整为 100
This commit is contained in:
2026-01-29 16:33:32 +08:00
parent 51c6f3fa2f
commit ec8cc3a8de
5 changed files with 197 additions and 152 deletions

View File

@@ -94,7 +94,7 @@ export interface ShopGoods {
supplierMerchantId?: number; supplierMerchantId?: number;
supplierName?: string; supplierName?: string;
// 状态0未上架1上架 // 状态0未上架1上架
isShow?: number; isShow?: boolean;
// 状态, 0上架 1待上架 2待审核 3审核不通过 // 状态, 0上架 1待上架 2待审核 3审核不通过
status?: number; status?: number;
// 备注 // 备注

View File

@@ -149,7 +149,8 @@
</template> </template>
</template> </template>
<template v-if="column.key === 'model'"> <template v-if="column.key === 'model'">
<text class="ele-text-placeholder">{{ record.model }}</text>
<text class="ele-text-placeholder"><span>{{ record.modelName }}({{ record.model }})</span></text>
</template> </template>
<template v-if="column.key === 'type'"> <template v-if="column.key === 'type'">
<a-tag v-if="isExternalLink(record.path)" color="purple" <a-tag v-if="isExternalLink(record.path)" color="purple"

View File

@@ -38,23 +38,23 @@
<div v-if="form.payType === 10" class="payment-info wechat-info"> <div v-if="form.payType === 10" class="payment-info wechat-info">
<a-alert <a-alert
message="微信收款信息" message="微信收款信息"
description="请确保微信账号信息准确,以免影响到账" description="选择审核通过/已打款,立即向用户发起转账"
type="success" type="success"
show-icon show-icon
style="margin-bottom: 16px" style="margin-bottom: 16px"
/> />
<a-form-item label="微信号" name="wechatAccount"> <!-- <a-form-item label="微信号" name="wechatAccount">-->
<a-input <!-- <a-input-->
placeholder="请输入微信号" <!-- placeholder="请输入微信号"-->
v-model:value="form.wechatAccount" <!-- v-model:value="form.wechatAccount"-->
/> <!-- />-->
</a-form-item> <!-- </a-form-item>-->
<a-form-item label="微信昵称" name="wechatName"> <!-- <a-form-item label="微信昵称" name="wechatName">-->
<a-input <!-- <a-input-->
placeholder="请输入微信昵称" <!-- placeholder="请输入微信昵称"-->
v-model:value="form.wechatName" <!-- v-model:value="form.wechatName"-->
/> <!-- />-->
</a-form-item> <!-- </a-form-item>-->
</div> </div>
<!-- 支付宝收款信息 --> <!-- 支付宝收款信息 -->
@@ -171,7 +171,7 @@
<a-form-item <a-form-item
label="上传支付凭证" label="上传支付凭证"
name="image" name="image"
v-if="form.applyStatus === 40" v-if="form.applyStatus === 40 && form.payType !== 10"
> >
<SelectFile <SelectFile
:placeholder="`请选择图片`" :placeholder="`请选择图片`"

View File

@@ -24,17 +24,9 @@
> >
<a-tabs type="card" v-model:active-key="active" @change="onChange"> <a-tabs type="card" v-model:active-key="active" @change="onChange">
<a-tab-pane tab="基本信息" key="base"> <a-tab-pane tab="基本信息" key="base">
<a-form-item label="商品ID" name="goodsId"> <!-- <a-form-item label="商品ID" name="goodsId">-->
{{ form.goodsId }} <!-- {{ form.goodsId }}-->
</a-form-item> <!-- </a-form-item>-->
<a-form-item label="商品名称" name="name">
<a-input
allow-clear
style="width: 558px"
placeholder="请输入商品名称"
v-model:value="form.name"
/>
</a-form-item>
<a-form-item label="所属栏目" name="categoryId"> <a-form-item label="所属栏目" name="categoryId">
<a-tree-select <a-tree-select
allow-clear allow-clear
@@ -49,6 +41,14 @@
@change="onCategoryId" @change="onCategoryId"
/> />
</a-form-item> </a-form-item>
<a-form-item label="商品名称" name="name">
<a-input
allow-clear
style="width: 558px"
placeholder="请输入商品名称"
v-model:value="form.name"
/>
</a-form-item>
<a-form-item label="商品卖点" name="comments"> <a-form-item label="商品卖点" name="comments">
<a-textarea <a-textarea
:rows="1" :rows="1"
@@ -177,13 +177,64 @@
</a-button> </a-button>
</a-upload> </a-upload>
</a-form-item> </a-form-item>
<a-form-item label="状态" name="isShow"> <a-form-item label="状态" name="status">
<a-radio-group v-model:value="form.isShow"> <a-radio-group v-model:value="form.status">
<a-radio :value="1">上架</a-radio> <a-radio :value="0">上架</a-radio>
<a-radio :value="0">下架</a-radio> <a-radio :value="1">下架</a-radio>
</a-radio-group> </a-radio-group>
</a-form-item> </a-form-item>
</a-tab-pane> </a-tab-pane>
<a-tab-pane tab="商品详情" key="content">
<!-- 富文本编辑器 -->
<div v-if="editor == 1">
<tinymce-editor
ref="editorRef"
class="editor-content"
v-model:value="content"
:disabled="disabled"
:init="config"
placeholder="支持直接粘贴或拖拽图片,也可点击工具栏图片按钮从文件库选择"
/>
<div class="file-selector-tip">
💡 提示工具栏"图片"按钮从图片库选择"上传"按钮快速上传图片"视频"按钮从视频库选择"上传视频"按钮快速上传视频"一键排版"按钮自动优化文章格式"首行缩进"按钮切换段落缩进
</div>
</div>
<!-- Markdown编辑器 -->
<div v-if="editor == 2">
<!-- 📝 Markdown编辑器工具栏扩展 -->
<div class="markdown-toolbar-extension">
<a-button
type="primary"
size="small"
@click="openMarkdownImageSelector"
style="margin-right: 8px;"
>
📷 从图片库选择
</a-button>
<a-button
type="default"
size="small"
@click="openMarkdownVideoSelector"
style="margin-right: 8px;"
>
🎬 从视频库选择
</a-button>
</div>
<MdEditor
v-model="content"
:disabled="disabled"
height="500px"
:placeholder="'请输入Markdown内容...'"
:toolbars="markdownToolbars"
:onUploadImg="onMarkdownUploadImg"
/>
<div class="file-selector-tip">
💡 提示支持Markdown语法可以使用工具栏按钮从文件库选择图片/视频也可以直接拖拽上传文件
</div>
</div>
</a-tab-pane>
<a-tab-pane tab="商品规格" key="spec"> <a-tab-pane tab="商品规格" key="spec">
<a-form-item label="规格类型" name="specs"> <a-form-item label="规格类型" name="specs">
<a-radio-group v-model:value="form.specs"> <a-radio-group v-model:value="form.specs">
@@ -326,57 +377,6 @@
</div> </div>
</a-form-item> </a-form-item>
</a-tab-pane> </a-tab-pane>
<a-tab-pane tab="商品详情" key="content">
<!-- 富文本编辑器 -->
<div v-if="editor == 1">
<tinymce-editor
ref="editorRef"
class="editor-content"
v-model:value="content"
:disabled="disabled"
:init="config"
placeholder="支持直接粘贴或拖拽图片,也可点击工具栏图片按钮从文件库选择"
/>
<div class="file-selector-tip">
💡 提示工具栏"图片"按钮从图片库选择"上传"按钮快速上传图片"视频"按钮从视频库选择"上传视频"按钮快速上传视频"一键排版"按钮自动优化文章格式"首行缩进"按钮切换段落缩进
</div>
</div>
<!-- Markdown编辑器 -->
<div v-if="editor == 2">
<!-- 📝 Markdown编辑器工具栏扩展 -->
<div class="markdown-toolbar-extension">
<a-button
type="primary"
size="small"
@click="openMarkdownImageSelector"
style="margin-right: 8px;"
>
📷 从图片库选择
</a-button>
<a-button
type="default"
size="small"
@click="openMarkdownVideoSelector"
style="margin-right: 8px;"
>
🎬 从视频库选择
</a-button>
</div>
<MdEditor
v-model="content"
:disabled="disabled"
height="500px"
:placeholder="'请输入Markdown内容...'"
:toolbars="markdownToolbars"
:onUploadImg="onMarkdownUploadImg"
/>
<div class="file-selector-tip">
💡 提示支持Markdown语法可以使用工具栏按钮从文件库选择图片/视频也可以直接拖拽上传文件
</div>
</div>
</a-tab-pane>
<a-tab-pane tab="营销设置" key="coupon"> <a-tab-pane tab="营销设置" key="coupon">
<a-form-item label="商品重量" name="goodsWeight"> <a-form-item label="商品重量" name="goodsWeight">
<a-input <a-input
@@ -423,6 +423,15 @@
v-model:value="form.position" v-model:value="form.position"
/> />
</a-form-item> </a-form-item>
<a-form-item label="排序号" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
style="width: 250px"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="是否可以快递配送"> <a-form-item label="是否可以快递配送">
<a-switch <a-switch
size="small" size="small"
@@ -439,26 +448,26 @@
:un-checked-value="0" :un-checked-value="0"
/> />
</a-form-item> </a-form-item>
<a-form-item label="是否开启分红功能" v-if="!merchantId"> <!-- <a-form-item label="是否开启分红功能" v-if="!merchantId">-->
<a-switch <!-- <a-switch-->
size="small" <!-- size="small"-->
v-model:checked="form.commissionRole" <!-- v-model:checked="form.commissionRole"-->
:checked-value="1" <!-- :checked-value="1"-->
:un-checked-value="0" <!-- :un-checked-value="0"-->
/> <!-- />-->
</a-form-item> <!-- </a-form-item>-->
<a-form-item label="角色分红配置" v-if="form.commissionRole === 1"> <!-- <a-form-item label="角色分红配置" v-if="form.commissionRole === 1">-->
<a-space> <!-- <a-space>-->
<a-input <!-- <a-input-->
v-model:value="form.goodsRoleCommission[index].amount" <!-- v-model:value="form.goodsRoleCommission[index].amount"-->
v-for="(item, index) in form.goodsRoleCommission" <!-- v-for="(item, index) in form.goodsRoleCommission"-->
:key="index" <!-- :key="index"-->
> <!-- >-->
<template #addonBefore>{{ item.roleName }}</template> <!-- <template #addonBefore>{{ item.roleName }}</template>-->
<template #addonAfter></template> <!-- <template #addonAfter></template>-->
</a-input> <!-- </a-input>-->
</a-space> <!-- </a-space>-->
</a-form-item> <!-- </a-form-item>-->
<a-divider orientation="left">分销设置</a-divider> <a-divider orientation="left">分销设置</a-divider>
<a-form-item label="是否开启分销" name="isOpenCommission"> <a-form-item label="是否开启分销" name="isOpenCommission">
@@ -473,7 +482,7 @@
<a-form-item label="分佣类型" name="commissionType"> <a-form-item label="分佣类型" name="commissionType">
<a-radio-group v-model:value="form.commissionType"> <a-radio-group v-model:value="form.commissionType">
<a-radio :value="10">固定金额</a-radio> <a-radio :value="10">固定金额</a-radio>
<a-radio :value="20">百分比(0.1代表10%)</a-radio> <a-radio :value="20">百分比</a-radio>
</a-radio-group> </a-radio-group>
</a-form-item> </a-form-item>
<a-form-item <a-form-item
@@ -483,7 +492,7 @@
<a-input-number <a-input-number
v-model:value="form.firstMoney" v-model:value="form.firstMoney"
:min="0" :min="0"
:max="form.commissionType === 20 ? 1 : undefined" :max="form.commissionType === 20 ? 100 : undefined"
:precision="2" :precision="2"
style="width: 250px" style="width: 250px"
:placeholder=" :placeholder="
@@ -493,8 +502,9 @@
" "
> >
<template #addonAfter>{{ <template #addonAfter>{{
form.commissionType === 20 ? '%' : '元' form.commissionType === 20 ? '%' : '元'
}}</template> }}
</template>
</a-input-number> </a-input-number>
</a-form-item> </a-form-item>
<a-form-item <a-form-item
@@ -504,7 +514,7 @@
<a-input-number <a-input-number
v-model:value="form.secondMoney" v-model:value="form.secondMoney"
:min="0" :min="0"
:max="form.commissionType === 20 ? 1 : undefined" :max="form.commissionType === 20 ? 100 : undefined"
:precision="2" :precision="2"
style="width: 250px" style="width: 250px"
:placeholder=" :placeholder="
@@ -514,57 +524,60 @@
" "
> >
<template #addonAfter>{{ <template #addonAfter>{{
form.commissionType === 20 ? '%' : '元' form.commissionType === 20 ? '%' : '元'
}}</template> }}
</template>
</a-input-number> </a-input-number>
</a-form-item> </a-form-item>
<!-- <a-form-item--> <!-- <a-form-item-->
<!-- :label="form.commissionType === 20 ? '三级佣金(%)' : '三级佣金(元)'"--> <!-- :label="form.commissionType === 20 ? '三级佣金(%)' : '三级佣金(元)'"-->
<!-- name="thirdMoney"--> <!-- name="thirdMoney"-->
<!-- >--> <!-- >-->
<!-- <a-input-number--> <!-- <a-input-number-->
<!-- v-model:value="form.thirdMoney"--> <!-- v-model:value="form.thirdMoney"-->
<!-- :min="0"--> <!-- :min="0"-->
<!-- :max="form.commissionType === 20 ? 100 : undefined"--> <!-- :max="form.commissionType === 20 ? 100 : undefined"-->
<!-- :precision="2"--> <!-- :precision="2"-->
<!-- style="width: 250px"--> <!-- style="width: 250px"-->
<!-- :placeholder="--> <!-- :placeholder="-->
<!-- form.commissionType === 20--> <!-- form.commissionType === 20-->
<!-- ? '请输入三级佣金百分比'--> <!-- ? '请输入三级佣金百分比'-->
<!-- : '请输入三级佣金金额'--> <!-- : '请输入三级佣金金额'-->
<!-- "--> <!-- "-->
<!-- >--> <!-- >-->
<!-- <template #addonAfter>{{--> <!-- <template #addonAfter>{{-->
<!-- form.commissionType === 20 ? '%' : '元'--> <!-- form.commissionType === 20 ? '%' : '元'-->
<!-- }}</template>--> <!-- }}</template>-->
<!-- </a-input-number>--> <!-- </a-input-number>-->
<!-- </a-form-item>--> <!-- </a-form-item>-->
<a-form-item label="一级分红" name="firstDividend"> <a-form-item label="一级分红" name="firstDividend">
<a-input-number <a-input-number
v-model:value="form.firstDividend" v-model:value="form.firstDividend"
:min="0" :min="0"
:max="form.commissionType === 20 ? 1 : undefined" :max="form.commissionType === 20 ? 100 : undefined"
:precision="2" :precision="2"
style="width: 250px" style="width: 250px"
placeholder="请输入一级分红" placeholder="请输入一级分红"
> >
<template #addonAfter>{{ <template #addonAfter>{{
form.commissionType === 20 ? '%' : '元' form.commissionType === 20 ? '%' : '元'
}}</template> }}
</template>
</a-input-number> </a-input-number>
</a-form-item> </a-form-item>
<a-form-item label="二级分红" name="secondDividend"> <a-form-item label="二级分红" name="secondDividend">
<a-input-number <a-input-number
v-model:value="form.secondDividend" v-model:value="form.secondDividend"
:min="0" :min="0"
:max="form.commissionType === 20 ? 1 : undefined" :max="form.commissionType === 20 ? 100 : undefined"
:precision="2" :precision="2"
style="width: 250px" style="width: 250px"
placeholder="请输入二级分红" placeholder="请输入二级分红"
> >
<template #addonAfter>{{ <template #addonAfter>{{
form.commissionType === 20 ? '%' : '元' form.commissionType === 20 ? '%' : '元'
}}</template> }}
</template>
</a-input-number> </a-input-number>
</a-form-item> </a-form-item>
</template> </template>
@@ -614,15 +627,6 @@
/> />
</a-form-item> </a-form-item>
</template> </template>
<a-form-item label="排序号" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
style="width: 250px"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
</a-tab-pane> </a-tab-pane>
</a-tabs> </a-tabs>
</a-form> </a-form>
@@ -1827,6 +1831,33 @@ const onPaste = (e) => {
const {resetFields} = useForm(form, rules); const {resetFields} = useForm(form, rules);
const COMMISSION_PERCENT_FIELDS = [
'firstMoney',
'secondMoney',
'thirdMoney',
'firstDividend',
'secondDividend'
] as const;
type CommissionPercentField = (typeof COMMISSION_PERCENT_FIELDS)[number];
const toDbPercent = (val: unknown) => {
if (val === null || val === undefined) return val as any;
const num = Number(val);
if (!Number.isFinite(num)) return val as any;
return num / 100;
};
// Back-end stores percent as a fraction (e.g. 0.1 = 10%); UI inputs percent (e.g. 10 = 10%).
const toUiPercent = (val: unknown) => {
if (val === null || val === undefined) return val as any;
const num = Number(val);
if (!Number.isFinite(num)) return val as any;
// If historical data is already stored as 0~1, convert to 0~100 for display.
if (num <= 1) return Number((num * 100).toFixed(2));
return num;
};
/* 保存编辑 */ /* 保存编辑 */
const save = () => { const save = () => {
if (!formRef.value) { if (!formRef.value) {
@@ -1851,14 +1882,11 @@ const save = () => {
form.secondDividend = 0; form.secondDividend = 0;
} }
if (form.isOpenCommission === 1 && form.commissionType === 20) { if (form.isOpenCommission === 1 && form.commissionType === 20) {
// 百分比:约定 0-100后端如用万分比/小数可再调整 // UI 输入0~100保存到后端0~1例如 10% => 0.1
const invalidPercent = const invalidPercent = COMMISSION_PERCENT_FIELDS.some((k) => {
(form.firstMoney ?? 0) > 100 || const v = (form as any)[k] ?? 0;
(form.secondMoney ?? 0) > 100 || return v < 0 || v > 100;
(form.thirdMoney ?? 0) > 100 || });
(form.firstMoney ?? 0) < 0 ||
(form.secondMoney ?? 0) < 0 ||
(form.thirdMoney ?? 0) < 0;
if (invalidPercent) { if (invalidPercent) {
return message.error('佣金百分比需在 0~100 之间'); return message.error('佣金百分比需在 0~100 之间');
} }
@@ -1890,6 +1918,14 @@ const save = () => {
if (isUpdate.value) { if (isUpdate.value) {
formData.type = props.data.type; formData.type = props.data.type;
} }
if (formData.isOpenCommission === 1 && formData.commissionType === 20) {
// Convert percent fields for persistence: 10 => 0.1
COMMISSION_PERCENT_FIELDS.forEach((k) => {
(formData as any)[k as CommissionPercentField] = toDbPercent(
(formData as any)[k]
);
});
}
const saveOrUpdate = isUpdate.value ? updateShopGoods : addShopGoods; const saveOrUpdate = isUpdate.value ? updateShopGoods : addShopGoods;
saveOrUpdate(formData) saveOrUpdate(formData)
.then((msg) => { .then((msg) => {
@@ -2018,6 +2054,14 @@ watch(
if (form.commissionType === undefined || form.commissionType === null) { if (form.commissionType === undefined || form.commissionType === null) {
form.commissionType = 10; form.commissionType = 10;
} }
if (form.isOpenCommission === 1 && form.commissionType === 20) {
// Convert historical DB values (0~1) to UI percent (0~100).
COMMISSION_PERCENT_FIELDS.forEach((k) => {
(form as any)[k as CommissionPercentField] = toUiPercent(
(form as any)[k]
);
});
}
if (props.data.image) { if (props.data.image) {
images.value.push({ images.value.push({
uid: uuid(), uid: uuid(),

View File

@@ -49,7 +49,7 @@
</a-space> </a-space>
</template> </template>
<template v-if="column.key === 'status'"> <template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">出售中</a-tag> <a-tag v-if="record.status === 0" color="green">已上架</a-tag>
<a-tag v-if="record.status === 1" color="orange">待上架</a-tag> <a-tag v-if="record.status === 1" color="orange">待上架</a-tag>
<a-tag v-if="record.status === 2" color="purple">待审核</a-tag> <a-tag v-if="record.status === 2" color="purple">待审核</a-tag>
<a-tag v-if="record.status === 3" color="red">审核不通过</a-tag> <a-tag v-if="record.status === 3" color="red">审核不通过</a-tag>