Commit 39999bd89c52e49e09cda6468f37dab47cf8ae79

Authored by “wangming”
1 parent cc466204

feat(erp-plat): 单据汇总与明细页、收银端及 Extend 后端配套

Made-with: Cursor
Showing 111 changed files with 13714 additions and 2454 deletions

Too many changes.

To preserve performance only 100 of 111 files are displayed.

Antis.Erp.Plat/antis-ncc-admin/src/components/NCC-billSummary/index.vue 0 → 100644
  1 +<template>
  2 + <span class="ncc-bill-summary" :class="rootClass">
  3 + <!-- 详情/弹窗等块级:可多行、带图标 -->
  4 + <template v-if="mode === 'block'">
  5 + <i v-if="showIcon" class="el-icon-document ncc-bill-summary__icon" aria-hidden="true" />
  6 + <span class="ncc-bill-summary__block">{{ displayText }}</span>
  7 + </template>
  8 + <!-- 表格:勿用 el-tooltip 包一层——在 el-table .cell 内易出现触发区域宽高为 0,接口有数据但肉眼看不到 -->
  9 + <template v-else-if="useElementTooltip && !isEmpty">
  10 + <el-tooltip
  11 + effect="dark"
  12 + :content="rawText"
  13 + placement="top"
  14 + :open-delay="280"
  15 + >
  16 + <span class="ncc-bill-summary__table-inner">
  17 + <span class="ncc-bill-summary__table-text cell-nowrap">{{ displayText }}</span>
  18 + </span>
  19 + </el-tooltip>
  20 + </template>
  21 + <template v-else>
  22 + <span
  23 + class="ncc-bill-summary__table-inner"
  24 + :title="!isEmpty && nativeTitle ? rawText : ''"
  25 + >
  26 + <span class="ncc-bill-summary__table-text cell-nowrap">{{ displayText }}</span>
  27 + </span>
  28 + </template>
  29 + </span>
  30 +</template>
  31 +
  32 +<script>
  33 +/**
  34 + * 业务摘要统一展示(与后端 zy 等字段配合;空值显示「无」)
  35 + * 列表摘要列请用 <ncc-table-summary-cell :row="scope.row" fields="zy,Zy" />(表格内勿用本组件)。
  36 + * 详情/表单:<ncc-bill-summary :value="detail.zy" mode="block" />
  37 + */
  38 +export default {
  39 + name: 'NCCBillSummary',
  40 + props: {
  41 + /** 摘要原文(后端生成或表单录入) */
  42 + value: { type: [String, Number], default: '' },
  43 + /** table:列表单元格;block:详情/卡片 */
  44 + mode: { type: String, default: 'table', validator: v => ['table', 'block'].includes(v) },
  45 + /** 空值占位 */
  46 + emptyText: { type: String, default: '无' },
  47 + /**
  48 + * 表格下是否使用 Element Tooltip(默认 false:避免表格单元格内触发区为 0 宽导致不显示)
  49 + * 需要时可传 :element-tooltip="true"
  50 + */
  51 + elementTooltip: { type: Boolean, default: false },
  52 + /** 表格模式下非空时是否设置原生 title(悬停看全文) */
  53 + nativeTitle: { type: Boolean, default: true },
  54 + /** 块级模式下是否显示文档图标 */
  55 + showIcon: { type: Boolean, default: true }
  56 + },
  57 + computed: {
  58 + rawText() {
  59 + if (this.value === null || this.value === undefined) return ''
  60 + return String(this.value).trim()
  61 + },
  62 + isEmpty() {
  63 + return this.rawText === ''
  64 + },
  65 + displayText() {
  66 + return this.isEmpty ? this.emptyText : this.rawText
  67 + },
  68 + useElementTooltip() {
  69 + return this.mode !== 'block' && this.elementTooltip
  70 + },
  71 + rootClass() {
  72 + return {
  73 + 'is-empty': this.isEmpty,
  74 + 'is-block': this.mode === 'block',
  75 + 'is-table': this.mode !== 'block'
  76 + }
  77 + }
  78 + }
  79 +}
  80 +</script>
  81 +
  82 +<style scoped lang="scss">
  83 +.ncc-bill-summary.is-table {
  84 + display: block;
  85 + width: 100%;
  86 + min-width: 0;
  87 + max-width: 100%;
  88 + box-sizing: border-box;
  89 + /* 防止祖先 font-size:0 等导致文字「有 DOM 看不见」 */
  90 + font-size: 13px !important;
  91 + line-height: 1.5 !important;
  92 + color: #303133 !important;
  93 + vertical-align: middle;
  94 +}
  95 +.ncc-bill-summary.is-empty {
  96 + color: #909399 !important;
  97 +}
  98 +.ncc-bill-summary.is-block {
  99 + display: block;
  100 + width: auto;
  101 + font-size: 13px;
  102 + line-height: 1.5;
  103 + color: #303133;
  104 +}
  105 +.ncc-bill-summary__icon {
  106 + margin-right: 6px;
  107 + color: #409eff;
  108 + font-size: 14px;
  109 + vertical-align: -1px;
  110 +}
  111 +.ncc-bill-summary__block {
  112 + display: inline;
  113 + white-space: normal;
  114 + word-break: break-all;
  115 + line-height: 1.55;
  116 +}
  117 +/* 表格内:单行省略,占满单元格内容区 */
  118 +.ncc-bill-summary__table-inner {
  119 + display: block;
  120 + width: 100%;
  121 + min-width: 0;
  122 + overflow: hidden;
  123 +}
  124 +.ncc-bill-summary__table-text {
  125 + display: block;
  126 + overflow: hidden;
  127 + text-overflow: ellipsis;
  128 + white-space: nowrap;
  129 + max-width: 100%;
  130 +}
  131 +.cell-nowrap {
  132 + white-space: nowrap;
  133 +}
  134 +</style>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/components/NCC-tableSummaryCell/index.vue 0 → 100644
  1 +<template>
  2 + <div class="ncc-table-summary-cell" :title="titleAttr">
  3 + <i class="el-icon-reading ncc-table-summary-cell__ico" aria-hidden="true" />
  4 + <span class="ncc-table-summary-cell__txt">{{ displayText }}</span>
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +/**
  10 + * 列表「摘要」列专用:与 wtDjzy 一致用 flex + 省略,不用 el-tooltip / 旧 ncc-bill-summary,避免表格单元格内不显示。
  11 + * 用法:<ncc-table-summary-cell :row="scope.row" fields="zy,Zy" />
  12 + */
  13 +export default {
  14 + name: 'NccTableSummaryCell',
  15 + props: {
  16 + row: { type: Object, default: null },
  17 + /** 逗号分隔,按顺序取 row 上第一个非空字段 */
  18 + fields: { type: String, default: 'zy,Zy' }
  19 + },
  20 + computed: {
  21 + keyList() {
  22 + return this.fields.split(',').map(s => s.trim()).filter(Boolean)
  23 + },
  24 + raw() {
  25 + const r = this.row
  26 + if (!r) return ''
  27 + for (const k of this.keyList) {
  28 + const v = r[k]
  29 + if (v != null && String(v).trim() !== '') return String(v).trim()
  30 + }
  31 + return ''
  32 + },
  33 + displayText() {
  34 + return this.raw || '无'
  35 + },
  36 + titleAttr() {
  37 + return this.raw || ''
  38 + }
  39 + }
  40 +}
  41 +</script>
  42 +
  43 +<style scoped lang="scss">
  44 +.ncc-table-summary-cell {
  45 + display: flex;
  46 + align-items: center;
  47 + min-width: 0;
  48 + width: 100%;
  49 +}
  50 +.ncc-table-summary-cell__ico {
  51 + flex-shrink: 0;
  52 + color: #409eff;
  53 + margin-right: 6px;
  54 + font-size: 14px;
  55 +}
  56 +.ncc-table-summary-cell__txt {
  57 + flex: 1;
  58 + min-width: 0;
  59 + overflow: hidden;
  60 + text-overflow: ellipsis;
  61 + white-space: nowrap;
  62 + color: #303133;
  63 + font-size: 13px;
  64 + line-height: 1.5;
  65 +}
  66 +</style>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/components/index.js
... ... @@ -8,6 +8,8 @@ import Screenfull from &#39;@/components/Screenfull&#39;
8 8 import ColumnSettings from '@/components/ColumnSettings'
9 9 import NCCQuill from '@/components/NCCEditor/quill'
10 10 import UserSelect from '@/components/NCC-userSelect'
  11 +import NCCBillSummary from '@/components/NCC-billSummary'
  12 +import NccTableSummaryCell from '@/components/NCC-tableSummaryCell'
11 13 import uploadBtn from '@/components/NCC-uploadBtn'
12 14 // 代码生成器专供
13 15 import NCCText from '@/components/Generator/components/NCCText'
... ... @@ -47,6 +49,8 @@ export default {
47 49 Vue.component('DepSelect', DepSelect)
48 50 Vue.component('PosSelect', PosSelect)
49 51 Vue.component('UserSelect', UserSelect)
  52 + Vue.component('NCCBillSummary', NCCBillSummary)
  53 + Vue.component('NccTableSummaryCell', NccTableSummaryCell)
50 54 Vue.component('DicSelect', DicSelect)
51 55 Vue.component('BillRule', BillRule)
52 56 Vue.component('NCCInputTable', NCCInputTable)
... ...
Antis.Erp.Plat/antis-ncc-admin/src/utils/wtComboSkzhDisplay.js 0 → 100644
  1 +import { dynamicText } from '@/filters'
  2 +
  3 +/**
  4 + * 收款账户字典 id → 显示名(全程 String 比较,避免大整数精度导致 == 失败)
  5 + * 未匹配时返回空串,便于调用方回退到 skfs 等。
  6 + */
  7 +export function resolveSkzhDictionaryLabel(id, options) {
  8 + if (id === null || id === undefined || id === '') return ''
  9 + const opts = Array.isArray(options) ? options : []
  10 + const sid = String(id).trim()
  11 + if (!sid) return ''
  12 + const row = opts.find(o => {
  13 + const oid = o.id != null && o.id !== '' ? String(o.id).trim() : ''
  14 + const ofid = o.F_Id != null && o.F_Id !== '' ? String(o.F_Id).trim() : ''
  15 + return oid === sid || ofid === sid
  16 + })
  17 + if (!row) return ''
  18 + const name = (row.fullName || row.F_FullName || row.F_mdmc || '').trim()
  19 + return name || ''
  20 +}
  21 +
  22 +/**
  23 + * 解析 skmx / fkmx:兼容双层 JSON 字符串、单对象非数组。
  24 + * @returns {{ list: Array, rawFallback: string }}
  25 + */
  26 +export function parseWtMxJsonArray(val) {
  27 + if (val === null || val === undefined || val === '') {
  28 + return { list: [], rawFallback: '' }
  29 + }
  30 + if (Array.isArray(val)) {
  31 + return { list: val, rawFallback: '' }
  32 + }
  33 + if (typeof val === 'object') {
  34 + return { list: [val], rawFallback: '' }
  35 + }
  36 + if (typeof val !== 'string') {
  37 + return { list: [], rawFallback: String(val) }
  38 + }
  39 + const str = val.trim()
  40 + if (!str) return { list: [], rawFallback: '' }
  41 + try {
  42 + let cur = JSON.parse(str)
  43 + let guard = 0
  44 + while (typeof cur === 'string' && guard < 4) {
  45 + cur = JSON.parse(String(cur).trim())
  46 + guard += 1
  47 + }
  48 + if (Array.isArray(cur)) return { list: cur, rawFallback: '' }
  49 + if (cur && typeof cur === 'object') return { list: [cur], rawFallback: '' }
  50 + return { list: [], rawFallback: str }
  51 + } catch (e) {
  52 + return { list: [], rawFallback: str }
  53 + }
  54 +}
  55 +
  56 +/**
  57 + * 列表/详情「收款账户」展示:组合支付时根据 skmx 展开为多段「账户 ¥金额」。
  58 + * skmx 项可含 skzh(账户字典 id)与 skfs(方式名称,兼容旧数据)。
  59 + *
  60 + * @param {Object} row - { skzh, skmx }
  61 + * @param {Array} skzhOptions - 与 dynamicText 一致的字典选项
  62 + * @returns {string}
  63 + */
  64 +export function formatWtSkzhDisplay(row, skzhOptions) {
  65 + if (!row || row.skzh === null || row.skzh === undefined || row.skzh === '') return '无'
  66 + const options = skzhOptions || []
  67 + if (row.skzh === '组合支付' && (row.skmx || row.fkmx)) {
  68 + try {
  69 + const { list: skList } = row.skmx ? parseWtMxJsonArray(row.skmx) : { list: [] }
  70 + const skParts = Array.isArray(skList)
  71 + ? skList.map(item => {
  72 + const je = parseFloat(item.skje || item.Skje || 0)
  73 + const jeStr = isNaN(je) ? '' : `¥${je.toFixed(2)}`
  74 + let name = ''
  75 + if (item.skzh != null && item.skzh !== '') {
  76 + name =
  77 + resolveSkzhDictionaryLabel(item.skzh, options) ||
  78 + (item.skfs || item.Skfs || '').trim() ||
  79 + '无'
  80 + } else {
  81 + name = (item.skfs || item.Skfs || '').trim() || '无'
  82 + }
  83 + const qtbz = (item.qtbz || item.Qtbz || '').trim()
  84 + const extra = qtbz ? `(${qtbz})` : ''
  85 + return jeStr ? `${name}${extra} ${jeStr}` : `${name}${extra}`
  86 + })
  87 + : []
  88 + let fkParts = []
  89 + if (row.fkmx) {
  90 + const { list: fk } = parseWtMxJsonArray(row.fkmx)
  91 + if (Array.isArray(fk)) {
  92 + fkParts = fk.map(item => {
  93 + const lx = (item.lx || item.Lx || '无').trim()
  94 + const je = parseFloat(item.je || item.Je || 0)
  95 + const jeStr = isNaN(je) ? '' : `¥${je.toFixed(2)}`
  96 + return jeStr ? `${lx} ${jeStr}` : lx
  97 + })
  98 + }
  99 + }
  100 + const seg = []
  101 + if (skParts.length) seg.push(`收款:${skParts.join(';')}`)
  102 + if (fkParts.length) seg.push(`付款:${fkParts.join(';')}`)
  103 + return seg.join('|') || '组合支付'
  104 + } catch (e) {
  105 + return '组合支付'
  106 + }
  107 + }
  108 + const byDict = resolveSkzhDictionaryLabel(row.skzh, options)
  109 + if (byDict) return byDict
  110 + const single = dynamicText(row.skzh, options)
  111 + if (single && String(single) !== String(row.skzh)) return single
  112 + return row.skzh ? String(row.skzh) : '无'
  113 +}
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtBjdbd/index.vue
... ... @@ -195,6 +195,11 @@
195 195 </span>
196 196 </template>
197 197 </el-table-column>
  198 + <el-table-column label="摘要" align="left" min-width="200" show-overflow-tooltip class-name="cell-nowrap">
  199 + <template slot-scope="scope">
  200 + <ncc-table-summary-cell :row="scope.row" fields="zy,Zy" />
  201 + </template>
  202 + </el-table-column>
198 203 <el-table-column label="操作" fixed="right" width="148">
199 204 <template slot-scope="scope">
200 205 <el-button type="text" @click="addOrUpdateHandle(scope.row.id, true)">查看</el-button>
... ... @@ -267,7 +272,8 @@ export default {
267 272 { prop: 'skje', label: '收款金额' },
268 273 { prop: 'shr', label: '审核人' },
269 274 { prop: 'gzr', label: '过账人' },
270   - { prop: 'djlx', label: '单据类型' }
  275 + { prop: 'djlx', label: '单据类型' },
  276 + { prop: 'zy', label: '摘要' }
271 277 ],
272 278 cjckOptions: [],
273 279 rkckOptions: [],
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtBsd/index.vue
1   -<template>
  1 +<template>
2 2 <div class="NCC-common-layout">
3 3 <div class="NCC-common-layout-center">
4 4 <el-row class="NCC-common-search-box" :gutter="16">
... ... @@ -123,6 +123,11 @@
123 123 <el-table-column prop="bz" label="备注" align="left" />
124 124 <el-table-column prop="djlx" label="单据类型" align="left" />
125 125 <el-table-column prop="djzt" label="单据状态" align="left" />
  126 + <el-table-column label="摘要" align="left" min-width="200" show-overflow-tooltip class-name="cell-nowrap">
  127 + <template slot-scope="scope">
  128 + <ncc-table-summary-cell :row="scope.row" fields="zy,Zy" />
  129 + </template>
  130 + </el-table-column>
126 131 <el-table-column label="操作" fixed="right" width="100">
127 132 <template slot-scope="scope">
128 133 <el-button type="text" @click="addOrUpdateHandle(scope.row.id)" >编辑</el-button>
... ... @@ -187,6 +192,7 @@
187 192 { prop: 'gzr', label: '过账人' },
188 193 { prop: 'bz', label: '备注' },
189 194 { prop: 'djlx', label: '单据类型' },
  195 + { prop: 'zy', label: '摘要' },
190 196 ],
191 197 cjckOptions : [],
192 198 rkckOptions : [],
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtByd/index.vue
1   -<template>
  1 +<template>
2 2 <div class="NCC-common-layout">
3 3 <div class="NCC-common-layout-center">
4 4 <el-row class="NCC-common-search-box" :gutter="16">
... ... @@ -123,6 +123,11 @@
123 123 <el-table-column prop="bz" label="备注" align="left" />
124 124 <el-table-column prop="djlx" label="单据类型" align="left" />
125 125 <el-table-column prop="djzt" label="单据状态" align="left" />
  126 + <el-table-column label="摘要" align="left" min-width="200" show-overflow-tooltip class-name="cell-nowrap">
  127 + <template slot-scope="scope">
  128 + <ncc-table-summary-cell :row="scope.row" fields="zy,Zy" />
  129 + </template>
  130 + </el-table-column>
126 131 <el-table-column label="操作" fixed="right" width="100">
127 132 <template slot-scope="scope">
128 133 <el-button type="text" @click="addOrUpdateHandle(scope.row.id)" >编辑</el-button>
... ... @@ -187,6 +192,7 @@
187 192 { prop: 'gzr', label: '过账人' },
188 193 { prop: 'bz', label: '备注' },
189 194 { prop: 'djlx', label: '单据类型' },
  195 + { prop: 'zy', label: '摘要' },
190 196 ],
191 197 cjckOptions : [],
192 198 rkckOptions : [],
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCgrkd/index.vue
... ... @@ -28,15 +28,15 @@
28 28 </el-form-item>
29 29 </el-col>
30 30 <el-col :span="6">
31   - <el-form-item label="收款账户">
32   - <el-select v-model="query.skzh" placeholder="收款账户" clearable >
  31 + <el-form-item label="付款账户">
  32 + <el-select v-model="query.skzh" placeholder="付款账户" clearable >
33 33 <el-option v-for="(item, index) in skzhOptions" :key="index" :label="item.fullName" :value="item.id" />
34 34 </el-select>
35 35 </el-form-item>
36 36 </el-col>
37 37 <el-col :span="6">
38   - <el-form-item label="收款金额">
39   - <el-input v-model="query.skje" placeholder="收款金额" clearable />
  38 + <el-form-item label="付款金额">
  39 + <el-input v-model="query.skje" placeholder="付款金额" clearable />
40 40 </el-form-item>
41 41 </el-col>
42 42 <el-col :span="6">
... ... @@ -96,10 +96,10 @@
96 96 <template slot-scope="scope">{{ scope.row.cjck | dynamicText(cjckOptions) }}</template>
97 97 </el-table-column>
98 98 <el-table-column prop="jsr" label="经手人" align="left" />
99   - <el-table-column label="款账户" prop="skzh" align="left">
  99 + <el-table-column label="款账户" prop="skzh" align="left">
100 100 <template slot-scope="scope">{{ scope.row.skzh | dynamicText(skzhOptions) }}</template>
101 101 </el-table-column>
102   - <el-table-column prop="skje" label="款金额" align="left" />
  102 + <el-table-column prop="skje" label="款金额" align="left" />
103 103 <el-table-column prop="zdr" label="制单人" align="left" />
104 104 <el-table-column prop="shr" label="审核人" align="left">
105 105 <template slot-scope="scope">{{ getShrDisplay(scope.row) }}</template>
... ... @@ -118,6 +118,11 @@
118 118 <el-tag v-else type="warning">{{ scope.row.djzt || '待审核' }}</el-tag>
119 119 </template>
120 120 </el-table-column>
  121 + <el-table-column label="摘要" align="left" min-width="200" show-overflow-tooltip class-name="cell-nowrap">
  122 + <template slot-scope="scope">
  123 + <ncc-table-summary-cell :row="scope.row" fields="zy,Zy" />
  124 + </template>
  125 + </el-table-column>
121 126 <el-table-column label="操作" fixed="right" width="310">
122 127 <template slot-scope="scope">
123 128 <el-button type="text" @click="openDetail(scope.row.id)">查看</el-button>
... ... @@ -181,13 +186,14 @@
181 186 { prop: 'djrq', label: '单据日期' },
182 187 { prop: 'cjck', label: '入库仓库' },
183 188 { prop: 'jsr', label: '经手人' },
184   - { prop: 'skzh', label: '收款账户' },
185   - { prop: 'skje', label: '收款金额' },
  189 + { prop: 'skzh', label: '付款账户' },
  190 + { prop: 'skje', label: '付款金额' },
186 191 { prop: 'zdr', label: '制单人' },
187 192 { prop: 'shr', label: '审核人' },
188 193 { prop: 'gzr', label: '过账人' },
189 194 { prop: 'bz', label: '备注' },
190 195 { prop: 'djlx', label: '单据类型' },
  196 + { prop: 'zy', label: '摘要' },
191 197 ],
192 198 cjckOptions : [],
193 199 rkckOptions : [],
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCgthd/index.vue
... ... @@ -111,6 +111,11 @@
111 111 <el-table-column prop="gzr" label="过账人" align="left" />
112 112 <el-table-column prop="bz" label="备注" align="left" />
113 113 <el-table-column prop="djlx" label="单据类型" align="left" />
  114 + <el-table-column label="摘要" align="left" min-width="200" show-overflow-tooltip class-name="cell-nowrap">
  115 + <template slot-scope="scope">
  116 + <ncc-table-summary-cell :row="scope.row" fields="zy,Zy" />
  117 + </template>
  118 + </el-table-column>
114 119 <el-table-column label="操作" fixed="right" width="140">
115 120 <template slot-scope="scope">
116 121 <el-button type="text" @click="openDetail(scope.row.id)" >查看</el-button>
... ... @@ -178,6 +183,7 @@
178 183 { prop: 'gzr', label: '过账人' },
179 184 { prop: 'bz', label: '备注' },
180 185 { prop: 'djlx', label: '单据类型' },
  186 + { prop: 'zy', label: '摘要' },
181 187 ],
182 188 cjckOptions : [],
183 189 rkckOptions : [],
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj/Form.vue
1   -<template>
  1 +<template>
2 2 <el-dialog :title="!dataForm.id ? '新建' : isDetail ? '详情':'编辑'" :close-on-click-modal="false" :visible.sync="visible" class="NCC-dialog NCC-dialog_center" lock-scroll width="90%">
3 3 <el-row :gutter="15" class="" >
4 4 <el-form ref="elForm" :model="dataForm" size="small" label-width="100px" label-position="right" :disabled="!!isDetail" :rules="rules">
... ... @@ -33,6 +33,11 @@
33 33 </el-input>
34 34 </el-form-item>
35 35 </el-col>
  36 + <el-col :span="24" v-if="dataForm.id">
  37 + <el-form-item label="业务摘要">
  38 + <ncc-bill-summary :value="dataForm.billZy" mode="block" />
  39 + </el-form-item>
  40 + </el-col>
36 41 <el-col :span="24">
37 42 <el-form-item label-width="0">
38 43 <el-table :data="dataForm.wtCwdjmxList" size='mini'>
... ... @@ -131,6 +136,7 @@
131 136 wldw:undefined,
132 137 jsr:undefined,
133 138 zy:undefined,
  139 + billZy:undefined,
134 140 wtCwdjmxList:[],
135 141 fkzh:undefined,
136 142 skzh:undefined,
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj/index.vue
1   -<template>
  1 +<template>
2 2 <div class="NCC-common-layout">
3 3 <div class="NCC-common-layout-center">
4 4 <el-row class="NCC-common-search-box" :gutter="16">
... ... @@ -64,7 +64,11 @@
64 64 <template slot-scope="scope">{{ scope.row.wldw | dynamicText(wldwOptions) }}</template>
65 65 </el-table-column>
66 66 <el-table-column prop="jsr" label="经手人" align="left" />
67   - <el-table-column prop="zy" label="摘要" align="left" />
  67 + <el-table-column label="摘要" align="left" min-width="200">
  68 + <template slot-scope="scope">
  69 + <ncc-table-summary-cell :row="scope.row" fields="billZy,BillZy,zy,Zy" />
  70 + </template>
  71 + </el-table-column>
68 72 <el-table-column label="操作" fixed="right" width="100">
69 73 <template slot-scope="scope">
70 74 <el-button type="text" @click="addOrUpdateHandle(scope.row.id)" >编辑</el-button>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_dtfyfs/Form.vue
1   -<template>
  1 +<template>
2 2 <el-dialog :title="!dataForm.id ? '新建' : isDetail ? '详情':'编辑'" :close-on-click-modal="false" :visible.sync="visible" class="NCC-dialog NCC-dialog_center" lock-scroll width="90%">
3 3 <el-row :gutter="15" class="" >
4 4 <el-form ref="elForm" :model="dataForm" size="small" label-width="100px" label-position="right" :disabled="!!isDetail" :rules="rules">
... ... @@ -39,6 +39,11 @@
39 39 </el-input>
40 40 </el-form-item>
41 41 </el-col>
  42 + <el-col :span="24" v-if="dataForm.id">
  43 + <el-form-item label="业务摘要">
  44 + <ncc-bill-summary :value="dataForm.billZy" mode="block" />
  45 + </el-form-item>
  46 + </el-col>
42 47 <el-col :span="24">
43 48 <el-form-item label-width="0">
44 49 <el-table :data="dataForm.wtCwdjmxList" size='mini'>
... ... @@ -138,6 +143,7 @@
138 143 jsr:undefined,
139 144 txqs:undefined,
140 145 zy:undefined,
  146 + billZy:undefined,
141 147 wtCwdjmxList:[],
142 148 fkzh:undefined,
143 149 skzh:undefined,
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_dtfyfs/index.vue
1   -<template>
  1 +<template>
2 2 <div class="NCC-common-layout">
3 3 <div class="NCC-common-layout-center">
4 4 <el-row class="NCC-common-search-box" :gutter="16">
... ... @@ -69,7 +69,11 @@
69 69 </el-table-column>
70 70 <el-table-column prop="jsr" label="经手人" align="left" />
71 71 <el-table-column prop="txqs" label="摊销期数" align="left" />
72   - <el-table-column prop="zy" label="摘要" align="left" />
  72 + <el-table-column label="摘要" align="left" min-width="200" class-name="cell-nowrap">
  73 + <template slot-scope="scope">
  74 + <ncc-table-summary-cell :row="scope.row" fields="billZy,BillZy,zy,Zy" />
  75 + </template>
  76 + </el-table-column>
73 77 <el-table-column label="操作" fixed="right" width="100">
74 78 <template slot-scope="scope">
75 79 <el-button type="text" @click="addOrUpdateHandle(scope.row.id)" >编辑</el-button>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_dtfytx/Form.vue
1   -<template>
  1 +<template>
2 2 <el-dialog :title="!dataForm.id ? '新建' : isDetail ? '详情':'编辑'" :close-on-click-modal="false" :visible.sync="visible" class="NCC-dialog NCC-dialog_center" lock-scroll width="90%">
3 3 <el-row :gutter="15" class="" >
4 4 <el-form ref="elForm" :model="dataForm" size="small" label-width="100px" label-position="right" :disabled="!!isDetail" :rules="rules">
... ... @@ -33,6 +33,11 @@
33 33 </el-input>
34 34 </el-form-item>
35 35 </el-col>
  36 + <el-col :span="24" v-if="dataForm.id">
  37 + <el-form-item label="业务摘要">
  38 + <ncc-bill-summary :value="dataForm.billZy" mode="block" />
  39 + </el-form-item>
  40 + </el-col>
36 41 <el-col :span="24">
37 42 <el-form-item label-width="0">
38 43 <el-table :data="dataForm.wtCwdjmxList" size='mini'>
... ... @@ -131,6 +136,7 @@
131 136 wldw:undefined,
132 137 jsr:undefined,
133 138 zy:undefined,
  139 + billZy:undefined,
134 140 wtCwdjmxList:[],
135 141 fkzh:undefined,
136 142 skzh:undefined,
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_dtfytx/index.vue
1   -<template>
  1 +<template>
2 2 <div class="NCC-common-layout">
3 3 <div class="NCC-common-layout-center">
4 4 <el-row class="NCC-common-search-box" :gutter="16">
... ... @@ -68,7 +68,11 @@
68 68 <template slot-scope="scope">{{ scope.row.wldw | dynamicText(wldwOptions) }}</template>
69 69 </el-table-column>
70 70 <el-table-column prop="jsr" label="经手人" align="left" />
71   - <el-table-column prop="zy" label="摘要" align="left" />
  71 + <el-table-column label="摘要" align="left" min-width="200" class-name="cell-nowrap">
  72 + <template slot-scope="scope">
  73 + <ncc-table-summary-cell :row="scope.row" fields="billZy,BillZy,zy,Zy" />
  74 + </template>
  75 + </el-table-column>
72 76 <el-table-column label="操作" fixed="right" width="100">
73 77 <template slot-scope="scope">
74 78 <el-button type="text" @click="addOrUpdateHandle(scope.row.id)" >编辑</el-button>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_fkd/Form.vue
... ... @@ -33,6 +33,11 @@
33 33 </el-input>
34 34 </el-form-item>
35 35 </el-col>
  36 + <el-col :span="24" v-if="dataForm.id">
  37 + <el-form-item label="业务摘要">
  38 + <ncc-bill-summary :value="dataForm.billZy" mode="block" />
  39 + </el-form-item>
  40 + </el-col>
36 41 <el-col :span="24">
37 42 <el-form-item label-width="0">
38 43 <el-table :data="dataForm.wtCwdjmxList" size='mini'>
... ... @@ -138,6 +143,7 @@
138 143 wldw:undefined,
139 144 jsr:undefined,
140 145 zy:undefined,
  146 + billZy:undefined,
141 147 wtCwdjmxList:[],
142 148 fkzh:undefined,
143 149 skzh:undefined,
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_fkd/detail-view.vue
... ... @@ -61,7 +61,7 @@
61 61 </span>
62 62 </el-descriptions-item>
63 63 <el-descriptions-item label="摘要" :span="2">
64   - <span class="detail-bz">{{ cellText(detail.zy) }}</span>
  64 + <ncc-bill-summary :value="detail.zy" mode="block" :show-icon="false" />
65 65 </el-descriptions-item>
66 66 </el-descriptions>
67 67  
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_fkd/index.vue
... ... @@ -68,7 +68,11 @@
68 68 <template slot-scope="scope">{{ scope.row.wldw | dynamicText(wldwOptions) }}</template>
69 69 </el-table-column>
70 70 <el-table-column prop="jsr" label="经手人" align="left" />
71   - <el-table-column prop="zy" label="摘要" align="left" />
  71 + <el-table-column label="摘要" align="left" min-width="200">
  72 + <template slot-scope="scope">
  73 + <ncc-table-summary-cell :row="scope.row" fields="billZy,BillZy,zy,Zy" />
  74 + </template>
  75 + </el-table-column>
72 76 <el-table-column label="操作" fixed="right" width="140">
73 77 <template slot-scope="scope">
74 78 <el-button type="text" @click="openDetail(scope.row.id)" >查看</el-button>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_fyd/Form.vue
... ... @@ -33,6 +33,11 @@
33 33 </el-input>
34 34 </el-form-item>
35 35 </el-col>
  36 + <el-col :span="24" v-if="dataForm.id">
  37 + <el-form-item label="业务摘要">
  38 + <ncc-bill-summary :value="dataForm.billZy" mode="block" />
  39 + </el-form-item>
  40 + </el-col>
36 41 <el-col :span="24">
37 42 <el-form-item label-width="0">
38 43 <el-table :data="dataForm.wtCwdjmxList" size='mini'>
... ... @@ -144,6 +149,7 @@
144 149 wldw:undefined,
145 150 jsr:undefined,
146 151 zy:undefined,
  152 + billZy:undefined,
147 153 wtCwdjmxList:[],
148 154 fkzh:undefined,
149 155 skzh:undefined,
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_fyd/index.vue
... ... @@ -86,9 +86,9 @@
86 86 {{ cellText(scope.row.jsr) }}
87 87 </template>
88 88 </el-table-column>
89   - <el-table-column label="摘要" align="left">
  89 + <el-table-column label="摘要" align="left" min-width="200">
90 90 <template slot-scope="scope">
91   - {{ cellText(scope.row.zy || scope.row.bz) }}
  91 + <ncc-table-summary-cell :row="scope.row" fields="billZy,BillZy,zy,Zy,bz,Bz" />
92 92 </template>
93 93 </el-table-column>
94 94 <el-table-column label="操作" fixed="right" width="100">
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_gdzcbm/Form.vue
1   -<template>
  1 +<template>
2 2 <el-dialog :title="!dataForm.id ? '新建' : isDetail ? '详情':'编辑'" :close-on-click-modal="false" :visible.sync="visible" class="NCC-dialog NCC-dialog_center" lock-scroll width="90%">
3 3 <el-row :gutter="15" class="" >
4 4 <el-form ref="elForm" :model="dataForm" size="small" label-width="100px" label-position="right" :disabled="!!isDetail" :rules="rules">
... ... @@ -33,6 +33,11 @@
33 33 </el-input>
34 34 </el-form-item>
35 35 </el-col>
  36 + <el-col :span="24" v-if="dataForm.id">
  37 + <el-form-item label="业务摘要">
  38 + <ncc-bill-summary :value="dataForm.billZy" mode="block" />
  39 + </el-form-item>
  40 + </el-col>
36 41 <el-col :span="24">
37 42 <el-form-item label-width="0">
38 43 <el-table :data="dataForm.wtCwdjmxList" size='mini'>
... ... @@ -131,6 +136,7 @@
131 136 wldw:undefined,
132 137 jsr:undefined,
133 138 zy:undefined,
  139 + billZy:undefined,
134 140 wtCwdjmxList:[],
135 141 fkzh:undefined,
136 142 skzh:undefined,
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_gdzcbm/index.vue
1   -<template>
  1 +<template>
2 2 <div class="NCC-common-layout">
3 3 <div class="NCC-common-layout-center">
4 4 <el-row class="NCC-common-search-box" :gutter="16">
... ... @@ -68,7 +68,11 @@
68 68 <template slot-scope="scope">{{ scope.row.wldw | dynamicText(wldwOptions) }}</template>
69 69 </el-table-column>
70 70 <el-table-column prop="jsr" label="经手人" align="left" />
71   - <el-table-column prop="zy" label="摘要" align="left" />
  71 + <el-table-column label="摘要" align="left" min-width="200" class-name="cell-nowrap">
  72 + <template slot-scope="scope">
  73 + <ncc-table-summary-cell :row="scope.row" fields="billZy,BillZy,zy,Zy" />
  74 + </template>
  75 + </el-table-column>
