fix: 优化定价管理页面标签清晰度和修复产品选项显示
- 修复产品下拉选项 /undefined 问题:展平 specifications 嵌套结构 - 页面标题"定价规则管理"→"产品定价管理",副标题更直白 - "基准售价"→"售价(元/单位)",去掉"基准"修饰 - "计价类型"→"计费方式","计价单位"→"单价单位" - "公式说明"→"价格说明","含税方式"→"是否含税" - 同步更新帮助弹窗、表格表头、操作按钮、确认弹窗中的所有文案 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9c34cc3745
commit
4ed74dccb0
@ -1,15 +1,15 @@
|
||||
<!--
|
||||
PricingRulesPage.vue - 定价规则管理页面
|
||||
职责:管理产品的定价公式、供应商成本和价格层级。
|
||||
列表模式展示所有定价规则,编辑/新增模式下可配置计价类型、基准售价、
|
||||
PricingRulesPage.vue - 产品定价管理页面
|
||||
职责:管理产品的售价、供应商成本和价格层级。
|
||||
列表模式展示所有定价规则,编辑/新增模式下可配置计费方式、售价、
|
||||
公式表达式、供应商成本明细和价格层级。支持 CRUD 操作。
|
||||
-->
|
||||
<template>
|
||||
<section class="page pricing-page">
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h2>定价规则管理</h2>
|
||||
<p class="subline">管理产品的定价公式、供应商成本和价格层级,配置后业务员下单时自动报价。</p>
|
||||
<h2>产品定价管理</h2>
|
||||
<p class="subline">配置产品的售价和计费方式,配置后业务员下单时自动计算报价。</p>
|
||||
</div>
|
||||
<button class="help-btn" @click="showHelp = !showHelp" :class="{ active: showHelp }">?</button>
|
||||
</div>
|
||||
@ -28,15 +28,15 @@
|
||||
</div>
|
||||
|
||||
<div class="help-section">
|
||||
<h4>如何新增一条定价规则?</h4>
|
||||
<h4>如何新增一条定价?</h4>
|
||||
<ol>
|
||||
<li>点击<strong>"新增定价规则"</strong>按钮</li>
|
||||
<li>点击<strong>"新增定价"</strong>按钮</li>
|
||||
<li><strong>选择产品</strong>:从下拉框选择要定价的产品</li>
|
||||
<li><strong>计价类型</strong>:选择按面积(㎡)、按公斤(kg)或按件 — 选好后系统自动填好公式和单位</li>
|
||||
<li><strong>基准售价</strong>:填写每单位的对外销售价格(元/㎡、元/kg 等)</li>
|
||||
<li><strong>计费方式</strong>:选择按面积(㎡)、按公斤(kg)或按件 — 选好后系统自动填好公式和单位</li>
|
||||
<li><strong>售价(元/单位)</strong>:填写每单位的对外销售价格(元/㎡、元/kg 等)</li>
|
||||
<li>如有附加费(包边、印刷等),在下方<strong>"附加费用"</strong>区点 + 添加</li>
|
||||
<li>下方绿色<strong>预览卡片</strong>会实时显示业务员看到的效果</li>
|
||||
<li>点击<strong>"保存定价规则"</strong>完成</li>
|
||||
<li>点击<strong>"保存定价"</strong>完成</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
@ -46,10 +46,10 @@
|
||||
<thead><tr><th>字段</th><th>说明</th><th>示例</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>选择产品</td><td>要定价的产品,选好后自动填充产品名称</td><td>高温布-9018AJ</td></tr>
|
||||
<tr><td>计价类型</td><td>决定按什么维度计算价格,选好后自动填好公式</td><td>按面积(㎡) — 适合板材、布料</td></tr>
|
||||
<tr><td>基准售价</td><td>每单位的对外销售价格,系统用这个乘以用量得出客户报价</td><td>28 表示对客户报 28 元/㎡</td></tr>
|
||||
<tr><td>计价单位</td><td>配合计价类型使用,切换类型时自动更新</td><td>㎡、kg、张、米</td></tr>
|
||||
<tr><td>公式说明</td><td>显示给业务员看的计算说明文字,切换类型时自动生成</td><td>长×宽×单价</td></tr>
|
||||
<tr><td>计费方式</td><td>决定按什么维度计算价格,选好后自动填好公式</td><td>按面积(㎡) — 适合板材、布料</td></tr>
|
||||
<tr><td>售价(元/单位)</td><td>每单位的对外销售价格,系统用这个乘以用量得出客户报价</td><td>28 表示对客户报 28 元/㎡</td></tr>
|
||||
<tr><td>单价单位</td><td>配合计费方式使用,切换计费方式时自动更新</td><td>㎡、kg、张、米</td></tr>
|
||||
<tr><td>价格说明</td><td>显示给业务员看的计算说明文字,切换计费方式时自动生成</td><td>长×宽×单价</td></tr>
|
||||
<tr><td>状态</td><td>启用=正常显示可用,停用=隐藏不出现在选择列表</td><td>一般选"启用"</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@ -62,16 +62,16 @@
|
||||
<thead><tr><th>页面显示</th><th>英文字段名</th><th>含义</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>产品名称</td><td><code>product_name</code></td><td>关联的产品</td></tr>
|
||||
<tr><td>计价类型</td><td><code>pricing_type</code></td><td>area=按面积, kg=按公斤, unit=按件</td></tr>
|
||||
<tr><td>基准售价</td><td><code>base_unit_price</code></td><td>每单位的对外销售基础价格(元)</td></tr>
|
||||
<tr><td>计价单位</td><td><code>pricing_unit</code></td><td>㎡、kg、张、米</td></tr>
|
||||
<tr><td>计费方式</td><td><code>pricing_type</code></td><td>area=按面积, kg=按公斤, unit=按件</td></tr>
|
||||
<tr><td>售价(元/单位)</td><td><code>base_unit_price</code></td><td>每单位的对外销售价格(元)</td></tr>
|
||||
<tr><td>单价单位</td><td><code>pricing_unit</code></td><td>㎡、kg、张、米</td></tr>
|
||||
<tr><td>公式表达式</td><td><code>formula_expr</code></td><td>计算公式,自动填好</td></tr>
|
||||
<tr><td>公式常量</td><td><code>formula_constants</code></td><td>公式中用到的固定数值(JSON)</td></tr>
|
||||
<tr><td>输入字段配置</td><td><code>pricing_inputs</code></td><td>业务员下单时的输入项(JSON)</td></tr>
|
||||
<tr><td>附加费配置</td><td><code>surcharge_json</code></td><td>可选附加费(JSON),由附加费行自动生成</td></tr>
|
||||
<tr><td>公式说明</td><td><code>formula_note</code></td><td>显示给业务员的说明文字</td></tr>
|
||||
<tr><td>价格说明</td><td><code>formula_note</code></td><td>显示给业务员的说明文字</td></tr>
|
||||
<tr><td>税率</td><td><code>tax_rate</code></td><td>税率百分比(0=不收税)</td></tr>
|
||||
<tr><td>含税方式</td><td><code>tax_inclusive</code></td><td>0=不含税正算, 1=含税反算</td></tr>
|
||||
<tr><td>是否含税</td><td><code>tax_inclusive</code></td><td>0=不含税正算, 1=含税反算</td></tr>
|
||||
<tr><td>状态</td><td><code>status</code></td><td>1=启用, 0=停用</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@ -98,8 +98,8 @@
|
||||
<thead><tr><th>字段</th><th>说明</th><th>需要改吗</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>税率(%)</td><td>如需含税报价,填写税率百分比</td><td>需要才填</td></tr>
|
||||
<tr><td>含税方式</td><td>不含税=正算(基础价+税),含税=反算(总价反推不含税价)</td><td>一般选"不含税"</td></tr>
|
||||
<tr><td>公式表达式</td><td>系统根据计价类型自动生成的计算公式</td><td>不需要改</td></tr>
|
||||
<tr><td>是否含税</td><td>不含税=正算(售价+税),含税=反算(总价反推不含税价)</td><td>一般选"不含税"</td></tr>
|
||||
<tr><td>公式表达式</td><td>系统根据计费方式自动生成的计算公式</td><td>不需要改</td></tr>
|
||||
<tr><td>公式常量</td><td>公式中用到的固定数值(JSON格式)</td><td>不需要改</td></tr>
|
||||
<tr><td>输入字段配置</td><td>定义业务员下单时需要填写哪些参数</td><td>不需要改</td></tr>
|
||||
</tbody>
|
||||
@ -113,7 +113,7 @@
|
||||
|
||||
<div class="help-section">
|
||||
<h4>供应商成本是什么?</h4>
|
||||
<p>保存定价规则后,页面下方会出现<strong>"供应商成本"</strong>区域。在这里记录不同供应商给你的进货价,系统会自动对比成本和售价,帮你算利润。</p>
|
||||
<p>保存定价后,页面下方会出现<strong>"供应商成本"</strong>区域。在这里记录不同供应商给你的进货价,系统会自动对比成本和售价,帮你算利润。</p>
|
||||
<ul>
|
||||
<li><strong>供应商ID</strong>:对应系统中供应商的编号</li>
|
||||
<li><strong>采购单价</strong>:你从这个供应商拿货的单价</li>
|
||||
@ -136,7 +136,7 @@
|
||||
<h4>常见问题</h4>
|
||||
<ul>
|
||||
<li><strong>Q: 新增后列表里看不到?</strong><br>A: 确认状态选的是"启用",并点击了"查询"刷新列表。</li>
|
||||
<li><strong>Q: 切换计价类型后之前的单价被覆盖了?</strong><br>A: 切换类型会自动更新公式和单位,但<strong>不会清空单价</strong>,需要手动填新的单价。</li>
|
||||
<li><strong>Q: 切换计费方式后之前的单价被覆盖了?</strong><br>A: 切换计费方式会自动更新公式和单位,但<strong>不会清空售价</strong>,需要手动填新的售价。</li>
|
||||
<li><strong>Q: 附加费填错了?</strong><br>A: 直接改对应的行,或点"删除"去掉不需要的行,保存时会自动同步。</li>
|
||||
<li><strong>Q: 高级设置里的公式被改坏了?</strong><br>A: 删除这条规则重新创建,公式会自动生成。或者手动恢复为:<code>round($input.length_m * $input.width_m * $rule.base_unit_price, 2)</code></li>
|
||||
<li><strong>Q: 删错了怎么办?</strong><br>A: 点击"删除"是软删除(可恢复),如果确认不要了再点"永久删除"。</li>
|
||||
@ -147,20 +147,20 @@
|
||||
</div>
|
||||
<section class="panel" v-if="!editMode">
|
||||
<div class="panel-header">
|
||||
<h3>定价规则列表</h3>
|
||||
<button class="primary-btn" @click="openCreateRule">新增定价规则</button>
|
||||
<h3>产品定价列表</h3>
|
||||
<button class="primary-btn" @click="openCreateRule">新增定价</button>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>产品名称</th>
|
||||
<th>计价类型</th>
|
||||
<th>基准售价</th>
|
||||
<th>计价单位</th>
|
||||
<th>计费方式</th>
|
||||
<th>售价</th>
|
||||
<th>单价单位</th>
|
||||
<th>税率</th>
|
||||
<th>含税方式</th>
|
||||
<th>公式说明</th>
|
||||
<th>是否含税</th>
|
||||
<th>价格说明</th>
|
||||
<th>状态</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
@ -180,16 +180,16 @@
|
||||
<button class="link-btn danger" @click="handleDeleteRule(rule)">删除</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="!rules.length"><td colspan="9" class="empty-cell">暂无定价规则</td></tr>
|
||||
<tr v-if="!rules.length"><td colspan="9" class="empty-cell">暂无定价数据</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 编辑/新增定价规则 -->
|
||||
<!-- 编辑/新增定价 -->
|
||||
<section v-if="editMode" class="panel">
|
||||
<div class="panel-header">
|
||||
<h3>{{ editingRule.id ? '编辑' : '新增' }}定价规则</h3>
|
||||
<h3>{{ editingRule.id ? '编辑' : '新增' }}定价</h3>
|
||||
<button class="ghost-btn" @click="cancelEdit">返回列表</button>
|
||||
</div>
|
||||
|
||||
@ -208,7 +208,7 @@
|
||||
<input v-model="editingRule.product_name" type="text" placeholder="自动填充或手动输入" />
|
||||
</label>
|
||||
<label>
|
||||
<span>计价类型 <em class="required">*</em></span>
|
||||
<span>计费方式 <em class="required">*</em></span>
|
||||
<select v-model="editingRule.pricing_type" @change="onPricingTypeChange">
|
||||
<option value="area">按面积(㎡)</option>
|
||||
<option value="kg">按公斤(kg)</option>
|
||||
@ -216,11 +216,11 @@
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span>基准售价(元) <em class="required">*</em></span>
|
||||
<span>售价(元/单位) <em class="required">*</em></span>
|
||||
<input v-model.number="editingRule.base_unit_price" type="number" min="0" step="0.01" :placeholder="pricingUnitHint" />
|
||||
</label>
|
||||
<label>
|
||||
<span>计价单位</span>
|
||||
<span>单价单位</span>
|
||||
<select v-model="editingRule.pricing_unit">
|
||||
<option value="㎡">㎡</option>
|
||||
<option value="kg">kg</option>
|
||||
@ -236,7 +236,7 @@
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span>公式说明(给业务员看)</span>
|
||||
<span>价格说明(给业务员看)</span>
|
||||
<input v-model="editingRule.formula_note" type="text" :placeholder="formulaNoteHint" />
|
||||
</label>
|
||||
</div>
|
||||
@ -266,7 +266,7 @@
|
||||
<input v-model.number="editingRule.tax_rate" type="number" min="0" max="100" step="0.01" placeholder="如 13 表示 13%" />
|
||||
</label>
|
||||
<label>
|
||||
<span>默认含税方式</span>
|
||||
<span>是否含税</span>
|
||||
<select v-model.number="editingRule.tax_inclusive">
|
||||
<option :value="0">不含税(正算)</option>
|
||||
<option :value="1">含税(反算)</option>
|
||||
@ -309,7 +309,7 @@
|
||||
|
||||
<div class="action-row">
|
||||
<button class="ghost-btn" @click="cancelEdit">取消</button>
|
||||
<button class="primary-btn" :disabled="saving" @click="handleSaveRule">{{ saving ? '保存中...' : '保存定价规则' }}</button>
|
||||
<button class="primary-btn" :disabled="saving" @click="handleSaveRule">{{ saving ? '保存中...' : '保存定价' }}</button>
|
||||
</div>
|
||||
|
||||
<!-- 供应商成本管理 -->
|
||||
@ -568,10 +568,13 @@ async function loadProductOptions() {
|
||||
try {
|
||||
const data = await apiRequest("/api/products?page_size=200");
|
||||
const list = data.list || [];
|
||||
productOptions.value = list.map(p => ({
|
||||
value: p.product_id, label: `${p.product_name} / ${p.specification}`,
|
||||
product_name: p.product_name,
|
||||
}));
|
||||
productOptions.value = list.flatMap(p =>
|
||||
(p.specifications || []).map(spec => ({
|
||||
value: spec.product_id,
|
||||
label: `${p.product_name} / ${spec.specification}`,
|
||||
product_name: p.product_name,
|
||||
})),
|
||||
);
|
||||
} catch (e) { /* ignore */ }
|
||||
}
|
||||
|
||||
@ -612,7 +615,7 @@ async function handleSaveRule() {
|
||||
}
|
||||
|
||||
async function handleDeleteRule(rule) {
|
||||
if (!confirm(`确认删除「${rule.product_name}」的定价规则?`)) return;
|
||||
if (!confirm(`确认删除「${rule.product_name}」的定价?`)) return;
|
||||
try {
|
||||
await apiRequest(`/api/pricing-rules/${rule.id}`, { method: "DELETE" });
|
||||
toast.success("删除成功");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user