vue3-element-plus-app-chu 0.0.33 → 0.0.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -34,11 +34,11 @@ pnpm dev:backend # 只启动 verce-vue-test/backend 后端
34
34
  - 新增仅要求业务类型、预报金额、交易日期和收支方向,客户、机构等字段选填;支付渠道未传时由后端默认 `8`,预报日期未传时由后端默认当天。新增、修改不展示或提交接口未声明的票号、出票日。
35
35
  - 详情只展示当前详情接口声明的 15 个字段;编辑仅提交定位流水号和实际变更的可写字段,避免将详情未返回的信息覆盖为空。查询排序按日期降序、日期升序、金额降序、金额升序分别提交 `1/2/3/4`。
36
36
  - 模块目录与授权页面保持一致:`api.ts` 放接口定义,`typs.ts` 放类型,`index.vue` 包含列表、表单、详情和页面内工具函数。默认交易日期通过共用的 `src/view/dcps/runtime.ts` 获取,接口定义只维护在各自模块下,不再集中到 `src/api`。
37
- - 新增、修改、详情页面每行四列展示,窗口变窄后依次降为三列、两列、一列。
37
+ - 新增、修改表单按实际内容区宽度自动排列,最多四列;侧栏或宿主容器变窄后自动减少列数。详情页面按窗口宽度调整列数。
38
38
 
39
39
  页面通过公共请求层读取 TAM 的 `head/body`,统一响应的解包与兼容处理由 `src/utils/request.ts` 负责。指定后端用于替代前端 mock;数字人民币核销、修改和撤销核销按顺序直接更新数据库,单机 MongoDB 即可使用。`head.consumerSeqNo` 可选,传入时支持相同请求重试;原金额和状态快照校验仍保留。注资发起只保存 `PENDING` / `NOT_SENT` 待处理记录,不调整账户余额;预报导入当前返回 `501`。业务校验、数据保存和导入导出均以指定后端的实时文档及实现为准。
40
40
 
41
- 数字人民币页面的业务类型使用 `201/202/203` 字典,新增预报不提交 `predName`;核销预报方向使用 `1/2`,待核销查询包含状态 `1/3`,展示交易对手账号;流水可按业务类型筛选并读取 `tranStatus`;注资明细支持起止交易日期;授权页展示业务类型中文名称。匡算明细展示部分核销状态。字段及页面接口映射见 [数字人民币接口摘录](docs/digital-rmb-apis.md),当前接口约束以实时文档为准。
41
+ 所有页面的支付渠道统一使用 `8` 表示数字人民币。数字人民币页面的业务类型使用 `201/202/203` 字典,新增预报不提交 `predName`;项目内预报收支方向统一使用 `1` 收入、`2` 支出,流水统一使用 `I` 收入、`O` 支出,查询、请求和结果展示均按各自编码处理。核销预报待核销查询包含状态 `1/3`,展示交易对手账号;流水可按业务类型筛选并读取 `tranStatus`;注资明细支持起止交易日期;授权页展示业务类型中文名称。匡算明细展示部分核销状态。字段及页面接口映射见 [数字人民币接口摘录](docs/digital-rmb-apis.md),当前接口约束以实时文档为准。
42
42
 
43
43
  独立页面 `/flow-query` 的普通查询、初次加载、分页和刷新与核销页面的流水信息共用 `/TAM/0001/140502002`,参数保持一致:交易日期 `tranDate` 必填且默认取共用业务日期,可按业务类型、我方机构、付款人、收款人、收支方向、金额范围和核销状态筛选,未填写的可选条件不提交。列表读取 `resultList` 和字符串类型的 `totalCount`,字段沿用核销流水模型。「查询」「实时查询流水」与「重置」按钮并排放在查询条件区末尾。「实时查询流水」单独调用 `/TAM/0001/140504002`,只携带公共分页参数 `pageIndex: 1`、`pageSize: 1`,业务请求体为空;成功提示“操作成功”,失败仅记录控制台,不更新列表。