72 76 <el-table-column label="操作" fixed="right" width="100">
73 77 <template slot-scope="scope">
74 78 <el-button type="text" @click="addOrUpdateHandle(scope.row.id)" >编辑</el-button>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_gdzcgm/Form.vue
1   -<template>
  1 +<template>
2 2 <el-dialog :title="!dataForm.id ? '新建' : isDetail ? '详情':'编辑'" :close-on-click-modal="false" :visible.sync="visible" class="NCC-dialog NCC-dialog_center" lock-scroll width="90%">
3 3 <el-row :gutter="15" class="" >
4 4 <el-form ref="elForm" :model="dataForm" size="small" label-width="100px" label-position="right" :disabled="!!isDetail" :rules="rules">
... ... @@ -39,6 +39,11 @@
39 39 </el-input>
40 40 </el-form-item>
41 41 </el-col>
  42 + <el-col :span="24" v-if="dataForm.id">
  43 + <el-form-item label="业务摘要">
  44 + <ncc-bill-summary :value="dataForm.billZy" mode="block" />
  45 + </el-form-item>
  46 + </el-col>
42 47 <el-col :span="24">
43 48 <el-form-item label-width="0">
44 49 <el-table :data="dataForm.wtCwdjmxList" size='mini'>
... ... @@ -138,6 +143,7 @@
138 143 jsr:undefined,
139 144 zjqs:undefined,
140 145 zy:undefined,
  146 + billZy:undefined,
141 147 wtCwdjmxList:[],
142 148 fkzh:undefined,
143 149 skzh:undefined,
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_gdzcgm/index.vue
1   -<template>
  1 +<template>
2 2 <div class="NCC-common-layout">
3 3 <div class="NCC-common-layout-center">
4 4 <el-row class="NCC-common-search-box" :gutter="16">
... ... @@ -69,7 +69,11 @@
69 69 </el-table-column>
70 70 <el-table-column prop="jsr" label="经手人" align="left" />
71 71 <el-table-column prop="zjqs" label="折旧期数" align="left" />
72   - <el-table-column prop="zy" label="摘要" align="left" />
  72 + <el-table-column label="摘要" align="left" min-width="200" class-name="cell-nowrap">
  73 + <template slot-scope="scope">
  74 + <ncc-table-summary-cell :row="scope.row" fields="billZy,BillZy,zy,Zy" />
  75 + </template>
  76 + </el-table-column>
73 77 <el-table-column label="操作" fixed="right" width="100">
74 78 <template slot-scope="scope">
75 79 <el-button type="text" @click="addOrUpdateHandle(scope.row.id)" >编辑</el-button>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_gdzczj/Form.vue
1   -<template>
  1 +<template>
2 2 <el-dialog :title="!dataForm.id ? '新建' : isDetail ? '详情':'编辑'" :close-on-click-modal="false" :visible.sync="visible" class="NCC-dialog NCC-dialog_center" lock-scroll width="90%">
3 3 <el-row :gutter="15" class="" >
4 4 <el-form ref="elForm" :model="dataForm" size="small" label-width="100px" label-position="right" :disabled="!!isDetail" :rules="rules">
... ... @@ -33,6 +33,11 @@
33 33 </el-input>
34 34 </el-form-item>
35 35 </el-col>
  36 + <el-col :span="24" v-if="dataForm.id">
  37 + <el-form-item label="业务摘要">
  38 + <ncc-bill-summary :value="dataForm.billZy" mode="block" />
  39 + </el-form-item>
  40 + </el-col>
36 41 <el-col :span="24">
37 42 <el-form-item label-width="0">
38 43 <el-table :data="dataForm.wtCwdjmxList" size='mini'>
... ... @@ -131,6 +136,7 @@
131 136 wldw:undefined,
132 137 jsr:undefined,
133 138 zy:undefined,
  139 + billZy:undefined,
134 140 wtCwdjmxList:[],
135 141 fkzh:undefined,
136 142 skzh:undefined,
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_gdzczj/index.vue
1   -<template>
  1 +<template>
2 2 <div class="NCC-common-layout">
3 3 <div class="NCC-common-layout-center">
4 4 <el-row class="NCC-common-search-box" :gutter="16">
... ... @@ -68,7 +68,11 @@
68 68 <template slot-scope="scope">{{ scope.row.wldw | dynamicText(wldwOptions) }}</template>
69 69 </el-table-column>
70 70 <el-table-column prop="jsr" label="经手人" align="left" />
71   - <el-table-column prop="zy" label="摘要" align="left" />
  71 + <el-table-column label="摘要" align="left" min-width="200" class-name="cell-nowrap">
  72 + <template slot-scope="scope">
  73 + <ncc-table-summary-cell :row="scope.row" fields="billZy,BillZy,zy,Zy" />
  74 + </template>
  75 + </el-table-column>
72 76 <el-table-column label="操作" fixed="right" width="100">
73 77 <template slot-scope="scope">
74 78 <el-button type="text" @click="addOrUpdateHandle(scope.row.id)" >编辑</el-button>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_skd/Form.vue
... ... @@ -33,6 +33,11 @@
33 33 </el-input>
34 34 </el-form-item>
35 35 </el-col>
  36 + <el-col :span="24" v-if="dataForm.id">
  37 + <el-form-item label="业务摘要">
  38 + <ncc-bill-summary :value="dataForm.billZy" mode="block" />
  39 + </el-form-item>
  40 + </el-col>
36 41 <el-col :span="24">
37 42 <el-form-item label-width="0">
38 43 <el-table :data="dataForm.wtCwdjmxList" size='mini'>
... ... @@ -138,6 +143,7 @@
138 143 wldw:undefined,
139 144 jsr:undefined,
140 145 zy:undefined,
  146 + billZy:undefined,
141 147 wtCwdjmxList:[],
142 148 fkzh:undefined,
143 149 skzh:undefined,
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_skd/detail-view.vue
... ... @@ -61,7 +61,7 @@
61 61 </span>
62 62 </el-descriptions-item>
63 63 <el-descriptions-item label="摘要" :span="2">
64   - <span class="detail-bz">{{ cellText(detail.zy) }}</span>
  64 + <ncc-bill-summary :value="detail.zy" mode="block" :show-icon="false" />
65 65 </el-descriptions-item>
66 66 </el-descriptions>
67 67  
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCwdj_skd/index.vue
... ... @@ -68,7 +68,11 @@
68 68 <template slot-scope="scope">{{ scope.row.wldw | dynamicText(wldwOptions) }}</template>
69 69 </el-table-column>
70 70 <el-table-column prop="jsr" label="经手人" align="left" />
71   - <el-table-column prop="zy" label="摘要" align="left" />
  71 + <el-table-column label="摘要" align="left" min-width="200">
  72 + <template slot-scope="scope">
  73 + <ncc-table-summary-cell :row="scope.row" fields="billZy,BillZy,zy,Zy" />
  74 + </template>
  75 + </el-table-column>
72 76 <el-table-column label="操作" fixed="right" width="140">
73 77 <template slot-scope="scope">
74 78 <el-button type="text" @click="openDetail(scope.row.id)" >查看</el-button>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCzd/detail-view.vue
... ... @@ -15,7 +15,9 @@
15 15 <el-descriptions-item label="经手人">{{ text(detail.jsr) }}</el-descriptions-item>
16 16 <el-descriptions-item label="出货仓库">{{ warehouseName(detail.chck, chckOptions) }}</el-descriptions-item>
17 17 <el-descriptions-item label="入货仓库">{{ warehouseName(detail.rhck, rhckOptions) }}</el-descriptions-item>
18   - <el-descriptions-item label="摘要">{{ text(detail.zy) }}</el-descriptions-item>
  18 + <el-descriptions-item label="摘要" :span="3">
  19 + <ncc-bill-summary :value="detail.zy" mode="block" :show-icon="false" />
  20 + </el-descriptions-item>
19 21 </el-descriptions>
20 22  
21 23 <div class="detail-title">出货明细</div>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtCzd/index.vue
... ... @@ -73,7 +73,11 @@
73 73 <el-table-column prop="zdr" label="制单人" align="left" />
74 74 <el-table-column prop="shr" label="审核人" align="left" />
75 75 <el-table-column prop="gzr" label="过账人" align="left" />
76   - <el-table-column prop="zy" label="摘要" align="left" />
  76 + <el-table-column label="摘要" align="left" min-width="200">
  77 + <template slot-scope="scope">
  78 + <ncc-table-summary-cell :row="scope.row" fields="zy,Zy" />
  79 + </template>
  80 + </el-table-column>
77 81 <el-table-column prop="bz" label="备注" align="left" />
78 82 <el-table-column label="操作" fixed="right" width="150">
79 83 <template slot-scope="scope">
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtDjzy/index.vue 0 → 100644
  1 +<template>
  2 + <div class="NCC-common-layout">
  3 + <div class="NCC-common-layout-center">
  4 + <el-row class="NCC-common-search-box" :gutter="16">
  5 + <el-form @submit.native.prevent>
  6 + <el-col :span="6">
  7 + <el-form-item label="单据编号">
  8 + <el-input v-model="query.djbh" placeholder="模糊" clearable />
  9 + </el-form-item>
  10 + </el-col>
  11 + <el-col :span="6">
  12 + <el-form-item label="来源">
  13 + <el-select v-model="query.ly" placeholder="全部" clearable style="width:100%">
  14 + <el-option label="销售/采购/委托/调拨入库等 (xsckd)" value="xsckd" />
  15 + <el-option label="财务单据 (cwdj)" value="cwdj" />
  16 + <el-option label="收付款 (sfk)" value="sfk" />
  17 + <el-option label="应收款增减 (yskzjjs)" value="yskzjjs" />
  18 + </el-select>
  19 + </el-form-item>
  20 + </el-col>
  21 + <el-col :span="6">
  22 + <el-form-item label="单据类型">
  23 + <el-input v-model="query.djlx" placeholder="模糊" clearable />
  24 + </el-form-item>
  25 + </el-col>
  26 + <el-col :span="6">
  27 + <el-form-item label="摘要关键字">
  28 + <el-input v-model="query.keyword" placeholder="匹配摘要全文" clearable />
  29 + </el-form-item>
  30 + </el-col>
  31 + <el-col :span="6">
  32 + <el-form-item label="单据日期">
  33 + <el-date-picker
  34 + v-model="query.djrq"
  35 + type="daterange"
  36 + value-format="timestamp"
  37 + format="yyyy-MM-dd"
  38 + start-placeholder="开始"
  39 + end-placeholder="结束"
  40 + style="width:100%"
  41 + />
  42 + </el-form-item>
  43 + </el-col>
  44 + <el-col :span="6">
  45 + <el-form-item>
  46 + <el-button type="primary" icon="el-icon-search" @click="search()">查询</el-button>
  47 + <el-button icon="el-icon-refresh-right" @click="reset()">重置</el-button>
  48 + </el-form-item>
  49 + </el-col>
  50 + </el-form>
  51 + </el-row>
  52 + <div class="NCC-common-layout-main NCC-flex-main">
  53 + <div class="NCC-common-head">
  54 + <div class="djzy-sync-btns">
  55 + <el-button type="primary" plain icon="el-icon-refresh" :loading="syncLoading === 'xsckd'" @click="syncModule('xsckd')">
  56 + 同步销售出库
  57 + </el-button>
  58 + <el-button type="primary" plain icon="el-icon-refresh" :loading="syncLoading === 'cwdj'" @click="syncModule('cwdj')">
  59 + 同步财务单据
  60 + </el-button>
  61 + <el-button type="primary" plain icon="el-icon-refresh" :loading="syncLoading === 'sfk'" @click="syncModule('sfk')">
  62 + 同步收付款
  63 + </el-button>
  64 + <el-button type="primary" plain icon="el-icon-refresh" :loading="syncLoading === 'yskzjjs'" @click="syncModule('yskzjjs')">
  65 + 同步应收款增减
  66 + </el-button>
  67 + </div>
  68 + <div class="NCC-common-head-right">
  69 + <el-tooltip effect="dark" content="刷新" placement="top">
  70 + <el-link icon="icon-ym icon-ym-Refresh NCC-common-head-icon" :underline="false" @click="reset()" />
  71 + </el-tooltip>
  72 + <screenfull isContainer />
  73 + </div>
  74 + </div>
  75 + <!-- 固定计算高度:避免 el-table height=100% 在 flex 链上算出 0 导致「有数据但不显示行」 -->
  76 + <NCC-table
  77 + v-loading="listLoading"
  78 + :data="list"
  79 + row-key="id"
  80 + height="calc(100vh - 280px)"
  81 + >
  82 + <el-table-column label="单据编号" align="left" min-width="140" show-overflow-tooltip class-name="cell-nowrap">
  83 + <template slot-scope="scope">
  84 + <i class="el-icon-document" style="color:#409EFF;margin-right:6px" />
  85 + <span>{{ scope.row.djbh || '无' }}</span>
  86 + </template>
  87 + </el-table-column>
  88 + <el-table-column label="来源" align="left" width="100" show-overflow-tooltip class-name="cell-nowrap">
  89 + <template slot-scope="scope">
  90 + <i class="el-icon-folder-opened" style="color:#67C23A;margin-right:6px" />
  91 + <span>{{ scope.row.ly || '无' }}</span>
  92 + </template>
  93 + </el-table-column>
  94 + <el-table-column label="单据类型" align="left" min-width="120" show-overflow-tooltip class-name="cell-nowrap">
  95 + <template slot-scope="scope">
  96 + <i class="el-icon-tickets" style="color:#E6A23C;margin-right:6px" />
  97 + <span>{{ scope.row.djlx || '无' }}</span>
  98 + </template>
  99 + </el-table-column>
  100 + <el-table-column label="单据日期" align="left" width="120" show-overflow-tooltip class-name="cell-nowrap">
  101 + <template slot-scope="scope">
  102 + <i class="el-icon-date" style="color:#909399;margin-right:6px" />
  103 + <span>{{ formatDate(scope.row.djrq) }}</span>
  104 + </template>
  105 + </el-table-column>
  106 + <el-table-column label="摘要" align="left" min-width="280" show-overflow-tooltip>
  107 + <template slot-scope="scope">
  108 + <!-- 不用 ncc-bill-summary+tooltip:在 el-table .cell 内易出现宽度为 0,文字不显示 -->
  109 + <div class="djzy-summary-cell" :title="summaryText(scope.row)">
  110 + <i class="el-icon-reading djzy-summary-ico" aria-hidden="true" />
  111 + <span class="djzy-summary-txt">{{ summaryText(scope.row) }}</span>
  112 + </div>
  113 + </template>
  114 + </el-table-column>
  115 + </NCC-table>
  116 + <pagination :total="total" :page.sync="listQuery.currentPage" :limit.sync="listQuery.pageSize" @pagination="initData" />
  117 + </div>
  118 + </div>
  119 + </div>
  120 +</template>
  121 +
  122 +<script>
  123 +import request from '@/utils/request'
  124 +
  125 +export default {
  126 + name: 'WtDjzy',
  127 + data() {
  128 + return {
  129 + query: {
  130 + djbh: undefined,
  131 + ly: undefined,
  132 + djlx: undefined,
  133 + keyword: undefined,
  134 + djrq: undefined
  135 + },
  136 + list: [],
  137 + listLoading: true,
  138 + syncLoading: null,
  139 + total: 0,
  140 + listQuery: {
  141 + currentPage: 1,
  142 + pageSize: 20,
  143 + sort: 'desc',
  144 + sidx: 'djrq'
  145 + }
  146 + }
  147 + },
  148 + created() {
  149 + this.initData()
  150 + },
  151 + methods: {
  152 + formatDate(v) {
  153 + if (!v) return '无'
  154 + const d = new Date(v)
  155 + if (isNaN(d.getTime())) return '无'
  156 + return d.toLocaleDateString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit' }).replace(/\//g, '-')
  157 + },
  158 + summaryText(row) {
  159 + if (!row) return '无'
  160 + const raw = row.zynr != null ? row.zynr : row.Zynr
  161 + const t = raw == null ? '' : String(raw).trim()
  162 + return t || '无'
  163 + },
  164 + initData() {
  165 + this.listLoading = true
  166 + const _query = {
  167 + ...this.listQuery,
  168 + ...this.query
  169 + }
  170 + const query = {}
  171 + for (const key in _query) {
  172 + if (Array.isArray(_query[key])) {
  173 + query[key] = _query[key].join()
  174 + } else {
  175 + query[key] = _query[key]
  176 + }
  177 + }
  178 + request({
  179 + url: '/api/Extend/WtDjzy',
  180 + method: 'GET',
  181 + data: query
  182 + })
  183 + .then(res => {
  184 + // 兼容:标准 { code, data: { list, pagination } };防 data 层差异
  185 + const pack = res && res.data !== undefined && res.data !== null ? res.data : res
  186 + const rows = pack && pack.list
  187 + this.list = Array.isArray(rows) ? rows : []
  188 + const pg = pack && pack.pagination
  189 + this.total = pg && typeof pg.total === 'number' ? pg.total : this.list.length
  190 + })
  191 + .catch(() => {
  192 + this.list = []
  193 + this.total = 0
  194 + })
  195 + .finally(() => {
  196 + this.listLoading = false
  197 + })
  198 + },
  199 + search() {
  200 + this.listQuery.currentPage = 1
  201 + this.initData()
  202 + },
  203 + reset() {
  204 + this.query = {
  205 + djbh: undefined,
  206 + ly: undefined,
  207 + djlx: undefined,
  208 + keyword: undefined,
  209 + djrq: undefined
  210 + }
  211 + this.listQuery = {
  212 + currentPage: 1,
  213 + pageSize: 20,
  214 + sort: 'desc',
  215 + sidx: 'djrq'
  216 + }
  217 + this.initData()
  218 + },
  219 + syncModule(key) {
  220 + const cfg = {
  221 + xsckd: {
  222 + url: '/api/Extend/WtDjzy/Actions/SyncFromXsckd',
  223 + name: 'wt_xsckd(含同价/变价调拨入库等)',
  224 + rangeHint: '按「单据日期」筛选 wt_xsckd(含调拨入库类单据)'
  225 + },
  226 + cwdj: {
  227 + url: '/api/Extend/WtDjzy/Actions/SyncFromCwdj',
  228 + name: '财务单据',
  229 + rangeHint: '按「单据日期」筛选 wt_cwdj 的录单日期 ldrq'
  230 + },
  231 + sfk: {
  232 + url: '/api/Extend/WtDjzy/Actions/SyncFromSfk',
  233 + name: '收付款',
  234 + rangeHint: '按「单据日期」筛选 wt_sfk'
  235 + },
  236 + yskzjjs: {
  237 + url: '/api/Extend/WtDjzy/Actions/SyncFromYskzjjs',
  238 + name: '应收款增减',
  239 + rangeHint: '按「单据日期」筛选 wt_yskzjjs'
  240 + }
  241 + }[key]
  242 + if (!cfg) return
  243 + const hasRange = Array.isArray(this.query.djrq) && this.query.djrq.length === 2
  244 + const tip = hasRange
  245 + ? `将${cfg.rangeHint}写入摘要汇总表。是否继续?`
  246 + : `将同步当前租户下全部${cfg.name}主表到摘要汇总表,数据量大时可能稍慢。是否继续?`
  247 + this.$confirm(tip, '同步摘要', { type: 'warning' })
  248 + .then(() => {
  249 + this.syncLoading = key
  250 + const body = {}
  251 + if (hasRange) {
  252 + body.djrqStart = String(this.query.djrq[0])
  253 + body.djrqEnd = String(this.query.djrq[1])
  254 + }
  255 + return request({
  256 + url: cfg.url,
  257 + method: 'POST',
  258 + data: body,
  259 + timeout: 180000
  260 + })
  261 + })
  262 + .then(res => {
  263 + const d = res.data || {}
  264 + const text = d.message || (d.syncedCount != null ? `已同步 ${d.syncedCount} 条` : '') || res.msg || '同步完成'
  265 + this.$message.success(text)
  266 + this.initData()
  267 + })
  268 + .catch(() => {})
  269 + .finally(() => {
  270 + this.syncLoading = null
  271 + })
  272 + }
  273 + }
  274 +}
  275 +</script>
  276 +
  277 +<style scoped lang="scss">
  278 +.djzy-sync-btns {
  279 + display: flex;
  280 + flex-wrap: wrap;
  281 + align-items: center;
  282 + gap: 8px;
  283 +}
  284 +.djzy-summary-cell {
  285 + display: flex;
  286 + align-items: center;
  287 + min-width: 0;
  288 + width: 100%;
  289 +}
  290 +.djzy-summary-ico {
  291 + flex-shrink: 0;
  292 + color: #409eff;
  293 + margin-right: 6px;
  294 + font-size: 14px;
  295 +}
  296 +.djzy-summary-txt {
  297 + flex: 1;
  298 + min-width: 0;
  299 + overflow: hidden;
  300 + text-overflow: ellipsis;
  301 + white-space: nowrap;
  302 + color: #303133;
  303 + font-size: 13px;
  304 + line-height: 1.5;
  305 +}
  306 +</style>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtHzd/index.vue
1   -<template>
  1 +<template>
2 2 <div class="NCC-common-layout">
3 3 <div class="NCC-common-layout-center">
4 4 <el-row class="NCC-common-search-box" :gutter="16">
... ... @@ -123,6 +123,11 @@
123 123 <el-table-column prop="bz" label="备注" align="left" />
124 124 <el-table-column prop="djlx" label="单据类型" align="left" />
125 125 <el-table-column prop="djzt" label="单据状态" align="left" />
  126 + <el-table-column label="摘要" align="left" min-width="200" show-overflow-tooltip class-name="cell-nowrap">
  127 + <template slot-scope="scope">
  128 + <ncc-table-summary-cell :row="scope.row" fields="zy,Zy" />
  129 + </template>
  130 + </el-table-column>
126 131 <el-table-column label="操作" fixed="right" width="100">
127 132 <template slot-scope="scope">
128 133 <el-button type="text" @click="addOrUpdateHandle(scope.row.id)" >编辑</el-button>
... ... @@ -187,6 +192,7 @@
187 192 { prop: 'gzr', label: '过账人' },
188 193 { prop: 'bz', label: '备注' },
189 194 { prop: 'djlx', label: '单据类型' },
  195 + { prop: 'zy', label: '摘要' },
190 196 ],
191 197 cjckOptions : [],
192 198 rkckOptions : [],
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtPdd/index.vue
1   -<template>
  1 +<template>
2 2 <div class="NCC-common-layout">
3 3 <div class="NCC-common-layout-center">
4 4 <el-row class="NCC-common-search-box" :gutter="16">
... ... @@ -123,6 +123,11 @@
123 123 <el-table-column prop="bz" label="备注" align="left" />
124 124 <el-table-column prop="djlx" label="单据类型" align="left" />
125 125 <el-table-column prop="djzt" label="单据状态" align="left" />
  126 + <el-table-column label="摘要" align="left" min-width="200" show-overflow-tooltip class-name="cell-nowrap">
  127 + <template slot-scope="scope">
  128 + <ncc-table-summary-cell :row="scope.row" fields="zy,Zy" />
  129 + </template>
  130 + </el-table-column>
126 131 <el-table-column label="操作" fixed="right" width="100">
127 132 <template slot-scope="scope">
128 133 <el-button type="text" @click="addOrUpdateHandle(scope.row.id)" >编辑</el-button>
... ... @@ -187,6 +192,7 @@
187 192 { prop: 'gzr', label: '过账人' },
188 193 { prop: 'bz', label: '备注' },
189 194 { prop: 'djlx', label: '单据类型' },
  195 + { prop: 'zy', label: '摘要' },
190 196 ],
191 197 cjckOptions : [],
192 198 rkckOptions : [],
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtSfk/Form.vue
... ... @@ -70,6 +70,11 @@
70 70 </el-input>
71 71 </el-form-item>
72 72 </el-col>
  73 + <el-col :span="24" v-if="dataForm.id">
  74 + <el-form-item label="业务摘要">
  75 + <ncc-bill-summary :value="dataForm.billZy" mode="block" />
  76 + </el-form-item>
  77 + </el-col>
73 78 <el-col :span="24" v-if="false" >
74 79 <el-form-item label="单据类型" prop="djlx">
75 80 <el-input v-model="dataForm.djlx" placeholder="请输入" clearable :style='{"width":"100%"}' >
... ... @@ -108,6 +113,7 @@
108 113 shr:undefined,
109 114 gzr:undefined,
110 115 bz:undefined,
  116 + billZy:undefined,
