Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
M
model_analysis
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
David Yang
model_analysis
Commits
00b6e86c
Commit
00b6e86c
authored
Sep 03, 2026
by
drigle
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: group model batches by model
parent
d99022c1
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
136 additions
and
33 deletions
+136
-33
manifest.json
public/manifest.json
+3
-2
model-monitor-source-fixtures.sql
scripts/mysql/model-monitor-source-fixtures.sql
+73
-5
Models.jsx
src/pages/project_manager_xy/Models.jsx
+58
-24
model-monitor.business-flow.md
src/pages/project_manager_xy/model-monitor.business-flow.md
+2
-2
No files found.
public/manifest.json
View file @
00b6e86c
{
"name"
:
"model_analysis"
,
"version"
:
"1.0.
2
"
,
"version"
:
"1.0.
3
"
,
"build"
:
"abc"
,
"description"
:
"merge master"
,
"date"
:
"2025-07-14 19:27:20"
,
"author"
:
"yang"
"author"
:
"yang"
,
"spa"
:
true
}
scripts/mysql/model-monitor-source-fixtures.sql
View file @
00b6e86c
-- MySQL 5.7+ fixture data for the model-monitor source connector.
-- This script is repeatable: existing fixture rows are updated by their stable keys.
-- Fixture coverage: 4 models, 4 batches per model, 2 calendar years.
CREATE
TABLE
IF
NOT
EXISTS
ANALYZE_MXVIEW_INFO
(
ID
VARCHAR
(
64
)
NOT
NULL
COMMENT
'来源模型 ID'
,
...
...
@@ -81,6 +82,22 @@ CREATE TABLE IF NOT EXISTS ANALYZE_MODEL_DATA_MX_411 (
KEY
IDX_ANALYZE_DATA_411_BATCH
(
MODEL_RUN_BATCH_ID
)
)
ENGINE
=
InnoDB
DEFAULT
CHARSET
=
utf8mb4
COMMENT
=
'授信敞口监测模型结果'
;
CREATE
TABLE
IF
NOT
EXISTS
ANALYZE_MODEL_DATA_MX_420
(
MODEL_ID
VARCHAR
(
64
)
NOT
NULL
COMMENT
'来源模型 ID'
,
MODEL_NAME
VARCHAR
(
128
)
NOT
NULL
COMMENT
'模型技术名称'
,
MODEL_RUN_BATCH_ID
VARCHAR
(
64
)
NOT
NULL
COMMENT
'来源跑批 ID'
,
MODEL_RUN_BATCH_DATE
DATETIME
(
3
)
NOT
NULL
COMMENT
'来源跑批时间'
,
REMARK
VARCHAR
(
1000
)
NULL
COMMENT
'来源备注'
,
LOAN_ID
VARCHAR
(
64
)
NOT
NULL
COMMENT
'贷款编号'
,
CUSTOMER_ID
VARCHAR
(
64
)
NOT
NULL
COMMENT
'客户编号'
,
OUTSTANDING_AMOUNT
DECIMAL
(
18
,
2
)
NOT
NULL
COMMENT
'逾期贷款余额'
,
DUE_DATE
DATETIME
(
3
)
NOT
NULL
COMMENT
'应还日期'
,
OVERDUE_DAYS
INT
NOT
NULL
COMMENT
'逾期天数'
,
IS_OVERDUE
TINYINT
(
1
)
NOT
NULL
COMMENT
'是否逾期'
,
UNIQUE
KEY
UK_ANALYZE_DATA_420_ROW
(
MODEL_RUN_BATCH_ID
,
LOAN_ID
),
KEY
IDX_ANALYZE_DATA_420_BATCH
(
MODEL_RUN_BATCH_ID
)
)
ENGINE
=
InnoDB
DEFAULT
CHARSET
=
utf8mb4
COMMENT
=
'贷款逾期监测模型结果'
;
START
TRANSACTION
;
INSERT
INTO
ANALYZE_MXVIEW_INFO
(
...
...
@@ -90,7 +107,8 @@ INSERT INTO ANALYZE_MXVIEW_INFO (
)
VALUES
(
'430'
,
'AML_CUSTOMER_RISK'
,
'客户洗钱风险模型'
,
'2026-08-26 08:00:00.000'
,
'enabled'
,
'applied'
,
'high'
,
'12'
,
'风险分析'
),
(
'412'
,
'TRANSACTION_ALERT'
,
'异常交易预警模型'
,
'2026-08-25 08:00:00.000'
,
'enabled'
,
'applied'
,
'medium'
,
'12'
,
'风险分析'
),
(
'411'
,
'CREDIT_EXPOSURE'
,
'授信敞口监测模型'
,
'2026-08-24 08:00:00.000'
,
'enabled'
,
'applied'
,
'medium'
,
'13'
,
'合规分析'
)
(
'411'
,
'CREDIT_EXPOSURE'
,
'授信敞口监测模型'
,
'2026-08-24 08:00:00.000'
,
'enabled'
,
'applied'
,
'medium'
,
'13'
,
'合规分析'
),
(
'420'
,
'LOAN_OVERDUE'
,
'贷款逾期监测模型'
,
'2026-09-01 08:00:00.000'
,
'enabled'
,
'applied'
,
'high'
,
'13'
,
'合规分析'
)
ON
DUPLICATE
KEY
UPDATE
MODEL_NAME
=
VALUES
(
MODEL_NAME
),
MODEL_ZH_NAME
=
VALUES
(
MODEL_ZH_NAME
),
...
...
@@ -109,12 +127,19 @@ INSERT INTO ANALYZE_MODEL_RUN_BATCH_INFO (
(
'690'
,
'430'
,
'AML_CUSTOMER_RISK'
,
'2026-08-26 08:00:00.000'
,
'ANALYZE_MODEL_DATA_MX_430'
,
'2026 年 8 月批次'
,
5
,
5
,
0
,
0
,
'success'
,
NULL
),
(
'652'
,
'430'
,
'AML_CUSTOMER_RISK'
,
'2026-07-31 08:00:00.000'
,
'ANALYZE_MODEL_DATA_MX_430'
,
'2026 年 7 月批次'
,
5
,
3
,
1
,
1
,
'success'
,
NULL
),
(
'590'
,
'430'
,
'AML_CUSTOMER_RISK'
,
'2025-12-31 08:00:00.000'
,
'ANALYZE_MODEL_DATA_MX_430'
,
'2025 年 12 月批次'
,
5
,
0
,
0
,
5
,
'success'
,
NULL
),
(
'691'
,
'430'
,
'AML_CUSTOMER_RISK'
,
'2026-09-01 08:00:00.000'
,
'ANALYZE_MODEL_DATA_MX_430'
,
'2026 年 9 月批次'
,
5
,
5
,
0
,
0
,
'success'
,
NULL
),
(
'670'
,
'412'
,
'TRANSACTION_ALERT'
,
'2026-08-25 08:00:00.000'
,
'ANALYZE_MODEL_DATA_MX_412'
,
'2026 年第 35 周'
,
7
,
7
,
0
,
0
,
'success'
,
NULL
),
(
'669'
,
'412'
,
'TRANSACTION_ALERT'
,
'2026-08-18 08:00:00.000'
,
'ANALYZE_MODEL_DATA_MX_412'
,
'2026 年第 34 周'
,
7
,
4
,
2
,
1
,
'success'
,
NULL
),
(
'570'
,
'412'
,
'TRANSACTION_ALERT'
,
'2025-12-29 08:00:00.000'
,
'ANALYZE_MODEL_DATA_MX_412'
,
'2025 年第 52 周'
,
7
,
0
,
0
,
7
,
'success'
,
NULL
),
(
'671'
,
'412'
,
'TRANSACTION_ALERT'
,
'2026-09-01 08:00:00.000'
,
'ANALYZE_MODEL_DATA_MX_412'
,
'2026 年第 36 周'
,
7
,
7
,
0
,
0
,
'success'
,
NULL
),
(
'630'
,
'411'
,
'CREDIT_EXPOSURE'
,
'2026-08-24 08:00:00.000'
,
'ANALYZE_MODEL_DATA_MX_411'
,
'2026 年 8 月批次'
,
4
,
4
,
0
,
0
,
'success'
,
NULL
),
(
'629'
,
'411'
,
'CREDIT_EXPOSURE'
,
'2026-06-30 08:00:00.000'
,
'ANALYZE_MODEL_DATA_MX_411'
,
'2026 年第二季度'
,
4
,
2
,
1
,
1
,
'success'
,
NULL
),
(
'530'
,
'411'
,
'CREDIT_EXPOSURE'
,
'2025-12-31 08:00:00.000'
,
'ANALYZE_MODEL_DATA_MX_411'
,
'2025 年第四季度'
,
4
,
0
,
0
,
4
,
'success'
,
NULL
)
(
'530'
,
'411'
,
'CREDIT_EXPOSURE'
,
'2025-12-31 08:00:00.000'
,
'ANALYZE_MODEL_DATA_MX_411'
,
'2025 年第四季度'
,
4
,
0
,
0
,
4
,
'success'
,
NULL
),
(
'631'
,
'411'
,
'CREDIT_EXPOSURE'
,
'2026-09-01 08:00:00.000'
,
'ANALYZE_MODEL_DATA_MX_411'
,
'2026 年 9 月批次'
,
4
,
4
,
0
,
0
,
'success'
,
NULL
),
(
'720'
,
'420'
,
'LOAN_OVERDUE'
,
'2026-09-01 08:00:00.000'
,
'ANALYZE_MODEL_DATA_MX_420'
,
'2026 年 9 月第一批'
,
4
,
4
,
0
,
0
,
'success'
,
NULL
),
(
'719'
,
'420'
,
'LOAN_OVERDUE'
,
'2026-08-25 08:00:00.000'
,
'ANALYZE_MODEL_DATA_MX_420'
,
'2026 年 8 月第四批'
,
4
,
3
,
1
,
0
,
'success'
,
NULL
),
(
'718'
,
'420'
,
'LOAN_OVERDUE'
,
'2026-08-18 08:00:00.000'
,
'ANALYZE_MODEL_DATA_MX_420'
,
'2026 年 8 月第三批'
,
4
,
2
,
1
,
1
,
'success'
,
NULL
),
(
'717'
,
'420'
,
'LOAN_OVERDUE'
,
'2025-12-22 08:00:00.000'
,
'ANALYZE_MODEL_DATA_MX_420'
,
'2025 年历史批次'
,
4
,
1
,
1
,
2
,
'success'
,
NULL
)
ON
DUPLICATE
KEY
UPDATE
MODEL_ID
=
VALUES
(
MODEL_ID
),
MODEL_NAME
=
VALUES
(
MODEL_NAME
),
...
...
@@ -147,7 +172,12 @@ INSERT INTO ANALYZE_MODEL_DATA_MX_430 (
(
'430'
,
'AML_CUSTOMER_RISK'
,
'590'
,
'2025-12-31 08:00:00.000'
,
NULL
,
'C0002'
,
'2025-12-04 00:00:00.000'
,
'海川商贸'
,
'高'
,
80
.
00
,
1
),
(
'430'
,
'AML_CUSTOMER_RISK'
,
'590'
,
'2025-12-31 08:00:00.000'
,
NULL
,
'C0003'
,
'2025-12-05 00:00:00.000'
,
'恒信科技'
,
'中'
,
71
.
00
,
0
),
(
'430'
,
'AML_CUSTOMER_RISK'
,
'590'
,
'2025-12-31 08:00:00.000'
,
NULL
,
'C0004'
,
'2025-12-06 00:00:00.000'
,
'嘉禾供应链'
,
'中'
,
62
.
00
,
0
),
(
'430'
,
'AML_CUSTOMER_RISK'
,
'590'
,
'2025-12-31 08:00:00.000'
,
NULL
,
'C0005'
,
'2025-12-07 00:00:00.000'
,
'远景投资'
,
'低'
,
53
.
00
,
0
)
(
'430'
,
'AML_CUSTOMER_RISK'
,
'590'
,
'2025-12-31 08:00:00.000'
,
NULL
,
'C0005'
,
'2025-12-07 00:00:00.000'
,
'远景投资'
,
'低'
,
53
.
00
,
0
),
(
'430'
,
'AML_CUSTOMER_RISK'
,
'691'
,
'2026-09-01 08:00:00.000'
,
NULL
,
'C0001'
,
'2026-09-01 00:00:00.000'
,
'华远实业'
,
'高'
,
94
.
00
,
1
),
(
'430'
,
'AML_CUSTOMER_RISK'
,
'691'
,
'2026-09-01 08:00:00.000'
,
NULL
,
'C0002'
,
'2026-09-02 00:00:00.000'
,
'海川商贸'
,
'高'
,
85
.
00
,
1
),
(
'430'
,
'AML_CUSTOMER_RISK'
,
'691'
,
'2026-09-01 08:00:00.000'
,
NULL
,
'C0003'
,
'2026-09-03 00:00:00.000'
,
'恒信科技'
,
'中'
,
76
.
00
,
0
),
(
'430'
,
'AML_CUSTOMER_RISK'
,
'691'
,
'2026-09-01 08:00:00.000'
,
NULL
,
'C0004'
,
'2026-09-04 00:00:00.000'
,
'嘉禾供应链'
,
'中'
,
67
.
00
,
0
),
(
'430'
,
'AML_CUSTOMER_RISK'
,
'691'
,
'2026-09-01 08:00:00.000'
,
NULL
,
'C0005'
,
'2026-09-05 00:00:00.000'
,
'远景投资'
,
'低'
,
58
.
00
,
0
)
ON
DUPLICATE
KEY
UPDATE
MODEL_ID
=
VALUES
(
MODEL_ID
),
MODEL_NAME
=
VALUES
(
MODEL_NAME
),
MODEL_RUN_BATCH_DATE
=
VALUES
(
MODEL_RUN_BATCH_DATE
),
REMARK
=
VALUES
(
REMARK
),
...
...
@@ -179,7 +209,14 @@ INSERT INTO ANALYZE_MODEL_DATA_MX_412 (
(
'412'
,
'TRANSACTION_ALERT'
,
'570'
,
'2025-12-29 08:00:00.000'
,
NULL
,
'AL52004'
,
'监测账户 4'
,
385500
.
00
,
'2025-12-25 03:30:00.000'
,
'交易对手集中度异常'
),
(
'412'
,
'TRANSACTION_ALERT'
,
'570'
,
'2025-12-29 08:00:00.000'
,
NULL
,
'AL52005'
,
'监测账户 5'
,
459000
.
00
,
'2025-12-26 04:30:00.000'
,
'短期高频大额交易'
),
(
'412'
,
'TRANSACTION_ALERT'
,
'570'
,
'2025-12-29 08:00:00.000'
,
NULL
,
'AL52006'
,
'监测账户 6'
,
532500
.
00
,
'2025-12-27 05:30:00.000'
,
'交易对手集中度异常'
),
(
'412'
,
'TRANSACTION_ALERT'
,
'570'
,
'2025-12-29 08:00:00.000'
,
NULL
,
'AL52007'
,
'监测账户 7'
,
606000
.
00
,
'2025-12-28 06:30:00.000'
,
'短期高频大额交易'
)
(
'412'
,
'TRANSACTION_ALERT'
,
'570'
,
'2025-12-29 08:00:00.000'
,
NULL
,
'AL52007'
,
'监测账户 7'
,
606000
.
00
,
'2025-12-28 06:30:00.000'
,
'短期高频大额交易'
),
(
'412'
,
'TRANSACTION_ALERT'
,
'671'
,
'2026-09-01 08:00:00.000'
,
NULL
,
'AL36001'
,
'监测账户 1'
,
190000
.
00
,
'2026-08-25 00:30:00.000'
,
'短期高频大额交易'
),
(
'412'
,
'TRANSACTION_ALERT'
,
'671'
,
'2026-09-01 08:00:00.000'
,
NULL
,
'AL36002'
,
'监测账户 2'
,
263500
.
00
,
'2026-08-26 01:30:00.000'
,
'交易对手集中度异常'
),
(
'412'
,
'TRANSACTION_ALERT'
,
'671'
,
'2026-09-01 08:00:00.000'
,
NULL
,
'AL36003'
,
'监测账户 3'
,
337000
.
00
,
'2026-08-27 02:30:00.000'
,
'短期高频大额交易'
),
(
'412'
,
'TRANSACTION_ALERT'
,
'671'
,
'2026-09-01 08:00:00.000'
,
NULL
,
'AL36004'
,
'监测账户 4'
,
410500
.
00
,
'2026-08-28 03:30:00.000'
,
'交易对手集中度异常'
),
(
'412'
,
'TRANSACTION_ALERT'
,
'671'
,
'2026-09-01 08:00:00.000'
,
NULL
,
'AL36005'
,
'监测账户 5'
,
484000
.
00
,
'2026-08-29 04:30:00.000'
,
'短期高频大额交易'
),
(
'412'
,
'TRANSACTION_ALERT'
,
'671'
,
'2026-09-01 08:00:00.000'
,
NULL
,
'AL36006'
,
'监测账户 6'
,
557500
.
00
,
'2026-08-30 05:30:00.000'
,
'交易对手集中度异常'
),
(
'412'
,
'TRANSACTION_ALERT'
,
'671'
,
'2026-09-01 08:00:00.000'
,
NULL
,
'AL36007'
,
'监测账户 7'
,
631000
.
00
,
'2026-08-31 06:30:00.000'
,
'短期高频大额交易'
)
ON
DUPLICATE
KEY
UPDATE
MODEL_ID
=
VALUES
(
MODEL_ID
),
MODEL_NAME
=
VALUES
(
MODEL_NAME
),
MODEL_RUN_BATCH_DATE
=
VALUES
(
MODEL_RUN_BATCH_DATE
),
REMARK
=
VALUES
(
REMARK
),
...
...
@@ -202,7 +239,11 @@ INSERT INTO ANALYZE_MODEL_DATA_MX_411 (
(
'411'
,
'CREDIT_EXPOSURE'
,
'530'
,
'2025-12-31 08:00:00.000'
,
NULL
,
'ORG1'
,
'2025-Q4'
,
'总行营业部'
,
10800000
.
00
,
7560000
.
00
,
0
),
(
'411'
,
'CREDIT_EXPOSURE'
,
'530'
,
'2025-12-31 08:00:00.000'
,
NULL
,
'ORG2'
,
'2025-Q4'
,
'华东分行'
,
13950000
.
00
,
11160000
.
00
,
0
),
(
'411'
,
'CREDIT_EXPOSURE'
,
'530'
,
'2025-12-31 08:00:00.000'
,
NULL
,
'ORG3'
,
'2025-Q4'
,
'华南分行'
,
17100000
.
00
,
15390000
.
00
,
0
),
(
'411'
,
'CREDIT_EXPOSURE'
,
'530'
,
'2025-12-31 08:00:00.000'
,
NULL
,
'ORG4'
,
'2025-Q4'
,
'西部中心'
,
20250000
.
00
,
20452500
.
00
,
1
)
(
'411'
,
'CREDIT_EXPOSURE'
,
'530'
,
'2025-12-31 08:00:00.000'
,
NULL
,
'ORG4'
,
'2025-Q4'
,
'西部中心'
,
20250000
.
00
,
20452500
.
00
,
1
),
(
'411'
,
'CREDIT_EXPOSURE'
,
'631'
,
'2026-09-01 08:00:00.000'
,
NULL
,
'ORG1'
,
'2026-09'
,
'总行营业部'
,
12200000
.
00
,
8784000
.
00
,
0
),
(
'411'
,
'CREDIT_EXPOSURE'
,
'631'
,
'2026-09-01 08:00:00.000'
,
NULL
,
'ORG2'
,
'2026-09'
,
'华东分行'
,
15750000
.
00
,
12915000
.
00
,
0
),
(
'411'
,
'CREDIT_EXPOSURE'
,
'631'
,
'2026-09-01 08:00:00.000'
,
NULL
,
'ORG3'
,
'2026-09'
,
'华南分行'
,
19300000
.
00
,
17756000
.
00
,
0
),
(
'411'
,
'CREDIT_EXPOSURE'
,
'631'
,
'2026-09-01 08:00:00.000'
,
NULL
,
'ORG4'
,
'2026-09'
,
'西部中心'
,
22850000
.
00
,
23377000
.
00
,
1
)
ON
DUPLICATE
KEY
UPDATE
MODEL_ID
=
VALUES
(
MODEL_ID
),
MODEL_NAME
=
VALUES
(
MODEL_NAME
),
MODEL_RUN_BATCH_DATE
=
VALUES
(
MODEL_RUN_BATCH_DATE
),
REMARK
=
VALUES
(
REMARK
),
...
...
@@ -210,4 +251,31 @@ ON DUPLICATE KEY UPDATE
CREDIT_LIMIT
=
VALUES
(
CREDIT_LIMIT
),
USED_AMOUNT
=
VALUES
(
USED_AMOUNT
),
OVER_LIMIT
=
VALUES
(
OVER_LIMIT
);
INSERT
INTO
ANALYZE_MODEL_DATA_MX_420
(
MODEL_ID
,
MODEL_NAME
,
MODEL_RUN_BATCH_ID
,
MODEL_RUN_BATCH_DATE
,
REMARK
,
LOAN_ID
,
CUSTOMER_ID
,
OUTSTANDING_AMOUNT
,
DUE_DATE
,
OVERDUE_DAYS
,
IS_OVERDUE
)
VALUES
(
'420'
,
'LOAN_OVERDUE'
,
'720'
,
'2026-09-01 08:00:00.000'
,
NULL
,
'LN72001'
,
'C0001'
,
850000
.
00
,
'2026-08-15 00:00:00.000'
,
17
,
1
),
(
'420'
,
'LOAN_OVERDUE'
,
'720'
,
'2026-09-01 08:00:00.000'
,
NULL
,
'LN72002'
,
'C0002'
,
420000
.
00
,
'2026-08-20 00:00:00.000'
,
12
,
1
),
(
'420'
,
'LOAN_OVERDUE'
,
'720'
,
'2026-09-01 08:00:00.000'
,
NULL
,
'LN72003'
,
'C0003'
,
275000
.
00
,
'2026-09-01 00:00:00.000'
,
0
,
0
),
(
'420'
,
'LOAN_OVERDUE'
,
'720'
,
'2026-09-01 08:00:00.000'
,
NULL
,
'LN72004'
,
'C0004'
,
960000
.
00
,
'2026-08-01 00:00:00.000'
,
31
,
1
),
(
'420'
,
'LOAN_OVERDUE'
,
'719'
,
'2026-08-25 08:00:00.000'
,
NULL
,
'LN71901'
,
'C0001'
,
835000
.
00
,
'2026-08-08 00:00:00.000'
,
17
,
1
),
(
'420'
,
'LOAN_OVERDUE'
,
'719'
,
'2026-08-25 08:00:00.000'
,
NULL
,
'LN71902'
,
'C0002'
,
410000
.
00
,
'2026-08-15 00:00:00.000'
,
10
,
1
),
(
'420'
,
'LOAN_OVERDUE'
,
'719'
,
'2026-08-25 08:00:00.000'
,
NULL
,
'LN71903'
,
'C0003'
,
265000
.
00
,
'2026-08-25 00:00:00.000'
,
0
,
0
),
(
'420'
,
'LOAN_OVERDUE'
,
'719'
,
'2026-08-25 08:00:00.000'
,
NULL
,
'LN71904'
,
'C0004'
,
945000
.
00
,
'2026-07-28 00:00:00.000'
,
28
,
1
),
(
'420'
,
'LOAN_OVERDUE'
,
'718'
,
'2026-08-18 08:00:00.000'
,
NULL
,
'LN71801'
,
'C0001'
,
820000
.
00
,
'2026-08-01 00:00:00.000'
,
17
,
1
),
(
'420'
,
'LOAN_OVERDUE'
,
'718'
,
'2026-08-18 08:00:00.000'
,
NULL
,
'LN71802'
,
'C0002'
,
400000
.
00
,
'2026-08-08 00:00:00.000'
,
10
,
1
),
(
'420'
,
'LOAN_OVERDUE'
,
'718'
,
'2026-08-18 08:00:00.000'
,
NULL
,
'LN71803'
,
'C0003'
,
255000
.
00
,
'2026-08-18 00:00:00.000'
,
0
,
0
),
(
'420'
,
'LOAN_OVERDUE'
,
'718'
,
'2026-08-18 08:00:00.000'
,
NULL
,
'LN71804'
,
'C0004'
,
930000
.
00
,
'2026-07-21 00:00:00.000'
,
28
,
1
),
(
'420'
,
'LOAN_OVERDUE'
,
'717'
,
'2025-12-22 08:00:00.000'
,
NULL
,
'LN71701'
,
'C0001'
,
805000
.
00
,
'2025-12-05 00:00:00.000'
,
17
,
1
),
(
'420'
,
'LOAN_OVERDUE'
,
'717'
,
'2025-12-22 08:00:00.000'
,
NULL
,
'LN71702'
,
'C0002'
,
390000
.
00
,
'2025-12-12 00:00:00.000'
,
10
,
1
),
(
'420'
,
'LOAN_OVERDUE'
,
'717'
,
'2025-12-22 08:00:00.000'
,
NULL
,
'LN71703'
,
'C0003'
,
245000
.
00
,
'2025-12-22 00:00:00.000'
,
0
,
0
),
(
'420'
,
'LOAN_OVERDUE'
,
'717'
,
'2025-12-22 08:00:00.000'
,
NULL
,
'LN71704'
,
'C0004'
,
915000
.
00
,
'2025-11-25 00:00:00.000'
,
31
,
1
)
ON
DUPLICATE
KEY
UPDATE
MODEL_ID
=
VALUES
(
MODEL_ID
),
MODEL_NAME
=
VALUES
(
MODEL_NAME
),
MODEL_RUN_BATCH_DATE
=
VALUES
(
MODEL_RUN_BATCH_DATE
),
REMARK
=
VALUES
(
REMARK
),
CUSTOMER_ID
=
VALUES
(
CUSTOMER_ID
),
OUTSTANDING_AMOUNT
=
VALUES
(
OUTSTANDING_AMOUNT
),
DUE_DATE
=
VALUES
(
DUE_DATE
),
OVERDUE_DAYS
=
VALUES
(
OVERDUE_DAYS
),
IS_OVERDUE
=
VALUES
(
IS_OVERDUE
);
COMMIT
;
src/pages/project_manager_xy/Models.jsx
View file @
00b6e86c
...
...
@@ -326,6 +326,21 @@ export default function Models() {
return
Number
(
right
)
-
Number
(
left
);
}),
[
batchesByYear
]);
const
activeYearEntries
=
batchesByYear
[
activeBatchYear
]
||
[];
const
activeYearModelGroups
=
useMemo
(()
=>
{
const
grouped
=
new
Map
();
activeYearEntries
.
forEach
((
entry
)
=>
{
const
modelKey
=
`
${
entry
.
sourceModel
.
source_model_id
||
entry
.
sourceModel
.
model_code
||
entry
.
sourceModel
.
model_name
}
`
;
if
(
!
grouped
.
has
(
modelKey
))
{
grouped
.
set
(
modelKey
,
{
key
:
modelKey
,
model
:
entry
.
sourceModel
,
entries
:
[],
});
}
grouped
.
get
(
modelKey
).
entries
.
push
(
entry
);
});
return
[...
grouped
.
values
()];
},
[
activeYearEntries
]);
const
activeYearSelectableEntries
=
activeYearEntries
.
filter
((
entry
)
=>
!
syncedBatchCodes
.
includes
(
entry
.
key
));
const
allActiveYearSelected
=
activeYearSelectableEntries
.
length
>
0
&&
activeYearSelectableEntries
.
every
((
entry
)
=>
selectedBatchCodes
.
includes
(
entry
.
key
));
...
...
@@ -337,8 +352,8 @@ export default function Models() {
:
current
.
filter
((
code
)
=>
!
activeCodes
.
includes
(
code
)));
}
function
handle
ActiveYearBatchSelection
(
key
s
)
{
const
selectableCodes
=
new
Set
(
activeYearSelectableEntries
.
map
((
entry
)
=>
entry
.
key
));
function
handle
BatchSelection
(
keys
,
entrie
s
)
{
const
selectableCodes
=
new
Set
(
entries
.
filter
((
entry
)
=>
!
syncedBatchCodes
.
includes
(
entry
.
key
))
.
map
((
entry
)
=>
entry
.
key
));
const
nextCodes
=
keys
===
'all'
?
selectableCodes
:
new
Set
(
keys
);
setSelectedBatchCodes
((
current
)
=>
[
...
current
.
filter
((
code
)
=>
!
selectableCodes
.
has
(
code
)),
...
...
@@ -521,32 +536,51 @@ export default function Models() {
{
activeYearEntries
.
length
?
(
<
ScrollShadow
className=
"max-h-[48vh] overflow-y-auto"
orientation=
"vertical"
size=
{
24
}
>
<
ListView
aria
-
label=
"当前年份可同步批次"
disabledKeys=
{
new
Set
(
activeYearEntries
.
filter
((
entry
)
=>
syncedBatchCodes
.
includes
(
entry
.
key
)).
map
((
entry
)
=>
entry
.
key
))
}
selectedKeys=
{
new
Set
(
activeYearEntries
.
filter
((
entry
)
=>
selectedBatchCodes
.
includes
(
entry
.
key
)).
map
((
entry
)
=>
entry
.
key
))
}
selectionBehavior=
"toggle"
selectionMode=
"multiple"
variant=
"primary"
onSelectionChange=
{
handleActiveYearBatchSelection
}
>
{
activeYearEntries
.
map
((
entry
)
=>
{
const
synced
=
syncedBatchCodes
.
includes
(
entry
.
key
);
<
div
className=
"space-y-3 pr-1"
>
{
activeYearModelGroups
.
map
((
modelGroup
)
=>
{
const
groupSelectableEntries
=
modelGroup
.
entries
.
filter
((
entry
)
=>
!
syncedBatchCodes
.
includes
(
entry
.
key
));
const
groupSelectedCount
=
groupSelectableEntries
.
filter
((
entry
)
=>
selectedBatchCodes
.
includes
(
entry
.
key
)).
length
;
return
(
<
ListView
.
Item
id=
{
entry
.
key
}
key=
{
entry
.
key
}
textValue=
{
entry
.
sourceBatch
.
batch_name
}
>
<
ListView
.
ItemContent
>
<
span
className=
"min-w-0 flex-1"
>
<
ListView
.
Title
className=
"block"
>
{
entry
.
sourceBatch
.
batch_name
}
</
ListView
.
Title
>
<
ListView
.
Description
className=
"block tabular-nums"
>
{
entry
.
sourceModel
.
model_name
}
·
{
entry
.
sourceModel
.
model_code
}
·
{
formatDateTime
(
entry
.
sourceBatch
.
source_batch_date
)
}
·
{
entry
.
sourceBatch
.
batch_code
}
</
ListView
.
Description
>
<
section
className=
"overflow-hidden rounded-xl border border-default bg-surface"
key=
{
modelGroup
.
key
}
>
<
div
className=
"flex flex-wrap items-center justify-between gap-2 border-b border-default bg-surface-secondary px-4 py-3"
>
<
div
className=
"min-w-0"
>
<
h3
className=
"truncate text-sm font-semibold text-foreground"
>
{
modelGroup
.
model
.
model_name
}
</
h3
>
<
p
className=
"mt-0.5 truncate text-xs text-muted"
>
{
modelGroup
.
model
.
model_code
}
</
p
>
</
div
>
<
span
className=
"shrink-0 text-xs tabular-nums text-muted"
>
{
modelGroup
.
entries
.
length
}
个批次
{
groupSelectedCount
?
` · 已选 ${groupSelectedCount}`
:
''
}
</
span
>
</
ListView
.
ItemContent
>
<
ListView
.
ItemAction
>
{
synced
?
<
Tag
tone=
"emerald"
>
已同步
</
Tag
>
:
<
Description
className=
"tabular-nums"
>
{
Number
(
entry
.
sourceBatch
.
source_model_data_count
||
0
).
toLocaleString
(
'zh-CN'
)
}
条
</
Description
>
}
</
ListView
.
ItemAction
>
</
ListView
.
Item
>
</
div
>
<
ListView
aria
-
label=
{
`${modelGroup.model.model_name} 批次`
}
disabledKeys=
{
new
Set
(
modelGroup
.
entries
.
filter
((
entry
)
=>
syncedBatchCodes
.
includes
(
entry
.
key
)).
map
((
entry
)
=>
entry
.
key
))
}
selectedKeys=
{
new
Set
(
modelGroup
.
entries
.
filter
((
entry
)
=>
selectedBatchCodes
.
includes
(
entry
.
key
)).
map
((
entry
)
=>
entry
.
key
))
}
selectionBehavior=
"toggle"
selectionMode=
"multiple"
variant=
"primary"
onSelectionChange=
{
(
keys
)
=>
handleBatchSelection
(
keys
,
modelGroup
.
entries
)
}
>
{
modelGroup
.
entries
.
map
((
entry
)
=>
{
const
synced
=
syncedBatchCodes
.
includes
(
entry
.
key
);
return
(
<
ListView
.
Item
id=
{
entry
.
key
}
key=
{
entry
.
key
}
textValue=
{
entry
.
sourceBatch
.
batch_name
}
>
<
ListView
.
ItemContent
>
<
span
className=
"min-w-0 flex-1"
>
<
ListView
.
Title
className=
"block"
>
{
entry
.
sourceBatch
.
batch_name
}
</
ListView
.
Title
>
<
ListView
.
Description
className=
"block tabular-nums"
>
{
formatDateTime
(
entry
.
sourceBatch
.
source_batch_date
)
}
·
{
entry
.
sourceBatch
.
batch_code
}
</
ListView
.
Description
>
</
span
>
</
ListView
.
ItemContent
>
<
ListView
.
ItemAction
>
{
synced
?
<
Tag
tone=
"emerald"
>
已同步
</
Tag
>
:
<
Description
className=
"tabular-nums"
>
{
Number
(
entry
.
sourceBatch
.
source_model_data_count
||
0
).
toLocaleString
(
'zh-CN'
)
}
条
</
Description
>
}
</
ListView
.
ItemAction
>
</
ListView
.
Item
>
);
})
}
</
ListView
>
</
section
>
);
})
}
</
ListView
>
</
div
>
</
ScrollShadow
>
)
:
<
EmptyCollection
title=
"该年份没有来源批次"
description=
"请选择其他年份查看可同步批次。"
/>
}
</
div
>
...
...
src/pages/project_manager_xy/model-monitor.business-flow.md
View file @
00b6e86c
...
...
@@ -60,7 +60,7 @@ loadSourceBatchData(sourceModel: SourceModel, sourceBatch: SourceBatch): Promise
`ANALYZE_MODEL_DATA_MX_*`
结果行不要求业务主键。每个批次只允许同步一次,结果行按来源读取顺序记录
`source_row_number`
并纯新增,不进行去重或更新。
MySQL 联调数据可通过
`scripts/mysql/model-monitor-source-fixtures.sql`
初始化。脚本只创建不存在的来源表,并按稳定键更新
3 个模型、9 个批次和 48 条结果样例;使用测试源启动前端时,必须把
`MODEL_MONITOR_CONNECTOR_NAME`
配置为对应的 MySQL Connector
。该环境只验证通用同步流程,不替代 Oracle 驱动和方言的集成验收。
MySQL 联调数据可通过
`scripts/mysql/model-monitor-source-fixtures.sql`
初始化。脚本只创建不存在的来源表,并按稳定键更新
4 个模型、16 个批次和 80 条结果样例;每个模型包含 2025 年历史批次和 2026 年当前批次,便于验证按年份分组、年份切换、跨年份勾选和全选口径。使用测试源启动前端时,必须把
`MODEL_MONITOR_CONNECTOR_NAME`
配置为对应的 MySQL Connector;当前测试环境的 Connector 名称为
`oqJDeVZszjRM`
,可用
`MODEL_MONITOR_CONNECTOR_NAME=oqJDeVZszjRM npm run dev`
启动
。该环境只验证通用同步流程,不替代 Oracle 驱动和方言的集成验收。
未来若固定数据源配置变化,只替换构建常量和适配器实现,不修改页面和本地持久化服务。
...
...
@@ -179,6 +179,6 @@ MySQL 联调数据可通过 `scripts/mysql/model-monitor-source-fixtures.sql`
-
勾选批次记录后在视口固定 ActionBar 中执行转发、隐藏或清空选择;所有按钮继续调用原处理函数。
-
模型同步、批次同步、隐藏管理、转发提交、审批详情和填写使用 HeroUI Modal/AlertDialog;关闭或取消不触发保存请求。
-
弹窗宽度按内容密度使用统一梯度:删除确认使用
`md`
,短单列表单使用
`lg`
,普通双列表单使用
`2xl`
,内容型详情、转发、批量同步和填写流程使用
`4xl`
(1088px);移动端保留 16px 安全边距,不改变关闭、校验、保存和审批回调。
-
批量同步模型批次弹窗使用紧凑步骤条、年份筛选与全选工具行
,以及单一 HeroUI Pro ListView 原生多选;每个批次行展示来源模型信息
,切换年份继续保留其它年份已选项,已同步批次继续禁用,选择和同步口径不变。
-
批量同步模型批次弹窗使用紧凑步骤条、年份筛选与全选工具行
;年份下按来源模型分段展示批次,同一模型的批次集中在同一列表区,并在分段标题展示模型名称、编码和批次数量。各分段使用 HeroUI Pro ListView 原生多选
,切换年份继续保留其它年份已选项,已同步批次继续禁用,选择和同步口径不变。
-
查看态详情统一放在单一 secondary Surface;编辑态字段直接位于 Modal Overlay,字段必填、枚举来源、主键禁用和完成填写校验保持原规则。
-
Loading、错误和空状态由 HeroUI/HeroUI Pro 语义组件展示;不得生成测试记录或用伪造数值填充空页面。
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment