From 7c5d0127cc82b285ac033c8acc6580a1cabfe59c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=85=E5=BF=B5?= Date: Wed, 28 Jan 2026 11:53:41 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=BC=98=E5=8C=96=20?= =?UTF-8?q?=E5=AE=A1=E6=89=B9=E5=92=8C=E5=A4=87=E8=B4=A7=E5=8D=95=20?= =?UTF-8?q?=E9=80=80=E7=A8=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/composables/useStockingForm.ts | 88 ++++++++++++++++++++-- src/views/admin/approval/approval_add.vue | 14 ++++ src/views/admin/approval/approval_edit.vue | 20 ++++- src/views/admin/system/notice/index.vue | 10 ++- 4 files changed, 122 insertions(+), 10 deletions(-) diff --git a/src/composables/useStockingForm.ts b/src/composables/useStockingForm.ts index d54a3ed..280a3d7 100644 --- a/src/composables/useStockingForm.ts +++ b/src/composables/useStockingForm.ts @@ -157,6 +157,7 @@ export function useStockingForm(isFinal = false, stockingId?: string | number) { // 回显填充抑制标记:为 true 时不触发自动计算覆盖接口值 const isPopulating = ref(false) const userEditing = ref>(new Set()) // 跟踪用户正在编辑的行 + const manualTaxRefundRows = ref>(new Set()) // 跟踪用户手动编辑过预估退税额的行 // 选项数据 const channelOptions = ref() @@ -766,14 +767,49 @@ export function useStockingForm(isFinal = false, stockingId?: string | number) { const copyRow = (idx: number) => { const copied = JSON.parse(JSON.stringify(items.value[idx])) as ItemRow items.value.splice(idx + 1, 0, copied) + // 如果原行是手动编辑的,复制的行也标记为手动编辑 + if (manualTaxRefundRows.value.has(idx)) { + // 需要调整后续行的索引 + const newManualRows = new Set() + manualTaxRefundRows.value.forEach((rowIdx) => { + if (rowIdx <= idx) { + newManualRows.add(rowIdx) + } else { + newManualRows.add(rowIdx + 1) + } + }) + newManualRows.add(idx + 1) // 新复制的行 + manualTaxRefundRows.value = newManualRows + } } const addRowAfter = (idx: number) => { items.value.splice(idx + 1, 0, newItem()) + // 调整后续行的手动编辑标记索引 + const newManualRows = new Set() + manualTaxRefundRows.value.forEach((rowIdx) => { + if (rowIdx <= idx) { + newManualRows.add(rowIdx) + } else { + newManualRows.add(rowIdx + 1) + } + }) + manualTaxRefundRows.value = newManualRows } const removeRow = (idx: number) => { items.value.splice(idx, 1) + // 移除该行的手动编辑标记,并调整后续行的索引 + const newManualRows = new Set() + manualTaxRefundRows.value.forEach((rowIdx) => { + if (rowIdx < idx) { + newManualRows.add(rowIdx) + } else if (rowIdx > idx) { + newManualRows.add(rowIdx - 1) + } + // rowIdx === idx 的行被删除,不添加到新集合中 + }) + manualTaxRefundRows.value = newManualRows } // 收款项操作方法 @@ -1098,6 +1134,16 @@ export function useStockingForm(isFinal = false, stockingId?: string | number) { } // 等待本轮变更完成后,再恢复自动计算 nextTick(() => { + // 检查哪些行的预估退税额与自动计算值不同,标记为手动编辑 + items.value.forEach((it: any, index: number) => { + const currentValue = String(it.tax_refund || '') + const autoCalculatedValue = String(calcTaxRefund(it) || '0') + if (currentValue !== autoCalculatedValue && currentValue !== '' && currentValue !== '0') { + manualTaxRefundRows.value.add(index) + } + }) + // 初始化 prevTaxRefundValues + prevTaxRefundValues.value = items.value.map((item: any) => String(item.tax_refund || '')) isPopulating.value = false }) } @@ -1329,11 +1375,13 @@ export function useStockingForm(isFinal = false, stockingId?: string | number) { } } - // 自动计算预估退税额 - const refund = calcTaxRefund(it) - if (items.value[index]) { - items.value[index].tax_refund = isNaN(refund) ? '0' : String(Number(refund.toFixed(2))) - ;(items.value[index] as any).tax_refund_currency = 'CNY' + // 自动计算预估退税额(跳过用户手动编辑过的行) + if (!manualTaxRefundRows.value.has(index)) { + const refund = calcTaxRefund(it) + if (items.value[index]) { + items.value[index].tax_refund = isNaN(refund) ? '0' : String(Number(refund.toFixed(2))) + ;(items.value[index] as any).tax_refund_currency = 'CNY' + } } // 自动计算车价 @@ -1385,13 +1433,41 @@ export function useStockingForm(isFinal = false, stockingId?: string | number) { { deep: true } ) + // 存储上一次的 tax_refund 值,用于检测用户手动输入 + const prevTaxRefundValues = ref([]) + // 当用户手动输入预估退税额时,重新计算利润 watch( () => items.value.map((item: any) => item.tax_refund), - () => { + (newValues) => { if (isPopulating.value) return + + // 初始化 prevTaxRefundValues + if (prevTaxRefundValues.value.length === 0) { + prevTaxRefundValues.value = newValues.map((v: any) => String(v || '')) + } + items.value.forEach((it: any, index: number) => { if (!items.value[index]) return + + const currentValue = String(it.tax_refund || '') + const prevValue = prevTaxRefundValues.value[index] || '' + const autoCalculatedValue = String(calcTaxRefund(it) || '0') + + // 如果当前值与自动计算值不同,且与上一次值不同,说明是用户手动输入的 + if ( + currentValue !== autoCalculatedValue && + currentValue !== prevValue && + currentValue !== '' + ) { + // 标记该行已被用户手动编辑 + manualTaxRefundRows.value.add(index) + } + + // 更新上一次的值 + prevTaxRefundValues.value[index] = currentValue + + // 重新计算利润 const profit = calcProfit(it) items.value[index].profit = isNaN(profit) ? 0 : Number(profit.toFixed(2)) ;(items.value[index] as any).profit_currency = (it as any).profit_currency || 'CNY' diff --git a/src/views/admin/approval/approval_add.vue b/src/views/admin/approval/approval_add.vue index a3c9597..81e6f0b 100644 --- a/src/views/admin/approval/approval_add.vue +++ b/src/views/admin/approval/approval_add.vue @@ -176,7 +176,13 @@ + + { if (group && group.type === 'initiator_leader') { approvers.push({ type: 'initiator_leader' }) + } else if (group && group.type === 'field_user') { + approvers.push({ type: group.type, value: group.users }) } else if (group && group.type && Array.isArray(group.users) && group.users.length > 0) { approvers.push({ type: group.type, value: group.users.join(',') }) } diff --git a/src/views/admin/approval/approval_edit.vue b/src/views/admin/approval/approval_edit.vue index 24af770..2f7904d 100644 --- a/src/views/admin/approval/approval_edit.vue +++ b/src/views/admin/approval/approval_edit.vue @@ -176,7 +176,13 @@ + + v.trim()) } else if (ap.value) { const values = String(ap.value) .split(',') @@ -637,6 +651,8 @@ await ensureOptionsLoaded(group) if (c.type === 'initiator_leader') { group.users = [] + } else if (c.type === 'field_user') { + group.users = c.value.split(',').map((v) => v.trim()) } else if (c.value) { // group.users = String(c.value) // .split(',') @@ -773,6 +789,8 @@ node.approverGroups.forEach((group) => { if (group && group.type === 'initiator_leader') { approvers.push({ type: 'initiator_leader' }) + } else if (group && group.type === 'field_user') { + approvers.push({ type: group.type, value: group.users }) } else if (group && group.type && Array.isArray(group.users) && group.users.length > 0) { approvers.push({ type: group.type, value: group.users.join(',') }) } @@ -789,7 +807,7 @@ if (group && group.type === 'initiator_leader') { cc.push({ type: 'initiator_leader' }) } else if (group && group.type && Array.isArray(group.users) && group.users.length > 0) { - cc.push({ type: group.type, value: group.users.join(',') }) + cc.push({ type: group.type, value: group.users }) } }) } diff --git a/src/views/admin/system/notice/index.vue b/src/views/admin/system/notice/index.vue index 1f95848..7b531b3 100644 --- a/src/views/admin/system/notice/index.vue +++ b/src/views/admin/system/notice/index.vue @@ -183,11 +183,15 @@ loading.value = true try { const { currentPage, pageSize } = pagination - - const { records, current, size, total } = await systemService.getNoticeList({ + const params: any = { current: currentPage, size: pageSize - }) + } + if (keyword.value) { + params.keyword = keyword.value + } + + const { records, current, size, total } = await systemService.getNoticeList(params) tableData.value = records.map((item: any) => ({ ...item }))