111 117 djlx:"收款单",
112 118 },
113 119 rules: {
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtSfk/index.vue
1   -<template>
  1 +<template>
2 2 <div class="NCC-common-layout">
3 3 <div class="NCC-common-layout-center">
4 4 <el-row class="NCC-common-search-box" :gutter="16">
... ... @@ -105,6 +105,12 @@
105 105 <el-table-column prop="gzr" label="过账人" align="left" />
106 106 <el-table-column prop="bz" label="备注" align="left" />
107 107 <el-table-column prop="djlx" label="单据类型" align="left" />
  108 + <el-table-column label="摘要" align="left" min-width="220" class-name="cell-nowrap">
  109 + <template slot-scope="scope">
  110 + <i class="el-icon-reading" style="color:#409EFF;margin-right:6px" />
  111 + <ncc-table-summary-cell :row="scope.row" fields="billZy,BillZy" />
  112 + </template>
  113 + </el-table-column>
108 114 <el-table-column label="操作" fixed="right" width="100">
109 115 <template slot-scope="scope">
110 116 <el-button type="text" @click="addOrUpdateHandle(scope.row.id)" >编辑</el-button>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtSkfkChannelStat/index.vue 0 → 100644
  1 +<template>
  2 + <div class="NCC-common-layout skfk-channel-stat-page">
  3 + <div class="NCC-common-layout-center">
  4 + <el-row class="NCC-common-search-box" :gutter="16">
  5 + <el-form :model="filters" label-width="90px" size="small" @submit.native.prevent>
  6 + <el-col :span="8">
  7 + <el-form-item label="查询日期">
  8 + <el-date-picker
  9 + v-model="filters.dateRange"
  10 + type="daterange"
  11 + range-separator="至"
  12 + start-placeholder="开始日期"
  13 + end-placeholder="结束日期"
  14 + style="width: 100%"
  15 + value-format="yyyy-MM-dd"
  16 + />
  17 + </el-form-item>
  18 + </el-col>
  19 + <el-col :span="6">
  20 + <el-form-item label="收付方向">
  21 + <el-select v-model="filters.fx" clearable placeholder="全部" style="width: 100%">
  22 + <el-option label="全部" value="" />
  23 + <el-option label="收款" value="sk" />
  24 + <el-option label="付款" value="fk" />
  25 + </el-select>
  26 + </el-form-item>
  27 + </el-col>
  28 + <template v-if="showAll">
  29 + <el-col :span="6">
  30 + <el-form-item label="关键字">
  31 + <el-input v-model="filters.qd" clearable placeholder="资金账户或方式" />
  32 + </el-form-item>
  33 + </el-col>
  34 + <el-col :span="12">
  35 + <el-form-item label="单据类型">
  36 + <el-input v-model="filters.djlx" clearable placeholder="模糊匹配单据类型" />
  37 + </el-form-item>
  38 + </el-col>
  39 + </template>
  40 + <el-col :span="showAll ? 24 : 10">
  41 + <el-form-item label-width="0">
  42 + <span class="action-row">
  43 + <el-button type="primary" icon="el-icon-search" @click="handleSearch">查询</el-button>
  44 + <el-button icon="el-icon-refresh-right" @click="handleReset">重置</el-button>
  45 + <el-button type="text" icon="el-icon-arrow-down" v-if="!showAll" @click="showAll = true">展开</el-button>
  46 + <el-button type="text" icon="el-icon-arrow-up" v-else @click="showAll = false">收起</el-button>
  47 + </span>
  48 + </el-form-item>
  49 + </el-col>
  50 + </el-form>
  51 + </el-row>
  52 +
  53 + <div class="NCC-common-layout-main NCC-flex-main skfk-channel-stat-page__main">
  54 + <div v-loading="summaryLoading" class="summary-wrap">
  55 + <el-row :gutter="16" class="summary-cards-row">
  56 + <el-col :xs="24" :sm="12">
  57 + <div class="stat-card stat-card--sk">
  58 + <i class="el-icon-top stat-card__icon stat-card__icon--sk" />
  59 + <div class="stat-card__body">
  60 + <div class="stat-card__label">收款侧合计</div>
  61 + <div class="stat-card__value">{{ formatMoney(skSideTotal) }}</div>
  62 + </div>
  63 + </div>
  64 + </el-col>
  65 + <el-col :xs="24" :sm="12">
  66 + <div class="stat-card stat-card--fk">
  67 + <i class="el-icon-bottom stat-card__icon stat-card__icon--fk" />
  68 + <div class="stat-card__body">
  69 + <div class="stat-card__label">付款侧合计</div>
  70 + <div class="stat-card__value">{{ formatMoney(fkSideTotal) }}</div>
  71 + </div>
  72 + </div>
  73 + </el-col>
  74 + </el-row>
  75 + </div>
  76 +
  77 + <div class="subsection-title">收款侧</div>
  78 + <el-row :gutter="16" class="channel-tables-row">
  79 + <el-col v-for="p in skPanels" :key="p.key" :xs="24" :lg="12">
  80 + <div class="table-section channel-block">
  81 + <div class="table-title-bar">
  82 + <i :class="[p.icon, 'title-icon', 'title-icon--' + p.tone]" />
  83 + <span>{{ p.title }}</span>
  84 + </div>
  85 + <el-table
  86 + :data="p.list"
  87 + border
  88 + stripe
  89 + size="small"
  90 + :header-cell-style="tableHeaderStyle"
  91 + class="channel-table cell-nowrap"
  92 + empty-text="无"
  93 + >
  94 + <el-table-column label="" width="44" align="center">
  95 + <template slot-scope="scope">
  96 + <i :class="[p.rowIcon, 'row-ico', 'row-ico--' + p.rowTone]" />
  97 + </template>
  98 + </el-table-column>
  99 + <el-table-column prop="qd" :label="p.colLabel" min-width="140" show-overflow-tooltip>
  100 + <template slot-scope="scope">
  101 + <span>{{ cellText(scope.row.qd) }}</span>
  102 + </template>
  103 + </el-table-column>
  104 + <el-table-column prop="je" label="金额" width="130" align="right">
  105 + <template slot-scope="scope">
  106 + <span class="amount-cell">{{ formatMoney(scope.row.je) }}</span>
  107 + </template>
  108 + </el-table-column>
  109 + </el-table>
  110 + </div>
  111 + </el-col>
  112 + </el-row>
  113 +
  114 + <div class="subsection-title">付款侧</div>
  115 + <el-row :gutter="16" class="channel-tables-row">
  116 + <el-col v-for="p in fkPanels" :key="p.key" :xs="24" :lg="12">
  117 + <div class="table-section channel-block">
  118 + <div class="table-title-bar">
  119 + <i :class="[p.icon, 'title-icon', 'title-icon--' + p.tone]" />
  120 + <span>{{ p.title }}</span>
  121 + </div>
  122 + <el-table
  123 + :data="p.list"
  124 + border
  125 + stripe
  126 + size="small"
  127 + :header-cell-style="tableHeaderStyle"
  128 + class="channel-table cell-nowrap"
  129 + empty-text="无"
  130 + >
  131 + <el-table-column label="" width="44" align="center">
  132 + <template slot-scope="scope">
  133 + <i :class="[p.rowIcon, 'row-ico', 'row-ico--' + p.rowTone]" />
  134 + </template>
  135 + </el-table-column>
  136 + <el-table-column prop="qd" :label="p.colLabel" min-width="140" show-overflow-tooltip>
  137 + <template slot-scope="scope">
  138 + <span>{{ cellText(scope.row.qd) }}</span>
  139 + </template>
  140 + </el-table-column>
  141 + <el-table-column prop="je" label="金额" width="130" align="right">
  142 + <template slot-scope="scope">
  143 + <span class="amount-cell">{{ formatMoney(scope.row.je) }}</span>
  144 + </template>
  145 + </el-table-column>
  146 + </el-table>
  147 + </div>
  148 + </el-col>
  149 + </el-row>
  150 +
  151 + <div class="table-section ledger-section">
  152 + <div class="table-title-bar ledger-title-bar">
  153 + <i class="el-icon-tickets title-icon title-icon--ledger" />
  154 + <span>流水明细</span>
  155 + </div>
  156 + <div class="table-scroll">
  157 + <el-table
  158 + :data="ledgerList"
  159 + border
  160 + stripe
  161 + v-loading="ledgerLoading"
  162 + :header-cell-style="tableHeaderStyle"
  163 + class="ledger-table cell-nowrap"
  164 + >
  165 + <el-table-column type="index" label="行号" width="56" :index="indexMethod" fixed />
  166 + <el-table-column label="" width="40" align="center" fixed>
  167 + <template slot-scope="scope">
  168 + <i :class="ledgerRowIcon(scope.row)" />
  169 + </template>
  170 + </el-table-column>
  171 + <el-table-column prop="djrq" label="单据日期" width="108" show-overflow-tooltip />
  172 + <el-table-column prop="djbh" label="单据编号" min-width="140" show-overflow-tooltip>
  173 + <template slot-scope="scope">
  174 + <i class="el-icon-document row-ico row-ico--doc" />
  175 + {{ cellText(scope.row.djbh) }}
  176 + </template>
  177 + </el-table-column>
  178 + <el-table-column prop="djlx" label="单据类型" min-width="120" show-overflow-tooltip>
  179 + <template slot-scope="scope">
  180 + <i class="el-icon-files row-ico row-ico--type" />
  181 + {{ cellText(scope.row.djlx) }}
  182 + </template>
  183 + </el-table-column>
  184 + <el-table-column prop="fx" label="方向" width="72" show-overflow-tooltip>
  185 + <template slot-scope="scope">
  186 + <el-tag :type="scope.row.fx === '收款' ? 'success' : 'danger'" size="mini" effect="plain">{{
  187 + cellText(scope.row.fx)
  188 + }}</el-tag>
  189 + </template>
  190 + </el-table-column>
  191 + <el-table-column prop="fffs" label="方式/渠道" min-width="120" show-overflow-tooltip>
  192 + <template slot-scope="scope">
  193 + <i class="el-icon-mobile-phone row-ico row-ico--fk" />
  194 + {{ cellText(scope.row.fffs) }}
  195 + </template>
  196 + </el-table-column>
  197 + <el-table-column prop="skzhMc" label="资金账户" min-width="140" show-overflow-tooltip>
  198 + <template slot-scope="scope">
  199 + <i
  200 + :class="
  201 + scope.row.fx === '收款'
  202 + ? 'el-icon-wallet row-ico row-ico--sk'
  203 + : 'el-icon-wallet row-ico row-ico--payacc'
  204 + "
  205 + />
  206 + {{ cellText(scope.row.skzhMc) }}
  207 + </template>
  208 + </el-table-column>
  209 + <el-table-column prop="je" label="金额" width="120" align="right">
  210 + <template slot-scope="scope">
  211 + <span :class="ledgerAmountClass(scope.row)">{{ formatMoney(scope.row.je) }}</span>
  212 + </template>
  213 + </el-table-column>
  214 + <el-table-column prop="ly" label="来源" width="100" show-overflow-tooltip>
  215 + <template slot-scope="scope">
  216 + <i class="el-icon-link row-ico row-ico--ly" />
  217 + {{ cellText(scope.row.ly) }}
  218 + </template>
  219 + </el-table-column>
  220 + <el-table-column prop="ycddh" label="原单号" min-width="130" show-overflow-tooltip>
  221 + <template slot-scope="scope">
  222 + <i class="el-icon-back row-ico row-ico--ret" />
  223 + {{ cellText(scope.row.ycddh) }}
  224 + </template>
  225 + </el-table-column>
  226 + <el-table-column prop="jsr" label="经手人" width="88" show-overflow-tooltip />
  227 + <el-table-column prop="zy" label="备注" min-width="160" show-overflow-tooltip />
  228 + </el-table>
  229 + <div class="pager-wrap">
  230 + <el-pagination
  231 + :current-page="pagination.currentPage"
  232 + :page-sizes="[50, 100, 200, 500]"
  233 + :page-size="pagination.pageSize"
  234 + layout="total, sizes, prev, pager, next, jumper"
  235 + :total="pagination.total"
  236 + @size-change="handleSizeChange"
  237 + @current-change="handleCurrentChange"
  238 + />
  239 + </div>
  240 + </div>
  241 + </div>
  242 + </div>
  243 + </div>
  244 + </div>
  245 +</template>
  246 +
  247 +<script>
  248 +import request from '@/utils/request'
  249 +
  250 +export default {
  251 + name: 'WtSkfkChannelStat',
  252 +
  253 + data() {
  254 + const y = new Date().getFullYear()
  255 + const m = String(new Date().getMonth() + 1).padStart(2, '0')
  256 + const start = `${y}-${m}-01`
  257 + const end = `${y}-${m}-${String(new Date(y, new Date().getMonth() + 1, 0).getDate()).padStart(2, '0')}`
  258 + return {
  259 + showAll: false,
  260 + summaryLoading: false,
  261 + filters: {
  262 + dateRange: [start, end],
  263 + fx: '',
  264 + qd: '',
  265 + djlx: ''
  266 + },
  267 + skAccountList: [],
  268 + skMethodList: [],
  269 + fkAccountList: [],
  270 + fkMethodList: [],
  271 + skSideTotal: 0,
  272 + fkSideTotal: 0,
  273 + ledgerList: [],
  274 + ledgerLoading: false,
  275 + pagination: {
  276 + currentPage: 1,
  277 + pageSize: 100,
  278 + total: 0
  279 + },
  280 + tableHeaderStyle: { background: '#f5f7fa' }
  281 + }
  282 + },
  283 +
  284 + computed: {
  285 + skPanels() {
  286 + return [
  287 + {
  288 + key: 'skacc',
  289 + title: '入账账户汇总',
  290 + icon: 'el-icon-coin',
  291 + tone: 'sk',
  292 + rowIcon: 'el-icon-coin',
  293 + rowTone: 'sk',
  294 + colLabel: '入账账户',
  295 + list: this.skAccountList
  296 + },
  297 + {
  298 + key: 'skmeth',
  299 + title: '买方付款方式汇总',
  300 + icon: 'el-icon-bank-card',
  301 + tone: 'fk',
  302 + rowIcon: 'el-icon-bank-card',
  303 + rowTone: 'fk',
  304 + colLabel: '付款方式',
  305 + list: this.skMethodList
  306 + }
  307 + ]
  308 + },
  309 + fkPanels() {
  310 + return [
  311 + {
  312 + key: 'fkacc',
  313 + title: '付款账户汇总',
  314 + icon: 'el-icon-wallet',
  315 + tone: 'payacc',
  316 + rowIcon: 'el-icon-wallet',
  317 + rowTone: 'payacc',
  318 + colLabel: '付款账户',
  319 + list: this.fkAccountList
  320 + },
  321 + {
  322 + key: 'fkmeth',
  323 + title: '方式/渠道汇总',
  324 + icon: 'el-icon-sort',
  325 + tone: 'fk',
  326 + rowIcon: 'el-icon-sort',
  327 + rowTone: 'fk',
  328 + colLabel: '方式',
  329 + list: this.fkMethodList
  330 + }
  331 + ]
  332 + }
  333 + },
  334 +
  335 + methods: {
  336 + indexMethod(index) {
  337 + return (this.pagination.currentPage - 1) * this.pagination.pageSize + index + 1
  338 + },
  339 + cellText(val) {
  340 + if (val === null || val === undefined || val === '') return '无'
  341 + return String(val)
  342 + },
  343 + formatMoney(val) {
  344 + if (val === null || val === undefined || val === '') return '无'
  345 + const n = Number(val)
  346 + if (Number.isNaN(n)) return String(val)
  347 + return n.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
  348 + },
  349 + ledgerRowIcon(row) {
  350 + if (row && row.fx === '收款') return 'el-icon-top row-ico row-ico--sk'
  351 + return 'el-icon-bottom row-ico row-ico--fk'
  352 + },
  353 + ledgerAmountClass(row) {
  354 + if (row && row.fx === '收款') return 'amount-cell amount-cell--sk'
  355 + return 'amount-cell amount-cell--fk'
  356 + },
  357 + buildDatePayload() {
  358 + const p = {}
  359 + if (this.filters.dateRange && this.filters.dateRange.length === 2) {
  360 + p.startDate = this.filters.dateRange[0]
  361 + p.endDate = this.filters.dateRange[1]
  362 + }
  363 + return p
  364 + },
  365 + fetchSummary() {
  366 + this.summaryLoading = true
  367 + const data = this.buildDatePayload()
  368 + return request({
  369 + url: '/api/Extend/WtSkfkChannelStat/Actions/GetChannelSummary',
  370 + method: 'GET',
  371 + data
  372 + })
  373 + .then(res => {
  374 + const body = res.data || {}
  375 + this.skAccountList = Array.isArray(body.skAccountList) ? body.skAccountList : []
  376 + this.skMethodList = Array.isArray(body.skMethodList) ? body.skMethodList : []
  377 + this.fkAccountList = Array.isArray(body.fkAccountList) ? body.fkAccountList : []
  378 + this.fkMethodList = Array.isArray(body.fkMethodList) ? body.fkMethodList : []
  379 + this.skSideTotal = body.skSideTotal != null ? Number(body.skSideTotal) : 0
  380 + this.fkSideTotal = body.fkSideTotal != null ? Number(body.fkSideTotal) : 0
  381 + })
  382 + .catch(() => {
  383 + this.$message.error('加载汇总失败,请稍后重试')
  384 + })
  385 + .finally(() => {
  386 + this.summaryLoading = false
  387 + })
  388 + },
  389 + fetchLedger() {
  390 + this.ledgerLoading = true
  391 + const data = {
  392 + ...this.buildDatePayload(),
  393 + currentPage: this.pagination.currentPage,
  394 + pageSize: this.pagination.pageSize
  395 + }
  396 + if (this.filters.fx) data.fx = this.filters.fx
  397 + if (this.filters.qd && this.filters.qd.trim()) data.qd = this.filters.qd.trim()
  398 + if (this.filters.djlx && this.filters.djlx.trim()) data.djlx = this.filters.djlx.trim()
  399 +
  400 + return request({
  401 + url: '/api/Extend/WtSkfkChannelStat/Actions/GetChannelLedger',
  402 + method: 'GET',
  403 + data
  404 + })
  405 + .then(res => {
  406 + const body = res.data || {}
  407 + this.ledgerList = Array.isArray(body.list) ? body.list : []
  408 + this.pagination.total = body.total != null ? Number(body.total) : 0
  409 + })
  410 + .catch(() => {
  411 + this.$message.error('加载流水明细失败,请稍后重试')
  412 + this.ledgerList = []
  413 + this.pagination.total = 0
  414 + })
  415 + .finally(() => {
  416 + this.ledgerLoading = false
  417 + })
  418 + },
  419 + refreshAll() {
  420 + return Promise.all([this.fetchSummary(), this.fetchLedger()])
  421 + },
  422 + handleSearch() {
  423 + this.pagination.currentPage = 1
  424 + this.refreshAll()
  425 + },
  426 + handleReset() {
  427 + const y = new Date().getFullYear()
  428 + const m = String(new Date().getMonth() + 1).padStart(2, '0')
  429 + const start = `${y}-${m}-01`
  430 + const end = `${y}-${m}-${String(new Date(y, new Date().getMonth() + 1, 0).getDate()).padStart(2, '0')}`
  431 + this.filters = {
  432 + dateRange: [start, end],
  433 + fx: '',
  434 + qd: '',
  435 + djlx: ''
  436 + }
  437 + this.showAll = false
  438 + this.pagination.currentPage = 1
  439 + this.refreshAll()
  440 + },
  441 + handleSizeChange(size) {
  442 + this.pagination.pageSize = size
  443 + this.pagination.currentPage = 1
  444 + this.fetchLedger()
  445 + },
  446 + handleCurrentChange(page) {
  447 + this.pagination.currentPage = page
  448 + this.fetchLedger()
  449 + }
  450 + },
  451 +
  452 + created() {
  453 + this.refreshAll()
  454 + }
  455 +}
  456 +</script>
  457 +
  458 +<style scoped lang="scss">
  459 +.skfk-channel-stat-page {
  460 + &.NCC-common-layout {
  461 + background: #ebeef5;
  462 + }
  463 +
  464 + &__main {
  465 + padding: 10px 16px 16px;
  466 + overflow: auto;
  467 + box-sizing: border-box;
  468 + }
  469 +}
  470 +
  471 +.summary-wrap {
  472 + min-height: 120px;
  473 + margin-bottom: 4px;
  474 +}
  475 +
  476 +.summary-cards-row {
  477 + margin-bottom: 10px;
  478 +}
  479 +
  480 +.subsection-title {
  481 + font-size: 15px;
  482 + font-weight: 600;
  483 + color: #303133;
  484 + margin: 14px 0 8px 2px;
  485 + padding-left: 8px;
  486 + border-left: 3px solid #409eff;
  487 +}
  488 +
  489 +.stat-card {
  490 + height: 100px;
  491 + border-radius: 12px;
  492 + padding: 12px;
  493 + box-sizing: border-box;
  494 + display: flex;
  495 + align-items: center;
  496 + gap: 12px;
  497 + margin-bottom: 10px;
  498 + background: #fff;
  499 + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
  500 +
  501 + &--sk {
  502 + border-left: 4px solid #67c23a;
  503 + }
  504 +
  505 + &--fk {
  506 + border-left: 4px solid #f56c6c;
  507 + }
  508 +
  509 + &__icon {
  510 + font-size: 36px;
  511 + color: #409eff;
  512 +
  513 + &--sk {
  514 + color: #67c23a;
  515 + }
  516 +
  517 + &--fk {
  518 + color: #f56c6c;
  519 + }
  520 + }
  521 +
  522 + &__body {
  523 + flex: 1;
  524 + display: flex;
  525 + flex-direction: column;
  526 + justify-content: center;
  527 + min-width: 0;
  528 + }
  529 +
  530 + &__label {
  531 + font-size: 13px;
  532 + color: #909399;
  533 + margin-bottom: 6px;
  534 + line-height: 1.3;
  535 + }
  536 +
  537 + &__value {
  538 + font-size: 22px;
  539 + font-weight: 600;
  540 + color: #303133;
  541 + font-variant-numeric: tabular-nums;
  542 + }
  543 +}
  544 +
  545 +.action-row {
  546 + display: inline-flex;
  547 + flex-wrap: wrap;
  548 + justify-content: flex-start;
  549 + align-items: center;
  550 + gap: 8px;
  551 +}
  552 +
  553 +.table-section {
  554 + background: #fff;
  555 + border-radius: 12px;
  556 + padding: 12px 12px 10px 12px;
  557 + margin: 0;
  558 + width: 100%;
  559 + box-sizing: border-box;
  560 + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04);
  561 +}
  562 +
  563 +.channel-block {
  564 + margin-bottom: 12px;
  565 +}
  566 +
  567 +.table-title-bar {
  568 + font-size: 15px;
  569 + font-weight: 600;
  570 + margin-bottom: 10px;
  571 + display: flex;
  572 + align-items: center;
  573 + flex-wrap: wrap;
  574 + gap: 8px;
  575 +}
  576 +
  577 +.ledger-title-bar {
  578 + margin-bottom: 12px;
  579 +}
  580 +
  581 +.title-icon {
  582 + font-size: 20px;
  583 + margin-right: 2px;
  584 +
  585 + &--sk {
  586 + color: #67c23a;
  587 + }
  588 +
  589 + &--fk {
  590 + color: #f56c6c;
  591 + }
  592 +
  593 + &--payacc {
  594 + color: #e6a23c;
  595 + }
  596 +
  597 + &--ledger {
  598 + color: #409eff;
  599 + }
  600 +}
  601 +
  602 +.row-ico {
  603 + margin-right: 4px;
  604 +
  605 + &--sk {
  606 + color: #67c23a;
  607 + }
  608 +
  609 + &--fk {
  610 + color: #f56c6c;
  611 + }
  612 +
  613 + &--doc {
  614 + color: #409eff;
  615 + }
  616 +
  617 + &--type {
  618 + color: #e6a23c;
  619 + }
  620 +
  621 + &--ly {
  622 + color: #909399;
  623 + }
  624 +
  625 + &--ret {
  626 + color: #f56c6c;
  627 + }
  628 +
  629 + &--payacc {
  630 + color: #e6a23c;
  631 + }
  632 +}
  633 +
  634 +.amount-cell {
  635 + font-variant-numeric: tabular-nums;
  636 + font-weight: 500;
  637 +
  638 + &--sk {
  639 + color: #67c23a;
  640 + }
  641 +
  642 + &--fk {
  643 + color: #f56c6c;
  644 + }
  645 +}
  646 +
  647 +.table-scroll {
  648 + max-height: none;
  649 +}
  650 +
  651 +.pager-wrap {
  652 + display: flex;
  653 + justify-content: flex-start;
  654 + padding: 12px 0 4px;
  655 +}
  656 +
  657 +.cell-nowrap ::v-deep .cell {
  658 + white-space: nowrap;
  659 +}
  660 +
  661 +.channel-tables-row {
  662 + margin-bottom: 4px;
  663 +}
  664 +
  665 +.ledger-section {
  666 + margin-top: 8px;
  667 +}
  668 +</style>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtSptz/Form.vue
... ... @@ -24,7 +24,7 @@
24 24 <el-form-item label-width="0">
25 25 <el-table :data="dataForm.wtSptzMxList" size='mini'>
26 26 <el-table-column type="index" width="50" label="序号" align="center" />
27   - <el-table-column prop="spbh" label="商品编号">
  27 + <el-table-column prop="spbh" label="商品编号" min-width="200">
28 28 <template slot-scope="scope">
29 29 <el-select
30 30 v-model="scope.row.spbh"
... ... @@ -43,9 +43,23 @@
43 43 </el-select>
44 44 </template>
45 45 </el-table-column>
46   - <el-table-column prop="spsl" label="商品数量">
  46 + <el-table-column prop="dqkc" label="当前库存" width="100" align="center">
47 47 <template slot-scope="scope">
48   - <el-input v-model="scope.row.spsl" placeholder="请输入" clearable @change="calculateTotalPrice()"></el-input>
  48 + <span>{{ formatRowStock(scope.row) }}</span>
  49 + </template>
  50 + </el-table-column>
  51 + <el-table-column prop="spsl" label="商品数量" width="130">
  52 + <template slot-scope="scope">
  53 + <el-input-number
  54 + v-model="scope.row.spsl"
  55 + :min="1"
  56 + :precision="0"
  57 + :step="1"
  58 + :disabled="!!isDetail"
  59 + controls-position="right"
  60 + :style='{"width":"100%"}'
  61 + @change="calculateTotalPrice()"
  62 + />
49 63 </template>
50 64 </el-table-column>
51 65 <!-- ✅ 添加零售价列 -->
... ... @@ -86,8 +100,6 @@
86 100 </template>
87 101 <script>
88 102 import request from '@/utils/request'
89   - import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
90   - import { previewDataInterface } from '@/api/systemData/dataInterface'
91 103 export default {
92 104 components: {},
93 105 props: [],
... ... @@ -97,11 +109,10 @@
97 109 visible: false,
98 110 isDetail: false,
99 111 dataForm: {
100   - id:'',
101   - id:undefined,
102   - tzmc:undefined,
103   - tzzj:0, // ✅ 添加套装总价字段
104   - wtSptzMxList:[],
  112 + id: undefined,
  113 + tzmc: undefined,
  114 + tzzj: 0,
  115 + wtSptzMxList: [],
105 116 },
106 117 rules: {
107 118 },
... ... @@ -116,65 +127,99 @@
116 127 mounted() {
117 128 },
118 129 methods: {
119   - getspbhOptions(){
120   - // ✅ 改为调用完整的商品API获取包含零售价和商品编码的数据
  130 + getspbhOptions() {
121 131 request({
122 132 url: '/api/Extend/WtSp',
123 133 method: 'get',
124   - params: {
  134 + data: {
125 135 currentPage: 1,
126   - pageSize: 1000 // 获取足够多的商品
127   - }
  136 + pageSize: 1000,
  137 + },
128 138 }).then(res => {
129 139 if (res.data && res.data.list) {
130   - // 将返回的商品列表转换为下拉选项格式
131 140 this.spbhOptions = res.data.list.map(item => ({
132 141 F_Id: item.id,
133 142 F_Spmc: item.spmc,
134   - spbm: item.spbm || '', // ✅ 包含商品编码,用于搜索
135   - F_Lsj: item.lsj // ✅ 包含零售价
  143 + spbm: item.spbm || '',
  144 + F_Lsj: item.lsj,
  145 + kc: item.kc,
  146 + mdkc: item.mdkc,
136 147 }));
137 148 }
138 149 }).catch(err => {
139 150 console.error('获取商品列表失败:', err);
140 151 });
141 152 },
  153 + formatRowStock(row) {
  154 + if (!row.spbh) return '—';
  155 + if (row.dqkc === undefined || row.dqkc === null) return '…';
  156 + return row.dqkc;
  157 + },
  158 + /** 档案库存 kc 与序列号在库数 mdkc 取较大值(序列号商品通常 kc 为 0) */
  159 + resolveDisplayStock(data) {
  160 + if (!data) return 0;
  161 + const kc = data.kc != null && data.kc !== '' ? Number(data.kc) : 0;
  162 + const kcNum = Number.isFinite(kc) ? kc : 0;
  163 + const md = parseInt(String(data.mdkc != null && data.mdkc !== '' ? data.mdkc : '0'), 10);
  164 + const mdNum = Number.isFinite(md) && !isNaN(md) ? md : 0;
  165 + return Math.max(kcNum, mdNum);
  166 + },
  167 + fetchRowStock(row) {
  168 + if (!row.spbh) return;
  169 + this.$set(row, 'dqkc', undefined);
  170 + request({
  171 + url: '/api/Extend/WtSp/' + row.spbh,
  172 + method: 'get',
  173 + })
  174 + .then(res => {
  175 + this.$set(row, 'dqkc', this.resolveDisplayStock(res.data));
  176 + })
  177 + .catch(() => {
  178 + this.$set(row, 'dqkc', '—');
  179 + });
  180 + },
142 181 goBack() {
143 182 this.$emit('refresh')
144 183 },
145 184 // ✅ 计算单个明细行的小计
146 185 calculateItemTotal(row) {
147   - // ✅ 正确处理0值:只有当数量或价格为null/undefined时才返回0
148   - const quantity = parseFloat(row.spsl);
  186 + const quantity = Number(row.spsl);
149 187 const price = parseFloat(row.lsj);
150   - if (isNaN(quantity) || isNaN(price)) {
  188 + if (!Number.isFinite(quantity) || isNaN(price)) {
151 189 return '0.00';
152 190 }
153   - const total = (quantity * price).toFixed(2);
154   - return total;
  191 + return (quantity * price).toFixed(2);
155 192 },
156 193 // ✅ 计算所有明细行的套装总价
157 194 calculateTotalPrice() {
158 195 let total = 0;
159 196 if (this.dataForm.wtSptzMxList && this.dataForm.wtSptzMxList.length > 0) {
160 197 this.dataForm.wtSptzMxList.forEach(row => {
161   - const quantity = parseFloat(row.spsl) || 0;
  198 + const quantity = Number(row.spsl);
162 199 const price = parseFloat(row.lsj) || 0;
163   - total += quantity * price;
  200 + if (Number.isFinite(quantity)) total += quantity * price;
164 201 });
165 202 }
166   - // ✅ 保留两位小数
167 203 this.dataForm.tzzj = parseFloat(total.toFixed(2));
168   - console.log('✅ 套装总价已更新:', this.dataForm.tzzj);
169 204 },
170   - // ✅ 处理商品选择变化,自动填充零售价
171 205 handleProductChange(row) {
172   - const product = this.spbhOptions.find(item => item.F_Id === row.spbh);
173   - if (product && product.F_Lsj) {
174   - this.$set(row, 'lsj', product.F_Lsj);
175   - // ✅ 商品选择后立即重新计算总价
  206 + if (!row.spbh) {
  207 + this.$set(row, 'lsj', 0);
  208 + this.$set(row, 'dqkc', undefined);
176 209 this.calculateTotalPrice();
  210 + return;
177 211 }
  212 + const product = this.spbhOptions.find(item => item.F_Id === row.spbh);
  213 + if (product) {
  214 + const lsj = product.F_Lsj != null && product.F_Lsj !== '' ? Number(product.F_Lsj) : 0;
  215 + this.$set(row, 'lsj', Number.isFinite(lsj) ? lsj : 0);
  216 + this.$set(row, 'dqkc', this.resolveDisplayStock({
  217 + kc: product.kc,
  218 + mdkc: product.mdkc,
  219 + }));
  220 + }
  221 + this.fetchRowStock(row);
  222 + this.calculateTotalPrice();
178 223 },
179 224 init(id, isDetail) {
180 225 this.dataForm.id = id || 0;
... ... @@ -185,25 +230,56 @@
185 230 if (this.dataForm.id) {
186 231 request({
187 232 url: '/api/Extend/WtSptz/' + this.dataForm.id,
188   - method: 'get'
189   - }).then(res =>{
  233 + method: 'get',
  234 + }).then(res => {
190 235 this.dataForm = res.data;
191   - // ✅ 加载数据后计算总价
192 236 this.$nextTick(() => {
  237 + const list = this.dataForm.wtSptzMxList || [];
  238 + list.forEach(r => {
  239 + const n = parseInt(String(r.spsl == null ? '' : r.spsl), 10);
  240 + this.$set(r, 'spsl', !isNaN(n) && n >= 1 ? n : 1);
  241 + if (r.spbh) this.fetchRowStock(r);
  242 + });
193 243 this.calculateTotalPrice();
194 244 });
195   - })
  245 + });
  246 + } else {
  247 + this.dataForm.wtSptzMxList = [];
  248 + this.dataForm.tzmc = undefined;
  249 + this.dataForm.tzzj = 0;
196 250 }
197   - })
  251 + });
