2020706005

This commit is contained in:
xiaojibeier
2026-07-06 19:26:03 +08:00
parent dd59b3aab5
commit f5206a2005
16 changed files with 359 additions and 380 deletions
-19
View File
@@ -160,25 +160,6 @@ export async function prCostRemove(expense_code) {
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 = {}) {
const limit = 50
+142
View File
@@ -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'
/** 成本围栏 · 纳税身份 Tabkey 即接口 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
}
-16
View File
@@ -287,19 +287,3 @@ export async function allocShareListed(body = {}) {
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)
}
-16
View File
@@ -270,19 +270,3 @@ export async function deployShareListed(body = {}) {
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)
}
-34
View File
@@ -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 = '操作失败') {
return String(err?.data?.message || err?.message || fallback).trim() || fallback
}
-16
View File
@@ -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 = '操作失败') {
return String(
err?.data?.message
+171 -47
View File
@@ -1,50 +1,56 @@
<template>
<div class="gt-cost-panel" v-loading="loading" element-loading-text="加载中…">
<div class="gt-cost-panel">
<template v-if="!goodsCode">
<el-empty :image-size="56" description="请先保存物料后再查看成本围栏" class="gt-cost-empty" />
</template>
<template v-else-if="loadError">
<el-alert type="error" :title="loadError" show-icon :closable="false" />
</template>
<template v-else>
<div class="gt-cost-layout">
<aside class="gt-cost-rdc-nav" aria-label="售出 RDC 列表">
<div class="gt-cost-rdc-hd">售出 RDC 列表</div>
<template v-if="rdcList.length">
<template v-if="rdcOptions.length">
<button
v-for="rdc in rdcList"
:key="rdc.warehouse_code"
v-for="rdc in rdcOptions"
:key="rdc.code"
type="button"
class="gt-cost-rdc-item"
:class="{ 'is-active': activeRdcCode === rdc.warehouse_code }"
@click="activeRdcCode = rdc.warehouse_code"
:class="{ 'is-active': activeRdcCode === rdc.code }"
@click="activeRdcCode = rdc.code"
>
<span class="gt-cost-rdc-name">{{ rdc.name || rdc.warehouse_code }}</span>
<span v-if="rdc.warehouse_code" class="gt-cost-rdc-code">{{ rdc.warehouse_code }}</span>
<span class="gt-cost-rdc-name">{{ rdcDisplayName(rdc) }}</span>
<span v-if="rdcDisplaySub(rdc)" class="gt-cost-rdc-code">{{ rdcDisplaySub(rdc) }}</span>
</button>
</template>
<p v-else class="gt-cost-rdc-empty">RDC 列表接口待接入</p>
<p v-else class="gt-cost-rdc-empty">暂无关联 RDC</p>
</aside>
<div class="gt-cost-main">
<div class="gt-cost-org-tabs" role="tablist" aria-label="组织类型">
<button
v-for="tab in ORG_TYPE_TABS"
v-for="tab in PRICING_TAXPAYER_TABS"
:key="tab.key"
type="button"
role="tab"
class="gt-cost-org-tab"
:class="[
{ 'is-active': activeOrgType === tab.key },
{ 'is-active': activeTaxpayerType === tab.key },
orgTypeTabClass(tab.key),
]"
:aria-selected="activeOrgType === tab.key"
@click="activeOrgType = tab.key"
:aria-selected="activeTaxpayerType === tab.key"
@click="activeTaxpayerType = tab.key"
>
{{ tab.label }}
</button>
</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="wops-flex-table is-cols-cost-fence">
<div class="wops-flex-scroll">
@@ -60,7 +66,13 @@
</div>
</div>
<div v-if="!fenceRows.length" class="wops-empty-wrap">
<div
class="gt-cost-table-body"
v-loading="loading"
element-loading-text="加载中"
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>
@@ -82,15 +94,15 @@
<div class="wops-col wops-col--plain">
<span class="wops-ellipsis">{{ row.bill_type || '—' }}</span>
</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">
<span class="wops-name wops-ellipsis">{{ row.source_company_name || '—' }}</span>
</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">
<span class="wops-ellipsis">{{ row.internal_bill_type || '—' }}</span>
</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">
<span class="wops-name wops-ellipsis">{{ row.source_rdc_name || row.source_rdc || '—' }}</span>
</div>
@@ -101,23 +113,28 @@
</div>
</div>
</div>
</div>
</template>
</div>
</template>
<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({
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 = [
{ key: 'supplier_bloc_name', label: '供应商集团名称' },
{ key: 'supplier_company_name', label: '供应商组织名称' },
@@ -161,20 +178,48 @@ function colHeadColorClass(key) {
}
function orgTypeTabClass(key) {
if (key === 'general') return 'is-general'
if (key === 'small') return 'is-small'
if (key === 'personal') return 'is-personal'
if (key === 'GENERAL') return 'is-general'
if (key === 'SMALL') return 'is-small'
if (key === 'INDIVIDUAL') return 'is-personal'
return ''
}
const loading = ref(false)
const loadError = ref('')
const activeOrgType = ref('general')
/** 当前 Tab 对应的接口 taxpayer_type 枚举 */
const activeTaxpayerType = ref(PRICING_TAXPAYER_DEFAULT)
const activeRdcCode = ref('')
/** @type {import('vue').Ref<Array<{ warehouse_code: string, name: string }>>} */
const rdcList = ref([])
/** @type {import('vue').Ref<object[]>} */
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) {
if (v == null || v === '') return '—'
@@ -190,23 +235,61 @@ function fmtTaxRate(v) {
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() {
const code = String(props.goodsCode || '').trim()
loadError.value = ''
rdcList.value = []
fenceRows.value = []
if (!code) {
activeTaxpayerType.value = PRICING_TAXPAYER_DEFAULT
activeRdcCode.value = ''
activeOrgType.value = 'general'
if (!code) return
loading.value = true
try {
// RDC 列表与围栏表格数据接口待接入;先保留布局与组织类型切换
} catch (e) {
loadError.value = String(e?.data?.message || e?.message || '加载失败').trim() || '加载失败'
} finally {
loading.value = false
return
}
if (!PRICING_TAXPAYER_TABS.some((t) => t.key === activeTaxpayerType.value)) {
activeTaxpayerType.value = PRICING_TAXPAYER_DEFAULT
}
pickInitialRdcCode()
await fetchFenceTable()
}
watch(
@@ -215,9 +298,21 @@ watch(
{ immediate: true },
)
watch(activeOrgType, () => {
// 组织类型切换后重新拉取列表(接口接入后实现)
fenceRows.value = []
watch(
() => props.rdcList,
() => {
pickInitialRdcCode()
void fetchFenceTable()
},
{ deep: true },
)
watch(activeRdcCode, () => {
void fetchFenceTable()
})
watch(activeTaxpayerType, () => {
void fetchFenceTable()
})
</script>
@@ -359,6 +454,10 @@ watch(activeOrgType, () => {
border-color: #67c23a;
background: #f0f9eb;
}
.gt-cost-table-error {
flex-shrink: 0;
margin: 0 12px;
}
.gt-cost-table-wrap {
flex: 1;
min-height: 0;
@@ -380,6 +479,13 @@ watch(activeOrgType, () => {
flex: 1;
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) {
flex: 1;
min-height: 0;
@@ -417,9 +523,27 @@ watch(activeOrgType, () => {
.gt-cost-table-wrap :deep(.wops-col--goods) {
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) {
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) {
.gt-cost-layout {
flex-direction: column;
+2 -2
View File
@@ -1,4 +1,4 @@
{
"buildId": "20260706001",
"generatedAt": "2026-07-06T04:43:39.914Z"
"buildId": "20260706004",
"generatedAt": "2026-07-06T11:25:37.842Z"
}
+25
View File
@@ -50,6 +50,31 @@ export const APP_CHANGELOG = [
{
date: '2026-07-06',
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',
kind: 'fix',
+2 -2
View File
@@ -89,9 +89,9 @@
.wops-flex-table.is-cols-pr-cost {
--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-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 {
+1 -44
View File
@@ -76,7 +76,6 @@
/>
<el-button type="primary" size="small" @click="doSearch">查询</el-button>
<el-button size="small" @click="resetFilters">重置</el-button>
<el-button type="warning" size="small" @click="runBatchAndLoad">重新跑批</el-button>
</div>
<div v-loading="loading" :element-loading-text="loadingText" class="asl-body">
@@ -155,9 +154,7 @@ import {
normalizeFinanceBillType,
} from '@/utils/financeBillTypes'
import {
allocAmortize,
allocShareListed,
isBenignAllocAmortizeError,
pickApiErrorMessage,
} from '@/api/warehouseAlloc'
@@ -365,46 +362,6 @@ function onSizeChange() {
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() {
loading.value = true
loadingText.value = '加载中…'
@@ -433,7 +390,7 @@ function resetFilters() {
async function initPage() {
await loadExpenseBills()
await runBatchAndLoad()
await search()
}
onMounted(initPage)
+1 -44
View File
@@ -76,7 +76,6 @@
/>
<el-button type="primary" size="small" @click="doSearch">查询</el-button>
<el-button size="small" @click="resetFilters">重置</el-button>
<el-button type="warning" size="small" @click="runBatchAndLoad">重新跑批</el-button>
</div>
<div v-loading="loading" :element-loading-text="loadingText" class="dsl-body">
@@ -155,9 +154,7 @@ import {
normalizeFinanceBillType,
} from '@/utils/financeBillTypes'
import {
deployAmortize,
deployShareListed,
isBenignDeployAmortizeError,
pickApiErrorMessage,
} from '@/api/warehouseDeploy'
@@ -365,46 +362,6 @@ function onSizeChange() {
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() {
loading.value = true
loadingText.value = '加载中…'
@@ -433,7 +390,7 @@ function resetFilters() {
async function initPage() {
await loadExpenseBills()
await runBatchAndLoad()
await search()
}
onMounted(initPage)
+1 -39
View File
@@ -76,7 +76,6 @@
/>
<el-button type="primary" size="small" @click="doSearch">查询</el-button>
<el-button size="small" @click="resetFilters">重置</el-button>
<el-button type="warning" size="small" @click="runBatchAndLoad">重新跑批</el-button>
</div>
<div v-loading="loading" :element-loading-text="loadingText" class="fsl-body">
@@ -158,9 +157,7 @@ import {
normalizeFinanceBillType,
} from '@/utils/financeBillTypes'
import {
freightAmortize,
freightShareListed,
isBenignFreightAmortizeError,
pickApiErrorMessage,
} from '@/api/warehouseFreight'
@@ -369,41 +366,6 @@ function onSizeChange() {
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() {
loading.value = true
loadingText.value = '加载中…'
@@ -432,7 +394,7 @@ function resetFilters() {
async function initPage() {
await loadExpenseBills()
await runBatchAndLoad()
await search()
}
onMounted(initPage)
+1 -49
View File
@@ -68,7 +68,6 @@
/>
<el-button type="primary" size="small" @click="doSearch">查询</el-button>
<el-button size="small" @click="resetFilters">重置</el-button>
<el-button type="warning" size="small" @click="runBatchAndLoad">重新跑批</el-button>
</div>
<div v-loading="loading" :element-loading-text="loadingText" class="pcsl-body">
@@ -150,11 +149,9 @@ import {
normalizeFinanceBillType,
} from '@/utils/financeBillTypes'
import {
prCostAmortize,
prCostShareListed,
pickPrCostShareGoodsName,
pickApiErrorMessage,
isBenignAmortizeError,
} from '@/api/prCost'
defineOptions({ name: 'PrCostShareListed' })
@@ -375,51 +372,6 @@ function onSizeChange() {
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() {
loading.value = true
loadingText.value = '加载中…'
@@ -447,7 +399,7 @@ function resetFilters() {
async function initPage() {
await loadExpenseBills()
await runBatchAndLoad()
await search()
}
onMounted(initPage)
+1 -43
View File
@@ -44,7 +44,6 @@
/>
<el-button type="primary" size="small" @click="doSearch">查询</el-button>
<el-button size="small" @click="resetFilters">重置</el-button>
<el-button type="warning" size="small" @click="runBatchAndLoad">重新跑批</el-button>
</div>
<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 { pickGoodsNameFromListedRow } from '@/utils/goodsCategorys'
import {
isBenignWasteAmortizeError,
pickApiErrorMessage,
wasteAmortize,
wasteShareListed,
} from '@/api/warehouseWaste'
@@ -245,45 +242,6 @@ function onSizeChange() {
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() {
loading.value = true
loadingText.value = '加载中…'
@@ -310,7 +268,7 @@ function resetFilters() {
}
async function initPage() {
await runBatchAndLoad()
await search()
}
onMounted(initPage)
+4 -1
View File
@@ -500,7 +500,10 @@
/>
</div>
<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>
<template v-for="(cat, catIdx) in materialForm.categories" :key="`${cat.category_code}-${catIdx}`">
<div