2020706005
This commit is contained in:
@@ -160,25 +160,6 @@ export async function prCostRemove(expense_code) {
|
|||||||
return res?.data ?? res
|
return res?.data ?? res
|
||||||
}
|
}
|
||||||
|
|
||||||
/** POST /api/pr/cost/amortize — 月度批量分摊(聚合时间段内已确认采购,逐笔未分摊费用) */
|
|
||||||
export async function prCostAmortize(body) {
|
|
||||||
const payload = {
|
|
||||||
start_time: str(body?.start_time),
|
|
||||||
end_time: str(body?.end_time),
|
|
||||||
}
|
|
||||||
if (!payload.start_time || !payload.end_time) throw new Error('请选择分摊时间段')
|
|
||||||
const expense_code = pickPrExpenseCode(body)
|
|
||||||
if (expense_code) payload.expense_code = expense_code
|
|
||||||
const res = await request.post('/api/pr/cost/amortize', payload, { skipErrorNotify: true })
|
|
||||||
return res?.data ?? res
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 已分摊 / 无匹配采购 / 时段内无可分摊等业务提示,非致命错误 */
|
|
||||||
export function isBenignAmortizeError(err) {
|
|
||||||
const msg = pickApiErrorMessage(err, '')
|
|
||||||
return !msg || /没有未分摊|已分摊|无需分摊|无可分摊|无匹配|没有.*采购|暂无/.test(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 分页拉全量公关费用 */
|
/** 分页拉全量公关费用 */
|
||||||
export async function prCostListedAll(body = {}) {
|
export async function prCostListedAll(body = {}) {
|
||||||
const limit = 50
|
const limit = 50
|
||||||
|
|||||||
@@ -0,0 +1,142 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
import { pickGoodsNameFromListedRow } from '@/utils/goodsCategorys'
|
||||||
|
|
||||||
|
function str(v) {
|
||||||
|
return String(v ?? '').trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 默认内销(暂无出口场景) */
|
||||||
|
export const PRICING_TRADE_DOMESTIC = 'DOMESTIC'
|
||||||
|
|
||||||
|
/** 成本围栏 · 纳税身份 Tab(key 即接口 taxpayer_type 枚举) */
|
||||||
|
export const PRICING_TAXPAYER_TABS = [
|
||||||
|
{ key: 'GENERAL', label: '一般纳税人' },
|
||||||
|
{ key: 'SMALL', label: '小规模纳税人' },
|
||||||
|
{ key: 'INDIVIDUAL', label: '收据组织' },
|
||||||
|
]
|
||||||
|
|
||||||
|
/** @deprecated 请直接用 PRICING_TAXPAYER_TABS[].key */
|
||||||
|
export const PRICING_TAXPAYER_BY_ORG = {
|
||||||
|
general: 'GENERAL',
|
||||||
|
small: 'SMALL',
|
||||||
|
personal: 'INDIVIDUAL',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PRICING_TAXPAYER_DEFAULT = 'GENERAL'
|
||||||
|
|
||||||
|
const PRICING_TAXPAYER_KEYS = new Set(PRICING_TAXPAYER_TABS.map((t) => t.key))
|
||||||
|
|
||||||
|
/** 接口 data.list */
|
||||||
|
function unwrapPricingTableList(res) {
|
||||||
|
const envelope = res?.data ?? res
|
||||||
|
if (Array.isArray(envelope)) return envelope
|
||||||
|
const payload = envelope?.data ?? envelope
|
||||||
|
if (Array.isArray(payload)) return payload
|
||||||
|
if (payload && typeof payload === 'object') {
|
||||||
|
const list = payload.list ?? payload.rows ?? payload.table
|
||||||
|
if (Array.isArray(list)) return list
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
function pickText(raw, ...keys) {
|
||||||
|
for (const k of keys) {
|
||||||
|
const v = raw[k]
|
||||||
|
if (v == null) continue
|
||||||
|
const s = String(v).trim()
|
||||||
|
if (s) return s
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 税率等:0 为有效值 */
|
||||||
|
function pickRate(raw, ...keys) {
|
||||||
|
for (const k of keys) {
|
||||||
|
const v = raw[k]
|
||||||
|
if (v == null || v === '') continue
|
||||||
|
const n = Number(v)
|
||||||
|
if (Number.isFinite(n)) return n
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 金额:过滤 null / 非有限数 / 明显异常值 */
|
||||||
|
function pickMoney(raw, ...keys) {
|
||||||
|
for (const k of keys) {
|
||||||
|
const v = raw[k]
|
||||||
|
if (v == null || v === '') continue
|
||||||
|
const n = Number(v)
|
||||||
|
if (!Number.isFinite(n)) continue
|
||||||
|
if (Math.abs(n) >= 1e12) continue
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 定价决策表行 → 成本围栏表格(字段对齐 /api/pricing/table) */
|
||||||
|
export function normalizePricingTableRow(raw, idx = 0) {
|
||||||
|
if (!raw || typeof raw !== 'object') return null
|
||||||
|
|
||||||
|
const supplier_bloc_name = pickText(raw, 'supplier_bloc_name')
|
||||||
|
const supplier_company_name = pickText(raw, 'supplier_company_name')
|
||||||
|
const goods_name = pickGoodsNameFromListedRow(raw) || pickText(raw, 'goods_name')
|
||||||
|
const bill_type = pickText(raw, 'bill_name', 'bill_type')
|
||||||
|
const input_tax_rate = pickRate(raw, 'bill_tax', 'input_tax_rate')
|
||||||
|
const source_company_name = pickText(raw, 'receive_company_name', 'source_company_name')
|
||||||
|
const internal_min_price = pickMoney(raw, 'internal_price', 'internal_min_price')
|
||||||
|
const internal_bill_type = pickText(raw, 'internal_bill_name', 'internal_bill_type')
|
||||||
|
const internal_input_tax_rate = pickRate(raw, 'internal_bill_tax', 'internal_input_tax_rate')
|
||||||
|
const source_rdc_name = pickText(raw, 'rdc_warehouse_name', 'source_rdc_name')
|
||||||
|
const source_rdc_code = pickText(raw, 'rdc_warehouse_code', 'source_rdc')
|
||||||
|
const fence_value = pickMoney(raw, 'fence_price', 'fence_value')
|
||||||
|
|
||||||
|
const bloc = pickText(raw, 'supplier_bloc_code')
|
||||||
|
const company = pickText(raw, 'supplier_company_code')
|
||||||
|
|
||||||
|
return {
|
||||||
|
key: pickText(raw, 'key', 'id') ?? `${bloc || 'bloc'}-${company || idx}`,
|
||||||
|
supplier_bloc_name,
|
||||||
|
supplier_company_name,
|
||||||
|
goods_name,
|
||||||
|
bill_type,
|
||||||
|
input_tax_rate,
|
||||||
|
source_company_name,
|
||||||
|
internal_min_price,
|
||||||
|
internal_bill_type,
|
||||||
|
internal_input_tax_rate,
|
||||||
|
source_rdc: source_rdc_name || source_rdc_code,
|
||||||
|
source_rdc_name,
|
||||||
|
fence_value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST /api/pricing/table
|
||||||
|
* 定价决策表:按 RDC、商品、纳税人身份、交易类型生成围栏支持数据
|
||||||
|
*/
|
||||||
|
export async function pricingTableQuery(body = {}) {
|
||||||
|
const taxpayer_type = str(body.taxpayer_type).toUpperCase()
|
||||||
|
const trade_type = str(body.trade_type) || PRICING_TRADE_DOMESTIC
|
||||||
|
const goods_code = str(body.goods_code)
|
||||||
|
const rdc_code = str(body.rdc_code)
|
||||||
|
if (!taxpayer_type) throw new Error('缺少纳税人身份')
|
||||||
|
if (!PRICING_TAXPAYER_KEYS.has(taxpayer_type)) {
|
||||||
|
throw new Error(`纳税人身份无效:${taxpayer_type}`)
|
||||||
|
}
|
||||||
|
if (!goods_code) throw new Error('缺少商品编码')
|
||||||
|
if (!rdc_code) throw new Error('缺少 RDC 仓库编码')
|
||||||
|
|
||||||
|
const res = await request.post('/api/pricing/table', {
|
||||||
|
taxpayer_type,
|
||||||
|
trade_type,
|
||||||
|
goods_code,
|
||||||
|
rdc_code,
|
||||||
|
})
|
||||||
|
return unwrapPricingTableList(res)
|
||||||
|
.map((row, idx) => normalizePricingTableRow(row, idx))
|
||||||
|
.filter(Boolean)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function pickPricingTableError(err, fallback = '加载定价决策表失败') {
|
||||||
|
return String(err?.data?.message || err?.message || fallback).trim() || fallback
|
||||||
|
}
|
||||||
@@ -287,19 +287,3 @@ export async function allocShareListed(body = {}) {
|
|||||||
total,
|
total,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** POST /api/warehouse/alloc/amortize */
|
|
||||||
export async function allocAmortize(body) {
|
|
||||||
const payload = {
|
|
||||||
start_time: str(body?.start_time),
|
|
||||||
end_time: str(body?.end_time),
|
|
||||||
}
|
|
||||||
if (!payload.start_time || !payload.end_time) throw new Error('请选择分摊时间段')
|
|
||||||
const res = await request.post('/api/warehouse/alloc/amortize', payload, { skipErrorNotify: true })
|
|
||||||
return res?.data ?? res
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isBenignAllocAmortizeError(err) {
|
|
||||||
const msg = pickApiErrorMessage(err, '')
|
|
||||||
return !msg || /没有|已分摊|无需分摊|无可分摊|暂无|为空/.test(msg)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -270,19 +270,3 @@ export async function deployShareListed(body = {}) {
|
|||||||
total,
|
total,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** POST /api/warehouse/deploy/amortize */
|
|
||||||
export async function deployAmortize(body) {
|
|
||||||
const payload = {
|
|
||||||
start_time: str(body?.start_time),
|
|
||||||
end_time: str(body?.end_time),
|
|
||||||
}
|
|
||||||
if (!payload.start_time || !payload.end_time) throw new Error('请选择分摊时间段')
|
|
||||||
const res = await request.post('/api/warehouse/deploy/amortize', payload, { skipErrorNotify: true })
|
|
||||||
return res?.data ?? res
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isBenignDeployAmortizeError(err) {
|
|
||||||
const msg = pickApiErrorMessage(err, '')
|
|
||||||
return !msg || /没有|已分摊|无需分摊|无可分摊|暂无|为空/.test(msg)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -291,40 +291,6 @@ export async function freightShareListed(body = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** POST /api/warehouse/freight/amortize — 月度批量分摊(按已到库订单 + 运费日志维度) */
|
|
||||||
export async function freightAmortize(body) {
|
|
||||||
const payload = {
|
|
||||||
start_time: str(body?.start_time),
|
|
||||||
end_time: str(body?.end_time),
|
|
||||||
}
|
|
||||||
if (!payload.start_time || !payload.end_time) throw new Error('请选择分摊时间段')
|
|
||||||
const res = await request.post('/api/warehouse/freight/amortize', payload, { skipErrorNotify: true })
|
|
||||||
return res?.data ?? res
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 时段内无运费日志 / 已分摊等业务提示,非致命错误 */
|
|
||||||
export function isBenignFreightAmortizeError(err) {
|
|
||||||
const msg = pickApiErrorMessage(err, '')
|
|
||||||
return !msg || /没有|已分摊|无需分摊|无可分摊|无运费|暂无|为空/.test(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 分页拉全量物料运费日志(跑批前校验时段内是否有日志) */
|
|
||||||
export async function freightLogsListedAll(body = {}) {
|
|
||||||
const limit = 50
|
|
||||||
let page = 1
|
|
||||||
const all = []
|
|
||||||
let total = 0
|
|
||||||
for (;;) {
|
|
||||||
const res = await freightLogsListed({ ...body, page, limit })
|
|
||||||
const batch = res.list || []
|
|
||||||
all.push(...batch)
|
|
||||||
total = res.total
|
|
||||||
if (!batch.length || all.length >= total) break
|
|
||||||
page += 1
|
|
||||||
}
|
|
||||||
return { list: all, total }
|
|
||||||
}
|
|
||||||
|
|
||||||
export function pickApiErrorMessage(err, fallback = '操作失败') {
|
export function pickApiErrorMessage(err, fallback = '操作失败') {
|
||||||
return String(err?.data?.message || err?.message || fallback).trim() || fallback
|
return String(err?.data?.message || err?.message || fallback).trim() || fallback
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -254,22 +254,6 @@ export async function wasteShareListed(body = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** POST /api/warehouse/waste/amortize */
|
|
||||||
export async function wasteAmortize(body) {
|
|
||||||
const payload = {
|
|
||||||
start_time: str(body?.start_time),
|
|
||||||
end_time: str(body?.end_time),
|
|
||||||
}
|
|
||||||
if (!payload.start_time || !payload.end_time) throw new Error('请选择分摊时间段')
|
|
||||||
const res = await request.post('/api/warehouse/waste/amortize', payload, { skipErrorNotify: true })
|
|
||||||
return res?.data ?? res
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isBenignWasteAmortizeError(err) {
|
|
||||||
const msg = pickApiErrorMessage(err, '')
|
|
||||||
return !msg || /没有|已分摊|无需分摊|无可分摊|暂无|为空/.test(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function pickApiErrorMessage(err, fallback = '操作失败') {
|
export function pickApiErrorMessage(err, fallback = '操作失败') {
|
||||||
return String(
|
return String(
|
||||||
err?.data?.message
|
err?.data?.message
|
||||||
|
|||||||
@@ -1,50 +1,56 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="gt-cost-panel" v-loading="loading" element-loading-text="加载中…">
|
<div class="gt-cost-panel">
|
||||||
<template v-if="!goodsCode">
|
<template v-if="!goodsCode">
|
||||||
<el-empty :image-size="56" description="请先保存物料后再查看成本围栏" class="gt-cost-empty" />
|
<el-empty :image-size="56" description="请先保存物料后再查看成本围栏" class="gt-cost-empty" />
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="loadError">
|
|
||||||
<el-alert type="error" :title="loadError" show-icon :closable="false" />
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="gt-cost-layout">
|
<div class="gt-cost-layout">
|
||||||
<aside class="gt-cost-rdc-nav" aria-label="售出 RDC 列表">
|
<aside class="gt-cost-rdc-nav" aria-label="售出 RDC 列表">
|
||||||
<div class="gt-cost-rdc-hd">售出 RDC 列表</div>
|
<div class="gt-cost-rdc-hd">售出 RDC 列表</div>
|
||||||
<template v-if="rdcList.length">
|
<template v-if="rdcOptions.length">
|
||||||
<button
|
<button
|
||||||
v-for="rdc in rdcList"
|
v-for="rdc in rdcOptions"
|
||||||
:key="rdc.warehouse_code"
|
:key="rdc.code"
|
||||||
type="button"
|
type="button"
|
||||||
class="gt-cost-rdc-item"
|
class="gt-cost-rdc-item"
|
||||||
:class="{ 'is-active': activeRdcCode === rdc.warehouse_code }"
|
:class="{ 'is-active': activeRdcCode === rdc.code }"
|
||||||
@click="activeRdcCode = rdc.warehouse_code"
|
@click="activeRdcCode = rdc.code"
|
||||||
>
|
>
|
||||||
<span class="gt-cost-rdc-name">{{ rdc.name || rdc.warehouse_code }}</span>
|
<span class="gt-cost-rdc-name">{{ rdcDisplayName(rdc) }}</span>
|
||||||
<span v-if="rdc.warehouse_code" class="gt-cost-rdc-code">{{ rdc.warehouse_code }}</span>
|
<span v-if="rdcDisplaySub(rdc)" class="gt-cost-rdc-code">{{ rdcDisplaySub(rdc) }}</span>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
<p v-else class="gt-cost-rdc-empty">RDC 列表接口待接入</p>
|
<p v-else class="gt-cost-rdc-empty">暂无关联 RDC</p>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<div class="gt-cost-main">
|
<div class="gt-cost-main">
|
||||||
<div class="gt-cost-org-tabs" role="tablist" aria-label="组织类型">
|
<div class="gt-cost-org-tabs" role="tablist" aria-label="组织类型">
|
||||||
<button
|
<button
|
||||||
v-for="tab in ORG_TYPE_TABS"
|
v-for="tab in PRICING_TAXPAYER_TABS"
|
||||||
:key="tab.key"
|
:key="tab.key"
|
||||||
type="button"
|
type="button"
|
||||||
role="tab"
|
role="tab"
|
||||||
class="gt-cost-org-tab"
|
class="gt-cost-org-tab"
|
||||||
:class="[
|
:class="[
|
||||||
{ 'is-active': activeOrgType === tab.key },
|
{ 'is-active': activeTaxpayerType === tab.key },
|
||||||
orgTypeTabClass(tab.key),
|
orgTypeTabClass(tab.key),
|
||||||
]"
|
]"
|
||||||
:aria-selected="activeOrgType === tab.key"
|
:aria-selected="activeTaxpayerType === tab.key"
|
||||||
@click="activeOrgType = tab.key"
|
@click="activeTaxpayerType = tab.key"
|
||||||
>
|
>
|
||||||
{{ tab.label }}
|
{{ tab.label }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<el-alert
|
||||||
|
v-if="loadError"
|
||||||
|
type="error"
|
||||||
|
:title="loadError"
|
||||||
|
show-icon
|
||||||
|
:closable="false"
|
||||||
|
class="gt-cost-table-error"
|
||||||
|
/>
|
||||||
|
|
||||||
<div class="gt-cost-table-wrap">
|
<div class="gt-cost-table-wrap">
|
||||||
<div class="wops-flex-table is-cols-cost-fence">
|
<div class="wops-flex-table is-cols-cost-fence">
|
||||||
<div class="wops-flex-scroll">
|
<div class="wops-flex-scroll">
|
||||||
@@ -60,16 +66,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="!fenceRows.length" class="wops-empty-wrap">
|
|
||||||
<p class="wops-empty">暂无围栏数据</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-for="(row, idx) in fenceRows"
|
class="gt-cost-table-body"
|
||||||
:key="row.key || idx"
|
v-loading="loading"
|
||||||
class="wops-flex-row wops-flex-data"
|
element-loading-text="加载中…"
|
||||||
:class="{ 'is-stripe': idx % 2 === 1 }"
|
element-loading-background="rgba(255, 255, 255, 0.72)"
|
||||||
>
|
>
|
||||||
|
<div v-if="!loading && !fenceRows.length" class="wops-empty-wrap">
|
||||||
|
<p class="wops-empty">暂无围栏数据</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-for="(row, idx) in fenceRows"
|
||||||
|
:key="row.key || idx"
|
||||||
|
class="wops-flex-row wops-flex-data"
|
||||||
|
:class="{ 'is-stripe': idx % 2 === 1 }"
|
||||||
|
>
|
||||||
<div class="wops-col wops-col--wh">
|
<div class="wops-col wops-col--wh">
|
||||||
<span class="wops-name wops-ellipsis">{{ row.supplier_bloc_name || '—' }}</span>
|
<span class="wops-name wops-ellipsis">{{ row.supplier_bloc_name || '—' }}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -82,19 +94,20 @@
|
|||||||
<div class="wops-col wops-col--plain">
|
<div class="wops-col wops-col--plain">
|
||||||
<span class="wops-ellipsis">{{ row.bill_type || '—' }}</span>
|
<span class="wops-ellipsis">{{ row.bill_type || '—' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="wops-col wops-col--num">{{ fmtTaxRate(row.input_tax_rate) }}</div>
|
<div class="wops-col wops-col--num gt-cost-col--tax-rate">{{ fmtTaxRate(row.input_tax_rate) }}</div>
|
||||||
<div class="wops-col wops-col--wh">
|
<div class="wops-col wops-col--wh">
|
||||||
<span class="wops-name wops-ellipsis">{{ row.source_company_name || '—' }}</span>
|
<span class="wops-name wops-ellipsis">{{ row.source_company_name || '—' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="wops-col wops-col--num">{{ fmtMoney(row.internal_min_price) }}</div>
|
<div class="wops-col wops-col--num gt-cost-col--min-price">{{ fmtMoney(row.internal_min_price) }}</div>
|
||||||
<div class="wops-col wops-col--plain">
|
<div class="wops-col wops-col--plain">
|
||||||
<span class="wops-ellipsis">{{ row.internal_bill_type || '—' }}</span>
|
<span class="wops-ellipsis">{{ row.internal_bill_type || '—' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="wops-col wops-col--num">{{ fmtTaxRate(row.internal_input_tax_rate) }}</div>
|
<div class="wops-col wops-col--num gt-cost-col--tax-rate">{{ fmtTaxRate(row.internal_input_tax_rate) }}</div>
|
||||||
<div class="wops-col wops-col--wh">
|
<div class="wops-col wops-col--wh">
|
||||||
<span class="wops-name wops-ellipsis">{{ row.source_rdc_name || row.source_rdc || '—' }}</span>
|
<span class="wops-name wops-ellipsis">{{ row.source_rdc_name || row.source_rdc || '—' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="wops-col wops-col--num">{{ fmtMoney(row.fence_value) }}</div>
|
<div class="wops-col wops-col--num">{{ fmtMoney(row.fence_value) }}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -106,18 +119,22 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch } from 'vue'
|
import { computed, ref, watch } from 'vue'
|
||||||
|
import { mapGoodsRdcsToOptions } from '@/utils/warehouseGlobalTabSchema'
|
||||||
|
import {
|
||||||
|
PRICING_TAXPAYER_DEFAULT,
|
||||||
|
PRICING_TAXPAYER_TABS,
|
||||||
|
PRICING_TRADE_DOMESTIC,
|
||||||
|
pickPricingTableError,
|
||||||
|
pricingTableQuery,
|
||||||
|
} from '@/api/pricingTable'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
goodsCode: { type: String, default: '' },
|
goodsCode: { type: String, default: '' },
|
||||||
|
/** 物料 /goods/view 返回的 rdcs,与仓库管理页签同源 */
|
||||||
|
rdcList: { type: Array, default: () => [] },
|
||||||
})
|
})
|
||||||
|
|
||||||
const ORG_TYPE_TABS = [
|
|
||||||
{ key: 'general', label: '一般纳税人' },
|
|
||||||
{ key: 'small', label: '小规模纳税人' },
|
|
||||||
{ key: 'personal', label: '收据组织' },
|
|
||||||
]
|
|
||||||
|
|
||||||
const FENCE_COLUMNS = [
|
const FENCE_COLUMNS = [
|
||||||
{ key: 'supplier_bloc_name', label: '供应商集团名称' },
|
{ key: 'supplier_bloc_name', label: '供应商集团名称' },
|
||||||
{ key: 'supplier_company_name', label: '供应商组织名称' },
|
{ key: 'supplier_company_name', label: '供应商组织名称' },
|
||||||
@@ -161,20 +178,48 @@ function colHeadColorClass(key) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function orgTypeTabClass(key) {
|
function orgTypeTabClass(key) {
|
||||||
if (key === 'general') return 'is-general'
|
if (key === 'GENERAL') return 'is-general'
|
||||||
if (key === 'small') return 'is-small'
|
if (key === 'SMALL') return 'is-small'
|
||||||
if (key === 'personal') return 'is-personal'
|
if (key === 'INDIVIDUAL') return 'is-personal'
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const loadError = ref('')
|
const loadError = ref('')
|
||||||
const activeOrgType = ref('general')
|
/** 当前 Tab 对应的接口 taxpayer_type 枚举 */
|
||||||
|
const activeTaxpayerType = ref(PRICING_TAXPAYER_DEFAULT)
|
||||||
const activeRdcCode = ref('')
|
const activeRdcCode = ref('')
|
||||||
/** @type {import('vue').Ref<Array<{ warehouse_code: string, name: string }>>} */
|
|
||||||
const rdcList = ref([])
|
|
||||||
/** @type {import('vue').Ref<object[]>} */
|
/** @type {import('vue').Ref<object[]>} */
|
||||||
const fenceRows = ref([])
|
const fenceRows = ref([])
|
||||||
|
/** 递增序号,避免切换 RDC / 纳税身份时旧请求覆盖新结果 */
|
||||||
|
let fenceFetchSeq = 0
|
||||||
|
|
||||||
|
const rdcOptions = computed(() => mapGoodsRdcsToOptions(props.rdcList))
|
||||||
|
|
||||||
|
function rdcDisplayName(rdc) {
|
||||||
|
const name = String(rdc?.name || '').trim()
|
||||||
|
const code = String(rdc?.code || '').trim()
|
||||||
|
if (name && name !== code) return name
|
||||||
|
return code || name || '—'
|
||||||
|
}
|
||||||
|
|
||||||
|
function rdcDisplaySub(rdc) {
|
||||||
|
const name = String(rdc?.name || '').trim()
|
||||||
|
const code = String(rdc?.code || '').trim()
|
||||||
|
if (name && name !== code) return code
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function pickInitialRdcCode() {
|
||||||
|
const opts = rdcOptions.value
|
||||||
|
if (!opts.length) {
|
||||||
|
activeRdcCode.value = ''
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const cur = String(activeRdcCode.value || '').trim()
|
||||||
|
if (cur && opts.some((r) => r.code === cur)) return
|
||||||
|
activeRdcCode.value = opts[0].code
|
||||||
|
}
|
||||||
|
|
||||||
function fmtMoney(v) {
|
function fmtMoney(v) {
|
||||||
if (v == null || v === '') return '—'
|
if (v == null || v === '') return '—'
|
||||||
@@ -190,23 +235,61 @@ function fmtTaxRate(v) {
|
|||||||
return `${n}%`
|
return `${n}%`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function fetchFenceTable() {
|
||||||
|
const goods_code = String(props.goodsCode || '').trim()
|
||||||
|
const rdc_code = String(activeRdcCode.value || '').trim()
|
||||||
|
const taxpayer_type = String(activeTaxpayerType.value || '').trim()
|
||||||
|
|
||||||
|
if (!goods_code) {
|
||||||
|
fenceRows.value = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!rdc_code) {
|
||||||
|
fenceRows.value = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!taxpayer_type) {
|
||||||
|
fenceRows.value = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const seq = ++fenceFetchSeq
|
||||||
|
loading.value = true
|
||||||
|
loadError.value = ''
|
||||||
|
try {
|
||||||
|
const rows = await pricingTableQuery({
|
||||||
|
goods_code,
|
||||||
|
rdc_code,
|
||||||
|
taxpayer_type,
|
||||||
|
trade_type: PRICING_TRADE_DOMESTIC,
|
||||||
|
})
|
||||||
|
if (seq !== fenceFetchSeq) return
|
||||||
|
if (activeTaxpayerType.value !== taxpayer_type) return
|
||||||
|
fenceRows.value = rows
|
||||||
|
} catch (e) {
|
||||||
|
if (seq !== fenceFetchSeq) return
|
||||||
|
if (activeTaxpayerType.value !== taxpayer_type) return
|
||||||
|
loadError.value = pickPricingTableError(e)
|
||||||
|
// 切换 Tab/RDC 失败时保留上一份数据,避免表格闪空
|
||||||
|
} finally {
|
||||||
|
if (seq === fenceFetchSeq) loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function loadCost() {
|
async function loadCost() {
|
||||||
const code = String(props.goodsCode || '').trim()
|
const code = String(props.goodsCode || '').trim()
|
||||||
loadError.value = ''
|
loadError.value = ''
|
||||||
rdcList.value = []
|
|
||||||
fenceRows.value = []
|
fenceRows.value = []
|
||||||
activeRdcCode.value = ''
|
if (!code) {
|
||||||
activeOrgType.value = 'general'
|
activeTaxpayerType.value = PRICING_TAXPAYER_DEFAULT
|
||||||
if (!code) return
|
activeRdcCode.value = ''
|
||||||
|
return
|
||||||
loading.value = true
|
|
||||||
try {
|
|
||||||
// RDC 列表与围栏表格数据接口待接入;先保留布局与组织类型切换
|
|
||||||
} catch (e) {
|
|
||||||
loadError.value = String(e?.data?.message || e?.message || '加载失败').trim() || '加载失败'
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
}
|
||||||
|
if (!PRICING_TAXPAYER_TABS.some((t) => t.key === activeTaxpayerType.value)) {
|
||||||
|
activeTaxpayerType.value = PRICING_TAXPAYER_DEFAULT
|
||||||
|
}
|
||||||
|
pickInitialRdcCode()
|
||||||
|
await fetchFenceTable()
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
@@ -215,9 +298,21 @@ watch(
|
|||||||
{ immediate: true },
|
{ immediate: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
watch(activeOrgType, () => {
|
watch(
|
||||||
// 组织类型切换后重新拉取列表(接口接入后实现)
|
() => props.rdcList,
|
||||||
fenceRows.value = []
|
() => {
|
||||||
|
pickInitialRdcCode()
|
||||||
|
void fetchFenceTable()
|
||||||
|
},
|
||||||
|
{ deep: true },
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(activeRdcCode, () => {
|
||||||
|
void fetchFenceTable()
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(activeTaxpayerType, () => {
|
||||||
|
void fetchFenceTable()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -359,6 +454,10 @@ watch(activeOrgType, () => {
|
|||||||
border-color: #67c23a;
|
border-color: #67c23a;
|
||||||
background: #f0f9eb;
|
background: #f0f9eb;
|
||||||
}
|
}
|
||||||
|
.gt-cost-table-error {
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin: 0 12px;
|
||||||
|
}
|
||||||
.gt-cost-table-wrap {
|
.gt-cost-table-wrap {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
@@ -380,6 +479,13 @@ watch(activeOrgType, () => {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
.gt-cost-table-body {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 120px;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
.gt-cost-table-wrap :deep(.wops-empty-wrap) {
|
.gt-cost-table-wrap :deep(.wops-empty-wrap) {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
@@ -417,9 +523,27 @@ watch(activeOrgType, () => {
|
|||||||
.gt-cost-table-wrap :deep(.wops-col--goods) {
|
.gt-cost-table-wrap :deep(.wops-col--goods) {
|
||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
}
|
}
|
||||||
|
.gt-cost-table-wrap :deep(.gt-cost-head-col--tax),
|
||||||
|
.gt-cost-table-wrap :deep(.gt-cost-head-col--int-tax),
|
||||||
|
.gt-cost-table-wrap :deep(.gt-cost-head-col--min-price) {
|
||||||
|
padding-left: 4px;
|
||||||
|
padding-right: 4px;
|
||||||
|
text-align: center;
|
||||||
|
overflow: visible;
|
||||||
|
text-overflow: clip;
|
||||||
|
}
|
||||||
|
.gt-cost-table-wrap :deep(.gt-cost-col--tax-rate),
|
||||||
|
.gt-cost-table-wrap :deep(.gt-cost-col--min-price) {
|
||||||
|
padding-left: 4px;
|
||||||
|
padding-right: 4px;
|
||||||
|
}
|
||||||
.gt-cost-table-wrap :deep(.is-cols-cost-fence .wops-col--num) {
|
.gt-cost-table-wrap :deep(.is-cols-cost-fence .wops-col--num) {
|
||||||
padding-right: 6px;
|
padding-right: 6px;
|
||||||
}
|
}
|
||||||
|
.gt-cost-table-wrap :deep(.is-cols-cost-fence .gt-cost-col--tax-rate),
|
||||||
|
.gt-cost-table-wrap :deep(.is-cols-cost-fence .gt-cost-col--min-price) {
|
||||||
|
padding-right: 4px;
|
||||||
|
}
|
||||||
@media (max-width: 900px) {
|
@media (max-width: 900px) {
|
||||||
.gt-cost-layout {
|
.gt-cost-layout {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"buildId": "20260706001",
|
"buildId": "20260706004",
|
||||||
"generatedAt": "2026-07-06T04:43:39.914Z"
|
"generatedAt": "2026-07-06T11:25:37.842Z"
|
||||||
}
|
}
|
||||||
@@ -50,6 +50,31 @@ export const APP_CHANGELOG = [
|
|||||||
{
|
{
|
||||||
date: '2026-07-06',
|
date: '2026-07-06',
|
||||||
items: [
|
items: [
|
||||||
|
{
|
||||||
|
icon: 'mdi:fence',
|
||||||
|
kind: 'change',
|
||||||
|
text: '「物料弹窗 → 成本围栏」切换一般纳税人 / 小规模 / 收据组织 Tab 时,仅表格数据区 loading,Tab 按钮与表头保持不动;请求期间保留上一份数据,避免闪空;`taxpayer_type` 直传 `GENERAL` / `SMALL` / `INDIVIDUAL` 枚举。',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'mdi:fence',
|
||||||
|
kind: 'fix',
|
||||||
|
text: '「物料弹窗 → 成本围栏」定价决策表字段对齐接口:`bill_name`、`bill_tax`、`receive_company_name`、`internal_price`、`internal_bill_name`、`internal_bill_tax`、`rdc_warehouse_name`、`fence_price` 等;商品名读 `goods_categorys`;税率为 0 显示 `0%`;明显异常金额过滤为「—」。',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'mdi:fence',
|
||||||
|
kind: 'add',
|
||||||
|
text: '「物料弹窗 → 成本围栏」接入 `POST /api/pricing/table` 定价决策表:左侧售出 RDC(与仓库管理同源 `rdcs`);顶栏纳税身份 Tab;表格展示供应商集团/组织、票据与进项税率、源采购组织、内部交易价与票据、源 RDC、围栏值;`trade_type` 固定 `DOMESTIC`,切换 RDC / 纳税身份 / 物料自动请求。',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'mdi:warehouse',
|
||||||
|
kind: 'change',
|
||||||
|
text: '「物料弹窗 → 仓库管理」布局调整:去掉中间费用票据竖 Tab;各 type=4 费用票据纵向分组展示,组内「提成 / 利润」并排,各含内部/零售/渠道率与额(额后加「元」);左侧 RDC 列表宽 168px。',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'mdi:format-list-bulleted',
|
||||||
|
kind: 'change',
|
||||||
|
text: '「物料列表」新增/编辑弹窗宽度改为 88vw;基础属性字段网格按右侧可用宽度自适应列数(1920 下约 6 列),大屏随宽度递增。',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
icon: 'mdi:cart-outline',
|
icon: 'mdi:cart-outline',
|
||||||
kind: 'fix',
|
kind: 'fix',
|
||||||
|
|||||||
@@ -89,9 +89,9 @@
|
|||||||
.wops-flex-table.is-cols-pr-cost {
|
.wops-flex-table.is-cols-pr-cost {
|
||||||
--wops-cols: 7fr 10.5fr 10.5fr 7fr 8fr 8fr 6fr 9fr 6fr 8fr;
|
--wops-cols: 7fr 10.5fr 10.5fr 7fr 8fr 8fr 6fr 9fr 6fr 8fr;
|
||||||
}
|
}
|
||||||
/* 物料成本围栏(11 列):内部交易相关表头加宽,配合 88vw 弹窗单行显示 */
|
/* 物料成本围栏(11 列):税率/内部最低价收窄,源采购组织加宽 */
|
||||||
.wops-flex-table.is-cols-cost-fence {
|
.wops-flex-table.is-cols-cost-fence {
|
||||||
--wops-cols: 8fr 9fr 10fr 7fr 6fr 9fr 10fr 8fr 11fr 7fr 5fr;
|
--wops-cols: 10fr 10fr 10fr 7fr minmax(4.2em, 4fr) 10fr minmax(7.2em, 8fr) 8fr minmax(8.5em, 9fr) 9fr 5fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wops-flex-scroll {
|
.wops-flex-scroll {
|
||||||
|
|||||||
@@ -76,7 +76,6 @@
|
|||||||
/>
|
/>
|
||||||
<el-button type="primary" size="small" @click="doSearch">查询</el-button>
|
<el-button type="primary" size="small" @click="doSearch">查询</el-button>
|
||||||
<el-button size="small" @click="resetFilters">重置</el-button>
|
<el-button size="small" @click="resetFilters">重置</el-button>
|
||||||
<el-button type="warning" size="small" @click="runBatchAndLoad">重新跑批</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-loading="loading" :element-loading-text="loadingText" class="asl-body">
|
<div v-loading="loading" :element-loading-text="loadingText" class="asl-body">
|
||||||
@@ -155,9 +154,7 @@ import {
|
|||||||
normalizeFinanceBillType,
|
normalizeFinanceBillType,
|
||||||
} from '@/utils/financeBillTypes'
|
} from '@/utils/financeBillTypes'
|
||||||
import {
|
import {
|
||||||
allocAmortize,
|
|
||||||
allocShareListed,
|
allocShareListed,
|
||||||
isBenignAllocAmortizeError,
|
|
||||||
pickApiErrorMessage,
|
pickApiErrorMessage,
|
||||||
} from '@/api/warehouseAlloc'
|
} from '@/api/warehouseAlloc'
|
||||||
|
|
||||||
@@ -365,46 +362,6 @@ function onSizeChange() {
|
|||||||
search()
|
search()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runBatchAndLoad() {
|
|
||||||
const start_time = String(batchRange.start_time || '').trim()
|
|
||||||
const end_time = String(batchRange.end_time || '').trim()
|
|
||||||
if (!start_time || !end_time) {
|
|
||||||
ElMessage.warning('请选择分摊时间段(开始日期、结束日期)')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (start_time > end_time) {
|
|
||||||
ElMessage.warning('开始日期不能晚于结束日期')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
page.value = 1
|
|
||||||
loading.value = true
|
|
||||||
loadingText.value = '正在跑批中…'
|
|
||||||
try {
|
|
||||||
let amortizeHint = ''
|
|
||||||
try {
|
|
||||||
await allocAmortize({ start_time, end_time })
|
|
||||||
} catch (e) {
|
|
||||||
if (!isBenignAllocAmortizeError(e)) {
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
amortizeHint = pickApiErrorMessage(e, '')
|
|
||||||
}
|
|
||||||
|
|
||||||
activeBillCode.value = ''
|
|
||||||
await fetchShareList()
|
|
||||||
if (amortizeHint) {
|
|
||||||
ElMessage.warning(amortizeHint)
|
|
||||||
} else if (rows.value.length) {
|
|
||||||
ElMessage.success(`跑批完成,分摊结果 ${total.value} 条`)
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
ElMessage.error(pickApiErrorMessage(e, '跑批失败'))
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function search() {
|
async function search() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
loadingText.value = '加载中…'
|
loadingText.value = '加载中…'
|
||||||
@@ -433,7 +390,7 @@ function resetFilters() {
|
|||||||
|
|
||||||
async function initPage() {
|
async function initPage() {
|
||||||
await loadExpenseBills()
|
await loadExpenseBills()
|
||||||
await runBatchAndLoad()
|
await search()
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(initPage)
|
onMounted(initPage)
|
||||||
|
|||||||
@@ -76,7 +76,6 @@
|
|||||||
/>
|
/>
|
||||||
<el-button type="primary" size="small" @click="doSearch">查询</el-button>
|
<el-button type="primary" size="small" @click="doSearch">查询</el-button>
|
||||||
<el-button size="small" @click="resetFilters">重置</el-button>
|
<el-button size="small" @click="resetFilters">重置</el-button>
|
||||||
<el-button type="warning" size="small" @click="runBatchAndLoad">重新跑批</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-loading="loading" :element-loading-text="loadingText" class="dsl-body">
|
<div v-loading="loading" :element-loading-text="loadingText" class="dsl-body">
|
||||||
@@ -155,9 +154,7 @@ import {
|
|||||||
normalizeFinanceBillType,
|
normalizeFinanceBillType,
|
||||||
} from '@/utils/financeBillTypes'
|
} from '@/utils/financeBillTypes'
|
||||||
import {
|
import {
|
||||||
deployAmortize,
|
|
||||||
deployShareListed,
|
deployShareListed,
|
||||||
isBenignDeployAmortizeError,
|
|
||||||
pickApiErrorMessage,
|
pickApiErrorMessage,
|
||||||
} from '@/api/warehouseDeploy'
|
} from '@/api/warehouseDeploy'
|
||||||
|
|
||||||
@@ -365,46 +362,6 @@ function onSizeChange() {
|
|||||||
search()
|
search()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runBatchAndLoad() {
|
|
||||||
const start_time = String(batchRange.start_time || '').trim()
|
|
||||||
const end_time = String(batchRange.end_time || '').trim()
|
|
||||||
if (!start_time || !end_time) {
|
|
||||||
ElMessage.warning('请选择分摊时间段(开始日期、结束日期)')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (start_time > end_time) {
|
|
||||||
ElMessage.warning('开始日期不能晚于结束日期')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
page.value = 1
|
|
||||||
loading.value = true
|
|
||||||
loadingText.value = '正在跑批中…'
|
|
||||||
try {
|
|
||||||
let amortizeHint = ''
|
|
||||||
try {
|
|
||||||
await deployAmortize({ start_time, end_time })
|
|
||||||
} catch (e) {
|
|
||||||
if (!isBenignDeployAmortizeError(e)) {
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
amortizeHint = pickApiErrorMessage(e, '')
|
|
||||||
}
|
|
||||||
|
|
||||||
activeBillCode.value = ''
|
|
||||||
await fetchShareList()
|
|
||||||
if (amortizeHint) {
|
|
||||||
ElMessage.warning(amortizeHint)
|
|
||||||
} else if (rows.value.length) {
|
|
||||||
ElMessage.success(`跑批完成,分摊结果 ${total.value} 条`)
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
ElMessage.error(pickApiErrorMessage(e, '跑批失败'))
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function search() {
|
async function search() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
loadingText.value = '加载中…'
|
loadingText.value = '加载中…'
|
||||||
@@ -433,7 +390,7 @@ function resetFilters() {
|
|||||||
|
|
||||||
async function initPage() {
|
async function initPage() {
|
||||||
await loadExpenseBills()
|
await loadExpenseBills()
|
||||||
await runBatchAndLoad()
|
await search()
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(initPage)
|
onMounted(initPage)
|
||||||
|
|||||||
@@ -76,7 +76,6 @@
|
|||||||
/>
|
/>
|
||||||
<el-button type="primary" size="small" @click="doSearch">查询</el-button>
|
<el-button type="primary" size="small" @click="doSearch">查询</el-button>
|
||||||
<el-button size="small" @click="resetFilters">重置</el-button>
|
<el-button size="small" @click="resetFilters">重置</el-button>
|
||||||
<el-button type="warning" size="small" @click="runBatchAndLoad">重新跑批</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-loading="loading" :element-loading-text="loadingText" class="fsl-body">
|
<div v-loading="loading" :element-loading-text="loadingText" class="fsl-body">
|
||||||
@@ -158,9 +157,7 @@ import {
|
|||||||
normalizeFinanceBillType,
|
normalizeFinanceBillType,
|
||||||
} from '@/utils/financeBillTypes'
|
} from '@/utils/financeBillTypes'
|
||||||
import {
|
import {
|
||||||
freightAmortize,
|
|
||||||
freightShareListed,
|
freightShareListed,
|
||||||
isBenignFreightAmortizeError,
|
|
||||||
pickApiErrorMessage,
|
pickApiErrorMessage,
|
||||||
} from '@/api/warehouseFreight'
|
} from '@/api/warehouseFreight'
|
||||||
|
|
||||||
@@ -369,41 +366,6 @@ function onSizeChange() {
|
|||||||
search()
|
search()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runBatchAndLoad() {
|
|
||||||
const start_time = String(batchRange.start_time || '').trim()
|
|
||||||
const end_time = String(batchRange.end_time || '').trim()
|
|
||||||
if (!start_time || !end_time) {
|
|
||||||
ElMessage.warning('请选择分摊时间段(开始日期、结束日期)')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (start_time > end_time) {
|
|
||||||
ElMessage.warning('开始日期不能晚于结束日期')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
page.value = 1
|
|
||||||
loading.value = true
|
|
||||||
loadingText.value = '正在跑批中…'
|
|
||||||
try {
|
|
||||||
try {
|
|
||||||
await freightAmortize({ start_time, end_time })
|
|
||||||
} catch (e) {
|
|
||||||
if (!isBenignFreightAmortizeError(e)) {
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await fetchShareList()
|
|
||||||
if (rows.value.length) {
|
|
||||||
ElMessage.success(`跑批完成,分摊结果 ${total.value} 条`)
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
ElMessage.error(pickApiErrorMessage(e, '跑批失败'))
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function search() {
|
async function search() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
loadingText.value = '加载中…'
|
loadingText.value = '加载中…'
|
||||||
@@ -432,7 +394,7 @@ function resetFilters() {
|
|||||||
|
|
||||||
async function initPage() {
|
async function initPage() {
|
||||||
await loadExpenseBills()
|
await loadExpenseBills()
|
||||||
await runBatchAndLoad()
|
await search()
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(initPage)
|
onMounted(initPage)
|
||||||
|
|||||||
@@ -68,7 +68,6 @@
|
|||||||
/>
|
/>
|
||||||
<el-button type="primary" size="small" @click="doSearch">查询</el-button>
|
<el-button type="primary" size="small" @click="doSearch">查询</el-button>
|
||||||
<el-button size="small" @click="resetFilters">重置</el-button>
|
<el-button size="small" @click="resetFilters">重置</el-button>
|
||||||
<el-button type="warning" size="small" @click="runBatchAndLoad">重新跑批</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-loading="loading" :element-loading-text="loadingText" class="pcsl-body">
|
<div v-loading="loading" :element-loading-text="loadingText" class="pcsl-body">
|
||||||
@@ -150,11 +149,9 @@ import {
|
|||||||
normalizeFinanceBillType,
|
normalizeFinanceBillType,
|
||||||
} from '@/utils/financeBillTypes'
|
} from '@/utils/financeBillTypes'
|
||||||
import {
|
import {
|
||||||
prCostAmortize,
|
|
||||||
prCostShareListed,
|
prCostShareListed,
|
||||||
pickPrCostShareGoodsName,
|
pickPrCostShareGoodsName,
|
||||||
pickApiErrorMessage,
|
pickApiErrorMessage,
|
||||||
isBenignAmortizeError,
|
|
||||||
} from '@/api/prCost'
|
} from '@/api/prCost'
|
||||||
|
|
||||||
defineOptions({ name: 'PrCostShareListed' })
|
defineOptions({ name: 'PrCostShareListed' })
|
||||||
@@ -375,51 +372,6 @@ function onSizeChange() {
|
|||||||
search()
|
search()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** cost/amortize(月度批量)→ cost/share/listed */
|
|
||||||
async function runBatchAndLoad() {
|
|
||||||
const start_time = String(batchRange.start_time || '').trim()
|
|
||||||
const end_time = String(batchRange.end_time || '').trim()
|
|
||||||
if (!start_time || !end_time) {
|
|
||||||
ElMessage.warning('请选择分摊时间段(开始日期、结束日期)')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (start_time > end_time) {
|
|
||||||
ElMessage.warning('开始日期不能晚于结束日期')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
page.value = 1
|
|
||||||
loading.value = true
|
|
||||||
loadingText.value = '正在跑批中…'
|
|
||||||
try {
|
|
||||||
let amortizeHint = ''
|
|
||||||
try {
|
|
||||||
await prCostAmortize({ start_time, end_time })
|
|
||||||
} catch (e) {
|
|
||||||
if (!isBenignAmortizeError(e)) {
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
amortizeHint = pickApiErrorMessage(e, '')
|
|
||||||
}
|
|
||||||
|
|
||||||
activeBillCode.value = ''
|
|
||||||
await fetchShareList()
|
|
||||||
if (amortizeHint) {
|
|
||||||
ElMessage.warning(amortizeHint)
|
|
||||||
} else if (rows.value.length) {
|
|
||||||
ElMessage.success(`跑批完成,分摊结果 ${total.value} 条`)
|
|
||||||
} else {
|
|
||||||
ElMessage.warning(
|
|
||||||
`跑批完成,暂无分摊结果(${start_time} ~ ${end_time})。请确认:① 该时段内有已确认/已到库采购(按订单确认时间,非采购日期);② 公关费用与采购在同一供应组织且商品能匹配;③ 票据 Tab 选「全部」`,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
ElMessage.error(pickApiErrorMessage(e, '跑批失败'))
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function search() {
|
async function search() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
loadingText.value = '加载中…'
|
loadingText.value = '加载中…'
|
||||||
@@ -447,7 +399,7 @@ function resetFilters() {
|
|||||||
|
|
||||||
async function initPage() {
|
async function initPage() {
|
||||||
await loadExpenseBills()
|
await loadExpenseBills()
|
||||||
await runBatchAndLoad()
|
await search()
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(initPage)
|
onMounted(initPage)
|
||||||
|
|||||||
@@ -44,7 +44,6 @@
|
|||||||
/>
|
/>
|
||||||
<el-button type="primary" size="small" @click="doSearch">查询</el-button>
|
<el-button type="primary" size="small" @click="doSearch">查询</el-button>
|
||||||
<el-button size="small" @click="resetFilters">重置</el-button>
|
<el-button size="small" @click="resetFilters">重置</el-button>
|
||||||
<el-button type="warning" size="small" @click="runBatchAndLoad">重新跑批</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-loading="loading" :element-loading-text="loadingText" class="wsl-body">
|
<div v-loading="loading" :element-loading-text="loadingText" class="wsl-body">
|
||||||
@@ -115,9 +114,7 @@ import WarehouseOpsNameCode from '@/components/warehouse/WarehouseOpsNameCode.vu
|
|||||||
import { formatOpsLogTime } from '@/utils/warehouseOpsDisplay'
|
import { formatOpsLogTime } from '@/utils/warehouseOpsDisplay'
|
||||||
import { pickGoodsNameFromListedRow } from '@/utils/goodsCategorys'
|
import { pickGoodsNameFromListedRow } from '@/utils/goodsCategorys'
|
||||||
import {
|
import {
|
||||||
isBenignWasteAmortizeError,
|
|
||||||
pickApiErrorMessage,
|
pickApiErrorMessage,
|
||||||
wasteAmortize,
|
|
||||||
wasteShareListed,
|
wasteShareListed,
|
||||||
} from '@/api/warehouseWaste'
|
} from '@/api/warehouseWaste'
|
||||||
|
|
||||||
@@ -245,45 +242,6 @@ function onSizeChange() {
|
|||||||
search()
|
search()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runBatchAndLoad() {
|
|
||||||
const start_time = String(batchRange.start_time || '').trim()
|
|
||||||
const end_time = String(batchRange.end_time || '').trim()
|
|
||||||
if (!start_time || !end_time) {
|
|
||||||
ElMessage.warning('请选择分摊时间段(开始日期、结束日期)')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (start_time > end_time) {
|
|
||||||
ElMessage.warning('开始日期不能晚于结束日期')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
page.value = 1
|
|
||||||
loading.value = true
|
|
||||||
loadingText.value = '正在跑批中…'
|
|
||||||
try {
|
|
||||||
let amortizeHint = ''
|
|
||||||
try {
|
|
||||||
await wasteAmortize({ start_time, end_time })
|
|
||||||
} catch (e) {
|
|
||||||
if (!isBenignWasteAmortizeError(e)) {
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
amortizeHint = pickApiErrorMessage(e, '')
|
|
||||||
}
|
|
||||||
|
|
||||||
await fetchShareList()
|
|
||||||
if (amortizeHint) {
|
|
||||||
ElMessage.warning(amortizeHint)
|
|
||||||
} else if (rows.value.length) {
|
|
||||||
ElMessage.success(`跑批完成,分摊结果 ${total.value} 条`)
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
ElMessage.error(pickApiErrorMessage(e, '跑批失败'))
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function search() {
|
async function search() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
loadingText.value = '加载中…'
|
loadingText.value = '加载中…'
|
||||||
@@ -310,7 +268,7 @@ function resetFilters() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function initPage() {
|
async function initPage() {
|
||||||
await runBatchAndLoad()
|
await search()
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(initPage)
|
onMounted(initPage)
|
||||||
|
|||||||
@@ -500,7 +500,10 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="mlActiveNavKey === ML_NAV_COST" class="mf-nav-pane mf-nav-pane--cost-api">
|
<div v-if="mlActiveNavKey === ML_NAV_COST" class="mf-nav-pane mf-nav-pane--cost-api">
|
||||||
<GlobalTabCostPanel :goods-code="materialEditingId || ''" />
|
<GlobalTabCostPanel
|
||||||
|
:goods-code="materialEditingId || ''"
|
||||||
|
:rdc-list="materialWarehouseRdcs"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<template v-for="(cat, catIdx) in materialForm.categories" :key="`${cat.category_code}-${catIdx}`">
|
<template v-for="(cat, catIdx) in materialForm.categories" :key="`${cat.category_code}-${catIdx}`">
|
||||||
<div
|
<div
|
||||||
|
|||||||
Reference in New Issue
Block a user