198 252 },
199 253 dataFormSubmit() {
  254 + const mx = this.dataForm.wtSptzMxList || [];
  255 + for (let i = 0; i < mx.length; i++) {
  256 + const row = mx[i];
  257 + if (!row.spbh) {
  258 + this.$message.warning(`第 ${i + 1} 行请选择商品`);
  259 + return;
  260 + }
  261 + const q = Number(row.spsl);
  262 + if (!Number.isInteger(q) || q < 1) {
  263 + this.$message.warning(`第 ${i + 1} 行商品数量须为正整数`);
  264 + return;
  265 + }
  266 + }
200 267 this.$refs['elForm'].validate((valid) => {
201 268 if (valid) {
  269 + const mxPayload = mx.map(r => ({
  270 + id: r.id,
  271 + spbh: r.spbh,
  272 + spmc: r.spmc,
  273 + spsl: String(r.spsl),
  274 + lsj: r.lsj,
  275 + tzbh: r.tzbh,
  276 + }));
  277 + const payload = { ...this.dataForm, wtSptzMxList: mxPayload };
202 278 if (!this.dataForm.id) {
203 279 request({
204 280 url: `/api/Extend/WtSptz`,
205 281 method: 'post',
206   - data: this.dataForm,
  282 + data: payload,
207 283 }).then((res) => {
208 284 this.$message({
209 285 message: res.msg,
... ... @@ -219,7 +295,7 @@
219 295 request({
220 296 url: '/api/Extend/WtSptz/' + this.dataForm.id,
221 297 method: 'PUT',
222   - data: this.dataForm
  298 + data: payload,
223 299 }).then((res) => {
224 300 this.$message({
225 301 message: res.msg,
... ... @@ -237,10 +313,11 @@
237 313 },
238 314 addHandleWtSptzMxEntityList() {
239 315 let item = {
240   - spbh:undefined,
241   - spsl:undefined,
242   - lsj:0, // ✅ 添加零售价字段
243   - tzbh:undefined,
  316 + spbh: undefined,
  317 + spsl: 1,
  318 + lsj: 0,
  319 + tzbh: undefined,
  320 + dqkc: undefined,
244 321 }
245 322 this.dataForm.wtSptzMxList.push(item)
246 323 // ✅ 新增后重新计算总价
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtSwdd/index.vue
1   -<template>
  1 +<template>
2 2 <div class="NCC-common-layout">
3 3 <div class="NCC-common-layout-center">
4 4 <el-row class="NCC-common-search-box" :gutter="16">
... ... @@ -111,6 +111,11 @@
111 111 <el-table-column prop="gzr" label="过账人" align="left" />
112 112 <el-table-column prop="bz" label="备注" align="left" />
113 113 <el-table-column prop="djlx" label="单据类型" align="left" />
  114 + <el-table-column label="摘要" align="left" min-width="200" show-overflow-tooltip class-name="cell-nowrap">
  115 + <template slot-scope="scope">
  116 + <ncc-table-summary-cell :row="scope.row" fields="zy,Zy" />
  117 + </template>
  118 + </el-table-column>
114 119 <el-table-column label="操作" fixed="right" width="100">
115 120 <template slot-scope="scope">
116 121 <el-button type="text" @click="addOrUpdateHandle(scope.row.id)" >编辑</el-button>
... ... @@ -174,6 +179,7 @@
174 179 { prop: 'gzr', label: '过账人' },
175 180 { prop: 'bz', label: '备注' },
176 181 { prop: 'djlx', label: '单据类型' },
  182 + { prop: 'zy', label: '摘要' },
177 183 ],
178 184 cjckOptions : [],
179 185 rkckOptions : [],
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtTjdbd/index.vue
... ... @@ -151,6 +151,11 @@
151 151 <el-tag v-else type="warning" size="mini">{{ cellText(getAuditStatus(scope.row)) }}</el-tag>
152 152 </template>
153 153 </el-table-column>
  154 + <el-table-column label="摘要" align="left" min-width="200" show-overflow-tooltip class-name="cell-nowrap">
  155 + <template slot-scope="scope">
  156 + <ncc-table-summary-cell :row="scope.row" fields="zy,Zy" />
  157 + </template>
  158 + </el-table-column>
154 159 <el-table-column label="操作" fixed="right" width="320">
155 160 <template slot-scope="scope">
156 161 <el-button type="text" @click="openDetail(scope.row.id)" >查看</el-button>
... ... @@ -222,6 +227,7 @@
222 227 { prop: 'bz', label: '备注' },
223 228 { prop: 'djlx', label: '单据类型' },
224 229 { prop: 'shzt', label: '审核状态' },
  230 + { prop: 'zy', label: '摘要' },
225 231 ],
226 232 cjckOptions : [],
227 233 rkckOptions : [],
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtWldzcx/index.vue
... ... @@ -222,10 +222,10 @@
222 222 {{ fmtMoney(scope.row.wlye) }}
223 223 </template>
224 224 </el-table-column>
225   - <el-table-column prop="zy" label="摘要" min-width="160" show-overflow-tooltip>
  225 + <el-table-column label="摘要" min-width="160">
226 226 <template slot-scope="scope">
227 227 <i class="el-icon-notebook-2 row-icon brand" />
228   - {{ cellText(scope.row.zy) }}
  228 + <ncc-table-summary-cell :row="scope.row" fields="zy,Zy" />
229 229 </template>
230 230 </el-table-column>
231 231 </el-table>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXndd/index.vue
1   -<template>
  1 +<template>
2 2 <div class="NCC-common-layout">
3 3 <div class="NCC-common-layout-center">
4 4 <el-row class="NCC-common-search-box" :gutter="16">
... ... @@ -111,6 +111,11 @@
111 111 <el-table-column prop="gzr" label="过账人" align="left" />
112 112 <el-table-column prop="bz" label="备注" align="left" />
113 113 <el-table-column prop="djlx" label="单据类型" align="left" />
  114 + <el-table-column label="摘要" align="left" min-width="200" show-overflow-tooltip class-name="cell-nowrap">
  115 + <template slot-scope="scope">
  116 + <ncc-table-summary-cell :row="scope.row" fields="zy,Zy" />
  117 + </template>
  118 + </el-table-column>
114 119 <el-table-column label="操作" fixed="right" width="100">
115 120 <template slot-scope="scope">
116 121 <el-button type="text" @click="addOrUpdateHandle(scope.row.id)" >编辑</el-button>
... ... @@ -174,6 +179,7 @@
174 179 { prop: 'gzr', label: '过账人' },
175 180 { prop: 'bz', label: '备注' },
176 181 { prop: 'djlx', label: '单据类型' },
  182 + { prop: 'zy', label: '摘要' },
177 183 ],
178 184 cjckOptions : [],
179 185 rkckOptions : [],
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXsckd/Form.vue
... ... @@ -238,11 +238,16 @@
238 238 </el-input>
239 239 </el-form-item>
240 240 <!-- 支付明细显示(当收款方式为组合支付时) -->
241   - <div v-if="dataForm.skzh === '组合支付' && dataForm.skmx" style="margin-top: 10px; padding: 10px; background: #f5f7fa; border-radius: 4px; border-left: 3px solid #409eff;">
242   - <div style="font-size: 12px; font-weight: bold; color: #606266; margin-bottom: 8px;">支付明细:</div>
243   - <div v-for="(item, index) in parsePaymentDetails(dataForm.skmx)" :key="index" style="display: flex; justify-content: space-between; padding: 4px 0; font-size: 12px; color: #606266;">
244   - <span>{{ item.skfs }}</span>
245   - <span style="color: #409eff; font-weight: bold;">¥{{ parseFloat(item.skje).toFixed(2) }}</span>
  241 + <div v-if="dataForm.skzh === '组合支付' && (dataForm.skmx || dataForm.fkmx)" style="margin-top: 10px; padding: 10px; background: #f5f7fa; border-radius: 4px; border-left: 3px solid #409eff;">
  242 + <div style="font-size: 12px; font-weight: bold; color: #606266; margin-bottom: 8px;">收款明细(skmx):</div>
  243 + <div v-for="(item, index) in parsePaymentDetails(dataForm.skmx)" :key="'sk'+index" style="display: flex; justify-content: space-between; padding: 4px 0; font-size: 12px; color: #606266;">
  244 + <span>{{ item.skfs }}{{ item.qtbz ? '(' + item.qtbz + ')' : '' }}</span>
  245 + <span style="color: #409eff; font-weight: bold;">¥{{ parseFloat(item.skje || 0).toFixed(2) }}</span>
  246 + </div>
  247 + <div style="font-size: 12px; font-weight: bold; color: #606266; margin: 8px 0 4px;">付款明细(fkmx):</div>
  248 + <div v-for="(item, index) in parsePaymentDetails(dataForm.fkmx)" :key="'fk'+index" style="display: flex; justify-content: space-between; padding: 4px 0; font-size: 12px; color: #606266;">
  249 + <span>{{ item.lx || item.skfs }}</span>
  250 + <span style="color: #67C23A; font-weight: bold;">¥{{ parseFloat(item.je || item.skje || 0).toFixed(2) }}</span>
246 251 </div>
247 252 </div>
248 253 </el-col>
... ... @@ -322,6 +327,7 @@
322 327 skzh:undefined,
323 328 skje:undefined,
324 329 skmx:undefined,
  330 + fkmx:undefined,
325 331 zdr:undefined,
326 332 shr:undefined,
327 333 gzr:undefined,
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXsckd/detail-view.vue
... ... @@ -31,7 +31,7 @@
31 31 </div>
32 32 <p class="collect-stat-card__hint">
33 33 <i class="el-icon-info" />
34   - 有原价时收款=原价−优惠;组合支付以 skmx 汇总为准
  34 + 有原价时收款=原价−优惠;无原价时按 skmx+fkmx 或 skje 汇总
35 35 </p>
36 36 </div>
37 37  
... ... @@ -160,7 +160,7 @@
160 160 <el-descriptions-item label="收款账户">
161 161 <span class="cell-nowrap">
162 162 <i class="el-icon-bank-card desc-icon desc-icon--success" />
163   - {{ labelFromOptions(detail.skzh, skzhOptions) }}
  163 + {{ displaySkzhLabel }}
164 164 </span>
165 165 </el-descriptions-item>
166 166 <el-descriptions-item label="原价">
... ... @@ -206,6 +206,90 @@
206 206 <span class="detail-bz">{{ cellText(detail.spbz) }}</span>
207 207 </el-descriptions-item>
208 208 </el-descriptions>
  209 +
  210 + <div class="pay-mx-section">
  211 + <div class="detail-section-head">
  212 + <i class="el-icon-wallet detail-section-head__icon" />
  213 + <span>收款 / 付款渠道明细</span>
  214 + <span class="detail-section-head__sub">(skmx:各账户实收;fkmx:余额/积分等扣减)</span>
  215 + </div>
  216 + <div class="pay-mx-subhead">收款渠道(skmx)</div>
  217 + <el-alert
  218 + v-if="skmxUnparsedRaw"
  219 + type="warning"
  220 + :closable="false"
  221 + show-icon
  222 + class="pay-mx-alert"
  223 + title="skmx 无法解析为数组,以下为原始内容"
  224 + />
  225 + <pre v-if="skmxUnparsedRaw" class="pay-mx-raw">{{ skmxUnparsedRaw }}</pre>
  226 + <el-table
  227 + :data="skmxTableRows"
  228 + size="small"
  229 + border
  230 + stripe
  231 + class="detail-mx-table pay-mx-table"
  232 + empty-text="暂无收款渠道明细"
  233 + >
  234 + <el-table-column type="index" width="48" label="#" align="center" />
  235 + <el-table-column label="收款方式" min-width="100" show-overflow-tooltip>
  236 + <template slot-scope="scope">
  237 + <span class="cell-nowrap mx-cell">
  238 + <i class="el-icon-s-finance mx-cell__icon mx-cell__icon--success" />
  239 + {{ cellText(scope.row.skfs) }}
  240 + </span>
  241 + </template>
  242 + </el-table-column>
  243 + <el-table-column label="收款账户" min-width="120" show-overflow-tooltip>
  244 + <template slot-scope="scope">
  245 + <span class="cell-nowrap">{{ cellText(scope.row.skzhLabel) }}</span>
  246 + </template>
  247 + </el-table-column>
  248 + <el-table-column label="其他备注" min-width="120" show-overflow-tooltip>
  249 + <template slot-scope="scope">
  250 + <span class="cell-nowrap">{{ cellText(scope.row.qtbz) }}</span>
  251 + </template>
  252 + </el-table-column>
  253 + <el-table-column label="金额" width="100" align="right">
  254 + <template slot-scope="scope">
  255 + <span class="cell-nowrap mx-cell__money">¥{{ scope.row.je }}</span>
  256 + </template>
  257 + </el-table-column>
  258 + </el-table>
  259 + <div class="pay-mx-subhead pay-mx-subhead--fk">付款渠道(fkmx)</div>
  260 + <el-alert
  261 + v-if="fkmxUnparsedRaw"
  262 + type="warning"
  263 + :closable="false"
  264 + show-icon
  265 + class="pay-mx-alert"
  266 + title="fkmx 无法解析为数组,以下为原始内容"
  267 + />
  268 + <pre v-if="fkmxUnparsedRaw" class="pay-mx-raw">{{ fkmxUnparsedRaw }}</pre>
  269 + <el-table
  270 + :data="fkmxTableRows"
  271 + size="small"
  272 + border
  273 + stripe
  274 + class="detail-mx-table pay-mx-table pay-mx-table--fk"
  275 + empty-text="暂无付款渠道明细"
  276 + >
  277 + <el-table-column type="index" width="48" label="#" align="center" />
  278 + <el-table-column label="付款类型" min-width="120" show-overflow-tooltip>
  279 + <template slot-scope="scope">
  280 + <span class="cell-nowrap mx-cell">
  281 + <i class="el-icon-wallet mx-cell__icon mx-cell__icon--primary" />
  282 + {{ cellText(scope.row.lx) }}
  283 + </span>
  284 + </template>
  285 + </el-table-column>
  286 + <el-table-column label="金额(元)" width="120" align="right">
  287 + <template slot-scope="scope">
  288 + <span class="cell-nowrap mx-cell__money">¥{{ scope.row.je }}</span>
  289 + </template>
  290 + </el-table-column>
  291 + </el-table>
  292 + </div>
209 293 </template>
210 294 <div v-else-if="!loading" class="detail-empty">
211 295 <i class="el-icon-warning-outline" />
... ... @@ -223,6 +307,11 @@ import request from &#39;@/utils/request&#39;
223 307 import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
224 308 import { previewDataInterface } from '@/api/systemData/dataInterface'
225 309 import { dynamicText } from '@/filters'
  310 +import {
  311 + formatWtSkzhDisplay,
  312 + resolveSkzhDictionaryLabel,
  313 + parseWtMxJsonArray
  314 +} from '@/utils/wtComboSkzhDisplay'
226 315  
227 316 export default {
228 317 name: 'WtXsckdDetailView',
... ... @@ -276,15 +365,17 @@ export default {
276 365 const ysje = parseFloat(row.ysje) || 0
277 366 return !isNaN(ydje) ? ydje - ysje : 0
278 367 }
279   - if (row.skmx) {
280   - try {
281   - const paymentDetails = JSON.parse(row.skmx)
282   - if (Array.isArray(paymentDetails) && paymentDetails.length > 0) {
283   - return paymentDetails.reduce((sum, item) => sum + (parseFloat(item.skje) || 0), 0)
284   - }
285   - } catch (e) {
286   - // ignore
  368 + if (row.skmx || row.fkmx) {
  369 + let sum = 0
  370 + if (row.skmx) {
  371 + const { list } = parseWtMxJsonArray(row.skmx)
  372 + sum += list.reduce((s, item) => s + (parseFloat(item.skje || item.Skje) || 0), 0)
  373 + }
  374 + if (row.fkmx) {
  375 + const { list } = parseWtMxJsonArray(row.fkmx)
  376 + sum += list.reduce((s, item) => s + (parseFloat(item.je || item.Je) || 0), 0)
287 377 }
  378 + if (sum > 0) return sum
288 379 }
289 380 if (row.skje != null && row.skje !== '') return parseFloat(row.skje)
290 381 return 0
... ... @@ -293,6 +384,57 @@ export default {
293 384 const n = this.displayCollectionRaw
294 385 if (typeof n === 'number' && !isNaN(n)) return n.toFixed(2)
295 386 return '0.00'
  387 + },
  388 + displaySkzhLabel() {
  389 + if (!this.detail) return '无'
  390 + return formatWtSkzhDisplay(this.detail, this.skzhOptions)
  391 + },
  392 + skmxTableRows() {
  393 + if (!this.detail || !this.detail.skmx) return []
  394 + const { list } = parseWtMxJsonArray(this.detail.skmx)
  395 + return list.map((item, i) => ({
  396 + _idx: i,
  397 + skfs: item.skfs || item.Skfs || '无',
  398 + skzhLabel:
  399 + item.skzh || item.Skzh
  400 + ? resolveSkzhDictionaryLabel(item.skzh || item.Skzh, this.skzhOptions) ||
  401 + (item.skfs || item.Skfs || '').trim() ||
  402 + '无'
  403 + : '无',
  404 + qtbz: (item.qtbz || item.Qtbz || '').trim() || '无',
  405 + je: (() => {
  406 + const n = parseFloat(item.skje || item.Skje || 0)
  407 + return isNaN(n) ? '0.00' : n.toFixed(2)
  408 + })()
  409 + }))
  410 + },
  411 + fkmxTableRows() {
  412 + if (!this.detail || !this.detail.fkmx) return []
  413 + const { list } = parseWtMxJsonArray(this.detail.fkmx)
  414 + return list.map((item, i) => ({
  415 + _idx: i,
  416 + lx: item.lx || item.Lx || '无',
  417 + je: (() => {
  418 + const n = parseFloat(item.je || item.Je || 0)
  419 + return isNaN(n) ? '0.00' : n.toFixed(2)
  420 + })()
  421 + }))
  422 + },
  423 + skmxUnparsedRaw() {
  424 + if (!this.detail || this.detail.skmx === null || this.detail.skmx === undefined || this.detail.skmx === '') {
  425 + return ''
  426 + }
  427 + const { list, rawFallback } = parseWtMxJsonArray(this.detail.skmx)
  428 + if (list.length > 0) return ''
  429 + return rawFallback || ''
  430 + },
  431 + fkmxUnparsedRaw() {
  432 + if (!this.detail || this.detail.fkmx === null || this.detail.fkmx === undefined || this.detail.fkmx === '') {
  433 + return ''
  434 + }
  435 + const { list, rawFallback } = parseWtMxJsonArray(this.detail.fkmx)
  436 + if (list.length > 0) return ''
  437 + return rawFallback || ''
296 438 }
297 439 },
298 440 methods: {
... ... @@ -392,7 +534,9 @@ export default {
392 534 this.cjckOptions = res.data || []
393 535 })
394 536 getDictionaryDataSelector('681761709836207365').then(res => {
395   - this.skzhOptions = res.data.list || []
  537 + const d = res.data
  538 + this.skzhOptions =
  539 + d && Array.isArray(d.list) ? d.list : Array.isArray(d) ? d : []
396 540 })
397 541 }
398 542 },
... ... @@ -592,4 +736,55 @@ export default {
592 736 .xsckd-detail-footer {
593 737 text-align: left;
594 738 }
  739 +
  740 +.pay-mx-section {
  741 + margin-top: 16px;
  742 + padding-top: 14px;
  743 + border-top: 1px solid #ebeef5;
  744 +}
  745 +.pay-mx-subhead {
  746 + font-size: 13px;
  747 + font-weight: 600;
  748 + color: #303133;
  749 + margin: 12px 0 8px;
  750 + display: flex;
  751 + align-items: center;
  752 + gap: 6px;
  753 +}
  754 +.pay-mx-subhead:first-of-type {
  755 + margin-top: 0;
  756 +}
  757 +.pay-mx-subhead::before {
  758 + content: '';
  759 + width: 3px;
  760 + height: 14px;
  761 + border-radius: 2px;
  762 + background: #409eff;
  763 + flex-shrink: 0;
  764 +}
  765 +.pay-mx-subhead--fk::before {
  766 + background: #67c23a;
  767 +}
  768 +.pay-mx-alert {
  769 + margin-bottom: 8px;
  770 +}
  771 +.pay-mx-raw {
  772 + font-size: 11px;
  773 + max-height: 120px;
  774 + overflow: auto;
  775 + background: #f5f7fa;
  776 + border: 1px solid #ebeef5;
  777 + padding: 8px 10px;
  778 + border-radius: 8px;
  779 + margin: 0 0 10px;
  780 + white-space: pre-wrap;
  781 + word-break: break-all;
  782 + color: #606266;
  783 +}
  784 +.pay-mx-table--fk {
  785 + margin-top: 0;
  786 +}
  787 +.mx-cell__icon--success {
  788 + color: #67c23a;
  789 +}
595 790 </style>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXsckd/index.vue
... ... @@ -132,12 +132,17 @@
132 132 <template slot-scope="scope">{{ getDisplayOutboundCost(scope.row) }}</template>
133 133 </el-table-column>
134 134 <el-table-column label="收款账户" prop="skzh" align="left">
135   - <template slot-scope="scope">{{ scope.row.skzh | dynamicText(skzhOptions) }}</template>
  135 + <template slot-scope="scope">{{ formatSkzhRow(scope.row) }}</template>
136 136 </el-table-column>
137 137 <el-table-column prop="zdr" label="制单人" align="left" />
138 138 <el-table-column prop="shr" label="审核人" align="left" />
139 139 <el-table-column prop="gzr" label="过账人" align="left" />
140 140 <el-table-column prop="bz" label="备注" align="left" />
  141 + <el-table-column label="摘要" align="left" min-width="240">
  142 + <template slot-scope="scope">
  143 + <ncc-table-summary-cell :row="scope.row" fields="zy,Zy" />
  144 + </template>
  145 + </el-table-column>
141 146 <el-table-column prop="djlx" label="单据类型" align="left" />
142 147 <el-table-column label="单据来源" prop="ly" align="left" min-width="100">
143 148 <template slot-scope="scope">{{ formatLy(scope.row.ly) }}</template>
... ... @@ -180,6 +185,7 @@
180 185 import ExportBox from './ExportBox'
181 186 import { previewDataInterface } from '@/api/systemData/dataInterface'
182 187 import { promptApprovalRemark, postApproveSalesOutbound, postRejectGeneric } from '@/utils/wtRejectApproval'
  188 + import { formatWtSkzhDisplay } from '@/utils/wtComboSkzhDisplay'
183 189 export default {
184 190 components: { NCCForm, DetailView, ExportBox },
185 191 data() {
... ... @@ -225,6 +231,7 @@
225 231 { prop: 'shr', label: '审核人' },
226 232 { prop: 'gzr', label: '过账人' },
227 233 { prop: 'bz', label: '备注' },
  234 + { prop: 'zy', label: '摘要' },
228 235 { prop: 'djlx', label: '单据类型' },
229 236 ],
230 237 cjckOptions : [],
... ... @@ -275,6 +282,9 @@
275 282 if (ly === '后台') return '后台'
276 283 return ly
277 284 },
  285 + formatSkzhRow(row) {
  286 + return formatWtSkzhDisplay(row, this.skzhOptions)
  287 + },
278 288 // ✅ 原价:优先使用后端存储的 ydje(与收银台订单原价一致),无则用 收款+优惠 兼容旧数据
279 289 getDisplayOriginalPrice(row) {
280 290 const ydje = row.ydje != null && row.ydje !== '';
... ... @@ -294,15 +304,22 @@
294 304 const ysje = parseFloat(row.ysje) || 0;
295 305 return (!isNaN(ydje) ? (ydje - ysje).toFixed(2) : null) || '0.00';
296 306 }
297   - if (row.skmx) {
  307 + if (row.skmx || row.fkmx) {
298 308 try {
299   - const paymentDetails = JSON.parse(row.skmx);
300   - if (Array.isArray(paymentDetails) && paymentDetails.length > 0) {
301   - const totalAmount = paymentDetails.reduce((sum, item) => {
302   - return sum + (parseFloat(item.skje) || 0);
303   - }, 0);
304   - return totalAmount.toFixed(2);
  309 + let totalAmount = 0;
  310 + if (row.skmx) {
  311 + const paymentDetails = JSON.parse(row.skmx);
  312 + if (Array.isArray(paymentDetails) && paymentDetails.length > 0) {
  313 + totalAmount += paymentDetails.reduce((sum, item) => sum + (parseFloat(item.skje) || 0), 0);
  314 + }
  315 + }
  316 + if (row.fkmx) {
  317 + const fk = JSON.parse(row.fkmx);
  318 + if (Array.isArray(fk) && fk.length > 0) {
  319 + totalAmount += fk.reduce((sum, item) => sum + (parseFloat(item.je) || 0), 0);
  320 + }
305 321 }
  322 + if (totalAmount > 0) return totalAmount.toFixed(2);
306 323 } catch (e) {
307 324 console.error('解析组合支付明细失败:', e);
308 325 }
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXsthd/index.vue
... ... @@ -133,6 +133,11 @@
133 133 <el-tag v-else type="warning">{{ scope.row.djzt || '待审核' }}</el-tag>
134 134 </template>
135 135 </el-table-column>
  136 + <el-table-column label="摘要" align="left" min-width="200" show-overflow-tooltip class-name="cell-nowrap">
  137 + <template slot-scope="scope">
  138 + <ncc-table-summary-cell :row="scope.row" fields="zy,Zy" />
  139 + </template>
  140 + </el-table-column>
136 141 <el-table-column label="操作" fixed="right" width="310">
137 142 <template slot-scope="scope">
138 143 <el-button type="text" @click="addOrUpdateHandle(scope.row.id, true)">查看</el-button>
... ... @@ -209,6 +214,7 @@
209 214 { prop: 'gzr', label: '过账人' },
210 215 { prop: 'bz', label: '备注' },
211 216 { prop: 'djlx', label: '单据类型' },
  217 + { prop: 'zy', label: '摘要' },
212 218 ],
213 219 cjckOptions : [],
214 220 rkckOptions : [],
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXswtdxfhd/index.vue
... ... @@ -129,6 +129,11 @@
129 129 <el-tag v-else type="warning">{{ scope.row.djzt || '待审核' }}</el-tag>
130 130 </template>
131 131 </el-table-column>
  132 + <el-table-column label="摘要" align="left" min-width="200" show-overflow-tooltip class-name="cell-nowrap">
  133 + <template slot-scope="scope">
  134 + <ncc-table-summary-cell :row="scope.row" fields="zy,Zy" />
  135 + </template>
  136 + </el-table-column>
132 137 <el-table-column label="操作" fixed="right" width="250">
133 138 <template slot-scope="scope">
134 139 <el-button type="text" @click="addOrUpdateHandle(scope.row.id, true)">查看</el-button>
... ... @@ -201,6 +206,7 @@
201 206 { prop: 'gzr', label: '过账人' },
202 207 { prop: 'bz', label: '备注' },
203 208 { prop: 'djlx', label: '单据类型' },
  209 + { prop: 'zy', label: '摘要' },
204 210 ],
205 211 cjckOptions : [],
206 212 rkckOptions : [],
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXswtdxjsd/ShipmentOrderSelect.vue
... ... @@ -140,6 +140,11 @@
140 140 {{ getKhName(scope.row.kh) }}
141 141 </template>
142 142 </el-table-column>
  143 + <el-table-column label="摘要" min-width="220">
  144 + <template slot-scope="scope">
  145 + <ncc-table-summary-cell :row="scope.row" fields="zy,Zy" />
  146 + </template>
  147 + </el-table-column>
143 148 <el-table-column prop="jsr" label="经手人" width="100">
144 149 <template slot-scope="scope">
145 150 {{ getUserName(scope.row.jsr) }}
... ... @@ -522,10 +527,11 @@ export default {
522 527 return date.toLocaleDateString()
523 528 },
524 529  
525   - // 获取往来单位名称
526   - getKhName(khId) {
527   - const kh = this.khOptions.find(item => item.id === khId)
528   - return kh ? kh.dwmc : khId
  530 + // 获取往来单位名称(列表 kh 已为解析后的展示名时直接显示)
  531 + getKhName(val) {
  532 + if (val == null || val === '') return '无'
  533 + const kh = this.khOptions.find(item => item.id === val)
  534 + return kh ? kh.dwmc : val
529 535 },
530 536  
531 537 // 获取用户名称
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXswtdxjsd/index.vue
... ... @@ -128,6 +128,11 @@
128 128 <el-tag v-else type="warning">{{ scope.row.djzt || '待审核' }}</el-tag>
129 129 </template>
130 130 </el-table-column>
  131 + <el-table-column label="摘要" align="left" min-width="200" show-overflow-tooltip class-name="cell-nowrap">
  132 + <template slot-scope="scope">
  133 + <ncc-table-summary-cell :row="scope.row" fields="zy,Zy" />
  134 + </template>
  135 + </el-table-column>
131 136 <el-table-column label="操作" fixed="right" width="250">
132 137 <template slot-scope="scope">
133 138 <el-button type="text" @click="openDetail(scope.row.id)">查看</el-button>
... ... @@ -200,6 +205,7 @@
200 205 { prop: 'gzr', label: '过账人' },
201 206 { prop: 'bz', label: '备注' },
202 207 { prop: 'djlx', label: '单据类型' },
  208 + { prop: 'zy', label: '摘要' },
203 209 ],
204 210 cjckOptions : [],
205 211 rkckOptions : [],
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtXswtdxthd/index.vue
... ... @@ -128,6 +128,11 @@
128 128 <el-tag v-else type="warning">{{ scope.row.djzt || '待审核' }}</el-tag>
129 129 </template>
130 130 </el-table-column>
  131 + <el-table-column label="摘要" align="left" min-width="200" show-overflow-tooltip class-name="cell-nowrap">
  132 + <template slot-scope="scope">
  133 + <ncc-table-summary-cell :row="scope.row" fields="zy,Zy" />
  134 + </template>
  135 + </el-table-column>
131 136 <el-table-column label="操作" fixed="right" width="250">
132 137 <template slot-scope="scope">
133 138 <el-button type="text" @click="addOrUpdateHandle(scope.row.id, true)">查看</el-button>
... ... @@ -201,6 +206,7 @@
201 206 { prop: 'bz', label: '备注' },
202 207 { prop: 'djlx', label: '单据类型' },
203 208 { prop: 'ytwtfhd', label: '原委托发货单' },
  209 + { prop: 'zy', label: '摘要' },
204 210 ],
205 211 cjckOptions : [],
206 212 rkckOptions : [],
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYfkzjjs/Form.vue
... ... @@ -20,6 +20,11 @@
20 20 </user-select>
21 21 </el-form-item>
22 22 </el-col>
  23 + <el-col :span="24" v-if="dataForm.id">
  24 + <el-form-item label="业务摘要">
  25 + <ncc-bill-summary :value="dataForm.billZy" mode="block" />
  26 + </el-form-item>
  27 + </el-col>
23 28 <el-col :span="24">
24 29 <el-form-item label-width="0">
25 30 <el-table :data="dataForm.wtYskzjjsMxList" size='mini'>
... ... @@ -141,6 +146,7 @@
141 146 skzh:undefined,
142 147 skje:undefined,
143 148 djlx:undefined,
  149 + billZy:undefined,
144 150 },
145 151 rules: {
146 152 wtYskzjjsMxList: [{ required: true, message: '请至少添加一条明细', trigger: 'change' }],
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYfkzjjs/detail-view.vue
... ... @@ -55,6 +55,9 @@
55 55 {{ cellText(detail.jsr) }}
56 56 </span>
57 57 </el-descriptions-item>
  58 + <el-descriptions-item label="业务摘要" :span="2">
  59 + <ncc-bill-summary :value="detail.billZy || detail.zy" mode="block" :show-icon="false" />
  60 + </el-descriptions-item>
58 61 </el-descriptions>
59 62  
60 63 <div class="detail-section-head">
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYfkzjjs/index.vue
... ... @@ -98,6 +98,11 @@
98 98 </el-table-column>
99 99 <el-table-column prop="skje" label="收款金额" align="left" />
100 100 <el-table-column prop="djlx" label="单据类型" align="left" />
  101 + <el-table-column label="摘要" align="left" min-width="200" show-overflow-tooltip class-name="cell-nowrap">
  102 + <template slot-scope="scope">
  103 + <ncc-table-summary-cell :row="scope.row" fields="billZy,BillZy,zy,Zy" />
  104 + </template>
  105 + </el-table-column>
101 106 <el-table-column label="操作" fixed="right" width="150">
102 107 <template slot-scope="scope">
103 108 <el-button type="text" @click="openDetail(scope.row.id)">查看</el-button>
... ... @@ -157,6 +162,7 @@
157 162 { prop: 'skzh', label: '收款账户' },
158 163 { prop: 'skje', label: '收款金额' },
159 164 { prop: 'djlx', label: '单据类型' },
  165 + { prop: 'billZy', label: '摘要' },
160 166 ],
161 167 fkzhOptions : [],
162 168 skzhOptions : [],
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYfkzjjs_js/Form.vue
1   -<template>
  1 +<template>
2 2 <el-dialog :title="!dataForm.id ? '新建' : isDetail ? '详情':'编辑'" :close-on-click-modal="false" :visible.sync="visible" class="NCC-dialog NCC-dialog_center" lock-scroll width="90%">
3 3 <el-row :gutter="15" class="" >
4 4 <el-form ref="elForm" :model="dataForm" size="small" label-width="100px" label-position="right" :disabled="!!isDetail" :rules="rules">
... ... @@ -20,6 +20,11 @@
20 20 </user-select>
21 21 </el-form-item>
22 22 </el-col>
  23 + <el-col :span="24" v-if="dataForm.id">
  24 + <el-form-item label="业务摘要">
  25 + <ncc-bill-summary :value="dataForm.billZy" mode="block" />
  26 + </el-form-item>
  27 + </el-col>
23 28 <el-col :span="24">
24 29 <el-form-item label-width="0">
25 30 <el-table :data="dataForm.wtYskzjjsMxList" size='mini'>
... ... @@ -124,6 +129,7 @@
124 129 skzh:undefined,
125 130 skje:undefined,
126 131 djlx:undefined,
  132 + billZy:undefined,
127 133 },
128 134 rules: {
129 135 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYfkzjjs_js/detail-view.vue
... ... @@ -55,6 +55,9 @@
55 55 {{ cellText(detail.jsr) }}
56 56 </span>
57 57 </el-descriptions-item>
  58 + <el-descriptions-item label="业务摘要" :span="2">
  59 + <ncc-bill-summary :value="detail.billZy || detail.zy" mode="block" :show-icon="false" />
  60 + </el-descriptions-item>
58 61 </el-descriptions>
59 62  
60 63 <div class="detail-section-head">
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYfkzjjs_js/index.vue
... ... @@ -98,6 +98,11 @@
98 98 </el-table-column>
99 99 <el-table-column prop="skje" label="收款金额" align="left" />
100 100 <el-table-column prop="djlx" label="单据类型" align="left" />
  101 + <el-table-column label="摘要" align="left" min-width="200" show-overflow-tooltip class-name="cell-nowrap">
  102 + <template slot-scope="scope">
  103 + <ncc-table-summary-cell :row="scope.row" fields="billZy,BillZy,zy,Zy" />
  104 + </template>
  105 + </el-table-column>
101 106 <el-table-column label="操作" fixed="right" width="150">
102 107 <template slot-scope="scope">
103 108 <el-button type="text" @click="openDetail(scope.row.id)">查看</el-button>
... ... @@ -157,6 +162,7 @@
157 162 { prop: 'skzh', label: '收款账户' },
158 163 { prop: 'skje', label: '收款金额' },
159 164 { prop: 'djlx', label: '单据类型' },
  165 + { prop: 'billZy', label: '摘要' },
160 166 ],
161 167 fkzhOptions : [],
162 168 skzhOptions : [],
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYsckd/detail-view.vue
... ... @@ -36,7 +36,7 @@
36 36 </div>
37 37 <p class="collect-stat-card__hint">
38 38 <i class="el-icon-info" />
39   - 有原价时收款=原价−优惠;组合支付以 skmx 汇总为准
  39 + 有原价时收款=原价−优惠;无原价时按 skmx+fkmx 或 skje 汇总
40 40 </p>
41 41 </div>
42 42  
... ... @@ -165,7 +165,7 @@
165 165 <el-descriptions-item label="收款账户">
166 166 <span class="cell-nowrap">
167 167 <i class="el-icon-bank-card desc-icon desc-icon--success" />
168   - {{ labelFromOptions(detail.skzh, skzhOptions) }}
  168 + {{ displaySkzhLabel }}
169 169 </span>
170 170 </el-descriptions-item>
171 171 <el-descriptions-item label="原价">
... ... @@ -211,6 +211,90 @@
211 211 <span class="detail-bz">{{ cellText(detail.spbz) }}</span>
212 212 </el-descriptions-item>
213 213 </el-descriptions>
  214 +
  215 + <div class="pay-mx-section">
  216 + <div class="detail-section-head">
  217 + <i class="el-icon-wallet detail-section-head__icon" />
  218 + <span>收款 / 付款渠道明细</span>
  219 + <span class="detail-section-head__sub">(skmx:各账户实收;fkmx:余额/积分等扣减)</span>
  220 + </div>
  221 + <div class="pay-mx-subhead">收款渠道(skmx)</div>
  222 + <el-alert
  223 + v-if="skmxUnparsedRaw"
  224 + type="warning"
  225 + :closable="false"
  226 + show-icon
  227 + class="pay-mx-alert"
  228 + title="skmx 无法解析为数组,以下为原始内容"
  229 + />
  230 + <pre v-if="skmxUnparsedRaw" class="pay-mx-raw">{{ skmxUnparsedRaw }}</pre>
  231 + <el-table
  232 + :data="skmxTableRows"
  233 + size="small"
  234 + border
  235 + stripe
  236 + class="detail-mx-table pay-mx-table"
  237 + empty-text="暂无收款渠道明细"
  238 + >
  239 + <el-table-column type="index" width="48" label="#" align="center" />
  240 + <el-table-column label="收款方式" min-width="100" show-overflow-tooltip>
  241 + <template slot-scope="scope">
  242 + <span class="cell-nowrap mx-cell">
  243 + <i class="el-icon-s-finance mx-cell__icon mx-cell__icon--success" />
  244 + {{ cellText(scope.row.skfs) }}
  245 + </span>
  246 + </template>
  247 + </el-table-column>
  248 + <el-table-column label="收款账户" min-width="120" show-overflow-tooltip>
  249 + <template slot-scope="scope">
  250 + <span class="cell-nowrap">{{ cellText(scope.row.skzhLabel) }}</span>
  251 + </template>
  252 + </el-table-column>
  253 + <el-table-column label="其他备注" min-width="120" show-overflow-tooltip>
  254 + <template slot-scope="scope">
  255 + <span class="cell-nowrap">{{ cellText(scope.row.qtbz) }}</span>
  256 + </template>
  257 + </el-table-column>
  258 + <el-table-column label="金额" width="100" align="right">
  259 + <template slot-scope="scope">
  260 + <span class="cell-nowrap mx-cell__money">¥{{ scope.row.je }}</span>
  261 + </template>
  262 + </el-table-column>
  263 + </el-table>
  264 + <div class="pay-mx-subhead pay-mx-subhead--fk">付款渠道(fkmx)</div>
  265 + <el-alert
  266 + v-if="fkmxUnparsedRaw"
  267 + type="warning"
  268 + :closable="false"
  269 + show-icon
  270 + class="pay-mx-alert"
  271 + title="fkmx 无法解析为数组,以下为原始内容"
  272 + />
  273 + <pre v-if="fkmxUnparsedRaw" class="pay-mx-raw">{{ fkmxUnparsedRaw }}</pre>
  274 + <el-table
  275 + :data="fkmxTableRows"
  276 + size="small"
  277 + border
  278 + stripe
  279 + class="detail-mx-table pay-mx-table pay-mx-table--fk"
  280 + empty-text="暂无付款渠道明细"
  281 + >
  282 + <el-table-column type="index" width="48" label="#" align="center" />
  283 + <el-table-column label="付款类型" min-width="120" show-overflow-tooltip>
  284 + <template slot-scope="scope">
  285 + <span class="cell-nowrap mx-cell">
  286 + <i class="el-icon-wallet mx-cell__icon mx-cell__icon--primary" />
  287 + {{ cellText(scope.row.lx) }}
  288 + </span>
  289 + </template>
  290 + </el-table-column>
  291 + <el-table-column label="金额(元)" width="120" align="right">
  292 + <template slot-scope="scope">
  293 + <span class="cell-nowrap mx-cell__money">¥{{ scope.row.je }}</span>
  294 + </template>
  295 + </el-table-column>
  296 + </el-table>
  297 + </div>
214 298 </template>
215 299 <div v-else-if="!loading" class="detail-empty">
216 300 <i class="el-icon-warning-outline" />
... ... @@ -225,6 +309,11 @@ import request from &#39;@/utils/request&#39;
225 309 import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
226 310 import { previewDataInterface } from '@/api/systemData/dataInterface'
227 311 import { dynamicText } from '@/filters'
  312 +import {
  313 + formatWtSkzhDisplay,
  314 + resolveSkzhDictionaryLabel,
  315 + parseWtMxJsonArray
  316 +} from '@/utils/wtComboSkzhDisplay'
228 317  
229 318 export default {
230 319 name: 'WtYsckdDetailView',
... ... @@ -262,15 +351,17 @@ export default {
262 351 const ysje = parseFloat(row.ysje) || 0
263 352 return !isNaN(ydje) ? ydje - ysje : 0
264 353 }
265   - if (row.skmx) {
266   - try {
267   - const paymentDetails = JSON.parse(row.skmx)
268   - if (Array.isArray(paymentDetails) && paymentDetails.length > 0) {
269   - return paymentDetails.reduce((sum, item) => sum + (parseFloat(item.skje) || 0), 0)
270   - }
271   - } catch (e) {
272   - // ignore
  354 + if (row.skmx || row.fkmx) {
  355 + let sum = 0
  356 + if (row.skmx) {
  357 + const { list } = parseWtMxJsonArray(row.skmx)
  358 + sum += list.reduce((s, item) => s + (parseFloat(item.skje || item.Skje) || 0), 0)
  359 + }
  360 + if (row.fkmx) {
  361 + const { list } = parseWtMxJsonArray(row.fkmx)
  362 + sum += list.reduce((s, item) => s + (parseFloat(item.je || item.Je) || 0), 0)
273 363 }
  364 + if (sum > 0) return sum
274 365 }
275 366 if (row.skje != null && row.skje !== '') return parseFloat(row.skje)
276 367 return 0
... ... @@ -279,6 +370,57 @@ export default {
279 370 const n = this.displayCollectionRaw
280 371 if (typeof n === 'number' && !isNaN(n)) return n.toFixed(2)
281 372 return '0.00'
  373 + },
  374 + displaySkzhLabel() {
  375 + if (!this.detail) return '无'
  376 + return formatWtSkzhDisplay(this.detail, this.skzhOptions)
  377 + },
  378 + skmxTableRows() {
  379 + if (!this.detail || !this.detail.skmx) return []
  380 + const { list } = parseWtMxJsonArray(this.detail.skmx)
  381 + return list.map((item, i) => ({
  382 + _idx: i,
  383 + skfs: item.skfs || item.Skfs || '无',
  384 + skzhLabel:
  385 + item.skzh || item.Skzh
  386 + ? resolveSkzhDictionaryLabel(item.skzh || item.Skzh, this.skzhOptions) ||
  387 + (item.skfs || item.Skfs || '').trim() ||
  388 + '无'
  389 + : '无',
  390 + qtbz: (item.qtbz || item.Qtbz || '').trim() || '无',
  391 + je: (() => {
  392 + const n = parseFloat(item.skje || item.Skje || 0)
  393 + return isNaN(n) ? '0.00' : n.toFixed(2)
  394 + })()
  395 + }))
  396 + },
  397 + fkmxTableRows() {
  398 + if (!this.detail || !this.detail.fkmx) return []
  399 + const { list } = parseWtMxJsonArray(this.detail.fkmx)
  400 + return list.map((item, i) => ({
  401 + _idx: i,
  402 + lx: item.lx || item.Lx || '无',
  403 + je: (() => {
  404 + const n = parseFloat(item.je || item.Je || 0)
  405 + return isNaN(n) ? '0.00' : n.toFixed(2)
  406 + })()
  407 + }))
  408 + },
  409 + skmxUnparsedRaw() {
  410 + if (!this.detail || this.detail.skmx === null || this.detail.skmx === undefined || this.detail.skmx === '') {
  411 + return ''
  412 + }
  413 + const { list, rawFallback } = parseWtMxJsonArray(this.detail.skmx)
  414 + if (list.length > 0) return ''
  415 + return rawFallback || ''
  416 + },
  417 + fkmxUnparsedRaw() {
  418 + if (!this.detail || this.detail.fkmx === null || this.detail.fkmx === undefined || this.detail.fkmx === '') {
  419 + return ''
  420 + }
  421 + const { list, rawFallback } = parseWtMxJsonArray(this.detail.fkmx)
  422 + if (list.length > 0) return ''
  423 + return rawFallback || ''
282 424 }
283 425 },
284 426 methods: {
... ... @@ -382,7 +524,9 @@ export default {
382 524 this.cjckOptions = res.data || []
383 525 })
384 526 getDictionaryDataSelector('681761709836207365').then(res => {
385   - this.skzhOptions = res.data.list || []
  527 + const d = res.data
  528 + this.skzhOptions =
  529 + d && Array.isArray(d.list) ? d.list : Array.isArray(d) ? d : []
386 530 })
387 531 }
388 532 },
... ... @@ -588,4 +732,55 @@ export default {
588 732 .ysckd-detail-footer {
589 733 text-align: left;
590 734 }
  735 +
  736 +.pay-mx-section {
  737 + margin-top: 16px;
  738 + padding-top: 14px;
  739 + border-top: 1px solid #ebeef5;
  740 +}
  741 +.pay-mx-subhead {
  742 + font-size: 13px;
  743 + font-weight: 600;
  744 + color: #303133;
  745 + margin: 12px 0 8px;
  746 + display: flex;
  747 + align-items: center;
  748 + gap: 6px;
  749 +}
  750 +.pay-mx-subhead:first-of-type {
  751 + margin-top: 0;
  752 +}
  753 +.pay-mx-subhead::before {
  754 + content: '';
  755 + width: 3px;
  756 + height: 14px;
  757 + border-radius: 2px;
  758 + background: #409eff;
  759 + flex-shrink: 0;
  760 +}
  761 +.pay-mx-subhead--fk::before {
  762 + background: #67c23a;
  763 +}
  764 +.pay-mx-alert {
  765 + margin-bottom: 8px;
  766 +}
  767 +.pay-mx-raw {
  768 + font-size: 11px;
  769 + max-height: 120px;
  770 + overflow: auto;
  771 + background: #f5f7fa;
  772 + border: 1px solid #ebeef5;
  773 + padding: 8px 10px;
  774 + border-radius: 8px;
  775 + margin: 0 0 10px;
  776 + white-space: pre-wrap;
  777 + word-break: break-all;
  778 + color: #606266;
  779 +}
  780 +.pay-mx-table--fk {
  781 + margin-top: 0;
  782 +}
  783 +.mx-cell__icon--success {
  784 + color: #67c23a;
  785 +}
591 786 </style>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYsckd/index.vue
... ... @@ -134,7 +134,7 @@
134 134 <template slot-scope="scope">{{ getDisplayOutboundCost(scope.row) }}</template>
135 135 </el-table-column>
136 136 <el-table-column label="收款账户" prop="skzh" align="left">
137   - <template slot-scope="scope">{{ scope.row.skzh | dynamicText(skzhOptions) }}</template>
  137 + <template slot-scope="scope">{{ formatSkzhRow(scope.row) }}</template>
138 138 </el-table-column>
139 139 <el-table-column prop="zdr" label="制单人" align="left" />
140 140 <el-table-column prop="shr" label="审核人" align="left" />
... ... @@ -154,6 +154,11 @@
154 154 <el-tag v-else type="warning">{{ scope.row.djzt || '待审核' }}</el-tag>
155 155 </template>
156 156 </el-table-column>
  157 + <el-table-column label="摘要" align="left" min-width="200" show-overflow-tooltip class-name="cell-nowrap">
  158 + <template slot-scope="scope">
  159 + <ncc-table-summary-cell :row="scope.row" fields="zy,Zy" />
  160 + </template>
  161 + </el-table-column>
157 162 <el-table-column label="操作" fixed="right" width="420">
158 163 <template slot-scope="scope">
159 164 <el-button type="text" @click="openDetail(scope.row.id)">查看</el-button>
... ... @@ -242,6 +247,7 @@
242 247 import SerialNumberSelect from './SerialNumberSelect'
243 248 import { previewDataInterface } from '@/api/systemData/dataInterface'
244 249 import { promptApprovalRemark, postApproveSalesOutbound } from '@/utils/wtRejectApproval'
  250 + import { formatWtSkzhDisplay } from '@/utils/wtComboSkzhDisplay'
245 251 export default {
246 252 components: { NCCForm, DetailView, ExportBox, SerialNumberSelect },
247 253 data() {
... ... @@ -291,6 +297,7 @@
291 297 { prop: 'djlx', label: '单据类型' },
292 298 { prop: 'ly', label: '单据来源' },
293 299 { prop: 'djzt', label: '审核状态' },
  300 + { prop: 'zy', label: '摘要' },
294 301 ],
295 302 cjckOptions : [],
296 303 rkckOptions : [],
... ... @@ -340,6 +347,9 @@
340 347 if (ly === '抖音订单') return '抖音订单'
341 348 return ly
342 349 },
  350 + formatSkzhRow(row) {
  351 + return formatWtSkzhDisplay(row, this.skzhOptions)
  352 + },
343 353 getDisplayOutboundCost(row) {
344 354 const val = parseFloat(row.cbje)
345 355 return isNaN(val) ? '0.00' : val.toFixed(2)
... ... @@ -392,15 +402,22 @@
392 402 const ysje = parseFloat(row.ysje) || 0;
393 403 return (!isNaN(ydje) ? (ydje - ysje).toFixed(2) : null) || '0.00';
394 404 }
395   - if (row.skmx) {
  405 + if (row.skmx || row.fkmx) {
396 406 try {
397   - const paymentDetails = JSON.parse(row.skmx);
398   - if (Array.isArray(paymentDetails) && paymentDetails.length > 0) {
399   - const totalAmount = paymentDetails.reduce((sum, item) => {
400   - return sum + (parseFloat(item.skje) || 0);
401   - }, 0);
402   - return totalAmount.toFixed(2);
  407 + let totalAmount = 0;
  408 + if (row.skmx) {
  409 + const paymentDetails = JSON.parse(row.skmx);
  410 + if (Array.isArray(paymentDetails) && paymentDetails.length > 0) {
  411 + totalAmount += paymentDetails.reduce((sum, item) => sum + (parseFloat(item.skje) || 0), 0);
  412 + }
  413 + }
  414 + if (row.fkmx) {
  415 + const fk = JSON.parse(row.fkmx);
  416 + if (Array.isArray(fk) && fk.length > 0) {
  417 + totalAmount += fk.reduce((sum, item) => sum + (parseFloat(item.je) || 0), 0);
  418 + }
403 419 }
  420 + if (totalAmount > 0) return totalAmount.toFixed(2);
404 421 } catch (e) {
405 422 console.error('解析组合支付明细失败:', e);
406 423 }
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs/Form.vue
... ... @@ -20,6 +20,11 @@
20 20 </user-select>
21 21 </el-form-item>
22 22 </el-col>
  23 + <el-col :span="24" v-if="dataForm.id">
  24 + <el-form-item label="业务摘要">
  25 + <ncc-bill-summary :value="dataForm.billZy" mode="block" />
  26 + </el-form-item>
  27 + </el-col>
23 28 <el-col :span="24">
24 29 <el-form-item label-width="0">
25 30 <el-table :data="dataForm.wtYskzjjsMxList" size='mini'>
... ... @@ -141,6 +146,7 @@
141 146 skzh:undefined,
142 147 skje:undefined,
143 148 djlx:undefined,
  149 + billZy:undefined,
144 150 },
145 151 rules: {
146 152 wtYskzjjsMxList: [{ required: true, message: '请至少添加一条明细', trigger: 'change' }],
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs/detail-view.vue
... ... @@ -55,6 +55,9 @@
55 55 {{ cellText(detail.jsr) }}
56 56 </span>
57 57 </el-descriptions-item>
  58 + <el-descriptions-item label="业务摘要" :span="2">
  59 + <ncc-bill-summary :value="detail.billZy || detail.zy" mode="block" :show-icon="false" />
  60 + </el-descriptions-item>
58 61 </el-descriptions>
59 62  
60 63 <div class="detail-section-head">
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs/index.vue
... ... @@ -98,6 +98,12 @@
98 98 </el-table-column>
99 99 <el-table-column prop="skje" label="收款金额" align="left" />
100 100 <el-table-column prop="djlx" label="单据类型" align="left" />
  101 + <el-table-column label="摘要" align="left" min-width="220" class-name="cell-nowrap">
  102 + <template slot-scope="scope">
  103 + <i class="el-icon-reading" style="color:#409EFF;margin-right:6px" />
  104 + <ncc-table-summary-cell :row="scope.row" fields="billZy,BillZy,zy,Zy" />
  105 + </template>
  106 + </el-table-column>
101 107 <el-table-column label="操作" fixed="right" width="150">
102 108 <template slot-scope="scope">
103 109 <el-button type="text" @click="openDetail(scope.row.id)">查看</el-button>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs_hy/detail-view.vue
... ... @@ -20,7 +20,9 @@
20 20 <el-descriptions-item label="会员手机号码">{{ cellText(detail.hysjh) }}</el-descriptions-item>
21 21 <el-descriptions-item label="金额">{{ money(detail.skje) }}</el-descriptions-item>
22 22 <el-descriptions-item label="账户">{{ accountText(detail.fkzh) }}</el-descriptions-item>
23   - <el-descriptions-item label="摘要" :span="2">{{ cellText(detail.zy) }}</el-descriptions-item>
  23 + <el-descriptions-item label="摘要" :span="2">
  24 + <ncc-bill-summary :value="detail.billZy || detail.zy" mode="block" :show-icon="false" />
  25 + </el-descriptions-item>
24 26 </el-descriptions>
25 27  
26 28 <div class="mx-title">明细</div>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs_hy/index.vue
... ... @@ -78,7 +78,11 @@
78 78 <el-table-column label="账户" prop="fkzh" align="left">
79 79 <template slot-scope="scope">{{ scope.row.fkzh | dynamicText(fkzhOptions) }}</template>
80 80 </el-table-column>
81   - <el-table-column prop="zy" label="摘要" align="left" show-overflow-tooltip />
  81 + <el-table-column label="摘要" align="left" min-width="200">
  82 + <template slot-scope="scope">
  83 + <ncc-table-summary-cell :row="scope.row" fields="billZy,BillZy,zy,Zy" />
  84 + </template>
  85 + </el-table-column>
82 86 <el-table-column label="操作" fixed="right" width="140">
83 87 <template slot-scope="scope">
84 88 <el-button type="text" @click="openDetail(scope.row.id)" >查看</el-button>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs_js/Form.vue
1   -<template>
  1 +<template>
2 2 <el-dialog :title="!dataForm.id ? '新建' : isDetail ? '详情':'编辑'" :close-on-click-modal="false" :visible.sync="visible" class="NCC-dialog NCC-dialog_center" lock-scroll width="90%">
3 3 <el-row :gutter="15" class="" >
4 4 <el-form ref="elForm" :model="dataForm" size="small" label-width="100px" label-position="right" :disabled="!!isDetail" :rules="rules">
... ... @@ -20,6 +20,11 @@
20 20 </user-select>
21 21 </el-form-item>
22 22 </el-col>
  23 + <el-col :span="24" v-if="dataForm.id">
  24 + <el-form-item label="业务摘要">
  25 + <ncc-bill-summary :value="dataForm.billZy" mode="block" />
  26 + </el-form-item>
  27 + </el-col>
23 28 <el-col :span="24">
24 29 <el-form-item label-width="0">
25 30 <el-table :data="dataForm.wtYskzjjsMxList" size='mini'>
... ... @@ -124,6 +129,7 @@
124 129 skzh:undefined,
125 130 skje:undefined,
126 131 djlx:undefined,
  132 + billZy:undefined,
127 133 },
128 134 rules: {
129 135 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs_js/detail-view.vue
... ... @@ -55,6 +55,9 @@
55 55 {{ cellText(detail.jsr) }}
56 56 </span>
57 57 </el-descriptions-item>
  58 + <el-descriptions-item label="业务摘要" :span="2">
  59 + <ncc-bill-summary :value="detail.billZy || detail.zy" mode="block" :show-icon="false" />
  60 + </el-descriptions-item>
58 61 </el-descriptions>
59 62  
60 63 <div class="detail-section-head">
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs_js/index.vue
... ... @@ -98,6 +98,11 @@
98 98 </el-table-column>
99 99 <el-table-column prop="skje" label="收款金额" align="left" />
100 100 <el-table-column prop="djlx" label="单据类型" align="left" />
  101 + <el-table-column label="摘要" align="left" min-width="180" show-overflow-tooltip>
  102 + <template slot-scope="scope">
  103 + <ncc-table-summary-cell :row="scope.row" fields="billZy,BillZy,zy,Zy" />
  104 + </template>
  105 + </el-table-column>
101 106 <el-table-column label="操作" fixed="right" width="150">
102 107 <template slot-scope="scope">
103 108 <el-button type="text" @click="openDetail(scope.row.id)">查看</el-button>
... ... @@ -157,6 +162,7 @@
157 162 { prop: 'skzh', label: '收款账户' },
158 163 { prop: 'skje', label: '收款金额' },
159 164 { prop: 'djlx', label: '单据类型' },
  165 + { prop: 'billZy', label: '摘要' },
160 166 ],
161 167 fkzhOptions : [],
162 168 skzhOptions : [],
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs_qt/detail-view.vue
... ... @@ -18,7 +18,9 @@
18 18 <el-descriptions-item label="往来单位">{{ wldwText(detail.wldw) }}</el-descriptions-item>
19 19 <el-descriptions-item label="金额">{{ money(detail.skje) }}</el-descriptions-item>
20 20 <el-descriptions-item label="经手人">{{ cellText(detail.jsr) }}</el-descriptions-item>
21   - <el-descriptions-item label="摘要" :span="2">{{ cellText(detail.zy || detail.bz) }}</el-descriptions-item>
  21 + <el-descriptions-item label="摘要" :span="2">
  22 + <ncc-bill-summary :value="detail.billZy || detail.zy || detail.bz" mode="block" :show-icon="false" />
  23 + </el-descriptions-item>
22 24 </el-descriptions>
23 25  
24 26 <div class="mx-title">明细</div>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs_qt/index.vue
... ... @@ -71,9 +71,9 @@
71 71 </el-table-column>
72 72 <el-table-column prop="skje" label="金额" align="left" />
73 73 <el-table-column prop="jsr" label="经手人" align="left" />
74   - <el-table-column label="摘要" align="left" min-width="180" show-overflow-tooltip>
  74 + <el-table-column label="摘要" align="left" min-width="200">
75 75 <template slot-scope="scope">
76   - {{ scope.row.zy || scope.row.bz || '无' }}
  76 + <ncc-table-summary-cell :row="scope.row" fields="billZy,BillZy,zy,Zy,bz,Bz" />
77 77 </template>
78 78 </el-table-column>
79 79 <el-table-column label="操作" fixed="right" width="140">
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs_xj/detail-view.vue
... ... @@ -18,7 +18,9 @@
18 18 <el-descriptions-item label="金额">{{ money(totalAmount) }}</el-descriptions-item>
19 19 <el-descriptions-item label="账户">{{ accountText(detail.fkzh) }}</el-descriptions-item>
20 20 <el-descriptions-item label="经手人">{{ cellText(detail.jsr) }}</el-descriptions-item>
21   - <el-descriptions-item label="摘要" :span="2">{{ cellText(summaryText) }}</el-descriptions-item>
  21 + <el-descriptions-item label="业务摘要" :span="2">
  22 + <ncc-bill-summary :value="summaryText" mode="block" :show-icon="false" />
  23 + </el-descriptions-item>
22 24 </el-descriptions>
23 25  
24 26 <div class="mx-title">明细</div>
... ... @@ -63,9 +65,9 @@ export default {
63 65 return mxList.reduce((sum, row) => sum + (parseFloat(row.je) || 0), 0)
64 66 },
65 67 summaryText() {
66   - if (!this.detail) return ''
  68 + if (!this.detail) return ''
67 69 const mxList = this.detail.wtYskzjjsMxList || []
68   - return this.detail.zy || this.detail.bz || (mxList[0] && mxList[0].bz) || '无'
  70 + return this.detail.billZy || this.detail.zy || this.detail.bz || (mxList[0] && mxList[0].bz) || ''
69 71 }
70 72 },
71 73 created() {
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs_xj/index.vue
... ... @@ -97,7 +97,7 @@
97 97 <el-table-column prop="jsr" label="经手人" align="left" />
98 98 <el-table-column label="摘要" align="left" min-width="180" show-overflow-tooltip>
99 99 <template slot-scope="scope">
100   - {{ scope.row.summary || '无' }}
  100 + <ncc-table-summary-cell :row="scope.row" fields="summary" />
101 101 </template>
102 102 </el-table-column>
103 103 <el-table-column label="操作" fixed="right" width="140">
... ... @@ -204,7 +204,7 @@
204 204 const amount = item.fkje !== undefined && item.fkje !== null && item.fkje !== ''
205 205 ? item.fkje
206 206 : mxList.reduce((sum, row) => sum + (parseFloat(row.je) || 0), 0)
207   - const summary = item.zy || item.bz || (mxList[0] && mxList[0].bz) || ''
  207 + const summary = item.billZy || item.zy || item.bz || (mxList[0] && mxList[0].bz) || ''
208 208 return {
209 209 ...item,
210 210 amount,
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs_zk/detail-view.vue
... ... @@ -14,6 +14,9 @@
14 14 <el-descriptions-item label="单据日期">{{ formatDate(detail.djrq) }}</el-descriptions-item>
15 15 <el-descriptions-item label="经手人">{{ text(detail.jsr) }}</el-descriptions-item>
16 16 <el-descriptions-item label="单据类型">{{ text(detail.djlx || '转款单') }}</el-descriptions-item>
  17 + <el-descriptions-item label="业务摘要" :span="2">
  18 + <ncc-bill-summary :value="detail.billZy || detail.zy" mode="block" :show-icon="false" />
  19 + </el-descriptions-item>
17 20 <el-descriptions-item label="付款账户">{{ accountLabel(detail.fkzh) }}</el-descriptions-item>
18 21 <el-descriptions-item label="付款金额">{{ formatMoney(detail.fkje) }}</el-descriptions-item>
19 22 </el-descriptions>
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYskzjjs_zk/index.vue
... ... @@ -103,6 +103,11 @@
103 103 <el-table-column prop="djlx" label="单据类型" align="left">
104 104 <template slot-scope="scope">{{ scope.row.djlx || '无' }}</template>
105 105 </el-table-column>
  106 + <el-table-column label="摘要" align="left" min-width="180" show-overflow-tooltip>
  107 + <template slot-scope="scope">
  108 + <ncc-table-summary-cell :row="scope.row" fields="billZy,BillZy,zy,Zy" />
  109 + </template>
  110 + </el-table-column>
106 111 <el-table-column label="操作" fixed="right" width="150">
107 112 <template slot-scope="scope">
108 113 <el-button type="text" @click="openDetail(scope.row.id)">查看</el-button>
... ... @@ -161,6 +166,7 @@
161 166 { prop: 'skzh', label: '收款账户' },
162 167 { prop: 'skje', label: '收款金额' },
163 168 { prop: 'djlx', label: '单据类型' },
  169 + { prop: 'billZy', label: '摘要' },
164 170 ],
165 171 fkzhOptions : [],
166 172 skzhOptions : [],
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYsthd/Form.vue
1   -<template>
  1 +<template>
2 2 <el-dialog :title="!dataForm.id ? '新建' : isDetail ? '详情':'编辑'" :close-on-click-modal="false" :visible.sync="visible" class="NCC-dialog NCC-dialog_center" lock-scroll width="80%">
3 3 <el-row :gutter="15" class="" >
4 4 <el-form ref="elForm" :model="dataForm" size="small" label-width="100px" label-position="right" :disabled="!!isDetail" :rules="rules">
... ... @@ -27,6 +27,26 @@
27 27 </user-select>
28 28 </el-form-item>
29 29 </el-col>
  30 + <el-col :span="12">
  31 + <el-form-item label="原预售出库单" prop="ycddh">
  32 + <el-input
  33 + v-model="dataForm.ycddh"
  34 + placeholder="可选,点击右侧按钮选择预售出库单"
  35 + readonly
  36 + clearable
  37 + :style='{"width":"100%"}'
  38 + @clear="dataForm.ycddh = undefined"
  39 + >
  40 + <el-button
  41 + slot="append"
  42 + type="primary"
  43 + icon="el-icon-search"
  44 + :disabled="!!isDetail"
  45 + @click="openShipmentOrderSelect"
  46 + >调原预售出库单</el-button>
  47 + </el-input>
  48 + </el-form-item>
  49 + </el-col>
30 50 <!-- 主表入库仓库字段 -->
31 51 <!-- <el-col :span="12" v-if="false">
32 52 <el-form-item label="入库仓库" prop="rkck">
... ... @@ -219,6 +239,13 @@
219 239 </span>
220 240 <!-- 序列号选择弹窗 -->
221 241 <SerialNumberSelect ref="serialNumberSelect" @confirm="handleSerialNumberSelect" />
  242 + <ShipmentOrderSelect
  243 + ref="shipmentOrderSelect"
  244 + :single-select="true"
  245 + djlx="预售出库单"
  246 + bill-type-label="预售出库单"
  247 + @confirm="handleShipmentOrderSelect"
  248 + />
222 249 </el-dialog>
223 250 </template>
224 251 <script>
... ... @@ -226,8 +253,9 @@
226 253 import { getDictionaryDataSelector } from '@/api/systemData/dictionary'
227 254 import { previewDataInterface } from '@/api/systemData/dataInterface'
228 255 import SerialNumberSelect from '../wtXsckd/SerialNumberSelect.vue'
  256 + import ShipmentOrderSelect from '../wtXswtdxjsd/ShipmentOrderSelect.vue'
229 257 export default {
230   - components: { SerialNumberSelect },
  258 + components: { SerialNumberSelect, ShipmentOrderSelect },
231 259 props: [],
232 260 data() {
233 261 return {
... ... @@ -248,6 +276,7 @@
248 276 zdr:undefined,
249 277 shr:undefined,
250 278 gzr:undefined,
  279 + ycddh: undefined,
251 280 bz:undefined,
252 281 djlx:"预售退货单",
253 282 },
... ... @@ -324,6 +353,58 @@
324 353 goBack() {
325 354 this.$emit('refresh')
326 355 },
  356 + openShipmentOrderSelect() {
  357 + if (this.isDetail) return
  358 + this.$refs.shipmentOrderSelect.open()
  359 + },
  360 + async handleShipmentOrderSelect(shipmentDetails, mainTableInfo) {
  361 + if (!shipmentDetails || shipmentDetails.length === 0) {
  362 + this.$message.warning('未选择任何预售出库单明细')
  363 + return
  364 + }
  365 + try {
  366 + if (mainTableInfo && mainTableInfo.sourceBillId) {
  367 + this.dataForm.ycddh = mainTableInfo.sourceBillId
  368 + }
  369 + this.dataForm.wtXsckdMxList = []
  370 + for (const detail of shipmentDetails) {
  371 + const sourceNo = detail.djbh || detail.sourceOrderId || (mainTableInfo && mainTableInfo.sourceBillId) || undefined
  372 + const newDetail = {
  373 + rkck: undefined,
  374 + ckck: this.dataForm.cjck || undefined,
  375 + spbh: detail.spbh,
  376 + spmc: detail.spmc,
  377 + sptm: detail.sptm,
  378 + dw: detail.dw,
  379 + sl: detail.sl || 0,
  380 + dj: detail.dj || 0,
  381 + je: detail.je || 0,
  382 + description: detail.description || '',
  383 + selectedSerialNumbers: detail.selectedSerialNumbers || [],
  384 + spxlhLoaded: false,
  385 + productQuery: '',
  386 + djbh: sourceNo,
  387 + sourceOrderId: detail.sourceOrderId,
  388 + sourceOrderDate: detail.sourceOrderDate
  389 + }
  390 + this.dataForm.wtXsckdMxList.push(newDetail)
  391 + if (detail.spbh) {
  392 + this.getProductInfo(detail.spbh).then(productInfo => {
  393 + if (productInfo && productInfo.spxlhType) {
  394 + this.$set(newDetail, 'spxlhLoaded', true)
  395 + this.$forceUpdate()
  396 + }
  397 + })
  398 + }
  399 + }
  400 + this.syncDetailWarehouses()
  401 + this.updateTotalAmount()
  402 + this.$message.success(`成功加载 ${shipmentDetails.length} 条预售出库单明细`)
  403 + } catch (error) {
  404 + console.error('处理预售出库单明细失败:', error)
  405 + this.$message.error('加载预售出库单明细失败')
  406 + }
  407 + },
327 408 init(id, isDetail) {
328 409 this.dataForm.id = id || 0;
329 410 this.visible = true;
... ... @@ -362,8 +443,9 @@
362 443 this.updateTotalAmount();
363 444 })
364 445 } else {
365   - // 新建时确保wtXsckdMxList为空数组
366   - this.dataForm.wtXsckdMxList = [];
  446 + // 新建时确保wtXsckdMxList为空数组,并清空原单号
  447 + this.dataForm.wtXsckdMxList = []
  448 + this.dataForm.ycddh = undefined
367 449 }
368 450 })
369 451 },
... ...
Antis.Erp.Plat/antis-ncc-admin/src/views/wtYsthd/index.vue
... ... @@ -132,6 +132,11 @@
132 132 <el-tag v-else type="warning">{{ scope.row.djzt || '待审核' }}</el-tag>
133 133 </template>
134 134 </el-table-column>
  135 + <el-table-column label="摘要" align="left" min-width="200" show-overflow-tooltip class-name="cell-nowrap">
  136 + <template slot-scope="scope">
  137 + <ncc-table-summary-cell :row="scope.row" fields="zy,Zy" />
  138 + </template>
  139 + </el-table-column>
135 140 <el-table-column label="操作" fixed="right" width="250">
136 141 <template slot-scope="scope">
137 142 <el-button type="text" @click="addOrUpdateHandle(scope.row.id, true)">查看</el-button>
... ... @@ -207,6 +212,7 @@
207 212 { prop: 'gzr', label: '过账人' },
208 213 { prop: 'bz', label: '备注' },
209 214 { prop: 'djlx', label: '单据类型' },
  215 + { prop: 'zy', label: '摘要' },
210 216 ],
211 217 cjckOptions : [],
212 218 rkckOptions : [],
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtCwdjInfoOutput.cs
1   -using System;
  1 +using System;
2 2 using System.Collections.Generic;
3 3  
4 4 namespace NCC.Extend.Entitys.Dto.WtCwdj
... ... @@ -42,6 +42,11 @@ namespace NCC.Extend.Entitys.Dto.WtCwdj
42 42 /// 摘要
43 43 /// </summary>
44 44 public string zy { get; set; }
  45 +
  46 + /// <summary>
  47 + /// 业务摘要(与摘要汇总表规则一致,服务端计算,不落库)
  48 + /// </summary>
  49 + public string billZy { get; set; }
45 50  
46 51 /// <summary>
47 52 /// 审核时间
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtCwdjListOutput.cs
... ... @@ -43,6 +43,11 @@ namespace NCC.Extend.Entitys.Dto.WtCwdj
43 43 public string zy { get; set; }
44 44  
45 45 /// <summary>
  46 + /// 业务摘要(与摘要汇总表规则一致,服务端计算,不落库)
  47 + /// </summary>
  48 + public string billZy { get; set; }
  49 +
  50 + /// <summary>
46 51 /// 发生金额
47 52 /// </summary>
48 53 public decimal fsje { get; set; }
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtDjzy/WtDjzyListOutput.cs 0 → 100644
  1 +using System;
  2 +
  3 +namespace NCC.Extend.Entitys.Dto.WtDjzy
  4 +{
  5 + /// <summary>
  6 + /// 摘要汇总表列表行
  7 + /// </summary>
  8 + public class WtDjzyListOutput
  9 + {
  10 + /// <summary>
  11 + /// 主键
  12 + /// </summary>
  13 + public string id { get; set; }
  14 +
  15 + /// <summary>
  16 + /// 业务单据编号
  17 + /// </summary>
  18 + public string djbh { get; set; }
  19 +
  20 + /// <summary>
  21 + /// 来源模块
  22 + /// </summary>
  23 + public string ly { get; set; }
  24 +
  25 + /// <summary>
  26 + /// 单据类型
  27 + /// </summary>
  28 + public string djlx { get; set; }
  29 +
  30 + /// <summary>
  31 + /// 单据日期
  32 + /// </summary>
  33 + public DateTime? djrq { get; set; }
  34 +
  35 + /// <summary>
  36 + /// 摘要全文
  37 + /// </summary>
  38 + public string zynr { get; set; }
  39 + }
  40 +}
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtDjzy/WtDjzyListQueryInput.cs 0 → 100644
  1 +using NCC.Common.Filter;
  2 +
  3 +namespace NCC.Extend.Entitys.Dto.WtDjzy
  4 +{
  5 + /// <summary>
  6 + /// 摘要汇总表分页查询
  7 + /// </summary>
  8 + public class WtDjzyListQueryInput : PageInputBase
  9 + {
  10 + /// <summary>
  11 + /// 单据编号(模糊)
  12 + /// </summary>
  13 + public string djbh { get; set; }
  14 +
  15 + /// <summary>
  16 + /// 来源 ly:xsckd、cwdj 等
  17 + /// </summary>
  18 + public string ly { get; set; }
  19 +
  20 + /// <summary>
  21 + /// 单据类型(模糊)
  22 + /// </summary>
  23 + public string djlx { get; set; }
  24 +
  25 + /// <summary>
  26 + /// 单据日期范围,逗号分隔时间戳
  27 + /// </summary>
  28 + public string djrq { get; set; }
  29 + }
  30 +}
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtDjzy/WtDjzySyncInput.cs 0 → 100644
  1 +namespace NCC.Extend.Entitys.Dto.WtDjzy
  2 +{
  3 + /// <summary>
  4 + /// 将业务主表批量同步到 wt_djzy 时的可选日期筛选(各 SyncFrom* 接口共用;均为可选)
  5 + /// </summary>
  6 + public class WtDjzySyncInput
  7 + {
  8 + /// <summary>
  9 + /// 单据日期起(可与前端 daterange 一致:时间戳毫秒,或 yyyy-MM-dd)
  10 + /// </summary>
  11 + public string djrqStart { get; set; }
  12 +
  13 + /// <summary>
  14 + /// 单据日期止(含当天结束时)
  15 + /// </summary>
  16 + public string djrqEnd { get; set; }
  17 + }
  18 +}
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtSfkInfoOutput.cs
1   -using System;
  1 +using System;
2 2 using System.Collections.Generic;
3 3  
4 4 namespace NCC.Extend.Entitys.Dto.WtSfk
... ... @@ -62,6 +62,11 @@ namespace NCC.Extend.Entitys.Dto.WtSfk
62 62 /// 单据类型
63 63 /// </summary>
64 64 public string djlx { get; set; }
  65 +
  66 + /// <summary>
  67 + /// 业务摘要(与摘要汇总表规则一致,服务端计算,不落库)
  68 + /// </summary>
  69 + public string billZy { get; set; }
65 70  
66 71 }
67 72 }
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtSfkListOutput.cs
1   -using System;
  1 +using System;
2 2  
3 3 namespace NCC.Extend.Entitys.Dto.WtSfk
4 4 {
... ... @@ -61,6 +61,11 @@ namespace NCC.Extend.Entitys.Dto.WtSfk
61 61 /// 单据类型
62 62 /// </summary>
63 63 public string djlx { get; set; }
  64 +
  65 + /// <summary>
  66 + /// 业务摘要(与摘要汇总表规则一致,服务端计算,不落库)
  67 + /// </summary>
  68 + public string billZy { get; set; }
64 69  
65 70 }
66 71 }
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtSkfkChannelStat/WtSkfkChannelStatChannelRowOutput.cs 0 → 100644
  1 +namespace NCC.Extend.Entitys.Dto.WtSkfkChannelStat
  2 +{
  3 + /// <summary>
  4 + /// 按渠道汇总一行
  5 + /// </summary>
  6 + public class WtSkfkChannelStatChannelRowOutput
  7 + {
  8 + /// <summary>
  9 + /// 渠道名称(收款方式 / 付款方式 / 账户字典名等)
  10 + /// </summary>
  11 + public string qd { get; set; }
  12 +
  13 + /// <summary>
  14 + /// 金额合计
  15 + /// </summary>
  16 + public decimal je { get; set; }
  17 + }
  18 +}
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtSkfkChannelStat/WtSkfkChannelStatLedgerRowOutput.cs 0 → 100644
  1 +namespace NCC.Extend.Entitys.Dto.WtSkfkChannelStat
  2 +{
  3 + /// <summary>
  4 + /// 收付款渠道流水一行
  5 + /// </summary>
  6 + public class WtSkfkChannelStatLedgerRowOutput
  7 + {
  8 + /// <summary>
  9 + /// 单据日期 yyyy-MM-dd
  10 + /// </summary>
  11 + public string djrq { get; set; }
  12 +
  13 + /// <summary>
  14 + /// 单据编号
  15 + /// </summary>
  16 + public string djbh { get; set; }
  17 +
  18 + /// <summary>
  19 + /// 单据类型
  20 + /// </summary>
  21 + public string djlx { get; set; }
  22 +
  23 + /// <summary>
  24 + /// 业务方向:收款 / 付款(含销售退货等退款)
  25 + /// </summary>
  26 + public string fx { get; set; }
  27 +
  28 + /// <summary>
  29 + /// 买方付款方式(微信、支付宝、余额、积分抵扣等,来自 skmx.skfs 或 fkmx.lx)
  30 + /// </summary>
  31 + public string fffs { get; set; }
  32 +
  33 + /// <summary>
  34 + /// 收款账户(入账端,如莱迪收钱吧;来自 skmx.skzh 或主表 skzh 字典名)
  35 + /// </summary>
  36 + public string skzhMc { get; set; }
  37 +
  38 + /// <summary>
  39 + /// 金额(正数)
  40 + /// </summary>
  41 + public decimal je { get; set; }
  42 +
  43 + /// <summary>
  44 + /// 数据来源:进销存单据 / 收付款单 / 财务单据
  45 + /// </summary>
  46 + public string ly { get; set; }
  47 +
  48 + /// <summary>
  49 + /// 原单号(销售退货、预售退货等关联原出库单)
  50 + /// </summary>
  51 + public string ycddh { get; set; }
  52 +
  53 + /// <summary>
  54 + /// 备注或摘要(无则「无」)
  55 + /// </summary>
  56 + public string zy { get; set; }
  57 +
  58 + /// <summary>
  59 + /// 经手人姓名(无则「无」)
  60 + /// </summary>
  61 + public string jsr { get; set; }
  62 + }
  63 +}
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtSkfkChannelStat/WtSkfkChannelStatQueryInput.cs 0 → 100644
  1 +namespace NCC.Extend.Entitys.Dto.WtSkfkChannelStat
  2 +{
  3 + /// <summary>
  4 + /// 收付款渠道统计与流水查询条件(GET 使用 data 传参)
  5 + /// </summary>
  6 + public class WtSkfkChannelStatQueryInput
  7 + {
  8 + /// <summary>
  9 + /// 开始日期 yyyy-MM-dd(含)
  10 + /// </summary>
  11 + public string startDate { get; set; }
  12 +
  13 + /// <summary>
  14 + /// 结束日期 yyyy-MM-dd(含)
  15 + /// </summary>
  16 + public string endDate { get; set; }
  17 +
  18 + /// <summary>
  19 + /// 收付方向筛选:空=全部;sk=仅收款;fk=仅付款(与流水接口一致)
  20 + /// </summary>
  21 + public string fx { get; set; }
  22 +
  23 + /// <summary>
  24 + /// 渠道名称模糊匹配(流水)
  25 + /// </summary>
  26 + public string qd { get; set; }
  27 +
  28 + /// <summary>
  29 + /// 单据类型模糊匹配(流水)
  30 + /// </summary>
  31 + public string djlx { get; set; }
  32 +
  33 + /// <summary>
  34 + /// 当前页,默认 1
  35 + /// </summary>
  36 + public int? currentPage { get; set; }
  37 +
  38 + /// <summary>
  39 + /// 每页条数,默认 100,最大 500
  40 + /// </summary>
  41 + public int? pageSize { get; set; }
  42 + }
  43 +}
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtSkzhbListOutput.cs
... ... @@ -21,6 +21,10 @@ namespace NCC.Extend.Entitys.Dto.WtSkzhb
21 21 /// 所属门店
22 22 /// </summary>
23 23 public string ssmd { get; set; }
24   -
  24 +
  25 + /// <summary>
  26 + /// 收款账户字典项 Id(表字段 zhmc,与 ERP 字典一致;写入出库单 skzh / skmx.skzh,勿用本表 F_Id)
  27 + /// </summary>
  28 + public string skzhDictId { get; set; }
25 29 }
26 30 }
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtSpInfoOutput.cs
... ... @@ -68,6 +68,11 @@ namespace NCC.Extend.Entitys.Dto.WtSp
68 68 /// 库存
69 69 /// </summary>
70 70 public int? kc { get; set; }
  71 +
  72 + /// <summary>
  73 + /// 在库序列号数量(未指定门店时为全库 status=0 合计,与商品列表 <c>mdkc</c> 一致;序列号管理商品以此为准)
  74 + /// </summary>
  75 + public string mdkc { get; set; }
71 76  
72 77 /// <summary>
73 78 /// 详情
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtXsckdCrInput.cs
... ... @@ -122,9 +122,14 @@ namespace NCC.Extend.Entitys.Dto.WtXsckd
122 122 public string djzt { get; set; }
123 123  
124 124 /// <summary>
125   - /// 收款明细 (JSON格式: [{"skfs":"微信","skje":"100.00"},...])
  125 + /// 收款明细 (JSON格式: [{"skfs":"微信","skje":"100.00","skzh":"账户id"},...])
126 126 /// </summary>
127 127 public string skmx { get; set; }
  128 +
  129 + /// <summary>
  130 + /// 付款明细(会员余额、积分抵扣等,JSON)
  131 + /// </summary>
  132 + public string fkmx { get; set; }
128 133  
129 134 /// <summary>
130 135 /// 原销售出库单编号(退货类单据可选;不传时后端从备注「原订单号:」解析)
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtXsckdInfoOutput.cs
... ... @@ -132,6 +132,11 @@ namespace NCC.Extend.Entitys.Dto.WtXsckd
132 132 /// 收款明细
133 133 /// </summary>
134 134 public string skmx { get; set; }
  135 +
  136 + /// <summary>
  137 + /// 付款明细(会员余额、积分抵扣等)
  138 + /// </summary>
  139 + public string fkmx { get; set; }
135 140  
136 141 /// <summary>
137 142 /// 原销售出库单编号(退货类单据)
... ... @@ -147,5 +152,10 @@ namespace NCC.Extend.Entitys.Dto.WtXsckd
147 152 /// 关联退货单单号(销售/预售出库单:逗号分隔)
148 153 /// </summary>
149 154 public string thdh { get; set; }
  155 +
  156 + /// <summary>
  157 + /// 业务摘要(详情展示用,与列表 zy 规则一致)
  158 + /// </summary>
  159 + public string zy { get; set; }
150 160 }
151 161 }
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtXsckdListOutput.cs
... ... @@ -137,6 +137,16 @@ namespace NCC.Extend.Entitys.Dto.WtXsckd
137 137 /// 收款明细
138 138 /// </summary>
139 139 public string skmx { get; set; }
  140 +
  141 + /// <summary>
  142 + /// 付款明细(会员侧)
  143 + /// </summary>
  144 + public string fkmx { get; set; }
  145 +
  146 + /// <summary>
  147 + /// 业务摘要(列表展示用,服务端按单据类型与明细拼装,不落库)
  148 + /// </summary>
  149 + public string zy { get; set; }
140 150  
141 151 }
142 152 }
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtYskzjjsInfoOutput.cs
... ... @@ -52,6 +52,11 @@ namespace NCC.Extend.Entitys.Dto.WtYskzjjs
52 52 /// 摘要
53 53 /// </summary>
54 54 public string zy { get; set; }
  55 +
  56 + /// <summary>
  57 + /// 业务摘要(与摘要汇总表规则一致,服务端计算,不落库)
  58 + /// </summary>
  59 + public string billZy { get; set; }
