fix: 对齐field_to_perm与sys_element权限码 + 税率6% + 含税总价反算

- buy/semi/product: 数量字段映射对齐sys_element实际注册码(qty_inbound/qty_stock/qty_available)
- 数据库: 补全buy(9)+semi(10)+product(13)缺失权限码
- deploy_production.sql: 同步更新
- buy.vue: 税率新增6%选项, 价格联动以含税为主输入, 税率变化保持最后编辑价格不变
- buy.vue: 新增含税总价可输入反算功能
This commit is contained in:
yueli
2026-07-15 15:03:37 +08:00
parent 0651eb07fa
commit 4b1a86a870
5 changed files with 271 additions and 23 deletions

View File

@ -529,6 +529,7 @@
<el-select v-model="form.tax_rate" style="width:100%" @change="updatePrices('tax')">
<el-option label="0%" :value="0" />
<el-option label="1%" :value="1" />
<el-option label="6%" :value="6" />
<el-option label="13%" :value="13" />
</el-select>
</el-form-item>
@ -575,6 +576,22 @@
</el-col>
</el-row>
<el-row :gutter="20" v-if="hasFormFieldPermission('total_price') && form.tax_rate > 0">
<el-col :span="8">
<el-form-item label="含税总价">
<el-input-number
v-model="form._post_tax_total_price"
:precision="2"
:controls="false"
style="width:100%"
class="total-price-input"
placeholder="输入含税总价反算"
@change="updatePrices('post_total')"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" style="margin-top: 15px;">
<el-col :span="8">
<el-form-item label="供应商">
@ -1161,7 +1178,8 @@ const form = reactive({
supplier_name: '', purchaser: '', purchaser_email: '', source_link: '', detail_link: '',
arrival_photo: [] as string[], inspection_report: [] as string[],
print_copies: 1,
request_id: undefined as number | undefined // [新增] 关联采购申请单
request_id: undefined as number | undefined, // [新增] 关联采购申请单
_post_tax_total_price: undefined as number | undefined // 含税总价(仅前端输入用,不提交后端)
})
// ------------------------------------
@ -1364,38 +1382,61 @@ const handleEntryModeChange = (val: string) => {
if(formRef.value) formRef.value.clearValidate('batch_number')
}
}
// 价格联动计算 (精确到小数点后2位并支持空值)
// 价格联动:含税单价为主输入,不含税价格自动反算
// 追踪用户最后编辑的是含税还是不含税('pre' | 'post'
const lastPriceEdit = ref<'pre' | 'post'>('post') // 默认以含税为主
const updatePrices = (source: string) => {
const taxMultiplier = 1 + (form.tax_rate || 0) / 100;
if (source === 'pre') {
if (form.unit_price !== undefined && form.unit_price !== null) {
// 用户编辑了不含税单价 → 反推含税
lastPriceEdit.value = 'pre'
if (form.unit_price != null) {
form.post_tax_unit_price = Number((form.unit_price * taxMultiplier).toFixed(2));
} else {
form.post_tax_unit_price = undefined;
}
} else if (source === 'post') {
if (form.post_tax_unit_price !== undefined && form.post_tax_unit_price !== null) {
form.unit_price = Number((form.post_tax_unit_price / taxMultiplier).toFixed(2));
// 用户编辑了含税单价 → 反推不含税
lastPriceEdit.value = 'post'
if (form.post_tax_unit_price != null) {
form.unit_price = Number((form.post_tax_unit_price / taxMultiplier).toFixed(4));
} else {
form.unit_price = undefined;
}
} else if (source === 'tax') {
if (form.unit_price !== undefined && form.unit_price !== null) {
// 税率变化:保持用户最后编辑的那个价格不变,重算另一个
if (lastPriceEdit.value === 'post' && form.post_tax_unit_price != null) {
form.unit_price = Number((form.post_tax_unit_price / taxMultiplier).toFixed(4));
} else if (form.unit_price != null) {
form.post_tax_unit_price = Number((form.unit_price * taxMultiplier).toFixed(2));
}
} else if (source === 'post_total') {
// 用户输入了含税总价 → 反推不含税总价和单价
lastPriceEdit.value = 'post'
const postTaxTotal = form._post_tax_total_price
if (postTaxTotal != null && form.in_quantity > 0) {
const preTaxTotal = postTaxTotal / taxMultiplier
form.total_price = Number(preTaxTotal.toFixed(2))
form.unit_price = Number((preTaxTotal / form.in_quantity).toFixed(4))
form.post_tax_unit_price = Number((form.unit_price * taxMultiplier).toFixed(2))
}
return // 已完整计算,跳过下面的总价逻辑
}
if (form.in_quantity !== undefined && form.unit_price !== undefined && form.unit_price !== null) {
// 计算不含税总价
if (form.in_quantity > 0 && form.unit_price != null) {
form.total_price = Number((form.in_quantity * form.unit_price).toFixed(2));
} else {
form.total_price = undefined;
}
}
// 数量或不含税单价变化 → 自动推总价和含税单价
watch(() => [form.in_quantity, form.unit_price], () => {
if (form.unit_price !== undefined && form.unit_price !== null) {
if (form.unit_price != null && form.in_quantity > 0) {
form.total_price = Number((form.in_quantity * form.unit_price).toFixed(2));
// 同时更新含税单价
const taxMultiplier = 1 + (form.tax_rate || 0) / 100;
form.post_tax_unit_price = Number((form.unit_price * taxMultiplier).toFixed(2));
} else {
@ -2005,7 +2046,8 @@ const resetForm = () => {
tax_rate: 0,
currency: 'CNY', exchange_rate: 1.00, supplier_name: '', purchaser: '', purchaser_email: '', source_link: '', detail_link: '', arrival_photo: [], inspection_report: [],
print_copies: 1,
request_id: undefined
request_id: undefined,
_post_tax_total_price: undefined
})
}
const getStatusType = (status: string) => { const map: any = {'在库': 'success', '出库': 'info', '损耗': 'danger'}; return map[status] || 'warning' }