vue3-element-plus-app-chu 0.0.24 → 0.0.25
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/package.json
CHANGED
package/src/router/index.ts
CHANGED
|
@@ -6,6 +6,7 @@ import DigitalRmbForecast from '@/view/dcps/forecast/index.vue'
|
|
|
6
6
|
import DigitalRmbInjection from '@/view/dcps/funding/injection/index.vue'
|
|
7
7
|
import DigitalRmbWriteOff from '@/view/dcps/write-off/index.vue'
|
|
8
8
|
import DigitalRmbPositionEstimation from '@/view/dcps/estimation/index.vue'
|
|
9
|
+
import DigitalRmbFlowQuery from '@/view/dcps/flow-query/index.vue'
|
|
9
10
|
import DigitalRmbParameters from '@/view/dcps/parameters/index.vue'
|
|
10
11
|
|
|
11
12
|
declare module 'vue-router' {
|
|
@@ -57,6 +58,12 @@ const routes: RouteRecordRaw[] = [
|
|
|
57
58
|
},
|
|
58
59
|
],
|
|
59
60
|
},
|
|
61
|
+
{
|
|
62
|
+
path: 'flow-query',
|
|
63
|
+
name: 'flow-query',
|
|
64
|
+
component: DigitalRmbFlowQuery,
|
|
65
|
+
meta: { menu: 'flow-query', title: '数字人民币流水查询' },
|
|
66
|
+
},
|
|
60
67
|
{
|
|
61
68
|
path: 'auth',
|
|
62
69
|
name: 'auth',
|
package/src/router/menus.ts
CHANGED
|
@@ -23,6 +23,7 @@ export const layoutMenus: LayoutMenu[] = [
|
|
|
23
23
|
{ name: 'balance', title: '数字人民币账户行余额查询申请', compactTitle: '余额查询' },
|
|
24
24
|
],
|
|
25
25
|
},
|
|
26
|
+
{ name: 'flow-query', title: '数字人民币流水查询', compactTitle: '流水查询' },
|
|
26
27
|
{ name: 'auth', title: '数字人民币授权', compactTitle: '授权' },
|
|
27
28
|
{ name: 'write-off', title: '数字人民币核销', compactTitle: '核销' },
|
|
28
29
|
{ name: 'parameters', title: '数字人民币参数管理', compactTitle: '参数管理' },
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import baseHttpClient from '@chic/http'
|
|
2
|
+
import type { FlowQueryParams } from './typs'
|
|
3
|
+
import type { Tam140502002OutBody } from './typs'
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
/**
|
|
7
|
+
* 分页查询数字人民币流水信息。
|
|
8
|
+
* 接口:140502002 头寸核销-流水查询(/TAM/0001/140502002)。
|
|
9
|
+
* @param params tranDate 交易日期(必填,YYYYMMDD);pageIndex、pageSize 分页;
|
|
10
|
+
* orgName 我方机构,payerName/payeeName 付款人/收款人名称,
|
|
11
|
+
* payDirec 收支方向,startTransAmt/endTransAmt 金额范围,verifyStatus 核销状态。
|
|
12
|
+
*/
|
|
13
|
+
queryFlowApi: (params: FlowQueryParams) =>
|
|
14
|
+
baseHttpClient.post<Tam140502002OutBody>('/TAM/0001/140502002', params),
|
|
15
|
+
}
|
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { onBeforeUnmount, onMounted, reactive, ref } from 'vue'
|
|
3
|
+
import { ElMessage } from 'element-plus'
|
|
4
|
+
import API from './api'
|
|
5
|
+
import { dcpsRuntime } from '../runtime'
|
|
6
|
+
import { ArtDataTable, type ColumnOption, type PaginationOptions, type TableSettings } from '@/components/table'
|
|
7
|
+
import type { FlowRow, FlowFilters, FlowQueryParams } from './typs'
|
|
8
|
+
import type { Tam140502002OutBody } from './typs'
|
|
9
|
+
|
|
10
|
+
defineOptions({ name: 'DcpsFlowQueryPage' })
|
|
11
|
+
|
|
12
|
+
// ---------- 页面内工具函数 ----------
|
|
13
|
+
|
|
14
|
+
/** 列表查询结果:当前页记录和符合条件的总条数。 */
|
|
15
|
+
interface FlowPage<T> {
|
|
16
|
+
data: T[] // 当前页的记录列表。
|
|
17
|
+
total: number // 符合查询条件的总记录数。
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** 校验公共响应头;retCode 不是 00000 时按服务端提示或 fallback 抛错。 */
|
|
21
|
+
const ensureSuccess = <T,>(response: any, fallback: string): T | null => {
|
|
22
|
+
if (response?.head?.retCode !== '00000') {
|
|
23
|
+
throw new Error(response?.head?.retMsg?.trim() || fallback)
|
|
24
|
+
}
|
|
25
|
+
return response.body
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** 校验查询响应并取出当前页数据。 */
|
|
29
|
+
const readPage = <R extends { resultList?: unknown[]; totalCount?: unknown }>(
|
|
30
|
+
body: R | null,
|
|
31
|
+
fallback: string,
|
|
32
|
+
): FlowPage<NonNullable<R['resultList']>[number]> => {
|
|
33
|
+
if (!body || !Array.isArray(body.resultList)) throw new Error(fallback)
|
|
34
|
+
const totalText = String(body.totalCount ?? body.resultList.length)
|
|
35
|
+
const total = Number(totalText)
|
|
36
|
+
if (!/^\d+$/.test(totalText) || !Number.isSafeInteger(total)) throw new Error('查询返回的总条数无效')
|
|
37
|
+
return { data: body.resultList, total }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** 提取可展示的错误信息;无法识别时给出统一提示。 */
|
|
41
|
+
const getErrorMessage = (error: unknown): string => {
|
|
42
|
+
if (error instanceof Error && error.message.trim()) return error.message
|
|
43
|
+
if (typeof error === 'string' && error.trim()) return error
|
|
44
|
+
return '操作失败,请稍后重试'
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** 判断是否为合法的 YYYYMMDD 日期。 */
|
|
48
|
+
const isValidDate = (value: string): boolean => {
|
|
49
|
+
if (!/^\d{8}$/.test(value)) return false
|
|
50
|
+
const year = Number(value.slice(0, 4))
|
|
51
|
+
const month = Number(value.slice(4, 6))
|
|
52
|
+
const day = Number(value.slice(6, 8))
|
|
53
|
+
if (year < 1 || month < 1 || month > 12 || day < 1) return false
|
|
54
|
+
const leap = year % 400 === 0 || (year % 4 === 0 && year % 100 !== 0)
|
|
55
|
+
const monthDays = [31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
|
56
|
+
return day <= (monthDays[month - 1] || 0)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** 把 YYYYMMDD 格式化为 YYYY-MM-DD 展示;空值显示横线,其他格式保留原文。 */
|
|
60
|
+
const formatDate = (value?: string): string => {
|
|
61
|
+
const text = value?.trim() || ''
|
|
62
|
+
if (!text) return '—'
|
|
63
|
+
return isValidDate(text) ? `${text.slice(0, 4)}-${text.slice(4, 6)}-${text.slice(6, 8)}` : text
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** 只接受十进制文本和合法千分位;保留全部小数位,避免改变输入精度。 */
|
|
67
|
+
const normalizeAmount = (value: string): string => {
|
|
68
|
+
let text = value.trim()
|
|
69
|
+
if (text.includes(',')) {
|
|
70
|
+
if (!/^[+-]?\d{1,3}(?:,\d{3})+(?:\.\d*)?$/.test(text)) return ''
|
|
71
|
+
text = text.replace(/,/g, '')
|
|
72
|
+
}
|
|
73
|
+
const match = /^([+-]?)(\d*)(?:\.(\d*))?$/.exec(text)
|
|
74
|
+
if (!match || (!match[2] && !match[3])) return ''
|
|
75
|
+
const integer = (match[2] || '0').replace(/^0+(?=\d)/, '')
|
|
76
|
+
const fraction = match[3] || ''
|
|
77
|
+
const negative = match[1] === '-' && /[1-9]/.test(integer + fraction)
|
|
78
|
+
return `${negative ? '-' : ''}${integer}${fraction ? `.${fraction}` : ''}`
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** 千分位展示至少两位小数,超过两位的小数原样保留,不做浮点数转换或舍入。 */
|
|
82
|
+
const formatAmount = (value?: string): string => {
|
|
83
|
+
const original = value?.trim() || ''
|
|
84
|
+
if (!original) return '—'
|
|
85
|
+
const normalized = normalizeAmount(original)
|
|
86
|
+
if (!normalized) return original
|
|
87
|
+
const negative = normalized.startsWith('-')
|
|
88
|
+
const [integer = '0', fraction = ''] = (negative ? normalized.slice(1) : normalized).split('.')
|
|
89
|
+
const grouped = integer.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
|
90
|
+
return `${negative ? '-' : ''}${grouped}.${fraction.padEnd(2, '0')}`
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** 比较两个标准化后的金额字符串,返回 -1/0/1。 */
|
|
94
|
+
const compareAmounts = (left: string, right: string): number => {
|
|
95
|
+
const leftText = normalizeAmount(left)
|
|
96
|
+
const rightText = normalizeAmount(right)
|
|
97
|
+
if (!leftText || !rightText) {
|
|
98
|
+
if (!leftText && !rightText) return 0
|
|
99
|
+
return leftText ? -1 : 1
|
|
100
|
+
}
|
|
101
|
+
const parts = (text: string) => {
|
|
102
|
+
const negative = text.startsWith('-')
|
|
103
|
+
const [integer = '0', fraction = ''] = (negative ? text.slice(1) : text).split('.')
|
|
104
|
+
return { negative, integer, fraction }
|
|
105
|
+
}
|
|
106
|
+
const a = parts(leftText)
|
|
107
|
+
const b = parts(rightText)
|
|
108
|
+
const precision = Math.max(a.fraction.length, b.fraction.length)
|
|
109
|
+
const toInteger = (amount: ReturnType<typeof parts>) =>
|
|
110
|
+
BigInt(amount.integer + amount.fraction.padEnd(precision, '0')) * (amount.negative ? -1n : 1n)
|
|
111
|
+
const aValue = toInteger(a)
|
|
112
|
+
const bValue = toInteger(b)
|
|
113
|
+
return aValue < bValue ? -1 : aValue > bValue ? 1 : 0
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** 业务类型字典:201 兑回、202 兑出、203 付现;超出字典的值保留原文。 */
|
|
117
|
+
const busiTypeLabels: Record<string, string> = { '201': '兑回', '202': '兑出', '203': '付现' }
|
|
118
|
+
/** 收支方向字典:I 来账、O 往账。 */
|
|
119
|
+
const payDirecLabels: Record<string, string> = { I: '来账', O: '往账' }
|
|
120
|
+
/** 支付渠道:5、8 均表示数字人民币,其余渠道保留原文。 */
|
|
121
|
+
const payChannelLabels: Record<string, string> = { '5': '数字人民币', '8': '数字人民币' }
|
|
122
|
+
/** 核销状态字典:1 未核销、2 已核销。 */
|
|
123
|
+
const verifyStatusLabels: Record<string, string> = { '1': '未核销', '2': '已核销' }
|
|
124
|
+
|
|
125
|
+
/** 读取字典文案;空值显示横线,未登记的代码保留原文展示。 */
|
|
126
|
+
const dictLabel = (labels: Record<string, string>, value?: string): string => {
|
|
127
|
+
const text = value?.trim() || ''
|
|
128
|
+
return text ? labels[text] ?? text : '—'
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** 校验金额文本:非负十进制,最多两位小数;返回标准化后的文本。 */
|
|
132
|
+
const validAmount = (value: string) => {
|
|
133
|
+
const normalized = normalizeAmount(value)
|
|
134
|
+
if (!normalized || normalized.startsWith('-') || (normalized.split('.')[1]?.length || 0) > 2) return ''
|
|
135
|
+
return normalized
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ---------- 查询条件与列表状态 ----------
|
|
139
|
+
|
|
140
|
+
let disposed = false // 页面是否已卸载,避免未完成请求继续更新界面。
|
|
141
|
+
|
|
142
|
+
// 默认查询条件;空字符串表示不限制该条件,重置时恢复此配置。
|
|
143
|
+
const createFlowFilters = () => ({
|
|
144
|
+
tranDate: dcpsRuntime.date, // 必填交易日期,格式为 YYYYMMDD。
|
|
145
|
+
orgName: '', // 我方机构。
|
|
146
|
+
payerName: '', // 付款人名称。
|
|
147
|
+
payeeName: '', // 收款人名称。
|
|
148
|
+
payDirec: '', // 收支方向:I 来账、O 往账。
|
|
149
|
+
startTransAmt: '', // 起始金额。
|
|
150
|
+
endTransAmt: '', // 截止金额。
|
|
151
|
+
verifyStatus: '', // 核销状态:1 未核销、2 已核销。
|
|
152
|
+
})
|
|
153
|
+
const flowFilters = ref<FlowFilters>(createFlowFilters())
|
|
154
|
+
let flowAppliedQuery: FlowQueryParams = { ...createFlowFilters(), pageIndex: 1, pageSize: 15 }
|
|
155
|
+
|
|
156
|
+
// 重复输入项共用一份配置,依次为字段、名称和输入框长度限制。
|
|
157
|
+
const flowTextFilters = [
|
|
158
|
+
['orgName', '我方机构', 160],
|
|
159
|
+
['payerName', '付款人名称', 180],
|
|
160
|
+
['payeeName', '收款人名称', 180],
|
|
161
|
+
] as const
|
|
162
|
+
|
|
163
|
+
const busiTypeOptions = Object.entries(busiTypeLabels).map(([value, label]) => ({ value, label }))
|
|
164
|
+
const payDirecOptions = Object.entries(payDirecLabels).map(([value, label]) => ({ value, label }))
|
|
165
|
+
const verifyStatusOptions = Object.entries(verifyStatusLabels).map(([value, label]) => ({ value, label }))
|
|
166
|
+
const payChannelOptions = Object.entries(payChannelLabels).map(([value, label]) => ({ value, label }))
|
|
167
|
+
|
|
168
|
+
// 列表、分页与请求状态;请求序号防止旧响应覆盖新结果。
|
|
169
|
+
const flowRows = ref<FlowRow[]>([])
|
|
170
|
+
const flowPagination = reactive({ current: 1, size: 15, total: 0 })
|
|
171
|
+
const flowPaginationOptions: PaginationOptions = { align: 'right', pageSizes: [15, 30, 50, 100], background: false }
|
|
172
|
+
const flowTableSettings = ref<TableSettings>({ size: 'small', stripe: true, border: true, headerBackground: true })
|
|
173
|
+
const flowLoading = ref(false)
|
|
174
|
+
const flowQueryError = ref('')
|
|
175
|
+
const flowTableRef = ref<InstanceType<typeof ArtDataTable> | null>(null)
|
|
176
|
+
let flowRequestId = 0
|
|
177
|
+
|
|
178
|
+
/** 生成普通文本列,默认将空值显示为横线。 */
|
|
179
|
+
const flowTextColumn = (prop: keyof FlowRow, label: string, width: number, visible = true): ColumnOption<FlowRow> => ({
|
|
180
|
+
prop, label, width, visible, showOverflowTooltip: true,
|
|
181
|
+
formatter: (row) => row[prop]?.trim() || '—',
|
|
182
|
+
})
|
|
183
|
+
/** 生成字典翻译列;未登记的代码保留原文展示。 */
|
|
184
|
+
const flowDictColumn = (prop: keyof FlowRow, label: string, width: number, labels: Record<string, string>): ColumnOption<FlowRow> => ({
|
|
185
|
+
...flowTextColumn(prop, label, width),
|
|
186
|
+
formatter: (row) => dictLabel(labels, row[prop]),
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
// 表格完整列配置;字段顺序即展示顺序,辅助字段默认隐藏。
|
|
190
|
+
const flowColumns: ColumnOption<FlowRow>[] = [
|
|
191
|
+
{ type: 'globalIndex', label: '序号', width: 60, align: 'center' },
|
|
192
|
+
flowTextColumn('refNo', '流水号', 190),
|
|
193
|
+
{ ...flowTextColumn('tranDate', '交易日期', 110), formatter: (row) => formatDate(row.tranDate) },
|
|
194
|
+
flowTextColumn('tranTime', '交易时间', 110),
|
|
195
|
+
flowDictColumn('payDirec', '收支方向', 90, payDirecLabels),
|
|
196
|
+
flowTextColumn('payerName', '付款人名称', 170),
|
|
197
|
+
flowTextColumn('payeeName', '收款人名称', 170),
|
|
198
|
+
{ prop: 'tranAmt', label: '交易金额(元)', width: 160, align: 'right', useSlot: true, slotName: 'tranAmount' },
|
|
199
|
+
flowDictColumn('payChannel', '支付渠道', 110, payChannelLabels),
|
|
200
|
+
flowDictColumn('busiType', '业务类型', 95, busiTypeLabels),
|
|
201
|
+
flowTextColumn('busiStatus', '业务状态', 110),
|
|
202
|
+
flowDictColumn('verifyStatus', '核销状态', 95, verifyStatusLabels),
|
|
203
|
+
flowTextColumn('branchName', '我方机构', 150),
|
|
204
|
+
flowTextColumn('collBankName', '收款行名称', 160, false),
|
|
205
|
+
flowTextColumn('payBankName', '付款行名称', 160, false),
|
|
206
|
+
flowTextColumn('branchCode', '机构行号', 150, false),
|
|
207
|
+
flowTextColumn('collBankNo', '收款行行号', 170, false),
|
|
208
|
+
flowTextColumn('payBankNo', '付款行行号', 170, false),
|
|
209
|
+
flowTextColumn('collWltId', '收款钱包ID', 190, false),
|
|
210
|
+
flowTextColumn('payWltId', '付款钱包ID', 190, false),
|
|
211
|
+
flowTextColumn('remark', '备注', 160, false),
|
|
212
|
+
]
|
|
213
|
+
|
|
214
|
+
// 请求序号防止旧响应覆盖新结果;页码越界时最多补查一次。
|
|
215
|
+
const loadFlowList = async () => {
|
|
216
|
+
if (disposed) return
|
|
217
|
+
const currentId = ++flowRequestId
|
|
218
|
+
const query = { ...flowAppliedQuery }
|
|
219
|
+
const pageSize = flowPagination.size
|
|
220
|
+
let pageIndex = flowPagination.current
|
|
221
|
+
flowLoading.value = true
|
|
222
|
+
flowQueryError.value = ''
|
|
223
|
+
flowTableRef.value?.getElTable()?.clearSelection()
|
|
224
|
+
try {
|
|
225
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
226
|
+
const response = await API.queryFlowApi({ ...query, pageIndex, pageSize })
|
|
227
|
+
if (currentId !== flowRequestId) return
|
|
228
|
+
const page = readPage<Tam140502002OutBody>(
|
|
229
|
+
ensureSuccess<Tam140502002OutBody>(response, '流水查询失败'),
|
|
230
|
+
'查询结果缺少流水列表,请联系服务端确认返回数据',
|
|
231
|
+
)
|
|
232
|
+
const lastPage = Math.max(1, Math.ceil(page.total / pageSize))
|
|
233
|
+
if (pageIndex > lastPage && attempt === 0) {
|
|
234
|
+
pageIndex = lastPage
|
|
235
|
+
continue
|
|
236
|
+
}
|
|
237
|
+
flowPagination.current = pageIndex
|
|
238
|
+
flowPagination.total = page.total
|
|
239
|
+
flowRows.value = page.data
|
|
240
|
+
return
|
|
241
|
+
}
|
|
242
|
+
} catch (error) {
|
|
243
|
+
if (currentId !== flowRequestId) return
|
|
244
|
+
flowRows.value = []
|
|
245
|
+
flowPagination.total = 0
|
|
246
|
+
flowQueryError.value = getErrorMessage(error)
|
|
247
|
+
} finally {
|
|
248
|
+
if (currentId === flowRequestId) flowLoading.value = false
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// 新查询从第一页开始;重置后复用同一查询流程。
|
|
253
|
+
const searchFlow = () => {
|
|
254
|
+
if (disposed) return
|
|
255
|
+
const source = flowFilters.value
|
|
256
|
+
if (!/^\d{8}$/.test(source.tranDate.trim())) return void ElMessage.warning('请选择交易日期')
|
|
257
|
+
const startTransAmt = validAmount(source.startTransAmt)
|
|
258
|
+
if (source.startTransAmt.trim() && !startTransAmt) {
|
|
259
|
+
return void ElMessage.warning('起始金额请输入非负数,最多保留两位小数')
|
|
260
|
+
}
|
|
261
|
+
const endTransAmt = validAmount(source.endTransAmt)
|
|
262
|
+
if (source.endTransAmt.trim() && !endTransAmt) {
|
|
263
|
+
return void ElMessage.warning('截止金额请输入非负数,最多保留两位小数')
|
|
264
|
+
}
|
|
265
|
+
if (startTransAmt && endTransAmt && compareAmounts(startTransAmt, endTransAmt) > 0) {
|
|
266
|
+
return void ElMessage.warning('起始金额不能大于截止金额')
|
|
267
|
+
}
|
|
268
|
+
// 只保留已填写的筛选条件;空字符串不发送,表示不限制该条件。
|
|
269
|
+
const query: FlowQueryParams = { tranDate: source.tranDate.trim(), pageIndex: 1, pageSize: flowPagination.size }
|
|
270
|
+
for (const [key] of flowTextFilters) {
|
|
271
|
+
const value = source[key].trim()
|
|
272
|
+
if (value) query[key] = value
|
|
273
|
+
}
|
|
274
|
+
if (source.payDirec.trim()) query.payDirec = source.payDirec.trim()
|
|
275
|
+
if (source.verifyStatus.trim()) query.verifyStatus = source.verifyStatus.trim()
|
|
276
|
+
if (startTransAmt) query.startTransAmt = startTransAmt
|
|
277
|
+
if (endTransAmt) query.endTransAmt = endTransAmt
|
|
278
|
+
flowAppliedQuery = query
|
|
279
|
+
void loadFlowList()
|
|
280
|
+
}
|
|
281
|
+
const resetFlowFilters = () => {
|
|
282
|
+
if (disposed) return
|
|
283
|
+
flowFilters.value = createFlowFilters()
|
|
284
|
+
searchFlow()
|
|
285
|
+
}
|
|
286
|
+
// 更新分页;current 为目标页码,size 为每页条数,切换条数时 current 传入 1。
|
|
287
|
+
const changeFlowPage = (current: number, size = flowPagination.size) => {
|
|
288
|
+
if (disposed) return
|
|
289
|
+
flowPagination.current = current
|
|
290
|
+
flowPagination.size = size
|
|
291
|
+
void loadFlowList()
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// 页面首次显示时,按默认条件加载流水列表。
|
|
295
|
+
onMounted(() => {
|
|
296
|
+
void loadFlowList()
|
|
297
|
+
})
|
|
298
|
+
// 页面离开后,未完成的请求不再更新界面或弹出消息。
|
|
299
|
+
onBeforeUnmount(() => {
|
|
300
|
+
disposed = true
|
|
301
|
+
flowRequestId += 1
|
|
302
|
+
})
|
|
303
|
+
</script>
|
|
304
|
+
|
|
305
|
+
<template>
|
|
306
|
+
<main class="dcps-page">
|
|
307
|
+
<section class="view-region">
|
|
308
|
+
<!-- 查询条件:控件尺寸跟随表格设置,卡片内边距为 10px,点击查询生效。 -->
|
|
309
|
+
<el-card class="flow-search" shadow="never" :body-style="{ padding: '10px' }">
|
|
310
|
+
<el-form class="filter-form" :model="flowFilters" :size="flowTableSettings.size" label-position="top" @submit.prevent="searchFlow">
|
|
311
|
+
<el-form-item class="filter-date" label="交易日期" required>
|
|
312
|
+
<el-date-picker v-model="flowFilters.tranDate" type="date" format="YYYY-MM-DD" value-format="YYYYMMDD" :clearable="false" :editable="false" />
|
|
313
|
+
</el-form-item>
|
|
314
|
+
<el-form-item class="filter-status" label="核销状态">
|
|
315
|
+
<el-select v-model="flowFilters.verifyStatus" clearable placeholder="不限">
|
|
316
|
+
<el-option v-for="option in verifyStatusOptions" :key="option.value" :label="option.label" :value="option.value" />
|
|
317
|
+
</el-select>
|
|
318
|
+
</el-form-item>
|
|
319
|
+
<el-form-item class="filter-status" label="收支方向">
|
|
320
|
+
<el-select v-model="flowFilters.payDirec" clearable placeholder="不限">
|
|
321
|
+
<el-option v-for="option in payDirecOptions" :key="option.value" :label="option.label" :value="option.value" />
|
|
322
|
+
</el-select>
|
|
323
|
+
</el-form-item>
|
|
324
|
+
<!-- prop 为查询字段,label 为字段名称,maxlength 为允许输入的最大字符数。 -->
|
|
325
|
+
<el-form-item v-for="[key, label, maxlength] in flowTextFilters" :key="key" :label="label">
|
|
326
|
+
<el-input v-model="flowFilters[key]" :placeholder="`输入${label}`" :maxlength="maxlength" clearable />
|
|
327
|
+
</el-form-item>
|
|
328
|
+
<el-form-item class="filter-amount" label="起始金额(元)">
|
|
329
|
+
<el-input v-model="flowFilters.startTransAmt" placeholder="不限制" inputmode="decimal" :maxlength="40" clearable />
|
|
330
|
+
</el-form-item>
|
|
331
|
+
<el-form-item class="filter-amount" label="截止金额(元)">
|
|
332
|
+
<el-input v-model="flowFilters.endTransAmt" placeholder="不限制" inputmode="decimal" :maxlength="40" clearable />
|
|
333
|
+
</el-form-item>
|
|
334
|
+
<el-space class="filter-actions" :size="8">
|
|
335
|
+
<el-button @click="resetFlowFilters">重置</el-button>
|
|
336
|
+
<el-button type="primary" native-type="submit" :loading="flowLoading">查询</el-button>
|
|
337
|
+
</el-space>
|
|
338
|
+
</el-form>
|
|
339
|
+
</el-card>
|
|
340
|
+
|
|
341
|
+
<el-alert v-if="flowQueryError" :title="flowQueryError" type="error" show-icon :closable="false">
|
|
342
|
+
<el-button link type="primary" :disabled="flowLoading" @click="void loadFlowList()">重新查询</el-button>
|
|
343
|
+
</el-alert>
|
|
344
|
+
|
|
345
|
+
<!-- 流水信息表格:分页由表格内置分页组件承载。 -->
|
|
346
|
+
<div class="table-region">
|
|
347
|
+
<ArtDataTable
|
|
348
|
+
ref="flowTableRef"
|
|
349
|
+
v-model:settings="flowTableSettings"
|
|
350
|
+
:show-search-bar="false"
|
|
351
|
+
class="flow-table"
|
|
352
|
+
fill
|
|
353
|
+
title="流水信息"
|
|
354
|
+
toolbar-layout="search,refresh,size,fullscreen,columns,settings"
|
|
355
|
+
:data="flowRows"
|
|
356
|
+
:columns="flowColumns"
|
|
357
|
+
:loading="flowLoading"
|
|
358
|
+
:pagination="flowPagination"
|
|
359
|
+
:pagination-options="flowPaginationOptions"
|
|
360
|
+
row-key="refNo"
|
|
361
|
+
:empty-text="flowQueryError ? '查询失败,请重新查询' : '暂无符合条件的流水信息'"
|
|
362
|
+
@pagination:current-change="changeFlowPage"
|
|
363
|
+
@pagination:size-change="(size: number) => changeFlowPage(1, size)"
|
|
364
|
+
@refresh="void loadFlowList()"
|
|
365
|
+
>
|
|
366
|
+
<!-- row 为当前行原始流水记录,金额字段单位为元。 -->
|
|
367
|
+
<template #tranAmount="{ row }"><span class="amount-cell">{{ formatAmount(row.tranAmt) }}</span></template>
|
|
368
|
+
</ArtDataTable>
|
|
369
|
+
</div>
|
|
370
|
+
</section>
|
|
371
|
+
</main>
|
|
372
|
+
</template>
|
|
373
|
+
|
|
374
|
+
<style scoped>
|
|
375
|
+
/* 页面先扣除宿主占用高度,再使用 flex 分配剩余高度,列表内部滚动并保留分页。 */
|
|
376
|
+
.dcps-page {
|
|
377
|
+
box-sizing: border-box;
|
|
378
|
+
display: flex;
|
|
379
|
+
width: 100%;
|
|
380
|
+
max-width: 100%;
|
|
381
|
+
flex-direction: column;
|
|
382
|
+
gap: 5px;
|
|
383
|
+
height: calc(100vh - var(--dpcs-host-layout-height));
|
|
384
|
+
height: calc(100dvh - var(--dpcs-host-layout-height));
|
|
385
|
+
min-height: 0;
|
|
386
|
+
min-width: 0;
|
|
387
|
+
padding: 5px;
|
|
388
|
+
overflow: hidden;
|
|
389
|
+
background: var(--el-bg-color-page, #f7f8fa);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/* 视图区域:纵向占父页面剩余高度,列表内部滚动并保留分页。 */
|
|
393
|
+
.view-region {
|
|
394
|
+
display: flex;
|
|
395
|
+
flex: 1;
|
|
396
|
+
flex-direction: column;
|
|
397
|
+
gap: 5px;
|
|
398
|
+
min-height: 0;
|
|
399
|
+
min-width: 0;
|
|
400
|
+
}
|
|
401
|
+
/* 筛选项压成一行,等分剩余宽度,窗口过窄时才换行并限制高度,为列表保留空间。 */
|
|
402
|
+
.flow-search {
|
|
403
|
+
flex: 0 0 auto;
|
|
404
|
+
max-height: min(38dvh, 320px);
|
|
405
|
+
overflow-y: auto;
|
|
406
|
+
}
|
|
407
|
+
.filter-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px 6px; }
|
|
408
|
+
.filter-form :deep(.el-form-item) { flex: 1 1 76px; min-width: 76px; margin: 0; }
|
|
409
|
+
.filter-form :deep(.el-form-item__label) { height: auto; margin-bottom: 4px; padding: 0; font-size: 12px; line-height: 16px; }
|
|
410
|
+
/* 下拉和日期控件撑满筛选格,避免宽度塌缩。 */
|
|
411
|
+
.filter-form :deep(.el-select), .filter-form :deep(.el-date-editor) { width: 100%; min-width: 0; }
|
|
412
|
+
.filter-form :deep(.filter-date) { flex: 1.5 0 116px; }
|
|
413
|
+
.filter-form :deep(.filter-status) { flex: 1.1 0 96px; }
|
|
414
|
+
.filter-form :deep(.filter-amount) { flex: 1.2 0 92px; }
|
|
415
|
+
.filter-actions { flex: 0 0 auto; }
|
|
416
|
+
.table-region { flex: 1; min-width: 0; min-height: 0; }
|
|
417
|
+
.flow-table { padding: 10px; }
|
|
418
|
+
.amount-cell { color: var(--el-text-color-primary); font-variant-numeric: tabular-nums; }
|
|
419
|
+
|
|
420
|
+
@media (max-width: 640px) {
|
|
421
|
+
.filter-form :deep(.el-form-item) { flex-basis: 100%; }
|
|
422
|
+
.filter-actions { margin-left: 0; }
|
|
423
|
+
}
|
|
424
|
+
</style>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** 数字人民币流水查询(140502002)的类型定义,复用核销页面的协议类型。 */
|
|
2
|
+
export type {
|
|
3
|
+
/** 140502002 请求体业务字段。 */
|
|
4
|
+
Tam140502002InBody,
|
|
5
|
+
/** 140502002 响应体。 */
|
|
6
|
+
Tam140502002OutBody,
|
|
7
|
+
/** 140502002 返回的单条流水记录。 */
|
|
8
|
+
Tam140502002OutBodyResultList,
|
|
9
|
+
/** 流水查询条件;空字符串表示不限制该条件。 */
|
|
10
|
+
FlowFilters,
|
|
11
|
+
/** 流水查询参数:必填 tranDate,分页从第 1 页开始。 */
|
|
12
|
+
FlowQueryParams,
|
|
13
|
+
/** 流水查询(140502002)返回的单条流水记录。 */
|
|
14
|
+
FlowRow,
|
|
15
|
+
} from '../write-off/typs'
|