55 60  
56 61 /// <summary>
57 62 /// 付款账户
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/WtYskzjjsListOutput.cs
... ... @@ -73,6 +73,11 @@ namespace NCC.Extend.Entitys.Dto.WtYskzjjs
73 73 public string zy { get; set; }
74 74  
75 75 /// <summary>
  76 + /// 业务摘要(与摘要汇总表规则一致,服务端计算,不落库)
  77 + /// </summary>
  78 + public string billZy { get; set; }
  79 +
  80 + /// <summary>
76 81 /// 往来单位主键
77 82 /// </summary>
78 83 public string wldw { get; set; }
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/WtDjzyEntity.cs 0 → 100644
  1 +using NCC.Common.Const;
  2 +using SqlSugar;
  3 +using System;
  4 +
  5 +namespace NCC.Extend.Entitys
  6 +{
  7 + /// <summary>
  8 + /// 业务单据摘要汇总表:各模块写入后供集中查询(与业务主表通过 djbh + ly 关联)
  9 + /// </summary>
  10 + [SugarTable("wt_djzy")]
  11 + [Tenant(ClaimConst.TENANT_ID)]
  12 + public class WtDjzyEntity
  13 + {
  14 + /// <summary>
  15 + /// 主键
  16 + /// </summary>
  17 + [SugarColumn(ColumnName = "F_Id", IsPrimaryKey = true)]
  18 + public string Id { get; set; }
  19 +
  20 + /// <summary>
  21 + /// 业务单据编号(如 CHD…、财务单号等)
  22 + /// </summary>
  23 + [SugarColumn(ColumnName = "djbh")]
  24 + public string Djbh { get; set; }
  25 +
  26 + /// <summary>
  27 + /// 来源模块编码:xsckd、cwdj、czd…(与 djbh 组成业务唯一)
  28 + /// </summary>
  29 + [SugarColumn(ColumnName = "ly")]
  30 + public string Ly { get; set; }
  31 +
  32 + /// <summary>
  33 + /// 单据类型(展示)
  34 + /// </summary>
  35 + [SugarColumn(ColumnName = "djlx")]
  36 + public string Djlx { get; set; }
  37 +
  38 + /// <summary>
  39 + /// 单据日期
  40 + /// </summary>
  41 + [SugarColumn(ColumnName = "djrq", IsNullable = true)]
  42 + public DateTime? Djrq { get; set; }
  43 +
  44 + /// <summary>
  45 + /// 摘要全文
  46 + /// </summary>
  47 + [SugarColumn(ColumnName = "zynr", ColumnDataType = "text", IsNullable = true)]
  48 + public string Zynr { get; set; }
  49 +
  50 + /// <summary>
  51 + /// 创建时间
  52 + /// </summary>
  53 + [SugarColumn(ColumnName = "F_CreatorTime", IsNullable = true)]
  54 + public DateTime? CreatorTime { get; set; }
  55 +
  56 + /// <summary>
  57 + /// 最后修改时间
  58 + /// </summary>
  59 + [SugarColumn(ColumnName = "F_LastModifyTime", IsNullable = true)]
  60 + public DateTime? LastModifyTime { get; set; }
  61 + }
  62 +}
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Entity/WtXsckdEntity.cs
... ... @@ -169,9 +169,15 @@ namespace NCC.Extend.Entitys
169 169 public string Ly { get; set; }
170 170  
171 171 /// <summary>
172   - /// 收款明细 (JSON格式: [{"skfs":"微信","skje":"100.00"},{"skfs":"现金","skje":"50.00"}])
  172 + /// 收款明细 (JSON格式: [{"skfs":"微信","skje":"100.00","skzh":"账户id"},{"skfs":"其他","skje":"10","qtbz":"备注"}])