44
44
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue3-element-plus-app-chu",
3
- "version": "0.0.33",
3
+ "version": "0.0.35",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "files": [
@@ -16,15 +16,22 @@
16
16
 
17
17
  公共样式变量仍放在 `common.css`,由 `src/main.ts` 统一引入。
18
18
 
19
+ ## 移植到其他宿主项目
20
+
21
+ - 同步完整的页面模块及它引用的公共文件,包括 `runtime.ts`、`dictionaries.ts` 和表格组件;仅复制旧版 `index.vue` 或遗漏公共字典,会造成控件、选项和当前代码不一致。预报新增页的支付渠道应为“数字人民币”下拉项,提交字符串 `8`。
22
+ - 宿主须注册 Element Plus 并加载配套样式。预报新增、修改表单在页面内明确约束标签在上方左对齐、控件占满列宽及卡片内部滚动;这些样式只作用于当前表单。宿主若使用 `!important` 强制覆盖 Element Plus 内部类,仍需收窄该全局规则的作用范围。
23
+ - 表单按实际内容宽度分列,每列以 `240px` 为基准,最多四列,不再依赖整个浏览器视口决定列数。
24
+ - 高度变量 `--dpcs-host-layout-height` 表示宿主顶部导航、页签、底部状态栏及外部上下留白的总高度。移植时在宿主容器上设置实际值,例如 `.dcps-host { --dpcs-host-layout-height: 120px; }` 中的 `120px` 只是示例。预报页在变量缺失时按 `0px` 计算;宿主有额外栏位时仍须设置此值。其他 DCPS 页面继续共用 `common.css`。
25
+
19
26
  ## 当前接口契约
20
27
 
21
28
  接口统一使用 `/Users/bombingpig/WebstormProjects/verce-vue-test/backend`,以 [Scalar 文档](http://localhost:3011/oms/docs) 和 [OpenAPI JSON](http://localhost:3011/oms/openapi.json) 为准。服务前缀为 `/oms`,前端开发代理将 `/TAM`、`/api`、`/nacos` 转发到 `http://localhost:3011/oms`。本项目已移除原 `backend/`;仓库内 `docs/digital-rmb.openapi.json` 为字段摘录。
22
29
 
23
- 预报新增必填 `busiType`、`predAmt`、`tranDate`、`payDirec`,业务类型字典为 `201` 兑回、`202` 兑出、`203` 付现;新增和修改不提交 `predName`、`billNo`、`billDate`。客户和机构等字段选填,`payChannel` 缺省为 `8`,`predDate` 缺省为后端当天日期。核销预报查询使用方向 `1/2`,待核销传 `verifyStatusList: ['1', '3']`,已核销传 `['2']`;预报管理和流水方向保持各自原协议。核销页流水查询使用 `busiType`,读取 `tranStatus`(`S/P/F`),展示核销状态 `3` 部分核销。注资明细提供 `txnDtStart`、`txnDtEnd` 筛选。字段摘录及页面接口映射见 `docs/digital-rmb-apis.md`,业务校验与保存行为由指定后端负责。
30
+ 预报新增必填 `busiType`、`predAmt`、`tranDate`、`payDirec`,业务类型字典为 `201` 兑回、`202` 兑出、`203` 付现;新增和修改不提交 `predName`、`billNo`、`billDate`。客户和机构等字段选填,`payChannel` 缺省为 `8`,`predDate` 缺省为后端当天日期。所有页面的支付渠道统一使用 `8` 表示数字人民币。项目内预报收支方向统一为 `1` 收入、`2` 支出,流水统一为 `I` 收入、`O` 支出;预报管理、核销预报和匡算预报明细按 `1/2` 处理,流水查询、核销流水和匡算流水明细按 `I/O` 处理。核销预报待核销传 `verifyStatusList: ['1', '3']`,已核销传 `['2']`。核销页流水查询使用 `busiType`,读取 `tranStatus`(`S/P/F`),展示核销状态 `3` 部分核销。注资明细提供 `txnDtStart`、`txnDtEnd` 筛选。字段摘录及页面接口映射见 `docs/digital-rmb-apis.md`,业务校验与保存行为由指定后端负责。
24
31
 
25
- 当前核销预报 API 将页面 `1/2` 方向与后端实现的 `I/O` 双向转换;核销写操作提交公共 `consumerSeqNo`、原状态和原金额快照。后端作为替代前端 mock 的本地测试服务,核销、修改和撤销核销按顺序直接更新数据库,各种 MongoDB 部署模式均不启动事务。`consumerSeqNo` 可选,缺省时后端生成,传入时支持相同请求重试;快照校验和关联撤回逻辑仍保留。注资明细使用服务端分页;发起注资只保存 `PENDING` / `NOT_SENT` 记录,不改变余额。参数接口当前由 `swaggerStub` 返回静态兼容数据,不持久化参数增删改。
32
+ 核销预报 API 按 `1/2` 原值提交并读取方向,流水 API 按 `I/O` 原值提交并读取方向;核销写操作提交公共 `consumerSeqNo`、原状态和原金额快照。后端作为替代前端 mock 的本地测试服务,核销、修改和撤销核销按顺序直接更新数据库,各种 MongoDB 部署模式均不启动事务。`consumerSeqNo` 可选,缺省时后端生成,传入时支持相同请求重试;快照校验和关联撤回逻辑仍保留。注资明细使用服务端分页;发起注资只保存 `PENDING` / `NOT_SENT` 记录,不改变余额。参数接口当前由 `swaggerStub` 返回静态兼容数据,不持久化参数增删改。
26
33
 
27
- 独立流水查询页面 `/flow-query` 的普通查询、初次加载、分页和刷新复用核销页的 `queryFlowApi`(`140502002`)与流水模型,读取 `resultList` 和字符串类型的 `totalCount`。查询参数与核销页流水信息保持一致:`tranDate` 必填,默认取 `dcpsRuntime.date`;可选条件为 `busiType`、`orgName`、`payerName`、`payeeName`、`payDirec`(I/O)、`startTransAmt`、`endTransAmt` 和 `verifyStatus`(1/2),空条件不发送;分页放在公共请求头。「查询」「实时查询流水」与「重置」按钮并排放在查询条件区末尾。「实时查询流水」通过独立的 `queryRealtimeFlowApi` 调用 `140504002`,只传公共分页 `pageIndex: 1`、`pageSize: 1`,业务请求体为空;成功提示“操作成功”,失败仅记录控制台,不改变表格和分页。
34
+ 独立流水查询页面 `/flow-query` 的普通查询、初次加载、分页和刷新复用核销页的 `queryFlowApi`(`140502002`)与流水模型,读取 `resultList` 和字符串类型的 `totalCount`。查询参数与核销页流水信息保持一致:`tranDate` 必填,默认取 `dcpsRuntime.date`;可选条件为 `busiType`、`orgName`、`payerName`、`payeeName`、`payDirec`(`I` 收入、`O` 支出)、`startTransAmt`、`endTransAmt` 和 `verifyStatus`(1/2),空条件不发送;分页放在公共请求头。「查询」「实时查询流水」与「重置」按钮并排放在查询条件区末尾。「实时查询流水」通过独立的 `queryRealtimeFlowApi` 调用 `140504002`,只传公共分页 `pageIndex: 1`、`pageSize: 1`,业务请求体为空;成功提示“操作成功”,失败仅记录控制台,不改变表格和分页。
28
35
 
29
36
  ## 命名约定
30
37
 
@@ -1,3 +1,10 @@
1
+ /** 所有页面共用的支付渠道字典:8 数字人民币。 */
2
+ export const payChannelLabels: Record<string, string> = { '8': '数字人民币' }
3
+
4
+ /** 支付渠道下拉展示中文,查询和表单提交字符串代码。 */
5
+ export const payChannelOptions = Object.entries(payChannelLabels)
6
+ .map(([value, label]) => ({ value, label }))
7
+
1
8
  /** 注资明细、流水查询和核销共用的交易处理状态。 */
2
9
  export const transactionStatusLabels: Record<string, string> = {
3
10
  S: '成功',
@@ -3,6 +3,7 @@ import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue'
3
3
  import { ElConfigProvider, ElMessage } from 'element-plus'
4
4
  import API from './api'
5
5
  import { dcpsRuntime } from '../runtime'
6
+ import { payChannelLabels } from '../dictionaries'
6
7
  import { localSort } from '@/utils/table-sort'
7
8
  import type {
8
9
  EstimationAmounts, EstimationCell, EstimationPredRow, EstimationQueryParams, EstimationTranRow,
@@ -21,11 +22,11 @@ const tableSize = 'small'
21
22
  // 单击可查看明细的金额单元格按位置编码查询详情(140503003)。
22
23
 
23
24
  // 金额字段编码与图中报表位置的对应关系:
24
- // C3 数币账户昨日余额;C6/D6 报备金额;C7/D7 未核销金额;
25
+ // C3 数字人民币账户昨日余额;C6/D6 报备金额;C7/D7 未核销金额;
25
26
  // C8/D8 未核销业务流水;C9 日初可用资金(前端计算:C3 + C6 - D6 + C8 - D8);
26
27
  // C11/D11 今日预计调拨金额(查询条件输入框,不查详情);
27
- // C12 数币账户预留金额(前端计算:C9 + C11 - D11);
28
- // B15 当日实时余额。C3、C9、C12、B15 仅展示金额,不提供明细弹窗。
28
+ // C12 数字人民币账户预留金额(前端计算:C9 + C11 - D11);
29
+ // B15 当日实时余额。C3、C9、C12、B15 仅展示金额,不提供明细查看。
29
30
  // 轧差列由前端按「收入减支出」计算:结果行随查询结果更新,
30
31
  // 调拨行随输入实时更新;两条空行按原型占位留空。
31
32
 
@@ -112,10 +113,10 @@ const calcTotalAmount = (terms: Array<[string, 1 | -1]>): string => {
112
113
  const calcGapAmount = (inAmt: string, outAmt: string): string =>
113
114
  calcTotalAmount([[inAmt, 1], [outAmt, -1]])
114
115
 
115
- /** 收支方向字典:I 来账、O 往账。 */
116
- const payDirecLabels: Record<string, string> = { I: '来账', O: '往账' }
117
- /** 支付渠道:预报与流水的数字人民币分别为 8、5;其余渠道保留原文。 */
118
- const payChannelLabels: Record<string, string> = { '5': '数字人民币', '8': '数字人民币' }
116
+ /** 预报收支方向:1 收入、2 支出。 */
117
+ const forecastPayDirecLabels: Record<string, string> = { '1': '收入', '2': '支出' }
118
+ /** 流水收支方向:I 收入、O 支出。 */
119
+ const flowPayDirecLabels: Record<string, string> = { I: '收入', O: '支出' }
119
120
  /** 与核销页面统一展示核销状态;部分核销记录仍可能出现在匡算明细中。 */
120
121
  const verifyStatusLabels: Record<string, string> = { '1': '未核销', '2': '已核销', '3': '部分核销' }
121
122
  /** 业务类型字典:201 兑回、202 兑出、203 付现;与核销预报使用同一套枚举。 */
@@ -145,7 +146,7 @@ const amountText = (position: string): string => {
145
146
  return value ? formatAmount(value) : ''
146
147
  }
147
148
 
148
- /** 组装单元格对象供详情弹窗使用:位置编码、展示名称与当前金额一起带入。 */
149
+ /** 组装单元格对象供详情页使用:位置编码、展示名称与当前金额一起带入。 */
149
150
  const cellOf = (position: string): EstimationCell => ({
150
151
  position,
151
152
  label: cellLabels[position] ?? position,
@@ -195,7 +196,7 @@ const gapText = (inPosition: string, outPosition: string): string => {
195
196
  const inputGapText = computed(() =>
196
197
  calcGapAmount(queryForm.predictAllotInAmt, queryForm.predictAllotOutAmt))
197
198
 
198
- /** 数币账户预留金额 C12 = C3 + C6 - D6 + C8 - D8 + (C11 - D11),随调拨输入实时更新。 */
199
+ /** 数字人民币账户预留金额 C12 = C3 + C6 - D6 + C8 - D8 + (C11 - D11),随调拨输入实时更新。 */
199
200
  const reservedBalanceText = computed(() =>
200
201
  calcTotalAmount([[openingBalanceText.value, 1], [inputGapText.value, 1]]))
201
202
 
@@ -291,9 +292,9 @@ const submitExport = () => {
291
292
  console.log('[导出数字人民币头寸匡算参数]', params)
292
293
  }
293
294
 
294
- // ---------- 单元格明细弹窗 ----------
295
+ // ---------- 单元格明细页 ----------
295
296
 
296
- // 弹窗状态:cell 为被单击的报表单元格;明细请求在弹窗打开时发起。
297
+ // 在当前组件内切换报表与明细视图,保留报表查询条件和结果,不新增路由。
297
298
  const detailVisible = ref(false)
298
299
  const detailCell = ref<EstimationCell | null>(null)
299
300
  // 报备金额、未核销金额仅展示预报;未核销业务流水仅展示流水。
@@ -332,21 +333,23 @@ const loadDetailInfo = async () => {
332
333
  }
333
334
  }
334
335
 
335
- /** 关闭弹窗:重置明细并让未完成的请求失效。 */
336
+ /** 返回匡算报表:重置明细并让未完成的请求失效。 */
336
337
  const closeDetail = () => {
337
338
  detailVisible.value = false
338
339
  detailRequestId += 1
340
+ detailCell.value = null
339
341
  detailPredList.value = []
340
342
  detailTranList.value = []
341
343
  detailTotalCount.value = ''
342
344
  detailLoading.value = false
343
345
  }
344
346
 
345
- /** 打开单元格明细弹窗;结果就绪前其余单元格为占位横线,不发起详情查询。 */
347
+ /** 打开单元格明细页并查询;结果未就绪时不切换视图或发起请求。 */
346
348
  const openDetail = (cell?: EstimationCell) => {
347
349
  if (!cell || !resultReady.value) return
348
350
  detailCell.value = cell
349
351
  detailVisible.value = true
352
+ void loadDetailInfo()
350
353
  }
351
354
 
352
355
  /** 明细总条数优先使用接口 totalCount,缺失时仅统计当前展示的列表。 */
@@ -371,7 +374,7 @@ onBeforeUnmount(() => {
371
374
  <ElConfigProvider :size="tableSize">
372
375
  <main class="dcps-page">
373
376
  <!-- 顶部操作区:交易日期选择与导出、查询入口(收支金额在下方表格内填写)。 -->
374
- <el-card class="estimation-header" shadow="never" :body-style="{ padding: '10px 14px' }">
377
+ <el-card v-show="!detailVisible" class="estimation-header" shadow="never" :body-style="{ padding: '10px 14px' }">
375
378
  <div class="estimation-heading">
376
379
  <div class="filter-field">
377
380
  <label>交易日期</label>
@@ -390,7 +393,7 @@ onBeforeUnmount(() => {
390
393
  </el-card>
391
394
 
392
395
  <!-- 匡算报表:合并单元格的头寸匡算表,与业务原型一致;表格常显,结果就绪前金额显示占位。 -->
393
- <el-card class="estimation-report" shadow="never" :body-style="{ padding: '12px 14px' }">
396
+ <el-card v-show="!detailVisible" class="estimation-report" shadow="never" :body-style="{ padding: '12px 14px' }">
394
397
  <div class="report-scroll">
395
398
  <table class="report-table" :class="{ 'is-ready': resultReady }">
396
399
  <!-- 列:两个左侧标签列、收入、支付、轧差。 -->
@@ -404,7 +407,7 @@ onBeforeUnmount(() => {
404
407
  </tr>
405
408
  <!-- 前一日余额:C3 横跨收入、支付两列,右侧标注单位。 -->
406
409
  <tr>
407
- <td colspan="2" class="report-label">数币账户昨日余额</td>
410
+ <td colspan="2" class="report-label">数字人民币账户昨日余额</td>
408
411
  <td colspan="2" class="report-data">
409
412
  <div class="report-value report-value--static">
410
413
  <span class="report-amount">{{ amountText('C3') }}</span>
@@ -510,9 +513,9 @@ onBeforeUnmount(() => {
510
513
  </td>
511
514
  <td class="report-gap" title="轧差 = 收入 − 支出(前端计算)">{{ inputGapText }}</td>
512
515
  </tr>
513
- <!-- 数币账户预留金额:C12 = C9 + C11 - D11,横跨收入、支付、轧差三列。 -->
516
+ <!-- 数字人民币账户预留金额:C12 = C9 + C11 - D11,横跨收入、支付、轧差三列。 -->
514
517
  <tr>
515
- <td colspan="2" class="report-label">数币账户预留金额</td>
518
+ <td colspan="2" class="report-label">数字人民币账户预留金额</td>
516
519
  <td colspan="3" class="report-data">
517
520
  <div class="report-value report-value--static">
518
521
  <span class="report-amount">{{ reservedBalanceText }}</span>
@@ -543,17 +546,20 @@ onBeforeUnmount(() => {
543
546
  </div>
544
547
  </el-card>
545
548
 
546
- <!-- 单元格明细弹窗:按位置编码查询,并仅展示对应的预报或流水列表。 -->
547
- <el-dialog
548
- v-model="detailVisible"
549
- :title="detailCell ? `匡算明细 - ${detailCell.label}` : '匡算明细'"
550
- width="min(1080px, calc(100vw - 32px))"
551
- top="16px"
552
- append-to-body
553
- destroy-on-close
554
- @open="loadDetailInfo"
555
- @closed="closeDetail"
556
- >
549
+ <!-- 单元格明细页:顶部返回报表,内容区展示对应的预报或流水列表。 -->
550
+ <template v-if="detailVisible">
551
+ <el-card class="estimation-header" shadow="never" :body-style="{ padding: '10px 14px' }">
552
+ <div class="detail-heading">
553
+ <el-button @click="closeDetail">
554
+ <svg class="detail-back-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
555
+ <path d="M14 5l-7 7 7 7" />
556
+ </svg>
557
+ 返回匡算
558
+ </el-button>
559
+ <h1 class="detail-title">{{ detailCell ? `匡算明细 - ${detailCell.label}` : '匡算明细' }}</h1>
560
+ </div>
561
+ </el-card>
562
+ <el-card class="detail-card" shadow="never" :body-style="{ padding: '12px 14px', height: '100%', boxSizing: 'border-box' }">
557
563
  <el-scrollbar class="detail-scrollbar">
558
564
  <div class="detail-content">
559
565
  <!-- 上下文摘要:被点击单元格的位置、金额与详情查询的交易日期。 -->
@@ -578,8 +584,8 @@ onBeforeUnmount(() => {
578
584
 
579
585
  <div v-loading="detailLoading" class="detail-tables">
580
586
  <!-- C6/C7/D6/D7 仅展示预报信息;列表为空时展示统一空态。 -->
581
- <div v-if="showPredDetail" class="dialog-section-title">预报信息</div>
582
- <el-table v-if="showPredDetail" :data="detailPredList" :size="tableSize" border max-height="240px" empty-text="暂无预报信息">
587
+ <div v-if="showPredDetail" class="detail-section-title">预报信息</div>
588
+ <el-table v-if="showPredDetail" :data="detailPredList" :size="tableSize" border empty-text="暂无预报信息">
583
589
  <el-table-column label="预报流水号" min-width="150" show-overflow-tooltip>
584
590
  <template #default="{ row }">{{ displayText(row.predRefNo) }}</template>
585
591
  </el-table-column>
@@ -593,7 +599,7 @@ onBeforeUnmount(() => {
593
599
  <template #default="{ row }">{{ displayText(row.competName) }}</template>
594
600
  </el-table-column>
595
601
  <el-table-column label="收支方向" width="80" align="center">
596
- <template #default="{ row }">{{ dictLabel(payDirecLabels, row.payDirec) }}</template>
602
+ <template #default="{ row }">{{ dictLabel(forecastPayDirecLabels, row.payDirec) }}</template>
597
603
  </el-table-column>
598
604
  <el-table-column label="支付渠道" width="110" align="center">
599
605
  <template #default="{ row }">{{ dictLabel(payChannelLabels, row.payChannel) }}</template>
@@ -615,9 +621,9 @@ onBeforeUnmount(() => {
615
621
  </el-table-column>
616
622
  </el-table>
617
623
 
618
- <!-- C8/D8 仅展示流水信息;失败的详情可重新打开弹窗重试。 -->
619
- <div v-if="showTranDetail" class="dialog-section-title">流水信息</div>
620
- <el-table v-if="showTranDetail" :data="detailTranList" :size="tableSize" border max-height="240px" empty-text="暂无流水信息">
624
+ <!-- C8/D8 仅展示流水信息;失败的详情可返回后重新打开重试。 -->
625
+ <div v-if="showTranDetail" class="detail-section-title">流水信息</div>
626
+ <el-table v-if="showTranDetail" :data="detailTranList" :size="tableSize" border empty-text="暂无流水信息">
621
627
  <el-table-column label="交易参考号" min-width="150" show-overflow-tooltip>
622
628
  <template #default="{ row }">{{ displayText(row.refNo) }}</template>
623
629
  </el-table-column>
@@ -631,7 +637,7 @@ onBeforeUnmount(() => {
631
637
  <template #default="{ row }">{{ displayText(row.payeeName) }}</template>
632
638
  </el-table-column>
633
639
  <el-table-column label="收支方向" width="80" align="center">
634
- <template #default="{ row }">{{ dictLabel(payDirecLabels, row.payDirec) }}</template>
640
+ <template #default="{ row }">{{ dictLabel(flowPayDirecLabels, row.payDirec) }}</template>
635
641
  </el-table-column>
636
642
  <el-table-column label="支付渠道" width="110" align="center">
637
643
  <template #default="{ row }">{{ dictLabel(payChannelLabels, row.payChannel) }}</template>
@@ -653,10 +659,8 @@ onBeforeUnmount(() => {
653
659
  </div>
654
660
  </div>
655
661
  </el-scrollbar>
656
- <template #footer>
657
- <el-button @click="closeDetail">关闭</el-button>
658
- </template>
659
- </el-dialog>
662
+ </el-card>
663
+ </template>
660
664
  </main>
661
665
  </ElConfigProvider>
662
666
  </template>
@@ -789,8 +793,12 @@ td.report-data--input { padding: 5px 8px; }
789
793
  letter-spacing: 0.02em;
790
794
  }
791
795
 
792
- /* ---------- 单元格明细弹窗 ---------- */
793
- .detail-scrollbar { max-height: calc(100vh - 240px); }
796
+ /* ---------- 单元格明细页 ---------- */
797
+ .detail-heading { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 12px; }
798
+ .detail-back-icon { width: 15px; height: 15px; margin-right: 4px; }
799
+ .detail-title { margin: 0; color: var(--el-text-color-primary); font-size: 16px; font-weight: 600; line-height: 22px; }
800
+ .detail-card { flex: 1; min-height: 0; min-width: 0; overflow: hidden; }
801
+ .detail-scrollbar { height: 100%; }
794
802
  .detail-content { padding: 2px 4px 4px; }
795
803
 
796
804
  /* 摘要区:位置编码、金额、日期放在一行,便于确认明细上下文。 */
@@ -810,10 +818,10 @@ td.report-data--input { padding: 5px 8px; }
810
818
  .detail-reference { margin-left: auto; }
811
819
  .detail-reference strong { font-weight: 600; }
812
820
 
813
- .dialog-section-title { margin: 12px 0 6px; color: var(--el-text-color-regular); font-size: 13px; font-weight: 600; }
821
+ .detail-section-title { margin: 12px 0 6px; color: var(--el-text-color-regular); font-size: 13px; font-weight: 600; }
814
822
  .detail-tables .el-table + .el-table { margin-top: 2px; }
815
823
  .detail-tables { min-height: 160px; }
816
- .detail-tables .dialog-section-title:first-child { margin-top: 0; }
824
+ .detail-tables .detail-section-title:first-child { margin-top: 0; }
817
825
  .amount-cell { color: var(--el-text-color-primary); font-variant-numeric: tabular-nums; }
818
826
  .detail-retry { margin-top: 10px; color: var(--el-color-danger); font-size: 12px; text-align: center; }
819
827
  </style>
@@ -81,9 +81,9 @@ export interface Tam140503003OutBodyPredList {
81
81
  competName?: string
82
82
  /** 落地支行 */
83
83
  groundBranch?: string
84
- /** 支付渠道 */
84
+ /** 支付渠道:8 数字人民币。 */
85
85
  payChannel?: string
86
- /** 收支方向 */
86
+ /** 预报收支方向:1 收入、2 支出。 */
87
87
  payDirec?: string
88
88
  /** 预报金额 */
89
89
  predAmt?: string
@@ -105,9 +105,9 @@ export interface Tam140503003OutBodyTranList {
105
105
  busiType?: string
106
106
  /** 落地支行 */
107
107
  groundBranch?: string
108
- /** 支付渠道 */
108
+ /** 支付渠道:8 数字人民币。 */
109
109
  payChannel?: string
110
- /** 收支方向 */
110
+ /** 流水收支方向:I 收入、O 支出。 */
111
111
  payDirec?: string
112
112
  /** 收款人名称 */
113
113
  payeeName?: string
@@ -98,8 +98,8 @@ const validAmount = (value: string) => {
98
98
 
99
99
  /** 业务类型字典:201 兑回、202 兑出、203 付现。 */
100
100
  const busiTypeLabels: Record<string, string> = { '201': '兑回', '202': '兑出', '203': '付现' }
101
- /** 收支方向字典:I 来账、O 往账。 */
102
- const payDirecLabels: Record<string, string> = { I: '来账', O: '往账' }
101
+ /** 流水收支方向字典:I 收入、O 支出。 */
102
+ const payDirecLabels: Record<string, string> = { I: '收入', O: '支出' }
103
103
  /** 流水查询筛选只提供未核销和已核销,部分核销仅在结果中展示。 */
104
104
  const verifyStatusLabels: Record<string, string> = { '1': '未核销', '2': '已核销', '3': '部分核销' }
105
105
 
@@ -1,4 +1,4 @@
1
- /** 普通流水查询与核销页面共用 140502002 的请求、筛选及响应类型。 */
1
+ /** 普通流水查询与核销页面共用 140502002 的请求、筛选及响应类型;收支方向为 I 收入、O 支出。 */
2
2
  export type {
3
3
  FlowFilters,
4
4
  FlowQueryParams,
@@ -24,6 +24,7 @@ import { computed, onActivated, onBeforeUnmount, reactive, ref, watch } from 'vu
24
24
  import { ElConfigProvider, ElMessage, ElMessageBox } from 'element-plus'
25
25
  import API from './api'
26
26
  import { dcpsRuntime } from '../runtime'
27
+ import { payChannelLabels, payChannelOptions } from '../dictionaries'
27
28
  import { ArtDataTable, type ColumnOption, type PaginationOptions, type TableSettings } from '@/components/table'
28
29
  import { localSort } from '@/utils/table-sort'
29
30
  import type {
@@ -159,6 +160,7 @@ const validateForm = (values: ForecastFormValues, mode: 'create' | 'edit' = 'cre
159
160
  }
160
161
  if (values.busiType && !Object.hasOwn(busiTypeLabels, values.busiType)) return '请选择有效的业务类型'
161
162
  if (values.payDirec && !Object.hasOwn(payDirecLabels, values.payDirec)) return '请选择有效的收支方向'
163
+ if (values.payChannel && !Object.hasOwn(payChannelLabels, values.payChannel)) return '请选择有效的支付渠道'
162
164
  for (const [key, label] of [['tranDate', '交易日期'], ['predDate', '预报日期']] as const) {
163
165
  const date = values[key].trim()
164
166
  if ((date || (mode === 'create' && key === 'tranDate')) && !isValidDate(date)) return `${label}须为有效日期,格式为 YYYYMMDD`
@@ -203,20 +205,37 @@ const createFilters = (): ForecastFilters => ({
203
205
  })
204
206
  const listFilters = ref(createFilters())
205
207
  let listAppliedQuery: ForecastFilters = { ...listFilters.value }
206
- // 重复输入项共用一份配置,依次为字段、名称;输入框较窄,占位文案统一使用简短提示。
207
- const listTextFilters = [
208
- ['clientName', '客户名称'],
209
- ['competName', '交易对手名称'],
210
- ['payChannel', '支付渠道'],
211
- ['groundBranch', '落地机构'],
212
- ['predStatus', '预报状态'],
213
- ['verifyStatus', '核销状态'],
214
- ] as const
215
208
  /** 新接口明确给出的业务类型;未登记代码保留接口原值。 */
216
209
  const busiTypeLabels: Record<string, string> = { '201': '兑回', '202': '兑出', '203': '付现' }
217
210
  const busiTypeOptions = Object.entries(busiTypeLabels).map(([value, label]) => ({ value, label }))
218
- const payDirecLabels: Record<string, string> = { I: '收入', O: '支出' }
211
+ /** 预报页面按业务字典展示中文,查询和编辑提交对应的字符串代码。 */
212
+ const payDirecLabels: Record<string, string> = { '1': '收入', '2': '支出' }
219
213
  const payDirecOptions = Object.entries(payDirecLabels).map(([value, label]) => ({ value, label }))
214
+ const predStatusLabels: Record<string, string> = {
215
+ '1': '正常预报',
216
+ '2': '延迟预报',
217
+ '3': '正常预报正常删除',
218
+ '4': '正常预报延迟删除',
219
+ '5': '延迟预报延时删除',
220
+ '7': '正常预报新增超时',
221
+ '8': '延迟预报新增超时',
222
+ }
223
+ const predStatusOptions = Object.entries(predStatusLabels).map(([value, label]) => ({ value, label }))
224
+ const verifyStatusLabels: Record<string, string> = { '1': '未核销', '2': '已核销', '3': '部分核销' }
225
+ const verifyStatusOptions = Object.entries(verifyStatusLabels).map(([value, label]) => ({ value, label }))
226
+ // 已提供字典的筛选项使用下拉框,其余字段保留文本输入。
227
+ const listAdditionalFilters: {
228
+ key: 'clientName' | 'competName' | 'payChannel' | 'groundBranch' | 'predStatus' | 'verifyStatus'
229
+ label: string
230
+ options?: { value: string; label: string }[]
231
+ }[] = [
232
+ { key: 'clientName', label: '客户名称' },
233
+ { key: 'competName', label: '交易对手名称' },
234
+ { key: 'payChannel', label: '支付渠道', options: payChannelOptions },
235
+ { key: 'groundBranch', label: '落地机构' },
236
+ { key: 'predStatus', label: '预报状态', options: predStatusOptions },
237
+ { key: 'verifyStatus', label: '核销状态', options: verifyStatusOptions },
238
+ ]
220
239
  const sortRuleOptions = [
221
240
  { value: '1', label: '预报日期降序' },
222
241
  { value: '2', label: '预报日期升序' },
@@ -247,7 +266,7 @@ const isDetail = computed(() => detailDialogVisible.value)
247
266
 
248
267
  const listHasReference = (row: ForecastRow) => Boolean(row.predRefNo?.trim())
249
268
  const canChangeRecord = (row: ForecastRow) => listHasReference(row)
250
- && row.predStatus !== '3' && row.verifyStatus === '1'
269
+ && !['3', '4', '5'].includes(row.predStatus ?? '') && row.verifyStatus === '1'
251
270
  && !!normalizeAmount(row.verifyAmt ?? '') && compareAmounts(row.verifyAmt ?? '', '0') === 0
252
271
  const listTextColumn = (prop: keyof ForecastRow, label: string, width: number, visible = true): ColumnOption<ForecastRow> => ({
253
272
  prop, label, width, visible, showOverflowTooltip: true,
@@ -261,13 +280,13 @@ const listColumns: ColumnOption<ForecastRow>[] = [
261
280
  listTextColumn('clientName', '客户名称', 180),
262
281
  { ...listTextColumn('payDirec', '收支方向', 95), formatter: (row) => payDirecLabels[row.payDirec ?? ''] ?? row.payDirec ?? '—' },
263
282
  { ...listTextColumn('busiType', '业务类型', 110), formatter: (row) => busiTypeLabels[row.busiType ?? ''] ?? row.busiType ?? '—' },
264
- listTextColumn('payChannel', '支付渠道', 110),
283
+ { ...listTextColumn('payChannel', '支付渠道', 110), formatter: (row) => payChannelLabels[row.payChannel ?? ''] ?? row.payChannel ?? '—' },
265
284
  { prop: 'predAmt', label: '预报金额(元)', width: 180, align: 'right', useSlot: true, slotName: 'amount', ...localSort('predAmt', 'amount') },
266
285
  { prop: 'verifyAmt', label: '已核销金额(元)', width: 180, align: 'right', useSlot: true, slotName: 'verifiedAmount', ...localSort('verifyAmt', 'amount') },
267
286
  listTextColumn('competName', '交易对手名称', 180),
268
287
  listTextColumn('groundBranch', '落地机构', 160),
269
- listTextColumn('predStatus', '预报状态', 100),
270
- listTextColumn('verifyStatus', '核销状态', 100),
288
+ { ...listTextColumn('predStatus', '预报状态', 180), formatter: (row) => predStatusLabels[row.predStatus ?? ''] ?? row.predStatus ?? '—' },
289
+ { ...listTextColumn('verifyStatus', '核销状态', 100), formatter: (row) => verifyStatusLabels[row.verifyStatus ?? ''] ?? row.verifyStatus ?? '—' },
271
290
  listTextColumn('competAcct', '交易对手账号', 190, false),
272
291
  listTextColumn('clientType', '客户类型', 100, false),
273
292
  listTextColumn('groundBranchCode', '落地机构代码', 150, false),
@@ -433,7 +452,7 @@ type FieldKey = keyof ForecastFormValues
433
452
  type EditorField = {
434
453
  key: FieldKey
435
454
  label: string
436
- kind?: 'date' | 'amount' | 'textarea' | 'businessType' | 'direction'
455
+ kind?: 'date' | 'amount' | 'textarea' | 'businessType' | 'direction' | 'paymentChannel'
437
456
  placeholder?: string
438
457
  createOnly?: boolean
439
458
  }
@@ -457,7 +476,7 @@ const fieldGroups: { title: string; fields: EditorField[] }[] = [
457
476
  { key: 'predAmt', label: '预报金额(元)', kind: 'amount', placeholder: '请输入金额,最多两位小数' },
458
477
  { key: 'payDirec', label: '收支方向', kind: 'direction' },
459
478
  { key: 'busiType', label: '业务类型', kind: 'businessType' },
460
- { key: 'payChannel', label: '支付渠道代码', placeholder: '请输入支付渠道代码' },
479
+ { key: 'payChannel', label: '支付渠道', kind: 'paymentChannel' },
461
480
  { key: 'clientName', label: '客户名称' },
462
481
  { key: 'clientType', label: '客户类型代码', placeholder: '请输入客户类型代码' },
463
482
  ],
@@ -665,8 +684,8 @@ const detailGroups: { title: string; fields: DetailField[] }[] = [
665
684
  { key: 'tranDate', label: '交易日期', kind: 'date' },
666
685
  { key: 'predAmt', label: '预报金额(元)', kind: 'amount' },
667
686
  { key: 'standardName', label: '标准名称' },
668
- { key: 'predStatus', label: '预报状态代码', kind: 'status' },
669
- { key: 'verifyStatus', label: '核销状态代码', kind: 'status' },
687
+ { key: 'predStatus', label: '预报状态', kind: 'status' },
688
+ { key: 'verifyStatus', label: '核销状态', kind: 'status' },
670
689
  { key: 'verifyAmt', label: '已核销金额(元)', kind: 'amount' },
671
690
  { key: 'edusFlag', label: '释放状态代码', kind: 'status' },
672
691
  ],
@@ -676,7 +695,7 @@ const detailGroups: { title: string; fields: DetailField[] }[] = [
676
695
  fields: [
677
696
  { key: 'busiType', label: '业务类型代码' },
678
697
  { key: 'payDirec', label: '收支方向' },
679
- { key: 'payChannel', label: '支付渠道代码' },
698
+ { key: 'payChannel', label: '支付渠道' },
680
699
  { key: 'clientName', label: '客户名称' },
681
700
  { key: 'competName', label: '交易对手名称' },
682
701
  { key: 'competAcct', label: '交易对手账号' },
@@ -712,6 +731,9 @@ const displayValue = (field: DetailField) => {
712
731
  if (field.kind === 'date') return formatDate(value)
713
732
  if (field.key === 'busiType') return busiTypeLabels[value] ?? value
714
733
  if (field.key === 'payDirec') return payDirecLabels[value] ?? value
734
+ if (field.key === 'payChannel') return payChannelLabels[value] ?? value
735
+ if (field.key === 'predStatus') return predStatusLabels[value] ?? value
736
+ if (field.key === 'verifyStatus') return verifyStatusLabels[value] ?? value
715
737
  return String(value)
716
738
  }
717
739
 
@@ -742,7 +764,7 @@ watch([detailDialogVisible, detailDialogPredRefNo], ([visible]) => {
742
764
  <template>
743
765
  <ElConfigProvider :size="listTableSettings.size">
744
766
  <!-- 新增 / 修改页 -->
745
- <main v-if="isEditor" class="page-shell">
767
+ <main v-if="isEditor" class="dcps-forecast-shell">
746
768
  <el-card class="shell-header" shadow="never" :body-style="{ padding: '10px' }">
747
769
  <div class="shell-heading">
748
770
  <el-button class="shell-back" :disabled="submitting" @click="backToList">
@@ -764,7 +786,7 @@ watch([detailDialogVisible, detailDialogPredRefNo], ([visible]) => {
764
786
  </div>
765
787
  <template v-else>
766
788
  <p class="editor-note">金额单位为元;业务类型按接口提供的选项选择,其他未提供字典的字段按业务代码填写。</p>
767
- <el-form :model="form" label-position="top" :disabled="editorDisabled" @submit.prevent="submit">
789
+ <el-form class="dcps-forecast-form" :model="form" :inline="false" label-position="top" :disabled="editorDisabled" @submit.prevent="submit">
768
790
  <section v-for="group in visibleGroups" :key="group.title" class="editor-group" :aria-label="group.title">
769
791
  <h3>{{ group.title }}</h3>
770
792
  <div class="editor-fields">
@@ -805,6 +827,14 @@ watch([detailDialogVisible, detailDialogPredRefNo], ([visible]) => {
805
827
  >
806
828
  <el-option v-for="option in payDirecOptions" :key="option.value" :label="option.label" :value="option.value" />
807
829
  </el-select>
830
+ <el-select
831
+ v-else-if="field.kind === 'paymentChannel'"
832
+ v-model="form.payChannel"
833
+ placeholder="请选择支付渠道"
834
+ clearable
835
+ >
836
+ <el-option v-for="option in payChannelOptions" :key="option.value" :label="option.label" :value="option.value" />
837
+ </el-select>
808
838
  <el-input
809
839
  v-else-if="field.kind === 'textarea'"
810
840
  v-model="form[field.key]"
@@ -843,7 +873,7 @@ watch([detailDialogVisible, detailDialogPredRefNo], ([visible]) => {
843
873
  </main>
844
874
 
845
875
  <!-- 详情页 -->
846
- <main v-else-if="isDetail" class="page-shell">
876
+ <main v-else-if="isDetail" class="dcps-forecast-shell">
847
877
  <el-card class="shell-header" shadow="never" :body-style="{ padding: '10px' }">
848
878
  <div class="shell-heading">
849
879
  <el-button class="shell-back" :disabled="detailLoading" @click="backToList">
@@ -896,9 +926,11 @@ watch([detailDialogVisible, detailDialogPredRefNo], ([visible]) => {
896
926
  <el-option v-for="option in payDirecOptions" :key="option.value" :label="option.label" :value="option.value" />
897
927
  </el-select>
898
928
  </el-form-item>
899
- <!-- label 为查询字段名称,输入框较窄,占位文案统一为简短提示。 -->
900
- <el-form-item v-for="[key, label] in listTextFilters" :key="key" :label="label">
901
- <el-input v-model="listFilters[key]" placeholder="请输入" :maxlength="200" clearable />
929
+ <el-form-item v-for="filter in listAdditionalFilters" :key="filter.key" :label="filter.label">
930
+ <el-select v-if="filter.options" v-model="listFilters[filter.key]" placeholder="全部" clearable>
931
+ <el-option v-for="option in filter.options" :key="option.value" :label="option.label" :value="option.value" />
932
+ </el-select>
933
+ <el-input v-else v-model="listFilters[filter.key]" placeholder="请输入" :maxlength="200" clearable />
902
934
  </el-form-item>
903
935
  <el-form-item label="排序规则">
904
936
  <el-select v-model="listFilters.sortRule" clearable placeholder="默认排序">
@@ -984,8 +1016,8 @@ watch([detailDialogVisible, detailDialogPredRefNo], ([visible]) => {
984
1016
  max-width: 100%;
985
1017
  flex-direction: column;
986
1018
  gap: 5px;
987
- height: calc(100vh - var(--dpcs-host-layout-height));
988
- height: calc(100dvh - var(--dpcs-host-layout-height));
1019
+ height: calc(100vh - var(--dpcs-host-layout-height, 0px));
1020
+ height: calc(100dvh - var(--dpcs-host-layout-height, 0px));
989
1021
  min-width: 0;
990
1022
  min-height: 0;
991
1023
  padding: 5px;
@@ -1019,13 +1051,15 @@ watch([detailDialogVisible, detailDialogPredRefNo], ([visible]) => {
1019
1051
 
1020
1052
  /* ---------- 新增 / 修改、详情页外壳 ---------- */
1021
1053
  /* 与列表页面一致:扣除宿主占用高度后,把剩余空间分给内容区,内容区内部滚动。 */
1022
- .page-shell {
1054
+ .dcps-forecast-shell {
1023
1055
  box-sizing: border-box;
1024
1056
  display: flex;
1057
+ width: 100%;
1058
+ max-width: 100%;
1025
1059
  flex-direction: column;
1026
1060
  gap: 5px;
1027
- height: calc(100vh - var(--dpcs-host-layout-height));
1028
- height: calc(100dvh - var(--dpcs-host-layout-height));
1061
+ height: calc(100vh - var(--dpcs-host-layout-height, 0px));
1062
+ height: calc(100dvh - var(--dpcs-host-layout-height, 0px));
1029
1063
  min-width: 0;
1030
1064
  min-height: 0;
1031
1065
  padding: 5px;
@@ -1039,34 +1073,30 @@ watch([detailDialogVisible, detailDialogPredRefNo], ([visible]) => {
1039
1073
  .shell-title { margin: 0; color: var(--el-text-color-primary); font-size: 16px; font-weight: 600; line-height: 22px; }
1040
1074
 
1041
1075
  /* ---------- 新增 / 修改页 ---------- */
1042
- .editor-card { flex: 1; min-height: 0; min-width: 0; }
1043
- .editor-body { display: flex; height: 100%; min-height: 0; flex-direction: column; gap: 10px; }
1044
- .editor-scroll { flex: 1; min-height: 0; padding-right: 2px; overflow-y: auto; }
1076
+ .dcps-forecast-shell .editor-card { display: flex; flex: 1; flex-direction: column; min-height: 0; min-width: 0; }
1077
+ /* 显式建立卡片内容区的高度链,不依赖宿主的 Element Plus 卡片布局。 */
1078
+ .dcps-forecast-shell .editor-card > :deep(.el-card__body) { box-sizing: border-box; display: flex; flex: 1; flex-direction: column; min-width: 0; min-height: 0; overflow: hidden; }
1079
+ .editor-body { display: flex; flex: 1; width: 100%; min-width: 0; min-height: 0; flex-direction: column; gap: 10px; }
1080
+ .editor-scroll { flex: 1; min-width: 0; min-height: 0; padding-right: 2px; overflow-y: auto; }
1045
1081
  .editor-load-error { margin-bottom: 12px; }
1046
1082
  .editor-note { margin: 0 0 12px; color: var(--el-text-color-secondary); font-size: 12px; line-height: 1.6; }
1047
1083
  .editor-group + .editor-group { margin-top: 10px; padding-top: 12px; border-top: 1px solid var(--el-border-color-lighter); }
1048
1084
  .editor-group h3 { margin: 0 0 12px; color: var(--el-text-color-primary); font-size: 13px; font-weight: 600; line-height: 18px; }
1049
- .editor-fields { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); column-gap: 18px; }
1050
- .editor-fields :deep(.el-form-item) { min-width: 0; margin-bottom: 14px; }
1051
- .editor-fields :deep(.el-form-item__label) { display: flex; align-items: center; gap: 6px; margin-bottom: 5px; padding: 0; line-height: 20px; }
1052
- .editor-fields :deep(.el-date-editor.el-input), .editor-fields :deep(.el-select) { width: 100%; }
1085
+ .dcps-forecast-form { width: 100%; min-width: 0; margin: 0; }
1086
+ /* 以实际内容宽度分列:每列至少 240px,最多四列;54px 是三处 18px 列间距。 */
1087
+ .editor-fields { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, max(240px, calc((100% - 54px) / 4))), 1fr)); column-gap: 18px; }
1088
+ /* 仅约束此表单,避免宿主的横向表单、右对齐标签或固定控件宽度影响移植布局。 */
1089
+ .dcps-forecast-form .editor-fields :deep(.el-form-item) { display: flex; flex-direction: column; align-items: stretch; width: 100%; min-width: 0; margin: 0 0 14px; }
1090
+ .dcps-forecast-form .editor-fields :deep(.el-form-item__label-wrap) { width: 100%; margin: 0; }
1091
+ .dcps-forecast-form .editor-fields :deep(.el-form-item__label) { display: flex; float: none; align-items: center; justify-content: flex-start; gap: 6px; width: 100%; height: auto; margin: 0 0 5px; padding: 0; line-height: 20px; text-align: left; }
1092
+ .dcps-forecast-form .editor-fields :deep(.el-form-item__content) { width: 100%; min-width: 0; margin-left: 0; }
1093
+ .dcps-forecast-form .editor-fields :deep(.el-input), .dcps-forecast-form .editor-fields :deep(.el-textarea), .dcps-forecast-form .editor-fields :deep(.el-date-editor), .dcps-forecast-form .editor-fields :deep(.el-select) { box-sizing: border-box; width: 100%; min-width: 0; max-width: 100%; }
1053
1094
  .editor-field--wide { grid-column: 1 / -1; }
1054
1095
  .field-unavailable { color: var(--el-text-color-secondary); font-size: 11px; font-weight: 400; }
1055
- .editor-footer { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px 12px; padding-top: 10px; border-top: 1px solid var(--el-border-color-lighter); }
1096
+ .editor-footer { display: flex; flex: 0 0 auto; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px 12px; padding-top: 10px; border-top: 1px solid var(--el-border-color-lighter); }
1056
1097
  .editor-tip { color: var(--el-text-color-secondary); font-size: 12px; }
1057
1098
  .editor-error { margin: 0; padding: 6px 10px; border: 1px solid var(--el-color-danger-light-7); border-radius: 4px; background: var(--el-color-danger-light-9); color: var(--el-color-danger); font-size: 12px; line-height: 1.6; }
1058
1099
 
1059
- @media (max-width: 1400px) {
1060
- .editor-fields { grid-template-columns: repeat(3, minmax(0, 1fr)); }
1061
- }
1062
- @media (max-width: 1000px) {
1063
- .editor-fields { grid-template-columns: repeat(2, minmax(0, 1fr)); }
1064
- }
1065
- @media (max-width: 600px) {
1066
- .editor-fields { grid-template-columns: minmax(0, 1fr); }
1067
- .editor-field--wide { grid-column: auto; }
1068
- }
1069
-
1070
1100
  /* ---------- 详情页 ---------- */
1071
1101
  .detail-card { flex: 1; min-height: 0; min-width: 0; }
1072
1102
  .detail-scroll { height: 100%; padding-right: 2px; overflow-y: auto; }
@@ -23,9 +23,9 @@ export interface Tam120501001InBody {
23
23
  groundBranchName?: string
24
24
  /** 联系人 */
25
25
  linkMan?: string
26
- /** 支付渠道 */
26
+ /** 支付渠道:8 数字人民币。 */
27
27
  payChannel?: string
28
- /** 收支方向 */
28
+ /** 收支方向:1 收入、2 支出。 */
29
29
  payDirec: string
30
30
  /** 联系电话 */
31
31
  phoneNo?: string
@@ -63,9 +63,9 @@ export interface Tam120501002InBody {
63
63
  groundBranchName?: string
64
64
  /** 联系人 */
65
65
  linkMan?: string
66
- /** 支付渠道 */
66
+ /** 支付渠道:8 数字人民币。 */
67
67
  payChannel?: string
68
- /** 收支方向 */
68
+ /** 收支方向:1 收入、2 支出。 */
69
69
  payDirec?: string
70
70
  /** 联系电话 */
71
71
  phoneNo?: string
@@ -101,11 +101,11 @@ export interface Tam140501001InBody {
101
101
  endTransAmt?: string
102
102
  /** 落地机构 */
103
103
  groundBranch?: string
104
- /** 支付渠道 */
104
+ /** 支付渠道:8 数字人民币。 */
105
105
  payChannel?: string
106
- /** 收支方向 */
106
+ /** 收支方向:1 收入、2 支出。 */
107
107
  payDirec?: string
108
- /** 预报状态 */
108
+ /** 预报状态:1 正常预报、2 延迟预报、3 正常预报正常删除、4 正常预报延迟删除、5 延迟预报延时删除、7 正常预报新增超时、8 延迟预报新增超时。 */
109
109
  predStatus?: string
110
110
  /** 排序 */
111
111
  sortRule?: string
@@ -113,7 +113,7 @@ export interface Tam140501001InBody {
113
113
  startTransAmt?: string
114
114
  /** 交易时间 */
115
115
  tranDate: string
116
- /** 核销状态 */
116
+ /** 核销状态:1 未核销、2 已核销、3 部分核销。 */
117
117
  verifyStatus?: string
118
118
  }
119
119
 
@@ -145,9 +145,9 @@ export interface Tam140501001OutBodyResultList {
145
145
  groundBranch?: string
146
146
  /** 机构代码 */
147
147
  groundBranchCode?: string
148
- /** 支付渠道 */
148
+ /** 支付渠道:8 数字人民币。 */
149
149
  payChannel?: string
150
- /** 收支方向 */
150
+ /** 收支方向:1 收入、2 支出。 */
151
151
  payDirec?: string
152
152
  /** 预报金额 */
153
153
  predAmt?: string
@@ -157,7 +157,7 @@ export interface Tam140501001OutBodyResultList {
157
157
  predDate?: string
158
158
  /** 预报流水号 */
159
159
  predRefNo?: string
160
- /** 预报状态 */
160
+ /** 预报状态:1 正常预报、2 延迟预报、3 正常预报正常删除、4 正常预报延迟删除、5 延迟预报延时删除、7 正常预报新增超时、8 延迟预报新增超时。 */
161
161
  predStatus?: string
162
162
  /** 标准名称 */
163
163
  standardName?: string
@@ -165,7 +165,7 @@ export interface Tam140501001OutBodyResultList {
165
165
  tranDate?: string
166
166
  /** 已核销金额 */
167
167
  verifyAmt?: string
168
- /** 核销状态 */
168
+ /** 核销状态:1 未核销、2 已核销、3 部分核销。 */
169
169
  verifyStatus?: string
170
170
  }
171
171
 
@@ -189,15 +189,15 @@ export interface Tam140501002OutBody {
189
189
  edusFlag?: string
190
190
  /** 落地机构名称 */
191
191
  groundBranchName?: string
192
- /** 支付渠道 */
192
+ /** 支付渠道:8 数字人民币。 */
193
193
  payChannel?: string
194
- /** 收支方向 */
194
+ /** 收支方向:1 收入、2 支出。 */
195
195
  payDirec?: string
196
196
  /** 预报金额 */
197
197
  predAmt?: string
198
198
  /** 预报流水号 */
199
199
  predRefNo?: string
200
- /** 预报状态 */
200
+ /** 预报状态:1 正常预报、2 延迟预报、3 正常预报正常删除、4 正常预报延迟删除、5 延迟预报延时删除、7 正常预报新增超时、8 延迟预报新增超时。 */
201
201
  predStatus?: string
202
202
  /** 标准名称 */
203
203
  standardName?: string
@@ -205,7 +205,7 @@ export interface Tam140501002OutBody {
205
205
  tranDate?: string
206
206
  /** 已核销金额 */
207
207
  verifyAmt?: string
208
- /** 核销状态 */
208
+ /** 核销状态:1 未核销、2 已核销、3 部分核销。 */
209
209
  verifyStatus?: string
210
210
  }
211
211
 
@@ -4,7 +4,6 @@ import type {
4
4
  ForecastQueryParams,
5
5
  Tam120502002InBody,
6
6
  Tam120502003InBody,
7
- Tam140502001OutBody,
8
7
  } from './typs'
9
8
 
10
9
  // 同一操作的相同请求失败后复用流水号,避免响应丢失后重试导致重复记账。
@@ -51,33 +50,14 @@ export default {
51
50
  * clientName 为客户名称,competName 为交易对手名称,payDirec 为收支方向(1 收入、2 支出),
52
51
  * startTransAmt、endTransAmt 为金额范围,verifyStatusList 待核销传 [1,3]、已核销传 [2]。
53
52
  */
54
- queryForecastApi: async (params: ForecastQueryParams) => {
55
- // 文档/页面的核销预报方向为 1/2,当前后端实际使用 I/O;只在 API 边界转换。
56
- const requestDirections: Record<string, string> = { '1': 'I', '2': 'O' }
57
- const responseDirections: Record<string, string> = { I: '1', O: '2' }
58
- const response = await baseHttpClient.post<any>('/TAM/0001/140502001', {
59
- ...params,
60
- payDirec: params.payDirec ? requestDirections[params.payDirec] ?? params.payDirec : undefined,
61
- })
62
- const body: Tam140502001OutBody | null = response.body
63
- if (!body || !Array.isArray(body.resultList)) return response
64
- return {
65
- ...response,
66
- body: {
67
- ...body,
68
- resultList: body.resultList.map((row) => ({
69
- ...row,
70
- payDirec: row.payDirec ? responseDirections[row.payDirec] ?? row.payDirec : row.payDirec,
71
- })),
72
- },
73
- }
74
- },
53
+ queryForecastApi: (params: ForecastQueryParams) =>
54
+ baseHttpClient.post<any>('/TAM/0001/140502001', params),
75
55
  /**
76
56
  * 分页查询核销流水信息。
77
57
  * @param params 查询参数:tranDate 为交易日期(必填,YYYYMMDD);pageIndex、pageSize 为页码和每页条数。
78
58
  * 业务筛选:busiType 为业务类型(201 兑回、202 兑出、203 付现),orgName 为我方机构,
79
59
  * payerName、payeeName 为付款人和收款人名称,
80
- * payDirec 为收支方向,startTransAmt、endTransAmt 为金额范围,verifyStatus 为核销状态。
60
+ * payDirec 为收支方向(I 收入、O 支出),startTransAmt、endTransAmt 为金额范围,verifyStatus 为核销状态。
81
61
  */
82
62
  queryFlowApi: (params: unknown) => baseHttpClient.post<any>("/TAM/0001/140502002", params)
83
63
  }
@@ -3,7 +3,7 @@ import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue'
3
3
  import { ElConfigProvider, ElMessage, ElMessageBox } from 'element-plus'
4
4
  import API from './api'
5
5
  import { dcpsRuntime } from '../runtime'
6
- import { transactionStatusLabels as tranStatusLabels } from '../dictionaries'
6
+ import { payChannelLabels, transactionStatusLabels as tranStatusLabels } from '../dictionaries'
7
7
  import { ArtDataTable, type ColumnOption, type PaginationOptions, type TableSettings } from '@/components/table'
8
8
  import { localSort } from '@/utils/table-sort'
9
9
  import type {
@@ -118,11 +118,9 @@ const compareAmounts = (left: string, right: string): number => {
118
118
 
119
119
  /** 业务类型字典:201 兑回、202 兑出、203 付现;超出字典的值保留原文。 */
120
120
  const busiTypeLabels: Record<string, string> = { '201': '兑回', '202': '兑出', '203': '付现' }
121
- /** 界面保留预报 1/2,API 层转换当前后端的 I/O;流水直接使用 I/O。 */
121
+ /** 预报使用 1 收入、2 支出;流水使用 I 收入、O 支出,查询按各自编码提交。 */
122
122
  const forecastPayDirecLabels: Record<string, string> = { '1': '收入', '2': '支出' }
123
- const flowPayDirecLabels: Record<string, string> = { I: '来账', O: '往账' }
124
- /** 支付渠道:核销预报为 8、流水为 5,均表示数字人民币;其余渠道保留原文。 */
125
- const payChannelLabels: Record<string, string> = { '5': '数字人民币', '8': '数字人民币' }
123
+ const flowPayDirecLabels: Record<string, string> = { I: '收入', O: '支出' }
126
124
  /** 响应核销状态字典;流水筛选仍按请求协议仅提供 1、2。 */
127
125
  const verifyStatusLabels: Record<string, string> = { '1': '未核销', '2': '已核销', '3': '部分核销' }
128
126
  const predStatusLabels: Record<string, string> = { '1': '正常预报', '2': '延迟预报' }
@@ -607,7 +605,7 @@ type FlowAppliedQuery = {
607
605
  busiType?: string // 业务类型:201 兑回、202 兑出、203 付现。
608
606
  payerName?: string // 付款人名称。
609
607
  payeeName?: string // 收款人名称。
610
- payDirec?: string // 收支方向:I 来账、O 往账。
608
+ payDirec?: string // 收支方向:I 收入、O 支出。
611
609
  startTransAmt?: string // 起始金额,查询提交时已由万元转换为元。
612
610
  endTransAmt?: string // 截止金额,查询提交时已由万元转换为元。
613
611
  verifyStatus?: string // 核销状态:1 未核销、2 已核销。
@@ -637,7 +635,7 @@ const flowTextFilters = [
637
635
 
638
636
  // 列表、分页与请求状态;请求序号防止旧响应覆盖新结果。
639
637
  const flowRows = ref<FlowRow[]>([])
640
- /** 只计算勾选流水的轧差:来账收入减去往账支出,未勾选时为 0.00。 */
638
+ /** 只计算勾选流水的轧差:收入减去支出,未勾选时为 0.00。 */
641
639
  const selectedFlowNetAmount = computed(() => formatCents(flowSelection.value.reduce((total, row) => {
642
640
  const direction = row.payDirec?.trim()
643
641
  if (direction === 'I') return total + amountToCents(row.tranAmt)
@@ -92,7 +92,7 @@ export interface Tam140502001InBody {
92
92
  competName?: string
93
93
  /** 截止金额 */
94
94
  endTransAmt?: string
95
- /** 支付渠道,8:数字人民币 */
95
+ /** 支付渠道:8 数字人民币。 */
96
96
  payChannel?: string
97
97
  /** 收支方向:1 收入、2 支出。 */
98
98
  payDirec?: string
@@ -126,7 +126,7 @@ export interface Tam140502001OutBodyResultList {
126
126
  edusFlag?: string
127
127
  /** 落地机构名称 */
128
128
  groundBranchName?: string
129
- /** 支付渠道,8:数字人民币 */
129
+ /** 支付渠道:8 数字人民币。 */
130
130
  payChannel?: string
131
131
  /** 收支方向:1 收入、2 支出。 */
132
132
  payDirec?: string
@@ -152,7 +152,7 @@ export interface Tam140502002InBody {
152
152
  endTransAmt?: string
153
153
  /** 我方机构 */
154
154
  orgName?: string
155
- /** 收支方向 */
155
+ /** 收支方向:I 收入、O 支出。 */
156
156
  payDirec?: string
157
157
  /** 收款人名称 */
158
158
  payeeName?: string
@@ -196,9 +196,9 @@ export interface Tam140502002OutBodyResultList {
196
196
  payBankName?: string
197
197
  /** 付款行行号 */
198
198
  payBankNo?: string
199
- /** 支付渠道,5:数字人民币 */
199
+ /** 支付渠道:8 数字人民币。 */
200
200
  payChannel?: string
201
- /** 收支方向,I=来账 O=往账 */
201
+ /** 收支方向:I 收入、O 支出。 */
202
202
  payDirec?: string
203
203
  /** 付款钱包ID */
204
204
  payWltId?: string