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

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

View File

@@ -24,17 +24,9 @@
>
<a-tabs type="card" v-model:active-key="active" @change="onChange">
<a-tab-pane tab="基本信息" key="base">
<a-form-item label="商品ID" name="goodsId">
{{ form.goodsId }}
</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="商品ID" name="goodsId">-->
<!-- {{ form.goodsId }}-->
<!-- </a-form-item>-->
<a-form-item label="所属栏目" name="categoryId">
<a-tree-select
allow-clear
@@ -49,6 +41,14 @@
@change="onCategoryId"
/>
</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-textarea
:rows="1"
@@ -177,13 +177,64 @@
</a-button>
</a-upload>
</a-form-item>
<a-form-item label="状态" name="isShow">
<a-radio-group v-model:value="form.isShow">
<a-radio :value="1">上架</a-radio>
<a-radio :value="0">下架</a-radio>
<a-form-item label="状态" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">上架</a-radio>
<a-radio :value="1">下架</a-radio>
</a-radio-group>
</a-form-item>
</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-form-item label="规格类型" name="specs">
<a-radio-group v-model:value="form.specs">
@@ -326,57 +377,6 @@
</div>
</a-form-item>
</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-form-item label="商品重量" name="goodsWeight">
<a-input
@@ -423,6 +423,15 @@
v-model:value="form.position"
/>
</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-switch
size="small"
@@ -439,26 +448,26 @@
:un-checked-value="0"
/>
</a-form-item>
<a-form-item label="是否开启分红功能" v-if="!merchantId">
<a-switch
size="small"
v-model:checked="form.commissionRole"
:checked-value="1"
:un-checked-value="0"
/>
</a-form-item>
<a-form-item label="角色分红配置" v-if="form.commissionRole === 1">
<a-space>
<a-input
v-model:value="form.goodsRoleCommission[index].amount"
v-for="(item, index) in form.goodsRoleCommission"
:key="index"
>
<template #addonBefore>{{ item.roleName }}</template>
<template #addonAfter></template>
</a-input>
</a-space>
</a-form-item>
<!-- <a-form-item label="是否开启分红功能" v-if="!merchantId">-->
<!-- <a-switch-->
<!-- size="small"-->
<!-- v-model:checked="form.commissionRole"-->
<!-- :checked-value="1"-->
<!-- :un-checked-value="0"-->
<!-- />-->
<!-- </a-form-item>-->
<!-- <a-form-item label="角色分红配置" v-if="form.commissionRole === 1">-->
<!-- <a-space>-->
<!-- <a-input-->
<!-- v-model:value="form.goodsRoleCommission[index].amount"-->
<!-- v-for="(item, index) in form.goodsRoleCommission"-->
<!-- :key="index"-->
<!-- >-->
<!-- <template #addonBefore>{{ item.roleName }}</template>-->
<!-- <template #addonAfter></template>-->
<!-- </a-input>-->
<!-- </a-space>-->
<!-- </a-form-item>-->
<a-divider orientation="left">分销设置</a-divider>
<a-form-item label="是否开启分销" name="isOpenCommission">
@@ -473,7 +482,7 @@
<a-form-item label="分佣类型" name="commissionType">
<a-radio-group v-model:value="form.commissionType">
<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-form-item>
<a-form-item
@@ -483,7 +492,7 @@
<a-input-number
v-model:value="form.firstMoney"
:min="0"
:max="form.commissionType === 20 ? 1 : undefined"
:max="form.commissionType === 20 ? 100 : undefined"
:precision="2"
style="width: 250px"
:placeholder="
@@ -493,8 +502,9 @@
"
>
<template #addonAfter>{{
form.commissionType === 20 ? '%' : '元'
}}</template>
form.commissionType === 20 ? '%' : '元'
}}
</template>
</a-input-number>
</a-form-item>
<a-form-item
@@ -504,7 +514,7 @@
<a-input-number
v-model:value="form.secondMoney"
:min="0"
:max="form.commissionType === 20 ? 1 : undefined"
:max="form.commissionType === 20 ? 100 : undefined"
:precision="2"
style="width: 250px"
:placeholder="
@@ -514,57 +524,60 @@
"
>
<template #addonAfter>{{
form.commissionType === 20 ? '%' : '元'
}}</template>
form.commissionType === 20 ? '%' : '元'
}}
</template>
</a-input-number>
</a-form-item>
<!-- <a-form-item-->
<!-- :label="form.commissionType === 20 ? '三级佣金(%)' : '三级佣金(元)'"-->
<!-- name="thirdMoney"-->
<!-- >-->
<!-- <a-input-number-->
<!-- v-model:value="form.thirdMoney"-->
<!-- :min="0"-->
<!-- :max="form.commissionType === 20 ? 100 : undefined"-->
<!-- :precision="2"-->
<!-- style="width: 250px"-->
<!-- :placeholder="-->
<!-- form.commissionType === 20-->
<!-- ? '请输入三级佣金百分比'-->
<!-- : '请输入三级佣金金额'-->
<!-- "-->
<!-- >-->
<!-- <template #addonAfter>{{-->
<!-- form.commissionType === 20 ? '%' : '元'-->
<!-- }}</template>-->
<!-- </a-input-number>-->
<!-- </a-form-item>-->
<!-- <a-form-item-->
<!-- :label="form.commissionType === 20 ? '三级佣金(%)' : '三级佣金(元)'"-->
<!-- name="thirdMoney"-->
<!-- >-->
<!-- <a-input-number-->
<!-- v-model:value="form.thirdMoney"-->
<!-- :min="0"-->
<!-- :max="form.commissionType === 20 ? 100 : undefined"-->
<!-- :precision="2"-->
<!-- style="width: 250px"-->
<!-- :placeholder="-->
<!-- form.commissionType === 20-->
<!-- ? '请输入三级佣金百分比'-->
<!-- : '请输入三级佣金金额'-->
<!-- "-->
<!-- >-->
<!-- <template #addonAfter>{{-->
<!-- form.commissionType === 20 ? '%' : '元'-->
<!-- }}</template>-->
<!-- </a-input-number>-->
<!-- </a-form-item>-->
<a-form-item label="一级分红" name="firstDividend">
<a-input-number
v-model:value="form.firstDividend"
:min="0"
:max="form.commissionType === 20 ? 1 : undefined"
:max="form.commissionType === 20 ? 100 : undefined"
:precision="2"
style="width: 250px"
placeholder="请输入一级分红"
>
<template #addonAfter>{{
form.commissionType === 20 ? '%' : '元'
}}</template>
}}
</template>
</a-input-number>
</a-form-item>
<a-form-item label="二级分红" name="secondDividend">
<a-input-number
v-model:value="form.secondDividend"
:min="0"
:max="form.commissionType === 20 ? 1 : undefined"
:max="form.commissionType === 20 ? 100 : undefined"
:precision="2"
style="width: 250px"
placeholder="请输入二级分红"
>
<template #addonAfter>{{
form.commissionType === 20 ? '%' : '元'
}}</template>
}}
</template>
</a-input-number>
</a-form-item>
</template>
@@ -614,15 +627,6 @@
/>
</a-form-item>
</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-tabs>
</a-form>
@@ -1827,6 +1831,33 @@ const onPaste = (e) => {
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 = () => {
if (!formRef.value) {
@@ -1851,14 +1882,11 @@ const save = () => {
form.secondDividend = 0;
}
if (form.isOpenCommission === 1 && form.commissionType === 20) {
// 百分比:约定 0-100后端如用万分比/小数可再调整
const invalidPercent =
(form.firstMoney ?? 0) > 100 ||
(form.secondMoney ?? 0) > 100 ||
(form.thirdMoney ?? 0) > 100 ||
(form.firstMoney ?? 0) < 0 ||
(form.secondMoney ?? 0) < 0 ||
(form.thirdMoney ?? 0) < 0;
// UI 输入0~100保存到后端0~1例如 10% => 0.1
const invalidPercent = COMMISSION_PERCENT_FIELDS.some((k) => {
const v = (form as any)[k] ?? 0;
return v < 0 || v > 100;
});
if (invalidPercent) {
return message.error('佣金百分比需在 0~100 之间');
}
@@ -1890,6 +1918,14 @@ const save = () => {
if (isUpdate.value) {
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;
saveOrUpdate(formData)
.then((msg) => {
@@ -2018,6 +2054,14 @@ watch(
if (form.commissionType === undefined || form.commissionType === null) {
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) {
images.value.push({
uid: uuid(),

View File

@@ -49,7 +49,7 @@
</a-space>
</template>
<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 === 2" color="purple">待审核</a-tag>
<a-tag v-if="record.status === 3" color="red">审核不通过</a-tag>