173 173 /// </summary>
174 174 [SugarColumn(ColumnName = "skmx", IsNullable = true)]
175 175 public string Skmx { get; set; }
  176 +
  177 + /// <summary>
  178 + /// 付款明细(会员侧扣减,便于统计):JSON 如 [{"lx":"余额","je":"50.00"},{"lx":"积分抵扣","je":"10.00"}]
  179 + /// </summary>
  180 + [SugarColumn(ColumnName = "fkmx", IsNullable = true, ColumnDataType = "text")]
  181 + public string Fkmx { get; set; }
176 182 }
177 183 }
178 184 \ No newline at end of file
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend/BillSummary/WtBillSummaryFormat.cs 0 → 100644
  1 +using System;
  2 +using System.Collections.Generic;
  3 +using System.Linq;
  4 +
  5 +namespace NCC.Extend.BillSummary
  6 +{
  7 + /// <summary>
  8 + /// 业务摘要文案拼装工具(无数据库依赖,各单据服务可复用)
  9 + /// </summary>
  10 + public static class WtBillSummaryFormat
  11 + {
  12 + /// <summary>
  13 + /// 空值展示为「无」(与前端列表规范一致)
  14 + /// </summary>
  15 + public static string Wu(string? s) =>
  16 + string.IsNullOrWhiteSpace(s) ? "无" : s.Trim();
  17 +
  18 + /// <summary>
  19 + /// 使用全角书名号包裹展示片段
  20 + /// </summary>
  21 + public static string Bracket(string? s)
  22 + {
  23 + var t = string.IsNullOrWhiteSpace(s) ? "无" : s.Trim();
  24 + return $"【{t}】";
  25 + }
  26 +
  27 + /// <summary>
  28 + /// 金额千分位两位小数
  29 + /// </summary>
  30 + public static string Money(decimal d) => d.ToString("N2");
  31 +
  32 + /// <summary>
  33 + /// 根据明细商品名称生成摘要中的商品片段:单条【名】、两条【A、B】、多条【首条】等
  34 + /// </summary>
  35 + public static string GoodsDigest(IEnumerable<string?>? spmcs)
  36 + {
  37 + var list = spmcs?
  38 + .Where(s => !string.IsNullOrWhiteSpace(s))
  39 + .Select(s => s!.Trim())
  40 + .Distinct(StringComparer.Ordinal)
  41 + .ToList() ?? new List<string>();
  42 + if (list.Count == 0)
  43 + return "【无】";
  44 + if (list.Count == 1)
  45 + return Bracket(list[0]);
  46 + if (list.Count == 2)
  47 + return Bracket($"{list[0]}、{list[1]}");
  48 + return $"{Bracket(list[0])}等";
  49 + }
  50 +
  51 + /// <summary>
  52 + /// 摘要检索格式:往来单位+经手人+事项(历史兼容;新摘要请用自然语句 + <see cref="WithJsrColon"/>)
  53 + /// </summary>
  54 + public static string QueryTriple(string? khDisplay, string? jsrDisplay, string matter)
  55 + {
  56 + var k = Wu(khDisplay);
  57 + var j = Wu(jsrDisplay);
  58 + var m = string.IsNullOrWhiteSpace(matter) ? "无" : matter.Trim();
  59 + return $"{k}+{j}+{m}";
  60 + }
  61 +
  62 + /// <summary>
  63 + /// 句末全角冒号 + 经手人姓名(与 Excel 摘要样例一致;经手人空则为「无」)
  64 + /// </summary>
  65 + public static string WithJsrColon(string sentenceBody, string? jsrDisplay)
  66 + {
  67 + var b = string.IsNullOrWhiteSpace(sentenceBody) ? "无" : sentenceBody.Trim();
  68 + return $"{b}:{Wu(jsrDisplay)}";
  69 + }
  70 + }
  71 +}
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend/BillSummary/WtBillSummaryService.cs 0 → 100644
  1 +using NCC.Dependency;
  2 +using NCC.Extend.Entitys;
  3 +using NCC.Extend.Entitys.Dto.WtCwdj;
  4 +using NCC.Extend.Entitys.Dto.WtSfk;
  5 +using NCC.Extend.Entitys.Dto.WtXsckd;
  6 +using NCC.Extend.Entitys.Dto.WtYskzjjs;
  7 +using NCC.System.Entitys.Permission;
  8 +using SqlSugar;
  9 +using System;
  10 +using System.Collections.Generic;
  11 +using System.Linq;
  12 +using System.Threading.Tasks;
  13 +using System.Collections.Concurrent;
  14 +
  15 +namespace NCC.Extend.BillSummary
  16 +{
  17 + /// <summary>
  18 + /// 统一业务摘要生成:按单据类型拼装可读文案,供列表/详情/弹窗等多处复用;后续可扩展财务单 wt_cwdj 等。
  19 + /// </summary>
  20 + public class WtBillSummaryService : ITransient
  21 + {
  22 + private readonly SqlSugarScope _db;
  23 +
  24 + /// <summary>
  25 + /// 初始化摘要服务
  26 + /// </summary>
  27 + public WtBillSummaryService(ISqlSugarRepository<WtXsckdEntity> wtXsckdRepository)
  28 + {
  29 + _db = wtXsckdRepository.Context;
  30 + }
  31 +
  32 + /// <summary>
  33 + /// 为 wt_xsckd 列表行批量填充摘要(依赖列表已完成的 kh/jsr/仓库等展示字段)
  34 + /// </summary>
  35 + /// <param name="items">列表行</param>
  36 + public async Task EnrichWtXsckdListOutputsAsync(List<WtXsckdListOutput> items)
  37 + {
  38 + if (items == null || items.Count == 0) return;
  39 + var billIds = items.Select(x => x.id).Where(id => !string.IsNullOrEmpty(id)).Select(id => id.Trim()).Distinct().ToList();
  40 + if (billIds.Count == 0) return;
  41 +
  42 + var mxRows = await _db.Queryable<WtXsckdMxEntity>()
  43 + .Where(m => billIds.Contains(m.Djbh))
  44 + .OrderBy(m => m.Djbh)
  45 + .OrderBy(m => m.Id)
  46 + .Select(m => new { m.Djbh, m.Spmc })
  47 + .ToListAsync();
  48 +
  49 + var spByBill = mxRows
  50 + .Where(x => !string.IsNullOrWhiteSpace(x.Djbh))
  51 + .GroupBy(x => x.Djbh!.Trim(), StringComparer.Ordinal)
  52 + .ToDictionary(g => g.Key, g => g.Select(r => r.Spmc).ToList(), StringComparer.Ordinal);
  53 +
  54 + foreach (var row in items)
  55 + {
  56 + var id = row.id?.Trim();
  57 + if (string.IsNullOrEmpty(id))
  58 + {
  59 + row.zy = "无";
  60 + continue;
  61 + }
  62 + spByBill.TryGetValue(id, out var spmcs);
  63 + row.zy = BuildWtXsckdZy(row.djlx, row.kh, row.hysjh, row.jsr, row.gys, row.cjck, row.rkck, spmcs);
  64 + }
  65 + }
  66 +
  67 + /// <summary>
  68 + /// 根据详情输出(含明细)生成摘要
  69 + /// </summary>
  70 + /// <param name="output">详情 DTO</param>
  71 + /// <returns>摘要文本</returns>
  72 + public string BuildWtXsckdZyFromInfo(WtXsckdInfoOutput output)
  73 + {
  74 + if (output == null) return "无";
  75 + var spmcs = output.wtXsckdMxList?
  76 + .Select(m => m.spmc)
  77 + .ToList();
  78 + return BuildWtXsckdZy(output.djlx, output.kh, output.hysjh, output.jsr, output.gys, output.cjck, output.rkck, spmcs);
  79 + }
  80 +
  81 + /// <summary>
  82 + /// 按 wt_xsckd 单据类型拼装摘要(供列表/详情及其它模块直接调用)
  83 + /// </summary>
  84 + /// <param name="djlx">单据类型</param>
  85 + /// <param name="khDisplay">往来/会员展示名</param>
  86 + /// <param name="hysjh">会员手机</param>
  87 + /// <param name="jsrDisplay">经手人展示名</param>
  88 + /// <param name="gysDisplay">供应商展示名</param>
  89 + /// <param name="cjckDisplay">出库仓库展示</param>
  90 + /// <param name="rkckDisplay">入库仓库展示</param>
  91 + /// <param name="spmcs">明细商品名称列表</param>
  92 + public static string BuildWtXsckdZy(
  93 + string? djlx,
  94 + string? khDisplay,
  95 + string? hysjh,
  96 + string? jsrDisplay,
  97 + string? gysDisplay,
  98 + string? cjckDisplay,
  99 + string? rkckDisplay,
  100 + IList<string?>? spmcs)
  101 + {
  102 + var lx = (djlx ?? string.Empty).Trim();
  103 + var kh = WtBillSummaryFormat.Wu(khDisplay);
  104 + var gys = WtBillSummaryFormat.Wu(gysDisplay);
  105 + var cjck = WtBillSummaryFormat.Wu(cjckDisplay);
  106 + var rkck = WtBillSummaryFormat.Wu(rkckDisplay);
  107 + var sjh = string.IsNullOrWhiteSpace(hysjh) ? "" : hysjh.Trim();
  108 + var goods = WtBillSummaryFormat.GoodsDigest(spmcs);
  109 +
  110 + // 自然语句 + 全角【】;销售/预售退货与出库类句末带经手人(全角:+姓名)
  111 + if (lx.Contains("销售退货") || lx.Contains("预售退货"))
  112 + {
  113 + var tag = lx.Contains("预售") ? "预售退货" : "销售退货";
  114 + return WtBillSummaryFormat.WithJsrColon($"{WtBillSummaryFormat.Bracket(khDisplay)}{tag}{goods}", jsrDisplay);
  115 + }
  116 +
  117 + if (lx.Contains("委托代销发货"))
  118 + {
  119 + var to = string.IsNullOrEmpty(sjh) ? kh : $"{kh} {sjh}".Trim();
  120 + return WtBillSummaryFormat.WithJsrColon($"委托{goods}等给{WtBillSummaryFormat.Bracket(to)}", jsrDisplay);
  121 + }
  122 +
  123 + if (lx.Contains("委托代销退货"))
  124 + return WtBillSummaryFormat.WithJsrColon($"委托代销退货{goods}", jsrDisplay);
  125 +
  126 + if (lx.Contains("委托代销结算"))
  127 + return WtBillSummaryFormat.WithJsrColon($"委托代销结算{goods}", jsrDisplay);
  128 +
  129 + // 同价/变价调拨单、调拨入库:必须先于 Contains("调拨"),否则「同价调拨单」会先命中泛化分支导致口径与 Excel/业务不一致
  130 + if (lx.Contains("同价调拨单") || lx.Contains("变价调拨单") || lx.Contains("调拨入库"))
  131 + {
  132 + var dest = rkck != "无" ? rkck : cjck;
  133 + return WtBillSummaryFormat.WithJsrColon($"调拨入库{goods}等货到{WtBillSummaryFormat.Bracket(dest)}", jsrDisplay);
  134 + }
  135 +
  136 + if (lx.Contains("调拨"))
  137 + {
  138 + var dest = rkck != "无" ? rkck : cjck;
  139 + return WtBillSummaryFormat.WithJsrColon($"调拨{goods}等货到{WtBillSummaryFormat.Bracket(dest)}", jsrDisplay);
  140 + }
  141 +
  142 + if (lx.Contains("采购入库"))
  143 + return WtBillSummaryFormat.WithJsrColon($"从{WtBillSummaryFormat.Bracket(gys)}购进{goods}等", jsrDisplay);
  144 +
  145 + if (lx.Contains("采购退货"))
  146 + return WtBillSummaryFormat.WithJsrColon($"向{WtBillSummaryFormat.Bracket(gys)}采购退货{goods}等", jsrDisplay);
  147 +
  148 + if (lx.Contains("销售出库") || lx.Contains("预售出库"))
  149 + {
  150 + // 口径:【经手人】销售/预售出库【商品】:会员姓名(有手机)或往来称呼;不再把会员名放在句首括号内
  151 + var tag = lx.Contains("预售") ? "预售出库" : "销售出库";
  152 + var head = WtBillSummaryFormat.Bracket(jsrDisplay);
  153 + var body = $"{head}{tag}{goods}";
  154 + string tail;
  155 + if (!string.IsNullOrWhiteSpace(sjh))
  156 + tail = $"会员{kh}";
  157 + else if (kh != "无" && kh != "门店散客")
  158 + tail = kh;
  159 + else
  160 + tail = "无";
  161 + return $"{body}:{tail}";
  162 + }
  163 +
  164 + if (string.IsNullOrEmpty(lx))
  165 + return WtBillSummaryFormat.WithJsrColon($"其他{goods}", jsrDisplay);
  166 +
  167 + return WtBillSummaryFormat.WithJsrColon($"{WtBillSummaryFormat.Bracket(lx)}{goods}", jsrDisplay);
  168 + }
  169 +
  170 + /// <summary>
  171 + /// 按 wt_xsckd 主键从库中拼装与列表/详情一致的摘要文本(供 wt_djzy 写入)
  172 + /// </summary>
  173 + /// <param name="billId">单据编号 F_Id</param>
  174 + public async Task<string> ComputeWtXsckdZyByBillIdAsync(string billId)
  175 + {
  176 + if (string.IsNullOrWhiteSpace(billId)) return "无";
  177 + var id = billId.Trim();
  178 + var xsckd = await _db.Queryable<WtXsckdEntity>().FirstAsync(x => x.Id == id);
  179 + if (xsckd == null) return "无";
  180 +
  181 + string khDisplay;
  182 + var hysjh = xsckd.Hysjh ?? "";
  183 + var rawKh = xsckd.Kh?.Trim();
  184 + if (string.IsNullOrWhiteSpace(rawKh))
  185 + {
  186 + khDisplay = "门店散客";
  187 + }
  188 + else
  189 + {
  190 + var hyXmList = await _db.Queryable<WtHyEntity>()
  191 + .Where(h => h.Id == rawKh)
  192 + .Select(h => h.Xm)
  193 + .ToListAsync();
  194 + if (hyXmList.Count > 0)
  195 + {
  196 + var xm = hyXmList[0];
  197 + khDisplay = !string.IsNullOrEmpty(xm) ? xm : "门店散客";
  198 + }
  199 + else
  200 + {
  201 + var dwList = await _db.Queryable<WtWldwEntity>()
  202 + .Where(w => w.Id == rawKh)
  203 + .Select(w => w.Dwmc)
  204 + .ToListAsync();
  205 + var dwmc = dwList.Count > 0 ? dwList[0] : null;
  206 + khDisplay = !string.IsNullOrWhiteSpace(dwmc) ? dwmc.Trim() : "门店散客";
  207 + }
  208 + }
  209 +
  210 + string jsrDisp = "";
  211 + if (!string.IsNullOrWhiteSpace(xsckd.Jsr))
  212 + {
  213 + var jList = await _db.Queryable<UserEntity>()
  214 + .Where(u => u.Id == xsckd.Jsr)
  215 + .Select(u => u.RealName)
  216 + .ToListAsync();
  217 + if (jList.Count > 0)
  218 + jsrDisp = jList[0] ?? "";
  219 + }
  220 +
  221 + string gysDisp = "";
  222 + if (!string.IsNullOrWhiteSpace(xsckd.Gys))
  223 + {
  224 + var gList = await _db.Queryable<WtGysEntity>()
  225 + .Where(g => g.Id == xsckd.Gys)
  226 + .Select(g => g.Gysmc)
  227 + .ToListAsync();
  228 + if (gList.Count > 0)
  229 + gysDisp = gList[0] ?? "";
  230 + }
  231 +
  232 + var (cjckDisp, rkckDisp) = await ResolveMainWarehouseDisplayAsync(xsckd.Cjck, xsckd.Rkck);
  233 +
  234 + var spmcs = await _db.Queryable<WtXsckdMxEntity>()
  235 + .Where(m => m.Djbh == id)
  236 + .OrderBy(m => m.Id)
  237 + .Select(m => m.Spmc)
  238 + .ToListAsync();
  239 +
  240 + return BuildWtXsckdZy(xsckd.Djlx, khDisplay, hysjh, jsrDisp, gysDisp, cjckDisp, rkckDisp, spmcs);
  241 + }
  242 +
  243 + private async Task<(string cjck, string rkck)> ResolveMainWarehouseDisplayAsync(string cjckId, string rkckId)
  244 + {
  245 + var keys = new[] { cjckId, rkckId }
  246 + .Where(k => !string.IsNullOrWhiteSpace(k))
  247 + .Select(k => k.Trim())
  248 + .Distinct()
  249 + .ToList();
  250 + if (keys.Count == 0)
  251 + return ("无", "无");
  252 +
  253 + var nameMap = new Dictionary<string, string>(StringComparer.Ordinal);
  254 + var ckRows = await _db.Queryable<WtCkEntity>().In(c => c.Id, keys).Select(c => new { c.Id, c.Mdmc }).ToListAsync();
  255 + foreach (var r in ckRows)
  256 + {
  257 + if (!string.IsNullOrEmpty(r.Id) && !string.IsNullOrEmpty(r.Mdmc))
  258 + nameMap[r.Id] = r.Mdmc;
  259 + if (!string.IsNullOrEmpty(r.Mdmc) && !nameMap.ContainsKey(r.Mdmc))
  260 + nameMap[r.Mdmc] = r.Mdmc;
  261 + }
  262 +
  263 + var mdRows = await _db.Queryable<WtMdEntity>().In(m => m.Id, keys).Select(m => new { m.Id, m.Mdmc }).ToListAsync();
  264 + foreach (var r in mdRows)
  265 + {
  266 + if (!string.IsNullOrEmpty(r.Id) && !string.IsNullOrEmpty(r.Mdmc))
  267 + nameMap[r.Id] = r.Mdmc;
  268 + if (!string.IsNullOrEmpty(r.Mdmc) && !nameMap.ContainsKey(r.Mdmc))
  269 + nameMap[r.Mdmc] = r.Mdmc;
  270 + }
  271 +
  272 + string MapOne(string raw)
  273 + {
  274 + if (string.IsNullOrWhiteSpace(raw)) return "无";
  275 + var k = raw.Trim();
  276 + return nameMap.TryGetValue(k, out var n) ? n : k;
  277 + }
  278 +
  279 + return (MapOne(cjckId), MapOne(rkckId));
  280 + }
  281 +
  282 + /// <summary>
  283 + /// 按 wt_cwdj 主键拼装摘要(自然语句 + 句末经手人,对齐 Excel 样例)
  284 + /// </summary>
  285 + /// <param name="billId">财务单据 F_Id</param>
  286 + public async Task<string> ComputeWtCwdjZyByBillIdAsync(string billId)
  287 + {
  288 + if (string.IsNullOrWhiteSpace(billId)) return "无";
  289 + var id = billId.Trim();
  290 + var cwdjRows = await _db.Queryable<WtCwdjEntity>().Where(x => x.Id == id).ToListAsync();
  291 + var e = cwdjRows.FirstOrDefault();
  292 + if (e == null) return "无";
  293 +
  294 + var wldwDisp = await ResolveWldwDisplayForDjzyAsync(e.Wldw);
  295 + var jsrDisp = await ResolveJsrDisplayForDjzyAsync(e.Jsr);
  296 + var lx = (e.Djlx ?? string.Empty).Trim();
  297 + var wPart = WtBillSummaryFormat.Bracket(wldwDisp);
  298 + var moneyTxt = WtBillSummaryFormat.Money(e.Fsje);
  299 +
  300 + string body;
  301 + if (lx.Contains("收入"))
  302 + {
  303 + var tag = string.IsNullOrEmpty(lx) ? "其他收入" : lx;
  304 + body = $"【{tag}】等收入共{moneyTxt}元";
  305 + }
  306 + else if (lx.Contains("付款"))
  307 + {
  308 + var acc = WtBillSummaryFormat.Wu(e.Fkzh);
  309 + if (acc == "无") acc = WtBillSummaryFormat.Wu(e.Skzh);
  310 + body = $"{WtBillSummaryFormat.Bracket(acc)}等付款给{wPart}金额{moneyTxt}人民币";
  311 + }
  312 + else if (lx.Contains("收款"))
  313 + {
  314 + var acc = WtBillSummaryFormat.Wu(e.Skzh);
  315 + if (acc == "无") acc = WtBillSummaryFormat.Wu(e.Fkzh);
  316 + body = $"{WtBillSummaryFormat.Bracket(acc)}等收款自{wPart}金额{moneyTxt}人民币";
  317 + }
  318 + else
  319 + {
  320 + var zyPart = string.IsNullOrWhiteSpace(e.Zy) ? "" : e.Zy.Trim();
  321 + var lxShow = string.IsNullOrEmpty(lx) ? "财务单" : lx;
  322 + body = string.IsNullOrEmpty(zyPart)
  323 + ? $"【{lxShow}】金额{moneyTxt}元"
  324 + : $"【{lxShow}】{zyPart} 金额{moneyTxt}元";
  325 + }
  326 +
  327 + return WtBillSummaryFormat.WithJsrColon(body, jsrDisp);
  328 + }
  329 +
  330 + /// <summary>
  331 + /// 按 wt_sfk 主键拼装摘要(自然语句 + 句末经手人,对齐 Excel 样例)
  332 + /// </summary>
  333 + /// <param name="billId">收付款单 F_Id</param>
  334 + public async Task<string> ComputeWtSfkZyByBillIdAsync(string billId)
  335 + {
  336 + if (string.IsNullOrWhiteSpace(billId)) return "无";
  337 + var id = billId.Trim();
  338 + var sfkRows = await _db.Queryable<WtSfkEntity>().Where(x => x.Id == id).ToListAsync();
  339 + var e = sfkRows.FirstOrDefault();
  340 + if (e == null) return "无";
  341 +
  342 + var wldwDisp = await ResolveWldwDisplayForDjzyAsync(e.Wldw);
  343 + var jsrDisp = await ResolveJsrDisplayForDjzyAsync(e.Jsr);
  344 + var lx = (e.Djlx ?? string.Empty).Trim();
  345 + var zh = WtBillSummaryFormat.Wu(string.IsNullOrWhiteSpace(e.Jszh) ? "" : e.Jszh.Trim());
  346 + var wPart = WtBillSummaryFormat.Bracket(wldwDisp);
  347 + var moneyTxt = WtBillSummaryFormat.Money(e.Je);
  348 +
  349 + string body;
  350 + if (lx.Contains("付款") || lx.Contains("付"))
  351 + body = $"{WtBillSummaryFormat.Bracket(zh)}等付款给{wPart}金额{moneyTxt}人民币";
  352 + else if (lx.Contains("收款") || lx.Contains("收"))
  353 + body = $"{WtBillSummaryFormat.Bracket(zh)}等收款自{wPart}金额{moneyTxt}人民币";
  354 + else
  355 + {
  356 + var lxShow = string.IsNullOrEmpty(lx) ? "收付款" : lx.Trim();
  357 + body = $"{WtBillSummaryFormat.Bracket(zh)}等{lxShow}{wPart}金额{moneyTxt}人民币";
  358 + }
  359 +
  360 + if (!string.IsNullOrWhiteSpace(e.Bz))
  361 + body += $" {e.Bz.Trim()}";
  362 +
  363 + return WtBillSummaryFormat.WithJsrColon(body, jsrDisp);
  364 + }
  365 +
  366 + /// <summary>
  367 + /// 按 wt_yskzjjs 主键拼装摘要(自然语句 + 句末经手人;转款单对齐「转款到【账户】等共金额元:经手人」)
  368 + /// </summary>
  369 + /// <param name="billId">应收款增加减少 F_Id</param>
  370 + public async Task<string> ComputeWtYskzjjsZyByBillIdAsync(string billId)
  371 + {
  372 + if (string.IsNullOrWhiteSpace(billId)) return "无";
  373 + var id = billId.Trim();
  374 + var yskRows = await _db.Queryable<WtYskzjjsEntity>().Where(x => x.Id == id).ToListAsync();
  375 + var e = yskRows.FirstOrDefault();
  376 + if (e == null) return "无";
  377 +
  378 + var wldwDisp = await ResolveWldwDisplayForDjzyAsync(e.Wldw);
  379 + var jsrDisp = await ResolveJsrDisplayForDjzyAsync(e.Jsr);
  380 + var lx = (e.Djlx ?? string.Empty).Trim();
  381 +
  382 + if (lx.Contains("转款"))
  383 + {
  384 + var accRaw = e.Skje != 0
  385 + ? (string.IsNullOrWhiteSpace(e.Skzh) ? e.Fkzh : e.Skzh)
  386 + : (string.IsNullOrWhiteSpace(e.Fkzh) ? e.Skzh : e.Fkzh);
  387 + var acc = WtBillSummaryFormat.Wu(string.IsNullOrWhiteSpace(accRaw) ? "" : accRaw.Trim());
  388 + var amt = e.Skje != 0 ? e.Skje : (e.Fkje != 0 ? e.Fkje : 0m);
  389 + return WtBillSummaryFormat.WithJsrColon($"转款到{WtBillSummaryFormat.Bracket(acc)}等共{WtBillSummaryFormat.Money(amt)}元", jsrDisp);
  390 + }
  391 +
  392 + string amtPart;
  393 + if (e.Skje != 0)
  394 + amtPart = $"收款{WtBillSummaryFormat.Money(e.Skje)}元";
  395 + else if (e.Fkje != 0)
  396 + amtPart = $"付款{WtBillSummaryFormat.Money(e.Fkje)}元";
  397 + else
  398 + amtPart = $"金额{WtBillSummaryFormat.Money(0)}元";
  399 +
  400 + var lxShow = string.IsNullOrEmpty(lx) ? "应收款增减" : lx;
  401 + var body = $"{WtBillSummaryFormat.Bracket(wldwDisp)}{lxShow}{amtPart}";
  402 + if (!string.IsNullOrWhiteSpace(e.Hysjh))
  403 + body += $" 手机{WtBillSummaryFormat.Bracket(e.Hysjh.Trim())}";
  404 + if (!string.IsNullOrWhiteSpace(e.Zy))
  405 + body += $" {e.Zy.Trim()}";
  406 +
  407 + return WtBillSummaryFormat.WithJsrColon(body, jsrDisp);
  408 + }
  409 +
  410 + private async Task<string> ResolveWldwDisplayForDjzyAsync(string? rawId)
  411 + {
  412 + if (string.IsNullOrWhiteSpace(rawId))
  413 + return "无";
  414 + var wid = rawId.Trim();
  415 +
  416 + var hyXmList = await _db.Queryable<WtHyEntity>()
  417 + .Where(h => h.Id == wid)
  418 + .Select(h => h.Xm)
  419 + .ToListAsync();
  420 + if (hyXmList.Count > 0 && !string.IsNullOrWhiteSpace(hyXmList[0]))
  421 + return hyXmList[0]!.Trim();
  422 +
  423 + var dwList = await _db.Queryable<WtWldwEntity>()
  424 + .Where(w => w.Id == wid)
  425 + .Select(w => w.Dwmc)
  426 + .ToListAsync();
  427 + if (dwList.Count > 0 && !string.IsNullOrWhiteSpace(dwList[0]))
  428 + return dwList[0]!.Trim();
  429 +
  430 + var gysList = await _db.Queryable<WtGysEntity>()
  431 + .Where(g => g.Id == wid)
  432 + .Select(g => g.Gysmc)
  433 + .ToListAsync();
  434 + if (gysList.Count > 0 && !string.IsNullOrWhiteSpace(gysList[0]))
  435 + return gysList[0]!.Trim();
  436 +
  437 + return wid;
  438 + }
  439 +
  440 + private async Task<string> ResolveJsrDisplayForDjzyAsync(string? jsrId)
  441 + {
  442 + if (string.IsNullOrWhiteSpace(jsrId))
  443 + return string.Empty;
  444 + var jList = await _db.Queryable<UserEntity>()
  445 + .Where(u => u.Id == jsrId.Trim())
  446 + .Select(u => u.RealName)
  447 + .ToListAsync();
  448 + return jList.Count > 0 ? (jList[0] ?? string.Empty) : string.Empty;
  449 + }
  450 +
  451 + /// <summary>
  452 + /// 为财务单据列表行填充业务摘要(与 wt_djzy / 摘要概览规则一致)
  453 + /// </summary>
  454 + public async Task EnrichWtCwdjListBillZyAsync(List<WtCwdjListOutput> items)
  455 + {
  456 + if (items == null || items.Count == 0) return;
  457 + var bag = new ConcurrentBag<(WtCwdjListOutput row, string text)>();
  458 + await Task.WhenAll(items.Select(async row =>
  459 + {
  460 + if (string.IsNullOrWhiteSpace(row.id))
  461 + {
  462 + bag.Add((row, "无"));
  463 + return;
  464 + }
  465 + var t = await ComputeWtCwdjZyByBillIdAsync(row.id.Trim());
  466 + bag.Add((row, t));
  467 + }));
  468 + foreach (var (row, text) in bag)
  469 + row.billZy = text;
  470 + }
  471 +
  472 + /// <summary>
  473 + /// 为收付款单列表行填充业务摘要
  474 + /// </summary>
  475 + public async Task EnrichWtSfkListBillZyAsync(List<WtSfkListOutput> items)
  476 + {
  477 + if (items == null || items.Count == 0) return;
  478 + var bag = new ConcurrentBag<(WtSfkListOutput row, string text)>();
  479 + await Task.WhenAll(items.Select(async row =>
  480 + {
  481 + if (string.IsNullOrWhiteSpace(row.id))
  482 + {
  483 + bag.Add((row, "无"));
  484 + return;
  485 + }
  486 + var t = await ComputeWtSfkZyByBillIdAsync(row.id.Trim());
  487 + bag.Add((row, t));
  488 + }));
  489 + foreach (var (row, text) in bag)
  490 + row.billZy = text;
  491 + }
  492 +
  493 + /// <summary>
  494 + /// 为应收款增加减少列表行填充业务摘要
  495 + /// </summary>
  496 + public async Task EnrichWtYskzjjsListBillZyAsync(List<WtYskzjjsListOutput> items)
  497 + {
  498 + if (items == null || items.Count == 0) return;
  499 + var bag = new ConcurrentBag<(WtYskzjjsListOutput row, string text)>();
  500 + await Task.WhenAll(items.Select(async row =>
  501 + {
  502 + if (string.IsNullOrWhiteSpace(row.id))
  503 + {
  504 + bag.Add((row, "无"));
  505 + return;
  506 + }
  507 + var t = await ComputeWtYskzjjsZyByBillIdAsync(row.id.Trim());
  508 + bag.Add((row, t));
  509 + }));
  510 + foreach (var (row, text) in bag)
  511 + row.billZy = text;
  512 + }
  513 + }
  514 +}
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend/WtCwdjService.cs
... ... @@ -22,6 +22,8 @@ using NCC.Common.Model.NPOI;
22 22 using NCC.Common.Configuration;
23 23 using NCC.DataEncryption;
24 24 using NCC.ClayObject;
  25 +using NCC.Extend.WtDjzy;
  26 +using NCC.Extend.BillSummary;
25 27  
26 28 namespace NCC.Extend.WtCwdj
27 29 {
... ... @@ -36,6 +38,8 @@ namespace NCC.Extend.WtCwdj
36 38 private readonly ISqlSugarRepository<WtCwdjmxEntity> _wtCwdjmxRepository;
37 39 private readonly SqlSugarScope _db;
38 40 private readonly IUserManager _userManager;
  41 + private readonly WtDjzyService _wtDjzyService;
  42 + private readonly WtBillSummaryService _billSummaryService;
39 43  
40 44 /// <summary>
41 45 /// 初始化一个<see cref="WtCwdjService"/>类型的新实例
... ... @@ -43,12 +47,16 @@ namespace NCC.Extend.WtCwdj
43 47 public WtCwdjService(
44 48 ISqlSugarRepository<WtCwdjEntity> wtCwdjRepository,
45 49 ISqlSugarRepository<WtCwdjmxEntity> wtCwdjmxRepository,
46   - IUserManager userManager)
  50 + IUserManager userManager,
  51 + WtDjzyService wtDjzyService,
  52 + WtBillSummaryService billSummaryService)
47 53 {
48 54 _wtCwdjRepository = wtCwdjRepository;
49 55 _db = _wtCwdjRepository.Context;
50 56 _wtCwdjmxRepository = wtCwdjmxRepository;
51 57 _userManager = userManager;
  58 + _wtDjzyService = wtDjzyService;
  59 + _billSummaryService = billSummaryService;
52 60 }
53 61  
54 62 /// <summary>
... ... @@ -64,6 +72,7 @@ namespace NCC.Extend.WtCwdj
64 72  
65 73 var wtCwdjmxList = await _db.Queryable<WtCwdjmxEntity>().Where(w => w.Djbh == entity.Id).ToListAsync();
66 74 output.wtCwdjmxList = wtCwdjmxList.Adapt<List<WtCwdjmxInfoOutput>>();
  75 + output.billZy = await _billSummaryService.ComputeWtCwdjZyByBillIdAsync(entity.Id);
67 76 return output;
68 77 }
69 78  
... ... @@ -102,6 +111,8 @@ namespace NCC.Extend.WtCwdj
102 111 djzt = it.Djzt,
103 112 shzt = it.Djzt,
104 113 }).MergeTable().OrderBy(sidx+" "+input.sort).ToPagedListAsync(input.currentPage, input.pageSize);
  114 + var cwdjPageRows = data.list?.ToList() ?? new List<WtCwdjListOutput>();
  115 + await _billSummaryService.EnrichWtCwdjListBillZyAsync(cwdjPageRows);
105 116 return PageResult<WtCwdjListOutput>.SqlSugarPageResult(data);
106 117 }
107 118  
... ... @@ -173,6 +184,8 @@ namespace NCC.Extend.WtCwdj
173 184 await _db.Insertable(wtCwdjmxEntityList).ExecuteCommandAsync();
174 185 }
175 186  
  187 + await _wtDjzyService.UpsertFromCwdjAsync(newEntity.Id);
  188 +
176 189 //关闭事务
177 190 _db.CommitTran();
178 191 // 返回新创建的实体信息
... ... @@ -235,6 +248,7 @@ namespace NCC.Extend.WtCwdj
235 248 djzt = it.Djzt,
236 249 shzt = it.Djzt,
237 250 }).MergeTable().OrderBy(sidx+" "+input.sort).ToListAsync();
  251 + await _billSummaryService.EnrichWtCwdjListBillZyAsync(data);
238 252 return data;
239 253 }
240 254  
... ... @@ -299,6 +313,7 @@ namespace NCC.Extend.WtCwdj
299 313 {
300 314 //开启事务
301 315 _db.BeginTran();
  316 + await _wtDjzyService.DeleteByCwdjAsync(ids);
302 317 //批量删除财务单据
303 318 await _db.Deleteable<WtCwdjEntity>().In(d => d.Id,ids).ExecuteCommandAsync();
304 319  
... ... @@ -347,6 +362,8 @@ namespace NCC.Extend.WtCwdj
347 362 }
348 363 await _db.Insertable(wtCwdjmxEntityList).ExecuteCommandAsync();
349 364 }
  365 +
  366 + await _wtDjzyService.UpsertFromCwdjAsync(id);
350 367  
351 368 //关闭事务
352 369 _db.CommitTran();
... ... @@ -372,6 +389,8 @@ namespace NCC.Extend.WtCwdj
372 389 {
373 390 //开启事务
374 391 _db.BeginTran();
  392 +
  393 + await _wtDjzyService.DeleteByCwdjAsync(id);
375 394  
376 395 //删除财务单据记录
377 396 await _db.Deleteable<WtCwdjEntity>().Where(d => d.Id == id).ExecuteCommandAsync();
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend/WtDjzyService.cs 0 → 100644
  1 +using NCC.Common.Extension;
  2 +using NCC.JsonSerialization;
  3 +using NCC.Common.Filter;
  4 +using NCC.Dependency;
  5 +using NCC.DynamicApiController;
  6 +using Microsoft.AspNetCore.Mvc;
  7 +using NCC.Extend.BillSummary;
  8 +using NCC.Extend.Entitys;
  9 +using NCC.Extend.Entitys.Dto.WtDjzy;
  10 +using SqlSugar;
  11 +using System;
  12 +using System.Collections.Generic;
  13 +using System.Linq;
  14 +using System.Threading.Tasks;
  15 +using Yitter.IdGenerator;
  16 +
  17 +namespace NCC.Extend.WtDjzy
  18 +{
  19 + /// <summary>
  20 + /// 业务单据摘要汇总表:各模块写入 <c>wt_djzy</c>;本服务提供分页查询及按来源批量同步(销售出库、财务单、收付款、应收款增减等)。
  21 + /// </summary>
  22 + [ApiDescriptionSettings(Tag = "Extend", Name = "WtDjzy", Order = 200)]
  23 + [Route("api/Extend/[controller]")]
  24 + public class WtDjzyService : IDynamicApiController, ITransient
  25 + {
  26 + /// <summary>
  27 + /// 来源:销售出库主数据在 <c>wt_xsckd</c>,摘要行 <c>djbh</c> 与 <c>F_Id</c> 一致。
  28 + /// </summary>
  29 + public const string LyXsckd = "xsckd";
  30 +
  31 + /// <summary>来源:<c>wt_cwdj</c> 财务单据</summary>
  32 + public const string LyCwdj = "cwdj";
  33 +
  34 + /// <summary>来源:<c>wt_sfk</c> 收付款单</summary>
  35 + public const string LySfk = "sfk";
  36 +
  37 + /// <summary>来源:<c>wt_yskzjjs</c> 应收款增加减少</summary>
  38 + public const string LyYskzjjs = "yskzjjs";
  39 +
  40 + private readonly SqlSugarScope _db;
  41 + private readonly WtBillSummaryService _billSummary;
  42 + private static bool _tableEnsured;
  43 +
  44 + /// <summary>
  45 + /// 初始化摘要汇总服务
  46 + /// </summary>
  47 + public WtDjzyService(
  48 + ISqlSugarRepository<WtDjzyEntity> djzyRepository,
  49 + WtBillSummaryService billSummary)
  50 + {
  51 + _db = djzyRepository.Context;
  52 + _billSummary = billSummary;
  53 + }
  54 +
  55 + /// <summary>
  56 + /// 分页查询摘要汇总表
  57 + /// </summary>
  58 + /// <param name="input">分页与筛选条件</param>
  59 + /// <returns>分页列表</returns>
  60 + /// <response code="200">成功</response>
  61 + [HttpGet("")]
  62 + public async Task<dynamic> GetList([FromQuery] WtDjzyListQueryInput input)
  63 + {
  64 + EnsureWtDjzyTable();
  65 + var sidx = string.IsNullOrEmpty(input.sidx) ? "djrq" : input.sidx;
  66 + List<string> queryDjrq = input.djrq != null ? input.djrq.Split(',').ToObeject<List<string>>() : null;
  67 + DateTime? startDjrq = queryDjrq != null ? Ext.GetDateTime(queryDjrq.First()) : null;
  68 + DateTime? endDjrq = queryDjrq != null ? Ext.GetDateTime(queryDjrq.Last()) : null;
  69 +
  70 + var data = await _db.Queryable<WtDjzyEntity>()
  71 + .WhereIF(!string.IsNullOrEmpty(input.djbh), z => z.Djbh.Contains(input.djbh))
  72 + .WhereIF(!string.IsNullOrEmpty(input.ly), z => z.Ly == input.ly)
  73 + .WhereIF(!string.IsNullOrEmpty(input.djlx), z => z.Djlx.Contains(input.djlx))
  74 + .WhereIF(!string.IsNullOrEmpty(input.keyword), z => z.Zynr.Contains(input.keyword))
  75 + .WhereIF(queryDjrq != null, z => z.Djrq >= new DateTime(startDjrq.ToDate().Year, startDjrq.ToDate().Month, startDjrq.ToDate().Day, 0, 0, 0))
  76 + .WhereIF(queryDjrq != null, z => z.Djrq <= new DateTime(endDjrq.ToDate().Year, endDjrq.ToDate().Month, endDjrq.ToDate().Day, 23, 59, 59))
  77 + .Select(z => new WtDjzyListOutput
  78 + {
  79 + id = z.Id,
  80 + djbh = z.Djbh,
  81 + ly = z.Ly,
  82 + djlx = z.Djlx,
  83 + djrq = z.Djrq,
  84 + zynr = z.Zynr
  85 + })
  86 + .MergeTable()
  87 + .OrderBy(sidx + " " + input.sort)
  88 + .ToPagedListAsync(input.currentPage, input.pageSize);
  89 +
  90 + return PageResult<WtDjzyListOutput>.SqlSugarPageResult(data);
  91 + }
  92 +
  93 + /// <summary>
  94 + /// 将 <c>wt_xsckd</c> 批量同步到 <c>wt_djzy</c>(含销售/采购/委托及同价调拨单、变价调拨单等调拨入库类;新建/编辑由 WtXsckd 自动维护)
  95 + /// </summary>
  96 + /// <param name="input">可选单据日期起止;不传则同步全部主表</param>
  97 + /// <returns>已处理单据条数</returns>
  98 + /// <response code="200">成功</response>
  99 + [HttpPost("Actions/SyncFromXsckd")]
  100 + public async Task<dynamic> SyncFromXsckd([FromBody] WtDjzySyncInput input)
  101 + {
  102 + input ??= new WtDjzySyncInput();
  103 + EnsureWtDjzyTable();
  104 + var start = ParseDjrqBound(input.djrqStart, true);
  105 + var end = ParseDjrqBound(input.djrqEnd, false);
  106 +
  107 + const int batch = 300;
  108 + var synced = 0;
  109 + var skip = 0;
  110 + while (true)
  111 + {
  112 + var ids = await _db.Queryable<WtXsckdEntity>()
  113 + .WhereIF(start.HasValue, x => x.Djrq >= start)
  114 + .WhereIF(end.HasValue, x => x.Djrq <= end)
  115 + .OrderBy(x => x.Djrq)
  116 + .OrderBy(x => x.Id)
  117 + .Select(x => x.Id)
  118 + .Skip(skip)
  119 + .Take(batch)
  120 + .ToListAsync();
  121 + if (ids == null || ids.Count == 0)
  122 + break;
  123 + foreach (var bid in ids)
  124 + {
  125 + if (!string.IsNullOrWhiteSpace(bid))
  126 + await UpsertFromXsckdAsync(bid.Trim());
  127 + }
  128 + synced += ids.Count;
  129 + if (ids.Count < batch)
  130 + break;
  131 + skip += batch;
  132 + }
  133 +
  134 + return new { syncedCount = synced, message = $"已同步 {synced} 条 wt_xsckd 到摘要表" };
  135 + }
  136 +
  137 + /// <summary>
  138 + /// 将 <c>wt_cwdj</c> 批量同步到 <c>wt_djzy</c>(按录单日期 <c>ldrq</c> 筛选)
  139 + /// </summary>
  140 + /// <param name="input">可选日期起止;不传则同步全部</param>
  141 + /// <returns>已处理条数</returns>
  142 + /// <response code="200">成功</response>
  143 + [HttpPost("Actions/SyncFromCwdj")]
  144 + public async Task<dynamic> SyncFromCwdj([FromBody] WtDjzySyncInput input)
  145 + {
  146 + input ??= new WtDjzySyncInput();
  147 + EnsureWtDjzyTable();
  148 + var start = ParseDjrqBound(input.djrqStart, true);
  149 + var end = ParseDjrqBound(input.djrqEnd, false);
  150 + const int batch = 300;
  151 + var synced = 0;
  152 + var skip = 0;
  153 + while (true)
  154 + {
  155 + var ids = await _db.Queryable<WtCwdjEntity>()
  156 + .WhereIF(start.HasValue, x => x.Ldrq >= start)
  157 + .WhereIF(end.HasValue, x => x.Ldrq <= end)
  158 + .OrderBy(x => x.Ldrq)
  159 + .OrderBy(x => x.Id)
  160 + .Select(x => x.Id)
  161 + .Skip(skip)
  162 + .Take(batch)
  163 + .ToListAsync();
  164 + if (ids == null || ids.Count == 0)
  165 + break;
  166 + foreach (var bid in ids)
  167 + {
  168 + if (!string.IsNullOrWhiteSpace(bid))
  169 + await UpsertFromCwdjAsync(bid.Trim());
  170 + }
  171 + synced += ids.Count;
  172 + if (ids.Count < batch)
  173 + break;
  174 + skip += batch;
  175 + }
  176 +
  177 + return new { syncedCount = synced, message = $"已同步 {synced} 条 wt_cwdj 到摘要表" };
  178 + }
  179 +
  180 + /// <summary>
  181 + /// 将 <c>wt_sfk</c> 批量同步到 <c>wt_djzy</c>
  182 + /// </summary>
  183 + /// <param name="input">可选单据日期起止</param>
  184 + /// <returns>已处理条数</returns>
  185 + /// <response code="200">成功</response>
  186 + [HttpPost("Actions/SyncFromSfk")]
  187 + public async Task<dynamic> SyncFromSfk([FromBody] WtDjzySyncInput input)
  188 + {
  189 + input ??= new WtDjzySyncInput();
  190 + EnsureWtDjzyTable();
  191 + var start = ParseDjrqBound(input.djrqStart, true);
  192 + var end = ParseDjrqBound(input.djrqEnd, false);
  193 + const int batch = 300;
  194 + var synced = 0;
  195 + var skip = 0;
  196 + while (true)
  197 + {
  198 + var ids = await _db.Queryable<WtSfkEntity>()
  199 + .WhereIF(start.HasValue, x => x.Djrq >= start)
  200 + .WhereIF(end.HasValue, x => x.Djrq <= end)
  201 + .OrderBy(x => x.Djrq)
  202 + .OrderBy(x => x.Id)
  203 + .Select(x => x.Id)
  204 + .Skip(skip)
  205 + .Take(batch)
  206 + .ToListAsync();
  207 + if (ids == null || ids.Count == 0)
  208 + break;
  209 + foreach (var bid in ids)
  210 + {
  211 + if (!string.IsNullOrWhiteSpace(bid))
  212 + await UpsertFromSfkAsync(bid.Trim());
  213 + }
  214 + synced += ids.Count;
  215 + if (ids.Count < batch)
  216 + break;
  217 + skip += batch;
  218 + }
  219 +
  220 + return new { syncedCount = synced, message = $"已同步 {synced} 条 wt_sfk 到摘要表" };
  221 + }
  222 +
  223 + /// <summary>
  224 + /// 将 <c>wt_yskzjjs</c> 批量同步到 <c>wt_djzy</c>
  225 + /// </summary>
  226 + /// <param name="input">可选单据日期起止</param>
  227 + /// <returns>已处理条数</returns>
  228 + /// <response code="200">成功</response>
  229 + [HttpPost("Actions/SyncFromYskzjjs")]
  230 + public async Task<dynamic> SyncFromYskzjjs([FromBody] WtDjzySyncInput input)
  231 + {
  232 + input ??= new WtDjzySyncInput();
  233 + EnsureWtDjzyTable();
  234 + var start = ParseDjrqBound(input.djrqStart, true);
  235 + var end = ParseDjrqBound(input.djrqEnd, false);
  236 + const int batch = 300;
  237 + var synced = 0;
  238 + var skip = 0;
  239 + while (true)
  240 + {
  241 + var ids = await _db.Queryable<WtYskzjjsEntity>()
  242 + .WhereIF(start.HasValue, x => x.Djrq >= start)
  243 + .WhereIF(end.HasValue, x => x.Djrq <= end)
  244 + .OrderBy(x => x.Djrq)
  245 + .OrderBy(x => x.Id)
  246 + .Select(x => x.Id)
  247 + .Skip(skip)
  248 + .Take(batch)
  249 + .ToListAsync();
  250 + if (ids == null || ids.Count == 0)
  251 + break;
  252 + foreach (var bid in ids)
  253 + {
  254 + if (!string.IsNullOrWhiteSpace(bid))
  255 + await UpsertFromYskzjjsAsync(bid.Trim());
  256 + }
  257 + synced += ids.Count;
  258 + if (ids.Count < batch)
  259 + break;
  260 + skip += batch;
  261 + }
  262 +
  263 + return new { syncedCount = synced, message = $"已同步 {synced} 条 wt_yskzjjs 到摘要表" };
  264 + }
  265 +
  266 + /// <summary>
  267 + /// 按销售出库单主键写入或更新摘要行(与事务同事务调用)
  268 + /// </summary>
  269 + /// <param name="billId">wt_xsckd.F_Id</param>
  270 + [NonAction]
  271 + public async Task UpsertFromXsckdAsync(string billId)
  272 + {
  273 + if (string.IsNullOrWhiteSpace(billId)) return;
  274 + var id = billId.Trim();
  275 + EnsureWtDjzyTable();
  276 + var heads = await _db.Queryable<WtXsckdEntity>().Where(x => x.Id == id).ToListAsync();
  277 + var head = heads.FirstOrDefault();
  278 + if (head == null) return;
  279 +
  280 + var zynr = await _billSummary.ComputeWtXsckdZyByBillIdAsync(id);
  281 + var now = DateTime.Now;
  282 + var rows = await _db.Queryable<WtDjzyEntity>()
  283 + .Where(x => x.Djbh == id && x.Ly == LyXsckd)
  284 + .ToListAsync();
  285 + var existing = rows.FirstOrDefault();
  286 + if (existing != null)
  287 + {
  288 + existing.Djlx = head.Djlx;
  289 + existing.Djrq = head.Djrq;
  290 + existing.Zynr = zynr;
  291 + existing.LastModifyTime = now;
  292 + await _db.Updateable(existing).ExecuteCommandAsync();
  293 + }
  294 + else
  295 + {
  296 + var e = new WtDjzyEntity
  297 + {
  298 + Id = YitIdHelper.NextId().ToString(),
  299 + Djbh = id,
  300 + Ly = LyXsckd,
  301 + Djlx = head.Djlx,
  302 + Djrq = head.Djrq,
  303 + Zynr = zynr,
  304 + CreatorTime = now,
  305 + LastModifyTime = now
  306 + };
  307 + await _db.Insertable(e).ExecuteCommandAsync();
  308 + }
  309 + }
  310 +
  311 + /// <summary>
  312 + /// 删除销售出库单对应的摘要行
  313 + /// </summary>
  314 + /// <param name="djbh">单据编号</param>
  315 + [NonAction]
  316 + public async Task DeleteByXsckdAsync(string djbh)
  317 + {
  318 + if (string.IsNullOrWhiteSpace(djbh)) return;
  319 + EnsureWtDjzyTable();
  320 + await _db.Deleteable<WtDjzyEntity>()
  321 + .Where(x => x.Djbh == djbh.Trim() && x.Ly == LyXsckd)
  322 + .ExecuteCommandAsync();
  323 + }
  324 +
  325 + /// <summary>
  326 + /// 批量删除销售出库单对应的摘要行
  327 + /// </summary>
  328 + /// <param name="djbhs">单据编号列表</param>
  329 + [NonAction]
  330 + public async Task DeleteByXsckdAsync(IReadOnlyCollection<string> djbhs)
  331 + {
  332 + if (djbhs == null || djbhs.Count == 0) return;
  333 + EnsureWtDjzyTable();
  334 + var ids = djbhs.Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).Distinct().ToList();
  335 + if (ids.Count == 0) return;
  336 + await _db.Deleteable<WtDjzyEntity>()
  337 + .Where(x => ids.Contains(x.Djbh) && x.Ly == LyXsckd)
  338 + .ExecuteCommandAsync();
  339 + }
  340 +
  341 + /// <summary>
  342 + /// 按财务单据主键写入或更新摘要行(与 wt_cwdj 事务同事务调用)
  343 + /// </summary>
  344 + /// <param name="billId">wt_cwdj.F_Id</param>
  345 + [NonAction]
  346 + public async Task UpsertFromCwdjAsync(string billId)
  347 + {
  348 + if (string.IsNullOrWhiteSpace(billId)) return;
  349 + var id = billId.Trim();
  350 + EnsureWtDjzyTable();
  351 + var head = (await _db.Queryable<WtCwdjEntity>().Where(x => x.Id == id).ToListAsync()).FirstOrDefault();
  352 + if (head == null) return;
  353 +
  354 + var zynr = await _billSummary.ComputeWtCwdjZyByBillIdAsync(id);
  355 + var now = DateTime.Now;
  356 + var rows = await _db.Queryable<WtDjzyEntity>()
  357 + .Where(x => x.Djbh == id && x.Ly == LyCwdj)
  358 + .ToListAsync();
  359 + var existing = rows.FirstOrDefault();
  360 + var djrq = head.Ldrq ?? now;
  361 + if (existing != null)
  362 + {
  363 + existing.Djlx = head.Djlx;
  364 + existing.Djrq = djrq;
  365 + existing.Zynr = zynr;
  366 + existing.LastModifyTime = now;
  367 + await _db.Updateable(existing).ExecuteCommandAsync();
  368 + }
  369 + else
  370 + {
  371 + var e = new WtDjzyEntity
  372 + {
  373 + Id = YitIdHelper.NextId().ToString(),
  374 + Djbh = id,
  375 + Ly = LyCwdj,
  376 + Djlx = head.Djlx,
  377 + Djrq = djrq,
  378 + Zynr = zynr,
  379 + CreatorTime = now,
  380 + LastModifyTime = now
  381 + };
  382 + await _db.Insertable(e).ExecuteCommandAsync();
  383 + }
  384 + }
  385 +
  386 + /// <summary>
  387 + /// 删除财务单据对应的摘要行
  388 + /// </summary>
  389 + [NonAction]
  390 + public async Task DeleteByCwdjAsync(string djbh)
  391 + {
  392 + if (string.IsNullOrWhiteSpace(djbh)) return;
  393 + EnsureWtDjzyTable();
  394 + await _db.Deleteable<WtDjzyEntity>()
  395 + .Where(x => x.Djbh == djbh.Trim() && x.Ly == LyCwdj)
  396 + .ExecuteCommandAsync();
  397 + }
  398 +
  399 + /// <summary>
  400 + /// 批量删除财务单据对应的摘要行
  401 + /// </summary>
  402 + [NonAction]
  403 + public async Task DeleteByCwdjAsync(IReadOnlyCollection<string> djbhs)
  404 + {
  405 + if (djbhs == null || djbhs.Count == 0) return;
  406 + EnsureWtDjzyTable();
  407 + var ids = djbhs.Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).Distinct().ToList();
  408 + if (ids.Count == 0) return;
  409 + await _db.Deleteable<WtDjzyEntity>()
  410 + .Where(x => ids.Contains(x.Djbh) && x.Ly == LyCwdj)
  411 + .ExecuteCommandAsync();
  412 + }
  413 +
  414 + /// <summary>
  415 + /// 按收付款单主键写入或更新摘要行
  416 + /// </summary>
  417 + [NonAction]
  418 + public async Task UpsertFromSfkAsync(string billId)
  419 + {
  420 + if (string.IsNullOrWhiteSpace(billId)) return;
  421 + var id = billId.Trim();
  422 + EnsureWtDjzyTable();
  423 + var head = (await _db.Queryable<WtSfkEntity>().Where(x => x.Id == id).ToListAsync()).FirstOrDefault();
  424 + if (head == null) return;
  425 +
  426 + var zynr = await _billSummary.ComputeWtSfkZyByBillIdAsync(id);
  427 + var now = DateTime.Now;
  428 + var rows = await _db.Queryable<WtDjzyEntity>()
  429 + .Where(x => x.Djbh == id && x.Ly == LySfk)
  430 + .ToListAsync();
  431 + var existing = rows.FirstOrDefault();
  432 + var djrq = head.Djrq ?? now;
  433 + if (existing != null)
  434 + {
  435 + existing.Djlx = head.Djlx;
  436 + existing.Djrq = djrq;
  437 + existing.Zynr = zynr;
  438 + existing.LastModifyTime = now;
  439 + await _db.Updateable(existing).ExecuteCommandAsync();
  440 + }
  441 + else
  442 + {
  443 + var e = new WtDjzyEntity
  444 + {
  445 + Id = YitIdHelper.NextId().ToString(),
  446 + Djbh = id,
  447 + Ly = LySfk,
  448 + Djlx = head.Djlx,
  449 + Djrq = djrq,
  450 + Zynr = zynr,
  451 + CreatorTime = now,
  452 + LastModifyTime = now
  453 + };
  454 + await _db.Insertable(e).ExecuteCommandAsync();
  455 + }
  456 + }
  457 +
  458 + /// <summary>
  459 + /// 删除收付款单对应的摘要行
  460 + /// </summary>
  461 + [NonAction]
  462 + public async Task DeleteBySfkAsync(string djbh)
  463 + {
  464 + if (string.IsNullOrWhiteSpace(djbh)) return;
  465 + EnsureWtDjzyTable();
  466 + await _db.Deleteable<WtDjzyEntity>()
  467 + .Where(x => x.Djbh == djbh.Trim() && x.Ly == LySfk)
  468 + .ExecuteCommandAsync();
  469 + }
  470 +
  471 + /// <summary>
  472 + /// 批量删除收付款单对应的摘要行
  473 + /// </summary>
  474 + [NonAction]
  475 + public async Task DeleteBySfkAsync(IReadOnlyCollection<string> djbhs)
  476 + {
  477 + if (djbhs == null || djbhs.Count == 0) return;
  478 + EnsureWtDjzyTable();
  479 + var ids = djbhs.Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).Distinct().ToList();
  480 + if (ids.Count == 0) return;
  481 + await _db.Deleteable<WtDjzyEntity>()
  482 + .Where(x => ids.Contains(x.Djbh) && x.Ly == LySfk)
  483 + .ExecuteCommandAsync();
  484 + }
  485 +
  486 + /// <summary>
  487 + /// 按应收款增加减少主键写入或更新摘要行
  488 + /// </summary>
  489 + [NonAction]
  490 + public async Task UpsertFromYskzjjsAsync(string billId)
  491 + {
  492 + if (string.IsNullOrWhiteSpace(billId)) return;
  493 + var id = billId.Trim();
  494 + EnsureWtDjzyTable();
  495 + var head = (await _db.Queryable<WtYskzjjsEntity>().Where(x => x.Id == id).ToListAsync()).FirstOrDefault();
  496 + if (head == null) return;
  497 +
  498 + var zynr = await _billSummary.ComputeWtYskzjjsZyByBillIdAsync(id);
  499 + var now = DateTime.Now;
  500 + var rows = await _db.Queryable<WtDjzyEntity>()
  501 + .Where(x => x.Djbh == id && x.Ly == LyYskzjjs)
  502 + .ToListAsync();
  503 + var existing = rows.FirstOrDefault();
  504 + var djrq = head.Djrq ?? now;
  505 + if (existing != null)
  506 + {
  507 + existing.Djlx = head.Djlx;
  508 + existing.Djrq = djrq;
  509 + existing.Zynr = zynr;
  510 + existing.LastModifyTime = now;
  511 + await _db.Updateable(existing).ExecuteCommandAsync();
  512 + }
  513 + else
  514 + {
  515 + var e = new WtDjzyEntity
  516 + {
  517 + Id = YitIdHelper.NextId().ToString(),
  518 + Djbh = id,
  519 + Ly = LyYskzjjs,
  520 + Djlx = head.Djlx,
  521 + Djrq = djrq,
  522 + Zynr = zynr,
  523 + CreatorTime = now,
  524 + LastModifyTime = now
  525 + };
  526 + await _db.Insertable(e).ExecuteCommandAsync();
  527 + }
  528 + }
  529 +
  530 + /// <summary>
  531 + /// 删除应收款增加减少对应的摘要行
  532 + /// </summary>
  533 + [NonAction]
  534 + public async Task DeleteByYskzjjsAsync(string djbh)
  535 + {
  536 + if (string.IsNullOrWhiteSpace(djbh)) return;
  537 + EnsureWtDjzyTable();
  538 + await _db.Deleteable<WtDjzyEntity>()
  539 + .Where(x => x.Djbh == djbh.Trim() && x.Ly == LyYskzjjs)
  540 + .ExecuteCommandAsync();
  541 + }
  542 +
  543 + /// <summary>
  544 + /// 批量删除应收款增加减少对应的摘要行
  545 + /// </summary>
  546 + [NonAction]
  547 + public async Task DeleteByYskzjjsAsync(IReadOnlyCollection<string> djbhs)
  548 + {
  549 + if (djbhs == null || djbhs.Count == 0) return;
  550 + EnsureWtDjzyTable();
  551 + var ids = djbhs.Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).Distinct().ToList();
  552 + if (ids.Count == 0) return;
  553 + await _db.Deleteable<WtDjzyEntity>()
  554 + .Where(x => ids.Contains(x.Djbh) && x.Ly == LyYskzjjs)
  555 + .ExecuteCommandAsync();
  556 + }
  557 +
  558 + private void EnsureWtDjzyTable()
  559 + {
  560 + if (_tableEnsured) return;
  561 + lock (typeof(WtDjzyService))
  562 + {
  563 + if (_tableEnsured) return;
  564 + try
  565 + {
  566 + if (!_db.DbMaintenance.IsAnyTable("wt_djzy"))
  567 + {
  568 + _db.Ado.ExecuteCommand(@"
  569 +CREATE TABLE `wt_djzy` (
  570 + `F_Id` varchar(50) NOT NULL COMMENT '主键',
  571 + `djbh` varchar(50) NOT NULL COMMENT '业务单据编号',
  572 + `ly` varchar(32) NOT NULL COMMENT '来源模块',
  573 + `djlx` varchar(100) NULL COMMENT '单据类型',
  574 + `djrq` datetime NULL COMMENT '单据日期',
  575 + `zynr` text NULL COMMENT '摘要全文',
  576 + `F_CreatorTime` datetime NULL COMMENT '创建时间',
  577 + `F_LastModifyTime` datetime NULL COMMENT '最后修改时间',
  578 + PRIMARY KEY (`F_Id`),
  579 + UNIQUE KEY `uk_djbh_ly` (`djbh`,`ly`)
  580 +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='业务单据摘要汇总';");
  581 + }
  582 + }
  583 + catch (Exception ex)
  584 + {
  585 + Console.WriteLine($"EnsureWtDjzyTable: {ex.Message}");
  586 + }
  587 +
  588 + _tableEnsured = true;
  589 + }
  590 + }
  591 +
  592 + /// <summary>
  593 + /// 解析前端日期:支持 yyyy-MM-dd 或毫秒时间戳字符串;起始归 0 点,结束归 23:59:59
  594 + /// </summary>
  595 + private static DateTime? ParseDjrqBound(string raw, bool isStart)
  596 + {
  597 + if (string.IsNullOrWhiteSpace(raw)) return null;
  598 + var s = raw.Trim();
  599 + if (DateTime.TryParse(s, out var d))
  600 + {
  601 + return isStart
  602 + ? new DateTime(d.Year, d.Month, d.Day, 0, 0, 0)
  603 + : new DateTime(d.Year, d.Month, d.Day, 23, 59, 59);
  604 + }
  605 + if (long.TryParse(s, out var ms))
  606 + {
  607 + var local = DateTimeOffset.FromUnixTimeMilliseconds(ms).LocalDateTime;
  608 + return isStart
  609 + ? new DateTime(local.Year, local.Month, local.Day, 0, 0, 0)
  610 + : new DateTime(local.Year, local.Month, local.Day, 23, 59, 59);
  611 + }
  612 + return null;
  613 + }
  614 + }
  615 +}
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend/WtSfkService.cs
1   -using NCC.Common.Core.Manager;
  1 +using NCC.Common.Core.Manager;
2 2 using NCC.Common.Enum;
3 3 using NCC.Common.Extension;
4 4 using NCC.Common.Filter;
... ... @@ -22,6 +22,8 @@ using NCC.Common.Model.NPOI;
22 22 using NCC.Common.Configuration;
23 23 using NCC.DataEncryption;
24 24 using NCC.ClayObject;
  25 +using NCC.Extend.WtDjzy;
  26 +using NCC.Extend.BillSummary;
25 27  
26 28 namespace NCC.Extend.WtSfk
27 29 {
... ... @@ -35,17 +37,23 @@ namespace NCC.Extend.WtSfk
35 37 private readonly ISqlSugarRepository<WtSfkEntity> _wtSfkRepository;
36 38 private readonly SqlSugarScope _db;
37 39 private readonly IUserManager _userManager;
  40 + private readonly WtDjzyService _wtDjzyService;
  41 + private readonly WtBillSummaryService _billSummaryService;
38 42  
39 43 /// <summary>
40 44 /// 初始化一个<see cref="WtSfkService"/>类型的新实例
41 45 /// </summary>
42 46 public WtSfkService(
43 47 ISqlSugarRepository<WtSfkEntity> wtSfkRepository,
44   - IUserManager userManager)
  48 + IUserManager userManager,
  49 + WtDjzyService wtDjzyService,
  50 + WtBillSummaryService billSummaryService)
45 51 {
46 52 _wtSfkRepository = wtSfkRepository;
47 53 _db = _wtSfkRepository.Context;
48 54 _userManager = userManager;
  55 + _wtDjzyService = wtDjzyService;
  56 + _billSummaryService = billSummaryService;
49 57 }
50 58  
51 59 /// <summary>
... ... @@ -58,6 +66,7 @@ namespace NCC.Extend.WtSfk
58 66 {
59 67 var entity = await _db.Queryable<WtSfkEntity>().FirstAsync(p => p.Id == id);
60 68 var output = entity.Adapt<WtSfkInfoOutput>();
  69 + output.billZy = await _billSummaryService.ComputeWtSfkZyByBillIdAsync(entity.Id);
61 70 return output;
62 71 }
63 72  
... ... @@ -100,6 +109,8 @@ namespace NCC.Extend.WtSfk
100 109 bz=it.Bz,
101 110 djlx=it.Djlx,
102 111 }).MergeTable().OrderBy(sidx+" "+input.sort).ToPagedListAsync(input.currentPage, input.pageSize);
  112 + var sfkPageRows = data.list?.ToList() ?? new List<WtSfkListOutput>();
  113 + await _billSummaryService.EnrichWtSfkListBillZyAsync(sfkPageRows);
103 114 return PageResult<WtSfkListOutput>.SqlSugarPageResult(data);
104 115 }
105 116  
... ... @@ -114,8 +125,19 @@ namespace NCC.Extend.WtSfk
114 125 var userInfo = await _userManager.GetUserInfo();
115 126 var entity = input.Adapt<WtSfkEntity>();
116 127 entity.Id = YitIdHelper.NextId().ToString();
117   - var isOk = await _db.Insertable(entity).IgnoreColumns(ignoreNullColumn: true).ExecuteCommandAsync();
118   - if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1000);
  128 + try
  129 + {
  130 + _db.BeginTran();
  131 + var isOk = await _db.Insertable(entity).IgnoreColumns(ignoreNullColumn: true).ExecuteCommandAsync();
  132 + if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1000);
  133 + await _wtDjzyService.UpsertFromSfkAsync(entity.Id);
  134 + _db.CommitTran();
  135 + }
  136 + catch (Exception)
  137 + {
  138 + _db.RollbackTran();
  139 + throw;
  140 + }
119 141 }
120 142  
121 143 /// <summary>
... ... @@ -157,6 +179,7 @@ namespace NCC.Extend.WtSfk
157 179 bz=it.Bz,
158 180 djlx=it.Djlx,
159 181 }).MergeTable().OrderBy(sidx+" "+input.sort).ToListAsync();
  182 + await _billSummaryService.EnrichWtSfkListBillZyAsync(data);
160 183 return data;
161 184 }
162 185  
... ... @@ -221,6 +244,7 @@ namespace NCC.Extend.WtSfk
221 244 {
222 245 //开启事务
223 246 _db.BeginTran();
  247 + await _wtDjzyService.DeleteBySfkAsync(ids);
224 248 //批量删除收付款单
225 249 await _db.Deleteable<WtSfkEntity>().In(d => d.Id,ids).ExecuteCommandAsync();
226 250 //关闭事务
... ... @@ -245,8 +269,19 @@ namespace NCC.Extend.WtSfk
245 269 public async Task Update(string id, [FromBody] WtSfkUpInput input)
246 270 {
247 271 var entity = input.Adapt<WtSfkEntity>();
248   - var isOk = await _db.Updateable(entity).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
249   - if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1001);
  272 + try
  273 + {
  274 + _db.BeginTran();
  275 + var isOk = await _db.Updateable(entity).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
  276 + if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1001);
  277 + await _wtDjzyService.UpsertFromSfkAsync(id);
  278 + _db.CommitTran();
  279 + }
  280 + catch (Exception)
  281 + {
  282 + _db.RollbackTran();
  283 + throw;
  284 + }
250 285 }
251 286  
252 287 /// <summary>
... ... @@ -258,8 +293,19 @@ namespace NCC.Extend.WtSfk
258 293 {
259 294 var entity = await _db.Queryable<WtSfkEntity>().FirstAsync(p => p.Id == id);
260 295 _ = entity ?? throw NCCException.Oh(ErrorCode.COM1005);
261   - var isOk = await _db.Deleteable<WtSfkEntity>().Where(d => d.Id == id).ExecuteCommandAsync();
262   - if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1002);
  296 + try
  297 + {
  298 + _db.BeginTran();
  299 + await _wtDjzyService.DeleteBySfkAsync(id);
  300 + var isOk = await _db.Deleteable<WtSfkEntity>().Where(d => d.Id == id).ExecuteCommandAsync();
  301 + if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1002);
  302 + _db.CommitTran();
  303 + }
  304 + catch (Exception)
  305 + {
  306 + _db.RollbackTran();
  307 + throw;
  308 + }
263 309 }
264 310 }
265 311 }
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend/WtSkfkChannelStatService.cs 0 → 100644
  1 +using NCC.Dependency;
  2 +using NCC.DynamicApiController;
  3 +using NCC.FriendlyException;
  4 +using Microsoft.AspNetCore.Mvc;
  5 +using Newtonsoft.Json.Linq;
  6 +using SqlSugar;
  7 +using System;
  8 +using System.Collections.Generic;
  9 +using System.Globalization;
  10 +using System.Linq;
  11 +using System.Threading.Tasks;
  12 +using NCC.Extend.Entitys;
  13 +using NCC.Extend.Entitys.Dto.WtSkfkChannelStat;
  14 +using NCC.System.Entitys.Permission;
  15 +using NCC.System.Entitys.System;
  16 +
  17 +namespace NCC.Extend.WtSkfkChannelStat
  18 +{
  19 + /// <summary>
  20 + /// 财务收付款渠道统计:按收付方向分别二维汇总,并提供流水明细。
  21 + /// <para>收款侧(销售/预售出库等):入账账户= <c>skzh</c> 字典;方式维度= <c>skmx.skfs</c>、<c>fkmx.lx</c>(微信、余额等)。</para>
  22 + /// <para>付款侧(采购入库、退货退款等):出账账户= <c>skzh</c>(采购为付款账户);方式维度=同上列或「其他」。</para>
  23 + /// <para>数据来源:<c>wt_xsckd</c>(已审核)、<c>wt_sfk</c>(已审)、<c>wt_cwdj</c>(已审核)。</para>
  24 + /// </summary>
  25 + [ApiDescriptionSettings(Tag = "Extend", Name = "WtSkfkChannelStat", Order = 200)]
  26 + [Route("api/Extend/[controller]")]
  27 + public class WtSkfkChannelStatService : IDynamicApiController, ITransient
  28 + {
  29 + private readonly ISqlSugarRepository<WtXsckdEntity> _xsckdRepository;
  30 + private readonly SqlSugarScope _db;
  31 +
  32 + /// <summary>
  33 + /// 初始化服务
  34 + /// </summary>
  35 + public WtSkfkChannelStatService(ISqlSugarRepository<WtXsckdEntity> xsckdRepository)
  36 + {
  37 + _xsckdRepository = xsckdRepository;
  38 + _db = _xsckdRepository.Context;
  39 + }
  40 +
  41 + /// <summary>
  42 + /// 汇总:按收付方向拆分。收款侧仅含 Fx=收款 的流水;付款侧仅含 Fx=付款 的流水,避免采购付款计入「入账」。
  43 + /// </summary>
  44 + /// <param name="input">开始/结束日期</param>
  45 + /// <returns>
  46 + /// skAccountList/skMethodList=收款侧按账户/按方式;fkAccountList/fkMethodList=付款侧按账户/按方式;
  47 + /// skSideTotal/fkSideTotal=各侧金额合计。
  48 + /// </returns>
  49 + /// <response code="200">成功</response>
  50 + /// <response code="400">日期无效</response>
  51 + [HttpGet("Actions/GetChannelSummary")]
  52 + public async Task<dynamic> GetChannelSummary([FromQuery] WtSkfkChannelStatQueryInput input)
  53 + {
  54 + input ??= new WtSkfkChannelStatQueryInput();
  55 + if (!TryParseRange(input, out var start, out var endEx, out var err))
  56 + throw NCCException.Oh(err);
  57 +
  58 + var lines = await BuildLedgerLinesAsync(start, endEx);
  59 + var skLines = lines.Where(x => x.FxCode == "sk").ToList();
  60 + var fkLines = lines.Where(x => x.FxCode == "fk").ToList();
  61 +
  62 + var skAccountList = GroupChannelRows(skLines, x => x.SkzhMc);
  63 + var skMethodList = GroupChannelRows(skLines, x => x.Fffs);
  64 + var fkAccountList = GroupChannelRows(fkLines, x => x.SkzhMc);
  65 + var fkMethodList = GroupChannelRows(fkLines, x => x.Fffs);
  66 +
  67 + var skSideTotal = skLines.Sum(x => x.Je);
  68 + var fkSideTotal = fkLines.Sum(x => x.Je);
  69 + return new
  70 + {
  71 + skAccountList,
  72 + skMethodList,
  73 + fkAccountList,
  74 + fkMethodList,
  75 + skAccountTotal = skAccountList.Sum(x => x.je),
  76 + skMethodTotal = skMethodList.Sum(x => x.je),
  77 + fkAccountTotal = fkAccountList.Sum(x => x.je),
  78 + fkMethodTotal = fkMethodList.Sum(x => x.je),
  79 + skSideTotal,
  80 + fkSideTotal
  81 + };
  82 + }
  83 +
  84 + private static List<WtSkfkChannelStatChannelRowOutput> GroupChannelRows(
  85 + List<InternalLine> src,
  86 + Func<InternalLine, string> keySelector)
  87 + {
  88 + return src
  89 + .GroupBy(x => keySelector(x) ?? "", StringComparer.Ordinal)
  90 + .Select(g => new WtSkfkChannelStatChannelRowOutput { qd = string.IsNullOrEmpty(g.Key) ? "无" : g.Key, je = g.Sum(x => x.Je) })
  91 + .OrderByDescending(x => x.je)
  92 + .ToList();
  93 + }
  94 +
  95 + /// <summary>
  96 + /// 收付款渠道流水分页(含销售/预售退货退款按 skmx/fkmx 拆行)
  97 + /// </summary>
  98 + /// <param name="input">日期区间、方向/渠道/单据类型筛选、分页</param>
  99 + /// <returns>流水列表与 total</returns>
  100 + /// <response code="200">成功</response>
  101 + /// <response code="400">日期无效</response>
  102 + [HttpGet("Actions/GetChannelLedger")]
  103 + public async Task<dynamic> GetChannelLedger([FromQuery] WtSkfkChannelStatQueryInput input)
  104 + {
  105 + input ??= new WtSkfkChannelStatQueryInput();
  106 + if (!TryParseRange(input, out var start, out var endEx, out var err))
  107 + throw NCCException.Oh(err);
  108 +
  109 + var page = input.currentPage.GetValueOrDefault(1);
  110 + if (page < 1) page = 1;
  111 + var size = input.pageSize.GetValueOrDefault(100);
  112 + if (size < 1) size = 100;
  113 + if (size > 500) size = 500;
  114 +
  115 + var lines = await BuildLedgerLinesAsync(start, endEx);
  116 + IEnumerable<InternalLine> q = lines;
  117 +
  118 + if (!string.IsNullOrWhiteSpace(input.fx))
  119 + {
  120 + var f = input.fx.Trim().ToLowerInvariant();
  121 + if (f == "sk" || f == "收款")
  122 + q = q.Where(x => x.FxCode == "sk");
  123 + else if (f == "fk" || f == "付款")
  124 + q = q.Where(x => x.FxCode == "fk");
  125 + }
  126 +
  127 + if (!string.IsNullOrWhiteSpace(input.qd))
  128 + {
  129 + var k = input.qd.Trim();
  130 + q = q.Where(x =>
  131 + (x.Fffs != null && x.Fffs.Contains(k, StringComparison.Ordinal)) ||
  132 + (x.SkzhMc != null && x.SkzhMc.Contains(k, StringComparison.Ordinal)));
  133 + }
  134 +
  135 + if (!string.IsNullOrWhiteSpace(input.djlx))
  136 + {
  137 + var k = input.djlx.Trim();
  138 + q = q.Where(x => x.Djlx != null && x.Djlx.Contains(k, StringComparison.Ordinal));
  139 + }
  140 +
  141 + var ordered = q.OrderBy(x => x.Dt).ThenBy(x => x.Djbh).ThenBy(x => x.Fffs).ToList();
  142 + var total = ordered.Count;
  143 + var slice = ordered.Skip((page - 1) * size).Take(size).ToList();
  144 +
  145 + var userIds = slice.Where(x => !string.IsNullOrEmpty(x.JsrId)).Select(x => x.JsrId).Distinct().ToList();
  146 + var userMap = await BuildUserNameMapAsync(userIds);
  147 +
  148 + var list = slice.Select(x => new WtSkfkChannelStatLedgerRowOutput
  149 + {
  150 + djrq = x.Dt.ToString("yyyy-MM-dd"),
  151 + djbh = x.Djbh ?? "",
  152 + djlx = string.IsNullOrEmpty(x.Djlx) ? "无" : x.Djlx,
  153 + fx = x.FxCode == "sk" ? "收款" : "付款",
  154 + fffs = string.IsNullOrEmpty(x.Fffs) ? "无" : x.Fffs,
  155 + skzhMc = string.IsNullOrEmpty(x.SkzhMc) ? "无" : x.SkzhMc,
  156 + je = x.Je,
  157 + ly = x.Ly ?? "无",
  158 + ycddh = string.IsNullOrEmpty(x.Ycddh) ? "无" : x.Ycddh,
  159 + zy = string.IsNullOrWhiteSpace(x.Zy) ? "无" : x.Zy.Trim(),
  160 + jsr = userMap.TryGetValue(x.JsrId ?? "", out var nm) && !string.IsNullOrEmpty(nm) ? nm : "无"
  161 + }).ToList();
  162 +
  163 + return new { list, total };
  164 + }
  165 +
  166 + private sealed class InternalLine
  167 + {
  168 + public DateTime Dt { get; set; }
  169 + public string Djbh { get; set; }
  170 + public string Djlx { get; set; }
  171 + public string FxCode { get; set; }
  172 + /// <summary>买方付款方式(微信、余额等)</summary>
  173 + public string Fffs { get; set; }
  174 + /// <summary>收款账户入账端(字典名)</summary>
  175 + public string SkzhMc { get; set; }
  176 + public decimal Je { get; set; }
  177 + public string Ly { get; set; }
  178 + public string Ycddh { get; set; }
  179 + public string Zy { get; set; }
  180 + public string JsrId { get; set; }
  181 + }
  182 +
  183 + private static bool TryParseRange(WtSkfkChannelStatQueryInput input, out DateTime start, out DateTime endExclusive,
  184 + out string err)
  185 + {
  186 + start = default;
  187 + endExclusive = default;
  188 + err = null;
  189 + var y = DateTime.Now.Year;
  190 + var s = string.IsNullOrWhiteSpace(input.startDate) ? $"{y}-01-01" : input.startDate.Trim();
  191 + var e = string.IsNullOrWhiteSpace(input.endDate) ? $"{y}-12-31" : input.endDate.Trim();
  192 + if (!DateTime.TryParse(s, out start))
  193 + {
  194 + err = "开始日期无效";
  195 + return false;
  196 + }
  197 +
  198 + if (!DateTime.TryParse(e, out var endDay))
  199 + {
  200 + err = "结束日期无效";
  201 + return false;
  202 + }
  203 +
  204 + if (endDay.Date < start.Date)
  205 + {
  206 + err = "结束日期不能早于开始日期";
  207 + return false;
  208 + }
  209 +
  210 + start = start.Date;
  211 + endExclusive = endDay.Date.AddDays(1);
  212 + return true;
  213 + }
  214 +
  215 + private async Task<List<InternalLine>> BuildLedgerLinesAsync(DateTime start, DateTime endExclusive)
  216 + {
  217 + var dictIds = new HashSet<string>(StringComparer.Ordinal);
  218 + var lines = new List<InternalLine>();
  219 +
  220 + var xsRows = await _db.Queryable<WtXsckdEntity>()
  221 + .Where(x => x.Djrq >= start && x.Djrq < endExclusive && x.Djzt == "已审核")
  222 + .ToListAsync();
  223 +
  224 + foreach (var x in xsRows)
  225 + {
  226 + if (!TryClassifyXsckd(x.Djlx, out var fxCode))
  227 + continue;
  228 + CollectDictIdsForXsckd(x, dictIds);
  229 + }
  230 +
  231 + var sfkRows = await _db.Queryable<WtSfkEntity>()
  232 + .Where(x => x.Djrq >= start && x.Djrq < endExclusive
  233 + && x.Shr != null && x.Shr != "")
  234 + .ToListAsync();
  235 + foreach (var s in sfkRows)
  236 + {
  237 + if (!string.IsNullOrEmpty(s.Jszh))
  238 + dictIds.Add(s.Jszh.Trim());
  239 + }
  240 +
  241 + var cwdjRows = await _db.Queryable<WtCwdjEntity>()
  242 + .Where(x => x.Ldrq >= start && x.Ldrq < endExclusive && x.Djzt == "已审核")
  243 + .ToListAsync();
  244 + foreach (var c in cwdjRows)
  245 + {
  246 + if (!string.IsNullOrEmpty(c.Fkzh))
  247 + dictIds.Add(c.Fkzh.Trim());
  248 + if (!string.IsNullOrEmpty(c.Skzh))
  249 + dictIds.Add(c.Skzh.Trim());
  250 + }
  251 +
  252 + var dictMap = await BuildDictionaryMapAsync(dictIds);
  253 +
  254 + foreach (var x in xsRows)
  255 + {
  256 + if (!TryClassifyXsckd(x.Djlx, out var fxCode))
  257 + continue;
  258 + AppendXsckdChannelLines(x, fxCode, dictMap, lines);
  259 + }
  260 +
  261 + foreach (var s in sfkRows)
  262 + {
  263 + if (!TryClassifySfk(s.Djlx, out var fxCode) || s.Je == 0)
  264 + continue;
  265 + var zhMc = ResolveDictLabel(s.Jszh, dictMap, "结算账户");
  266 + var fffs = string.IsNullOrEmpty(s.Djlx) ? "收付款单" : s.Djlx.Trim();
  267 + lines.Add(new InternalLine
  268 + {
  269 + Dt = s.Djrq ?? DateTime.MinValue,
  270 + Djbh = s.Id,
  271 + Djlx = string.IsNullOrEmpty(s.Djlx) ? "收付款单" : s.Djlx,
  272 + FxCode = fxCode,
  273 + Fffs = fffs,
  274 + SkzhMc = zhMc,
  275 + Je = Math.Abs(s.Je),
  276 + Ly = "收付款单",
  277 + Ycddh = null,
  278 + Zy = s.Bz,
  279 + JsrId = s.Jsr
  280 + });
  281 + }
  282 +
  283 + foreach (var c in cwdjRows)
  284 + {
  285 + if (!ClassifyCwdj(c, out var isPay))
  286 + continue;
  287 + var zhMc = isPay
  288 + ? ResolveDictLabel(c.Fkzh, dictMap, "付款账户")
  289 + : ResolveDictLabel(c.Skzh, dictMap, "收款账户");
  290 + var fxCode = isPay ? "fk" : "sk";
  291 + var zyShort = string.IsNullOrWhiteSpace(c.Zy) ? "" : c.Zy.Trim();
  292 + var djlxShort = string.IsNullOrWhiteSpace(c.Djlx) ? "" : c.Djlx.Trim();
  293 + var fffs = !string.IsNullOrEmpty(djlxShort)
  294 + ? djlxShort
  295 + : (!string.IsNullOrEmpty(zyShort) ? TruncateForFffs(zyShort) : (isPay ? "财务付款" : "财务收款"));
  296 + lines.Add(new InternalLine
  297 + {
  298 + Dt = c.Ldrq ?? DateTime.MinValue,
  299 + Djbh = c.Id,
  300 + Djlx = string.IsNullOrEmpty(c.Djlx) ? "财务单据" : c.Djlx,
  301 + FxCode = fxCode,
  302 + Fffs = fffs,
  303 + SkzhMc = zhMc,
  304 + Je = Math.Abs(c.Fsje),
  305 + Ly = "财务单据",
  306 + Ycddh = null,
  307 + Zy = c.Zy,
  308 + JsrId = c.Jsr
  309 + });
  310 + }
  311 +
  312 + return lines;
  313 + }
  314 +
  315 + private static void CollectDictIdsForXsckd(WtXsckdEntity x, HashSet<string> dictIds)
  316 + {
  317 + if (!string.IsNullOrEmpty(x.Skzh))
  318 + dictIds.Add(x.Skzh.Trim());
  319 + foreach (var (_, skzh, _) in ParseSkmxRows(x.Skmx))
  320 + {
  321 + if (!string.IsNullOrEmpty(skzh))
  322 + dictIds.Add(skzh.Trim());
  323 + }
  324 + }
  325 +
  326 + private static bool TryClassifyXsckd(string djlx, out string fxCode)
  327 + {
  328 + fxCode = null;
  329 + if (string.IsNullOrEmpty(djlx))
  330 + return false;
  331 + if (djlx == "销售出库单" || djlx == "预售出库单" || djlx == "委托代销发货单")
  332 + {
  333 + fxCode = "sk";
  334 + return true;
  335 + }
  336 +
  337 + if (djlx == "销售退货单" || djlx == "预售退货单" || djlx == "委托代销退货单")
  338 + {
  339 + fxCode = "fk";
  340 + return true;
  341 + }
  342 +
  343 + if (djlx == "采购入库单" || djlx == "委托代销结算单")
  344 + {
  345 + fxCode = "fk";
  346 + return true;
  347 + }
  348 +
  349 + if (djlx == "采购退货单")
  350 + {
  351 + fxCode = "sk";
  352 + return true;
  353 + }
  354 +
  355 + return false;
  356 + }
  357 +
  358 + private static bool TryClassifySfk(string djlx, out string fxCode)
  359 + {
  360 + fxCode = null;
  361 + if (string.IsNullOrEmpty(djlx))
  362 + return false;
  363 + if (djlx.Contains("收款"))
  364 + {
  365 + fxCode = "sk";
  366 + return true;
  367 + }
  368 +
  369 + if (djlx.Contains("付款"))
  370 + {
  371 + fxCode = "fk";
  372 + return true;
  373 + }
  374 +
  375 + return false;
  376 + }
  377 +
  378 + private static bool ClassifyCwdj(WtCwdjEntity d, out bool isPay)
  379 + {
  380 + isPay = false;
  381 + var t = (d.Djlx ?? "") + (d.Zy ?? "");
  382 + if (t.Contains("付"))
  383 + {
  384 + isPay = true;
  385 + return true;
  386 + }
  387 +
  388 + if (t.Contains("收"))
  389 + {
  390 + isPay = false;
  391 + return true;
  392 + }
  393 +
  394 + return false;
  395 + }
  396 +
  397 + private void AppendXsckdChannelLines(WtXsckdEntity x, string fxCode, Dictionary<string, string> dictMap,
  398 + List<InternalLine> lines)
  399 + {
  400 + var dt = x.Djrq ?? DateTime.MinValue;
  401 + var skmxRows = ParseSkmxRows(x.Skmx);
  402 + var fkmxRows = ParseFkmxRows(x.Fkmx);
  403 + var any = false;
  404 + var mainSkzh = string.IsNullOrEmpty(x.Skzh) ? null : x.Skzh.Trim();
  405 + var accountFallback = fxCode == "sk" ? "未指定收款账户" : "未指定付款账户";
  406 +
  407 + foreach (var (skfs, skzh, je) in skmxRows)
  408 + {
  409 + if (je == 0)
  410 + continue;
  411 + any = true;
  412 + var fffs = !string.IsNullOrWhiteSpace(skfs) ? skfs.Trim() : "其他";
  413 + var skzhId = !string.IsNullOrWhiteSpace(skzh) ? skzh.Trim() : mainSkzh;
  414 + var skzhMc = ResolveDictLabel(skzhId, dictMap, accountFallback);
  415 + lines.Add(new InternalLine
  416 + {
  417 + Dt = dt,
  418 + Djbh = x.Id,
  419 + Djlx = x.Djlx,
  420 + FxCode = fxCode,
  421 + Fffs = fffs,
  422 + SkzhMc = skzhMc,
  423 + Je = Math.Abs(je),
  424 + Ly = "进销存单据",
  425 + Ycddh = string.IsNullOrEmpty(x.Ycddh) ? null : x.Ycddh,
  426 + Zy = x.Bz,
  427 + JsrId = x.Jsr
  428 + });
  429 + }
  430 +
  431 + foreach (var (lx, je) in fkmxRows)
  432 + {
  433 + if (je == 0)
  434 + continue;
  435 + any = true;
  436 + var fffs = string.IsNullOrWhiteSpace(lx) ? "会员扣款" : lx.Trim();
  437 + var skzhMc = ResolveDictLabel(mainSkzh, dictMap, accountFallback);
  438 + lines.Add(new InternalLine
  439 + {
  440 + Dt = dt,
  441 + Djbh = x.Id,
  442 + Djlx = x.Djlx,
  443 + FxCode = fxCode,
  444 + Fffs = fffs,
  445 + SkzhMc = skzhMc,
  446 + Je = Math.Abs(je),
  447 + Ly = "进销存单据",
  448 + Ycddh = string.IsNullOrEmpty(x.Ycddh) ? null : x.Ycddh,
  449 + Zy = x.Bz,
  450 + JsrId = x.Jsr
  451 + });
  452 + }
  453 +
  454 + if (any || x.Skje == 0)
  455 + return;
  456 +
  457 + lines.Add(new InternalLine
  458 + {
  459 + Dt = dt,
  460 + Djbh = x.Id,
  461 + Djlx = x.Djlx,
  462 + FxCode = fxCode,
  463 + Fffs = "其他",
  464 + SkzhMc = ResolveDictLabel(mainSkzh, dictMap, accountFallback),
  465 + Je = Math.Abs(x.Skje),
  466 + Ly = "进销存单据",
  467 + Ycddh = string.IsNullOrEmpty(x.Ycddh) ? null : x.Ycddh,
  468 + Zy = x.Bz,
  469 + JsrId = x.Jsr
  470 + });
  471 + }
  472 +
  473 + private static string TruncateForFffs(string zy, int maxLen = 32)
  474 + {
  475 + if (string.IsNullOrEmpty(zy) || zy.Length <= maxLen)
  476 + return zy;
  477 + return zy.Substring(0, maxLen) + "…";
  478 + }
  479 +
  480 + private static List<(string skfs, string skzh, decimal je)> ParseSkmxRows(string skmx)
  481 + {
  482 + var list = new List<(string, string, decimal)>();
  483 + if (string.IsNullOrWhiteSpace(skmx))
  484 + return list;
  485 + try
  486 + {
  487 + var arr = JArray.Parse(skmx.Trim());
  488 + foreach (var tok in arr)
  489 + {
  490 + if (tok is not JObject o)
  491 + continue;
  492 + var skfs = o.Value<string>("skfs") ?? o.Value<string>("Skfs");
  493 + var skzh = o.Value<string>("skzh") ?? o.Value<string>("Skzh");
  494 + var je = ParseDecimalToken(o["skje"] ?? o["Skje"]);
  495 + list.Add((skfs, skzh, je));
  496 + }
  497 + }
  498 + catch
  499 + {
  500 + // ignore
  501 + }
  502 +
  503 + return list;
  504 + }
  505 +
  506 + private static List<(string lx, decimal je)> ParseFkmxRows(string fkmx)
  507 + {
  508 + var list = new List<(string, decimal)>();
  509 + if (string.IsNullOrWhiteSpace(fkmx))
  510 + return list;
  511 + var t = fkmx.Trim();
  512 + if (t == "[]" || t == "{}")
  513 + return list;
  514 + try
  515 + {
  516 + var arr = JArray.Parse(t);
  517 + foreach (var tok in arr)
  518 + {
  519 + if (tok is not JObject o)
  520 + continue;
  521 + var lx = o.Value<string>("lx") ?? o.Value<string>("Lx");
  522 + var je = ParseDecimalToken(o["je"] ?? o["Je"]);
  523 + list.Add((lx, je));
  524 + }
  525 + }
  526 + catch
  527 + {
  528 + // ignore
  529 + }
  530 +
  531 + return list;
  532 + }
  533 +
  534 + private static decimal ParseDecimalToken(JToken token)
  535 + {
  536 + if (token == null || token.Type == JTokenType.Null)
  537 + return 0;
  538 + if (token.Type == JTokenType.Integer || token.Type == JTokenType.Float)
  539 + return token.Value<decimal>();
  540 + return ParseDecimalLoose(token.ToString());
  541 + }
  542 +
  543 + private static decimal ParseDecimalLoose(string s)
  544 + {
  545 + if (string.IsNullOrWhiteSpace(s))
  546 + return 0;
  547 + return decimal.TryParse(s.Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out var d)
  548 + ? d
  549 + : decimal.TryParse(s.Trim(), out d) ? d : 0;
  550 + }
  551 +
  552 + private static string ResolveDictLabel(string id, Dictionary<string, string> map, string fallbackPrefix)
  553 + {
  554 + if (string.IsNullOrWhiteSpace(id))
  555 + return fallbackPrefix;
  556 + var k = id.Trim();
  557 + if (map.TryGetValue(k, out var name) && !string.IsNullOrWhiteSpace(name))
  558 + return name.Trim();
  559 + return $"{fallbackPrefix}({k})";
  560 + }
  561 +
  562 + private async Task<Dictionary<string, string>> BuildDictionaryMapAsync(HashSet<string> ids)
  563 + {
  564 + var map = new Dictionary<string, string>(StringComparer.Ordinal);
  565 + if (ids == null || ids.Count == 0)
  566 + return map;
  567 + var idList = ids.Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList();
  568 + if (idList.Count == 0)
  569 + return map;
  570 + var rows = await _db.Queryable<DictionaryDataEntity>()
  571 + .Where(d => d.DeleteMark == null && idList.Contains(d.Id))
  572 + .Select(d => new { d.Id, d.FullName })
  573 + .ToListAsync();
  574 + foreach (var r in rows)
  575 + {
  576 + if (!string.IsNullOrEmpty(r.Id))
  577 + map[r.Id] = r.FullName ?? "";
  578 + }
  579 +
  580 + return map;
  581 + }
  582 +
  583 + private async Task<Dictionary<string, string>> BuildUserNameMapAsync(List<string> userIds)
  584 + {
  585 + var map = new Dictionary<string, string>(StringComparer.Ordinal);
  586 + if (userIds == null || userIds.Count == 0)
  587 + return map;
  588 + var ids = userIds.Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList();
  589 + if (ids.Count == 0)
  590 + return map;
  591 + var rows = await _db.Queryable<UserEntity>().In(u => u.Id, ids).Select(u => new { u.Id, u.RealName })
  592 + .ToListAsync();
  593 + foreach (var r in rows)
  594 + {
  595 + if (!string.IsNullOrEmpty(r.Id))
  596 + map[r.Id] = r.RealName ?? "";
  597 + }
  598 +
  599 + return map;
  600 + }
  601 + }
  602 +}
... ...
Antis.Erp.Plat/netcore/src/Modularity/Extend/NCC.Extend/WtSkzhbService.cs
... ... @@ -50,15 +50,26 @@ namespace NCC.Extend.WtSkzhb
50 50 }
51 51  
52 52 /// <summary>
53   - /// 获取收款账户管理
  53 + /// 获取收款账户管理(账户名称、所属门店与列表接口一致,解析为字典/门店中文名)
54 54 /// </summary>
55   - /// <param name="id">参数</param>
  55 + /// <param name="id">账户主键</param>
56 56 /// <returns></returns>
57 57 [HttpGet("{id}")]
58 58 public async Task<dynamic> GetInfo(string id)
59 59 {
60   - var entity = await _db.Queryable<WtSkzhbEntity>().FirstAsync(p => p.Id == id);
61   - var output = entity.Adapt<WtSkzhbInfoOutput>();
  60 + var output = await _db.Queryable<WtSkzhbEntity>()
  61 + .Where(p => p.Id == id)
  62 + .Select(it => new WtSkzhbInfoOutput
  63 + {
  64 + id = it.Id,
  65 + zhmc = SqlFunc.Subqueryable<DictionaryDataEntity>()
  66 + .Where(d => d.Id == it.Zhmc)
  67 + .Select(d => d.FullName),
  68 + ssmd = SqlFunc.Subqueryable<WtMdEntity>()
  69 + .Where(m => m.Id == it.Ssmd)
  70 + .Select(m => m.Mdmc),
  71 + })
  72 + .FirstAsync();
62 73 return output;
63 74 }
64 75  
... ... @@ -78,6 +89,7 @@ namespace NCC.Extend.WtSkzhb
78 89 .Select(it=> new WtSkzhbListOutput
79 90 {
80 91 id = it.Id,
  92 + skzhDictId = it.Zhmc,
81 93 // ✅ 账户名称:通过子查询关联字典表,将ID转换为中文名称
82 94 zhmc = SqlFunc.Subqueryable<DictionaryDataEntity>()
83 95 .Where(d => d.Id == it.Zhmc)
... ... @@ -121,6 +133,7 @@ namespace NCC.Extend.WtSkzhb
121 133 .Select(it=> new WtSkzhbListOutput
122 134 {
123 135 id = it.Id,
  136 + skzhDictId = it.Zhmc,
124 137 // ✅ 账户名称:通过子查询关联字典表,将ID转换为中文名称
125 138 zhmc = SqlFunc.Subqueryable<DictionaryDataEntity>()
126 139 .Where(d => d.Id == it.Zhmc)
... ...