From 9bad721754fe8bbe2e5f459d0706e0fefac569f3 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期日, 20 九月 2026 09:05:41 +0800
Subject: [PATCH] feat(mes): 添加智能质检报告功能与AI导入能力
---
docs/sql/config_export_all_20260918.sql | 11435 +++++++++++++++++++
docs/project-business/mermaid/05-quality-flow.mmd | 63
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/QcReportAiImportService.java | 29
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportLlmCall.java | 44
yudao-server/pom.xml | 7
yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t5-v1.0.json | 1
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/template/QcReportTemplateService.java | 98
yudao-module-qcreport/src/test/resources/qcreport/context.json | 32
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceRespVO.java | 51
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/Numbers.java | 26
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/PageSizes.java | 48
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/render/PdfPrintOptions.java | 76
yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/engine/render/CanvasSafetyTest.java | 242
yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/version/ReportTemplateSchemaCompatibilityTest.java | 104
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleParser.java | 372
docs/qc_report_template_version_frontend_integration.md | 124
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/enums/ErrorCodeConstants.java | 117
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/QualityReportEngine.java | 115
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/aiimport/vo/QcReportComponentSpecVO.java | 67
yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/indicator/MesQcIndicatorServiceImplTest.java | 323
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstancePreviewRespVO.java | 27
docs/project-business/data/flows.json | 7
docs/智能质检报告平台-质检单对接方案.md | 572
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/storage/StorageRecordTypeEnum.java | 6
yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/engine/context/ReportContextCodecTest.java | 198
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleToken.java | 11
yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportLlmCallPlannerTest.java | 85
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstancePdfRespVO.java | 46
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/indicator/vo/MesQcIndicatorSaveReqVO.java | 15
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleEvaluator.java | 415
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleScope.java | 28
docs/qc_report_generate_from_qc_frontend_integration.md | 251
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/PdfArchiveResult.java | 22
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/QcReportDocumentExtract.java | 83
yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/engine/FrontendConformanceTest.java | 172
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/context/InspectionItem.java | 113
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/enums/QcReportSourceTypeEnum.java | 54
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstancePageReqVO.java | 39
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ai/ErpPurchaseInvoiceAiServiceImpl.java | 13
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/context/ReportContextCodec.java | 137
yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportTemplatePromptBuilderTest.java | 244
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/render/PdfRenderService.java | 104
yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t3-v1.0.json | 1
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/QcReportInstanceService.java | 117
docs/project-business/data/modules.json | 8
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/aiimport/QcReportAiImportController.java | 44
yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/engine/ReportEvaluatorTest.java | 399
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/version/vo/QcReportTemplateVersionUpdateReqVO.java | 29
pom.xml | 2
yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/AiImportFixtures.java | 241
yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t5-v1.2.json | 1
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/indicator/MesQcIndicatorService.java | 7
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/context/ReportFields.java | 85
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/template/QcReportTemplateServiceImpl.java | 229
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/qc/MesQcReportApiImpl.java | 632 +
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportTemplatePromptBuilder.java | 247
yudao-dependencies/pom.xml | 8
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/ResolvedPage.java | 21
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/QcReportImportAdapter.java | 36
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/GenerateResult.java | 14
yudao-server/src/main/resources/application-local.yaml | 23
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/render/HtmlRenderer.java | 408
yudao-module-mes/src/test/resources/sql/clean.sql | 1
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/mysql/render/QcReportRenderRecordMapper.java | 14
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/storage/SystemStorageBlobService.java | 13
docs/智能质检报告平台-开发进度.md | 3382 +++++
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/template/vo/QcReportTemplatePageReqVO.java | 45
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/PageMargin.java | 16
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/template/QcReportTemplateController.java | 94
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/QcReportAiImportServiceImpl.java | 323
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/config/QcReportAiImportProperties.java | 66
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleNode.java | 42
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/ImageImportAdapter.java | 62
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleSyntaxException.java | 20
docs/project-business/data/business.json | 4
yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t1-v1.1.json | 1
yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/qc/MesQcReportApi.java | 28
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/storage/StorageBlobApiImpl.java | 21
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/version/vo/QcReportTemplateVersionPageReqVO.java | 33
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/render/BrowserManager.java | 229
docs/project-business/mermaid/10-business-object.mmd | 2
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java | 18
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/QcReportInstanceController.java | 172
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/mysql/version/QcReportTemplateVersionMapper.java | 55
docs/qc_report_indicator_hierarchy_frontend_integration.md | 196
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/indicator/vo/MesQcIndicatorPageReqVO.java | 3
yudao-module-qcreport/src/test/resources/qcreport/expected-html.html | 19
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/aiimport/vo/QcReportAiDraftReqVO.java | 52
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/QualityRuleDefinition.java | 79
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/version/vo/QcReportTemplateVersionSaveReqVO.java | 33
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/QualityResult.java | 55
docs/project-business/mermaid/08-module-relation.mmd | 2
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceGenerateRespVO.java | 32
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/template/vo/QcReportTemplateSaveReqVO.java | 57
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/render/QcReportRenderRecordDO.java | 63
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportAiDraftNormalizer.java | 227
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/config/QcReportPdfProperties.java | 44
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/version/QcReportTemplateVersionService.java | 113
yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/QcReportImportAdapterTest.java | 312
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/Paths.java | 199
docs/project-business/index.html | 155
yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/engine/QualityReportEngineTest.java | 96
yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t1-v1.0.json | 1
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportAiDraftParser.java | 140
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/QcReportDocumentExtractService.java | 52
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/storage/SystemStorageBlobServiceImpl.java | 54
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/render/CanvasSafety.java | 268
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/PdfImportAdapter.java | 146
docs/sql/qc_report_platform_ddl.sql | 140
docs/qc_report_instance_frontend_integration.md | 290
yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/qc/dto/MesQcReportRespDTO.java | 116
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/MesQcReportContextMapper.java | 218
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/mysql/template/QcReportTemplateMapper.java | 43
docs/qc_report_configurable_columns_design.md | 239
yudao-module-mes/src/test/resources/sql/create_tables.sql | 26
yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/instance/ReportNoGeneratorTest.java | 94
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/quotation/ai/CrmSaleQuotationAiServiceImpl.java | 13
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/enums/QcReportEnums.java | 156
yudao-module-qcreport/src/test/resources/qcreport/expected-rules.json | 247
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/indicator/MesQcIndicatorController.java | 37
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/version/vo/QcReportTemplateVersionRespVO.java | 40
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/version/ReportTemplateSchema.java | 145
docs/sql/qc_report_menu.sql | 34
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java | 11
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/aiimport/vo/QcReportAiDraftRespVO.java | 69
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java | 6
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceRegenerateRespVO.java | 26
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/template/QcReportTemplateDO.java | 69
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/version/QcReportTemplateVersionServiceImpl.java | 238
.playwright-mcp/物料导入模板.xls | 0
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/render/RenderOutcome.java | 16
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/instance/QcReportInstanceDO.java | 72
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportLlmCallPlanner.java | 47
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/mysql/instance/QcReportInstanceMapper.java | 49
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/indicator/MesQcIndicatorMapper.java | 32
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceGenerateFromQcReqVO.java | 37
docs/智能质检报告设计平台——Claude Code Agent 专业开发提示词.md | 2547 ++++
yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportAiDraftNormalizerTest.java | 230
yudao-server/src/main/resources/application-test.yaml | 28
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/ReportNoGenerator.java | 85
docs/qc_report_ai_import_frontend_integration.md | 360
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleEngine.java | 101
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceGenerateFromQcRespVO.java | 41
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceGenerateReqVO.java | 39
docs/project-business/mermaid/09-data-flow.mmd | 33
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/context/ReportContext.java | 120
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/version/QcReportTemplateVersionController.java | 113
yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/render/PdfPrintOptionsTest.java | 158
docs/sql/qc_report_dict.sql | 55
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/report/EvaluationOutcome.java | 14
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java | 10
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/indicator/vo/MesQcIndicatorRespVO.java | 20
docs/智能质检报告平台-方案设计.md | 374
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/Bindings.java | 88
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/indicator/MesQcIndicatorDO.java | 40
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/qc/MesQcIndicatorItemTypeEnum.java | 44
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleRuntimeException.java | 12
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/template/vo/QcReportTemplateRespVO.java | 51
yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t5-v1.1.json | 1
docs/qc_report_grouped_inspection_design.md | 187
yudao-module-qcreport/pom.xml | 98
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiModelServiceImpl.java | 8
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/JsValues.java | 43
docs/project-business/mermaid/01-business-mindmap.mmd | 7
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/TokenType.java | 30
docs/project-business/mermaid/11-ai-business-flow.mmd | 17
docs/project-business/data/objects.json | 12
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/PageSetting.java | 15
yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportAiDraftParserTest.java | 132
yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactory.java | 11
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/version/QcReportTemplateVersionDO.java | 58
yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/instance/MesQcReportContextMapperTest.java | 364
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/storage/StorageBlobApi.java | 21
yudao-module-qcreport/src/test/resources/qcreport/schema.json | 107
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/render/RenderNode.java | 88
yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/qc/dto/MesQcReportItemRespDTO.java | 89
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/indicator/MesQcIndicatorServiceImpl.java | 116
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/QcReportInstanceServiceImpl.java | 531
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/report/ReportEvaluator.java | 190
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/GenerateFromQcResult.java | 19
yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/OfficeImportAdapter.java | 372
181 files changed, 35,141 insertions(+), 55 deletions(-)
diff --git "a/.playwright-mcp/\347\211\251\346\226\231\345\257\274\345\205\245\346\250\241\346\235\277.xls" "b/.playwright-mcp/\347\211\251\346\226\231\345\257\274\345\205\245\346\250\241\346\235\277.xls"
new file mode 100644
index 0000000..28de632
--- /dev/null
+++ "b/.playwright-mcp/\347\211\251\346\226\231\345\257\274\345\205\245\346\250\241\346\235\277.xls"
Binary files differ
diff --git a/docs/project-business/data/business.json b/docs/project-business/data/business.json
index 7aec6dc..8442228 100644
--- a/docs/project-business/data/business.json
+++ b/docs/project-business/data/business.json
@@ -21,8 +21,8 @@
"frontend": "mom-pro2-before锛圴ue3 绠$悊鍚庡彴锛屽悓浠撳簱瀛樻斁锛屽彧璇诲弬鑰冿級"
},
"stats": {
- "businessModules": 12,
- "coreObjects": 46,
+ "businessModules": 13,
+ "coreObjects": 48,
"documentFlows": 6,
"approvalListeners": 13,
"aiCapabilities": 8,
diff --git a/docs/project-business/data/flows.json b/docs/project-business/data/flows.json
index f555390..d66f454 100644
--- a/docs/project-business/data/flows.json
+++ b/docs/project-business/data/flows.json
@@ -29,13 +29,15 @@
{"stage": "鑱斿姩", "action": "瀹℃壒閫氳繃鎸夊伐搴忔爣璁�: 鍊掑啿鈫掕嚜鍔ㄧ墿鏂欐秷鑰楁墸绾胯竟搴�(鍏佽璐熷簱瀛�)锛涜川妫�鈫掍骇鍑哄緟妫�琛岀瓑 IPQC锛涘叧閿潪妫�鈫掔洿鎺ヤ骇鍑哄叆搴�", "roles": ["绯荤粺鑷姩"]},
{"stage": "瀹屽伐", "action": "浠呮湯閬撳伐搴忓洖鍐欏伐鍗曞凡鐢熶骇鏁伴噺锛岃揪鏍囪嚜鍔ㄥ畬鎴愶紱MPS 绱鍒ゆ柇瀹屾垚骞跺彂浜嬩欢缁欓攢鍞鍗�", "roles": ["绯荤粺鑷姩"]}]},
{"id": "quality", "name": "璐ㄩ噺娴佺▼", "mermaid": "mermaid/05-quality-flow.mmd", "color": "#e06c6c",
- "summary": "鍥涢亾妫�楠岄椄鍙�(IQC/IPQC/OQC/RQC锛屼簩鎬� 0鈫�4) + 鍒ゅ畾鍥涙灉(鍚堟牸/鐗归噰/閫�璐�/鎶ュ簾) + NCR 璇勫澶勭疆鍏抽棴锛汚I 鎻愪緵鍒ゅ畾寤鸿锛汵CR 褰撳墠浠呭彴璐︿笉瑙﹀彂杩斿伐鍗曘��",
+ "summary": "鍥涢亾妫�楠岄椄鍙�(IQC/IPQC/OQC/RQC锛屼簩鎬� 0鈫�4) + 鍒ゅ畾鍥涙灉(鍚堟牸/鐗归噰/閫�璐�/鎶ュ簾) + NCR 璇勫澶勭疆鍏抽棴锛汚I 鎻愪緵鍒ゅ畾寤鸿锛汵CR 褰撳墠浠呭彴璐︿笉瑙﹀彂杩斿伐鍗曪紱妫�楠屽崟鍙敱鏅鸿兘璐ㄦ鎶ュ憡骞冲彴涓�閿嚭浠讹紙generate-from-qc锛氭暟鎹粠 MES 鍙栵紝浜旈亾鏍¢獙鍚庢覆鏌撹惤搴擄級銆�",
"steps": [
{"stage": "鏉ユ枡", "action": "鍒拌揣閫氱煡/澶栧崗鍏ュ簱鈫扞QC锛岀粨璁哄洖鍐欐帹杩涘緟鍏ュ簱鎴栬Е鍙戦��璐�", "roles": ["IQC 璐ㄦ鍛�"]},
{"stage": "杩囩▼", "action": "鎶ュ伐璐ㄦ宸ュ簭浜у嚭琛屸啋IPQC锛屽悎鏍兼媶琛屽叆搴撱�佷笉鍚堟牸鐢熸垚 NCR", "roles": ["IPQC 璐ㄦ鍛�"]},
{"stage": "鍑鸿揣", "action": "閿�鍞嚭搴撴彁浜も啋OQC锛屽畬鎴愬悗鍑哄簱鍗曡繘鍏ュ緟鎷h揣", "roles": ["OQC 璐ㄦ鍛�"]},
{"stage": "閫�璐�", "action": "閫�鏂�/閿�鍞��璐�/鍞悗閫�璐р啋RQC锛岀粨璁哄洖璋冨崟鎹笌鍞悗", "roles": ["RQC 璐ㄦ鍛�"]},
- {"stage": "涓嶅悎鏍�", "action": "NCR: 寰呰瘎瀹♀啋璇勫鈫掑缃�(閫�璐�/鎶ュ簾/杩斿伐/璁╂鎺ユ敹/闄嶇骇)鈫掑叧闂�", "roles": ["璐ㄩ噺宸ョ▼甯�"]}]},
+ {"stage": "涓嶅悎鏍�", "action": "NCR: 寰呰瘎瀹♀啋璇勫鈫掑缃�(閫�璐�/鎶ュ簾/杩斿伐/璁╂鎺ユ敹/闄嶇骇)鈫掑叧闂�", "roles": ["璐ㄩ噺宸ョ▼甯�"]},
+ {"stage": "鍑轰欢", "action": "涓ゆ潯鍑轰欢鍏ュ彛锛氣憼閫氱敤 generate/preview(璋冪敤鏂硅嚜甯︿笂涓嬫枃) 娓叉煋 HTML 骞跺喕缁撴暟鎹揩鐓э紝缂栧彿 QR+鏃ユ湡+4浣嶆祦姘存寜澶╃嫭绔嬶紝preview 鍙覆鏌撲笉钀藉簱涓嶆秷鑰楃紪鍙凤紝regenerate 鐢ㄥ喕缁撳揩鐓ч噸娓蹭笖鏁版嵁涓庣紪鍙蜂笉鍙樺苟浣滃簾宸插綊妗� PDF锛屽鍑� PDF 鐢卞悗绔皟 Chromium 鎵撳嵃瀹炰緥宸插瓨鐨� HTML 鍚庡綊妗i檮浠朵腑蹇冿紱鈶enerate-from-qc 鐢辫川妫�鍗曠洿鎺ュ嚭浠�(鏁版嵁缁� MesQcReportApi 浠� MES 鍙栵紝鍓嶇涓嶆嫾涓婁笅鏂�)锛屽嚭浠跺墠浜旈亾鏍¢獙鎸変笟鍔′紭鍏堢骇鍙姤绗竴澶勶細绫诲瀷闈炴硶/鍗曟嵁涓嶅瓨鍦�/鏈畬鎴愭楠�/鏈~鍒ゅ畾/妯℃澘绫诲瀷涓嶇/鏃犲彲鐢ㄦ楠岄」锛屾姤鍛婂ご鍙﹀甫鍗曟嵁鍘熷垽瀹� qcResult+qcResultText 涓庡紩鎿庡垽瀹氬苟瀛橈紝鍝嶅簲鍥� undecidableCount 寰呭垽瀹氶」鏁颁笌 warnings(鍒嗙粍鏍囬璺宠繃/鎸囨爣宸插垹/鏈綍瀹炴祴鍊�/鏍峰搧瓒�3)锛屽悓涓�寮犲崟鎹彲鍙嶅鍑哄浠�", "roles": ["璐ㄦ鍛�"]},
+ {"stage": "寤烘ā鏉�", "action": "AI 瀵煎叆锛氫笂浼犳棦鏈夋楠屾姤鍛婃枃浠�(鎵弿浠�/鐓х墖銆佺數瀛愮増 PDF銆乄ord/Excel) 鈫� 璇嗗埆鎴愭ā鏉胯崏绋�(涓嶈惤搴�) 鈫� 浜哄伐鍦ㄨ璁″櫒纭璋冩暣鍚庝繚瀛樹负鐗堟湰锛�.doc/.xls 鏃ф牸寮忎笉鏀寔", "roles": ["璐ㄦ鍛�", "璐ㄩ噺宸ョ▼甯�"]}]},
{"id": "warehouse", "name": "浠撳偍娴佺▼", "mermaid": "mermaid/06-warehouse-flow.mmd", "color": "#7e6bd6",
"summary": "15 绫诲崟鎹┍鍔ㄥ簱瀛樺彴璐�(鍏厓缁勩�佸洓閲�)鍙樺姩锛屽叏閮ㄧ粡浜嬪姟娴佹按鐣欑棔锛涙敮鎸佽皟鎷ㄥ湪閫斻�佺洏鐐硅皟鏁淬�佹壒娆�/SN 杩芥函銆佸簱瀛樺崰鐢ㄤ笌鍥涚骇鍐荤粨銆佺嚎杈硅櫄鎷熷簱璐熷簱瀛橈紱瀵瑰 WmsStockApi 渚� ERP 鏀跺彂銆�",
"steps": [
@@ -57,6 +59,7 @@
{"stage": "褰曞叆鎻愭晥", "action": "鍙戠エ OCR(鍥剧墖澶氭ā鎬�/PDF鏂囨湰)銆佹姤浠峰崟 OCR 鈫� 缁撴瀯鍖栭濉�", "roles": ["閲囪喘鍛�", "閿�鍞�"]},
{"stage": "杈呭姪鍒ゅ畾", "action": "璐ㄦ鍗�+鎸囨爣+缂洪櫡 鈫� 寤鸿鍚堟牸/鐗归噰/閫�璐�/鎶ュ簾+鐞嗙敱", "roles": ["璐ㄦ鍛�"]},
{"stage": "鍐崇瓥棰勬祴", "action": "缂烘枡/鐢熶骇鏃堕暱/鐢熶骇椋庨櫓/浜や粯鍥涚被棰勬祴渚涜鍒掓帓浜у弬鑰�", "roles": ["璁″垝鍛�"]},
+ {"stage": "妯℃澘璇嗗埆", "action": "涓婁紶鏃㈡湁妫�楠屾姤鍛婃枃浠�(鎵弿浠�/鐓х墖銆佺數瀛愮増 PDF銆乄ord/Excel) 鈫� 鍒嗛�氶亾鎶藉彇(鏈夋枃鏈眰璧版枃鏈�佹壂鎻忕増閫愰〉杞浘) 鈫� 澶фā鍨嬫寜鍓嶇涓婁紶鐨勭粍浠舵竻鍗曚骇鍑烘墎骞崇粍浠惰崏绋� 鈫� 浜哄伐鍦ㄨ璁″櫒纭鍚庝繚瀛樹负妯℃澘鐗堟湰", "roles": ["璐ㄦ鍛�", "璐ㄩ噺宸ョ▼甯�"]},
{"stage": "鐭ヨ瘑妫�绱�", "action": "鏂囨。鈫掑垏鐗団啋Milvus 鍚戦噺鈫掓绱㈡帴鍙�(棰勭暀)", "roles": ["鈥�"]}]}
]
}
diff --git a/docs/project-business/data/modules.json b/docs/project-business/data/modules.json
index 09137e1..db8b10f 100644
--- a/docs/project-business/data/modules.json
+++ b/docs/project-business/data/modules.json
@@ -56,6 +56,14 @@
"roles": ["璐ㄦ鍛�(IQC/IPQC/OQC)", "璐ㄩ噺宸ョ▼甯�"],
"upstream": ["浠撳偍(鍒拌揣)", "鐢熶骇(鎶ュ伐)", "閿�鍞�(鍑哄簱)", "鍞悗(閫�璐�)"], "downstream": ["浠撳偍(鍚堟牸鍏ュ簱/鎶ュ簾鍑哄簱)", "鐢熶骇(NCR杩斿伐)"],
"coreTables": ["mes_qc_iqc", "mes_qc_ipqc", "mes_qc_oqc", "mes_qc_rqc", "mes_qc_template", "mes_qc_indicator", "mes_qc_defect", "mes_qc_ncr"]},
+ {"key": "qcreport", "name": "鏅鸿兘璐ㄦ鎶ュ憡", "color": "#b06ce0", "tag": "QC-REPORT", "flow": "quality",
+ "positioning": "鍙鍖栬璁℃姤鍛婃ā鏉� 鈫� 涓�閿嚭浠跺苟鍐荤粨鍘嗗彶鎶ュ憡",
+ "problem": "鍚勮涓氳川妫�鎶ュ憡鏍煎紡鍚勫紓锛屾帓鐗堢‖缂栫爜鏀逛竴娆″彂涓�娆$増锛涗笖鍘嗗彶鎶ュ憡蹇呴』鍙鐜般�佷笉闅忎笟鍔℃暟鎹彉鍖�",
+ "features": ["GrapesJS 鍙鍖栬璁″櫒锛堣川妫�缁勪欢璧版敞鍐屾満鍒讹紝涓嶇‖缂栫爜杩涚紪杈戝櫒锛�", "妯℃澘 + 澶氱増鏈細鑽夌0/宸插彂甯�1/宸插仠鐢�2锛屽凡鍙戝竷鐗堟湰鍐呭涓嶅彲瑕嗙洊", "缁勪欢鏁版嵁缁戝畾涓庣嫭绔嬪垽瀹氳鍒欏紩鎿庯紙绂佺敤 eval / ScriptEngine锛�", "涓庡墠绔�愬瓧瀵归綈鐨� Java 娓叉煋寮曟搸锛屽嚭绔� HTML 鍓ョ on* 浜嬩欢灞炴�т笌 javascript:/vbscript:/data: 鍗忚", "鍑轰欢鎺ュ彛锛歱review 鍙覆鏌撲笉钀藉簱涓嶆秷鑰楃紪鍙� / generate 娓叉煋+钀藉簱+鍐荤粨 data_snapshot / regenerate 鐢ㄥ喕缁撳揩鐓т笌鍚屼竴鐗堟湰閲嶆覆", "鎶ュ憡缂栧彿 QR+yyyyMMdd+4浣嶆祦姘达紝鎸夊ぉ鐙珛锛屽彲鏄惧紡鎸囧畾锛堟挒鍙蜂細鎶ュ嚭鍏蜂綋缂栧彿锛�", "缂哄彛娓呭崟鍙湪 preview/generate/regenerate 鍝嶅簲閲岃繑鍥烇紝涓嶈惤搴�", "PDF(Playwright) 褰掓。涓� MES 鍥涚璐ㄦ鍗曞綊涓�鍖栧鎺ュ緟鍚庣画杞"],
+ "objects": ["鎶ュ憡妯℃澘", "鎶ュ憡瀹炰緥"],
+ "roles": ["鎶ュ憡璁捐鍛�", "璐ㄦ鍛橈紙鍑轰欢锛�"],
+ "upstream": ["璐ㄩ噺锛堣川妫�鍗曚笂涓嬫枃锛屾湰杞敱璋冪敤鏂逛紶鍏ワ級"], "downstream": ["闄勪欢涓績锛圥DF 褰掓。路鍚庣画杞锛�", "BI"],
+ "coreTables": ["qc_report_template", "qc_report_template_version", "qc_report_instance", "qc_report_data_source", "qc_report_rule", "qc_report_render_record"]},
{"key": "dv", "name": "璁惧涓庡伐瑁呮帓鐝�", "color": "#59a8b8", "tag": "MES-DV/TM/CAL", "flow": null,
"positioning": "璁惧璧勪骇鍋ュ悍涓庣敓浜ц祫婧愪繚闅�",
"problem": "璁惧鐐规淇濆吇缁翠慨鍙墽琛屻�佸伐瑁呯姸鎬佸彲鎺с�佺彮缁勬帓鐝湁渚濇嵁",
diff --git a/docs/project-business/data/objects.json b/docs/project-business/data/objects.json
index b9ab1c5..ac4ea65 100644
--- a/docs/project-business/data/objects.json
+++ b/docs/project-business/data/objects.json
@@ -35,16 +35,18 @@
{"name": "鐩樼偣浠诲姟", "module": "浠撳偍", "table": "mes_wm_stock_taking_task", "doc": "闈欐��/鍔ㄦ�佺洏鐐癸紝琛岀粨鏋�:姝e父/鐩樼泩(ADJUST_IN)/鐩樹簭(ADJUST_OUT)锛屽彲鍐荤粨搴撳瓨銆佺洸鐩�", "upstream": ["搴撳瓨鍙拌处"], "downstream": ["搴撳瓨鍙拌处(璋冩暣)"], "keywords": "鐩樼偣 鐩樼泩 鐩樹簭 stock taking"},
{"name": "搴撳瓨鍙拌处", "module": "浠撳偍", "table": "mes_wm_material_stock", "doc": "鐗╂枡脳浠撳簱脳搴撳尯脳搴撲綅脳鎵规脳渚涘簲鍟嗗叚鍏冪粍锛屾暟閲�/鍐荤粨/鍗犵敤/鍦ㄩ�斿洓閲�", "upstream": ["鍏ㄩ儴鍏ュ簱鍗�"], "downstream": ["鍏ㄩ儴鍑哄簱鍗�", "浜嬪姟娴佹按"], "keywords": "搴撳瓨 鍙拌处 stock 鍙敤閲�"},
{"name": "鎵规", "module": "浠撳偍", "table": "mes_wm_batch", "doc": "鍏宠仈鐗╂枡/宸ュ崟/渚涘簲鍟�/瀹㈡埛/璐ㄩ噺鐘舵�侊紱SN 鐮佸惈鎵规 uuid锛涙潯鐮佹敮鎸�18绉嶄笟鍔″璞�", "upstream": ["鍏ュ簱鍗曟嵁"], "downstream": ["搴撳瓨鍙拌处"], "keywords": "鎵规 batch SN 鏉$爜 杩芥函"},
- {"name": "IQC鏉ユ枡妫�楠�", "module": "璐ㄩ噺", "table": "mes_qc_iqc", "doc": "鍒拌揣閫氱煡/澶栧崗鍏ュ簱瑙﹀彂锛岃崏绋�0鈫掑畬鎴�4锛岀粨璁哄洖鍐欐潵婧愬崟鎹�", "upstream": ["鍒拌揣閫氱煡", "澶栧崗鍏ュ簱"], "downstream": ["閲囪喘鍏ュ簱", "渚涘簲鍟嗛��璐�", "NCR"], "keywords": "IQC 鏉ユ枡妫�楠�"},
- {"name": "IPQC杩囩▼妫�楠�", "module": "璐ㄩ噺", "table": "mes_qc_ipqc", "doc": "鎶ュ伐璐ㄦ宸ュ簭浜у嚭琛岃Е鍙戯紝瀹屾垚鍥炶皟鎺ㄨ繘鎶ュ伐涓庝骇鍑哄叆搴�", "upstream": ["鎶ュ伐"], "downstream": ["浜у嚭鍏ュ簱", "NCR"], "keywords": "IPQC 杩囩▼妫�楠� 宸℃"},
- {"name": "OQC鍑鸿揣妫�楠�", "module": "璐ㄩ噺", "table": "mes_qc_oqc", "doc": "閿�鍞嚭搴撴彁浜よЕ鍙戯紝瀹屾垚鎺ㄨ繘鍑哄簱鍗曞緟鎷h揣", "upstream": ["閿�鍞嚭搴撳崟"], "downstream": ["閿�鍞嚭搴撳崟(鎺ㄨ繘)"], "keywords": "OQC 鍑鸿揣妫�楠� 鍑哄巶妫�楠�"},
- {"name": "RQC閫�璐ф楠�", "module": "璐ㄩ噺", "table": "mes_qc_rqc", "doc": "鐢熶骇閫�鏂�/閿�鍞��璐�/鍞悗閫�璐цЕ鍙戯紝缁撹鍥炶皟鍞悗", "upstream": ["閫�鏂�", "閫�璐�"], "downstream": ["閫�璐у叆搴�", "鍞悗鍥炶皟"], "keywords": "RQC 閫�璐ф楠�"},
+ {"name": "IQC鏉ユ枡妫�楠�", "module": "璐ㄩ噺", "table": "mes_qc_iqc", "doc": "鍒拌揣閫氱煡/澶栧崗鍏ュ簱瑙﹀彂锛岃崏绋�0鈫掑畬鎴�4锛岀粨璁哄洖鍐欐潵婧愬崟鎹紱琛屾搷浣溿�屽嚭鎶ュ憡銆嶄粎鍦ㄥ凡瀹屾垚鏃跺彲瑙�", "upstream": ["鍒拌揣閫氱煡", "澶栧崗鍏ュ簱"], "downstream": ["閲囪喘鍏ュ簱", "渚涘簲鍟嗛��璐�", "NCR", "鎶ュ憡瀹炰緥(鍑烘姤鍛�)"], "keywords": "IQC 鏉ユ枡妫�楠� 鍑烘姤鍛�"},
+ {"name": "IPQC杩囩▼妫�楠�", "module": "璐ㄩ噺", "table": "mes_qc_ipqc", "doc": "鎶ュ伐璐ㄦ宸ュ簭浜у嚭琛岃Е鍙戯紝瀹屾垚鍥炶皟鎺ㄨ繘鎶ュ伐涓庝骇鍑哄叆搴擄紱琛屾搷浣溿�屽嚭鎶ュ憡銆嶄粎鍦ㄥ凡瀹屾垚鏃跺彲瑙�", "upstream": ["鎶ュ伐"], "downstream": ["浜у嚭鍏ュ簱", "NCR", "鎶ュ憡瀹炰緥(鍑烘姤鍛�)"], "keywords": "IPQC 杩囩▼妫�楠� 宸℃ 鍑烘姤鍛�"},
+ {"name": "OQC鍑鸿揣妫�楠�", "module": "璐ㄩ噺", "table": "mes_qc_oqc", "doc": "閿�鍞嚭搴撴彁浜よЕ鍙戯紝瀹屾垚鎺ㄨ繘鍑哄簱鍗曞緟鎷h揣锛涜鎿嶄綔銆屽嚭鎶ュ憡銆嶄粎鍦ㄥ凡瀹屾垚鏃跺彲瑙�", "upstream": ["閿�鍞嚭搴撳崟"], "downstream": ["閿�鍞嚭搴撳崟(鎺ㄨ繘)", "鎶ュ憡瀹炰緥(鍑烘姤鍛�)"], "keywords": "OQC 鍑鸿揣妫�楠� 鍑哄巶妫�楠� 鍑烘姤鍛�"},
+ {"name": "RQC閫�璐ф楠�", "module": "璐ㄩ噺", "table": "mes_qc_rqc", "doc": "鐢熶骇閫�鏂�/閿�鍞��璐�/鍞悗閫�璐цЕ鍙戯紝缁撹鍥炶皟鍞悗锛涜鎿嶄綔銆屽嚭鎶ュ憡銆嶄粎鍦ㄥ凡瀹屾垚鏃跺彲瑙併�傛帾杈炲凡缁熶竴涓恒�岄��璐ф楠屻�嶏紙鍘熻彍鍗曠埗椤逛笌 mes_qc_type 瀛楀吀鍐欍�岄��鏂欐楠屻�嶏紝涓庡悗绔灇涓�/琛ㄦ敞閲�/鑿滃崟鏉冮檺瀛愰」涓嶄竴鑷达紱RQC 涓夎�呴兘瑕嗙洊锛屾晠鍙栥�岄��璐ф楠屻�嶏級", "upstream": ["閫�鏂�", "閫�璐�"], "downstream": ["閫�璐у叆搴�", "鍞悗鍥炶皟", "鎶ュ憡瀹炰緥(鍑烘姤鍛�)"], "keywords": "RQC 閫�璐ф楠� 閫�鏂欐楠� 鍑烘姤鍛�"},
{"name": "NCR涓嶅悎鏍煎搧", "module": "璐ㄩ噺", "table": "mes_qc_ncr", "doc": "寰呰瘎瀹�0鈫掑凡璇勫6鈫掑凡澶勭疆7鈫掑凡鍏抽棴8锛屽缃�:閫�璐�/鎶ュ簾/杩斿伐/璁╂鎺ユ敹/闄嶇骇", "upstream": ["IQC/IPQC/OQC/RQC"], "downstream": ["閫�璐�/鎶ュ簾/杩斿伐(鍙拌处)"], "keywords": "NCR 涓嶅悎鏍� 澶勭疆 鐗归噰 鎶ュ簾"},
{"name": "璁惧", "module": "璁惧", "table": "mes_dv_machinery", "doc": "鍙拌处鐘舵��:鍋滄満/鐢熶骇涓�/淇濆吇涓紱鐐规路淇濆吇路缁翠慨宸ュ崟锛汚I 椋庨櫓棰勬祴娑堣垂鍏舵暟鎹�", "upstream": [], "downstream": ["鐐规", "缁翠慨", "鐢熶骇椋庨櫓棰勬祴"], "keywords": "璁惧 鐐规 淇濆吇 缁翠慨 machinery"},
{"name": "鍞悗宸ュ崟", "module": "鍞悗", "table": "after_sale_ticket", "doc": "鑽夌0鈫掑鐞嗕腑10鈫掑緟鍏ュ簱30鈫掑緟閫�娆�40鈫掑畬缁�50鈫掑叧闂�60/鍙栨秷99锛屽垽瀹�:涓�鑸�/缁翠慨/閫�璐�", "upstream": ["瀹㈡埛鍙嶉(浜哄伐褰曞叆)"], "downstream": ["缁翠慨璁板綍", "閫�璐х敵璇�"], "keywords": "鍞悗 宸ュ崟 ticket 缁翠慨"},
{"name": "閫�璐х敵璇�", "module": "鍞悗", "table": "after_sale_return", "doc": "鑽夌0鈫掑凡瀹℃牳20(鑷姩寤篗ES閫�璐у崟)鈫掑凡璐ㄦ40鈫掑凡鍏ュ簱50鈫掑凡閫�娆�60鈫掑叧闂�70锛涚被鍨�:閫�娆鹃��璐�/鎹㈣揣/浠呴��娆�", "upstream": ["鍞悗宸ュ崟"], "downstream": ["閿�鍞��璐у崟", "閫�娆�"], "keywords": "鍞悗閫�璐� return"},
{"name": "鍛樺伐", "module": "浜哄姏", "table": "hrm_employee", "doc": "鍦ㄨ亴1/璇曠敤2/绂昏亴3锛屽叆鑱岃嚜鍔ㄥ缓绯荤粺璐﹀彿", "upstream": [], "downstream": ["浜ゆ帴鏄犲皠", "鑰冨嫟", "钖叕"], "keywords": "鍛樺伐 鍏ヨ亴 employee"},
{"name": "绂昏亴浜ゆ帴", "module": "浜哄姏", "table": "hrm_user_handover", "doc": "from鈫抰o 鏄犲皠锛屽凡瀹屾垚20 鍚� expandUserIds 鎵╁睍浜ゆ帴浜哄彲瑙佹暟鎹紙褰撳墠鍚勪笟鍔℃ā鍧楀皻鏈疄闄呮帴鍏ヨ皟鐢級", "upstream": ["绂昏亴鐢宠"], "downstream": ["鍚勬ā鍧楁垜鐨勬暟鎹煡璇�"], "keywords": "浜ゆ帴 绂昏亴 handover expandUserIds"},
- {"name": "鎺掔彮璁″垝", "module": "璁惧", "table": "mes_cal_plan", "doc": "鐝粍脳鐝脳鏃ユ湡鎺掔彮锛屼緵鐢熶骇涓庤�冨嫟寮曠敤", "upstream": [], "downstream": ["鐢熶骇浠诲姟", "鑰冨嫟"], "keywords": "鎺掔彮 鐝粍 鐝 鏃ュ巻"}
+ {"name": "鎺掔彮璁″垝", "module": "璁惧", "table": "mes_cal_plan", "doc": "鐝粍脳鐝脳鏃ユ湡鎺掔彮锛屼緵鐢熶骇涓庤�冨嫟寮曠敤", "upstream": [], "downstream": ["鐢熶骇浠诲姟", "鑰冨嫟"], "keywords": "鎺掔彮 鐝粍 鐝 鏃ュ巻"},
+ {"name": "鎶ュ憡妯℃澘", "module": "璐ㄦ鎶ュ憡", "table": "qc_report_template", "doc": "鏅鸿兘璐ㄦ鎶ュ憡妯℃澘锛屽惎鐢�0/鍋滅敤1锛涚敾甯冨唴瀹瑰瓨鍦� qc_report_template_version锛堣崏绋�0/宸插彂甯�1/宸插仠鐢�2锛屽凡鍙戝竷涓嶅彲瑕嗙洊锛夛紝currentVersion 鎸囧悜褰撳墠宸插彂甯冪増鏈紱婧愭枃浠剁粡 AI 瀵煎叆璇嗗埆鎴愯崏绋垮悗鐢变汉宸ョ‘璁ゆ墠鎴愪负鐗堟湰锛涘悓涓�妯℃澘閲嶅瀵煎叆鎸夈�愭浛鎹€�戝鐞嗏�斺�斿厛鍒犳棫闄勪欢锛堣繛甯� blob 琛屼笌纾佺洏鏂囦欢锛夊啀缁戞柊鐨勶紝涓嶇暀瀛ゅ効鏂囦欢锛涘垹闄ゆā鏉夸細杩炲甫娓呴檮浠�", "upstream": ["浜哄伐璁捐(GrapesJS 璁捐鍣�)", "AI 瀵煎叆鑽夌(qc-report/ai-import/draft)"], "downstream": ["妯℃澘鐗堟湰", "鎶ュ憡瀹炰緥"], "keywords": "鎶ュ憡妯℃澘 璐ㄦ鎶ュ憡 template 璁捐鍣� 鐗堟湰 AI瀵煎叆 璇嗗埆 鑽夌 婧愭枃浠舵浛鎹�"},
+ {"name": "鎶ュ憡瀹炰緥", "module": "璐ㄦ鎶ュ憡", "table": "qc_report_instance", "doc": "鍑轰欢浜х墿锛岀紪鍙� QR+yyyyMMdd+4浣嶆祦姘存寜澶╃嫭绔嬩笖涓氬姟鍞竴锛屽彲鏄惧紡鎸囧畾瑕嗙洊锛堟敞鎰� uk_report_no 涓嶅尯鍒嗚蒋鍒犻櫎锛屽垹鎺夌殑鍙蜂笉鍥炴敹锛夛紱涓ゆ潯鍑轰欢鍏ュ彛锛氶�氱敤 generate锛堣皟鐢ㄦ柟鑷甫 context锛変笌 generate-from-qc锛堟暟鎹粠 MES 璐ㄦ鍗曞彇锛屾潈闄愮爜 qc-report:instance:generate 宸插叆 system_menu id=1075416锛屼簲閬撴牎楠屾寜涓氬姟浼樺厛绾у彧鎶ョ涓�澶勶細105_000 绫诲瀷闈炴硶 / 105_001 鍗曟嵁涓嶅瓨鍦� / 105_002 鏈畬鎴� / 105_003 鏈垽瀹� / 105_005 妯℃澘绫诲瀷涓嶇 / 105_006 鏃犲彲鐢ㄦ楠岄」锛涘洓寮犺川妫�鍗曞垪琛ㄧ殑琛屾搷浣溿�屽嚭鎶ュ憡銆嶄粎鍦� status=宸插畬鎴愭椂鍙锛屽脊绐楀彧鍒� reportType 涓�鑷淬�佹ā鏉垮惎鐢ㄣ�佷笖 currentVersion 鎸囧悜鐨勭増鏈凡鍙戝竷鐨勬ā鏉匡紙鍚庣 /qc-report/template/selectable 鍒ゅ畾鈥斺�斿仠鐢ㄧ増鏈笉娓呯┖ currentVersion锛屽墠绔嬁鍒嗛〉缁撴灉鑷繁鎺ㄥ浼氭紡锛夛紝缁撴灉灏卞湴灞曠ず骞惰烦鏈〉鍒楄〃锛夛紱鍐荤粨 data_snapshot锛堝垽瀹氬悗鏁版嵁锛屽惈鍚庣绠楀ソ鐨� PASS/FAIL 涓庡悎鏍肩巼锛変笌 render_html锛況egenerate 鍙噸娓叉帓鐗堛�佹暟鎹笌缂栧彿涓嶅彉锛沚usiness_id/business_type 瀛� MES 琛ㄥ悕锛坢es_qc_iqc 绛夛級涓庡崟鎹� ID锛屽彲鍙嶆煡銆佷竴鍗曞彲鍑哄浠斤紱鎶ュ憡澶村彟甯﹀崟鎹師鍒ゅ畾 qcResult(鏁�)/qcResultText(涓枃锛屽悎鏍�/鐗归噰/涓嶅悎鏍奸��璐�/涓嶅悎鏍兼姤搴�)锛屼笌寮曟搸涓夋�佸垽瀹氬苟瀛樹簰涓嶈鐩栵紱鍝嶅簲甯� undecidableCount=蹇収涓� result 涓虹┖涓茬殑椤规暟涓� warnings锛堝垎缁勬爣棰樿烦杩�/鎸囨爣宸插垹/鏈綍瀹炴祴鍊�/鏍峰搧瓒�3锛夛紝涓よ�呴兘涓嶈惤搴撱�佷簨鍚庣湅涓嶅埌", "upstream": ["鎶ュ憡妯℃澘鐗堟湰", "璐ㄦ鍗曚笂涓嬫枃(閫氱敤 generate 鐢辫皟鐢ㄦ柟浼犲叆)", "MES 璐ㄦ鍗� IQC/IPQC/OQC/RQC(generate-from-qc 缁� MesQcReportApi 鍙栨暟)"], "downstream": ["鍓嶇瀹炰緥椤� /qc/report-instance(鍒楄〃路iframe棰勮路蹇収椤电路瀵煎嚭PDF)", "PDF褰掓。(system_storage_attachment recordType=qc_report_instance)"], "keywords": "鎶ュ憡瀹炰緥 鍑轰欢 QR缂栧彿 蹇収 澶嶇幇 regenerate PDF褰掓。 鎶ュ憡瀹炰緥椤� 瀵煎嚭PDF generate-from-qc 璐ㄦ鍗曞嚭鎶ュ憡 鍑烘姤鍛婂脊绐� qcResult undecidableCount warnings 寰呭垽瀹� 鍙嶆煡 涓氬姟鍗曟嵁绛涢��"}
]
}
diff --git a/docs/project-business/index.html b/docs/project-business/index.html
index ec3a7aa..72f2500 100644
--- a/docs/project-business/index.html
+++ b/docs/project-business/index.html
@@ -201,8 +201,8 @@
"frontend": "mom-pro2-before锛圴ue3 绠$悊鍚庡彴锛屽悓浠撳簱瀛樻斁锛屽彧璇诲弬鑰冿級"
},
"stats": {
- "businessModules": 12,
- "coreObjects": 46,
+ "businessModules": 13,
+ "coreObjects": 48,
"documentFlows": 6,
"approvalListeners": 13,
"aiCapabilities": 8,
@@ -386,6 +386,14 @@
"roles": ["璐ㄦ鍛�(IQC/IPQC/OQC)", "璐ㄩ噺宸ョ▼甯�"],
"upstream": ["浠撳偍(鍒拌揣)", "鐢熶骇(鎶ュ伐)", "閿�鍞�(鍑哄簱)", "鍞悗(閫�璐�)"], "downstream": ["浠撳偍(鍚堟牸鍏ュ簱/鎶ュ簾鍑哄簱)", "鐢熶骇(NCR杩斿伐)"],
"coreTables": ["mes_qc_iqc", "mes_qc_ipqc", "mes_qc_oqc", "mes_qc_rqc", "mes_qc_template", "mes_qc_indicator", "mes_qc_defect", "mes_qc_ncr"]},
+ {"key": "qcreport", "name": "鏅鸿兘璐ㄦ鎶ュ憡", "color": "#b06ce0", "tag": "QC-REPORT", "flow": "quality",
+ "positioning": "鍙鍖栬璁℃姤鍛婃ā鏉� 鈫� 涓�閿嚭浠跺苟鍐荤粨鍘嗗彶鎶ュ憡",
+ "problem": "鍚勮涓氳川妫�鎶ュ憡鏍煎紡鍚勫紓锛屾帓鐗堢‖缂栫爜鏀逛竴娆″彂涓�娆$増锛涗笖鍘嗗彶鎶ュ憡蹇呴』鍙鐜般�佷笉闅忎笟鍔℃暟鎹彉鍖�",
+ "features": ["GrapesJS 鍙鍖栬璁″櫒锛堣川妫�缁勪欢璧版敞鍐屾満鍒讹紝涓嶇‖缂栫爜杩涚紪杈戝櫒锛�", "妯℃澘 + 澶氱増鏈細鑽夌0/宸插彂甯�1/宸插仠鐢�2锛屽凡鍙戝竷鐗堟湰鍐呭涓嶅彲瑕嗙洊", "缁勪欢鏁版嵁缁戝畾涓庣嫭绔嬪垽瀹氳鍒欏紩鎿庯紙绂佺敤 eval / ScriptEngine锛�", "涓庡墠绔�愬瓧瀵归綈鐨� Java 娓叉煋寮曟搸锛屽嚭绔� HTML 鍓ョ on* 浜嬩欢灞炴�т笌 javascript:/vbscript:/data: 鍗忚", "鍑轰欢鎺ュ彛锛歱review 鍙覆鏌撲笉钀藉簱涓嶆秷鑰楃紪鍙� / generate 娓叉煋+钀藉簱+鍐荤粨 data_snapshot / regenerate 鐢ㄥ喕缁撳揩鐓т笌鍚屼竴鐗堟湰閲嶆覆", "鎶ュ憡缂栧彿 QR+yyyyMMdd+4浣嶆祦姘达紝鎸夊ぉ鐙珛锛屽彲鏄惧紡鎸囧畾锛堟挒鍙蜂細鎶ュ嚭鍏蜂綋缂栧彿锛�", "缂哄彛娓呭崟鍙湪 preview/generate/regenerate 鍝嶅簲閲岃繑鍥烇紝涓嶈惤搴�", "PDF(Playwright) 褰掓。涓� MES 鍥涚璐ㄦ鍗曞綊涓�鍖栧鎺ュ緟鍚庣画杞"],
+ "objects": ["鎶ュ憡妯℃澘", "鎶ュ憡瀹炰緥"],
+ "roles": ["鎶ュ憡璁捐鍛�", "璐ㄦ鍛橈紙鍑轰欢锛�"],
+ "upstream": ["璐ㄩ噺锛堣川妫�鍗曚笂涓嬫枃锛屾湰杞敱璋冪敤鏂逛紶鍏ワ級"], "downstream": ["闄勪欢涓績锛圥DF 褰掓。路鍚庣画杞锛�", "BI"],
+ "coreTables": ["qc_report_template", "qc_report_template_version", "qc_report_instance", "qc_report_data_source", "qc_report_rule", "qc_report_render_record"]},
{"key": "dv", "name": "璁惧涓庡伐瑁呮帓鐝�", "color": "#59a8b8", "tag": "MES-DV/TM/CAL", "flow": null,
"positioning": "璁惧璧勪骇鍋ュ悍涓庣敓浜ц祫婧愪繚闅�",
"problem": "璁惧鐐规淇濆吇缁翠慨鍙墽琛屻�佸伐瑁呯姸鎬佸彲鎺с�佺彮缁勬帓鐝湁渚濇嵁",
@@ -470,17 +478,19 @@
{"name": "鐩樼偣浠诲姟", "module": "浠撳偍", "table": "mes_wm_stock_taking_task", "doc": "闈欐��/鍔ㄦ�佺洏鐐癸紝琛岀粨鏋�:姝e父/鐩樼泩(ADJUST_IN)/鐩樹簭(ADJUST_OUT)锛屽彲鍐荤粨搴撳瓨銆佺洸鐩�", "upstream": ["搴撳瓨鍙拌处"], "downstream": ["搴撳瓨鍙拌处(璋冩暣)"], "keywords": "鐩樼偣 鐩樼泩 鐩樹簭 stock taking"},
{"name": "搴撳瓨鍙拌处", "module": "浠撳偍", "table": "mes_wm_material_stock", "doc": "鐗╂枡脳浠撳簱脳搴撳尯脳搴撲綅脳鎵规脳渚涘簲鍟嗗叚鍏冪粍锛屾暟閲�/鍐荤粨/鍗犵敤/鍦ㄩ�斿洓閲�", "upstream": ["鍏ㄩ儴鍏ュ簱鍗�"], "downstream": ["鍏ㄩ儴鍑哄簱鍗�", "浜嬪姟娴佹按"], "keywords": "搴撳瓨 鍙拌处 stock 鍙敤閲�"},
{"name": "鎵规", "module": "浠撳偍", "table": "mes_wm_batch", "doc": "鍏宠仈鐗╂枡/宸ュ崟/渚涘簲鍟�/瀹㈡埛/璐ㄩ噺鐘舵�侊紱SN 鐮佸惈鎵规 uuid锛涙潯鐮佹敮鎸�18绉嶄笟鍔″璞�", "upstream": ["鍏ュ簱鍗曟嵁"], "downstream": ["搴撳瓨鍙拌处"], "keywords": "鎵规 batch SN 鏉$爜 杩芥函"},
- {"name": "IQC鏉ユ枡妫�楠�", "module": "璐ㄩ噺", "table": "mes_qc_iqc", "doc": "鍒拌揣閫氱煡/澶栧崗鍏ュ簱瑙﹀彂锛岃崏绋�0鈫掑畬鎴�4锛岀粨璁哄洖鍐欐潵婧愬崟鎹�", "upstream": ["鍒拌揣閫氱煡", "澶栧崗鍏ュ簱"], "downstream": ["閲囪喘鍏ュ簱", "渚涘簲鍟嗛��璐�", "NCR"], "keywords": "IQC 鏉ユ枡妫�楠�"},
- {"name": "IPQC杩囩▼妫�楠�", "module": "璐ㄩ噺", "table": "mes_qc_ipqc", "doc": "鎶ュ伐璐ㄦ宸ュ簭浜у嚭琛岃Е鍙戯紝瀹屾垚鍥炶皟鎺ㄨ繘鎶ュ伐涓庝骇鍑哄叆搴�", "upstream": ["鎶ュ伐"], "downstream": ["浜у嚭鍏ュ簱", "NCR"], "keywords": "IPQC 杩囩▼妫�楠� 宸℃"},
- {"name": "OQC鍑鸿揣妫�楠�", "module": "璐ㄩ噺", "table": "mes_qc_oqc", "doc": "閿�鍞嚭搴撴彁浜よЕ鍙戯紝瀹屾垚鎺ㄨ繘鍑哄簱鍗曞緟鎷h揣", "upstream": ["閿�鍞嚭搴撳崟"], "downstream": ["閿�鍞嚭搴撳崟(鎺ㄨ繘)"], "keywords": "OQC 鍑鸿揣妫�楠� 鍑哄巶妫�楠�"},
- {"name": "RQC閫�璐ф楠�", "module": "璐ㄩ噺", "table": "mes_qc_rqc", "doc": "鐢熶骇閫�鏂�/閿�鍞��璐�/鍞悗閫�璐цЕ鍙戯紝缁撹鍥炶皟鍞悗", "upstream": ["閫�鏂�", "閫�璐�"], "downstream": ["閫�璐у叆搴�", "鍞悗鍥炶皟"], "keywords": "RQC 閫�璐ф楠�"},
+ {"name": "IQC鏉ユ枡妫�楠�", "module": "璐ㄩ噺", "table": "mes_qc_iqc", "doc": "鍒拌揣閫氱煡/澶栧崗鍏ュ簱瑙﹀彂锛岃崏绋�0鈫掑畬鎴�4锛岀粨璁哄洖鍐欐潵婧愬崟鎹紱琛屾搷浣溿�屽嚭鎶ュ憡銆嶄粎鍦ㄥ凡瀹屾垚鏃跺彲瑙�", "upstream": ["鍒拌揣閫氱煡", "澶栧崗鍏ュ簱"], "downstream": ["閲囪喘鍏ュ簱", "渚涘簲鍟嗛��璐�", "NCR", "鎶ュ憡瀹炰緥(鍑烘姤鍛�)"], "keywords": "IQC 鏉ユ枡妫�楠� 鍑烘姤鍛�"},
+ {"name": "IPQC杩囩▼妫�楠�", "module": "璐ㄩ噺", "table": "mes_qc_ipqc", "doc": "鎶ュ伐璐ㄦ宸ュ簭浜у嚭琛岃Е鍙戯紝瀹屾垚鍥炶皟鎺ㄨ繘鎶ュ伐涓庝骇鍑哄叆搴擄紱琛屾搷浣溿�屽嚭鎶ュ憡銆嶄粎鍦ㄥ凡瀹屾垚鏃跺彲瑙�", "upstream": ["鎶ュ伐"], "downstream": ["浜у嚭鍏ュ簱", "NCR", "鎶ュ憡瀹炰緥(鍑烘姤鍛�)"], "keywords": "IPQC 杩囩▼妫�楠� 宸℃ 鍑烘姤鍛�"},
+ {"name": "OQC鍑鸿揣妫�楠�", "module": "璐ㄩ噺", "table": "mes_qc_oqc", "doc": "閿�鍞嚭搴撴彁浜よЕ鍙戯紝瀹屾垚鎺ㄨ繘鍑哄簱鍗曞緟鎷h揣锛涜鎿嶄綔銆屽嚭鎶ュ憡銆嶄粎鍦ㄥ凡瀹屾垚鏃跺彲瑙�", "upstream": ["閿�鍞嚭搴撳崟"], "downstream": ["閿�鍞嚭搴撳崟(鎺ㄨ繘)", "鎶ュ憡瀹炰緥(鍑烘姤鍛�)"], "keywords": "OQC 鍑鸿揣妫�楠� 鍑哄巶妫�楠� 鍑烘姤鍛�"},
+ {"name": "RQC閫�璐ф楠�", "module": "璐ㄩ噺", "table": "mes_qc_rqc", "doc": "鐢熶骇閫�鏂�/閿�鍞��璐�/鍞悗閫�璐цЕ鍙戯紝缁撹鍥炶皟鍞悗锛涜鎿嶄綔銆屽嚭鎶ュ憡銆嶄粎鍦ㄥ凡瀹屾垚鏃跺彲瑙併�傛帾杈炲凡缁熶竴涓恒�岄��璐ф楠屻�嶏紙鍘熻彍鍗曠埗椤逛笌 mes_qc_type 瀛楀吀鍐欍�岄��鏂欐楠屻�嶏紝涓庡悗绔灇涓�/琛ㄦ敞閲�/鑿滃崟鏉冮檺瀛愰」涓嶄竴鑷达紱RQC 涓夎�呴兘瑕嗙洊锛屾晠鍙栥�岄��璐ф楠屻�嶏級", "upstream": ["閫�鏂�", "閫�璐�"], "downstream": ["閫�璐у叆搴�", "鍞悗鍥炶皟", "鎶ュ憡瀹炰緥(鍑烘姤鍛�)"], "keywords": "RQC 閫�璐ф楠� 閫�鏂欐楠� 鍑烘姤鍛�"},
{"name": "NCR涓嶅悎鏍煎搧", "module": "璐ㄩ噺", "table": "mes_qc_ncr", "doc": "寰呰瘎瀹�0鈫掑凡璇勫6鈫掑凡澶勭疆7鈫掑凡鍏抽棴8锛屽缃�:閫�璐�/鎶ュ簾/杩斿伐/璁╂鎺ユ敹/闄嶇骇", "upstream": ["IQC/IPQC/OQC/RQC"], "downstream": ["閫�璐�/鎶ュ簾/杩斿伐(鍙拌处)"], "keywords": "NCR 涓嶅悎鏍� 澶勭疆 鐗归噰 鎶ュ簾"},
{"name": "璁惧", "module": "璁惧", "table": "mes_dv_machinery", "doc": "鍙拌处鐘舵��:鍋滄満/鐢熶骇涓�/淇濆吇涓紱鐐规路淇濆吇路缁翠慨宸ュ崟锛汚I 椋庨櫓棰勬祴娑堣垂鍏舵暟鎹�", "upstream": [], "downstream": ["鐐规", "缁翠慨", "鐢熶骇椋庨櫓棰勬祴"], "keywords": "璁惧 鐐规 淇濆吇 缁翠慨 machinery"},
{"name": "鍞悗宸ュ崟", "module": "鍞悗", "table": "after_sale_ticket", "doc": "鑽夌0鈫掑鐞嗕腑10鈫掑緟鍏ュ簱30鈫掑緟閫�娆�40鈫掑畬缁�50鈫掑叧闂�60/鍙栨秷99锛屽垽瀹�:涓�鑸�/缁翠慨/閫�璐�", "upstream": ["瀹㈡埛鍙嶉(浜哄伐褰曞叆)"], "downstream": ["缁翠慨璁板綍", "閫�璐х敵璇�"], "keywords": "鍞悗 宸ュ崟 ticket 缁翠慨"},
{"name": "閫�璐х敵璇�", "module": "鍞悗", "table": "after_sale_return", "doc": "鑽夌0鈫掑凡瀹℃牳20(鑷姩寤篗ES閫�璐у崟)鈫掑凡璐ㄦ40鈫掑凡鍏ュ簱50鈫掑凡閫�娆�60鈫掑叧闂�70锛涚被鍨�:閫�娆鹃��璐�/鎹㈣揣/浠呴��娆�", "upstream": ["鍞悗宸ュ崟"], "downstream": ["閿�鍞��璐у崟", "閫�娆�"], "keywords": "鍞悗閫�璐� return"},
{"name": "鍛樺伐", "module": "浜哄姏", "table": "hrm_employee", "doc": "鍦ㄨ亴1/璇曠敤2/绂昏亴3锛屽叆鑱岃嚜鍔ㄥ缓绯荤粺璐﹀彿", "upstream": [], "downstream": ["浜ゆ帴鏄犲皠", "鑰冨嫟", "钖叕"], "keywords": "鍛樺伐 鍏ヨ亴 employee"},
{"name": "绂昏亴浜ゆ帴", "module": "浜哄姏", "table": "hrm_user_handover", "doc": "from鈫抰o 鏄犲皠锛屽凡瀹屾垚20 鍚� expandUserIds 鎵╁睍浜ゆ帴浜哄彲瑙佹暟鎹紙褰撳墠鍚勪笟鍔℃ā鍧楀皻鏈疄闄呮帴鍏ヨ皟鐢級", "upstream": ["绂昏亴鐢宠"], "downstream": ["鍚勬ā鍧楁垜鐨勬暟鎹煡璇�"], "keywords": "浜ゆ帴 绂昏亴 handover expandUserIds"},
- {"name": "鎺掔彮璁″垝", "module": "璁惧", "table": "mes_cal_plan", "doc": "鐝粍脳鐝脳鏃ユ湡鎺掔彮锛屼緵鐢熶骇涓庤�冨嫟寮曠敤", "upstream": [], "downstream": ["鐢熶骇浠诲姟", "鑰冨嫟"], "keywords": "鎺掔彮 鐝粍 鐝 鏃ュ巻"}
+ {"name": "鎺掔彮璁″垝", "module": "璁惧", "table": "mes_cal_plan", "doc": "鐝粍脳鐝脳鏃ユ湡鎺掔彮锛屼緵鐢熶骇涓庤�冨嫟寮曠敤", "upstream": [], "downstream": ["鐢熶骇浠诲姟", "鑰冨嫟"], "keywords": "鎺掔彮 鐝粍 鐝 鏃ュ巻"},
+ {"name": "鎶ュ憡妯℃澘", "module": "璐ㄦ鎶ュ憡", "table": "qc_report_template", "doc": "鏅鸿兘璐ㄦ鎶ュ憡妯℃澘锛屽惎鐢�0/鍋滅敤1锛涚敾甯冨唴瀹瑰瓨鍦� qc_report_template_version锛堣崏绋�0/宸插彂甯�1/宸插仠鐢�2锛屽凡鍙戝竷涓嶅彲瑕嗙洊锛夛紝currentVersion 鎸囧悜褰撳墠宸插彂甯冪増鏈紱婧愭枃浠剁粡 AI 瀵煎叆璇嗗埆鎴愯崏绋垮悗鐢变汉宸ョ‘璁ゆ墠鎴愪负鐗堟湰锛涘悓涓�妯℃澘閲嶅瀵煎叆鎸夈�愭浛鎹€�戝鐞嗏�斺�斿厛鍒犳棫闄勪欢锛堣繛甯� blob 琛屼笌纾佺洏鏂囦欢锛夊啀缁戞柊鐨勶紝涓嶇暀瀛ゅ効鏂囦欢锛涘垹闄ゆā鏉夸細杩炲甫娓呴檮浠�", "upstream": ["浜哄伐璁捐(GrapesJS 璁捐鍣�)", "AI 瀵煎叆鑽夌(qc-report/ai-import/draft)"], "downstream": ["妯℃澘鐗堟湰", "鎶ュ憡瀹炰緥"], "keywords": "鎶ュ憡妯℃澘 璐ㄦ鎶ュ憡 template 璁捐鍣� 鐗堟湰 AI瀵煎叆 璇嗗埆 鑽夌 婧愭枃浠舵浛鎹�"},
+ {"name": "鎶ュ憡瀹炰緥", "module": "璐ㄦ鎶ュ憡", "table": "qc_report_instance", "doc": "鍑轰欢浜х墿锛岀紪鍙� QR+yyyyMMdd+4浣嶆祦姘存寜澶╃嫭绔嬩笖涓氬姟鍞竴锛屽彲鏄惧紡鎸囧畾瑕嗙洊锛堟敞鎰� uk_report_no 涓嶅尯鍒嗚蒋鍒犻櫎锛屽垹鎺夌殑鍙蜂笉鍥炴敹锛夛紱涓ゆ潯鍑轰欢鍏ュ彛锛氶�氱敤 generate锛堣皟鐢ㄦ柟鑷甫 context锛変笌 generate-from-qc锛堟暟鎹粠 MES 璐ㄦ鍗曞彇锛屾潈闄愮爜 qc-report:instance:generate 宸插叆 system_menu id=1075416锛屼簲閬撴牎楠屾寜涓氬姟浼樺厛绾у彧鎶ョ涓�澶勶細105_000 绫诲瀷闈炴硶 / 105_001 鍗曟嵁涓嶅瓨鍦� / 105_002 鏈畬鎴� / 105_003 鏈垽瀹� / 105_005 妯℃澘绫诲瀷涓嶇 / 105_006 鏃犲彲鐢ㄦ楠岄」锛涘洓寮犺川妫�鍗曞垪琛ㄧ殑琛屾搷浣溿�屽嚭鎶ュ憡銆嶄粎鍦� status=宸插畬鎴愭椂鍙锛屽脊绐楀彧鍒� reportType 涓�鑷淬�佹ā鏉垮惎鐢ㄣ�佷笖 currentVersion 鎸囧悜鐨勭増鏈凡鍙戝竷鐨勬ā鏉匡紙鍚庣 /qc-report/template/selectable 鍒ゅ畾鈥斺�斿仠鐢ㄧ増鏈笉娓呯┖ currentVersion锛屽墠绔嬁鍒嗛〉缁撴灉鑷繁鎺ㄥ浼氭紡锛夛紝缁撴灉灏卞湴灞曠ず骞惰烦鏈〉鍒楄〃锛夛紱鍐荤粨 data_snapshot锛堝垽瀹氬悗鏁版嵁锛屽惈鍚庣绠楀ソ鐨� PASS/FAIL 涓庡悎鏍肩巼锛変笌 render_html锛況egenerate 鍙噸娓叉帓鐗堛�佹暟鎹笌缂栧彿涓嶅彉锛沚usiness_id/business_type 瀛� MES 琛ㄥ悕锛坢es_qc_iqc 绛夛級涓庡崟鎹� ID锛屽彲鍙嶆煡銆佷竴鍗曞彲鍑哄浠斤紱鎶ュ憡澶村彟甯﹀崟鎹師鍒ゅ畾 qcResult(鏁�)/qcResultText(涓枃锛屽悎鏍�/鐗归噰/涓嶅悎鏍奸��璐�/涓嶅悎鏍兼姤搴�)锛屼笌寮曟搸涓夋�佸垽瀹氬苟瀛樹簰涓嶈鐩栵紱鍝嶅簲甯� undecidableCount=蹇収涓� result 涓虹┖涓茬殑椤规暟涓� warnings锛堝垎缁勬爣棰樿烦杩�/鎸囨爣宸插垹/鏈綍瀹炴祴鍊�/鏍峰搧瓒�3锛夛紝涓よ�呴兘涓嶈惤搴撱�佷簨鍚庣湅涓嶅埌", "upstream": ["鎶ュ憡妯℃澘鐗堟湰", "璐ㄦ鍗曚笂涓嬫枃(閫氱敤 generate 鐢辫皟鐢ㄦ柟浼犲叆)", "MES 璐ㄦ鍗� IQC/IPQC/OQC/RQC(generate-from-qc 缁� MesQcReportApi 鍙栨暟)"], "downstream": ["鍓嶇瀹炰緥椤� /qc/report-instance(鍒楄〃路iframe棰勮路蹇収椤电路瀵煎嚭PDF)", "PDF褰掓。(system_storage_attachment recordType=qc_report_instance)"], "keywords": "鎶ュ憡瀹炰緥 鍑轰欢 QR缂栧彿 蹇収 澶嶇幇 regenerate PDF褰掓。 鎶ュ憡瀹炰緥椤� 瀵煎嚭PDF generate-from-qc 璐ㄦ鍗曞嚭鎶ュ憡 鍑烘姤鍛婂脊绐� qcResult undecidableCount warnings 寰呭垽瀹� 鍙嶆煡 涓氬姟鍗曟嵁绛涢��"}
]
}</script>
<script type="application/json" id="data-flows">{
@@ -514,13 +524,15 @@
{"stage": "鑱斿姩", "action": "瀹℃壒閫氳繃鎸夊伐搴忔爣璁�: 鍊掑啿鈫掕嚜鍔ㄧ墿鏂欐秷鑰楁墸绾胯竟搴�(鍏佽璐熷簱瀛�)锛涜川妫�鈫掍骇鍑哄緟妫�琛岀瓑 IPQC锛涘叧閿潪妫�鈫掔洿鎺ヤ骇鍑哄叆搴�", "roles": ["绯荤粺鑷姩"]},
{"stage": "瀹屽伐", "action": "浠呮湯閬撳伐搴忓洖鍐欏伐鍗曞凡鐢熶骇鏁伴噺锛岃揪鏍囪嚜鍔ㄥ畬鎴愶紱MPS 绱鍒ゆ柇瀹屾垚骞跺彂浜嬩欢缁欓攢鍞鍗�", "roles": ["绯荤粺鑷姩"]}]},
{"id": "quality", "name": "璐ㄩ噺娴佺▼", "mermaid": "mermaid/05-quality-flow.mmd", "color": "#e06c6c",
- "summary": "鍥涢亾妫�楠岄椄鍙�(IQC/IPQC/OQC/RQC锛屼簩鎬� 0鈫�4) + 鍒ゅ畾鍥涙灉(鍚堟牸/鐗归噰/閫�璐�/鎶ュ簾) + NCR 璇勫澶勭疆鍏抽棴锛汚I 鎻愪緵鍒ゅ畾寤鸿锛汵CR 褰撳墠浠呭彴璐︿笉瑙﹀彂杩斿伐鍗曘��",
+ "summary": "鍥涢亾妫�楠岄椄鍙�(IQC/IPQC/OQC/RQC锛屼簩鎬� 0鈫�4) + 鍒ゅ畾鍥涙灉(鍚堟牸/鐗归噰/閫�璐�/鎶ュ簾) + NCR 璇勫澶勭疆鍏抽棴锛汚I 鎻愪緵鍒ゅ畾寤鸿锛汵CR 褰撳墠浠呭彴璐︿笉瑙﹀彂杩斿伐鍗曪紱妫�楠屽崟鍙敱鏅鸿兘璐ㄦ鎶ュ憡骞冲彴涓�閿嚭浠讹紙generate-from-qc锛氭暟鎹粠 MES 鍙栵紝浜旈亾鏍¢獙鍚庢覆鏌撹惤搴擄級銆�",
"steps": [
{"stage": "鏉ユ枡", "action": "鍒拌揣閫氱煡/澶栧崗鍏ュ簱鈫扞QC锛岀粨璁哄洖鍐欐帹杩涘緟鍏ュ簱鎴栬Е鍙戦��璐�", "roles": ["IQC 璐ㄦ鍛�"]},
{"stage": "杩囩▼", "action": "鎶ュ伐璐ㄦ宸ュ簭浜у嚭琛屸啋IPQC锛屽悎鏍兼媶琛屽叆搴撱�佷笉鍚堟牸鐢熸垚 NCR", "roles": ["IPQC 璐ㄦ鍛�"]},
{"stage": "鍑鸿揣", "action": "閿�鍞嚭搴撴彁浜も啋OQC锛屽畬鎴愬悗鍑哄簱鍗曡繘鍏ュ緟鎷h揣", "roles": ["OQC 璐ㄦ鍛�"]},
{"stage": "閫�璐�", "action": "閫�鏂�/閿�鍞��璐�/鍞悗閫�璐р啋RQC锛岀粨璁哄洖璋冨崟鎹笌鍞悗", "roles": ["RQC 璐ㄦ鍛�"]},
- {"stage": "涓嶅悎鏍�", "action": "NCR: 寰呰瘎瀹♀啋璇勫鈫掑缃�(閫�璐�/鎶ュ簾/杩斿伐/璁╂鎺ユ敹/闄嶇骇)鈫掑叧闂�", "roles": ["璐ㄩ噺宸ョ▼甯�"]}]},
+ {"stage": "涓嶅悎鏍�", "action": "NCR: 寰呰瘎瀹♀啋璇勫鈫掑缃�(閫�璐�/鎶ュ簾/杩斿伐/璁╂鎺ユ敹/闄嶇骇)鈫掑叧闂�", "roles": ["璐ㄩ噺宸ョ▼甯�"]},
+ {"stage": "鍑轰欢", "action": "涓ゆ潯鍑轰欢鍏ュ彛锛氣憼閫氱敤 generate/preview(璋冪敤鏂硅嚜甯︿笂涓嬫枃) 娓叉煋 HTML 骞跺喕缁撴暟鎹揩鐓э紝缂栧彿 QR+鏃ユ湡+4浣嶆祦姘存寜澶╃嫭绔嬶紝preview 鍙覆鏌撲笉钀藉簱涓嶆秷鑰楃紪鍙凤紝regenerate 鐢ㄥ喕缁撳揩鐓ч噸娓蹭笖鏁版嵁涓庣紪鍙蜂笉鍙樺苟浣滃簾宸插綊妗� PDF锛屽鍑� PDF 鐢卞悗绔皟 Chromium 鎵撳嵃瀹炰緥宸插瓨鐨� HTML 鍚庡綊妗i檮浠朵腑蹇冿紱鈶enerate-from-qc 鐢辫川妫�鍗曠洿鎺ュ嚭浠�(鏁版嵁缁� MesQcReportApi 浠� MES 鍙栵紝鍓嶇涓嶆嫾涓婁笅鏂�)锛屽嚭浠跺墠浜旈亾鏍¢獙鎸変笟鍔′紭鍏堢骇鍙姤绗竴澶勶細绫诲瀷闈炴硶/鍗曟嵁涓嶅瓨鍦�/鏈畬鎴愭楠�/鏈~鍒ゅ畾/妯℃澘绫诲瀷涓嶇/鏃犲彲鐢ㄦ楠岄」锛屾姤鍛婂ご鍙﹀甫鍗曟嵁鍘熷垽瀹� qcResult+qcResultText 涓庡紩鎿庡垽瀹氬苟瀛橈紝鍝嶅簲鍥� undecidableCount 寰呭垽瀹氶」鏁颁笌 warnings(鍒嗙粍鏍囬璺宠繃/鎸囨爣宸插垹/鏈綍瀹炴祴鍊�/鏍峰搧瓒�3)锛屽悓涓�寮犲崟鎹彲鍙嶅鍑哄浠�", "roles": ["璐ㄦ鍛�"]},
+ {"stage": "寤烘ā鏉�", "action": "AI 瀵煎叆锛氫笂浼犳棦鏈夋楠屾姤鍛婃枃浠�(鎵弿浠�/鐓х墖銆佺數瀛愮増 PDF銆乄ord/Excel) 鈫� 璇嗗埆鎴愭ā鏉胯崏绋�(涓嶈惤搴�) 鈫� 浜哄伐鍦ㄨ璁″櫒纭璋冩暣鍚庝繚瀛樹负鐗堟湰锛�.doc/.xls 鏃ф牸寮忎笉鏀寔", "roles": ["璐ㄦ鍛�", "璐ㄩ噺宸ョ▼甯�"]}]},
{"id": "warehouse", "name": "浠撳偍娴佺▼", "mermaid": "mermaid/06-warehouse-flow.mmd", "color": "#7e6bd6",
"summary": "15 绫诲崟鎹┍鍔ㄥ簱瀛樺彴璐�(鍏厓缁勩�佸洓閲�)鍙樺姩锛屽叏閮ㄧ粡浜嬪姟娴佹按鐣欑棔锛涙敮鎸佽皟鎷ㄥ湪閫斻�佺洏鐐硅皟鏁淬�佹壒娆�/SN 杩芥函銆佸簱瀛樺崰鐢ㄤ笌鍥涚骇鍐荤粨銆佺嚎杈硅櫄鎷熷簱璐熷簱瀛橈紱瀵瑰 WmsStockApi 渚� ERP 鏀跺彂銆�",
"steps": [
@@ -542,6 +554,7 @@
{"stage": "褰曞叆鎻愭晥", "action": "鍙戠エ OCR(鍥剧墖澶氭ā鎬�/PDF鏂囨湰)銆佹姤浠峰崟 OCR 鈫� 缁撴瀯鍖栭濉�", "roles": ["閲囪喘鍛�", "閿�鍞�"]},
{"stage": "杈呭姪鍒ゅ畾", "action": "璐ㄦ鍗�+鎸囨爣+缂洪櫡 鈫� 寤鸿鍚堟牸/鐗归噰/閫�璐�/鎶ュ簾+鐞嗙敱", "roles": ["璐ㄦ鍛�"]},
{"stage": "鍐崇瓥棰勬祴", "action": "缂烘枡/鐢熶骇鏃堕暱/鐢熶骇椋庨櫓/浜や粯鍥涚被棰勬祴渚涜鍒掓帓浜у弬鑰�", "roles": ["璁″垝鍛�"]},
+ {"stage": "妯℃澘璇嗗埆", "action": "涓婁紶鏃㈡湁妫�楠屾姤鍛婃枃浠�(鎵弿浠�/鐓х墖銆佺數瀛愮増 PDF銆乄ord/Excel) 鈫� 鍒嗛�氶亾鎶藉彇(鏈夋枃鏈眰璧版枃鏈�佹壂鎻忕増閫愰〉杞浘) 鈫� 澶фā鍨嬫寜鍓嶇涓婁紶鐨勭粍浠舵竻鍗曚骇鍑烘墎骞崇粍浠惰崏绋� 鈫� 浜哄伐鍦ㄨ璁″櫒纭鍚庝繚瀛樹负妯℃澘鐗堟湰", "roles": ["璐ㄦ鍛�", "璐ㄩ噺宸ョ▼甯�"]},
{"stage": "鐭ヨ瘑妫�绱�", "action": "鏂囨。鈫掑垏鐗団啋Milvus 鍚戦噺鈫掓绱㈡帴鍙�(棰勭暀)", "roles": ["鈥�"]}]}
]
}</script>
@@ -627,6 +640,13 @@
RQC 閫�璐ф楠�
NCR 涓嶅悎鏍煎搧
璐ㄦ鏂规涓庢寚鏍囩己闄�
+ 鏅鸿兘璐ㄦ鎶ュ憡 QC-REPORT
+ 鎶ュ憡妯℃澘涓庡鐗堟湰
+ 鍙鍖栬璁″櫒
+ 缁勪欢缁戝畾涓庡垽瀹氳鍒�
+ HTML 娓叉煋寮曟搸
+ 鎶ュ憡鍑轰欢涓庣紪鍙�
+ 鏁版嵁蹇収鍐荤粨
璁惧涓庢帓鐝�
璁惧鍙拌处
鐐规涓庝繚鍏�
@@ -749,6 +769,69 @@
N2 -->|澶勭疆鏂瑰紡:閫�璐�1鎶ュ簾2杩斿伐3璁╂鎺ユ敹4闄嶇骇浣跨敤5| N3[宸插缃�7]
N3 -->|鍏抽棴| N4[宸插叧闂�8]
Q8[鏀拺鏁版嵁:璐ㄦ鏂规路妫�楠屾寚鏍嚶风己闄峰簱路鎸囨爣缁撴灉] --- A1
+ Q8H["妫�楠屾寚鏍囩殑灞傜骇鍙湪璐ㄦ鎸囨爣椤电淮鎶ぢ锋潯鐩被鍨� 鎵�灞炲垎缁� 鍏紡 鎺掑簭鍙仿峰彧鍏佽涓ゅ眰路鍒犲垎缁勭骇鑱斿垹瀛愰」"] --- Q8
+ A1 -->|鍑轰欢 generate-from-qc| GATE{鍑轰欢鍏亾鏍¢獙路鎸変笟鍔′紭鍏堢骇鍙姤绗竴澶剗
+ A2 -->|鍑轰欢 generate-from-qc| GATE
+ A3 -->|鍑轰欢 generate-from-qc| GATE
+ A4 -->|鍑轰欢 generate-from-qc| GATE
+ GATE -->|000 绫诲瀷闈炴硶| GE0[105_000 qcType 涓嶅湪 1~4]
+ GATE -->|001 鍗曟嵁涓嶅瓨鍦▅ GE1[105_001]
+ GATE -->|002 鏈畬鎴愭楠寍 GE2[105_002路甯﹀綋鍓嶇姸鎬佷腑鏂囧悕]
+ GATE -->|003 鏈~鍒ゅ畾| GE3[105_003路鍒楀嚭鍥涗釜鍙�夊垽瀹歖
+ GATE -->|005 妯℃澘绫诲瀷涓嶇| GE5[105_005路涓よ竟绫诲瀷涓枃鍚嶉兘缁櫬峰墠绔寜 reportType 棰勮繃婊
+ GATE -->|006 鏃犲彲鐢ㄦ楠岄」| GE6[105_006]
+ GATE -->|閫氳繃路鍙厑璁稿悓绫诲瀷宸插彂甯冩ā鏉縷 RP[鏅鸿兘璐ㄦ鎶ュ憡骞冲彴 qcreport]
+ RP --> RPT[鎶ュ憡妯℃澘 qc_report_template路鍚敤0鍋滅敤1]
+ RPT --> RPTV[妯℃澘鐗堟湰 qc_report_template_version路鑽夌0宸插彂甯�1宸插仠鐢�2路褰撳墠鐗堟湰涓嶅彲鍋滅敤 101_010]
+ RPTVSAVE[璁捐鍣ㄤ繚瀛� create 鎴� update] -->|鍐欏叆渚ч椄闂疯鍒�101_006 涓庣敾甯冨畨鍏�101_009 涓嶅悎鏍间竴寰嬩笉钀藉簱| RPTV
+ RPTVSAVE -.->|鍙崱鏂板啓鍏ヂ峰瓨閲忚剰鐢诲竷涓嶅洖婧牳鏌 CVNOTE[鐢诲竷鏍¢獙瑕嗙洊涓夊娉ㄥ叆闈⒙穞agName 灞炴�у悕 鏁存CSS]
+ RPTV -->|鎸夊凡鍙戝竷鐗堟湰娓叉煋| RPI[鎶ュ憡瀹炰緥 qc_report_instance路缂栧彿 QR+yyyyMMdd+4浣嶆祦姘绰锋寜澶╃嫭绔媇
+ RPI --> SNAP[鍐荤粨 data_snapshot路鍒ゅ畾鍚庢暟鎹惈 PASS FAIL 涓庡悎鏍肩巼]
+ RPI --> RHTML[render_html 瀹屾暣 HTML 鏂囨。路鍑虹珯宸插墺绂讳簨浠跺睘鎬т笌鍗遍櫓鍗忚]
+ RPI --> RREGEN[閲嶆柊鐢熸垚 regenerate路鍐荤粨蹇収+鍚屼竴妯℃澘鐗堟湰閲嶆覆路鏁版嵁涓庣紪鍙蜂笉鍙樎峰苟浣滃簾宸插綊妗DF]
+ RPI --> RPDF[瀵煎嚭PDF 鍚庣璋僀hromium鎵撳嵃宸插瓨HTML路褰掓。 system_storage_attachment路recordType=qc_report_instance]
+ RPI --> RUI[鎶ュ憡瀹炰緥椤� /qc/report-instance路鑿滃崟鎸傝川閲忕鐞� parent_id=5500]
+ RUI -->|鏉冮檺鐮亅 RPERM["qc-report:instance:query 鏌ヨ路:export 瀵煎嚭PDF路:delete 鍒犻櫎路:create 閫氱敤鍑轰欢路:generate 璐ㄦ鍗曞嚭浠�(menu 1075416)"]
+ RUI -->|鍙嶆煡 businessType=mes_qc_iqc 绛夎〃鍚� + businessId| RBACK[鍚屼竴寮犺川妫�鍗曞彲鍑哄浠芥姤鍛娐峰巻鍙茬暀鐥曢渶瑕伮蜂笉鍋氶噸澶嶆嫤鎴猐
+ RUI --> RPREVIEW[璇︽儏寮圭獥路iframe sandbox绌哄睘鎬ф覆鏌� render_html路鏁版嵁蹇収椤电灞曠ず鍐荤粨 data_snapshot]
+ A1 -.->|鍓嶇鍏ュ彛路琛屾搷浣溿�屽嚭鎶ュ憡銆嶄粎 status=宸插畬鎴愬彲瑙亅 UIREP[鍑烘姤鍛婂脊绐椔稩QC IPQC OQC RQC 鍥涢〉鍏辩敤]
+ A2 -.->|鍚屼笂| UIREP
+ A3 -.->|鍚屼笂| UIREP
+ A4 -.->|鍚屼笂| UIREP
+ UIREP -->|鍙垪 reportType 涓庢湰鍗曚竴鑷绰峰惎鐢峰綋鍓嶇増鏈凡鍙戝竷涓旂敾甯冮潪绌郝烽伩鍏嶉�変腑蹇呰鎷掔殑缁勫悎| UIPICK[鐢ㄦ埛閫夋ā鏉縘
+ UIPICK -->|POST generate-from-qc| GATE
+ UIREP -->|缁撴灉灏卞湴灞曠ず reportNo itemCount| UIRES["undecidableCount>0 钃濊壊淇℃伅鏉★紙澶氫负杩囩▼鍙傛暟鏃犲垽瀹氳鍒櫬烽粍鑹蹭細鍑犱箮姣忓崟璇姤锛壜穡arnings 涓� errors 閫愭潯灞曠ず路涓嶈惤搴撲簨鍚庣湅涓嶅埌"]
+ UIRES -->|鏌ョ湅鎶ュ憡鍒楄〃| RUI
+ RUI -->|璺敱 query 甯﹀叆 businessType+businessId 骞堕濉悳绱 RBACK
+ GATE -->|MesQcReportApi.getQcReportData| MESMAP[MES 鍥涘眰鍙栨暟褰掍竴路鍗曞ご / 鍒ゅ畾渚濇嵁琛� max min threshold / 鏍峰搧 indicator_result / 瀹炴祴鍊� result_detail]
+ MESMAP --> RCTX[鎶ュ憡涓婁笅鏂� report+inspectionItems路鐢卞悗绔槧灏勫櫒浜у嚭路鍓嶇涓嶅啀鑷繁鎷糫
+ RCTX --> RCITEM[妫�楠岄」=鏍峰搧脳鎸囨爣浜ゅ弶灞曞紑路鍏ㄦ寚鏍囪繘涓嶈繃婊ぢ峰鏍峰搧鏃舵牱鍝佸彿鎶樿繘 remark]
+ RCTX --> RCQC[鎼哄甫鍗曟嵁鍘熷垽瀹� qcResult 鏁奥穛cResultText 涓枃路涓庡紩鎿庡垽瀹氬苟瀛樹簰涓嶈鐩朷
+ MESMAP -->|鍒嗙粍椤� item_type=2 涓庡畠鐨勫瓙椤规寜 parent_id 杩樺師涓ゅ眰路褰掑睘涓嶇湅 type 涔熶笉鐪嬭搴弢 RCTXG
+ RCTXG["鍒嗙粍杩樺師路缁勫ご琛岃儗缁勫悕涓� formula_text 鍏紡路缁勫唴绗竴琛岃儗 span=璇ョ粍鎬昏鏁奥峰悓缁勫叾浣欒 span=1 涓� hidden 璁╀綅路鍙悎骞舵楠岄」鐩竴鍒�"] --- RCTX
+ MESMAP -.->|鍒嗙粍椤规湰鍗曟病鏈夊睘浜庡畠鐨勫瓙椤� / 缁勫ご鏈崟娌℃湁琛岀敱鍚庣琛ヤ竴琛寍 RCWARN
+ MESMAP -.->|鎸囨爣宸插垹 / 鏈綍瀹炴祴鍊硷紙缁勫ご閿氱偣琛屾寜瀹氫箟鏃犲�悸蜂笉鎶ワ級 / 鏍峰搧瓒� 3 涓疯繘 warnings| RCWARN
+ RCWARN[warnings 杞彁绀郝蜂笉钀藉簱路浜嬪悗鐪嬩笉鍒伴渶鑷鐣欑棔] --- RCTX
+ RCITEM --- RCTX
+ RCQC --- RCTX
+ RCTX --> RPI
+ RCTX --> RUNDEC["undecidableCount 娌℃湁鍒ゅ畾缁撹鐨勯」鏁�=蹇収閲� result 涓虹┖涓茬殑椤孤峰惈鏃犲垽瀹氳鍒欎笌寰呭垽瀹氫袱绉嵚蜂笉璁″叆鍚堟牸鐜囧垎姣嶄笌鎶ュ憡缁撹路鐢熸垚鏃跺脊鎻愮ず涓嶅洖濉�"]
+ RPT -->|杩涘叆璁捐鍣ㄥ苟甯� templateId路鏉冮檺 qc-report:template:ai-import| AIIMP[AI瀵煎叆 qc-report/ai-import/draft]
+ AISRC["婧愭枃浠� 鎵弿浠剁収鐗嚶风數瀛愮増PDF路Word(.docx) Excel(.xlsx)路txt csv"] -->|涓婁紶璧� system Storage API 鍙� blobId路缁戜负 qc_report_template 闄勪欢| AIIMP
+ AISRC -.->|鍚屼竴妯℃澘閲嶅瀵煎叆鎸夋浛鎹㈠鐞喡峰厛鍒犳棫闄勪欢鍐嶇粦鏂扮殑路杩炲悓 blob 琛屼笌纾佺洏鏂囦欢涓�璧锋竻| AIIMP
+ AISRC -.->|docx 鐨� Word 椤电湁椤佃剼璇诲彇骞朵互 椤电湁 椤佃剼 鏍囪骞跺叆璇嗗埆鍐呭路椤电湁鍦ㄦ鏂囧墠椤佃剼鍦ㄦ鏂囧悗路鍚屾椂杩� warnings路鎵弿浠剁収鐗囦笉鍙楀奖鍝峾 AIIMP
+ AIIMP -->|璇嗗埆路鍙骇鑽夌涓嶈惤搴搢 AIRD[妯℃澘鑽夌 鎵佸钩缁勪欢+灞炴�ф竻鍗昡
+ AIHINT[绉湪娓呭崟姣忛」甯� hint 閫夊瀷璇存槑路鏉ヨ嚜鍓嶇娉ㄥ唽琛� aiHint路缁勪欢閫夊瀷鐨勫敮涓�鐪熺浉鏉ユ簮] -.->|閫夊瀷浠� hint 涓哄噯路鏈変笓闂ㄧ粍浠跺氨涓嶉��鐢ㄩ�氱敤缁勪欢鍑戞暟| AIIMP
+ AIIMP -->|琛ㄦ牸鏈鐨勮惤娆剧缃茶灞炶惤娆句笉灞炴暟鎹路涓庡師浠堕〉鑴氬悎骞朵笖浜哄悕鏃ユ湡鐣欑┖鎵嬪~路涓嶅緱鑷�犵粦瀹氶敭| AIRD
+ AIIMP -.->|鍘熶欢鍒楁瘮榛樿澶氭垨琛ㄥご鍒嗕袱灞傛垨鏍峰搧瀛楁涓嶅悓鏃堵峰啓杩涚粍浠剁殑 columns headerSpans fields 涓変釜鏂囨湰灞炴�ц鐩柭蜂笉鎹㈢粍浠秥 AIRD
+ AIKEY[鎶ュ憡鍙粦瀹氶敭鐧藉悕鍗暵风敱鍚庣 ReportFields 鍙嶅皠鐢熸垚路涓嶆墜鍐橾 -.->|鍙缂栭�犱笉缁欏彲閫夐泦鍚堟ā鍨嬪彧鑳界寽路鏁呭叏閲忔灇涓緗 AIIMP
+ AIRD -->|浜哄伐鍦ㄨ璁″櫒纭路瑁呴厤鍣ㄧ紪璇戣繘鐢诲竷鍚庝繚瀛榺 RPTV
+ AIRD -.->|鐢诲竷涓婄殑 ReportHeader ReportFooter 鏄鏂囬噷鐨勬姮澶磋惤娆韭蜂笌 PDF 姣忛〉閲嶅鐨勭増寮忛〉鐪夐〉鑴氫笉鏄竴鍥炰簨| RPTV
+ AIIMP -.->|琛ㄥご鏌愬垪鑷繁鏃㈡槸鍒楀悕鍙堟槸涓婃牸路鍘熶欢閲屾槸涓�鏍肩旱鍚戝悎骞惰法浣忎笂涓嬩袱灞傘�佷笅灞傞偅鏍煎湪鎻愬彇鏂囨湰閲屽啓鐫�鈫戝悓涓妡 AIRD
+ AIIMP -.->|璇ユ鏍囬涓庡垪鍚嶄竴瀛椾笉宸墠璁ゆ垚绾靛悜鍚堝苟鏍笺�佸嚭 rowspan=2 涓�鏍间笖涓嬪眰璺宠繃璇ュ垪路涓嶄竴鑷村氨琚綋鎴愬彟涓�灞傚垎缁勬爣棰樸�佺粨璁轰簩瀛椾笂涓嬪悇鍗颁竴閬峾 AIRD
+ RPTVSAVE -.->|璁捐鍣ㄧ敾甯冧笉璺戠粦瀹毬风粍鍚嶆牸鐨� hidden 鍗犱綅绗︿細琚祻瑙堝櫒褰撴垚鐪� hidden 璁╂暣琛屽乏绉汇�佹湯鍒楁尋鎴愮珫鎺掔粏鏉 CVNOTE
+ RPTVSAVE -.->|鑷畾鍒椾笉甯﹀搴﹀0鏄幝峰垪瀹藉彧鑳界敱鏈�灏忓唴瀹瑰搴﹀�掓帹路鑰屽�兼槸鍗犱綅绗﹁繖绫讳笉鍚┖鏍肩殑闀夸覆路鏁磋〃浼氳鎾戝嚭绾稿紶銆佹湯鍒楁尋鎴愮珫鏉 CVWIDTH
+ CVWIDTH["鏁呰嚜瀹氬垪鐨勫崟鍏冩牸甯� overflow-wrap:anywhere 鍏佽闀夸覆鎶樿路榛樿鍒楁湁鎵嬪伐瀹藉害澹版槑涓嶅姞路瀹炴祴鍔犱簡鍙嶈�屾妸妫�楠岄」鐩瓙椤规尋鍒� 30 浣欏儚绱犮�佽楂樼炕鍑犲��"] --- RPTVSAVE
</pre>
<pre style="display:none" class="mmd-src" data-mmd="06-warehouse-flow">
flowchart LR
@@ -824,6 +907,8 @@
AI[AI 骞冲彴 閫氫箟鍗冮棶+Milvus] -.->|鍙戠エOCR| ERP
AI -.->|鎶ヤ环OCR| CRM
AI -.->|璐ㄦ鍒ゅ畾涓庣敓浜ч娴媩 MES
+ MES -.->|璐ㄦ鍗曚笂涓嬫枃路鏈疆鐢辫皟鐢ㄦ柟浼犲叆 寰� MesQcReportApi 鎵撻�殀 QCR[鏅鸿兘璐ㄦ鎶ュ憡 qcreport 妯℃澘鐗堟湰瀹炰緥蹇収]
+ QCR -.->|PDF 褰掓。路鍚庣画杞| STG
MES --> BI[BI 绠$悊椹鹃┒鑸� SQL閰嶇疆澶у睆]
ERP --> BI
CRM --> BI
@@ -872,6 +957,39 @@
IV -->|鍥炴寮哄埗鍏堝紑绁▅ RK
RC -->|鍏宠仈CRM瀹㈡埛鏍¢獙| CU
PA -->|鍏宠仈鏉ョエ涓庝緵搴斿晢| PI
+ subgraph S4 [鏅鸿兘璐ㄦ鎶ュ憡 qcreport]
+ RPT[鎶ュ憡妯℃澘] --> RPTV[妯℃澘鐗堟湰]
+ RPTVSAVE[璁捐鍣ㄤ繚瀛� create 鎴� update] -->|鍐欏叆渚ч椄闂� 瑙勫垯101_006 鐢诲竷瀹夊叏101_009 涓嶅悎鏍间笉钀藉簱| RPTV
+ RPTVSAVE -.->|鍙崱鏂板啓鍏� 瀛橀噺鑴忕敾甯冧笉鍥炴函鏍告煡| CVNOTE[鐢诲竷鏍¢獙瑕嗙洊 tagName 灞炴�у悕 鏁存CSS 涓夊娉ㄥ叆闈
+ RPTV --> RPI[鎶ュ憡瀹炰緥]
+ RPI --> SNAP[鏁版嵁蹇収鍐荤粨]
+ RPI --> RHTML[HTML 娓叉煋浜х墿]
+ RPI --> RPDF[PDF 浜х墿]
+ AISRC[婧愭枃浠� 鎵弿浠剁収鐗嚶风數瀛愮増PDF路Word Excel路txt csv] -->|涓婁紶璧� system Storage API 鍙� blobId 骞剁粦涓烘ā鏉块檮浠秥 AIRD[AI 璇嗗埆鑽夌]
+ AIRD -->|浜哄伐鍦ㄨ璁″櫒纭鍚庝繚瀛榺 RPTV
+ end
+ QCDOC[璐ㄦ鍗� IQC IPQC OQC RQC] -->|generate-from-qc路甯� qcType qcId templateId| QCGATE{浜旈亾鏍¢獙 绫诲瀷 瀛樺湪 宸插畬鎴� 宸插垽瀹� 妯℃澘绫诲瀷 鏈夋楠岄」}
+ QCGATE -->|浠讳竴涓嶈繃路鎸変笟鍔′紭鍏堢骇鍙姤绗竴澶剕 QCERR[105_000~105_006]
+ QCGATE -->|閫氳繃| MESQCAPI[MesQcReportApi 鍥涘眰鍙栨暟路鍗曞ご 鍒ゅ畾渚濇嵁琛� 鏍峰搧 瀹炴祴鍊糫
+ MESQCAPI -->|绾嚱鏁版槧灏勫櫒褰掍竴 鍚師鍒ゅ畾 qcResult qcResultText| RPI
+ MESQCAPI -.->|鍒嗙粍鏍囬璺宠繃 鎸囨爣宸插垹 鏈綍瀹炴祴鍊� 鏍峰搧瓒�3| QCWARN[warnings 杞彁绀郝蜂笉钀藉簱]
+ QCWARN -.-> RPI
+ RPI -.->|undecidableCount=蹇収 result 涓虹┖涓茬殑椤孤风敓鎴愭椂寮规彁绀簗 QCFE
+ RPI -.->|businessType=mes_qc_iqc 绛夎〃鍚� + businessId 鍙嶆煡路涓�鍗曞彲鍑哄浠絴 QCFE
+ RPT -.->|report_type 鏁板瓧瀛楃涓查』绛変簬 qcType路鍓嶇鎹杩囨护妯℃澘鍒楄〃| QCGATE
+ RPTV -->|妯℃澘鍋滅敤鍚庝笉鍐嶅嚭鏂颁欢路鍘嗗彶瀹炰緥涓嶅彈褰卞搷路褰撳墠鐗堟湰涓嶅彲鍋滅敤 101_010| RPI
+ RPT -->|杩涘叆璁捐鍣ㄥ甫 templateId 璋� AI 瀵煎叆| AIRD
+ RPI -->|鍒楄〃 璇︽儏 棰勮 鎵撳嵃| QCFE["鍓嶇鎶ュ憡椤甸潰 /qc/report-instance 宸茶惤鍦奥穒frame 娓叉煋 render_html + 蹇収椤电 + 瀵煎嚭PDF"]
+ RPDF -->|褰掓。 闄勪欢涓績 recordType=qc_report_instance| PDFARCH[system_storage_attachment]
+ AISRC -.->|褰掑睘 闄勪欢涓績 recordType=qc_report_template| PDFARCH
+ AISRC -.->|鍚屼竴妯℃澘閲嶅瀵煎叆鎸夋浛鎹㈠鐞喡峰厛鍒犳棫闄勪欢路杩炲悓 blob 琛屼笌纾佺洏鏂囦欢涓�璧锋竻| PDFARCH
+ QCFE -.->|鏉冮檺鐮� qc-report:instance:query/export/delete/create 宸插叆 system_menu| SYS1[system_menu]
+ QCGATE -.->|鏉冮檺鐮� qc-report:instance:generate 宸插叆 system_menu id=1075416| SYS1[system_menu]
+ QCDOC -.->|鍓嶇鍏ュ彛 琛屾搷浣溿�屽嚭鎶ュ憡銆嶄粎 status=宸插畬鎴愬彲瑙伮峰洓椤靛叡鐢ㄥ悓涓�寮圭獥| UIREP[鍑烘姤鍛婂脊绐椔峰彧鍒楀悓绫诲瀷 鍚敤 涓旀湁鐢熸晥鐗堟湰鐨勬ā鏉縘
+ UIREP -->|閫夋ā鏉垮悗 POST generate-from-qc| QCGATE
+ UIREP -.->|缁撴灉灏卞湴灞曠ず reportNo itemCount 涓� undecidableCount 鍛婅| QCFE
+ QCFE -.->|杩涘叆鏃跺甫 businessType+businessId 璺敱 query路棰勫~鎼滅储琛ㄥ崟鐨勩�屼笟鍔″崟鎹�嶅瓧娈祙 UIREP
+ RPT -.->|鏉冮檺鐮� qc-report:template:ai-import 宸插叆 system_menu| SYS1
</pre>
<pre style="display:none" class="mmd-src" data-mmd="10-business-object">
erDiagram
@@ -910,6 +1028,8 @@
erp_purchase_order ||--o{ erp_purchase_invoice : "鏉ョエ"
erp_purchase_invoice ||--o{ erp_finance_payment : "浠樻"
hrm_employee ||--o| hrm_user_handover : "绂昏亴浜ゆ帴鏄犲皠"
+ qc_report_template ||--o{ qc_report_template_version : "澶氱増鏈�"
+ qc_report_template_version ||--o{ qc_report_instance : "鍐荤粨鍑轰欢鐗堟湰"
</pre>
<pre style="display:none" class="mmd-src" data-mmd="11-ai-business-flow">
flowchart TD
@@ -931,6 +1051,23 @@
R3[宸ュ簭鏍囧噯宸ユ椂+璁惧姣忓皬鏃朵骇閲�+浼犻�佸�嶇巼] --> R4[鐢熶骇鏃堕暱棰勬祴]
R5[IPQC缂洪櫡鐜�+璁惧淇濆吇鐐规+鐗╂枡鍙敤鐜�+鍏抽敭宸ュ簭] --> R6[鐢熶骇椋庨櫓棰勬祴]
R7[杩涘害+鍓╀綑澶╂暟+浠诲姟瀹屾垚鐘舵��+瀹㈡埛浜ゆ湡] --> R8[浜や粯棰勬祴路鑳藉惁鎸夋椂+缃俊搴�+寤惰鍥犵礌]
+ W1[璐ㄦ鍛樹笂浼犳棦鏈夋楠屾姤鍛婃枃浠� blobId] --> W2{鎵╁睍鍚嶄笌鍐呭鍒ゅ畾}
+ W2 -->|png/jpg/bmp/gif/webp| W3[鍘熷瓧鑺傝蛋 chatWithImage]
+ W2 -->|PDF 鏈夋枃鏈眰| W4[PDFBox 鎶藉彇鏂囨湰 鈫� chat]
+ W2 -->|PDF 鎵弿鐗坾 W5[PDFRenderer 閫愰〉杞琍NG 鈫� 姣忛〉 chatWithImage]
+ W2 -->|docx/xlsx| W6["POI 鎶藉彇路琛ㄦ牸褰掍竴鎴愮ǔ瀹氱綉鏍硷紙gridSpan 琛ョ┖鍗犱綅 / vMerge 缁牸鏍� 鈫戝悓涓婏級"]
+ W2 -->|txt/csv| W7[鐩磋鏂囨湰 鈫� chat]
+ W2 -->|doc/xls| W8[鎷掔粷路鎻愮ず鍙﹀瓨涓� docx/xlsx]
+ W3 --> W9[澶氶〉閫愰〉璇嗗埆]
+ W4 --> W9
+ W5 --> W9
+ W6 --> W9
+ W7 --> W9
+ W9 --> W10["鎸�(type,props)鍘婚噸鍚堝苟鈫掓墎骞崇粍浠惰崏绋�+summary+warnings"]
+ W10 --> W11[寮圭獥棰勮路浜哄伐纭鍚庤杩涜璁″櫒鐢诲竷]
+ W11 --> W12[浜哄伐璋冩暣鈫掍繚瀛樹负妯℃澘鐗堟湰路杩欐槸鍞竴钀藉簱鐐筣
+ WCL[缁勪欢绉湪娓呭崟鐢卞墠绔粠娲绘敞鍐岃〃鐢熸垚骞堕殢璇锋眰涓婁紶] --- W9
+ WSAFE[鍙骇鑽夌涓嶈惤搴撀锋湭娉ㄥ唽type鍦ㄨ閰嶉樁娈佃璺宠繃路姘歌繙浜т笉鍑轰换鎰廐TML] --- W10
KB1[鐭ヨ瘑搴撴枃妗d笂浼燯RL] --> KB2[POI/Tika鎻愬彇鏂囨湰] --> KB3[鍒囩墖绾�800tokens鈫掑悜閲忓寲鈫扢ilvus]
KB3 --> KB4[鍒嗘妫�绱㈡帴鍙� topK+鐩镐技搴﹂槇鍊糫
KB4 -.-> KB5[鏆傛湭鎺ュ叆涓氬姟闂瓟娴佺▼路寰呯‘璁
diff --git a/docs/project-business/mermaid/01-business-mindmap.mmd b/docs/project-business/mermaid/01-business-mindmap.mmd
index c27d91f..fad892e 100644
--- a/docs/project-business/mermaid/01-business-mindmap.mmd
+++ b/docs/project-business/mermaid/01-business-mindmap.mmd
@@ -55,6 +55,13 @@
RQC 閫�璐ф楠�
NCR 涓嶅悎鏍煎搧
璐ㄦ鏂规涓庢寚鏍囩己闄�
+ 鏅鸿兘璐ㄦ鎶ュ憡 QC-REPORT
+ 鎶ュ憡妯℃澘涓庡鐗堟湰
+ 鍙鍖栬璁″櫒
+ 缁勪欢缁戝畾涓庡垽瀹氳鍒�
+ HTML 娓叉煋寮曟搸
+ 鎶ュ憡鍑轰欢涓庣紪鍙�
+ 鏁版嵁蹇収鍐荤粨
璁惧涓庢帓鐝�
璁惧鍙拌处
鐐规涓庝繚鍏�
diff --git a/docs/project-business/mermaid/05-quality-flow.mmd b/docs/project-business/mermaid/05-quality-flow.mmd
index d34e8f7..ea108dc 100644
--- a/docs/project-business/mermaid/05-quality-flow.mmd
+++ b/docs/project-business/mermaid/05-quality-flow.mmd
@@ -18,3 +18,66 @@
N2 -->|澶勭疆鏂瑰紡:閫�璐�1鎶ュ簾2杩斿伐3璁╂鎺ユ敹4闄嶇骇浣跨敤5| N3[宸插缃�7]
N3 -->|鍏抽棴| N4[宸插叧闂�8]
Q8[鏀拺鏁版嵁:璐ㄦ鏂规路妫�楠屾寚鏍嚶风己闄峰簱路鎸囨爣缁撴灉] --- A1
+ Q8H["妫�楠屾寚鏍囩殑灞傜骇鍙湪璐ㄦ鎸囨爣椤电淮鎶ぢ锋潯鐩被鍨� 鎵�灞炲垎缁� 鍏紡 鎺掑簭鍙仿峰彧鍏佽涓ゅ眰路鍒犲垎缁勭骇鑱斿垹瀛愰」"] --- Q8
+ A1 -->|鍑轰欢 generate-from-qc| GATE{鍑轰欢鍏亾鏍¢獙路鎸変笟鍔′紭鍏堢骇鍙姤绗竴澶剗
+ A2 -->|鍑轰欢 generate-from-qc| GATE
+ A3 -->|鍑轰欢 generate-from-qc| GATE
+ A4 -->|鍑轰欢 generate-from-qc| GATE
+ GATE -->|000 绫诲瀷闈炴硶| GE0[105_000 qcType 涓嶅湪 1~4]
+ GATE -->|001 鍗曟嵁涓嶅瓨鍦▅ GE1[105_001]
+ GATE -->|002 鏈畬鎴愭楠寍 GE2[105_002路甯﹀綋鍓嶇姸鎬佷腑鏂囧悕]
+ GATE -->|003 鏈~鍒ゅ畾| GE3[105_003路鍒楀嚭鍥涗釜鍙�夊垽瀹歖
+ GATE -->|005 妯℃澘绫诲瀷涓嶇| GE5[105_005路涓よ竟绫诲瀷涓枃鍚嶉兘缁櫬峰墠绔寜 reportType 棰勮繃婊
+ GATE -->|006 鏃犲彲鐢ㄦ楠岄」| GE6[105_006]
+ GATE -->|閫氳繃路鍙厑璁稿悓绫诲瀷宸插彂甯冩ā鏉縷 RP[鏅鸿兘璐ㄦ鎶ュ憡骞冲彴 qcreport]
+ RP --> RPT[鎶ュ憡妯℃澘 qc_report_template路鍚敤0鍋滅敤1]
+ RPT --> RPTV[妯℃澘鐗堟湰 qc_report_template_version路鑽夌0宸插彂甯�1宸插仠鐢�2路褰撳墠鐗堟湰涓嶅彲鍋滅敤 101_010]
+ RPTVSAVE[璁捐鍣ㄤ繚瀛� create 鎴� update] -->|鍐欏叆渚ч椄闂疯鍒�101_006 涓庣敾甯冨畨鍏�101_009 涓嶅悎鏍间竴寰嬩笉钀藉簱| RPTV
+ RPTVSAVE -.->|鍙崱鏂板啓鍏ヂ峰瓨閲忚剰鐢诲竷涓嶅洖婧牳鏌 CVNOTE[鐢诲竷鏍¢獙瑕嗙洊涓夊娉ㄥ叆闈⒙穞agName 灞炴�у悕 鏁存CSS]
+ RPTV -->|鎸夊凡鍙戝竷鐗堟湰娓叉煋| RPI[鎶ュ憡瀹炰緥 qc_report_instance路缂栧彿 QR+yyyyMMdd+4浣嶆祦姘绰锋寜澶╃嫭绔媇
+ RPI --> SNAP[鍐荤粨 data_snapshot路鍒ゅ畾鍚庢暟鎹惈 PASS FAIL 涓庡悎鏍肩巼]
+ RPI --> RHTML[render_html 瀹屾暣 HTML 鏂囨。路鍑虹珯宸插墺绂讳簨浠跺睘鎬т笌鍗遍櫓鍗忚]
+ RPI --> RREGEN[閲嶆柊鐢熸垚 regenerate路鍐荤粨蹇収+鍚屼竴妯℃澘鐗堟湰閲嶆覆路鏁版嵁涓庣紪鍙蜂笉鍙樎峰苟浣滃簾宸插綊妗DF]
+ RPI --> RPDF[瀵煎嚭PDF 鍚庣璋僀hromium鎵撳嵃宸插瓨HTML路褰掓。 system_storage_attachment路recordType=qc_report_instance]
+ RPI --> RUI[鎶ュ憡瀹炰緥椤� /qc/report-instance路鑿滃崟鎸傝川閲忕鐞� parent_id=5500]
+ RUI -->|鏉冮檺鐮亅 RPERM["qc-report:instance:query 鏌ヨ路:export 瀵煎嚭PDF路:delete 鍒犻櫎路:create 閫氱敤鍑轰欢路:generate 璐ㄦ鍗曞嚭浠�(menu 1075416)"]
+ RUI -->|鍙嶆煡 businessType=mes_qc_iqc 绛夎〃鍚� + businessId| RBACK[鍚屼竴寮犺川妫�鍗曞彲鍑哄浠芥姤鍛娐峰巻鍙茬暀鐥曢渶瑕伮蜂笉鍋氶噸澶嶆嫤鎴猐
+ RUI --> RPREVIEW[璇︽儏寮圭獥路iframe sandbox绌哄睘鎬ф覆鏌� render_html路鏁版嵁蹇収椤电灞曠ず鍐荤粨 data_snapshot]
+ A1 -.->|鍓嶇鍏ュ彛路琛屾搷浣溿�屽嚭鎶ュ憡銆嶄粎 status=宸插畬鎴愬彲瑙亅 UIREP[鍑烘姤鍛婂脊绐椔稩QC IPQC OQC RQC 鍥涢〉鍏辩敤]
+ A2 -.->|鍚屼笂| UIREP
+ A3 -.->|鍚屼笂| UIREP
+ A4 -.->|鍚屼笂| UIREP
+ UIREP -->|鍙垪 reportType 涓庢湰鍗曚竴鑷绰峰惎鐢峰綋鍓嶇増鏈凡鍙戝竷涓旂敾甯冮潪绌郝烽伩鍏嶉�変腑蹇呰鎷掔殑缁勫悎| UIPICK[鐢ㄦ埛閫夋ā鏉縘
+ UIPICK -->|POST generate-from-qc| GATE
+ UIREP -->|缁撴灉灏卞湴灞曠ず reportNo itemCount| UIRES["undecidableCount>0 钃濊壊淇℃伅鏉★紙澶氫负杩囩▼鍙傛暟鏃犲垽瀹氳鍒櫬烽粍鑹蹭細鍑犱箮姣忓崟璇姤锛壜穡arnings 涓� errors 閫愭潯灞曠ず路涓嶈惤搴撲簨鍚庣湅涓嶅埌"]
+ UIRES -->|鏌ョ湅鎶ュ憡鍒楄〃| RUI
+ RUI -->|璺敱 query 甯﹀叆 businessType+businessId 骞堕濉悳绱 RBACK
+ GATE -->|MesQcReportApi.getQcReportData| MESMAP[MES 鍥涘眰鍙栨暟褰掍竴路鍗曞ご / 鍒ゅ畾渚濇嵁琛� max min threshold / 鏍峰搧 indicator_result / 瀹炴祴鍊� result_detail]
+ MESMAP --> RCTX[鎶ュ憡涓婁笅鏂� report+inspectionItems路鐢卞悗绔槧灏勫櫒浜у嚭路鍓嶇涓嶅啀鑷繁鎷糫
+ RCTX --> RCITEM[妫�楠岄」=鏍峰搧脳鎸囨爣浜ゅ弶灞曞紑路鍏ㄦ寚鏍囪繘涓嶈繃婊ぢ峰鏍峰搧鏃舵牱鍝佸彿鎶樿繘 remark]
+ RCTX --> RCQC[鎼哄甫鍗曟嵁鍘熷垽瀹� qcResult 鏁奥穛cResultText 涓枃路涓庡紩鎿庡垽瀹氬苟瀛樹簰涓嶈鐩朷
+ MESMAP -->|鍒嗙粍椤� item_type=2 涓庡畠鐨勫瓙椤规寜 parent_id 杩樺師涓ゅ眰路褰掑睘涓嶇湅 type 涔熶笉鐪嬭搴弢 RCTXG
+ RCTXG["鍒嗙粍杩樺師路缁勫ご琛岃儗缁勫悕涓� formula_text 鍏紡路缁勫唴绗竴琛岃儗 span=璇ョ粍鎬昏鏁奥峰悓缁勫叾浣欒 span=1 涓� hidden 璁╀綅路鍚堝苟鐨勬槸妯℃澘 columns 閲屽甫 # 鐨勯偅涓�鍒楋紙榛樿鍒楀嵆妫�楠岄」鐩級路鍚堝苟琛屾暟鏄湰鍗曡缁勫疄闄呰鏁拌�岄潪涓绘暟鎹瓙椤规暟路璇ョ粍鏈崟鏃犲瓙椤硅鍒欎笉鍚堝苟"] --- RCTX
+ MESMAP -.->|鍒嗙粍椤规湰鍗曟病鏈夊睘浜庡畠鐨勫瓙椤� / 缁勫ご鏈崟娌℃湁琛岀敱鍚庣琛ヤ竴琛寍 RCWARN
+ MESMAP -.->|鎸囨爣宸插垹 / 鏈綍瀹炴祴鍊硷紙缁勫ご閿氱偣琛屾寜瀹氫箟鏃犲�悸蜂笉鎶ワ級 / 鏍峰搧瓒� 3 涓疯繘 warnings| RCWARN
+ RCWARN[warnings 杞彁绀郝蜂笉钀藉簱路浜嬪悗鐪嬩笉鍒伴渶鑷鐣欑棔] --- RCTX
+ RCITEM --- RCTX
+ RCQC --- RCTX
+ RCTX --> RPI
+ RCTX --> RUNDEC["undecidableCount 娌℃湁鍒ゅ畾缁撹鐨勯」鏁�=蹇収閲� result 涓虹┖涓茬殑椤孤峰惈鏃犲垽瀹氳鍒欎笌寰呭垽瀹氫袱绉嵚蜂笉璁″叆鍚堟牸鐜囧垎姣嶄笌鎶ュ憡缁撹路鐢熸垚鏃跺脊鎻愮ず涓嶅洖濉�"]
+ RPT -->|杩涘叆璁捐鍣ㄥ苟甯� templateId路鏉冮檺 qc-report:template:ai-import| AIIMP[AI瀵煎叆 qc-report/ai-import/draft]
+ AISRC["婧愭枃浠� 鎵弿浠剁収鐗嚶风數瀛愮増PDF路Word(.docx) Excel(.xlsx)路txt csv"] -->|涓婁紶璧� system Storage API 鍙� blobId路缁戜负 qc_report_template 闄勪欢| AIIMP
+ AISRC -.->|鍚屼竴妯℃澘閲嶅瀵煎叆鎸夋浛鎹㈠鐞喡峰厛鍒犳棫闄勪欢鍐嶇粦鏂扮殑路杩炲悓 blob 琛屼笌纾佺洏鏂囦欢涓�璧锋竻| AIIMP
+ AISRC -.->|docx 鐨� Word 椤电湁椤佃剼璇诲彇骞朵互 椤电湁 椤佃剼 鏍囪骞跺叆璇嗗埆鍐呭路椤电湁鍦ㄦ鏂囧墠椤佃剼鍦ㄦ鏂囧悗路鍚屾椂杩� warnings路鎵弿浠剁収鐗囦笉鍙楀奖鍝峾 AIIMP
+ AIIMP -->|璇嗗埆路鍙骇鑽夌涓嶈惤搴搢 AIRD[妯℃澘鑽夌 鎵佸钩缁勪欢+灞炴�ф竻鍗昡
+ AIHINT[绉湪娓呭崟姣忛」甯� hint 閫夊瀷璇存槑路鏉ヨ嚜鍓嶇娉ㄥ唽琛� aiHint路缁勪欢閫夊瀷鐨勫敮涓�鐪熺浉鏉ユ簮] -.->|閫夊瀷浠� hint 涓哄噯路鏈変笓闂ㄧ粍浠跺氨涓嶉��鐢ㄩ�氱敤缁勪欢鍑戞暟| AIIMP
+ AIIMP -->|琛ㄦ牸鏈鐨勮惤娆剧缃茶灞炶惤娆句笉灞炴暟鎹路涓庡師浠堕〉鑴氬悎骞朵笖浜哄悕鏃ユ湡鐣欑┖鎵嬪~路涓嶅緱鑷�犵粦瀹氶敭| AIRD
+ AIIMP -.->|鍘熶欢鍒楁瘮榛樿澶氭垨琛ㄥご鍒嗕袱灞傛垨鏍峰搧瀛楁涓嶅悓鏃堵峰啓杩涚粍浠剁殑 columns headerSpans fields 涓変釜鏂囨湰灞炴�ц鐩柭蜂笉鎹㈢粍浠秥 AIRD
+ AIKEY[鎶ュ憡鍙粦瀹氶敭鐧藉悕鍗暵风敱鍚庣 ReportFields 鍙嶅皠鐢熸垚路涓嶆墜鍐橾 -.->|鍙缂栭�犱笉缁欏彲閫夐泦鍚堟ā鍨嬪彧鑳界寽路鏁呭叏閲忔灇涓緗 AIIMP
+ AIRD -->|浜哄伐鍦ㄨ璁″櫒纭路瑁呴厤鍣ㄧ紪璇戣繘鐢诲竷鍚庝繚瀛榺 RPTV
+ AIRD -.->|鐢诲竷涓婄殑 ReportHeader ReportFooter 鏄鏂囬噷鐨勬姮澶磋惤娆韭蜂笌 PDF 姣忛〉閲嶅鐨勭増寮忛〉鐪夐〉鑴氫笉鏄竴鍥炰簨| RPTV
+ AIIMP -.->|琛ㄥご鏌愬垪鑷繁鏃㈡槸鍒楀悕鍙堟槸涓婃牸路鍘熶欢閲屾槸涓�鏍肩旱鍚戝悎骞惰法浣忎笂涓嬩袱灞傘�佷笅灞傞偅鏍煎湪鎻愬彇鏂囨湰閲屽啓鐫�鈫戝悓涓妡 AIRD
+ AIIMP -.->|璇ユ鏍囬涓庡垪鍚嶄竴瀛椾笉宸墠璁ゆ垚绾靛悜鍚堝苟鏍笺�佸嚭 rowspan=2 涓�鏍间笖涓嬪眰璺宠繃璇ュ垪路涓嶄竴鑷村氨琚綋鎴愬彟涓�灞傚垎缁勬爣棰樸�佺粨璁轰簩瀛椾笂涓嬪悇鍗颁竴閬峾 AIRD
+ RPTVSAVE -.->|璁捐鍣ㄧ敾甯冧笉璺戠粦瀹毬风粍鍚嶆牸鐨� hidden 鍗犱綅绗︿細琚祻瑙堝櫒褰撴垚鐪� hidden 璁╂暣琛屽乏绉汇�佹湯鍒楁尋鎴愮珫鎺掔粏鏉 CVNOTE
+ RPTVSAVE -.->|鑷畾鍒椾笉甯﹀搴﹀0鏄幝峰垪瀹藉彧鑳界敱鏈�灏忓唴瀹瑰搴﹀�掓帹路鑰屽�兼槸鍗犱綅绗﹁繖绫讳笉鍚┖鏍肩殑闀夸覆路鏁磋〃浼氳鎾戝嚭绾稿紶銆佹湯鍒楁尋鎴愮珫鏉 CVWIDTH
+ CVWIDTH["鏁呰嚜瀹氬垪鐨勫崟鍏冩牸甯� overflow-wrap:anywhere 鍏佽闀夸覆鎶樿路榛樿鍒楁湁鎵嬪伐瀹藉害澹版槑涓嶅姞路瀹炴祴鍔犱簡鍙嶈�屾妸妫�楠岄」鐩瓙椤规尋鍒� 30 浣欏儚绱犮�佽楂樼炕鍑犲��"] --- RPTVSAVE
diff --git a/docs/project-business/mermaid/08-module-relation.mmd b/docs/project-business/mermaid/08-module-relation.mmd
index 0cd30bd..3086aab 100644
--- a/docs/project-business/mermaid/08-module-relation.mmd
+++ b/docs/project-business/mermaid/08-module-relation.mmd
@@ -19,6 +19,8 @@
AI[AI 骞冲彴 閫氫箟鍗冮棶+Milvus] -.->|鍙戠エOCR| ERP
AI -.->|鎶ヤ环OCR| CRM
AI -.->|璐ㄦ鍒ゅ畾涓庣敓浜ч娴媩 MES
+ MES -.->|璐ㄦ鍗曚笂涓嬫枃路鏈疆鐢辫皟鐢ㄦ柟浼犲叆 寰� MesQcReportApi 鎵撻�殀 QCR[鏅鸿兘璐ㄦ鎶ュ憡 qcreport 妯℃澘鐗堟湰瀹炰緥蹇収]
+ QCR -.->|PDF 褰掓。路鍚庣画杞| STG
MES --> BI[BI 绠$悊椹鹃┒鑸� SQL閰嶇疆澶у睆]
ERP --> BI
CRM --> BI
diff --git a/docs/project-business/mermaid/09-data-flow.mmd b/docs/project-business/mermaid/09-data-flow.mmd
index 71f8cba..83d6023 100644
--- a/docs/project-business/mermaid/09-data-flow.mmd
+++ b/docs/project-business/mermaid/09-data-flow.mmd
@@ -37,3 +37,36 @@
IV -->|鍥炴寮哄埗鍏堝紑绁▅ RK
RC -->|鍏宠仈CRM瀹㈡埛鏍¢獙| CU
PA -->|鍏宠仈鏉ョエ涓庝緵搴斿晢| PI
+ subgraph S4 [鏅鸿兘璐ㄦ鎶ュ憡 qcreport]
+ RPT[鎶ュ憡妯℃澘] --> RPTV[妯℃澘鐗堟湰]
+ RPTVSAVE[璁捐鍣ㄤ繚瀛� create 鎴� update] -->|鍐欏叆渚ч椄闂� 瑙勫垯101_006 鐢诲竷瀹夊叏101_009 涓嶅悎鏍间笉钀藉簱| RPTV
+ RPTVSAVE -.->|鍙崱鏂板啓鍏� 瀛橀噺鑴忕敾甯冧笉鍥炴函鏍告煡| CVNOTE[鐢诲竷鏍¢獙瑕嗙洊 tagName 灞炴�у悕 鏁存CSS 涓夊娉ㄥ叆闈
+ RPTV --> RPI[鎶ュ憡瀹炰緥]
+ RPI --> SNAP[鏁版嵁蹇収鍐荤粨]
+ RPI --> RHTML[HTML 娓叉煋浜х墿]
+ RPI --> RPDF[PDF 浜х墿]
+ AISRC[婧愭枃浠� 鎵弿浠剁収鐗嚶风數瀛愮増PDF路Word Excel路txt csv] -->|涓婁紶璧� system Storage API 鍙� blobId 骞剁粦涓烘ā鏉块檮浠秥 AIRD[AI 璇嗗埆鑽夌]
+ AIRD -->|浜哄伐鍦ㄨ璁″櫒纭鍚庝繚瀛榺 RPTV
+ end
+ QCDOC[璐ㄦ鍗� IQC IPQC OQC RQC] -->|generate-from-qc路甯� qcType qcId templateId| QCGATE{浜旈亾鏍¢獙 绫诲瀷 瀛樺湪 宸插畬鎴� 宸插垽瀹� 妯℃澘绫诲瀷 鏈夋楠岄」}
+ QCGATE -->|浠讳竴涓嶈繃路鎸変笟鍔′紭鍏堢骇鍙姤绗竴澶剕 QCERR[105_000~105_006]
+ QCGATE -->|閫氳繃| MESQCAPI[MesQcReportApi 鍥涘眰鍙栨暟路鍗曞ご 鍒ゅ畾渚濇嵁琛� 鏍峰搧 瀹炴祴鍊糫
+ MESQCAPI -->|绾嚱鏁版槧灏勫櫒褰掍竴 鍚師鍒ゅ畾 qcResult qcResultText| RPI
+ MESQCAPI -.->|鍒嗙粍鏍囬璺宠繃 鎸囨爣宸插垹 鏈綍瀹炴祴鍊� 鏍峰搧瓒�3| QCWARN[warnings 杞彁绀郝蜂笉钀藉簱]
+ QCWARN -.-> RPI
+ RPI -.->|undecidableCount=蹇収 result 涓虹┖涓茬殑椤孤风敓鎴愭椂寮规彁绀簗 QCFE
+ RPI -.->|businessType=mes_qc_iqc 绛夎〃鍚� + businessId 鍙嶆煡路涓�鍗曞彲鍑哄浠絴 QCFE
+ RPT -.->|report_type 鏁板瓧瀛楃涓查』绛変簬 qcType路鍓嶇鎹杩囨护妯℃澘鍒楄〃| QCGATE
+ RPTV -->|妯℃澘鍋滅敤鍚庝笉鍐嶅嚭鏂颁欢路鍘嗗彶瀹炰緥涓嶅彈褰卞搷路褰撳墠鐗堟湰涓嶅彲鍋滅敤 101_010| RPI
+ RPT -->|杩涘叆璁捐鍣ㄥ甫 templateId 璋� AI 瀵煎叆| AIRD
+ RPI -->|鍒楄〃 璇︽儏 棰勮 鎵撳嵃| QCFE["鍓嶇鎶ュ憡椤甸潰 /qc/report-instance 宸茶惤鍦奥穒frame 娓叉煋 render_html + 蹇収椤电 + 瀵煎嚭PDF"]
+ RPDF -->|褰掓。 闄勪欢涓績 recordType=qc_report_instance| PDFARCH[system_storage_attachment]
+ AISRC -.->|褰掑睘 闄勪欢涓績 recordType=qc_report_template| PDFARCH
+ AISRC -.->|鍚屼竴妯℃澘閲嶅瀵煎叆鎸夋浛鎹㈠鐞喡峰厛鍒犳棫闄勪欢路杩炲悓 blob 琛屼笌纾佺洏鏂囦欢涓�璧锋竻| PDFARCH
+ QCFE -.->|鏉冮檺鐮� qc-report:instance:query/export/delete/create 宸插叆 system_menu| SYS1[system_menu]
+ QCGATE -.->|鏉冮檺鐮� qc-report:instance:generate 宸插叆 system_menu id=1075416| SYS1[system_menu]
+ QCDOC -.->|鍓嶇鍏ュ彛 琛屾搷浣溿�屽嚭鎶ュ憡銆嶄粎 status=宸插畬鎴愬彲瑙伮峰洓椤靛叡鐢ㄥ悓涓�寮圭獥| UIREP[鍑烘姤鍛婂脊绐椔峰彧鍒楀悓绫诲瀷 鍚敤 涓旀湁鐢熸晥鐗堟湰鐨勬ā鏉縘
+ UIREP -->|閫夋ā鏉垮悗 POST generate-from-qc| QCGATE
+ UIREP -.->|缁撴灉灏卞湴灞曠ず reportNo itemCount 涓� undecidableCount 鍛婅| QCFE
+ QCFE -.->|杩涘叆鏃跺甫 businessType+businessId 璺敱 query路棰勫~鎼滅储琛ㄥ崟鐨勩�屼笟鍔″崟鎹�嶅瓧娈祙 UIREP
+ RPT -.->|鏉冮檺鐮� qc-report:template:ai-import 宸插叆 system_menu| SYS1
diff --git a/docs/project-business/mermaid/10-business-object.mmd b/docs/project-business/mermaid/10-business-object.mmd
index a4cb793..c10c095 100644
--- a/docs/project-business/mermaid/10-business-object.mmd
+++ b/docs/project-business/mermaid/10-business-object.mmd
@@ -34,3 +34,5 @@
erp_purchase_order ||--o{ erp_purchase_invoice : "鏉ョエ"
erp_purchase_invoice ||--o{ erp_finance_payment : "浠樻"
hrm_employee ||--o| hrm_user_handover : "绂昏亴浜ゆ帴鏄犲皠"
+ qc_report_template ||--o{ qc_report_template_version : "澶氱増鏈�"
+ qc_report_template_version ||--o{ qc_report_instance : "鍐荤粨鍑轰欢鐗堟湰"
diff --git a/docs/project-business/mermaid/11-ai-business-flow.mmd b/docs/project-business/mermaid/11-ai-business-flow.mmd
index 947d2eb..a67a38e 100644
--- a/docs/project-business/mermaid/11-ai-business-flow.mmd
+++ b/docs/project-business/mermaid/11-ai-business-flow.mmd
@@ -17,6 +17,23 @@
R3[宸ュ簭鏍囧噯宸ユ椂+璁惧姣忓皬鏃朵骇閲�+浼犻�佸�嶇巼] --> R4[鐢熶骇鏃堕暱棰勬祴]
R5[IPQC缂洪櫡鐜�+璁惧淇濆吇鐐规+鐗╂枡鍙敤鐜�+鍏抽敭宸ュ簭] --> R6[鐢熶骇椋庨櫓棰勬祴]
R7[杩涘害+鍓╀綑澶╂暟+浠诲姟瀹屾垚鐘舵��+瀹㈡埛浜ゆ湡] --> R8[浜や粯棰勬祴路鑳藉惁鎸夋椂+缃俊搴�+寤惰鍥犵礌]
+ W1[璐ㄦ鍛樹笂浼犳棦鏈夋楠屾姤鍛婃枃浠� blobId] --> W2{鎵╁睍鍚嶄笌鍐呭鍒ゅ畾}
+ W2 -->|png/jpg/bmp/gif/webp| W3[鍘熷瓧鑺傝蛋 chatWithImage]
+ W2 -->|PDF 鏈夋枃鏈眰| W4[PDFBox 鎶藉彇鏂囨湰 鈫� chat]
+ W2 -->|PDF 鎵弿鐗坾 W5[PDFRenderer 閫愰〉杞琍NG 鈫� 姣忛〉 chatWithImage]
+ W2 -->|docx/xlsx| W6["POI 鎶藉彇路琛ㄦ牸褰掍竴鎴愮ǔ瀹氱綉鏍硷紙gridSpan 琛ョ┖鍗犱綅 / vMerge 缁牸鏍� 鈫戝悓涓婏級"]
+ W2 -->|txt/csv| W7[鐩磋鏂囨湰 鈫� chat]
+ W2 -->|doc/xls| W8[鎷掔粷路鎻愮ず鍙﹀瓨涓� docx/xlsx]
+ W3 --> W9[澶氶〉閫愰〉璇嗗埆]
+ W4 --> W9
+ W5 --> W9
+ W6 --> W9
+ W7 --> W9
+ W9 --> W10["鎸�(type,props)鍘婚噸鍚堝苟鈫掓墎骞崇粍浠惰崏绋�+summary+warnings"]
+ W10 --> W11[寮圭獥棰勮路浜哄伐纭鍚庤杩涜璁″櫒鐢诲竷]
+ W11 --> W12[浜哄伐璋冩暣鈫掍繚瀛樹负妯℃澘鐗堟湰路杩欐槸鍞竴钀藉簱鐐筣
+ WCL[缁勪欢绉湪娓呭崟鐢卞墠绔粠娲绘敞鍐岃〃鐢熸垚骞堕殢璇锋眰涓婁紶] --- W9
+ WSAFE[鍙骇鑽夌涓嶈惤搴撀锋湭娉ㄥ唽type鍦ㄨ閰嶉樁娈佃璺宠繃路姘歌繙浜т笉鍑轰换鎰廐TML] --- W10
KB1[鐭ヨ瘑搴撴枃妗d笂浼燯RL] --> KB2[POI/Tika鎻愬彇鏂囨湰] --> KB3[鍒囩墖绾�800tokens鈫掑悜閲忓寲鈫扢ilvus]
KB3 --> KB4[鍒嗘妫�绱㈡帴鍙� topK+鐩镐技搴﹂槇鍊糫
KB4 -.-> KB5[鏆傛湭鎺ュ叆涓氬姟闂瓟娴佺▼路寰呯‘璁
diff --git a/docs/qc_report_ai_import_frontend_integration.md b/docs/qc_report_ai_import_frontend_integration.md
new file mode 100644
index 0000000..f5c7f2e
--- /dev/null
+++ b/docs/qc_report_ai_import_frontend_integration.md
@@ -0,0 +1,360 @@
+# 鏅鸿兘璐ㄦ鎶ュ憡 鈥� AI 瀵煎叆妯℃澘 鍓嶇鑱旇皟鏂规
+
+> 鍚庣妯″潡锛歚yudao-module-qcreport`銆�鎺ュ彛鍓嶇紑锛歚/admin-api/qc-report/ai-import`
+> 鏈疆鑼冨洿锛�**涓婁紶涓�浠藉凡鏈夌殑妫�楠屾姤鍛婃枃浠� 鈫� AI 璇绘噦 鈫� 浜у嚭妯℃澘鑽夌**銆�
+> **鎺ュ彛涓嶈惤搴�**锛岃崏绋垮彧鏄�屼竴涓茬粍浠� + 鍚勮嚜鐨勫睘鎬с�嶏紱浜哄伐鍦ㄨ璁″櫒纭鍚庣偣鏃㈡湁鐨勩�屼繚瀛樸�嶆墠浼氬啓鎴愭ā鏉跨増鏈��
+
+## 娑夊強椤甸潰
+
+| 椤甸潰 | 璇存槑 | 鏈疆鐘舵�� |
+|---|---|---|
+| 妯℃澘璁捐鍣紙鏃㈡湁锛� | 椤舵爮銆孉I 瀵煎叆銆嶆寜閽� 鈫� 寮圭獥閫夋枃浠� 鈫� 璇嗗埆 鈫� 棰勮 鈫� 銆岀敓鎴愬埌鐢诲竷銆� | 宸叉帴鍏� |
+| 妯℃澘鍒楄〃椤� | 鏈疆**涓嶅仛**銆孉I 鏂板缓妯℃澘銆嶅叆鍙o紝瑙併�屾敞鎰忎簨椤广�� | 涓嶅仛 |
+
+## 涓氬姟娴佺▼涓庢暟鎹甫鍏�
+
+1. **杩涘叆璁捐鍣�**锛氬繀椤诲甫 `templateId` 杩涘叆锛坄/qc/report-template/designer?id=5`锛夈��
+ AI 瀵煎叆鍙湪鏃㈡湁妯℃澘鐨勮璁″櫒鍐咃紝`templateId` 鏄悗缁�岀粦闄勪欢銆嶄笌銆屾棩蹇楃暀鐥曘�嶇殑涓婚敭銆�
+2. **涓婁紶**锛氱敤鎴烽�夋枃浠跺悗璋� system 妯″潡鏃㈡湁鐨勪笂浼犳帴鍙f嬁 `blobId`銆�
+ **蹇呴』淇濇寔鐢ㄦ埛鐨勯�夋嫨椤哄簭**鈥斺�斿悗绔寜杩欎釜椤哄簭鐞嗚В鏂囨。椤靛簭銆�**杩欎竴姝ヤ笉鍙戣瘑鍒姹�**锛岀敤鎴风偣澶存墠鍙戙��
+3. **缁戦檮浠�**锛氭嬁鍒� `blobId` 鍚�**绔嬪嵆**璋� system 妯″潡鏃㈡湁鐨勯檮浠剁粦瀹氭帴鍙o紝鎶婃枃浠跺綊灞炲埌褰撳墠妯℃澘
+ 锛坄application='file'`銆乣recordType='qc_report_template'`銆乣recordId=templateId`锛夈��
+ 鈿� `application` 鍙楀悗绔灇涓鹃檺鍒讹紝**鍙兘鏄� `file` / `image` / `avatar`**锛屼紶鍏跺畠鍊间細 500銆�
+ **鍏堢粦鍐嶈瘑鍒�**锛氳瘑鍒嵆浣垮け璐ワ紝鏂囦欢涔熷凡褰掑睘鍒版ā鏉垮悕涓嬶紝涓嶄細鐣欐垚娌′汉璁ら鐨勫鍎挎枃浠躲��
+4. **璇嗗埆**锛氳皟鏈枃妗g殑 `draft` 鎺ュ彛锛屽甫涓� `blobIds`銆乣templateId`銆乣schemaVersion`銆乣catalog`銆佸彲閫夌殑 `hint`銆�
+ **杩欐潯璇锋眰瑕佸崟鐙斁瀹借秴鏃跺埌 180 绉�**锛堝崟娆℃渶闀胯鍙� 5 娆″ぇ妯″瀷璋冪敤锛岄粯璁よ秴鏃朵細鍦ㄦā鍨嬭繑鍥炲墠灏辨帎鏂級銆�
+5. **棰勮**锛氬脊绐楀垪璇嗗埆鍑虹殑缁勪欢锛堢被鍨嬫樉绀哄悕 + 宸茶瘑鍒殑灞炴�э級銆乣summary`銆乣warnings`銆�
+ 杩欎竴姝�**娌℃湁浠讳綍鍐欐搷浣�**锛岀敤鎴峰彲浠ュ弽澶嶉噸鏂颁笂浼犮��
+6. **鐢熸垚鍒扮敾甯�**锛氱敾甯冮潪绌烘椂鍏堝脊鏇挎崲纭锛�**鏇挎崲鍚庢棤娉曠敤鎾ら攢鎭㈠**锛夆啋 鍓嶇瑁呴厤鍣ㄦ妸鑽夌缂栬瘧鎴愮敾甯冩暟鎹杩涘幓銆�
+7. **淇濆瓨**锛氫汉宸ュ湪璁捐鍣ㄨ皟鏁村悗鐐�**鏃㈡湁鐨�**銆屼繚瀛樸�嶁啋 璧版棦鏈夌殑鐗堟湰淇濆瓨鎺ュ彛銆�
+ **杩欐槸鍞竴鐨勮惤搴撶偣锛孉I 杩欐潯璺病鏈夌浜屾潯淇濆瓨璺緞**锛屽洜姝ゆ棦鏈夌殑妯℃澘鏍¢獙锛堝惈鍒ゅ畾瑙勫垯锛夎嚜鍔ㄧ敓鏁堛��
+
+**甯﹀叆鍏崇郴瑕佺偣**
+
+- `templateId` 鏄富绾匡紝浠庢ā鏉垮垪琛ㄥ甫鍏ヨ璁″櫒銆佸啀甯﹀叆 AI 瀵煎叆涓庨檮浠剁粦瀹氥��
+- `catalog`锛堢Н鏈ㄦ竻鍗曪級**姣忔璇锋眰閮戒粠褰撳墠鍓嶇娉ㄥ唽琛ㄧ幇绠椾竴閬嶅啀浼�**锛屼笉瑕佸湪搴旂敤閲岀紦瀛樻垚甯搁噺锛�
+ 缂撳瓨瀹冪瓑浜庢妸銆屾敞鍐岃〃鏄敮涓�鐪熺浉鏉ユ簮銆嶈繖鏉″墠鎻愭倓鎮勪綔搴熴��
+- `blobIds` 鐨勯『搴忓嵆鏂囨。椤靛簭锛屽椤垫枃浠舵寜杩欎釜椤哄簭閫愰〉璇嗗埆銆佹渶鍚庡悎骞跺幓閲嶃��
+
+## API
+
+| 鏂规硶 | 璺緞 | 璇存槑 | 鏉冮檺鐮� |
+|---|---|---|---|
+| POST | `/qc-report/ai-import/draft` | 璇嗗埆鏂囦欢鐢熸垚妯℃澘鑽夌銆�**鍚屾杩斿洖銆佷笉钀藉簱銆佷笉寤虹増鏈** | `qc-report:template:ai-import` |
+
+> 鈿� 鏈疆**鏈�**寰� `system_menu` 鎻掑叆 `qc-report:template:ai-import` 鏉冮檺琛岋紙涓庡嚭浠舵帴鍙e悓涓�鍙e緞锛夈��
+> 褰撳墠 `admin` 鏄秴绠°�佺洿鎺ユ斁琛岋紝鑱旇皟涓嶅彈褰卞搷锛�**鍓嶇椤甸潰姝e紡钀藉湴鏃堕渶涓�骞惰ˉ鑿滃崟涓庢寜閽潈闄�**锛�
+> 鍚﹀垯闈炶秴绠¤鑹茶皟鏈帴鍙d細 403銆�
+
+### 璇锋眰鍙傛暟
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|---|---|---|---|
+| `blobIds` | Long 鏁扮粍 | **鏄�** | 涓婁紶鏂囦欢瀵瑰簲鐨� blobId銆�**椤哄簭鍗虫枃妗i〉搴�**锛涙渶澶� 3 涓紙璇ヤ笂闄愮敱鍚庣 `yudao.qcreport.ai-import.max-files` 鍐冲畾锛岃秴闄愭姤 `1_070_104_005`锛夛紝鍗曚釜鏂囦欢鏈�澶� 20MB |
+| `templateId` | Long | **鏄�** | 鐩爣妯℃澘缂栧彿锛岀敤浜庢棩蹇楃暀鐥曚笌闄勪欢褰掑睘 |
+| `schemaVersion` | String | **鏄�** | 鍥哄畾浼� `1.1`銆備笌璁捐鍣ㄥ悓婧愶紝涓ょ涓嶄竴鑷存椂鍚庣鐩存帴鎶ラ敊 |
+| `catalog` | Object 鏁扮粍 | **鏄�** | 鍙敤缁勪欢绉湪娓呭崟锛岃銆宍catalog` 鐨勬瀯閫犳柟寮忋�嶏紱鏈�澶� 40 椤� |
+| `hint` | String | 鍚� | 鐢ㄦ埛琛ュ厖璇存槑锛屼細鎷艰繘鎻愮ず璇嶏紝渚嬪銆岃繖鏄� IQC 鏉ユ枡妫�楠屾姤鍛娿�� |
+
+**`catalog` 涓�椤圭殑缁撴瀯**
+
+| 瀛楁 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|---|---|---|---|
+| `type` | String | **鏄�** | 缁勪欢绫诲瀷锛屽 `QualityTable`銆�**澶у皬鍐欐晱鎰�**锛屾ā鍨嬩細鍘熸牱鎶勮繘缁撴灉 |
+| `label` | String | 鍚� | 缁勪欢鏄剧ず鍚嶏紝渚涙ā鍨嬬悊瑙h涔� |
+| `category` | String | 鍚� | 缁勪欢鍒嗙被锛屽 `basic` / `data` / `result` |
+| `hint` | String | **鏄�** | 璇ョ粍浠剁殑**閫夊瀷璇存槑**锛氱敤鏉ユ斁浠�涔堛�佷笉瑕佺敤鏉ユ斁浠�涔堛�傛ā鍨嬮�夊瀷浠ュ畠涓哄噯锛岃銆岄�夊瀷鎸囧紩蹇呴』闅忔竻鍗曞甫鍑恒�� |
+| `fields` | Object 鏁扮粍 | 鍚� | 璇ョ粍浠跺厑璁稿~鍐欑殑灞炴�� |
+
+> `hint` 鏍囦负**鏄�**涓嶆槸鍥犱负鍚庣寮哄埗锛堝悗绔敹鍒扮┖鍊间笉鎶ラ敊锛夛紝鑰屾槸鍥犱负**婕忓甫瀹� = 妯″瀷閫�鍥炵瀻鐚�**锛�
+> 缁勪欢涔嬮棿澶ч噺鍙簰鐩告浛浠o紙鎶ュ憡鎶ご鍙啓 `Heading` / `Text` / `ReportHeader`锛夛紝
+> 妯″瀷鍙湅涓枃 `label` 鏃朵細鎸戝瓧娈垫渶绠�鍗曘�佹渶閫氱敤鐨勯偅涓�傚疄娴嬫紡甯﹀墠鐨勮〃鐜板氨鏄�
+> 銆岄〉鐪夐〉鑴氫綅缃敤浜嗘枃鏈粍浠躲�嶃��
+
+**`catalog[].fields[]` 涓�椤圭殑缁撴瀯**
+
+| 瀛楁 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|---|---|---|---|
+| `key` | String | **鏄�** | 灞炴�� key锛屽 `itemsPath` |
+| `label` | String | 鍚� | 瀛楁鏄剧ず鍚� |
+| `type` | String | 鍚� | 瀛楁绫诲瀷锛屽 `text` / `number` / `boolean` / `enum` |
+| `required` | Boolean | 鍚� | 鏄惁蹇呭~锛�**鍙疆鐪熶笉缃亣** |
+| `bindable` | Boolean | 鍚� | 鏄惁鏀寔鏁版嵁缁戝畾锛�**鍙疆鐪熶笉缃亣** |
+| `enumOptions` | Object 鏁扮粍 | 鍚� | 鏋氫妇鍙�夊�硷紝鍏冪礌褰㈠ `{ label: '妯悜', value: 'landscape' }`銆�**浠呭湪 `type=enum` 鏃舵湁鎰忎箟** |
+
+### 鍝嶅簲瀛楁
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|---|---|---|
+| `components` | Object 鏁扮粍 | 璇嗗埆鍑虹殑缁勪欢鑽夌锛屾寜鎶ュ憡浠庝笂鍒颁笅鐨勯『搴忥紱宸插仛杩囧悎骞跺幓閲嶄笌闈炴硶椤硅繃婊� |
+| `components[].type` | String | 缁勪欢绫诲瀷锛�**淇濊瘉鏄� `catalog` 閲屽0鏄庤繃鐨� type** |
+| `components[].props` | Object | 缁勪欢灞炴�с�傛竻鍗曢噷鏈0鏄庣殑 key 宸茶鍚庣涓㈠純 |
+| `page` | Object | AI 鐚滄祴鐨勭焊寮犻厤缃紝**鍙兘涓虹┖**锛堜负绌鸿〃绀烘部鐢ㄥ綋鍓嶆ā鏉跨殑绾稿紶锛� |
+| `page.size` | String | `A3` / `A4` / `A5` / `Letter` |
+| `page.orientation` | String | `portrait` / `landscape` |
+| `page.margin` | Object | `top` / `right` / `bottom` / `left`锛屽崟浣� mm |
+| `summary` | String | AI 瀵硅繖浠芥枃妗g殑涓�鍙ヨ瘽璇存槑锛屽睍绀哄湪棰勮寮圭獥椤堕儴 |
+| `warnings` | String 鏁扮粍 | 杞彁绀猴細琚烦杩囩殑椤点�佹棤娉曡〃杈剧殑鍖哄潡銆佽涓㈠純鐨勬湭鐭ョ粍浠躲��**鍘熶欢甯﹂〉鐪�/椤佃剼宸茶鏍囪骞跺叆璇嗗埆鍐呭**绛� |
+| `durationMs` | Long | 璇嗗埆鎬昏�楁椂锛堟绉掞級锛屽惈澶氭妯″瀷璋冪敤 |
+
+**鍝嶅簲绀轰緥**
+
+```json
+{
+ "code": 0,
+ "data": {
+ "components": [
+ { "type": "ReportHeader", "props": { "title": "鏉ユ枡妫�楠屾姤鍛�" } },
+ { "type": "QualityTable", "props": { "itemsPath": "inspectionItems" } },
+ { "type": "Result", "props": { "conclusion": "{{report.conclusion}}" } }
+ ],
+ "page": { "size": "A4", "orientation": "portrait" },
+ "summary": "杩欐槸涓�浠� IQC 鏉ユ枡妫�楠屾姤鍛婏紝鍚〃澶淬�佹楠岄」鐩〃鏍间笌缁撹鏍忋��",
+ "warnings": ["绗� 2 椤电殑鍒ゅ畾瑙勫垯璇存槑鏃犳硶鐢ㄥ彲鐢ㄧ粍浠惰〃杈撅紝宸蹭涪寮�"],
+ "durationMs": 12400
+ }
+}
+```
+
+> 鈿� **鍝嶅簲閲屾病鏈� `rawText` 瀛楁**锛岃繖鏄湁鎰忕殑锛氬畬鍏ㄨВ鏋愪笉鍑虹粨鏋滄椂鎺ュ彛鐩存帴鎶涢敊
+> 锛坄1_070_104_012`锛夛紝鍝嶅簲浣撴槸閿欒缁撴瀯鑰屼笉鏄湰鍝嶅簲锛涘涓�涓亽涓虹┖鐨勫瓧娈靛彧浼氳浜鸿浠ヤ负
+> 銆岃В鏋愬け璐ユ椂鍓嶇鑳芥嬁鍒版ā鍨嬪師鏂囥�嶃�傛ā鍨嬪師鏂囧啓杩涗簡鏈嶅姟绔棩蹇椼��
+
+## `catalog` 鐨勬瀯閫犳柟寮�
+
+`catalog` 涓嶆槸鎵嬪啓鐨勫父閲忚〃锛岃�屾槸**浠庤璁″櫒瀹為檯浣跨敤鐨勭粍浠舵敞鍐岃〃鐜扮畻鍑烘潵鐨勬淳鐢熻鍥�**銆�
+
+| 瑕佺偣 | 璇存槑 |
+|---|---|
+| **鏉ユ簮** | 璁捐鍣ㄥ疄闄呬娇鐢ㄧ殑閭d釜缁勪欢娉ㄥ唽琛紙`src/components/quality`锛夛紝瀹冩槸缁勪欢娓呭崟鐨�**鍞竴鐪熺浉鏉ユ簮** |
+| **浣曟椂绠�** | 姣忔鍙戣捣璇嗗埆璇锋眰鍓嶇幇绠椾竴閬� |
+| **蹇呴』鍏堝幓娉ㄥ唽** | 娉ㄥ唽琛�**鍙湁鏄惧紡娉ㄥ唽杩囨墠鏈夊唴瀹�**銆傝璁″櫒鍒濆鍖栨椂宸插仛杩囦竴娆★紝寮圭獥閲屽啀琛ヤ竴娆℃槸骞傜瓑鐨勫厹搴� |
+| **鍓ユ帀浠�涔�** | 鍓ョ涓嶅彲搴忓垪鍖栫殑瀹炵幇鎴愬憳锛堝浘鏍囥�佹瀯寤哄嚱鏁般�佹牎楠屽嚱鏁般�侀粯璁ゅ�硷級锛屽彧鐣欍�屾ā鍨嬮渶瑕佺煡閬撶殑銆嶏細绫诲瀷銆佹樉绀哄悕銆佸垎绫汇��**閫夊瀷璇存槑**銆佸瓧娈� |
+| **涓轰粈涔堜笉鍦ㄥ悗绔‖缂栫爜** | 鍚庣鎶勪竴浠藉氨鏄浜屼釜鐪熺浉鏉ユ簮锛屼笖鏄渶鍧忕殑锛氬墠绔姞缁勪欢/鏀瑰繀濉瓧娈垫椂鍓嶇绔嬪埢鐢熸晥銆佸悗绔壇鏈潤榛樿繃鏈燂紝妯″瀷闅忓嵆浼氱紪鍑烘敞鍐岃〃閲屾牴鏈笉瀛樺湪鐨� `type` |
+| **杈圭晫涓轰粈涔堟病琚墛寮�** | 娓呭崟杩涙彁绀鸿瘝鍚庣殑鍞竴鍑哄彛鏄�岃妯″瀷鎶勬垚 JSON 瀛楃涓层�嶃�傜湡姝f妸鍏崇殑鏄�**鍓嶇瑁呴厤鍣ㄥ鐫�娲绘敞鍐岃〃鏌�**锛氭湭娉ㄥ唽鐨� `type` 浼氳璺宠繃锛�**姘歌繙浜т笉鍑轰换鎰� HTML** |
+| **鍓嶇疆鏍¢獙** | 娉ㄥ唽琛ㄤ负绌烘椂鏋勯�犲嚱鏁�**鐩存帴鎶涢敊**锛屼笉瑕佸彂涓�涓┖娓呭崟鍑哄幓鈥斺�斿悗绔細鍒や负鍏ュ弬闈炴硶锛屾姤鍑烘潵鐨勯敊鍜岀湡瀹炲師鍥犻殧浜嗗ソ鍑犲眰 |
+
+### 閫夊瀷鎸囧紩蹇呴』闅忔竻鍗曞甫鍑�
+
+`hint` 鏄�**缁勪欢閫夊瀷鐨勫敮涓�鐪熺浉鏉ユ簮**锛屽拰缁勪欢瀹氫箟鍚屾簮锛氭敼娉ㄥ唽琛ㄩ噷鏌愪釜缁勪欢鐨� `hint`锛屼笅娆¤姹傝嚜鍔ㄧ敓鏁堬紝
+鍚庣涓嶉渶瑕侊紙涔熶笉搴旇锛夊悓姝ヤ换浣曚竴浠藉壇鏈��
+
+| 瑕佺偣 | 璇存槑 |
+|---|---|
+| **鍐欏湪鍝�** | 姣忎釜缁勪欢瀹氫箟鐨勪竴鏉� `aiHint` 鏂囨锛岄殢娓呭崟搴忓垪鍖栧甫鍑� |
+| **鍐欎粈涔�** | 銆岀敤鏉ユ斁浠�涔堛��+銆�**涓嶈**鐢ㄦ潵鏀句粈涔堛�嶃�傚悗鑰呮墠鏄叧閿�斺�旀ā鍨嬭鐢ㄧ殑鏍瑰洜鏄�屼笉鐭ラ亾鏌愪釜閫氱敤缁勪欢涓嶈鐢ㄥ湪杩欓噷銆� |
+| **鎬庝箞鐢�** | 鍚庣鍙礋璐f妸瀹冨師鏍峰簭鍒楀寲杩涙彁绀鸿瘝锛屼竴鏉℃娊鍙栬鍒欒姹傛ā鍨嬨�岄�夊瀷鏃朵互 hint 涓哄噯锛屾竻鍗曢噷瀛樺湪涓撻棬缁勪欢灏变笉瑕侀��鑰岀敤閫氱敤缁勪欢鍑戞暟銆� |
+| **涓嶅啓浼氭�庢牱** | 妯″瀷鍙湅鍒扮粍浠朵腑鏂囧悕锛屼細鎸戝瓧娈垫渶绠�鍗曠殑閭d釜銆傚疄娴嬬棁鐘跺氨鏄細鎶ュ憡鎶ご涓庤惤娆惧叏钀藉埌浜嗛�氱敤鏂囨湰缁勪欢涓� |
+| **鍜岃璁″櫒鐣岄潰鐨勫叧绯�** | `hint` **涓嶈繘璁捐鍣ㄧ晫闈�**锛屽畠鏄粰妯″瀷鐪嬬殑璇存槑锛屼笉鏄粍浠剁殑灞曠ず鍚嶆垨灞炴�ф彁绀� |
+
+## 鑽夌 鈫� 鐢诲竷锛氱紪璇戝绾�
+
+鑽夌**涓嶈兘鐩存帴濉炶繘鐢诲竷**銆傚畠瑕佸厛缁忓墠绔殑瑁呴厤鍣ㄧ紪璇戞垚鐢诲竷鏁版嵁锛屽啀浜ょ粰璁捐鍣ㄨ浇鍏ワ紙涓庛�屾墦寮�涓�浠藉凡淇濆瓨鐨勬ā鏉裤�嶈蛋瀹屽叏鍚屼竴鏉¤矾锛夈��
+
+**瑁呴厤鍣紙`assembleQualityCanvas`锛夊叆鍙� / 鍑哄弬**
+
+| 鏂瑰悜 | 鍚嶅瓧 | 绫诲瀷 | 璇存槑 |
+|---|---|---|---|
+| 鍏� | `components` | 鑽夌缁勪欢鏁扮粍 | 鍗冲搷搴旈噷鐨� `components`锛涘彲涓虹┖ |
+| 鍑� | `grapes` | Object | 鐢诲竷鏁版嵁锛屽杺缁欒璁″櫒鐨勮浇鍏ユ柟娉� |
+| 鍑� | `skipped` | Object 鏁扮粍 | 琚烦杩囩殑缁勪欢锛歚{ type, label, reason }`銆�**`reason` 鏄粰浜虹湅鐨勪腑鏂囷紝鐩存帴灞曠ず** |
+| 鍑� | `problems` | String 鏁扮粍 | 瑁呰繘鍘讳簡浣嗘湁闂锛氬繀濉己澶便�佹敹鍒扮粨鏋勫寲鏁版嵁鑰屽洖钀介粯璁ゅ�肩瓑 |
+
+**閫愰」琛屼负锛堜笌鏃㈡湁銆屼粠鐢诲竷鏀堕泦璇箟銆嶄簰涓洪�嗚繍绠楋級**
+
+| 鎯呭喌 | 琛屼负 |
+|---|---|
+| `type` 鍙栦笉鍒版敞鍐岃〃閲岀殑瀹氫箟 | 杩� `skipped`锛�**缁х画澶勭悊涓嬩竴涓�**锛屼笉鏁存壒澶辫触 |
+| `type` 涓虹┖ / 缂哄け | 鍚屼笂锛岃繘 `skipped` |
+| AI 婕忎簡鏌愪簺瀛楁 | 鐢ㄧ粍浠跺0鏄庣殑榛樿鍊艰ˉ榻愶紙涓嶄細鍑虹幇銆岀粍浠剁己灞炴�с�嶏級 |
+| AI 缂栦簡娓呭崟澶栫殑灞炴�� key | **闈欓粯涓㈠純**锛堝睘鎬у簭鍒楀寲鍙緭鍑哄0鏄庤繃鐨� key锛� |
+| 鏌愪釜瀛楁鏀跺埌瀵硅薄 / 鏁扮粍 | 璁颁竴鏉� `problems`锛岃瀛楁鎸夐粯璁ゅ�煎鐞嗭紙闃叉 `[object Object]` 琚啓杩涚敾甯冿級 |
+| 蹇呭~瀛楁涓虹┖ | 璁颁竴鏉� `problems`锛�**缁勪欢浠嶇劧瑁呰繘鐢诲竷**锛堢敤鎴峰彲浠ュ湪璁捐鍣ㄩ噷琛ワ級 |
+| 涓�涓粍浠堕兘瑁呬笉杩涘幓 | **涓嶅姩鐢诲竷**锛屽彧鎶ラ敊銆傝浇鍏ュ姩浣滀細娓呯┖鎾ら攢鏍堜笌宸叉湁鍐呭锛岀櫧鐧芥惌杩涘幓涓�鐗堢敾甯冨嵈浠�涔堥兘鎹笉鏉� |
+
+**杞藉叆鍔ㄤ綔鐨勪袱涓壇浣滅敤锛堝繀椤昏鐢ㄦ埛鐭ユ儏锛�**
+
+- **娓呯┖鎾ら攢鏍�**锛氳瀹屼箣鍚�**鏃犳硶鐢ㄦ挙閿�鎭㈠**鍘熸潵鐨勭敾甯冦�傛墍浠ョ敾甯冮潪绌烘椂瑕佸厛寮圭‘璁わ紝骞跺缓璁敤鎴峰厛淇濆瓨褰撳墠鍐呭銆�
+- **浼氱敤浼犲叆鐨勫垽瀹氳鍒欒鐩栧綋鍓嶈鍒�**锛氳閰嶈矾寰�**鏄惧紡娌跨敤褰撳墠宸茬紪杈戠殑瑙勫垯**锛屼笉浼氭妸鐢ㄦ埛鍐欏ソ鐨勫垽瀹氳鍒欓潤榛樻竻绌恒��
+
+> **瑁呴厤浜х墿涓嶈兘鐩存帴钀藉簱銆�** 鍑哄弬 `grapes` 閲屾瘡涓妭鐐圭殑 `components` 浠嶆槸**鏈В鏋愮殑 HTML 瀛楃涓�**鈥斺�斿畠蹇呴』鍏堣繘鐢诲竷锛圙rapesJS 浼氭妸瀹冩媶鎴愯妭鐐规爲锛夋墠鑳戒繚瀛樸�傜粫杩囪璁″櫒鐩存帴鎶婅繖涓插啓杩� `schema_json`锛屽悗绔覆鏌撳櫒涓嶄細瑙f瀽瀹冿紝鍑轰欢鏃剁粍浠朵細娓叉垚绌� div銆�
+>
+> 鍚岀悊锛岃嫢瑕佺▼搴忓寲鍦版妸缁勪欢鏀捐繘鐢诲竷锛�**瑕佹妸鑺傜偣瀵硅薄浜ょ粰鐢诲竷锛屼笉瑕佽嚜宸辨嫾 HTML 涓插啀瑙f瀽**锛欻TML 瑙f瀽鍣ㄤ細鎶婂睘鎬у悕杞皬鍐欙紙`data-qc-itemsPath` 鈫� `data-qc-itemspath`锛夛紝灞炴�ч潰鏉夸笌娓叉煋閮戒細缁戜笉涓娿�傝璁″櫒鍐呴儴璧扮殑灏辨槸銆岀洿鎺ヤ紶瀵硅薄銆嶈繖鏉¤矾寰勩��
+
+## AI 鍙~鐨勬ā鏉跨粨鏋勫睘鎬э紙鍒楀畾涔� / 琛ㄥご璺ㄥ垪 / 鏍峰搧瀛楁锛�
+
+鍘熶欢鐨勬楠岃〃**鍒�**甯稿父姣旂粍浠堕粯璁ゅ垪澶氾紙銆屾娴嬫柟娉曘�嶃�屾爣鍑嗚姹傘�嶃�岀粨璁恒�嶇瓑锛夛紝鏍峰搧淇℃伅鍧楃殑瀛楁涔熷父涓庨粯璁ゅ叚椤逛笉鍚屻�備负姝ゆ柊澧炰笁涓彲濉睘鎬э紝AI 浼氭妸鍘熶欢鐨勫垪涓庡瓧娈靛啓杩涘幓銆�**杩欎笁涓睘鎬ч兘鏄函鏂囨湰瀛楃涓诧紝涓嶆槸鏁扮粍**鈥斺�斿睘鎬у�煎湪鐢诲竷涓婃槸鏍囬噺锛屾暟缁勫瓨涓嶈繘鍘汇��
+
+| 灞炴�� | 鎸傚湪鍝釜缁勪欢 | 浣滅敤 |
+|---|---|---|
+| `columns` | 鍒嗙粍妫�楠岄」琛� | 瑕嗙洊璇ヨ〃鐨勫垪锛氬垪鏍囬 + 姣忓垪缁戝畾鐨勬暟鎹� |
+| `headerSpans` | 鍒嗙粍妫�楠岄」琛� | 琛ㄥご鍒嗕笂涓嬩袱灞傛椂锛屾弿杩�**涓婇潰閭d竴灞�** |
+| `fields` | 鏍峰搧淇℃伅 | 瑕嗙洊鏍峰搧淇℃伅鍧楀睍绀虹殑瀛楁 |
+
+### `columns` 鐨勫啓娉�
+
+涓�琛屽瓧绗︿覆锛屽垪涓庡垪涔嬮棿鐢� `|` 鍒嗛殧锛屾瘡鍒楀啓浣溿�屽垪鏍囬=缁戝畾琛ㄨ揪寮忋�嶏紝**鍦ㄧ涓�涓� `=` 澶勫垏鍒�**锛堟墍浠ュ垪鏍囬閲屼笉鑳藉嚭鐜� `=`锛夈��
+
+- 鍒楁爣棰樺墠鍔� `#` = 璇ュ垪瑕�**绾靛悜鍚堝苟璺ㄤ綇鏁寸粍**锛堟斁缁勫悕鐨勯偅涓�鍒楋級锛屼竴琛ㄥ彧鏈変竴鍒楄鍔犮��
+- **濉簡 `columns` 鏁磋〃灏辨寜瀹冩潵**锛屻�屾樉绀哄簭鍙� / 鏄剧ず妫�娴嬭姹� / 鏄剧ず瀹炴祴鍊� / 鏄剧ず鍗曚綅 / 鏄剧ず鍒ゅ畾銆嶈繖浜涘紑鍏冲叏閮ㄥけ鏁堬紙瀹冧滑鍙榛樿鍒楋級銆�
+- 鍒楁爣棰樹笌缁戝畾琛ㄨ揪寮忛兘浼氬仛 HTML 杞箟锛岀敤鎴峰啓浠�涔堥兘涓嶄細鍙樻垚鍙墽琛岀殑鏍囩銆�
+
+**鍙敤鐨勭粦瀹氳矾寰勬槸鐧藉悕鍗�**锛屽啓鐧藉悕鍗曞鐨勮矾寰勪細鍦ㄦ牎楠屾椂鎶ラ敊锛歚{{index}}` 琛屽簭鍙枫�乣{{item.itemName}}` 妫�楠岄」鐩悕銆乣{{item.group.childName}}` 瀛愰」鍚嶃�乣{{item.checkMethod}}` 妫�娴嬫柟娉曘�乣{{item.requirement}}` 妫�娴嬭姹傘�乣{{item.standardValue}}` 鏍囧噯鍊笺�乣{{item.actualValue}}` 瀹炴祴鍊笺�乣{{item.unit}}` 鍗曚綅銆乣{{item.resultText}}` 鍒ゅ畾缁撹銆乣{{item.remark}}` 澶囨敞銆�
+
+**缁欏垎缁勮〃鍐� `columns` 鏃跺繀椤讳繚鐣欍�屽瓙椤广�嶅垪**锛坄瀛愰」={{item.group.childName}}`锛夛紝涓斿畠涓嶅姞 `#`銆傚垎缁勮〃鐨勯粯璁ゅ垪鏈潵灏辨湁杩欎竴鍒楋紝AI 鎶婂垪鍐欏叏鏃舵渶瀹规槗婕忔帀瀹冣�斺�斾竴婕忥紝瀛愰」鍚嶆暣鍒椾粠鎶ュ憡涓婃秷澶憋紝鑰屽瓙椤瑰線寰�鎵嶆槸鏍囧噯鐪熸鑰冩牳鐨勫璞°�傚疄娴嬶細涓嶅啓鏄庤繖鏉℃椂 3/3 杞兘鎶婂瓙椤瑰垪涓㈡帀锛堝彧鍐欏嚭 4 鍒楋級锛屽啓鏄庡悗 5/5 杞繚鐣欍�佷笖涓庡師浠剁殑 6 鍒楅�愬垪瀵归綈銆�
+
+### 銆�#銆嶉偅涓�鍒楀埌搴曟�庝箞鍚堝苟鐨�
+
+鍚堝苟**涓嶅湪鍓嶇绠楋紝涔熺敾甯冧笂鐪嬩笉瑙�**锛屽叏閮ㄧ敱鏁版嵁涓嬪彂銆佸嚭浠舵椂鎵嶇敓鏁堬細
+
+| 鐜妭 | 璋佸仛 | 鍋氫粈涔� |
+|---|---|---|
+| 鏍囧嚭鍚堝苟鍒� | 妯℃澘 | `columns` 閲岀粰璇ュ垪鏍囬鍔� `#`锛岀粍浠舵嵁姝ゅ彧鍦ㄨ繖涓�鏍煎啓 `rowspan` / `hidden` 涓や釜缁戝畾 |
+| 绠楀嚭鍚堝苟鍑犺 | 鍚庣 | 缁勭殑绗竴琛屼笅鍙� `span = 鏈崟璇ョ粍鐨勫疄闄呰鏁癭銆乣hidden = 绌轰覆`锛涚粍鍐呭叾浣欒涓嬪彂 `span = 1`銆乣hidden = hidden` |
+| 娓叉垚瑙嗚鍚堝苟 | 鍓嶇 / Java 娓叉煋鍣� | 涓よ竟閮藉湪銆屾眰鍊肩粨鏋滀负绌轰覆銆嶆椂涓嶈緭鍑鸿灞炴�с�備簬鏄粍澶磋鐨� `hidden` 娑堝け銆侀偅涓�鏍煎甫鐫� `rowspan` 鏄剧ず锛涘叾浣欒鐨� `hidden="hidden"` 璁╂暣鏍� `display:none`锛屾妸浣嶇疆璁╃粰涓婃柟鐨勫悎骞舵牸 |
+
+涓夋潯鐢辨鎺ㄥ嚭鐨勫彛寰勶細
+
+- **鍚堝苟琛屾暟鏄�屾湰鍗曡缁勫疄闄呭嚭浜嗗嚑琛屻�嶏紝涓嶆槸鎸囨爣涓绘暟鎹噷璇ュ垎缁勬寕浜嗗灏戜釜瀛愰」銆�** 鏈崟灏戝綍涓や釜瀛愰」锛屾牸瀛愬氨鍙法閭e嚑琛屻��
+- **璇ョ粍鍦ㄦ湰鍗曟病鏈夊瓙椤硅鏃朵笉鍚堝苟**锛堝悗绔寜 `span = 1` 涓嬪彂锛夛紝鐙珛褰曞叆椤瑰悓鐞嗏�斺�旀湰鏉ュ氨鍙湁涓�琛岋紝鏃犳墍璋撹法琛屻��
+- **`hidden` 鍙兘闈犮�屽睘鎬у湪涓嶅湪銆嶈〃杈�**锛屾墍浠ヨ繖涓�煎繀椤绘槸瀛楃涓诧細`hidden="false"` 鐓ф牱闅愯棌锛屽彧鏈夌┖涓茶兘琛ㄧず銆屼笉杈撳嚭璇ュ睘鎬� = 杩欎竴鏍煎彲瑙併�嶃�傚墠绔笉瑕佹妸瀹冨綋甯冨皵鍊煎鐞嗐��
+
+### 鑷畾鍒楃殑鍒楀锛氶暱涓蹭笉璁告妸琛ㄦ牸鎾戝嚭绾稿紶
+
+鑷畾鍒�**涓嶅甫浠讳綍瀹藉害澹版槑**锛堥粯璁ゅ垪甯︼細搴忓彿 48px銆佹娴嬭姹� 30%銆佸疄娴嬪�� 26%鈥︹�︼級锛屾墍浠ユ暣寮犺〃鐨勫垪瀹藉彧鑳界敱鍚勫垪鐨�**鏈�灏忓唴瀹瑰搴�**鍊掓帹銆傝�屾姤鍛婇噷鐨勫�兼槸 `{{item.standardValue}}` 杩欑涓嶅惈绌烘牸鐨勯暱涓诧紝鏈�灏忓唴瀹瑰搴﹀氨鏄暣涓查暱搴︹�斺�斿嚑鍒楀姞璧锋潵杞绘槗瓒呰繃 A4 姝f枃瀹藉害锛屾祻瑙堝櫒鍙兘鎶婅〃鏍兼拺鍑虹焊寮狅紝鏈�鏈竴鍒楄鎸ゆ垚浜屽崄鍑犱釜鍍忕礌鐨勭珫鏉°��
+
+淇硶锛�**鍙湪鑷畾鍒楁椂**缁欏崟鍏冩牸鍔� `overflow-wrap:anywhere`銆傚畠浼氬弬涓庢渶灏忓唴瀹瑰搴﹁绠楋紙`break-word` 涓嶄細锛夛紝鍒楀鍥犳涓嶅啀琚暱涓茬粦鏋讹紱鍑轰欢鏃跺�兼湰鏉ュ氨鐭紙銆岀儤绠卞共鐕ユ硶銆嶃��13.2銆嶏級锛屾姌琛屾瀬灏戣Е鍙戙��
+
+| 鍦烘櫙锛圓4 绾靛悜锛屾鏂囧 672px锛� | 淇墠 | 淇悗 |
+|---|---|---|
+| 鑷畾 6 鍒楋紝鍊间负鍗犱綅绗� | 鏁磋〃 810px銆佹孩鍑� 138px銆佹湯鍒� 29px | 鏁磋〃 672px銆佷笉婧㈠嚭銆佹湯鍒� 97px |
+| 鑷畾 6 鍒楋紝鍊间负鐪熷疄鏁版嵁 | 鏈氨 672px | 672px锛屽垪瀹藉垎甯冧笉鍙� |
+| **榛樿鍒�**锛堝垎缁勮〃 7 鍒楋級 | 807px銆佹孩鍑� 135px | **淇濇寔鍘熸牱** |
+
+鏈�鍚庝竴琛屾槸鍒绘剰涓轰箣锛氶粯璁ゅ垪鐨勫搴﹀0鏄庡凡缁忓畾浣忕増闈紝鍐嶅彔涓�鏉℃姌琛屽弽鑰屼細璁╂病鍐欏搴︾殑銆屾楠岄」鐩�嶃�屽瓙椤广�嶈鎸ゅ埌 30 浣欏儚绱犮�佽楂樹粠 59px 娑ㄥ埌 283px锛堝疄娴嬶級銆傚洜姝よ繖鏉″彧鎸傚湪鑷畾鍒椾笂锛�**娌℃湁 `columns` 鐨勫瓨閲忔ā鏉夸骇鐗╅�愬瓧涓嶅彉**锛堟帰閽堜互 sha256 瀹堢潃锛夈��
+
+> 鑷畾鍒楃殑灞炴�ф槸闅忔湰杞竴璧疯繘鐨勶紝瀛橀噺妯℃澘涓庡凡鍙戝竷鐗堟湰閲屼竴鏉¢兘娌℃湁锛堝叏搴撳疄娴� `data-qc-columns` / `data-qc-headerSpans` / `data-qc-fields` 鍛戒腑鏁板潎涓� 0锛夛紝鍥犳杩欐潯鏀瑰姩瀵规棦鏈夋姤鍛婇浂褰卞搷銆�
+
+### `headerSpans` 鐨勫啓娉�
+
+鍚屾牱鏄� `|` 鍒嗛殧鐨勪竴琛屽瓧绗︿覆锛屾瘡娈靛啓浣溿�屾爣棰榐璺ㄨ秺鍒楁暟銆嶏紝**鍦ㄦ渶鍚庝竴涓� `^` 澶勫垏鍒�**锛涗笉鍐欒法瓒婂垪鏁版椂鎸� 1 绠椼��
+
+- **涓嬮潰閭d竴灞傜敱 `columns` 鍚勫垪鐨勬爣棰樿嚜鍔ㄦ嫾鍑猴紝涓嶈閲嶅鍐�**鈥斺�擿headerSpans` 鍙弿杩颁笂闈㈤偅涓�灞傘��
+- **鍚勬璺ㄨ秺鍒楁暟涔嬪拰蹇呴』绛変簬鍒楁暟**銆傚涓嶄笂鏃舵暣灞備細琚涪寮冦�侀��鍥炲崟灞傝〃澶达紙涓嶆姤閿欍�佷笉宕╋級锛屾墍浠ヨ繖鏉′笉婊¤冻鏃剁敤鎴风湅鍒扮殑鏄�屼袱灞傝〃澶存病鐢熸晥銆嶈�屼笉鏄竴鏉¢敊璇��
+- 鍘熶欢鏈�鍙宠竟閭e垪銆岀粨璁恒��/銆屽垽瀹氥�嶅湪鍘熶欢閲屼笉灞炰簬涓婂眰鍒嗙粍鏍囬鏃�**瑕佸崟鐙垚娈�**锛坄缁撹^1`锛夈�備笉鐐规槑鏃舵ā鍨嬩細鍥剧渷浜嬫妸瀹冪殑鍒楁暟骞惰繘銆屾楠岀粨鏋溿�嶏紙鍐欐垚 `妫�楠岀粨鏋淾6`锛夛紝琛ㄥご灏辨妸缁撹鍒楃敾鍒版楠岀粨鏋滃簳涓嬨��
+- **鏌愬垪鑷繁鏃㈡槸鍒楀悕鍙堟槸涓婃牸鏃�**锛堝師浠堕噷鏄竴鏍肩旱鍚戝悎骞躲�佸崰婊′笂涓嬩袱灞傝〃澶达紝鎻愬彇鏂囨湰閲岃〃鐜颁负涓嬪眰琛ㄥご閭d竴鏍煎啓鐫�銆屸啈鍚屼笂銆嶏級锛屼粛鐓у啓涓�娈点�佽法瓒婂垪鏁板啓 1锛屼絾璇ユ鏍囬蹇呴』涓� `columns` 閲岃繖涓�鍒楃殑鍒楁爣棰�**涓�瀛椾笉宸�**銆備袱鑰呯浉鍚屾椂鎶ュ憡浼氭妸瀹冨悎鍑轰竴鏍艰法涓よ锛坄rowspan`锛夛紝涓嬪眰涓嶅啀閲嶅鍑鸿繖涓�鏍硷紱涓嶄竴鑷存椂浼氳褰撴垚鍙︿竴灞傜殑鏂板垎缁勬爣棰橈紝銆岀粨璁恒�嶄簩瀛楀湪琛ㄥご涓婂嵃涓ら亶銆�
+ - 杩欐槸鏈疆淇帀鐨勪竴澶勭湡缂洪櫡锛氭ā鍨嬫鍓� 5/5 杞兘鍐� `缁撹^1`銆佸垪鍚嶄篃鍙�岀粨璁恒�嶏紝涓ゅ眰鍚勫嵃涓�娆★紝鐢ㄦ埛鐪嬪埌鐨勫氨鏄�屽浜嗕竴涓粨璁恒�嶃�傝ˉ涓娿�屼袱杈逛竴瀛椾笉宸� 鈬� 鍚堟垚涓�鏍艰法涓よ銆嶈繖鏉″垽鎹悗锛岀洿杩� 5/5 杞悎鎴愪负涓�鏍笺��
+ - 鍙嶄緥瑙佸疄娴嬶細鏈� 1/5 杞ā鍨嬫妸 `columns` 閲岄偅涓�鍒楁敼鍚嶆垚銆屽垽瀹氥�嶃�乣headerSpans` 鍗翠粛鍐欑潃鍘熶欢涓婄殑銆岀粨璁恒�嶏紝涓よ竟瀵逛笉涓婂張閫�鍥炲鍗颁竴涓〃澶淬�傛彁绀鸿瘝閲屽洜姝よˉ浜嗕竴鍙ャ�屼笉瑕佽嚜浣滀富寮犳妸瀹冩敼鍚嶆垚杩戜箟璇嶃�嶅苟鍐欐槑鍚庢灉锛屽璺� 5/5 杞笉鍐嶅嚭鐜般��
+
+### `fields` 鐨勫啓娉�
+
+璇硶涓� `columns` 瀹屽叏鐩稿悓锛堝瓧娈靛悕=缁戝畾琛ㄨ揪寮忥紝`|` 鍒嗛殧锛夛紝浣�**涓嶅厑璁� `#` 鍚堝苟鏍囪**锛堥偅鏄垎缁勮〃鏍囩粍鍚嶇殑锛夈�傛瘡琛屾斁鍑犵粍浠嶇敱銆屾瘡琛屽瓧娈垫暟銆嶅睘鎬ф帶鍒躲��
+
+缁戝畾琛ㄨ揪寮忓彧鑳藉啓鎶ュ憡涓婁笅鏂囬噷纭疄瀛樺湪鐨勫瓧娈碉紙涓� `columns` 鍚屽彈銆屼笉璁歌嚜閫犻敭銆嶇害鏉燂級锛涘師浠堕噷鏈夈�佷笂涓嬫枃閲屾病鏈夌殑鏍忕洰锛堝銆屼骇鍝佹暟閲忋�嶃�屽湡璞嗗搧绉嶃�嶃�岀敓浜ф棩鏈熴�嶃�屾湁鏁堟棩鏈熴�嶏級浼氳涓㈠純锛屽苟鍦� `summary` 閲岃鏄庛��
+
+瀛楁鏁颁笉鏄�屾瘡琛屽瓧娈垫暟銆嶇殑鏁存暟鍊嶆椂锛�**鍘熶欢甯歌**锛屽鍘熶欢 5 椤广�佹瘡琛屾斁 2 缁勶級锛屾湯琛岀敱鏈�鍚庝竴涓�兼牸妯悜璺ㄦ帀浣欎笅鐨勫垪锛屽彸渚т笉浼氱暀鍑哄彧鏈夎竟妗嗙殑绌烘牸銆傝繖鏄覆鏌撴湡鐨勫浐瀹氳涓猴紝**涓嶉渶瑕佸湪 `fields` 閲屽仛浠讳綍鏍囪**锛屼篃涓嶄細鍥犳澧炲噺瀛楁鏍兼暟銆�
+
+### 鐢诲竷鏄剧ず涓庡嚭浠剁粨鏋滅殑宸紓
+
+璁捐鍣ㄧ敾甯�**涓嶆眰瑙g粦瀹�**鈥斺�擿{{item.group.childName}}` 杩欑被鍗犱綅绗﹀師鏍风暀鐫�銆傜敱姝ゆ湁涓�澶勫繀椤诲崟鐙鐞嗭細鍒嗙粍妫�楠岄」琛ㄧ殑缁勫悕鏍煎啓鎴� `hidden="{{item.group.hidden}}"`锛屽湪娴忚鍣ㄧ溂閲屻�屾湁 `hidden` 灞炴�с�嶅氨鎴愮珛锛屼簬鏄敾甯冮噷杩欎竴鏍艰 `display:none`锛岃琛屽悗闈㈢殑鏍兼暣浣撳乏绉讳竴鏍硷紝鏈垪鍙墿琛ㄥご銆佽鎸ゆ垚绔栨帓缁嗘潯鈥斺�旂敾甯冧笂鐪嬪埌鐨勬帓鐗堜笌鍑轰欢缁撴灉瀵逛笉涓娿��
+
+璁捐鍣ㄤ负姝ゅ彧鍦�**鐢诲竷鏂囨。鍐�**娉ㄥ叆涓�鏉″紩瀵兼牱寮忥紝鎶娿�屽�艰繕鍋滃湪鍗犱綅绗︺�嶇殑 `hidden` 杩樺師鎴愬彲瑙佹牸銆傚嚭浠舵椂璇ュ�煎凡瑙f垚绌轰覆鎴� `hidden`锛岄�夋嫨鍣ㄤ笉鍐嶅懡涓紝鎶ュ憡娓叉煋涓�涓瓧閮戒笉鍙楀奖鍝嶏紱杩欐潯鏍峰紡鍙姞鍦ㄧ敾甯� iframe 閲岋紝涓嶅啓杩� Schema銆佷笉闅忔ā鏉夸繚瀛樸��
+
+鍗犱綅绗﹀甫鏉ョ殑绗簩澶勫樊寮傛槸**瀹藉害**锛氬崰浣嶇姣旂湡鍊奸暱寰楀锛屾拺涓嶆拺寰楃牬绾稿紶鍦ㄤ袱渚ц〃鐜颁笉鍚屻�傝繖涓�澶勪笉璧扮敾甯冩牱寮忥紝鑰屾槸鎶� `overflow-wrap:anywhere` 鍐欒繘鑷畾鍒楃殑鍗曞厓鏍兼牱寮忛噷鈥斺�斾袱渚х敤鍚屼竴濂楄鍒欙紝鎵�瑙佸嵆鎵�寰楋紙璇﹁涓婁竴鑺傦級銆�
+
+### 璋佸湪浠�涔堟椂鍊欐牎楠岃繖涓変釜灞炴��
+
+鍙湁**淇濆瓨 / 鍙戝竷鍓�**鐨勫睘鎬ф牎楠屼細妫�鏌ュ畠浠紙鍒楀畾涔夎娉曘�佽法鍒楁暟鍚堣銆乣#` 鐢ㄥ湪鏍峰搧淇℃伅涓婄瓑锛夛紝璁捐杩囩▼涓殑涓棿鎬佷笉瑙﹀彂銆傛牎楠屼俊鎭蛋鏃㈡湁鐨� `problems` 閫氶亾锛�**闈為樆鏂�**锛夛紝缁勪欢浠嶄細瑁呰繘鐢诲竷锛岀敤鎴峰彲浠ュ湪璁捐鍣ㄩ噷鏀广��
+
+> **宸茬煡杈圭晫**锛欰I 瀵煎叆璺緞浼氳窇杩欏鏍¢獙锛涜璁″櫒閲�**鎵嬪伐缂栬緫**鍚庣偣淇濆瓨**鐩墠涓嶈窇**锛坄validateQualityProps` 鍙湪瑁呴厤鍣ㄩ噷琚皟鐢級銆備篃灏辨槸璇存墜宸ュ~閿欑殑鍒楀畾涔変笉浼氬湪淇濆瓨鏃惰鎷︿綇锛屽彧浼氬湪鍑轰欢鏃朵互銆岀粦瀹氬彇涓嶅埌鍊笺�嶇殑褰㈠紡鏆撮湶銆傝繖鏄棦鏈夌己鍙o紝鏈疆鏈敼銆�
+
+## 瀛楁灞曠ず瑙勫垯
+
+| 瀛楁 | 灞曠ず浣嶇疆 | 璇存槑 |
+|---|---|---|
+| `summary` | 寮圭獥椤堕儴 | 鎴愬姛鑹叉彁绀烘潯銆備负绌烘椂涓嶅睍绀� |
+| `warnings` | 寮圭獥涓儴 | 璀﹀憡鑹叉彁绀烘潯锛岄�愭潯 `路` 鍒楀嚭銆�**蹇呴』灞曠ず**鈥斺�斿畠鎵胯浇銆屾枃浠堕噷鏈夊摢浜涘唴瀹规病琚瘑鍒埌銆� |
+| `components` | 寮圭獥涓儴鍒楄〃 | 姣忚锛氬簭鍙� + 绫诲瀷鏄剧ず鍚� + 绫诲瀷鍘熷鍊� + 宸茶瘑鍒殑灞炴�э紙`瀛楁鏄剧ず鍚�=鍊糮锛夈�傜被鍨嬪彇涓嶅埌瀹氫箟鏃堕澶栨墦銆屾湭娉ㄥ唽锛屽皢琚烦杩囥�嶆爣璁� |
+| `components` 鏉℃暟 | 鍒楄〃涓婃柟 | 銆岃瘑鍒嚭 N 涓粍浠躲�嶏紱鏈夋湭娉ㄥ唽椤规椂杩藉姞銆孧 涓粍浠惰璁″櫒涓嶈璇嗐�嶆爣璁� |
+| `durationMs` | 鍒楄〃涓婃柟 | 銆岃�楁椂 N 绉掋�� |
+| `page` | 涓嶈繘寮圭獥 | 骞跺叆璁捐鍣ㄧ殑绾稿紶璁剧疆鍚庡啀杞藉叆鐢诲竷锛岃銆屼笟鍔¤鍒欍�� |
+| `skipped` / `problems` | 杞藉叆鍚庡脊绐� | 銆屾湁 N 澶勯渶瑕佺暀鎰忋�嶏紝閫愭潯鍒楀嚭 |
+
+## 涓氬姟瑙勫垯璇存槑
+
+| 鍦烘櫙 | 瑙勫垯 |
+|---|---|
+| **鍙綔鑽夌锛屼笉钀藉簱** | 鎺ュ彛涓嶅缓妯℃澘銆佷笉寤虹増鏈銆佷笉鍐欑敾甯冦��**鍞竴鐨勮惤搴撶偣鏄璁″櫒鏃㈡湁鐨勩�屼繚瀛樸��**锛屾墍浠ユ棦鏈夌殑妯℃澘鏍¢獙锛堝惈鍒ゅ畾瑙勫垯锛夎嚜鍔ㄧ敓鏁� |
+| **澶氶〉閫愰〉璇嗗埆鍚庡幓閲嶅悎骞�** | 鎵弿浠�/鐓х墖鎸夐〉鍚勫嚭涓�娆¤崏绋匡紝鍐嶆寜銆岀被鍨� + 灞炴�с�嶅畬鍏ㄧ浉鍚屽幓閲嶅悎骞躲�傞〉鐪夈�佹爣棰樸�佽〃澶村湪澶氶〉閲嶅鍑虹幇鏃跺彧鐣欑涓�浠� |
+| **`.doc` / `.xls` 鏃ф牸寮忎笉鏀寔** | 鐩存帴鎶� `1_070_104_003`锛屾彁绀哄彟瀛樹负 `.docx` / `.xlsx`銆俙.docx` / `.xlsx` / `.pdf` / 鍥剧墖 / `.txt` / `.csv` 鏀寔 |
+| **銆岀┖鐧姐�嶄笌銆屾崯鍧忋�嶅垎寮�鎶�** | 鎵╁睍鍚嶅悎娉曚絾鍐呭涓虹┖ 鈫� `1_070_104_005`锛涙墿灞曞悕鍚堟硶浣嗘枃浠舵墦涓嶅紑锛堟崯鍧忋�佸甫瀵嗙爜锛� 鈫� `1_070_104_015`銆備袱鑰呯粰鐢ㄦ埛鐨勫姩浣滃畬鍏ㄤ笉鍚岋紝涓嶈兘鍚堟垚涓�鏉� |
+| **PDF 璧板摢鏉¢�氶亾鐢便�屾湁娌℃湁鏂囨湰灞傘�嶅喅瀹�** | 鐢靛瓙鐗� PDF锛堟湁鏂囨湰灞傦級璧版枃鏈�氶亾锛屾暣浠� 1 娆¤皟鐢紱鎵弿鐗� PDF锛堟棤鏂囨湰灞傦級閫愰〉杞浘鍚庢寜鍥捐瘑鍒� |
+| **琛ㄦ牸鍙瘑鍒粨鏋�** | 琛ㄦ牸鐨�**鍏蜂綋鏁版嵁琛屼笉浼氬啓杩涙ā鏉�**锛宍QualityTable` 鐨勬暟鎹簮涓�寰嬫槸 `inspectionItems`锛涚湡瀹炴暟鎹湪鍑轰欢鏃剁敱涓氬姟鍗曟嵁鎻愪緵銆�**杩欎竴鐐瑰繀椤诲悜鐢ㄦ埛璇存槑**锛屽惁鍒欑敤鎴蜂細浠ヤ负鏂囦欢閲岀殑鏁版嵁涔熷杩涙潵浜� |
+| **鍘熶欢鍒�/瀛楁涓庨粯璁や笉鍚屾椂鏄鐩栵紝涓嶆槸鎹㈢粍浠�** | 妫�楠岃〃鍒楁瘮榛樿澶氾紙妫�娴嬫柟娉� / 鏍囧噯瑕佹眰 / 缁撹鈥︼級鈫� 鍐� `columns`锛涜〃澶村垎涓婁笅涓ゅ眰 鈫� 鍐� `headerSpans`锛涙牱鍝佷俊鎭瓧娈典笌榛樿鍏」涓嶅悓 鈫� 鍐� `fields`銆�**涓�寰嬩笉鎹㈢粍浠�**鈥斺�旀崲鎴愬埆鐨勭粍浠跺彧浼氭妸澶氬嚭鏉ョ殑鍐呭涓㈡帀銆備笁鑰呯殑璇硶銆佺櫧鍚嶅崟涓庢牎楠岃涓婃枃銆孉I 鍙~鐨勬ā鏉跨粨鏋勫睘鎬с�� |
+| **缁戝畾琛ㄨ揪寮忓師鏍蜂繚鐣�** | 鏂囦欢閲屽嚭鐜� `{{report.reportNo}}` 杩欑被鍗犱綅绗︽椂锛孉I 浼氬師鏍蜂繚鐣欙紝涓嶄細鏇挎崲鎴愬畠鐪嬪埌鐨勫瓧闈㈠�� |
+| **AI 涓嶅緱鑷�犵粦瀹氶敭** | 鎻愮ず璇嶆槑纭姝㈡ā鍨嬪彂鏄庢柊鐨� `{{...}}` 閿紝骞朵笖**鎶婂彲鐢ㄧ殑閿叏閲忓垪浜嗗嚭鏉�**锛氭姤鍛婄骇瀛楁鍙栬嚜鍚庣 `ReportFields`锛堟姤鍛婂彿銆佹牱鍝佸悕銆佽鏍笺�佹壒鍙枫�佹楠屽憳銆佹楠屾棩鏈熴�佺粨璁恒�佸悎鏍肩巼銆佽鏁扮瓑 23 涓紝鍙嶅皠鐢熸垚銆佷笉鎵嬪啓锛夛紝妫�楠岄」瀛楁鍙栬嚜琛ㄦ牸缁勪欢鐨勭粦瀹氳矾寰勩��**鍙缂栭�犮�佷笉缁欏彲閫夐泦鍚堟椂妯″瀷鍙兘闈犵寽**鈥斺�斿疄娴� 5/5 杞兘缂栧嚭浜� `{{report.productionDate}}` / `{{report.expiryDate}}` 杩欑被涓嶅瓨鍦ㄧ殑閿紝鎶ュ憡涓婄暀鐧藉苟瑙﹀彂銆岀粦瀹氬彇涓嶅埌鍊笺�嶅憡璀� |
+| **`.docx` 鐨� Word 椤电湁/椤佃剼浼氳鏍囪骞跺叆鍐呭** | Word 鏂囨。鐨�**椤电湁涓庨〉鑴�**锛堟瘡椤甸噸澶嶇殑鍏徃鎶ご銆佸巶鍧�鐢佃瘽绛夛級鍘熸湰涓嶅湪姝f枃娴侀噷锛岀幇宸茶璇诲彇骞朵互 `[椤电湁]` / `[椤佃剼]` 鏍囪鎷艰繘璇嗗埆鍐呭锛堥〉鐪夊湪姝f枃鍓嶃�侀〉鑴氬湪姝f枃鍚庯級锛屽悓鏃跺線 `warnings` 閲屽姞涓�鏉℃彁绀恒��**鎵弿浠�/鐓х墖涓嶅彈褰卞搷**锛氬畠浠殑椤电湁椤佃剼鏈潵灏辨槸椤甸潰鍍忕礌鐨勪竴閮ㄥ垎 |
+| **琛ㄦ牸鏈鐨勮惤娆剧缃茶灞炰簬钀芥** | 妫�楠屽憳 / 瀹℃牳浜� / 鎵瑰噯浜� / 鏃ユ湡杩欑被绛剧讲琛�**甯告帓鍦ㄦ楠岃〃鏍肩殑鏈�鍚庝竴琛�**銆傚畠涓嶇畻銆屽叿浣撴暟鎹銆嶏紝搴旇鍙栧嚭鏉ヤ笌鍘熶欢椤佃剼鍚堟垚鏀捐繘 `ReportFooter`锛坄ReportFooter` 涓� `QualityTable` 涓ゆ潯閫夊瀷璇存槑閲屽悇鑷啓鏄庝簡杩欐潯杈圭晫锛� |
+| **绛剧讲琛岀殑浜哄悕涓庢棩鏈熺暀绌�** | 绛剧讲琛�**淇濈暀鏍忕洰鍚嶃�佸�肩暀绌�**锛堝舰濡傘�屾楠屽憳锛歕_\_\_\_銆�瀹℃牳浜猴細\_\_\_\_銆�鏃ユ湡锛歕_\_\_\_銆嶏級锛屾墦鍗板嚭鏉ョ敱浜烘墜濉�備汉鍚嶄笌鏃ユ湡鏄瘡涓�浠芥姤鍛婂悇鑷殑鏁版嵁锛屽啓姝诲師浠朵笂鐨勯偅鍑犱釜浜轰細璁╂墍鏈夋姤鍛婂嵃鎴愬悓涓�涓楠屽憳 |
+| **钀芥鍏佽澶氳锛屾崲琛岃鐪熺殑鎶樿** | 绛剧讲琛屼笌鍘熶欢椤佃剼鍚堟垚涓�娈�**澶氳**鏂囨湰浜ょ粰 `ReportFooter`锛屽嚑琛屽唴瀹�**蹇呴』鎶樿鏄剧ず**锛屼笉鑳界硦鎴愪竴鐗囥�傚睘鎬у�奸噷淇濈暀鐨勬槸鍘熷鎹㈣锛�**鎶樿鍙戠敓鍦ㄦ覆鏌撲骇鐗╄繖涓�渚�**鈥斺�旂粍浠剁敓鎴愮殑鐢诲竷 `content` 閲屾槸 `<br>`锛屾覆鏌撳紩鎿庢寜鍘熸牱杈撳嚭銆俙Text` 缁勪欢鍚屾牱鏀寔澶氳 |
+| **鍒ゅ畾瑙勫垯涓庢暟鎹粦瀹氫笉鐢� AI 鐢熸垚** | AI 鍙嚭缁勪欢鐨勯潤鎬佸睘鎬э紱鍒ゅ畾瑙勫垯銆佹暟鎹粦瀹氫竴寰嬩繚鐣欓粯璁ゅ�硷紝鐢变汉宸ュ湪璁捐鍣ㄩ噷閰嶇疆 |
+| **绾稿紶鐨勫悎骞惰鍒�** | AI 鐚滃嚭鐨勭焊寮犲苟鍏ュ綋鍓嶈璁″櫒鐨勭焊寮犺缃紙**鎸夊瓧娈靛悎骞�**锛孉I 娌$寽鍒扮殑瀛楁娌跨敤鐢ㄦ埛褰撳墠璁剧疆锛夛紝鍐嶉殢杞藉叆鍔ㄤ綔涓�璧风敓鏁堛��**涓嶅悓姝ョ殑璇濓紝淇濆瓨鏃朵細琚ā鏉夸繚瀛樻帴鍙f寜鏃у�煎啓鍥�** |
+| **AI 鐚滀笉鍒扮焊寮犳椂涓嶈鐩�** | `page` 涓虹┖鏃�**蹇呴』浼犲綋鍓嶈璁″櫒鐨勭焊寮犺缃�**锛屼笉鑳戒紶绌恒�備紶绌轰細璁╄浇鍏ュ姩浣滈��鍥為粯璁� A4锛屾妸鐢ㄦ埛宸茬粡璋冨ソ鐨勭焊寮犳倓鎮勬敼鎺� |
+| **缁勪欢鏁颁笂闄�** | 璇嗗埆缁撴灉鏈�澶� 200 涓粍浠讹紝瓒呭嚭鎴柇骞跺湪 `warnings` 閲屾彁绀鸿ˉ褰� |
+| **浠讳綍鍗曚釜缁勪欢鍧忔帀閮戒笉褰卞搷鏁翠綋** | 鏈煡绫诲瀷銆佺粨鏋勫寲灞炴�с�佸繀濉己澶遍兘鍙繘 `warnings` / `problems`锛屽叾浣欑粍浠舵甯歌繑鍥炪��**鍙湁銆屼竴涓粍浠堕兘娌¤瘑鍒嚭鏉ャ�嶆墠鏁翠綋鎶ラ敊** |
+| **鍔熻兘鍙杩愮淮鍏虫帀** | 閮ㄧ讲鐜涓嶈兘鍑虹綉鏃朵細鍏虫帀锛坄yudao.qcreport.ai-import.enabled=false`锛夛紝姝ゆ椂鎺ュ彛鎶� `1_070_104_000`銆傚墠绔簲鍘熸牱鎻愮ず锛屼笉瑕佸綋鎴愮郴缁熷紓甯� |
+
+### 銆屾鏂囨姮澶�/钀芥銆嶄笌銆屾瘡椤甸噸澶嶇殑椤电湁椤佃剼銆嶄笉鏄竴鍥炰簨
+
+杩欐潯鍙e緞瀹规槗娣锋穯锛屽墠绔仈璋冩椂鍔″繀瀵归綈锛�
+
+| | 鐢诲竷涓婄殑 `ReportHeader` / `ReportFooter` | 鏈嶅姟绔嚭浠舵椂鐨勯〉鐪夐〉鑴� |
+|---|---|---|
+| **浣嶇疆** | **姝f枃娴侀噷**鐨勯《閮ㄦ姮澶村潡 / 搴曢儴钀芥鍧楋紝闅忔鏂囧彧鍑虹幇涓�娆� | 鎵撳嵃鏃�**姣忛〉閲嶅**鐨勭増寮忓尯鍩� |
+| **鐢辫皝鐢熸垚** | AI 浠庢枃浠堕噷璇嗗埆鍑烘潵銆佽杩涚敾甯冿紝鐢ㄦ埛鍙紪杈� | 鏈嶅姟绔� PDF 鍑轰欢閰嶇疆锛坄PdfPrintOptions`锛夊姞鐨勶紝鐩墠鍙湁椤电爜 |
+| **鏈疆鏀瑰姩** | `.docx` 鐨� Word 椤电湁琚杩涙潵鍚庯紝妯″瀷浼氭妸瀹冩尓杩涙鏂囬《閮ㄧ殑 `ReportHeader` | **鏈敼鍔�** |
+
+涔熷氨鏄锛氭妸 Word 椤电湁璁ゆ垚 `ReportHeader`锛屾槸**鎶婂畠鎼繘姝f枃椤堕儴**锛�**涓嶆槸**杩樺師姣忛〉閲嶅鐨勬墦鍗扮増寮忋��
+鐪熸姣忛〉閲嶅鐨勯偅涓�灞備粛鐢辨湇鍔$ PDF 鍑轰欢閰嶇疆鎺у埗銆�**涓嶈鍚戝墠绔壙璇恒�屽鍏ュ悗浼氬緱鍒版瘡椤甸噸澶嶇殑椤电湁銆�**銆�
+
+## 娉ㄦ剰浜嬮」
+
+- **涓嶈缂撳瓨 `catalog`**锛氭瘡娆¤姹傜幇绠椼�傜悊鐢辫銆宍catalog` 鐨勬瀯閫犳柟寮忋�嶃��
+- **`catalog` 姣忛」蹇呴』甯� `hint`**锛氶�夊瀷鎸囧紩鏄畠鍙互琚ā鍨嬬湅瑙佺殑鍞竴鍑哄彛銆傛敞鍐岃〃閲屾柊澧炵粍浠舵椂锛�
+ 璇ョ粍浠剁殑 `aiHint` 瑕佷竴骞跺啓鍏ㄢ�斺�旀紡涓�鏉★紝閭d釜缁勪欢灏卞熀鏈笉浼氳妯″瀷閫変腑銆�
+- **`blobIds` 椤哄簭鏈夋剰涔�**锛氬椤垫枃浠舵寜鏁扮粍椤哄簭鐞嗚В椤靛簭锛屽墠绔淇濆簭锛屼笉瑕佺敤鏃犲簭闆嗗悎鎵胯浇銆�
+- **涓婁紶涓庤瘑鍒槸涓ゆ**锛氱敤鎴烽�夊畬鏂囦欢**涓嶅彂**璇嗗埆璇锋眰锛岀瓑鐢ㄦ埛鐐广�屽紑濮嬭瘑鍒�嶆墠鍙戙�備笂浼犲湪 AntDV 鐨勪笂浼犵粍浠堕噷瑕佸厛鍏虫帀瀹冨唴缃殑鑷姩涓婁紶閫氶亾锛岀敱鎸夐挳缁熶竴瑙﹀彂銆�
+- **缁戦檮浠惰鍏堜簬璇嗗埆**锛氬厛缁戝啀璇嗗埆锛岃瘑鍒け璐ユ枃浠朵篃宸插綊灞炲埌妯℃澘锛屼笉浼氱暀瀛ゅ効鏂囦欢銆�
+- **璇嗗埆瑕佹斁瀹借秴鏃�**锛氳繖鏉¤姹傚崟鐙 180 绉掋�傜敤榛樿瓒呮椂浼氬湪妯″瀷杩斿洖鍓嶅氨琚帎鏂紝鑰屼笖閿欒淇℃伅鐪嬩笉鍑烘槸瓒呮椂杩樻槸妯″瀷鎸備簡銆�
+- **涓嶈鍦ㄥ脊绐楅噷鍚炴帀璇嗗埆閿欒**锛氬悗绔凡鎸夈�岀淮搴� + 瀹為檯鍊� + 鍙墽琛屽姩浣溿�嶇粰浜嗙簿纭枃妗堬紝鐢辫姹傚眰缁熶竴寮瑰嚭鍗冲彲锛屽脊绐楅噷鍐嶅寘涓�灞傚弽鑰屼細鐩栦綇瀹冦��
+- **杞藉叆鏃惰浼犲綋鍓嶈鍒�**锛氳閰嶈矾寰勫鏋滀笉浼犲綋鍓嶅凡缂栬緫鐨勫垽瀹氳鍒欙紝绛変簬鎶婄敤鎴峰啓濂界殑瑙勫垯闈欓粯娓呯┖銆�
+- **钀芥鐨勫睘鎬ц緭鍏ユ鏄崟琛岀殑**锛氬彲缁戝畾瀛楁缁熶竴鐢ㄨ嚜瀹氫箟鎺т欢锛堜笅鎷� + 鍗曡杈撳叆妗嗭級銆�**AI 瀵煎叆鍑烘潵鐨勫琛岃惤娆惧�间細鍘熸牱淇濈暀銆佷篃鑳芥纭姌琛�**锛屼絾鍙鐢ㄦ埛鍘荤紪杈戦偅涓緭鍏ユ锛屾崲琛屽氨浼氳鎵撴帀銆侀噸鏂板彉鍥炰竴鐗囥�傝鍋氥�屽湪璁捐鍣ㄩ噷涔熻兘鎵嬪伐鏁插琛岃惤娆俱�嶏紝寰楁妸璇ユ帶浠剁殑杈撳叆妗嗘崲鎴愬琛岃緭鍏ユ鈥斺�旇鎺т欢琚叏閮ㄥ彲缁戝畾瀛楁鍏辩敤锛屽睘浜庨渶瑕佸崟鐙瘎浼扮殑鏀瑰姩銆�
+- **杞藉叆浼氭竻绌烘挙閿�鏍�**锛氱敾甯冮潪绌烘椂鍏堝脊纭骞跺缓璁厛淇濆瓨锛涙枃妗堣**鏄庤鏃犳硶鐢ㄦ挙閿�鎭㈠**銆�
+- **`skipped` / `problems` 閫愭潯灞曠ず**锛氫笉瑕佸彧鎶ユ潯鏁帮紝鐢ㄦ埛瑕佺収鐫�鏀广��
+- **鏈疆涓嶅仛銆孉I 鏂板缓妯℃澘銆�**锛氳璁″櫒蹇呴』甯� `templateId` 杩涘叆锛孉I 瀵煎叆鍙湪鏃㈡湁妯℃澘鐨勮璁″櫒鍐呫�傛兂鍋氥�屼笂浼犳枃浠剁洿鎺ラ�犳柊妯℃澘銆嶉渶鍏堝缓妯℃澘澹筹紝鏄彟涓�鏉℃祦绋嬨��
+- **鏈疆涓嶅仛 AI 鑷姩鍙戝竷鐗堟湰**锛屼篃涓嶅仛鎾ら攢銆�
+- **鏂囦欢绫诲瀷鍦ㄥ墠绔彧鍋氬嵆鏃剁害鏉�**锛堟墿灞曞悕鐧藉悕鍗� + 鎷栨嫿鍖烘彁绀猴級锛�**鏉冨▉鏍¢獙鍦ㄥ悗绔�**锛屽墠绔埆鎶婅繖閲岀殑 3 涓枃浠朵笂闄愬綋鎴愬畨鍏ㄨ竟鐣屻��
+- **妯℃澘鍒犻櫎浼氳繛甯︽竻鐞嗛檮浠�**锛氭湰杞ˉ榻愪簡銆屽垹闄ゆā鏉挎椂娓呯悊鍏跺悕涓嬮檮浠躲�嶇殑鍔ㄤ綔锛孉I 瀵煎叆鐨勬簮鏂囦欢涓嶄細鍦ㄦā鏉垮垹闄ゅ悗鍙樻垚姘镐箙瀛ゅ効銆傚墠绔笉闇�瑕佸鐞嗭紝浣嗛獙鏀舵椂鍊煎緱纭涓�娆°��
+
+## 閿欒鐮�
+
+| 閿欒鐮� | 鎶ユ枃 | 瑙﹀彂鍦烘櫙 |
+|---|---|---|
+| `1_070_104_000` | AI 瀵煎叆鍔熻兘鏈惎鐢紙`yudao.qcreport.ai-import.enabled` 褰撳墠涓� false锛夛紝璇疯仈绯荤鐞嗗憳寮�鍚悗鍐嶈瘯 | 杩愮淮鎶婂紑鍏冲叧鎴愪簡 `false` |
+| `1_070_104_001` | 涓婁紶鐨勬枃浠讹紙blobId=X锛変笉瀛樺湪鎴栧凡琚竻鐞嗭紝璇烽噸鏂颁笂浼犲悗鍐嶈瘯 | `blobId` 鏌ヤ笉鍒般�傛枃浠跺凡琚竻鐞嗘垨缂栧彿浼犻敊 |
+| `1_070_104_002` | 涓嶆敮鎸佺殑鏂囦欢銆孹銆嶏紙鎵╁睍鍚嶏細Y锛夈�備粎鏀寔 PDF銆乄ord(.docx)銆丒xcel(.xlsx)銆佸浘鐗�(png/jpg/jpeg/bmp/gif/webp) 涓庢枃鏈�(txt/csv)锛岃杞崲鏍煎紡鍚庨噸鏂板鍏� | 鎵╁睍鍚嶄笉鍦ㄧ櫧鍚嶅崟鍐� |
+| `1_070_104_003` | 涓嶆敮鎸佺殑鏂囦欢銆孹銆嶏紙鏃х増 Office 鏍煎紡.Y锛夈�傝鐢� Office 鎵撳紑鍚庛�屽彟瀛樹负銆�.docx 鎴� .xlsx 鍐嶉噸鏂板鍏� | 涓婁紶浜� `.doc` / `.xls` |
+| `1_070_104_004` | 鏂囦欢銆孹銆嶅ぇ灏� YMB锛岃秴杩囧崟鏂囦欢涓婇檺 ZMB锛岃鍘嬬缉鎴栨媶鍒嗗悗閲嶆柊瀵煎叆 | 瓒呰繃 `maxFileSizeMb`锛堥粯璁� 20MB锛� |
+| `1_070_104_005` | 鏂囦欢銆孹銆嶆湭瑙f瀽鍑轰换浣曞彲鐢ㄥ唴瀹癸紙鍏� N 椤碉級銆傝嫢鏄壂鎻忎欢锛岃纭鍒嗚鲸鐜囦笉浣庝簬 200 DPI銆佹枃瀛楁棤涓ラ噸鍊炬枩鎴栭伄鎸★紱鎺ㄨ崘鏀圭敤鐢靛瓙鐗� PDF 鎴� Word/Excel | 绌烘枃浠讹紱浼犵湡浠剁瓑缂栫爜涓嶅彈鏀寔鐨勫浘鐗囷紱**鍐呭涓虹函绌虹櫧鐨� `.docx` / `.xlsx` / `.txt`**銆俙.docx` / `.xlsx` 鎵撲笉寮�锛堟崯鍧忋�佸甫瀵嗙爜锛夎蛋 `1_070_104_015`锛屼笉浼氳惤鍒拌繖閲� |
+| `1_070_104_006` | 涓�娆℃渶澶氬鍏� N 涓枃浠讹紝鏈鎻愪氦浜� M 涓紝璇峰垎鎵瑰鍏� | 瓒呰繃 `maxFiles`锛堥粯璁� 3锛� |
+| `1_070_104_007` | 鏂囦欢銆孹銆嶅叡 N 椤碉紝瓒呰繃鍗曟璇嗗埆涓婇檺 M 椤碉紝璇锋媶鍒嗗悗鍒嗘壒瀵煎叆 | 瓒呰繃 `maxPagesPerFile`锛堥粯璁� 5锛夈��**涓嶉潤榛樻埅鏂�** |
+| `1_070_104_008` | 缁勪欢娓呭崟鍙傛暟涓嶅悎娉曪紙鍘熷洜锛夛紝璇峰埛鏂伴〉闈㈠悗閲嶈瘯 | `catalog` 涓虹┖銆佸惈娌℃湁 `type` 鐨勯」銆佽秴 40 椤广�佸簭鍒楀寲瓒� 32KB |
+| `1_070_104_009` | 缁勪欢娓呭崟鐨� Schema 鐗堟湰涓恒�孹銆嶏紝鏈嶅姟绔彧鎺ュ彈銆孻銆嶏紝璇峰埛鏂伴〉闈㈠悗閲嶈瘯 | `schemaVersion` 涓庤璁″櫒涓嶄竴鑷达紙閫氬父鏄墠绔凡鏇存柊鑰屽悗绔湭鍙戠増锛� |
+| `1_070_104_010` | AI 璇嗗埆璋冪敤澶辫触锛堝凡鑰楁椂 Nms锛夛細鍘熷洜銆傝鍒般�孉I 澶фā鍨嬨�嶄腑纭瀵硅瘽妯″瀷宸插惎鐢ㄤ笖瀵嗛挜鏈夋晥锛屾垨绋嶅悗閲嶈瘯 | 妯″瀷鏈嶅姟寮傚父銆佺綉缁滀笉閫氥�佸瘑閽ユ棤鏁� |
+| `1_070_104_011` | AI 璇嗗埆瓒呮椂锛堟湰娆″凡绛� N 绉掞級銆傛枃浠堕〉鏁版垨鏁伴噺杈冨鏃惰�楁椂鏇撮暱锛岃鍑忓皯鏂囦欢鏁伴噺锛屾垨鏀圭敤鐢靛瓙鐗� PDF / Word / Excel | 妯″瀷鎺掗槦鎴栨枃浠惰繃澶с��**鎺ュ彛渚ц秴鏃堕粯璁� 60 绉�**锛堝悗绔� `yudao.ai.timeout`锛屼笌鍓嶇閭f潯 axios 鐨� 180 绉掓槸涓ら亾鐙珛鐨勯椄锛� |
+| `1_070_104_012` | AI 杩斿洖鐨勫唴瀹规棤娉曡В鏋愪负妯℃澘鑽夌锛堝凡鏀跺埌 N 涓瓧绗︼級銆傝嫢鏂囦欢鍐呭寰堥暱锛岃鎷嗗垎鍚庡垎鎵瑰鍏ワ紱鑻ユ寔缁け璐ワ紝璇锋敼鐢ㄦ墜宸ヨ璁� | 妯″瀷杈撳嚭涓嶆槸棰勬湡 JSON锛堣鎴柇銆佸す甯﹁В閲婃枃瀛楃瓑锛夈�傚師濮嬭緭鍑哄凡鍐欒繘鏈嶅姟绔棩蹇� |
+| `1_070_104_013` | AI 鏈兘浠庢枃浠躲�孹銆嶄腑璇嗗埆鍑轰换浣曞彲鐢ㄧ粍浠躲�傝纭璇ユ枃浠舵槸妫�楠屾姤鍛婏紱鑻ョ‘瀹炴槸锛岃鏀圭敤鎵嬪伐璁捐妯℃澘 | 涓�涓粍浠堕兘娌¤瘑鍒嚭鏉ャ��**杩欐槸鍞竴涓�涓�屾暣浣撳け璐ャ�嶇殑璇箟** |
+| `1_070_104_014` | 鏈鎻愪氦鐨勬枃浠跺悎璁� N 椤碉紝瓒呰繃鍗曟璇嗗埆涓婇檺 M 椤碉紙鍗曟枃浠朵笂闄� K 椤碉級锛岃鍑忓皯鏂囦欢鏁伴噺鎴栧垎鎵瑰鍏� | 姣忎釜鏂囦欢閮芥病瓒呫�佸姞璧锋潵瓒� `maxPagesPerRequest`锛堥粯璁� 8锛� |
+| `1_070_104_015` | 鏂囦欢銆孹銆嶆棤娉曚綔涓� .Y 鎵撳紑锛屽唴瀹瑰凡鎹熷潖鎴栧彈瀵嗙爜淇濇姢銆傝鍏堢敤 Office 鎵撳紑璇ユ枃浠讹紝纭鑳芥甯告樉绀哄悗銆屽彟瀛樹负銆�.docx / .xlsx 鍐嶉噸鏂板鍏ワ紱鑻ユ枃浠舵湁鎵撳紑瀵嗙爜锛岃鍏堣В闄ゅ瘑鐮佷繚鎶� | `.docx` / `.xlsx` 瑙f瀽鎶涘紓甯革紙POI 鎵撲笉寮�锛夈��**銆岀┖鐧姐�嶄笌銆屾崯鍧忋�嶆槸涓ゅ洖浜嬶紝鎶ユ枃鍒嗗紑**锛涙鍓嶆崯鍧忔枃浠惰鎶� `1_070_104_005`锛堣鐢ㄦ埛鍘绘煡鍒嗚鲸鐜囷級锛屽凡绾犳 |
+
+> 娉細`templateId` **涓嶅仛瀛樺湪鎬ф牎楠�**锛屽畠鍙敤浜庢棩蹇楃暀鐥曚笌闄勪欢褰掑睘銆傚墠绔姟蹇呭厛鐢ㄧ湡瀹炲瓨鍦ㄧ殑妯℃澘 id 杩涜璁″櫒銆�
diff --git a/docs/qc_report_configurable_columns_design.md b/docs/qc_report_configurable_columns_design.md
new file mode 100644
index 0000000..d021069
--- /dev/null
+++ b/docs/qc_report_configurable_columns_design.md
@@ -0,0 +1,239 @@
+# 璐ㄦ鎶ュ憡銆岃〃杈惧姏缂哄彛銆嶈璁★細鍙嚜瀹氬垪鐨勬楠岃〃 + 鍙厤瀛楁鐨勬牱鍝佷俊鎭�
+
+> 鐘舵�侊細**寰呯‘璁�**銆傛湰鏂囧彧鍋氭柟妗堬紝涓嶅姩浠g爜銆�
+> 瑙﹀彂鑳屾櫙锛欰I 瀵煎叆宸茶兘姝g‘閫夊埌 `GroupedQualityTable`锛堥�夊瀷闂宸蹭慨锛岃寮�鍙戣繘搴� 搂浜屽崄鍥涳級锛�
+> 浣嗙敤鎴锋瘮瀵瑰師浠跺悗鎸囧嚭銆岃崏绋夸粛涓嶅儚鍘熶欢銆嶃�傜粡鏍告煡锛屽墿涓嬬殑宸窛**鍏ㄩ儴鏄�屽彲鐢ㄧН鏈ㄧ殑琛ㄨ揪鍔涗笉澶熴��**锛�
+> 涓嶆槸璇嗗埆闂鈥斺�旀枃瀛楅兘鎶藉嚭鏉ヤ簡锛屾槸缁勪欢瑁呬笉涓嬨��
+
+---
+
+## 1. 璇佹嵁锛氬樊璺濆埌搴曞湪鍝�
+
+鐢ㄦ埛鍘熶欢銆婄櫨浜嬫ā鐗�.docx銆嬶紙142373 瀛楄妭锛変笌褰撳墠鑽夌鐨勯�愰」瀵规瘮锛�
+
+| 鍘熶欢閲屾湁鐨� | 鑽夌閲岀殑涓嬪満 | 鍘熷洜 |
+|---|---|---|
+| 琛ㄦ牸鍒椼�屾娴嬫柟娉曘�嶏紙`GB 5009.3-2016` / `ANA.MTH-000034`锛� | **鏁村垪涓㈠純** | `GroupedQualityTable` 鐨� 7 鍒楀啓姝诲湪浠g爜甯搁噺閲� |
+| 琛ㄦ牸鍒椼�岀粨璁恒�嶏紙`鍚堟牸Checkout`锛� | 鏁村垪涓㈠純 | 鍚屼笂 |
+| 涓ょ骇琛ㄥご銆屾楠岀粨鏋� \| 缁撹銆� | 鎷嶅钩 | 缁勪欢鍙敮鎸佸崟灞傝〃澶� |
+| 鏍峰搧淇℃伅 7 椤癸紙浜у搧鍚嶇О / 浜у搧鏁伴噺 / 瑙勬牸 / 鐢熶骇鏃ユ湡 / 鎵瑰彿 / 鍦熻眴鍝佺 / 鏈夋晥鏃ユ湡锛� | 鍙墿 6 椤癸紝涓斾笌鍘熶欢鐨� 6 椤�**涓嶆槸鍚屼竴鎵�** | `SampleInfo` 鐨勫瓧娈靛啓姝诲湪浠g爜甯搁噺閲� |
+| 棣栬鏍忕洰鍚� `浜у搧鍚嶇ОMaterial Names` | 妯″瀷鎷块�氱敤缁勪欢纭噾鎴愮嫭绔嬩竴琛� | 娌℃湁浠讳綍缁勪欢鑳芥壙鎺ャ�岃〃澶撮噷鐨勬爮鐩悕銆� |
+
+涓ゅ銆屽啓姝汇�嶇殑浣嶇疆锛�
+
+- `mom-pro2-before/src/components/quality/inspection/grouped-quality-table.ts` 鐨� `COLUMNS` 甯搁噺锛�7 椤癸級
+- `mom-pro2-before/src/components/quality/header/sample-info.ts` 鐨� `SAMPLE_FIELDS` 甯搁噺锛�6 椤癸級
+
+---
+
+## 2. 涓ゆ潯纭害鏉燂紙鍏堣娓呮锛屽畠浠喅瀹氭柟妗堝舰鐘讹級
+
+### 2.1 灞炴�у崗璁彧璁ゆ爣閲忊�斺�斾笉鑳界敤銆屾暟缁勫睘鎬с��
+
+`QualityProps = Record<string, boolean | number | string | undefined>`锛�
+`QualityFieldType` 鍙湁 `boolean | enum | number | string | text` 浜旂銆�
+灞炴�ф渶缁堣惤鍒扮敾甯冭妭鐐圭殑 `attributes` 涓婏紙鍐欎綔 `data-qc-<key>`锛夛紝鑰�
+`ReportTemplateSchema.QualityComponentNode.attributes` 涔熸槸瀛楃涓叉槧灏勩��
+
+鈬� **鏂板涓�涓�屽垪鏁扮粍銆嶅睘鎬х被鍨嬭鍔ㄥ崗璁湰韬�**锛堝睘鎬ч潰鏉挎帶浠躲�佺敾甯冨簭鍒楀寲銆乻chema 濂戠害娴嬭瘯銆�
+涓や晶娓叉煋鍣級锛屼唬浠疯繙瓒呮敹鐩娿�傚垪瀹氫箟蹇呴』鑳借缂栫爜鎴�**涓�涓爣閲忓瓧绗︿覆**銆�
+
+### 2.2 娓叉煋鍣ㄤ笉璁よ瘑缁勪欢绫诲瀷鈥斺�斾笉闇�瑕佸姩娓叉煋鍣�
+
+杩欐槸濂芥秷鎭紝宸叉牳鏌ワ細
+
+- 鍚庣 `HtmlRenderer.renderAttributes` 鍙仛涓や欢涓庣粍浠舵棤鍏崇殑浜嬶細璺宠繃 `data-quality-type` / `data-qc-*`銆�
+ 鎷︽帀 `on*` 涓庡嵄闄╁崗璁紱**娌℃湁浠讳綍鎸夌粍浠剁被鍨嬪垎鏀殑閫昏緫**锛屼篃娌℃湁灞炴�х櫧鍚嶅崟銆�
+- 鍚庣 `CanvasSafety.validate` 鏄粦鍚嶅崟锛坄script` 绛夊彲鎵ц鏍囩銆佷簨浠跺睘鎬с�佹暣娈� CSS锛夛紝
+ 涓嶆槸鏍囩/灞炴�х櫧鍚嶅崟 鈬� `colspan` / `rowspan` 鏈潵灏辨斁琛屻��
+- 琛屽惊鐜潬 `data-qc-repeat` / `data-qc-repeat-row` 杩欎袱涓�氱敤灞炴�ч┍鍔ㄣ��
+
+鈬� **鏈疆涓嶉渶瑕佹敼 `HtmlRenderer`銆乣BASE_CSS`銆乣CanvasSafety`**锛屼篃涓嶉渶瑕佹敼 schema 鐗堟湰鍙枫��
+缁勪欢渚ф敼鍔ㄩ泦涓湪銆屾敞鍐岃〃閲岀殑涓�涓� definition銆嶃�傝繖涔熸鏄川閲忕粍浠跺崗璁殑璁捐鍒濊》
+锛坄core/types.ts` 寮�澶达細銆屾柊澧炶川閲忕粍浠讹紳娉ㄥ唽涓�涓柊 definition锛屼笉闇�瑕佹敼鍔� GrapesJS 闆嗘垚浠g爜銆嶏級銆�
+
+---
+
+## 3. 鏂规
+
+### 3.1 鎬诲師鍒欙細涓嶆柊澧炵粍浠讹紝缁欑幇鏈夌粍浠跺姞銆屽彲閫夎鐩栥�嶅睘鎬�
+
+**鎺ㄨ崘鍋氭硶**锛氱粰 `GroupedQualityTable` 鍔犱袱涓�**鍙��**灞炴�� `columns` / `headerSpans`锛涚粰 `SampleInfo`
+鍔犱竴涓�**鍙��**灞炴�� `fields`銆�
+
+- 灞炴��**缂哄腑鏃惰涓洪�愬瓧涓嶅彉**锛坄buildContent` 閲屽洖钀藉埌鐜版湁甯搁噺锛夆噿 瀛橀噺鍜屽凡鍙戝竷妯℃澘闆跺奖鍝嶏紝
+ 涓嶉渶瑕佹暟鎹縼绉伙紝涓嶉渶瑕佹敼 `defaults`銆�
+- **涓嶆柊澧炵涓変釜妫�楠岃〃缁勪欢**銆傚綋鍓� 13 涓粍浠堕噷宸茬粡鏈変袱涓楠岃〃锛坄QualityTable` / `GroupedQualityTable`锛夛紝
+ 鍐嶅姞涓�涓氨鏄笁涓悓绫荤珵浜夛紝**鏋佸彲鑳芥妸鍒氬垰淇ソ鐨勯�夊瀷绋冲畾鎬у啀娆℃墦鐮�**锛堝弬瑙� 搂浜屽崄鍥涳細
+ 閫夊瀷涓嶇ǔ鐨勬牴鍥犲氨鏄彁绀鸿瘝閲屽浜嗕竴澶勬寚鍚戝钩閾鸿〃鐨勬帾杈烇紝缁勪欢鏁伴噺澧炲姞鏄悓涓�涓満鐞嗭級銆�
+ 鐢ㄦ埛鐨勬敹鐩婃潵鑷�屽垪鑳芥敼銆嶏紝涓嶆槸銆屽涓�涓粍浠躲�嶃��
+
+### 3.2 鍒�/瀛楁鎻忚堪鐨勮娉�
+
+**鍗曡瀛楃涓�**锛屽垪涓庡垪涔嬮棿鐢� `|` 鍒嗛殧锛屾瘡鍒楀啓浣� `鍒楁爣棰�=缁戝畾琛ㄨ揪寮廯锛�
+
+```
+搴忓彿={{index}}|妫�楠岄」鐩�={{item.itemName}}|妫�娴嬫柟娉�={{item.checkMethod}}|鏍囧噯瑕佹眰={{item.standardValue}}|瀹炴祴鍊�={{item.actualValue}}|鍗曚綅={{item.unit}}|鍒ゅ畾={{item.resultText}}
+```
+
+涓夋潯绾︽潫锛岄兘鏉ヨ嚜 2.1锛�
+
+1. **蹇呴』鍗曡**锛氳繖涓蹭笢瑗挎渶缁堟槸鐢诲竷鑺傜偣鐨勪竴涓� HTML 灞炴�у�硷紝鎹㈣鍦ㄥ睘鎬ч噷鏄悎娉曠殑浣嗘瀬鏄撹
+ 缂栬緫鍣�/搴忓垪鍖栫幆鑺傛敼鍐欙紝缁熶竴鎸夊崟琛屽鐞嗐��
+2. **`=` 鍙綔绗竴涓垎闅旂**锛氭爣棰樹笌琛ㄨ揪寮忛兘涓嶅厑璁稿惈 `=`锛岃〃杈惧紡閲岀殑 `{{...}}` 鍘熸牱淇濈暀銆�
+3. **鏍囬閲屼笉鍏佽鍑虹幇 `|`**锛涢渶瑕佺珫绾挎椂鐢ㄥ叏瑙� `锝渀銆�
+
+**绾靛悜鍚堝苟鍒楋紙鍒嗙粍琛ㄤ笓鐢級**锛氬垪鏍囬鍓嶅姞 `#` 琛ㄧず銆岃繖涓�鍒楄璺ㄤ綇鏁寸粍銆嶏紝娌跨敤鐜版湁
+`GroupedQualityTable` 鐨� `rowspan` / `hidden` 鏈哄埗锛�
+
+```
+#妫�楠岄」鐩�={{item.itemName}}|瀛愰」={{item.group.childName}}|...
+```
+
+### 3.3 涓ょ骇琛ㄥご锛堝彲閫夛級
+
+`headerSpans` 鎻忚堪**涓婇潰閭d竴灞�**琛ㄥご锛屽崟鍏冩牸鍐欎綔 `鏍囬^璺ㄨ秺鍒楁暟`锛�
+
+```
+妫�楠岀粨鏋淾3|缁撹^2
+```
+
+涓嬪眰琛ㄥご鐢� `columns` 閲屽悇鍒楃殑鏍囬鑷姩鎷煎嚭锛堥『搴忓嵆鍒楅『搴忥級銆傜害鏉燂細
+**鍚勫崟鍏冩牸璺ㄨ秺鍒楁暟涔嬪拰蹇呴』绛変簬 `columns` 鐨勫垪鏁�**锛屽惁鍒欎繚瀛樻椂缁欏嚭绮剧‘鎶ラ敊锛�
+
+> 琛ㄥご璺ㄥ垪鏁板悎璁� 5锛屾楠岃〃鐨勫疄闄呭垪鏁颁负 7锛屼袱鑰呭繀椤荤浉绛夈�傝妫�鏌ャ�岃〃澶磋法鍒椼�嶉噷鍚勬鏈熬鐨� `^` 鏁板瓧銆�
+
+锛堟寜 `error-message-precision`锛氱粰鍑哄叿浣撶淮搴� + 涓や晶瀹為檯鍊� + 鍙墽琛屽姩浣溿�傦級
+
+### 3.4 鏍峰搧淇℃伅瀛楁鍙厤
+
+鍚屼竴涓娉曪紝鐢ㄥ湪 `SampleInfo` 涓婏細
+
+```
+鏍峰搧缂栧彿={{report.sampleNo}}|浜у搧鍚嶇О={{report.productName}}|瑙勬牸={{report.spec}}|鐢熶骇鏃ユ湡={{report.produceDate}}|鎵瑰彿={{report.batchNo}}|鍦熻眴鍝佺={{report.potatoVariety}}|鏈夋晥鏃ユ湡={{report.expireDate}}
+```
+
+姣忚鏀惧嚑缁勪粛鐢辩幇鏈夌殑 `pairsPerRow` 灞炴�ф帶鍒讹紝甯冨眬閫昏緫涓嶅彉銆�
+
+---
+
+## 4. 蹇呴』涓�骞朵慨鐨勬暟鎹晶缂哄彛锛氥�屾娴嬫柟娉曘�嶇洰鍓嶄笉鍦ㄦ覆鏌撲綔鐢ㄥ煙
+
+杩欐槸鏈疆鏈�瀹规槗婕忔帀銆佷笖**涓嶄慨鍒欐柊鍔熻兘褰㈠悓铏氳**鐨勪竴鏉°��
+
+| 灞� | 鐜扮姸 |
+|---|---|
+| MES 鍗曟嵁渚� `MesQcReportItemRespDTO` | **宸叉湁** `checkMethod`锛堟娴嬫柟娉曪級銆乣tool`锛堟娴嬪伐鍏凤級 |
+| qcreport 寮曟搸 `InspectionItem` | **娌℃湁**杩欎袱涓瓧娈� |
+| `ReportContext.itemMap()` 涓嬪彂鐨勫墠绔綔鐢ㄥ煙 | 鍙湁 `index / itemCode / itemName / standardValue / actualValue / unit / requirement / group.* / upperLimit / lowerLimit / result / resultText / remark` |
+
+鈬� 灏辩畻鍒楀畾涔夐噷鍐欎簡 `妫�娴嬫柟娉�={{item.checkMethod}}`锛屾覆鏌撴湡涔熷彇涓嶅埌鍊硷紝鍙細鎸夈�岀粦瀹氬彇涓嶅埌鍊笺��
+璁颁竴鏉$己鍙c�佺暀涓�鐗囩┖鐧姐��
+
+**椤昏ˉ鐨勯摼璺�**锛堢己涓�涓嶅彲锛屼笖涓や晶瀛楁鍚嶅繀椤婚�愬瓧涓�鑷达級锛�
+
+1. `MesQcReportContextMapper`锛氭妸 DTO 鐨� `checkMethod`锛堝繀瑕佹椂鍚� `tool`锛夋槧灏勮繘 `InspectionItem`
+2. `InspectionItem`锛氬姞瀛楁 + 杩� `copy()`
+3. `ReportContext.itemMap()`锛氫笅鍙戝埌鍓嶇浣滅敤鍩�
+4. `ReportContextCodec`锛氬喕缁撳揩鐓х殑璇诲啓锛堝惁鍒欏巻鍙叉姤鍛婇噸娓叉煋鏃朵涪鍊硷級
+5. 鍓嶇 `engine/context.ts` 鐨� `ReportContextItem`锛氶暅鍍忓悓鍚嶅瓧娈�
+6. 瀵规媿 fixture 涓庣浉鍏冲崟娴�
+
+**娉ㄦ剰**锛歚resultText`锛堝垽瀹氾級鏄�**寮曟搸绠楀嚭鏉ョ殑**锛坄InspectionItem.applyResult`锛夛紝涓嶆槸 MES 缁欑殑锛�
+銆岀粨璁恒�嶅垪濡傛灉瑕佺殑鏄汉宸ユ媿鐨勭粨璁猴紝杩樿纭瀹冩槸鍚﹀凡鏈変笅鍙戯紙`MesQcReportContextMapper` 娉ㄩ噴鎻愬埌
+銆屼汉宸ユ媿鐨勬楠屽垽瀹氾紝涓庡紩鎿庣畻鍑虹殑 result/resultText/conclusion 鍒嗗垪涓ゅ銆嶏級銆傝繖涓�鏉�**寰呯‘璁ゅ悗鍐嶅畾**銆�
+
+---
+
+## 5. 琚惁鐨勫閫�
+
+| 澶囬�� | 鍚︽帀鐨勫師鍥� |
+|---|---|
+| 鍒楃殑鍒楀畾涔夌敤 JSON 瀛楃涓� | 妯″瀷瑕佽緭鍑鸿浆涔夊悗鐨勫祵濂� JSON锛坄"columns":"[{\"label\":鈥]"`锛夛紝瀹炴祴杩欑被杞箟鏄ā鍨嬪嚭閿欑殑閲嶇伨鍖猴紱灞炴�ч潰鏉块噷浜轰篃娌℃硶鎵嬫敼銆傚崟琛岃娉曚俊鎭噺鐩稿悓鑰屼袱杈归兘濂藉啓銆� |
+| 缁� `QualityFieldType` 鍔犳暟缁勭被鍨� | 瑕佸姩鍗忚銆佸睘鎬ч潰鏉裤�佺敾甯冨簭鍒楀寲銆乻chema 濂戠害娴嬭瘯锛屼唬浠疯繙瓒呮敹鐩婏紙瑙� 2.1锛夈�� |
+| 鏂板鐙珛鐨勩�屽彲鑷畾鍒楁楠岃〃銆嶇粍浠� | 涓� `QualityTable` / `GroupedQualityTable` 涓夋柟绔炰簤锛岄�夊瀷绋冲畾鎬ч闄╁ぇ锛堣 3.1锛夛紱鐢ㄦ埛杩樿缁存姢涓ゅ鍚岀被缁勪欢銆� |
+| 鍋氫竴涓彲瑙嗗寲鐨勫垪缂栬緫鍣紙澧炲垹鎷栨嫿锛� | 鏀剁泭纭疄鏇撮珮锛屼絾鎴愭湰鏄墠鑰呯殑鏁板�嶏紝涓旈渶瑕佹柊鐨勫睘鎬ч潰鏉挎帶浠剁被鍨嬨��**寤鸿鍏堢敤鎵嬪~瀛楃涓查獙璇佷环鍊�**锛岀湡鏈夐渶姹傚啀杩唬鈥斺�旈偅鏃跺瓧绗︿覆璇硶宸茬粡鏄幇鎴愮殑瀛樺偍鏍煎紡锛屼笉鐢ㄨ縼绉汇�� |
+| 鎶� `SampleInfo` 鐨� `dataSchema` 鏀规垚鍔ㄦ�� | 缁戝畾閫夋嫨鍣ㄥ彧鑳芥灇涓鹃潤鎬� `dataSchema`锛屽姩鎬佸寲浼氳銆岄�夋暟鎹瓧娈点�嶅叆鍙eけ鏁堛��**淇濇寔闈欐��**锛歚columns`/`fields` 灞炴�ц涓�**涓嶅彲缁戝畾**锛坄bindable` 涓嶅0鏄庯級锛岀敱浜烘墜鍐欏畬鏁翠覆銆� |
+
+---
+
+## 6. AI 渚х殑褰卞搷锛堟湰杞殑閲嶇偣椋庨櫓锛�
+
+鏂板睘鎬у繀椤昏妯″瀷鑳藉~锛屽惁鍒� AI 瀵煎叆浠嶄骇涓嶅嚭杩欎簺鍒椼��
+
+1. **娓呭崟鑷姩甯︿笂**锛歚buildQualityComponentCatalog()` 鎶� `propertySchema` 鍘熸牱鏄犲皠鎴� `fields`锛�
+ 鏂板睘鎬у0鏄庝负 `type: 'text'` 鍗宠嚜鍔ㄨ繘鎻愮ず璇嶏紝**涓嶉渶瑕佹敼 `catalog.ts`**銆�
+ 鐢ㄧ幇鏈� `text` 绫诲瀷锛堣�屼笉鏄嚜閫犱竴涓柊绫诲瀷锛夎繕鑳借灞炴�ч潰鏉跨洿鎺ユ覆鏌撴垚澶氳杈撳叆妗嗭紝闆舵敼鍔ㄣ��
+2. **鎻愮ず璇嶈琛ヨ鍒�**锛氶渶瑕佹柊澧炰竴鏉℃娊鍙栬鍒欙紝璇存槑銆屽師浠堕噷妫�楠岃〃闄ゆ爣鍑嗗垪涔嬪杩樻湁鍒殑鍒�
+ 锛堟娴嬫柟娉曘�佺粨璁恒�佸娉ㄧ瓑锛夋椂锛岀敤 `columns` 鎶婅繖浜涘垪鎸� `鏍囬=缁戝畾` 鍐欒繘鍘汇�嶏紝
+ 骞剁粰鍑哄彲鐢ㄧ粦瀹氳矾寰勭櫧鍚嶅崟銆�
+3. **`aiHint` 蹇呴』閲嶅啓**锛歚GroupedQualityTable` 鐨� hint 瑕佽鏄庛�屽垪涓庢湰缁勪欢榛樿涓嶅悓鏃剁敤 `columns` 瑕嗙洊銆嶏紝
+ 涓�**涓嶈兘**璁╂ā鍨嬩互涓恒�屽垪涓嶄竴鑷村氨瑕佹崲缁勪欢銆嶁�斺�斿惁鍒欏張浼氬洖鍒伴�夊瀷涓嶇ǔ銆�
+4. **楠屾敹鍙e緞**锛欰I 瀵煎叆鐨勯獙鏀跺繀椤诲寘鍚�屽垪鏄惁涓庡師浠剁殑鍒�**閫愬垪瀵归綈**銆嶏紝
+ 鑰屼笉鍙槸銆宼ype 閫夊浜嗐�嶃�傝繖鏄湰杞粠鐢ㄦ埛鍙嶉閲屽鍒扮殑锛歚GroupedQualityTable` 閫夊涓嶇瓑浜庢姤鍛婂浜嗐��
+
+---
+
+## 7. 褰卞搷闈紙棰勪及鏀瑰姩娓呭崟锛�
+
+**鍓嶇锛坄mom-pro2-before/src/components/quality/`锛�**
+
+- `inspection/grouped-quality-table.ts`锛歚propertySchema` 鍔� `columns` / `headerSpans`锛坄type: 'text'`锛夛紱
+ `buildContent` 閲岃В鏋愶紝缂哄腑鍥炶惤鐜版湁 `COLUMNS`锛沗validate` 鍔犺法鍒楁暟鏍¢獙
+- `header/sample-info.ts`锛歚propertySchema` 鍔� `fields`锛坄type: 'text'`锛夛紱`buildContent` 鍚岀悊鍥炶惤
+- 鏂板涓�涓�**鍏辩敤鐨勮В鏋愬嚱鏁�**锛堝垪璇存槑涓� 鈫� 鍒楀畾涔夋暟缁勶級锛屼袱涓粍浠跺叡鐢紝閬垮厤涓や唤瑙f瀽閫昏緫婕傜Щ
+- `aiHint` 涓� `validate` 鐨勬枃妗�
+
+**鍚庣锛坄yudao-module-qcreport`锛�**
+
+- 鏁版嵁渚� 6 澶勶紝瑙� 搂4
+- 鎻愮ず璇嶏細`QcReportTemplatePromptBuilder.EXTRACTION_RULES` 鍔犱竴鏉¤鍒�
+- **涓嶉渶瑕�**鍔� `HtmlRenderer` / `BASE_CSS` / `CanvasSafety` / schema 鐗堟湰鍙�
+
+**涓嶅姩**锛歚docs/sql/config_export_all_*.sql`锛堟棤琛ㄧ粨鏋勩�佹棤閰嶇疆鏁版嵁鍙樻洿锛夈��
+
+---
+
+## 8. 鍏煎鎬�
+
+- 鏂板睘鎬ч兘鏄�**鍙��**涓�**涓嶅啓杩� `defaults`** 鈬� 宸蹭繚瀛樻ā鏉跨殑 `attributes` 閲屾病鏈夎繖涓敭锛�
+ `buildContent` 璧板洖钀藉垎鏀紝浜х墿閫愬瓧涓嶅彉銆�
+- `schemaVersion` 淇濇寔 `1.1`锛歚ReportTemplateSchemaCompatibilityTest` 瀹堢殑鏄�屾棫 JSON 璇诲緱鍑恒�嶏紝
+ 鍔犲睘鎬т笉褰卞搷锛沗QualityComponentNode.attributes` 鏄瓧绗︿覆鏄犲皠锛屾柊閿ぉ鐒跺吋瀹广��
+- 宸插彂甯冪増鏈紙鍐荤粨蹇収锛変笉閲嶇畻锛屼笉鍙楀奖鍝嶃��
+
+---
+
+## 9. 楠岃瘉璁″垝
+
+1. 鍗曟祴锛氫袱绫荤粍浠跺悇瑕嗙洊銆屽睘鎬х己甯� 鈫� 浜х墿涓庢敼鍓嶉�愬瓧涓�鑷淬�嶏紙闃插洖褰掔殑**绗竴浼樺厛绾�**鐢ㄤ緥锛夈��
+ 銆屽睘鎬у湪鍦� 鈫� 鍒楁暟/鍒楀簭/琛ㄥご璺ㄥ垪姝g‘銆嶃�佽法鍒楁暟涓嶅尮閰嶇殑鎶ラ敊鏂囨銆�
+2. 瑙f瀽鍑芥暟鐨勭函鍑芥暟鍗曟祴锛氶潪娉曡緭鍏ワ紙缂� `=`銆佺┖鏍囬銆乣|` 鍑虹幇鍦ㄦ爣棰橀噷锛夊悇鑷姤浠�涔堥敊銆�
+3. 鍓嶅悗绔竴鑷存�э細鏂板垪浜у嚭鐨� HTML 瑕佽繃 `FrontendConformanceTest` 涓� `CanvasSafetyTest`锛�
+ `rowspan`/`hidden` 鐨勫垎缁勬満鍒跺湪瑕嗙洊鍒椾箣鍚庝粛瑕佸伐浣溿��
+4. 鏁版嵁渚э細`{{item.checkMethod}}` 鍦ㄧ湡瀹炶川妫�鍗曚笂鍙栧緱鍒板�硷紙涓嶈捣缂哄彛鍛婅锛夈��
+5. AI 瀵煎叆锛氱湡瀹炴枃浠� + 绌� hint锛屾鏌�**鍒楅�愬垪瀵归綈**锛屼笉鍙湅 type銆�
+6. 瀛橀噺鍥炲綊锛歚mvn -o -pl yudao-module-qcreport -am test` 鍏ㄧ豢锛涘墠绔� `pnpm typecheck`銆�
+
+---
+
+## 10. 鏄庣‘涓嶅仛
+
+- 涓嶅仛鍙鍖栧垪缂栬緫鍣紙鍏堥獙璇佸瓧绗︿覆鏂规鐨勪环鍊硷級
+- 涓嶆柊澧炴楠岃〃缁勪欢
+- 涓嶆敼灞炴�у崗璁紙涓嶅姞鏁扮粍绫诲瀷锛�
+- 涓嶆敼 `HtmlRenderer` / `BASE_CSS` / `CanvasSafety`
+- 涓嶅姩 schema 鐗堟湰鍙枫�佷笉鍋氭暟鎹縼绉�
+- 涓嶆敼 `docs/sql/config_export_all_*.sql`
+
+---
+
+## 11. 寰呰鍐�
+
+1. **`headerSpans`锛堜袱绾ц〃澶达級鏄惁鏈疆灏卞仛**锛熶笉鍋氱殑璇濄�屾楠岀粨鏋� | 缁撹銆嶈繖灞備粛杩樺師涓嶄簡锛�
+ 浣嗗垪瑕嗙洊宸茬粡鑳借В鍐炽�屾娴嬫柟娉�/缁撹鍒椾涪澶便�嶈繖涓洿澶х殑缂哄彛銆�
+2. **銆岀粨璁恒�嶅垪鍙栧摢涓��**锛熶汉宸ユ媿鐨勫垽瀹氾紙`MesQcReportContextMapper` 閲屾彁鍒扮殑閭d竴澶勶級杩樻槸
+ 寮曟搸绠楃殑 `resultText`锛熷彇閿欎細璁╂姤鍛婄粨璁轰笌鍗曟嵁缁撹涓嶄竴鑷达紝灞炰簬涓氬姟鍙e緞锛岄渶浣犵‘璁ゃ��
+3. **`tool`锛堟娴嬪伐鍏凤級鏄惁涓�骞朵笅鍙�**锛熷師浠舵病鏈夎繖涓�鍒楋紝鍏堜笉涓嬪彂锛岄渶瑕佹椂鍐嶅姞銆�
+4. **鏍峰搧淇℃伅鐨勯粯璁ゅ瓧娈佃涓嶈淇濇寔鐜扮姸**锛�6 椤癸級锛熸敼浜嗛粯璁ゅ�间細璁�**鏂板缓**鐨勬牱鍝佷俊鎭潡涓庣幇鍦ㄤ笉鍚屻��
+ 寤鸿淇濇寔涓嶅彉锛屽彧璁┿�屽彲閰嶃�嶆垚涓虹敤鎴疯兘鏀圭殑鑳藉姏銆�
diff --git a/docs/qc_report_generate_from_qc_frontend_integration.md b/docs/qc_report_generate_from_qc_frontend_integration.md
new file mode 100644
index 0000000..efaac4b
--- /dev/null
+++ b/docs/qc_report_generate_from_qc_frontend_integration.md
@@ -0,0 +1,251 @@
+# 璐ㄦ鍗� 鈫� 璐ㄦ鎶ュ憡 鍑轰欢 鍓嶇鑱旇皟鏂规
+
+> 鍚庣妯″潡锛歚yudao-module-qcreport`銆�鎺ュ彛鍓嶇紑锛歚/admin-api/qc-report/instance`
+> 涓婃父鏁版嵁婧愶細`yudao-module-mes`锛坄MesQcReportApi`锛屾湰妯″潡涓嶇洿鎺ヨ MES 琛級
+> 鏈疆鑼冨洿锛�**鐢� MES 璐ㄦ鍗曪紙IQC/IPQC/OQC/RQC锛夌洿鎺ュ嚭鎶ュ憡**銆傚墠绔彧闇�閫夈�屽摢寮犲崟鎹� + 鐢ㄥ摢寮犳ā鏉裤�嶏紝
+> 鏁版嵁鍏ㄩ儴鐢卞悗绔粠 MES 鍙栵紝**鍓嶇涓嶅啀鑷繁鎷� `context`**銆�
+
+## 娑夊強椤甸潰
+
+| 椤甸潰 | 璺敱 | 璇存槑 | 鐘舵�� |
+|---|---|---|---|
+| MES 璐ㄦ鍗曞垪琛紙IQC/IPQC/OQC/RQC 鍥涗釜椤甸潰锛� | `/mes/qc/iqc`銆乣ipqc`銆乣oqc`銆乣rqc` | 琛屾搷浣滄柊澧炪�屽嚭鎶ュ憡銆嶏細閫夋ā鏉� 鈫� 璋冩湰鎺ュ彛 鈫� 璺虫姤鍛婂疄渚嬪垪琛紙宸插甫绛涢�夋潯浠讹級 | **宸茶惤鍦�** |
+| 鎶ュ憡瀹炰緥鍒楄〃椤� | `/qc/report-instance` | 鐢熸垚鍚庢寜 `businessType` + `businessId` 鍙嶆煡寰楀埌锛涙悳绱㈣〃鍗曞凡鍔犮�屼笟鍔″崟鎹�嶅瓧娈靛苟鏀寔璺敱甯﹀叆 | 宸茶惤鍦帮紙`views/mes/qc/report/instance/index.vue`锛� |
+| 妯℃澘璁捐鍣� | `/qc/report-template` | 鏃犳敼鍔紙妯℃澘闇�鍏堝湪璁捐鍣ㄩ噷閰嶅ソ妫�楠岄」琛ㄦ牸骞跺彂甯冿級 | 宸茶惤鍦� |
+
+> 涓� `qc_report_instance_frontend_integration.md` 鐨勫垎宸ワ細閭d唤璁茬殑鏄�岃皟鐢ㄦ柟鑷繁鍑嗗鏁版嵁銆嶇殑閫氱敤鍑轰欢锛�
+> 鏈唤璁茬殑鏄�屾暟鎹粠 MES 鍙栥�嶇殑涓撶敤鍏ュ彛銆備袱鑰呮渶缁堥兘钀藉埌鍚屼竴涓疄渚嬭〃銆佸悓涓�涓垪琛ㄩ〉銆�
+
+## 涓氬姟娴佺▼涓庢暟鎹甫鍏�
+
+1. **璐ㄦ鍗� 鈫� 鍑烘姤鍛�**锛氱敤鎴峰湪璐ㄦ鍗�**鍒楄〃琛屾搷浣�**閲岀偣銆屽嚭鎶ュ憡銆嶁啋 鍓嶇寮圭獥鍒楀嚭鍙�夋ā鏉�
+ 锛�**鍙垪鍑� `reportType` 涓庤鍗曟嵁绫诲瀷涓�鑷寸殑妯℃澘**锛夆啋 璋� `generate-from-qc`銆�
+2. **鍚庣鍏亾鏍¢獙**锛堟寜涓氬姟浼樺厛绾э紝鍙姤绗竴澶勶紝涓嶄竴娆℃姏澶氭潯锛夛細
+ 绫诲瀷鍚堟硶 鈫� 鍗曟嵁瀛樺湪 鈫� 宸插畬鎴愭楠� 鈫� 宸插~鍒ゅ畾 鈫� 妯℃澘绫诲瀷鍖归厤 鈫� 鏈夊彲鐢ㄦ楠岄」銆�
+3. **鍚庣鍙栨暟骞跺嚭浠�**锛歚MesQcReportApi` 瑁呴厤璐ㄦ鍗曞洓灞傜粨鏋勶紙鍗曞ご / 鍒ゅ畾渚濇嵁 / 鏍峰搧 / 瀹炴祴鍊硷級
+ 鈫� 褰掍竴鎴愭姤鍛婁笂涓嬫枃 鈫� 璧�**鏃㈡湁鐨�** `generate` 娴佺▼锛堢増鏈彂甯冩牎楠屻�佺紪鍙风敓鎴愩�佸揩鐓у喕缁撱�佸垽瀹氬紩鎿庡叏閮ㄧ収鏃э級銆�
+4. **缁撴灉鍥炲埌鍓嶇**锛氬脊绐楀唴灏卞湴灞曠ず缁撴灉锛坄reportNo` / `itemCount` / `undecidableCount` / `warnings` / `errors`锛夛紝
+ 搴曢儴銆屾煡鐪嬫姤鍛婂垪琛ㄣ�嶈烦杞姤鍛婂疄渚嬪垪琛ㄩ〉骞跺甫涓婄瓫閫夋潯浠躲��
+5. **鍙嶆煡**锛氭姤鍛婂疄渚嬪垪琛ㄩ〉鐢� `businessType=mes_qc_iqc` + `businessId=1` 鍗冲彲鏌ュ嚭璇ュ崟鎹嚭杩囩殑鎵�鏈夋姤鍛娿��
+
+**甯﹀叆鍏崇郴瑕佺偣**
+
+- `qcType` + `qcId` 鏄富绾匡紝浠庤川妫�鍗曞垪琛ㄨ甯﹀叆銆俙qcType` 鐢ㄥ瓧鍏� `mes_qc_type` 鐨�**鏁板��**锛坄1`/`2`/`3`/`4`锛夈��
+- `templateId` 鐢辩敤鎴峰湪寮圭獥閲岄�夈��**鍓嶇蹇呴』鍏堟寜 `reportType` 杩囨护妯℃澘鍒楄〃**锛屽惁鍒欑敤鎴蜂細閫夊埌鍚庣蹇呯劧鎷掔粷鐨勭粍鍚堛��
+- `version` 涓嶄紶鏃跺悗绔彇妯℃澘鐨� `currentVersion`锛堣姹傚凡鍙戝竷锛夈�傝璁″櫒鍒氬瓨浜嗚崏绋挎兂绔嬪埢鍑轰欢鎵嶉渶瑕佹樉寮忎紶銆�
+- `reportNo` 涓嶄紶鐢卞悗绔嚜鍔ㄧ敓鎴愶紙`QR + 鏃ユ湡 + 4 浣嶆祦姘碻锛夈��
+- **鍒楄〃 鈫� 鎶ュ憡瀹炰緥鐨勫弽鏌ョ瓫閫夋槸璺敱 query 甯﹀叆**锛氳烦杞椂甯� `businessType`锛堣〃鍚嶏紝濡� `mes_qc_oqc`锛�
+ 涓� `businessId`锛堣川妫�鍗曚富閿殑瀛楃涓插舰寮忥級涓や釜鍙傛暟锛屾姤鍛婂疄渚嬪垪琛ㄩ〉鍦ㄦ寕杞芥椂鎶婂畠浠濉繘鎼滅储琛ㄥ崟锛�
+ 鐢ㄦ埛钀藉湴鍗崇湅鍒板垰鍑虹殑鎶ュ憡锛屼笉闇�瑕佽嚜宸卞啀绛涗竴閬嶃��
+
+## UI 鍏ュ彛锛堝凡钀藉湴锛�
+
+| 浣嶇疆 | 鍏冪礌 | 灞曠ず瑙勫垯 | 璇存槑 |
+|---|---|---|---|
+| 璐ㄦ鍗曞垪琛ㄨ鎿嶄綔 | 銆屽嚭鎶ュ憡銆嶆寜閽� | **浠呭綋 `status === 宸插畬鎴恅 鏃舵樉绀�** | 涓庛�岀紪杈戙�嶃�屽垹闄ゃ�嶏紙浠呰崏绋垮彲瑙侊級浜掓枼锛岄伩鍏嶇敤鎴峰鏈畬鎴愮殑鍗曟嵁鐐� |
+| 寮圭獥鏍囬 | `鍑烘姤鍛� - {鍗曟嵁缂栧彿}` | 鈥� | 缂栧彿鐢卞垪琛ㄨ甯﹀叆锛屼粎鐢ㄤ簬灞曠ず |
+| 寮圭獥閫夋ā鏉垮尯 | 鍗曢�夋ā鏉垮垪琛� | 鐢卞悗绔� `/qc-report/template/selectable` 杩斿洖锛歚reportType` 涓庢湰鍗曠被鍨嬩竴鑷淬�乣status=鍚敤`銆�**`currentVersion` 鎸囧悜鐨勭増鏈浜庛�屽凡鍙戝竷銆嶃�佷笖璇ョ増鏈殑鐢诲竷鏈夊彲娓叉煋鐨勫唴瀹�** | 鏃犲彲閫夐」鏃剁粰绌虹姸鎬佹彁绀猴紝寮曞鍏堝幓妯℃澘璁捐鍣ㄩ厤濂藉苟鍙戝竷 |
+| 寮圭獥缁撴灉鍖� | 鎴愬姛鎻愮ず + 鍛婅鍖� | 鐢熸垚鎴愬姛鍚庡氨鍦板垏鎹紝涓嶅叧寮圭獥 | `undecidableCount > 0` 鐢�**钃濊壊淇℃伅鏉�**锛堜笉鏄粍鑹插憡璀︼級锛氳繖椤规暟閲岀粷澶у鏁版槸銆岃繃绋嬪弬鏁般�嶈繖绫绘甯告儏鍐碉紝鏍囬粍浼氬湪鍑犱箮姣忎唤鎶ュ憡涓婅鎶� |
+| 寮圭獥搴曢儴 | 銆屾煡鐪嬫姤鍛婂垪琛ㄣ�� | 缁撴灉鍖烘墠鍑虹幇 | 鍏冲脊绐楀悗璺虫姤鍛婂疄渚嬪垪琛ㄥ苟甯︿笂 `businessType` + `businessId` |
+
+> **寮圭獥鏍囬涓嶅甫绫诲瀷涓枃鍚�**锛堜粛淇濇寔杩欎釜鍋氭硶锛夛細`mes_qc_rqc` 杩欎竴璺浘鏈夋帾杈炲垎姝р�斺��
+> 鍚庣鏋氫妇銆佽〃娉ㄩ噴銆佽彍鍗曟潈闄愬瓙椤归兘鍐欎綔銆岄��璐ф楠屻�嶏紝鍙湁鑿滃崟鐖堕」涓� `mes_qc_type` 瀛楀吀鍐欎綔銆岄��鏂欐楠屻�嶃��
+> 鐜板凡缁熶竴涓�**銆岄��璐ф楠屻��**锛堢悊鐢憋細RQC 鐨勫璞″悓鏃惰鐩栫敓浜ч��鏂欍�侀攢鍞��璐с�佸敭鍚庨��璐э紝
+> 銆岄��璐ф楠屻�嶆槸鑳借鐩栦笁鑰呯殑璇存硶锛涗笖瀹冩湰灏辨槸澶氭暟娲撅級銆傛爣棰樹粛涓嶅甫绫诲瀷鍚嶏紝灏戜竴澶勯渶瑕佽窡鐫�鍙樼殑鏂囨銆�
+
+## API
+
+| 鏂规硶 | 璺緞 | 璇存槑 | 鏉冮檺鐮� |
+|---|---|---|---|
+| POST | `/qc-report/instance/generate-from-qc` | 鐢辫川妫�鍗曠敓鎴愭姤鍛婏紙鏁版嵁浠� MES 鍙栵級 | `qc-report:instance:generate` |
+| GET | `/qc-report/template/selectable` | 鍙栥�屽彲鐢ㄤ簬鍑轰欢銆嶇殑妯℃澘鍒楄〃 | `qc-report:template:query` |
+
+> `qc-report:instance:generate` 鏄�**鐙珛鏉冮檺鐮�**锛屼笌 `:create`銆乣:query` 閮戒笉閫氱敤銆�
+
+**`GET /qc-report/template/selectable` 璇锋眰鍙傛暟锛�**
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|---|---|---|---|
+| `reportType` | String | 鏄� | 鎶ュ憡绫诲瀷锛屽嵆 `mes_qc_type` 鐨�**鏁板�煎瓧绗︿覆**锛屽 `"1"` / `"4"`銆備紶 `"IQC"` 杩欑被鑻辨枃鍚嶄細涓�涓兘鏌ヤ笉鍒� |
+
+**鍝嶅簲锛�** `Template[]`锛�**鏁扮粍锛屼笉鏄垎椤电粨鏋�**锛夛紝瀛楁涓庢ā鏉垮垎椤垫帴鍙d竴鑷淬��
+
+**涓轰粈涔堝崟寮�杩欎釜鎺ュ彛锛岃�屼笉鏄湪鍓嶇杩囨护妯℃澘鍒嗛〉缁撴灉锛�**
+涓ゆ潯杩囨护鏉′欢閮借惤鍦�**鐗堟湰琛�**涓婏紝鍒嗛〉鎺ュ彛杩斿洖鐨� `currentVersion` 鍙槸妯℃澘琛ㄤ笂鐨勪竴涓瓧绗︿覆锛岀湅涓嶅埌鐗堟湰鐘舵�佷笌鐢诲竷鍐呭銆�
+
+1. **鐗堟湰鏈彂甯�**锛氬仠鐢ㄤ竴涓増鏈�**涓嶄細**娓呯┖妯℃澘鐨� `currentVersion`锛屼簬鏄細鍑虹幇銆宍currentVersion` 鏈夊�笺�佷絾閭d釜鐗堟湰宸插仠鐢ㄣ�嶇殑妯℃澘锛涜繖绉嶆ā鏉块�変腑鍚庡嚭浠跺繀鐒跺け璐ワ紙`1_070_101_003`锛夈��
+2. **鐢诲竷娌℃湁鍙覆鏌撳唴瀹�**锛欸rapesJS 鎶娿�屾墦寮�杩囪璁″櫒浣嗕竴涓粍浠堕兘娌℃斁銆嶇殑椤圭洰瀛樻垚 `{"assets":[],"styles":[]}`鈥斺�斿畠<b>闈炵┖</b>锛屾墍浠ユ棫鍒ゆ嵁浼氭斁瀹冭繃鍘伙紝娓叉煋鏃跺張鍙栦笉鍒版牴缁勪欢銆乥ody 娓叉煋鎴愮┖涓诧紝**涓嶆姤閿�**锛岀敤鎴锋渶缁堟嬁鍒颁竴寮犵櫧绾� PDF銆�
+
+涓ゆ潯閮芥槸銆岀湅璧锋潵鑳介�夈�侀�変簡蹇呭嚭闂銆嶏紝鍒ゆ柇瀹冧滑瑕佽鐗堟湰琛岋紝鏀惧湪鍚庣鍋氭墠鏄崟鐐癸紱
+鍓嶇鎷跨潃鍒嗛〉缁撴灉鑷繁鎺ㄥ浼氬緱鍒般�岀湅璧锋潵瀵逛絾浼氭紡銆嶇殑缁撹銆�
+> 宸茶ˉ鍏� `system_menu`锛歚id=1075416`锛屽悕绉般�屾姤鍛婂疄渚嬭川妫�鍗曞嚭浠躲�嶏紝绫诲瀷 3锛堟寜閽級锛�
+> 鎸傚湪銆屾姤鍛婂疄渚嬨�嶏紙`parent_id=1075410`锛変笅锛宍sort=5`銆傞潪瓒呯瑙掕壊闇�鎺堜簣璇ヨ彍鍗曞悗鎵嶅彲瑙佹寜閽� / 鍙皟鐢ㄦ帴鍙�
+> 锛堣秴绠$敱浠g爜鐩磋繑鍏ㄩ儴鑿滃崟锛屼笉鍙楀奖鍝嶏級銆�
+
+### 璇锋眰鍙傛暟
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|---|---|---|---|
+| `qcType` | Integer | **鏄�** | 璐ㄦ绫诲瀷锛歚1` 鏉ユ枡妫�楠�(IQC) / `2` 杩囩▼妫�楠�(IPQC) / `3` 鍑鸿揣妫�楠�(OQC) / `4` 閫�璐ф楠�(RQC) |
+| `qcId` | Long | **鏄�** | 璐ㄦ鍗曠紪鍙凤紙鍥涘紶琛ㄥ悇鑷殑涓婚敭锛� |
+| `templateId` | Long | **鏄�** | 鎶ュ憡妯℃澘缂栧彿銆�**鍏� `reportType` 蹇呴』涓� `qcType` 涓�鑷�** |
+| `version` | String | 鍚� | 妯℃澘鐗堟湰鍙凤紝濡� `v1.0`銆備笉浼犲垯鍙栨ā鏉跨殑 `currentVersion` |
+| `reportNo` | String | 鍚� | 鎶ュ憡缂栧彿銆備紶浜嗗氨鐢ㄥ畠锛堟挒鍙蜂細鎶ラ敊锛夛紝涓嶄紶鐢卞悗绔嚜鍔ㄧ敓鎴� |
+
+**璇锋眰绀轰緥**
+
+```json
+{
+ "qcType": 1,
+ "qcId": 1,
+ "templateId": 1,
+ "version": "v1.1"
+}
+```
+
+### 鍝嶅簲瀛楁
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|---|---|---|
+| `id` | Long | 鎶ュ憡瀹炰緥缂栧彿锛屾嬁瀹冨幓鏌ヨ鎯� / 璺宠浆 |
+| `reportNo` | String | 鏈�缁堢敓鏁堢殑鎶ュ憡缂栧彿 |
+| `templateVersion` | String | 鏈浣跨敤鐨勬ā鏉跨増鏈彿 |
+| `itemCount` | Integer | 鍐欏叆鎶ュ憡鐨勬楠岄」鏉℃暟 |
+| `undecidableCount` | Integer | **娌℃湁鍒ゅ畾缁撹鐨勯」鏁�**锛堛�屾棤鍒ゅ畾瑙勫垯銆�+ 瑙勫垯鎵ц澶辫触鐨勩�屽緟鍒ゅ畾銆嶏級锛岃銆屼笟鍔¤鍒欍�� |
+| `warnings` | Array\<String\> | 杞彁绀猴細鏍峰搧鐨勫彇鑸嶃�佹病鎴愮粍鐨勫垎缁勯」銆佷负缁勫ご琛ュ嚭鏉ョ殑琛屻�佹寚鏍囧凡鍒犻櫎銆佹湭褰曞叆瀹炴祴鍊� |
+| `errors` | Array\<String\> | 娓叉煋鏈熸暟鎹己鍙o紙涓庨�氱敤鍑轰欢鎺ュ彛鍚屼竴濂楁満鍒讹級 |
+
+**鍝嶅簲绀轰緥**
+
+```json
+{
+ "code": 0,
+ "data": {
+ "id": 38,
+ "reportNo": "QR20260919-0001",
+ "templateVersion": "v1.1",
+ "itemCount": 14,
+ "undecidableCount": 5,
+ "warnings": [
+ "浠ヤ笅 2 涓垎缁勯」鍦ㄦ湰鍗曠殑妫�楠屾槑缁嗛噷娌℃湁鑷繁鐨勮锛堝鍗婃槸妫�楠屾ā鏉垮彧閫変簡瀛愰」锛夛紝鎶ュ憡閲屼负瀹冧滑鍚勮ˉ浜嗕竴琛屾潵鏄剧ず缁勫悕涓庡叕寮忥細銆屾按鍒嗐�侀吀鍚噺銆�",
+ "浠ヤ笅 1 涓寚鏍囨槸鎸囨爣搴撻噷鐨勫垎缁勯」锛屼絾鏈崟娌℃湁灞炰簬瀹冧滑鐨勫瓙椤癸紝鎶ュ憡閲屾寜鐙珛妫�楠岄」鍒楀嚭銆佺粍鍚嶄笉鍚堝苟锛氥�岃壊搴︺��"
+ ],
+ "errors": []
+ }
+}
+```
+
+### 鎶ュ憡涓婁笅鏂囨柊澧炲瓧娈碉紙璁捐鍣ㄥ彲缁戝畾锛�
+
+鍑轰欢鏃跺悗绔啓杩涙姤鍛婄殑姣忎釜妫�楠岄」涓婏紝鏂板浜嗕笅闈� 4 涓瓧娈点�傚畠浠笉鍦ㄨ繖鏉℃帴鍙g殑鍝嶅簲閲岋紝鑰屾槸浣撶幇鍦�**鎶ュ憡涓婁笅鏂�**涓紝
+渚涙ā鏉垮湪璁捐鍣ㄩ噷缁戝畾锛堛�屽垎缁勬楠岄」琛ㄣ�嶇粍浠跺凡鍐呯疆杩欎簺缁戝畾锛屼竴鑸笉闇�瑕佹墜宸ラ厤锛夛細
+
+| 瀛楁 | 绫诲瀷 | 鍙栧�� | 璇存槑 |
+|---|---|---|---|
+| `item.requirement` | String | 缁勫ご琛� = 璇ユ寚鏍囩殑鍏紡锛涘叾浣欒 = 鍗曟嵁涓婄殑鏍囧噯瑕佹眰 | 銆屾娴嬭姹傘�嶅垪銆備笌 `standardValue` 骞跺瓨涓嶅悎骞讹細涓よ�呮潵婧愪笉鍚岋紙涓�涓槸鎸囨爣涓绘暟鎹殑鍏紡锛屼竴涓槸鍗曟嵁琛岀殑鏍囧噯瑕佹眰锛� |
+| `item.group.childName` | String | 缁勫唴瀛愰」 = 鑷繁鐨勫悕瀛楋紱缁勫ご琛屼笌鐙珛椤� = 绌轰覆 | 銆屽瓙椤广�嶅垪 |
+| `item.group.span` | Integer | 缁勫唴绗竴琛� = 璇ョ粍鎬昏鏁帮紱鍚岀粍鍏朵綑琛屼笌鐙珛椤� = `1` | 銆屾楠岄」鐩�嶅垪鐨勫悎骞惰鏁� |
+| `item.group.hidden` | String | 缁勫唴绗竴琛屼笌鐙珛椤� = 绌轰覆锛涘悓缁勫叾浣欒 = `hidden` | `hidden` 灞炴�ч潬銆屽湪涓嶅湪銆嶈捣浣滅敤锛堝啓鎴� `hidden="false"` 鐓ф牱闅愯棌锛夛紝鎵�浠ュ彧鏈夈�岀┖涓� = 杩欎竴鏍煎彲瑙併�嶈繖涓�涓彲鍒ゅ畾鐨勫舰鎬� |
+
+**娌℃湁鍒嗙粍鐨勬姤鍛婁笉浼氬甫 `group`**锛氭暣涓姤鍛婁竴涓垎缁勯兘娌℃湁鏃讹紝`item.group` 杩欎釜閿笉鍑虹幇锛屾ā鏉块噷涔熷氨涓嶄細澶氬嚭涓�灞傜┖鏍煎瓙銆�
+涓�鏃︽姤鍛婇噷鏈夊垎缁勶紝鍒�**姣忎竴椤归兘浼氬甫 `group`**锛堢嫭绔嬮」缁欑┖涓蹭笌 `1`锛夆�斺�� 瀛楁缂哄腑浼氳鍚堝苟灞炴�ц璺宠繃锛屽弽鑰屾妸璇ラ殣钘忕殑鏍煎瓙闇插嚭鏉ャ��
+
+**涓や釜瀛楁蹇呴』鎴愬浣跨敤**锛歚item.group.span` 涓� `item.group.hidden` 鍙綔鐢ㄥ湪銆屾楠岄」鐩�嶈繖涓�鍒椾笂銆�
+涓嶈鎶婂畠浠粦鍒板埆鐨勫垪锛堝銆屾娴嬭姹傘�嶏級锛氱粍鍐呭瓙椤瑰悇鑷殑妫�娴嬭姹傝閫愯鏄剧ず锛屽苟杩涚粍澶存牸浼氭妸瀹冧滑缈绘帀銆�
+
+## 瀛楁灞曠ず瑙勫垯
+
+| 瀛楁 | 灞曠ず浣嶇疆 | 璇存槑 |
+|---|---|---|
+| `undecidableCount` | 鐢熸垚鎴愬姛鍚庣殑鎻愮ず鏉� | **涓嶈褰撴垚鏁呴殰鎶ヨ**銆傚畠鏁扮殑鏄�屾病鏈夌粨璁虹殑椤广�嶏紝鍏朵腑缁濆ぇ澶氭暟鏄�岃繃绋嬪弬鏁般�嶈繖绫绘甯告儏鍐碉紙璇曟牱璐ㄩ噺 m銆佺О閲忕摱 m0 鈥斺�� 鍙緵鍏紡鍙栨暟锛屾湰鏉ュ氨娌℃湁鍙垽瀹氱殑瑙勬牸锛夈�傛彁绀烘枃妗堝缓璁�屾湰娆℃湁 N 椤规病鏈夊垽瀹氱粨璁恒�嶏紱**鑻ョ‘瀹炶鍖哄垎**銆屾甯告棤瑙勫垯銆嶄笌銆岃鍒欐病璺戦�氥�嶏紝璇蜂互鎶ュ憡璇︽儏閲屽悇妫�楠岄」鐨� `resultText` 涓哄噯锛坄鏃犲垽瀹氳鍒檂 / `寰呭垽瀹歚锛夛紝涓嶈鐢ㄨ繖涓�绘暟鍙嶆帹 |
+| `warnings` | 鐢熸垚鎴愬姛鍚庣殑鎻愮ず鏉� | 寤鸿鍙姌鍙狅紱鍐呭宸茬粡鏄畬鏁翠腑鏂囧彞瀛愶紝鐩存帴鍘熸枃灞曠ず鍗冲彲锛屼笉瑕佹敼鍐� |
+| `errors` | 鍚屼笂 | 鏁版嵁缂哄彛锛屼笌閫氱敤鍑轰欢鎺ュ彛鍚屼箟 |
+| `reportNo` | 鎴愬姛鎻愮ず銆佽烦杞悗璇︽儏椤靛ご閮� | **涓氬姟鍞竴閿�**锛屽缓璁甫銆屽鍒剁紪鍙枫�� |
+| `id` | 涓嶅睍绀� | 鐢ㄦ潵璺宠浆 `/qc/report-instance` 璇︽儏 |
+
+## 涓氬姟瑙勫垯璇存槑
+
+| 鍦烘櫙 | 瑙勫垯 |
+|---|---|
+| **璋佹彁渚涙暟鎹�** | 鍚庣銆傚墠绔�**涓嶈**鑷繁鎷� `context` 浼犺繘鏉ワ紝鏈帴鍙d笉鎺ュ彈 `context` 鍙傛暟 |
+| **绫诲瀷涓嶅悎娉�** | `qcType` 涓嶅湪 1~4 鈫� `1_070_105_000`锛屾姤鏂囬噷鍒楀嚭鏀跺埌鐨勫�间笌鍥涗釜鍚堟硶鍊� |
+| **鍗曟嵁涓嶅瓨鍦�** | 鈫� `1_070_105_001`锛屾姤鏂囧甫鍗曟嵁绫诲瀷涓枃鍚嶄笌 ID |
+| **鍗曟嵁鏈畬鎴愭楠�** | 鐘舵�佷笉鏄�屽凡瀹屾垚銆嶁啋 `1_070_105_002`锛屾姤鏂囧甫**褰撳墠鐘舵�佷腑鏂囧悕**锛岀敤鎴蜂竴鐪肩煡閬撳崱鍦ㄥ摢涓�姝� |
+| **鍗曟嵁娌℃湁鍒ゅ畾** | 宸插畬鎴愪絾 `checkResult` 涓虹┖ 鈫� `1_070_105_003`锛屾姤鏂囧垪鍑哄洓涓彲閫夊垽瀹� |
+| **妯℃澘绫诲瀷涓嶇** | 妯℃澘 `reportType` 鈮� `qcType` 鈫� `1_070_105_005`锛屾姤鏂�**鍚屾椂缁欏嚭妯℃澘绫诲瀷涓庡崟鎹被鍨嬩袱杈圭殑涓枃鍚�**銆�**鍓嶇搴斿湪閫夋ā鏉挎椂灏辨妸涓嶇鐨勮繃婊ゆ帀**锛岃繖鏉℃槸鍏滃簳 |
+| **妯℃澘娌¢厤鎶ュ憡绫诲瀷** | 妯℃澘 `report_type` 涓虹┖ 鈫� 鍚屾牱 `1_070_105_005`锛屼絾鎶ユ枃鏀规垚鎻愮ず銆岃鍏堢粰璇ユā鏉胯缃姤鍛婄被鍨嬨�� |
+| **娌℃湁鍙敤妫�楠岄」** | 鈫� `1_070_105_006`锛屾姤鏂囪鏄庡叿浣撳師鍥狅紙濡傘�屽彧鏈夊垎缁勬爣棰樸�嶏級 |
+| **鑳藉嚭澶氫唤鎶ュ憡鍚�** | **鑳�**銆傚悓涓�寮犺川妫�鍗曞彲浠ュ弽澶嶅嚭浠讹紝姣忔鐢熸垚涓�浠界嫭绔嬫姤鍛婏紙鍘嗗彶鐣欑棔闇�瑕侊級銆�**涓嶅仛閲嶅鐢熸垚鎷︽埅**锛屽墠绔篃涓嶅繀鎷� |
+| **妫�楠岄」鎬庝箞鏉ョ殑** | 璐ㄦ鍗曘�屽垽瀹氫緷鎹銆嶏紙`max_threshold`/`min_threshold`/鏍囧噯鍊硷級涓庛�屽疄娴嬪�兼槑缁嗐�嶏紙鎸夋牱鍝� 脳 鎸囨爣锛�**浜ゅ弶**灞曞紑銆�**涓嶅仛浠讳綍鎸囨爣杩囨护**锛屽叏閮ㄨ繘鎶ュ憡 |
+| **澶氫釜鏍峰搧鎬庝箞鍔�** | 鍚屼竴涓紙鏍峰搧 脳 鎸囨爣锛夊睍寮�鎴�**涓�鏉�**鎶ュ憡妫�楠岄」銆傛牱鍝佺紪鍙峰彧鍦�**鏍峰搧鏁� > 1** 鏃舵姌杩涜椤圭殑澶囨敞锛堝銆屾牱鍝� S1銆嶏級锛屽崟涓�鏍峰搧鏃朵笉鍐欙紝閬垮厤姹℃煋 |
+| **鏍峰搧澶鎬庝箞鍔�** | 鏍峰搧鏁拌秴杩� 3 鏃讹紝鎶ュ憡澶寸殑銆屾牱鍝佺紪鍙枫�嶅瓧娈�**鐣欑┖**骞跺彂 `warnings`锛堝垪鍑哄墠 3 涓笌鍓� N 鎬绘暟锛夛紝涓嶆埅鏂槑缁嗘暟鎹� |
+| **鍒嗙粍浼氭�庢牱锛堟湰杞敼鍔級** | 鍒嗙粍椤�**涓嶅啀琚烦杩�**銆傚垎缁勭埗椤癸紙濡傘�屾按鍒嗐�嶏級浣滀负涓�琛岃繘鎶ュ憡锛岀粍鍐呭瓙椤圭揣闅忓叾鍚庯紝缁勫悕鍦ㄦ姤鍛婁笂绾靛悜鍚堝苟 鈥斺�� 鎶ュ憡鑳界湅鍑哄摢浜涘瓙椤瑰睘浜庡摢涓�缁勶紝鐖堕」鐨勫叕寮忎篃涓嶅啀涓� |
+| **缁勫悕涓庡叕寮忔斁鍝�** | 缁勫悕鏀俱�屾楠岄」鐩�嶅垪骞跺悜涓嬪悎骞讹紱鍏紡鏀剧粍澶撮偅涓�琛岀殑銆屾娴嬭姹傘�嶅垪銆�**缁勫唴瀛愰」鍚勮嚜鐨勬娴嬭姹備粛閫愯淇濈暀**锛屼簩鑰呬笉浜掔浉瑕嗙洊 |
+| **璋佹槸缁勫ご** | 鍚庣鎸夋寚鏍囩殑 `parent_id` 鍒ゅ綊灞烇紙涓嶇湅琛屽簭銆佷笉鐪嬫暟鍊肩被鍨嬶級锛屽苟缁欐瘡琛屼笅鍙� `group.span`锛堝悎骞跺嚑琛岋級涓� `group.hidden`锛堣繖涓�鏍艰涓嶈璁╀綅锛夈�傚墠绔�**涓嶉渶瑕佷篃涓嶄細**鑷繁绠楀悎骞惰鏁� |
+| **鍒嗙粍椤规湰鍗曟病鏈夊瓙椤�** | 鎸夌嫭绔嬫楠岄」鍒楀嚭銆佺粍鍚嶄笉鍚堝苟锛屽苟鎶婂悕瀛楁敹杩� `warnings`锛堛�屸�︽槸鎸囨爣搴撻噷鐨勫垎缁勯」锛屼絾鏈崟娌℃湁灞炰簬瀹冧滑鐨勫瓙椤光�︺�嶏級 |
+| **缁勫ご鏈崟娌℃湁琛�** | 鑻ユ楠屾ā鏉垮彧鍕句簡瀛愰」锛屽悗绔�**涓虹粍澶磋ˉ涓�琛�**鏉ユ斁缁勫悕涓庡叕寮忥紝骞跺湪 `warnings` 閲岃鏄庝负鍝嚑涓粍澶磋ˉ浜嗚銆傝ˉ鍑烘潵鐨勮瀹炴祴鍊间负绌猴紝鍒ゅ畾涓恒�屾棤鍒ゅ畾瑙勫垯銆嶏紝涓嶅奖鍝嶅悎鏍肩巼涓庣粨璁� |
+| **鎸囨爣琚垹浜嗕細鎬庢牱** | 鍗曟嵁琛屽紩鐢ㄤ簡涓�涓凡琚垹闄ょ殑鎸囨爣 鈫� 璇ユ潯璺宠繃锛宍warnings` 閲屾姤銆屾湁 N 鏉℃槑缁嗘墍寮曠敤鐨勬楠屾寚鏍囧凡琚垹闄ゃ�� |
+| **娌″綍瀹炴祴鍊间細鎬庢牱** | 璇ラ」鐓у父杩涙姤鍛婏紝浣� `warnings` 鎻愮ず銆岀 N 椤广�孹銆嶅皻鏈綍鍏ュ疄娴嬪�笺�嶏紱**缁勫ご鐨勯敋鐐硅闄ゅ**锛堝畠鎸夊畾涔夋病鏈夊疄娴嬪�硷紝鍊奸兘鍦ㄥ瓙椤硅涓婏紝鎶ュ嚭鏉ユ槸璇姤锛� |
+| **鎶ュ憡琛屽簭鍙樹簡** | 浠庢鍓嶇殑銆岃琛ㄩ『搴忋�嶆敼涓烘寜鎸囨爣鐨� `sort_order` 鍗囧簭锛堢己澶辨帓鏈�鍚庯紝鍚屽�间繚鎸佽搴忥級锛岀粍鍐呭瓙椤规寜鍚勮嚜鐨� `sort_order`銆傝繖鏍锋姤鍛婇『搴忎笌妫�楠屽崟鐨勮璁℃剰鍥句竴鑷达紱榛樿涓嶉渶瑕佸墠绔仛浠讳綍浜� |
+| **鍝紶鐢诲竷缁勪欢鑳芥覆鏌撳垎缁�** | 闇�瑕佹ā鏉块噷鐢�**銆屽垎缁勬楠岄」琛ㄣ�嶏紙`GroupedQualityTable`锛�**銆傜敤瀹冧箣澶栫殑琛紙濡傚熀纭�銆屾楠岄」琛ㄦ牸銆嶏級涓嶄細鍑虹幇鍚堝苟鏁堟灉 鈥斺�� 鏁版嵁鐓у父涓嬪彂锛屽彧鏄ā鏉挎病鐢汇�備簩鑰呯敤鍏朵竴锛氭湁鍒嗙粍鐢ㄥ墠鑰咃紝绾钩灞傜敤鍚庤�� |
+| **鍒ゅ畾璋佺畻** | 鎶ュ憡绾х殑 `result`/`resultText`/`conclusion`/`passRate` 鐢�**鍚庣鍒ゅ畾寮曟搸**绠楋紙閫愰」瑙勫垯 鈫� 瑙勬牸涓婁笅闄� 鈫� 鏁版嵁鑷甫缁撴灉锛夛紝涓庨�氱敤鍑轰欢涓�鑷� |
+| **璐ㄦ鍗曠殑鍘熷垽瀹氬幓鍝簡** | 瀛樿繘鎶ュ憡鐨� `report.qcResult` / `report.qcResultText` 涓や釜**鏂板瓧娈�**锛屼笌寮曟搸鍒ゅ畾**骞跺瓨銆佷簰涓嶈鐩�**銆傝川妫�鍗曚笂鐨勫垽瀹氭槸浜哄伐鎷嶇殑鏉匡紙鍚堟牸/鐗归噰/涓嶅悎鏍奸��璐�/涓嶅悎鏍兼姤搴燂級锛屽紩鎿庡彧鏈変笁鎬佽涓嶄笅瀹冿紝鎵�浠ュ垎寮�瀛� |
+| **`undecidableCount` 鎬庝箞绠�** | 鏁般�屽揩鐓ч噷 `result` 涓虹┖涓茬殑椤广�嶃�傝繖姝f槸寮曟搸瀵广�屽緟鍒ゅ畾銆嶇殑瀹氫箟锛屼篃椤哄甫鎶娿�屽崱鍦ㄨ鍒欐姤閿欎笂銆嶇殑椤圭畻杩涘幓锛屼笉鍙︾畻涓�閬嶅垽瀹氭潯浠� |
+| **鍘熷垽瀹氭槸鏁板瓧** | `qcResult` 鏄暟瀛楀瓧绗︿覆锛坄"1"`~`"4"`锛夛紝`qcResultText` 鎵嶆槸涓枃锛堝悎鏍�/鐗归噰/涓嶅悎鏍奸��璐�/涓嶅悎鏍兼姤搴燂級銆�**鐢诲竷涓婃樉绀� `qcResultText`** |
+| **妯℃澘蹇呴』宸插彂甯�** | 涓庨�氱敤鍑轰欢涓�鑷达紝鑽夌鐗堟湰浼氳鎷掞紙`1_070_101_003`锛夈�傚鐢ㄦ棦鏈夐敊璇爜锛屾湰鎺ュ彛涓嶅彟閫� |
+| **妯℃澘宸插仠鐢�** | 澶嶇敤 `1_070_100_002` |
+| **鎶ュ憡缂栧彿鎾炲彿** | 澶嶇敤 `1_070_102_001`銆傚凡杞垹闄ょ殑缂栧彿**涓嶅洖鏀�** |
+| **鏁版嵁蹇収鍐荤粨** | 鍑轰欢鏃舵妸鍒ゅ畾鍚庣殑鏁版嵁鏁翠唤鍐荤粨銆侻ES 閲岀殑鍗曟嵁鍚庢潵鎬庝箞鏀癸紝**閮戒笉褰卞搷杩欎唤鍘嗗彶鎶ュ憡** |
+
+## 娉ㄦ剰浜嬮」
+
+- **`engine/context.ts` 鐨� `qcResult` / `qcResultText` 宸茶ˉ榻�**锛堢被鍨嬫帴鍙� + `emptyReport()` 绌轰覆榛樿鍊硷級锛�
+ 璁捐鍣ㄧ殑缁戝畾闈㈡澘閲岀幇鍦ㄥ彲浠ラ�夊埌杩欎袱涓瓧娈碉紝鐢诲竷涓婁篃鑳界粦銆傝嫢瑕佺敤瀹冧滑锛屾ā鏉块渶鑷缁戝埌鏌愪釜鏂囨湰缁勪欢涓娿��
+- **妯℃澘鍒楄〃瑕佹寜 `reportType` 杩囨护**锛氭ā鏉跨殑 `report_type` 瀛樼殑鏄瓧鍏告暟鍊煎瓧绗︿覆锛坄"1"`/`"2"`/`"3"`/`"4"`锛夛紝
+ 涓� `qcType` **鐩存帴鐩哥瓑姣旇緝**鍗冲彲锛屼笉瑕佹嬁 `"IQC"` 杩欑被鑻辨枃鍚嶅幓姣斻��
+- **`qcType` 浼犳暟鍊间笉浼犲瓧绗︿覆鍚�**锛氬悗绔寜 `1`~`4` 璇嗗埆锛屼紶 `"IQC"` 浼氬緱鍒� `1_070_105_000`銆�
+- **涓嶈缂撳瓨 `warnings`**锛氬畠鍙湪鏈鍝嶅簲閲屽嚭鐜帮紝**涓嶈惤搴�**銆備簨鍚庡洖鐪嬪巻鍙叉姤鍛婃椂鐪嬩笉鍒板綋鏃舵湁鍝簺鎻愮ず銆�
+ 闇�瑕佺暀鐥曡鍦ㄥ嚭浠舵垚鍔熸椂鑷繁璁颁竴浠姐��
+- **`warnings` 涓� `errors` 鍒嗗伐**锛歚warnings` 鏄�屾暟鎹彇鑸嶇殑杞彁绀恒�嶏紙璺宠繃銆佹埅鏂�佺己鍊硷級锛�
+ `errors` 鏄�屾ā鏉跨粦瀹氫簡浣嗘病鏁版嵁鐨勫瓧娈点�嶈繖绫绘覆鏌撴湡缂哄彛銆�**涓よ�呴兘瑕佸睍绀�**锛屼笉瑕佸彧鏄剧ず鍏朵腑涓�涓��
+- **`itemCount` 涓嶇瓑浜庤川妫�鍗曠殑琛屾暟**锛氭寚鏍囪鍒犱細琚烦杩囥�佷竴涓寚鏍囧鏉″疄娴嬪�间細灞曞紑鎴愬鏉°��
+ 缁勫ご鍦ㄦ湰鍗曟病鏈夎鏃跺悗绔細琛ヤ竴琛岋紝鎵�浠ヨ繖涓暟**鍙兘鐢ㄦ潵灞曠ず**锛屼笉瑕佹嬁瀹冨幓鍜岃川妫�鍗曡鏁板仛鏂█銆�
+- **閮ㄥ垎瀛楁鍒绘剰涓嶅甫杩囧幓**锛歁ES 渚ф楠岄」涓婄殑銆屾楠屾柟娉曘�嶏紙`checkMethod`锛変笌銆屾楠屽伐鍏枫�嶏紙`tool`锛�
+ 鍦ㄦ姤鍛婁笂涓嬫枃閲�**娌℃湁鎵胯浇浣�**锛屾湰杞湭浼犻�掋�傝嫢鎶ュ憡瑕佸睍绀鸿繖涓ゅ垪锛岄渶瑕佸厛鎵� `InspectionItem` 濂戠害
+ 锛堥偅鏄敼鍔ㄥ墠绔彲瑙佺殑鏁版嵁濂戠害锛岄渶鍗曠嫭纭鍚庡啀鍋氾級銆�
+- **璐ㄦ鍗曚笂娌℃湁銆岄儴闂ㄣ��**锛氭姤鍛婄殑 `department` 瀛楁鎭掍负绌猴紝涓嶈鎷垮埆鐨勫瓧娈电‖鍑戙��
+- **鎵规鍙峰彇鍝釜瀛楁鎸夌被鍨嬩笉鍚�**锛氭潵鏂欐楠屽彇渚涘簲鍟嗘壒鍙凤紝鍑鸿揣/閫�璐у彇鎵规鍙凤紝杩囩▼妫�楠屼袱鑰呴兘娌℃湁锛堝彧鏈夊伐鍗曞彿锛夈�傝繖鏄悗绔寜涓氬姟璇箟瀹氱殑锛屽墠绔笉鐢ㄧ銆�
+- **鎶ュ憡瀹炰緥钀藉簱鏃� `businessType` 鏄〃鍚�**锛坄mes_qc_iqc` / `mes_qc_ipqc` / `mes_qc_oqc` / `mes_qc_rqc`锛夛紝
+ 涓庡墠绔矾鐢�/瀛楀吀閲岀殑鑻辨枃鏋氫妇鍚屽悕浣嗕笌瀛楀吀鏁板�间笉鍚岋紝鍙嶆煡鏃�**鐩存帴鐢ㄨ繖鍥涗釜瀛楃涓�**銆�
+- **澶辫触鏃朵笉瑕侀噸璇曞嚭浠�**锛氫簲閬撴牎楠屽け璐ラ兘鏄�屾暟鎹垨閫夋嫨涓嶅銆嶏紝閲嶈瘯鍚屾牱浼氬け璐ャ�傛寜鎶ユ枃鎻愮ず鍘绘敼鏁版嵁鎴栨崲妯℃澘銆�
+- **澶辫触鎶ユ枃鐢辫姹傛嫤鎴櫒鑷姩寮瑰嚭锛屼笟鍔′唬鐮佷笉瑕佸啀寮逛竴娆�**锛歚code != 0` 鏃舵嫤鎴櫒宸叉妸鍚庣 `message`
+ 鏄剧ず鎴� toast锛岃皟鐢ㄥ鍙啓 `catch {}` 鍗冲彲锛岄噸澶嶆彁绀轰細璁╃敤鎴风湅鍒颁袱鏉′竴鏍风殑鎶ラ敊銆�
+- **鏉冮檺**锛氭湰鎺ュ彛鏉冮檺鐮� `qc-report:instance:generate`锛屽凡琛ュ叆 `system_menu`锛坄id=1075416`锛夈��
+
+## 閿欒鐮�
+
+### 鏈帴鍙f柊澧烇紙`1_070_105_xxx`锛�
+
+| 閿欒鐮� | 鎶ユ枃 | 瑙﹀彂鍦烘櫙 |
+|---|---|---|
+| `1_070_105_000` | 璐ㄦ绫诲瀷銆�9銆嶄笉鍚堟硶锛屽彧鏀寔 IQC锛堟潵鏂欐楠岋級銆両PQC锛堣繃绋嬫楠岋級銆丱QC锛堝嚭璐ф楠岋級銆丷QC锛堥��璐ф楠岋級 | `qcType` 涓嶅湪 1~4 |
+| `1_070_105_001` | 鏉ユ枡妫�楠岀殑璐ㄦ鍗曪紙ID=999999锛変笉瀛樺湪鎴栧凡琚垹闄わ紝璇峰埛鏂板垪琛ㄥ悗閲嶆柊閫夋嫨 | `qcId` 鏌ヤ笉鍒� |
+| `1_070_105_002` | 鏉ユ枡妫�楠岀殑璐ㄦ鍗曘�孖QC20260919001銆嶅綋鍓嶇姸鎬佷负銆岃崏绋裤�嶏紝灏氭湭瀹屾垚妫�楠岋紝涓嶈兘鐢熸垚鎶ュ憡銆傝鍏堟妸璇ュ崟鎹彁浜ゅ苟瀹屾垚妫�楠屽垽瀹氬悗鍐嶇敓鎴� | 鍗曟嵁鐘舵�侀潪銆屽凡瀹屾垚銆� |
+| `1_070_105_003` | 鏉ユ枡妫�楠岀殑璐ㄦ鍗曘�孖QC20260919001銆嶅皻鏈~鍐欐楠屽垽瀹氾紙鍒ゅ畾涓虹┖锛夛紝涓嶈兘鐢熸垚鎶ュ憡銆傝鍏堝湪璇ュ崟鎹笂濉啓鍒ゅ畾缁撹锛堝悎鏍� / 鐗归噰 / 涓嶅悎鏍奸��璐� / 涓嶅悎鏍兼姤搴燂級鍚庡啀鐢熸垚 | 宸插畬鎴愪絾 `checkResult` 绌� |
+| `1_070_105_005` | 鎶ュ憡妯℃澘鐨勬姤鍛婄被鍨嬫槸銆屽嚭璐ф楠屻�嶏紝涓庢湰娆¤川妫�鍗曠殑绫诲瀷銆屾潵鏂欐楠屻�嶄笉涓�鑷达紝鏃犳硶鐢熸垚鎶ュ憡銆傝閲嶆柊閫夋嫨涓�寮犳潵鏂欐楠岀殑鎶ュ憡妯℃澘 | 妯℃澘涓庡崟鎹被鍨嬩笉绗︼紙鎴栨ā鏉挎湭閰嶇被鍨嬶級 |
+| `1_070_105_006` | 鏉ユ枡妫�楠岀殑璐ㄦ鍗曘�孖QC20260919001銆嶏紙ID=1锛夋病鏈変换浣曟楠屾寚鏍囷紝鏃犳硶鐢熸垚鎶ュ憡銆傝鍏堝湪璇ュ崟鎹笂褰曞叆妫�楠屾寚鏍囦笌瀹炴祴鍊煎悗鍐嶇敓鎴� | 鍗曟嵁娌℃湁浠讳綍妫�楠屾寚鏍囪銆傝嫢鍏朵腑閮ㄥ垎鏄庣粏寮曠敤鐨勬寚鏍囧凡琚垹闄わ紝鎶ユ枃浼氬湪鎷彿閲岃ˉ涓�鍙ャ�屽叾涓� N 鏉℃槑缁嗘墍寮曠敤鐨勬楠屾寚鏍囧凡琚垹闄ゃ�� |
+
+### 澶嶇敤鏃㈡湁閿欒鐮侊紙鏈帴鍙d笉鍙﹂�犲壇鏈級
+
+| 閿欒鐮� | 鎶ユ枃 | 瑙﹀彂鍦烘櫙 |
+|---|---|---|
+| `1_070_100_000` | 妯℃澘涓嶅瓨鍦� | `templateId` 鎵句笉鍒� |
+| `1_070_100_002` | 璇ユā鏉垮凡鍋滅敤锛屼笉鑳界敓鎴愭姤鍛� | 妯℃澘 `status=1` |
+| `1_070_101_000` | 妯℃澘鐗堟湰涓嶅瓨鍦� | `version` 浼犱簡浣嗘煡涓嶅埌 |
+| `1_070_101_003` | 璇ユā鏉跨増鏈湭鍙戝竷 | `version` 鎸囧悜鑽夌 |
+| `1_070_101_007` | 璇ユā鏉胯繕娌℃湁宸插彂甯冪殑鐗堟湰锛屾棤娉曠敓鎴愭姤鍛婏紝璇峰厛鍦ㄨ璁″櫒涓彂甯冧竴涓増鏈� | 涓嶄紶 `version` 涓� `currentVersion` 涓虹┖ |
+| `1_070_101_008` | 璇ユā鏉跨増鏈病鏈夌敾甯冨唴瀹癸紝鏃犳硶鐢熸垚鎶ュ憡锛岃鍏堝湪璁捐鍣ㄤ腑璁捐骞朵繚瀛樻ā鏉垮唴瀹� | 鐗堟湰鏈夎褰曚絾鐢诲竷绌� |
+| `1_070_102_001` | 鎶ュ憡缂栧彿銆孹銆嶅凡琚崰鐢紝璇锋崲涓�涓紪鍙凤紝鎴栫暀绌虹敱绯荤粺鎸� QR+鏃ユ湡+娴佹按 鑷姩鐢熸垚 | 鎸囧畾浜嗛噸澶嶇紪鍙� |
+
+> **涓庡師濮嬫柟妗堟枃妗g殑鍋忕锛堝凡钀藉湴鍙e緞锛�**锛氭柟妗堟枃妗� 搂7 閲屽垪鐨� `105_004`锛堟ā鏉夸笉瀛樺湪锛変笌 `105_007`锛堟ā鏉挎棤宸插彂甯冪増鏈級
+> **鏈疄鐜�**锛屾敼涓哄鐢ㄤ笂闈㈢殑鏃㈡湁鐮併�傜悊鐢憋細閭e嚑鏉℃枃妗堟湰鏉ュ氨鏄簿纭殑锛屽啀閫犱竴閬嶅彧浼氬涓ゆ潯浼氭紓绉荤殑鍓湰銆�
diff --git a/docs/qc_report_grouped_inspection_design.md b/docs/qc_report_grouped_inspection_design.md
new file mode 100644
index 0000000..3eef7a9
--- /dev/null
+++ b/docs/qc_report_grouped_inspection_design.md
@@ -0,0 +1,187 @@
+# 澶嶆潅妫�楠岄」锛堝垎缁勬楠岄」锛夎繕鍘� 鈥� 闇�姹備笌鏂规
+
+> 鐘舵�侊細**宸插畾绋匡紝寮�宸�**銆傚绾︿笌缁撴瀯瑙佺鍥涜妭锛屽疄鐜版竻鍗曡绗簲鑺傘��
+> 鍏宠仈锛歚docs/qc_report_ai_import_frontend_integration.md`锛圓I 瀵煎叆鑱旇皟锛夈�乣docs/鏅鸿兘璐ㄦ鎶ュ憡骞冲彴-寮�鍙戣繘搴�.md`锛堣繘搴︾暀鐥曪級銆�
+>
+> 鍙樻洿璁板綍锛�2026-09-19锛夛細鐢ㄩ」鐩嚜甯︾殑 `grapesjs@0.23.6` + Chromium 瀹炴祴鍚庯紝**鎺ㄧ炕浜嗗垵绋裤�岀敤缁戝畾鏍峰紡闅愯棌閲嶅鍗曞厓鏍笺�嶇殑鍐欐硶**锛堝疄娴嬩笉鍙锛岃绗笁鑺傘�岄殣钘忛�氶亾銆嶏級锛屾敼涓� `hidden` 灞炴�э紱鍚屾椂鎶婄敤鎴峰凡鎷嶆澘鐨勪袱鏉″彛寰勶紙鏃犲垽瀹氳鍒欍�佸叕寮忚惤鏍硷級涓庡師濮� docx 鐨勫疄娴嬬粨鏋勫啓杩涘绾︺��
+
+## 涓�銆佽儗鏅笌鐩爣
+
+鍘熷瀷鏉ヨ嚜 `鐧句簨妯$増.docx`锛氭楠岄」鏄�**涓ゅ眰**鐨� 鈥斺�� 涓�涓垎缁勶紙姘村垎 / 閰稿惈閲� / 姝d竵閱囧惈閲忥級锛岀粍鍐呮寕鑻ュ共瀛愰」锛堣繃绋嬪弬鏁� + 缁撴灉锛夈�傝繖绉嶇粨鏋勭洰鍓嶆棤娉曡繕鍘燂紝鎶ュ憡閲岃〃鐜颁负銆屼竴鍫嗘暎瑁呭弬鏁拌锛岀湅涓嶅嚭灞炰簬鍝竴缁勶紝鍏紡涔熶涪浜嗐�嶃��
+
+瀹炴祴 `鐧句簨妯$増.docx` 鐨勬楠岀粨鏋滆〃锛坄word/document.xml`锛�27 琛岋級锛�**椤圭洰鍒楃敤 `w:vMerge` 绾靛悜鍚堝苟**璺ㄤ綇鏁寸粍鐨勮锛屽瓙椤瑰崟鐙崰涓�鍒楋紝鍏朵綑鍒楋紙妫�娴嬫柟娉�/鏍囧噯瑕佹眰/缁撴灉锛夐�愯鐙珛銆傚嵆銆岀粍鍚嶅悎骞躲�佸瓙椤瑰垎琛屻�嶆槸杩欎唤鎶ュ憡鐨勫師鐢熺増寮� 鈥斺�� 鏈柟妗堣杩樺師鐨勫氨鏄畠銆�
+
+**宸叉媿鏉跨殑涓氬姟鍙e緞**锛堢敤鎴风‘璁わ級锛�
+
+| 鍐呭 | 鍙e緞 |
+|---|---|
+| 鐖堕」锛堝垎缁勶級鐨勩�屾娴嬭姹傘�嶉偅涓�鏍� | 鏄剧ず `mes_qc_indicator.formula_text` 鍏紡 |
+| 缁勫唴瀛愰」锛屽銆屾按鍒嗙粨鏋� w銆嶃�岄吀鍚噺缁撴灉 w3銆� | 鎸夋湰韬粨鏋勬樉绀猴紝涓嶅仛鐗规畩澶勭悊 |
+| 娌℃湁瑙勬牸涓婁笅闄愮殑椤� | 鍒ゅ畾鍒楁樉绀恒�屾棤鍒ゅ畾瑙勫垯銆嶏紝**涓嶈鍏ュ悎鏍肩巼鍒嗘瘝銆佷笉鍙備笌鎶ュ憡缁撹**锛堝凡浜庝笂涓�杞疄鐜帮紝瑙� `docs/鏅鸿兘璐ㄦ鎶ュ憡骞冲彴-寮�鍙戣繘搴�.md`锛� |
+
+## 浜屻�佹柇灞傦細灞傜骇瀛樺湪浜庢暟鎹簱锛屼絾鏈変笁澶勮鍒囨柇
+
+瀹炴祴 `mes_qc_indicator`锛堝涓� `2a8dea946ada`锛夛細
+
+| id | name | item_type | parent_id | result_type | formula_text | sort_order |
+|---|---|---|---|---|---|---|
+| 21 | 姘村垎 | 2 | 0 | NULL | `w = (m1 - m0) / m 脳 100%` | 30 |
+| 22鈥�25 | 璇曟牱璐ㄩ噺 m / 璇曟牱+绉伴噺鐡� m1 / 绉伴噺鐡� m0 / 姘村垎缁撴灉 w | 1 | 21 | 1 | 鈥� | 1鈥�4 |
+| 26 | 閰稿惈閲� | 2 | 0 | NULL | `w3 = c 脳 V 脳 0.06005 / m 脳 100%` | 40 |
+| 27鈥�30 | 鏍囨恫娴撳害 c / 娑堣�楁淮瀹氭恫浣撶Н V / 璇曟牱璐ㄩ噺 m / 閰稿惈閲忕粨鏋� w3 | 1 | 26 | 1 | 鈥� | 1鈥�4 |
+| 31 | 姝d竵閱囧惈閲� | 2 | 0 | NULL | `绾害 = 100% - 姘村垎 - 閰稿惈閲� - 鍏跺畠鏉傝川` | 50 |
+| 32 | 姝d竵閱囧惈閲� /% | 1 | 31 | 1 | 鈥� | 1 |
+| 19/20/33/34 | 澶栬 / 鑹插害 / 瀵嗗害 / 鎶樺厜鐜� | 1 | 0 | 3/1 | 鈥� | 10/20/60/70 |
+
+**褰掑睘渚濇嵁鏄� `parent_id`锛屼笉鏄搴�**锛歚item_type=2` 鏄垎缁勫ご锛屽瓙椤� `sort_order` 鎸夌粍鍐呴噸鏂颁粠 1 鎺掞紱鑰�**琛岃〃閲岀埗椤归偅涓�琛屼笌瀹冪殑瀛愰」骞朵笉鐩搁偦**锛坕qc_id=1 閲� 姘村垎 鍦ㄧ 1 琛岋紝瀹冪殑瀛愰」鍦ㄧ 11鈥�14 琛岋級銆�
+
+闄勫甫瀹炴祴锛堝悓涓�娆℃煡璇級锛氳鍗�**鎵�鏈夎**鐨� `standard_value` / `max_threshold` / `min_threshold` / `check_method` **鍏ㄤ负 NULL** 鈥斺�� 杩囩▼鍙傛暟娌℃湁瑙勬牸锛岀粍澶存洿鏄彧鏈夊叕寮忋�傝繖鏉″喅瀹氫簡銆屾娴嬭姹傚垪鏀惧叕寮忋�嶄笉浼氳鐩栨帀浠讳綍宸叉湁鍐呭銆�
+
+涓夊鏂眰锛�
+
+1. `MesQcIndicatorDO` 鍙槧灏� `id/code/name/type/tool/resultType/resultSpecification/remark` 鈥斺�� `parent_id`銆乣item_type`銆乣formula_text`銆乣unit_text`銆乣sort_order` 涓�涓兘娌℃槧灏勶紝灞傜骇鍒� DO 灏变涪銆�
+2. `MesQcReportItemRespDTO` 娌℃湁浠讳綍鐖�/缁勫瓧娈碉紝绫绘敞閲婃槑鍐欍�屾姤鍛婁晶涓嶉渶瑕佺煡閬撴牱鍝佷笌瀹炴祴鍊肩殑灞傜骇鍏崇郴锛岄�愯娓叉煋鍗冲彲銆嶃��
+3. `MesQcReportApiImpl.buildItems` 鐢� `indicator.getResultType() == null` 褰撱�岃繖鏄垎缁勬爣棰樸�嶇殑鍒ゆ嵁锛屾妸鐖堕」涓㈣繘 `groupItemNames` 璧� warnings 鑰屼笉鏄叆鎶ュ憡銆�**鏂瑰悜鏄弽鐨�**锛氳涓㈡帀鐨勬伆濂芥槸甯﹀叕寮忕殑缁勫悕锛堟按鍒�/閰稿惈閲�/姝d竵閱囧惈閲忥級锛岀暀涓嬫潵鐨勬伆濂芥槸杩囩▼鍙傛暟琛屻��
+
+## 涓夈�佸紩鎿庤兘琛ㄨ揪浠�涔堬細鎺㈤拡瀹炴祴缁撹
+
+鑴氭湰 `.qc-conformance/verify-group-repeat.ts`锛堝彧璇伙紝涓嶆敼浠g爜涓嶅姩搴擄級锛屼骇鐗� `group-probe-p4.html`銆乣group-probe-p5.html`銆�
+
+**鍏堝喅绾︽潫**锛堣 `report-evaluator.ts:237` + `ReportContext.itemMap` 寰楀埌锛夛細鍒ゅ畾闃舵鎶婁笂涓嬫枃閲嶅缓鎴� `{ report, inspectionItems }` **涓や釜閿�**锛屼袱渚т竴鑷存敹鍙c�備换浣曡嚜瀹氫箟椤跺眰鏁扮粍锛坄inspectionGroups` 涔嬬被锛夐兘杩涗笉浜嗘覆鏌撲綔鐢ㄥ煙 鈥斺�� 鎺㈤拡 P3 瀹炴祴娓叉煋鍑� 0 琛岋紝涓斾笉鎶ラ敊銆�**鍒嗙粍淇℃伅鍙兘鎸傚湪姣忎釜妫�楠岄」涓娿��**
+
+| 缁撴瀯 | 缁撴灉 |
+|---|---|
+| P1 鎵佸钩浜ら敊锛堢粍澶磋涓庢槑缁嗚鍚屼竴濂楀崟鍏冩牸锛屾棤 rowspan锛� | 鍙敤锛涗絾缁勫ご琛屽繀椤绘槸鏁扮粍閲岀殑涓�椤� 鈫� **姹℃煋 total / passCount** |
+| P2 姣忚棣栧垪閮藉啓 `rowspan` | 娓叉煋鍑� `rowspan="5"`銆乣rowspan="1"`锛屼絾姣忚閮借嚜甯﹂鍒� 鈫� 鍒楅敊浣嶏紝**涓嶅悎骞朵笖鏇寸碂** |
+| P3 椤跺眰鑷畾涔夋暟缁� | 娓叉煋 0 琛岋紙涓婁笅鏂囪鏀跺彛锛岄潤榛樹涪寮冿級 |
+| P4 宓屽 repeat锛堝灞傛寜缁勩�乣tbody` 鍐呭啀鎸� `children`锛� | 鍙敤锛宍rowspan` 缁戝畾鐢熸晥銆侀『搴忔纭紱浣嗙粍蹇呴』浣滀负涓�椤硅繘鏁扮粍 鈫� 鍚屾牱姹℃煋缁熻锛涗笖闇�瑕� `tbody` 濂� `tbody` |
+| **P5 鎵佸钩 + rowspan + 闅愯棌閲嶅鍗曞厓鏍�** | **鍙敤锛岄噰鐢�** |
+
+**P5 瀹炴祴**锛堟祻瑙堝櫒锛宍border-collapse: collapse`锛夛細
+
+- 棣栬涓ゆ牸 `<td rowspan="4">姘村垎</td><td rowspan="4">w = 鈥�</td>`锛岄珮搴� = 4 琛屼箣鍜岋紝鍚堝苟鎴愮珛锛�
+- 缁勫唴绗� 2鈥�4 琛屽悓涓ゆ牸琚� `display:none` 鍓旈櫎鍚庯紝杩欎簺琛岀殑鍙鍗曞厓鏍� `left` 涓庤〃澶寸 3鈥�7 鍒�**閫愬垪鐩哥瓑** 鈫� 鍒楀榻愭棤鎹熴��
+
+鎺㈤拡褰撴椂骞朵簡**涓�**鏍硷紙缁勫悕 + 鍏紡锛夛紱鏈�缁堢粨鏋勫彧骞剁粍鍚嶄竴鏍硷紙瑙� 搂4.1 鐨勫彛寰勮鏄庯級锛屾槸鎺㈤拡缁撹鐨勭湡瀛愰泦 鈥斺�� 鏈哄埗鐩稿悓锛屽彧鏄皯骞朵竴鏍硷紝绗� 4 鍒楃収甯搁�愯鍙栧�笺��
+
+### 闅愯棌閫氶亾锛氬垵绋跨殑鍐欐硶涓嶅彲琛岋紙2026-09-19 淇锛�
+
+鍒濈鍐欍�宍group.hidden` 鐢ㄥ竷灏旓紝`buildContent` 閲屽啀鎶婂畠鎶樻垚 `display:none`銆嶃�傝繖**鍋氫笉鍒�**锛屾湁涓ゅ纭啿绐侊細
+
+- `binding.ts:4` 鏄庡啓銆屽彧鍋氬彇鍊间笌鏇挎崲锛屼笉鍋氫换浣曡〃杈惧紡姹傚�笺�嶏紝`{{...}}` 鍙栧埌鐨勬槸瀛楅潰閲忥紝涓嶅彲鑳藉彉鎴� CSS锛�
+- `buildContent` 鏄�**璁捐鏈熼潤鎬�**鐨勶紝瀹冩嬁涓嶅埌杩愯鏈熺殑琛屾暟鎹紝鏇磋皥涓嶄笂鎸夎鎶樻牱寮忋��
+
+浜庢槸鏀规垚銆屾妸闅愯棌鍊间氦缁欐暟鎹晶銆嶃�備笁鏉¢�氶亾瀹炴祴锛堣剼鏈蛋鐪熷疄 `grapesjs.init` 鈫� `getWrapper().append()` 鈫� `getProjectData()` 鈫� `loadProjectData()`锛屽嵆璁捐鍣ㄧ殑鐪熷疄搴忓垪鍖栬矾寰勶級锛�
+
+| 閫氶亾 | GrapesJS 瑙f瀽鎴� | `getHtml()` | 椤圭洰鏁版嵁寰�杩� | 鑳芥寜琛屽彉 |
+|---|---|---|---|---|
+| 鍐呭閲屽啓 `style="{{璺緞}}"` | 鍙繚鐣欓潤鎬� CSS 杩涜妭鐐� `style` 瀵硅薄锛�**缁戝畾涓茶鏁存潯涓㈠純** | 涓㈠け | 鐣欏湪 attributes锛屼絾鐢诲竷/HTML 閲屽凡娌℃湁 | 鍚� |
+| `attributes.style="{{璺緞}}"` | 鍘熸牱鐣欏湪 attributes锛堜笉杩� `style` 瀵硅薄锛� | **涓㈠け** | 淇濈暀 | 鏄紙浣嗙敾甯冪湅涓嶅埌锛� |
+| **`hidden="{{璺緞}}"`** | 鏅�氬睘鎬э紝鍘熸牱鐣欏湪 attributes | **淇濈暀** | 淇濈暀 | **鏄�** |
+
+**閲囩敤 `hidden`**銆傚啀鍔犱袱鏉″疄娴嬫妸瀹冪殑琛屼负閽夋锛�
+
+- Chromium 閲� `td[hidden]` 瀹炴祴 `display: none`銆侀珮搴� 0锛屼笌 `style="display:none"` 绛夋晥 鈥斺�� 鑰屾湇鍔$ PDF 鐢ㄧ殑灏辨槸鍚屼竴涓� Chromium锛坄PdfRenderService` 鈫� Playwright锛夛紝鎵�浠ユ祻瑙堝櫒閲岀殑缁撹鐩存帴閫傜敤浜庢墦鍗颁骇鐗╋紱
+- 涓や晶娓叉煋鍣�**閮借烦杩囥�屾眰鍊煎悗涓虹┖涓层�嶇殑灞炴��**锛堝墠绔� `render.ts:234`銆佸悗绔� `HtmlRenderer.java:214`锛夛紝浜庢槸銆岄琛岀粰绌轰覆 鈫� 涓嶈緭鍑鸿灞炴�� 鈫� 鍙锛涘叾浣欒缁欎竴涓潪绌哄�� 鈫� 杈撳嚭 鈫� 闅愯棌銆嶆槸涓や晶閫愬瓧涓�鑷寸殑纭畾鎬ц涓恒��
+
+涓や釜瀹炴祴寰楀埌鐨勭‖绾︽潫锛屽繀椤诲啓杩涘绾︼細
+
+- **`{{item.group.children.length}}` 鍙栦笉鍒板��**锛氳矾寰勫湪鏁扮粍涓婄户缁彇灞炴�т細鎸夊厓绱� pluck锛宍.length` 璇讳笉鍒般��**璺ㄨ鏁板繀椤荤敱鏁版嵁渚ф樉寮忕粰鍑�**锛坄group.span`锛夈��
+- **缁戝畾鐨勫瓧娈靛繀椤诲湪姣忎竴椤逛笂閮藉瓨鍦�**锛堝摢鎬曟槸绌轰覆锛夈�傚瓧娈电己甯細娓叉煋涓虹┖骞惰涓�鏉°�屽湪褰撳墠鏁版嵁涓彇涓嶅埌鍊笺�嶇殑闂锛沗hidden` 鑻ュ彇鍒� `undefined`锛屽睘鎬т細琚烦杩� 鈫� 璇ラ殣钘忕殑琛屽弽鑰岄湶鍑烘潵銆�
+
+## 鍥涖�佹柟妗�
+
+### 4.1 鏁版嵁渚у绾�
+
+鍦�**鐜版湁 `inspectionItems` 鐨勬瘡涓�椤�**涓婂鍔狅紙鏁扮粍閲屼粛鐒跺彧鏈夌湡瀹炴楠岄」锛�**涓嶅鍚堟垚缁勫ご琛屼互澶栫殑浠讳綍涓滆タ**锛涚粍澶存湰韬氨鏄崟鎹噷鐨勪竴椤癸級锛�
+
+| 瀛楁 | 绫诲瀷 | 鍚箟 |
+|---|---|---|
+| `item.requirement` | String | 鏈銆屾娴嬭姹傘�嶆枃鏈細**鍒嗙粍鐖堕」 = `formula_text` 鍏紡**锛屽叾浣� = 鍗曟嵁涓婄殑鏍囧噯瑕佹眰 |
+| `item.group.childName` | String | 銆屽瓙椤广�嶅垪鏂囨湰锛�**缁勫唴瀛愰」 = 鑷繁鐨勫悕瀛�**锛涚粍鍐呴敋鐐硅锛堝惈澶氭牱鍝佸鍑烘潵鐨勯敋鐐硅锛変笌鐙珛椤� = 绌轰覆 |
+| `item.group.span` | Integer | **銆屾楠岄」鐩�嶅垪**鐨� `rowspan`锛�**缁勫唴绗竴琛� = 璇ョ粍鐨勬�昏鏁�**锛堥敋鐐硅 + 瀛愰」琛岋級锛涘悓缁勫叾浣欒涓庣嫭绔嬮」 = 1 |
+| `item.group.hidden` | String | **缁勫唴绗竴琛� = 绌轰覆**锛堣繖涓�鏍煎彲瑙侊紝骞跺悜涓嬪悎骞讹級锛�**鍚岀粍鍏朵綑琛� = `hidden`**锛堣浣嶇粰涓婇潰鐨勫悎骞舵牸锛夛紱鐙珛椤� = 绌轰覆 |
+
+> **鍚堝苟鍙e緞缁熶竴鎴愪竴鏉¤鍒欙細缁勫唴绗竴琛岃儗 `span = 璇ョ粍鎬昏鏁癭锛屽悓缁勫叾浣欒涓�寰� `span = 1` + `hidden = hidden`銆�**
+> 杩欐牱澶氭牱鍝佺殑缁勫ご锛堜竴涓寚鏍囧琛岋級涔熻嚜鍔ㄨ惤鍦ㄨ鍒欓噷 鈥斺�� 鍙湁绗竴琛屽彲瑙佸苟鍚堝苟锛屽鍑烘潵鐨勯敋鐐硅璁╀綅锛�
+> 鏃笉浼氬鍑轰竴鏍肩┖鐧斤紝涔熶笉浼氭妸鍒楁尋姝��
+
+> **鍙悎骞躲�屾楠岄」鐩�嶄竴鏍硷紝涓嶅悎骞躲�屾娴嬭姹傘��**锛歞ocx 鍘熺敓鐗堝紡閲屽悎骞剁殑鍙湁椤圭洰鍒楋紝鏍囧噯瑕佹眰浠嶆槸閫愯鐨�
+> 锛堝疄娴� `20鐩笂` / `0-5` 閭d竴琛屽氨鏄嫭绔嬬殑鏍囧噯瑕佹眰锛夈�傝嫢鎶婃娴嬭姹備篃骞惰繘缁勫ご鏍硷紝缁勫唴瀛愰」鍚勮嚜鐨勬爣鍑嗚姹�
+> 灏辨棤澶勫彲鏀俱�佷細琚炕鎺夈�傜粍澶寸殑鍏紡鍙崰缁勫ご閿氱偣琛岃嚜宸遍偅涓�鏍笺��
+
+涓や晶鍚屾锛堝惁鍒欏墠绔瑙堜笌鍚庣鍑轰欢涓嶄竴鑷达級锛�
+
+- 鍚庣 `engine/context/ReportContext.java`锛歚InspectionItem` 鍔� `requirement` 涓庡祵濂� `ItemGroup group`锛宍itemMap()` 鏄惧紡鏀惧叆锛堣鏂规硶閫愬瓧娈垫灇涓撅紝涓嶉潬鍙嶅皠锛沗group` 涓� null 鏃朵笉鏀撅紝閬垮厤姹℃煋鍐荤粨 fixture 鐨勪綔鐢ㄥ煙锛夈��
+- 鍓嶇 `components/quality/engine/context.ts`锛歚ReportContextItem` 鍔犲悓鍚嶇殑鍙�� `requirement` 涓� `group`銆�
+
+`hidden` 鏄�**瀛楃涓茶�屼笉鏄竷灏�**锛氳繖涓睘鎬ч潬銆屽湪涓嶅湪銆嶈捣浣滅敤锛宍hidden="false"` 鐓ф牱闅愯棌锛屾墍浠ュ彧鑳界敤銆岀┖涓� = 涓嶈緭鍑恒�嶈繖涓�涓彲鍒ゅ畾鐨勫舰鎬併�傚悕瀛楀彇寰楃洿鐧斤紝鍊煎氨鏄灞炴�х殑鍊笺��
+
+### 4.2 鍒嗙粍璇嗗埆涓庢姤鍛婇『搴�
+
+- **璋佹槸缁勫ご**锛氭煇椤规寚鏍囪鏈崟閲屽埆鐨勮鐢� `parent_id` 鎸囪锛屽畠灏辨槸缁勫ご銆備笉渚濊禆 `item_type`锛屼篃涓嶄緷璧栬搴� 鈥斺�� 琛屽簭鏄潬涓嶄綇鐨勶紙鐖堕」閭h涓庡瓙椤逛笉鐩搁偦锛夈�俙item_type = 2`锛堝垎缁勯」锛夊彧鐢ㄦ潵鍒ゆ柇杩欎釜鐖舵寚鏍囥�屽涓嶅鏍煎綋缁勫ご銆嶏紝涓嶅弬涓庡綊灞炲垽鏂��
+- **鎶ュ憡椤哄簭**锛氶《灞傛潯鐩紙鐙珛椤逛笌缁勶級鎸夋寚鏍囩殑 `sort_order` 鍗囧簭锛宍sort_order` 缂哄け鐨勬帓鏈�鍚庯紝鍚屽�间繚鎸佽搴忥紙绋冲畾鎺掑簭锛夛紱缁勫唴瀛愰」鎸夎嚜宸辩殑 `sort_order`銆傚疄娴嬭繖缁勬暟鎹帓鍑烘潵鏄� 澶栬(10) 鈫� 鑹插害(20) 鈫� 姘村垎缁�(30) 鈫� 閰稿惈閲忕粍(40) 鈫� 姝d竵閱囧惈閲忕粍(50) 鈫� 瀵嗗害(60) 鈫� 鎶樺厜鐜�(70)锛屼笌 docx 鍜� `sort_order` 鐨勬剰鍥句竴鑷淬��
+ - 杩欐槸**鍞竴涓�澶勫鏃㈡湁琛屼负鐨勬敼鍔�**锛氭鍓嶆姤鍛婅搴� = 琛岃〃椤哄簭銆俙sort_order` 鏈氨鏄繖浠戒富鏁版嵁閲岃〃鎰忋�屾樉绀洪『搴忋�嶇殑瀛楁锛屼笖鏈崟閲岀嫭绔嬮」涓よ�呮伆濂戒竴鑷达紝瀹為檯褰卞搷闈㈠緢灏忋�傝嫢涓氬姟瑕佹眰涓ユ牸鎸夎搴忥紝鏀瑰洖涓�琛屽嵆鍙紙鎺掑簭閿崲鎴愯搴忥級銆�
+- **缁勫ご鑷繁閭d竴琛�**锛氱粍澶存寚鏍囬�氬父鍦ㄦ湰鍗曢噷涔熸湁琛岋紙姘村垎灏辨槸绗� 1 琛岋級锛屽畠浣滀负鍚堝苟鏍肩殑閿氱偣琛岃緭鍑恒��
+- **缁勫ご鎸囨爣鍦ㄦ湰鍗曢噷娌℃湁琛�**锛堟楠屾ā鏉垮彧鍕句簡瀛愰」鏃朵細杩欐牱锛夆�斺�� **浠嶇劧涓哄畠琛ヤ竴琛�**锛屽惁鍒欑粍鍚嶄笌鍏紡鏃犲鍙斁銆佹姤鍛婁笂杩欑粍灏辨暎鎴愪簡閫愭潯鏄庣粏銆傝ˉ鍑烘潵鐨勮繖涓�琛岋細瀹炴祴鍊间笌鍗曚綅涓虹┖銆乣requirement` 鍙栧叕寮忋�乣span` 鑳屾暣缁勮鏁帮紙瑙� 搂4.1 鐨勫悎骞跺彛寰勶級锛屽苟鍦ㄥ搷搴旂殑 `synthesizedGroupNames` 閲岃鏄庝负鍝嚑涓粍澶磋ˉ浜嗚銆佷负浠�涔堛��
+ - 鏃╂湡鏂规鏇炬妸杩欑鎯呭喌鍒や负銆岀粍涓嶆垚绔嬨�佹寜鐙珛椤瑰鐞嗐�嶏紝閭f牱浼�**鍘熸牱澶嶇幇鏈瑕佷慨鐨� bug**锛堢粍鍚嶄笌鍏紡鍐嶆涓㈠け锛夈�傚疄娴嬬‘璁よ繖鏉¤矾寰勫彲杈撅紙`mes_qc_template_indicator` 鍐冲畾鏈崟鏈夊摢浜涜锛屾ā鏉垮彲鑳藉彧鍕惧瓙椤癸級锛屾墍浠ユ寜銆岃ˉ琛屻�嶅疄鐜般��
+- **缁勫ご鎸囨爣鍦ㄦ湰鍗曢噷鏍规湰娌℃湁瀛愰」**锛堝嵆瀹冩槸涓�涓垎缁勯」锛屼絾娌℃湁浠讳綍琛岀敤 `parent_id` 鎸囧悜瀹冿級鈥斺�� 鎸夌嫭绔嬫楠岄」鍒楀嚭銆佺粍鍚嶄笉鍚堝苟锛屽苟鎶婂畠鐨勫悕瀛楁敹杩� `childlessGroupNames` 璇存槑銆�
+
+### 4.3 娓叉煋缁撴瀯
+
+鏂板缁勪欢 `GroupedQualityTable`銆屽垎缁勬楠岄」琛ㄣ�嶏紙涓嶆敼閫� `QualityTable`锛氬悗鑰呰鍔犵粍鐩稿叧 props 骞跺湪 `buildContent` 閲屽垎鏀紝灞炴�ч潰鏉垮鏉傚害涓婂崌锛屼笖鏂扮粍浠惰兘淇濊瘉鏃㈡湁鐢诲竷闆跺奖鍝嶏級銆�
+
+7 鍒楋紝鍏朵腑绗� 2 鏍硷紙妫�楠岄」鐩級鍦ㄧ粍澶磋绾靛悜鍚堝苟锛�
+
+| 鍒� | 缁戝畾 | 缁勫ご琛� | 缁勫唴瀛愰」琛� | 鐙珛椤� |
+|---|---|---|---|---|
+| 1 搴忓彿 | `{{index}}` | 琛屽彿 | 琛屽彿 | 琛屽彿 |
+| 2 妫�楠岄」鐩� | `{{item.itemName}}` + `rowspan="{{item.group.span}}"` + `hidden="{{item.group.hidden}}"` | 缁勫悕锛堝悎骞讹級 | 璇ユ牸闅愯棌 | 鑷繁鐨勫悕瀛� |
+| 3 瀛愰」 | `{{item.group.childName}}` | 绌� | 鑷繁鐨勫悕瀛� | 绌� |
+| 4 妫�娴嬭姹� | `{{item.requirement}}` | **鍏紡** | 鑷繁鐨勬爣鍑嗚姹� | 鑷繁鐨勬爣鍑嗚姹� |
+| 5 瀹炴祴鍊� | `{{item.actualValue}}` | 缁勫ご鑷繁鐨勫�� | 鑷繁鐨勫疄娴嬪�� | 鑷繁鐨勫疄娴嬪�� |
+| 6 鍗曚綅 | `{{item.unit}}` | 鍚屼笂 | 鍚屼笂 | 鍚屼笂 |
+| 7 鍒ゅ畾 | `{{item.resultText}}` | 鏃犲垽瀹氳鍒� | 鑷繁鐨勫垽瀹� | 鑷繁鐨勫垽瀹� |
+
+缁撴瀯瑕佺偣锛�
+
+1. 澶栧眰浠嶆槸**鍗曞眰** `repeat`锛岃矾寰� `inspectionItems`锛堥粯璁ゅ�硷紝灞炴�ч潰鏉垮彲鏀癸級銆�
+2. 鍓嶄袱鍒椾箣澶栫収鎼� `QualityTable` 鐨勯潤鎬佸崟鍏冩牸鏍峰紡锛坄components` 杩斿洖 HTML 瀛楃涓诧紝涓庡叾浣� 11 涓粍浠跺悓娆惧啓娉曪級銆�
+3. `rowspan` / `hidden` 蹇呴』鍐欏湪**灞炴��**涓婏紝涓嶈兘鍐欒繘琛屽唴 `style`锛堣鍐呮牱寮忎細琚� GrapesJS 瑙f瀽鎴愯妭鐐� `style` 瀵硅薄锛岃�� `renderStyle` 涓嶈窇缁戝畾锛夈��
+4. `GroupedQualityTable` 涓� `QualityTable` **浜岃�呯敤鍏朵竴**锛氬墠鑰呯敤浜庢湁鍒嗙粍鐨勫崟鎹紝鍚庤�呯敤浜庣函骞崇殑妫�楠岄」琛ㄣ��
+
+## 浜斻�佽惤鍦版竻鍗�
+
+**鍚庣 `yudao-module-mes`**
+- `MesQcIndicatorDO`锛氳ˉ鏄犲皠 `parent_id` / `item_type` / `formula_text` / `unit_text` / `sort_order`銆�
+- `MesQcReportItemRespDTO`锛氬姞 `requirement` 涓� `groupChildName` / `groupSpan` / `groupHidden`锛堣法妯″潡 API 鍙樻洿 鈫� 闇� `mvn compile -pl yudao-module-qcreport -am -q`锛夈��
+- `MesQcReportApiImpl.buildItems`锛氭敼鐢� `parent_id` 鍒ゅ綊灞烇紙涓嶅啀鐢� `result_type IS NULL`锛屼篃涓嶅啀涓㈢埗椤癸級锛屾寜 `sort_order` 鎺掑簭锛屾妸缁勪俊鎭笅鍙戝埌缁勫ご鐨勯敋鐐硅涓庢瘡涓瓙椤广��
+- `MesQcReportRespDTO`锛氬師 `groupItemNames` 鎷嗘垚涓や釜鍚勮涓�浠朵簨鐨勫瓧娈� 鈥斺�� `childlessGroupNames`锛堟槸鍒嗙粍椤广�佷絾鏈崟娌℃湁灞炰簬瀹冪殑瀛愰」锛変笌 `synthesizedGroupNames`锛堟湰鍗曟病鏈夎嚜宸辩殑琛屻�佽琛ヤ簡涓�琛屾潵鏀剧粍鍚嶄笌鍏紡锛夛紝鍙︽湁 `missingIndicatorCount`锛堟槑缁嗗紩鐢ㄧ殑鎸囨爣宸茶鍒犻櫎锛夈��
+
+**鍚庣 `yudao-module-qcreport`**
+- `engine/context/ReportContext.java`锛歚InspectionItem` 鍔� `requirement` 涓� `group`锛宍itemMap()` 甯︿笂銆�
+- `MesQcReportContextMapper`锛氭妸 MES 鐨� `requirement` / `group*` 閫忚繘鎶ュ憡涓婁笅鏂囷紱缁勫ご閿氱偣琛屼笉鍐嶆姤銆屽皻鏈綍鍏ュ疄娴嬪�笺�嶏紙瀹冩寜瀹氫箟娌℃湁瀹炴祴鍊硷級锛沗appendSkipWarnings` 鏂囨闅忕埗椤逛笉鍐嶈涓㈠純鑰岃皟鏁淬��
+
+**鍓嶇 `mom-pro2-before`**
+- `engine/context.ts` 鐨� `ReportContextItem` 鍔� `requirement` / `group`銆�
+- 鏂板 `inspection/grouped-quality-table.ts` 骞舵敞鍐岋紱`aiHint` 鍐欐竻銆屾湁鍒嗙粍鏃剁敤瀹冿紝鏃犲垎缁勭敤 QualityTable銆嶃��
+- `.qc-conformance/assemble-ts.ts`锛歚definitions.length === 12`锛堢 100 琛岋級銆乣catalog.length === 12`锛堢 255 琛岋級銆佸瓧娈甸泦鍚堟柇瑷�閮借闅忕 13 涓粍浠舵洿鏂般��
+
+**娴嬭瘯涓庡鎷�**
+- 鍚庣瀛橀噺蹇呴』鍏ㄧ豢锛坄FrontendConformanceTest` 閫愬瓧姣斿鐨勬湡鏈涗骇鐗╁彧鏄� HTML 涓庤鍒欑粨鏋滐紝鏂板鐨� `group` 涓嶅弬涓庝换浣� fixture 琛ㄨ揪寮忥紝鏁呬笉蹇呴噸鐢熸垚锛夈�傚疄娴嬶細`yudao-module-qcreport` 141 椤瑰叏缁裤��
+- 鍓嶇鎺㈤拡 `.qc-conformance/verify-grouped-table.ts`锛氱敤鐪熷疄寮曟搸璺戙�岀粍澶� + 瀛愰」 + 鐙珛椤广�嶆贩鎺掔殑涓婁笅鏂囷紝鏂█鍚堝苟鏍笺�侀殣钘忔牸銆佸垪瀵归綈涓庛�屾棤鍒ゅ畾瑙勫垯銆嶄笉鍙楀奖鍝嶃��**宸茶惤鍦板苟鍏ㄧ豢**锛涘垪瀵归綈鍙︽湁涓�娆℃祻瑙堝櫒瀹炴祴锛堣杩涘害鏂囨。锛夈��
+- 鍒嗙粍鐢诲竷 fixture 杩� `FrontendConformanceTest` 鐨勫弻渚ч�愬瓧姣斿 鈥斺�� **鏈疆鏈仛**锛屽彧鍋氬墠绔帰閽堛�傜悊鐢憋細璇� fixture 瑕佹眰鍓嶇鍏堜骇鍑恒�屾湡鏈� HTML銆嶅啀鐢� Java 閫愬瓧姣斿锛岃�屽垎缁勭粨鏋勭殑鍏抽敭椋庨櫓锛坄rowspan` 璁╀綅鍚庡垪鏄惁涓蹭綅锛夊彇鍐充簬娴忚鍣ㄨ〃鏍煎竷灞�锛岄�愬瓧姣斿鍥哄畾涓嶄綇杩欎竴鏉★紝鎺㈤拡 + 娴忚鍣ㄥ疄娴嬫墠鏄湁鏁堣瘉鎹��
+
+## 鍏�佸凡瀹氱殑鍙e緞锛堝師銆屽緟纭銆嶏級
+
+1. **杩囩▼鍙傛暟琛岀殑鍒ゅ畾鍙e緞** 鈥斺�� 宸插疄鐜般�屾棤鍒ゅ畾瑙勫垯銆嶏細鏃㈡病鏈夎鏍间笂涓嬮檺銆佷篃娌℃湁鍒ゅ畾瑙勫垯鐨勮鏍囦负銆屾棤鍒ゅ畾瑙勫垯銆嶏紝涓嶈鍏ュ悎鏍肩巼鍒嗘瘝銆佷笉鍙備笌鎶ュ憡缁撹锛涜繖鍙槸鏄剧ず涓庣粺璁″彛寰勶紝**涓嶆柊澧炰篃涓嶅垹闄ゆ楠岄」**锛宍total` 浠嶆槸鐪熷疄椤规暟銆�
+2. **缁勫ご涓ゅ垪鐨勫搴�** 鈥斺�� 缁勫悕涓庡叕寮忓悇鍗犱竴鍒楋紝**妫�娴嬭姹傚垪鍚屾椂鎵挎媴銆岀粍澶存斁鍏紡銆嶄笌銆屽叾瀹冭鏀炬爣鍑嗚姹傘��**锛堝疄娴嬫湰鍗曟墍鏈夋爣鍑嗚姹備负绌猴紝涓嶄細浜掔浉瑕嗙洊锛夈�備笉鍙﹀紑涓�鍒楋紝閬垮厤绾钩鍗曟嵁鍑虹幇鏁村垪绌虹櫧銆�
+3. **AI 瀵煎叆** 鈥斺�� 妯″瀷瑕佽兘鍦� `QualityTable` 涓� `GroupedQualityTable` 涔嬮棿閫夊锛屼緷璧� `aiHint` 涓庢彁绀鸿瘝瑙勫垯锛涜瘑鍒噯纭巼鏃犳硶鍏堥獙淇濊瘉锛岄渶鐪熷疄璋冪敤瑙傚療鍚庡瀹炴眹鎶ャ��
+
+## 涓冦�佹槑纭笉鍋�
+
+- 涓嶆敼 `HtmlRenderer` / `BASE_CSS`锛圥5 宸查獙璇侀浂鏀瑰姩鍙锛夈��
+- 涓嶆敼 Schema 濂戠害 1.1銆佷笉鏂板椤跺眰涓婁笅鏂囨暟缁勩��
+- 涓嶄负銆屽悎骞跺崟鍏冩牸銆嶅紩鍏� `tbody` 宓屽锛圥4 鍙浣嗗睘闄嶇骇鍏煎璺緞锛屼笖姹℃煋缁熻锛屼笉閲囩敤锛夈��
+- 涓嶅湪灞炴�ч潰鏉垮紩鍏ョ粨鏋勫寲 props锛堟棦鏈夎兘鍔涗笉鏀寔锛屼笖鏃犲繀瑕侊級銆�
+- 涓嶆妸缁勫唴瀛愰」鍐嶅悜涓嬪祵濂楋紙褰撳墠鏁版嵁鍙湁涓ゅ眰锛涚湡瑕佹洿娣辩殑灞傜骇锛宍parent_id` 宸茶兘琛ㄨ揪锛屼絾娓叉煋缁撴瀯瑕侀噸鏂拌璁★級銆�
diff --git a/docs/qc_report_indicator_hierarchy_frontend_integration.md b/docs/qc_report_indicator_hierarchy_frontend_integration.md
new file mode 100644
index 0000000..d1dc219
--- /dev/null
+++ b/docs/qc_report_indicator_hierarchy_frontend_integration.md
@@ -0,0 +1,196 @@
+# 璐ㄦ鎸囨爣灞傜骇缁存姢 - 鍓嶇鑱旇皟鏂规
+
+> 鍙樻洿妯″潡锛歚yudao-module-mes`锛堣川妫�鎸囨爣涓绘暟鎹級
+> 鍙樻洿鐩殑锛氳銆屽垎缁勯」 / 鎵�灞炲垎缁� / 鍏紡 / 鎺掑簭鍙枫�嶈繖鍥涗釜灞傜骇瀛楁鍙互鍦�**璐ㄦ鎸囨爣椤�**缁存姢锛�
+> 涓嶅啀鍙兘闈� SQL 閫犳暟鎹��
+> 鎶ュ憡渚х殑鍙栨暟閫昏緫**涓�琛屾湭鏀�** 鈥斺�� 鐣岄潰閫犲嚭鏉ョ殑鍒嗙粍涓� SQL 閫犲嚭鏉ョ殑鍒嗙粍锛屽湪鎶ュ憡閲屽畬鍏ㄥ悓褰€��
+
+## 娑夊強椤甸潰
+
+- 璐ㄦ鎸囨爣鍒楄〃椤碉紙鑿滃崟锛氳川閲忕鐞� 鈫� 璐ㄦ鎸囨爣锛�
+
+## 涓氬姟娴佺▼涓庢暟鎹甫鍏�
+
+1. 鍦ㄨ川妫�鎸囨爣椤垫柊寤恒�屽垎缁勯」銆嶁啋 璇ユ寚鏍囨垚涓�**椤剁骇鎸囨爣**锛宍鎵�灞炲垎缁刞 鍥哄畾涓洪《绾с�乣鍏紡` 蹇呭~銆�
+2. 鏂板缓銆屽綍鍏ラ」銆嶁啋 鍦� `鎵�灞炲垎缁刞 閲岄�夋嫨绗� 1 姝ュ缓鐨勫垎缁勯」 鈫� 璇ユ寚鏍囨垚涓鸿繖涓垎缁勭殑瀛愰」銆�
+3. 妫�娴嬫柟妗� 鈫� 璐ㄦ鍗� 鈫� 鍑烘姤鍛婏細鎶ュ憡渚ф寜 `parent_id` 鎶婂垎缁勯」涓庡畠鐨勫瓙椤硅繕鍘熸垚涓ゅ眰琛ㄥご锛�
+ 缁勫悕绾靛悜鍚堝苟銆佸叕寮忚繘銆屾娴嬭姹傘�嶅垪銆�**杩欎竴姝ョ殑灞曠ず鏁堟灉涓庢暟鎹潵鑷� SQL 鏃跺畬鍏ㄤ竴鑷淬��**
+
+## API
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|------|------|------|
+| GET | `/mes/qc/indicator/page` | 鍒嗛〉鏌ヨ锛堟潈闄� `mes:qc-indicator:query`锛� |
+| GET | `/mes/qc/indicator/group-list` | **鏂板**锛氬垎缁勯」绮剧畝鍒楄〃锛堟潈闄� `mes:qc-indicator:query`锛� |
+| POST | `/mes/qc/indicator/create` | 鏂板锛堟潈闄� `mes:qc-indicator:create`锛� |
+| PUT | `/mes/qc/indicator/update` | 淇敼锛堟潈闄� `mes:qc-indicator:update`锛� |
+| DELETE | `/mes/qc/indicator/delete` | 鍒犻櫎锛堟潈闄� `mes:qc-indicator:delete`锛� |
+| GET | `/mes/qc/indicator/export-excel` | 瀵煎嚭锛堟潈闄� `mes:qc-indicator:export`锛� |
+
+鎺ュ彛鍓嶇紑涓� `/admin-api`锛屼笌鏃㈡湁绾﹀畾涓�鑷达紝涓嬫枃璺緞鍧囩渷鐣ヨ鍓嶇紑銆�
+
+### GET /mes/qc/indicator/group-list
+
+涓撲緵銆屾墍灞炲垎缁勩�嶄笅鎷夈��**鍙繑鍥炲垎缁勯」**锛坄item_type = 2`锛夛紝涓嶈繑鍥炲綍鍏ラ」銆�
+
+鏃犺姹傚弬鏁般�傚搷搴斾负鎸囨爣瀵硅薄鏁扮粍锛堝瓧娈靛悓涓嬫柟鍝嶅簲瀛楁琛紝姝ゅ鍙繚璇� `id` / `name` 鏈夊�硷級銆�
+
+### 璇锋眰鍙傛暟锛坈reate / update锛�
+
+`update` 涓� `create` 鍏辩敤鍚屼竴涓姹備綋銆傛柊澧炲瓧娈垫爣 鈽呫��
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|------|------|------|------|
+| id | Long | update 蹇呭~ | 缂栧彿 |
+| code | String | 鏄� | 妫�娴嬮」缂栫爜 |
+| name | String | 鏄� | 妫�娴嬮」鍚嶇О |
+| type | Integer | 鏄� | 妫�娴嬮」绫诲瀷锛堝瓧鍏� `mes_indicator_type`锛� |
+| tool | String | 鍚� | 妫�娴嬪伐鍏� |
+| 鈽� itemType | Integer | 鍚� | 鏉$洰绫诲瀷锛歚1`=褰曞叆椤癸紙榛樿锛夛紝`2`=鍒嗙粍椤� |
+| 鈽� parentId | Long | 鍚� | 鐖舵寚鏍囩紪鍙凤紝`0` 鎴栫暀绌� = 椤剁骇鎸囨爣 |
+| 鈽� formulaText | String | 鍒嗙粍椤瑰繀濉� | 鍏紡灞曠ず鏂囨湰锛屾姤鍛婇噷浣滀负璇ュ垎缁勭殑銆屾娴嬭姹傘�� |
+| 鈽� sortOrder | Integer | 鍚� | 鍚岀骇鎺掑簭鍙凤紝鐣欑┖鍒欒嚜鍔ㄦ帓鍒板悓绾ф湯灏� |
+| resultType | Integer | 褰曞叆椤瑰繀濉� | 缁撴灉鍊肩被鍨嬶紙瀛楀吀 `mes_qc_result_type`锛夈��**鍒嗙粍椤逛笉濉�** |
+| resultSpecification | String | 鏉′欢蹇呭~ | 缁撴灉鍊煎睘鎬с�俙resultType` 涓恒�屾枃浠躲�嶆垨銆屽瓧鍏搞�嶆椂蹇呭~ |
+| remark | String | 鍚� | 澶囨敞 |
+
+> `resultType` 鍘熷厛甯� `@NotNull`锛屾湰杞�**鎽樻帀浜�**锛氬垎缁勯」鎸夌幇缃戝彛寰勫氨鏄� `NULL`锛堢幇缃� 3 涓垎缁勮
+> 鐨� `result_type` 鍏ㄤ负 NULL锛夈�傛敼涓烘湇鍔$鎸夋潯鐩被鍨嬫潯浠舵牎楠岋細**鍙湁褰曞叆椤瑰繀濉�**銆�
+
+### 鍝嶅簲瀛楁鏂板锛坧age / export-excel锛�
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| itemType | Integer | 鏉$洰绫诲瀷 |
+| parentId | Long | 鐖舵寚鏍囩紪鍙凤紝`0` 琛ㄧず椤剁骇 |
+| parentName | String | **鎵�灞炲垎缁勫悕绉�**锛岀敱鍚庣鍥炲~锛涢《绾ф寚鏍囦负 `null` |
+| formulaText | String | 鍏紡 |
+| sortOrder | Integer | 鍚岀骇鎺掑簭鍙� |
+
+`parentName` 鐢辨帶鍒跺櫒鍥炲~锛屽彇鍊兼柟寮忔槸锛氭敹闆嗘湰椤垫墍鏈夐潪 `0` 鐨� `parentId` 鈫� 涓�娆℃�ф寜 id 鎵归噺鏌ユ寚鏍� 鈫�
+寤� `id 鈫� name` 鏄犲皠鍥炲~銆傚洜姝�**鐖舵寚鏍囧嵆浣夸笉鍦ㄥ綋鍓嶉〉銆佺敋鑷充笉鍦ㄧ瓫閫夌粨鏋滃唴锛屽悕绉颁篃鑳芥纭В鏋�**銆�
+
+> **`/get`锛堣鎯咃級鎺ュ彛涓嶅洖濉� `parentName`**锛屼笌 `/page`銆乣/export-excel` 涓嶄竴鑷淬��
+> 缂栬緫寮圭獥鐨勬暟鎹潵婧愭槸鍒楄〃琛岋紙鍒楄〃琛屽凡甯� `parentName`锛夛紝涓嶅彈褰卞搷锛涜嫢鍚庣画鏈夐〉闈㈢洿鎺ヨ皟 `/get` 灞曠ず
+> 鎵�灞炲垎缁勶紝闇�瑕佸彟琛屽鐞嗐��
+
+### 鍝嶅簲绀轰緥
+
+```json
+{
+ "code": 0,
+ "data": {
+ "list": [
+ {
+ "id": 21,
+ "code": "SEED-BT-WATER",
+ "name": "姘村垎",
+ "type": 4,
+ "itemType": 2,
+ "parentId": 0,
+ "parentName": null,
+ "formulaText": "w = (m1 - m0) / m 脳 100%",
+ "sortOrder": 30,
+ "resultType": null,
+ "resultSpecification": null
+ },
+ {
+ "id": 22,
+ "code": "SEED-BT-WATER-M",
+ "name": "璇曟牱璐ㄩ噺 m",
+ "type": 4,
+ "itemType": 1,
+ "parentId": 21,
+ "parentName": "姘村垎",
+ "formulaText": null,
+ "sortOrder": 1,
+ "resultType": 1,
+ "resultSpecification": null
+ }
+ ],
+ "total": 34
+ }
+}
+```
+
+## 瀛楁灞曠ず瑙勫垯
+
+| 瀛楁 | 灞曠ず浣嶇疆 | 璇存槑 |
+|------|----------|------|
+| 鏉$洰绫诲瀷 | 鍒楄〃鍒椼�佹柊澧�/淇敼琛ㄥ崟 | 鍒楄〃鐢ㄦ爣绛惧睍绀猴細`鍒嗙粍椤筦 / `褰曞叆椤筦 |
+| 鎵�灞炲垎缁� | 鍒楄〃鍒椼�佹柊澧�/淇敼琛ㄥ崟 | 鍒楄〃鍙� `parentName`锛屼负 `null` 鏃舵樉绀� `-`锛堣〃绀洪《绾ф寚鏍囷級 |
+| 鍏紡 | 鏂板/淇敼琛ㄥ崟 | **浠呭垎缁勯」鍙锛屼笖蹇呭~** |
+| 鎺掑簭鍙� | 鏂板/淇敼琛ㄥ崟 | 鏁板瓧杈撳叆锛屾渶灏� `0`锛涚暀绌虹敱鏈嶅姟绔ˉ榻� |
+| 鏉$洰绫诲瀷 | 鎼滅储琛ㄥ崟 | 涓嬫媺锛氬綍鍏ラ」 / 鍒嗙粍椤� |
+
+**銆屾墍灞炲垎缁勩�嶄笉鏄爲褰㈠睍绀�**锛氬垎缁勯」鍙兘鏄《绾э紝鎵�浠ュ�欓�夐」灏辨槸涓�灞傚钩閾虹殑鍒嗙粍椤瑰垪琛�
+锛堝灞傚涓�涓�岄《绾ф寚鏍囥�嶆牴鑺傜偣锛夈�備笉鎻愪緵澶氱骇鏍戙��
+
+## 涓氬姟瑙勫垯璇存槑
+
+### 灞傜骇瑙勫垯锛堝彧鍏佽涓ゅ眰锛�
+
+| 鍦烘櫙 | 瑙勫垯 |
+|------|------|
+| 鍒嗙粍椤� | 蹇呴』鏄�**椤剁骇鎸囨爣**锛宍鎵�灞炲垎缁刞 椤瑰湪琛ㄥ崟涓�**涓嶅嚭鐜�**锛岃惤搴撳浐瀹� `parentId = 0` |
+| 褰曞叆椤� | 鍙寕鍒颁换鎰忓垎缁勯」涓嬶紝涔熷彲浣滀负椤剁骇鎸囨爣锛坄鎵�灞炲垎缁刞 鐣欑┖锛� |
+| 涓轰粈涔堝彧鏈変袱灞� | 瑙勫垯鏈韩鎺ㄥ嚭锛氱埗蹇呴』鏄�**鍒嗙粍椤�**锛岃�屽垎缁勯」**鍙兘椤剁骇** 鈬� 绗笁灞傛棤娉曟瀯閫� |
+
+**銆屾墍灞炲垎缁勩�嶅湪琛ㄥ崟涓婄殑鍊欓�夊彧鏈夊垎缁勯」**锛氭柊寤哄綍鍏ラ」鏃朵笉鍙兘閫夊埌鑷繁锛屼篃涓嶅彲鑳介�夊埌鍙︿竴涓綍鍏ラ」銆�
+
+### 鏍¢獙瑙勫垯涓庢彁绀烘枃妗�
+
+鏈嶅姟绔寜涓氬姟浼樺厛绾�**鍙繑鍥炵涓�澶勪笉婊¤冻鐨勬潯浠�**锛岄伩鍏嶄竴娆℃姏澶氭潯璁╃敤鎴锋姄涓嶄綇閲嶇偣銆�
+
+| 閿欒鐮� | 瑙﹀彂鏉′欢 | 鎻愮ず鏂囨瑕佺偣 |
+|--------|----------|--------------|
+| `1040601007` | 鍒嗙粍椤瑰嵈閫変簡鎵�灞炲垎缁� | 鍚垎缁勫悕 + 鎵�閫夌埗鎸囨爣鍚� + 鏀规硶锛堟妸鏉$洰绫诲瀷鏀逛负褰曞叆椤瑰啀閫夊垎缁勶級 |
+| `1040601006` | 鐖舵寚鏍囨槸鑷繁 | 銆岀埗鎸囨爣涓嶈兘鏄嚜宸便�� |
+| `1040601004` | 鐖舵寚鏍囦笉瀛樺湪锛堝凡琚垹闄わ級 | 鍚埗鎸囨爣缂栧彿 + 鏀规硶锛堥噸鏂伴�夋嫨鎴栨竻绌猴級 |
+| `1040601005` | 鐖舵寚鏍囦笉鏄垎缁勯」 | 鍚埗鎸囨爣鍚� + 瀹冨綋鍓嶇殑鏉$洰绫诲瀷涓枃鍚� + 鏀规硶锛堟敼閫夊垎缁勯」 / 鍏堟妸瀹冪殑鏉$洰绫诲瀷鏀逛负鍒嗙粍椤癸級 |
+| `1040601009` | 褰曞叆椤规湭濉粨鏋滃�肩被鍨� | 銆屽綍鍏ラ」鐨勭粨鏋滃�肩被鍨嬩笉鑳戒负绌恒�� |
+| `1040601003` | 缁撴灉鍊肩被鍨嬩负鏂囦欢/瀛楀吀浣嗙粨鏋滃�煎睘鎬т负绌� | 銆岀粨鏋滃�煎睘鎬т笉鑳戒负绌恒�� |
+| `1040601008` | **鏀规寕鍒板垎缁勪笅**鏃讹紝璇ユ寚鏍囦笅宸叉湁瀛愰」 | 鍚寚鏍囧悕 + 瀛愰」鏉℃暟 + 銆岃鍏堝垹闄ゆ垨绉昏蛋杩� N 涓瓙椤广�� |
+| `1040601008` | **鏀逛负褰曞叆椤�**鏃讹紝璇ユ寚鏍囦笅宸叉湁瀛愰」 | 鍚屼笂閿欒鐮侊紝鏂囨鏀逛负銆屽惁鍒欒繖浜涘瓙椤逛細澶卞幓鎵�灞炲垎缁勩�� |
+
+鍚庝袱鏉$敤鍚屼竴涓敊璇爜銆�**鏂囨鍚勮嚜璐村悎鍦烘櫙**锛氫竴涓槸銆屼笉鑳藉啀鎸傚埌鍒殑鍒嗙粍涓嬨�嶏紝涓�涓槸
+銆屼笉鑳藉弽杩囨潵鍙樻垚瀛愰」銆嶃��
+
+### 钀藉簱鏃剁殑鑷姩澶勭悊
+
+| 瀛楁 | 澶勭悊 |
+|------|------|
+| `parentId` | 鐣欑┖琛� `0` |
+| `itemType` | 鐣欑┖琛� `1`锛堝綍鍏ラ」锛� |
+| `resultType` / `resultSpecification` | **鍒嗙粍椤瑰己鍒舵竻绌�**銆傚綍鍏ラ」鏀瑰垎缁勯」鏃讹紝鏃х殑缁撴灉鍊间細琚湡姝e啓鍥� `NULL` |
+| `sortOrder` | 鐣欑┖鑷姩鎺掑埌鍚岀骇鏈熬锛氶《绾ф闀� `10`锛屽瓙椤规闀� `1` |
+
+> 銆屾敼鍒嗙粍椤瑰悗缁撴灉鍊艰娓呯┖銆嶄緷璧� DO 涓婄殑 `updateStrategy = ALWAYS`銆侻yBatis-Plus 榛樿鐨�
+> `NOT_NULL` 绛栫暐浼氭妸 `null` 瀛楁浠� UPDATE 璇彞閲屽墧闄わ紝瀵艰嚧鏃х粨鏋滃�兼畫鐣� 鈥斺�� 杩欐槸鏈疆淇帀鐨�
+> 涓�涓湡瀹炲啓鍏ョ己闄凤紝鍓嶇鏃犻渶鎰熺煡銆�
+
+### 鍒犻櫎
+
+**鍒犻櫎鍒嗙粍椤逛細绾ц仈鍒犻櫎瀹冧笅闈㈢殑鎵�鏈夊瓙椤广��**
+
+| 鎿嶄綔 | 缁撴灉 |
+|------|------|
+| 鍒犻櫎鍒嗙粍椤� | 瀹冪殑鍏ㄩ儴瀛愰」涓�骞跺垹闄� |
+| 鍒犻櫎褰曞叆椤� | 鍙垹瀹冭嚜宸� |
+
+鎶ュ憡渚у鎸囨爣琚垹宸叉湁鍏滃簳锛氭寚鏍囧凡琚垹闄ょ殑鏄庣粏琛屽彧璁″叆 `missingIndicatorCount` 杩� `warnings`锛�
+涓嶄細瀵艰嚧鍑轰欢澶辫触銆�
+
+## 娉ㄦ剰浜嬮」
+
+- **銆屾潯鐩被鍨嬨�嶄笉鍦ㄥ鍑� Excel 閲�**銆俙鎵�灞炲垎缁刞銆乣鍏紡`銆乣鎺掑簭鍙穈 涓夊垪宸茶繘 Excel锛�
+ 鏉$洰绫诲瀷娌℃湁瀵瑰簲鍒楋紙鍙粨鍚堛�屾墍灞炲垎缁勩�嶆槸鍚︽湁鍊煎垽鏂級銆傝繖鏄湰杞槑纭帴鍙楃殑鍙e緞銆�
+- **`鍗曚綅` 瀛楁涓嶅鍓嶇鏆撮湶**锛屼篃涓嶅湪鏂板/淇敼琛ㄥ崟閲屻�傚師鍥狅細璇ュ垪鍦ㄥ叏閮ㄥ悗绔唬鐮侀噷娌℃湁浠讳綍璇诲彇鏂癸紝
+ 鎶ュ憡閲岀殑銆屽崟浣嶃�嶅彇鑷楠屾柟妗堣鐨勮閲忓崟浣嶏紱鏀句竴涓病浜鸿鐨勫瓧娈佃繘琛ㄥ崟鍙細璇褰曞叆浜恒��
+- **鍒囨崲鏉$洰绫诲瀷浼氭竻绌哄綍鍏ラ」涓撳睘瀛楁**锛氳〃鍗曞垏鍒般�屽垎缁勯」銆嶆椂锛屾墍灞炲垎缁勪細琚噸缃负椤剁骇銆�
+ 缁撴灉鍊肩被鍨嬩笌缁撴灉鍊煎睘鎬т細琚竻绌恒�傝繖鏄繀瑕佺殑 鈥斺�� 鍚﹀垯琚殣钘忕殑瀛楁浠嶄細闅忚〃鍗曟彁浜わ紝
+ 娈嬬暀鐨� `parentId` 浼氳鍚庣灞傜骇鏍¢獙椤跺洖鏉ャ��
+- **缂栬緫鍒嗙粍椤规椂锛屻�屾墍灞炲垎缁勩�嶅瓧娈典笉鍙銆併�屽叕寮忋�嶅繀濉敓鏁�**銆�
+- **`sortOrder` 鍏佽閲嶅**锛氭湇鍔$涓嶆牎楠屽悓绾ф帓搴忓彿鐨勫敮涓�鎬э紝鐩稿悓鎺掑簭鍙风殑鐩稿椤哄簭涓嶄繚璇併��
+- **`group-list` 杩斿洖鐨勬槸鍏ㄩ儴鍒嗙粍椤�**锛屼笉鎸変换浣曠淮搴﹁繃婊わ紱濡傛灉鍒嗙粍椤规暟閲忓闀垮埌寰堝ぇ锛�
+ 闇�瑕佽�冭檻鏀归�犱负鍒嗛〉鎴栨悳绱㈠紡閫夋嫨銆�
diff --git a/docs/qc_report_instance_frontend_integration.md b/docs/qc_report_instance_frontend_integration.md
new file mode 100644
index 0000000..a908336
--- /dev/null
+++ b/docs/qc_report_instance_frontend_integration.md
@@ -0,0 +1,290 @@
+# 鏅鸿兘璐ㄦ鎶ュ憡 鈥� 鍑轰欢鎺ュ彛 鍓嶇鑱旇皟鏂规
+
+> 鍚庣妯″潡锛歚yudao-module-qcreport`銆�鎺ュ彛鍓嶇紑锛歚/admin-api/qc-report/instance`
+> 鏈疆鑼冨洿锛�**HTML 鍑轰欢 + PDF 鍑轰欢**銆侾DF 鐢卞悗绔皟 Chromium 鎵撳嵃锛屾帴鍙e彧杩斿洖褰掓。缁撴灉涓庣鍚嶅湴鍧�锛�
+> 鎶ュ憡瀹炰緥琛�**涓嶅瓨鏂囦欢鍦板潃**锛孭DF 缁熶竴鎸傚湪闄勪欢搴擄紙`system_storage_attachment`锛夐噷銆�
+
+## 娑夊強椤甸潰
+
+| 椤甸潰 | 璺敱 | 璇存槑 | 鐘舵�� |
+|---|---|---|---|
+| 鎶ュ憡瀹炰緥鍒楄〃椤� | `/qc/report-instance` | 鍒嗛〉鏌ョ湅宸插嚭浠剁殑鎶ュ憡锛屾寜妯℃澘/缂栧彿/涓氬姟鍗曟嵁/鐘舵��/鏃堕棿绛涢�� | **宸茶惤鍦�**锛坄views/mes/qc/report/instance/index.vue`锛� |
+| 鎶ュ憡棰勮 / 璇︽儏寮圭獥 | 鍚屼笂 | 灞曠ず娓叉煋鍑虹殑 HTML锛涙暟鎹揩鐓ч〉绛撅紱**銆屽鍑� PDF銆嶆寜閽皟 `pdf` 鎺ュ彛** | **宸茶惤鍦�**锛坄.../instance/modules/detail.vue`锛� |
+| 妯℃澘璁捐鍣紙鏃㈡湁锛� | `/qc/report-template` | 銆岄瑙堛�嶆寜閽渶瑕佽皟鐢ㄦ湰鏂囨。鐨� `preview` 鎺ュ彛 | 浠嶅緟鎺ュ叆锛堟湰杞彧鍔犱簡銆孉I 瀵煎叆銆嶆寜閽級 |
+| MES 璐ㄦ鍗曪紙鏃㈡湁锛屽悗缁級 | 鈥� | 銆屽嚭鎶ュ憡銆嶅叆鍙o紝鎶婅川妫�鍗曟暟鎹綊涓�鍖栧悗璋� `generate` | **鍚庣画杞**锛堟湰杞敱璋冪敤鏂硅嚜琛岀粍缁囨暟鎹級 |
+
+鑿滃崟宸插叆搴擄細銆屾姤鍛婂疄渚嬨�嶆寕鍦ㄣ�岃川閲忕鐞嗐�嶏紙`parent_id=5500`锛変笅锛宍component` 濉� `mes/qc/report/instance/index`锛屽墠绔姩鎬佽矾鐢辫В鏋愬埌鍚屽悕 `.vue`銆�
+
+## 涓氬姟娴佺▼涓庢暟鎹甫鍏�
+
+1. **璁捐鍣� 鈫� 棰勮**锛氳璁″櫒鎶婂綋鍓嶇敾甯冧繚瀛樻垚鐗堟湰鍚庯紝鐢ㄣ�屽綋鍓嶇敾甯冨搴旂殑妯℃澘 + 鐗堟湰銆嶅姞涓�浠界ず渚嬫暟鎹皟鐢� `preview`锛�
+ 鎷垮埌 HTML 鐩存帴灞曠ず銆�**棰勮涓嶆秷鑰楁姤鍛婄紪鍙�**锛屽彲浠ュ弽澶嶈皟鐢紱**棰勮鎺ュ彈鑽夌鐗堟湰**锛堣銆屼笟鍔¤鍒欍�嶏級銆�
+2. **涓氬姟绯荤粺 鈫� 鍑轰欢**锛氳皟鐢ㄦ柟锛堟湰杞槸鎵嬪伐鏋勯�狅紝鍚庣画鏄� MES 璐ㄦ鍗曪級鍑嗗銆屾姤鍛婁笂涓嬫枃銆嶁啋 璋� `generate`
+ 鈫� 鍚庣娓叉煋銆佽惤搴撱�佸喕缁撴暟鎹揩鐓� 鈫� 杩斿洖瀹炰緥缂栧彿涓庢姤鍛婄紪鍙枫��
+3. **鍒楄〃 鈫� 璇︽儏**锛氬垪琛ㄦ嬁鍒� `id` 鈫� 璋� `get` 鍙� `renderHtml` 灞曠ず锛涢渶瑕佺湅銆屽綋鏃剁敤鐨勪粈涔堟暟鎹�嶅啀璋� `snapshot`銆�
+4. **璇︽儏 鈫� 閲嶆柊鐢熸垚**锛氳皟 `regenerate` 鐢�**鍐荤粨鐨勫揩鐓�**閲嶆覆锛岃鐩栦骇鐗� HTML銆傛暟鎹笌缂栧彿閮戒笉鍙樸��
+ **宸插綊妗g殑 PDF 浼氳涓�骞朵綔搴�**锛堣銆屼笟鍔¤鍒欍�嶏級銆�
+5. **璇︽儏 鈫� 瀵煎嚭 PDF**锛氱偣銆屽鍑� PDF銆嶈皟 `pdf` 鎺ュ彛 鈫� 鍚庣鎵撳嵃骞跺綊妗� 鈫� 鎺ュ彛杩斿洖鏈鐨勪笅杞藉湴鍧�锛堜复鏃剁鍚嶏級銆�
+ 椤甸潰瑕侀暱鏈熸樉绀恒�岃繖浠芥姤鍛婃湁 PDF銆嶈璋�**闄勪欢鍒楄〃鎺ュ彛**锛堣銆孭DF 褰掓。鎬庝箞鏌ャ�嶏級锛屼笉瑕佺紦瀛樻帴鍙h繑鍥炵殑绛惧悕鍦板潃銆�
+
+**甯﹀叆鍏崇郴瑕佺偣**
+
+- `templateId` 鏄富绾匡紝浠庢ā鏉垮垪琛ㄥ甫鍏ヨ璁″櫒銆佸啀甯﹀叆鍑轰欢銆�
+- `version` 鍙互涓嶄紶锛氫笉浼犳椂鍚庣鍙�**妯℃澘褰撳墠鐨勭増鏈�**锛坄currentVersion`锛夛紱涓�瀹氳鐢ㄦ煇涓壒瀹氱増鏈墠闇�瑕佹樉寮忎紶銆�
+ **璁捐鍣ㄩ瑙堝缓璁缁堟樉寮忎紶鐗堟湰**鈥斺�旇銆屼笟鍔¤鍒欍�嶉噷瀵� `currentVersion` 鐨勮鏄庛��
+- `reportNo` 鍙互涓嶄紶锛氫笉浼犳椂鐢卞悗绔寜 `QR + 鏃ユ湡 + 4 浣嶆祦姘碻 鑷姩鐢熸垚銆�
+- `businessId` / `businessType` 鍙仛鐣欑棔涓庢煡璇㈣繃婊わ紝鍚庣涓嶆牎楠屻�佷笉瑙f瀽瀹冩寚鍚戠殑鍗曟嵁銆�
+
+## API
+
+| 鏂规硶 | 璺緞 | 璇存槑 | 鏉冮檺鐮� |
+|---|---|---|---|
+| POST | `/qc-report/instance/preview` | 鍙覆鏌擄紝**涓嶈惤搴撱�佷笉鐢熸垚銆佷笉娑堣�楁姤鍛婄紪鍙�** | `qc-report:instance:query` |
+| POST | `/qc-report/instance/generate` | 娓叉煋 + 钀藉簱 + 鍐荤粨鏁版嵁蹇収 | `qc-report:instance:create` |
+| GET | `/qc-report/instance/get?id=` | 璇︽儏锛氬厓淇℃伅 + 娓叉煋浜х墿 HTML锛�**涓嶅惈**鏁版嵁蹇収锛� | `qc-report:instance:query` |
+| GET | `/qc-report/instance/snapshot?id=` | 鍙栧喕缁撶殑鏁版嵁蹇収 | `qc-report:instance:query` |
+| GET | `/qc-report/instance/page` | 鍒嗛〉 | `qc-report:instance:query` |
+| POST | `/qc-report/instance/regenerate?id=` | 鐢ㄥ喕缁撳揩鐓� + 鍚屼竴妯℃澘鐗堟湰閲嶆覆锛岃鐩栦骇鐗� HTML | `qc-report:instance:create` |
+| POST | `/qc-report/instance/pdf?id=` | **鎵撳嵃瀹炰緥宸插瓨鐨勪骇鐗� HTML 鎴� PDF 骞跺綊妗�**锛屽彲閲嶅璋冪敤 | `qc-report:instance:export` |
+| DELETE | `/qc-report/instance/delete?id=` | 鍒犻櫎瀹炰緥锛�**宸插綊妗g殑 PDF 涓�骞舵竻鐞�**锛� | `qc-report:instance:delete` |
+
+> 鉁� 鍓嶇瀹炰緥椤佃惤鍦版椂锛宍qc-report:instance:*` 鐨勮彍鍗曚笌鎸夐挳鏉冮檺**宸插悓姝ヨˉ鍏� `system_menu`**
+> 锛堣彍鍗曘�屾姤鍛婂疄渚嬨��+ 鏌ヨ/鍑轰欢/瀵煎嚭PDF/鍒犻櫎鍥涙潯鎸夐挳 + `qc-report:template:ai-import` 涓�鏉★級銆�
+> 鏈彃杩欎簺琛屼箣鍓嶏紝闈炶秴绠¤鑹茶皟杩欎簺鎺ュ彛浼� 403锛涜秴绠$敱浠g爜鐩磋繑鍏ㄩ儴鑿滃崟锛岃仈璋冧粠涓嶅彈褰卞搷銆�
+
+### 鍑轰欢 / 棰勮璇锋眰鍙傛暟锛坄preview` 涓� `generate` 鍚屼竴濂楋級
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|---|---|---|---|
+| `templateId` | Long | **鏄�** | 妯℃澘缂栧彿 |
+| `version` | String | 鍚� | 妯℃澘鐗堟湰鍙凤紝濡� `v1.0`銆備笉浼犲垯鍙栬妯℃澘鐨� `currentVersion` |
+| `reportNo` | String | 鍚� | 鎶ュ憡缂栧彿銆備紶浜嗗氨鐢ㄥ畠锛堟挒鍙蜂細鎶ラ敊锛夛紝涓嶄紶鐢卞悗绔嚜鍔ㄧ敓鎴� |
+| `businessId` | String | 鍚� | 涓氬姟鍗曟嵁缂栧彿锛屼粎鐣欑棔涓庢煡璇㈢敤 |
+| `businessType` | String | 鍚� | 涓氬姟鍗曟嵁绫诲瀷锛屽 `mes_qc_oqc`锛屼粎鐣欑棔涓庢煡璇㈢敤 |
+| `context` | Object | **鏄�** | 鎶ュ憡鏁版嵁锛岀粨鏋勮涓� |
+
+**`context` 缁撴瀯**锛堜笌璁捐鍣ㄩ噷鐨勬暟鎹绾﹀悓鏋勶級
+
+| 瀛楁 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|---|---|---|---|
+| `report` | Object | 鍚� | 鎶ュ憡绾у瓧娈点�傛樉寮忎紶 `null` 浼氳鍚庣鍏滄垚绌哄瓧娈甸泦锛屼笉浼氭姤閿� |
+| `report.reportNo` | String | 鍚� | 鎶ュ憡缂栧彿銆�**椤跺眰 `reportNo` 浼樺厛浜庡畠** |
+| `report.reportName` | String | 鍚� | 鎶ュ憡鍚嶇О |
+| `report.sampleNo` | String | 鍚� | 鏍峰搧缂栧彿 |
+| `report.productCode` | String | 鍚� | 浜у搧缂栫爜 |
+| `report.productName` | String | 鍚� | 浜у搧鍚嶇О |
+| `report.spec` | String | 鍚� | 瑙勬牸鍨嬪彿 |
+| `report.batchNo` | String | 鍚� | 鎵规鍙� |
+| `report.workOrderNo` | String | 鍚� | 宸ュ崟鍙� |
+| `report.inspectType` | String | 鍚� | 妫�楠岀被鍨� |
+| `report.inspector` | String | 鍚� | 妫�楠屽憳 |
+| `report.inspectDate` | String | 鍚� | 妫�楠屾棩鏈� |
+| `report.department` | String | 鍚� | 閮ㄩ棬 |
+| `report.customerName` | String | 鍚� | 瀹㈡埛鍚嶇О |
+| `report.supplierName` | String | 鍚� | 渚涘簲鍟嗗悕绉� |
+| `report.result` / `report.resultText` / `report.conclusion` / `report.passRate` | String | 鍚� | **鍒ゅ畾缁撴灉锛岀敱鍚庣绠楀嚭骞惰鐩�**锛岃皟鐢ㄦ柟涓嶇敤浼� |
+| `report.total` / `report.passCount` / `report.failCount` | Number | 鍚� | **鍚屼笂锛岀敱鍚庣绠楀嚭** |
+| `inspectionItems` | Array | **鏄�** | 妫�楠岄」鍒楄〃锛�**涓嶈兘涓虹┖**锛堢┖鏁扮粍浼氭姤閿欙紝瑙併�岄敊璇爜銆嶏級 |
+| `inspectionItems[].index` | Number | 鍚� | 搴忓彿锛屾覆鏌� `{{index}}` 鐢� |
+| `inspectionItems[].itemCode` | String | 鍚� | 妫�楠岄」缂栫爜 |
+| `inspectionItems[].itemName` | String | 鍚� | 妫�楠岄」鍚嶇О |
+| `inspectionItems[].standardValue` | String | 鍚� | 鏍囧噯鍊硷紙鏂囨湰锛屽 `10卤0.5`锛� |
+| `inspectionItems[].actualValue` | String | 鍚� | 瀹炴祴鍊� |
+| `inspectionItems[].unit` | String | 鍚� | 鍗曚綅 |
+| `inspectionItems[].upperLimit` / `lowerLimit` | Number | 鍚� | 瑙勬牸涓婁笅闄愩��**涓嶄紶灏辨槸娌℃湁瑙勬牸鍖洪棿**锛屽垽瀹氫細钀藉埌瑙勫垯鎴栨暟鎹嚜甯︾粨鏋滀笂 |
+| `inspectionItems[].result` / `resultText` | String | 鍚� | 鍒ゅ畾缁撴灉锛�**鐢卞悗绔畻鍑哄苟瑕嗙洊** |
+| `inspectionItems[].remark` | String | 鍚� | 澶囨敞 |
+
+**璇锋眰绀轰緥**
+
+```json
+{
+ "templateId": 5,
+ "version": "v1.0",
+ "businessId": "OQC20260918001",
+ "businessType": "mes_qc_oqc",
+ "context": {
+ "report": { "reportName": "鍑鸿揣妫�楠屾姤鍛�", "productName": "娉曞叞", "inspector": "寮犱笁" },
+ "inspectionItems": [
+ { "index": 1, "itemName": "澶栬", "standardValue": "鏃犲垝鐥�", "actualValue": "鍚堟牸" },
+ { "index": 2, "itemName": "闀垮害", "standardValue": "10卤0.5", "actualValue": 10.2, "upperLimit": 10.5, "lowerLimit": 9.5 }
+ ]
+ }
+}
+```
+
+### 鍝嶅簲瀛楁
+
+**`preview` 鍝嶅簲**
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|---|---|---|
+| `reportNo` | String | 鏈娓叉煋鐢ㄧ殑缂栧彿銆�**鏉ヨ嚜鍏ュ弬**锛屾病浼犲氨鏄┖ 鈥斺�� 棰勮涓嶇敓鎴愮紪鍙� |
+| `html` | String | 瀹屾暣 HTML 鏂囨。锛屽彲鐩存帴棰勮/鎵撳嵃 |
+| `errors` | Array\<String\> | 鏁版嵁缂哄彛娓呭崟锛岃涓� |
+
+**`generate` 鍝嶅簲**
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|---|---|---|
+| `id` | Long | 瀹炰緥缂栧彿锛屾嬁瀹冨幓鏌ヨ鎯� |
+| `reportNo` | String | 鏈�缁堢敓鏁堢殑鎶ュ憡缂栧彿锛堣嚜鍔ㄧ敓鎴愭垨鍏ュ弬鎸囧畾锛� |
+| `templateVersion` | String | 鏈浣跨敤鐨勬ā鏉跨増鏈彿 |
+| `status` | Number | 鎶ュ憡鐘舵�侊細`0` 鐢熸垚涓� / `1` 鐢熸垚鎴愬姛 / `2` 鐢熸垚澶辫触銆傚綋鍓嶅彧浼氳繑鍥� `1` |
+| `errors` | Array\<String\> | 鏁版嵁缂哄彛娓呭崟 |
+
+**`regenerate` 鍝嶅簲**
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|---|---|---|
+| `id` | Long | 瀹炰緥缂栧彿 |
+| `reportNo` | String | 鎶ュ憡缂栧彿锛堜笌鐢熸垚鏃剁浉鍚岋級 |
+| `errors` | Array\<String\> | 鏁版嵁缂哄彛娓呭崟 |
+
+**`pdf` 鍝嶅簲**
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|---|---|---|
+| `id` | Long | 瀹炰緥缂栧彿 |
+| `reportNo` | String | 鎶ュ憡缂栧彿 |
+| `fileName` | String | PDF 鏂囦欢鍚嶏紝瑙勫垯鏄� `<鎶ュ憡缂栧彿>.pdf`锛堝 `QR20260918-0001.pdf`锛� |
+| `byteSize` | Long | PDF 瀛楄妭鏁� |
+| `blobId` | Long | 鏂囦欢缂栧彿锛坄system_storage_blob` 涓婚敭锛� |
+| `attachmentId` | Long | 闄勪欢鍏宠仈缂栧彿锛坄system_storage_attachment` 涓婚敭锛� |
+| `previewURL` | String | 棰勮鍦板潃銆�**涓存椂绛惧悕锛屼細杩囨湡**锛屽埆瀛樿捣鏉ラ暱鏈熺敤 |
+| `downloadURL` | String | 涓嬭浇鍦板潃銆�**涓存椂绛惧悕锛屼細杩囨湡**锛屼笅杞藉姩浣滆鎷垮嵆鏃惰繑鍥炵殑杩欎釜鍊� |
+| `durationMs` | Long | 鏈鍑轰欢鎬昏�楁椂锛堟绉掞級锛屽惈鎺掗槦绛夊苟鍙戝悕棰濄�佸繀瑕佹椂閲嶅惎娴忚鍣ㄧ殑绛夊緟 |
+| `pdfDurationMs` | Long | 鎵撳嵃鑰楁椂锛堟绉掞級锛屼粎鍚瓑椤甸潰璧勬簮涓庢墦鍗般�備笌 `durationMs` 涔嬪樊灏辨槸绛夊緟鎴愭湰 |
+| `browserStatus` | String | `READY`锛堝鐢ㄤ簡宸插湪杩愯鐨勬祻瑙堝櫒锛�/ `RESTARTED`锛堟湰娆¢噸鍚簡娴忚鍣級銆�**浠呬緵鍙傝�冧笌鎺掓煡**锛屽墠绔笉闇�瑕佸垎鏀鐞� |
+
+> `pdf` 鏄�**鏄惧紡瑙﹀彂**鐨勶細鐢ㄦ埛鐐广�屽鍑� PDF銆嶆墠鐢熸垚銆傚畠涓嶄細闅� `generate` / `regenerate` 鑷姩璺戯紝
+> 鍥犱负姣忓涓�娆¢兘瑕佹媺璧� Chromium 鎵撳嵃锛堢绾э級锛屽嚭浠舵帴鍙d笉璇ヨ儗杩欎釜寮�閿�銆�
+
+**`get` 鍝嶅簲**锛歚id`銆乣reportNo`銆乣templateId`銆乣templateVersion`銆乣businessId`銆乣businessType`銆乣renderHtml`銆乣status`銆乣creator`銆乣createTime`銆乣updateTime`銆�
+**娉ㄦ剰涓嶅惈 `dataSnapshot`**锛堜綋绉ぇ涓斿垪琛�/璇︽儏鐢ㄤ笉鍒帮級锛岃瀹冭璋� `snapshot`銆�
+
+**`snapshot` 鍝嶅簲**锛歚{ "report": {...}, "inspectionItems": [...] }`锛屽嵆鍑轰欢褰撴椂鍐荤粨鐨勯偅浠芥暟鎹紙鍚畻濂界殑 PASS/FAIL 涓庡悎鏍肩巼锛夈��
+
+**`page` 璇锋眰鍙傛暟**锛堝叾浣欎负閫氱敤鍒嗛〉鍙傛暟 `pageNo` / `pageSize`锛�
+
+| 鍙傛暟 | 绫诲瀷 | 璇存槑 |
+|---|---|---|
+| `templateId` | Long | 妯℃澘缂栧彿锛岀簿纭尮閰� |
+| `reportNo` | String | 鎶ュ憡缂栧彿锛�**妯$硦鍖归厤** |
+| `businessType` | String | 涓氬姟鍗曟嵁绫诲瀷锛岀簿纭尮閰� |
+| `businessId` | String | 涓氬姟鍗曟嵁缂栧彿锛岀簿纭尮閰� |
+| `status` | Number | 鎶ュ憡鐘舵�侊紝绮剧‘鍖归厤 |
+| `createTime` | Array\<String\> | 鍒涘缓鏃堕棿鍖洪棿锛宍["寮�濮�","缁撴潫"]`锛屾牸寮� `yyyy-MM-dd HH:mm:ss` |
+
+### PDF 褰掓。鎬庝箞鏌ワ紙涓嶆柊澧炰笓鐢ㄦ煡璇㈡帴鍙o級
+
+鎶ュ憡瀹炰緥琛ㄩ噷**娌℃湁涔熶笉浼氭湁** `pdfUrl` / `pdfPath` 杩欑被瀛楁銆侾DF 缁熶竴閫氳繃 system 妯″潡鐨勯檮浠跺簱閲屾煡锛�
+璧扮殑鏄叏椤圭洰閫氱敤鐨勯檮浠舵帴鍙o紙ERP / CRM 椤甸潰鍚屾濮垮娍锛夛細
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|---|---|---|
+| GET | `/system/storage-attachment/list?recordType=qc_report_instance&recordId=<瀹炰緥缂栧彿>` | 鏌ヨ繖浠芥姤鍛婂綊妗g殑 PDF |
+
+| 鍙傛暟 | 鍊� | 璇存槑 |
+|---|---|---|
+| `recordType` | 鍥哄畾 `qc_report_instance` | 鎶ュ憡瀹炰緥鐨勮褰曠被鍨嬶紝鍐欐杩欎釜鍊� |
+| `recordId` | 鎶ュ憡瀹炰緥缂栧彿锛坄instance.id`锛� | |
+
+鍝嶅簲鏄竴涓暟缁勶紝姣忛」鍚� `url` / `previewURL` / `downloadURL` / `name` / `id`锛堥檮浠剁紪鍙凤級绛夈��
+**姝e父鎯呭喌鏁扮粍閲屾渶澶氫竴鏉�**锛堝啀娆″鍑轰細鏇挎崲鎺夋棫鐨勶紝涓嶄細瓒婂瓒婂锛夈��
+
+鍓嶇灞曠ず銆孭DF銆嶆寜閽殑閫昏緫寤鸿锛�
+
+1. 杩涜鎯呴〉鏃惰皟涓�娆¢檮浠跺垪琛ㄦ帴鍙o紝鏈夋暟鎹� 鈫� 鏄剧ず銆屼笅杞� PDF銆嶏紱娌℃湁 鈫� 鏄剧ず銆屽鍑� PDF銆嶃��
+2. 鐐广�屽鍑� PDF銆嶈皟 `pdf` 鎺ュ彛锛屾垚鍔熷悗鐢ㄨ繑鍥炵殑 `downloadURL` 鐩存帴涓嬭浇锛堟垨閲嶆柊鏌ヤ竴娆¢檮浠跺垪琛ㄥ埛鏂扮姸鎬侊級銆�
+3. **涓嶈鎶� `downloadURL` 瀛樿繘鍓嶇鐘舵�侀暱鏈熶娇鐢�**锛氬畠鏄甫绛惧悕鐨勪复鏃跺湴鍧�锛岃繃鏈熷悗浼� 401/403銆�
+
+## 瀛楁灞曠ず瑙勫垯
+
+| 瀛楁 | 灞曠ず浣嶇疆 | 璇存槑 |
+|---|---|---|
+| `reportNo` | 鍒楄〃鍒椼�佽鎯呭ご閮ㄣ�丠TML 鍐� | 鍒楄〃寤鸿鍔犮�屽鍒剁紪鍙枫�嶏紱**瀹冩槸涓氬姟鍞竴閿紝涓嶈兘閲嶅** |
+| `templateVersion` | 鍒楄〃鍒椼�佽鎯� | 寤鸿鏄剧ず鎴愩�屾ā鏉垮悕 v1.0銆嶏紱鍘嗗彶鎶ュ憡瑕佽兘鐪嬪嚭鐢ㄧ殑鏄摢涓�鐗� |
+| `businessType` / `businessId` | 鍒楄〃鍒椼�佽鎯� | 寤鸿鐢ㄥ瓧鍏告妸 `businessType` 杞垚涓枃锛堝 `mes_qc_oqc` 鈫� 鍑鸿揣妫�楠屽崟锛� |
+| `status` | 鍒楄〃鍒� | 鐢ㄥ瓧鍏� `qc_report_instance_status` 娓叉煋鏍囩锛堢敓鎴愪腑/鐢熸垚鎴愬姛/鐢熸垚澶辫触锛� |
+| `renderHtml` | 璇︽儏銆侀瑙� | 鐢� iframe 鎴栨暣鍧� HTML 瀹瑰櫒娓叉煋锛�**涓嶈鎶� HTML 褰撶函鏂囨湰灞曠ず** |
+| PDF 鏄惁瀛樺湪 | 璇︽儏椤点�屼笅杞� PDF / 瀵煎嚭 PDF銆嶆寜閽�佸垪琛ㄥ垪 | 鏁版嵁鏉ユ簮鏄檮浠跺垪琛ㄦ帴鍙o紙`recordType=qc_report_instance`锛夛紝涓嶆槸瀹炰緥琛ㄣ�俙regenerate` 涔嬪悗瑕佸埛鏂拌繖涓姸鎬� |
+| `creator` / `createTime` | 鍒楄〃鍒椼�佽鎯� | 鈥� |
+| `errors` | 鍑轰欢/棰勮/閲嶆柊鐢熸垚鍚� | **鐢ㄥ彲鎶樺彔闈㈡澘鎴栨彁绀烘潯灞曠ず**锛屼笉瑕侀潤榛樹涪寮冿紝瑙併�屼笟鍔¤鍒欍�� |
+
+## 涓氬姟瑙勫垯璇存槑
+
+| 鍦烘櫙 | 瑙勫垯 |
+|---|---|
+| **鎶ュ憡缂栧彿璋佺敓鎴�** | 鍚庣銆傛牸寮� `QR + yyyyMMdd + '-' + 4 浣嶆祦姘碻锛堝 `QR20260918-0001`锛夛紝**鎸夊ぉ鐙珛锛岃法澶╀粠 0001 閲嶆潵**銆備紶鍏� `reportNo` 鍙鐩� |
+| **鎸囧畾缂栧彿鎾炲彿** | 鎶ラ敊骞�**鎸囨槑鏄摢涓紪鍙�**锛堜笉鏄缁熴�岀紪鍙峰凡瀛樺湪銆嶏級銆傝涔堟崲缂栧彿锛岃涔堢暀绌鸿鍚庣鐢熸垚 |
+| **棰勮涓嶆秷鑰楀簭鍙�** | `preview` 鍙覆鏌擄紝涓嶈惤搴撱�佷笉鍙栨祦姘村彿銆傚彲浠ュ弽澶嶇偣棰勮锛屼笉浼氭妸褰撳ぉ鐨勭紪鍙疯烦鍙� |
+| **鍒犳帀鐨勭紪鍙蜂笉浼氳閲嶇敤** | 鍒犻櫎鎶ュ憡鏄蒋鍒犻櫎锛岀紪鍙蜂粛鐒跺崰浣嶏紝褰撳ぉ鐨勬祦姘�**鍙涓嶅噺**銆傚垹鎺� `鈥�-0001` 涔嬪悗涓嬩竴浠芥槸 `鈥�-0002`锛�**涓嶄細鍥炲埌 0001**銆傚墠绔笉瑕佸亣璁俱�岀紪鍙疯繛缁�� |
+| **鐢ㄥ摢涓増鏈紙鍑轰欢锛�** | `generate` **瑕佹眰鐗堟湰宸插彂甯�**锛岃崏绋夸細琚嫆锛坄1_070_101_003`锛夈�傚嚭浠朵細鎶婄増鏈彿鍐荤粨杩涘疄渚嬨�佽�屽疄渚嬪苟涓嶅瓨鍐呭锛岀敤鑽夌鍑轰欢绛変簬缁欏巻鍙叉姤鍛婂煁涓�棰椼�岀増鏈彿瀵瑰緱涓娿�佸唴瀹瑰凡缁忓彉浜嗐�嶇殑闆� |
+| **鐢ㄥ摢涓増鏈紙棰勮锛�** | `preview` **鎺ュ彈鑽夌鐗堟湰锛屼篃鎺ュ彈宸插仠鐢ㄧ増鏈�**锛屽彧瑕佺増鏈瓨鍦ㄤ笖鏈夌敾甯冨唴瀹瑰嵆鍙�傝璁″櫒鐨勪富娴佺▼灏辨槸銆屼繚瀛樿崏绋� 鈫� 鐐归瑙堛�嶏紝鑽夌浼氬彉鍦ㄩ瑙堣繖閲屾病鏈夊悗鏋滐紙涓嶈惤搴撱�佷笉鍐荤粨鏁版嵁銆佷笉娑堣�楃紪鍙凤級 |
+| **`currentVersion` 涓虹┖鏃�** | 涓嶄紶 `version` 涓旀ā鏉� `currentVersion` 涓虹┖ 鈫� `1_070_101_007`銆�**姝ゆ椂 `preview` 涔熸嬁涓嶅埌鐗堟湰**锛岃璁″櫒棰勮蹇呴』鏄惧紡浼� `version`锛堝鍒氫繚瀛樼殑鑽夌 `v1.1`锛� |
+| **鏁版嵁蹇収鍐荤粨** | 鍑轰欢鏃舵妸銆屽垽瀹氬悗鐨勬暟鎹�嶆暣浠藉喕缁撹繘瀹炰緥銆備笟鍔$郴缁熼噷鐨勬暟鎹悗鏉ユ�庝箞鍙橈紝**閮戒笉褰卞搷杩欎唤鍘嗗彶鎶ュ憡** |
+| **閲嶆柊鐢熸垚鍔ㄧ殑鏄粈涔�** | 鍙噸娓�**鎺掔増浜х墿**锛岀敤鐨勬槸**瀹炰緥閲屽喕缁撶殑蹇収**涓�**鍚屼竴涓ā鏉跨増鏈�**銆傛暟鎹�佹姤鍛婄紪鍙烽兘涓嶅彉 |
+| **閲嶆柊鐢熸垚涓嶈姹傜増鏈粛宸插彂甯�** | 鐗堟湰鍚庢潵琚仠鐢紝鍘嗗彶鎶ュ憡涔熶笉鑳藉洜姝ゆ墦涓嶅紑锛屾墍浠� `regenerate` 鍏佽鐢ㄥ凡鍋滅敤鐨勭増鏈� |
+| **鍒ゅ畾缁撴灉鐢卞悗绔畻** | `result` / `resultText` / `conclusion` / `passRate` / `total` / `passCount` / `failCount` 涓�寰嬩互**鍚庣绠楀嚭鐨�**涓哄噯锛岃皟鐢ㄦ柟浼犱簡涔熶細琚鐩� |
+| **`result` 涓� `resultText` 鍒嗗伐** | `result` 鏄満鍣ㄥ�硷紙`PASS` / `FAIL` / 绌哄瓧绗︿覆锛夛紝`resultText` 鏄粰浜虹湅鐨勪腑鏂囷紙鍚堟牸 / 涓嶅悎鏍� / 寰呭垽瀹氾級銆�**鐢诲竷涓婃樉绀虹殑鏄� `resultText`**锛屾墍浠ヤ骇鐗� HTML 閲屾悳涓嶅埌 `PASS` 瀛楁牱锛屽埆鎹浠ヤ负娌″垽瀹� |
+| **鏃犳硶鍒ゅ畾鐨勯」** | 鏃㈡病鏈夎鏍间笂涓嬮檺銆佷篃娌℃湁鍛戒腑浠讳綍瑙勫垯鐨勬楠岄」 鈫� `result` 涓虹┖銆乣resultText` 涓� `寰呭垽瀹歚锛�**涓嶈鍏� `passCount`/`failCount` 浣嗚鍏� `total`**锛屾墍浠ュ彲鑳藉嚭鐜� `total=3 pass=1 fail=1`锛堝悎鏍肩巼鎸� `pass/total` 绠楋級銆傚悓鏃跺畠浼氬嚭鐜板湪 `errors` 閲岋紙濡傘�岀 1 椤广�屽瑙傘�嶆病鏈夎鏍间笂涓嬮檺涔熸病鏈夊垽瀹氳鍒欙紝鏃犳硶鍒ゅ畾銆嶏級 |
+| **鏁版嵁缂哄彛娓呭崟** | 妯℃澘缁戝畾浜嗕絾鏁版嵁閲屾病鏈夌殑瀛楁銆佷互鍙婅瀹夊叏绛栫暐鎷︿笅鐨勬ā鏉垮睘鎬э紝閮戒細鍑虹幇鍦� `errors` 閲屻��**瀹冨彧鍦� preview/generate/regenerate 鐨勫搷搴旈噷鍑虹幇锛屼笉钀藉簱** 鈥斺�� 浜嬪悗鍥炵湅鍘嗗彶鎶ュ憡鏃�**鐪嬩笉鍒�**褰撴椂鏈夊摢浜涘瓧娈电己鍊笺�傞渶瑕佺暀鐥曡鍦ㄥ嚭浠舵椂鑷璁板綍 |
+| **PDF 鎵撶殑鏄摢浠� HTML** | 鎵撶殑鏄�**瀹炰緥閲屽凡缁忓瓨鐫�鐨勯偅浠� HTML**锛屼笉閲嶆柊娓叉煋銆傛墍浠ャ�岃鎯呴〉鐪嬪埌鐨勩�嶄笌銆屾墦鍑烘潵鐨勩�嶅繀鐒跺嚭鑷悓涓�浠藉瓧鑺傦紝**涓嶄細鍑虹幇椤甸潰涓婂ソ濂界殑銆佹墦鍑烘潵鍙樺舰** |
+| **閲嶆覆鍗充綔搴熷凡褰掓。 PDF** | 璋� `regenerate` 涔嬪悗锛屼箣鍓嶅鍑虹殑 PDF **浼氳浣滃簾**锛堥檮浠跺垪琛ㄤ細鍙樻垚绌猴級銆傚師鍥狅細浜х墿 HTML 鎹簡锛屽啀鐣欑潃鏃� PDF 灏辨槸銆岄〉闈㈡槸鏂版帓鐗堛�佷笅杞藉埌鐨勬槸鏃ф枃浠躲�嶇殑闈欓粯涓嶄竴鑷淬��**鍓嶇鍦� `regenerate` 鎴愬姛鍚庤鎶娿�屼笅杞� PDF銆嶆寜閽仮澶嶆垚銆屽鍑� PDF銆�** |
+| **PDF 绾搁潰涓庨〉闈㈤瑙堜竴鑷�** | A4/A3/A5/Letter銆佹í绔栧悜銆侀〉杈硅窛閮藉彇鑷ā鏉跨殑绾稿紶閰嶇疆锛屼笌 HTML 閲� `@page` 鐢ㄧ殑鏄悓涓�浠芥暟瀛楋紝涓嶅瓨鍦ㄣ�岄瑙� 210mm銆丳DF 鎵� 210.5mm銆嶈繖绫绘紓绉� |
+| **PDF 鏄�"鏄惧紡鐢熸垚"鐨�** | 鍙湁璋� `pdf` 鎺ュ彛鎵嶄細鏈� PDF銆俙generate` / `regenerate` 閮戒笉浼氶『甯︾敓鎴� PDF |
+| **閲嶅瀵煎嚭鏄畨鍏ㄧ殑** | 鍐嶅涓�娆′細鏇挎崲鎺夋棫鐨勫綊妗o紙闄勪欢浠嶆槸 1 鏉★級锛屼笉浼氳秺瀵艰秺澶氥�佷篃涓嶄細鐣欏鍎挎枃浠躲��**鍙互鏀惧績璁╃敤鎴烽噸澶嶇偣** |
+| **鍑轰欢寰堟參鏃跺厛鍛婅瘔鐢ㄦ埛** | 棣栨瀵煎嚭鎴栨祻瑙堝櫒鍒氬穿杩囪閲嶅惎鏃堕渶瑕佸嚑绉掞紝鎺ュ彛鍦� `durationMs` 閲屽瀹炶繑鍥炪�傚墠绔缓璁偣鎸夐挳鍚庤浆鍦堢洿鍒板搷搴旓紝涓嶈鑷繁璁惧畾鏃跺櫒鍒よ秴鏃� |
+| **骞跺彂涓婇檺** | 鏈嶅姟绔悓鏃惰繘琛岀殑 PDF 鎵撳嵃鏈変笂闄愶紙榛樿 2锛夛紝鎺掗槦瓒呰繃 30 绉掍細杩斿洖 `1_070_103_007`銆傛壒閲忓鍑烘椂涓嶈骞跺彂鐚涙墦锛屼覆琛屾垨灏忓苟鍙� |
+| **鍗曚唤鎶ュ憡鏂囦欢澶氶〉** | 闀挎姤鍛婏紙妫�楠岄」澶氾級浼氳嚜鍔ㄥ垎椤碉紝`printBackground` 宸插紑锛屽垽瀹氬簳鑹蹭細鎵撳嚭鏉ワ紱琛ㄥご璺ㄩ〉閲嶅 |
+| **PDF 鍔熻兘鍙杩愮淮鍏虫帀** | 閮ㄧ讲鐜娌℃祻瑙堝櫒鏃朵細鍏虫帀锛坄yudao.qcreport.pdf.enabled=false`锛夛紝姝ゆ椂 `pdf` 鎺ュ彛杩斿洖 `1_070_103_008`銆傚墠绔簲鍘熸牱鎻愮ず锛屼笉瑕佸綋鎴愮郴缁熷紓甯� |
+| **鍒犻櫎瀹炰緥** | 杞垹闄ゃ�傚垹鎺夊悗 `get` 杩斿洖 `null`锛堜笉鎶ラ敊锛夛紝鍓嶇瑕佸厹绌恒��**宸插綊妗g殑 PDF 浼氫竴骞舵竻鐞�** |
+| **妯℃澘鍋滅敤** | 鍋滅敤鐨勬ā鏉�**涓嶈兘鍑烘柊浠�**锛涘凡鏈夊巻鍙叉姤鍛婁笉鍙楀奖鍝� |
+
+## 娉ㄦ剰浜嬮」
+
+- **鍒楄〃/璇︽儏涓嶈灞曠ず `dataSnapshot` 瀛楁**锛歚get` 涓� `page` 閮戒笉杩斿洖瀹冿紝杩欐槸鏈夋剰鐨勶紙浣撶Н澶э級銆�
+- **`get` 瀵瑰凡鍒犻櫎鐨勫疄渚嬭繑鍥� `data:null`**锛屼笉鏄姤閿欍�傛墍鏈夋寜 `id` 鍙栬鎯呯殑鍏ュ彛閮借鍒ょ┖銆�
+- **HTML 娓叉煋瑕佹敞鎰忔牱寮忛殧绂�**锛氫骇鐗╂槸瀹屾暣 HTML 鏂囨。锛堣嚜甯� `@page` 涓庢牱寮忥級锛�
+ 鐩存帴濉炶繘椤甸潰浼氭薄鏌撳叏灞�鏍峰紡锛屽缓璁敤 `iframe` 鎵胯浇銆�
+- **棰勮鍝嶅簲閲岀殑 `reportNo` 鍙兘涓虹┖**锛岃繖鏄甯哥殑锛堥瑙堜笉鐢熸垚缂栧彿锛夛紝涓嶈鎷垮畠褰撳嚭浠剁粨鏋溿��
+- **`inspectionItems` 涓嶈兘浼犵┖鏁扮粍**锛氭病鏈夋楠岄」鐨勩�屾姤鍛娿�嶆病鏈夋剰涔夛紝鍚庣浼氱洿鎺ユ姤閿欍��
+- **`businessId` 涓嶄細鏄暟瀛楃被鍨�**锛氳櫧鐒惰〃閲屾槸 `varchar`锛屼絾璋冪敤鏂圭粰鐨勫彲鑳芥槸宸ュ崟鍙枫�佹壒娆″彿涓�绫荤殑瀛楃涓诧紝鍓嶇鍒寜 Long 澶勭悊銆�
+- **`errors` 鍙兘寰堥暱**锛屽挨鍏舵ā鏉垮垰鍋氬ソ鏃躲�傚缓璁姌鍙犲睍绀� + 鏄剧ず鏉℃暟銆�
+- **鏉冮檺**锛氭帴鍙f潈闄愮爜鏄� `qc-report:instance:query` / `:create` / `:delete` / `:export`銆�
+ 宸插叆搴撳埌 `system_menu`锛堣銆孉PI銆嶈妭涓嬬殑璇存槑锛夈�俙create` 鏄�**棰勭疆**鐨勶細鏈疆椤甸潰娌℃湁鍑轰欢鍏ュ彛锛�
+ 瀹冩槸缁欏悗缁� `MesQcReportApi` 杞噯澶囩殑锛屼笉鏄仐婕忋��
+- **銆孉I 瀵煎叆銆嶆寜閽敤鐙珛鏉冮檺鐮� `qc-report:template:ai-import`**锛氳兘鏀规ā鏉夸笉绛変簬鑳界敤澶фā鍨嬭瘑鍒枃浠�
+ 锛堟瘡娆¤皟鐢ㄩ兘浜х敓璐圭敤锛夛紝涓よ�呭繀椤诲垎寮�鎺堟潈锛屼笉鑳藉悎骞跺埌妯℃澘鐨勭紪杈戞潈闄愰噷銆�
+- **棰勮蹇呴』 `sandbox=""`**锛堢┖灞炴�э紝涓嶆槸鐪佺暐璇ュ睘鎬э級锛氱┖鍊� = 瀹屽叏绂佺敤鑴氭湰銆佽〃鍗曚笌鍚屾簮锛屽彧璁� CSS 鐢熸晥銆�
+ 浜х墿 HTML 鏄覆鏌撶粨鏋滐紝涓嶉渶瑕佷篃涓嶅簲璇ヨ瀹冩墽琛屼换浣曚笢瑗裤��
+- **閲嶅瀵煎嚭涓嶅爢鏂囦欢宸插疄娴�**锛氬悓涓�瀹炰緥杩炵偣 3 娆★紝搴撲腑濮嬬粓鍙湁 1 鏉℃湁鏁堥檮浠�
+ 锛堝墠涓ゆ潯闄勪欢琛屼笌 blob 琛屽潎涓� `deleted=1`锛夛紝纾佺洏鐩綍閲屼篃鍙暀褰撳墠杩欎竴浠� PDF銆�
+- **瀵煎嚭鐨� PDF 涓枃渚濊禆鏈嶅姟鍣ㄧ殑瀛椾綋**锛氬紑鍙戞満锛圵indows锛夎嚜甯﹀井杞泤榛戞病闂锛�
+ 鐢熶骇 Linux 鏈嶅姟鍣ㄨ嫢娌¤ CJK 瀛椾綋浼氭墦鎴愭柟妗嗐�傝繖灞炰簬閮ㄧ讲鍓嶇疆锛屽墠绔笉闇�瑕佸鐞嗭紝浣�**楠屾敹鏃惰鍦ㄧ洰鏍囩幆澧冧笂鐪嬩竴鐪间腑鏂�**銆�
+- **`pdf` 鎺ュ彛鐨勮繑鍥炲湴鍧�鏄鍚嶇殑涓存椂鍦板潃**锛屽甫杩囨湡鏃堕棿涓庝娇鐢ㄦ鏁伴檺鍒讹紝
+ **涓嶈**鎶婂畠鍐欒繘鏁版嵁搴撱�佷篃涓嶈鏀捐繘鍒楄〃鎺ュ彛缂撳瓨锛岄渶瑕佹椂閲嶆柊鏌ラ檮浠跺垪琛ㄦ垨閲嶆柊瀵煎嚭銆�
+- **闄勪欢鍒楄〃閲岀殑 `name` 鏄� PDF 鏂囦欢鍚�**锛坄QR20260918-0001.pdf`锛夛紝涓嬭浇鏃剁敤瀹冨懡鍚嶅嵆鍙��
+
+## 閿欒鐮�
+
+| 閿欒鐮� | 鎶ユ枃 | 瑙﹀彂鍦烘櫙 |
+|---|---|---|
+| `1_070_100_000` | 妯℃澘涓嶅瓨鍦� | `templateId` 鎵句笉鍒� |
+| `1_070_100_002` | 璇ユā鏉垮凡鍋滅敤锛屼笉鑳界敓鎴愭姤鍛� | 妯℃澘 `status=1` |
+| `1_070_101_000` | 妯℃澘鐗堟湰涓嶅瓨鍦� | `version` 浼犱簡浣嗘煡涓嶅埌 |
+| `1_070_101_003` | 璇ユā鏉跨増鏈湭鍙戝竷 | `generate` 鐨� `version` 鎸囧悜鑽夌锛�**`preview` 涓嶆姤杩欎釜閿�**锛� |
+| `1_070_101_007` | 璇ユā鏉胯繕娌℃湁宸插彂甯冪殑鐗堟湰锛屾棤娉曠敓鎴愭姤鍛婏紝璇峰厛鍦ㄨ璁″櫒涓彂甯冧竴涓増鏈� | 涓嶄紶 `version` 涓旀ā鏉� `currentVersion` 涓虹┖锛坄preview` 鍚屾牱浼氭姤锛屾鏃堕』鏄惧紡浼� `version`锛� |
+| `1_070_101_008` | 璇ユā鏉跨増鏈病鏈夌敾甯冨唴瀹癸紝鏃犳硶鐢熸垚鎶ュ憡锛岃鍏堝湪璁捐鍣ㄤ腑璁捐骞朵繚瀛樻ā鏉垮唴瀹� | 鐗堟湰鏈夎褰曚絾鐢诲竷鏄┖鐨� |
+| `1_070_102_000` | 鎶ュ憡瀹炰緥涓嶅瓨鍦� | `id` 鎵句笉鍒帮紙`get` 闄ゅ锛屽畠杩斿洖 null锛� |
+| `1_070_102_001` | 鎶ュ憡缂栧彿銆孹銆嶅凡琚崰鐢紝璇锋崲涓�涓紪鍙凤紝鎴栫暀绌虹敱绯荤粺鎸� QR+鏃ユ湡+娴佹按 鑷姩鐢熸垚 | 鎸囧畾浜嗛噸澶嶇紪鍙枫��**鍚凡琚蒋鍒犻櫎鐨勭紪鍙�**锛堝垹鎺夌殑鍙蜂笉鍥炴敹锛� |
+| `1_070_102_001` | 鑷姩鐢熸垚鎶ュ憡缂栧彿鏃惰繛缁� 5 娆′笌宸叉湁鎶ュ憡鍐茬獊锛岃绋嶅悗閲嶈瘯锛涗篃鍙湪璇锋眰閲屾樉寮忔寚瀹氫竴涓湭琚崰鐢ㄧ殑鎶ュ憡缂栧彿 | 浠呭湪鍚屼竴鏃跺埢鏈夊涓嚭浠惰姹傛姠鍚屼竴涓祦姘村彿鏃跺嚭鐜帮紱姝e父浣跨敤涓嶅簲鐪嬪埌 |
+| `1_070_102_002` | 鎶ュ憡瀹炰緥缂哄皯鏁版嵁蹇収锛屾棤娉曢噸鏂扮敓鎴� | 蹇収涓虹┖鐨勮剰鏁版嵁 |
+| `1_070_102_003` | 鎶ュ憡瀹炰緥娌℃湁娓叉煋浜х墿 HTML锛屾棤娉曠敓鎴� PDF锛岃鍏堝璇ユ姤鍛婃墽琛屻�岄噸鏂扮敓鎴愩�� | `pdf` 鏃跺疄渚嬬殑 `render_html` 涓虹┖锛堣剰鏁版嵁锛夈��**鎻愮ず閲屽凡缁欏嚭鍔ㄤ綔锛氬厛銆岄噸鏂扮敓鎴愩��** |
+| `1_070_103_004` | PDF 娓叉煋娴忚鍣ㄥ惎鍔ㄥけ璐ワ紝璇锋鏌� Chromium 鏄惁宸插畨瑁� | 鏈嶅姟鍣ㄦ病瑁� Chrome / 閰嶇疆鐨� `executable-path` 涓嶅銆傛姤鏂囬噷浼氬甫涓婂綋鍓嶉厤缃殑娴忚鍣ㄦ潵婧愪笌瀹為檯鍘熷洜 |
+| `1_070_103_005` | PDF 鐢熸垚澶辫触 | 鎵撳嵃杩囩▼涓祻瑙堝櫒鎶ラ敊锛堝惈绛夐〉闈㈣祫婧愯秴鏃讹級 |
+| `1_070_103_006` | PDF 宸茬敓鎴愶紝浣嗗綊妗e埌闄勪欢搴撳け璐� | 鎵撳嵃鎴愬姛銆佸瓨妗eけ璐ャ��**娉ㄦ剰瀹冧笉绛変簬銆孭DF 娌$敓鎴愩��**锛屽墠绔殑鎻愮ず鏂囨涓嶈鍐欐垚銆岀敓鎴愬け璐ャ�� |
+| `1_070_103_007` | 褰撳墠 PDF 娓叉煋浠诲姟宸茶揪涓婇檺锛岃绋嶅悗閲嶈瘯 | 骞跺彂鎺掗槦瓒呰繃 30 绉掋�傛姤鏂囬噷甯﹀綋鍓嶅苟鍙戜笂闄愬�� |
+| `1_070_103_008` | PDF 鍑轰欢鍔熻兘鏈惎鐢紝璇疯仈绯荤鐞嗗憳 | 杩愮淮鎶� `yudao.qcreport.pdf.enabled` 鍏虫垚浜� `false` |
+| `1_070_103_000` | 妫�楠岄」鍒楄〃涓虹┖锛屾病鏈夊彲鍒ゅ畾鐨勫唴瀹癸細璇疯嚦灏戜紶鍏ヤ竴涓楠岄」锛坕nspectionItems锛夊啀鍑轰欢 | `inspectionItems` 涓虹┖ |
diff --git a/docs/qc_report_template_version_frontend_integration.md b/docs/qc_report_template_version_frontend_integration.md
new file mode 100644
index 0000000..2b43e57
--- /dev/null
+++ b/docs/qc_report_template_version_frontend_integration.md
@@ -0,0 +1,124 @@
+# 鎶ュ憡妯℃澘鐗堟湰绠$悊 - 鍓嶇鑱旇皟鏂规锛堜繚瀛樻牎楠� + 鍋滅敤绾︽潫锛�
+
+## 娑夊強椤甸潰
+
+- 鎶ュ憡妯℃澘璁捐鍣紙淇濆瓨 / 鍙﹀瓨鏂扮増鏈紝璧� `create` 涓� `update`锛�
+- 鎶ュ憡妯℃澘璇︽儏 鈫� 鐗堟湰鍒楄〃锛堝彂甯� / 鍥炴粴 / 鍋滅敤锛�
+
+## 鏈鍙樻洿姒傝堪
+
+`qc_report_template_version` 鐨勫啓鍏ュ彛鏂板涓ゆ潯**鎷掔粷瑙勫垯**锛屽悇瀵瑰簲涓�涓柊閿欒鐮併��
+涓ゆ潯閮戒笉鏄柊澧炲瓧娈点�佷篃涓嶆槸鏂板鎺ュ彛锛岃�屾槸鎶娿�屼互鍓嶄細闈欓粯瀛樹笅 / 瀛樹笅鍚庢墠鐐搞�嶇殑鎯呭喌鏀规垚**褰撳満鎶ラ敊**銆�
+鍓嶇闇�瑕佸仛鐨勬槸锛氭妸鍚庣杩斿洖鐨� `msg` 鍘熸牱灞曠ず锛堟枃妗堝凡鍙洿鎺ョ粰鐢ㄦ埛鐪嬶級锛屽苟淇濊瘉杩欎袱绉嶅け璐�**涓嶅脊閫氱敤銆岀郴缁熷紓甯搞��**銆�
+
+| 鎺ュ彛 | 鏂规硶 | 鏂板鎷掔粷瑙勫垯 | 閿欒鐮� |
+|---|---|---|---|
+| `/qc-report/template-version/create` | POST | 鐢诲竷鍚笉鍏佽娓叉煋鐨勫唴瀹� | `1_070_101_009` |
+| `/qc-report/template-version/update` | PUT | 鍚屼笂 | `1_070_101_009` |
+| `/qc-report/template-version/disable` | POST | 鐩爣鏄ā鏉跨殑**褰撳墠鐗堟湰** | `1_070_101_010` |
+
+> `create` 涓� `update` 鍏辩敤鍚屼竴娈� Schema 鏍¢獙锛屼袱鏉″叆鍙h涓轰竴鑷达細**鍙鎻愪氦鐨� Schema 涓嶅悎鏍硷紝涓�寰嬩笉钀藉簱**銆�
+
+## 瑙勫垯涓�锛氱敾甯冨唴瀹瑰畨鍏ㄦ牎楠岋紙`1_070_101_009`锛�
+
+### 鎸$殑鏄粈涔�
+
+鎶ュ憡浜х墿鏄嫾瀛楃涓叉嫾鍑烘潵鐨勶紝妯℃澘鐢诲竷閲屾湁涓夊鍐呭浼�**涓嶇粡杞箟**鐩存帴杩涘叆 HTML锛�
+
+1. **鑺傜偣鐨勬爣绛惧悕**锛堝 `tagName: "h2"`锛夛紱
+2. **灞炴�у悕**锛堝睘鎬�**鍊�**浼氳浆涔夛紝灞炴��**鍚�**涓嶄細锛夛紱
+3. **鏁存 CSS**锛坄styles` 鍐欐垚瀛楃涓叉椂浼氳鍘熸牱濉炶繘 `<style>`锛夈��
+
+妯℃澘鐢诲竷鍙堟槸鐢ㄦ埛鍙紪杈戞暟鎹紝鎵�浠ヨ繖涓夊閮芥槸鍙鍐欏叆鐨勬敞鍏ラ潰銆�
+
+### 鏍¢獙瑙勫垯
+
+| 缁村害 | 瑙勫垯 |
+|---|---|
+| 鏍囩鍚� | 蹇呴』钀藉湪鐧藉悕鍗曞唴锛氬父瑙勬帓鐗堜笌鏂囨湰鏍囩锛坄div/p/span/h1~h6/img/hr`銆佽〃鏍间竴鏃忋�佸垪琛ㄤ竴鏃忋�佸父瑙佽鍐呰涔夋爣绛撅級銆傝剼鏈�佹牱寮忋�佸唴宓岄〉闈€�佽〃鍗曠被鏍囩涓�寰嬫嫆缁� |
+| 鏍囩鍚� | 闇�**鏁翠綋**鍖归厤鐧藉悕鍗曪紝`"img src=x onerror=alert(1)"` 杩欑銆屾爣绛惧悕閲屽灞炴�с�嶇殑鍐欐硶浼氳鎷� |
+| 灞炴�у悕 | 鍙厑璁稿瓧姣� / 鏁板瓧 / `-` `_` `:` `.`锛屼笖涓嶈兘浠ユ暟瀛楀紑澶达紱鍚紩鍙锋垨绌烘牸鐨勫睘鎬у悕浼氳鎷掞紙瀹冭兘椤跺嚭涓�涓柊灞炴�э級 |
+| 灞炴�у悕 | 浠� `on` 寮�澶寸殑涓�寰嬭涓轰簨浠跺睘鎬э紝鎷掔粷 |
+| `styles` | 蹇呴』鏄�**鏍峰紡瑙勫垯鏁扮粍**锛涘啓鎴愪竴娈� CSS 鏂囨湰浼氳鎷掞紙鏀规牱寮忚蛋璁捐鍣ㄧ殑鏍峰紡闈㈡澘锛屼繚瀛樺悗鑷劧鏄鍒欐暟缁勶級 |
+| `selectors` / `mediaText` / 鏍峰紡灞炴�у悕涓庡睘鎬у�� | 鍑虹幇 `<` 鍗虫嫆缁濓紙`</style>` 鑳芥彁鍓嶉棴鍚堟牱寮忓潡锛屾妸鍚庨潰鐨勫唴瀹瑰彉鎴愮湡 HTML锛� |
+
+### 涓嶄細璇潃鐨勪笁绉嶆儏鍐�
+
+璁捐鍣ㄦ甯镐繚瀛樼殑鐢诲竷**涓嶄細**琚嫤锛屼互涓嬩笁绫诲湪瀹炵幇閲岃鏄庣‘鎺掗櫎锛屽墠绔棤闇�鐗规畩澶勭悊锛�
+
+- **`textnode` 鑺傜偣涓婄殑 `tagName`**锛氭覆鏌撳櫒鏍规湰涓嶈瀹冿紱
+- **GrapesJS 鎸傚湪鑺傜偣涓婄殑 `docEl` / `head` 鍏冩暟鎹�**锛氭覆鏌撳櫒涓嶈锛屾牎楠屼篃鍙部 `components` 璧帮紱
+- **瀛橀噺鐢诲竷**锛氬凡瀵硅繍琛屽簱涓叏閮ㄧ湡瀹炵増鏈疄娴嬮�氳繃銆�
+
+### 鎶ラ敊鏂囨
+
+涓�娆℃渶澶氳繑鍥� **8 鏉�**闂锛屾瘡鏉¢兘甯�**浣嶇疆**涓�**杩濊鍐呭**锛屽舰濡傦細
+
+```
+妯℃澘鐢诲竷閲屾湁涓嶅厑璁稿嚭鐜扮殑鍐呭锛屽凡鎷掔粷淇濆瓨锛氱敾甯冦�屾牴 > 绗� 1 涓粍浠躲�嶇殑鏍囩鏄�宻cript銆嶏紝
+鎶ュ憡涓嶆敮鎸佽鏍囩銆傚彲鐢ㄧ殑鍙湁甯歌鎺掔増鏍囩锛坉iv/p/span/h1~h6/img/hr 涓庤〃鏍笺�佸垪琛ㄣ�佽鍐呮枃鏈爣绛撅級锛�
+鑴氭湰銆佹牱寮忋�佸唴宓岄〉闈€�佽〃鍗曠被鏍囩涓�寰嬩笉鍏佽銆傝鍦ㄨ璁″櫒涓垹鎺夎繖浜涘唴瀹瑰悗閲嶆柊淇濆瓨
+```
+
+澶氭潯闂浠� `锛沗 杩炴帴銆傛敼瀹屽啀淇濆瓨涓�娆″嵆鍙湅鍒颁笅涓�鎵广��
+
+## 瑙勫垯浜岋細涓嶈兘鍋滅敤銆屽綋鍓嶇増鏈�嶏紙`1_070_101_010`锛�
+
+### 鎸$殑鏄粈涔�
+
+妯℃澘琛ㄤ笂鐨� `current_version` 鎸囧悜銆屽嚭浠舵椂榛樿鐢ㄥ摢涓増鏈�嶃��
+鍋滅敤鏌愪釜鐗堟湰**涓嶄細**娓呯┖ `current_version`锛屼簬鏄仠鐢ㄥ綋鍓嶇増鏈細閫犲嚭涓�浠�**鑷浉鐭涚浘**鐨勬ā鏉匡細
+`current_version` 杩樻寚鐫�瀹冿紝瀹冨嵈宸茬粡涓嶅彲鐢ㄣ�傝繖绉嶆ā鏉胯嚜姝ゅ嚭涓嶄簡鎶ュ憡锛�
+鑰屼笖澶辫触鍙戠敓鍦�**鍑轰欢閭d竴鍒�**锛堟姤 `1_070_101_003`锛夛紝鐢ㄦ埛涓嶄細鎯冲埌璧峰洜鏄箣鍓嶉偅娆″仠鐢ㄣ��
+
+鍥犳 `disable` 鐩存帴鎷掔粷锛�**涓嶄細**椤烘墜鏇跨敤鎴锋敼鎺� `current_version`鈥斺��
+銆屾敼鍝釜鐗堟湰銆嶆槸鐢ㄦ埛鐨勫喅瀹氾紝涓嶈鐢便�屽仠鐢ㄣ�嶈繖涓姩浣滄倓鎮勪唬鍔炽��
+
+### 鎶ラ敊鏂囨
+
+```
+鐗堟湰銆寁1.1銆嶆槸妯℃澘銆屾潵鏂欐楠屾姤鍛婃ā鏉裤�嶅綋鍓嶆鍦ㄤ娇鐢ㄧ殑鐗堟湰锛屼笉鑳藉仠鐢ㄣ��
+璇峰厛鍒拌妯℃澘鐨勭増鏈垪琛ㄩ噷瀵瑰彟涓�涓凡鍙戝竷鐗堟湰鎵ц銆屽洖婊氥�嶏紝鎶婂綋鍓嶇増鏈垏璧帮紝鍐嶅仠鐢ㄦ湰鐗堟湰锛�
+鑻ヨ璁╂暣涓ā鏉垮仠姝娇鐢紝璇锋敼涓哄仠鐢ㄦā鏉挎湰韬�
+```
+
+鏂囨閲岀粰鍑轰簡**涓ゆ潯鍙墽琛屽嚭璺�**锛屽墠绔笉闇�瑕佽嚜宸辩粍缁囧紩瀵艰瘽鏈��
+
+### 琚嫆鐨勫垽瀹氬彛寰�
+
+- 姣旇緝瀵硅薄鏄�**妯℃澘琛� `current_version` 鐨勫瓧绗︿覆**涓�**璇ョ増鏈褰曠殑 `version`**锛�
+- 鍙鐩哥瓑灏辨嫆缁濓紝**涓嶇湅鐗堟湰鏄惁宸插彂甯�**锛堣崏绋跨増鏈悓鏍峰彲鑳借 `current_version` 鎸囧埌锛夛紱
+- 鍋滅敤**闈炲綋鍓嶇増鏈�**鐨勫凡鍙戝竷鐗堟湰渚濈劧鍏佽锛岃涓轰笉鍙樸��
+
+## 瀛楁灞曠ず瑙勫垯
+
+鏈鏃犳柊澧炲瓧娈碉紝鏃犻渶璋冩暣鍒楄〃鎴栬〃鍗曞垪銆�
+
+| 鍦烘櫙 | 鍓嶇琛ㄧ幇 |
+|---|---|
+| 淇濆瓨妯℃澘鎶� `1_070_101_009` | 鐢� `msg` 鍏ㄦ枃鎻愮ず锛堝彲鑳藉惈澶氭潯锛岀敤 `锛沗 鍒嗛殧锛夛紱**涓嶈**鎴柇鎴愩�屼繚瀛樺け璐ャ�� |
+| 鍋滅敤鐗堟湰鎶� `1_070_101_010` | 鐢� `msg` 鍏ㄦ枃鎻愮ず锛涙彁绀烘枃妗堝凡鍚悗缁搷浣滄楠わ紝鏃犻渶鍙﹀姞鎸囧紩 |
+| 鍏跺畠閿欒鐮� | 琛屼负涓嶅彉 |
+
+## 涓氬姟瑙勫垯璇存槑
+
+| 鍦烘櫙 | 瑙勫垯 |
+|---|---|
+| 鏂板缓鐗堟湰 / 鏇存柊鐗堟湰鏃� Schema 涓虹┖ | 鍏佽锛堝厛寤虹増鏈悗璁捐锛夛紝涓嶈Е鍙戠敾甯冩牎楠� |
+| 鏂板缓鐗堟湰 / 鏇存柊鐗堟湰鏃� Schema 闈炵┖浣嗙己 `schemaVersion` | 鎷掔粷锛宍1_070_101_004` |
+| 鐢诲竷鏈夐棶棰� | 鎷掔粷淇濆瓨锛宍1_070_101_009`锛�**涓嶈惤搴�** |
+| 鏇存柊**宸插彂甯�**鐗堟湰 | 浠嶇劧鎷掔粷锛宍1_070_101_002`锛堟敼鍔ㄥ彧鑳藉彟瀛樻柊鑽夌锛夛紝涓庢湰娆″彉鏇存棤鍏� |
+| 鍋滅敤褰撳墠鐗堟湰 | 鎷掔粷锛宍1_070_101_010` |
+| 鍋滅敤闈炲綋鍓嶇増鏈� | 姝e父鍋滅敤 |
+| 鍋滅敤鏁翠釜妯℃澘 | 璧般�屽仠鐢ㄦā鏉裤�嶅叆鍙o紝涓嶅彈鏈鍙樻洿褰卞搷 |
+
+## 娉ㄦ剰浜嬮」
+
+- **閿欒鎻愮ず涓嶈鍚炴帀**锛氳繖涓ゆ潯閮芥槸**鐢ㄦ埛鍦ㄧ紪杈戝櫒閲岀殑鎿嶄綔鍙嶉**锛屽繀椤绘妸鍚庣 `msg` 鍘熸牱灞曠ず銆�
+ 鐢诲竷闂涓�娆℃渶澶� 8 鏉★紝澶氭潯鏃跺缓璁寜 `锛沗 鎷嗚灞曠ず锛屼究浜庨�愭潯澶勭悊銆�
+- **瀵规牎楠屼笂绾垮墠灏卞凡鍏ュ簱鐨勮剰鏁版嵁娌℃湁鍏滃簳**锛氭牎楠屽彧鍦ㄤ繚瀛樻椂鎵ц锛屽巻鍙茬増鏈笉浼氳鍥炴函妫�鏌ャ��
+ 鑻ユ��鐤戝瓨閲忕増鏈湁闂锛岄渶瑕佸彟琛屾牳鏌ワ紙鍑轰欢閾捐矾涓嶅彈褰卞搷锛屼粛鎸夊師鏍锋覆鏌擄級銆�
+- **`1_070_101_009` 鐨勫畾浣嶄俊鎭槸銆岀 N 涓粍浠躲��**锛氭寚璇ョ粍浠跺湪鍏剁埗鑺傜偣 `components` 鏁扮粍涓殑搴忓彿锛堜粠 1 寮�濮嬶級锛�
+ 璺緞褰㈠ `鏍� > 绗� 2 涓粍浠� > 绗� 1 涓粍浠禶锛涘眰绾ц繃娣辨椂涓棿閮ㄥ垎浼氭姌鍙犱负 `鈥銆�
+- 鐢诲竷鏍¢獙**涓嶆敼鍙樻覆鏌撶粨鏋�**锛氭覆鏌撳紩鎿庝笌鍓嶇 `engine/render.ts` 鐨勯�愬瓧涓�鑷存�у拰瀛橀噺鎶ュ憡鐨�
+ `regenerate` 澶嶇幇鎬ч兘涓嶅彈褰卞搷锛屾湰娆″彧鍦�**鍐欏叆渚�**鍔犻椄闂ㄣ��
diff --git a/docs/sql/config_export_all_20260918.sql b/docs/sql/config_export_all_20260918.sql
new file mode 100644
index 0000000..f948f41
--- /dev/null
+++ b/docs/sql/config_export_all_20260918.sql
@@ -0,0 +1,11435 @@
+-- =======================================================================
+-- 鏂囦欢锛歝onfig_export_all_20260918.sql
+-- 鐢ㄩ�旓細ruoyi-vue-pro銆屽叏搴撹〃缁撴瀯 + 6 绫婚厤缃暟鎹�嶅鍑猴紝渚涘悓缁撴瀯鍏ㄦ柊搴撳垵濮嬪寲
+-- 鏉ユ簮搴擄細ruoyi-vue-pro
+-- 鍩虹嚎锛�2026-09-04 瀵煎嚭锛�413 寮犺〃锛夛紱
+-- 鏈涓�**琛ヤ竵鐗�**锛氬熀浜� 0904 鏂囦欢澧為噺淇敼涓ゅ锛屾湭閲嶈窇鍏ㄥ簱瀵煎嚭锛堥伩鍏嶆妸鏃犲叧琛ㄤ竴璧锋悈鍔級銆�
+-- 琛ヤ竵鍐呭锛�2026-09-18锛夛細
+-- 鈶� 琛� 6 寮� qc_report_* 琛ㄧ粨鏋勶紙鏅鸿兘璐ㄦ鎶ュ憡璁捐骞冲彴锛�0904 瀵煎嚭鏃惰妯″潡灏氭湭寤烘垚锛屽睘閬楁紡鍥炲啓锛�
+-- 鍏朵腑 qc_report_instance 鐨� pdf_file_url 鍒�**宸叉寜瑕佹眰鍒犻櫎**锛堟枃浠惰蛋 system_storage_attachment 涓棿琛級
+-- 鈶� 琛� qc_report_* 鐨� 6 涓瓧鍏哥被鍨� + 21 鏉″瓧鍏告暟鎹紙骞跺叆闃舵涓�鐨� system_dict_type / system_dict_data锛�
+-- 鈶� 鍙︿慨锛歲c_report_instance.id 鍒楁敞閲婄敱銆屾姤鍛婄紪鍙枫�嶆敼涓恒�屽疄渚嬬紪鍙枫�嶏紙report_no 鎵嶆槸鎶ュ憡缂栧彿锛�
+-- 鈶� **淇闃舵浜屼竴涓棦鏈夌己闄凤紙0904 鍩虹嚎鍚屾牱瀛樺湪锛屼細瀵艰嚧鏁磋剼鏈腑鏂級**锛�
+-- 鈶ャ�宎dmin 鍚勮鑹茬殑鑿滃崟鍏宠仈銆嶅師鍐欐硶鏄� INNER JOIN `system_user_role`锛�
+-- 鑰屾簮搴� system_user_role 涓婚敭鍙湁 id銆佸悓涓� (user_id, role_id) 鍙湁澶氳
+-- 锛堝疄娴� admin 鐨� role_id=1 灏辨湁 2 琛岋紝浜� 2026-09-02 閲嶅鍒嗛厤锛夛紝
+-- JOIN 鎶� system_role_menu 姣忚鏀惧ぇ鎴� N 琛� 鈫� 鎾炰富閿� "Duplicate entry '6352'"锛�
+-- 鑴氭湰鍦� 11411 琛屼腑鏂紝**鏂板簱鍒濆鍖栧嚭鏉ユ槸鍗婃垚鍝�**銆傚凡鏀逛负 IN锛堝瓙鏌ヨ澶╃劧鍘婚噸锛夈��
+-- 鈶� 琛� 6 鏉� qc_report 鑿滃崟锛�2026-09-19锛屾櫤鑳借川妫�鎶ュ憡璁捐骞冲彴鍓嶇鎺ュ叆锛夛細
+-- 1075410 鎶ュ憡瀹炰緥锛堣彍鍗曪級+ 1075411~1075414 鏌ヨ/鍑轰欢/瀵煎嚭PDF/鍒犻櫎锛堟寜閽級
+-- + 1075415 鎶ュ憡妯℃澘AI瀵煎叆锛堟寜閽紝鎸傚湪 1075400 鎶ュ憡妯℃澘璁捐涓嬶級銆�
+-- **鏈枃浠舵棤闇�涓烘鏀瑰姩**锛氶樁娈碘憽 鐨勫啓娉曟槸 `INSERT INTO system_menu SELECT * FROM
+-- ruoyi-vue-pro.system_menu WHERE deleted=b'0'`锛屾槸鎵ц鏈熻法搴撳叏閲忔嫹璐濓紝
+-- 鍙婧愬簱 ruoyi-vue-pro 鏈夎繖鍑犺灏变細琚甫杩囧幓 鈥斺�� 涓庨樁娈典竴鐨勫瓧闈㈤噺 INSERT 涓嶅悓銆�
+-- 鍦ㄦ鐧昏鍙负璇存槑銆岃繖鐗堟枃浠剁‘瀹炶鐩栦簡璇ュ彉鏇淬�嶏紝閬垮厤鍚庢潵鑰呬互涓烘紡浜嗐��
+-- 楠岃瘉锛氭湰鏂囦欢宸插湪鍏ㄦ柊绌哄簱锛圡ySQL 8.4.6锛夋暣浠芥墽琛岄�氳繃 鈥斺�� 419 寮犺〃銆�6 寮� qc_report_*銆�
+-- 6 涓瓧鍏哥被鍨� + 21 鏉″瓧鍏告暟鎹�乤dmin 璐﹀彿 / 1258 鏉¤彍鍗� / 2349 鏉� role_menu /
+-- 榛樿 OAuth2 瀹㈡埛绔潎姝g‘钀藉簱銆�
+-- 鑼冨洿锛氬叏搴� BASE TABLE 鍏� 419 寮狅紝鍏ㄩ儴杈撳嚭 CREATE TABLE锛�
+-- 浠呬互涓嬮厤缃被琛ㄥ甫鏁版嵁(INSERT)锛屽叾浣欎笟鍔�/绯荤粺/杩愯鍘嗗彶琛ㄥ彧淇濈暀绌鸿〃缁撴瀯锛�
+-- 鈶� 鍗忓悓瀹℃壒娴佺▼锛堝紩鎿庡厓鏁版嵁+瀹氫箟锛屼粎婵�娲绘祦绋嬶紝鍓斿巻鍙�/杩愯/韬唤锛夛細act_ge_property銆乤ct_id_property銆乤ct_re_procdef銆乤ct_re_deployment銆乤ct_ge_bytearray銆乤ct_re_model銆乥pm_process_definition_info
+-- 鈶� 鍗忓悓锛堜笟鍔¢檮浠堕厤缃� + 鍒嗙被 + 琛ㄥ崟 + 鎵╁睍閰嶇疆锛夛細bpm_business_attach銆乥pm_category銆乥pm_form銆乥pm_user_group銆乥pm_process_listener銆乥pm_process_expression
+-- 鈶� BI 鍐崇瓥澶у睆 / go-view锛歜i_dashboard銆乥i_chart_config銆乥i_data_source_config銆乥i_warehouse_coordinate銆乺eport_go_view_project
+-- 鈶� MES 缂栫爜瑙勫垯锛堝墧娴佹按璁板綍锛夛細mes_md_auto_code_rule銆乵es_md_auto_code_part
+-- 鈶� 绯荤粺閰嶇疆涓绘暟鎹紙瀛楀吀/绉熸埛/鍏徃閰嶇疆锛涘墧韬唤/鑿滃崟/鏃ュ織锛夛細system_dict_type銆乻ystem_dict_data銆乻ystem_tenant銆乻ystem_tenant_package銆乻ystem_company_config
+-- 鈿� 韬唤/鏉冮檺绫昏〃锛坰ystem_users/role/menu/role_menu/user_role/dept/post/oauth2_client锛夋澶勪粎寤虹┖琛ㄧ粨鏋勶紝鏁版嵁鐢辨枃浠舵湯灏�"闃舵浜�"璺ㄥ簱琛ュ銆�
+-- 鈶� AI 閰嶇疆锛堜粎妯″瀷+key锛�+ 鍩虹璁炬柦閰嶇疆绠$悊锛歛i_model銆乤i_api_key銆乮nfra_config銆乮nfra_job銆乮nfra_file_config銆乮nfra_data_source_config銆乮nfra_codegen_table銆乮nfra_codegen_column
+-- 杩囨护锛氬崗鍚屾祦绋嬩粎淇濈暀婵�娲�(SUSPENSION_STATE_=1)瀹氫箟鍙婂叾閮ㄧ讲/瀛楄妭/妯″瀷/鎵╁睍淇℃伅锛�
+-- 缂栫爜瑙勫垯鍓旈櫎娴佹按璁板綍 mes_md_auto_code_record锛涜蒋鍒犻櫎琛ㄤ粎瀵� deleted=0銆�
+-- 鈿� 鑴氭湰鍚叏搴� DROP TABLE IF EXISTS锛屼細鎶婇櫎鏈剼鏈缓琛ㄥ鐨勬墍鏈夎〃鍒犻櫎閲嶅缓锛�
+-- 涓氬姟琛ㄦ暟鎹皢鍏ㄩ儴娓呯┖锛屼粎鍙湪鍏ㄦ柊/鍙鐩栫殑绌哄簱鎵ц锛�
+-- =======================================================================
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+SET @OLD_SQL_MODE = @@SQL_MODE, SQL_MODE = 'NO_AUTO_VALUE_ON_ZERO';
+
+
+-- ***********************************************************************
+-- 鈶� 鍗忓悓瀹℃壒娴佺▼锛堝紩鎿庡厓鏁版嵁+瀹氫箟锛屼粎婵�娲绘祦绋嬶紝鍓斿巻鍙�/杩愯/韬唤锛夛紙DDL + 鏁版嵁锛�
+-- ***********************************************************************
+
+-- ============ 琛細act_ge_property锛堝鍑� 7 琛岋級 ============
+DROP TABLE IF EXISTS `act_ge_property`;
+CREATE TABLE `act_ge_property` (
+ `NAME_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `VALUE_` varchar(300) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `REV_` int DEFAULT NULL,
+ PRIMARY KEY (`NAME_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+INSERT INTO `act_ge_property` (`NAME_`, `VALUE_`, `REV_`) VALUES
+('cfg.execution-related-entities-count', 'true', '1'),
+('cfg.task-related-entities-count', 'true', '1'),
+('common.schema.version', '8.0.0.0', '1'),
+('eventregistry.schema.version', '8.0.0.0', '1'),
+('next.dbid', '1', '1'),
+('schema.history', 'upgrade(7.2.0.2->8.0.0.0)', '2'),
+('schema.version', '8.0.0.0', '2');
+
+-- ============ 琛細act_id_property锛堝鍑� 1 琛岋級 ============
+DROP TABLE IF EXISTS `act_id_property`;
+CREATE TABLE `act_id_property` (
+ `NAME_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `VALUE_` varchar(300) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `REV_` int DEFAULT NULL,
+ PRIMARY KEY (`NAME_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+INSERT INTO `act_id_property` (`NAME_`, `VALUE_`, `REV_`) VALUES
+('schema.version', '8.0.0.0', '1');
+
+-- ============ 琛細act_re_procdef锛堝鍑� 20 琛岋級 ============
+DROP TABLE IF EXISTS `act_re_procdef`;
+CREATE TABLE `act_re_procdef` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `VERSION_` int NOT NULL,
+ `DEPLOYMENT_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `RESOURCE_NAME_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DGRM_RESOURCE_NAME_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DESCRIPTION_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `HAS_START_FORM_KEY_` tinyint DEFAULT NULL,
+ `HAS_GRAPHICAL_NOTATION_` tinyint DEFAULT NULL,
+ `SUSPENSION_STATE_` int DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '',
+ `ENGINE_VERSION_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DERIVED_FROM_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DERIVED_FROM_ROOT_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DERIVED_VERSION_` int NOT NULL DEFAULT '0',
+ PRIMARY KEY (`ID_`) USING BTREE,
+ UNIQUE KEY `ACT_UNIQ_PROCDEF` (`KEY_`,`VERSION_`,`DERIVED_VERSION_`,`TENANT_ID_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+INSERT INTO `act_re_procdef` (`ID_`, `REV_`, `CATEGORY_`, `NAME_`, `KEY_`, `VERSION_`, `DEPLOYMENT_ID_`, `RESOURCE_NAME_`, `DGRM_RESOURCE_NAME_`, `DESCRIPTION_`, `HAS_START_FORM_KEY_`, `HAS_GRAPHICAL_NOTATION_`, `SUSPENSION_STATE_`, `TENANT_ID_`, `ENGINE_VERSION_`, `DERIVED_FROM_`, `DERIVED_FROM_ROOT_`, `DERIVED_VERSION_`) VALUES
+('crm-contract-audit:1:dep_febd13bedc800a97127ae1c042eb557b', '1', 'contract_approve', '鍚堝悓瀹℃壒', 'crm-contract-audit', '1', 'dep_febd13bedc800a97127ae1c042eb557b', 'crm-contract-audit.bpmn', NULL, NULL, '0', '1', '1', '', NULL, NULL, NULL, '0'),
+('crm-invoice-audit:1:c101d3e0-0001-11f2-8a27-00155dad6485', '1', 'crm_invoice_approve', '寮�绁ㄥ鎵规祦绋�', 'crm-invoice-audit', '1', 'c101d3e0-0001-11f2-8a27-00155dad6485', 'crm-invoice-audit.bpmn', NULL, NULL, '0', '0', '1', '', NULL, NULL, NULL, '0'),
+('crm-receivable-audit:1:7215184e-948c-11f1-9271-1ab6da3745b7', '1', '1111', '鍥炴瀹℃壒娴佺▼', 'crm-receivable-audit', '1', '7215184e-948c-11f1-9271-1ab6da3745b7', 'crm-receivable-audit.bpmn', NULL, NULL, '0', '0', '1', '', NULL, NULL, NULL, '0'),
+('erp-finance-payment-audit:1:f1a1b2c3d4e5465f8a9b0c1d2e3f4a5b', '1', 'erp_finance_payment_approve', '浠樻瀹℃壒娴佺▼', 'erp-finance-payment-audit', '1', 'f1a1b2c3d4e5465f8a9b0c1d2e3f4a5b', 'erp-finance-payment-audit.bpmn', NULL, NULL, '0', '1', '1', '', NULL, NULL, NULL, '0'),
+('erp-purchase-invoice-audit:1:0b7c7557949111f192711ab6da3745b7', '1', 'erp_purchase_invoice_approve', '鏉ョエ瀹℃壒娴佺▼', 'erp-purchase-invoice-audit', '1', '0b7c7557949111f192711ab6da3745b7', 'erp-purchase-invoice-audit.bpmn', '', '', '0', '0', '1', '', NULL, '', '', '0'),
+('hrm_attendance_approve:1:dep_d1d2025350ea9af098ca7dbe6e80b442', '1', 'hrm_attendance_approve', '鑰冨嫟寮傚父瀹℃壒', 'hrm_attendance_approve', '1', 'dep_d1d2025350ea9af098ca7dbe6e80b442', 'hrm_attendance_approve.bpmn', NULL, NULL, '0', '1', '1', '', NULL, NULL, NULL, '0'),
+('hrm_leave:1:dep_862c6766e8cd1b32946a1ed2956a68bf', '1', 'hrm_leave_approve', '璇峰亣瀹℃壒', 'hrm_leave', '1', 'dep_862c6766e8cd1b32946a1ed2956a68bf', 'hrm_leave.bpmn', NULL, NULL, '0', '1', '1', '', NULL, NULL, NULL, '0'),
+('hrm_overtime:1:dep_ecb89d4a54da3ae23601fef85642b0ce', '1', 'overtime_approve', '鍔犵彮瀹℃壒', 'hrm_overtime', '1', 'dep_ecb89d4a54da3ae23601fef85642b0ce', 'hrm_overtime.bpmn', NULL, NULL, '0', '1', '1', '', NULL, NULL, NULL, '0'),
+('hrm_resignation:1:dep_33d3b1649a923d986d89604267b79bbf', '1', 'hrm_resignation_approve', '绂昏亴瀹℃壒', 'hrm_resignation', '1', 'dep_33d3b1649a923d986d89604267b79bbf', 'hrm_resignation.bpmn', NULL, NULL, '0', '1', '1', '', NULL, NULL, NULL, '0'),
+('hrm_transfer:1:dep_66ea9f27906591b4d0048d854c633a82', '1', 'hrm_transfer_approve', '璋冨姩瀹℃壒', 'hrm_transfer', '1', 'dep_66ea9f27906591b4d0048d854c633a82', 'hrm_transfer.bpmn', NULL, NULL, '0', '1', '1', '', NULL, NULL, NULL, '0'),
+('item_receipt_approve:1:dep_c16d0eef322695bed1c0c20e1d0190ce', '1', 'item_receipt_approve', '閲囪喘鍏ュ簱瀹℃壒', 'item_receipt_approve', '1', 'dep_c16d0eef322695bed1c0c20e1d0190ce', 'item_receipt_approve.bpmn', NULL, NULL, '0', '1', '1', '', NULL, NULL, NULL, '0'),
+('mes-pd-project-audit:1:ce99813cfeb29f270355dd39f8ef74f2', '1', 'mes_pd_project_approve', '浜у搧椤圭洰瀹℃壒娴佺▼', 'mes-pd-project-audit', '1', 'ce99813cfeb29f270355dd39f8ef74f2', 'mes-pd-project-audit.bpmn', NULL, NULL, '0', '1', '1', NULL, NULL, NULL, NULL, '0'),
+('mes-pro-feedback-audit:1:dep_08349f78d675f582f1ff5f08e7714a8d', '1', 'mes_pro_feedback_audit', '鎶ュ伐瀹℃壒', 'mes-pro-feedback-audit', '1', 'dep_08349f78d675f582f1ff5f08e7714a8d', 'mes-pro-feedback-audit.bpmn', NULL, NULL, '0', '1', '1', '', NULL, NULL, NULL, '0'),
+('purchase_order_approve:1:dep_09ba42e32e7a436ee4e2a9b6eef0d232', '1', 'purchase_order_approve', '閲囪喘璁㈠崟瀹℃壒', 'purchase_order_approve', '1', 'dep_09ba42e32e7a436ee4e2a9b6eef0d232', 'purchase_order_approve.bpmn', NULL, NULL, '0', '1', '1', '', NULL, NULL, NULL, '0'),
+('purchase_request_approve:3:d239e27d-74fe-11f1-9120-00155dd68500', '2', 'purchase_request_approve', '閲囪喘瀹℃牳', 'purchase_request_approve', '3', 'd232b68a-74fe-11f1-9120-00155dd68500', 'purchase_request_approve.bpmn', 'purchase_request_approve.purchase_request_approve.png', NULL, '0', '1', '1', '', NULL, NULL, NULL, '0'),
+('sale_order_approve:1:dep_b9d15a0bc2b775bebb84987fb4b07cad', '1', 'sale_order_approve', '閿�鍞鍗曞鎵�', 'sale_order_approve', '1', 'dep_b9d15a0bc2b775bebb84987fb4b07cad', 'sale_order_approve.bpmn', NULL, NULL, '0', '1', '1', '', NULL, NULL, NULL, '0'),
+('supplier_apply_approve:1:dep_b6e816103961b88392e4ac24c87dddf8', '1', 'supplier_apply_approve', '渚涘簲鍟嗗噯鍏ュ鎵�', 'supplier_apply_approve', '1', 'dep_b6e816103961b88392e4ac24c87dddf8', 'supplier_apply_approve.bpmn', NULL, NULL, '0', '1', '1', '', NULL, NULL, NULL, '0'),
+('wms_inbound_approve:1:dep_6e0f473d28c042b8b372d00797549423', '1', 'wms_approve', '浠撳簱鍏ュ簱瀹℃壒', 'wms_inbound_approve', '1', 'dep_6e0f473d28c042b8b372d00797549423', 'wms_inbound_approve.bpmn', NULL, NULL, '0', '1', '1', '', NULL, NULL, NULL, '0'),
+('wms_outbound_approve:1:dep_bed6796545faa2cb7851a019948e4e49', '1', 'wms_approve', '浠撳簱鍑哄簱瀹℃壒', 'wms_outbound_approve', '1', 'dep_bed6796545faa2cb7851a019948e4e49', 'wms_outbound_approve.bpmn', NULL, NULL, '0', '1', '1', '', NULL, NULL, NULL, '0'),
+('wms_transfer_approve:1:dep_9b3368e05f1d39dee636f464f2d65c16', '1', 'wms_approve', '浠撳簱璋冩嫧瀹℃壒', 'wms_transfer_approve', '1', 'dep_9b3368e05f1d39dee636f464f2d65c16', 'wms_transfer_approve.bpmn', NULL, NULL, '0', '1', '1', '', NULL, NULL, NULL, '0');
+
+-- ============ 琛細act_re_deployment锛堝鍑� 20 琛岋級 ============
+DROP TABLE IF EXISTS `act_re_deployment`;
+CREATE TABLE `act_re_deployment` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '',
+ `DEPLOY_TIME_` timestamp(3) NULL DEFAULT NULL,
+ `DERIVED_FROM_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DERIVED_FROM_ROOT_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PARENT_DEPLOYMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ENGINE_VERSION_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ PRIMARY KEY (`ID_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+INSERT INTO `act_re_deployment` (`ID_`, `NAME_`, `CATEGORY_`, `KEY_`, `TENANT_ID_`, `DEPLOY_TIME_`, `DERIVED_FROM_`, `DERIVED_FROM_ROOT_`, `PARENT_DEPLOYMENT_ID_`, `ENGINE_VERSION_`) VALUES
+('0b7c7557949111f192711ab6da3745b7', '鏉ョエ瀹℃壒娴佺▼', 'erp_purchase_invoice_approve', '', '', '2026-08-10 15:56:54.000', NULL, NULL, NULL, NULL),
+('7215184e-948c-11f1-9271-1ab6da3745b7', '鍥炴瀹℃壒娴佺▼', '1111', NULL, '', '2026-08-10 15:24:24.000', NULL, NULL, NULL, NULL),
+('c101d3e0-0001-11f2-8a27-00155dad6485', '寮�绁ㄥ鎵规祦绋�', 'crm_invoice_approve', NULL, '', '2026-08-10 14:35:22.000', NULL, NULL, NULL, NULL),
+('ce99813cfeb29f270355dd39f8ef74f2', '浜у搧椤圭洰瀹℃壒娴佺▼', 'mes_pd_project_approve', 'mes-pd-project-audit', NULL, '2026-08-13 16:12:13.000', NULL, NULL, NULL, NULL),
+('d232b68a-74fe-11f1-9120-00155dd68500', '閲囪喘瀹℃牳', 'purchase_request_approve', 'purchase_request_approve', '', '2026-07-01 19:42:02.225', NULL, NULL, 'd232b68a-74fe-11f1-9120-00155dd68500', NULL),
+('dep_08349f78d675f582f1ff5f08e7714a8d', '鎶ュ伐瀹℃壒', 'mes_pro_feedback_audit', 'mes-pro-feedback-audit', '', '2026-09-04 06:09:24.000', NULL, NULL, NULL, NULL),
+('dep_09ba42e32e7a436ee4e2a9b6eef0d232', '閲囪喘璁㈠崟瀹℃壒', 'purchase_order_approve', 'purchase_order_approve', '', '2026-09-04 06:07:01.000', NULL, NULL, NULL, NULL),
+('dep_33d3b1649a923d986d89604267b79bbf', '绂昏亴瀹℃壒', 'hrm_resignation_approve', 'hrm_resignation', '', '2026-09-04 06:08:24.000', NULL, NULL, NULL, NULL),
+('dep_66ea9f27906591b4d0048d854c633a82', '璋冨姩瀹℃壒', 'hrm_transfer_approve', 'hrm_transfer', '', '2026-09-04 06:08:31.000', NULL, NULL, NULL, NULL),
+('dep_6e0f473d28c042b8b372d00797549423', '浠撳簱鍏ュ簱瀹℃壒', 'wms_approve', 'wms_inbound_approve', '', '2026-09-04 06:08:56.000', NULL, NULL, NULL, NULL),
+('dep_862c6766e8cd1b32946a1ed2956a68bf', '璇峰亣瀹℃壒', 'hrm_leave_approve', 'hrm_leave', '', '2026-09-04 06:07:26.000', NULL, NULL, NULL, NULL),
+('dep_9b3368e05f1d39dee636f464f2d65c16', '浠撳簱璋冩嫧瀹℃壒', 'wms_approve', 'wms_transfer_approve', '', '2026-09-04 06:09:10.000', NULL, NULL, NULL, NULL),
+('dep_b6e816103961b88392e4ac24c87dddf8', '渚涘簲鍟嗗噯鍏ュ鎵�', 'supplier_apply_approve', 'supplier_apply_approve', '', '2026-09-04 06:08:50.000', NULL, NULL, NULL, NULL),
+('dep_b9d15a0bc2b775bebb84987fb4b07cad', '閿�鍞鍗曞鎵�', 'sale_order_approve', 'sale_order_approve', '', '2026-09-04 06:06:43.000', NULL, NULL, NULL, NULL),
+('dep_bed6796545faa2cb7851a019948e4e49', '浠撳簱鍑哄簱瀹℃壒', 'wms_approve', 'wms_outbound_approve', '', '2026-09-04 06:09:03.000', NULL, NULL, NULL, NULL),
+('dep_c16d0eef322695bed1c0c20e1d0190ce', '閲囪喘鍏ュ簱瀹℃壒', 'item_receipt_approve', 'item_receipt_approve', '', '2026-09-04 06:09:17.000', NULL, NULL, NULL, NULL),
+('dep_d1d2025350ea9af098ca7dbe6e80b442', '鑰冨嫟寮傚父瀹℃壒', 'hrm_attendance_approve', 'hrm_attendance_approve', '', '2026-09-04 06:08:38.000', NULL, NULL, NULL, NULL),
+('dep_ecb89d4a54da3ae23601fef85642b0ce', '鍔犵彮瀹℃壒', 'overtime_approve', 'hrm_overtime', '', '2026-09-04 06:07:33.000', NULL, NULL, NULL, NULL),
+('dep_febd13bedc800a97127ae1c042eb557b', '鍚堝悓瀹℃壒', 'contract_approve', 'crm-contract-audit', '', '2026-09-04 06:07:09.000', NULL, NULL, NULL, NULL),
+('f1a1b2c3d4e5465f8a9b0c1d2e3f4a5b', '浠樻瀹℃壒娴佺▼', 'erp_finance_payment_approve', 'erp-finance-payment-audit', '', '2026-08-10 17:35:43.000', NULL, NULL, NULL, NULL);
+
+-- ============ 琛細act_ge_bytearray锛堝鍑� 21 琛岋級 ============
+DROP TABLE IF EXISTS `act_ge_bytearray`;
+CREATE TABLE `act_ge_bytearray` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DEPLOYMENT_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `BYTES_` longblob,
+ `GENERATED_` tinyint DEFAULT NULL,
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `ACT_IDX_BYTEAR_DEPL` (`DEPLOYMENT_ID_`) USING BTREE,
+ CONSTRAINT `ACT_FK_BYTEARR_DEPL` FOREIGN KEY (`DEPLOYMENT_ID_`) REFERENCES `act_re_deployment` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+INSERT INTO `act_ge_bytearray` (`ID_`, `REV_`, `NAME_`, `DEPLOYMENT_ID_`, `BYTES_`, `GENERATED_`) VALUES
+('0b7c7572949111f192711ab6da3745b7', '1', 'erp-purchase-invoice-audit.bpmn', '0b7c7557949111f192711ab6da3745b7', X'3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f3e0a3c646566696e6974696f6e7320786d6c6e733d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c2220786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220786d6c6e733a62706d6e64693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f44492220786d6c6e733a6f6d6764633d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44432220786d6c6e733a6f6d6764693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44492220747970654c616e67756167653d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d61222065787072657373696f6e4c616e67756167653d22687474703a2f2f7777772e77332e6f72672f313939392f585061746822207461726765744e616d6573706163653d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c223e0a20203c70726f636573732069643d226572702d70757263686173652d696e766f6963652d617564697422206e616d653d22e69da5e7a5a8e5aea1e689b9e6b581e7a88b2220697345786563757461626c653d2274727565223e0a202020203c73746172744576656e742069643d2253746172744576656e7422206e616d653d22e5bc80e5a78b223e3c2f73746172744576656e743e0a202020203c757365725461736b2069643d225374617274557365724e6f646522206e616d653d22e58f91e8b5b7e4baba223e0a2020202020203c657874656e73696f6e456c656d656e74733e0a20202020202020203c666c6f7761626c653a617070726f76655479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a617070726f7665547970653e0a20202020202020203c666c6f7761626c653a63616e646964617465537472617465677920786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b33365d5d3e3c2f666c6f7761626c653a63616e64696461746553747261746567793e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68f90e4baa42220656e61626c653d2274727565222069643d2231223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68b92e7bb9d2220656e61626c653d2266616c7365222069643d2232223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e8bdace58a9e2220656e61626c653d2266616c7365222069643d2233223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e5a794e6b4be2220656e61626c653d2266616c7365222069643d2234223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e58aa0e7adbe2220656e61626c653d2266616c7365222069643d2235223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e98080e59b9e2220656e61626c653d2266616c7365222069643d2236223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a61737369676e53746172745573657248616e646c65725479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b325d5d3e3c2f666c6f7761626c653a61737369676e53746172745573657248616e646c6572547970653e0a2020202020203c2f657874656e73696f6e456c656d656e74733e0a202020203c2f757365725461736b3e0a202020203c656e644576656e742069643d22456e644576656e7422206e616d653d22e7bb93e69d9f223e3c2f656e644576656e743e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d312220736f757263655265663d2253746172744576656e7422207461726765745265663d225374617274557365724e6f6465223e3c2f73657175656e6365466c6f773e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d322220736f757263655265663d225374617274557365724e6f646522207461726765745265663d22456e644576656e74223e3c2f73657175656e6365466c6f773e0a20203c2f70726f636573733e0a20203c62706d6e64693a42504d4e4469616772616d2069643d2242504d4e4469616772616d5f6572702d70757263686173652d696e766f6963652d6175646974223e0a202020203c62706d6e64693a42504d4e506c616e652062706d6e456c656d656e743d226572702d70757263686173652d696e766f6963652d6175646974222069643d2242504d4e506c616e655f6572702d70757263686173652d696e766f6963652d6175646974223e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d225374617274557365724e6f6465222069643d2242504d4e53686170655f5374617274557365724e6f6465223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2236302e30222077696474683d223130302e302220783d2238302e302220793d22302e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d2253746172744576656e74222069643d2242504d4e53686170655f53746172744576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d22302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d22456e644576656e74222069643d2242504d4e53686170655f456e644576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d223233302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d32222069643d2242504d4e456467655f73657175656e6365466c6f772d32223e0a20202020202020203c6f6d6764693a776179706f696e7420783d223138302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d223233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d31222069643d2242504d4e456467655f73657175656e6365466c6f772d31223e0a20202020202020203c6f6d6764693a776179706f696e7420783d2233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d2238302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a202020203c2f62706d6e64693a42504d4e506c616e653e0a20203c2f62706d6e64693a42504d4e4469616772616d3e0a3c2f646566696e6974696f6e733e', '0'),
+('72151877-948c-11f1-9271-1ab6da3745b7', '1', 'crm-receivable-audit.bpmn', '7215184e-948c-11f1-9271-1ab6da3745b7', X'3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f3e0a3c646566696e6974696f6e7320786d6c6e733d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c2220786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220786d6c6e733a62706d6e64693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f44492220786d6c6e733a6f6d6764633d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44432220786d6c6e733a6f6d6764693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44492220747970654c616e67756167653d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d61222065787072657373696f6e4c616e67756167653d22687474703a2f2f7777772e77332e6f72672f313939392f585061746822207461726765744e616d6573706163653d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c223e0a20203c70726f636573732069643d2263726d2d72656365697661626c652d617564697422206e616d653d22e59b9ee6acbee5aea1e689b9e6b581e7a88b2220697345786563757461626c653d2274727565223e0a202020203c73746172744576656e742069643d2253746172744576656e7422206e616d653d22e5bc80e5a78b223e3c2f73746172744576656e743e0a202020203c757365725461736b2069643d225374617274557365724e6f646522206e616d653d22e58f91e8b5b7e4baba223e0a2020202020203c657874656e73696f6e456c656d656e74733e0a20202020202020203c666c6f7761626c653a617070726f76655479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a617070726f7665547970653e0a20202020202020203c666c6f7761626c653a63616e646964617465537472617465677920786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b33365d5d3e3c2f666c6f7761626c653a63616e64696461746553747261746567793e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68f90e4baa42220656e61626c653d2274727565222069643d2231223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68b92e7bb9d2220656e61626c653d2266616c7365222069643d2232223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e8bdace58a9e2220656e61626c653d2266616c7365222069643d2233223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e5a794e6b4be2220656e61626c653d2266616c7365222069643d2234223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e58aa0e7adbe2220656e61626c653d2266616c7365222069643d2235223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e98080e59b9e2220656e61626c653d2266616c7365222069643d2236223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a61737369676e53746172745573657248616e646c65725479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b325d5d3e3c2f666c6f7761626c653a61737369676e53746172745573657248616e646c6572547970653e0a2020202020203c2f657874656e73696f6e456c656d656e74733e0a202020203c2f757365725461736b3e0a202020203c656e644576656e742069643d22456e644576656e7422206e616d653d22e7bb93e69d9f223e3c2f656e644576656e743e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d312220736f757263655265663d2253746172744576656e7422207461726765745265663d225374617274557365724e6f6465223e3c2f73657175656e6365466c6f773e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d322220736f757263655265663d225374617274557365724e6f646522207461726765745265663d22456e644576656e74223e3c2f73657175656e6365466c6f773e0a20203c2f70726f636573733e0a20203c62706d6e64693a42504d4e4469616772616d2069643d2242504d4e4469616772616d5f63726d2d72656365697661626c652d6175646974223e0a202020203c62706d6e64693a42504d4e506c616e652062706d6e456c656d656e743d2263726d2d72656365697661626c652d6175646974222069643d2242504d4e506c616e655f63726d2d72656365697661626c652d6175646974223e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d225374617274557365724e6f6465222069643d2242504d4e53686170655f5374617274557365724e6f6465223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2236302e30222077696474683d223130302e302220783d2238302e302220793d22302e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d2253746172744576656e74222069643d2242504d4e53686170655f53746172744576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d22302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d22456e644576656e74222069643d2242504d4e53686170655f456e644576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d223233302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d32222069643d2242504d4e456467655f73657175656e6365466c6f772d32223e0a20202020202020203c6f6d6764693a776179706f696e7420783d223138302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d223233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d31222069643d2242504d4e456467655f73657175656e6365466c6f772d31223e0a20202020202020203c6f6d6764693a776179706f696e7420783d2233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d2238302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a202020203c2f62706d6e64693a42504d4e506c616e653e0a20203c2f62706d6e64693a42504d4e4469616772616d3e0a3c2f646566696e6974696f6e733e', '0'),
+('c101d3e1-0001-11f2-8a27-00155dad6485', '1', 'crm-invoice-audit.bpmn', 'c101d3e0-0001-11f2-8a27-00155dad6485', X'3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f3e0a3c646566696e6974696f6e7320786d6c6e733d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c2220786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220786d6c6e733a62706d6e64693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f44492220786d6c6e733a6f6d6764633d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44432220786d6c6e733a6f6d6764693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44492220747970654c616e67756167653d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d61222065787072657373696f6e4c616e67756167653d22687474703a2f2f7777772e77332e6f72672f313939392f585061746822207461726765744e616d6573706163653d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c223e0a20203c70726f636573732069643d2263726d2d696e766f6963652d617564697422206e616d653d22e5bc80e7a5a8e5aea1e689b9e6b581e7a88b2220697345786563757461626c653d2274727565223e0a202020203c73746172744576656e742069643d2253746172744576656e7422206e616d653d22e5bc80e5a78b223e3c2f73746172744576656e743e0a202020203c757365725461736b2069643d225374617274557365724e6f646522206e616d653d22e58f91e8b5b7e4baba223e0a2020202020203c657874656e73696f6e456c656d656e74733e0a20202020202020203c666c6f7761626c653a617070726f76655479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a617070726f7665547970653e0a20202020202020203c666c6f7761626c653a63616e646964617465537472617465677920786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b33365d5d3e3c2f666c6f7761626c653a63616e64696461746553747261746567793e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68f90e4baa42220656e61626c653d2274727565222069643d2231223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68b92e7bb9d2220656e61626c653d2266616c7365222069643d2232223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e8bdace58a9e2220656e61626c653d2266616c7365222069643d2233223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e5a794e6b4be2220656e61626c653d2266616c7365222069643d2234223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e58aa0e7adbe2220656e61626c653d2266616c7365222069643d2235223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e98080e59b9e2220656e61626c653d2266616c7365222069643d2236223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a61737369676e53746172745573657248616e646c65725479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b325d5d3e3c2f666c6f7761626c653a61737369676e53746172745573657248616e646c6572547970653e0a2020202020203c2f657874656e73696f6e456c656d656e74733e0a202020203c2f757365725461736b3e0a202020203c656e644576656e742069643d22456e644576656e7422206e616d653d22e7bb93e69d9f223e3c2f656e644576656e743e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d312220736f757263655265663d2253746172744576656e7422207461726765745265663d225374617274557365724e6f6465223e3c2f73657175656e6365466c6f773e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d322220736f757263655265663d225374617274557365724e6f646522207461726765745265663d22456e644576656e74223e3c2f73657175656e6365466c6f773e0a20203c2f70726f636573733e0a20203c62706d6e64693a42504d4e4469616772616d2069643d2242504d4e4469616772616d5f63726d2d696e766f6963652d6175646974223e0a202020203c62706d6e64693a42504d4e506c616e652062706d6e456c656d656e743d2263726d2d696e766f6963652d6175646974222069643d2242504d4e506c616e655f63726d2d696e766f6963652d6175646974223e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d225374617274557365724e6f6465222069643d2242504d4e53686170655f5374617274557365724e6f6465223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2236302e30222077696474683d223130302e302220783d2238302e302220793d22302e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d2253746172744576656e74222069643d2242504d4e53686170655f53746172744576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d22302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d22456e644576656e74222069643d2242504d4e53686170655f456e644576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d223233302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d32222069643d2242504d4e456467655f73657175656e6365466c6f772d32223e0a20202020202020203c6f6d6764693a776179706f696e7420783d223138302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d223233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d31222069643d2242504d4e456467655f73657175656e6365466c6f772d31223e0a20202020202020203c6f6d6764693a776179706f696e7420783d2233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d2238302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a202020203c2f62706d6e64693a42504d4e506c616e653e0a20203c2f62706d6e64693a42504d4e4469616772616d3e0a3c2f646566696e6974696f6e733e', '0'),
+('44318b176050e94d2c4a86595763dde8', '1', 'mes-pd-project-audit.bpmn', 'ce99813cfeb29f270355dd39f8ef74f2', X'3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f3e0a3c646566696e6974696f6e7320786d6c6e733d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c2220786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220786d6c6e733a62706d6e64693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f44492220786d6c6e733a6f6d6764633d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44432220786d6c6e733a6f6d6764693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44492220747970654c616e67756167653d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d61222065787072657373696f6e4c616e67756167653d22687474703a2f2f7777772e77332e6f72672f313939392f585061746822207461726765744e616d6573706163653d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c223e0a20203c70726f636573732069643d226d65732d70642d70726f6a6563742d617564697422206e616d653d22e4baa7e59381e9a1b9e79baee5aea1e689b9e6b581e7a88b2220697345786563757461626c653d2274727565223e0a202020203c73746172744576656e742069643d2253746172744576656e7422206e616d653d22e5bc80e5a78b223e3c2f73746172744576656e743e0a202020203c757365725461736b2069643d225374617274557365724e6f646522206e616d653d22e58f91e8b5b7e4baba223e0a2020202020203c657874656e73696f6e456c656d656e74733e0a20202020202020203c666c6f7761626c653a617070726f76655479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a617070726f7665547970653e0a20202020202020203c666c6f7761626c653a63616e646964617465537472617465677920786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b33365d5d3e3c2f666c6f7761626c653a63616e64696461746553747261746567793e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68f90e4baa42220656e61626c653d2274727565222069643d2231223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68b92e7bb9d2220656e61626c653d2266616c7365222069643d2232223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e8bdace58a9e2220656e61626c653d2266616c7365222069643d2233223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e5a794e6b4be2220656e61626c653d2266616c7365222069643d2234223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e58aa0e7adbe2220656e61626c653d2266616c7365222069643d2235223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e98080e59b9e2220656e61626c653d2266616c7365222069643d2236223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a61737369676e53746172745573657248616e646c65725479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b325d5d3e3c2f666c6f7761626c653a61737369676e53746172745573657248616e646c6572547970653e0a2020202020203c2f657874656e73696f6e456c656d656e74733e0a202020203c2f757365725461736b3e0a202020203c656e644576656e742069643d22456e644576656e7422206e616d653d22e7bb93e69d9f223e3c2f656e644576656e743e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d312220736f757263655265663d2253746172744576656e7422207461726765745265663d225374617274557365724e6f6465223e3c2f73657175656e6365466c6f773e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d322220736f757263655265663d225374617274557365724e6f646522207461726765745265663d22456e644576656e74223e3c2f73657175656e6365466c6f773e0a20203c2f70726f636573733e0a20203c62706d6e64693a42504d4e4469616772616d2069643d2242504d4e4469616772616d5f6d65732d70642d70726f6a6563742d6175646974223e0a202020203c62706d6e64693a42504d4e506c616e652062706d6e456c656d656e743d226d65732d70642d70726f6a6563742d6175646974222069643d2242504d4e506c616e655f6d65732d70642d70726f6a6563742d6175646974223e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d225374617274557365724e6f6465222069643d2242504d4e53686170655f5374617274557365724e6f6465223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2236302e30222077696474683d223130302e302220783d2238302e302220793d22302e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d2253746172744576656e74222069643d2242504d4e53686170655f53746172744576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d22302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d22456e644576656e74222069643d2242504d4e53686170655f456e644576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d223233302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d32222069643d2242504d4e456467655f73657175656e6365466c6f772d32223e0a20202020202020203c6f6d6764693a776179706f696e7420783d223138302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d223233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d31222069643d2242504d4e456467655f73657175656e6365466c6f772d31223e0a20202020202020203c6f6d6764693a776179706f696e7420783d2233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d2238302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a202020203c2f62706d6e64693a42504d4e506c616e653e0a20203c2f62706d6e64693a42504d4e4469616772616d3e0a3c2f646566696e6974696f6e733e', '0'),
+('d232b68b-74fe-11f1-9120-00155dd68500', '1', 'purchase_request_approve.bpmn', 'd232b68a-74fe-11f1-9120-00155dd68500', X'3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f3e0a3c646566696e6974696f6e7320786d6c6e733d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c2220786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220786d6c6e733a62706d6e64693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f44492220786d6c6e733a6f6d6764633d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44432220786d6c6e733a6f6d6764693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44492220747970654c616e67756167653d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d61222065787072657373696f6e4c616e67756167653d22687474703a2f2f7777772e77332e6f72672f313939392f585061746822207461726765744e616d6573706163653d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c223e0a20203c70726f636573732069643d2270757263686173655f726571756573745f617070726f766522206e616d653d22e98787e8b4ade5aea1e6a0b82220697345786563757461626c653d2274727565223e0a202020203c73746172744576656e742069643d2253746172744576656e7422206e616d653d22e5bc80e5a78b223e3c2f73746172744576656e743e0a202020203c757365725461736b2069643d225374617274557365724e6f646522206e616d653d22e58f91e8b5b7e4baba223e0a2020202020203c657874656e73696f6e456c656d656e74733e0a20202020202020203c666c6f7761626c653a617070726f76655479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a617070726f7665547970653e0a20202020202020203c666c6f7761626c653a63616e646964617465537472617465677920786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b33365d5d3e3c2f666c6f7761626c653a63616e64696461746553747261746567793e0a20202020202020203c666c6f7761626c653a6669656c64735065726d697373696f6e20786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e22206669656c643d22467971796d7171646f6c6e3261626322207469746c653d22e5a793e5908d22207065726d697373696f6e3d2232223e3c2f666c6f7761626c653a6669656c64735065726d697373696f6e3e0a20202020202020203c666c6f7761626c653a6669656c64735065726d697373696f6e20786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e22206669656c643d22466836676d7171646f6f793561656322207469746c653d22e5b9b4e9be8422207065726d697373696f6e3d2232223e3c2f666c6f7761626c653a6669656c64735065726d697373696f6e3e0a20202020202020203c666c6f7761626c653a6669656c64735065726d697373696f6e20786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e22206669656c643d2246356d726d71716475746e6e61626322207469746c653d22e98089e68ba9e599a822207065726d697373696f6e3d2232223e3c2f666c6f7761626c653a6669656c64735065726d697373696f6e3e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68f90e4baa42220656e61626c653d2274727565222069643d2231223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68b92e7bb9d2220656e61626c653d2266616c7365222069643d2232223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e8bdace58a9e2220656e61626c653d2266616c7365222069643d2233223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e5a794e6b4be2220656e61626c653d2266616c7365222069643d2234223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e58aa0e7adbe2220656e61626c653d2266616c7365222069643d2235223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e98080e59b9e2220656e61626c653d2266616c7365222069643d2236223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a61737369676e53746172745573657248616e646c65725479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b325d5d3e3c2f666c6f7761626c653a61737369676e53746172745573657248616e646c6572547970653e0a2020202020203c2f657874656e73696f6e456c656d656e74733e0a202020203c2f757365725461736b3e0a202020203c757365725461736b2069643d2241637469766974795f5f363936363337373834323137383238373732393237313622206e616d653d22e5aea1e689b9e4baba223e0a2020202020203c657874656e73696f6e456c656d656e74733e0a20202020202020203c666c6f7761626c653a617070726f76655479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a617070726f7665547970653e0a20202020202020203c666c6f7761626c653a63616e646964617465537472617465677920786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b33305d5d3e3c2f666c6f7761626c653a63616e64696461746553747261746567793e0a20202020202020203c666c6f7761626c653a63616e646964617465506172616d20786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b3134325d5d3e3c2f666c6f7761626c653a63616e646964617465506172616d3e0a20202020202020203c666c6f7761626c653a6669656c64735065726d697373696f6e20786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e22206669656c643d22467971796d7171646f6c6e3261626322207469746c653d22e5a793e5908d22207065726d697373696f6e3d2231223e3c2f666c6f7761626c653a6669656c64735065726d697373696f6e3e0a20202020202020203c666c6f7761626c653a6669656c64735065726d697373696f6e20786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e22206669656c643d22466836676d7171646f6f793561656322207469746c653d22e5b9b4e9be8422207065726d697373696f6e3d2231223e3c2f666c6f7761626c653a6669656c64735065726d697373696f6e3e0a20202020202020203c666c6f7761626c653a6669656c64735065726d697373696f6e20786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e22206669656c643d2246356d726d71716475746e6e61626322207469746c653d22e98089e68ba9e599a822207065726d697373696f6e3d2231223e3c2f666c6f7761626c653a6669656c64735065726d697373696f6e3e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e9809ae8bf872220656e61626c653d2274727565222069643d2231223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68b92e7bb9d2220656e61626c653d2274727565222069643d2232223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e8bdace58a9e2220656e61626c653d2274727565222069643d2233223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e5a794e6b4be2220656e61626c653d2274727565222069643d2234223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e58aa0e7adbe2220656e61626c653d2274727565222069643d2235223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e98080e59b9e2220656e61626c653d2274727565222069643d2236223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a617070726f76654d6574686f6420786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b345d5d3e3c2f666c6f7761626c653a617070726f76654d6574686f643e0a20202020202020203c666c6f7761626c653a72656a65637448616e646c65725479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a72656a65637448616e646c6572547970653e0a20202020202020203c666c6f7761626c653a61737369676e53746172745573657248616e646c65725479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a61737369676e53746172745573657248616e646c6572547970653e0a20202020202020203c666c6f7761626c653a61737369676e456d70747948616e646c65725479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a61737369676e456d70747948616e646c6572547970653e0a20202020202020203c666c6f7761626c653a7369676e456e61626c6520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b66616c73655d5d3e3c2f666c6f7761626c653a7369676e456e61626c653e0a20202020202020203c666c6f7761626c653a726561736f6e5265717569726520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b66616c73655d5d3e3c2f666c6f7761626c653a726561736f6e526571756972653e0a20202020202020203c666c6f7761626c653a6e6f64655479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b31315d5d3e3c2f666c6f7761626c653a6e6f6465547970653e0a2020202020203c2f657874656e73696f6e456c656d656e74733e0a2020202020203c6d756c7469496e7374616e63654c6f6f7043686172616374657269737469637320697353657175656e7469616c3d22747275652220666c6f7761626c653a636f6c6c656374696f6e3d22247b636f6c6c5f757365724c6973747d223e0a20202020202020203c6c6f6f7043617264696e616c6974793e313c2f6c6f6f7043617264696e616c6974793e0a20202020202020203c636f6d706c6574696f6e436f6e646974696f6e3e247b206e724f66436f6d706c65746564496e7374616e636573202667743b3d206e724f66496e7374616e636573207d3c2f636f6d706c6574696f6e436f6e646974696f6e3e0a2020202020203c2f6d756c7469496e7374616e63654c6f6f704368617261637465726973746963733e0a202020203c2f757365725461736b3e0a202020203c656e644576656e742069643d22456e644576656e7422206e616d653d22e7bb93e69d9f223e3c2f656e644576656e743e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d37626264323239362d303635622d343334652d623536332d6131633164373035626435362220736f757263655265663d2253746172744576656e7422207461726765745265663d225374617274557365724e6f6465223e3c2f73657175656e6365466c6f773e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d65623033353365322d356431392d346462662d623162642d6239646561343435613034372220736f757263655265663d225374617274557365724e6f646522207461726765745265663d2241637469766974795f5f3639363633373738343231373832383737323932373136223e3c2f73657175656e6365466c6f773e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d65616533333231612d313462392d343831632d393731652d3365656130663331626638332220736f757263655265663d2241637469766974795f5f363936363337373834323137383238373732393237313622207461726765745265663d22456e644576656e74223e3c2f73657175656e6365466c6f773e0a20203c2f70726f636573733e0a20203c62706d6e64693a42504d4e4469616772616d2069643d2242504d4e4469616772616d5f70757263686173655f726571756573745f617070726f7665223e0a202020203c62706d6e64693a42504d4e506c616e652062706d6e456c656d656e743d2270757263686173655f726571756573745f617070726f7665222069643d2242504d4e506c616e655f70757263686173655f726571756573745f617070726f7665223e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d225374617274557365724e6f6465222069643d2242504d4e53686170655f5374617274557365724e6f6465223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2236302e30222077696474683d223130302e302220783d2238302e302220793d22302e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d2241637469766974795f5f3639363633373738343231373832383737323932373136222069643d2242504d4e53686170655f41637469766974795f5f3639363633373738343231373832383737323932373136223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2236302e30222077696474683d223130302e302220783d223233302e302220793d22302e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d2253746172744576656e74222069643d2242504d4e53686170655f53746172744576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d22302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d22456e644576656e74222069643d2242504d4e53686170655f456e644576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d223338302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d65623033353365322d356431392d346462662d623162642d623964656134343561303437222069643d2242504d4e456467655f73657175656e6365466c6f772d65623033353365322d356431392d346462662d623162642d623964656134343561303437223e0a20202020202020203c6f6d6764693a776179706f696e7420783d223138302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d223233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d65616533333231612d313462392d343831632d393731652d336565613066333162663833222069643d2242504d4e456467655f73657175656e6365466c6f772d65616533333231612d313462392d343831632d393731652d336565613066333162663833223e0a20202020202020203c6f6d6764693a776179706f696e7420783d223333302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d223338302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d37626264323239362d303635622d343334652d623536332d613163316437303562643536222069643d2242504d4e456467655f73657175656e6365466c6f772d37626264323239362d303635622d343334652d623536332d613163316437303562643536223e0a20202020202020203c6f6d6764693a776179706f696e7420783d2233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d2238302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a202020203c2f62706d6e64693a42504d4e506c616e653e0a20203c2f62706d6e64693a42504d4e4469616772616d3e0a3c2f646566696e6974696f6e733e', '0'),
+('d2396d4c-74fe-11f1-9120-00155dd68500', '1', 'purchase_request_approve.purchase_request_approve.png', 'd232b68a-74fe-11f1-9120-00155dd68500', X'efbfbd504e470d0a1a0a0000000d49484452000001efbfbd000000460806000000efbfbdefbfbdefbfbd0800000b7649444154785eefbfbdefbfbd4f1cefbfbd19c6892b55efbfbdefbfbd7f10efbfbd2aefbfbdefbfbdefbfbd4aefbfbd72e18ba8efbfbdefbfbdefbfbd226cefbfbd5defbfbdefbfbd00efbfbd646c4befbfbdefbfbd42efbfbd4d516423efbfbd72efbfbdefbfbd44efbfbdefbfbd0ad592efbfbd25361fefbfbd604c1d70efbfbd15efbfbd0defbfbd260e04c7b10906efbfbd6d50efbfbd60efbfbdefbfbdefbfbdefbfbd54efbfbd7707efbfbdefbfbd1aefbfbdefbfbdefbfbdefbfbdefbfbd470befbfbd71efbfbd61efbfbdefbfbd397b66efbfbdefbfbd1415efbfbdefbfbd701cefbfbdefbfbdefbfbdefbfbdefbfbd7f1f1c1c5cefbfbdefbfbdefbfbd71efbfbdefbfbdefbfbdefbfbdefbfbd65efbfbdefbfbdefbfbdefbfbdefbfbdefbfbdc7bdefbfbdefbfbd1fefbfbdefbfbd632befbfbdefbfbdefbfbd4befbfbdefbfbdefbfbd724c685c30efbfbd75efbfbdefbfbdefbfbdefbfbdefbfbdefbfbd45efbfbdefbfbdcb9750c8a2efbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbd264876efbfbd636423efbfbdefbfbdefbfbd4befbfbdefbfbdefbfbd72efbfbd132cefbfbdefbfbdefbfbd190a5fefbfbdefbfbdefbfbd332638efbfbdefbfbd31efbfbd11efbfbd4aefbfbd34efbfbd0a28efbfbd4eefbfbdefbfbd13efbfbd0cefbfbd7130efbfbdefbfbdc48fefbfbdefbfbdefbfbd5772efbfbdefbfbd57403974efbfbdefbfbd1b18efbfbd3eefbfbdefbfbdefbfbdefbfbdefbfbd46efbfbd2b59efbfbdefbfbd2befbfbdefbfbdefbfbdefbfbdefbfbdefbfbd6cefbfbd19efbfbdefbfbdefbfbd3372efbfbdefbfbdeba29f6919efbfbd0eefbfbd4d5aefbfbd03efbfbdefbfbd252defbfbd02efbfbd09121cefbfbd73efbfbdefbfbde1ae93cebfefbfbd1e794defbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbd2538efbfbd2b59efbfbdefbfbd2befbfbdefbfbd20efbfbdefbfbd70efbfbd2d2d345cefbfbd30efbfbd79efbfbdefbfbd50efbfbdefbfbd121cefbfbd2c69efbfbd15504eefbfbdefbfbdefbfbdefbfbdefbfbd3fefbfbd05efbfbd2b5ac7b7efbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbd6449efbfbdefbfbdefbfbd72efbfbd04efbfbd7077435a60efbfbdefbfbd757c7b287b69090eefbfbd4aefbfbdefbfbdefbfbd0a2807efbfbd214b5aefbfbd03efbfbdefbfbd252defbfbd02efbfbd09121c34efbfbdefbfbd07efbfbd2b5ac7b7efbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbd6449efbfbdefbfbdefbfbd72efbfbd04efbfbdefbfbd2fefbfbdefbfbd1618efbfbd681defbfbd1eefbfbd5e5aefbfbd03efbfbdefbfbd252defbfbd02efbfbd09121cefbfbdefbfbdefbfbdefbfbd0c7fefbfbdd0a065efbfbdefbfbd6f0f652f2defbfbd015fc992165f01efbfbd04090eefbfbd7777cea705072defbfbdefbfbd41efbfbd494b70efbfbd57efbfbdefbfbdefbfbd5741292e2eefbfbd456969efbfbd11efbfbdefbfbd48243264efbfbdefbfbdefbfbd49efbfbd0eefbfbd725a4fefbfbdefbfbd7d0befbfbdefbfbd38efbfbd0607077f7befbfbdefbfbdefbfbd2f1a1b1b67efbfbd1d3befbfbd585d5defbfbd460d4c24122befbfbdefbfbdefbfbd2fccb26fefbfbdefbfbdefbfbd3eefbfbdefbfbdefbfbd78efbfbdefaf9940efbfbdefbfbdefbfbdefbfbdefbfbd1fefbfbd735a70efbfbd325aefbfbdefbfbd3defbfbdefbfbdefbfbd04077c254b5a7cefbfbd19efbfbd73efbfbdefbfbdefbfbdefbfbdd89e3d7b4652efbfbd4f20efbfbdefbfbdefbfbdefbfbdefbfbdefbfbdccbc623aefbfbd373b3b3b3f3979efbfbdefbfbd723c1e77ce9e3defbfbddcba75efbfbd191b1b736667671defbfbd5eefbfbd775a4eefbfbd63efbfbdefbfbd6a6d6defbfbd786565efbfbd07efbfbd3cefbfbd6c151c74efbfbdefbfbd375fefbfbd312d345cefbfbd3a5c55efbfbd3f69090eefbfbd4aefbfbdefbfbdefbfbd6a234cefbfbdefbfbdefbfbd742c777967efbfbdefbfbd521d53611eefbfbd613aefbfbdefbfbdcc8867efbfbdd0a143efbfbd191d39efbfbdefbfbdefbfbdefbfbd1defbfbd56efbfbd76efbfbd7d5d5defbfbdefbfbdefbfbdefbfbd07efbfbd32c3ba7779d99aefbfbd3038efbfbd27efbfbdefbfbdefbfbdefbfbdefbfbdd79defbfbdefbfbdc282efbfbdefbfbdefbfbd6defbfbd367769090eefbfbd4aefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdd0b0efbfbd7424cdbc73d9bf7fefbfbdefbfbdefbfbdefbfbdefbfbdefbfbd33efbfbdefbfbd0620efbfbdefbfbdefbfbdefbfbd767c5f2aefbfbdefbfbdefbfbd7565efbfbdefbfbdf38daeaeefbfbdcfaaefbfbdefbfbdefbfbdefbfbdefbfbd76efbfbdd5ab57efbfbdefbfbd3801efbfbdefbfbd687fefbfbdefbfbd05efbfbdefbfbdefbfbd793d5aefbfbd0befbfbdefbfbd3eefbfbd6e247cefbfbdefbfbd5d5aefbfbd03efbfbdefbfbd252defbfbdefbfbd525c5cefbfbdefbfbd19305cefbfbd7626efbfbd58efbfbd4926efbfbdefbfbdefbfbdefbfbd32efbfbd745f683bda9eefbfbdefbfbd43efbfbd52efbfbdefbfbdce8c30efbfbd71efbfbdefbfbdefbfbd7f5657573befbfbdefbfbdefbfbdefbfbd756705efbfbd13efbfbdefbfbd7fefbfbd46efbfbd315eefbfbd06efbfbdefbfbd23c8a7d78d44efbfbdefbfbdefbfbdefbfbdefbfbd121cefbfbd2c69efbfbd0befbfbd604cefbfbd71efbfbddb89efbfbd3e7dda99efbfbdefbfbdefbfbd111e08da8fefbfbd67efbfbdefbfbd2b39efbfbdefbfbd6864efbfbd4824efbfbd1fdb9b4fefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbd78efbfbdefbfbdefbfbd171c3c0c32152f0f0a2e2defbfbd015fc992165fefbfbd784fd399efbfbdefbfbd0b172e386b6b6b3cefbfbd33efbfbdefbfbdefbfbd72efbfbd3c4fefbfbdcdbcefbfbd400c0c0c7c44efbfbd51efbfbd46461c53efbfbdefbfbddebd7befbfbd65efbfbd6001efbfbd0b0e68efbfbdefbfbd2538efbfbd2b59efbfbdefbfbd2befbfbd7414efbfbdefbfbd2319efbfbd44efbfbd09efbfbdefbfbd464aefbfbd4d743065efbfbd79efbfbdd4a945efbfbdcea7efbfbd24efbfbdc9b96834efbfbdefbfbdefbfbd1904efbfbd2c69090eefbfbd4aefbfbdefbfbdefbfbdefbfbdefbfbd667b67efbfbdefbfbd69efbfbd5c47461c2aefbfbd7befbfbdefbfbd66efbfbd653425efbfbdefbfbdefbfbdefbfbd2f34efbfbd2eefbfbd090c41efbfbdefbfbdefbfbdefbfbdefbfbd744949c9af791b6c05efbfbd214b5aefbfbd03efbfbdefbfbd252defbfbd321d44efbfbdefbfbd28682242efbfbdefbfbd196d05efbfbdefbfbd263a04efbfbd4360efbfbdefbfbd75efbfbdc48965efbfbdefbfbd1d06376fefbfbd7c661aefbfbd0fefbfbd0e5b4170c892efbfbdefbfbdefbfbdefbfbd6449efbfbdefbfbdefbfbd17efbfbdefbfbdefbfbdefbfbdefbfbd78efbfbd2b54efbfbd77efbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbd6f2a2b2b035f67efbfbd2b544f5959efbfbd3333efbfbd7befbfbdefbfbd4512efbfbd4defbfbd6eefbfbd2befbfbdefbfbdefbfbdefbfbdefbfbd25efbfbdefbfbd015fefbfbd290defbfbdefbfbd46efbfbdefbfbd743b08efbfbd7eefbfbdefbfbdefbfbd4242efbfbd7befbfbd53efbfbdefbfbd79efbfbdefbfbd3877efbfbd5c37efbfbd61214c1a1b1befbfbd4b4b4befbfbd795b24e1be895b1d6804efbfbd2c59101cefbfbdefbfbdefbfbd2befbfbdefbfbdefbfbdefbfbdefbfbdcc99333cefbfbd0b02efbfbdefbfbd695b3d6f531a4d4d4defbfbd61efbfbdefbfbd73efbfbd76efbfbd1a0d1b2fefbfbd48efbfbdefbfbd266e7aefbfbd111cefbfbd645170efbfbd571649efbfbdefbfbdefbfbdefbfbd49773defbfbd69210cefbfbd1e4fefbfbdefbfbdefbfbdefbfbdefbfbd72efbfbdefbfbdefbfbdefbfbdefbfbdefbfbd715e4e41191d1defbfbd30efbfbdefbfbdefbfbdefbfbd2209efbfbd03efbfbd7befbfbd111cefbfbd646170efbfbd571648efbfbdefbfbdefbfbdefbfbd6d777958efbfbd4fefbfbd78dab275efbfbd2712efbfbdefbfbdefbfbd4fefbfbdefbfbd720aefbfbdefbfbdefbfbdefbfbd69efbfbd23efbfbd1649efbfbd1c58efbfbdefbfbd03efbfbdefbfbdefbfbd25efbfbdefbfbd03efbfbd122c25efbfbdefbfbd717f0f2befbfbd1e4f1befbfbdefbfbdefbfbdefbfbdefbfbd72676565efbfbdefbfbd53504c7d2f7cefbfbd302befbfbdefbfbdefbfbd257e7c6c157c254befbfbdefbfbdd8aeefbfbd32efbfbdefbfbdefbfbdd4bbefbfbdefbfbdefbfbd34efbfbdefbfbdefbfbd56efbfbdefbfbd2d5defbfbdefbfbdefbfbdefbfbdefbfbd04efbfbd2defbfbd117e003defbfbd1eefbfbdefbfbd15efbfbdefbfbdefbfbdefbfbd2c7c25581a7c655e1fefbfbdefbfbdefbfbdefbfbdefbfbdefbfbd4748efbfbd0f1f7e11efbfbdefbfbd44efbfbdefbfbd77efbfbdde890439efbfbdefbfbdefbfbd6c7660efbfbd480f0eefbfbd445fefbfbd6befbfbd3459181cefbfbdefbfbd7a69efbfbde0ab880defbfbd211d3f7eefbfbdefbfbdefbfbd67efbfbd5defbfbd74efbfbd1eefbfbd6befbfbd2cefbfbdefbfbd03efbfbdc586efbfbdefbfbd6c59efbfbdefbfbdc9a2efbfbdefbfbdefbfbd36592f4d1a7c15efbfbd61efbfbd5d6363efbfbdefbfbd615fefbfbd545353efbfbd6eefbfbd75481b1e582f080e59efbfbd2038efbfbd00efbfbd49efbfbdefbfbd22365cefbfbd545151efbfbd4e3c1e5f0defbfbd4e0d3fefbfbdefbfbd4d4befbfbd534350101cefbfbd243d38efbfbd025fc992065f6dc79d1aefbfbdefbfbddbb7efbfbdefbfbd19efbfbd4e0d446d6defbfbd7761efbfbdefbfbd6b6d6defbfbd6b04efbfbdefbfbd0b4d453eefbfbdefbfbdefbfbd65efbfbdefbfbdefbfbd260defbfbd41efbfbd57efbfbdefbfbdefbfbd57efbfbdefbfbd65475456567e505757efbfbd12efbfbdddbe1fefbfbdefbfbdefbfbdefbfbdddbeefbfbd53efbfbdefbfbd3fefbfbd7759efbfbdefbfbd494b70efbfbd57efbfbdefbfbdefbfbd57efbfbd10efbfbdefbfbd7defbfbdefbfbdefbfbd55efbfbd2eefbfbdefbfbdefbfbd65536a6a6aefbfbd6a6f6fefbfbdefbfbd315e67efbfbdefbfbdefbfbdefbfbd53d3b0765eefbfbdefbfbd203864494b70efbfbd57efbfbdefbfbdefbfbd57efbfbdefbfbd21efbfbd7fefbfbd24efbfbd7948043dc9951e335eefbfbd27efbfbddeb871efbfbd69efbfbd24efbfbd181befbfbd4c137defbfbdefbfbdefbfbdd2a42538efbfbd2b59efbfbdefbfbd2b2222efbfbdefbfbdefbfbd2eefbfbd277befbfbd0cefbfbd7eefbfbdefbfbdefbfbdefbfbd75efbfbdefbfbdefbfbdefbfbdefbfbdefbfbd51efbfbd4b4a4aefbfbdefbfbd75da8eefbfbdefbfbdefbfbd69efbfbd121cefbfbd2c69efbfbdefbfbdefbfbd66efbfbd0866efbfbd13efbfbd75efbfbd44efbfbd533954efbfbdefbfbdefbfbd665e774644efbfbdd1981929efbfbdefbfbdefbfbd48293532efbfbd2befbfbd0fefbfbd34efbfbdefbfbdefbfbd252defbfbd015fc992165fefbfbd343434efbfbd32efbfbd7cefbfbd3befbfbdefbfbdefbfbd6cefbfbd7eefbfbd44efbfbd794fd3a574efbfbdefbfbdefbfbd75670cefbfbd64efbfbdefbfbdefbfbdefbfbdefbfbdefbfbd5cefbfbd131d680243efbfbd3befbfbd1f35efbfbdefbfbd5c101cefbfbdefbfbd2538efbfbd2b59efbfbdefbfbd2b2fefbfbdefbfbdefbfbd6fefbfbdefbfbdefbfbd5eefbfbd762234efbfbdefbfbde4beb3efbfbdefbfbdefbfbd23efbfbd17da8eefbfbd6713181c2aefbfbdefbfbdefbfbd7566efbfbd29efbfbd5d335aefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbd29efbfbdefbfbdefbfbd5a5b5b3f33efbfbdefbfbd6fefbfbd41efbfbdefbfbd35efbfbdefbfbdefbfbd252defbfbd015fc992165f716804efbfbd3d7de78aae536a696959efbfbdefbfbdefbfbdefbfbdefbfbd183defbfbd613defbfbdefbfbd7eefbfbdefbfbdefbfbd7befbfbdefbfbd2b2a2f2f23233f68efbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdecb9a9efbfbdeb9e9eefbfbdefbfbdefbfbdefbfbdefbfbdefbfbd676666164cefbfbdefbfbd3c79323e323272efbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbdda8eefbfbdefbfbd6e71deaf696aefbfbd66203864494b70efbfbde4ab85efbfbd056778783863efbfbd7eefbfbd2cefbfbdefbfbde2ab8d30efbfbdefbfbdefbfbd3befbfbd2e1befbfbdefbfbdefbfbd6e0243efbfbdd09d154c650933efbfbdefbfbdefbfbd0d19efbfbd3545efbfbd107a1d4a2d4f68efbfbd0343506c0aefbfbdefbfbd202defbfbd61efbfbdefbfbdefbfbd7329efbfbd31efbfbdefbfbd683f5eefbfbd5469efbfbdefbfbd66efbfbdefbfbd6cefbfbdefbfbd4c3befbfbdefbfbdefbfbdefbfbdefbfbdefbfbd76efbfbdefbfbd635370efbfbd0469090eefbfbd7cefbfbd11efbfbd3eefbfbdefbfbd1c33efbfbd38efbfbdefbfbd00efbfbdefbfbd6befbfbdefbfbdefbfbd7a6c0aefbfbdefbfbd202defbfbd015fc992165f01efbfbd203864494b70efbfbd57efbfbdefbfbdefbfbd574039080e59efbfbd121cefbfbd2c69efbfbd15500eefbfbd43efbfbdefbfbd04efbfbd4defbfbdefbfbd77480008efbfbdefbfbdefbfbdefbfbd09efbfbd121c36efbfbdefbfbd3aefbfbd22efbfbd59745befbfbdefbfbdefbfbd6549efbfbd165f01efbfbdefbfbd141c3b415aefbfbdefbfbd265f61efbfbd04efbfbd106c0aefbfbdefbfbd202defbfbd015fc992165f01efbfbd203864494b70efbfbd57efbfbdefbfbdefbfbd574039080e59efbfbd121cefbfbd2c69efbfbd15500eefbfbd43efbfbdefbfbd04efbfbd4defbfbdefbfbd77480008efbfbdefbfbdefbfbd676d717131efbfbdefbfbd50efbfbd32efbfbdefbfbd09efbfbd257eefbfbd6cefbfbd265f51efbfbd52efbfbd33efbfbd6e2befbfbd7eefbfbd2cefbfbdefbfbdefbfbd2befbfbdefbfbdefbfbdefbfbdefbfbdefbfbdefbfbd5d6e62287c3d78efbfbdefbfbd04efbfbd103f463662efbfbdefbfbdefbfbdefbfbdefbfbd34efbfbd0a28efbfbdefbfbdefbfbdefbfbdc3beefbfbdefbfbde79393efbfbd33efbfbd7cefbfbdefbfbd26efbfbd4f4e4c4cefbfbdcd84efbfbdefbfbd46efbfbdefbfbdefbfbdefbfbdefbfbdefbfbd57efbfbd2fefbfbdefbfbd023b00322b7defbfbd327a49e79aa1efbfbd45efbfbd3befbfbdefbfbdefbfbd42efbfbdefbfbdefbfbdefbfbdefbfbd055f6defbfbd54efbfbd0a000000000000000000000000000000000000000000000000000000000000000000000000efbfbd23efbfbd050befbfbd0816330fefbfbdefbfbd0000000049454e44efbfbd4260efbfbd', '1'),
+('byte_08349f78d675f582f1ff5f08e7714a8d', NULL, 'mes-pro-feedback-audit.bpmn', 'dep_08349f78d675f582f1ff5f08e7714a8d', X'3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f3e0a3c646566696e6974696f6e7320786d6c6e733d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c2220786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220786d6c6e733a62706d6e64693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f44492220786d6c6e733a6f6d6764633d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44432220786d6c6e733a6f6d6764693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44492220747970654c616e67756167653d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d61222065787072657373696f6e4c616e67756167653d22687474703a2f2f7777772e77332e6f72672f313939392f585061746822207461726765744e616d6573706163653d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c223e0a20203c70726f636573732069643d226d65732d70726f2d666565646261636b2d617564697422206e616d653d22e68aa5e5b7a5e5aea1e689b92220697345786563757461626c653d2274727565223e0a202020203c73746172744576656e742069643d2253746172744576656e7422206e616d653d22e5bc80e5a78b223e3c2f73746172744576656e743e0a202020203c757365725461736b2069643d225374617274557365724e6f646522206e616d653d22e58f91e8b5b7e4baba223e0a2020202020203c657874656e73696f6e456c656d656e74733e0a20202020202020203c666c6f7761626c653a617070726f76655479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a617070726f7665547970653e0a20202020202020203c666c6f7761626c653a63616e646964617465537472617465677920786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b33365d5d3e3c2f666c6f7761626c653a63616e64696461746553747261746567793e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68f90e4baa42220656e61626c653d2274727565222069643d2231223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68b92e7bb9d2220656e61626c653d2266616c7365222069643d2232223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e8bdace58a9e2220656e61626c653d2266616c7365222069643d2233223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e5a794e6b4be2220656e61626c653d2266616c7365222069643d2234223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e58aa0e7adbe2220656e61626c653d2266616c7365222069643d2235223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e98080e59b9e2220656e61626c653d2266616c7365222069643d2236223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a61737369676e53746172745573657248616e646c65725479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b325d5d3e3c2f666c6f7761626c653a61737369676e53746172745573657248616e646c6572547970653e0a2020202020203c2f657874656e73696f6e456c656d656e74733e0a202020203c2f757365725461736b3e0a202020203c656e644576656e742069643d22456e644576656e7422206e616d653d22e7bb93e69d9f223e3c2f656e644576656e743e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d312220736f757263655265663d2253746172744576656e7422207461726765745265663d225374617274557365724e6f6465223e3c2f73657175656e6365466c6f773e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d322220736f757263655265663d225374617274557365724e6f646522207461726765745265663d22456e644576656e74223e3c2f73657175656e6365466c6f773e0a20203c2f70726f636573733e0a20203c62706d6e64693a42504d4e4469616772616d2069643d2242504d4e4469616772616d5f6d65732d70726f2d666565646261636b2d6175646974223e0a202020203c62706d6e64693a42504d4e506c616e652062706d6e456c656d656e743d226d65732d70726f2d666565646261636b2d6175646974222069643d2242504d4e506c616e655f6d65732d70726f2d666565646261636b2d6175646974223e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d225374617274557365724e6f6465222069643d2242504d4e53686170655f5374617274557365724e6f6465223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2236302e30222077696474683d223130302e302220783d2238302e302220793d22302e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d2253746172744576656e74222069643d2242504d4e53686170655f53746172744576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d22302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d22456e644576656e74222069643d2242504d4e53686170655f456e644576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d223233302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d32222069643d2242504d4e456467655f73657175656e6365466c6f772d32223e0a20202020202020203c6f6d6764693a776179706f696e7420783d223138302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d223233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d31222069643d2242504d4e456467655f73657175656e6365466c6f772d31223e0a20202020202020203c6f6d6764693a776179706f696e7420783d2233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d2238302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a202020203c2f62706d6e64693a42504d4e506c616e653e0a20203c2f62706d6e64693a42504d4e4469616772616d3e0a3c2f646566696e6974696f6e733e', '0'),
+('byte_09ba42e32e7a436ee4e2a9b6eef0d232', NULL, 'purchase_order_approve.bpmn', 'dep_09ba42e32e7a436ee4e2a9b6eef0d232', X'3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f3e0a3c646566696e6974696f6e7320786d6c6e733d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c2220786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220786d6c6e733a62706d6e64693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f44492220786d6c6e733a6f6d6764633d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44432220786d6c6e733a6f6d6764693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44492220747970654c616e67756167653d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d61222065787072657373696f6e4c616e67756167653d22687474703a2f2f7777772e77332e6f72672f313939392f585061746822207461726765744e616d6573706163653d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c223e0a20203c70726f636573732069643d2270757263686173655f6f726465725f617070726f766522206e616d653d22e98787e8b4ade8aea2e58d95e5aea1e689b92220697345786563757461626c653d2274727565223e0a202020203c73746172744576656e742069643d2253746172744576656e7422206e616d653d22e5bc80e5a78b223e3c2f73746172744576656e743e0a202020203c757365725461736b2069643d225374617274557365724e6f646522206e616d653d22e58f91e8b5b7e4baba223e0a2020202020203c657874656e73696f6e456c656d656e74733e0a20202020202020203c666c6f7761626c653a617070726f76655479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a617070726f7665547970653e0a20202020202020203c666c6f7761626c653a63616e646964617465537472617465677920786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b33365d5d3e3c2f666c6f7761626c653a63616e64696461746553747261746567793e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68f90e4baa42220656e61626c653d2274727565222069643d2231223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68b92e7bb9d2220656e61626c653d2266616c7365222069643d2232223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e8bdace58a9e2220656e61626c653d2266616c7365222069643d2233223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e5a794e6b4be2220656e61626c653d2266616c7365222069643d2234223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e58aa0e7adbe2220656e61626c653d2266616c7365222069643d2235223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e98080e59b9e2220656e61626c653d2266616c7365222069643d2236223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a61737369676e53746172745573657248616e646c65725479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b325d5d3e3c2f666c6f7761626c653a61737369676e53746172745573657248616e646c6572547970653e0a2020202020203c2f657874656e73696f6e456c656d656e74733e0a202020203c2f757365725461736b3e0a202020203c656e644576656e742069643d22456e644576656e7422206e616d653d22e7bb93e69d9f223e3c2f656e644576656e743e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d312220736f757263655265663d2253746172744576656e7422207461726765745265663d225374617274557365724e6f6465223e3c2f73657175656e6365466c6f773e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d322220736f757263655265663d225374617274557365724e6f646522207461726765745265663d22456e644576656e74223e3c2f73657175656e6365466c6f773e0a20203c2f70726f636573733e0a20203c62706d6e64693a42504d4e4469616772616d2069643d2242504d4e4469616772616d5f70757263686173655f6f726465725f617070726f7665223e0a202020203c62706d6e64693a42504d4e506c616e652062706d6e456c656d656e743d2270757263686173655f6f726465725f617070726f7665222069643d2242504d4e506c616e655f70757263686173655f6f726465725f617070726f7665223e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d225374617274557365724e6f6465222069643d2242504d4e53686170655f5374617274557365724e6f6465223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2236302e30222077696474683d223130302e302220783d2238302e302220793d22302e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d2253746172744576656e74222069643d2242504d4e53686170655f53746172744576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d22302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d22456e644576656e74222069643d2242504d4e53686170655f456e644576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d223233302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d32222069643d2242504d4e456467655f73657175656e6365466c6f772d32223e0a20202020202020203c6f6d6764693a776179706f696e7420783d223138302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d223233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d31222069643d2242504d4e456467655f73657175656e6365466c6f772d31223e0a20202020202020203c6f6d6764693a776179706f696e7420783d2233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d2238302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a202020203c2f62706d6e64693a42504d4e506c616e653e0a20203c2f62706d6e64693a42504d4e4469616772616d3e0a3c2f646566696e6974696f6e733e', '0'),
+('byte_33d3b1649a923d986d89604267b79bbf', NULL, 'hrm_resignation.bpmn', 'dep_33d3b1649a923d986d89604267b79bbf', X'3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f3e0a3c646566696e6974696f6e7320786d6c6e733d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c2220786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220786d6c6e733a62706d6e64693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f44492220786d6c6e733a6f6d6764633d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44432220786d6c6e733a6f6d6764693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44492220747970654c616e67756167653d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d61222065787072657373696f6e4c616e67756167653d22687474703a2f2f7777772e77332e6f72672f313939392f585061746822207461726765744e616d6573706163653d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c223e0a20203c70726f636573732069643d2268726d5f72657369676e6174696f6e22206e616d653d22e7a6bbe8818ce5aea1e689b92220697345786563757461626c653d2274727565223e0a202020203c73746172744576656e742069643d2253746172744576656e7422206e616d653d22e5bc80e5a78b223e3c2f73746172744576656e743e0a202020203c757365725461736b2069643d225374617274557365724e6f646522206e616d653d22e58f91e8b5b7e4baba223e0a2020202020203c657874656e73696f6e456c656d656e74733e0a20202020202020203c666c6f7761626c653a617070726f76655479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a617070726f7665547970653e0a20202020202020203c666c6f7761626c653a63616e646964617465537472617465677920786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b33365d5d3e3c2f666c6f7761626c653a63616e64696461746553747261746567793e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68f90e4baa42220656e61626c653d2274727565222069643d2231223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68b92e7bb9d2220656e61626c653d2266616c7365222069643d2232223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e8bdace58a9e2220656e61626c653d2266616c7365222069643d2233223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e5a794e6b4be2220656e61626c653d2266616c7365222069643d2234223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e58aa0e7adbe2220656e61626c653d2266616c7365222069643d2235223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e98080e59b9e2220656e61626c653d2266616c7365222069643d2236223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a61737369676e53746172745573657248616e646c65725479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b325d5d3e3c2f666c6f7761626c653a61737369676e53746172745573657248616e646c6572547970653e0a2020202020203c2f657874656e73696f6e456c656d656e74733e0a202020203c2f757365725461736b3e0a202020203c656e644576656e742069643d22456e644576656e7422206e616d653d22e7bb93e69d9f223e3c2f656e644576656e743e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d312220736f757263655265663d2253746172744576656e7422207461726765745265663d225374617274557365724e6f6465223e3c2f73657175656e6365466c6f773e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d322220736f757263655265663d225374617274557365724e6f646522207461726765745265663d22456e644576656e74223e3c2f73657175656e6365466c6f773e0a20203c2f70726f636573733e0a20203c62706d6e64693a42504d4e4469616772616d2069643d2242504d4e4469616772616d5f68726d5f72657369676e6174696f6e223e0a202020203c62706d6e64693a42504d4e506c616e652062706d6e456c656d656e743d2268726d5f72657369676e6174696f6e222069643d2242504d4e506c616e655f68726d5f72657369676e6174696f6e223e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d225374617274557365724e6f6465222069643d2242504d4e53686170655f5374617274557365724e6f6465223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2236302e30222077696474683d223130302e302220783d2238302e302220793d22302e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d2253746172744576656e74222069643d2242504d4e53686170655f53746172744576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d22302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d22456e644576656e74222069643d2242504d4e53686170655f456e644576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d223233302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d32222069643d2242504d4e456467655f73657175656e6365466c6f772d32223e0a20202020202020203c6f6d6764693a776179706f696e7420783d223138302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d223233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d31222069643d2242504d4e456467655f73657175656e6365466c6f772d31223e0a20202020202020203c6f6d6764693a776179706f696e7420783d2233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d2238302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a202020203c2f62706d6e64693a42504d4e506c616e653e0a20203c2f62706d6e64693a42504d4e4469616772616d3e0a3c2f646566696e6974696f6e733e', '0'),
+('byte_66ea9f27906591b4d0048d854c633a82', NULL, 'hrm_transfer.bpmn', 'dep_66ea9f27906591b4d0048d854c633a82', X'3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f3e0a3c646566696e6974696f6e7320786d6c6e733d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c2220786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220786d6c6e733a62706d6e64693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f44492220786d6c6e733a6f6d6764633d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44432220786d6c6e733a6f6d6764693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44492220747970654c616e67756167653d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d61222065787072657373696f6e4c616e67756167653d22687474703a2f2f7777772e77332e6f72672f313939392f585061746822207461726765744e616d6573706163653d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c223e0a20203c70726f636573732069643d2268726d5f7472616e7366657222206e616d653d22e8b083e58aa8e5aea1e689b92220697345786563757461626c653d2274727565223e0a202020203c73746172744576656e742069643d2253746172744576656e7422206e616d653d22e5bc80e5a78b223e3c2f73746172744576656e743e0a202020203c757365725461736b2069643d225374617274557365724e6f646522206e616d653d22e58f91e8b5b7e4baba223e0a2020202020203c657874656e73696f6e456c656d656e74733e0a20202020202020203c666c6f7761626c653a617070726f76655479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a617070726f7665547970653e0a20202020202020203c666c6f7761626c653a63616e646964617465537472617465677920786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b33365d5d3e3c2f666c6f7761626c653a63616e64696461746553747261746567793e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68f90e4baa42220656e61626c653d2274727565222069643d2231223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68b92e7bb9d2220656e61626c653d2266616c7365222069643d2232223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e8bdace58a9e2220656e61626c653d2266616c7365222069643d2233223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e5a794e6b4be2220656e61626c653d2266616c7365222069643d2234223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e58aa0e7adbe2220656e61626c653d2266616c7365222069643d2235223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e98080e59b9e2220656e61626c653d2266616c7365222069643d2236223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a61737369676e53746172745573657248616e646c65725479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b325d5d3e3c2f666c6f7761626c653a61737369676e53746172745573657248616e646c6572547970653e0a2020202020203c2f657874656e73696f6e456c656d656e74733e0a202020203c2f757365725461736b3e0a202020203c656e644576656e742069643d22456e644576656e7422206e616d653d22e7bb93e69d9f223e3c2f656e644576656e743e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d312220736f757263655265663d2253746172744576656e7422207461726765745265663d225374617274557365724e6f6465223e3c2f73657175656e6365466c6f773e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d322220736f757263655265663d225374617274557365724e6f646522207461726765745265663d22456e644576656e74223e3c2f73657175656e6365466c6f773e0a20203c2f70726f636573733e0a20203c62706d6e64693a42504d4e4469616772616d2069643d2242504d4e4469616772616d5f68726d5f7472616e73666572223e0a202020203c62706d6e64693a42504d4e506c616e652062706d6e456c656d656e743d2268726d5f7472616e73666572222069643d2242504d4e506c616e655f68726d5f7472616e73666572223e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d225374617274557365724e6f6465222069643d2242504d4e53686170655f5374617274557365724e6f6465223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2236302e30222077696474683d223130302e302220783d2238302e302220793d22302e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d2253746172744576656e74222069643d2242504d4e53686170655f53746172744576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d22302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d22456e644576656e74222069643d2242504d4e53686170655f456e644576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d223233302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d32222069643d2242504d4e456467655f73657175656e6365466c6f772d32223e0a20202020202020203c6f6d6764693a776179706f696e7420783d223138302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d223233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d31222069643d2242504d4e456467655f73657175656e6365466c6f772d31223e0a20202020202020203c6f6d6764693a776179706f696e7420783d2233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d2238302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a202020203c2f62706d6e64693a42504d4e506c616e653e0a20203c2f62706d6e64693a42504d4e4469616772616d3e0a3c2f646566696e6974696f6e733e', '0'),
+('byte_6e0f473d28c042b8b372d00797549423', NULL, 'wms_inbound_approve.bpmn', 'dep_6e0f473d28c042b8b372d00797549423', X'3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f3e0a3c646566696e6974696f6e7320786d6c6e733d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c2220786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220786d6c6e733a62706d6e64693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f44492220786d6c6e733a6f6d6764633d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44432220786d6c6e733a6f6d6764693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44492220747970654c616e67756167653d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d61222065787072657373696f6e4c616e67756167653d22687474703a2f2f7777772e77332e6f72672f313939392f585061746822207461726765744e616d6573706163653d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c223e0a20203c70726f636573732069643d22776d735f696e626f756e645f617070726f766522206e616d653d22e4bb93e5ba93e585a5e5ba93e5aea1e689b92220697345786563757461626c653d2274727565223e0a202020203c73746172744576656e742069643d2253746172744576656e7422206e616d653d22e5bc80e5a78b223e3c2f73746172744576656e743e0a202020203c757365725461736b2069643d225374617274557365724e6f646522206e616d653d22e58f91e8b5b7e4baba223e0a2020202020203c657874656e73696f6e456c656d656e74733e0a20202020202020203c666c6f7761626c653a617070726f76655479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a617070726f7665547970653e0a20202020202020203c666c6f7761626c653a63616e646964617465537472617465677920786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b33365d5d3e3c2f666c6f7761626c653a63616e64696461746553747261746567793e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68f90e4baa42220656e61626c653d2274727565222069643d2231223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68b92e7bb9d2220656e61626c653d2266616c7365222069643d2232223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e8bdace58a9e2220656e61626c653d2266616c7365222069643d2233223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e5a794e6b4be2220656e61626c653d2266616c7365222069643d2234223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e58aa0e7adbe2220656e61626c653d2266616c7365222069643d2235223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e98080e59b9e2220656e61626c653d2266616c7365222069643d2236223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a61737369676e53746172745573657248616e646c65725479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b325d5d3e3c2f666c6f7761626c653a61737369676e53746172745573657248616e646c6572547970653e0a2020202020203c2f657874656e73696f6e456c656d656e74733e0a202020203c2f757365725461736b3e0a202020203c656e644576656e742069643d22456e644576656e7422206e616d653d22e7bb93e69d9f223e3c2f656e644576656e743e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d312220736f757263655265663d2253746172744576656e7422207461726765745265663d225374617274557365724e6f6465223e3c2f73657175656e6365466c6f773e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d322220736f757263655265663d225374617274557365724e6f646522207461726765745265663d22456e644576656e74223e3c2f73657175656e6365466c6f773e0a20203c2f70726f636573733e0a20203c62706d6e64693a42504d4e4469616772616d2069643d2242504d4e4469616772616d5f776d735f696e626f756e645f617070726f7665223e0a202020203c62706d6e64693a42504d4e506c616e652062706d6e456c656d656e743d22776d735f696e626f756e645f617070726f7665222069643d2242504d4e506c616e655f776d735f696e626f756e645f617070726f7665223e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d225374617274557365724e6f6465222069643d2242504d4e53686170655f5374617274557365724e6f6465223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2236302e30222077696474683d223130302e302220783d2238302e302220793d22302e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d2253746172744576656e74222069643d2242504d4e53686170655f53746172744576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d22302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d22456e644576656e74222069643d2242504d4e53686170655f456e644576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d223233302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d32222069643d2242504d4e456467655f73657175656e6365466c6f772d32223e0a20202020202020203c6f6d6764693a776179706f696e7420783d223138302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d223233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d31222069643d2242504d4e456467655f73657175656e6365466c6f772d31223e0a20202020202020203c6f6d6764693a776179706f696e7420783d2233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d2238302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a202020203c2f62706d6e64693a42504d4e506c616e653e0a20203c2f62706d6e64693a42504d4e4469616772616d3e0a3c2f646566696e6974696f6e733e', '0'),
+('byte_862c6766e8cd1b32946a1ed2956a68bf', NULL, 'hrm_leave.bpmn', 'dep_862c6766e8cd1b32946a1ed2956a68bf', X'3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f3e0a3c646566696e6974696f6e7320786d6c6e733d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c2220786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220786d6c6e733a62706d6e64693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f44492220786d6c6e733a6f6d6764633d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44432220786d6c6e733a6f6d6764693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44492220747970654c616e67756167653d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d61222065787072657373696f6e4c616e67756167653d22687474703a2f2f7777772e77332e6f72672f313939392f585061746822207461726765744e616d6573706163653d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c223e0a20203c70726f636573732069643d2268726d5f6c6561766522206e616d653d22e8afb7e58187e5aea1e689b92220697345786563757461626c653d2274727565223e0a202020203c73746172744576656e742069643d2253746172744576656e7422206e616d653d22e5bc80e5a78b223e3c2f73746172744576656e743e0a202020203c757365725461736b2069643d225374617274557365724e6f646522206e616d653d22e58f91e8b5b7e4baba223e0a2020202020203c657874656e73696f6e456c656d656e74733e0a20202020202020203c666c6f7761626c653a617070726f76655479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a617070726f7665547970653e0a20202020202020203c666c6f7761626c653a63616e646964617465537472617465677920786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b33365d5d3e3c2f666c6f7761626c653a63616e64696461746553747261746567793e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68f90e4baa42220656e61626c653d2274727565222069643d2231223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68b92e7bb9d2220656e61626c653d2266616c7365222069643d2232223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e8bdace58a9e2220656e61626c653d2266616c7365222069643d2233223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e5a794e6b4be2220656e61626c653d2266616c7365222069643d2234223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e58aa0e7adbe2220656e61626c653d2266616c7365222069643d2235223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e98080e59b9e2220656e61626c653d2266616c7365222069643d2236223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a61737369676e53746172745573657248616e646c65725479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b325d5d3e3c2f666c6f7761626c653a61737369676e53746172745573657248616e646c6572547970653e0a2020202020203c2f657874656e73696f6e456c656d656e74733e0a202020203c2f757365725461736b3e0a202020203c656e644576656e742069643d22456e644576656e7422206e616d653d22e7bb93e69d9f223e3c2f656e644576656e743e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d312220736f757263655265663d2253746172744576656e7422207461726765745265663d225374617274557365724e6f6465223e3c2f73657175656e6365466c6f773e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d322220736f757263655265663d225374617274557365724e6f646522207461726765745265663d22456e644576656e74223e3c2f73657175656e6365466c6f773e0a20203c2f70726f636573733e0a20203c62706d6e64693a42504d4e4469616772616d2069643d2242504d4e4469616772616d5f68726d5f6c65617665223e0a202020203c62706d6e64693a42504d4e506c616e652062706d6e456c656d656e743d2268726d5f6c65617665222069643d2242504d4e506c616e655f68726d5f6c65617665223e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d225374617274557365724e6f6465222069643d2242504d4e53686170655f5374617274557365724e6f6465223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2236302e30222077696474683d223130302e302220783d2238302e302220793d22302e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d2253746172744576656e74222069643d2242504d4e53686170655f53746172744576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d22302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d22456e644576656e74222069643d2242504d4e53686170655f456e644576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d223233302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d32222069643d2242504d4e456467655f73657175656e6365466c6f772d32223e0a20202020202020203c6f6d6764693a776179706f696e7420783d223138302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d223233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d31222069643d2242504d4e456467655f73657175656e6365466c6f772d31223e0a20202020202020203c6f6d6764693a776179706f696e7420783d2233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d2238302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a202020203c2f62706d6e64693a42504d4e506c616e653e0a20203c2f62706d6e64693a42504d4e4469616772616d3e0a3c2f646566696e6974696f6e733e', '0'),
+('byte_9b3368e05f1d39dee636f464f2d65c16', NULL, 'wms_transfer_approve.bpmn', 'dep_9b3368e05f1d39dee636f464f2d65c16', X'3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f3e0a3c646566696e6974696f6e7320786d6c6e733d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c2220786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220786d6c6e733a62706d6e64693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f44492220786d6c6e733a6f6d6764633d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44432220786d6c6e733a6f6d6764693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44492220747970654c616e67756167653d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d61222065787072657373696f6e4c616e67756167653d22687474703a2f2f7777772e77332e6f72672f313939392f585061746822207461726765744e616d6573706163653d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c223e0a20203c70726f636573732069643d22776d735f7472616e736665725f617070726f766522206e616d653d22e4bb93e5ba93e8b083e68ba8e5aea1e689b92220697345786563757461626c653d2274727565223e0a202020203c73746172744576656e742069643d2253746172744576656e7422206e616d653d22e5bc80e5a78b223e3c2f73746172744576656e743e0a202020203c757365725461736b2069643d225374617274557365724e6f646522206e616d653d22e58f91e8b5b7e4baba223e0a2020202020203c657874656e73696f6e456c656d656e74733e0a20202020202020203c666c6f7761626c653a617070726f76655479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a617070726f7665547970653e0a20202020202020203c666c6f7761626c653a63616e646964617465537472617465677920786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b33365d5d3e3c2f666c6f7761626c653a63616e64696461746553747261746567793e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68f90e4baa42220656e61626c653d2274727565222069643d2231223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68b92e7bb9d2220656e61626c653d2266616c7365222069643d2232223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e8bdace58a9e2220656e61626c653d2266616c7365222069643d2233223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e5a794e6b4be2220656e61626c653d2266616c7365222069643d2234223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e58aa0e7adbe2220656e61626c653d2266616c7365222069643d2235223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e98080e59b9e2220656e61626c653d2266616c7365222069643d2236223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a61737369676e53746172745573657248616e646c65725479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b325d5d3e3c2f666c6f7761626c653a61737369676e53746172745573657248616e646c6572547970653e0a2020202020203c2f657874656e73696f6e456c656d656e74733e0a202020203c2f757365725461736b3e0a202020203c656e644576656e742069643d22456e644576656e7422206e616d653d22e7bb93e69d9f223e3c2f656e644576656e743e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d312220736f757263655265663d2253746172744576656e7422207461726765745265663d225374617274557365724e6f6465223e3c2f73657175656e6365466c6f773e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d322220736f757263655265663d225374617274557365724e6f646522207461726765745265663d22456e644576656e74223e3c2f73657175656e6365466c6f773e0a20203c2f70726f636573733e0a20203c62706d6e64693a42504d4e4469616772616d2069643d2242504d4e4469616772616d5f776d735f7472616e736665725f617070726f7665223e0a202020203c62706d6e64693a42504d4e506c616e652062706d6e456c656d656e743d22776d735f7472616e736665725f617070726f7665222069643d2242504d4e506c616e655f776d735f7472616e736665725f617070726f7665223e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d225374617274557365724e6f6465222069643d2242504d4e53686170655f5374617274557365724e6f6465223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2236302e30222077696474683d223130302e302220783d2238302e302220793d22302e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d2253746172744576656e74222069643d2242504d4e53686170655f53746172744576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d22302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d22456e644576656e74222069643d2242504d4e53686170655f456e644576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d223233302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d32222069643d2242504d4e456467655f73657175656e6365466c6f772d32223e0a20202020202020203c6f6d6764693a776179706f696e7420783d223138302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d223233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d31222069643d2242504d4e456467655f73657175656e6365466c6f772d31223e0a20202020202020203c6f6d6764693a776179706f696e7420783d2233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d2238302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a202020203c2f62706d6e64693a42504d4e506c616e653e0a20203c2f62706d6e64693a42504d4e4469616772616d3e0a3c2f646566696e6974696f6e733e', '0'),
+('byte_b6e816103961b88392e4ac24c87dddf8', NULL, 'supplier_apply_approve.bpmn', 'dep_b6e816103961b88392e4ac24c87dddf8', X'3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f3e0a3c646566696e6974696f6e7320786d6c6e733d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c2220786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220786d6c6e733a62706d6e64693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f44492220786d6c6e733a6f6d6764633d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44432220786d6c6e733a6f6d6764693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44492220747970654c616e67756167653d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d61222065787072657373696f6e4c616e67756167653d22687474703a2f2f7777772e77332e6f72672f313939392f585061746822207461726765744e616d6573706163653d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c223e0a20203c70726f636573732069643d22737570706c6965725f6170706c795f617070726f766522206e616d653d22e4be9be5ba94e59586e58786e585a5e5aea1e689b92220697345786563757461626c653d2274727565223e0a202020203c73746172744576656e742069643d2253746172744576656e7422206e616d653d22e5bc80e5a78b223e3c2f73746172744576656e743e0a202020203c757365725461736b2069643d225374617274557365724e6f646522206e616d653d22e58f91e8b5b7e4baba223e0a2020202020203c657874656e73696f6e456c656d656e74733e0a20202020202020203c666c6f7761626c653a617070726f76655479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a617070726f7665547970653e0a20202020202020203c666c6f7761626c653a63616e646964617465537472617465677920786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b33365d5d3e3c2f666c6f7761626c653a63616e64696461746553747261746567793e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68f90e4baa42220656e61626c653d2274727565222069643d2231223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68b92e7bb9d2220656e61626c653d2266616c7365222069643d2232223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e8bdace58a9e2220656e61626c653d2266616c7365222069643d2233223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e5a794e6b4be2220656e61626c653d2266616c7365222069643d2234223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e58aa0e7adbe2220656e61626c653d2266616c7365222069643d2235223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e98080e59b9e2220656e61626c653d2266616c7365222069643d2236223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a61737369676e53746172745573657248616e646c65725479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b325d5d3e3c2f666c6f7761626c653a61737369676e53746172745573657248616e646c6572547970653e0a2020202020203c2f657874656e73696f6e456c656d656e74733e0a202020203c2f757365725461736b3e0a202020203c656e644576656e742069643d22456e644576656e7422206e616d653d22e7bb93e69d9f223e3c2f656e644576656e743e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d312220736f757263655265663d2253746172744576656e7422207461726765745265663d225374617274557365724e6f6465223e3c2f73657175656e6365466c6f773e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d322220736f757263655265663d225374617274557365724e6f646522207461726765745265663d22456e644576656e74223e3c2f73657175656e6365466c6f773e0a20203c2f70726f636573733e0a20203c62706d6e64693a42504d4e4469616772616d2069643d2242504d4e4469616772616d5f737570706c6965725f6170706c795f617070726f7665223e0a202020203c62706d6e64693a42504d4e506c616e652062706d6e456c656d656e743d22737570706c6965725f6170706c795f617070726f7665222069643d2242504d4e506c616e655f737570706c6965725f6170706c795f617070726f7665223e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d225374617274557365724e6f6465222069643d2242504d4e53686170655f5374617274557365724e6f6465223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2236302e30222077696474683d223130302e302220783d2238302e302220793d22302e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d2253746172744576656e74222069643d2242504d4e53686170655f53746172744576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d22302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d22456e644576656e74222069643d2242504d4e53686170655f456e644576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d223233302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d32222069643d2242504d4e456467655f73657175656e6365466c6f772d32223e0a20202020202020203c6f6d6764693a776179706f696e7420783d223138302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d223233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d31222069643d2242504d4e456467655f73657175656e6365466c6f772d31223e0a20202020202020203c6f6d6764693a776179706f696e7420783d2233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d2238302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a202020203c2f62706d6e64693a42504d4e506c616e653e0a20203c2f62706d6e64693a42504d4e4469616772616d3e0a3c2f646566696e6974696f6e733e', '0'),
+('byte_b9d15a0bc2b775bebb84987fb4b07cad', NULL, 'sale_order_approve.bpmn', 'dep_b9d15a0bc2b775bebb84987fb4b07cad', X'3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f3e0a3c646566696e6974696f6e7320786d6c6e733d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c2220786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220786d6c6e733a62706d6e64693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f44492220786d6c6e733a6f6d6764633d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44432220786d6c6e733a6f6d6764693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44492220747970654c616e67756167653d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d61222065787072657373696f6e4c616e67756167653d22687474703a2f2f7777772e77332e6f72672f313939392f585061746822207461726765744e616d6573706163653d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c223e0a20203c70726f636573732069643d2273616c655f6f726465725f617070726f766522206e616d653d22e99480e594aee8aea2e58d95e5aea1e689b92220697345786563757461626c653d2274727565223e0a202020203c73746172744576656e742069643d2253746172744576656e7422206e616d653d22e5bc80e5a78b223e3c2f73746172744576656e743e0a202020203c757365725461736b2069643d225374617274557365724e6f646522206e616d653d22e58f91e8b5b7e4baba223e0a2020202020203c657874656e73696f6e456c656d656e74733e0a20202020202020203c666c6f7761626c653a617070726f76655479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a617070726f7665547970653e0a20202020202020203c666c6f7761626c653a63616e646964617465537472617465677920786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b33365d5d3e3c2f666c6f7761626c653a63616e64696461746553747261746567793e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68f90e4baa42220656e61626c653d2274727565222069643d2231223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68b92e7bb9d2220656e61626c653d2266616c7365222069643d2232223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e8bdace58a9e2220656e61626c653d2266616c7365222069643d2233223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e5a794e6b4be2220656e61626c653d2266616c7365222069643d2234223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e58aa0e7adbe2220656e61626c653d2266616c7365222069643d2235223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e98080e59b9e2220656e61626c653d2266616c7365222069643d2236223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a61737369676e53746172745573657248616e646c65725479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b325d5d3e3c2f666c6f7761626c653a61737369676e53746172745573657248616e646c6572547970653e0a2020202020203c2f657874656e73696f6e456c656d656e74733e0a202020203c2f757365725461736b3e0a202020203c656e644576656e742069643d22456e644576656e7422206e616d653d22e7bb93e69d9f223e3c2f656e644576656e743e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d312220736f757263655265663d2253746172744576656e7422207461726765745265663d225374617274557365724e6f6465223e3c2f73657175656e6365466c6f773e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d322220736f757263655265663d225374617274557365724e6f646522207461726765745265663d22456e644576656e74223e3c2f73657175656e6365466c6f773e0a20203c2f70726f636573733e0a20203c62706d6e64693a42504d4e4469616772616d2069643d2242504d4e4469616772616d5f73616c655f6f726465725f617070726f7665223e0a202020203c62706d6e64693a42504d4e506c616e652062706d6e456c656d656e743d2273616c655f6f726465725f617070726f7665222069643d2242504d4e506c616e655f73616c655f6f726465725f617070726f7665223e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d225374617274557365724e6f6465222069643d2242504d4e53686170655f5374617274557365724e6f6465223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2236302e30222077696474683d223130302e302220783d2238302e302220793d22302e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d2253746172744576656e74222069643d2242504d4e53686170655f53746172744576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d22302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d22456e644576656e74222069643d2242504d4e53686170655f456e644576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d223233302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d32222069643d2242504d4e456467655f73657175656e6365466c6f772d32223e0a20202020202020203c6f6d6764693a776179706f696e7420783d223138302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d223233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d31222069643d2242504d4e456467655f73657175656e6365466c6f772d31223e0a20202020202020203c6f6d6764693a776179706f696e7420783d2233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d2238302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a202020203c2f62706d6e64693a42504d4e506c616e653e0a20203c2f62706d6e64693a42504d4e4469616772616d3e0a3c2f646566696e6974696f6e733e', '0'),
+('byte_bed6796545faa2cb7851a019948e4e49', NULL, 'wms_outbound_approve.bpmn', 'dep_bed6796545faa2cb7851a019948e4e49', X'3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f3e0a3c646566696e6974696f6e7320786d6c6e733d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c2220786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220786d6c6e733a62706d6e64693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f44492220786d6c6e733a6f6d6764633d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44432220786d6c6e733a6f6d6764693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44492220747970654c616e67756167653d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d61222065787072657373696f6e4c616e67756167653d22687474703a2f2f7777772e77332e6f72672f313939392f585061746822207461726765744e616d6573706163653d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c223e0a20203c70726f636573732069643d22776d735f6f7574626f756e645f617070726f766522206e616d653d22e4bb93e5ba93e587bae5ba93e5aea1e689b92220697345786563757461626c653d2274727565223e0a202020203c73746172744576656e742069643d2253746172744576656e7422206e616d653d22e5bc80e5a78b223e3c2f73746172744576656e743e0a202020203c757365725461736b2069643d225374617274557365724e6f646522206e616d653d22e58f91e8b5b7e4baba223e0a2020202020203c657874656e73696f6e456c656d656e74733e0a20202020202020203c666c6f7761626c653a617070726f76655479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a617070726f7665547970653e0a20202020202020203c666c6f7761626c653a63616e646964617465537472617465677920786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b33365d5d3e3c2f666c6f7761626c653a63616e64696461746553747261746567793e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68f90e4baa42220656e61626c653d2274727565222069643d2231223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68b92e7bb9d2220656e61626c653d2266616c7365222069643d2232223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e8bdace58a9e2220656e61626c653d2266616c7365222069643d2233223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e5a794e6b4be2220656e61626c653d2266616c7365222069643d2234223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e58aa0e7adbe2220656e61626c653d2266616c7365222069643d2235223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e98080e59b9e2220656e61626c653d2266616c7365222069643d2236223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a61737369676e53746172745573657248616e646c65725479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b325d5d3e3c2f666c6f7761626c653a61737369676e53746172745573657248616e646c6572547970653e0a2020202020203c2f657874656e73696f6e456c656d656e74733e0a202020203c2f757365725461736b3e0a202020203c656e644576656e742069643d22456e644576656e7422206e616d653d22e7bb93e69d9f223e3c2f656e644576656e743e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d312220736f757263655265663d2253746172744576656e7422207461726765745265663d225374617274557365724e6f6465223e3c2f73657175656e6365466c6f773e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d322220736f757263655265663d225374617274557365724e6f646522207461726765745265663d22456e644576656e74223e3c2f73657175656e6365466c6f773e0a20203c2f70726f636573733e0a20203c62706d6e64693a42504d4e4469616772616d2069643d2242504d4e4469616772616d5f776d735f6f7574626f756e645f617070726f7665223e0a202020203c62706d6e64693a42504d4e506c616e652062706d6e456c656d656e743d22776d735f6f7574626f756e645f617070726f7665222069643d2242504d4e506c616e655f776d735f6f7574626f756e645f617070726f7665223e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d225374617274557365724e6f6465222069643d2242504d4e53686170655f5374617274557365724e6f6465223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2236302e30222077696474683d223130302e302220783d2238302e302220793d22302e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d2253746172744576656e74222069643d2242504d4e53686170655f53746172744576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d22302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d22456e644576656e74222069643d2242504d4e53686170655f456e644576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d223233302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d32222069643d2242504d4e456467655f73657175656e6365466c6f772d32223e0a20202020202020203c6f6d6764693a776179706f696e7420783d223138302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d223233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d31222069643d2242504d4e456467655f73657175656e6365466c6f772d31223e0a20202020202020203c6f6d6764693a776179706f696e7420783d2233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d2238302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a202020203c2f62706d6e64693a42504d4e506c616e653e0a20203c2f62706d6e64693a42504d4e4469616772616d3e0a3c2f646566696e6974696f6e733e', '0'),
+('byte_c16d0eef322695bed1c0c20e1d0190ce', NULL, 'item_receipt_approve.bpmn', 'dep_c16d0eef322695bed1c0c20e1d0190ce', X'3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f3e0a3c646566696e6974696f6e7320786d6c6e733d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c2220786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220786d6c6e733a62706d6e64693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f44492220786d6c6e733a6f6d6764633d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44432220786d6c6e733a6f6d6764693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44492220747970654c616e67756167653d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d61222065787072657373696f6e4c616e67756167653d22687474703a2f2f7777772e77332e6f72672f313939392f585061746822207461726765744e616d6573706163653d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c223e0a20203c70726f636573732069643d226974656d5f726563656970745f617070726f766522206e616d653d22e98787e8b4ade585a5e5ba93e5aea1e689b92220697345786563757461626c653d2274727565223e0a202020203c73746172744576656e742069643d2253746172744576656e7422206e616d653d22e5bc80e5a78b223e3c2f73746172744576656e743e0a202020203c757365725461736b2069643d225374617274557365724e6f646522206e616d653d22e58f91e8b5b7e4baba223e0a2020202020203c657874656e73696f6e456c656d656e74733e0a20202020202020203c666c6f7761626c653a617070726f76655479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a617070726f7665547970653e0a20202020202020203c666c6f7761626c653a63616e646964617465537472617465677920786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b33365d5d3e3c2f666c6f7761626c653a63616e64696461746553747261746567793e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68f90e4baa42220656e61626c653d2274727565222069643d2231223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68b92e7bb9d2220656e61626c653d2266616c7365222069643d2232223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e8bdace58a9e2220656e61626c653d2266616c7365222069643d2233223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e5a794e6b4be2220656e61626c653d2266616c7365222069643d2234223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e58aa0e7adbe2220656e61626c653d2266616c7365222069643d2235223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e98080e59b9e2220656e61626c653d2266616c7365222069643d2236223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a61737369676e53746172745573657248616e646c65725479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b325d5d3e3c2f666c6f7761626c653a61737369676e53746172745573657248616e646c6572547970653e0a2020202020203c2f657874656e73696f6e456c656d656e74733e0a202020203c2f757365725461736b3e0a202020203c656e644576656e742069643d22456e644576656e7422206e616d653d22e7bb93e69d9f223e3c2f656e644576656e743e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d312220736f757263655265663d2253746172744576656e7422207461726765745265663d225374617274557365724e6f6465223e3c2f73657175656e6365466c6f773e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d322220736f757263655265663d225374617274557365724e6f646522207461726765745265663d22456e644576656e74223e3c2f73657175656e6365466c6f773e0a20203c2f70726f636573733e0a20203c62706d6e64693a42504d4e4469616772616d2069643d2242504d4e4469616772616d5f6974656d5f726563656970745f617070726f7665223e0a202020203c62706d6e64693a42504d4e506c616e652062706d6e456c656d656e743d226974656d5f726563656970745f617070726f7665222069643d2242504d4e506c616e655f6974656d5f726563656970745f617070726f7665223e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d225374617274557365724e6f6465222069643d2242504d4e53686170655f5374617274557365724e6f6465223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2236302e30222077696474683d223130302e302220783d2238302e302220793d22302e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d2253746172744576656e74222069643d2242504d4e53686170655f53746172744576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d22302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d22456e644576656e74222069643d2242504d4e53686170655f456e644576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d223233302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d32222069643d2242504d4e456467655f73657175656e6365466c6f772d32223e0a20202020202020203c6f6d6764693a776179706f696e7420783d223138302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d223233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d31222069643d2242504d4e456467655f73657175656e6365466c6f772d31223e0a20202020202020203c6f6d6764693a776179706f696e7420783d2233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d2238302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a202020203c2f62706d6e64693a42504d4e506c616e653e0a20203c2f62706d6e64693a42504d4e4469616772616d3e0a3c2f646566696e6974696f6e733e', '0'),
+('byte_d1d2025350ea9af098ca7dbe6e80b442', NULL, 'hrm_attendance_approve.bpmn', 'dep_d1d2025350ea9af098ca7dbe6e80b442', X'3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f3e0a3c646566696e6974696f6e7320786d6c6e733d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c2220786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220786d6c6e733a62706d6e64693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f44492220786d6c6e733a6f6d6764633d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44432220786d6c6e733a6f6d6764693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44492220747970654c616e67756167653d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d61222065787072657373696f6e4c616e67756167653d22687474703a2f2f7777772e77332e6f72672f313939392f585061746822207461726765744e616d6573706163653d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c223e0a20203c70726f636573732069643d2268726d5f617474656e64616e63655f617070726f766522206e616d653d22e88083e58ba4e5bc82e5b8b8e5aea1e689b92220697345786563757461626c653d2274727565223e0a202020203c73746172744576656e742069643d2253746172744576656e7422206e616d653d22e5bc80e5a78b223e3c2f73746172744576656e743e0a202020203c757365725461736b2069643d225374617274557365724e6f646522206e616d653d22e58f91e8b5b7e4baba223e0a2020202020203c657874656e73696f6e456c656d656e74733e0a20202020202020203c666c6f7761626c653a617070726f76655479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a617070726f7665547970653e0a20202020202020203c666c6f7761626c653a63616e646964617465537472617465677920786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b33365d5d3e3c2f666c6f7761626c653a63616e64696461746553747261746567793e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68f90e4baa42220656e61626c653d2274727565222069643d2231223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68b92e7bb9d2220656e61626c653d2266616c7365222069643d2232223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e8bdace58a9e2220656e61626c653d2266616c7365222069643d2233223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e5a794e6b4be2220656e61626c653d2266616c7365222069643d2234223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e58aa0e7adbe2220656e61626c653d2266616c7365222069643d2235223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e98080e59b9e2220656e61626c653d2266616c7365222069643d2236223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a61737369676e53746172745573657248616e646c65725479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b325d5d3e3c2f666c6f7761626c653a61737369676e53746172745573657248616e646c6572547970653e0a2020202020203c2f657874656e73696f6e456c656d656e74733e0a202020203c2f757365725461736b3e0a202020203c656e644576656e742069643d22456e644576656e7422206e616d653d22e7bb93e69d9f223e3c2f656e644576656e743e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d312220736f757263655265663d2253746172744576656e7422207461726765745265663d225374617274557365724e6f6465223e3c2f73657175656e6365466c6f773e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d322220736f757263655265663d225374617274557365724e6f646522207461726765745265663d22456e644576656e74223e3c2f73657175656e6365466c6f773e0a20203c2f70726f636573733e0a20203c62706d6e64693a42504d4e4469616772616d2069643d2242504d4e4469616772616d5f68726d5f617474656e64616e63655f617070726f7665223e0a202020203c62706d6e64693a42504d4e506c616e652062706d6e456c656d656e743d2268726d5f617474656e64616e63655f617070726f7665222069643d2242504d4e506c616e655f68726d5f617474656e64616e63655f617070726f7665223e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d225374617274557365724e6f6465222069643d2242504d4e53686170655f5374617274557365724e6f6465223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2236302e30222077696474683d223130302e302220783d2238302e302220793d22302e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d2253746172744576656e74222069643d2242504d4e53686170655f53746172744576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d22302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d22456e644576656e74222069643d2242504d4e53686170655f456e644576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d223233302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d32222069643d2242504d4e456467655f73657175656e6365466c6f772d32223e0a20202020202020203c6f6d6764693a776179706f696e7420783d223138302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d223233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d31222069643d2242504d4e456467655f73657175656e6365466c6f772d31223e0a20202020202020203c6f6d6764693a776179706f696e7420783d2233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d2238302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a202020203c2f62706d6e64693a42504d4e506c616e653e0a20203c2f62706d6e64693a42504d4e4469616772616d3e0a3c2f646566696e6974696f6e733e', '0'),
+('byte_ecb89d4a54da3ae23601fef85642b0ce', NULL, 'hrm_overtime.bpmn', 'dep_ecb89d4a54da3ae23601fef85642b0ce', X'3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f3e0a3c646566696e6974696f6e7320786d6c6e733d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c2220786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220786d6c6e733a62706d6e64693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f44492220786d6c6e733a6f6d6764633d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44432220786d6c6e733a6f6d6764693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44492220747970654c616e67756167653d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d61222065787072657373696f6e4c616e67756167653d22687474703a2f2f7777772e77332e6f72672f313939392f585061746822207461726765744e616d6573706163653d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c223e0a20203c70726f636573732069643d2268726d5f6f76657274696d6522206e616d653d22e58aa0e78fade5aea1e689b92220697345786563757461626c653d2274727565223e0a202020203c73746172744576656e742069643d2253746172744576656e7422206e616d653d22e5bc80e5a78b223e3c2f73746172744576656e743e0a202020203c757365725461736b2069643d225374617274557365724e6f646522206e616d653d22e58f91e8b5b7e4baba223e0a2020202020203c657874656e73696f6e456c656d656e74733e0a20202020202020203c666c6f7761626c653a617070726f76655479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a617070726f7665547970653e0a20202020202020203c666c6f7761626c653a63616e646964617465537472617465677920786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b33365d5d3e3c2f666c6f7761626c653a63616e64696461746553747261746567793e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68f90e4baa42220656e61626c653d2274727565222069643d2231223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68b92e7bb9d2220656e61626c653d2266616c7365222069643d2232223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e8bdace58a9e2220656e61626c653d2266616c7365222069643d2233223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e5a794e6b4be2220656e61626c653d2266616c7365222069643d2234223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e58aa0e7adbe2220656e61626c653d2266616c7365222069643d2235223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e98080e59b9e2220656e61626c653d2266616c7365222069643d2236223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a61737369676e53746172745573657248616e646c65725479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b325d5d3e3c2f666c6f7761626c653a61737369676e53746172745573657248616e646c6572547970653e0a2020202020203c2f657874656e73696f6e456c656d656e74733e0a202020203c2f757365725461736b3e0a202020203c656e644576656e742069643d22456e644576656e7422206e616d653d22e7bb93e69d9f223e3c2f656e644576656e743e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d312220736f757263655265663d2253746172744576656e7422207461726765745265663d225374617274557365724e6f6465223e3c2f73657175656e6365466c6f773e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d322220736f757263655265663d225374617274557365724e6f646522207461726765745265663d22456e644576656e74223e3c2f73657175656e6365466c6f773e0a20203c2f70726f636573733e0a20203c62706d6e64693a42504d4e4469616772616d2069643d2242504d4e4469616772616d5f68726d5f6f76657274696d65223e0a202020203c62706d6e64693a42504d4e506c616e652062706d6e456c656d656e743d2268726d5f6f76657274696d65222069643d2242504d4e506c616e655f68726d5f6f76657274696d65223e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d225374617274557365724e6f6465222069643d2242504d4e53686170655f5374617274557365724e6f6465223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2236302e30222077696474683d223130302e302220783d2238302e302220793d22302e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d2253746172744576656e74222069643d2242504d4e53686170655f53746172744576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d22302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d22456e644576656e74222069643d2242504d4e53686170655f456e644576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d223233302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d32222069643d2242504d4e456467655f73657175656e6365466c6f772d32223e0a20202020202020203c6f6d6764693a776179706f696e7420783d223138302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d223233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d31222069643d2242504d4e456467655f73657175656e6365466c6f772d31223e0a20202020202020203c6f6d6764693a776179706f696e7420783d2233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d2238302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a202020203c2f62706d6e64693a42504d4e506c616e653e0a20203c2f62706d6e64693a42504d4e4469616772616d3e0a3c2f646566696e6974696f6e733e', '0'),
+('byte_febd13bedc800a97127ae1c042eb557b', NULL, 'crm-contract-audit.bpmn', 'dep_febd13bedc800a97127ae1c042eb557b', X'3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f3e0a3c646566696e6974696f6e7320786d6c6e733d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c2220786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220786d6c6e733a62706d6e64693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f44492220786d6c6e733a6f6d6764633d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44432220786d6c6e733a6f6d6764693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44492220747970654c616e67756167653d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d61222065787072657373696f6e4c616e67756167653d22687474703a2f2f7777772e77332e6f72672f313939392f585061746822207461726765744e616d6573706163653d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c223e0a20203c70726f636573732069643d2263726d2d636f6e74726163742d617564697422206e616d653d22e59088e5908ce5aea1e689b92220697345786563757461626c653d2274727565223e0a202020203c73746172744576656e742069643d2253746172744576656e7422206e616d653d22e5bc80e5a78b223e3c2f73746172744576656e743e0a202020203c757365725461736b2069643d225374617274557365724e6f646522206e616d653d22e58f91e8b5b7e4baba223e0a2020202020203c657874656e73696f6e456c656d656e74733e0a20202020202020203c666c6f7761626c653a617070726f76655479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a617070726f7665547970653e0a20202020202020203c666c6f7761626c653a63616e646964617465537472617465677920786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b33365d5d3e3c2f666c6f7761626c653a63616e64696461746553747261746567793e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68f90e4baa42220656e61626c653d2274727565222069643d2231223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68b92e7bb9d2220656e61626c653d2266616c7365222069643d2232223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e8bdace58a9e2220656e61626c653d2266616c7365222069643d2233223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e5a794e6b4be2220656e61626c653d2266616c7365222069643d2234223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e58aa0e7adbe2220656e61626c653d2266616c7365222069643d2235223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e98080e59b9e2220656e61626c653d2266616c7365222069643d2236223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a61737369676e53746172745573657248616e646c65725479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b325d5d3e3c2f666c6f7761626c653a61737369676e53746172745573657248616e646c6572547970653e0a2020202020203c2f657874656e73696f6e456c656d656e74733e0a202020203c2f757365725461736b3e0a202020203c656e644576656e742069643d22456e644576656e7422206e616d653d22e7bb93e69d9f223e3c2f656e644576656e743e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d312220736f757263655265663d2253746172744576656e7422207461726765745265663d225374617274557365724e6f6465223e3c2f73657175656e6365466c6f773e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d322220736f757263655265663d225374617274557365724e6f646522207461726765745265663d22456e644576656e74223e3c2f73657175656e6365466c6f773e0a20203c2f70726f636573733e0a20203c62706d6e64693a42504d4e4469616772616d2069643d2242504d4e4469616772616d5f63726d2d636f6e74726163742d6175646974223e0a202020203c62706d6e64693a42504d4e506c616e652062706d6e456c656d656e743d2263726d2d636f6e74726163742d6175646974222069643d2242504d4e506c616e655f63726d2d636f6e74726163742d6175646974223e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d225374617274557365724e6f6465222069643d2242504d4e53686170655f5374617274557365724e6f6465223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2236302e30222077696474683d223130302e302220783d2238302e302220793d22302e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d2253746172744576656e74222069643d2242504d4e53686170655f53746172744576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d22302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d22456e644576656e74222069643d2242504d4e53686170655f456e644576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d223233302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d32222069643d2242504d4e456467655f73657175656e6365466c6f772d32223e0a20202020202020203c6f6d6764693a776179706f696e7420783d223138302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d223233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d31222069643d2242504d4e456467655f73657175656e6365466c6f772d31223e0a20202020202020203c6f6d6764693a776179706f696e7420783d2233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d2238302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a202020203c2f62706d6e64693a42504d4e506c616e653e0a20203c2f62706d6e64693a42504d4e4469616772616d3e0a3c2f646566696e6974696f6e733e', '0'),
+('f1a1b2c3d4e5465f8a9b0c1d2e3f4a5c', '1', 'erp-finance-payment-audit.bpmn', 'f1a1b2c3d4e5465f8a9b0c1d2e3f4a5b', X'3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f3e0a3c646566696e6974696f6e7320786d6c6e733d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c2220786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220786d6c6e733a62706d6e64693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f44492220786d6c6e733a6f6d6764633d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44432220786d6c6e733a6f6d6764693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44492220747970654c616e67756167653d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d61222065787072657373696f6e4c616e67756167653d22687474703a2f2f7777772e77332e6f72672f313939392f585061746822207461726765744e616d6573706163653d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c223e0a20203c70726f636573732069643d226572702d66696e616e63652d7061796d656e742d617564697422206e616d653d22e4bb98e6acbee5aea1e689b9e6b581e7a88b2220697345786563757461626c653d2274727565223e0a202020203c73746172744576656e742069643d2253746172744576656e7422206e616d653d22e5bc80e5a78b223e3c2f73746172744576656e743e0a202020203c757365725461736b2069643d225374617274557365724e6f646522206e616d653d22e58f91e8b5b7e4baba223e0a2020202020203c657874656e73696f6e456c656d656e74733e0a20202020202020203c666c6f7761626c653a617070726f76655479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b315d5d3e3c2f666c6f7761626c653a617070726f7665547970653e0a20202020202020203c666c6f7761626c653a63616e646964617465537472617465677920786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b33365d5d3e3c2f666c6f7761626c653a63616e64696461746553747261746567793e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68f90e4baa42220656e61626c653d2274727565222069643d2231223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e68b92e7bb9d2220656e61626c653d2266616c7365222069643d2232223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e8bdace58a9e2220656e61626c653d2266616c7365222069643d2233223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e5a794e6b4be2220656e61626c653d2266616c7365222069643d2234223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e58aa0e7adbe2220656e61626c653d2266616c7365222069643d2235223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a627574746f6e7353657474696e6720786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220646973706c61794e616d653d22e98080e59b9e2220656e61626c653d2266616c7365222069643d2236223e3c2f666c6f7761626c653a627574746f6e7353657474696e673e0a20202020202020203c666c6f7761626c653a61737369676e53746172745573657248616e646c65725479706520786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e223e3c215b43444154415b325d5d3e3c2f666c6f7761626c653a61737369676e53746172745573657248616e646c6572547970653e0a2020202020203c2f657874656e73696f6e456c656d656e74733e0a202020203c2f757365725461736b3e0a202020203c656e644576656e742069643d22456e644576656e7422206e616d653d22e7bb93e69d9f223e3c2f656e644576656e743e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d312220736f757263655265663d2253746172744576656e7422207461726765745265663d225374617274557365724e6f6465223e3c2f73657175656e6365466c6f773e0a202020203c73657175656e6365466c6f772069643d2273657175656e6365466c6f772d322220736f757263655265663d225374617274557365724e6f646522207461726765745265663d22456e644576656e74223e3c2f73657175656e6365466c6f773e0a20203c2f70726f636573733e0a20203c62706d6e64693a42504d4e4469616772616d2069643d2242504d4e4469616772616d5f6572702d66696e616e63652d7061796d656e742d6175646974223e0a202020203c62706d6e64693a42504d4e506c616e652062706d6e456c656d656e743d226572702d66696e616e63652d7061796d656e742d6175646974222069643d2242504d4e506c616e655f6572702d66696e616e63652d7061796d656e742d6175646974223e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d225374617274557365724e6f6465222069643d2242504d4e53686170655f5374617274557365724e6f6465223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2236302e30222077696474683d223130302e302220783d2238302e302220793d22302e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d2253746172744576656e74222069643d2242504d4e53686170655f53746172744576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d22302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652062706d6e456c656d656e743d22456e644576656e74222069643d2242504d4e53686170655f456e644576656e74223e0a20202020202020203c6f6d6764633a426f756e6473206865696768743d2233302e30222077696474683d2233302e302220783d223233302e302220793d2231352e30223e3c2f6f6d6764633a426f756e64733e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d32222069643d2242504d4e456467655f73657175656e6365466c6f772d32223e0a20202020202020203c6f6d6764693a776179706f696e7420783d223138302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d223233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a2020202020203c62706d6e64693a42504d4e456467652062706d6e456c656d656e743d2273657175656e6365466c6f772d31222069643d2242504d4e456467655f73657175656e6365466c6f772d31223e0a20202020202020203c6f6d6764693a776179706f696e7420783d2233302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a20202020202020203c6f6d6764693a776179706f696e7420783d2238302e302220793d2233302e30223e3c2f6f6d6764693a776179706f696e743e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a202020203c2f62706d6e64693a42504d4e506c616e653e0a20203c2f62706d6e64693a42504d4e4469616772616d3e0a3c2f646566696e6974696f6e733e', '0');
+
+-- ============ 琛細act_re_model锛堝鍑� 20 琛岋級 ============
+DROP TABLE IF EXISTS `act_re_model`;
+CREATE TABLE `act_re_model` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL,
+ `LAST_UPDATE_TIME_` timestamp(3) NULL DEFAULT NULL,
+ `VERSION_` int DEFAULT NULL,
+ `META_INFO_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DEPLOYMENT_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `EDITOR_SOURCE_VALUE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `EDITOR_SOURCE_EXTRA_VALUE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '',
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `ACT_FK_MODEL_SOURCE` (`EDITOR_SOURCE_VALUE_ID_`) USING BTREE,
+ KEY `ACT_FK_MODEL_SOURCE_EXTRA` (`EDITOR_SOURCE_EXTRA_VALUE_ID_`) USING BTREE,
+ KEY `ACT_FK_MODEL_DEPLOYMENT` (`DEPLOYMENT_ID_`) USING BTREE,
+ CONSTRAINT `ACT_FK_MODEL_DEPLOYMENT` FOREIGN KEY (`DEPLOYMENT_ID_`) REFERENCES `act_re_deployment` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_MODEL_SOURCE` FOREIGN KEY (`EDITOR_SOURCE_VALUE_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_MODEL_SOURCE_EXTRA` FOREIGN KEY (`EDITOR_SOURCE_EXTRA_VALUE_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+INSERT INTO `act_re_model` (`ID_`, `REV_`, `NAME_`, `KEY_`, `CATEGORY_`, `CREATE_TIME_`, `LAST_UPDATE_TIME_`, `VERSION_`, `META_INFO_`, `DEPLOYMENT_ID_`, `EDITOR_SOURCE_VALUE_ID_`, `EDITOR_SOURCE_EXTRA_VALUE_ID_`, `TENANT_ID_`) VALUES
+('0b7c7577949111f192711ab6da3745b7', '1', '鏉ョエ瀹℃壒娴佺▼', 'erp-purchase-invoice-audit', 'erp_purchase_invoice_approve', '2026-08-10 15:57:11.000', '2026-08-10 15:57:11.000', '1', '{"allowCancelRunningProcess":true,"allowWithdrawTask":false,"autoApprovalType":0,"description":"","formCustomCreatePath":"","formCustomViewPath":"","formId":1,"formType":10,"icon":null,"managerUserIds":[1],"printTemplateSetting":{"enable":false,"template":""},"processAfterTriggerSetting":null,"processBeforeTriggerSetting":null,"processIdRule":{"enable":false,"infix":"","length":5,"postfix":"","prefix":""},"sort":1785465606228,"startDeptIds":[],"startUserIds":[],"summarySetting":{"enable":false,"summary":[]},"taskAfterTriggerSetting":null,"taskBeforeTriggerSetting":null,"titleSetting":{"enable":false,"title":""},"type":10,"visible":true}', '0b7c7557949111f192711ab6da3745b7', '0b7c7572949111f192711ab6da3745b7', NULL, ''),
+('23afd50c-8c89-11f1-8a27-00155dad6485', '5', '鍥炴瀹℃壒娴佺▼', 'crm-receivable-audit', '1111', '2026-07-31 18:40:06.233', '2026-08-10 15:25:04.000', '1', '{"allowCancelRunningProcess":true,"allowWithdrawTask":false,"autoApprovalType":0,"description":"","formCustomCreatePath":"","formCustomViewPath":"","formId":1,"formType":10,"icon":null,"managerUserIds":[1],"printTemplateSetting":{"enable":false,"template":""},"processAfterTriggerSetting":null,"processBeforeTriggerSetting":null,"processIdRule":{"enable":false,"infix":"","length":5,"postfix":"","prefix":""},"sort":1785465606228,"startDeptIds":[],"startUserIds":[],"summarySetting":{"enable":false,"summary":[]},"taskAfterTriggerSetting":null,"taskBeforeTriggerSetting":null,"titleSetting":{"enable":false,"title":""},"type":20,"visible":true}', '7215184e-948c-11f1-9271-1ab6da3745b7', '23d3fedd-8c89-11f1-8a27-00155dad6485', '23db9ffe-8c89-11f1-8a27-00155dad6485', ''),
+('44318b176050e94d2c4a86595763dde8', '1', '浜у搧椤圭洰瀹℃壒娴佺▼', 'mes-pd-project-audit', 'mes_pd_project_approve', '2026-08-13 16:12:35.000', '2026-08-13 16:12:35.000', '1', '{"type":10,"sort":1788501889992.000,"formType":10,"visible":true}', 'ce99813cfeb29f270355dd39f8ef74f2', NULL, NULL, NULL),
+('5ddab987-74f9-11f1-91b4-00155dd68500', '7', '閲囪喘瀹℃牳', 'purchase_request_approve', 'purchase_request_approve', '2026-07-01 19:02:59.548', '2026-07-01 19:42:02.328', '1', '{"allowCancelRunningProcess":true,"allowWithdrawTask":false,"autoApprovalType":0,"description":"","formCustomCreatePath":"","formCustomViewPath":"","formId":1,"formType":10,"icon":null,"managerUserIds":[142],"printTemplateSetting":{"enable":false,"template":""},"processAfterTriggerSetting":null,"processBeforeTriggerSetting":null,"processIdRule":{"enable":false,"infix":"","length":5,"postfix":"","prefix":""},"sort":1782874979545,"startDeptIds":[],"startUserIds":[],"summarySetting":{"enable":false,"summary":[]},"taskAfterTriggerSetting":null,"taskBeforeTriggerSetting":null,"titleSetting":{"enable":false,"title":""},"type":20,"visible":true}', 'd232b68a-74fe-11f1-9120-00155dd68500', '5dfd83c8-74f9-11f1-91b4-00155dd68500', '5dff7f99-74f9-11f1-91b4-00155dd68500', ''),
+('c101d3e2-0001-11f2-8a27-00155dad6485', '1', '寮�绁ㄥ鎵规祦绋�', 'crm-invoice-audit', 'crm_invoice_approve', '2026-08-10 14:35:45.000', '2026-08-10 14:35:45.000', '1', '{"allowCancelRunningProcess":true,"allowWithdrawTask":false,"autoApprovalType":0,"description":"","formCustomCreatePath":"","formCustomViewPath":"","formId":1,"formType":10,"icon":null,"managerUserIds":[1],"printTemplateSetting":{"enable":false,"template":""},"processAfterTriggerSetting":null,"processBeforeTriggerSetting":null,"processIdRule":{"enable":false,"infix":"","length":5,"postfix":"","prefix":""},"sort":1785465606228,"startDeptIds":[],"startUserIds":[],"summarySetting":{"enable":false,"summary":[]},"taskAfterTriggerSetting":null,"taskBeforeTriggerSetting":null,"titleSetting":{"enable":false,"title":""},"type":10,"visible":true}', 'c101d3e0-0001-11f2-8a27-00155dad6485', 'c101d3e3-0001-11f2-8a27-00155dad6485', NULL, ''),
+('f1a1b2c3d4e5465f8a9b0c1d2e3f4a5c', '1', '浠樻瀹℃壒娴佺▼', 'erp-finance-payment-audit', 'erp_finance_payment_approve', '2026-08-10 17:35:58.000', '2026-08-10 17:35:58.000', '1', '{"type":10,"sort":1788501889992.000,"formType":10,"visible":true}', 'f1a1b2c3d4e5465f8a9b0c1d2e3f4a5b', NULL, NULL, ''),
+('model_08349f78d675f582f1ff5f08e7714a8d', NULL, '鎶ュ伐瀹℃壒', 'mes-pro-feedback-audit', 'mes_pro_feedback_audit', '2026-09-04 06:09:24.000', '2026-09-04 06:09:24.000', '1', '{"type":10,"formType":10,"sort":1788502164266.000,"visible":true}', 'dep_08349f78d675f582f1ff5f08e7714a8d', NULL, NULL, ''),
+('model_09ba42e32e7a436ee4e2a9b6eef0d232', NULL, '閲囪喘璁㈠崟瀹℃壒', 'purchase_order_approve', 'purchase_order_approve', '2026-09-04 06:07:01.000', '2026-09-04 06:07:01.000', '1', '{"type":10,"formType":10,"sort":1788502021886.000,"visible":true,"allowCancelRunningProcess":true,"allowWithdrawTask":false,"autoApprovalType":0,"description":"","formCustomCreatePath":"","formCustomViewPath":"","formId":null,"managerUserIds":[],"startUserIds":[],"startDeptIds":[],"icon":null,"processBeforeTriggerSetting":null,"processAfterTriggerSetting":null,"taskBeforeTriggerSetting":null,"taskAfterTriggerSetting":null,"printTemplateSetting":null,"summarySetting":null,"titleSetting":null,"processIdRule":null}', 'dep_09ba42e32e7a436ee4e2a9b6eef0d232', NULL, NULL, ''),
+('model_33d3b1649a923d986d89604267b79bbf', NULL, '绂昏亴瀹℃壒', 'hrm_resignation', 'hrm_resignation_approve', '2026-09-04 06:08:24.000', '2026-09-04 06:08:24.000', '1', '{"type":10,"formType":10,"sort":1788502104477.000,"visible":true}', 'dep_33d3b1649a923d986d89604267b79bbf', NULL, NULL, ''),
+('model_66ea9f27906591b4d0048d854c633a82', NULL, '璋冨姩瀹℃壒', 'hrm_transfer', 'hrm_transfer_approve', '2026-09-04 06:08:31.000', '2026-09-04 06:08:31.000', '1', '{"type":10,"formType":10,"sort":1788502111086.000,"visible":true}', 'dep_66ea9f27906591b4d0048d854c633a82', NULL, NULL, ''),
+('model_6e0f473d28c042b8b372d00797549423', NULL, '浠撳簱鍏ュ簱瀹℃壒', 'wms_inbound_approve', 'wms_approve', '2026-09-04 06:08:56.000', '2026-09-04 06:08:56.000', '1', '{"type":10,"formType":10,"sort":1788502136794.000,"visible":true}', 'dep_6e0f473d28c042b8b372d00797549423', NULL, NULL, ''),
+('model_862c6766e8cd1b32946a1ed2956a68bf', NULL, '璇峰亣瀹℃壒', 'hrm_leave', 'hrm_leave_approve', '2026-09-04 06:07:26.000', '2026-09-04 06:07:26.000', '1', '{"type":10,"formType":10,"sort":1788502046995.000,"visible":true}', 'dep_862c6766e8cd1b32946a1ed2956a68bf', NULL, NULL, ''),
+('model_9b3368e05f1d39dee636f464f2d65c16', NULL, '浠撳簱璋冩嫧瀹℃壒', 'wms_transfer_approve', 'wms_approve', '2026-09-04 06:09:10.000', '2026-09-04 06:09:10.000', '1', '{"type":10,"formType":10,"sort":1788502150287.000,"visible":true}', 'dep_9b3368e05f1d39dee636f464f2d65c16', NULL, NULL, ''),
+('model_b6e816103961b88392e4ac24c87dddf8', NULL, '渚涘簲鍟嗗噯鍏ュ鎵�', 'supplier_apply_approve', 'supplier_apply_approve', '2026-09-04 06:08:50.000', '2026-09-04 06:08:50.000', '1', '{"type":10,"formType":10,"sort":1788502130293.000,"visible":true}', 'dep_b6e816103961b88392e4ac24c87dddf8', NULL, NULL, ''),
+('model_b9d15a0bc2b775bebb84987fb4b07cad', NULL, '閿�鍞鍗曞鎵�', 'sale_order_approve', 'sale_order_approve', '2026-09-04 06:06:43.000', '2026-09-04 06:06:43.000', '1', '{"type":10,"formType":10,"sort":1788502003324.000,"visible":true,"allowCancelRunningProcess":true,"allowWithdrawTask":false,"autoApprovalType":0,"description":"","formCustomCreatePath":"","formCustomViewPath":"","formId":null,"managerUserIds":[],"startUserIds":[],"startDeptIds":[],"icon":null,"processBeforeTriggerSetting":null,"processAfterTriggerSetting":null,"taskBeforeTriggerSetting":null,"taskAfterTriggerSetting":null,"printTemplateSetting":null,"summarySetting":null,"titleSetting":null,"processIdRule":null}', 'dep_b9d15a0bc2b775bebb84987fb4b07cad', NULL, NULL, ''),
+('model_bed6796545faa2cb7851a019948e4e49', NULL, '浠撳簱鍑哄簱瀹℃壒', 'wms_outbound_approve', 'wms_approve', '2026-09-04 06:09:03.000', '2026-09-04 06:09:03.000', '1', '{"type":10,"formType":10,"sort":1788502143438.000,"visible":true}', 'dep_bed6796545faa2cb7851a019948e4e49', NULL, NULL, ''),
+('model_c16d0eef322695bed1c0c20e1d0190ce', NULL, '閲囪喘鍏ュ簱瀹℃壒', 'item_receipt_approve', 'item_receipt_approve', '2026-09-04 06:09:17.000', '2026-09-04 06:09:17.000', '1', '{"type":10,"formType":10,"sort":1788502157420.000,"visible":true}', 'dep_c16d0eef322695bed1c0c20e1d0190ce', NULL, NULL, ''),
+('model_d1d2025350ea9af098ca7dbe6e80b442', NULL, '鑰冨嫟寮傚父瀹℃壒', 'hrm_attendance_approve', 'hrm_attendance_approve', '2026-09-04 06:08:38.000', '2026-09-04 06:08:38.000', '1', '{"type":10,"formType":10,"sort":1788502118154.000,"visible":true}', 'dep_d1d2025350ea9af098ca7dbe6e80b442', NULL, NULL, ''),
+('model_ecb89d4a54da3ae23601fef85642b0ce', NULL, '鍔犵彮瀹℃壒', 'hrm_overtime', 'overtime_approve', '2026-09-04 06:07:33.000', '2026-09-04 06:07:33.000', '1', '{"type":10,"formType":10,"sort":1788502053543.000,"visible":true}', 'dep_ecb89d4a54da3ae23601fef85642b0ce', NULL, NULL, ''),
+('model_febd13bedc800a97127ae1c042eb557b', NULL, '鍚堝悓瀹℃壒', 'crm-contract-audit', 'contract_approve', '2026-09-04 06:07:09.000', '2026-09-04 06:07:09.000', '1', '{"type":10,"formType":10,"sort":1788502029973.000,"visible":true,"allowCancelRunningProcess":true,"allowWithdrawTask":false,"autoApprovalType":0,"description":"","formCustomCreatePath":"","formCustomViewPath":"","formId":null,"managerUserIds":[],"startUserIds":[],"startDeptIds":[],"icon":null,"processBeforeTriggerSetting":null,"processAfterTriggerSetting":null,"taskBeforeTriggerSetting":null,"taskAfterTriggerSetting":null,"printTemplateSetting":null,"summarySetting":null,"titleSetting":null,"processIdRule":null}', 'dep_febd13bedc800a97127ae1c042eb557b', NULL, NULL, '');
+
+-- ============ 琛細bpm_process_definition_info锛堝鍑� 20 琛岋級 ============
+DROP TABLE IF EXISTS `bpm_process_definition_info`;
+CREATE TABLE `bpm_process_definition_info` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `process_definition_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '娴佺▼瀹氫箟鐨勭紪鍙�',
+ `model_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '娴佺▼妯″瀷鐨勭紪鍙�',
+ `model_type` tinyint NOT NULL DEFAULT '10' COMMENT '娴佺▼妯″瀷鐨勭被鍨�',
+ `category` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴佺▼鍒嗙被鐨勭紪鐮�',
+ `icon` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍥炬爣',
+ `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎻忚堪',
+ `form_type` tinyint NOT NULL DEFAULT '10' COMMENT '琛ㄥ崟绫诲瀷锛�10鏅�氳〃鍗� 20鑷畾涔夎〃鍗曪級',
+ `form_id` bigint DEFAULT NULL COMMENT '鍔ㄦ�佽〃鍗曠紪鍙�',
+ `form_conf` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '琛ㄥ崟鐨勯厤缃�',
+ `form_fields` json DEFAULT NULL COMMENT '琛ㄥ崟椤圭殑鏁扮粍',
+ `form_custom_create_path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑷畾涔夎〃鍗曠殑鎻愪氦璺緞',
+ `form_custom_view_path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑷畾涔夎〃鍗曠殑鏌ョ湅璺緞',
+ `simple_model` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT 'SIMPLE 璁捐鍣ㄦā鍨嬫暟鎹�',
+ `visible` bit(1) NOT NULL DEFAULT b'1' COMMENT '鏄惁鍙',
+ `sort` bigint NOT NULL DEFAULT '0' COMMENT '鎺掑簭鍊�',
+ `start_user_ids` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍙彂璧风敤鎴风紪鍙锋暟缁�',
+ `start_dept_ids` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍙彂璧烽儴闂ㄧ紪鍙锋暟缁�',
+ `manager_user_ids` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍙鐞嗙敤鎴风紪鍙锋暟缁�',
+ `allow_cancel_running_process` bit(1) NOT NULL DEFAULT b'1' COMMENT '鏄惁鍏佽鎾ら攢瀹℃壒涓殑鐢宠',
+ `allow_withdraw_task` bit(1) NOT NULL DEFAULT b'1' COMMENT '鏄惁鍏佽瀹℃壒浜烘挙鍥炰换鍔�',
+ `process_id_rule` json DEFAULT NULL COMMENT '娴佺▼ ID 瑙勫垯',
+ `auto_approval_type` tinyint DEFAULT NULL COMMENT '鑷姩鍘婚噸绫诲瀷',
+ `title_setting` json DEFAULT NULL COMMENT '鏍囬璁剧疆',
+ `summary_setting` json DEFAULT NULL COMMENT '鎽樿璁剧疆',
+ `process_before_trigger_setting` json DEFAULT NULL COMMENT '娴佺▼鍓嶇疆閫氱煡璁剧疆',
+ `process_after_trigger_setting` json DEFAULT NULL COMMENT '娴佺▼鍚庣疆閫氱煡璁剧疆',
+ `task_before_trigger_setting` json DEFAULT NULL COMMENT '浠诲姟鍓嶇疆閫氱煡璁剧疆',
+ `task_after_trigger_setting` json DEFAULT NULL COMMENT '浠诲姟鍚庣疆閫氱煡璁剧疆',
+ `print_template_setting` json DEFAULT NULL COMMENT '鑷畾涔夋墦鍗版ā鏉胯缃�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=40 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='BPM 娴佺▼瀹氫箟鎷撳睍淇℃伅琛�';
+INSERT INTO `bpm_process_definition_info` (`id`, `process_definition_id`, `model_id`, `model_type`, `category`, `icon`, `description`, `form_type`, `form_id`, `form_conf`, `form_fields`, `form_custom_create_path`, `form_custom_view_path`, `simple_model`, `visible`, `sort`, `start_user_ids`, `start_dept_ids`, `manager_user_ids`, `allow_cancel_running_process`, `allow_withdraw_task`, `process_id_rule`, `auto_approval_type`, `title_setting`, `summary_setting`, `process_before_trigger_setting`, `process_after_trigger_setting`, `task_before_trigger_setting`, `task_after_trigger_setting`, `print_template_setting`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES
+('8', 'purchase_request_approve:3:d239e27d-74fe-11f1-9120-00155dd68500', '5ddab987-74f9-11f1-91b4-00155dd68500', '20', 'purchase_request_approve', NULL, '', '10', '1', '{"form":{"layout":"horizontal","labelAlign":"right","size":"middle","colon":false,"labelCol":{"style":{"width":"125px"}},"wrapperCol":{"span":24},"labelWidth":"100px"},"resetBtn":{"show":false,"innerText":"閲嶇疆"},"submitBtn":{"show":true,"innerText":"鎻愪氦"}}', '["{\\"type\\":\\"input\\",\\"field\\":\\"Fyqymqqdoln2abc\\",\\"title\\":\\"濮撳悕\\",\\"info\\":\\"\\",\\"$required\\":false,\\"_fc_id\\":\\"id_Fuplmqqdoln2acc\\",\\"name\\":\\"ref_F18omqqdoln2adc\\",\\"_fc_drag_tag\\":\\"input\\",\\"display\\":true,\\"hidden\\":false}","{\\"type\\":\\"input\\",\\"field\\":\\"Fh6gmqqdooy5aec\\",\\"title\\":\\"骞撮緞\\",\\"info\\":\\"\\",\\"$required\\":false,\\"_fc_id\\":\\"id_F5whmqqdooy5afc\\",\\"name\\":\\"ref_Fltemqqdooy5agc\\",\\"_fc_drag_tag\\":\\"input\\",\\"display\\":true,\\"hidden\\":false}","{\\"type\\":\\"select\\",\\"field\\":\\"F5mrmqqdutnnabc\\",\\"title\\":\\"閫夋嫨鍣╘\",\\"info\\":\\"\\",\\"effect\\":{\\"fetch\\":\\"\\"},\\"$required\\":false,\\"options\\":[{\\"label\\":\\"閫夐」01\\",\\"value\\":\\"1\\"},{\\"label\\":\\"閫夐」02\\",\\"value\\":\\"2\\"},{\\"label\\":\\"閫夐」03\\",\\"value\\":\\"3\\"}],\\"_fc_id\\":\\"id_Fhnumqqdutnoacc\\",\\"name\\":\\"ref_Fd1wmqqdutnoadc\\",\\"display\\":true,\\"hidden\\":false,\\"_fc_drag_tag\\":\\"select\\"}"]', '', '', '{"buttonsSetting":[{"displayName":"鎻愪氦","enable":true,"id":1},{"displayName":"鎷掔粷","enable":false,"id":2},{"displayName":"杞姙","enable":false,"id":3},{"displayName":"濮旀淳","enable":false,"id":4},{"displayName":"鍔犵","enable":false,"id":5},{"displayName":"閫�鍥�","enable":false,"id":6}],"childNode":{"approveMethod":4,"approveType":1,"assignEmptyHandler":{"type":1,"userIds":null},"assignStartUserHandlerType":1,"buttonsSetting":[{"displayName":"閫氳繃","enable":true,"id":1},{"displayName":"鎷掔粷","enable":true,"id":2},{"displayName":"杞姙","enable":true,"id":3},{"displayName":"濮旀淳","enable":true,"id":4},{"displayName":"鍔犵","enable":true,"id":5},{"displayName":"閫�鍥�","enable":true,"id":6}],"candidateParam":"142","candidateStrategy":30,"childNode":{"id":"EndEvent","name":"缁撴潫","type":1},"fieldsPermission":[{"field":"Fyqymqqdoln2abc","title":"濮撳悕","permission":"1"},{"field":"Fh6gmqqdooy5aec","title":"骞撮緞","permission":"1"},{"field":"F5mrmqqdutnnabc","title":"閫夋嫨鍣�","permission":"1"}],"id":"Activity__69663778421782877292716","name":"瀹℃壒浜�","reasonRequire":false,"rejectHandler":{"returnNodeId":null,"type":1},"showText":"鎸囧畾鎴愬憳锛歵est01","signEnable":false,"skipExpression":"","taskAssignListener":{"body":[],"enable":false,"header":[],"path":null},"taskCompleteListener":{"body":[],"enable":false,"header":[],"path":null},"taskCreateListener":{"body":[],"enable":false,"header":[],"path":null},"timeoutHandler":{"enable":false,"maxRemindCount":null,"timeDuration":null,"type":null},"type":11},"fieldsPermission":[{"field":"Fyqymqqdoln2abc","title":"濮撳悕","permission":"2"},{"field":"Fh6gmqqdooy5aec","title":"骞撮緞","permission":"2"},{"field":"F5mrmqqdutnnabc","title":"閫夋嫨鍣�","permission":"2"}],"id":"StartUserNode","name":"鍙戣捣浜�","showText":"宸茶缃�","type":10}', X'01', '1782874979545', '', '', '142', X'01', X'00', '{"infix":"","enable":false,"length":5,"prefix":"","postfix":""}', '0', '{"title":"","enable":false}', '{"enable":false,"summary":[]}', NULL, NULL, NULL, NULL, '{"enable":false,"template":""}', '142', '2026-07-01 11:42:02', '142', '2026-07-01 11:42:02', X'00'),
+('15', 'crm-receivable-audit:1:7215184e-948c-11f1-9271-1ab6da3745b7', '23afd50c-8c89-11f1-8a27-00155dad6485', '10', '1111', NULL, '', '10', '1', '{"form":{"layout":"horizontal","labelAlign":"right","size":"middle","colon":false,"labelCol":{"style":{"width":"125px"}},"wrapperCol":{"span":24},"labelWidth":"100px"},"resetBtn":{"show":false,"innerText":"閲嶇疆"},"submitBtn":{"show":true,"innerText":"鎻愪氦"}}', '["{\\"type\\":\\"input\\",\\"field\\":\\"Fyqymqqdoln2abc\\",\\"title\\":\\"濮撳悕\\",\\"info\\":\\"\\",\\"$required\\":false,\\"_fc_id\\":\\"id_Fuplmqqdoln2acc\\",\\"name\\":\\"ref_F18omqqdoln2adc\\",\\"_fc_drag_tag\\":\\"input\\",\\"display\\":true,\\"hidden\\":false}","{\\"type\\":\\"input\\",\\"field\\":\\"Fh6gmqqdooy5aec\\",\\"title\\":\\"骞撮緞\\",\\"info\\":\\"\\",\\"$required\\":false,\\"_fc_id\\":\\"id_F5whmqqdooy5afc\\",\\"name\\":\\"ref_Fltemqqdooy5agc\\",\\"_fc_drag_tag\\":\\"input\\",\\"display\\":true,\\"hidden\\":false}","{\\"type\\":\\"select\\",\\"field\\":\\"F5mrmqqdutnnabc\\",\\"title\\":\\"閫夋嫨鍣╘\",\\"info\\":\\"\\",\\"effect\\":{\\"fetch\\":\\"\\"},\\"$required\\":false,\\"options\\":[{\\"label\\":\\"閫夐」01\\",\\"value\\":\\"1\\"},{\\"label\\":\\"閫夐」02\\",\\"value\\":\\"2\\"},{\\"label\\":\\"閫夐」03\\",\\"value\\":\\"3\\"}],\\"_fc_id\\":\\"id_Fhnumqqdutnoacc\\",\\"name\\":\\"ref_Fd1wmqqdutnoadc\\",\\"_fc_drag_tag\\":\\"select\\",\\"display\\":true,\\"hidden\\":false}","{\\"type\\":\\"ApiSelect\\",\\"field\\":\\"dc4b501620bb4c8184aaaeb66398324a\\",\\"title\\":\\"鎺ュ彛閫夋嫨鍣╘\",\\"info\\":\\"\\",\\"$required\\":false,\\"props\\":{\\"method\\":\\"GET\\"},\\"_fc_id\\":\\"id_F6ewmrbn96xdc3c\\",\\"name\\":\\"ref_F1jomrbn96xdc4c\\",\\"display\\":true,\\"hidden\\":false,\\"_fc_drag_tag\\":\\"ApiSelect\\"}"]', '', '', NULL, X'01', '1785465606228', '', '', '1', X'01', X'00', '{"infix":"","enable":false,"length":5,"prefix":"","postfix":""}', '0', '{"title":"","enable":false}', '{"enable":false,"summary":[]}', NULL, NULL, NULL, NULL, '{"enable":false,"template":""}', '1', '2026-07-31 10:40:16', '1', '2026-08-10 07:29:22', X'00'),
+('16', 'crm-invoice-audit:1:c101d3e0-0001-11f2-8a27-00155dad6485', 'c101d3e2-0001-11f2-8a27-00155dad6485', '10', 'crm_invoice_approve', NULL, NULL, '10', '1', '{"form":{"layout":"horizontal","labelAlign":"right","size":"middle","colon":false,"labelCol":{"style":{"width":"125px"}},"wrapperCol":{"span":24},"labelWidth":"100px"},"resetBtn":{"show":false,"innerText":"閲嶇疆"},"submitBtn":{"show":true,"innerText":"鎻愪氦"}}', '["{\\"type\\":\\"input\\",\\"field\\":\\"Fyqymqqdoln2abc\\",\\"title\\":\\"濮撳悕\\",\\"info\\":\\"\\",\\"$required\\":false,\\"_fc_id\\":\\"id_Fuplmqqdoln2acc\\",\\"name\\":\\"ref_F18omqqdoln2adc\\",\\"_fc_drag_tag\\":\\"input\\",\\"display\\":true,\\"hidden\\":false}","{\\"type\\":\\"input\\",\\"field\\":\\"Fh6gmqqdooy5aec\\",\\"title\\":\\"骞撮緞\\",\\"info\\":\\"\\",\\"$required\\":false,\\"_fc_id\\":\\"id_F5whmqqdooy5afc\\",\\"name\\":\\"ref_Fltemqqdooy5agc\\",\\"_fc_drag_tag\\":\\"input\\",\\"display\\":true,\\"hidden\\":false}","{\\"type\\":\\"select\\",\\"field\\":\\"F5mrmqqdutnnabc\\",\\"title\\":\\"閫夋嫨鍣╘\",\\"info\\":\\"\\",\\"effect\\":{\\"fetch\\":\\"\\"},\\"$required\\":false,\\"options\\":[{\\"label\\":\\"閫夐」01\\",\\"value\\":\\"1\\"},{\\"label\\":\\"閫夐」02\\",\\"value\\":\\"2\\"},{\\"label\\":\\"閫夐」03\\",\\"value\\":\\"3\\"}],\\"_fc_id\\":\\"id_Fhnumqqdutnoacc\\",\\"name\\":\\"ref_Fd1wmqqdutnoadc\\",\\"_fc_drag_tag\\":\\"select\\",\\"display\\":true,\\"hidden\\":false}","{\\"type\\":\\"ApiSelect\\",\\"field\\":\\"dc4b501620bb4c8184aaaeb66398324a\\",\\"title\\":\\"鎺ュ彛閫夋嫨鍣╘\",\\"info\\":\\"\\",\\"$required\\":false,\\"props\\":{\\"method\\":\\"GET\\"},\\"_fc_id\\":\\"id_F6ewmrbn96xdc3c\\",\\"name\\":\\"ref_F1jomrbn96xdc4c\\",\\"display\\":true,\\"hidden\\":false,\\"_fc_drag_tag\\":\\"ApiSelect\\"}"]', NULL, NULL, NULL, X'01', '1785465606228', NULL, NULL, '1', X'01', X'01', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-08-10 06:35:49', '1', '2026-08-10 06:42:48', X'00'),
+('17', 'erp-purchase-invoice-audit:1:0b7c7557949111f192711ab6da3745b7', '0b7c7577949111f192711ab6da3745b7', '10', 'erp_purchase_invoice_approve', NULL, NULL, '10', '1', '{"form":{"layout":"horizontal","labelAlign":"right","size":"middle","colon":false,"labelCol":{"style":{"width":"125px"}},"wrapperCol":{"span":24},"labelWidth":"100px"},"resetBtn":{"show":false,"innerText":"閲嶇疆"},"submitBtn":{"show":true,"innerText":"鎻愪氦"}}', '["{\\"type\\":\\"input\\",\\"field\\":\\"Fyqymqqdoln2abc\\",\\"title\\":\\"濮撳悕\\",\\"info\\":\\"\\",\\"$required\\":false,\\"_fc_id\\":\\"id_Fuplmqqdoln2acc\\",\\"name\\":\\"ref_F18omqqdoln2adc\\",\\"_fc_drag_tag\\":\\"input\\",\\"display\\":true,\\"hidden\\":false}","{\\"type\\":\\"input\\",\\"field\\":\\"Fh6gmqqdooy5aec\\",\\"title\\":\\"骞撮緞\\",\\"info\\":\\"\\",\\"$required\\":false,\\"_fc_id\\":\\"id_F5whmqqdooy5afc\\",\\"name\\":\\"ref_Fltemqqdooy5agc\\",\\"_fc_drag_tag\\":\\"input\\",\\"display\\":true,\\"hidden\\":false}","{\\"type\\":\\"select\\",\\"field\\":\\"F5mrmqqdutnnabc\\",\\"title\\":\\"閫夋嫨鍣╘\",\\"info\\":\\"\\",\\"effect\\":{\\"fetch\\":\\"\\"},\\"$required\\":false,\\"options\\":[{\\"label\\":\\"閫夐」01\\",\\"value\\":\\"1\\"},{\\"label\\":\\"閫夐」02\\",\\"value\\":\\"2\\"},{\\"label\\":\\"閫夐」03\\",\\"value\\":\\"3\\"}],\\"_fc_id\\":\\"id_Fhnumqqdutnoacc\\",\\"name\\":\\"ref_Fd1wmqqdutnoadc\\",\\"_fc_drag_tag\\":\\"select\\",\\"display\\":true,\\"hidden\\":false}","{\\"type\\":\\"ApiSelect\\",\\"field\\":\\"dc4b501620bb4c8184aaaeb66398324a\\",\\"title\\":\\"鎺ュ彛閫夋嫨鍣╘\",\\"info\\":\\"\\",\\"$required\\":false,\\"props\\":{\\"method\\":\\"GET\\"},\\"_fc_id\\":\\"id_F6ewmrbn96xdc3c\\",\\"name\\":\\"ref_F1jomrbn96xdc4c\\",\\"display\\":true,\\"hidden\\":false,\\"_fc_drag_tag\\":\\"ApiSelect\\"}"]', NULL, NULL, NULL, X'01', '1785465606228', NULL, NULL, '1', X'01', X'01', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-08-10 07:57:25', '1', '2026-08-10 07:57:25', X'00'),
+('18', 'erp-finance-payment-audit:1:f1a1b2c3d4e5465f8a9b0c1d2e3f4a5b', 'f1a1b2c3d4e5465f8a9b0c1d2e3f4a5c', '10', 'erp_finance_payment_approve', NULL, NULL, '10', NULL, NULL, NULL, NULL, NULL, NULL, X'01', '1785465606228', NULL, NULL, NULL, X'01', X'01', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-08-10 09:36:01', '1', '2026-08-10 09:36:01', X'00'),
+('19', 'mes-pd-project-audit:1:ce99813cfeb29f270355dd39f8ef74f2', '44318b176050e94d2c4a86595763dde8', '10', 'mes_pd_project_approve', NULL, NULL, '10', NULL, NULL, NULL, NULL, NULL, NULL, X'01', '1786608755902', NULL, NULL, NULL, X'01', X'01', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-08-13 08:12:35', '1', '2026-08-13 08:12:35', X'00'),
+('26', 'sale_order_approve:1:dep_b9d15a0bc2b775bebb84987fb4b07cad', 'model_b9d15a0bc2b775bebb84987fb4b07cad', '10', 'sale_order_approve', NULL, NULL, '10', NULL, NULL, NULL, NULL, NULL, NULL, X'01', '1788502003364', NULL, NULL, NULL, X'01', X'01', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-09-04 06:06:43', '1', '2026-09-04 06:06:43', X'00'),
+('27', 'purchase_order_approve:1:dep_09ba42e32e7a436ee4e2a9b6eef0d232', 'model_09ba42e32e7a436ee4e2a9b6eef0d232', '10', 'purchase_order_approve', NULL, NULL, '10', NULL, NULL, NULL, NULL, NULL, NULL, X'01', '1788502021926', NULL, NULL, NULL, X'01', X'01', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-09-04 06:07:01', '1', '2026-09-04 06:07:01', X'00'),
+('28', 'crm-contract-audit:1:dep_febd13bedc800a97127ae1c042eb557b', 'model_febd13bedc800a97127ae1c042eb557b', '10', 'contract_approve', NULL, NULL, '10', NULL, NULL, NULL, NULL, NULL, NULL, X'01', '1788502030005', NULL, NULL, NULL, X'01', X'01', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-09-04 06:07:10', '1', '2026-09-04 06:07:10', X'00'),
+('29', 'hrm_leave:1:dep_862c6766e8cd1b32946a1ed2956a68bf', 'model_862c6766e8cd1b32946a1ed2956a68bf', '10', 'hrm_leave_approve', NULL, NULL, '10', NULL, NULL, NULL, NULL, NULL, NULL, X'01', '1788502047026', NULL, NULL, NULL, X'01', X'01', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-09-04 06:07:27', '1', '2026-09-04 06:07:27', X'00'),
+('30', 'hrm_overtime:1:dep_ecb89d4a54da3ae23601fef85642b0ce', 'model_ecb89d4a54da3ae23601fef85642b0ce', '10', 'overtime_approve', NULL, NULL, '10', NULL, NULL, NULL, NULL, NULL, NULL, X'01', '1788502053580', NULL, NULL, NULL, X'01', X'01', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-09-04 06:07:33', '1', '2026-09-04 06:07:33', X'00'),
+('31', 'hrm_resignation:1:dep_33d3b1649a923d986d89604267b79bbf', 'model_33d3b1649a923d986d89604267b79bbf', '10', 'hrm_resignation_approve', NULL, NULL, '10', NULL, NULL, NULL, NULL, NULL, NULL, X'01', '1788502104511', NULL, NULL, NULL, X'01', X'01', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-09-04 06:08:24', '1', '2026-09-04 06:08:24', X'00'),
+('32', 'hrm_transfer:1:dep_66ea9f27906591b4d0048d854c633a82', 'model_66ea9f27906591b4d0048d854c633a82', '10', 'hrm_transfer_approve', NULL, NULL, '10', NULL, NULL, NULL, NULL, NULL, NULL, X'01', '1788502111121', NULL, NULL, NULL, X'01', X'01', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-09-04 06:08:31', '1', '2026-09-04 06:08:31', X'00'),
+('33', 'hrm_attendance_approve:1:dep_d1d2025350ea9af098ca7dbe6e80b442', 'model_d1d2025350ea9af098ca7dbe6e80b442', '10', 'hrm_attendance_approve', NULL, NULL, '10', NULL, NULL, NULL, NULL, NULL, NULL, X'01', '1788502118186', NULL, NULL, NULL, X'01', X'01', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-09-04 06:08:38', '1', '2026-09-04 06:08:38', X'00'),
+('34', 'supplier_apply_approve:1:dep_b6e816103961b88392e4ac24c87dddf8', 'model_b6e816103961b88392e4ac24c87dddf8', '10', 'supplier_apply_approve', NULL, NULL, '10', NULL, NULL, NULL, NULL, NULL, NULL, X'01', '1788502130327', NULL, NULL, NULL, X'01', X'01', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-09-04 06:08:50', '1', '2026-09-04 06:08:50', X'00'),
+('35', 'wms_inbound_approve:1:dep_6e0f473d28c042b8b372d00797549423', 'model_6e0f473d28c042b8b372d00797549423', '10', 'wms_approve', NULL, NULL, '10', NULL, NULL, NULL, NULL, NULL, NULL, X'01', '1788502136828', NULL, NULL, NULL, X'01', X'01', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-09-04 06:08:56', '1', '2026-09-04 06:08:56', X'00'),
+('36', 'wms_outbound_approve:1:dep_bed6796545faa2cb7851a019948e4e49', 'model_bed6796545faa2cb7851a019948e4e49', '10', 'wms_approve', NULL, NULL, '10', NULL, NULL, NULL, NULL, NULL, NULL, X'01', '1788502143469', NULL, NULL, NULL, X'01', X'01', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-09-04 06:09:03', '1', '2026-09-04 06:09:03', X'00'),
+('37', 'wms_transfer_approve:1:dep_9b3368e05f1d39dee636f464f2d65c16', 'model_9b3368e05f1d39dee636f464f2d65c16', '10', 'wms_approve', NULL, NULL, '10', NULL, NULL, NULL, NULL, NULL, NULL, X'01', '1788502150320', NULL, NULL, NULL, X'01', X'01', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-09-04 06:09:10', '1', '2026-09-04 06:09:10', X'00'),
+('38', 'item_receipt_approve:1:dep_c16d0eef322695bed1c0c20e1d0190ce', 'model_c16d0eef322695bed1c0c20e1d0190ce', '10', 'item_receipt_approve', NULL, NULL, '10', NULL, NULL, NULL, NULL, NULL, NULL, X'01', '1788502157451', NULL, NULL, NULL, X'01', X'01', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-09-04 06:09:17', '1', '2026-09-04 06:09:17', X'00'),
+('39', 'mes-pro-feedback-audit:1:dep_08349f78d675f582f1ff5f08e7714a8d', 'model_08349f78d675f582f1ff5f08e7714a8d', '10', 'mes_pro_feedback_audit', NULL, NULL, '10', NULL, NULL, NULL, NULL, NULL, NULL, X'01', '1788502164296', NULL, NULL, NULL, X'01', X'01', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-09-04 06:09:24', '1', '2026-09-04 06:09:24', X'00');
+
+-- ***********************************************************************
+-- 鈶� 鍗忓悓锛堜笟鍔¢檮浠堕厤缃� + 鍒嗙被 + 琛ㄥ崟 + 鎵╁睍閰嶇疆锛夛紙DDL + 鏁版嵁锛�
+-- ***********************************************************************
+
+-- ============ 琛細bpm_business_attach锛堝鍑� 11 琛岋級 ============
+DROP TABLE IF EXISTS `bpm_business_attach`;
+CREATE TABLE `bpm_business_attach` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `process_definition_key` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '娴佺▼瀹氫箟鐨� Key',
+ `business_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '涓氬姟绫诲瀷锛屼緥濡� erp_purchase_order',
+ `component_path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '涓氬姟璇︽儏缁勪欢璺緞锛屼緥濡� /erp/purchase/order/detail/index.vue',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0寮�鍚� 1鍏抽棴锛�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ `deleted` bit(1) NOT NULL DEFAULT b'0',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_process_definition_key` (`process_definition_key`,`deleted`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='BPM 涓氬姟闄勪欢閰嶇疆琛�';
+INSERT INTO `bpm_business_attach` (`id`, `process_definition_key`, `business_type`, `component_path`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES
+('1', 'purchase_approve', 'erp_purchase_order', '/erp/purchase/order/detail/index.vue', '0', '閲囪喘璁㈠崟瀹℃壒灞曠ず閲囪喘璁㈠崟璇︽儏', '', '2026-08-14 06:11:59', '', '2026-08-14 06:11:59', X'00'),
+('2', 'purchase_request_approve', 'erp_purchase_request', '/erp/purchase/request/detail/index.vue', '0', '閲囪喘鐢宠瀹℃壒灞曠ず閲囪喘鐢宠璇︽儏', '', '2026-08-14 06:36:14', '1', '2026-08-14 15:06:16', X'00'),
+('3', 'contract_approve', 'crm_contract', '/crm/contract/detail/approve/index.vue', '0', '鍚堝悓瀹℃牳灞曠ず鍚堝悓璇︽儏', '', '2026-08-14 07:08:08', '', '2026-08-14 07:13:05', X'00'),
+('4', 'crm-invoice-audit', 'crm_invoice', '/crm/invoice/detail/approve/index.vue', '0', '寮�绁ㄥ鎵瑰睍绀哄紑绁ㄨ鎯�', '', '2026-08-14 07:22:40', '', '2026-08-14 07:22:40', X'00'),
+('5', 'crm-receivable-audit', 'crm_receivable', '/crm/receivable/detail/approve/index.vue', '0', '鍥炴瀹℃壒灞曠ず鍥炴璇︽儏', '', '2026-08-14 07:22:40', '', '2026-08-14 07:22:40', X'00'),
+('6', 'erp-finance-payment-audit', 'erp_finance_payment', '/erp/finance/payment/detail/approve/index.vue', '0', '浠樻瀹℃壒灞曠ず浠樻鍗曡鎯�', '', '2026-08-14 07:22:40', '', '2026-08-14 07:22:40', X'00'),
+('7', 'erp-purchase-invoice-audit', 'erp_purchase_invoice', '/erp/purchase/invoice/detail/approve/index.vue', '0', '鏉ョエ瀹℃壒灞曠ず鏉ョエ璇︽儏', '', '2026-08-14 07:22:40', '', '2026-08-14 07:22:40', X'00'),
+('8', 'hrm_leave', 'hrm_leave', '/hrm/leave/detail/approve/index.vue', '0', '璇峰亣瀹℃壒灞曠ず璇峰亣璇︽儏', '', '2026-08-14 07:45:33', '', '2026-08-14 07:45:33', X'00'),
+('9', 'hrm_resignation', 'hrm_resignation', '/hrm/resignation/detail/approve/index.vue', '0', '绂昏亴瀹℃壒灞曠ず绂昏亴璇︽儏', '', '2026-08-14 07:45:33', '', '2026-08-14 07:45:33', X'00'),
+('10', 'hrm_transfer', 'hrm_transfer', '/hrm/transfer/detail/approve/index.vue', '0', '璋冨矖瀹℃壒灞曠ず璋冨矖璇︽儏', '', '2026-08-14 07:45:33', '', '2026-08-14 07:45:33', X'00'),
+('11', 'hrm_attendance_exception', 'hrm_attendance_exception', '/hrm/attendance/exception/detail/approve/index.vue', '0', '鑰冨嫟寮傚父瀹℃壒灞曠ず鑰冨嫟寮傚父璇︽儏', '', '2026-08-14 07:45:33', '', '2026-08-14 07:45:33', X'00');
+
+-- ============ 琛細bpm_category锛堝鍑� 22 琛岋級 ============
+DROP TABLE IF EXISTS `bpm_category`;
+CREATE TABLE `bpm_category` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鍒嗙被缂栧彿',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍒嗙被鍚�',
+ `code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍒嗙被鏍囧織',
+ `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍒嗙被鎻忚堪',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鍒嗙被鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+ `sort` int NOT NULL DEFAULT '0' COMMENT '鍒嗙被鎺掑簭',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=216 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='BPM 娴佺▼鍒嗙被琛�';
+INSERT INTO `bpm_category` (`id`, `name`, `code`, `description`, `status`, `sort`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES
+('1', '鍙戣揣瀹℃壒', '鍒嗙被1', '鍒嗙被1', '0', '1', '1', '2026-06-23 16:23:03', '1', '2026-07-08 13:36:20', X'00'),
+('2', '閲囪喘瀹℃牳', 'purchase_request_approve', NULL, '0', '2', '142', '2026-06-30 16:44:10', '142', '2026-07-01 11:02:23', X'00'),
+('3', '閿�鍞姤浠峰鎵�', 'sale_quotation_approve', NULL, '0', '3', '142', '2026-07-02 09:54:40', '142', '2026-07-02 09:54:40', X'00'),
+('4', '鍚堝悓瀹℃壒', 'contract_approve', '鍚堝悓瀹℃壒娴佺▼鍒嗙被', '0', '0', '1', '2026-07-02 03:34:03', '1', '2026-07-02 03:34:03', X'00'),
+('5', '浜哄姏璧勬簮', 'hrm', NULL, '0', '5', '1', '2026-07-06 13:13:03', '1', '2026-07-06 13:13:03', X'00'),
+('120', '浠撳簱瀹℃牳', 'wms_approve', '浠撳簱绠$悊瀹℃壒娴佺▼鍒嗙被', '0', '30', '1', '2026-07-09 02:25:58', '1', '2026-07-09 02:25:58', X'00'),
+('200', '鑰冨嫟寮傚父瀹℃壒', 'hrm_attendance_approve', 'HRM鑰冨嫟寮傚父瀹℃壒鍒嗙被', '0', '50', '1', '2026-07-08 02:05:39', '1', '2026-07-08 02:05:39', X'00'),
+('201', '璇峰亣瀹℃壒', '鍒嗙被2', '123123123', '0', '12', '1', '2026-07-08 13:56:23', '1', '2026-07-08 13:56:23', X'00'),
+('202', '閲囪喘鍏ュ簱瀹℃壒', 'item_receipt_approve', 'MES閲囪喘鍏ュ簱鍗曞鎵瑰垎绫�', '0', '0', '1', '2026-07-10 03:29:18', '1', '2026-07-10 03:29:18', X'00'),
+('203', '鍥炴瀹℃壒', '1111', '222', '0', '1', '1', '2026-07-31 10:38:55', '1', '2026-07-31 10:38:55', X'00'),
+('204', '寮�绁ㄥ鎵�', 'crm_invoice_approve', '寮�绁ㄥ鎵规祦绋嬪垎绫�', '0', '60', '1', '2026-08-10 06:34:18', '1', '2026-08-10 06:34:18', X'00'),
+('205', '鏉ョエ瀹℃壒', 'erp_purchase_invoice_approve', 'ERP閲囪喘鏉ョエ瀹℃壒鍒嗙被', '0', '70', '1', '2026-08-10 07:56:24', '1', '2026-08-10 07:56:24', X'00'),
+('206', '浠樻瀹℃牳', 'erp_finance_payment_approve', '浠樻鍗曞鎵�', '0', '80', '1', '2026-08-10 09:35:41', '1', '2026-08-10 09:35:41', X'00'),
+('207', '浜у搧椤圭洰瀹℃壒', 'mes_pd_project_approve', '浜у搧椤圭洰鏈�鍚庡鏍窧PM瀹℃壒', '0', '90', '1', '2026-08-13 08:12:13', '1', '2026-08-13 08:12:13', X'00'),
+('208', '渚涘簲鍟嗗噯鍏ュ鎵�', 'supplier_apply_approve', 'SRM渚涘簲鍟嗗噯鍏ョ敵璇峰鎵规祦绋嬪垎绫�', '0', '100', '1', '2026-09-02 08:30:00', '1', '2026-09-02 08:30:00', X'00'),
+('209', '閲囪喘璁㈠崟瀹℃壒', 'purchase_order_approve', 'ERP 閲囪喘璁㈠崟瀹℃壒', '0', '10', '1', '2026-09-04 06:05:04', '1', '2026-09-04 06:05:04', X'00'),
+('210', '閿�鍞鍗曞鎵�', 'sale_order_approve', 'ERP 閿�鍞鍗曞鎵�', '0', '20', '1', '2026-09-04 06:05:04', '1', '2026-09-04 06:05:04', X'00'),
+('211', '璇峰亣瀹℃壒', 'hrm_leave_approve', 'HRM 璇峰亣鐢宠瀹℃壒', '0', '30', '1', '2026-09-04 06:05:04', '1', '2026-09-04 06:05:04', X'00'),
+('212', '鍔犵彮瀹℃壒', 'overtime_approve', 'HRM 鍔犵彮鐢宠瀹℃壒', '0', '40', '1', '2026-09-04 06:05:04', '1', '2026-09-04 06:05:04', X'00'),
+('213', '绂昏亴瀹℃壒', 'hrm_resignation_approve', 'HRM 绂昏亴鐢宠瀹℃壒', '0', '50', '1', '2026-09-04 06:05:04', '1', '2026-09-04 06:05:04', X'00'),
+('214', '璋冨姩瀹℃壒', 'hrm_transfer_approve', 'HRM 璋冨姩鐢宠瀹℃壒', '0', '60', '1', '2026-09-04 06:05:04', '1', '2026-09-04 06:05:04', X'00'),
+('215', '鎶ュ伐瀹℃壒', 'mes_pro_feedback_audit', 'MES 鐢熶骇鎶ュ伐/宸ュ崟瀹℃壒', '0', '70', '1', '2026-09-04 06:05:04', '1', '2026-09-04 06:05:04', X'00');
+
+-- ============ 琛細bpm_form锛堝鍑� 4 琛岋級 ============
+DROP TABLE IF EXISTS `bpm_form`;
+CREATE TABLE `bpm_form` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '琛ㄥ崟鍚�',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+ `conf` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '琛ㄥ崟鐨勯厤缃�',
+ `fields` json NOT NULL COMMENT '琛ㄥ崟椤圭殑鏁扮粍',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='BPM 宸ヤ綔娴佽〃鍗曞畾涔夎〃';
+INSERT INTO `bpm_form` (`id`, `name`, `status`, `conf`, `fields`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES
+('1', '琛ㄥ崟1', '0', '{"form":{"layout":"horizontal","labelAlign":"right","size":"middle","colon":false,"labelCol":{"style":{"width":"125px"}},"wrapperCol":{"span":24},"labelWidth":"100px"},"resetBtn":{"show":false,"innerText":"閲嶇疆"},"submitBtn":{"show":true,"innerText":"鎻愪氦"}}', '["{\\"type\\":\\"input\\",\\"field\\":\\"Fyqymqqdoln2abc\\",\\"title\\":\\"濮撳悕\\",\\"info\\":\\"\\",\\"$required\\":false,\\"_fc_id\\":\\"id_Fuplmqqdoln2acc\\",\\"name\\":\\"ref_F18omqqdoln2adc\\",\\"_fc_drag_tag\\":\\"input\\",\\"display\\":true,\\"hidden\\":false}","{\\"type\\":\\"input\\",\\"field\\":\\"Fh6gmqqdooy5aec\\",\\"title\\":\\"骞撮緞\\",\\"info\\":\\"\\",\\"$required\\":false,\\"_fc_id\\":\\"id_F5whmqqdooy5afc\\",\\"name\\":\\"ref_Fltemqqdooy5agc\\",\\"_fc_drag_tag\\":\\"input\\",\\"display\\":true,\\"hidden\\":false}","{\\"type\\":\\"select\\",\\"field\\":\\"F5mrmqqdutnnabc\\",\\"title\\":\\"閫夋嫨鍣╘\",\\"info\\":\\"\\",\\"effect\\":{\\"fetch\\":\\"\\"},\\"$required\\":false,\\"options\\":[{\\"label\\":\\"閫夐」01\\",\\"value\\":\\"1\\"},{\\"label\\":\\"閫夐」02\\",\\"value\\":\\"2\\"},{\\"label\\":\\"閫夐」03\\",\\"value\\":\\"3\\"}],\\"_fc_id\\":\\"id_Fhnumqqdutnoacc\\",\\"name\\":\\"ref_Fd1wmqqdutnoadc\\",\\"_fc_drag_tag\\":\\"select\\",\\"display\\":true,\\"hidden\\":false}","{\\"type\\":\\"ApiSelect\\",\\"field\\":\\"dc4b501620bb4c8184aaaeb66398324a\\",\\"title\\":\\"鎺ュ彛閫夋嫨鍣╘\",\\"info\\":\\"\\",\\"$required\\":false,\\"props\\":{\\"method\\":\\"GET\\"},\\"_fc_id\\":\\"id_F6ewmrbn96xdc3c\\",\\"name\\":\\"ref_F1jomrbn96xdc4c\\",\\"display\\":true,\\"hidden\\":false,\\"_fc_drag_tag\\":\\"ApiSelect\\"}"]', NULL, '1', '2026-06-23 16:24:37', '1', '2026-07-08 13:35:39', X'00'),
+('2', '璇峰亣琛ㄥ崟', '0', '{"form":{"layout":"horizontal","labelAlign":"right","size":"middle","colon":false,"labelCol":{"style":{"width":"125px"}},"wrapperCol":{"span":24},"labelWidth":"100px"},"resetBtn":{"show":false,"innerText":"閲嶇疆"},"submitBtn":{"show":true,"innerText":"鎻愪氦"}}', '["{\\"type\\":\\"DeptSelect\\",\\"field\\":\\"ce674cb3f7604c5da893b347bf1ff855\\",\\"title\\":\\"閮ㄩ棬閫夋嫨鍣╘\",\\"info\\":\\"\\",\\"$required\\":true,\\"props\\":{\\"returnType\\":\\"id\\",\\"defaultCurrentDept\\":false},\\"_fc_id\\":\\"id_Fgcgmrbnv9c4cbc\\",\\"name\\":\\"ref_F7c0mrbnv9c4ccc\\",\\"_fc_drag_tag\\":\\"DeptSelect\\",\\"display\\":true,\\"hidden\\":false}","{\\"type\\":\\"UserSelect\\",\\"field\\":\\"6ada8f47c5ad483ca7e2a15da2d922d1\\",\\"title\\":\\"鐢ㄦ埛閫夋嫨鍣╘\",\\"info\\":\\"\\",\\"$required\\":true,\\"props\\":{\\"defaultCurrentUser\\":false},\\"_fc_id\\":\\"id_F0pdmrbnvboxcdc\\",\\"name\\":\\"ref_F6pamrbnvboxcec\\",\\"_fc_drag_tag\\":\\"UserSelect\\",\\"display\\":true,\\"hidden\\":false}","{\\"type\\":\\"datePicker\\",\\"field\\":\\"Fio0ms5fmwwnabc\\",\\"title\\":\\"寮�濮嬫棩鏈焅\",\\"info\\":\\"\\",\\"$required\\":true,\\"props\\":{\\"showTime\\":true},\\"_fc_id\\":\\"id_F28vms5fmwwnacc\\",\\"name\\":\\"ref_Fhufms5fmwwnadc\\",\\"_fc_drag_tag\\":\\"datePicker\\",\\"display\\":true,\\"hidden\\":false}","{\\"type\\":\\"datePicker\\",\\"field\\":\\"Fpn0ms5fmyb4aec\\",\\"title\\":\\"缁撴潫鏃ユ湡\\",\\"info\\":\\"\\",\\"$required\\":true,\\"props\\":{\\"showTime\\":true},\\"_fc_id\\":\\"id_Fxrgms5fmyb4afc\\",\\"name\\":\\"ref_Fffoms5fmyb4agc\\",\\"_fc_drag_tag\\":\\"datePicker\\",\\"display\\":true,\\"hidden\\":false}","{\\"type\\":\\"inputNumber\\",\\"field\\":\\"F3n6ms5fwzqaaqc\\",\\"title\\":\\"璇峰亣澶╂暟\\",\\"info\\":\\"\\",\\"$required\\":true,\\"props\\":{\\"min\\":1},\\"_fc_id\\":\\"id_Fas0ms5fwzqbarc\\",\\"name\\":\\"ref_Fz1mms5fwzqbasc\\",\\"display\\":true,\\"hidden\\":false,\\"_fc_drag_tag\\":\\"inputNumber\\"}","{\\"type\\":\\"input\\",\\"field\\":\\"F1noms5fo0j5ahc\\",\\"title\\":\\"璇峰亣浜嬬敱\\",\\"info\\":\\"\\",\\"$required\\":true,\\"_fc_id\\":\\"id_Fybxms5fo0j5aic\\",\\"name\\":\\"ref_Fcv7ms5fo0j5ajc\\",\\"_fc_drag_tag\\":\\"input\\",\\"display\\":true,\\"hidden\\":false}"]', '1111', '1', '2026-07-08 13:54:31', '1', '2026-07-29 10:06:22', X'00'),
+('3', '渚涘簲鍟嗗噯鍏�', '0', '{"form":{"layout":"horizontal","labelAlign":"right","size":"middle","colon":false,"labelCol":{"style":{"width":"125px"}},"wrapperCol":{"span":24},"labelWidth":"100px"},"resetBtn":{"show":false,"innerText":"閲嶇疆"},"submitBtn":{"show":true,"innerText":"鎻愪氦"},"formName":"渚涘簲鍟嗗噯鍏�"}', '["{\\"type\\":\\"input\\",\\"field\\":\\"Ftvpmtjte8y4abc\\",\\"title\\":\\"鍚嶇О\\",\\"info\\":\\"鍏徃鍚嶅瓧\\",\\"$required\\":false,\\"_fc_id\\":\\"id_Fgxsmtjte8y4acc\\",\\"name\\":\\"ref_Fu8smtjte8y4adc\\",\\"display\\":true,\\"hidden\\":false,\\"_fc_drag_tag\\":\\"input\\"}","{\\"type\\":\\"input\\",\\"field\\":\\"Fe4zmtjtepcyaec\\",\\"title\\":\\"鍏徃浠嬬粛\\",\\"info\\":\\"鍏徃绠�浠媆\",\\"$required\\":false,\\"props\\":{\\"type\\":\\"textarea\\"},\\"_fc_id\\":\\"id_Fapymtjtepcyafc\\",\\"name\\":\\"ref_Fofimtjtepcyagc\\",\\"display\\":true,\\"hidden\\":false,\\"_fc_drag_tag\\":\\"textarea\\"}","{\\"type\\":\\"input\\",\\"field\\":\\"Fxoumtjtfdmsahc\\",\\"title\\":\\"鐢佃瘽\\",\\"info\\":\\"\\",\\"$required\\":false,\\"_fc_id\\":\\"id_F430mtjtfdmsaic\\",\\"name\\":\\"ref_Fjpwmtjtfdmsajc\\",\\"display\\":true,\\"hidden\\":false,\\"_fc_drag_tag\\":\\"input\\"}","{\\"type\\":\\"input\\",\\"field\\":\\"Fs0kmtjtficsakc\\",\\"title\\":\\"娉曚汉鍚嶇О\\",\\"info\\":\\"\\",\\"$required\\":false,\\"_fc_id\\":\\"id_Fwmbmtjtficsalc\\",\\"name\\":\\"ref_Fcr1mtjtficsamc\\",\\"display\\":true,\\"hidden\\":false,\\"_fc_drag_tag\\":\\"input\\"}","{\\"type\\":\\"input\\",\\"field\\":\\"F3m4mtjtfqiqanc\\",\\"title\\":\\"鍏徃璐熻矗浜鸿仈绯绘柟寮廫\",\\"info\\":\\"\\",\\"$required\\":false,\\"_fc_id\\":\\"id_Fgh9mtjtfqiqaoc\\",\\"name\\":\\"ref_Fs96mtjtfqiqapc\\",\\"display\\":true,\\"hidden\\":false,\\"_fc_drag_tag\\":\\"input\\"}"]', NULL, '1', '2026-09-02 16:08:31', '1', '2026-09-02 16:08:31', X'00'),
+('4', '閲囪喘琛ㄥ崟', '0', '{"form":{"layout":"horizontal","labelAlign":"right","size":"middle","colon":false,"labelCol":{"style":{"width":"125px"}},"wrapperCol":{"span":24},"labelWidth":"100px"},"resetBtn":{"show":false,"innerText":"閲嶇疆"},"submitBtn":{"show":true,"innerText":"鎻愪氦"}}', '["{\\"type\\":\\"input\\",\\"field\\":\\"Fr9umtk0jqtyabc\\",\\"title\\":\\"閲囪喘鍗曞彿\\",\\"info\\":\\"\\",\\"$required\\":false,\\"_fc_id\\":\\"id_Fqzrmtk0jqtzacc\\",\\"name\\":\\"ref_Fk3emtk0jqtzadc\\",\\"display\\":true,\\"hidden\\":false,\\"_fc_drag_tag\\":\\"input\\"}","{\\"type\\":\\"input\\",\\"field\\":\\"F5vrmtk0kaowaec\\",\\"title\\":\\"閲囪喘閮ㄩ棬\\",\\"info\\":\\"\\",\\"$required\\":false,\\"_fc_id\\":\\"id_F0qwmtk0kaowafc\\",\\"name\\":\\"ref_Fxpfmtk0kaowagc\\",\\"display\\":true,\\"hidden\\":false,\\"_fc_drag_tag\\":\\"input\\"}","{\\"type\\":\\"timePicker\\",\\"field\\":\\"Faoymtk0kvopahc\\",\\"title\\":\\"閲囪喘鏃堕棿\\",\\"info\\":\\"\\",\\"$required\\":false,\\"_fc_id\\":\\"id_Fhmemtk0kvopaic\\",\\"name\\":\\"ref_Fa30mtk0kvopajc\\",\\"display\\":true,\\"hidden\\":false,\\"_fc_drag_tag\\":\\"timePicker\\"}","{\\"type\\":\\"timePicker\\",\\"field\\":\\"Fseemtk0l4kpakc\\",\\"title\\":\\"鍒拌揣鏃堕棿\\",\\"info\\":\\"\\",\\"$required\\":false,\\"_fc_id\\":\\"id_F4dfmtk0l4kpalc\\",\\"name\\":\\"ref_F3jqmtk0l4kpamc\\",\\"display\\":true,\\"hidden\\":false,\\"_fc_drag_tag\\":\\"timePicker\\"}","{\\"type\\":\\"input\\",\\"field\\":\\"Fjeimtk0lyj1awc\\",\\"title\\":\\"閲囪喘鏁伴噺\\",\\"info\\":\\"\\",\\"$required\\":false,\\"_fc_id\\":\\"id_Fcs1mtk0lyj1axc\\",\\"name\\":\\"ref_Fx89mtk0lyj1ayc\\",\\"display\\":true,\\"hidden\\":false,\\"_fc_drag_tag\\":\\"input\\"}","{\\"type\\":\\"input\\",\\"field\\":\\"Fizgmtk0lz00azc\\",\\"title\\":\\"閲囪喘鍗曚环\\",\\"info\\":\\"\\",\\"$required\\":false,\\"_fc_id\\":\\"id_Fklomtk0lz01b0c\\",\\"name\\":\\"ref_Fz4smtk0lz01b1c\\",\\"display\\":true,\\"hidden\\":false,\\"_fc_drag_tag\\":\\"input\\"}","{\\"type\\":\\"input\\",\\"field\\":\\"Feejmtk0lzgmb2c\\",\\"title\\":\\"閲囪喘鎬讳环\\",\\"info\\":\\"\\",\\"$required\\":false,\\"_fc_id\\":\\"id_Fgpumtk0lzgmb3c\\",\\"name\\":\\"ref_Ffaomtk0lzgmb4c\\",\\"display\\":true,\\"hidden\\":false,\\"_fc_drag_tag\\":\\"input\\"}","{\\"type\\":\\"input\\",\\"field\\":\\"Feo7mtk0m9sab5c\\",\\"title\\":\\"閲囪喘鏄庣粏\\",\\"info\\":\\"\\",\\"$required\\":false,\\"props\\":{\\"type\\":\\"textarea\\"},\\"_fc_id\\":\\"id_Fht3mtk0m9sab6c\\",\\"name\\":\\"ref_Fwwpmtk0m9sab7c\\",\\"display\\":true,\\"hidden\\":false,\\"_fc_drag_tag\\":\\"textarea\\"}"]', NULL, '1', '2026-09-02 19:30:15', '1', '2026-09-02 19:30:15', X'00');
+
+-- ============ 琛細bpm_user_group锛堝鍑� 3 琛岋級 ============
+DROP TABLE IF EXISTS `bpm_user_group`;
+CREATE TABLE `bpm_user_group` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '缁勫悕',
+ `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎻忚堪',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+ `user_ids` json NOT NULL COMMENT '鎴愬憳鐢ㄦ埛缂栧彿鏁扮粍',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='BPM 鐢ㄦ埛缁勮〃';
+INSERT INTO `bpm_user_group` (`id`, `name`, `description`, `status`, `user_ids`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES
+('1', '缁�1', NULL, '0', '[1,113,115,100]', '1', '2026-06-23 16:27:37', '1', '2026-08-06 16:51:20', X'00'),
+('2', '缁忚惀缁�', NULL, '0', '[247]', '1', '2026-09-02 15:58:35', '1', '2026-09-02 15:58:35', X'00'),
+('3', '缁忚惀閮�', NULL, '0', '[1,247,233]', '1', '2026-09-02 19:26:22', '1', '2026-09-03 13:37:13', X'00');
+
+-- ============ 琛細bpm_process_listener锛堝鍑� 1 琛岋級 ============
+DROP TABLE IF EXISTS `bpm_process_listener`;
+CREATE TABLE `bpm_process_listener` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭 ID',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐩戝惉鍣ㄥ悕瀛�',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+ `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐩戝惉绫诲瀷锛坋xecution鎵ц鐩戝惉鍣ㄣ�乼ask浠诲姟鐩戝惉鍣級',
+ `event` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐩戝惉浜嬩欢',
+ `value_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍊肩被鍨嬶紙class绫汇�乨elegateExpression濮旀墭琛ㄨ揪寮忋�乪xpression琛ㄨ揪寮忥級',
+ `value` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍊�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='BPM 娴佺▼鐩戝惉鍣ㄨ〃';
+INSERT INTO `bpm_process_listener` (`id`, `name`, `status`, `type`, `event`, `value_type`, `value`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES
+('1', '娴嬭瘯鐩戝惉鍣�', '0', 'task', 'create', 'class', 'org.flowable.engine.delegate.TaskListener', '1', '2026-07-08 13:43:00', '1', '2026-07-08 13:43:00', X'00');
+
+-- ============ 琛細bpm_process_expression锛堝鍑� 1 琛岋級 ============
+DROP TABLE IF EXISTS `bpm_process_expression`;
+CREATE TABLE `bpm_process_expression` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '琛ㄨ揪寮忓悕瀛�',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '琛ㄨ揪寮忕姸鎬侊紙0姝e父 1鍋滅敤锛�',
+ `expression` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '琛ㄨ揪寮�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='BPM 娴佺▼琛ㄨ揪寮忚〃';
+INSERT INTO `bpm_process_expression` (`id`, `name`, `status`, `expression`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES
+('1', '閰掓硥', '0', '鐜板湪鎵�', '1', '2026-06-23 16:25:59', '1', '2026-06-23 16:25:59', X'00');
+
+-- ***********************************************************************
+-- 鈶� BI 鍐崇瓥澶у睆 / go-view锛圖DL + 鏁版嵁锛�
+-- ***********************************************************************
+
+-- ============ 琛細bi_dashboard锛堝鍑� 5 琛岋級 ============
+DROP TABLE IF EXISTS `bi_dashboard`;
+CREATE TABLE `bi_dashboard` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '浠〃鐩樺悕绉�',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '浠〃鐩樼紪鐮侊紙鍞竴鏍囪瘑锛�',
+ `group_code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鎵�灞炲垎缁勶細purchase_sales/warehouse/production_equipment/quality/hr_oa',
+ `icon` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍥炬爣',
+ `sort` int NOT NULL DEFAULT '0' COMMENT '鎺掑簭',
+ `status` tinyint NOT NULL DEFAULT '1' COMMENT '鐘舵�侊細0-绂佺敤 1-鍚敤',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_code` (`code`) USING BTREE,
+ KEY `idx_group_code` (`group_code`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='BI浠〃鐩樺畾涔夎〃';
+INSERT INTO `bi_dashboard` (`id`, `name`, `code`, `group_code`, `icon`, `sort`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES
+('1', '閲囪喘閿�鍞敭鍚庡ぇ灞�', 'purchase_sales', 'purchase_sales', 'ep:trend-charts', '1', '1', '閲囪喘銆侀攢鍞�佸敭鍚庝笟鍔℃瑙�', '1', '2026-08-05 06:24:55', '1', '2026-08-05 06:24:55', X'00'),
+('2', '浠撳簱澶у睆', 'warehouse', 'warehouse', 'ep:warehouse', '2', '1', '浠撳偍鐗╂祦涓氬姟姒傝', '1', '2026-08-05 06:24:55', '1', '2026-08-05 06:24:55', X'00'),
+('3', '鐢熶骇璁惧澶у睆', 'production_equipment', 'production_equipment', 'ep:set-up', '3', '1', '鐢熶骇绠℃帶銆佽澶囩鐞嗕笟鍔℃瑙�', '1', '2026-08-05 06:24:55', '1', '2026-08-05 06:24:55', X'00'),
+('4', '璐ㄩ噺澶у睆', 'quality', 'quality', 'ep:circle-check', '4', '1', '璐ㄩ噺绠$悊涓氬姟姒傝', '1', '2026-08-05 06:24:55', '1', '2026-08-05 06:24:55', X'00'),
+('5', '浜鸿祫鍔炲叕澶у睆', 'hr_oa', 'hr_oa', 'ep:office-building', '5', '1', '浜哄姏璧勬簮銆佸崗鍚屽姙鍏笟鍔℃瑙�', '1', '2026-08-05 06:24:55', '1', '2026-08-05 06:24:55', X'00');
+
+-- ============ 琛細bi_chart_config锛堝鍑� 36 琛岋級 ============
+DROP TABLE IF EXISTS `bi_chart_config`;
+CREATE TABLE `bi_chart_config` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `dashboard_id` bigint NOT NULL COMMENT '鎵�灞炰华琛ㄧ洏ID',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍥捐〃鍚嶇О',
+ `chart_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍥捐〃绫诲瀷锛歜ar/line/pie/scatter/gauge/table/number',
+ `data_source_id` bigint DEFAULT NULL COMMENT '鏁版嵁婧愰厤缃甀D',
+ `query_sql` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鏌ヨSQL锛堟敮鎸� {{param}} 鍗犱綅绗︼級',
+ `position` json DEFAULT NULL COMMENT '甯冨眬浣嶇疆 {x, y, w, h}',
+ `chart_options` json DEFAULT NULL COMMENT 'ECharts 閰嶇疆椤硅鐩�',
+ `refresh_interval` int NOT NULL DEFAULT '0' COMMENT '鍒锋柊闂撮殧锛堢锛夛紝0琛ㄧず涓嶈嚜鍔ㄥ埛鏂�',
+ `sort` int NOT NULL DEFAULT '0' COMMENT '鎺掑簭',
+ `status` tinyint NOT NULL DEFAULT '1' COMMENT '鐘舵�侊細0-绂佺敤 1-鍚敤',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_dashboard_id` (`dashboard_id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='BI鍥捐〃閰嶇疆琛�';
+INSERT INTO `bi_chart_config` (`id`, `dashboard_id`, `name`, `chart_type`, `data_source_id`, `query_sql`, `position`, `chart_options`, `refresh_interval`, `sort`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES
+('1', '1', '閲囪喘璁㈠崟鎬绘暟', 'number', NULL, 'SELECT COUNT(*) AS value FROM erp_purchase_order WHERE deleted = 0', '{"h":4,"w":3,"x":0,"y":0}', NULL, '10', '1', '1', '1', '2026-08-05 07:07:40', '142', '2026-08-05 17:42:42', X'00'),
+('2', '1', '閿�鍞鍗曟�绘暟', 'number', NULL, 'SELECT COUNT(*) AS value FROM erp_sale_order WHERE deleted = 0', '{"h":4,"w":3,"x":3,"y":0}', NULL, '0', '2', '1', '1', '2026-08-05 07:07:47', '1', '2026-08-05 07:07:47', X'00'),
+('3', '1', '瀹㈡埛鎬绘暟', 'number', NULL, 'SELECT COUNT(*) AS value FROM crm_customer WHERE deleted = 0', '{"h":4,"w":3,"x":6,"y":0}', NULL, '0', '3', '1', '1', '2026-08-05 07:07:47', '1', '2026-08-05 07:07:47', X'00'),
+('4', '1', '渚涘簲鍟嗘�绘暟', 'number', NULL, 'SELECT COUNT(*) AS value FROM erp_supplier WHERE deleted = 0', '{"h":4,"w":3,"x":9,"y":0}', NULL, '0', '4', '1', '1', '2026-08-05 07:07:47', '1', '2026-08-05 07:07:47', X'00'),
+('5', '1', '閲囪喘璁㈠崟鏈堝害瓒嬪娍', 'bar', NULL, 'SELECT DATE_FORMAT(order_time, \'%Y-%m\') AS name, COUNT(*) AS value FROM erp_purchase_order WHERE deleted = 0 AND order_time >= DATE_SUB(NOW(), INTERVAL 12 MONTH) GROUP BY DATE_FORMAT(order_time, \'%Y-%m\') ORDER BY name', '{"h":8,"w":7,"x":0,"y":4}', NULL, '0', '5', '1', '1', '2026-08-05 07:07:58', '1', '2026-08-05 07:07:58', X'00'),
+('6', '1', '閿�鍞鍗曟湀搴﹁秼鍔�', 'line', NULL, 'SELECT DATE_FORMAT(order_time, \'%Y-%m\') AS name, COUNT(*) AS value FROM erp_sale_order WHERE deleted = 0 AND order_time >= DATE_SUB(NOW(), INTERVAL 12 MONTH) GROUP BY DATE_FORMAT(order_time, \'%Y-%m\') ORDER BY name', '{"h":8,"w":5,"x":7,"y":4}', NULL, '0', '6', '1', '1', '2026-08-05 07:07:58', '1', '2026-08-05 07:07:58', X'00'),
+('7', '1', '閲囪喘璁㈠崟鐘舵�佸垎甯�', 'pie', NULL, 'SELECT CASE status WHEN 0 THEN \'寰呭鎵筡' WHEN 1 THEN \'瀹℃壒涓璡' WHEN 2 THEN \'宸查�氳繃\' WHEN 3 THEN \'宸查┏鍥瀄' WHEN 4 THEN \'宸插叧闂璡' ELSE \'鏈煡\' END AS name, COUNT(*) AS value FROM erp_purchase_order WHERE deleted = 0 GROUP BY status', '{"h":8,"w":5,"x":0,"y":12}', NULL, '0', '7', '1', '1', '2026-08-05 07:07:58', '1', '2026-08-05 07:07:58', X'00'),
+('8', '1', '鏈�杩戦噰璐鍗�', 'table', NULL, 'SELECT no AS 璁㈠崟鍙�, total_price AS 閲戦, order_time AS 涓嬪崟鏃堕棿 FROM erp_purchase_order WHERE deleted = 0 ORDER BY order_time DESC LIMIT 10', '{"h":8,"w":7,"x":5,"y":12}', NULL, '0', '8', '1', '1', '2026-08-05 07:07:58', '1', '2026-08-05 07:07:58', X'00'),
+('9', '2', '浠撳簱鏁伴噺', 'number', NULL, 'SELECT COUNT(*) AS value FROM mes_wm_warehouse WHERE deleted = 0 AND frozen = 0', '{"h":4,"w":3,"x":0,"y":0}', NULL, '0', '1', '1', '1', '2026-08-05 07:08:31', '1', '2026-08-05 07:08:31', X'00'),
+('10', '2', '鐗╂枡搴撳瓨鍝佺鏁�', 'number', NULL, 'SELECT COUNT(*) AS value FROM mes_wm_material_stock WHERE deleted = 0 AND quantity > 0', '{"h":4,"w":3,"x":3,"y":0}', NULL, '0', '2', '1', '1', '2026-08-05 07:08:31', '1', '2026-08-05 07:08:31', X'00'),
+('11', '2', '鍒拌揣閫氱煡鏁�', 'number', NULL, 'SELECT COUNT(*) AS value FROM mes_wm_arrival_notice WHERE deleted = 0', '{"h":4,"w":3,"x":6,"y":0}', NULL, '0', '3', '1', '1', '2026-08-05 07:08:31', '1', '2026-08-05 07:08:31', X'00'),
+('12', '2', '鍑鸿揣閫氱煡鏁�', 'number', NULL, 'SELECT COUNT(*) AS value FROM mes_wm_sales_notice WHERE deleted = 0', '{"h":4,"w":3,"x":9,"y":0}', NULL, '0', '4', '1', '1', '2026-08-05 07:08:31', '1', '2026-08-05 07:08:31', X'00'),
+('13', '2', '鍚勪粨搴撳簱瀛橀噺', 'bar', NULL, 'SELECT w.name, COALESCE(SUM(s.quantity), 0) AS value FROM mes_wm_warehouse w LEFT JOIN mes_wm_material_stock s ON w.id = s.warehouse_id AND s.deleted = 0 WHERE w.deleted = 0 GROUP BY w.id, w.name', '{"h":8,"w":7,"x":0,"y":4}', NULL, '0', '5', '1', '1', '2026-08-05 07:08:46', '1', '2026-08-05 07:08:46', X'00'),
+('14', '2', '鍑哄叆搴撹秼鍔�', 'line', NULL, 'SELECT DATE_FORMAT(transaction_time, \'%Y-%m\') AS name, SUM(CASE WHEN type = 1 THEN quantity ELSE 0 END) AS \'鍏ュ簱\', SUM(CASE WHEN type = 2 THEN quantity ELSE 0 END) AS \'鍑哄簱\' FROM mes_wm_transaction WHERE deleted = 0 AND transaction_time >= DATE_SUB(NOW(), INTERVAL 12 MONTH) GROUP BY DATE_FORMAT(transaction_time, \'%Y-%m\') ORDER BY name', '{"h":8,"w":5,"x":7,"y":4}', NULL, '0', '6', '1', '1', '2026-08-05 07:08:47', '1', '2026-08-05 07:09:25', X'00'),
+('15', '2', '鏈�杩戝叆搴撹褰�', 'table', NULL, 'SELECT code AS 鍗曞彿, name AS 鍚嶇О, receipt_date AS 鍏ュ簱鏃ユ湡 FROM mes_wm_item_receipt WHERE deleted = 0 ORDER BY create_time DESC LIMIT 10', '{"h":8,"w":12,"x":0,"y":12}', NULL, '0', '7', '1', '1', '2026-08-05 07:08:47', '1', '2026-08-05 07:09:11', X'00'),
+('16', '3', '宸ュ崟鎬绘暟', 'number', NULL, 'SELECT COUNT(*) AS value FROM mes_pro_work_order WHERE deleted = 0', '{"h":4,"w":3,"x":0,"y":0}', NULL, '0', '1', '1', '1', '2026-08-05 07:09:49', '1', '2026-08-05 07:09:49', X'00'),
+('17', '3', '璁惧鎬绘暟', 'number', NULL, 'SELECT COUNT(*) AS value FROM mes_dv_machinery WHERE deleted = 0', '{"h":4,"w":3,"x":3,"y":0}', NULL, '0', '2', '1', '1', '2026-08-05 07:09:49', '1', '2026-08-05 07:09:49', X'00'),
+('18', '3', '鏈湀鎶ュ伐鏁�', 'number', NULL, 'SELECT COUNT(*) AS value FROM mes_pro_feedback WHERE deleted = 0 AND MONTH(feedback_time) = MONTH(NOW()) AND YEAR(feedback_time) = YEAR(NOW())', '{"h":4,"w":3,"x":6,"y":0}', NULL, '0', '3', '1', '1', '2026-08-05 07:09:49', '1', '2026-08-05 07:09:49', X'00'),
+('19', '3', '宸ュ崟瀹屾垚鐜�', 'gauge', NULL, 'SELECT ROUND(SUM(CASE WHEN status = 3 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 1) AS value FROM mes_pro_work_order WHERE deleted = 0', '{"h":4,"w":3,"x":9,"y":0}', NULL, '0', '4', '1', '1', '2026-08-05 07:09:49', '1', '2026-08-05 07:09:49', X'00'),
+('20', '3', '宸ュ崟鐘舵�佸垎甯�', 'bar', NULL, 'SELECT CASE status WHEN 0 THEN \'鑽夌\' WHEN 1 THEN \'瀹℃壒涓璡' WHEN 2 THEN \'宸蹭笅杈綷' WHEN 3 THEN \'宸插畬鎴怽' WHEN 4 THEN \'宸插彇娑圽' ELSE \'鏈煡\' END AS name, COUNT(*) AS value FROM mes_pro_work_order WHERE deleted = 0 GROUP BY status', '{"h":8,"w":6,"x":0,"y":4}', NULL, '0', '5', '1', '1', '2026-08-05 07:10:04', '1', '2026-08-05 07:10:04', X'00'),
+('21', '3', '宸ュ崟绫诲瀷鍒嗗竷', 'pie', NULL, 'SELECT CASE type WHEN 1 THEN \'鐢熶骇宸ュ崟\' WHEN 2 THEN \'杩斿伐宸ュ崟\' WHEN 3 THEN \'鏀瑰埗宸ュ崟\' WHEN 4 THEN \'缁翠慨宸ュ崟\' ELSE \'鍏朵粬\' END AS name, COUNT(*) AS value FROM mes_pro_work_order WHERE deleted = 0 GROUP BY type', '{"h":8,"w":6,"x":6,"y":4}', NULL, '0', '6', '1', '1', '2026-08-05 07:10:04', '1', '2026-08-05 07:10:04', X'00'),
+('22', '3', '鏈�杩戝伐鍗曞垪琛�', 'table', NULL, 'SELECT code AS 宸ュ崟鍙�, name AS 宸ュ崟鍚嶇О, quantity AS 鐢熶骇鏁伴噺, request_date AS 闇�姹傛棩鏈� FROM mes_pro_work_order WHERE deleted = 0 ORDER BY create_time DESC LIMIT 10', '{"h":8,"w":12,"x":0,"y":12}', NULL, '0', '7', '1', '1', '2026-08-05 07:10:04', '1', '2026-08-05 07:10:04', X'00'),
+('23', '4', '鏉ユ枡妫�楠屾�绘暟', 'number', NULL, 'SELECT COUNT(*) AS value FROM mes_qc_iqc WHERE deleted = 0', '{"h":4,"w":3,"x":0,"y":0}', NULL, '0', '1', '1', '1', '2026-08-05 07:10:25', '1', '2026-08-05 07:10:25', X'00'),
+('24', '4', '鍒剁▼妫�楠屾�绘暟', 'number', NULL, 'SELECT COUNT(*) AS value FROM mes_qc_ipqc WHERE deleted = 0', '{"h":4,"w":3,"x":3,"y":0}', NULL, '0', '2', '1', '1', '2026-08-05 07:10:25', '1', '2026-08-05 07:10:25', X'00'),
+('25', '4', '鍑鸿揣妫�楠屾�绘暟', 'number', NULL, 'SELECT COUNT(*) AS value FROM mes_qc_oqc WHERE deleted = 0', '{"h":4,"w":3,"x":6,"y":0}', NULL, '0', '3', '1', '1', '2026-08-05 07:10:25', '1', '2026-08-05 07:10:25', X'00'),
+('26', '4', '鏉ユ枡鍚堟牸鐜�', 'gauge', NULL, 'SELECT COALESCE(ROUND(SUM(qualified_quantity) * 100.0 / NULLIF(SUM(check_quantity), 0), 1), 0) AS value FROM mes_qc_iqc WHERE deleted = 0', '{"h":4,"w":3,"x":9,"y":0}', NULL, '0', '4', '1', '1', '2026-08-05 07:10:25', '1', '2026-08-05 07:10:25', X'00'),
+('27', '4', '妫�楠岀被鍨嬪垎甯�', 'pie', NULL, 'SELECT \'鏉ユ枡妫�楠孿' AS name, COUNT(*) AS value FROM mes_qc_iqc WHERE deleted = 0 UNION ALL SELECT \'鍒剁▼妫�楠孿', COUNT(*) FROM mes_qc_ipqc WHERE deleted = 0 UNION ALL SELECT \'鍑鸿揣妫�楠孿', COUNT(*) FROM mes_qc_oqc WHERE deleted = 0', '{"h":8,"w":5,"x":0,"y":4}', NULL, '0', '5', '1', '1', '2026-08-05 07:10:34', '1', '2026-08-05 07:10:34', X'00'),
+('28', '4', '鏈堝害妫�楠岃秼鍔�', 'bar', NULL, 'SELECT DATE_FORMAT(create_time, \'%Y-%m\') AS name, COUNT(*) AS value FROM (SELECT create_time FROM mes_qc_iqc WHERE deleted = 0 UNION ALL SELECT create_time FROM mes_qc_ipqc WHERE deleted = 0 UNION ALL SELECT create_time FROM mes_qc_oqc WHERE deleted = 0) t WHERE create_time >= DATE_SUB(NOW(), INTERVAL 12 MONTH) GROUP BY DATE_FORMAT(create_time, \'%Y-%m\') ORDER BY name', '{"h":8,"w":7,"x":5,"y":4}', NULL, '0', '6', '1', '1', '2026-08-05 07:10:34', '1', '2026-08-05 07:10:34', X'00'),
+('29', '4', '鏈�杩戞楠岃褰�', 'table', NULL, 'SELECT * FROM (SELECT \'鏉ユ枡妫�楠孿' AS 绫诲瀷, code AS 鍗曞彿, name AS 鍚嶇О, inspect_date AS 妫�楠屾棩鏈� FROM mes_qc_iqc WHERE deleted = 0 UNION ALL SELECT \'鍒剁▼妫�楠孿', code, name, create_time FROM mes_qc_ipqc WHERE deleted = 0 UNION ALL SELECT \'鍑鸿揣妫�楠孿', code, name, create_time FROM mes_qc_oqc WHERE deleted = 0) t ORDER BY 妫�楠屾棩鏈� DESC LIMIT 10', '{"h":8,"w":12,"x":0,"y":12}', NULL, '0', '7', '1', '1', '2026-08-05 07:10:35', '1', '2026-08-05 07:10:43', X'00'),
+('30', '5', '鍦ㄨ亴鍛樺伐鏁�', 'number', NULL, 'SELECT COUNT(*) AS value FROM hrm_employee WHERE deleted = 0 AND employee_status IN (1, 2)', '{"h":4,"w":3,"x":0,"y":0}', NULL, '0', '1', '1', '1', '2026-08-05 07:10:59', '1', '2026-08-05 07:10:59', X'00'),
+('31', '5', '璇峰亣鐢宠鏁�', 'number', NULL, 'SELECT COUNT(*) AS value FROM hrm_leave_application WHERE deleted = 0', '{"h":4,"w":3,"x":3,"y":0}', NULL, '0', '2', '1', '1', '2026-08-05 07:10:59', '1', '2026-08-05 07:10:59', X'00'),
+('32', '5', '鏈湀绂昏亴鏁�', 'number', NULL, 'SELECT COUNT(*) AS value FROM hrm_employee WHERE deleted = 0 AND employee_status = 3 AND MONTH(leave_date) = MONTH(NOW()) AND YEAR(leave_date) = YEAR(NOW())', '{"h":4,"w":3,"x":6,"y":0}', NULL, '0', '3', '1', '1', '2026-08-05 07:10:59', '1', '2026-08-05 07:10:59', X'00'),
+('33', '5', '鑰冨嫟寮傚父鏁�', 'number', NULL, 'SELECT COUNT(*) AS value FROM hrm_attendance_exception WHERE deleted = 0', '{"h":4,"w":3,"x":9,"y":0}', NULL, '0', '4', '1', '1', '2026-08-05 07:10:59', '1', '2026-08-05 07:10:59', X'00'),
+('34', '5', '閮ㄩ棬浜烘暟鍒嗗竷', 'pie', NULL, 'SELECT d.name, COUNT(*) AS value FROM hrm_employee e JOIN system_dept d ON e.dept_id = d.id WHERE e.deleted = 0 AND e.employee_status IN (1, 2) AND d.deleted = 0 GROUP BY d.id, d.name', '{"h":8,"w":5,"x":0,"y":4}', NULL, '0', '5', '1', '1', '2026-08-05 07:11:07', '1', '2026-08-05 07:11:07', X'00'),
+('35', '5', '璇峰亣绫诲瀷鍒嗗竷', 'bar', NULL, 'SELECT CASE leave_type WHEN 1 THEN \'浜嬪亣\' WHEN 2 THEN \'鐥呭亣\' WHEN 3 THEN \'骞村亣\' WHEN 4 THEN \'濠氬亣\' WHEN 5 THEN \'浜у亣\' WHEN 6 THEN \'涓у亣\' ELSE \'鍏朵粬\' END AS name, COUNT(*) AS value FROM hrm_leave_application WHERE deleted = 0 GROUP BY leave_type', '{"h":8,"w":7,"x":5,"y":4}', NULL, '0', '6', '1', '1', '2026-08-05 07:11:07', '1', '2026-08-05 07:11:07', X'00'),
+('36', '5', '鏈�杩戝叆鑱屽憳宸�', 'table', NULL, 'SELECT employee_no AS 宸ュ彿, name AS 濮撳悕, hire_date AS 鍏ヨ亴鏃ユ湡 FROM hrm_employee WHERE deleted = 0 ORDER BY hire_date DESC LIMIT 10', '{"h":8,"w":12,"x":0,"y":12}', NULL, '0', '7', '1', '1', '2026-08-05 07:11:07', '1', '2026-08-05 07:11:07', X'00');
+
+-- ============ 琛細bi_data_source_config锛堝鍑� 0 琛岋級 ============
+DROP TABLE IF EXISTS `bi_data_source_config`;
+CREATE TABLE `bi_data_source_config` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鏁版嵁婧愬悕绉�',
+ `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'mysql' COMMENT '绫诲瀷锛歮ysql/api',
+ `config` json DEFAULT NULL COMMENT '杩炴帴閰嶇疆',
+ `status` tinyint NOT NULL DEFAULT '1' COMMENT '鐘舵�侊細0-绂佺敤 1-鍚敤',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='BI鏁版嵁婧愰厤缃〃';
+
+-- ============ 琛細bi_warehouse_coordinate锛堝鍑� 1 琛岋級 ============
+DROP TABLE IF EXISTS `bi_warehouse_coordinate`;
+CREATE TABLE `bi_warehouse_coordinate` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '浠撳簱鍚嶇О',
+ `longitude` decimal(10,6) NOT NULL COMMENT '缁忓害',
+ `latitude` decimal(10,6) NOT NULL COMMENT '绾害',
+ `sort` int NOT NULL DEFAULT '0' COMMENT '鎺掑簭',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='BI浠撳簱鍧愭爣閰嶇疆琛�';
+INSERT INTO `bi_warehouse_coordinate` (`id`, `name`, `longitude`, `latitude`, `sort`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES
+('1', '铏氭嫙绾胯竟浠撳簱', '110.313100', '32.344400', '1', '1', '2026-08-31 16:06:11', '1', '2026-08-31 16:06:11', X'00');
+
+-- ============ 琛細report_go_view_project锛堝鍑� 0 琛岋級 ============
+DROP TABLE IF EXISTS `report_go_view_project`;
+CREATE TABLE `report_go_view_project` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '椤圭洰鍚嶇О',
+ `pic_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '棰勮鍥剧墖 URL',
+ `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鎶ヨ〃鍐呭锛圝SON 閰嶇疆锛�',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鍙戝竷鐘舵�侊細0-宸插彂甯冿紝1-鏈彂甯�',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '椤圭洰澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='GoView 椤圭洰琛�';
+
+-- ***********************************************************************
+-- 鈶� MES 缂栫爜瑙勫垯锛堝墧娴佹按璁板綍锛夛紙DDL + 鏁版嵁锛�
+-- ***********************************************************************
+
+-- ============ 琛細mes_md_auto_code_rule锛堝鍑� 52 琛岋級 ============
+DROP TABLE IF EXISTS `mes_md_auto_code_rule`;
+CREATE TABLE `mes_md_auto_code_rule` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瑙勫垯缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瑙勫垯鍚嶇О',
+ `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎻忚堪',
+ `max_length` int DEFAULT NULL COMMENT '鏈�澶ч暱搴�',
+ `padded` bit(1) DEFAULT b'0' COMMENT '鏄惁琛ラ綈',
+ `padded_char` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '琛ラ綈瀛楃',
+ `padded_method` int DEFAULT NULL COMMENT '琛ラ綈鏂瑰紡',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=71 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 缂栫爜瑙勫垯';
+INSERT INTO `mes_md_auto_code_rule` (`id`, `code`, `name`, `description`, `max_length`, `padded`, `padded_char`, `padded_method`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES
+('1', 'MD_ITEM_TYPE_CODE', '鐗╂枡鍒嗙被缂栫爜', '鐗╂枡鍒嗙被鑷姩缂栫爜', '6', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('2', 'MD_ITEM_CODE', '鐗╂枡缂栫爜', '鐗╂枡鑷姩缂栫爜', '16', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '103', '2026-07-16 16:17:45', X'00'),
+('3', 'MD_VENDOR_CODE', '渚涘簲鍟嗙紪鐮�', '渚涘簲鍟嗚嚜鍔ㄧ紪鐮�', '15', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('4', 'MD_CLIENT_CODE', '瀹㈡埛缂栫爜', '瀹㈡埛鑷姩缂栫爜', '15', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('5', 'MD_WORKSTATION_CODE', '宸ヤ綔绔欑紪鐮�', '宸ヤ綔绔欒嚜鍔ㄧ紪鐮�', '6', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('6', 'MD_WORKSHOP_CODE', '杞﹂棿缂栫爜', '杞﹂棿鑷姩缂栫爜', '6', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('7', 'TM_TOOL_TYPE_CODE', '宸ュ叿绫诲瀷缂栫爜', '宸ュ叿绫诲瀷鑷姩缂栫爜', '6', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('10', 'WM_WAREHOUSE_CODE', '浠撳簱缂栫爜', '浠撳簱鑷姩缂栫爜', '6', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('11', 'WM_LOCATION_CODE', '搴撳尯缂栫爜', '搴撳尯鑷姩缂栫爜', '6', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('12', 'WM_AREA_CODE', '搴撲綅缂栫爜', '搴撲綅鑷姩缂栫爜', '6', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('13', 'WM_ARRIVAL_NOTICE_CODE', '鍒拌揣閫氱煡鍗曠紪鐮�', '鍒拌揣閫氱煡鍗曡嚜鍔ㄧ紪鐮�', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('14', 'WM_ITEM_RECEIPT_CODE', '閲囪喘鍏ュ簱鍗曠紪鐮�', '閲囪喘鍏ュ簱鍗曡嚜鍔ㄧ紪鐮�', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('15', 'WM_RETURN_VENDOR_CODE', '閲囪喘閫�璐у崟缂栫爜', '閲囪喘閫�璐у崟鑷姩缂栫爜', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('16', 'WM_RETURN_ISSUE_CODE', '鐢熶骇閫�鏂欏崟缂栫爜', '鐢熶骇閫�鏂欏崟鑷姩缂栫爜', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('17', 'WM_SN_CODE', 'SN鐮�', 'SN鐮佽嚜鍔ㄧ紪鐮�', '15', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('18', 'WM_PACKAGE_CODE', '瑁呯鍗曠紪鐮�', '瑁呯鍗曡嚜鍔ㄧ紪鐮�', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('19', 'WM_BATCH_CODE', '鎵规缂栫爜', '鎵规鑷姩缂栫爜', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('20', 'WM_PRODUCT_SALES_CODE', '閿�鍞嚭搴撳崟缂栫爜', '閿�鍞嚭搴撳崟鑷姩缂栫爜', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('21', 'WM_MISC_RECEIPT_CODE', '鏉傞」鍏ュ簱鍗曠紪鐮�', '鏉傞」鍏ュ簱鍗曡嚜鍔ㄧ紪鐮�', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('22', 'WM_MISC_ISSUE_CODE', '鏉傞」鍑哄簱鍗曠紪鐮�', '鏉傞」鍑哄簱鍗曡嚜鍔ㄧ紪鐮�', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('23', 'WM_STOCK_TAKING_PLAN_CODE', '鐩樼偣鏂规缂栫爜', '鐩樼偣鏂规鑷姩缂栫爜', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('24', 'WM_STOCK_TAKING_CODE', '鐩樼偣浠诲姟缂栫爜', '鐩樼偣浠诲姟鑷姩缂栫爜', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('25', 'TRANSFER_CODE', '杞Щ璋冩嫧鍗曠紪鐮�', '杞Щ璋冩嫧鍗曡嚜鍔ㄧ紪鐮�', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('26', 'WM_OUTSOURCE_ISSUE_CODE', '澶栧崗鍙戞枡鍗曠紪鐮�', '澶栧崗鍙戞枡鍗曡嚜鍔ㄧ紪鐮�', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('27', 'WM_OUTSOURCE_RECEIPT_CODE', '澶栧崗鍏ュ簱鍗曠紪鐮�', '澶栧崗鍏ュ簱鍗曡嚜鍔ㄧ紪鐮�', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('28', 'WM_SALES_NOTICE_CODE', '鍙戣揣閫氱煡鍗曠紪鐮�', '鍙戣揣閫氱煡鍗曡嚜鍔ㄧ紪鐮�', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('29', 'WM_RETURN_SALES_CODE', '閿�鍞��璐у崟缂栫爜', '閿�鍞��璐у崟鑷姩缂栫爜', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('30', 'PRO_WORK_ORDER_CODE', '鐢熶骇宸ュ崟缂栫爜', '鐢熶骇宸ュ崟鑷姩缂栫爜', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('31', 'PRO_TASK_CODE', '鐢熶骇浠诲姟缂栫爜', '鐢熶骇浠诲姟鑷姩缂栫爜', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('32', 'PRO_ROUTE_CODE', '宸ヨ壓璺嚎缂栫爜', '宸ヨ壓璺嚎鑷姩缂栫爜', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('33', 'PRO_FEEDBACK_CODE', '鐢熶骇鎶ュ伐鍗曠紪鐮�', '鐢熶骇鎶ュ伐鍗曡嚜鍔ㄧ紪鐮�', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('40', 'QC_IQC_CODE', '鏉ユ枡妫�楠屽崟缂栫爜', '鏉ユ枡妫�楠屽崟鑷姩缂栫爜', '15', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('41', 'QC_IPQC_CODE', '杩囩▼妫�楠屽崟缂栫爜', '杩囩▼妫�楠屽崟鑷姩缂栫爜', '16', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('42', 'QC_OQC_CODE', '鍑鸿揣妫�楠屽崟缂栫爜', '鍑鸿揣妫�楠屽崟鑷姩缂栫爜', '15', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('43', 'QC_RQC_CODE', '閫�璐ф楠屽崟缂栫爜', '閫�璐ф楠屽崟鑷姩缂栫爜', '15', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('44', 'QC_DEFECT_CODE', '缂洪櫡绫诲瀷缂栫爜', '缂洪櫡绫诲瀷鑷姩缂栫爜', '6', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('45', 'QC_INDICATOR_RESULT_CODE', '鏍峰搧妫�楠岀粨鏋滅紪鐮�', '鏍峰搧妫�楠岀粨鏋滆嚜鍔ㄧ紪鐮�', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('50', 'DV_MACHINERY_CODE', '璁惧缂栫爜', '璁惧鑷姩缂栫爜', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('51', 'DV_MACHINERY_TYPE_CODE', '璁惧绫诲瀷缂栫爜', '璁惧绫诲瀷鑷姩缂栫爜', '6', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('52', 'DV_SUBJECT_CODE', '鐐规淇濆吇椤圭洰缂栫爜', '鐐规淇濆吇椤圭洰鑷姩缂栫爜', '6', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('53', 'DV_REPAIR_CODE', '缁翠慨鍗曠紪鐮�', '缁翠慨鍗曡嚜鍔ㄧ紪鐮�', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('60', 'PD_DOCUMENT_AUDIT_CODE', '璧勬枡瀹℃牳鍗曠紪鐮�', '璧勬枡瀹℃牳鍗曡嚜鍔ㄧ紪鐮�', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('61', 'PD_ARCHIVE_CODE', '褰掓。鍙拌处缂栫爜', '褰掓。鍙拌处鑷姩缂栫爜', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('62', 'PD_PROCESS_PARAM_CODE', '宸ヨ壓鍙傛暟缂栫爜', '宸ヨ壓鍙傛暟鑷姩缂栫爜', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:15:29', X'00'),
+('63', 'PD_PROCESS_PARAM_TEMPLATE_CODE', '宸ヨ壓鍙傛暟妯℃澘缂栫爜', '宸ヨ壓鍙傛暟妯℃澘鑷姩缂栫爜', '14', X'01', '0', '1', '0', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 16:06:38', X'00'),
+('64', 'WM_PRODUCT_ISSUE_CODE', '棰嗘枡鍗�', NULL, '15', X'01', '0', '1', '0', NULL, '103', '2026-07-16 16:58:14', '103', '2026-07-16 16:59:03', X'00'),
+('65', 'MPS', '鐢熶骇涓昏鍒掔紪鐮�', '鐢熶骇涓昏鍒掕嚜鍔ㄧ紪鐮�', '14', X'01', '0', '1', '0', '', '1', '2026-07-17 05:17:30', '1', '2026-07-17 05:17:30', X'00'),
+('66', 'QC_INDICATOR_CODE', '璐ㄦ鎸囨爣缂栫爜', NULL, '12', X'01', '0', '1', '0', NULL, '1', '2026-07-17 14:31:46', '1', '2026-07-17 14:32:23', X'00'),
+('67', 'QC_TEMPLATE_CODE', '璐ㄦ鏂规缂栫爜', NULL, '11', X'01', '0', '1', '0', NULL, '1', '2026-07-17 14:36:35', '1', '2026-07-17 14:37:05', X'00'),
+('68', 'SALESNOTICE_CODE', '閿�鍞�氱煡缂栫爜', '閿�鍞�氱煡鑷姩缂栫爜', '20', X'01', '0', '1', '0', '', 'admin', '2026-07-17 07:36:53', 'admin', '2026-07-17 07:36:53', X'00'),
+('69', 'CAL_TEAM_CODE', '鐝粍缂栫爜瑙勫垯', '鐝粍缂栫爜瑙勫垯', '10', X'01', '0', '1', '0', NULL, '1', '2026-07-31 09:57:04', '1', '2026-07-31 09:57:36', X'00'),
+('70', 'CAL_PLAN_CODE', '鎺掔彮璁″垝', NULL, '14', X'01', '0', '1', '0', NULL, '1', '2026-07-31 09:59:32', '1', '2026-07-31 10:00:17', X'00');
+
+-- ============ 琛細mes_md_auto_code_part锛堝鍑� 145 琛岋級 ============
+DROP TABLE IF EXISTS `mes_md_auto_code_part`;
+CREATE TABLE `mes_md_auto_code_part` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `rule_id` bigint DEFAULT NULL COMMENT '瑙勫垯缂栧彿',
+ `sort` int DEFAULT NULL COMMENT '鍒嗘搴忓彿',
+ `type` int DEFAULT NULL COMMENT '鍒嗘绫诲瀷',
+ `length` int DEFAULT NULL COMMENT '鍒嗘闀垮害',
+ `date_format` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏃ユ湡鏍煎紡',
+ `fix_character` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍥哄畾瀛楃',
+ `serial_start_no` int DEFAULT NULL COMMENT '娴佹按鍙疯捣濮嬪��',
+ `serial_step` int DEFAULT NULL COMMENT '娴佹按鍙锋闀�',
+ `cycle_flag` bit(1) DEFAULT b'0' COMMENT '娴佹按鍙锋槸鍚﹀惊鐜�',
+ `cycle_method` int DEFAULT NULL COMMENT '寰幆鏂瑰紡',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=478 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 缂栫爜瑙勫垯缁勬垚';
+INSERT INTO `mes_md_auto_code_part` (`id`, `rule_id`, `sort`, `type`, `length`, `date_format`, `fix_character`, `serial_start_no`, `serial_step`, `cycle_flag`, `cycle_method`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES
+('333', '1', '1', '3', '3', NULL, 'IT_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('334', '1', '2', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('335', '2', '1', '3', '5', NULL, 'ITEM_', NULL, NULL, X'00', NULL, NULL, '1', '2026-07-16 08:06:12', '103', '2026-07-16 16:17:41', X'00'),
+('336', '2', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('337', '2', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('338', '3', '1', '3', '4', NULL, 'VND_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('339', '3', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('340', '3', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('341', '4', '1', '3', '4', NULL, 'CLT_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('342', '4', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('343', '4', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('344', '5', '1', '3', '3', NULL, 'WS_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('345', '5', '2', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('346', '6', '1', '3', '3', NULL, 'WP_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('347', '6', '2', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('348', '7', '1', '3', '3', NULL, 'TL_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('349', '7', '2', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('350', '10', '1', '3', '3', NULL, 'WH_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('351', '10', '2', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('352', '11', '1', '3', '3', NULL, 'LC_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('353', '11', '2', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('354', '12', '1', '3', '3', NULL, 'AR_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('355', '12', '2', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('356', '13', '1', '3', '3', NULL, 'AN_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('357', '13', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('358', '13', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('359', '14', '1', '3', '3', NULL, 'IR_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('360', '14', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('361', '14', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('362', '15', '1', '3', '3', NULL, 'RV_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('363', '15', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('364', '15', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('365', '16', '1', '3', '3', NULL, 'RI_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('366', '16', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('367', '16', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('368', '17', '1', '3', '3', NULL, 'SN_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('369', '17', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('370', '17', '3', '4', '4', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('371', '18', '1', '3', '3', NULL, 'PK_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('372', '18', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('373', '18', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('374', '19', '1', '3', '3', NULL, 'BT_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('375', '19', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('376', '19', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('377', '20', '1', '3', '3', NULL, 'SL_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('378', '20', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('379', '20', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('380', '21', '1', '3', '3', NULL, 'MI_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('381', '21', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('382', '21', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('383', '22', '1', '3', '3', NULL, 'MO_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('384', '22', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('385', '22', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('386', '23', '1', '3', '3', NULL, 'SP_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('387', '23', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('388', '23', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('389', '24', '1', '3', '3', NULL, 'ST_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('390', '24', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('391', '24', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('392', '25', '1', '3', '3', NULL, 'TF_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('393', '25', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('394', '25', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('395', '26', '1', '3', '3', NULL, 'OI_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('396', '26', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('397', '26', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('398', '27', '1', '3', '3', NULL, 'OR_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('399', '27', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('400', '27', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('401', '28', '1', '3', '3', NULL, 'SN_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('402', '28', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('403', '28', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('404', '29', '1', '3', '3', NULL, 'RS_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('405', '29', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('406', '29', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('407', '30', '1', '3', '3', NULL, 'WO_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('408', '30', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('409', '30', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('410', '31', '1', '3', '3', NULL, 'TK_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('411', '31', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('412', '31', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('413', '32', '1', '3', '3', NULL, 'RT_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('414', '32', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('415', '32', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('416', '33', '1', '3', '3', NULL, 'FB_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('417', '33', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('418', '33', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('419', '40', '1', '3', '4', NULL, 'IQC_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('420', '40', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('421', '40', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('422', '41', '1', '3', '5', NULL, 'IPQC_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('423', '41', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('424', '41', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('425', '42', '1', '3', '4', NULL, 'OQC_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('426', '42', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('427', '42', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('428', '43', '1', '3', '4', NULL, 'RQC_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('429', '43', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('430', '43', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('431', '44', '1', '3', '3', NULL, 'DF_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('432', '44', '2', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('433', '45', '1', '3', '3', NULL, 'IR_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('434', '45', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('435', '45', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('436', '50', '1', '3', '3', NULL, 'MC_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('437', '50', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('438', '50', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('439', '51', '1', '3', '3', NULL, 'MT_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('440', '51', '2', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('441', '52', '1', '3', '3', NULL, 'SJ_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('442', '52', '2', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('443', '53', '1', '3', '3', NULL, 'RP_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('444', '53', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('445', '53', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('446', '60', '1', '3', '3', NULL, 'DA_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('447', '60', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('448', '60', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('449', '61', '1', '3', '3', NULL, 'AC_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('450', '61', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('451', '61', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('452', '62', '1', '3', '3', NULL, 'PP_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('453', '62', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('454', '62', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('455', '63', '1', '3', '3', NULL, 'PT_', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('456', '63', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('457', '63', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-16 08:06:12', '1', '2026-07-16 08:06:12', X'00'),
+('458', '64', '1', '3', '3', NULL, 'LWL', NULL, NULL, X'00', NULL, NULL, '103', '2026-07-16 16:58:38', '103', '2026-07-16 16:58:38', X'00'),
+('459', '64', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, X'00', NULL, NULL, '103', '2026-07-16 16:58:48', '103', '2026-07-16 16:58:48', X'00'),
+('460', '64', '3', '4', '4', NULL, NULL, '1', '1', X'01', '3', NULL, '103', '2026-07-16 16:58:57', '103', '2026-07-16 16:58:57', X'00'),
+('461', '65', '1', '3', '3', NULL, 'MPS', NULL, NULL, NULL, NULL, NULL, '1', '2026-07-17 05:18:27', '1', '2026-07-17 05:18:27', X'00'),
+('462', '65', '2', '2', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, '1', '2026-07-17 05:18:27', '1', '2026-07-17 05:18:27', X'00'),
+('463', '65', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, '1', '2026-07-17 05:18:27', '1', '2026-07-17 05:18:27', X'00'),
+('464', '66', '1', '3', '4', NULL, 'IND_', NULL, NULL, X'00', NULL, NULL, '1', '2026-07-17 14:31:57', '1', '2026-07-17 14:31:57', X'00'),
+('465', '66', '2', '3', '4', NULL, 'CAR_', NULL, NULL, X'00', NULL, NULL, '1', '2026-07-17 14:32:07', '1', '2026-07-17 14:32:07', X'00'),
+('466', '66', '3', '4', '4', NULL, NULL, '5', '1', X'00', NULL, NULL, '1', '2026-07-17 14:32:22', '1', '2026-07-17 14:32:22', X'00'),
+('467', '67', '1', '3', '3', NULL, 'QC_', NULL, NULL, X'00', NULL, NULL, '1', '2026-07-17 14:36:45', '1', '2026-07-17 14:36:45', X'00'),
+('468', '67', '2', '3', '4', NULL, 'CAR_', NULL, NULL, X'00', NULL, NULL, '1', '2026-07-17 14:36:54', '1', '2026-07-17 14:36:54', X'00'),
+('469', '67', '3', '4', '4', NULL, NULL, '2', '1', X'00', NULL, NULL, '1', '2026-07-17 14:37:04', '1', '2026-07-17 14:37:04', X'00'),
+('470', '68', '1', '3', '3', NULL, 'XSTZ', NULL, NULL, NULL, NULL, NULL, 'admin', '2026-07-17 07:37:20', 'admin', '2026-07-17 07:37:20', X'00'),
+('471', '68', '2', '1', '8', 'yyyyMMdd', NULL, NULL, NULL, NULL, NULL, NULL, 'admin', '2026-07-17 07:37:20', 'admin', '2026-07-17 07:37:20', X'00'),
+('472', '68', '3', '4', '3', NULL, NULL, '1', '1', X'01', '3', NULL, 'admin', '2026-07-17 07:37:20', 'admin', '2026-07-17 07:37:20', X'00'),
+('473', '69', '1', '3', '5', NULL, 'TEAM_', NULL, NULL, X'00', NULL, NULL, '1', '2026-07-31 09:57:21', '1', '2026-07-31 09:57:21', X'00'),
+('474', '69', '2', '4', '5', NULL, NULL, '1', '1', X'00', NULL, NULL, '1', '2026-07-31 09:57:31', '1', '2026-07-31 09:57:31', X'00'),
+('475', '70', '1', '3', '3', NULL, 'PB_', NULL, NULL, X'00', NULL, NULL, '1', '2026-07-31 09:59:47', '1', '2026-07-31 09:59:47', X'00'),
+('476', '70', '2', '2', '6', 'yyyyMM', NULL, NULL, NULL, X'00', NULL, NULL, '1', '2026-07-31 10:00:03', '1', '2026-07-31 10:00:03', X'00'),
+('477', '70', '3', '4', '5', NULL, NULL, '1', '1', X'01', '2', NULL, '1', '2026-07-31 10:00:13', '1', '2026-07-31 10:00:13', X'00');
+
+-- ***********************************************************************
+-- 鈶� 绯荤粺閰嶇疆涓绘暟鎹紙瀛楀吀/绉熸埛/鍏徃閰嶇疆锛涘墧韬唤/鑿滃崟/鏃ュ織锛夛紙DDL + 鏁版嵁锛�
+-- ***********************************************************************
+
+-- ============ 琛細system_dict_type锛堝鍑� 241 琛岋級 ============
+DROP TABLE IF EXISTS `system_dict_type`;
+CREATE TABLE `system_dict_type` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '瀛楀吀涓婚敭',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '瀛楀吀鍚嶇О',
+ `type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '瀛楀吀绫诲瀷',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `deleted_time` datetime DEFAULT NULL COMMENT '鍒犻櫎鏃堕棿',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=1065306 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='瀛楀吀绫诲瀷琛�';
+INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES
+('1', '鐢ㄦ埛鎬у埆', 'system_user_sex', '0', NULL, 'admin', '2021-01-05 17:03:48', '1', '2022-05-16 20:29:32', X'00', NULL),
+('6', '鍙傛暟绫诲瀷', 'infra_config_type', '0', NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:36:54', X'00', NULL),
+('7', '閫氱煡绫诲瀷', 'system_notice_type', '0', NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:35:26', X'00', NULL),
+('9', '鎿嶄綔绫诲瀷', 'infra_operate_type', '0', NULL, 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:01', X'00', NULL),
+('10', '绯荤粺鐘舵��', 'common_status', '0', NULL, 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:21:28', X'00', NULL),
+('11', 'Boolean 鏄惁绫诲瀷', 'infra_boolean_string', '0', 'boolean 杞槸鍚�', '', '2021-01-19 03:20:08', '', '2022-02-01 16:37:10', X'00', NULL),
+('104', '鐧婚檰缁撴灉', 'system_login_result', '0', '鐧婚檰缁撴灉', '', '2021-01-18 06:17:11', '', '2022-02-01 16:36:00', X'00', NULL),
+('106', '浠g爜鐢熸垚妯℃澘绫诲瀷', 'infra_codegen_template_type', '0', NULL, '', '2021-02-05 07:08:06', '1', '2022-05-16 20:26:50', X'00', NULL),
+('107', '瀹氭椂浠诲姟鐘舵��', 'infra_job_status', '0', NULL, '', '2021-02-07 07:44:16', '', '2022-02-01 16:51:11', X'00', NULL),
+('108', '瀹氭椂浠诲姟鏃ュ織鐘舵��', 'infra_job_log_status', '0', NULL, '', '2021-02-08 10:03:51', '', '2022-02-01 16:50:43', X'00', NULL),
+('109', '鐢ㄦ埛绫诲瀷', 'user_type', '0', NULL, '', '2021-02-26 00:15:51', '', '2021-02-26 00:15:51', X'00', NULL),
+('110', 'API 寮傚父鏁版嵁鐨勫鐞嗙姸鎬�', 'infra_api_error_log_process_status', '0', NULL, '', '2021-02-26 07:07:01', '', '2022-02-01 16:50:53', X'00', NULL),
+('111', '鐭俊娓犻亾缂栫爜', 'system_sms_channel_code', '0', NULL, '1', '2021-04-05 01:04:50', '1', '2022-02-16 02:09:08', X'00', NULL),
+('112', '鐭俊妯℃澘鐨勭被鍨�', 'system_sms_template_type', '0', NULL, '1', '2021-04-05 21:50:43', '1', '2022-02-01 16:35:06', X'00', NULL),
+('113', '鐭俊鍙戦�佺姸鎬�', 'system_sms_send_status', '0', NULL, '1', '2021-04-11 20:18:03', '1', '2022-02-01 16:35:09', X'00', NULL),
+('114', '鐭俊鎺ユ敹鐘舵��', 'system_sms_receive_status', '0', NULL, '1', '2021-04-11 20:27:14', '1', '2022-02-01 16:35:14', X'00', NULL),
+('116', '鐧婚檰鏃ュ織鐨勭被鍨�', 'system_login_type', '0', '鐧婚檰鏃ュ織鐨勭被鍨�', '1', '2021-10-06 00:50:46', '1', '2022-02-01 16:35:56', X'00', NULL),
+('117', 'OA 璇峰亣绫诲瀷', 'bpm_oa_leave_type', '0', NULL, '1', '2021-09-21 22:34:33', '1', '2022-01-22 10:41:37', X'00', NULL),
+('130', '鏀粯娓犻亾缂栫爜绫诲瀷', 'pay_channel_code', '0', '鏀粯娓犻亾鐨勭紪鐮�', '1', '2021-12-03 10:35:08', '1', '2023-07-10 10:11:39', X'00', NULL),
+('131', '鏀粯鍥炶皟鐘舵��', 'pay_notify_status', '0', '鏀粯鍥炶皟鐘舵�侊紙鍖呮嫭閫�娆惧洖璋冿級', '1', '2021-12-03 10:53:29', '1', '2023-07-19 18:09:43', X'00', NULL),
+('132', '鏀粯璁㈠崟鐘舵��', 'pay_order_status', '0', '鏀粯璁㈠崟鐘舵��', '1', '2021-12-03 11:17:50', '1', '2021-12-03 11:17:50', X'00', NULL),
+('134', '閫�娆捐鍗曠姸鎬�', 'pay_refund_status', '0', '閫�娆捐鍗曠姸鎬�', '1', '2021-12-10 16:42:50', '1', '2023-07-19 10:13:17', X'00', NULL),
+('139', '娴佺▼瀹炰緥鐨勭姸鎬�', 'bpm_process_instance_status', '0', '娴佺▼瀹炰緥鐨勭姸鎬�', '1', '2022-01-07 23:46:42', '1', '2022-01-07 23:46:42', X'00', NULL),
+('140', '娴佺▼瀹炰緥鐨勭粨鏋�', 'bpm_task_status', '0', '娴佺▼瀹炰緥鐨勭粨鏋�', '1', '2022-01-07 23:48:10', '1', '2024-03-08 22:42:03', X'00', NULL),
+('141', '娴佺▼鐨勮〃鍗曠被鍨�', 'bpm_model_form_type', '0', '娴佺▼鐨勮〃鍗曠被鍨�', '103', '2022-01-11 23:50:45', '103', '2022-01-11 23:50:45', X'00', NULL),
+('142', '浠诲姟鍒嗛厤瑙勫垯鐨勭被鍨�', 'bpm_task_candidate_strategy', '0', 'BPM 浠诲姟鐨勫�欓�変汉鐨勭瓥鐣�', '103', '2022-01-12 23:21:04', '103', '2024-03-06 02:53:59', X'00', NULL),
+('144', '浠g爜鐢熸垚鐨勫満鏅灇涓�', 'infra_codegen_scene', '0', '浠g爜鐢熸垚鐨勫満鏅灇涓�', '1', '2022-02-02 13:14:45', '1', '2022-03-10 16:33:46', X'00', NULL),
+('145', '瑙掕壊绫诲瀷', 'system_role_type', '0', '瑙掕壊绫诲瀷', '1', '2022-02-16 13:01:46', '1', '2022-02-16 13:01:46', X'00', NULL),
+('146', '鏂囦欢瀛樺偍鍣�', 'infra_file_storage', '0', '鏂囦欢瀛樺偍鍣�', '1', '2022-03-15 00:24:38', '1', '2022-03-15 00:24:38', X'00', NULL),
+('147', 'OAuth 2.0 鎺堟潈绫诲瀷', 'system_oauth2_grant_type', '0', 'OAuth 2.0 鎺堟潈绫诲瀷锛堟ā寮忥級', '1', '2022-05-12 00:20:52', '1', '2022-05-11 16:25:49', X'00', NULL),
+('149', '鍟嗗搧 SPU 鐘舵��', 'product_spu_status', '0', '鍟嗗搧 SPU 鐘舵��', '1', '2022-10-24 21:19:04', '1', '2022-10-24 21:19:08', X'00', NULL),
+('150', '浼樻儬绫诲瀷', 'promotion_discount_type', '0', '浼樻儬绫诲瀷', '1', '2022-11-01 12:46:06', '1', '2022-11-01 12:46:06', X'00', NULL),
+('151', '浼樻儬鍔垫ā鏉跨殑鏈夐檺鏈熺被鍨�', 'promotion_coupon_template_validity_type', '0', '浼樻儬鍔垫ā鏉跨殑鏈夐檺鏈熺被鍨�', '1', '2022-11-02 00:06:20', '1', '2022-11-04 00:08:26', X'00', NULL),
+('152', '钀ラ攢鐨勫晢鍝佽寖鍥�', 'promotion_product_scope', '0', '钀ラ攢鐨勫晢鍝佽寖鍥�', '1', '2022-11-02 00:28:01', '1', '2022-11-02 00:28:01', X'00', NULL),
+('153', '浼樻儬鍔电殑鐘舵��', 'promotion_coupon_status', '0', '浼樻儬鍔电殑鐘舵��', '1', '2022-11-04 00:14:49', '1', '2022-11-04 00:14:49', X'00', NULL),
+('154', '浼樻儬鍔电殑棰嗗彇鏂瑰紡', 'promotion_coupon_take_type', '0', '浼樻儬鍔电殑棰嗗彇鏂瑰紡', '1', '2022-11-04 19:12:27', '1', '2022-11-04 19:12:27', X'00', NULL),
+('155', '淇冮攢娲诲姩鐨勭姸鎬�', 'promotion_activity_status', '0', '淇冮攢娲诲姩鐨勭姸鎬�', '1', '2022-11-04 22:54:23', '1', '2022-11-04 22:54:23', X'00', NULL),
+('156', '钀ラ攢鐨勬潯浠剁被鍨�', 'promotion_condition_type', '0', '钀ラ攢鐨勬潯浠剁被鍨�', '1', '2022-11-04 22:59:23', '1', '2022-11-04 22:59:23', X'00', NULL),
+('157', '浜ゆ槗鍞悗鐘舵��', 'trade_after_sale_status', '0', '浜ゆ槗鍞悗鐘舵��', '1', '2022-11-19 20:52:56', '1', '2022-11-19 20:52:56', X'00', NULL),
+('158', '浜ゆ槗鍞悗鐨勭被鍨�', 'trade_after_sale_type', '0', '浜ゆ槗鍞悗鐨勭被鍨�', '1', '2022-11-19 21:04:09', '1', '2022-11-19 21:04:09', X'00', NULL),
+('159', '浜ゆ槗鍞悗鐨勬柟寮�', 'trade_after_sale_way', '0', '浜ゆ槗鍞悗鐨勬柟寮�', '1', '2022-11-19 21:39:04', '1', '2022-11-19 21:39:04', X'00', NULL),
+('160', '缁堢', 'terminal', '0', '缁堢', '1', '2022-12-10 10:50:50', '1', '2022-12-10 10:53:11', X'00', NULL),
+('161', '浜ゆ槗璁㈠崟鐨勭被鍨�', 'trade_order_type', '0', '浜ゆ槗璁㈠崟鐨勭被鍨�', '1', '2022-12-10 16:33:54', '1', '2022-12-10 16:33:54', X'00', NULL),
+('162', '浜ゆ槗璁㈠崟鐨勭姸鎬�', 'trade_order_status', '0', '浜ゆ槗璁㈠崟鐨勭姸鎬�', '1', '2022-12-10 16:48:44', '1', '2022-12-10 16:48:44', X'00', NULL),
+('163', '浜ゆ槗璁㈠崟椤圭殑鍞悗鐘舵��', 'trade_order_item_after_sale_status', '0', '浜ゆ槗璁㈠崟椤圭殑鍞悗鐘舵��', '1', '2022-12-10 20:58:08', '1', '2022-12-10 20:58:08', X'00', NULL),
+('164', '鍏紬鍙疯嚜鍔ㄥ洖澶嶇殑璇锋眰鍏抽敭瀛楀尮閰嶆ā寮�', 'mp_auto_reply_request_match', '0', '鍏紬鍙疯嚜鍔ㄥ洖澶嶇殑璇锋眰鍏抽敭瀛楀尮閰嶆ā寮�', '1', '2023-01-16 23:29:56', '1', '2023-01-16 23:29:56', X'00', '1970-01-01 00:00:00'),
+('165', '鍏紬鍙风殑娑堟伅绫诲瀷', 'mp_message_type', '0', '鍏紬鍙风殑娑堟伅绫诲瀷', '1', '2023-01-17 22:17:09', '1', '2023-01-17 22:17:09', X'00', '1970-01-01 00:00:00'),
+('166', '閭欢鍙戦�佺姸鎬�', 'system_mail_send_status', '0', '閭欢鍙戦�佺姸鎬�', '1', '2023-01-26 09:53:13', '1', '2023-01-26 09:53:13', X'00', '1970-01-01 00:00:00'),
+('167', '绔欏唴淇℃ā鐗堢殑绫诲瀷', 'system_notify_template_type', '0', '绔欏唴淇℃ā鐗堢殑绫诲瀷', '1', '2023-01-28 10:35:10', '1', '2023-01-28 10:35:10', X'00', '1970-01-01 00:00:00'),
+('168', '浠g爜鐢熸垚鐨勫墠绔被鍨�', 'infra_codegen_front_type', '0', '', '1', '2023-04-12 23:57:52', '1', '2023-04-12 23:57:52', X'00', '1970-01-01 00:00:00'),
+('170', '蹇�掕璐规柟寮�', 'trade_delivery_express_charge_mode', '0', '鐢ㄤ簬鍟嗗煄浜ゆ槗妯″潡閰嶉�佺鐞�', '1', '2023-05-21 22:45:03', '1', '2023-05-21 22:45:03', X'00', '1970-01-01 00:00:00'),
+('171', '绉垎涓氬姟绫诲瀷', 'member_point_biz_type', '0', '', '1', '2023-06-10 12:15:00', '1', '2023-06-28 13:48:20', X'00', '1970-01-01 00:00:00'),
+('173', '鏀粯閫氱煡绫诲瀷', 'pay_notify_type', '0', NULL, '1', '2023-07-20 12:23:03', '1', '2023-07-20 12:23:03', X'00', '1970-01-01 00:00:00'),
+('174', '浼氬憳缁忛獙涓氬姟绫诲瀷', 'member_experience_biz_type', '0', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', X'00', NULL),
+('175', '浜ゆ槗閰嶉�佺被鍨�', 'trade_delivery_type', '0', '', '1', '2023-08-23 00:03:14', '1', '2023-08-23 00:03:14', X'00', '1970-01-01 00:00:00'),
+('176', '鍒嗕剑妯″紡', 'brokerage_enabled_condition', '0', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00', NULL),
+('177', '鍒嗛攢鍏崇郴缁戝畾妯″紡', 'brokerage_bind_mode', '0', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00', NULL),
+('178', '浣i噾鎻愮幇绫诲瀷', 'brokerage_withdraw_type', '0', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00', NULL),
+('179', '浣i噾璁板綍涓氬姟绫诲瀷', 'brokerage_record_biz_type', '0', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00', NULL),
+('180', '浣i噾璁板綍鐘舵��', 'brokerage_record_status', '0', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00', NULL),
+('181', '浣i噾鎻愮幇鐘舵��', 'brokerage_withdraw_status', '0', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00', NULL),
+('182', '浣i噾鎻愮幇閾惰', 'brokerage_bank_name', '0', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00', NULL),
+('183', '鐮嶄环璁板綍鐨勭姸鎬�', 'promotion_bargain_record_status', '0', '', '1', '2023-10-05 10:41:08', '1', '2023-10-05 10:41:08', X'00', '1970-01-01 00:00:00'),
+('184', '鎷煎洟璁板綍鐨勭姸鎬�', 'promotion_combination_record_status', '0', '', '1', '2023-10-08 07:24:25', '1', '2023-10-08 07:24:25', X'00', '1970-01-01 00:00:00'),
+('185', '鍥炴-鍥炴鏂瑰紡', 'crm_receivable_return_type', '0', '鍥炴-鍥炴鏂瑰紡', '1', '2023-10-18 21:54:10', '1', '2023-10-18 21:54:10', X'00', '1970-01-01 00:00:00'),
+('186', 'CRM 瀹㈡埛琛屼笟', 'crm_customer_industry', '0', 'CRM 瀹㈡埛鎵�灞炶涓�', '1', '2023-10-28 22:57:07', '1', '2024-02-18 23:30:22', X'00', NULL),
+('187', '瀹㈡埛绛夌骇', 'crm_customer_level', '0', 'CRM 瀹㈡埛绛夌骇', '1', '2023-10-28 22:59:12', '1', '2023-10-28 15:11:16', X'00', NULL),
+('188', '瀹㈡埛鏉ユ簮', 'crm_customer_source', '0', 'CRM 瀹㈡埛鏉ユ簮', '1', '2023-10-28 23:00:34', '1', '2023-10-28 15:11:16', X'00', NULL),
+('600', 'Banner 浣嶇疆', 'promotion_banner_position', '0', '', '1', '2023-10-08 07:24:25', '1', '2023-11-04 13:04:02', X'00', '1970-01-01 00:00:00'),
+('601', '绀句氦绫诲瀷', 'system_social_type', '0', '', '1', '2023-11-04 13:03:54', '1', '2023-11-04 13:03:54', X'00', '1970-01-01 00:00:00'),
+('604', '浜у搧鐘舵��', 'crm_product_status', '0', '', '1', '2023-10-30 21:47:59', '1', '2023-10-30 21:48:45', X'00', '1970-01-01 00:00:00'),
+('605', 'CRM 鏁版嵁鏉冮檺鐨勭骇鍒�', 'crm_permission_level', '0', '', '1', '2023-11-30 09:51:59', '1', '2023-11-30 09:51:59', X'00', '1970-01-01 00:00:00'),
+('606', 'CRM 瀹℃壒鐘舵��', 'crm_audit_status', '0', '', '1', '2023-11-30 18:56:23', '1', '2023-11-30 18:56:23', X'00', '1970-01-01 00:00:00'),
+('607', 'CRM 浜у搧鍗曚綅', 'crm_product_unit', '0', '', '1', '2023-12-05 23:01:51', '1', '2023-12-05 23:01:51', X'00', '1970-01-01 00:00:00'),
+('608', 'CRM 璺熻繘鏂瑰紡', 'crm_follow_up_type', '0', '', '1', '2024-01-15 20:48:05', '1', '2024-01-15 20:48:05', X'00', '1970-01-01 00:00:00'),
+('610', '杞处璁㈠崟鐘舵��', 'pay_transfer_status', '0', '', '1', '2023-10-28 16:18:32', '1', '2023-10-28 16:18:32', X'00', '1970-01-01 00:00:00'),
+('611', 'ERP 搴撳瓨鏄庣粏鐨勪笟鍔$被鍨�', 'erp_stock_record_biz_type', '0', 'ERP 搴撳瓨鏄庣粏鐨勪笟鍔$被鍨�', '1', '2024-02-05 18:07:02', '1', '2024-02-05 18:07:02', X'00', '1970-01-01 00:00:00'),
+('612', 'ERP 瀹℃壒鐘舵��', 'erp_audit_status', '0', '', '1', '2024-02-06 00:00:07', '1', '2024-02-06 00:00:07', X'00', '1970-01-01 00:00:00'),
+('613', 'BPM 鐩戝惉鍣ㄧ被鍨�', 'bpm_process_listener_type', '0', '', '1', '2024-03-23 12:52:24', '1', '2024-03-09 15:54:28', X'00', '1970-01-01 00:00:00'),
+('615', 'BPM 鐩戝惉鍣ㄥ�肩被鍨�', 'bpm_process_listener_value_type', '0', '', '1', '2024-03-23 13:00:31', '1', '2024-03-23 13:00:31', X'00', '1970-01-01 00:00:00'),
+('616', '鏃堕棿闂撮殧', 'date_interval', '0', '', '1', '2024-03-29 22:50:09', '1', '2024-03-29 22:50:09', X'00', '1970-01-01 00:00:00'),
+('619', 'CRM 鍟嗘満缁撴潫鐘舵�佺被鍨�', 'crm_business_end_status_type', '0', '', '1', '2024-04-13 23:23:00', '1', '2024-04-13 23:23:00', X'00', '1970-01-01 00:00:00'),
+('620', 'AI 妯″瀷骞冲彴', 'ai_platform', '0', '', '1', '2024-05-09 22:27:38', '1', '2024-05-09 22:27:38', X'00', '1970-01-01 00:00:00'),
+('621', 'AI 缁樼敾鐘舵��', 'ai_image_status', '0', '', '1', '2024-06-26 20:51:23', '1', '2024-06-26 20:51:23', X'00', '1970-01-01 00:00:00'),
+('622', 'AI 闊充箰鐘舵��', 'ai_music_status', '0', '', '1', '2024-06-27 22:45:07', '1', '2024-06-28 00:56:27', X'00', '1970-01-01 00:00:00'),
+('623', 'AI 闊充箰鐢熸垚妯″紡', 'ai_generate_mode', '0', '', '1', '2024-06-27 22:46:21', '1', '2024-06-28 01:22:29', X'00', '1970-01-01 00:00:00'),
+('624', '鍐欎綔璇皵', 'ai_write_tone', '0', '', '1', '2024-07-07 15:19:02', '1', '2024-07-07 15:19:02', X'00', '1970-01-01 00:00:00'),
+('625', '鍐欎綔璇█', 'ai_write_language', '0', '', '1', '2024-07-07 15:18:52', '1', '2024-07-07 15:18:52', X'00', '1970-01-01 00:00:00'),
+('626', '鍐欎綔闀垮害', 'ai_write_length', '0', '', '1', '2024-07-07 15:18:41', '1', '2024-07-07 15:18:41', X'00', '1970-01-01 00:00:00'),
+('627', '鍐欎綔鏍煎紡', 'ai_write_format', '0', '', '1', '2024-07-07 15:14:34', '1', '2024-07-07 15:14:34', X'00', '1970-01-01 00:00:00'),
+('628', 'AI 鍐欎綔绫诲瀷', 'ai_write_type', '0', '', '1', '2024-07-10 21:25:29', '1', '2024-07-10 21:25:29', X'00', '1970-01-01 00:00:00'),
+('629', 'BPM 娴佺▼妯″瀷绫诲瀷', 'bpm_model_type', '0', '', '1', '2024-08-26 15:21:43', '1', '2024-08-26 15:21:43', X'00', '1970-01-01 00:00:00'),
+('640', 'AI 妯″瀷绫诲瀷', 'ai_model_type', '0', '', '1', '2025-03-03 12:24:07', '1', '2025-03-03 12:24:07', X'00', '1970-01-01 00:00:00'),
+('1001', 'IoT 浜у搧璁惧绫诲瀷', 'iot_product_device_type', '0', '', '1', '2024-08-10 11:54:30', '1', '2025-03-17 09:25:08', X'00', '1970-01-01 00:00:00'),
+('1002', 'IoT 浜у搧鐘舵��', 'iot_product_status', '0', '', '1', '2024-08-10 12:06:09', '1', '2025-03-17 09:25:10', X'00', '1970-01-01 00:00:00'),
+('1004', 'IoT 鑱旂綉鏂瑰紡', 'iot_net_type', '0', '', '1', '2024-09-06 22:04:13', '1', '2025-03-17 09:25:14', X'00', '1970-01-01 00:00:00'),
+('1006', 'IoT 璁惧鐘舵��', 'iot_device_state', '0', '', '1', '2024-09-21 08:12:55', '1', '2025-03-17 09:25:19', X'00', '1970-01-01 00:00:00'),
+('1007', 'IoT 鐗╂ā鍨嬪姛鑳界被鍨�', 'iot_thing_model_type', '0', '', '1', '2024-09-29 20:02:36', '1', '2025-03-17 09:25:24', X'00', '1970-01-01 00:00:00'),
+('1011', 'IoT 鐗╂ā鍨嬪崟浣�', 'iot_thing_model_unit', '0', '', '1', '2024-12-25 17:36:46', '1', '2025-03-17 09:25:35', X'00', '1970-01-01 00:00:00'),
+('1013', 'IoT 鏁版嵁娴佽浆鐩殑鐨勭被鍨嬫灇涓�', 'iot_data_sink_type_enum', '0', '', '1', '2025-03-09 12:39:36', '1', '2025-06-24 12:45:24', X'00', '1970-01-01 00:00:00'),
+('1014', 'IoT 鍦烘櫙娴佽浆鐨勮Е鍙戠被鍨嬫灇涓�', 'iot_rule_scene_trigger_type_enum', '0', '', '1', '2025-03-20 14:59:44', '1', '2025-03-20 14:59:44', X'00', '1970-01-01 00:00:00'),
+('1015', 'IoT 璁惧娑堟伅绫诲瀷鏋氫妇', 'iot_device_message_type_enum', '0', '', '1', '2025-03-20 15:01:15', '1', '2025-03-20 15:01:15', X'00', '1970-01-01 00:00:00'),
+('1016', 'IoT 瑙勫垯鍦烘櫙鐨勮Е鍙戠被鍨嬫灇涓�', 'iot_rule_scene_action_type_enum', '0', '', '1', '2025-03-28 15:26:54', '1', '2025-03-28 15:29:13', X'00', '1970-01-01 00:00:00'),
+('1017', 'MES 鐗╂枡娑堣�楄褰曠姸鎬�', 'mes_wm_item_consume_status', '0', 'MES 鐗╂枡娑堣�楄褰曠姸鎬�', '1', '2026-03-19 15:06:23', '1', '2026-03-19 15:06:23', X'00', NULL),
+('2001', 'IoT 鍛婅绾у埆', 'iot_alert_level', '0', '', '1', '2025-06-27 20:30:57', '1', '2025-06-27 20:30:57', X'00', '1970-01-01 00:00:00'),
+('2002', 'IoT 鍛婅', 'iot_alert_receive_type', '0', '', '1', '2025-06-27 22:49:19', '1', '2025-06-27 22:49:19', X'00', '1970-01-01 00:00:00'),
+('2003', 'IoT 鍥轰欢璁惧鑼冨洿', 'iot_ota_task_device_scope', '0', '', '1', '2025-07-02 09:42:49', '1', '2025-07-02 09:42:49', X'00', '1970-01-01 00:00:00'),
+('2004', 'IoT 鍥轰欢鍗囩骇浠诲姟鐘舵��', 'iot_ota_task_status', '0', '', '1', '2025-07-02 09:43:43', '1', '2025-07-02 09:43:43', X'00', '1970-01-01 00:00:00'),
+('2005', 'IoT 鍥轰欢鍗囩骇璁板綍鐘舵��', 'iot_ota_task_record_status', '0', '', '1', '2025-07-02 09:45:02', '1', '2025-07-02 09:45:02', X'00', '1970-01-01 00:00:00'),
+('2007', 'AI MCP 瀹㈡埛绔悕瀛�', 'ai_mcp_client_name', '0', '', '1', '2025-08-28 13:57:40', '1', '2025-08-28 13:57:40', X'00', '1970-01-01 00:00:00'),
+('2008', 'IoT 鍗忚绫诲瀷', 'iot_protocol_type', '0', 'IoT 璁惧鎺ュ叆鍗忚绫诲瀷', '1', '2026-02-04 00:31:33', '1', '2026-02-04 00:31:33', X'00', '1970-01-01 00:00:00'),
+('2009', 'IoT 搴忓垪鍖栫被鍨�', 'iot_serialize_type', '0', 'IoT 璁惧娑堟伅搴忓垪鍖栫被鍨�', '1', '2026-02-04 00:33:16', '1', '2026-02-04 00:33:16', X'00', '1970-01-01 00:00:00'),
+('2010', 'IoT Modbus 宸ヤ綔妯″紡', 'iot_modbus_mode', '0', 'Modbus 璁惧鏁版嵁閲囬泦妯″紡', '1', '2025-06-12 22:55:46', '1', '2025-06-12 22:55:46', X'00', '1970-01-01 00:00:00'),
+('2011', 'IoT Modbus 甯ф牸寮�', 'iot_modbus_frame_format', '0', 'Modbus 鏁版嵁甯у崗璁牸寮�', '1', '2025-06-12 22:55:46', '1', '2025-06-12 22:55:46', X'00', '1970-01-01 00:00:00'),
+('2012', 'MES 瀹㈡埛绫诲瀷', 'mes_client_type', '0', '', '1', '2026-02-15 14:38:25', '1', '2026-02-15 14:38:25', X'00', NULL),
+('2013', 'MES 渚涘簲鍟嗙骇鍒�', 'mes_vendor_level', '0', '', '1', '2026-02-15 15:59:15', '1', '2026-02-15 15:59:15', X'00', NULL),
+('2014', 'MES 鍋囨湡绫诲瀷', 'mes_cal_holiday_type', '0', 'MES 鏃ュ巻鎺掔彮 - 鍋囨湡绫诲瀷锛圚OLIDAY=鍋囨湡锛學ORKDAY=宸ヤ綔鏃ワ級', '1', '2026-02-16 07:35:58', '1', '2026-02-16 07:35:58', X'00', NULL),
+('2015', 'MES 宸ュ叿鐘舵��', 'mes_tm_tool_status', '0', 'MES 宸ュ叿绠$悊 - 宸ュ叿鐘舵�侊紙1=鍦ㄥ簱锛�2=棰嗙敤涓紝3=缁翠慨涓紝4=鎶ュ簾锛�', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', X'00', NULL),
+('2016', 'MES 淇濆吇缁存姢绫诲瀷', 'mes_tm_mainten_type', '0', 'MES 宸ュ叿绠$悊 - 淇濆吇缁存姢绫诲瀷锛�1=瀹氭湡缁存姢锛�2=鎸変娇鐢ㄦ鏁扮淮鎶わ級', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', X'00', NULL),
+('2017', 'MES 璁惧鐘舵��', 'mes_dv_machinery_status', '0', 'MES 璁惧绠$悊 - 璁惧鐘舵�侊紙1=杩愯涓紝2=鍋滄満锛�3=鏁呴殰锛�', '1', '2026-02-17 01:00:06', '1', '2026-02-17 01:00:06', X'00', NULL),
+('2018', 'MES 妫�娴嬮」绫诲瀷', 'mes_indicator_type', '0', '', '1', '2026-02-17 02:16:22', '1', '2026-02-21 15:25:04', X'00', NULL),
+('2019', 'MES 缂洪櫡绛夌骇', 'mes_defect_level', '0', '', '1', '2026-02-17 02:16:22', '1', '2026-02-17 02:16:22', X'00', NULL),
+('2020', 'MES 杞彮鏂瑰紡', 'mes_cal_shift_type', '0', 'MES 鏃ュ巻鎺掔彮 - 杞彮鏂瑰紡', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', X'00', NULL),
+('2021', 'MES 鍊掔彮鏂瑰紡', 'mes_cal_shift_method', '0', 'MES 鏃ュ巻鎺掔彮 - 鍊掔彮鏂瑰紡', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', X'00', NULL),
+('2022', 'MES 鐝粍绫诲瀷', 'mes_cal_calendar_type', '0', 'MES 鏃ュ巻鎺掔彮 - 鐝粍绫诲瀷', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', X'00', NULL),
+('2023', 'MES 鎺掔彮璁″垝鐘舵��', 'mes_cal_plan_status', '0', 'MES 鏃ュ巻鎺掔彮 - 鎺掔彮璁″垝鐘舵��', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', X'00', NULL),
+('2026', 'MES 妫�娴嬬绫�', 'mes_qc_type', '0', 'IQC/IPQC/OQC/RQC', '1', '2026-02-17 08:34:40', '1', '2026-02-17 08:34:40', X'00', NULL),
+('2027', 'MES 鐢熶骇宸ュ崟鐘舵��', 'mes_pro_work_order_status', '0', 'MES 鐢熶骇绠$悊 - 宸ュ崟鐘舵�侊紙0=鑽夌锛�1=宸茬‘璁わ紝2=宸插畬鎴愶紝3=宸插彇娑堬級', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', X'00', NULL),
+('2028', 'MES 宸ュ崟鏉ユ簮绫诲瀷', 'mes_pro_work_order_source_type', '0', 'MES 鐢熶骇绠$悊 - 宸ュ崟鏉ユ簮绫诲瀷锛�1=瀹㈡埛璁㈠崟锛�2=搴撳瓨澶囪揣锛�', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', X'00', NULL),
+('2029', 'MES 宸ュ崟绫诲瀷', 'mes_pro_work_order_type', '0', 'MES 鐢熶骇绠$悊 - 宸ュ崟绫诲瀷锛�1=鑷鐢熶骇锛�2=浠e伐锛�3=閲囪喘锛�', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', X'00', NULL),
+('2036', 'MES 宸ュ簭鍏崇郴绫诲瀷', 'mes_pro_link_type', '0', '宸ヨ壓璺嚎涓伐搴忎箣闂寸殑鍏崇郴绫诲瀷', '1', '2026-02-19 04:24:53', '1', '2026-04-05 15:05:07', X'00', NULL),
+('2037', 'MES 鏃堕棿鍗曚綅', 'mes_time_unit_type', '0', '鐢熶骇鏃堕棿鐨勮閲忓崟浣�', '1', '2026-02-19 04:24:53', '1', '2026-04-05 15:04:57', X'00', NULL),
+('2038', 'MES 鐢熶骇浠诲姟鐘舵��', 'mes_pro_task_status', '0', 'MES 鐢熶骇绠$悊 - 浠诲姟鐘舵�侊紙0=鑽夌锛�4=宸插畬鎴愶紝5=宸插彇娑堬級', '1', '2026-02-19 15:25:27', '1', '2026-06-13 10:32:58', X'00', NULL),
+('2039', 'MES 鐐规淇濆吇椤圭洰绫诲瀷', 'mes_dv_subject_type', '0', 'MES 璁惧绠$悊 - 鐐规淇濆吇椤圭洰绫诲瀷锛�1=璁惧鐐规锛�2=璁惧淇濆吇锛�', '1', '2026-02-20 01:42:58', '1', '2026-02-20 01:42:58', X'00', NULL),
+('2040', 'MES 淇濆吇璁板綍鐘舵��', 'mes_mainten_record_status', '0', NULL, 'admin', '2026-02-20 02:59:55', 'admin', '2026-02-20 02:59:55', X'00', NULL),
+('2041', 'MES 淇濆吇缁撴灉', 'mes_mainten_status', '0', NULL, 'admin', '2026-02-20 02:59:55', 'admin', '2026-02-20 02:59:55', X'00', NULL),
+('2042', 'MES 鐐规淇濆吇鍛ㄦ湡绫诲瀷', 'mes_dv_cycle_type', '0', 'MES 璁惧绠$悊 - 鐐规淇濆吇鍛ㄦ湡绫诲瀷锛�1=澶╋紝2=鍛紝3=鏈堬紝4=骞达級', '1', '2026-02-20 07:11:43', '1', '2026-02-20 07:11:43', X'00', NULL),
+('2043', 'MES 鐐规淇濆吇鏂规鐘舵��', 'mes_dv_check_plan_status', '0', 'MES 璁惧绠$悊 - 鐐规淇濆吇鏂规鐘舵�侊紙0=鑽夌锛�1=宸插惎鐢級', '1', '2026-02-20 07:11:43', '1', '2026-02-20 07:11:43', X'00', NULL),
+('2044', 'MES 鐐规璁板綍鐘舵��', 'mes_dv_check_record_status', '0', NULL, 'admin', '2026-02-20 09:46:19', 'admin', '2026-02-20 09:46:19', X'00', NULL),
+('2045', 'MES 鐐规缁撴灉', 'mes_dv_check_result', '0', NULL, 'admin', '2026-02-20 09:46:19', 'admin', '2026-02-20 09:46:19', X'00', NULL),
+('2046', 'MES 缁翠慨宸ュ崟鐘舵��', 'mes_dv_repair_status', '0', 'MES 璁惧绠$悊 - 缁翠慨宸ュ崟鐘舵�侊紙10=寰呯淮淇紝20=缁翠慨涓紝30=宸插畬鎴愶紝40=宸查獙鏀讹級', '1', '2026-02-20 10:56:24', '1', '2026-02-20 10:56:24', X'00', NULL),
+('2047', 'MES 缁翠慨缁撴灉', 'mes_dv_repair_result', '0', 'MES 璁惧绠$悊 - 缁翠慨缁撴灉锛�1=淇鎴愬姛锛�2=鎶ュ簾锛�', '1', '2026-02-20 10:56:24', '1', '2026-02-20 10:56:24', X'00', NULL),
+('2049', 'MES 妫�娴嬬粨鏋�', 'mes_qc_check_result', '0', '鏉ユ枡妫�楠岀殑鏈�缁堢粨鏋滃垽瀹�', '1', '2026-02-20 11:23:35', '1', '2026-02-20 11:23:35', X'00', NULL),
+('2050', 'MES 鏉ユ簮鍗曟嵁绫诲瀷', 'mes_qc_source_doc_type', '0', 'IQC 鏉ユ枡妫�楠岀殑鏉ユ簮鍗曟嵁绫诲瀷', '1', '2026-02-20 11:23:35', '1', '2026-02-20 11:23:35', X'00', NULL),
+('2051', 'MES 瀹夌伅澶勭疆鐘舵��', 'mes_pro_andon_status', '0', 'MES 鐢熶骇绠$悊 - 瀹夌伅澶勭疆鐘舵�侊紙0=鏈缃紝1=宸插缃級', '1', '2026-02-21 00:08:38', '1', '2026-02-21 00:08:38', X'00', NULL),
+('2052', 'MES 瀹夌伅绾у埆', 'mes_pro_andon_level', '0', 'MES 鐢熶骇绠$悊 - 瀹夌伅绾у埆锛�1=涓�绾э紝2=浜岀骇锛�3=涓夌骇锛�', '1', '2026-02-21 00:08:38', '1', '2026-02-21 00:08:38', X'00', NULL),
+('2053', 'MES 鐢熶骇鎶ュ伐鐘舵��', 'mes_pro_feedback_status', '0', 'MES 鐢熶骇绠$悊 - 鎶ュ伐鐘舵�侊紙0=鑽夌锛�1=瀹℃壒涓紝2=寰呮楠岋紝3=宸插畬鎴愶紝4=宸插彇娑堬級', '1', '2026-02-21 00:50:32', '1', '2026-02-21 00:50:32', X'00', NULL),
+('2054', 'MES 鐢熶骇鎶ュ伐绫诲瀷', 'mes_pro_feedback_type', '0', 'MES 鐢熶骇绠$悊 - 鎶ュ伐绫诲瀷锛�1=鑷鎶ュ伐锛�2=缁熶竴鎶ュ伐锛�', '1', '2026-02-21 00:50:32', '1', '2026-02-21 00:50:32', X'00', NULL),
+('2055', 'MES 鐢熶骇鎶ュ伐閫斿緞', 'mes_pro_feedback_channel', '0', 'MES 鐢熶骇绠$悊 - 鎶ュ伐閫斿緞锛圥C/APP/PDA锛�', '1', '2026-02-21 00:50:32', '1', '2026-02-21 00:50:32', X'00', NULL),
+('2056', 'MES 璐ㄦ鍊肩被鍨�', 'mes_qc_result_type', '0', '妫�楠岀粨鏋滄槑缁嗙殑鍊肩被鍨嬶細娴偣/鏁存暟/鏂囨湰/瀛楀吀/鏂囦欢', '1', '2026-02-21 13:37:17', '1', '2026-02-21 13:37:17', X'00', NULL),
+('2057', 'MES 閫�璐ф楠岀被鍨�', 'mes_rqc_type', '0', 'MES 閫�璐ф楠岀被鍨�', '1', '2026-02-22 06:43:18', '1', '2026-02-22 06:43:18', X'00', NULL),
+('2062', 'MES IPQC 妫�楠岀被鍨�', 'mes_ipqc_type', '0', 'IPQC 杩囩▼妫�楠岀殑妫�楠岀被鍨�', '1', '2026-02-22 07:01:04', '1', '2026-02-22 07:01:04', X'00', NULL),
+('2066', 'MES 鍒拌揣閫氱煡鍗曠姸鎬�', 'mes_wm_arrival_notice_status', '0', 'MES 鍒拌揣閫氱煡鍗曠姸鎬�', '1', '2026-02-22 14:53:18', '1', '2026-02-22 14:53:18', X'00', NULL),
+('2067', 'MES 閲囪喘鍏ュ簱鍗曠姸鎬�', 'mes_wm_item_receipt_status', '0', 'MES 閲囪喘鍏ュ簱鍗曠姸鎬�', '1', '2026-02-22 14:54:05', '1', '2026-02-22 14:54:05', X'00', NULL),
+('2068', 'MES 鍗曟嵁鐘舵��', 'mes_order_status', '0', '', '1', '2026-02-23 21:16:03', '1', '2026-02-23 21:17:37', X'00', NULL),
+('2069', 'MES 棰嗘枡鍑哄簱鍗曠姸鎬�', 'mes_wm_product_issue_status', '0', 'MES 棰嗘枡鍑哄簱鍗曠姸鎬�', '1', '2026-02-26 16:39:44', '1', '2026-04-05 15:05:11', X'00', NULL),
+('2073', 'MES 鐢熶骇閫�鏂欏崟鐘舵��', 'mes_wm_return_issue_status', '0', 'MES 鐢熶骇閫�鏂欏崟鐘舵��', '1', '2026-02-28 14:11:09', '1', '2026-04-05 15:05:14', X'00', NULL),
+('2074', 'MES 鐢熶骇閫�鏂欑被鍨�', 'mes_wm_return_issue_type', '0', 'MES 鐢熶骇閫�鏂欑被鍨�', '1', '2026-02-28 14:11:09', '1', '2026-04-05 15:05:16', X'00', NULL),
+('2075', 'MES 璐ㄩ噺鐘舵��', 'mes_wm_quality_status', '0', 'MES 璐ㄩ噺鐘舵�侊紙寰呮/鍚堟牸/涓嶅悎鏍硷級', '1', '2026-02-28 15:00:53', '1', '2026-02-28 15:00:53', X'00', NULL),
+('2100', 'MES 浜у搧鍏ュ簱鍗曠姸鎬�', 'mes_wm_product_receipt_status', '0', 'MES 浜у搧鍏ュ簱鍗曠姸鎬�', '1', '2026-03-01 06:03:04', '1', '2026-04-05 15:05:49', X'00', NULL),
+('2102', 'MES 閿�鍞嚭搴撳崟鐘舵��', 'mes_wm_product_sales_status', '0', 'MES 閿�鍞嚭搴撳崟鐘舵��', '1', '2026-03-02 08:55:11', '1', '2026-04-05 15:05:18', X'00', NULL),
+('2105', 'MES 鏉傞」鍏ュ簱绫诲瀷', 'mes_wm_misc_receipt_type', '0', '鏉傞」鍏ュ簱绫诲瀷', '1', '2026-03-03 07:18:12', '1', '2026-04-05 15:05:23', X'00', NULL),
+('2106', 'MES 鏉傞」鍏ュ簱鐘舵��', 'mes_wm_misc_receipt_status', '0', '鏉傞」鍏ュ簱鐘舵��', '1', '2026-03-03 07:18:12', '1', '2026-04-05 15:05:25', X'00', NULL),
+('2109', 'MES 鏉傞」鍑哄簱绫诲瀷', 'mes_wm_misc_issue_type', '0', 'MES 鏉傞」鍑哄簱绫诲瀷', '1', '2026-03-03 07:34:33', '1', '2026-03-03 07:34:33', X'00', NULL),
+('2110', 'MES 澶栧崗鍏ュ簱鍗曠姸鎬�', 'mes_wm_outsource_receipt_status', '0', 'MES 澶栧崗鍏ュ簱鍗曠姸鎬�', '1', '2026-03-03 14:03:20', '1', '2026-03-03 14:03:20', X'00', NULL),
+('2112', 'MES 澶栧崗鍙戞枡鍗曠姸鎬�', 'mes_wm_outsource_issue_status', '0', 'MES 澶栧崗鍙戞枡鍗曠姸鎬�', '1', '2026-03-03 16:30:56', '1', '2026-04-05 15:05:47', X'00', NULL),
+('2113', 'MES 缂栫爜瑙勫垯鍒嗘绫诲瀷', 'mes_md_auto_code_part_type', '0', 'MES 缂栫爜瑙勫垯鍒嗘绫诲瀷', '1', '2026-03-04 14:45:46', '1', '2026-03-04 15:24:40', X'00', NULL),
+('2115', 'MES 缂栫爜瑙勫垯琛ラ綈鏂瑰紡', 'mes_md_auto_code_padded_method', '0', 'MES 缂栫爜瑙勫垯琛ラ綈鏂瑰紡', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', X'00', NULL),
+('2116', 'MES 缂栫爜瑙勫垯寰幆鏂瑰紡', 'mes_md_auto_code_cycle_method', '0', 'MES 缂栫爜瑙勫垯寰幆鏂瑰紡', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', X'00', NULL),
+('2117', 'MES 鏉$爜鏍煎紡', 'mes_wm_barcode_format', '0', 'MES 鏉$爜鏍煎紡', '1', '2026-03-05 14:37:20', '1', '2026-04-05 15:05:27', X'00', NULL),
+('2118', 'MES 鏉$爜涓氬姟绫诲瀷', 'mes_wm_barcode_biz_type', '0', 'MES 鏉$爜涓氬姟绫诲瀷', '1', '2026-03-05 14:37:20', '1', '2026-04-05 15:05:29', X'00', NULL),
+('2121', 'MES 瑁呯鍗曠姸鎬�', 'mes_wm_package_status', '0', 'MES 瑁呯鍗曠姸鎬�', '1', '2026-03-08 02:05:46', '1', '2026-04-05 15:05:35', X'00', NULL),
+('2122', 'MES 璋冩嫧鍗曠姸鎬�', 'mes_wm_transfer_status', '0', 'MES 璋冩嫧鍗曠姸鎬�', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', X'00', NULL),
+('2123', 'MES 璋冩嫧绫诲瀷', 'mes_wm_transfer_type', '0', 'MES 璋冩嫧绫诲瀷', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', X'00', NULL),
+('2124', 'MES 鐩樼偣绫诲瀷', 'mes_wm_stock_taking_type', '0', 'MES 鐩樼偣绫诲瀷', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', X'00', NULL),
+('2125', 'MES 鐩樼偣鏂规鍙傛暟绫诲瀷', 'mes_wm_stock_taking_plan_param_type', '0', 'MES 鐩樼偣鏂规鍙傛暟绫诲瀷', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', X'00', NULL),
+('2126', 'MES 鐩樼偣浠诲姟鐘舵��', 'mes_wm_stock_taking_task_status', '0', 'MES 鐩樼偣浠诲姟鐘舵��', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', X'00', NULL),
+('2127', 'MES 鐩樼偣浠诲姟琛岀姸鎬�', 'mes_wm_stock_taking_task_line_status', '0', 'MES 鐩樼偣浠诲姟琛岀姸鎬�', '1', '2026-03-09 00:00:00', '1', '2026-04-05 15:02:18', X'00', NULL),
+('2129', 'MES 鐗╂枡浜у搧鏍囪瘑', 'mes_md_item_or_product', '0', '鐗╂枡鍒嗙被锛氱墿鏂�(ITEM) / 浜у搧(PRODUCT)', '1', '2026-03-15 01:55:06', '1', '2026-03-15 01:55:06', X'00', NULL),
+('2130', 'MES 渚涘簲鍟嗛��璐у崟鐘舵��', 'mes_wm_return_vendor_status', '0', '閲囪喘閫�璐у崟鐘舵��', '', '2026-03-29 13:49:57', '', '2026-04-05 15:53:46', X'00', NULL),
+('2131', 'MES 鍙戣揣閫氱煡鍗曠姸鎬�', 'mes_wm_sales_notice_status', '0', 'MES 鍙戣揣閫氱煡鍗曠姸鎬�', '1', '2026-03-30 08:54:30', '1', '2026-04-05 15:53:46', X'00', NULL),
+('2132', 'MES 鏉傞」鍑哄簱鍗曠姸鎬�', 'mes_wm_misc_issue_status', '0', '鏉傞」鍑哄簱鍗曠姸鎬�', '1', '2026-03-30 15:00:18', '1', '2026-04-05 15:05:41', X'00', NULL),
+('2133', 'MES 閿�鍞��璐у崟鐘舵��', 'mes_wm_return_sales_status', '0', 'MES 閿�鍞��璐у崟鐘舵�佹灇涓�', '1', '2026-04-03 17:20:25', '1', '2026-04-05 15:05:39', X'00', NULL),
+('2135', 'MES 涓婁笅宸ョ姸鎬佺被鍨�', 'mes_pro_work_record_type', '0', 'MES 涓婁笅宸ョ姸鎬佺被鍨�', '1', '2026-04-05 14:07:27', '1', '2026-04-05 14:07:27', X'00', NULL),
+('2138', 'MES 鐢熶骇鍏ュ簱鍗曠姸鎬�', 'mes_wm_product_produce_status', '0', 'MES 鐢熶骇鍏ュ簱鍗曠姸鎬�', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', X'00', '1970-01-01 00:00:00'),
+('2200', 'IM 鍐呭绫诲瀷', 'im_content_type', '0', '瀵瑰簲 ImContentTypeEnum', 'admin', '2026-04-30 11:35:07', 'admin', '2026-06-16 03:41:55', X'00', NULL),
+('2202', 'IM 娑堟伅鍥炴墽鐘舵��', 'im_message_receipt_status', '0', '瀵瑰簲 ImMessageReceiptStatusEnum', 'admin', '2026-04-30 11:35:07', 'admin', '2026-06-16 03:41:55', X'00', NULL),
+('2203', 'IM 濂藉弸鐘舵��', 'im_friend_status', '0', '0=姝e父 / 1=宸插垹闄�', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', X'00', NULL),
+('2204', 'IM 缇ょ姸鎬�', 'im_group_status', '0', '0=姝e父 / 1=宸茶В鏁�', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', X'00', NULL),
+('2205', 'IM 娑堟伅鐘舵��', 'im_message_status', '0', '瀵瑰簲 ImMessageStatusEnum锛�0=姝e父 / 2=宸叉挙鍥烇紙绉佽亰 / 缇よ亰鍏辩敤锛�', 'admin', '2026-04-30 15:14:36', 'admin', '2026-06-16 03:41:55', X'00', NULL),
+('2206', 'IM 缇ゆ垚鍛樿鑹�', 'im_group_member_role', '0', NULL, '1', '2026-05-02 02:14:12', '1', '2026-05-02 02:14:12', X'00', NULL),
+('2207', 'IM 濂藉弸娣诲姞鏉ユ簮', 'im_friend_add_source', '0', NULL, '1', '2026-05-04 02:43:41', '1', '2026-05-04 02:43:41', X'00', NULL),
+('2208', 'IM 濂藉弸鐢宠澶勭悊缁撴灉', 'im_friend_request_handle_result', '0', NULL, '1', '2026-05-04 02:43:41', '1', '2026-05-04 02:43:41', X'00', NULL),
+('2209', 'IM 鍔犵兢鏉ユ簮', 'im_group_add_source', '0', NULL, '', '2026-05-06 09:26:36', '', '2026-05-06 09:26:36', X'00', NULL),
+('2210', 'IM 鍔犵兢鐢宠澶勭悊缁撴灉', 'im_group_request_handle_result', '0', NULL, '', '2026-05-06 09:26:36', '', '2026-05-06 09:26:36', X'00', NULL),
+('1061050', '寰�鏉ヤ紒涓氱被鍨�', 'merchant_type', '0', 'WMS 寰�鏉ヤ紒涓氱被鍨�', '1', '2026-05-10 15:26:09', '1', '2026-05-10 15:26:09', X'00', NULL),
+('1061060', 'WMS 鍗曟嵁绫诲瀷', 'wms_order_type', '0', 'WMS 鍗曟嵁绫诲瀷', '1', '2026-05-10 17:51:46', '1', '2026-05-14 08:14:09', X'00', NULL),
+('1061070', 'WMS 鍗曟嵁鐘舵��', 'wms_order_status', '0', 'WMS 鍗曟嵁鐘舵��', '1', '2026-05-12 13:40:29', '1', '2026-05-12 13:40:29', X'00', NULL),
+('1061080', '鍏ュ簱鍗曠被鍨�', 'wms_receipt_order_type', '0', 'WMS 鍏ュ簱鍗曠被鍨�', '1', '2026-05-11 11:21:49', '1', '2026-05-12 13:40:29', X'00', NULL),
+('1061090', '鍑哄簱鍗曠被鍨�', 'wms_shipment_order_type', '0', 'WMS 鍑哄簱鍗曠被鍨�', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', X'00', NULL),
+('1061092', 'IM 閫氳瘽濯掍綋绫诲瀷', 'im_rtc_call_media_type', '0', NULL, 'admin', '2026-05-16 11:34:50', 'admin', '2026-05-16 11:34:50', X'00', NULL),
+('1061093', 'IM 閫氳瘽浼氳瘽绫诲瀷', 'im_rtc_call_conversation_type', '0', '1=绉佽亰锛�2=缇よ亰', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00', NULL),
+('1061094', 'IM 閫氳瘽鐘舵��', 'im_rtc_call_status', '0', '10=鍒涘缓锛�20=杩涜涓紱30=宸茬粨鏉�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00', NULL),
+('1061095', 'IM 閫氳瘽缁撴潫鍘熷洜', 'im_rtc_call_end_reason', '0', '1=閫氳瘽缁撴潫锛�2=宸叉嫆缁濓紱3=宸插彇娑堬紱4=鏃犱汉鎺ュ惉锛�5=瀵规柟姝e繖锛�9=閫氳瘽寮傚父', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00', NULL),
+('1061096', 'IM 閫氳瘽鍙備笌瑙掕壊', 'im_rtc_participant_role', '0', '1=鍙戣捣浜猴紱2=琚個璇疯�咃紱3=涓诲姩鍔犲叆鑰�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00', NULL),
+('1061097', 'IM 閫氳瘽鍙備笌鐘舵��', 'im_rtc_participant_status', '0', '10=閭�璇蜂腑锛�20=宸插姞鍏ワ紱30=宸叉嫆缁濓紱40=鏈簲绛旓紱50=宸茬寮�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00', NULL),
+('1061098', 'IM 棰戦亾绱犳潗鍐呭绫诲瀷', 'im_channel_material_type', '0', '1=绔欏唴瀵屾枃鏈� / 2=澶栭摼', '1', '2026-05-19 14:09:25', '1', '2026-05-19 14:09:25', X'00', NULL),
+('1061099', 'WMS 搴撳瓨棰勭暀涓氬姟绫诲瀷', 'wms_reserve_biz_type', '0', '搴撳瓨棰勭暀鐨勪笟鍔℃潵婧愮被鍨�', '1', '2026-06-26 08:15:54', '1', '2026-06-26 08:15:54', X'00', NULL),
+('1061100', 'WMS 搴撳瓨浜嬪姟绫诲瀷', 'wms_transaction_type', '0', '搴撳瓨浜嬪姟娴佹按绫诲瀷', '1', '2026-06-26 08:15:54', '1', '2026-06-26 08:15:54', X'00', NULL),
+('1061101', 'WMS 搴撳瓨棰勭暀鐘舵��', 'wms_reserve_status', '0', '搴撳瓨棰勭暀鐘舵��', '1', '2026-06-26 08:15:54', '1', '2026-06-26 08:15:54', X'00', NULL),
+('1061102', 'MES 鍙傛暟鏍煎紡', 'mes_pd_param_type', '0', NULL, '1', '2026-07-02 13:59:05', '1', '2026-07-02 13:59:05', X'00', '1970-01-01 00:00:00'),
+('1061103', 'MES 鍙傛暟妯℃澘', 'mes_pd_template_type', '0', NULL, '1', '2026-07-02 14:02:13', '1', '2026-07-02 14:02:13', X'00', '1970-01-01 00:00:00'),
+('1061104', '璁捐椤圭洰鐘舵��', 'mes_pd_project_status', '0', '璁捐椤圭洰鐘舵��', '1', '2026-07-03 02:17:25', '1', '2026-07-03 02:17:25', X'00', NULL),
+('1061105', '璧勬枡绫诲瀷', 'mes_pd_document_type', '0', '璧勬枡绫诲瀷', '1', '2026-07-03 02:17:25', '1', '2026-07-03 02:17:25', X'00', NULL),
+('1061106', '璧勬枡瀹℃牳鐘舵��', 'mes_pd_document_audit_status', '0', '璧勬枡瀹℃牳鐘舵��', '1', '2026-07-03 02:17:25', '1', '2026-07-03 02:17:25', X'00', NULL),
+('1061107', '褰掓。鐘舵��', 'mes_pd_archive_status', '0', '褰掓。鐘舵��', '1', '2026-07-03 02:17:25', '1', '2026-07-03 02:17:25', X'00', NULL),
+('1061108', '鎬у埆', 'hrm_gender', '0', NULL, '1', '2026-07-06 11:00:21', '1', '2026-07-06 11:00:21', X'00', '1970-01-01 00:00:00'),
+('1061109', '鍛樺伐鐘舵��', 'hrm_employee_status', '0', NULL, '1', '2026-07-06 11:01:28', '1', '2026-07-06 11:01:28', X'00', '1970-01-01 00:00:00'),
+('1061110', '瀛﹀巻', 'hrm_degree', '0', NULL, '1', '2026-07-06 11:13:51', '1', '2026-07-06 11:13:51', X'00', '1970-01-01 00:00:00'),
+('1061111', '璇峰亣绫诲瀷', 'hrm_leave_type', '0', NULL, '1', '2026-07-06 11:15:50', '1', '2026-07-06 11:15:50', X'00', '1970-01-01 00:00:00'),
+('1061112', '璋冨矖绫诲瀷', 'hrm_transfer_type', '0', NULL, '1', '2026-07-06 11:18:02', '1', '2026-07-06 11:18:02', X'00', '1970-01-01 00:00:00'),
+('1061113', '绂昏亴绫诲瀷', 'hrm_resignation_type', '0', NULL, '1', '2026-07-06 11:18:32', '1', '2026-07-06 11:18:32', X'00', '1970-01-01 00:00:00'),
+('1061114', '鎵撳崱绫诲瀷', 'hrm_clock_type', '0', NULL, '1', '2026-07-06 11:20:57', '1', '2026-07-06 11:20:57', X'00', '1970-01-01 00:00:00'),
+('1061115', '钖祫鐘舵��', 'hrm_salary_status', '0', NULL, '1', '2026-07-06 11:21:41', '1', '2026-07-06 11:21:41', X'00', '1970-01-01 00:00:00'),
+('1061116', '浜ゆ帴鐘舵��', 'hrm_handover_status', '0', NULL, '1', '2026-07-06 11:22:47', '1', '2026-07-06 11:22:47', X'00', '1970-01-01 00:00:00'),
+('1061117', '鍙戞斁鏂瑰紡', 'hrm_payment_method', '0', NULL, '1', '2026-07-06 11:23:38', '1', '2026-07-06 11:23:38', X'00', '1970-01-01 00:00:00'),
+('1061118', '鐗╂枡绫诲瀷', 'MDM_ITEM_TYPE', '0', NULL, '1', '2026-07-14 12:04:18', '1', '2026-07-14 12:04:18', X'00', '1970-01-01 00:00:00'),
+('1061119', 'MPS 鐘舵��', 'mes_pro_mps_status', '0', 'MPS 鐘舵��', '1', '2026-07-17 02:04:12', '1', '2026-07-17 02:04:12', X'00', NULL),
+('1061120', 'MES NCR 鐘舵��', 'mes_ncr_status', '0', '涓嶅悎鏍煎搧澶勭悊鍗曠姸鎬�', '1', '2026-08-06 09:25:18', '1', '2026-08-06 09:25:18', X'00', NULL),
+('1061121', 'MES NCR 澶勭疆鏂瑰紡', 'mes_ncr_disposition', '0', '涓嶅悎鏍煎搧澶勭疆鏂瑰紡', '1', '2026-08-06 09:25:18', '1', '2026-08-06 09:25:18', X'00', NULL),
+('1061122', '鍙戠エ绫诲瀷', 'crm_invoice_type', '0', NULL, '1', '2026-08-10 14:04:10', '1', '2026-08-10 14:04:10', X'00', '1970-01-01 00:00:00'),
+('1061123', '鍚堝悓绫诲瀷', 'hrm_contract_type', '0', NULL, '', '2026-08-10 07:51:38', '', '2026-08-10 07:51:38', X'00', NULL),
+('1061124', '鍚堝悓鏈熼檺绫诲瀷', 'hrm_contract_term_type', '0', NULL, '', '2026-08-10 07:51:38', '', '2026-08-10 07:51:38', X'00', NULL),
+('1061125', '鍚堝悓鐘舵��', 'hrm_contract_status', '0', NULL, '', '2026-08-10 07:51:38', '', '2026-08-10 07:51:38', X'00', NULL),
+('1061126', '瑙i櫎缁堟鐘舵��', 'hrm_contract_terminate_status', '0', NULL, '', '2026-08-10 07:51:38', '', '2026-08-10 07:51:38', X'00', NULL),
+('1065300', '閿�鍞洰鏍囧懆鏈熺被鍨�', 'crm_sales_target_period_type', '0', '閿�鍞洰鏍囩殑璁″垝鍛ㄦ湡绫诲瀷', '1', '2026-08-12 07:21:28', '1', '2026-08-12 07:21:28', X'00', NULL),
+('1065301', '閿�鍞洰鏍囩淮搴�', 'crm_sales_target_dimension', '0', '閿�鍞洰鏍囨寜浠�涔堢淮搴﹁瀹�', '1', '2026-08-12 07:21:28', '1', '2026-08-12 07:21:28', X'00', NULL),
+('1065302', '閿�鍞洰鏍囩姸鎬�', 'crm_sales_target_status', '0', '閿�鍞洰鏍囩殑鐢熷懡鍛ㄦ湡鐘舵��', '1', '2026-08-12 07:21:28', '1', '2026-08-12 07:21:28', X'00', NULL),
+('1065303', 'MES 璁¢噺鍣ㄥ叿绫诲埆', 'mes_dv_metering_category', '0', '璁¢噺鍣ㄥ叿绫诲埆', '1', '2026-08-13 01:36:06', '1', '2026-08-13 01:36:06', X'00', NULL),
+('1065304', 'MES 璁¢噺鍣ㄥ叿鐘舵��', 'mes_dv_metering_status', '0', '璁¢噺鍣ㄥ叿鐘舵��', '1', '2026-08-13 01:36:06', '1', '2026-08-13 01:36:06', X'00', NULL),
+('1065305', 'MES 璁¢噺妫�娴嬬粨璁�', 'mes_dv_metering_check_result', '0', '璁¢噺妫�娴嬬粨璁�', '1', '2026-08-13 01:36:06', '1', '2026-08-13 01:36:06', X'00', NULL),
+('1065400', '璐ㄦ鎶ュ憡妯℃澘鐘舵��', 'qc_report_template_status', '0', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00', NULL),
+('1065401', '璐ㄦ鎶ュ憡妯℃澘鐗堟湰鐘舵��', 'qc_report_version_status', '0', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00', NULL),
+('1065402', '璐ㄦ鎶ュ憡瀹炰緥鐘舵��', 'qc_report_instance_status', '0', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00', NULL),
+('1065403', '璐ㄦ鎶ュ憡绾稿紶灏哄', 'qc_report_page_size', '0', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00', NULL),
+('1065404', '璐ㄦ鎶ュ憡绾稿紶鏂瑰悜', 'qc_report_orientation', '0', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00', NULL),
+('1065405', '璐ㄦ鎶ュ憡閫傜敤琛屼笟', 'qc_report_industry', '0', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00', NULL);
+
+-- ============ 琛細system_dict_data锛堝鍑� 1157 琛岋級 ============
+DROP TABLE IF EXISTS `system_dict_data`;
+CREATE TABLE `system_dict_data` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '瀛楀吀缂栫爜',
+ `sort` int NOT NULL DEFAULT '0' COMMENT '瀛楀吀鎺掑簭',
+ `label` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '瀛楀吀鏍囩',
+ `value` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '瀛楀吀閿��',
+ `dict_type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '瀛楀吀绫诲瀷',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+ `color_type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '棰滆壊绫诲瀷',
+ `css_class` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT 'css 鏍峰紡',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=1065347 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='瀛楀吀鏁版嵁琛�';
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES
+('1', '1', '鐢�', '1', 'system_user_sex', '0', 'primary', 'A', '鎬у埆鐢�', 'admin', '2021-01-05 17:03:48', '1', '2025-12-10 13:19:26', X'00'),
+('2', '2', '濂�', '2', 'system_user_sex', '0', 'success', '', '鎬у埆濂�', 'admin', '2021-01-05 17:03:48', '1', '2023-11-15 23:30:37', X'00'),
+('8', '1', '姝e父', '1', 'infra_job_status', '0', 'success', '', '姝e父鐘舵��', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:33:38', X'00'),
+('9', '2', '鏆傚仠', '2', 'infra_job_status', '0', 'danger', '', '鍋滅敤鐘舵��', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:33:45', X'00'),
+('12', '1', '绯荤粺鍐呯疆', '1', 'infra_config_type', '0', 'danger', '', '鍙傛暟绫诲瀷 - 绯荤粺鍐呯疆', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:06:02', X'00'),
+('13', '2', '鑷畾涔�', '2', 'infra_config_type', '0', 'primary', '', '鍙傛暟绫诲瀷 - 鑷畾涔�', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:06:07', X'00'),
+('14', '1', '閫氱煡', '1', 'system_notice_type', '0', 'success', '', '閫氱煡', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:05:57', X'00'),
+('15', '2', '鍏憡', '2', 'system_notice_type', '0', 'info', '', '鍏憡', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:06:01', X'00'),
+('16', '0', '鍏跺畠', '0', 'infra_operate_type', '0', 'default', '', '鍏跺畠鎿嶄綔', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:19', X'00'),
+('17', '1', '鏌ヨ', '1', 'infra_operate_type', '0', 'info', '', '鏌ヨ鎿嶄綔', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:20', X'00'),
+('18', '2', '鏂板', '2', 'infra_operate_type', '0', 'primary', '', '鏂板鎿嶄綔', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:21', X'00'),
+('19', '3', '淇敼', '3', 'infra_operate_type', '0', 'warning', '', '淇敼鎿嶄綔', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:22', X'00'),
+('20', '4', '鍒犻櫎', '4', 'infra_operate_type', '0', 'danger', '', '鍒犻櫎鎿嶄綔', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:23', X'00'),
+('22', '5', '瀵煎嚭', '5', 'infra_operate_type', '0', 'default', '', '瀵煎嚭鎿嶄綔', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:24', X'00'),
+('23', '6', '瀵煎叆', '6', 'infra_operate_type', '0', 'default', '', '瀵煎叆鎿嶄綔', 'admin', '2021-01-05 17:03:48', '1', '2024-03-14 12:44:25', X'00'),
+('27', '1', '寮�鍚�', '0', 'common_status', '0', 'primary', '', '寮�鍚姸鎬�', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 08:00:39', X'00'),
+('28', '2', '鍏抽棴', '1', 'common_status', '0', 'info', '', '鍏抽棴鐘舵��', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 08:00:44', X'00'),
+('29', '1', '鐩綍', '1', 'system_menu_type', '0', '', '', '鐩綍', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:43:45', X'00'),
+('30', '2', '鑿滃崟', '2', 'system_menu_type', '0', '', '', '鑿滃崟', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:43:41', X'00'),
+('31', '3', '鎸夐挳', '3', 'system_menu_type', '0', '', '', '鎸夐挳', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:43:39', X'00'),
+('32', '1', '鍐呯疆', '1', 'system_role_type', '0', 'danger', '', '鍐呯疆瑙掕壊', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:02:08', X'00'),
+('33', '2', '鑷畾涔�', '2', 'system_role_type', '0', 'primary', '', '鑷畾涔夎鑹�', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 13:02:12', X'00'),
+('34', '1', '鍏ㄩ儴鏁版嵁鏉冮檺', '1', 'system_data_scope', '0', '', '', '鍏ㄩ儴鏁版嵁鏉冮檺', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:17', X'00'),
+('35', '2', '鎸囧畾閮ㄩ棬鏁版嵁鏉冮檺', '2', 'system_data_scope', '0', '', '', '鎸囧畾閮ㄩ棬鏁版嵁鏉冮檺', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:18', X'00'),
+('36', '3', '鏈儴闂ㄦ暟鎹潈闄�', '3', 'system_data_scope', '0', '', '', '鏈儴闂ㄦ暟鎹潈闄�', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:16', X'00'),
+('37', '4', '鏈儴闂ㄥ強浠ヤ笅鏁版嵁鏉冮檺', '4', 'system_data_scope', '0', '', '', '鏈儴闂ㄥ強浠ヤ笅鏁版嵁鏉冮檺', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:21', X'00'),
+('38', '5', '浠呮湰浜烘暟鎹潈闄�', '5', 'system_data_scope', '0', '', '', '浠呮湰浜烘暟鎹潈闄�', 'admin', '2021-01-05 17:03:48', '', '2022-02-01 16:47:23', X'00'),
+('39', '0', '鎴愬姛', '0', 'system_login_result', '0', 'success', '', '鐧婚檰缁撴灉 - 鎴愬姛', '', '2021-01-18 06:17:36', '1', '2022-02-16 13:23:49', X'00'),
+('40', '10', '璐﹀彿鎴栧瘑鐮佷笉姝g‘', '10', 'system_login_result', '0', 'primary', '', '鐧婚檰缁撴灉 - 璐﹀彿鎴栧瘑鐮佷笉姝g‘', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:27', X'00'),
+('41', '20', '鐢ㄦ埛琚鐢�', '20', 'system_login_result', '0', 'warning', '', '鐧婚檰缁撴灉 - 鐢ㄦ埛琚鐢�', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:23:57', X'00'),
+('42', '30', '楠岃瘉鐮佷笉瀛樺湪', '30', 'system_login_result', '0', 'info', '', '鐧婚檰缁撴灉 - 楠岃瘉鐮佷笉瀛樺湪', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:07', X'00'),
+('43', '31', '楠岃瘉鐮佷笉姝g‘', '31', 'system_login_result', '0', 'info', '', '鐧婚檰缁撴灉 - 楠岃瘉鐮佷笉姝g‘', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:11', X'00'),
+('44', '100', '鏈煡寮傚父', '100', 'system_login_result', '0', 'danger', '', '鐧婚檰缁撴灉 - 鏈煡寮傚父', '', '2021-01-18 06:17:54', '1', '2022-02-16 13:24:23', X'00'),
+('45', '1', '鏄�', 'true', 'infra_boolean_string', '0', 'danger', '', 'Boolean 鏄惁绫诲瀷 - 鏄�', '', '2021-01-19 03:20:55', '1', '2022-03-15 23:01:45', X'00'),
+('46', '1', '鍚�', 'false', 'infra_boolean_string', '0', 'info', '', 'Boolean 鏄惁绫诲瀷 - 鍚�', '', '2021-01-19 03:20:55', '1', '2022-03-15 23:09:45', X'00'),
+('50', '1', '鍗曡〃锛堝鍒犳敼鏌ワ級', '1', 'infra_codegen_template_type', '0', '', '', NULL, '', '2021-02-05 07:09:06', '', '2022-03-10 16:33:15', X'00'),
+('51', '2', '鏍戣〃锛堝鍒犳敼鏌ワ級', '2', 'infra_codegen_template_type', '0', '', '', NULL, '', '2021-02-05 07:14:46', '', '2022-03-10 16:33:19', X'00'),
+('53', '0', '鍒濆鍖栦腑', '0', 'infra_job_status', '0', 'primary', '', NULL, '', '2021-02-07 07:46:49', '1', '2022-02-16 19:33:29', X'00'),
+('57', '0', '杩愯涓�', '0', 'infra_job_log_status', '0', 'primary', '', 'RUNNING', '', '2021-02-08 10:04:24', '1', '2022-02-16 19:07:48', X'00'),
+('58', '1', '鎴愬姛', '1', 'infra_job_log_status', '0', 'success', '', NULL, '', '2021-02-08 10:06:57', '1', '2022-02-16 19:07:52', X'00'),
+('59', '2', '澶辫触', '2', 'infra_job_log_status', '0', 'warning', '', '澶辫触', '', '2021-02-08 10:07:38', '1', '2022-02-16 19:07:56', X'00'),
+('60', '1', '浼氬憳', '1', 'user_type', '0', 'primary', '', NULL, '', '2021-02-26 00:16:27', '1', '2022-02-16 10:22:19', X'00'),
+('61', '2', '绠$悊鍛�', '2', 'user_type', '0', 'success', '', NULL, '', '2021-02-26 00:16:34', '1', '2025-04-06 18:37:43', X'00'),
+('62', '0', '鏈鐞�', '0', 'infra_api_error_log_process_status', '0', 'primary', '', NULL, '', '2021-02-26 07:07:19', '1', '2022-02-16 20:14:17', X'00'),
+('63', '1', '宸插鐞�', '1', 'infra_api_error_log_process_status', '0', 'success', '', NULL, '', '2021-02-26 07:07:26', '1', '2022-02-16 20:14:08', X'00'),
+('64', '2', '宸插拷鐣�', '2', 'infra_api_error_log_process_status', '0', 'danger', '', NULL, '', '2021-02-26 07:07:34', '1', '2022-02-16 20:14:14', X'00'),
+('66', '1', '闃块噷浜�', 'ALIYUN', 'system_sms_channel_code', '0', 'primary', '', NULL, '1', '2021-04-05 01:05:26', '1', '2024-07-22 22:23:25', X'00'),
+('67', '1', '楠岃瘉鐮�', '1', 'system_sms_template_type', '0', 'warning', '', NULL, '1', '2021-04-05 21:50:57', '1', '2022-02-16 12:48:30', X'00'),
+('68', '2', '閫氱煡', '2', 'system_sms_template_type', '0', 'primary', '', NULL, '1', '2021-04-05 21:51:08', '1', '2022-02-16 12:48:27', X'00'),
+('69', '0', '钀ラ攢', '3', 'system_sms_template_type', '0', 'danger', '', NULL, '1', '2021-04-05 21:51:15', '1', '2022-02-16 12:48:22', X'00'),
+('70', '0', '鍒濆鍖�', '0', 'system_sms_send_status', '0', 'primary', '', NULL, '1', '2021-04-11 20:18:33', '1', '2022-02-16 10:26:07', X'00'),
+('71', '1', '鍙戦�佹垚鍔�', '10', 'system_sms_send_status', '0', 'success', '', NULL, '1', '2021-04-11 20:18:43', '1', '2022-02-16 10:25:56', X'00'),
+('72', '2', '鍙戦�佸け璐�', '20', 'system_sms_send_status', '0', 'danger', '', NULL, '1', '2021-04-11 20:18:49', '1', '2022-02-16 10:26:03', X'00'),
+('73', '3', '涓嶅彂閫�', '30', 'system_sms_send_status', '0', 'info', '', NULL, '1', '2021-04-11 20:19:44', '1', '2022-02-16 10:26:10', X'00'),
+('74', '0', '绛夊緟缁撴灉', '0', 'system_sms_receive_status', '0', 'primary', '', NULL, '1', '2021-04-11 20:27:43', '1', '2022-02-16 10:28:24', X'00'),
+('75', '1', '鎺ユ敹鎴愬姛', '10', 'system_sms_receive_status', '0', 'success', '', NULL, '1', '2021-04-11 20:29:25', '1', '2022-02-16 10:28:28', X'00'),
+('76', '2', '鎺ユ敹澶辫触', '20', 'system_sms_receive_status', '0', 'danger', '', NULL, '1', '2021-04-11 20:29:31', '1', '2022-02-16 10:28:32', X'00'),
+('77', '0', '璋冭瘯(閽夐拤)', 'DEBUG_DING_TALK', 'system_sms_channel_code', '0', 'info', '', NULL, '1', '2021-04-13 00:20:37', '1', '2022-02-16 10:10:00', X'00'),
+('80', '100', '璐﹀彿鐧诲綍', '100', 'system_login_type', '0', 'primary', '', '璐﹀彿鐧诲綍', '1', '2021-10-06 00:52:02', '1', '2022-02-16 13:11:34', X'00'),
+('81', '101', '绀句氦鐧诲綍', '101', 'system_login_type', '0', 'info', '', '绀句氦鐧诲綍', '1', '2021-10-06 00:52:17', '1', '2022-02-16 13:11:40', X'00'),
+('83', '200', '涓诲姩鐧诲嚭', '200', 'system_login_type', '0', 'primary', '', '涓诲姩鐧诲嚭', '1', '2021-10-06 00:52:58', '1', '2022-02-16 13:11:49', X'00'),
+('85', '202', '寮哄埗鐧诲嚭', '202', 'system_login_type', '0', 'danger', '', '寮哄埗閫�鍑�', '1', '2021-10-06 00:53:41', '1', '2022-02-16 13:11:57', X'00'),
+('86', '0', '鐥呭亣', '1', 'bpm_oa_leave_type', '0', 'primary', '', NULL, '1', '2021-09-21 22:35:28', '1', '2022-02-16 10:00:41', X'00'),
+('87', '1', '浜嬪亣', '2', 'bpm_oa_leave_type', '0', 'info', '', NULL, '1', '2021-09-21 22:36:11', '1', '2022-02-16 10:00:49', X'00'),
+('88', '2', '濠氬亣', '3', 'bpm_oa_leave_type', '0', 'warning', '', NULL, '1', '2021-09-21 22:36:38', '1', '2022-02-16 10:00:53', X'00'),
+('112', '0', '寰俊 Wap 缃戠珯鏀粯', 'wx_wap', 'pay_channel_code', '0', 'success', '', '寰俊 Wap 缃戠珯鏀粯', '1', '2023-07-19 20:08:06', '1', '2023-07-19 20:09:08', X'00'),
+('113', '1', '寰俊鍏紬鍙锋敮浠�', 'wx_pub', 'pay_channel_code', '0', 'success', '', '寰俊鍏紬鍙锋敮浠�', '1', '2021-12-03 10:40:24', '1', '2023-07-19 20:08:47', X'00'),
+('114', '2', '寰俊灏忕▼搴忔敮浠�', 'wx_lite', 'pay_channel_code', '0', 'success', '', '寰俊灏忕▼搴忔敮浠�', '1', '2021-12-03 10:41:06', '1', '2023-07-19 20:08:50', X'00'),
+('115', '3', '寰俊 App 鏀粯', 'wx_app', 'pay_channel_code', '0', 'success', '', '寰俊 App 鏀粯', '1', '2021-12-03 10:41:20', '1', '2023-07-19 20:08:56', X'00'),
+('116', '10', '鏀粯瀹� PC 缃戠珯鏀粯', 'alipay_pc', 'pay_channel_code', '0', 'primary', '', '鏀粯瀹� PC 缃戠珯鏀粯', '1', '2021-12-03 10:42:09', '1', '2023-07-19 20:09:12', X'00'),
+('117', '11', '鏀粯瀹� Wap 缃戠珯鏀粯', 'alipay_wap', 'pay_channel_code', '0', 'primary', '', '鏀粯瀹� Wap 缃戠珯鏀粯', '1', '2021-12-03 10:42:26', '1', '2023-07-19 20:09:16', X'00'),
+('118', '12', '鏀粯瀹� App 鏀粯', 'alipay_app', 'pay_channel_code', '0', 'primary', '', '鏀粯瀹� App 鏀粯', '1', '2021-12-03 10:42:55', '1', '2023-07-19 20:09:20', X'00'),
+('119', '14', '鏀粯瀹濇壂鐮佹敮浠�', 'alipay_qr', 'pay_channel_code', '0', 'primary', '', '鏀粯瀹濇壂鐮佹敮浠�', '1', '2021-12-03 10:43:10', '1', '2023-07-19 20:09:28', X'00'),
+('120', '10', '閫氱煡鎴愬姛', '10', 'pay_notify_status', '0', 'success', '', '閫氱煡鎴愬姛', '1', '2021-12-03 11:02:41', '1', '2023-07-19 10:08:19', X'00'),
+('121', '20', '閫氱煡澶辫触', '20', 'pay_notify_status', '0', 'danger', '', '閫氱煡澶辫触', '1', '2021-12-03 11:02:59', '1', '2023-07-19 10:08:21', X'00'),
+('122', '0', '绛夊緟閫氱煡', '0', 'pay_notify_status', '0', 'info', '', '鏈�氱煡', '1', '2021-12-03 11:03:10', '1', '2023-07-19 10:08:24', X'00'),
+('123', '10', '鏀粯鎴愬姛', '10', 'pay_order_status', '0', 'success', '', '鏀粯鎴愬姛', '1', '2021-12-03 11:18:29', '1', '2023-07-19 18:04:28', X'00'),
+('124', '30', '鏀粯鍏抽棴', '30', 'pay_order_status', '0', 'info', '', '鏀粯鍏抽棴', '1', '2021-12-03 11:18:42', '1', '2023-07-19 18:05:07', X'00'),
+('125', '0', '绛夊緟鏀粯', '0', 'pay_order_status', '0', 'info', '', '鏈敮浠�', '1', '2021-12-03 11:18:18', '1', '2023-07-19 18:04:15', X'00'),
+('600', '5', '棣栭〉', '1', 'promotion_banner_position', '0', 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', X'00'),
+('601', '4', '绉掓潃娲诲姩椤�', '2', 'promotion_banner_position', '0', 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', X'00'),
+('602', '3', '鐮嶄环娲诲姩椤�', '3', 'promotion_banner_position', '0', 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', X'00'),
+('603', '2', '闄愭椂鎶樻墸椤�', '4', 'promotion_banner_position', '0', 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', X'00'),
+('604', '1', '婊″噺閫侀〉', '5', 'promotion_banner_position', '0', 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', X'00'),
+('1118', '0', '绛夊緟閫�娆�', '0', 'pay_refund_status', '0', 'info', '', '绛夊緟閫�娆�', '1', '2021-12-10 16:44:59', '1', '2023-07-19 10:14:39', X'00'),
+('1119', '20', '閫�娆惧け璐�', '20', 'pay_refund_status', '0', 'danger', '', '閫�娆惧け璐�', '1', '2021-12-10 16:45:10', '1', '2023-07-19 10:15:10', X'00'),
+('1124', '10', '閫�娆炬垚鍔�', '10', 'pay_refund_status', '0', 'success', '', '閫�娆炬垚鍔�', '1', '2021-12-10 16:46:26', '1', '2023-07-19 10:15:00', X'00'),
+('1127', '1', '瀹℃壒涓�', '1', 'bpm_process_instance_status', '0', 'default', '', '娴佺▼瀹炰緥鐨勭姸鎬� - 杩涜涓�', '1', '2022-01-07 23:47:22', '1', '2024-03-16 16:11:45', X'00'),
+('1128', '2', '瀹℃壒閫氳繃', '2', 'bpm_process_instance_status', '0', 'success', '', '娴佺▼瀹炰緥鐨勭姸鎬� - 宸插畬鎴�', '1', '2022-01-07 23:47:49', '1', '2024-03-16 16:11:54', X'00'),
+('1129', '1', '瀹℃壒涓�', '1', 'bpm_task_status', '0', 'primary', '', '娴佺▼瀹炰緥鐨勭粨鏋� - 澶勭悊涓�', '1', '2022-01-07 23:48:32', '1', '2024-03-08 22:41:37', X'00'),
+('1130', '2', '瀹℃壒閫氳繃', '2', 'bpm_task_status', '0', 'success', '', '娴佺▼瀹炰緥鐨勭粨鏋� - 閫氳繃', '1', '2022-01-07 23:48:45', '1', '2024-03-08 22:41:38', X'00'),
+('1131', '3', '瀹℃壒涓嶉�氳繃', '3', 'bpm_task_status', '0', 'danger', '', '娴佺▼瀹炰緥鐨勭粨鏋� - 涓嶉�氳繃', '1', '2022-01-07 23:48:55', '1', '2024-03-08 22:41:38', X'00'),
+('1132', '4', '宸插彇娑�', '4', 'bpm_task_status', '0', 'info', '', '娴佺▼瀹炰緥鐨勭粨鏋� - 鎾ら攢', '1', '2022-01-07 23:49:06', '1', '2024-03-08 22:41:39', X'00'),
+('1133', '10', '娴佺▼琛ㄥ崟', '10', 'bpm_model_form_type', '0', '', '', '娴佺▼鐨勮〃鍗曠被鍨� - 娴佺▼琛ㄥ崟', '103', '2022-01-11 23:51:30', '103', '2022-01-11 23:51:30', X'00'),
+('1134', '20', '涓氬姟琛ㄥ崟', '20', 'bpm_model_form_type', '0', '', '', '娴佺▼鐨勮〃鍗曠被鍨� - 涓氬姟琛ㄥ崟', '103', '2022-01-11 23:51:47', '103', '2022-01-11 23:51:47', X'00'),
+('1135', '10', '瑙掕壊', '10', 'bpm_task_candidate_strategy', '0', 'info', '', '浠诲姟鍒嗛厤瑙勫垯鐨勭被鍨� - 瑙掕壊', '103', '2022-01-12 23:21:22', '1', '2024-03-06 02:53:16', X'00'),
+('1136', '20', '閮ㄩ棬鐨勬垚鍛�', '20', 'bpm_task_candidate_strategy', '0', 'primary', '', '浠诲姟鍒嗛厤瑙勫垯鐨勭被鍨� - 閮ㄩ棬鐨勬垚鍛�', '103', '2022-01-12 23:21:47', '1', '2024-03-06 02:53:17', X'00'),
+('1137', '21', '閮ㄩ棬鐨勮礋璐d汉', '21', 'bpm_task_candidate_strategy', '0', 'primary', '', '浠诲姟鍒嗛厤瑙勫垯鐨勭被鍨� - 閮ㄩ棬鐨勮礋璐d汉', '103', '2022-01-12 23:33:36', '1', '2024-03-06 02:53:18', X'00'),
+('1138', '30', '鐢ㄦ埛', '30', 'bpm_task_candidate_strategy', '0', 'info', '', '浠诲姟鍒嗛厤瑙勫垯鐨勭被鍨� - 鐢ㄦ埛', '103', '2022-01-12 23:34:02', '1', '2024-03-06 02:53:19', X'00'),
+('1139', '40', '鐢ㄦ埛缁�', '40', 'bpm_task_candidate_strategy', '0', 'warning', '', '浠诲姟鍒嗛厤瑙勫垯鐨勭被鍨� - 鐢ㄦ埛缁�', '103', '2022-01-12 23:34:21', '1', '2024-03-06 02:53:20', X'00'),
+('1140', '60', '娴佺▼琛ㄨ揪寮�', '60', 'bpm_task_candidate_strategy', '0', 'danger', '', '浠诲姟鍒嗛厤瑙勫垯鐨勭被鍨� - 娴佺▼琛ㄨ揪寮�', '103', '2022-01-12 23:34:43', '1', '2024-03-06 02:53:20', X'00'),
+('1141', '22', '宀椾綅', '22', 'bpm_task_candidate_strategy', '0', 'success', '', '浠诲姟鍒嗛厤瑙勫垯鐨勭被鍨� - 宀椾綅', '103', '2022-01-14 18:41:55', '1', '2024-03-06 02:53:21', X'00'),
+('1145', '1', '绠$悊鍚庡彴', '1', 'infra_codegen_scene', '0', '', '', '浠g爜鐢熸垚鐨勫満鏅灇涓� - 绠$悊鍚庡彴', '1', '2022-02-02 13:15:06', '1', '2022-03-10 16:32:59', X'00'),
+('1146', '2', '鐢ㄦ埛 APP', '2', 'infra_codegen_scene', '0', '', '', '浠g爜鐢熸垚鐨勫満鏅灇涓� - 鐢ㄦ埛 APP', '1', '2022-02-02 13:15:19', '1', '2022-03-10 16:33:03', X'00'),
+('1150', '1', '鏁版嵁搴�', '1', 'infra_file_storage', '0', 'default', '', NULL, '1', '2022-03-15 00:25:28', '1', '2022-03-15 00:25:28', X'00'),
+('1151', '10', '鏈湴纾佺洏', '10', 'infra_file_storage', '0', 'default', '', NULL, '1', '2022-03-15 00:25:41', '1', '2022-03-15 00:25:56', X'00'),
+('1152', '11', 'FTP 鏈嶅姟鍣�', '11', 'infra_file_storage', '0', 'default', '', NULL, '1', '2022-03-15 00:26:06', '1', '2022-03-15 00:26:10', X'00'),
+('1153', '12', 'SFTP 鏈嶅姟鍣�', '12', 'infra_file_storage', '0', 'default', '', NULL, '1', '2022-03-15 00:26:22', '1', '2022-03-15 00:26:22', X'00'),
+('1154', '20', 'S3 瀵硅薄瀛樺偍', '20', 'infra_file_storage', '0', 'default', '', NULL, '1', '2022-03-15 00:26:31', '1', '2022-03-15 00:26:45', X'00'),
+('1155', '103', '鐭俊鐧诲綍', '103', 'system_login_type', '0', 'default', '', NULL, '1', '2022-05-09 23:57:58', '1', '2022-05-09 23:58:09', X'00'),
+('1156', '1', 'password', 'password', 'system_oauth2_grant_type', '0', 'default', '', '瀵嗙爜妯″紡', '1', '2022-05-12 00:22:05', '1', '2022-05-11 16:26:01', X'00'),
+('1157', '2', 'authorization_code', 'authorization_code', 'system_oauth2_grant_type', '0', 'primary', '', '鎺堟潈鐮佹ā寮�', '1', '2022-05-12 00:22:59', '1', '2022-05-11 16:26:02', X'00'),
+('1158', '3', 'implicit', 'implicit', 'system_oauth2_grant_type', '0', 'success', '', '绠�鍖栨ā寮�', '1', '2022-05-12 00:23:40', '1', '2022-05-11 16:26:05', X'00'),
+('1159', '4', 'client_credentials', 'client_credentials', 'system_oauth2_grant_type', '0', 'default', '', '瀹㈡埛绔ā寮�', '1', '2022-05-12 00:23:51', '1', '2022-05-11 16:26:08', X'00'),
+('1160', '5', 'refresh_token', 'refresh_token', 'system_oauth2_grant_type', '0', 'info', '', '鍒锋柊妯″紡', '1', '2022-05-12 00:24:02', '1', '2022-05-11 16:26:11', X'00'),
+('1162', '1', '閿�鍞腑', '1', 'product_spu_status', '0', 'success', '', '鍟嗗搧 SPU 鐘舵�� - 閿�鍞腑', '1', '2022-10-24 21:19:47', '1', '2022-10-24 21:20:38', X'00'),
+('1163', '0', '浠撳簱涓�', '0', 'product_spu_status', '0', 'info', '', '鍟嗗搧 SPU 鐘舵�� - 浠撳簱涓�', '1', '2022-10-24 21:20:54', '1', '2022-10-24 21:21:22', X'00'),
+('1164', '0', '鍥炴敹绔�', '-1', 'product_spu_status', '0', 'default', '', '鍟嗗搧 SPU 鐘舵�� - 鍥炴敹绔�', '1', '2022-10-24 21:21:11', '1', '2022-10-24 21:21:11', X'00'),
+('1165', '1', '婊″噺', '1', 'promotion_discount_type', '0', 'success', '', '浼樻儬绫诲瀷 - 婊″噺', '1', '2022-11-01 12:46:41', '1', '2022-11-01 12:50:11', X'00'),
+('1166', '2', '鎶樻墸', '2', 'promotion_discount_type', '0', 'primary', '', '浼樻儬绫诲瀷 - 鎶樻墸', '1', '2022-11-01 12:46:51', '1', '2022-11-01 12:50:08', X'00'),
+('1167', '1', '鍥哄畾鏃ユ湡', '1', 'promotion_coupon_template_validity_type', '0', 'default', '', '浼樻儬鍔垫ā鏉跨殑鏈夐檺鏈熺被鍨� - 鍥哄畾鏃ユ湡', '1', '2022-11-02 00:07:34', '1', '2022-11-04 00:07:49', X'00'),
+('1168', '2', '棰嗗彇涔嬪悗', '2', 'promotion_coupon_template_validity_type', '0', 'default', '', '浼樻儬鍔垫ā鏉跨殑鏈夐檺鏈熺被鍨� - 棰嗗彇涔嬪悗', '1', '2022-11-02 00:07:54', '1', '2022-11-04 00:07:52', X'00'),
+('1169', '1', '閫氱敤鍔�', '1', 'promotion_product_scope', '0', 'default', '', '钀ラ攢鐨勫晢鍝佽寖鍥� - 鍏ㄩ儴鍟嗗搧鍙備笌', '1', '2022-11-02 00:28:22', '1', '2023-09-28 00:27:42', X'00'),
+('1170', '2', '鍟嗗搧鍔�', '2', 'promotion_product_scope', '0', 'default', '', '钀ラ攢鐨勫晢鍝佽寖鍥� - 鎸囧畾鍟嗗搧鍙備笌', '1', '2022-11-02 00:28:34', '1', '2023-09-28 00:27:44', X'00'),
+('1171', '1', '鏈娇鐢�', '1', 'promotion_coupon_status', '0', 'primary', '', '浼樻儬鍔电殑鐘舵�� - 宸查鍙�', '1', '2022-11-04 00:15:08', '1', '2023-10-03 12:54:38', X'00'),
+('1172', '2', '宸蹭娇鐢�', '2', 'promotion_coupon_status', '0', 'success', '', '浼樻儬鍔电殑鐘舵�� - 宸蹭娇鐢�', '1', '2022-11-04 00:15:21', '1', '2022-11-04 19:16:08', X'00'),
+('1173', '3', '宸茶繃鏈�', '3', 'promotion_coupon_status', '0', 'info', '', '浼樻儬鍔电殑鐘舵�� - 宸茶繃鏈�', '1', '2022-11-04 00:15:43', '1', '2022-11-04 19:16:12', X'00'),
+('1174', '1', '鐩存帴棰嗗彇', '1', 'promotion_coupon_take_type', '0', 'primary', '', '浼樻儬鍔电殑棰嗗彇鏂瑰紡 - 鐩存帴棰嗗彇', '1', '2022-11-04 19:13:00', '1', '2022-11-04 19:13:25', X'00'),
+('1175', '2', '鎸囧畾鍙戞斁', '2', 'promotion_coupon_take_type', '0', 'success', '', '浼樻儬鍔电殑棰嗗彇鏂瑰紡 - 鎸囧畾鍙戞斁', '1', '2022-11-04 19:13:13', '1', '2022-11-04 19:14:48', X'00'),
+('1176', '10', '鏈紑濮�', '10', 'promotion_activity_status', '0', 'primary', '', '淇冮攢娲诲姩鐨勭姸鎬佹灇涓� - 鏈紑濮�', '1', '2022-11-04 22:54:49', '1', '2022-11-04 22:55:53', X'00'),
+('1177', '20', '杩涜涓�', '20', 'promotion_activity_status', '0', 'success', '', '淇冮攢娲诲姩鐨勭姸鎬佹灇涓� - 杩涜涓�', '1', '2022-11-04 22:55:06', '1', '2022-11-04 22:55:20', X'00'),
+('1178', '30', '宸茬粨鏉�', '30', 'promotion_activity_status', '0', 'info', '', '淇冮攢娲诲姩鐨勭姸鎬佹灇涓� - 宸茬粨鏉�', '1', '2022-11-04 22:55:41', '1', '2022-11-04 22:55:41', X'00'),
+('1179', '40', '宸插叧闂�', '40', 'promotion_activity_status', '0', 'warning', '', '淇冮攢娲诲姩鐨勭姸鎬佹灇涓� - 宸插叧闂�', '1', '2022-11-04 22:56:10', '1', '2022-11-04 22:56:18', X'00'),
+('1180', '10', '婊� N 鍏�', '10', 'promotion_condition_type', '0', 'primary', '', '钀ラ攢鐨勬潯浠剁被鍨� - 婊� N 鍏�', '1', '2022-11-04 22:59:45', '1', '2022-11-04 22:59:45', X'00'),
+('1181', '20', '婊� N 浠�', '20', 'promotion_condition_type', '0', 'success', '', '钀ラ攢鐨勬潯浠剁被鍨� - 婊� N 浠�', '1', '2022-11-04 23:00:02', '1', '2022-11-04 23:00:02', X'00'),
+('1182', '10', '鐢宠鍞悗', '10', 'trade_after_sale_status', '0', 'primary', '', '浜ゆ槗鍞悗鐘舵�� - 鐢宠鍞悗', '1', '2022-11-19 20:53:33', '1', '2022-11-19 20:54:42', X'00'),
+('1183', '20', '鍟嗗搧寰呴��璐�', '20', 'trade_after_sale_status', '0', 'primary', '', '浜ゆ槗鍞悗鐘舵�� - 鍟嗗搧寰呴��璐�', '1', '2022-11-19 20:54:36', '1', '2022-11-19 20:58:58', X'00'),
+('1184', '30', '鍟嗗寰呮敹璐�', '30', 'trade_after_sale_status', '0', 'primary', '', '浜ゆ槗鍞悗鐘舵�� - 鍟嗗寰呮敹璐�', '1', '2022-11-19 20:56:56', '1', '2022-11-19 20:59:20', X'00'),
+('1185', '40', '绛夊緟閫�娆�', '40', 'trade_after_sale_status', '0', 'primary', '', '浜ゆ槗鍞悗鐘舵�� - 绛夊緟閫�娆�', '1', '2022-11-19 20:59:54', '1', '2022-11-19 21:00:01', X'00'),
+('1186', '50', '閫�娆炬垚鍔�', '50', 'trade_after_sale_status', '0', 'default', '', '浜ゆ槗鍞悗鐘舵�� - 閫�娆炬垚鍔�', '1', '2022-11-19 21:00:33', '1', '2022-11-19 21:00:33', X'00'),
+('1187', '61', '涔板鍙栨秷', '61', 'trade_after_sale_status', '0', 'info', '', '浜ゆ槗鍞悗鐘舵�� - 涔板鍙栨秷', '1', '2022-11-19 21:01:29', '1', '2022-11-19 21:01:29', X'00'),
+('1188', '62', '鍟嗗鎷掔粷', '62', 'trade_after_sale_status', '0', 'info', '', '浜ゆ槗鍞悗鐘舵�� - 鍟嗗鎷掔粷', '1', '2022-11-19 21:02:17', '1', '2022-11-19 21:02:17', X'00'),
+('1189', '63', '鍟嗗鎷掓敹璐�', '63', 'trade_after_sale_status', '0', 'info', '', '浜ゆ槗鍞悗鐘舵�� - 鍟嗗鎷掓敹璐�', '1', '2022-11-19 21:02:37', '1', '2022-11-19 21:03:07', X'00'),
+('1190', '10', '鍞腑閫�娆�', '10', 'trade_after_sale_type', '0', 'success', '', '浜ゆ槗鍞悗鐨勭被鍨� - 鍞腑閫�娆�', '1', '2022-11-19 21:05:05', '1', '2022-11-19 21:38:23', X'00'),
+('1191', '20', '鍞悗閫�娆�', '20', 'trade_after_sale_type', '0', 'primary', '', '浜ゆ槗鍞悗鐨勭被鍨� - 鍞悗閫�娆�', '1', '2022-11-19 21:05:32', '1', '2022-11-19 21:38:32', X'00'),
+('1192', '10', '浠呴��娆�', '10', 'trade_after_sale_way', '0', 'primary', '', '浜ゆ槗鍞悗鐨勬柟寮� - 浠呴��娆�', '1', '2022-11-19 21:39:19', '1', '2022-11-19 21:39:19', X'00'),
+('1193', '20', '閫�璐ч��娆�', '20', 'trade_after_sale_way', '0', 'success', '', '浜ゆ槗鍞悗鐨勬柟寮� - 閫�璐ч��娆�', '1', '2022-11-19 21:39:38', '1', '2022-11-19 21:39:49', X'00'),
+('1194', '10', '寰俊灏忕▼搴�', '10', 'terminal', '0', 'default', '', '缁堢 - 寰俊灏忕▼搴�', '1', '2022-12-10 10:51:11', '1', '2022-12-10 10:51:57', X'00'),
+('1195', '20', 'H5 缃戦〉', '20', 'terminal', '0', 'default', '', '缁堢 - H5 缃戦〉', '1', '2022-12-10 10:51:30', '1', '2022-12-10 10:51:59', X'00'),
+('1196', '11', '寰俊鍏紬鍙�', '11', 'terminal', '0', 'default', '', '缁堢 - 寰俊鍏紬鍙�', '1', '2022-12-10 10:54:16', '1', '2022-12-10 10:52:01', X'00'),
+('1197', '31', '鑻规灉 App', '31', 'terminal', '0', 'default', '', '缁堢 - 鑻规灉 App', '1', '2022-12-10 10:54:42', '1', '2022-12-10 10:52:18', X'00'),
+('1198', '32', '瀹夊崜 App', '32', 'terminal', '0', 'default', '', '缁堢 - 瀹夊崜 App', '1', '2022-12-10 10:55:02', '1', '2022-12-10 10:59:17', X'00'),
+('1199', '0', '鏅�氳鍗�', '0', 'trade_order_type', '0', 'default', '', '浜ゆ槗璁㈠崟鐨勭被鍨� - 鏅�氳鍗�', '1', '2022-12-10 16:34:14', '1', '2022-12-10 16:34:14', X'00'),
+('1200', '1', '绉掓潃璁㈠崟', '1', 'trade_order_type', '0', 'default', '', '浜ゆ槗璁㈠崟鐨勭被鍨� - 绉掓潃璁㈠崟', '1', '2022-12-10 16:34:26', '1', '2022-12-10 16:34:26', X'00'),
+('1201', '2', '鐮嶄环璁㈠崟', '2', 'trade_order_type', '0', 'default', '', '浜ゆ槗璁㈠崟鐨勭被鍨� - 鎷煎洟璁㈠崟', '1', '2022-12-10 16:34:36', '1', '2024-09-07 14:18:39', X'00'),
+('1202', '3', '鎷煎洟璁㈠崟', '3', 'trade_order_type', '0', 'default', '', '浜ゆ槗璁㈠崟鐨勭被鍨� - 鐮嶄环璁㈠崟', '1', '2022-12-10 16:34:48', '1', '2024-09-07 14:18:32', X'00'),
+('1203', '0', '寰呮敮浠�', '0', 'trade_order_status', '0', 'default', '', '浜ゆ槗璁㈠崟鐘舵�� - 寰呮敮浠�', '1', '2022-12-10 16:49:29', '1', '2022-12-10 16:49:29', X'00'),
+('1204', '10', '寰呭彂璐�', '10', 'trade_order_status', '0', 'primary', '', '浜ゆ槗璁㈠崟鐘舵�� - 寰呭彂璐�', '1', '2022-12-10 16:49:53', '1', '2022-12-10 16:51:17', X'00'),
+('1205', '20', '宸插彂璐�', '20', 'trade_order_status', '0', 'primary', '', '浜ゆ槗璁㈠崟鐘舵�� - 宸插彂璐�', '1', '2022-12-10 16:50:13', '1', '2022-12-10 16:51:31', X'00'),
+('1206', '30', '宸插畬鎴�', '30', 'trade_order_status', '0', 'success', '', '浜ゆ槗璁㈠崟鐘舵�� - 宸插畬鎴�', '1', '2022-12-10 16:50:30', '1', '2022-12-10 16:51:06', X'00'),
+('1207', '40', '宸插彇娑�', '40', 'trade_order_status', '0', 'danger', '', '浜ゆ槗璁㈠崟鐘舵�� - 宸插彇娑�', '1', '2022-12-10 16:50:50', '1', '2022-12-10 16:51:00', X'00'),
+('1208', '0', '鏈敭鍚�', '0', 'trade_order_item_after_sale_status', '0', 'info', '', '浜ゆ槗璁㈠崟椤圭殑鍞悗鐘舵�� - 鏈敭鍚�', '1', '2022-12-10 20:58:42', '1', '2022-12-10 20:59:29', X'00'),
+('1209', '10', '鍞悗涓�', '10', 'trade_order_item_after_sale_status', '0', 'primary', '', '浜ゆ槗璁㈠崟椤圭殑鍞悗鐘舵�� - 鍞悗涓�', '1', '2022-12-10 20:59:21', '1', '2024-07-21 17:01:24', X'00'),
+('1210', '20', '宸查��娆�', '20', 'trade_order_item_after_sale_status', '0', 'success', '', '浜ゆ槗璁㈠崟椤圭殑鍞悗鐘舵�� - 宸查��娆�', '1', '2022-12-10 20:59:46', '1', '2024-07-21 17:01:35', X'00'),
+('1211', '1', '瀹屽叏鍖归厤', '1', 'mp_auto_reply_request_match', '0', 'primary', '', '鍏紬鍙疯嚜鍔ㄥ洖澶嶇殑璇锋眰鍏抽敭瀛楀尮閰嶆ā寮� - 瀹屽叏鍖归厤', '1', '2023-01-16 23:30:39', '1', '2023-01-16 23:31:00', X'00'),
+('1212', '2', '鍗婂尮閰�', '2', 'mp_auto_reply_request_match', '0', 'success', '', '鍏紬鍙疯嚜鍔ㄥ洖澶嶇殑璇锋眰鍏抽敭瀛楀尮閰嶆ā寮� - 鍗婂尮閰�', '1', '2023-01-16 23:30:55', '1', '2023-01-16 23:31:10', X'00'),
+('1213', '1', '鏂囨湰', 'text', 'mp_message_type', '0', 'default', '', '鍏紬鍙风殑娑堟伅绫诲瀷 - 鏂囨湰', '1', '2023-01-17 22:17:32', '1', '2023-01-17 22:17:39', X'00'),
+('1214', '2', '鍥剧墖', 'image', 'mp_message_type', '0', 'default', '', '鍏紬鍙风殑娑堟伅绫诲瀷 - 鍥剧墖', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:19:47', X'00'),
+('1215', '3', '璇煶', 'voice', 'mp_message_type', '0', 'default', '', '鍏紬鍙风殑娑堟伅绫诲瀷 - 璇煶', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:20:08', X'00'),
+('1216', '4', '瑙嗛', 'video', 'mp_message_type', '0', 'default', '', '鍏紬鍙风殑娑堟伅绫诲瀷 - 瑙嗛', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:21:08', X'00'),
+('1217', '5', '灏忚棰�', 'shortvideo', 'mp_message_type', '0', 'default', '', '鍏紬鍙风殑娑堟伅绫诲瀷 - 灏忚棰�', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:19:59', X'00'),
+('1218', '6', '鍥炬枃', 'news', 'mp_message_type', '0', 'default', '', '鍏紬鍙风殑娑堟伅绫诲瀷 - 鍥炬枃', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:22:54', X'00'),
+('1219', '7', '闊充箰', 'music', 'mp_message_type', '0', 'default', '', '鍏紬鍙风殑娑堟伅绫诲瀷 - 闊充箰', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:22:54', X'00'),
+('1220', '8', '鍦扮悊浣嶇疆', 'location', 'mp_message_type', '0', 'default', '', '鍏紬鍙风殑娑堟伅绫诲瀷 - 鍦扮悊浣嶇疆', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:23:51', X'00'),
+('1221', '9', '閾炬帴', 'link', 'mp_message_type', '0', 'default', '', '鍏紬鍙风殑娑堟伅绫诲瀷 - 閾炬帴', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:24:49', X'00'),
+('1222', '10', '浜嬩欢', 'event', 'mp_message_type', '0', 'default', '', '鍏紬鍙风殑娑堟伅绫诲瀷 - 浜嬩欢', '1', '2023-01-17 22:17:32', '1', '2023-01-17 14:24:49', X'00'),
+('1223', '0', '鍒濆鍖�', '0', 'system_mail_send_status', '0', 'primary', '', '閭欢鍙戦�佺姸鎬� - 鍒濆鍖朶n', '1', '2023-01-26 09:53:49', '1', '2023-01-26 16:36:14', X'00'),
+('1224', '10', '鍙戦�佹垚鍔�', '10', 'system_mail_send_status', '0', 'success', '', '閭欢鍙戦�佺姸鎬� - 鍙戦�佹垚鍔�', '1', '2023-01-26 09:54:28', '1', '2023-01-26 16:36:22', X'00'),
+('1225', '20', '鍙戦�佸け璐�', '20', 'system_mail_send_status', '0', 'danger', '', '閭欢鍙戦�佺姸鎬� - 鍙戦�佸け璐�', '1', '2023-01-26 09:54:50', '1', '2023-01-26 16:36:26', X'00'),
+('1226', '30', '涓嶅彂閫�', '30', 'system_mail_send_status', '0', 'info', '', '閭欢鍙戦�佺姸鎬� - 涓嶅彂閫�', '1', '2023-01-26 09:55:06', '1', '2023-01-26 16:36:36', X'00'),
+('1227', '1', '閫氱煡鍏憡', '1', 'system_notify_template_type', '0', 'primary', '', '绔欏唴淇℃ā鐗堢殑绫诲瀷 - 閫氱煡鍏憡', '1', '2023-01-28 10:35:59', '1', '2023-01-28 10:35:59', X'00'),
+('1228', '2', '绯荤粺娑堟伅', '2', 'system_notify_template_type', '0', 'success', '', '绔欏唴淇℃ā鐗堢殑绫诲瀷 - 绯荤粺娑堟伅', '1', '2023-01-28 10:36:20', '1', '2023-01-28 10:36:25', X'00'),
+('1230', '13', '鏀粯瀹濇潯鐮佹敮浠�', 'alipay_bar', 'pay_channel_code', '0', 'primary', '', '鏀粯瀹濇潯鐮佹敮浠�', '1', '2023-02-18 23:32:24', '1', '2023-07-19 20:09:23', X'00'),
+('1231', '10', 'Vue2 Element UI 鏍囧噯妯$増', '10', 'infra_codegen_front_type', '0', '', '', '', '1', '2023-04-13 00:03:55', '1', '2023-04-13 00:03:55', X'00'),
+('1232', '20', 'Vue3 Element Plus 鏍囧噯妯$増', '20', 'infra_codegen_front_type', '0', '', '', '', '1', '2023-04-13 00:04:08', '1', '2023-04-13 00:04:08', X'00'),
+('1234', '30', 'Vben2.0 Ant Design Schema 妯$増', '30', 'infra_codegen_front_type', '1', '', '', '', '1', '2023-04-13 00:04:26', '1', '2025-07-27 10:55:14', X'00'),
+('1244', '0', '鎸変欢', '1', 'trade_delivery_express_charge_mode', '0', '', '', '', '1', '2023-05-21 22:46:40', '1', '2023-05-21 22:46:40', X'00'),
+('1245', '1', '鎸夐噸閲�', '2', 'trade_delivery_express_charge_mode', '0', '', '', '', '1', '2023-05-21 22:46:58', '1', '2023-05-21 22:46:58', X'00'),
+('1246', '2', '鎸変綋绉�', '3', 'trade_delivery_express_charge_mode', '0', '', '', '', '1', '2023-05-21 22:47:18', '1', '2023-05-21 22:47:18', X'00'),
+('1335', '11', '璁㈠崟绉垎鎶垫墸', '11', 'member_point_biz_type', '0', '', '', '', '1', '2023-06-10 12:15:27', '1', '2023-10-11 07:41:43', X'00'),
+('1336', '1', '绛惧埌', '1', 'member_point_biz_type', '0', '', '', '', '1', '2023-06-10 12:15:48', '1', '2023-08-20 11:59:53', X'00'),
+('1341', '20', '宸查��娆�', '20', 'pay_order_status', '0', 'danger', '', '宸查��娆�', '1', '2023-07-19 18:05:37', '1', '2023-07-19 18:05:37', X'00'),
+('1342', '21', '璇锋眰鎴愬姛锛屼絾鏄粨鏋滃け璐�', '21', 'pay_notify_status', '0', 'warning', '', '璇锋眰鎴愬姛锛屼絾鏄粨鏋滃け璐�', '1', '2023-07-19 18:10:47', '1', '2023-07-19 18:11:38', X'00'),
+('1343', '22', '璇锋眰澶辫触', '22', 'pay_notify_status', '0', 'warning', '', NULL, '1', '2023-07-19 18:11:05', '1', '2023-07-19 18:11:27', X'00'),
+('1344', '4', '寰俊鎵爜鏀粯', 'wx_native', 'pay_channel_code', '0', 'success', '', '寰俊鎵爜鏀粯', '1', '2023-07-19 20:07:47', '1', '2023-07-19 20:09:03', X'00'),
+('1345', '5', '寰俊鏉$爜鏀粯', 'wx_bar', 'pay_channel_code', '0', 'success', '', '寰俊鏉$爜鏀粯\n', '1', '2023-07-19 20:08:06', '1', '2023-07-19 20:09:08', X'00'),
+('1346', '1', '鏀粯鍗�', '1', 'pay_notify_type', '0', 'primary', '', '鏀粯鍗�', '1', '2023-07-20 12:23:17', '1', '2023-07-20 12:23:17', X'00'),
+('1347', '2', '閫�娆惧崟', '2', 'pay_notify_type', '0', 'danger', '', NULL, '1', '2023-07-20 12:23:26', '1', '2023-07-20 12:23:26', X'00'),
+('1348', '20', '妯℃嫙鏀粯', 'mock', 'pay_channel_code', '0', 'default', '', '妯℃嫙鏀粯', '1', '2023-07-29 11:10:51', '1', '2023-07-29 03:14:10', X'00'),
+('1349', '12', '璁㈠崟绉垎鎶垫墸锛堟暣鍗曞彇娑堬級', '12', 'member_point_biz_type', '0', '', '', '', '1', '2023-08-20 12:00:03', '1', '2023-10-11 07:42:01', X'00'),
+('1350', '0', '绠$悊鍛樿皟鏁�', '0', 'member_experience_biz_type', '0', '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', X'00'),
+('1351', '1', '閭�鏂板鍔�', '1', 'member_experience_biz_type', '0', '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', X'00'),
+('1352', '11', '涓嬪崟濂栧姳', '11', 'member_experience_biz_type', '0', 'success', '', NULL, '', '2023-08-22 12:41:01', '1', '2023-10-11 07:45:09', X'00'),
+('1353', '12', '涓嬪崟濂栧姳锛堟暣鍗曞彇娑堬級', '12', 'member_experience_biz_type', '0', 'warning', '', NULL, '', '2023-08-22 12:41:01', '1', '2023-10-11 07:45:01', X'00'),
+('1354', '4', '绛惧埌濂栧姳', '4', 'member_experience_biz_type', '0', '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', X'00'),
+('1355', '5', '鎶藉濂栧姳', '5', 'member_experience_biz_type', '0', '', '', NULL, '', '2023-08-22 12:41:01', '', '2023-08-22 12:41:01', X'00'),
+('1356', '1', '蹇�掑彂璐�', '1', 'trade_delivery_type', '0', '', '', '', '1', '2023-08-23 00:04:55', '1', '2023-08-23 00:04:55', X'00'),
+('1357', '2', '鐢ㄦ埛鑷彁', '2', 'trade_delivery_type', '0', '', '', '', '1', '2023-08-23 00:05:05', '1', '2023-08-23 00:05:05', X'00'),
+('1358', '3', '鍝佺被鍔�', '3', 'promotion_product_scope', '0', 'default', '', '', '1', '2023-09-01 23:43:07', '1', '2023-09-28 00:27:47', X'00'),
+('1359', '1', '浜轰汉鍒嗛攢', '1', 'brokerage_enabled_condition', '0', '', '', '鎵�鏈夌敤鎴烽兘鍙互鍒嗛攢', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1360', '2', '鎸囧畾鍒嗛攢', '2', 'brokerage_enabled_condition', '0', '', '', '浠呭彲鍚庡彴鎵嬪姩璁剧疆鎺ㄥ箍鍛�', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1361', '1', '棣栨缁戝畾', '1', 'brokerage_bind_mode', '0', '', '', '鍙鐢ㄦ埛娌℃湁鎺ㄥ箍浜猴紝闅忔椂閮藉彲浠ョ粦瀹氭帹骞垮叧绯�', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1362', '2', '娉ㄥ唽缁戝畾', '2', 'brokerage_bind_mode', '0', '', '', '浠呮柊鐢ㄦ埛娉ㄥ唽鏃舵墠鑳界粦瀹氭帹骞垮叧绯�', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1363', '3', '瑕嗙洊缁戝畾', '3', 'brokerage_bind_mode', '0', '', '', '濡傛灉鐢ㄦ埛宸茬粡鏈夋帹骞夸汉锛屾帹骞夸汉浼氳鍙樻洿', '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1364', '1', '閽卞寘', '1', 'brokerage_withdraw_type', '0', '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1365', '2', '閾惰鍗�', '2', 'brokerage_withdraw_type', '0', '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1366', '3', '寰俊鏀舵鐮�', '3', 'brokerage_withdraw_type', '0', '', '', '鎵嬪姩鎵撴', '', '2023-09-28 02:46:05', '1', '2025-05-10 08:24:25', X'00'),
+('1367', '4', '鏀粯瀹濇敹娆剧爜', '4', 'brokerage_withdraw_type', '0', '', '', '鎵嬪姩鎵撴', '', '2023-09-28 02:46:05', '1', '2025-05-10 08:24:37', X'00'),
+('1368', '1', '璁㈠崟杩斾剑', '1', 'brokerage_record_biz_type', '0', '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1369', '2', '鐢宠鎻愮幇', '2', 'brokerage_record_biz_type', '0', '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1370', '3', '鐢宠鎻愮幇椹冲洖', '3', 'brokerage_record_biz_type', '0', '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1371', '0', '寰呯粨绠�', '0', 'brokerage_record_status', '0', '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1372', '1', '宸茬粨绠�', '1', 'brokerage_record_status', '0', '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1373', '2', '宸插彇娑�', '2', 'brokerage_record_status', '0', '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1374', '0', '瀹℃牳涓�', '0', 'brokerage_withdraw_status', '0', '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1375', '10', '瀹℃牳閫氳繃', '10', 'brokerage_withdraw_status', '0', 'success', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1376', '11', '鎻愮幇鎴愬姛', '11', 'brokerage_withdraw_status', '0', 'success', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1377', '20', '瀹℃牳涓嶉�氳繃', '20', 'brokerage_withdraw_status', '0', 'danger', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1378', '21', '鎻愮幇澶辫触', '21', 'brokerage_withdraw_status', '0', 'danger', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1379', '0', '宸ュ晢閾惰', '0', 'brokerage_bank_name', '0', '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1380', '1', '寤鸿閾惰', '1', 'brokerage_bank_name', '0', '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1381', '2', '鍐滀笟閾惰', '2', 'brokerage_bank_name', '0', '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1382', '3', '涓浗閾惰', '3', 'brokerage_bank_name', '0', '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1383', '4', '浜ら�氶摱琛�', '4', 'brokerage_bank_name', '0', '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1384', '5', '鎷涘晢閾惰', '5', 'brokerage_bank_name', '0', '', '', NULL, '', '2023-09-28 02:46:05', '', '2023-09-28 02:46:05', X'00'),
+('1385', '21', '閽卞寘', 'wallet', 'pay_channel_code', '0', 'primary', '', '', '1', '2023-10-01 21:46:19', '1', '2023-10-01 21:48:01', X'00'),
+('1386', '1', '鐮嶄环涓�', '1', 'promotion_bargain_record_status', '0', 'default', '', '', '1', '2023-10-05 10:41:26', '1', '2023-10-05 10:41:26', X'00'),
+('1387', '2', '鐮嶄环鎴愬姛', '2', 'promotion_bargain_record_status', '0', 'success', '', '', '1', '2023-10-05 10:41:39', '1', '2023-10-05 10:41:39', X'00'),
+('1388', '3', '鐮嶄环澶辫触', '3', 'promotion_bargain_record_status', '0', 'warning', '', '', '1', '2023-10-05 10:41:57', '1', '2023-10-05 10:41:57', X'00'),
+('1389', '0', '鎷煎洟涓�', '0', 'promotion_combination_record_status', '0', '', '', '', '1', '2023-10-08 07:24:44', '1', '2024-10-13 10:08:17', X'00'),
+('1390', '1', '鎷煎洟鎴愬姛', '1', 'promotion_combination_record_status', '0', 'success', '', '', '1', '2023-10-08 07:24:56', '1', '2024-10-13 10:08:20', X'00'),
+('1391', '2', '鎷煎洟澶辫触', '2', 'promotion_combination_record_status', '0', 'warning', '', '', '1', '2023-10-08 07:25:11', '1', '2024-10-13 10:08:24', X'00'),
+('1392', '2', '绠$悊鍛樹慨鏀�', '2', 'member_point_biz_type', '0', 'default', '', '', '1', '2023-10-11 07:41:34', '1', '2023-10-11 07:41:34', X'00'),
+('1393', '13', '璁㈠崟绉垎鎶垫墸锛堝崟涓��娆撅級', '13', 'member_point_biz_type', '0', '', '', '', '1', '2023-10-11 07:42:29', '1', '2023-10-11 07:42:29', X'00'),
+('1394', '21', '璁㈠崟绉垎濂栧姳', '21', 'member_point_biz_type', '0', 'default', '', '', '1', '2023-10-11 07:42:44', '1', '2023-10-11 07:42:44', X'00'),
+('1395', '22', '璁㈠崟绉垎濂栧姳锛堟暣鍗曞彇娑堬級', '22', 'member_point_biz_type', '0', 'default', '', '', '1', '2023-10-11 07:42:55', '1', '2023-10-11 07:43:01', X'00'),
+('1396', '23', '璁㈠崟绉垎濂栧姳锛堝崟涓��娆撅級', '23', 'member_point_biz_type', '0', 'default', '', '', '1', '2023-10-11 07:43:16', '1', '2023-10-11 07:43:16', X'00'),
+('1397', '13', '涓嬪崟濂栧姳锛堝崟涓��娆撅級', '13', 'member_experience_biz_type', '0', 'warning', '', '', '1', '2023-10-11 07:45:24', '1', '2023-10-11 07:45:38', X'00'),
+('1398', '5', '缃戜笂杞处', '5', 'crm_receivable_return_type', '0', 'default', '', '', '1', '2023-10-18 21:55:24', '1', '2023-10-18 21:55:24', X'00'),
+('1399', '6', '鏀粯瀹�', '6', 'crm_receivable_return_type', '0', 'default', '', '', '1', '2023-10-18 21:55:38', '1', '2023-10-18 21:55:38', X'00'),
+('1400', '7', '寰俊鏀粯', '7', 'crm_receivable_return_type', '0', 'default', '', '', '1', '2023-10-18 21:55:53', '1', '2023-10-18 21:55:53', X'00'),
+('1401', '8', '鍏朵粬', '8', 'crm_receivable_return_type', '0', 'default', '', '', '1', '2023-10-18 21:56:06', '1', '2023-10-18 21:56:06', X'00'),
+('1402', '1', 'IT', '1', 'crm_customer_industry', '0', 'default', '', '', '1', '2023-10-28 23:02:15', '1', '2024-02-18 23:30:38', X'00'),
+('1403', '2', '閲戣瀺涓�', '2', 'crm_customer_industry', '0', 'default', '', '', '1', '2023-10-28 23:02:29', '1', '2024-02-18 23:30:43', X'00'),
+('1404', '3', '鎴垮湴浜�', '3', 'crm_customer_industry', '0', 'default', '', '', '1', '2023-10-28 23:02:41', '1', '2024-02-18 23:30:48', X'00'),
+('1405', '4', '鍟嗕笟鏈嶅姟', '4', 'crm_customer_industry', '0', 'default', '', '', '1', '2023-10-28 23:02:54', '1', '2024-02-18 23:30:54', X'00'),
+('1406', '5', '杩愯緭/鐗╂祦', '5', 'crm_customer_industry', '0', 'default', '', '', '1', '2023-10-28 23:03:03', '1', '2024-02-18 23:31:00', X'00'),
+('1407', '6', '鐢熶骇', '6', 'crm_customer_industry', '0', 'default', '', '', '1', '2023-10-28 23:03:13', '1', '2024-02-18 23:31:08', X'00'),
+('1408', '7', '鏀垮簻', '7', 'crm_customer_industry', '0', 'default', '', '', '1', '2023-10-28 23:03:27', '1', '2024-02-18 23:31:13', X'00'),
+('1409', '8', '鏂囧寲浼犲獟', '8', 'crm_customer_industry', '0', 'default', '', '', '1', '2023-10-28 23:03:37', '1', '2024-02-18 23:31:20', X'00'),
+('1422', '1', 'A 锛堥噸鐐瑰鎴凤級', '1', 'crm_customer_level', '0', 'primary', '', '', '1', '2023-10-28 23:07:13', '1', '2023-10-28 23:07:13', X'00'),
+('1423', '2', 'B 锛堟櫘閫氬鎴凤級', '2', 'crm_customer_level', '0', 'info', '', '', '1', '2023-10-28 23:07:35', '1', '2023-10-28 23:07:35', X'00'),
+('1424', '3', 'C 锛堥潪浼樺厛瀹㈡埛锛�', '3', 'crm_customer_level', '0', 'default', '', '', '1', '2023-10-28 23:07:53', '1', '2023-10-28 23:07:53', X'00'),
+('1425', '1', '淇冮攢', '1', 'crm_customer_source', '0', 'default', '', '', '1', '2023-10-28 23:08:29', '1', '2023-10-28 23:08:29', X'00'),
+('1426', '2', '鎼滅储寮曟搸', '2', 'crm_customer_source', '0', 'default', '', '', '1', '2023-10-28 23:08:39', '1', '2023-10-28 23:08:39', X'00'),
+('1427', '3', '骞垮憡', '3', 'crm_customer_source', '0', 'default', '', '', '1', '2023-10-28 23:08:47', '1', '2023-10-28 23:08:47', X'00'),
+('1428', '4', '杞粙缁�', '4', 'crm_customer_source', '0', 'default', '', '', '1', '2023-10-28 23:08:58', '1', '2023-10-28 23:08:58', X'00'),
+('1429', '5', '绾夸笂娉ㄥ唽', '5', 'crm_customer_source', '0', 'default', '', '', '1', '2023-10-28 23:09:12', '1', '2023-10-28 23:09:12', X'00'),
+('1430', '6', '绾夸笂鍜ㄨ', '6', 'crm_customer_source', '0', 'default', '', '', '1', '2023-10-28 23:09:22', '1', '2023-10-28 23:09:22', X'00'),
+('1431', '7', '棰勭害涓婇棬', '7', 'crm_customer_source', '0', 'default', '', '', '1', '2023-10-28 23:09:39', '1', '2023-10-28 23:09:39', X'00'),
+('1432', '8', '闄屾嫓', '8', 'crm_customer_source', '0', 'default', '', '', '1', '2023-10-28 23:10:04', '1', '2023-10-28 23:10:04', X'00'),
+('1433', '9', '鐢佃瘽鍜ㄨ', '9', 'crm_customer_source', '0', 'default', '', '', '1', '2023-10-28 23:10:18', '1', '2023-10-28 23:10:18', X'00'),
+('1434', '10', '閭欢鍜ㄨ', '10', 'crm_customer_source', '0', 'default', '', '', '1', '2023-10-28 23:10:33', '1', '2023-10-28 23:10:33', X'00'),
+('1435', '10', 'Gitee', '10', 'system_social_type', '0', '', '', '', '1', '2023-11-04 13:04:42', '1', '2023-11-04 13:04:42', X'00'),
+('1436', '20', '閽夐拤', '20', 'system_social_type', '0', '', '', '', '1', '2023-11-04 13:04:54', '1', '2023-11-04 13:04:54', X'00'),
+('1437', '30', '浼佷笟寰俊', '30', 'system_social_type', '0', '', '', '', '1', '2023-11-04 13:05:09', '1', '2023-11-04 13:05:09', X'00'),
+('1438', '31', '寰俊鍏紬骞冲彴', '31', 'system_social_type', '0', '', '', '', '1', '2023-11-04 13:05:18', '1', '2023-11-04 13:05:18', X'00'),
+('1439', '32', '寰俊寮�鏀惧钩鍙�', '32', 'system_social_type', '0', '', '', '', '1', '2023-11-04 13:05:30', '1', '2023-11-04 13:05:30', X'00'),
+('1440', '34', '寰俊灏忕▼搴�', '34', 'system_social_type', '0', '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', X'00'),
+('1441', '1', '涓婃灦', '1', 'crm_product_status', '0', 'success', '', '', '1', '2023-10-30 21:49:34', '1', '2023-10-30 21:49:34', X'00'),
+('1442', '0', '涓嬫灦', '0', 'crm_product_status', '0', 'success', '', '', '1', '2023-10-30 21:49:13', '1', '2023-10-30 21:49:13', X'00'),
+('1443', '15', '瀛愯〃', '15', 'infra_codegen_template_type', '0', 'default', '', '', '1', '2023-11-13 23:06:16', '1', '2023-11-13 23:06:16', X'00'),
+('1444', '10', '涓昏〃锛堟爣鍑嗘ā寮忥級', '10', 'infra_codegen_template_type', '0', 'default', '', '', '1', '2023-11-14 12:32:49', '1', '2023-11-14 12:32:49', X'00'),
+('1445', '11', '涓昏〃锛圗RP 妯″紡锛�', '11', 'infra_codegen_template_type', '0', 'default', '', '', '1', '2023-11-14 12:33:05', '1', '2023-11-14 12:33:05', X'00'),
+('1446', '12', '涓昏〃锛堝唴宓屾ā寮忥級', '12', 'infra_codegen_template_type', '0', '', '', '', '1', '2023-11-14 12:33:31', '1', '2023-11-14 12:33:31', X'00'),
+('1447', '1', '璐熻矗浜�', '1', 'crm_permission_level', '0', 'default', '', '', '1', '2023-11-30 09:53:12', '1', '2023-11-30 09:53:12', X'00'),
+('1448', '2', '鍙', '2', 'crm_permission_level', '0', '', '', '', '1', '2023-11-30 09:53:29', '1', '2023-11-30 09:53:29', X'00'),
+('1449', '3', '璇诲啓', '3', 'crm_permission_level', '0', '', '', '', '1', '2023-11-30 09:53:36', '1', '2023-11-30 09:53:36', X'00'),
+('1450', '0', '鏈彁浜�', '0', 'crm_audit_status', '0', '', '', '', '1', '2023-11-30 18:56:59', '1', '2023-11-30 18:56:59', X'00'),
+('1451', '10', '瀹℃壒涓�', '10', 'crm_audit_status', '0', '', '', '', '1', '2023-11-30 18:57:10', '1', '2023-11-30 18:57:10', X'00'),
+('1452', '20', '瀹℃牳閫氳繃', '20', 'crm_audit_status', '0', '', '', '', '1', '2023-11-30 18:57:24', '1', '2023-11-30 18:57:24', X'00'),
+('1453', '30', '瀹℃牳涓嶉�氳繃', '30', 'crm_audit_status', '0', '', '', '', '1', '2023-11-30 18:57:32', '1', '2023-11-30 18:57:32', X'00'),
+('1454', '40', '宸插彇娑�', '40', 'crm_audit_status', '0', '', '', '', '1', '2023-11-30 18:57:42', '1', '2023-11-30 18:57:42', X'00'),
+('1456', '1', '鏀エ', '1', 'crm_receivable_return_type', '0', 'default', '', '', '1', '2023-10-18 21:54:29', '1', '2023-10-18 21:54:29', X'00'),
+('1457', '2', '鐜伴噾', '2', 'crm_receivable_return_type', '0', 'default', '', '', '1', '2023-10-18 21:54:41', '1', '2023-10-18 21:54:41', X'00'),
+('1458', '3', '閭斂姹囨', '3', 'crm_receivable_return_type', '0', 'default', '', '', '1', '2023-10-18 21:54:53', '1', '2023-10-18 21:54:53', X'00'),
+('1459', '4', '鐢垫眹', '4', 'crm_receivable_return_type', '0', 'default', '', '', '1', '2023-10-18 21:55:07', '1', '2023-10-18 21:55:07', X'00'),
+('1461', '1', '涓�', '1', 'crm_product_unit', '0', '', '', '', '1', '2023-12-05 23:02:26', '1', '2023-12-05 23:02:26', X'00'),
+('1462', '2', '鍧�', '2', 'crm_product_unit', '0', '', '', '', '1', '2023-12-05 23:02:34', '1', '2023-12-05 23:02:34', X'00'),
+('1463', '3', '鍙�', '3', 'crm_product_unit', '0', '', '', '', '1', '2023-12-05 23:02:57', '1', '2023-12-05 23:02:57', X'00'),
+('1464', '4', '鎶�', '4', 'crm_product_unit', '0', '', '', '', '1', '2023-12-05 23:03:05', '1', '2023-12-05 23:03:05', X'00'),
+('1465', '5', '鏋�', '5', 'crm_product_unit', '0', '', '', '', '1', '2023-12-05 23:03:14', '1', '2023-12-05 23:03:14', X'00'),
+('1466', '6', '鐡�', '6', 'crm_product_unit', '0', '', '', '', '1', '2023-12-05 23:03:20', '1', '2023-12-05 23:03:20', X'00'),
+('1467', '7', '鐩�', '7', 'crm_product_unit', '0', '', '', '', '1', '2023-12-05 23:03:30', '1', '2023-12-05 23:03:30', X'00'),
+('1468', '8', '鍙�', '8', 'crm_product_unit', '0', '', '', '', '1', '2023-12-05 23:03:41', '1', '2023-12-05 23:03:41', X'00'),
+('1469', '9', '鍚�', '9', 'crm_product_unit', '0', '', '', '', '1', '2023-12-05 23:03:48', '1', '2023-12-05 23:03:48', X'00'),
+('1470', '10', '鍗冨厠', '10', 'crm_product_unit', '0', '', '', '', '1', '2023-12-05 23:04:03', '1', '2023-12-05 23:04:03', X'00'),
+('1471', '11', '绫�', '11', 'crm_product_unit', '0', '', '', '', '1', '2023-12-05 23:04:12', '1', '2023-12-05 23:04:12', X'00'),
+('1472', '12', '绠�', '12', 'crm_product_unit', '0', '', '', '', '1', '2023-12-05 23:04:25', '1', '2023-12-05 23:04:25', X'00'),
+('1473', '13', '濂�', '13', 'crm_product_unit', '0', '', '', '', '1', '2023-12-05 23:04:34', '1', '2023-12-05 23:04:34', X'00'),
+('1474', '1', '鎵撶數璇�', '1', 'crm_follow_up_type', '0', '', '', '', '1', '2024-01-15 20:48:20', '1', '2024-01-15 20:48:20', X'00'),
+('1475', '2', '鍙戠煭淇�', '2', 'crm_follow_up_type', '0', '', '', '', '1', '2024-01-15 20:48:31', '1', '2024-01-15 20:48:31', X'00'),
+('1476', '3', '涓婇棬鎷滆', '3', 'crm_follow_up_type', '0', '', '', '', '1', '2024-01-15 20:49:07', '1', '2024-01-15 20:49:07', X'00'),
+('1477', '4', '寰俊娌熼��', '4', 'crm_follow_up_type', '0', '', '', '', '1', '2024-01-15 20:49:15', '1', '2024-01-15 20:49:15', X'00'),
+('1482', '4', '杞处澶辫触', '20', 'pay_transfer_status', '0', 'warning', '', '', '1', '2023-10-28 16:24:16', '1', '2025-05-08 12:59:01', X'00'),
+('1483', '3', '杞处鎴愬姛', '10', 'pay_transfer_status', '0', 'success', '', '', '1', '2023-10-28 16:23:50', '1', '2025-05-08 12:58:58', X'00'),
+('1484', '2', '杞处杩涜涓�', '5', 'pay_transfer_status', '0', 'info', '', '', '1', '2023-10-28 16:23:12', '1', '2025-05-08 12:58:54', X'00'),
+('1485', '1', '绛夊緟杞处', '0', 'pay_transfer_status', '0', 'default', '', '', '1', '2023-10-28 16:21:43', '1', '2023-10-28 16:23:22', X'00'),
+('1486', '10', '鍏跺畠鍏ュ簱', '10', 'erp_stock_record_biz_type', '0', '', '', '', '1', '2024-02-05 18:07:25', '1', '2024-02-05 18:07:43', X'00'),
+('1487', '11', '鍏跺畠鍏ュ簱锛堜綔搴燂級', '11', 'erp_stock_record_biz_type', '0', 'danger', '', '', '1', '2024-02-05 18:08:07', '1', '2024-02-05 19:20:16', X'00'),
+('1488', '20', '鍏跺畠鍑哄簱', '20', 'erp_stock_record_biz_type', '0', '', '', '', '1', '2024-02-05 18:08:51', '1', '2024-02-05 18:08:51', X'00'),
+('1489', '21', '鍏跺畠鍑哄簱锛堜綔搴燂級', '21', 'erp_stock_record_biz_type', '0', 'danger', '', '', '1', '2024-02-05 18:09:00', '1', '2024-02-05 19:20:10', X'00'),
+('1490', '10', '瀹℃壒涓�', '10', 'erp_audit_status', '0', 'default', '', '', '1', '2024-02-06 00:00:21', '1', '2026-06-26 08:46:48', X'00'),
+('1491', '20', '瀹℃壒閫氳繃', '20', 'erp_audit_status', '0', 'success', '', '', '1', '2024-02-06 00:00:35', '1', '2026-06-26 08:46:48', X'00'),
+('1492', '30', '璋冩嫧鍏ュ簱', '30', 'erp_stock_record_biz_type', '0', '', '', '', '1', '2024-02-07 20:34:19', '1', '2024-02-07 12:36:31', X'00'),
+('1493', '31', '璋冩嫧鍏ュ簱锛堜綔搴燂級', '31', 'erp_stock_record_biz_type', '0', 'danger', '', '', '1', '2024-02-07 20:34:29', '1', '2024-02-07 20:37:11', X'00'),
+('1494', '32', '璋冩嫧鍑哄簱', '32', 'erp_stock_record_biz_type', '0', '', '', '', '1', '2024-02-07 20:34:38', '1', '2024-02-07 12:36:33', X'00'),
+('1495', '33', '璋冩嫧鍑哄簱锛堜綔搴燂級', '33', 'erp_stock_record_biz_type', '0', 'danger', '', '', '1', '2024-02-07 20:34:49', '1', '2024-02-07 20:37:06', X'00'),
+('1496', '40', '鐩樼泩鍏ュ簱', '40', 'erp_stock_record_biz_type', '0', '', '', '', '1', '2024-02-08 08:53:00', '1', '2024-02-08 08:53:09', X'00'),
+('1497', '41', '鐩樼泩鍏ュ簱锛堜綔搴燂級', '41', 'erp_stock_record_biz_type', '0', 'danger', '', '', '1', '2024-02-08 08:53:39', '1', '2024-02-16 19:40:54', X'00'),
+('1498', '42', '鐩樹簭鍑哄簱', '42', 'erp_stock_record_biz_type', '0', '', '', '', '1', '2024-02-08 08:54:16', '1', '2024-02-08 08:54:16', X'00'),
+('1499', '43', '鐩樹簭鍑哄簱锛堜綔搴燂級', '43', 'erp_stock_record_biz_type', '0', 'danger', '', '', '1', '2024-02-08 08:54:31', '1', '2024-02-16 19:40:46', X'00'),
+('1500', '50', '閿�鍞嚭搴�', '50', 'erp_stock_record_biz_type', '0', '', '', '', '1', '2024-02-11 21:47:25', '1', '2024-02-11 21:50:40', X'00'),
+('1501', '51', '閿�鍞嚭搴擄紙浣滃簾锛�', '51', 'erp_stock_record_biz_type', '0', 'danger', '', '', '1', '2024-02-11 21:47:37', '1', '2024-02-11 21:51:12', X'00'),
+('1502', '60', '閿�鍞��璐у叆搴�', '60', 'erp_stock_record_biz_type', '0', '', '', '', '1', '2024-02-12 06:51:05', '1', '2024-02-12 06:51:05', X'00'),
+('1503', '61', '閿�鍞��璐у叆搴擄紙浣滃簾锛�', '61', 'erp_stock_record_biz_type', '0', 'danger', '', '', '1', '2024-02-12 06:51:18', '1', '2024-02-12 06:51:18', X'00'),
+('1504', '70', '閲囪喘鍏ュ簱', '70', 'erp_stock_record_biz_type', '0', '', '', '', '1', '2024-02-16 13:10:02', '1', '2024-02-16 13:10:02', X'00'),
+('1505', '71', '閲囪喘鍏ュ簱锛堜綔搴燂級', '71', 'erp_stock_record_biz_type', '0', 'danger', '', '', '1', '2024-02-16 13:10:10', '1', '2024-02-16 19:40:40', X'00'),
+('1506', '80', '閲囪喘閫�璐у嚭搴�', '80', 'erp_stock_record_biz_type', '0', '', '', '', '1', '2024-02-16 13:10:17', '1', '2024-02-16 13:10:17', X'00'),
+('1507', '81', '閲囪喘閫�璐у嚭搴擄紙浣滃簾锛�', '81', 'erp_stock_record_biz_type', '0', 'danger', '', '', '1', '2024-02-16 13:10:26', '1', '2024-02-16 19:40:33', X'00'),
+('1509', '3', '瀹℃壒涓嶉�氳繃', '3', 'bpm_process_instance_status', '0', 'danger', '', '', '1', '2024-03-16 16:12:06', '1', '2024-03-16 16:12:06', X'00'),
+('1510', '4', '宸插彇娑�', '4', 'bpm_process_instance_status', '0', 'warning', '', '', '1', '2024-03-16 16:12:22', '1', '2024-03-16 16:12:22', X'00'),
+('1511', '5', '宸查��鍥�', '5', 'bpm_task_status', '0', 'warning', '', '', '1', '2024-03-16 19:10:46', '1', '2024-03-08 22:41:40', X'00'),
+('1512', '6', '濮旀淳涓�', '6', 'bpm_task_status', '0', 'primary', '', '', '1', '2024-03-17 10:06:22', '1', '2024-03-08 22:41:40', X'00'),
+('1513', '7', '瀹℃壒閫氳繃涓�', '7', 'bpm_task_status', '0', 'success', '', '', '1', '2024-03-17 10:06:47', '1', '2024-03-08 22:41:41', X'00'),
+('1514', '0', '寰呭鎵�', '0', 'bpm_task_status', '0', 'info', '', '', '1', '2024-03-17 10:07:11', '1', '2024-03-08 22:41:42', X'00'),
+('1515', '35', '鍙戣捣浜鸿嚜閫�', '35', 'bpm_task_candidate_strategy', '0', '', '', '', '1', '2024-03-22 19:45:16', '1', '2024-03-22 19:45:16', X'00'),
+('1516', '1', '鎵ц鐩戝惉鍣�', 'execution', 'bpm_process_listener_type', '0', 'primary', '', '', '1', '2024-03-23 12:54:03', '1', '2024-03-23 19:14:19', X'00'),
+('1517', '1', '浠诲姟鐩戝惉鍣�', 'task', 'bpm_process_listener_type', '0', 'success', '', '', '1', '2024-03-23 12:54:13', '1', '2024-03-23 19:14:24', X'00'),
+('1526', '1', 'Java 绫�', 'class', 'bpm_process_listener_value_type', '0', 'primary', '', '', '1', '2024-03-23 15:08:45', '1', '2024-03-23 19:14:32', X'00'),
+('1527', '2', '琛ㄨ揪寮�', 'expression', 'bpm_process_listener_value_type', '0', 'success', '', '', '1', '2024-03-23 15:09:06', '1', '2024-03-23 19:14:38', X'00'),
+('1528', '3', '浠g悊琛ㄨ揪寮�', 'delegateExpression', 'bpm_process_listener_value_type', '0', 'info', '', '', '1', '2024-03-23 15:11:23', '1', '2024-03-23 19:14:41', X'00'),
+('1529', '1', '澶�', '1', 'date_interval', '0', '', '', '', '1', '2024-03-29 22:50:26', '1', '2024-03-29 22:50:26', X'00'),
+('1530', '2', '鍛�', '2', 'date_interval', '0', '', '', '', '1', '2024-03-29 22:50:36', '1', '2024-03-29 22:50:36', X'00'),
+('1531', '3', '鏈�', '3', 'date_interval', '0', '', '', '', '1', '2024-03-29 22:50:46', '1', '2024-03-29 22:50:54', X'00'),
+('1532', '4', '瀛e害', '4', 'date_interval', '0', '', '', '', '1', '2024-03-29 22:51:01', '1', '2024-03-29 22:51:01', X'00'),
+('1533', '5', '骞�', '5', 'date_interval', '0', '', '', '', '1', '2024-03-29 22:51:07', '1', '2024-03-29 22:51:07', X'00'),
+('1537', '1', 'OpenAI', 'OpenAI', 'ai_platform', '0', '', '', '', '1', '2024-05-09 22:33:47', '1', '2024-05-09 22:58:46', X'00'),
+('1538', '2', 'Ollama', 'Ollama', 'ai_platform', '0', '', '', '', '1', '2024-05-17 23:02:55', '1', '2024-05-17 23:02:55', X'00'),
+('1539', '3', '鏂囧績涓�瑷�', 'YiYan', 'ai_platform', '0', '', '', '', '1', '2024-05-18 09:24:20', '1', '2024-05-18 09:29:01', X'00'),
+('1540', '4', '璁鏄熺伀', 'XingHuo', 'ai_platform', '0', '', '', '', '1', '2024-05-18 10:08:56', '1', '2024-05-18 10:08:56', X'00'),
+('1541', '5', '閫氫箟鍗冮棶', 'TongYi', 'ai_platform', '0', '', '', '', '1', '2024-05-18 10:32:29', '1', '2024-07-06 15:42:29', X'00'),
+('1542', '6', 'StableDiffusion', 'StableDiffusion', 'ai_platform', '0', '', '', '', '1', '2024-06-01 15:09:31', '1', '2024-06-01 15:10:25', X'00'),
+('1543', '10', '杩涜涓�', '10', 'ai_image_status', '0', 'primary', '', '', '1', '2024-06-26 20:51:41', '1', '2024-06-26 20:52:48', X'00'),
+('1544', '20', '宸插畬鎴�', '20', 'ai_image_status', '0', 'success', '', '', '1', '2024-06-26 20:52:07', '1', '2024-06-26 20:52:41', X'00'),
+('1545', '30', '宸插け璐�', '30', 'ai_image_status', '0', 'warning', '', '', '1', '2024-06-26 20:52:25', '1', '2024-06-26 20:52:35', X'00'),
+('1546', '7', 'Midjourney', 'Midjourney', 'ai_platform', '0', '', '', '', '1', '2024-06-26 22:14:46', '1', '2024-06-26 22:14:46', X'00'),
+('1547', '10', '杩涜涓�', '10', 'ai_music_status', '0', 'primary', '', '', '1', '2024-06-27 22:45:22', '1', '2024-06-28 00:56:17', X'00'),
+('1548', '20', '宸插畬鎴�', '20', 'ai_music_status', '0', 'success', '', '', '1', '2024-06-27 22:45:33', '1', '2024-06-28 00:56:18', X'00'),
+('1549', '30', '宸插け璐�', '30', 'ai_music_status', '0', 'danger', '', '', '1', '2024-06-27 22:45:44', '1', '2024-06-28 00:56:19', X'00'),
+('1550', '1', '姝岃瘝妯″紡', '1', 'ai_generate_mode', '0', '', '', '', '1', '2024-06-27 22:46:31', '1', '2024-06-28 01:22:25', X'00'),
+('1551', '2', '鎻忚堪妯″紡', '2', 'ai_generate_mode', '0', '', '', '', '1', '2024-06-27 22:46:37', '1', '2024-06-28 01:22:24', X'00'),
+('1552', '8', 'Suno', 'Suno', 'ai_platform', '0', '', '', '', '1', '2024-06-29 09:13:36', '1', '2024-06-29 09:13:41', X'00'),
+('1553', '9', 'DeepSeek', 'DeepSeek', 'ai_platform', '0', '', '', '', '1', '2024-07-06 12:04:30', '1', '2024-07-06 12:05:20', X'00'),
+('1554', '13', '鏅鸿氨', 'ZhiPu', 'ai_platform', '0', '', '', '', '1', '2024-07-06 18:00:35', '1', '2025-02-24 20:18:41', X'00'),
+('1555', '4', '闀�', '4', 'ai_write_length', '0', '', '', '', '1', '2024-07-07 15:49:03', '1', '2024-07-07 15:49:03', X'00'),
+('1556', '5', '娈佃惤', '5', 'ai_write_format', '0', '', '', '', '1', '2024-07-07 15:49:54', '1', '2024-07-07 15:49:54', X'00'),
+('1557', '6', '鏂囩珷', '6', 'ai_write_format', '0', '', '', '', '1', '2024-07-07 15:50:05', '1', '2024-07-07 15:50:05', X'00'),
+('1558', '7', '鍗氬鏂囩珷', '7', 'ai_write_format', '0', '', '', '', '1', '2024-07-07 15:50:23', '1', '2024-07-07 15:50:23', X'00'),
+('1559', '8', '鎯虫硶', '8', 'ai_write_format', '0', '', '', '', '1', '2024-07-07 15:50:31', '1', '2024-07-07 15:50:31', X'00'),
+('1560', '9', '澶х翰', '9', 'ai_write_format', '0', '', '', '', '1', '2024-07-07 15:50:37', '1', '2024-07-07 15:50:37', X'00'),
+('1561', '1', '鑷姩', '1', 'ai_write_tone', '0', '', '', '', '1', '2024-07-07 15:51:06', '1', '2024-07-07 15:51:06', X'00'),
+('1562', '2', '鍙嬪杽', '2', 'ai_write_tone', '0', '', '', '', '1', '2024-07-07 15:51:19', '1', '2024-07-07 15:51:19', X'00'),
+('1563', '3', '闅忔剰', '3', 'ai_write_tone', '0', '', '', '', '1', '2024-07-07 15:51:27', '1', '2024-07-07 15:51:27', X'00'),
+('1564', '4', '鍙嬪ソ', '4', 'ai_write_tone', '0', '', '', '', '1', '2024-07-07 15:51:37', '1', '2024-07-07 15:51:37', X'00'),
+('1565', '5', '涓撲笟', '5', 'ai_write_tone', '0', '', '', '', '1', '2024-07-07 15:51:49', '1', '2024-07-07 15:52:02', X'00'),
+('1566', '6', '璇欒皭', '6', 'ai_write_tone', '0', '', '', '', '1', '2024-07-07 15:52:15', '1', '2024-07-07 15:52:15', X'00'),
+('1567', '7', '鏈夎叮', '7', 'ai_write_tone', '0', '', '', '', '1', '2024-07-07 15:52:24', '1', '2024-07-07 15:52:24', X'00'),
+('1568', '8', '姝e紡', '8', 'ai_write_tone', '0', '', '', '', '1', '2024-07-07 15:54:33', '1', '2024-07-07 15:54:33', X'00'),
+('1570', '1', '鑷姩', '1', 'ai_write_format', '0', '', '', '', '1', '2024-07-07 15:19:34', '1', '2024-07-07 15:19:34', X'00'),
+('1571', '2', '鐢靛瓙閭欢', '2', 'ai_write_format', '0', '', '', '', '1', '2024-07-07 15:19:50', '1', '2024-07-07 15:49:30', X'00'),
+('1572', '3', '娑堟伅', '3', 'ai_write_format', '0', '', '', '', '1', '2024-07-07 15:20:01', '1', '2024-07-07 15:49:38', X'00'),
+('1573', '4', '璇勮', '4', 'ai_write_format', '0', '', '', '', '1', '2024-07-07 15:20:13', '1', '2024-07-07 15:49:45', X'00'),
+('1574', '1', '鑷姩', '1', 'ai_write_language', '0', '', '', '', '1', '2024-07-07 15:44:18', '1', '2024-07-07 15:44:18', X'00'),
+('1575', '2', '涓枃', '2', 'ai_write_language', '0', '', '', '', '1', '2024-07-07 15:44:28', '1', '2024-07-07 15:44:28', X'00'),
+('1576', '3', '鑻辨枃', '3', 'ai_write_language', '0', '', '', '', '1', '2024-07-07 15:44:37', '1', '2024-07-07 15:44:37', X'00'),
+('1577', '4', '闊╄', '4', 'ai_write_language', '0', '', '', '', '1', '2024-07-07 15:46:28', '1', '2024-07-07 15:46:28', X'00'),
+('1578', '5', '鏃ヨ', '5', 'ai_write_language', '0', '', '', '', '1', '2024-07-07 15:46:44', '1', '2024-07-07 15:46:44', X'00'),
+('1579', '1', '鑷姩', '1', 'ai_write_length', '0', '', '', '', '1', '2024-07-07 15:48:34', '1', '2024-07-07 15:48:34', X'00'),
+('1580', '2', '鐭�', '2', 'ai_write_length', '0', '', '', '', '1', '2024-07-07 15:48:44', '1', '2024-07-07 15:48:44', X'00'),
+('1581', '3', '涓瓑', '3', 'ai_write_length', '0', '', '', '', '1', '2024-07-07 15:48:52', '1', '2024-07-07 15:48:52', X'00'),
+('1584', '1', '鎾板啓', '1', 'ai_write_type', '0', '', '', '', '1', '2024-07-10 21:26:00', '1', '2024-07-10 21:26:00', X'00'),
+('1585', '2', '鍥炲', '2', 'ai_write_type', '0', '', '', '', '1', '2024-07-10 21:26:06', '1', '2024-07-10 21:26:06', X'00'),
+('1586', '2', '鑵捐浜�', 'TENCENT', 'system_sms_channel_code', '0', '', '', '', '1', '2024-07-22 22:23:16', '1', '2024-07-22 22:23:16', X'00'),
+('1587', '3', '鍗庝负浜�', 'HUAWEI', 'system_sms_channel_code', '0', '', '', '', '1', '2024-07-22 22:23:46', '1', '2024-07-22 22:23:53', X'00'),
+('1588', '1', 'OpenAI 寰蒋', 'AzureOpenAI', 'ai_platform', '0', '', '', '', '1', '2024-08-10 14:07:41', '1', '2024-08-10 14:07:41', X'00'),
+('1589', '10', 'BPMN 璁捐鍣�', '10', 'bpm_model_type', '0', 'primary', '', '', '1', '2024-08-26 15:22:17', '1', '2024-08-26 16:46:02', X'00'),
+('1590', '20', 'SIMPLE 璁捐鍣�', '20', 'bpm_model_type', '0', 'success', '', '', '1', '2024-08-26 15:22:27', '1', '2024-08-26 16:45:58', X'00'),
+('1591', '4', '涓冪墰浜�', 'QINIU', 'system_sms_channel_code', '0', '', '', '', '1', '2024-08-31 08:45:03', '1', '2024-08-31 08:45:24', X'00'),
+('1592', '3', '鏂颁汉鍒�', '3', 'promotion_coupon_take_type', '0', 'info', '', '鏂颁汉娉ㄥ唽鍚庯紝鑷姩鍙戞斁', '1', '2024-09-03 11:57:16', '1', '2024-09-03 11:57:28', X'00'),
+('1593', '5', '寰俊闆堕挶', '5', 'brokerage_withdraw_type', '0', '', '', 'API 鎵撴', '1', '2024-10-13 11:06:48', '1', '2025-05-10 08:24:55', X'00'),
+('1683', '10', '瀛楄妭璞嗗寘', 'DouBao', 'ai_platform', '0', '', '', '', '1', '2025-02-23 19:51:40', '1', '2025-02-23 19:52:02', X'00'),
+('1684', '11', '鑵捐娣峰厓', 'HunYuan', 'ai_platform', '0', '', '', '', '1', '2025-02-23 20:58:04', '1', '2025-02-23 20:58:04', X'00'),
+('1685', '12', '纭呭熀娴佸姩', 'SiliconFlow', 'ai_platform', '0', '', '', '', '1', '2025-02-24 20:19:09', '1', '2025-02-24 20:19:09', X'00'),
+('1686', '1', '鑱婂ぉ', '1', 'ai_model_type', '0', '', '', '', '1', '2025-03-03 12:26:34', '1', '2025-03-03 12:26:34', X'00'),
+('1687', '2', '鍥惧儚', '2', 'ai_model_type', '0', '', '', '', '1', '2025-03-03 12:27:23', '1', '2025-03-03 12:27:23', X'00'),
+('1688', '3', '闊抽', '3', 'ai_model_type', '0', '', '', '', '1', '2025-03-03 12:27:51', '1', '2025-03-03 12:27:51', X'00'),
+('1689', '4', '瑙嗛', '4', 'ai_model_type', '0', '', '', '', '1', '2025-03-03 12:28:03', '1', '2025-03-03 12:28:03', X'00'),
+('1690', '5', '鍚戦噺', '5', 'ai_model_type', '0', '', '', '', '1', '2025-03-03 12:28:15', '1', '2025-03-03 12:28:15', X'00'),
+('1691', '6', '閲嶆帓', '6', 'ai_model_type', '0', '', '', '', '1', '2025-03-03 12:28:26', '1', '2025-03-03 12:28:26', X'00'),
+('1692', '14', 'MiniMax', 'MiniMax', 'ai_platform', '0', '', '', '', '1', '2025-03-11 20:04:51', '1', '2025-03-11 20:04:51', X'00'),
+('1693', '15', '鏈堜箣鏆楅潰', 'Moonshot', 'ai_platform', '0', '', '', '', '1', '2025-03-11 20:05:08', '1', '2025-11-24 07:17:39', X'00'),
+('2002', '0', '鐩磋繛璁惧', '0', 'iot_product_device_type', '0', 'default', '', '', '1', '2024-08-10 11:54:58', '1', '2025-03-17 09:28:22', X'00'),
+('2003', '2', '缃戝叧璁惧', '2', 'iot_product_device_type', '0', 'default', '', '', '1', '2024-08-10 11:55:08', '1', '2025-03-17 09:28:28', X'00'),
+('2004', '1', '缃戝叧瀛愯澶�', '1', 'iot_product_device_type', '0', 'default', '', '', '1', '2024-08-10 11:55:20', '1', '2025-03-17 09:28:31', X'00'),
+('2005', '1', '宸插彂甯�', '1', 'iot_product_status', '0', 'success', '', '', '1', '2024-08-10 12:10:33', '1', '2025-03-17 09:28:34', X'00'),
+('2006', '0', '寮�鍙戜腑', '0', 'iot_product_status', '0', 'default', '', '', '1', '2024-08-10 14:19:18', '1', '2025-03-17 09:28:39', X'00'),
+('2009', '0', 'Wi-Fi', '0', 'iot_net_type', '0', '', '', '', '1', '2024-09-06 22:04:47', '1', '2025-03-17 09:28:47', X'00'),
+('2010', '1', '绉诲姩缃戠粶', '1', 'iot_net_type', '0', '', '', '', '1', '2024-09-06 22:05:14', '1', '2025-06-12 23:27:19', X'00'),
+('2011', '2', '浠ュお缃�', '2', 'iot_net_type', '0', '', '', '', '1', '2024-09-06 22:05:35', '1', '2025-03-17 09:28:51', X'00'),
+('2012', '3', '鍏朵粬', '3', 'iot_net_type', '0', '', '', '', '1', '2024-09-06 22:05:52', '1', '2025-03-17 09:28:54', X'00'),
+('2018', '0', '鏈縺娲�', '0', 'iot_device_state', '0', '', '', '', '1', '2024-09-21 08:13:34', '1', '2025-03-17 09:29:09', X'00'),
+('2019', '1', '鍦ㄧ嚎', '1', 'iot_device_state', '0', '', '', '', '1', '2024-09-21 08:13:48', '1', '2025-03-17 09:29:12', X'00'),
+('2020', '2', '绂荤嚎', '2', 'iot_device_state', '0', '', '', '', '1', '2024-09-21 08:13:59', '1', '2025-03-17 09:29:14', X'00'),
+('2021', '1', '灞炴��', '1', 'iot_thing_model_type', '0', '', '', '', '1', '2024-09-29 20:03:01', '1', '2025-03-17 09:29:24', X'00'),
+('2022', '2', '鏈嶅姟', '2', 'iot_thing_model_type', '0', '', '', '', '1', '2024-09-29 20:03:11', '1', '2025-03-17 09:29:27', X'00'),
+('2023', '3', '浜嬩欢', '3', 'iot_thing_model_type', '0', '', '', '', '1', '2024-09-29 20:03:20', '1', '2025-03-17 09:29:29', X'00'),
+('2030', '1', '鍗囨瘡鍒嗛挓', 'L/min', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:34:24', X'00'),
+('2031', '2', '姣厠姣忓崈鍏�', 'mg/kg', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:34:27', X'00'),
+('2032', '3', '娴婂害', 'NTU', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:34:31', X'00'),
+('2033', '4', 'PH鍊�', 'pH', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:34:36', X'00'),
+('2034', '5', '鍦熷¥EC鍊�', 'dS/m', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:34:43', X'00'),
+('2035', '6', '澶槼鎬昏緪灏�', 'W/銕�', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:36:20', X'00'),
+('2036', '7', '闄嶉洦閲�', 'mm/hour', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:36:24', X'00'),
+('2037', '8', '涔�', 'var', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:36:27', X'00'),
+('2038', '9', '鍘樻硦', 'cP', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:36:33', X'00'),
+('2039', '10', '楗卞拰搴�', 'aw', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:37:11', X'00'),
+('2040', '11', '涓�', 'pcs', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:37:19', X'00'),
+('2041', '12', '鍘樻柉', 'cst', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:37:22', X'00'),
+('2042', '13', '宸�', 'bar', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:37:24', X'00'),
+('2043', '14', '绾冲厠姣忓崌', 'ppt', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:37:27', X'00'),
+('2044', '15', '鍗佷嚎鍒嗕箣涓�', 'ppb', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2026-04-05 15:53:29', X'00'),
+('2045', '16', '寰タ姣忓帢绫�', 'uS/cm', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:37:34', X'00'),
+('2046', '17', '鐗涢】姣忓簱浠�', 'N/C', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:37:38', X'00'),
+('2047', '18', '浼忕壒姣忕背', 'V/m', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:37:43', X'00'),
+('2048', '19', '婊撮��', 'ml/min', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:37:46', X'00'),
+('2049', '20', '姣背姹炴煴', 'mmHg', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:37:48', X'00'),
+('2050', '21', '琛�绯�', 'mmol/L', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:37:54', X'00'),
+('2051', '22', '姣背姣忕', 'mm/s', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:38:02', X'00'),
+('2052', '23', '杞瘡绫�', 'turn/m', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2026-04-05 15:53:29', X'00'),
+('2053', '24', '娆�', 'count', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:38:09', X'00'),
+('2054', '25', '妗�', 'gear', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:38:11', X'00'),
+('2055', '26', '姝�', 'stepCount', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:38:13', X'00'),
+('2056', '27', '鏍囧噯绔嬫柟绫虫瘡灏忔椂', 'Nm3/h', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:38:15', X'00'),
+('2057', '28', '鍗冧紡', 'kV', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:38:20', X'00'),
+('2058', '29', '鍗冧紡瀹�', 'kVA', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:38:24', X'00'),
+('2060', '30', '鍗冧箯', 'kVar', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2061', '31', '寰摝姣忓钩鏂瑰帢绫�', 'uw/cm2', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2062', '32', '鍙�', '鍙�', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2063', '33', '鐩稿婀垮害', '%RH', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2064', '34', '绔嬫柟绫虫瘡绉�', 'm鲁/s', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2065', '35', '鍏枻姣忕', 'kg/s', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2066', '36', '杞瘡鍒嗛挓', 'r/min', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2067', '37', '鍚ㄦ瘡灏忔椂', 't/h', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2068', '38', '鍗冨崱姣忓皬鏃�', 'KCL/h', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2069', '39', '鍗囨瘡绉�', 'L/s', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2070', '40', '鍏嗗笗', 'MPa', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2026-04-05 15:53:29', X'00'),
+('2071', '41', '绔嬫柟绫虫瘡灏忔椂', 'm鲁/h', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2072', '42', '鍗冧箯鏃�', 'kvarh', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2073', '43', '寰厠姣忓崌', '渭g/L', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2074', '44', '鍗冨崱璺噷', 'kcal', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2075', '45', '鍚夊瓧鑺�', 'GB', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2076', '46', '鍏嗗瓧鑺�', 'MB', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2077', '47', '鍗冨瓧鑺�', 'KB', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2078', '48', '瀛楄妭', 'B', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2079', '49', '寰厠姣忓钩鏂瑰垎绫虫瘡澶�', '渭g/(d銕÷穌)', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2080', '50', '鏃�', '', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2081', '51', '鐧句竾鍒嗙巼', 'ppm', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2082', '52', '鍍忕礌', 'pixel', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2083', '53', '鐓у害', 'Lux', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2084', '54', '閲嶅姏鍔犻�熷害', 'grav', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2085', '55', '鍒嗚礉', 'dB', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2086', '56', '鐧惧垎姣�', '%', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2087', '57', '娴佹槑', 'lm', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2088', '58', '姣旂壒', 'bit', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2089', '59', '鍏嬫瘡姣崌', 'g/mL', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2090', '60', '鍏嬫瘡鍗�', 'g/L', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2091', '61', '姣厠姣忓崌', 'mg/L', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2092', '62', '寰厠姣忕珛鏂圭背', '渭g/m鲁', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2093', '63', '姣厠姣忕珛鏂圭背', 'mg/m鲁', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2094', '64', '鍏嬫瘡绔嬫柟绫�', 'g/m鲁', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2095', '65', '鍗冨厠姣忕珛鏂圭背', 'kg/m鲁', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2096', '66', '绾虫硶', 'nF', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2097', '67', '鐨硶', 'pF', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2098', '68', '寰硶', '渭F', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2099', '69', '娉曟媺', 'F', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2100', '70', '娆у', '惟', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2101', '71', '寰畨', '渭A', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2102', '72', '姣畨', 'mA', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2103', '73', '鍗冨畨', 'kA', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2104', '74', '瀹夊煿', 'A', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2105', '75', '姣紡', 'mV', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2106', '76', '浼忕壒', 'V', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2107', '77', '姣', 'ms', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2108', '78', '绉�', 's', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2109', '79', '鍒嗛挓', 'min', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2110', '80', '灏忔椂', 'h', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2111', '81', '鏃�', 'day', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2112', '82', '鍛�', 'week', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2113', '83', '鏈�', 'month', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2114', '84', '骞�', 'year', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2115', '85', '鑺�', 'kn', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2116', '86', '鍗冪背姣忓皬鏃�', 'km/h', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2117', '87', '绫虫瘡绉�', 'm/s', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2118', '88', '瑙掔', '鈥�', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2026-04-05 15:53:29', X'00'),
+('2119', '89', '鍒�', '鈥�', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2120', '90', '搴�', '掳', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2121', '91', '寮у害', 'rad', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2122', '92', '璧吂', 'Hz', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2123', '93', '寰摝', '渭W', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2124', '94', '姣摝', 'mW', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2125', '95', '鍗冪摝鐗�', 'kW', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2126', '96', '鐡︾壒', 'W', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2127', '97', '鍗¤矾閲�', 'cal', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2128', '98', '鍗冪摝鏃�', 'kW路h', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2129', '99', '鐡︽椂', 'Wh', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2130', '100', '鐢靛瓙浼�', 'eV', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2131', '101', '鍗冪劍', 'kJ', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2132', '102', '鐒﹁��', 'J', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2133', '103', '鍗庢皬搴�', '鈩�', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2134', '104', '寮�灏旀枃', 'K', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2135', '105', '鍚�', 't', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2136', '106', '鎽勬皬搴�', '掳C', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2137', '107', '姣笗', '1e-3Pa', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2026-04-05 15:53:29', X'00'),
+('2138', '108', '鐧惧笗', 'hPa', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2139', '109', '鍗冨笗', 'kPa', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2140', '110', '甯曟柉鍗�', 'Pa', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2141', '111', '姣厠', 'mg', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2142', '112', '鍏�', 'g', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2143', '113', '鍗冨厠', 'kg', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2144', '114', '鐗�', 'N', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2145', '115', '姣崌', 'mL', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2146', '116', '鍗�', 'L', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2147', '117', '绔嬫柟姣背', 'mm鲁', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2148', '118', '绔嬫柟鍘樼背', 'cm鲁', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2149', '119', '绔嬫柟鍗冪背', 'km鲁', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2150', '120', '绔嬫柟绫�', 'm鲁', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2151', '121', '鍏》', 'h銕�', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2152', '122', '骞虫柟鍘樼背', 'c銕�', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2153', '123', '骞虫柟姣背', 'm銕�', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2154', '124', '骞虫柟鍗冪背', 'k銕�', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2155', '125', '骞虫柟绫�', '銕�', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2156', '126', '绾崇背', 'nm', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2157', '127', '寰背', '渭m', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2158', '128', '姣背', 'mm', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2159', '129', '鍘樼背', 'cm', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2160', '130', '鍒嗙背', 'dm', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2161', '131', '鍗冪背', 'km', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2162', '132', '绫�', 'm', 'iot_thing_model_unit', '0', '', '', '', '1', '2024-12-13 11:08:41', '1', '2025-03-17 09:40:46', X'00'),
+('2165', '1', 'HTTP', '1', 'iot_data_sink_type_enum', '0', 'default', '', '', '1', '2025-03-09 12:39:54', '1', '2025-06-24 12:44:47', X'00'),
+('2166', '2', 'TCP', '2', 'iot_data_sink_type_enum', '0', 'default', '', '', '1', '2025-03-09 12:40:06', '1', '2025-06-24 12:44:46', X'00'),
+('2167', '3', 'WebSocket', '3', 'iot_data_sink_type_enum', '0', 'default', '', '', '1', '2025-03-09 12:40:24', '1', '2025-06-24 12:44:45', X'00'),
+('2168', '10', 'MQTT', '10', 'iot_data_sink_type_enum', '0', 'default', '', '', '1', '2025-03-09 12:40:37', '1', '2025-06-24 12:44:44', X'00'),
+('2169', '20', 'Database', '20', 'iot_data_sink_type_enum', '0', 'default', '', '', '1', '2025-03-09 12:41:05', '1', '2025-06-24 12:44:44', X'00'),
+('2170', '21', 'Redis Stream', '21', 'iot_data_sink_type_enum', '0', 'default', '', '', '1', '2025-03-09 12:41:18', '1', '2025-06-24 12:44:43', X'00'),
+('2171', '30', 'RocketMQ', '30', 'iot_data_sink_type_enum', '0', 'default', '', '', '1', '2025-03-09 12:41:30', '1', '2025-06-24 12:44:42', X'00'),
+('2172', '31', 'RabbitMQ', '31', 'iot_data_sink_type_enum', '0', 'default', '', '', '1', '2025-03-09 12:41:47', '1', '2025-06-24 12:44:41', X'00'),
+('2173', '32', 'Kafka', '32', 'iot_data_sink_type_enum', '0', 'default', '', '', '1', '2025-03-09 12:41:59', '1', '2025-06-24 12:44:39', X'00'),
+('2174', '1', '璁惧涓婁笅绾垮彉鏇�', '1', 'iot_rule_scene_trigger_type_enum', '0', 'primary', '', '', '1', '2025-03-20 15:00:01', '"1"', '2025-07-06 10:28:16', X'00'),
+('2175', '2', '鐗╂ā鍨嬪睘鎬т笂鎶�', '2', 'iot_rule_scene_trigger_type_enum', '0', 'primary', '', '', '1', '2025-03-20 15:00:09', '"1"', '2025-07-06 10:28:22', X'00'),
+('2176', '1', '璁惧鐘舵��', 'state', 'iot_device_message_type_enum', '0', 'primary', '', '', '1', '2025-03-20 15:24:58', '1', '2025-03-20 15:24:58', X'00'),
+('2177', '2', '璁惧灞炴��', 'property', 'iot_device_message_type_enum', '0', 'primary', '', '', '1', '2025-03-20 15:25:09', '1', '2025-03-20 15:25:09', X'00'),
+('2178', '3', '璁惧浜嬩欢', 'event', 'iot_device_message_type_enum', '0', 'primary', '', '', '1', '2025-03-20 15:25:23', '1', '2025-03-20 15:25:23', X'00'),
+('2179', '4', '璁惧鏈嶅姟', 'service', 'iot_device_message_type_enum', '0', 'primary', '', '', '1', '2025-03-20 15:25:39', '1', '2025-03-20 15:25:39', X'00'),
+('2180', '5', '璁惧閰嶇疆', 'config', 'iot_device_message_type_enum', '0', 'primary', '', '', '1', '2025-03-20 15:25:51', '1', '2025-03-20 15:25:57', X'00'),
+('2181', '6', '璁惧 OTA', 'ota', 'iot_device_message_type_enum', '0', 'primary', '', '', '1', '2025-03-20 15:26:17', '1', '2025-03-20 15:26:17', X'00'),
+('2182', '7', '璁惧娉ㄥ唽', 'register', 'iot_device_message_type_enum', '0', 'primary', '', '', '1', '2025-03-20 15:26:35', '1', '2025-03-20 15:26:35', X'00'),
+('2183', '8', '璁惧鎷撴墤', 'topology', 'iot_device_message_type_enum', '0', 'primary', '', '', '1', '2025-03-20 15:26:46', '1', '2025-03-20 15:26:46', X'00'),
+('2184', '1', '璁惧灞炴�ц缃�', '1', 'iot_rule_scene_action_type_enum', '0', 'primary', '', '', '1', '2025-03-28 15:27:12', '"1"', '2025-07-06 10:37:33', X'00'),
+('2185', '2', '璁惧鏈嶅姟璋冪敤', '2', 'iot_rule_scene_action_type_enum', '0', 'primary', '', '', '1', '2025-03-28 15:27:25', '"1"', '2025-07-06 10:37:41', X'00'),
+('2186', '100', '鍛婅瑙﹀彂', '100', 'iot_rule_scene_action_type_enum', '0', 'primary', '', '', '1', '2025-03-28 15:27:35', '"1"', '2025-07-06 10:37:50', X'00'),
+('3000', '16', '鐧惧窛鏅鸿兘', 'BaiChuan', 'ai_platform', '0', '', '', '', '1', '2025-03-23 12:15:46', '1', '2025-03-23 12:15:46', X'00'),
+('3001', '40', 'Vben5.0 Ant Design Schema 妯$増', '40', 'infra_codegen_front_type', '0', '', '', NULL, '1', '2025-04-23 21:47:47', '1', '2025-09-04 23:25:12', X'00'),
+('3002', '6', '鏀粯瀹濅綑棰�', '6', 'brokerage_withdraw_type', '0', '', '', 'API 鎵撴', '1', '2025-05-10 08:24:49', '1', '2025-05-10 08:24:49', X'00'),
+('3004', '3', 'WARN', '3', 'iot_alert_level', '0', 'warning', '', '', '1', '2025-06-27 20:32:22', '1', '2025-06-27 20:34:31', X'00'),
+('3005', '1', 'INFO', '1', 'iot_alert_level', '0', 'primary', '', '', '1', '2025-06-27 20:33:28', '1', '2025-06-27 20:34:35', X'00'),
+('3006', '5', 'ERROR', '5', 'iot_alert_level', '0', 'danger', '', '', '1', '2025-06-27 20:33:50', '1', '2025-06-27 20:33:50', X'00'),
+('3007', '1', '鐭俊', '1', 'iot_alert_receive_type', '0', '', '', '', '1', '2025-06-27 22:49:30', '1', '2025-06-27 22:49:30', X'00'),
+('3008', '2', '閭', '2', 'iot_alert_receive_type', '0', '', '', '', '1', '2025-06-27 22:49:39', '1', '2025-06-27 22:50:07', X'00'),
+('3009', '3', '绔欏唴淇�', '3', 'iot_alert_receive_type', '0', '', '', '', '1', '2025-06-27 22:50:20', '1', '2025-06-27 22:50:20', X'00'),
+('3010', '1', '鍏ㄩ儴璁惧', '1', 'iot_ota_task_device_scope', '0', '', '', '', '1', '2025-07-02 09:43:09', '1', '2025-07-02 09:43:09', X'00'),
+('3011', '2', '鎸囧畾璁惧', '2', 'iot_ota_task_device_scope', '0', '', '', '', '1', '2025-07-02 09:43:15', '1', '2025-07-02 09:43:15', X'00'),
+('3012', '10', '杩涜涓�', '10', 'iot_ota_task_status', '0', 'primary', '', '', '1', '2025-07-02 09:44:01', '"1"', '2025-07-02 09:44:21', X'00'),
+('3013', '20', '宸茬粨鏉�', '20', 'iot_ota_task_status', '0', 'success', '', '', '1', '2025-07-02 09:44:14', '"1"', '2025-07-02 23:56:12', X'00'),
+('3014', '30', '宸插彇娑�', '30', 'iot_ota_task_status', '0', 'danger', '', '', '1', '2025-07-02 09:44:36', '1', '2025-07-02 09:44:36', X'00'),
+('3015', '0', '寰呮帹閫�', '0', 'iot_ota_task_record_status', '0', '', '', '', '1', '2025-07-02 09:45:16', '1', '2025-07-02 09:45:16', X'00'),
+('3016', '10', '宸叉帹閫�', '10', 'iot_ota_task_record_status', '0', '', '', '', '1', '2025-07-02 09:45:25', '1', '2025-07-02 09:45:25', X'00'),
+('3017', '20', '鍗囩骇涓�', '20', 'iot_ota_task_record_status', '0', 'primary', '', '', '1', '2025-07-02 09:45:37', '1', '2025-07-02 09:45:37', X'00'),
+('3018', '30', '鍗囩骇鎴愬姛', '30', 'iot_ota_task_record_status', '0', 'success', '', '', '1', '2025-07-02 09:45:47', '1', '2025-07-02 09:45:47', X'00'),
+('3019', '40', '鍗囩骇澶辫触', '40', 'iot_ota_task_record_status', '0', 'danger', '', '', '1', '2025-07-02 09:46:02', '1', '2025-07-02 09:46:02', X'00'),
+('3020', '50', '鍗囩骇鍙栨秷', '50', 'iot_ota_task_record_status', '0', 'warning', '', '', '1', '2025-07-02 09:46:09', '"1"', '2025-07-02 09:46:27', X'00'),
+('3024', '3', '璁惧浜嬩欢涓婃姤', '3', 'iot_rule_scene_trigger_type_enum', '0', '', '', '', '1', '2025-07-06 10:28:29', '1', '2025-07-06 10:28:29', X'00'),
+('3025', '4', '璁惧鏈嶅姟璋冪敤', '4', 'iot_rule_scene_trigger_type_enum', '0', '', '', '', '1', '2025-07-06 10:28:35', '1', '2025-07-06 10:28:35', X'00'),
+('3026', '100', '瀹氭椂瑙﹀彂', '100', 'iot_rule_scene_trigger_type_enum', '0', '', '', '', '1', '2025-07-06 10:28:48', '1', '2025-07-06 10:28:48', X'00'),
+('3027', '101', '鍛婅鎭㈠', '101', 'iot_rule_scene_action_type_enum', '0', '', '', '', '1', '2025-07-06 10:37:57', '1', '2025-07-06 10:37:57', X'00'),
+('3028', '2', 'Anthropic', 'Anthropic', 'ai_platform', '0', '', '', '', '1', '2025-08-21 22:54:24', '1', '2025-08-21 22:57:58', X'00'),
+('3029', '2', '璋锋瓕 Gemini', 'Gemini', 'ai_platform', '0', '', '', '', '1', '2025-08-22 22:39:35', '1', '2025-08-22 22:44:49', X'00'),
+('3030', '1', '鏂囦欢绯荤粺', 'filesystem', 'ai_mcp_client_name', '0', '', '', '', '1', '2025-08-28 13:58:43', '1', '2025-08-28 21:19:42', X'00'),
+('3031', '41', 'Vben5.0 Ant Design 鏍囧噯妯$増', '41', 'infra_codegen_front_type', '0', '', '', '', '1', '2025-09-04 23:26:07', '1', '2025-09-04 23:26:07', X'00'),
+('3032', '50', 'Vben5.0 Element Plus Schema 妯$増', '50', 'infra_codegen_front_type', '0', '', '', '', '1', '2025-09-04 23:26:38', '1', '2025-09-04 23:26:38', X'00'),
+('3033', '51', 'Vben5.0 Element Plus 鏍囧噯妯$増', '51', 'infra_codegen_front_type', '0', '', '', '', '1', '2025-09-04 23:26:49', '1', '2025-09-04 23:26:49', X'00'),
+('3034', '1', 'ttt', 'tt', 'iot_ota_task_record_status', '0', 'success', '', NULL, '1', '2025-09-06 00:02:21', '1', '2025-09-06 00:02:31', X'00'),
+('3035', '40', '鏀粯瀹濆皬绋嬪簭', '40', 'system_social_type', '0', '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', X'00'),
+('3036', '60', 'Admin Uniapp 绉诲姩绔�', '60', 'infra_codegen_front_type', '0', '', '', NULL, '1', '2025-12-16 19:25:51', '1', '2025-12-17 09:46:15', X'00'),
+('3037', '42', 'Vben5.0 Antdv Next Schema 妯$増', '42', 'infra_codegen_front_type', '0', '', '', '', '1', '2026-05-23 13:52:25', '1', '2026-05-23 13:52:25', X'00'),
+('3038', '43', 'Vben5.0 Antdv Next 鏍囧噯妯$増', '43', 'infra_codegen_front_type', '0', '', '', '', '1', '2026-05-23 13:52:25', '1', '2026-05-23 13:52:25', X'00'),
+('3040', '1', 'UDP', 'udp', 'iot_protocol_type', '0', '', '', 'UDP 鍗忚', '1', '2026-02-04 00:32:47', '1', '2026-02-04 00:32:47', X'00'),
+('3041', '2', 'WebSocket', 'websocket', 'iot_protocol_type', '0', '', '', 'WebSocket 鍗忚', '1', '2026-02-04 00:32:55', '1', '2026-02-04 00:32:55', X'00'),
+('3042', '3', 'HTTP', 'http', 'iot_protocol_type', '0', '', '', 'HTTP 鍗忚', '1', '2026-02-04 00:32:55', '1', '2026-02-04 00:32:55', X'00'),
+('3043', '4', 'MQTT', 'mqtt', 'iot_protocol_type', '0', 'success', '', 'MQTT 鍗忚', '1', '2026-02-04 00:32:55', '1', '2026-02-04 00:32:55', X'00'),
+('3044', '5', 'EMQX', 'emqx', 'iot_protocol_type', '0', 'success', '', 'EMQX 鍗忚', '1', '2026-02-04 00:32:55', '1', '2026-02-04 00:32:55', X'00'),
+('3045', '6', 'CoAP', 'coap', 'iot_protocol_type', '0', '', '', 'CoAP 鍗忚', '1', '2026-02-04 00:32:55', '1', '2026-02-04 00:32:55', X'00'),
+('3046', '7', 'Modbus TCP Server', 'modbus_tcp_server', 'iot_protocol_type', '0', '', '', 'Modbus TCP Server 鍗忚', '1', '2026-02-04 00:32:55', '1', '2026-02-12 15:16:45', X'00'),
+('3047', '0', 'JSON', 'json', 'iot_serialize_type', '0', 'success', '', 'JSON 鏍煎紡', '1', '2026-02-04 00:33:19', '1', '2026-02-04 00:33:19', X'00'),
+('3048', '1', '浜岃繘鍒�', 'binary', 'iot_serialize_type', '0', 'warning', '', '浜岃繘鍒舵牸寮�', '1', '2026-02-04 00:33:19', '1', '2026-02-04 00:33:19', X'00'),
+('3049', '8', 'Modbus TCP Client', 'modbus_tcp_client', 'iot_protocol_type', '0', '', '', 'Modbus TCP Client 鍗忚', '1', '2026-02-08 18:29:46', '1', '2026-02-12 15:16:32', X'00'),
+('3050', '2', '杈圭紭閲囬泦', '2', 'iot_modbus_mode', '0', 'success', '', '璁惧涓诲姩涓婃姤鏁版嵁锛屾棤闇�杞', '1', '2025-06-12 22:56:06', '1', '2026-02-09 13:03:23', X'00'),
+('3051', '1', 'Modbus TCP', '1', 'iot_modbus_frame_format', '0', 'default', '', 'MBAP 澶撮儴鏍煎紡', '1', '2025-06-12 22:56:06', '1', '2025-06-12 22:56:06', X'00'),
+('3052', '2', 'Modbus RTU', '2', 'iot_modbus_frame_format', '0', 'warning', '', 'CRC16 鏍¢獙鏍煎紡', '1', '2025-06-12 22:56:06', '1', '2025-06-12 22:56:06', X'00'),
+('3053', '1', '浜戠杞', '1', 'iot_modbus_mode', '0', 'primary', '', '缃戝叧涓诲姩杞璇诲彇璁惧瀵勫瓨鍣�', '1', '2025-06-12 22:56:06', '1', '2025-06-12 22:56:06', X'00'),
+('3054', '1', '浼佷笟瀹㈡埛', '1', 'mes_client_type', '0', 'primary', '', '', '1', '2026-02-15 14:38:25', '1', '2026-02-15 14:38:25', X'00'),
+('3055', '2', '涓汉', '2', 'mes_client_type', '0', 'success', '', '', '1', '2026-02-15 14:38:25', '1', '2026-02-15 14:38:25', X'00'),
+('3056', '1', '浼樿川渚涘簲鍟�', 'A', 'mes_vendor_level', '0', 'success', '', '', '1', '2026-02-15 15:59:15', '1', '2026-02-15 15:59:15', X'00'),
+('3057', '2', '姝e父', 'B', 'mes_vendor_level', '0', 'primary', '', '', '1', '2026-02-15 15:59:15', '1', '2026-02-15 15:59:15', X'00'),
+('3058', '3', '閲嶇偣鍏虫敞', 'C', 'mes_vendor_level', '0', 'warning', '', '', '1', '2026-02-15 15:59:15', '1', '2026-02-15 15:59:15', X'00'),
+('3059', '4', '鍔h川渚涘簲鍟�', 'D', 'mes_vendor_level', '0', 'danger', '', '', '1', '2026-02-15 15:59:15', '1', '2026-02-15 15:59:15', X'00'),
+('3060', '5', '榛戝悕鍗�', 'E', 'mes_vendor_level', '0', 'info', '', '', '1', '2026-02-15 15:59:15', '1', '2026-02-15 15:59:15', X'00'),
+('3061', '1', '鍋囨湡', '2', 'mes_cal_holiday_type', '0', 'success', '', '', '1', '2026-02-16 07:35:58', '1', '2026-02-16 11:20:42', X'00'),
+('3062', '2', '宸ヤ綔鏃�', '1', 'mes_cal_holiday_type', '0', 'primary', '', '', '1', '2026-02-16 07:35:58', '1', '2026-02-16 11:20:40', X'00'),
+('3063', '1', '鍦ㄥ簱', '1', 'mes_tm_tool_status', '0', 'success', '', '', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', X'00'),
+('3064', '2', '棰嗙敤涓�', '2', 'mes_tm_tool_status', '0', 'primary', '', '', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', X'00'),
+('3065', '3', '缁翠慨涓�', '3', 'mes_tm_tool_status', '0', 'warning', '', '', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', X'00'),
+('3066', '4', '鎶ュ簾', '4', 'mes_tm_tool_status', '0', 'danger', '', '', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', X'00'),
+('3067', '1', '瀹氭湡缁存姢', '1', 'mes_tm_mainten_type', '0', 'primary', '', '', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', X'00'),
+('3068', '2', '鎸変娇鐢ㄦ鏁扮淮鎶�', '2', 'mes_tm_mainten_type', '0', 'success', '', '', '1', '2026-02-16 11:10:55', '1', '2026-02-16 11:10:55', X'00'),
+('3069', '1', '鍋滄満', '1', 'mes_dv_machinery_status', '0', 'success', '', '', '1', '2026-02-17 01:00:06', '1', '2026-02-17 03:28:27', X'00'),
+('3070', '2', '鐢熶骇涓�', '2', 'mes_dv_machinery_status', '0', 'info', '', '', '1', '2026-02-17 01:00:06', '1', '2026-02-17 03:28:33', X'00'),
+('3071', '3', '缁存姢涓�', '3', 'mes_dv_machinery_status', '0', 'danger', '', '', '1', '2026-02-17 01:00:06', '1', '2026-02-17 03:28:41', X'00'),
+('3072', '1', '灏哄', '1', 'mes_indicator_type', '0', '', '', '', '1', '2026-02-17 02:18:18', '1', '2026-04-09 14:38:53', X'00'),
+('3073', '2', '澶栬', '2', 'mes_indicator_type', '0', '', '', '', '1', '2026-02-17 02:18:18', '1', '2026-04-09 14:38:53', X'00'),
+('3074', '3', '閲嶉噺', '3', 'mes_indicator_type', '0', '', '', '', '1', '2026-02-17 02:18:18', '1', '2026-04-09 14:38:53', X'00'),
+('3075', '4', '鎬ц兘', '4', 'mes_indicator_type', '0', '', '', '', '1', '2026-02-17 02:18:18', '1', '2026-04-09 14:38:53', X'00'),
+('3076', '5', '鎴愬垎', '5', 'mes_indicator_type', '0', '', '', '', '1', '2026-02-17 02:18:18', '1', '2026-04-09 14:38:53', X'00'),
+('3077', '1', '鑷村懡缂洪櫡', '1', 'mes_defect_level', '0', 'danger', '', '', '1', '2026-02-17 02:18:18', '1', '2026-02-21 12:21:12', X'00'),
+('3078', '2', '涓ラ噸缂洪櫡', '2', 'mes_defect_level', '0', 'warning', '', '', '1', '2026-02-17 02:18:18', '1', '2026-02-21 12:21:15', X'00'),
+('3079', '3', '杞诲井缂洪櫡', '3', 'mes_defect_level', '0', 'info', '', '', '1', '2026-02-17 02:18:18', '1', '2026-02-21 12:21:19', X'00'),
+('3080', '1', '鍗曠櫧鐝�', '1', 'mes_cal_shift_type', '0', 'primary', '', '', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', X'00'),
+('3081', '2', '涓ょ彮鍊�', '2', 'mes_cal_shift_type', '0', 'success', '', '', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', X'00'),
+('3082', '3', '涓夌彮鍊�', '3', 'mes_cal_shift_type', '0', 'warning', '', '', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', X'00'),
+('3083', '1', '鎸夊搴�', '1', 'mes_cal_shift_method', '0', '', '', '', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', X'00'),
+('3084', '2', '鎸夋湀', '2', 'mes_cal_shift_method', '0', '', '', '', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', X'00'),
+('3085', '3', '鎸夊懆', '3', 'mes_cal_shift_method', '0', '', '', '', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', X'00'),
+('3086', '4', '鎸夊ぉ', '4', 'mes_cal_shift_method', '0', '', '', '', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', X'00'),
+('3089', '0', '鑽夌', '0', 'mes_cal_plan_status', '0', 'info', '', '', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', X'00'),
+('3090', '1', '宸茬‘璁�', '1', 'mes_cal_plan_status', '0', 'success', '', '', '1', '2026-02-17 03:40:09', '1', '2026-02-17 03:40:09', X'00'),
+('3100', '0', '鑽夌', '0', 'mes_pro_work_order_status', '0', 'info', '', '', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', X'00'),
+('3101', '1', '宸茬‘璁�', '1', 'mes_pro_work_order_status', '0', 'primary', '', '', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', X'00'),
+('3102', '2', '宸插畬鎴�', '2', 'mes_pro_work_order_status', '0', 'success', '', '', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', X'00'),
+('3103', '3', '宸插彇娑�', '3', 'mes_pro_work_order_status', '0', 'warning', '', '', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', X'00'),
+('3104', '1', '瀹㈡埛璁㈠崟', '1', 'mes_pro_work_order_source_type', '0', 'primary', '', '', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', X'00'),
+('3105', '2', '搴撳瓨澶囪揣', '2', 'mes_pro_work_order_source_type', '0', 'success', '', '', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', X'00'),
+('3106', '1', '鑷鐢熶骇', '1', 'mes_pro_work_order_type', '0', 'primary', '', '', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', X'00'),
+('3107', '2', '浠e伐', '2', 'mes_pro_work_order_type', '0', 'warning', '', '', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', X'00'),
+('3108', '3', '閲囪喘', '3', 'mes_pro_work_order_type', '0', 'info', '', '', '1', '2026-02-17 11:43:47', '1', '2026-02-17 11:43:47', X'00'),
+('3121', '1', 'IQC锛堟潵鏂欐楠岋級', '1', 'mes_qc_type', '0', 'primary', '', '鏉ユ枡璐ㄩ噺妫�楠�', '1', '2026-02-18 14:12:05', '1', '2026-02-18 14:12:05', X'00'),
+('3122', '2', 'IPQC锛堣繃绋嬫楠岋級', '2', 'mes_qc_type', '0', 'warning', '', '鐢熶骇鍒剁▼璐ㄩ噺妫�楠�', '1', '2026-02-18 14:12:05', '1', '2026-03-24 15:21:34', X'00'),
+('3123', '3', 'OQC锛堝嚭璐ф楠岋級', '3', 'mes_qc_type', '0', 'success', '', '鍑鸿揣璐ㄩ噺妫�楠�', '1', '2026-02-18 14:12:05', '1', '2026-02-18 14:12:05', X'00'),
+('3124', '4', 'RQC锛堥��璐ф楠岋級', '4', 'mes_qc_type', '0', 'danger', '', '閫�璐ц川閲忔楠�', '1', '2026-02-18 14:12:05', '1', '2026-09-19 00:00:00', X'00'),
+('3125', '0', '寮�濮�-寮�濮�(SS)', '0', 'mes_pro_link_type', '0', 'default', '', '鍓嶅簭寮�濮嬪悗锛屽悗搴忓彲浠ュ紑濮�', '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', X'00'),
+('3126', '1', '缁撴潫-缁撴潫(FF)', '1', 'mes_pro_link_type', '0', 'default', '', '鍓嶅簭缁撴潫鍚庯紝鍚庡簭鎵嶈兘缁撴潫', '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', X'00'),
+('3127', '2', '寮�濮�-缁撴潫(SF)', '2', 'mes_pro_link_type', '0', 'default', '', '鍓嶅簭寮�濮嬪悗锛屽悗搴忔墠鑳界粨鏉�', '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', X'00'),
+('3128', '3', '缁撴潫-寮�濮�(FS)', '3', 'mes_pro_link_type', '0', 'default', '', '鍓嶅簭缁撴潫鍚庯紝鍚庡簭鎵嶈兘寮�濮�', '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', X'00'),
+('3129', '1', '鍒嗛挓', 'MINUTE', 'mes_time_unit_type', '0', 'default', '', '', '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', X'00'),
+('3130', '2', '灏忔椂', 'HOUR', 'mes_time_unit_type', '0', 'default', '', '', '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', X'00'),
+('3131', '3', '澶�', 'DAY', 'mes_time_unit_type', '0', 'default', '', '', '1', '2026-02-19 04:24:53', '1', '2026-02-19 04:24:53', X'00'),
+('3137', '1', '璁惧鐐规', '1', 'mes_dv_subject_type', '0', 'info', '', '', '1', '2026-02-20 01:42:58', '1', '2026-02-20 01:42:58', X'00'),
+('3138', '2', '璁惧淇濆吇', '2', 'mes_dv_subject_type', '0', 'success', '', '', '1', '2026-02-20 01:42:58', '1', '2026-02-20 01:42:58', X'00'),
+('3139', '1', '寰呬繚鍏�', '0', 'mes_mainten_record_status', '0', 'info', '', NULL, 'admin', '2026-02-20 02:59:55', '1', '2026-04-16 05:32:37', X'00'),
+('3140', '2', '宸插畬鎴�', '4', 'mes_mainten_record_status', '0', 'success', '', NULL, 'admin', '2026-02-20 02:59:55', '1', '2026-04-16 05:32:37', X'00'),
+('3141', '1', '姝e父', '1', 'mes_mainten_status', '0', 'success', '', NULL, 'admin', '2026-02-20 02:59:55', 'admin', '2026-02-20 02:59:55', X'00'),
+('3142', '2', '寮傚父', '0', 'mes_mainten_status', '0', 'danger', '', NULL, 'admin', '2026-02-20 02:59:55', 'admin', '2026-02-20 02:59:55', X'00'),
+('3143', '1', '澶�', '1', 'mes_dv_cycle_type', '0', 'default', '', '', '1', '2026-02-20 07:11:43', '1', '2026-02-20 07:11:43', X'00'),
+('3144', '2', '鍛�', '2', 'mes_dv_cycle_type', '0', 'default', '', '', '1', '2026-02-20 07:11:43', '1', '2026-02-20 07:11:43', X'00'),
+('3145', '3', '鏈�', '3', 'mes_dv_cycle_type', '0', 'default', '', '', '1', '2026-02-20 07:11:43', '1', '2026-02-20 07:11:43', X'00'),
+('3146', '4', '骞�', '4', 'mes_dv_cycle_type', '0', 'default', '', '', '1', '2026-02-20 07:11:43', '1', '2026-02-20 07:11:43', X'00'),
+('3147', '0', '鑽夌', '0', 'mes_dv_check_plan_status', '0', 'info', '', '', '1', '2026-02-20 07:11:43', '1', '2026-02-20 07:11:43', X'00'),
+('3148', '1', '宸插惎鐢�', '1', 'mes_dv_check_plan_status', '0', 'success', '', '', '1', '2026-02-20 07:11:43', '1', '2026-02-20 07:11:43', X'00'),
+('3149', '1', '寰呯偣妫�', '10', 'mes_dv_check_record_status', '0', 'info', '', NULL, 'admin', '2026-02-20 09:46:19', 'admin', '2026-02-20 09:46:19', X'00'),
+('3150', '2', '宸插畬鎴�', '20', 'mes_dv_check_record_status', '0', 'success', '', NULL, 'admin', '2026-02-20 09:46:19', 'admin', '2026-02-20 09:46:19', X'00'),
+('3151', '1', '姝e父', '1', 'mes_dv_check_result', '0', 'success', '', NULL, 'admin', '2026-02-20 09:46:19', 'admin', '2026-02-20 09:46:19', X'00'),
+('3152', '2', '寮傚父', '2', 'mes_dv_check_result', '0', 'danger', '', NULL, 'admin', '2026-02-20 09:46:19', 'admin', '2026-02-20 09:46:19', X'00'),
+('3157', '1', '淇鎴愬姛', '1', 'mes_dv_repair_result', '0', 'success', '', '', '1', '2026-02-20 10:56:24', '1', '2026-02-20 10:56:24', X'00'),
+('3158', '2', '鎶ュ簾', '2', 'mes_dv_repair_result', '0', 'danger', '', '', '1', '2026-02-20 10:56:24', '1', '2026-02-20 10:56:24', X'00'),
+('3161', '1', '鏍¢獙閫氳繃', '1', 'mes_qc_check_result', '0', 'success', '', '', '1', '2026-02-20 11:23:35', '1', '2026-02-20 16:15:54', X'00'),
+('3162', '2', '鏍¢獙涓嶉�氳繃', '2', 'mes_qc_check_result', '0', 'danger', '', '', '1', '2026-02-20 11:23:35', '1', '2026-02-20 16:15:52', X'00'),
+('3166', '0', '鏈缃�', '0', 'mes_pro_andon_status', '0', 'danger', '', '', '1', '2026-02-21 00:08:38', '1', '2026-02-21 00:08:38', X'00'),
+('3167', '1', '宸插缃�', '1', 'mes_pro_andon_status', '0', 'success', '', '', '1', '2026-02-21 00:08:38', '1', '2026-02-21 00:08:38', X'00'),
+('3168', '1', '涓�绾�', '1', 'mes_pro_andon_level', '0', 'danger', '', '', '1', '2026-02-21 00:08:38', '1', '2026-02-21 00:08:38', X'00'),
+('3169', '2', '浜岀骇', '2', 'mes_pro_andon_level', '0', 'warning', '', '', '1', '2026-02-21 00:08:38', '1', '2026-02-21 00:08:38', X'00'),
+('3170', '3', '涓夌骇', '3', 'mes_pro_andon_level', '0', 'info', '', '', '1', '2026-02-21 00:08:38', '1', '2026-02-21 00:08:38', X'00'),
+('3171', '0', '鑽夌', '0', 'mes_pro_feedback_status', '0', 'info', '', '', '1', '2026-02-21 00:50:32', '1', '2026-02-21 00:50:32', X'00'),
+('3172', '2', '瀹℃壒涓�', '2', 'mes_pro_feedback_status', '0', 'primary', '', '', '1', '2026-02-21 00:50:32', '1', '2026-03-19 00:51:54', X'00'),
+('3173', '3', '寰呮楠�', '3', 'mes_pro_feedback_status', '0', 'warning', '', '', '1', '2026-02-21 00:50:32', '1', '2026-03-19 00:51:54', X'00'),
+('3174', '4', '宸插畬鎴�', '4', 'mes_pro_feedback_status', '0', 'success', '', '', '1', '2026-02-21 00:50:32', '1', '2026-03-19 00:51:54', X'00'),
+('3176', '1', '鑷鎶ュ伐', '1', 'mes_pro_feedback_type', '0', 'primary', '', '', '1', '2026-02-21 00:50:32', '1', '2026-02-21 00:50:32', X'00'),
+('3177', '2', '缁熶竴鎶ュ伐', '2', 'mes_pro_feedback_type', '0', 'success', '', '', '1', '2026-02-21 00:50:32', '1', '2026-02-21 00:50:32', X'00'),
+('3178', '1', 'PC', 'PC', 'mes_pro_feedback_channel', '0', 'primary', '', '', '1', '2026-02-21 00:50:32', '1', '2026-02-21 00:50:32', X'00'),
+('3179', '2', 'APP', 'APP', 'mes_pro_feedback_channel', '0', 'success', '', '', '1', '2026-02-21 00:50:32', '1', '2026-02-21 00:50:32', X'00'),
+('3180', '3', 'PDA', 'PDA', 'mes_pro_feedback_channel', '0', 'info', '', '', '1', '2026-02-21 00:50:32', '1', '2026-02-21 00:50:32', X'00'),
+('3181', '1', '娴偣', '1', 'mes_qc_result_type', '0', 'primary', '', '', '1', '2026-02-21 13:37:17', '1', '2026-02-21 13:37:17', X'00'),
+('3182', '2', '鏁存暟', '2', 'mes_qc_result_type', '0', 'success', '', '', '1', '2026-02-21 13:37:17', '1', '2026-02-21 13:37:17', X'00'),
+('3183', '3', '鏂囨湰', '3', 'mes_qc_result_type', '0', 'info', '', '', '1', '2026-02-21 13:37:17', '1', '2026-02-21 13:37:17', X'00'),
+('3184', '4', '瀛楀吀', '4', 'mes_qc_result_type', '0', 'warning', '', '', '1', '2026-02-21 13:37:17', '1', '2026-02-21 13:37:17', X'00'),
+('3185', '5', '鏂囦欢', '5', 'mes_qc_result_type', '0', 'danger', '', '', '1', '2026-02-21 13:37:17', '1', '2026-02-21 13:37:17', X'00'),
+('3186', '1', '鐢熶骇閫�鏂�', '1', 'mes_rqc_type', '0', 'default', '', '鐢熶骇閫�鏂欐楠�', '1', '2026-02-22 06:44:09', '1', '2026-02-22 06:44:09', X'00'),
+('3187', '2', '閿�鍞��璐�', '2', 'mes_rqc_type', '0', 'default', '', '閿�鍞��璐ф楠�', '1', '2026-02-22 06:44:09', '1', '2026-02-22 06:44:09', X'00'),
+('3188', '1', '鑷埗宸ュ簭妫�楠�', '1', 'mes_ipqc_type', '0', 'primary', '', '', '1', '2026-02-22 07:01:04', '1', '2026-02-22 07:01:04', X'00'),
+('3189', '2', '棣栨', '2', 'mes_ipqc_type', '0', 'success', '', '', '1', '2026-02-22 07:01:04', '1', '2026-02-22 07:01:04', X'00'),
+('3190', '3', '宸℃', '3', 'mes_ipqc_type', '0', 'warning', '', '', '1', '2026-02-22 07:01:04', '1', '2026-02-22 07:01:04', X'00'),
+('3191', '4', '鑷', '4', 'mes_ipqc_type', '0', 'info', '', '', '1', '2026-02-22 07:01:04', '1', '2026-02-22 07:01:04', X'00'),
+('3192', '5', '鎴愬搧妫�楠�', '5', 'mes_ipqc_type', '0', 'danger', '', '', '1', '2026-02-22 07:01:04', '1', '2026-02-22 07:01:04', X'00'),
+('3205', '0', '鑽夌', '0', 'mes_wm_arrival_notice_status', '0', 'info', '', '', '1', '2026-02-22 14:53:18', '1', '2026-02-22 14:53:18', X'00'),
+('3206', '2', '寰呰川妫�', '2', 'mes_wm_arrival_notice_status', '0', 'warning', '', '', '1', '2026-02-22 14:53:18', '1', '2026-02-26 05:24:40', X'00'),
+('3207', '3', '寰呭叆搴�', '3', 'mes_wm_arrival_notice_status', '0', 'success', '', '', '1', '2026-02-22 14:53:18', '1', '2026-02-26 05:24:47', X'00'),
+('3208', '4', '宸插畬鎴�', '4', 'mes_wm_arrival_notice_status', '0', 'primary', '', '', '1', '2026-02-22 14:53:18', '1', '2026-02-26 05:24:52', X'00'),
+('3209', '0', '鑽夌', '0', 'mes_wm_item_receipt_status', '0', 'info', '', '', '1', '2026-02-22 14:54:05', '1', '2026-02-22 14:54:05', X'00'),
+('3210', '1', '寰呬笂鏋�', '2', 'mes_wm_item_receipt_status', '0', 'warning', '', '', '1', '2026-02-22 14:54:05', '1', '2026-02-26 08:03:35', X'00'),
+('3211', '2', '寰呮墽琛屽叆搴�', '3', 'mes_wm_item_receipt_status', '0', 'success', '', '', '1', '2026-02-22 14:54:05', '1', '2026-02-26 08:03:31', X'00'),
+('3212', '3', '宸插畬鎴�', '4', 'mes_wm_item_receipt_status', '0', 'primary', '', '', '1', '2026-02-22 14:54:05', '1', '2026-02-26 08:03:20', X'00'),
+('3213', '4', '宸插彇娑�', '5', 'mes_wm_item_receipt_status', '0', 'danger', '', '', '1', '2026-02-22 14:54:05', '1', '2026-02-26 08:03:24', X'00'),
+('3214', '1', '鑽夌', '0', 'mes_order_status', '0', 'info', '', '', '1', '2026-02-23 21:16:03', '1', '2026-02-23 21:16:03', X'00'),
+('3215', '2', '宸茬‘璁�', '1', 'mes_order_status', '0', 'primary', '', '', '1', '2026-02-23 21:16:03', '1', '2026-02-23 21:16:03', X'00'),
+('3216', '3', '瀹℃壒涓�', '2', 'mes_order_status', '0', 'warning', '', '', '1', '2026-02-23 21:16:03', '1', '2026-02-23 21:16:03', X'00'),
+('3217', '4', '宸插鎵�', '3', 'mes_order_status', '0', 'success', '', '', '1', '2026-02-23 21:16:03', '1', '2026-02-23 21:16:03', X'00'),
+('3218', '5', '宸插畬鎴�', '4', 'mes_order_status', '0', 'success', '', '', '1', '2026-02-23 21:16:03', '1', '2026-02-23 21:16:03', X'00'),
+('3219', '6', '宸插彇娑�', '5', 'mes_order_status', '0', 'danger', '', '', '1', '2026-02-23 21:16:03', '1', '2026-02-23 21:16:03', X'00'),
+('3220', '1', '鑽夌', '0', 'mes_wm_issue_status', '0', 'info', '', '鑽夌鐘舵�侊紝鏈畬鎴�', '1', '2026-02-26 15:54:25', '1', '2026-02-26 15:54:25', X'00'),
+('3221', '2', '宸插畬鎴�', '4', 'mes_wm_issue_status', '0', 'success', '', '宸插畬鎴愬嚭搴�', '1', '2026-02-26 15:54:25', '1', '2026-02-26 15:54:25', X'00'),
+('3222', '1', '鑽夌', '0', 'mes_wm_product_issue_status', '0', 'info', '', '鑽夌鐘舵�侊紝鍙紪杈�', '1', '2026-02-26 16:39:12', '1', '2026-03-23 13:18:02', X'00'),
+('3223', '2', '寰呮嫞璐�', '2', 'mes_wm_product_issue_status', '0', 'warning', '', '瀹℃壒涓紝鍙墽琛屾嫞璐�', '1', '2026-02-26 16:39:12', '1', '2026-03-23 13:18:02', X'00'),
+('3224', '3', '寰呮墽琛岄鍑�', '3', 'mes_wm_product_issue_status', '0', 'primary', '', '宸插鎵癸紝鎷h揣瀹屾垚', '1', '2026-02-26 16:39:12', '1', '2026-03-23 13:18:02', X'00'),
+('3225', '4', '宸插畬鎴�', '4', 'mes_wm_product_issue_status', '0', 'success', '', '宸插畬鎴愬嚭搴�', '1', '2026-02-26 16:39:12', '1', '2026-03-23 13:18:02', X'00'),
+('3226', '5', '宸插彇娑�', '5', 'mes_wm_product_issue_status', '0', 'success', '', '宸插畬鎴愬嚭搴�', '1', '2026-02-26 16:39:12', '1', '2026-03-23 13:18:02', X'00'),
+('3232', '1', '鑽夌', '0', 'mes_wm_return_issue_status', '0', 'info', '', '鑽夌鐘舵�侊紝鍙紪杈�', '1', '2026-02-28 14:11:12', '1', '2026-02-28 14:28:24', X'00'),
+('3233', '2', '寰呮楠�', '1', 'mes_wm_return_issue_status', '0', 'default', '', '宸茬‘璁わ紝绛夊緟璐ㄦ', '1', '2026-02-28 14:11:12', '1', '2026-02-28 14:28:28', X'00'),
+('3234', '3', '寰呬笂鏋�', '2', 'mes_wm_return_issue_status', '0', 'warning', '', '妫�楠屽畬鎴愶紝绛夊緟浠撳簱涓婃灦', '1', '2026-02-28 14:11:12', '1', '2026-02-28 14:28:31', X'00'),
+('3235', '4', '寰呮墽琛岄��鏂�', '3', 'mes_wm_return_issue_status', '0', 'primary', '', '涓婃灦瀹屾垚锛岀瓑寰呮墽琛岄��鏂欐搷浣�', '1', '2026-02-28 14:11:12', '1', '2026-02-28 14:28:34', X'00'),
+('3236', '5', '宸插畬鎴�', '4', 'mes_wm_return_issue_status', '0', 'success', '', '閫�鏂欐墽琛屽畬鎴愶紝搴撳瓨宸叉洿鏂�', '1', '2026-02-28 14:11:12', '1', '2026-02-28 14:28:37', X'00'),
+('3237', '6', '宸插彇娑�', '5', 'mes_wm_return_issue_status', '0', 'danger', '', '宸插彇娑�', '1', '2026-02-28 14:11:12', '1', '2026-02-28 14:28:40', X'00'),
+('3238', '1', '浣欐枡閫�鏂�', '1', 'mes_wm_return_issue_type', '0', 'success', '', '浣欐枡閫�鍥烇紝鐩存帴鍚堟牸', '1', '2026-02-28 14:11:12', '1', '2026-02-28 14:27:47', X'00'),
+('3239', '2', '涓嶈壇閫�鏂�', '2', 'mes_wm_return_issue_type', '0', 'danger', '', '涓嶈壇鍝侀��鍥�', '1', '2026-02-28 14:11:12', '1', '2026-02-28 14:27:49', X'00'),
+('3240', '3', '鍏朵粬閫�鏂�', '3', 'mes_wm_return_issue_type', '0', 'info', '', '鍏朵粬鍘熷洜閫�鏂�', '1', '2026-02-28 14:11:12', '1', '2026-02-28 14:27:55', X'00'),
+('3241', '1', '寰呮', '0', 'mes_wm_quality_status', '0', 'warning', '', '寰呮鐘舵��', '1', '2026-02-28 15:00:53', '1', '2026-02-28 15:00:53', X'00'),
+('3242', '2', '鍚堟牸', '1', 'mes_wm_quality_status', '0', 'success', '', '鍚堟牸鐘舵��', '1', '2026-02-28 15:00:53', '1', '2026-02-28 15:00:53', X'00'),
+('3243', '3', '涓嶅悎鏍�', '2', 'mes_wm_quality_status', '0', 'danger', '', '涓嶅悎鏍肩姸鎬�', '1', '2026-02-28 15:00:53', '1', '2026-02-28 15:00:53', X'00'),
+('3244', '1', '鑽夌', '0', 'mes_wm_product_receipt_status', '0', 'info', '', '鑽夌鐘舵��', '1', '2026-03-01 06:03:07', '1', '2026-03-01 06:03:07', X'00'),
+('3245', '2', '寰呬笂鏋�', '2', 'mes_wm_product_receipt_status', '0', 'primary', '', '寰呬笂鏋�', '1', '2026-03-01 06:03:07', '1', '2026-03-01 06:03:07', X'00'),
+('3246', '3', '寰呮墽琛屽叆搴�', '3', 'mes_wm_product_receipt_status', '0', 'warning', '', '寰呮墽琛屽叆搴�', '1', '2026-03-01 06:03:07', '1', '2026-03-01 06:03:07', X'00'),
+('3247', '4', '宸插畬鎴�', '4', 'mes_wm_product_receipt_status', '0', 'success', '', '宸插畬鎴�', '1', '2026-03-01 06:03:07', '1', '2026-03-01 06:03:07', X'00'),
+('3248', '5', '宸插彇娑�', '5', 'mes_wm_product_receipt_status', '0', 'danger', '', '宸插彇娑�', '1', '2026-03-01 06:03:07', '1', '2026-03-01 06:03:07', X'00'),
+('3252', '1', '鑽夌', '0', 'mes_wm_product_sales_status', '0', 'info', '', '鑽夌鐘舵��', '1', '2026-03-02 08:55:11', '1', '2026-03-02 08:55:11', X'00'),
+('3253', '3', '寰呮嫞璐�', '2', 'mes_wm_product_sales_status', '0', 'warning', '', '寰呮嫞璐х姸鎬�', '1', '2026-03-02 08:55:11', '1', '2026-03-27 11:44:48', X'00'),
+('3254', '4', '寰呭嚭搴�', '3', 'mes_wm_product_sales_status', '0', 'primary', '', '寰呭嚭搴撶姸鎬�', '1', '2026-03-02 08:55:11', '1', '2026-03-27 11:44:48', X'00'),
+('3255', '5', '宸插畬鎴�', '4', 'mes_wm_product_sales_status', '0', 'success', '', '宸插畬鎴愮姸鎬�', '1', '2026-03-02 08:55:11', '1', '2026-03-27 11:44:48', X'00'),
+('3256', '6', '宸插彇娑�', '5', 'mes_wm_product_sales_status', '0', 'danger', '', '宸插彇娑堢姸鎬�', '1', '2026-03-02 08:55:11', '1', '2026-03-27 11:44:48', X'00'),
+('3272', '1', '鑽夌', '0', 'mes_wm_misc_receipt_status', '0', 'info', '', '鑽夌鐘舵��', '1', '2026-03-03 07:33:41', '1', '2026-03-03 07:33:41', X'00'),
+('3273', '2', '寰呮墽琛屽叆搴�', '3', 'mes_wm_misc_receipt_status', '0', 'primary', '', '寰呮墽琛屽叆搴撶姸鎬�', '1', '2026-03-03 07:33:41', '1', '2026-03-03 07:37:34', X'00'),
+('3274', '3', '宸插畬鎴�', '4', 'mes_wm_misc_receipt_status', '0', 'success', '', '宸插畬鎴愮姸鎬�', '1', '2026-03-03 07:33:41', '1', '2026-03-03 07:33:41', X'00'),
+('3275', '4', '宸插彇娑�', '5', 'mes_wm_misc_receipt_status', '0', 'danger', '', '宸插彇娑堢姸鎬�', '1', '2026-03-03 07:33:41', '1', '2026-03-03 07:33:41', X'00'),
+('3277', '1', '搴撳瓨璋冩暣', '1', 'mes_wm_misc_receipt_type', '0', 'primary', '', '搴撳瓨璋冩暣鍏ュ簱', '1', '2026-03-03 07:34:33', '1', '2026-03-03 07:34:33', X'00'),
+('3278', '1', '搴撳瓨璋冩暣', '1', 'mes_wm_misc_issue_type', '0', 'primary', '', '搴撳瓨璋冩暣鍑哄簱', '1', '2026-03-03 07:34:33', '1', '2026-03-03 07:34:33', X'00'),
+('3279', '2', '鎶ュ簾鍑哄簱', '2', 'mes_wm_misc_issue_type', '0', 'danger', '', '鎶ュ簾鍑哄簱', '1', '2026-03-03 07:36:13', '1', '2026-03-03 07:36:13', X'00'),
+('3280', '1', '鑽夌', '0', 'mes_wm_outsource_receipt_status', '0', 'info', '', '鑽夌鐘舵��', '1', '2026-03-03 14:03:57', '1', '2026-03-03 14:03:57', X'00'),
+('3281', '2', '寰呮楠�', '1', 'mes_wm_outsource_receipt_status', '0', 'warning', '', '宸茬‘璁わ紝绛夊緟璐ㄦ', '1', '2026-03-03 14:03:57', '1', '2026-03-03 14:03:57', X'00'),
+('3282', '3', '寰呬笂鏋�', '2', 'mes_wm_outsource_receipt_status', '0', 'primary', '', '妫�楠屽畬鎴愶紝绛夊緟浠撳簱涓婃灦', '1', '2026-03-03 14:03:57', '1', '2026-03-03 14:03:57', X'00'),
+('3283', '4', '寰呮墽琛屽叆搴�', '3', 'mes_wm_outsource_receipt_status', '0', 'warning', '', '涓婃灦瀹屾垚锛岀瓑寰呮墽琛屽叆搴撴搷浣�', '1', '2026-03-03 14:03:57', '1', '2026-03-03 14:03:57', X'00'),
+('3284', '5', '宸插畬鎴�', '4', 'mes_wm_outsource_receipt_status', '0', 'success', '', '鍏ュ簱鎵ц瀹屾垚锛屽簱瀛樺凡鏇存柊', '1', '2026-03-03 14:03:57', '1', '2026-03-03 14:03:57', X'00'),
+('3285', '6', '宸插彇娑�', '5', 'mes_wm_outsource_receipt_status', '0', 'danger', '', '宸插彇娑�', '1', '2026-03-03 14:03:57', '1', '2026-03-03 14:03:57', X'00'),
+('3286', '1', '鑽夌', '0', 'mes_wm_outsource_issue_status', '0', 'info', '', '鑽夌鐘舵�侊紝鍙紪杈戙�佸垹闄ゃ�佹墽琛屽嚭搴�', '1', '2026-03-03 16:31:00', '1', '2026-03-03 16:31:00', X'00'),
+('3287', '2', '寰呮嫞璐�', '2', 'mes_wm_outsource_issue_status', '0', 'warning', '', '寰呮嫞璐х姸鎬�', '1', '2026-03-03 16:31:00', '1', '2026-03-03 16:31:00', X'00'),
+('3288', '3', '寰呮墽琛屽嚭搴�', '3', 'mes_wm_outsource_issue_status', '0', 'primary', '', '寰呮墽琛屽嚭搴撶姸鎬�', '1', '2026-03-03 16:31:00', '1', '2026-03-03 16:31:00', X'00'),
+('3289', '4', '宸插畬鎴�', '4', 'mes_wm_outsource_issue_status', '0', 'success', '', '宸插畬鎴愶紝搴撳瓨宸叉墸鍑�', '1', '2026-03-03 16:31:00', '1', '2026-03-03 16:31:00', X'00'),
+('3290', '5', '宸插彇娑�', '5', 'mes_wm_outsource_issue_status', '0', 'danger', '', '宸插彇娑堢姸鎬�', '1', '2026-03-03 16:31:00', '1', '2026-03-03 16:31:00', X'00'),
+('3301', '1', '杈撳叆瀛楃', '1', 'mes_md_auto_code_part_type', '0', 'default', '', '杈撳叆瀛楃', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', X'00'),
+('3302', '2', '褰撳墠鏃ユ湡', '2', 'mes_md_auto_code_part_type', '0', 'primary', '', '褰撳墠鏃ユ湡鏃堕棿', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', X'00'),
+('3303', '3', '鍥哄畾瀛楃', '3', 'mes_md_auto_code_part_type', '0', 'success', '', '鍥哄畾瀛楃', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', X'00'),
+('3304', '4', '娴佹按鍙�', '4', 'mes_md_auto_code_part_type', '0', 'warning', '', '娴佹按鍙�', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', X'00'),
+('3305', '1', '宸﹁ˉ榻�', '1', 'mes_md_auto_code_padded_method', '0', 'primary', '', '宸﹁ˉ榻�', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', X'00'),
+('3306', '2', '鍙宠ˉ榻�', '2', 'mes_md_auto_code_padded_method', '0', 'success', '', '鍙宠ˉ榻�', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', X'00'),
+('3307', '1', '鎸夊勾', '1', 'mes_md_auto_code_cycle_method', '0', 'default', '', '鎸夊勾寰幆', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', X'00'),
+('3308', '2', '鎸夋湀', '2', 'mes_md_auto_code_cycle_method', '0', 'primary', '', '鎸夋湀寰幆', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', X'00'),
+('3309', '3', '鎸夊ぉ', '3', 'mes_md_auto_code_cycle_method', '0', 'success', '', '鎸夊ぉ寰幆', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', X'00'),
+('3310', '4', '鎸夊皬鏃�', '4', 'mes_md_auto_code_cycle_method', '0', 'warning', '', '鎸夊皬鏃跺惊鐜�', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', X'00'),
+('3311', '5', '鎸夊垎閽�', '5', 'mes_md_auto_code_cycle_method', '0', 'danger', '', '鎸夊垎閽熷惊鐜�', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', X'00'),
+('3312', '10', '鎸変紶鍏ュ瓧绗�', '10', 'mes_md_auto_code_cycle_method', '0', 'info', '', '鎸変紶鍏ュ瓧绗﹀惊鐜�', '1', '2026-03-04 14:46:22', '1', '2026-03-04 15:24:40', X'00'),
+('3313', '1', '浜岀淮鐮�', '1', 'mes_wm_barcode_format', '0', 'primary', '', 'QR_CODE', '1', '2026-03-05 14:37:20', '1', '2026-03-06 13:18:21', X'00'),
+('3314', '2', 'EAN13 鍟嗗搧鏉$爜', '2', 'mes_wm_barcode_format', '0', 'success', '', 'EAN13', '1', '2026-03-05 14:37:20', '1', '2026-03-06 13:18:23', X'00'),
+('3315', '3', 'CODE39 宸ヤ笟鏉$爜', '3', 'mes_wm_barcode_format', '0', 'info', '', 'CODE39', '1', '2026-03-05 14:37:20', '1', '2026-03-06 13:18:25', X'00'),
+('3316', '4', 'UPC-A 缇庡浗鍟嗗搧鐮�', '4', 'mes_wm_barcode_format', '0', 'warning', '', 'UPC_A', '1', '2026-03-05 14:37:20', '1', '2026-03-06 13:18:28', X'00'),
+('3318', '3', '搴撲綅', '104', 'mes_wm_barcode_biz_type', '0', 'default', '', 'AREA', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', X'00'),
+('3319', '4', '瑁呯鍗�', '105', 'mes_wm_barcode_biz_type', '0', 'default', '', 'PACKAGE', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', X'00'),
+('3320', '5', '搴撳瓨', '106', 'mes_wm_barcode_biz_type', '0', 'default', '', 'STOCK', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', X'00'),
+('3321', '6', '鎵规', '107', 'mes_wm_barcode_biz_type', '0', 'default', '', 'BATCH', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', X'00'),
+('3322', '7', '娴佽浆鍗�', '300', 'mes_wm_barcode_biz_type', '0', 'primary', '', 'PROCARD', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', X'00'),
+('3323', '8', '宸ュ崟', '301', 'mes_wm_barcode_biz_type', '0', 'primary', '', 'WORKORDER', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', X'00'),
+('3324', '9', '娴佽浆鍗�', '302', 'mes_wm_barcode_biz_type', '0', 'primary', '', 'TRANSORDER', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', X'00'),
+('3325', '10', '璁惧', '400', 'mes_wm_barcode_biz_type', '0', 'success', '', 'MACHINERY', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', X'00'),
+('3327', '12', '浜у搧鐗╂枡', '600', 'mes_wm_barcode_biz_type', '0', 'info', '', 'ITEM', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', X'00'),
+('3328', '13', '渚涘簲鍟�', '601', 'mes_wm_barcode_biz_type', '0', 'info', '', 'VENDOR', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', X'00'),
+('3329', '14', '宸ヤ綔绔�', '602', 'mes_wm_barcode_biz_type', '0', 'info', '', 'WORKSTATION', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', X'00'),
+('3330', '15', '杞﹂棿', '603', 'mes_wm_barcode_biz_type', '0', 'info', '', 'WORKSHOP', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', X'00'),
+('3331', '16', '浜哄憳', '604', 'mes_wm_barcode_biz_type', '0', 'info', '', 'USER', '1', '2026-03-05 14:37:20', '1', '2026-03-07 06:25:19', X'00'),
+('3351', '1', '浠撳簱', '102', 'mes_wm_barcode_biz_type', '0', '', '', NULL, '', '2026-03-07 06:22:27', '', '2026-03-07 06:25:19', X'00'),
+('3352', '2', '搴撳尯', '103', 'mes_wm_barcode_biz_type', '0', '', '', NULL, '', '2026-03-07 06:22:27', '', '2026-03-07 06:25:19', X'00'),
+('3353', '11', '宸ュ叿', '500', 'mes_wm_barcode_biz_type', '0', '', '', NULL, '', '2026-03-07 06:22:27', '', '2026-03-07 06:22:27', X'00'),
+('3354', '17', '瀹㈡埛', '605', 'mes_wm_barcode_biz_type', '0', '', '', NULL, '', '2026-03-07 06:22:27', '', '2026-03-07 06:25:19', X'00'),
+('3355', '1', '鑽夌', '0', 'mes_wm_package_status', '0', 'info', '', '鑽夌鐘舵�侊紝鍙紪杈�', '1', '2026-03-08 02:05:46', '1', '2026-03-08 02:05:46', X'00'),
+('3356', '2', '宸插畬鎴�', '4', 'mes_wm_package_status', '0', 'success', '', '瑁呯宸插畬鎴�', '1', '2026-03-08 02:05:46', '1', '2026-03-08 02:05:46', X'00'),
+('3357', '1', '鑽夌', '0', 'mes_wm_transfer_status', '0', 'info', '', '鑽夌鐘舵�侊紝鍙紪杈�', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', X'00'),
+('3358', '2', '寰呯‘璁�', '1', 'mes_wm_transfer_status', '0', 'warning', '', '澶栭儴璋冩嫧寰呯‘璁ゅ埌璐�', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', X'00'),
+('3359', '3', '寰呬笂鏋�', '2', 'mes_wm_transfer_status', '0', 'primary', '', '寰呯淮鎶ょ洰鏍囧簱浣嶆槑缁�', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', X'00'),
+('3360', '4', '寰呮墽琛�', '3', 'mes_wm_transfer_status', '0', 'success', '', '鐩爣搴撲綅宸插垎閰嶏紝寰呮墽琛岃皟鎷�', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', X'00'),
+('3361', '5', '宸插畬鎴�', '4', 'mes_wm_transfer_status', '0', 'success', '', '璋冩嫧宸插畬鎴�', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', X'00'),
+('3362', '6', '宸插彇娑�', '5', 'mes_wm_transfer_status', '0', 'danger', '', '璋冩嫧宸插彇娑�', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', X'00'),
+('3363', '1', '鍐呴儴璋冩嫧', '1', 'mes_wm_transfer_type', '0', 'success', '', '鍐呴儴浠撳偍璋冩嫧', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', X'00'),
+('3364', '2', '澶栭儴璋冩嫧', '2', 'mes_wm_transfer_type', '0', 'warning', '', '澶栭儴閰嶉��/澶栭儴鏀惰揣璋冩嫧', '1', '2026-03-08 11:55:25', '1', '2026-03-08 11:55:25', X'00'),
+('3365', '1', '闈欐�佺洏鐐�', '1', 'mes_wm_stock_taking_type', '0', 'primary', '', '闈欐�佺洏鐐�', '1', '2026-03-09 00:00:00', '1', '2026-04-05 15:02:18', X'00'),
+('3366', '2', '鍔ㄦ�佺洏鐐�', '2', 'mes_wm_stock_taking_type', '0', 'success', '', '鍔ㄦ�佺洏鐐�', '1', '2026-03-09 00:00:00', '1', '2026-04-05 15:02:18', X'00'),
+('3367', '1', '浠撳簱', '102', 'mes_wm_stock_taking_plan_param_type', '0', 'primary', '', '鎸変粨搴撶洏鐐�', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', X'00'),
+('3368', '2', '搴撳尯', '103', 'mes_wm_stock_taking_plan_param_type', '0', 'success', '', '鎸夊簱鍖虹洏鐐�', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', X'00'),
+('3369', '3', '搴撲綅', '104', 'mes_wm_stock_taking_plan_param_type', '0', 'info', '', '鎸夊簱浣嶇洏鐐�', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', X'00'),
+('3370', '4', '鐗╂枡', '600', 'mes_wm_stock_taking_plan_param_type', '0', 'warning', '', '鎸夌墿鏂欑洏鐐�', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', X'00'),
+('3371', '5', '鎵规', '107', 'mes_wm_stock_taking_plan_param_type', '0', 'danger', '', '鎸夋壒娆$洏鐐�', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', X'00'),
+('3372', '1', '鑽夌', '0', 'mes_wm_stock_taking_task_status', '0', 'info', '', '鑽夌', '1', '2026-03-09 00:00:00', '1', '2026-04-05 15:02:18', X'00'),
+('3373', '2', '瀹℃壒涓�', '2', 'mes_wm_stock_taking_task_status', '0', 'primary', '', '鐩樼偣浠诲姟瀹℃壒涓�', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', X'00'),
+('3374', '3', '宸插畬鎴�', '4', 'mes_wm_stock_taking_task_status', '0', 'success', '', '宸插畬鎴�', '1', '2026-03-09 00:00:00', '1', '2026-04-05 15:02:18', X'00'),
+('3375', '4', '宸插彇娑�', '5', 'mes_wm_stock_taking_task_status', '0', 'danger', '', '宸插彇娑�', '1', '2026-03-09 00:00:00', '1', '2026-04-05 15:02:18', X'00'),
+('3377', '1', '姝e父', '1', 'mes_wm_stock_taking_task_line_status', '0', 'success', '', '姝e父', '1', '2026-03-09 00:00:00', '1', '2026-04-05 15:02:18', X'00'),
+('3378', '2', '鐩樼泩', '2', 'mes_wm_stock_taking_task_line_status', '0', 'primary', '', '鐩樼泩', '1', '2026-03-09 00:00:00', '1', '2026-04-05 15:02:18', X'00'),
+('3379', '3', '鐩樹簭', '3', 'mes_wm_stock_taking_task_line_status', '0', 'danger', '', '鐩樹簭', '1', '2026-03-09 00:00:00', '1', '2026-04-05 15:02:18', X'00'),
+('3380', '6', '璐ㄩ噺鐘舵��', '900', 'mes_wm_stock_taking_plan_param_type', '0', 'default', '', '鎸夎川閲忕姸鎬佺洏鐐�', '1', '2026-03-09 00:00:00', '1', '2026-03-09 00:00:00', X'00'),
+('3381', '1', '鐗╂枡', 'ITEM', 'mes_md_item_or_product', '0', 'info', '', '', '1', '2026-03-15 01:55:06', '1', '2026-03-15 01:55:06', X'00'),
+('3382', '2', '浜у搧', 'PRODUCT', 'mes_md_item_or_product', '0', 'success', '', '', '1', '2026-03-15 01:55:06', '1', '2026-03-15 01:55:06', X'00'),
+('3383', '1', '鑽夌', '0', 'mes_wm_item_consume_status', '0', 'info', '', '鑽夌鐘舵��', '1', '2026-03-19 15:06:23', '1', '2026-03-19 15:06:23', X'00'),
+('3384', '2', '宸插畬鎴�', '4', 'mes_wm_item_consume_status', '0', 'success', '', '宸插畬鎴�', '1', '2026-03-19 15:06:23', '1', '2026-03-19 15:06:23', X'00'),
+('3385', '1', '鍒拌揣閫氱煡鍗�', '100', 'mes_qc_source_doc_type', '0', 'primary', '', 'IQC', '1', '2026-03-26 13:01:09', '1', '2026-03-26 13:01:09', X'00'),
+('3386', '2', '澶栧崗鍏ュ簱鍗�', '121', 'mes_qc_source_doc_type', '0', 'warning', '', 'IQC', '1', '2026-03-26 13:01:09', '1', '2026-03-26 13:01:09', X'00'),
+('3387', '3', '鐢熶骇鎶ュ伐', '304', 'mes_qc_source_doc_type', '0', 'success', '', 'IPQC', '1', '2026-03-26 13:01:09', '1', '2026-03-26 13:01:09', X'00'),
+('3388', '4', '閿�鍞嚭搴撳崟', '118', 'mes_qc_source_doc_type', '0', 'info', '', 'OQC', '1', '2026-03-26 13:01:09', '1', '2026-03-26 13:01:09', X'00'),
+('3389', '5', '鐢熶骇閫�鏂欏崟', '116', 'mes_qc_source_doc_type', '0', 'danger', '', 'RQC', '1', '2026-03-26 13:01:09', '1', '2026-03-26 13:01:09', X'00'),
+('3390', '6', '閿�鍞��璐у崟', '119', 'mes_qc_source_doc_type', '0', 'default', '', 'RQC', '1', '2026-03-26 13:01:09', '1', '2026-03-26 13:01:09', X'00'),
+('3397', '2', '寰呮娴�', '1', 'mes_wm_product_sales_status', '0', 'warning', '', 'OQC 妫�楠屼腑', '1', '2026-03-27 11:44:48', '1', '2026-03-27 11:44:48', X'00'),
+('3398', '0', '鑽夌', '0', 'mes_wm_return_vendor_status', '0', 'info', '', NULL, '', '2026-03-29 13:49:57', '', '2026-04-05 15:53:46', X'00'),
+('3399', '1', '寰呮嫞璐�', '2', 'mes_wm_return_vendor_status', '0', 'primary', '', NULL, '', '2026-03-29 13:49:57', '', '2026-04-05 15:53:46', X'00'),
+('3400', '2', '寰呮墽琛岄��璐�', '3', 'mes_wm_return_vendor_status', '0', 'warning', '', NULL, '', '2026-03-29 13:49:57', '', '2026-04-05 15:53:46', X'00'),
+('3401', '3', '宸插畬鎴�', '4', 'mes_wm_return_vendor_status', '0', 'success', '', NULL, '', '2026-03-29 13:49:57', '', '2026-04-05 15:53:46', X'00'),
+('3402', '4', '宸插彇娑�', '5', 'mes_wm_return_vendor_status', '0', 'danger', '', NULL, '', '2026-03-29 13:49:57', '', '2026-04-05 15:53:46', X'00'),
+('3403', '1', '鑽夌', '0', 'mes_wm_sales_notice_status', '0', 'info', '', '鑽夌鐘舵�侊紝鍙互淇敼鍜屽垹闄�', '1', '2026-03-30 08:54:30', '1', '2026-04-05 15:53:46', X'00'),
+('3404', '2', '寰呭嚭搴�', '3', 'mes_wm_sales_notice_status', '0', 'success', '', '宸叉彁浜ょ姸鎬侊紝涓嶅彲淇敼鍜屽垹闄�', '1', '2026-03-30 08:54:30', '1', '2026-04-05 15:53:46', X'00'),
+('3405', '3', '宸插畬鎴�', '4', 'mes_wm_sales_notice_status', '0', '', '', NULL, '1', '2026-03-30 10:02:10', '1', '2026-04-05 15:53:46', X'00'),
+('3406', '1', '鑽夌', '0', 'mes_wm_misc_issue_status', '0', 'info', '', '鑽夌鐘舵��', '1', '2026-03-30 15:00:18', '1', '2026-03-30 15:00:18', X'00'),
+('3407', '2', '寰呭嚭搴�', '3', 'mes_wm_misc_issue_status', '0', 'warning', '', '寰呭嚭搴撶姸鎬�', '1', '2026-03-30 15:00:18', '1', '2026-03-30 15:00:18', X'00'),
+('3408', '3', '宸插畬鎴�', '4', 'mes_wm_misc_issue_status', '0', 'success', '', '鎵ц鍑哄簱鍚庣殑鐘舵��', '1', '2026-03-30 15:00:18', '1', '2026-03-30 15:00:18', X'00'),
+('3409', '4', '宸插彇娑�', '5', 'mes_wm_misc_issue_status', '0', 'danger', '', '宸插彇娑堢姸鎬�', '1', '2026-03-30 15:00:18', '1', '2026-03-30 15:00:18', X'00'),
+('3415', '1', '娉ㄥ', '1', 'mes_cal_calendar_type', '0', 'primary', '', '', '1', '2026-04-01 15:23:14', '1', '2026-04-01 16:08:31', X'00'),
+('3416', '2', '鎶曟枡宸�', '2', 'mes_cal_calendar_type', '0', 'success', '', '', '1', '2026-04-01 15:23:14', '1', '2026-08-25 16:35:23', X'00'),
+('3417', '3', '缁勮', '3', 'mes_cal_calendar_type', '0', 'warning', '', '', '1', '2026-04-01 15:23:14', '1', '2026-04-01 16:08:33', X'00'),
+('3418', '4', '浠撳簱', '4', 'mes_cal_calendar_type', '0', 'danger', '', '', '1', '2026-04-01 15:23:14', '1', '2026-04-01 16:08:34', X'00'),
+('3419', '0', '鑽夌', '0', 'mes_dv_repair_status', '0', 'info', '', '', '1', '2026-04-03 17:20:23', '1', '2026-04-03 17:20:23', X'00'),
+('3420', '1', '缁翠慨涓�', '1', 'mes_dv_repair_status', '0', 'primary', '', '', '1', '2026-04-03 17:20:23', '1', '2026-04-03 17:20:23', X'00'),
+('3421', '2', '寰呴獙鏀�', '2', 'mes_dv_repair_status', '0', 'warning', '', '', '1', '2026-04-03 17:20:23', '1', '2026-04-03 17:20:23', X'00'),
+('3422', '3', '宸茬‘璁�', '4', 'mes_dv_repair_status', '0', 'success', '', '', '1', '2026-04-03 17:20:23', '1', '2026-04-03 17:20:23', X'00'),
+('3423', '0', '鑽夌', '0', 'mes_wm_return_sales_status', '0', 'info', '', '', '1', '2026-04-03 17:20:25', '1', '2026-04-03 17:20:25', X'00'),
+('3424', '1', '寰呮楠�', '1', 'mes_wm_return_sales_status', '0', 'warning', '', '', '1', '2026-04-03 17:20:25', '1', '2026-04-03 17:20:25', X'00'),
+('3425', '2', '寰呮墽琛�', '2', 'mes_wm_return_sales_status', '0', 'warning', '', '', '1', '2026-04-03 17:20:25', '1', '2026-04-03 17:20:25', X'00'),
+('3426', '3', '寰呬笂鏋�', '3', 'mes_wm_return_sales_status', '0', 'primary', '', '', '1', '2026-04-03 17:20:25', '1', '2026-04-03 17:20:25', X'00'),
+('3427', '4', '宸插畬鎴�', '4', 'mes_wm_return_sales_status', '0', 'success', '', '', '1', '2026-04-03 17:20:25', '1', '2026-04-03 17:20:25', X'00'),
+('3428', '5', '宸插彇娑�', '5', 'mes_wm_return_sales_status', '0', 'danger', '', '', '1', '2026-04-03 17:20:25', '1', '2026-04-03 17:20:25', X'00'),
+('3436', '1', '涓婂伐', '1', 'mes_pro_work_record_type', '0', 'success', '', '', '1', '2026-04-05 14:07:27', '1', '2026-04-05 14:07:27', X'00'),
+('3437', '2', '涓嬪伐', '2', 'mes_pro_work_record_type', '0', 'danger', '', '', '1', '2026-04-05 14:07:27', '1', '2026-04-05 14:07:27', X'00'),
+('3443', '1', '鑽夌', '0', 'mes_wm_product_produce_status', '0', 'info', '', '鑽夌鐘舵��', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', X'00'),
+('3444', '2', '宸插畬鎴�', '4', 'mes_wm_product_produce_status', '0', 'success', '', '宸插畬鎴愮姸鎬�', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', X'00'),
+('3445', '3', '宸插彇娑�', '5', 'mes_wm_product_produce_status', '0', 'danger', '', '宸插彇娑堢姸鎬�', '1', '2026-04-05 15:53:46', '1', '2026-04-05 15:53:46', X'00'),
+('3446', '0', '鑽夌', '0', 'mes_pro_task_status', '0', 'default', '', 'PREPARE', '1', '2026-04-16 09:47:00', '1', '2026-06-13 10:32:58', X'00'),
+('3447', '4', '宸插畬鎴�', '4', 'mes_pro_task_status', '0', 'success', '', 'FINISHED', '1', '2026-04-16 09:47:00', '1', '2026-07-22 08:00:26', X'00'),
+('3448', '2', '宸插彇娑�', '5', 'mes_pro_task_status', '0', 'danger', '', 'CANCELED', '1', '2026-04-16 09:47:00', '1', '2026-06-13 10:32:58', X'00'),
+('3525', '1', '姝e父', '0', 'im_message_status', '0', 'success', '', '姝e父锛堝垵濮嬬姸鎬侊級', 'admin', '2026-04-30 15:14:36', 'admin', '2026-06-16 03:41:55', X'00'),
+('3526', '2', '宸叉挙鍥�', '2', 'im_message_status', '0', 'danger', '', '宸叉挙鍥�', 'admin', '2026-04-30 15:14:36', 'admin', '2026-06-16 03:41:55', X'00'),
+('3530', '1', '涓嶉渶瑕佸洖鎵�', '0', 'im_message_receipt_status', '0', 'info', '', 'NO_RECEIPT', 'admin', '2026-04-30 11:35:07', 'admin', '2026-06-14 00:32:47', X'00'),
+('3531', '2', '寰呭畬鎴�', '1', 'im_message_receipt_status', '0', 'warning', '', 'PENDING', 'admin', '2026-04-30 11:35:07', 'admin', '2026-06-14 00:32:47', X'00'),
+('3532', '3', '宸插畬鎴�', '2', 'im_message_receipt_status', '0', 'success', '', 'DONE', 'admin', '2026-04-30 11:35:07', 'admin', '2026-06-14 00:32:47', X'00'),
+('3540', '1', '姝e父', '0', 'im_friend_status', '0', 'success', '', '姝e父濂藉弸鍏崇郴', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', X'00'),
+('3541', '2', '宸插垹闄�', '1', 'im_friend_status', '0', 'danger', '', '宸插垹闄ゅソ鍙嬪叧绯�', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', X'00'),
+('3550', '1', '姝e父', '0', 'im_group_status', '0', 'success', '', '缇ゆ甯�', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', X'00'),
+('3551', '2', '宸茶В鏁�', '1', 'im_group_status', '0', 'info', '', '缇ゅ凡瑙f暎', 'admin', '2026-04-30 11:35:07', 'admin', '2026-04-30 11:35:07', X'00'),
+('3552', '1', '缇や富', '1', 'im_group_member_role', '0', 'primary', '', NULL, '1', '2026-05-02 02:14:12', '1', '2026-05-02 02:14:12', X'00'),
+('3553', '2', '绠$悊鍛�', '2', 'im_group_member_role', '0', 'warning', '', NULL, '1', '2026-05-02 02:14:12', '1', '2026-05-02 02:14:12', X'00'),
+('3554', '3', '鏅�氭垚鍛�', '3', 'im_group_member_role', '0', 'info', '', NULL, '1', '2026-05-02 02:14:12', '1', '2026-05-02 02:14:12', X'00'),
+('3555', '1', '鎼滅储', '1', 'im_friend_add_source', '0', 'default', '', NULL, '1', '2026-05-04 02:43:41', '1', '2026-05-05 11:46:57', X'00'),
+('3556', '2', '缇よ亰', '2', 'im_friend_add_source', '0', 'default', '', NULL, '1', '2026-05-04 02:43:41', '1', '2026-05-05 11:46:53', X'00'),
+('3557', '3', '鎵爜', '3', 'im_friend_add_source', '0', 'default', '', NULL, '1', '2026-05-04 02:43:41', '1', '2026-05-05 11:46:50', X'00'),
+('3558', '4', '鍚嶇墖', '4', 'im_friend_add_source', '0', 'default', '', NULL, '1', '2026-05-04 02:43:41', '1', '2026-05-05 11:46:48', X'00'),
+('3559', '1', '绛夊緟楠岃瘉', '0', 'im_friend_request_handle_result', '0', 'warning', '', NULL, '1', '2026-05-04 02:43:41', '1', '2026-05-04 02:43:41', X'00'),
+('3560', '2', '宸叉坊鍔�', '1', 'im_friend_request_handle_result', '0', 'success', '', NULL, '1', '2026-05-04 02:43:41', '1', '2026-05-04 02:43:41', X'00'),
+('3561', '3', '宸叉嫆缁�', '2', 'im_friend_request_handle_result', '0', 'info', '', NULL, '1', '2026-05-04 02:43:41', '1', '2026-05-04 02:43:41', X'00'),
+('3562', '101', '鏂囨湰', '101', 'im_content_type', '0', '', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3563', '102', '鍥剧墖', '102', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3564', '103', '璇煶', '103', 'im_content_type', '0', 'warning', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3565', '104', '瑙嗛', '104', 'im_content_type', '0', 'warning', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3566', '105', '鏂囦欢', '105', 'im_content_type', '0', 'info', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3568', '2101', '鎾ゅ洖', '2101', 'im_content_type', '0', 'danger', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3569', '2200', '鍥炴墽', '2200', 'im_content_type', '0', 'warning', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3570', '2201', '宸茶', '2201', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3571', '1501', '缇ゅ垱寤�', '1501', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3572', '1502', '缇や俊鎭彉鏇�', '1502', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3573', '1503', '鏀跺埌鏂扮殑鍏ョ兢鐢宠', '1503', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:47:00', X'00'),
+('3574', '1504', '鎴愬憳閫�缇�', '1504', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3575', '1505', '鍏ョ兢鐢宠琚悓鎰�', '1505', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:47:00', X'00'),
+('3576', '1506', '鍏ョ兢鐢宠琚嫆缁�', '1506', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:47:00', X'00'),
+('3577', '1507', '缇や富杞', '1507', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3578', '1508', '鎴愬憳琚Щ鍑�', '1508', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3579', '1509', '鎴愬憳鍔犲叆', '1509', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3580', '1510', '鑷敱杩涚兢', '1510', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3581', '1511', '缇よВ鏁�', '1511', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3582', '1512', '鎴愬憳绂佽█', '1512', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3583', '1513', '鎴愬憳鍙栨秷绂佽█', '1513', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3584', '1514', '鍏ㄧ兢绂佽█', '1514', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3585', '1515', '鍏ㄧ兢鍙栨秷绂佽█', '1515', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3586', '1516', '鎴愬憳鏄电О鍙樻洿', '1516', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3587', '1517', '娣诲姞绠$悊鍛�', '1517', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3588', '1518', '鎾ら攢绠$悊鍛�', '1518', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3589', '1519', '缇ゅ叕鍛婂彉鏇�', '1519', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3590', '1520', '缇ゅ悕鍙樻洿', '1520', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3591', '1531', '缇ゆ秷鎭疆椤�', '1531', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3592', '1532', '缇ゆ秷鎭彇娑堢疆椤�', '1532', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3593', '1533', '缇ゅ皝绂佸彉鏇�', '1533', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 11:52:30', 'admin', '2026-06-16 03:41:55', X'00'),
+('3594', '1204', '鏂板濂藉弸', '1204', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-05-05 13:26:53', 'admin', '2026-06-16 03:41:55', X'00'),
+('3595', '1205', '濂藉弸琚垹闄�', '1205', 'im_content_type', '0', 'warning', '', NULL, 'admin', '2026-05-05 13:26:53', 'admin', '2026-06-16 03:41:55', X'00'),
+('3596', '1', '鎼滅储', '1', 'im_group_add_source', '0', '', '', NULL, '', '2026-05-06 09:26:36', '', '2026-05-06 09:26:36', X'00'),
+('3597', '2', '閭�璇�', '2', 'im_group_add_source', '0', '', '', NULL, '', '2026-05-06 09:26:36', '', '2026-05-06 09:26:36', X'00'),
+('3598', '3', '鎵爜', '3', 'im_group_add_source', '0', '', '', NULL, '', '2026-05-06 09:26:36', '', '2026-05-06 09:26:36', X'00'),
+('3599', '4', '鍒嗕韩閾炬帴', '4', 'im_group_add_source', '0', '', '', NULL, '', '2026-05-06 09:26:36', '', '2026-05-06 09:26:36', X'00'),
+('3600', '1', '鏈鐞�', '0', 'im_group_request_handle_result', '0', '', '', NULL, '', '2026-05-06 09:26:36', '', '2026-05-06 09:26:36', X'00'),
+('3601', '2', '鍚屾剰', '1', 'im_group_request_handle_result', '0', '', '', NULL, '', '2026-05-06 09:26:36', '', '2026-05-06 09:26:36', X'00'),
+('3602', '3', '鎷掔粷', '2', 'im_group_request_handle_result', '0', '', '', NULL, '', '2026-05-06 09:26:36', '', '2026-05-06 09:26:36', X'00'),
+('1061051', '1', '瀹㈡埛', '1', 'merchant_type', '0', 'primary', '', '瀹㈡埛', '1', '2026-05-10 15:26:09', '1', '2026-05-10 15:26:09', X'00'),
+('1061052', '2', '渚涘簲鍟�', '2', 'merchant_type', '0', 'success', '', '渚涘簲鍟�', '1', '2026-05-10 15:26:09', '1', '2026-05-10 15:26:09', X'00'),
+('1061053', '3', '瀹㈡埛/渚涘簲鍟�', '3', 'merchant_type', '0', 'warning', '', '瀹㈡埛/渚涘簲鍟�', '1', '2026-05-10 15:26:09', '1', '2026-05-10 15:26:09', X'00'),
+('1061061', '1', '鍏ュ簱鍗�', '1', 'wms_order_type', '0', 'success', '', '', '1', '2026-05-10 17:51:46', '1', '2026-05-14 08:14:09', X'00'),
+('1061062', '2', '鍑哄簱鍗�', '2', 'wms_order_type', '0', 'danger', '', '', '1', '2026-05-10 17:51:46', '1', '2026-05-14 08:14:09', X'00'),
+('1061063', '3', '绉诲簱鍗�', '3', 'wms_order_type', '0', 'primary', '', '', '1', '2026-05-10 17:51:46', '1', '2026-05-14 08:14:09', X'00'),
+('1061064', '4', '鐩樺簱鍗�', '4', 'wms_order_type', '0', 'warning', '', '', '1', '2026-05-10 17:51:46', '1', '2026-05-14 08:14:09', X'00'),
+('1061071', '1', '鑽夌', '0', 'wms_order_status', '0', 'info', '', '鑽夌', '1', '2026-05-12 13:40:29', '1', '2026-05-12 13:40:29', X'00'),
+('1061072', '2', '宸插畬鎴�', '4', 'wms_order_status', '0', 'success', '', '宸插畬鎴�', '1', '2026-05-12 13:40:29', '1', '2026-05-12 13:40:29', X'00'),
+('1061073', '3', '宸蹭綔搴�', '5', 'wms_order_status', '0', 'danger', '', '宸蹭綔搴�', '1', '2026-05-12 13:40:29', '1', '2026-05-12 13:40:29', X'00'),
+('1061081', '1', '鐢熶骇鍏ュ簱', '100', 'wms_receipt_order_type', '0', 'success', '', '', '1', '2026-05-11 11:21:49', '1', '2026-05-14 02:21:20', X'00'),
+('1061082', '2', '閲囪喘鍏ュ簱', '101', 'wms_receipt_order_type', '0', 'primary', '', '', '1', '2026-05-11 11:21:49', '1', '2026-05-14 02:21:20', X'00'),
+('1061083', '3', '閫�璐у叆搴�', '102', 'wms_receipt_order_type', '0', 'warning', '', '', '1', '2026-05-11 11:21:49', '1', '2026-05-14 02:21:20', X'00'),
+('1061084', '4', '褰掕繕鍏ュ簱', '103', 'wms_receipt_order_type', '0', 'info', '', '', '1', '2026-05-13 16:02:33', '1', '2026-05-14 02:21:20', X'00'),
+('1061091', '1', '閫�璐у嚭搴�', '200', 'wms_shipment_order_type', '0', 'warning', '', '閫�璐у嚭搴�', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', X'00'),
+('1061092', '2', '閿�鍞嚭搴�', '201', 'wms_shipment_order_type', '0', 'primary', '', '閿�鍞嚭搴�', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', X'00'),
+('1061093', '3', '鐢熶骇鍑哄簱', '202', 'wms_shipment_order_type', '0', 'success', '', '鐢熶骇鍑哄簱', '1', '2026-05-12 17:48:35', '1', '2026-05-12 17:48:35', X'00'),
+('1061096', '1', '璇煶', '1', 'im_rtc_call_media_type', '0', '', '', '璇煶閫氳瘽', 'admin', '2026-05-16 11:34:50', 'admin', '2026-05-16 11:34:50', X'00'),
+('1061097', '2', '瑙嗛', '2', 'im_rtc_call_media_type', '0', '', '', '瑙嗛閫氳瘽', 'admin', '2026-05-16 11:34:50', 'admin', '2026-05-16 11:34:50', X'00'),
+('1061098', '1', '绉佽亰', '1', 'im_rtc_call_conversation_type', '0', 'primary', '', '涓�瀵逛竴绉佽亰閫氳瘽', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00'),
+('1061099', '2', '缇よ亰', '2', 'im_rtc_call_conversation_type', '0', 'success', '', '缇ゅ唴澶氫汉閫氳瘽', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00'),
+('1061100', '1', '鍒涘缓', '10', 'im_rtc_call_status', '0', 'info', '', '閫氳瘽宸插垱寤猴紝绛夊緟鎺ラ��', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00'),
+('1061101', '2', '杩涜涓�', '20', 'im_rtc_call_status', '0', 'primary', '', '宸叉湁浜烘帴閫氾紝閫氳瘽涓�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00'),
+('1061102', '3', '宸茬粨鏉�', '30', 'im_rtc_call_status', '0', 'success', '', '閫氳瘽缁撴潫', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00'),
+('1061103', '1', '閫氳瘽缁撴潫', '1', 'im_rtc_call_end_reason', '0', 'success', '', '鎺ラ�氬悗浠讳竴鏂逛富鍔ㄦ寕鏂�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00'),
+('1061104', '2', '宸叉嫆缁�', '2', 'im_rtc_call_end_reason', '0', 'warning', '', '琚彨鎺ラ�氬墠鐐规嫆鎺�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00'),
+('1061105', '3', '宸插彇娑�', '3', 'im_rtc_call_end_reason', '0', 'info', '', '涓诲彨鎺ラ�氬墠涓诲姩鍙栨秷', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00'),
+('1061106', '4', '鏃犱汉鎺ュ惉', '4', 'im_rtc_call_end_reason', '0', 'info', '', '鎸搩瓒呮椂鏈帴閫�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00'),
+('1061107', '5', '瀵规柟姝e繖', '5', 'im_rtc_call_end_reason', '0', 'warning', '', '瀵规柟鍦ㄥ彟涓�閫氳瘽涓�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00'),
+('1061108', '6', '閫氳瘽寮傚父', '9', 'im_rtc_call_end_reason', '0', 'danger', '', '缃戠粶涓柇銆佽澶囧け璐ョ瓑', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00'),
+('1061109', '1', '鍙戣捣浜�', '1', 'im_rtc_participant_role', '0', 'primary', '', '閫氳瘽鍙戣捣鑰�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00'),
+('1061110', '2', '琚個璇疯��', '2', 'im_rtc_participant_role', '0', 'info', '', '琚個璇峰姞鍏�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00'),
+('1061111', '3', '涓诲姩鍔犲叆鑰�', '3', 'im_rtc_participant_role', '0', 'success', '', '缇ら�氳瘽鍦烘櫙锛屾梺瑙傝�呬富鍔ㄥ姞鍏�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00'),
+('1061112', '1', '閭�璇蜂腑', '10', 'im_rtc_participant_status', '0', 'info', '', '宸插彂鍑� invite锛岀瓑寰呭搷搴�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00'),
+('1061113', '2', '宸插姞鍏�', '20', 'im_rtc_participant_status', '0', 'primary', '', '宸叉帴閫氬苟杩涘叆鎴块棿', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00');
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES
+('1061114', '3', '宸叉嫆缁�', '30', 'im_rtc_participant_status', '0', 'warning', '', '鎺ラ�氬墠鐐规嫆鎺�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00'),
+('1061115', '4', '鏈簲绛�', '40', 'im_rtc_participant_status', '0', 'info', '', '閫氳瘽宸茬粨鏉熶粛鏈簲绛�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00'),
+('1061116', '5', '宸茬寮�', '50', 'im_rtc_participant_status', '0', 'success', '', '鎺ラ�氬悗鎸傛柇 / 绂诲紑', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', X'00'),
+('1061117', '1610', '閫氳瘽寮�濮�', '1610', 'im_content_type', '0', 'info', '', '鍏ユ秷鎭祦锛涚鑱婂畾鍚戦�氱煡锛岀兢鑱婂叏鍛樺箍鎾�', 'admin', '2026-05-18 03:36:12', 'admin', '2026-06-16 03:41:55', X'00'),
+('1061118', '1611', '閫氳瘽缁撴潫', '1611', 'im_content_type', '0', 'info', '', '鍏ユ秷鎭祦锛涚鑱婂噯姘旀场锛岀兢鑱婄郴缁� tip', 'admin', '2026-05-18 03:36:12', 'admin', '2026-06-16 03:41:55', X'00'),
+('1061119', '125', '绱犳潗', '125', 'im_content_type', '0', 'success', '', '棰戦亾杩愯惀鎺ㄩ�佺殑鍥炬枃鍗$墖娑堟伅', '1', '2026-05-18 13:14:34', 'admin', '2026-06-16 03:41:55', X'00'),
+('1061120', '1', '瀵屾枃鏈�', '1', 'im_channel_material_type', '0', 'primary', '', '', '1', '2026-05-19 14:09:25', '1', '2026-05-19 14:09:25', X'00'),
+('1061121', '2', '澶栭摼', '2', 'im_channel_material_type', '0', 'info', '', '', '1', '2026-05-19 14:09:25', '1', '2026-05-19 14:09:25', X'00'),
+('1061122', '7', 'SN 鐮�', '109', 'mes_wm_barcode_biz_type', '0', 'default', '', 'SN', '1', '2026-06-13 10:30:30', '1', '2026-06-13 10:30:30', X'00'),
+('1061123', '107', '鍚堝苟杞彂', '107', 'im_content_type', '0', '', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', X'00'),
+('1061124', '108', '鍚嶇墖', '108', 'im_content_type', '0', '', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', X'00'),
+('1061125', '115', '琛ㄦ儏', '115', 'im_content_type', '0', '', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', X'00'),
+('1061126', '1201', '濂藉弸鐢宠琚悓鎰�', '1201', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', X'00'),
+('1061127', '1202', '濂藉弸鐢宠琚嫆缁�', '1202', 'im_content_type', '0', 'warning', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', X'00'),
+('1061128', '1203', '鏀跺埌鏂扮殑濂藉弸鐢宠', '1203', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', X'00'),
+('1061129', '1207', '鍔犲叆榛戝悕鍗�', '1207', 'im_content_type', '0', 'danger', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', X'00'),
+('1061130', '1208', '绉诲嚭榛戝悕鍗�', '1208', 'im_content_type', '0', 'success', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', X'00'),
+('1061131', '1209', '濂藉弸璧勬枡鍙樻洿', '1209', 'im_content_type', '0', 'info', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', X'00'),
+('1061132', '1210', '濂藉弸淇℃伅鎵归噺鏇存柊', '1210', 'im_content_type', '0', 'info', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', X'00'),
+('1061133', '1530', '缇ゆ垚鍛樹釜浜鸿缃彉鏇�', '1530', 'im_content_type', '0', 'info', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', X'00'),
+('1061134', '1601', '閫氳瘽淇′护', '1601', 'im_content_type', '0', 'info', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', X'00'),
+('1061135', '1602', '閫氳瘽鍙備笌鑰呭姞鍏�', '1602', 'im_content_type', '0', 'info', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', X'00'),
+('1061136', '1603', '閫氳瘽鍙備笌鑰呯寮�', '1603', 'im_content_type', '0', 'info', '', NULL, 'admin', '2026-06-16 03:47:00', 'admin', '2026-06-16 03:47:00', X'00'),
+('1061137', '10', '閿�鍞鐣�', '10', 'wms_reserve_biz_type', '0', 'primary', '', '閿�鍞鍗曢鐣欏簱瀛�', '1', '2026-06-26 08:15:54', '1', '2026-06-26 08:15:54', X'00'),
+('1061138', '20', '鐢熶骇棰勭暀', '20', 'wms_reserve_biz_type', '0', 'success', '', '鐢熶骇宸ュ崟棰勭暀搴撳瓨', '1', '2026-06-26 08:15:54', '1', '2026-06-26 08:15:54', X'00'),
+('1061139', '10', '鍏ュ簱', '10', 'wms_transaction_type', '0', 'success', '', '搴撳瓨鍏ュ簱', '1', '2026-06-26 08:15:54', '1', '2026-06-26 08:15:54', X'00'),
+('1061140', '20', '鍑哄簱', '20', 'wms_transaction_type', '0', 'warning', '', '搴撳瓨鍑哄簱', '1', '2026-06-26 08:15:54', '1', '2026-06-26 08:15:54', X'00'),
+('1061141', '30', '棰勭暀', '30', 'wms_transaction_type', '0', 'primary', '', '搴撳瓨棰勭暀', '1', '2026-06-26 08:15:54', '1', '2026-06-26 08:15:54', X'00'),
+('1061142', '40', '閲婃斁', '40', 'wms_transaction_type', '0', 'info', '', '棰勭暀閲婃斁', '1', '2026-06-26 08:15:54', '1', '2026-06-26 08:15:54', X'00'),
+('1061143', '50', '鐩樼偣', '50', 'wms_transaction_type', '0', 'default', '', '搴撳瓨鐩樼偣', '1', '2026-06-26 08:15:54', '1', '2026-06-26 08:15:54', X'00'),
+('1061144', '60', '璋冩嫧', '60', 'wms_transaction_type', '0', 'default', '', '搴撳瓨璋冩嫧', '1', '2026-06-26 08:15:54', '1', '2026-06-26 08:15:54', X'00'),
+('1061145', '0', '棰勭暀涓�', '0', 'wms_reserve_status', '0', 'primary', '', '搴撳瓨棰勭暀涓�', '1', '2026-06-26 08:15:54', '1', '2026-06-26 08:15:54', X'00'),
+('1061146', '1', '閮ㄥ垎浣跨敤', '1', 'wms_reserve_status', '0', 'warning', '', '閮ㄥ垎宸蹭娇鐢�', '1', '2026-06-26 08:15:54', '1', '2026-06-26 08:15:54', X'00'),
+('1061147', '2', '宸蹭娇鐢�', '2', 'wms_reserve_status', '0', 'success', '', '宸插叏閮ㄤ娇鐢�', '1', '2026-06-26 08:15:54', '1', '2026-06-26 08:15:54', X'00'),
+('1061148', '3', '宸查噴鏀�', '3', 'wms_reserve_status', '0', 'info', '', '棰勭暀宸查噴鏀�', '1', '2026-06-26 08:15:54', '1', '2026-06-26 08:15:54', X'00'),
+('1061149', '0', '鑽夌', '0', 'erp_audit_status', '0', 'info', '', '璁㈠崟鑽夌鐘舵��', '1', '2026-06-26 08:46:48', '1', '2026-06-26 08:46:48', X'00'),
+('1061150', '30', '瀹℃壒涓嶉�氳繃', '30', 'erp_audit_status', '0', 'danger', '', '瀹℃壒涓嶉�氳繃', '1', '2026-06-26 08:46:48', '1', '2026-06-26 08:46:48', X'00'),
+('1061151', '1', '瀹℃壒涓�', '1', 'mes_pro_work_order_status', '0', 'warning', '', 'MES鐢熶骇宸ュ崟鐘舵��-瀹℃壒涓�', '1', '2026-06-26 09:46:00', '1', '2026-06-26 09:46:00', X'00'),
+('1061152', '5', '瀹℃壒涓嶉�氳繃', '5', 'mes_pro_work_order_status', '0', 'danger', '', 'MES鐢熶骇宸ュ崟鐘舵��-瀹℃壒涓嶉�氳繃', '1', '2026-06-26 09:46:00', '1', '2026-06-26 09:46:00', X'00'),
+('1061153', '1', '鏁板�兼牸寮�', '1', 'mes_pd_param_type', '0', '', '', NULL, '1', '2026-07-02 14:00:17', '1', '2026-07-02 14:01:19', X'00'),
+('1061154', '2', '鏂囨湰鏍煎紡', '2', 'mes_pd_param_type', '0', '', '', NULL, '1', '2026-07-02 14:00:31', '1', '2026-07-02 14:01:15', X'00'),
+('1061155', '3', '涓嬫媺閫夐」', '3', 'mes_pd_param_type', '0', '', '', NULL, '1', '2026-07-02 14:01:00', '1', '2026-07-02 14:01:10', X'00'),
+('1061156', '4', '鏃堕棿鏍煎紡', '4', 'mes_pd_param_type', '0', '', '', NULL, '1', '2026-07-02 14:01:37', '1', '2026-07-02 14:01:37', X'00'),
+('1061157', '5', '鏃ユ湡鏍煎紡', '5', 'mes_pd_param_type', '0', '', '', NULL, '1', '2026-07-02 14:01:48', '1', '2026-07-02 14:01:48', X'00'),
+('1061158', '1', '鐢熶骇瑕佹眰', '1', 'mes_pd_template_type', '0', '', '', NULL, '1', '2026-07-02 14:02:31', '1', '2026-07-02 14:02:31', X'00'),
+('1061159', '2', '鑷瑕佹眰', '2', 'mes_pd_template_type', '0', '', '', NULL, '1', '2026-07-02 14:02:42', '1', '2026-07-02 14:02:42', X'00'),
+('1061160', '3', '宸℃瑕佹眰', '3', 'mes_pd_template_type', '0', '', '', NULL, '1', '2026-07-02 14:02:54', '1', '2026-07-02 14:02:54', X'00'),
+('1061161', '0', '寰呭彂甯�', '0', 'mes_pd_project_status', '0', 'info', '', '', '1', '2026-07-03 02:17:25', '1', '2026-07-03 02:17:25', X'00'),
+('1061162', '1', '寰呬笂浼�', '1', 'mes_pd_project_status', '0', 'primary', '', '', '1', '2026-07-03 02:17:25', '1', '2026-07-03 02:17:25', X'00'),
+('1061163', '2', '寰呭鏍�', '2', 'mes_pd_project_status', '0', 'warning', '', '', '1', '2026-07-03 02:17:25', '1', '2026-07-03 02:17:25', X'00'),
+('1061164', '4', '寰呭綊妗�', '3', 'mes_pd_project_status', '0', 'success', '', '', '1', '2026-07-03 02:17:25', '1', '2026-08-13 07:48:14', X'00'),
+('1061165', '5', '宸插綊妗�', '4', 'mes_pd_project_status', '0', 'danger', '', '', '1', '2026-07-03 02:17:25', '1', '2026-08-13 07:48:14', X'00'),
+('1061166', '0', '寰呭鏍�', '0', 'mes_pd_document_audit_status', '0', 'info', '', '', '1', '2026-07-03 02:17:25', '1', '2026-07-03 02:17:25', X'00'),
+('1061167', '1', '瀹℃牳閫氳繃', '1', 'mes_pd_document_audit_status', '0', 'success', '', '', '1', '2026-07-03 02:17:25', '1', '2026-07-03 02:17:25', X'00'),
+('1061168', '2', '瀹℃牳涓嶉�氳繃', '2', 'mes_pd_document_audit_status', '0', 'danger', '', '', '1', '2026-07-03 02:17:25', '1', '2026-07-03 02:17:25', X'00'),
+('1061169', '0', '寰呭綊妗�', '0', 'mes_pd_archive_status', '0', 'info', '', '', '1', '2026-07-03 02:17:25', '1', '2026-07-03 02:17:25', X'00'),
+('1061170', '1', '宸插綊妗�', '1', 'mes_pd_archive_status', '0', 'success', '', '', '1', '2026-07-03 02:17:25', '1', '2026-07-03 02:17:25', X'00'),
+('1061171', '1', '鐢�', '1', 'hrm_gender', '0', '', '', NULL, '1', '2026-07-06 11:00:38', '1', '2026-07-06 11:00:38', X'00'),
+('1061172', '2', '濂�', '2', 'hrm_gender', '0', '', '', NULL, '1', '2026-07-06 11:00:47', '1', '2026-07-06 11:00:47', X'00'),
+('1061173', '1', '鍦ㄨ亴', '1', 'hrm_employee_status', '0', '', '', NULL, '1', '2026-07-06 11:01:37', '1', '2026-07-06 11:01:37', X'00'),
+('1061174', '2', '璇曠敤', '2', 'hrm_employee_status', '0', '', '', NULL, '1', '2026-07-06 11:01:44', '1', '2026-07-06 11:01:44', X'00'),
+('1061175', '3', '绂昏亴', '3', 'hrm_employee_status', '0', '', '', NULL, '1', '2026-07-06 11:01:49', '1', '2026-07-06 11:01:49', X'00'),
+('1061176', '1', '楂樹腑', '1', 'hrm_degree', '0', '', '', NULL, '1', '2026-07-06 11:14:01', '1', '2026-07-06 11:14:01', X'00'),
+('1061177', '2', '澶т笓', '2', 'hrm_degree', '0', '', '', NULL, '1', '2026-07-06 11:14:15', '1', '2026-07-06 11:14:15', X'00'),
+('1061178', '3', '鏈', '3', 'hrm_degree', '0', '', '', NULL, '1', '2026-07-06 11:14:26', '1', '2026-07-06 11:14:26', X'00'),
+('1061179', '4', '纭曞+', '4', 'hrm_degree', '0', '', '', NULL, '1', '2026-07-06 11:14:32', '1', '2026-07-06 11:14:32', X'00'),
+('1061180', '5', '鍗氬+', '5', 'hrm_degree', '0', '', '', NULL, '1', '2026-07-06 11:14:40', '1', '2026-07-06 11:14:40', X'00'),
+('1061181', '1', '浜嬪亣', '1', 'hrm_leave_type', '0', '', '', NULL, '1', '2026-07-06 11:16:00', '1', '2026-07-06 11:16:00', X'00'),
+('1061182', '2', '鐥呭亣', '2', 'hrm_leave_type', '0', '', '', NULL, '1', '2026-07-06 11:17:02', '1', '2026-07-06 11:17:02', X'00'),
+('1061183', '3', '骞村亣', '3', 'hrm_leave_type', '0', '', '', NULL, '1', '2026-07-06 11:17:19', '1', '2026-07-06 11:17:19', X'00'),
+('1061184', '4', '濠氬亣', '4', 'hrm_leave_type', '0', '', '', NULL, '1', '2026-07-06 11:17:27', '1', '2026-07-06 11:17:27', X'00'),
+('1061185', '5', '浜у亣', '5', 'hrm_leave_type', '0', '', '', NULL, '1', '2026-07-06 11:17:37', '1', '2026-07-06 11:17:37', X'00'),
+('1061186', '6', '涓у亣', '6', 'hrm_leave_type', '0', '', '', NULL, '1', '2026-07-06 11:17:44', '1', '2026-07-06 11:17:44', X'00'),
+('1061187', '1', '骞宠皟', '1', 'hrm_transfer_type', '0', '', '', NULL, '1', '2026-07-06 11:18:09', '1', '2026-07-06 11:18:09', X'00'),
+('1061188', '2', '鍗囪亴', '2', 'hrm_transfer_type', '0', '', '', NULL, '1', '2026-07-06 11:18:16', '1', '2026-07-06 11:18:16', X'00'),
+('1061189', '3', '闄嶈亴', '3', 'hrm_transfer_type', '0', '', '', NULL, '1', '2026-07-06 11:18:22', '1', '2026-07-06 11:18:22', X'00'),
+('1061190', '1', '涓诲姩绂昏亴', '1', 'hrm_resignation_type', '0', '', '', NULL, '1', '2026-07-06 11:20:26', '1', '2026-07-06 11:20:26', X'00'),
+('1061191', '2', '琚姩绂昏亴', '2', 'hrm_resignation_type', '0', '', '', NULL, '1', '2026-07-06 11:20:35', '1', '2026-07-06 11:20:35', X'00'),
+('1061192', '3', '鍚堝悓鍒版湡', '3', 'hrm_resignation_type', '0', '', '', NULL, '1', '2026-07-06 11:20:44', '1', '2026-07-06 11:20:44', X'00'),
+('1061193', '1', '姝e父', '1', 'hrm_clock_type', '0', '', '', NULL, '1', '2026-07-06 11:21:04', '1', '2026-07-06 11:21:04', X'00'),
+('1061194', '2', '杩熷埌/鏃╅��', '2', 'hrm_clock_type', '0', '', '', NULL, '1', '2026-07-06 11:21:19', '1', '2026-07-06 11:21:19', X'00'),
+('1061195', '3', '缂哄崱', '3', 'hrm_clock_type', '0', '', '', NULL, '1', '2026-07-06 11:21:26', '1', '2026-07-06 11:21:26', X'00'),
+('1061196', '0', '寰呯‘璁�', '0', 'hrm_salary_status', '0', '', '', NULL, '1', '2026-07-06 11:22:05', '1', '2026-07-06 11:22:05', X'00'),
+('1061197', '1', '宸茬‘璁�', '10', 'hrm_salary_status', '0', '', '', NULL, '1', '2026-07-06 11:22:16', '1', '2026-07-06 11:22:16', X'00'),
+('1061198', '2', '宸插彂鏀�', '20', 'hrm_salary_status', '0', '', '', NULL, '1', '2026-07-06 11:22:25', '1', '2026-07-06 11:22:25', X'00'),
+('1061199', '1', '鏈紑濮�', '0', 'hrm_handover_status', '0', '', '', NULL, '1', '2026-07-06 11:23:08', '1', '2026-07-06 11:23:08', X'00'),
+('1061200', '2', '杩涜涓�', '10', 'hrm_handover_status', '0', '', '', NULL, '1', '2026-07-06 11:23:18', '1', '2026-07-06 11:23:18', X'00'),
+('1061201', '3', '宸插畬鎴�', '20', 'hrm_handover_status', '0', '', '', NULL, '1', '2026-07-06 11:23:28', '1', '2026-07-06 11:23:28', X'00'),
+('1061202', '1', '閾惰杞处', '1', 'hrm_payment_method', '0', '', '', NULL, '1', '2026-07-06 11:23:45', '1', '2026-07-06 11:23:45', X'00'),
+('1061203', '2', '鐜伴噾', '2', 'hrm_payment_method', '0', '', '', NULL, '1', '2026-07-06 11:23:52', '1', '2026-07-06 11:23:52', X'00'),
+('1061204', '3', '鏀エ', '3', 'hrm_payment_method', '0', '', '', NULL, '1', '2026-07-06 11:23:59', '1', '2026-07-06 11:23:59', X'00'),
+('1061205', '1', '鍘熸枡', '1', 'MDM_ITEM_TYPE', '0', '', '', NULL, '1', '2026-07-14 12:04:36', '1', '2026-07-14 12:04:36', X'00'),
+('1061206', '2', '鍗婃垚鍝�', '2', 'MDM_ITEM_TYPE', '0', '', '', NULL, '1', '2026-07-14 12:04:47', '1', '2026-07-14 12:04:47', X'00'),
+('1061207', '3', '鎴愬搧', '3', 'MDM_ITEM_TYPE', '0', '', '', NULL, '1', '2026-07-14 12:04:54', '1', '2026-07-14 12:04:54', X'00'),
+('1061208', '4', '杈呮枡', '4', 'MDM_ITEM_TYPE', '0', '', '', NULL, '1', '2026-07-14 12:05:02', '1', '2026-07-14 12:05:02', X'00'),
+('1061209', '0', '鑽夌', '0', 'mes_pro_mps_status', '0', 'info', '', '', '1', '2026-07-17 02:04:33', '1', '2026-07-17 02:04:33', X'00'),
+('1061210', '1', '宸蹭笅鍙�', '1', 'mes_pro_mps_status', '0', 'success', '', '', '1', '2026-07-17 02:04:33', '1', '2026-07-17 02:04:33', X'00'),
+('1061211', '2', '宸插畬鎴�', '2', 'mes_pro_mps_status', '0', 'primary', '', '', '1', '2026-07-17 02:04:33', '1', '2026-07-17 02:04:33', X'00'),
+('1061212', '3', '宸插彇娑�', '3', 'mes_pro_mps_status', '0', 'danger', '', '', '1', '2026-07-17 02:04:33', '1', '2026-07-17 02:04:33', X'00'),
+('1061213', '1', '鎷滆', '1', 'crm_business_end_status_type', '0', '', '', NULL, '1', '2026-07-20 11:00:15', '1', '2026-07-20 11:00:15', X'00'),
+('1061214', '2', '鎷熺绾�', '2', 'crm_business_end_status_type', '0', '', '', NULL, '1', '2026-07-20 11:00:25', '1', '2026-07-20 11:00:25', X'00'),
+('1061215', '3', '绛剧害', '3', 'crm_business_end_status_type', '0', '', '', NULL, '1', '2026-07-20 11:00:31', '1', '2026-07-20 11:00:31', X'00'),
+('1061216', '4', '澶辨晥', '4', 'crm_business_end_status_type', '0', '', '', NULL, '1', '2026-07-20 11:00:38', '1', '2026-07-20 11:00:38', X'00'),
+('1061217', '1', '鐢熶骇涓�', '1', 'mes_pro_task_status', '0', 'processing', '', '浠诲姟姝e湪鐢熶骇涓�', 'admin', '2026-07-22 07:59:56', 'admin', '2026-07-22 07:59:56', X'00'),
+('1061218', '2', '閮ㄥ垎瀹屾垚', '2', 'mes_pro_task_status', '0', 'warning', '', '浠诲姟閮ㄥ垎瀹屾垚', 'admin', '2026-07-22 08:00:15', 'admin', '2026-07-22 08:00:15', X'00'),
+('1061219', '1', '寰呰瘎瀹�', '0', 'mes_ncr_status', '0', '', '', '寰呰瘎瀹�', '1', '2026-08-06 09:25:25', '1', '2026-08-06 09:25:25', X'00'),
+('1061220', '2', '宸茶瘎瀹�', '1', 'mes_ncr_status', '0', '', '', '宸茶瘎瀹�', '1', '2026-08-06 09:25:25', '1', '2026-08-06 09:25:25', X'00'),
+('1061221', '3', '宸插缃�', '2', 'mes_ncr_status', '0', '', '', '宸插缃�', '1', '2026-08-06 09:25:25', '1', '2026-08-06 09:25:25', X'00'),
+('1061222', '4', '宸插叧闂�', '3', 'mes_ncr_status', '0', '', '', '宸插叧闂�', '1', '2026-08-06 09:25:25', '1', '2026-08-06 09:25:25', X'00'),
+('1061223', '1', '閫�璐�', '1', 'mes_ncr_disposition', '0', '', '', '閫�璐�', '1', '2026-08-06 09:25:25', '1', '2026-08-06 09:25:25', X'00'),
+('1061224', '2', '鎶ュ簾', '2', 'mes_ncr_disposition', '0', '', '', '鎶ュ簾', '1', '2026-08-06 09:25:25', '1', '2026-08-06 09:25:25', X'00'),
+('1061225', '3', '杩斿伐', '3', 'mes_ncr_disposition', '0', '', '', '杩斿伐', '1', '2026-08-06 09:25:25', '1', '2026-08-06 09:25:25', X'00'),
+('1061226', '4', '璁╂鎺ユ敹', '4', 'mes_ncr_disposition', '0', '', '', '璁╂鎺ユ敹', '1', '2026-08-06 09:25:25', '1', '2026-08-06 09:25:25', X'00'),
+('1061227', '5', '闄嶇骇浣跨敤', '5', 'mes_ncr_disposition', '0', '', '', '闄嶇骇浣跨敤', '1', '2026-08-06 09:25:25', '1', '2026-08-06 09:25:25', X'00'),
+('1061228', '1', '澧炲�肩◣涓撶敤鍙戠エ', '1', 'crm_invoice_type', '0', '', '', NULL, '1', '2026-08-10 14:04:20', '1', '2026-08-10 14:04:20', X'00'),
+('1061229', '2', '澧炲�肩◣鏅�氬彂绁�', '2', 'crm_invoice_type', '0', '', '', NULL, '1', '2026-08-10 14:04:25', '1', '2026-08-10 14:04:25', X'00'),
+('1061230', '3', '鐢靛瓙鍙戠エ', '3', 'crm_invoice_type', '0', '', '', NULL, '1', '2026-08-10 14:04:31', '1', '2026-08-10 14:04:31', X'00'),
+('1061231', '1', '鍔冲姩鍚堝悓', '1', 'hrm_contract_type', '0', 'primary', '', NULL, '', '2026-08-10 07:52:13', '', '2026-08-10 07:52:13', X'00'),
+('1061232', '2', '鍔冲姟鍚堝悓', '2', 'hrm_contract_type', '0', 'success', '', NULL, '', '2026-08-10 07:52:13', '', '2026-08-10 07:52:13', X'00'),
+('1061233', '3', '瀹炰範鍗忚', '3', 'hrm_contract_type', '0', 'warning', '', NULL, '', '2026-08-10 07:52:13', '', '2026-08-10 07:52:13', X'00'),
+('1061234', '4', '鍔冲姟娲鹃仯', '4', 'hrm_contract_type', '0', 'info', '', NULL, '', '2026-08-10 07:52:13', '', '2026-08-10 07:52:13', X'00'),
+('1061235', '5', '鍏朵粬', '5', 'hrm_contract_type', '0', 'default', '', NULL, '', '2026-08-10 07:52:13', '', '2026-08-10 07:52:13', X'00'),
+('1061236', '1', '鍥哄畾鏈熼檺', '1', 'hrm_contract_term_type', '0', 'primary', '', NULL, '', '2026-08-10 07:52:13', '', '2026-08-10 07:52:13', X'00'),
+('1061237', '2', '鏃犲浐瀹氭湡闄�', '2', 'hrm_contract_term_type', '0', 'success', '', NULL, '', '2026-08-10 07:52:13', '', '2026-08-10 07:52:13', X'00'),
+('1061238', '3', '浠ュ畬鎴愪竴瀹氬伐浣滀换鍔′负鏈熼檺', '3', 'hrm_contract_term_type', '0', 'warning', '', NULL, '', '2026-08-10 07:52:13', '', '2026-08-10 07:52:13', X'00'),
+('1061239', '1', '寰呯敓鏁�', '1', 'hrm_contract_status', '0', 'info', '', NULL, '', '2026-08-10 07:52:13', '', '2026-08-10 07:52:13', X'00'),
+('1061240', '2', '鐢熸晥涓�', '2', 'hrm_contract_status', '0', 'success', '', NULL, '', '2026-08-10 07:52:13', '', '2026-08-10 07:52:13', X'00'),
+('1061241', '3', '鍗冲皢鍒版湡', '3', 'hrm_contract_status', '0', 'warning', '', NULL, '', '2026-08-10 07:52:13', '', '2026-08-10 07:52:13', X'00'),
+('1061242', '4', '宸插埌鏈�', '4', 'hrm_contract_status', '0', 'default', '', NULL, '', '2026-08-10 07:52:13', '', '2026-08-10 07:52:13', X'00'),
+('1061243', '5', '宸茶В闄�', '5', 'hrm_contract_status', '0', 'danger', '', NULL, '', '2026-08-10 07:52:13', '', '2026-08-10 07:52:13', X'00'),
+('1061244', '6', '宸茬粓姝�', '6', 'hrm_contract_status', '0', 'danger', '', NULL, '', '2026-08-10 07:52:13', '', '2026-08-10 07:52:13', X'00'),
+('1061245', '1', '姝e父', '0', 'hrm_contract_terminate_status', '0', 'success', '', NULL, '', '2026-08-10 07:52:13', '', '2026-08-10 07:52:13', X'00'),
+('1061246', '2', '宸茶В闄�', '1', 'hrm_contract_terminate_status', '0', 'danger', '', NULL, '', '2026-08-10 07:52:13', '', '2026-08-10 07:52:13', X'00'),
+('1061247', '3', '宸茬粓姝�', '2', 'hrm_contract_terminate_status', '0', 'warning', '', NULL, '', '2026-08-10 07:52:13', '', '2026-08-10 07:52:13', X'00'),
+('1065310', '1', '骞村害', '1', 'crm_sales_target_period_type', '0', 'primary', '', '', '1', '2026-08-12 07:21:28', '1', '2026-08-12 07:21:28', X'00'),
+('1065311', '2', '瀛e害', '2', 'crm_sales_target_period_type', '0', 'success', '', '', '1', '2026-08-12 07:21:28', '1', '2026-08-12 07:21:28', X'00'),
+('1065312', '3', '鏈堝害', '3', 'crm_sales_target_period_type', '0', 'warning', '', '', '1', '2026-08-12 07:21:28', '1', '2026-08-12 07:21:28', X'00'),
+('1065320', '1', '涓汉', '1', 'crm_sales_target_dimension', '0', 'primary', '', '', '1', '2026-08-12 07:21:28', '1', '2026-08-12 07:21:28', X'00'),
+('1065321', '2', '閮ㄩ棬', '2', 'crm_sales_target_dimension', '0', 'success', '', '', '1', '2026-08-12 07:21:28', '1', '2026-08-12 07:21:28', X'00'),
+('1065322', '3', '浜у搧', '3', 'crm_sales_target_dimension', '0', 'warning', '', '', '1', '2026-08-12 07:21:28', '1', '2026-08-12 07:21:28', X'00'),
+('1065330', '0', '鏈敓鏁�', '0', 'crm_sales_target_status', '0', 'info', '', '', '1', '2026-08-12 07:21:28', '1', '2026-08-12 07:21:28', X'00'),
+('1065331', '1', '宸茬敓鏁�', '1', 'crm_sales_target_status', '0', 'success', '', '', '1', '2026-08-12 07:21:28', '1', '2026-08-12 07:21:28', X'00'),
+('1065332', '2', '宸茬粨鏉�', '2', 'crm_sales_target_status', '0', 'warning', '', '', '1', '2026-08-12 07:21:28', '1', '2026-08-12 07:21:28', X'00'),
+('1065333', '3', '宸蹭綔搴�', '3', 'crm_sales_target_status', '0', 'danger', '', '', '1', '2026-08-12 07:21:28', '1', '2026-08-12 07:21:28', X'00'),
+('1065334', '1', '鍗″昂', '1', 'mes_dv_metering_category', '0', '', '', '鍗″昂', '1', '2026-08-13 01:36:15', '1', '2026-08-13 01:36:15', X'00'),
+('1065335', '2', '鍗冨垎灏�', '2', 'mes_dv_metering_category', '0', '', '', '鍗冨垎灏�', '1', '2026-08-13 01:36:15', '1', '2026-08-13 01:36:15', X'00'),
+('1065336', '3', '鍘嬪姏琛�', '3', 'mes_dv_metering_category', '0', '', '', '鍘嬪姏琛�', '1', '2026-08-13 01:36:15', '1', '2026-08-13 01:36:15', X'00'),
+('1065337', '4', '娓╁害璁�', '4', 'mes_dv_metering_category', '0', '', '', '娓╁害璁�', '1', '2026-08-13 01:36:15', '1', '2026-08-13 01:36:15', X'00'),
+('1065338', '5', '涓囩敤琛�', '5', 'mes_dv_metering_category', '0', '', '', '涓囩敤琛�', '1', '2026-08-13 01:36:15', '1', '2026-08-13 01:36:15', X'00'),
+('1065339', '6', '澶╁钩鐮濈爜', '6', 'mes_dv_metering_category', '0', '', '', '澶╁钩鐮濈爜', '1', '2026-08-13 01:36:15', '1', '2026-08-13 01:36:15', X'00'),
+('1065340', '7', '鍏朵粬', '7', 'mes_dv_metering_category', '0', '', '', '鍏朵粬', '1', '2026-08-13 01:36:15', '1', '2026-08-13 01:36:15', X'00'),
+('1065341', '1', '鍦ㄧ敤', '1', 'mes_dv_metering_status', '0', 'success', '', '鍦ㄧ敤', '1', '2026-08-13 01:36:15', '1', '2026-08-13 01:36:15', X'00'),
+('1065342', '2', '鍋滅敤', '2', 'mes_dv_metering_status', '0', 'info', '', '鍋滅敤', '1', '2026-08-13 01:36:15', '1', '2026-08-13 01:36:15', X'00'),
+('1065343', '3', '鎶ュ簾', '3', 'mes_dv_metering_status', '0', 'danger', '', '鎶ュ簾', '1', '2026-08-13 01:36:15', '1', '2026-08-13 01:36:15', X'00'),
+('1065344', '1', '鍚堟牸', '1', 'mes_dv_metering_check_result', '0', 'success', '', '鍚堟牸', '1', '2026-08-13 01:36:15', '1', '2026-08-13 01:36:15', X'00'),
+('1065345', '2', '涓嶅悎鏍�', '2', 'mes_dv_metering_check_result', '0', 'danger', '', '涓嶅悎鏍�', '1', '2026-08-13 01:36:15', '1', '2026-08-13 01:36:15', X'00'),
+('1065346', '3', '瀹℃壒涓�', '5', 'mes_pd_project_status', '0', 'processing', '', 'BPM 瀹℃壒涓姸鎬�', '1', '2026-08-13 07:48:27', '1', '2026-08-13 07:48:27', X'00'),
+('1065410', '1', '鍚敤', '0', 'qc_report_template_status', '0', 'success', '', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00'),
+('1065411', '2', '鍋滅敤', '1', 'qc_report_template_status', '0', 'info', '', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00'),
+('1065420', '1', '鑽夌', '0', 'qc_report_version_status', '0', 'default', '', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00'),
+('1065421', '2', '宸插彂甯�', '1', 'qc_report_version_status', '0', 'success', '', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00'),
+('1065422', '3', '宸插仠鐢�', '2', 'qc_report_version_status', '0', 'info', '', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00'),
+('1065430', '1', '鐢熸垚涓�', '0', 'qc_report_instance_status', '0', 'processing', '', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00'),
+('1065431', '2', '鐢熸垚鎴愬姛', '1', 'qc_report_instance_status', '0', 'success', '', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00'),
+('1065432', '3', '鐢熸垚澶辫触', '2', 'qc_report_instance_status', '0', 'error', '', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00'),
+('1065440', '1', 'A3', 'A3', 'qc_report_page_size', '0', 'default', '', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00'),
+('1065441', '2', 'A4', 'A4', 'qc_report_page_size', '0', 'default', '', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00'),
+('1065442', '3', 'A5', 'A5', 'qc_report_page_size', '0', 'default', '', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00'),
+('1065443', '4', 'Letter', 'Letter', 'qc_report_page_size', '0', 'default', '', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00'),
+('1065450', '1', '绾靛悜', 'portrait', 'qc_report_orientation', '0', 'default', '', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00'),
+('1065451', '2', '妯悜', 'landscape', 'qc_report_orientation', '0', 'default', '', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00'),
+('1065460', '1', '閫氱敤', 'general', 'qc_report_industry', '0', 'default', '', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00'),
+('1065461', '2', '鐢靛瓙鐢靛櫒', 'electronics', 'qc_report_industry', '0', 'default', '', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00'),
+('1065462', '3', '浜旈噾鏈烘', 'hardware', 'qc_report_industry', '0', 'default', '', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00'),
+('1065463', '4', '姹借溅闆堕儴浠�', 'auto', 'qc_report_industry', '0', 'default', '', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00'),
+('1065464', '5', '濉戣兌鍒跺搧', 'plastic', 'qc_report_industry', '0', 'default', '', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00'),
+('1065465', '6', '椋熷搧楗枡', 'food', 'qc_report_industry', '0', 'default', '', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00'),
+('1065466', '7', '鍖昏嵂鍖荤枟', 'pharma', 'qc_report_industry', '0', 'default', '', NULL, '1', '2026-09-18 02:09:52', '1', '2026-09-18 02:09:52', X'00');
+
+-- ============ 琛細system_tenant锛堝鍑� 3 琛岋級 ============
+DROP TABLE IF EXISTS `system_tenant`;
+CREATE TABLE `system_tenant` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '绉熸埛缂栧彿',
+ `name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '绉熸埛鍚�',
+ `contact_user_id` bigint DEFAULT NULL COMMENT '鑱旂郴浜虹殑鐢ㄦ埛缂栧彿',
+ `contact_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鑱旂郴浜�',
+ `contact_mobile` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑱旂郴鎵嬫満',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '绉熸埛鐘舵��',
+ `websites` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '缁戝畾鍩熷悕鏁扮粍',
+ `package_id` bigint NOT NULL COMMENT '绉熸埛濂楅缂栧彿',
+ `expire_time` datetime NOT NULL COMMENT '杩囨湡鏃堕棿',
+ `account_count` int NOT NULL COMMENT '璐﹀彿鏁伴噺',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=162 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='绉熸埛琛�';
+INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `websites`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES
+('1', '瓒呯骇绠$悊鍛�', NULL, '绠$悊鍛�', '17321315478', '0', 'www.iocoder.cn,127.0.0.1:3000,wxc4598c446f8a9cb3', '0', '2099-02-19 17:14:16', '9999', '1', '2021-01-05 17:03:47', '1', '2026-08-06 09:21:19', X'00'),
+('121', '灏忕鎴�', '110', '灏忕帇2', '15601691300', '0', 'zsxq.iocoder.cn,123321', '111', '2026-07-10 00:00:00', '30', '1', '2022-02-22 00:56:14', '1', '2025-08-19 21:19:29', X'00'),
+('122', '娴嬭瘯绉熸埛', '113', '鑺嬮亾', '15601691300', '0', 'test.iocoder.cn,222,333', '111', '2023-04-29 00:00:00', '50', '1', '2022-03-07 21:37:58', '1', '2026-06-01 23:29:35', X'00');
+
+-- ============ 琛細system_tenant_package锛堝鍑� 2 琛岋級 ============
+DROP TABLE IF EXISTS `system_tenant_package`;
+CREATE TABLE `system_tenant_package` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '濂楅缂栧彿',
+ `name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '濂楅鍚�',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '绉熸埛鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+ `remark` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '澶囨敞',
+ `menu_ids` varchar(4096) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍏宠仈鐨勮彍鍗曠紪鍙�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=114 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='绉熸埛濂楅琛�';
+INSERT INTO `system_tenant_package` (`id`, `name`, `status`, `remark`, `menu_ids`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES
+('111', '鏅�氬椁�', '0', '灏忓姛鑳�', '[1,2,5,1031,1032,1033,1034,1035,1036,1037,1038,1039,1050,1051,1052,1053,1054,1056,1057,1058,1059,1060,1063,1064,1065,1066,1067,1070,1075,1077,1078,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1117,1118,1119,1120,100,101,102,1126,103,1127,1128,1129,106,1130,107,1132,1133,110,1134,111,1135,112,1136,113,1137,2161,114,1138,1139,115,1140,116,1141,1142,1143,1150,1161,1162,1166,1173,1174,2713,2714,1178,2715,2716,2717,2718,2720,2721,1185,2722,1186,1187,2723,1188,2724,1189,2725,1190,2726,1191,2727,1192,2728,2729,1193,1194,2730,1195,2731,2732,1197,2733,1198,2734,1199,2735,1200,1201,1202,2739,2740,1207,1208,1209,2745,1210,2746,1211,2747,1212,2748,1213,1215,1216,1217,1218,1219,1220,2756,1221,2757,1222,1224,1225,1226,1227,1228,1229,1237,1238,2262,1239,1240,1241,1242,1243,2275,2276,2277,1255,1256,1257,2281,1258,2282,1259,2283,1260,2284,2285,2287,2288,2293,2294,2297,2300,2301,2302,2317,2318,2319,2320,2321,2322,2323,2324,2325,2326,2327,2328,2329,2330,2331,2332,2333,2334,2335,2363,2364,5011,5012,2472,2478,2479,2480,2481,2482,2483,2484,2485,2486,2487,2488,2489,2490,2491,2492,2493,2494,2495,2497,2525,1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012,1013,2549,1014,2550,1015,2551,1016,2552,1017,2553,1018,2554,1019,2555,1020,2556,2557,2558,2559]', '1', '2022-02-22 00:54:00', '1', '2025-09-06 20:52:25', X'00'),
+('113', '娴嬭瘯濂楅锛堝暐閮芥病鏈夛級', '0', '', '[2160,1254,2159]', '1', '2026-06-01 23:22:39', '1', '2026-06-09 14:44:00', X'00');
+
+-- ============ 琛細system_company_config锛堝鍑� 0 琛岋級 ============
+DROP TABLE IF EXISTS `system_company_config`;
+CREATE TABLE `system_company_config` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `company_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鍏徃鍚嶇О',
+ `logo_url` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'logo姘镐箙鍏紑閾炬帴(previewURL)',
+ `logo_blob_id` bigint DEFAULT NULL COMMENT 'logo瀵瑰簲blob璁板綍ID',
+ `login_title` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐧诲綍椤垫爣棰�',
+ `login_description` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐧诲綍椤垫弿杩�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鍏徃鍝佺墝淇℃伅閰嶇疆琛�';
+
+-- ***********************************************************************
+-- 鈶� AI 閰嶇疆锛堜粎妯″瀷+key锛�+ 鍩虹璁炬柦閰嶇疆绠$悊锛圖DL + 鏁版嵁锛�
+-- ***********************************************************************
+
+-- ============ 琛細ai_model锛堝鍑� 4 琛岋級 ============
+DROP TABLE IF EXISTS `ai_model`;
+CREATE TABLE `ai_model` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `key_id` bigint NOT NULL COMMENT 'API 绉橀挜缂栧彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '妯″瀷鍚嶇О',
+ `model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '妯″瀷鏍囧織',
+ `platform` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '骞冲彴',
+ `type` tinyint NOT NULL COMMENT '绫诲瀷',
+ `sort` int NOT NULL DEFAULT '0' COMMENT '鎺掑簭鍊�',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵��',
+ `temperature` double DEFAULT NULL COMMENT '娓╁害鍙傛暟',
+ `max_tokens` int DEFAULT NULL COMMENT '鍗曟潯鍥炲鐨勬渶澶� Token 鏁伴噺',
+ `max_contexts` int DEFAULT NULL COMMENT '涓婁笅鏂囩殑鏈�澶� Message 鏁伴噺',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='AI 妯″瀷琛�';
+INSERT INTO `ai_model` (`id`, `key_id`, `name`, `model`, `platform`, `type`, `sort`, `status`, `temperature`, `max_tokens`, `max_contexts`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES
+('1', '1', '閫氫箟鍗冮棶鍚戦噺妯″瀷', 'text-embedding-v3', 'TongYi', '5', '0', '0', NULL, NULL, NULL, '1', '2026-07-31 01:17:22', '142', '2026-07-31 11:13:39', X'00'),
+('2', '1', '閫氫箟鍗冮棶瀵硅瘽妯″瀷', 'qwen-max', 'TongYi', '1', '0', '0', '0.7', '4096', '20', '', '2026-07-31 07:51:42', '142', '2026-07-31 15:57:16', X'00'),
+('3', '1', '閫氫箟鍗冮棶鍥惧儚妯″瀷', 'qwen-plus', 'TongYi', '2', '1', '0', NULL, NULL, NULL, '142', '2026-07-31 17:37:16', '142', '2026-07-31 17:37:45', X'00'),
+('4', '1', '閫氫箟鍗冮棶瑙嗚妯″瀷', 'qwen-vl-plus', 'TongYi', '1', '1', '0', '0.7', '4096', '10', '', '2026-07-31 09:44:21', '', '2026-07-31 09:44:21', X'00');
+
+-- ============ 琛細ai_api_key锛堝鍑� 1 琛岋級 ============
+DROP TABLE IF EXISTS `ai_api_key`;
+CREATE TABLE `ai_api_key` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鍚嶇О',
+ `api_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '瀵嗛挜',
+ `platform` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '骞冲彴',
+ `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'API 鍦板潃',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵��',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='AI API 绉橀挜琛�';
+INSERT INTO `ai_api_key` (`id`, `name`, `api_key`, `platform`, `url`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES
+('1', '閫氫箟鍗冮棶', 'sk-bd235cc13cd74e2388aa8984c84f691f', 'TongYi', NULL, '0', '1', '2026-07-31 01:17:19', '142', '2026-07-31 16:00:35', X'00');
+
+-- ============ 琛細infra_config锛堝鍑� 8 琛岋級 ============
+DROP TABLE IF EXISTS `infra_config`;
+CREATE TABLE `infra_config` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鍙傛暟涓婚敭',
+ `category` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍙傛暟鍒嗙粍',
+ `type` tinyint NOT NULL COMMENT '鍙傛暟绫诲瀷',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鍙傛暟鍚嶇О',
+ `config_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鍙傛暟閿悕',
+ `value` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鍙傛暟閿��',
+ `visible` bit(1) NOT NULL COMMENT '鏄惁鍙',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_config_key` (`config_key`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鍙傛暟閰嶇疆琛�';
+INSERT INTO `infra_config` (`id`, `category`, `type`, `name`, `config_key`, `value`, `visible`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES
+('2', 'biz', '1', '鐢ㄦ埛绠$悊-璐﹀彿鍒濆瀵嗙爜', 'system.user.init-password', '123456', X'00', '鍒濆鍖栧瘑鐮� 123456', 'admin', '2021-01-05 17:03:48', '1', '2024-07-20 17:22:47', X'00'),
+('7', 'url', '2', 'MySQL 鐩戞帶鐨勫湴鍧�', 'url.druid', '', X'01', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:33:38', X'00'),
+('8', 'url', '2', 'SkyWalking 鐩戞帶鐨勫湴鍧�', 'url.skywalking', '', X'01', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:57:03', X'00'),
+('9', 'url', '2', 'Spring Boot Admin 鐩戞帶鐨勫湴鍧�', 'url.spring-boot-admin', '', X'01', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:52:07', X'00'),
+('10', 'url', '2', 'Swagger 鎺ュ彛鏂囨。鐨勫湴鍧�', 'url.swagger', '', X'01', '', '1', '2023-04-07 13:41:16', '1', '2023-04-07 14:59:00', X'00'),
+('12', 'test2', '2', 'test3', 'test4', 'test5', X'01', 'test6', '1', '2023-12-03 09:55:16', '1', '2025-04-06 21:00:09', X'00'),
+('13', '鐢ㄦ埛绠$悊-璐﹀彿鍒濆瀵嗙爜', '2', '鐢ㄦ埛绠$悊-娉ㄥ唽寮�鍏�', 'system.user.register-enabled', 'true', X'00', '', '1', '2025-04-26 17:23:41', '1', '2025-04-26 17:23:41', X'00'),
+('14', 'biz', '2', 'MES 璁¢噺鍣ㄥ叿鍒版湡鎻愰啋澶╂暟', 'mes.dv-metering.remind-days', '1', X'00', '璁¢噺鍣ㄥ叿涓嬫妫�娴嬫棩鏈熷埌鏈熷墠 N 澶╂彁閱掞紙绔欏唴淇″彂閫佺粰璐d换浜猴級', '1', '2026-08-13 01:36:45', '1', '2026-08-13 10:29:56', X'00');
+
+-- ============ 琛細infra_job锛堝鍑� 18 琛岋級 ============
+DROP TABLE IF EXISTS `infra_job`;
+CREATE TABLE `infra_job` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '浠诲姟缂栧彿',
+ `name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '浠诲姟鍚嶇О',
+ `status` tinyint NOT NULL COMMENT '浠诲姟鐘舵��',
+ `handler_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '澶勭悊鍣ㄧ殑鍚嶅瓧',
+ `handler_param` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶勭悊鍣ㄧ殑鍙傛暟',
+ `cron_expression` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'CRON 琛ㄨ揪寮�',
+ `retry_count` int NOT NULL DEFAULT '0' COMMENT '閲嶈瘯娆℃暟',
+ `retry_interval` int NOT NULL DEFAULT '0' COMMENT '閲嶈瘯闂撮殧',
+ `monitor_timeout` int NOT NULL DEFAULT '0' COMMENT '鐩戞帶瓒呮椂鏃堕棿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=41 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='瀹氭椂浠诲姟琛�';
+INSERT INTO `infra_job` (`id`, `name`, `status`, `handler_name`, `handler_param`, `cron_expression`, `retry_count`, `retry_interval`, `monitor_timeout`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES
+('5', '鏀粯閫氱煡 Job', '2', 'payNotifyJob', NULL, '* * * * * ?', '0', '0', '0', '1', '2021-10-27 08:34:42', '1', '2024-09-12 13:32:48', X'00'),
+('17', '鏀粯璁㈠崟鍚屾 Job', '2', 'payOrderSyncJob', NULL, '0 0/1 * * * ?', '0', '0', '0', '1', '2023-07-22 14:36:26', '1', '2023-07-22 15:39:08', X'00'),
+('18', '鏀粯璁㈠崟杩囨湡 Job', '2', 'payOrderExpireJob', NULL, '0 0/1 * * * ?', '0', '0', '0', '1', '2023-07-22 15:36:23', '1', '2023-07-22 15:39:54', X'00'),
+('19', '閫�娆捐鍗曠殑鍚屾 Job', '2', 'payRefundSyncJob', NULL, '0 0/1 * * * ?', '0', '0', '0', '1', '2023-07-23 21:03:44', '1', '2023-07-23 21:09:00', X'00'),
+('21', 'Mall 浜ゆ槗璁㈠崟鐨勮嚜鍔ㄨ繃鏈� Job', '2', 'tradeOrderAutoCancelJob', '', '0 * * * * ?', '3', '0', '0', '1', '2023-09-25 23:43:26', '1', '2025-10-02 11:08:34', X'00'),
+('22', 'Mall 浜ゆ槗璁㈠崟鐨勮嚜鍔ㄦ敹璐� Job', '2', 'tradeOrderAutoReceiveJob', '', '0 * * * * ?', '3', '0', '0', '1', '2023-09-26 19:23:53', '1', '2025-10-02 11:08:36', X'00'),
+('23', 'Mall 浜ゆ槗璁㈠崟鐨勮嚜鍔ㄨ瘎璁� Job', '2', 'tradeOrderAutoCommentJob', '', '0 * * * * ?', '3', '0', '0', '1', '2023-09-26 23:38:29', '1', '2025-10-02 11:08:38', X'00'),
+('24', 'Mall 浣i噾瑙e喕 Job', '2', 'brokerageRecordUnfreezeJob', '', '0 * * * * ?', '3', '0', '0', '1', '2023-09-28 22:01:46', '1', '2025-10-02 11:08:04', X'00'),
+('25', '璁块棶鏃ュ織娓呯悊 Job', '2', 'accessLogCleanJob', '', '0 0 0 * * ?', '3', '0', '0', '1', '2023-10-03 10:59:41', '1', '2023-10-03 11:01:10', X'00'),
+('26', '閿欒鏃ュ織娓呯悊 Job', '2', 'errorLogCleanJob', '', '0 0 0 * * ?', '3', '0', '0', '1', '2023-10-03 11:00:43', '1', '2023-10-03 11:01:12', X'00'),
+('27', '浠诲姟鏃ュ織娓呯悊 Job', '2', 'jobLogCleanJob', '', '0 0 0 * * ?', '3', '0', '0', '1', '2023-10-03 11:01:33', '1', '2024-09-12 13:40:34', X'00'),
+('33', 'demoJob', '2', 'demoJob', '', '0 * * * * ?', '1', '1', '0', '1', '2024-10-27 19:38:46', '1', '2025-05-10 18:13:54', X'00'),
+('35', '杞处璁㈠崟鐨勫悓姝� Job', '2', 'payTransferSyncJob', '', '0 * * * * ?', '0', '0', '0', '1', '2025-05-10 17:35:54', '1', '2025-05-10 18:13:52', X'00'),
+('36', 'IoT 璁惧绂荤嚎妫�鏌� Job', '2', 'iotDeviceOfflineCheckJob', '', '0 * * * * ?', '0', '0', '0', '1', '2025-07-03 23:48:44', '"1"', '2025-07-03 23:48:47', X'00'),
+('37', 'IoT OTA 鍗囩骇鎺ㄩ�� Job', '2', 'iotOtaUpgradeJob', '', '0 * * * * ?', '0', '0', '0', '1', '2025-07-03 23:49:07', '"1"', '2025-07-03 23:49:13', X'00'),
+('38', 'Mall 鎷煎洟杩囨湡 Job', '2', 'combinationRecordExpireJob', '', '0 * * * * ?', '0', '0', '0', '1', '2025-10-02 11:07:11', '1', '2025-10-02 11:07:14', X'00'),
+('39', 'Mall 浼樻儬鍒歌繃鏈� Job', '2', 'couponExpireJob', '', '0 * * * * ?', '0', '0', '0', '1', '2025-10-02 11:07:34', '1', '2025-10-02 11:07:37', X'00'),
+('40', 'Mall 鍟嗗搧缁熻 Job', '2', 'productStatisticsJob', '', '0 0 0 * * ?', '0', '0', '0', '1', '2025-11-22 18:51:25', '1', '2025-11-22 18:56:21', X'00');
+
+-- ============ 琛細infra_file_config锛堝鍑� 11 琛岋級 ============
+DROP TABLE IF EXISTS `infra_file_config`;
+CREATE TABLE `infra_file_config` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `name` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '閰嶇疆鍚�',
+ `storage` tinyint NOT NULL COMMENT '瀛樺偍鍣�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `master` bit(1) NOT NULL COMMENT '鏄惁涓轰富閰嶇疆',
+ `config` varchar(4096) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '瀛樺偍閰嶇疆',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鏂囦欢閰嶇疆琛�';
+INSERT INTO `infra_file_config` (`id`, `name`, `storage`, `remark`, `master`, `config`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES
+('4', '鏁版嵁搴擄紙绀轰緥锛�', '1', '鎴戞槸鏁版嵁搴�', X'00', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig","domain":"http://127.0.0.1:48080"}', '1', '2022-03-15 23:56:24', '1', '2026-07-03 11:47:08', X'00'),
+('22', '涓冪墰瀛樺偍鍣紙绀轰緥锛�', '20', '璇锋崲鎴愪綘鑷繁鐨勫瘑閽ワ紒锛侊紒', X'00', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"s3.cn-south-1.qiniucs.com","domain":"http://test.yudao.iocoder.cn","bucket":"ruoyi-vue-pro","accessKey":"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS","accessSecret":"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY","enablePathStyleAccess":false,"enablePublicAccess":true}', '1', '2024-01-13 22:11:12', '1', '2026-07-03 11:47:08', X'00'),
+('24', '鑵捐浜戝瓨鍌紙绀轰緥锛�', '20', '璇锋崲鎴愪綘鐨勫瘑閽ワ紒锛侊紒', X'00', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"https://cos.ap-shanghai.myqcloud.com","domain":"http://tengxun-oss.iocoder.cn","bucket":"aoteman-1255880240","accessKey":"AKIDAF6WSh1uiIjwqtrOsGSN3WryqTM6cTMt","accessSecret":"X","enablePathStyleAccess":false,"enablePublicAccess":true}', '1', '2024-11-09 16:03:22', '1', '2026-07-03 11:47:08', X'00'),
+('25', '闃块噷浜戝瓨鍌紙绀轰緥锛�', '20', '', X'00', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"oss-cn-beijing.aliyuncs.com","domain":"http://ali-oss.iocoder.cn","bucket":"yunai-aoteman","accessKey":"LTAI5tEQLgnDyjh3WpNcdMKA","accessSecret":"X","enablePathStyleAccess":false,"enablePublicAccess":true}', '1', '2024-11-09 16:47:08', '1', '2026-07-03 11:47:08', X'00'),
+('26', '鐏北浜戝瓨鍌紙绀轰緥锛�', '20', '', X'00', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"tos-s3-cn-beijing.volces.com","domain":null,"bucket":"yunai","accessKey":"AKLTZjc3Zjc4MzZmMjU3NDk0ZTgxYmIyMmFkNTIwMDI1ZGE","accessSecret":"X==","enablePathStyleAccess":false,"enablePublicAccess":true}', '1', '2024-11-09 16:56:42', '1', '2026-07-03 11:47:08', X'00'),
+('27', '鍗庝负浜戝瓨鍌紙绀轰緥锛�', '20', '', X'00', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"obs.cn-east-3.myhuaweicloud.com","domain":"","bucket":"yudao","accessKey":"PVDONDEIOTW88LF8DC4U","accessSecret":"X","enablePathStyleAccess":false,"enablePublicAccess":true}', '1', '2024-11-09 17:18:41', '1', '2026-07-03 11:47:08', X'00'),
+('28', 'MinIO 瀛樺偍锛堢ず渚嬶級', '20', '', X'00', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"http://127.0.0.1:9000","domain":"http://127.0.0.1:9000/yudao","bucket":"yudao","accessKey":"admin","accessSecret":"password","enablePathStyleAccess":false,"enablePublicAccess":true}', '1', '2024-11-09 17:43:10', '1', '2026-07-03 11:47:08', X'00'),
+('29', '鏈湴瀛樺偍锛堢ず渚嬶級', '10', 'mac/linux 浣跨敤 /锛寃indows 浣跨敤 \\', X'01', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.local.LocalFileClientConfig","basePath":"/Users/yunai/tmp/file","domain":"http://127.0.0.1:48080"}', '1', '2025-05-02 11:25:45', '1', '2026-07-03 11:47:08', X'00'),
+('30', 'SFTP 瀛樺偍锛堢ず渚嬶級', '12', '', X'00', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.sftp.SftpFileClientConfig","basePath":"/upload","domain":"http://127.0.0.1:48080","host":"127.0.0.1","port":2222,"username":"foo","password":"pass"}', '1', '2025-05-02 16:34:10', '1', '2026-07-03 11:47:08', X'00'),
+('34', '涓冪墰浜戝瓨鍌ㄣ�愮鏈夈�戯紙绀轰緥锛�', '20', '璇锋崲鎴愪綘鑷繁鐨勫瘑閽ワ紒锛侊紒', X'00', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"s3.cn-south-1.qiniucs.com","domain":"http://t151glocd.hn-bkt.clouddn.com","bucket":"ruoyi-vue-pro-private","accessKey":"3TvrJ70gl2Gt6IBe7_IZT1F6i_k0iMuRtyEv4EyS","accessSecret":"wd0tbVBYlp0S-ihA8Qg2hPLncoP83wyrIq24OZuY","enablePathStyleAccess":false,"enablePublicAccess":false}', '1', '2025-08-17 21:22:00', '1', '2026-07-03 11:47:08', X'00'),
+('35', '1', '20', '1', X'00', '{"@class":"cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig","endpoint":"http://www.baidu.com","domain":"http://www.xxx.com","bucket":"1","accessKey":"2","accessSecret":"3","enablePathStyleAccess":false,"enablePublicAccess":false,"region":"1"}', '1', '2025-10-02 14:32:12', '1', '2026-07-03 11:47:08', X'00');
+
+-- ============ 琛細infra_data_source_config锛堝鍑� 0 琛岋級 ============
+DROP TABLE IF EXISTS `infra_data_source_config`;
+CREATE TABLE `infra_data_source_config` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭缂栧彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鍙傛暟鍚嶇О',
+ `url` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鏁版嵁婧愯繛鎺�',
+ `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐢ㄦ埛鍚�',
+ `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '瀵嗙爜',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鏁版嵁婧愰厤缃〃';
+
+-- ============ 琛細infra_codegen_table锛堝鍑� 0 琛岋級 ============
+DROP TABLE IF EXISTS `infra_codegen_table`;
+CREATE TABLE `infra_codegen_table` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `data_source_config_id` bigint NOT NULL COMMENT '鏁版嵁婧愰厤缃殑缂栧彿',
+ `scene` tinyint NOT NULL DEFAULT '1' COMMENT '鐢熸垚鍦烘櫙',
+ `table_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '琛ㄥ悕绉�',
+ `table_comment` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '琛ㄦ弿杩�',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `module_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '妯″潡鍚�',
+ `business_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '涓氬姟鍚�',
+ `class_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '绫诲悕绉�',
+ `class_comment` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '绫绘弿杩�',
+ `author` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '浣滆��',
+ `template_type` tinyint NOT NULL DEFAULT '1' COMMENT '妯℃澘绫诲瀷',
+ `front_type` tinyint NOT NULL COMMENT '鍓嶇绫诲瀷',
+ `parent_menu_id` bigint DEFAULT NULL COMMENT '鐖惰彍鍗曠紪鍙�',
+ `master_table_id` bigint DEFAULT NULL COMMENT '涓昏〃鐨勭紪鍙�',
+ `sub_join_column_id` bigint DEFAULT NULL COMMENT '瀛愯〃鍏宠仈涓昏〃鐨勫瓧娈电紪鍙�',
+ `sub_join_many` bit(1) DEFAULT NULL COMMENT '涓昏〃涓庡瓙琛ㄦ槸鍚︿竴瀵瑰',
+ `tree_parent_column_id` bigint DEFAULT NULL COMMENT '鏍戣〃鐨勭埗瀛楁缂栧彿',
+ `tree_name_column_id` bigint DEFAULT NULL COMMENT '鏍戣〃鐨勫悕瀛楀瓧娈电紪鍙�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=210 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='浠g爜鐢熸垚琛ㄥ畾涔�';
+
+-- ============ 琛細infra_codegen_column锛堝鍑� 0 琛岋級 ============
+DROP TABLE IF EXISTS `infra_codegen_column`;
+CREATE TABLE `infra_codegen_column` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `table_id` bigint NOT NULL COMMENT '琛ㄧ紪鍙�',
+ `column_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '瀛楁鍚�',
+ `data_type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '瀛楁绫诲瀷',
+ `column_comment` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '瀛楁鎻忚堪',
+ `nullable` bit(1) NOT NULL COMMENT '鏄惁鍏佽涓虹┖',
+ `primary_key` bit(1) NOT NULL COMMENT '鏄惁涓婚敭',
+ `ordinal_position` int NOT NULL COMMENT '鎺掑簭',
+ `java_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'Java 灞炴�х被鍨�',
+ `java_field` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'Java 灞炴�у悕',
+ `dict_type` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '瀛楀吀绫诲瀷',
+ `example` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏁版嵁绀轰緥',
+ `create_operation` bit(1) NOT NULL COMMENT '鏄惁涓� Create 鍒涘缓鎿嶄綔鐨勫瓧娈�',
+ `update_operation` bit(1) NOT NULL COMMENT '鏄惁涓� Update 鏇存柊鎿嶄綔鐨勫瓧娈�',
+ `list_operation` bit(1) NOT NULL COMMENT '鏄惁涓� List 鏌ヨ鎿嶄綔鐨勫瓧娈�',
+ `list_operation_condition` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '=' COMMENT 'List 鏌ヨ鎿嶄綔鐨勬潯浠剁被鍨�',
+ `list_operation_result` bit(1) NOT NULL COMMENT '鏄惁涓� List 鏌ヨ鎿嶄綔鐨勮繑鍥炲瓧娈�',
+ `html_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鏄剧ず绫诲瀷',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_table_id` (`table_id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=2880 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='浠g爜鐢熸垚琛ㄥ瓧娈靛畾涔�';
+
+-- ***********************************************************************
+-- 鍏朵綑 380 寮犺〃锛堜粎琛ㄧ粨鏋勶紝鏃犳暟鎹級
+-- ***********************************************************************
+
+-- ============ 琛細act_evt_log锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_evt_log`;
+CREATE TABLE `act_evt_log` (
+ `LOG_NR_` bigint NOT NULL AUTO_INCREMENT,
+ `TYPE_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TIME_STAMP_` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
+ `USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DATA_` longblob,
+ `LOCK_OWNER_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `LOCK_TIME_` timestamp(3) NULL DEFAULT NULL,
+ `IS_PROCESSED_` tinyint DEFAULT '0',
+ PRIMARY KEY (`LOG_NR_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_hi_actinst锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_hi_actinst`;
+CREATE TABLE `act_hi_actinst` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT '1',
+ `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `ACT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CALL_PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ACT_NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ACT_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `ASSIGNEE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `COMPLETED_BY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `START_TIME_` datetime(3) NOT NULL,
+ `END_TIME_` datetime(3) DEFAULT NULL,
+ `TRANSACTION_ORDER_` int DEFAULT NULL,
+ `DURATION_` bigint DEFAULT NULL,
+ `DELETE_REASON_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '',
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `ACT_IDX_HI_ACT_INST_START` (`START_TIME_`) USING BTREE,
+ KEY `ACT_IDX_HI_ACT_INST_END` (`END_TIME_`) USING BTREE,
+ KEY `ACT_IDX_HI_ACT_INST_PROCINST` (`PROC_INST_ID_`,`ACT_ID_`) USING BTREE,
+ KEY `ACT_IDX_HI_ACT_INST_EXEC` (`EXECUTION_ID_`,`ACT_ID_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_hi_attachment锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_hi_attachment`;
+CREATE TABLE `act_hi_attachment` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DESCRIPTION_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `URL_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CONTENT_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TIME_` datetime(3) DEFAULT NULL,
+ PRIMARY KEY (`ID_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_hi_comment锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_hi_comment`;
+CREATE TABLE `act_hi_comment` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TIME_` datetime(3) NOT NULL,
+ `USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ACTION_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `MESSAGE_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `FULL_MSG_` longblob,
+ PRIMARY KEY (`ID_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_hi_detail锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_hi_detail`;
+CREATE TABLE `act_hi_detail` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ACT_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `VAR_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `REV_` int DEFAULT NULL,
+ `TIME_` datetime(3) NOT NULL,
+ `BYTEARRAY_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DOUBLE_` double DEFAULT NULL,
+ `LONG_` bigint DEFAULT NULL,
+ `TEXT_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TEXT2_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `ACT_IDX_HI_DETAIL_PROC_INST` (`PROC_INST_ID_`) USING BTREE,
+ KEY `ACT_IDX_HI_DETAIL_ACT_INST` (`ACT_INST_ID_`) USING BTREE,
+ KEY `ACT_IDX_HI_DETAIL_TIME` (`TIME_`) USING BTREE,
+ KEY `ACT_IDX_HI_DETAIL_NAME` (`NAME_`) USING BTREE,
+ KEY `ACT_IDX_HI_DETAIL_TASK_ID` (`TASK_ID_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_hi_entitylink锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_hi_entitylink`;
+CREATE TABLE `act_hi_entitylink` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `LINK_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CREATE_TIME_` datetime(3) DEFAULT NULL,
+ `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PARENT_ELEMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `REF_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `REF_SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `REF_SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ROOT_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ROOT_SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `HIERARCHY_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `ACT_IDX_HI_ENT_LNK_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`,`LINK_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_HI_ENT_LNK_REF_SCOPE` (`REF_SCOPE_ID_`,`REF_SCOPE_TYPE_`,`LINK_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_HI_ENT_LNK_ROOT_SCOPE` (`ROOT_SCOPE_ID_`,`ROOT_SCOPE_TYPE_`,`LINK_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_HI_ENT_LNK_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`,`LINK_TYPE_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_hi_identitylink锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_hi_identitylink`;
+CREATE TABLE `act_hi_identitylink` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `GROUP_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CREATE_TIME_` datetime(3) DEFAULT NULL,
+ `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `ACT_IDX_HI_IDENT_LNK_USER` (`USER_ID_`) USING BTREE,
+ KEY `ACT_IDX_HI_IDENT_LNK_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_HI_IDENT_LNK_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_HI_IDENT_LNK_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_HI_IDENT_LNK_TASK` (`TASK_ID_`) USING BTREE,
+ KEY `ACT_IDX_HI_IDENT_LNK_PROCINST` (`PROC_INST_ID_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_hi_procinst锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_hi_procinst`;
+CREATE TABLE `act_hi_procinst` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT '1',
+ `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `BUSINESS_KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `START_TIME_` datetime(3) NOT NULL,
+ `END_TIME_` datetime(3) DEFAULT NULL,
+ `DURATION_` bigint DEFAULT NULL,
+ `START_USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `START_ACT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `END_ACT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SUPER_PROCESS_INSTANCE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DELETE_REASON_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '',
+ `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CALLBACK_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CALLBACK_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `REFERENCE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `REFERENCE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROPAGATED_STAGE_INST_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `BUSINESS_STATUS_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `END_USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `STATE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ PRIMARY KEY (`ID_`) USING BTREE,
+ UNIQUE KEY `PROC_INST_ID_` (`PROC_INST_ID_`) USING BTREE,
+ KEY `ACT_IDX_HI_PRO_INST_END` (`END_TIME_`) USING BTREE,
+ KEY `ACT_IDX_HI_PRO_I_BUSKEY` (`BUSINESS_KEY_`) USING BTREE,
+ KEY `ACT_IDX_HI_PRO_SUPER_PROCINST` (`SUPER_PROCESS_INSTANCE_ID_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_hi_taskinst锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_hi_taskinst`;
+CREATE TABLE `act_hi_taskinst` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT '1',
+ `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TASK_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TASK_DEF_KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROPAGATED_STAGE_INST_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `STATE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PARENT_TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DESCRIPTION_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `OWNER_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ASSIGNEE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `START_TIME_` datetime(3) NOT NULL,
+ `IN_PROGRESS_TIME_` datetime(3) DEFAULT NULL,
+ `IN_PROGRESS_STARTED_BY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CLAIM_TIME_` datetime(3) DEFAULT NULL,
+ `CLAIMED_BY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SUSPENDED_TIME_` datetime(3) DEFAULT NULL,
+ `SUSPENDED_BY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `END_TIME_` datetime(3) DEFAULT NULL,
+ `COMPLETED_BY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DURATION_` bigint DEFAULT NULL,
+ `DELETE_REASON_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PRIORITY_` int DEFAULT NULL,
+ `IN_PROGRESS_DUE_DATE_` datetime(3) DEFAULT NULL,
+ `DUE_DATE_` datetime(3) DEFAULT NULL,
+ `FORM_KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '',
+ `LAST_UPDATED_TIME_` datetime(3) DEFAULT NULL,
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `ACT_IDX_HI_TASK_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_HI_TASK_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_HI_TASK_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_HI_TASK_INST_PROCINST` (`PROC_INST_ID_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_hi_tsk_log锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_hi_tsk_log`;
+CREATE TABLE `act_hi_tsk_log` (
+ `ID_` bigint NOT NULL AUTO_INCREMENT,
+ `TYPE_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `TIME_STAMP_` timestamp(3) NOT NULL,
+ `USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DATA_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '',
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `ACT_IDX_ACT_HI_TSK_LOG_TASK` (`TASK_ID_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_hi_varinst锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_hi_varinst`;
+CREATE TABLE `act_hi_varinst` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT '1',
+ `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `VAR_TYPE_` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `BYTEARRAY_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DOUBLE_` double DEFAULT NULL,
+ `LONG_` bigint DEFAULT NULL,
+ `TEXT_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TEXT2_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `META_INFO_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CREATE_TIME_` datetime(3) DEFAULT NULL,
+ `LAST_UPDATED_TIME_` datetime(3) DEFAULT NULL,
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `ACT_IDX_HI_PROCVAR_NAME_TYPE` (`NAME_`,`VAR_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_HI_VAR_SCOPE_ID_TYPE` (`SCOPE_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_HI_VAR_SUB_ID_TYPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_HI_PROCVAR_PROC_INST` (`PROC_INST_ID_`) USING BTREE,
+ KEY `ACT_IDX_HI_PROCVAR_TASK_ID` (`TASK_ID_`) USING BTREE,
+ KEY `ACT_IDX_HI_PROCVAR_EXE` (`EXECUTION_ID_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_id_bytearray锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_id_bytearray`;
+CREATE TABLE `act_id_bytearray` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `BYTES_` longblob,
+ PRIMARY KEY (`ID_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_id_group锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_id_group`;
+CREATE TABLE `act_id_group` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ PRIMARY KEY (`ID_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_id_info锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_id_info`;
+CREATE TABLE `act_id_info` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `USER_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TYPE_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `VALUE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PASSWORD_` longblob,
+ `PARENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ PRIMARY KEY (`ID_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_id_membership锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_id_membership`;
+CREATE TABLE `act_id_membership` (
+ `USER_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `GROUP_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ PRIMARY KEY (`USER_ID_`,`GROUP_ID_`) USING BTREE,
+ KEY `ACT_FK_MEMB_GROUP` (`GROUP_ID_`) USING BTREE,
+ CONSTRAINT `ACT_FK_MEMB_GROUP` FOREIGN KEY (`GROUP_ID_`) REFERENCES `act_id_group` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_MEMB_USER` FOREIGN KEY (`USER_ID_`) REFERENCES `act_id_user` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_id_priv锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_id_priv`;
+CREATE TABLE `act_id_priv` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ PRIMARY KEY (`ID_`) USING BTREE,
+ UNIQUE KEY `ACT_UNIQ_PRIV_NAME` (`NAME_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_id_priv_mapping锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_id_priv_mapping`;
+CREATE TABLE `act_id_priv_mapping` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `PRIV_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `GROUP_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `ACT_FK_PRIV_MAPPING` (`PRIV_ID_`) USING BTREE,
+ KEY `ACT_IDX_PRIV_USER` (`USER_ID_`) USING BTREE,
+ KEY `ACT_IDX_PRIV_GROUP` (`GROUP_ID_`) USING BTREE,
+ CONSTRAINT `ACT_FK_PRIV_MAPPING` FOREIGN KEY (`PRIV_ID_`) REFERENCES `act_id_priv` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_id_token锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_id_token`;
+CREATE TABLE `act_id_token` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `TOKEN_VALUE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TOKEN_DATE_` timestamp(3) NULL DEFAULT NULL,
+ `IP_ADDRESS_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `USER_AGENT_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TOKEN_DATA_` varchar(2000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ PRIMARY KEY (`ID_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_id_user锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_id_user`;
+CREATE TABLE `act_id_user` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `FIRST_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `LAST_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DISPLAY_NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `EMAIL_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PWD_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PICTURE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '',
+ PRIMARY KEY (`ID_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_procdef_info锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_procdef_info`;
+CREATE TABLE `act_procdef_info` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `INFO_JSON_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ PRIMARY KEY (`ID_`) USING BTREE,
+ UNIQUE KEY `ACT_UNIQ_INFO_PROCDEF` (`PROC_DEF_ID_`) USING BTREE,
+ KEY `ACT_IDX_INFO_PROCDEF` (`PROC_DEF_ID_`) USING BTREE,
+ KEY `ACT_FK_INFO_JSON_BA` (`INFO_JSON_ID_`) USING BTREE,
+ CONSTRAINT `ACT_FK_INFO_JSON_BA` FOREIGN KEY (`INFO_JSON_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_INFO_PROCDEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_ru_actinst锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_ru_actinst`;
+CREATE TABLE `act_ru_actinst` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT '1',
+ `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `ACT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CALL_PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ACT_NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ACT_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `ASSIGNEE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `COMPLETED_BY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `START_TIME_` datetime(3) NOT NULL,
+ `END_TIME_` datetime(3) DEFAULT NULL,
+ `DURATION_` bigint DEFAULT NULL,
+ `TRANSACTION_ORDER_` int DEFAULT NULL,
+ `DELETE_REASON_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '',
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `ACT_IDX_RU_ACTI_START` (`START_TIME_`) USING BTREE,
+ KEY `ACT_IDX_RU_ACTI_END` (`END_TIME_`) USING BTREE,
+ KEY `ACT_IDX_RU_ACTI_PROC` (`PROC_INST_ID_`) USING BTREE,
+ KEY `ACT_IDX_RU_ACTI_PROC_ACT` (`PROC_INST_ID_`,`ACT_ID_`) USING BTREE,
+ KEY `ACT_IDX_RU_ACTI_EXEC` (`EXECUTION_ID_`) USING BTREE,
+ KEY `ACT_IDX_RU_ACTI_EXEC_ACT` (`EXECUTION_ID_`,`ACT_ID_`) USING BTREE,
+ KEY `ACT_IDX_RU_ACTI_TASK` (`TASK_ID_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_ru_deadletter_job锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_ru_deadletter_job`;
+CREATE TABLE `act_ru_deadletter_job` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `EXCLUSIVE_` tinyint(1) DEFAULT NULL,
+ `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROCESS_INSTANCE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ELEMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ELEMENT_NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CORRELATION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `EXCEPTION_STACK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `EXCEPTION_MSG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DUEDATE_` timestamp(3) NULL DEFAULT NULL,
+ `REPEAT_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `HANDLER_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `HANDLER_CFG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CUSTOM_VALUES_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '',
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `ACT_IDX_DEADLETTER_JOB_EXCEPTION_STACK_ID` (`EXCEPTION_STACK_ID_`) USING BTREE,
+ KEY `ACT_IDX_DEADLETTER_JOB_CUSTOM_VALUES_ID` (`CUSTOM_VALUES_ID_`) USING BTREE,
+ KEY `ACT_IDX_DEADLETTER_JOB_CORRELATION_ID` (`CORRELATION_ID_`) USING BTREE,
+ KEY `ACT_IDX_DJOB_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_DJOB_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_DJOB_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_FK_DEADLETTER_JOB_EXECUTION` (`EXECUTION_ID_`) USING BTREE,
+ KEY `ACT_FK_DEADLETTER_JOB_PROCESS_INSTANCE` (`PROCESS_INSTANCE_ID_`) USING BTREE,
+ KEY `ACT_FK_DEADLETTER_JOB_PROC_DEF` (`PROC_DEF_ID_`) USING BTREE,
+ CONSTRAINT `ACT_FK_DEADLETTER_JOB_CUSTOM_VALUES` FOREIGN KEY (`CUSTOM_VALUES_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_DEADLETTER_JOB_EXCEPTION` FOREIGN KEY (`EXCEPTION_STACK_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_DEADLETTER_JOB_EXECUTION` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_DEADLETTER_JOB_PROC_DEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_DEADLETTER_JOB_PROCESS_INSTANCE` FOREIGN KEY (`PROCESS_INSTANCE_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_ru_entitylink锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_ru_entitylink`;
+CREATE TABLE `act_ru_entitylink` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `CREATE_TIME_` datetime(3) DEFAULT NULL,
+ `LINK_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PARENT_ELEMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `REF_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `REF_SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `REF_SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ROOT_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ROOT_SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `HIERARCHY_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `ACT_IDX_ENT_LNK_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`,`LINK_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_ENT_LNK_REF_SCOPE` (`REF_SCOPE_ID_`,`REF_SCOPE_TYPE_`,`LINK_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_ENT_LNK_ROOT_SCOPE` (`ROOT_SCOPE_ID_`,`ROOT_SCOPE_TYPE_`,`LINK_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_ENT_LNK_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`,`LINK_TYPE_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_ru_event_subscr锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_ru_event_subscr`;
+CREATE TABLE `act_ru_event_subscr` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `EVENT_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `EVENT_NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ACTIVITY_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CONFIGURATION_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CREATED_` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
+ `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SUB_SCOPE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_DEFINITION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_DEFINITION_KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_TYPE_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `LOCK_TIME_` timestamp(3) NULL DEFAULT NULL,
+ `LOCK_OWNER_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '',
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `ACT_IDX_EVENT_SUBSCR_CONFIG_` (`CONFIGURATION_`) USING BTREE,
+ KEY `ACT_IDX_EVENT_SUBSCR_EXEC_ID` (`EXECUTION_ID_`) USING BTREE,
+ KEY `ACT_IDX_EVENT_SUBSCR_PROC_ID` (`PROC_INST_ID_`) USING BTREE,
+ KEY `ACT_IDX_EVENT_SUBSCR_SCOPEREF_` (`SCOPE_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ CONSTRAINT `ACT_FK_EVENT_EXEC` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_ru_execution锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_ru_execution`;
+CREATE TABLE `act_ru_execution` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `BUSINESS_KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PARENT_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SUPER_EXEC_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ROOT_PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ACT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `IS_ACTIVE_` tinyint DEFAULT NULL,
+ `IS_CONCURRENT_` tinyint DEFAULT NULL,
+ `IS_SCOPE_` tinyint DEFAULT NULL,
+ `IS_EVENT_SCOPE_` tinyint DEFAULT NULL,
+ `IS_MI_ROOT_` tinyint DEFAULT NULL,
+ `SUSPENSION_STATE_` int DEFAULT NULL,
+ `CACHED_ENT_STATE_` int DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '',
+ `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `START_ACT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `START_TIME_` datetime(3) DEFAULT NULL,
+ `START_USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `LOCK_TIME_` timestamp(3) NULL DEFAULT NULL,
+ `LOCK_OWNER_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `IS_COUNT_ENABLED_` tinyint DEFAULT NULL,
+ `EVT_SUBSCR_COUNT_` int DEFAULT NULL,
+ `TASK_COUNT_` int DEFAULT NULL,
+ `JOB_COUNT_` int DEFAULT NULL,
+ `TIMER_JOB_COUNT_` int DEFAULT NULL,
+ `SUSP_JOB_COUNT_` int DEFAULT NULL,
+ `DEADLETTER_JOB_COUNT_` int DEFAULT NULL,
+ `EXTERNAL_WORKER_JOB_COUNT_` int DEFAULT NULL,
+ `VAR_COUNT_` int DEFAULT NULL,
+ `ID_LINK_COUNT_` int DEFAULT NULL,
+ `CALLBACK_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CALLBACK_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `REFERENCE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `REFERENCE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROPAGATED_STAGE_INST_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `BUSINESS_STATUS_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `ACT_IDX_EXEC_BUSKEY` (`BUSINESS_KEY_`) USING BTREE,
+ KEY `ACT_IDC_EXEC_ROOT` (`ROOT_PROC_INST_ID_`) USING BTREE,
+ KEY `ACT_IDX_EXEC_REF_ID_` (`REFERENCE_ID_`) USING BTREE,
+ KEY `ACT_FK_EXE_PROCINST` (`PROC_INST_ID_`) USING BTREE,
+ KEY `ACT_FK_EXE_PARENT` (`PARENT_ID_`) USING BTREE,
+ KEY `ACT_FK_EXE_SUPER` (`SUPER_EXEC_`) USING BTREE,
+ KEY `ACT_FK_EXE_PROCDEF` (`PROC_DEF_ID_`) USING BTREE,
+ CONSTRAINT `ACT_FK_EXE_PARENT` FOREIGN KEY (`PARENT_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE CASCADE ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_EXE_PROCDEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_EXE_PROCINST` FOREIGN KEY (`PROC_INST_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT `ACT_FK_EXE_SUPER` FOREIGN KEY (`SUPER_EXEC_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE CASCADE ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_ru_external_job锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_ru_external_job`;
+CREATE TABLE `act_ru_external_job` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `LOCK_EXP_TIME_` timestamp(3) NULL DEFAULT NULL,
+ `LOCK_OWNER_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `EXCLUSIVE_` tinyint(1) DEFAULT NULL,
+ `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROCESS_INSTANCE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ELEMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ELEMENT_NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CORRELATION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `RETRIES_` int DEFAULT NULL,
+ `EXCEPTION_STACK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `EXCEPTION_MSG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DUEDATE_` timestamp(3) NULL DEFAULT NULL,
+ `REPEAT_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `HANDLER_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `HANDLER_CFG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CUSTOM_VALUES_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '',
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `ACT_IDX_EXTERNAL_JOB_EXCEPTION_STACK_ID` (`EXCEPTION_STACK_ID_`) USING BTREE,
+ KEY `ACT_IDX_EXTERNAL_JOB_CUSTOM_VALUES_ID` (`CUSTOM_VALUES_ID_`) USING BTREE,
+ KEY `ACT_IDX_EXTERNAL_JOB_CORRELATION_ID` (`CORRELATION_ID_`) USING BTREE,
+ KEY `ACT_IDX_EJOB_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_EJOB_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_EJOB_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ CONSTRAINT `ACT_FK_EXTERNAL_JOB_CUSTOM_VALUES` FOREIGN KEY (`CUSTOM_VALUES_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_EXTERNAL_JOB_EXCEPTION` FOREIGN KEY (`EXCEPTION_STACK_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_ru_history_job锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_ru_history_job`;
+CREATE TABLE `act_ru_history_job` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `LOCK_EXP_TIME_` timestamp(3) NULL DEFAULT NULL,
+ `LOCK_OWNER_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `RETRIES_` int DEFAULT NULL,
+ `EXCEPTION_STACK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `EXCEPTION_MSG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `HANDLER_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `HANDLER_CFG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CUSTOM_VALUES_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ADV_HANDLER_CFG_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL,
+ `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '',
+ PRIMARY KEY (`ID_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_ru_identitylink锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_ru_identitylink`;
+CREATE TABLE `act_ru_identitylink` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `GROUP_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `USER_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `ACT_IDX_IDENT_LNK_USER` (`USER_ID_`) USING BTREE,
+ KEY `ACT_IDX_IDENT_LNK_GROUP` (`GROUP_ID_`) USING BTREE,
+ KEY `ACT_IDX_IDENT_LNK_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_IDENT_LNK_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_IDENT_LNK_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_ATHRZ_PROCEDEF` (`PROC_DEF_ID_`) USING BTREE,
+ KEY `ACT_FK_TSKASS_TASK` (`TASK_ID_`) USING BTREE,
+ KEY `ACT_FK_IDL_PROCINST` (`PROC_INST_ID_`) USING BTREE,
+ CONSTRAINT `ACT_FK_ATHRZ_PROCEDEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_IDL_PROCINST` FOREIGN KEY (`PROC_INST_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_TSKASS_TASK` FOREIGN KEY (`TASK_ID_`) REFERENCES `act_ru_task` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_ru_job锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_ru_job`;
+CREATE TABLE `act_ru_job` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `LOCK_EXP_TIME_` timestamp(3) NULL DEFAULT NULL,
+ `LOCK_OWNER_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `EXCLUSIVE_` tinyint(1) DEFAULT NULL,
+ `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROCESS_INSTANCE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ELEMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ELEMENT_NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CORRELATION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `RETRIES_` int DEFAULT NULL,
+ `EXCEPTION_STACK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `EXCEPTION_MSG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DUEDATE_` timestamp(3) NULL DEFAULT NULL,
+ `REPEAT_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `HANDLER_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `HANDLER_CFG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CUSTOM_VALUES_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '',
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `ACT_IDX_JOB_EXCEPTION_STACK_ID` (`EXCEPTION_STACK_ID_`) USING BTREE,
+ KEY `ACT_IDX_JOB_CUSTOM_VALUES_ID` (`CUSTOM_VALUES_ID_`) USING BTREE,
+ KEY `ACT_IDX_JOB_CORRELATION_ID` (`CORRELATION_ID_`) USING BTREE,
+ KEY `ACT_IDX_JOB_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_JOB_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_JOB_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_FK_JOB_EXECUTION` (`EXECUTION_ID_`) USING BTREE,
+ KEY `ACT_FK_JOB_PROCESS_INSTANCE` (`PROCESS_INSTANCE_ID_`) USING BTREE,
+ KEY `ACT_FK_JOB_PROC_DEF` (`PROC_DEF_ID_`) USING BTREE,
+ CONSTRAINT `ACT_FK_JOB_CUSTOM_VALUES` FOREIGN KEY (`CUSTOM_VALUES_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_JOB_EXCEPTION` FOREIGN KEY (`EXCEPTION_STACK_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_JOB_EXECUTION` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_JOB_PROC_DEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_JOB_PROCESS_INSTANCE` FOREIGN KEY (`PROCESS_INSTANCE_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_ru_suspended_job锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_ru_suspended_job`;
+CREATE TABLE `act_ru_suspended_job` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `EXCLUSIVE_` tinyint(1) DEFAULT NULL,
+ `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROCESS_INSTANCE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ELEMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ELEMENT_NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CORRELATION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `RETRIES_` int DEFAULT NULL,
+ `EXCEPTION_STACK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `EXCEPTION_MSG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DUEDATE_` timestamp(3) NULL DEFAULT NULL,
+ `REPEAT_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `HANDLER_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `HANDLER_CFG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CUSTOM_VALUES_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '',
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `ACT_IDX_SUSPENDED_JOB_EXCEPTION_STACK_ID` (`EXCEPTION_STACK_ID_`) USING BTREE,
+ KEY `ACT_IDX_SUSPENDED_JOB_CUSTOM_VALUES_ID` (`CUSTOM_VALUES_ID_`) USING BTREE,
+ KEY `ACT_IDX_SUSPENDED_JOB_CORRELATION_ID` (`CORRELATION_ID_`) USING BTREE,
+ KEY `ACT_IDX_SJOB_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_SJOB_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_SJOB_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_FK_SUSPENDED_JOB_EXECUTION` (`EXECUTION_ID_`) USING BTREE,
+ KEY `ACT_FK_SUSPENDED_JOB_PROCESS_INSTANCE` (`PROCESS_INSTANCE_ID_`) USING BTREE,
+ KEY `ACT_FK_SUSPENDED_JOB_PROC_DEF` (`PROC_DEF_ID_`) USING BTREE,
+ CONSTRAINT `ACT_FK_SUSPENDED_JOB_CUSTOM_VALUES` FOREIGN KEY (`CUSTOM_VALUES_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_SUSPENDED_JOB_EXCEPTION` FOREIGN KEY (`EXCEPTION_STACK_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_SUSPENDED_JOB_EXECUTION` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_SUSPENDED_JOB_PROC_DEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_SUSPENDED_JOB_PROCESS_INSTANCE` FOREIGN KEY (`PROCESS_INSTANCE_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_ru_task锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_ru_task`;
+CREATE TABLE `act_ru_task` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TASK_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROPAGATED_STAGE_INST_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `STATE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PARENT_TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DESCRIPTION_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TASK_DEF_KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `OWNER_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ASSIGNEE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DELEGATION_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PRIORITY_` int DEFAULT NULL,
+ `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL,
+ `IN_PROGRESS_TIME_` datetime(3) DEFAULT NULL,
+ `IN_PROGRESS_STARTED_BY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CLAIM_TIME_` datetime(3) DEFAULT NULL,
+ `CLAIMED_BY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SUSPENDED_TIME_` datetime(3) DEFAULT NULL,
+ `SUSPENDED_BY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `IN_PROGRESS_DUE_DATE_` datetime(3) DEFAULT NULL,
+ `DUE_DATE_` datetime(3) DEFAULT NULL,
+ `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SUSPENSION_STATE_` int DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '',
+ `FORM_KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `IS_COUNT_ENABLED_` tinyint DEFAULT NULL,
+ `VAR_COUNT_` int DEFAULT NULL,
+ `ID_LINK_COUNT_` int DEFAULT NULL,
+ `SUB_TASK_COUNT_` int DEFAULT NULL,
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `ACT_IDX_TASK_CREATE` (`CREATE_TIME_`) USING BTREE,
+ KEY `ACT_IDX_TASK_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_TASK_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_TASK_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_FK_TASK_EXE` (`EXECUTION_ID_`) USING BTREE,
+ KEY `ACT_FK_TASK_PROCINST` (`PROC_INST_ID_`) USING BTREE,
+ KEY `ACT_FK_TASK_PROCDEF` (`PROC_DEF_ID_`) USING BTREE,
+ CONSTRAINT `ACT_FK_TASK_EXE` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_TASK_PROCDEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_TASK_PROCINST` FOREIGN KEY (`PROC_INST_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_ru_timer_job锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_ru_timer_job`;
+CREATE TABLE `act_ru_timer_job` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `LOCK_EXP_TIME_` timestamp(3) NULL DEFAULT NULL,
+ `LOCK_OWNER_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `EXCLUSIVE_` tinyint(1) DEFAULT NULL,
+ `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROCESS_INSTANCE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROC_DEF_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ELEMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ELEMENT_NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_DEFINITION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CORRELATION_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `RETRIES_` int DEFAULT NULL,
+ `EXCEPTION_STACK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `EXCEPTION_MSG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DUEDATE_` timestamp(3) NULL DEFAULT NULL,
+ `REPEAT_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `HANDLER_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `HANDLER_CFG_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CUSTOM_VALUES_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '',
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `ACT_IDX_TIMER_JOB_EXCEPTION_STACK_ID` (`EXCEPTION_STACK_ID_`) USING BTREE,
+ KEY `ACT_IDX_TIMER_JOB_CUSTOM_VALUES_ID` (`CUSTOM_VALUES_ID_`) USING BTREE,
+ KEY `ACT_IDX_TIMER_JOB_CORRELATION_ID` (`CORRELATION_ID_`) USING BTREE,
+ KEY `ACT_IDX_TIMER_JOB_DUEDATE` (`DUEDATE_`) USING BTREE,
+ KEY `ACT_IDX_TJOB_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_TJOB_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_TJOB_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_FK_TIMER_JOB_EXECUTION` (`EXECUTION_ID_`) USING BTREE,
+ KEY `ACT_FK_TIMER_JOB_PROCESS_INSTANCE` (`PROCESS_INSTANCE_ID_`) USING BTREE,
+ KEY `ACT_FK_TIMER_JOB_PROC_DEF` (`PROC_DEF_ID_`) USING BTREE,
+ CONSTRAINT `ACT_FK_TIMER_JOB_CUSTOM_VALUES` FOREIGN KEY (`CUSTOM_VALUES_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_TIMER_JOB_EXCEPTION` FOREIGN KEY (`EXCEPTION_STACK_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_TIMER_JOB_EXECUTION` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_TIMER_JOB_PROC_DEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_TIMER_JOB_PROCESS_INSTANCE` FOREIGN KEY (`PROCESS_INSTANCE_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細act_ru_variable锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `act_ru_variable`;
+CREATE TABLE `act_ru_variable` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `EXECUTION_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PROC_INST_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TASK_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SUB_SCOPE_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_TYPE_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `BYTEARRAY_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DOUBLE_` double DEFAULT NULL,
+ `LONG_` bigint DEFAULT NULL,
+ `TEXT_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TEXT2_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `META_INFO_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `ACT_IDX_RU_VAR_SCOPE_ID_TYPE` (`SCOPE_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_IDX_RU_VAR_SUB_ID_TYPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`) USING BTREE,
+ KEY `ACT_FK_VAR_BYTEARRAY` (`BYTEARRAY_ID_`) USING BTREE,
+ KEY `ACT_IDX_VARIABLE_TASK_ID` (`TASK_ID_`) USING BTREE,
+ KEY `ACT_FK_VAR_EXE` (`EXECUTION_ID_`) USING BTREE,
+ KEY `ACT_FK_VAR_PROCINST` (`PROC_INST_ID_`) USING BTREE,
+ CONSTRAINT `ACT_FK_VAR_BYTEARRAY` FOREIGN KEY (`BYTEARRAY_ID_`) REFERENCES `act_ge_bytearray` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_VAR_EXE` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `ACT_FK_VAR_PROCINST` FOREIGN KEY (`PROC_INST_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細after_sale_permission锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `after_sale_permission`;
+CREATE TABLE `after_sale_permission` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `biz_type` tinyint NOT NULL COMMENT '鏁版嵁绫诲瀷: 1-鍞悗宸ュ崟 2-閫�璐х敵璇� 3-缁翠慨璁板綍',
+ `biz_id` bigint NOT NULL COMMENT '鏁版嵁缂栧彿',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `level` tinyint NOT NULL COMMENT '鏉冮檺绾у埆: 1-璐熻矗浜� 2-鍙 3-璇诲啓',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_biz` (`biz_type`,`biz_id`) USING BTREE,
+ KEY `idx_user` (`user_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鍞悗鏁版嵁鏉冮檺琛�';
+
+-- ============ 琛細after_sale_repair锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `after_sale_repair`;
+CREATE TABLE `after_sale_repair` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缁翠慨璁板綍缂栧彿',
+ `ticket_id` bigint NOT NULL COMMENT '鍏宠仈宸ュ崟缂栧彿锛屽叧鑱� after_sale_ticket.id',
+ `repair_type` tinyint NOT NULL COMMENT '缁翠慨绫诲瀷: 1-鐜板満缁翠慨 2-杩斿巶缁翠慨 3-杩滅▼鎸囧',
+ `fault_description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鏁呴殰鎻忚堪',
+ `repair_action` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '缁翠慨鎺柦',
+ `repair_result` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '缁翠慨缁撴灉: 宸蹭慨澶�/鏃犳硶淇/閮ㄥ垎淇',
+ `repair_cost` decimal(10,2) DEFAULT '0.00' COMMENT '缁翠慨璐圭敤',
+ `repair_user_id` bigint DEFAULT NULL COMMENT '缁翠慨浜�',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵��: 0-寰呭鐞� 10-缁翠慨涓� 20-宸插畬鎴� 30-宸插叧闂�',
+ `start_time` datetime DEFAULT NULL COMMENT '寮�濮嬬淮淇椂闂�',
+ `finish_time` datetime DEFAULT NULL COMMENT '瀹屾垚缁翠慨鏃堕棿',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_ticket_id` (`ticket_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鍞悗缁翠慨璁板綍琛�';
+
+-- ============ 琛細after_sale_return锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `after_sale_return`;
+CREATE TABLE `after_sale_return` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '閫�璐х敵璇风紪鍙�',
+ `no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '閫�璐у崟鍙�',
+ `ticket_id` bigint NOT NULL COMMENT '鍏宠仈宸ュ崟缂栧彿',
+ `customer_id` bigint NOT NULL COMMENT '瀹㈡埛缂栧彿',
+ `sale_order_id` bigint DEFAULT NULL COMMENT '鍏宠仈閿�鍞鍗曠紪鍙�',
+ `return_type` tinyint NOT NULL COMMENT '閫�璐х被鍨�: 1-閫�娆鹃��璐� 2-鎹㈣揣 3-浠呴��娆�',
+ `return_reason` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '閫�璐у師鍥�',
+ `defect_category` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '缂洪櫡鍒嗙被',
+ `total_return_price` decimal(12,2) NOT NULL DEFAULT '0.00' COMMENT '搴旈��鎬婚噾棰�',
+ `actual_refund_price` decimal(12,2) DEFAULT '0.00' COMMENT '瀹為��閲戦',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵��: 0-鑽夌 10-閿�鍞鏍镐腑 20-瀹℃牳閫氳繃宸插悓姝ES 30-妫�楠屼腑 40-妫�楠屽畬鎴� 50-宸插叆搴� 60-閫�娆�/鎹㈣揣瀹屾垚 70-宸插叧闂� 99-宸插彇娑�',
+ `audit_user_id` bigint DEFAULT NULL COMMENT '瀹℃牳浜�',
+ `audit_time` datetime DEFAULT NULL COMMENT '瀹℃牳鏃堕棿',
+ `mes_return_id` bigint DEFAULT NULL COMMENT 'MES閫�璐у崟缂栧彿',
+ `mes_return_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'MES閫�璐у崟鍙�(鍐椾綑)',
+ `quality_result` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璐ㄦ缁撹',
+ `quality_report_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璐ㄦ鎶ュ憡闄勪欢URL',
+ `return_inbound_time` datetime DEFAULT NULL COMMENT '閫�璐у叆搴撳畬鎴愭椂闂�',
+ `refund_time` datetime DEFAULT NULL COMMENT '閫�娆�/鎹㈣揣瀹屾垚鏃堕棿',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_no` (`no`) USING BTREE,
+ KEY `idx_ticket_id` (`ticket_id`) USING BTREE,
+ KEY `idx_mes_return_id` (`mes_return_id`) USING BTREE,
+ KEY `idx_status` (`status`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鍞悗閫�璐х敵璇疯〃';
+
+-- ============ 琛細after_sale_return_item锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `after_sale_return_item`;
+CREATE TABLE `after_sale_return_item` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `return_id` bigint NOT NULL COMMENT '閫�璐х敵璇风紪鍙�',
+ `ticket_item_id` bigint NOT NULL COMMENT '宸ュ崟鏄庣粏琛岀紪鍙�',
+ `item_id` bigint NOT NULL COMMENT 'MDM鐗╂枡缂栧彿',
+ `item_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐗╂枡缂栫爜(鍐椾綑)',
+ `item_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐗╂枡鍚嶇О(鍐椾綑)',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规缂栧彿',
+ `batch_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵规鍙�',
+ `return_quantity` decimal(10,3) NOT NULL COMMENT '閫�璐ф暟閲�',
+ `unit_price` decimal(12,2) NOT NULL COMMENT '閿�鍞崟浠�',
+ `return_price` decimal(12,2) NOT NULL COMMENT '閫�璐ч噾棰�',
+ `mes_return_line_id` bigint DEFAULT NULL COMMENT 'MES閫�璐у崟琛岀紪鍙�',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_return_id` (`return_id`) USING BTREE,
+ KEY `idx_ticket_item_id` (`ticket_item_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鍞悗閫�璐ф槑缁嗚琛�';
+
+-- ============ 琛細after_sale_ticket锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `after_sale_ticket`;
+CREATE TABLE `after_sale_ticket` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '宸ュ崟缂栧彿',
+ `no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '宸ュ崟鍗曞彿',
+ `name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '宸ュ崟涓婚/鏍囬',
+ `customer_id` bigint NOT NULL COMMENT '瀹㈡埛缂栧彿锛屽叧鑱� crm_customer.id',
+ `contact_id` bigint DEFAULT NULL COMMENT '鑱旂郴浜虹紪鍙凤紝鍏宠仈 crm_contact.id',
+ `sale_order_id` bigint DEFAULT NULL COMMENT '閿�鍞鍗曠紪鍙凤紝鍏宠仈 erp_sale_order.id',
+ `sale_order_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閿�鍞鍗曞彿(鍐椾綑)',
+ `contract_id` bigint DEFAULT NULL COMMENT '鍚堝悓缂栧彿锛屽叧鑱� crm_contract.id',
+ `issue_type` tinyint NOT NULL DEFAULT '0' COMMENT '闂绫诲瀷: 0-鏈垽瀹� 1-涓�鑸棶棰� 2-缁翠慨闂 3-閫�璐ч棶棰�',
+ `issue_category` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '闂鍒嗙被',
+ `issue_description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '闂鎻忚堪',
+ `severity_level` tinyint DEFAULT '0' COMMENT '涓ラ噸绋嬪害: 0-杞诲井 1-涓�鑸� 2-涓ラ噸 3-鑷村懡',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵��: 0-鑽夌 10-澶勭悊涓� 30-寰呴��璐� 40-寰呴��娆�/鎹㈣揣 50-宸插畬缁� 60-宸插叧闂� 99-宸插彇娑�',
+ `owner_user_id` bigint NOT NULL COMMENT '璐熻矗浜虹敤鎴风紪鍙�',
+ `handler_user_id` bigint DEFAULT NULL COMMENT '澶勭悊浜虹敤鎴风紪鍙�',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'BPM宸ヤ綔娴佸疄渚嬬紪鍙�',
+ `return_id` bigint DEFAULT NULL COMMENT '鍏宠仈閫�璐х敵璇风紪鍙�',
+ `repair_id` bigint DEFAULT NULL COMMENT '鍏宠仈缁翠慨璁板綍缂栧彿',
+ `resolved_time` datetime DEFAULT NULL COMMENT '瑙e喅鏃堕棿',
+ `closed_time` datetime DEFAULT NULL COMMENT '鍏抽棴鏃堕棿',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_no` (`no`) USING BTREE,
+ KEY `idx_customer_id` (`customer_id`) USING BTREE,
+ KEY `idx_sale_order_id` (`sale_order_id`) USING BTREE,
+ KEY `idx_owner_user_id` (`owner_user_id`) USING BTREE,
+ KEY `idx_status` (`status`) USING BTREE,
+ KEY `idx_create_time` (`create_time`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鍞悗宸ュ崟涓昏〃';
+
+-- ============ 琛細after_sale_ticket_item锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `after_sale_ticket_item`;
+CREATE TABLE `after_sale_ticket_item` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `ticket_id` bigint NOT NULL COMMENT '宸ュ崟缂栧彿锛屽叧鑱� after_sale_ticket.id',
+ `sale_order_item_id` bigint DEFAULT NULL COMMENT '閿�鍞鍗曡缂栧彿',
+ `item_id` bigint NOT NULL COMMENT 'MDM鐗╂枡缂栧彿',
+ `item_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐗╂枡缂栫爜(鍐椾綑)',
+ `item_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐗╂枡鍚嶇О(鍐椾綑)',
+ `batch_id` bigint DEFAULT NULL COMMENT '鐢熶骇鎵规缂栧彿',
+ `batch_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐢熶骇鎵规鍙�',
+ `sale_quantity` decimal(10,3) NOT NULL DEFAULT '0.000' COMMENT '閿�鍞暟閲�',
+ `return_quantity` decimal(10,3) DEFAULT '0.000' COMMENT '閫�璐ф暟閲�',
+ `need_repair` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁闇�瑕佺淮淇�',
+ `need_return` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁闇�瑕侀��璐�',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_ticket_id` (`ticket_id`) USING BTREE,
+ KEY `idx_item_id` (`item_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鍞悗宸ュ崟鏄庣粏琛岃〃';
+
+-- ============ 琛細ai_chat_conversation锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `ai_chat_conversation`;
+CREATE TABLE `ai_chat_conversation` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID 缂栧彿',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '鏂板璇�' COMMENT '瀵硅瘽鏍囬',
+ `pinned` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁缃《',
+ `pinned_time` datetime DEFAULT NULL COMMENT '缃《鏃堕棿',
+ `role_id` bigint DEFAULT NULL COMMENT '瑙掕壊缂栧彿',
+ `model_id` bigint DEFAULT NULL COMMENT '妯″瀷缂栧彿',
+ `model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妯″瀷鏍囧織',
+ `system_message` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瑙掕壊璁惧畾',
+ `temperature` double DEFAULT NULL COMMENT '娓╁害鍙傛暟',
+ `max_tokens` int DEFAULT NULL COMMENT '鍗曟潯鍥炲鐨勬渶澶� Token 鏁伴噺',
+ `max_contexts` int DEFAULT NULL COMMENT '涓婁笅鏂囩殑鏈�澶� Message 鏁伴噺',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='AI Chat 瀵硅瘽琛�';
+
+-- ============ 琛細ai_chat_message锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `ai_chat_message`;
+CREATE TABLE `ai_chat_message` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `conversation_id` bigint NOT NULL COMMENT '瀵硅瘽缂栧彿',
+ `reply_id` bigint DEFAULT NULL COMMENT '鍥炲娑堟伅缂栧彿',
+ `type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '娑堟伅绫诲瀷',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `role_id` bigint DEFAULT NULL COMMENT '瑙掕壊缂栧彿',
+ `model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妯″瀷鏍囧織',
+ `model_id` bigint DEFAULT NULL COMMENT '妯″瀷缂栧彿',
+ `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鑱婂ぉ鍐呭',
+ `reasoning_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鎺ㄧ悊鍐呭',
+ `use_context` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鎼哄甫涓婁笅鏂�',
+ `segment_ids` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐭ヨ瘑搴撴钀界紪鍙锋暟缁�',
+ `web_search_pages` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鑱旂綉鎼滅储鐨勭綉椤靛唴瀹规暟缁�',
+ `attachment_urls` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '闄勪欢 URL 鏁扮粍',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='AI Chat 娑堟伅琛�';
+
+-- ============ 琛細ai_chat_role锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `ai_chat_role`;
+CREATE TABLE `ai_chat_role` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '瑙掕壊鍚嶇О',
+ `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瑙掕壊澶村儚',
+ `category` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '瑙掕壊鍒嗙被',
+ `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瑙掕壊鎻忚堪',
+ `system_message` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瑙掕壊璁惧畾',
+ `user_id` bigint DEFAULT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `model_id` bigint DEFAULT NULL COMMENT '妯″瀷缂栧彿',
+ `knowledge_ids` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '寮曠敤鐨勭煡璇嗗簱缂栧彿鍒楄〃',
+ `tool_ids` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '寮曠敤鐨勫伐鍏风紪鍙峰垪琛�',
+ `mcp_client_names` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '寮曠敤鐨� MCP Client 鍚嶅瓧鍒楄〃',
+ `public_status` bit(1) NOT NULL DEFAULT b'1' COMMENT '鏄惁鍏紑',
+ `sort` int NOT NULL DEFAULT '0' COMMENT '鎺掑簭鍊�',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵��',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='AI 鑱婂ぉ瑙掕壊琛�';
+
+-- ============ 琛細ai_image锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `ai_image`;
+CREATE TABLE `ai_image` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `prompt` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鎻愮ず璇�',
+ `platform` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '骞冲彴',
+ `model_id` bigint DEFAULT NULL COMMENT '妯″瀷缂栧彿',
+ `model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妯″瀷鏍囪瘑',
+ `width` int DEFAULT NULL COMMENT '鍥剧墖瀹藉害',
+ `height` int DEFAULT NULL COMMENT '鍥剧墖楂樺害',
+ `status` tinyint NOT NULL COMMENT '鐢熸垚鐘舵��',
+ `finish_time` datetime DEFAULT NULL COMMENT '瀹屾垚鏃堕棿',
+ `error_message` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '缁樼敾閿欒淇℃伅',
+ `pic_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍥剧墖鍦板潃',
+ `public_status` bit(1) NOT NULL DEFAULT b'1' COMMENT '鏄惁鍏紑',
+ `options` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '缁樺埗鍙傛暟',
+ `buttons` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT 'mj buttons 鎸夐挳',
+ `task_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '浠诲姟缂栧彿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='AI 缁樼敾琛�';
+
+-- ============ 琛細ai_knowledge锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `ai_knowledge`;
+CREATE TABLE `ai_knowledge` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鐭ヨ瘑搴撳悕绉�',
+ `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐭ヨ瘑搴撴弿杩�',
+ `embedding_model_id` bigint DEFAULT NULL COMMENT '鍚戦噺妯″瀷缂栧彿',
+ `embedding_model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妯″瀷鏍囪瘑',
+ `top_k` int DEFAULT NULL COMMENT 'topK',
+ `similarity_threshold` double DEFAULT NULL COMMENT '鐩镐技搴﹂槇鍊�',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵��',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='AI 鐭ヨ瘑搴撹〃';
+
+-- ============ 琛細ai_knowledge_document锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `ai_knowledge_document`;
+CREATE TABLE `ai_knowledge_document` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `knowledge_id` bigint NOT NULL COMMENT '鐭ヨ瘑搴撶紪鍙�',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鏂囨。鍚嶇О',
+ `url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏂囦欢 URL',
+ `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鍐呭',
+ `content_length` int DEFAULT NULL COMMENT '鏂囨。闀垮害',
+ `tokens` int DEFAULT NULL COMMENT '鏂囨。 token 鏁伴噺',
+ `segment_max_tokens` int DEFAULT NULL COMMENT '鍒嗙墖鏈�澶� Token 鏁�',
+ `retrieval_count` int NOT NULL DEFAULT '0' COMMENT '鍙洖娆℃暟',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵��',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='AI 鐭ヨ瘑搴撴枃妗h〃';
+
+-- ============ 琛細ai_knowledge_segment锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `ai_knowledge_segment`;
+CREATE TABLE `ai_knowledge_segment` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `knowledge_id` bigint NOT NULL COMMENT '鐭ヨ瘑搴撶紪鍙�',
+ `document_id` bigint NOT NULL COMMENT '鏂囨。缂栧彿',
+ `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鍒囩墖鍐呭',
+ `content_length` int DEFAULT NULL COMMENT '鍒囩墖鍐呭闀垮害',
+ `vector_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍚戦噺搴撶殑缂栧彿',
+ `tokens` int DEFAULT NULL COMMENT 'token 鏁伴噺',
+ `retrieval_count` int NOT NULL DEFAULT '0' COMMENT '鍙洖娆℃暟',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵��',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='AI 鐭ヨ瘑搴撴枃妗e垎娈佃〃';
+
+-- ============ 琛細ai_mind_map锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `ai_mind_map`;
+CREATE TABLE `ai_mind_map` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `platform` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '骞冲彴',
+ `model_id` bigint DEFAULT NULL COMMENT '妯″瀷缂栧彿',
+ `model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妯″瀷',
+ `prompt` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鐢熸垚鍐呭鎻愮ず',
+ `generated_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鐢熸垚鐨勫唴瀹�',
+ `error_message` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閿欒淇℃伅',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='AI 鎬濈淮瀵煎浘琛�';
+
+-- ============ 琛細ai_music锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `ai_music`;
+CREATE TABLE `ai_music` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '闊充箰鍚嶇О',
+ `lyric` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '姝岃瘝',
+ `image_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍥剧墖鍦板潃',
+ `audio_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '闊抽鍦板潃',
+ `video_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瑙嗛鍦板潃',
+ `status` tinyint NOT NULL COMMENT '闊充箰鐘舵��',
+ `generate_mode` tinyint NOT NULL COMMENT '鐢熸垚妯″紡',
+ `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎻忚堪璇�',
+ `platform` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '骞冲彴',
+ `model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妯″瀷',
+ `tags` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '闊充箰椋庢牸鏍囩',
+ `duration` double DEFAULT NULL COMMENT '闊充箰鏃堕暱',
+ `public_status` bit(1) NOT NULL DEFAULT b'1' COMMENT '鏄惁鍏紑',
+ `task_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '浠诲姟缂栧彿',
+ `error_message` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閿欒淇℃伅',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='AI 闊充箰琛�';
+
+-- ============ 琛細ai_tool锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `ai_tool`;
+CREATE TABLE `ai_tool` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '宸ュ叿缂栧彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '宸ュ叿鍚嶇О',
+ `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宸ュ叿鎻忚堪',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵��',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='AI 宸ュ叿琛�';
+
+-- ============ 琛細ai_workflow锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `ai_workflow`;
+CREATE TABLE `ai_workflow` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '宸ヤ綔娴佸悕绉�',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '宸ヤ綔娴佹爣璇�',
+ `graph` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '宸ヤ綔娴佹ā鍨� JSON 鏁版嵁',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵��',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='AI 宸ヤ綔娴佽〃';
+
+-- ============ 琛細ai_write锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `ai_write`;
+CREATE TABLE `ai_write` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `type` tinyint NOT NULL COMMENT '鍐欎綔绫诲瀷',
+ `platform` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '骞冲彴',
+ `model_id` bigint DEFAULT NULL COMMENT '妯″瀷缂栧彿',
+ `model` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妯″瀷',
+ `prompt` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鐢熸垚鍐呭鎻愮ず',
+ `generated_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鐢熸垚鐨勫唴瀹�',
+ `original_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鍘熸枃',
+ `length` tinyint DEFAULT NULL COMMENT '闀垮害鎻愮ず璇�',
+ `format` tinyint DEFAULT NULL COMMENT '鏍煎紡鎻愮ず璇�',
+ `tone` tinyint DEFAULT NULL COMMENT '璇皵鎻愮ず璇�',
+ `language` tinyint DEFAULT NULL COMMENT '璇█鎻愮ず璇�',
+ `error_message` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閿欒淇℃伅',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='AI 鍐欎綔琛�';
+
+-- ============ 琛細bpm_bak_20260904_bytearray锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `bpm_bak_20260904_bytearray`;
+CREATE TABLE `bpm_bak_20260904_bytearray` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DEPLOYMENT_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `BYTES_` longblob,
+ `GENERATED_` tinyint DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+
+-- ============ 琛細bpm_bak_20260904_category锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `bpm_bak_20260904_category`;
+CREATE TABLE `bpm_bak_20260904_category` (
+ `id` bigint NOT NULL DEFAULT '0' COMMENT '鍒嗙被缂栧彿',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍒嗙被鍚�',
+ `code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍒嗙被鏍囧織',
+ `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍒嗙被鎻忚堪',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鍒嗙被鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+ `sort` int NOT NULL DEFAULT '0' COMMENT '鍒嗙被鎺掑簭',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+
+-- ============ 琛細bpm_bak_20260904_deployment锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `bpm_bak_20260904_deployment`;
+CREATE TABLE `bpm_bak_20260904_deployment` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '',
+ `DEPLOY_TIME_` timestamp(3) NULL DEFAULT NULL,
+ `DERIVED_FROM_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DERIVED_FROM_ROOT_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `PARENT_DEPLOYMENT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `ENGINE_VERSION_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+
+-- ============ 琛細bpm_bak_20260904_model锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `bpm_bak_20260904_model`;
+CREATE TABLE `bpm_bak_20260904_model` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL,
+ `LAST_UPDATE_TIME_` timestamp(3) NULL DEFAULT NULL,
+ `VERSION_` int DEFAULT NULL,
+ `META_INFO_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DEPLOYMENT_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `EDITOR_SOURCE_VALUE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `EDITOR_SOURCE_EXTRA_VALUE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT ''
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+
+-- ============ 琛細bpm_bak_20260904_procdef锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `bpm_bak_20260904_procdef`;
+CREATE TABLE `bpm_bak_20260904_procdef` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `CATEGORY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `NAME_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `VERSION_` int NOT NULL,
+ `DEPLOYMENT_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `RESOURCE_NAME_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DGRM_RESOURCE_NAME_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DESCRIPTION_` varchar(4000) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `HAS_START_FORM_KEY_` tinyint DEFAULT NULL,
+ `HAS_GRAPHICAL_NOTATION_` tinyint DEFAULT NULL,
+ `SUSPENSION_STATE_` int DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '',
+ `ENGINE_VERSION_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DERIVED_FROM_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DERIVED_FROM_ROOT_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `DERIVED_VERSION_` int NOT NULL DEFAULT '0'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+
+-- ============ 琛細bpm_bak_20260904_procinfo锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `bpm_bak_20260904_procinfo`;
+CREATE TABLE `bpm_bak_20260904_procinfo` (
+ `id` bigint NOT NULL DEFAULT '0' COMMENT '缂栧彿',
+ `process_definition_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '娴佺▼瀹氫箟鐨勭紪鍙�',
+ `model_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '娴佺▼妯″瀷鐨勭紪鍙�',
+ `model_type` tinyint NOT NULL DEFAULT '10' COMMENT '娴佺▼妯″瀷鐨勭被鍨�',
+ `category` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴佺▼鍒嗙被鐨勭紪鐮�',
+ `icon` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍥炬爣',
+ `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎻忚堪',
+ `form_type` tinyint NOT NULL DEFAULT '10' COMMENT '琛ㄥ崟绫诲瀷锛�10鏅�氳〃鍗� 20鑷畾涔夎〃鍗曪級',
+ `form_id` bigint DEFAULT NULL COMMENT '鍔ㄦ�佽〃鍗曠紪鍙�',
+ `form_conf` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '琛ㄥ崟鐨勯厤缃�',
+ `form_fields` json DEFAULT NULL COMMENT '琛ㄥ崟椤圭殑鏁扮粍',
+ `form_custom_create_path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑷畾涔夎〃鍗曠殑鎻愪氦璺緞',
+ `form_custom_view_path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑷畾涔夎〃鍗曠殑鏌ョ湅璺緞',
+ `simple_model` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT 'SIMPLE 璁捐鍣ㄦā鍨嬫暟鎹�',
+ `visible` bit(1) NOT NULL DEFAULT b'1' COMMENT '鏄惁鍙',
+ `sort` bigint NOT NULL DEFAULT '0' COMMENT '鎺掑簭鍊�',
+ `start_user_ids` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍙彂璧风敤鎴风紪鍙锋暟缁�',
+ `start_dept_ids` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍙彂璧烽儴闂ㄧ紪鍙锋暟缁�',
+ `manager_user_ids` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍙鐞嗙敤鎴风紪鍙锋暟缁�',
+ `allow_cancel_running_process` bit(1) NOT NULL DEFAULT b'1' COMMENT '鏄惁鍏佽鎾ら攢瀹℃壒涓殑鐢宠',
+ `allow_withdraw_task` bit(1) NOT NULL DEFAULT b'1' COMMENT '鏄惁鍏佽瀹℃壒浜烘挙鍥炰换鍔�',
+ `process_id_rule` json DEFAULT NULL COMMENT '娴佺▼ ID 瑙勫垯',
+ `auto_approval_type` tinyint DEFAULT NULL COMMENT '鑷姩鍘婚噸绫诲瀷',
+ `title_setting` json DEFAULT NULL COMMENT '鏍囬璁剧疆',
+ `summary_setting` json DEFAULT NULL COMMENT '鎽樿璁剧疆',
+ `process_before_trigger_setting` json DEFAULT NULL COMMENT '娴佺▼鍓嶇疆閫氱煡璁剧疆',
+ `process_after_trigger_setting` json DEFAULT NULL COMMENT '娴佺▼鍚庣疆閫氱煡璁剧疆',
+ `task_before_trigger_setting` json DEFAULT NULL COMMENT '浠诲姟鍓嶇疆閫氱煡璁剧疆',
+ `task_after_trigger_setting` json DEFAULT NULL COMMENT '浠诲姟鍚庣疆閫氱煡璁剧疆',
+ `print_template_setting` json DEFAULT NULL COMMENT '鑷畾涔夋墦鍗版ā鏉胯缃�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+
+-- ============ 琛細bpm_oa_leave锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `bpm_oa_leave`;
+CREATE TABLE `bpm_oa_leave` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '璇峰亣琛ㄥ崟涓婚敭',
+ `user_id` bigint NOT NULL COMMENT '鐢宠浜虹殑鐢ㄦ埛缂栧彿',
+ `type` tinyint NOT NULL COMMENT '璇峰亣绫诲瀷',
+ `reason` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍘熷洜',
+ `start_time` datetime NOT NULL COMMENT '寮�濮嬫椂闂�',
+ `end_time` datetime NOT NULL COMMENT '缁撴潫鏃堕棿',
+ `day` bigint NOT NULL COMMENT '璇峰亣澶╂暟',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '瀹℃壒缁撴灉',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瀵瑰簲鐨勬祦绋嬬紪鍙�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='OA 璇峰亣鐢宠琛�';
+
+-- ============ 琛細bpm_process_instance_copy锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `bpm_process_instance_copy`;
+CREATE TABLE `bpm_process_instance_copy` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `start_user_id` bigint NOT NULL COMMENT '鍙戣捣浜� Id',
+ `process_instance_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '娴佺▼鍚�',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '娴佺▼瀹炰緥鐨勭紪鍙�',
+ `process_definition_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '娴佺▼瀹炰緥鐨勬祦绋嬪畾涔夌紪鍙�',
+ `category` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴佺▼鍒嗙被',
+ `activity_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴佺▼娲诲姩鐨勭紪鍙�',
+ `activity_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴佺▼娲诲姩鐨勫悕瀛�',
+ `task_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴佺▼浠诲姟鐨勭紪鍙�',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿锛堣鎶勯�佺殑鐢ㄦ埛缂栧彿锛�',
+ `reason` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎶勯�佹剰瑙�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='娴佺▼鎶勯�佽〃';
+
+-- ============ 琛細crm_business锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `crm_business`;
+CREATE TABLE `crm_business` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍟嗘満鍚嶇О',
+ `customer_id` bigint NOT NULL COMMENT '瀹㈡埛缂栧彿',
+ `follow_up_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '璺熻繘鐘舵��',
+ `contact_last_time` datetime DEFAULT NULL COMMENT '鏈�鍚庤窡杩涙椂闂�',
+ `contact_next_time` datetime DEFAULT NULL COMMENT '涓嬫鑱旂郴鏃堕棿',
+ `owner_user_id` bigint DEFAULT NULL COMMENT '璐熻矗浜虹殑鐢ㄦ埛缂栧彿',
+ `status_type_id` bigint NOT NULL COMMENT '鍟嗘満鐘舵�佺粍缂栧彿',
+ `status_id` bigint NOT NULL COMMENT '鍟嗘満鐘舵�佺紪鍙�',
+ `end_status` int DEFAULT NULL COMMENT '缁撴潫鐘舵��',
+ `end_remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '缁撴潫鏃剁殑澶囨敞',
+ `deal_time` datetime DEFAULT NULL COMMENT '棰勮鎴愪氦鏃ユ湡',
+ `total_product_price` decimal(24,6) DEFAULT NULL COMMENT '浜у搧鎬婚噾棰濓紝鍗曚綅锛氬厓',
+ `discount_percent` decimal(24,6) DEFAULT NULL COMMENT '鏁村崟鎶樻墸锛岀櫨鍒嗘瘮',
+ `total_price` decimal(24,6) DEFAULT NULL COMMENT '鍟嗘満鎬婚噾棰濓紝鍗曚綅锛氬厓',
+ `order_id` bigint DEFAULT NULL COMMENT '鍏宠仈 ERP 閿�鍞鍗曠紪鍙�',
+ `order_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'ERP 閿�鍞鍗曞崟鍙�',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
+ `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='CRM 鍟嗘満琛�';
+
+-- ============ 琛細crm_business_product锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `crm_business_product`;
+CREATE TABLE `crm_business_product` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `business_id` bigint NOT NULL COMMENT '鍟嗘満缂栧彿',
+ `item_id` bigint NOT NULL COMMENT 'MDM 鐗╂枡缂栧彿',
+ `item_unit_id` bigint DEFAULT NULL COMMENT '璁¢噺鍗曚綅缂栧彿',
+ `item_price` decimal(24,6) DEFAULT NULL COMMENT '鐗╂枡鍘熶环锛屽崟浣嶏細鍏�',
+ `business_price` decimal(24,6) DEFAULT NULL COMMENT '鍟嗘満浠锋牸锛屽崟浣嶏細鍏�',
+ `count` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `total_price` decimal(24,6) DEFAULT NULL COMMENT '鎬昏浠锋牸锛屽崟浣嶏細鍏�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
+ `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='CRM 鍟嗘満浜у搧鍏宠仈琛�';
+
+-- ============ 琛細crm_business_status锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `crm_business_status`;
+CREATE TABLE `crm_business_status` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `type_id` bigint NOT NULL COMMENT '鐘舵�佺被鍨嬬紪鍙�',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐘舵�佸悕',
+ `percent` int DEFAULT NULL COMMENT '璧㈠崟鐜囷紝鐧惧垎姣�',
+ `sort` int DEFAULT NULL COMMENT '鎺掑簭',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
+ `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='CRM 鍟嗘満鐘舵�佽〃';
+
+-- ============ 琛細crm_business_status_type锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `crm_business_status_type`;
+CREATE TABLE `crm_business_status_type` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐘舵�佺被鍨嬪悕',
+ `dept_ids` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '浣跨敤鐨勯儴闂ㄧ紪鍙�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
+ `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='CRM 鍟嗘満鐘舵�佺粍琛�';
+
+-- ============ 琛細crm_clue锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `crm_clue`;
+CREATE TABLE `crm_clue` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿锛屼富閿嚜澧�',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '绾跨储鍚嶇О',
+ `follow_up_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '璺熻繘鐘舵��',
+ `contact_last_time` datetime DEFAULT NULL COMMENT '鏈�鍚庤窡杩涙椂闂�',
+ `contact_last_content` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏈�鍚庤窡杩涘唴瀹�',
+ `contact_next_time` datetime DEFAULT NULL COMMENT '涓嬫鑱旂郴鏃堕棿',
+ `owner_user_id` bigint DEFAULT NULL COMMENT '璐熻矗浜虹殑鐢ㄦ埛缂栧彿',
+ `transform_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '杞寲鐘舵��',
+ `customer_id` bigint DEFAULT NULL COMMENT '瀹㈡埛缂栧彿',
+ `mobile` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵嬫満鍙�',
+ `telephone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐢佃瘽',
+ `qq` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'QQ',
+ `wechat` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '寰俊',
+ `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閭',
+ `area_id` int DEFAULT NULL COMMENT '鎵�鍦ㄥ湴',
+ `detail_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璇︾粏鍦板潃',
+ `industry_id` int DEFAULT NULL COMMENT '鎵�灞炶涓�',
+ `level` int DEFAULT NULL COMMENT '瀹㈡埛绛夌骇',
+ `source` int DEFAULT NULL COMMENT '瀹㈡埛鏉ユ簮',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
+ `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='CRM 绾跨储琛�';
+
+-- ============ 琛細crm_contact锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `crm_contact`;
+CREATE TABLE `crm_contact` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鑱旂郴浜哄鍚�',
+ `customer_id` bigint NOT NULL COMMENT '瀹㈡埛缂栧彿',
+ `contact_last_time` datetime DEFAULT NULL COMMENT '鏈�鍚庤窡杩涙椂闂�',
+ `contact_last_content` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏈�鍚庤窡杩涘唴瀹�',
+ `contact_next_time` datetime DEFAULT NULL COMMENT '涓嬫鑱旂郴鏃堕棿',
+ `owner_user_id` bigint DEFAULT NULL COMMENT '璐熻矗浜虹敤鎴风紪鍙�',
+ `mobile` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵嬫満鍙�',
+ `telephone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐢佃瘽',
+ `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐢靛瓙閭',
+ `qq` bigint DEFAULT NULL COMMENT 'QQ',
+ `wechat` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '寰俊',
+ `area_id` int DEFAULT NULL COMMENT '鎵�鍦ㄥ湴',
+ `detail_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璇︾粏鍦板潃',
+ `sex` int DEFAULT NULL COMMENT '鎬у埆',
+ `master` tinyint(1) DEFAULT NULL COMMENT '鏄惁鍏抽敭鍐崇瓥浜�',
+ `post` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑱屼綅',
+ `parent_id` bigint DEFAULT NULL COMMENT '鐩村睘涓婄骇',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
+ `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='CRM 鑱旂郴浜鸿〃';
+
+-- ============ 琛細crm_contact_business锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `crm_contact_business`;
+CREATE TABLE `crm_contact_business` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `contact_id` bigint NOT NULL COMMENT '鑱旂郴浜虹紪鍙�',
+ `business_id` bigint NOT NULL COMMENT '鍟嗘満缂栧彿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
+ `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='CRM 鑱旂郴浜轰笌鍟嗘満鍏宠仈琛�';
+
+-- ============ 琛細crm_contract锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `crm_contract`;
+CREATE TABLE `crm_contract` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鍚堝悓缂栧彿',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍚堝悓鍚嶇О',
+ `no` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍚堝悓缂栧彿',
+ `customer_id` bigint NOT NULL COMMENT '瀹㈡埛缂栧彿',
+ `business_id` bigint DEFAULT NULL COMMENT '鍟嗘満缂栧彿',
+ `contact_last_time` datetime DEFAULT NULL COMMENT '鏈�鍚庤窡杩涙椂闂�',
+ `owner_user_id` bigint DEFAULT NULL COMMENT '璐熻矗浜虹殑鐢ㄦ埛缂栧彿',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宸ヤ綔娴佺紪鍙�',
+ `audit_status` int DEFAULT NULL COMMENT '瀹℃壒鐘舵��',
+ `order_date` datetime DEFAULT NULL COMMENT '涓嬪崟鏃ユ湡',
+ `start_time` datetime DEFAULT NULL COMMENT '寮�濮嬫椂闂�',
+ `end_time` datetime DEFAULT NULL COMMENT '缁撴潫鏃堕棿',
+ `total_product_price` decimal(24,6) DEFAULT NULL COMMENT '浜у搧鎬婚噾棰濓紝鍗曚綅锛氬厓',
+ `discount_percent` decimal(24,6) DEFAULT NULL COMMENT '鏁村崟鎶樻墸',
+ `total_price` decimal(24,6) DEFAULT NULL COMMENT '鍚堝悓鎬婚噾棰濓紝鍗曚綅锛氬垎',
+ `deposit_price` decimal(24,6) DEFAULT NULL COMMENT '瀹氶噾閲戦锛屽崟浣嶏細鍏�',
+ `order_id` bigint DEFAULT NULL COMMENT '鍏宠仈 ERP 閿�鍞鍗曠紪鍙�',
+ `order_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'ERP 閿�鍞鍗曞崟鍙�',
+ `sign_contact_id` bigint DEFAULT NULL COMMENT '瀹㈡埛绛剧害浜�',
+ `sign_user_id` bigint DEFAULT NULL COMMENT '鍏徃绛剧害浜�',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
+ `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='CRM 鍚堝悓琛�';
+
+-- ============ 琛細crm_contract_config锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `crm_contract_config`;
+CREATE TABLE `crm_contract_config` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `notify_enabled` tinyint(1) DEFAULT NULL COMMENT '鏄惁寮�鍚彁鍓嶆彁閱�',
+ `notify_days` int DEFAULT NULL COMMENT '鎻愬墠鎻愰啋澶╂暟',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
+ `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='CRM 鍚堝悓閰嶇疆琛�';
+
+-- ============ 琛細crm_contract_product锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `crm_contract_product`;
+CREATE TABLE `crm_contract_product` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `contract_id` bigint NOT NULL COMMENT '鍚堝悓缂栧彿',
+ `item_id` bigint DEFAULT NULL COMMENT 'MDM鐗╂枡缂栧彿',
+ `item_unit_id` bigint DEFAULT NULL COMMENT '璁¢噺鍗曚綅缂栧彿',
+ `item_price` decimal(24,6) DEFAULT NULL COMMENT '鐗╂枡鍘熶环锛堝啑浣欙級',
+ `contract_price` decimal(24,6) DEFAULT NULL COMMENT '鍚堝悓浠锋牸锛屽崟浣嶏細鍏�',
+ `count` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `total_price` decimal(24,6) DEFAULT NULL COMMENT '鎬昏浠锋牸锛屽崟浣嶏細鍏�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
+ `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='CRM 鍚堝悓浜у搧鍏宠仈琛�';
+
+-- ============ 琛細crm_customer锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `crm_customer`;
+CREATE TABLE `crm_customer` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '瀹㈡埛鍚嶇О',
+ `follow_up_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '璺熻繘鐘舵��',
+ `contact_last_time` datetime DEFAULT NULL COMMENT '鏈�鍚庤窡杩涙椂闂�',
+ `contact_last_content` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏈�鍚庤窡杩涘唴瀹�',
+ `contact_next_time` datetime DEFAULT NULL COMMENT '涓嬫鑱旂郴鏃堕棿',
+ `owner_user_id` bigint DEFAULT NULL COMMENT '璐熻矗浜虹殑鐢ㄦ埛缂栧彿',
+ `owner_time` datetime DEFAULT NULL COMMENT '鎴愪负璐熻矗浜虹殑鏃堕棿',
+ `lock_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '閿佸畾鐘舵��',
+ `deal_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '鎴愪氦鐘舵��',
+ `mobile` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵嬫満',
+ `telephone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐢佃瘽',
+ `qq` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'QQ',
+ `wechat` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '寰俊',
+ `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閭',
+ `area_id` int DEFAULT NULL COMMENT '鎵�鍦ㄥ湴',
+ `detail_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璇︾粏鍦板潃',
+ `industry_id` int DEFAULT NULL COMMENT '鎵�灞炶涓�',
+ `level` int DEFAULT NULL COMMENT '瀹㈡埛绛夌骇',
+ `source` int DEFAULT NULL COMMENT '瀹㈡埛鏉ユ簮',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
+ `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='CRM 瀹㈡埛琛�';
+
+-- ============ 琛細crm_customer_limit_config锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `crm_customer_limit_config`;
+CREATE TABLE `crm_customer_limit_config` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `type` int NOT NULL COMMENT '瑙勫垯绫诲瀷',
+ `user_ids` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瑙勫垯閫傜敤浜虹兢',
+ `dept_ids` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瑙勫垯閫傜敤閮ㄩ棬',
+ `max_count` int DEFAULT NULL COMMENT '鏁伴噺涓婇檺',
+ `deal_count_enabled` tinyint(1) DEFAULT NULL COMMENT '鎴愪氦瀹㈡埛鏄惁鍗犳湁鎷ユ湁瀹㈡埛鏁�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
+ `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='CRM 瀹㈡埛闄愬埗閰嶇疆琛�';
+
+-- ============ 琛細crm_customer_pool_config锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `crm_customer_pool_config`;
+CREATE TABLE `crm_customer_pool_config` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '鏄惁鍚敤瀹㈡埛鍏捣',
+ `contact_expire_days` int DEFAULT NULL COMMENT '鏈窡杩涙斁鍏ュ叕娴峰ぉ鏁�',
+ `deal_expire_days` int DEFAULT NULL COMMENT '鏈垚浜ゆ斁鍏ュ叕娴峰ぉ鏁�',
+ `notify_enabled` tinyint(1) DEFAULT NULL COMMENT '鏄惁寮�鍚彁鍓嶆彁閱�',
+ `notify_days` int DEFAULT NULL COMMENT '鎻愬墠鎻愰啋澶╂暟',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
+ `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='CRM 瀹㈡埛鍏捣閰嶇疆琛�';
+
+-- ============ 琛細crm_follow_up_record锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `crm_follow_up_record`;
+CREATE TABLE `crm_follow_up_record` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `biz_type` int NOT NULL COMMENT '鏁版嵁绫诲瀷',
+ `biz_id` bigint NOT NULL COMMENT '鏁版嵁缂栧彿',
+ `type` int DEFAULT NULL COMMENT '璺熻繘绫诲瀷',
+ `content` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璺熻繘鍐呭',
+ `next_time` datetime DEFAULT NULL COMMENT '涓嬫鑱旂郴鏃堕棿',
+ `pic_urls` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍥剧墖',
+ `business_ids` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍏宠仈鐨勫晢鏈虹紪鍙锋暟缁�',
+ `contact_ids` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍏宠仈鐨勮仈绯讳汉缂栧彿鏁扮粍',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
+ `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='CRM 璺熻繘璁板綍琛�';
+
+-- ============ 琛細crm_invoice锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `crm_invoice`;
+CREATE TABLE `crm_invoice` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID',
+ `no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '寮�绁ㄧ紪鍙�',
+ `customer_id` bigint NOT NULL COMMENT '瀹㈡埛缂栧彿',
+ `contract_id` bigint NOT NULL COMMENT '鍚堝悓缂栧彿',
+ `owner_user_id` bigint NOT NULL COMMENT '璐熻矗浜虹紪鍙�',
+ `invoice_type` int NOT NULL COMMENT '鍙戠エ绫诲瀷锛堝瓧鍏� crm_invoice_type锛�',
+ `invoice_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鍙戠エ鍙风爜',
+ `invoice_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鍙戠エ鎶ご',
+ `price` decimal(18,2) NOT NULL COMMENT '寮�绁ㄩ噾棰濓紙鍏冿級',
+ `invoice_time` datetime DEFAULT NULL COMMENT '寮�绁ㄦ棩鏈�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '宸ヤ綔娴佺紪鍙�',
+ `audit_status` int NOT NULL COMMENT '瀹℃壒鐘舵�侊紙crm_audit_status锛�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
+ `deleted` tinyint NOT NULL DEFAULT '0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='CRM 寮�绁�';
+
+-- ============ 琛細crm_permission锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `crm_permission`;
+CREATE TABLE `crm_permission` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿锛屼富閿嚜澧�',
+ `biz_type` int NOT NULL COMMENT '鏁版嵁绫诲瀷',
+ `biz_id` bigint NOT NULL COMMENT '鏁版嵁缂栧彿',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `level` int NOT NULL COMMENT '鏉冮檺绾у埆',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
+ `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='CRM 鏁版嵁鏉冮檺琛�';
+
+-- ============ 琛細crm_receivable锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `crm_receivable`;
+CREATE TABLE `crm_receivable` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID',
+ `no` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍥炴缂栧彿',
+ `plan_id` bigint DEFAULT NULL COMMENT '鍥炴璁″垝缂栧彿',
+ `customer_id` bigint NOT NULL COMMENT '瀹㈡埛缂栧彿',
+ `contract_id` bigint NOT NULL COMMENT '鍚堝悓缂栧彿',
+ `invoice_id` bigint DEFAULT NULL COMMENT '鍏宠仈鐨勫紑绁ㄧ紪鍙凤紝鍏宠仈 crm_invoice.id',
+ `owner_user_id` bigint DEFAULT NULL COMMENT '璐熻矗浜虹紪鍙�',
+ `return_time` datetime DEFAULT NULL COMMENT '鍥炴鏃ユ湡',
+ `return_type` int DEFAULT NULL COMMENT '鍥炴鏂瑰紡',
+ `price` decimal(24,6) DEFAULT NULL COMMENT '璁″垝鍥炴閲戦锛屽崟浣嶏細鍏�',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宸ヤ綔娴佺紪鍙�',
+ `audit_status` int DEFAULT NULL COMMENT '瀹℃壒鐘舵��',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
+ `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='CRM 鍥炴琛�';
+
+-- ============ 琛細crm_receivable_plan锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `crm_receivable_plan`;
+CREATE TABLE `crm_receivable_plan` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `period` int DEFAULT NULL COMMENT '鏈熸暟',
+ `customer_id` bigint NOT NULL COMMENT '瀹㈡埛缂栧彿',
+ `contract_id` bigint NOT NULL COMMENT '鍚堝悓缂栧彿',
+ `owner_user_id` bigint DEFAULT NULL COMMENT '璐熻矗浜虹紪鍙�',
+ `return_time` datetime DEFAULT NULL COMMENT '璁″垝鍥炴鏃ユ湡',
+ `return_type` int DEFAULT NULL COMMENT '璁″垝鍥炴绫诲瀷',
+ `price` decimal(24,6) DEFAULT NULL COMMENT '璁″垝鍥炴閲戦锛屽崟浣嶏細鍏�',
+ `receivable_id` bigint DEFAULT NULL COMMENT '鍥炴缂栧彿',
+ `remind_days` int DEFAULT NULL COMMENT '鎻愬墠鍑犲ぉ鎻愰啋',
+ `remind_time` datetime DEFAULT NULL COMMENT '鎻愰啋鏃ユ湡',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
+ `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='CRM 鍥炴璁″垝琛�';
+
+-- ============ 琛細crm_sale_quotation锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `crm_sale_quotation`;
+CREATE TABLE `crm_sale_quotation` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鎶ヤ环鍗曞彿',
+ `name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鎶ヤ环鍗曞悕绉�',
+ `customer_id` bigint NOT NULL COMMENT '瀹㈡埛缂栧彿',
+ `business_id` bigint DEFAULT NULL COMMENT '鍟嗘満缂栧彿',
+ `contact_id` bigint DEFAULT NULL COMMENT '鑱旂郴浜虹紪鍙�',
+ `owner_user_id` bigint NOT NULL COMMENT '璐熻矗浜虹紪鍙�',
+ `status` int NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0鑽夌 10瀹℃壒涓� 20宸查�氳繃 30宸叉嫆缁� 40宸插彇娑� 50宸茶浆鍚堝悓锛�',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '宸ヤ綔娴佺紪鍙�',
+ `quotation_time` datetime DEFAULT NULL COMMENT '鎶ヤ环鏃ユ湡',
+ `valid_until` datetime DEFAULT NULL COMMENT '鏈夋晥鏈熻嚦',
+ `total_product_price` decimal(24,6) DEFAULT NULL COMMENT '浜у搧鎬婚噾棰�',
+ `discount_percent` decimal(10,2) DEFAULT '0.00' COMMENT '鏁村崟鎶樻墸(%)',
+ `discount_price` decimal(24,6) DEFAULT '0.000000' COMMENT '浼樻儬閲戦',
+ `total_price` decimal(24,6) DEFAULT NULL COMMENT '鎶ヤ环鎬婚噾棰�',
+ `tax_rate` decimal(10,2) DEFAULT NULL COMMENT '绋庣巼(%)',
+ `tax_price` decimal(24,6) DEFAULT NULL COMMENT '绋庨',
+ `contract_id` bigint DEFAULT NULL COMMENT '鍏宠仈鍚堝悓缂栧彿',
+ `contract_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鍏宠仈鍚堝悓鍗曞彿',
+ `remark` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_no` (`no`) USING BTREE,
+ KEY `idx_customer_id` (`customer_id`) USING BTREE,
+ KEY `idx_business_id` (`business_id`) USING BTREE,
+ KEY `idx_owner_user_id` (`owner_user_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='CRM 閿�鍞姤浠峰崟';
+
+-- ============ 琛細crm_sale_quotation_product锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `crm_sale_quotation_product`;
+CREATE TABLE `crm_sale_quotation_product` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `quotation_id` bigint NOT NULL COMMENT '鎶ヤ环鍗曠紪鍙�',
+ `item_id` bigint NOT NULL COMMENT 'MDM鐗╂枡缂栧彿',
+ `item_unit_id` bigint DEFAULT NULL COMMENT '璁¢噺鍗曚綅缂栧彿',
+ `item_price` decimal(24,6) NOT NULL COMMENT '鐗╂枡鍘熶环锛堝啑浣欙級',
+ `quotation_price` decimal(24,6) NOT NULL COMMENT '鎶ヤ环鍗曚环',
+ `count` decimal(24,6) NOT NULL COMMENT '鏁伴噺',
+ `total_price` decimal(24,6) NOT NULL COMMENT '灏忚閲戦',
+ `tax_percent` decimal(10,2) DEFAULT NULL COMMENT '绋庣巼(%)',
+ `tax_price` decimal(24,6) DEFAULT NULL COMMENT '绋庨',
+ `remark` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_quotation_id` (`quotation_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='CRM 閿�鍞姤浠峰崟浜у搧鏄庣粏';
+
+-- ============ 琛細crm_sales_target锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `crm_sales_target`;
+CREATE TABLE `crm_sales_target` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID',
+ `name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鐩爣鍚嶇О',
+ `period_type` int NOT NULL COMMENT '鍛ㄦ湡绫诲瀷(瀛楀吀 crm_sales_target_period_type: 1骞�/2瀛e害/3鏈�)',
+ `period_value` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鍛ㄦ湡鍊硷紝濡� 2026 / 2026-Q1 / 2026-07',
+ `start_time` datetime NOT NULL COMMENT '鍛ㄦ湡寮�濮嬫椂闂�(淇濆瓨鏃剁敱鍛ㄦ湡璁$畻鍐欏叆)',
+ `end_time` datetime NOT NULL COMMENT '鍛ㄦ湡缁撴潫鏃堕棿(淇濆瓨鏃剁敱鍛ㄦ湡璁$畻鍐欏叆)',
+ `target_dimension` int NOT NULL COMMENT '鐩爣缁村害(瀛楀吀 crm_sales_target_dimension: 1涓汉/2閮ㄩ棬/3浜у搧)',
+ `target_user_id` bigint DEFAULT NULL COMMENT '鐩爣鐢ㄦ埛缂栧彿(缁村害=涓汉)',
+ `target_dept_id` bigint DEFAULT NULL COMMENT '鐩爣閮ㄩ棬缂栧彿(缁村害=閮ㄩ棬)',
+ `target_item_id` bigint DEFAULT NULL COMMENT '鐩爣鐗╂枡缂栧彿(缁村害=浜у搧锛屽叧鑱� MDM)',
+ `contract_target` decimal(18,2) DEFAULT NULL COMMENT '鍚堝悓閲戦鐩爣(鍏�)',
+ `receivable_target` decimal(18,2) DEFAULT NULL COMMENT '鍥炴閲戦鐩爣(鍏�)',
+ `business_target` decimal(18,2) DEFAULT NULL COMMENT '鍟嗘満閲戦鐩爣(鍏�)',
+ `customer_target` int DEFAULT NULL COMMENT '鏂板瀹㈡埛鏁扮洰鏍�',
+ `contract_count_target` int DEFAULT NULL COMMENT '鏂板鍚堝悓鏁扮洰鏍�',
+ `status` int NOT NULL DEFAULT '0' COMMENT '鐘舵��(瀛楀吀 crm_sales_target_status: 0鏈敓鏁�/1宸茬敓鏁�/2宸茬粨鏉�/3宸蹭綔搴�)',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏈�鍚庢洿鏂版椂闂�',
+ `deleted` tinyint NOT NULL DEFAULT '0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_period` (`period_type`,`period_value`) USING BTREE,
+ KEY `idx_dimension` (`target_dimension`,`target_user_id`,`target_dept_id`,`target_item_id`) USING BTREE,
+ KEY `idx_status` (`status`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='CRM 閿�鍞洰鏍�';
+
+-- ============ 琛細erp_account锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `erp_account`;
+CREATE TABLE `erp_account` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缁撶畻璐︽埛缂栧彿',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '璐︽埛鍚嶇О',
+ `no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '璐︽埛缂栫爜',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `status` int NOT NULL COMMENT '寮�鍚姸鎬�',
+ `sort` int NOT NULL COMMENT '鎺掑簭',
+ `default_status` tinyint(1) NOT NULL COMMENT '鏄惁榛樿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='ERP 缁撶畻璐︽埛';
+
+-- ============ 琛細erp_finance_payment锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `erp_finance_payment`;
+CREATE TABLE `erp_finance_payment` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '浠樻鍗曞彿',
+ `status` int NOT NULL COMMENT '浠樻鐘舵��',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宸ヤ綔娴佺紪鍙凤紝鍏宠仈 BPM 娴佺▼瀹炰緥',
+ `payment_time` datetime NOT NULL COMMENT '浠樻鏃堕棿',
+ `finance_user_id` bigint DEFAULT NULL COMMENT '璐㈠姟浜哄憳缂栧彿',
+ `supplier_id` bigint DEFAULT NULL COMMENT '渚涘簲鍟嗙紪鍙�',
+ `invoice_id` bigint DEFAULT NULL COMMENT '鍏宠仈鐨勬潵绁ㄧ紪鍙凤紝鍏宠仈 erp_purchase_invoice.id',
+ `account_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '浠樻璐︽埛',
+ `total_price` decimal(24,6) NOT NULL COMMENT '鍚堣浠锋牸锛屽崟浣嶏細鍏�',
+ `discount_price` decimal(24,6) NOT NULL COMMENT '浼樻儬閲戦锛屽崟浣嶏細鍏�',
+ `payment_price` decimal(24,6) NOT NULL COMMENT '瀹炰粯閲戦锛屽崟浣嶏細鍒�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='ERP 浠樻鍗�';
+
+-- ============ 琛細erp_finance_payment_item锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `erp_finance_payment_item`;
+CREATE TABLE `erp_finance_payment_item` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鍏ュ簱椤圭紪鍙�',
+ `payment_id` bigint DEFAULT NULL COMMENT '浠樻鍗曠紪鍙�',
+ `biz_type` int DEFAULT NULL COMMENT '涓氬姟绫诲瀷',
+ `biz_id` bigint DEFAULT NULL COMMENT '涓氬姟缂栧彿',
+ `biz_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '涓氬姟鍗曞彿',
+ `total_price` decimal(24,6) NOT NULL COMMENT '搴斾粯閲戦锛屽崟浣嶏細鍒�',
+ `paid_price` decimal(24,6) NOT NULL COMMENT '宸蹭粯閲戦锛屽崟浣嶏細鍒�',
+ `payment_price` decimal(24,6) NOT NULL COMMENT '鏈浠樻锛屽崟浣嶏細鍒�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='ERP 浠樻椤�';
+
+-- ============ 琛細erp_finance_receipt锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `erp_finance_receipt`;
+CREATE TABLE `erp_finance_receipt` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鏀舵鍗曞彿',
+ `status` int NOT NULL COMMENT '鏀舵鐘舵��',
+ `receipt_time` datetime NOT NULL COMMENT '鏀舵鏃堕棿',
+ `finance_user_id` bigint DEFAULT NULL COMMENT '璐㈠姟浜哄憳缂栧彿',
+ `customer_id` bigint DEFAULT NULL COMMENT '瀹㈡埛缂栧彿',
+ `account_id` bigint DEFAULT NULL COMMENT '鏀舵璐︽埛缂栧彿',
+ `total_price` decimal(24,6) NOT NULL COMMENT '鍚堣浠锋牸锛屽崟浣嶏細鍏�',
+ `discount_price` decimal(24,6) NOT NULL COMMENT '浼樻儬閲戦锛屽崟浣嶏細鍏�',
+ `receipt_price` decimal(24,6) NOT NULL COMMENT '瀹炴敹閲戦锛屽崟浣嶏細鍒�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='ERP 鏀舵鍗�';
+
+-- ============ 琛細erp_finance_receipt_item锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `erp_finance_receipt_item`;
+CREATE TABLE `erp_finance_receipt_item` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鍏ュ簱椤圭紪鍙�',
+ `receipt_id` bigint DEFAULT NULL COMMENT '鏀舵鍗曠紪鍙�',
+ `biz_type` int DEFAULT NULL COMMENT '涓氬姟绫诲瀷',
+ `biz_id` bigint DEFAULT NULL COMMENT '涓氬姟缂栧彿',
+ `biz_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '涓氬姟鍗曞彿',
+ `total_price` decimal(24,6) NOT NULL COMMENT '搴旀敹閲戦锛屽崟浣嶏細鍒�',
+ `receipted_price` decimal(24,6) NOT NULL COMMENT '宸叉敹閲戦锛屽崟浣嶏細鍒�',
+ `receipt_price` decimal(24,6) NOT NULL COMMENT '鏈鏀舵锛屽崟浣嶏細鍒�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='ERP 鏀舵椤�';
+
+-- ============ 琛細erp_purchase_invoice锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `erp_purchase_invoice`;
+CREATE TABLE `erp_purchase_invoice` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鏉ョエ缂栧彿',
+ `supplier_id` bigint NOT NULL COMMENT '渚涘簲鍟嗙紪鍙�',
+ `purchase_order_id` bigint NOT NULL COMMENT '閲囪喘璁㈠崟缂栧彿',
+ `invoice_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鍙戠エ鍙风爜',
+ `invoice_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鍙戠エ鎶ご',
+ `price` decimal(24,6) NOT NULL COMMENT '鏉ョエ閲戦锛屽崟浣嶏細鍏�',
+ `invoice_time` datetime NOT NULL COMMENT '鏉ョエ鏃ユ湡',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='閲囪喘鏉ョエ';
+
+-- ============ 琛細erp_purchase_order锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `erp_purchase_order`;
+CREATE TABLE `erp_purchase_order` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '閲囪喘璁㈠崟鍙�',
+ `status` int NOT NULL COMMENT '閲囪喘鐘舵��',
+ `supplier_id` bigint DEFAULT NULL COMMENT '渚涘簲鍟嗙紪鍙�',
+ `account_id` bigint DEFAULT NULL COMMENT '缁撶畻璐︽埛缂栧彿',
+ `order_time` datetime NOT NULL COMMENT '涓嬪崟鏃堕棿',
+ `total_count` decimal(24,6) NOT NULL COMMENT '鍚堣鏁伴噺',
+ `total_price` decimal(24,6) NOT NULL COMMENT '鏈�缁堝悎璁′环鏍硷紝鍗曚綅锛氬厓',
+ `total_product_price` decimal(24,6) NOT NULL COMMENT '鍚堣浜у搧浠锋牸锛屽崟浣嶏細鍏�',
+ `total_tax_price` decimal(24,6) NOT NULL COMMENT '鍚堣绋庨锛屽崟浣嶏細鍏�',
+ `discount_percent` decimal(24,6) NOT NULL COMMENT '浼樻儬鐜囷紝鐧惧垎姣�',
+ `discount_price` decimal(24,6) NOT NULL COMMENT '浼樻儬閲戦锛屽崟浣嶏細鍏�',
+ `deposit_price` decimal(24,6) NOT NULL COMMENT '瀹氶噾閲戦锛屽崟浣嶏細鍏�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `source_type` int DEFAULT NULL COMMENT '鏉ユ簮绫诲瀷',
+ `source_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏉ユ簮鍗曞彿',
+ `source_id` bigint DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'BPM 娴佺▼瀹炰緥缂栧彿',
+ `in_count` decimal(24,6) DEFAULT NULL COMMENT '閲囪喘鍏ュ簱鏁伴噺',
+ `return_count` decimal(24,6) DEFAULT NULL COMMENT '閲囪喘閫�璐ф暟閲�',
+ `in_status` tinyint DEFAULT '0' COMMENT '鍏ュ簱鐘舵�侊紙0:鏈叆搴� 1:閮ㄥ垎鍏ュ簱 2:鍏ㄩ儴鍏ュ簱锛�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='ERP 閲囪喘璁㈠崟';
+
+-- ============ 琛細erp_purchase_order_items锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `erp_purchase_order_items`;
+CREATE TABLE `erp_purchase_order_items` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `order_id` bigint DEFAULT NULL COMMENT '閲囪喘璁㈠崟缂栧彿',
+ `request_item_id` bigint DEFAULT NULL COMMENT '閲囪喘鐢宠鏄庣粏缂栧彿',
+ `product_id` bigint DEFAULT NULL COMMENT '浜у搧缂栧彿',
+ `product_unit_id` bigint DEFAULT NULL COMMENT '浜у搧鍗曚綅缂栧彿',
+ `product_price` decimal(24,6) NOT NULL COMMENT '浜у搧鍗曚綅鍗曚环锛屽崟浣嶏細鍏�',
+ `count` decimal(24,6) NOT NULL COMMENT '鏁伴噺',
+ `total_price` decimal(24,6) NOT NULL COMMENT '鎬讳环锛屽崟浣嶏細鍏�',
+ `tax_percent` decimal(24,6) DEFAULT NULL COMMENT '绋庣巼锛岀櫨鍒嗘瘮',
+ `tax_price` decimal(24,6) DEFAULT NULL COMMENT '绋庨锛屽崟浣嶏細鍏�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `in_count` decimal(24,6) DEFAULT NULL COMMENT '閲囪喘鍏ュ簱鏁伴噺',
+ `return_count` decimal(24,6) DEFAULT NULL COMMENT '閲囪喘閫�璐ф暟閲�',
+ `qc_check_flag` tinyint(1) DEFAULT '0' COMMENT '鏄惁闇�瑕佹潵鏂欐楠�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='ERP 閲囪喘璁㈠崟椤�';
+
+-- ============ 琛細erp_purchase_request锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `erp_purchase_request`;
+CREATE TABLE `erp_purchase_request` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '閲囪喘鐢宠鍗曞彿',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0:鏈彁浜� 10:瀹℃壒涓� 20:瀹℃牳閫氳繃 30:瀹℃牳涓嶉�氳繃 40:宸插彇娑堬級',
+ `request_user_id` bigint NOT NULL COMMENT '鐢宠浜虹紪鍙�',
+ `request_dept_id` bigint DEFAULT NULL COMMENT '鐢宠閮ㄩ棬缂栧彿',
+ `request_time` datetime NOT NULL COMMENT '鐢宠鏃堕棿',
+ `request_reason` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐢宠鐞嗙敱',
+ `supplier_id` bigint DEFAULT NULL COMMENT '渚涘簲鍟嗙紪鍙凤紙鍙�夛級',
+ `total_count` decimal(24,6) NOT NULL DEFAULT '0.000000' COMMENT '鍚堣鏁伴噺',
+ `total_price` decimal(24,6) NOT NULL DEFAULT '0.000000' COMMENT '鍚堣浠锋牸',
+ `total_product_price` decimal(24,6) NOT NULL DEFAULT '0.000000' COMMENT '鍚堣浜у搧浠锋牸',
+ `total_tax_price` decimal(24,6) NOT NULL DEFAULT '0.000000' COMMENT '鍚堣绋庨',
+ `discount_percent` decimal(24,6) DEFAULT '0.000000' COMMENT '浼樻儬鐜囷紝鐧惧垎姣�',
+ `discount_price` decimal(24,6) DEFAULT '0.000000' COMMENT '浼樻儬閲戦',
+ `deposit_price` decimal(24,6) DEFAULT '0.000000' COMMENT '瀹氶噾閲戦',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'BPM 娴佺▼瀹炰緥缂栧彿',
+ `order_id` bigint DEFAULT NULL COMMENT '鐢熸垚鐨勯噰璐鍗曠紪鍙�',
+ `order_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐢熸垚鐨勯噰璐鍗曞彿',
+ `in_status` tinyint DEFAULT '0' COMMENT '鍏ュ簱鐘舵�侊紙0:鏈叆搴� 1:閮ㄥ垎鍏ュ簱 2:鍏ㄩ儴鍏ュ簱锛�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_no` (`no`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='ERP 閲囪喘鐢宠琛�';
+
+-- ============ 琛細erp_purchase_request_items锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `erp_purchase_request_items`;
+CREATE TABLE `erp_purchase_request_items` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `request_id` bigint NOT NULL COMMENT '閲囪喘鐢宠缂栧彿',
+ `product_id` bigint NOT NULL COMMENT '浜у搧缂栧彿',
+ `product_unit_id` bigint DEFAULT NULL COMMENT '浜у搧鍗曚綅缂栧彿',
+ `product_price` decimal(24,6) DEFAULT NULL COMMENT '浜у搧鍙傝�冨崟浠�',
+ `count` decimal(24,6) NOT NULL COMMENT '鏁伴噺',
+ `total_price` decimal(24,6) DEFAULT NULL COMMENT '鎬讳环',
+ `tax_percent` decimal(24,6) DEFAULT NULL COMMENT '绋庣巼锛岀櫨鍒嗘瘮',
+ `tax_price` decimal(24,6) DEFAULT NULL COMMENT '绋庨',
+ `demand_time` datetime DEFAULT NULL COMMENT '闇�姹傛棩鏈�',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `qc_check_flag` tinyint DEFAULT '0' COMMENT '鏄惁闇�瑕佹潵鏂欐楠�',
+ `in_count` decimal(24,6) DEFAULT '0.000000' COMMENT '鍏ュ簱鏁伴噺',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_request_id` (`request_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='ERP 閲囪喘鐢宠鏄庣粏琛�';
+
+-- ============ 琛細erp_sale_order锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `erp_sale_order`;
+CREATE TABLE `erp_sale_order` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '閿�鍞鍗曞彿',
+ `status` int NOT NULL COMMENT '閿�鍞姸鎬�',
+ `customer_id` bigint DEFAULT NULL COMMENT '瀹㈡埛缂栧彿',
+ `contract_id` bigint DEFAULT NULL COMMENT '鍏宠仈 CRM 鍚堝悓缂栧彿',
+ `contract_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'CRM 鍚堝悓鍗曞彿',
+ `account_id` bigint DEFAULT NULL COMMENT '缁撶畻璐︽埛缂栧彿',
+ `sale_user_id` bigint DEFAULT NULL COMMENT '閿�鍞憳缂栧彿',
+ `order_time` datetime NOT NULL COMMENT '涓嬪崟鏃堕棿',
+ `total_count` decimal(24,6) NOT NULL COMMENT '鍚堣鏁伴噺',
+ `total_price` decimal(24,6) NOT NULL COMMENT '鏈�缁堝悎璁′环鏍硷紝鍗曚綅锛氬厓',
+ `total_product_price` decimal(24,6) NOT NULL COMMENT '鍚堣浜у搧浠锋牸锛屽崟浣嶏細鍏�',
+ `total_tax_price` decimal(24,6) NOT NULL COMMENT '鍚堣绋庨锛屽崟浣嶏細鍏�',
+ `discount_percent` decimal(24,6) NOT NULL COMMENT '浼樻儬鐜囷紝鐧惧垎姣�',
+ `discount_price` decimal(24,6) NOT NULL COMMENT '浼樻儬閲戦锛屽崟浣嶏細鍏�',
+ `deposit_price` decimal(24,6) NOT NULL DEFAULT '0.000000' COMMENT '瀹氶噾閲戦锛屽崟浣嶏細鍏�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'BPM 娴佺▼瀹炰緥缂栧彿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `out_count` decimal(24,6) DEFAULT '0.000000' COMMENT '閿�鍞嚭搴撴暟閲�',
+ `out_status` tinyint DEFAULT '0' COMMENT '鍑哄簱鐘舵�侊紙0:鏈嚭搴� 1:閮ㄥ垎鍑哄簱 2:鍏ㄩ儴鍏ュ簱锛�',
+ `production_status` tinyint DEFAULT '0' COMMENT '鐢熶骇鐘舵�侊細0-鏈畬鎴愶紝1-宸插畬鎴�',
+ `production_finish_time` datetime DEFAULT NULL COMMENT '鐢熶骇瀹屾垚鏃堕棿',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='ERP 閿�鍞鍗�';
+
+-- ============ 琛細erp_sale_order_items锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `erp_sale_order_items`;
+CREATE TABLE `erp_sale_order_items` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `order_id` bigint DEFAULT NULL COMMENT '閿�鍞鍗曠紪鍙�',
+ `product_id` bigint DEFAULT NULL COMMENT '浜у搧缂栧彿',
+ `product_unit_id` bigint DEFAULT NULL COMMENT '浜у搧鍗曚綅缂栧彿',
+ `product_price` decimal(24,6) NOT NULL COMMENT '浜у搧鍗曚綅鍗曚环锛屽崟浣嶏細鍏�',
+ `count` decimal(24,6) NOT NULL COMMENT '鏁伴噺',
+ `total_price` decimal(24,6) NOT NULL COMMENT '鎬讳环锛屽崟浣嶏細鍏�',
+ `tax_percent` decimal(24,6) DEFAULT NULL COMMENT '绋庣巼锛岀櫨鍒嗘瘮',
+ `tax_price` decimal(24,6) DEFAULT NULL COMMENT '绋庨锛屽崟浣嶏細鍏�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `out_count` decimal(24,6) DEFAULT '0.000000' COMMENT '閿�鍞嚭搴撴暟閲�',
+ `need_production` tinyint DEFAULT '0' COMMENT '鏄惁闇�瑕佺敓浜э紙0=鍚� 1=鏄級',
+ `mps_id` bigint DEFAULT NULL COMMENT '鍏宠仈鐨凪PS缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='ERP 閿�鍞鍗曢」';
+
+-- ============ 琛細erp_supplier锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `erp_supplier`;
+CREATE TABLE `erp_supplier` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '渚涘簲鍟嗙紪鍙�',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '渚涘簲鍟嗗悕绉�',
+ `contact` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑱旂郴浜�',
+ `mobile` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵嬫満鍙风爜',
+ `telephone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑱旂郴鐢佃瘽',
+ `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐢靛瓙閭',
+ `fax` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '浼犵湡',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `status` int NOT NULL COMMENT '寮�鍚姸鎬�',
+ `sort` int NOT NULL COMMENT '鎺掑簭',
+ `tax_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '绾崇◣浜鸿瘑鍒彿',
+ `tax_percent` decimal(24,6) DEFAULT NULL COMMENT '绋庣巼',
+ `bank_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '寮�鎴疯',
+ `bank_account` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '寮�鎴疯处鍙�',
+ `bank_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '寮�鎴峰湴鍧�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='ERP 渚涘簲鍟�';
+
+-- ============ 琛細flw_channel_definition锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `flw_channel_definition`;
+CREATE TABLE `flw_channel_definition` (
+ `ID_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+ `NAME_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+ `VERSION_` int DEFAULT NULL,
+ `KEY_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+ `CATEGORY_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+ `TYPE_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+ `IMPLEMENTATION_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+ `DEPLOYMENT_ID_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+ `CREATE_TIME_` datetime(3) DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+ `RESOURCE_NAME_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+ `DESCRIPTION_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+ PRIMARY KEY (`ID_`) USING BTREE,
+ UNIQUE KEY `ACT_IDX_CHANNEL_DEF_UNIQ` (`KEY_`,`VERSION_`,`TENANT_ID_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細flw_event_definition锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `flw_event_definition`;
+CREATE TABLE `flw_event_definition` (
+ `ID_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+ `NAME_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+ `VERSION_` int DEFAULT NULL,
+ `KEY_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+ `CATEGORY_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+ `DEPLOYMENT_ID_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+ `RESOURCE_NAME_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+ `DESCRIPTION_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+ PRIMARY KEY (`ID_`) USING BTREE,
+ UNIQUE KEY `ACT_IDX_EVENT_DEF_UNIQ` (`KEY_`,`VERSION_`,`TENANT_ID_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細flw_event_deployment锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `flw_event_deployment`;
+CREATE TABLE `flw_event_deployment` (
+ `ID_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+ `NAME_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+ `CATEGORY_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+ `DEPLOY_TIME_` datetime(3) DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+ `PARENT_DEPLOYMENT_ID_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+ PRIMARY KEY (`ID_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細flw_event_resource锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `flw_event_resource`;
+CREATE TABLE `flw_event_resource` (
+ `ID_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
+ `NAME_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+ `DEPLOYMENT_ID_` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
+ `RESOURCE_BYTES_` longblob,
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `FLW_IDX_EVENT_RSRC_DPL` (`DEPLOYMENT_ID_`) USING BTREE,
+ CONSTRAINT `FLW_FK_EVENT_RSRC_DPL` FOREIGN KEY (`DEPLOYMENT_ID_`) REFERENCES `flw_event_deployment` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細flw_ru_batch锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `flw_ru_batch`;
+CREATE TABLE `flw_ru_batch` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `TYPE_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `SEARCH_KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SEARCH_KEY2_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CREATE_TIME_` datetime(3) NOT NULL,
+ `COMPLETE_TIME_` datetime(3) DEFAULT NULL,
+ `STATUS_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `BATCH_DOC_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '',
+ PRIMARY KEY (`ID_`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細flw_ru_batch_part锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `flw_ru_batch_part`;
+CREATE TABLE `flw_ru_batch_part` (
+ `ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `REV_` int DEFAULT NULL,
+ `BATCH_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TYPE_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
+ `SCOPE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SUB_SCOPE_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SCOPE_TYPE_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SEARCH_KEY_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `SEARCH_KEY2_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `CREATE_TIME_` datetime(3) NOT NULL,
+ `COMPLETE_TIME_` datetime(3) DEFAULT NULL,
+ `STATUS_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `RESULT_DOC_ID_` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT NULL,
+ `TENANT_ID_` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '',
+ PRIMARY KEY (`ID_`) USING BTREE,
+ KEY `FLW_IDX_BATCH_PART` (`BATCH_ID_`) USING BTREE,
+ CONSTRAINT `FLW_FK_BATCH_PART_PARENT` FOREIGN KEY (`BATCH_ID_`) REFERENCES `flw_ru_batch` (`ID_`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細hrm_attendance_exception锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_attendance_exception`;
+CREATE TABLE `hrm_attendance_exception` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鐢宠ID',
+ `no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐢宠鍗曞彿',
+ `user_id` bigint NOT NULL COMMENT '鐢宠浜篒D',
+ `dept_id` bigint NOT NULL COMMENT '閮ㄩ棬ID',
+ `type` tinyint NOT NULL COMMENT '寮傚父绫诲瀷锛�1-琛ュ崱锛�2-鍔犵彮锛�3-鍑哄樊',
+ `exception_date` date NOT NULL COMMENT '寮傚父鏃ユ湡',
+ `exception_time` datetime DEFAULT NULL COMMENT '寮傚父鏃堕棿鐐�',
+ `reason` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐢宠鍘熷洜',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊細0-鑽夌锛�10-瀹℃壒涓紝20-閫氳繃锛�30-椹冲洖锛�40-鎾ら攢',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'BPM娴佺▼瀹炰緥ID',
+ `approve_time` datetime DEFAULT NULL COMMENT '瀹℃壒瀹屾垚鏃堕棿',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_no` (`no`) USING BTREE,
+ KEY `idx_user_status` (`user_id`,`status`) USING BTREE,
+ KEY `idx_dept_date` (`dept_id`,`exception_date`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM鑰冨嫟寮傚父鐢宠琛�';
+
+-- ============ 琛細hrm_attendance_holiday锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_attendance_holiday`;
+CREATE TABLE `hrm_attendance_holiday` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鑺傚亣鏃D',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鑺傚亣鏃ュ悕绉�',
+ `date` date NOT NULL COMMENT '鏃ユ湡',
+ `type` tinyint NOT NULL DEFAULT '1' COMMENT '绫诲瀷锛�1-浼戞伅鏃ワ紝2-宸ヤ綔鏃�',
+ `is_legal` tinyint NOT NULL DEFAULT '0' COMMENT '鏄惁娉曞畾鑺傚亣鏃ワ細0-鍚︼紝1-鏄�',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_date` (`date`,`deleted`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM鑰冨嫟鑺傚亣鏃ラ厤缃〃';
+
+-- ============ 琛細hrm_attendance_record锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_attendance_record`;
+CREATE TABLE `hrm_attendance_record` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '璁板綍ID',
+ `user_id` bigint NOT NULL COMMENT '鍛樺伐ID',
+ `dept_id` bigint NOT NULL COMMENT '閮ㄩ棬ID',
+ `date` date NOT NULL COMMENT '鑰冨嫟鏃ユ湡',
+ `clock_in_time` datetime DEFAULT NULL COMMENT '涓婄彮鎵撳崱鏃堕棿',
+ `clock_out_time` datetime DEFAULT NULL COMMENT '涓嬬彮鎵撳崱鏃堕棿',
+ `clock_in_type` tinyint DEFAULT NULL COMMENT '涓婄彮鎵撳崱绫诲瀷锛�1-姝e父锛�2-杩熷埌锛�3-缂哄崱',
+ `clock_out_type` tinyint DEFAULT NULL COMMENT '涓嬬彮鎵撳崱绫诲瀷锛�1-姝e父锛�2-鏃╅��锛�3-缂哄崱',
+ `work_hours` decimal(4,2) DEFAULT NULL COMMENT '宸ヤ綔鏃堕暱锛堝皬鏃讹級',
+ `overtime_hours` decimal(4,2) DEFAULT '0.00' COMMENT '鍔犵彮鏃堕暱锛堝皬鏃讹級',
+ `location` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵撳崱鍦扮偣',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `data_source` tinyint DEFAULT '1' COMMENT '鏁版嵁鏉ユ簮锛�1-鎵撳崱锛�2-瀵煎叆',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_user_date` (`user_id`,`date`) USING BTREE,
+ KEY `idx_dept_date` (`dept_id`,`date`) USING BTREE,
+ KEY `idx_create_time` (`create_time`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM鑰冨嫟鎵撳崱璁板綍琛�';
+
+-- ============ 琛細hrm_attendance_rule锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_attendance_rule`;
+CREATE TABLE `hrm_attendance_rule` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '瑙勫垯ID',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '瑙勫垯鍚嶇О',
+ `dept_id` bigint DEFAULT NULL COMMENT '閫傜敤閮ㄩ棬ID锛堢┖琛ㄧず鍏ㄥ眬锛�',
+ `work_start_time` time NOT NULL COMMENT '涓婄彮鏃堕棿',
+ `work_end_time` time NOT NULL COMMENT '涓嬬彮鏃堕棿',
+ `late_allow_minutes` tinyint DEFAULT '0' COMMENT '杩熷埌鍏佽鍒嗛挓鏁�',
+ `early_allow_minutes` tinyint DEFAULT '0' COMMENT '鏃╅��鍏佽鍒嗛挓鏁�',
+ `overtime_threshold` decimal(4,2) DEFAULT '1.00' COMMENT '鍔犵彮璧风畻鏃堕暱锛堝皬鏃讹級',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊細0-鍚敤锛�1-绂佺敤',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_dept_id` (`dept_id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM鑰冨嫟瑙勫垯閰嶇疆琛�';
+
+-- ============ 琛細hrm_attendance_summary锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_attendance_summary`;
+CREATE TABLE `hrm_attendance_summary` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '姹囨�籌D',
+ `user_id` bigint NOT NULL COMMENT '鍛樺伐ID',
+ `dept_id` bigint NOT NULL COMMENT '閮ㄩ棬ID',
+ `year_month` varchar(7) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '骞存湀锛屾牸寮忥細yyyy-MM',
+ `work_days` int NOT NULL DEFAULT '0' COMMENT '搴斿嚭鍕ゅぉ鏁�',
+ `actual_days` int NOT NULL DEFAULT '0' COMMENT '瀹為檯鍑哄嫟澶╂暟',
+ `late_count` int NOT NULL DEFAULT '0' COMMENT '杩熷埌娆℃暟',
+ `early_count` int NOT NULL DEFAULT '0' COMMENT '鏃╅��娆℃暟',
+ `absent_count` int NOT NULL DEFAULT '0' COMMENT '缂哄崱娆℃暟',
+ `overtime_hours` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '鍔犵彮鏃堕暱锛堝皬鏃讹級',
+ `leave_hours` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '璇峰亣鏃堕暱锛堝皬鏃讹級',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_user_year_month` (`user_id`,`year_month`,`deleted`) USING BTREE,
+ KEY `idx_dept_year_month` (`dept_id`,`year_month`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM鑰冨嫟缁熻姹囨�昏〃';
+
+-- ============ 琛細hrm_employee锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_employee`;
+CREATE TABLE `hrm_employee` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鍛樺伐ID',
+ `user_id` bigint DEFAULT NULL COMMENT '绯荤粺鐢ㄦ埛id',
+ `dept_id` bigint NOT NULL COMMENT '閮ㄩ棬ID',
+ `post_id` bigint DEFAULT NULL COMMENT '宀椾綅ID',
+ `post_ids` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宀椾綅ID鍒楄〃锛圝SON鏍煎紡锛�',
+ `employee_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍛樺伐缂栧彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍛樺伐濮撳悕',
+ `gender` tinyint DEFAULT NULL COMMENT '鎬у埆锛�1-鐢凤紝2-濂�',
+ `birthday` date DEFAULT NULL COMMENT '鍑虹敓鏃ユ湡',
+ `phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵嬫満鍙风爜',
+ `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閭',
+ `id_card` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '韬唤璇佸彿',
+ `nation` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '姘戞棌',
+ `marriage_status` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '濠氬Щ鐘舵��',
+ `age` int DEFAULT NULL COMMENT '骞撮緞',
+ `education` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瀛﹀巻',
+ `political_status` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏀挎不闈㈣矊',
+ `hire_date` date NOT NULL COMMENT '鍏ヨ亴鏃ユ湡',
+ `regular_date` date DEFAULT NULL COMMENT '杞鏃ユ湡',
+ `leave_date` date DEFAULT NULL COMMENT '绂昏亴鏃ユ湡',
+ `employee_status` tinyint NOT NULL DEFAULT '1' COMMENT '鍛樺伐鐘舵�侊細1-鍦ㄨ亴锛�2-璇曠敤锛�3-绂昏亴',
+ `annual_leave_balance` decimal(4,2) DEFAULT '0.00' COMMENT '骞村亣浣欓锛堝ぉ锛�',
+ `sick_leave_balance` decimal(4,2) DEFAULT '0.00' COMMENT '鐥呭亣浣欓锛堝ぉ锛�',
+ `salary_structure_id` bigint DEFAULT NULL COMMENT '钖叕缁撴瀯ID',
+ `base_salary` decimal(12,2) DEFAULT NULL COMMENT '鍩烘湰宸ヨ祫',
+ `role_ids` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瑙掕壊ID鍒楄〃锛圝SON鏍煎紡锛�',
+ `bank_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '寮�鎴烽摱琛�',
+ `bank_account` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閾惰璐﹀彿',
+ `address` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '灞呬綇鍦板潃',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_employee_no` (`employee_no`) USING BTREE,
+ UNIQUE KEY `uk_phone` (`phone`) USING BTREE,
+ KEY `idx_dept_id` (`dept_id`) USING BTREE,
+ KEY `idx_employee_status` (`employee_status`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM鍛樺伐淇℃伅琛�';
+
+-- ============ 琛細hrm_employee_contract锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_employee_contract`;
+CREATE TABLE `hrm_employee_contract` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鍚堝悓ID',
+ `parent_id` bigint DEFAULT NULL COMMENT '缁涓婁竴浠藉悎鍚孖D',
+ `is_current` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁褰撳墠鐢熸晥鍚堝悓',
+ `contract_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍚堝悓缂栧彿',
+ `employee_id` bigint NOT NULL COMMENT '鍛樺伐ID',
+ `contract_type` tinyint NOT NULL COMMENT '鍚堝悓绫诲瀷锛�1-鍔冲姩鍚堝悓锛�2-鍔冲姟鍚堝悓锛�3-瀹炰範鍗忚锛�4-鍔冲姟娲鹃仯锛�5-鍏朵粬',
+ `contract_term_type` tinyint NOT NULL COMMENT '鍚堝悓鏈熼檺绫诲瀷锛�1-鍥哄畾鏈熼檺锛�2-鏃犲浐瀹氭湡闄愶紝3-浠ュ畬鎴愪竴瀹氬伐浣滀换鍔′负鏈熼檺',
+ `sign_company` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '绛剧害涓讳綋锛堝叕鍙稿叏绉帮級',
+ `sign_date` date DEFAULT NULL COMMENT '绛捐鏃ユ湡',
+ `start_date` date NOT NULL COMMENT '鍚堝悓寮�濮嬫棩鏈�',
+ `end_date` date DEFAULT NULL COMMENT '鍚堝悓缁撴潫鏃ユ湡锛堟棤鍥哄畾鏈熼檺鍙负绌猴級',
+ `probation_start_date` date DEFAULT NULL COMMENT '璇曠敤鏈熷紑濮嬫棩鏈�',
+ `probation_end_date` date DEFAULT NULL COMMENT '璇曠敤鏈熺粨鏉熸棩鏈�',
+ `probation_salary` decimal(10,2) DEFAULT NULL COMMENT '璇曠敤鏈熷伐璧�',
+ `regular_salary` decimal(10,2) DEFAULT NULL COMMENT '杞宸ヨ祫',
+ `terminate_status` tinyint NOT NULL DEFAULT '0' COMMENT '瑙i櫎/缁堟鐘舵�侊細0-姝e父锛�1-宸茶В闄わ紝2-宸茬粓姝�',
+ `terminate_date` date DEFAULT NULL COMMENT '瑙i櫎/缁堟鏃ユ湡',
+ `terminate_reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瑙i櫎/缁堟鍘熷洜',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_contract_no` (`contract_no`) USING BTREE,
+ KEY `idx_employee_id` (`employee_id`) USING BTREE,
+ KEY `idx_end_date` (`end_date`) USING BTREE,
+ KEY `idx_terminate_status` (`terminate_status`) USING BTREE,
+ KEY `idx_parent_id` (`parent_id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM鍛樺伐鍚堝悓琛�';
+
+-- ============ 琛細hrm_employee_education锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_employee_education`;
+CREATE TABLE `hrm_employee_education` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '璁板綍ID',
+ `employee_id` bigint NOT NULL COMMENT '鍛樺伐ID',
+ `school_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '瀛︽牎鍚嶇О',
+ `major` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '涓撲笟',
+ `degree` tinyint NOT NULL COMMENT '瀛﹀巻锛�1-楂樹腑锛�2-澶т笓锛�3-鏈锛�4-纭曞+锛�5-鍗氬+',
+ `start_date` date NOT NULL COMMENT '鍏ュ鏃堕棿',
+ `end_date` date NOT NULL COMMENT '姣曚笟鏃堕棿',
+ `certificate_no` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璇佷功缂栧彿',
+ `remark` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_employee_id` (`employee_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM鍛樺伐鏁欒偛缁忓巻琛�';
+
+-- ============ 琛細hrm_employee_emergency_contact锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_employee_emergency_contact`;
+CREATE TABLE `hrm_employee_emergency_contact` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '璁板綍ID',
+ `employee_id` bigint NOT NULL COMMENT '鍛樺伐ID',
+ `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鑱旂郴浜哄鍚�',
+ `relationship` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '涓庡憳宸ュ叧绯�',
+ `phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鑱旂郴鐢佃瘽',
+ `address` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑱旂郴鍦板潃',
+ `sort` tinyint DEFAULT '1' COMMENT '鎺掑簭锛堝彲璁剧疆澶氫釜绱ф�ヨ仈绯讳汉锛�',
+ `remark` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_employee_id` (`employee_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM鍛樺伐绱ф�ヨ仈绯讳汉琛�';
+
+-- ============ 琛細hrm_employee_salary锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_employee_salary`;
+CREATE TABLE `hrm_employee_salary` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '妗fID',
+ `user_id` bigint NOT NULL COMMENT '鍛樺伐ID',
+ `salary_structure_id` bigint NOT NULL COMMENT '钖叕缁撴瀯ID',
+ `base_salary` decimal(12,2) NOT NULL COMMENT '鍩烘湰宸ヨ祫',
+ `performance_salary` decimal(12,2) DEFAULT NULL COMMENT '缁╂晥宸ヨ祫',
+ `meal_allowance` decimal(12,2) DEFAULT '0.00' COMMENT '椁愯ˉ',
+ `transport_allowance` decimal(12,2) DEFAULT '0.00' COMMENT '浜ら�氳ˉ璐�',
+ `other_allowance` decimal(12,2) DEFAULT '0.00' COMMENT '鍏朵粬琛ヨ创',
+ `effective_date` date NOT NULL COMMENT '鐢熸晥鏃ユ湡',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊細0-鍚敤锛�1-绂佺敤',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_user_effective` (`user_id`,`effective_date`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM鍛樺伐钖叕妗f琛�';
+
+-- ============ 琛細hrm_employee_schedule锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_employee_schedule`;
+CREATE TABLE `hrm_employee_schedule` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鎺掔彮ID',
+ `employee_id` bigint NOT NULL COMMENT '鍛樺伐ID锛屽叧鑱� hrm_employee.id',
+ `date` date NOT NULL COMMENT '鎺掔彮鏃ユ湡',
+ `shift_id` bigint DEFAULT NULL COMMENT '鐝ID锛屽叧鑱� hrm_shift.id锛屼负绌鸿〃绀轰紤鎭�',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_employee_date` (`employee_id`,`date`) USING BTREE,
+ KEY `idx_date` (`date`) USING BTREE,
+ KEY `idx_shift_id` (`shift_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM鍛樺伐鎺掔彮鏄庣粏琛�';
+
+-- ============ 琛細hrm_employee_social_security锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_employee_social_security`;
+CREATE TABLE `hrm_employee_social_security` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '妗fID',
+ `user_id` bigint NOT NULL COMMENT '绯荤粺鐢ㄦ埛ID',
+ `social_security_scheme_id` bigint NOT NULL COMMENT '绀句繚鍏Н閲戞柟妗圛D',
+ `social_security_base` decimal(12,2) NOT NULL COMMENT '绀句繚缂寸撼鍩烘暟',
+ `housing_fund_base` decimal(12,2) NOT NULL COMMENT '鍏Н閲戠即绾冲熀鏁�',
+ `effective_date` date NOT NULL COMMENT '鐢熸晥鏃ユ湡',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊細0-鍚敤锛�1-绂佺敤',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_user_effective` (`user_id`,`effective_date`) USING BTREE,
+ KEY `idx_user_id` (`user_id`) USING BTREE,
+ KEY `idx_scheme_id` (`social_security_scheme_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM鍛樺伐绀句繚鍏Н閲戞。妗堣〃';
+
+-- ============ 琛細hrm_employee_work_history锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_employee_work_history`;
+CREATE TABLE `hrm_employee_work_history` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '璁板綍ID',
+ `employee_id` bigint NOT NULL COMMENT '鍛樺伐ID',
+ `company_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍏徃鍚嶇О',
+ `position` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鑱屼綅',
+ `start_date` date NOT NULL COMMENT '鍏ヨ亴鏃堕棿',
+ `end_date` date DEFAULT NULL COMMENT '绂昏亴鏃堕棿',
+ `work_content` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宸ヤ綔鍐呭',
+ `leave_reason` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '绂昏亴鍘熷洜',
+ `reference_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璇佹槑浜哄鍚�',
+ `reference_phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璇佹槑浜虹數璇�',
+ `remark` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_employee_id` (`employee_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM鍛樺伐宸ヤ綔缁忓巻琛�';
+
+-- ============ 琛細hrm_leave_application锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_leave_application`;
+CREATE TABLE `hrm_leave_application` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鐢宠ID',
+ `no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐢宠鍗曞彿',
+ `user_id` bigint NOT NULL COMMENT '鐢宠浜篒D',
+ `dept_id` bigint NOT NULL COMMENT '閮ㄩ棬ID',
+ `leave_type` tinyint NOT NULL COMMENT '璇峰亣绫诲瀷锛�1-浜嬪亣锛�2-鐥呭亣锛�3-骞村亣锛�4-濠氬亣锛�5-浜у亣锛�6-涓у亣',
+ `start_time` datetime NOT NULL COMMENT '寮�濮嬫椂闂�',
+ `end_time` datetime NOT NULL COMMENT '缁撴潫鏃堕棿',
+ `duration` decimal(4,2) NOT NULL COMMENT '璇峰亣鏃堕暱锛堝ぉ锛�',
+ `reason` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '璇峰亣鍘熷洜',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊細0-鑽夌锛�10-瀹℃壒涓紝20-閫氳繃锛�30-椹冲洖锛�40-鎾ら攢',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'BPM娴佺▼瀹炰緥ID',
+ `approve_time` datetime DEFAULT NULL COMMENT '瀹℃壒瀹屾垚鏃堕棿',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_no` (`no`) USING BTREE,
+ KEY `idx_user_status` (`user_id`,`status`) USING BTREE,
+ KEY `idx_dept_time` (`dept_id`,`start_time`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM璇峰亣鐢宠琛�';
+
+-- ============ 琛細hrm_leave_type_config锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_leave_type_config`;
+CREATE TABLE `hrm_leave_type_config` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `leave_type` int NOT NULL COMMENT '璇峰亣绫诲瀷锛�1-浜嬪亣, 2-鐥呭亣, 3-骞村亣, 4-濠氬亣, 5-浜у亣, 6-涓у亣',
+ `name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '绫诲瀷鍚嶇О',
+ `deduction_ratio` decimal(5,4) NOT NULL DEFAULT '0.0000' COMMENT '鎵f姣斾緥锛�0-1涔嬮棿锛屽0.5琛ㄧず鎵�50%锛�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞',
+ `status` int NOT NULL DEFAULT '0' COMMENT '鐘舵�侊細0-鍚敤, 1-绂佺敤',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鍒涘缓浜�',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鏇存柊浜�',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='璇峰亣绫诲瀷鎵f閰嶇疆';
+
+-- ============ 琛細hrm_overtime_application锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_overtime_application`;
+CREATE TABLE `hrm_overtime_application` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鐢宠ID',
+ `no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐢宠鍗曞彿',
+ `user_id` bigint NOT NULL COMMENT '绯荤粺鐢ㄦ埛ID',
+ `employee_id` bigint NOT NULL COMMENT '鍛樺伐ID',
+ `dept_id` bigint NOT NULL COMMENT '閮ㄩ棬ID',
+ `overtime_date` date NOT NULL COMMENT '鍔犵彮鏃ユ湡',
+ `start_time` time NOT NULL COMMENT '寮�濮嬫椂闂�',
+ `end_time` time NOT NULL COMMENT '缁撴潫鏃堕棿',
+ `duration` decimal(6,1) NOT NULL COMMENT '鎵i櫎鐢ㄩ鍚庣殑鍔犵彮鏃堕暱锛�0.5灏忔椂鍙栨暣锛�',
+ `overtime_type` tinyint NOT NULL COMMENT '1-宸ヤ綔鏃ワ紝2-浼戞伅鏃ワ紝3-娉曞畾鑺傚亣鏃�',
+ `cross_day` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁璺ㄥぉ',
+ `meal_deduction` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鎵i櫎鐢ㄩ鏃堕棿',
+ `meal_deduction_hours` decimal(4,1) NOT NULL DEFAULT '0.0' COMMENT '鐢ㄩ鎵i櫎灏忔椂鏁�',
+ `reason` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍔犵彮鍘熷洜',
+ `related_type` tinyint DEFAULT NULL COMMENT '鍏宠仈绫诲瀷锛�1-椤圭洰锛�2-宸ュ崟',
+ `related_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '椤圭洰/宸ュ崟缂栧彿',
+ `work_content` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宸ヤ綔鍐呭绠�杩�',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '0-鑽夌锛�10-瀹℃壒涓紝20-閫氳繃锛�30-椹冲洖锛�40-鎾ら攢',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍗忓悓鍔炲叕娴佺▼瀹炰緥ID',
+ `approve_time` datetime DEFAULT NULL COMMENT '瀹℃壒瀹屾垚鏃堕棿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_hrm_overtime_no` (`no`) USING BTREE,
+ KEY `idx_hrm_overtime_user_date_status` (`user_id`,`overtime_date`,`status`) USING BTREE,
+ KEY `idx_hrm_overtime_process_instance` (`process_instance_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM鍔犵彮鐢宠琛�';
+
+-- ============ 琛細hrm_resignation_application锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_resignation_application`;
+CREATE TABLE `hrm_resignation_application` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鐢宠ID',
+ `no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐢宠鍗曞彿',
+ `user_id` bigint NOT NULL COMMENT '鐢宠浜篒D',
+ `dept_id` bigint NOT NULL COMMENT '閮ㄩ棬ID',
+ `resignation_type` tinyint NOT NULL COMMENT '绂昏亴绫诲瀷锛�1-涓诲姩绂昏亴锛�2-琚姩绂昏亴锛�3-鍚堝悓鍒版湡',
+ `expected_date` date NOT NULL COMMENT '棰勮绂昏亴鏃ユ湡',
+ `actual_date` date DEFAULT NULL COMMENT '瀹為檯绂昏亴鏃ユ湡',
+ `reason` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '绂昏亴鍘熷洜',
+ `handover_user_id` bigint DEFAULT NULL COMMENT '浜ゆ帴浜篒D',
+ `handover_status` tinyint DEFAULT '0' COMMENT '浜ゆ帴鐘舵�侊細0-鏈紑濮嬶紝10-杩涜涓紝20-宸插畬鎴�',
+ `handover_remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '浜ゆ帴璇存槑',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊細0-鑽夌锛�10-瀹℃壒涓紝20-閫氳繃锛�30-椹冲洖锛�40-鎾ら攢',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'BPM娴佺▼瀹炰緥ID',
+ `approve_time` datetime DEFAULT NULL COMMENT '瀹℃壒瀹屾垚鏃堕棿',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_no` (`no`) USING BTREE,
+ KEY `idx_user_status` (`user_id`,`status`) USING BTREE,
+ KEY `idx_dept_time` (`dept_id`,`expected_date`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM绂昏亴鐢宠琛�';
+
+-- ============ 琛細hrm_salary_calculation锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_salary_calculation`;
+CREATE TABLE `hrm_salary_calculation` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鏍哥畻ID',
+ `no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鏍哥畻鍗曞彿',
+ `period` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鏍哥畻鍛ㄦ湡锛堝2024-01锛�',
+ `user_id` bigint NOT NULL COMMENT '鍛樺伐ID',
+ `dept_id` bigint NOT NULL COMMENT '閮ㄩ棬ID',
+ `base_salary` decimal(12,2) NOT NULL COMMENT '鍩烘湰宸ヨ祫',
+ `performance_salary` decimal(12,2) DEFAULT NULL COMMENT '缁╂晥宸ヨ祫',
+ `overtime_pay` decimal(12,2) DEFAULT '0.00' COMMENT '鍔犵彮宸ヨ祫',
+ `meal_allowance` decimal(12,2) DEFAULT '0.00' COMMENT '椁愯ˉ',
+ `transport_allowance` decimal(12,2) DEFAULT '0.00' COMMENT '浜ら�氳ˉ璐�',
+ `other_allowance` decimal(12,2) DEFAULT '0.00' COMMENT '鍏朵粬琛ヨ创',
+ `social_security_deduction` decimal(12,2) DEFAULT NULL COMMENT '绀句繚鎵i櫎',
+ `housing_fund_deduction` decimal(12,2) DEFAULT NULL COMMENT '鍏Н閲戞墸闄�',
+ `tax_deduction` decimal(12,2) DEFAULT NULL COMMENT '涓◣鎵i櫎',
+ `other_deduction` decimal(12,2) DEFAULT '0.00' COMMENT '鍏朵粬鎵i櫎',
+ `leave_deduction` decimal(10,2) DEFAULT '0.00' COMMENT '璇峰亣鎵f',
+ `actual_salary` decimal(12,2) NOT NULL COMMENT '瀹炲彂宸ヨ祫',
+ `work_days` tinyint DEFAULT NULL COMMENT '鍑哄嫟澶╂暟',
+ `overtime_hours` decimal(4,2) DEFAULT NULL COMMENT '鍔犵彮鏃堕暱',
+ `total_work_hours` decimal(8,2) DEFAULT NULL COMMENT '鎺掔彮鎬诲伐鏃讹紙灏忔椂锛�',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊細0-寰呯‘璁わ紝10-宸茬‘璁わ紝20-宸插彂鏀�',
+ `confirm_time` datetime DEFAULT NULL COMMENT '纭鏃堕棿',
+ `confirm_user_id` bigint DEFAULT NULL COMMENT '纭浜篒D',
+ `payment_time` datetime DEFAULT NULL COMMENT '鍙戞斁鏃堕棿',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_no` (`no`) USING BTREE,
+ KEY `idx_user_period` (`user_id`,`period`) USING BTREE,
+ KEY `idx_dept_period` (`dept_id`,`period`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM钖叕鏍哥畻璁板綍琛�';
+
+-- ============ 琛細hrm_salary_payment锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_salary_payment`;
+CREATE TABLE `hrm_salary_payment` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鍙戞斁ID',
+ `no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍙戞斁鍗曞彿',
+ `period` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍙戞斁鍛ㄦ湡',
+ `total_amount` decimal(14,2) DEFAULT NULL COMMENT '鍙戞斁鎬婚噾棰�',
+ `total_count` int DEFAULT NULL COMMENT '鍙戞斁浜烘暟',
+ `payment_method` tinyint DEFAULT NULL COMMENT '鍙戞斁鏂瑰紡锛�1-閾惰杞处锛�2-鐜伴噾',
+ `payment_time` datetime DEFAULT NULL COMMENT '鍙戞斁鏃堕棿',
+ `status` tinyint DEFAULT '0' COMMENT '鐘舵�侊細0-寰呭彂鏀撅紝10-宸插彂鏀�',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_no` (`no`) USING BTREE,
+ KEY `idx_period` (`period`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM钖祫鍙戞斁鍙拌处琛�';
+
+-- ============ 琛細hrm_salary_payment_detail锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_salary_payment_detail`;
+CREATE TABLE `hrm_salary_payment_detail` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `payment_id` bigint NOT NULL COMMENT '鍙戞斁鍙拌处ID',
+ `calculation_id` bigint NOT NULL COMMENT '钖叕鏍哥畻ID',
+ `user_id` bigint NOT NULL COMMENT '鍛樺伐ID',
+ `dept_id` bigint DEFAULT NULL COMMENT '閮ㄩ棬ID',
+ `actual_salary` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '瀹炲彂宸ヨ祫',
+ `status` int NOT NULL DEFAULT '0' COMMENT '鍙戞斁鐘舵�侊細0-寰呭彂鏀撅紝10-宸插彂鏀�',
+ `payment_time` datetime DEFAULT NULL COMMENT '鍙戞斁鏃堕棿',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓浜�',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊浜�',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_payment_id` (`payment_id`) USING BTREE,
+ KEY `idx_calculation_id` (`calculation_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='钖祫鍙戞斁鏄庣粏';
+
+-- ============ 琛細hrm_salary_structure锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_salary_structure`;
+CREATE TABLE `hrm_salary_structure` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缁撴瀯ID',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '缁撴瀯鍚嶇О',
+ `base_salary` decimal(12,2) NOT NULL COMMENT '鍩烘湰宸ヨ祫',
+ `performance_ratio` decimal(4,2) DEFAULT '0.00' COMMENT '缁╂晥宸ヨ祫鍗犳瘮锛�%锛�',
+ `overtime_pay_ratio` decimal(4,2) DEFAULT '1.50' COMMENT '鍔犵彮宸ヨ祫鍊嶇巼',
+ `rest_day_overtime_pay_ratio` decimal(4,2) DEFAULT '2.00' COMMENT '浼戞伅鏃ュ姞鐝伐璧勫�嶇巼',
+ `legal_holiday_overtime_pay_ratio` decimal(4,2) DEFAULT '3.00' COMMENT '娉曞畾鑺傚亣鏃ュ姞鐝伐璧勫�嶇巼',
+ `social_security_base` decimal(12,2) DEFAULT NULL COMMENT '绀句繚鍩烘暟',
+ `housing_fund_base` decimal(12,2) DEFAULT NULL COMMENT '鍏Н閲戝熀鏁�',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊細0-鍚敤锛�1-绂佺敤',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM钖叕缁撴瀯琛�';
+
+-- ============ 琛細hrm_shift锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_shift`;
+CREATE TABLE `hrm_shift` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鐝ID',
+ `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐝鍚嶇О',
+ `start_time` time NOT NULL COMMENT '涓婄彮鏃堕棿',
+ `end_time` time NOT NULL COMMENT '涓嬬彮鏃堕棿',
+ `work_hours` decimal(5,2) DEFAULT NULL COMMENT '鏍囧噯宸ユ椂锛堝皬鏃讹級',
+ `cross_day` tinyint(1) NOT NULL DEFAULT '0' COMMENT '鏄惁璺ㄥぉ',
+ `color` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏍囩棰滆壊锛堝崄鍏繘鍒讹級',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊細0-鍚敤锛�1-绂佺敤',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_status` (`status`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM鐝瀹氫箟琛�';
+
+-- ============ 琛細hrm_social_security_scheme锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_social_security_scheme`;
+CREATE TABLE `hrm_social_security_scheme` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鏂规ID',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鏂规鍚嶇О',
+ `effective_date` date NOT NULL COMMENT '鐢熸晥鏃ユ湡',
+ `pension_company_ratio` decimal(5,4) NOT NULL DEFAULT '0.1600' COMMENT '鍏昏�佷繚闄╀紒涓氱即绾虫瘮渚�',
+ `pension_personal_ratio` decimal(5,4) NOT NULL DEFAULT '0.0800' COMMENT '鍏昏�佷繚闄╀釜浜虹即绾虫瘮渚�',
+ `medical_company_ratio` decimal(5,4) NOT NULL DEFAULT '0.0950' COMMENT '鍖荤枟淇濋櫓浼佷笟缂寸撼姣斾緥',
+ `medical_personal_ratio` decimal(5,4) NOT NULL DEFAULT '0.0200' COMMENT '鍖荤枟淇濋櫓涓汉缂寸撼姣斾緥',
+ `unemployment_company_ratio` decimal(5,4) NOT NULL DEFAULT '0.0050' COMMENT '澶变笟淇濋櫓浼佷笟缂寸撼姣斾緥',
+ `unemployment_personal_ratio` decimal(5,4) NOT NULL DEFAULT '0.0050' COMMENT '澶变笟淇濋櫓涓汉缂寸撼姣斾緥',
+ `work_injury_ratio` decimal(5,4) NOT NULL DEFAULT '0.0050' COMMENT '宸ヤ激淇濋櫓浼佷笟缂寸撼姣斾緥',
+ `maternity_ratio` decimal(5,4) NOT NULL DEFAULT '0.0050' COMMENT '鐢熻偛淇濋櫓浼佷笟缂寸撼姣斾緥',
+ `housing_fund_company_ratio` decimal(5,4) NOT NULL DEFAULT '0.1200' COMMENT '鍏Н閲戜紒涓氱即绾虫瘮渚�',
+ `housing_fund_personal_ratio` decimal(5,4) NOT NULL DEFAULT '0.1200' COMMENT '鍏Н閲戜釜浜虹即绾虫瘮渚�',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊細0-鍚敤锛�1-绂佺敤',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_effective_date` (`effective_date`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM绀句繚鍏Н閲戞柟妗堣〃';
+
+-- ============ 琛細hrm_tax_rate_config锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_tax_rate_config`;
+CREATE TABLE `hrm_tax_rate_config` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '閰嶇疆ID',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '閰嶇疆鍚嶇О',
+ `effective_date` date NOT NULL COMMENT '鐢熸晥鏃ユ湡',
+ `level` tinyint NOT NULL COMMENT '绋庣巼绾ф暟锛�1-7',
+ `min_amount` decimal(12,2) NOT NULL COMMENT '搴旂撼绋庢墍寰楅涓嬮檺锛堝惈锛�',
+ `max_amount` decimal(12,2) NOT NULL COMMENT '搴旂撼绋庢墍寰楅涓婇檺锛堜笉鍚級锛�0琛ㄧず鏃犱笂闄�',
+ `tax_rate` decimal(5,4) NOT NULL COMMENT '绋庣巼',
+ `quick_deduction` decimal(12,2) NOT NULL DEFAULT '0.00' COMMENT '閫熺畻鎵i櫎鏁�',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊細0-鍚敤锛�1-绂佺敤',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_effective_date` (`effective_date`) USING BTREE,
+ KEY `idx_level` (`level`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM涓◣绋庣巼閰嶇疆琛�';
+
+-- ============ 琛細hrm_transfer_application锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `hrm_transfer_application`;
+CREATE TABLE `hrm_transfer_application` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鐢宠ID',
+ `no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐢宠鍗曞彿',
+ `user_id` bigint NOT NULL COMMENT '鐢宠浜篒D',
+ `current_dept_id` bigint NOT NULL COMMENT '鍘熼儴闂↖D',
+ `current_post_id` bigint NOT NULL COMMENT '鍘熷矖浣岻D',
+ `target_dept_id` bigint NOT NULL COMMENT '鐩爣閮ㄩ棬ID',
+ `target_post_id` bigint NOT NULL COMMENT '鐩爣宀椾綅ID',
+ `transfer_type` tinyint NOT NULL COMMENT '璋冨矖绫诲瀷锛�1-骞宠皟锛�2-鍗囪亴锛�3-闄嶈亴',
+ `effective_date` date NOT NULL COMMENT '鐢熸晥鏃ユ湡',
+ `reason` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '璋冨矖鍘熷洜',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊細0-鑽夌锛�10-瀹℃壒涓紝20-閫氳繃锛�30-椹冲洖锛�40-鎾ら攢',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'BPM娴佺▼瀹炰緥ID',
+ `approve_time` datetime DEFAULT NULL COMMENT '瀹℃壒瀹屾垚鏃堕棿',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_no` (`no`) USING BTREE,
+ KEY `idx_user_status` (`user_id`,`status`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='HRM璋冨矖鐢宠琛�';
+
+-- ============ 琛細im_channel锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `im_channel`;
+CREATE TABLE `im_channel` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '棰戦亾涓氬姟鐮�',
+ `name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '棰戦亾鍚嶇О',
+ `avatar` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '棰戦亾澶村儚',
+ `sort` int DEFAULT '0' COMMENT '鎺掑簭',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1绂佺敤锛�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_code` (`code`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='IM 棰戦亾琛�';
+
+-- ============ 琛細im_channel_material锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `im_channel_material`;
+CREATE TABLE `im_channel_material` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `channel_id` bigint NOT NULL COMMENT '棰戦亾缂栧彿',
+ `type` tinyint NOT NULL COMMENT '绱犳潗鍐呭绫诲瀷',
+ `title` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鏍囬',
+ `cover_url` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '灏侀潰鍥�',
+ `summary` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎽樿',
+ `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '瀵屾枃鏈� HTML',
+ `url` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璺宠浆閾炬帴',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_channel_id` (`channel_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='IM 棰戦亾绱犳潗琛�';
+
+-- ============ 琛細im_channel_message锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `im_channel_message`;
+CREATE TABLE `im_channel_message` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `channel_id` bigint NOT NULL COMMENT '棰戦亾缂栧彿',
+ `material_id` bigint DEFAULT NULL COMMENT '鍏宠仈绱犳潗缂栧彿',
+ `type` tinyint NOT NULL COMMENT '娑堟伅绫诲瀷',
+ `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '娑堟伅鍐呭 JSON',
+ `receiver_user_ids` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎺ユ敹浜虹紪鍙峰垪琛�',
+ `send_time` datetime DEFAULT NULL COMMENT '鍙戦�佹椂闂�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_channel_id` (`channel_id`) USING BTREE,
+ KEY `idx_send_time` (`send_time`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='IM 棰戦亾娑堟伅琛�';
+
+-- ============ 琛細im_conversation锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `im_conversation`;
+CREATE TABLE `im_conversation` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '浼氳瘽缂栧彿',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `conversation_type` tinyint NOT NULL COMMENT '浼氳瘽绫诲瀷锛�1绉佽亰 2缇よ亰锛�',
+ `target_id` bigint NOT NULL COMMENT '鐩爣缂栧彿锛堢鑱婁负鐢ㄦ埛ID锛岀兢鑱婁负缇D锛�',
+ `last_message_id` bigint DEFAULT NULL COMMENT '鏈�鍚庢秷鎭紪鍙�',
+ `last_message_time` datetime DEFAULT NULL COMMENT '鏈�鍚庢秷鎭椂闂�',
+ `unread_count` int NOT NULL DEFAULT '0' COMMENT '鏈娑堟伅鏁�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_user_target_type` (`user_id`,`target_id`,`conversation_type`) USING BTREE,
+ KEY `idx_user_id` (`user_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='浼氳瘽琛�';
+
+-- ============ 琛細im_conversation_read锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `im_conversation_read`;
+CREATE TABLE `im_conversation_read` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `conversation_type` tinyint NOT NULL COMMENT '浼氳瘽绫诲瀷锛�1绉佽亰 2缇よ亰 3棰戦亾锛�',
+ `target_id` bigint NOT NULL COMMENT '鐩爣缂栧彿',
+ `message_id` bigint NOT NULL COMMENT '鏈�澶у凡璇绘秷鎭紪鍙�',
+ `read_time` datetime DEFAULT NULL COMMENT '鏈�杩戝凡璇绘椂闂�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_user_conv` (`user_id`,`conversation_type`,`target_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='IM 浼氳瘽璇讳綅缃〃';
+
+-- ============ 琛細im_face_pack锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `im_face_pack`;
+CREATE TABLE `im_face_pack` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '琛ㄦ儏鍖呭悕绉�',
+ `icon` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '琛ㄦ儏鍖呭浘鏍�',
+ `sort` int DEFAULT '0' COMMENT '鎺掑簭',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1绂佺敤锛�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='IM 琛ㄦ儏鍖呰〃';
+
+-- ============ 琛細im_face_pack_item锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `im_face_pack_item`;
+CREATE TABLE `im_face_pack_item` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `pack_id` bigint NOT NULL COMMENT '鎵�灞炶〃鎯呭寘缂栧彿',
+ `url` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '琛ㄦ儏鍥� URL',
+ `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '琛ㄦ儏鍚�',
+ `width` int DEFAULT NULL COMMENT '娓叉煋瀹藉害锛堝儚绱狅級',
+ `height` int DEFAULT NULL COMMENT '娓叉煋楂樺害锛堝儚绱狅級',
+ `sort` int DEFAULT '0' COMMENT '鎺掑簭',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1绂佺敤锛�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_pack_id` (`pack_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='IM 琛ㄦ儏鍖呴」琛�';
+
+-- ============ 琛細im_face_user_item锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `im_face_user_item`;
+CREATE TABLE `im_face_user_item` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `user_id` bigint NOT NULL COMMENT '鎵�灞炵敤鎴风紪鍙�',
+ `url` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '琛ㄦ儏鍥� URL',
+ `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '琛ㄦ儏鍚�',
+ `width` int DEFAULT NULL COMMENT '娓叉煋瀹藉害锛堝儚绱狅級',
+ `height` int DEFAULT NULL COMMENT '娓叉煋楂樺害锛堝儚绱狅級',
+ `sort` int DEFAULT '0' COMMENT '鎺掑簭',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_user_id` (`user_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='IM 鐢ㄦ埛绉佹湁琛ㄦ儏琛�';
+
+-- ============ 琛細im_friend锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `im_friend`;
+CREATE TABLE `im_friend` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `friend_user_id` bigint NOT NULL COMMENT '濂藉弸鐢ㄦ埛缂栧彿',
+ `silent` bit(1) DEFAULT b'0' COMMENT '鏄惁鍏嶆墦鎵�',
+ `display_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '濂藉弸灞曠ず澶囨敞',
+ `add_source` tinyint DEFAULT NULL COMMENT '娣诲姞鏉ユ簮',
+ `pinned` bit(1) DEFAULT b'0' COMMENT '鏄惁缃《鑱旂郴浜�',
+ `blocked` bit(1) DEFAULT b'0' COMMENT '鏄惁鎷夐粦',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '濂藉弸鐘舵�侊紙0姝e父 1绂佺敤/宸插垹闄わ級',
+ `add_time` datetime DEFAULT NULL COMMENT '娣诲姞濂藉弸鏃堕棿',
+ `delete_time` datetime DEFAULT NULL COMMENT '鍒犻櫎濂藉弸鏃堕棿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_user_friend` (`user_id`,`friend_user_id`) USING BTREE,
+ KEY `idx_friend_user_id` (`friend_user_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='IM 濂藉弸鍏崇郴琛�';
+
+-- ============ 琛細im_friend_request锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `im_friend_request`;
+CREATE TABLE `im_friend_request` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `from_user_id` bigint NOT NULL COMMENT '鍙戣捣鏂圭敤鎴风紪鍙�',
+ `to_user_id` bigint NOT NULL COMMENT '鎺ユ敹鏂圭敤鎴风紪鍙�',
+ `apply_content` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐢宠鐞嗙敱',
+ `display_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍙戣捣鏂瑰鎺ユ敹鏂圭殑澶囨敞',
+ `add_source` tinyint DEFAULT NULL COMMENT '娣诲姞鏉ユ簮',
+ `handle_result` tinyint DEFAULT NULL COMMENT '澶勭悊缁撴灉',
+ `handle_content` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶勭悊鐞嗙敱',
+ `handle_time` datetime DEFAULT NULL COMMENT '澶勭悊鏃堕棿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_from_user_id` (`from_user_id`) USING BTREE,
+ KEY `idx_to_user_id` (`to_user_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='IM 濂藉弸鐢宠璁板綍琛�';
+
+-- ============ 琛細im_group锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `im_group`;
+CREATE TABLE `im_group` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '缇ゅ悕绉�',
+ `owner_user_id` bigint NOT NULL COMMENT '缇や富鐢ㄦ埛缂栧彿',
+ `avatar` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '缇ゅご鍍�',
+ `notice` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '缇ゅ叕鍛�',
+ `join_approval` bit(1) DEFAULT b'0' COMMENT '杩涚兢鏄惁闇�瀹℃壒',
+ `banned` bit(1) DEFAULT b'0' COMMENT '鏄惁灏佺',
+ `banned_reason` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '灏佺鍘熷洜',
+ `banned_time` datetime DEFAULT NULL COMMENT '灏佺鏃堕棿',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '缇ょ姸鎬侊紙0姝e父 1宸茶В鏁o級',
+ `dissolved_time` datetime DEFAULT NULL COMMENT '瑙f暎鏃堕棿',
+ `muted_all` bit(1) DEFAULT b'0' COMMENT '鏄惁鍏ㄧ兢绂佽█',
+ `pinned_message_ids` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '缇ょ疆椤舵秷鎭紪鍙峰垪琛�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_owner_user_id` (`owner_user_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='IM 缇や俊鎭〃';
+
+-- ============ 琛細im_group_member锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `im_group_member`;
+CREATE TABLE `im_group_member` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `group_id` bigint NOT NULL COMMENT '缇ょ紪鍙�',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `display_user_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '缁勫唴鏄剧ず鍚�',
+ `group_remark` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '缇ゅ娉�',
+ `silent` bit(1) DEFAULT b'0' COMMENT '鏄惁鍏嶆墦鎵�',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鎴愬憳鐘舵�侊紙0姝e父 1绂佺敤锛�',
+ `role` tinyint NOT NULL DEFAULT '0' COMMENT '鎴愬憳瑙掕壊锛�0鏅�氭垚鍛� 1绠$悊鍛� 2缇や富锛�',
+ `join_time` datetime DEFAULT NULL COMMENT '鍏ョ兢鏃堕棿',
+ `add_source` tinyint DEFAULT NULL COMMENT '鍔犲叆鏉ユ簮',
+ `inviter_user_id` bigint DEFAULT NULL COMMENT '閭�璇蜂汉鐢ㄦ埛缂栧彿',
+ `quit_time` datetime DEFAULT NULL COMMENT '閫�缇ゆ椂闂�',
+ `mute_end_time` datetime DEFAULT NULL COMMENT '绂佽█鍒版湡鏃堕棿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_group_user` (`group_id`,`user_id`) USING BTREE,
+ KEY `idx_user_id` (`user_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='IM 缇ゆ垚鍛樿〃';
+
+-- ============ 琛細im_group_message锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `im_group_message`;
+CREATE TABLE `im_group_message` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `client_message_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瀹㈡埛绔秷鎭紪鍙�',
+ `sender_id` bigint NOT NULL COMMENT '鍙戦�佷汉缂栧彿',
+ `group_id` bigint NOT NULL COMMENT '缇ょ紪鍙�',
+ `type` tinyint NOT NULL COMMENT '娑堟伅绫诲瀷',
+ `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '娑堟伅鍐呭 JSON',
+ `status` tinyint DEFAULT NULL COMMENT '娑堟伅鐘舵��',
+ `send_time` datetime DEFAULT NULL COMMENT '鍙戦�佹椂闂�',
+ `receiver_user_ids` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瀹氬悜鎺ユ敹鐢ㄦ埛缂栧彿鍒楄〃',
+ `at_user_ids` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '@鐩爣鐢ㄦ埛缂栧彿鍒楄〃',
+ `receipt_status` tinyint DEFAULT NULL COMMENT '鍥炴墽鐘舵��',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_client_message_id` (`client_message_id`) USING BTREE,
+ KEY `idx_group_id` (`group_id`) USING BTREE,
+ KEY `idx_sender_id` (`sender_id`) USING BTREE,
+ KEY `idx_send_time` (`send_time`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='IM 缇よ亰娑堟伅琛�';
+
+-- ============ 琛細im_group_message_receipt锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `im_group_message_receipt`;
+CREATE TABLE `im_group_message_receipt` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `message_id` bigint NOT NULL COMMENT '缇ゆ秷鎭紪鍙�',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `read_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '宸茶鏃堕棿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_message_user` (`message_id`,`user_id`) USING BTREE,
+ KEY `idx_message_id` (`message_id`) USING BTREE,
+ KEY `idx_user_id` (`user_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='缇ゆ秷鎭洖鎵ц〃';
+
+-- ============ 琛細im_group_request锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `im_group_request`;
+CREATE TABLE `im_group_request` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `group_id` bigint NOT NULL COMMENT '缇ょ紪鍙�',
+ `user_id` bigint NOT NULL COMMENT '鐢宠浜�/琚個璇蜂汉鐢ㄦ埛缂栧彿',
+ `inviter_user_id` bigint DEFAULT NULL COMMENT '閭�璇蜂汉鐢ㄦ埛缂栧彿',
+ `apply_content` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐢宠鐞嗙敱',
+ `add_source` tinyint DEFAULT NULL COMMENT '鍔犲叆鏉ユ簮',
+ `handle_result` tinyint DEFAULT NULL COMMENT '澶勭悊缁撴灉',
+ `handle_user_id` bigint DEFAULT NULL COMMENT '澶勭悊浜虹敤鎴风紪鍙�',
+ `handle_content` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶勭悊鐞嗙敱',
+ `handle_time` datetime DEFAULT NULL COMMENT '澶勭悊鏃堕棿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_group_id` (`group_id`) USING BTREE,
+ KEY `idx_user_id` (`user_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='IM 鍔犵兢鐢宠璁板綍琛�';
+
+-- ============ 琛細im_message_file锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `im_message_file`;
+CREATE TABLE `im_message_file` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `message_id` bigint NOT NULL COMMENT '娑堟伅缂栧彿',
+ `message_type` tinyint NOT NULL COMMENT '娑堟伅绫诲瀷锛�102鍥剧墖 103璇煶 104瑙嗛 105鏂囦欢锛�',
+ `file_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鏂囦欢URL',
+ `file_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鏂囦欢鍚�',
+ `file_size` bigint DEFAULT NULL COMMENT '鏂囦欢澶у皬锛堝瓧鑺傦級',
+ `file_duration` int DEFAULT NULL COMMENT '鏂囦欢鏃堕暱锛堢锛岃闊�/瑙嗛锛�',
+ `width` int DEFAULT NULL COMMENT '瀹藉害锛堝浘鐗�/瑙嗛锛�',
+ `height` int DEFAULT NULL COMMENT '楂樺害锛堝浘鐗�/瑙嗛锛�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_message_id` (`message_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='娑堟伅鏂囦欢琛�';
+
+-- ============ 琛細im_private_message锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `im_private_message`;
+CREATE TABLE `im_private_message` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `client_message_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瀹㈡埛绔秷鎭紪鍙�',
+ `sender_id` bigint NOT NULL COMMENT '鍙戦�佷汉缂栧彿',
+ `receiver_id` bigint NOT NULL COMMENT '鎺ユ敹浜虹紪鍙�',
+ `type` tinyint NOT NULL COMMENT '娑堟伅绫诲瀷',
+ `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '娑堟伅鍐呭 JSON',
+ `status` tinyint DEFAULT NULL COMMENT '娑堟伅鐘舵��',
+ `receipt_status` tinyint DEFAULT NULL COMMENT '鍥炴墽鐘舵��',
+ `send_time` datetime DEFAULT NULL COMMENT '鍙戦�佹椂闂�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_client_message_id` (`client_message_id`) USING BTREE,
+ KEY `idx_sender_id` (`sender_id`) USING BTREE,
+ KEY `idx_receiver_id` (`receiver_id`) USING BTREE,
+ KEY `idx_send_time` (`send_time`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='IM 绉佽亰娑堟伅琛�';
+
+-- ============ 琛細im_rtc_call锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `im_rtc_call`;
+CREATE TABLE `im_rtc_call` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `room` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '涓氬姟閫氳瘽缂栧彿锛圲UID锛�',
+ `conversation_type` tinyint NOT NULL COMMENT '浼氳瘽绫诲瀷',
+ `media_type` tinyint NOT NULL COMMENT '濯掍綋绫诲瀷',
+ `inviter_user_id` bigint NOT NULL COMMENT '鍙戣捣浜虹敤鎴风紪鍙�',
+ `group_id` bigint DEFAULT NULL COMMENT '缇ょ紪鍙�',
+ `status` tinyint NOT NULL COMMENT '閫氳瘽鐘舵��',
+ `end_reason` tinyint DEFAULT NULL COMMENT '缁撴潫鍘熷洜',
+ `start_time` datetime DEFAULT NULL COMMENT '鍙戣捣鏃堕棿',
+ `accept_time` datetime DEFAULT NULL COMMENT '鎺ラ�氭椂闂�',
+ `end_time` datetime DEFAULT NULL COMMENT '閫氳瘽缁撴潫鏃堕棿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_room` (`room`) USING BTREE,
+ KEY `idx_inviter_user_id` (`inviter_user_id`) USING BTREE,
+ KEY `idx_group_id` (`group_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='IM 閫氳瘽璁板綍琛�';
+
+-- ============ 琛細im_rtc_participant锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `im_rtc_participant`;
+CREATE TABLE `im_rtc_participant` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `call_id` bigint NOT NULL COMMENT '閫氳瘽缂栧彿',
+ `room` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '涓氬姟閫氳瘽缂栧彿',
+ `user_id` bigint NOT NULL COMMENT '鍙備笌鑰呯敤鎴风紪鍙�',
+ `role` tinyint NOT NULL COMMENT '鍙備笌瑙掕壊',
+ `status` tinyint NOT NULL COMMENT '鍙備笌鐘舵��',
+ `invite_time` datetime DEFAULT NULL COMMENT '琚個璇锋椂闂�',
+ `accept_time` datetime DEFAULT NULL COMMENT '鎺ュ惉鏃堕棿',
+ `leave_time` datetime DEFAULT NULL COMMENT '绂诲紑鏃堕棿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_call_id` (`call_id`) USING BTREE,
+ KEY `idx_room` (`room`) USING BTREE,
+ KEY `idx_user_id` (`user_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='IM 閫氳瘽鍙備笌鑰呰〃';
+
+-- ============ 琛細im_sensitive_word锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `im_sensitive_word`;
+CREATE TABLE `im_sensitive_word` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `word` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鏁忔劅璇�',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1绂佺敤锛�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_word` (`word`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='IM 鏁忔劅璇嶈〃';
+
+-- ============ 琛細im_user_online锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `im_user_online`;
+CREATE TABLE `im_user_online` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `online_status` tinyint NOT NULL DEFAULT '0' COMMENT '鍦ㄧ嚎鐘舵�侊紙0绂荤嚎 1鍦ㄧ嚎锛�',
+ `last_online_time` datetime DEFAULT NULL COMMENT '鏈�鍚庡湪绾挎椂闂�',
+ `last_offline_time` datetime DEFAULT NULL COMMENT '鏈�鍚庣绾挎椂闂�',
+ `device_type` tinyint DEFAULT NULL COMMENT '璁惧绫诲瀷锛�1Web 2Android 3iOS锛�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_user_id` (`user_id`) USING BTREE,
+ KEY `idx_user_id` (`user_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='鐢ㄦ埛鍦ㄧ嚎鐘舵�佽〃';
+
+-- ============ 琛細infra_api_access_log锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `infra_api_access_log`;
+CREATE TABLE `infra_api_access_log` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鏃ュ織涓婚敭',
+ `trace_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '閾捐矾杩借釜缂栧彿',
+ `user_id` bigint NOT NULL DEFAULT '0' COMMENT '鐢ㄦ埛缂栧彿',
+ `user_type` tinyint NOT NULL DEFAULT '0' COMMENT '鐢ㄦ埛绫诲瀷',
+ `application_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '搴旂敤鍚�',
+ `request_method` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '璇锋眰鏂规硶鍚�',
+ `request_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '璇锋眰鍦板潃',
+ `request_params` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '璇锋眰鍙傛暟',
+ `response_body` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鍝嶅簲缁撴灉',
+ `user_ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐢ㄦ埛 IP',
+ `user_agent` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '娴忚鍣� UA',
+ `operate_module` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎿嶄綔妯″潡',
+ `operate_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎿嶄綔鍚�',
+ `operate_type` tinyint DEFAULT '0' COMMENT '鎿嶄綔鍒嗙被',
+ `begin_time` datetime NOT NULL COMMENT '寮�濮嬭姹傛椂闂�',
+ `end_time` datetime NOT NULL COMMENT '缁撴潫璇锋眰鏃堕棿',
+ `duration` int NOT NULL COMMENT '鎵ц鏃堕暱',
+ `result_code` int NOT NULL DEFAULT '0' COMMENT '缁撴灉鐮�',
+ `result_msg` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '缁撴灉鎻愮ず',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_create_time` (`create_time`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='API 璁块棶鏃ュ織琛�';
+
+-- ============ 琛細infra_api_error_log锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `infra_api_error_log`;
+CREATE TABLE `infra_api_error_log` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `trace_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '閾捐矾杩借釜缂栧彿',
+ `user_id` bigint NOT NULL DEFAULT '0' COMMENT '鐢ㄦ埛缂栧彿',
+ `user_type` tinyint NOT NULL DEFAULT '0' COMMENT '鐢ㄦ埛绫诲瀷',
+ `application_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '搴旂敤鍚�',
+ `request_method` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '璇锋眰鏂规硶鍚�',
+ `request_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '璇锋眰鍦板潃',
+ `request_params` varchar(8000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '璇锋眰鍙傛暟',
+ `user_ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐢ㄦ埛 IP',
+ `user_agent` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '娴忚鍣� UA',
+ `exception_time` datetime NOT NULL COMMENT '寮傚父鍙戠敓鏃堕棿',
+ `exception_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '寮傚父鍚�',
+ `exception_message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '寮傚父瀵艰嚧鐨勬秷鎭�',
+ `exception_root_cause_message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '寮傚父瀵艰嚧鐨勬牴娑堟伅',
+ `exception_stack_trace` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '寮傚父鐨勬爤杞ㄨ抗',
+ `exception_class_name` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '寮傚父鍙戠敓鐨勭被鍏ㄥ悕',
+ `exception_file_name` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '寮傚父鍙戠敓鐨勭被鏂囦欢',
+ `exception_method_name` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '寮傚父鍙戠敓鐨勬柟娉曞悕',
+ `exception_line_number` int NOT NULL COMMENT '寮傚父鍙戠敓鐨勬柟娉曟墍鍦ㄨ',
+ `process_status` tinyint NOT NULL COMMENT '澶勭悊鐘舵��',
+ `process_time` datetime DEFAULT NULL COMMENT '澶勭悊鏃堕棿',
+ `process_user_id` int DEFAULT '0' COMMENT '澶勭悊鐢ㄦ埛缂栧彿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_create_time` (`create_time`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='绯荤粺寮傚父鏃ュ織';
+
+-- ============ 琛細infra_file锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `infra_file`;
+CREATE TABLE `infra_file` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鏂囦欢缂栧彿',
+ `config_id` bigint DEFAULT NULL COMMENT '閰嶇疆缂栧彿',
+ `name` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏂囦欢鍚�',
+ `path` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鏂囦欢璺緞',
+ `url` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鏂囦欢 URL',
+ `type` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏂囦欢绫诲瀷',
+ `size` int NOT NULL COMMENT '鏂囦欢澶у皬',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鏂囦欢琛�';
+
+-- ============ 琛細infra_file_content锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `infra_file_content`;
+CREATE TABLE `infra_file_content` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `config_id` bigint NOT NULL COMMENT '閰嶇疆缂栧彿',
+ `path` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鏂囦欢璺緞',
+ `content` mediumblob NOT NULL COMMENT '鏂囦欢鍐呭',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_config_id_path` (`config_id`,`path`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鏂囦欢琛�';
+
+-- ============ 琛細infra_job_log锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `infra_job_log`;
+CREATE TABLE `infra_job_log` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鏃ュ織缂栧彿',
+ `job_id` bigint NOT NULL COMMENT '浠诲姟缂栧彿',
+ `handler_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '澶勭悊鍣ㄧ殑鍚嶅瓧',
+ `handler_param` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶勭悊鍣ㄧ殑鍙傛暟',
+ `execute_index` tinyint NOT NULL DEFAULT '1' COMMENT '绗嚑娆℃墽琛�',
+ `begin_time` datetime NOT NULL COMMENT '寮�濮嬫墽琛屾椂闂�',
+ `end_time` datetime DEFAULT NULL COMMENT '缁撴潫鎵ц鏃堕棿',
+ `duration` int DEFAULT NULL COMMENT '鎵ц鏃堕暱',
+ `status` tinyint NOT NULL COMMENT '浠诲姟鐘舵��',
+ `result` varchar(4000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '缁撴灉鏁版嵁',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_job_id` (`job_id`) USING BTREE,
+ KEY `idx_create_time` (`create_time`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='瀹氭椂浠诲姟鏃ュ織琛�';
+
+-- ============ 琛細mdm_brand锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mdm_brand`;
+CREATE TABLE `mdm_brand` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鍝佺墝缂栧彿',
+ `code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍝佺墝缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍝佺墝鍚嶇О',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_code` (`code`,`deleted`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MDM 鍝佺墝琛�';
+
+-- ============ 琛細mdm_item锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mdm_item`;
+CREATE TABLE `mdm_item` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鐗╂枡缂栧彿',
+ `code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐗╂枡缂栫爜',
+ `name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐗╂枡鍚嶇О',
+ `bar_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐗╂枡鏉$爜',
+ `specification` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瑙勬牸鍨嬪彿',
+ `category_id` bigint DEFAULT NULL COMMENT '鐗╂枡鍒嗙被缂栧彿',
+ `unit_measure_id` bigint DEFAULT NULL COMMENT '璁¢噺鍗曚綅缂栧彿',
+ `unit_measure_id2` bigint DEFAULT NULL COMMENT '杈呭崟浣�1缂栧彿',
+ `unit_measure_rate1` decimal(24,6) DEFAULT NULL COMMENT '杈呭崟浣�1鎹㈢畻姣旂巼',
+ `unit_measure_id3` bigint DEFAULT NULL COMMENT '杈呭崟浣�2缂栧彿',
+ `unit_measure_rate2` decimal(24,6) DEFAULT NULL COMMENT '杈呭崟浣�2鎹㈢畻姣旂巼',
+ `warehouse_id` bigint DEFAULT NULL COMMENT '榛樿浠撳簱缂栧彿',
+ `warehouse_code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '榛樿浠撳簱缂栫爜',
+ `brand_id` bigint DEFAULT NULL COMMENT '鍝佺墝缂栧彿',
+ `item_type` tinyint NOT NULL DEFAULT '1' COMMENT '鐗╂枡绫诲瀷锛�1:鐗╂枡 2:浜у搧 3:鍗婃垚鍝侊級',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+ `purchase_price` decimal(24,2) DEFAULT NULL COMMENT '閲囪喘浠�',
+ `sales_price` decimal(24,2) DEFAULT NULL COMMENT '閿�鍞环',
+ `cost_price` decimal(24,2) DEFAULT NULL COMMENT '鎴愭湰浠�',
+ `min_price` decimal(24,2) DEFAULT NULL COMMENT '鏈�浣庝环',
+ `safety_stock` decimal(24,6) DEFAULT NULL COMMENT '瀹夊叏搴撳瓨',
+ `min_stock` decimal(24,6) DEFAULT NULL COMMENT '鏈�浣庡簱瀛橀噺',
+ `max_stock` decimal(24,6) DEFAULT NULL COMMENT '鏈�楂樺簱瀛橀噺',
+ `min_order_qty` decimal(24,6) DEFAULT NULL COMMENT '鏈�灏忚璐ч噺',
+ `lead_time` int DEFAULT NULL COMMENT '閲囪喘鎻愬墠鏈燂紙澶╋級',
+ `is_batch_managed` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鎵规绠$悊',
+ `is_serial_managed` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁搴忓垪鍙风鐞�',
+ `barcode_rule_id` bigint DEFAULT NULL COMMENT '鏉$爜瑙勫垯ID',
+ `expiry_day` int DEFAULT NULL COMMENT '淇濊川鏈熷ぉ鏁�',
+ `high_value` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁楂樺�肩墿鏂�',
+ `weight` decimal(24,6) DEFAULT NULL COMMENT '閲嶉噺(kg)',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_name` (`name`) USING BTREE,
+ KEY `idx_category_id` (`category_id`) USING BTREE,
+ KEY `idx_item_type` (`item_type`) USING BTREE,
+ KEY `idx_status` (`status`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=45 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MDM 鐗╂枡涓绘暟鎹〃';
+
+-- ============ 琛細mdm_item_batch_config锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mdm_item_batch_config`;
+CREATE TABLE `mdm_item_batch_config` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '閰嶇疆缂栧彿',
+ `item_id` bigint NOT NULL COMMENT '鐗╂枡缂栧彿',
+ `produce_date_flag` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍚敤鐢熶骇鏃ユ湡',
+ `expire_date_flag` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍚敤澶辨晥鏃ユ湡',
+ `receipt_date_flag` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍚敤鍏ュ簱鏃ユ湡',
+ `vendor_flag` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍚敤渚涘簲鍟�',
+ `client_flag` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍚敤瀹㈡埛',
+ `sales_order_code_flag` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍚敤閿�鍞鍗曞彿',
+ `purchase_order_code_flag` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍚敤閲囪喘璁㈠崟鍙�',
+ `work_order_flag` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍚敤鐢熶骇宸ュ崟',
+ `task_flag` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍚敤鐢熶骇浠诲姟',
+ `workstation_flag` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍚敤宸ヤ綅',
+ `tool_flag` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍚敤宸ヨ澶瑰叿',
+ `mold_flag` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍚敤妯″叿',
+ `lot_number_flag` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍚敤鎵规鍙�',
+ `quality_status_flag` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍚敤璐ㄩ噺鐘舵��',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_item_id` (`item_id`,`deleted`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MDM 鐗╂枡鎵规灞炴�ч厤缃〃';
+
+-- ============ 琛細mdm_item_category锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mdm_item_category`;
+CREATE TABLE `mdm_item_category` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鍒嗙被缂栧彿',
+ `parent_id` bigint NOT NULL DEFAULT '0' COMMENT '鐖跺垎绫荤紪鍙凤紙鏍硅妭鐐�=0锛�',
+ `code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍒嗙被缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍒嗙被鍚嶇О',
+ `item_type` tinyint DEFAULT NULL COMMENT '閫傜敤鐗╂枡绫诲瀷锛�1:鐗╂枡 2:浜у搧 3:鍗婃垚鍝� NULL:鍏ㄩ儴锛�',
+ `item_or_product` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐗╂枡/浜у搧鏍囪瘑(鍏煎MES: ITEM/PRODUCT)',
+ `sort` int NOT NULL DEFAULT '0' COMMENT '鎺掑簭',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_parent_id` (`parent_id`) USING BTREE,
+ KEY `idx_code` (`code`) USING BTREE,
+ KEY `idx_item_or_product` (`item_or_product`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MDM 鐗╂枡鍒嗙被琛�';
+
+-- ============ 琛細mdm_item_migration_map锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mdm_item_migration_map`;
+CREATE TABLE `mdm_item_migration_map` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鏄犲皠ID',
+ `source_module` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鏉ユ簮妯″潡(ERP/MES/WMS)',
+ `source_table` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鏉ユ簮琛ㄥ悕',
+ `source_id` bigint NOT NULL COMMENT '鍘烮D',
+ `target_item_id` bigint NOT NULL COMMENT 'MDM鐗╂枡ID',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_source` (`source_module`,`source_table`,`source_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鐗╂枡杩佺Щ鏄犲皠琛�';
+
+-- ============ 琛細mdm_item_sku锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mdm_item_sku`;
+CREATE TABLE `mdm_item_sku` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'SKU缂栧彿',
+ `item_id` bigint NOT NULL COMMENT '鐗╂枡缂栧彿',
+ `code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'SKU缂栫爜',
+ `name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'SKU鍚嶇О',
+ `bar_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'SKU鏉$爜',
+ `length` decimal(24,6) DEFAULT NULL COMMENT '闀垮害锛坈m锛�',
+ `width` decimal(24,6) DEFAULT NULL COMMENT '瀹藉害锛坈m锛�',
+ `height` decimal(24,6) DEFAULT NULL COMMENT '楂樺害锛坈m锛�',
+ `gross_weight` decimal(24,6) DEFAULT NULL COMMENT '姣涢噸锛坘g锛�',
+ `net_weight` decimal(24,6) DEFAULT NULL COMMENT '鍑�閲嶏紙kg锛�',
+ `cost_price` decimal(24,2) DEFAULT NULL COMMENT '鎴愭湰浠�',
+ `sale_price` decimal(24,2) DEFAULT NULL COMMENT '閿�鍞环',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_code` (`code`,`deleted`) USING BTREE,
+ KEY `idx_item_id` (`item_id`) USING BTREE,
+ KEY `idx_bar_code` (`bar_code`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MDM 鐗╂枡SKU琛�';
+
+-- ============ 琛細mdm_unit_measure锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mdm_unit_measure`;
+CREATE TABLE `mdm_unit_measure` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鍗曚綅缂栧彿',
+ `code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍗曚綅缂栫爜',
+ `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍗曚綅鍚嶇О',
+ `primary_flag` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁涓诲崟浣�',
+ `primary_id` bigint DEFAULT NULL COMMENT '涓诲崟浣嶇紪鍙�',
+ `change_rate` decimal(24,6) DEFAULT '1.000000' COMMENT '涓庝富鍗曚綅鎹㈢畻姣斾緥',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_code` (`code`,`deleted`) USING BTREE,
+ KEY `idx_name` (`name`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MDM 璁¢噺鍗曚綅琛�';
+
+-- ============ 琛細mdm_warehouse锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mdm_warehouse`;
+CREATE TABLE `mdm_warehouse` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '浠撳簱缂栧彿',
+ `code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '浠撳簱缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '浠撳簱鍚嶇О',
+ `type` tinyint DEFAULT NULL COMMENT '浠撳簱绫诲瀷',
+ `charge_user_id` bigint DEFAULT NULL COMMENT '璐熻矗浜虹敤鎴稩D',
+ `address` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '浠撳簱鍦板潃',
+ `area` decimal(10,2) DEFAULT NULL COMMENT '闈㈢Н锛堝钩鏂圭背锛�',
+ `principal` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璐熻矗浜�',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+ `frozen` bit(1) DEFAULT b'0' COMMENT '鏄惁鍐荤粨',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_code` (`code`,`deleted`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MDM 浠撳簱琛�';
+
+-- ============ 琛細mes_cal_holiday锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_cal_holiday`;
+CREATE TABLE `mes_cal_holiday` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `day` datetime DEFAULT NULL COMMENT '鏃ユ湡',
+ `type` int DEFAULT NULL COMMENT '鏃ユ湡绫诲瀷',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鍋囨湡璁剧疆';
+
+-- ============ 琛細mes_cal_plan锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_cal_plan`;
+CREATE TABLE `mes_cal_plan` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '璁″垝缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璁″垝缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璁″垝鍚嶇О',
+ `calendar_type` int DEFAULT NULL COMMENT '鐝粍绫诲瀷',
+ `start_date` datetime DEFAULT NULL COMMENT '寮�濮嬫棩鏈�',
+ `end_date` datetime DEFAULT NULL COMMENT '缁撴潫鏃ユ湡',
+ `shift_type` int DEFAULT NULL COMMENT '杞彮鏂瑰紡',
+ `shift_method` int DEFAULT NULL COMMENT '鍊掔彮鏂瑰紡',
+ `shift_count` int DEFAULT NULL COMMENT '鍊掔彮澶╂暟',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `exclude_weekend` tinyint(1) DEFAULT '1' COMMENT '鏄惁鎺掗櫎鍛ㄦ湯: 1鏄� 0鍚�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鎺掔彮璁″垝';
+
+-- ============ 琛細mes_cal_plan_shift锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_cal_plan_shift`;
+CREATE TABLE `mes_cal_plan_shift` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鐝缂栧彿',
+ `plan_id` bigint DEFAULT NULL COMMENT '鎺掔彮璁″垝缂栧彿',
+ `sort` int DEFAULT NULL COMMENT '鏄剧ず椤哄簭',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐝鍚嶇О',
+ `start_time` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '寮�濮嬫椂闂达紙HH:mm 鏍煎紡锛�',
+ `end_time` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '缁撴潫鏃堕棿锛圚H:mm 鏍煎紡锛�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 璁″垝鐝';
+
+-- ============ 琛細mes_cal_plan_team锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_cal_plan_team`;
+CREATE TABLE `mes_cal_plan_team` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `plan_id` bigint DEFAULT NULL COMMENT '鎺掔彮璁″垝缂栧彿',
+ `team_id` bigint DEFAULT NULL COMMENT '鐝粍缂栧彿',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 璁″垝鐝粍鍏宠仈';
+
+-- ============ 琛細mes_cal_team锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_cal_team`;
+CREATE TABLE `mes_cal_team` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鐝粍缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐝粍缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐝粍鍚嶇О',
+ `calendar_type` int DEFAULT NULL COMMENT '鐝粍绫诲瀷',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐝粍';
+
+-- ============ 琛細mes_cal_team_member锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_cal_team_member`;
+CREATE TABLE `mes_cal_team_member` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鐝粍鎴愬憳缂栧彿',
+ `team_id` bigint DEFAULT NULL COMMENT '鐝粍缂栧彿',
+ `user_id` bigint DEFAULT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐝粍鎴愬憳';
+
+-- ============ 琛細mes_cal_team_shift锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_cal_team_shift`;
+CREATE TABLE `mes_cal_team_shift` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `plan_id` bigint DEFAULT NULL COMMENT '鎺掔彮璁″垝缂栧彿',
+ `team_id` bigint DEFAULT NULL COMMENT '鐝粍缂栧彿',
+ `shift_id` bigint DEFAULT NULL COMMENT '鐝缂栧彿',
+ `day` datetime DEFAULT NULL COMMENT '鏃ユ湡',
+ `sort` int DEFAULT NULL COMMENT '鎺掑簭',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐝粍鎺掔彮';
+
+-- ============ 琛細mes_dv_check_plan锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_dv_check_plan`;
+CREATE TABLE `mes_dv_check_plan` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏂规缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏂规鍚嶇О',
+ `type` int DEFAULT NULL COMMENT '鏂规绫诲瀷',
+ `start_date` datetime DEFAULT NULL COMMENT '寮�濮嬫棩鏈�',
+ `end_date` datetime DEFAULT NULL COMMENT '缁撴潫鏃ユ湡',
+ `cycle_type` int DEFAULT NULL COMMENT '鍛ㄦ湡绫诲瀷',
+ `cycle_count` int DEFAULT NULL COMMENT '鍛ㄦ湡鏁伴噺',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐐规淇濆吇鏂规';
+
+-- ============ 琛細mes_dv_check_plan_machinery锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_dv_check_plan_machinery`;
+CREATE TABLE `mes_dv_check_plan_machinery` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `plan_id` bigint DEFAULT NULL COMMENT '鏂规缂栧彿',
+ `machinery_id` bigint DEFAULT NULL COMMENT '璁惧缂栧彿',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐐规淇濆吇鏂规璁惧';
+
+-- ============ 琛細mes_dv_check_plan_subject锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_dv_check_plan_subject`;
+CREATE TABLE `mes_dv_check_plan_subject` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `plan_id` bigint DEFAULT NULL COMMENT '鏂规缂栧彿',
+ `subject_id` bigint DEFAULT NULL COMMENT '椤圭洰缂栧彿',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐐规淇濆吇鏂规椤圭洰';
+
+-- ============ 琛細mes_dv_check_record锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_dv_check_record`;
+CREATE TABLE `mes_dv_check_record` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `plan_id` bigint DEFAULT NULL COMMENT '鐐规璁″垝缂栧彿',
+ `machinery_id` bigint DEFAULT NULL COMMENT '璁惧缂栧彿',
+ `check_time` datetime DEFAULT NULL COMMENT '鐐规鏃堕棿',
+ `user_id` bigint DEFAULT NULL COMMENT '鐐规浜虹紪鍙�',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 璁惧鐐规璁板綍';
+
+-- ============ 琛細mes_dv_check_record_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_dv_check_record_line`;
+CREATE TABLE `mes_dv_check_record_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `record_id` bigint DEFAULT NULL COMMENT '鐐规璁板綍缂栧彿',
+ `subject_id` bigint DEFAULT NULL COMMENT '鐐规椤圭洰缂栧彿',
+ `check_status` int DEFAULT NULL COMMENT '鐐规缁撴灉',
+ `check_result` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '寮傚父鎻忚堪',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 璁惧鐐规璁板綍鏄庣粏';
+
+-- ============ 琛細mes_dv_machinery锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_dv_machinery`;
+CREATE TABLE `mes_dv_machinery` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璁惧缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璁惧鍚嶇О',
+ `brand` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍝佺墝',
+ `specification` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瑙勬牸鍨嬪彿',
+ `machinery_type_id` bigint DEFAULT NULL COMMENT '璁惧绫诲瀷缂栧彿',
+ `workshop_id` bigint DEFAULT NULL COMMENT '鎵�灞炶溅闂寸紪鍙�',
+ `status` int DEFAULT NULL COMMENT '璁惧鐘舵��',
+ `last_mainten_time` datetime DEFAULT NULL COMMENT '鏈�杩戜繚鍏绘椂闂�',
+ `last_check_time` datetime DEFAULT NULL COMMENT '鏈�杩戠偣妫�鏃堕棿',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `production_efficiency` decimal(10,2) DEFAULT NULL COMMENT '鐢熶骇鏁堢巼锛堟瘡鍒嗛挓锛�',
+ `conveyor_belt` int DEFAULT NULL COMMENT '浼犻�佸饱甯︼紙2=鍙屽�嶆晥鐜囷級',
+ `workstation_id` bigint DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 璁惧鍙拌处';
+
+-- ============ 琛細mes_dv_machinery_type锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_dv_machinery_type`;
+CREATE TABLE `mes_dv_machinery_type` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '绫诲瀷缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '绫诲瀷鍚嶇О',
+ `parent_id` bigint DEFAULT NULL COMMENT '鐖剁被鍨嬬紪鍙�',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `sort` int DEFAULT NULL COMMENT '鏄剧ず鎺掑簭',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 璁惧绫诲瀷';
+
+-- ============ 琛細mes_dv_mainten_record锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_dv_mainten_record`;
+CREATE TABLE `mes_dv_mainten_record` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `plan_id` bigint DEFAULT NULL COMMENT '璁″垝缂栧彿',
+ `machinery_id` bigint DEFAULT NULL COMMENT '璁惧缂栧彿',
+ `mainten_time` datetime DEFAULT NULL COMMENT '淇濆吇鏃堕棿',
+ `user_id` bigint DEFAULT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 璁惧淇濆吇璁板綍';
+
+-- ============ 琛細mes_dv_mainten_record_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_dv_mainten_record_line`;
+CREATE TABLE `mes_dv_mainten_record_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `record_id` bigint DEFAULT NULL COMMENT '淇濆吇璁板綍缂栧彿',
+ `subject_id` bigint DEFAULT NULL COMMENT '椤圭洰缂栧彿',
+ `status` int DEFAULT NULL COMMENT '淇濆吇缁撴灉',
+ `result` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '寮傚父鎻忚堪',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 璁惧淇濆吇璁板綍鏄庣粏';
+
+-- ============ 琛細mes_dv_metering锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_dv_metering`;
+CREATE TABLE `mes_dv_metering` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '璁¢噺鍣ㄥ叿缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '璁¢噺鍣ㄥ叿鍚嶇О',
+ `specification` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瑙勬牸鍨嬪彿',
+ `brand` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍝佺墝/鐢熶骇鍘傚',
+ `category` int DEFAULT NULL COMMENT '鍣ㄥ叿绫诲埆锛堝崱灏�/鍗冨垎灏�/鍘嬪姏琛ㄧ瓑锛夛紝瀛楀吀 mes_dv_metering_category',
+ `precision` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '绮惧害',
+ `range` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閲忕▼',
+ `dept_id` bigint DEFAULT NULL COMMENT '浣跨敤閮ㄩ棬缂栧彿',
+ `charge_user_id` bigint DEFAULT NULL COMMENT '璐d换浜虹紪鍙凤紙绔欏唴淇″彂閫佸璞★級',
+ `check_cycle_count` int NOT NULL COMMENT '鏍″噯鍛ㄦ湡锛堟湀锛�',
+ `use_date` date DEFAULT NULL COMMENT '鎶曞叆浣跨敤鏃ユ湡',
+ `last_check_date` date DEFAULT NULL COMMENT '涓婃妫�娴嬫棩鏈�',
+ `next_check_date` date DEFAULT NULL COMMENT '涓嬫妫�娴嬫棩鏈燂紙鍒版湡鏃ワ級',
+ `status` int NOT NULL COMMENT '鐘舵�侊紙鍦ㄧ敤/鍋滅敤/鎶ュ簾锛夛紝瀛楀吀 mes_dv_metering_status',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_code` (`code`) USING BTREE,
+ KEY `idx_dept_id` (`dept_id`) USING BTREE,
+ KEY `idx_charge_user_id` (`charge_user_id`) USING BTREE,
+ KEY `idx_next_check_date` (`next_check_date`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 璁¢噺鍣ㄥ叿';
+
+-- ============ 琛細mes_dv_metering_check锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_dv_metering_check`;
+CREATE TABLE `mes_dv_metering_check` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
+ `metering_id` bigint NOT NULL COMMENT '璁¢噺鍣ㄥ叿ID',
+ `check_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '妫�娴嬬紪鍙�',
+ `check_date` date DEFAULT NULL COMMENT '妫�娴嬫棩鏈�',
+ `check_org` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妫�娴嬫満鏋�',
+ `check_result` int DEFAULT NULL COMMENT '妫�娴嬬粨璁猴紙鍚堟牸/涓嶅悎鏍硷級锛屽瓧鍏� mes_dv_metering_check_result',
+ `cert_no` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璇佷功缂栧彿',
+ `check_user_id` bigint DEFAULT NULL COMMENT '妫�娴嬩汉缂栧彿',
+ `next_check_date` date DEFAULT NULL COMMENT '涓嬫妫�娴嬫棩鏈燂紙鑷姩璁$畻鎴栨墜鍔ㄦ寚瀹氾級',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_check_code` (`check_code`) USING BTREE,
+ KEY `idx_metering_id` (`metering_id`) USING BTREE,
+ KEY `idx_check_date` (`check_date`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 璁¢噺妫�娴嬭褰�';
+
+-- ============ 琛細mes_dv_repair锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_dv_repair`;
+CREATE TABLE `mes_dv_repair` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '缁翠慨宸ュ崟缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '缁翠慨宸ュ崟鍚嶇О',
+ `machinery_id` bigint DEFAULT NULL COMMENT '璁惧缂栧彿',
+ `require_date` datetime DEFAULT NULL COMMENT '鎶ヤ慨鏃ユ湡',
+ `finish_date` datetime DEFAULT NULL COMMENT '缁翠慨瀹屾垚鏃ユ湡',
+ `confirm_date` datetime DEFAULT NULL COMMENT '楠屾敹鏃ユ湡',
+ `result` int DEFAULT NULL COMMENT '缁翠慨缁撴灉',
+ `accepted_user_id` bigint DEFAULT NULL COMMENT '缁翠慨浜虹敤鎴风紪鍙�',
+ `confirm_user_id` bigint DEFAULT NULL COMMENT '楠屾敹浜虹敤鎴风紪鍙�',
+ `source_doc_type` int DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁绫诲瀷',
+ `source_doc_id` bigint DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
+ `source_doc_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栫爜',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 缁翠慨宸ュ崟';
+
+-- ============ 琛細mes_dv_repair_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_dv_repair_line`;
+CREATE TABLE `mes_dv_repair_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `repair_id` bigint DEFAULT NULL COMMENT '缁翠慨宸ュ崟缂栧彿',
+ `subject_id` bigint DEFAULT NULL COMMENT '鐐规淇濆吇椤圭洰缂栧彿',
+ `malfunction` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏁呴殰鎻忚堪',
+ `malfunction_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏁呴殰鍥剧墖 URL',
+ `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '缁翠慨鎻忚堪',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 缁翠慨宸ュ崟琛�';
+
+-- ============ 琛細mes_dv_subject锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_dv_subject`;
+CREATE TABLE `mes_dv_subject` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '椤圭洰缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '椤圭洰鍚嶇О',
+ `type` int DEFAULT NULL COMMENT '椤圭洰绫诲瀷',
+ `content` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '椤圭洰鍐呭',
+ `standard` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏍囧噯',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐐规淇濆吇椤圭洰';
+
+-- ============ 琛細mes_md_auto_code_record锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_md_auto_code_record`;
+CREATE TABLE `mes_md_auto_code_record` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `rule_id` bigint DEFAULT NULL COMMENT '瑙勫垯缂栧彿',
+ `result` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐢熸垚鐨勭紪鐮�',
+ `serial_no` bigint DEFAULT NULL COMMENT '鐢熸垚鐨勬祦姘村彿',
+ `input_char` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '浼犲叆鐨勫弬鏁�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 缂栫爜鐢熸垚璁板綍';
+
+-- ============ 琛細mes_md_item锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_md_item`;
+CREATE TABLE `mes_md_item` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `mdm_item_id` bigint DEFAULT NULL COMMENT 'MDM 鐗╂枡 ID',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐗╂枡缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐗╂枡鍚嶇О',
+ `specification` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瑙勬牸鍨嬪彿',
+ `unit_measure_id` bigint DEFAULT NULL COMMENT '璁¢噺鍗曚綅缂栧彿',
+ `item_type_id` bigint DEFAULT NULL COMMENT '鐗╂枡鍒嗙被缂栧彿',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `safe_stock_flag` bit(1) DEFAULT b'0' COMMENT '鏄惁鍚敤瀹夊叏搴撳瓨',
+ `min_stock` decimal(24,6) DEFAULT NULL COMMENT '鏈�浣庡簱瀛橀噺',
+ `max_stock` decimal(24,6) DEFAULT NULL COMMENT '鏈�楂樺簱瀛橀噺',
+ `high_value` bit(1) DEFAULT b'0' COMMENT '鏄惁楂樺�肩墿鏂�',
+ `batch_flag` bit(1) DEFAULT b'0' COMMENT '鏄惁鍚敤鎵规绠$悊',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐗╂枡浜у搧';
+
+-- ============ 琛細mes_md_item_batch_config锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_md_item_batch_config`;
+CREATE TABLE `mes_md_item_batch_config` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡缂栧彿',
+ `produce_date_flag` bit(1) DEFAULT b'0' COMMENT '鎵规灞炴��-鐢熶骇鏃ユ湡',
+ `expire_date_flag` bit(1) DEFAULT b'0' COMMENT '鎵规灞炴��-鏈夋晥鏈�',
+ `receipt_date_flag` bit(1) DEFAULT b'0' COMMENT '鎵规灞炴��-鍏ュ簱鏃ユ湡',
+ `vendor_flag` bit(1) DEFAULT b'0' COMMENT '鎵规灞炴��-渚涘簲鍟�',
+ `client_flag` bit(1) DEFAULT b'0' COMMENT '鎵规灞炴��-瀹㈡埛',
+ `sales_order_code_flag` bit(1) DEFAULT b'0' COMMENT '鎵规灞炴��-閿�鍞鍗曠紪鍙�',
+ `purchase_order_code_flag` bit(1) DEFAULT b'0' COMMENT '鎵规灞炴��-閲囪喘璁㈠崟缂栧彿',
+ `work_order_flag` bit(1) DEFAULT b'0' COMMENT '鎵规灞炴��-鐢熶骇宸ュ崟',
+ `task_flag` bit(1) DEFAULT b'0' COMMENT '鎵规灞炴��-鐢熶骇浠诲姟',
+ `workstation_flag` bit(1) DEFAULT b'0' COMMENT '鎵规灞炴��-宸ヤ綔绔�',
+ `tool_flag` bit(1) DEFAULT b'0' COMMENT '鎵规灞炴��-宸ュ叿',
+ `mold_flag` bit(1) DEFAULT b'0' COMMENT '鎵规灞炴��-妯″叿',
+ `lot_number_flag` bit(1) DEFAULT b'0' COMMENT '鎵规灞炴��-鐢熶骇鎵瑰彿',
+ `quality_status_flag` bit(1) DEFAULT b'0' COMMENT '鎵规灞炴��-璐ㄩ噺鐘舵��',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐗╂枡鎵规灞炴�ч厤缃�';
+
+-- ============ 琛細mes_md_item_type锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_md_item_type`;
+CREATE TABLE `mes_md_item_type` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍒嗙被缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍒嗙被鍚嶇О',
+ `parent_id` bigint DEFAULT NULL COMMENT '鐖跺垎绫荤紪鍙�',
+ `item_or_product` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐗╂枡/浜у搧鏍囪瘑',
+ `sort` int DEFAULT NULL COMMENT '鏄剧ず鎺掑簭',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐗╂枡浜у搧鍒嗙被';
+
+-- ============ 琛細mes_md_product_bom锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_md_product_bom`;
+CREATE TABLE `mes_md_product_bom` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡浜у搧缂栧彿',
+ `bom_item_id` bigint DEFAULT NULL COMMENT 'BOM鐗╂枡缂栧彿',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鐗╂枡浣跨敤姣斾緥',
+ `status` int DEFAULT NULL COMMENT '鏄惁鍚敤',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 浜у搧 BOM';
+
+-- ============ 琛細mes_md_product_sip锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_md_product_sip`;
+CREATE TABLE `mes_md_product_sip` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡浜у搧缂栧彿',
+ `sort` int DEFAULT NULL COMMENT '鎺掑垪椤哄簭',
+ `process_id` bigint DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
+ `title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏍囬',
+ `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璇︾粏鎻忚堪',
+ `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍥剧墖鍦板潃',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 浜у搧 SIP';
+
+-- ============ 琛細mes_md_product_sop锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_md_product_sop`;
+CREATE TABLE `mes_md_product_sop` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡浜у搧缂栧彿',
+ `sort` int DEFAULT NULL COMMENT '鎺掑垪椤哄簭',
+ `process_id` bigint DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
+ `title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏍囬',
+ `description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璇︾粏鎻忚堪',
+ `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍥剧墖鍦板潃',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 浜у搧 SOP';
+
+-- ============ 琛細mes_md_unit_measure锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_md_unit_measure`;
+CREATE TABLE `mes_md_unit_measure` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍗曚綅缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍗曚綅鍚嶇О',
+ `primary_flag` bit(1) DEFAULT b'0' COMMENT '鏄惁涓诲崟浣�',
+ `primary_id` bigint DEFAULT NULL COMMENT '涓诲崟浣嶇紪鍙�',
+ `change_rate` decimal(24,6) DEFAULT NULL COMMENT '涓庝富鍗曚綅鎹㈢畻姣斾緥',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 璁¢噺鍗曚綅';
+
+-- ============ 琛細mes_md_vendor锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_md_vendor`;
+CREATE TABLE `mes_md_vendor` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '渚涘簲鍟嗙紪鐮�',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '渚涘簲鍟嗗悕绉�',
+ `nickname` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '渚涘簲鍟嗙畝绉�',
+ `english_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '渚涘簲鍟嗚嫳鏂囧悕绉�',
+ `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '渚涘簲鍟嗙畝浠�',
+ `logo` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '渚涘簲鍟哃OGO鍦板潃',
+ `level` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '渚涘簲鍟嗙瓑绾�',
+ `score` int DEFAULT NULL COMMENT '渚涘簲鍟嗚瘎鍒�',
+ `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '渚涘簲鍟嗗湴鍧�',
+ `website` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '渚涘簲鍟嗗畼缃戝湴鍧�',
+ `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '渚涘簲鍟嗛偖绠卞湴鍧�',
+ `telephone` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '渚涘簲鍟嗙數璇�',
+ `contact1_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑱旂郴浜�1',
+ `contact1_telephone` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑱旂郴浜�1-鐢佃瘽',
+ `contact1_email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑱旂郴浜�1-閭',
+ `contact2_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑱旂郴浜�2',
+ `contact2_telephone` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑱旂郴浜�2-鐢佃瘽',
+ `contact2_email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑱旂郴浜�2-閭',
+ `credit_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '缁熶竴绀句細淇$敤浠g爜',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 渚涘簲鍟�';
+
+-- ============ 琛細mes_md_workshop锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_md_workshop`;
+CREATE TABLE `mes_md_workshop` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '杞﹂棿缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '杞﹂棿鍚嶇О',
+ `area` decimal(24,6) DEFAULT NULL COMMENT '闈㈢Н锛堝钩鏂圭背锛�',
+ `charge_user_id` bigint DEFAULT NULL COMMENT '璐熻矗浜虹敤鎴风紪鍙�',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 杞﹂棿';
+
+-- ============ 琛細mes_md_workstation锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_md_workstation`;
+CREATE TABLE `mes_md_workstation` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鐮�',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宸ヤ綔绔欏悕绉�',
+ `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宸ヤ綔绔欏湴鐐�',
+ `workshop_id` bigint DEFAULT NULL COMMENT '鎵�鍦ㄨ溅闂寸紪鍙�',
+ `process_id` bigint DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
+ `warehouse_id` bigint DEFAULT NULL COMMENT '绾胯竟搴撶紪鍙�',
+ `location_id` bigint DEFAULT NULL COMMENT '搴撳尯缂栧彿',
+ `area_id` bigint DEFAULT NULL COMMENT '搴撲綅缂栧彿',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 宸ヤ綔绔�';
+
+-- ============ 琛細mes_md_workstation_machine锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_md_workstation_machine`;
+CREATE TABLE `mes_md_workstation_machine` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `workstation_id` bigint DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
+ `machinery_id` bigint DEFAULT NULL COMMENT '璁惧缂栧彿',
+ `quantity` int DEFAULT NULL COMMENT '鏁伴噺',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 宸ヤ綔绔欒澶囪祫婧�';
+
+-- ============ 琛細mes_md_workstation_tool锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_md_workstation_tool`;
+CREATE TABLE `mes_md_workstation_tool` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `workstation_id` bigint DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
+ `tool_type_id` bigint DEFAULT NULL COMMENT '宸ュ叿绫诲瀷缂栧彿',
+ `quantity` int DEFAULT NULL COMMENT '鏁伴噺',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 宸ヤ綔绔欏伐瑁呭す鍏疯祫婧�';
+
+-- ============ 琛細mes_md_workstation_worker锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_md_workstation_worker`;
+CREATE TABLE `mes_md_workstation_worker` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `workstation_id` bigint DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
+ `post_id` bigint DEFAULT NULL COMMENT '宀椾綅缂栧彿',
+ `quantity` int DEFAULT NULL COMMENT '鏁伴噺',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 宸ヤ綔绔欎汉鍔涜祫婧�';
+
+-- ============ 琛細mes_pd_archive锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pd_archive`;
+CREATE TABLE `mes_pd_archive` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `archive_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '褰掓。缂栧彿',
+ `project_id` bigint NOT NULL COMMENT '璁捐椤圭洰ID',
+ `archiver` bigint DEFAULT NULL COMMENT '褰掓。浜�',
+ `archive_status` tinyint DEFAULT NULL COMMENT '褰掓。鐘舵��',
+ `archive_time` datetime DEFAULT NULL COMMENT '褰掓。鏃堕棿',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='MES 褰掓。鍙拌处';
+
+-- ============ 琛細mes_pd_document锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pd_document`;
+CREATE TABLE `mes_pd_document` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `project_id` bigint NOT NULL COMMENT '璁捐椤圭洰ID',
+ `document_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '璧勬枡绫诲瀷',
+ `document_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '璧勬枡鍚嶇О',
+ `document_version` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鐗堟湰',
+ `file_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鏂囦欢鍚�',
+ `upload_user_id` bigint DEFAULT NULL COMMENT '涓婁紶浜�',
+ `upload_time` datetime DEFAULT NULL COMMENT '涓婁紶鏃堕棿',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='MES 璁捐璧勬枡';
+
+-- ============ 琛細mes_pd_document_audit锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pd_document_audit`;
+CREATE TABLE `mes_pd_document_audit` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `audit_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '瀹℃牳鍗曞彿',
+ `document_id` bigint NOT NULL COMMENT '璧勬枡ID',
+ `document_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '璧勬枡鍚嶇О锛堝啑浣欙級',
+ `document_version` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '璧勬枡鐗堟湰锛堝啑浣欙級',
+ `reviewer` bigint DEFAULT NULL COMMENT '瀹℃牳浜�',
+ `audit_status` tinyint DEFAULT NULL COMMENT '瀹℃牳鐘舵��',
+ `audit_time` datetime DEFAULT NULL COMMENT '瀹℃牳鏃堕棿',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='MES 璧勬枡瀹℃牳';
+
+-- ============ 琛細mes_pd_process_param锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pd_process_param`;
+CREATE TABLE `mes_pd_process_param` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `param_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鍙傛暟缂栫爜',
+ `param_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鍙傛暟鍚嶇О',
+ `param_type` tinyint DEFAULT NULL COMMENT '鍙傛暟绫诲瀷锛堝瓧鍏� mes_pd_process_param_type锛�',
+ `unit_measure_id` bigint DEFAULT NULL COMMENT '璁¢噺鍗曚綅ID锛堝叧鑱� mes_md_unit_measure锛�',
+ `required` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁蹇呭~',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='MES 宸ヨ壓鍙傛暟';
+
+-- ============ 琛細mes_pd_process_param_template锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pd_process_param_template`;
+CREATE TABLE `mes_pd_process_param_template` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `template_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '妯℃澘缂栫爜',
+ `template_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '妯℃澘鍚嶇О',
+ `template_type` tinyint DEFAULT NULL COMMENT '妯℃澘绫诲瀷锛堝瓧鍏� mes_pd_process_param_template_type锛�',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='MES 宸ヨ壓鍙傛暟妯℃澘';
+
+-- ============ 琛細mes_pd_process_param_template_detail锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pd_process_param_template_detail`;
+CREATE TABLE `mes_pd_process_param_template_detail` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `template_id` bigint NOT NULL COMMENT '妯℃澘ID锛堝叧鑱� mes_pd_process_param_template锛�',
+ `process_param_id` bigint DEFAULT NULL COMMENT '宸ヨ壓鍙傛暟ID锛堜粎浣滄函婧愶紝涓嶅奖鍝嶅揩鐓у�硷級',
+ `param_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鍙傛暟缂栫爜锛堝揩鐓э級',
+ `param_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鍙傛暟鍚嶇О锛堝揩鐓э級',
+ `param_type` tinyint DEFAULT NULL COMMENT '鍙傛暟绫诲瀷锛堝揩鐓э級',
+ `unit_measure_id` bigint DEFAULT NULL COMMENT '璁¢噺鍗曚綅ID锛堝揩鐓э級',
+ `required` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁蹇呭~锛堝揩鐓э級',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞锛堝揩鐓э級',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='MES 宸ヨ壓鍙傛暟妯℃澘鏄庣粏';
+
+-- ============ 琛細mes_pd_project锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pd_project`;
+CREATE TABLE `mes_pd_project` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `task_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '浠诲姟缂栫爜',
+ `task_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '浠诲姟鍚嶇О',
+ `product_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '浜у搧缂栫爜',
+ `product_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '浜у搧鍚嶇О',
+ `version` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鐗堟湰鍙�',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0=寰呭彂甯� 1=寰呬笂浼� 2=寰呭鏍� 3=寰呭綊妗� 4=宸插綊妗o級',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'BPM 娴佺▼瀹炰緥缂栧彿',
+ `process_definition_key` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT 'BPM 娴佺▼瀹氫箟 Key',
+ `chief_designer` bigint DEFAULT NULL COMMENT '涓昏璁″笀',
+ `reviewer` bigint DEFAULT NULL COMMENT '瀹℃牳浜�',
+ `plan_finish_time` datetime DEFAULT NULL COMMENT '璁″垝瀹屾垚鏃堕棿',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='MES 璁捐椤圭洰';
+
+-- ============ 琛細mes_pro_andon_config锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_andon_config`;
+CREATE TABLE `mes_pro_andon_config` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍛煎彨鍘熷洜',
+ `level` int DEFAULT NULL COMMENT '绾у埆',
+ `handler_role_id` bigint DEFAULT NULL COMMENT '澶勭疆浜鸿鑹茬紪鍙�',
+ `handler_user_id` bigint DEFAULT NULL COMMENT '澶勭疆浜虹紪鍙�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 瀹夌伅鍛煎彨閰嶇疆';
+
+-- ============ 琛細mes_pro_andon_record锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_andon_record`;
+CREATE TABLE `mes_pro_andon_record` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `config_id` bigint DEFAULT NULL COMMENT '瀹夌伅閰嶇疆缂栧彿',
+ `workstation_id` bigint DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
+ `user_id` bigint DEFAULT NULL COMMENT '鍙戣捣鐢ㄦ埛缂栧彿',
+ `work_order_id` bigint DEFAULT NULL COMMENT '鐢熶骇宸ュ崟缂栧彿',
+ `process_id` bigint DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
+ `reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍛煎彨鍘熷洜',
+ `level` int DEFAULT NULL COMMENT '绾у埆',
+ `status` int DEFAULT NULL COMMENT '澶勭疆鐘舵��',
+ `handle_time` datetime DEFAULT NULL COMMENT '澶勭疆鏃堕棿',
+ `handler_user_id` bigint DEFAULT NULL COMMENT '澶勭疆浜虹紪鍙�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 瀹夌伅鍛煎彨璁板綍';
+
+-- ============ 琛細mes_pro_bag_code锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_bag_code`;
+CREATE TABLE `mes_pro_bag_code` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `uuid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鐢熸垚缁� UUID锛堟爣璁板悓涓�娆$敓鎴愮殑鏁版嵁鍖咃級',
+ `code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '琚嬬爜锛堜簩缁寸爜鍐呭锛氭壒娆″彿-琚嬪簭鍙凤紝鍏ㄥ眬鍞竴锛�',
+ `bag_no` int NOT NULL COMMENT '鎵规鍐呰搴忓彿',
+ `batch_id` bigint NOT NULL COMMENT '鐢熶骇鎵规缂栧彿锛屽叧鑱� mes_pro_batch.id',
+ `batch_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鎵规鍙凤紙鍐椾綑锛屼究浜庡睍绀猴級',
+ `pallet_id` bigint DEFAULT NULL COMMENT '缁戝畾鎵樼洏缂栧彿锛屽叧鑱� mes_pro_pallet.id',
+ `pallet_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鎵樼洏鐮侊紙鍐椾綑锛屼究浜庡睍绀猴級',
+ `status` tinyint NOT NULL DEFAULT '10' COMMENT '鐘舵�侊紙瀛楀吀 mes_pro_bag_code_status锛�10 宸茬敓鎴� 20 宸插鍑哄嵃鍒� 30 宸蹭綔搴燂級',
+ `print_time` datetime DEFAULT NULL COMMENT '瀵煎嚭锛堜氦浠樺嵃鍒凤級鏃堕棿',
+ `cancel_time` datetime DEFAULT NULL COMMENT '浣滃簾鏃堕棿',
+ `cancel_reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '浣滃簾鍘熷洜',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_code` (`code`) USING BTREE,
+ KEY `idx_batch_id` (`batch_id`) USING BTREE,
+ KEY `idx_uuid` (`uuid`) USING BTREE,
+ KEY `idx_pallet_id` (`pallet_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='MES 琚嬬爜璧嬬爜锛堜竴琚嬩竴鐮侊級';
+
+-- ============ 琛細mes_pro_bag_code_replace锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_bag_code_replace`;
+CREATE TABLE `mes_pro_bag_code_replace` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `replace_uuid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鏇挎崲缁� UUID',
+ `batch_id` bigint NOT NULL COMMENT '鐢熶骇鎵规缂栧彿',
+ `batch_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鐢熶骇鎵规鍙�',
+ `old_bag_code_id` bigint NOT NULL COMMENT '鏃ц鐮佺紪鍙�',
+ `old_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鏃ц鐮�',
+ `old_bag_no` int NOT NULL COMMENT '鏃ц搴忓彿',
+ `old_status` tinyint NOT NULL COMMENT '鏃ц鐮佷綔搴熷墠鐘舵��',
+ `old_pallet_id` bigint DEFAULT NULL COMMENT '鏃ц鐮佸師鎵樼洏缂栧彿',
+ `old_pallet_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鏃ц鐮佸師鎵樼洏鐮�',
+ `new_bag_code_id` bigint NOT NULL COMMENT '鏂拌鐮佺紪鍙�',
+ `new_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鏂拌鐮�',
+ `new_bag_no` int NOT NULL COMMENT '鏂拌搴忓彿',
+ `reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鏇挎崲鍘熷洜',
+ `replace_time` datetime NOT NULL COMMENT '鏇挎崲鏃堕棿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_old_bag_code_id` (`old_bag_code_id`) USING BTREE,
+ UNIQUE KEY `uk_new_bag_code_id` (`new_bag_code_id`) USING BTREE,
+ KEY `idx_replace_uuid` (`replace_uuid`) USING BTREE,
+ KEY `idx_batch_id` (`batch_id`) USING BTREE,
+ KEY `idx_old_code` (`old_code`) USING BTREE,
+ KEY `idx_new_code` (`new_code`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='MES 琚嬬爜鏇挎崲璁板綍';
+
+-- ============ 琛細mes_pro_batch锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_batch`;
+CREATE TABLE `mes_pro_batch` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鎵规鍙凤紙鑷姩鐢熸垚锛氬墠缂�+鏃ユ湡+浜х嚎+娴佹按鍙凤級',
+ `item_id` bigint DEFAULT NULL COMMENT '鍝佺锛堢墿鏂欙級缂栧彿锛屽叧鑱� mdm_item.id',
+ `line_id` bigint DEFAULT NULL COMMENT '浜х嚎缂栧彿锛屽叧鑱� mes_pro_line.id',
+ `line_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '浜х嚎缂栫爜锛堟墜濉紝鍙備笌鎵规鍙风敓鎴愶級',
+ `line_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '浜х嚎鍚嶇О锛堟墜濉級',
+ `produce_date` datetime DEFAULT NULL COMMENT '鐢熶骇鏃ユ湡',
+ `plan_quantity` decimal(24,6) DEFAULT NULL COMMENT '璁″垝鏁伴噺',
+ `owner_user_id` bigint DEFAULT NULL COMMENT '璐d换浜虹敤鎴风紪鍙凤紙璐d换钀藉疄鍒颁汉锛夛紝鍏宠仈 system_users.id',
+ `bag_quantity` int NOT NULL DEFAULT '0' COMMENT '宸茬敓鎴愯鐮佹暟閲忥紙涓�琚嬩竴鐮侊級',
+ `pallet_quantity` int NOT NULL DEFAULT '0' COMMENT '宸茬敓鎴愭墭鐩樼爜鏁伴噺',
+ `status` tinyint NOT NULL DEFAULT '10' COMMENT '鎵规鐘舵�侊紙瀛楀吀 mes_pro_batch_status锛�10 鑽夌 20 鐢熶骇涓� 30 宸插畬鎴� 40 宸蹭綔搴燂級',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_code` (`code`) USING BTREE,
+ KEY `idx_status` (`status`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇鎵规';
+
+-- ============ 琛細mes_pro_batch_worker锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_batch_worker`;
+CREATE TABLE `mes_pro_batch_worker` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `batch_id` bigint NOT NULL COMMENT '鐢熶骇鎵规缂栧彿锛屽叧鑱� mes_pro_batch.id',
+ `user_id` bigint NOT NULL COMMENT '鐢熶骇浜哄憳鐢ㄦ埛缂栧彿锛屽叧鑱� system_users.id',
+ `worker_type` tinyint NOT NULL COMMENT '宀椾綅绫诲瀷锛堝瓧鍏� mes_pro_batch_worker_type锛�10 缁勯暱 20 鎿嶄綔宸� 30 鍖呰宸� 40 璐ㄦ鍛� 50 鍏朵粬锛�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_batch_id` (`batch_id`) USING BTREE,
+ KEY `idx_user_id` (`user_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇鎵规浜哄憳閰嶇疆';
+
+-- ============ 琛細mes_pro_card锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_card`;
+CREATE TABLE `mes_pro_card` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴佽浆鍗$紪鐮�',
+ `work_order_id` bigint DEFAULT NULL COMMENT '鐢熶骇宸ュ崟缂栧彿',
+ `item_id` bigint DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
+ `batch_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵规鍙�',
+ `transfered_quantity` decimal(24,6) DEFAULT NULL COMMENT '娴佽浆鏁伴噺',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇娴佽浆鍗�';
+
+-- ============ 琛細mes_pro_card_process锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_card_process`;
+CREATE TABLE `mes_pro_card_process` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `card_id` bigint DEFAULT NULL COMMENT '娴佽浆鍗$紪鍙�',
+ `sort` int DEFAULT NULL COMMENT '搴忓彿',
+ `process_id` bigint DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
+ `input_time` datetime DEFAULT NULL COMMENT '杩涘叆宸ュ簭鏃堕棿',
+ `output_time` datetime DEFAULT NULL COMMENT '鍑哄伐搴忔椂闂�',
+ `input_quantity` decimal(24,6) DEFAULT NULL COMMENT '鎶曞叆鏁伴噺',
+ `output_quantity` decimal(24,6) DEFAULT NULL COMMENT '浜у嚭鏁伴噺',
+ `unqualified_quantity` decimal(24,6) DEFAULT NULL COMMENT '涓嶅悎鏍煎搧鏁伴噺',
+ `workstation_id` bigint DEFAULT NULL COMMENT '宸ヤ綅缂栧彿',
+ `user_id` bigint DEFAULT NULL COMMENT '鎿嶄綔浜虹紪鍙�',
+ `ipqc_id` bigint DEFAULT NULL COMMENT '杩囩▼妫�楠屽崟缂栧彿',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 娴佽浆鍗″伐搴忚褰�';
+
+-- ============ 琛細mes_pro_feedback锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_feedback`;
+CREATE TABLE `mes_pro_feedback` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎶ュ伐鍗曠紪鍙�',
+ `type` int DEFAULT NULL COMMENT '鎶ュ伐绫诲瀷',
+ `channel` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎶ュ伐閫斿緞',
+ `feedback_time` datetime DEFAULT NULL COMMENT '鎶ュ伐鏃堕棿',
+ `workstation_id` bigint DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
+ `route_id` bigint DEFAULT NULL COMMENT '宸ヨ壓璺嚎缂栧彿',
+ `process_id` bigint DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
+ `work_order_id` bigint DEFAULT NULL COMMENT '鐢熶骇宸ュ崟缂栧彿',
+ `task_id` bigint DEFAULT NULL COMMENT '鐢熶骇浠诲姟缂栧彿',
+ `item_id` bigint DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
+ `expire_date` datetime DEFAULT NULL COMMENT '杩囨湡鏃ユ湡',
+ `lot_number` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐢熶骇鎵瑰彿',
+ `scheduled_quantity` decimal(24,6) DEFAULT NULL COMMENT '鎺掍骇鏁伴噺',
+ `feedback_quantity` decimal(24,6) DEFAULT NULL COMMENT '鏈鎶ュ伐鏁伴噺',
+ `qualified_quantity` decimal(24,6) DEFAULT NULL COMMENT '鍚堟牸鍝佹暟閲�',
+ `unqualified_quantity` decimal(24,6) DEFAULT NULL COMMENT '涓嶈壇鍝佹暟閲�',
+ `uncheck_quantity` decimal(24,6) DEFAULT NULL COMMENT '寰呮娴嬫暟閲�',
+ `labor_scrap_quantity` decimal(24,6) DEFAULT NULL COMMENT '宸ュ簾鏁伴噺',
+ `material_scrap_quantity` decimal(24,6) DEFAULT NULL COMMENT '鏂欏簾鏁伴噺',
+ `other_scrap_quantity` decimal(24,6) DEFAULT NULL COMMENT '鍏朵粬搴熷搧鏁伴噺',
+ `feedback_user_id` bigint DEFAULT NULL COMMENT '鎶ュ伐鐢ㄦ埛缂栧彿',
+ `approve_user_id` bigint DEFAULT NULL COMMENT '瀹℃牳鐢ㄦ埛缂栧彿',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'BPM 娴佺▼瀹炰緥缂栧彿',
+ `process_definition_key` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'BPM 娴佺▼瀹氫箟 Key',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_task_id` (`task_id`) USING BTREE,
+ KEY `idx_work_order_id` (`work_order_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇鎶ュ伐';
+
+-- ============ 琛細mes_pro_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_line`;
+CREATE TABLE `mes_pro_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '浜х嚎缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '浜х嚎鍚嶇О',
+ `status` int NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0鍚敤 1鍋滅敤锛�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='浜х嚎缁存姢';
+
+-- ============ 琛細mes_pro_mps锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_mps`;
+CREATE TABLE `mes_pro_mps` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'MPS 缂栫爜',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0=鑽夌 1=宸蹭笅鍙� 2=宸插畬鎴� 3=宸插彇娑堬級',
+ `sale_order_id` bigint DEFAULT NULL COMMENT '閿�鍞鍗旾D',
+ `sale_order_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '閿�鍞鍗曞彿',
+ `sale_order_item_id` bigint DEFAULT NULL COMMENT '閿�鍞鍗曟槑缁咺D',
+ `product_id` bigint NOT NULL COMMENT '浜у搧缂栧彿',
+ `quantity` decimal(24,6) NOT NULL COMMENT '璁″垝鐢熶骇鏁伴噺',
+ `quantity_produced` decimal(24,6) DEFAULT '0.000000' COMMENT '宸茬敓浜ф暟閲�',
+ `unit_measure_id` bigint DEFAULT NULL COMMENT '璁¢噺鍗曚綅ID',
+ `client_id` bigint DEFAULT NULL COMMENT '瀹㈡埛缂栧彿',
+ `request_date` datetime DEFAULT NULL COMMENT '闇�姹傛棩鏈�',
+ `issue_date` datetime DEFAULT NULL COMMENT '涓嬪彂鏃ユ湡',
+ `finish_date` datetime DEFAULT NULL COMMENT '瀹屾垚鏃ユ湡',
+ `work_order_id` bigint DEFAULT NULL COMMENT '鐢熶骇宸ュ崟ID',
+ `work_order_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鐢熶骇宸ュ崟缂栫爜',
+ `merge_flag` tinyint DEFAULT '0' COMMENT '鏄惁鍚堝苟涓嬪彂锛�0=鍚� 1=鏄級',
+ `merge_batch_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鍚堝苟鎵规鍙�',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_sale_order_item_id` (`sale_order_item_id`) USING BTREE,
+ KEY `idx_product_id` (`product_id`) USING BTREE,
+ KEY `idx_status` (`status`) USING BTREE,
+ KEY `idx_merge_batch_no` (`merge_batch_no`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇涓昏鍒�';
+
+-- ============ 琛細mes_pro_mps_merge_item锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_mps_merge_item`;
+CREATE TABLE `mes_pro_mps_merge_item` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `merge_batch_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鍚堝苟鎵规鍙�',
+ `mps_id` bigint NOT NULL COMMENT 'MPS 缂栧彿',
+ `work_order_id` bigint DEFAULT NULL COMMENT '鐢熸垚鐨勭敓浜у伐鍗旾D',
+ `quantity` decimal(24,6) NOT NULL COMMENT '鍒嗛厤鏁伴噺',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_merge_batch_no` (`merge_batch_no`) USING BTREE,
+ KEY `idx_mps_id` (`mps_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='MPS 鍚堝苟涓嬪彂鏄庣粏';
+
+-- ============ 琛細mes_pro_pallet锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_pallet`;
+CREATE TABLE `mes_pro_pallet` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鎵樼洏鐮侊紙鎵规鍙�-P+鎵樼洏搴忓彿锛屽叏灞�鍞竴锛�',
+ `batch_id` bigint NOT NULL COMMENT '鐢熶骇鎵规缂栧彿锛屽叧鑱� mes_pro_batch.id',
+ `batch_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鎵规鍙凤紙鍐椾綑锛屼究浜庡睍绀猴級',
+ `pallet_no` int NOT NULL COMMENT '鎵规鍐呮墭鐩樺簭鍙�',
+ `capacity` int DEFAULT NULL COMMENT '鍙琚嬫暟锛堣/鎵樼洏锛�',
+ `bag_count` int NOT NULL DEFAULT '0' COMMENT '宸茬粦瀹氳鐮佹暟閲�',
+ `status` tinyint NOT NULL DEFAULT '10' COMMENT '鐘舵�侊紙瀛楀吀 mes_pro_pallet_status锛�10 鍚敤 20 浣滃簾锛�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_code` (`code`) USING BTREE,
+ KEY `idx_batch_id` (`batch_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鎵樼洏鐮�';
+
+-- ============ 琛細mes_pro_process锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_process`;
+CREATE TABLE `mes_pro_process` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宸ュ簭缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宸ュ簭鍚嶇О',
+ `attention` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宸ヨ壓瑕佹眰',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇宸ュ簭';
+
+-- ============ 琛細mes_pro_process_content锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_process_content`;
+CREATE TABLE `mes_pro_process_content` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `process_id` bigint DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
+ `sort` int DEFAULT NULL COMMENT '椤哄簭缂栧彿',
+ `content` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '姝ラ璇存槑',
+ `device` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '杈呭姪璁惧',
+ `material` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '杈呭姪鏉愭枡',
+ `doc_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏉愭枡鏂囨。 URL',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇宸ュ簭鍐呭';
+
+-- ============ 琛細mes_pro_process_param锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_process_param`;
+CREATE TABLE `mes_pro_process_param` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `process_id` bigint NOT NULL COMMENT '宸ュ簭缂栧彿锛堝叧鑱� mes_pro_process锛�',
+ `process_param_id` bigint NOT NULL COMMENT '宸ヨ壓鍙傛暟缂栧彿锛堝叧鑱� mes_pd_process_param锛�',
+ `required` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁蹇呭~',
+ `sort` int DEFAULT NULL COMMENT '鎺掑簭',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_process_id` (`process_id`) USING BTREE,
+ KEY `idx_process_param_id` (`process_param_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 宸ュ簭-宸ヨ壓鍙傛暟缁戝畾';
+
+-- ============ 琛細mes_pro_route锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_route`;
+CREATE TABLE `mes_pro_route` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宸ヨ壓璺嚎缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宸ヨ壓璺嚎鍚嶇О',
+ `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宸ヨ壓璺嚎璇存槑',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 宸ヨ壓璺嚎';
+
+-- ============ 琛細mes_pro_route_process锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_route_process`;
+CREATE TABLE `mes_pro_route_process` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `route_id` bigint DEFAULT NULL COMMENT '宸ヨ壓璺嚎缂栧彿',
+ `process_id` bigint DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
+ `param_template_id` bigint DEFAULT NULL COMMENT '宸ヨ壓鍙傛暟妯℃澘缂栧彿',
+ `sort` int DEFAULT NULL COMMENT '搴忓彿',
+ `next_process_id` bigint DEFAULT NULL COMMENT '涓嬩竴閬撳伐搴忕紪鍙�',
+ `link_type` int DEFAULT NULL COMMENT '涓庝笅涓�閬撳伐搴忓叧绯�',
+ `prepare_time` int DEFAULT NULL COMMENT '鍑嗗鏃堕棿锛堝垎閽燂級',
+ `wait_time` int DEFAULT NULL COMMENT '绛夊緟鏃堕棿锛堝垎閽燂級',
+ `color_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐢樼壒鍥炬樉绀洪鑹�',
+ `key_flag` bit(1) DEFAULT b'0' COMMENT '鏄惁鍏抽敭宸ュ簭',
+ `check_flag` bit(1) DEFAULT b'0' COMMENT '鏄惁璐ㄦ宸ュ簭',
+ `backflush_flag` bit(1) DEFAULT b'1' COMMENT '鏄惁鍊掑啿',
+ `output_item_id` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '浜у嚭浜у搧鐗╂枡缂栧彿锛屽涓敤閫楀彿鍒嗛殧',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_output_item_id` (`output_item_id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 宸ヨ壓璺嚎宸ュ簭';
+
+-- ============ 琛細mes_pro_route_product锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_route_product`;
+CREATE TABLE `mes_pro_route_product` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `route_id` bigint DEFAULT NULL COMMENT '宸ヨ壓璺嚎缂栧彿',
+ `item_id` bigint DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
+ `quantity` int DEFAULT NULL COMMENT '鐢熶骇鏁伴噺',
+ `production_time` decimal(24,6) DEFAULT NULL COMMENT '鐢熶骇鐢ㄦ椂',
+ `time_unit_type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏃堕棿鍗曚綅',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 宸ヨ壓璺嚎浜у搧';
+
+-- ============ 琛細mes_pro_route_product_bom锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_route_product_bom`;
+CREATE TABLE `mes_pro_route_product_bom` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `route_id` bigint DEFAULT NULL COMMENT '宸ヨ壓璺嚎缂栧彿',
+ `process_id` bigint DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
+ `product_id` bigint DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
+ `item_id` bigint DEFAULT NULL COMMENT 'BOM 鐗╂枡缂栧彿',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鐢ㄦ枡姣斾緥',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 宸ヨ壓璺嚎浜у搧 BOM';
+
+-- ============ 琛細mes_pro_task锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_task`;
+CREATE TABLE `mes_pro_task` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '浠诲姟缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '浠诲姟鍚嶇О',
+ `work_order_id` bigint DEFAULT NULL COMMENT '鐢熶骇宸ュ崟缂栧彿',
+ `workstation_id` bigint DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
+ `route_id` bigint DEFAULT NULL COMMENT '宸ヨ壓璺嚎缂栧彿',
+ `process_id` bigint DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
+ `param_template_id` bigint DEFAULT NULL COMMENT '宸ヨ壓鍙傛暟妯℃澘缂栧彿',
+ `item_id` bigint DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鎺掍骇鏁伴噺',
+ `produced_quantity` decimal(24,6) DEFAULT NULL COMMENT '宸茬敓浜ф暟閲�',
+ `qualify_quantity` decimal(24,6) DEFAULT NULL COMMENT '鍚堟牸鍝佹暟閲�',
+ `unqualify_quantity` decimal(24,6) DEFAULT NULL COMMENT '涓嶈壇鍝佹暟閲�',
+ `changed_quantity` decimal(24,6) DEFAULT NULL COMMENT '璋冩暣鏁伴噺',
+ `client_id` bigint DEFAULT NULL COMMENT '瀹㈡埛缂栧彿',
+ `start_time` datetime DEFAULT NULL COMMENT '寮�濮嬬敓浜ф椂闂�',
+ `duration` int DEFAULT NULL COMMENT '鐢熶骇鏃堕暱',
+ `end_time` datetime DEFAULT NULL COMMENT '缁撴潫鐢熶骇鏃堕棿',
+ `color_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐢樼壒鍥炬樉绀洪鑹�',
+ `finish_date` datetime DEFAULT NULL COMMENT '瀹屾垚鏃ユ湡',
+ `cancel_date` datetime DEFAULT NULL COMMENT '鍙栨秷鏃ユ湡',
+ `first_feedback_time` datetime DEFAULT NULL COMMENT '棣栨鎶ュ伐鏃堕棿',
+ `last_feedback_time` datetime DEFAULT NULL COMMENT '鏈�杩戞姤宸ユ椂闂�',
+ `status` int DEFAULT NULL COMMENT '浠诲姟鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_work_order_process` (`work_order_id`,`process_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇浠诲姟';
+
+-- ============ 琛細mes_pro_task_assignee锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_task_assignee`;
+CREATE TABLE `mes_pro_task_assignee` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `task_id` bigint DEFAULT NULL COMMENT '鐢熶骇浠诲姟 ID',
+ `user_id` bigint DEFAULT NULL COMMENT '绯荤粺鐢ㄦ埛 ID (鎸囧畾鎶ュ伐浜哄憳)',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_task_id` (`task_id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='鐢熶骇浠诲姟鎸囧畾鎶ュ伐浜哄憳琛�';
+
+-- ============ 琛細mes_pro_task_issue锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_task_issue`;
+CREATE TABLE `mes_pro_task_issue` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `task_id` bigint DEFAULT NULL COMMENT '鐢熶骇浠诲姟缂栧彿',
+ `work_order_id` bigint DEFAULT NULL COMMENT '鐢熶骇宸ュ崟缂栧彿',
+ `workstation_id` bigint DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
+ `source_doc_type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁绫诲瀷',
+ `source_doc_id` bigint DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
+ `source_line_id` bigint DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁琛岀紪鍙�',
+ `source_doc_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栫爜',
+ `batch_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎶曟枡鎵规',
+ `item_id` bigint DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
+ `unit_measure_id` bigint DEFAULT NULL COMMENT '鍗曚綅缂栧彿',
+ `issued_quantity` decimal(24,6) DEFAULT NULL COMMENT '鎬绘姇鏂欐暟閲�',
+ `available_quantity` decimal(24,6) DEFAULT NULL COMMENT '褰撳墠鍙敤鏁伴噺',
+ `used_quantity` decimal(24,6) DEFAULT NULL COMMENT '褰撳墠浣跨敤鏁伴噺',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇浠诲姟鎶曟枡';
+
+-- ============ 琛細mes_pro_task_pause_record锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_task_pause_record`;
+CREATE TABLE `mes_pro_task_pause_record` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `task_id` bigint NOT NULL COMMENT '浠诲姟缂栧彿',
+ `work_order_id` bigint DEFAULT NULL COMMENT '宸ュ崟缂栧彿',
+ `workstation_id` bigint DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
+ `reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍋滃伐鍘熷洜',
+ `pause_time` datetime NOT NULL COMMENT '鍋滃伐鏃堕棿',
+ `pause_user_id` bigint NOT NULL COMMENT '鍋滃伐鎿嶄綔浜篒D',
+ `resume_time` datetime DEFAULT NULL COMMENT '澶嶅伐鏃堕棿',
+ `resume_user_id` bigint DEFAULT NULL COMMENT '澶嶅伐鎿嶄綔浜篒D',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_task_id` (`task_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鐢熶骇浠诲姟鍋滃伐璁板綍琛�';
+
+-- ============ 琛細mes_pro_work_order锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_work_order`;
+CREATE TABLE `mes_pro_work_order` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宸ュ崟缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宸ュ崟鍚嶇О',
+ `type` int DEFAULT NULL COMMENT '宸ュ崟绫诲瀷',
+ `order_source_type` int DEFAULT NULL COMMENT '鏉ユ簮绫诲瀷',
+ `order_source_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
+ `product_id` bigint DEFAULT NULL COMMENT '浜у搧缂栧彿',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鐢熶骇鏁伴噺',
+ `quantity_produced` decimal(24,6) DEFAULT NULL COMMENT '宸茬敓浜ф暟閲�',
+ `quantity_changed` decimal(24,6) DEFAULT NULL COMMENT '璋冩暣鏁伴噺',
+ `quantity_scheduled` decimal(24,6) DEFAULT NULL COMMENT '宸叉帓浜ф暟閲�',
+ `client_id` bigint DEFAULT NULL COMMENT '瀹㈡埛缂栧彿',
+ `vendor_id` bigint DEFAULT NULL COMMENT '渚涘簲鍟嗙紪鍙�',
+ `batch_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵规鍙�',
+ `route_id` bigint DEFAULT NULL COMMENT '宸ヨ壓璺嚎缂栧彿',
+ `auto_finish_flag` tinyint(1) DEFAULT '1' COMMENT '鏄惁鑷姩瀹屾垚',
+ `request_date` datetime DEFAULT NULL COMMENT '闇�姹傛棩鏈�',
+ `parent_id` bigint DEFAULT NULL COMMENT '鐖跺伐鍗曠紪鍙�',
+ `finish_date` datetime DEFAULT NULL COMMENT '瀹屾垚鏃堕棿',
+ `cancel_date` datetime DEFAULT NULL COMMENT '鍙栨秷鏃堕棿',
+ `status` int DEFAULT NULL COMMENT '宸ュ崟鐘舵��',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'BPM 娴佺▼瀹炰緥缂栧彿',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `is_feedback_approve` tinyint(1) DEFAULT NULL COMMENT '鏄惁寮�鍚姤宸ュ鎵� (1: 寮�鍚�, 0/NULL: 鍏抽棴)',
+ `process_definition_key` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'BPM 娴佺▼瀹氫箟 Key',
+ `feedback_role` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎶ュ伐瑙掕壊 (澶氫釜瑙掕壊浠ラ�楀彿鍒嗛殧)',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇宸ュ崟';
+
+-- ============ 琛細mes_pro_work_order_bom锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_work_order_bom`;
+CREATE TABLE `mes_pro_work_order_bom` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `work_order_id` bigint DEFAULT NULL COMMENT '鐢熶骇宸ュ崟缂栧彿',
+ `process_id` bigint DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
+ `item_id` bigint DEFAULT NULL COMMENT 'BOM 鐗╂枡缂栧彿',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '棰勮浣跨敤閲�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇宸ュ崟 BOM';
+
+-- ============ 琛細mes_pro_work_order_param_record锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_work_order_param_record`;
+CREATE TABLE `mes_pro_work_order_param_record` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `work_order_id` bigint NOT NULL COMMENT '鐢熶骇宸ュ崟缂栧彿',
+ `template_id` bigint DEFAULT NULL COMMENT '鍙傛暟妯℃澘缂栧彿锛堝伐搴忕粦瀹氬弬鏁扮敓鎴愭椂涓虹┖锛�',
+ `template_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妯℃澘缂栫爜锛堝揩鐓э級',
+ `template_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妯℃澘鍚嶇О锛堝揩鐓э級',
+ `record_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璁板綍搴忓彿/鎵规鍙�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `task_id` int DEFAULT NULL,
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_work_order_id` (`work_order_id`) USING BTREE,
+ KEY `idx_mes_pro_work_order_param_record_task_id` (`task_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇宸ュ崟鍙傛暟璁板綍';
+
+-- ============ 琛細mes_pro_work_order_param_record_detail锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_work_order_param_record_detail`;
+CREATE TABLE `mes_pro_work_order_param_record_detail` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `record_id` bigint NOT NULL COMMENT '鍙傛暟璁板綍缂栧彿',
+ `template_detail_id` bigint DEFAULT NULL COMMENT '妯℃澘鏄庣粏缂栧彿锛堟函婧愮敤锛�',
+ `param_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍙傛暟缂栫爜锛堝揩鐓э級',
+ `param_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍙傛暟鍚嶇О锛堝揩鐓э級',
+ `param_type` tinyint DEFAULT NULL COMMENT '鍙傛暟绫诲瀷锛堝揩鐓э級',
+ `required` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁蹇呭~锛堝揩鐓э級',
+ `unit_measure_id` bigint DEFAULT NULL COMMENT '璁¢噺鍗曚綅缂栧彿锛堝揩鐓э級',
+ `param_value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍙傛暟鍊�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_record_id` (`record_id`) USING BTREE,
+ KEY `idx_mes_pro_work_order_param_record_detail_record_id` (`record_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇宸ュ崟鍙傛暟璁板綍鏄庣粏';
+
+-- ============ 琛細mes_pro_work_order_process锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_work_order_process`;
+CREATE TABLE `mes_pro_work_order_process` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `work_order_id` bigint DEFAULT NULL COMMENT '鐢熶骇宸ュ崟缂栧彿',
+ `process_id` bigint DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
+ `param_template_id` bigint DEFAULT NULL COMMENT '宸ヨ壓鍙傛暟妯℃澘缂栧彿',
+ `sort` int DEFAULT NULL COMMENT '搴忓彿',
+ `next_process_id` bigint DEFAULT NULL COMMENT '涓嬩竴閬撳伐搴忕紪鍙�',
+ `link_type` int DEFAULT NULL COMMENT '涓庝笅涓�閬撳伐搴忓叧绯�',
+ `prepare_time` int DEFAULT NULL COMMENT '鍑嗗鏃堕棿锛堝垎閽燂級',
+ `wait_time` int DEFAULT NULL COMMENT '绛夊緟鏃堕棿锛堝垎閽燂級',
+ `color_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鐢樼壒鍥炬樉绀洪鑹�',
+ `key_flag` bit(1) DEFAULT b'0' COMMENT '鏄惁鍏抽敭宸ュ簭',
+ `check_flag` bit(1) DEFAULT b'0' COMMENT '鏄惁璐ㄦ宸ュ簭',
+ `backflush_flag` bit(1) DEFAULT b'1' COMMENT '鏄惁鍊掑啿',
+ `output_item_id` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '浜у嚭浜у搧鐗╂枡缂栧彿锛屽涓敤閫楀彿鍒嗛殧',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_work_order_id` (`work_order_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇宸ュ崟宸ュ簭';
+
+-- ============ 琛細mes_pro_work_record锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_work_record`;
+CREATE TABLE `mes_pro_work_record` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `user_id` bigint DEFAULT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `workstation_id` bigint DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
+ `type` int DEFAULT NULL COMMENT '褰撳墠鐘舵��',
+ `clock_in_time` datetime DEFAULT NULL COMMENT '涓婂伐鏃堕棿',
+ `clock_out_time` datetime DEFAULT NULL COMMENT '涓嬪伐鏃堕棿',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢ㄦ埛宸ヤ綔绔欑粦瀹氬叧绯�';
+
+-- ============ 琛細mes_pro_work_record_log锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_pro_work_record_log`;
+CREATE TABLE `mes_pro_work_record_log` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `user_id` bigint DEFAULT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `workstation_id` bigint DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
+ `type` int DEFAULT NULL COMMENT '鎿嶄綔绫诲瀷',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 涓婁笅宸ヨ褰曟祦姘�';
+
+-- ============ 琛細mes_qc_defect锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_qc_defect`;
+CREATE TABLE `mes_qc_defect` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '缂洪櫡缂栫爜',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '缂洪櫡鎻忚堪',
+ `type` int DEFAULT NULL COMMENT '妫�娴嬮」绫诲瀷',
+ `level` int DEFAULT NULL COMMENT '缂洪櫡绛夌骇',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 缂洪櫡绫诲瀷';
+
+-- ============ 琛細mes_qc_defect_record锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_qc_defect_record`;
+CREATE TABLE `mes_qc_defect_record` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `qc_type` int DEFAULT NULL COMMENT '妫�楠岀被鍨�',
+ `qc_id` bigint DEFAULT NULL COMMENT '妫�楠屽崟缂栧彿',
+ `line_id` bigint DEFAULT NULL COMMENT '妫�楠岃缂栧彿',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '缂洪櫡鎻忚堪',
+ `level` int DEFAULT NULL COMMENT '缂洪櫡绛夌骇',
+ `quantity` int DEFAULT NULL COMMENT '缂洪櫡鏁伴噺',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 璐ㄦ缂洪櫡璁板綍';
+
+-- ============ 琛細mes_qc_indicator锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_qc_indicator`;
+CREATE TABLE `mes_qc_indicator` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妫�娴嬮」缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妫�娴嬮」鍚嶇О',
+ `type` int DEFAULT NULL COMMENT '妫�娴嬮」绫诲瀷',
+ `tool` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妫�娴嬪伐鍏�',
+ `result_type` int DEFAULT NULL COMMENT '缁撴灉鍊肩被鍨�',
+ `result_specification` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '缁撴灉鍊煎睘鎬�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 璐ㄦ鎸囨爣';
+
+-- ============ 琛細mes_qc_indicator_result锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_qc_indicator_result`;
+CREATE TABLE `mes_qc_indicator_result` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏍峰搧缂栧彿',
+ `qc_id` bigint DEFAULT NULL COMMENT '鍏宠仈璐ㄦ鍗曠紪鍙�',
+ `qc_type` int DEFAULT NULL COMMENT '璐ㄦ绫诲瀷',
+ `item_id` bigint DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
+ `sn` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐗╄祫 SN',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 妫�楠岀粨鏋滆褰�';
+
+-- ============ 琛細mes_qc_indicator_result_detail锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_qc_indicator_result_detail`;
+CREATE TABLE `mes_qc_indicator_result_detail` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `result_id` bigint DEFAULT NULL COMMENT '鍏宠仈妫�楠岀粨鏋滅紪鍙�',
+ `indicator_id` bigint DEFAULT NULL COMMENT '妫�娴嬫寚鏍囩紪鍙�',
+ `value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妫�娴嬪��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 妫�楠岀粨鏋滄槑缁嗚褰�';
+
+-- ============ 琛細mes_qc_ipqc锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_qc_ipqc`;
+CREATE TABLE `mes_qc_ipqc` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妫�楠屽崟缂栧彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妫�楠屽崟鍚嶇О',
+ `type` int DEFAULT NULL COMMENT 'IPQC 妫�楠岀被鍨�',
+ `template_id` bigint DEFAULT NULL COMMENT '妫�楠屾ā鏉跨紪鍙�',
+ `source_doc_type` int DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁绫诲瀷',
+ `source_doc_id` bigint DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
+ `source_line_id` bigint DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁琛岀紪鍙�',
+ `source_doc_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
+ `work_order_id` bigint DEFAULT NULL COMMENT '鐢熶骇宸ュ崟缂栧彿',
+ `task_id` bigint DEFAULT NULL COMMENT '鐢熶骇浠诲姟缂栧彿',
+ `workstation_id` bigint DEFAULT NULL COMMENT '宸ヤ綅缂栧彿',
+ `process_id` bigint DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
+ `item_id` bigint DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
+ `check_quantity` decimal(24,6) DEFAULT NULL COMMENT '妫�娴嬫暟閲�',
+ `qualified_quantity` decimal(24,6) DEFAULT NULL COMMENT '鍚堟牸鍝佹暟閲�',
+ `unqualified_quantity` decimal(24,6) DEFAULT NULL COMMENT '涓嶅悎鏍煎搧鏁伴噺',
+ `labor_scrap_quantity` decimal(24,6) DEFAULT NULL COMMENT '宸ュ簾鏁伴噺',
+ `material_scrap_quantity` decimal(24,6) DEFAULT NULL COMMENT '鏂欏簾鏁伴噺',
+ `other_scrap_quantity` decimal(24,6) DEFAULT NULL COMMENT '鍏朵粬搴熷搧鏁伴噺',
+ `critical_rate` decimal(24,6) DEFAULT NULL COMMENT '鑷村懡缂洪櫡鐜�',
+ `major_rate` decimal(24,6) DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鐜�',
+ `minor_rate` decimal(24,6) DEFAULT NULL COMMENT '杞诲井缂洪櫡鐜�',
+ `critical_quantity` int DEFAULT NULL COMMENT '鑷村懡缂洪櫡鏁伴噺',
+ `major_quantity` int DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鏁伴噺',
+ `minor_quantity` int DEFAULT NULL COMMENT '杞诲井缂洪櫡鏁伴噺',
+ `check_result` int DEFAULT NULL COMMENT '妫�娴嬬粨鏋�',
+ `inspect_date` datetime DEFAULT NULL COMMENT '妫�娴嬫棩鏈�',
+ `inspector_user_id` bigint DEFAULT NULL COMMENT '妫�娴嬩汉鍛樼敤鎴风紪鍙�',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 杩囩▼妫�楠屽崟';
+
+-- ============ 琛細mes_qc_ipqc_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_qc_ipqc_line`;
+CREATE TABLE `mes_qc_ipqc_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `ipqc_id` bigint DEFAULT NULL COMMENT '杩囩▼妫�楠屽崟缂栧彿',
+ `indicator_id` bigint DEFAULT NULL COMMENT '妫�娴嬫寚鏍囩紪鍙�',
+ `tool` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妫�娴嬪伐鍏�',
+ `check_method` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妫�娴嬫柟娉�',
+ `standard_value` decimal(24,6) DEFAULT NULL COMMENT '鏍囧噯鍊�',
+ `unit_measure_id` bigint DEFAULT NULL COMMENT '璁¢噺鍗曚綅缂栧彿',
+ `max_threshold` decimal(24,6) DEFAULT NULL COMMENT '璇樊涓婇檺',
+ `min_threshold` decimal(24,6) DEFAULT NULL COMMENT '璇樊涓嬮檺',
+ `critical_quantity` int DEFAULT NULL COMMENT '鑷村懡缂洪櫡鏁伴噺',
+ `major_quantity` int DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鏁伴噺',
+ `minor_quantity` int DEFAULT NULL COMMENT '杞诲井缂洪櫡鏁伴噺',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 杩囩▼妫�楠屽崟琛�';
+
+-- ============ 琛細mes_qc_iqc锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_qc_iqc`;
+CREATE TABLE `mes_qc_iqc` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妫�楠屽崟缂栧彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妫�楠屽崟鍚嶇О',
+ `template_id` bigint DEFAULT NULL COMMENT '妫�楠屾ā鏉跨紪鍙�',
+ `source_doc_type` int DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁绫诲瀷',
+ `source_doc_id` bigint DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
+ `source_line_id` bigint DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁琛岀紪鍙�',
+ `source_doc_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
+ `vendor_id` bigint DEFAULT NULL COMMENT '渚涘簲鍟嗙紪鍙�',
+ `vendor_batch` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '渚涘簲鍟嗘壒娆″彿',
+ `item_id` bigint DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
+ `received_quantity` decimal(24,6) DEFAULT NULL COMMENT '鏈鎺ユ敹鏁伴噺',
+ `check_quantity` decimal(24,6) DEFAULT NULL COMMENT '鏈妫�娴嬫暟閲�',
+ `qualified_quantity` decimal(24,6) DEFAULT NULL COMMENT '鍚堟牸鍝佹暟閲�',
+ `unqualified_quantity` decimal(24,6) DEFAULT NULL COMMENT '涓嶅悎鏍煎搧鏁伴噺',
+ `critical_rate` decimal(24,6) DEFAULT NULL COMMENT '鑷村懡缂洪櫡鐜�',
+ `major_rate` decimal(24,6) DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鐜�',
+ `minor_rate` decimal(24,6) DEFAULT NULL COMMENT '杞诲井缂洪櫡鐜�',
+ `critical_quantity` int DEFAULT NULL COMMENT '鑷村懡缂洪櫡鏁伴噺',
+ `major_quantity` int DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鏁伴噺',
+ `minor_quantity` int DEFAULT NULL COMMENT '杞诲井缂洪櫡鏁伴噺',
+ `check_result` int DEFAULT NULL COMMENT '妫�娴嬬粨鏋�',
+ `receive_date` datetime DEFAULT NULL COMMENT '鏉ユ枡鏃ユ湡',
+ `inspect_date` datetime DEFAULT NULL COMMENT '妫�娴嬫棩鏈�',
+ `inspector_user_id` bigint DEFAULT NULL COMMENT '妫�娴嬩汉鍛樼敤鎴风紪鍙�',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鏉ユ枡妫�楠屽崟';
+
+-- ============ 琛細mes_qc_iqc_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_qc_iqc_line`;
+CREATE TABLE `mes_qc_iqc_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `iqc_id` bigint DEFAULT NULL COMMENT '鏉ユ枡妫�楠屽崟缂栧彿',
+ `indicator_id` bigint DEFAULT NULL COMMENT '妫�娴嬫寚鏍囩紪鍙�',
+ `tool` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妫�娴嬪伐鍏�',
+ `check_method` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妫�娴嬫柟娉�',
+ `standard_value` decimal(24,6) DEFAULT NULL COMMENT '鏍囧噯鍊�',
+ `unit_measure_id` bigint DEFAULT NULL COMMENT '璁¢噺鍗曚綅缂栧彿',
+ `max_threshold` decimal(24,6) DEFAULT NULL COMMENT '璇樊涓婇檺',
+ `min_threshold` decimal(24,6) DEFAULT NULL COMMENT '璇樊涓嬮檺',
+ `critical_quantity` int DEFAULT NULL COMMENT '鑷村懡缂洪櫡鏁伴噺',
+ `major_quantity` int DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鏁伴噺',
+ `minor_quantity` int DEFAULT NULL COMMENT '杞诲井缂洪櫡鏁伴噺',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鏉ユ枡妫�楠屽崟琛�';
+
+-- ============ 琛細mes_qc_ncr锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_qc_ncr`;
+CREATE TABLE `mes_qc_ncr` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'NCR鍗曞彿',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'NCR鍚嶇О',
+ `qc_type` int DEFAULT NULL COMMENT '妫�楠岀被鍨嬶紙IQC/IPQC/OQC/RQC锛夛紝瀛楀吀 mes_qc_type',
+ `qc_id` bigint DEFAULT NULL COMMENT '鏉ユ簮妫�楠屽崟ID',
+ `qc_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏉ユ簮妫�楠屽崟缂栧彿锛堝啑浣欙級',
+ `item_id` bigint DEFAULT NULL COMMENT '涓嶅悎鏍肩墿鏂橧D',
+ `defect_level` int DEFAULT NULL COMMENT '缂洪櫡绛夌骇锛堣嚧鍛�/涓ラ噸/杞诲井锛夛紝瀛楀吀 mes_defect_level',
+ `unqualified_quantity` decimal(24,6) DEFAULT NULL COMMENT '涓嶅悎鏍兼暟閲�',
+ `defect_description` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '涓嶅悎鏍兼弿杩�',
+ `disposition` int DEFAULT NULL COMMENT '澶勭疆鏂瑰紡锛堥��璐�/鎶ュ簾/杩斿伐/璁╂鎺ユ敹/闄嶇骇浣跨敤锛夛紝瀛楀吀 mes_ncr_disposition',
+ `responsible_dept_id` bigint DEFAULT NULL COMMENT '璐d换閮ㄩ棬ID',
+ `reviewer_user_id` bigint DEFAULT NULL COMMENT '璇勫浜篒D',
+ `review_date` datetime DEFAULT NULL COMMENT '璇勫鏃ユ湡',
+ `review_opinion` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璇勫鎰忚',
+ `handler_user_id` bigint DEFAULT NULL COMMENT '澶勭悊浜篒D',
+ `handle_date` datetime DEFAULT NULL COMMENT '澶勭悊鏃ユ湡',
+ `handle_result` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶勭悊缁撴灉璇存槑',
+ `root_cause` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏍规湰鍘熷洜',
+ `corrective_action` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '绾犳鎺柦',
+ `preventive_action` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '棰勯槻鎺柦',
+ `close_user_id` bigint DEFAULT NULL COMMENT '鍏抽棴浜篒D',
+ `close_date` datetime DEFAULT NULL COMMENT '鍏抽棴鏃ユ湡',
+ `close_opinion` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍏抽棴鎰忚',
+ `status` int DEFAULT NULL COMMENT '鐘舵�侊紙寰呰瘎瀹�/宸茶瘎瀹�/宸插缃�/宸插叧闂級锛屽瓧鍏� mes_ncr_status',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'BPM娴佺▼瀹炰緥ID锛堥鐣欙級',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_qc_type_id` (`qc_type`,`qc_id`) USING BTREE,
+ KEY `idx_status` (`status`) USING BTREE,
+ KEY `idx_item_id` (`item_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 涓嶅悎鏍煎搧澶勭悊鍗�';
+
+-- ============ 琛細mes_qc_oqc锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_qc_oqc`;
+CREATE TABLE `mes_qc_oqc` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妫�楠屽崟缂栧彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妫�楠屽崟鍚嶇О',
+ `template_id` bigint DEFAULT NULL COMMENT '妫�楠屾ā鏉跨紪鍙�',
+ `source_doc_type` int DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁绫诲瀷',
+ `source_doc_id` bigint DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
+ `source_line_id` bigint DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁琛岀紪鍙�',
+ `source_doc_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
+ `client_id` bigint DEFAULT NULL COMMENT '瀹㈡埛缂栧彿',
+ `batch_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵规鍙�',
+ `item_id` bigint DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
+ `min_check_quantity` int DEFAULT NULL COMMENT '鏈�浣庢娴嬫暟',
+ `max_unqualified_quantity` int DEFAULT NULL COMMENT '鏈�澶т笉鍚堟牸鏁�',
+ `out_quantity` decimal(24,6) DEFAULT NULL COMMENT '鏈鍑鸿揣鏁伴噺',
+ `check_quantity` decimal(24,6) DEFAULT NULL COMMENT '鏈妫�娴嬫暟閲�',
+ `qualified_quantity` decimal(24,6) DEFAULT NULL COMMENT '鍚堟牸鍝佹暟閲�',
+ `unqualified_quantity` decimal(24,6) DEFAULT NULL COMMENT '涓嶅悎鏍煎搧鏁伴噺',
+ `critical_rate` decimal(24,6) DEFAULT NULL COMMENT '鑷村懡缂洪櫡鐜�',
+ `major_rate` decimal(24,6) DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鐜�',
+ `minor_rate` decimal(24,6) DEFAULT NULL COMMENT '杞诲井缂洪櫡鐜�',
+ `critical_quantity` int DEFAULT NULL COMMENT '鑷村懡缂洪櫡鏁伴噺',
+ `major_quantity` int DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鏁伴噺',
+ `minor_quantity` int DEFAULT NULL COMMENT '杞诲井缂洪櫡鏁伴噺',
+ `check_result` int DEFAULT NULL COMMENT '妫�娴嬬粨鏋�',
+ `out_date` datetime DEFAULT NULL COMMENT '鍑鸿揣鏃ユ湡',
+ `inspect_date` datetime DEFAULT NULL COMMENT '妫�娴嬫棩鏈�',
+ `inspector_user_id` bigint DEFAULT NULL COMMENT '妫�娴嬩汉鍛樼敤鎴风紪鍙�',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鍑鸿揣妫�楠屽崟';
+
+-- ============ 琛細mes_qc_oqc_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_qc_oqc_line`;
+CREATE TABLE `mes_qc_oqc_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `oqc_id` bigint DEFAULT NULL COMMENT '鍑鸿揣妫�楠屽崟缂栧彿',
+ `indicator_id` bigint DEFAULT NULL COMMENT '妫�娴嬫寚鏍囩紪鍙�',
+ `tool` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妫�娴嬪伐鍏�',
+ `check_method` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妫�娴嬫柟娉�',
+ `standard_value` decimal(24,6) DEFAULT NULL COMMENT '鏍囧噯鍊�',
+ `unit_measure_id` bigint DEFAULT NULL COMMENT '璁¢噺鍗曚綅缂栧彿',
+ `max_threshold` decimal(24,6) DEFAULT NULL COMMENT '璇樊涓婇檺',
+ `min_threshold` decimal(24,6) DEFAULT NULL COMMENT '璇樊涓嬮檺',
+ `critical_quantity` int DEFAULT NULL COMMENT '鑷村懡缂洪櫡鏁伴噺',
+ `major_quantity` int DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鏁伴噺',
+ `minor_quantity` int DEFAULT NULL COMMENT '杞诲井缂洪櫡鏁伴噺',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鍑鸿揣妫�楠屽崟琛�';
+
+-- ============ 琛細mes_qc_rqc锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_qc_rqc`;
+CREATE TABLE `mes_qc_rqc` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妫�楠屽崟缂栧彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妫�楠屽崟鍚嶇О',
+ `template_id` bigint DEFAULT NULL COMMENT '妫�楠屾ā鏉跨紪鍙�',
+ `source_doc_type` int DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁绫诲瀷',
+ `source_doc_id` bigint DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
+ `source_line_id` bigint DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁琛岀紪鍙�',
+ `source_doc_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏉ユ簮鍗曟嵁缂栧彿',
+ `type` int DEFAULT NULL COMMENT '妫�楠岀被鍨�',
+ `item_id` bigint DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
+ `batch_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵规鍙�',
+ `check_quantity` decimal(24,6) DEFAULT NULL COMMENT '妫�娴嬫暟閲�',
+ `qualified_quantity` decimal(24,6) DEFAULT NULL COMMENT '鍚堟牸鍝佹暟閲�',
+ `unqualified_quantity` decimal(24,6) DEFAULT NULL COMMENT '涓嶅悎鏍兼暟閲�',
+ `critical_rate` decimal(24,6) DEFAULT NULL COMMENT '鑷村懡缂洪櫡鐜�',
+ `major_rate` decimal(24,6) DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鐜�',
+ `minor_rate` decimal(24,6) DEFAULT NULL COMMENT '杞诲井缂洪櫡鐜�',
+ `critical_quantity` int DEFAULT NULL COMMENT '鑷村懡缂洪櫡鏁伴噺',
+ `major_quantity` int DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鏁伴噺',
+ `minor_quantity` int DEFAULT NULL COMMENT '杞诲井缂洪櫡鏁伴噺',
+ `check_result` int DEFAULT NULL COMMENT '妫�娴嬬粨鏋�',
+ `inspect_date` datetime DEFAULT NULL COMMENT '妫�娴嬫棩鏈�',
+ `inspector_user_id` bigint DEFAULT NULL COMMENT '妫�娴嬩汉鍛樼敤鎴风紪鍙�',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 閫�璐ф楠屽崟';
+
+-- ============ 琛細mes_qc_rqc_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_qc_rqc_line`;
+CREATE TABLE `mes_qc_rqc_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `rqc_id` bigint DEFAULT NULL COMMENT '閫�璐ф楠屽崟缂栧彿',
+ `indicator_id` bigint DEFAULT NULL COMMENT '妫�娴嬫寚鏍囩紪鍙�',
+ `tool` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妫�娴嬪伐鍏�',
+ `check_method` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妫�娴嬫柟娉�',
+ `standard_value` decimal(24,6) DEFAULT NULL COMMENT '鏍囧噯鍊�',
+ `unit_measure_id` bigint DEFAULT NULL COMMENT '璁¢噺鍗曚綅缂栧彿',
+ `max_threshold` decimal(24,6) DEFAULT NULL COMMENT '璇樊涓婇檺',
+ `min_threshold` decimal(24,6) DEFAULT NULL COMMENT '璇樊涓嬮檺',
+ `critical_quantity` int DEFAULT NULL COMMENT '鑷村懡缂洪櫡鏁伴噺',
+ `major_quantity` int DEFAULT NULL COMMENT '涓ラ噸缂洪櫡鏁伴噺',
+ `minor_quantity` int DEFAULT NULL COMMENT '杞诲井缂洪櫡鏁伴噺',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 閫�璐ф楠岃';
+
+-- ============ 琛細mes_qc_template锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_qc_template`;
+CREATE TABLE `mes_qc_template` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏂规缂栧彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏂规鍚嶇О',
+ `types` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妫�娴嬬绫�',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 璐ㄦ鏂规';
+
+-- ============ 琛細mes_qc_template_indicator锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_qc_template_indicator`;
+CREATE TABLE `mes_qc_template_indicator` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `template_id` bigint DEFAULT NULL COMMENT '璐ㄦ鏂规缂栧彿',
+ `indicator_id` bigint DEFAULT NULL COMMENT '璐ㄦ鎸囨爣缂栧彿',
+ `check_method` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妫�娴嬫柟娉�',
+ `standard_value` decimal(24,6) DEFAULT NULL COMMENT '鏍囧噯鍊�',
+ `unit_measure_id` bigint DEFAULT NULL COMMENT '璁¢噺鍗曚綅缂栧彿',
+ `threshold_max` decimal(24,6) DEFAULT NULL COMMENT '璇樊涓婇檺',
+ `threshold_min` decimal(24,6) DEFAULT NULL COMMENT '璇樊涓嬮檺',
+ `doc_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璇存槑鍥� URL',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 璐ㄦ鏂规妫�娴嬫寚鏍囬」';
+
+-- ============ 琛細mes_qc_template_item锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_qc_template_item`;
+CREATE TABLE `mes_qc_template_item` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `template_id` bigint DEFAULT NULL COMMENT '璐ㄦ鏂规缂栧彿',
+ `item_id` bigint DEFAULT NULL COMMENT '浜у搧鐗╂枡缂栧彿',
+ `quantity_check` int DEFAULT NULL COMMENT '鏈�浣庢娴嬫暟',
+ `quantity_unqualified` int DEFAULT NULL COMMENT '鏈�澶т笉鍚堟牸鏁�',
+ `critical_rate` decimal(24,6) DEFAULT NULL COMMENT '鏈�澶ц嚧鍛界己闄风巼',
+ `major_rate` decimal(24,6) DEFAULT NULL COMMENT '鏈�澶т弗閲嶇己闄风巼',
+ `minor_rate` decimal(24,6) DEFAULT NULL COMMENT '鏈�澶ц交寰己闄风巼',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 璐ㄦ鏂规浜у搧鍏宠仈';
+
+-- ============ 琛細mes_tm_tool锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_tm_tool`;
+CREATE TABLE `mes_tm_tool` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宸ュ叿缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宸ュ叿鍚嶇О',
+ `brand` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍝佺墝',
+ `specification` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍨嬪彿瑙勬牸',
+ `tool_type_id` bigint DEFAULT NULL COMMENT '宸ュ叿绫诲瀷缂栧彿',
+ `quantity` int DEFAULT NULL COMMENT '鏁伴噺',
+ `available_quantity` int DEFAULT NULL COMMENT '鍙敤鏁伴噺',
+ `mainten_type` int DEFAULT NULL COMMENT '淇濆吇缁存姢绫诲瀷',
+ `next_mainten_period` int DEFAULT NULL COMMENT '涓嬫淇濆吇鍛ㄦ湡锛堟鏁帮級',
+ `next_mainten_date` datetime DEFAULT NULL COMMENT '涓嬫淇濆吇鏃ユ湡',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 宸ュ叿鍙拌处';
+
+-- ============ 琛細mes_tm_tool_type锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_tm_tool_type`;
+CREATE TABLE `mes_tm_tool_type` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '绫诲瀷缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '绫诲瀷鍚嶇О',
+ `code_flag` bit(1) DEFAULT b'0' COMMENT '鏄惁缂栫爜绠$悊',
+ `mainten_type` int DEFAULT NULL COMMENT '淇濆吇缁存姢绫诲瀷',
+ `mainten_period` int DEFAULT NULL COMMENT '淇濆吇鍛ㄦ湡',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 宸ュ叿绫诲瀷';
+
+-- ============ 琛細mes_wm_arrival_notice锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_arrival_notice`;
+CREATE TABLE `mes_wm_arrival_notice` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍗曞彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍚嶇О',
+ `purchase_order_id` bigint DEFAULT NULL COMMENT '閲囪喘璁㈠崟缂栧彿',
+ `purchase_order_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閲囪喘璁㈠崟缂栫爜锛堝啑浣欏瓧娈碉級',
+ `vendor_id` bigint DEFAULT NULL COMMENT '渚涘簲鍟� ID',
+ `arrival_date` datetime DEFAULT NULL COMMENT '棰勮鍒拌揣鏃ユ湡',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `contact_telephone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑱旂郴浜虹數璇�',
+ `contact_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑱旂郴浜�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鍒拌揣閫氱煡鍗�';
+
+-- ============ 琛細mes_wm_arrival_notice_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_arrival_notice_line`;
+CREATE TABLE `mes_wm_arrival_notice_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `notice_id` bigint DEFAULT NULL COMMENT '鍒拌揣閫氱煡鍗� ID',
+ `purchase_order_item_id` bigint DEFAULT NULL COMMENT '閲囪喘璁㈠崟琛岀紪鍙凤紙鍏宠仈 ERP 閲囪喘璁㈠崟鏄庣粏锛�',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `arrival_quantity` decimal(24,6) DEFAULT NULL COMMENT '鍒拌揣鏁伴噺',
+ `qualified_quantity` decimal(24,6) DEFAULT NULL COMMENT '鍚堟牸鏁伴噺',
+ `iqc_check_flag` bit(1) DEFAULT b'0' COMMENT '鏄惁闇�瑕佹潵鏂欐楠�',
+ `iqc_id` bigint DEFAULT NULL COMMENT '鏉ユ枡妫�楠屽崟缂栧彿',
+ `iqc_check_result` tinyint DEFAULT NULL COMMENT '璐ㄦ缁撴灉锛�1鍚堟牸 2鐗归噰 3涓嶅悎鏍奸��璐� 4涓嶅悎鏍兼姤搴�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_purchase_order_item_id` (`purchase_order_item_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鍒拌揣閫氱煡鍗曡';
+
+-- ============ 琛細mes_wm_barcode锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_barcode`;
+CREATE TABLE `mes_wm_barcode` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `config_id` bigint DEFAULT NULL COMMENT '鏉$爜閰嶇疆缂栧彿',
+ `format` int DEFAULT NULL COMMENT '鏉$爜鏍煎紡',
+ `biz_type` int DEFAULT NULL COMMENT '涓氬姟绫诲瀷',
+ `content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏉$爜鍐呭',
+ `biz_id` bigint DEFAULT NULL COMMENT '涓氬姟缂栧彿',
+ `biz_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '涓氬姟缂栫爜',
+ `biz_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '涓氬姟鍚嶇О',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鏉$爜娓呭崟';
+
+-- ============ 琛細mes_wm_barcode_config锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_barcode_config`;
+CREATE TABLE `mes_wm_barcode_config` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `format` int DEFAULT NULL COMMENT '鏉$爜鏍煎紡',
+ `biz_type` int DEFAULT NULL COMMENT '涓氬姟绫诲瀷',
+ `content_format` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍐呭鏍煎紡妯℃澘',
+ `content_example` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍐呭鏍蜂緥',
+ `auto_generate_flag` bit(1) DEFAULT b'0' COMMENT '鏄惁鑷姩鐢熸垚',
+ `default_template` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '榛樿鎵撳嵃妯℃澘',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鏉$爜閰嶇疆';
+
+-- ============ 琛細mes_wm_batch锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_batch`;
+CREATE TABLE `mes_wm_batch` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵规鍙�',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `produce_date` datetime DEFAULT NULL COMMENT '鐢熶骇鏃ユ湡',
+ `expire_date` datetime DEFAULT NULL COMMENT '澶辨晥鏃ユ湡',
+ `receipt_date` datetime DEFAULT NULL COMMENT '鍏ュ簱鏃ユ湡',
+ `vendor_id` bigint DEFAULT NULL COMMENT '渚涘簲鍟� ID',
+ `client_id` bigint DEFAULT NULL COMMENT '瀹㈡埛ID',
+ `sales_order_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閿�鍞鍗曠紪鍙�',
+ `purchase_order_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閲囪喘璁㈠崟缂栧彿',
+ `work_order_id` bigint DEFAULT NULL COMMENT '鐢熶骇宸ュ崟ID',
+ `task_id` bigint DEFAULT NULL COMMENT '鐢熶骇浠诲姟ID',
+ `workstation_id` bigint DEFAULT NULL COMMENT '宸ヤ綔绔橧D',
+ `tool_id` bigint DEFAULT NULL COMMENT '宸ュ叿ID',
+ `mold_id` bigint DEFAULT NULL COMMENT '妯″叿ID',
+ `lot_number` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐢熶骇鎵瑰彿',
+ `quality_status` tinyint DEFAULT NULL COMMENT '璐ㄩ噺鐘舵��',
+ `vendor_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '渚涘簲鍟嗙紪鐮�',
+ `vendor_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '渚涘簲鍟嗗悕绉�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鎵规';
+
+-- ============ 琛細mes_wm_item_consume锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_item_consume`;
+CREATE TABLE `mes_wm_item_consume` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍗曞彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍚嶇О',
+ `work_order_id` bigint DEFAULT NULL COMMENT '鐢熶骇宸ュ崟 ID',
+ `task_id` bigint DEFAULT NULL COMMENT '鐢熶骇浠诲姟缂栧彿',
+ `workstation_id` bigint DEFAULT NULL COMMENT '宸ヤ綔绔欑紪鍙�',
+ `process_id` bigint DEFAULT NULL COMMENT '宸ュ簭缂栧彿',
+ `feedback_id` bigint DEFAULT NULL COMMENT '鎶ュ伐璁板綍缂栧彿',
+ `consume_date` datetime DEFAULT NULL COMMENT '娑堣�楁棩鏈�',
+ `return_date` datetime DEFAULT NULL COMMENT '閫�鏂欐棩鏈�',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐗╂枡閫�鏂欏崟';
+
+-- ============ 琛細mes_wm_item_consume_detail锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_item_consume_detail`;
+CREATE TABLE `mes_wm_item_consume_detail` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `line_id` bigint DEFAULT NULL COMMENT '琛� ID',
+ `consume_id` bigint DEFAULT NULL COMMENT '閫�鏂欏崟 ID',
+ `material_stock_id` bigint DEFAULT NULL COMMENT '搴撳瓨 ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规 ID',
+ `warehouse_id` bigint DEFAULT NULL COMMENT '浠撳簱 ID',
+ `location_id` bigint DEFAULT NULL COMMENT '搴撳尯 ID',
+ `area_id` bigint DEFAULT NULL COMMENT '搴撲綅 ID',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `batch_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐗╂枡閫�鏂欏崟鏄庣粏';
+
+-- ============ 琛細mes_wm_item_consume_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_item_consume_line`;
+CREATE TABLE `mes_wm_item_consume_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `consume_id` bigint DEFAULT NULL COMMENT '閫�鏂欏崟 ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `batch_id` int DEFAULT NULL,
+ `batch_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐗╂枡閫�鏂欏崟琛�';
+
+-- ============ 琛細mes_wm_item_receipt锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_item_receipt`;
+CREATE TABLE `mes_wm_item_receipt` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍗曞彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍚嶇О',
+ `iqc_id` bigint DEFAULT NULL COMMENT '鏉ユ枡妫�楠屽崟缂栧彿',
+ `notice_id` bigint DEFAULT NULL COMMENT '鍒拌揣閫氱煡鍗曠紪鍙�',
+ `purchase_order_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閲囪喘璁㈠崟鍙�',
+ `purchase_order_id` bigint DEFAULT NULL COMMENT '閲囪喘璁㈠崟缂栧彿',
+ `vendor_id` bigint DEFAULT NULL COMMENT '渚涘簲鍟嗙紪鍙�',
+ `receipt_date` datetime DEFAULT NULL COMMENT '閫�搴撴棩鏈�',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴佺▼瀹炰緥ID',
+ `process_definition_key` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴佺▼瀹氫箟Key',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_process_instance_id` (`process_instance_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 閲囪喘鍏ュ簱鍗�';
+
+-- ============ 琛細mes_wm_item_receipt_detail锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_item_receipt_detail`;
+CREATE TABLE `mes_wm_item_receipt_detail` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `line_id` bigint DEFAULT NULL COMMENT '琛� ID',
+ `receipt_id` bigint DEFAULT NULL COMMENT '閫�搴撳崟 ID',
+ `material_stock_id` bigint DEFAULT NULL COMMENT '搴撳瓨 ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规 ID',
+ `warehouse_id` bigint DEFAULT NULL COMMENT '浠撳簱 ID',
+ `location_id` bigint DEFAULT NULL COMMENT '搴撳尯 ID',
+ `area_id` bigint DEFAULT NULL COMMENT '搴撲綅 ID',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐗╂枡閫�搴撳崟鏄庣粏';
+
+-- ============ 琛細mes_wm_item_receipt_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_item_receipt_line`;
+CREATE TABLE `mes_wm_item_receipt_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `receipt_id` bigint DEFAULT NULL COMMENT '閫�搴撳崟 ID',
+ `arrival_notice_line_id` bigint DEFAULT NULL COMMENT '鍒拌揣閫氱煡鍗曡缂栧彿',
+ `purchase_order_item_id` bigint DEFAULT NULL COMMENT '閲囪喘璁㈠崟琛岀紪鍙凤紙瀹屾暣杩芥函閾撅級',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `received_quantity` decimal(24,6) DEFAULT NULL COMMENT '鍏ュ簱鏁伴噺',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规缂栧彿',
+ `batch_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵规缂栫爜',
+ `production_date` datetime DEFAULT NULL COMMENT '鐢熶骇鏃ユ湡',
+ `expire_date` datetime DEFAULT NULL COMMENT '鏈夋晥鏈�',
+ `lot_number` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐢熶骇鎵瑰彿',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_purchase_order_item_id` (`purchase_order_item_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐗╂枡閫�搴撳崟琛�';
+
+-- ============ 琛細mes_wm_material_stock锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_material_stock`;
+CREATE TABLE `mes_wm_material_stock` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `item_type_id` bigint DEFAULT NULL COMMENT '鐗╂枡鍒嗙被缂栧彿',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规 ID',
+ `batch_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵规缂栫爜',
+ `warehouse_id` bigint DEFAULT NULL COMMENT '浠撳簱 ID',
+ `location_id` bigint DEFAULT NULL COMMENT '搴撳尯 ID',
+ `area_id` bigint DEFAULT NULL COMMENT '搴撲綅 ID',
+ `vendor_id` bigint DEFAULT NULL COMMENT '渚涘簲鍟嗙紪鍙�',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '搴撳瓨鏁伴噺',
+ `frozen_quantity` decimal(24,6) DEFAULT '0.000000' COMMENT '鍐荤粨鏁伴噺',
+ `reserved_quantity` decimal(24,6) DEFAULT '0.000000' COMMENT '鍗犵敤閲忥紙宸插垎閰嶅緟鍑哄簱锛�',
+ `in_transit_quantity` decimal(24,6) DEFAULT '0.000000' COMMENT '鍦ㄩ�旈噺锛堣皟鎷ㄥ湪閫旓級',
+ `erp_time` datetime DEFAULT NULL COMMENT 'ERP 璐︽湡',
+ `receipt_time` datetime DEFAULT NULL COMMENT '鍏ュ簱鏃堕棿',
+ `frozen` bit(1) DEFAULT b'0' COMMENT '鏄惁鍐荤粨',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 搴撳瓨璁板綍';
+
+-- ============ 琛細mes_wm_misc_issue锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_misc_issue`;
+CREATE TABLE `mes_wm_misc_issue` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍗曞彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍚嶇О',
+ `issue_date` datetime DEFAULT NULL COMMENT '鍑哄簱鏃ユ湡',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴佺▼瀹炰緥ID',
+ `process_definition_key` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴佺▼瀹氫箟Key',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `type` int DEFAULT NULL,
+ `source_doc_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
+ `source_doc_id` int DEFAULT NULL,
+ `source_doc_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鍏朵粬鍑哄簱鍗�';
+
+-- ============ 琛細mes_wm_misc_issue_detail锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_misc_issue_detail`;
+CREATE TABLE `mes_wm_misc_issue_detail` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `line_id` bigint DEFAULT NULL COMMENT '琛� ID',
+ `issue_id` bigint DEFAULT NULL COMMENT '鍑哄簱鍗� ID',
+ `material_stock_id` bigint DEFAULT NULL COMMENT '搴撳瓨 ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规 ID',
+ `warehouse_id` bigint DEFAULT NULL COMMENT '浠撳簱 ID',
+ `location_id` bigint DEFAULT NULL COMMENT '搴撳尯 ID',
+ `area_id` bigint DEFAULT NULL COMMENT '搴撲綅 ID',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `batch_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵规鍙�',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鍏朵粬鍑哄簱鍗曟槑缁�';
+
+-- ============ 琛細mes_wm_misc_issue_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_misc_issue_line`;
+CREATE TABLE `mes_wm_misc_issue_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `issue_id` bigint DEFAULT NULL COMMENT '鍑哄簱鍗� ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `material_stock_id` bigint DEFAULT NULL COMMENT '搴撳瓨璁板綍ID',
+ `batch_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵规鍙�',
+ `warehouse_id` bigint DEFAULT NULL,
+ `location_id` bigint DEFAULT NULL,
+ `area_id` bigint DEFAULT NULL,
+ `source_doc_line_id` bigint DEFAULT NULL,
+ `batch_id` bigint DEFAULT NULL,
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鍏朵粬鍑哄簱鍗曡';
+
+-- ============ 琛細mes_wm_misc_receipt锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_misc_receipt`;
+CREATE TABLE `mes_wm_misc_receipt` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍗曞彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍚嶇О',
+ `receipt_date` datetime DEFAULT NULL COMMENT '鍏ュ簱鏃ユ湡',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴佺▼瀹炰緥ID',
+ `process_definition_key` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴佺▼瀹氫箟Key',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鍏朵粬鍏ュ簱鍗�';
+
+-- ============ 琛細mes_wm_misc_receipt_detail锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_misc_receipt_detail`;
+CREATE TABLE `mes_wm_misc_receipt_detail` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `line_id` bigint DEFAULT NULL COMMENT '琛� ID',
+ `receipt_id` bigint DEFAULT NULL COMMENT '鍏ュ簱鍗� ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规 ID',
+ `warehouse_id` bigint DEFAULT NULL COMMENT '浠撳簱 ID',
+ `location_id` bigint DEFAULT NULL COMMENT '搴撳尯 ID',
+ `area_id` bigint DEFAULT NULL COMMENT '搴撲綅 ID',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鍏朵粬鍏ュ簱鍗曟槑缁�';
+
+-- ============ 琛細mes_wm_misc_receipt_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_misc_receipt_line`;
+CREATE TABLE `mes_wm_misc_receipt_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `receipt_id` bigint DEFAULT NULL COMMENT '鍏ュ簱鍗� ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鍏朵粬鍏ュ簱鍗曡';
+
+-- ============ 琛細mes_wm_outsource_issue锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_outsource_issue`;
+CREATE TABLE `mes_wm_outsource_issue` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍗曞彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍚嶇О',
+ `work_order_id` bigint DEFAULT NULL COMMENT '澶栧崗宸ュ崟 ID',
+ `vendor_id` bigint DEFAULT NULL COMMENT '渚涘簲鍟� ID',
+ `issue_date` datetime DEFAULT NULL COMMENT '鍙戞枡鏃ユ湡',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 澶栧崗鍙戞枡鍗�';
+
+-- ============ 琛細mes_wm_outsource_issue_detail锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_outsource_issue_detail`;
+CREATE TABLE `mes_wm_outsource_issue_detail` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `line_id` bigint DEFAULT NULL COMMENT '琛� ID',
+ `issue_id` bigint DEFAULT NULL COMMENT '鍙戞枡鍗� ID',
+ `material_stock_id` bigint DEFAULT NULL COMMENT '搴撳瓨 ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规 ID',
+ `warehouse_id` bigint DEFAULT NULL COMMENT '浠撳簱 ID',
+ `location_id` bigint DEFAULT NULL COMMENT '搴撳尯 ID',
+ `area_id` bigint DEFAULT NULL COMMENT '搴撲綅 ID',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 澶栧崗鍙戞枡鍗曟槑缁�';
+
+-- ============ 琛細mes_wm_outsource_issue_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_outsource_issue_line`;
+CREATE TABLE `mes_wm_outsource_issue_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `issue_id` bigint DEFAULT NULL COMMENT '鍙戞枡鍗� ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 澶栧崗鍙戞枡鍗曡';
+
+-- ============ 琛細mes_wm_outsource_receipt锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_outsource_receipt`;
+CREATE TABLE `mes_wm_outsource_receipt` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍗曞彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍚嶇О',
+ `work_order_id` bigint DEFAULT NULL COMMENT '澶栧崗宸ュ崟 ID',
+ `vendor_id` bigint DEFAULT NULL COMMENT '渚涘簲鍟� ID',
+ `receipt_date` datetime DEFAULT NULL COMMENT '鍏ュ簱鏃ユ湡',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 澶栧崗鍏ュ簱鍗�';
+
+-- ============ 琛細mes_wm_outsource_receipt_detail锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_outsource_receipt_detail`;
+CREATE TABLE `mes_wm_outsource_receipt_detail` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `line_id` bigint DEFAULT NULL COMMENT '琛� ID',
+ `receipt_id` bigint DEFAULT NULL COMMENT '鍏ュ簱鍗� ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规 ID',
+ `warehouse_id` bigint DEFAULT NULL COMMENT '浠撳簱 ID',
+ `location_id` bigint DEFAULT NULL COMMENT '搴撳尯 ID',
+ `area_id` bigint DEFAULT NULL COMMENT '搴撲綅 ID',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 澶栧崗鍏ュ簱鍗曟槑缁�';
+
+-- ============ 琛細mes_wm_outsource_receipt_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_outsource_receipt_line`;
+CREATE TABLE `mes_wm_outsource_receipt_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `receipt_id` bigint DEFAULT NULL COMMENT '鍏ュ簱鍗� ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `iqc_id` bigint DEFAULT NULL COMMENT '鏉ユ枡妫�楠屽崟缂栧彿',
+ `iqc_check_flag` bit(1) DEFAULT b'0' COMMENT '鏄惁闇�瑕佹潵鏂欐楠�',
+ `quality_status` int DEFAULT NULL COMMENT '璐ㄩ噺鐘舵��',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 澶栧崗鍏ュ簱鍗曡';
+
+-- ============ 琛細mes_wm_package锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_package`;
+CREATE TABLE `mes_wm_package` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '瑁呯鍗� ID',
+ `code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '瑁呯鍗曠紪鍙�',
+ `parent_id` bigint DEFAULT '0' COMMENT '鐖剁 ID',
+ `package_date` datetime DEFAULT NULL COMMENT '瑁呯鏃ユ湡',
+ `sales_order_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '閿�鍞鍗曠紪鍙�',
+ `invoice_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鍙戠エ缂栧彿',
+ `client_id` bigint DEFAULT NULL COMMENT '瀹㈡埛 ID',
+ `length` decimal(24,6) DEFAULT NULL COMMENT '绠遍暱搴�',
+ `width` decimal(24,6) DEFAULT NULL COMMENT '绠卞搴�',
+ `height` decimal(24,6) DEFAULT NULL COMMENT '绠遍珮搴�',
+ `size_unit_id` bigint DEFAULT NULL COMMENT '灏哄鍗曚綅 ID',
+ `net_weight` decimal(24,6) DEFAULT NULL COMMENT '鍑�閲�',
+ `gross_weight` decimal(24,6) DEFAULT NULL COMMENT '姣涢噸',
+ `weight_unit_id` bigint DEFAULT NULL COMMENT '閲嶉噺鍗曚綅 ID',
+ `inspector_user_id` bigint DEFAULT NULL COMMENT '妫�鏌ュ憳鐢ㄦ埛 ID',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` bigint DEFAULT NULL COMMENT '鍒涘缓鑰�',
+ `create_time` datetime DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
+ `updater` bigint DEFAULT NULL COMMENT '鏇存柊鑰�',
+ `update_time` datetime DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='MES 瑁呯鍗�';
+
+-- ============ 琛細mes_wm_package_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_package_line`;
+CREATE TABLE `mes_wm_package_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `package_id` bigint DEFAULT NULL COMMENT '鍖呰鍗� ID',
+ `material_stock_id` bigint DEFAULT NULL COMMENT '搴撳瓨 ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规 ID',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鍖呰鍗曡';
+
+-- ============ 琛細mes_wm_product_issue锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_product_issue`;
+CREATE TABLE `mes_wm_product_issue` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍗曞彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍚嶇О',
+ `work_order_id` bigint DEFAULT NULL COMMENT '鐢熶骇宸ュ崟 ID',
+ `task_id` bigint DEFAULT NULL COMMENT '鐢熶骇浠诲姟ID',
+ `issue_date` datetime DEFAULT NULL COMMENT '棰嗘枡鏃ユ湡',
+ `required_time` datetime DEFAULT NULL COMMENT '闇�姹傛椂闂�',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴佺▼瀹炰緥ID',
+ `process_definition_key` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴佺▼瀹氫箟Key',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `workstation_id` int DEFAULT NULL,
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇棰嗘枡鍗�';
+
+-- ============ 琛細mes_wm_product_issue_detail锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_product_issue_detail`;
+CREATE TABLE `mes_wm_product_issue_detail` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `line_id` bigint DEFAULT NULL COMMENT '琛� ID',
+ `issue_id` bigint DEFAULT NULL COMMENT '棰嗘枡鍗� ID',
+ `material_stock_id` bigint DEFAULT NULL COMMENT '搴撳瓨 ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规 ID',
+ `warehouse_id` bigint DEFAULT NULL COMMENT '浠撳簱 ID',
+ `location_id` bigint DEFAULT NULL COMMENT '搴撳尯 ID',
+ `area_id` bigint DEFAULT NULL COMMENT '搴撲綅 ID',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `batch_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇棰嗘枡鍗曟槑缁�';
+
+-- ============ 琛細mes_wm_product_issue_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_product_issue_line`;
+CREATE TABLE `mes_wm_product_issue_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `issue_id` bigint DEFAULT NULL COMMENT '棰嗘枡鍗� ID',
+ `task_id` bigint DEFAULT NULL COMMENT '鐢熶骇浠诲姟ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `batch_id` int DEFAULT NULL,
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇棰嗘枡鍗曡';
+
+-- ============ 琛細mes_wm_product_produce锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_product_produce`;
+CREATE TABLE `mes_wm_product_produce` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍗曞彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍚嶇О',
+ `work_order_id` bigint DEFAULT NULL COMMENT '鐢熶骇宸ュ崟 ID',
+ `feedback_id` bigint DEFAULT NULL COMMENT '鎶ュ伐璁板綍 ID',
+ `produce_date` datetime DEFAULT NULL COMMENT '鍏ュ簱鏃ユ湡',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `workstation_id` int DEFAULT NULL,
+ `process_id` bigint DEFAULT NULL COMMENT '宸ュ簭 ID',
+ `task_id` int DEFAULT NULL,
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇鍏ュ簱鍗�';
+
+-- ============ 琛細mes_wm_product_produce_detail锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_product_produce_detail`;
+CREATE TABLE `mes_wm_product_produce_detail` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `line_id` bigint DEFAULT NULL COMMENT '琛� ID',
+ `produce_id` bigint DEFAULT NULL COMMENT '鍏ュ簱鍗� ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规 ID',
+ `batch_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵规鍙�',
+ `warehouse_id` bigint DEFAULT NULL COMMENT '浠撳簱 ID',
+ `location_id` bigint DEFAULT NULL COMMENT '搴撳尯 ID',
+ `area_id` bigint DEFAULT NULL COMMENT '搴撲綅 ID',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇鍏ュ簱鍗曟槑缁�';
+
+-- ============ 琛細mes_wm_product_produce_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_product_produce_line`;
+CREATE TABLE `mes_wm_product_produce_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `produce_id` bigint DEFAULT NULL COMMENT '鍏ュ簱鍗� ID',
+ `feedback_id` bigint DEFAULT NULL COMMENT '鎶ュ伐璁板綍 ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规 ID',
+ `batch_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵规鍙�',
+ `expire_date` datetime DEFAULT NULL COMMENT '杩囨湡鏃ユ湡',
+ `lot_number` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐢熶骇鎵瑰彿',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `quality_status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇鍏ュ簱鍗曡';
+
+-- ============ 琛細mes_wm_product_receipt锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_product_receipt`;
+CREATE TABLE `mes_wm_product_receipt` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍗曞彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍚嶇О',
+ `work_order_id` bigint DEFAULT NULL COMMENT '鐢熶骇宸ュ崟 ID',
+ `receipt_date` datetime DEFAULT NULL COMMENT '閫�鏂欐棩鏈�',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴佺▼瀹炰緥ID',
+ `process_definition_key` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴佺▼瀹氫箟Key',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `item_id` int DEFAULT NULL,
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇閫�鏂欏崟';
+
+-- ============ 琛細mes_wm_product_receipt_detail锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_product_receipt_detail`;
+CREATE TABLE `mes_wm_product_receipt_detail` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `line_id` bigint DEFAULT NULL COMMENT '琛� ID',
+ `receipt_id` bigint DEFAULT NULL COMMENT '閫�鏂欏崟 ID',
+ `material_stock_id` bigint DEFAULT NULL COMMENT '搴撳瓨 ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规 ID',
+ `warehouse_id` bigint DEFAULT NULL COMMENT '浠撳簱 ID',
+ `location_id` bigint DEFAULT NULL COMMENT '搴撳尯 ID',
+ `area_id` bigint DEFAULT NULL COMMENT '搴撲綅 ID',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇閫�鏂欏崟鏄庣粏';
+
+-- ============ 琛細mes_wm_product_receipt_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_product_receipt_line`;
+CREATE TABLE `mes_wm_product_receipt_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `receipt_id` bigint DEFAULT NULL COMMENT '閫�鏂欏崟 ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `material_stock_id` int DEFAULT NULL,
+ `batch_id` int DEFAULT NULL,
+ `batch_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇閫�鏂欏崟琛�';
+
+-- ============ 琛細mes_wm_product_sales锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_product_sales`;
+CREATE TABLE `mes_wm_product_sales` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍗曞彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍚嶇О',
+ `client_id` bigint DEFAULT NULL COMMENT '瀹㈡埛 ID',
+ `sale_order_id` bigint DEFAULT NULL COMMENT '閿�鍞鍗旾D',
+ `notice_id` bigint DEFAULT NULL COMMENT '鍙戣揣閫氱煡鍗旾D',
+ `sales_order_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閿�鍞鍗曞彿',
+ `sales_date` datetime DEFAULT NULL COMMENT '鍑哄簱鏃ユ湡',
+ `contact_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑱旂郴浜�',
+ `contact_telephone` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑱旂郴鐢佃瘽',
+ `contact_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏀惰揣鍦板潃',
+ `carrier` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵胯繍鍟�',
+ `shipping_number` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '杩愯緭鍗曞彿',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴佺▼瀹炰緥ID',
+ `process_definition_key` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴佺▼瀹氫箟Key',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 閿�鍞嚭搴撳崟';
+
+-- ============ 琛細mes_wm_product_sales_detail锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_product_sales_detail`;
+CREATE TABLE `mes_wm_product_sales_detail` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `line_id` bigint DEFAULT NULL COMMENT '琛� ID',
+ `sales_id` bigint DEFAULT NULL COMMENT '鍑哄簱鍗� ID',
+ `material_stock_id` bigint DEFAULT NULL COMMENT '搴撳瓨 ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规 ID',
+ `batch_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵规鍙�',
+ `warehouse_id` bigint DEFAULT NULL COMMENT '浠撳簱 ID',
+ `location_id` bigint DEFAULT NULL COMMENT '搴撳尯 ID',
+ `area_id` bigint DEFAULT NULL COMMENT '搴撲綅 ID',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 閿�鍞嚭搴撳崟鏄庣粏';
+
+-- ============ 琛細mes_wm_product_sales_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_product_sales_line`;
+CREATE TABLE `mes_wm_product_sales_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `sales_id` bigint DEFAULT NULL COMMENT '鍑哄簱鍗� ID',
+ `sale_order_item_id` bigint DEFAULT NULL COMMENT '閿�鍞鍗曟槑缁咺D',
+ `notice_line_id` bigint DEFAULT NULL COMMENT '鍙戣揣閫氱煡鍗曡ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规ID',
+ `batch_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵规鍙�',
+ `material_stock_id` bigint DEFAULT NULL COMMENT '搴撳瓨璁板綍ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `oqc_check_flag` tinyint(1) DEFAULT '0' COMMENT '鏄惁妫�楠�',
+ `oqc_id` bigint DEFAULT NULL COMMENT '鍑哄巶妫�楠屽崟ID',
+ `quality_status` int DEFAULT NULL COMMENT '璐ㄩ噺鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 閿�鍞嚭搴撳崟琛�';
+
+-- ============ 琛細mes_wm_return_issue锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_return_issue`;
+CREATE TABLE `mes_wm_return_issue` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍗曞彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍚嶇О',
+ `work_order_id` bigint DEFAULT NULL COMMENT '鐢熶骇宸ュ崟 ID',
+ `task_id` bigint DEFAULT NULL COMMENT '鐢熶骇浠诲姟ID',
+ `issue_date` datetime DEFAULT NULL COMMENT '閫�鏂欐棩鏈�',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `workstation_id` int DEFAULT NULL,
+ `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
+ `return_date` datetime DEFAULT NULL,
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇閫�鏂欏崟锛堝彂鏂欙級';
+
+-- ============ 琛細mes_wm_return_issue_detail锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_return_issue_detail`;
+CREATE TABLE `mes_wm_return_issue_detail` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `line_id` bigint DEFAULT NULL COMMENT '琛� ID',
+ `issue_id` bigint DEFAULT NULL COMMENT '閫�鏂欏崟 ID',
+ `material_stock_id` bigint DEFAULT NULL COMMENT '搴撳瓨 ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规 ID',
+ `warehouse_id` bigint DEFAULT NULL COMMENT '浠撳簱 ID',
+ `location_id` bigint DEFAULT NULL COMMENT '搴撳尯 ID',
+ `area_id` bigint DEFAULT NULL COMMENT '搴撲綅 ID',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `batch_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇閫�鏂欏崟鏄庣粏锛堝彂鏂欙級';
+
+-- ============ 琛細mes_wm_return_issue_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_return_issue_line`;
+CREATE TABLE `mes_wm_return_issue_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `issue_id` bigint DEFAULT NULL COMMENT '閫�鏂欏崟 ID',
+ `task_id` bigint DEFAULT NULL COMMENT '鐢熶骇浠诲姟ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `material_stock_id` int DEFAULT NULL,
+ `rqc_check_flag` tinyint(1) DEFAULT NULL,
+ `quality_status` int DEFAULT NULL,
+ `batch_id` int DEFAULT NULL,
+ `batch_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
+ `rqc_id` int DEFAULT NULL,
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐢熶骇閫�鏂欏崟琛岋紙鍙戞枡锛�';
+
+-- ============ 琛細mes_wm_return_sales锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_return_sales`;
+CREATE TABLE `mes_wm_return_sales` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `after_sale_return_id` bigint DEFAULT NULL COMMENT '鍞悗閫�璐х敵璇风紪鍙凤紝鍏宠仈 after_sale_return.id',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍗曞彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍚嶇О',
+ `sales_order_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閿�鍞鍗曠紪鍙�',
+ `sale_order_id` bigint DEFAULT NULL COMMENT '閿�鍞鍗� ID',
+ `client_id` bigint DEFAULT NULL COMMENT '瀹㈡埛 ID',
+ `return_date` datetime DEFAULT NULL COMMENT '閫�璐ф棩鏈�',
+ `return_reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閫�璐у師鍥�',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 閿�鍞��璐у崟';
+
+-- ============ 琛細mes_wm_return_sales_detail锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_return_sales_detail`;
+CREATE TABLE `mes_wm_return_sales_detail` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `line_id` bigint DEFAULT NULL COMMENT '琛� ID',
+ `return_id` bigint DEFAULT NULL COMMENT '閫�璐у崟 ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规 ID',
+ `batch_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵规鍙�',
+ `warehouse_id` bigint DEFAULT NULL COMMENT '浠撳簱 ID',
+ `location_id` bigint DEFAULT NULL COMMENT '搴撳尯 ID',
+ `area_id` bigint DEFAULT NULL COMMENT '搴撲綅 ID',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 閿�鍞��璐у崟鏄庣粏';
+
+-- ============ 琛細mes_wm_return_sales_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_return_sales_line`;
+CREATE TABLE `mes_wm_return_sales_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `return_id` bigint DEFAULT NULL COMMENT '閫�璐у崟 ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规 ID',
+ `batch_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵规鍙�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `rqc_check_flag` tinyint(1) DEFAULT NULL COMMENT '鏄惁闇�瑕佽川妫�',
+ `rqc_id` int DEFAULT NULL,
+ `quality_status` int DEFAULT NULL,
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 閿�鍞��璐у崟琛�';
+
+-- ============ 琛細mes_wm_return_vendor锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_return_vendor`;
+CREATE TABLE `mes_wm_return_vendor` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍗曞彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍚嶇О',
+ `vendor_id` bigint DEFAULT NULL COMMENT '渚涘簲鍟� ID',
+ `purchase_order_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閲囪喘璁㈠崟缂栧彿',
+ `purchase_order_id` bigint DEFAULT NULL COMMENT '閲囪喘璁㈠崟缂栧彿',
+ `return_date` datetime DEFAULT NULL COMMENT '閫�璐ф棩鏈�',
+ `return_reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閫�璐у師鍥�',
+ `transport_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐗╂祦鍗曞彿',
+ `transport_telephone` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐗╂祦鑱旂郴鐢佃瘽',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 閲囪喘閫�璐у崟';
+
+-- ============ 琛細mes_wm_return_vendor_detail锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_return_vendor_detail`;
+CREATE TABLE `mes_wm_return_vendor_detail` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `line_id` bigint DEFAULT NULL COMMENT '琛� ID',
+ `return_id` bigint DEFAULT NULL COMMENT '閫�璐у崟 ID',
+ `material_stock_id` bigint DEFAULT NULL COMMENT '搴撳瓨 ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规 ID',
+ `warehouse_id` bigint DEFAULT NULL COMMENT '浠撳簱 ID',
+ `location_id` bigint DEFAULT NULL COMMENT '搴撳尯 ID',
+ `area_id` bigint DEFAULT NULL COMMENT '搴撲綅 ID',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `batch_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵规鍙�',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 閲囪喘閫�璐у崟鏄庣粏';
+
+-- ============ 琛細mes_wm_return_vendor_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_return_vendor_line`;
+CREATE TABLE `mes_wm_return_vendor_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `return_id` bigint DEFAULT NULL COMMENT '閫�璐у崟 ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规 ID',
+ `batch_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵规鍙�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 閲囪喘閫�璐у崟琛�';
+
+-- ============ 琛細mes_wm_sales_notice锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_sales_notice`;
+CREATE TABLE `mes_wm_sales_notice` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍗曞彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍚嶇О',
+ `client_id` bigint DEFAULT NULL COMMENT '瀹㈡埛 ID',
+ `sale_order_id` bigint DEFAULT NULL COMMENT '閿�鍞鍗旾D',
+ `sale_order_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閿�鍞鍗曞彿',
+ `sales_date` datetime DEFAULT NULL COMMENT '閿�鍞棩鏈�',
+ `recipient_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏀惰揣浜�',
+ `recipient_telephone` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑱旂郴鏂瑰紡',
+ `recipient_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏀惰揣鍦板潃',
+ `delivery_date` datetime DEFAULT NULL COMMENT '棰勮鍙戣揣鏃ユ湡',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `out_status` int DEFAULT '0' COMMENT '鍑哄簱鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 閿�鍞彂璐ч�氱煡鍗�';
+
+-- ============ 琛細mes_wm_sales_notice_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_sales_notice_line`;
+CREATE TABLE `mes_wm_sales_notice_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `notice_id` bigint DEFAULT NULL COMMENT '閿�鍞彂璐ч�氱煡鍗� ID',
+ `sale_order_item_id` bigint DEFAULT NULL COMMENT '閿�鍞鍗曟槑缁咺D',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规ID',
+ `batch_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵规鍙�',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏁伴噺',
+ `out_count` decimal(24,6) DEFAULT '0.000000' COMMENT '宸插嚭搴撴暟閲�',
+ `oqc_check_flag` tinyint(1) DEFAULT '0' COMMENT '鏄惁妫�楠�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 閿�鍞彂璐ч�氱煡鍗曡';
+
+-- ============ 琛細mes_wm_sn锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_sn`;
+CREATE TABLE `mes_wm_sn` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `uuid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵规UUID',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '搴忓垪鍙�',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `batch_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵规鍙�',
+ `work_order_id` bigint DEFAULT NULL COMMENT '鐢熶骇宸ュ崟缂栧彿',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规 ID',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 搴忓垪鍙�';
+
+-- ============ 琛細mes_wm_stock_reserve锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_stock_reserve`;
+CREATE TABLE `mes_wm_stock_reserve` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `material_stock_id` bigint NOT NULL COMMENT '搴撳瓨璁板綍ID',
+ `biz_type` int NOT NULL COMMENT '涓氬姟绫诲瀷锛�1閿�鍞嚭搴� 2鐢熶骇棰嗘枡 3澶栧崗鍙戞枡 4鏉傞」鍑哄簱 5杞Щ璋冩嫧锛�',
+ `biz_id` bigint NOT NULL COMMENT '涓氬姟鍗曟嵁ID',
+ `biz_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '涓氬姟鍗曞彿',
+ `biz_line_id` bigint DEFAULT NULL COMMENT '涓氬姟鍗曟嵁琛孖D',
+ `item_id` bigint NOT NULL COMMENT '鐗╂枡ID',
+ `quantity` decimal(24,6) NOT NULL COMMENT '鍗犵敤鏁伴噺',
+ `status` int NOT NULL DEFAULT '1' COMMENT '鐘舵�侊紙1鍗犵敤涓� 2宸查噴鏀� 3宸插嚭搴擄級',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_material_stock` (`material_stock_id`) USING BTREE,
+ KEY `idx_biz` (`biz_type`,`biz_id`) USING BTREE,
+ KEY `idx_status` (`status`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='MES 搴撳瓨鍗犵敤璁板綍';
+
+-- ============ 琛細mes_wm_stock_taking_plan锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_stock_taking_plan`;
+CREATE TABLE `mes_wm_stock_taking_plan` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐩樼偣璁″垝缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐩樼偣璁″垝鍚嶇О',
+ `plan_date` datetime DEFAULT NULL COMMENT '鐩樼偣鏃ユ湡',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴佺▼瀹炰緥ID',
+ `process_definition_key` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴佺▼瀹氫箟Key',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `type` int DEFAULT NULL COMMENT '鐩樼偣绫诲瀷',
+ `start_time` datetime DEFAULT NULL COMMENT '璁″垝寮�濮嬫椂闂�',
+ `end_time` datetime DEFAULT NULL COMMENT '璁″垝缁撴潫鏃堕棿',
+ `blind_flag` bit(1) DEFAULT NULL COMMENT '鏄惁鐩茬洏',
+ `frozen` bit(1) DEFAULT NULL COMMENT '鏄惁鍐荤粨搴撳瓨',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐩樼偣璁″垝';
+
+-- ============ 琛細mes_wm_stock_taking_plan_param锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_stock_taking_plan_param`;
+CREATE TABLE `mes_wm_stock_taking_plan_param` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `plan_id` bigint DEFAULT NULL COMMENT '鐩樼偣璁″垝 ID',
+ `warehouse_id` bigint DEFAULT NULL COMMENT '浠撳簱 ID',
+ `location_id` bigint DEFAULT NULL COMMENT '搴撳尯 ID',
+ `area_id` bigint DEFAULT NULL COMMENT '搴撲綅 ID',
+ `item_type_id` bigint DEFAULT NULL COMMENT '鐗╂枡鍒嗙被 ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `type` int DEFAULT NULL COMMENT '鍙傛暟鍊肩被鍨�',
+ `value_id` bigint DEFAULT NULL COMMENT '鍙傛暟鍊肩紪鍙�',
+ `value_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍙傛暟鍊肩紪鐮�',
+ `value_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍙傛暟鍊煎悕绉�',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐩樼偣璁″垝鍙傛暟';
+
+-- ============ 琛細mes_wm_stock_taking_task锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_stock_taking_task`;
+CREATE TABLE `mes_wm_stock_taking_task` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐩樼偣浠诲姟缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐩樼偣浠诲姟鍚嶇О',
+ `plan_id` bigint DEFAULT NULL COMMENT '鐩樼偣璁″垝 ID',
+ `task_date` datetime DEFAULT NULL COMMENT '鐩樼偣鏃ユ湡',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐩樼偣浠诲姟';
+
+-- ============ 琛細mes_wm_stock_taking_task_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_stock_taking_task_line`;
+CREATE TABLE `mes_wm_stock_taking_task_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `task_id` bigint DEFAULT NULL COMMENT '鐩樼偣浠诲姟 ID',
+ `material_stock_id` bigint DEFAULT NULL COMMENT '搴撳瓨 ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规 ID',
+ `warehouse_id` bigint DEFAULT NULL COMMENT '浠撳簱 ID',
+ `location_id` bigint DEFAULT NULL COMMENT '搴撳尯 ID',
+ `area_id` bigint DEFAULT NULL COMMENT '搴撲綅 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '璐﹂潰鏁伴噺',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐩樼偣浠诲姟琛�';
+
+-- ============ 琛細mes_wm_stock_taking_task_result锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_stock_taking_task_result`;
+CREATE TABLE `mes_wm_stock_taking_task_result` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `task_id` bigint DEFAULT NULL COMMENT '鐩樼偣浠诲姟 ID',
+ `line_id` bigint DEFAULT NULL COMMENT '鐩樼偣浠诲姟琛� ID',
+ `material_stock_id` bigint DEFAULT NULL COMMENT '搴撳瓨 ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规 ID',
+ `warehouse_id` bigint DEFAULT NULL COMMENT '浠撳簱 ID',
+ `location_id` bigint DEFAULT NULL COMMENT '搴撳尯 ID',
+ `area_id` bigint DEFAULT NULL COMMENT '搴撲綅 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '瀹炵洏鏁伴噺',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 鐩樼偣浠诲姟缁撴灉';
+
+-- ============ 琛細mes_wm_transaction锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_transaction`;
+CREATE TABLE `mes_wm_transaction` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `type` int DEFAULT NULL COMMENT '浜嬪姟绫诲瀷',
+ `biz_type` int DEFAULT NULL COMMENT '涓氬姟绫诲瀷',
+ `biz_id` bigint DEFAULT NULL COMMENT '鏉ユ簮涓氬姟涓诲崟 ID',
+ `biz_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏉ユ簮涓氬姟鍗曞彿',
+ `biz_line_id` bigint DEFAULT NULL COMMENT '鏉ユ簮涓氬姟琛� ID',
+ `material_stock_id` bigint DEFAULT NULL COMMENT '搴撳瓨璁板綍 ID',
+ `related_transaction_id` bigint DEFAULT NULL COMMENT '鍏宠仈鐨勪簨鍔� ID',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡 ID',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '鏈鍙樺姩鏁伴噺',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规 ID',
+ `batch_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵规鍙�',
+ `warehouse_id` bigint DEFAULT NULL COMMENT '浠撳簱 ID',
+ `location_id` bigint DEFAULT NULL COMMENT '搴撳尯 ID',
+ `area_id` bigint DEFAULT NULL COMMENT '搴撲綅 ID',
+ `transaction_time` datetime DEFAULT NULL COMMENT '浜嬪姟鍙戠敓鏃堕棿',
+ `erp_time` datetime DEFAULT NULL COMMENT 'ERP 璐︽湡',
+ `receipt_time` datetime DEFAULT NULL COMMENT '鍏ュ簱鏃堕棿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 搴撳瓨浜嬪姟娴佹按';
+
+-- ============ 琛細mes_wm_transfer锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_transfer`;
+CREATE TABLE `mes_wm_transfer` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '杞Щ鍗曠紪鍙�',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '杞Щ鍗曞悕绉�',
+ `type` int DEFAULT NULL COMMENT '杞Щ鍗曠被鍨�',
+ `delivery_flag` bit(1) DEFAULT b'0' COMMENT '鏄惁閰嶉��',
+ `recipient_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏀惰揣浜�',
+ `recipient_telephone` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑱旂郴鏂瑰紡',
+ `destination_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐩殑鍦�',
+ `carrier` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵胯繍鍟�',
+ `shipping_number` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '杩愯緭鍗曞彿',
+ `confirm_flag` bit(1) DEFAULT b'0' COMMENT '鏄惁宸茬‘璁�',
+ `transfer_date` datetime DEFAULT NULL COMMENT '杞Щ鏃ユ湡',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴佺▼瀹炰緥ID',
+ `process_definition_key` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴佺▼瀹氫箟Key',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 杞Щ鍗�';
+
+-- ============ 琛細mes_wm_transfer_detail锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_transfer_detail`;
+CREATE TABLE `mes_wm_transfer_detail` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `line_id` bigint DEFAULT NULL COMMENT '杞Щ鍗曡缂栧彿',
+ `transfer_id` bigint DEFAULT NULL COMMENT '杞Щ鍗曠紪鍙�',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡缂栧彿',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '涓婃灦鏁伴噺',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规缂栧彿',
+ `to_warehouse_id` bigint DEFAULT NULL COMMENT '绉诲叆浠撳簱缂栧彿',
+ `to_location_id` bigint DEFAULT NULL COMMENT '绉诲叆搴撳尯缂栧彿',
+ `to_area_id` bigint DEFAULT NULL COMMENT '绉诲叆搴撲綅缂栧彿',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 杞Щ鍗曟槑缁�';
+
+-- ============ 琛細mes_wm_transfer_line锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_transfer_line`;
+CREATE TABLE `mes_wm_transfer_line` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `transfer_id` bigint DEFAULT NULL COMMENT '杞Щ鍗曠紪鍙�',
+ `material_stock_id` bigint DEFAULT NULL COMMENT '搴撳瓨璁板綍缂栧彿',
+ `item_id` bigint DEFAULT NULL COMMENT '鐗╂枡缂栧彿',
+ `quantity` decimal(24,6) DEFAULT NULL COMMENT '杞Щ鏁伴噺',
+ `batch_id` bigint DEFAULT NULL COMMENT '鎵规缂栧彿',
+ `from_warehouse_id` bigint DEFAULT NULL COMMENT '绉诲嚭浠撳簱缂栧彿',
+ `from_location_id` bigint DEFAULT NULL COMMENT '绉诲嚭搴撳尯缂栧彿',
+ `from_area_id` bigint DEFAULT NULL COMMENT '绉诲嚭搴撲綅缂栧彿',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 杞Щ鍗曡';
+
+-- ============ 琛細mes_wm_warehouse锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_warehouse`;
+CREATE TABLE `mes_wm_warehouse` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '浠撳簱缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '浠撳簱鍚嶇О',
+ `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '浠撳簱鍦板潃',
+ `area` decimal(24,6) DEFAULT NULL COMMENT '闈㈢Н',
+ `charge_user_id` bigint DEFAULT NULL COMMENT '璐熻矗浜虹敤鎴风紪鍙�',
+ `frozen` bit(1) DEFAULT b'0' COMMENT '鏄惁鍐荤粨',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 浠撳簱';
+
+-- ============ 琛細mes_wm_warehouse_area锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_warehouse_area`;
+CREATE TABLE `mes_wm_warehouse_area` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '搴撲綅缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '搴撲綅鍚嶇О',
+ `location_id` bigint DEFAULT NULL COMMENT '搴撳尯缂栧彿',
+ `area` decimal(24,6) DEFAULT NULL COMMENT '闈㈢Н',
+ `max_load` decimal(24,6) DEFAULT NULL COMMENT '鏈�澶ц浇閲�',
+ `position_x` int DEFAULT NULL COMMENT '浣嶇疆 X',
+ `position_y` int DEFAULT NULL COMMENT '浣嶇疆 Y',
+ `position_z` int DEFAULT NULL COMMENT '浣嶇疆 Z',
+ `status` int DEFAULT NULL COMMENT '鐘舵��',
+ `frozen` bit(1) DEFAULT b'0' COMMENT '鏄惁鍐荤粨',
+ `allow_item_mixing` bit(1) DEFAULT b'0' COMMENT '鏄惁鍏佽鐗╂枡娣锋斁',
+ `allow_batch_mixing` bit(1) DEFAULT b'0' COMMENT '鏄惁鍏佽鎵规娣锋斁',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 搴撲綅';
+
+-- ============ 琛細mes_wm_warehouse_location锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `mes_wm_warehouse_location`;
+CREATE TABLE `mes_wm_warehouse_location` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '搴撳尯缂栫爜',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '搴撳尯鍚嶇О',
+ `warehouse_id` bigint DEFAULT NULL COMMENT '浠撳簱缂栧彿',
+ `area` decimal(24,6) DEFAULT NULL COMMENT '闈㈢Н',
+ `frozen` bit(1) DEFAULT b'0' COMMENT '鏄惁鍐荤粨',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='MES 搴撳尯';
+
+-- ============ 琛細oa_notice锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `oa_notice`;
+CREATE TABLE `oa_notice` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
+ `title` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鍏憡鏍囬',
+ `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鍏憡鍐呭',
+ `type` tinyint NOT NULL COMMENT '鍏憡绫诲瀷锛�1閫氱煡 2鍏憡锛�',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0鑽夌 1宸插彂甯� 2宸叉挙閿�锛�',
+ `send_scope` tinyint NOT NULL COMMENT '鍙戦�佽寖鍥达紙1閫氱煡鎵�鏈変汉 2鎸囧畾浜猴級',
+ `is_top` tinyint NOT NULL DEFAULT '0' COMMENT '鏄惁缃《锛�0鍚� 1鏄級',
+ `publish_user_id` bigint DEFAULT NULL COMMENT '鍙戝竷浜篒D',
+ `publish_time` datetime DEFAULT NULL COMMENT '鍙戝竷鏃堕棿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_type` (`type`) USING BTREE,
+ KEY `idx_status` (`status`) USING BTREE,
+ KEY `idx_publish_time` (`publish_time`) USING BTREE,
+ KEY `idx_is_top` (`is_top`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='OA閫氱煡鍏憡琛�';
+
+-- ============ 琛細oa_notice_read锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `oa_notice_read`;
+CREATE TABLE `oa_notice_read` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
+ `notice_id` bigint NOT NULL COMMENT '閫氱煡鍏憡ID',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛ID',
+ `read_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '闃呰鏃堕棿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_notice_user` (`notice_id`,`user_id`) USING BTREE,
+ KEY `idx_notice_id` (`notice_id`) USING BTREE,
+ KEY `idx_user_id` (`user_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='OA閫氱煡鍏憡宸茶璁板綍琛�';
+
+-- ============ 琛細oa_notice_user锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `oa_notice_user`;
+CREATE TABLE `oa_notice_user` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭ID',
+ `notice_id` bigint NOT NULL COMMENT '閫氱煡鍏憡ID',
+ `user_id` bigint NOT NULL COMMENT '鎸囧畾鐢ㄦ埛ID',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_notice_id` (`notice_id`) USING BTREE,
+ KEY `idx_user_id` (`user_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='OA閫氱煡鍏憡鎸囧畾浜哄叧鑱旇〃';
+
+-- ============ 琛細qc_report_template锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `qc_report_template`;
+CREATE TABLE `qc_report_template` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '妯℃澘缂栧彿',
+ `template_code` varchar(64) NOT NULL COMMENT '妯℃澘缂栫爜',
+ `template_name` varchar(128) NOT NULL COMMENT '妯℃澘鍚嶇О',
+ `industry` varchar(32) DEFAULT NULL COMMENT '鎵�灞炶涓�',
+ `report_type` varchar(32) DEFAULT NULL COMMENT '鎶ュ憡绫诲瀷',
+ `page_size` varchar(16) NOT NULL DEFAULT 'A4' COMMENT '绾稿紶灏哄锛欰3/A4/A5/Letter',
+ `orientation` varchar(16) NOT NULL DEFAULT 'portrait' COMMENT '绾稿紶鏂瑰悜锛歱ortrait/landscape',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '妯℃澘鐘舵�侊細0鍚敤 1鍋滅敤',
+ `current_version` varchar(32) DEFAULT NULL COMMENT '褰撳墠鐗堟湰鍙�',
+ `description` varchar(512) DEFAULT NULL COMMENT '妯℃澘鎻忚堪',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_template_code` (`template_code`) USING BTREE,
+ KEY `idx_template_name` (`template_name`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='鏅鸿兘璐ㄦ鎶ュ憡-鎶ュ憡妯℃澘';
+
+-- ============ 琛細qc_report_template_version锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `qc_report_template_version`;
+CREATE TABLE `qc_report_template_version` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鐗堟湰缂栧彿',
+ `template_id` bigint NOT NULL COMMENT '妯℃澘缂栧彿',
+ `version` varchar(32) NOT NULL COMMENT '鐗堟湰鍙凤紝濡� v1.0',
+ `schema_json` longtext COMMENT '妯℃澘 Schema锛圙rapesJS JSON + 缁勪欢 + 鏁版嵁婧� + 缁戝畾 + 瑙勫垯 + 鏍峰紡锛�',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鐗堟湰鐘舵�侊細0鑽夌 1宸插彂甯� 2宸插仠鐢�',
+ `description` varchar(512) DEFAULT NULL COMMENT '鐗堟湰璇存槑',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_template_version` (`template_id`,`version`) USING BTREE,
+ KEY `idx_template_id` (`template_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='鏅鸿兘璐ㄦ鎶ュ憡-妯℃澘鐗堟湰';
+
+-- ============ 琛細qc_report_instance锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `qc_report_instance`;
+CREATE TABLE `qc_report_instance` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '瀹炰緥缂栧彿',
+ `report_no` varchar(64) NOT NULL COMMENT '鎶ュ憡缂栧彿锛堜笟鍔″敮涓�锛�',
+ `template_id` bigint NOT NULL COMMENT '妯℃澘缂栧彿',
+ `template_version` varchar(32) NOT NULL COMMENT '鐢熸垚鏃朵娇鐢ㄧ殑妯℃澘鐗堟湰鍙�',
+ `business_id` varchar(64) DEFAULT NULL COMMENT '涓氬姟鍗曟嵁缂栧彿',
+ `business_type` varchar(64) DEFAULT NULL COMMENT '涓氬姟鍗曟嵁绫诲瀷锛屽 mes_qc_iqc',
+ `data_snapshot` longtext COMMENT '鏁版嵁蹇収锛氭覆鏌撴椂鐨勫畬鏁存暟鎹笂涓嬫枃',
+ `render_html` longtext COMMENT '娓叉煋浜х墿 HTML',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鎶ュ憡鐘舵�侊細0鐢熸垚涓� 1鐢熸垚鎴愬姛 2鐢熸垚澶辫触',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_report_no` (`report_no`) USING BTREE,
+ KEY `idx_template_id` (`template_id`) USING BTREE,
+ KEY `idx_business` (`business_type`,`business_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='鏅鸿兘璐ㄦ鎶ュ憡-鎶ュ憡瀹炰緥';
+
+-- ============ 琛細qc_report_data_source锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `qc_report_data_source`;
+CREATE TABLE `qc_report_data_source` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `template_id` bigint NOT NULL COMMENT '妯℃澘缂栧彿',
+ `source_key` varchar(64) NOT NULL COMMENT '鏁版嵁婧愭爣璇嗭紝濡� inspectionItems',
+ `source_type` varchar(32) NOT NULL COMMENT '鏁版嵁婧愮被鍨嬶細BUILTIN/SQL/API',
+ `config` longtext COMMENT '鏁版嵁婧愰厤缃� JSON',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_template_id` (`template_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='鏅鸿兘璐ㄦ鎶ュ憡-鏁版嵁婧�';
+
+-- ============ 琛細qc_report_rule锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `qc_report_rule`;
+CREATE TABLE `qc_report_rule` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `template_id` bigint NOT NULL COMMENT '妯℃澘缂栧彿',
+ `rule_name` varchar(128) NOT NULL COMMENT '瑙勫垯鍚嶇О',
+ `target_path` varchar(256) NOT NULL COMMENT '浣滅敤鐩爣璺緞锛屽 inspectionItems[].actualValue',
+ `expression` varchar(1024) NOT NULL COMMENT '鍒ゅ畾琛ㄨ揪寮忥紝濡� actualValue >= lowerLimit AND actualValue <= upperLimit',
+ `pass_value` varchar(64) DEFAULT 'PASS' COMMENT '鍚堟牸鏃惰緭鍑哄��',
+ `fail_value` varchar(64) DEFAULT 'FAIL' COMMENT '涓嶅悎鏍兼椂杈撳嚭鍊�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_template_id` (`template_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='鏅鸿兘璐ㄦ鎶ュ憡-鍒ゅ畾瑙勫垯';
+
+-- ============ 琛細qc_report_render_record锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `qc_report_render_record`;
+CREATE TABLE `qc_report_render_record` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `report_id` bigint DEFAULT NULL COMMENT '鎶ュ憡瀹炰緥缂栧彿',
+ `template_id` bigint DEFAULT NULL COMMENT '妯℃澘缂栧彿',
+ `business_id` varchar(64) DEFAULT NULL COMMENT '涓氬姟鍗曟嵁缂栧彿',
+ `render_start_time` datetime DEFAULT NULL COMMENT '娓叉煋寮�濮嬫椂闂�',
+ `render_end_time` datetime DEFAULT NULL COMMENT '娓叉煋缁撴潫鏃堕棿',
+ `render_duration` bigint DEFAULT NULL COMMENT '娓叉煋鑰楁椂锛堟绉掞級',
+ `pdf_duration` bigint DEFAULT NULL COMMENT 'PDF 鐢熸垚鑰楁椂锛堟绉掞級',
+ `browser_status` varchar(64) DEFAULT NULL COMMENT '娴忚鍣ㄧ姸鎬�',
+ `error_stack` longtext COMMENT '寮傚父鍫嗘爤',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_report_id` (`report_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='鏅鸿兘璐ㄦ鎶ュ憡-娓叉煋璁板綍';
+
+-- ============ 琛細qrtz_blob_triggers锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `qrtz_blob_triggers`;
+CREATE TABLE `qrtz_blob_triggers` (
+ `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `BLOB_DATA` blob,
+ PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`) USING BTREE,
+ KEY `SCHED_NAME` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`) USING BTREE,
+ CONSTRAINT `qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細qrtz_calendars锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `qrtz_calendars`;
+CREATE TABLE `qrtz_calendars` (
+ `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `CALENDAR_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `CALENDAR` blob NOT NULL,
+ PRIMARY KEY (`SCHED_NAME`,`CALENDAR_NAME`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細qrtz_cron_triggers锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `qrtz_cron_triggers`;
+CREATE TABLE `qrtz_cron_triggers` (
+ `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `CRON_EXPRESSION` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `TIME_ZONE_ID` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
+ PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`) USING BTREE,
+ CONSTRAINT `qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細qrtz_fired_triggers锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `qrtz_fired_triggers`;
+CREATE TABLE `qrtz_fired_triggers` (
+ `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `ENTRY_ID` varchar(95) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `INSTANCE_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `FIRED_TIME` bigint NOT NULL,
+ `SCHED_TIME` bigint NOT NULL,
+ `PRIORITY` int NOT NULL,
+ `STATE` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `JOB_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
+ `JOB_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
+ `IS_NONCONCURRENT` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
+ `REQUESTS_RECOVERY` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
+ PRIMARY KEY (`SCHED_NAME`,`ENTRY_ID`) USING BTREE,
+ KEY `IDX_QRTZ_FT_TRIG_INST_NAME` (`SCHED_NAME`,`INSTANCE_NAME`) USING BTREE,
+ KEY `IDX_QRTZ_FT_INST_JOB_REQ_RCVRY` (`SCHED_NAME`,`INSTANCE_NAME`,`REQUESTS_RECOVERY`) USING BTREE,
+ KEY `IDX_QRTZ_FT_J_G` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`) USING BTREE,
+ KEY `IDX_QRTZ_FT_JG` (`SCHED_NAME`,`JOB_GROUP`) USING BTREE,
+ KEY `IDX_QRTZ_FT_T_G` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`) USING BTREE,
+ KEY `IDX_QRTZ_FT_TG` (`SCHED_NAME`,`TRIGGER_GROUP`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細qrtz_job_details锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `qrtz_job_details`;
+CREATE TABLE `qrtz_job_details` (
+ `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `JOB_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `JOB_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `DESCRIPTION` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
+ `JOB_CLASS_NAME` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `IS_DURABLE` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `IS_NONCONCURRENT` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `IS_UPDATE_DATA` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `REQUESTS_RECOVERY` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `JOB_DATA` blob,
+ PRIMARY KEY (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`) USING BTREE,
+ KEY `IDX_QRTZ_J_REQ_RECOVERY` (`SCHED_NAME`,`REQUESTS_RECOVERY`) USING BTREE,
+ KEY `IDX_QRTZ_J_GRP` (`SCHED_NAME`,`JOB_GROUP`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細qrtz_locks锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `qrtz_locks`;
+CREATE TABLE `qrtz_locks` (
+ `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `LOCK_NAME` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ PRIMARY KEY (`SCHED_NAME`,`LOCK_NAME`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細qrtz_paused_trigger_grps锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `qrtz_paused_trigger_grps`;
+CREATE TABLE `qrtz_paused_trigger_grps` (
+ `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ PRIMARY KEY (`SCHED_NAME`,`TRIGGER_GROUP`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細qrtz_scheduler_state锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `qrtz_scheduler_state`;
+CREATE TABLE `qrtz_scheduler_state` (
+ `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `INSTANCE_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `LAST_CHECKIN_TIME` bigint NOT NULL,
+ `CHECKIN_INTERVAL` bigint NOT NULL,
+ PRIMARY KEY (`SCHED_NAME`,`INSTANCE_NAME`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細qrtz_simple_triggers锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `qrtz_simple_triggers`;
+CREATE TABLE `qrtz_simple_triggers` (
+ `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `REPEAT_COUNT` bigint NOT NULL,
+ `REPEAT_INTERVAL` bigint NOT NULL,
+ `TIMES_TRIGGERED` bigint NOT NULL,
+ PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`) USING BTREE,
+ CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細qrtz_simprop_triggers锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `qrtz_simprop_triggers`;
+CREATE TABLE `qrtz_simprop_triggers` (
+ `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `STR_PROP_1` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
+ `STR_PROP_2` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
+ `STR_PROP_3` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
+ `INT_PROP_1` int DEFAULT NULL,
+ `INT_PROP_2` int DEFAULT NULL,
+ `LONG_PROP_1` bigint DEFAULT NULL,
+ `LONG_PROP_2` bigint DEFAULT NULL,
+ `DEC_PROP_1` decimal(13,4) DEFAULT NULL,
+ `DEC_PROP_2` decimal(13,4) DEFAULT NULL,
+ `BOOL_PROP_1` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
+ `BOOL_PROP_2` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
+ PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`) USING BTREE,
+ CONSTRAINT `qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細qrtz_triggers锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `qrtz_triggers`;
+CREATE TABLE `qrtz_triggers` (
+ `SCHED_NAME` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `TRIGGER_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `TRIGGER_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `JOB_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `JOB_GROUP` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `DESCRIPTION` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
+ `NEXT_FIRE_TIME` bigint DEFAULT NULL,
+ `PREV_FIRE_TIME` bigint DEFAULT NULL,
+ `PRIORITY` int DEFAULT NULL,
+ `TRIGGER_STATE` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `TRIGGER_TYPE` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
+ `START_TIME` bigint NOT NULL,
+ `END_TIME` bigint DEFAULT NULL,
+ `CALENDAR_NAME` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
+ `MISFIRE_INSTR` smallint DEFAULT NULL,
+ `JOB_DATA` blob,
+ PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`) USING BTREE,
+ KEY `IDX_QRTZ_T_J` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`) USING BTREE,
+ KEY `IDX_QRTZ_T_JG` (`SCHED_NAME`,`JOB_GROUP`) USING BTREE,
+ KEY `IDX_QRTZ_T_C` (`SCHED_NAME`,`CALENDAR_NAME`) USING BTREE,
+ KEY `IDX_QRTZ_T_G` (`SCHED_NAME`,`TRIGGER_GROUP`) USING BTREE,
+ KEY `IDX_QRTZ_T_STATE` (`SCHED_NAME`,`TRIGGER_STATE`) USING BTREE,
+ KEY `IDX_QRTZ_T_N_STATE` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`) USING BTREE,
+ KEY `IDX_QRTZ_T_N_G_STATE` (`SCHED_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`) USING BTREE,
+ KEY `IDX_QRTZ_T_NEXT_FIRE_TIME` (`SCHED_NAME`,`NEXT_FIRE_TIME`) USING BTREE,
+ KEY `IDX_QRTZ_T_NFT_ST` (`SCHED_NAME`,`TRIGGER_STATE`,`NEXT_FIRE_TIME`) USING BTREE,
+ KEY `IDX_QRTZ_T_NFT_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`) USING BTREE,
+ KEY `IDX_QRTZ_T_NFT_ST_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_STATE`) USING BTREE,
+ KEY `IDX_QRTZ_T_NFT_ST_MISFIRE_GRP` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_GROUP`,`TRIGGER_STATE`) USING BTREE,
+ CONSTRAINT `qrtz_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) REFERENCES `qrtz_job_details` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
+
+-- ============ 琛細srm_bid_award锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `srm_bid_award`;
+CREATE TABLE `srm_bid_award` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '瀹氭爣ID',
+ `tender_project_id` bigint NOT NULL COMMENT '鎷涙爣椤圭洰ID',
+ `supplier_id` bigint NOT NULL COMMENT '涓爣渚涘簲鍟咺D',
+ `bid_id` bigint NOT NULL COMMENT '涓爣鎶曟爣ID',
+ `award_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '涓爣閫氱煡涔︾紪鍙�',
+ `award_status` int NOT NULL DEFAULT '0' COMMENT '瀹氭爣鐘舵��',
+ `award_amount` decimal(24,6) NOT NULL COMMENT '涓爣閲戦',
+ `award_time` datetime DEFAULT NULL COMMENT '瀹氭爣鏃堕棿',
+ `notice_file_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '涓爣閫氱煡涔︽枃浠跺悕',
+ `notice_file_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '涓爣閫氱煡涔︽枃浠跺湴鍧�',
+ `purchase_order_id` bigint DEFAULT NULL COMMENT '鍏宠仈鐢熸垚鐨勯噰璐鍗旾D',
+ `purchase_order_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍏宠仈鐢熸垚鐨勯噰璐鍗曞彿',
+ `approver_id` bigint DEFAULT NULL COMMENT '瀹℃壒浜篒D',
+ `approval_time` datetime DEFAULT NULL COMMENT '瀹℃壒鏃堕棿',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_award_no` (`award_no`) USING BTREE,
+ KEY `idx_tender_project_id` (`tender_project_id`) USING BTREE,
+ KEY `idx_supplier_id` (`supplier_id`) USING BTREE,
+ KEY `idx_purchase_order_id` (`purchase_order_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='瀹氭爣璁板綍琛�';
+
+-- ============ 琛細srm_bid_evaluation锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `srm_bid_evaluation`;
+CREATE TABLE `srm_bid_evaluation` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '璇勬爣ID',
+ `tender_project_id` bigint NOT NULL COMMENT '鎷涙爣椤圭洰ID',
+ `supplier_id` bigint NOT NULL COMMENT '渚涘簲鍟咺D',
+ `bid_id` bigint NOT NULL COMMENT '鎶曟爣璁板綍ID',
+ `price_score` decimal(5,2) DEFAULT NULL COMMENT '浠锋牸璇勫垎',
+ `tech_score` decimal(5,2) DEFAULT NULL COMMENT '鎶�鏈瘎鍒�',
+ `delivery_score` decimal(5,2) DEFAULT NULL COMMENT '浜や粯璇勫垎',
+ `service_score` decimal(5,2) DEFAULT NULL COMMENT '鏈嶅姟璇勫垎',
+ `composite_score` decimal(5,2) DEFAULT NULL COMMENT '缁煎悎璇勫垎',
+ `ranking` int DEFAULT NULL COMMENT '鎺掑悕',
+ `evaluator_id` bigint DEFAULT NULL COMMENT '璇勬爣浜篒D',
+ `evaluator_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璇勬爣浜哄鍚�',
+ `evaluation_opinion` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璇勬爣鎰忚',
+ `evaluation_time` datetime DEFAULT NULL COMMENT '璇勬爣鏃堕棿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_tender_project_id` (`tender_project_id`) USING BTREE,
+ KEY `idx_supplier_id` (`supplier_id`) USING BTREE,
+ KEY `idx_bid_id` (`bid_id`) USING BTREE,
+ KEY `idx_ranking` (`ranking`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='璇勬爣璁板綍琛�';
+
+-- ============ 琛細srm_bid_open锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `srm_bid_open`;
+CREATE TABLE `srm_bid_open` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '寮�鏍嘔D',
+ `tender_project_id` bigint NOT NULL COMMENT '鎷涙爣椤圭洰ID',
+ `open_time` datetime NOT NULL COMMENT '寮�鏍囨椂闂�',
+ `open_person_id` bigint DEFAULT NULL COMMENT '寮�鏍囦汉鍛業D',
+ `open_person_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '寮�鏍囦汉鍛樺鍚�',
+ `open_record` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '寮�鏍囪褰�',
+ `attachment_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '闄勪欢鍚嶇О',
+ `attachment_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '闄勪欢鍦板潃',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_tender_project_id` (`tender_project_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='寮�鏍囪褰曡〃';
+
+-- ============ 琛細srm_delivery_plan锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `srm_delivery_plan`;
+CREATE TABLE `srm_delivery_plan` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '浜よ揣璁″垝ID',
+ `collaboration_id` bigint NOT NULL COMMENT '閲囪喘鍗忓悓ID',
+ `order_id` bigint NOT NULL COMMENT '閲囪喘璁㈠崟ID',
+ `order_item_id` bigint DEFAULT NULL COMMENT '閲囪喘璁㈠崟椤笽D',
+ `product_id` bigint DEFAULT NULL COMMENT '鐗╂枡ID',
+ `product_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐗╂枡鍚嶇О',
+ `planned_quantity` decimal(24,6) NOT NULL COMMENT '璁″垝鏁伴噺',
+ `actual_quantity` decimal(24,6) DEFAULT NULL COMMENT '瀹為檯鏁伴噺',
+ `planned_delivery_date` date NOT NULL COMMENT '璁″垝浜よ揣鏃ユ湡',
+ `actual_delivery_date` date DEFAULT NULL COMMENT '瀹為檯浜よ揣鏃ユ湡',
+ `delivery_status` int NOT NULL DEFAULT '0' COMMENT '浜よ揣鐘舵��',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_collaboration_id` (`collaboration_id`) USING BTREE,
+ KEY `idx_order_id` (`order_id`) USING BTREE,
+ KEY `idx_delivery_status` (`delivery_status`) USING BTREE,
+ KEY `idx_planned_delivery_date` (`planned_delivery_date`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='浜よ揣璁″垝琛�';
+
+-- ============ 琛細srm_purchase_collaboration锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `srm_purchase_collaboration`;
+CREATE TABLE `srm_purchase_collaboration` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鍗忓悓ID',
+ `order_id` bigint NOT NULL COMMENT '閲囪喘璁㈠崟ID',
+ `order_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '閲囪喘璁㈠崟鍙�',
+ `supplier_id` bigint NOT NULL COMMENT '渚涘簲鍟咺D',
+ `collaboration_status` int NOT NULL DEFAULT '0' COMMENT '鍗忓悓鐘舵��',
+ `confirm_time` datetime DEFAULT NULL COMMENT '纭鏃堕棿',
+ `confirm_user` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '纭浜�',
+ `reject_reason` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎷掔粷鍘熷洜',
+ `planned_delivery_time` datetime DEFAULT NULL COMMENT '棰勮浜や粯鏃堕棿',
+ `actual_delivery_time` datetime DEFAULT NULL COMMENT '瀹為檯浜や粯鏃堕棿',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_order_id` (`order_id`) USING BTREE,
+ KEY `idx_supplier_id` (`supplier_id`) USING BTREE,
+ KEY `idx_collaboration_status` (`collaboration_status`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='閲囪喘鍗忓悓璁板綍琛�';
+
+-- ============ 琛細srm_supplier锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `srm_supplier`;
+CREATE TABLE `srm_supplier` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '渚涘簲鍟咺D',
+ `code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '渚涘簲鍟嗙紪鐮�',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '渚涘簲鍟嗗悕绉�',
+ `short_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '渚涘簲鍟嗙畝绉�',
+ `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '渚涘簲鍟嗙被鍨�',
+ `company_nature` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '浼佷笟鎬ц川',
+ `registered_capital` decimal(24,6) DEFAULT NULL COMMENT '娉ㄥ唽璧勯噾锛堜竾鍏冿級',
+ `business_license_no` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '钀ヤ笟鎵х収缂栧彿',
+ `tax_no` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '绋庡彿',
+ `legal_person` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娉曚汉浠h〃',
+ `address` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍏徃鍦板潃',
+ `website` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍏徃缃戝潃',
+ `contact_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑱旂郴浜�',
+ `contact_mobile` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑱旂郴鐢佃瘽',
+ `contact_email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閭',
+ `bank_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '寮�鎴烽摱琛�',
+ `bank_account` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閾惰璐﹀彿',
+ `status` int NOT NULL DEFAULT '0' COMMENT '鐘舵�侊紙0鍚敤 1绂佺敤锛�',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `erp_supplier_id` bigint DEFAULT NULL COMMENT '鍏宠仈ERP渚涘簲鍟咺D',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_code` (`code`) USING BTREE,
+ KEY `idx_name` (`name`) USING BTREE,
+ KEY `idx_status` (`status`) USING BTREE,
+ KEY `idx_erp_supplier_id` (`erp_supplier_id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='渚涘簲鍟嗕富琛�';
+
+-- ============ 琛細srm_supplier_apply锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `srm_supplier_apply`;
+CREATE TABLE `srm_supplier_apply` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鐢宠ID',
+ `apply_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐢宠缂栧彿',
+ `supplier_id` bigint DEFAULT NULL COMMENT '渚涘簲鍟咺D',
+ `erp_supplier_id` bigint DEFAULT NULL COMMENT '鍏宠仈ERP渚涘簲鍟咺D',
+ `supplier_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '渚涘簲鍟嗗悕绉�',
+ `supplier_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '渚涘簲鍟嗙被鍨�',
+ `company_nature` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '浼佷笟鎬ц川',
+ `registered_capital` decimal(24,6) DEFAULT NULL COMMENT '娉ㄥ唽璧勯噾锛堜竾鍏冿級',
+ `business_license_no` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '钀ヤ笟鎵х収缂栧彿',
+ `tax_no` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '绋庡彿',
+ `address` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍏徃鍦板潃',
+ `bank_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '寮�鎴烽摱琛�',
+ `bank_account` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閾惰璐﹀彿',
+ `contact_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑱旂郴浜�',
+ `contact_mobile` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑱旂郴鐢佃瘽',
+ `contact_email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閭',
+ `apply_user_id` bigint DEFAULT NULL COMMENT '鐢宠浜篒D',
+ `apply_user_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐢宠浜哄鍚�',
+ `apply_time` datetime DEFAULT NULL COMMENT '鐢宠鏃堕棿',
+ `apply_status` int NOT NULL DEFAULT '0' COMMENT '瀹℃牳鐘舵��',
+ `process_instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'BPM 娴佺▼瀹炰緥缂栧彿',
+ `purchase_reviewer_id` bigint DEFAULT NULL COMMENT '閲囪喘瀹℃牳浜篒D',
+ `purchase_review_time` datetime DEFAULT NULL COMMENT '閲囪喘瀹℃牳鏃堕棿',
+ `purchase_review_opinion` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閲囪喘瀹℃牳鎰忚',
+ `quality_reviewer_id` bigint DEFAULT NULL COMMENT '璐ㄩ噺瀹℃牳浜篒D',
+ `quality_review_time` datetime DEFAULT NULL COMMENT '璐ㄩ噺瀹℃牳鏃堕棿',
+ `quality_review_opinion` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璐ㄩ噺瀹℃牳鎰忚',
+ `finance_reviewer_id` bigint DEFAULT NULL COMMENT '璐㈠姟瀹℃牳浜篒D',
+ `finance_review_time` datetime DEFAULT NULL COMMENT '璐㈠姟瀹℃牳鏃堕棿',
+ `finance_review_opinion` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璐㈠姟瀹℃牳鎰忚',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_apply_no` (`apply_no`) USING BTREE,
+ KEY `idx_supplier_id` (`supplier_id`) USING BTREE,
+ KEY `idx_apply_status` (`apply_status`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='渚涘簲鍟嗗噯鍏ョ敵璇疯〃';
+
+-- ============ 琛細srm_supplier_category锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `srm_supplier_category`;
+CREATE TABLE `srm_supplier_category` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鍏宠仈ID',
+ `supplier_id` bigint NOT NULL COMMENT '渚涘簲鍟咺D',
+ `category_id` bigint NOT NULL COMMENT '鍒嗙被ID',
+ `category_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍒嗙被鍚嶇О锛堝啑浣欙級',
+ `deleted` int NOT NULL DEFAULT '0' COMMENT '鏄惁鍒犻櫎 0=鍚� 1=鏄�',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_supplier_id` (`supplier_id`) USING BTREE,
+ KEY `idx_category_id` (`category_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='渚涘簲鍟嗗垎绫诲叧鑱旇〃';
+
+-- ============ 琛細srm_supplier_certificate锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `srm_supplier_certificate`;
+CREATE TABLE `srm_supplier_certificate` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '璇佷功ID',
+ `supplier_id` bigint NOT NULL COMMENT '渚涘簲鍟咺D',
+ `certificate_type` int NOT NULL COMMENT '璇佷功绫诲瀷',
+ `certificate_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '璇佷功鍚嶇О',
+ `certificate_no` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璇佷功缂栧彿',
+ `file_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏂囦欢鍚嶇О',
+ `file_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏂囦欢鍦板潃',
+ `issuing_authority` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '棰佸彂鏈烘瀯',
+ `valid_start_date` date DEFAULT NULL COMMENT '鏈夋晥寮�濮嬫棩鏈�',
+ `valid_end_date` date DEFAULT NULL COMMENT '鏈夋晥缁撴潫鏃ユ湡',
+ `status` int NOT NULL DEFAULT '0' COMMENT '鐘舵��',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_supplier_id` (`supplier_id`) USING BTREE,
+ KEY `idx_certificate_type` (`certificate_type`) USING BTREE,
+ KEY `idx_valid_end_date` (`valid_end_date`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='渚涘簲鍟嗚祫璐ㄨ瘉涔﹁〃';
+
+-- ============ 琛細srm_supplier_contact锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `srm_supplier_contact`;
+CREATE TABLE `srm_supplier_contact` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鑱旂郴浜篒D',
+ `supplier_id` bigint NOT NULL COMMENT '渚涘簲鍟咺D',
+ `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鑱旂郴浜哄鍚�',
+ `position` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑱屼綅',
+ `mobile` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎵嬫満鍙风爜',
+ `telephone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍥哄畾鐢佃瘽',
+ `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閭',
+ `wechat` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '寰俊鍙�',
+ `is_default` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁榛樿鑱旂郴浜�',
+ `sort` int NOT NULL DEFAULT '0' COMMENT '鎺掑簭',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_supplier_id` (`supplier_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='渚涘簲鍟嗚仈绯讳汉琛�';
+
+-- ============ 琛細srm_supplier_evaluation锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `srm_supplier_evaluation`;
+CREATE TABLE `srm_supplier_evaluation` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '璇勪环ID',
+ `supplier_id` bigint NOT NULL COMMENT '渚涘簲鍟咺D',
+ `evaluation_period` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '璇勪环鍛ㄦ湡',
+ `quality_score` decimal(5,2) DEFAULT NULL COMMENT '璐ㄩ噺璇勫垎',
+ `quality_pass_rate` decimal(5,2) DEFAULT NULL COMMENT '鏉ユ枡鍚堟牸鐜�',
+ `quality_defect_count` int DEFAULT '0' COMMENT '涓嶈壇娆℃暟',
+ `delivery_score` decimal(5,2) DEFAULT NULL COMMENT '浜や粯璇勫垎',
+ `delivery_on_time_rate` decimal(5,2) DEFAULT NULL COMMENT '鍑嗘椂浜や粯鐜�',
+ `delivery_delay_count` int DEFAULT '0' COMMENT '寤惰繜娆℃暟',
+ `price_score` decimal(5,2) DEFAULT NULL COMMENT '浠锋牸璇勫垎',
+ `service_score` decimal(5,2) DEFAULT NULL COMMENT '鏈嶅姟璇勫垎',
+ `service_response_speed` int DEFAULT NULL COMMENT '鍝嶅簲閫熷害璇勫垎',
+ `composite_score` decimal(5,2) DEFAULT NULL COMMENT '缁煎悎璇勫垎',
+ `evaluation_level` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璇勪环绛夌骇',
+ `evaluator_id` bigint DEFAULT NULL COMMENT '璇勪环浜篒D',
+ `evaluation_time` datetime DEFAULT NULL COMMENT '璇勪环鏃堕棿',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_supplier_id` (`supplier_id`) USING BTREE,
+ KEY `idx_evaluation_period` (`evaluation_period`) USING BTREE,
+ KEY `idx_composite_score` (`composite_score`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='渚涘簲鍟嗙哗鏁堣瘎浠疯〃';
+
+-- ============ 琛細srm_supplier_quote锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `srm_supplier_quote`;
+CREATE TABLE `srm_supplier_quote` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鎶ヤ环ID',
+ `tender_project_id` bigint NOT NULL COMMENT '鎷涙爣椤圭洰ID',
+ `supplier_id` bigint NOT NULL COMMENT '渚涘簲鍟咺D',
+ `bid_id` bigint DEFAULT NULL COMMENT '鎶曟爣璁板綍ID',
+ `tender_material_id` bigint NOT NULL COMMENT '鎷涙爣鐗╂枡ID',
+ `quote_price` decimal(24,6) NOT NULL COMMENT '鎶ヤ环浠锋牸',
+ `tax_rate` decimal(5,2) DEFAULT NULL COMMENT '绋庣巼(%)',
+ `delivery_cycle` int DEFAULT NULL COMMENT '浜よ揣鍛ㄦ湡锛堝ぉ锛�',
+ `payment_terms` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '浠樻鏉′欢',
+ `warranty_period` int DEFAULT NULL COMMENT '璐ㄤ繚鏈燂紙鏈堬級',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_tender_project_id` (`tender_project_id`) USING BTREE,
+ KEY `idx_supplier_id` (`supplier_id`) USING BTREE,
+ KEY `idx_bid_id` (`bid_id`) USING BTREE,
+ KEY `idx_tender_material_id` (`tender_material_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='渚涘簲鍟嗘姤浠锋槑缁嗚〃';
+
+-- ============ 琛細srm_tender_bid锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `srm_tender_bid`;
+CREATE TABLE `srm_tender_bid` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鎶曟爣ID',
+ `tender_project_id` bigint NOT NULL COMMENT '鎷涙爣椤圭洰ID',
+ `supplier_id` bigint NOT NULL COMMENT '渚涘簲鍟咺D',
+ `bid_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鎶曟爣缂栧彿',
+ `bid_status` int NOT NULL DEFAULT '0' COMMENT '鎶曟爣鐘舵��',
+ `bid_time` datetime DEFAULT NULL COMMENT '鎶曟爣鏃堕棿',
+ `bid_total_amount` decimal(24,6) DEFAULT NULL COMMENT '鎶曟爣鎬婚噾棰�',
+ `bid_file_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎶曟爣鏂囦欢鍚嶇О',
+ `bid_file_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎶曟爣鏂囦欢鍦板潃',
+ `withdraw_reason` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎾ゆ爣鍘熷洜',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_bid_no` (`bid_no`) USING BTREE,
+ KEY `idx_tender_project_id` (`tender_project_id`) USING BTREE,
+ KEY `idx_supplier_id` (`supplier_id`) USING BTREE,
+ KEY `idx_bid_status` (`bid_status`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鎶曟爣璁板綍琛�';
+
+-- ============ 琛細srm_tender_config锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `srm_tender_config`;
+CREATE TABLE `srm_tender_config` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '閰嶇疆ID',
+ `default_bidding_mode` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'FULL' COMMENT '榛樿鎷涙姇鏍囨ā寮�: FULL-瀹屾暣鐗�, SIMPLE-绠�鏄撶増',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='SRM鎷涙姇鏍囬厤缃〃';
+
+-- ============ 琛細srm_tender_material锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `srm_tender_material`;
+CREATE TABLE `srm_tender_material` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鐗╂枡鏄庣粏ID',
+ `tender_project_id` bigint NOT NULL COMMENT '鎷涙爣椤圭洰ID',
+ `product_id` bigint DEFAULT NULL COMMENT '鐗╂枡ID',
+ `product_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐗╂枡缂栫爜',
+ `product_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐗╂枡鍚嶇О',
+ `product_spec` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瑙勬牸鍨嬪彿',
+ `quantity` decimal(24,6) NOT NULL COMMENT '鏁伴噺',
+ `unit` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍗曚綅',
+ `tech_requirement` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鎶�鏈姹�',
+ `estimated_price` decimal(24,6) DEFAULT NULL COMMENT '棰勪及鍗曚环',
+ `sort` int NOT NULL DEFAULT '0' COMMENT '鎺掑簭',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_tender_project_id` (`tender_project_id`) USING BTREE,
+ KEY `idx_product_code` (`product_code`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鎷涙爣鐗╂枡鏄庣粏琛�';
+
+-- ============ 琛細srm_tender_project锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `srm_tender_project`;
+CREATE TABLE `srm_tender_project` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鎷涙爣椤圭洰ID',
+ `tender_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鎷涙爣缂栧彿',
+ `tender_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鎷涙爣鍚嶇О',
+ `tender_type` int NOT NULL COMMENT '鎷涙爣绫诲瀷',
+ `purchase_org` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閲囪喘缁勭粐',
+ `project_leader_id` bigint DEFAULT NULL COMMENT '椤圭洰璐熻矗浜篒D',
+ `project_leader_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '椤圭洰璐熻矗浜哄鍚�',
+ `tender_status` int NOT NULL DEFAULT '0' COMMENT '鎷涙爣鐘舵��',
+ `bidding_mode` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'FULL' COMMENT '鎷涙姇鏍囨ā寮�: FULL-瀹屾暣鐗�, SIMPLE-绠�鏄撶増',
+ `budget_amount` decimal(24,6) DEFAULT NULL COMMENT '棰勭畻閲戦',
+ `start_time` datetime DEFAULT NULL COMMENT '寮�濮嬫椂闂�',
+ `end_time` datetime DEFAULT NULL COMMENT '鎴鏃堕棿',
+ `bid_open_time` datetime DEFAULT NULL COMMENT '棰勮寮�鏍囨椂闂�',
+ `tender_desc` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '鎷涙爣璇存槑',
+ `qualification_requirements` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '璧勮川瑕佹眰',
+ `purchase_request_id` bigint DEFAULT NULL COMMENT '鍏宠仈閲囪喘鐢宠ID',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_tender_no` (`tender_no`) USING BTREE,
+ KEY `idx_tender_status` (`tender_status`) USING BTREE,
+ KEY `idx_purchase_request_id` (`purchase_request_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鎷涙爣椤圭洰琛�';
+
+-- ============ 琛細storage_attachment锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `storage_attachment`;
+CREATE TABLE `storage_attachment` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bigint NOT NULL DEFAULT '0' COMMENT '閫昏緫鍒犻櫎锛�0姝e父锛�',
+ `record_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鍏宠仈鐨勮褰曠被鍨嬶紙瀵瑰簲RecordTypeEnum鐨則ype鍊硷級',
+ `record_id` bigint DEFAULT NULL COMMENT '鍏宠仈鐨勮褰旾D',
+ `application` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鏂囦欢鐢ㄩ�旓紙瀵瑰簲ApplicationTypeEnum鐨則ype鍊硷級锛屽 file/avatar/image',
+ `storage_blob_id` bigint DEFAULT NULL COMMENT '鍏宠仈storage_blob璁板綍ID',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_record` (`record_type`,`record_id`) USING BTREE COMMENT '涓氬姟璁板綍鏌ヨ绱㈠紩',
+ KEY `idx_blob_id` (`storage_blob_id`) USING BTREE COMMENT '鏂囦欢鍏宠仈绱㈠紩'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='鏂囦欢鍏宠仈琛�';
+
+-- ============ 琛細storage_blob锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `storage_blob`;
+CREATE TABLE `storage_blob` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `resource_key` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '璧勬簮鍞竴鏍囪瘑锛堝叕鍏辫闂甼ey锛�',
+ `content_type` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '璧勬簮绫诲瀷锛屽 image/jpeg',
+ `original_filename` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鍘熸枃浠跺悕',
+ `uid_filename` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '鍞竴鏂囦欢鍚嶏紙UUID_鍘熸枃浠跺悕锛�',
+ `byte_size` bigint DEFAULT NULL COMMENT '鏂囦欢澶у皬锛堝瓧鑺傦級',
+ `path` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '鏂囦欢鐩稿璺緞锛堝 2026/0430锛�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_uid_filename` (`uid_filename`) USING BTREE COMMENT '鍞竴鏂囦欢鍚嶇储寮�',
+ KEY `idx_resource_key` (`resource_key`) USING BTREE COMMENT '鍏叡璁块棶key绱㈠紩'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='鏂囦欢琛�';
+
+-- ============ 琛細system_dept锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_dept`;
+CREATE TABLE `system_dept` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '閮ㄩ棬id',
+ `name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '閮ㄩ棬鍚嶇О',
+ `parent_id` bigint NOT NULL DEFAULT '0' COMMENT '鐖堕儴闂╥d',
+ `sort` int NOT NULL DEFAULT '0' COMMENT '鏄剧ず椤哄簭',
+ `leader_user_id` bigint DEFAULT NULL COMMENT '璐熻矗浜�',
+ `phone` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑱旂郴鐢佃瘽',
+ `email` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '閭',
+ `status` tinyint NOT NULL COMMENT '閮ㄩ棬鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=129 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='閮ㄩ棬琛�';
+
+-- ============ 琛細system_login_log锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_login_log`;
+CREATE TABLE `system_login_log` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '璁块棶ID',
+ `log_type` bigint NOT NULL COMMENT '鏃ュ織绫诲瀷',
+ `trace_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '閾捐矾杩借釜缂栧彿',
+ `user_id` bigint NOT NULL DEFAULT '0' COMMENT '鐢ㄦ埛缂栧彿',
+ `user_type` tinyint NOT NULL DEFAULT '0' COMMENT '鐢ㄦ埛绫诲瀷',
+ `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鐢ㄦ埛璐﹀彿',
+ `result` tinyint NOT NULL COMMENT '鐧婚檰缁撴灉',
+ `user_ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐢ㄦ埛 IP',
+ `user_agent` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '娴忚鍣� UA',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_username` (`username`) USING BTREE,
+ KEY `idx_create_time` (`create_time`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='绯荤粺璁块棶璁板綍';
+
+-- ============ 琛細system_mail_account锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_mail_account`;
+CREATE TABLE `system_mail_account` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `mail` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '閭',
+ `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐢ㄦ埛鍚�',
+ `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '瀵嗙爜',
+ `host` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'SMTP 鏈嶅姟鍣ㄥ煙鍚�',
+ `port` int NOT NULL COMMENT 'SMTP 鏈嶅姟鍣ㄧ鍙�',
+ `ssl_enable` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁寮�鍚� SSL',
+ `starttls_enable` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁寮�鍚� STARTTLS',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='閭璐﹀彿琛�';
+
+-- ============ 琛細system_mail_log锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_mail_log`;
+CREATE TABLE `system_mail_log` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `user_id` bigint DEFAULT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `user_type` tinyint DEFAULT NULL COMMENT '鐢ㄦ埛绫诲瀷',
+ `to_mails` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鎺ユ敹閭鍦板潃',
+ `cc_mails` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎶勯�侀偖绠卞湴鍧�',
+ `bcc_mails` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '瀵嗛�侀偖绠卞湴鍧�',
+ `account_id` bigint NOT NULL COMMENT '閭璐﹀彿缂栧彿',
+ `from_mail` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍙戦�侀偖绠卞湴鍧�',
+ `template_id` bigint NOT NULL COMMENT '妯℃澘缂栧彿',
+ `template_code` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '妯℃澘缂栫爜',
+ `template_nickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '妯$増鍙戦�佷汉鍚嶇О',
+ `template_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '閭欢鏍囬',
+ `template_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '閭欢鍐呭',
+ `template_params` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '閭欢鍙傛暟',
+ `send_status` tinyint NOT NULL DEFAULT '0' COMMENT '鍙戦�佺姸鎬�',
+ `send_time` datetime DEFAULT NULL COMMENT '鍙戦�佹椂闂�',
+ `send_message_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍙戦�佽繑鍥炵殑娑堟伅 ID',
+ `send_exception` varchar(4096) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍙戦�佸紓甯�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='閭欢鏃ュ織琛�';
+
+-- ============ 琛細system_mail_template锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_mail_template`;
+CREATE TABLE `system_mail_template` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `name` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '妯℃澘鍚嶇О',
+ `code` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '妯℃澘缂栫爜',
+ `account_id` bigint NOT NULL COMMENT '鍙戦�佺殑閭璐﹀彿缂栧彿',
+ `nickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍙戦�佷汉鍚嶇О',
+ `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '妯℃澘鏍囬',
+ `content` varchar(10240) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '妯℃澘鍐呭',
+ `params` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍙傛暟鏁扮粍',
+ `status` tinyint NOT NULL COMMENT '寮�鍚姸鎬�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='閭欢妯$増琛�';
+
+-- ============ 琛細system_menu锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_menu`;
+CREATE TABLE `system_menu` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鑿滃崟ID',
+ `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鑿滃崟鍚嶇О',
+ `permission` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鏉冮檺鏍囪瘑',
+ `type` tinyint NOT NULL COMMENT '鑿滃崟绫诲瀷',
+ `sort` int NOT NULL DEFAULT '0' COMMENT '鏄剧ず椤哄簭',
+ `parent_id` bigint NOT NULL DEFAULT '0' COMMENT '鐖惰彍鍗旾D',
+ `path` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '璺敱鍦板潃',
+ `icon` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '#' COMMENT '鑿滃崟鍥炬爣',
+ `component` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '缁勪欢璺緞',
+ `component_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '缁勪欢鍚�',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鑿滃崟鐘舵��',
+ `visible` bit(1) NOT NULL DEFAULT b'1' COMMENT '鏄惁鍙',
+ `keep_alive` bit(1) NOT NULL DEFAULT b'1' COMMENT '鏄惁缂撳瓨',
+ `always_show` bit(1) NOT NULL DEFAULT b'1' COMMENT '鏄惁鎬绘槸鏄剧ず',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=1075310 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鑿滃崟鏉冮檺琛�';
+
+-- ============ 琛細system_notice锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_notice`;
+CREATE TABLE `system_notice` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鍏憡ID',
+ `title` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍏憡鏍囬',
+ `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍏憡鍐呭',
+ `type` tinyint NOT NULL COMMENT '鍏憡绫诲瀷锛�1閫氱煡 2鍏憡锛�',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '鍏憡鐘舵�侊紙0姝e父 1鍏抽棴锛�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='閫氱煡鍏憡琛�';
+
+-- ============ 琛細system_notify_message锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_notify_message`;
+CREATE TABLE `system_notify_message` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鐢ㄦ埛ID',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛id',
+ `user_type` tinyint NOT NULL COMMENT '鐢ㄦ埛绫诲瀷',
+ `template_id` bigint NOT NULL COMMENT '妯$増缂栧彿',
+ `template_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '妯℃澘缂栫爜',
+ `template_nickname` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '妯$増鍙戦�佷汉鍚嶇О',
+ `template_content` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '妯$増鍐呭',
+ `template_type` int NOT NULL COMMENT '妯$増绫诲瀷',
+ `template_params` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '妯$増鍙傛暟',
+ `read_status` bit(1) NOT NULL COMMENT '鏄惁宸茶',
+ `read_time` datetime DEFAULT NULL COMMENT '闃呰鏃堕棿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_user_id_user_type_read_status` (`user_id`,`user_type`,`read_status`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='绔欏唴淇℃秷鎭〃';
+
+-- ============ 琛細system_notify_template锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_notify_template`;
+CREATE TABLE `system_notify_template` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `name` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '妯℃澘鍚嶇О',
+ `code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '妯$増缂栫爜',
+ `nickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍙戦�佷汉鍚嶇О',
+ `content` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '妯$増鍐呭',
+ `type` tinyint NOT NULL COMMENT '绫诲瀷',
+ `params` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍙傛暟鏁扮粍',
+ `status` tinyint NOT NULL COMMENT '鐘舵��',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='绔欏唴淇℃ā鏉胯〃';
+
+-- ============ 琛細system_oauth2_access_token锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_oauth2_access_token`;
+CREATE TABLE `system_oauth2_access_token` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `user_type` tinyint NOT NULL COMMENT '鐢ㄦ埛绫诲瀷',
+ `user_info` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐢ㄦ埛淇℃伅',
+ `access_token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '璁块棶浠ょ墝',
+ `refresh_token` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍒锋柊浠ょ墝',
+ `client_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '瀹㈡埛绔紪鍙�',
+ `scopes` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎺堟潈鑼冨洿',
+ `expires_time` datetime NOT NULL COMMENT '杩囨湡鏃堕棿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_access_token` (`access_token`) USING BTREE,
+ KEY `idx_refresh_token` (`refresh_token`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='OAuth2 璁块棶浠ょ墝';
+
+-- ============ 琛細system_oauth2_approve锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_oauth2_approve`;
+CREATE TABLE `system_oauth2_approve` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `user_type` tinyint NOT NULL COMMENT '鐢ㄦ埛绫诲瀷',
+ `client_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '瀹㈡埛绔紪鍙�',
+ `scope` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鎺堟潈鑼冨洿',
+ `approved` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鎺ュ彈',
+ `expires_time` datetime NOT NULL COMMENT '杩囨湡鏃堕棿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_user_id_user_type_client_id` (`user_id`,`user_type`,`client_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='OAuth2 鎵瑰噯琛�';
+
+-- ============ 琛細system_oauth2_client锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_oauth2_client`;
+CREATE TABLE `system_oauth2_client` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `client_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '瀹㈡埛绔紪鍙�',
+ `secret` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '瀹㈡埛绔瘑閽�',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '搴旂敤鍚�',
+ `logo` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '搴旂敤鍥炬爣',
+ `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '搴旂敤鎻忚堪',
+ `status` tinyint NOT NULL COMMENT '鐘舵��',
+ `access_token_validity_seconds` int NOT NULL COMMENT '璁块棶浠ょ墝鐨勬湁鏁堟湡',
+ `refresh_token_validity_seconds` int NOT NULL COMMENT '鍒锋柊浠ょ墝鐨勬湁鏁堟湡',
+ `redirect_uris` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍙噸瀹氬悜鐨� URI 鍦板潃',
+ `authorized_grant_types` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鎺堟潈绫诲瀷',
+ `scopes` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎺堟潈鑼冨洿',
+ `auto_approve_scopes` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鑷姩閫氳繃鐨勬巿鏉冭寖鍥�',
+ `authorities` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏉冮檺',
+ `resource_ids` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璧勬簮',
+ `additional_information` varchar(4096) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '闄勫姞淇℃伅',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_client_id` (`client_id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=43 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='OAuth2 瀹㈡埛绔〃';
+
+-- ============ 琛細system_oauth2_code锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_oauth2_code`;
+CREATE TABLE `system_oauth2_code` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `user_type` tinyint NOT NULL COMMENT '鐢ㄦ埛绫诲瀷',
+ `code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鎺堟潈鐮�',
+ `client_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '瀹㈡埛绔紪鍙�',
+ `scopes` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鎺堟潈鑼冨洿',
+ `expires_time` datetime NOT NULL COMMENT '杩囨湡鏃堕棿',
+ `redirect_uri` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍙噸瀹氬悜鐨� URI 鍦板潃',
+ `state` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鐘舵��',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_code` (`code`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='OAuth2 鎺堟潈鐮佽〃';
+
+-- ============ 琛細system_oauth2_refresh_token锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_oauth2_refresh_token`;
+CREATE TABLE `system_oauth2_refresh_token` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `refresh_token` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍒锋柊浠ょ墝',
+ `user_type` tinyint NOT NULL COMMENT '鐢ㄦ埛绫诲瀷',
+ `client_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '瀹㈡埛绔紪鍙�',
+ `scopes` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鎺堟潈鑼冨洿',
+ `expires_time` datetime NOT NULL COMMENT '杩囨湡鏃堕棿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_refresh_token` (`refresh_token`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='OAuth2 鍒锋柊浠ょ墝';
+
+-- ============ 琛細system_operate_log锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_operate_log`;
+CREATE TABLE `system_operate_log` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鏃ュ織涓婚敭',
+ `trace_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '閾捐矾杩借釜缂栧彿',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `user_type` tinyint NOT NULL DEFAULT '0' COMMENT '鐢ㄦ埛绫诲瀷',
+ `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鎿嶄綔妯″潡绫诲瀷',
+ `sub_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鎿嶄綔鍚�',
+ `biz_id` bigint NOT NULL COMMENT '鎿嶄綔鏁版嵁妯″潡缂栧彿',
+ `action` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鎿嶄綔鍐呭',
+ `success` bit(1) NOT NULL DEFAULT b'1' COMMENT '鎿嶄綔缁撴灉',
+ `extra` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鎷撳睍瀛楁',
+ `request_method` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '璇锋眰鏂规硶鍚�',
+ `request_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '璇锋眰鍦板潃',
+ `user_ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐢ㄦ埛 IP',
+ `user_agent` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '娴忚鍣� UA',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_user_id` (`user_id`) USING BTREE,
+ KEY `idx_create_time` (`create_time`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鎿嶄綔鏃ュ織璁板綍 V2 鐗堟湰';
+
+-- ============ 琛細system_post锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_post`;
+CREATE TABLE `system_post` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '宀椾綅ID',
+ `code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '宀椾綅缂栫爜',
+ `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '宀椾綅鍚嶇О',
+ `sort` int NOT NULL COMMENT '鏄剧ず椤哄簭',
+ `status` tinyint NOT NULL COMMENT '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='宀椾綅淇℃伅琛�';
+
+-- ============ 琛細system_role锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_role`;
+CREATE TABLE `system_role` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '瑙掕壊ID',
+ `name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '瑙掕壊鍚嶇О',
+ `code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '瑙掕壊鏉冮檺瀛楃涓�',
+ `sort` int NOT NULL COMMENT '鏄剧ず椤哄簭',
+ `data_scope` tinyint NOT NULL DEFAULT '1' COMMENT '鏁版嵁鑼冨洿锛�1锛氬叏閮ㄦ暟鎹潈闄� 2锛氳嚜瀹氭暟鎹潈闄� 3锛氭湰閮ㄩ棬鏁版嵁鏉冮檺 4锛氭湰閮ㄩ棬鍙婁互涓嬫暟鎹潈闄愶級',
+ `data_scope_dept_ids` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鏁版嵁鑼冨洿(鎸囧畾閮ㄩ棬鏁扮粍)',
+ `status` tinyint NOT NULL COMMENT '瑙掕壊鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+ `type` tinyint NOT NULL COMMENT '瑙掕壊绫诲瀷',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=167 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='瑙掕壊淇℃伅琛�';
+
+-- ============ 琛細system_role_menu锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_role_menu`;
+CREATE TABLE `system_role_menu` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鑷缂栧彿',
+ `role_id` bigint NOT NULL COMMENT '瑙掕壊ID',
+ `menu_id` bigint NOT NULL COMMENT '鑿滃崟ID',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_role_id` (`role_id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=8766 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='瑙掕壊鍜岃彍鍗曞叧鑱旇〃';
+
+-- ============ 琛細system_sms_channel锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_sms_channel`;
+CREATE TABLE `system_sms_channel` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `signature` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐭俊绛惧悕',
+ `code` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '娓犻亾缂栫爜',
+ `status` tinyint NOT NULL COMMENT '寮�鍚姸鎬�',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `api_key` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐭俊 API 鐨勮处鍙�',
+ `api_secret` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐭俊 API 鐨勭閽�',
+ `callback_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐭俊鍙戦�佸洖璋� URL',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鐭俊娓犻亾';
+
+-- ============ 琛細system_sms_code锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_sms_code`;
+CREATE TABLE `system_sms_code` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `mobile` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鎵嬫満鍙�',
+ `code` varchar(6) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '楠岃瘉鐮�',
+ `create_ip` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍒涘缓 IP',
+ `scene` tinyint NOT NULL COMMENT '鍙戦�佸満鏅�',
+ `today_index` tinyint NOT NULL COMMENT '浠婃棩鍙戦�佺殑绗嚑鏉�',
+ `used` tinyint NOT NULL COMMENT '鏄惁浣跨敤',
+ `used_time` datetime DEFAULT NULL COMMENT '浣跨敤鏃堕棿',
+ `used_ip` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '浣跨敤 IP',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_mobile` (`mobile`) USING BTREE COMMENT '鎵嬫満鍙�'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鎵嬫満楠岃瘉鐮�';
+
+-- ============ 琛細system_sms_log锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_sms_log`;
+CREATE TABLE `system_sms_log` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `channel_id` bigint NOT NULL COMMENT '鐭俊娓犻亾缂栧彿',
+ `channel_code` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐭俊娓犻亾缂栫爜',
+ `template_id` bigint NOT NULL COMMENT '妯℃澘缂栧彿',
+ `template_code` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '妯℃澘缂栫爜',
+ `template_type` tinyint NOT NULL COMMENT '鐭俊绫诲瀷',
+ `template_content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐭俊鍐呭',
+ `template_params` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐭俊鍙傛暟',
+ `api_template_id` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐭俊 API 鐨勬ā鏉跨紪鍙�',
+ `mobile` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鎵嬫満鍙�',
+ `user_id` bigint DEFAULT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `user_type` tinyint DEFAULT NULL COMMENT '鐢ㄦ埛绫诲瀷',
+ `send_status` tinyint NOT NULL DEFAULT '0' COMMENT '鍙戦�佺姸鎬�',
+ `send_time` datetime DEFAULT NULL COMMENT '鍙戦�佹椂闂�',
+ `api_send_code` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐭俊 API 鍙戦�佺粨鏋滅殑缂栫爜',
+ `api_send_msg` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐭俊 API 鍙戦�佸け璐ョ殑鎻愮ず',
+ `api_request_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐭俊 API 鍙戦�佽繑鍥炵殑鍞竴璇锋眰 ID',
+ `api_serial_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐭俊 API 鍙戦�佽繑鍥炵殑搴忓彿',
+ `receive_status` tinyint NOT NULL DEFAULT '0' COMMENT '鎺ユ敹鐘舵��',
+ `receive_time` datetime DEFAULT NULL COMMENT '鎺ユ敹鏃堕棿',
+ `api_receive_code` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'API 鎺ユ敹缁撴灉鐨勭紪鐮�',
+ `api_receive_msg` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'API 鎺ユ敹缁撴灉鐨勮鏄�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鐭俊鏃ュ織';
+
+-- ============ 琛細system_sms_template锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_sms_template`;
+CREATE TABLE `system_sms_template` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `type` tinyint NOT NULL COMMENT '妯℃澘绫诲瀷',
+ `status` tinyint NOT NULL COMMENT '寮�鍚姸鎬�',
+ `code` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '妯℃澘缂栫爜',
+ `name` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '妯℃澘鍚嶇О',
+ `content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '妯℃澘鍐呭',
+ `params` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍙傛暟鏁扮粍',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `api_template_id` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐭俊 API 鐨勬ā鏉跨紪鍙�',
+ `channel_id` bigint NOT NULL COMMENT '鐭俊娓犻亾缂栧彿',
+ `channel_code` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐭俊娓犻亾缂栫爜',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鐭俊妯℃澘';
+
+-- ============ 琛細system_social_client锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_social_client`;
+CREATE TABLE `system_social_client` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '搴旂敤鍚�',
+ `social_type` tinyint NOT NULL COMMENT '绀句氦骞冲彴鐨勭被鍨�',
+ `user_type` tinyint NOT NULL COMMENT '鐢ㄦ埛绫诲瀷',
+ `client_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '瀹㈡埛绔紪鍙�',
+ `client_secret` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '瀹㈡埛绔瘑閽�',
+ `agent_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '浠g悊缂栧彿',
+ `public_key` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'publicKey 鍏挜',
+ `status` tinyint NOT NULL COMMENT '鐘舵��',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='绀句氦瀹㈡埛绔〃';
+
+-- ============ 琛細system_social_user锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_social_user`;
+CREATE TABLE `system_social_user` (
+ `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭(鑷绛栫暐)',
+ `type` tinyint NOT NULL COMMENT '绀句氦骞冲彴鐨勭被鍨�',
+ `openid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '绀句氦 openid',
+ `token` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '绀句氦 token',
+ `raw_token_info` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍘熷 Token 鏁版嵁锛屼竴鑸槸 JSON 鏍煎紡',
+ `nickname` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐢ㄦ埛鏄电О',
+ `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鐢ㄦ埛澶村儚',
+ `raw_user_info` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍘熷鐢ㄦ埛鏁版嵁锛屼竴鑸槸 JSON 鏍煎紡',
+ `code` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鏈�鍚庝竴娆$殑璁よ瘉 code',
+ `state` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏈�鍚庝竴娆$殑璁よ瘉 state',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_type_openid` (`type`,`openid`) USING BTREE,
+ KEY `idx_type_code_state` (`type`,`code`,`state`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='绀句氦鐢ㄦ埛琛�';
+
+-- ============ 琛細system_social_user_bind锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_social_user_bind`;
+CREATE TABLE `system_social_user_bind` (
+ `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭(鑷绛栫暐)',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛缂栧彿',
+ `user_type` tinyint NOT NULL COMMENT '鐢ㄦ埛绫诲瀷',
+ `social_type` tinyint NOT NULL COMMENT '绀句氦骞冲彴鐨勭被鍨�',
+ `social_user_id` bigint NOT NULL COMMENT '绀句氦鐢ㄦ埛鐨勭紪鍙�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_user_type_social_user_id` (`user_type`,`social_user_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='绀句氦缁戝畾琛�';
+
+-- ============ 琛細system_storage_attachment锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_storage_attachment`;
+CREATE TABLE `system_storage_attachment` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
+ `record_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍏宠仈鐨勮褰曠被鍨�',
+ `record_id` bigint DEFAULT NULL COMMENT '鍏宠仈鐨勮褰旾D',
+ `application` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏂囦欢鐢ㄩ��',
+ `storage_blob_id` bigint DEFAULT NULL COMMENT '鍏宠仈storage_blob璁板綍ID',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_record` (`record_type`,`record_id`) USING BTREE,
+ KEY `idx_blob_id` (`storage_blob_id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鏂囦欢鍏宠仈琛�';
+
+-- ============ 琛細system_storage_blob锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_storage_blob`;
+CREATE TABLE `system_storage_blob` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `resource_key` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '璧勬簮鍞竴鏍囪瘑锛堝叕鍏辫闂甼ey锛�',
+ `content_type` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '璧勬簮绫诲瀷锛屽 image/jpeg',
+ `original_filename` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鍘熸枃浠跺悕',
+ `uid_filename` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鍞竴鏂囦欢鍚嶏紙UUID_鍘熸枃浠跺悕锛�',
+ `byte_size` bigint DEFAULT NULL COMMENT '鏂囦欢澶у皬锛堝瓧鑺傦級',
+ `path` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '鏂囦欢鐩稿璺緞锛堝 2026/0430锛�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_uid_filename` (`uid_filename`) USING BTREE,
+ KEY `idx_resource_key` (`resource_key`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鏂囦欢琛�';
+
+-- ============ 琛細system_user_post锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_user_post`;
+CREATE TABLE `system_user_post` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
+ `user_id` bigint NOT NULL DEFAULT '0' COMMENT '鐢ㄦ埛ID',
+ `post_id` bigint NOT NULL DEFAULT '0' COMMENT '宀椾綅ID',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=202 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鐢ㄦ埛宀椾綅琛�';
+
+-- ============ 琛細system_user_role锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_user_role`;
+CREATE TABLE `system_user_role` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鑷缂栧彿',
+ `user_id` bigint NOT NULL COMMENT '鐢ㄦ埛ID',
+ `role_id` bigint NOT NULL COMMENT '瑙掕壊ID',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_user_id` (`user_id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=131 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鐢ㄦ埛鍜岃鑹插叧鑱旇〃';
+
+-- ============ 琛細system_users锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `system_users`;
+CREATE TABLE `system_users` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '鐢ㄦ埛ID',
+ `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐢ㄦ埛璐﹀彿',
+ `password` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '瀵嗙爜',
+ `nickname` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐢ㄦ埛鏄电О',
+ `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶囨敞',
+ `dept_id` bigint DEFAULT NULL COMMENT '閮ㄩ棬ID',
+ `post_ids` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '宀椾綅缂栧彿鏁扮粍',
+ `email` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鐢ㄦ埛閭',
+ `mobile` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鎵嬫満鍙风爜',
+ `sex` tinyint DEFAULT '0' COMMENT '鐢ㄦ埛鎬у埆',
+ `avatar` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '澶村儚鍦板潃',
+ `status` tinyint NOT NULL DEFAULT '0' COMMENT '甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+ `login_ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏈�鍚庣櫥褰旾P',
+ `login_date` datetime DEFAULT NULL COMMENT '鏈�鍚庣櫥褰曟椂闂�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_username` (`username`) USING BTREE,
+ KEY `idx_mobile` (`mobile`) USING BTREE,
+ KEY `idx_email` (`email`) USING BTREE,
+ KEY `idx_dept_id` (`dept_id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=297 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='鐢ㄦ埛淇℃伅琛�';
+
+-- ============ 琛細yudao_demo01_contact锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `yudao_demo01_contact`;
+CREATE TABLE `yudao_demo01_contact` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鍚嶅瓧',
+ `sex` tinyint(1) NOT NULL COMMENT '鎬у埆',
+ `birthday` datetime NOT NULL COMMENT '鍑虹敓骞�',
+ `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '绠�浠�',
+ `avatar` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '澶村儚',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='绀轰緥鑱旂郴浜鸿〃';
+
+-- ============ 琛細yudao_demo02_category锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `yudao_demo02_category`;
+CREATE TABLE `yudao_demo02_category` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鍚嶅瓧',
+ `parent_id` bigint NOT NULL COMMENT '鐖剁骇缂栧彿',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='绀轰緥鍒嗙被琛�';
+
+-- ============ 琛細yudao_demo03_course锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `yudao_demo03_course`;
+CREATE TABLE `yudao_demo03_course` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `student_id` bigint NOT NULL COMMENT '瀛︾敓缂栧彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鍚嶅瓧',
+ `score` tinyint NOT NULL COMMENT '鍒嗘暟',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='瀛︾敓璇剧▼琛�';
+
+-- ============ 琛細yudao_demo03_grade锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `yudao_demo03_grade`;
+CREATE TABLE `yudao_demo03_grade` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `student_id` bigint NOT NULL COMMENT '瀛︾敓缂栧彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鍚嶅瓧',
+ `teacher` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '鐝富浠�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='瀛︾敓鐝骇琛�';
+
+-- ============ 琛細yudao_demo03_student锛堜粎 DDL锛屾棤鏁版嵁锛� ============
+DROP TABLE IF EXISTS `yudao_demo03_student`;
+CREATE TABLE `yudao_demo03_student` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '鍚嶅瓧',
+ `sex` tinyint NOT NULL COMMENT '鎬у埆',
+ `birthday` datetime NOT NULL COMMENT '鍑虹敓鏃ユ湡',
+ `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '绠�浠�',
+ `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '绉熸埛缂栧彿',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='瀛︾敓琛�';
+
+SET FOREIGN_KEY_CHECKS = 1;
+SET SQL_MODE = @OLD_SQL_MODE;
+
+
+-- =======================================================================
+-- 闃舵浜岋細琛ュ韬唤/鑿滃崟/OAuth2锛堝師 test_identity_seed_20260904.sql 鍚堝苟浜庢锛�
+-- =======================================================================
+
+-- =======================================================================
+-- 鏂囦欢锛歵est_identity_seed_20260904.sql锛坅dmin 鍗曡处鍙疯韩浠�/鏉冮檺琛ュ锛�
+-- 鐢ㄩ�旓細缁� test 搴撹ˉ榻�"admin 璐﹀彿 + 鑿滃崟 + 鏉冮檺"鏁版嵁锛屾暟鎹簮锛歳uoyi-vue-pro
+-- 鍓嶆彁锛歵est 搴撳凡鎵ц杩� config_export_20260904.sql锛堝叏琛ㄧ粨鏋勫凡瀛樺湪锛屽瓧鍏稿凡瀵硷級锛�
+-- 鏈剼鏈』鍦ㄢ�滃悓鏃跺瓨鍦� ruoyi-vue-pro 涓� test鈥濈殑鍚屼竴 MySQL 瀹炰緥涓婃墽琛屻��
+-- 瑕嗙洊锛堜粎 admin 涓�涓处鍙凤紝鍙婂叾鎷ユ湁鐨勮鑹蹭笌鏉冮檺锛夛細
+-- 鈶� system_menu 鍏ㄩ儴鏈夋晥鑿滃崟锛堣秴绠$敱浠g爜杩斿洖鍏ㄩ儴鑿滃崟锛屾櫘閫氳鑹蹭緷璧� role_menu锛�
+-- 鈶� system_dept / post 婧愬簱鏈垹闄ょ殑鏈夋晥閮ㄩ棬/宀椾綅琛岋紙admin 鐨� dept_id 钀藉湪鍏朵腑锛�
+-- 鈶� system_role 浠� admin 鎷ユ湁鐨勮鑹诧紙super_admin銆乧ommon銆�001銆乧rm_admin 绛夛級
+-- 鈶� system_users 浠� admin 璐﹀彿锛堝瘑鐮佸搱甯屼竴骞舵嫹璐濓紝鐧诲綍瀵嗙爜鍚屾簮搴擄級
+-- 鈶� system_user_role admin 涓庡叾瑙掕壊鐨勫叧鑱�
+-- 鈶� system_role_menu admin 鍚勮鑹茬殑鑿滃崟鍏宠仈锛堜繚璇佹櫘閫氳鑹叉潈闄愭甯革級
+-- 鈶� system_oauth2_client 榛樿 OAuth2 瀹㈡埛绔紙鐧诲綍/鍒锋柊浠ょ墝蹇呴渶锛宑lient_id='default'锛�
+-- 瀛楀吀 system_dict_type / system_dict_data锛歝onfig_export 宸插鍏ワ紙test 鐜颁负 241/1157锛夛紝姝ゅ涓嶉噸澶嶅鐞嗐��
+-- 骞傜瓑锛氭瘡寮犺〃鍏� DELETE 鍐� INSERT锛屽彲閲嶅鎵ц锛涗笉褰卞搷鍏跺畠琛ㄣ��
+-- 鈿� 浠呬綔鐢ㄤ簬涓婅堪鍒楀嚭鐨勮〃锛屼笉浼氭竻绌哄叾瀹冭〃鏁版嵁銆�
+-- 鈿� 婧愬簱 system_dept / system_post / system_users / system_role 鍚蒋鍒犻櫎琛岋紝浠呮嫹璐濇湭鍒犻櫎(deleted=0)鐨勩��
+-- =======================================================================
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+SET @OLD_SQL_MODE = @@SQL_MODE, SQL_MODE = 'NO_AUTO_VALUE_ON_ZERO';
+
+-- 鈶� 鑿滃崟锛堝叏閲忔湁鏁堬級
+DELETE FROM `system_menu`;
+INSERT INTO `system_menu`
+SELECT * FROM `ruoyi-vue-pro`.`system_menu`
+WHERE `deleted` = b'0';
+
+-- 鈶燽 OAuth2 瀹㈡埛绔紙鐧诲綍蹇呴渶锛宑lient_id='default'锛�
+DELETE FROM `system_oauth2_client`;
+INSERT INTO `system_oauth2_client`
+SELECT * FROM `ruoyi-vue-pro`.`system_oauth2_client`
+WHERE `deleted` = b'0';
+
+-- 鈶� 閮ㄩ棬 / 宀椾綅锛堜粎鏈垹闄ょ殑鏈夋晥琛岋級
+DELETE FROM `system_dept`;
+INSERT INTO `system_dept`
+SELECT * FROM `ruoyi-vue-pro`.`system_dept`
+WHERE `deleted` = b'0';
+
+DELETE FROM `system_post`;
+INSERT INTO `system_post`
+SELECT * FROM `ruoyi-vue-pro`.`system_post`
+WHERE `deleted` = b'0';
+
+-- 鈶� admin 鎷ユ湁鐨勮鑹�
+DELETE FROM `system_role`;
+INSERT INTO `system_role`
+SELECT * FROM `ruoyi-vue-pro`.`system_role`
+WHERE `deleted` = b'0'
+ AND `id` IN (SELECT `role_id` FROM `ruoyi-vue-pro`.`system_user_role`
+ WHERE `user_id` = (SELECT `id` FROM `ruoyi-vue-pro`.`system_users` WHERE `username` = 'admin' LIMIT 1));
+
+-- 鈶� admin 璐﹀彿
+DELETE FROM `system_users`;
+INSERT INTO `system_users`
+SELECT * FROM `ruoyi-vue-pro`.`system_users`
+WHERE `username` = 'admin' AND `deleted` = b'0';
+
+-- 鈶� 鐢ㄦ埛-瑙掕壊鍏宠仈锛坅dmin锛�
+DELETE FROM `system_user_role`;
+INSERT INTO `system_user_role`
+SELECT * FROM `ruoyi-vue-pro`.`system_user_role`
+WHERE `user_id` = (SELECT `id` FROM `system_users` WHERE `username` = 'admin' LIMIT 1);
+
+-- 鈶� 瑙掕壊-鑿滃崟鍏宠仈锛坅dmin 鍚勮鑹诧紝淇濊瘉鏅�氳鑹叉潈闄愭甯革級
+DELETE FROM `system_role_menu`;
+-- 鈿� 涓嶈兘鍐欐垚 INNER JOIN `system_user_role`锛氭簮搴� system_user_role 鐨勪富閿彧鏄� id锛�
+-- 鍚屼竴 (user_id, role_id) 鍙互瀛樺湪澶氳锛堝疄娴� admin 鐨� role_id=1 灏辨湁 2 琛岋級锛�
+-- JOIN 浼氭妸 system_role_menu 鐨勬瘡涓�琛屾斁澶ф垚 N 琛岋紝鎾� system_role_menu 涓婚敭瀵艰嚧鏁磋剼鏈腑鏂��
+-- 鐢� IN锛堝瓙鏌ヨ澶╃劧鍘婚噸锛夎〃杈俱�岃繖浜涜鑹茬殑鑿滃崟銆嶏紝涓庤鏁版棤鍏炽��
+INSERT INTO `system_role_menu`
+SELECT rm.* FROM `ruoyi-vue-pro`.`system_role_menu` rm
+WHERE rm.`role_id` IN (SELECT `role_id` FROM `system_user_role`);
+
+SET FOREIGN_KEY_CHECKS = 1;
diff --git a/docs/sql/qc_report_dict.sql b/docs/sql/qc_report_dict.sql
new file mode 100644
index 0000000..4ed4482
--- /dev/null
+++ b/docs/sql/qc_report_dict.sql
@@ -0,0 +1,55 @@
+-- ============================================================
+-- 鏅鸿兘璐ㄦ鎶ュ憡璁捐骞冲彴 瀛楀吀鏁版嵁
+-- 鐩爣搴擄細ruoyi-vue-pro锛坙ocal profile 鐨� master 鏁版嵁婧愶級
+-- 骞傜瓑锛氬厛鍒犲悗鎻�
+-- 璇存槑锛氭姤鍛婄被鍨嬪鐢� MES 宸叉湁瀛楀吀 mes_qc_type锛屼笉鍙﹀缓閲嶅瀛楀吀
+-- ============================================================
+
+USE `ruoyi-vue-pro`;
+
+-- 娓呯悊
+DELETE FROM `system_dict_data` WHERE `id` BETWEEN 1065400 AND 1065499;
+DELETE FROM `system_dict_type` WHERE `id` BETWEEN 1065400 AND 1065499;
+
+-- ------------------------------------------------------------
+-- 瀛楀吀绫诲瀷
+-- ------------------------------------------------------------
+INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES
+(1065400, '璐ㄦ鎶ュ憡妯℃澘鐘舵��', 'qc_report_template_status', 0, '1', NOW(), '1', NOW(), b'0'),
+(1065401, '璐ㄦ鎶ュ憡妯℃澘鐗堟湰鐘舵��', 'qc_report_version_status', 0, '1', NOW(), '1', NOW(), b'0'),
+(1065402, '璐ㄦ鎶ュ憡瀹炰緥鐘舵��', 'qc_report_instance_status', 0, '1', NOW(), '1', NOW(), b'0'),
+(1065403, '璐ㄦ鎶ュ憡绾稿紶灏哄', 'qc_report_page_size', 0, '1', NOW(), '1', NOW(), b'0'),
+(1065404, '璐ㄦ鎶ュ憡绾稿紶鏂瑰悜', 'qc_report_orientation', 0, '1', NOW(), '1', NOW(), b'0'),
+(1065405, '璐ㄦ鎶ュ憡閫傜敤琛屼笟', 'qc_report_industry', 0, '1', NOW(), '1', NOW(), b'0');
+
+-- ------------------------------------------------------------
+-- 瀛楀吀鏁版嵁
+-- ------------------------------------------------------------
+INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES
+-- 妯℃澘鐘舵�侊紙瀵瑰簲 QcReportEnums.TemplateStatusEnum锛�
+(1065410, 1, '鍚敤', '0', 'qc_report_template_status', 0, 'success', '', '1', NOW(), '1', NOW(), b'0'),
+(1065411, 2, '鍋滅敤', '1', 'qc_report_template_status', 0, 'info', '', '1', NOW(), '1', NOW(), b'0'),
+-- 鐗堟湰鐘舵�侊紙瀵瑰簲 QcReportEnums.VersionStatusEnum锛�
+(1065420, 1, '鑽夌', '0', 'qc_report_version_status', 0, 'default', '', '1', NOW(), '1', NOW(), b'0'),
+(1065421, 2, '宸插彂甯�', '1', 'qc_report_version_status', 0, 'success', '', '1', NOW(), '1', NOW(), b'0'),
+(1065422, 3, '宸插仠鐢�', '2', 'qc_report_version_status', 0, 'info', '', '1', NOW(), '1', NOW(), b'0'),
+-- 瀹炰緥鐘舵�侊紙瀵瑰簲 QcReportEnums.InstanceStatusEnum锛�
+(1065430, 1, '鐢熸垚涓�', '0', 'qc_report_instance_status', 0, 'processing', '', '1', NOW(), '1', NOW(), b'0'),
+(1065431, 2, '鐢熸垚鎴愬姛', '1', 'qc_report_instance_status', 0, 'success', '', '1', NOW(), '1', NOW(), b'0'),
+(1065432, 3, '鐢熸垚澶辫触', '2', 'qc_report_instance_status', 0, 'error', '', '1', NOW(), '1', NOW(), b'0'),
+-- 绾稿紶灏哄锛堝搴� QcReportEnums.PageSizeEnum锛屽�间负瀛楃涓诧級
+(1065440, 1, 'A3', 'A3', 'qc_report_page_size', 0, 'default', '', '1', NOW(), '1', NOW(), b'0'),
+(1065441, 2, 'A4', 'A4', 'qc_report_page_size', 0, 'default', '', '1', NOW(), '1', NOW(), b'0'),
+(1065442, 3, 'A5', 'A5', 'qc_report_page_size', 0, 'default', '', '1', NOW(), '1', NOW(), b'0'),
+(1065443, 4, 'Letter', 'Letter', 'qc_report_page_size', 0, 'default', '', '1', NOW(), '1', NOW(), b'0'),
+-- 绾稿紶鏂瑰悜锛堝搴� QcReportEnums.OrientationEnum锛�
+(1065450, 1, '绾靛悜', 'portrait', 'qc_report_orientation', 0, 'default', '', '1', NOW(), '1', NOW(), b'0'),
+(1065451, 2, '妯悜', 'landscape', 'qc_report_orientation', 0, 'default', '', '1', NOW(), '1', NOW(), b'0'),
+-- 閫傜敤琛屼笟
+(1065460, 1, '閫氱敤', 'general', 'qc_report_industry', 0, 'default', '', '1', NOW(), '1', NOW(), b'0'),
+(1065461, 2, '鐢靛瓙鐢靛櫒', 'electronics', 'qc_report_industry', 0, 'default', '', '1', NOW(), '1', NOW(), b'0'),
+(1065462, 3, '浜旈噾鏈烘', 'hardware', 'qc_report_industry', 0, 'default', '', '1', NOW(), '1', NOW(), b'0'),
+(1065463, 4, '姹借溅闆堕儴浠�', 'auto', 'qc_report_industry', 0, 'default', '', '1', NOW(), '1', NOW(), b'0'),
+(1065464, 5, '濉戣兌鍒跺搧', 'plastic', 'qc_report_industry', 0, 'default', '', '1', NOW(), '1', NOW(), b'0'),
+(1065465, 6, '椋熷搧楗枡', 'food', 'qc_report_industry', 0, 'default', '', '1', NOW(), '1', NOW(), b'0'),
+(1065466, 7, '鍖昏嵂鍖荤枟', 'pharma', 'qc_report_industry', 0, 'default', '', '1', NOW(), '1', NOW(), b'0');
\ No newline at end of file
diff --git a/docs/sql/qc_report_menu.sql b/docs/sql/qc_report_menu.sql
new file mode 100644
index 0000000..62bac72
--- /dev/null
+++ b/docs/sql/qc_report_menu.sql
@@ -0,0 +1,34 @@
+-- ============================================================
+-- 鏅鸿兘璐ㄦ鎶ュ憡璁捐骞冲彴 鑿滃崟涓庢潈闄�
+-- 鐩爣搴擄細ruoyi-vue-pro锛坙ocal profile 鐨� master 鏁版嵁婧愶級
+-- 褰掑睘锛氳川閲忕鐞嗭紙鑿滃崟 id = 5500锛変笅
+-- 骞傜瓑锛氬厛鍒犲悗鎻�
+-- ============================================================
+
+USE `ruoyi-vue-pro`;
+
+-- 娓呯悊锛堝惈涔嬪墠鍙兘宸插瓨鍦ㄧ殑璁板綍锛�1075406 鏇句綔涓鸿璁″櫒鐨勯殣钘忚彍鍗曪紝宸叉敼涓哄墠绔潤鎬佽矾鐢憋級
+DELETE FROM `system_menu` WHERE `id` IN (1075400, 1075401, 1075402, 1075403, 1075404, 1075405, 1075406);
+-- 鍚屾娓呮帀璁捐鍣ㄩ殣钘忚彍鍗曢仐鐣欑殑瑙掕壊鎺堟潈锛岄伩鍏嶇暀涓嬪鍎挎巿鏉�
+DELETE FROM `system_role_menu` WHERE `menu_id` = 1075406;
+
+-- 鎶ュ憡妯℃澘璁捐锛堣彍鍗曪級
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`) VALUES
+(1075400, '鎶ュ憡妯℃澘璁捐', '', 2, 12, 5500, 'report-template', 'ep:document', 'mes/qc/report/template/index', NULL, 0);
+
+-- 鎶ュ憡妯℃澘 鎸夐挳鏉冮檺
+INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`) VALUES
+(1075401, '鎶ュ憡妯℃澘鏌ヨ', 'qc-report:template:query', 3, 1, 1075400, '', '', NULL, NULL, 0),
+(1075402, '鎶ュ憡妯℃澘鍒涘缓', 'qc-report:template:create', 3, 2, 1075400, '', '', NULL, NULL, 0),
+(1075403, '鎶ュ憡妯℃澘鏇存柊', 'qc-report:template:update', 3, 3, 1075400, '', '', NULL, NULL, 0),
+(1075404, '鎶ュ憡妯℃澘鍒犻櫎', 'qc-report:template:delete', 3, 4, 1075400, '', '', NULL, NULL, 0),
+(1075405, '鎶ュ憡妯℃澘鍙戝竷', 'qc-report:template:publish', 3, 5, 1075400, '', '', NULL, NULL, 0);
+
+-- 鎺堟潈缁欒秴绾х鐞嗗憳瑙掕壊锛堣嫢浠g爜宸插瓒呯杩斿洖鍏ㄩ儴鑿滃崟锛屾姝ヤ负鍐椾綑浣嗘棤瀹筹級
+INSERT INTO `system_role_menu` (`role_id`, `menu_id`, `creator`, `updater`, `deleted`)
+SELECT 1, m.`id`, 'admin', 'admin', b'0'
+FROM `system_menu` m
+WHERE m.`id` IN (1075400, 1075401, 1075402, 1075403, 1075404, 1075405)
+ AND NOT EXISTS (
+ SELECT 1 FROM `system_role_menu` rm WHERE rm.`role_id` = 1 AND rm.`menu_id` = m.`id` AND rm.`deleted` = b'0'
+ );
\ No newline at end of file
diff --git a/docs/sql/qc_report_platform_ddl.sql b/docs/sql/qc_report_platform_ddl.sql
new file mode 100644
index 0000000..ef4a269
--- /dev/null
+++ b/docs/sql/qc_report_platform_ddl.sql
@@ -0,0 +1,140 @@
+-- ============================================================
+-- 鏅鸿兘璐ㄦ鎶ュ憡璁捐骞冲彴 寤鸿〃鑴氭湰
+-- 妯″潡锛歽udao-module-qcreport
+-- 璇存槑锛氶」鐩笉浣跨敤澶氱鎴凤紝鏁呬笉鍚� tenant_id 瀛楁
+-- ============================================================
+
+-- ----------------------------
+-- 鎶ュ憡妯℃澘
+-- ----------------------------
+DROP TABLE IF EXISTS `qc_report_template`;
+CREATE TABLE `qc_report_template` (
+ `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '妯℃澘缂栧彿',
+ `template_code` VARCHAR(64) NOT NULL COMMENT '妯℃澘缂栫爜',
+ `template_name` VARCHAR(128) NOT NULL COMMENT '妯℃澘鍚嶇О',
+ `industry` VARCHAR(32) DEFAULT NULL COMMENT '鎵�灞炶涓�',
+ `report_type` VARCHAR(32) DEFAULT NULL COMMENT '鎶ュ憡绫诲瀷',
+ `page_size` VARCHAR(16) NOT NULL DEFAULT 'A4' COMMENT '绾稿紶灏哄锛欰3/A4/A5/Letter',
+ `orientation` VARCHAR(16) NOT NULL DEFAULT 'portrait' COMMENT '绾稿紶鏂瑰悜锛歱ortrait/landscape',
+ `status` TINYINT NOT NULL DEFAULT 0 COMMENT '妯℃澘鐘舵�侊細0鍚敤 1鍋滅敤',
+ `current_version` VARCHAR(32) DEFAULT NULL COMMENT '褰撳墠鐗堟湰鍙�',
+ `description` VARCHAR(512) DEFAULT NULL COMMENT '妯℃澘鎻忚堪',
+ `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_template_code` (`template_code`),
+ KEY `idx_template_name` (`template_name`)
+) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '鏅鸿兘璐ㄦ鎶ュ憡-鎶ュ憡妯℃澘';
+
+-- ----------------------------
+-- 妯℃澘鐗堟湰锛堝彂甯冨悗涓嶅彲瑕嗙洊锛�
+-- ----------------------------
+DROP TABLE IF EXISTS `qc_report_template_version`;
+CREATE TABLE `qc_report_template_version` (
+ `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '鐗堟湰缂栧彿',
+ `template_id` BIGINT NOT NULL COMMENT '妯℃澘缂栧彿',
+ `version` VARCHAR(32) NOT NULL COMMENT '鐗堟湰鍙凤紝濡� v1.0',
+ `schema_json` LONGTEXT COMMENT '妯℃澘 Schema锛圙rapesJS JSON + 缁勪欢 + 鏁版嵁婧� + 缁戝畾 + 瑙勫垯 + 鏍峰紡锛�',
+ `status` TINYINT NOT NULL DEFAULT 0 COMMENT '鐗堟湰鐘舵�侊細0鑽夌 1宸插彂甯� 2宸插仠鐢�',
+ `description` VARCHAR(512) DEFAULT NULL COMMENT '鐗堟湰璇存槑',
+ `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_template_version` (`template_id`, `version`),
+ KEY `idx_template_id` (`template_id`)
+) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '鏅鸿兘璐ㄦ鎶ュ憡-妯℃澘鐗堟湰';
+
+-- ----------------------------
+-- 鎶ュ憡瀹炰緥锛堝繀椤讳繚瀛樻暟鎹揩鐓э級
+-- ----------------------------
+DROP TABLE IF EXISTS `qc_report_instance`;
+CREATE TABLE `qc_report_instance` (
+ `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '瀹炰緥缂栧彿',
+ `report_no` VARCHAR(64) NOT NULL COMMENT '鎶ュ憡缂栧彿锛堜笟鍔″敮涓�锛�',
+ `template_id` BIGINT NOT NULL COMMENT '妯℃澘缂栧彿',
+ `template_version` VARCHAR(32) NOT NULL COMMENT '鐢熸垚鏃朵娇鐢ㄧ殑妯℃澘鐗堟湰鍙�',
+ `business_id` VARCHAR(64) DEFAULT NULL COMMENT '涓氬姟鍗曟嵁缂栧彿',
+ `business_type` VARCHAR(64) DEFAULT NULL COMMENT '涓氬姟鍗曟嵁绫诲瀷锛屽 mes_qc_iqc',
+ `data_snapshot` LONGTEXT COMMENT '鏁版嵁蹇収锛氭覆鏌撴椂鐨勫畬鏁存暟鎹笂涓嬫枃',
+ `render_html` LONGTEXT COMMENT '娓叉煋浜х墿 HTML',
+ `status` TINYINT NOT NULL DEFAULT 0 COMMENT '鎶ュ憡鐘舵�侊細0鐢熸垚涓� 1鐢熸垚鎴愬姛 2鐢熸垚澶辫触',
+ `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_report_no` (`report_no`),
+ KEY `idx_template_id` (`template_id`),
+ KEY `idx_business` (`business_type`, `business_id`)
+) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '鏅鸿兘璐ㄦ鎶ュ憡-鎶ュ憡瀹炰緥';
+
+-- ----------------------------
+-- 鏁版嵁婧愬畾涔�
+-- ----------------------------
+DROP TABLE IF EXISTS `qc_report_data_source`;
+CREATE TABLE `qc_report_data_source` (
+ `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `template_id` BIGINT NOT NULL COMMENT '妯℃澘缂栧彿',
+ `source_key` VARCHAR(64) NOT NULL COMMENT '鏁版嵁婧愭爣璇嗭紝濡� inspectionItems',
+ `source_type` VARCHAR(32) NOT NULL COMMENT '鏁版嵁婧愮被鍨嬶細BUILTIN/SQL/API',
+ `config` LONGTEXT COMMENT '鏁版嵁婧愰厤缃� JSON',
+ `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`),
+ KEY `idx_template_id` (`template_id`)
+) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '鏅鸿兘璐ㄦ鎶ュ憡-鏁版嵁婧�';
+
+-- ----------------------------
+-- 鍒ゅ畾瑙勫垯
+-- ----------------------------
+DROP TABLE IF EXISTS `qc_report_rule`;
+CREATE TABLE `qc_report_rule` (
+ `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `template_id` BIGINT NOT NULL COMMENT '妯℃澘缂栧彿',
+ `rule_name` VARCHAR(128) NOT NULL COMMENT '瑙勫垯鍚嶇О',
+ `target_path` VARCHAR(256) NOT NULL COMMENT '浣滅敤鐩爣璺緞锛屽 inspectionItems[].actualValue',
+ `expression` VARCHAR(1024) NOT NULL COMMENT '鍒ゅ畾琛ㄨ揪寮忥紝濡� actualValue >= lowerLimit AND actualValue <= upperLimit',
+ `pass_value` VARCHAR(64) DEFAULT 'PASS' COMMENT '鍚堟牸鏃惰緭鍑哄��',
+ `fail_value` VARCHAR(64) DEFAULT 'FAIL' COMMENT '涓嶅悎鏍兼椂杈撳嚭鍊�',
+ `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`),
+ KEY `idx_template_id` (`template_id`)
+) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '鏅鸿兘璐ㄦ鎶ュ憡-鍒ゅ畾瑙勫垯';
+
+-- ----------------------------
+-- 娓叉煋璁板綍锛堟帓鏌ョ敤锛氳�楁椂銆佹祻瑙堝櫒鐘舵�併�佸紓甯告爤锛�
+-- ----------------------------
+DROP TABLE IF EXISTS `qc_report_render_record`;
+CREATE TABLE `qc_report_render_record` (
+ `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '缂栧彿',
+ `report_id` BIGINT DEFAULT NULL COMMENT '鎶ュ憡瀹炰緥缂栧彿',
+ `template_id` BIGINT DEFAULT NULL COMMENT '妯℃澘缂栧彿',
+ `business_id` VARCHAR(64) DEFAULT NULL COMMENT '涓氬姟鍗曟嵁缂栧彿',
+ `render_start_time` DATETIME DEFAULT NULL COMMENT '娓叉煋寮�濮嬫椂闂�',
+ `render_end_time` DATETIME DEFAULT NULL COMMENT '娓叉煋缁撴潫鏃堕棿',
+ `render_duration` BIGINT DEFAULT NULL COMMENT '娓叉煋鑰楁椂锛堟绉掞級',
+ `pdf_duration` BIGINT DEFAULT NULL COMMENT 'PDF 鐢熸垚鑰楁椂锛堟绉掞級',
+ `browser_status` VARCHAR(64) DEFAULT NULL COMMENT '娴忚鍣ㄧ姸鎬�',
+ `error_stack` LONGTEXT COMMENT '寮傚父鍫嗘爤',
+ `creator` VARCHAR(64) DEFAULT '' COMMENT '鍒涘缓鑰�',
+ `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `updater` VARCHAR(64) DEFAULT '' COMMENT '鏇存柊鑰�',
+ `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+ `deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '鏄惁鍒犻櫎',
+ PRIMARY KEY (`id`),
+ KEY `idx_report_id` (`report_id`)
+) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT = '鏅鸿兘璐ㄦ鎶ュ憡-娓叉煋璁板綍';
\ No newline at end of file
diff --git "a/docs/\346\231\272\350\203\275\350\264\250\346\243\200\346\212\245\345\221\212\345\271\263\345\217\260-\345\274\200\345\217\221\350\277\233\345\272\246.md" "b/docs/\346\231\272\350\203\275\350\264\250\346\243\200\346\212\245\345\221\212\345\271\263\345\217\260-\345\274\200\345\217\221\350\277\233\345\272\246.md"
new file mode 100644
index 0000000..dacf288
--- /dev/null
+++ "b/docs/\346\231\272\350\203\275\350\264\250\346\243\200\346\212\245\345\221\212\345\271\263\345\217\260-\345\274\200\345\217\221\350\277\233\345\272\246.md"
@@ -0,0 +1,3382 @@
+# 鏅鸿兘璐ㄦ鎶ュ憡璁捐骞冲彴 鈥� 寮�鍙戣繘搴�
+
+> 渚濇嵁鏂囨。锛歚docs/鏅鸿兘璐ㄦ鎶ュ憡璁捐骞冲彴鈥斺�擟laude Code Agent 涓撲笟寮�鍙戞彁绀鸿瘝.md`
+> 鏂规璁捐锛歚docs/鏅鸿兘璐ㄦ鎶ュ憡骞冲彴-鏂规璁捐.md`
+> 寤鸿〃鑴氭湰锛歚docs/sql/qc_report_platform_ddl.sql`
+
+---
+
+## 2026-09-17锛堢 1 澶╋級
+
+### 涓�銆佷粖鏃ュ畬鎴愰」
+
+| # | 浜嬮」 | 鐘舵�� | 浜у嚭 |
+|---|---|---|---|
+| 1 | **Phase 0 椤圭洰鎵弿**锛堝悗绔� + 鍓嶇骞惰鎵弿锛� | 鉁� 瀹屾垚 | 鍚庣妯″潡甯冨眬/璐ㄦ鍩�/PDF鑳藉姏/鏂囦欢瀛樺偍/妗嗘灦宸ュ叿銆佸墠绔� Vben5.7+AntDV4.2.6/璺敱鑿滃崟椹卞姩/GrapesJS 缂哄け 绛夌粨璁� |
+| 2 | **鏂规璁捐鏂囨。** | 鉁� 瀹屾垚 | `docs/鏅鸿兘璐ㄦ鎶ュ憡骞冲彴-鏂规璁捐.md`锛�21 涓珷鑺傦細鎶�鏈爤銆佸彲澶嶇敤鑳藉姏銆佹暟鎹簱璁捐銆佺粍浠舵灦鏋勩�丟rapesJS 闆嗘垚銆丼chema銆佺粦瀹�/瑙勫垯/娓叉煋/Playwright/鍒嗛〉鏂规銆丄PI 鑽夋銆丳hase 1~5 璁″垝銆侀闄╂竻鍗曘�佸緟纭闂锛� |
+| 3 | **鍏抽敭鍐崇瓥纭**锛堢敤鎴锋媿鏉匡級 | 鉁� 瀹屾垚 | 瑙佷笅鏂广�屼簩銆佸叧閿喅绛栥�� |
+| 4 | **鍚庣妯″潡楠ㄦ灦** | 鉁� 瀹屾垚 | 鏂板缓 `yudao-module-qcreport` 妯″潡锛坧om + 瀹屾暣鍖呯洰褰曢鏋讹級 |
+| 5 | **妯″潡娉ㄥ唽** | 鉁� 瀹屾垚 | 鏍� `pom.xml` 鐨� `<modules>`銆乣yudao-server/pom.xml` 鐨� `<dependencies>` 鍚勫姞涓�鏉� |
+| 6 | **閿欒鐮佸畾涔�** | 鉁� 瀹屾垚 | `enums/ErrorCodeConstants.java`锛屼娇鐢� **1-070-000-000** 娈碉紙宸叉牳瀵� 1-001~1-013/020/022/030/040/050/051/060 鍧囪鍗犵敤锛� |
+| 7 | **鏍稿績 DO** | 鉁� 瀹屾垚 | `QcReportTemplateDO`銆乣QcReportTemplateVersionDO`銆乣QcReportInstanceDO` |
+| 8 | **妯℃澘 Schema 妯″瀷** | 鉁� 瀹屾垚 | `ReportTemplateSchema`锛坧age/grapes/components/dataSources/bindings/rules/styles锛� |
+| 9 | **鏋氫妇闆嗗悎** | 鉁� 瀹屾垚 | `QcReportEnums`锛歍emplateStatus / VersionStatus / InstanceStatus / PageSize / Orientation / CheckResult |
+| 10 | **寤鸿〃鑴氭湰** | 鉁� 瀹屾垚 | `docs/sql/qc_report_platform_ddl.sql`锛�6 寮犺〃锛屾棤 tenant_id锛� |
+
+### 浜屻�佸叧閿喅绛栵紙宸茶幏鐢ㄦ埛纭锛�
+
+| 璁 | 鍐崇瓥 | 璇存槑 |
+|---|---|---|
+| **鍓嶇淇敼鎺堟潈** | 鉁� **宸叉巿鏉�** | 鍏佽淇敼 `mom-pro2-before`锛堟柊澧為〉闈�/缁勪欢/API 鏂囦欢锛屼笉閲嶆瀯鏃㈡湁浠g爜锛� |
+| **PDF 鏂规** | 鉁� **鐢� Playwright + Chromium** | 鐢ㄦ埛纭杩愯/閮ㄧ讲鐜**鑳借仈缃�**锛屽彲涓嬭浇 Chromium |
+| **浠婃棩鑼冨洿** | 鉁� **鍚庣妯″潡楠ㄦ灦 + 妯℃澘 CRUD** | 娓叉煋閾捐矾涓庡墠绔璁″櫒鍚庣画杩涜 |
+| **妯″潡鍛藉悕** | 鉁� `yudao-module-qcreport` | 琛ㄥ悕 `qc_report_*`锛屾帴鍙e墠缂� `/qc-report/*`锛堣创鍚堥」鐩�屾ā鍧梍鍩熴�嶅懡鍚嶄範鎯級 |
+| 鍚庣妯″潡褰掑睘 | 鐙珛鏂版ā鍧� | 涓庤涓氫笟鍔¤В鑰︼紙鏂囨。 搂35 瑕佹眰鏍稿績缂栬緫鍣ㄤ笉涓庤涓氬己鑰﹀悎锛� |
+
+### 涓夈�佹壂鎻忓緱鍒扮殑鍏抽敭浜嬪疄锛堝悗缁紑鍙戝繀椤婚伒瀹堬級
+
+1. **UI 鏍堝敮涓�**锛氬墠绔槸 **Ant Design Vue 4.2.6 + Vben Admin 5.7.0 鍗曞簲鐢ㄧ増**锛�**鏃� Element Plus**銆傛柊椤甸潰蹇呴』鐢� AntDV锛岀姝㈠紩鍏� Element Plus銆�
+2. **鑿滃崟/璺敱鐢卞悗绔┍鍔�**锛氶〉闈㈡斁鍒� `src/views/**/index.vue`锛屽悗绔� `system_menu.component` 鍐欑浉瀵硅矾寰勶紙濡� `mes/qc/report/template/index`锛夊嵆鍙嚭鐜拌彍鍗曪紝**鏃犻渶鎵嬪伐娉ㄥ唽璺敱**銆�
+3. **璐ㄦ涓氬姟妯″瀷宸插瓨鍦ㄤ笖瀹屽**锛圡ES `qc` 鍩燂級锛歚mes_qc_iqc / ipqc / oqc / rqc` + `*_line`銆乣mes_qc_template / _indicator / _item`銆乣mes_qc_indicator_result(_detail)`銆乣mes_qc_ncr`銆�**鎶ュ憡骞冲彴蹇呴』缁戝畾澶嶇敤锛岀姝㈤噸寤鸿川妫�妯″瀷銆�**
+4. **椤圭洰闆� PDF 鐢熸垚鑳藉姏**锛氫粎鏈� PDFBox锛圕RM/ERP 鍙瑙f瀽锛夈�丗astExcel锛圗xcel 瀵煎嚭锛夈�侾laywright/Chromium/FreeMarker/openhtmltopdf **鍏ㄩ儴涓嶅瓨鍦�**锛岄渶鏂板銆�
+5. **绉湪鎶ヨ〃妯″潡琚敞閲婄鐢�**锛氭牴 `pom.xml` 涓� `yudao-server/pom.xml` 涓� `yudao-module-report` 涓烘敞閲婄姸鎬侊紙娉ㄩ噴璇存槑銆岀Н鏈ㄦ姤琛ㄦ殏涓嶆敮鎸� Spring Boot 4銆嶏級鈥斺�旀晠鏂版ā鍧�**涓嶅鐢ㄨ鍚嶅瓧**锛屾敼鐢� `yudao-module-qcreport`銆�
+6. **鍓嶇宸茶鍙洿鎺ュ鐢ㄧ殑搴�**锛堥伩鍏嶉噸澶嶉�犺疆瀛愶級锛�
+ - `qrcode 1.5.4` + `jsbarcode 3.12.3`锛堝凡灏佽 `packages/effects/common-ui/src/components/barcode/barcode.vue`锛屽惈 `getImageBase64()`锛�
+ - `vue3-print-nb 0.1.4`锛堟墦鍗帮紝鑼冧緥 `views/bpm/processInstance/detail/modules/process-print.vue`锛�
+ - `vue3-signature 0.4.4`锛堢數瀛愮鍚嶏紝HRM 宸茬敤锛�
+ - `vuedraggable 4.1.0` + `sortablejs 1.15.7`锛堟嫋鎷斤級
+ - `tinymce 7.9.3` / `@tiptap/*`锛堝瘜鏂囨湰锛夈�乣echarts 6.1.0`锛堝浘琛級
+ - `bpmn-js 18.16.1`锛堥」鐩唴鍞竴銆岀敾甯�+灞炴�ч潰鏉裤�嶅厛渚嬶紝鍙弬鑰冨竷灞�缁勭粐锛�
+7. **GrapesJS 纭鏈畨瑁�**锛孭hase 1 闇�鏂板渚濊禆锛堜綋绉�/鏋勫缓褰卞搷闇�璇勪及锛夈��
+8. **JSON 鍒楀瓨鍌ㄨ寖寮�**锛歚@TableName(value=..., autoResultMap = true)` + `@TableField(typeHandler = Jackson3TypeHandler.class)`锛堣寖渚� `BpmFormDO.java:53`锛夈��
+9. **妗嗘灦閫氱敤浠�**锛歚CommonResult` / `PageResult` / `PageParam` / `BaseDO`锛坈reator/updater/createTime/updateTime/deleted 鑷姩濉厖锛�/ `ServiceException`+`ServiceExceptionUtil.exception(...)` / `BeanUtils` / `BaseMapperX` / `LambdaQueryWrapperX`銆�
+10. **鏃犲绉熸埛**锛歚yudao.tenant.enable: false`锛屾柊琛�**涓嶅姞 tenant_id**锛堜笌椤圭洰瑙勫垯涓�鑷达級銆�
+11. **娴嬭瘯鍩虹被**锛欽Unit5 + `BaseDbUnitTest`锛圚2锛�/ `BaseMockitoUnitTest` + PODAM銆�
+12. **鏋勫缓鍛戒护**锛氬悗绔� `mvn compile -pl <妯″潡> -am -q` / 鍏ㄩ噺 `mvn compile -q`锛涘墠绔� `pnpm dev`(5666) / `pnpm build` / `pnpm typecheck`銆�
+
+### 鍥涖�佷粖鏃ユ柊澧�/淇敼鏂囦欢娓呭崟
+
+**鏂板锛堝悗绔級**
+
+```
+yudao-module-qcreport/pom.xml
+yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/
+鈹溾攢鈹� enums/ErrorCodeConstants.java # 1-070 娈甸敊璇爜
+鈹溾攢鈹� enums/QcReportEnums.java # 6 缁勬灇涓�
+鈹溾攢鈹� dal/dataobject/template/QcReportTemplateDO.java
+鈹溾攢鈹� dal/dataobject/version/QcReportTemplateVersionDO.java
+鈹溾攢鈹� dal/dataobject/version/ReportTemplateSchema.java
+鈹斺攢鈹� dal/dataobject/instance/QcReportInstanceDO.java
+锛堝彟宸插缓濂� controller/service/dal.mysql/engine{bounding,rule,render}/config 鐨勭┖鐩綍楠ㄦ灦锛�
+```
+
+**淇敼锛堝悗绔叕鍏辨枃浠讹紝褰卞搷闈㈠凡璇勪及锛�**
+
+| 鏂囦欢 | 鏀瑰姩 | 褰卞搷闈� |
+|---|---|---|
+| `pom.xml` | `<modules>` 澧炲姞 `yudao-module-qcreport` | 浠呮柊澧炰竴涓瓙妯″潡锛屼笉褰卞搷鏃㈡湁妯″潡鏋勫缓 |
+| `yudao-server/pom.xml` | `<dependencies>` 澧炲姞 `yudao-module-qcreport` | 鍚姩妯″潡澶氳仛鍚堜竴涓� jar |
+
+**鏂板锛堟枃妗�/SQL锛�**
+
+```
+docs/鏅鸿兘璐ㄦ鎶ュ憡骞冲彴-鏂规璁捐.md
+docs/鏅鸿兘璐ㄦ鎶ュ憡骞冲彴-寮�鍙戣繘搴�.md # 鏈枃浠�
+docs/sql/qc_report_platform_ddl.sql # 6 寮犺〃寤鸿〃鑴氭湰
+```
+
+### 浜斻�佽繘琛屼腑 / 鏈畬鎴愰」
+
+| 浜嬮」 | 鐘舵�� | 涓嬩竴姝� |
+|---|---|---|
+| 鏂版ā鍧楃紪璇戦獙璇� | 鉁� **宸查�氳繃** | `mvn compile -pl yudao-module-qcreport -am -q` **exit code 0**锛宍target/classes/.../qcreport/{dal,enums}` 宸蹭骇鍑恒�傛棤闇�淇 |
+| 妯℃澘 CRUD锛圕ontroller/Service/Mapper/VO锛� | 鏈紑濮� | Phase 1 棣栬浠诲姟 |
+| 鐗堟湰 CRUD + 鍙戝竷/鍥炴粴 | 猬� 鏈紑濮� | |
+| 鑿滃崟/鏉冮檺 SQL锛坄system_menu` + 鏉冮檺鐮侊級 | 鏈紑濮� | 闇�鎸夊綋鍓嶆縺娲� profile 鎸囧悜鐨勭洰鏍囧簱鍐欏叆 |
+| DDL 钀藉簱鎵ц | 猬� 鏈紑濮� | 娉ㄦ剰锛�**涓嶅緱鍦ㄨ繍琛屽簱 `ruoyi-vue-pro` 闅忔剰鎵ц**锛屾寜鐩爣搴撴墽琛� |
+| 鍓嶇 Designer + Quality Components | 猬� 鏈紑濮� | 宸茶幏鎺堟潈 |
+| GrapesJS 渚濊禆寮曞叆 | 猬� 鏈紑濮� | 闇�璇勪及浣撶Н涓� Vite 鏋勫缓褰卞搷 |
+| 鏁版嵁缁戝畾寮曟搸 / 瑙勫垯寮曟搸 | 猬� 鏈紑濮� | **绂佹鐢� eval**锛岄』鑷缓 AST 瑙f瀽鐧藉悕鍗曟眰鍊� |
+| HTML 娓叉煋 + Playwright PDF | 猬� 鏈紑濮� | 闇�鍔� `com.microsoft.playwright:playwright` 鍒� `yudao-dependencies` |
+| 鎶ュ憡瀹炰緥 + data_snapshot | 鏈紑濮� | |
+
+### 鍏�佽俯杩囩殑鍧� / 娉ㄦ剰浜嬮」
+
+1. **閿欒鐮佹鍙峰啿绐�**锛氭柊澧炴ā鍧楀墠蹇呴』鍏� grep 鍏ㄩ」鐩� `ErrorCodeConstants` 纭娈靛彿鏈鍗犵敤锛堟湰椤圭洰宸茬敤 1-001~1-013銆�1-020銆�1-022銆�1-030銆�1-040銆�1-050銆�1-051銆�1-060锛夛紝鏈閫夌敤 **1-070**銆�
+2. **`yudao-module-report` 鍚嶅瓧琚崰**锛堢Н鏈ㄦ姤琛紝娉ㄩ噴鐘舵�侊級锛屾柊妯″潡閬垮紑璇ュ悕锛岄伩鍏嶆棩鍚庡惎鐢ㄧН鏈ㄦ姤琛ㄦ椂鍐茬獊銆�
+3. **鍓嶇鏄�屽崟搴旂敤鐗堛��**锛坄@vben/web-antd-standalone`锛夛細涓氬姟浠g爜鍦�**鏍� `src/`**锛屼笉鏄� `apps/web-antd/src`銆傛壂鎻忔椂瀹规槗鐪嬮敊銆�
+4. **鍓嶇鏃� Element Plus**锛氭柟妗堟枃妗f彁鍒� Vben + AntDV锛屽疄闄呯‘璁�**鏃� Element Plus**锛屼笉瑕佹寜"鏌愪笟鍔℃ā鍧楀凡缁熶竴鐢� Element Plus"鍘婚�夊瀷銆�
+5. **`docs/` 涓嬪凡鏈夊ぇ閲忔棦鏈夋柟妗堟枃妗�**锛屾柊鏂囨。鍛藉悕闇�甯︽ā鍧楀墠缂�锛堟湰娆$敤銆屾櫤鑳借川妫�鎶ュ憡骞冲彴-銆嶏級浠ュ厤娣锋穯銆�
+6. **DDL 涓殑 `schema` 鏄� MySQL 淇濈暀瀛�**锛屽缓琛ㄨ剼鏈凡鐢ㄥ弽寮曞彿鍖呰9锛汳yBatis-Plus 鏄犲皠鏃跺瓧娈靛悕 `schema` 涔熼渶娉ㄦ剰锛堝綋鍓嶇敱 `Jackson3TypeHandler` 鏄犲皠涓� `ReportTemplateSchema` 瀵硅薄锛屾甯革級銆�
+7. **Playwright 棣栨浣跨敤闇�涓嬭浇 Chromium**锛堢害 150MB锛夛紝鐢ㄦ埛宸茬‘璁ょ幆澧冨彲鑱旂綉锛涘疄鐜版椂闇�澶勭悊銆屾湭瀹夎鏃剁粰鍑哄彲璇绘彁绀恒�嶏紙宸插畾涔夐敊璇爜 `RENDER_PDF_BROWSER_LAUNCH_FAILED`锛夈��
+
+### 涓冦�佹槑鏃ワ紙2026-09-18锛夊緟鍔炴竻鍗�
+
+1. **纭鏂版ā鍧楃紪璇戠粨鏋�**锛屼慨澶嶇紪璇戦敊璇紙`mvn compile -pl yudao-module-qcreport -am -q`锛夈��
+2. **鎵ц DDL 钀藉簱**锛氱洰鏍囧簱 = **`ruoyi-vue-pro`**锛�2026-09-17 鏅氬疄娴嬶細`application.yaml:6` active=local锛沗application-local.yaml:68` master 鏁版嵁婧� = `jdbc:mysql://localhost:3306/ruoyi-vue-pro`锛宺oot/123456锛夈��
+ 鈿� 璇ラ厤缃紓绉婚绻侊紙鍘嗗彶涓婂嚭鐜拌繃 mom-xgdl / mom-thzy锛夛紝**鍔ㄦ墜鍓嶅姟蹇呴噸鏂� grep 涓�娆� datasource**锛涘彟闇�纭 MySQL MCP 杩炵殑鏄惁鍚屼竴瀹炰緥锛屼笉鏄垯鐢� `docker exec mysql8 mysql -uroot -p123456 -e "..."`锛屽苟鐢� `information_schema` 鍥炶楠岃瘉銆�
+3. **瀹屾垚妯℃澘 CRUD**锛圥hase 1 鍚庣閮ㄥ垎锛夛細
+ - `QcReportTemplateMapper` + `QcReportTemplateService/Impl` + `QcReportTemplateController`
+ - VO锛歚QcReportTemplateSaveReqVO` / `PageReqVO` / `RespVO`
+ - 鏌ヨ鏉′欢锛氭ā鏉垮悕绉般�佺紪鐮併�佽涓氥�佹姤鍛婄被鍨嬨�佺姸鎬併�佸垱寤轰汉銆佸垱寤烘椂闂�
+ - 鎺ュ彛锛歝reate / update / delete / get / page / copy
+4. **鐗堟湰 CRUD**锛歚QcReportTemplateVersionMapper/Service/Controller`锛宑reate / list / publish / rollback锛堝彂甯冨悗涓嶅彲瑕嗙洊锛夈��
+5. **鑿滃崟涓庢潈闄�**锛歚system_menu` 鑿滃崟璁板綍 + 鏉冮檺鐮� `qc-report:template:*`銆乣qc-report:instance:*`锛屾寜鐩爣搴撳啓鍏ャ��
+6. **鍓嶇璧锋**锛堝凡鑾锋巿鏉冿級锛氳瘎浼板苟寮曞叆 GrapesJS锛屾惌 `src/views/mes/qc/report/template/` 鍒楄〃椤碉紙鐓ф妱 `src/views/mes/qc/defect/` 缁撴瀯锛�+ `src/api/mes/qc/report/` API 鏂囦欢銆�
+7. 锛堣嫢鏃堕棿鍏佽锛夊惎鍔� **Quality Components core**锛坱ypes/registry/factory/serializer/validator锛夈��
+
+### 鍏�侀闄╂彁閱掞紙鏄庢棩寮�宸ュ墠鍏堢湅锛�
+
+| # | 椋庨櫓 | 绛夌骇 |
+|---|---|---|
+| 1 | Playwright Chromium 涓嬭浇鍙楃綉缁滈檺鍒讹紙宸茬‘璁ゅ彲鑱旂綉锛屼絾闇�瀹炴祴锛� | 馃煛 |
+| 2 | GrapesJS 鏂板渚濊禆瀵� Vite 鏋勫缓浣撶Н鐨勫奖鍝� | 馃煛 |
+| 3 | 瑙勫垯寮曟搸琛ㄨ揪寮忓畨鍏紙**涓ョ eval / ScriptEngine**锛� | |
+| 4 | 妯℃澘 HTML 灞炵敤鎴峰彲缂栬緫鍐呭 鈫� 蹇呴』鏈嶅姟绔� Sanitization锛圶SS锛� | 馃煛 |
+| 5 | 鏂拌〃 DDL 蹇呴』钀藉埌**鐩爣搴�**锛岀姝㈡薄鏌撹繍琛屽簱 | 馃煛 |
+| 6 | 100+ 椤� PDF / 1000+ 琛岃〃鏍肩殑鎬ц兘涓庡唴瀛� | 馃煝 |
+
+---
+
+## 2026-09-18锛堢 2 澶╋級
+
+### 涓�銆佷粖鏃ュ畬鎴愰」
+
+| # | 浜嬮」 | 鐘舵�� | 浜у嚭 |
+|---|---|---|---|
+| 1 | **DDL / 瀛楀吀 / 鑿滃崟 钀藉簱** | 鉁� 瀹屾垚 | `qc_report_platform_ddl.sql`锛�6 寮犺〃锛夈�乣qc_report_dict.sql`銆乣qc_report_menu.sql` 宸叉墽琛屽埌杩愯搴� `ruoyi-vue-pro` |
+| 2 | **妯℃澘 CRUD 鍚庣** | 鉁� 瀹屾垚 | Controller/Service/Mapper/VO 鍏ㄥ锛屽惈 **copy锛堝鍒舵ā鏉匡級**锛涙帴鍙� `/qc-report/template/{create,update,delete,get,page,copy}` |
+| 3 | **鐗堟湰 CRUD + 鍙戝竷** | 鉁� 瀹屾垚 | `/qc-report/template-version/{create,update,get,list-by-template,publish}`锛�**宸插彂甯冪増鏈笉鍙鐩�**锛屾敼鍔ㄥ彧鑳藉彟瀛樻柊鑽夌 |
+| 4 | **鑿滃崟涓庢潈闄愮爜** | 鉁� 瀹屾垚 | 鑿滃崟銆岃川閲忕鐞� 鈫� 鎶ュ憡妯℃澘銆�+ 鏉冮檺鐮� `qc-report:template:*` |
+| 5 | **鍓嶇寮曞叆 GrapesJS + 鍒楄〃椤�** | 鉁� 瀹屾垚 | `grapesjs ^0.23.6`锛堢粡 `catalog:` 澹版槑锛夛紱鍒楄〃椤� `template/index.vue` + `modules/form.vue` + `data.ts` |
+| 6 | **妯℃澘璁捐鍣ㄩ〉闈紙Phase 1 鍓嶇锛�** | 鉁� 瀹屾垚 | `template/designer/`锛坄index.vue` / `use-designer.ts` / `blocks.ts` / `constants.ts`锛�+ 闈欐�佽矾鐢� `router/routes/modules/qcreport.ts` |
+| 7 | **璁捐鍣ㄧ鍒扮鑱旇皟楠岃瘉** | 鉁� 瀹屾垚 | 瑙佷笅鏂广�屼簩銆佽璁″櫒鑱旇皟锛氬畾浣嶅苟淇鐨� 12 涓棶棰樸�� |
+
+### 浜屻�佽璁″櫒鑱旇皟锛氬畾浣嶅苟淇鐨� 12 涓棶棰�
+
+Phase 1 鐨勮璁″櫒鏄妸 GrapesJS 宓岃繘 AntDV 椤甸潰锛岀嫭绔嬭俯浜� 12 涓潙锛屽潎宸蹭慨澶嶅苟閫愭潯鍦ㄦ祻瑙堝櫒瀹炴祴锛�
+
+| # | 鐜拌薄 | 鏍瑰洜 | 淇 |
+|---|---|---|---|
+| 1 | 椤甸潰鐧藉睆锛屾帶鍒跺彴鎶� `does not provide an export named 'useTabs'` | `useTabs` 浠� `@vben/common-ui` 瀵煎叆锛屽疄闄呭湪 **`@vben/hooks`** | 鏀瑰鍏ユ潵婧愶紙`designer/index.vue`锛� |
+| 2 | 璋冩暣绾稿紶璁剧疆鍚庯紝鐢诲竷涓婃湭淇濆瓨鐨勫唴瀹硅娓呯┖ | 銆屽簲鐢ㄥ埌鐢诲竷銆嶅鐢ㄤ簡 `loadSchema()`锛屼細鎶婁笂娆′繚瀛樼殑鏁版嵁閲嶆柊鐏屽洖鐢诲竷 | 鏂板**闈炵牬鍧忓紡** `applyPageSize()`锛屽彧閲嶆帓灏哄涓庡弬鑰冪嚎锛屼笉鍔ㄧ敾甯冨唴瀹� |
+| 3 | 鐢诲竷绌虹櫧锛宨frame 灏哄 0脳0 | `Devices.remove(id)` + `add(id)` + `setDevice(id)` 鍚� device 鍙栧�兼病鍙橈紝Backbone 涓嶈Е鍙� `change:device`锛宍Canvas.updateDevice` 涓嶆墽琛� | 璁惧 id 缂栫爜灏哄锛坄qc-report-page-1123x794`锛夛紝淇濊瘉鍙栧�肩湡鍙樺寲 |
+| 4 | 淇濆瓨涓嬫潵鐨勬牱寮忔寕鍦� `@media (max-width: 794px)` 涓婏紝鎹㈢焊寮犲嵆澶辨晥 | `Device` 鐨� `widthMedia` 涓� `null` 鏃朵細鍥為��鎴� `width`锛屼骇鐢熸寜璁惧瀹界殑濯掍綋鏌ヨ | 娉ㄥ唽璁惧鏃舵樉寮� `widthMedia: ''` |
+| 5 | 鑰佹ā鏉挎墦寮�鏄┖鐧界紪杈戝櫒锛堜笉鏄師鏈夊唴瀹癸級 | 鏃ф暟鎹� `grapes` 鍙湁 `{assets, styles}`銆�**娌℃湁 `pages`**锛宍loadProjectData` 杞戒笉鍑洪〉闈� | `loadSchema` 澧炲姞 `Array.isArray(pages) && pages.length > 0` 瀹堝崼 |
+| 6 | 绾稿紶鐪嬩笉瑙侊紙娣辫壊鑳屾櫙锛� | GrapesJS 榛樿**娣辫壊涓婚**锛屼笖 `--gjs-left-width:15%`/`--gjs-canvas-top:40px` 浠嶅湪鐢熸晥锛宍panels:{defaults:[]}` 骞朵笉鑳藉幓鎺夊畠浠� | 鍦ㄩ〉闈㈡牴鑺傜偣瑕嗙洊 `--gjs-*` 鍙橀噺涓烘祬鑹蹭富棰� + 缃浂 `--gjs-left-width`/`--gjs-canvas-top` |
+| 7 | 绾稿紶鐧藉簳鏃舵湁鏃舵棤 | `canvas.frameStyle` **鍙綔鐢ㄤ簬绗竴涓敾甯冨抚**锛宍loadProjectData` 鏂板缓鐨勫抚娌$櫧搴� | `applyFrameGuide()` 鍦ㄦ瘡娆� `canvas:frame:load` 涓庨噸寤哄悗鏄惧紡鍐� body 鐧藉簳 + 椤佃竟璺� |
+| 8 | 鐢诲竷姣斿彲瑙嗗尯澶ф椂琚鎺夛紝涓�**鏃犳硶婊氬姩** | `.gjs-cv-canvas` 鏄� `overflow:hidden` 鐨勭粷瀵瑰畾浣嶈垶鍙帮紝甯т篃鏄粷瀵瑰畾浣� | 瑕嗙洊涓� `overflow:auto` 婊氬姩瀹瑰櫒锛屽抚瀹瑰櫒/甯у寘瑁� `position:static`銆乣margin:24px auto` 鍥炲綊鏂囨。娴� |
+| 9 | **鐐瑰嚮宸︿晶缁勪欢鍧楁棤浠讳綍鍙嶅簲** | `BlockView.handleClick` 鍦ㄤ笉婊¤冻 `block.onClick \|\| config.appendOnClick` 鏃剁洿鎺� return | `blockManager.appendOnClick: true`锛岀偣鍑诲嵆杩藉姞锛堟嫋鎷藉悓鏃跺彲鐢級 |
+| 10 | **宸﹀彸涓や晶銆岀粍浠� / 灞炴�с�嶉潰鏉挎粴涓嶅姩锛屽簳閮ㄨ瑁�** | Ant `Spin` 澶氬寘浜嗕竴灞� `.ant-spin-container`锛屽畠榛樿鏄�**鍐呭楂樺害**鑰岄潪鎾戞弧鐖剁骇锛屾妸涓ゆ爮鎾戝埌 785px > 鍙鍖� 735px锛宍overflow:auto` 姘镐笉瑙﹀彂 | `:deep(.ant-spin-container){ height:100% }` 鎶婇珮搴﹂摼鎺ュ洖 `flex-1` 鐖剁骇 |
+| 11 | 鐢诲竷 iframe 鐨� `<style>` 閲屽嚭鐜板瓧闈㈤噺 `[object Object]` | `canvas.frameStyle` 浼氳**鍘熸牱鎷兼帴**鎴� CSS 鏂囨湰锛屼紶瀵硅薄鍗冲嚭閿� | 鏀逛负浼� CSS 瀛楃涓� |
+| 12 | 鎵撳紑宸插垹闄ょ殑妯℃澘 / 鍒囨崲宸插垹闄ょ殑鐗堟湰鏃�**鏁撮〉宕╂簝**锛坄Cannot read properties of null`锛� | `getTemplate`/`getVersion` 瀵瑰凡杞垹闄ょ殑璁板綍杩斿洖 `data:null`锛屽墠绔湭鍏� | 涓ゅ鍧囧姞绌哄�煎畧鍗細鎻愮ず銆屼笉瀛樺湪鎴栧凡琚垹闄ゃ�嶅苟杩斿洖鍒楄〃 / 鍒锋柊鐗堟湰鍒楄〃 |
+
+### 涓夈�佽仈璋冮獙璇佺粨璁猴紙娴忚鍣ㄥ疄娴嬶級
+
+| 楠岃瘉椤� | 缁撴灉 |
+|---|---|
+| 鐐瑰嚮缁勪欢鍧楄拷鍔犲埌鐢诲竷 | 鉁� 杩藉姞鍑� `data-quality-type` 涓� `Heading` / `Table` 鐨勭粍浠讹紝琛ㄦ牸 12 涓崟鍏冩牸姝e父鐢熸垚 |
+| 鐢诲竷婊氬姩 | 鉁� `scrollHeight 842 > clientHeight 725`锛屽彲婊氬姩 |
+| 宸︿晶缁勪欢闈㈡澘婊氬姩 | 鉁� `scrollHeight 785 > clientHeight 735`锛屽疄娴� `scrollTop` 鍙揪 50.7 |
+| 鍙充晶灞炴�ч潰鏉挎粴鍔� | 鉁� 閫変腑缁勪欢骞跺睍寮�鏍峰紡鍒嗗尯鍚� `scrollHeight 1458 > clientHeight 735`锛屽疄娴嬪彲婊氬埌搴� |
+| 淇濆瓨鑽夌锛堟柊寤虹増鏈級 | 鉁� 鏂版ā鏉夸繚瀛樺嚭 `v1.0(鑽夌)`锛岃惤搴� `schema_json` 4527 瀛楃 |
+| 淇濆瓨鍐呭姝g‘鎬� | 鉁� `schemaVersion=1.0`銆乣page=A4绾靛悜10mm`銆乣grapes.pages` 1 涓�乣components` 璁板綍 `ReportHeader`+`Table` 涓斿甫 `index`锛�**鏃� `mediaText`銆佹棤 `[object Object]`** |
+| 閲嶆柊鎵撳紑杩樺師 | 鉁� 鐗堟湰涓嬫媺鏄剧ず銆寁1.0锛堣崏绋匡級銆嶏紝鐢诲竷杩樺師鍑� `ReportHeader`+`Table` 涓庨〉杈硅窛 |
+| 鍓嶇绫诲瀷妫�鏌� | 鉁� `pnpm typecheck` 鍦ㄦ湰妯″潡鏂版敼鏂囦欢涓� **0 error**锛堜粨搴撳叾浣� 316 鏉′负鏃㈡湁闂锛岄泦涓湪 `views/bi/warehouse`銆乣views/wls`銆乣views/crm` 绛夛紝闈炴湰娆″紩鍏ワ級 |
+
+### 鍥涖�佷粖鏃ユ柊澧�/淇敼鏂囦欢娓呭崟
+
+**鏂板锛堝悗绔� `yudao-module-qcreport`锛�**
+
+```
+controller/admin/template/QcReportTemplateController.java
+controller/admin/template/vo/{QcReportTemplatePageReqVO,RespVO,SaveReqVO}.java
+controller/admin/version/QcReportTemplateVersionController.java
+controller/admin/version/vo/{PageReqVO,RespVO,SaveReqVO,UpdateReqVO}.java
+dal/mysql/{template/QcReportTemplateMapper,version/QcReportTemplateVersionMapper}.java
+service/template/{QcReportTemplateService,QcReportTemplateServiceImpl}.java
+service/version/{QcReportTemplateVersionService,QcReportTemplateVersionServiceImpl}.java
+```
+
+**鏂板锛堝墠绔� `mom-pro2-before`锛�**
+
+```
+src/api/mes/qc/report/template/index.ts
+src/api/mes/qc/report/version/index.ts
+src/router/routes/modules/qcreport.ts # 璁捐鍣ㄩ潤鎬佽矾鐢憋紙hideInMenu锛屽甫 id 璺宠浆锛�
+src/views/mes/qc/report/template/index.vue # 妯℃澘鍒楄〃椤碉紙鏂板銆岃璁°�嶅叆鍙o級
+src/views/mes/qc/report/template/modules/form.vue
+src/views/mes/qc/report/template/data.ts # 鍒楄〃/琛ㄥ崟 schema
+src/views/mes/qc/report/template/designer/index.vue # 璁捐鍣ㄩ〉闈紙椤舵爮/绾稿紶璁剧疆/涓夋爮甯冨眬锛�
+src/views/mes/qc/report/template/designer/use-designer.ts # GrapesJS 灏佽锛堢敾甯� 鈫� Schema 鍙屽悜杞崲锛�
+src/views/mes/qc/report/template/designer/blocks.ts # 鍩虹缁勪欢鍧楀畾涔�
+src/views/mes/qc/report/template/designer/constants.ts # 绾稿紶灏哄/榛樿椤�/鎹㈢畻
+```
+
+**鏂板锛圫QL锛�**锛歚docs/sql/qc_report_dict.sql`銆乣docs/sql/qc_report_menu.sql`
+
+### 浜斻�佽繘琛屼腑 / 鏈畬鎴愰」
+
+| 浜嬮」 | 鐘舵�� | 涓嬩竴姝� |
+|---|---|---|
+| GrapesJS 璁捐鍣紙Phase 1锛� | 鉁� 瀹屾垚骞跺疄娴� | 鈥� |
+| **Quality Components 娉ㄥ唽鏈哄埗** | 鉁� 瀹屾垚 | 瑙佹枃鏈�孭hase 2 瀹炴柦璁板綍銆� |
+| 璐ㄩ噺缁勪欢鏈綋 | 鉁� 瀹屾垚 | 12 涓粍浠讹紙鍩虹 6 + 鎶ュ憡 3 + 妫�楠� 2 + 缁撴灉 1锛� |
+| QualityPropertyPanel锛堜笟鍔″睘鎬ч潰鏉匡級 | 鉁� 瀹屾垚 | 鍗忚瀛楁缁� traits 钀藉埌灞炴�ч潰鏉匡紝鍚�岀粦瀹氭暟鎹�嶆帶浠� |
+| 鏁版嵁缁戝畾寮曟搸 | 鉁� 瀹屾垚 | 璺緞瑙f瀽 + 鍙栧�� + 缂哄彛涓婃姤 |
+| 瑙勫垯寮曟搸 | 鉁� 瀹屾垚 | 鑷缓 AST 鐧藉悕鍗曟眰鍊硷紝**鏃� eval / ScriptEngine** |
+| HTML 娓叉煋寮曟搸 | 鉁� 瀹屾垚 | 瑙佹枃鏈�孭hase 2 瀹炴柦璁板綍銆� |
+| Playwright / Chromium PDF | 猬� 鏈紑濮� | Phase 3锛�**绂佹鐢ㄦ埅鍥炬柟寮忕敓鎴� PDF**锛涢渶鍏堝畾銆屽墠绔覆鏌� HTML 鈫� 鍚庣鎵撳嵃銆嶈繕鏄�屽悗绔� Java 閲嶅啓娓叉煋銆� |
+| 鎶ュ憡瀹炰緥 + `data_snapshot` | 猬� 鏈紑濮� | Phase 4锛涚敓鎴愭椂蹇収锛屼繚璇佸巻鍙叉姤鍛婁笉闅忎富鏁版嵁鍙樺寲 |
+| 鑷姩鍖栨祴璇� / E2E | 猬� 鏈紑濮� | Phase 5 |
+
+### 鍏�佽俯杩囩殑鍧� / 娉ㄦ剰浜嬮」锛堣ˉ鍏咃級
+
+1. **GrapesJS 鐨� `frameStyle` 鏄� CSS 瀛楃涓蹭笉鏄璞�**锛屼紶瀵硅薄浼氳鎷兼垚 `[object Object]` 鍐欒繘鐢诲竷銆�
+2. **GrapesJS 榛樿娣辫壊涓婚**锛屽嵆浣� `panels:{defaults:[]}` 鍘绘帀浜嗛粯璁ら潰鏉匡紝`--gjs-left-width`/`--gjs-canvas-top` 浠嶄細褰卞搷 `.gjs-cv-canvas` 鐨勫楂樿绠楋紝蹇呴』涓�骞惰鐩栥��
+3. **`Devices` 鐨� `setDevice` 鍦� id 涓嶅彉鏃朵笉浼氳Е鍙� `change:device`**锛圔ackbone 璇箟锛夛紝瑕侀噸鎺掔敾甯冨氨寰楄 device 鍊肩湡鐨勫彉鍖栥��
+4. **`Device.widthMedia` 涓� `null` 浼氬洖閫�鎴� `width`**锛屼粠鑰屾妸鏍峰紡鍐欒繘 `@media (max-width: Npx)`锛涙ā鏉跨被鐢诲竷搴旀樉寮忎紶 `''`銆�
+5. **Ant `Spin` 浼氭彃鍏� `.ant-spin-container` 鎵撴柇 `height:100%` 閾�**銆備换浣曘�孲pin 鍖呰9 + 鍐呴儴 flex 鎾戞弧 + 鍐呴儴鍐� overflow:auto銆嶇殑甯冨眬閮借琛� `:deep(.ant-spin-container){height:100%}`锛屽惁鍒欏唴閮ㄦ粴鍔ㄦ潯姘歌繙涓嶅嚭鐜般�佸簳閮ㄨ闈欓粯瑁佹帀銆�
+6. **`loadProjectData` 闇�瑕佸甫 `pages` 鐨勯」鐩暟鎹�**锛宍{assets,styles}` 杩欑浼氳杞芥垚绌虹紪杈戝櫒锛岃浇鍏ュ墠蹇呴』鍒ょ┖銆�
+7. 鍚庣瀵�**宸茶蒋鍒犻櫎**鐨勮褰曪紝`get` 鎺ュ彛杩斿洖 `data:null`锛堜笉鏄姤閿欙級锛屽墠绔墍鏈夋寜 id 鍙栬鎯呯殑鍏ュ彛閮借鍏滅┖銆�
+
+### 涓冦�佺幆澧冪姸鎬佷笌閬楃暀鎻愰啋
+
+1. **鍚庣涓嶅湪杩愯**锛�2026-09-18 12:18 涔嬪悗 `48080` 宸叉棤鐩戝惉锛堟棩蹇楀仠鍦� 12:18:37锛屾棤寮傚父鏍堬紝鏄鍋滄鑰岄潪宕╂簝锛夈�傚綋鏃ユ渶鍚庝竴娆°�屼繚瀛樸�嶅洜姝よ繑鍥� **502 Bad Gateway**锛堝墠绔凡鏈夌粺涓�閿欒鎻愮ず锛岄潪闈欓粯澶辫触锛夈��
+ 鍚庣鐢辩敤鎴峰湪 IntelliJ 涓繍琛岋紙`-Dmaven.multiModuleProjectDirectory=.../mom-pro2-after-test`锛夛紝**鍚姩/鍋滄浜ょ敱鐢ㄦ埛鎵嬪姩澶勭悊**銆�
+2. **鑱旇皟閬楃暀鏁版嵁**锛氬綋鏃ヤ负楠岃瘉淇濆瓨閾捐矾锛屽湪**妯℃澘 3锛圦C_IQC_DEMO_COPY锛�**涓婁骇鐢熶簡涓�鏉� `v1.0` 鑽夌鐗堟湰锛坄qc_report_template_version.id=6`锛夆�斺�旇妯℃澘姝ゅ墠鏃犵増鏈紝濡備笉闇�瑕佸彲鐩存帴鍒犻櫎銆�
+3. 鏁版嵁搴擄細`application.yaml` `active: local` 鈫� `application-local.yaml` 鎸囧悜 `jdbc:mysql://localhost:3306/ruoyi-vue-pro`銆�**璇ラ厤缃巻鍙蹭笂婕傜Щ杩囧娆★紝鍔ㄦ墜鍓嶅姟蹇呴噸鏂扮‘璁ゃ��**
+
+### 鍏�佹槑鏃ワ紙2026-09-19锛夊緟鍔炴竻鍗�
+
+> 璇ユ竻鍗曞凡褰撳満鎵ц瀹屾瘯锛屽疄鏂戒笌楠岃瘉璁板綍瑙佷笅涓�鑺傘�孭hase 2 瀹炴柦璁板綍銆嶃��
+
+1. **Phase 2 璧锋锛歈uality Components 娉ㄥ唽鏈哄埗**
+ - `engine/component` 涓嬬殑 `types / registry / factory / serializer / validator`锛堢嫭绔嬫敞鍐岋紝涓嶈繘 GrapesJS 鍐呮牳锛�
+ - 璁捐鍣ㄧ殑宸︿晶銆岃川閲忕粍浠躲�嶅垎绫绘敼涓轰粠 registry 鍔ㄦ�佺敓鎴愶紝鑰屼笉鏄啓姝诲湪 `blocks.ts`
+2. **璐ㄩ噺缁勪欢鏈綋**锛歈ualityTable / SampleInfo / ReportHeader / InspectionItem / Result 浜旂被锛屾瘡绫诲甫 `qualityType` + 灞炴�� schema銆�
+3. **QualityPropertyPanel**锛氶�変腑璐ㄩ噺缁勪欢鏃讹紝鍙充晶闄� GrapesJS 鏍峰紡闈㈡澘澶栵紝鍐嶆覆鏌撲笟鍔″睘鎬ц〃鍗曘��
+4. **鏁版嵁缁戝畾寮曟搸**锛堢粦瀹氳矾寰勮В鏋� + 鍙栧�硷級锛屼负 Phase 3 娓叉煋鍋氬噯澶囥��
+5. **瑙勫垯寮曟搸**锛氬厛瀹氳〃杈惧紡璇硶涓� AST 姹傚�煎櫒楠ㄦ灦锛�**涓ョ `eval` / `ScriptEngine`**銆�
+6. 鏀跺熬锛氱‘璁ゆ槸鍚︽竻鐞嗘ā鏉� 3 鐨勮仈璋冮仐鐣欑増鏈��
+
+---
+
+## Phase 2 瀹炴柦璁板綍锛�2026-09-18 缁級
+
+> 鐩爣锛氳銆岃川閲忕粍浠躲�嶆垚涓轰竴濂�**鐙珛浜� GrapesJS 鐨勬敞鍐屾満鍒�**锛屽苟鎵撻��
+> `妯℃澘 Schema + 鎶ュ憡涓婁笅鏂� 鈫� HTML` 鐨勬覆鏌撻摼璺紝杈炬垚 Phase 2 楠屾敹鏍囧噯
+> **銆宍inspectionItems` 鑷姩鐢熸垚琛ㄦ牸骞剁畻鍑� PASS/FAIL銆�**銆�
+
+### 涓�銆佷氦浠樼墿
+
+**鍗忚灞傦紙`src/components/quality/core/`锛�** 鈥� 缁勪欢瀹炵幇閲屼笉鍑虹幇浠讳綍 GrapesJS 姒傚康
+
+| 鏂囦欢 | 鑱岃矗 |
+|---|---|
+| `types.ts` | `QualityComponentDefinition` 鍗忚锛歱ropertySchema / dataSchema / buildContent / validate |
+| `registry.ts` | 骞傜瓑娉ㄥ唽琛紝鎸� type 绱㈠紩 |
+| `factory.ts` | 鍗忚 鈫� GrapesJS 浜х墿锛氱粍浠跺潡銆佺敾甯冨唴瀹广�乼raits锛�**鍞竴鐨勬ˉ鎺ュ眰**锛� |
+| `serializer.ts` | 涓氬姟灞炴�� 鈫� `data-qc-*` 灞炴�у線杩� |
+| `validator.ts` | 灞炴�ф敹鏁涗笌鏍¢獙 |
+| `attrs.ts` | `data-quality-type` / `data-qc-*` / `data-qc-repeat(-row)` / `data-qc-id` 甯搁噺 |
+| `html.ts` / `icons.ts` | `cssStyle` / `escapeHtml` / 鍐呰仈 SVG 鍥炬爣 |
+| `lookup.ts` | 鎸夎妭鐐逛笂鐨� `data-quality-type` 鍙嶆煡瀹氫箟 |
+| `canvas-sync.ts` | 鐢诲竷鏂囧瓧 鈫� 涓氬姟灞炴�у弻鍚戝悓姝ワ紱杞藉叆鍚庨噸寤� traits |
+| `trait-binding.ts` | 銆岀粦瀹氭暟鎹�嶈嚜瀹氫箟 trait 鎺т欢锛堜笅鎷夋寫閫� + 鎵嬪伐杈撳叆 + `tip` 鎻愮ず锛� |
+
+**缁勪欢鏈綋锛�12 涓級**
+
+- 鍩虹锛歚Heading` / `Text` / `Image` / `Divider` / `Spacer` / `Table`
+- 鎶ュ憡锛歚ReportHeader` / `ReportFooter` / `SampleInfo`
+- 妫�楠岋細`QualityTable` / `InspectionItem`
+- 缁撴灉锛歚ReportResult`
+
+鏂板涓�涓粍浠讹紳鍦� `index.ts` 鐨� `BUILT_IN_DEFINITIONS` 閲屽姞涓�琛岋紝**涓嶆敼璁捐鍣ㄩ〉闈€�佷笉鏀� GrapesJS 闆嗘垚浠g爜**銆�
+
+**寮曟搸灞傦紙`src/components/quality/engine/`锛�**
+
+| 鏂囦欢 | 鑱岃矗 |
+|---|---|
+| `path.ts` | 缁戝畾璺緞瑙f瀽锛坄a.b.c`锛変笌鏁板�艰浆鎹� |
+| `binding.ts` | `{{path}}` 鏂囨湰瑙f瀽锛岀己鍊艰蛋鍥炶皟涓婃姤鑰屼笉鏄潤榛樺悶鎺� |
+| `context.ts` | 鎶ュ憡涓婁笅鏂囨ā鍨� + `PASS`/`FAIL`/`寰呭垽瀹歚 甯搁噺 |
+| `rule-engine.ts` | **鑷缓璇嶆硶/AST 瑙f瀽涓庣櫧鍚嶅崟姹傚�硷紝鏃� `eval`銆佹棤 `ScriptEngine`** |
+| `report-evaluator.ts` | 閫愰」鍒ゅ畾锛坕tem 瑙勫垯 鈫� 瑙勬牸涓婁笅闄� 鈫� 鏁版嵁鑷甫缁撴灉锛変笌鎶ュ憡姹囨�� |
+| `page.ts` | A3/A4/A5/Letter 绾稿紶涓庨〉杈硅窛鎹㈢畻锛坢m锛� |
+| `render.ts` | GrapesJS 椤圭洰鏁版嵁 鈫� HTML 鏂囨。锛堝惈 `@page` 涓庢牱寮忛�夋嫨鍣ㄦ敼鍐欙級 |
+
+璁捐鍣ㄤ晶鐨勬帴绾匡細宸︿晶缁勪欢闈㈡澘鏀圭敱 registry 鍔ㄦ�佺敓鎴愶紱`registerBindingTraitType()` 娉ㄥ唽缁戝畾鎺т欢锛�
+`loadSchema` 杞藉叆鍚庤皟鐢� `restoreQualityTraits()` 閲嶅缓灞炴�ч潰鏉垮瓧娈点��
+
+### 浜屻�丳hase 2 楠屾敹锛氭祻瑙堝櫒瀹炴祴缁撴灉
+
+鐢�**鍚庣鐪熷疄淇濆瓨鐨� Schema**锛堟ā鏉� 3 鑽夌 `qc_report_template_version.id=6`锛夐厤涓�浠� 3 琛屾楠屾暟鎹紝
+鍦ㄩ〉闈㈠唴鐩存帴璋冪敤 `renderReport({ schema, context })`锛�
+
+| 楠岃瘉椤� | 缁撴灉 |
+|---|---|
+| 妫�楠岄」琛ㄦ牸鎸� `inspectionItems` 鑷姩鐢熸垚琛� | 鉁� `tbody` 灞曞紑 3 琛岋紙澶栬 / 闀垮害 / 鐩村緞锛夛紝鍏ㄦ枃妗� 3 琛� / 10 `tr` / 42 `td` / 6 `th` |
+| PASS/FAIL 鍒ゅ畾 | 鉁� 鏈夎鏍间笂涓嬮檺鏃� 1 鍚堟牸 / 1 涓嶅悎鏍硷紝`result=FAIL`銆乣passRate=50.00%` |
+| 鍏ㄩ儴鍚堟牸 | 鉁� `result=PASS`銆乣passRate=100.00%`銆佺粨璁恒�屽悎鏍笺�� |
+| 绾稿紶涓庨〉杈硅窛 | 鉁� 浜у嚭 `@page { size: 210mm 297mm; margin: 10mm 10mm 10mm 10mm; }` |
+| 缁戝畾鍏ㄩ儴瑙f瀽 | 鉁� 浜х墿鏃犳畫鐣� `{{}}` |
+| 缁勪欢 id 涓嶅啀娉勬紡鎴� DOM `id` | 鉁� 鏀瑰啓涓� `data-qc-id`锛岄噸澶嶈涓嶄細鎾� id |
+| 鏁版嵁缂哄彛鏄惧紡鏆撮湶 | 鉁� 濡傘�岀 1 椤广�屽瑙傘�嶆病鏈夎鏍间笂涓嬮檺涔熸病鏈夊垽瀹氳鍒欙紝鏃犳硶鍒ゅ畾銆嶈繘 `errors`锛屼笉闈欓粯 |
+| 銆岀粦瀹氭暟鎹�嶆帶浠讹紙text 妯″紡锛� | 鉁� 鎸戦�夈�屽垽瀹氱粨璁恒�嶅啓鍏� `{{report.conclusion}}`锛涙墜宸ヨ緭鍏ャ�屽悎鏍笺�嶆椂涓嬫媺鍥炶惤銆屼笉缁戝畾銆� |
+| 銆岀粦瀹氭暟鎹�嶆帶浠讹紙path 妯″紡锛� | 鉁� 鎸戦�夈�屾楠岄」鐩垪琛ㄣ�嶅啓鍏ヨ8 `inspectionItems`锛堜笉鍔� `{{}}`锛� |
+| 琛屽簭鍙� | 鉁� `{{index}}` 娓叉煋鍑� 1銆�2鈥� |
+| 鍓嶇绫诲瀷妫�鏌� | 鉁� `pnpm typecheck` 鍦ㄦ湰妯″潡鏂版敼鏂囦欢涓� **0 error**锛堜粨搴撳叾浣� 316 鏉′负鏃㈡湁闂锛岄潪鏈寮曞叆锛� |
+
+### 涓夈�佹湰闃舵瀹氫綅骞朵慨澶嶇殑闂
+
+| # | 鐜拌薄 | 鏍瑰洜 | 淇 |
+|---|---|---|---|
+| 1 | **淇濆瓨鍚庨噸寮�妯℃澘锛屽彸渚т笟鍔″睘鎬ч潰鏉垮叏绌�**锛岀粍浠跺彧鍓� Id/Title | traits **涓嶅弬涓�** GrapesJS 椤圭洰鏁版嵁搴忓垪鍖栵紱涓旀瘡涓粍浠堕兘鑷甫 `id`/`title` 涓や釜榛樿 trait锛屽鑷淬�屽凡鏈� trait 灏辫烦杩囬噸寤恒�嶇殑鍒ょ┖鎭掍负鐪� | `restoreQualityTraits()` 鎸� `data-quality-type` 浠庢敞鍐岃〃**鏃犳潯浠堕噸寤�** traits銆傚睘鎬у�间粛浼樺厛璇� `data-qc-*`锛屼笉浼氭妸鐢ㄦ埛鏀硅繃鐨勫�煎啿鍥為粯璁� |
+| 2 | 鐐瑰嚮宸︿晶缁勪欢鍧楋紝鏂扮粍浠惰**濉炶繘褰撳墠閫変腑缁勪欢鍐呴儴**锛屽苟椤舵帀瀹冨師鏈夌殑鏂囨湰 | `BlockView.handleClick` 浼樺厛 `append` 杩� `editor.getSelected()` | 姣忎釜 block 鑷畾涔� `onClick`锛岀粺涓�杩藉姞鍒� `editor.getWrapper()`锛涙嫋鎷戒粛鍙簿纭惤鐐� |
+| 3 | 鏁村紶琛ㄦ牸娓叉煋鎴愪竴鍫� `div` | 椤圭洰鏁版嵁鍦� `tagName` 绛変簬缁勪欢绫诲瀷榛樿鍊兼椂涓嶅啓 `tagName`锛宍table/thead/tbody/row/cell` 鍙暀 `type` | `render.ts` 澧炲姞 `TYPE_TAGS` 鏄犲皠鎸� `type` 鎺ㄦ爣绛� |
+| 4 | 娓叉煋浜х墿涓庤璁″櫒鎵�瑙佷笉涓�鑷� | GrapesJS `__innerHTML` 鏄� `!cmps.length ? content : cmps.map(...)`锛�**瀛愮粍浠朵紭鍏堜簬 content** | `renderChildren` 鍚岃鍒欙細鏈夊瓙缁勪欢灏卞拷鐣� `content` |
+| 5 | 搴忓彿鍒楁案杩滅┖鐧� | 閲嶅瀹瑰櫒鎶婅鍙锋敞鍏ュ埌浣滅敤鍩�**椤跺眰** `index`锛岀粍浠堕噷鍗村啓鐨勬槸 `{{item.index}}` | 琛ㄨ揪寮忔敼 `{{index}}`锛涘苟鎶娿�岃搴忓彿銆嶇櫥璁拌繘 `dataSchema`锛岀粦瀹氫笅鎷夐噷鑳介�夊埌 |
+| 6 | **銆岀粨璁猴細鍚堟牸銆嶄笌銆屽悎鏍肩巼 0.00%銆嶅悓鏃跺嚭鐜�** | 鎶ュ憡绾у垽瀹氬啓鎴� `failCount === 0 ? PASS : FAIL`锛屽叏閮ㄥ緟鍒ゅ畾鏃� `failCount=0` 琚垽鎴愬悎鏍� | 鍙湁 `passCount === total` 鎵嶇粰鍚堟牸缁撹锛涘瓨鍦ㄥ緟鍒ゅ畾椤规椂涓嶄笅缁撹锛堟病楠岃繃涓嶈兘璇村悎鏍硷紝娌¤瘉鎹篃涓嶈兘璇翠笉鍚堟牸锛� |
+| 7 | 銆岀粦瀹氭暟鎹�嶆帶浠剁粰**璺緞鍨�**瀛楁鍖呬笂 `{{}}`锛屾覆鏌撴湡灏辨壘涓嶅埌鏁扮粍 | 鍗忚閲屾病鍖哄垎銆屾枃鏈粦瀹氥�嶄笌銆岃矾寰勭粦瀹氥�� | `QualityFieldSchema` 鏂板 `bindAs: 'path' \| 'text'`锛堥粯璁� `text`锛夛紱`QualityTable` 鐨勩�屾楠岄」鏁版嵁婧愩�嶅0鏄庝负 `path` |
+
+### 鍥涖�佸悗缁墿灞曢渶姹傦紙2026-09-18 涓庣敤鎴风‘璁ゅ彛寰勶級
+
+鐢ㄦ埛鎻愬嚭鍚庣画瑕佸姞 **AI + OCR 璇嗗埆鏂囦欢鑷姩鐢熸垚妯℃澘**銆傚凡纭涓ょ偣鍙e緞锛�
+
+1. **杈撳叆鏂囦欢涓夌被閮借**锛氭壂鎻忎欢/鐓х墖銆佺數瀛愮増 PDF銆乄ord/Excel 妯℃澘銆�
+ 鈫� 杈撳叆渚у繀椤诲仛鎴�**鍙彃鎷旈�傞厤鍣�**锛岀粺涓�浜у嚭銆屼腑闂存枃妗g粨鏋勩�嶅啀浜� AI銆�
+ 锛圥DF 璧� PDFBox銆乄ord/Excel 璧� POI / FastExcel锛岄」鐩潎宸叉湁锛涙壂鎻忎欢闇� OCR + 鐗堥潰鍒嗘瀽锛孞ava 鏃犵幇鎴愭柟妗堬紝鍊惧悜鎺ヤ簯绔〃鏍艰瘑鍒� API銆傦級
+2. **AI 浜у嚭鍙綔鑽夌**锛屼汉宸ュ湪璁捐鍣ㄧ‘璁ゅ悗鎵嶄繚瀛樹负姝e紡鐗堟湰銆�
+
+**杩欎袱鐐瑰彛寰勫鏋舵瀯鐨勫奖鍝嶏紙閲嶈锛夛細**
+
+鍥犱负鑽夌涓嶉渶瑕佺珛鍒诲彲娓叉煋锛�**銆岃涔� 鈫� 鐢诲竷 JSON銆嶇殑缂栬瘧鍙互鏀惧湪鍓嶇**锛�
+AI 鍑鸿涔夎崏绋� 鈫� 鐢ㄦ埛鍦ㄨ璁″櫒鎵撳紑 鈫� 鍓嶇鐢ㄧ幇鎴愮殑 TS 缁勪欢瀹氫箟锛坄factory.buildContent`锛夌紪璇戞垚鐢诲竷 鈫�
+鐢ㄦ埛纭淇濆瓨鏃舵墠钀� `grapes`銆�**鏈嶅姟绔洜姝や笉闇�瑕佺粍浠剁煡璇�**锛孞ava 娓叉煋寮曟搸缁х画鍙 `grapes`銆佺户缁粍浠舵棤鍏筹紝
+涓嶅瓨鍦ㄣ��12 涓粍浠跺湪 TS/Java 鍚勫啓涓�浠姐�嶇殑婕傜Щ椋庨櫓銆�
+
+**蹇呴』鍐欒繘濂戠害鐨勭害鏉燂細** 璇箟灞傛槸**鏈夋剰鐨勫瓙闆�**鈥斺�斿彧琛ㄨ揪銆岀敤娉ㄥ唽缁勪欢鎼嚭鏉ョ殑鎵佸钩缁撴瀯銆嶏紝
+涓嶈〃杈句换鎰� HTML锛堢敤鎴锋墜宸ユ嫋鍏ョ殑瑁歌〃鏍笺�佽嚜瀹氫箟 div 涓嶅湪鍏跺唴锛夈�侫I 鍙兘鐢ㄥ凡娉ㄥ唽鐨勭粍浠朵綔涓虹Н鏈ㄣ��
+杩欐槸鏈夋剰鏀剁獎鐨勮竟鐣岋紝涓嶆槸瀹炵幇鐤忔紡銆�
+
+**瑕佸仛鐨勪簨锛�**
+- 鎶� `ReportTemplateSchema.components` 浠庛�宍collectSchema` 椤烘墜濉�佹覆鏌撲笉璇汇�嶇殑**姝绘暟鎹ˉ鎴愭寮忓绾�**锛�
+ 杩� `dataSources` / `bindings` 涓�璧峰畾涔夋竻妤氾紝骞跺喕缁撹繘 `schemaVersion`銆�
+- 璇ュ绾﹀悓鏃朵篃鏄�**缁� LLM 鐨勭Н鏈ㄦ竻鍗�**锛堣璁″櫒缁勪欢闈㈡澘銆佸墠绔紪璇戙�丄I 鎻愮ず涓夊澶嶇敤鍚屼竴浠芥潵婧愶級銆�
+
+### 浜斻�佺暀缁欎笅涓�姝ョ殑鎻愰啋
+
+1. **Phase 3 鏈変竴涓緟鎷嶆澘鐨勬灦鏋勫垎鍙�**锛氭覆鏌撳紩鎿庣洰鍓嶆槸 **TS**锛岃窇鍦ㄦ祻瑙堝櫒閲屻�傚悗绔� Playwright 鎵撳嵃 PDF 闇�瑕� HTML鈥斺��
+ (A) 鍓嶇娓叉煋 HTML 鈫� POST 缁欏悗绔紝鍚庣鍋� **Sanitization** 鍐嶇敤 Playwright/Chromium 鎵撳嵃锛�
+ (B) 鎶婃覆鏌撳紩鎿庣Щ妞嶆垚 Java锛屾湇鍔$鍏ㄩ摼璺嚜鎸併��
+ 鏂规璁捐鏂囨。鐨勯闄╂竻鍗曡姹傘�屾ā鏉� HTML 灞炵敤鎴峰彲缂栬緫鍐呭 鈫� **蹇呴』鏈嶅姟绔� Sanitization**銆嶏紝涓ゆ潯璺兘鑳芥弧瓒筹紝浣嗘姇鍏ュ樊鍒緢澶с��
+2. **妯℃澘 3锛圦C_IQC_DEMO_COPY锛夌殑鑽夌鐗堟湰 `id=6` 鏄仈璋冮仐鐣欐暟鎹�**锛岄噷闈㈡槸娴嬭瘯缁勪欢锛堜笖鍚竴澶勬棭鏈熴�岀粍浠惰濉炶繘鏍囬銆嶇殑鐥曡抗锛夛紝寤鸿鐩存帴鍒犻櫎銆�
+3. **MySQL MCP 褰撳墠鎸囧悜娌欑洅瀹炰緥**锛坄product-inventory-management-jcck`銆丮ySQL 8.0.32锛夛紝**涓嶅惈鏈」鐩换浣曞簱**銆�
+ 鏈樁娈垫牳瀵圭湡瀹炴暟鎹蛋鐨勬槸椤甸潰鍐� `requestClient` / 鍚庣鎺ュ彛锛屼笉鏄� MCP銆�
+4. 鍓嶇**鏃犳祴璇曟鏋�**锛屾湰闃舵鐨勯獙璇佹柟寮忔槸銆屾祻瑙堝櫒鍐� `await import('#/components/quality/index.ts')` 鐩存帴璋冪函鍑芥暟 + Playwright 鎿嶄綔鐪熷疄璁捐鍣ㄣ�嶃��
+ Phase 5 鑻ヨ琛ヨ嚜鍔ㄥ寲娴嬭瘯锛岄渶瑕佸厛寮曞叆娴嬭瘯杩愯鍣ㄣ��
+---
+
+## Phase 3 瀹炴柦璁板綍锛�2026-09-18 缁級
+
+> 鐩爣锛氳**鏈嶅姟绔嚜鎸佸嚭浠堕摼璺�**鈥斺�擿Schema + 涓婁笅鏂� 鈫� HTML 鈫� PDF`锛�
+> 涓嶄緷璧栨祻瑙堝櫒銆佷笉渚濊禆鍓嶇鍦ㄨ窇锛屾壒閲忓嚭浠朵笌瀹氭椂浠诲姟鎵嶈兘璧板悓涓�涓叆鍙c��
+
+### 涓�銆佹灦鏋勫垎鍙夌殑缁撹锛氶�� B锛堟妸寮曟搸绉绘鎴� Java锛�
+
+绗竴浠借繘搴﹂噷鐣欑殑闂锛圓锛氬墠绔覆鏌� HTML 鍥炰紶鍚庣鎵撳嵃 / B锛氱Щ妞嶆垚 Java锛夊凡鎷嶆澘璧� **B**銆�
+
+| 缁村害 | A锛堝墠绔覆鏌� + 鍥炰紶锛� | B锛圝ava 寮曟搸锛� |
+|---|---|---|
+| 鎬ц兘 | 鍑轰欢瑕佷箞鍗犵敤鎴锋祻瑙堝櫒锛岃涔堣捣鏃犲ご娴忚鍣紱鎵归噺鍑轰欢瑕佹帓闃熺瓑娴忚鍣ㄥ疄渚� | 绾唴瀛樿绠楋紝鏃犳祻瑙堝櫒寮�閿�锛汸DF 闃舵鎵嶉渶瑕� Chromium锛屼笖鍙鐢ㄥ疄渚� |
+| 鎵╁睍鎬� | 鍓嶇涓�鏀规覆鏌撻�昏緫锛屽巻鍙叉姤鍛婇噸鍑虹粨鏋滃氨鍙� | 寮曟搸鏃犵姸鎬併�佺粍浠舵棤鍏筹紝鎺ュ叾瀹冩ā鍧� / 瀹氭椂浠诲姟 / 娑堟伅娑堣垂閮戒笉鏀逛唬鐮� |
+| 鍙淮鎶ゆ�� | 娓叉煋閫昏緫鏁e湪娴忚鍣ㄧ锛屾帓鏌ヨ寮� DevTools | 鏈嶅姟绔彲鏂偣銆佸彲鍗曟祴銆佸彲鎵撴棩蹇楋紝鍑轰欢闂鐩存帴瀹氫綅 |
+| 鍙敤鎬� | 鍓嶇涓嶅湪绾垮氨鍑轰笉浜嗕欢 | 涓庡墠绔В鑰︼紝鎺ュ彛/浠诲姟閮借兘鍑轰欢 |
+
+**B 鐨勫敮涓�鐪熷疄椋庨櫓鏄�屼袱濂楀紩鎿庢紓绉汇��**锛堥瑙堢敤 TS銆佸嚭浠剁敤 Java锛屼笉涓�鑷村氨鏄�岄瑙堜笌鍑轰欢涓嶇銆嶏級銆�
+鎵�浠ユ湰闃舵涓嶆槸鍗曠函绉绘锛岃�屾槸**杩炲甫鍋氫簡涓�濂楀鎷嶆満鍒�**鈥斺�旇绗笁鑺傦紝杩欐槸 B 鑳芥垚绔嬬殑鍓嶆彁锛屼笉鏄檮鍔犻」銆�
+
+### 浜屻�佷氦浠樼墿
+
+**Java 寮曟搸锛坄yudao-module-qcreport/src/main/java/.../engine/`锛�24 涓枃浠讹級**
+
+| 鍖� | 鏂囦欢 | 鑱岃矗 |
+|---|---|---|
+| `engine/` | `QualityReportEngine` | 闂ㄩ潰锛歚render` / `rulesOf` / `pageOf` / `grapesOf` / `validateRules` |
+| | `Paths` `Numbers` `JsValues` `Bindings` | 璺緞鍙栧�笺�乣String(value)` 璇箟銆乣{{path}}` 缁戝畾瑙f瀽 |
+| | `QualityResult` | PASS/FAIL + `寰呭垽瀹歚 |
+| | `PageSetting` `PageMargin` `ResolvedPage` `PageSizes` | 绾稿紶/椤佃竟璺濇崲绠椾笌 `@page` 杈撳嚭 |
+| `engine/context/` | `ReportContext` `ReportFields` `InspectionItem` | 鎶ュ憡涓婁笅鏂囨ā鍨嬶紙瀛楁鍚嶄笌 TS 渚т竴鑷达級 |
+| `engine/rule/` | `RuleEngine` `RuleParser` `RuleEvaluator` `RuleNode` `RuleToken` `TokenType` | **鑷缓璇嶆硶/AST + 鐧藉悕鍗曞嚱鏁�**锛屾棤 `eval`銆佹棤 `ScriptEngine` |
+| | `QualityRuleDefinition` `RuleScope` | 瑙勫垯瀹氫箟涓庝綔鐢ㄥ煙 |
+| | `RuleSyntaxException` `RuleRuntimeException` | 璇硶閿欒锛堝甫浣嶇疆锛変笌姹傚�奸敊璇� |
+| `engine/report/` | `ReportEvaluator` `EvaluationOutcome` | 閫愰」鍒ゅ畾涓庢姤鍛婃眹鎬� |
+| `engine/render/` | `HtmlRenderer` `RenderNode` `RenderOutcome` | Schema 鈫� HTML 鏂囨。锛堝惈 `@page`銆佹牱寮忛�夋嫨鍣ㄦ敼鍐欙級 |
+
+寮曟搸**涓嶄緷璧� Spring銆佷笉钀藉簱銆佷笉鍋氭潈闄�**鈥斺�斿彧鍚冦�孲chema + 涓婁笅鏂囥�嶅悙 HTML锛�
+杩欐牱鎵归噺鐢熸垚銆佸畾鏃朵换鍔°�佸叾瀹冩ā鍧楄皟鐢ㄩ兘璧板悓涓�涓叆鍙c��
+
+**瀵规媿鏈哄埗锛堟湰闃舵鐨勬牳蹇冧骇鍑轰箣涓�锛�**
+
+| 浣嶇疆 | 浣滅敤 |
+|---|---|
+| `src/test/resources/qcreport/schema.json` `context.json` | 鍚屼竴浠借緭鍏� fixture |
+| `src/test/resources/qcreport/expected-html.html` `expected-rules.json` | **鍓嶇寮曟搸**璺戝嚭鏉ョ殑鏈熸湜浜х墿锛堝喕缁擄級 |
+| `mom-pro2-before/.qc-conformance/render-ts.ts` | 鐢ㄥ墠绔紩鎿庨噸绠楁湡鏈涗骇鐗╃殑鑴氭湰锛堟敼鍔ㄤ换涓�渚у紩鎿庡悗閲嶈窇锛� |
+| `FrontendConformanceTest` | 鍚庣寮曟搸璺戝悓涓� fixture锛岄�愬瓧姣斿 HTML / 缂哄彛娓呭崟 / 41 鏉¤〃杈惧紡 |
+| `ReportEvaluatorTest` | 鍒ゅ畾璇箟涓庢眰鍊煎仴澹�э紙19 涓敤渚嬶級 |
+
+閲嶇畻鏈熸湜浜х墿鐨勫懡浠わ紙鍦� `mom-pro2-before` 涓嬶級锛�
+
+```powershell
+./node_modules/.bin/tsx .qc-conformance/render-ts.ts ../yudao-module-qcreport/src/test/resources/qcreport ../yudao-module-qcreport/src/test/resources/qcreport
+```
+
+### 涓夈�佸鎷嶈鐩栦簡浠�涔�
+
+`FrontendConformanceTest` 涓夐」鏂█锛�**鍏ㄧ豢**锛�
+
+| 鐢ㄤ緥 | 姣斿鍐呭 |
+|---|---|
+| 娓叉煋浜х墿閫愬瓧涓�鑷� | HTML 鍏ㄦ枃锛堝惈 `@page`銆乣data-qc-id` 鏀瑰啓銆侀噸澶嶈灞曞紑銆佽浆涔夛級锛� 鏁版嵁缂哄彛娓呭崟 |
+| 鍒ゅ畾缁撴灉涓�鑷� | 缁撹 OK/涓嶅悎鏍笺�乼otal/passCount/failCount/passRate銆侀�愰」 PASS/FAIL |
+| 瑙勫垯姹傚�间竴鑷� | **41 鏉¤〃杈惧紡**鐨勭被鍨嬩笌鏂囨湰锛屾垨鎶ラ敊鏂囨閫愬瓧鐩稿悓 |
+
+41 鏉¤〃杈惧紡瑕嗙洊锛氬瓧绗︿覆/鏁板��/甯冨皵姣旇緝銆乣IN` / `NOT IN` / `BETWEEN` / `NOT BETWEEN`銆�
+`AND` / `OR` / `!` / 涓�鍏冭礋鍙枫�佺畻鏈笌闄ら浂銆佹枃鏈嫾鎺ャ�乣NULL` 姣旇緝銆�
+12 涓櫧鍚嶅崟鍑芥暟鐨勬甯稿�硷紙鍚� `STDDEV` / `CP` / `CPK` 鐨勬诞鐐规枃鏈級銆�
+缂哄弬 / 绫诲瀷涓嶇 / 鏈煡鍑芥暟 / 璇硶娈嬬己鐨勬姤閿欐枃妗堛�佷互鍙�**鐪熷�煎彛寰�**銆�
+
+绉绘杩囩▼涓湡姝d細鍜汉鐨勬槸 **JS 涓� Java 鐨勫彇鍊�/鏍煎紡鍖栧樊寮�**锛岄�愭潯澶勭悊杩囷細
+
+| 闄烽槺 | 澶勭悊 |
+|---|---|
+| `String(60)` 鈫� `"60"`锛孞ava `String.valueOf(60.0D)` 鈫� `"60.0"` | `Numbers.toString` 鎶婃暣鏁板�兼诞鐐规暟鏀舵垚鏁存暟 |
+| 鏁扮粍 `String()`锛欽S `"1,2"`锛孞ava `"[1, 2]"` | `JsValues.asText` 瀵� List 閫愬厓绱犳嫾鎺� |
+| 绉戝璁℃暟娉曢槇鍊间笉鍚岋紙JS <-6 鎴� 鈮�21锛孞ava <-3 鎴� 鈮�7锛� | 缁熶竴璧� `Numbers.toString` |
+| `toUpperCase()` 鍙� locale 褰卞搷锛堝湡鑰冲叾璇� i 鈫� 陌锛� | 鍒ゅ畾鍙栧�煎綊涓�鍖栫敤 `Locale.ROOT` |
+| `Map.copyOf` 涓嶄繚璇侀亶鍘嗛『搴忥紝浼氳鎶ラ敊閲岀殑鍙敤鍑芥暟闅忔満鎺� | 鐢� `Collections.unmodifiableMap` 淇濅綇 LinkedHashMap 椤哄簭 |
+| `Map.of(...).get(null)` 鎶� NPE | 绫诲瀷鏄犲皠鍏堝垽绌哄啀鏌ヨ〃 |
+| **鐪熷�煎彛寰�**锛氳兘褰撴暟瀛楃湅鐨勫彇鍊间竴寰嬫寜 `!== 0` 鍒ょ湡 | 鎵�浠� `"0"` 鏄�**鍋囧��**锛岃�屽師鐢� JS `Boolean("0")` 鏄湡鍊硷紱绌烘暟缁勪篃鏄亣鍊笺�傚悗绔収鎼墠绔紝鏀瑰姩鍓嶅繀椤诲厛鏀瑰墠绔� |
+
+### 鍥涖�佽繙瓒呭墠绔紩鎿庣殑涓�澶勫畨鍏ㄥ姞鍥�
+
+`HtmlRenderer` 鍦ㄥ睘鎬ц緭鍑哄墠鍔犱簡涓�閬撻椄锛�**杩欐槸鏈夋剰鍋忕 TS 鐗�**锛�
+
+- **浜嬩欢灞炴��**锛坄on*`锛変竴寰嬩笉杈撳嚭鈥斺�旀ā鏉块噷濉� `onclick` 涓嶈鍑虹幇鍦ㄥ嚭浠朵骇鐗╅噷锛�
+- **鍗遍櫓鍗忚 URL**锛坄javascript:` / `vbscript:` / `data:`锛宍data:image/` 闄ゅ锛変竴寰嬩笉杈撳嚭銆�
+
+琚嫤涓嬬殑灞炴��**鍐欒繘闂娓呭崟**锛堝銆屾ā鏉垮睘鎬с�宱nclick銆嶆槸浜嬩欢灞炴�э紝鎶ュ憡浜х墿涓嶈緭鍑猴紝宸插拷鐣ャ�嶏級锛�
+璁╂ā鏉夸綔鑰呯湅寰楄锛岃�屼笉鏄倓鎮勫皯涓睘鎬с�俆S 鐗堟病鏈夎繖閬撻椄锛屾墍浠ヨ繖鏉�**涓嶅湪瀵规媿鑼冨洿鍐�**锛岄潬 `ReportEvaluatorTest` 涔嬪鐨勫崟娴嬪畧銆�
+
+鍙﹂渶璇存槑锛�**鍏ョ珯 HTML 鐨� Sanitization 浠嶅綊鍑轰欢鎺ュ彛璐熻矗**锛圥hase 3 绗� 4 姝ワ級锛�
+娓叉煋寮曟搸鐨勮繖閬撻椄鍙銆岀粍浠跺睘鎬� 鈫� 浜х墿灞炴�с�嶈繖涓�灞傦紝涓よ�呬笉閲嶅彔銆�
+
+### 浜斻�佸垽瀹氳涔夛細涓�涓湡瀹炵己闄疯娴嬭瘯閽変綇浜�
+
+Phase 2 淇繃鐨勭己闄凤紙銆岀粨璁哄悎鏍� + 鍚堟牸鐜� 0%銆嶈嚜鐩哥煕鐩撅級鐜板湪鏈夊洖褰掔敤渚嬪畧鐫�锛�
+涓夐」閲屼袱椤瑰悎鏍笺�佷竴椤瑰緟鍒ゅ畾 鈫� **涓嶇粰鍚堟牸缁撹**锛堢粨璁轰负銆屽緟鍒ゅ畾銆嶏級锛屽悎鏍肩巼鐓х畻 66.67%銆�
+`ReportEvaluatorTest` 鍙︽湁瑕嗙洊锛氬崟渚ц鏍笺�佽鍒欎紭鍏堜簬涓婁笅闄愩�佹暟鎹嚜甯︾粨鏋滃厹搴曘��
+瑙勫垯璺戜笉閫氭椂涓嶇粰缁撹銆佸仠鐢ㄨ鍒欏拷鐣ャ�佹姤鍛婄骇瑙勫垯浼樺厛浜庢眹鎬汇�佺┖鎶ュ憡涓嶇粰缁撹銆�
+**鍒ゅ畾涓嶄慨鏀逛紶鍏ヤ笂涓嬫枃**銆佸嚱鏁扮己鍙傛姤鍙閿欒锛堜笉鏄� `IndexOutOfBoundsException` 绌块�忔垚銆岀郴缁熷紓甯搞�嶏級銆�
+
+### 鍏�侀獙鏀�
+
+```
+Tests run: 29, Failures: 0, Errors: 0, Skipped: 0
+```
+
+- `FrontendConformanceTest`锛�3/3 閫氳繃锛圚TML 鍏ㄦ枃閫愬瓧涓�鑷淬��41 鏉¤〃杈惧紡涓�鑷达級
+- `ReportEvaluatorTest`锛�23/23 閫氳繃锛堝垽瀹氳涔� + 瑙勫垯姹傚�煎仴澹�� + 淇濆瓨鍓嶆牎楠岋級
+- `ReportTemplateSchemaCompatibilityTest`锛�3/3 閫氳繃锛堣蛋鐢熶骇鍚屾 `Jackson3TypeHandler` 璇绘棫 JSON锛�
+- 缂栬瘧锛歚mvn compile -pl yudao-module-qcreport -am -q -o` 閫氳繃
+
+杩愯鍛戒护锛�
+
+```powershell
+mvn test -pl yudao-module-qcreport -am -q -o -Dtest='FrontendConformanceTest,ReportEvaluatorTest,ReportTemplateSchemaCompatibilityTest' -Dsurefire.failIfNoSpecifiedTests=false
+```
+
+### 涓冦�佽繘琛屼腑 / 鏈畬鎴愰」
+
+| # | 浜嬮」 | 鐘舵�� |
+|---|---|---|
+| 1 | 寮曟搸绉绘锛堟覆鏌� + 瑙勫垯 + 鍒ゅ畾锛� | 鉁� 瀹屾垚骞堕�氳繃瀵规媿 |
+| 2 | 鍐荤粨 Schema 璇箟灞傚绾︼紙濂戠害 1.1锛� | 鉁� 瀹屾垚锛岃绗節鑺� |
+| 2b | 淇璁捐鍣ㄤ繚瀛樻竻绌哄垽瀹氳鍒欙紙鏁版嵁涓㈠け锛� | 鉁� 瀹屾垚锛岃绗節鑺� |
+| 2c | 瑙勫垯缂栬緫鐣岄潰 + 淇濆瓨鍓嶆牎楠岄椄鍙� | 鉁� 瀹屾垚骞舵祻瑙堝櫒瀹炴祴锛岃绗崄鑺� |
+| 3 | **寮曞叆 Playwright + 涓嬭浇 Chromium** | 猬� 鏈紑濮嬶紝**闇�瑕佺敤鎴烽噸鍚悗绔�** |
+| 4 | 鍑轰欢鎺ュ彛 + `data_snapshot` + HTML/PDF 褰掓。锛堝惈鍏ョ珯 HTML Sanitization锛� | 猬� 鏈紑濮� |
+| 5 | Phase 4锛堝疄渚�/鐗堟湰/鏉冮檺/鏃ュ織锛夈�丳hase 5锛堣嚜鍔ㄥ寲 + E2E锛� | 猬� 鏈紑濮� |
+| 6 | AI + OCR 璇嗗埆鏂囦欢鐢熸垚妯℃澘鑽夌 | 猬� 鏈紑濮嬶紙鍙e緞宸茬‘璁わ紝瑙� Phase 2 绗洓鑺傦級 |
+
+### 涔濄�丼chema 濂戠害鍐荤粨 1.1 + 瑙勫垯鏁版嵁涓㈠け淇锛�2026-09-18 缁級
+
+绗� 2 姝ュ師鏈互涓哄彧鏄�"琛ュ瓧娈�"锛屽疄闄呮帓鏌ュ嚭**涓変釜鐪熷疄缂洪櫡**锛屼竴骞跺鐞嗕簡銆�
+
+#### 9.1 缂洪櫡涓�锛氫繚瀛樹竴娆¤璁″櫒灏辨妸宸叉湁鍒ゅ畾瑙勫垯鎶规帀锛堥潤榛樻暟鎹涪澶憋級
+
+`use-designer.ts` 鐨� `collectSchema` 閲岀‖缂栫爜 `rules: []`锛岃�屽悗绔� `updateVersion` 鏄�
+`BeanUtils.toBean(updateReqVO, DO.class)` + `updateById`鈥斺��**鏁翠唤 Schema 鏁翠綋瑕嗙洊**銆�
+涓よ�呭彔鍔犵殑缁撴灉锛氬彧瑕佹墦寮�妯℃澘鐐逛竴娆′繚瀛橈紝搴撻噷宸叉湁鐨勮鍒欏氨琚竻绌猴紝
+鑰屼笖娌℃湁浠讳綍鎶ラ敊锛岀敤鎴蜂笉浼氱煡閬撹嚜宸卞紕涓簡浠�涔堛��
+
+淇硶鏄璁捐鍣ㄦ妸"鑷繁涓嶈礋璐g紪杈戠殑瀛楁"鍘熸牱甯﹀洖锛坄use-designer.ts`锛夛細
+
+```ts
+// 杞藉叆鏃剁暀瀛橈紝淇濆瓨鏃跺甫鍥烇紱鍒囧埌绌虹櫧鐗堟湰鏃惰窡鐫�娓呯┖
+let retainedSchema: Pick<QcReportVersionApi.ReportTemplateSchema, 'rules'> = {};
+```
+
+`loadSchema` 閲� `retainedSchema = schema?.rules ? { rules: schema.rules } : {}`锛�
+`collectSchema` 鏈熬 `...retained`銆俙rules` 涓虹┖鏁扮粍鏃舵槸**鐪熷��**锛屾墍浠�
+"鍒囧埌涓�涓� rules:[] 鐨勭増鏈�"浼氭纭甫涓婄┖鏁扮粍鑰屼笉鏄畫鐣欎笂涓�涓増鏈殑瑙勫垯锛�
+`schema` 涓� undefined锛堟病鍐欒繃鍐呭鐨勮崏绋匡級鏃舵竻绌虹暀瀛橈紝涔熶笉浼氫覆鍛炽��
+
+**宸茬敤娴忚鍣ㄥ疄娴�**锛氬啓涓ゆ潯瑙勫垯鍒版ā鏉� 3 鐨勮崏绋跨増鏈� 鈫� 閲嶈浇璁捐鍣� 鈫� 鐐广�屼繚瀛樸�嶁啋
+鍥炶鐗堟湰 Schema锛宍rules` 涓ゆ潯閮藉湪銆傞獙璇佸畬宸叉妸璇ヨ崏绋胯繕鍘燂紙`rules: []`銆乣schemaVersion: "1.0"`锛夈��
+
+#### 9.2 缂洪櫡浜岋細瑙勫垯鏍¢獙鍐欏ソ浜嗕絾娌℃湁浠讳綍璋冪敤鏂�
+
+`QualityReportEngine.validateRules` 鍙湁瀹氫箟娌℃湁璋冪敤锛宍validateSchema` 鍙煡浜�
+`schemaVersion` 闈炵┖銆傝鍒欏啓閿欒鍒板嚭浠舵椂鎵嶇偢锛岀敤鎴风湅鍒扮殑鏄�"鎶ュ憡鍑轰笉鏉�"锛�
+鍗翠笉鐭ラ亾鏄ā鏉块噷鍝潯瑙勫垯鍐欏潖鐨勩�傜幇宸插湪淇濆瓨璺緞涓婃帴閫氾紝閫愭潯鍒楀嚭鏄摢鏉¤鍒欍�侀敊鍦ㄥ摢锛�
+
+```java
+throw new ServiceException(TEMPLATE_VERSION_RULE_INVALID.getCode(),
+ TEMPLATE_VERSION_RULE_INVALID.getMsg() + "锛�" + String.join("锛�", ruleErrors));
+```
+
+閿欒鐮� `1_070_101_006`锛歚妯℃澘閲岀殑鍒ゅ畾瑙勫垯涓嶅悎娉曪紝璇蜂慨鏀瑰悗閲嶈瘯`銆�
+
+**涓�涓湁鎰忕暀涓嬬殑渚嬪**锛歚validateRules` **璺宠繃绌鸿〃杈惧紡鐨勮鍒�**锛屼笉褰撲繚瀛橀敊璇��
+鐞嗙敱鍐欏湪鏂规硶 javadoc 閲屸�斺�旇繖绫婚」鍙彲鑳芥槸鍘嗗彶鑴忔暟鎹紝鑰�**瑙勫垯缂栬緫鐣岄潰杩樹笉瀛樺湪**锛�
+鎶ヤ簡閿欑敤鎴蜂篃鏃犲鍙敼锛屽彧鑳藉崱鍦�"淇濆瓨涓嶄簡"锛岀瓑浜庢妸"涓�鏉″潖鏁版嵁"鍗囩骇鎴�"鏁翠唤妯℃澘涓嶈兘淇濆瓨"銆�
+鎵ц鏈熶粛浼氱収甯告妸瀹冩姤鍑烘潵锛坄绗� N 椤广�孹銆嶇殑瑙勫垯銆孻銆嶆棤娉曟墽琛岋細瑙勫垯琛ㄨ揪寮忎负绌篳锛夊苟鏍囦负寰呭垽瀹氾紝
+涓嶆槸闈欓粯鍚炴帀銆�**瑙勫垯缂栬緫鐣岄潰鍋氬嚭鏉ヤ箣鍚庯紝杩欓噷搴斿綋鏀规垚鏄庣‘鎶ラ敊銆�**
+
+> **宸插厬鐜�**锛氳鍒欑紪杈戠晫闈㈠仛鍑烘潵涔嬪悗锛堣绗崄鑺� 10.1锛夛紝鍚庣杩欓噷鎸変笂闈㈣繖鍙ヨ瘽鏀规垚浜嗘槑纭姤閿欙紝
+> 鍗曟祴 `ReportEvaluatorTest.blankExpressionRuleBlocksSave` 璺熺潃鏀瑰啓鎴�"璇诲緱鍑烘潵銆佷絾闃绘柇淇濆瓨"銆�
+
+#### 9.3 缂洪櫡涓夛細`dataSources` / `bindings` / `styles` 鏄鏁版嵁
+
+涓変釜瀛楁鑷� 1.0 璧峰氨鏄┖鏁扮粍锛屾棦鏃犱汉鍐欏叆涔熸棤浜鸿鍙栵紝绫诲瀷涓婅繕鏄棤濂戠害鐨�
+`Record<string, unknown>[]`銆傚凡浠庡墠鍚庣涓�骞跺垹闄わ紝`schemaVersion` 鍗囧埌 `1.1`銆�
+鍥犳瀛楁鍘熸湰鎭掍负 `[]`锛�**1.1 鏃犻渶鏁版嵁杩佺Щ**銆�
+
+鍚屾椂鎶� `components` 鐢� `Map` 鏀逛负寮虹被鍨� `QualityComponentNode`锛坄id`/`index`/`qualityType`/`attributes`锛夛紝
+骞跺湪 `ReportTemplateSchema` javadoc 閲屽啓鏄�**璇箟灞傛槸鏈夋剰鐨勫瓙闆�**锛�
+鍙〃杈�"鐢ㄥ凡娉ㄥ唽璐ㄩ噺缁勪欢鎼嚭鏉ョ殑鎵佸钩缁撴瀯"锛�**涓嶈〃杈句换鎰� HTML**銆�
+杩欐潯杈圭晫鏄粰 AI 鐢熸垚妯℃澘鐢ㄧ殑绾︽潫鈥斺�旀湁浜嗗畠鎵嶈兘瑕佹眰"鍙兘鐢ㄥ凡娉ㄥ唽缁勪欢褰撶Н鏈�"锛�
+鑰屼笉鏄悙涓�娈佃皝涔熶笉鏁㈡覆鏌撶殑 HTML銆備换浣�"缁欒涔夊眰鍔犱釜涓囪兘 customHtml 瀛楁"鐨勬敼鍔ㄩ兘鍦ㄦ媶杩欐潯杈圭晫锛岄渶瑕佸厛璁ㄨ銆�
+
+#### 9.4 瀛橀噺鏁版嵁鍏煎
+
+`ReportTemplateSchemaCompatibilityTest` 璧�**鐢熶骇鍚屾璇诲彇璺緞**
+锛圡yBatis-Plus `Jackson3TypeHandler` + `QcReportTemplateVersionDO.schema` 瀛楁锛夛紝
+涓嶆槸娴嬭瘯鑷繁 new 涓�涓� ObjectMapper鈥斺�斿洜涓鸿闃茬殑灏辨槸"鍙嶅簭鍒楀寲璇诲彇"杩欐潯閾捐矾銆�
+瀹炴祴妯℃澘 3 鐨勫簱閲岃褰曠‘瀹炶繕甯︾潃 `bindings`/`dataSources`/`styles` 涓変釜閿紝鐢ㄤ緥浠ュ畠涓鸿摑鏈��
+
+涓�鍙ユ緞娓呭厤寰楀悗浜鸿瑙o細**杩欎釜鐢ㄤ緥涓嶈礋璐h瘉鏄� `@JsonIgnoreProperties` 鐨勫繀瑕佹��**鈥斺��
+瀹炴祴鎶婇偅琛屾敞瑙e幓鎺夋湰鐢ㄤ緥鐓ф牱閫氳繃锛圝ackson 3 榛樿灏卞拷鐣ユ湭鐭ュ睘鎬э級銆�
+娉ㄨВ鐪熸闃茬殑鏄彟澶栦袱鏉★細Spring 鍙嶅簭鍒楀寲璇锋眰浣撶敤鐨� ObjectMapper锛堥厤缃笉鍙楁湰妯″潡鎺у埗锛夛紝
+浠ュ強灏嗘潵鏈変汉缁欑被鍨嬪鐞嗗櫒鎹竴涓洿涓ユ牸鐨� Mapper銆傛祴璇曠被 javadoc 閲屽凡鏄惧紡澹版槑瀹�**涓�**鏄偅鏉℃敞瑙g殑瀹堝崼銆�
+
+### 鍏�佺暀缁欎笅涓�姝ョ殑鎻愰啋
+
+1. **鏀瑰姩浠讳竴渚у紩鎿庡悗蹇呴』閲嶈窇瀵规媿**锛氬厛璺� `render-ts.ts` 閲嶇畻鏈熸湜浜х墿锛屽啀璺� `FrontendConformanceTest`銆�
+ 鏈熸湜浜х墿鏄�**鍐荤粨**鐨勶紝涓嶉噸绠楀氨鍙槸銆屽悗绔窡涓�浠芥棫浜х墿姣斻�嶏紝姣旇繃浜嗕篃涓嶄唬琛ㄤ袱杈逛竴鑷淬��
+2. **绗� 3 姝ュ繀椤荤敱鐢ㄦ埛鎿嶄綔**锛歅laywright 渚濊禆瑕佸姞杩� `yudao-dependencies` 骞朵笅杞� Chromium锛岄渶瑕侀噸鍚悗绔墠鐢熸晥銆�
+3. **`.qc-conformance/` 鍦� `mom-pro2-before` 涓�**锛堣鐩綍鏁翠釜涓嶈鏈粨搴撹窡韪級锛屾槸涓存椂瀵规媿宸ュ叿锛屼笉瑕佸綋浣滃墠绔寮忎唬鐮併��
+4. **绗節鑺傜殑涓ら」鏀瑰姩瑕佸悗绔噸鍚墠鐢熸晥**锛氳鍒欎繚瀛樻牎楠岋紙`validateRules` 鎺ョ嚎锛変笌濂戠害 1.1
+ 锛堝垹闄や笁涓瀛楁锛夐兘鍦ㄥ悗绔��**閲嶅惎鍓�**娴忚鍣ㄩ獙璇佸埌鐨勫彧鏈夊墠绔偅涓�鍗婏紙瑙勫垯鐣欏瓨锛夛紝
+ 鍚庣閭d竴鍗婄洰鍓嶉潬鍗曟祴淇濊瘉銆傞噸鍚悗鍙洿鎺ョ湅妯℃澘 3 鐨勮崏绋胯褰曪細涓変釜姝诲瓧娈靛簲浠� `schema` 閲屾秷澶便��
+5. 妯℃澘 3 鑽夌鐗堟湰 `qc_report_template_version.id=6` 鏄仈璋冮仐鐣欐暟鎹紝鏈疆楠岃瘉宸茬敤鍒板苟**杩樺師**
+ 锛坄rules: []`銆乣schemaVersion: "1.0"`锛夛紱寤鸿鍚庣画杩炴ā鏉夸竴璧锋竻鎺夛紝閬垮厤鍜屾寮忔暟鎹殑鐗堟湰鍙锋贩娣嗐��
+
+## 鍗併�佽鍒欑紪杈戠晫闈� + 淇濆瓨鍓嶆牎楠岄椄鍙o紙2026-09-18 缁級
+
+鐢ㄦ埛閫夊畾鐨勯『搴忔槸"**鍏堣鍒� UI锛屽啀鍑轰欢鎺ュ彛**"锛氬厛鍋氫笉闇�瑕侀噸鍚悗绔殑閮ㄥ垎骞跺湪娴忚鍣ㄩ獙璇侊紝
+鍑轰欢鎺ュ彛鍐欏畬鍚庡啀缁熶竴閲嶅惎涓�娆°�傛湰鑺傛槸鍓嶅崐娈点��
+
+### 10.1 浜や粯鐗�
+
+| 鏂囦欢 | 鏀瑰姩 |
+|---|---|
+| `designer/modules/rule-editor.vue` | **鏂板**锛堢害 170 琛岋級銆傛娊灞夊紡瑙勫垯缂栬緫鍣細鏂板/鍒犻櫎瑙勫垯銆佹敼鍚嶇О銆佸垏浣滅敤鍩熴�佸惎鍋溿�佺紪杈戣〃杈惧紡锛岄�愭潯鍐呰仈鎶ラ敊 |
+| `designer/use-designer.ts` | `retainedSchema` 閭e"鐣欏瓨鍐嶅甫鍥�"鎹㈡垚涓�绛夌姸鎬� `rules` ref锛岄殢 `loadSchema` 杞藉叆銆侀殢 `collectSchema` 浜у嚭 |
+| `designer/index.vue` | 椤舵爮鍔犮�屽垽瀹氳鍒欙紙N锛夈�嶆寜閽� + 绾㈡爣銆孨 鏉¤鍒欏緟淇銆嶏紱`handleSave` / `handlePublish` 鍓嶅姞 `blockOnInvalidRules()` 闂稿彛 |
+| `components/quality/engine/report-evaluator.ts` | `validateRule` 琛ヤ笂**鍑芥暟鐧藉悕鍗�**鏍¢獙锛堝師鍏堝彧鏌ヨ娉曪級锛屽叆鍙傛敼鐢ㄦ柊绫诲瀷 `RuleValidationInput` |
+| `components/quality/engine/rule-engine.ts` | 鏂板 `listAllFunctionNames()`锛岀晫闈㈡彁绀轰笌寮曟搸鐧藉悕鍗曞叡鐢ㄤ竴浠芥潵婧� |
+| `components/quality/index.ts` | 瀵煎嚭 `listAllFunctionNames` |
+| `engine/QualityReportEngine.java` | 绌鸿〃杈惧紡瑙勫垯鐢�"鏀捐"鏀逛负**鏄庣‘鎶ラ敊**锛堝厬鐜扮涔濊妭 9.2 鐣欑殑渚嬪锛� |
+| `ReportEvaluatorTest.java` | 瀵瑰簲鐢ㄤ緥鏀瑰啓涓�"璇诲緱鍑烘潵銆佷絾闃绘柇淇濆瓨" |
+
+**涓轰粈涔� `listAllFunctionNames` 瑕佷粠寮曟搸閲屽鍑鸿�屼笉鏄湪 UI 閲屽彟鎶勪竴浠�**锛氱櫧鍚嶅崟鏄紩鎿庣殑涓�閮ㄥ垎锛�
+鎶勪竴浠藉氨浼氬湪鍔犲嚱鏁版椂婕忔敼锛岀敤鎴风湅鍒扮殑鍙敤鍑芥暟鍒楄〃涓庡紩鎿庡疄闄呮敮鎸佺殑鎮勬倓瀵逛笉涓娿��
+
+**涓轰粈涔� `validateRule` 涓嶅啀澶嶇敤 `QualityRuleDefinition`**锛氶偅涓被鍨嬬殑 `expression` 鏄繀濉紝
+鑰岃璁″櫒閲屾鍦ㄧ紪杈戠殑瑙勫垯銆佸巻鍙叉暟鎹噷鐨勮鍒欓」閮藉彲鑳芥槸绌虹殑锛屾牎楠屽嚱鏁版伆鎭拌鎺ヤ綇杩欑"杩樻病鍐欏畬"鐨勫叆鍙傦紝
+鎵�浠ュ崟鐙畾涔変簡 `RuleValidationInput`锛堜笁涓瓧娈靛叏鍙�夛級銆�
+
+**鍓嶇涓轰綍涔熻鎷︾櫧鍚嶅崟**锛氬彧璁╁悗绔殑 `validateRules` 鎷︼紝鐢ㄦ埛鐐逛繚瀛樺悗浼氬湪鐣岄潰涓婃敹鍒板悗绔姤閿欙紝
+浣嗛偅鏃朵汉宸茬粡绂诲紑鎶藉眽锛岃繕寰楄嚜宸辩炕鏄摢鏉¤鍒欏啓鍧忕殑銆傝璁″櫒閲岀洿鎺ユ嫤锛岀孩瀛楀氨鏍囧湪鍑洪棶棰樼殑閭d竴鏉′笂锛�
+鍚屾椂鎶婃娊灞夎嚜鍔ㄦ墦寮�銆�
+
+### 10.2 鏈疆鍙堝畾浣嶅埌涓�涓湡瀹炵己闄凤細鏀圭焊寮犺缃粠鏉ユ病淇濆瓨鎴愬姛杩�
+
+**鐜拌薄**锛氭瘡娆$偣銆屼繚瀛樸�嶆帶鍒跺彴閮芥姏涓�涓湭澶勭悊寮傚父锛坄Unhandled error during execution of component event handler`
+鎸傚湪淇濆瓨鎸夐挳涓婏級锛屼絾淇濆瓨鎴愬姛鐨勬彁绀虹収甯稿脊鍑烘潵锛岀焊寮犺缃嵈姘歌繙涓嶄細鐢熸晥銆�
+
+**鏍瑰洜**锛歚handleSave` 鏈熬鍚屾绾稿紶璁剧疆鏃跺彧浼犱簡涓変釜瀛楁鈥斺��
+
+```ts
+await updateTemplate({ id, pageSize, orientation }); // 鈫� 鏃у啓娉�
+```
+
+鑰� `qc-report/template/update` 鏄�**鏁翠綋鏇存柊**锛宍QcReportTemplateSaveReqVO` 涓�
+`templateCode` / `templateName` / `pageSize` / `orientation` 閮芥槸 `@NotEmpty`銆�
+婕忎紶妯℃澘缂栫爜锛屽悗绔洿鎺� 400锛歚璇锋眰鍙傛暟涓嶆纭�:妯℃澘缂栫爜涓嶈兘涓虹┖`銆�
+
+**涓轰粈涔堜互鍓嶆病琚彂鐜�**锛氳繖涓� 400 鍙戠敓鍦� `message.success('宸蹭繚瀛樺埌 v1.0')` **涔嬪悗**锛�
+鐗堟湰鏈韩宸茬粡瀛樺ソ浜嗭紝鎵�浠ヨ〃闈笂鐪�"淇濆瓨鏄垚鍔熺殑"锛涘彧鏈夎法鐗堟湰鏍稿妯℃澘琛ㄦ墠浼氬彂鐜扮焊寮犺缃病钀藉簱銆�
+鍙堝洜涓鸿璁″櫒璇荤焊寮犳槸浠�**鐗堟湰 Schema** 鐨� `page` 璇荤殑锛坄loadSchema`锛夛紝
+涓嶆槸浠庢ā鏉胯〃璇荤殑锛岄噸鏂拌繘璁捐鍣ㄧ湅鍒扮殑浠嶆槸姝g‘绾稿紶锛屾妸杩欎釜闂褰诲簳鐩栦綇浜嗐��
+
+**淇硶**锛氭妸妯℃澘鍘熸湁瀛楁涓�璧峰甫涓婏紝鍙鐩栫焊寮犱袱椤癸紙涓庡垪琛ㄩ〉 `form.vue` 鏁翠綋鏇存柊鐨勫彛寰勪竴鑷达級锛�
+
+```ts
+await updateTemplate({
+ ...template.value,
+ id,
+ pageSize: pageSetting.value.size,
+ orientation: pageSetting.value.orientation,
+});
+```
+
+### 10.3 娴忚鍣ㄥ疄娴嬭瘉鎹�
+
+鐜锛歞ev server `http://192.168.0.10:5666`锛屾ā鏉� **5 / 鍑鸿揣妫�楠屾姤鍛婃ā鏉�**锛圦C_OQC_UI锛夈��
+
+| # | 楠岃瘉椤� | 缁撴灉 |
+|---|---|---|
+| 1 | 鎶藉眽鎵撳紑锛岀┖鎬佷笌甯姪鍧楋紙浣滅敤鍩熻鏄庛�佸彲鐢ㄥ瓧娈点�佸彲鐢ㄥ嚱鏁帮級姝e父 | 鉁� |
+| 2 | 鏂板瑙勫垯 鈫� 绔嬪埢鍐呰仈鎶ラ敊銆岃鍒欍�岃鍒� 1銆嶇殑琛ㄨ揪寮忎负绌恒��+ 椤堕儴銆屾湁 1 鏉¤鍒欒繕娌″啓瀹屾暣銆� | 鉁� |
+| 3 | 濉叆鍚堟硶琛ㄨ揪寮忓悗鎶ラ敊琛屾秷澶� | 鉁� |
+| 4 | 鍒囧埌銆屾姤鍛婄骇銆嶏紝琛ㄨ揪寮忓崰浣嶆彁绀哄悓姝ユ崲鎴� `PASS_RATE(...) >= 60` | 鉁� |
+| 5 | 濉叆 `FOO(...)` 鈫� 鍐呰仈鎶ラ敊銆岃皟鐢ㄤ簡涓嶆敮鎸佺殑鍑芥暟 FOO锛屽彲鐢ㄥ嚱鏁帮細ABS銆丄VG銆佲�︺�� | 鉁� |
+| 6 | 瑙勫垯鏈夐棶棰樻椂鐐广�屼繚瀛樸�嶁啋 鎶藉眽鑷姩鎵撳紑 + 鎻愮ず銆屾湁 1 鏉″垽瀹氳鍒欒繕娌″啓瀹屾暣锛岃鍏堜慨姝e啀淇濆瓨銆嶏紝**涓斾笉鍙戜换浣曞啓璇锋眰**锛堢綉缁滈潰鏉跨‘璁わ級 | 鉁� |
+| 7 | 鏀规垚鍚堟硶鍚庝繚瀛� 鈫� 銆屽凡淇濆瓨鍒� v1.0銆嶏紱**閲嶈浇璁捐鍣ㄥ悗椤舵爮鏄剧ず銆屽垽瀹氳鍒欙紙2锛夈�嶏紝涓ゆ潯瑙勫垯鐨勪綔鐢ㄥ煙涓庤〃杈惧紡閮藉湪** | 鉁� |
+| 8 | 淇濆瓨绾稿紶璁剧疆 鈫� `template/update` 杩斿洖 `{"code":0}`锛屾棤鏈鐞嗗紓甯革紱鏀圭焊寮犳柟鍚戝悗鍥炶妯℃澘琛ㄧ‘瀹炲彉浜嗭紙楠岃瘉瀹屽凡鏀瑰洖 landscape锛� | 鉁� |
+| 9 | 鍙戝竷 v1.0 鈫� 宸插彂甯冪増鏈唴瀹逛笉鍙橈紱鍐嶇偣淇濆瓨 鈫� 鍙﹀瓨鍑烘柊鑽夌 v1.1锛�**涓ゆ潯瑙勫垯瀹屾暣甯﹁繃鍘�** | 鉁� |
+
+绗� 7銆�9 涓ゆ潯鍚堣捣鏉ヨ瘉鏄庝簡**瑙勫垯鏁版嵁涓嶅啀涓㈠け**锛氭棦涓嶄細琚鐩栨竻绌猴紝涔熶笉浼氬湪鍙﹀瓨鏂扮増鏈椂鎺夈��
+
+`pnpm typecheck` 鍥炲埌鍩虹嚎 **316 鏉�**锛堟敼鍔ㄥ墠鍩虹嚎 316锛宍qc/report` 涓� `components/quality` 涓� **0 鏉�**锛夈��
+鍚庣鍗曟祴 **29 鏉″叏缁�**锛坄ReportEvaluatorTest` 23 + `FrontendConformanceTest` 3 + `ReportTemplateSchemaCompatibilityTest` 3锛夈��
+
+### 10.4 鏈瀹炴祴鐣欎笅鐨勬暟鎹�
+
+楠岃瘉鍦�**妯℃澘 5锛堝嚭璐ф楠屾姤鍛婃ā鏉匡級**涓婂仛鐨勶紝鐘舵�佹槸锛�
+
+- 鐗堟湰 `v1.0`锛坄qc_report_template_version.id=5`锛夛細**宸插彂甯�**锛堝彧璇伙級锛屽甫 2 鏉$ず渚嬭鍒�
+- 鐗堟湰 `v1.1`锛坄id=7`锛夛細**鑽夌**锛屽悓鏍� 2 鏉$ず渚嬭鍒�
+
+涓ゆ潯绀轰緥瑙勫垯锛歚瀹炴祴鍊煎湪瑙勬牸鍐卄锛堥�愰」锛夈�乣鏁翠綋鍚堟牸鐜囦笉浣庝簬 90%`锛堟姤鍛婄骇锛夈��
+閮芥槸鏈夋剰涔夌殑婕旂ず鏁版嵁锛�**娌℃湁鍒犻櫎**锛涘鏋滀笉鎯崇暀锛屽垹鎺夋ā鏉� 5 鍗冲彲銆�
+
+### 10.5 涓嬩竴姝�
+
+鎸夌敤鎴烽�夊畾鐨勯『搴忥紝鎺ヤ笅鏉ユ槸**鍑轰欢鎺ュ彛**锛圥hase 3 绗� 4 姝ワ級锛氬嚭浠� + `data_snapshot` + HTML/PDF 褰掓。 +
+鍏ョ珯 HTML 鏈嶅姟绔� Sanitization銆傚姩鎵嬪墠蹇呴』鍏堝鐞嗕竴浠朵簨锛�
+
+`QcReportInstanceDO` 閲屾湁涓� `pdfFileUrl` 瀛楁锛�**杩濆弽** `.claude/rules/file-upload.md`
+锛堢姝笟鍔¤〃/DO 鍑虹幇 `file_url` / `attachment_url` 涓�绫荤殑鏂囦欢鍦板潃瀛楁锛夈��
+PDF 蹇呴』璧� `system_storage_attachment` 涓棿琛紝`recordType = 'qc_report_instance'`銆�
+杩欎釜 DO 鐩墠鏄釜瀛ゅ効锛堟病鏈� Mapper/Service/寤鸿〃鑴氭湰锛夛紝鏀硅捣鏉ユ病鏈夊吋瀹硅礋鎷呫��
+鍙︼細`ErrorCodeConstants` 閲� `1_070_102_000/001/002`锛堝疄渚嬶級涓� `1_070_103_000..005`锛堟覆鏌擄級宸查鐣欎絾鏈娇鐢ㄣ��
+
+---
+
+## 鍗佷竴銆佸嚭浠舵帴鍙o紙Phase 3 绗� 4 姝ワ級鈥斺�� 鉁� 瀹屾垚锛氫袱杞� HTTP 鑱旇皟鍏ㄧ豢锛�27/27 + 24/24锛夛紝淇 2 涓湡瀹炵己闄峰苟澶嶉獙
+
+> 瀹屾暣鏂规瑙佽鍒掓枃浠� `C:\Users\浜慭.claude\plans\smooth-greeting-garden.md`
+> **浠g爜灞傞潰宸插叏閮ㄨ惤鍦�**锛圕ontroller / 鍗曟祴 / 鍚堝苟鑴氭湰閮藉凡瀹屾垚锛�43 椤规祴璇曞叏缁匡級銆�
+> 鍞竴娌″仛鐨勬槸**绔埌绔� HTTP 鑱旇皟**鈥斺�旈渶鍏堥噸鍚悗绔� 48080 璁╂柊浠g爜鐢熸晥锛岃 11.5銆�
+
+### 11.1 鏈疆鍙e緞锛堢敤鎴锋媿鏉匡級
+
+| 璁 | 鍐崇瓥 |
+|---|---|
+| 鏁版嵁鏉ユ簮 | **涓ゆ璧�**锛氭湰杞帴鍙e彧鍚�**璋冪敤鏂逛紶鍏ョ殑涓婁笅鏂�**锛宷creport **涓嶄緷璧�** `yudao-module-mes`锛涗笅涓�杞啀鍋� `MesQcReportApi` 鎵撻�� IPQC/IPQC/OQC/RQC 鍥涚璐ㄦ鍗� |
+| PDF 鑼冨洿 | **鍏堝彧鍋� HTML**銆侾DF 闅� Playwright 涓�璧蜂笂锛堥渶鑱旂綉涓嬭浇 Chromium + 閲嶅惎鍚庣锛夛紱椤哄甫娓呮帀杩濊鐨� `pdf_file_url` |
+| 鎶ュ憡缂栧彿 | **qcreport 鑷繁鐢熸垚**锛宍QR20260918-0001`锛涜皟鐢ㄦ柟涔熷彲鏄惧紡浼犲叆瑕嗙洊 |
+| 缂哄彛娓呭崟钀藉簱锛� | **涓嶈惤搴�**锛屽彧鍦� preview/generate/regenerate 鐨勫搷搴旈噷杩斿洖 |
+| `pdf_file_url` 鎬庝箞鍒� | 鐢� MCP 鐩存帴鍦ㄨ繍琛屽簱鎵ц `DROP COLUMN` + 鍚屾鏀� DDL 鑴氭湰 |
+| 鍚堝苟鍒濆鍖栬剼鏈己鍙� | **鏈疆涓�骞惰ˉ涓�** |
+
+### 11.2 宸插畬鎴�
+
+**锛�1锛夋竻鎺夎繚瑙勭殑 `pdf_file_url`**
+
+| 鍔ㄤ綔 | 缁撴灉 |
+|---|---|
+| `QcReportInstanceDO` 鍒犲瓧娈� | 鉁� 宸插垹锛岄『鎵嬫妸 `id` 涓婂啓閿欑殑娉ㄩ噴銆屾姤鍛婄紪鍙枫�嶆敼涓恒�屽疄渚嬬紪鍙枫�� |
+| `docs/sql/qc_report_platform_ddl.sql` 鍒犲垪瀹氫箟 | 鉁� 宸插垹 |
+| 杩愯搴� `ruoyi-vue-pro` 鎵ц `ALTER TABLE ... DROP COLUMN` | 鉁� 宸叉墽琛� |
+| **鍥炶楠岃瘉**锛坄information_schema`锛� | 鉁� `ruoyi-vue-pro` **14 鍒� / `has_pdf_url`=0**锛沗mom-jhhg` 浠嶆槸 15 鍒楋紙鍘嗗彶閬楃暀搴擄紝鏃� profile 鎸囧悜锛�**鏈夋剰涓嶅姩**锛� |
+
+**锛�2锛夐敊璇爜鏂板涓や釜**锛坄enums/ErrorCodeConstants.java`锛�1-070-101 娈靛唴 007/008 鍘熸湰绌虹潃锛�
+
+```java
+TEMPLATE_NO_PUBLISHED_VERSION = 1_070_101_007 // 璇ユā鏉胯繕娌℃湁宸插彂甯冪殑鐗堟湰锛屾棤娉曠敓鎴愭姤鍛婏紝璇峰厛鍦ㄨ璁″櫒涓彂甯冧竴涓増鏈�
+TEMPLATE_VERSION_CANVAS_EMPTY = 1_070_101_008 // 璇ユā鏉跨増鏈病鏈夌敾甯冨唴瀹癸紝鏃犳硶鐢熸垚鎶ュ憡锛岃鍏堝湪璁捐鍣ㄤ腑璁捐骞朵繚瀛樻ā鏉垮唴瀹�
+```
+
+涓嶅姞杩欎袱涓爜灏卞彧鑳藉鐢ㄣ�屾ā鏉跨増鏈笉瀛樺湪銆嶏紝鐢ㄦ埛鐪嬩笉鎳傞棶棰樺湪鍝紙杩濆弽 `.claude/rules/error-message-precision.md`锛夈��
+鍏朵綑鍏ㄩ儴澶嶇敤宸查鐣欑殑鐮侊細`REPORT_INSTANCE_NOT_EXISTS` / `REPORT_INSTANCE_NO_DUPLICATE` /
+`REPORT_INSTANCE_DATA_SNAPSHOT_MISSING` / `RENDER_BUSINESS_DATA_MISSING`銆�
+
+**锛�3锛変袱涓函閫昏緫鎺ョ紳**锛堝彲鑴辩 Spring 鍗曟祴锛屽崟娴嬭锛�8锛夛級
+
+| 鏂囦欢 | 鑱岃矗 |
+|---|---|
+| `service/instance/ReportNoGenerator.java` | `prefix(day)` 鈫� `QR20260918-`锛沗format(day, seq)` 鈫� 琛ラ浂 4 浣嶃�佽秴 9999 鑷劧鍔犲锛沗nextSequence(latestNo, day)` 鈫� 灏惧彿 +1锛�**璺ㄦ棩/鏍煎紡涓嶈璇�/涓虹┖涓�寰嬪綊 1** |
+| `engine/context/ReportContextCodec.java` | `toMap(ReportContext)`锛堬紳`context.toScope()`锛�/ `fromMap(Map)`銆�**鎵嬪啓**閫愬瓧娈佃鍥烇紝涓嶉潬 Jackson 鍙嶅皠 鈥斺�� 寮曟搸鏈潵灏辨槸杩欎釜椋庢牸锛坄reportMap()`/`itemMap()` 鍏ㄦ槸鏄惧紡瀛楁娓呭崟锛夛紝涓旇兘閬垮紑 Jackson 3 / Jackson 2 涓ゅ Mapper 骞跺瓨甯︽潵鐨勬暟鍊肩被鍨嬩笌鏈煡瀛楁宸紓銆�**杩欐槸銆屽巻鍙叉姤鍛婂彲澶嶇幇銆嶇殑鍞竴瀹炵幇璺緞** |
+
+**锛�4锛夋寔涔呭眰涓� Service**
+
+- `dal/mysql/instance/QcReportInstanceMapper.java`锛歚selectPage` / `selectByReportNo` /
+ `selectLatestByReportNoPrefix`銆�**鏈�呯殑鎺掑簭鍒绘剰鍐欐垚 `ORDER BY CHAR_LENGTH(report_no) DESC, report_no DESC LIMIT 1`**锛�
+ 搴忓彿琛ラ浂 4 浣嶏紝褰撳ぉ涓�鏃﹁秴杩� 9999 浣嶅灏卞彉闀匡紝绾瓧鍏稿簭浼氭妸 `...-9999` 鎺掑埌 `...-10000` 鍓嶉潰锛坖avadoc 宸插啓鏄庯級銆�
+- `service/instance/QcReportInstanceService.java` + `Impl`锛歚preview` / `generate` / `regenerate` /
+ `validateInstanceExists` / `getInstance` / `getSnapshot` / `getInstancePage` / `deleteInstance`銆�
+- `service/instance/GenerateResult.java`锛歚record GenerateResult(QcReportInstanceDO instance, List<String> errors)`銆�
+- `service/version/QcReportTemplateVersionService(+Impl)`锛�**鏂板** `getVersionByTemplateIdAndVersion(templateId, version)`锛�
+ 鍙栫増鏈絾**涓嶈姹傚凡鍙戝竷**锛坄regenerate` 瑕佺敤锛岀悊鐢辫 11.3锛夈��
+
+**锛�5锛塚O 鍏釜**锛坄controller/admin/instance/vo/`锛�
+
+`QcReportInstanceGenerateReqVO`锛坄templateId` @NotNull銆乣version`銆乣reportNo`銆乣businessId`銆乣businessType`銆�
+`context` @NotNull **鐩存帴澶嶇敤寮曟搸鐨� `ReportContext`**锛夈�乣PageReqVO`銆乣RespVO`锛�**鍒绘剰涓嶅惈 `dataSnapshot`**锛夈��
+`PreviewRespVO`锛坄reportNo`/`html`/`errors`锛夈�乣GenerateRespVO`锛坄id`/`reportNo`/`templateVersion`/`status`/`errors`锛夈��
+`RegenerateRespVO`锛坄id`/`reportNo`/`errors`锛夈��
+
+`context` 鐢� `ReportContext` 鑰屼笉鍙﹂�犻暅鍍� VO锛氬畠灏辨槸杩欎釜骞冲彴瀵瑰鐨勫敮涓�鏁版嵁濂戠害锛屽彟閫犱竴涓彧浼氬涓�澶勮鍚屾鐨勫瓧娈垫竻鍗曘��
+
+**锛�6锛夌紪璇�** 鉁� `mvn compile -pl yudao-module-qcreport -am -q -o` 鈫� **exit 0**
+
+**锛�7锛塁ontroller 涓冧釜绔偣** 鉁�
+
+`controller/admin/instance/QcReportInstanceController.java`锛宍@RequestMapping("/qc-report/instance")`锛�
+鐓� `QcReportTemplateVersionController` 鐨勫啓娉曪紙`@Tag` / `@RestController` / `@Validated` /
+`@PreAuthorize("@ss.hasPermission(...)")` / `CommonResult.success` / `BeanUtils.toBean`锛夛細
+
+| 绔偣 | 鏉冮檺鐮� | 缂栨帓 |
+|---|---|---|
+| `POST /preview` | `qc-report:instance:query` | `instanceService.preview(reqVO)` 鈫� `PreviewRespVO`锛坄reportNo` 鍙� `outcome.context().getReport().getReportNo()`锛屽彲鑳戒负绌猴紱`html`锛沗errors`锛� |
+| `POST /generate` | `qc-report:instance:create` | `GenerateResult` 鈫� `GenerateRespVO`锛坕d/reportNo/templateVersion/status/errors锛� |
+| `GET /get?id=` | `qc-report:instance:query` | `getInstance(id)` 鈫� `BeanUtils.toBean(...)`锛�**鍒ょ┖**锛堣蒋鍒犲悗杩斿洖 `data:null`锛屼笉鎶ラ敊锛� |
+| `GET /snapshot?id=` | `qc-report:instance:query` | `getSnapshot(id)` 鈫� `CommonResult<Map<String,Object>>` |
+| `GET /page` | `qc-report:instance:query` | `getInstancePage(reqVO)` 鈫� `PageResult<RespVO>` |
+| `POST /regenerate?id=` | `qc-report:instance:create` | `GenerateResult` 鈫� `RegenerateRespVO`锛坕d/reportNo/errors锛� |
+| `DELETE /delete?id=` | `qc-report:instance:delete` | `deleteInstance(id)` |
+
+**锛�8锛変袱涓崟娴嬬被锛�14 鏉$敤渚�** 鉁�
+
+| 绫� | 鏉℃暟 | 瀹堢殑鏄粈涔� |
+|---|---|---|
+| `service/instance/ReportNoGeneratorTest` | 7 | 鍓嶇紑涓庢牸寮忋�佽秴 9999 浣嶅鑷劧鍔犲銆�**locale 鏃犲叧**锛堣 `th-TH-u-ca-buddhist-nu-thai` 浠嶈緭鍑� `QR20260918-0007`锛夈�佸悓鏃ラ�掑銆佹棤缂栧彿褰� 1銆佽法鏃ュ綊 1銆佹牸寮忎笉璁よ瘑褰� 1锛�7 绉嶇暩褰㈣緭鍏ワ級 |
+| `engine/context/ReportContextCodecTest` | 7 | **鏍稿績涓�鏉� `roundTripReproducesHtml`**锛氳 fixture 鈫� 娓叉煋 鈫� `toMap` 鈫� `fromMap` 鈫� 鍐嶆覆鏌擄紝鏂█涓ゆ HTML **閫愬瓧鐩稿悓**涓� `errors` 鐩稿悓 鈥斺�� 杩欏氨鏄�屽巻鍙叉姤鍛婂彲澶嶇幇銆嶇殑鏈哄櫒璇佹槑锛屽悓鏃惰瘉鍑哄垽瀹氭槸骞傜瓑鐨勩�傚彟锛氬揩鐓у甫鐫�绠楀ソ鐨勫垽瀹氫笌鍚堟牸鐜囥�佸線杩斾笉涓㈠瓧娈点�佹棤涓婁笅闄愪繚鎸� null銆佺己瀛楁钀界┖涓层�佺┖蹇収涓嶆姏銆佹暟缁勯噷娣峰叆闈炲璞″厓绱犲彧璺宠繃璇ュ厓绱� |
+
+鍏ㄦā鍧� **43 椤瑰叏缁�**锛堝師鏈� 29 + 鏈疆 14锛夛紝`mvn -pl yudao-module-qcreport test` exit 0銆�
+
+**锛�9锛夊悎骞跺垵濮嬪寲鑴氭湰 `config_export_all_20260918.sql`** 鉁�
+
+0904 鍓湰 + 涓夊鏀瑰姩锛氣憼澶撮儴璇存槑鏀瑰啓锛涒憽`qc_report_*` 6 寮犺〃寤鸿〃娈垫彃鍦� `oa_notice_user` 涓� `qrtz_blob_triggers` 涔嬮棿
+锛坄qc_` < `qr_`锛夛紝`qc_report_instance` **涓嶅惈 `pdf_file_url`**锛涒憿闃舵涓�鐨� `system_dict_type` 琛� 6 琛岋紙1065400~1065405锛夈��
+`system_dict_data` 琛� 21 琛岋紙1065410~1065466锛夈��
+
+**瀹炴祴楠岃瘉**锛堜笉鏄彧鐪嬭娉曪級锛氬湪鐪熷疄瀹炰緥涓婂缓涓存椂搴� `qc_init_check_tmp`锛屾暣浠� 1.2 MB 鏂囦欢璺戝畬 鈫�
+EXIT=0锛�**419 寮犺〃**銆�6 寮� `qc_report_*`銆乣qc_report_instance` 14 鍒楁棤 `pdf_file_url`銆�
+6 涓瓧鍏哥被鍨� + 21 鏉″瓧鍏告暟鎹��1 涓� admin銆�1258 涓彍鍗曘��1 涓� default oauth2 client銆�
+2349 鏉� `system_role_menu`銆乹creport 鑿滃崟 1075400~1075405 榻愬叏锛涢殢鍚� drop 涓存椂搴撳苟纭娈嬬暀涓� 0銆�
+
+> 鏃ф枃浠� `config_export_all_20260904.sql` **鍘熸牱淇濈暀澶囨煡**锛屽彧缁存姢鏂扮増锛坄.claude/rules/sql-config-export-init.md`锛夈��
+> 鈿� 闃舵涓�鍚叏搴� `DROP TABLE IF EXISTS`锛�**鍙兘鍦ㄥ叏鏂�/鍙鐩栫┖搴撴墽琛岋紝绂佹鍦ㄨ繍琛屽簱涓婅窇**銆�
+
+**锛�10锛夊彂鐜板苟淇浜� 0904 鍩虹嚎閲岀殑涓�涓棦鏈夌己闄凤紙闃舵浜� 鈶ワ級** 鉁�
+
+鏂板簱棣栨鎵ц鏃惰剼鏈湪 `system_role_menu` 涓婃姤
+`Duplicate entry '6352' for key 'system_role_menu.PRIMARY'` 鏁存涓柇锛�**搴撳仠鍦ㄥ崐鍒濆鍖栫姸鎬�**銆�
+鏍瑰洜**涓嶆槸鏈疆寮曞叆鐨�**锛屾槸 0904 鍩虹嚎鏃㈡湁鍐欐硶锛氶樁娈典簩 鈶� 鍐欐垚
+
+```sql
+DELETE FROM `system_role_menu`;
+INSERT INTO `system_role_menu`
+SELECT rm.* FROM `ruoyi-vue-pro`.`system_role_menu` rm
+INNER JOIN `system_user_role` ur ON ur.`role_id` = rm.`role_id`;
+```
+
+婧愬簱 `system_user_role` 鐨�**涓婚敭鍙湁 `id`**锛屾墍浠ュ悓涓� `(user_id, role_id)` 鍙互瀛樺湪澶氳 鈥斺��
+瀹炴祴璇ヨ〃 5 琛� / 鍙湁 4 涓笉鍚� `role_id`锛坄1:1, 1:2, 1:160, 1:1, 1:3`锛宎dmin 鐨� `role_id=1` 纭疄鏈� 2 琛岋細
+id=1 寤轰簬 2022-01-11銆乮d=129 寤轰簬 2026-09-02锛夈�俙INNER JOIN` 鎶� `system_role_menu` 鐨勬瘡涓�琛屾斁澶ф垚 N 琛岋紝
+鎾炰富閿鑷存暣鑴氭湰涓柇銆�
+
+**宸叉敼涓哄幓閲嶅啓娉�**锛坄IN` 瀛愭煡璇㈠ぉ鐒跺幓閲嶏紝涓庤鏁版棤鍏筹級锛�
+
+```sql
+-- 鈿� 涓嶈兘鍐欐垚 INNER JOIN `system_user_role`锛氭簮搴� system_user_role 鐨勪富閿彧鏄� id锛�
+-- 鍚屼竴 (user_id, role_id) 鍙互瀛樺湪澶氳锛堝疄娴� admin 鐨� role_id=1 灏辨湁 2 琛岋級锛�
+-- JOIN 浼氭妸 system_role_menu 鐨勬瘡涓�琛屾斁澶ф垚 N 琛岋紝鎾� system_role_menu 涓婚敭瀵艰嚧鏁磋剼鏈腑鏂��
+-- 鐢� IN锛堝瓙鏌ヨ澶╃劧鍘婚噸锛夎〃杈俱�岃繖浜涜鑹茬殑鑿滃崟銆嶏紝涓庤鏁版棤鍏炽��
+INSERT INTO `system_role_menu`
+SELECT rm.* FROM `ruoyi-vue-pro`.`system_role_menu` rm
+WHERE rm.`role_id` IN (SELECT `role_id` FROM `system_user_role`);
+```
+
+鏀瑰悗閲嶈窇涓存椂搴� EXIT=0锛屼笖琛屾暟涓庢簮搴�**閫愰」鐩哥瓑**锛坄role_menu` 2349=2349銆乣menus` 1258=1258锛夈��
+**杩欑被缂洪櫡鍙湁鐪熷湪绌哄簱璺戜竴閬嶆墠浼氭毚闇诧紝绾娉曟鏌ユ姄涓嶅埌銆�**
+
+**锛�11锛夆殸 鐜鍧戯細MCP 杩炵殑涓嶆槸鍚庣鐢ㄧ殑閭d釜搴�**
+
+鏈疆鍋氬埌涓�鍗婃椂锛屽悓涓�涓煡璇㈠厛鑳借繑鍥� `ruoyi-vue-pro` + `mom-jhhg`锛屽嚑鍒嗛挓鍚庣獊鐒惰繑鍥炵┖銆�
+鏌� `SELECT @@hostname, @@port, DATABASE(), @@version` 鈫�
+`6c8bf09fabf1` / 3306 / `product-inventory-management-rbhb` / 8.4.6锛屾槸**鍙︿竴鍙版矙鐩掑疄渚�**
+锛�30+ 涓� `product-inventory-management-*` 搴撱�佹病鏈� `mom-jhhg`銆佸叾 `ruoyi-vue-pro` 鏈� 410 寮犺〃涓� **0 寮� `qc_report_*`**锛夈��
+
+鏀硅蛋鏉冨▉璺緞锛歚docker ps` 鈫� 瀹瑰櫒 `mysql8`锛坄0.0.0.0:3306`锛夆啋 `docker exec mysql8 mysql ...` 寰�
+`@@hostname` = **`2a8dea946ada`**銆�**416 寮犺〃**銆�6 寮� `qc_report_*`銆�
+鍦ㄨ繖鍙扮湡瀹炲疄渚嬩笂鍥炶锛歚ruoyi-vue-pro.qc_report_instance` **14 鍒� / `has_pdf_url`=0**
+锛堣鏄� 11.2锛�1锛夌殑 `DROP COLUMN` 钀藉浜嗗簱锛夛紝`mom-jhhg` 浠� 15 鍒楋紙**鏈夋剰涓嶅姩**锛夛紝瀹炰緥琛� 0 琛屻��
+
+> 涓庤蹇嗛噷銆孧CP 甯歌繛鍙︿竴鍙版矙鐩掑疄渚嬨�嶄竴鑷达細**鏈」鐩殑寤鸿〃/杩佺Щ鏍搁獙涓嶈淇� MCP锛岃蛋 `docker exec mysql8`**銆�
+> 鍙︼細鐢� `docker exec mysql8 mysql -e "..."` 鍐欎腑鏂囨敞閲�**蹇呴』鍔� `--default-character-set=utf8mb4`**锛�
+> 鍚﹀垯瀛樿繘鍘绘槸涔辩爜锛堟湰杞凡韪╄繃涓�娆★細`瀹炰緥缂栧彿` 鍐欐垚 `氓庐啪盲戮鈥姑尖�撁ヂ穈锛屽姞浜嗗弬鏁伴噸鎵ц鍚�
+> `column_comment` 涓� `HEX()` 鍧囨纭級銆�
+
+### 11.3 鍒绘剰鐨勮璁″彇鑸嶏紙閮戒笉鏄殢鎵嬪啓鐨勶級
+
+| # | 鍙栬垗 | 鐞嗙敱 |
+|---|---|---|
+| 1 | **`generate` 涓嶅姞 `@Transactional`** | 鏁存鍙湁涓�娆� insert锛屾病鏈夊璇彞涓�鑷存�ч渶姹傦紱鍙嶈�屽姞浜嗕簨鍔′箣鍚庯紝閲嶈瘯璺緞涓婅 `catch` 鎺夌殑 `DuplicateKeyException` 鏈夎鏍囪鎴� rollback-only 鐨勯闄╋紝浼氭妸銆岄噸璇曘�嶅彉鎴愩�屽繀瀹氬け璐ャ�� |
+| 2 | **鑷姩缂栧彿鎾炲彿閲嶈瘯 5 娆�** | 骞跺彂涓嬩袱涓姹備細绠楀嚭鍚屼竴搴忓彿锛岄潬 `uk_report_no` 鍞竴绱㈠紩鎸′笅鏉ラ噸绠楀嵆鍙紱杩炴挒 5 娆″凡杩滆秴銆屽悓鏃跺嚭涓�浠芥姤鍛娿�嶇殑姝e父骞跺彂锛屽啀澶辫触灏卞瀹炴姤閿欙紙鏂囨甯︿笂閲嶈瘯娆℃暟涓庛�屽彲鏄惧紡鎸囧畾缂栧彿銆嶏級锛屼笉鍋氭棤闄愰噸璇� |
+| 3 | **鏄惧紡缂栧彿涓嶉噸璇�** | 鎸囧畾浜嗙紪鍙峰氨鏄瘡娆″悓涓�涓彿锛岄噸璇曟病鏈夋剰涔夛紱鍏堟煡閲嶏紝鎾炰簡鐩存帴鎶ャ�屾姤鍛婄紪鍙枫�孹銆嶅凡琚崰鐢紝璇锋崲涓�涓紪鍙凤紝鎴栫暀绌虹敱绯荤粺鎸� QR+鏃ユ湡+娴佹按 鑷姩鐢熸垚銆� |
+| 4 | **`regenerate` 鏌ョ増鏈笉瑕佹眰宸插彂甯�** | 宸插彂甯冪増鏈殑鍐呭鏀逛笉浜嗭紙`updateVersion` 鎷︾潃锛夛紝浣嗗畠鍙兘鍚庢潵琚� `disableVersion` 鍋滅敤锛涗竴浠�**宸茬粡鍑鸿繃**鐨勫巻鍙叉姤鍛婁笉璇ュ洜姝ゅ彉鎴愭墦涓嶅紑銆傜敤 `getPublishedVersion` 浼氭妸杩欎釜鍦烘櫙鍗℃锛屾墍浠ユ柊澧炰簡 `getVersionByTemplateIdAndVersion` |
+| 5 | **`regenerate` 涓嶈鐩� `data_snapshot`** | 鍐荤粨鐨勬暟鎹槸鍘嗗彶鎶ュ憡鐨勪緷鎹紝閲嶆柊鐢熸垚鍔ㄧ殑鍙槸**鎺掔増浜х墿**銆傚紩鎿庡崌绾у悗閲嶆覆鍙兘寰楀埌涓嶅悓 HTML锛岄偅姝f槸銆岄噸鏂扮敓鎴愩�嶈鏈夌殑鏁堟灉 |
+| 6 | **蹇収瀛樸�屽垽瀹氬悗銆嶇殑涓婁笅鏂�**锛坄outcome.context().toScope()`锛� | 杩欐墠鏄骇鍑鸿繖浠� HTML 鐨勯偅浠芥暟鎹紝鍚畻濂界殑 PASS/FAIL 涓庡悎鏍肩巼銆傚瓨鍒ゅ畾**鍓�**鐨勫師濮嬫暟鎹紝浜嬪悗灏辩湅涓嶅嚭褰撴椂鏄�庝箞鍒ょ殑 |
+| 7 | **鐢熸晥缂栧彿鏃犳潯浠跺啓鍥� context 鍐嶆覆鏌�** | 绾搁潰涓婄殑鎶ュ憡缂栧彿涓庡疄渚嬬紪鍙峰繀椤绘槸鍚屼竴涓紝涓嶈兘鍑虹幇銆屾姤鍛婁笂鍗扮潃涓�涓彿銆佺郴缁熼噷瀛樼潃鍙︿竴涓彿銆� |
+| 8 | **`preview` 涓嶇敓鎴愩�佷笉娑堣�楀簭鍙�** | 缂栧彿鏄嚭浠舵椂鎵嶇‘瀹氱殑娴佹按鍙凤紝棰勮涓嶈娑堣�楀畠锛涢瑙堝彧鐢ㄥ叆鍙傞噷甯﹁繃鏉ョ殑缂栧彿 |
+| 9 | **`resolveVersion` 瑕佹眰妯℃澘 `ENABLE`** | 涓� `createVersion` 淇濇寔涓�鑷达細鍋滅敤鐨勬ā鏉夸笉鍐嶄骇鍑烘柊鎶ュ憡锛堝巻鍙叉姤鍛婇噸鏂扮敓鎴愪笉璧拌繖鏉¤矾寰勶級 |
+| 9b | **`resolveVersion` 鐨� `requirePublished` 寮�鍏筹細鍑轰欢瑕併�侀瑙堜笉瑕�** | 鍑轰欢浼氭妸鐗堟湰鍙峰喕缁撹繘瀹炰緥銆佽�屽疄渚嬪彧璁扮増鏈彿涓嶈鍐呭锛岀敤鑽夌鍑轰欢绛変簬鍩嬩竴棰椼�岀増鏈彿瀵瑰緱涓娿�佸唴瀹瑰凡缁忓彉浜嗐�嶇殑闆凤紱棰勮涓嶈惤搴撱�佷笉鍐荤粨鏁版嵁銆佷笉娑堣�楃紪鍙凤紝鑽夌浼氬彉鍦ㄨ繖閲屾病鏈夊悗鏋滐紝鑰屻�屼繚瀛樿崏绋� 鈫� 鐐归瑙堛�嶆鏄璁″櫒涓绘祦绋嬶紙瑙� 11.7 缂洪櫡 2锛� |
+| 9c | **缂栧彿鍙涓嶅噺锛屽垹鎺夌殑鍙蜂笉鍥炴敹** | `uk_report_no` 鍞竴绱㈠紩涓嶈 `deleted`锛岃嫢鎸夈�屽彲瑙佺殑鏈�澶у彿 +1銆嶇畻锛屽垹鎺夊綋澶╂渶澶у彿鍚庡繀鐒跺弽澶嶆挒鍙凤紙瑙� 11.7 缂洪櫡 1锛夈�傚洜姝ゅ彇鏈�澶у彿鏃�**鎶婅蒋鍒犻櫎鐨勮涔熺畻杩涙潵**锛屼唬浠锋槸褰撳ぉ娴佹按浼氳烦鍙� |
+| 10 | **`prepareContext` 鍏� `report == null`** | 璇锋眰浣撻噷鏄惧紡浼� `"report": null` 浼氭妸瀹冪疆绌猴紝涓嶅厹鐨勮瘽 `reportMap()` 浼氬湪娓叉煋娣卞鎶� NPE锛岀敤鎴峰彧鐪嬪埌銆岀郴缁熷紓甯搞�� |
+| 11 | **鏍¢獙 `inspectionItems` 闈炵┖** | 娌℃湁妫�楠岄」鐨勩�屾姤鍛娿�嶆病鏈夋剰涔夛紝鎶ュ嚭鏉ユ瘮缁欎竴寮犵┖琛ㄥソ |
+| 12 | **鏈疆涓嶅線 `system_menu` 鎻掓潈闄愯** | 鍓嶇杩樻病鏈夊疄渚嬪垪琛ㄩ〉锛屾彃涓�涓寚鍚戜笉瀛樺湪缁勪欢鐨勯〉闈㈣彍鍗曚細鎶婂鑸墦鍧忋�傚綋鍓� `admin` 鏄� `super_admin`锛岃秴绠$洿鎺ユ斁琛岋紝鑱旇皟涓嶅彈褰卞搷銆�**鍓嶇瀹炰緥椤佃惤鍦版椂涓�骞惰ˉ鑿滃崟 + 鎸夐挳鏉冮檺**锛屽苟鎸� `.claude/rules/sql-config-export-init.md` 褰掑叆闃舵浜� |
+
+### 11.4 鏈疆鏂板/淇敼鏂囦欢娓呭崟
+
+**鏂板锛堝悗绔� `yudao-module-qcreport`锛�**
+
+```
+service/instance/{QcReportInstanceService,QcReportInstanceServiceImpl,GenerateResult,ReportNoGenerator}.java
+engine/context/ReportContextCodec.java
+dal/mysql/instance/QcReportInstanceMapper.java
+controller/admin/instance/QcReportInstanceController.java
+controller/admin/instance/vo/{GenerateReqVO,PageReqVO,RespVO,PreviewRespVO,GenerateRespVO,RegenerateRespVO}.java
+```
+
+**鏂板锛堟祴璇曪級**
+
+```
+src/test/java/.../service/instance/ReportNoGeneratorTest.java (7 鏉�)
+src/test/java/.../engine/context/ReportContextCodecTest.java (7 鏉�)
+```
+
+**淇敼锛堝悗绔� `yudao-module-qcreport`锛�**
+
+| 鏂囦欢 | 鏀瑰姩 |
+|---|---|
+| `enums/ErrorCodeConstants.java` | +2 涓敊璇爜锛堣 11.2锛� |
+| `dal/dataobject/instance/QcReportInstanceDO.java` | 鍒� `pdfFileUrl` 瀛楁锛涗慨姝� `id` 鐨勯敊璇敞閲� |
+| `service/version/QcReportTemplateVersionService(+Impl)` | +`getVersionByTemplateIdAndVersion` |
+| `service/instance/ReportNoGenerator.java` | 鍔� `Locale.ROOT`锛坄ofPattern` 涓� `String.format` 涓ゅ锛岃涓嬶級 |
+| `dal/mysql/instance/QcReportInstanceMapper.java` | **鑱旇皟鍚庝慨缂洪櫡 1**锛歚selectLatestByReportNoPrefix` 鈫� 鎵嬪啓 `@Select selectLatestReportNoByPrefix`锛岀粫杩囬�昏緫鍒犻櫎銆佸彧鍙栫紪鍙峰垪锛堣 11.7锛� |
+| `service/instance/QcReportInstanceServiceImpl.java` | **鑱旇皟鍚庝慨缂洪櫡 2**锛歚resolveVersion` 鍔� `requirePublished` 寮�鍏筹紝`preview` 鏀捐鑽夌锛涜ˉ `versionDO == null 鈫� TEMPLATE_VERSION_NOT_EXISTS`锛堣 11.7锛� |
+
+**鏂板锛堟枃妗� / SQL锛�**
+
+| 鏂囦欢 | 璇存槑 |
+|---|---|
+| `docs/qc_report_instance_frontend_integration.md` | 鍓嶇鑱旇皟鏂规锛坄.claude/rules/frontend-docs.md` 寮哄埗锛夛紝**鏃犱换浣曞墠绔唬鐮佺墖娈�** |
+| `docs/sql/config_export_all_20260918.sql` | 鍚堝苟鍒濆鍖栬剼鏈柊鐗堬紙瑙� 11.2锛�9锛夛級 |
+| `docs/sql/qc_report_platform_ddl.sql` | 鍒� `pdf_file_url` 鍒楀畾涔夛紱`id` 娉ㄩ噴鏀广�屽疄渚嬬紪鍙枫�� |
+| `docs/project-business/` | 澧為噺锛歚01-business-mindmap` / `05-quality-flow` / `08-module-relation` / `09-data-flow` / `10-business-object` 浜斿紶鍥� + `data/{objects,modules,flows,business}.json`锛堟ā鍧� 12鈫�13銆佸璞� 46鈫�48锛夛紝宸茶窇 `sync_index.js`銆�**宸插湪娴忚鍣ㄥ疄娴�**锛氳捣闈欐�佹湇鍔℃墦寮� `index.html`锛�5 寮犳敼鍔ㄥ浘 `mermaid.parse` 鍏ㄩ儴閫氳繃銆佽川閲忔祦绋嬪浘娓叉煋鎴� SVG 涓旀楠よ〃 7 琛岋紙鍚柊澧炪�屽嚭浠躲�嶏級銆佹ā鍧楀崱鐗� 13 寮犲惈銆屾櫤鑳借川妫�鎶ュ憡銆嶃�佸璞¢〉鍑虹幇銆屾姤鍛婃ā鏉�/鎶ュ憡瀹炰緥銆嶃�佹棤浠讳綍 mermaid 閿欒妯箙 |
+
+**鏁版嵁搴�**
+
+| 搴� | 鍔ㄤ綔 |
+|---|---|
+| `ruoyi-vue-pro`锛堝鍣� `mysql8` / `2a8dea946ada`锛� | `ALTER TABLE qc_report_instance DROP COLUMN pdf_file_url`锛堝凡鎵ц銆佸凡鍥炶楠岃瘉 14 鍒楋級 |
+| `mom-jhhg` | **鏈夋剰涓嶅姩**锛堝巻鍙查仐鐣欏簱锛屾棤 profile 鎸囧悜锛� |
+| `qc_init_check_tmp` | 涓存椂搴擄紝鐢ㄤ簬瀹炶窇鍚堝苟鑴氭湰锛�**楠岃瘉瀹屽凡 drop** |
+
+> 鈿� 鎻愪氦鎻愰啋锛歚.gitignore:64` 鏈� `/docs/`锛宍docs/` 涓嬬殑鏂版枃浠�**榛樿鏄湭璺熻釜涓旇蹇界暐鐨�**锛�
+> 闇�瑕� `git add -f`锛堟棦鏈夌殑 `docs/sql/config_export_all_20260904.sql`銆乣docs/鏅鸿兘璐ㄦ鎶ュ憡*.md` 閮芥槸杩欎箞杩涙潵鐨勶級銆�
+> `yudao-module-qcreport/` 鏁翠釜妯″潡鐩綍涔熻繕鏄湭璺熻釜鐘舵�併��
+
+**涓�涓『鎵嬩慨鎺夌殑闅愭�� bug**锛歚ReportNoGenerator` 鍘熸潵鏄� `DateTimeFormatter.ofPattern("yyyyMMdd")` +
+`String.format("%04d", seq)`锛屼袱澶勯兘璺熼殢**榛樿 locale**锛�
+榛樿 locale 甯﹀巻娉曟椂锛堝娉板巻锛夊勾浠戒細鍐欐垚 2569锛屾暟瀛楀瓧褰㈤潪鎷変竵鏃朵細鍐欏嚭闃挎媺浼�-鍗板害鏁板瓧銆�
+宸查攣 `Locale.ROOT`锛屽苟琛ヤ簡瀵瑰簲鐨勫洖褰掔敤渚嬨��
+
+### 11.5 猬� 鏈畬鎴愰」锛堟帴鎵嬪厛鐪嬭繖閲岋級
+
+**鍚庣鎺ュ彛杩欓儴鍒嗘病鏈夐仐鐣欓」浜�** 鈥斺�� 涓や釜缂洪櫡宸蹭慨宸插楠岋紝瑙� 搂11.7/搂11.8銆傚墿涓嬬殑閮芥槸銆屼笅涓�杞�嶇殑浜嬶細
+
+| # | 浜嬮」 | 鐘舵�� | 璇存槑 |
+|---|---|---|---|
+| 1 | **鍏ョ珯 HTML Sanitization** | 猬� 鏈疆**鏈夋剰涓嶅仛** | 鏈疆娌℃湁澶栨潵 HTML 鍏ョ珯锛氭ā鏉� Schema 鍙瓨鐢诲竷 JSON锛屽嚭绔� HTML 鐢� `HtmlRenderer` 鐢熸垚涓斿凡鍓ョ `on*` 涓� `javascript:`/`vbscript:`/`data:` 鍗忚锛堟嫤涓嬬殑浼氳繘缂哄彛娓呭崟锛夈�傜瓑 AI/OCR 閭f潯璺紙浼氬甫杩涗换鎰� HTML锛夊紑宸ユ椂鍐嶅仛锛屼袱鑰呬笉閲嶅彔 |
+| 2 | **PDF / Playwright / `system_storage_attachment` 褰掓。** | 猬� 鏈疆鏈紑濮� | 涓嬩竴杞紙闇�鑱旂綉涓嬭浇 Chromium + 閲嶅惎鍚庣锛夈��**绂佹鐢ㄦ埅鍥炬柟寮忕敓鎴� PDF** |
+| 鈥� | 鍓嶇瀹炰緥鍒楄〃/棰勮/璇︽儏椤� | 猬� 鏈紑濮� | 鍚庣鎺ュ彛绋冲畾鍚庡啀鍋氥��**钀藉湴鏃惰涓�骞惰ˉ `qc-report:instance:{query,create,delete}` 鐨勮彍鍗曚笌鎸夐挳鏉冮檺骞跺綊鍏ュ悎骞惰剼鏈樁娈典簩**锛屽惁鍒欓潪瓒呯瑙掕壊璋冭繖浜涙帴鍙d細 403锛堣瑙� 11.3 #12 涓庤仈璋冩柟妗堟枃妗o級 |
+
+### 11.6 鏄庣‘涓嶅仛锛堥伩鍏嶈寖鍥磋敁寤讹級
+
+- `MesQcReportApi` + 鍥涚璐ㄦ鍗曞綊涓�鍖� 鈥斺�� 涓嬩竴杞��
+- 鍓嶇瀹炰緥鍒楄〃/棰勮/璇︽儏椤� 鈥斺�� 鍚庣鎺ュ彛绋冲畾鍚庡啀鍋氥��
+- 缂哄彛娓呭崟钀藉簱锛堜笉鍔� `render_errors` 鍒楋級鈥斺�� 宸叉寜鐢ㄦ埛閫夋嫨锛氬彧鍦ㄥ搷搴旈噷杩斿洖銆�
+- `qc_report_data_source` / `qc_report_rule` / `qc_report_render_record` 涓夊紶鏃� Java 瀵瑰簲鐨勮〃 鈥斺�� 缁存寔鐜扮姸銆�
+
+### 11.7 棣栬疆 HTTP 鑱旇皟璁板綍锛�2026-09-18锛夆�斺�� 27/27 閫氳繃锛岄檮 2 涓湡瀹炵己闄�
+
+鑱旇皟鑴氭湰鍦� `D:/qcl-tmp/`锛�**浠撳簱澶�**锛屼竴娆℃�ч獙鏀跺伐鍏凤紝涓嶆彁浜わ級锛�
+`e2e.mjs` 27 椤归獙鏀� + `preview2.mjs` 棰勮琛屼负鐭╅樀銆傚嚟璇佺敤 `POST /admin-api/system/auth/login`
+锛坙ocal profile 鍏嶉獙璇佺爜锛宍admin/admin123`锛夌洿鎺ュ彇 token锛屼笉璧板墠绔� localStorage銆�
+
+**27/27 PASS锛屽叾涓繖浜涙槸涔嬪墠鍙湁鍗曟祴銆佹病鏈夎繍琛屾椂璇佹嵁鐨�**锛�
+
+| 楠屾敹鐐� | 瀹炴祴缁撴灉 |
+|---|---|
+| 鏁撮摼鎵撻�� | `generate` 鈫� `code=0`锛岀紪鍙� `QR20260918-0001`銆乣id=1`銆乣status=1`銆乣templateVersion=v1.0` |
+| 缂栧彿鏍煎紡 | 姝e垯 `^QR\d{8}-\d{4}$` 鍛戒腑 |
+| 鍒ゅ畾鐪熺殑绠楀嚭鏉ヤ簡 | `snapshot` 閲� 澶栬=FAIL / 闀垮害=PASS / 纭害=FAIL锛宍passRate=33.33%`锛宍total=3 pass=1 fail=2` |
+| **涓庡墠绔紩鎿庨浂婕傜Щ** | 涓婅堪涓夐」鍒ゅ畾涓� `passRate` 涓庡墠绔喕缁� fixture **閫愬�肩浉鍚�** 鈥斺�� 銆屼袱濂楀紩鎿庝細婕傘�嶇殑椋庨櫓灏辨浠庛�屽崟娴嬩繚璇併�嶅崌绾т负銆岀湡瀹炴暟鎹疄娴嬨�� |
+| 蹇収缁撴瀯 | `snapshot` 涓� `context.json` 鍚屾瀯锛沗get` **涓嶅惈** `dataSnapshot` |
+| regenerate 澶嶇幇鎬� | 鍓嶅悗 `renderHtml` **閫愬瓧鐩稿悓**锛屼笖缂栧彿涓嶅彉銆佸簱琛屾暟涓嶅彉 |
+| 閲嶅鏄惧紡缂栧彿 | `code=1070102001`锛宮sg **甯﹀嚭鍏蜂綋缂栧彿** `QR20260918-0001` |
+| 鏃犲凡鍙戝竷鐗堟湰 / 鑽夌鐗堟湰 / 妯℃澘涓嶅瓨鍦� | 鍒嗗埆 `1070101007` / `1070101003` / `1070100000` |
+| 绌� `inspectionItems` / 缂� `templateId` | `1070103000` / `400` |
+| `page` 杩囨护锛坱emplateId+businessType+businessId / 涓嶅尮閰� / 缂栧彿妯$硦锛� | 鍏ㄩ儴绗﹀悎棰勬湡 |
+| 鍒犻櫎 | `delete` 鎴愬姛锛涘垹闄ゅ悗 `get` 杩斿洖 `code=0, data=null`锛�**涓嶆姤閿�**锛夛紱`regenerate` 鎶� `1070102000` |
+
+**鍙﹀纭**锛歚data_snapshot` 瀛樼殑鏄�**鍒ゅ畾鍚�**鐨勪笂涓嬫枃锛涙ā鏉� 5 v1.0 閭f潯 `scope:"item"` 瑙勫垯
+锛坄actualValue >= lowerLimit AND actualValue <= upperLimit`锛夊娌℃湁涓婁笅闄愮殑銆屽瑙傘�嶅垽 FAIL 鈥斺�� 杩欐鏄墠绔紩鎿庣殑琛屼负锛屼笉鏄悗绔畻閿欍��
+
+#### 缂洪櫡 1锛氳蒋鍒犻櫎鐨勬姤鍛婁細姣掓褰撳ぉ鐨勮嚜鍔ㄧ紪鍙凤紙涓ラ噸锛�
+
+**鐜拌薄**锛歚e2e.mjs` 鍑轰欢寰楀埌 `QR20260918-0001`锛坕d=1锛夊悗杞垹闄ゅ畠锛屼笅涓�娆� `generate` 鐩存帴澶辫触锛�
+`1070102001 鑷姩鐢熸垚鎶ュ憡缂栧彿鏃惰繛缁� 5 娆′笌宸叉湁鎶ュ憡鍐茬獊锛岃绋嶅悗閲嶈瘯锛涗篃鍙湪璇锋眰閲屾樉寮忔寚瀹氫竴涓湭琚崰鐢ㄧ殑鎶ュ憡缂栧彿`銆�
+
+**鏍瑰洜**锛歚selectLatestByReportNoPrefix` 鐢ㄧ殑鏄潯浠舵瀯閫犲櫒锛孧yBatis-Plus 鑷姩杩藉姞 `deleted = 0`锛�
+浣� `uk_report_no` 鍞竴绱㈠紩**涓嶈 `deleted`**銆傝蒋鍒犻櫎鍚庯細
+1. 鏉′欢鏋勯�犲櫒鐪嬩笉鍒板綋澶╂渶澶у彿閭h 鈫� `nextSequence` 姣忚疆閮界畻鍥炲悓涓�涓� `0001`锛�
+2. 鎻掑叆姣忔閮芥挒鍞竴绱㈠紩 鈫� 5 娆¢噸璇曟槸 5 娆″悓涓�涓粨鏋滐紝涓嶆槸銆岃繍姘斿樊銆嶏紱
+3. 鍚庢灉鏄�**鍒犺繃涓�浠芥姤鍛婏紝杩欎竴鏁村ぉ灏卞啀涔熷嚭涓嶄簡浠�**锛岃�屼笖鎶ラ敊鏂囨鎶婅矗浠绘帹缁欍�屽苟鍙戝啿绐併�嶏紝鎶婁汉寰�閿欐柟鍚戝紩銆�
+
+**淇**锛坄QcReportInstanceMapper`锛夛細鏀规墜鍐� `@Select` 缁曡繃閫昏緫鍒犻櫎锛屽苟鍙彇缂栧彿鍒楁湰韬�
+锛堜笉蹇呮妸 JSON 蹇収鏁村垪鎷藉嚭鏉ワ級锛�
+
+```sql
+SELECT report_no FROM qc_report_instance
+WHERE report_no LIKE CONCAT(#{prefix}, '%')
+ORDER BY CHAR_LENGTH(report_no) DESC, report_no DESC LIMIT 1
+```
+
+**琛屼负鍙樺寲**锛氱紪鍙�**鍙涓嶅噺锛屽垹鎺夌殑鍙蜂笉鍥炴敹**銆傚垹鎺� `鈥�-0001` 鍚庝笅涓�浠芥槸 `鈥�-0002`銆傚凡鍐欒繘鑱旇皟鏂规銆�
+骞跺彂閲嶈瘯璺緞浠嶇劧淇濈暀锛堢湡姝g殑骞跺彂鎶㈠彿杩樺緱闈犲畠锛夛紝鍙槸涓嶅啀鏄�屽垹闄ゅ悗蹇呭畾瑙﹀彂銆嶃��
+
+**搴撲笂鐨勭‖璇佹嵁**锛堝鍣� `mysql8`锛宍ruoyi-vue-pro`锛夛細
+
+```
+qc_report_instance: id=1 report_no=QR20260918-0001 deleted=1 鈫� 杞垹闄ゅ悗浠嶅湪鐗╃悊琛ㄩ噷
+uk_report_no: Non_unique=0 Column_name=report_no 鈫� 鍞竴绱㈠紩鍙湁 report_no锛屼笉鍚� deleted
+```
+
+鍚屼竴鏉″墠缂�鏌ヨ锛屼袱绉嶅啓娉曠粨鏋滀笉鍚� 鈥斺�� 杩欏氨鏄己闄风殑鍏ㄩ儴鏈哄埗锛�
+
+```sql
+-- 鏂� SQL锛堟妸杞垹闄ょ畻杩涙潵锛夆啋 杩斿洖 QR20260918-0001 鈫� nextSequence 寰� 2 鈫� 鎻掑叆鎴愬姛
+SELECT report_no FROM qc_report_instance WHERE report_no LIKE CONCAT(@prefix,'%')
+ORDER BY CHAR_LENGTH(report_no) DESC, report_no DESC LIMIT 1;
+
+-- 鏃у啓娉曠瓑浠风墿锛堟潯浠舵瀯閫犲櫒鑷姩鍔� deleted=0锛夆啋 涓�琛岄兘鏌ヤ笉鍒� 鈫� nextSequence 寰� 1 鈫� 鎾炲敮涓�绱㈠紩
+SELECT report_no FROM qc_report_instance WHERE report_no LIKE CONCAT(@prefix,'%') AND deleted = 0
+ORDER BY CHAR_LENGTH(report_no) DESC, report_no DESC LIMIT 1;
+```
+
+**杩欐潯淇娌℃湁浠讳綍鍗曟祴瑕嗙洊**锛堟ā鍧楁棤 H2/DB 娴嬭瘯鍩哄骇锛岀己闄峰湪璇� SQL 鑰屼笉鍦� Java 鍒嗘敮閲岋級锛�
+鎵�浠ヤ笂闈㈣繖鏉� SQL 鏄洿鎺ユ嬁鐪熷簱楠岀殑锛涗慨澶嶅悗鐨勮涓鸿闈� 搂11.5 绗� 1 椤圭殑 HTTP 澶嶉獙銆�
+
+#### 缂洪櫡 2锛歚preview` 瑕佹眰鐗堟湰宸插彂甯冿紝鎶婅璁″櫒涓绘祦绋嬪崱姝伙紙涓ラ噸锛�
+
+**鐜拌薄**锛氭ā鏉� 5 鐨� `v1.1`锛堣崏绋匡級涓庢ā鏉� 3 鐨� `v1.0`锛堣崏绋匡紝涓旀槸**搴撻噷鍞竴涓�浠界湡瀹炵敾甯�**锛�14657 瀛楄妭锛�
+璋� `preview` 閮借繑鍥� `1070101003 妯℃澘鐗堟湰鏈彂甯冿紝鏃犳硶鐢熸垚鎶ュ憡`銆�
+
+**鏍瑰洜**锛歚preview()` 澶嶇敤浜嗕负鍑轰欢鍐欑殑 `resolveVersion()`锛岄噷闈㈣皟鐨勬槸 `getPublishedVersion()`銆�
+浣嗚璁″櫒鐨勪富娴佺▼姝f槸銆屼繚瀛樿崏绋� 鈫� 鐐归瑙堛�嶏紝淇濆瓨鍑烘潵鐨勫繀鐒舵槸鑽夌 鈥斺�� 涔熷氨鏄杩欐潯璺緞**涓嶅彲鑳芥垚鍔�**銆�
+鏂规硶涓婄殑 javadoc 鍐欑潃銆岀敤鍝釜妯℃澘鐗堟湰**鍑轰欢**銆嶏紝鏈韩灏辨毚闇蹭簡瀹冩槸琚�熺敤鐨勩��
+
+**淇**锛歚resolveVersion(reqVO, boolean requirePublished)` 鍔犲紑鍏筹紝
+`generate` 浼� `true`銆乣preview` 浼� `false`锛堣蛋 `getVersionByTemplateIdAndVersion`锛夈��
+`getPublishedVersion` 鏌ヤ笉鍒颁細鎶涢敊銆乣getVersionByTemplateIdAndVersion` 杩斿洖 `null`锛屾墍浠ヨˉ浜嗕竴鍙�
+`versionDO == null 鈫� TEMPLATE_VERSION_NOT_EXISTS`銆�
+
+**涓轰粈涔堜笉鏀炬澗 `generate`**锛氬嚭浠朵細鎶婄増鏈彿鍐荤粨杩涘疄渚嬶紝鑰屽疄渚嬮噷**鍙鐗堟湰鍙枫�佷笉璁板唴瀹�**锛�
+鐢ㄨ崏绋垮嚭浠剁瓑浜庣粰鍘嗗彶鎶ュ憡鍩嬩竴棰椼�岀増鏈彿瀵瑰緱涓娿�佸唴瀹瑰凡缁忓彉浜嗐�嶇殑闆凤紱
+棰勮涓嶈惤搴撱�佷笉鍐荤粨鏁版嵁銆佷笉娑堣�楃紪鍙凤紝鑽夌浼氬彉鍦ㄨ繖閲屾病鏈変换浣曞悗鏋溿��
+
+**椤哄甫璁颁竴绗�**锛氬簱閲屽敮涓�涓�浠芥湁鐪熷疄鐢诲竷鐨勭増鏈槸**鑽夌**锛堟ā鏉� 3 v1.0锛夛紝涓旀ā鏉� 3 鐨�
+`current_version` 涓� `NULL` 鈥斺�� 鎵�浠ラ杞仈璋冪殑娓叉煋楠岃瘉鍙兘鐢ㄦā鏉� 5 鐨�**绌虹敾甯�**锛�560 瀛楄妭銆乥ody 涓虹┖锛夈��
+闈炲钩鍑� HTML 鐨勬覆鏌撻獙璇佽缂洪櫡 2 鎸$潃锛屼慨瀹屽悗鎵嶅仛寰椾簡銆�
+
+#### 鑱旇皟閲屼袱涓�屽亣缂洪櫡銆嶏紝鍒噸韪�
+
+- **`500 绯荤粺寮傚父` 涓夋锛屽疄闄呮槸鎴戣嚜宸辩殑閿�**锛歜ash `for` 寰幆閲屽唴鑱斾腑鏂囷紝shell 鎸� GBK 缂栫爜鍙戝嚭鍘伙紝
+ 鍚庣鎶� `tools.jackson.core.exc.StreamReadException: Invalid UTF-8 middle byte 0xe2`
+ 锛堣矾寰勭洿鎸� `ReportContext["inspectionItems"][0]["itemName"]`锛夈�傛崲鎴� node 鑴氭湰鍙� UTF-8 JSON 鍗冲ソ銆�
+ **鏁欒**锛氬甫涓枃鐨勮姹備綋鍒敤 bash 鍐呰仈銆�
+- **`file://` 鎵撲笉寮� `docs/project-business/index.html`**锛歅laywright 绂佹 `file://` 瀵艰埅锛�
+ 璧蜂簡涓复鏃堕潤鎬佹湇鍔″櫒鎵嶉獙鎴愩�傞獙璇佹湰韬槸蹇呰鐨� 鈥斺�� 5 涓敼鍔ㄧ殑 `.mmd` 鐢� mermaid 11 鐨� `mermaid.parse()`
+ 閫愪釜瑙f瀽閫氳繃銆佺偣杩涘鑸覆鏌撳嚭 SVG銆佹棤鎶ラ敊妯箙锛�13 涓ā鍧楀崱鐗囦笌銆屾姤鍛婃ā鏉�/鎶ュ憡瀹炰緥銆嶅璞¢兘鍦ㄣ��
+
+### 11.8 淇鍚庡楠岋紙鍚屾棩锛岄噸鍚悗绔悗锛夆�斺�� 24/24 + 27/27 鍏ㄧ豢
+
+鏂板 `D:/qcl-tmp/real-canvas.mjs`锛堜粨搴撳锛屼竴娆℃�ц剼鏈級銆傚畠瑕佽В鍐充竴涓毦棰橈細**搴撻噷鍞竴鏈夌湡瀹炵敾甯冪殑鐗堟湰鏄崏绋�**
+锛堟ā鏉� 3 v1.0锛�14657 瀛楄妭锛宍rules: []`锛屼笖妯℃澘 3 鐨� `current_version` 涓� `NULL`锛夛紝
+鑰� `generate` 鎸夎璁℃嫆缁濊崏绋裤�傝剼鏈殑鍋氭硶鏄�**寤轰竴涓复鏃舵ā鏉� 鈫� 鎶婃ā鏉� 3 鐨勭敾甯冨鍒舵垚瀹冪殑 v1.0 鈫� 鍙戝竷 鈫� 璺戝叏閾�**锛�
+璺戝畬鍒犲共鍑�銆�**涓嶇妯℃澘 1/3/4/5/6 鐨勪换浣曟棦鏈夋暟鎹��**
+
+| 楠屾敹鐐� | 瀹炴祴缁撴灉 |
+|---|---|
+| 缂洪櫡 2 淇锛歚preview` 鏀捐鑽夌 | 妯℃澘 3 v1.0锛堢湡瀹炵敾甯冿級鈫� `code=0`锛�**HTML 6719 瀛楄妭**锛涙ā鏉� 5 v1.1锛堣崏绋匡級鈫� `code=0` |
+| 缂洪櫡 2 鐨勮竟鐣岋細`generate` 浠嶆嫆鑽夌 | 妯℃澘 3 v1.0 涓庢ā鏉� 5 v1.1 鈫� **閮戒粛鏄� `1_070_101_003`**锛堟湁鎰忕殑涓嶅绉帮紝娌¤椤烘墜鏀炬澗锛� |
+| 缂洪櫡 2 鐨勮繛甯︼細宸插仠鐢ㄧ増鏈篃鍙瑙� | 妯℃澘 1 涓嶄紶 `version`锛坄currentVersion=v1.0`锛宻tatus=2 鍋滅敤锛夆啋 `code=0`锛�468 瀛楄妭锛堥杞繖閲屾槸 `1_070_101_003`锛� |
+| **鐪熷疄鐢诲竷鐨� preview 浜х墿鏄湡娓叉煋** | 6719 瀛楄妭閲屽惈 `鍒ゅ畾缁撹锛氫笉鍚堟牸`銆乣鍚堟牸鐜囷細33.33%`銆佷笁涓楠岄」鍚勪竴琛岋紙`data-qc-repeat` 灞曞紑浜嗭級 |
+| **鐪熷疄鐢诲竷鐨� preview 鈫� generate 涓�鑷�** | `preview.html === get.renderHtml`锛屼袱渚ч兘鏄� 6719 瀛楄妭锛�**閫愬瓧鐩稿悓** |
+| **鐪熷疄鐢诲竷鐨� regenerate 澶嶇幇鎬�** | 閲嶆覆鍓嶅悗 `renderHtml` **閫愬瓧鐩稿悓**锛�6719 鈫� 6719锛夛紝缂栧彿涓嶅彉 |
+| 鐪熷疄鐢诲竷鐨勫垽瀹氳惤杩涘揩鐓� | `passRate=33.33% total=3 pass=1 fail=1`锛宍items=[澶栬:(绌�) 闀垮害:PASS 纭害:FAIL]` |
+| 缂洪櫡 1 淇锛氳蒋鍒犻櫎鍚庝粛鑳藉嚭浠� | 鍑� `鈥�-0003` 鈫� 杞垹闄ゅ畠 鈫� 鍐嶅嚭 `code=0`锛屽緱 `鈥�-0004`锛�**淇鍓嶈繖閲屽繀瀹氭槸 `1_070_102_001`**锛� |
+| 缂洪櫡 1 鐨勮涓猴細缂栧彿鍙涓嶅噺 | `QR20260918-0003 鈫� QR20260918-0004`锛屼弗鏍奸�掑锛屾病鍥炴敹 |
+| 缂洪櫡 1 鐨勪竴鑷达細鏄惧紡鍗犵敤琚蒋鍒犻櫎鐨勫彿浠嶈鎷� | 鎸囧畾 `鈥�-0003` 鈫� `1070102001`锛宮sg 甯﹀嚭鍏蜂綋缂栧彿 |
+| 鍥炲綊锛氶杞� 27 椤瑰叏杩� | `e2e.mjs` 閲嶈窇 **27/27 PASS**锛堝惈缂栧彿鏍煎紡 / 蹇収鍒ゅ畾 / regenerate 閫愬瓧 / 鍚勯敊璇爜 / page / delete锛� |
+| 鍥炲綊锛氶瑙堣涓虹煩闃� | `preview2.mjs` 鐭╅樀鍏ㄩ儴绗﹀悎棰勬湡锛涙ā鏉� 3 涓嶄紶鐗堟湰浠� `1_070_101_007`锛坄currentVersion` 涓� NULL锛�**棰勮涔熷緱鏄惧紡浼犵増鏈�**锛� |
+
+**楠岃瘉杩囩▼涓籂姝g殑涓�涓鍒�**锛堣涓嬫潵鍏嶅緱鍚庝汉閲嶈俯锛夛細
+`real-canvas.mjs` 棣栬窇 `1.3` 鍒� FAIL锛屾柇瑷�銆屼骇鐗� HTML 閲屽簲鍚� `PASS`/`FAIL` 瀛楁牱銆嶁�斺�旀槸**鎴戠殑鏂█鍐欓敊浜�**锛屼笉鏄己闄枫��
+妯℃澘 3 鐨勭敾甯冩樉绀虹殑鏄� `resultText`锛堜腑鏂� `鍚堟牸` / `涓嶅悎鏍糮 / `寰呭垽瀹歚锛夛紝
+`result`锛坄PASS`/`FAIL`锛夋槸鏁版嵁灞傛満鍣ㄥ�笺�傚凡鎶婃柇瑷�鏀规垚妫�鏌ヤ腑鏂囨枃妗� + 缂哄彛娓呭崟锛屾敼鎴� 24/24銆�
+**缁撹**锛氫骇鐗� HTML 閲屾悳涓嶅埌 `PASS` 涓嶄唬琛ㄦ病鍒ゅ畾锛涜繖鏉″凡鍐欒繘鑱旇皟鏂规锛屽厤寰楀墠绔篃杩欎箞璇垽銆�
+
+**椤哄甫纭鐨勪竴鏉″紩鎿庤涔�**锛氭棦鏃犺鏍间笂涓嬮檺銆佸張娌″懡涓换浣曡鍒欑殑妫�楠岄」 鈫� `result` 涓虹┖銆乣resultText` 涓� `寰呭垽瀹歚锛�
+**涓嶈鍏� `passCount`/`failCount` 浣嗚鍏� `total`**锛堟墍浠ヤ細鍑虹幇 `total=3 pass=1 fail=1`锛夛紝
+鍚屾椂杩涚己鍙f竻鍗曪紙銆岀 1 椤广�屽瑙傘�嶆病鏈夎鏍间笂涓嬮檺涔熸病鏈夊垽瀹氳鍒欙紝鏃犳硶鍒ゅ畾銆嶏級銆傛ā鏉� 3 鐨� `rules` 鏄┖鏁扮粍锛�
+姝eソ鎾炰笂杩欎釜鍒嗘敮 鈥斺�� 妯℃澘 5 鏈夐偅鏉� `scope:"item"` 瑙勫垯锛屾墍浠ュ悓鏍风殑涓夐」鍦ㄦā鏉� 5 涓婃槸 FAIL/PASS/FAIL銆�
+
+**鏀跺熬锛堝凡鎵ц锛�**锛氫复鏃舵ā鏉� 8/9銆佷复鏃剁増鏈� 8/9銆佷互鍙婃湰杞骇鐢熺殑 9 琛屾姤鍛婂疄渚嬪叏閮ㄧ‖鍒犻櫎銆�
+鍥炶鏍稿锛歚qc_report_template` **5 琛�**銆乣qc_report_template_version` **7 琛�**銆乣qc_report_instance` **0 琛�**銆�
+`qc_report_render_record` **0 琛�** 鈥斺�� 涓庡紑宸ュ墠涓�鑷达紝妯℃澘 1/3/4/5/6 鍙婂叾 `current_version` 鍘熸牱鏈姩銆�
+
+### 11.9 鈿� 宸查獙璇� / 鏈獙璇侊紝蹇呴』鍒嗗紑璇�
+
+**宸茬粡鎷垮埌瀹炴祴璇佹嵁鐨�**锛堣繖浜涘彲浠ヨ銆岄獙璇佽繃銆嶏級
+
+| 缁撹 | 璇佹嵁 |
+|---|---|
+| 缂栬瘧閫氳繃 | `mvn compile -pl yudao-module-qcreport -am -q` exit 0锛堜袱涓己闄蜂慨瀹屽悗閲嶈窇浠� exit 0锛� |
+| 43 椤规祴璇曞叏缁� | `mvn -pl yudao-module-qcreport test` 鈫� `Tests run: 43, Failures: 0, Errors: 0`锛堝鎷� 3 + 鍒ゅ畾 23 + Codec 7 + 缂栧彿 7 + 瀛橀噺鍏煎 3锛� |
+| 鍒ゅ畾骞傜瓑銆佸揩鐓у線杩斿彲澶嶇幇 | `ReportContextCodecTest.roundTripReproducesHtml` 鏂█涓ゆ HTML 閫愬瓧鐩稿悓 |
+| 缂栧彿鐢熸垚 locale 鏃犲叧 | `ReportNoGeneratorTest.independentOfDefaultLocale` 鍦ㄦ嘲鍘� + 娉版枃鏁板瓧 locale 涓嬩粛寰� `QR20260918-0007` |
+| **鍑轰欢鎺ュ彛鏁撮摼鍙敤锛堜袱杞級** | 棣栬疆 `e2e.mjs` 27/27锛涗慨澶嶅悗閲嶈窇浠� 27/27锛沗real-canvas.mjs` 24/24銆傛瘡椤归兘璧扮湡瀹� HTTP 鏁撮摼锛堥壌鏉� 鈫� 鍙傛暟缁戝畾 鈫� 缂栨帓 鈫� 钀藉簱 鈫� 搴忓垪鍖栵級 |
+| **鍚庣鍒ゅ畾涓庡墠绔紩鎿庨浂婕傜Щ** | 妯℃澘 5 v1.0锛堟湁瑙勫垯锛夆啋 FAIL/PASS/FAIL銆乣passRate=33.33%`锛屼笌鍓嶇 fixture 閫愬�肩浉鍚� |
+| **闈炲钩鍑� HTML 鐨勬覆鏌撲笌澶嶇幇** | 妯℃澘 3 鐨勭湡瀹炵敾甯冿紙14657 瀛楄妭锛夆啋 6719 瀛楄妭浜х墿锛沗preview === get.renderHtml` 涓� `regenerate` 鍓嶅悗閫愬瓧鐩稿悓 |
+| **涓や釜缂洪櫡鐨勪慨澶嶅凡琚楠�** | 杞垹闄ゅ悗浠嶈兘鍑轰欢涓旂紪鍙烽�掑锛沗preview` 鏀捐鑽夌鑰� `generate` 浠嶆嫆鑽夌锛堣 搂11.8锛� |
+| `pdf_file_url` 宸蹭粠杩愯搴撳垹闄� | 瀹瑰櫒 `mysql8`锛坄@@hostname=2a8dea946ada`锛夊洖璇� `information_schema`锛歚ruoyi-vue-pro.qc_report_instance` **14 鍒� / `has_pdf_url`=0** |
+| 鍚堝苟鍒濆鍖栬剼鏈湪绌哄簱鑳戒竴閿窇閫� | 涓存椂搴� `qc_init_check_tmp` 瀹炶窇鏁翠唤 1.2 MB 鏂囦欢 鈫� EXIT=0锛�419 琛� / 6 寮� `qc_report_*` / 6 瀛楀吀绫诲瀷 / 21 瀛楀吀鏁版嵁 / 1258 鑿滃崟 / 2349 `system_role_menu`锛�**楠屽畬宸� drop** |
+| 涓氬姟鍙鍖栧閲忓湪娴忚鍣ㄩ噷鐪熺殑娓叉煋鍑烘潵浜� | 5 涓敼鍔ㄧ殑 `.mmd` 鍦� mermaid 11 涓� `parse()` 鍏� ok锛涜川閲忔祦绋嬪浜嗐�屽嚭浠躲�嶄竴琛岋紱13 涓ā鍧楀崱鐗囷紱瀵硅薄椤垫湁銆屾姤鍛婃ā鏉�/鎶ュ憡瀹炰緥銆� |
+
+**杩樻病鏈変换浣曞疄娴嬭瘉鎹殑**锛堣繖浜�**涓嶈兘璇淬�屽彲鐢ㄣ��**锛�
+
+- **骞跺彂鑷姩缂栧彿鐨勯噸璇曡矾寰勬病鍘嬭繃**銆傞�昏緫鍦紙鎾� `uk_report_no` 灏遍噸绠楀簭鍙峰啀璇曪紝鏈�澶� 5 娆★級锛屼絾娌℃湁骞跺彂娴嬭瘯銆�
+ 缂洪櫡 1 淇鍚庯紝杩欐潯璺緞鍙細鍦�**鐪熸鐨勫悓鏃舵姠鍙�**鏃惰Е鍙戯紝姝e父浣跨敤涓嶈鐪嬪埌瀹冦��
+- **缂洪櫡 1 鐨勪慨澶嶆病鏈夊崟娴嬭鐩�**銆傛ā鍧楁病鏈� H2/DB 娴嬭瘯鍩哄骇锛岃�岀己闄峰湪璇� SQL 涓嶅湪 Java 鍒嗘敮閲�
+ 锛坄@Select` 缁曡繃閫昏緫鍒犻櫎锛夈�傚畠鐜板湪鍙湁銆岀湡搴撲笂璺戜袱绉嶅啓娉曠殑瀵规瘮 + HTTP 澶嶉獙銆嶄袱绫昏瘉鎹紝
+ 涓嶈鍘� `ReportNoGeneratorTest` 閲屾壘瀹冿紝閭i噷娴嬩笉鍒般��
+- **鍓嶇瀹炰緥鍒楄〃/棰勮/璇︽儏椤垫病鏈夊仛锛屾墍浠ユ病鏈変换浣� UI 楠岃瘉**銆備笟鍔″彲瑙嗗寲鐨勬祻瑙堝櫒楠岃瘉涓嶈兘绠椾綔銆屽疄渚嬮〉琚獙璇佽繃銆嶃��
+- **鍓嶇杩樻病鎺� `preview`**锛坄grep -r "instance/preview" mom-pro2-before/src` 鏃犲懡涓級锛岃璁″櫒鐨勯瑙堟寜閽粛璧拌�侀�昏緫銆�
+- **`qc-report:instance:{query,create,delete}` 鏉冮檺鐮佹病鍏ュ簱**锛岄潪瓒呯瑙掕壊璋冭繖浜涙帴鍙d細 403锛堝墠绔〉闈㈣惤鍦版椂涓�骞惰ˉ锛夈��
+- **绾ц仈鍒犻櫎 / 鏁版嵁鏉冮檺 / 瀵煎嚭** 閮戒笉鍦ㄦ湰杞寖鍥达紱`GENERATING`/`FAILED` 涓や釜鐘舵�佹殏鏈娇鐢紱缂哄彛娓呭崟涓嶈惤搴撱��
+- PDF 閾捐矾锛圥laywright + `system_storage_attachment` 褰掓。锛�**鏈紑濮�**銆�
+
+> **鍑嗙‘鐨勮娉�**锛氬嚭浠舵帴鍙o紙鍙仛 HTML锛�**鍚庣閮ㄥ垎宸插畬鎴愬苟涓よ疆瀹炴祴閫氳繃**锛�
+> 浣嗗畠**杩樻病鏈変换浣曞墠绔〉闈㈡帴鍏�**锛屾潈闄愮爜涔熻繕娌¤繘 `system_menu`銆�
+> 涓嶈鎶娿�孒TTP 鑱旇皟鍏ㄧ豢銆嶈鎴愩�屽姛鑳藉凡涓婄嚎銆嶏紝涔熶笉瑕佹妸銆屼笟鍔″浘娓叉煋姝e父銆嶈鎴愩�屽疄渚嬮〉楠岃瘉杩囥�嶃��
+
+## 鍗佷簩銆丳DF 鍑轰欢锛圥hase 3 绗� 5 姝ワ級鈥斺�� 鉁� 鐪熷疄 HTTP 鑱旇皟 + 瑙嗚楠屾敹宸插畬鎴愶紙8 娆$湡瀹炲鍑恒��7 鏉℃覆鏌撹褰曘��3 椤典腑鏂� PDF 宸茬湅杩囷級锛涴煙� 椤电湁淇涓庝笁鏉¢敊璇垎鏀粛寰呭楠�
+
+> 鐩爣锛氭妸瀹炰緥閲屽凡瀛樼殑浜х墿 HTML **鐢卞悗绔皟 Chromium 鎵撳嵃鎴� PDF**锛屽綊妗h繘闄勪欢搴擄紝鍓嶇鍙嬁涓嬭浇鍦板潃銆�
+> 搂30 鏄庣‘绂佹銆屾瘡娆¤姹� launch 娴忚鍣� 鈫� 鐢熸垚 PDF 鈫� close 娴忚鍣ㄣ�嶏紝搂41 瑕佹眰鐣欐覆鏌撹褰曘��
+
+### 12.1 浜や粯鐗�
+
+| 灞� | 鏂囦欢 | 鑱岃矗 |
+|---|---|---|
+| 閰嶇疆 | `config/QcReportPdfProperties.java` | `yudao.qcreport.pdf` 鍓嶇紑锛歚enabled` / `channel` / `executable-path` / `concurrency`(2) / `timeout-ms`(30s) / `show-page-number` / `browser-args` |
+| 绾帴缂� | `service/render/PdfPrintOptions.java` | **绾嚱鏁�**锛氱焊寮犻厤缃� 鈫� 鎵撳嵃鍑犱綍 + 椤佃剼/椤电湁妯℃澘 + 浠呬緵鎵撳嵃鐨勫姞鍥� CSS銆備笉渚濊禆 Spring銆佷笉渚濊禆 Playwright锛屽洜姝ゅ彲鍗曟祴 |
+| 娴忚鍣ㄦ睜 | `service/render/BrowserManager.java` | Playwright 鐢熷懡鍛ㄦ湡锛歚volatile Semaphore` 闄愬苟鍙戙�乣synchronized(browserLock)` 淇濊瘉娴忚鍣ㄥ疄渚嬪敮涓�銆佸穿浜嗚兘閲嶅缓骞舵姤 `RESTARTED` |
+| 鎵撳嵃 | `service/render/PdfRenderService.java` | 杞藉叆 HTML 鈫� `addStyleTag` 娉ㄥ叆鎵撳嵃 CSS 鈫� `page.pdf()`銆傝繑鍥� `PdfResult(content, pdfDurationMs, browserStatus)` |
+| 鍑轰欢渚� | `service/instance/QcReportInstanceServiceImpl#exportPdf` + `PdfArchiveResult` + `QcReportInstancePdfRespVO` | 鎵撳疄渚嬪凡瀛� HTML 鈫� 瀛� blob 鈫� 鎹㈤檮浠� 鈫� 鍐欐覆鏌撹褰� |
+| 绔偣 | `POST /qc-report/instance/pdf?id=` | 鏉冮檺鐮� `qc-report:instance:export` |
+| 鐣欑棔 | `QcReportRenderRecordDO` / `Mapper` / 琛� `qc_report_render_record` | 搂41锛歚reportId` `templateId` `businessId` `renderStartTime/EndTime` `renderDuration` `pdfDuration` `browserStatus` `errorStack` |
+| 渚濊禆 | `yudao-module-qcreport/pom.xml` | `com.microsoft.playwright:playwright` |
+| 閰嶇疆 | `application-local.yaml` + `application-test.yaml` | `yudao.qcreport.pdf` 鏁存锛坄channel: chrome`锛屾湰鏈哄凡瑁� Chrome锛� |
+
+### 12.2 涓冧釜鍒绘剰鐨勮璁¢�夋嫨
+
+| 閫夋嫨 | 鐞嗙敱 |
+|---|---|
+| **鎵撶殑鏄疄渚嬮噷宸插瓨鐨� HTML锛屼笉閲嶆覆** | 銆岃鎯呴〉鐪嬪埌鐨勩�嶄笌銆屾墦鍑烘潵鐨勩�嶅繀鐒跺嚭鑷悓涓�浠藉瓧鑺傘�傝嫢閲嶆覆锛岄〉闈笂鏄柊鎺掔増銆佷笅杞藉埌鐨勬槸鏃ф枃浠讹紝浼氶潤榛樹笉涓�鑷� |
+| **鍑犱綍涓�寰嬩粠 `PageSizes.resolve` 鍙�** | 涓� `HtmlRenderer` 鍐欒繘 HTML 鐨勯偅琛� `@page { size: 鈥�; margin: 鈥�; }` **鍚屾簮銆佸悓涓�涓暟瀛楁牸寮忓寲鍑芥暟**锛坄Numbers.toString`锛夛紝鍥犳涓嶅瓨鍦ㄣ�岄瑙� 210mm銆丳DF 鎵� 210.5mm銆嶈繖绫绘紓绉汇�傜敤 `String.format` 浼氬紩鍏� locale 宸紓骞惰緭鍑� `210.0` |
+| **`PRINT_CSS` 涓嶈繘娓叉煋寮曟搸鐨� `BASE_CSS`** | 浜х墿 HTML 涓庡墠绔喕缁撴牱渚嬫槸**閫愬瓧姣斿**鐨勶紙`FrontendConformanceTest`锛夛紝鍔� `BASE_CSS` 浼氳瀛橀噺鎶ュ憡鐨勩�岄噸鏂扮敓鎴愩�嶇粨鏋滃彉鏍枫�傛墍浠ュ姞鍥烘牱寮忥紙琛ㄥご璺ㄩ〉閲嶅銆侀伩鍏嶅厓绱犺鍒囨柇銆佸己鍒舵墦鍗拌儗鏅壊锛夎蛋 Playwright `addStyleTag` 鍗曠嫭娉ㄥ叆 |
+| **椤电湁妯℃澘鏄惧紡缁欎竴涓┖ `<div>`** | `displayHeaderFooter=true` 鑰� `headerTemplate` 鐣欑┖鏃讹紝Chromium 浼氱敤瀹冭嚜宸辩殑榛樿椤电湁锛氬乏涓婅鎵撳嵃鏃ユ湡銆佸彸涓婅鏂囨。鏍囬銆傞偅涓や覆娌′汉瑕佽繃锛岄〉鐪夐噷鐨勬椂闂磋繕瀹规槗琚褰撴垚鎶ュ憡鍑哄叿鏃堕棿 |
+| **褰掓。涓夋椤哄簭锛氬瓨鏂� blob 鈫� 鍒犳棫闄勪欢 鈫� 缁戞柊闄勪欢** | `bindAttachments` 鍙崲鍏宠仈銆�**涓嶅垹鏃� blob**锛屼笉鍏堝垹灏变細姣忓涓�娆″湪纾佺洏涓婂鐣欎竴浠芥病浜鸿棰嗙殑 PDF锛涜�屻�屽厛鍒犲悗瀛樸�嶅張浼氬湪瀛樻。澶辫触鏃舵妸杩樺ソ鐨勬棫 PDF 涓�璧峰紕涓€�傛墍浠ユ柊 blob 鍏堣惤鍦帮紝鍐嶅垹鏃х殑锛屾渶鍚庣粦瀹� |
+| **`regenerate` 鍗充綔搴熷凡褰掓。 PDF** | 浜х墿 HTML 鎹簡锛屽啀鐣欑潃鏃� PDF 灏辨槸銆岄〉闈㈡槸鏂版帓鐗堛�佷笅杞藉埌鐨勬槸鏃ф枃浠躲�嶇殑闈欓粯涓嶄竴鑷淬�傚畞鍙綔搴燂紙闅忔椂鑳藉啀瀵间竴娆★級 |
+| **澶辫触涔熷啓娓叉煋璁板綍** | `catch` 閲屽厛鍐欎竴鏉″甫寮傚父鏍堢殑璁板綍鍐嶆妸寮傚父鍘熸牱鎶涘嚭锛屼笉鍚� |
+
+`exportPdf` 鐢ㄧ殑鏄� `getVersionByTemplateIdAndVersion` 鑰�**涓嶈姹傜増鏈綋鍓嶄粛宸插彂甯�** 鈥斺�� 涓� `regenerate` 鍚屼竴鍙e緞锛氬巻鍙叉姤鍛婁笉璇ュ洜涓虹増鏈悗鏉ヨ鍋滅敤灏卞涓嶅嚭鏉ャ��
+
+### 12.3 瀹炴祴璇佹嵁
+
+#### 12.3.1 缂栬瘧 + 鍗曟祴灞�
+
+| 缁撹 | 璇佹嵁 |
+|---|---|
+| 缂栬瘧閫氳繃 | `mvn compile -pl yudao-module-qcreport -am -q` exit 0 |
+| 51 椤规祴璇曞叏缁� | `mvn -pl yudao-module-qcreport test` 鈫� **51 椤� 0 澶辫触**锛�43 鈫� 51锛屾柊澧� `PdfPrintOptionsTest` **8 椤�**锛� |
+| 绾稿紶鍑犱綍涓� HTML 鍚屾簮 | `PdfPrintOptionsTest` 鏂█ width/height/margin 鐨� CSS 鏂囨湰涓� `PageSizes.resolve` + `Numbers.toString` 鐨勪骇鐗╅�愬瓧涓�鑷达紙鍚� A3/A5/Letter 涓庢í绔栧悜锛� |
+| 椤佃剼妯℃澘鑷甫鍐呰仈鏍峰紡 | `PdfPrintOptionsTest` 鏂█鍚� `pageNumber` / `totalPages` 鍗犱綅绗︿笌鍐呰仈 `font-size`锛圥laywright 鐨� header/footer 妯℃澘涓嶈繘娴忚鍣ㄩ粯璁ゆ牱寮忥紝涓嶅啓鍐呰仈灏辨槸 0 鍙峰瓧鐪嬩笉瑙侊級 |
+| 椤电湁妯℃澘闈� null | `PdfPrintOptionsTest` 鏂█ `HEADER_TEMPLATE` 闈炵┖瀛楃涓� |
+| `PRINT_CSS` 鏈硠杩涙覆鏌撳紩鎿� | `FrontendConformanceTest` 浠� 3/3 缁匡紙涓庡墠绔喕缁撲骇鐗╅�愬瓧姣斿锛夛紝璇存槑 `BASE_CSS` 娌¤鍔ㄨ繃 |
+
+#### 12.3.2 鐪熷疄 HTTP 灞傦紙8 娆$湡瀹炲鍑鸿姹傦級
+
+鍏ㄩ儴鍙栬嚜 `logs/yudao-server.log` 鐨� `ApiAccessLogInterceptor`锛屼氦鍙夋牳瀵� `qc_report_render_record`銆乣system_storage_attachment`銆乣system_storage_blob` 涓庣鐩樼洰褰曪細
+
+| # | 瀹炰緥 | 鍙戣捣鏃跺埢 | 鑰楁椂 | 缁撴灉 |
+|---|---|---|---|---|
+| 1 | 22 `QR20260918-0001` | 21:14:17 | **611 249 ms** | 鉂� 澶辫触锛歚java.lang.RuntimeException: Failed to create driver 鈥� com.microsoft.playwright.impl.driver.Driver.createAndInstall` |
+| 2 | 22 `QR20260918-0001` | 21:21:28 | **628 741 ms** | 鉁� 鎴愬姛锛堥娆℃垚鍔燂紱Playwright 棣栨浣跨敤瑕佽 driver + Chromium锛屾墍浠ユ參鍒� 10 鍒嗛挓锛� |
+| 3 | 23 `QR20260918-0002` | 21:32:13 | 921 ms | 鉁� 鎴愬姛 |
+| 4 | 23 `QR20260918-0002` | 21:32:14 | 904 ms | 鉁� 鎴愬姛锛堥噸澶嶅鍑猴級 |
+| 5 | 23 `QR20260918-0002` | 21:32:15 | 871 ms | 鉁� 鎴愬姛锛堥噸澶嶅鍑猴級 |
+| 6 | 24 `QR20260918-0003` | 21:32:16 | 868 ms | 鉁� 鎴愬姛 |
+| 7 | 25 `PG20260918001` | 21:34:20 | 1 316 ms | 鉁� 鎴愬姛锛�3 椤典腑鏂� PDF锛� |
+| 8 | 26 `ZZ-DIRTY-HTML-TEST` | 21:40:22 | 47 ms | 鉂� 澶辫触锛氬疄渚� `render_html` 涓虹┖ 鈫� `REPORT_INSTANCE_HTML_MISSING`锛�**鍦� try 涔嬪墠**鎶涳紝鏁呮湭鍐欐覆鏌撹褰� |
+
+- **鏁存潯閾捐矾璧伴�氫簡**锛氶壌鏉� 鈫� 鍙傛暟缁戝畾 鈫� 鍙栧疄渚� 鈫� 鍙栫増鏈� 鈫� Playwright 鍚姩 鈫� 鎵撳嵃 鈫� 瀛� blob 鈫� 鍒犳棫闄勪欢 鈫� 缁戞柊闄勪欢 鈫� 鍐欐覆鏌撹褰曘��
+- **鍐风儹鍚姩鑰楁椂宸� 3 涓暟閲忕骇**锛氶娆℃垚鍔� 628 741 ms锛堣 driver + Chromium锛夛紝姝ゅ悗绋冲畾鍦� **47鈥�1 316 ms**銆傞儴缃叉椂鑻ユ妸杩欐绠楄繘璇锋眰瓒呮椂锛屽墠绔偅鏉� axios 涓庣綉鍏宠秴鏃堕兘瑕佹斁瀹斤紙鍓嶇鏈疆鐨� AI 閭f潯宸插崟鐙斁瀹藉埌 180 绉掞紝PDF 杩欐潯鍚屾牱闇�瑕侊級銆�
+- **娓叉煋璁板綍纭疄鍐欏叆浜�**锛歚qc_report_render_record` 7 琛屻�傚け璐ラ偅娆★紙#1锛夌暀浜嗗畬鏁村紓甯告爤锛沗browser_status` 瀹炴祴瑙傛祴鍒� `RESTARTED`锛�#2锛屾祻瑙堝櫒瀹炰緥鏄噸寤哄嚭鏉ョ殑锛変笌 `READY`锛�#3鈥�#7锛夈��#8 鏃犺褰曟槸**璁捐濡傛**锛堟牎楠屽湪 try 涔嬪锛夈��
+- **娓叉煋璁板綍鐨勬帓鏌ヤ环鍊艰鐪熷疄楠岃瘉**锛歚Drivers.createAndInstall` 杩欐潯鏍堝氨鏄潬娓叉煋璁板綍琛ㄦ嬁鍒扮殑锛屽惁鍒欏彧鏈変竴琛� 500 鏃ュ織銆�
+
+#### 12.3.3 瑙嗚灞傦紙3 椤典腑鏂� PDF 宸查�愰〉鐪嬭繃锛�
+
+瀹炰緥 25锛坄PG20260918001`锛屾ā鏉� 11锛夋槸涓撻棬閫犵殑瑙嗚 fixture锛�60 琛岃〃鏍� + 鍐呭祵绾㈢豢娓愬彉鍥撅紝瀵煎嚭鍚庡瓨涓� `D:/qcl-tmp/verify-60.pdf`锛�87 842 瀛楄妭锛夛紝閫愰〉鎴浘 `pdf-60-p1.png` / `pdf-60-p2.png` / `pdf-60-p3-full.png`銆�
+
+| 缁撹 | 璇佹嵁 |
+|---|---|
+| 涓枃姝e父 | 鏍囬銆屾潵鏂欐楠屾姤鍛婏紙60椤孤疯法椤甸獙鏀讹級銆嶄笌琛ㄥ唴涓枃鍧囦负鐭㈤噺鍙鏂囨湰锛屾湭鍑虹幇鏂瑰潡/涔辩爜锛堟湰鏈� Chrome + 寰蒋闆呴粦锛� |
+| 鑳屾櫙鑹�/鍥剧墖鎵撳嚭鏉ヤ簡 | 鍐呭祵娓愬彉鍥惧湪 PDF 閲屽彲瑙� 鈫� `print-color-adjust: exact` 鐢熸晥 |
+| 璺ㄩ〉涓庨〉鑴� | 3 椤碉紱琛ㄦ牸浠庣 2 椤垫孩鍒扮 3 椤碉紱椤佃剼椤电爜姝e父鍑虹幇 |
+| 鈿� **闀胯〃浼氭妸棣栭〉椤剁┖** | `PRINT_CSS` 閲� `table { break-inside: avoid }` 浣滅敤浜庢暣寮犺〃锛屾祻瑙堝櫒涓轰簡銆屼笉鍒囨柇琛ㄦ牸銆嶆妸 60 琛岃〃鏁翠綋鎺ㄥ埌绗� 2 椤� 鈫� **绗� 1 椤靛彧鏈夋姤鍛婂ご鍜屼竴寮犲浘锛屼笅闈㈠ぇ鐗囩┖鐧�**銆傝繖鏄凡瑙傛祴鍒扮殑鎺掔増缂洪櫡锛堜笉鏄姤閿欙級锛岄暱鏈熻〃鏍兼姤鍛婇渶瑕佹妸 `table` 浠� `break-inside: avoid` 鍚嶅崟閲屾憳鎺夛紝鍙繚鐣� `tr, td, th, img` |
+| 鈿� **椤电湁淇娌¤刀涓婅繖娆″鍑�** | 绗� 1 椤甸〉鐪変粛鏄� Chromium 榛樿鐨勩�宍2026/9/18 21:34` + 鏂囨。鏍囬銆嶃�俙PdfPrintOptions` 鐨� `HEADER_TEMPLATE = "<div></div>"` 鍐欎簬 **21:36**锛岃�屾渶鍚庝竴娆″鍑烘槸 **21:34:21** 鈥斺�� 鍗充慨澶�**灏氭湭琚獙璇佽繃**锛堣 12.4锛� |
+
+#### 12.3.4 褰掓。骞傜瓑鎬э紙瀹炰緥 23 杩炲 3 娆★級
+
+| 缁撹 | 璇佹嵁 |
+|---|---|
+| 搴撻噷涓嶇疮绉敓鏁堥檮浠� | `system_storage_attachment` 涓� `record_id=23` 鏈� 3 琛岋紝浣�**鍓嶄袱琛屼笌绗� 3 琛屽叏閮� `deleted=1`**锛堥�昏緫鍒犻櫎锛夆啋 浠讳竴鏃跺埢鐢熸晥鐨勫彧鏈� 1 鏉� |
+| 鏃� blob 琚湡鍒狅紙涓嶆槸绱Н锛� | `system_storage_blob` 6 琛屽叏涓� `deleted=1`锛涚鐩樼洰褰� `D:/uploads/2026/0918/` **涓虹┖** 鈫� 銆屽瓨鏂� blob 鈫� 鍒犳棫闄勪欢锛堢骇鑱斿垹鏃� blob 涓庣鐩樻枃浠讹級鈫� 缁戞柊闄勪欢銆嶄笁姝ョ‘瀹炴妸涓婁竴浠� PDF 娓呮帀浜� |
+| 閲嶅瀵煎嚭鐨勮涔夎瀹炴祴纭 | 涓� `docs/qc_report_instance_frontend_integration.md` 鐨勮〃杩颁竴鑷达細**涓嶄細瓒婂瓒婂銆佷篃涓嶄細鐣欏鍎挎枃浠�** |
+| 娓呯悊褰诲簳 | 瀹炰緥 22鈥�26銆佹ā鏉� 5/11 鍧囧凡杞垹锛岀鐩樻棤娈嬬暀 |
+
+> **涓�搴﹁鎴戣鍒�**锛氬彧鎸夎鏁扮湅浼氫互涓恒�屽疄渚� 23 鐣欎笅 3 鏉¢檮浠� + 3 涓� blob = 绱Н bug銆嶃�傚疄闄呮槸婕忕湅浜� `deleted` 浣� 鈥斺�� yudao 鐨� `deleteByIds` 鏄�昏緫鍒犻櫎锛岃杩樺湪銆佷絾宸插け鏁堬紝鐗╃悊鏂囦欢宸蹭粠纾佺洏鍒犻櫎銆�**鏌� yudao 鐨勪换浣曞垹鏀圭粨鏋滈兘蹇呴』鏄惧紡鐪� `deleted`**锛屽惁鍒欎細鎶婅蒋鍒犺璇绘垚娈嬬暀銆�
+
+### 12.4 鈿� 宸查獙璇� / 鏈獙璇侊紙鏈妭鐨勯噸鐐癸級
+
+**宸查獙璇�**锛堟湁瀹炴祴璇佹嵁锛屽彲浠ヨ銆屽彲鐢ㄣ�嶏級锛�
+
+- 鏁存潯 HTTP 閾捐矾锛�8 娆$湡瀹炶姹傘��7 鏉℃覆鏌撹褰曪紝鎴愬姛/澶辫触涓ゆ潯璺緞閮借蛋杩囷紙12.3.2锛夈��
+- 娴忚鍣ㄥ惎鍔ㄥけ璐ョ殑**鐪熷疄鎶ラ敊涓庣暀鐥�**锛�#1锛�611 249 ms锛宍Drivers.createAndInstall` 鏍堣繘浜嗘覆鏌撹褰曡〃锛夈��
+- 绌� `render_html` 鐨勬嫆缁濊矾寰勶紙#8锛�47 ms锛夈��
+- 绋冲畾鎬佹�ц兘锛�47鈥�1 316 ms锛涘喎鍚姩 628 741 ms銆�
+- `.doc` 涔嬪鐨�**涓枃娓叉煋銆佽儗鏅壊/鍥剧墖鎵撳嵃銆佽法椤点�侀〉鑴氶〉鐮�**锛�12.3.3锛夈��
+- 褰掓。涓夋椤哄簭鐨勫箓绛夋�э紙12.3.4锛夈��
+
+**鏈獙璇�**锛�**涓嶈兘璇淬�屽彲鐢ㄣ��**锛夛細
+
+- **`HEADER_TEMPLATE = "<div></div>"` 淇灏氭湭澶嶉獙銆�** 浠g爜宸茬紪璇戙�佸崟娴嬪彧鏂█銆岄潪绌恒�嶏紱鏈�鍚庝竴娆″鍑猴紙21:34:21锛夌殑 PDF 绗� 1 椤�**浠嶇劧甯︾潃 Chromium 榛樿椤电湁**锛岃�屼慨澶嶅啓浜� 21:36 鈥斺�� 娌℃湁涓�娆″鍑烘槸鍦ㄤ慨澶嶄箣鍚庤窇鐨勩��**杩欐槸鏈疆鏈�璇ュ厛琛ョ殑涓�鏉�**锛氶噸鍚悗绔涓�娆� PDF锛岀湅绗� 1 椤靛乏涓婅鏄惁杩樻湁鏃ユ湡銆�
+- **`yudao.qcreport.pdf.enabled=false 鈫� RENDER_PDF_DISABLED(1_070_103_008)` 鏈疄娴�**锛堥渶涓存椂鏀归厤缃� + 閲嶅惎锛夈��
+- **鎵撳嵃澶辫触 / 瀛樻。澶辫触涓ゆ潯閿欒鍒嗘敮鏈疄娴�**锛坄1_070_103_005/006`锛夈�傛姤鏂囧甫浜嗗疄闄呭師鍥狅紝浣嗘病浜鸿窇杩囥��
+- **骞跺彂闂革紙`concurrency=2`锛変笌鎵撳嵃瓒呮椂锛�30s锛夋湭鍘嬭繃**銆俙BrowserManager` 鏈� Semaphore锛屼絾娌″仛骞跺彂娴嬭瘯锛涙帓闃熻秴 30 绉掔殑 `1_070_103_007` 浠庢湭瑙﹀彂杩囥��
+- **`regenerate` 浣滃簾宸插綊妗� PDF** 鏈疄娴嬶紙`deleteAttachmentsByRecord` 鐨勮皟鐢ㄤ綅缃凡鏍稿锛沗deleteInstance` 閭f潯娓呯悊璧伴�氬苟鐣欎簡鐥曪級銆�
+- **闀胯〃鐨勯椤电暀鐧�**锛�12.3.3锛夊凡瑙傛祴銆佹湭淇��
+
+> **鍑嗙‘鐨勮娉�**锛歅DF 鍑轰欢**浠g爜銆佸崟娴嬨�佺湡瀹� HTTP 閾捐矾涓庤瑙夌粨鏋滈兘宸查獙杩�**锛涘墿涓嬬殑鏄�**椤电湁淇澶嶉獙**涓庝笁鏉℃湭瑙﹀彂鐨勯敊璇垎鏀��
+> 涓嶈鎶娿��12.3.4 鐨勪笁姝ラ『搴忛獙璇佽繃銆嶆帹骞挎垚銆屾墍鏈夊苟鍙�/瓒呮椂璺緞閮介獙杩囥�嶃��
+
+### 12.5 涓嬩竴姝�
+
+1. **澶嶉獙椤电湁淇**锛堟渶鐪佷簨鐨勪竴鏉★級锛氶噸鍚悗绔� 鈫� 瀵间竴娆� PDF 鈫� 鐪嬬 1 椤靛乏涓婅鏄惁杩樻湁 `2026/9/18 鈥 涓庢枃妗f爣棰樸��
+2. **淇暱琛ㄩ椤电暀鐧�**锛氭妸 `PdfPrintOptions.PRINT_CSS` 鐨� `table` 浠� `break-inside: avoid` 鍚嶅崟閲屾憳鎺夛紙淇濈暀 `tr, td, th, img`锛夛紝鍐嶅涓�娆� 60 琛� fixture 纭绗� 1 椤典笉鍐嶇┖銆�**娉ㄦ剰 `PdfPrintOptionsTest` 涓庡墠绔喕缁撲骇鐗╅兘浼氬彈褰卞搷锛屾敼鍓嶅厛纭 `PRINT_CSS` 涓嶈繘 `BASE_CSS` 杩欐潯杈圭晫娌¤纰般��**
+3. **琛ヤ笁鏉℃湭瑙﹀彂鐨勯敊璇垎鏀�**锛歚pdf.enabled: false` 鈫� `1_070_103_008`锛涘苟鍙�/瓒呮椂锛坄1_070_103_007`锛夊姞鍘嬶紱瀛樻。澶辫触锛坄1_070_103_006`锛夈��
+4. **`regenerate` 浣滃簾宸插綊妗� PDF** 瀹炴祴涓�娆°��
+5. **閮ㄧ讲娉ㄦ剰椤瑰啓杩涗氦浠樿鏄�**锛氬墠绔偅鏉� axios 涓庣綉鍏宠秴鏃堕兘瑕� 鈮� 鍐峰惎鍔ㄩ偅娆★紙628 741 ms + 浣欓噺锛夛紝鍚﹀垯棣栨瀵煎嚭蹇呰鍓嶇鎺愭柇銆�
+
+## 鍗佷笁銆丄I 瀵煎叆锛圥hase 4 路 鑽夌鎬侊級鈥斺�� 鉁� 鐪熷疄 HTTP 鑱旇皟 **54/54** + 璁捐鍣ㄣ�屼繚瀛樷啋鍒锋柊銆嶅線杩旈獙鏀堕�氳繃锛涢『甯﹀楠� PDF 椤电湁淇
+
+> 鐩爣锛氫笂浼犱竴浠藉凡鏈夌殑妫�楠屾姤鍛婃枃浠讹紙鎵弿浠�/鐓х墖銆佺數瀛愮増 PDF銆乄ord/Excel锛夆啋 AI 璇绘噦 鈫� 浜у嚭**妯℃澘鑽夌** 鈫�
+> 浜哄伐鍒拌璁″櫒纭鍚庢墠淇濆瓨涓烘寮忕増鏈��**杩欐槸鐢ㄦ埛鏄庣‘瑕佹眰琛ヤ笂鐨勮兘鍔涖��**
+
+### 13.1 浜や粯鐗�
+
+| 灞� | 鏂囦欢 | 鑱岃矗 |
+|---|---|---|
+| **AI 妯″潡鏀跺彛**锛堣法妯″潡锛� | `yudao-module-ai` 鐨� `AiAutoConfiguration` / `YudaoAiProperties` / `AiModelFactory(+Impl)` / `AiModelServiceImpl` | 鍔� `timeout`锛堥粯璁� 60s锛夛紱鎶� `AiModelDO.temperature` / `maxTokens` **鐪熸璇昏繘鍘�**锛堟鍓嶅0鏄庝簡浣嗗叏椤圭洰鏃犱竴澶勮鍙栵級锛�**cacheKey 鎶婃柊鍙傛暟涓�璧风畻杩� key**锛屽惁鍒欐敼浜� DB 閲岀殑 temperature 浼氶潤榛樿繑鍥炴棫妯″瀷 |
+| 杈撳叆閫傞厤鍣� | `service/aiimport/document/`锛歚QcReportImportAdapter` / `QcReportDocumentExtract` / `QcReportDocumentExtractService` / `ImageImportAdapter` / `PdfImportAdapter` / `OfficeImportAdapter` | 涓夌被杈撳叆缁熶竴浜у嚭銆屾枃鏈�氶亾 鎴� 鍥剧墖閫氶亾銆嶇殑涓棿缁撴瀯銆俙@Order` 鍥哄畾 **Image 鈫� Pdf 鈫� Office**锛屾秷闄ゃ�宲df 鍚屾椂琚� Pdf 涓� Office 鍖归厤銆嶈繖绫绘涔� |
+| 绾嚱鏁板眰 | `service/aiimport/llm/`锛歚QcReportTemplatePromptBuilder` / `QcReportAiDraftParser` / `QcReportAiDraftNormalizer` / `QcReportLlmCallPlanner` / `QcReportLlmCall` | 鎷� prompt銆佸垏鐗囪В鏋愩�佸綊涓�杩囨护銆�**璋冪敤璁″垝鎶芥垚绾嚱鏁�** |
+| 濂戠害 | `controller/admin/aiimport/` + `vo/`锛坄QcReportAiDraftReqVO` / `QcReportAiDraftRespVO` / `QcReportComponentSpecVO`锛� | `POST /qc-report/ai-import/draft`锛屾潈闄愮爜 `qc-report:template:ai-import` |
+| 缂栨帓 | `service/aiimport/QcReportAiImportService(+Impl)` | 鏍¢獙 鈫� 璇� blob 瀛楄妭 鈫� 閫愭枃浠惰蛋閫傞厤鍣� 鈫� 鎵ц璋冪敤璁″垝 鈫� 瑙f瀽褰掍竴 鈫� 鍚堝苟鍘婚噸 鈫� 杩斿洖銆�**鍏ㄧ▼涓嶈惤搴�** |
+| 閰嶇疆 | `config/QcReportAiImportProperties.java` + 涓や釜 profile | `enabled` / `maxFiles`(3) / `maxPagesPerFile`(5) / `maxPagesPerRequest`(8) / `maxFileSizeMb`(20) / `maxComponents`(200) / `pdfTextPageThreshold`(30) / `renderDpi`(200) / `maxXlsxRows`(300) |
+| 閿欒鐮� | `enums/ErrorCodeConstants.java` 鏂板 `1_070_104_000`锝瀈014` | 15 鏉★紝姣忔潯鎸� `error-message-precision.md` 缁欍�岀淮搴� + 鍙屾柟瀹為檯鍊� + 鍙墽琛屽姩浣溿�� |
+| 婧愭枃浠跺綊灞� | `yudao-module-system` 鐨� `StorageRecordTypeEnum` 鍔� `QC_REPORT_TEMPLATE` | 绫绘敞閲婂啓鐫�銆屾寜闇�鎵╁睍銆嶏紝鏄畼鏂圭暀鐨勬墿灞曠偣锛沗getByType` 瀵规湭鐭ョ被鍨嬫姏 `IllegalArgumentException`锛屼笉鍔犲氨鏄� 500 |
+| 杩炲甫 | `QcReportTemplateServiceImpl.deleteTemplate` | 鍔� `deleteAttachmentsByRecord(QC_REPORT_TEMPLATE, id)`锛屽惁鍒欐ā鏉垮垹闄ゅ悗闄勪欢涓庣鐩樻枃浠舵案涔呭鍎� |
+| **鍓嶇瑁呴厤鍣�**锛堟湰杞渶澶х己鍙o級 | `mom-pro2-before/src/components/quality/core/assembler.ts` | **姝ゅ墠璇箟灞傛槸銆屽彧鍐欑殑銆�**锛氬彧鑳戒粠鐢诲竷鏀堕泦鍑烘潵锛屼笉鑳藉啀瑁呭洖鍘汇�傝繖涓枃浠舵槸 `collectSchema` 鐨勭函鍑芥暟閫嗚繍绠� |
+| 鍓嶇绉湪娓呭崟 | `.../core/catalog.ts` | 娉ㄥ唽琛� 鈫� 鍠傜粰 LLM 鐨勬淳鐢熻鍥撅紙鍓ユ帀 icon/buildContent/validate锛夛紝绾嚱鏁� |
+| 鍓嶇鎺ュ叆 | `api/mes/qc/report/ai/index.ts` / `designer/modules/ai-import-modal.vue` / `designer/index.vue` / `use-designer.ts` | API 瀹氫箟銆佸脊绐椼�侀《鏍忔寜閽�乣loadCanvasFromDraft` |
+| 鑱旇皟鏂规 | `docs/qc_report_ai_import_frontend_integration.md` | 鎸� `frontend-docs.md` 寮哄埗瑕佹眰浜у嚭锛屼笉鍚换浣曞墠绔唬鐮佺墖娈� |
+
+### 13.2 鍏鍒绘剰鐨勫彇鑸�
+
+| 鍙栬垗 | 鐞嗙敱 |
+|---|---|
+| **绉湪娓呭崟鐢卞墠绔殢璇锋眰浼狅紝鍚庣涓嶇‖缂栫爜** | 缁勪欢娉ㄥ唽琛ㄧ殑鍞竴鐪熺浉鏉ユ簮鍦ㄥ墠绔�傚悗绔妱涓�浠藉氨鏄�**绗簩涓湡鐩告潵婧�**锛屼笖鏄渶鍧忕殑閭g锛氬墠绔姞缁勪欢/鏀瑰繀濉瓧娈垫椂鍓嶇绔嬪埢鐢熸晥銆佸悗绔壇鏈潤榛樿繃鏈燂紝妯″瀷闅忓嵆浼氱紪鍑烘敞鍐岃〃閲屾牴鏈笉瀛樺湪鐨� `type`銆傞」鐩凡鍦� `ReportTemplateSchema.QualityComponentNode` 娉ㄩ噴閲屾槑纭弽瀵硅繖浠朵簨 |
+| **杈圭晫娌℃湁琚墛寮�** | 娓呭崟杩� prompt 鍚庣殑鍞竴鍑哄彛鏄�岃妯″瀷鎶勬垚 JSON 瀛楃涓层�嶃�傜湡姝f妸鍏崇殑鏄�**鍓嶇瑁呴厤鍣ㄥ鐫�娲绘敞鍐岃〃鏌� `getQualityComponent`**锛氭湭娉ㄥ唽鐨� `type` 浼氳璺宠繃锛�**姘歌繙浜т笉鍑轰换鎰� HTML**銆傚氨绠楁湁浜轰吉閫犲惈 `type:'CustomHtml'` 鐨勬竻鍗曪紝涔熷彧浼氳 skip |
+| **POI 涓嶇敤 Tika** | 琛ㄦ牸鐨勮鍒楃粨鏋勬槸鏍稿績淇℃伅锛孴ika 浼氭媿骞虫垚绾枃鏈紱涓� `tika-parsers-standard-package` 浼氭嫋杩涘嚑鐧� MB 瑙f瀽鍣紝qcreport 娌″繀瑕佽儗 |
+| **鍚屾杩斿洖锛屼笉鍋氬紓姝ヤ换鍔� + 杩涘害杞 + 浠诲姟琛�** | 宸插拰鐢ㄦ埛鏁插畾鐨勬柟妗堛�備唬浠锋槸鎺ュ彛鏈�闀挎寕 180 绉掞紝鎵�浠ュ墠绔偅鏉� axios 鍗曠嫭鏀惧瓒呮椂 |
+| **閿欒鐢ㄧ湡姝g殑 `ServiceException` + 鍒嗛敊璇爜** | ERP / CRM 鍏堜緥鎶婇敊璇杩� `respVO.rawText` 涓� HTTP 200锛岃鍓嶇闈犮�宺awText 鏈夋病鏈夊�笺�嶅梾鎺㈠け璐ワ紙`crm_sale_quotation_ocr_integration.md` 閭e紶琛ㄥ氨鏄繖绉嶇害瀹氱殑鍖栫煶锛夈�傛湰鏂规鍒绘剰鍋忕 |
+| **澶氶〉閫愰〉璇嗗埆鍚庢寜 `(type, props)` 鍘婚噸鍚堝苟** | 椤电湁銆佹爣棰樸�佽〃澶村湪澶氶〉閲嶅鍑虹幇鏃跺彧鐣欑涓�浠姐�備笂闄� 5 椤�/鏂囦欢銆�8 椤�/璇锋眰 |
+| **缁濆涓嶅鍒� ERP/CRM 鐨� `tempFile.delete()` 缂洪櫡** | `ErpPurchaseInvoiceAiServiceImpl` 涓� `CrmSaleQuotationAiServiceImpl` 鍦� `finally` 閲屽垹鐨勬槸 `getPublicFile` 杩斿洖鐨�**鐪熷疄瀛樺偍 blob 鏂囦欢鏈韩**锛屽嵆鍒犵敤鎴风殑鐪熷疄涓婁紶鏁版嵁銆傛湰杞笉纰板畠浠紝浣嗕篃缁濅笉澶嶅埗銆傚缓璁崟鐙紑淇椤癸紙涓夊鍚屾瀯锛� |
+| **瀹屽叏瑙f瀽涓嶅嚭鏃剁洿鎺ユ姏閿欙紝鍝嶅簲閲屼笉鏀� `rawText`** | 濉炰竴涓亽涓� null 鐨勫瓧娈靛彧浼氳鍚庢潵浜轰互涓恒�岃В鏋愬け璐ユ椂鍓嶇鑳芥嬁鍒版ā鍨嬪師鏂囥�嶃�傛ā鍨嬪師鏂囧啓杩涗簡鏈嶅姟绔棩蹇� |
+
+### 13.3 瀹炴祴璇佹嵁
+
+| 缁撹 | 璇佹嵁 |
+|---|---|
+| **缂栬瘧閫氳繃** | `mvn compile -pl yudao-module-qcreport -am -q` exit 0 |
+| **93 椤规祴璇曞叏缁�** | `mvn -pl yudao-module-qcreport test` 鈫� **93 椤� 0 澶辫触**锛�51 鈫� 93锛屾湰杞柊澧� **42 椤�**锛氶�傞厤鍣� 13 + 褰掍竴 11 + 瑙f瀽 9 + 璋冪敤璁″垝 3 + 鎻愮ず璇� 6锛夛紝閫愭潯鏉ヨ嚜 `target/surefire-reports/*.txt` |
+| **瑁呴厤鍣ㄤ笌 `collectSchema` 浜掍负閫嗚繍绠楋紙鏈哄櫒璇佹槑锛�** | `.qc-conformance/assemble-ts.ts`锛坄npx tsx` 鐩磋窇锛�**9 缁勩�佺害 60 鏉℃柇瑷�鍏ㄨ繃**锛�12 涓粍浠跺叏閮ㄨ閰嶆垚鍔燂紱姣忎釜椤跺眰鑺傜偣閮藉甫 `data-quality-type` 涓�**椤跺眰涓嶅惈 `data-qc-repeat`/`repeat-row`**锛�**`attributesToProps 鈭� assemble === resolveQualityProps`锛�12/12 寰�杩旀棤鎹燂級**锛涙瘡涓瓧娈电殑 `data-qc-<key>` **纭疄鍐欒繘浜嗙敾甯�**锛堥槻姝㈤潬涓よ竟鍚屾椂鍙栭粯璁ゅ�艰�屽亣缁匡級锛沚oolean `false/true` 鈫� `'false'/'true'`锛沗Divider.thickness` 鏁板瓧 3 鈫� `'3'` 鈫� 鏁板瓧 3锛沞num 鏁板瓧鍊兼敹鏁涙垚瀛楃涓� `'3'`锛堜笌鏍¢獙銆乣buildContent` 鐨� `String()`/`Number()` 姣旇緝鍙e緞涓�鑷达級锛沗CustomHtml` + 绌� type 杩� `skipped` 涓� **`alert(1)` 娌℃笚杩涚敾甯冩暟鎹�**锛涚粨鏋勫寲灞炴�у洖钀介粯璁ゅ�煎苟鍚勪骇涓�鏉� problem锛涘繀濉己澶憋紙`itemsPath: ''`锛変骇 problem銆侀潪蹇呭~锛坄title: ''`锛変笉浜э紱绌�/undefined 杈撳叆浠嶈繑鍥為潪绌� `pages`锛涙竻鍗� 12 椤广�佸彧鍚� `category/fields/label/type` 鍥涗釜 key銆�**鏃� `buildContent`/`icon`/`validate`/`defaults` 娉勬紡** |
+| **鍓嶇闆舵柊澧炵被鍨嬮敊璇�** | `vue-tsc --noEmit`锛堝甫 `NODE_OPTIONS=--max-old-space-size=8192`锛夛細鏀瑰墠 **316** 鈫� 鏀瑰悗 **316**锛宼ypecheck 鏃ュ織閲� `catalog.ts` / `assembler.ts` / `components/quality` **闆跺懡涓�** |
+| **璁捐鍣� UI 鎺ュ叆 + 鍏ㄩ摼璺線杩�** | 閲嶅惎鍚庡凡璧板畬**瀹屾暣閾捐矾**锛堜笉鍐嶅彧鍒板悗绔竟鐣岋級锛氳 13.5 鈥斺�� 11 寮犳埅鍥� `ai-02-designer.png` 锝� `ai-11-published.png`锛屽惈鍒锋柊鍚�**璇箟绛惧悕閫愬瓧涓�鑷�**涓庡彂甯冩垚鍔� |
+| **AI 妯″潡瓒呮椂鏀跺彛鏈牬鍧忔棦鏈夎皟鐢�** | 鍙敼浜� 1 涓皟鐢ㄧ偣锛坄AiModelServiceImpl:101`锛屾墜涓婃鏈� `AiModelDO`锛夛紱ERP/CRM/MES 涓夊 AI 璋冪敤璧板悓涓�宸ュ巶锛屼竴璧疯幏寰楄秴鏃朵笌 `maxTokens` |
+| **涓氬姟鍙鍖栫殑涓変唤 mmd 澧為噺璇硶鏈夋晥** | 鏈満鏃� `mmdc`銆佸墠绔� `node_modules` 閲屼篃娌℃湁 mermaid锛屾晠鐢ㄦ棤澶� Chromium 杞藉叆 **mermaid 11锛堜笌 `index.html` 鍚屼竴涓� jsDelivr CDN 鐗堟湰锛�** 瀵规敼鍔ㄥ悗鐨勪笁浠芥枃浠惰窇 `mermaid.parse()`锛歚05-quality-flow` / `09-data-flow` / `11-ai-business-flow` **鍏ㄩ儴 `ok: true`**銆傝繖涓�姝ヨˉ涓婁簡姝ゅ墠鍙仛銆岀紪杈� + `sync_index.js` 闀滃儚銆嶈�屾病鍋氳娉曟牎楠岀殑缂哄彛 |
+
+**楠岃瘉杩囩▼涓籂姝g殑鍥涘璇垽**锛堣涓嬫潵鍏嶅緱鍚庝汉閲嶈俯锛夛細
+
+1. **`鑽夌 0 / 鑺傜偣 0`**锛歚listQualityComponents()` 杩斿洖 0 鈥斺�� 娉ㄥ唽琛�**鍙湁鏄惧紡璋冪敤 `registerAllQualityComponents()` 鎵嶆湁鍐呭**锛堣璁″櫒鍦� `init` 鏃跺仛锛夛紝瀵煎叆 barrel 涓嶄細娉ㄥ唽浠讳綍涓滆タ銆備袱澶勪慨澶嶏細缁� `buildQualityComponentCatalog()` 鍔犵┖娉ㄥ唽琛�**鐩存帴鎶涢敊**鐨勫畧鍗紙鎴戣嚜宸辩殑娴嬭瘯鑴氭湰灏辫俯浜嗚繖涓潙锛岃鏄庤繖涓満鏅槸鐪熷疄鐨勶級锛屽苟鍦ㄥ鎷嶈剼鏈噷琛ヤ笂娉ㄥ唽璋冪敤銆�
+2. **`number 3 杩樺師涓烘暟瀛� 3` 鎶� `string 3`**锛氭垜璇互涓� `Heading.level` 鏄暟瀛楀瓧娈点�傚疄闄呭畠鏄� `type: 'enum'` 涓�**閫夐」鍊兼槸鏁板瓧** 鈥斺�� 鎵�浠ュ線杩旀垚瀛楃涓� `'3'` 鏄�**姝g‘鐨�**锛堟牎楠岀敤 `String()` 姣斿銆乣buildContent` 鐢� `Number()`锛夈��**瑁呴厤鍣ㄦ槸瀵圭殑锛屾垜鐨勬祴璇曟槸閿欑殑銆�** 宸叉妸鏁板瓧寰�杩旀敼鐢� `Divider.thickness`锛堢‘璁ゆ槸鐪熸鐨� `type: 'number'`锛夛紝enum 鏀逛负鏂█ `String(back.level) === '3'`銆�
+3. **`鍧忓厓绱犱笉褰卞搷鍏朵綑锛�4 椤逛腑瑁呰繘 3 椤筦 瀹為檯鏄� 2**锛氭垜鏁伴敊浜嗐�俙QualityTable` / `CustomHtml` / `Heading` / `{type:''}` 鍥涢」閲屼袱椤硅 skip锛屾墍浠ヨ杩� **2** 椤� 鈥斺�� `skipped.length === 2` 鏃╁凡纭杩欎竴鐐广�傞『甯︿慨鎺変簡涓�澶勮秺鐣屽彇鍊煎鑷寸殑 `TypeError`銆�
+4. **`蹇呭~缂哄け浜� problem` 寰楀埌 `[]`**锛氭垜鐢ㄤ簡 `QualityTable.props.title`锛屽畠**涓嶆槸蹇呭~**銆傛敼鐢� `itemsPath`锛堝敮涓�蹇呭~瀛楁锛夛紝骞惰ˉ浜嗕竴鏉°�岄潪蹇呭~鐣欑┖涓嶄骇 problem銆嶇殑瀵圭収鏂█銆�
+
+### 13.4 鐪熷疄 HTTP 鑱旇皟 鈥斺�� 鉁� **54/54 鍏ㄧ豢**锛堝悗绔噸鍚悗棣栬窇锛�
+
+鑴氭湰 `D:/qcl-tmp/ai-import-e2e.mjs`锛堥鏍肩収鏃㈡湁 `real-canvas.mjs`/`pdf-e2e.mjs`锛氱櫥褰曞彇 token 鈫� multipart 涓婁紶鎷� `blobId` 鈫� `bind` 褰掑睘鍒版ā鏉� 鈫� `POST /qc-report/ai-import/draft` 鈫� 鏂█锛夈��
+
+**涓よ疆**锛氶杞� 46/47锛屽敮涓�閭f潯 FAIL 鏄�**鎴戣嚜宸辨妸鏂█鍐欓敊浜�**锛堟妸銆宑atalog 涓虹┖銆嶅綋鎴� 008 鍙揪璺緞锛屽疄闄呰 VO 涓婄殑 `@NotEmpty` 鍏堟嫤鎴� HTTP 400锛屽睘妗嗘灦鏍¢獙锛屽悎鐞嗭級锛涙敼鍐欐垚涓ゆ潯鐪熸鍙揪鐨� 008 璺緞锛�41 椤硅秴涓婇檺銆佺己 `type`锛夊悗**绗簩杞� 54/54**銆�
+
+| 鐢ㄤ緥 | 鍏抽敭鏂█ | 瀹炴祴 |
+|---|---|---|
+| 鐢靛瓙鐗� PDF | `code=0`銆佺粍浠堕潪绌恒�乣type` 鈭� 12 鍐呯疆 | 鉁� |
+| 鎵弿鐗� PDF锛�3 椤碉級 | 鍚屼笂 + **澶氶〉鍘婚噸鐢熸晥** | 鉁咃紙瑙佷笅锛� |
+| 鍗曢〉鎵弿鍥剧墖 | 鍚屼笂 | 鉁� |
+| Word 鍚〃鏍� | 鍚屼笂锛岃〃鏍艰鍒楁湭鎷嶅钩 | 鉁� |
+| Excel 妫�楠岄」鐩� | 鍚屼笂 | 鉁� |
+| 绾枃鏈� / CSV | 鍚屼笂 | 鉁� |
+| 鏃х増 `.doc` | `1_070_104_003` 涓旀枃妗堝惈銆屽彟瀛樹负 .docx銆� | 鉁� |
+| 鍙傛暟绫婚敊璇� 6 鏉� | 001 / 005 / 008脳2 / 009 / 400 | 鉁� 6/6 |
+
+**鐪熷疄妯″瀷璋冪敤寤舵椂**锛氬疄娴� `durationMs` 钀藉湪 **2 786 锝� 13 642 ms**锛岄殢鏂囦欢椤垫暟涓庨�氶亾锛堟枃鏈� vs 瑙嗚锛夋诞鍔紝涓庤剼鏈晶 wall clock 鍚诲悎 鈥斺�� 璇存槑纭疄鏄墦鍒颁簡 DashScope锛屼笉鏄紦瀛樻垨鐭矾銆�
+
+**澶氶〉鍘婚噸锛坄scan-3page.pdf`锛夌殑 warnings 鍘熸枃**锛屼袱鏉¢兘鍦細
+
+```
+鏂囦欢銆宻can-3page.pdf銆嶆病鏈夋枃鏈眰锛堝叡 3 椤碉級锛屽凡鎸夋壂鎻忎欢閫愰〉璇嗗埆锛屼細姣旇緝鎱�
+澶氶〉璇嗗埆鍏卞緱鍒� 15 椤圭粍浠讹紝鍏朵腑鏈� 6 椤瑰湪鍏跺畠椤靛凡鍑虹幇锛堥〉鐪夈�佹爣棰樸�佽〃澶寸瓑閲嶅鍐呭锛夛紝宸插悎骞�
+```
+
+鍗� **15 鈫� 9**锛屽幓閲嶆寜 `(type, props)` 鐢熸晥锛屼笉鏄彧鍐欏湪娉ㄩ噴閲岀殑鎵胯銆�
+
+**銆孉I 浜у嚭鍙綔鑽夌銆嶆湁 DB 璇佹嵁**锛氬叏閮� AI 璋冪敤璺戝畬锛宍qc_report_template_version` 閲屾ā鏉� 5 **浠嶇劧鍙湁 v1.0 / v1.1 涓よ**锛屾病鏈変换浣曚竴琛屾槸 AI 鐩存帴鍐欒繘鍘荤殑銆傝惤搴撳彧鍙戠敓鍦ㄤ汉宸ョ偣銆屼繚瀛樸�嶆椂銆�
+
+**`type` 瓒婄晫鐜囦负 0**锛氭瘡涓敤渚嬮兘鎶婅繑鍥炵殑 `type` 闆嗗悎涓� 12 涓唴缃� type 姹傚樊闆嗭紝**鏃犱竴瓒婄晫**锛沗summary` 鍧囦负閫氶『涓枃锛堜緥锛氥�屾湰鏂囦欢涓哄嚭璐ф楠屾姤鍛婏紝鍖呭惈鎶ュ憡澶淬�佹楠岄」鐩〃鏍间笌缁撹銆嶏級銆�
+
+### 13.5 璁捐鍣ㄣ�岀敓鎴愬埌鐢诲竷 鈫� 淇濆瓨 鈫� 鍒锋柊銆嶅線杩旈獙鏀� 鈥斺�� 鉁� 鏈疆鐪熸鐨勯獙鏀剁偣
+
+鐢� Playwright MCP 鎶婃暣鏉¢摼璺蛋瀹屽苟閫愭鎴浘锛坄.playwright-mcp/ai-02-designer.png` 锝� `ai-11-published.png`锛夛細
+
+| 姝ラ | 缁撴灉 |
+|---|---|
+| 杩涜璁″櫒 鈫� 鐐归《鏍忋�孉I 瀵煎叆銆� | 鎸夐挳涓庡脊绐楁甯革紙`ai-02`/`ai-03`锛� |
+| 閫夊叆鐪熷疄鎵弿浠� 鈫� 銆屽紑濮嬭瘑鍒�� | 5 涓粍浠讹紝**4.5 s**锛坄ai-04`/`ai-05`锛� |
+| 銆岀敓鎴愬埌鐢诲竷銆� | 缁勪欢鎸夊簭鍑虹幇锛屽睘鎬ч潰鏉胯 `restoreQualityTraits` 閲嶅缓锛坄ai-06`锛� |
+| **鐐广�屼繚瀛樸�嶁啋 淇濆瓨 v1.1** | 钀藉簱鎴愬姛锛坄ai-07`/`ai-08`锛� |
+| **鍒锋柊椤甸潰 鈫� 鍒囩増鏈啀鍒囧洖** | **璇箟绛惧悕閫愬瓧涓�鑷�**锛坄ai-09`锛� |
+| 鍙戝竷 v1.1 | toast銆岀増鏈� v1.1 宸插彂甯冦�嶏紙`ai-10`/`ai-11`锛� |
+
+> **涓轰粈涔堢敤銆屽綊涓�鍖栬涔夌鍚嶃�嶈�屼笉鏄8瀛楃涓叉瘮瀵�**锛欸rapesJS 鐨勮妭鐐� `id` 姣忔浼氳瘽閲嶆柊鐢熸垚锛屼袱浠藉唴瀹圭浉鍚岀殑 Schema 瀛楃涓蹭竴瀹氫笉鍚屻�傛瘮瀵瑰崟浣嶅彇**椤跺眰 `[data-gjs-type="wrapper"] > [data-quality-type]` 鑺傜偣鍙婂叾 `data-qc-*` 灞炴�ч泦鍚�**锛岃繖鎵嶆槸銆岀敾甯冨唴瀹广�嶇殑姝g‘琛ㄧず銆傚埛鏂板墠鍚庤绛惧悕**瀹屽叏涓�鑷�**锛屽嵆璇佹槑 `collectSchema` 鈫� 鏂扮増鏈 鈫� `loadSchema` 寰�杩旀棤鎹燂紝鍚屾椂鎶婅閰嶅櫒涓� `restoreQualityTraits` 涓�璧烽獙浜嗐��
+
+涓ゅ闄勫甫纭锛欰I 鐚滃嚭鐨勭焊寮犺骞跺叆 `pageSetting` 骞�**鑷姩鍒囧埌绾靛悜**锛沗ReportHeader.reportNo` / `Result.conclusion` 鐨� **`{{...}}` 缁戝畾鍗犱綅绗﹀師鏍蜂繚鐣�**锛屾病琚浛鎹㈡垚妯″瀷鐪嬪埌鐨勫瓧闈㈠�笺��
+
+### 13.6 PDF 椤电湁淇澶嶉獙 鈥斺�� 鉁� 闂幆 搂鍗佷簩 閬楃暀绗� 1 鏉�
+
+瀹炰緥 30锛坄QR20260919-0003`锛夊鍑猴細**1 209 ms**銆�**59 809 瀛楄妭**銆乣browserStatus: READY`銆傜敤 PDFBox 鎶界 1 椤电函鏂囨湰 + 娓叉煋鎴� PNG 鍙岄噸纭锛�
+
+- 绗� 1 椤垫枃鏈�**棣栬鏄姤鍛婃鏂�**銆屾潵鏂欐楠屾姤鍛娿�嶃��**鏈鏄垜浠嚜宸辩殑椤佃剼**銆岀 1 椤� / 鍏� 1 椤点�嶏紱
+- **閫氱瘒娌℃湁** Chromium 鑷甫鐨勩�屾墦鍗版棩鏈� + 鏂囨。鏍囬銆嶉〉鐪夛紱
+- 娓叉煋鍥� `D:/qcl-tmp/header-check-30-p1.png` 鑲夌溂澶嶆牳涓�鑷淬��
+
+鍗� `PdfPrintOptions.HEADER_TEMPLATE = "<div></div>"` + `.setHeaderTemplate(...)` 纭疄鐢熸晥銆�
+
+### 13.7 鏈疆鏆撮湶鐨� 1 涓湡瀹炵己闄凤紙宸蹭慨锛�+ 1 涓湡瀹為殣鎮o紙鏈慨锛屽瀹炶褰曪級
+
+**鈶� 缂洪櫡锛堝凡淇級鈥斺�旀柟妗堟枃妗i噷鐨� `application` 鍊间笉鍦ㄥ悗绔灇涓惧唴銆�**
+
+棣栨 `bind` 鐩存帴 **HTTP 500 绯荤粺寮傚父**锛屾棩蹇楋細
+
+```
+java.lang.IllegalArgumentException: 鏃犳晥鐨勬枃浠剁敤閫旂被鍨�: ai_import_source
+ at cn.iocoder.yudao.module.system.enums.storage.StorageApplicationTypeEnum.getByType(:30)
+```
+
+鏍瑰洜涓嶅湪鍓嶇銆佷篃涓嶅湪娴嬭瘯锛�**`StorageApplicationTypeEnum` 鍙湁 `file` / `image` / `avatar` 涓変釜鍊�**锛坄getByType` 瀵规湭鐭ュ�肩洿鎺ユ姏锛夛紝鑰�**鎵瑰噯鏂规閲屽啓鐨勬槸 `ai_import_source`**銆傝繖涓瓧闈㈠�兼病瀵圭潃鏋氫妇鏍歌繃锛屽彧鏈夌湡璺� HTTP 鎵嶄細鏆撮湶 鈥斺�� 鍗曟祴鍜� typecheck 閮芥嫤涓嶄綇瀹冦��
+
+宸蹭慨 **3 澶�**锛歚ai-import-modal.vue`銆乣docs/qc_report_ai_import_frontend_integration.md`锛堝苟鍔犱簡涓�琛� 鈿� 璇存槑鏋氫妇闄愬埗锛夈�佽仈璋冭剼鏈�俙recordType` 浠嶆槸鎴戜滑鑷繁鐨� `qc_report_template`锛屼笉鍙楀奖鍝嶃��
+
+**鈶� 闅愭偅锛堟湭淇級鈥斺�斿鍚屼竴妯℃澘閲嶅瀵煎叆浼氱暀涓嬪鍎� blob + 纾佺洏鏂囦欢銆�**
+
+`StorageFileUtil.saveStorageAttachmentByRecordTypeAndRecordId` 鐨勬棦鏈夎涔夋槸銆�**鍙垹闄ゆ棫鐨勯檮浠跺叧鑱旇褰曪紝淇濈暀 blob 璁板綍锛堟枃浠舵湰韬笉鍒犻櫎锛�**銆嶃�傚 AI 瀵煎叆杩欐潯娴侊紝鍚箟鏄細**鍚屼竴妯℃澘绗簩娆″鍏ユ簮鏂囦欢鏃讹紝涓婁竴浠芥簮鏂囦欢鍙樻垚瀛ゅ効 blob锛屼笖纾佺洏鏂囦欢涓嶄細鍒�**锛岄殢閲嶅瀵煎叆鏃犵晫澧為暱銆�
+
+杩炲甫涓�涓竻鐞嗕笂鐨勫潙锛歚deleteAttachments(ids)` 涔熸竻涓嶆帀銆屽凡琚墠涓�娆� bind 杞垹銆嶇殑闄勪欢琛� 鈥斺�� 瀹冨唴閮ㄨ蛋 `storageAttachmentMapper.selectByIds(...)`锛�**甯﹂�昏緫鍒犻櫎杩囨护**锛屽彇涓嶅埌閭d簺琛岃嚜鐒朵篃灏卞彇涓嶅埌瀵瑰簲 blob銆傛湰杞殑涓存椂鏁版嵁鏈�鍚庢槸鎵嬪伐 `UPDATE system_storage_blob SET deleted=1 ...` + `rm` 纾佺洏鏂囦欢鎵嶅共鍑�鐨勩��
+
+**澶勭疆寤鸿锛堢暀寰呬笅涓�杞畾澶猴級**锛氳涔堣 AI 瀵煎叆銆屾浛鎹㈠悗椤哄甫娓呯悊琚《鎺夌殑 blob銆嶏紝瑕佷箞鏄庣‘鎶婃簮鏂囦欢褰�**姝e紡褰掓。绱Н**锛堥偅灏变笉绠楀鍎匡紝浣嗚鏈夐厤棰濅笌鑷竻鐞嗭級銆備袱鏉¤矾閮介渶瑕佷骇鍝佸彛寰勶紝涓嶅睘鏈疆鑼冨洿銆�
+
+### 13.8 鈿� 宸查獙璇� / 鏈獙璇侊紙鏈妭鐨勯噸鐐癸級
+
+**宸叉嬁鍒板疄娴嬭瘉鎹�佸彲浠ヨ銆屽彲鐢ㄣ�嶇殑**锛�
+
+- 鍚庣鐪熷疄 HTTP 閾捐矾 **54/54**锛�8 鏍煎紡鐢ㄤ緥 + `.doc` 鎷掓敹 + 6 鏉″叆鍙傞敊璇級锛屽惈鐪熷疄妯″瀷寤舵椂锛�
+- **澶氶〉鍘婚噸**銆�**`type` 闆惰秺鐣�**銆�**AI 涓嶈惤搴�** 涓夐」鍧囨湁瀹炶瘉锛�
+- 璁捐鍣� **UI 鍏ㄩ摼璺� + 鍒锋柊寰�杩旀棤鎹� + 鍙戝竷**锛�
+- PDF 椤电湁淇澶嶉獙锛�
+- 缂栬瘧閫氳繃銆�**93 椤瑰崟娴�**銆佽閰嶅櫒瀵规媿 **绾� 60 鏉℃柇瑷�**銆佸墠绔� **闆舵柊澧炵被鍨嬮敊璇�**锛堣 13.3锛夈��
+
+**浠嶆湭楠岃瘉鐨勶紙涓嶈兘璇淬�屽彲鐢ㄣ�嶏級**锛�
+
+- **`yudao.qcreport.ai-import.enabled=false 鈫� 1_070_104_000`** 鈥斺�� 鏈疄娴嬶紙闇�涓存椂鏀归厤缃� + 閲嶅惎锛夈��
+- **瓒呮椂鍒嗘敮 `1_070_104_011`** 鈥斺�� 鏈疄娴嬨�俙yudao.ai.timeout` 鐨� 60 s 涓庡墠绔偅鏉� 180 s 鏄�**涓ら亾鐙珛鐨勯椄**锛岄兘娌¤Е鍙戣繃銆傛渶鐪佷簨鐨勯獙娉曟槸鎶� `yudao.ai.timeout` 涓存椂鏀规垚 `1s`锛�**娌″仛**銆�
+- **瓒呴〉锛坄FILE_TOO_MANY_PAGES`锛�/ 鍚堣瓒呴〉锛坄TOO_MANY_PAGES_TOTAL`锛�/ 瓒呭ぇ灏忥紙`FILE_TOO_LARGE`锛変笁鏉�** 鈥斺�� 鏈疄娴嬨�傚悓鏃忛噷銆岃秴鏂囦欢鏁般�嶅凡琚� `@Size` 鎷︽垚 400 骞跺疄娴嬪埌锛屼絾鍙﹀涓夋潯娌¢�犺繃瓒呴檺 fixture銆�
+- **銆屾ā鏉垮垹闄ゆ竻闄勪欢銆嶇殑杩炲甫鏀瑰姩鏈疄娴�** 鈥斺�� 浠g爜鍦紙`deleteTemplate` 閲屽姞浜� `deleteAttachmentsByRecord`锛夛紝**娌¤窇杩�**銆�
+- **娌″啓 `@Disabled` 鐨勭湡瀹炶仈璋冩祴璇�**锛堣鍒掗噷鎻愬埌鍙互鍐欎竴涓粯璁や笉璺戠殑锛夆�斺�� 鏈疆**娌″啓**銆�
+- **AI 鐨勮瘑鍒�屽噯纭巼銆嶆湭琚害閲�** 鈥斺�� 鎴戜滑楠岀殑鏄�岄摼璺�氥�佺粨鏋勫悎娉曘�乣type` 涓嶈秺鐣屻�嶏紝**涓嶆槸**銆岃鍑烘潵鐨勭粍浠朵笌鍘熶欢閫愰」鍚诲悎銆嶃�傝繖浠藉垽鏂渶瑕佷汉宸ュ鐓х湡瀹炴姤鍛婏紝鏈疆鍙仛鍒颁汉宸ョ湅浜嗘埅鍥捐寰楀悎鐞嗐��
+- **Linux 閮ㄧ讲涓嬫湭楠�** 鈥斺�� AI 瀵煎叆涓嶄緷璧栨祻瑙堝櫒/瀛椾綋锛堜笌 Phase 3 涓嶅悓锛夛紝棰勬湡鏃犻闄╋紝浣�**鏈獙**銆�
+
+> **鍑嗙‘鐨勮娉�**锛欰I 瀵煎叆**鍚庣 + 鍓嶇 + 鐪熷疄閾捐矾鍏ㄩ��**锛屾牳蹇冨彛寰勶紙鍙綔鑽夌銆佸椤靛幓閲嶃�乣type` 涓嶈秺鐣岋級閮芥湁瀹炴祴璇佹嵁銆�
+> 浣�**涓や釜閰嶇疆寮�鍏冲垎鏀�佷笁鏉¤緭鍏ヤ笂闄愩�佹ā鏉垮垹闄ゆ竻鐞嗐�佽瘑鍒噯纭巼**浠嶅睘鏈獙璇� 鈥斺��
+> 涓嶈鎶娿��54/54 閫氳繃銆嶈鎴愩�屾墍鏈夐敊璇垎鏀兘楠岃繃銆嶏紝閭d簺鏁板瓧鍙鐩栦簡宸叉瀯閫犵殑鐢ㄤ緥銆�
+
+### 13.9 淇濈暀鏁版嵁涓庡洖婊氳鏄�
+
+- **鏈夋剰淇濈暀**锛氭ā鏉� 5锛坄QC_OQC_UI` 鍑鸿揣妫�楠屾姤鍛婃ā鏉匡級鐨� **v1.1**锛宻chema 22 541 瀛楃锛�**宸插彂甯�**涓� `current_version = v1.1` 鈥斺�� 杩欐槸 UI 寰�杩旈獙鏀剁殑浜х墿锛岀暀鐫�璁╁姛鑳藉彲婕旂ず銆傚畠鍘熷厛鏄竴浠�**绌虹敾甯冭崏绋�**锛屾墍浠�**瀹屽叏鍙洖婊�**锛堟妸 v1.1 鍋滅敤 / 鍒犳帀锛宍current_version` 鍒囧洖 v1.0 鍗冲彲锛夈��**濡傞渶杩樺師浠ヤ究閲嶅仛楠屾敹锛岃涓�澹板嵆鍙��**
+- **宸叉竻鐞嗗共鍑�**锛氬疄渚� 9 琛屽叏閮ㄨ蒋鍒� / **0 瀛樻椿**锛沗system_storage_blob` 19 琛� / **0 瀛樻椿**锛沗system_storage_attachment` 17 琛� / **0 瀛樻椿**锛沗D:/uploads/2026/0918/` 涓� `D:/uploads/2026/0919/` **鍧囦负绌�**銆�
+- **鏈夋剰涓嶅垹**锛歚qc_report_render_record` 10 琛� 鈥斺�� `deleteInstance` 鏈夋剰涓嶅垹娓叉煋璁板綍锛堝璁$暀鐥曪級銆�
+- **涓�鏉″凡閲嶇紪璇戙�佸緟閲嶅惎鐢熸晥鐨勬枃妗堝井璋�**锛歚ErrorCodeConstants.AI_IMPORT_FILE_LEGACY_OFFICE` 鐨勬ā鏉块噷 `.{}` 鍓嶅浜嗕竴涓┖鏍硷紙鍚屼竴鍙ラ噷鐨� `.docx`/`.xlsx` 閮芥病鏈夛級锛屾覆鏌撴垚銆屾棫鐗� Office 鏍煎紡 **.doc**銆嶏紝宸插幓鎺夌┖鏍笺�俙mvn compile -pl yudao-module-qcreport -am -q` **EXIT=0**锛�**閲嶅惎鍚庣鍚庣敓鏁�**锛涙湭鐢熸晥涓嶅奖鍝嶅姛鑳姐��
+
+### 13.10 涓嬩竴姝ワ紙鎸変紭鍏堢骇锛�
+
+1. **閲嶅惎鍚庣**锛堣 `.doc` 鏂囨閭e寰皟鐢熸晥锛夆�斺�� `mvn compile -pl yudao-module-qcreport -am -q` **宸茶窇銆丒XIT=0**锛屽彧鍓╂墜宸ラ噸鍚��
+2. **琛ヤ笁涓厤缃�/闄愬埗鍒嗘敮鐨勫疄娴�**锛堥兘瑕佷复鏃舵敼閰嶇疆 + 閲嶅惎锛夛細`ai-import.enabled: false` 鈫� `1_070_104_000`锛沗yudao.ai.timeout: 1s` 鈫� `1_070_104_011`锛涜秴澶у皬 fixture 鈫� `1_070_104_004`銆�
+3. **瀹炴祴銆屽垹妯℃澘椤哄甫娓呴檮浠朵笌 blob銆�**锛氬缓涓�涓复鏃舵ā鏉� 鈫� 瀵煎叆涓�娆℃簮鏂囦欢 鈫� 鍒犳ā鏉� 鈫� 鍥炶涓夊紶琛� + 纾佺洏鐩綍銆�
+4. **瀹氬ず 13.7 鈶� 鐨勫鍎� blob 澶勭疆**锛堟竻鐞� vs 褰掓。绱Н锛夛紝瀹氬畬鍐嶅姩鎵嬨��
+5. **淇� 搂12.3.3 鐨勯暱琛ㄥ垎椤电己闄�**锛氭妸 `PdfPrintOptions.PRINT_CSS` 鐨� `table` 浠� `break-inside: avoid` 鍚嶅崟閲屾憳鎺夛紝鍐嶅涓�娆� 60 琛� fixture 纭绗� 1 椤典笉鍐嶇暀鐧姐��
+6. **鏉冮檺鐮佸叆 `system_menu`**锛歚qc-report:template:ai-import` 涓� `qc-report:instance:*` 鐩墠闈犺秴绠$洿閫氾紝姝e紡鍚敤鍓嶈钀借彍鍗曡锛堝睘鍒濆鍖栬剼鏈彉鏇达紝鎸� `sql-config-export-init.md` 璧帮級銆�
+
+---
+
+## 鍗佸洓銆佹敹鍙d笁浠讹紙2026-09-19锛夆�斺�� 搂13.10 寰呭姙 2/3/5/6 涓殑鍥涢」钀藉湴
+
+> 鏈妭鎶� 搂13.10 閲屻�屽凡鍐欎唬鐮佷絾娌¢獙杩囥�嶅拰銆屽帇鏍规病鍋氥�嶇殑鍑犻」涓�娆℃�ф竻鎺夛紝骞惰ˉ涓婂钩鍙扮殑**鍑轰欢闂幆鍓嶇**銆�
+> 涓�鍙ヨ瘽缁撹锛�**闀胯〃鍒嗛〉缂洪櫡宸蹭慨涓旀湁涓�鏉″彲澶嶇幇鐨勫垽鎹�**锛�**AI 瀵煎叆鐨勫鍎� blob 闅愭偅宸蹭慨涓旀湁 15 鏉℃柇瑷�**锛�
+> **鎶ュ憡瀹炰緥浠庛�屽彧鏈� 8 涓悗绔帴鍙c�嶅彉鎴愩�岄〉闈笂鑳界偣銆�**锛屾潈闄愮爜涔熻惤搴撲簡銆�
+
+### 14.1 #43 闀胯〃鍒嗛〉缂洪櫡 鈥斺�� 鉁� 宸蹭慨锛屼笖鐣欎笅浜嗕竴鏉℃満鍣ㄥ彲鍒ょ殑鍒ゆ嵁
+
+**鏀圭殑鏄粈涔�**锛歚PdfPrintOptions.PRINT_CSS` 閲� **鎶� `table` 浠� `break-inside: avoid` 鍚嶅崟鎽樻帀**锛屼繚鐣� `tr/td/th/img`銆�
+
+```java
+// 鏀瑰墠锛歵r, td, th, img, table { break-inside: avoid; ... }
+// 鏀瑰悗锛�
+tr, td, th, img { break-inside: avoid; page-break-inside: avoid; }
+```
+
+**涓轰粈涔�**锛歚break-inside: avoid` 鍔犲湪 `table` 涓婃槸銆屾暣寮犺〃涓嶈璺ㄩ〉銆嶃��60 琛屾楠岄」鐨勮〃鍦ㄤ竴椤垫斁涓嶄笅鏃讹紝Chromium 浼氭妸**鏁村紶琛�**鎼埌涓嬩竴椤碉紝绗� 1 椤靛彧鍓╅〉鐪変笌涓�澶х墖绌虹櫧銆傞暱琛ㄨ法椤电殑姝hВ鏄� `thead { display: table-header-group }` 璁╄〃澶存瘡椤甸噸澶� + 琛屽唴涓嶆柇椤碉紝杩欎袱鏉℃湰鏉ュ氨鍦ㄣ�傛敼鍓嶇殑瀹炴祴鐜拌薄璁板綍鍦� 搂12.3.3銆�
+
+**鍒ゆ嵁锛堣繖鏄湰娆℃渶鏈変环鍊肩殑閮ㄥ垎锛�**锛氶�犱竴浠� 60 琛屽惊鐜〃鏍� + 鍐呭祵鍥剧墖鐨勪复鏃舵ā鏉垮苟鍑轰欢瀵煎嚭锛坄D:/qcl-tmp/pdf-visual-fixture.mjs`锛夛紝鍐嶇敤 `PageFillProbe.java` 鎸夐〉缁熻鏂囨湰閲忎笌鍏抽敭璇嶃�岄」鐩�嶇殑鍑虹幇娆℃暟锛�
+
+| 鎸囨爣 | 鏀瑰墠锛埪�12.3.3 璁板綍锛� | 鏀瑰悗锛堟湰娆″疄娴嬶級 |
+|---|---|---|
+| 绗� 1 椤靛叧閿瘝鍛戒腑鏁� | **0**锛坄VERDICT=FIRST_PAGE_BLANK`锛� | **36**锛坄VERDICT=FIRST_PAGE_HAS_ROWS`锛� |
+| 鍒嗛〉 | 1 椤碉紙琛ㄨ鏁翠綋鎺ㄥ埌涓嶅瓨鍦ㄧ殑绗� 2 椤靛鑷存孩鍑猴級 | 2 椤碉紝page1 36 琛� / page2 26 琛� |
+
+`pdf-visual-fixture.mjs` 鏈疆 **11/11 PASS**锛�60 椤瑰嚭浠跺悗 `<tr>` 鏁� = 61锛�60 鏁版嵁 + 1 琛ㄥご锛夈�佷骇鐗� HTML 淇濈暀 `data:image` 鍐呭祵鍥俱�乣@page` 鏄� `210mm 297mm`銆丳DF 2 椤点�丮ediaBox `594.96 脳 841.92`锛圓4 绔栫増锛夈�佸惈 `/Subtype /Image`銆佸惈 `/FontFile2`銆�
+
+> 淇� `pdf-visual-fixture.mjs` 鐨勪竴澶�**鏂█鑷韩鍐欓敊**锛氬獟浣撶洅鏂█鍘熷啓姝� `/0 0 595\.\d+ 841\.\d+/`锛岃�� Chromium 鍑虹殑 A4 鏄� `594.95996 脳 841.91998`鈥斺�斿樊 0.05 pt 鏄诞鐐硅垗鍏ワ紝涓嶆槸绾稿瀷涓嶅銆傚凡鏀规垚甯﹀宸殑鏁板�兼瘮杈冦��**杩欎笉鏄悗绔己闄枫��**
+
+### 14.2 #44 AI 瀵煎叆瀛ゅ効 blob 闅愭偅 鈥斺�� 鉁� 宸蹭慨锛�15/15 鏂█
+
+搂13.7 鈶� 鎻愮殑闅愭偅锛屽缃彛寰勫畾涓� **銆屾浛鎹€�嶈�屼笉鏄�岀疮绉��**锛氫竴娆″鍏ュ搴斾竴浠芥簮鏂囦欢锛屾柊鐨勮繘鏉ャ�佹棫鐨勫嚭鍘汇�傛簮鏂囦欢鍙槸璇嗗埆鐢ㄧ殑杈撳叆锛屾ā鏉跨湡姝g殑浜х墿鏄増鏈� Schema锛屾病鏈夊綊妗e畠浠殑蹇呰銆�
+
+**鏀圭殑鏄粈涔�**锛歚ai-import-modal.vue` 鍦� `bind` **涔嬪墠**鍔犱竴姝� `removeExistingSourceFiles(templateId)` 鈥斺�� 鍏� `listAttachments(recordType=qc_report_template, recordId)` 鎷垮埌鏃ч檮浠� id锛屽啀 `deleteAttachments(ids)`锛岀劧鍚庢墠涓婁紶鈫掔粦瀹氭柊鏂囦欢銆�
+
+**涓轰粈涔堝繀椤诲崟鐙垹**锛歚bind` 鐨勫疄鐜版槸銆屽彧鍒犳棫鐨�**闄勪欢鍏宠仈璁板綍**锛屼繚鐣� **blob 璁板綍**锛堟枃浠舵湰韬笉鍒犻櫎锛夈�嶃�傛墍浠ユ寚鏈涚粦瀹氶『鎵嬫竻鐞嗘槸閿欑殑鈥斺�旀棫鏂囦欢鍒犱笉浜嗚涔熷垹涓嶄簡鐩橈紝閲嶅瀵煎叆鍑犳纾佺洏涓婂氨澶氬嚑浠藉啀娌′汉寮曠敤鐨勬枃浠躲��
+
+**瀹炴祴锛坄D:/qcl-tmp/verify-44-blob-lifecycle.mjs`锛�15/15 PASS锛�**锛屽鍒诲墠绔洓姝ユ椂搴忥紝鐩存帴姣斿 DB 涓庣鐩橈細
+
+| 鏂█ | 缁撴灉 |
+|---|---|
+| 涓婁紶 A 鈫� 鍒犳棫锛堟鏃朵负绌猴級鈫� 缁戝畾 A锛氶檮浠跺垪琛� 1 鏉°�佺鐩樻湁 A | 鉁� |
+| 鍐嶄笂浼� B 鈫� 鍒犳棫锛堟鏃舵槸 A锛夆啋 缁戝畾 B | 鉁� `code=0` |
+| **A 鐨勭鐩樻枃浠堕殢涔嬪垹闄わ紙#44 鐨勬牳蹇冿級** | 鉁� `...round-a.txt exists=false` |
+| 鏇挎崲鍚庨檮浠跺垪琛ㄥ彧鍓� B锛孊 鐨勭鐩樻枃浠朵粛鍦� | 鉁� |
+| 鍒犳ā鏉� 鈫� 闄勪欢鍒楄〃娓呯┖銆丅 鐨勭鐩樻枃浠朵篃琚竻鎺� | 鉁� |
+
+鏈�鍚庝竴鏉″悓鏃舵妸 搂13.10 寰呭姙 3銆�**瀹炴祴鍒犳ā鏉块『甯︽竻闄勪欢涓� blob**銆嶄竴璧烽獙浜嗭細`deleteTemplate` 閲岀殑 `deleteAttachmentsByRecord(QC_REPORT_TEMPLATE, id)` 纭疄鐢熸晥锛坄live attachment for template 15 = 0`锛屼袱涓� blob 琛屽潎 `deleted=1`锛岀鐩樻棤娈嬬暀锛夈��
+
+### 14.3 #45 鍓嶇鎶ュ憡瀹炰緥椤� 鈥斺�� 鉁� 宸茶惤鍦帮紝娴忚鍣ㄥ叏閾捐矾楠屾敹閫氳繃
+
+**杩欐槸 搂13.10 閲屾病鏈夌殑涓�椤�**锛氭鍓嶅钩鍙扮殑 8 涓疄渚嬫帴鍙�**鍓嶇涓�涓兘娌℃帴**锛屻�屽嚭浠堕棴鐜�嶅湪椤甸潰涓婄偣涓嶅埌銆傛湰杞ˉ榻愩��
+
+| 灞� | 鏂囦欢 | 鐘舵�� |
+|---|---|---|
+| API | `mom-pro2-before/src/api/mes/qc/report/instance/index.ts` | 鏂板缓锛堟鍓嶅畬鍏ㄤ笉瀛樺湪锛� |
+| 鍒楄〃椤� | `.../views/mes/qc/report/instance/index.vue` + `data.ts` | 鏂板缓锛岃矾鐢� `/qc/report-instance` |
+| 璇︽儏寮圭獥 | `.../instance/modules/detail.vue` | 鏂板缓锛氭姤鍛婇瑙堬紙iframe锛�/ 鏁版嵁蹇収 / 瀵煎嚭 PDF |
+| 鏉冮檺 | `system_menu` 6 琛� | 鑿滃崟銆屾姤鍛婂疄渚嬨��+ 鏌ヨ/鍑轰欢/瀵煎嚭PDF/鍒犻櫎 4 涓寜閽� + `qc-report:template:ai-import` |
+| 鑱旇皟鏂规 | `docs/qc_report_instance_frontend_integration.md` | 澧為噺鏇存柊锛堝師 PDF 杞凡寤猴級 |
+
+**鏉冮檺閾惧叏绋嬭拷杩囦竴閬�**锛堣繖鍐冲畾浜嗚涓嶈閲嶅惎鍚庣锛夛細鍚庣 `@ss.hasPermission` 瀵硅秴绠$煭璺斁琛岋紱鍓嶇 `hasAccessByCodes` 鏄嬁 `accessCodes` 鍋�**绮剧‘闆嗗悎鍖归厤**锛岃�屽畠鐢� `/get-permission-info` 鐜板満浠� `menuService.getMenuList(menuIds)` 鏋勫缓锛宍getMenuList()` **涓嶆槸 `@Cacheable`**銆傗噿 **鍙彃 `system_menu` 琛岋紝鍒锋柊椤甸潰鍗冲彲鐢熸晥锛屼笉闇�瑕侀噸鍚悗绔��** 宸插疄娴嬶細鏂拌彍鍗曢」鍑虹幇鍦ㄤ晶鏍忋�乣/qc/report-instance` 璺敱鍙繘銆佹寜閽甯告覆鏌撱��
+
+**娴忚鍣ㄩ獙鏀讹紙Playwright MCP锛�6 寮犳埅鍥撅級**锛�
+
+| 楠岃瘉鐐� | 缁撴灉 |
+|---|---|
+| 鍒楄〃娓叉煋 | 5 琛岋紱妯℃澘鍚� / 涓氬姟绫诲瀷锛坄mes_qc_oqc`鈫掑嚭璐ф楠岋級/ 鐢熸垚浜猴紙缂栧彿鈫掓樀绉帮級**閮芥纭В鏋�**锛屾棤 `妯℃澘 #id` 鎴栬8缂栧彿娈嬬暀 |
+| 璇︽儏寮圭獥 | Descriptions 榻愬叏锛屾ā鏉跨増鏈豢鑹� Tag銆佺姸鎬佽蛋 `DictTag` |
+| **鎶ュ憡棰勮椤电** | iframe锛坄sandbox=""`锛�**鐪熸覆鍑烘姤鍛婃湰浣�**锛屽惈鍐呭祵鍥剧墖鐨勭孩/缁挎笎鍙橈紱60 琛岃〃鏍煎彲瑙� |
+| 鏁版嵁蹇収椤电 | 鍐荤粨鐨� context JSON 姝e父灞曠ず + 璇存槑鎬� Alert |
+| **瀵煎嚭 PDF 鎸夐挳** | toast銆屽凡鐢熸垚 VERIFY鈥�.pdf锛�44.25 KB锛岃�楁椂 1615 姣锛夈�嶏紝寮圭獥鍐呭嚭鐜般�屽湪绾块瑙� / 涓嬭浇 PDF銆� |
+| **閲嶅瀵煎嚭涓嶅爢鏂囦欢** | 鍚屽疄渚嬭繛鐐� 3 娆″悗锛宍system_storage_attachment` 鍙湁 **1 鏉℃湁鏁堣**锛堝墠涓ゆ潯 `deleted=1`锛夈�乣system_storage_blob` 瀵瑰簲琛屽悓鏍疯蒋鍒犮��**纾佺洏鐩綍閲屽彧鐣欏綋鍓嶈繖涓�浠� PDF** |
+
+**鍓嶇闆舵柊澧炵被鍨嬮敊璇�**锛歚vue-tsc --noEmit`锛堝甫 8 GB 鍫嗗弬鏁帮級鎬昏 **316 椤�**锛堜笌鏃㈡湁鍩虹嚎瀹屽叏涓�鑷达級锛屽叾涓� `qc/report` 鐩稿叧鏂囦欢 **0 椤�**銆�
+
+### 14.4 鍒濆鍖栬剼鏈� 鈥斺�� 缁撹锛�**鏈鏃犻渶鏀瑰姩**
+
+6 鏉¤彍鍗曡鍙彃杩涗簡杩愯搴� `ruoyi-vue-pro`銆傛寜 `sql-config-export-init.md` 鏈閲嶆柊鐢熸垚 `config_export_all_<鏃ユ湡>.sql`锛屼絾瀹為檯鎯呭喌涓嶅悓锛�
+
+> **璇ユ枃浠剁殑銆岄樁娈典簩銆嶄笉鏄瓧闈㈤噺 INSERT锛岃�屾槸鎵ц鏈熺殑璺ㄥ簱鎷疯礉** 鈥斺��
+> `INSERT INTO system_menu SELECT * FROM \`ruoyi-vue-pro\`.system_menu WHERE deleted = b'0'`銆�
+> 鍙婧愬簱鏈夎繖鍑犺锛屽湪鏂板簱鎵ц鏃跺氨浼氳甯﹁繃鍘伙紝**涓庢枃浠跺唴瀹规棤鍏�**锛堥樁娈典竴鐨勫瓧闈㈤噺 INSERT 鎵嶉渶瑕侀噸鏂板鍑猴級銆�
+
+鎵�浠�**鏂囦欢鏈韩宸茬粡鏄渶鏂扮殑**銆傚凡鍦ㄦ枃浠跺ご銆岃ˉ涓佽鏄庛�嶅姞浜嗙 鈶� 鏉$櫥璁拌繖浠朵簨锛屽苟鍐欐槑銆屾澶勬棤闇�鏀瑰姩銆佺櫥璁板彧涓鸿鏄庤繖鐗堟枃浠剁‘瀹炶鐩栦簡璇ュ彉鏇淬�嶏紝閬垮厤鍚庢潵鑰呰浠ヤ负婕忎簡銆�
+
+### 14.5 鏈疆鍙戠幇鐨�**涓ゅ瀛橀噺鏁版嵁涓嶄竴鑷�**锛堜笉鏄湰杞唬鐮佸紩鍏ワ紝濡傚疄涓婃姤锛�
+
+鐢� `pdf-e2e.mjs` 澶嶈窇鏃跺嚭鐜� 2 鏉� FAIL锛�17/19锛夛紝閫愭潯杩藉埌鐨勬槸**鏁版嵁闂鑰岄潪缂洪櫡**锛�
+
+| 鐜拌薄 | 鏍瑰洜 |
+|---|---|
+| 鏂█銆岀焊闈㈡槸 A4 绔栫増銆嶅け璐ワ紝瀹炲緱 `MediaBox [0 0 841.92 594.96]`锛�**妯悜**锛� | 妯℃澘 5 鐨� `qc_report_template` 琛屽啓鐨勬槸 A4/**portrait**锛屼絾瀹�**鐗堟湰 schema 閲岀殑 `page.orientation` 鏄� landscape`**銆�**娓叉煋鍣ㄤ互 schema 涓哄噯**锛堢焊闈㈤厤缃殑鐪熺浉鍦ㄧ増鏈噷锛屼笉鍦ㄦā鏉胯涓婏級鈫� 琛屼笌 schema 涓嶄竴鑷达紝娓叉煋鎸� schema 璧� |
+| 鏂█銆�60 椤瑰簲鎵撴垚澶氶〉銆嶅け璐ワ紝瀹炲緱 1 椤� | 妯℃澘 5 **v1.0 鐨勭敾甯冩槸绌虹殑**锛坄{"components":[],鈥`锛宻chema 浠� 959 瀛楃锛夛紝60 琛岃〃鏍兼牴鏈病娓茶繘鍘汇�傝繖鏉℃柇瑷�鏄� v1.0 杩樻湁鍐呭鏃跺啓鐨勶紝鏁版嵁琚竻鍚庢柇瑷�灏辨偓绌轰簡 |
+
+**鍙︿竴鏉″�煎緱璁扮殑瑙勫垯鎬т簨瀹�**锛歚uk_report_no` **涓嶅尯鍒嗚蒋鍒犻櫎**銆備竴鏉″疄渚嬭鍒犻櫎鍚庡畠鐨勬姤鍛婄紪鍙蜂粛琚崰鐢紝鍐嶆鍑轰欢鍚屽彿浼氭姤 `1_070_102_001`銆傛湰杞�� fixture 鏃跺氨鎾炲埌杩囦竴娆★紙纭紪鐮佺殑 `PG20260918001` 涓庡凡杞垹鐨勫疄渚� 25 鍐茬獊锛夛紝鏀规垚甯︽椂闂存埑鐨勭紪鍙锋墠閫氳繃銆傚啓鑱旇皟鑴氭湰鏃�**涓嶈纭紪鐮佹姤鍛婄紪鍙�**銆�
+
+### 14.6 鈿� 宸查獙璇� / 鏈獙璇侊紙鎵挎帴 搂13.8锛�
+
+**鏈疆鏂版嬁鍒板疄娴嬭瘉鎹殑**锛�
+
+- 闀胯〃鍒嗛〉淇锛坄PageFillProbe` 鐨� `FIRST_PAGE_HAS_ROWS`锛屽惈鏀瑰墠鍚庡鐓э級锛�
+- AI 瀵煎叆婧愭枃浠舵浛鎹㈢殑 blob/纾佺洏鐢熷懡鍛ㄦ湡锛�15 鏉℃柇瑷�锛岀洿鏌� DB + 纾佺洏锛夛紱
+- 鍒犳ā鏉挎竻闄勪欢涓� blob锛堝悓鏃ラ獙璇侊級锛�
+- 鎶ュ憡瀹炰緥椤电殑鍒楄〃 / 璇︽儏 / iframe 棰勮 / 蹇収 / 瀵煎嚭 PDF / 閲嶅瀵煎嚭涓嶅爢鏂囦欢锛�6 寮犳埅鍥撅級锛�
+- 鏉冮檺鐮佸叆 `system_menu` 鍚庡墠绔嵆鏃剁敓鏁堬紙鏃犻渶閲嶅惎锛夛紱
+- 鍓嶇绫诲瀷妫�鏌ラ浂鏂板閿欒锛�316 鈫� 316锛夈��
+
+**浠嶆湭楠岃瘉鐨勶紙鎵挎帴 搂13.8锛屾湰杞�**娌℃湁**鎺ㄨ繘锛�**锛�
+
+- **`yudao.qcreport.ai-import.enabled=false 鈫� 1_070_104_000`** 鈥斺�� 浠嶆湭瀹炴祴銆�
+- **瓒呮椂鍒嗘敮 `1_070_104_011`** 鈥斺�� 浠嶆湭瀹炴祴銆�
+- **瓒呴〉 / 鍚堣瓒呴〉 / 瓒呭ぇ灏忎笁鏉★紙`FILE_TOO_MANY_PAGES` / `TOO_MANY_PAGES_TOTAL` / `FILE_TOO_LARGE`锛�** 鈥斺�� 浠嶆湭瀹炴祴锛岀己瓒呴檺 fixture銆�
+- **`yudao.qcreport.pdf.enabled=false 鈫� 1_070_103_008`** 鈥斺�� 浠嶆湭瀹炴祴銆�
+- **AI 璇嗗埆鍑嗙‘鐜�** 鈥斺�� 浠嶆湭搴﹂噺銆�
+- **Linux 閮ㄧ讲** 鈥斺�� 浠嶆湭楠屻��
+
+> 杩欎簲椤归兘闇�瑕�**涓存椂鏀归厤缃� + 閲嶅惎鍚庣**锛岄泦涓湪涓嬩竴杞竴娆″仛瀹岋紙瑙� 14.7锛夈��
+
+### 14.7 涓嬩竴姝�
+
+1. **涓�娆℃�цˉ瀹岄厤缃垎鏀疄娴�**锛堟敼涓�娆¢厤缃� + 閲嶅惎涓�娆★紝鎶婂洓鏉′竴璧锋墦鎺夛級锛歚ai-import.enabled=false` 鈫� `104_000`锛沗yudao.ai.timeout=1s` 鈫� `104_011`锛涜秴澶у皬 fixture 鈫� `104_004`锛沗pdf.enabled=false` 鈫� `103_008`銆�
+2. **瀹氬ず骞朵笂鎶ユā鏉� 5 鐨勩�岃 vs schema 绾稿瀷涓嶄竴鑷淬�嶄笌銆寁1.0 绌虹敾甯冦��**锛堣 14.5锛夆�斺�� 灞炲瓨閲忔暟鎹紝闇�浜哄伐纭鏄慨鏁版嵁杩樻槸鏀� `pdf-e2e.mjs` 鐨勬柇瑷�銆�
+3. **`MesQcReportApi` + 鍥涚璐ㄦ鍗曞綊涓�鍖�**锛氭妸銆岃川妫�鍗� 鈫� 鍑烘姤鍛娿�嶇殑鍏ュ彛鎺ヤ笂锛屽眾鏃跺垪琛ㄩ〉鐨� `qc-report:instance:create` 鏉冮檺鐮佹墠鐪熸鐢ㄥ緱涓婏紙鐜板凡棰勭疆鍏ュ簱锛夈��
+4. **鍗曠嫭寮�淇椤癸細ERP/CRM/MES 涓夊 `tempFile.delete()` 缂洪櫡**锛堝悓鏋勪笁澶勶紝鍒犵殑鏄敤鎴风湡瀹炰笂浼犵殑 blob 鏂囦欢鏈韩锛夈��
+5. 鍏朵綑缁存寔涓嶅彉锛氬叆绔� HTML 鍑�鍖栥�佷簩缁寸爜鐢熸垚銆乣qc_report_data_source`/`qc_report_rule` 涓ゅ紶鏃� Java 瀵瑰簲鐨勮〃銆�
+
+---
+
+## 鍗佷簲銆侀檺鍒朵笌閰嶇疆鍒嗘敮瀹炴祴锛�2026-09-19锛�
+
+搂14.6 鍒楃殑浜旈」鏈獙璇侊紝鏈疆鍏ㄩ儴鎵撴帀銆�**涓嶆敼浠讳綍涓氬姟浠g爜锛屽彧鍋氶獙璇�**锛屾墍浠ユ湰鑺傛病鏈変氦浠樼墿锛屽彧鏈夎瘉鎹笌涓変釜鏂版毚闇茬殑闂銆�
+
+### 15.1 鏂规硶锛氭妸楠岃瘉鑴氭湰鍖栵紝鑰屼笉鏄墜鐐�
+
+涓夋潯鑴氭湰鏀惧湪 `D:/qcl-tmp/`锛堜笉鍏ュ簱锛夛細
+
+| 鑴氭湰 | 瑕嗙洊 | 鏄惁闇�閲嶅惎 |
+|---|---|---|
+| `verify-46-limit-branches.mjs` | 杈撳叆鏍¢獙绫� 10 渚� | 鍚� |
+| `verify-46-config-a.mjs` | 涓や釜 `enabled=false` 寮�鍏� | 鏄紙鏀归厤缃級 |
+| `verify-46-config-b.mjs` | AI 璋冪敤瓒呮椂 | 鏄紙鏀归厤缃級 |
+
+澶氶〉 PDF fixture锛坄p6/p5a/p5b.pdf`锛夌敤 Playwright 鐜伴�犮��**椤垫暟涓嶇敱鑴氭湰鑷О銆佺敱鍚庣鑷繁鎶ュ嚭鏉�**锛�"鍏� 6 椤�"/"鍚堣 10 椤�"锛夛紝閬垮厤鑷瘉銆�
+
+### 15.2 瀹炴祴缁撴灉锛�11 鏉¢敊璇爜 + 1 鏉′笂浼犲彛鎷︽埅
+
+| 鍦烘櫙 | 棰勬湡鐮� | 缁撴灉 |
+|---|---|---|
+| blobId 涓嶅瓨鍦� | `1_070_104_001` | 鉁� |
+| `.exe` | `1_070_104_002` | 鉁� |
+| `.doc` 鏃ф牸寮� | `1_070_104_003` | 鉁� |
+| 21MB 鏂囦欢 | `1_070_104_004` | 鉁� |
+| 鍙湁绌虹櫧鐨� txt / 鎹熷潖鐨� xlsx | `1_070_104_005` | 鉁� |
+| 缁勪欢娓呭崟 41 椤� / 鏌愰」缂� type | `1_070_104_008` | 鉁� |
+| `schemaVersion=1.0` | `1_070_104_009` | 鉁� |
+| 6 椤� PDF锛堝崟鏂囦欢瓒� 5 椤碉級 | `1_070_104_007` | 鉁� |
+| 涓や釜 5 椤� PDF锛堝悎璁� 10 > 8锛� | `1_070_104_014` | 鉁� |
+| `ai-import.enabled=false` | `1_070_104_000` | 鉁� |
+| `yudao.ai.timeout=1s` | `1_070_104_011` | 鉁� |
+| `pdf.enabled=false` | `1_070_103_008` | 鉁� |
+| 4 涓枃浠� | 鈥� | 鈿� 瑙� 15.3 闂涓� |
+
+涓ゆ潯銆屾湭鍚敤銆嶆彁绀洪兘鐐瑰悕浜嗗叿浣撻厤缃」锛坄yudao.qcreport.ai-import.enabled` / `yudao.qcreport.pdf.enabled`锛夛紝鐢ㄦ埛鑳界収鐫�鏀广�俙ai-import.enabled=false` 閭d緥**鏁呮剰浼犱笉瀛樺湪鐨� blobId**锛屼粛鎷垮埌 `104_000` 鑰岄潪 `104_001` 鈥斺�� 椤哄甫璇佹槑寮�鍏虫鏌ユ帓鍦ㄦ枃浠惰鍙栦箣鍓嶃��
+
+**0 瀛楄妭鏂囦欢璧颁笉鍒颁笟鍔″眰**锛歴torage 涓婁紶鍙g洿鎺ヤ互 `涓婁紶鏂囦欢涓嶈兘涓虹┖`锛坈ode `1002029000`锛夋嫆缁濓紝鎵�浠� `OfficeImportAdapter` 閲� `content.length == 0` 閭f潯鍒嗘敮缁� HTTP 涓嶅彲杈撅紱`text.isBlank()` 閭f潯鎵嶆槸瀹為檯鐢熸晥鐨勶紙鐢ㄥ彧鏈夌┖鐧界殑 txt 楠屽埌锛夈�傚睘姝e父鐨勭旱娣辫闃诧紝浠呰褰曘��
+
+### 15.3 涓変釜娴嬪嚭鏉ョ殑闂
+
+**闂涓�锛歚max-files` 杩欎釜閰嶇疆椤瑰彧鑳藉線涓嬭皟锛屼笉鑳藉線涓婅皟銆�**
+
+`QcReportAiImportReqVO.blobIds` 涓婂啓姝讳簡 `@Size(max = 3)`锛孊ean Validation 鍏堜簬鏈嶅姟鎵ц銆傚悗鏋滄湁涓ゅ眰锛�
+
+1. `AI_IMPORT_TOO_MANY_FILES`锛坄104_006`锛夊湪榛樿閰嶇疆涓�**涓嶅彲杈�** 鈥斺�� 浼� 4 涓枃浠舵嬁鍒扮殑鏄� HTTP 400銆屼竴娆℃渶澶氳瘑鍒� 3 涓枃浠躲�嶏紝鑰屼笉鏄繖涓敊璇爜銆傛湇鍔¢噷鐨� `validateFileCount` 涓� VO 娉ㄨВ闄愮殑鏄悓涓�浠朵簨銆�
+2. 鎶� YAML 閲岀殑 `max-files` 璋冨埌 5 涔�**涓嶄細鐢熸晥**锛堜粛琚� `@Size(max=3)` 鍗″湪 3锛夛紝鍙湁璋冨埌 3 浠ヤ笅鎵嶆湁鎰忎箟銆�
+
+浠g爜閲屾病鏈変换浣曟敞閲婅鏄庤繖涓や釜鏁板瓧鏄�﹀悎鐨勶紝鍚庢潵鐨勭淮鎶よ�呭ぇ姒傜巼浼氫互涓烘敼 YAML 灏辫兘鏀惧紑銆�
+
+**闂浜岋細鎹熷潖鐨� Office 鏂囦欢缁欏嚭鐨勬槸銆屾壂鎻忎欢鍒嗚鲸鐜囥�嶇殑寤鸿銆�** 鉁� **宸蹭慨锛岃 搂15.7**
+
+浼犱竴涓崯鍧忕殑 `.xlsx`锛岃繑鍥� `104_005`锛�
+
+> 鏂囦欢銆宐roken.xlsx銆嶆湭瑙f瀽鍑轰换浣曞彲鐢ㄥ唴瀹癸紙鍏� 1 椤碉級銆�**鑻ユ槸鎵弿浠讹紝璇风‘璁ゅ垎杈ㄧ巼涓嶄綆浜� 200 DPI銆佹枃瀛楁棤涓ラ噸鍊炬枩鎴栭伄鎸�**锛涙帹鑽愭敼鐢ㄧ數瀛愮増 PDF 鎴� Word/Excel
+
+鐪熷疄鍘熷洜鏄�**鏂囦欢鎹熷潖鎴栦笉鏄湁鏁堢殑 Excel**锛屼笌鎵弿鍒嗚鲸鐜囧拰 PDF 姣棤鍏崇郴锛坄readXlsx`/`readDocx` 鐨� catch 鍧楃粺涓�鎶� `FILE_EMPTY`锛夈�傛寜鎻愮ず鎿嶄綔鐨勭敤鎴蜂細鍘昏皟鍒嗚鲸鐜囥�佹崲 PDF锛屾�庝箞璇曢兘涓嶄細濂姐�傝繖杩濆弽 `.claude/rules/error-message-precision.md` 鐨勪笁瑕佺礌锛堝叿浣撶淮搴� / 鍙屾柟鍊� / 鍙墽琛屽姩浣滐級鈥斺�� 缁村害鎸囬敊浜嗭紝鍔ㄤ綔涔熷氨閿欎簡銆�**寤鸿鍔犱竴涓笓灞為敊璇爜**锛堝 `AI_IMPORT_OFFICE_CORRUPT`锛夛紝鏂囨鎸囧悜"鏂囦欢鍙兘宸叉崯鍧忥紝璇风敤 Excel/Word 閲嶆柊鎵撳紑骞跺彟瀛樹负 .xlsx/.docx 鍚庨噸璇曪紱鑻ュ師鏂囦欢鏈夊瘑鐮佷繚鎶よ鍏堣В闄�"銆�
+
+**闂涓夛紙鏈�閲嶈锛夛細`yudao.ai.timeout` 涓嶆槸绔埌绔�楁椂涓婇檺銆�**
+
+閰� `1s`锛屽疄娴嬬鍒扮 **7967ms**锛屾棩蹇楅噷鐨勫紓甯告槸 `OpenAIIoException 鈫� InterruptedIOException: timeout 鈫� SocketTimeoutException`锛坥khttp3 HTTP/2锛夈�俙isTimeout()` 璁ゅ嚭浜嗗畠锛屾墍浠ユ槧灏勫埌 `104_011` 鏄鐨� 鈥斺�� **浣� 1 绉掑彉鎴愪簡 8 绉�**銆�
+
+璇� `openai-java-core` 婧愮爜锛坄RetryingHttpClient.kt` / `ClientOptions.kt`锛夌‘璁や簡涓変釜涔樻暟锛�
+
+1. **SDK 榛樿 `maxRetries = 2`**锛屽嵆鏈�澶� 3 娆″皾璇曘�俙shouldRetry()` 鏄庣‘鎶� `IOException` 涓� `OpenAIIoException` 鍒椾负鍙噸璇� 鈥斺�� **瓒呮椂鏈韩灏变細琚噸璇�**銆�
+2. 閫�閬� `min(0.5 脳 2^(n-1), 8s)` 鍐嶄箻 jitter锛屼袱娆¢棿闅旂害 1.1锝�1.5s銆�
+3. `OpenAiChatOptions.timeout` 璁剧殑鏄�**璇�/娴佽秴鏃�**锛屼笉瑕嗙洊 okhttp 鐨� `connectTimeout`锛堥粯璁� 10s锛夈�傛彙鎵嬮樁娈典笉鍚冭繖涓绠椼��
+
+鈬� 鐢熶骇閰嶇殑 `60s`锛�**鐢ㄦ埛鍙鐨勬渶鍧忕瓑寰呯害 3 鍒嗛挓**锛�60脳3 + 閫�閬� + 閲嶈繛锛夛紝涓嶆槸 60 绉掋�傜晫闈㈡彁绀哄啓鐨勬槸"棰勮 10鈥�60 绉�"锛屽樊 3 鍊嶃�傛枃妗堟湰韬病楠椾汉锛堝畠璇荤殑鏄湡瀹� `elapsed`锛屽瀹炲啓浜�"宸茬瓑 7 绉�"锛夛紝浣�**绛夊緟鏃堕暱涓庣敤鎴烽鏈熻劚鑺�**銆�
+
+杩欎笉鏄綋鍒濋偅鏉� `timeout` 淇娌$敓鏁堬紝鑰屾槸淇鐢熸晥鍚庢毚闇插嚭鐨勭浜屽眰锛氭妸 per-attempt 瓒呮椂褰撴垚浜嗘暣浣撹秴鏃躲�傚彲閫夊缃紙鍚勬湁鍙栬垗锛屽緟瀹氬ず锛夛細缁欒繖涓ā鍨嬪叧鎺夐噸璇曪紙`maxRetries(0)`锛屼絾浼氬け鍘诲娴佹帶 429 鐨勫脊鎬э級锛涙垨淇濇寔閲嶈瘯銆佹妸 YAML 鍊兼寜 `棰勬湡 梅 3` 璁撅紱鎴栨帴鍙楃幇鐘朵粎鎶婄晫闈㈡枃妗堟敼鎴�"鏈�鍧忕害 3 鍒嗛挓"銆�
+
+### 15.4 闄勫甫鐨勫疄璇侊細闄勪欢 bind 浼氭案涔呭鍎垮寲鏃� blob
+
+璺� `verify-46-limit-branches.mjs` 鏃舵垜婕忔帀浜嗗墠绔� `removeExistingSourceFiles` 閭d竴姝ワ紝鐩存帴杩炵画 `bind`锛岀粨鏋� **7 涓� blob锛堝惈涓�涓� 21MB 鐨勶級琛屼笌纾佺洏鏂囦欢鍏ㄩ儴澶卞幓寮曠敤**銆�
+
+閾捐矾锛歚saveStorageAttachmentByRecordTypeAndRecordId` 鍙蒋鍒�**鏃х殑闄勪欢鍏宠仈琛�**锛屼笉纰� blob銆傝疆鍒颁笅涓�涓� `stage()` 鍐� bind 鏃讹紝涓婁竴鎵归檮浠惰琚蒋鍒狅紝鑰屽畠浠寚鍚戠殑 blob 鍐嶆病鏈変换浣曟湭鍒犻櫎鐨勯檮浠惰寮曠敤 鈥斺�� 娌℃湁浠讳綍鏈哄埗浼氬洖鏀跺畠銆�
+
+**杩欏潗瀹炰簡 `memory/qc-report-platform.md` 閲岄偅鏉¤鍛婏紝骞惰ˉ涓婂畠鐨勬帹璁猴細闃插鍎跨殑閭i亾闂搁棬鍦ㄨ皟鐢ㄦ柟锛堝墠绔� `removeExistingSourceFiles`锛夛紝瀛樺偍灞傛湰韬病鏈変换浣曞厹搴曘��** 鍓嶇鐩墠鍋氬浜嗭紱浣嗕换浣曠粫杩囧墠绔殑璋冪敤鏂癸紙鍚仈璋冭剼鏈級閮戒細闈欓粯婕忔枃浠躲�傛畫鐣欏凡鐢ㄤ骇鍝佽嚜韬殑绾ц仈锛堢粦鍒颁复鏃舵ā鏉� 鈫� 鍒犳ā鏉匡級娓呭共鍑�锛孌B 涓庣鐩橀兘鏍稿杩囥��
+
+### 15.5 鈿� 浠嶆湭楠岃瘉锛堣瘹瀹炲0鏄庯級
+
+- **`104_010 AI_UNAVAILABLE`**锛氶渶瑕佹妸 `ai_api_key`/`ai_model` 鏀瑰潖鎵嶈兘瑙﹀彂锛屼細褰卞搷 ERP/CRM/MES 鐨勫叏閮� AI 璋冪敤锛岄闄╁ぇ浜庢敹鐩娿�傚畠鏄� `104_011` 鍚屼竴涓� try/catch 鐨勫厹搴曞垎鏀紝寮傚父鏀跺彛璺緞宸茶瓒呮椂鐢ㄤ緥璇佹槑鍙敤銆�
+- **`104_012 RESPONSE_UNPARSEABLE` / `104_013 DRAFT_EMPTY`**锛氶渶瑕佹ā鍨嬭繑鍥炵暩褰㈡垨绌虹粨鏋滐紝鏃犳硶纭畾鎬цЕ鍙戙�備袱鑰呴兘鏈夌函鍗曟祴瑕嗙洊锛坄QcReportAiDraftParser` 缃愬ご瀛楃涓� / `Normalizer` 绌虹粨鏋滐級锛岀己鐨勫彧鏄鍒扮閭d竴姝ャ��
+- **AI 璇嗗埆鍑嗙‘鐜�**锛氫粛鏈害閲忥紙闇�瑕佷汉宸ユ爣娉ㄦ牱鏈紝鏄嫭绔嬭棰橈級銆�
+- **Linux 閮ㄧ讲**锛氫粛鏈獙銆�
+
+### 15.6 鏀跺熬鐘舵��
+
+閰嶇疆宸茶繕鍘燂細`application-local.yaml` 鐨� `pdf.enabled`銆乣ai-import.enabled` 鍥炲埌 `true`锛宍yudao.ai.timeout` 鍥炲埌 `60s`锛堜笁澶勪复鏃舵敼鍔ㄩ兘鐣欎簡 `銆�#46 涓存椂銆慲 鏍囪锛屽凡鍏ㄩ儴鎾ら攢锛夈�傛祴璇曟湡闂村缓鐨� 5 涓复鏃舵ā鏉匡紙id 16~20锛変笌 1 涓疄渚嬶紙id 37锛夎繛鍚屽叾闄勪欢銆乥lob 琛屻�佺鐩樻枃浠跺叏閮ㄥ垹闄ゃ��
+
+### 15.7 搂15.3 涓や釜鍐冲畾鐨勮惤鍦帮紙2026-09-19 缁級
+
+搂15.3 鐨勪笁涓棶棰橀噷锛岄棶棰樹竴锛坄@Size(max=3)` 涓� YAML 鑰﹀悎锛変笌闂涓夛紙`timeout` 鏄� per-attempt锛夊凡鎸夌敤鎴锋媿鏉垮缃紱闂浜岀殑淇硶濡備笅銆�
+
+**鍐冲畾涓�锛氳秴鏃朵笉鏀逛唬鐮侊紝鍙敼鐣岄潰鏂囨銆�**锛堥棶棰樹笁锛�
+
+鐢ㄦ埛鍙e緞鏄�"涓嶆敼浠g爜锛屽彧鎶婄晫闈㈡枃妗堟敼鎴愩�屾渶鍧忕害 3 鍒嗛挓銆�"銆傛敼鍔ㄥ彧鏈変竴澶勶細
+
+`mom-pro2-before/src/views/mes/qc/report/template/designer/modules/ai-import-modal.vue` 鐨勭瓑寰呮彁绀猴紝鐢�
+
+> 姝e湪璇嗗埆锛岄璁� 10鈥�60 绉掞紱鏂囦欢椤垫暟鎴栨暟閲忚緝澶氭椂鏇翠箙锛岃鍕垮叧闂〉闈€��
+
+鏀逛负
+
+> 姝e湪璇嗗埆锛岄璁� 10鈥�60 绉掋�傛壂鎻忎欢鎸夐〉閫愰〉璇嗗埆锛屾瘡椤靛崟鐙竴娆¤皟鐢紝椤垫暟澶氭椂浼氭槑鏄炬洿涔咃紱鏈�闀跨瓑寰呯害 3 鍒嗛挓锛岃秴鏃跺悗璇峰噺灏戞枃浠舵暟閲忔垨椤垫暟鍐嶈瘯銆傝鍕垮叧闂〉闈€��
+
+**娌℃湁**鍔� `src/api/mes/qc/report/ai/index.ts` 閲岄偅鏉� axios 鐨� `timeout: 180_000` 鈥斺�� 瀹冩伆濂戒笌"鐢ㄦ埛鍙鐨� 3 鍒嗛挓"鍚屽�硷紝鏄瘹瀹炵殑銆�
+
+> 鈿� **搂15.3 闂涓夌殑瑙勬ā闇�瑕佷慨姝o紙姹囨姤鍙e緞锛�**锛�3 鍒嗛挓鏄�**鍗曟 LLM 璋冪敤**鐨勬渶鍧忓�笺�傝�� `QcReportLlmCallPlanner` 瀵规壂鎻忎欢鏄�**姣忛〉涓�娆¤皟鐢�**锛屽崟璇锋眰涓婇檺 8 椤� 鈥斺�� 鍚庣鏈�鍧忓彲浠ヨ繛缁儳 8 杞�佺害 24 鍒嗛挓銆傚墠绔� 180 绉掑厛鎺愭柇锛屾墍浠�**鐢ㄦ埛鍙鐨勫氨鏄� 3 鍒嗛挓**锛堟枃妗堟病楠椾汉锛夛紝浣�**娴忚鍣ㄦ斁寮冧箣鍚庡悗绔粛鍦ㄧ户缁窇骞剁户缁璐�**銆傝繖鏄湰杞湭澶勭疆鐨勬畫鐣欙紝搴斿崟鐙紑涓�椤广��
+
+**鍐冲畾浜岋細涓烘崯鍧忕殑 Office 鏂囦欢鍔犱笓灞為敊璇爜銆�**锛堥棶棰樹簩锛�
+
+`1_070_104_015 AI_IMPORT_OFFICE_CORRUPT`锛�
+
+> 鏂囦欢銆孹銆嶆棤娉曚綔涓� .Y 鎵撳紑锛屽唴瀹瑰凡鎹熷潖鎴栧彈瀵嗙爜淇濇姢銆傝鍏堢敤 Office 鎵撳紑璇ユ枃浠讹紝纭鑳芥甯告樉绀哄悗銆屽彟瀛樹负銆�.docx / .xlsx 鍐嶉噸鏂板鍏ワ紱鑻ユ枃浠舵湁鎵撳紑瀵嗙爜锛岃鍏堣В闄ゅ瘑鐮佷繚鎶�
+
+鏀瑰姩涓夊锛�
+
+| 鏂囦欢 | 鏀瑰姩 |
+|---|---|
+| `enums/ErrorCodeConstants.java` | 鏂板 `AI_IMPORT_OFFICE_CORRUPT = 1_070_104_015`锛堣娈靛師姝簬 `_014`锛� |
+| `service/aiimport/document/OfficeImportAdapter.java` | `readDocx` / `readXlsx` 涓や釜 catch 鍧楃敱鎶� `FILE_EMPTY` 鏀逛负鎶涙柊鐮� |
+| `docs/qc_report_ai_import_frontend_integration.md` | 閿欒鐮佽〃澧炶锛沗_005` 鐨勮Е鍙戝満鏅敹绐勶紱涓氬姟瑙勫垯琛ㄥ銆岀┖鐧戒笌鎹熷潖鍒嗗紑鎶ャ�嶄竴琛� |
+
+**杈圭晫鍒绘剰鍒掓竻**锛歚text.isBlank()` 閭f潯鍒嗘敮浠嶆姏 `FILE_EMPTY`銆傝涔夋槸鈥斺��"鎵╁睍鍚嶅悎娉曚絾鍐呭涓�**绌�**"锛堝鍙湁绌虹櫧瀛楃鐨� `.docx`锛夎蛋 `_005`锛�"鎵╁睍鍚嶅悎娉曚絾鏂囦欢**鎵撲笉寮�**"锛堟崯鍧忋�佸姞瀵嗭級璧� `_015`銆備袱鑰呯粰鐢ㄦ埛鐨勫姩浣滃畬鍏ㄤ笉鍚岋紙鍓嶈�呮崲鏂囦欢锛屽悗鑰呬慨澶嶆枃浠讹級锛屼笉鑳藉悎鎴愪竴鏉°��
+
+`mvn compile -pl yudao-module-qcreport -am -q` 宸查�氳繃锛坄MVN_EXIT=0`锛夈�傛柊鐮佺殑绔埌绔楠岃 搂15.8銆�
+
+### 15.8 `1_070_104_015` 绔埌绔楠岋細**4/4 PASS**锛�2026-09-19 缁級
+
+閲嶅惎鍚庣鍚庤窇 `D:/qcl-tmp/verify-104-015.mjs`锛屽洓鏉$敤渚嬪叏缁匡紝瀹炴嵁濡備笅锛�
+
+| 鐢ㄤ緥 | 鏈熸湜鐮� | 瀹炴祴鐮� | 鎶ユ枃锛堟埅鏂級 |
+|---|---|---|---|
+| 鎹熷潖鐨� `.xlsx`锛堟湁 PK 澶淬�佸唴瀹逛笉鏄� zip锛� | `1_070_104_015` | 鉁� `1070104015` | 鏂囦欢銆宐roken.xlsx銆嶆棤娉曚綔涓� .xlsx 鎵撳紑锛屽唴瀹瑰凡鎹熷潖鎴栧彈瀵嗙爜淇濇姢鈥�**鍙﹀瓨涓�** .docx / .xlsx 鍐嶉噸鏂板鍏� |
+| 鎹熷潖鐨� `.docx`锛堟湁 PK 澶淬�佸唴瀹逛笉鏄� zip锛� | `1_070_104_015` | 鉁� `1070104015` | 鍚屼笂锛屾墿灞曞悕鏇挎崲涓� .docx |
+| 鏍规湰涓嶆槸琛ㄦ牸鐨� `.xlsx`锛堟棤 PK 澶达級 | `1_070_104_015` | 鉁� `1070104015` | 鍚屼笂 |
+| 鍙湁绌虹櫧鐨� `.txt`锛堝洖褰掞級 | `1_070_104_005` | 鉁� `1070104005` | 鏂囦欢銆宐lank.txt銆嶆湭瑙f瀽鍑轰换浣曞彲鐢ㄥ唴瀹癸紙鍏� 1 椤碉級鈥� |
+
+**涓ょ鎹熷潖褰㈡�侀兘褰掑埌 `_015`**锛堟湁 zip 澶翠絾鍐呭鍧� / 杩� zip 澶撮兘娌℃湁锛夛紝璇存槑 catch 瑕嗙洊闈笌棰勬湡涓�鑷达紱
+绌虹櫧鏂囦欢浠嶈蛋 `_005`锛�**杈圭晫娌℃湁琚繖娆℃敼鍔ㄦ斁瀹�**銆傛瘡涓敤渚嬮厤涓�涓竴娆℃�фā鏉垮苟鍦ㄦ柇瑷�鍚庡綋鍦哄垹闄わ紝
+浜嬪悗鏍稿 `qc_report_template.id >= 10` 鍏� 21 琛�**鍏ㄩ儴 `deleted=1`**銆乣qc_report_instance` 鍏ㄩ儴 `deleted=1`銆�
+`mes_qc_oqc` 鏃� `ZZ_E2E_%` 鈥斺�� 鏃犳椿鍔ㄦ畫鐣欍��
+
+### 15.9 鈿� 浠嶆湭楠岃瘉锛堣瘹瀹炲0鏄庯級
+
+- **鍓嶇鏂囨鏀瑰姩鏈粡 typecheck**锛歚ai-import-modal.vue` 鍙敼浜嗘ā鏉块噷鐨勫瓧绗︿覆锛岀悊璁烘棤绫诲瀷褰卞搷锛屼絾鏈窇 `vue-tsc` 纭锛堝熀绾� 316 鏉″瓨閲忛敊璇級銆�
+- 鍓嶇鏂囨涓� `timeout: 180_000` 鐨勪竴鑷存�у彧鏄�**浜哄伐鏍稿鍚屽��**锛屾湭鍋氭祻瑙堝櫒瀹炴祴銆�
+- 搂15.3 闂涓夌殑娈嬬暀浠嶅湪锛堟祻瑙堝櫒 180 绉掓斁寮冨悗锛屽悗绔粛缁х画璺戝畬骞剁户缁璐癸級锛屾湰杞湭澶勭疆銆�
+
+## 鍗佸叚銆佽川妫�鍗� 鈫� 鎶ュ憡瀵规帴锛�2026-09-19 缁級鈥斺�� 鉁� 绔埌绔� **19/19** 鍏ㄧ豢 + 鍓嶇銆屽嚭鎶ュ憡銆嶅叆鍙e凡鎺ュ叆骞� UI 楠屾敹閫氳繃锛堝墠鍚庣涓�骞惰惤鍦帮級
+
+鐢ㄦ埛鍘熻瘽锛�**銆屾姤鍛婃ā鏉胯璁¤繕鏄病鏈夊拰璐ㄦ鍏宠仈鍚э紝鐜板湪涓嶇煡閬撴�庝箞瀵煎嚭鏁版嵁銆�**銆傛湰鑺傝В鍐崇殑灏辨槸杩欏彞锛�
+璁� MES 鐨� IQC/IPQC/OQC/RQC 鍥涚被璐ㄦ鍗曡兘涓�閿嚭鎴愭姤鍛婏紝鍓嶇**涓嶅啀鑷繁鎷兼暟鎹�**銆�
+
+### 16.1 鍏釜鍙e緞锛堢敤鎴锋媿鏉匡紝鏈疆鎹瀹炵幇锛�
+
+鏂规鏂囨。 搂12 鍒椾簡鍏釜寰呭畾闂锛岀敤鎴风殑绛斿鏄細`1.a, 2.鐢熸垚鏃跺脊鎻愮ず, 3.鍏ㄩ儴杩�, 4.浼�, 5.鍙兘閫夋嫨瀵瑰簲绫诲瀷妯℃澘, 6.鍏佽`銆�
+
+| # | 闂 | 缁撹 | 钀藉湴鏂瑰紡 |
+|---|---|---|---|
+| 1 | 璐ㄦ鍗曠殑銆岀壒閲� / 涓嶅悎鏍奸��璐� / 涓嶅悎鏍兼姤搴熴�嶅洓鍊煎垽瀹氾紝鎶ュ憡鐨勩�屽悎鏍�/涓嶅悎鏍笺�嶄笁鎬佽涓嶄笅 | **A锛氬彟瀛樹袱涓瓧娈�** | `ReportFields` 鍔� `qcResult` / `qcResultText`锛屼笌寮曟搸鍒ゅ畾**骞跺瓨浜掍笉瑕嗙洊** |
+| 2 | 娌℃湁瑙勬牸涓婁笅闄愮殑椤规�庝箞鍔� | **鐢熸垚鏃跺脊鎻愮ず**锛屼笉鍥炲~鏁版嵁 | 鍝嶅簲甯� `undecidableCount`锛屽墠绔繀椤绘彁绀� |
+| 3 | 妫�楠屾寚鏍囨槸鍚﹁杩囨护 | **鍏ㄩ儴杩�**锛屼笉鍔� `judge_flag` 杩囨护銆佷笉鍔犲垪 | 鏄犲皠鍣ㄤ笉鍋氭寚鏍囩瓫閫� |
+| 4 | 涓�涓寚鏍囧鏉″疄娴嬪�硷紙澶氭牱鍝侊級鎬庝箞鍔� | **浼氾細涓�鏉★紙鏍峰搧 脳 鎸囨爣锛変竴鏉℃姤鍛婇」** | 鏍峰搧鏁� > 1 鏃舵妸銆屾牱鍝� X銆嶆姌杩� `remark`锛屼笉涓㈡暟鎹� |
+| 5 | 妯℃澘绫诲瀷瑕佷笉瑕佹牎楠� | **鍙兘閫夊搴旂被鍨嬫ā鏉�** | 鍚庣 `105_005` 鎷掔粷锛堜袱杈逛腑鏂囧悕閮界粰锛夛紝鍓嶇鎸� `reportType` 杩囨护 |
+| 6 | 鍚屼竴寮犲崟鎹兘鍚﹀嚭澶氫唤鎶ュ憡 | **鍏佽**锛堝巻鍙茬暀鐥曢渶瑕侊級 | 涓嶅仛閲嶅鐢熸垚鎷︽埅 |
+
+### 16.2 浜や粯鐗�
+
+**鏂板锛圡ES 渚э紝`yudao-module-mes-api` / `yudao-module-mes`锛�**
+
+| 鏂囦欢 | 璇存槑 |
+|---|---|
+| `api/qc/MesQcReportApi.java` | `getQcReportData(qcType, qcId)`锛屽洓绫诲崟鎹粺涓�鍏ュ彛 |
+| `api/qc/dto/MesQcReportRespDTO.java` | 鍗曞ご + `items` + `groupItemNames` + `missingIndicatorCount` + `finished` + `statusName` |
+| `api/qc/dto/MesQcReportItemRespDTO.java` | 鍗曟潯妫�楠岄」锛堝惈 `itemsIndex` 绛夛級 |
+| `api/qc/MesQcReportApiImpl.java` | 瑁呴厤璐ㄦ鍗曞洓灞傜粨鏋勶紙鍗曞ご / 鍒ゅ畾渚濇嵁琛� / 鏍峰搧 / 瀹炴祴鍊兼槑缁嗭級 |
+
+**鏂板锛坬creport 渚э級**
+
+| 鏂囦欢 | 璇存槑 |
+|---|---|
+| `enums/QcReportSourceTypeEnum.java` | 鍥涚被鍗曟嵁鐨勬灇涓撅紝甯� `businessType` 琛ㄥ悕涓� `matchesTemplateReportType` |
+| `service/instance/MesQcReportContextMapper.java` | **绾嚱鏁�**鏄犲皠鍣細`MesQcReportRespDTO` 鈫� `ReportContext` + `warnings` |
+| `service/instance/GenerateFromQcResult.java` | 鍑轰欢缁撴灉 record |
+| `controller/admin/instance/vo/QcReportInstanceGenerateFromQc{Req,Resp}VO.java` | 鍑哄叆鍙� |
+| `service/instance/MesQcReportContextMapperTest.java` | **12 鏉$函鍗曟祴** |
+
+**鏀癸紙qcreport 渚э級**
+
+| 鏂囦欢 | 鏀瑰姩 |
+|---|---|
+| `pom.xml` | 鍔� `yudao-module-mes-api` 渚濊禆 |
+| `enums/ErrorCodeConstants.java` | 鏂板 `1_070_105_000`~`_006` 鍏潯 |
+| `engine/context/ReportFields.java` | 鍔� `qcResult` / `qcResultText` 涓ゅ瓧娈碉紙`copy()` 鍚屾锛� |
+| `engine/context/ReportContext.java` | `reportMap()` 澧炲姞涓や釜 key |
+| `engine/context/ReportContextCodec.java` | `reportOf()` 澧炲姞涓や釜瀛楁 鈥斺�� **婕忎簡杩欏 `regenerate` 浼氶潤榛樹涪瀛楁** |
+| `service/instance/QcReportInstanceService(+Impl).java` | `generateFromQc` + 鍥涗釜鏍¢獙鍣� |
+| `controller/admin/instance/QcReportInstanceController.java` | `POST /generate-from-qc` |
+
+### 16.3 鍥涙潯鍒绘剰鍙栬垗
+
+**鍙栬垗涓�锛氫笉鏂板紑钀藉簱璺緞锛屽唴閮ㄥ氨璋� `generate`銆�**
+
+`generateFromQc` 鏍¢獙瀹屽氨缁勮涓�涓� `QcReportInstanceGenerateReqVO` 璋冩棦鏈夌殑 `generate`銆�
+浜庢槸鐗堟湰鍙戝竷鏍¢獙銆佺紪鍙风敓鎴愪笌鎾炲彿閲嶈瘯銆佹暟鎹揩鐓у喕缁撱�佸垽瀹氬紩鎿�**鍏ㄩ儴鐓ф棫鐢熸晥锛屼竴鏉¢兘娌$粫寮�**銆�
+鍙﹀啓涓�鏉¤惤搴撻摼璺瓑浜庢妸浜旈亾闂搁棬澶嶅埗涓�閬嶏紝鑰屽壇鏈竴瀹氫細婕傜Щ銆�
+
+**鍙栬垗浜岋細鏍¢獙鎸変笟鍔′紭鍏堢骇鍙姤绗竴澶勩��**
+
+绫诲瀷 鈫� 鍗曟嵁瀛樺湪 鈫� 宸插畬鎴� 鈫� 宸插垽瀹� 鈫� 妯℃澘绫诲瀷 鈫� 鏈夋楠岄」銆備竴娆℃姏澶氭潯浼氳鐢ㄦ埛鎶撲笉浣忛噸鐐�
+锛坄error-message-precision.md` 鏄庣‘瑕佹眰锛夈�傚叚鏉℃枃妗堥兘鍋氬埌浜嗐�屽叿浣撶淮搴� + 鍙屾柟瀹為檯鍊� + 鍙墽琛屽姩浣溿�嶏紝
+涓�**涓よ竟鍊奸兘鏄笟鍔′腑鏂囧悕**锛堛�屾姤鍛婃ā鏉跨殑鎶ュ憡绫诲瀷鏄�屽嚭璐ф楠屻�嶏紝涓庢湰娆¤川妫�鍗曠殑绫诲瀷銆屾潵鏂欐楠屻�嶄笉涓�鑷淬�嶏級锛�
+涓嶆槸瑁� ID銆�
+
+**鍙栬垗涓夛細`105_004`锛堟ā鏉夸笉瀛樺湪锛変笌 `105_007`锛堟ā鏉挎棤宸插彂甯冪増鏈級涓嶅疄鐜般��**
+
+鏂规鏂囨。 搂7 鍒椾簡杩欎袱鏉★紝瀹為檯鏀逛负**澶嶇敤鏃㈡湁鐨�** `TEMPLATE_NOT_EXISTS` /
+`TEMPLATE_STATUS_DISABLED` / `TEMPLATE_NO_PUBLISHED_VERSION`銆傞偅鍑犳潯鏂囨鏈潵灏辨槸绮剧‘鐨勶紝
+鍐嶉�犱竴閬嶅彧浼氬涓ゆ潯浼氭紓绉荤殑鍓湰銆�**杩欐槸涓庢柟妗堟枃妗g殑鏄惧紡鍋忕锛屽凡鍦ㄨ仈璋冩柟妗堥噷鍐欐槑銆�**
+
+**鍙栬垗鍥涳細`sampleStrategy` 鍙傛暟涓嶅仛銆�**
+
+鏂规鏂囨。鍘熸湰璁炬兂璁╄皟鐢ㄦ柟閫夈�屽鏍峰搧鎬庝箞澶勭悊銆嶏紝鐢ㄦ埛鍙e緞 4锛堛�屼細銆嶏級鐩存帴瀹氭浜嗕竴浠朵簨锛�
+閫夋嫨鏉冩病蹇呰鏆撮湶缁欏墠绔紝鍙傛暟鍒犳帀銆�
+
+### 16.4 `undecidableCount` 鎬庝箞绠楋紙涓嶉噸绠楀垽瀹氭潯浠讹級
+
+鏁�**蹇収閲� `result` 涓虹┖涓�**鐨勯」锛�
+
+```java
+ReportContext frozen = ReportContextCodec.fromMap(result.instance().getDataSnapshot());
+int undecidable = 0;
+for (InspectionItem item : frozen.getInspectionItems()) {
+ if (StrUtil.isBlank(item.getResult())) { undecidable++; }
+}
+```
+
+銆宍result` 涓虹┖銆嶆鏄紩鎿庡銆屽緟鍒ゅ畾銆嶇殑瀹氫箟锛坄ReportEvaluator` 鎷夸笉鍒� verdict 鏃� `applyResult(null)`锛夛紝
+鎵�浠ュ惈涔夊ぉ鐒朵竴鑷达紝杩橀『甯︽妸銆屽崱鍦ㄨ鍒欐姤閿欎笂銆嶇殑椤圭畻杩涘幓銆�**涓嶅彟鍐欎竴閬嶅垽瀹氭潯浠�** 鈥斺��
+閭f牱鏃㈠彲鑳戒笌寮曟搸鍚勮鍚勮瘽锛屽張浼氭紡鎺夎鍒欐姤閿欒繖涓�绫汇��
+
+### 16.5 瀹炴祴璇佹嵁
+
+**宸查獙璇�**
+
+| 椤� | 缁撴灉 |
+|---|---|
+| 鍏ㄩ」鐩紪璇� `mvn compile -q` | 鉁� 閫氳繃锛堣法鏀逛簡 `yudao-module-ai` / `-system` / `-mes-api` / `-mes` / `-qcreport`锛� |
+| `mvn -pl yudao-module-qcreport test` | 鉁� **Tests run: 106, Failures: 0, Errors: 0** 鈥� BUILD SUCCESS |
+| 鍏朵腑 `MesQcReportContextMapperTest` | 鉁� 12/12 |
+| 鍏朵腑 `FrontendConformanceTest`锛堝喕缁撳鎷嶏級 | 鉁� 3/3锛�**璇佹槑 `ReportFields` 鍔犲瓧娈垫病鏈夌牬鍧忓墠绔喕缁撲骇鐗�**锛� |
+| `ReportContextCodecTest` | 鉁� 7/7 |
+| 瀛橀噺鐢ㄤ緥锛堝垽瀹� 23 / AI 瀵煎叆 42 / PDF 9 / 鍑轰欢 7 鈥︼級 | 鉁� 鍏ㄩ儴浠嶇豢 |
+
+`MesQcReportContextMapperTest` 鐨� 12 鏉¤鐩栵細鍗曞ご鏄犲皠锛堝惈 IQC 鍙� `vendorBatch` 浣滄壒娆″彿銆�
+鏃ユ湡 `2026-09-17 14:30:05` 鏍煎紡銆乣qcResult="2"`/`qcResultText="鐗归噰"`锛夛紱寮曟搸瀛楁涓嶈鏄犲皠鍣ㄦ薄鏌擄紱
+缂轰笂涓嬮檺鏃�**淇濇寔 null 鑰岄潪 0**锛堟樉寮忔敞閲婏細鍙樻垚 0 鐨勮瘽瀹炴祴鍊� 0.09 浼氳鍒ゆ垚銆岃秴涓婇檺涓嶅悎鏍笺�嶏級锛�
+鍗曟牱鍝佷笉鍐� `remark`銆佸鏍峰搧鍐欍�屾牱鍝� S1銆嶃�佽秴 3 涓牱鍝佺暀绌� + warning锛涙湭褰曞疄娴嬪�� warning锛�
+鍒嗙粍鏍囬涓庡凡鍒犳寚鏍囩殑 warning锛涙棩鏈熸牸寮�**涓� locale 鏃犲叧**锛堢敤 `th-TH-u-ca-buddhist-nu-thai` 楠岋級銆�
+
+**鏈獙璇侊紙璇氬疄澹版槑锛�**
+
+- 涓� 搂16.9 鍚屼竴鏉★細**鍙獙浜� IQC 涓�璺�**锛孖PQC / OQC / RQC 涓夐〉鐨勬寜閽笌寮圭獥鏈�愪竴鐐硅繃锛堝洓椤典唬鐮佸悓鏋勶紝
+ 宸紓鍙湁 `QC_TYPE` 甯搁噺涓庤鎿嶄綔閿氱偣锛夈��
+
+### 16.6 绔埌绔� HTTP 鑱旇皟 鈥斺�� 鉁� **19/19 PASS**
+
+鐢ㄦ埛閲嶅惎鍚庣鍚庤窇 `node D:/qcl-tmp/verify-qc-generate.mjs`锛�**19 椤规柇瑷�鍏ㄩ儴閫氳繃**锛�
+
+| # | 鐢ㄤ緥 | 缁撴灉 |
+|---|---|---|
+| 1 | `qcType=9` | 鉁� `105_000`锛屾姤鏂囧惈銆屽彧鏀寔 IQC銆� |
+| 2 | `qcId=999999` | 鉁� `105_001`锛屾姤鏂囧惈璇� ID |
+| 3 | 鐪熷疄鍗曟嵁 1锛堣崏绋匡級 | 鉁� `105_002`锛屾姤鏂囧惈銆岃崏绋裤�� |
+| 4 | 缃� status=4 + check_result=NULL | 鉁� `105_003`锛屾姤鏂囧惈銆屽皻鏈~鍐欐楠屽垽瀹氥�� |
+| 5 | 鏉ユ枡鍗� + 鍑鸿揣妯℃澘 | 鉁� `105_005`锛屾姤鏂�**鍚屾椂**鍚�屽嚭璐ф楠屻�嶄笌銆屾潵鏂欐楠屻�� |
+| 6 | IQC happy path | 鉁� `itemCount=14` / `undecidableCount=14`锛涘惈銆�3 涓寚鏍団�﹀彧浣滃垎缁勬爣棰樸�嶏紱DB `business_type/business_id = 'mes_qc_iqc\t1'`锛涘揩鐓� `qcResult='1'`/`qcResultText='鍚堟牸'`/`resultText='寰呭垽瀹�'` |
+| 7 | OQC 澶瑰叿锛堟ā鏉� 5 甯� item 绾ц鍒欙級 | 鉁� 3 椤瑰叏鍒わ紙`undecidableCount=0`锛夛紝蹇収甯︾湡瀹炴壒娆�/瀹㈡埛/passRate锛屾覆鏌� HTML 鍚疄娴嬪�� |
+| 7b | OQC 澶瑰叿 + **鏃犺鍒欎复鏃舵ā鏉�** | 鉁� `itemCount=4` / `undecidableCount=1`锛�**鎸夋寚鏍囧悕瀹氫綅**锛氳壊搴�=PASS(30)銆佸瘑搴�=PASS(850)銆佹姌鍏夌巼=FAIL(1.3993)銆佸瑙�=寰呭垽瀹� 鈥斺�� **杩欐潯鏄湰杞渶鍏抽敭鐨勮瘉鎹細瑙勬牸涓婁笅闄愬垎鏀‘瀹炲湪鐢ㄧ湡瀹� MES 鏁版嵁绠�** |
+| 8 | 鍙嶆煡 `businessType=mes_qc_iqc&businessId=1` | 鉁� 鏌ュ緱鍒扮敤渚� 6 鐨勫疄渚� |
+| 9 | 鍙湁鍒嗙粍鏍囬鎸囨爣鐨� OQC 澶瑰叿 | 鉁� `105_006`锛屾姤鏂囧惈銆屽垎缁勬爣棰樸�� |
+| 10 | 瀵圭敤渚� 7 鐨勫疄渚嬪 PDF | 鉁� `code=0` 涓� `byteSize>1000` |
+| 11 | 娓呯悊鍚庢棤娈嬫福 | 鉁� 瀹炰緥 / 澶瑰叿 / 涓存椂妯℃澘 / 闄勪欢鍏ㄩ儴褰掗浂锛�**宸叉寜 `deleted=0` 缁熻**锛� |
+
+**璋冭瘯杩囩▼涓殑 5 涓�屽け璐ャ�嶅叏鏄剼鏈柇瑷�鍐欓敊锛屼笉鏄骇鍝佺己闄�**锛岄�愭潯鏌ュ簱璇佷吉鍚庝慨姝o細
+
+1. 銆岃烦杩囧垎缁勬爣棰樻湁鎻愮ず銆嶇殑 regex 鍐欏緱澶锛坄/3 涓寚鏍囧彧浣滃垎缁勬爣棰�/`锛夛紝瀹為檯鎶ユ枃涓棿闅斾簡銆屽湪璐ㄦ鍗曢噷銆嶏紝
+ 鏀规垚 `/3 涓寚鏍�.*鍙綔鍒嗙粍鏍囬/`銆�
+2. **鐢ㄤ緥 7 鐨勬湡鏈涙湰韬敊浜�**锛氭ā鏉� 5 v1.1 閲屽甫浜嗕竴鏉� item 绾ц鍒�
+ 锛坄item.actualValue >= item.lowerLimit AND item.actualValue <= item.upperLimit`锛夛紝
+ 瀹�**浼樺厛浜�**瑙勬牸涓婁笅闄愬垎鏀紝鎵�浠� 3 椤瑰叏琚垽浜嗐�傛柇瑷�鏀瑰悕涓哄畠鐪熸璇佹槑鐨勪簨锛屽苟**鏂板鐢ㄤ緥 7b** 鐢�
+ 鏃犺鍒欑殑涓存椂妯℃澘鍘荤湡姝i殧绂汇�岃鏍间笂涓嬮檺銆嶈繖鏉″垎鏀��
+3. 銆屾覆鏌撲骇鐗╁甫鐪熷疄鏁版嵁銆嶅け璐ワ細`renderHtml` 閲屾湁 `850`锛屼絾娌℃湁鎵规鍙�/瀹㈡埛鍚嶃�傛娊鍑哄崰浣嶇娓呭崟鍚庣‘璁�
+ 妯℃澘 5 v1.1 鐨勭敾甯�**鍙粦浜� `{{report.reportNo}}` 涓庨」绾у瓧娈�**锛屽帇鏍规病缁� `{{report.batchNo}}` /
+ `{{report.customerName}}` 鈥斺�� 鏄ā鏉垮唴瀹归棶棰橈紝涓嶆槸鍚庣婕忎紶锛屾晠鎶婅繖涓ら」鏂█绉诲埌蹇収锛堝揩鐓ч噷纭疄鏈夛級銆�
+4. 銆屾棤娈嬫福銆嶅け璐ワ細鎴戣嚜宸辩殑鏌ヨ婕忎簡 `AND deleted=0`锛屼袱鏉¤蒋鍒犲疄渚嬭绠楁垚娈嬫福锛堣繖姝f槸鏈」鐩�
+ 鏂囨。閲岃杩囩殑鍧戯級銆傝ˉ涓婃潯浠跺悗褰掗浂銆�
+5. 椤哄甫鏍稿疄 `storage_blob_id=20` 閭f潯闄勪欢鏄�**涓婁竴杞� AI 瀵煎叆鎸夎璁$粦瀹氬埌妯℃澘 5 鐨勬簮鏂囦欢**锛屼笉鏄湰杞畫鐣欍��
+
+### 16.7 鍓嶇鎺ュ叆锛堢敤鎴锋巿鏉冦�屽墠鍚庣涓�璧锋敼銆嶅悗钀藉湴锛�
+
+| 鏂囦欢 | 鏀瑰姩 |
+|---|---|
+| `src/components/quality/engine/context.ts` | `ReportContextReport` 鍔� `qcResult` / `qcResultText`锛宍emptyReport()` 琛ョ┖涓查粯璁ゅ�硷紙宸茬‘璁� `emptyReport()` 鏄敮涓�鏋勯�犵偣锛屾敼蹇呭~瀹夊叏锛� |
+| `src/api/mes/qc/report/instance/index.ts` | 鍔� `GenerateFromQcReq` / `GenerateFromQcResult` 涓や釜 interface + `generateInstanceFromQc()` |
+| `src/views/mes/qc/components/report-generate-modal.vue` | **鏂板**锛屽洓涓川妫�鍗曢〉鍏辩敤锛氶�夋ā鏉匡紙鎸� `reportType` 杩囨护 + 鍙暀鏈夌敓鏁堢増鏈殑锛夆啋 鐢熸垚 鈫� 灏卞湴灞曠ず缁撴灉涓庡憡璀� 鈫� 銆屾煡鐪嬫姤鍛婂垪琛ㄣ�� |
+| `src/views/mes/qc/{iqc,ipqc,oqc,rqc}/index.vue` | 鍚勫姞 5 澶勶細import 寮圭獥銆乣QC_TYPE` 甯搁噺 + `useVbenModal`銆乣handleReport`銆乣<ReportModal />`銆佽鎿嶄綔銆屽嚭鎶ュ憡銆嶏紙`ifShow: status === 宸插畬鎴恅锛� |
+| `src/views/mes/qc/report/instance/data.ts` | 鎼滅储琛ㄥ崟鍔犮�屼笟鍔″崟鎹�嶅瓧娈碉紙`businessId`锛�**鍚庣鏄簿纭尮閰�**锛宲laceholder 宸插啓鏄庯級 |
+| `src/views/mes/qc/report/instance/index.vue` | `onMounted` 璇昏矾鐢� query 棰勫~ `businessType` / `businessId` |
+
+**涓や釜鍒绘剰鐨勫鐞�**
+
+- **寮圭獥鏍囬涓嶅啓璐ㄦ绫诲瀷涓枃鍚�**锛堣鍋氭硶淇濈暀锛夛細`mes_qc_rqc` 杩欎竴璺浘鎺緸涓嶄竴鑷粹�斺�斿悗绔灇涓俱�佽〃娉ㄩ噴銆�
+ 鑿滃崟鏉冮檺瀛愰」鍐欍�岄��璐ф楠屻�嶏紝鑿滃崟鐖堕」涓� `mes_qc_type` 瀛楀吀鍐欍�岄��鏂欐楠屻�嶃��**鏈疆宸茬粺涓�涓恒�岄��璐ф楠屻��**锛堣 搂17.3锛夈��
+- **`catch {}` 閲屼笉鍐嶅脊鎻愮ず**锛氬悗绔け璐ユ姤鏂囧凡鐢辫姹傛嫤鎴櫒锛坄preset-interceptors.ts` 鎶涢敊 鈫�
+ `api/request.ts` 鐨� `errorMessageResponseInterceptor`锛夎嚜鍔� toast锛屼笟鍔′唬鐮佸啀寮逛竴娆′細鍑虹幇涓ゆ潯涓�鏍风殑鎶ラ敊銆�
+
+**鏉冮檺鐮佸叆搴�**锛歚system_menu` 鏂板 `id=1075416`銆屾姤鍛婂疄渚嬭川妫�鍗曞嚭浠躲�嶏紝
+`permission=qc-report:instance:generate`锛宍type=3`锛宍sort=5`锛宍parent_id=1075410`锛堟姤鍛婂疄渚嬶級銆�
+**涓嶉渶瑕侀噸鏂扮敓鎴愬悎骞惰剼鏈�** 鈥斺�� `config_export_all_20260918.sql` 闃舵浜屾槸鎵ц鏃惰法搴�
+`INSERT INTO system_menu SELECT * FROM ruoyi-vue-pro.system_menu`锛屾柊琛屼細鑷劧琚甫杩囧幓銆�
+
+### 16.9 鍓嶇 UI 楠屾敹锛圥laywright锛孖FC 涓�璺蛋閫氾級
+
+鐢� Playwright MCP 瀵� `http://localhost:5666` 鐪熺偣浜嗕竴閬嶏紝缁撹锛�
+
+| 楠屾敹鐐� | 缁撴灉 |
+|---|---|
+| 鑽夌鍗�**涓嶆樉绀�**銆屽嚭鎶ュ憡銆� | 鉁� 鍞竴閭e紶 IQC 鍗� `status=0` 鏃讹紝琛屾搷浣滃彧鏈� 淇敼/鍒犻櫎/璇︽儏锛屾棤銆屽嚭鎶ュ憡銆嶁�斺�擿ifShow: status === 宸插畬鎴恅 鐢熸晥 |
+| 宸插畬鎴愬崟**鍙樉绀�**銆屽嚭鎶ュ憡銆� | 鉁� 涓存椂鎶� `status=4` 鍚庯紝淇敼/鍒犻櫎娑堝け銆併�屽嚭鎶ュ憡銆嶅嚭鐜帮紙涓よ�呮潯浠朵簰鏂ワ紝绗﹀悎璁捐锛� |
+| 寮圭獥鏍囬 | 鉁� `鍑烘姤鍛� - IQC_20260917001`锛�**涓嶅甫绫诲瀷涓枃鍚�**锛岃閬� RQC 鎺緸鍒嗘锛� |
+| 妯℃澘**棰勮繃婊�** | 鉁� 搴撻噷 3 寮犳ā鏉匡紝鍙垪鍑� 1 寮犲彲閫夐」銆屾潵鏂欐楠屾姤鍛婃ā鏉� v1.0銆嶁�斺�旀ā鏉� 3锛堝悓绫诲瀷浣� `current_version` 涓虹┖锛変笌妯℃澘 5锛圤QC 绫诲瀷锛夐兘琚纭帓闄� |
+| 鏈�夋ā鏉挎椂 | 鉁� 銆岀敓鎴愭姤鍛娿�嶇疆鐏� |
+| 缁撴灉灏卞湴灞曠ず | 鉁� `鎶ュ憡宸茬敓鎴愶細QR20260919-0012` + `妯℃澘鐗堟湰 v1.1锛涘啓鍏ユ楠岄」 14 鏉 + **榛勮壊鍛婅銆屾湰娆℃湁 14 椤圭己灏戣鏍间笂涓嬮檺涓庤鍒欙紝鍒ゅ畾涓恒�屽緟鍒ゅ畾銆嶃��** + 銆屾暟鎹彇鑸嶆彁绀猴紙1锛夈��+銆屼笉钀藉簱銆嶈鏄� 鈥斺�� **杩欐鏄彛寰� 2 瑕佹眰鐨勬晥鏋�** |
+| 璺宠浆 + 绛涢�� | 鉁� 璺冲埌 `/qc/report-instance?businessType=mes_qc_iqc&businessId=1`锛屾悳绱㈣〃鍗曢濉�屾潵鏂欐楠屻��+ 涓氬姟鍗曟嵁 `1`锛屽垪琛�**鍏� 1 鏉¤褰�**锛堝氨鏄垰鍑虹殑閭d唤锛� |
+
+**杩欒疆楠屾敹鎶撳埌涓�涓墠绔湡瀹炵己闄凤紙宸蹭慨锛�**锛氭渶鍒濇垜鐢� `formApi.setFieldValue` 棰勫~鎼滅储鏉′欢锛�
+璇� `use-vxe-grid.vue` 鎵嶇‘璁よ〃鏍煎彇鎼滅储鏉′欢鏄 `formApi.getLatestSubmissionValues()`
+锛坄extends.ts` 鐨� `extendProxyOption` 鍖呰浜� ajax query锛屽彧鍚�**宸叉彁浜�**鐨勫�硷級锛�
+**鍙� set 涓� submit 鐨勮瘽鏉′欢濉繘琛ㄥ崟浣嗗垪琛ㄤ粛鏌ュ叏閲�**鈥斺�旂瓑浜庢病绛涖��
+宸叉敼涓� `setValues` + `submitForm()`锛屽苟鍔犱簡娉ㄩ噴璇存槑涓轰粈涔堝繀椤昏窡鐫� submit銆�
+
+**椤哄甫鍙戠幇涓�澶勫瓨閲忔暟鎹笉涓�鑷达紙涓嶆槸鏈疆寮曞叆锛屾湰杞凡淇� 鈫� 搂17.2锛�**锛氭ā鏉� 1 `QC_IQC_DEMO` 鐨�
+`current_version = 'v1.0'`锛屼絾鐗堟湰 v1.0 鏄�**宸插仠鐢紙status=2锛�**銆佺湡姝e凡鍙戝竷鐨勬槸 v1.1銆�
+浜庢槸**鐢ㄦā鏉� 1 鍑烘姤鍛婂繀鐒跺け璐�**锛坄1_070_101_003 妯℃澘鐗堟湰鏈彂甯冿紝鏃犳硶鐢熸垚鎶ュ憡`锛夛紝
+鑰屽脊绐楀張浼氭妸瀹冨垪鎴愬彲閫夐」锛堝墠绔彧鍒� `currentVersion` 闈炵┖锛屾ā鏉垮垎椤垫帴鍙d笉杩斿洖璇ョ増鏈殑鐘舵�侊紝**鍓嶇鏃犱粠鍒ゆ柇**锛夈��
+褰撹疆鍙复鏃舵敼鎴� v1.1 璧板畬楠屾敹锛�**宸茶繕鍘熶负 v1.0**锛屾湭鎿呰嚜鏀规暟鎹��
+
+楠屾敹杩囩▼涓存椂鏀瑰姩鍏ㄩ儴宸茶繕鍘燂細IQC 鍗� 1 鎭㈠ `status=0` / `check_result=NULL`锛�
+妯℃澘 1 鎭㈠ `current_version='v1.0'`锛岀敓鎴愮殑瀹炰緥 `QR20260919-0012` 宸茬‖鍒犻櫎锛坄qc_report_instance` 璁℃暟 0锛夈��
+
+### 16.10 涓嬩竴姝�
+
+1. 涓婁竴杞仐鐣欙紙涓嶅睘鏈妭锛夛細`blobIds @Size(max=3)` 涓� YAML `max-files` 鐨勮�﹀悎銆�
+ `@Disabled` 鐪熷疄 AI 鑱旇皟娴嬭瘯銆傦紙銆屽悗绔粛鍦ㄧ儳 AI 璋冪敤銆嶅凡鍦� 搂17.3 鏀跺彛銆傦級
+2. ~~妯℃澘 1 鐨� `current_version` 鏁版嵁涓嶄竴鑷磣~ 鈫� 宸插湪 搂17.2 淇銆�
+3. ~~RQC 鎺緸鍒嗘~~ 鈫� 宸插湪 搂17.3 缁熶竴涓恒�岄��璐ф楠屻�嶃��
+4. IPQC / OQC / RQC 涓夐〉鐨� UI 鏈�愪竴鐐硅繃锛堝悓鏋勪唬鐮侊紝椋庨櫓浣庯級銆�
+
+---
+
+## 鍗佷竷銆佷紭鍖栬疆锛氬脊绐楄繃婊� / 璇垹涓婁紶鏂囦欢 / AI 鎬婚绠� / 涓ゅ寰呰鍐抽」
+
+鍥涢」涓�娆℃�у仛瀹岋紝鍧囦负瀵规棦鏈夎兘鍔涚殑琛ュ己鎴栫己闄蜂慨澶嶏紝鏃犳柊澧炰笟鍔″璞°��
+
+### 17.1 鍑烘姤鍛婂脊绐楄ˉ銆屽綋鍓嶇増鏈凡鍙戝竷銆嶆牎楠�
+
+**闂**锛氬脊绐楀彧鎸� `reportType` + 妯℃澘 `status=鍚敤` 鏌ユā鏉垮垎椤碉紝鍐嶅湪鍓嶇鍒� `currentVersion` 闈炵┖銆�
+浣嗐�屽綋鍓嶇増鏈槸鍚﹀凡鍙戝竷銆嶆槸**鐗堟湰琛�**涓婄殑鐘舵�侊紝鍒嗛〉鎺ュ彛涓嶈繑鍥烇紱鑰�**鍋滅敤涓�涓増鏈笉浼氭竻绌烘ā鏉跨殑 `currentVersion`**锛�
+浜庢槸 `currentVersion` 鏈夊�笺�侀偅涓増鏈凡鍋滅敤鐨勬ā鏉跨収鏍疯鍒楀嚭锛岄�変腑鍚庡繀鐒舵姤 `1_070_101_003`銆�
+妯℃澘 1 灏辨槸杩欑锛堣 搂16.9锛夈��
+
+**鏀规硶**锛氭柊澧� `GET /qc-report/template/selectable?reportType=`锛堟潈闄� `qc-report:template:query`锛夛紝
+鍦�**鍚庣**涓�娆℃�у仛涓夐噸杩囨护锛氭ā鏉� `report_type` 涓�鑷� 鈫� 妯℃澘 `status=鍚敤` 鈫� `current_version` 鎸囧悜鐨勭増鏈� `status=宸插彂甯僠銆�
+涓ゆ潯 SQL 瑙e喅锛屾棤 N+1锛堝厛鏌ユā鏉匡紝鍐嶇敤 `templateId IN (...)` 鎵归噺鏌ュ凡鍙戝竷鐗堟湰锛屽湪鍐呭瓨閲屾寜 `templateId@version` 姹備氦闆嗭級銆�
+鍓嶇鏀圭敤杩欎釜鎺ュ彛锛屼笉鍐嶈嚜宸辨帹瀵艰鍒欍��
+
+**涓轰粈涔堜笉鎶婄増鏈姸鎬佸杩涙ā鏉垮垎椤电殑鍝嶅簲**锛氶偅瑕佸湪鍒楄〃閲屽姣忚鍐嶆煡涓�娆$増鏈〃锛圢+1锛夛紝
+鑰屼笖銆岀増鏈繀椤诲凡鍙戝竷銆嶈繖鏉¤鍒欎細璺戝埌鍓嶇鍘伙紝鎴愪负绗簩涓湡鐩告潵婧愩��
+
+**椤哄甫璁板綍涓�涓唬鐮佸眰鐨勬礊锛堟湰杞湭鏀癸紝闇�鍐崇瓥锛�**锛歚QcReportTemplateVersionServiceImpl.disableVersion`
+鍋滅敤鐗堟湰鏃�**涓嶆竻绌� `template.currentVersion`**锛屾墍浠ャ�屽仠鐢ㄥ綋鍓嶇増鏈�嶈繖涓搷浣滄湰韬氨鑳介�犲嚭涓婇潰閭g涓嶄竴鑷存暟鎹��
+鏈疆鍙尅浣忎簡銆岀敤鎴风湅鍒板苟閫変腑瀹冦�嶏紝娌″牭浣忋�屼骇鐢熷畠銆嶃�傝涓嶈鍦ㄥ仠鐢ㄥ綋鍓嶇増鏈椂鐩存帴鎷掔粷
+锛堟彁绀恒�岃鍏堟妸褰撳墠鐗堟湰鍥炴粴鍒板彟涓�涓凡鍙戝竷鐗堟湰銆嶏級鏄笟鍔″彛寰勯棶棰橈紝鏈搮鑷喅瀹氥��
+
+### 17.2 妯℃澘 1 鏁版嵁淇
+
+`qc_report_template` id=1锛歚current_version` 鐢� `v1.0`锛坰tatus=2 宸插仠鐢級鏀逛负 `v1.1`锛坰tatus=1 宸插彂甯冿級銆�
+鏀瑰悗妯℃澘 1 鏃㈣兘琚柊鎺ュ彛鍒楀嚭銆佷篃鐪熺殑鑳藉嚭鎶ュ憡銆傝繖鏄暟鎹慨澶嶏紝涓嶆敼浠g爜銆�
+
+### 17.3 RQC 鎺緸缁熶竴涓恒�岄��璐ф楠屻��
+
+鍘熷厛鐨勫垎姝ч潰锛�
+
+| 浣嶇疆 | 鍘熸枃 |
+|---|---|
+| `MesQcTypeEnum.RQC.name`銆乣QcReportSourceTypeEnum.RQC.name`銆乣MesQcReportContextMapper` 鐩稿叧鏂囨 | 閫�璐ф楠� |
+| `mes_qc_rqc` 琛ㄦ敞閲娿�乣system_menu` id=5671~5675锛堟潈闄愬瓙椤癸級 | 閫�璐ф楠� |
+| `system_menu` id=5670锛堣彍鍗曠埗椤癸級銆乣system_dict_data` id=3124 鐨� label | 閫�鏂欐楠� |
+| 鍓嶇 `instance/data.ts` 鐨� `BUSINESS_TYPE_LABEL`銆乣pendinginspect/index.vue` 涓ゅ | 閫�鏂欐楠� |
+
+**缁熶竴鍒般�岄��璐ф楠屻��**锛岀悊鐢憋細鈶� 瀹冩槸澶氭暟娲撅紙鍚庣 Java 鏋氫妇闆跺鍑虹幇銆岄��鏂欐楠屻�嶏級锛�
+鈶� RQC 鐨勫璞″悓鏃惰鐩栫敓浜ч��鏂欍�侀攢鍞��璐с�佸敭鍚庨��璐э紝銆岄��璐ф楠屻�嶆槸鑳借鐩栦笁鑰呯殑璇存硶锛屻�岄��鏂欐楠屻�嶅彧瑕嗙洊鍏朵竴锛�
+鈶� `system_dict_data` id=3124 鐨� `remark` 鏈潵灏卞啓鐫�銆岄��璐ц川閲忔楠屻�嶏紝璇存槑銆岄��鏂欍�嶆槸 label 鍗曠嫭鍐欏矓鐨勩��
+
+**鏀瑰姩鐐�**锛歚system_menu` id=5670 鐨� `name`銆乣system_dict_data` id=3124 鐨� `label`銆�
+鍓嶇 `instance/data.ts` + `pendinginspect/index.vue`锛坄name` 鍓嶇疆涓蹭笌琛屾搷浣� label锛夈��
+`docs/sql/config_export_all_20260918.sql` 閲� id=3124 鐨勫瓧闈㈤噺銆�
+
+> 鑿滃崟鍚嶆敼鍔�**涓嶉渶瑕侀噸鏂扮敓鎴愬悎骞惰剼鏈�**锛氶樁娈典簩鏄墽琛屾椂璺ㄥ簱 `INSERT INTO system_menu SELECT * FROM ...`銆�
+> 瀛楀吀鏄樁娈典竴鐨勫瓧闈㈤噺锛屾墍浠ユ墜宸ユ敼浜嗛偅涓�琛屼互淇濇寔涓�鑷达紙鍙敼 label 涓�涓瓧闈㈤噺锛屼笉蹇呮暣浠介噸瀵硷級銆�
+
+### 17.4 AI 瀵煎叆鍔犺姹傜骇鎬昏�楁椂棰勭畻
+
+**闂**锛歚max-files` / `max-pages-per-file` / `max-pages-per-request` 鍙害鏉熻皟鐢�**娆℃暟**锛屼笉绾︽潫**鏃堕暱**銆�
+妯″瀷鎺掗槦鏃舵瘡娆¤皟鐢ㄩ兘鑳借�楁弧 `yudao.ai.timeout`锛�60s锛夛紝8 娆″彔鍔犺兘鎶婁竴娆¤鎿嶄綔鎷栨垚 8 鍒嗛挓鐨勪粯璐硅皟鐢紱
+鑰屽墠绔� axios 180s 灏辨柇浜嗭紝鐢ㄦ埛鍦ㄦ柇绾垮悗瀹屽叏涓嶇煡閬撳悗绔繕鍦ㄨ窇銆�
+
+**鏀规硶**锛氭柊澧� `yudao.qcreport.ai-import.max-duration-seconds`锛堥粯璁� 180锛屼袱涓� profile 鍚屾锛夈��
+鍦�**涓ゆ妯″瀷璋冪敤涔嬮棿**妫�鏌ュ凡鑰楁椂锛岃秴浜嗗氨鍋滄鍚庣画璋冪敤锛�
+
+- 宸茶瘑鍒埌鐨勯儴鍒�**鐓у父杩斿洖**锛屽苟鍦� `warnings` 閲屾槑鍐欍�屽凡杈惧埌鍗曟瀵煎叆鑰楁椂涓婇檺锛�180 绉掞紝宸茬敤鏃� X 绉掞級锛�
+ 鍚庣画鍐呭鏈啀璇嗗埆銆嶁�斺�旇繖鏄樉寮忔埅鏂紝涓嶆槸闈欓粯鎴柇锛屼笌妯″潡鏃㈡湁鍙e緞涓�鑷淬��
+- 濡傛灉涓�涓粍浠堕兘娌¤瘑鍒嚭鏉ワ紝鏀规姏鏂伴敊璇爜 `AI_IMPORT_AI_BUDGET_EXCEEDED`锛坄1_070_104_016`锛夛紝
+ 鑰屼笉鏄� `AI_IMPORT_DRAFT_EMPTY`鈥斺�斾袱鑰呯敤鎴疯閲囧彇鐨勫姩浣滃畬鍏ㄤ笉鍚岋紙鍓嶈�呭垎鎵癸紝鍚庤�呮敼鐢ㄦ墜宸ヨ璁★級銆�
+- 杩涙瘡涓枃浠朵箣鍓嶄篃妫�鏌ヤ竴娆★紝瓒呬簡灏变笉鍐嶈涓嬩竴浠姐�佷笉鍐嶆覆鏌撳畠鐨勯〉锛堢渷鎺夌櫧鑺辩殑 CPU 涓庡唴瀛橈級銆�
+
+**涓轰粈涔堝彧鑳藉湪涓ゆ璋冪敤涔嬮棿鍏抽棬**锛歚AiChatApi` 涓嶆帴鍙楄秴鏃跺弬鏁帮紝鍗曟璋冪敤鏃犳硶涓�旀墦鏂紝
+鎵�浠ユ渶鍧忎細澶氬嚭涓�涓� `yudao.ai.timeout`銆傚洜姝�**鍓嶇 axios 瓒呮椂浠� 180s 鎻愬埌 300s**
+锛�180 棰勭畻 + 60 鍗曟瓒呮椂 = 240 鏈�鍧忥紝鐣� 60s 浣欓噺锛夆�斺�斿師鍏� 180s 鍙嶈�屾瘮鍚庣鏈�鍧忔儏鍐垫洿鐭紝
+鐢ㄦ埛浼氬厛鐪嬪埌娴忚鍣ㄦ柇寮�鑰屼笉鏄悗绔偅鏉¤娓呭師鍥犵殑鎻愮ず銆傚彇 180 绉掍綔涓洪绠楋細
+甯歌 8 娆′互鍐呯殑璋冪敤閮借窇寰楀畬锛屽彧鏈夋ā鍨嬫槑鏄惧彉鎱㈡椂鎵嶈Е鍙戙��
+
+### 17.5 淇 ERP / CRM 涓ゅ璇垹鐢ㄦ埛涓婁紶鏂囦欢
+
+**闂**锛歚ErpPurchaseInvoiceAiServiceImpl` 涓� `CrmSaleQuotationAiServiceImpl` 鍦� `finally` 閲�
+`tempFile.delete()`锛岃�岄偅涓� `File` 鏉ヨ嚜 `SystemStorageBlobService.getPublicFile(...)` 鈥斺��
+**瀹冩槸纾佺洏涓婄湡瀹炲瓨鍌ㄧ殑閭d唤 blob锛屼笉鏄复鏃跺壇鏈�**銆傜瓑浜庢瘡娆� AI 璇嗗埆瀹屽氨鎶婄敤鎴蜂笂浼犵殑鍘熷鍙戠エ/鎶ヤ环鏂囦欢鍒犱簡銆�
+
+**鏀规硶**锛氬幓鎺夋暣涓� `finally` 鍒犻櫎鍧楋紝鍙橀噺鍚� `tempFile` 鏀逛负 `blobFile` 骞跺姞涓�琛屾敞閲婅鏄庛�岃繖涓嶆槸涓存椂鍓湰锛岃瀹屼笉鑳藉垹銆嶃��
+鍛藉悕璇姝f槸杩欎釜缂洪櫡鐨勬垚鍥狅紝鐣欑潃瀹规槗鍐嶇姱銆�
+
+> 璁扮殑銆屼笁澶勩�嶅疄涓�**涓ゅ**锛歚MesQcAiServiceImpl` 鏄函鏂囨湰鍒ゅ畾寤鸿锛堝叆鍙傛槸 VO锛屼笉纰版枃浠讹級锛屾病鏈夎繖涓己闄枫��
+
+### 17.6 鏈疆鏈仛
+
+- `disableVersion` 鍋滅敤褰撳墠鐗堟湰鏃剁殑鎷︽埅锛堣 搂17.1 鏈級鈥斺�旈渶涓氬姟鍙e緞銆�
+- AI 瀵煎叆鐨� `blobIds @Size(max=3)` 涓� YAML `max-files` 鐨勮�﹀悎銆�
+- `@Disabled` 鐨勭湡瀹� AI 鑱旇皟娴嬭瘯銆�
+- IPQC / OQC / RQC 涓夐〉鐨� UI 閫愪竴鐐归獙锛堝悓鏋勪唬鐮侊級銆�
+
+## 鍗佸叓銆佷紭鍖栬疆锛堜簩锛夛細鐢诲竷鍐欏叆渚ф牎楠� / 鍋滅敤褰撳墠鐗堟湰鎷︽埅 / 绌虹敾甯冨垽鎹� / 涓夊鏀跺熬锛�2026-09-19 缁級
+
+鍥涢」鍧囨槸 搂17.6 閬楃暀椤圭殑钀藉湴鎴栨湰杞柊鍙戠幇鐨勭己闄蜂慨澶嶏紝鏃犳柊澧炰笟鍔″璞°�佹棤寤鸿〃銆佹棤娓叉煋寮曟搸鏀瑰姩銆�
+**鍏ㄩ儴涓哄悗绔敼鍔紝鏈疆鏈姩浠讳綍鍓嶇鏂囦欢銆�**
+
+### 18.1 鐢诲竷鍐欏叆渚у畨鍏ㄦ牎楠岋紙鏂板 `CanvasSafety`锛�
+
+**闂**锛氭姤鍛婁骇鐗╂槸鎷煎瓧绗︿覆鎷煎嚭鏉ョ殑锛屾ā鏉跨敾甯冩槸鐢ㄦ埛鍙紪杈戞暟鎹�傛煡 `HtmlRenderer` 鍚庣‘璁ゆ敞鍏ラ潰**姣旈鎯崇殑澶氫袱澶�**锛�
+涓�鍏变笁澶勫唴瀹逛細**涓嶇粡杞箟**杩涘叆浜х墿锛�
+
+| 鎷兼帴鐐� | 浣嶇疆 | 鍚庢灉 |
+|---|---|---|
+| 鑺傜偣 `tagName` 鐩存帴鎷兼垚 `<tag>` | `resolveTag` | 鍙啓 `<script>`锛涘啓 `"img src=x onerror=alert(1)"` 杩樿兘鏁存濉炶繘涓�涓簨浠跺睘鎬� |
+| 灞炴��**鍚�**鐩存帴鎷间笂锛堝彧鏈夊睘鎬�**鍊�**杞箟锛� | `renderAttributes` | 涓�涓惈寮曞彿鐨勫睘鎬у悕灏辫兘鎶婂悗闈㈢殑鍐呭椤舵垚鏂板睘鎬� |
+| `styles` 鍐欐垚瀛楃涓叉椂**鍘熸牱**濉炶繘 `<style>` | `buildCss` | 鍑虹幇 `</style>` 鍗虫彁鍓嶉棴鍚堬紝鍚庨潰鍙樻垚鐪� HTML |
+
+> 鍘熻鍒掔殑鈶e彧鎻愪簡 `tagName` 涓�鏉°�傝娓叉煋鍣ㄥ悗鎸夊疄闄呮敞鍏ラ潰鎵╂垚涓夋潯鈥斺�斿皯鍫典袱鏉★紝鐧藉悕鍗曞氨绛変簬娌″仛銆�
+
+**鏀规硶**锛氭柊澧� `engine/render/CanvasSafety.validate(grapes) 鈫� List<String>`锛屽湪 `validateSchema` 閲岃皟鐢�
+锛坄createVersion` 涓� `updateVersion` 涓ゆ潯鍏ュ彛鍏辩敤鍚屼竴娈垫牎楠岋紝涓嶅悎鏍�**涓�寰嬩笉钀藉簱**锛夛細
+
+- 鏍囩璧�**鐧藉悕鍗�**锛堝父瑙勬帓鐗堜笌鏂囨湰鏍囩锛夛紝涓嶇敤榛戝悕鍗曗�斺�旈粦鍚嶅崟姘歌繙婕忥紝鑰屾姤鍛婃帓鐗堢敤寰楀埌鐨勬爣绛炬槸鍙灇涓剧殑锛�
+- 灞炴�у悕鎸夊瓧绗﹂泦鏍¢獙 + `on` 鍓嶇紑鍒や簨浠跺睘鎬э紱
+- `styles` 蹇呴』鏄鍒欐暟缁勶紝涓� `selectors` / `mediaText` / 鏍峰紡灞炴�у悕涓庡�奸噷鍑虹幇 `<` 鍗虫嫆缁濓紱
+- 涓�娆℃渶澶氭姤 **8 鏉�**锛屾瘡鏉″甫銆屼綅缃� + 杩濊鍐呭銆嶏紝澶氭潯浠� `锛沗 杩炴帴銆�
+
+**涓轰粈涔堝湪淇濆瓨鏃跺崱锛岃�屼笉鏄湪娓叉煋鏃跺崱**锛氭覆鏌撻摼璺笂鐨� `HtmlRenderer` 涓庡墠绔� `engine/render.ts` 蹇呴』**閫愬瓧涓�鑷�**锛�
+鏀瑰畠灏辫閲嶇畻瀵规媿浜х墿銆佸苟璁╁瓨閲忔姤鍛婄殑 `regenerate` 涓嶅啀閫愬瓧澶嶇幇銆傘�屽叆绔欏唴瀹规槸鍚﹀彲淇°�嶆湰鏉ュ氨鏄啓鍏ヤ晶鐨勯棶棰橈紝
+鍦ㄦ暟鎹繘搴撳墠鎷︽帀锛屾覆鏌撲晶鍙互缁х画涓庡墠绔畬鍏ㄥ绉般�備唬浠锋槸**瀵规牎楠屼笂绾垮墠宸插叆搴撶殑鑴忔暟鎹病鏈夊厹搴�**銆�
+
+**涓嶈鏉�鐨勪笁绫�**锛堝疄鐜伴噷鏄庣‘鎺掗櫎锛屽潎鏈夊崟娴嬶級锛歚textnode` 涓婄殑 `tagName`锛堟覆鏌撳櫒涓嶈锛夈��
+GrapesJS 鎸傚湪鑺傜偣涓婄殑 `docEl`/`head` 鍏冩暟鎹紙娓叉煋鍣ㄤ笉璇伙紝鏍¢獙鍙部 `components` 璧帮級銆佸瓨閲忕湡瀹炵敾甯冦��
+
+**鏂板娴嬭瘯** `CanvasSafetyTest`锛�17 椤癸紝鍚� 6 涓湡瀹炲瓨閲忕敾甯冪殑鍙傛暟鍖栫敤渚嬶級銆�
+鍏朵腑 `acceptsRealStoredCanvases` 鏄妸搴撻噷鍏ㄩ儴鐗堟湰瀵兼垚澶瑰叿锛坄src/test/resources/qcreport/canvas/`锛夛紝
+鐢ㄦ潵瀹堜綇銆岀櫧鍚嶅崟涓嶈鏀跺緱杩囩揣銆嶁�斺�斿畠姣斻�屾嫆缁濊剰鍐呭銆嶉偅鍑犳潯鏇撮噸瑕侊紝鍥犱负璇潃鐨勫悗鏋滄槸鐢ㄦ埛绐佺劧瀛樹笉浜嗘ā鏉裤��
+
+> 鍐欒繖鎵圭敤渚嬫椂韪╄繃涓�娆″潙锛氭渶鍒濇妸 `components` 鎽嗗湪 `grapes` 鏍逛笂锛岃�屾牎楠屽櫒锛堟纭湴锛屼笌娓叉煋鍣ㄤ竴鑷达級鍙部
+> `pages[0].frames[0].component` 璧帮紝浜庢槸銆屾嫆缁濄�嶇被鏂█鍏ㄩ儴**鍋囬�氳繃**锛堜粈涔堥兘娌℃鏌ワ級銆傚凡鏀逛负鍏ㄩ儴鎸夌湡瀹炵敾甯冨舰鐘跺啓銆�
+> 瀹夊叏娴嬭瘯鐨勫亣閫氳繃姣斾笉鍐欐洿鍗遍櫓銆�
+
+### 18.2 鍋滅敤銆屽綋鍓嶇増鏈�嶇洿鎺ユ嫆缁濓紙`TEMPLATE_VERSION_CURRENT_CANNOT_DISABLE` = `1_070_101_010`锛�
+
+**闂**锛埪�17.1 鏈鐨勯偅涓�屼骇鐢熷畠銆嶇殑娲烇級锛歚disableVersion` 鍋滅敤鐗堟湰鏃朵笉娓呯┖ `template.currentVersion`銆�
+鍋滅敤褰撳墠鐗堟湰浼氶�犲嚭鑷浉鐭涚浘鐨勬ā鏉库�斺�擿current_version` 杩樻寚鐫�瀹冦�佸畠鍗村凡涓嶅彲鐢紝璇ユā鏉胯嚜姝ゅ嚭涓嶄簡鎶ュ憡锛�
+涓斿け璐ュ彂鐢熷湪**鍑轰欢閭d竴鍒�**锛坄1_070_101_003`锛夛紝鐢ㄦ埛涓嶄細鎯冲埌璧峰洜鏄箣鍓嶉偅娆″仠鐢ㄣ��
+
+**鏀规硶**锛歚disableVersion` 閲屾瘮瀵规ā鏉� `current_version` 涓庤鐗堟湰 `version`锛岀浉绛夌洿鎺ユ嫆缁濄��
+**涓嶉『鎵嬫浛鐢ㄦ埛鏀� `current_version`**鈥斺�斻�屾敼鍝釜鐗堟湰銆嶆槸鐢ㄦ埛鐨勫喅瀹氾紝涓嶈鐢便�屽仠鐢ㄣ�嶈繖涓姩浣滄倓鎮勪唬鍔筹紱
+鏂囨閲岀粰鍑轰袱鏉″嚭璺紙鍏堝洖婊氬埌鍙︿竴涓凡鍙戝竷鐗堟湰 / 鏀逛负鍋滅敤鏁翠釜妯℃澘锛夈��
+
+鍙e緞锛氬彧姣斿瓧绗︿覆锛�**涓嶇湅鐗堟湰鏄惁宸插彂甯�**锛堣崏绋垮悓鏍峰彲鑳借鎸囧埌锛夛紱鍋滅敤闈炲綋鍓嶇増鏈殑琛屼负涓嶅彉銆�
+
+### 18.3 `hasCanvas` 鍒ゆ嵁寮哄寲 + `/selectable` 琛ョ涓夐噸杩囨护锛堟湰杞嚜琛岃拷鍔狅紝闈炲師瀹氳寖鍥达級
+
+**鍙戠幇**锛氬鍑哄簱涓叏閮ㄧ増鏈悗鏍稿锛屾ā鏉� 1 鐨勫綋鍓嶇増鏈紙id=2, v1.1, 宸插彂甯冿級鐨� `grapes` 鏄�
+`{"assets":[],"styles":[]}`鈥斺��**闈炵┖锛屽嵈涓�涓粍浠堕兘娌℃湁**銆傝�� `hasCanvas` 褰撴椂鐨勫垽鎹鏄�実rapes 杩欎釜 Map 闈炵┖銆嶏紝
+浜庢槸瀹冭鍒や负鏈夊唴瀹癸紱缁х画璧版覆鏌擄紝`HtmlRenderer` 鍙� `pages[0].frames[0].component` 鍙栧埌 null锛�
+**鎶� body 娓叉煋鎴愮┖涓层�佷笉鎶ラ敊**锛岀敤鎴锋嬁鍒颁竴寮�**鐧界焊 PDF**銆傝繖姣旀姤閿欐洿绯燂細鐢ㄦ埛涓嶇煡閬撹鏀逛粈涔堛��
+
+**鏀规硶**锛氭妸 `hasCanvas` 鐨勫垽鎹敼鎴愪笌娓叉煋鍣ㄨ鐢诲竷鐨勯偅涓�琛�**涓ユ牸涓�鑷�**锛�
+
+```
+Paths.readPath(grapesOf(schema), "pages[0].frames[0].component") instanceof Map<?, ?>
+```
+
+瀹冨悓鏃跺畧鐫�涓ゅ锛歚getSelectableTemplates`锛堣涓嶈鎶婅繖涓ā鏉挎憜杩涘嚭鎶ュ憡寮圭獥锛変笌
+`resolveVersion`锛堝嚭浠跺墠瑕佷笉瑕佺洿鎺ユ嫆缁濓紝鎶ユ棦鏈夌殑 `1_070_101_008`锛夈�備竴涓垽鎹崟鐐瑰畾涔夛紝涓ゅ鍙e緞涓嶄細婕傘��
+
+**褰卞搷闈㈠凡瀹炴祴**锛氬叏搴� 6 涓増鏈腑锛屽彧鏈� id=1銆乮d=2锛堥兘鏄ā鏉� 1 鐨勭┖鐧界敾甯冿級鐢便�岄�氳繃銆嶅彉銆屾嫆缁濄�嶏紝
+4 涓湡姝g敾浜嗕笢瑗跨殑鐗堟湰涓嶅彈褰卞搷銆傛姤琛ㄥ疄渚嬪叏搴撳彧鏈� 1 鏉★紙妯℃澘 3 v1.0锛夛紝涓嶈娉㈠強銆�
+
+**`/selectable` 闅忎箣琛ヤ笂绗笁閲嶈繃婊�**锛氬�欓�夌増鏈鏈潵灏辨暣琛岃鍑烘潵锛堝惈 `schema_json`锛夛紝
+鎷垮畠鍒� `hasCanvas` 鏄櫧鎹$殑锛�**娌℃湁棰濆鏌ュ簱**锛涙敼鎴� exists 瀛愭煡璇㈠弽鑰屽涓�娆″線杩斻��
+
+> 杩欎竴鏉¤秴鍑轰簡鍘熷畾鐨勫洓椤硅寖鍥达紝灞炶浠g爜鏃跺彂鐜板苟椤烘墜鍫垫帀鐨勭己闄凤紝鍦ㄦ鍗曞垪璇存槑銆�
+
+### 18.4 鍘绘帀 AI 瀵煎叆 `blobIds` 涓婂啓姝荤殑 `@Size(max=3)`
+
+**闂**锛氬叆鍙� VO 涓婃寕鐫� `@Size(max = 3)`锛岃�屼笂闄愮湡姝g敱 `yudao.qcreport.ai-import.max-files` 鍐冲畾銆�
+涓や釜鏁板瓧骞跺瓨鐨勭粨鏋滃彧浼氭槸**娉ㄨВ鏇翠弗銆侀厤缃け鍘诲彲璋冩��**锛堥厤缃彧鏁㈠線涓嬭皟锛夛紝涓斾笉鍚屾鏃剁敤鎴风湅鍒扮殑涓婇檺涓庣敓鏁堢殑涓婇檺瀵逛笉涓娿��
+
+**鏀规硶**锛氬垹鎺夋敞瑙o紝鎶婃湇鍔″眰鐨� `validateFileCount` 澹版槑涓�**鍞竴闂搁棬**銆�
+宸茬‘璁ゅ畠鐨勮皟鐢ㄤ綅缃湪 `generateDraft` 鏈�鍓嶆銆�**浠讳綍 blob 璇诲彇涔嬪墠**锛屾墍浠ユ斁澶ф枃浠舵暟涓嶅甫鏉ラ澶栫殑纾佺洏/鍐呭瓨寮�閿�锛�
+娉ㄨВ閭e眰鎷︽埅骞舵棤蹇呰銆�
+
+### 18.5 妯℃澘琛岀焊鍨嬪榻� + `pdf-e2e.mjs` 淇
+
+**鏁版嵁渚�**锛氭牳瀵瑰悗锛屼笁寮犳ā鏉胯閲屽彧鏈夋ā鏉� 1 鐨� `orientation`锛坧ortrait锛変笌鍏跺綋鍓嶇増鏈紙landscape锛変笉涓�鑷达紝
+妯℃澘 3銆佹ā鏉� 5 鏈潵涓�鑷达紙搂17 鏃朵互涓虹殑銆屾ā鏉� 5 涓嶄竴鑷淬�嶆槸鍏� v1.0 鐨勶紝鑰� v1.0 涓嶆槸褰撳墠鐗堟湰锛夈��
+宸叉妸妯℃澘 1 鐨� `page_size`/`orientation` 瀵归綈鍒板綋鍓嶇増鏈紝鍏ㄨ〃涓夎鐜板湪閮戒笌鍏跺綋鍓嶇増鏈竴鑷淬��
+
+> 澶囨敞锛歚qc_report_template.page_size` / `orientation` **鍏ㄩ」鐩棤璇诲彇鏂�**锛堝彧鏈� DO 涓� RespVO 澹版槑锛夛紝
+> 娓叉煋涓�寰嬪彇 Schema 閲岀殑 `page`銆傚畠浠彧鏄ā鏉垮垪琛ㄩ〉鐨勫睍绀哄厓鏁版嵁鈥斺�旀墍浠ヨ繖娆″榻愬彧褰卞搷鍒楄〃鏄剧ず锛�
+> 涓嶆敼浠讳綍娓叉煋缁撴灉銆傛ā鏉� 1 鐨勪袱涓増鏈敾甯冮兘鏄┖鐨勶紙瑙� 搂18.3锛夛紝瀹冨湪 `/selectable` 閲屽凡琚繃婊ゆ帀锛�
+> 鍥犳杩欐瀵归綈瀵瑰畠鏄�屾樉绀轰竴鑷淬�嶈�岄潪銆屽彲鐢ㄣ�嶃��
+
+**鑴氭湰渚�**锛坄D:/qcl-tmp/pdf-e2e.mjs`锛屼粨搴撳锛夛細
+
+1. 涓嶅啀鍐欐 `version: 'v1.0'`锛屾敼涓哄厛鏌ユā鏉跨殑 `currentVersion` 鍐嶅甫涓娾�斺��
+ 鍐欐鐨勭増鏈彿浼氬湪妯℃澘鍙戞柊鐗堟湰鍚庤鑴氭湰**鎮勬倓鍘婚獙涓�涓繃鏈熺殑鍘嗗彶鐗堟湰**锛岃�屾垜浠互涓哄畠杩樺湪楠屽綋鍓嶆ā鏉裤��
+2. 鏂█ `3.4` 鍘熷厛鍐欐銆孉4 绾靛悜 595.28x841.89pt銆嶃�備絾 `orientation` **鏄敓鏁堢殑**
+ 锛坄PageSizes.resolve` 妯悜浼氱炕杞楂橈級锛岀洰鏍囩増鏈敼涓哄綋鍓嶇増鏈悗璇ユ柇瑷�蹇呯劧璇姤銆�
+ 鏀逛负浠庡疄渚� HTML 鐨� `@page { size: Wmm Hmm }` 鍙栫湡鍊笺�佹崲绠楁垚 pt 鍐嶄笌 PDF 鐨� MediaBox 姣斿鈥斺��
+ 鑷唇涓斾笉闅忕焊鍨嬪彉鍖栬�屽け鏁堛��
+3. 鏂板鏂█ `0.5.1`锛氭ā鏉胯鐨勭焊鍨嬩笌褰撳墠鐗堟湰 Schema 鐨勭焊鍨嬩竴鑷淬�傝繖姝f槸 搂18.5 鏁版嵁渚ч偅鏉′笉鍙橀噺鐨勬満鍣ㄦ鏌ワ紝
+ 浠ュ悗鍐嶆湁婕傜Щ浼氳杩欐潯鎶撲綇銆�
+
+### 18.6 楠岃瘉鐘舵�侊紙宸插仛 / 鏈仛鍒嗗紑澹版槑锛�
+
+**宸查獙璇�**锛�
+
+- `mvn compile -q -o` 鍏ㄩ」鐩紪璇戦�氳繃锛堟湰杞敼浜� qcreport 涓� ai銆乻ystem 涓変釜妯″潡锛夈��
+- `mvn -pl yudao-module-qcreport test -o` 鈫� **`Tests run: 132, Failures: 0, Errors: 0`**
+ 锛堝師 106 椤� + 鏂板 `CanvasSafetyTest` 17 椤� + 鏂板 `QualityReportEngineTest` 9 椤癸級锛屽叏缁裤��
+- 鍏ㄥ簱 6 涓増鏈窇銆屽己鍖栧墠 / 寮哄寲鍚庛�嶅垽鎹鐓э紝纭褰卞搷闈�**鍙湁妯℃澘 1 鐨勪袱涓┖鐢诲竷**銆�
+- 妯℃澘琛岀焊鍨嬪榻愬悗鍥炶涓夎锛岀‘璁ゅ叏閮ㄤ笌褰撳墠鐗堟湰涓�鑷淬��
+
+**HTTP 瀹炴祴宸插畬鎴愶紙2026-09-19锛岀敤鎴蜂袱娆¢噸鍚悗绔悗锛�**锛�
+
+- `/d/qcl-tmp/verify-round2.mjs` 鈫� **21/21 PASS**锛圓 缁� 6 + B 缁� 7 + C 缁� 8锛夈��
+ - **A 缁� `/selectable`**锛氬厛璇佹槑妯℃澘 1 鍦ㄦ櫘閫氬垪琛ㄩ噷瀛樺湪銆乣status=0`锛堝惎鐢級銆乣current_version=v1.1` 鐘舵�� `1`锛堝凡鍙戝竷锛夈��
+ `grapes` 椤跺眰閿彧鏈� `assets,styles`锛�**闈炵┖浣嗘棤 pages**锛夆�斺�斿嵆鍓嶄袱閲嶈繃婊ゅ畠杩囧緱鍘伙紝
+ 鍞竴鑳芥尅瀹冪殑灏辨槸绗笁閲嶏紱闅忓悗 `/selectable?reportType=1` 杩斿洖 `[3]`锛�**妯℃澘 1 娑堝け**锛�
+ 鑰� `reportType=3` 浠嶈繑鍥炴ā鏉� 5锛堢涓夐噸娌℃湁涓�鍒�鍒囪浼わ級锛沗reportType=2` 杩斿洖绌烘暟缁勮�岄潪鎶ラ敊銆�
+ - **B 缁� `disableVersion`**锛堝湪涓存椂妯℃澘涓婂仛锛屼笉纰扮湡瀹炴暟鎹級锛氬仠鐢ㄩ潪褰撳墠鐗堟湰鎴愬姛涓� `status` 钀藉埌 2锛�
+ 鍋滅敤褰撳墠鐗堟湰杩斿洖 `1070101010`锛屾枃妗堝悓鏃跺甫鍑虹増鏈彿涓庢ā鏉垮悕锛屽苟缁欏嚭銆屽洖婊氬垏璧� / 鍋滅敤鏁翠釜妯℃澘銆嶄袱鏉″嚭璺紱
+ 鍙﹀姞涓�鏉�**銆岃鎷掑悗褰撳墠鐗堟湰鐘舵�佹湭琚敼鍔ㄣ��**锛岃瘉鏄庢嫆缁濇槸鐪熸病鍐欏簱锛岃�屼笉鏄厛鍐欏悗鎶涖��
+ - **C 缁� `CanvasSafety`**锛氬叚绉嶆敞鍏ュ舰鎬侊紙`<script>` 鏍囩銆乣tagName` 澶� `onerror`銆乣onclick` 浜嬩欢灞炴�с��
+ 灞炴�у悕澶瑰紩鍙枫�乣styles` 鏁存 CSS 瀛楃涓层�佹牱寮忚鍒欏�煎惈 `<`锛�**閫愪竴杩斿洖 `1070101009` 涓旀枃妗堝悇鑷偣鏄庡師鍥�**锛�
+ 姝e父鐢诲竷锛堝惈琛ㄦ牸/鍥剧墖/hr/鏂囨湰鑺傜偣锛夋斁琛岋紱`update` 璺緞鍚屾牱琚嫤锛堜笉鍙湁 `create` 鏈夐椄闂級銆�
+- `/d/qcl-tmp/pdf-e2e.mjs` 閲嶈窇 鈫� **20/20 PASS**銆傛湰杞柊鍔�/鏀瑰啓鐨勪袱鏉℃柇瑷�閮借繃浜嗭細
+ `0.5.1 妯℃澘琛岀殑绾稿瀷涓庡綋鍓嶇増鏈� Schema 鐨勭焊鍨嬩竴鑷� | 妯℃澘琛�=A4/portrait 鐗堟湰 v1.1=A4/portrait`锛�
+ `3.4 绾搁潰鍑犱綍涓庢覆鏌撴椂澹版槑鐨� @page 涓�鑷� | @page=210x297mm 鏈熸湜鈮�595.28x841.89pt 瀹為檯=594.96x841.92pt`
+ 锛堜笉鍐嶅啓姝荤旱鍚戯紝妯悜鐗堟湰涔熶笉浼氳鎶ワ級銆�60 椤归暱鎶ュ憡 3 椤点�佷腑鏂囧瓧浣撳凡宓屽叆銆�
+- `/d/qcl-tmp/verify-budget.mjs` 鈫� **6/6 PASS**锛坄max-duration-seconds` 涓存椂鏀� 0 + 閲嶅惎鍚庤窇锛岃窇瀹屽凡杩樺師涓� 180锛夛細
+ `1070104016` 鑰岄潪 `DRAFT_EMPTY`锛屾枃妗堝甫鍑虹敓鏁堥绠楋紙0 绉掞級涓庡疄闄呰�楁椂锛屽苟缁欏嚭銆屽噺灏戞枃浠�/鏌ユā鍨嬨�嶄袱鏉″姩浣滐紱
+ 绔埌绔� **29鈥�84 ms** 璇佹槑**涓�娆℃ā鍨嬭皟鐢ㄩ兘娌″彂**锛堢湡璋冧細鏄暟鍗冩绉掞級锛�
+ 瀵圭収缁勮瘉鏄庡叆鍙傛牎楠岋紙`schemaVersion` 鈫� `1070104009`锛夋帓鍦ㄩ绠楁鏌ヤ箣鍓嶃��
+ - **涓�涓彧鍦ㄦ瀬绔厤缃笅鎵嶅嚭鐜扮殑鏂囨鐟曠柕锛堟湭淇紝鍒ゅ畾涓轰笉鍊煎緱淇級**锛氶绠椾负 0 鏃跺惊鐜湪璇诲埌绗竴涓枃浠�**涔嬪墠**灏辫烦鍑猴紝
+ `fileNames` 涓虹┖锛屼簬鏄枃妗堝嚭鐜般�屽湪鏂囦欢銆屻�嶄腑鏈瘑鍒嚭浠讳綍鍙敤缁勪欢銆嶃�傜湡瀹為厤缃紙180 绉掞級涓嬪繀鐒跺凡缁忚杩囪嚦灏戜竴涓枃浠讹紝
+ 杩欎釜绌轰覆褰㈡�侀厤涓嶅嚭 0 灏卞鐜颁笉浜嗭紝灞炴祴璇曚笓鐢ㄥ舰鎬併��
+- **涓ゅ FAIL 鍏ㄦ槸鏂█鍐欓敊銆佷笉鏄骇鍝佺己闄�**锛歚1_070_104_016` 鐨勬暟鍊兼槸 **`1070104016`**锛�
+ 鎴戠涓�鐗堟寜 `1_070_104_016` 鐩村啓鎴� `10701010416`锛堝涓�浣嶏級銆�**娈靛彿鎷兼帴瑙勫垯锛歚1|070|104|016` 鈫� 鍘绘帀鍒嗛殧绗�**锛�
+ 鍐欐柇瑷�鍓嶅厛鐪嬫帴鍙g湡瀹炶繑鍥炲�硷紝鍒収鎶勯敊璇爜甯搁噺閲岀殑涓嬪垝绾垮舰寮忋��
+
+**娴嬭瘯鏁版嵁宸叉竻骞插噣**锛氫复鏃舵ā鏉� 32 鍙婂叾 3 涓増鏈‖鍒狅紱`pdf-e2e` 閫犵殑瀹炰緥 46/47銆侀檮浠� 69~72銆乥lob 63~66
+杩炲悓纾佺洏鏂囦欢涓�骞舵竻鎺夛紱棰勭畻鐢ㄤ緥鐨� 2 涓崰浣� blob锛�68/69锛変笌纾佺洏鏂囦欢鍚屾牱娓呮帀銆�
+鍥炶涓庡紑宸ュ墠涓�鑷达紙`qc_report_template` 3 琛屻�乣version` 6 琛屻�佸疄渚嬪彧鍓� 44/45銆乥lob 涓婇檺 67銆侀檮浠朵笂闄� 73锛夈��
+**鐢ㄦ埛鑷繁鐨勬暟鎹竴寰嬫湭鍔�**锛歜lob 67锛坄鐧句簨妯$増.docx`锛変笌闄勪欢 73锛堢粦鍦ㄦā鏉� 1 涓婏級銆佸疄渚� 44/45 鍧囦繚鎸佸師鏍枫��
+
+### 18.7 鏈疆鏈仛
+
+- 瀛橀噺鑴忕敾甯冪殑**鍥炴函鏍告煡**锛坄CanvasSafety` 鍙湪淇濆瓨鏃舵墽琛岋紝涓嶅洖鎵巻鍙茬増鏈級銆�
+- 璁捐鍣ㄣ�岄瑙堛�嶆寜閽帴 `instance/preview`锛堟湇鍔$娓叉煋锛夆�斺�旂敤鎴峰凡鏄庣‘閫夋嫨**淇濇寔鐜扮姸**銆�
+- 浜岀淮鐮佺敓鎴愯兘鍔涳紱`GENERATING` / `FAILED` 瀹炰緥鐘舵�侊紱`qc_report_data_source` / `qc_report_rule` 涓ゅ紶鏃� Java 瀵瑰簲鐨勮〃銆�
+- `@Disabled` 鐨勭湡瀹� AI 鑱旇皟娴嬭瘯锛汭PQC / OQC / RQC 涓夐〉 UI 閫愪竴鐐归獙銆�
+
+## 鍗佷節銆丄I 瀵煎叆淇锛氶〉鐪�/椤佃剼琚鎴愭枃鏈粍浠讹紙2026-09-19 缁級
+
+**鐢ㄦ埛鎶ョ殑鐜拌薄**锛氥�宎i 璇嗗埆鍑虹被浼奸〉鐪夋垨鑰呴〉鑴氱殑鏃跺�欎娇鐢ㄥ搴旂粍浠讹紝鐜板湪濂藉儚浣跨敤鐨勬槸鏂囨湰缁勪欢銆嶃��
+
+鎺掓煡鍚庣‘璁よ儗鍚庢槸**涓ゅ眰鐙珛鍘熷洜**锛屽彧淇竴灞備笉澶熴�傛湰杞�**鍓嶅悗绔竴骞舵敼**锛堢敤鎴峰凡鎺堟潈鍓嶇锛夈��
+鏃犳柊澧炰笟鍔″璞°�佹棤寤鸿〃銆佹棤娓叉煋寮曟搸鏀瑰姩銆佹棤璺ㄦā鍧� API 鍙樺寲銆�
+
+### 19.1 绗竴灞傦細鎻愮ず璇嶉噷瀵广��12 涓粍浠惰閫夊摢涓�嶉浂鎸囧
+
+绉湪娓呭崟鍙甫 `type` / `label` / `category` / `fields`锛岄搧寰� 5 鏉� + 鎶藉彇瑙勫垯 4 鏉�**娌℃湁涓�鏉¤閫夊瀷**銆�
+鑰岀粍浠朵箣闂村ぇ閲忓彲浜掔浉鏇夸唬锛�
+
+| 鏂囦欢閲岀殑鍐呭 | 鍙�夐」 |
+|---|---|
+| 鎶ュ憡鎶ご锛堝叕鍙稿悕 + 鎶ュ憡鏍囬锛� | `Heading`銆屾爣棰樸��/ `Text`銆屾枃鏈��/ `ReportHeader`銆屾姤鍛婇〉鐪夈�� |
+| 钀芥绛剧讲琛岋紙妫�楠屽憳/瀹℃牳/鏃ユ湡锛� | `Text` / `ReportFooter`銆屾姤鍛婇〉鑴氥�� |
+| 鏍峰搧/鐗╂枡淇℃伅鍧� | `Table` / `Text` / `SampleInfo`銆屾牱鍝佷俊鎭�� |
+| 妫�楠屾暟鎹〃 | `Table`銆屽熀纭�琛ㄦ牸銆�/ `QualityTable`銆屾楠岄」鐩〃鏍笺�� |
+| 鏁翠綋缁撹 | `Heading` / `Text` / `Result`銆屽垽瀹氱粨鏋溿�� |
+
+妯″瀷鍙湅涓枃 `label`锛屾病鏈夌悊鐢变笉鎸戝瓧娈垫渶绠�鍗曘�佹渶閫氱敤鐨勯偅涓�斺�旇繖灏辨槸銆岀敤浜嗘枃鏈粍浠躲�嶇殑鐩存帴鍘熷洜銆�
+
+**鐢ㄦ埛鎷嶆澘鐨勫彛寰�**锛氶�夊瀷鎸囧紩**鏀惧湪鍓嶇娉ㄥ唽琛ㄧ殑瀛楁閲�**锛堜笌缁勪欢瀹氫箟鍚屾簮锛屽墠绔敼缁勪欢鏃惰嚜鍔ㄨ窡闅忥級锛�
+**涓嶅悗绔‖缂栫爜**銆備竴鏃﹀悗绔偣鍚嶇粍浠讹紝缁勪欢璇箟灏卞張鍙樻垚绗簩涓湡鐩告潵婧愶紝姝f槸鏈」鐩竴鐩村湪閬垮厤鐨勩��
+
+**鏀规硶**锛堝墠绔� `mom-pro2-before/`锛屾湰杞敮涓�鏀瑰墠绔殑杞锛夛細
+
+| 钀界偣 | 鏀瑰姩 |
+|---|---|
+| `components/quality/core/types.ts` | `QualityComponentDefinition` 鍔犲彲閫夋垚鍛� `aiHint?: string` |
+| 12 涓粍浠舵枃浠� | 鍚勮ˉ涓�鏉� `aiHint`锛�**銆岀敤鏉ユ斁浠�涔堛��+銆屼笉瑕佺敤鏉ユ斁浠�涔堛��**銆傚悗鑰呮槸鍏抽敭锛屾ā鍨嬭鐢ㄧ殑鏍瑰洜姝f槸涓嶇煡閬撴煇涓�氱敤缁勪欢涓嶈鐢ㄥ湪杩欓噷 |
+| `components/quality/core/catalog.ts` | 娓呭崟椤瑰甫鍑� `hint?`锛堟部鐢ㄦ棦鏈夈�岀己甯嵆鐪佺暐銆嶉鏍硷級 |
+| `api/mes/qc/report/ai/index.ts` | catalog 鐨� TS 绫诲瀷鍔� `hint?` |
+
+**涓轰粈涔堝畨鍏�**锛氬叏 `src/` 娌℃湁浠讳綍 `Object.keys(definition)` / `for...in` / `{...definition}` /
+`JSON.stringify(definition)` / 娣辨瘮杈冦�傜敾甯冩瀯閫犳槸閫愬瓧娈垫樉寮忔寫锛涘睘鎬ч潰鏉垮彧浠� `propertySchema` 娲剧敓锛�
+搴忓垪鍖� / 瑁呴厤 / 鏍¢獙涓夊閮藉彧閬嶅巻 `propertySchema`锛涙敞鍐岃〃鏄� Map 鎸� `type` 绱㈠紩銆傚敮涓�鑱斿姩鐐规槸娓呭崟娲剧敓灞傘��
+
+**鍚庣鍙礋璐e簭鍒楀寲**锛歚QcReportComponentSpecVO` 鍔� `hint`锛�**缁勪欢绾�**锛屼笉鍔犲湪宓屽鐨� `Field` 涓婏級锛�
+鎻愮ず璇嶉噷杩藉姞涓�鏉℃娊鍙栬鍒欒姹傘�岄�夊瀷鏃朵互 hint 涓哄噯锛屾竻鍗曢噷瀛樺湪涓撻棬缁勪欢灏变笉瑕侀��鑰岀敤 Text / Heading 杩欑被閫氱敤缁勪欢鍑戞暟銆嶃��
+**鍒绘剰涓嶇偣鍚嶄换浣曠粍浠�**鈥斺�旇鍒� 5 鍏ㄦ枃涓嶅惈缁勪欢鍚嶏紝璇箟浠嶅彧娲诲湪鍓嶇銆�
+
+### 19.2 绗簩灞傦細`.docx` 鐨� Word 椤电湁/椤佃剼鍘嬫牴娌¤繘鎻愮ず璇�
+
+`OfficeImportAdapter` 璧� `document.getBodyElements()`锛屽彧閬嶅巻**姝f枃**锛涘叏妯″潡 grep 纭
+`getHeaderList()` / `getFooterList()` **涓�娆¢兘娌¤皟鐢ㄨ繃**銆備簬鏄偅浠芥枃浠剁殑椤电湁
+锛堝叕鍙稿悕 / 鑻辨枃鍚嶏級涓庨〉鑴氾紙鍒堕�犲晢 / 鍘傚潃 / 鐢佃瘽锛�**妯″瀷浠庢潵娌$湅瑙佽繃**锛屽畠鎯崇敤 `ReportHeader` 涔熸棤浠庝笅鎵嬨��
+
+**鐢ㄦ埛鎷嶆澘鐨勫彛寰�**锛歞ocx 鐨� Word 椤电湁椤佃剼**璇昏繘鏉ュ苟鍔� `[椤电湁]` / `[椤佃剼]` 鏍囪**銆�
+
+**鏀规硶**锛坄OfficeImportAdapter`锛夛細
+
+1. 鎶婃鏂囬亶鍘嗘娊鎴� `appendBodyElements(StringBuilder, List<IBodyElement>)`锛屾鏂�/椤电湁/椤佃剼**鍏辩敤涓�浠借〃鏍奸�昏緫**锛岄伩鍏嶄袱濂楁紓绉伙紱
+2. 鏂板 `collectHeaderFooter(...)`锛氶�愪釜鏀堕泦鍚�**鎸夊綊涓�鍖栨枃鏈幓閲�**锛圵ord 鏈夐椤�/濂囨暟椤�/鍋舵暟椤靛濂楅〉鐪夛紝鍐呭甯搁�愬瓧鐩稿悓锛夛紱
+ **绌虹櫧蹇呴』杩囨护**鈥斺�旀枃妗f病鏈夐〉鐪夋椂 POI 浠嶅彲鑳借繑鍥炰竴涓┖ header锛屼笉杩囨护浼氳鏃㈡湁澶瑰叿鍑┖澶氬嚭 `[椤电湁]` 鏍囪锛�
+3. `readDocx` 鏀逛负杩斿洖 `record DocxRead(String text, List<String> notes)`锛屾嫾瑁呴『搴忎负
+ `[椤电湁] 鈫� 姝f枃 鈫� [椤佃剼]`锛堜笌鏂囨。瑙嗚椤哄簭涓�鑷达紝涓�**浠呭綋闈炵┖**锛夛紱
+4. 瀹為檯璇诲埌鍐呭鏃跺線 `notes` 鍔犱竴鏉¤蒋鎻愮ず锛岀粡 `QcReportImportServiceImpl` 鏃㈡湁鐨�
+ `warnings.addAll(extract.notes())` 鐩存帴杩涘搷搴� `warnings`锛�**鍓嶇鏃犻渶浠讳綍鏂颁唬鐮佸氨鑳藉睍绀�**銆�
+
+**鍙湁 docx 闇�瑕�**锛歅DF / 鍥剧墖閫氶亾閲岄〉鐪夐〉鑴氭湰鏉ュ氨鏄〉闈㈠儚绱犳垨鏂囨湰鐨勪竴閮ㄥ垎锛屾棤闇�鏍囪銆�
+
+### 19.3 椤哄甫淇帀鐨勪袱涓湡瀹炵己闄凤紙鐢ㄦ埛閫愭潯鎷嶆澘鍚庤惤鍦帮級
+
+**(a) 琛ㄦ牸鏈鐨勮惤娆剧缃茶琚綋鎴愭暟鎹涓㈡帀銆�** 鎶藉彇瑙勫垯绗� 1 鏉″啓鐫�銆屽叿浣撴暟鎹涓嶈鍐欒繘妯℃澘銆嶏紝
+鑰岀缃茶锛堟楠屽憳/瀹℃牳浜�/鏃ユ湡锛�**灏辨帓鍦ㄦ楠岃〃鏍肩殑鏈�鍚庝竴琛�**锛屼簬鏄鏁磋涓㈡帀锛岃惤娆惧啀涔熸壘涓嶅洖鏉ャ��
+鏀规硶锛氳鍒� 6 鏄惧紡鎶婂畠浠庣 1 鏉¢噷璞佸厤鍑烘潵锛屽苟瑕佹眰**涓庡師浠堕〉鑴氬悎鎴愪竴澶�**鏀捐繘 `ReportFooter`锛�
+鍚屾椂鎶婂畠鍐欒繘 `ReportFooter` 涓� `QualityTable` 涓ゆ潯 `aiHint`锛堜袱渚у悇鑷0鏄庤竟鐣岋紝妯″瀷浠庝换涓�渚х湅閮戒竴鑷达級銆�
+**瑕佺偣鍚嶃�屽嵆浣垮畠鎺掑湪妫�楠岃〃鏍肩殑鏈�鍚庝竴琛屼篃涓�鏍枫�嶈繖涓綅缃�**鈥斺�斾笉鐐瑰悕锛屾ā鍨嬩粛浼氭寜绗� 1 鏉℃妸瀹冨綋鏁版嵁琛屻��
+
+**(b) 妯″瀷缁欑缃茶缂栭�犱簡涓嶅瓨鍦ㄧ殑缁戝畾閿��** 淇ソ (a) 涔嬪悗瀹炴祴杈撳嚭锛�
+
+```
+ReportFooter.props.text = "妫�楠屽憳锛歿{report.inspector}} 瀹℃牳浜� Auditor锛歿{report.auditor}} 鏃ユ湡 Date锛歿{report.date}}"
+```
+
+`{{report.auditor}}` / `{{report.date}}` **鍦ㄤ笂涓嬫枃閲屾牴鏈笉瀛樺湪**鈥斺�旀煡 `ReportFields`
+锛堟姤鍛婁笂涓嬫枃瀛楁鐨勬潈濞佹竻鍗曪級纭鍙湁 `inspector` 涓� `inspectDate`锛�**娌℃湁 `auditor`銆佹病鏈� `date`**銆�
+鏌� `binding.ts` 纭鍙栦笉鍒扮殑璺緞娓叉煋鎴�**绌哄瓧绗︿覆**锛堟姤鍛婁笂涓嶄細鍑虹幇鐢ㄦ埛鐪嬩笉鎳傜殑 `{{}}`锛夛紝
+浣嗕細**鐣欎笅绌虹櫧骞惰Е鍙戜竴鏉°�岀粦瀹氬彇涓嶅埌鍊笺�嶅憡璀�**銆�
+
+**鐢ㄦ埛鎸囦护**锛�**銆屽鏍镐汉鐣欑┖鎵撳嵃鍑烘潵濉��**銆傜敱姝よ惤鍦颁负瑙勫垯 6 鐨勫悗鍗� + 鏂板瑙勫垯 7锛�
+
+- 绛剧讲琛�**淇濈暀鏍忕洰鍚嶃�佸�肩暀绌�**锛屽啓鎴愩�屾楠屽憳锛歕_\_\_\_銆�瀹℃牳浜猴細\_\_\_\_銆�鏃ユ湡锛歕_\_\_\_銆嶈繖鏍风殑濉啓浣嶏紝
+ 鎵撳嵃鍑烘潵鐢变汉鎵嬪~銆�**浜哄悕涓庢棩鏈熸槸姣忎竴浠芥姤鍛婂悇鑷殑鏁版嵁**锛屽啓姝诲師浠朵笂鐨勯偅鍑犱釜浜轰細璁╂墍鏈夋姤鍛婂嵃鎴愬悓涓�涓楠屽憳锛�
+- 瑙勫垯 7 鏄庝护**涓嶅緱鑷�犵粦瀹氶敭**锛氭ā鍨嬪苟涓嶇煡閬撲笂涓嬫枃閲屾湁鍝簺瀛楁锛岀紪鍑烘潵鐨勯敭娓叉煋鏃跺彧浼氱暀鐧藉姞鍛婅銆�
+
+> 杩欎竴鏉′笌鎴戝厛鍓嶇粰鐢ㄦ埛鐪嬭繃鐨勯瑙堜笉涓�鑷达紙棰勮閲屾槸銆屾楠屽憳锛氭紗鍏甸湠 鏉ㄦ収銆嶈繖绫�**瀛楅潰浜哄悕**锛夈��
+> 鐢ㄦ埛鐨勬寚浠よ鐩栦簡閭d釜缁嗚妭锛屾敼涓虹暀绌衡�斺�斾笖瀹冧笌瑙勫垯 1 鐨勫墠鎻愶紙妯℃澘鍙暀缁撴瀯锛夋湰灏辫嚜娲斤紝
+> `ReportFooter` 鐨勯粯璁ゅ�间篃姝f槸銆屾楠屽憳锛歕_\_\_\_銆�瀹℃牳浜猴細\_\_\_\_銆�鏃ユ湡锛歕_\_\_\_銆嶃��
+> **鐣欑棔鍦ㄦ锛岄伩鍏嶄互鍚庢湁浜轰互涓哄瓧闈汉鍚嶆墠鏄鏈熴��**
+
+### 19.4 涓�澶勪竴骞惰娓呯殑鍙e緞锛氭鏂囨姮澶�/钀芥 鈮� 姣忛〉閲嶅鐨勯〉鐪夐〉鑴�
+
+鐢诲竷涓婄殑 `ReportHeader` / `ReportFooter` 鏄�**姝f枃娴侀噷**鐨勬姮澶村潡涓庤惤娆惧潡锛�
+PDF 姣忛〉閲嶅鐨勯〉鐪夐〉鑴氭槸鏈嶅姟绔� `PdfPrintOptions` 鍔犵殑锛堢洰鍓嶅彧鏈夐〉鐮侊級銆�
+鎵�浠ャ�學ord 椤电湁 鈫� `ReportHeader`銆嶆槸**鎶婂畠鎸繘姝f枃椤堕儴**锛�**涓嶆槸**杩樺師姣忛〉閲嶅鐨勬墦鍗扮増寮忋��
+宸插啓杩涘墠绔仈璋冩枃妗o紝閬垮厤鍓嶇璇互涓哄鍏ュ悗鑳藉緱鍒版瘡椤甸噸澶嶇殑椤电湁銆�
+
+### 19.5 娴嬭瘯涓庨獙璇佺姸鎬侊紙宸插仛 / 鏈仛鍒嗗紑澹版槑锛�
+
+**宸查獙璇侊紙纭畾鎬э級**锛�
+
+- `mvn -pl yudao-module-qcreport test` 鈫� **`Tests run: 137, Failures: 0, Errors: 0`**锛�
+ 鍏ㄧ豢锛�132 椤瑰瓨閲� + 鏈疆鏂板锛沗QcReportTemplatePromptBuilderTest` 8 鈫� 9锛夈��
+- 鍓嶇瀵规媿 `npx tsx .qc-conformance/assemble-ts.ts` 鈫� 鍏ㄩ儴閫氳繃銆傛竻鍗曟柊澧炰竴鏉℃柇瑷�
+ **銆屾瘡涓粍浠堕兘鍐欎簡闈炵┖ aiHint銆�**锛�12/12锛夛紝瀛楁闆嗗悎鏂█鍚屾涓� `category/fields/hint/label/type`銆�
+- **鎻愮ず璇嶆瀯閫犲疄娴�**锛堝垪浠撳簱澶栨帰閽� `D:/qcl-tmp/PromptProbe.java`锛夛細鎷�**鐪熷疄鍓嶇瀵煎嚭鐨勬竻鍗�**鍙嶅簭鍒楀寲鍚�
+ 璋冪湡瀹� `QcReportTemplatePromptBuilder.buildSystemPrompt`锛屾彁绀鸿瘝 5816 瀛楃锛�
+ **12 鏉� `hint` 閫愭潯鍦ㄥ満锛堢己澶� 0锛�**锛岃鍒� 6/7 鏂囨閫愬彞鍦ㄥ満銆�
+- **docx 鎶藉彇瀹炴祴**锛堝垪浠撳簱澶栨帰閽� `D:/qcl-tmp/HeaderFooterProbe.java`锛夛細瀵圭湡瀹炴枃浠惰皟**鐢熶骇绫�**
+ `OfficeImportAdapter`锛岀‘璁ら〉鐪�/椤佃剼琚鍑哄苟浠� `[椤电湁]` / `[椤佃剼]` 鏍囪骞跺叆锛宍notes` 闈炵┖銆�
+ > 杩欎袱涓帰閽堢殑鎰忎箟鏄細鎶娿�屽悗绔�昏緫瀵逛笉瀵广�嶄笌銆屾ā鍨嬮�夊緱瀵逛笉瀵广��**褰诲簳鍒嗗紑**銆�
+ > 鍓嶈�呭繀椤荤‘瀹氭�ф柇瑷�锛屽悗鑰呭彧鑳介潬鐪熷疄璋冪敤瑙傚療銆�
+
+**HTTP 瀹炴祴锛堢湡瀹炶皟鐢紝濡傚疄姹囨姤娉㈠姩锛�**锛�
+
+- 瑙勫垯 6/7 钀藉湴**鍓�**鐨勭姸鎬佸凡瀹炴祴 3 娆★紙2 娆¤剼鏈� + 1 娆� UI锛夛紝3 娆$粨鏋滀竴鑷达細
+ `ReportHeader 鈫� SampleInfo 鈫� QualityTable 鈫� Result 鈫� ReportFooter`锛�**`Text` 鏈嚭鐜�**锛�
+ 5 椤圭‘瀹氭�ф柇瑷�姣忔鍏ㄨ繃锛堝惈 `warnings` 鍑虹幇銆屽師浠跺甫鏈夐〉鐪�/椤佃剼銆嶏級銆�**椤堕儴涓庡簳閮ㄩ兘钀藉埌浜嗕笓闂ㄧ粍浠朵笂**銆�
+- **瑙勫垯 6/7 钀藉湴鍚庯紙鐢ㄦ埛閲嶅惎鍚庣鍚庯級澶嶉獙 2 娆★紝涓ゆ缁撴灉涓�鑷�**锛屽叧閿瘉鎹� 鈥斺�� `ReportFooter.props.text`锛�
+
+ 绗� 1 娆★細
+
+ ```
+ 妫�楠屽憳 锛歘_________ 瀹℃牳浜� Auditor锛歘_________ 鏃ユ湡 Date锛歘_________
+ 鍒堕�犲晢锛氭柊鐤嗗ぇ缃楃礌椹搩钖埗鍝佹湁闄愬叕鍙�
+ 鍘傚潃锛氭柊鐤嗗寳灞競宸ヤ笟鍥尯閲戣緣璺�555鍙�
+ 鐢佃瘽鍙风爜锛�0906-7516688
+ ```
+
+ 绗� 2 娆★紙鎺緸涓庢崲琛屾湁宸紓锛屽舰鎬佺浉鍚岋級锛�
+
+ ```
+ 妫�楠屽憳 锛歘_________ __________
+ 瀹℃牳浜� Auditor锛歘_________
+ 鏃ユ湡 Date锛歘_________
+ 鍒堕�犲晢锛氭柊鐤嗗ぇ缃楃礌椹搩钖埗鍝佹湁闄愬叕鍙�
+ 鍘傚潃锛氭柊鐤嗗寳灞競宸ヤ笟鍥尯閲戣緣璺�555鍙�
+ 鐢佃瘽鍙风爜锛�0906-7516688
+ ```
+
+ 涓ゆ閮芥弧瓒充笁浠朵簨锛�**鈶� 绛剧讲琛屾爮鐩悕鍦ㄣ�佸�肩暀绌�**锛堣鍒� 6 鍚庡崐鐢熸晥锛夛紱
+ **鈶� 閫氱瘒鏃� `{{report.auditor}}` / `{{report.date}}`**锛堣鍒� 7 鐢熸晥锛屽姣斿楠屽墠閭f鐨�
+ `瀹℃牳浜� Auditor锛歿{report.auditor}} 鏃ユ湡 Date锛歿{report.date}}`锛夛紱
+ **鈶� Word 椤佃剼涓夎涓庣缃茶鍚堟垚鍦ㄥ悓涓�涓� `ReportFooter` 閲�**锛堢敤鎴锋媿鏉跨殑銆孉 + B 閮借杩涖�嶏級銆�
+ 涓ゆ鐨� `type` 搴忓垪鍧囦负 `ReportHeader 鈫� SampleInfo 鈫� QualityTable 鈫� Result 鈫� ReportFooter`锛�
+ **`Text` 鏈嚭鐜�**锛�5 椤圭‘瀹氭�ф柇瑷� **5/5 PASS**锛岃�楁椂 11.7 s / 10.4 s銆�
+
+**鏈獙璇� / 涓嶄富寮�**锛�
+
+- **妯″瀷鏄惁姣忔閮介伒瀹堣鍒� 6/7锛屾病鏈夌‘瀹氭�ц瘉鎹�**銆傛ā鍨嬭緭鍑轰細娉㈠姩锛屽楠屽彧浣溿�岃瀵熻褰曘�嶏紝
+ **涓嶅啓鎴愩�屽凡楠岃瘉姝g‘銆�**銆傜湡姝g殑闂搁棬鍦ㄥ啓鍏ヤ晶涓庡墠绔閰嶅櫒锛堟湭娉ㄥ唽 type 浼氳璺宠繃锛夈��
+ 涓ゆ澶嶉獙鐨勬帾杈�/鎹㈣閮芥湁鍑哄叆锛堢 2 娆℃妸銆屾楠屽憳銆嶅悗闈㈢殑绗簩涓~鍐欎綅鍗曠嫭鎹㈣浜嗭級锛�
+ 姝h鏄庤繖绫绘敼鍔ㄥ彧鑳介潬鐪熷疄璋冪敤瑙傚療锛屼笉鑳界敤鏂█閽夋銆�
+- **鏈仛 UI 楠屾敹锛堢浜岃疆锛�**锛氭湰杞� UI 楠屾敹鏄湪瑙勫垯 6/7 钀藉湴**鍓�**鍋氱殑锛堜复鏃舵ā鏉� 34锛夈��
+ 钀藉湴鍚庡彧鍋氫簡 HTTP 澶嶉獙锛�**娌℃湁閲嶈窇璁捐鍣� UI 閭d竴璺�**銆傛敼鍔ㄥ彧褰卞搷鎻愮ず璇嶆枃鏈紝
+ 瑁呴厤鍣ㄤ笌璁捐鍣ㄤ唬鐮佷竴琛屾湭鍔紝鍥犳鍒ゅ畾涓轰綆椋庨櫓锛涗絾**杩欎竴鏉℃槸銆屾病鍋氥�嶈�屼笉鏄�岄�氳繃銆�**銆�
+- 鏈啓銆宮ock 妯″瀷鍠傜綈澶� JSON 鏂█瀹冮�夊浜嗙粍浠躲�嶈繖绫绘祴璇曗�斺�旈偅鏄湪娴� mock锛屼笉鏄祴浜у搧銆�
+
+**娴嬭瘯鏁版嵁娓呯悊锛堝凡鍥炶姣斿锛�**锛氫复鏃舵ā鏉� 34 / 35 / 36 鍏ㄩ儴杞垹锛涘楠屼笂浼犵殑瀛ゅ効 blob 76 / 77
+璧般�屽厛 bind 鍒颁复鏃舵ā鏉� 36 鍐嶅垹闄勪欢銆嶇殑绾ц仈娓呮帀锛�**blob 娌℃湁鐙珛鍒犻櫎鎺ュ彛**锛夛紱
+`D:/uploads/2026/0919/` 鍥炲埌鐢ㄦ埛鑷繁鐨� 4 涓枃浠躲�傚洖璇讳笌寮�宸ュ墠涓�鑷达細
+blobs `20/62/67/70`銆乤ttachments `18/68/73/74`銆�**鐢ㄦ埛鑷繁涓婁紶鐨� `鐧句簨妯$増.docx`锛坆lob 67/70銆侀檮浠� 73/74锛夊叏绋嬫湭鍔ㄣ��**
+
+### 19.6 鏈疆鏈仛 / 閬楃暀
+
+- `docs/qc_report_ai_import_frontend_integration.md` 宸插悓姝ワ紙`hint` 瀛楁銆乣[椤电湁]`/`[椤佃剼]` 鍙e緞銆�
+ 姝f枃鎶ご涓庣増寮忛〉鐪夌殑鍖哄埆銆佺缃茶涓ゆ潯瑙勫垯锛夈��**鏈啓浠讳綍鍓嶇浠g爜鐗囨**锛堟寜椤圭洰瑙勫垯锛夈��
+- 棰勭暀浣嗘湭瀹炴柦锛歚.qc-conformance/dump-catalog.ts`锛堟湰杞负瀵煎嚭鐪熷疄娓呭崟涓存椂鍔犵殑鑴氭湰锛�**鏈 git 璺熻釜**锛�
+ 鐢ㄩ�旀槸鎶婃竻鍗� dump 鎴� JSON 渚涜仈璋冭剼鏈鍙栵紱淇濈暀涓庡惁寰呭畾锛夈��
+- 鐢ㄦ埛鍏堝墠鎻愬嚭鐨勫彟涓�涓棶棰樸�屽浣曢珮搴﹁繕鍘熻繖绉嶅鏉傜殑妫�楠岄」銆�**浠嶆湭閫夊畾鏂规**锛屾湰杞湭鍔ㄣ��
+
+## 浜屽崄銆佽惤娆炬姌琛屼慨姝o細绛剧讲琛屼笌鍒堕�犲晢琚姌鎴愪竴鐗囷紙2026-09-19 缁級
+
+### 20.1 鐜拌薄涓庢牴鍥�
+
+鐢ㄦ埛鍦ㄦ覆鏌撳嚭鏉ョ殑鎶ュ憡涓婃寚鍑恒��**鏃ユ湡鍜屽埗閫犲晢甯冨眬鏈夌偣涓嶈**銆嶏細钀芥搴旇鏄嚑琛岋紝瀹為檯鏄�
+`妫�楠屽憳锛歘_________ 瀹℃牳浜� Auditor锛歘_________ 鏃ユ湡 Date锛氬埗閫犲晢锛氭柊鐤嗗ぇ缃楃礌椹搩钖埗鍝佹湁闄愬叕鍙稿巶鍧�锛氣�︾數璇濆彿鐮侊細鈥
+**涓�鏁寸墖杩炲湪涓�璧�**锛堝彧闈犲鍣ㄥ搴︽姌鎴愪袱琛岋紝鎹㈣浣嶇疆鐢卞搴﹀喅瀹氾紝涓嶆槸鍐呭鏈韩鐨勬柇鐐癸級銆�
+
+鏍瑰洜鏄�**娓叉煋渚у鎹㈣鐨勫鐞嗭紝涓嶆槸 AI 杈撳嚭**锛圓I 渚х殑杈撳嚭鏄鐨勶級锛氳鍒� 6 瑕佹眰鎶婄缃茶涓庡師浠堕〉鑴�
+**鍚堟垚鍚屼竴涓� `ReportFooter`**锛孉I 鐓у仛锛屽嚑娈典箣闂寸敤 `\n` 鍒嗛殧銆傝��
+`ReportFooter.buildContent` 鍙仛浜� `escapeHtml(properties.text)`锛�
+**`escapeHtml` 鍙鐞� `& < > " '`锛屽畬鍏ㄤ笉纰版崲琛�**锛坄core/html.ts`锛夛紱
+HTML 鐨勭┖鐧芥姌鍙犺鍒欐妸 `\n` 鎶樻垚鏅�氱┖鏍硷紝浜庢槸鍥涜绮樿繛鎴愪竴娈点��
+
+**鍚屼竴寮犳埅鍥鹃噷鐨勮摑鑹� `Table cell` 涓嶆槸缂洪櫡**锛氶偅鏄� GrapesJS 閫変腑鎬佺殑缁勪欢鍚嶅窘鏍�
+锛圙rapesJS 鎶� `<td>` 鍛藉悕涓� "Table cell"锛夛紝宸茬‘璁ゅ墠绔簮鐮佷笌鍏ㄩ儴宸插瓨鐢诲竷閲岄兘涓嶅瓨鍦ㄨ繖涓瓧绗︿覆銆�
+
+### 20.2 鏀瑰姩锛堜笁澶勶紝鍏ㄥ湪鍓嶇锛�
+
+| 鏂囦欢 | 鏀瑰姩 |
+|---|---|
+| `src/components/quality/core/html.ts` | 鏂板 `escapeHtmlMultiline`锛�**鍏堣浆涔夈�佸啀鎶� `\r\n?|\n` 鎶樻垚 `<br>`** |
+| `src/components/quality/header/report-footer.ts` | `escapeHtml` 鈫� `escapeHtmlMultiline` |
+| `src/components/quality/base/text.ts` | 鍚屼笂锛圓I 鏈夋椂鎶婄缃茶鏀捐繘 `Text`锛屽彧淇〉鑴氫細鐣欐紡娲烇級 |
+
+**鎶樿鏀惧湪璁捐鏈燂紙`buildContent`锛夎�屼笉鏄覆鏌撴湡**锛歚HtmlRenderer` 涓� `BASE_CSS` 鏄喕缁撶殑
+锛坄FrontendConformanceTest` 涓庡墠绔紩鎿庨�愬瓧瀵规媿锛夛紝**绾㈢嚎涓嶅姩**銆俙buildContent` 浜у嚭鐨�
+`content` 灏辨槸鐢诲竷鍐呭锛屾覆鏌撳紩鎿庡彧鍋� `{{}}` 鍙栧�笺�佸師鏍疯緭鍑猴紙鍓嶅悗绔袱渚ч兘宸茶鐮佺‘璁わ細
+`render.ts:renderText` / `HtmlRenderer.renderText` 鈫� `Bindings.resolveText`锛�**鍧囦笉鍐嶈浆涔�**锛夛紝
+鎵�浠ュ啓杩� `content` 鐨� `<br>` 鑳戒竴璺椿鍒� HTML 涓� PDF銆�
+
+`Heading` 鏈敼锛氭爣棰樻槸鐭崟琛岋紝娌℃湁澶氳鐨勮瘉鎹�俙Result` / `SampleInfo` / `ReportHeader`
+鏄嫾鎺ュ紡鎴栭敭鍊煎紡锛屼笉鍙楀奖鍝嶃��
+
+### 20.3 楠岃瘉锛堝凡鍋氾級
+
+- **鍚庣 `mvn -pl yudao-module-qcreport test`锛�137/137 鍏ㄧ豢**銆傜敾甯� fixture 鏄喕缁撶殑棰勬瀯寤� JSON锛�
+ `buildContent` 鍙湪璁捐鏈熻窇锛屾晠涓�鑷存�у鎷嶄笉鍙楀奖鍝嶃��
+- **鍓嶇瀵规媿鑴氭湰鏂板绗� 10 鑺�**锛坄.qc-conformance/assemble-ts.ts`锛岃剼鏈湰浣撴湭琚� git 璺熻釜锛夛細
+ `ReportFooter` / `Text` 鍚勪袱鏉℃柇瑷� 鈥斺�� `content` 閲屽嚭鐜� `<br>` 涓�**涓嶆槸琚浆涔夌殑 `<br>`**銆�
+ `data-qc-text` 灞炴��**淇濈暀鍘熷 `\n`**锛堝睘鎬ч潰鏉夸笌缁戝畾鎸夌函鏂囨湰澶勭悊锛屾姌琛屽彧鍙戠敓鍦ㄦ覆鏌撲骇鐗╄繖涓�渚э級銆�
+ 杩炲師鏈夊悇鑺備竴璧� **鍏ㄩ儴閫氳繃**銆�
+- **瑁呴厤 鈫� 娓叉煋鎺㈤拡**锛堜复鏃� tsx 鑴氭湰锛岀敤瀹屽凡鍒狅級锛氬琛岃惤娆剧粡 `assembleQualityCanvas` +
+ `renderReport` 鍚庝骇鍑� 3 涓� `<br>`銆佸洓琛屾枃瀛楀叏鍦ㄥ満锛沗<script>` 浠嶈杞箟鎴� `<script>`锛�
+ **鎹㈣澶勭悊娌℃湁鍓婂急娉ㄥ叆闃叉姢**锛涘崟琛岃惤娆鹃�愬瓧涓嶅彉锛堟棤鍥炲綊锛夈��
+- **娴忚鍣ㄩ獙鏀讹紙璁捐鍣ㄧ敾甯冿級**锛氫复鏃跺缓妯℃澘 37 / 鑽夌鐗堟湰 22锛岀敾甯冮噷鐨� `ReportFooter`
+ 甯﹂偅鍥涜钀芥锛屾墦寮� `/qc/report-template/designer?id=37` 璇荤敾甯� iframe 鐨勭湡瀹� DOM锛�
+ `innerText` 鏂垚 **4 琛�**銆乣<br>` **3 涓�**銆乣data-qc-text` 閲� `\n` 鍘熸牱淇濈暀锛�
+ 椤堕儴 `Heading`銆屾 楠� 鎶� 鍛娿�嶄篃鍦ㄣ��**杩欎竴灞忓氨鏄敤鎴风湅鍒板嚭闂鐨勯偅涓�灞忥紝鐜板湪鏄鐨勩��**
+
+### 20.4 鏈仛 / 宸茬煡杈圭晫锛堝瀹炲0鏄庯級
+
+- **瀛橀噺宸蹭繚瀛樼殑鐢诲竷涓嶅洖婧�**銆俙content` 鍙湪 `buildContent`锛堟柊寤虹粍浠� / AI 瑁呴厤锛夋椂鐢熸垚锛�
+ 璁捐鍣�**杞藉叆**妯℃澘涓嶄細閲嶇畻 `content`锛坄canvas-sync.ts` 鍙噸寤� traits锛屼笉閲嶇畻鍐呭锛夛紝
+ 鎵�浠�**鏀瑰姩涔嬪墠**灏变繚瀛樿繃鐨勫琛岃惤娆句粛浼氭槸鎶樺湪涓�璧风殑銆傚疄娴� 7 涓凡瀛樼敾甯冪増鏈噷
+ **娌℃湁浠讳綍涓�涓惈銆屽埗閫犲晢銆�/銆屽巶鍧�銆�**锛屽嵆娌℃湁瀛橀噺鍙楀奖鍝嶏紱浠嶅�煎緱鏃ュ悗涓�璧锋竻鐞嗚剰鐢诲竷鏃剁粺涓�澶勭悊銆�
+- **灞炴�ч潰鏉夸粛鏄崟琛岃緭鍏�**锛氬彲缁戝畾瀛楁缁熶竴鐢ㄨ嚜瀹氫箟鎺т欢 `qc-binding`锛岄噷闈㈡槸
+ `<input type="text">`锛坄trait-binding.ts`锛夈��**浜烘墜鍦ㄨ璁″櫒閲屾敼钀芥锛屼粛鐒舵墦涓嶅嚭鎹㈣銆�**
+ 鏈疆**鏈姩**锛氭妸瀹冩崲鎴� `<textarea>` 浼氬悓鏃舵敼鍙� 12 涓粍浠堕噷鍏ㄩ儴鍙粦瀹氬瓧娈电殑杈撳叆褰㈡�侊紝
+ 灞炰簬瑕佸崟鐙媿鏉跨殑鍙栬垗锛屼笉澶瑰甫鍦ㄥ竷灞�淇閲屻��**AI 瀵煎叆鍑烘潵鐨勫琛岃惤娆句笉鍙楁闄�**锛堝�煎師鏍蜂繚鐣欙紝
+ 鍙涓嶅幓缂栬緫閭d釜杈撳叆妗嗭級銆�
+- **娴忚鍣ㄩ獙鏀跺彧瑕嗙洊璁捐鍣ㄧ敾甯�**锛�**娌℃湁閲嶈窇銆岀湡瀹� AI 瀵煎叆 + 鎴浘銆嶉偅涓�璺�**锛�
+ 鏈疆鍓嶇鏀瑰姩涓嶆敼鍙� AI 鐨勮緭鍑烘枃鏈紝鐢ㄨ閰嶅ソ鐨勫悓涓�娈靛琛岃惤娆惧嵆鍙‘瀹氭�у鐜扮敤鎴烽偅涓�灞忥紝
+ 鍥犳娌℃湁涓轰竴娆¢潪纭畾鎬х殑 AI 璋冪敤鍐嶈姳涓�娆¢绠椼��**杩欎竴鏉℃槸銆屾病鍋氥�嶏紝涓嶆槸銆岄�氳繃銆嶃��**
+- 鏈疆**娌℃湁**鏀规彁绀鸿瘝銆�**娌℃湁**鏀� `HtmlRenderer` / `BASE_CSS`銆�**娌℃湁**鏀� SQL 涓庡缓琛ㄣ��
+ 涓氬姟鍙鍖栨枃妗� `docs/project-business/` 鏈疆**鏈敼**锛氳繖鏄覆鏌撳眰甯冨眬淇锛�
+ 涓氬姟妯″潡 / 瀵硅薄 / 娴佺▼姝ラ / 鐘舵�佹祦杞� / 鏉冮檺鍧囨棤鍙樺寲锛堝垽鎹細AI 鐨勮緭鍑鸿涔変笌涓婁竴杞畬鍏ㄤ竴鑷达級銆�
+
+### 20.5 娴嬭瘯鏁版嵁娓呯悊
+
+涓存椂妯℃澘 37 涓庤崏绋跨増鏈� 22 **宸插垹闄ゅ苟鍥炶纭**锛堢増鏈垪琛ㄤ负绌恒�佹ā鏉� `get` 杩斿洖 `data=null`锛夛紱
+鏈疆**娌℃湁涓婁紶鏂囦欢**锛屼笉娑夊強闄勪欢涓� `blob`锛涗复鏃剁殑瑁呴厤鑴氭湰涓庢埅鍥惧凡浠庡伐浣滃尯绉婚櫎銆�
+
+## 浜屽崄涓�銆佸鏉傛楠岄」杩樺師锛氬垎缁勬楠岄」锛�2026-09-19 缁級
+
+> 鏂规涓庡畾绋垮彛寰勶細`docs/qc_report_grouped_inspection_design.md`锛�**宸插畾绋垮苟寮�宸�**锛夈��
+> 鎵挎帴 搂19.6 鐣欑殑閭f潯銆岀敤鎴峰厛鍓嶆彁鍑虹殑鍙︿竴涓棶棰樸�庡浣曢珮搴﹁繕鍘熻繖绉嶅鏉傜殑妫�楠岄」銆忎粛鏈�夊畾鏂规銆嶃��
+
+### 21.1 瑕佷慨鐨勬槸浠�涔�
+
+鍘熶欢锛堟潵鏂欐楠屾姤鍛婏級閲岀殑妫�楠岄」鏄�**涓ゅ眰**鐨勶細`姘村垎` 鏄竴涓垎缁勯」锛屽畠鑷繁鍙湁涓�鏉″叕寮�
+`w = (m1 - m0) / m 脳 100%`锛屽疄娴嬪�煎湪瀹冧笅闈㈢殑瀛愰」 `璇曟牱璐ㄩ噺 m` / `姘村垎缁撴灉 w` 涓娿��
+澶嶆潅璐ㄦ鍗曟棭宸叉寜杩欎釜缁撴瀯瀛樹簡鏁版嵁锛坄mes_qc_indicator.parent_id` / `item_type` / `formula_text`锛夛紝
+**鍑烘姤鍛婇偅涓�渚ф妸瀹冨帇骞充簡**锛氱粍鍚嶄笌鍏紡鏁存潯涓㈡帀锛屽瓙椤瑰悇鍗犱竴琛屻�佺湅涓嶅嚭璋佸睘浜庤皝銆�
+
+| 浣嶇疆 | 鏀瑰墠 | 鏀瑰悗 |
+|---|---|---|
+| 褰掑睘淇℃伅 | 鏃� | 缁勫悕鍚堝苟锛坄rowspan`锛夛紝瀛愰」琛岃浣嶏紙`hidden`锛� |
+| 缁勫叕寮� `formula_text` | 涓� | 杩涚粍澶磋鐨勩�屾娴嬭姹傘�嶆牸 |
+| 鍒楁暟 | 6 鍒� `QualityTable` | 鏂板 **7 鍒�** `GroupedQualityTable`锛堝涓�鍒椼�屽瓙椤广�嶏級 |
+
+### 21.2 褰掑睘鍒ゆ嵁涓庡悎骞惰鍒欙紙瀹炴祴寰楀嚭锛屼笉鏄帹鏂級
+
+**褰掑睘鍙湅 `parent_id`锛屼笉鐪� `item_type`锛屼篃涓嶇湅琛屽簭** 鈥斺�� 琛岃〃閲岀埗椤归偅涓�琛屼笌瀹冪殑瀛愰」
+**骞朵笉鐩搁偦**锛堝悓涓�浠藉崟閲岀埗椤瑰彲鑳芥帓鍦ㄤ竴缁勫瓙椤逛腑闂达級銆俙item_type = 2` 鍙敤鏉ュ垽鏂�
+銆岃繖涓寚鏍囧涓嶅鏍煎綋缁勫ご銆嶃��
+
+**鍚堝苟鍙e緞缁熶竴鎴愪竴鏉¤鍒�**锛�**缁勫唴绗竴琛岃儗 `span = 璇ョ粍鎬昏鏁癭锛屽悓缁勫叾浣欒涓�寰� `span = 1` + `hidden = hidden`銆�**
+杩欐牱澶氭牱鍝佺殑缁勫ご锛堜竴涓寚鏍囧琛岋級涔熻嚜鍔ㄨ惤鍦ㄨ鍒欓噷锛屼笉闇�瑕佺浜屽鍒嗘敮銆�
+
+钀藉湴鎵嬫鏄�**鐢辨暟鎹笅鍙戙�佷笉鍦ㄦ覆鏌撴湡璁$畻**锛氬悎骞跺睘鎬у啓鎴�
+`rowspan="{{item.group.span}}" hidden="{{item.group.hidden}}"`銆備箣鎵�浠ョ畻涓嶅嚭鏉� 鈥斺��
+缁戝畾寮曟搸鍦ㄦ暟缁勪笂浼氭寜鍏冪礌 pluck锛宍{{item.group.children.length}}` 鍙栦笉鍒板�笺��
+鍚岀悊锛�**姣忎竴椤归兘蹇呴』甯� `group`**锛堢嫭绔嬮」缁欑┖涓蹭笌 `1`锛夛細瀛楁缂哄腑鏃剁粦瀹氱殑灞炴�т細琚烦杩囷紝
+璇ラ殣钘忕殑鏍煎瓙鍙嶈�屼細闇插嚭鏉ャ��**娌℃湁鍒嗙粍鐨勬姤鍛婃暣浣撲笉甯� `group`**锛屽悎骞跺睘鎬т竴涓兘涓嶅嚭鐜般��
+
+### 21.3 鍒椾綅鏄祻瑙堝櫒閲忓嚭鏉ョ殑锛堟湰棰樺敮涓�鐨勭湡涓嶇‘瀹氱偣锛�
+
+銆岄殣钘忎竴鏍间細涓嶄細鎶婃暣琛屽墿浣欐牸瀛愬乏绉讳竴鍒椼�嶅湪 HTML 缁撴瀯灞傞潰楠屼笉鍑烘潵锛堝彧鑳芥暟 `td`锛夛紝
+鐪熸鐨勮〃鏍煎竷灞�鐢辨祻瑙堝櫒瀹氥�傛墍浠ョ敤**鐪熷疄娓叉煋浜х墿 + 鐪熷疄 Chromium**锛堝氨鏄湇鍔$ PDF 鐢ㄧ殑閭d釜锛�
+閫愭牸閲� `getBoundingClientRect().left`锛屾槧灏勫洖琛ㄥご鍒楋細
+
+- 琛ㄥご鍒楀乏杈圭晫锛歚0 / 133 / 343 / 601 / 1154 / 1326 / 1458`锛�
+- **缁勫ご琛� 鈫� 鍒� 1鈥�7**锛堝叏鍗狅級锛�
+- **瀛愰」琛� 鈫� 鍒� 1銆�3銆�4銆�5銆�6銆�7** 鈥斺�� 搴忓彿浠嶅湪鍒� 1锛�**鍒� 2 琚� `rowspan` 鍗犱綇鑰岃烦杩�**锛�
+ `瀛愰」` 钀藉垪 3銆乣瀹炴祴鍊糮 钀藉垪 5銆乣鍒ゅ畾` 钀藉垪 7銆�**娌℃湁宸︾Щ銆佹病鏈変覆浣嶃��**
+- 姣忎竴琛岀殑鍒楀彿搴忓垪閮芥弧瓒� `ascending: true, unique: true`銆�
+- 鎴浘瀛樿瘉锛歚mom-pro2-before/.qc-conformance/grouped-table-render.png`
+ 锛堝彲瑙� `姘村垎` 璺ㄤ綇 1鈥�3 琛岋紝`璇曟牱璐ㄩ噺 m` / `姘村垎缁撴灉 w` 骞舵帓鍦ㄣ�屽瓙椤广�嶅垪锛夈��
+
+> 鎴戝師鍏堢殑蹇冪畻鏄敊鐨勶細鎴戜互涓哄瓙椤硅鐨� 6 涓牸瀛愪細钀藉埌鍒� 2鈥�7銆傚疄娴嬫槸**鍒� 1 + 鍒� 3鈥�7**銆�
+> 缁撹锛堜笉閿欎綅锛変竴鑷达紝浣嗚繃绋嬫寜瀹炴祴鏇存锛屼笉鎸夊績绠楀啓杩涙枃妗c��
+
+### 21.4 缁勫ご鍦ㄦ湰鍗曟病鏈夎鏃讹細**琛ヤ竴琛�**锛屼笉鏄�屾寜鐙珛椤瑰鐞嗐��
+
+杩欐槸鏈疆鍞竴涓�澶勩�屾敼浜嗘棭鏈熻璁°�嶇殑鍦版柟銆傛棭鏈熸柟妗堝啓鐨勬槸锛氬垎缁勯」鍦ㄦ湰鍗曠殑妫�楠屾槑缁嗛噷娌℃湁鑷繁鐨勮
+鈬� 鍒や负銆岀粍涓嶆垚绔嬨�佹寜鐙珛椤瑰鐞嗐�嶃��**閭f牱浼氬師鏍峰鐜版湰娆¤淇殑 bug**锛堝叕寮忓張涓簡锛夈��
+瀹氱鏀逛负锛�**浠嶇劧涓哄畠琛ヤ竴琛�**鏉ユ樉绀虹粍鍚嶄笌鍏紡锛屽苟鍦ㄥ搷搴旂殑 `synthesizedGroupNames` 閲岃鏄庛��
+
+瀹炴祴纭杩欐潯璺緞鍙揪锛歚mes_qc_template_indicator` 鍐冲畾鏈崟鏈夊摢浜涜锛�
+**妫�楠屾ā鏉垮畬鍏ㄥ彲鑳藉彧鍕句簡瀛愰」銆佹病鍕剧埗椤�**銆�
+
+鍚屾椂鎶婅繖鏉� warning 涓庡彟涓�鏉�**鍒嗗紑**锛堟棭鏈熸槸鍚屼竴涓瓧娈碉紝娣峰湪涓�璧疯涓嶆竻锛夛細
+
+| 鎯呭喌 | 瀛楁 | 鎻愮ず璇箟 |
+|---|---|---|
+| 鍒嗙粍椤规湰鍗�**娌℃湁鑷繁鐨勮** 鈬� 鍚庣琛ヤ簡涓�琛� | `synthesizedGroupNames` | 銆屾姤鍛婇噷涓哄畠浠悇琛ヤ簡涓�琛屾潵鏄剧ず缁勫悕涓庡叕寮忋�� |
+| 鍒嗙粍椤规湰鍗�**娌℃湁灞炰簬瀹冪殑瀛愰」** 鈬� 鎸夌嫭绔嬮」鍒楀嚭銆佺粍鍚嶄笉鍚堝苟 | `childlessGroupNames` | 銆屾姤鍛婇噷鎸夌嫭绔嬫楠岄」鍒楀嚭銆佺粍鍚嶄笉鍚堝苟銆� |
+| 鎸囨爣宸茶鍒犻櫎鐨勬槑缁嗘潯鏁� | `missingIndicatorCount` | 銆屾湁 N 鏉℃槑缁嗙殑鎸囨爣宸茶鍒犻櫎锛屽凡璺宠繃銆� |
+
+**缁勫ご鐨勯敋鐐硅鎸夊畾涔夋病鏈夊疄娴嬪��**锛堝�煎湪瀛愰」涓婏級锛屾墍浠ュ畠**涓嶆姤**銆屽皻鏈綍鍏ュ疄娴嬪�笺�嶁�斺��
+涓嶇劧姣忎竴浠藉甫鍒嗙粍鐨勬姤鍛婇兘浼氳鎶ャ��
+
+### 21.5 鍒ゅ畾鍙e緞锛氥�屾棤鍒ゅ畾瑙勫垯銆嶆槸鍚堟硶鐘舵��
+
+鎸夌敤鎴锋媿鏉匡細**娌℃湁涓婁笅闄愪篃娌℃湁鍒ゅ畾瑙勫垯鐨勯」鏄剧ず銆屾棤鍒ゅ畾瑙勫垯銆嶏紝涓斾笉璁″叆鍚堟牸鐜囧垎姣嶄笌鎶ュ憡缁撹**
+锛堣繃绋嬪弬鏁板氨鏄繖涓�绫荤殑鍏稿瀷锛夈�傚疄娴嬭惤鍦版晥鏋滐細
+
+- `report.total = 4`銆乣passCount = 1`銆乣passRate = 100.00%`銆乣conclusion = 鍚堟牸`
+ 鈥斺�� 缁勫ご閿氱偣琛屼笌杩囩▼鍙傛暟**娌℃湁鎶婄粨璁哄帇涓嬪幓**锛�
+- 鍒ゅ畾鍒楃収鏍锋覆鏌撳嚭銆屾棤鍒ゅ畾瑙勫垯銆嶏紙涓嶈鍒嗙粍缁撴瀯鍚冩帀锛夛紝甯﹁鏍肩殑瀛愰」鐓у父鍒ゃ�屽悎鏍笺�嶃��
+
+`undecidableCount` 鐨勫彛寰勫樊涓�鐐规病鍐欐竻锛氬畠鏁扮殑鏄�**蹇収閲� `result` 涓虹┖涓茬殑椤�**锛�
+閲岄潰**娣风潃涓ょ鐘舵��** 鈥斺�� 銆屾棤鍒ゅ畾瑙勫垯銆嶏紙鍚堟硶锛変笌銆屽緟鍒ゅ畾銆嶏紙瑙勫垯鎵ц澶辫触锛屾槸鐪熼棶棰橈級銆�
+鎵�浠ュ墠绔�**涓嶈鎶婂畠褰撴晠闅滄姤璀�**锛堣 `docs/qc_report_generate_from_qc_frontend_integration.md`
+鐨勫睍绀鸿鍒欙細钃濊壊淇℃伅鏉¤�岄潪榛勮壊鍛婅锛屽洜涓哄嚑涔庢瘡涓�浠芥姤鍛婇兘浼氭湁杩囩▼鍙傛暟锛夈��
+
+### 21.6 鏀瑰姩娓呭崟
+
+**鍚庣 `yudao-module-mes`**
+- `MesQcIndicatorDO`锛氳ˉ鏄犲皠 `parentId` / `itemType` / `formulaText` / `unitText` / `sortOrder`
+ 锛�**鍙姞鏄犲皠锛屽垪鏈潵灏卞湪搴撻噷**锛屾湰杞病寤鸿〃銆佹病鏀� SQL锛夈��
+- 鏂板 `MesQcIndicatorItemTypeEnum`锛�1=褰曞叆椤癸紝2=鍒嗙粍椤癸級銆�
+- 鏂板 `api/qc/MesQcReportApiImpl` + API 鎺ュ彛锛氬洓灞傚彇鏁板綊涓�鍚�**鎸� `parent_id` 杩樺師涓ゅ眰**锛�
+ 缁勫ご鐨勯敋鐐硅銆佸瓙椤硅鍒嗗埆浜у嚭琛岋紱琛ラ綈銆屾病鎴愮粍 / 琛ュ嚭鏉ョ殑琛� / 鎸囨爣宸插垹銆嶄笁绫� warning銆�
+
+**鍚庣 `yudao-module-qcreport`**
+- `ReportContext`锛氭柊澧� `group`锛坄childName` / `span` / `hidden`锛夛紝**鏉′欢甯﹀嚭**锛堟棤鍒嗙粍灏变笉缁欙級銆�
+- `ReportContextCodec`锛�**鎵嬪啓** Map鈫斿璞¤浆鎹㈤噷琛� `group`锛堜笉鐢� Jackson 鍙嶅皠锛�
+ 婕忎簡杩欎竴姝ュ喕缁撳揩鐓у氨浼氫涪鍒嗙粍锛夈��
+- `InspectionItem`锛氭柊澧� `requirement` 涓庡祵濂� `Group`锛�**`copy()` 涓�骞跺甫鍑�**
+ 锛坄ReportEvaluator` 浼氳皟 `copy()`锛夈��
+- `MesQcReportContextMapper`锛氬垎缁勬椂閫愰」涓嬪彂 `group`銆佺粍澶翠笉鎶ユ紡褰曞疄娴嬪�笺�佷笁鏉� warning 鏂囨銆�
+- `QcReportInstanceServiceImpl`锛歚undecidableCount` 鍙e緞涓� `1_070_105_006` 鏂囨銆�
+
+**鍓嶇 `mom-pro2-before`**
+- 鏂板绗� 13 涓粍浠� `inspection/grouped-quality-table.ts`锛�7 鍒楋級銆�
+- `engine/context.ts`锛氭柊澧� `ReportContextItemGroup` 涓� `item.group?`銆�
+- `engine/render.ts` 鏈敼锛坄rowspan` / `hidden` 璧扮粦瀹氬睘鎬ц繖鏉¤矾锛屾覆鏌撴湡涓嶅弬涓庤绠楋級銆�
+
+### 21.7 楠岃瘉锛堝凡鍋� / 鏈仛鍒嗗紑澹版槑锛�
+
+**宸插仛锛堢‘瀹氭�э級**
+
+- **鍚庣 `mvn -o -pl yudao-module-qcreport -am test`锛歚Tests run: 141, Failures: 0, Errors: 0` 鍏ㄧ豢**
+ 锛埪�19/搂20 璁板綍涓� 137锛涙湰杞柊澧� 4 鏉″叏鍦� `MesQcReportContextMapperTest`锛岃绫诲叡 15 椤癸細
+ `mapsGroupStructure` / `groupAnchorDoesNotWarnAboutMissingActualValue` /
+ `noGroupingLeavesGroupNull` / `warnsOnSkippedRows`锛夈��
+ 鈿� **蹇呴』甯� `-am`**锛氫笉甯︿細鎷垮埌鏈湴浠撳簱閲屾棫鐨� `mes-api` jar锛屾姤
+ `NoSuchMethodError 鈥� getGroupChildName()`銆�
+- `mvn -o compile -pl yudao-module-mes -am -q` 骞插噣銆�
+- **鍓嶇瀵规媿 `npx tsx .qc-conformance/assemble-ts.ts`**锛氬叏缁匡紝缁勪欢鏁版柇瑷�鐢� 12 鏀逛负 **13**銆�
+- **鏂板鏂█鎺㈤拡 `.qc-conformance/verify-grouped-table.ts`**锛堢豢锛夛細涓夎妭 鈥斺��
+ 鈶� 鎵撳湪**鐪熷疄 `buildContent` 浜х墿**涓婏細琛ㄥご/琛屾ā鏉垮悇 7 鏍笺�乣rowspan` **鍙寕鍦ㄤ竴鏍间笂**
+ 锛堟寕閿欐牸 = 缁勫悕璺ㄩ敊鍒楋級銆侀噸澶嶆爣璁拌惤鍦� `tbody/tr`锛涒憽 缁勫ご + 瀛愰」 + 鐙珛椤规贩鎺掔殑閫愭牸鏂█锛�
+ 鈶� **闄嶇骇**锛氭暣浠芥暟鎹兘娌℃湁 `group` 鏃堕��鍖栨垚鏅�氳〃鑰屼笉鏄鎺夛紙鏃� `rowspan`/`hidden`銆�
+ 琛屼粛鍗犳弧 7 鍒椼�佸唴瀹圭収甯告覆鏌擄級锛屼笖缂哄彛浠� `item.group.span` 杩� `errors` 鏆撮湶銆�**涓嶉潤榛�**銆�
+- **娴忚鍣ㄥ疄娴�**瑙� 搂21.3锛堝垪浣嶃�佹埅鍥撅級銆�
+
+**鏈仛 / 涓嶄富寮�**
+
+- **`FrontendConformanceTest` 娌℃湁鍔犲垎缁勭敤渚�**锛氬墠鍚庣閫愬瓧瀵规媿閽夌殑鏄�屾覆鏌撲骇鐗╀竴瀛椾笉宸�嶏紝
+ 鑰屽垎缁勮繖涓�棰樼殑鍏抽敭鏄�**娴忚鍣ㄨ〃鏍煎竷灞�**锛宍rowspan` 涓� `hidden` 鐨勮В鏋愮粨鏋�**涓嶆槸瀛楅潰閲忚兘閽変綇鐨�**銆�
+ 閽夊瓧闈㈤噺鍙兘璇佹槑銆屼袱杈归兘璺宠繃/閮借緭鍑哄悓涓�涓睘鎬с�嶏紝璇佹槑涓嶄簡鍒楁病涓蹭綅銆傛湁鏁堢殑璇佹嵁鏄笂闈㈢殑
+ 鎺㈤拡 + 鐪熷疄娴忚鍣ㄩ�愭牸娴嬮噺锛屾晠鏈疆**涓嶅仛**杩欐潯瀵规媿锛�**濡傚疄澹版槑涓烘湭鍋�**銆�
+- **娌℃湁璧扮湡瀹� HTTP 鑱旇皟**锛堢湡瀹� MES 鏁版嵁 + 閲嶅惎鍚庣 + UI 楠屾敹锛夛細鏈疆楠岃瘉鍏ㄩ儴鍦�
+ 鍗曞厓/瀵规媿/鎺㈤拡灞傚畬鎴愩��**杩欎竴鏉℃槸銆屾病鍋氥�嶏紝涓嶆槸銆岄�氳繃銆嶃��**
+- **`GroupedQualityTable` 鐨� AI 閫夊瀷鍑嗙‘鐜囨湭娴�**锛氫笂涓�杞殑瀹炴祴閮芥槸閽堝
+ `ReportHeader` / `ReportFooter` 鐨勯�夊瀷锛�**娌℃湁瑙傚療杩囨ā鍨嬩細涓嶄細姝g‘鎸戜腑杩欑 13 涓粍浠�**銆�
+ 妯″瀷閫夊瀷鍙兘闈犵湡瀹炶皟鐢ㄨ瀵燂紝涓嶄吉閫犵‘瀹氭�с��
+
+### 21.8 鏈疆椤哄甫鍙戠幇锛�**鏈慨**锛屼氦鐢ㄦ埛鍒ゆ柇锛�
+
+- **`docs/sql/config_export_all_20260918.sql` 宸蹭笌杩愯搴撴紓绉�**锛堝疄娴嬫瘮瀵� information_schema 涓�
+ 瀵煎嚭鏂囦欢鐨� `CREATE TABLE` 鍒楅泦鍚堬級锛�
+
+ | 椤� | 鏁伴噺 |
+ |---|---|
+ | 杩愯搴撴湁銆佸鍑洪噷**娌℃湁鐨勮〃** | 3锛坄after_sale_problem` / `after_sale_visit` / `bpm_process_auto_approve_config`锛� |
+ | 杩愯搴撴湁銆佸鍑洪噷**娌℃湁鐨勫垪** | **86** |
+ | 瀵煎嚭閲屾湁銆佽繍琛屽簱**娌℃湁鐨勮〃** | 6锛坄bpm_bak_20260904_*` 澶囦唤琛ㄥ凡涓嶅瓨鍦級 |
+
+ 鍏朵腑灞炴湰杞浉鍏崇殑鍙湁 `mes_qc_indicator` 鐨� 5 鍒楋紙`parent_id` / `item_type` / `formula_text` /
+ `unit_text` / `sort_order`锛夛紱**鍏朵綑 80 浣欏垪鏉ヨ嚜鏇存棭鐨勮疆娆�**
+ 锛堝敭鍚庨棶棰樺簱銆丅PM 鍏嶅鎵瑰紑鍏炽�両QC/IPQC/OQC/RQC 鐨勫鏍镐笌鎵ц鏍囧噯瀛楁绛夛級銆�
+ 鎸� `sql-config-export-init.md`锛屾柊搴撳垵濮嬪寲浼�**缂鸿繖浜涘垪**銆�**鏈疆鏈姩璇ユ枃浠�**锛�
+ 琛ュ叏瀹冪瓑浜庢妸鍏朵粬杞鐨勬紓绉讳竴骞跺揩鐓ц繘鏉ワ紝灞炰簬瑕佸崟鐙媿鏉跨殑鎿嶄綔锛屼笉澶瑰甫鍦ㄦ湰杞噷銆�
+- **鎸囨爣涓绘暟鎹紙`mes_qc_indicator`锛夌殑灞傜骇瀛楁娌℃湁 CRUD 鐣岄潰**锛�
+ `SaveReqVO` / `RespVO` 閲屾病鏈� `parent_id` / `item_type` / `formula_text` /
+ `unit_text` / `sort_order` 鐨勬槧灏勶紝**鐜板湪鍙兘闈� SQL 閫犲垎缁勬暟鎹�**銆�
+ 鏈疆鍙仛浜嗐�岃鍑烘潵娓叉煋鎴愭姤鍛娿�嶏紝**娌℃湁鍋氥�岀紪杈戝垎缁勩��**銆�
+
+### 21.9 娴嬭瘯鏁版嵁娓呯悊
+
+鏈疆**鏈笂浼犳枃浠躲�佹湭寤烘ā鏉裤�佹湭鐢熸垚鎶ュ憡瀹炰緥**锛屼笉浜х敓 `blob` / 闄勪欢 / 妯℃澘鐗堟湰锛�
+`docs/` 涓嬬殑鏀瑰姩涓烘枃妗o紝`mom-pro2-before/.qc-conformance/` 涓嬬殑浜х墿涓烘帰閽堣緭鍑�
+锛坄.html` / `.png`锛屼笉鍏ュ簱锛夈�傜敤鎴疯嚜宸变笂浼犵殑 `鐧句簨妯$増.docx`锛坆lob 67/70銆侀檮浠� 73/74锛�**鍏ㄧ▼鏈姩**銆�
+
+## 浜屽崄浜屻�佽川妫�鎸囨爣灞傜骇鍙淮鎶わ細鍒嗙粍鏁版嵁浠庛�屽彧鑳� SQL 閫犮�嶅埌銆岀晫闈㈣兘缂栬緫銆嶏紙2026-09-19 缁級
+
+> 鎵挎帴 搂21.8 鐨勭浜屾潯鍙戠幇锛氥�屾寚鏍囦富鏁版嵁鐨勫眰绾у瓧娈垫病鏈� CRUD 鐣岄潰锛岀幇鍦ㄥ彧鑳介潬 SQL 閫犲垎缁勬暟鎹�嶃��
+
+### 22.1 瑕佽ˉ鐨勬槸銆屽啓銆嶏紝涓嶆槸銆岃銆�
+
+搂21 鍙仛浜嗐��**璇�**銆嶏細鎶ュ憡渚у凡鑳芥寜 `mes_qc_indicator.parent_id` 鎶婂垎缁勯」涓庡畠鐨勫瓙椤硅繕鍘熸垚涓ゅ眰琛ㄥご銆�
+浣嗐��**鍐�**銆嶆槸缂虹殑 鈥斺�� `MesQcIndicatorSaveReqVO` / `RespVO` 瀹屽叏娌℃湁灞傜骇瀛楁鏄犲皠锛�
+`mes_qc_indicator` 鐨� `parent_id` / `item_type` / `formula_text` / `sort_order` / `unit_text`
+浜斿垪**鍦ㄤ笟鍔$晫闈笂鏃犲鍙~**銆�
+
+鍚庢灉锛氱幇缃戦偅 3 涓垎缁勶紙`姘村垎` / `閰稿惈閲廯 / `姝d竵閱囧惈閲廯锛夊彧鑳介潬 SQL 閫狅紱
+杩愮淮鎯冲姞涓�涓垎缁勩�佹妸鏌愪釜鎸囨爣鎸傝繘鍒嗙粍銆佽皟鏁村垎缁勯『搴忥紝鍏ㄩ兘寰楄繘鏁版嵁搴撱��
+
+**鎶ュ憡渚т竴琛屾湭鏀�**锛氬凡鏈夌殑鍒嗙粍杩樺師閫昏緫鎸� `parent_id` 鍙栨暟锛�
+鐣岄潰閫犲嚭鏉ョ殑鍒嗙粍涓� SQL 閫犲嚭鏉ョ殑鍒嗙粍鍦ㄦ姤鍛婇噷瀹屽叏鍚屽舰銆�
+
+### 22.2 鐢ㄦ埛鎷嶆澘鐨勫洓鏉″彛寰�
+
+| 宀旇矾 | 鎷嶆澘 |
+|---|---|
+| 瀛楁鑼冨洿 | **鍙姞灞傜骇鍥涢」**锛堟潯鐩被鍨� / 鎵�灞炲垎缁� / 鍏紡 / 鎺掑簭鍙凤級銆俙unit_text` **涓嶈繘鐣岄潰** |
+| 鍒犻櫎鏈夊瓙椤圭殑鍒嗙粍 | **绾ц仈鍒犻櫎瀛愰」** |
+| 鍒楄〃鍛堢幇 | **骞抽摵琛ㄦ牸 + 涓ゅ垪**锛堟潯鐩被鍨� / 鎵�灞炲垎缁勶級锛屼笉鏀� vxe 鏍戣〃鏍� |
+| 灞傜骇娣卞害 | **鍙厑璁镐袱灞�** |
+
+`unit_text` 涓嶈繘鐨勪緷鎹紙瀹炴祴锛岄潪鎺ㄦ柇锛夛細鍏ㄦā鍧� grep 璇ュ垪鍙嚭鐜板湪 `MesQcIndicatorDO.java` 涓�澶勫0鏄庯紝
+**娌℃湁浠讳綍璇诲彇鏂�**銆傛姤鍛婄殑銆屽崟浣嶃�嶅彇鑷楠屾柟妗堣鐨� `unit_measure_id` 鈫� `mes_md_unit_measure.name`锛�
+鍥炶惤鎵嶆槸鎸囨爣鑷甫鍗曚綅銆傜晫闈㈡斁涓�涓病浜鸿鐨勫瓧娈靛彧浼氳瀵煎綍鍏ヤ汉銆�
+
+### 22.3 鏁版嵁瀹炶瘉锛堝鍣� `mysql8` / `ruoyi-vue-pro`锛宍deleted=0`锛�
+
+34 琛屾湁鏁堟暟鎹細31 鏉″綍鍏ラ」 + 3 鏉″垎缁勯」锛�**灞傜骇鍒椾竴鏉� NULL 閮芥病鏈�**銆�
+
+| 鍒� | 鍒嗙粍椤癸紙`item_type=2`锛�3 琛岋級 | 褰曞叆椤癸紙`item_type=1`锛�31 琛岋級 |
+|---|---|---|
+| `parent_id` | 3 鏉″叏涓� `0` | 9 鏉′负鍒嗙粍 id锛�22 鏉′负 `0` |
+| `result_type` | **鍏ㄤ负 NULL** | 鍏ㄦ湁鍊硷紙1=FLOAT锛� |
+| `formula_text` | 鍏ㄦ湁鍏紡锛堝 `w = (m1 - m0) / m 脳 100%`锛� | 鍏ㄤ负 NULL |
+| `unit_text` | 鍏ㄤ负 NULL | 鏈夊�硷紙`g` / `%` / `mol/L` / `mL`锛� |
+| `sort_order` | 椤剁骇 30 / 40 / 50 | 椤剁骇 10..70锛屽瓙椤� 1..4 |
+
+涓ゆ潯鐢辨鎺ㄥ嚭鐨勭‖鍙e緞锛�
+
+1. **鍒嗙粍椤圭殑 `result_type` 涓� NULL** 鈬� `SaveReqVO` 涓� `resultType` 鐨� `@NotNull` 蹇呴』鎷挎帀锛�
+ 鏀规垚銆屼粎褰曞叆椤瑰繀濉�嶇殑鏈嶅姟绔潯浠舵牎楠岋紱钀藉簱鏃跺垎缁勯」寮哄埗娓呯┖ `resultType` / `resultSpecification`銆�
+2. **`sort_order` 鏄� `NOT NULL DEFAULT 0`**锛屼絾娌℃湁銆屽悓绾ф闀裤�嶇害鏉燂紙椤剁骇姝ラ暱 10锛屽瓙椤规闀� 1锛�
+ 鈬� 鏂拌褰曠暀绌烘椂鐢辨湇鍔$鎸変笅鍙戦粯璁ゅ�艰ˉ榻愩��
+
+灞傜骇鍒椾笌绱㈠紩 `idx_qc_indicator_parent_id` **鐜扮綉宸插瓨鍦�**锛堝彟涓�寮�鍙戣�呯殑
+`feat(mes): 鏂板璐ㄦ鎸囨爣鍒嗙粍鏍戝拰骞宠娴嬮噺鍔熻兘` 甯﹁繘鏉ョ殑锛夆噿 **鏈疆鏃犺〃缁撴瀯鍙樻洿锛�
+涓嶅姩 `docs/sql/config_export_all_*.sql`銆�**
+
+### 22.4 鍏潯灞傜骇鏍¢獙瑙勫垯锛堟寜涓氬姟浼樺厛绾у彧鎶涚涓�澶勶級
+
+| 椤哄簭 | 鏉′欢 | 閿欒鐮� |
+|---|---|---|
+| 1 | 鍒嗙粍椤瑰嵈甯� `parentId != 0` | `1040601007` `QC_INDICATOR_GROUP_CANNOT_NEST` |
+| 2 | `parentId == id` | `1040601006` `QC_INDICATOR_PARENT_SELF` |
+| 3 | 鐖舵寚鏍囦笉瀛樺湪 | `1040601004` `QC_INDICATOR_PARENT_NOT_EXISTS` |
+| 4 | 鐖舵寚鏍囦笉鏄垎缁勯」 | `1040601005` `QC_INDICATOR_PARENT_NOT_GROUP` |
+| 5 | 褰曞叆椤硅�� `resultType` 涓虹┖ | `1040601009` `QC_INDICATOR_RESULT_TYPE_REQUIRED` |
+| 6 | 鏀规寕鍒嗙粍 / 鏀规垚褰曞叆椤癸紝浣嗚鎸囨爣宸叉湁瀛愰」 | `1040601008` `QC_INDICATOR_HAS_CHILDREN`锛堜袱绉嶅満鏅�**鏂囨鍚勮嚜鐙珛**锛� |
+
+**銆屽彧鍏佽涓ゅ眰銆嶆病鏈夊崟鐙啓涓�鏉℃牎楠�** 鈥斺�� 瀹冪敱瑙勫垯 1 + 瑙勫垯 4 鑷姩鎺ㄥ嚭锛氱埗蹇呴』鏄垎缁勯」锛�
+鑰屽垎缁勯」鍙兘椤剁骇锛屾墍浠ョ涓夊眰涓嶅彲鏋勯�犮��**涓嶅啓涓�鏉″彲杈炬�т负鍋囩殑鏍¢獙銆�**
+
+鎶涢敊涓�寰嬪甫鍏蜂綋鍊硷紙鍒嗙粍鍚� / 鐖舵寚鏍囧悕 / 瀛愰」鏉℃暟锛変笌鍙墽琛屽姩浣滐紝
+閬靛畧 `error-message-precision.md`锛屼笉鍐欐垚绗肩粺鍙ャ��
+
+### 22.5 淇帀涓�涓湡瀹炵殑鍐欏叆缂洪櫡锛堝崟娴嬫姄鍑烘潵鐨勶紝涓嶆槸娴嬭瘯鍋囪薄锛�
+
+`testUpdateIndicator_toGroup_clearsResultFields` 鏂█澶辫触锛歚expected: <null> but was: <5>`銆�
+
+鏍瑰洜锛歁yBatis-Plus 鐨� `updateById` 榛樿鐢� `FieldStrategy.NOT_NULL`锛�**浼氭妸 `null` 瀛楁浠� UPDATE
+璇彞閲屽墧闄�**銆傛墍浠ャ�屽綍鍏ラ」鏀规垚鍒嗙粍椤广�嶆椂锛宍normalizeHierarchy` 铏界劧鎶� `resultType` 缃簡 `null`锛�
+**杩欎釜 null 鏍规湰娌″啓杩涘簱**锛屾棫鐨勭粨鏋滃�� `5` 娈嬬暀涓嬫潵銆�
+
+杩欐槸**鐢熶骇缂洪櫡**锛屼笉鏄祴璇曞啓娉曢棶棰橈細鏀规垚鍒嗙粍椤瑰悗缁撴灉鍊间細闈欓粯鐣欑潃銆�
+淇硶鏄� DO 绾у0鏄庡紡锛�
+
+```java
+@TableField(updateStrategy = FieldStrategy.ALWAYS)
+private Integer resultType;
+
+@TableField(updateStrategy = FieldStrategy.ALWAYS)
+private String resultSpecification;
+```
+
+閫夎繖鏉¤�屼笉鏄樉寮� `LambdaUpdateWrapper` 鐨勭悊鐢憋細浠撳簱鏈夌幇鎴愬厛渚�
+锛坄DictDataDO.java:60`銆乣CrmContractConfigDO.java`銆乣CrmCustomerPoolConfigDO.java`锛夛紝
+涓旇 DO 鍙敱 `MesQcIndicatorServiceImpl` 鍐欏叆锛屽姞娉ㄨВ鐨勭垎鐐稿崐寰勫彲鎺с��
+
+**杩欐浠峰�煎湪浜庯細鍗曟祴閽変綇浜� `updateById` 鐨� null 鍓旈櫎琛屼负锛岃�岃繖鍦ㄧ函璇讳唬鐮佹椂涓嶄細鏆撮湶銆�**
+
+椤哄甫淇殑鍙︿竴澶勶細`validateResultSpecification` 鍘熸湰鏄袱鍙傦紝琚户鎵跨殑浠g爜鐢ㄤ笁鍙傝皟鐢紙缂栬瘧涓嶈繃锛夈��
+鏀逛负鎸夋潯鐩被鍨嬫彁鍓嶈繑鍥� 鈥斺�� **鍒嗙粍椤圭殑缁撴灉鍊艰惤搴撳墠浼氳娓呯┖锛屾墍浠ヤ笉璇ヨ銆岀粨鏋滃�煎睘鎬т笉鑳戒负绌恒�嶆嫤浣�**銆�
+
+### 22.6 鏀瑰姩娓呭崟
+
+**鍚庣 `yudao-module-mes`锛堟敼锛�**
+- `MesQcIndicatorDO`锛氬姞甯搁噺 `PARENT_ID_ROOT = 0L`锛沗resultType` / `resultSpecification`
+ 鍔� `@TableField(updateStrategy = FieldStrategy.ALWAYS)`锛堣 搂22.5锛夈��
+- `MesQcIndicatorSaveReqVO`锛氬姞 `itemType` / `parentId` / `formulaText` / `sortOrder`锛�
+ `resultType` 鍘绘帀 `@NotNull`銆�
+- `MesQcIndicatorRespVO`锛氬姞 `parentId` / `itemType` / `formulaText` / `sortOrder` / `parentName`锛�
+ `@ExcelProperty` 鍙墦 `鎵�灞炲垎缁刞 / `鍏紡` / `鎺掑簭鍙穈 涓夊锛坄itemType` 涓嶆墦娉ㄨВ锛�
+ 绫讳笂宸叉湁 `@ExcelIgnoreUnannotated` 鈬� 涓嶈繘 Excel锛夈��
+- `MesQcIndicatorPageReqVO`锛氬姞 `itemType`銆�
+- `MesQcIndicatorMapper`锛氬姞 `selectListByItemType` / `selectListByParentId` /
+ `selectCountByParentId` / `selectMaxSortOrder`锛沗selectPage` 杩藉姞 `eqIfPresent(itemType)`銆�
+- `MesQcIndicatorService` / `Impl`锛氬姞 `getIndicatorGroupList()`锛涙柊澧� `validateHierarchy` /
+ `normalizeHierarchy`锛沗deleteIndicator` 鏀圭骇鑱斿垹瀛愰」锛沗validateResultSpecification` 鏀逛笁鍙傘��
+- `MesQcIndicatorController`锛歚/page` 涓� `/export-excel` 鐢ㄧ鏈� `fillParentName` 鍥炲~
+ `parentName`锛涙柊澧� `GET /group-list`銆�
+- `ErrorCodeConstants`锛歚_004` ~ `_009` 鍏潯鏂伴敊璇爜銆�
+
+**鍚庣锛堟祴璇曪級**
+- 鏂板 `MesQcIndicatorServiceImplTest`锛�**14 渚�**锛宍BaseDbUnitTest` 椋庢牸锛孒2 + 鐪熷疄 Mapper锛夈��
+- `src/test/resources/sql/create_tables.sql` 琛� `CREATE TABLE IF NOT EXISTS "mes_qc_indicator"`
+ 锛�**绾拷鍔� 26 琛岋紝0 鍒犻櫎**锛夛紱`clean.sql` 琛� `DELETE FROM "mes_qc_indicator";`銆�
+
+**鍓嶇 `mom-pro2-before`锛堟敼锛�**
+- `packages/constants/src/biz-mes-enum.ts`锛氬姞 `MesQcIndicatorItemType = { ENTRY: 1, GROUP: 2 }`銆�
+ **涓嶅仛瀛楀吀** 鈥斺�� 1/2 涓や釜鍊煎湪鍚庣鏋氫妇涓庢姤鍛婅繕鍘熼�昏緫閲岄兘鏄‖缂栫爜锛屽仛鎴愬彲鏀瑰�煎瓧鍏镐細涓庝唬鐮佽劚鑺傦紱
+ 鍚岄〉鍚岃〃鐨� `MesQcResultValueType` 灏辨槸璧扮殑甯搁噺璺��**鏈疆涓嶄骇鐢熶换浣� DB / 閰嶇疆鍙樻洿銆�**
+- `api/mes/qc/indicator/index.ts`锛歚Indicator` 鎺ュ彛鍔� 5 涓瓧娈碉紱鍔� `getIndicatorGroupList()`銆�
+- `views/mes/qc/indicator/data.ts`锛氳〃鍗曞姞 鏉$洰绫诲瀷锛圧adioGroup锛�/ 鎵�灞炲垎缁勶紙`ApiTreeSelect`锛�/
+ 鍏紡锛圱extarea锛屼粎鍒嗙粍椤癸級/ 鎺掑簭鍙凤紙InputNumber锛夛紱鎼滅储琛ㄥ崟鍔犮�屾潯鐩被鍨嬨�嶏紱
+ 鍒楄〃鍒楀姞銆屾潯鐩被鍨嬨�嶏紙slot Tag锛変笌銆屾墍灞炲垎缁勩�嶏紙`parentName`锛岄《绾ф樉绀� `-`锛夈��
+- `views/mes/qc/indicator/index.vue`锛氬姞 `#itemType` / `#parentName` 涓や釜鎻掓Ы銆�
+
+**娌℃湁鏂板鑿滃崟涓庢潈闄愮爜**锛歚/group-list` 澶嶇敤鏃㈡湁鐨� `mes:qc-indicator:query`銆�
+
+### 22.7 鍓嶇涓ゅ銆屽繀椤昏繖涔堝啓銆嶇殑缁嗚妭
+
+1. **鍒囨崲鏉$洰绫诲瀷鏃朵富鍔ㄦ竻绌哄綍鍏ラ」涓撳睘瀛楁**锛歚itemType` 鐨� `dependencies.trigger` 閲屾妸
+ `parentId` 缃� `0`銆乣resultType` / `resultSpecification` 缃� `undefined`銆�
+ **涓轰粈涔堝繀椤绘竻**锛歷ben 鐨� `dependencies.if` 鏄�屽垹闄� DOM銆嶈涔夛紝琚Щ闄ょ殑瀛楁锛�
+ 鍏跺��**浠嶇暀鍦ㄨ〃鍗曟暟鎹噷**锛屼細涓�璧锋彁浜わ紱娈嬬暀鐨� `parentId` 浼氳鍚庣灞傜骇鏍¢獙椤跺洖鏉ャ��
+2. **`resultType` 鐨勫繀濉粠闈欐�� `rules: 'required'` 鏀逛负鎸夋潯鐩被鍨嬫潯浠跺垽鏂�**锛�
+ 鍒嗙粍椤瑰湪琛ㄥ崟涓婁笉灞曠ず璇ュ瓧娈碉紙`dependencies.if`锛夛紝涔熶笉鍙備笌鏍¢獙锛�
+ 鏈嶅姟绔悓鏍锋寜鏉$洰绫诲瀷鏉′欢鏍¢獙锛堣 搂22.4 瑙勫垯 5锛夈��
+
+### 22.8 楠岃瘉锛堝凡鍋� / 鏈仛鍒嗗紑澹版槑锛�
+
+**宸插仛锛堢‘瀹氭�э級**
+
+- `mvn compile -pl yudao-module-mes -am -q` 鈫� 骞插噣閫�鍑恒��
+- `mvn -o -pl yudao-module-mes test -Dtest=MesQcIndicatorServiceImplTest` 鈫�
+ **`Tests run: 14, Failures: 0, Errors: 0`锛孊UILD SUCCESS**銆�
+ 鐢ㄤ緥閫愭潯瑕嗙洊 搂22.4 鐨勮鍒欙細寤哄垎缁勬垚鍔燂紙缁撴灉鍊艰娓呯┖銆乣sortOrder` 鑷姩琛� 10锛�/
+ 寤哄瓙椤规垚鍔燂紙`sortOrder` = 鍚岀骇 max+1锛�/ 椤剁骇姝ラ暱 10 / 鍒嗙粍甯� `parentId` 琚嫆 /
+ 鐖朵笉鏄垎缁勯」琚嫆 / 鐖朵笉瀛樺湪琚嫆 / 鐖舵槸鑷繁琚嫆 / 褰曞叆椤圭己缁撴灉鍊艰鎷� /
+ 缁撴灉鍊煎睘鎬х己澶辫鎷� / 鍒嗙粍椤逛笉鍙祵濂� / 鏀规垚鍒嗙粍椤规竻缁撴灉鍊� / 鏈夊瓙椤逛笉鑳芥敼鎸傚垎缁� /
+ 鏈夊瓙椤逛笉鑳芥敼鎴愬綍鍏ラ」 / 绾ц仈鍒犻櫎 / 鎸囨爣涓嶅瓨鍦ㄣ��
+- 鍓嶇 `pnpm typecheck`锛�**鏈疆鏀瑰姩鐨勬枃浠� 0 鎶ラ敊**
+ 锛坄wls/*` 绛夋棦鏈夋姤閿欎笉鍦ㄦ湰杞寖鍥达級銆�
+
+**宸插仛锛堢湡瀹� HTTP + UI 楠屾敹锛�2026-09-19 鐢ㄦ埛閲嶅惎鍚庣鍚庯級**
+
+閲嶅惎鍓嶅厛鏍稿疄浜嗐�岃窇鐨勬槸涓嶆槸鏂扮被銆嶏細`/group-list` 褰撴椂杩斿洖 404銆乣/page` 鐨勪簲涓柊瀛楁鍏� `null`锛�
+鑰屾潈濞佸簱锛坄@@hostname=2a8dea946ada`锛夎繖浜涘垪**涓�鏉� NULL 閮芥病鏈�** 鈬� 鍒や负銆岄儴鍒嗘棫銆侀儴鍒嗘柊銆嶇殑
+娣峰悎 classpath锛岃鐢ㄦ埛閲嶅惎銆傞噸鍚悗 `/group-list` 杩斿洖 3 涓垎缁勶紝楠屾敹闅忓嵆璺戦�氥��
+
+**HTTP 楠屾敹锛�14 椤癸紝鍏ㄨ繃锛�**
+
+| # | 鐢ㄤ緥 | 缁撴灉 |
+|---|---|---|
+| 1 | `/page?itemType=2` 杩囨护 | `total=3`锛屽彧杩斿洖鍒嗙粍椤� |
+| 2 | 瀛愰」 `parentName` 鍥炲~ | 瀛愰」 22/23/24 鐨� `parentName` = `姘村垎`锛�**鐖舵寚鏍囦笉鍦ㄥ悓涓�娆$瓫閫夌粨鏋滈噷涔熻兘瑙f瀽**锛� |
+| 3 | 寤哄垎缁勶紙甯� `resultType=1`銆乣sortOrder` 鐣欑┖锛� | 鎴愬姛锛涜惤搴� `result_type=NULL`锛堣娓呯┖锛夈�乣sort_order=80`锛堝悓绾� max 70 + 10锛� |
+| 4 | 寤洪《绾у綍鍏ラ」锛坄sortOrder` 鐣欑┖锛� | 鎴愬姛锛沗sort_order=90`锛坢ax 80 + 10锛� |
+| 5 | 璐熷悜锛氬垎缁勯」甯� `parentId` | `1040601007`锛屾枃妗堝惈`[ZZ闈炴硶宓屽鍒嗙粍]`+`[姘村垎]`+鏀规硶 |
+| 6 | 璐熷悜锛氱埗鏄綍鍏ラ」锛坕d=1 閰稿�硷級 | `1040601005`锛屾枃妗堝惈鐖跺悕 + 鍏舵潯鐩被鍨嬩腑鏂囧悕 + 鏀规硶 |
+| 7 | 璐熷悜锛氱埗鏄嚜宸� | `1040601006`銆岀埗鎸囨爣涓嶈兘鏄嚜宸便�� |
+| 8 | 璐熷悜锛氬綍鍏ラ」缂虹粨鏋滃�肩被鍨� | `1040601009` |
+| 9 | 璐熷悜锛氱埗鎸囨爣涓嶅瓨鍦紙`parentId=999999`锛� | `1040601004`锛屾枃妗堝惈缂栧彿 999999 + 鏀规硶 |
+| 10 | 鎸傚瓙椤癸紙`sortOrder` 鐣欑┖锛� | 鎴愬姛锛沗sort_order=1`锛�**鍚岀骇姝ラ暱 1**锛屼笌椤剁骇鐨� 10 鍖哄垎寮�锛� |
+| 11 | 璐熷悜锛氭湁瀛愰」涓嶈兘鏀规垚褰曞叆椤� | `1040601008`锛屾枃妗堝惈瀛愰」鏉℃暟 + 銆岃鍏堝垹闄ゆ垨绉昏蛋杩� 1 涓瓙椤广�� |
+| 12 | 鏀规寕鍒扮幇缃戝垎缁� 21銆屾按鍒嗐�� | 鎴愬姛锛屽洖璇� `parent_id=21` |
+| 13 | 鍒犲垎缁勶紙甯� 2 涓瓙椤癸級 | 鎴愬姛锛�**鍥炶鍒嗙粍涓庡叾 2 涓瓙椤� `deleted` 鍏ㄩ儴缈讳负 1**锛堢骇鑱旓級 |
+| 14 | 瀵煎嚭 Excel | HTTP 200 / 6 350 瀛楄妭锛涜В鍖� `sheet1.xml` 璇昏〃澶� = `缂栧彿锝滄娴嬮」缂栫爜锝滄娴嬮」鍚嶇О锝滄娴嬮」绫诲瀷锝滄娴嬪伐鍏凤綔鎵�灞炲垎缁勶綔鍏紡锝滄帓搴忓彿锝滅粨鏋滃�肩被鍨嬶綔缁撴灉鍊煎睘鎬э綔澶囨敞锝滃垱寤烘椂闂碻 鈥斺�� **涓夊垪鏂板閮藉湪銆乣鏉$洰绫诲瀷` 纭疄涓嶅湪** |
+
+**鈿� 涓�鏉″彛寰勯渶瑕佽娓咃紙鐢ㄤ緥 11 鐨勬梺鏀級**锛氳鍒� 6 鐨�**绗竴涓垎鏀�**锛堛�屾湁瀛愰」鏃朵笉鑳芥寕鍒板埆鐨勫垎缁勪笅銆嶏級
+**缁忕晫闈�/鎺ュ彛涓嶅彲杈�** 鈥斺�� 鑳藉甫瀛愰」鐨勫彧鏈夊垎缁勯」锛岃�屽垎缁勯」鎯抽�� `parentId` 浼氬厛琚鍒� 1
+锛坄1040601007`锛夋嫤鎺夛紙瀹炴祴鐢ㄤ緥銆屾湁瀛愰」涓嶈兘鎸傚埌鍒殑鍒嗙粍涓嬨�嶈繑鍥炵殑姝f槸 `1040601007` 鑰屼笉鏄� `1008`锛�
+**杩欐槸璁捐浣跨劧锛屼笉鏄己闄�**锛氳鍒� 1 缁欑殑鏀规硶鏇村彲鎵ц锛夈�傝鍒嗘敮鍙湪**搴撻噷瀛樺湪銆屾潯鐩被鍨�=褰曞叆椤瑰嵈鏈夊瓙椤广��
+鐨� SQL 閫犳暟**鏃舵墠鍙兘鍛戒腑鐨勶紝鍗曟祴 `testUpdateIndicator_hasChildrenCannotReparent`
+姝f槸**鐩存帴鐢� mapper 閫犲嚭杩欑琛�**鍘昏鐩栧畠銆傝鍒� 6 鐨勭浜屼釜鍒嗘敮锛堟敼鎴愬綍鍏ラ」锛夌粡鐣岄潰瀹屽叏鍙揪锛堢敤渚� 11锛夈��
+
+**UI 楠屾敹锛圥laywright锛屽叏杩囷級**
+
+- **鍒楄〃涓ゅ垪**锛氳〃澶翠负 `妫�娴嬮」缂栫爜 / 妫�娴嬮」鍚嶇О / 鏉$洰绫诲瀷 / 鎵�灞炲垎缁� / 妫�娴嬮」绫诲瀷 / 鈥锛�
+ 鍒嗙粍椤规樉绀� Tag `鍒嗙粍椤筦 + 鎵�灞炲垎缁� `-`锛屽瓙椤规樉绀� Tag `褰曞叆椤筦 + 鎵�灞炲垎缁勪负**鐖跺垎缁勫悕**銆�
+- **鏂板琛ㄥ崟榛樿鎬�**锛氭潯鐩被鍨� RadioGroup 榛樿閫変腑銆屽綍鍏ラ」銆嶏紙`z.number().default()` 鐢熸晥锛夛紱
+ 鍙瀛楁涓� 缂栫爜 / 鍚嶇О / 鏉$洰绫诲瀷 / 鎵�灞炲垎缁� / 妫�娴嬮」绫诲瀷 / 妫�娴嬪伐鍏� / 鎺掑簭鍙� / 缁撴灉鍊肩被鍨� / 澶囨敞锛�**鏃犲叕寮�**銆�
+- **鍒囧埌銆屽垎缁勯」銆�**锛歚鎵�灞炲垎缁刞 涓� `缁撴灉鍊肩被鍨媊 **浠� DOM 娑堝け**锛宍鍏紡` 鍑虹幇涓斿甫蹇呭~鏄熷彿銆�
+- **璧板畬鏁存潯閾捐矾**锛歎I 寤哄垎缁勶紙`ZZ-UI-GRP`锛夆啋 钀藉簱 `item_type=2 / parent_id=0 / result_type=NULL / formula_text` 榻愬叏锛�
+ 鍐嶅缓褰曞叆椤瑰苟**浠庝笅鎷夋爲閲岄�変腑鏂板垎缁�**锛堟爲鑺傜偣鍒楀嚭 `姘村垎 / 閰稿惈閲� / 姝d竵閱囧惈閲� / ZZ鐣岄潰鍒嗙粍` 4 椤癸紝
+ 鏂板鐨勫垎缁�**绔嬪嵆鍙��**锛夆啋 钀藉簱 `parent_id=40 / sort_order=1`銆�
+- **UI 鍒犻櫎鍒嗙粍**锛氫簩娆$‘璁ゆ皵娉℃枃妗堜负銆岀‘瀹氬垹闄� ZZ鐣岄潰鍒嗙粍 鍚楋紵銆嶏紱纭鍚�**鍥炶鍒嗙粍涓庡叾瀛愰」 `deleted` 鍏ㄤ负 1**銆�
+- **缂栬緫鍒嗙粍锛堝彧璇绘鏌ワ紝鏈繚瀛橈級**锛氭墦寮�鐜扮綉鍒嗙粍 21銆屾按鍒嗐�嶇殑淇敼寮圭獥 鈥斺�� `鎵�灞炲垎缁刞 **涓嶅湪 DOM 閲�**銆�
+ `鍏紡` 甯﹀繀濉槦鍙凤紝涓� `code / name / formulaText / sortOrder=30 / remark` 鍏ㄩ儴姝g‘鍥炲~銆�
+
+**鏈仛 / 涓嶄富寮�**
+
+- **`group-list` 鍦ㄥ垎缁勯」鏁伴噺寰堝ぇ鏃剁殑琛ㄧ幇鏈瘎浼�**锛氱洰鍓嶆槸鍏ㄩ噺杩斿洖銆佹棤鍒嗛〉銆�
+- **娌℃湁鍦ㄧ晫闈笂閫愪竴璇曡繃鍏ㄩ儴 6 鏉¢敊璇爜鐨� toast 鍛堢幇**锛堥敊璇爜涓庢枃妗堝湪 HTTP 灞傚凡閫愭潯楠岃繃锛�
+ UI 灞傞獙鐨勬槸琛ㄥ崟褰㈡�佷笌閾捐矾锛屾湭閫愭潯鍒堕�犻敊璇湅 Toast锛夈��
+
+### 22.9 鏈疆椤哄甫韪╁埌鐨勫伐绋嬪潙锛堝�煎緱澶嶇敤锛�
+
+- **`mvn -o -pl yudao-module-mes test`锛堜笉甯� `-am`锛変細鎷垮埌鏈湴浠撳簱閲岄檲鏃х殑 `mes-api` jar**锛�
+ 鎶� `鎵句笉鍒扮鍙� setGroupChildName/setGroupSpan/...` 涔嬬被鐨勫亣缂栬瘧閿欒銆�
+ 淇硶锛氬厛 `mvn -o -pl yudao-module-mes-api install -DskipTests -q` 鍒锋柊锛屾垨鐩存帴甯� `-am`銆�
+ **搂21.7 璁拌繃鍚屼竴鏉★紝鏈疆鍙堝鐜颁竴娆°��**
+- **鍏ㄦā鍧楁祴璇曞浠舵湁 16 涓被銆�107 椤瑰け璐ワ紝涓庢湰杞棤鍏筹紝涓斿凡鐢ㄨ瘉鎹瘉浼�屾槸鎴戞敼鍧忕殑銆�**锛�
+ 鏍瑰洜鏄袱绫�**瀛橀噺**闂 鈥斺��
+ 鈶� `NoSuchBeanDefinitionException: SrmSupplierApi`锛坄MesQcIqcServiceImpl` 娉ㄥ叆瀹冿紝
+ 浣嗗叾宸叉彁浜ょ殑娴嬭瘯娌℃湁 `@MockitoBean`锛夛紱鈶� H2 娴嬭瘯 DDL 婕傜Щ
+ 锛坄Column "param_template_id"/"exclude_weekend"/"process_instance_id" not found`锛夈��
+ 璇佹嵁閾撅細`git status --short` 瀵硅繖浜涜矾寰�**涓虹┖**锛堟湭琚垜瑙︾锛夛紱
+ `git diff --stat create_tables.sql` = **26 insertions(+), 0 deletions**锛堢函杩藉姞锛夛紱
+ `git show HEAD:...create_tables.sql | grep -c <鍒楀悕>` **涓夊垪鍦� HEAD 閲屽氨宸叉槸 0**銆�
+ **杩欎笁鏉″睘浜庡叾浠栧紑鍙戣�呯殑杞锛屾湰杞彧鎶ュ憡銆佷笉浠d慨銆�**
+- **鍒ゆ柇銆岃窇鐨勬槸涓嶆槸鏃х被銆嶇殑鍙鐢ㄦ帰閽�**锛氭嬁涓�涓�**鍙湁鏂颁唬鐮佹墠鏈夌殑鎺ュ彛**鎵撲竴娆�
+ 锛堟湰杞槸 `/group-list`锛夈�傝繑鍥� 404 鍗宠繘绋嬮噷娌℃湁鏂� Controller锛�
+ 杩斿洖 200 浣嗗瓧娈靛叏 `null` 鍒欐槸銆岄儴鍒嗘棫銆侀儴鍒嗘柊銆嶇殑娣峰悎 classpath 鈥斺�� **姣旂湅鏂囦欢 mtime 鏇寸洿鎺�**銆�
+
+### 22.10 娴嬭瘯鏁版嵁娓呯悊
+
+楠屾敹鏈熼棿鍏遍�� 6 琛岋紙HTTP锛�35/36/37/38/39锛沀I锛�40/41锛夛紝**鍏ㄩ儴宸蹭粠搴撲腑纭垹闄�**锛�
+鍥炶涓庡紑宸ュ墠閫愰」涓�鑷达細
+
+| 椤� | 娓呯悊鍚� | 寮�宸ュ墠 |
+|---|---|---|
+| `code LIKE 'ZZ-%'` 娈嬬暀 | `0` | 0 |
+| `deleted=0` 鎬昏鏁� | `34` | 34 |
+| 鍒嗙粍椤癸紙`item_type=2`锛� | `3` | 3 |
+| 鏈夌埗鐨勮锛坄parent_id<>0`锛� | `9` | 9 |
+| 銆屾按鍒嗐�嶇殑瀛愰」鏁� | `4` | 4 |
+| `MAX(id)` | `34` | 34 |
+| 鍒嗙粍 21 鏈韩锛坄SEED-BT-WATER锝滄按鍒嗭綔parent_id=0锝渋tem_type=2锝渟ort_order=30锝滃叕寮廯锛� | 閫愬瓧娈垫湭鍙� | 鍚� |
+
+**鐜扮綉閭� 34 琛岋紙鍚� 21/26/31 涓変釜鍒嗙粍涓庡瓙椤� 22鈥�25 / 27鈥�30 / 32锛夊叏绋嬫湭鍔�**锛�
+鍗曞厓娴嬭瘯璺戝湪 H2 鍐呭瓨搴擄紙`jdbc:h2:mem:testdb`锛夛紝姣忔鐢ㄤ緥鍚庣敤 `clean.sql` 娓呰〃锛�**涓嶇杩愯搴�**銆�
+鏈疆鏃犱笂浼狅紝涓嶆秹鍙� `blob` / 闄勪欢銆備复鏃惰剼鏈笌瑙e寘浜х墿鏀惧湪浠撳簱澶栫殑
+`D:/qcl-tmp/`锛堝凡 `mv` 鏀瑰悕褰掓。锛宍rm -rf` 琚潈闄愭嫆缁濓級銆�
+
+## 浜屽崄涓夈�丄I 瀵煎叆璁や笉鍑恒�屽垎缁勬楠岄」琛ㄣ�嶏細鏍瑰洜鍦ㄦ娊鍙栧眰涓㈠悎骞朵俊鎭紙2026-09-19 缁級
+
+### 23.1 鐜拌薄
+
+鐢ㄦ埛鎷跨湡瀹炴潵鏂欐楠屾姤鍛� `鐧句簨妯$増.docx` 璧� AI 瀵煎叆锛岃瘑鍒嚭鏉ョ殑妫�楠岃〃鏄�**涓�灞傚钩閾�**鐨�
+`QualityTable`锛岃�屽師浠剁殑妫�楠岄」鏄�**涓ゅ眰缁撴瀯**锛堜竴涓楠岄」鐩笅鎸傝嫢骞插瓙椤癸紝椤圭洰鍚嶇旱鍚戝悎骞讹級銆�
+鐢ㄦ埛鍦ㄧ‖鍒锋柊锛圕trl+F5锛夊悗澶嶆祴浠嶆槸鍚屾牱缁撴灉銆�
+
+### 23.2 鎴戝厛璇垽杩囦竴娆★紝璁板湪杩欓噷閬垮厤閲嶇姱
+
+绗竴娆℃帓鏌ユ椂鎴戞嬁 `hint = "杩欐槸 IQC 鏉ユ枡妫�楠屾姤鍛婏紝琛ㄦ牸鏈夊垎缁勭殑妫�楠岄」鐩�"` 澶嶈窇锛�
+妯″瀷 3/3 閮芥寫涓簡 `GroupedQualityTable`锛屼簬鏄垜鍒ゅ畾鏍瑰洜鏄�屽墠绔Н鏈ㄦ竻鍗曡繃鏈熴�佸皯浜嗚繖涓粍浠躲�嶃��
+**杩欎釜缁撹鏄敊鐨�**锛岃�屼笖閿欑殑鍘熷洜灏卞湪鎴戣嚜宸憋細閭e彞 hint 绛変簬鎶婄瓟妗堝啓鍦ㄤ簡棰樺共閲岋紝
+妯″瀷涓嶉渶瑕佷粠琛ㄦ牸閲岀湅鍑哄垎缁勭粨鏋勶紝鍙璇� hint 灏卞浜嗐�傜敤鎴风‖鍒锋柊鍚庣幇璞′緷鏃э紝璇佷吉浜嗚繖鏉″垽鏂��
+
+**鏁欒锛堝彲澶嶇敤锛�**锛氬鐜般�屾ā鍨嬮�夐敊缁勪欢銆嶈繖绫婚棶棰樻椂锛宍hint` **蹇呴』鐣欑┖**锛堟垨鍘熸牱鐓ф妱鐢ㄦ埛杈撳叆鐨勶級锛�
+鍚﹀垯娴嬬殑鏄�屾彁绀鸿瘝閲屾湁娌℃湁鍐欑瓟妗堛�嶏紝涓嶆槸銆屾ā鍨嬭兘涓嶈兘鑷繁鐪嬪嚭鏉ャ�嶃��
+
+### 23.3 鐪熸牴鍥狅紙瀹炶瘉锛岄潪鎺ㄦ柇锛�
+
+鎷跨┖ hint 澶嶈窇锛堟竻鍗� 13 椤广�乣GroupedQualityTable` 鍦ㄥ満锛夛紝妯″瀷**姣忔閮芥寫骞抽摵鐨� `QualityTable`**銆�
+浜庢槸杞悜鐪嬫ā鍨嬪埌搴曟敹鍒颁簡浠�涔堚�斺�旀妸鐪熷疄 docx 鐨勬娊鍙栫粨鏋滄墦鍑烘潵锛岄棶棰樹竴鐩簡鐒讹細
+
+`OfficeImportAdapter` 鐢� `row.getTableCells()` 涓�鏍兼牸鍙栨枃瀛楀啀 Tab 鎷兼帴锛岃�� POI 瀵瑰悎骞跺崟鍏冩牸鐨勮涓烘槸锛�
+
+| Word 閲岀殑鍐欐硶 | POI 缁欎綘浠�涔� | 鍚庢灉 |
+|---|---|---|
+| `w:gridSpan="2"`锛堟í鍚戝悎骞讹級 | 鍙繑鍥� 1 涓� `XWPFTableCell` | 琚洊浣忕殑鍚庡嚑鍒�**鍑┖娑堝け**锛岃琛屽垪鏁颁笌琛ㄥご瀵逛笉涓� |
+| `w:vMerge`锛堢旱鍚戝悎骞剁画鏍硷級 | 鏂囧瓧鏄�**绌轰覆** | 鍒嗙粍鍚嶅彧鍦ㄧ涓�琛屽嚭鐜帮紝鍚庡嚑琛岀湅璧锋潵鏄�屾病鏈夊垎缁勭殑鐙珛妫�楠岄」銆� |
+
+鍚屼竴娆¤瘑鍒殑鎶藉彇缁撴灉瀵圭収锛堢湡瀹炴枃浠讹紝闈炴瀯閫犳牱鏈級锛�
+
+```
+鏀瑰墠锛氱矑搴�-绛涗笂鐗╂瘮渚嬶紙%锛塒article Size-% RemainsON 20鐩笂 ANA.MTH-000034 0-5 鍚堟牸Checkout
+ 40鐩笂 ANA.MTH-000034 20-40
+ 60鐩笂 ANA.MTH-000034 30-50
+ 80鐩笂 ANA.MTH-000034 0-20
+ 100鐩笂 ANA.MTH-000034 0-12
+鏀瑰悗锛氱矑搴�-绛涗笂鐗╂瘮渚嬶紙%锛塒article Size-% RemainsON 20鐩笂 ANA.MTH-000034 0-5 鍚堟牸Checkout
+ 鈫戝悓涓� 40鐩笂 ANA.MTH-000034 20-40 鈫戝悓涓�
+ 鈫戝悓涓� 60鐩笂 ANA.MTH-000034 30-50 鈫戝悓涓�
+ 鈫戝悓涓� 80鐩笂 ANA.MTH-000034 0-20 鈫戝悓涓�
+ 鈫戝悓涓� 100鐩笂 ANA.MTH-000034 0-12 鈫戝悓涓�
+```
+
+鏀瑰墠鐨勫悗鍥涜鏄�岄鏍肩┖鐨勫钩閾鸿銆嶁�斺��**妯″瀷娌℃湁浠讳綍渚濇嵁鍒ゆ柇瀹冧滑灞炰簬涓婇潰閭d竴琛�**锛�
+棰樼洰鏈韩灏辨棤瑙o紱鏀瑰悗銆屼笌涓婁竴琛屽悓鍊笺�嶈鏄庤鍑烘潵锛屼袱灞傜粨鏋勬墠绗竴娆¤繘鍏ユā鍨嬬殑瑙嗛噹銆�
+
+### 23.4 鏀瑰姩锛�3 涓敓浜ф枃浠� + 1 涓祴璇曟枃浠讹級
+
+| 鏂囦欢 | 鏀瑰姩 |
+|---|---|
+| `OfficeImportAdapter.appendBodyElements()` | 琛ㄦ牸鍒嗘敮鎹㈡垚 `appendTable()`锛氭寜 `w:gridSpan` 琛ョ┖鍗犱綅銆佹寜 `w:vMerge` 鏍囩画鏍笺�佹瘡琛屾寜**鏁磋〃缃戞牸瀹藉害**锛堝彇鎵�鏈夎鐨勬渶澶у�硷紝涓嶆槸琛ㄥご琛岋級琛ラ綈 |
+| `QcReportDocumentExtract` | 鏂板甯搁噺 `VERTICAL_MERGE_MARK = "鈫戝悓涓�"`銆傛斁鍦ㄨ繖閲屾槸鍥犱负瀹冩槸銆屾娊鍙栧嚭鏉ョ殑鏂囨湰闀夸粈涔堟牱銆嶈繖鏉″绾︾殑涓�閮ㄥ垎锛岃�� `llm` 鍖呭凡缁忎緷璧� `document` 鍖咃紙`QcReportLlmCallPlanner` 灏卞紩浜� `QcReportDocumentExtract`锛夛紝涓よ竟鍏辩敤涓�浠藉父閲忥紝涓嶄細鍚勫啓涓�涓瓧闈㈤噺鍚庡悇鑷紓绉� |
+| `QcReportTemplatePromptBuilder.EXTRACTION_RULES` | 琛ョ 8 鏉★紝璇存槑銆屸啈鍚屼笂銆嶈〃绀恒�屼笌涓婁竴琛屾槸鍚屼竴涓�笺�嶏紙绾靛悜鍚堝苟锛夛紝涓嶆槸鍥涗釜瀛楃殑鏅�氬唴瀹癸紱骞舵寚鍑哄悓涓�鍒楄繛缁嚭鐜版椂閫氬父灏辨槸涓ゅ眰缁撴瀯鈥斺��**浣嗘寫鍝釜缁勪欢浠嶄互娓呭崟 hint 涓哄噯**锛屼笉鍦ㄨ繖閲屾浛 `hint` 鍋氬喅瀹� |
+| `AiImportFixtures` + `QcReportImportAdapterTest` | 鏂板涓や釜澶瑰叿锛堢旱鍚戝悎骞� / 妯悜鍚堝苟锛変笌涓ゆ潯鐢ㄤ緥 |
+
+涓ゅ鍒绘剰鐨勫彇鑸嶏細
+
+- **缁牸鑷韩鏈夋枃瀛楁椂浠ユ枃瀛椾负鍑�**锛屼笉瑕嗙洊鎴愭爣璁般�傜画鏍煎湪 Word 閲屾湰涓嶈鏈夊唴瀹癸紝鐪熸湁灏辫鏄庡埗琛ㄤ笉瑙勮寖锛�
+ 姝ゆ椂涓㈡枃瀛楁瘮涓㈢粨鏋勬洿鍙儨銆�
+- **缃戞牸瀹藉害鍙栨墍鏈夎鐨勬渶澶у��**锛屼笉鍙栬〃澶磋鐨勫垪鏁帮細琛ㄥご甯稿父甯︽í鍚戝悎骞讹紝鎸夎〃澶村搴﹀垏浼氭妸涓嬮潰鍑犺鎴柇銆�
+
+### 23.5 楠岃瘉锛堝凡鍋� / 鏈仛鍒嗗紑澹版槑锛�
+
+**宸插仛**
+
+- `mvn compile -pl yudao-module-qcreport -am -q` 閫氳繃銆�
+- `mvn -o -pl yudao-module-qcreport -am test` 鈫� **143 / 143 鍏ㄧ豢**锛堟柊澧� 2 鏉″湪鍐咃級銆�
+ 鍏朵腑 `docxKeepsLayoutOrder` 鐢ㄦ棤鍚堝苟澶瑰叿锛屾敼鍚庤緭鍑洪�愬瓧鏈彉锛岃瘉鏄庛�屾病鏈夊悎骞剁殑琛ㄦ牸涓嶅彈褰卞搷銆嶃��
+- **鐢ㄦ敼鍚庣殑鐪熷疄绫昏窇鐪熷疄鏂囦欢**锛坄D:/qcl-tmp/MergeProbe.java`锛宑lasspath 鎸囧埌 `target/classes`锛�
+ 杈撳叆鐢ㄦ埛閭d唤 142373 瀛楄妭鐨� `bs.docx`锛夛細鎶藉彇缁撴灉鍗� 23.3 鐨勩�屾敼鍚庛�嶅舰鎬侊紝
+ 5 琛� `绮掑害-绛涗笂鐗╂瘮渚媊 鐨勫瓙椤瑰叏閮ㄥ甫涓� `鈫戝悓涓奰锛岃〃澶磋涔熶粠 5 鏍艰ˉ鎴愪笌鏁版嵁琛屽榻愮殑 6 鏍笺��
+
+**鏈仛锛堟埅鑷虫湰鑺傝惤绗旓級**
+
+- **鐪熷疄 HTTP 澶嶈窇灏氭湭鎵ц**锛氳繍琛屼腑鐨勫悗绔粛鏄敼鍓嶇殑绫伙紙鍙敤 22.9 璁板綍鐨勫垽瀹氭帰閽堢‘璁わ級锛�
+ 闇�瑕佺敤鎴�**鎵嬪伐閲嶅惎鍚庣**銆傞噸鍚悗瑕佺敤 **绌� hint** 鎵撲竴娆� `/qc-report/ai-import/draft`锛坆lob 浠ュ綋娆′笂浼犱负鍑嗭紝
+ AI 瀵煎叆寮圭獥姣忔涓婁紶閮戒細娓呮帀涓婁竴涓� blob锛宨d 浼氬彉锛夛紝纭妯″瀷鑷繁鏀规寫 `GroupedQualityTable`銆�
+ **鍦ㄨ窇瀹岃繖涓�姝ヤ箣鍓嶏紝鍙兘澹版槑銆屾娊鍙栧眰鐨勮緭鍏ュ凡缁忓叿澶囧垽鍒袱灞傜粨鏋勬墍闇�鐨勪俊鎭�嶏紝
+ 涓嶈兘澹版槑銆孉I 宸茬粡鑳借鍑哄鏉傜粨鏋勩��**鈥斺�斿悗鑰呯殑璐d换鍦ㄦā鍨嬶紝鍙湁鐪熷疄璋冪敤鎵嶈兘鍥炵瓟銆�
+ > 鍚庣画锛氶噸鍚悗澶嶈窇缁撴灉鏄� **2/5**锛堜笉鏄叏涓級锛屾牴鍥犺浆鍒版彁绀鸿瘝鎺緸涓婏紝瑙�**绗簩鍗佸洓鑺�**銆�
+
+### 23.6 鏈疆鏈仛 / 宸茬煡杈圭晫锛堝瀹炲0鏄庯級
+
+- **璇箟灞傜殑缂哄彛娌″姩**锛氬師浠堕噷銆屾娴嬫柟娉曘�嶈繖涓�鍒椼�佷互鍙娿�屾楠岀粨鏋� / 缁撹銆嶈繖绉�**涓ょ骇琛ㄥご**锛�
+ 13 涓粍浠堕噷娌℃湁浠讳綍涓�涓兘琛ㄨ揪銆傝繖涓嶆槸鎶藉彇灞傜殑闂鈥斺�旀枃瀛楀凡缁忓畬鏁存娊鍑烘潵浜嗭紙瑙� 23.3 鐨勮鍐呭锛夛紝
+ 鏄�屽彲鐢ㄧН鏈ㄣ�嶇殑琛ㄨ揪鍔涜竟鐣屻�傝琛ュ氨寰楁柊澧炰竴涓�屽彲鑷畾鍒楃殑妫�楠岃〃銆嶇粍浠讹紝
+ 鎸夐」鐩鍒欏睘浜�**鍏堝嚭 `docs/` 璁捐鏂囨。鍐嶅姩鎵�**鐨勯偅绫绘敼鍔紝鏈疆涓嶇銆�
+- **娓呭崟澶у皬娌¤繘鏃ュ織**锛歚QcReportAiImportServiceImpl` 鐨勫畬鎴愭棩蹇楁湁 `files/pages/calls/components/budgetExceeded/durationMs`锛�
+ 浣嗘病鏈� catalog 椤规暟銆備笅娆″啀閬囧埌銆屾ā鍨嬮�変簡涓嶅瓨鍦ㄧ殑缁勪欢銆嶈繖绫婚棶棰樻椂锛岃繖涓�椤硅兘涓�鐪兼帓闄ゃ�屾竻鍗曚紶閿欎簡銆嶃��
+ 鏀瑰姩寰堝皬锛屼絾涓嶅湪鐢ㄦ埛鏈疆銆屽紑濮嬩紭鍖栥�嶆巿鏉冪殑鑼冨洿鍐咃紝鐣欏緟鐢ㄦ埛鐐瑰ご銆�
+
+### 23.7 涓�涓�煎緱澶嶇敤鐨勫伐绋嬪潙
+
+Java 鐨� `@argfile` 鏄�**鎸夊钩鍙伴粯璁ゅ瓧绗﹂泦**璇荤殑銆傛垜鎶婂惈涓枃鐨勮矾寰勶紙`D:/鐗涢┈/...`锛夊啓杩� argfile 鍚庯紝
+`javac` 鎶ャ�屾壘涓嶅埌绗﹀彿銆嶏紝浣嗛敊璇俊鎭湰韬槸涔辩爜锛岀湅璧锋潵鍍忓埆鐨勯棶棰樸��
+**瑙e喅鍔炴硶**锛氭妸鏂扮紪璇戠殑 `target/classes` 鎷峰埌涓�涓函 ASCII 璺緞锛堟湰杞� `/d/qcl-tmp/qcr-classes-new`锛夊啀鎷艰繘 classpath銆�
+鎺掓煡鏃跺鏋� `java @argfile` 鐨勬姤閿欓噷鍑虹幇涔辩爜锛屽厛鎬�鐤戝瓧绗﹂泦锛屽埆鍏堟��鐤戜唬鐮併��
+
+## 浜屽崄鍥涖�佸悓涓婄画锛氭彁绀鸿瘝鏈韩鍦ㄧ粰骞抽摵琛ㄦ墦骞垮憡锛�2026-09-19 缁級
+
+### 24.1 鐜拌薄锛氭娊鍙栧眰淇畬锛岀敤鎴烽噸鍚悗銆岃繕鏄繖鏍枫��
+
+浜屽崄涓夎妭钀藉湴鍚庣敤鎴烽噸鍚簡鍚庣锛岄噸浼犲悓涓�浠� `鐧句簨妯$増.docx`锛岃璁″櫒鐢诲竷涓婁粛鏄�**骞抽摵**鍥涘垪
+锛堟楠岄」鐩�/鏍囧噯鍊�/瀹炴祴鍊�/鍒ゅ畾锛夈�備篃灏辨槸璇达細**杈撳叆渚х殑淇℃伅宸茬粡澶熶簡锛屾槸妯″瀷娌¢�夊缁勪欢銆�**
+
+### 24.2 绌� hint 澶嶈窇閲忓寲锛氫笉鏄�屽畬鍏ㄦ病鐢ㄣ�嶏紝鏄�屼笉绋冲畾銆�
+
+鎷跨敤鎴烽偅浠芥枃浠讹紙blob 83锛岄噸鍚悗涓婁紶锛岀‘璁ゅ凡璧板埌鏂颁唬鐮侊級鐢�**绌� hint** 鎵� 5 娆� `/qc-report/ai-import/draft`锛�
+
+| 鏃剁偣 | 鍛戒腑 `GroupedQualityTable` |
+|---|---|
+| 鎶藉彇灞備慨澶嶅墠 | 0 / 5 |
+| 鎶藉彇灞備慨澶嶅悗銆佹彁绀鸿瘝鏈敼 | **2 / 5** |
+
+2/5 璇存槑鎶藉彇灞備慨澶嶆槸鐪熺殑鏈夋晥锛堜粠銆屼竴娆¢兘涓嶄腑銆嶅埌銆岃兘涓�嶏級锛屼絾**涓嶇ǔ瀹�**鈥斺�旂敤鎴风湅鍒扮殑閭d竴娆″ぇ姒傜巼灏辨槸娌′腑鐨勯偅 3/5銆�
+
+### 24.3 鐪熸牴鍥狅細绯荤粺鎻愮ず璇嶉噷鏈変笁澶勫湪鎶婃ā鍨嬪線骞抽摵琛ㄤ笂鎺�
+
+瀹℃彁绀鸿瘝鍏ㄦ枃鍚庡彂鐜帮紝鐪熸鍘嬩綇妯″瀷鐨勬槸鎺緸锛岃�屼笉鏄兘鍔涳細
+
+1. **鎶藉彇瑙勫垯绗� 1 鏉$洿鎺ョ偣鍚嶄簡 `QualityTable`**锛氥�宍QualityTable` 鐨� `itemsPath` 涓�寰嬪~
+ `inspectionItems`銆嶃�傝繖鏉¤鍒欑殑鏈剰鏄�屾楠岃〃鐨勬暟鎹簮璺緞缁熶竴銆嶏紝浣嗗瓧闈㈠啓鎴愪簡涓�涓�**鍏蜂綋缁勪欢鍚�**锛�
+ 浜庢槸鏁翠唤鎻愮ず璇嶉噷鍞竴琚鍒欐闈㈢偣鍚嶇殑妫�楠岃〃灏辨槸骞抽摵琛ㄢ�斺�旂瓑浜庡叏绋嬬粰瀹冩墦骞垮憡銆�**瀚岀枒鏈�澶с��**
+2. **杈撳嚭鏍煎紡绀轰緥閲岀浜屼釜缁勪欢灏辨槸 `{"type": "QualityTable"}`**銆傜ず渚嬫槸妯″瀷鏈�瀹规槗鐓ф妱鐨勪笢瑗裤��
+3. 绗� 8 鏉″彧璇翠簡銆宍鈫戝悓涓奰 鏄悎骞舵爣璁般�嶏紝**娌¤杩欎釜鏍囪鎰忓懗鐫�浠�涔堢粨鏋�**锛屾ā鍨嬭鍒扮殑鏄�屼竴涓蹇界暐鐨勭鍙枫�嶏紝
+ 鑰屼笉鏄�岃繖閲屽瓨鍦ㄤ袱灞傜粨鏋勩�嶃��
+
+### 24.4 鏀瑰姩
+
+**鍚庣鎻愮ず璇嶏紙`QcReportTemplatePromptBuilder`锛変笁澶�**
+
+| 浣嶇疆 | 鏀规硶 |
+|---|---|
+| `EXTRACTION_RULES` 绗� 1 鏉� | `QualityTable 鐨� itemsPath` 鈫� **銆屽嚒鏄甫妫�楠岄」鐨勮〃鏍肩粍浠躲��**锛岃鍒欎笉鍐嶇偣鍚嶄换浣曚竴涓叿浣撶粍浠� |
+| `EXTRACTION_RULES` 鍘熺 8 鏉℃媶鎴� 8 / 9 | 绗� 8 鏉″彧璁叉爣璁板惈涔夛紱**鏂板绗� 9 鏉�**缁欏嚭鎺ㄨ锛氥�屽悓涓�鍒楅噷杩炵画鍑虹幇 `鈫戝悓涓奰锛岃繖寮犺〃灏辨槸涓ゅ眰缁撴瀯鈥︹�﹀繀椤诲綋鎴愪簨瀹炲弬涓庨�夊瀷銆嶏紝骞剁偣鏄庝涪鎺夊瓙椤圭瓑浜庢姤鍛婂け鐪� |
+| `OUTPUT_FORMAT` 缁撳熬 | 琛ヤ竴鍙ャ�屼笂闈㈢ず渚嬮噷鐨� type **鍙槸鏍煎紡绀烘剰**锛岄�夊瀷涓�寰嬩互銆婂彲鐢ㄧ粍浠舵竻鍗曘�嬮噷鍚勭粍浠� hint 涓哄噯锛屼笉瑕佸洜涓虹ず渚嬮噷鍐欎簡鏌愪釜 type 灏辩収鎶勫畠銆� |
+
+**鍓嶇绉湪娓呭崟锛坄components/quality/inspection/quality-table.ts` 鐨� `aiHint`锛岀敤鎴峰凡鎵瑰噯锛�**
+
+鍘熸枃銆屸�︹��**鎶ュ憡姝f枃鏈�涓昏鐨勭粍浠躲��**銆嶆槸涓�鍙ヤ細涓诲姩璇妯″瀷鐨勮瘽锛氬畠鏄� `QualityTable` 鑷繁鐨勮嚜杩帮紝
+妯″瀷璇诲埌鍙細鏇村�惧悜浜庨�夊畠銆傛敼鎴愭潯浠跺紡锛�
+
+```
+澶氳妫�楠屾暟鎹殑琛ㄦ牸锛屾楠岄」骞抽摵涓�灞傘�佹病鏈夌埗瀛愬叧绯伙紙搴忓彿/妫�楠岄」鐩�/鏍囧噯鍊�/瀹炴祴鍊�/鍗曚綅/鍒ゅ畾锛夈��
+涓�涓楠岄」鐩笅鎸傝嫢骞插瓙椤癸紙鍘熶欢閲岃〃鐜颁负璇ュ垪绾靛悜鍚堝苟銆佸悗缁鍐欑潃銆屸啈鍚屼笂銆嶏級鏃朵笉瑕佺敤鎴戯紝
+鏀圭敤鍒嗙粍妫�楠岄」琛ㄣ��
+鎶ュ憡鏈熬鐨勮惤娆剧缃茶锛堟楠屽憳/瀹℃牳浜�/鏃ユ湡锛変笉瑕佹斁杩涙垜杩欓噷锛岄偅灞炰簬 ReportFooter銆�
+```
+
+鏀规硶鏄�**鎶婂垽鍒潯浠跺啓杩� hint 鏈韩**锛坄鈫戝悓涓奰 = 鏈夊瓙椤癸級锛岃�屼笉鏄彧鐣欎竴鍙ャ�屾垜涓嶉�傚悎澶嶆潅鎯呭喌銆嶁�斺��
+妯″瀷鎵嬩笂娌℃湁鍒殑绾跨储鑳藉垽鏂�屽鏉傘�嶅湪鍝��
+
+### 24.5 楠岃瘉锛氱粫杩囪繍琛屼腑鐨勫悗绔紝鐩存帴鐢ㄦ柊鎻愮ず璇嶆墦鐪熸ā鍨�
+
+鍚庣閲嶅惎瑕佺敤鎴锋搷浣滐紝涓轰簡**鍦ㄩ噸鍚箣鍓嶅氨鑳藉洖绛斻�屾柊鎻愮ず璇嶅埌搴曟湁娌℃湁鐢ㄣ��**锛�
+鐢ㄥ垰缂栬瘧鍑虹殑绫绘妸鎻愮ず璇嶈惤鐩橈紝鍐嶇敱鑴氭湰鐩存帴鎵� DashScope锛坄qwen-max`锛宍temperature=0.7` 涓庡簱涓厤缃竴鑷达級锛�
+
+- `PromptDumpProbe.java`锛氳 `bs-catalog.json`锛�13 椤规竻鍗曪級鈫� 璋� `buildSystemPrompt` /
+ `buildUserMessage`锛堢┖ hint锛夆啋 鍐� UTF-8 鏂囦欢銆�
+- `bs-direct-run.mjs`锛氳鎻愮ず璇� + `bs-extract-new.txt`锛�**鏀瑰悗鎶藉彇灞傚鐢ㄦ埛閭d唤 docx 鐨勭湡瀹炶緭鍑�**锛夛紝
+ POST `https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions`锛岃窇 5 杞粺璁″懡涓��
+
+| 缁勫悎 | 鍛戒腑 `GroupedQualityTable` |
+|---|---|
+| 鏂版彁绀鸿瘝 + 鏂版竻鍗� hint | **5 / 5** |
+| 鏂版彁绀鸿瘝 + **鏃�**娓呭崟 hint锛堟秷铻嶅鐓э級 | **5 / 5** |
+
+**缁撹**锛氭湰杞捣鍐冲畾浣滅敤鐨勬槸**鍚庣鎻愮ず璇嶉偅涓夊**锛涘墠绔� hint 鐨勪慨鏀瑰湪杩欎唤杈撳叆涓婃病鏈夋敼鍙樼粨鏋滐紝
+浣嗗畠淇帀鐨勬槸涓�鍙�**纭疄閿欒鐨勮嚜杩�**锛堛�屾姤鍛婃鏂囨渶涓昏鐨勭粍浠躲�嶏級锛屼繚鐣欍��
+
+### 24.6 楠岃瘉鐘舵�侊紙鍔″繀鍒嗘竻锛�
+
+- **宸查獙璇�**锛氭柊鎻愮ず璇� + 鏂版竻鍗曪紝瀵圭敤鎴疯繖浠界湡瀹炴枃浠躲�佺湡瀹炴ā鍨嬨�佺┖ hint锛�**5/5 绋冲畾鍛戒腑鍒嗙粍琛�**銆�
+ 杩欐潯閾捐矾鏄�屾彁绀鸿瘝 鈫� 妯″瀷鍥炲銆嶏紝涓棿娌$粡杩囧悗绔殑瑙f瀽/褰掍竴鍖栥��
+- **鏈獙璇�**锛氭暣鏉� `/qc-report/ai-import/draft` HTTP 閾捐矾锛堥渶瑕佺敤鎴�**鍐嶉噸鍚竴娆″悗绔�**锛夈��
+ 瑙f瀽鍣ㄤ笌褰掍竴鍖栧櫒鏈疆涓�瀛楁湭鏀癸紝涓旀娊鍙栧眰淇鍚庡凡鑳戒骇鍑鸿繃 `GroupedQualityTable`锛堝嵆 2/5 閭d袱娆★級锛�
+ 鎵�浠ユ暣閾捐矾鐨勯闄╁緢浣庘�斺�斾絾娌¤窇杩囧氨涓嶅啓鎴愩�屽凡閫氳繃銆嶃��
+- **杩欎竴杞殑鏁欒锛堜笌 23.2 鍚屾簮锛岀浜屾韪╋級**锛氬垽鏂�屾ā鍨嬭兘涓嶈兘鍋氬銆嶆椂锛�**杈撳叆閲屾瘡涓�澶�
+ 鍙兘璇卞瀹冪殑鎺緸閮借涓�璧锋煡**銆備笂涓�杞槸鑷繁鐨� hint 璇卞锛岃繖涓�杞槸鎻愮ず璇嶉噷鐐瑰悕鐨勭粍浠跺悕涓庣ず渚嬨��
+ 銆岃緭鍏ヤ俊鎭浜嗐�嶄笉绛変簬銆屾ā鍨嬩細閫夊銆嶁�斺�斾腑闂寸殑鎺緸鏈韩灏辨槸鍙橀噺銆�
+
+## 浜屽崄浜斻�侀�夊瀷淇ソ涔嬪悗锛氬墿涓嬬殑宸窛鍏ㄥ湪銆岃〃杈惧姏銆嶏紙2026-09-19 缁級
+
+### 25.1 鍏堢‘璁ら�夊瀷纭疄淇ソ浜�
+
+鐢ㄦ埛閲嶅惎鍚庝粛鍥炪�岃繕鏄繖鏍枫�嶃�傛嬁**琛ㄥご**褰撳垽鎹嵆鍙尯鍒嗕袱涓粍浠讹細
+
+| | 琛ㄥご |
+|---|---|
+| `QualityTable`锛堝钩閾猴級 | 妫�楠岄」鐩� / **鏍囧噯鍊�** / 瀹炴祴鍊� / 鍒ゅ畾 |
+| `GroupedQualityTable`锛堝垎缁勶級 | 妫�楠岄」鐩� / **瀛愰」** / **妫�娴嬭姹�** / 瀹炴祴鍊� / 鍒ゅ畾 |
+
+鐢ㄦ埛鎴浘閲屽嚭鐜颁簡銆屽瓙椤广�嶃�屾娴嬭姹傘�嶁�斺��**骞抽摵琛ㄦ牴鏈病鏈夎繖涓ゅ垪** 鈬� 缁勪欢宸茬粡鎹㈣繃鏉ヤ簡銆�
+鐢ㄧ┖ hint 澶嶈窇 blob 84 璧板畬鏁� HTTP 閾捐矾涔熺‘璁よ繑鍥� `GroupedQualityTable`銆�
+
+椤哄甫婢勬竻涓�涓湅鐫�鍍� bug 鐨勪笢瑗匡細鎴浘閲屽崟鍏冩牸涓婄殑 `Table cell pec}}` **涓嶆槸鏂囨。鍐呭**銆�
+`Table cell` 鏄� GrapesJS 鑷繁鐨勭粍浠剁被鍨嬪悕锛坄node_modules/grapesjs/locale/en.js:43` 鐨� `cell: 'Table cell'`锛夛紝
+鏄紪杈戝櫒鐢诲湪鍗曞厓鏍煎乏涓婅鐨勬偓娴爣绛撅紝鐩栦綇浜� `{{report.s` 鍓� 10 涓瓧绗︼紝鍓╀笅鐨� `pec}}` 鎵嶉湶鍑烘潵銆�
+
+### 25.2 鍓╀笅鐨勫樊璺濆叏閮ㄦ槸琛ㄨ揪鍔涳紝涓嶆槸璇嗗埆
+
+閫愰」姣斿鍘熶欢鍚庣‘璁わ細`GroupedQualityTable` 鐨� 7 鍒椼�乣SampleInfo` 鐨� 6 涓瓧娈�**閮藉啓姝诲湪浠g爜甯搁噺閲�**锛�
+鍘熶欢閲岀殑銆屾娴嬫柟娉� / 缁撹銆嶄袱鍒椾笌銆屾楠岀粨鏋� | 缁撹銆嶄袱绾ц〃澶淬�佷互鍙婂師浠剁殑 7 涓牱鍝佸瓧娈�
+锛堜骇鍝佹暟閲� / 鐢熶骇鏃ユ湡 / 鍦熻眴鍝佺 / 鏈夋晥鏃ユ湡绛夛級**娌℃湁浠讳綍缁勪欢瑁呭緱涓�**銆�
+
+### 25.3 涓�鏉″繀椤诲厛淇�佸惁鍒欐柊鍔熻兘褰㈠悓铏氳鐨勬暟鎹晶缂哄彛
+
+`MesQcReportItemRespDTO` **宸茬粡鏈� `checkMethod`锛堟娴嬫柟娉曪級**锛屼絾 qcreport 寮曟搸鐨� `InspectionItem`
+鎶婂畠涓簡锛宍ReportContext.itemMap()` 涓嬪彂鐨勪綔鐢ㄥ煙閲屾病鏈夊畠銆傗噿 鍒楀畾涔夐噷灏辩畻鍐�
+`妫�娴嬫柟娉�={{item.checkMethod}}`锛屾覆鏌撴湡涔熷彧浼氱暀涓�鐗囩┖鐧藉姞涓�鏉°�岀粦瀹氬彇涓嶅埌鍊笺�嶃��
+琛ヨ繖鏉¢摼璺鍔� 6 澶勶紙mapper / DO / itemMap / Codec / 鍓嶇 context.ts / fixture锛夛紝瑙佽璁℃枃妗� 搂4銆�
+
+### 25.4 鏂规鏂囨。宸插嚭锛�**寰呯敤鎴风‘璁ゅ悗鍔ㄦ墜**
+
+`docs/qc_report_configurable_columns_design.md`銆傛牳蹇冪祼璜栵細
+
+- **涓嶆柊澧炵粍浠�**锛岀粰 `GroupedQualityTable` 鍔犲彲閫� `columns` / `headerSpans`銆佺粰 `SampleInfo` 鍔犲彲閫� `fields`锛�
+ 缂哄腑鏃跺洖钀界幇鏈夊父閲� 鈬� 瀛橀噺妯℃澘闆跺奖鍝嶃�佹棤鏁版嵁杩佺Щ銆�
+- 鍒楀畾涔夌紪鐮佹垚**鍗曡瀛楃涓�**锛堝睘鎬у崗璁彧璁ゆ爣閲忥紝`QualityProps` 涓� `attributes` 閮芥槸瀛楃涓诧級銆�
+- **涓嶉渶瑕佹敼娓叉煋鍣�**锛氬凡鏍告煡 `HtmlRenderer` 鏃犱换浣曟寜缁勪欢绫诲瀷鍒嗘敮鐨勯�昏緫銆乣CanvasSafety` 鏄粦鍚嶅崟鑰岄潪鐧藉悕鍗�
+ 鈬� `colspan`/`rowspan` 鏈潵灏辨斁琛岋紝schema 鐗堟湰鍙蜂篃涓嶇敤鍔ㄣ��
+- 鏈�澶х殑椋庨櫓宸插啓杩涙枃妗o細鍐嶅姞绗笁涓楠岃〃浼氳閫夊瀷鍥炲埌涓嶇ǔ锛埪т簩鍗佸洓 鐨勬満鐞嗭級锛屾墍浠�**涓嶅姞**銆�
+
+**宸插仛 / 鏈仛**锛氭枃妗e凡钀界洏锛坄docs/` 琚� gitignore锛岄渶瑕� `git add -f` 鎵嶈繘鐗堟湰搴擄級锛�
+**浠g爜涓�琛屾湭鍔�**锛岀瓑鐢ㄦ埛瀵规枃妗� 搂11 鐨勫洓涓緟瑁佸喅鐐硅〃鎬併��
+
+---
+
+## 浜屽崄鍏�佽〃杈惧姏琛ラ綈钀藉湴锛氬垪瀹氫箟 / 琛ㄥご璺ㄥ垪 / 鏍峰搧瀛楁锛�2026-09-19 缁級
+
+鐢ㄦ埛瀵� 搂浜屽崄浜� 鐨勮璁℃枃妗g粰鍑恒�屾寜鐓т綘鐨勬兂娉曟潵灏辫浜嗐�嶏紝鍗虫寜鎴戠殑鍒ゆ柇钀藉湴 搂11 鐨勫洓涓緟瑁佸喅鐐广��
+
+### 26.1 鍥涗釜寰呰鍐崇偣鐨勮鍐�
+
+| 宀旇矾 | 瑁佸喅 | 渚濇嵁 |
+|---|---|---|
+| 涓ょ骇琛ㄥご `headerSpans` 杩欒疆鍋氳繕鏄笅杞仛 | **杩欒疆鍋�** | 鍘熶欢銆屾楠岀粨鏋� \| 缁撹銆嶇‘瀹炴槸涓ゅ眰锛涘厛鍋氬悗鍋氶兘瑕佸姩鍚屼竴鎵规枃浠讹紝鎷嗘垚涓よ疆鍙槸澶氫竴娆$紪璇戜笌鑱旇皟 |
+| 鍘熶欢鐨勩�岀粨璁恒�嶅垪鏄犲皠鍒板摢涓粦瀹� | 寮曟搸鐨� `resultText` | `resultText` 灏辨槸閫愰」鐨勫垽瀹氭枃鏈紙`鍚堟牸`/`涓嶅悎鏍糮锛夛紝涓庡師浠躲�岀粨璁恒�嶅垪鐨勫唴瀹逛竴鑷达紱`actualValue` 鏄疄娴嬪�笺�佸師浠堕偅涓�鍒楁槸绌虹殑 |
+| 鍔犱竴涓� `tool`锛堝伐鍏�/娌诲叿锛夊瓧娈� | **涓嶅姞** | 鏃犲満鏅�佹棤璇诲彇鏂癸紱鍔犱簡灏辨槸绗簩涓� `unit_text`锛堣 搂22 鐨勬鍒楁暀璁級 |
+| `SampleInfo` 榛樿瀛楁鏄惁鎵╁埌 7 椤� | **淇濇寔 6 椤�** | 鎵╅粯璁ゅ�间細鏀瑰瓨閲忔ā鏉跨殑娓叉煋浜х墿锛堣繚鑳屻�屽瓨閲忛浂褰卞搷銆嶏級锛岃�� `fields` 瑕嗙洊宸茬粡鑳借〃杈� 7 椤� |
+| 骞抽摵 `QualityTable` 鏄惁涔熷姞 `columns` | **涓嶅姞** | 鍐嶅姞涓�澶勩�屽垪鍙互鑷畾銆嶄細璁╅�夊瀷閲嶆柊鍥炲埌涓嶇ǔ锛埪т簩鍗佸洓 鐨勬満鐞嗭級锛屾敹鐩婂彧鏄钩閾鸿〃涔熻兘澶氬垪 |
+
+### 26.2 钀藉湴鍐呭
+
+**鍓嶇锛坄mom-pro2-before/src/components/quality/`锛�**
+
+- `inspection/grouped-quality-table.ts`锛氭柊澧� `columns` / `headerSpans` 涓や釜鏂囨湰灞炴�э紙**鏁呮剰涓嶇粰 `defaultValue`銆佷笉缁� `bindable`**锛夛紝`dataSchema` 琛� `item.checkMethod`锛宍aiHint` 琛ャ�屽垪姣旈粯璁ゅ鏃跺啓 columns銆佷袱灞傝〃澶村啓 headerSpans锛屼笉瑕佹崲缁勪欢銆嶃��
+- `header/sample-info.ts`锛氭柊澧� `fields` 鏂囨湰灞炴�с��
+- `core/validator.ts`锛�**鎺ヤ笂 `definition.validate`**锛堣瑙� 26.3锛夈��
+- `engine/context.ts`锛歚ReportContextItem` 琛� `checkMethod`锛堟娴嬫柟娉曢�愯杩涗笂涓嬫枃锛屼笌 `requirement` 骞跺瓨涓嶅悎骞讹級銆�
+
+**鍚庣**
+
+- `MesQcReportContextMapper` 鈫� `checkMethod` 璐�氬埌鎶ュ憡涓婁笅鏂囷紙`InspectionItem` 渚ф棭宸叉湁璇ュ瓧娈碉級銆�
+- `QcReportTemplatePromptBuilder`锛氭柊澧炴娊鍙栬鍒� 10锛坄columns` + 缁戝畾璺緞鐧藉悕鍗曪級銆�11锛坄headerSpans`锛夈��12锛坄fields`锛夈��**銆愭姤鍛婁笂涓嬫枃鐨勫瓧娈点�戠櫧鍚嶅崟**锛堣瑙� 26.4锛夈��
+
+### 26.3 椤哄甫淇帀涓�澶勬浠g爜锛歚definition.validate` 浠庢潵娌¤璋冪敤
+
+璁捐鏂囨。瑕佹眰銆岄潪娉曞垪瀹氫箟瑕佸湪淇濆瓨鏃舵姤閿欍�嶏紝浣嗚惤鍒颁唬鐮佹椂鍙戠幇锛�**`definition.validate` 鍦ㄦ暣鍓嶇涓�娆¢兘娌¤璋冪敤杩�**銆�
+鍙湁 `validateQualityProps` 琚皟鐢紙瑁呴厤鍣� `assembler.ts:82`锛夛紝鑰屽畠涓嶇 `definition.validate`銆�
+涔熷氨鏄杩欎釜閽╁瓙鍐欎簡涔熶笉浼氭嫤浣忎换浣曚汉鈥斺�斾袱涓棦鏈夌殑 `validate` 瀹炵幇涓�鐩存寕鍦ㄧ┖妗d笂銆�
+
+宸叉妸 `definition.validate?.(resolved)` 鎺ヨ繘 `validateQualityProps` 鏈熬锛屾柊澧炵殑涓夋潯鏍¢獙涓庢棦鏈夌殑涓ゆ潯鍚屾椂鐢熸晥銆�
+
+> **浠嶆湭瑕嗙洊**锛氳璁″櫒閲�**鎵嬪伐缂栬緫鍚庣偣淇濆瓨**杩欐潯璺洰鍓嶄笉璺� `validateQualityProps`锛堝彧鏈� AI 瀵煎叆瑁呴厤閭f潯璺窇锛夈��
+> 鎵嬪伐濉敊鐨勫垪瀹氫箟涓嶄細鍦ㄤ繚瀛樻椂琚嫤浣忥紝鍙細鍦ㄥ嚭浠舵椂浠ャ�岀粦瀹氬彇涓嶅埌鍊笺�嶆毚闇层�傚睘鏃㈡湁缂哄彛锛屾湰杞湭鏀癸紝宸插啓杩涜仈璋冩枃妗c��
+
+### 26.4 鐩磋繛鐪熸ā鍨嬩笁杞疄娴嬶細淇帀涓変釜鐪熷疄缂洪櫡
+
+鍋氭硶锛氭妸鏂版彁绀鸿瘝浠庢柊缂栬瘧鐨� class 閲� dump 鍑烘潵锛�**涓嶈蛋鍚庣**鐩存帴鎵� DashScope
+锛坄qwen-max`锛夛紝鍠傜湡瀹炵殑鐧句簨 docx 鎶藉彇缁撴灉锛坄bs-extract-new.txt`锛夛紝**hint 鐣欑┖**锛屾瘡杞窇 5 娆$湅绋冲畾鎬с��
+
+| 杞 | 鍙戠幇鐨勯棶棰� | 淇硶 | 淇悗 |
+|---|---|---|---|
+| 绗� 1 杞� | 妯″瀷缁欏垎缁勮〃鍐� `columns` 鏃�**鎶娿�屽瓙椤广�嶆暣鍒椾涪浜�**锛�3/3 杞彧鍐� 4 鍒楋級銆傝�屽垎缁勮〃鐨�**榛樿鍒楁湰鏉ュ氨鏈夊瓙椤�** 鈬� 瑕嗙洊鍙嶈�屾瘮涓嶈鐩栨洿宸� | 瑙勫垯 10 琛ヤ竴鏉$‖瑕佹眰锛氬垎缁勮〃鍐� `columns` 蹇呴』淇濈暀 `瀛愰」={{item.group.childName}}`锛屽苟璇存竻婕忔帀鍚庡瓙椤瑰悕鏁村垪娑堝け | 5/5 淇濈暀锛屼笖涓庡師浠� 6 鍒�**閫愬垪瀵归綈** |
+| 绗� 2 杞� | `headerSpans` 鎶娿�岀粨璁恒�嶅垪鐨勮法鍒楁暟骞惰繘浜嗐�屾楠岀粨鏋溿�嶏紙鍐欐垚 `妫�楠岀粨鏋淾6`锛夛紝琛ㄥご浼氭妸缁撹鍒楃敾鍒版楠岀粨鏋滃簳涓嬶紱鍙︽湁涓�杞悎璁� 8 鈮� 鍒楁暟 7 | 瑙勫垯 11 琛ヤ竴鏉★細缁撹/鍒ゅ畾鍒楀湪鍘熶欢閲屼笉灞炰簬涓婂眰鍒嗙粍鏍囬鏃�**瑕佸崟鐙垚娈�** | 5/5 杈撳嚭 `妫�楠岀粨鏋淾5|缁撹^1` |
+| 绗� 3 杞� | `SampleInfo.fields` 閲�**5/5 杞兘缂栭�犱簡鎶ュ憡瀛楁**锛坄{{report.productionDate}}` / `{{report.expiryDate}}` / `{{report.potatoVariety}}`锛� | 鏍瑰洜鏄鍒� 7 鍙銆屼笉璁哥紪閫犮�嶅嵈**涓嶈鏈夊摢浜涢敭**銆傛柊澧炪�愭姤鍛婁笂涓嬫枃鐨勫瓧娈点�戝潡锛屾妸 23 涓彲缁戝畾閿叏閲忓垪鍑� | 5/5 鍏ㄩ儴鍚堟硶锛屼笉瀛樺湪鐨勬爮鐩敼涓哄啓杩� `summary` 璇存槑 |
+
+**涓変釜缂洪櫡鐨勫叡鍚岀偣**锛氶兘涓嶆槸妯″瀷銆屼笉鍚瘽銆嶏紝鑰屾槸鎻愮ず璇�**鍙粰浜嗙浠ゃ�佹病缁欏彲閫夐」**銆�
+鍒楃殑鐧藉悕鍗曪紙瑙勫垯 10锛夋湰鏉ュ氨缁欎簡锛屾墍浠� `columns` 鐨勭粦瀹氳矾寰� 5/5 鍚堟硶鈥斺�斿弽璇佷簡銆屾憡寮�鍙�夐泦鍚堛�嶆墠鏄湁鏁堝仛娉曘��
+
+### 26.5 涓轰粈涔堣浠� `ReportFields` 鍙嶅皠鐢熸垚鐧藉悕鍗曪紝鑰屼笉鏄墜鍐欏父閲�
+
+鎵嬪啓鐨勬竻鍗曚細鍦ㄦ湁浜虹粰鎶ュ憡鍔犲瓧娈垫椂**闈欓粯杩囨湡**锛岃�屾ā鍨嬫鏄潬杩欎唤娓呭崟鎵嶇煡閬� `{{report.xxx}}` 鑳藉啓浠�涔堬細
+娓呭崟閲屽皯涓�涓敭锛岀敤鎴峰氨浼氬湪鎶ュ憡涓婄湅鍒颁竴鐗囩┖鐧藉姞涓�鏉″憡璀︼紝涓�**鐪嬩笉鍑烘槸鎻愮ず璇嶈繃鏈熼�犳垚鐨�**銆�
+鎵�浠ョ櫧鍚嶅崟鐢� `ReportFields` 鐨勫瓧娈靛悕鍙嶅皠鐢熸垚锛堝悓妯″潡锛屾棤璺ㄦā鍧楄�﹀悎锛夛紝鍗曟祴**閫愪釜瀛楁鏍稿**鑰屼笉鏄娊鏌ヤ袱涓��
+
+### 26.6 楠岃瘉缁撹
+
+| 楠岃瘉椤� | 缁撴灉 |
+|---|---|
+| 瀛橀噺妯℃澘瀛楄妭涓�鑷� | **12 缁勫睘鎬х粍鍚堝叏閮ㄩ�愬瓧鑺傜浉鍚�**锛坰ha256 涓�鑷达級锛屽苟鍐荤粨鎴愭帰閽堥噷鐨勪袱涓寚绾瑰父閲� |
+| 鍓嶇鎺㈤拡 `verify-columns.ts` | **83 鏉℃柇瑷�鍏ㄧ豢**锛堝垪瑕嗙洊鐨勮惤鍦颁綅缃�佷袱绾ц〃澶寸殑 colspan銆侀獙璇佹枃妗堛�佹牱鍝佸瓧娈点�乆SS 杞箟銆佽В鏋愬櫒杈圭晫銆乤iHint 涓庢椿娓呭崟濂戠害锛� |
+| 鍚庣鍗曟祴 | `yudao-module-qcreport` **147/147 鍏ㄧ豢**锛堟柊澧� 4 鏉★細2 鏉℃彁绀鸿瘝瑙勫垯鏂█ + 1 鏉$櫧鍚嶅崟鍏ㄩ噺鏍稿 + 1 鏉� checkMethod 鏄犲皠锛� |
+| 鍓嶇绫诲瀷妫�鏌� | `components/quality` 涓� **0 涓被鍨嬮敊璇�**锛堟棦鏈� 36 涓湪 `src/views/wls|im|erp`锛屼笌鏈疆鏃犲叧锛� |
+| 鐩磋繛鐪熸ā鍨� | 閫夊瀷 **5/5**銆佸垪涓庡師浠剁殑 6 鍒�**閫愬垪瀵归綈 5/5**銆乣headerSpans` 姝g‘ **5/5**銆佹牱鍝佸瓧娈甸敭鍚堟硶 **5/5** |
+
+**宸查獙璇� / 鏈獙璇佸垎寮�澹版槑**锛�
+
+- 鉁� 宸查獙璇侊細涓婅堪浜旈」锛涗互鍙娿�屾彁绀鸿瘝 + 鍓嶇缁勪欢銆嶈繖鏉¢摼璺殑**鐩磋繛**琛屼负銆�
+- 馃煛 鏈獙璇侊細**HTTP 鍏ㄩ摼璺笌 UI 楠屾敹灏氭湭璺�**鈥斺�旀敼鐨勬槸鎻愮ず璇嶏紙鍚庣锛変笌鍓嶇缁勪欢锛屽悗绔渶**閲嶅惎**鎵嶇敓鏁堛��
+ 閲嶅惎鍚庨渶鍦ㄧ湡瀹� AI 瀵煎叆寮圭獥閲岀‘璁わ細妫�楠岃〃鍑虹幇銆屾娴嬫柟娉� / 鏍囧噯瑕佹眰 / 缁撹銆嶅垪涓庝袱绾ц〃澶淬�佹牱鍝佷俊鎭潡鎸夊師浠剁殑瀛楁灞曠ず銆�
+ `problems` 閲�**娌℃湁**銆岀粦瀹氬彇涓嶅埌鍊笺�嶅憡璀︺��
+- 鈿� 宸茬煡杈圭晫锛氭墜宸ヤ繚瀛樿矾寰勪笉璺戞牎楠岋紙26.3锛夛紱琛ㄦ牸鐨勩�屽崟浣嶃�嶅垪鍦ㄥ師浠堕噷娌℃湁瀵瑰簲鍒楁椂 AI 鍋跺皵浼氬鍔犱竴鍒楃┖鍒楋紙鏃犲锛岀敤鎴峰湪璁捐鍣ㄩ噷鍒犳帀鍗冲彲锛夈��
+
+### 26.7 鏈仛
+
+- 骞抽摵 `QualityTable` 鐨� `columns`锛沗unit_text` 涓嶆帴鐣岄潰锛汦xcel銆屾潯鐩被鍨嬨�嶅垪锛堝潎瑙� 26.1 涓� 搂22锛�
+- 璁捐鍣ㄦ墜宸ヤ繚瀛樿矾寰勭殑鏍¢獙闂稿彛锛堟棦鏈夌己鍙o紝闇�鍗曠嫭鍐崇瓥鏄惁瑕佸仛鎴愬叏妯℃澘鏍¢獙锛�
+- 鏈姩 `HtmlRenderer` / `BASE_CSS` / `CanvasSafety`锛堟湰杞牳鏌ュ悗纭鏃犻渶鏀癸細娓叉煋鍣ㄦ棤鎸夌粍浠剁被鍨嬪垎鏀�佺櫧鍚嶅崟鏈氨鏀捐 `colspan`/`rowspan`锛�
+- 鏈姩 `docs/sql/config_export_all_*.sql`锛堟棤琛ㄧ粨鏋勫彉鏇达級
+
+## 浜屽崄涓冦�佺敾甯冩帓鐗堜笌琛ㄥご銆屽浜嗕竴涓粨璁恒�嶏細涓ゅ鐙珛缂洪櫡锛�2026-09-19 缁級
+
+鐢ㄦ埛鍦ㄧ湡瀹� UI 閲岃窇瀹� AI 瀵煎叆鍚庡弽棣堬細**銆屽浜嗕竴涓粨璁猴紝浼樺寲涓�涓嬫帓鐗堛��**銆�
+杩欎笉鏄竴鏉¢棶棰橈紝鏄袱鏉′簰涓嶇浉骞茬殑缂洪櫡鍙犲湪鍚屼竴寮犺〃涓娿��
+
+### 27.1 鐜拌薄涓庡彇璇�
+
+| # | 鐜拌薄 | 鍙栬瘉 |
+|---|---|---|
+| A | 琛ㄥご鍙崇銆岀粨璁恒�嶄簩瀛�**涓婁笅鍚勫嵃涓�娆�** | 妯℃澘 33 鐨� AI 鑽夌閲� `columns` 鏈垪鍐欑殑鏄� `缁撹={{item.resultText}}`锛宍headerSpans` 鏈鍐欑殑鏄� `缁撹^1` 鈥斺�� 涓ゅ眰鍚勫嚭涓�鏍笺�岀粨璁恒�� |
+| B | 琛ㄤ綋**鏁翠綋宸︾Щ涓�鏍�**锛屾湯鍒楀彧鍓╄〃澶淬�佽鎸ゆ垚绔栨帓缁嗘潯 | 澶嶅埢 `GroupedQualityTable.buildContent` 鐨勪骇鐗╁崟鐙覆鏌擄細缁勫悕鏍� `display:none`銆佸 0锛屾湯鍒楀 64px锛屽悗 5 鏍兼暣浣撳乏绉汇�傚垪鐨勯敊浣嶄笌鐢ㄦ埛鎴浘閫愭牸涓�鑷� |
+
+B 鐨勬垚鍥狅細缁勫悕鏍煎啓浣� `hidden="{{item.group.hidden}}"`銆�**鐢诲竷涓嶈窇缁戝畾**锛屾祻瑙堝櫒鐪嬪埌銆屾湁 `hidden` 灞炴�с�嶅氨鎴愮珛 鈬� 璇ユ牸 `display:none`锛岃繖涓�琛屽悗闈㈢殑鏍兼暣浣撳乏绉汇�傝繖鏄釜涓�鐩村瓨鍦ㄧ殑鑰佽涓猴紝鍙槸浠庡墠 AI 浠庢病浜у嚭杩囧垎缁勮〃锛屾墍浠ユ病鏆撮湶銆�
+
+A 鐨勬垚鍥犳槸璇硶缂哄彛锛氬師浠剁殑銆岀粨璁恒�嶅湪鍘熶欢閲屾槸**涓�鏍肩旱鍚戝悎骞躲�佽嚜宸卞崰婊′笂涓嬩袱灞傝〃澶�**锛堟彁鍙栨枃鏈噷琛ㄧ幇涓轰笅灞傝〃澶撮偅涓�鏍煎啓鐫�銆屸啈鍚屼笂銆嶏級銆備絾 `headerSpans` 鐨勮娉�**涓嶅厑璁哥┖鏍囬**锛坄parseHeaderSpans` 瀵圭┖鏍囬鐩存帴鎶ラ敊锛夛紝琛ㄨ揪涓嶅嚭銆屼笂鏍肩暀绌恒�嶏紝浜庢槸妯″瀷鍙兘鎶婂垪鍚嶅啀鍐欎竴閬� 鈥斺�� 灏遍噸澶嶄簡銆�
+
+### 27.2 淇硶
+
+| # | 鏀瑰姩 | 浣嶇疆 |
+|---|---|---|
+| A | 鏂板鍒ゆ嵁锛氭煇娈佃法 1 鍒椼�佷笖**璇ユ鏍囬涓庡畠姝d笅鏂归偅涓�鍒楃殑鍒楁爣棰樹竴瀛椾笉宸�** 鈬� 璁ゅ畾鏄旱鍚戝悎骞舵牸锛屽嚭 `rowspan="2"`锛屼笅灞傝〃澶�**璺宠繃璇ュ垪** | `components/quality/inspection/grouped-quality-table.ts` |
+| B | 鍙湪**鐢诲竷鏂囨。鍐�**娉ㄥ叆涓�鏉″紩瀵兼牱寮� `td[hidden*="{{"] { display: table-cell; }`锛屾妸銆屽�艰繕鍋滃湪鍗犱綅绗︺�嶇殑 `hidden` 杩樺師鎴愬彲瑙佹牸 | `views/mes/qc/report/template/designer/use-designer.ts` |
+| 鈥� | 鎻愮ず璇嶈鍒� 11 琛ヤ袱鏉★細璇ユ鏍囬蹇呴』涓庡垪鏍囬**涓�瀛椾笉宸�**锛�**涓嶈鑷綔涓诲紶鎶婅鍒楁敼鍚嶆垚杩戜箟璇�**锛堝苟鍐欐槑鍚庢灉锛� | `QcReportTemplatePromptBuilder` 瑙勫垯 11 |
+| 鈥� | 鍒嗙粍琛ㄧ殑 `aiHint` 涓� `headerSpans` 鐨勫睘鎬ц鏄庡悓姝ヨˉ涓婅繖鏉″舰鎬� | 鍚屼笂缁勪欢 |
+
+**涓轰粈涔堝垽鎹敤銆屾爣棰樹竴瀛椾笉宸�嶈�屼笉鏄�屾帓鍦ㄦ渶鍚庝竴鍒椼��**锛氭帓鍦ㄦ渶鍚庡彧鏄阀鍚堬紝鍒ゆ嵁鏈韩寰楄鏄庡師浠堕噷閭d袱鏍兼槸鍚屼竴涓牸銆傚疄娴嬩篃璇佹槑杩欎釜鍒ゆ嵁鍙妯″瀷绋冲畾婊¤冻锛堣 27.4锛夈��
+
+B 鐨勬牱寮�**鍙姞鍦ㄧ敾甯冪殑 iframe 閲�**锛屼笉鍐欒繘 Schema銆佷笉闅忔ā鏉夸繚瀛橈紱鍑轰欢鏃惰鍊煎凡瑙f垚绌轰覆鎴� `hidden`锛岄�夋嫨鍣ㄤ笉鍐嶅懡涓紝**鎶ュ憡娓叉煋涓�涓瓧閮戒笉鍙楀奖鍝�**銆�
+鏍峰紡鏀剁獎鍒� `td`锛氳灞炴�х洰鍓嶅彧鐢ㄥ湪鍗曞厓鏍间笂锛屽摢澶╃湡鐢ㄥ埌鍒殑鏍囩涔熻鎸夐偅涓爣绛剧殑 `display` 鍚勫啓涓�鏉★紝涓嶈兘涓�鏉¢�氱敤瑙勫垯绯婅繃鍘汇��
+
+### 27.3 鎻愮ず璇嶄负浠�涔堣鍐欏埌銆屼笉瑕佹敼鍚嶃�嶈繖涔堢粏
+
+琛ヤ笂銆屼袱杈逛竴瀛椾笉宸�嶅悗澶嶈窇锛屼粛鏈� **1/5 杞�**鍑洪棶棰橈細妯″瀷鎶� `columns` 閲岄偅涓�鍒楁敼鍚嶆垚銆屽垽瀹氥�嶏紝`headerSpans` 鍗磋繕鍐欑潃鍘熶欢涓婄殑銆岀粨璁恒�嶏紝涓よ竟瀵逛笉涓婏紝鍙堥��鍥炲幓澶氬嵃涓�涓〃澶淬��
+鏍瑰洜鏄悓涓�鏉′俊鎭湪鎻愮ず璇嶉噷鍑虹幇涓ゆ锛堝師浠惰〃澶淬�乣columns`锛夋椂妯″瀷浼氬悇鍐欏悇鐨勩�傝ˉ涓娿�屼笉瑕佽嚜浣滀富寮犳妸瀹冩敼鍚嶆垚杩戜箟璇嶃�嶅苟鍐欐槑鍚庢灉鍚庯紝澶嶈窇 **5/5 杞悎鎴愪负涓�鏍�**銆�
+
+### 27.4 楠岃瘉缁撹
+
+| 楠岃瘉椤� | 缁撴灉 |
+|---|---|
+| 鍓嶇鎺㈤拡 `verify-columns.ts` | 鍏ㄧ豢锛堟柊澧� 7 鏉$旱鍚戝悎骞舵柇瑷� + 1 鏉� hint 鏂█锛夛細鍚堟垚鍚� `rowspan="2"` 鍦ㄥ満銆佷笉鍐嶅嚭 `colspan="1"`銆併�岀粨璁恒�嶅叏鏂�**鍙嵃涓�娆�**銆佷笂 2 鏍� + 涓� 5 鏍� = 7锛�**鍙嶄緥**锛氫笂鏍间笌鍒楀悕涓嶅悓瀛楁椂涓嶅嚭 `rowspan`锛堝垽鎹槸銆屼竴瀛椾笉宸�嶈�屼笉鏄�屽湪鏈�鍚庛�嶏級 |
+| 鍚庣鍗曟祴 | `yudao-module-qcreport` **147/147 鍏ㄧ豢**锛堟柊澧� 2 鏉℃彁绀鸿瘝鏂█锛� |
+| 鍓嶇绫诲瀷妫�鏌� | 鏈疆鐩稿叧鏂囦欢 **0 涓被鍨嬮敊璇�**锛堟棦鏈� 36 涓粛鍦� `src/views/wls|im|erp`锛屼笌鏈疆鏃犲叧锛� |
+| 娓叉煋澶嶅埢瀵圭収 | 淇墠锛氱粨璁哄嵃涓ゆ + 鏁磋宸︾Щ + 鏈垪 64px 绔栨帓锛涗慨鍚庯細`缁撹` 涓�鏍艰法涓よ銆佽〃浣撻�愭牸瀵归綈 |
+| 鐩磋繛鐪熸ā鍨� 5 杞� | 閫夊瀷 **5/5** 鍒嗙粍琛紱`columns` 6~7 鍒椼�佽法鍒楁暟鍚堣=鍒楁暟 **5/5**锛涙湯娈垫爣棰樹笌鏈垪鍒楀悕涓�鑷� **5/5** 鈬� **绾靛悜鍚堟垚 5/5**锛涙牱鍝佸瓧娈甸敭鍚堟硶 **5/5** |
+
+**宸查獙璇� / 鏈獙璇佸垎寮�澹版槑**锛�
+
+- 鉁� 宸查獙璇侊細鎺㈤拡銆佸悗绔崟娴嬨�佺被鍨嬫鏌ャ�佹覆鏌撳鍒诲鐓с�佺洿杩� 5 杞��
+- 馃煛 鏈獙璇侊細**HTTP 鍏ㄩ摼璺笌 UI 楠屾敹鏈窇** 鈥斺�� 鎻愮ず璇嶆敼鍔ㄥ湪鍚庣绫婚噷锛岄渶**閲嶅惎鍚庣**鎵嶇敓鏁堬紱缁勪欢涓� `aiHint` 鏀瑰姩鍦ㄥ墠绔紝鐑洿鏂板嵆鍙��
+ 閲嶅惎鍚庨渶鍦ㄧ湡瀹� AI 瀵煎叆寮圭獥閲岀‘璁わ細琛ㄥご銆岀粨璁恒�嶅彧鍑虹幇涓�娆′笖涓轰竴鏍艰法涓よ銆佽〃浣撲笌琛ㄥご閫愭牸瀵归綈銆佹湯鍒椾笉鍐嶈鎸ゆ垚缁嗘潯銆�
+ 鍙﹀**瀛橀噺妯℃澘 33 鐨勮崏绋夸笉浼氳嚜鍔ㄥ彉濂�**鈥斺�斿畠宸茬粡鎶� `缁撹^1` 瀛樿繘鐢诲竷浜嗭紝闇�閲嶆柊瀵煎叆鎴栨墜宸ユ敼锛涗絾绾靛悜鍚堝苟鍒ゆ嵁鏄覆鏌撴湡鐢熸晥鐨勶紝鍙 `columns` 鏈垪涓庢湯娈垫爣棰樹竴鑷达紝**宸蹭繚瀛樼殑妯℃澘閲嶆柊鍑轰欢涔熶細鑷姩鍚堟垚涓�鏍�**銆�
+
+### 27.5 鏈仛
+
+- 娌″姩 `parseHeaderSpans` 鐨勩�屽悎璁″繀椤荤瓑浜庡垪鏁般�嶈繖鏉$‖瑙勫垯锛堟柊澧炵殑绾靛悜鍚堝苟鏍兼寜 1 鍒楄鍏ュ悎璁★紝瑙勫垯涓嶅彉锛�
+- 娌″姩鎶ュ憡渚у彇鏁般�乣HtmlRenderer`銆乣BASE_CSS`銆乣CanvasSafety`
+- 娌″仛銆屼笂鏍肩湡姝g殑 rowspan 琛ㄥご缂栬緫銆嶁�斺�旇璁″櫒灞炴�ч潰鏉夸粛鏄墜鍐欏瓧绗︿覆锛屾湰杞彧淇濊瘉瀹冩覆鏌撴纭�
+
+## 浜屽崄鍏�佽嚜瀹氬垪鐨勫垪瀹斤細闀垮崰浣嶇鎶婅〃鏍兼拺鍑虹焊寮狅紙2026-09-19 缁級
+
+### 28.1 鐜拌薄涓庡彇璇�
+
+鐢ㄦ埛鍙嶉锛堟壙鎺ョ浜屽崄涓冭妭锛岄噸鍚悗绔悗澶嶇湅鍚屼竴寮犳ā鏉匡級锛氥�岀粨璁哄ソ鍍忚秴鍑哄幓浜嗭紝鍍忎釜鍔炴硶浼樺寲涓�涓嬨�嶏紝闄勮璁″櫒鎴浘銆�
+
+鎴浘閲岀殑琛ㄧ幇涓� 27 鑺備慨瀹岀殑褰㈡�佷笉鍚岋細琛ㄥご銆岀粨璁恒��**鍙嚭鐜颁竴娆�**锛�27 鑺傜殑绾靛悜鍚堝苟宸茬敓鏁堬級锛屼絾閭d竴鍒楄鎸ゆ垚浜屽崄鍑犱釜鍍忕礌銆佷袱涓瓧绔栫潃鎺掞紝鏁村垪钀藉埌绾稿紶澶栭潰銆�
+
+鎶婃ā鍨嬪疄闄呬骇鍑虹殑灞炴�э紙`D:/qcl-tmp/bs-direct-out.json` 绗� 5 杞紝涓庢埅鍥鹃�愬瓧涓�鑷达級缂栬瘧鎴� HTML锛屽湪 Chromium 閲屾寜 A4 姝f枃瀹� 672px 閲忥細
+
+| 鍦烘櫙 | 鏁磋〃瀹� | 婧㈠嚭 | 鏈垪瀹� |
+|---|---|---|---|
+| 鑷畾 6 鍒楋紝鍊间负鍗犱綅绗� | **810px** | **138px** | **29px** |
+| 鍚屼笂锛屽�兼崲鎴愮湡瀹炴暟鎹紙姘村垎/20鐩笂/鐑樼骞茬嚗娉�/鈮�14.0/13.2/鍚堟牸锛� | 672px | 0 | 86px |
+| 鍒嗙粍琛�**榛樿** 7 鍒楋紝鍊间负鍗犱綅绗� | 807px | 135px | 116px |
+
+鏍瑰洜涓ゅ眰锛�
+
+1. **鍒楀鐢辨渶灏忓唴瀹瑰搴﹀�掓帹**銆傝嚜瀹氬垪涓�涓搴﹀0鏄庨兘娌℃湁锛堥粯璁ゅ垪鏈夛細搴忓彿 48px銆佹娴嬭姹� 30%銆佸疄娴嬪�� 26%鈥︹�︼級锛屾暣琛ㄥ垪瀹藉彧鑳界敱鍚勫垪鐨勬渶灏忓唴瀹瑰搴﹀喅瀹氾紱鑰屽�兼槸 `{{item.standardValue}}` 杩欑被涓嶅惈绌烘牸鐨勯暱涓诧紝鏈�灏忓唴瀹瑰搴﹀氨鏄暣涓查暱搴︼紝鍏垪涓�鍔犲氨瓒呰繃 672px銆�
+2. **鍑轰欢鏃跺�兼湰鏉ュ氨鐭�**锛屾墍浠ヨ繖涓昏鏄璁″櫒閲岀殑瑙傛劅闂鈥斺�斾絾鎾戠牬绾稿紶鐨勪复鐣岀偣鍦ㄧ湡瀹為暱鍊硷紙濡傘�屸墹0.5 mg/kg锛堜互骞插熀璁★級銆嶏級涓婁竴鏍蜂細韪╁埌锛屼笉鏄函璁捐鍣ㄩ棶棰樸��
+
+### 28.2 淇硶锛歚overflow-wrap:anywhere`锛屽彧鎸傚湪鑷畾鍒椾笂
+
+`overflow-wrap:anywhere` 浼氬弬涓庢渶灏忓唴瀹瑰搴﹁绠楋紙`break-word` 涓嶄細锛夛紝鍒楀鍥犳涓嶅啀琚暱涓茬粦鏋躲��
+
+鍏抽敭鍙栬垗鏄�**鍙粰鑷畾鍒楀姞**锛�
+
+| 鍔犲湪鍝� | 6 鍒楄嚜瀹氳〃 | 榛樿 7 鍒楀垎缁勮〃 |
+|---|---|---|
+| 涓嶅姞 | 810px銆佹孩鍑� 138px | 807px銆佹孩鍑� 135px |
+| 鍔� | 672px銆佷笉婧㈠嚭 | 672px銆�**浣嗐�屾楠岄」鐩�嶃�屽瓙椤广�嶈鎸ゅ埌 32/33px銆佽楂� 59鈫�283px** |
+
+榛樿鍒楃殑瀹藉害澹版槑宸茬粡瀹氫綇鐗堥潰锛屽啀鍙犱竴鏉℃姌琛屽弽鑰屾洿宸紙瀹炴祴锛夈�傛墍浠ヨ繖鏉″彧鎸傚湪鑷畾鍒椾笂锛�**娌℃湁 `columns` 鐨勫瓨閲忔ā鏉夸骇鐗╅�愬瓧涓嶅彉**锛堟帰閽� sha256 瀹堢潃锛岀浜岃妭鐨� `GROUPED_TABLE_BASELINE` 鏈彉锛夈��
+
+椤哄甫鏍稿疄锛氬叏搴� `qc_report_template_version` 閲� `data-qc-columns` / `data-qc-headerSpans` / `data-qc-fields` 鍛戒腑鏁�**鍧囦负 0**锛堣繖涓変釜灞炴�ф槸鏈疆鎵嶈繘鐨勶級锛屾墍浠ヨ繖鏉℃敼鍔ㄥ鏃㈡湁宸插彂甯冩姤鍛婇浂褰卞搷銆�
+
+### 28.3 涓轰粈涔堜笉鏄�屽湪鐢诲竷涓婂啀琛ヤ竴鏉″紩瀵兼牱寮忋��
+
+绗簩鍗佷竷鑺傞偅鏉$敾甯冨紩瀵兼牱寮忓鐞嗙殑鏄�**缁戝畾涓嶆眰鍊�**锛坄hidden` 琚綋鐪燂級鈥斺�斿嚭浠朵晶鍚屼竴涓睘鎬т細瑙f垚绌轰覆銆佽涓轰竴鑷达紝灞炰簬绾璁″櫒鍋囪薄锛屾墍浠ユ斁鐢诲竷涓婃槸骞插噣鐨勩��
+
+瀹藉害杩欎欢浜嬩笉涓�鏍凤細鍑轰欢渚у悓鏍蜂細韪╋紙鐪熷疄闀垮�硷級锛屼袱渚ч渶瑕�**鍚屼竴濂楄鍒�**鎵嶈兘鎵�瑙佸嵆鎵�寰椼�傝嫢鍙湪鐢诲竷涓婂姞鎶樿锛岀敾甯冩寜鎶樿鍚庣殑瀹藉害鍒嗗竷銆佸嚭浠舵寜鏈�灏忓唴瀹瑰搴﹀垎甯冿紝鍙嶈�屽埗閫犲嚭鏂扮殑銆岃璁″櫒涓庡嚭浠朵笉涓�鏍枫�嶃�傛墍浠ヨ繖娆″啓杩涚粍浠朵骇鐗╅噷銆�
+
+### 28.4 楠岃瘉
+
+| 椤� | 缁撴灉 |
+|---|---|
+| `.qc-conformance/verify-columns.ts` 鏂板 3c 娈� | 鍏ㄧ豢锛氳嚜瀹氬垪 6 鏍煎叏甯� `overflow-wrap:anywhere`锛涢粯璁ゅ垪涓嶅甫 |
+| `verify-columns.ts` 绗� 1 鑺傚瓧鑺傛寚绾� | `GROUPED_TABLE_BASELINE` / `SAMPLE_INFO_BASELINE` **鏈彉** 鈬� 榛樿鍒椾骇鐗╅�愬瓧涓嶅彉 |
+| Chromium 瀹炴祴锛�672px 姝f枃瀹斤級 | 鑷畾 6 鍒楋細淇墠 810px/婧㈠嚭 138px/鏈垪 29px 鈫� 淇悗 672px/涓嶆孩鍑�/鏈垪 97px |
+| 鐪熷疄鏁版嵁瀵圭収 | 淇墠淇悗鍧� 672px锛屽垪瀹藉垎甯冧笉鍙� |
+| 娓叉煋澶嶅埢鎴浘 | `缁撹` 涓�鏍艰法涓よ銆佽〃浣撻�愭牸瀵归綈銆佽〃鏍艰惤鍦ㄧ焊寮犲唴锛坄D:/qcl-tmp/gqt-final.png`锛� |
+| 瑁呴厤寰�杩� | `assembleQualityCanvas` 浜х墿鍐� `overflow-wrap` / `anywhere` 鍧囧湪锛宍skipped` / `problems` 鍧囩┖ 鈬� 鏍峰紡涓嶄細琚� GrapesJS 涓㈠純 |
+| 鍓嶇绫诲瀷妫�鏌� | 鏈疆鐩稿叧鏂囦欢 **0 涓被鍨嬮敊璇�**锛堟棦鏈� 316 涓笌鍓嶅嚑杞悓閲忕骇锛屽潎鍦� `src/views/wls\|im\|erp` 绛夋棤鍏崇洰褰曪級 |
+
+**宸查獙璇� / 鏈獙璇佸垎寮�澹版槑**锛�
+
+- 鉁� 宸查獙璇侊細鎺㈤拡銆佸瓧鑺傛寚绾广�丆hromium 瀹炴祴閲忓銆佹覆鏌撳鍒绘埅鍥俱�佽閰嶅線杩斻�佺被鍨嬫鏌ャ�侴rapesJS 鑷韩纭疄鏀跺綍浜� `overflow-wrap`锛坉ist 鍐呭懡涓級銆�
+- 馃煛 鏈獙璇侊細**璁捐鍣ㄩ噷鐨勭湡瀹炶鎰熸湭澶嶈窇**銆傛湰杞敼鍔ㄥ湪鍓嶇锛堢粍浠朵骇鐗╋級锛岀儹鏇存柊鍗冲彲鐢熸晥锛屾棤闇�閲嶅惎鍚庣锛涗絾鎴浘閲岄偅浠界敾甯冩槸**鏈繚瀛樼殑 AI 瀵煎叆鑽夌**锛屽埛鏂板悗鐪嬪埌鐨勬槸搴撻噷鐨勬棫 v1.0锛堝钩閾� `QualityTable`锛屾病鏈夎嚜瀹氫箟鍒楋級锛岄渶瑕�**閲嶆柊璺戜竴娆� AI 瀵煎叆**鎵嶈兘澶嶇幇鏂板舰鎬併��
+- 鍙︽敞锛氭ā鏉� 33 搴撻噷鐨� v1.0 鑽夌锛坄qc_report_template_version.id=21`锛変粛鏄棫鐨勫钩閾鸿〃锛屼笌鏈疆鏃犲叧銆�
+
+### 28.5 鏈仛
+
+- 娌″姩榛樿鍒楃殑瀹藉害澹版槑锛堥偅浼氳瀛橀噺妯℃澘鐨勬帓鐗堝彉鍖栵級
+- 娌$粰鑷畾鍒楀姞瀹藉害璇硶锛堝闇�銆岃繖涓�鍒楃獎涓�鐐广�嶅緱鍐嶆墿 `columns` 鐨勮娉曪紝鏄嫭绔嬪喅绛栵級
+- 娌″姩 `HtmlRenderer` / `BASE_CSS` / `CanvasSafety` / 鎶ュ憡渚у彇鏁�
+- 娌$浜屽崄涓冭妭閬楃暀鐨勩�屾墜宸ョ紪杈戝悗淇濆瓨涓嶈窇鏍¢獙銆嶆棦鏈夌己鍙�
+
+## 浜屽崄涔濄�佺‘璁ゃ�屽悓缁勫瓙椤圭殑椤圭洰鍒椾細涓嶄細鍚堝苟銆嶏紙2026-09-19 缁級
+
+鐢ㄦ埛闂細灞炰簬鍚屼竴涓」鐩殑瀛愰」锛屻�岄」鐩�嶅垪浼氫笉浼氱旱鍚戝悎骞躲�傜粨璁�**浼�**锛屼絾鍙湪**鍑轰欢**锛圚TML / PDF锛夐噷鍚堝苟锛岃璁″櫒鐢诲竷涓婄湅涓嶈銆傛湰杞�**娌℃敼浠讳綍鐢熶骇浠g爜**锛屽彧琛ヤ簡瀵规媿瑕嗙洊 + 鍙栬瘉銆�
+
+### 29.1 鍚堝苟鎬庝箞鍙戠敓鐨勶紙涓夋鍚勫綊璋侊級
+
+| 鐜妭 | 璋佸仛 | 鍋氫粈涔� |
+|---|---|---|
+| 鏍囧嚭鍚堝苟鍒� | 妯℃澘 | `columns` 閲岃鍒楁爣棰樺甫 `#`锛宍buildContent` 鍙湪杩欎竴鏍煎啓 `rowspan="{{item.group.span}}"` 涓� `hidden="{{item.group.hidden}}"` |
+| 绠楀嚭鍚堝苟鍑犺 | 鍚庣 `MesQcReportApiImpl.java:331-351` | 缁勭殑绗竴琛� `span = entryRows.size()`銆乣hidden = ""`锛涚粍鍐呭叾浣欒 `span = 1`銆乣hidden = "hidden"` |
+| 娓叉垚瑙嗚鍚堝苟 | 涓や晶娓叉煋鍣� `render.ts:242` / `HtmlRenderer.java:222` | 閮芥寜銆屾眰鍊肩粨鏋滀负绌轰覆 鈬� 涓嶈緭鍑鸿灞炴�с�嶅鐞嗭細缁勫ご琛� `hidden` 娑堝け銆佸甫 `rowspan` 鏄剧ず锛涘叾浣欒 `hidden="hidden"` 璁╂暣鏍� `display:none` |
+
+涓夋潯鍙e緞锛氬悎骞惰鏁版槸**鏈崟璇ョ粍瀹為檯琛屾暟**鑰岄潪涓绘暟鎹瓙椤规暟锛涜缁勬湰鍗曟棤瀛愰」琛屽垯 `span=1` 涓嶅悎骞讹紙鐙珛椤瑰悓鐞嗭級锛沗hidden` 蹇呴』鏄瓧绗︿覆锛岄潬銆屽睘鎬у湪涓嶅湪銆嶈捣浣滅敤锛坄hidden="false"` 鐓ф牱闅愯棌锛夈��
+
+### 29.2 涓轰粈涔堣繖杞墠纭锛氳嚜瀹氬垪鍒嗘敮涓�鐩存槸鐩插尯
+
+绗� 1~3 鑺傜殑鎺㈤拡鎵撶殑鏄�**榛樿鍒�**鍒嗘敮锛坄tableSchema()` 鎵嬪伐鍚屾瀯锛夛紝鑰� **AI 瀵煎叆涓�寰嬪~ `columns`**锛岃蛋鐨勬槸 `effectiveColumns` 鐨勫彟涓�鏉″垎鏀�備袱鏉″垎鏀悇鑷嫾 `<tr>`锛屽悎骞跺睘鎬ф湁娌℃湁璺熺潃璧帮紝榛樿鍒楃豢涓嶄唬琛ㄨ嚜瀹氬垪缁库�斺�擿verify-grouped-table.ts` 閲屽師鍏堝鑷畾鍒楁槸**闆惰鐩�**銆�
+
+瀹為檯璇荤爜鐪嬶細鑷畾鍒楀垎鏀悓鏍风敤 `column.merge ? GROUP_CELL_ATTRS : ''`锛宍merge` 鏉ヨ嚜 `parseColumnSpec` 鐨� `#` 鍓嶇紑锛屾墍浠ユ槸閫氱殑銆備絾杩欐槸銆岃鐮佹帹瀹氥�嶏紝涓嶆槸鍙栬瘉锛屾湰杞ˉ涓娿��
+
+### 29.3 鏈疆鐨勫彇璇�
+
+| 椤� | 鍋氭硶 | 缁撴灉 |
+|---|---|---|
+| 鑷畾鍒楃粨鏋� | 鐢ㄦā鍨嬬湡瀹炰骇鍑猴紙妯℃澘 33 鑽夌鏈�鍚庝竴杞紝`#椤圭洰=鈥︼綔鈥︼綔缁撹=鈥銆乣headerSpans=妫�楠岀粨鏋淾5锝滅粨璁篰1`锛夐�愬瓧鍠� `assembleQualityCanvas` | `[#椤圭洰]` 鏍煎甫 `rowspan="{{item.group.span}}"`+`hidden="{{item.group.hidden}}"`锛屽叏琛ㄥ彧姝や竴鏍煎甫 `rowspan`锛涗笂灞� `妫�楠岀粨鏋渀 `colspan=5`銆乣缁撹` `rowspan=2`銆佷笅灞傝〃澶� 5 鍒� |
+| 璐熷悜瀵圭収 | 鍚屼竴浠� `columns` 鍘绘帀 `#` | 涓ゅ缁戝畾鏁翠釜娑堝け銆佸垪鏁颁笌缁戝畾涓嶅彉 鈬� `#` 涓嶆槸瑁呴グ锛屾湁娌℃湁瀹冪粨鏋滅‘瀹炰笉鍚� |
+| 娓叉煋璇箟 | `verify-grouped-table.ts` 绗� 2/3 鑺傦紙鏃㈡湁锛屾湰杞噸璺戯級 | `hidden=""` 鐨勬牸鍙銆乣hidden="hidden"` 鐨勬牸 `display:none`銆佸垪鏁扮ǔ瀹� |
+| Chromium 瀹炴祴 | 鎵撳紑绗� 2 鑺傛覆鏌撲骇鐗╋紝璇� `td.rowSpan` 涓� `getBoundingClientRect()` | 缁勫悕鏍� `rowSpan=3`銆佸儚绱犻珮 93px = 鍏跺悗涓夎锛堝悇 31px锛変箣鍜岋紱缁勫唴涓よ鐨勭粍鍚嶆牸 `display:none` |
+| 鐜扮綉瀹炰緥 | 鏌� `qc_report_instance`锛堜粎 id 44/45锛屾ā鏉� 3锛� | 浜х墿閲�**娌℃湁** `rowspan`锛屽揩鐓ч噷涔熸病鏈� `"group":` 瀛楁 鈬� 杩欎袱鍗曟湰韬笉甯﹀垎缁勭粨鏋勶紝灞炴甯� |
+
+### 29.4 绔埌绔疄璺戯紙鐪熸帴鍙� + 鐪熸覆鏌擄級
+
+涓婁竴鑺傚彧璇佸埌銆屽睘鎬ц惤鎴愩�佹覆鏌撳櫒璁ゅ緱銆嶃�傜敤鎴疯姹傜湅涓�鐪兼垚鍝侊紝浜庢槸璧颁簡涓�閬嶇湡瀹為摼璺細
+
+| 姝� | 鍔ㄤ綔 | 缁撴灉 |
+|---|---|---|
+| 1 | 鎽告竻鐜扮姸 | 鐜扮綉**娌℃湁**浠讳綍妯℃澘鐨勭敾甯冩斁 `GroupedQualityTable`锛�1/3/5/33 鍏ㄦ槸鎵佸钩 `QualityTable`锛夛紝蹇呴』鏂板缓涓�涓� |
+| 2 | 鍙戠幇 IQC 鍗� 1 **鏈韩灏辨寕涓婁簡鍒嗙粍鎸囨爣**锛�21+22/23/24/25銆�26+27~30銆�31+32锛夛紝鐘舵�� 4 宸插畬鎴� | 涓嶇敤閫犺川妫�鍗� |
+| 3 | 鐢� `assembleQualityCanvas` 鎶� AI 鑽夌锛堟ā鏉� 33 閭d唤锛宍#椤圭洰=鈥锛夌紪璇戞垚鐢诲竷 | 韪╁埌涓や釜鍧戯紝瑙佷笅 |
+| 4 | `POST /qc-report/template/create` 寤烘ā鏉� 38锛坮eportType=1锛夆啋 `template-version/create` 鍐欑敾甯� 鈫� `publish` | v1.0 寤哄ソ骞跺彂甯� |
+| 5 | `POST /qc-report/instance/generate-from-qc`锛坬cType=1, qcId=1, templateId=38锛� | 瀹炰緥 48锛�17 椤癸紝`warnings` 涓虹┖ |
+| 6 | 璇诲疄渚� 48 鐨� `render_html` | 鍙湁 5 涓�**绌� div**銆�0 涓� `<tr>` 鈬� 娓叉煋鍣ㄦ病鍚冨埌缁勪欢鐨� children |
+| 7 | 鏀圭敤 GrapesJS 瑙f瀽鍚庨噸鍙� v1.1 鈫� 閲嶆柊鍑轰欢 | 瀹炰緥 49锛宍render_html` 8356 瀛楃銆�22 涓� `<tr>` |
+
+瀹炰緥 49 浜х墿閲岀殑鍚堝苟锛堟鍒欒鏁帮紝闈炵洰娴嬶級锛�
+
+```
+rowspan = ["2","1","1","5","1","1","1","1","6","1","1","1","1","1","2","1","1","1"]
+hidden = ["hidden" 脳 10]
+```
+
+`5` / `6` / `2` 鍒嗗埆鏄按鍒嗭紙1 澶� + 4 瀛愰」锛夈�侀吀鍚噺锛�1 + 5锛夈�佹涓侀唶鍚噺锛�1 + 1锛夌殑缁勫悕鏍硷紱璁╀綅鏍� 4+5+1 = 10 涓紝涓� `hidden` 鏁板涓婏紱鏀跺熬閭d釜 `2` 鏄〃澶淬�岀粨璁恒�嶇旱鍚戣法涓ゅ眰銆�
+
+鍚屼竴浠戒骇鐗╀涪杩� Chromium 瀹炴祴锛堣 `td.rowSpan` 涓庡疄闄呭儚绱犻珮锛夛細
+
+| 缁� | rowSpan | 鍍忕礌楂� | 琛岄珮瀵圭収 |
+|---|---|---|---|
+| 姘村垎 | 5 | 155px | 5 脳 31px |
+| 閰稿惈閲� | 6 | 186px | 6 脳 31px |
+| 姝d竵閱囧惈閲� | 2 | 62px | 2 脳 31px |
+| 璇� 3 缁勫唴鐨勫瓙椤硅锛堝叡 10 琛岋級 | 1 | 0 | `display:none`锛岃浣� |
+| 鐙珛椤癸紙澶栬/鑹插害/瀵嗗害/鎶樺厜鐜囷級 | 1 | 31px | 鍚勫崰涓�琛� |
+
+娓叉煋澶嶅埢鍥撅細`D:/qcl-tmp/merge-e2e.png`锛堛�岄」鐩�嶅垪涓�鍒楀埌搴曘�佽〃澶淬�岀粨璁恒�嶅彧鍗颁竴閬嶃�佽〃鏍艰惤鍦ㄧ焊寮犲唴涓嶆孩鍑猴級銆�
+
+**寤烘ā鏉胯俯鍒扮殑鍧戯紙绋嬪簭鍖栧啓妯℃澘閮借娉ㄦ剰锛�**
+
+1. **钀藉簱鐨勭敾甯冨繀椤绘槸瑙f瀽鍚庣殑鑺傜偣鏍戯紝涓嶈兘鏄� HTML 涓层��** `assembleQualityCanvas` 浜х墿閲屾瘡涓妭鐐圭殑 `components` 鏄�**鏈В鏋愮殑 HTML 瀛楃涓�**鈥斺�擥rapesJS 鍦ㄦ祻瑙堝櫒閲屼細鎶婂畠鎷嗘垚鑺傜偣鏍戯紝浣�**鍚庣娓叉煋鍣ㄤ笉瑙f瀽**銆傜洿鎺ユ妸瑁呴厤浜х墿濉炶繘 `schema_json`锛屽悗绔細蹇界暐 children銆佹覆鍑� 5 涓┖ div锛堝疄渚� 48 灏辨槸杩欐牱锛夈��
+2. **鍠� GrapesJS 瑕佷紶鑺傜偣瀵硅薄锛屼笉鑳借嚜宸辨嫾 HTML 涓插啀 `setComponents`銆�** 璧板瓧绗︿覆瑙f瀽鏃跺睘鎬у悕浼氳 HTML 瑙f瀽鍣�**杞皬鍐�**锛坄data-qc-itemsPath` 鈫� `data-qc-itemspath`銆乣data-qc-headerSpans` 鈫� `data-qc-headerspans`锛夛紝灞炴�ч潰鏉夸笌娓叉煋閮戒細缁戜笉涓娿�傝璁″櫒璧扮殑灏辨槸銆岀洿鎺ヤ紶瀵硅薄銆嶈繖鏉¤矾锛屾墍浠ュ簱閲屽瓨鐨勪竴鐩存槸椹煎嘲銆�
+3. 瑙f瀽鍚� `getProjectData()` 鐨勭粨鏋勬槸 `{dataSources, assets, styles, pages, symbols}`锛屼笌瀛橀噺鐢诲竷**閫愰敭涓�鑷�**锛涘唴鑱� `style` 浼氳鎻愬崌鎴� `styles` 閲岀殑 `#id` 瑙勫垯銆�
+
+### 29.5 宸查獙璇� / 鏈獙璇�
+
+- 鉁� 宸查獙璇侊紙鏈疆琛ラ綈锛夛細鑷畾鍒楃殑鍚堝苟灞炴�х‘瀹炶惤鎴愶紙瑁呴厤浜х墿瀹炶瘉锛夛紱娓叉煋鍣ㄦ妸 `span`/`hidden` 娓叉垚鐪熷悎骞讹紙Chromium 瀹炴祴锛夛紱璐熷悜瀵圭収锛�**鐪熸帴鍙e嚭浠剁殑鎴愬搧閲� `rowspan`/`hidden` 涓庢祻瑙堝櫒瀹炴祴鎺掔増閮藉**锛堝疄渚� 49锛夈��
+- 馃煛 鏈獙璇侊細**PDF 鍑轰欢鏈窇**鈥斺�旀湰杞彧楠� HTML 浜х墿銆侾DF 鏄悗绔皟 Chromium 鎵撳嵃鍚屼竴浠� HTML锛屽睘鏃㈡湁鑳藉姏锛屾湭澶嶈窇銆�
+- 涓庡墠涓�杞浉鍚岀殑鎻愮ず锛氭埅鍥鹃噷閭d唤鐢诲竷鏄�**鏈繚瀛樼殑 AI 瀵煎叆鑽夌**锛屽埛鏂拌璁″櫒鐪嬪埌鐨勬槸搴撻噷鏃х殑骞抽摵 `QualityTable`锛坄id=21`锛屾棤 `columns`锛夈��
+
+### 29.6 鏈疆閫犲嚭鐨勬祴璇曟暟鎹紙**鏈竻鐞�**锛屽緟鐢ㄦ埛瀹氬ず锛�
+
+| 绫诲瀷 | 缂栧彿 | 璇存槑 |
+|---|---|---|
+| 鎶ュ憡妯℃澘 | 38 `ZZ_VERIFY_MERGE`銆岄獙璇�-鍒嗙粍绾靛悜鍚堝苟銆� | reportType=1銆�**鍚敤涓�**銆乧urrentVersion=v1.1 鈬� **浼氬嚭鐜板湪 IQC 鍑烘姤鍛婄殑妯℃澘涓嬫媺閲�** |
+| 妯℃澘鐗堟湰 | 23 / 24 | 鍧囧凡鍙戝竷锛�24 鏄В鏋愬悗鐨勬纭敾甯冿紝23 鏄潖鐨勯偅浠� |
+| 鎶ュ憡瀹炰緥 | 48 / 49 | 48 鏄潖浜х墿锛堢┖ div锛夛紝49 鏄悎骞舵纭殑鎴愬搧 |
+
+**娌$**锛氱幇缃� 34 琛岃川妫�鎸囨爣銆両QC 鍗� 1 鍙婂叾 16 琛屻�佹ā鏉� 1/3/5/33 涓庡叾鐗堟湰銆佸疄渚� 44/45銆�
+
+### 29.7 鐣欑棔
+
+- `mom-pro2-before/.qc-conformance/verify-grouped-table.ts`锛氭柊澧炵 4 鑺傦紙鑷畾鍒楃殑鍚堝苟缁撴瀯 + 璐熷悜瀵圭収锛夛紝鏂囦欢浠庡彧瑕嗙洊榛樿鍒楀彉鎴愪袱鏉″垎鏀兘瑕嗙洊銆�
+- `docs/qc_report_ai_import_frontend_integration.md`锛歚columns` 鐨勫啓娉曚箣鍚庤ˉ涓�灏忚妭銆屻��#銆嶉偅涓�鍒楀埌搴曟�庝箞鍚堝苟鐨勩�嶏紝鎶婁笁娈佃亴璐c�佷笁鏉″彛寰勫啓娓咃紙鍘熷厛鍙啓浜嗐�屽姞 `#` 灏卞悎骞躲�嶏紝娌¤鍚堝苟鍑犺銆佷粈涔堟椂鍊欎笉鍚堝苟锛夈��
+- `docs/project-business/mermaid/05-quality-flow.mmd`锛歚RCTXG` 鑺傜偣鍘熷厛鍐欍�屽彧鍚堝苟妫�楠岄」鐩竴鍒椼�嶁�斺�旇嚜瀹氬垪涔嬪悗鍚堝苟鍒楃敱 `#` 鍐冲畾锛屾敼涓烘寜 `#` 閭d竴鍒楁弿杩板苟琛ヤ笂涓ゆ潯鍙e緞銆�
+
+### 29.8 鏈仛
+
+- 娌℃敼浠讳綍鐢熶骇浠g爜锛堝悎骞堕�昏緫鏈潵灏遍�氾紝缂虹殑鏄彇璇侊級
+- 娌¤璁捐鍣ㄧ敾甯冮瑙堝悎骞讹紙鐢诲竷鍙湁涓�琛屾湭灞曞紑鐨勬ā鏉胯涓斾笉姹傝В缁戝畾锛宍rowspan="{{鈥}"` 鏄潪娉曞�兼寜 1 澶勭悊锛夆�斺�旇鍋氭槸鐙珛鍐崇瓥
+- 娌′负绔埌绔鐜板幓閫犱竴寮犲甫鍒嗙粍鎸囨爣鐨勮川妫�鍗�
+
+## 涓夊崄銆佹牱鍝佷俊鎭湯琛岃ˉ榻愮┖浣嶏紙2026-09-19 缁級
+
+**鐜拌薄**锛堢敤鎴峰湪璁捐鍣ㄩ噷鐪嬪埌鐨勶級锛氭ā鏉� 38 鐨勩�屾牱鍝佷俊鎭�嶈〃鏈�鍚庝竴琛屾槸 `妫�楠屾棩鏈� | {{report.inspectDate}} | 绌� | 绌篳鈥斺�斿彸渚х鍑轰袱涓彧鏈夎竟妗嗙殑绌烘牸瀛愩��
+
+**鏍瑰洜**锛歚sample-info.ts` 鐨� `buildRows` 鎸� `pairsPerRow` 姣忕粍 2 鏍煎垏瀛楁锛屾湯琛屽噾涓嶆弧涓�缁勬椂鐓ф牱鎶婃牸瀛愰摵婊★紝浣欎笅鐨勫垪灏辩┖鐫�銆傚瓧娈垫暟涓嶆槸銆屾瘡琛岀粍鏁般�嶆暣鏁板�嶆椂蹇呯劧鍑虹幇锛岃�� **AI 瀵煎叆鎸夊師浠跺瓧娈靛~ `fields`锛屽鍋朵笉鐢辨垜浠畾**锛堟湰鍗曞師浠� 5 椤广�佹瘡琛� 2 缁勶紝姝f槸鏈�鍏稿瀷鐨勪竴绉嶏級銆�
+
+**淇硶**锛氭湯琛屽瓧娈垫暟 `< pairsPerRow` 鏃讹紝璁�**鏈�鍚庝竴涓�屽�笺�嶆牸**妯悜鍚冩帀浣欎笅鐨勫垪銆傝法鍒楁暟 = `(pairsPerRow - 鏈瀛楁鏁�) 脳 2 + 1`銆�
+琛ュ湪鍊兼牸鑰屼笉鏄瓧娈靛悕鏍尖�斺�斿瓧娈靛悕鏍煎甫 `width:90px`锛岃ˉ涓婂幓杩欎竴鍒楃殑瀹藉害浼氳窡鐫�鍙橈紝鍚勮宸﹁竟缂樺氨閿欏紑浜嗐��
+
+**涓轰粈涔堥粯璁ゅ瓧娈典笉鍙楀奖鍝�**锛氶粯璁� 6 椤� 梅 2 = 3 涓暣琛岋紝涓�鏍奸兘涓嶈ˉ銆俙verify-columns.ts` 绗� 1 鑺傚喕缁撶殑閫愬瓧鎸囩汗 `SAMPLE_INFO_BASELINE` 鍥犳鍘熸牱閫氳繃鈥斺�旇繖涔熸槸銆屾敼杩欎釜涓嶄細鍔ㄥ埌宸插彂甯冩ā鏉裤�嶇殑鏈哄櫒璇佹嵁銆�
+
+**鎺㈤拡**锛歚verify-columns.ts` 绗� 5 鑺傝ˉ 9 鏉℃柇瑷�鈥斺��5 椤� 梅 2 鍑� 3 琛� 10 鏍� / 鍙 1 涓� `colspan` / 璺� 3 鍒� / 琛ョ殑鏄�兼牸锛堝鐫�瀛楁鍚嶆牸鏂█ `width:90px` 涓旀棤 `colspan`锛�/ 鏈浠嶆槸銆屾楠屾棩鏈� + 瀹冪殑鍊笺��/ 榛樿 6 椤规棤 `colspan` / `pairsPerRow=1` 姘镐笉琛� / 4 椤� 梅 3 璺� 5 鍒椼�傝窇閫氾紱涓変釜鍏勫紵鎺㈤拡锛堝垎缁勮〃銆侀噸澶嶈銆佸緟鍒ゅ畾锛変笌涓や釜鏀瑰姩鏂囦欢 typecheck 鍏ㄧ豢銆�
+
+**绔埌绔鐪嬫垚鍝�**锛氱敤鏇存柊鍚庣殑缁勪欢閲嶈閰嶆ā鏉� 38 鐨勫悓涓�浠借崏绋� 鈫� GrapesJS 瑙f瀽 鈫� 鍙� **v1.2**锛堢増鏈� id 25锛夆啋 `generate-from-qc` 鍑�**瀹炰緥 50**锛坄QR20260919-0016`锛夈��
+瀹炰緥 50 閲屾牱鍝佷俊鎭湯琛屽�兼牸 `colspan=3`銆佸疄娴嬪 809px = 鍏朵綑涓夊垪涔嬪拰锛�90 + 250 + 469锛夛紝鍙充晶鍐嶆棤绌烘牸锛涘垎缁勮〃鐨� `rowspan`锛�5/6/2锛変笌 10 涓浣嶆牸鍘熸牱淇濈暀銆傛覆鏌撳鍒诲浘 `D:/qcl-tmp/merge-v12.png`銆�
+
+**鐣欑棔**锛歚sample-info.ts`锛坄buildRows`锛夈�乣.qc-conformance/verify-columns.ts` 绗� 5 鑺傘�備竴娆℃�ц閰嶈剼鏈窇瀹屽凡鎼嚭浠撳簱锛坄D:/qcl-tmp/build-merge-v12.ts`锛夈��
+
+**鏈仛**锛氭病鏀� `HtmlRenderer` / `BASE_CSS`锛涙病鍔ㄦā鏉� 33 涓庡叾瀹冨瓨閲忔ā鏉跨殑鐢诲竷锛堟柊瑙勫垯鍙湪鏂拌閰嶆垨鐢ㄦ埛閲嶅瓨鏃剁敓鏁堬級锛汸DF 鏈噸璺戙��
+涓氬姟鍙鍖栨湭鏇存柊鈥斺�旇繖鏄粍浠舵帓鐗堢粏鑺傦紝涓嶈惤鍦ㄣ�屼笟鍔℃ā鍧� / 涓氬姟瀵硅薄 / 娴佺▼姝ラ / 鐘舵�佹祦杞� / 璺ㄦā鍧楁暟鎹祦 / AI 鑳藉姏 / 瑙掕壊鏉冮檺銆嶄换浣曚竴绫汇��
diff --git "a/docs/\346\231\272\350\203\275\350\264\250\346\243\200\346\212\245\345\221\212\345\271\263\345\217\260-\346\226\271\346\241\210\350\256\276\350\256\241.md" "b/docs/\346\231\272\350\203\275\350\264\250\346\243\200\346\212\245\345\221\212\345\271\263\345\217\260-\346\226\271\346\241\210\350\256\276\350\256\241.md"
new file mode 100644
index 0000000..7a6cf06
--- /dev/null
+++ "b/docs/\346\231\272\350\203\275\350\264\250\346\243\200\346\212\245\345\221\212\345\271\263\345\217\260-\346\226\271\346\241\210\350\256\276\350\256\241.md"
@@ -0,0 +1,374 @@
+
+# 鏅鸿兘璐ㄦ鎶ュ憡璁捐骞冲彴 鈥� 鏂规璁捐锛圥hase 0 椤圭洰鎵弿浜у嚭锛�
+
+> 鐘舵�侊細**寰呯敤鎴风‘璁�**锛堢‘璁ゅ悗鏂瑰彲杩涘叆 Phase 1 缂栫爜锛�
+> 鎵弿鏃ユ湡锛�2026-09-17
+> 渚濇嵁鏂囨。锛歚docs/鏅鸿兘璐ㄦ鎶ュ憡璁捐骞冲彴鈥斺�擟laude Code Agent 涓撲笟寮�鍙戞彁绀鸿瘝.md`
+> 鍘熷垯锛氬厛鐞嗚В鐜版湁绯荤粺 鈫� 鏈�澶у寲澶嶇敤 鈫� 鏈�灏忓寲渚靛叆
+
+---
+
+## 涓�銆佸綋鍓嶉」鐩妧鏈爤
+
+### 鍚庣
+
+| 椤� | 鐜板�� |
+|---|---|
+| 妗嗘灦 | Spring Boot 4.1锛坹udao 浣撶郴锛�+ Spring Security |
+| ORM | MyBatis-Plus锛坄BaseMapperX` / `LambdaQueryWrapperX`锛� |
+| 鏁版嵁搴� | MySQL 8锛坄application-local.yaml` 鎸囧悜 `ruoyi-vue-pro`锛� |
+| 绔彛 | 48080锛宲rofile = `local`锛堝彟鏈� dev/test/jhhg/wtxc/yzfx/zsjc锛� |
+| 澶氱鎴� | **鍏ㄥ眬鍏抽棴**锛坄yudao.tenant.enable: false`锛夆�� 鏂拌〃涓嶅姞 `tenant_id` |
+| 鏂囨。 | springdoc OpenAPI3 + Knife4j 4.5.0 |
+| Excel | FastExcel 1.3.0锛坄ExcelUtils`锛� |
+| 缂撳瓨 | Redis锛坉b 5锛� |
+
+### 鍓嶇锛坄mom-pro2-before`锛�**鍙**锛�
+
+| 椤� | 鐜板�� |
+|---|---|
+| 褰㈡�� | Vben Admin **5.7.0 鍗曞簲鐢ㄧ増**锛坄@vben/web-antd-standalone`锛夛紝涓氬姟浠g爜鍦ㄦ牴 `src/` |
+| 妗嗘灦 | Vue 3 + TypeScript + Vite + Pinia + Vue Router |
+| UI 搴� | **Ant Design Vue 4.2.6**锛堝敮涓�锛�**鏃� Element Plus**锛� |
+| 琛ㄦ牸 | vxe-table锛坄useVbenVxeGrid`锛�+ `TableAction` |
+| 璇锋眰 | `src/api/request.ts` 鐨� `requestClient`锛屽墠缂� `/admin-api`锛屼唬鐞嗗埌 `192.168.0.10:48080` |
+| 鍒悕 | `#/* 鈫� ./src/*` |
+| 寮�鍙戠鍙� | 5666 |
+| 鍛戒护 | `pnpm dev` / `pnpm build` / `pnpm typecheck` |
+
+---
+
+## 浜屻�佸綋鍓嶅墠绔灦鏋�
+
+- **璺敱涓庤彍鍗曠敱鍚庣椹卞姩**锛歚src/router/access.ts` 浠� `accessStore.accessMenus`锛堝悗绔� `system_menu`锛夌敓鎴愯矾鐢憋紝鐢� `import.meta.glob('../views/**/*.vue')` 鎶婂悗绔� `component` 瀛楃涓诧紙濡� `mes/qc/defect/index`锛夋槧灏勬垚缁勪欢銆�
+ 鈫� **鏂板椤甸潰鍙渶鏀惧埌 `src/views/**/index.vue` + 鎻掍竴鏉� `system_menu` 璁板綍锛屾棤闇�鎵嬪伐娉ㄥ唽璺敱銆�**
+- `src/router/routes/modules/*.ts` 浠呯敤浜庢斁闅愯棌椤碉紙`hideInMenu: true`锛夛紝濡傝鎯�/缂栬緫椤点��
+- **鍏稿瀷 CRUD 鍙傝�冩牱渚�**锛堟柊椤甸潰鐓ф妱缁撴瀯锛夛細
+ - `src/views/mes/qc/defect/index.vue`锛堝垪琛級
+ - `src/views/mes/qc/defect/data.ts`锛坄useGridColumns` / `useGridFormSchema` / `useFormSchema`锛�
+ - `src/views/mes/qc/defect/modules/form.vue`锛堝脊绐楄〃鍗曪級
+ - `src/api/mes/qc/defect/index.ts`锛圓PI 鍒嗗眰锛宍export namespace XxxApi`锛�
+- 鐩綍绾﹀畾锛歚src/views`銆乣src/api`锛堥暅鍍� views锛夈�乣src/store`銆乣src/components`銆乣src/types`銆乣src/utils`銆�
+- 鏉冮檺锛氭寜閽骇鐢� `v-access:code` 鎴� `TableAction` 鐨� `auth: [...]`锛屽垽鏉冪敤 `useAccess().hasAccessByCodes`銆�
+- 瀛楀吀锛歚@vben/constants` 鐨� `DICT_TYPE`锛坄src/packages/constants/src/dict-enum.ts`锛夛紝閰� `getDictOptions` / `DictTag` / `cellRender: CellDict`銆�
+
+---
+
+## 涓夈�佸綋鍓嶅悗绔灦鏋�
+
+- **Maven 澶氭ā鍧�**锛屽寘鏍� `cn.iocoder.yudao.module.{妯″潡}`銆傛柊澧炴ā鍧楅渶鏀� 2 澶勶細鏍� `pom.xml` 鐨� `<modules>`銆乣yudao-server/pom.xml` 鐨� `<dependencies>`锛坄yudao-dependencies` 鍙绗笁鏂圭増鏈紝`lombok.config` 鍏ㄥ眬鐢熸晥锛屾棤 `spring.factories` 闇�缁存姢锛夈��
+- 鍗曟ā鍧楀唴鍒嗗眰锛堜互 MES 涓轰緥锛夛細
+
+ | 灞� | 璺緞 |
+ |---|---|
+ | Controller | `controller/admin/{鍩焳/{瀛愬煙}/XxxController.java` |
+ | VO | `controller/admin/{鍩焳/{瀛愬煙}/vo/Xxx{Save,Resp,Page}ReqVO.java` |
+ | Service | `service/{鍩焳/{瀛愬煙}/XxxService.java` |
+ | ServiceImpl | `service/{鍩焳/{瀛愬煙}/XxxServiceImpl.java` |
+ | DO | `dal/dataobject/{鍩焳/{瀛愬煙}/XxxDO.java` |
+ | Mapper | `dal/mysql/{鍩焳/{瀛愬煙}/XxxMapper.java` |
+ | 鏋氫妇 | `enums/{鍩焳/` |
+ | 閿欒鐮� | `enums/ErrorCodeConstants.java` |
+
+- 閫氱敤鑳藉姏锛堢洿鎺ュ鐢級锛歚CommonResult<T>`銆乣PageResult<T>`/`PageParam`銆乣BaseDO`锛坄createTime/updateTime/creator/updater/deleted` 鑷姩濉厖锛夈�乣ServiceException` + `ServiceExceptionUtil.exception(ErrorCodeConstants.XXX)`銆乣BeanUtils`(MapStruct)銆乣BaseMapperX`銆乣LambdaQueryWrapperX`銆�
+- **JSON 鍒楀瓨鍌�**锛歚@TableName(value="...", autoResultMap=true)` + `@TableField(typeHandler = Jackson3TypeHandler.class)`锛堣 `BpmFormDO`锛夆�斺�旀ā鏉� Schema 澶у瓧娈佃蛋杩欎釜妯″紡銆�
+- 娴嬭瘯锛欽Unit5 + `BaseDbUnitTest`锛圚2锛�/ `BaseMockitoUnitTest` + PODAM銆�
+
+---
+
+## 鍥涖�佸綋鍓嶇洰褰曠粨鏋勶紙鍏抽敭閮ㄥ垎锛�
+
+```
+mom-pro2-after/ # 鍚庣浠撳簱鏍�
+鈹溾攢鈹� pom.xml # <modules> 娉ㄥ唽澶�
+鈹溾攢鈹� yudao-server/ # 鍚姩妯″潡锛坧om 閲岃仛鍚堜笟鍔℃ā鍧楋級
+鈹溾攢鈹� yudao-dependencies/ # 绗笁鏂圭増鏈鐞�
+鈹溾攢鈹� yudao-framework/ # 妗嗘灦 starter
+鈹溾攢鈹� yudao-module-system|infra|bpm|member|
+鈹� crm|erp|mes|mdm|hrm|srm|aftersales|ai|bi|im
+鈹溾攢鈹� yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/
+鈹� 鈹溾攢鈹� controller/admin/qc/{iqc,ipqc,oqc,rqc,ncr,defect,indicator,template}/
+鈹� 鈹溾攢鈹� service/qc/...
+鈹� 鈹溾攢鈹� dal/dataobject/qc/...
+鈹� 鈹斺攢鈹� enums/qc/ (MesQcTypeEnum / MesQcCheckResultEnum / MesQcResultValueTypeEnum ...)
+鈹溾攢鈹� docs/ # 鏂规/鑱旇皟鏂囨。
+鈹斺攢鈹� mom-pro2-before/ # 鍓嶇浠撳簱锛堝彧璇伙級
+ 鈹斺攢鈹� src/{api,views,router,store,components,packages}/
+```
+
+---
+
+## 浜斻�佸綋鍓� UI 妗嗘灦鍙婄増鏈�
+
+**Ant Design Vue 4.2.6 + Vben Admin 5.7.0**锛堟棤 Element Plus锛夈��
+鈫� 鏂版ā鍧� UI 蹇呴』鐢� **Vben + Ant Design Vue**锛�**绂佹寮曞叆 Element Plus**銆�
+
+---
+
+## 鍏�佸綋鍓嶅彲浠ュ鐢ㄧ殑鑳藉姏锛堥噸鐐癸級
+
+| 鑳藉姏 | 鐜扮姸 | 澶嶇敤鏂瑰紡 |
+|---|---|---|
+| **璐ㄦ涓氬姟鏁版嵁** | MES 鏈夊畬鏁� qc 鍩燂細`mes_qc_iqc/ipqc/oqc/rqc` + `*_line` + `mes_qc_template/_indicator/_item` + `mes_qc_indicator_result(_detail)` | 鏂板钩鍙扮洿鎺ユ敞鍏� `MesQcIqcService` 绛夊彇鏁帮紝**涓嶉噸寤鸿川妫�妯″瀷** |
+| 璐ㄦ鏋氫妇 | `MesQcTypeEnum`銆乣MesQcCheckResultEnum`銆乣MesQcResultValueTypeEnum` 绛� | 鐩存帴寮曠敤 |
+| 鏂囦欢涓婁紶锛堝悗绔級 | infra `FileApi.createFile(bytes,name,dir,type)` 鈫� 杩斿洖 URL锛泂ystem `StorageFileUtil.saveStorageAttachment(...)` 缁戝畾涓氬姟璁板綍 | PDF 鐢熸垚鍚庝竴琛屼繚瀛� |
+| 鏂囦欢涓婁紶锛堝墠绔級 | `src/api/system/storage/index.ts`锛歚/system/storage-blob/upload` + `/system/storage-attachment/bind` | 妯℃澘缂╃暐鍥�/闄勪欢澶嶇敤 |
+| **浜岀淮鐮�/鏉$爜锛堝墠绔級** | `qrcode 1.5.4`銆乣jsbarcode 3.12.3`锛屽凡灏佽 `packages/effects/common-ui/src/components/barcode/barcode.vue`锛堝惈 `getImageBase64()`锛� | **鐩存帴澶嶇敤锛屼笉鏂板搴�** |
+| 鎵撳嵃 | `vue3-print-nb 0.1.4`锛堣寖渚� `views/bpm/processInstance/detail/modules/process-print.vue`锛� | 澶嶇敤 |
+| 绛惧悕 | `vue3-signature 0.4.4`銆乣SignaturePad`锛圚RM 宸茬敤锛� | 澶嶇敤 |
+| 鎷栨嫿 | `vuedraggable 4.1.0`銆乣sortablejs 1.15.7` | 澶嶇敤 |
+| 瀵屾枃鏈� | `tinymce 7.9.3` / `@tiptap/*` | 澶嶇敤锛圧ichText 缁勪欢锛� |
+| 鍥捐〃 | `echarts 6.1.0` | 澶嶇敤锛堢粺璁$粍浠讹級 |
+| 璁捐鍣ㄥ厛渚� | `bpmn-js 18.16.1`锛坄views/bpm/model/`銆乣views/mes/process-design/`锛変负椤圭洰鍐呭敮涓�"鐢诲竷+灞炴�ч潰鏉�"鍏堜緥锛沗@form-create/antd-designer 3.4.0` 宸茶 | 鍙傝�冨竷灞�缁勭粐 |
+| 鏉冮檺浣撶郴 | `@PreAuthorize("@ss.hasPermission('x:y:z')")` + 鍚庣鑿滃崟 `system_menu` | 娌跨敤锛�**涓嶆柊寤烘潈闄愮郴缁�** |
+| 瀛楀吀浣撶郴 | `system_dict_type/data` + 鍓嶇 `DICT_TYPE` | 鏂板 `QC_REPORT_*` 瀛楀吀椤瑰嵆鍙� |
+
+---
+
+## 涓冦�佸綋鍓嶄笉鑳藉鐢ㄣ�侀渶瑕佹柊澧炵殑鑳藉姏
+
+| 缂哄彛 | 璇存槑 | 椋庨櫓 |
+|---|---|---|
+| **HTML/PDF 娓叉煋寮曟搸** | 鍏ㄩ」鐩�**闆� PDF 鐢熸垚鑳藉姏**銆備粎 PDFBox锛圕RM/ERP锛屽彧璇昏В鏋愶級銆丗astExcel锛圗xcel 瀵煎嚭锛夈�� | 楂� 鈥� 闇�鏂板渚濊禆 |
+| **Playwright / Chromium** | 瀹屽叏涓嶅瓨鍦� | **楂� 鈥� 闇�涓嬭浇 Chromium锛堢害 150MB锛夛紝闇�纭缃戠粶/绂荤嚎鐜** |
+| **GrapesJS** | 鍓嶇**鏈畨瑁�**锛堟棤 `grapesjs` 鍙婁换浣� preset/plugin锛� | 涓� 鈥� 闇�鏂板渚濊禆锛堟枃妗� 搂54 瑕佹眰鍏堣璇侊級 |
+| 妯℃澘 Schema 璁捐鍣� | 鏃狅紙BPM 琛ㄥ崟璁捐鍣ㄦ槸宸ヤ綔娴佺敤閫旓紝闈炴姤鍛婃帓鐗堬級 | 涓� |
+| 鎶ュ憡瀹炰緥/鐗堟湰浣撶郴 | 鏃� | 浣� |
+| 瑙勫垯寮曟搸 / 鏁版嵁缁戝畾寮曟搸 | 鏃狅紙`MesQcAiController` 鏈� AI 鍒ゅ畾寤鸿锛岄潪閫氱敤瑙勫垯寮曟搸锛� | 涓� |
+| 绉湪鎶ヨ〃 `yudao-module-report` | 鏍� pom **娉ㄩ噴绂佺敤**锛圝imuReport 2.3.4 鐗堟湰浠嶅湪 dependencies 涓級 | 鍛藉悕鍐茬獊椋庨櫓 |
+
+---
+
+## 鍏�佹暟鎹簱璁捐寤鸿
+
+**寤鸿鏂板缓鐙珛妯″潡**锛屼笌琛屼笟涓氬姟瑙h�︼紙鏂囨。 搂35 瑕佹眰锛夛紝琛ㄥ悕閲囩敤 `qc_report_*`锛堣创鍚堥」鐩�"妯″潡鍓嶇紑"鍛藉悕涔犳儻锛涙枃妗e師鏂囦负 `quality_report_*`锛岃涔変竴鑷达級锛�
+
+| 琛� | 鐢ㄩ�� | 鍏抽敭瀛楁 |
+|---|---|---|
+| `qc_report_template` | 妯℃澘涓昏〃 | `template_code`(uk), `template_name`, `industry`, `report_type`, `page_size/orientation`, `status`, `current_version`, `description`, `thumbnail_url` |
+| `qc_report_template_version` | 鐗堟湰蹇収锛�**鍙戝竷鍚庝笉鍙鐩�**锛� | `template_id`, `version`, `schema`(JSON longtext), `html`, `css`, `status`, `publish_time` |
+| `qc_report_data_source` | 鏁版嵁婧愬畾涔� | `template_id`, `source_key`, `source_type`(SQL/API/鍐呯疆), `config`(JSON) |
+| `qc_report_rule` | 鍒ゅ畾瑙勫垯 | `template_id`, `target_path`, `expression`, `pass_value/fail_value` |
+| `qc_report_instance` | 鎶ュ憡瀹炰緥锛�**蹇呴』瀛� `data_snapshot`**锛� | `report_no`(uk), `template_id`, `template_version`, `business_id`, `business_type`, `data_snapshot`(JSON), `render_html`, `pdf_file_url`, `status` |
+| `qc_report_render_record` | 娓叉煋/PDF 鑰楁椂涓庡紓甯歌褰曪紙鏂囨。 搂41 鏃ュ織瑕佹眰锛� | `report_id`, `render_start/end/duration`, `pdf_duration`, `browser_status`, `error_stack` |
+
+缁熶竴缁ф壙 `BaseDO`锛涗笉寤� `tenant_id`锛汼chema/Config 绫诲瓧娈电敤 `Jackson3TypeHandler` + `autoResultMap=true`銆�
+
+---
+
+## 涔濄�丵uality Components 鏋舵瀯锛堝墠绔級
+
+鎸夋枃妗� 搂8/搂9 寤虹珛鐙珛缁勪欢鍗忚灞傦紝**涓嶆妸涓氬姟缁勪欢鍐欐杩� GrapesJS**锛�
+
+```
+src/components/quality/
+鈹溾攢鈹� core/{types.ts, registry.ts, factory.ts, serializer.ts, validator.ts}
+鈹溾攢鈹� base/ layout/ inspection/ table/ result/ statistics/ signature/ header/ footer/ barcode/ qrcode/
+鈹斺攢鈹� index.ts # 缁熶竴娉ㄥ唽鍏ュ彛锛坮egisterAllQualityComponents(editor)锛�
+```
+
+`QualityComponentDefinition` 缁熶竴鍗忚锛歚type / name / label / category / icon / defaults / traits / dataSchema / styleSchema / propertySchema / render / validate / serialize / deserialize`銆�
+
+**琛屼笟鎵╁睍**锛歚registerIndustryPack('chemical')` 鍙敞鍐屾柊缁勪欢鍖咃紝**涓嶆敼鏍稿績 Designer**銆�
+
+**缁勪欢**锛氶鎵� 鍩虹锛圱ext/Title/RichText/Label/Image/Logo/Container/Row/Column/Section/Grid/Divider/Spacer锛夛紱璐ㄩ噺涓撲笟锛圧eportHeader / SampleInfo / InspectionItem / QualityTable / Result / Statistics / Signature / Barcode / QRCode / PageHeader / PageFooter锛夈��
+
+**TypeScript**锛氱鐢� `any`锛涚涓夋柟搴撴棤绫诲瀷鏃舵墠鍙眬閮ㄩ殧绂诲苟娉ㄦ槑鍘熷洜銆�
+
+---
+
+## 鍗併�丟rapesJS 闆嗘垚鏂规
+
+- **蹇呴』鏂板渚濊禆**锛歚grapesjs`锛�+ 鎸夐渶 `grapesjs-preset-webpage`锛夈�傞」鐩幇鏈� `@form-create/antd-designer` 鏄�**琛ㄥ崟璁捐鍣�**锛岃涔変笉绗︼紱`bpmn-js` 鏄祦绋嬭璁″櫒锛屽潎涓嶈兘鏇夸唬鎶ュ憡鎺掔増鐢诲竷銆�
+- 闆嗘垚瑕佺偣锛歚BlockManager` 娉ㄥ唽缁勪欢鍧楋紱`Components.addType` 娉ㄥ唽鑷畾涔夌粍浠讹紱鑷畾涔� `QualityPropertyPanel`锛�**涓嶄緷璧栭粯璁� StyleManager**锛夛紱`Commands` 鎸� `淇濆瓨/棰勮/鍙戝竷/PDF`锛沗StorageManager` 绂佺敤锛堟敼鐢卞悗绔� API 瀛樺彇锛夛紱`UndoManager` 鎻愪緵鎾ら攢閲嶅仛锛沗DeviceManager` 鎸夌焊寮犲昂瀵革紙A4/A3/A5 + 妯悜/绾靛悜锛夋敞鍐岃澶囥��
+- Designer 蹇呴』鎷嗗垎缁勪欢锛堟枃妗� 搂56锛岀姝� 2000+ 琛屽崟鏂囦欢锛夛細`DesignerToolbar / Sidebar / Canvas / PropertyPanel / DataPanel / RulePanel / PageSettings`銆�
+- 鐘舵�佺敤 Pinia 鍒嗙墖锛坄useDesignerStore`锛夛紝閬垮厤宸ㄥ瀷 Store銆�
+
+---
+
+## 鍗佷竴銆乀emplate Schema
+
+**涓嶄繚瀛樿8 HTML**锛屼繚瀛樼粨鏋勫寲 Schema锛堟枃妗� 搂21锛夛細
+
+```json
+{
+ "schemaVersion": "1.0.0",
+ "page": { "size": "A4", "orientation": "portrait",
+ "margin": { "top": 20, "right": 15, "bottom": 20, "left": 15 } },
+ "grapes": {},
+ "components": [],
+ "dataSources": [],
+ "bindings": [],
+ "rules": [],
+ "styles": []
+}
+```
+
+绾稿紶鏀寔锛歚A3 / A4 / A5 / Letter / 鑷畾涔塦 脳 `portrait / landscape`銆�
+
+---
+
+## 鍗佷簩銆丏ata Binding 鏂规
+
+缁熶竴 `{{path}}` 鍗忚锛堟枃妗� 搂18锛夛細
+
+```
+{{report.reportNo}} {{sample.sampleName}} {{sample.batchNo}}
+{{customer.name}} {{supplier.name}}
+{{inspectionItems[0].actualValue}} {{inspectionItems[0].result}}
+```
+
+鏀寔锛氬璞� / 鏁扮粍 / 宓屽 / 鏁扮粍閬嶅巻锛堝姩鎬佽〃鏍硷級/ 璁$畻瀛楁 / 琛ㄨ揪寮� / 鏉′欢瀛楁 / 鏍煎紡鍖� / 榛樿鍊笺��
+**蹇呴』鎻愪緵 `ContextBuilder`**锛氭妸 MES 璐ㄦ鍗曟嵁锛坄MesQcIqcDO` + `*_line` + `mes_qc_indicator`锛夋槧灏勬垚鏍囧噯 Context锛屼繚璇佸彲澶嶇敤鍒� IQC/IPQC/OQC/RQC銆�
+
+---
+
+## 鍗佷笁銆丷ule Engine 鏂规
+
+鐙珛 `QualityRuleEngine`锛�**绂佹鍐欐鍦� Vue 缁勪欢閲�**锛屾枃妗� 搂17锛夛細
+
+- 绠楀瓙锛歚> >= < <= = != BETWEEN IN NOT_IN` + `AND / OR`
+- 缁撴灉锛歚PASS / FAIL`
+- 缁熻鍑芥暟锛堟枃妗� 搂36锛夛細`AVG/MAX/MIN/COUNT/STDDEV/CP/CPK/PASS_RATE/FAIL_RATE`
+- 鍓嶅悗绔�**鍚勮嚜瀹炵幇涓�浠�**锛氬墠绔敤浜庤璁℃湡瀹炴椂棰勮鍒ゅ畾锛屽悗绔敤浜庢寮忔覆鏌擄紙浠ュ悗绔负鍑嗭紝娑堥櫎婕傜Щ锛夈��
+- **瀹夊叏**锛氳〃杈惧紡**涓嶅緱鐢� `eval` / `ScriptEngine` 鐩存帴鎵ц**銆傛柟妗堬細鑷缓璇嶆硶/璇硶瑙f瀽锛堥�掑綊涓嬮檷锛夌敓鎴� AST 姹傚�硷紝鐧藉悕鍗曞嚱鏁拌〃銆�
+
+---
+
+## 鍗佸洓銆丠TML Render 鏂规
+
+鏈嶅姟鍒嗗眰锛堟枃妗� 搂29锛孋ontroller 鍙敹鍙戯級锛�
+
+```
+ReportRenderService锛堢紪鎺掞級
+鈹溾攢鈹� TemplateRenderService # 鍔犺浇鐗堟湰 Schema
+鈹溾攢鈹� DataBindingService # Context + 缁戝畾姹傚��
+鈹溾攢鈹� QualityRuleEngine # 瑙勫垯璁$畻 PASS/FAIL
+鈹溾攢鈹� HtmlRenderService # Schema 鈫� HTML + 娉ㄥ叆 CSS锛園page銆佸垎椤碉級
+鈹斺攢鈹� PlaywrightRenderService 鈫� PdfRenderService
+```
+
+- **HTML Sanitization锛堟枃妗� 搂33锛屽繀椤诲仛锛�**锛氬墺绂� `<script>`銆乣<iframe>`銆乣on*=` 浜嬩欢灞炴�с�乣javascript:` URL锛涙覆鏌撶瀵瑰閮ㄨ祫婧愬仛鐧藉悕鍗�/鍐呰仈鍖栵紙鏈湴瀛椾綋銆佸浘鐗囪蛋鍐呯綉 URL锛夈��
+- 涓枃瀛椾綋闇�鍐呯疆/鎸囧畾锛圥DF 涓枃鍙敤鎬ч獙鏀堕」锛夈��
+
+---
+
+## 鍗佷簲銆丳laywright / Chromium 鏂规
+
+- 渚濊禆锛歚com.microsoft.playwright:playwright`锛堢増鏈叆 `yudao-dependencies`锛夈��
+- **`BrowserManager` 鍗曚緥**锛堟枃妗� 搂30锛夛細娴忚鍣ㄥ鐢ㄣ�丳age 鐢熷懡鍛ㄦ湡銆佸苟鍙戜俊鍙烽噺锛圥DF 骞跺彂涓婇檺锛屽缓璁� 2~4锛夈�佽秴鏃躲�佸穿婧冭嚜鍔ㄦ仮澶嶃�佸叧闂挬瀛愩��**绂佹姣忔璇锋眰 launch鈫抍lose**銆�
+- 鈿� **鏈�澶ч闄╃偣**锛氶渶棣栨涓嬭浇 Chromium锛堢害 150MB锛夈��**鑻ラ儴缃茬幆澧冩棤澶栫綉锛孭laywright 鏂规涓嶅彲琛�**锛屽繀椤绘敼鐢ㄧ函 Java 娓叉煋锛坥penhtmltopdf + Flying Saucer 鎴� iText锛夈��**姝ら」闇�鐢ㄦ埛鏄庣‘纭銆�**
+
+---
+
+## 鍗佸叚銆丳DF 鍒嗛〉鏂规
+
+- `@page { size: A4; margin: ... }` + `page-break-before/after/inside`銆�
+- QualityTable锛歚thead { display: table-header-group }` 瀹炵幇**璺ㄩ〉閲嶅琛ㄥご**锛沗tr { page-break-inside: avoid }` 閬垮厤琛岃鎷嗗紑銆�
+- 椤电湁/椤佃剼/椤电爜锛歅laywright `pdf()` 鐨� `headerTemplate/footerTemplate`锛坄<span class="pageNumber">`锛夈��
+- 鎬ц兘锛�1000+ 琛岃〃鏍奸渶鍒嗗潡娓叉煋锛岄伩鍏嶄竴娆℃�у法鍨� DOM锛堟枃妗� 搂39锛夈��
+
+---
+
+## 鍗佷竷銆丄PI 璁捐锛堣崏妗堬紝寰呯‘璁ゅ墠缂�锛�
+
+| 鏂规硶 | 璺緞 | 璇存槑 |
+|---|---|---|
+| POST | `/qc-report/template/create` | 鏂板缓妯℃澘 |
+| PUT | `/qc-report/template/update` | 淇敼妯℃澘 |
+| DELETE | `/qc-report/template/delete` | 鍒犻櫎 |
+| GET | `/qc-report/template/page` | 鍒嗛〉锛堝悕绉�/缂栫爜/琛屼笟/绫诲瀷/鐘舵��/鍒涘缓浜�/鏃堕棿锛� |
+| GET | `/qc-report/template/get` | 璇︽儏 |
+| POST | `/qc-report/template/copy` | 澶嶅埗 |
+| POST | `/qc-report/version/create` | 鍒涘缓鐗堟湰 |
+| GET | `/qc-report/version/list` | 鐗堟湰鍒楄〃 |
+| POST | `/qc-report/version/publish` | 鍙戝竷锛堜笉鍙鐩栵級 |
+| POST | `/qc-report/version/rollback` | 鍥炴粴 |
+| POST | `/qc-report/render/preview` | 棰勮 鈫� HTML |
+| POST | `/qc-report/render/html` | 鐢熸垚 HTML |
+| POST | `/qc-report/render/pdf` | 鐢熸垚 PDF |
+| GET | `/qc-report/instance/page` | 鎶ュ憡瀹炰緥鍒楄〃 |
+| GET | `/qc-report/instance/download` | 涓嬭浇 PDF |
+
+> 鏂囨。绀轰緥涓� `/quality/report/*`锛涙湰椤圭洰绾﹀畾涓� `/{妯″潡}/{鍩焳/*`锛屾晠寤鸿 `/qc-report/*`銆�**寰呯‘璁ゃ��**
+
+鏉冮檺鐮侊細`qc-report:template:{query,create,update,delete,publish}`銆乣qc-report:instance:{query,create,download}`锛屾部鐢ㄧ幇鏈� `@ss.hasPermission` 浣撶郴銆�
+
+---
+
+## 鍗佸叓銆佺洰褰曠粨鏋勫缓璁�
+
+鍚庣锛�**鏂板妯″潡** `yudao-module-qcreport` / 鍖呮牴 `cn.iocoder.yudao.module.qcreport`锛夛細
+
+```
+controller/admin/{template,version,instance,render}/...
+service/{template,version,instance,render}/...
+dal/dataobject|mysql/qcreport/...
+engine/{binding,rule,render}/
+engine/render/playwright/{BrowserManager,PdfRenderService}.java
+config/ enums/
+```
+
+鍓嶇锛�**闇�鎺堟潈鍚�**鍐嶅姩锛夛細
+
+```
+src/views/mes/qc/report/{template,designer,preview,instance}/
+src/components/quality/{core,base,inspection,table,result,statistics,signature,...}/
+src/api/mes/qc/report/
+src/store/qualityReport.ts
+```
+
+> 妯″潡鍛藉悕澶囬�夛細`yudao-module-report`锛堜笌娉ㄩ噴涓殑绉湪鎶ヨ〃妯″潡**閲嶅悕锛屼笉寤鸿**锛夈��
+
+---
+
+## 鍗佷節銆丳hase 1~5 瀹炴柦璁″垝
+
+| Phase | 鍐呭 | 楠屾敹 |
+|---|---|---|
+| **0** | 椤圭洰鎵弿 + 鏂规璁捐锛堟湰鏂囨。锛� | 鐢ㄦ埛纭 鉁�/鉂� |
+| **1** | 鍚庣妯″潡楠ㄦ灦 + 妯℃澘 CRUD + 鐗堟湰琛� + Schema 瀛樺彇锛汥esigner 鍩虹妗嗘灦 + Component Registry + GrapesJS 闆嗘垚 + 鍩虹缁勪欢 + 淇濆瓨/鍔犺浇 | 寤烘ā鏉库啋鎷栫粍浠垛啋淇濆瓨鈫掗噸寮�鐘舵�佷竴鑷� |
+| **2** | QualityTable / ReportHeader / SampleInfo / InspectionItem / Result + 鏁版嵁缁戝畾 + 鍔ㄦ�佽〃鏍� + 瑙勫垯寮曟搸 | `inspectionItems` 鑷姩鐢熸垚琛ㄦ牸骞剁畻鍑� PASS/FAIL |
+| **3** | HtmlRender + Preview + Playwright + Chromium + PDF + A4/鍒嗛〉/椤电湁椤佃剼/椤电爜 | A4 灏哄/杈硅窛/涓枃/澶氱骇琛ㄥご/閲嶅琛ㄥご/璺ㄩ〉姝g‘ |
+| **4** | 鐗堟湰绠$悊 + 鎶ュ憡瀹炰緥 + 鏉冮檺 + 鏃ュ織 + 寮傚父澶勭悊 | 鍙戝竷涓嶅彲瑕嗙洊銆乣data_snapshot` 鍐荤粨 |
+| **5** | 鑷姩鍖栨祴璇� + E2E + 澶嶆潅琛ㄦ牸/澶氶〉/100+ 琛�/鍥剧墖/浜岀淮鐮�/绛惧悕 | 鏂囨。 搂43 鍏ㄩ儴楠屾敹椤归�氳繃 |
+
+---
+
+## 浜屽崄銆侀闄╂竻鍗�
+
+| # | 椋庨櫓 | 绛夌骇 | 搴斿 |
+|---|---|---|---|
+| 1 | **鍚庣 Playwright/Chromium 闇�鑱旂綉涓嬭浇 ~150MB** | 馃敶 楂� | 闇�纭閮ㄧ讲鐜澶栫綉鍙揪锛涘惁鍒欐敼 openhtmltopdf 绾� Java 鏂规 |
+| 2 | **鍓嶇灞炵鏀瑰尯**锛坄.claude/rules/frontend-project.md`锛氭湭缁忔槑纭厑璁哥姝慨鏀� `mom-pro2-before` 浠讳綍鏂囦欢锛� | 馃敶 楂� | **蹇呴』鑾峰緱鐢ㄦ埛鏄惧紡鎺堟潈**锛屽惁鍒欐湰椤圭洰鏃犳硶浜や粯 |
+| 3 | **GrapesJS 闇�鏂板鍓嶇渚濊禆**锛堥」鐩棤锛� | 馃煛 涓� | 闇�鐢ㄦ埛鎵瑰噯锛涗綋绉�/鏋勫缓褰卞搷闇�璇勪及 |
+| 4 | 鏂板 Maven 妯″潡闇�鏀规牴 `pom.xml` + `yudao-server/pom.xml`锛堝叕鍏辨枃浠讹級 | 馃煛 涓� | 鎸夋枃妗� 搂53 璇存槑褰卞搷闈㈠苟楠岃瘉 `mvn compile -q` |
+| 5 | 琛ㄨ揪寮忓紩鎿庡畨鍏紙绂佹 eval锛� | 馃煛 涓� | 鑷缓 AST 瑙f瀽鐧藉悕鍗曟眰鍊� |
+| 6 | 妯℃澘 HTML 灞炵敤鎴峰彲缂栬緫鍐呭锛圶SS锛� | 馃煛 涓� | 鏈嶅姟绔� Sanitization + PDF 娓叉煋娌欑 |
+| 7 | 鍘嗗彶鎶ュ憡鍥犱笟鍔℃暟鎹彉鍖栬�屽彉 | 馃煛 涓� | `data_snapshot` 寮哄埗钀藉簱 |
+| 8 | 鍘嗗彶搴� `ruoyi-vue-pro` 涓鸿繍琛屽簱锛�**鏂拌〃 DDL 涓嶅緱鍦ㄦ簮搴撲贡璺�** | 馃煛 涓� | 璧� `docs/sql/` 鍒濆鍖栬剼鏈� + 鐩爣搴撴墽琛� |
+| 9 | 100+ 椤� PDF 鍐呭瓨/鎬ц兘 | 馃煝 浣� | BrowserManager 骞跺彂闄愬埗 + 娴佸紡鍐欏嚭 |
+
+---
+
+## 浜屽崄涓�銆丳hase 1 寮�濮嬪墠闇�瑕佺‘璁ょ殑闂
+
+1. **鍓嶇淇敼鎺堟潈**锛氭槸鍚﹀厑璁告垜淇敼 `mom-pro2-before`锛堟柊澧為〉闈�/缁勪欢/API 鏂囦欢锛屼笉閲嶆瀯鏃㈡湁浠g爜锛夛紵
+ - 鑻ヤ笉鍏佽 鈫� 鏈」鐩彧鑳戒氦浠�**鍚庣** + 鍓嶇鑱旇皟鏂规鏂囨。銆�
+2. **Playwright 鍙鎬�**锛氬悗绔繍琛�/閮ㄧ讲鐜**鑳藉惁璁块棶澶栫綉**涓嬭浇 Chromium锛熻嫢涓嶈兘锛屾槸鍚︽帴鍙楁敼鐢ㄧ函 Java 娓叉煋锛坥penhtmltopdf锛変綔涓洪檷绾ф柟妗堬紵
+3. **GrapesJS 渚濊禆**锛氭槸鍚︽壒鍑嗘柊澧� `grapesjs`锛堝強鍙�� preset锛夛紵
+4. **妯″潡鍛藉悕**锛氭柊鍚庣妯″潡鐢� `yudao-module-qcreport`锛堣〃 `qc_report_*`锛夋槸鍚﹀彲浠ワ紵杩樻槸娌跨敤鏂囨。鐨� `quality_report_*` / `/quality/report/*` 璺緞锛�
+5. **棣栨壒鑼冨洿**锛氫粖澶╂槸鍚﹀厛鍙仛 **Phase 1**锛堟ā鏉� CRUD + Schema 瀛樺彇 + Designer 楠ㄦ灦锛夛紝杩樻槸甯屾湜浼樺厛鍋氬悗绔� API + 娓叉煋閾捐矾锛�
+6. **鏁版嵁婧愯寖鍥�**锛氭姤鍛婁富瑕侀潰鍚� **MES 璐ㄦ鍗曪紙IQC/IPQC/OQC/RQC锛�**锛屾槸鍚﹁繕鏈� ERP 閲囪喘鍏ュ簱妫�楠� / CRM 绛夊叾浠栨潵婧愶紵
+
+---
+
+## 闄勫綍锛氭湰娆℃壂鎻忕殑鍏抽敭浜嬪疄鍑哄
+
+- 鏍规ā鍧楁敞鍐岋細`pom.xml:10-49`
+- MES 璐ㄦ鍩燂細`yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/{iqc,ipqc,oqc,rqc,ncr,defect,indicator,template,indicatorresult,defectrecord}`
+- 璐ㄦ鏋氫妇锛歚yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/qc/`
+- JSON 鍒楄寖渚嬶細`yudao-module-bpm/.../definition/BpmFormDO.java:53`
+- 鍓嶇 CRUD 鑼冧緥锛歚mom-pro2-before/src/views/mes/qc/defect/{index.vue,data.ts,modules/form.vue}`銆乣src/api/mes/qc/defect/index.ts`
+- 鍓嶇涓婁紶 API锛歚mom-pro2-before/src/api/system/storage/index.ts`
+- 鍚庣鏂囦欢 API锛歚yudao-module-infra/.../api/file/FileApi.java`
\ No newline at end of file
diff --git "a/docs/\346\231\272\350\203\275\350\264\250\346\243\200\346\212\245\345\221\212\345\271\263\345\217\260-\350\264\250\346\243\200\345\215\225\345\257\271\346\216\245\346\226\271\346\241\210.md" "b/docs/\346\231\272\350\203\275\350\264\250\346\243\200\346\212\245\345\221\212\345\271\263\345\217\260-\350\264\250\346\243\200\345\215\225\345\257\271\346\216\245\346\226\271\346\241\210.md"
new file mode 100644
index 0000000..9236247
--- /dev/null
+++ "b/docs/\346\231\272\350\203\275\350\264\250\346\243\200\346\212\245\345\221\212\345\271\263\345\217\260-\350\264\250\346\243\200\345\215\225\345\257\271\346\216\245\346\226\271\346\241\210.md"
@@ -0,0 +1,572 @@
+# 鏅鸿兘璐ㄦ鎶ュ憡骞冲彴 鈥� 璐ㄦ鍗曞鎺ユ柟妗堬紙宸茬‘璁わ級
+
+> 鐘舵�侊細**宸茶幏鐢ㄦ埛纭锛�2026-09-19锛�**锛屄�6 浜斾釜鍙e緞鍏ㄩ儴鏈夌粨璁猴紝鎸� 搂11 椤哄簭瀹炴柦銆�
+> 鏃ユ湡锛�2026-09-19
+> 鐩稿叧鏂囨。锛歚鏅鸿兘璐ㄦ鎶ュ憡骞冲彴-鏂规璁捐.md`锛�21 绔犳�绘柟妗堬級銆乣qc_report_ai_import_frontend_integration.md`銆乣qc_report_instance_frontend_integration.md`銆乣鏅鸿兘璐ㄦ鎶ュ憡骞冲彴-寮�鍙戣繘搴�.md`
+
+---
+
+## 闆躲�佺敤鎴风‘璁ょ粨璁猴紙2026-09-19锛屾湰娆″疄鏂戒緷鎹級
+
+| 缂栧彿 | 闂 | 鐢ㄦ埛缁撹 | 钀藉湴褰卞搷 |
+|---|---|---|---|
+| 搂6.1 | 鎶ュ憡鐨勫悎鏍肩粨璁虹敱璋佸畾 | **A** | `ReportFields` 澧� `qcResult` / `qcResultText`锛岄�忎紶 MES 鍘熷垽瀹氾紱寮曟搸閫愰」鍒ゅ畾鐓у父绠楋紝鎶ュ憡绾х粨璁轰互璐ㄦ鍗曚负鍑� |
+| 搂6.3 | 涓婁笅闄愪负绌� | **鐢熸垚鏃跺脊鎻愮ず** | 鍝嶅簲甯﹀洖 `undecidableCount`锛涘墠绔繀椤绘彁绀恒�孨 椤瑰洜缂哄皯瑙勬牸涓婁笅闄愯鍒や负寰呭垽瀹氥�� |
+| 搂6.2 | 鍝簺鎸囨爣杩涙姤鍛� | **鍏ㄩ儴杩�** | 涓嶆煡 `judge_flag`銆佷笉缁欒琛ㄨˉ鍒楋紱璐ㄦ鍗曡琛ㄦ湁浠�涔堝氨鍑轰粈涔� |
+| 搂6.4 | 澶氭牱鍝� / 鍚屾寚鏍囧娆″綍鍏� | **浼�** | 鍙栨柟妗� **A**锛氫竴涓� (鏍峰搧, 鎸囨爣) 缁勫悎 = 涓�琛屾楠岄」锛屾牱鍝佸彿鍐欒繘 `remark`锛屼笉涓㈡暟鎹� |
+| 搂7.3 | 妯℃澘绫诲瀷涓庤川妫�鍗曚笉绗� | **鍙兘閫夊搴旂被鍨嬫ā鏉�** | 鍚庣 `105_005` 鎷掔粷锛涘墠绔�夋ā鏉挎椂鎸� `reportType` 杩囨护锛岃鐢ㄦ埛閫変笉鍒伴敊 |
+| 搂6.5 | 涓�寮犺川妫�鍗曡兘鍚﹀嚭澶氫唤鎶ュ憡 | **鍏佽** | 鍙嶆煡杩斿洖鍒楄〃锛孶I 灞曠ず銆屾煡鐪嬫姤鍛� (N)銆� |
+
+> 鈿� 搂6.3 鐨勩�屽厛琛ユ暟鎹�嶄竴姝ワ紙搂11 姝� 1锛�**鐢ㄦ埛鏈��**锛屽嵆涓嶅己鍒惰ˉ鏁版嵁锛涗絾搴撻噷鐜板瓨鐨勬楠屾ā鏉夸笂涓嬮檺鍏ㄤ负绌猴紝
+> 鐓х幇鐘剁敓鎴愪細鏁翠唤銆屽緟鍒ゅ畾銆嶃��**钀藉湴鏃堕潬 `undecidableCount` 鎻愮ず濡傚疄鍛婄煡鐢ㄦ埛**锛屼笉浠e叾琛ユ暟鎹��
+
+---
+
+## 涓�銆佹湰鏂囨。瑕佽В鍐崇殑闂
+
+### 1.1 宸插畾鍙e緞锛堢敤鎴峰凡鎷嶆澘锛屼笉鍐嶈璁猴級
+
+| 鍐崇瓥 | 閫夋嫨 |
+|---|---|
+| 鎶ュ憡妯℃澘涓庤川妫�鍗曠殑鍏宠仈鏂瑰紡 | **姣忔鐢熸垚鏃朵汉宸ラ�夋ā鏉�**銆備笉寮曞叆銆岄粯璁ゆā鏉裤�嶆蹇� |
+| 绗竴姝ュ仛浠�涔� | **鍏堝嚭杩欎唤鏂规鏂囨。寰呯‘璁�**锛岀‘璁ゅ悗鍐嶅姩浠g爜 |
+
+### 1.2 鐢ㄦ埛鍘熻瘽
+
+> 鎶ュ憡妯℃澘璁捐杩樻槸娌℃湁鍜岃川妫�鍏宠仈鍚э紝鐜板湪涓嶇煡閬撴�庝箞瀵煎嚭鏁版嵁
+
+**杩欎釜鍒ゆ柇鏄鐨勩��** 鐜扮姸涓嶆槸銆屽叧鑱斿仛寰椾笉濂姐�嶏紝鑰屾槸**鏍规湰娌℃湁鍏宠仈**銆�
+
+---
+
+## 浜屻�佺幇鐘舵牳瀵癸紙缁撹锛氭病鎺ヤ笂锛屼絾鏈夊湴鍩猴級
+
+### 2.1 宸茬粡鏈夌殑
+
+| 鑳藉姏 | 浣嶇疆 | 鐘舵�� |
+|---|---|---|
+| 鎶ュ憡妯℃澘 CRUD + 鐗堟湰绠$悊 | `yudao-module-qcreport` | 鍙敤 |
+| GrapesJS 璁捐鍣� + 12 涓川妫�缁勪欢 | 鍓嶇 `views/mes/qc/report/template/designer` | 鍙敤 |
+| AI 瀵煎叆锛堜笂浼犳枃浠� 鈫� 妯℃澘鑽夌锛� | `service/aiimport/**` | 鍙敤锛�54/54 鑱旇皟宸茶繃 |
+| 鏈嶅姟绔覆鏌撳紩鎿� + 鍒ゅ畾鍣� + 瑙勫垯寮曟搸 | `engine/**` | 鍙敤锛屼笌鍓嶇閫愬瓧瀵规媿 |
+| 鍑轰欢锛氭覆鏌� + 钀藉簱 + 鍐荤粨蹇収 | `POST /qc-report/instance/generate` | **鍙敤锛屼絾鏁版嵁蹇呴』鐢辫皟鐢ㄦ柟浼犲叆** |
+| 瀵煎嚭 PDF + 褰掓。闄勪欢 | `POST /qc-report/instance/pdf` | 鍙敤 |
+| 瀹炰緥鍒楄〃 / 璇︽儏 / 鍒犻櫎 | 鍓嶇 `views/mes/qc/report/instance` | 鍙敤锛�#45 钀藉湴锛� |
+
+### 2.2 缂虹殑涓夊潡
+
+| # | 缂轰粈涔� | 璇佹嵁 |
+|---|---|---|
+| 1 | **鍚庣鏄犲皠**锛氳川妫�鍗� 鈫� `ReportContext` | 鍏ㄩ」鐩悳涓嶅埌 `MesQcReportApi`锛沗yudao-module-mes/pom.xml` 涓嶄緷璧� qcreport锛泀creport 杩� `-api` 瀛愭ā鍧楅兘娌℃湁 |
+| 2 | **鍚庣鍏ュ彛**锛氫竴涓�岀粰鎴戣繖寮犺川妫�鍗曠殑鎶ュ憡銆嶇殑鎺ュ彛 | 鍙湁 `/qc-report/instance/generate`锛屼笖瀹冭姹傝皟鐢ㄦ柟鎶婃暣涓� `ReportContext` 鎷煎ソ浼犺繘鏉� |
+| 3 | **鍓嶇鍏ュ彛**锛氳川妫�鍗曢〉闈笂鐨勩�岀敓鎴愭姤鍛娿�嶆寜閽� | 鍓嶇鍙皟浜嗗疄渚嬬殑 page / get / snapshot / pdf / delete锛�**`instance/generate` 涓� `instance/preview` 鍓嶇浠庢湭璋冪敤** |
+
+`QcReportInstanceController` 鐨勭被娉ㄩ噴鑷繁鍐欑潃锛�
+
+> 杩欓噷鏄�屾ā鏉� 鈫� 鎶ュ憡銆嶇殑瀵瑰鍏ュ彛鈥︹��**鏁版嵁鐢辫皟鐢ㄦ柟浼犲叆锛屾湰妯″潡涓嶈璇嗕换浣曚笟鍔″崟鎹��**
+
+鎵�浠ヤ綘鍦ㄧ晫闈笂鎵句笉鍒板嚭鍙f槸姝e父鐨勨�斺��**鐜板湪瑕佸嚭涓�浠芥姤鍛婏紝鍙兘鎷� curl 鎵嬫嫾 JSON**銆�
+
+### 2.3 鍦板熀鍏跺疄鐣欏ソ浜�
+
+| 宸叉湁鐨勮璁� | 浣嶇疆 | 璇存槑 |
+|---|---|---|
+| 妯℃澘澹版槑鑷繁鏈嶅姟鍝被璐ㄦ | `qc_report_template.report_type` | 鐢ㄧ殑灏辨槸 MES 鐨� `MES_QC_TYPE` 瀛楀吀锛圛QC/IPQC/OQC/RQC锛夛紝**涓庤川妫�鍗曞悓涓�濂楁灇涓�** |
+| 瀹炰緥鍙弽鏌ヤ笟鍔″崟鎹� | `qc_report_instance.business_id` / `business_type` | 瀛楁娉ㄩ噴鍐欑殑灏辨槸銆屼笟鍔″崟鎹紪鍙凤紝濡傝川妫�鍗� ID銆嶃�屼笟鍔″崟鎹被鍨嬶紝濡� mes_qc_iqc銆� |
+| 鍒嗛〉鏀寔鎸夊崟鎹弽鏌� | `QcReportInstancePageReqVO.businessType` / `businessId` | 鏌ヨ鏉′欢**宸茬粡鍋氬ソ浜�**锛宍GET /qc-report/instance/page?businessType=mes_qc_iqc&businessId=1` 鐩存帴鍙敤 |
+
+**鎹㈠彞璇濊锛氬叧鑱旈敭銆佸弽鏌ユ潯浠跺綋鍒濋兘璁捐濂戒簡锛屽彧鏄病鏈変换浣曚唬鐮佸幓鐢ㄥ畠浠��**
+
+### 2.4 涓や釜銆屾ā鏉裤�嶄笉瑕佹贩
+
+| | 妫�楠屾ā鏉� | 鎶ュ憡妯℃澘 |
+|---|---|---|
+| 琛� | `mes_qc_template` | `qc_report_template` |
+| 褰掑睘妯″潡 | MES | qcreport |
+| 绠′粈涔� | **妫�浠�涔�**锛氭楠屾寚鏍囨竻鍗曘�佸垽瀹氫笂涓嬮檺銆佹娴嬫柟娉� | **闀夸粈涔堟牱**锛氱増闈€�佺粍浠躲�佺粦瀹氥�佸垽瀹氳鍒欍�佺焊寮� |
+| 璋佺淮鎶� | 璐ㄩ噺宸ョ▼甯� | 鎶ュ憡璁捐浜哄憳 |
+| 鍓嶇椤甸潰 | MES 璐ㄦ 鈫� 妫�楠屾ā鏉� | MES 璐ㄦ 鈫� 鎶ュ憡妯℃澘 |
+
+鏈柟妗�**涓嶅悎骞躲�佷笉杩佺Щ**杩欎袱涓蹇点�備竴涓川妫�鍗曞紩鐢ㄤ竴涓楠屾ā鏉匡紙`mes_qc_iqc.template_id`锛夛紝鐢熸垚鎶ュ憡鏃朵汉宸ュ啀閫変竴涓姤鍛婃ā鏉库�斺�斾袱鑰呯嫭绔嬨��
+
+> **鍙︽敞**锛歁ES 璐ㄦ鍗�**宸茬粡鏈�** Excel 瀵煎嚭锛坄GET /mes/qc-iqc/export-excel` 绛夊洓绫伙紝鏉冮檺 `mes:qc-*-:export`锛夛紝瀵煎嚭鐨勬槸鍥哄畾鍒楃殑 `.xls`锛堝崟鍙� / 鐗╂枡 / 鎵瑰彿 / 妫�娴嬫棩鏈� / 妫�楠屾寚鏍� / 鍒ゅ畾渚濇嵁 / 妫�楠岀粨鏋� / 妫�楠屼汉 / 瀹℃牳浜� / 澶囨敞锛岃 `MesQcQualityExportVO`锛夈�傞偅鏄�屾暟鎹〃瀵煎嚭銆嶏紝涓庢湰鏂规鐨勩�屾寜璁捐濂界殑妯℃澘鍑烘姤鍛娿�嶆槸涓ゆ潯鐙珛鐨勭嚎锛屼簰涓嶆浛浠c��
+
+---
+
+## 涓夈�佷竴寮犵湡瀹炵殑璐ㄦ鍗曢暱浠�涔堟牱
+
+> 浠ヤ笅鍏ㄩ儴鏉ヨ嚜褰撳墠鏁版嵁搴撳疄娴嬶紙`ruoyi-vue-pro` 搴擄紝2026-09-19锛夛紝涓嶆槸鎺ㄦ祴銆�
+> 搴撻噷鐩墠鍙湁 **1 寮� IQC 鍗�**锛圛PQC/OQC/RQC 鍧囦负 0 鏉★級锛屾墍浠ヤ笅闈㈣繖寮犲崟鏄敮涓�鐨勬牱鏈��
+
+### 3.1 鍗曞ご `mes_qc_iqc`锛坕d=1锛�
+
+| 瀛楁 | 鍊� |
+|---|---|
+| code | `IQC_20260917001` |
+| name | `绮捐悩鏉ユ枡妫�楠�-0917` |
+| template_id | 6锛堟楠屾ā鏉裤�屾涓侀唶妫�楠岋紙GB/T 6027锛夈�嶏級 |
+| item_id | 2锛堢墿鏂欍�岀簿钀樸�嶏級 |
+| vendor_id / source_doc_type / source_doc_code | **鍏ㄤ负 NULL** |
+| vendor_batch | **NULL** |
+| received / check / qualified / unqualified_quantity | 100 / 100 / 100 / 0 |
+| **check_result** | **NULL** |
+| inspect_date | 2026-09-17 |
+| inspector_user_id | 1 |
+| **status** | **0锛堣崏绋匡級** |
+
+### 3.2 涓夊眰鏁版嵁缁撴瀯
+
+```
+mes_qc_iqc (1 鏉�) 璐ㄦ鍗曚富浣擄細瀵规柟銆佹暟閲忋�佺粨璁恒�佹棩鏈熴�佹楠屼汉
+ 鈹斺攢鈹� mes_qc_indicator_result (1 鏉�) 鏍峰搧璁板綍锛歲c_id + qc_type 鍏宠仈涓讳綋锛屽甫鏍峰搧缂栧彿 code
+ 鈹斺攢鈹� mes_qc_indicator_result_detail (14 鏉�) 瀹炴祴鍊硷細indicator_id + value
+ 鈹斺攢鈹� mes_qc_iqc_line (16 鏉�) 鍒ゅ畾渚濇嵁锛歩ndicator_id + 鏍囧噯鍊� + 涓婁笅闄愶紙娉ㄦ剰锛氫笉鍚疄娴嬪�硷級
+```
+
+### 3.3 瀹炴祴鍊间粠鍝潵锛堝叧閿級
+
+**瀹炴祴鍊间笉鍦� `mes_qc_iqc_line` 閲�**锛屽湪 `mes_qc_indicator_result_detail.value`锛堝瓧绗︿覆锛夈��
+
+`mes_qc_iqc_line` 鍙壙杞�**鍒ゅ畾渚濇嵁**锛歚standard_value`銆乣max_threshold`銆乣min_threshold`銆乣check_method`銆乣tool`銆佺己闄锋暟閲忋��
+
+鎵�浠ユ瀯閫犳姤鍛婇噷鐨勪竴琛屾楠岄」锛岄渶瑕�**鎶婅琛ㄤ笌缁撴灉鏄庣粏鎸� `indicator_id` 鎷艰捣鏉�**銆�
+
+### 3.4 瀹炴祴鎻ず浜嗗洓涓�屼笉鎺ヤ笉鐭ラ亾銆嶇殑浜嬪疄
+
+#### 浜嬪疄 1锛�16 鏉℃楠岃閲岋紝鍙湁 13 鏉℃湁瀹炴祴鍊�
+
+| 鎸囨爣 | 缁撴灉鍊肩被鍨� | 鏈夋棤瀹炴祴鍊� |
+|---|---|---|
+| 姘村垎 / 閰稿惈閲� / 姝d竵閱囧惈閲� | **NULL** | **鏃�** |
+| 澶栬銆佽壊搴︺�佹爣娑叉祿搴� c銆佹秷鑰楁淮瀹氭恫浣撶Н V銆佽瘯鏍疯川閲� m 脳2銆佺О閲忕摱 m0銆佽瘯鏍�+绉伴噺鐡� m1銆侀吀鍚噺缁撴灉 w3銆佹按鍒嗙粨鏋� w銆佹涓侀唶鍚噺 /%銆佸瘑搴︺�佹姌鍏夌巼 | 1(娴偣) / 3(鏂囨湰) | 鏈� |
+
+閭� 3 涓� `result_type=NULL`銆佹棦鏃犱笂涓嬮檺鍙堟棤瀹炴祴鍊肩殑鏄�**鍒嗙粍鏍囬椤�**锛堛�屾按鍒嗐�嶃�岄吀鍚噺銆嶃�屾涓侀唶鍚噺銆嶆槸缁撴灉椤圭殑灏忔爣棰橈級銆�
+
+#### 浜嬪疄 2锛氬悓涓�涓寚鏍囧彲浠ユ湁澶氭潯瀹炴祴鍊�
+
+`閰稿惈閲忕粨鏋� w3`锛坕ndicator 30锛夊湪鍚屼竴浠芥牱鍝佷笅鏈� **涓ゆ潯鏄庣粏锛�0.09 涓� 0.095**銆�
+
+绠楁湳鑷唇锛�16 琛� 鈭� 3 涓垎缁勯」 = 13 涓湁瀹炴祴鍊肩殑鎸囨爣锛�13 + 1 鏉¢噸澶� = 14 鏉℃槑缁嗭紝姝eソ瀵逛笂 `mes_qc_indicator_result_detail` 鐨� 14 鏉°��
+
+鈬� 鏄犲皠涓嶈兘鍋囪銆屼竴涓寚鏍囦竴涓�笺�嶃��
+
+#### 浜嬪疄 3锛氫笂涓嬮檺鍦ㄦ簮澶村氨鏄┖鐨勶紝涓嶅彧鏄病澶嶅埗
+
+| 浣嶇疆 | standard_value | 涓婁笅闄� |
+|---|---|---|
+| `mes_qc_template_indicator`锛堟ā鏉匡紝16 琛岋級 | **鍏� NULL** | **鍏� NULL** |
+| `mes_qc_iqc_line`锛堝崟鎹紝16 琛岋級 | **鍏� NULL** | **鍏� NULL** |
+
+鎵�浠ヤ笉鏄�岀敓鎴愬崟鎹椂涓簡涓婁笅闄愩�嶏紝鑰屾槸**鍘嬫牴娌″綍**銆�
+
+**鍚庢灉锛堟渶閲嶈锛�**锛氭姤鍛婂垽瀹氬櫒鐨勫崟椤瑰垽瀹氫紭鍏堢骇鏄�岄�愰」瑙勫垯 鈫� 瑙勬牸涓婁笅闄� 鈫� 鏁版嵁鑷甫缁撴灉銆嶏紙`ReportEvaluator.evaluateByLimit`锛夈�備笂涓嬮檺涓虹┖ 鈫� 鍓嶄袱鏉¢兘钀界┖ 鈫� **姣忎竴椤归兘鍙樻垚銆屽緟鍒ゅ畾銆�**锛岃繘鑰� `passCount != total` 鈫� **鎶ュ憡缁撹涔熸槸銆屽緟鍒ゅ畾銆嶃�佸悎鏍肩巼绌虹櫧**銆�
+
+**鍗筹細鐜板湪鎶婇摼璺帴閫氾紝鍑烘潵鐨勬姤鍛婁細鏄竴鏁撮〉銆屽緟鍒ゅ畾銆嶃�傜敤鎴蜂細浠ヤ负鍔熻兘鍧忎簡銆�**
+
+#### 浜嬪疄 4锛氭枃鏈瀷鎸囨爣鍗犲鏁�
+
+| `mes_qc_indicator.result_type` | 鏁伴噺 | 鑳藉惁琚尯闂村垽瀹� |
+|---|---|---|
+| 3 = 鏂囨湰 | **19** | 涓嶈兘 |
+| 1 = 娴偣 | 12 | 鑳斤紙浣嗛渶涓婁笅闄愶級 |
+| NULL锛堝垎缁勯」锛� | 3 | 涓嶉�傜敤 |
+
+澶栧舰濡傘�屽瑙� = 婢勬竻閫忔槑娑蹭綋锛屾棤鏈烘鏉傝川銆嶆槸鏂囨湰鍊硷紝娌℃湁涓婁笅闄愶紝鍒ゅ畾鍣ㄧ粰涓嶅嚭 PASS/FAIL銆�
+
+#### 浜嬪疄 5锛歚judge_flag`锛堟槸鍚﹀弬涓庡悎鏍煎垽瀹氾級鍦ㄥ崟鎹晶涓簡
+
+| 琛� | 鏄惁鏈� `judge_flag` |
+|---|---|
+| `mes_qc_template_indicator` | **鏈�**锛坄tinyint`锛屾敞閲娿�屾槸鍚﹀弬涓庡悎鏍煎垽瀹氾細1=鏄紝0=鍚︺�嶏級 |
+| `mes_qc_iqc_line` | **娌℃湁杩欎竴鍒�** |
+
+妯℃澘 6 閲� 7 椤� `judge_flag=1`銆�9 椤� `judge_flag=0`銆備絾鐢熸垚鍗曟嵁鍚庤繖涓俊鎭�**涓嶅彲鎭㈠**鈥斺�斿崟鎹鍙墿 `indicator_id / 鏍囧噯鍊� / 涓婁笅闄� / 缂洪櫡鏁伴噺 / 澶囨敞`銆�
+
+鈬� 鎶ュ憡鑻ユ兂銆屽彧缁熻鍙備笌鍒ゅ畾鐨勯」銆嶏紝**涓嶈兘鍙鍗曟嵁锛屽繀椤诲洖鏌ユ楠屾ā鏉�**锛涙垨鑰呯粰鍗曟嵁琛屽姞涓�鍒楋紙鏀硅〃锛夈��
+
+#### 浜嬪疄 6锛氳搴忎俊鎭篃鍦ㄥ崟鎹晶涓簡
+
+妯℃澘鏈� `sort_order`锛�10/20/40/50/60/70 杩欐牱鐨勫垎缁勬帓搴忥級锛屽崟鎹**娌℃湁**銆傛墍浠ユ姤鍛婇噷妫�楠岄」鐨勯『搴忓彧鑳芥寜 `line.id`锛屼笌妫�楠屾ā鏉夸笂鐨勬帓鍒楅『搴忓彲鑳戒笉涓�鑷淬��
+
+---
+
+## 鍥涖�佺洰鏍囨祦绋�
+
+```
+璐ㄦ鍗曞垪琛� / 璇︽儏
+ 鈹�
+ 鈹溾攢 鐐广�岀敓鎴愭姤鍛娿��
+ 鈹� 鈹�
+ 鈹� 鈹溾攢 1. 閫夋姤鍛婃ā鏉匡紙浜哄伐閫夛紝宸插畾鍙e緞锛�
+ 鈹� 鈹� 鈹斺攢 鍒楄〃鎸� qc_report_template.report_type = 璇ヨ川妫�绫诲瀷 杩囨护
+ 鈹� 鈹�
+ 鈹� 鈹溾攢 2. 鍚庣锛氭媺璐ㄦ鍗曚富浣� + 琛屾槑缁� + 鏍峰搧瀹炴祴鍊� 鈫� 鎷兼垚 ReportContext
+ 鈹� 鈹�
+ 鈹� 鈹溾攢 3. 鍚庣锛氳皟鏃㈡湁 instanceService.generate锛堟覆鏌� + 钀藉簱 + 鍐荤粨蹇収锛�
+ 鈹� 鈹� 鈹斺攢 businessId = 璐ㄦ鍗� ID锛宐usinessType = mes_qc_iqc / ipqc / oqc / rqc
+ 鈹� 鈹�
+ 鈹� 鈹斺攢 4. 杩斿洖鎶ュ憡瀹炰緥 ID 涓庢姤鍛婄紪鍙�
+ 鈹�
+ 鈹溾攢 鎶ュ憡宸茬敓鎴� 鈫� 鍒楄〃/璇︽儏鍙洿鎺ヨ烦杞姤鍛婂疄渚嬶紙鎸� businessType + businessId 鍙嶆煡锛屾煡璇㈡潯浠跺凡灏辩华锛�
+ 鈹�
+ 鈹斺攢 鎶ュ憡瀹炰緥椤� 鈫� 銆屽鍑� PDF銆嶁啋 褰掓。闄勪欢搴擄紙鏃㈡湁鑳藉姏锛屼笉鍔級
+```
+
+**鍞竴钀藉簱鐐规槸鏃㈡湁鐨勬ā鏉跨増鏈� + 瀹炰緥**锛屾湰鏂规涓嶆柊澧炰换浣曚繚瀛樿矾寰勩��
+
+---
+
+## 浜斻�佸瓧娈垫槧灏勶紙鏍稿績锛�
+
+### 5.1 鎶ュ憡绾у瓧娈碉細`ReportContext.report`
+
+| `ReportContext` 瀛楁 | 鍥涚被鍗曟嵁鏉ユ簮 | 澶囨敞 |
+|---|---|---|
+| `reportNo` | **涓嶅彇璐ㄦ鍗� code**锛岀敱 `ReportNoGenerator` 鎸� `QR+鏃ユ湡+娴佹按` 鐢熸垚 | 鐢ㄦ埛鍙湪鐢熸垚鏃惰鐩� |
+| `reportName` | `name`锛堟楠屽崟鍚嶇О锛� | 鍥涚被閮芥湁 |
+| `sampleNo` | `mes_qc_indicator_result.code`锛堟牱鍝佺紪鍙凤紝瀹炴祴 `IR_20260917001`锛� | 澶氭牱鍝佽 搂6.4 |
+| `productCode` | `mes_md_item.code`锛堢粡 `item_id`锛� | 瀹炴祴鍊� `2` |
+| `productName` | `mes_md_item.name` | 瀹炴祴鍊� `绮捐悩` |
+| `spec` | `mes_md_item.specification` | **瀹炴祴涓� NULL**锛屾姤鍛婁笂浼氭槸绌� |
+| `batchNo` | IQC 鈫� `vendor_batch`锛汷QC / RQC 鈫� `batch_code`锛�**IPQC 鈫� 鏃犳瀛楁** | 瀹炴祴 IQC 鐨� `vendor_batch` 涓� NULL |
+| `workOrderNo` | IPQC 鈫� `work_order_id` 鏌ュ伐鍗曠紪鍙凤紱鍏朵綑涓夌被鏃� | 寤鸿鍥為��鐢� `source_doc_code` |
+| `inspectType` | 鐢辫川妫�绫诲瀷鏄犲皠锛欼QC鈫掓潵鏂欐楠� / IPQC鈫掕繃绋嬫楠� / OQC鈫掑嚭璐ф楠� / RQC鈫掗��璐ф楠� | 鍙� `MesQcTypeEnum` 鐨� name |
+| `inspector` | `inspector_user_id` 鈫� `system_users.nickname` | 鍥涚被閮芥湁 |
+| `inspectDate` | `inspect_date` | 鍥涚被閮芥湁 |
+| `department` | **鍥涚被鍗曟嵁閮芥病鏈夐儴闂ㄥ瓧娈�** | 瑙� 搂6.1 鍐崇瓥 |
+| `customerName` | OQC 鈫� `client_id` 鏌� CRM 瀹㈡埛鍚嶏紱鍏朵綑涓夌被鏃� | |
+| `supplierName` | IQC 鈫� `vendor_id` 鏌� SRM 渚涘簲鍟嗗悕锛涘叾浣欎笁绫绘棤 | 瀹炴祴涓� NULL |
+| `result` / `resultText` / `conclusion` / `passRate` / `total` / `passCount` / `failCount` | **鐢� `ReportEvaluator` 绠楀嚭骞惰鐩�**锛岃皟鐢ㄦ柟涓嶅繀濉� | 瑙� 搂6.1 |
+
+### 5.2 妫�楠岄」锛歚ReportContext.inspectionItems[]`
+
+| `InspectionItem` 瀛楁 | 鏉ユ簮 | 澶囨敞 |
+|---|---|---|
+| `index` | 鐢熸垚鏃舵寜椤哄簭 1..N | |
+| `itemCode` | `mes_qc_indicator.code` | |
+| `itemName` | `mes_qc_indicator.name` | |
+| `standardValue` | `mes_qc_xxx_line.standard_value` | BigDecimal 鈫� 鍘诲熬闆跺瓧绗︿覆锛�**瀹炴祴鍏� NULL**锛� |
+| `actualValue` | `mes_qc_indicator_result_detail.value`锛圫tring锛� | 缁� `result_id` 鈫� `result.qc_id` 鍏宠仈 |
+| `unit` | `mes_qc_xxx_line.unit_measure_id` 鈫� `mes_md_unit_measure.name` | **娉ㄦ剰**锛氭ā鏉夸晶涔熸湁 `unit_measure_id`锛涘疄娴嬩袱鑰呴兘鏄� NULL |
+| `upperLimit` | `mes_qc_xxx_line.max_threshold` | Double锛�**瀹炴祴鍏� NULL**锛� |
+| `lowerLimit` | `mes_qc_xxx_line.min_threshold` | Double锛�**瀹炴祴鍏� NULL**锛� |
+| `result` / `resultText` | 鐢� `ReportEvaluator` 鍐欏洖 | 涓嶅彇 MES 鐨� `check_result` |
+| `remark` | `line.remark` 鎴� `detail.remark`锛�**涓ゅ閮芥湁**锛� | 闇�瀹氬彛寰勶紝瑙� 搂6.5 |
+
+> 鈿� **鍒楀悕涓嶄竴鑷寸殑鍧�**锛氬崟鎹琛ㄧ敤 `max_threshold` / `min_threshold`锛屾楠屾ā鏉胯〃鐢� `threshold_max` / `threshold_min`銆傚啓鏄犲皠鏃跺埆寮勬贩銆�
+
+### 5.3 鍥涚被鍗曟嵁鐨勫樊寮�
+
+| | IQC 鏉ユ枡妫�楠� | IPQC 杩囩▼妫�楠� | OQC 鍑鸿揣妫�楠� | RQC 閫�璐ф楠� |
+|---|---|---|---|---|
+| 涓讳綋琛� | `mes_qc_iqc` | `mes_qc_ipqc` | `mes_qc_oqc` | `mes_qc_rqc` |
+| 琛岃〃 | `mes_qc_iqc_line` | `mes_qc_ipqc_line` | `mes_qc_oqc_line` | `mes_qc_rqc_line` |
+| **琛岃〃鍒楃粨鏋�** | **鍥涜〃瀹屽叏鍚屾瀯**锛�13 鍒椾竴鑷达紝浠呯埗澶栭敭鍒楀悕涓嶅悓锛歚iqc_id` / `ipqc_id` / `oqc_id` / `rqc_id`锛� | | | |
+| 瀵规柟 | `vendor_id`锛圫RM 渚涘簲鍟嗭級 | 鏃� | `client_id`锛圕RM 瀹㈡埛锛� | 鏃� |
+| 鎵规 | `vendor_batch` | **鏃�** | `batch_code` | `batch_code` |
+| 鐢熶骇鍏宠仈 | 鏃� | `work_order_id` / `task_id` / `workstation_id` / `process_id` | 鏃� | 鏃� |
+| 鏃ユ湡 | `receive_date` + `inspect_date` | `inspect_date` | `out_date` + `inspect_date` | `inspect_date` |
+| 鏁伴噺 | 鎺ユ敹 / 妫�娴� / 鍚堟牸 / 涓嶅悎鏍� | 妫�娴� / 鍚堟牸 / 涓嶅悎鏍� + 宸ュ簾 / 鏂欏簾 / 鍏朵粬搴� | 鍑鸿揣 / 妫�娴� / 鍚堟牸 / 涓嶅悎鏍� + 鏈�浣庢娴嬫暟 / 鏈�澶т笉鍚堟牸鏁� | 妫�娴� / 鍚堟牸 / 涓嶅悎鏍� |
+| 鑷湁鍒嗙被 | 鏃� | `type`锛坄MES_IPQC_TYPE`锛� | 鏃� | `type`锛坄mes_rqc_type`锛� |
+| 缁撹 | `check_result`锛堝悎鏍� / 鐗归噰 / 涓嶅悎鏍奸��璐� / 涓嶅悎鏍兼姤搴燂級 | 鍚� | 鍚� | 鍚� |
+
+**鏀惰幏**锛氳琛ㄥ洓琛ㄥ悓鏋勶紝鎰忓懗鐫�**鏄犲皠閫昏緫鍙互鍙啓涓�浠�**锛岀敤娉涘瀷鎴栫粺涓�鎺ュ彛鎵挎帴锛屼笉蹇呭啓鍥涘銆�
+
+---
+
+## 鍏�佸繀椤诲厛鎷嶆澘鐨勫彛寰勶紙鎸夐噸瑕佹�ф帓搴忥級
+
+### 6.1 銆愭渶閲嶈銆戞姤鍛婄殑鍚堟牸缁撹鐢辫皝瀹氾紵
+
+**鍐茬獊鐐�**锛�
+
+| | MES 璐ㄦ鍗� | 鎶ュ憡寮曟搸 |
+|---|---|---|
+| 缁撹鍙栧�� | `check_result`锛氬悎鏍�(1) / **鐗归噰(2)** / 涓嶅悎鏍奸��璐�(3) / 涓嶅悎鏍兼姤搴�(4) | `QualityResult`锛�**鍙湁 PASS / FAIL**锛屽鍔犮�屽緟鍒ゅ畾銆嶅崰浣� |
+| 璋佸~ | **浜哄~鐨�** 鈥斺�� 浜哄彲鑳藉垽銆岀壒閲囥�嶏紙鍙叆搴撲絾闈炲悎鏍硷級 | **绠楀嚭鏉ョ殑** 鈥斺�� 涓婁笅闄愭垨瑙勫垯 |
+| 浼氫笉浼氳瑕嗙洊 | 鈥� | `ReportEvaluator` 鏃犳潯浠舵墽琛� `ReportFields.applyResult(verdict)`锛�**瑕嗙洊**璋冪敤鏂逛紶鍏ョ殑 result / resultText / conclusion |
+
+**蹇呯劧鍑虹幇鐨勭煕鐩�**锛氳川妫�鍗曞垽銆岀壒閲囥�嶏紝鎶ュ憡寮曟搸鍙 PASS/FAIL锛屽鍗婄畻鍑恒�屼笉鍚堟牸銆嶃�傛姤鍛婁笌璐ㄦ鍗曠粨璁烘墦鏋讹紝瀹㈡埛鎷垮埌鎶ュ憡浼氳川鐤戙��
+
+**涓変釜閫夋嫨**锛�
+
+| 鏂规 | 鍋氭硶 | 浠d环 |
+|---|---|---|
+| **A锛堟帹鑽愶級** | 鎶ュ憡缁撹浠�**寮曟搸**涓哄噯锛汳ES 鍘熷垽瀹氬彟瀛樺埌涓�涓�**鏂板鐨勬姤鍛婄骇瀛楁**锛堝 `report.qcResult` / `report.qcResultText`锛夛紝妯℃澘閲屽彲鐢� `{{report.qcResult}}` 鏄剧ず銆岃川妫�鍗曞師鍒わ細鐗归噰銆� | **鍔ㄦ暟鎹绾�**锛氳鏀� `ReportFields` + `ReportContext.reportMap()` + 鍓嶇 `engine/context.ts`锛屼笖 `FrontendConformanceTest` 浼氶�愬瓧瀵规媿锛岄渶鍚屾鍐荤粨浜х墿 |
+| B | 鍙憟鐜板紩鎿庡垽瀹氾紝**瀹屽叏涓嶄綋鐜�** MES 鐨� `check_result` | 闆舵敼鍔紝浣嗘姤鍛婂彲鑳戒笌璐ㄦ鍗曠粨璁轰笉涓�鑷达紙鐗归噰琚垽鎴愪笉鍚堟牸锛夛紝涓旂敤鎴锋棤浠庡療瑙� |
+| C | **浠ヨ川妫�鍗曚负鍑�**锛岃寮曟搸鍒垽 | 寮曟搸娌℃湁銆岃烦杩囧垽瀹氥�嶅紑鍏炽�傝涔堜笉浼犱笂涓嬮檺锛堝垯鍗曢」鍏ㄥ彉寰呭垽瀹氾級銆佽涔堟瘡涓姤鍛婃ā鏉块兘閰� report 绾ц鍒欌�斺��**渚濊禆浜哄伐閰嶆ā鏉匡紝瀹规槗婕�**锛屼笉鑳藉彧闈犱唬鐮佷繚璇� |
+
+> 鎴戠殑寤鸿鏄� **A**銆傜悊鐢辨槸銆岀壒閲囥�嶈繖绫讳腑闂存�佹槸璐ㄩ噺涓氬姟鐨勭湡瀹炵姸鎬侊紝鎶ュ憡涓婄洿鎺ユ姽鎺変細閫犳垚鎶ュ憡涓庡崟鎹涓嶄笂锛涜�� B 鐨勪笉涓�鑷存槸**闈欓粯**鐨勶紝鐢ㄦ埛涓嶄細鍙戠幇锛岄棶棰樹細娴佸埌瀹㈡埛閭h竟銆侫 鐨勪唬浠锋槸鍙帶鐨勨�斺�斿彧鏄姞涓や釜瀛楁锛屼笉鏄敼鍒ゅ畾閫昏緫銆�
+>
+> 浣嗗鏋滃笇鏈�**杩欎竴杞浂濂戠害鏀瑰姩銆佸厛璺戦�氶摼璺�**锛屽彲浠ュ厛鎸� **B** 涓婄嚎骞舵槑纭憡鐭ャ�屾姤鍛婄粨璁轰互鎶ュ憡妯℃澘鐨勫垽瀹氳鍒欎负鍑嗭紝涓庤川妫�鍗曠殑浜哄伐鍒ゅ畾鍙兘涓嶅悓銆嶏紝鎶� A 鐣欎綔涓嬩竴杞��
+
+### 6.2 銆愬喅瀹氭姤鍛婇暱浠�涔堟牱銆戝摢浜涙寚鏍囪鍑虹幇鍦ㄦ姤鍛婁笂锛�
+
+瀹炴祴閭e紶鍗� 16 琛岄噷锛�**9 琛屾槸 `judge_flag=0`**锛屽叾涓寘鍚細
+
+- 3 涓垎缁勬爣棰橀」锛堟按鍒� / 閰稿惈閲� / 姝d竵閱囧惈閲忥紝鏃犲疄娴嬪�硷級
+- 涓棿璁$畻閲忥細鏍囨恫娴撳害 c銆佹秷鑰楁淮瀹氭恫浣撶Н V銆佽瘯鏍疯川閲� m 脳2銆佺О閲忕摱 m0銆佽瘯鏍�+绉伴噺鐡� m1
+
+**銆屾秷鑰楁淮瀹氭恫浣撶Н銆嶅拰銆岀О閲忕摱璐ㄩ噺銆嶆槸鍖栭獙瀹ゅ唴閮ㄧ殑璁$畻杩囩▼锛屼笉璇ュ嚭鐜板湪缁欏鎴风湅鐨勬垚鍝佹楠屾姤鍛婁笂銆�**
+
+涓変釜閫夋嫨锛�
+
+| 鏂规 | 鍋氭硶 |
+|---|---|
+| **A锛堟帹鑽愶級** | **鍙彇 `judge_flag=1` 鐨勯」**锛堣妯℃澘涓� 7 椤癸級浣滀负鎶ュ憡鐨勩�屾楠岄」鐩〃銆嶏紱`judge_flag=0` 鐨勯」涓嶈繘鎶ュ憡 |
+| B | 鍏ㄩ儴杩涙姤鍛婏紝鍒嗙粍椤瑰綋灏忔爣棰樸�佷腑闂撮噺褰撴槑缁嗚 |
+| C | 鍏ㄩ儴杩涙姤鍛婏紝浣嗘寜 `judge_flag` 鍒嗘垚銆屽垽瀹氶」銆嶅拰銆屽弬鑰冮」銆嶄袱涓尯鍧� |
+
+**浠d环锛圓 鐨勯棶棰橈級**锛歚judge_flag` **鍦ㄥ崟鎹涓婁笉瀛樺湪**锛堜簨瀹� 5锛夛紝蹇呴』**鍥炴煡 `mes_qc_template_indicator`**锛堢敤 `mes_qc_iqc.template_id`锛夈�傝繖鏈変袱涓殣鎮o細
+1. 妫�楠屾ā鏉垮彲鑳借鏀硅繃锛堟敼浜� `judge_flag`锛夛紝鎶ュ憡浼氳窡鐫�鍙樷�斺�旇�屾姤鍛婃湰搴斿熀浜�**璐ㄦ鍗曞綋鏃�**鐨勫彛寰勩�傚ソ鍦ㄨ川妫�鍗曟湁鍐荤粨蹇収鏈哄埗锛坄dataSnapshot`锛夛紝钀藉簱鍚庝笉鍙楀奖鍝嶏紝浣�**鐢熸垚鐨勯偅涓�鍒�**鍙栫殑鏄ā鏉垮綋鍓嶅�笺��
+2. 鑻ヨ璐ㄦ鍗曠殑妫�楠屾ā鏉胯鍒犻櫎锛屽洖鏌ユ嬁涓嶅埌 鈫� 闇�瑕佸厹搴曪紙閫�鍖栧埌鏂规 B 鎴栨姤閿欙級銆�
+
+鏇夸唬鍋氭硶锛�**缁欏洓寮犺琛ㄥ悇鍔犱竴鍒� `judge_flag`**锛岀敓鎴愬崟鎹椂浠庢ā鏉垮甫杩囨潵銆傝繖鏍枫�屽崟鎹嚜鍖呭惈銆嶏紝涓嶅啀渚濊禆鍥炴煡銆傞渶瑕佹敼 4 寮犺〃 + 鐢熸垚鍗曟嵁鐨勪唬鐮侊紙灞炰簬 MES 渚ф敼鍔級銆�
+
+> **闇�瑕佷綘瀹�**锛�(A) 鍥炴煡妫�楠屾ā鏉� / (A鈥�) 缁欒琛ㄥ姞鍒楄鍗曟嵁鑷寘鍚� / (B) 鍏ㄩ儴杩涙姤鍛娿��
+
+### 6.3 銆愬墠缃暟鎹棶棰樸�戜笂涓嬮檺涓虹┖ 鈫� 鎶ュ憡浼氬叏銆屽緟鍒ゅ畾銆�
+
+**杩欎笌浠g爜鏃犲叧锛屾槸鏁版嵁闂锛屼絾浼氱洿鎺ュ喅瀹氱敤鎴风湅鍒扮殑鏁堟灉銆�**
+
+瀹炴祴锛氭楠屾ā鏉夸笌璐ㄦ鍗曡鐨� `standard_value` / 涓婁笅闄�**鍏ㄩ儴涓� NULL**銆傛姤鍛婂垽瀹氬櫒鐨勪紭鍏堢骇鏄�岄�愰」瑙勫垯 鈫� 瑙勬牸涓婁笅闄� 鈫� 鏁版嵁鑷甫缁撴灉銆嶏紝鍓嶄袱鏉¢兘钀界┖ 鈫� **姣忎竴椤归兘鏄�屽緟鍒ゅ畾銆�**锛屾姤鍛婄粨璁轰负銆屽緟鍒ゅ畾銆嶃�佸悎鏍肩巼绌虹櫧銆�
+
+涓変釜閫夋嫨锛�
+
+| 鏂规 | 鍋氭硶 |
+|---|---|
+| **A锛堟帹鑽愶級** | **鍏堣ˉ鏁版嵁鍐嶄笂鍔熻兘**锛氭妸杩欏妫�楠屾ā鏉跨殑涓婁笅闄愬綍杩涘幓锛堣嚦灏戠粰 7 涓� `judge_flag=1` 鐨勯」褰曪級銆傚姛鑳界収鍋氾紝浣�**楠屾敹鏃跺繀椤荤敤褰曚簡涓婁笅闄愮殑妯℃澘**锛屽惁鍒欑湅鍒扮殑鍏ㄦ槸銆屽緟鍒ゅ畾銆嶏紝浼氳鍒や负鍔熻兘鍧� |
+| B | 鍔熻兘鍏堜笂锛岀晫闈㈡槑纭彁绀恒�屾湁 N 椤瑰洜缂哄皯瑙勬牸涓婁笅闄愯�屾棤娉曞垽瀹氥�嶏紝寮曞鐢ㄦ埛鍘昏ˉ |
+| C | 闈犳姤鍛婃ā鏉跨殑鍒ゅ畾瑙勫垯鍏滃簳锛堣鍒欏彲浠ヤ粠鎸囨爣缂栫爜 / 鏂囨湰鍊煎垽鏂級 |
+
+> **寤鸿 A + B 鍚屾椂鍋�**锛氫唬鐮佺収鍋氾紝浣嗗綋銆屾棤浠讳綍涓�椤瑰彲鍒ゅ畾銆嶆椂锛岀敓鎴愮粨鏋滈噷鍥炰竴鏉℃槑纭彁绀衡�斺�斻�屾湰娆℃姤鍛婃湁 N 椤瑰洜缂哄皯瑙勬牸涓婁笅闄愯鍒や负銆庡緟鍒ゅ畾銆忥紝璇峰埌妫�楠屾ā鏉夸腑琛ュ厖涓婁笅闄愩�嶏紝骞堕�忎紶鍒板墠绔�傝繖鏍锋棦涓嶅亣瑁呮垚鍔燂紝涔熶笉闈欓粯銆�
+
+### 6.4 涓�涓川妫�鍗曞浠芥牱鍝� / 鍚屼竴鎸囨爣澶氭潯瀹炴祴鍊�
+
+**瀹炴祴鍒颁袱绉嶅鏉傚害**锛�
+
+1. 鍚屼竴鎸囨爣澶氭潯瀹炴祴鍊硷細`閰稿惈閲忕粨鏋� w3` 鍦ㄥ悓涓�浠芥牱鍝佷笅鏈� 0.09 涓� 0.095 涓ゆ潯銆�
+2. 澶氭牱鍝侊細`mes_qc_indicator_result` 缁撴瀯涓婃敮鎸佷竴涓川妫�鍗曟寕 N 鏉℃牱鍝佽褰曪紙`qc_id` + `qc_type` 鍏宠仈锛夛紝浣�**瀹炴祴搴撻噷鍙湁 1 鏉�**锛屾棤娉曡瘉瀹炲疄闄呬笟鍔′細涓嶄細鍑虹幇銆�
+
+`InspectionItem` 鏄�**鎵佸钩涓�灞�**锛屾棤娉曡〃杈俱�屾牱鍝併�嶈繖涓�灞傘��
+
+| 鏂规 | 鍋氭硶 |
+|---|---|
+| **A锛堟帹鑽愶級** | 涓�涓� (鏍峰搧, 鎸囨爣) 缁勫悎 = 涓�琛屾楠岄」锛沗sampleNo` 鎷艰繘 `itemCode` 鎴� `remark` 浠ュ尯鍒嗐�傚鏍峰搧鏃舵姤鍛婂彉闀夸絾淇℃伅涓嶄涪 |
+| B | 鍙彇**绗竴浠芥牱鍝�**锛屽叾浣欏拷鐣ュ苟鍦ㄦ姤鍛� warnings 閲屾彁绀� |
+| C | 鍚屼竴鎸囨爣澶氭潯瀹炴祴鍊煎彇**鏈�鍚庝竴鏉�**锛堣涓哄娴嬭鐩栵級 |
+
+> **闇�瑕佷綘纭涓氬姟浜嬪疄**锛�**IQC / IPQC / OQC / RQC 瀹為檯浼氫笉浼氬綍澶氫唤鏍峰搧锛熷悓涓�鎸囨爣浼氫笉浼氬綍澶氭锛�** 杩欏喅瀹氫簡閫� A 杩樻槸 B/C銆傜洰鍓嶅簱閲屽彧鏈� 1 浠芥牱鍝侊紝鎴戠粰涓嶅嚭缁撹銆�
+
+### 6.5 鍏朵綑闇�瑕佸畾鐨勫皬鍙e緞
+
+| 闂 | 璇存槑 | 寤鸿 |
+|---|---|---|
+| `remark` 鍙栧摢涓� | 琛岃〃涓庣粨鏋滄槑缁�**閮芥湁** `remark` | 鎷兼帴锛歚line.remark` 浣滃垽瀹氫緷鎹娉紝`detail.remark` 浣滃疄娴嬪娉� |
+| 鏂囨湰鍨嬫寚鏍囨�庝箞鍔� | 19/34 鏄枃鏈瀷锛屾棤涓婁笅闄� 鈫� 蹇呯劧銆屽緟鍒ゅ畾銆� | 鎶ュ憡涓婂甯稿睍绀烘枃鏈�硷紝缁撹鏍囨敞鑰屼笉鏄姤閿欙紱闇�瑕佸垽瀹氬氨閰嶆ā鏉胯鍒� |
+| 鎶ュ憡閲岀殑妫�楠岄」椤哄簭 | 鍗曟嵁琛屾棤 `sort_order`锛堜簨瀹� 6锛� | 鎸� `line.id`锛涜嫢瑕佹寜妯℃澘椤哄簭闇�鍥炴煡 `mes_qc_template_indicator.sort_order` |
+| 璐ㄦ鍗曚粈涔堟椂鍊欏厑璁稿嚭鎶ュ憡 | 搴撻噷鍞竴閭e紶鍗� `status=0`锛堣崏绋匡級涓� `check_result=NULL` | **寤鸿锛歚status != 宸插畬鎴恅 鎴� `check_result` 涓虹┖鏃舵嫆缁�**锛屾姤绮剧‘閿欒鐮侊紙瑙� 搂7.3锛夛紝涓嶇敓鎴愬崐鎴愬搧鎶ュ憡 |
+| `department` 浠庡摢鏉� | 鍥涚被鍗曟嵁閮芥病鏈夐儴闂ㄥ瓧娈� | 鐢辨楠屼汉鎵�灞為儴闂ㄥ甫鍑猴紱鎴栫暀绌虹敱妯℃澘涓婂啓姝� |
+| 涓�寮犺川妫�鍗曡兘鍚﹀嚭澶氫唤鎶ュ憡 | 缁撴瀯涓婂厑璁革紙瀹炰緥琛ㄦ棤鍞竴绾︽潫锛� | **寤鸿鍏佽**锛氬悓涓�寮犲崟鐢ㄤ笉鍚屾ā鏉垮嚭涓嶅悓鐢ㄩ�旂殑鎶ュ憡锛堝唴閮ㄧ増 / 瀹㈡埛鐗堬級銆傚弽鏌ュ垪琛ㄨ嚜鐒舵敮鎸� |
+
+---
+
+## 涓冦�佹帴鍙e绾�
+
+### 7.1 鏂板鎺ュ彛
+
+| 鏂规硶 | 璺緞 | 璇存槑 | 鏉冮檺鐮� |
+|---|---|---|---|
+| POST | `/qc-report/instance/generate-from-qc` | 鐢辫川妫�鍗曠敓鎴愭姤鍛� | `qc-report:instance:generate`锛堟柊澧烇級 |
+| GET | `/qc-report/instance/page-by-business` | 鎸夎川妫�鍗曞弽鏌ュ凡鐢熸垚鐨勬姤鍛� | `qc-report:instance:query`锛堝鐢級 |
+
+> 鍙嶆煡鍏跺疄鍙互鐩存帴澶嶇敤鏃㈡湁鐨� `GET /qc-report/instance/page?businessType=...&businessId=...`锛堟煡璇㈡潯浠跺凡瀛樺湪锛夛紝
+> 涓婅〃鐨� `page-by-business` 鍙槸涓轰簡璁╁墠绔皯浼犱袱涓弬鏁帮紝**鍙�夛紝涓嶅繀瑕�**銆�
+
+### 7.2 璇锋眰 / 鍝嶅簲
+
+**璇锋眰** `POST /qc-report/instance/generate-from-qc`
+
+| 鍙傛暟 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|---|---|---|---|
+| `qcType` | String | 鏄� | `IQC` / `IPQC` / `OQC` / `RQC`锛屽喅瀹氳鍝紶琛� |
+| `qcId` | Long | 鏄� | 璐ㄦ鍗� ID |
+| `templateId` | Long | 鏄� | **鎶ュ憡妯℃澘 ID锛屼汉宸ラ��**锛堝凡瀹氬彛寰勶級 |
+| `version` | String | 鍚� | 鎶ュ憡妯℃澘鐗堟湰锛涗笉浼犵敤褰撳墠宸插彂甯冪増鏈� |
+| `reportNo` | String | 鍚� | 鎶ュ憡缂栧彿锛涗笉浼犺嚜鍔ㄧ敓鎴� |
+| `sampleStrategy` | String | 鍚� | 澶氭牱鍝佸彛寰勶紝瑙� 搂6.4銆傞粯璁� `FIRST` |
+
+**鍝嶅簲**
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|---|---|---|
+| `id` | Long | 鎶ュ憡瀹炰緥 ID |
+| `reportNo` | String | 鎶ュ憡缂栧彿 |
+| `templateVersion` | String | 瀹為檯浣跨敤鐨勬ā鏉跨増鏈� |
+| `itemCount` | Integer | 鏈鍐欏叆鐨勬楠岄」鏉℃暟 |
+| `undecidableCount` | Integer | **鍥犵己灏戜笂涓嬮檺 / 瑙勫垯鑰屻�屽緟鍒ゅ畾銆嶇殑椤规暟**锛埪�6.3-B 鐨勮惤鍦帮級 |
+| `warnings` | String[] | 杞彁绀猴細璺宠繃鐨勫垎缁勯」銆佽鎴柇鐨勫浣欏疄娴嬪�笺�佹牱鍝佺殑鍙栬垗 |
+| `errors` | String[] | 娓叉煋鏈熸暟鎹己鍙o紙鏃㈡湁鏈哄埗锛� |
+
+### 7.3 閿欒鐮侊紙鎷燂紝`1_070_105_xxx` 娈碉級
+
+> 鈿� **鏈妭鏄柟妗堥樁娈垫嫙绋匡紝瀹為檯瀹炵幇宸插亸绂烩�斺�斾互 `docs/qc_report_generate_from_qc_frontend_integration.md` 涓庝唬鐮佷负鍑�**锛�
+> `105_004`锛堟ā鏉夸笉瀛樺湪/宸插仠鐢級涓� `105_007`锛堟ā鏉挎棤宸插彂甯冪増鏈級**鏈疄鐜�**锛屾敼涓哄鐢ㄦ棦鏈夐敊璇爜
+> `1_070_100_000`/`1_070_100_002`/`1_070_101_007`/`1_070_101_008`銆傜悊鐢憋細閭e嚑鏉℃枃妗堟湰鏉ュ氨绮剧‘锛�
+> 鍐嶉�犱竴閬嶅彧浼氬涓ゆ潯浼氭紓绉荤殑鍓湰銆傚疄闄呰惤鍦扮殑鏄笅闈㈡爣 鉁� 鐨勫叚鏉°��
+
+| 鐮� | 鍦烘櫙 | 鏂囨瑕佺偣锛堥伒瀹� `error-message-precision.md`锛� | 钀藉湴 |
+|---|---|---|---|
+| `105_000` | 璐ㄦ绫诲瀷涓嶅悎娉� | 鎸囨槑鏀跺埌鐨勫�间笌鍏佽鐨勫洓鍊� | 鉁� 宸插疄鐜� |
+| `105_001` | 璐ㄦ鍗曚笉瀛樺湪 | 鎸囨槑绫诲瀷 + ID | 鉁� 宸插疄鐜� |
+| `105_002` | 璐ㄦ鍗曟湭瀹屾垚锛屼笉鑳藉嚭鎶ュ憡 | 缁欏嚭褰撳墠鐘舵�佸悕 + 寤鸿鍔ㄤ綔锛堝厛鎶婂崟鎹蛋瀹岋級 | 鉁� 宸插疄鐜� |
+| `105_003` | 璐ㄦ鍗曟湭鍒ゅ畾锛坄check_result` 涓虹┖锛� | 缁欏嚭褰撳墠鍊� + 寤鸿鍔ㄤ綔 | 鉁� 宸插疄鐜� |
+| ~~`105_004`~~ | ~~鎶ュ憡妯℃澘涓嶅瓨鍦� / 宸插仠鐢▇~ | ~~鎸囨槑妯℃澘 ID 涓庣姸鎬亊~ | 鉂� **鏈疄鐜�**锛屽鐢� `1_070_100_000` / `1_070_100_002` |
+| `105_005` | 鎶ュ憡妯℃澘鐨勬姤鍛婄被鍨嬩笌璐ㄦ鍗曚笉绗� | **缁欏嚭鍙屾柟鍊�**锛堟ā鏉挎槸 IPQC锛岃川妫�鍗曟槸 IQC锛� | 鉁� 宸插疄鐜帮紙妯℃澘鏈厤绫诲瀷鏃跺鐢ㄥ悓鐮併�佹崲鏂囨锛� |
+| `105_006` | 璐ㄦ鍗曟病鏈夊彲鐢ㄧ殑妫�楠岄」 | 璇存槑鍘熷洜锛堟棤琛屾槑缁� / 鍏ㄩ儴涓哄垎缁勯」锛� | 鉁� 宸插疄鐜� |
+| ~~`105_007`~~ | ~~鎶ュ憡妯℃澘鏃犲凡鍙戝竷鐗堟湰~~ | ~~寤鸿鍏堝幓璁捐鍣ㄥ彂甯儈~ | 鉂� **鏈疄鐜�**锛屽鐢� `1_070_101_007` / `1_070_101_008` |
+
+> **`105_005` 璇存槑**锛氭ā鏉跨殑 `report_type` 涓庤川妫�鍗曠被鍨嬩笉绗︽椂**鎷掔粷**锛岃繕鏄�**鍏佽浣嗚鍛�**锛�
+> 宸叉寜**鎷掔粷**钀藉湴锛堥槻姝� IQC 鍗曞嚭鎴愬嚭璐ф姤鍛婅繖绉嶄綆绾ч敊璇級锛屽苟鍦ㄥ墠绔�夋ā鏉挎椂**鍙垪鍚岀被鍨嬬殑妯℃澘**锛�
+> 璁╃敤鎴锋牴鏈�変笉鍒伴敊鐨勩��
+
+### 7.4 钀藉簱绾﹀畾
+
+| 瀹炰緥瀛楁 | 鍊� |
+|---|---|
+| `businessId` | `String.valueOf(qcId)` |
+| `businessType` | `mes_qc_iqc` / `mes_qc_ipqc` / `mes_qc_oqc` / `mes_qc_rqc` |
+| `dataSnapshot` | 鏃㈡湁鏈哄埗鑷姩鍐荤粨锛�**涓嶅姩** |
+
+> 鈿� **`businessType` 瀛楃涓插繀椤讳笌 `QcReportInstanceGenerateReqVO` 閲屽凡鏈夌殑绀轰緥鍊煎畬鍏ㄤ竴鑷�**锛坄mes_qc_iqc` 绛夛級锛�
+> 鍚﹀垯鍙嶆煡浼氭煡涓嶅埌銆傝繖鍥涗釜瀛楃涓叉槸浜嬪疄涓婄殑濂戠害銆�
+
+---
+
+## 鍏�佸墠绔仈璋冩柟妗�
+
+### 8.1 娑夊強椤甸潰
+
+| 椤甸潰 | 鏀瑰姩 |
+|---|---|
+| MES 璐ㄦ 鈫� 鏉ユ枡妫�楠岋紙IQC锛夊垪琛� / 璇︽儏 | 鍔犮�岀敓鎴愭姤鍛娿�嶆寜閽� + 閫夋ā鏉垮脊绐� + 銆屾煡鐪嬫姤鍛娿�嶅叆鍙� |
+| MES 璐ㄦ 鈫� 杩囩▼妫�楠岋紙IPQC锛� | 鍚屼笂 |
+| MES 璐ㄦ 鈫� 鍑鸿揣妫�楠岋紙OQC锛� | 鍚屼笂 |
+| MES 璐ㄦ 鈫� 閫�璐ф楠岋紙RQC锛� | 鍚屼笂 |
+| MES 璐ㄦ 鈫� 鎶ュ憡瀹炰緥锛堟棦鏈夛級 | 鏃犻渶鏀瑰姩锛屼絾浼氬紑濮嬪嚭鐜扮湡瀹炴暟鎹� |
+
+### 8.2 鎸夐挳涓庢潈闄�
+
+| 鎸夐挳 | 鏉冮檺鐮� | 浣嶇疆 |
+|---|---|---|
+| 鐢熸垚鎶ュ憡 | `qc-report:instance:generate` | 璐ㄦ鍗曞垪琛ㄦ搷浣滃垪銆佽鎯呴〉 |
+| 鏌ョ湅鎶ュ憡 | `qc-report:instance:query`锛堝鐢級 | 鍚屼竴浣嶇疆锛屼粎鍦ㄥ凡鏈夋姤鍛婃椂鏄剧ず |
+
+### 8.3 閫夋ā鏉垮脊绐�
+
+| 椤� | 璇存槑 |
+|---|---|
+| 妯℃澘鍒楄〃鏁版嵁婧� | `GET /qc-report/template/page`锛屽墠绔�**蹇呴』甯� `reportType` = 褰撳墠璐ㄦ绫诲瀷** 鐨勮繃婊ゆ潯浠� |
+| 灞曠ず瀛楁 | 妯℃澘鍚嶇О銆佺紪鐮併�佸綋鍓嶇増鏈�佺姸鎬� |
+| 杩囨护 | 鍙垪**鍚敤**涓�**鏈夊凡鍙戝竷鐗堟湰**鐨勬ā鏉� |
+| 榛樿涓嶉�変腑 | 宸插畾鍙e緞鏄�屼汉宸ラ�夈�嶏紝涓嶈棰勯�夛紝閬垮厤璇偣 |
+| 鏃犲彲鐢ㄦā鏉挎椂 | 鏄庣‘鎻愮ず銆岃鎶ュ憡绫诲瀷涓嬭繕娌℃湁鍙敤妯℃澘锛岃鍏堝埌鎶ュ憡妯℃澘涓璁″苟鍙戝竷銆嶏紝骞剁粰鍑鸿烦杞叆鍙� |
+
+### 8.4 鐢熸垚鍚庣殑琛ㄧ幇
+
+| 鍦烘櫙 | 琛ㄧ幇 |
+|---|---|
+| 鐢熸垚鎴愬姛 | 鎻愮ず鎶ュ憡缂栧彿锛涙妸銆岀敓鎴愭姤鍛娿�嶆寜閽崲鎴愩�屾煡鐪嬫姤鍛娿�嶏紱鑻� `warnings` 闈炵┖锛岄�愭潯鎻愮ず |
+| `undecidableCount > 0` | **蹇呴』鎻愮ず**锛氥�屾湰娆℃姤鍛婃湁 N 椤瑰洜缂哄皯瑙勬牸涓婁笅闄愯鍒や负銆庡緟鍒ゅ畾銆忥紝璇峰埌妫�楠屾ā鏉夸腑琛ュ厖鍚庨噸鏂扮敓鎴愩�� |
+| 鐢熸垚澶辫触 | 鎸� 搂7.3 鐨勯敊璇爜鍘熸牱灞曠ず鍚庣鏂囨锛屽墠绔笉瑕佸啀鍖呬竴灞傦紙鏃㈡湁鍙e緞锛� |
+| 璐ㄦ鍗曟湭瀹屾垚 | 鎸夐挳缃伆骞剁粰鍑哄師鍥狅紝涓嶈璁╃敤鎴风偣浜嗘墠鎶ラ敊 |
+
+### 8.5 璋冪敤鏃跺簭锛堝叧閿細淇℃伅甯﹀叆锛�
+
+```
+鎵撳紑璐ㄦ鍗曞垪琛�
+ 鈫� GET /mes/qc-iqc/page 锛堟棦鏈夛級
+ 鈫� 瀵瑰凡瀹屾垚鐨勫崟锛欸ET /qc-report/instance/page?businessType=mes_qc_iqc&businessId={id}
+ 鈹斺攢 鏈夋暟鎹� 鈫� 鏄剧ず銆屾煡鐪嬫姤鍛娿�嶏紱鏃犳暟鎹� 鈫� 鏄剧ず銆岀敓鎴愭姤鍛娿��
+
+鐐广�岀敓鎴愭姤鍛娿��
+ 鈫� GET /qc-report/template/page?reportType=IQC&status=0 锛堝彧鍒楀彲鐢ㄦā鏉匡級
+ 鈫� 鐢ㄦ埛閫夋ā鏉�
+ 鈫� POST /qc-report/instance/generate-from-qc { qcType, qcId, templateId }
+ 鈫� 鎷垮埌 reportId / reportNo / undecidableCount / warnings
+
+鐐广�屾煡鐪嬫姤鍛娿��
+ 鈫� 璺宠浆鏃㈡湁鎶ュ憡瀹炰緥璇︽儏椤碉紙鐢� reportId锛�
+```
+
+**涓嶅甫鍏ョ殑涓滆タ**锛氭姤鍛婃ā鏉�**涓嶈蹇�**璐ㄦ鍗曠殑浠讳綍淇℃伅锛宍templateId` 姣忔鐢辩敤鎴烽�夛紙宸插畾鍙e緞锛夛紱璐ㄦ鍗曚篃**涓嶅瓨**鎶ュ憡 ID锛屽弽鏌ラ潬 `businessType + businessId` 鏌ヨ銆�
+
+### 8.6 娉ㄦ剰浜嬮」
+
+- **鍙嶆煡鏄煡璇㈣�屼笉鏄瓧娈�**锛氫笉瑕佸湪璐ㄦ鍗曡〃涓婂姞銆屾姤鍛� ID銆嶅垪锛堣繚鍙� `file-upload.md` 鍚岀被绮剧鈥斺�斾笟鍔¤〃涓嶅瓨娲剧敓寮曠敤锛夛紝鐢ㄥ疄渚嬭〃鐨� `businessType/businessId` 鍙嶆煡銆�
+- **涓�涓川妫�鍗曞彲鑳芥湁澶氫唤鎶ュ憡**锛氬弽鏌ヨ繑鍥炲垪琛紝UI 瑕佽兘灞曠ず澶氫唤锛堝銆屾煡鐪嬫姤鍛� (2)銆嶏級銆�
+- **鎶ュ憡妯℃澘鐨勭被鍨嬭繃婊ゅ繀椤荤敱鍓嶇浼�**锛氬悗绔篃浼氭牎楠岋紙搂7.3 `105_005`锛夛紝浣嗗墠绔繃婊よ兘璁╃敤鎴锋牴鏈�変笉鍒伴敊鐨勩��
+- **寤鸿鍚屾椂鏍¢獙璐ㄦ鍗曠姸鎬�**锛歚status != 宸插畬鎴恅 鏃舵寜閽疆鐏帮紝鍒鐢ㄦ埛鐧界偣銆�
+- **`mes:qc-*-:query` 涓� `qc-report:instance:generate` 鏄袱涓嫭绔嬫潈闄�**锛氫竴涓帶鍒惰兘涓嶈兘鐪嬭川妫�鍗曪紝涓�涓帶鍒惰兘涓嶈兘鍑烘姤鍛娿�傜粰杞﹂棿鐝粍闀垮彧寮�鍓嶈�呭嵆鍙��
+
+---
+
+## 涔濄�佹槑纭笉鍋氾紙闃茶寖鍥磋敁寤讹級
+
+1. **涓嶅悎骞躲�屾楠屾ā鏉裤�嶄笌銆屾姤鍛婃ā鏉裤��**鈥斺�斾袱鑰呰亴璐d笉鍚岋紙妫�浠�涔� vs 闀夸粈涔堟牱锛夈��
+2. **涓嶅仛銆岄粯璁ゆā鏉裤��**鈥斺�斿凡瀹氬彛寰勬槸姣忔浜哄伐閫夈��
+3. **涓嶈嚜鍔ㄧ敓鎴愭姤鍛�**鈥斺�旇川妫�鍗曞畬鎴愭椂鑷姩鍑烘姤鍛婏紝闇�瑕佸厛瀹氥�岀敤鍝釜妯℃澘銆嶏紝涓庡凡瀹氬彛寰勫啿绐併��
+4. **涓嶅仛鎵归噺鐢熸垚**锛堜竴娆$粰涓�鎵硅川妫�鍗曞嚭鎶ュ憡锛夈��
+5. **涓嶆敼鎶ュ憡瀹炰緥鐨勫鍑� / 褰掓。閾捐矾**鈥斺�擯DF 鍑轰欢宸查獙鏀讹紝鍘熸牱澶嶇敤銆�
+6. **涓嶅仛銆屾姤鍛婂洖鍐欒川妫�鍗曘��**鈥斺�旀姤鍛婄粨璁轰笉鏀瑰啓 `mes_qc_*.check_result`銆�
+7. **涓嶅湪璐ㄦ鍗曡〃鍔犳姤鍛婂紩鐢ㄥ垪**锛堣 搂8.6锛夈��
+8. **涓嶆敼 `HtmlRenderer` / `BASE_CSS`**鈥斺�斾細鐮村潖 `FrontendConformanceTest` 涓庡瓨閲忔姤鍛婄殑鍙鐜版�э紙鏃㈡湁绾㈢嚎锛夈��
+9. **涓嶅姩 ERP / CRM / MES 涓夊 `tempFile.delete()` 缂洪櫡**锛堜笁澶勫悓鏋勶紝搴斿崟鐙紑淇椤癸級銆�
+10. **涓嶉『鎵嬭ˉ ERP/CRM 鐨勫悓绫诲鎺�**銆�
+11. **涓嶅仛浜岀淮鐮佺敓鎴�**銆乣GENERATING`/`FAILED` 瀹炰緥鐘舵�佹祦杞�乣qc_report_data_source` / `qc_report_rule` 涓ゅ紶鏃� Java 瀵瑰簲鐨勮〃鈥斺�旂淮鎸佺幇鐘躲��
+
+---
+
+## 鍗併�侀闄╀笌鍓嶇疆
+
+| 椋庨櫓 | 璇存槑 | 澶勭疆 |
+|---|---|---|
+| **涓婁笅闄愪负绌猴紝鎶ュ憡鍏ㄣ�屽緟鍒ゅ畾銆�**锛堟渶楂樹紭鍏堢骇锛� | 搂6.3 宸插疄娴嬨�傞摼璺�氫簡浣嗘晥鏋滃儚鍧忎簡 | 涓婄嚎鍓嶅厛琛ヤ竴濂楁楠屾ā鏉跨殑涓婁笅闄愶紱鍚屾椂钀藉湴 `undecidableCount` 鎻愮ず |
+| **鎶ュ憡缁撹涓庤川妫�鍗曠粨璁轰笉涓�鑷�** | 搂6.1銆傘�岀壒閲囥�嶆棤娉曞湪鎶ュ憡涓婅〃杈� | 鎸� 搂6.1 閫� A锛堝姞瀛楁锛夋垨鏄庣‘鎸� B锛堜功闈㈠憡鐭ュ彛寰勶級 |
+| **`judge_flag` 鍗曟嵁渚т涪澶�** | 搂6.2 浜嬪疄 5銆傛姤鍛婅銆屽彧缁熻鍒ゅ畾椤广�嶅氨寰楀洖鏌ユā鏉� | 閫� 搂6.2 鐨� A锛堝洖鏌ワ級鎴� A鈥诧紙缁� 4 寮犺琛ㄥ姞鍒楋級 |
+| **澶氭牱鍝佸彛寰勬湭瀹�** | 搂6.4銆傚簱閲屽彧鏈� 1 浠芥牱鍝侊紝鏃犳硶璇佸疄涓氬姟瀹炲喌 | **闇�浣犵‘璁や笟鍔′簨瀹�**鍐嶅畾 |
+| **涓�涓寚鏍囧鏉″疄娴嬪��** | 宸插疄娴嬪埌锛坄閰稿惈閲忕粨鏋� w3` 涓ゆ潯锛� | 蹇呴』鍦ㄦ槧灏勯噷澶勭悊锛屼笉鑳藉亣璁句竴瀵逛竴 |
+| **IPQC 娌℃湁鎵规鍙�** | 搂5.3銆傛姤鍛婁笂 `batchNo` 浼氭槸绌� | 妯℃澘璁捐鏃舵敞鎰忥紱鎴栧洖閫�鍙栧伐鍗曞彿 |
+| **琛屽簭涓庢楠屾ā鏉夸笉涓�鑷�** | 搂5.3 浜嬪疄 6銆傚崟鎹棤 `sort_order` | 鎸� `line.id` 鎺掞紱鎴栧洖鏌ユā鏉挎帓搴� |
+| **鍥涚被鍗曟嵁瀛楁宸紓** | 瀵规柟瀛楁銆佹壒娆″瓧娈点�佺敓浜у叧鑱斿悇涓嶇浉鍚� | 琛岃〃鍚屾瀯锛堝埄濂斤級锛屽崟澶村樊寮傜敤涓�涓浆鎹㈡帴鍙f壙鎺� |
+| **璺ㄦā鍧椾緷璧栨柟鍚�** | MES 瑕佽皟 qcreport锛岄渶瑕� `yudao-module-qcreport-api` 瀛愭ā鍧� + MES 鍔犱緷璧� | 鐓� ERP/CRM 鏃㈡湁 `-api` 瀛愭ā鍧楀厛渚嬶紱**娉ㄦ剰涓嶈閫犳垚寰幆渚濊禆** |
+| **`FrontendConformanceTest` 閫愬瓧瀵规媿** | 鑻� 搂6.1 閫� A锛堝姞瀛楁锛夛紝瑕佸悓姝ュ墠绔喕缁撲骇鐗� | 鎻愬墠璇勪及锛屾敼鍔ㄨ涓よ竟鍚屾椂 |
+| **妯℃澘琚敼 / 琚垹** | 搂6.2 闅愭偅銆傚洖鏌ユ楠屾ā鏉挎椂鍙兘鎷垮埌鍙樻洿鍚庣殑鍊� | 鐢熸垚閭e埢鍙栧�� + 瀹炰緥蹇収鍐荤粨锛涙ā鏉垮垹闄ゆ椂缁欏厹搴� |
+
+---
+
+## 鍗佷竴銆佸疄鏂介『搴忥紙渚濊禆鎷撴墤锛岀‘璁ゅ悗鎵ц锛�
+
+| 姝� | 鍐呭 | 渚濊禆 |
+|---|---|---|
+| 0 | **鏈枃妗h幏寰楃‘璁�**锛屄�6 鐨勪簲涓彛寰勬湁缁撹 | 鈥� |
+| 1 | 琛ラ綈鍓嶇疆鏁版嵁锛氭楠屾ā鏉跨殑瑙勬牸涓婁笅闄愶紙搂6.3锛� | 涓庝唬鐮佸彲骞惰 |
+| 2 | `yudao-module-qcreport-api` 瀛愭ā鍧� + MES 鍔犱緷璧� | 鈥� |
+| 3 | `璐ㄦ鍗� 鈫� ReportContext` 鏄犲皠鍣紙绾嚱鏁般�佸彲鍗曟祴锛屽洓绫诲崟鎹叡鐢ㄤ竴浠斤紝琛岃〃鍚屾瀯鍒╁ソ锛� | 姝� 2 |
+| 4 | 鐢熸垚鎺ュ彛 + 閿欒鐮� + 鏉冮檺鐮� | 姝� 3 |
+| 5 | 鍓嶇锛氬洓澶勮川妫�鍗曢〉鍔犳寜閽� / 寮圭獥 / 鍙嶆煡灞曠ず | 姝� 4 |
+| 6 | 绔埌绔仈璋冿細鍥涚被鍗曟嵁鍚勯�犱竴寮狅紙鍚竴寮犲鎸囨爣銆佷竴寮犲甫涓婁笅闄愶級鈫� 鐢熸垚 鈫� 瀵煎嚭 PDF 鈫� 鏍稿鎶ュ憡鍐呭涓庡崟鎹�愰」涓�鑷� | 姝� 5 |
+| 7 | 鐣欑棔锛氳繘搴︽枃妗c�佸墠绔仈璋冩柟妗堝畾绋裤�佷笟鍔″彲瑙嗗寲 mmd/json 澧為噺 + `sync_index.js` | 姝� 6 |
+
+---
+
+## 鍗佷簩銆侀渶瑕佷綘鍥炵瓟鐨勯棶棰樻竻鍗曪紙姹囨�伙級鈥斺�� 宸插叏閮ㄧ瓟澶嶏紝瑙� 搂闆�
+
+鎸夐噸瑕佹�ф帓搴忥紝绛斿畬鍗冲彲寮�宸ワ細
+
+1. **搂6.1 鎶ュ憡鐨勫悎鏍肩粨璁虹敱璋佸畾锛�** 鈥斺�� 閫� A锛堝姞瀛楁鎵胯浇璐ㄦ鍗曞師鍒ゅ畾锛�/ B锛堝彧鍛堢幇寮曟搸鍒ゅ畾锛�/ C锛堜互璐ㄦ鍗曚负鍑嗭級
+2. **搂6.3 涓婁笅闄愪负绌烘�庝箞鍔烇紵** 鈥斺�� 鍏堣ˉ鏁版嵁 / 鍔犳彁绀� / 闈犺鍒欏厹搴曪紙鍙閫夛級
+3. **搂6.2 鍝簺鎸囨爣杩涙姤鍛婏紵** 鈥斺�� 鍙彇 `judge_flag=1`锛堝洖鏌ユā鏉匡級/ 缁欒琛ㄥ姞 `judge_flag` 鍒� / 鍏ㄩ儴杩�
+4. **搂6.4 涓氬姟涓婁細涓嶄細鏈夊浠芥牱鍝侊紵鍚屼竴鎸囨爣浼氫笉浼氬綍澶氭锛�** 鈥斺�� 杩欐槸浜嬪疄闂锛岄渶瑕佷綘纭
+5. **搂7.3 妯℃澘绫诲瀷涓庤川妫�鍗曚笉绗︽椂** 鈥斺�� 鎷掔粷锛堟帹鑽愶級杩樻槸鍏佽骞惰鍛�
+6. **搂6.5 涓�寮犺川妫�鍗曡兘鍚﹀嚭澶氫唤鎶ュ憡锛�** 鈥斺�� 寤鸿鍏佽
diff --git "a/docs/\346\231\272\350\203\275\350\264\250\346\243\200\346\212\245\345\221\212\350\256\276\350\256\241\345\271\263\345\217\260\342\200\224\342\200\224Claude Code Agent \344\270\223\344\270\232\345\274\200\345\217\221\346\217\220\347\244\272\350\257\215.md" "b/docs/\346\231\272\350\203\275\350\264\250\346\243\200\346\212\245\345\221\212\350\256\276\350\256\241\345\271\263\345\217\260\342\200\224\342\200\224Claude Code Agent \344\270\223\344\270\232\345\274\200\345\217\221\346\217\220\347\244\272\350\257\215.md"
new file mode 100644
index 0000000..8a6b346
--- /dev/null
+++ "b/docs/\346\231\272\350\203\275\350\264\250\346\243\200\346\212\245\345\221\212\350\256\276\350\256\241\345\271\263\345\217\260\342\200\224\342\200\224Claude Code Agent \344\270\223\344\270\232\345\274\200\345\217\221\346\217\220\347\244\272\350\257\215.md"
@@ -0,0 +1,2547 @@
+# 鏅鸿兘璐ㄦ鎶ュ憡璁捐骞冲彴
+## Claude Code Senior Full-Stack Agent 寮�鍙戞寚浠�
+
+浣犵幇鍦ㄤ笉鏄櫘閫氫唬鐮佺敓鎴愬姪鎵嬶紝鑰屾槸锛�
+
+> **Senior Full-Stack Engineer + Solution Architect + Vue 3 Expert + GrapesJS 浜屾寮�鍙戜笓瀹� + Spring Boot Expert + Quality Management System Architect**
+
+浣犵殑浠诲姟鏄湪**褰撳墠宸叉湁椤圭洰鍩虹涓�**锛岃璁″苟瀹炵幇涓�涓細
+
+> **涓撲笟绾с�佸彲鎵╁睍銆佸彲閰嶇疆銆佸琛屼笟閫氱敤鐨勫彲瑙嗗寲璐ㄦ鎶ュ憡璁捐涓庣敓鎴愬钩鍙般��**
+
+---
+
+# 0. 鏈�閲嶈鐨勫伐浣滃師鍒�
+
+## 0.1 绗竴鍘熷垯锛氬厛鐞嗚В椤圭洰锛屽啀淇敼浠g爜
+
+**绗竴娆℃墽琛屾椂绂佹鐩存帴澶ч噺鍐欎唬鐮併��**
+
+蹇呴』棣栧厛鎵弿褰撳墠椤圭洰鐪熷疄浠g爜銆�
+
+閲嶇偣妫�鏌ワ細
+
+```text
+package.json
+pnpm-workspace.yaml
+vite.config.*
+tsconfig.*
+src/
+router/
+stores/
+components/
+views/
+layouts/
+plugins/
+utils/
+services/
+```
+
+鍚庣閲嶇偣妫�鏌ワ細
+
+```text
+pom.xml
+src/main/java/
+controller/
+service/
+service/impl/
+mapper/
+domain/
+dto/
+vo/
+config/
+exception/
+security/
+```
+
+鏁版嵁搴撻噸鐐规鏌ワ細
+
+```text
+SQL
+琛ㄧ粨鏋�
+Mapper
+鏁版嵁搴撳垵濮嬪寲鑴氭湰
+鐜版湁涓氬姟琛�
+```
+
+鍚屾椂妫�鏌ワ細
+
+```text
+鐜版湁鏉冮檺浣撶郴
+鐜版湁鏂囦欢鏈嶅姟
+鐜版湁 HTTP Request 灏佽
+鐜版湁 CRUD
+鐜版湁寮圭獥
+鐜版湁瀛楀吀
+鐜版湁鐢ㄦ埛浣撶郴
+鐜版湁鑿滃崟
+鐜版湁鏃ュ織
+鐜版湁寮傚父澶勭悊
+鐜版湁浠g爜瑙勮寖
+```
+
+---
+
+# 1. 褰撳墠椤圭洰鎶�鏈爤蹇呴』浠ョ湡瀹為」鐩负鍑�
+
+褰撳墠椤圭洰宸茬粡瀛樺湪 Vben 浣撶郴浠ュ強 Ant Design Vue 绛変緷璧栥��
+
+渚嬪锛�
+
+```text
+@vben/access
+@vben/common-ui
+@vben/constants
+@vben/hooks
+@vben/icons
+@vben/layouts
+@vben/locales
+@vben/plugins
+@vben/preferences
+@vben/request
+@vben/stores
+@vben/styles
+@vben/types
+@vben/utils
+
+ant-design-vue
+vue
+vue-router
+pinia
+vite
+typescript
+```
+
+鍥犳锛�
+
+## 涓ョ榛樿鏇挎崲椤圭洰 UI 鎶�鏈爤銆�
+
+濡傛灉褰撳墠椤圭洰瀹為檯浣跨敤锛�
+
+```text
+Vben Admin
++
+Ant Design Vue
+```
+
+鍒欐柊寮�鍙戞ā鍧楀繀椤讳紭鍏堜娇鐢細
+
+```text
+Vben
++
+Ant Design Vue
+```
+
+鑰屼笉鏄噸鏂板紩鍏ワ細
+
+```text
+Element Plus
+```
+
+闄ら潪缁忚繃椤圭洰鍒嗘瀽鍚庣‘璁ゅ綋鍓嶄笟鍔℃ā鍧楀凡缁忕粺涓�浣跨敤 Element Plus銆�
+
+---
+
+# 2. 鎶�鏈爤
+
+## 鍓嶇
+
+浼樺厛澶嶇敤椤圭洰鐜版湁锛�
+
+```text
+Vue 3
+TypeScript
+Vite
+Vben Admin
+Ant Design Vue
+Pinia
+Vue Router
+SCSS
+Axios / @vben/request
+```
+
+璁捐鍣細
+
+```text
+GrapesJS
+```
+
+鍙牴鎹疄闄呴渶瑕佷娇鐢� GrapesJS 瀹樻柟鎻掍欢鏈哄埗銆�
+
+---
+
+## 鍚庣
+
+```text
+Java
+Spring Boot
+MyBatis / MyBatis-Plus
+MySQL 8
+Jackson
+```
+
+---
+
+## 鎶ュ憡娓叉煋
+
+```text
+HTML
+CSS
+Playwright
+Chromium
+PDF
+```
+
+---
+
+# 3. 鏂囦欢瀛樺偍绾︽潫
+
+褰撳墠椤圭洰锛�
+
+> **绂佹寮哄埗寮曞叆 MinIO銆�**
+
+浼樺厛浣跨敤褰撳墠椤圭洰宸叉湁鏂囦欢瀛樺偍鏈哄埗銆�
+
+濡傛灉褰撳墠椤圭洰涓嶅瓨鍦ㄧ粺涓�鏂囦欢瀛樺偍鏈嶅姟锛�
+
+璁捐锛�
+
+```text
+FileStorageService
+```
+
+鎶借薄瀛樺偍鑳藉姏锛�
+
+```text
+upload()
+delete()
+getUrl()
+getPath()
+exists()
+```
+
+鏈潵鍙互鎵╁睍锛�
+
+```text
+Local
+OSS
+S3
+COS
+MinIO
+```
+
+浣嗘槸锛�
+
+> 褰撳墠瀹炵幇涓嶈涓轰簡鏈郴缁熷己琛屽鍔� MinIO銆�
+
+---
+
+# 4. 鏈�缁堜笟鍔$洰鏍�
+
+绯荤粺鏍稿績娴佺▼锛�
+
+```text
+鍒涘缓璐ㄦ鎶ュ憡妯℃澘
+ 鈫�
+閫夋嫨绾稿紶
+ 鈫�
+杩涘叆鍙鍖栬璁″櫒
+ 鈫�
+鎷栨嫿缁勪欢
+ 鈫�
+閰嶇疆缁勪欢灞炴��
+ 鈫�
+閰嶇疆鏁版嵁缁戝畾
+ 鈫�
+閰嶇疆璐ㄦ椤圭洰
+ 鈫�
+閰嶇疆鍒ゅ畾瑙勫垯
+ 鈫�
+閰嶇疆鍔ㄦ�佽〃鏍�
+ 鈫�
+棰勮
+ 鈫�
+淇濆瓨妯℃澘
+ 鈫�
+鍒涘缓妯℃澘鐗堟湰
+ 鈫�
+鍙戝竷妯℃澘
+ 鈫�
+涓氬姟绯荤粺璋冪敤
+ 鈫�
+鍔犺浇涓氬姟鏁版嵁
+ 鈫�
+鏁版嵁缁戝畾
+ 鈫�
+瑙勫垯璁$畻
+ 鈫�
+鐢熸垚鏈�缁� HTML
+ 鈫�
+Playwright
+ 鈫�
+Chromium
+ 鈫�
+PDF
+ 鈫�
+淇濆瓨鎶ュ憡瀹炰緥
+```
+
+---
+
+# 5. 绯荤粺瀹氫綅
+
+鏈郴缁熶笉鏄細
+
+```text
+鏅�氬瘜鏂囨湰缂栬緫鍣�
+```
+
+涔熶笉鏄細
+
+```text
+绠�鍗� HTML 鎷栨嫿宸ュ叿
+```
+
+鑰屾槸锛�
+
+```text
+璐ㄩ噺鎶ュ憡浣庝唬鐮佽璁″櫒
++
+璐ㄩ噺鏁版嵁妯″瀷
++
+妯℃澘寮曟搸
++
+鏁版嵁缁戝畾寮曟搸
++
+瑙勫垯寮曟搸
++
+HTML Renderer
++
+PDF Renderer
+```
+
+---
+
+# 6. 绯荤粺鏋舵瀯
+
+蹇呴』淇濇寔浠ヤ笅鏋舵瀯锛�
+
+```text
+ Vue 3
+ 鈹�
+ Vben / Ant Design Vue
+ 鈹�
+ 鈻�
+ Quality Report Designer
+ 鈹�
+ 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹粹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+ 鈹� 鈹�
+ GrapesJS Quality
+ Components
+ 鈹� 鈹�
+ 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+ 鈻�
+ Template Schema
+ 鈹�
+ 鈻�
+ Spring Boot
+ 鈹�
+ 鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹尖攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+ 鈹� 鈹� 鈹�
+ Template API Data Engine Rule Engine
+ 鈹� 鈹� 鈹�
+ 鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹尖攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+ 鈻�
+ Render Engine
+ 鈹�
+ 鈻�
+ HTML
+ 鈹�
+ 鈻�
+ Playwright
+ 鈹�
+ 鈻�
+ Chromium
+ 鈹�
+ 鈻�
+ PDF
+```
+
+---
+
+# 7. 鏍稿績鏋舵瀯鍘熷垯
+
+## 7.1 GrapesJS 涓庢渶缁堟覆鏌撳繀椤昏В鑰�
+
+蹇呴』锛�
+
+```text
+GrapesJS
+ 鈫�
+Template JSON
+ 鈫�
+Render Engine
+ 鈫�
+HTML
+ 鈫�
+PDF
+```
+
+绂佹锛�
+
+```text
+GrapesJS Canvas
+ 鈫�
+鎴浘
+ 鈫�
+PDF
+```
+
+鏈�缁� PDF锛�
+
+> **绂佹浣跨敤鎴浘鏂瑰紡鐢熸垚銆�**
+
+---
+
+# 8. Quality Components
+
+杩欐槸鏁翠釜绯荤粺鏈�閲嶈鐨勬灦鏋勩��
+
+涓嶈鎶婁笟鍔$粍浠跺叏閮ㄧ洿鎺ュ啓姝诲湪 GrapesJS 涓��
+
+蹇呴』寤虹珛鐙珛锛�
+
+```text
+Quality Components
+```
+
+缁勪欢娉ㄥ唽鏈哄埗銆�
+
+鎺ㄨ崘锛�
+
+```text
+src/components/quality/
+
+鈹溾攢鈹� core/
+鈹� 鈹溾攢鈹� types.ts
+鈹� 鈹溾攢鈹� registry.ts
+鈹� 鈹溾攢鈹� factory.ts
+鈹� 鈹溾攢鈹� serializer.ts
+鈹� 鈹斺攢鈹� validator.ts
+鈹�
+鈹溾攢鈹� base/
+鈹溾攢鈹� layout/
+鈹溾攢鈹� inspection/
+鈹溾攢鈹� table/
+鈹溾攢鈹� result/
+鈹溾攢鈹� statistics/
+鈹溾攢鈹� signature/
+鈹溾攢鈹� header/
+鈹溾攢鈹� footer/
+鈹溾攢鈹� barcode/
+鈹溾攢鈹� qrcode/
+鈹斺攢鈹� index.ts
+```
+
+---
+
+# 9. QualityComponentDefinition
+
+璁捐缁熶竴缁勪欢鍗忚銆�
+
+渚嬪锛�
+
+```typescript
+interface QualityComponentDefinition {
+ type: string;
+
+ name: string;
+
+ label: string;
+
+ category: string;
+
+ icon?: string;
+
+ defaults?: Record<string, unknown>;
+
+ traits?: QualityTrait[];
+
+ dataSchema?: QualityDataSchema;
+
+ styleSchema?: QualityStyleSchema;
+
+ propertySchema?: QualityPropertySchema;
+
+ render?: QualityRenderDefinition;
+
+ validate?: QualityValidator;
+
+ serialize?: QualitySerializer;
+
+ deserialize?: QualityDeserializer;
+}
+```
+
+涓嶈澶ч噺浣跨敤锛�
+
+```typescript
+any
+```
+
+浼樺厛浣跨敤锛�
+
+```typescript
+unknown
+Record<string, unknown>
+娉涘瀷
+鏄庣‘ interface
+鑱斿悎绫诲瀷
+```
+
+---
+
+# 10. 缁勪欢蹇呴』鏀寔
+
+姣忎釜 Quality Component 蹇呴』鑳藉锛�
+
+```text
+娉ㄥ唽
+娉ㄩ攢
+鍒嗙被
+鎷栨嫿
+閰嶇疆
+鏁版嵁缁戝畾
+鏍峰紡閰嶇疆
+鏉′欢閰嶇疆
+鏍¢獙
+搴忓垪鍖�
+鍙嶅簭鍒楀寲
+棰勮
+HTML Render
+```
+
+---
+
+# 11. 绗竴鎵圭粍浠�
+
+## 鍩虹缁勪欢
+
+```text
+Text
+Title
+RichText
+Label
+
+Image
+Logo
+
+Container
+Row
+Column
+Section
+Grid
+
+Divider
+Spacer
+```
+
+---
+
+# 12. 璐ㄩ噺涓撲笟缁勪欢
+
+蹇呴』閲嶇偣瀹炵幇锛�
+
+## ReportHeader
+
+```text
+鎶ュ憡鍚嶇О
+鎶ュ憡缂栧彿
+鎶ュ憡鐗堟湰
+鎶ュ憡鏃ユ湡
+妫�娴嬬被鍨�
+```
+
+## SampleInfo
+
+```text
+鏍峰搧鍚嶇О
+鏍峰搧缂栧彿
+浜у搧鍨嬪彿
+瑙勬牸
+鎵规
+鏁伴噺
+渚涘簲鍟�
+瀹㈡埛
+鐢熶骇鏃ユ湡
+閫佹鏃ユ湡
+妫�楠屾棩鏈�
+```
+
+## InspectionItem
+
+```text
+妫�楠岄」鐩�
+妫�楠屾爣鍑�
+妫�楠屾柟娉�
+鎶�鏈姹�
+瀹炴祴鍊�
+鍗曚綅
+鍒ゅ畾
+澶囨敞
+```
+
+---
+
+# 13. QualityTable
+
+杩欐槸鏍稿績缁勪欢涔嬩竴銆�
+
+蹇呴』鏀寔锛�
+
+```text
+鍔ㄦ�佸垪
+鍔ㄦ�佽
+
+鍗曞厓鏍煎悎骞�
+rowspan
+colspan
+
+琛ㄥご
+澶氱骇琛ㄥご
+
+鍥哄畾鍒�
+
+鑷姩鎹㈣
+
+瀛椾綋
+杈规
+瀵归綈
+琛岄珮
+
+鏉′欢鏍峰紡
+
+鏁版嵁缁戝畾
+
+鍔ㄦ�佹暟鎹
+鍔ㄦ�佹暟鎹垪
+
+璺ㄩ〉
+
+閲嶅琛ㄥご
+
+灏忚
+鍚堣
+```
+
+蹇呴』鏀寔锛�
+
+```text
+inspectionItems
+```
+
+鑷姩鐢熸垚锛�
+
+```text
+搴忓彿 | 妫�娴嬮」鐩� | 鏍囧噯鍊� | 瀹炴祴鍊� | 鍗曚綅 | 鍒ゅ畾
+```
+
+绂佹瑕佹眰鐢ㄦ埛鎵嬪伐鍒涘缓 100 琛岃〃鏍笺��
+
+---
+
+# 14. 澶嶆潅妫�娴嬬粨鏋�
+
+鏀寔锛�
+
+## Number
+
+```text
+min
+max
+target
+actual
+unit
+lowerLimit
+upperLimit
+result
+```
+
+## String
+
+```text
+actual
+standard
+result
+```
+
+## Enum
+
+```text
+PASS
+FAIL
+```
+
+## Boolean
+
+```text
+true
+false
+```
+
+## Image
+
+```text
+inspectionImage
+defectImage
+microscopeImage
+equipmentImage
+```
+
+## Multi Value
+
+```text
+point1
+point2
+point3
+point4
+average
+max
+min
+```
+
+---
+
+# 15. 鎶芥牱妫�娴�
+
+鏀寔锛�
+
+```text
+samplingPlan
+sampleSize
+samplingRatio
+sampleNo
+result
+qualifiedCount
+unqualifiedCount
+AQL
+Ac
+Re
+```
+
+鑷姩璁$畻锛�
+
+```text
+qualifiedRate
+unqualifiedRate
+finalResult
+```
+
+---
+
+# 16. 缁熻缁勪欢
+
+鏀寔锛�
+
+```text
+骞冲潎鍊�
+鏈�澶у��
+鏈�灏忓��
+鏍囧噯宸�
+
+CP
+CPK
+
+鍚堟牸鐜�
+涓嶈壇鐜�
+
+瓒嬪娍
+缁熻琛�
+```
+
+鍩虹鍥捐〃鑳藉姏鍗冲彲銆�
+
+涓嶈涓轰簡绠�鍗曞浘琛ㄥ紩鍏ュぇ鍨嬪鏉傛鏋躲��
+
+---
+
+# 17. QualityRuleEngine
+
+瑙勫垯蹇呴』鐙珛銆�
+
+绂佹锛�
+
+```text
+鎶婅鍒欏啓姝诲湪 Vue Component
+```
+
+寤虹珛锛�
+
+```text
+QualityRuleEngine
+```
+
+鏀寔锛�
+
+```text
+>
+>=
+<
+<=
+=
+!=
+
+BETWEEN
+IN
+NOT_IN
+
+AND
+OR
+```
+
+渚嬪锛�
+
+```text
+actualValue >= lowerLimit
+AND
+actualValue <= upperLimit
+```
+
+缁撴灉锛�
+
+```text
+PASS
+```
+
+---
+
+# 18. 鏁版嵁缁戝畾寮曟搸
+
+璁捐缁熶竴鐨勬暟鎹粦瀹氬崗璁��
+
+渚嬪锛�
+
+```text
+{{report.reportNo}}
+
+{{sample.sampleName}}
+
+{{sample.batchNo}}
+
+{{customer.name}}
+
+{{supplier.name}}
+
+{{inspectionItems[0].actualValue}}
+
+{{inspectionItems[0].result}}
+```
+
+鏀寔锛�
+
+```text
+瀵硅薄
+鏁扮粍
+宓屽瀵硅薄
+鏁扮粍閬嶅巻
+璁$畻瀛楁
+琛ㄨ揪寮�
+鏉′欢瀛楁
+鏍煎紡鍖�
+榛樿鍊�
+```
+
+---
+
+# 19. Dynamic Table Binding
+
+蹇呴』鏀寔锛�
+
+```text
+DataSource:
+inspectionItems
+```
+
+鐒跺悗锛�
+
+```text
+inspectionItems[]
+```
+
+鑷姩鐢熸垚鏁版嵁琛屻��
+
+渚嬪锛�
+
+```text
+inspectionItems:
+
+[
+ {
+ itemName: "闀垮害",
+ standard: "10卤0.1",
+ actualValue: 10.03,
+ unit: "mm",
+ result: "PASS"
+ }
+]
+```
+
+鑷姩鐢熸垚锛�
+
+```text
+1 | 闀垮害 | 10卤0.1 | 10.03 | mm | PASS
+```
+
+---
+
+# 20. 鏉′欢娓叉煋
+
+鏀寔锛�
+
+```text
+IF
+ELSE
+```
+
+鑳藉姏锛�
+
+```text
+鏄剧ず
+闅愯棌
+鏇挎崲鏂囨湰
+鏇挎崲鏍峰紡
+```
+
+渚嬪锛�
+
+```text
+result == FAIL
+```
+
+鏄剧ず锛�
+
+```text
+涓嶅悎鏍�
+```
+
+---
+
+# 21. Template Schema
+
+涓嶈兘鍙繚瀛� HTML銆�
+
+蹇呴』淇濆瓨锛�
+
+```text
+GrapesJS JSON
++
+Quality Component JSON
++
+HTML
++
+CSS
++
+Template Config
++
+Data Schema
++
+Rules
+```
+
+寤鸿锛�
+
+```json
+{
+ "schemaVersion": "1.0.0",
+
+ "page": {
+ "size": "A4",
+ "orientation": "portrait",
+
+ "margin": {
+ "top": 20,
+ "right": 15,
+ "bottom": 20,
+ "left": 15
+ }
+ },
+
+ "grapes": {},
+
+ "components": [],
+
+ "dataSources": [],
+
+ "bindings": [],
+
+ "rules": [],
+
+ "styles": []
+}
+```
+
+鏈潵蹇呴』鏀寔锛�
+
+```text
+A3
+A4
+A5
+Letter
+鑷畾涔夌焊寮�
+
+portrait
+landscape
+```
+
+---
+
+# 22. 妯℃澘鐗堟湰
+
+蹇呴』鏀寔锛�
+
+```text
+v1.0
+v1.1
+v1.2
+v2.0
+```
+
+鍙戝竷鍚庣殑鐗堟湰锛�
+
+> **绂佹瑕嗙洊鍘熺増鏈��**
+
+鏀寔锛�
+
+```text
+鏌ョ湅
+姣旇緝
+澶嶅埗
+鍥炴粴
+鍙戝竷
+鍋滅敤
+```
+
+---
+
+# 23. 鏁版嵁搴�
+
+鑷冲皯鑰冭檻锛�
+
+```text
+quality_report_template
+
+quality_report_template_version
+
+quality_report_component
+
+quality_report_data_source
+
+quality_report_rule
+
+quality_report_instance
+
+quality_report_render_record
+```
+
+妯℃澘锛�
+
+```text
+id
+template_code
+template_name
+industry
+report_type
+status
+current_version
+description
+created_by
+created_time
+updated_by
+updated_time
+```
+
+鐗堟湰锛�
+
+```text
+id
+template_id
+version
+content
+schema
+style
+status
+created_by
+created_time
+```
+
+鎶ュ憡瀹炰緥锛�
+
+```text
+report_no
+template_id
+template_version
+business_id
+business_type
+data_snapshot
+render_html
+pdf_path
+status
+created_time
+```
+
+鏈�閲嶈锛�
+
+> **鎶ュ憡鐢熸垚鏃跺繀椤讳繚瀛� data_snapshot銆�**
+
+鍘嗗彶鎶ュ憡涓嶈兘鍥犱负涓氬姟鏁版嵁鍙樺寲鑰屽彂鐢熷彉鍖栥��
+
+---
+
+# 24. GrapesJS Designer
+
+璁捐鍣ㄩ噰鐢細
+
+```text
+鈹屸攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� 鏂板缓 淇濆瓨 棰勮 鍙戝竷 PDF 鎾ら攢 閲嶅仛 缂╂斁 鍏ㄥ睆 鈹�
+鈹溾攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� 鈹� 鈹� 鈹�
+鈹� 缁勪欢闈㈡澘 鈹� GrapesJS Canvas 鈹� 灞炴�ч潰鏉� 鈹�
+鈹� 鈹� 鈹� 鈹�
+鈹� 鍩虹缁勪欢 鈹� 鈹� 鍩虹灞炴�� 鈹�
+鈹� 璐ㄩ噺缁勪欢 鈹� 鈹� 鏁版嵁缁戝畾 鈹�
+鈹� 琛ㄦ牸缁勪欢 鈹� 鈹� 鏍峰紡 鈹�
+鈹� 鏁版嵁缁勪欢 鈹� 鈹� 鏉′欢 鈹�
+鈹� 鎶ュ憡缁勪欢 鈹� 鈹� 鍒嗛〉 鈹�
+鈹� 鈹� 鈹� 鈹�
+鈹溾攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹粹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹粹攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+鈹� 妯℃澘鍚嶇О | 鐗堟湰 | 淇濆瓨鐘舵�� | 褰撳墠椤甸潰 | 缂╂斁姣斾緥 鈹�
+鈹斺攢鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�鈹�
+```
+
+---
+
+# 25. GrapesJS 浜屾寮�鍙�
+
+蹇呴』鍚堢悊浣跨敤锛�
+
+```text
+Editor
+BlockManager
+Components
+Component
+Traits
+StyleManager
+Selectors
+Commands
+Panels
+Devices
+StorageManager
+UndoManager
+Modal
+Canvas
+```
+
+涓嶈鎶� GrapesJS 褰撴垚绠�鍗� iframe銆�
+
+蹇呴』閫氳繃 GrapesJS 鎵╁睍鏈哄埗瀹炵幇锛�
+
+```text
+Quality Components
+```
+
+---
+
+# 26. QualityPropertyPanel
+
+涓嶈瀹屽叏渚濊禆 GrapesJS 榛樿 StyleManager銆�
+
+寤虹珛锛�
+
+```text
+QualityPropertyPanel
+```
+
+鏍规嵁褰撳墠缁勪欢鍔ㄦ�佹樉绀洪厤缃��
+
+渚嬪锛�
+
+閫夋嫨锛�
+
+```text
+QualityTable
+```
+
+鏄剧ず锛�
+
+```text
+鍩虹灞炴��
+鈹溾攢鈹� 琛ㄦ牸鍚嶇О
+鈹溾攢鈹� 鏁版嵁婧�
+鈹溾攢鈹� 鏄剧ず搴忓彿
+鈹斺攢鈹� 鑷姩鍒嗛〉
+
+鍒楅厤缃�
+鈹溾攢鈹� 娣诲姞
+鈹溾攢鈹� 鍒犻櫎
+鈹溾攢鈹� 绉诲姩
+鈹斺攢鈹� 缂栬緫
+
+鏁版嵁缁戝畾
+鈹溾攢鈹� 瀛楁
+鈹溾攢鈹� 琛ㄨ揪寮�
+鈹斺攢鈹� 鏍煎紡鍖�
+
+鏍峰紡
+鈹溾攢鈹� 杈规
+鈹溾攢鈹� 瀛椾綋
+鈹溾攢鈹� 瀵归綈
+鈹溾攢鈹� 鑳屾櫙
+鈹斺攢鈹� 琛岄珮
+
+鏉′欢
+鈹溾攢鈹� PASS
+鈹斺攢鈹� FAIL
+```
+
+UI 蹇呴』閬靛惊褰撳墠椤圭洰鐨勶細
+
+```text
+Vben
++
+Ant Design Vue
+```
+
+璁捐瑙勮寖銆�
+
+---
+
+# 27. 妯℃澘绠$悊
+
+瀹炵幇锛�
+
+```text
+妯℃澘鍒楄〃
+
+鏂板缓
+缂栬緫
+澶嶅埗
+鍒犻櫎
+
+鍚敤
+鍋滅敤
+
+鐗堟湰绠$悊
+
+棰勮
+鍙戝竷
+```
+
+鏌ヨ鏉′欢锛�
+
+```text
+妯℃澘鍚嶇О
+妯℃澘缂栫爜
+琛屼笟
+鎶ュ憡绫诲瀷
+鐘舵��
+鐗堟湰
+鍒涘缓浜�
+鍒涘缓鏃堕棿
+```
+
+---
+
+# 28. 鎶ュ憡娓叉煋
+
+鍚庣鎻愪緵绫讳技锛�
+
+```text
+POST /quality/report/render
+
+POST /quality/report/preview
+
+POST /quality/report/pdf
+```
+
+瀹屾暣娴佺▼锛�
+
+```text
+Template
+ 鈫�
+Load Version
+ 鈫�
+Load Business Data
+ 鈫�
+Build Data Context
+ 鈫�
+Data Binding
+ 鈫�
+Rule Engine
+ 鈫�
+Generate HTML
+ 鈫�
+Inject CSS
+ 鈫�
+Playwright
+ 鈫�
+Chromium
+ 鈫�
+PDF
+```
+
+---
+
+# 29. Render Engine
+
+寤虹珛锛�
+
+```text
+ReportRenderService
+```
+
+杩涗竴姝ワ細
+
+```text
+TemplateRenderService
+DataBindingService
+QualityRuleEngine
+HtmlRenderService
+PlaywrightRenderService
+PdfRenderService
+```
+
+Controller锛�
+
+> 鍙礋璐h姹傛帴鏀跺拰鍝嶅簲銆�
+
+绂佹鎶婏細
+
+```text
+妯℃澘瑙f瀽
+鏁版嵁缁戝畾
+瑙勫垯璁$畻
+HTML鐢熸垚
+Playwright
+```
+
+鍏ㄩ儴鍐欒繘 Controller銆�
+
+---
+
+# 30. BrowserManager
+
+Playwright 蹇呴』缁熶竴绠$悊銆�
+
+寤虹珛锛�
+
+```text
+BrowserManager
+```
+
+鑰冭檻锛�
+
+```text
+Browser Singleton
+
+Page Lifecycle
+
+骞跺彂鎺у埗
+
+Timeout
+
+Memory
+
+Browser Crash
+
+鑷姩鎭㈠
+
+PDF 骞跺彂闄愬埗
+```
+
+绂佹姣忔璇锋眰锛�
+
+```text
+launch browser
+鈫�
+鐢熸垚 PDF
+鈫�
+close browser
+```
+
+---
+
+# 31. PDF / 鎵撳嵃
+
+鏈�缁堟姤鍛婂繀椤婚噸鐐硅�冭檻锛�
+
+```text
+A4
+A3
+A5
+
+portrait
+landscape
+
+椤电湁
+椤佃剼
+椤电爜
+
+鍒嗛〉
+鍒嗛〉绗�
+琛ㄦ牸璺ㄩ〉
+閲嶅琛ㄥご
+
+閬垮厤琛岃鎷嗗紑
+
+鍥剧墖
+浜岀淮鐮�
+绛惧悕
+```
+
+蹇呴』鏀寔锛�
+
+```css
+@page
+
+page-break-before
+page-break-after
+page-break-inside
+```
+
+鏈�缁堟姤鍛婁富瑕侀潰鍚戯細
+
+```text
+A4
+A3
+A5
+```
+
+涓嶈鍥犱负璁捐鍣ㄥ搷搴斿紡鑰岀牬鍧忔墦鍗板竷灞�銆�
+
+---
+
+# 32. Preview
+
+棰勮蹇呴』灏藉彲鑳芥帴杩戞渶缁� PDF銆�
+
+鎺ㄨ崘锛�
+
+```text
+Template
+鈫�
+Backend Render
+鈫�
+HTML
+鈫�
+Preview
+```
+
+涓嶈鍑虹幇锛�
+
+```text
+娴忚鍣ㄨ璁″櫒鏄剧ず姝e父
+
+浣嗘槸
+
+PDF 鍙戠敓涓ラ噸鍙樺舰
+```
+
+---
+
+# 33. 瀹夊叏
+
+妯℃澘鍐呭灞炰簬鐢ㄦ埛鍙紪杈戝唴瀹广��
+
+蹇呴』閲嶇偣闃叉姢锛�
+
+```text
+<script>
+
+iframe
+
+javascript:
+
+onerror=
+onclick=
+
+鎭舵剰 URL
+```
+
+蹇呴』杩涜锛�
+
+```text
+HTML Sanitization
+```
+
+骞堕檺鍒讹細
+
+```text
+鑴氭湰鎵ц
+澶栭儴璧勬簮
+鍗遍櫓浜嬩欢灞炴��
+```
+
+---
+
+# 34. 鏉冮檺
+
+缁撳悎鐜版湁椤圭洰鏉冮檺浣撶郴銆�
+
+鑷冲皯鏀寔锛�
+
+```text
+鏌ョ湅妯℃澘
+缂栬緫妯℃澘
+鍒犻櫎妯℃澘
+鍙戝竷妯℃澘
+鐢熸垚鎶ュ憡
+鏌ョ湅鎶ュ憡
+涓嬭浇鎶ュ憡
+```
+
+涓嶈閲嶆柊璁捐涓�濂楃嫭绔嬫潈闄愮郴缁熴��
+
+---
+
+# 35. 琛屼笟鎵╁睍
+
+鏍稿績缂栬緫鍣ㄤ笉鑳戒笌琛屼笟涓氬姟寮鸿�﹀悎銆�
+
+璁捐锛�
+
+```text
+IndustryComponentPack
+```
+
+渚嬪锛�
+
+```text
+manufacturing
+chemical
+food
+medical
+laboratory
+```
+
+鏈潵锛�
+
+```typescript
+registerIndustryPack("chemical")
+```
+
+鍗冲彲澧炲姞锛�
+
+```text
+PH
+绾害
+娴撳害
+娓╁害
+鍘嬪姏
+瀵嗗害
+鍖栧鎴愬垎
+```
+
+鑰屼笉搴旇淇敼鏍稿績 Designer銆�
+
+---
+
+# 36. 缁熻璁$畻
+
+鏀寔锛�
+
+```text
+AVG()
+MAX()
+MIN()
+COUNT()
+
+STDDEV()
+
+CP()
+CPK()
+
+PASS_RATE()
+FAIL_RATE()
+```
+
+渚嬪锛�
+
+```text
+AVG(inspectionItems.actualValue)
+```
+
+璁$畻閫昏緫蹇呴』鐙珛銆�
+
+---
+
+# 37. 绛惧悕
+
+鏀寔锛�
+
+```text
+妫�楠屽憳
+瀹℃牳鍛�
+鎵瑰噯浜�
+```
+
+瀛楁锛�
+
+```text
+濮撳悕
+鑱屼綅
+鐢靛瓙绛惧悕
+绛惧悕鏃堕棿
+```
+
+---
+
+# 38. 浜岀淮鐮� / 鏉$爜
+
+浜岀淮鐮侊細
+
+```text
+鎶ュ憡浜岀淮鐮�
+鎶ュ憡缂栧彿
+杩芥函浜岀淮鐮�
+```
+
+鏀寔锛�
+
+```text
+{{report.reportNo}}
+```
+
+鍔ㄦ�佺粦瀹氥��
+
+鏉$爜鏀寔锛�
+
+```text
+Code128
+Code39
+EAN
+```
+
+绗笁鏂瑰簱蹇呴』閫夋嫨锛�
+
+> 鎴愮啛銆佽交閲忋�佺淮鎶ゆ甯哥殑鏂规銆�
+
+---
+
+# 39. 鎬ц兘
+
+蹇呴』鑰冭檻锛�
+
+```text
+1000+ 琛ㄦ牸鏁版嵁琛�
+
+澶氬浘鐗�
+
+10+ 椤� PDF
+
+100+ 椤� PDF
+
+楂樺苟鍙� PDF
+```
+
+鍓嶇锛�
+
+> 涓嶈涓�娆℃�у垱寤哄法澶� DOM銆�
+
+鍚庣锛�
+
+> 鎺у埗 Playwright 骞跺彂銆�
+
+---
+
+# 40. 寮傚父
+
+鑷冲皯澶勭悊锛�
+
+```text
+妯℃澘涓嶅瓨鍦�
+妯℃澘鐗堟湰涓嶅瓨鍦�
+妯℃澘 JSON 鎹熷潖
+
+鏁版嵁瀛楁涓嶅瓨鍦�
+鏁版嵁鏍煎紡閿欒
+
+瑙勫垯瑙f瀽澶辫触
+
+HTML Render 澶辫触
+
+Chromium 鍚姩澶辫触
+Chromium Crash
+
+PDF 鐢熸垚澶辫触
+```
+
+缁熶竴寮傚父缁撴瀯銆�
+
+---
+
+# 41. 鏃ュ織
+
+璁板綍锛�
+
+```text
+templateId
+templateVersion
+reportId
+businessId
+
+renderStartTime
+renderEndTime
+renderDuration
+
+pdfDuration
+
+browserStatus
+
+errorStack
+```
+
+鏂逛究鐢熶骇鐜鎺掓煡銆�
+
+---
+
+# 42. 娴嬭瘯
+
+## 鍓嶇
+
+鑷冲皯锛�
+
+```text
+Quality Component Registry
+
+Template Serialize
+
+Template Deserialize
+
+Data Binding
+
+Rule Engine
+
+QualityTable Configuration
+```
+
+## 鍚庣
+
+鑷冲皯锛�
+
+```text
+Template CRUD
+
+Template Version
+
+Data Binding
+
+Rule Engine
+
+HTML Render
+
+PDF Render
+```
+
+## E2E
+
+浣跨敤 Playwright锛�
+
+```text
+鎵撳紑妯℃澘璁捐鍣�
+鈫�
+鎷栧叆缁勪欢
+鈫�
+閰嶇疆灞炴��
+鈫�
+缁戝畾鏁版嵁
+鈫�
+淇濆瓨
+鈫�
+鍙戝竷
+鈫�
+棰勮
+鈫�
+鐢熸垚 PDF
+鈫�
+楠岃瘉 PDF
+```
+
+---
+
+# 43. PDF 楠屾敹鏍囧噯
+
+鑷冲皯楠岃瘉锛�
+
+```text
+A4 灏哄姝g‘
+
+椤佃竟璺濇纭�
+
+涓枃瀛椾綋姝e父
+
+琛ㄦ牸甯冨眬姝e父
+
+澶氱骇琛ㄥご姝e父
+
+閲嶅琛ㄥご姝e父
+
+璺ㄩ〉姝e父
+
+鍥剧墖姝e父
+
+浜岀淮鐮佹甯�
+
+绛惧悕姝e父
+
+椤电爜姝e父
+
+椤电湁姝e父
+
+椤佃剼姝e父
+```
+
+閲嶇偣娴嬭瘯锛�
+
+```text
+10+ 椤垫姤鍛�
+
+100+ 琛ㄦ牸鏁版嵁
+
+璺ㄩ〉琛ㄦ牸
+
+澶氬浘鐗�
+
+PASS / FAIL 鏉′欢鏍峰紡
+```
+
+---
+
+# 44. 鐩綍璁捐
+
+鍓嶇浼樺厛褰㈡垚锛�
+
+```text
+src/
+鈹溾攢鈹� views/
+鈹� 鈹斺攢鈹� quality-report/
+鈹� 鈹溾攢鈹� template/
+鈹� 鈹溾攢鈹� designer/
+鈹� 鈹溾攢鈹� preview/
+鈹� 鈹斺攢鈹� instance/
+鈹�
+鈹溾攢鈹� components/
+鈹� 鈹斺攢鈹� quality/
+鈹� 鈹溾攢鈹� core/
+鈹� 鈹溾攢鈹� base/
+鈹� 鈹溾攢鈹� layout/
+鈹� 鈹溾攢鈹� inspection/
+鈹� 鈹溾攢鈹� table/
+鈹� 鈹溾攢鈹� result/
+鈹� 鈹溾攢鈹� statistics/
+鈹� 鈹溾攢鈹� signature/
+鈹� 鈹溾攢鈹� barcode/
+鈹� 鈹溾攢鈹� qrcode/
+鈹� 鈹斺攢鈹� registry.ts
+鈹�
+鈹溾攢鈹� services/
+鈹� 鈹斺攢鈹� quality-report/
+鈹�
+鈹溾攢鈹� stores/
+鈹� 鈹斺攢鈹� qualityReport.ts
+鈹�
+鈹斺攢鈹� types/
+ 鈹斺攢鈹� quality-report/
+```
+
+鍚庣锛�
+
+```text
+quality/
+鈹溾攢鈹� controller
+鈹溾攢鈹� service
+鈹溾攢鈹� service.impl
+鈹溾攢鈹� mapper
+鈹溾攢鈹� domain
+鈹溾攢鈹� dto
+鈹溾攢鈹� vo
+鈹溾攢鈹� converter
+鈹溾攢鈹� engine
+鈹� 鈹溾攢鈹� binding
+鈹� 鈹溾攢鈹� rule
+鈹� 鈹斺攢鈹� render
+鈹溾攢鈹� playwright
+鈹斺攢鈹� config
+```
+
+娉ㄦ剰锛�
+
+> 濡傛灉褰撳墠椤圭洰宸茬粡鏈夊搴旂洰褰曡鑼冿紝浼樺厛閬靛惊褰撳墠椤圭洰锛岃�屼笉鏄満姊板垱寤轰笂杩扮洰褰曘��
+
+---
+
+# 45. 寮�鍙戦樁娈�
+
+## Phase 0锛氶」鐩壂鎻�
+
+绗竴娆″彧鍋氾細
+
+```text
+鍒嗘瀽椤圭洰
+```
+
+涓嶈澶ч噺淇敼銆�
+
+杈撳嚭锛�
+
+### 1. 褰撳墠鎶�鏈爤
+
+### 2. 鍓嶇鏋舵瀯
+
+### 3. 鍚庣鏋舵瀯
+
+### 4. 褰撳墠鐩綍缁撴瀯
+
+### 5. 褰撳墠 UI 妗嗘灦
+
+### 6. 褰撳墠鏉冮檺浣撶郴
+
+### 7. 褰撳墠鏂囦欢瀛樺偍
+
+### 8. 褰撳墠 API 璇锋眰浣撶郴
+
+### 9. 鍙互澶嶇敤鐨勭粍浠�
+
+### 10. 鍙互澶嶇敤鐨勫伐鍏风被
+
+### 11. 闇�瑕佹柊澧炵殑妯″潡
+
+### 12. 鏁版嵁搴撹璁�
+
+### 13. Quality Components 璁捐
+
+### 14. GrapesJS 闆嗘垚鏂规
+
+### 15. Template Schema
+
+### 16. Data Binding 鏂规
+
+### 17. Rule Engine 鏂规
+
+### 18. Render Engine 鏂规
+
+### 19. Playwright 鏂规
+
+### 20. PDF 鍒嗛〉鏂规
+
+### 21. API 璁捐
+
+### 22. 椋庨櫓鐐�
+
+### 23. 寮�鍙戦樁娈垫媶鍒�
+
+---
+
+# 46. Phase 1
+
+瀹屾垚锛�
+
+```text
+妯℃澘绠$悊
++
+Designer 鍩虹妗嗘灦
++
+Quality Component Registry
++
+GrapesJS 闆嗘垚
++
+鍩虹缁勪欢
++
+妯℃澘淇濆瓨
++
+妯℃澘鍔犺浇
+```
+
+楠屾敹锛�
+
+```text
+鍒涘缓妯℃澘
+鈫�
+鎵撳紑 Designer
+鈫�
+鎷栫粍浠�
+鈫�
+缂栬緫
+鈫�
+淇濆瓨
+鈫�
+閲嶆柊鎵撳紑
+鈫�
+缁勪欢鐘舵�佷繚鎸佷竴鑷�
+```
+
+---
+
+# 47. Phase 2
+
+瀹屾垚锛�
+
+```text
+QualityTable
+
+SampleInfo
+
+ReportHeader
+
+InspectionItem
+
+Result
+
+Data Binding
+
+Dynamic Table
+
+Rule Engine
+```
+
+楠屾敹锛�
+
+```text
+inspectionItems
+鈫�
+鑷姩鐢熸垚琛ㄦ牸
+鈫�
+瑙勫垯璁$畻
+鈫�
+PASS / FAIL
+```
+
+---
+
+# 48. Phase 3
+
+瀹屾垚锛�
+
+```text
+HTML Render
+
+Preview
+
+Playwright
+
+Chromium
+
+PDF
+
+A4
+
+鍒嗛〉
+
+椤电湁
+
+椤佃剼
+
+椤电爜
+```
+
+---
+
+# 49. Phase 4
+
+瀹屾垚锛�
+
+```text
+妯℃澘鐗堟湰
+鎶ュ憡瀹炰緥
+鏉冮檺
+鏃ュ織
+寮傚父澶勭悊
+```
+
+---
+
+# 50. Phase 5
+
+瀹屾垚锛�
+
+```text
+鑷姩鍖栨祴璇�
+E2E
+
+澶嶆潅琛ㄦ牸娴嬭瘯
+
+澶氶〉 PDF
+
+100+ 琛屾暟鎹�
+
+鍥剧墖
+
+浜岀淮鐮�
+
+绛惧悕
+```
+
+---
+
+# 51. Claude Code Agent 宸ヤ綔鍗忚
+
+蹇呴』涓ユ牸閬靛惊锛�
+
+```text
+鐞嗚В
+ 鈫�
+鎵弿
+ 鈫�
+鍒嗘瀽
+ 鈫�
+璁捐
+ 鈫�
+灏忚寖鍥村疄鐜�
+ 鈫�
+缂栬瘧
+ 鈫�
+娴嬭瘯
+ 鈫�
+楠岃瘉
+ 鈫�
+淇
+ 鈫�
+缁х画
+```
+
+绂佹锛�
+
+```text
+鐞嗚В涓嶈冻
+ 鈫�
+涓�娆℃�х敓鎴愬嚑鍗佷釜鏂囦欢
+```
+
+---
+
+# 52. 姣忔淇敼涔嬪墠
+
+蹇呴』鍏堬細
+
+```text
+璇诲彇鐩稿叧鏂囦欢
+```
+
+鐒跺悗鍒ゆ柇锛�
+
+```text
+鏄惁宸叉湁瀹炵幇锛�
+鏄惁鍙互澶嶇敤锛�
+鏄惁瀛樺湪鍏叡缁勪欢锛�
+鏄惁瀛樺湪绫讳技椤甸潰锛�
+鏄惁瀛樺湪鍏叡 API锛�
+鏄惁瀛樺湪绫讳技鏁版嵁搴撹〃锛�
+```
+
+濡傛灉宸叉湁瀹炵幇锛�
+
+> **浼樺厛澶嶇敤銆�**
+
+绂佹锛�
+
+> 涓轰簡瀹屾垚褰撳墠闇�姹傞噸鏂伴�犺疆瀛愩��
+
+---
+
+# 53. 淇敼鑼冨洿鎺у埗
+
+绂佹锛�
+
+```text
+鏃犵悊鐢遍噸鏋�
+鏃犵悊鐢卞崌绾т緷璧�
+鏃犵悊鐢变慨鏀瑰叕鍏辩粍浠�
+鏃犵悊鐢变慨鏀瑰叏灞�鏍峰紡
+鍒犻櫎鐜版湁涓氬姟浠g爜
+```
+
+濡傛灉蹇呴』淇敼鍏叡浠g爜锛�
+
+蹇呴』璇存槑锛�
+
+```text
+涓轰粈涔堜慨鏀�
+褰卞搷鍝簺妯″潡
+濡備綍楠岃瘉
+```
+
+---
+
+# 54. 渚濊禆绠$悊
+
+褰撳墠椤圭洰宸叉湁澶ч噺渚濊禆銆�
+
+鍥犳锛�
+
+> **绂佹涓轰簡鏂逛究鐩存帴瀹夎鏂扮殑澶у瀷渚濊禆銆�**
+
+娣诲姞渚濊禆鍓嶅繀椤诲垽鏂細
+
+```text
+椤圭洰鏄惁宸叉湁绫讳技鑳藉姏锛�
+鐜版湁渚濊禆鏄惁鍙互瀹炵幇锛�
+鏄惁鍙互鑷繁瀹炵幇锛�
+渚濊禆浣撶Н鏄灏戯紵
+鏄惁缁存姢锛�
+鏄惁褰卞搷 PDF锛�
+鏄惁褰卞搷 Vite 鏋勫缓锛�
+```
+
+鍙湁纭蹇呰鍚庢墠鍏佽瀹夎銆�
+
+---
+
+# 55. TypeScript
+
+涓ユ牸鎺у埗锛�
+
+```text
+any
+```
+
+绂佹锛�
+
+```typescript
+const data: any
+```
+
+闄ら潪绗笁鏂瑰簱绫诲瀷纭疄鏃犳硶澶勭悊銆�
+
+濡傛灉蹇呴』浣跨敤锛�
+
+```typescript
+any
+```
+
+闇�瑕佸眬閮ㄩ殧绂伙紝骞惰В閲婂師鍥犮��
+
+---
+
+# 56. Vue 浠g爜
+
+绂佹鍒涘缓锛�
+
+```text
+2000+
+琛屽法澶� Vue 鏂囦欢
+```
+
+Designer 蹇呴』鎷嗗垎锛�
+
+```text
+DesignerToolbar
+
+DesignerSidebar
+
+DesignerCanvas
+
+DesignerPropertyPanel
+
+DesignerDataPanel
+
+DesignerRulePanel
+
+DesignerPageSettings
+```
+
+---
+
+# 57. 鐘舵�佺鐞�
+
+璁捐鍣ㄧ姸鎬佽嚦灏戣�冭檻锛�
+
+```text
+currentTemplate
+currentVersion
+editor
+selectedComponent
+templateSchema
+components
+dataSources
+rules
+dirty
+saving
+preview
+```
+
+浼樺厛浣跨敤锛�
+
+```text
+Pinia
+```
+
+骞堕伩鍏嶆妸鎵�鏈夌姸鎬佸杩涗竴涓法澶� Store銆�
+
+---
+
+# 58. Git 鑷
+
+姣忔瀹屾垚涓�涓姛鑳藉悗锛�
+
+```bash
+git diff
+```
+
+妫�鏌ワ細
+
+```text
+鏄惁璇慨鏀�
+鏄惁璇垹闄�
+鏄惁閲嶅浠g爜
+鏄惁鐮村潖鍏叡缁勪欢
+鏄惁淇敼鏃犲叧妯″潡
+```
+
+---
+
+# 59. 鏋勫缓楠岃瘉
+
+鍏堣鍙栧綋鍓嶉」鐩細
+
+```text
+package.json
+```
+
+纭瀹為檯鍛戒护銆�
+
+鍐嶆墽琛岀被浼硷細
+
+```bash
+pnpm build
+pnpm lint
+```
+
+鍚庣鏍规嵁瀹為檯椤圭洰锛�
+
+```bash
+mvn test
+mvn package
+```
+
+濡傛灉椤圭洰瀹為檯涓嶆槸杩欎簺鍛戒护锛�
+
+> 浣跨敤椤圭洰鐪熷疄鍛戒护銆�
+
+绂佹鍑┖鎵ц涓嶅瓨鍦ㄧ殑鍛戒护銆�
+
+---
+
+# 60. 瀹屾垚鏍囧噯
+
+涓嶈兘鍥犱负锛�
+
+```text
+浠g爜鍐欏畬
+```
+
+灏卞0绉板畬鎴愩��
+
+蹇呴』楠岃瘉锛�
+
+```text
+缂栬瘧
+TypeScript
+Lint
+API
+鏁版嵁搴�
+椤甸潰
+妯℃澘淇濆瓨
+妯℃澘鍔犺浇
+鏁版嵁缁戝畾
+瑙勫垯璁$畻
+HTML Render
+PDF Render
+```
+
+---
+
+# 61. 鏈�缁堥獙鏀跺満鏅�
+
+蹇呴』鏈�缁堝疄鐜帮細
+
+```text
+鏂板缓璐ㄦ鎶ュ憡
+ 鈫�
+閫夋嫨 A4
+ 鈫�
+鎷栧叆 ReportHeader
+ 鈫�
+鎷栧叆 SampleInfo
+ 鈫�
+鎷栧叆 QualityTable
+ 鈫�
+缁戝畾 inspectionItems
+ 鈫�
+閰嶇疆妫�娴嬪瓧娈�
+ 鈫�
+閰嶇疆鍒ゅ畾瑙勫垯
+ 鈫�
+鎷栧叆 Result
+ 鈫�
+鎷栧叆 Signature
+ 鈫�
+棰勮
+ 鈫�
+淇濆瓨
+ 鈫�
+鍙戝竷
+ 鈫�
+涓氬姟绯荤粺璋冪敤
+ 鈫�
+鍔犺浇璐ㄦ鏁版嵁
+ 鈫�
+鎵ц瑙勫垯
+ 鈫�
+鐢熸垚 HTML
+ 鈫�
+Playwright
+ 鈫�
+Chromium
+ 鈫�
+鐢熸垚 PDF
+ 鈫�
+淇濆瓨 ReportInstance
+```
+
+---
+
+# 62. 绗竴鏉℃寚浠�
+
+鐜板湪寮�濮嬫墽琛岋細
+
+## Phase 0锛氶」鐩壂鎻�
+
+**鏆傛椂涓嶈澶ч噺鍒涘缓鏂囦欢锛屼笉瑕佸ぇ瑙勬ā淇敼浠g爜锛屼笉瑕佸崌绾т緷璧栥��**
+
+鍏堟鏌ワ細
+
+```text
+package.json
+pnpm-workspace.yaml
+vite.config.*
+tsconfig.*
+src/
+router/
+stores/
+components/
+views/
+layouts/
+
+鍚庣 pom.xml
+controller
+service
+mapper
+domain
+dto
+vo
+config
+
+鏁版嵁搴�
+鏉冮檺
+鏂囦欢鏈嶅姟
+```
+
+鐒跺悗杈撳嚭锛�
+
+```text
+# 涓�銆佸綋鍓嶉」鐩妧鏈爤
+
+# 浜屻�佸綋鍓嶅墠绔灦鏋�
+
+# 涓夈�佸綋鍓嶅悗绔灦鏋�
+
+# 鍥涖�佸綋鍓嶇洰褰曠粨鏋�
+
+# 浜斻�佸綋鍓� UI 妗嗘灦鍙婄増鏈�
+
+# 鍏�佸綋鍓嶅彲浠ュ鐢ㄧ殑鑳藉姏
+
+# 涓冦�佸綋鍓嶄笉鑳藉鐢ㄣ�侀渶瑕佹柊澧炵殑鑳藉姏
+
+# 鍏�佹暟鎹簱璁捐寤鸿
+
+# 涔濄�丵uality Components 鏋舵瀯
+
+# 鍗併�丟rapesJS 闆嗘垚鏂规
+
+# 鍗佷竴銆乀emplate Schema
+
+# 鍗佷簩銆丏ata Binding 鏂规
+
+# 鍗佷笁銆丷ule Engine 鏂规
+
+# 鍗佸洓銆丠TML Render 鏂规
+
+# 鍗佷簲銆丳laywright/Chromium 鏂规
+
+# 鍗佸叚銆丳DF 鍒嗛〉鏂规
+
+# 鍗佷竷銆丄PI 璁捐
+
+# 鍗佸叓銆佺洰褰曠粨鏋勫缓璁�
+
+# 鍗佷節銆丳hase 1~5 瀹炴柦璁″垝
+
+# 浜屽崄銆侀闄╂竻鍗�
+
+# 浜屽崄涓�銆丳hase 1 寮�濮嬪墠闇�瑕佹垜纭鐨勯棶棰�
+```
+
+### 鐗瑰埆瑕佹眰
+
+濡傛灉椤圭洰鐜版湁瀹炵幇涓庢湰鏂规鍐茬獊锛�
+
+> **浠ラ」鐩幇鐘朵负鍩虹閫傞厤锛屼笉瑕佸己琛岄噸鏋勭幇鏈夌郴缁熴��**
+
+濡傛灉鍙戠幇宸叉湁鍔熻兘锛�
+
+> **浼樺厛澶嶇敤銆�**
+
+濡傛灉鍙戠幇鎶�鏈柟妗堝瓨鍦ㄥ涓彲琛屾柟妗堬細
+
+> 鍏堟瘮杈冩柟妗堢殑澶嶆潅搴︺�佺淮鎶ゆ垚鏈�佷笌鐜版湁椤圭洰鍏煎鎬э紝鍐嶉�夋嫨瀹炴柦鏂规銆�
+
+濡傛灉淇℃伅涓嶈冻锛�
+
+> 鍏堟壂鎻忎唬鐮侊紝涓嶈鐚溿��
+
+濡傛灉闇�姹傚瓨鍦ㄦ槑鏄炬妧鏈闄╋細
+
+> 鍏堟寚鍑洪闄╋紝鍐嶇粰鍑哄彲钀藉湴鏂规銆�
+
+濡傛灉鏌愰」鍔熻兘鏆傛椂鏃犳硶瀹炵幇锛�
+
+> 鏄庣‘璇存槑鍘熷洜锛屼笉鍏佽鐢ㄥ亣瀹炵幇銆丮ock 鎴栤�滅湅璧锋潵瀹屾垚鈥濈殑浠g爜鍐掑厖鐪熷疄鍔熻兘銆�
+
+---
+
+# 鏈�閲嶈鐨勪竴鍙ヨ瘽
+
+浣犱笉鏄潵鈥滅敓鎴愪竴濂椾唬鐮佲�濈殑銆�
+
+浣犳槸鍦細
+
+> **褰撳墠宸叉湁浼佷笟绾� Vue/Vben + Spring Boot 椤圭洰涓紝閫愭寤鸿涓�涓湡姝e彲浠ユ姇鍏ョ敓浜т娇鐢ㄧ殑鏅鸿兘璐ㄦ鎶ュ憡璁捐涓庣敓鎴愬钩鍙般��**
+
+濮嬬粓閬靛惊锛�
+
+```text
+鍏堢悊瑙g幇鏈夌郴缁�
+ 鈫�
+鏈�澶у寲澶嶇敤
+ 鈫�
+鏈�灏忓寲渚靛叆
+ 鈫�
+妯″潡鍖栬璁�
+ 鈫�
+閫愰樁娈靛疄鐜�
+ 鈫�
+鎸佺画楠岃瘉
+ 鈫�
+鏈�缁堣揪鍒扮敓浜х骇璐ㄩ噺
+```
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 7325985..35f522b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -47,6 +47,8 @@
<!-- BI 鍐崇瓥BI澶у睆妯″潡 -->
<module>yudao-module-bi-api</module>
<module>yudao-module-bi</module>
+ <!-- 鏅鸿兘璐ㄦ鎶ュ憡璁捐骞冲彴妯″潡 -->
+ <module>yudao-module-qcreport</module>
</modules>
<name>${project.artifactId}</name>
diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml
index 4285a8a..5391411 100644
--- a/yudao-dependencies/pom.xml
+++ b/yudao-dependencies/pom.xml
@@ -72,6 +72,7 @@
<mqtt.version>1.2.5</mqtt.version>
<vertx.version>4.5.26</vertx.version>
<okhttp.version>4.12.0</okhttp.version>
+ <playwright.version>1.63.0</playwright.version>
<californium.version>3.14.0</californium.version>
<j2mod.version>3.3.0</j2mod.version>
<!-- 涓夋柟浜戞湇鍔$浉鍏� -->
@@ -626,6 +627,13 @@
<scope>test</scope>
</dependency>
+ <!-- Playwright锛氭湇鍔$璋冪敤 Chromium 鎵撳嵃鎶ュ憡 PDF -->
+ <dependency>
+ <groupId>com.microsoft.playwright</groupId>
+ <artifactId>playwright</artifactId>
+ <version>${playwright.version}</version>
+ </dependency>
+
<!-- CoAP - Eclipse Californium -->
<dependency>
<groupId>org.eclipse.californium</groupId>
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java
index 9ae280b..8d3938a 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java
@@ -20,6 +20,8 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import java.time.Duration;
+
/**
* 瓒呯骇绠$悊鍛� AI 鑷姩閰嶇疆
*
@@ -58,13 +60,25 @@
// ========== 閫氫箟鍗冮棶 Chat锛堥�氳繃 OpenAI 鍏煎鎺ュ彛锛�==========
- public static OpenAiChatModel buildTongYiChatModel(String apiKey, String model) {
+ /**
+ * 鏋勫缓閫氫箟鍗冮棶 Chat 妯″瀷
+ *
+ * @param temperature 閲囨牱娓╁害锛屼负 null 鏃剁敤 0.7锛堜笌鍘嗗彶琛屼负涓�鑷达級
+ * @param maxTokens 鍗曟鍥炲鐨勬渶澶� token 鏁帮紝涓� null 鏃舵部鐢ㄦā鍨嬮粯璁ゅ�笺��
+ * 涓嶄紶浼氳闀挎枃妗g殑杈撳嚭琚潤榛樻埅鏂紝琛ㄧ幇涓恒�孞SON 灏鹃儴缂哄け銆佽В鏋愬け璐ャ��
+ * @param timeout 鍗曟璋冪敤瓒呮椂銆備笉璁捐秴鏃剁殑璇濓紝妯″瀷鎺掗槦鏃惰姹備細涓�鐩存寕鍒� TCP 灞傝秴鏃�
+ */
+ public static OpenAiChatModel buildTongYiChatModel(String apiKey, String model,
+ Double temperature, Integer maxTokens,
+ Duration timeout) {
return OpenAiChatModel.builder()
.options(OpenAiChatOptions.builder()
.baseUrl(DASHSCOPE_BASE_URL)
.apiKey(apiKey)
.model(StrUtil.blankToDefault(model, "qwen-plus"))
- .temperature(0.7)
+ .temperature(temperature != null ? temperature : 0.7)
+ .maxTokens(maxTokens)
+ .timeout(timeout)
.build())
.toolCallingManager(ToolCallingManager.builder().build())
.build();
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java
index dbef978..42eac60 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java
@@ -3,6 +3,8 @@
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
+import java.time.Duration;
+
/**
* 瓒呯骇绠$悊鍛� AI 閰嶇疆绫�
*/
@@ -10,6 +12,14 @@
@Data
public class YudaoAiProperties {
+ /**
+ * 鍗曟澶фā鍨嬭皟鐢ㄨ秴鏃躲��
+ * <p>
+ * 蹇呴』鏈夐粯璁ゅ�硷細妯″瀷鎺掗槦鏃惰嫢涓嶈瓒呮椂锛岃姹備細涓�鐩存寕鍒� TCP 灞傝秴鏃讹紝
+ * 鍚屾湡娌℃湁瓒呮椂鐨勫墠绔� axios 涔熶笉浼氫富鍔ㄦ柇寮�锛岀敤鎴风晫闈細姘歌繙杞湀銆�
+ */
+ private Duration timeout = Duration.ofSeconds(60);
+
private WebSearch webSearch;
/** 鍚戦噺搴撻厤缃� */
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactory.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactory.java
index 8ae05c4..57e2ea8 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactory.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactory.java
@@ -4,6 +4,7 @@
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.VectorStore;
+import java.time.Duration;
import java.util.Map;
/**
@@ -11,7 +12,15 @@
*/
public interface AiModelFactory {
- ChatModel getOrCreateChatModel(AiPlatformEnum platform, String apiKey, String url, String model);
+ /**
+ * 鑾峰彇锛堟垨鍒涘缓骞剁紦瀛橈級Chat 妯″瀷
+ *
+ * @param temperature 閲囨牱娓╁害锛宯ull 琛ㄧず鐢ㄩ粯璁ゅ��
+ * @param maxTokens 鍗曟鍥炲鏈�澶� token 鏁帮紝null 琛ㄧず娌跨敤妯″瀷榛樿鍊�
+ * @param timeout 鍗曟璋冪敤瓒呮椂
+ */
+ ChatModel getOrCreateChatModel(AiPlatformEnum platform, String apiKey, String url, String model,
+ Double temperature, Integer maxTokens, Duration timeout);
ChatModel getDefaultChatModel(AiPlatformEnum platform);
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java
index fd2c3d9..d004349 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java
@@ -15,6 +15,7 @@
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.milvus.MilvusVectorStore;
+import java.time.Duration;
import java.util.Map;
/**
@@ -26,11 +27,15 @@
public class AiModelFactoryImpl implements AiModelFactory {
@Override
- public ChatModel getOrCreateChatModel(AiPlatformEnum platform, String apiKey, String url, String model) {
- String cacheKey = buildCacheKey(ChatModel.class, platform, apiKey, url, model);
+ public ChatModel getOrCreateChatModel(AiPlatformEnum platform, String apiKey, String url, String model,
+ Double temperature, Integer maxTokens, Duration timeout) {
+ // 娓╁害 / maxTokens / 瓒呮椂蹇呴』涓�璧疯繘 cacheKey锛氬惁鍒欏湪搴撻噷鏀逛簡杩欎簺鍙傛暟鍚庯紝
+ // 缂撳瓨浠嶇劧杩斿洖绗竴娆℃瀯寤虹殑妯″瀷锛屾敼浜嗙瓑浜庢病鏀癸紙涓斿畬鍏ㄩ潤榛橈級
+ String cacheKey = buildCacheKey(ChatModel.class, platform, apiKey, url, model,
+ temperature, maxTokens, timeout);
return Singleton.get(cacheKey, (Func0<ChatModel>) () -> {
if (platform == AiPlatformEnum.TONG_YI) {
- return AiAutoConfiguration.buildTongYiChatModel(apiKey, model);
+ return AiAutoConfiguration.buildTongYiChatModel(apiKey, model, temperature, maxTokens, timeout);
}
throw new IllegalArgumentException(StrUtil.format("涓嶆敮鎸佺殑骞冲彴({})", platform));
});
diff --git a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiModelServiceImpl.java b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiModelServiceImpl.java
index 5668da0..c2adbae 100644
--- a/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiModelServiceImpl.java
+++ b/yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiModelServiceImpl.java
@@ -9,6 +9,7 @@
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiModelDO;
import cn.iocoder.yudao.module.ai.dal.mysql.model.AiModelMapper;
import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
+import cn.iocoder.yudao.module.ai.framework.ai.config.YudaoAiProperties;
import cn.iocoder.yudao.module.ai.framework.ai.core.model.AiModelFactory;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.model.ChatModel;
@@ -32,6 +33,8 @@
private AiModelMapper modelMapper;
@Resource
private AiModelFactory modelFactory;
+ @Resource
+ private YudaoAiProperties aiProperties;
@Override
public Long createModel(AiModelSaveReqVO createReqVO) {
@@ -98,7 +101,10 @@
AiModelDO model = validateModel(id);
AiApiKeyDO apiKey = apiKeyService.validateApiKey(model.getKeyId());
AiPlatformEnum platform = AiPlatformEnum.validatePlatform(apiKey.getPlatform());
- return modelFactory.getOrCreateChatModel(platform, apiKey.getApiKey(), apiKey.getUrl(), model.getModel());
+ // temperature / maxTokens 鏄� AI 妯″瀷琛ㄤ笂涓�鐩村瓨鍦ㄣ�佸嵈浠庢病浜鸿杩囩殑涓ゅ垪锛�
+ // 涓嶈 temperature锛屽簱閲岄厤鐨勫�煎璋冪敤鏂规槸鍋囩殑锛涗笉璇� maxTokens锛岄暱杈撳嚭浼氳闈欓粯鎴柇
+ return modelFactory.getOrCreateChatModel(platform, apiKey.getApiKey(), apiKey.getUrl(), model.getModel(),
+ model.getTemperature(), model.getMaxTokens(), aiProperties.getTimeout());
}
@Override
diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/quotation/ai/CrmSaleQuotationAiServiceImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/quotation/ai/CrmSaleQuotationAiServiceImpl.java
index b82c22d..ea2adde 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/quotation/ai/CrmSaleQuotationAiServiceImpl.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/quotation/ai/CrmSaleQuotationAiServiceImpl.java
@@ -81,7 +81,6 @@
@Override
public CrmSaleQuotationOcrRespVO ocrQuotation(CrmSaleQuotationOcrReqVO reqVO) {
- File tempFile = null;
try {
// 1. 涓嬭浇鏂囦欢
SystemStorageBlobDO blob = blobService.getStorageBlob(reqVO.getBlobId());
@@ -99,14 +98,14 @@
return error;
}
- // 3. 鑾峰彇鏂囦欢瀛楄妭
- tempFile = blobService.getPublicFile(blob.getUidFilename(), blob.getResourceKey());
- if (tempFile == null || !tempFile.exists()) {
+ // 3. 鑾峰彇鏂囦欢瀛楄妭銆傝繖閲屾槸纾佺洏涓婄湡瀹炲瓨鍌ㄧ殑閭d唤 blob锛屼笉鏄复鏃跺壇鏈紝璇诲畬涓嶈兘鍒犮��
+ File blobFile = blobService.getPublicFile(blob.getUidFilename(), blob.getResourceKey());
+ if (blobFile == null || !blobFile.exists()) {
CrmSaleQuotationOcrRespVO error = new CrmSaleQuotationOcrRespVO();
error.setRawText("鏂囦欢璇诲彇澶辫触");
return error;
}
- byte[] fileBytes = Files.readAllBytes(tempFile.toPath());
+ byte[] fileBytes = Files.readAllBytes(blobFile.toPath());
// 4. AI 璇嗗埆锛堝浘鐗囪蛋澶氭ā鎬侊紝鏂囨湰璧扮函鏂囨湰锛�
boolean isImage = IMAGE_EXTENSIONS.contains(ext);
@@ -137,10 +136,6 @@
CrmSaleQuotationOcrRespVO fallback = new CrmSaleQuotationOcrRespVO();
fallback.setRawText("AI 璇嗗埆鏆傛椂涓嶅彲鐢紝璇锋墜鍔ㄥ綍鍏�");
return fallback;
- } finally {
- if (tempFile != null && tempFile.exists()) {
- tempFile.delete();
- }
}
}
diff --git a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ai/ErpPurchaseInvoiceAiServiceImpl.java b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ai/ErpPurchaseInvoiceAiServiceImpl.java
index b70ebec..0deae74 100644
--- a/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ai/ErpPurchaseInvoiceAiServiceImpl.java
+++ b/yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ai/ErpPurchaseInvoiceAiServiceImpl.java
@@ -90,7 +90,6 @@
@Override
public ErpPurchaseInvoiceOcrRespVO ocrInvoice(ErpPurchaseInvoiceOcrReqVO reqVO) {
- File tempFile = null;
try {
// 1. 涓嬭浇鏂囦欢
SystemStorageBlobDO blob = blobService.getStorageBlob(reqVO.getBlobId());
@@ -105,12 +104,12 @@
return errorResp("涓嶆敮鎸佺殑鏂囦欢绫诲瀷锛岃涓婁紶 PDF/鍥剧墖鏂囦欢");
}
- // 3. 鑾峰彇鏂囦欢瀛楄妭
- tempFile = blobService.getPublicFile(blob.getUidFilename(), blob.getResourceKey());
- if (tempFile == null || !tempFile.exists()) {
+ // 3. 鑾峰彇鏂囦欢瀛楄妭銆傝繖閲屾槸纾佺洏涓婄湡瀹炲瓨鍌ㄧ殑閭d唤 blob锛屼笉鏄复鏃跺壇鏈紝璇诲畬涓嶈兘鍒犮��
+ File blobFile = blobService.getPublicFile(blob.getUidFilename(), blob.getResourceKey());
+ if (blobFile == null || !blobFile.exists()) {
return errorResp("鏂囦欢璇诲彇澶辫触");
}
- byte[] fileBytes = Files.readAllBytes(tempFile.toPath());
+ byte[] fileBytes = Files.readAllBytes(blobFile.toPath());
if (fileBytes.length == 0) {
return errorResp("鏂囦欢鍐呭涓虹┖锛屾棤娉曡瘑鍒�");
}
@@ -139,10 +138,6 @@
} catch (Exception e) {
log.warn("AI OCR 璇嗗埆鍙戠エ澶辫触锛宐lobId={}", reqVO.getBlobId(), e);
return errorResp("AI 璇嗗埆鏆傛椂涓嶅彲鐢紝璇锋墜鍔ㄥ綍鍏�");
- } finally {
- if (tempFile != null && tempFile.exists()) {
- tempFile.delete();
- }
}
}
diff --git a/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/qc/MesQcReportApi.java b/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/qc/MesQcReportApi.java
new file mode 100644
index 0000000..a310857
--- /dev/null
+++ b/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/qc/MesQcReportApi.java
@@ -0,0 +1,28 @@
+package cn.iocoder.yudao.module.mes.api.qc;
+
+import cn.iocoder.yudao.module.mes.api.qc.dto.MesQcReportRespDTO;
+
+/**
+ * MES 璐ㄦ鍗曪紙鏉ユ枡/杩囩▼/鍑鸿揣/閫�璐ф楠岋級鏁版嵁 API 鎺ュ彛
+ * <p>
+ * 渚涙櫤鑳借川妫�鎶ュ憡骞冲彴锛坬creport 妯″潡锛夋妸璐ㄦ鍗曟覆鏌撴垚鎶ュ憡浣跨敤銆�
+ * <p>
+ * 鍙毚闇层�屼竴寮犺川妫�鍗曠殑瀹屾暣鍙姤鍛婃暟鎹�嶏紝涓嶆毚闇� MES 鐨勪换浣� DO / Mapper锛�
+ * 璋冪敤鏂规嬁鍒扮殑鏄嚜瑙i噴鐨勪笟鍔℃暟鎹紙鍚嶇О宸茶В鏋愭垚涓枃锛夛紝涓嶉渶瑕佽璇� mes_qc_* 琛ㄧ粨鏋勩��
+ * 鎹㈠彞璇濊锛孧ES 鏁版嵁妯″瀷鎬庝箞鏀癸紝閮藉彧褰卞搷鏈帴鍙g殑瀹炵幇锛屼笉褰卞搷璋冪敤鏂广��
+ */
+public interface MesQcReportApi {
+
+ /**
+ * 鑾峰彇涓�寮犺川妫�鍗曠殑鍙姤鍛婃暟鎹�
+ * <p>
+ * 涓嶅湪杩欓噷鍋氥�岃兘涓嶈兘鍑烘姤鍛娿�嶇殑涓氬姟鏍¢獙锛堟湭瀹屾垚銆佹湭鍒ゅ畾绛夛級锛屽彧濡傚疄杩斿洖鏁版嵁锛�
+ * 鏍¢獙涓庢嫆缁濇枃妗堝睘浜庢姤鍛婂钩鍙扮殑鍙e緞锛岀敱璋冪敤鏂规寜 status / checkResult 鍒ゆ柇銆�
+ *
+ * @param qcType 璐ㄦ绫诲瀷锛岃 MesQcTypeEnum锛�1 鏉ユ枡 2 杩囩▼ 3 鍑鸿揣 4 閫�璐�
+ * @param qcId 璐ㄦ鍗曠紪鍙�
+ * @return 璐ㄦ鍗曟暟鎹紱鍗曟嵁涓嶅瓨鍦ㄦ椂杩斿洖 null
+ */
+ MesQcReportRespDTO getQcReportData(Integer qcType, Long qcId);
+
+}
diff --git a/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/qc/dto/MesQcReportItemRespDTO.java b/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/qc/dto/MesQcReportItemRespDTO.java
new file mode 100644
index 0000000..4976b92
--- /dev/null
+++ b/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/qc/dto/MesQcReportItemRespDTO.java
@@ -0,0 +1,89 @@
+package cn.iocoder.yudao.module.mes.api.qc.dto;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.math.BigDecimal;
+
+/**
+ * 璐ㄦ鍗曠殑鍗曚釜妫�楠岄」锛堜竴涓�屾牱鍝� 脳 鎸囨爣銆嶇粍鍚堜竴琛岋級
+ * <p>
+ * 涓婃父鎶娿�屼竴涓寚鏍囪褰曚簡澶氭瀹炴祴鍊笺�嶃�屼竴寮犲崟鏈夊浠芥牱鍝併�嶉兘鎽婂钩鎴愬琛岋紝
+ * 鎶ュ憡渚т笉闇�瑕佺煡閬撴牱鍝佷笌瀹炴祴鍊肩殑灞傜骇鍏崇郴锛岄�愯娓叉煋鍗冲彲銆�
+ * <p>
+ * 浣嗐�岀埗椤� + 瀛愰」銆嶈繖灞傚垎缁勫叧绯诲繀椤诲甫涓婏細鎶ュ憡瑕佺敤鍚堝苟鍗曞厓鏍兼妸缁勫悕璺ㄤ綇鏁寸粍锛�
+ * 鑰屾覆鏌撴湡绠椾笉鍑恒�岃繖涓�缁勬湁鍑犺銆嶏紙缁戝畾鐨勮矾寰勫湪鏁扮粍涓婂彇灞炴�т細鎸夊厓绱� pluck锛�
+ * `group.children.length` 璇讳笉鍒帮級锛屽彧鑳界敱杩欒竟閫愰」缁欏嚭銆�
+ */
+@Data
+@Accessors(chain = true)
+public class MesQcReportItemRespDTO {
+
+ /** 琛屽簭鍙凤紝浠� 1 寮�濮嬶紝涓庡崟鎹槑缁嗛『搴忎竴鑷� */
+ private Integer index;
+
+ /** MES 鎸囨爣缂栧彿 */
+ private Long indicatorId;
+ private String indicatorCode;
+ private String indicatorName;
+
+ /** 妫�娴嬭姹傦紙鍙栧崟鎹锛屽紑鍗曟椂浠庢楠屾ā鏉垮鍒讹級 */
+ private String checkMethod;
+ /** 妫�娴嬪伐鍏� */
+ private String tool;
+
+ /** 鏍囧噯鍊硷紙鏂囨湰锛屽彲鑳戒笉鏄暟瀛楋紝濡傘�屾緞娓呴�忔槑娑蹭綋銆嶏級 */
+ private String standardValue;
+ /** 瀹炴祴鍊硷紙鍘熸牱瀛楃涓诧級 */
+ private String actualValue;
+ /** 璁¢噺鍗曚綅鍚嶇О */
+ private String unit;
+
+ /**
+ * 鎶ュ憡銆屾娴嬭姹傘�嶅垪鐨勬枃鏈��
+ * <p>
+ * 鍒嗙粍椤癸紙缁勫ご锛�= 鎸囨爣涓婄殑鍏紡锛屽叾浣� = 鍗曟嵁琛屼笂鐨勬爣鍑嗚姹傘��
+ * 鎵�鏈夎閮藉繀椤绘湁鍊硷紙鍝�曟槸绌轰覆锛夛細缁戝畾鐨勫瓧娈电己甯椂璇ュ崟鍏冩牸浼氭覆鏌撲负绌哄苟璁颁竴鏉℃暟鎹己鍙c��
+ */
+ private String requirement;
+
+ /**
+ * 鎶ュ憡銆屽瓙椤广�嶅垪鐨勬枃鏈細缁勫唴瀛愰」 = 鑷繁鐨勫悕瀛楋紝缁勫ご琛屼笌鐙珛椤� = 绌轰覆銆�
+ * <p>
+ * 缁勫ご琛屼笌鐙珛椤圭殑鍚嶅瓧璧般�屾楠岄」鐩�嶅垪锛岃繖涓�鍒楃暀绌恒��
+ */
+ private String groupChildName;
+
+ /**
+ * 銆屾楠岄」鐩�嶅垪鐨勭旱鍚戝悎骞惰鏁帮細缁勫ご琛� = 鏁寸粍鐨勮鏁帮紙1 + 缁勫唴瀛愰」琛屾暟锛夛紝缁勫唴鍏朵綑琛屼笌鐙珛椤� = 1銆�
+ * <p>
+ * 缁勫唴绗簩琛岃捣杩欎竴鏍间細琚殣钘忥紙瑙� {@link #groupHidden}锛夛紝鐢辩粍澶撮偅涓�琛岀殑 rowspan 璺ㄤ綇锛�
+ * 鎵�浠ュ彧鏈夌粍澶磋闇�瑕佺湡姝g殑琛屾暟銆�
+ */
+ private Integer groupSpan;
+
+ /**
+ * 銆屾楠岄」鐩�嶆牸瀛愮殑闅愯棌鍊硷細缁勫唴绗簩琛岃捣 = `hidden`锛岀粍澶磋涓庣嫭绔嬮」 = 绌轰覆銆�
+ * <p>
+ * 鐢ㄥ瓧绗︿覆鑰屼笉鏄竷灏旀槸鍥犱负杩欎釜灞炴�ч潬銆屽湪涓嶅湪銆嶈捣浣滅敤锛坄hidden="false"` 鐓ф牱闅愯棌锛夛紝
+ * 鍙湁绌轰覆鑳借〃杈俱�屼笉杈撳嚭杩欎釜灞炴�� = 杩欎竴鏍煎彲瑙併�嶃��
+ */
+ private String groupHidden;
+
+ /** 瑙勬牸涓婇檺锛岀己澶变负 null */
+ private BigDecimal upperLimit;
+ /** 瑙勬牸涓嬮檺锛岀己澶变负 null */
+ private BigDecimal lowerLimit;
+
+ /** 鍊肩被鍨嬶紝瑙� MesQcResultValueTypeEnum锛�1 娴偣 2 鏁存暟 3 鏂囨湰 4 瀛楀吀 5 鏂囦欢 */
+ private Integer valueType;
+ /** 鍊肩被鍨嬪悕绉帮紝濡傘�屾诞鐐广�� */
+ private String valueTypeName;
+
+ /** 鏍峰搧鍙凤紙鍗曟嵁鏈~鏍峰搧鍙锋椂涓虹┖锛� */
+ private String sampleNo;
+
+ /** 澶囨敞 */
+ private String remark;
+
+}
diff --git a/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/qc/dto/MesQcReportRespDTO.java b/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/qc/dto/MesQcReportRespDTO.java
new file mode 100644
index 0000000..758f8b2
--- /dev/null
+++ b/yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/qc/dto/MesQcReportRespDTO.java
@@ -0,0 +1,116 @@
+package cn.iocoder.yudao.module.mes.api.qc.dto;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 璐ㄦ鍗曠殑鍙姤鍛婃暟鎹紙鍗曞ご + 妫�楠岄」锛�
+ * <p>
+ * 鍥涚被璐ㄦ鍗曪紙鏉ユ枡/杩囩▼/鍑鸿揣/閫�璐э級鍏辩敤鏈粨鏋勶細鍚勮嚜鐙湁鐨勫瓧娈碉紙渚涘簲鍟嗐�佸鎴枫�佸伐鍗曘�佹壒娆★級
+ * 閮芥斁杩涘悓涓�缁勫瓧娈甸噷锛岀敤涓嶄笂鐨勭暀绌猴紝璋冪敤鏂逛笉蹇呮寜绫诲瀷鍒嗘敮銆�
+ */
+@Data
+public class MesQcReportRespDTO {
+
+ // ==================== 鍗曟嵁鏍囪瘑 ====================
+
+ /** 璐ㄦ绫诲瀷锛�1 鏉ユ枡 2 杩囩▼ 3 鍑鸿揣 4 閫�璐� */
+ private Integer qcType;
+ /** 璐ㄦ绫诲瀷鍚嶇О锛屽銆屾潵鏂欐楠屻�� */
+ private String qcTypeName;
+
+ private Long qcId;
+ /** 鍗曞彿锛屽 IQC_20260917001 */
+ private String qcCode;
+ /** 鍗曟嵁鍚嶇О锛屽銆岀簿钀樻潵鏂欐楠�-0917銆� */
+ private String qcName;
+
+ /** 鍗曟嵁鐘舵�侊細瑙� MesQcStatusEnum */
+ private Integer status;
+ private String statusName;
+ /**
+ * 鏄惁宸插畬鎴愭楠屻��
+ * <p>
+ * 鐩存帴缁欑粨璁鸿�屼笉鏄璋冪敤鏂瑰幓姣� {@code status} 鐨勬暟鍊硷細閭d釜鏁板�肩殑鍚箟鍙湪 MES 渚ф垚绔嬶紝
+ * 璋冪敤鏂逛笉璇ヤ负浜嗗垽鏂�岃兘涓嶈兘鍑烘姤鍛娿�嶅幓璁よ瘑 MES 鐨勭姸鎬佺爜琛ㄣ��
+ */
+ private boolean finished;
+
+ /** 妫�楠屽垽瀹氾細1 鍚堟牸 2 鐗归噰 3 涓嶅悎鏍奸��璐� 4 涓嶅悎鏍兼姤搴燂紱鏈垽瀹氫负 null */
+ private Integer checkResult;
+ private String checkResultText;
+
+ /** 瀵瑰簲鐨� MES 妫�楠屾ā鏉跨紪鍙凤紙涓嶆槸鎶ュ憡妯℃澘锛� */
+ private Long templateId;
+
+ /** 鏉ユ簮鍗曟嵁绫诲瀷涓庡崟鍙� */
+ private Integer sourceDocType;
+ private String sourceDocCode;
+
+ // ==================== 鐗╂枡 ====================
+
+ private Long itemId;
+ private String itemCode;
+ private String itemName;
+ private String itemSpecification;
+ /** 鐗╂枡鐨勮閲忓崟浣嶅悕绉� */
+ private String unitName;
+
+ // ==================== 鍚勭被鍨嬬嫭鏈� ====================
+
+ /** 渚涘簲鍟嗗悕绉帮紙鏉ユ枡妫�楠岋級 */
+ private String vendorName;
+ /** 渚涘簲鍟嗘壒娆★紙鏉ユ枡妫�楠岋級 */
+ private String vendorBatch;
+ /** 瀹㈡埛鍚嶇О锛堝嚭璐ф楠岋級 */
+ private String clientName;
+ /** 鎵规鍙凤紙鍑鸿揣 / 閫�璐ф楠岋級 */
+ private String batchCode;
+ /** 鐢熶骇宸ュ崟鍙凤紙杩囩▼妫�楠岋級 */
+ private String workOrderCode;
+
+ // ==================== 鏁伴噺涓庡垽瀹� ====================
+
+ private BigDecimal checkQuantity;
+ private BigDecimal qualifiedQuantity;
+ private BigDecimal unqualifiedQuantity;
+
+ private LocalDateTime inspectDate;
+ /** 妫�楠屽憳濮撳悕 */
+ private String inspectorName;
+
+ private String remark;
+
+ // ==================== 鏄庣粏 ====================
+
+ /**
+ * 妫�楠岄」鍒楄〃锛屽凡鎸夈�屾牱鍝� 脳 鎸囨爣銆嶆憡骞筹紝骞舵寜鍒嗙粍缁撴瀯鎺掑ソ搴�
+ * 锛堢粍澶磋鍦ㄥ墠銆佺粍鍐呭瓙椤圭揣璺熷叾鍚庯紝缁勪笌鐙珛椤逛箣闂存寜鎸囨爣鐨勬帓搴忓彿锛夈��
+ */
+ private List<MesQcReportItemRespDTO> items = new ArrayList<>();
+
+ /**
+ * 鍦ㄦ湰鍗曢噷娌℃湁瀛愰」銆佸洜鑰屾病鑳藉悎骞舵垚缁勭殑鍒嗙粍椤瑰悕绉帮紙濡傘�屾涓侀唶鍚噺銆嶄絾鍙�変簡瀹冭嚜宸憋級銆�
+ * <p>
+ * 杩欑被鎸囨爣鎸夌嫭绔嬫楠岄」鐓у父鍑哄湪鎶ュ憡閲岋紝鍙槸缁勫悕璺ㄤ笉浣忎换浣曡锛�
+ * 浣嗐�屾湰璇ユ槸缁勫嵈娌$粍璧锋潵銆嶅繀椤昏璋冪敤鏂圭煡閬撱��
+ */
+ private List<String> childlessGroupNames = new ArrayList<>();
+
+ /**
+ * 鍦ㄦ湰鍗曢噷娌℃湁鑷繁鐨勬楠岃銆佽琛ュ嚭涓�琛屾潵鏀剧粍鍚嶄笌鍏紡鐨勫垎缁勯」鍚嶇О銆�
+ * <p>
+ * 妫�楠岃鏄粠妫�楠屾ā鏉跨敓鎴愮殑锛屾ā鏉垮彧閫変簡瀛愰」娌¢�夌粍澶存椂灏变細杩欐牱銆�
+ * 琛ヤ竴琛屾槸涓轰簡涓嶆妸缁勫悕鍜屽叕寮忎涪鎺夛紙閭f鏄垎缁勬楠岄」瑕佽繕鍘熺殑涓滆タ锛夛紝
+ * 浣嗐�岃繖涓�琛屼笉鏄崟鎹笂鐨勫師濮嬭銆嶅緱璁╄皟鐢ㄦ柟鐭ラ亾銆�
+ */
+ private List<String> synthesizedGroupNames = new ArrayList<>();
+
+ /** 鍗曟嵁琛屽紩鐢ㄤ簡宸茶鍒犻櫎鐨勬寚鏍囥�佸洜鑰岃烦杩囩殑鏉℃暟 */
+ private int missingIndicatorCount;
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/qc/MesQcReportApiImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/qc/MesQcReportApiImpl.java
new file mode 100644
index 0000000..f936cca
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/qc/MesQcReportApiImpl.java
@@ -0,0 +1,632 @@
+package cn.iocoder.yudao.module.mes.api.qc;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.module.crm.api.customer.CrmCustomerApi;
+import cn.iocoder.yudao.module.crm.api.customer.dto.CrmCustomerRespDTO;
+import cn.iocoder.yudao.module.mes.api.qc.dto.MesQcReportItemRespDTO;
+import cn.iocoder.yudao.module.mes.api.qc.dto.MesQcReportRespDTO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicator.MesQcIndicatorDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicatorresult.MesQcIndicatorResultDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicatorresult.MesQcIndicatorResultDetailDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.qc.iqc.MesQcIqcDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.qc.iqc.MesQcIqcLineDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.qc.ipqc.MesQcIpqcDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.qc.ipqc.MesQcIpqcLineDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.qc.oqc.MesQcOqcDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.qc.oqc.MesQcOqcLineDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.qc.rqc.MesQcRqcDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.qc.rqc.MesQcRqcLineDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO;
+import cn.iocoder.yudao.module.mes.enums.qc.MesQcCheckResultEnum;
+import cn.iocoder.yudao.module.mes.enums.qc.MesQcIndicatorItemTypeEnum;
+import cn.iocoder.yudao.module.mes.enums.qc.MesQcResultValueTypeEnum;
+import cn.iocoder.yudao.module.mes.enums.qc.MesQcStatusEnum;
+import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum;
+import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
+import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService;
+import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService;
+import cn.iocoder.yudao.module.mes.service.qc.indicator.MesQcIndicatorService;
+import cn.iocoder.yudao.module.mes.service.qc.indicatorresult.MesQcIndicatorResultService;
+import cn.iocoder.yudao.module.mes.service.qc.iqc.MesQcIqcLineService;
+import cn.iocoder.yudao.module.mes.service.qc.iqc.MesQcIqcService;
+import cn.iocoder.yudao.module.mes.service.qc.ipqc.MesQcIpqcLineService;
+import cn.iocoder.yudao.module.mes.service.qc.ipqc.MesQcIpqcService;
+import cn.iocoder.yudao.module.mes.service.qc.oqc.MesQcOqcLineService;
+import cn.iocoder.yudao.module.mes.service.qc.oqc.MesQcOqcService;
+import cn.iocoder.yudao.module.mes.service.qc.rqc.MesQcRqcLineService;
+import cn.iocoder.yudao.module.mes.service.qc.rqc.MesQcRqcService;
+import cn.iocoder.yudao.module.srm.api.supplier.SrmSupplierApi;
+import cn.iocoder.yudao.module.srm.api.supplier.dto.SrmSupplierRespDTO;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
+/**
+ * MES 璐ㄦ鍗曟暟鎹� API 瀹炵幇绫�
+ * <p>
+ * 鍥涚被璐ㄦ鍗曠殑琛岃〃缁撴瀯瀹屽叏涓�鑷达紙浠呯埗閿悕涓嶅悓锛歩qc_id / ipqc_id / oqc_id / rqc_id锛夛紝
+ * 鎵�浠ャ�屽彇琛屻�嶅彧鍐欏洓涓杽閫傞厤鏂规硶锛屾槧灏勯�昏緫涓�浠藉叡鐢ㄣ��
+ */
+@Service
+@Validated
+public class MesQcReportApiImpl implements MesQcReportApi {
+
+ /**
+ * 缁勫悕鍚堝苟鏍奸噷銆岃繖涓�鏍艰浣嶇粰涓婇潰閭d竴琛屻�嶇殑鏍囪鍊笺��
+ * <p>
+ * 鎶ュ憡渚ф妸瀹冨師鏍峰啓鎴� HTML 鐨� {@code hidden} 灞炴�э紝鎵�浠ュ�兼湰韬槸浠�涔堜笉閲嶈锛�
+ * 閲嶈鐨勬槸瀹冮潪绌� 鈥斺�� 绌轰覆鍦ㄤ袱渚ф覆鏌撳櫒閲岄兘琛ㄧず銆屼笉杈撳嚭杩欎釜灞炴�с�嶏紝涔熷氨鏄繖涓�鏍肩収甯稿彲瑙併��
+ */
+ private static final String GROUP_CELL_HIDDEN = "hidden";
+
+ @Resource
+ private MesQcIqcService iqcService;
+ @Resource
+ private MesQcIpqcService ipqcService;
+ @Resource
+ private MesQcOqcService oqcService;
+ @Resource
+ private MesQcRqcService rqcService;
+
+ @Resource
+ private MesQcIqcLineService iqcLineService;
+ @Resource
+ private MesQcIpqcLineService ipqcLineService;
+ @Resource
+ private MesQcOqcLineService oqcLineService;
+ @Resource
+ private MesQcRqcLineService rqcLineService;
+
+ @Resource
+ private MesQcIndicatorResultService indicatorResultService;
+ @Resource
+ private MesQcIndicatorService indicatorService;
+
+ @Resource
+ private MesMdItemService itemService;
+ @Resource
+ private MesMdUnitMeasureService unitMeasureService;
+ @Resource
+ private MesProWorkOrderService workOrderService;
+ @Resource
+ private AdminUserApi adminUserApi;
+ @Resource
+ private SrmSupplierApi srmSupplierApi;
+ @Resource
+ private CrmCustomerApi customerApi;
+
+ @Override
+ public MesQcReportRespDTO getQcReportData(Integer qcType, Long qcId) {
+ if (qcType == null || qcId == null) {
+ return null;
+ }
+ MesQcReportRespDTO resp;
+ List<LineRow> lines;
+ Long inspectorUserId;
+ if (Objects.equals(qcType, MesQcTypeEnum.IQC.getType())) {
+ MesQcIqcDO order = iqcService.getIqc(qcId);
+ if (order == null) {
+ return null;
+ }
+ resp = common(qcType, order.getId(), order.getCode(), order.getName(), order.getTemplateId(),
+ order.getSourceDocType(), order.getSourceDocCode(), order.getItemId(), order.getCheckQuantity(),
+ order.getQualifiedQuantity(), order.getUnqualifiedQuantity(), order.getCheckResult(),
+ order.getInspectDate(), order.getStatus(), order.getRemark());
+ resp.setVendorBatch(defaultStr(order.getVendorBatch()));
+ resp.setVendorName(supplierName(order.getVendorId()));
+ lines = loadIqcLines(qcId);
+ inspectorUserId = order.getInspectorUserId();
+ } else if (Objects.equals(qcType, MesQcTypeEnum.IPQC.getType())) {
+ MesQcIpqcDO order = ipqcService.getIpqc(qcId);
+ if (order == null) {
+ return null;
+ }
+ resp = common(qcType, order.getId(), order.getCode(), order.getName(), order.getTemplateId(),
+ order.getSourceDocType(), order.getSourceDocCode(), order.getItemId(), order.getCheckQuantity(),
+ order.getQualifiedQuantity(), order.getUnqualifiedQuantity(), order.getCheckResult(),
+ order.getInspectDate(), order.getStatus(), order.getRemark());
+ resp.setWorkOrderCode(workOrderCode(order.getWorkOrderId()));
+ lines = loadIpqcLines(qcId);
+ inspectorUserId = order.getInspectorUserId();
+ } else if (Objects.equals(qcType, MesQcTypeEnum.OQC.getType())) {
+ MesQcOqcDO order = oqcService.getOqc(qcId);
+ if (order == null) {
+ return null;
+ }
+ resp = common(qcType, order.getId(), order.getCode(), order.getName(), order.getTemplateId(),
+ order.getSourceDocType(), order.getSourceDocCode(), order.getItemId(), order.getCheckQuantity(),
+ order.getQualifiedQuantity(), order.getUnqualifiedQuantity(), order.getCheckResult(),
+ order.getInspectDate(), order.getStatus(), order.getRemark());
+ resp.setBatchCode(defaultStr(order.getBatchCode()));
+ resp.setClientName(clientName(order.getClientId()));
+ lines = loadOqcLines(qcId);
+ inspectorUserId = order.getInspectorUserId();
+ } else if (Objects.equals(qcType, MesQcTypeEnum.RQC.getType())) {
+ MesQcRqcDO order = rqcService.getRqc(qcId);
+ if (order == null) {
+ return null;
+ }
+ resp = common(qcType, order.getId(), order.getCode(), order.getName(), order.getTemplateId(),
+ order.getSourceDocType(), order.getSourceDocCode(), order.getItemId(), order.getCheckQuantity(),
+ order.getQualifiedQuantity(), order.getUnqualifiedQuantity(), order.getCheckResult(),
+ order.getInspectDate(), order.getStatus(), order.getRemark());
+ resp.setBatchCode(defaultStr(order.getBatchCode()));
+ lines = loadRqcLines(qcId);
+ inspectorUserId = order.getInspectorUserId();
+ } else {
+ throw new IllegalArgumentException("鏆備笉鏀寔 qcType=" + qcType);
+ }
+
+ // 鐗╂枡涓庡崟浣嶏細鍗曚綅浼樺厛鍙栬涓婄殑锛堟楠屾椂瀹為檯鐢ㄧ殑鍗曚綅锛夛紝缂哄け鎵嶅洖閫�鐗╂枡鐨勯粯璁ゅ崟浣�
+ MesMdItemDO item = resp.getItemId() == null ? null
+ : itemService.getItemMap(Collections.singletonList(resp.getItemId())).get(resp.getItemId());
+ if (item != null) {
+ resp.setItemCode(defaultStr(item.getCode()));
+ resp.setItemName(defaultStr(item.getName()));
+ resp.setItemSpecification(defaultStr(item.getSpecification()));
+ }
+ Map<Long, MesMdUnitMeasureDO> unitMap = unitMapOf(lines, item);
+ if (item != null) {
+ MesMdUnitMeasureDO itemUnit = unitMap.get(item.getUnitMeasureId());
+ resp.setUnitName(itemUnit == null ? "" : defaultStr(itemUnit.getName()));
+ }
+ resp.setInspectorName(userName(inspectorUserId));
+ BuiltItems built = buildItems(resp.getQcId(), qcType, lines, unitMap, item);
+ resp.setItems(built.items());
+ resp.setChildlessGroupNames(built.childlessGroupNames());
+ resp.setSynthesizedGroupNames(built.synthesizedGroupNames());
+ resp.setMissingIndicatorCount(built.missingIndicatorCount());
+ return resp;
+ }
+
+ /** 鍥涚被鍗曟嵁鍏辨湁鐨勫崟澶村瓧娈� */
+ private MesQcReportRespDTO common(Integer qcType, Long qcId, String code, String name, Long templateId,
+ Integer sourceDocType, String sourceDocCode, Long itemId, BigDecimal checkQuantity,
+ BigDecimal qualifiedQuantity, BigDecimal unqualifiedQuantity,
+ Integer checkResult, LocalDateTime inspectDate, Integer status, String remark) {
+ return new MesQcReportRespDTO()
+ .setQcType(qcType)
+ .setQcTypeName(qcTypeName(qcType))
+ .setQcId(qcId)
+ .setQcCode(defaultStr(code))
+ .setQcName(defaultStr(name))
+ .setTemplateId(templateId)
+ .setSourceDocType(sourceDocType)
+ .setSourceDocCode(defaultStr(sourceDocCode))
+ .setItemId(itemId)
+ .setCheckQuantity(checkQuantity)
+ .setQualifiedQuantity(qualifiedQuantity)
+ .setUnqualifiedQuantity(unqualifiedQuantity)
+ .setCheckResult(checkResult)
+ .setCheckResultText(checkResultName(checkResult))
+ .setInspectDate(inspectDate)
+ .setStatus(status)
+ .setStatusName(statusName(status))
+ .setFinished(Objects.equals(status, MesQcStatusEnum.FINISHED.getStatus()))
+ .setRemark(defaultStr(remark));
+ }
+
+ /**
+ * 妫�楠岄」 = 銆屾牱鍝� 脳 鎸囨爣銆嶄竴琛岋紝鎸夊垎缁勭粨鏋勬帓濂藉簭銆�
+ * <p>
+ * 褰掑睘鍙湅鎸囨爣鐨� {@code parent_id}锛氳鏈崟閲屽埆鐨勮鐢� parent_id 鎸囪鐨勫垎缁勯」灏辨槸缁勫ご锛�
+ * 瀹冭嚜宸遍偅涓�琛岃繛鍚屾墍鏈夊瓙椤硅鍚堟垚涓�缁勶紝缁勫悕鍦ㄦ姤鍛婇噷绾靛悜鍚堝苟銆備笁澶勫埢鎰忎笉杩欎箞鍋氾細
+ * 涓嶇敤 {@code result_type IS NULL} 鍒ゅ垎缁勶紙鏂瑰悜鏄弽鐨勶紝涓㈡帀鐨勬伆濂芥槸甯﹀叕寮忕殑缁勫悕銆�
+ * 鐣欎笅鐨勬伆濂芥槸杩囩▼鍙傛暟锛夛紝涓嶉潬琛屽簭锛堣琛ㄩ噷缁勫ご涓庡畠鐨勫瓙椤瑰苟涓嶇浉閭伙級锛屼篃涓嶆妸缁勫ご涓㈡帀
+ * 锛堢粍鍚嶄笌鍏紡鏄垎缁勬楠岄」鏈�涓嶈涓㈢殑涓ゆ牱涓滆タ锛夈��
+ */
+ private BuiltItems buildItems(Long qcId, Integer qcType, List<LineRow> lines,
+ Map<Long, MesMdUnitMeasureDO> unitMap, MesMdItemDO item) {
+ if (CollUtil.isEmpty(lines)) {
+ return new BuiltItems(Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), 0);
+ }
+ Map<Long, MesQcIndicatorDO> indicatorMap = indicatorService.getIndicatorMap(
+ convertSet(lines, LineRow::indicatorId));
+ // 鏍峰搧 鈫� 璇ユ牱鍝佺殑瀹炴祴鍊兼槑缁�
+ Map<Long, List<MesQcIndicatorResultDetailDO>> detailMap = Collections.emptyMap();
+ List<MesQcIndicatorResultDO> samples = indicatorResultService.getIndicatorResultListByQcIdAndType(qcId, qcType);
+ if (CollUtil.isNotEmpty(samples)) {
+ List<MesQcIndicatorResultDetailDO> details = indicatorResultService.getIndicatorResultDetailListByResultIds(
+ new ArrayList<>(convertSet(samples, MesQcIndicatorResultDO::getId)));
+ detailMap = new LinkedHashMap<>();
+ for (MesQcIndicatorResultDetailDO detail : details) {
+ detailMap.computeIfAbsent(detail.getResultId(), k -> new ArrayList<>()).add(detail);
+ }
+ }
+
+ // 鈶� 琛� 鈫� 鎸囨爣锛涙寚鏍囪鍒犳帀鐨勮杩樺師涓嶅嚭浠讳綍涓滆タ锛屽彧璁℃暟
+ List<LineRow> liveLines = new ArrayList<>(lines.size());
+ List<MesQcIndicatorDO> liveIndicators = new ArrayList<>(lines.size());
+ int missingIndicatorCount = 0;
+ for (LineRow line : lines) {
+ MesQcIndicatorDO indicator = indicatorMap.get(line.indicatorId());
+ if (indicator == null) {
+ missingIndicatorCount++;
+ continue;
+ }
+ liveLines.add(line);
+ liveIndicators.add(indicator);
+ }
+
+ // 鈶� 缁勫ご鎸囨爣鍙兘鍘嬫牴娌℃帓杩涙湰鍗曪紙妯℃澘鍙�変簡瀛愰」锛夛紝琛ュ彇鍑烘潵锛屽惁鍒欐暣缁勭殑缁勫悕涓庡叕寮忎細涓�
+ Map<Long, MesQcIndicatorDO> allIndicators = new LinkedHashMap<>(indicatorMap);
+ Set<Long> extraIds = new LinkedHashSet<>();
+ for (MesQcIndicatorDO indicator : liveIndicators) {
+ Long parentId = indicator.getParentId();
+ if (parentId != null && parentId != 0 && !allIndicators.containsKey(parentId)) {
+ extraIds.add(parentId);
+ }
+ }
+ if (CollUtil.isNotEmpty(extraIds)) {
+ allIndicators.putAll(indicatorService.getIndicatorMap(extraIds));
+ }
+
+ // 鈶� 姣忎竴琛屽綊鍒般�岀粍澶磋嚜宸辩殑琛屻�嶆垨銆屾煇涓粍鐨勫瓙椤硅銆�
+ Map<Long, List<Integer>> ownLinesOf = new LinkedHashMap<>();
+ Map<Long, List<Integer>> childLinesOf = new LinkedHashMap<>();
+ for (int i = 0; i < liveLines.size(); i++) {
+ Long headId = groupHeadId(liveIndicators.get(i), allIndicators);
+ if (headId == null) {
+ ownLinesOf.computeIfAbsent(liveLines.get(i).indicatorId(), k -> new ArrayList<>()).add(i);
+ } else {
+ childLinesOf.computeIfAbsent(headId, k -> new ArrayList<>()).add(i);
+ }
+ }
+
+ // 鈶� 椤跺眰鏉$洰 = 缁� + 鐙珛椤癸紱缁勫ご閭d竴琛屼粠鐙珛椤归噷鎽樺嚭鏉ュ綋浣滅粍鐨勯敋鐐硅
+ List<String> childlessGroupNames = new ArrayList<>();
+ List<String> synthesizedGroupNames = new ArrayList<>();
+ List<Entry> entries = new ArrayList<>();
+ for (Map.Entry<Long, List<Integer>> each : childLinesOf.entrySet()) {
+ Long headId = each.getKey();
+ MesQcIndicatorDO head = allIndicators.get(headId);
+ List<Integer> children = sortByIndicatorOrder(each.getValue(), liveIndicators);
+ List<Integer> own = ownLinesOf.remove(headId);
+ if (CollUtil.isEmpty(own)) {
+ synthesizedGroupNames.add(defaultStr(head.getName()));
+ }
+ entries.add(new Entry(head, own == null ? Collections.emptyList() : own, children,
+ children.get(0)));
+ }
+ for (Map.Entry<Long, List<Integer>> each : ownLinesOf.entrySet()) {
+ MesQcIndicatorDO indicator = allIndicators.get(each.getKey());
+ if (MesQcIndicatorItemTypeEnum.isGroup(indicator.getItemType())) {
+ // 鎸囨爣涓绘暟鎹噷鏄垎缁勯」锛屾湰鍗曞嵈娌℃湁灞炰簬瀹冪殑瀛愰」锛氱収甯稿嚭鎴愮嫭绔嬫楠岄」锛屽彧鏄粍涓嶈捣鏉�
+ childlessGroupNames.add(defaultStr(indicator.getName()));
+ }
+ entries.add(new Entry(indicator, each.getValue(), Collections.emptyList(), each.getValue().get(0)));
+ }
+ // 鎺掑簭鍙风己澶辩殑鎺掓渶鍚庯紱鍚屽�间繚鎸佽搴忥紙List.sort 绋冲畾锛屾瘮杈冮敭閲屽啀甯︿笂棣栬涓嬫爣鍏滃簳锛�
+ entries.sort(Comparator.comparingInt((Entry entry) -> sortKey(entry.indicator()))
+ .thenComparingInt(Entry::firstLine));
+
+ // 鈶� 閫愭潯鐩骇鍑鸿锛屽苟鎶婂垎缁勪俊鎭笅鍙戝埌姣忎竴琛�
+ List<MesQcReportItemRespDTO> items = new ArrayList<>();
+ int index = 0;
+ for (Entry entry : entries) {
+ List<MesQcReportItemRespDTO> groupRows = new ArrayList<>();
+ for (Integer lineIndex : entry.ownLines()) {
+ groupRows.addAll(expandRows(liveIndicators.get(lineIndex), liveLines.get(lineIndex),
+ samples, detailMap, unitMap, item));
+ }
+ boolean grouped = CollUtil.isNotEmpty(entry.childLines());
+ if (grouped && groupRows.isEmpty()) {
+ // 缁勫ご娌℃湁鑷繁鐨勮锛氳ˉ涓�琛岋紝鍚﹀垯缁勫悕涓庡叕寮忔棤澶勫彲鏀�
+ groupRows.add(toItem(entry.indicator(), emptyLine(entry.indicator()), "", "", "", unitMap, item));
+ }
+ int anchorCount = groupRows.size();
+ List<MesQcReportItemRespDTO> entryRows = new ArrayList<>(groupRows);
+ for (Integer lineIndex : entry.childLines()) {
+ for (MesQcReportItemRespDTO row : expandRows(liveIndicators.get(lineIndex), liveLines.get(lineIndex),
+ samples, detailMap, unitMap, item)) {
+ row.setGroupChildName(defaultStr(liveIndicators.get(lineIndex).getName()));
+ entryRows.add(row);
+ }
+ }
+ int span = grouped ? entryRows.size() : 1;
+ for (int i = 0; i < entryRows.size(); i++) {
+ MesQcReportItemRespDTO row = entryRows.get(i);
+ row.setIndex(++index);
+ // 缁勫悕鐨勫悎骞舵牸鍙寕鍦ㄧ粍鐨勭涓�琛岋紝缁勫唴鍏朵綑琛屾暣鏍奸殣钘忋�佽浣嶇粰瀹�
+ row.setGroupSpan(i == 0 ? span : 1);
+ row.setGroupHidden(i == 0 ? "" : GROUP_CELL_HIDDEN);
+ row.setRequirement(i < anchorCount
+ ? anchorRequirement(entry.indicator(), row)
+ : defaultStr(row.getStandardValue()));
+ items.add(row);
+ }
+ }
+ return new BuiltItems(items, childlessGroupNames, synthesizedGroupNames, missingIndicatorCount);
+ }
+
+ /** 瑁呴厤缁撴灉锛氭楠岄」鏈韩锛屼互鍙婃病鑳芥垚缁勩�佽琛ヤ簡琛岃�屽繀椤昏璋冪敤鏂圭煡閬撶殑閭d簺 */
+ private record BuiltItems(List<MesQcReportItemRespDTO> items, List<String> childlessGroupNames,
+ List<String> synthesizedGroupNames, int missingIndicatorCount) {
+ }
+
+ /**
+ * 涓�涓《灞傛潯鐩細涓�涓垎缁勶紙缁勫ご鎸囨爣 + 瀹冪殑瀛愰」琛岋級锛屾垨涓�涓嫭绔嬫楠岄」銆�
+ *
+ * @param indicator 缁勫ご鐨勬寚鏍� / 鐙珛椤圭殑鎸囨爣
+ * @param ownLines 缁勫ご鑷繁閭d簺琛岋紙鐙珛椤规椂灏辨槸瀹冨叏閮ㄧ殑琛岋級鍦ㄨ琛ㄩ噷鐨勪笅鏍�
+ * @param childLines 缁勫唴瀛愰」琛岀殑涓嬫爣锛岀嫭绔嬮」鎭掍负绌�
+ * @param firstLine 鏉$洰绗竴琛屽湪琛岃〃閲岀殑涓嬫爣锛屾帓搴忓彿鐩稿悓鏃堕潬瀹冧繚鎸佽搴�
+ */
+ private record Entry(MesQcIndicatorDO indicator, List<Integer> ownLines, List<Integer> childLines,
+ int firstLine) {
+ }
+
+ /**
+ * 杩欎竴琛岀殑缁勫ご鎸囨爣缂栧彿锛歿@code parent_id} 鎸囧悜涓�涓�屽垎缁勯」銆嶆墠绠楁暟銆�
+ * <p>
+ * 鎸囧悜褰曞叆椤瑰睘浜庢寚鏍囦富鏁版嵁閰嶇疆鏈夐棶棰橈紝涓嶈兘鎷垮畠鍘诲悎骞跺崟鍏冩牸锛�
+ * 鎸囧悜鐨勬寚鏍囧凡琚垹闄ゅ悓鏍蜂笉鎴愮粍銆�
+ */
+ private static Long groupHeadId(MesQcIndicatorDO indicator, Map<Long, MesQcIndicatorDO> allIndicators) {
+ Long parentId = indicator.getParentId();
+ if (parentId == null || parentId == 0) {
+ return null;
+ }
+ MesQcIndicatorDO head = allIndicators.get(parentId);
+ return head != null && MesQcIndicatorItemTypeEnum.isGroup(head.getItemType()) ? parentId : null;
+ }
+
+ /** 缁勫ご鐨勩�屾娴嬭姹傘�嶆斁鍏紡锛堝垎缁勯」鍙湁鍏紡銆佹病鏈夎鏍硷級锛屾病閰嶅叕寮忓氨鐓у父鏀炬爣鍑嗚姹� */
+ private static String anchorRequirement(MesQcIndicatorDO head, MesQcReportItemRespDTO row) {
+ String formula = defaultStr(head.getFormulaText());
+ return formula.isEmpty() ? defaultStr(row.getStandardValue()) : formula;
+ }
+
+ /** 缁勫ご娌℃帓杩涙湰鍗曟椂琛ュ嚭鏉ョ殑閭d竴琛岋細鍙湁鎸囨爣鏈韩锛屾病鏈夊崟鎹 */
+ private static LineRow emptyLine(MesQcIndicatorDO head) {
+ return new LineRow(head.getId(), head.getTool(), null, null, null, null, null, null);
+ }
+
+ /**
+ * 涓�涓楠岄」鎽婂钩鎴愯嫢骞茶锛氬鏍峰搧銆佷竴涓寚鏍囪褰曚簡澶氭瀹炴祴鍊奸兘浼氭憡骞炽��
+ * 涓�琛岄兘娌℃湁锛堝皻鏈綍鍏ュ疄娴嬪�硷級鏃朵粛鍑轰竴琛岋紝閬垮厤鎶ュ憡婕忛」銆�
+ */
+ private List<MesQcReportItemRespDTO> expandRows(MesQcIndicatorDO indicator, LineRow line,
+ List<MesQcIndicatorResultDO> samples,
+ Map<Long, List<MesQcIndicatorResultDetailDO>> detailMap,
+ Map<Long, MesMdUnitMeasureDO> unitMap, MesMdItemDO item) {
+ List<MesQcReportItemRespDTO> rows = new ArrayList<>();
+ for (MesQcIndicatorResultDO sample : samples) {
+ for (MesQcIndicatorResultDetailDO detail : detailMap.getOrDefault(sample.getId(),
+ Collections.emptyList())) {
+ if (Objects.equals(detail.getIndicatorId(), line.indicatorId())) {
+ rows.add(toItem(indicator, line, sample.getCode(), detail.getValue(), detail.getRemark(),
+ unitMap, item));
+ }
+ }
+ }
+ if (rows.isEmpty()) {
+ rows.add(toItem(indicator, line, "", "", "", unitMap, item));
+ }
+ return rows;
+ }
+
+ /** 鎺掑簭閿細鎸囨爣娌¤鎺掑簭鍙风殑涓�寰嬫帓鏈�鍚� */
+ private static int sortKey(MesQcIndicatorDO indicator) {
+ Integer sortOrder = indicator.getSortOrder();
+ return sortOrder == null ? Integer.MAX_VALUE : sortOrder;
+ }
+
+ /** 鎸夊悇琛岀殑鎸囨爣鎺掑簭鍙锋帓锛屽悓鍊间繚鎸佽搴� */
+ private static List<Integer> sortByIndicatorOrder(List<Integer> lineIndexes,
+ List<MesQcIndicatorDO> indicators) {
+ List<Integer> sorted = new ArrayList<>(lineIndexes);
+ sorted.sort(Comparator.comparingInt((Integer i) -> sortKey(indicators.get(i)))
+ .thenComparingInt(Integer::intValue));
+ return sorted;
+ }
+
+ private MesQcReportItemRespDTO toItem(MesQcIndicatorDO indicator, LineRow line, String sampleCode, String value,
+ String detailRemark, Map<Long, MesMdUnitMeasureDO> unitMap,
+ MesMdItemDO item) {
+ MesMdUnitMeasureDO unit = unitMap.get(line.unitMeasureId());
+ if (unit == null && item != null) {
+ unit = unitMap.get(item.getUnitMeasureId());
+ }
+ return new MesQcReportItemRespDTO()
+ .setIndicatorId(indicator.getId())
+ .setIndicatorCode(defaultStr(indicator.getCode()))
+ .setIndicatorName(defaultStr(indicator.getName()))
+ .setCheckMethod(defaultStr(line.checkMethod()))
+ .setTool(defaultStr(line.tool()))
+ .setStandardValue(plain(line.standardValue()))
+ .setActualValue(defaultStr(value))
+ .setUnit(unit == null ? "" : defaultStr(unit.getName()))
+ .setUpperLimit(line.maxThreshold())
+ .setLowerLimit(line.minThreshold())
+ .setValueType(indicator.getResultType())
+ .setValueTypeName(valueTypeName(indicator.getResultType()))
+ .setSampleNo(defaultStr(sampleCode))
+ // 榛樿銆屼笉鏄瓙椤广�佷笉鍙備笌鍚堝苟銆嶏紱鐪熷瓙椤圭敱瑁呴厤閭d竴姝ユ敼鍐�
+ .setGroupChildName("")
+ .setGroupSpan(1)
+ .setGroupHidden("")
+ .setRemark(mergeRemark(line.remark(), detailRemark));
+ }
+
+ // ==================== 鍙栬锛堝洓绫诲悓鏋勶級 ====================
+
+ private List<LineRow> loadIqcLines(Long qcId) {
+ List<MesQcIqcLineDO> lines = iqcLineService.getIqcLineListByIqcId(qcId);
+ if (CollUtil.isEmpty(lines)) {
+ return Collections.emptyList();
+ }
+ List<LineRow> rows = new ArrayList<>(lines.size());
+ for (MesQcIqcLineDO l : lines) {
+ rows.add(new LineRow(l.getIndicatorId(), l.getTool(), l.getCheckMethod(), l.getStandardValue(),
+ l.getUnitMeasureId(), l.getMaxThreshold(), l.getMinThreshold(), l.getRemark()));
+ }
+ return rows;
+ }
+
+ private List<LineRow> loadIpqcLines(Long qcId) {
+ List<MesQcIpqcLineDO> lines = ipqcLineService.getIpqcLineListByIpqcId(qcId);
+ if (CollUtil.isEmpty(lines)) {
+ return Collections.emptyList();
+ }
+ List<LineRow> rows = new ArrayList<>(lines.size());
+ for (MesQcIpqcLineDO l : lines) {
+ rows.add(new LineRow(l.getIndicatorId(), l.getTool(), l.getCheckMethod(), l.getStandardValue(),
+ l.getUnitMeasureId(), l.getMaxThreshold(), l.getMinThreshold(), l.getRemark()));
+ }
+ return rows;
+ }
+
+ private List<LineRow> loadOqcLines(Long qcId) {
+ List<MesQcOqcLineDO> lines = oqcLineService.getOqcLineListByOqcId(qcId);
+ if (CollUtil.isEmpty(lines)) {
+ return Collections.emptyList();
+ }
+ List<LineRow> rows = new ArrayList<>(lines.size());
+ for (MesQcOqcLineDO l : lines) {
+ rows.add(new LineRow(l.getIndicatorId(), l.getTool(), l.getCheckMethod(), l.getStandardValue(),
+ l.getUnitMeasureId(), l.getMaxThreshold(), l.getMinThreshold(), l.getRemark()));
+ }
+ return rows;
+ }
+
+ private List<LineRow> loadRqcLines(Long qcId) {
+ List<MesQcRqcLineDO> lines = rqcLineService.getRqcLineListByRqcId(qcId);
+ if (CollUtil.isEmpty(lines)) {
+ return Collections.emptyList();
+ }
+ List<LineRow> rows = new ArrayList<>(lines.size());
+ for (MesQcRqcLineDO l : lines) {
+ rows.add(new LineRow(l.getIndicatorId(), l.getTool(), l.getCheckMethod(), l.getStandardValue(),
+ l.getUnitMeasureId(), l.getMaxThreshold(), l.getMinThreshold(), l.getRemark()));
+ }
+ return rows;
+ }
+
+ // ==================== 鍏宠仈鍚嶇О ====================
+
+ private Map<Long, MesMdUnitMeasureDO> unitMapOf(List<LineRow> lines, MesMdItemDO item) {
+ List<Long> unitIds = new ArrayList<>();
+ for (LineRow line : lines) {
+ if (line.unitMeasureId() != null) {
+ unitIds.add(line.unitMeasureId());
+ }
+ }
+ if (item != null && item.getUnitMeasureId() != null) {
+ unitIds.add(item.getUnitMeasureId());
+ }
+ return unitIds.isEmpty() ? Collections.emptyMap() : unitMeasureService.getUnitMeasureMap(unitIds);
+ }
+
+ private String supplierName(Long vendorId) {
+ if (vendorId == null) {
+ return "";
+ }
+ List<SrmSupplierRespDTO> suppliers = srmSupplierApi.getSupplierList(Collections.singleton(vendorId))
+ .getCheckedData();
+ return CollUtil.isEmpty(suppliers) ? "" : defaultStr(suppliers.get(0).getName());
+ }
+
+ private String clientName(Long clientId) {
+ if (clientId == null) {
+ return "";
+ }
+ CrmCustomerRespDTO client = customerApi.getCustomerMap(Collections.singleton(clientId)).get(clientId);
+ return client == null ? "" : defaultStr(client.getName());
+ }
+
+ private String workOrderCode(Long workOrderId) {
+ if (workOrderId == null) {
+ return "";
+ }
+ MesProWorkOrderDO workOrder = workOrderService.getWorkOrder(workOrderId);
+ return workOrder == null ? "" : defaultStr(workOrder.getCode());
+ }
+
+ private String userName(Long userId) {
+ if (userId == null) {
+ return "";
+ }
+ AdminUserRespDTO user = adminUserApi.getUserMap(Collections.singleton(userId)).get(userId);
+ return user == null ? "" : defaultStr(user.getNickname());
+ }
+
+ // ==================== 灏忓伐鍏� ====================
+
+ /** 鍘绘帀鏃犳剰涔夌殑灏忔暟灏鹃浂锛岄伩鍏嶆姤鍛婇噷鍑虹幇 5.0000 杩欑鐢辨暟鎹簱绮惧害甯﹀嚭鏉ョ殑灏惧反 */
+ private static String plain(BigDecimal value) {
+ return value == null ? "" : value.stripTrailingZeros().toPlainString();
+ }
+
+ private static String mergeRemark(String lineRemark, String detailRemark) {
+ if (StrUtil.isBlank(lineRemark)) {
+ return defaultStr(detailRemark);
+ }
+ return StrUtil.isBlank(detailRemark) ? lineRemark : lineRemark + "锛�" + detailRemark;
+ }
+
+ private static String defaultStr(String value) {
+ return value == null ? "" : value;
+ }
+
+ private static String qcTypeName(Integer qcType) {
+ for (MesQcTypeEnum e : MesQcTypeEnum.values()) {
+ if (Objects.equals(e.getType(), qcType)) {
+ return e.getName();
+ }
+ }
+ return "";
+ }
+
+ private static String statusName(Integer status) {
+ for (MesQcStatusEnum e : MesQcStatusEnum.values()) {
+ if (Objects.equals(e.getStatus(), status)) {
+ return e.getName();
+ }
+ }
+ return "";
+ }
+
+ private static String checkResultName(Integer checkResult) {
+ for (MesQcCheckResultEnum e : MesQcCheckResultEnum.values()) {
+ if (Objects.equals(e.getType(), checkResult)) {
+ return e.getName();
+ }
+ }
+ return "";
+ }
+
+ private static String valueTypeName(Integer resultType) {
+ for (MesQcResultValueTypeEnum e : MesQcResultValueTypeEnum.values()) {
+ if (Objects.equals(e.getType(), resultType)) {
+ return e.getName();
+ }
+ }
+ return "";
+ }
+
+ /** 鍥涚被琛岃〃瀛楁瀹屽叏涓�鑷达紝鎶芥垚缁熶竴褰㈡�佸悗鍏辩敤鏄犲皠 */
+ private record LineRow(Long indicatorId, String tool, String checkMethod, BigDecimal standardValue,
+ Long unitMeasureId, BigDecimal maxThreshold, BigDecimal minThreshold, String remark) {
+ }
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/indicator/MesQcIndicatorController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/indicator/MesQcIndicatorController.java
index 14f49fe..b7d2e0b 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/indicator/MesQcIndicatorController.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/indicator/MesQcIndicatorController.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.mes.controller.admin.qc.indicator;
+import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
@@ -23,9 +24,13 @@
import java.io.IOException;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
@Tag(name = "绠$悊鍚庡彴 - MES 璐ㄦ鎸囨爣")
@RestController
@@ -74,7 +79,17 @@
@PreAuthorize("@ss.hasPermission('mes:qc-indicator:query')")
public CommonResult<PageResult<MesQcIndicatorRespVO>> getIndicatorPage(@Valid MesQcIndicatorPageReqVO pageReqVO) {
PageResult<MesQcIndicatorDO> pageResult = indicatorService.getIndicatorPage(pageReqVO);
- return success(BeanUtils.toBean(pageResult, MesQcIndicatorRespVO.class));
+ PageResult<MesQcIndicatorRespVO> voPageResult = BeanUtils.toBean(pageResult, MesQcIndicatorRespVO.class);
+ fillParentName(voPageResult.getList());
+ return success(voPageResult);
+ }
+
+ @GetMapping("/group-list")
+ @Operation(summary = "鑾峰緱鍒嗙粍椤圭簿绠�鍒楄〃", description = "鍙寘鍚垎缁勯」锛屼富瑕佺敤浜庛�屾墍灞炲垎缁勩�嶇殑涓嬫媺閫夐」")
+ @PreAuthorize("@ss.hasPermission('mes:qc-indicator:query')")
+ public CommonResult<List<MesQcIndicatorRespVO>> getIndicatorGroupList() {
+ List<MesQcIndicatorDO> list = indicatorService.getIndicatorGroupList();
+ return success(BeanUtils.toBean(list, MesQcIndicatorRespVO.class));
}
@GetMapping("/export-excel")
@@ -85,9 +100,25 @@
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<MesQcIndicatorDO> list = indicatorService.getIndicatorPage(pageReqVO).getList();
+ // 缁勮瀵煎嚭 VO锛堣ˉ榻愭墍灞炲垎缁勫悕绉帮級
+ List<MesQcIndicatorRespVO> excelList = BeanUtils.toBean(list, MesQcIndicatorRespVO.class);
+ fillParentName(excelList);
// 瀵煎嚭 Excel
- ExcelUtils.write(response, "璐ㄦ鎸囨爣.xls", "鏁版嵁", MesQcIndicatorRespVO.class,
- BeanUtils.toBean(list, MesQcIndicatorRespVO.class));
+ ExcelUtils.write(response, "璐ㄦ鎸囨爣.xls", "鏁版嵁", MesQcIndicatorRespVO.class, excelList);
+ }
+
+ /**
+ * 鍥炲~銆屾墍灞炲垎缁勩�嶅悕绉般�傜埗鎸囨爣鍙兘涓嶅湪褰撳墠椤碉紙鐢氳嚦涓嶅湪绛涢�夌粨鏋滃唴锛夛紝鎵�浠ュ崟鐙寜 id 鎵归噺鍙栦竴娆�
+ */
+ private void fillParentName(List<MesQcIndicatorRespVO> list) {
+ Set<Long> parentIds = convertSet(list, MesQcIndicatorRespVO::getParentId,
+ vo -> vo.getParentId() != null && !MesQcIndicatorDO.PARENT_ID_ROOT.equals(vo.getParentId()));
+ if (CollUtil.isEmpty(parentIds)) {
+ return;
+ }
+ Map<Long, String> parentNameMap = convertMap(indicatorService.getIndicatorList(parentIds),
+ MesQcIndicatorDO::getId, MesQcIndicatorDO::getName);
+ list.forEach(vo -> vo.setParentName(parentNameMap.get(vo.getParentId())));
}
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/indicator/vo/MesQcIndicatorPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/indicator/vo/MesQcIndicatorPageReqVO.java
index ff92db5..12b9f55 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/indicator/vo/MesQcIndicatorPageReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/indicator/vo/MesQcIndicatorPageReqVO.java
@@ -24,4 +24,7 @@
@Schema(description = "缁撴灉鍊肩被鍨�", example = "1")
private Integer resultType;
+ @Schema(description = "鏉$洰绫诲瀷锛�1=褰曞叆椤癸紝2=鍒嗙粍椤�", example = "2")
+ private Integer itemType;
+
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/indicator/vo/MesQcIndicatorRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/indicator/vo/MesQcIndicatorRespVO.java
index f3f5995..4ac6bf0 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/indicator/vo/MesQcIndicatorRespVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/indicator/vo/MesQcIndicatorRespVO.java
@@ -36,7 +36,25 @@
@ExcelProperty("妫�娴嬪伐鍏�")
private String tool;
- @Schema(description = "缁撴灉鍊肩被鍨�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @Schema(description = "鏉$洰绫诲瀷锛�1=褰曞叆椤癸紝2=鍒嗙粍椤�", example = "1")
+ private Integer itemType;
+
+ @Schema(description = "鐖舵寚鏍囩紪鍙凤紙0=椤剁骇锛�", example = "0")
+ private Long parentId;
+
+ @Schema(description = "鐖舵寚鏍囧悕绉帮紙鍗虫墍灞炲垎缁勫悕锛岄《绾ф椂涓虹┖锛�", example = "姘村垎")
+ @ExcelProperty("鎵�灞炲垎缁�")
+ private String parentName;
+
+ @Schema(description = "鍏紡灞曠ず鏂囨湰锛堝垎缁勯」鐨勩�屾娴嬭姹傘�嶅氨鏄繖鏉″叕寮忥級", example = "w = (m1 - m0) / m 脳 100%")
+ @ExcelProperty("鍏紡")
+ private String formulaText;
+
+ @Schema(description = "鍚岀骇鎺掑簭鍙�", example = "10")
+ @ExcelProperty("鎺掑簭鍙�")
+ private Integer sortOrder;
+
+ @Schema(description = "缁撴灉鍊肩被鍨嬨�傚垎缁勯」娌℃湁缁撴灉鍊硷紝鍙负绌�", example = "1")
@ExcelProperty(value = "缁撴灉鍊肩被鍨�", converter = DictConvert.class)
@DictFormat(DictTypeConstants.MES_QC_RESULT_TYPE)
private Integer resultType;
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/indicator/vo/MesQcIndicatorSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/indicator/vo/MesQcIndicatorSaveReqVO.java
index d7fa865..d83957c 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/indicator/vo/MesQcIndicatorSaveReqVO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/indicator/vo/MesQcIndicatorSaveReqVO.java
@@ -27,8 +27,19 @@
@Schema(description = "妫�娴嬪伐鍏�", example = "鍗″昂")
private String tool;
- @Schema(description = "缁撴灉鍊肩被鍨�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
- @NotNull(message = "缁撴灉鍊肩被鍨嬩笉鑳戒负绌�")
+ @Schema(description = "鏉$洰绫诲瀷锛�1=褰曞叆椤癸紝2=鍒嗙粍椤�", example = "1")
+ private Integer itemType;
+
+ @Schema(description = "鐖舵寚鏍囩紪鍙凤紙0=椤剁骇锛�", example = "0")
+ private Long parentId;
+
+ @Schema(description = "鍏紡灞曠ず鏂囨湰锛堝垎缁勯」鐨勩�屾娴嬭姹傘�嶅氨鏄繖鏉″叕寮忥級", example = "w = (m1 - m0) / m 脳 100%")
+ private String formulaText;
+
+ @Schema(description = "鍚岀骇鎺掑簭鍙凤紝鐣欑┖鍒欒嚜鍔ㄦ帓鍒板悓绾ф湯灏�", example = "10")
+ private Integer sortOrder;
+
+ @Schema(description = "缁撴灉鍊肩被鍨嬨�傚垎缁勯」娌℃湁缁撴灉鍊硷紝鍙笉濉�", example = "1")
private Integer resultType;
@Schema(description = "缁撴灉鍊煎睘鎬�", example = "IMG")
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/indicator/MesQcIndicatorDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/indicator/MesQcIndicatorDO.java
index b4c72e4..8695516 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/indicator/MesQcIndicatorDO.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/indicator/MesQcIndicatorDO.java
@@ -1,7 +1,9 @@
package cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicator;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
@@ -22,6 +24,8 @@
@AllArgsConstructor
public class MesQcIndicatorDO extends BaseDO {
+ public static final Long PARENT_ID_ROOT = 0L;
+
/**
* 缂栧彿
*/
@@ -35,6 +39,35 @@
* 妫�娴嬮」鍚嶇О
*/
private String name;
+ /**
+ * 鐖舵寚鏍囩紪鍙凤紙0=椤剁骇锛�
+ *
+ * 鎶ュ憡渚ч潬瀹冭繕鍘熴�岀粍鍚嶅悎骞躲�佸瓙椤瑰垎琛屻�嶇殑涓ゅ眰缁撴瀯 鈥斺�� 褰掑睘鍙湅杩欎釜瀛楁锛�
+ * 涓嶇湅 {@link #type}銆佷篃涓嶇湅琛屽簭锛堣琛ㄩ噷鐖堕」閭d竴琛屼笌瀹冪殑瀛愰」骞朵笉鐩搁偦锛夈��
+ */
+ private Long parentId;
+ /**
+ * 鏉$洰绫诲瀷锛�1=褰曞叆椤癸紝2=鍒嗙粍椤�
+ *
+ * 鍙敤鏉ュ垽鏂�岃繖涓寚鏍囧涓嶅鏍煎綋缁勫ご銆嶏紝褰掑睘鏈韩浠嶇湅 {@link #parentId}
+ */
+ private Integer itemType;
+ /**
+ * 鍏紡灞曠ず鏂囨湰锛堟墦鍗版姤鍛婄敤锛屼笉鍙備笌璁$畻锛�
+ *
+ * 鍒嗙粍椤规病鏈夎鏍间笂涓嬮檺锛屽畠鐨勩�屾娴嬭姹傘�嶅氨鏄繖鏉″叕寮�
+ */
+ private String formulaText;
+ /**
+ * 鍗曚綅鏂囨湰锛堝 kg/m鲁銆�/%锛屾墦鍗板睍绀虹敤锛�
+ */
+ private String unitText;
+ /**
+ * 鍚岀骇鎺掑簭鍙�
+ *
+ * 鎶ュ憡鐨勬楠岄」椤哄簭鎸夊畠鎺掞細鍒嗙粍椤逛笌鐙珛椤瑰悓灞炪�屽悓绾с�嶅崰涓�涓綅缃紝缁勫唴瀛愰」鍚勮嚜鍐嶆帓
+ */
+ private Integer sortOrder;
/**
* 妫�娴嬮」绫诲瀷
*
@@ -50,14 +83,21 @@
*
* 瀛楀吀 {@link DictTypeConstants#MES_QC_RESULT_TYPE}
* 鏋氫妇 {@link cn.iocoder.yudao.module.mes.enums.qc.MesQcResultValueTypeEnum}
+ *
+ * updateStrategy=ALWAYS锛氬綍鍏ラ」鏀规垚鍒嗙粍椤规椂瑕佽兘鎶婅繖涓�煎啓鍥� NULL锛�
+ * 榛樿鐨� NOT_NULL 绛栫暐浼氭妸 null 瀛楁浠� UPDATE 閲屽墧闄わ紝瀵艰嚧鏃х殑缁撴灉鍊兼畫鐣�
*/
+ @TableField(updateStrategy = FieldStrategy.ALWAYS)
private Integer resultType;
/**
* 缁撴灉鍊煎睘鎬�
*
* 1. FILE 鏃讹細瀛� IMG/FILE
* 2. DICT 鏃讹細瀛樺瓧鍏哥被鍨嬪悕
+ *
+ * updateStrategy 鍚� {@link #resultType}
*/
+ @TableField(updateStrategy = FieldStrategy.ALWAYS)
private String resultSpecification;
/**
* 澶囨敞
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/indicator/MesQcIndicatorMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/indicator/MesQcIndicatorMapper.java
index 5c37909..406d9c1 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/indicator/MesQcIndicatorMapper.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/indicator/MesQcIndicatorMapper.java
@@ -8,6 +8,7 @@
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
+import java.util.Objects;
/**
* MES 璐ㄦ鎸囨爣 Mapper
@@ -23,6 +24,7 @@
.likeIfPresent(MesQcIndicatorDO::getName, reqVO.getName())
.eqIfPresent(MesQcIndicatorDO::getType, reqVO.getType())
.eqIfPresent(MesQcIndicatorDO::getResultType, reqVO.getResultType())
+ .eqIfPresent(MesQcIndicatorDO::getItemType, reqVO.getItemType())
.orderByDesc(MesQcIndicatorDO::getId));
}
@@ -39,4 +41,34 @@
.orderByDesc(MesQcIndicatorDO::getId));
}
+ default List<MesQcIndicatorDO> selectListByItemType(Integer itemType) {
+ return selectList(new LambdaQueryWrapperX<MesQcIndicatorDO>()
+ .eq(MesQcIndicatorDO::getItemType, itemType)
+ .orderByAsc(MesQcIndicatorDO::getSortOrder)
+ .orderByAsc(MesQcIndicatorDO::getId));
+ }
+
+ default List<MesQcIndicatorDO> selectListByParentId(Long parentId) {
+ return selectList(new LambdaQueryWrapperX<MesQcIndicatorDO>()
+ .eq(MesQcIndicatorDO::getParentId, parentId)
+ .orderByAsc(MesQcIndicatorDO::getSortOrder)
+ .orderByAsc(MesQcIndicatorDO::getId));
+ }
+
+ default Long selectCountByParentId(Long parentId) {
+ return selectCount(new LambdaQueryWrapperX<MesQcIndicatorDO>()
+ .eq(MesQcIndicatorDO::getParentId, parentId));
+ }
+
+ /**
+ * 鍙栧悓绾ф渶澶х殑鎺掑簭鍙凤紱鍚岀骇娌℃湁璁板綍鏃惰繑鍥� null
+ */
+ default Integer selectMaxSortOrder(Long parentId) {
+ return selectListByParentId(parentId).stream()
+ .map(MesQcIndicatorDO::getSortOrder)
+ .filter(Objects::nonNull)
+ .max(Integer::compareTo)
+ .orElse(null);
+ }
+
}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
index 34ddf34..d93fca2 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
@@ -372,6 +372,12 @@
ErrorCode QC_INDICATOR_CODE_DUPLICATE = new ErrorCode(1_040_601_001, "璐ㄦ鎸囨爣缂栫爜宸插瓨鍦�");
ErrorCode QC_INDICATOR_NAME_DUPLICATE = new ErrorCode(1_040_601_002, "璐ㄦ鎸囨爣鍚嶇О宸插瓨鍦�");
ErrorCode QC_INDICATOR_RESULT_SPECIFICATION_REQUIRED = new ErrorCode(1_040_601_003, "缁撴灉鍊煎睘鎬т笉鑳戒负绌�");
+ ErrorCode QC_INDICATOR_PARENT_NOT_EXISTS = new ErrorCode(1_040_601_004, "鐖舵寚鏍囦笉瀛樺湪");
+ ErrorCode QC_INDICATOR_PARENT_NOT_GROUP = new ErrorCode(1_040_601_005, "鐖舵寚鏍囦笉鏄垎缁勯」");
+ ErrorCode QC_INDICATOR_PARENT_SELF = new ErrorCode(1_040_601_006, "鐖舵寚鏍囦笉鑳芥槸鑷繁");
+ ErrorCode QC_INDICATOR_GROUP_CANNOT_NEST = new ErrorCode(1_040_601_007, "鍒嗙粍椤逛笉鑳芥寕鍦ㄥ叾瀹冩寚鏍囦笅");
+ ErrorCode QC_INDICATOR_HAS_CHILDREN = new ErrorCode(1_040_601_008, "璇ユ寚鏍囦笅宸叉湁瀛愰」");
+ ErrorCode QC_INDICATOR_RESULT_TYPE_REQUIRED = new ErrorCode(1_040_601_009, "褰曞叆椤圭殑缁撴灉鍊肩被鍨嬩笉鑳戒负绌�");
// ========== MES 璐ㄩ噺绠$悊-缂洪櫡绫诲瀷锛�1-040-602-000锛� ==========
ErrorCode QC_DEFECT_NOT_EXISTS = new ErrorCode(1_040_602_000, "缂洪櫡绫诲瀷涓嶅瓨鍦�");
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/qc/MesQcIndicatorItemTypeEnum.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/qc/MesQcIndicatorItemTypeEnum.java
new file mode 100644
index 0000000..9fe7c59
--- /dev/null
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/qc/MesQcIndicatorItemTypeEnum.java
@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.mes.enums.qc;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * MES 璐ㄦ鎸囨爣鏉$洰绫诲瀷鏋氫妇
+ * <p>
+ * 涓�涓垎缁勭殑缁勫悕涓庡叕寮忔寕鍦ㄣ�屽垎缁勯」銆嶄笂锛屽疄娴嬪�兼寕鍦ㄥ畠涓嬮潰鐨勩�屽綍鍏ラ」銆嶄笂銆�
+ *
+ * @author 瓒呯骇绠$悊鍛�
+ */
+@Getter
+@AllArgsConstructor
+public enum MesQcIndicatorItemTypeEnum implements ArrayValuable<Integer> {
+
+ ENTRY(1, "褰曞叆椤�"),
+ GROUP(2, "鍒嗙粍椤�");
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesQcIndicatorItemTypeEnum::getType).toArray(Integer[]::new);
+
+ /**
+ * 绫诲瀷鍊�
+ */
+ private final Integer type;
+ /**
+ * 绫诲瀷鍚�
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+ public static boolean isGroup(Integer type) {
+ return Objects.equals(GROUP.getType(), type);
+ }
+
+}
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/indicator/MesQcIndicatorService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/indicator/MesQcIndicatorService.java
index f70945b..20aeb2a 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/indicator/MesQcIndicatorService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/indicator/MesQcIndicatorService.java
@@ -65,6 +65,13 @@
List<MesQcIndicatorDO> getIndicatorList();
/**
+ * 鑾峰緱鍒嗙粍椤瑰垪琛紙鏉$洰绫诲瀷涓哄垎缁勯」锛夛紝涓昏鐢ㄤ簬銆屾墍灞炲垎缁勩�嶄笅鎷夐�夐」
+ *
+ * @return 鍒嗙粍椤瑰垪琛�
+ */
+ List<MesQcIndicatorDO> getIndicatorGroupList();
+
+ /**
* 鑾峰緱璐ㄦ鎸囨爣鍒楄〃
*
* @param ids 缂栧彿鏁扮粍
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/indicator/MesQcIndicatorServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/indicator/MesQcIndicatorServiceImpl.java
index 10fa498..562b5bf 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/indicator/MesQcIndicatorServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/indicator/MesQcIndicatorServiceImpl.java
@@ -3,6 +3,7 @@
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
@@ -10,6 +11,7 @@
import cn.iocoder.yudao.module.mes.controller.admin.qc.indicator.vo.MesQcIndicatorSaveReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicator.MesQcIndicatorDO;
import cn.iocoder.yudao.module.mes.dal.mysql.qc.indicator.MesQcIndicatorMapper;
+import cn.iocoder.yudao.module.mes.enums.qc.MesQcIndicatorItemTypeEnum;
import cn.iocoder.yudao.module.mes.enums.qc.MesQcResultValueTypeEnum;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@@ -19,8 +21,10 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
@@ -43,6 +47,7 @@
// 鎻掑叆
MesQcIndicatorDO indicator = BeanUtils.toBean(createReqVO, MesQcIndicatorDO.class);
+ normalizeHierarchy(indicator);
indicatorMapper.insert(indicator);
return indicator.getId();
}
@@ -56,6 +61,7 @@
// 鏇存柊
MesQcIndicatorDO updateObj = BeanUtils.toBean(updateReqVO, MesQcIndicatorDO.class);
+ normalizeHierarchy(updateObj);
indicatorMapper.updateById(updateObj);
}
@@ -63,6 +69,11 @@
public void deleteIndicator(Long id) {
// 鏍¢獙瀛樺湪
validateIndicatorExists(id);
+ // 绾ц仈鍒犻櫎瀛愰」锛氭寚鏍囧彧鏀寔涓ゅ眰锛屾寕鍦ㄥ畠涓嬮潰鐨勯兘鏄畠鐨勬槑缁嗛」锛岀埗鍒犱簡瀛愭棤澶勫彲鎸�
+ List<MesQcIndicatorDO> children = indicatorMapper.selectListByParentId(id);
+ if (CollUtil.isNotEmpty(children)) {
+ indicatorMapper.deleteByIds(convertList(children, MesQcIndicatorDO::getId));
+ }
// 鍒犻櫎
indicatorMapper.deleteById(id);
}
@@ -72,8 +83,100 @@
validateIndicatorCodeUnique(id, saveReqVO.getCode());
// 鏍¢獙鍚嶇О鍞竴
validateIndicatorNameUnique(id, saveReqVO.getName());
+ // 鏍¢獙灞傜骇褰掑睘锛堝彧鍏佽涓ゅ眰锛�
+ validateHierarchy(id, saveReqVO);
// 鏍¢獙缁撴灉鍊煎睘鎬�
- validateResultSpecification(saveReqVO.getResultType(), saveReqVO.getResultSpecification());
+ validateResultSpecification(saveReqVO.getItemType(), saveReqVO.getResultType(), saveReqVO.getResultSpecification());
+ }
+
+ /**
+ * 鏍¢獙灞傜骇褰掑睘銆傚彧鍏佽涓ゅ眰锛氬垎缁勯」蹇呴』椤剁骇锛屽綍鍏ラ」鍙寕鍒板垎缁勯」涓嬨��
+ * <p>
+ * 銆岀埗蹇呴』鏄垎缁勯」銆嶈繖鏉℃湰韬氨鎺愭浜嗙涓夊眰锛屾墍浠ヤ笉鍐嶅崟鐙啓涓�鏉°�岀埗蹇呴』椤剁骇銆嶇殑鏍¢獙銆�
+ * 鎸変笟鍔′紭鍏堢骇鍙姏绗竴澶勪笉婊¤冻锛岄伩鍏嶄竴娆℃姏澶氭潯璁╃敤鎴锋姄涓嶄綇閲嶇偣銆�
+ */
+ private void validateHierarchy(Long id, MesQcIndicatorSaveReqVO reqVO) {
+ Long parentId = ObjectUtils.defaultIfNull(reqVO.getParentId(), MesQcIndicatorDO.PARENT_ID_ROOT);
+ Integer itemType = ObjectUtils.defaultIfNull(reqVO.getItemType(), MesQcIndicatorItemTypeEnum.ENTRY.getType());
+ // 1. 鍒嗙粍椤瑰彧鑳介《绾�
+ if (MesQcIndicatorItemTypeEnum.isGroup(itemType) && !MesQcIndicatorDO.PARENT_ID_ROOT.equals(parentId)) {
+ throw new ServiceException(QC_INDICATOR_GROUP_CANNOT_NEST.getCode(),
+ String.format("鍒嗙粍椤筟%s]蹇呴』浣滀负椤剁骇鎸囨爣锛屼笉鑳芥寕鍒板叾瀹冩寚鏍囦笅锛堝綋鍓嶉�夋嫨浜嗙埗鎸囨爣[%s]锛夈��"
+ + "濡傞渶璋冩暣灞傜骇锛岃鎶娿�屾潯鐩被鍨嬨�嶆敼涓哄綍鍏ラ」鍚庡啀閫夋嫨鎵�灞炲垎缁勩��",
+ defaultStr(reqVO.getName()), nameOf(parentId)));
+ }
+ // 2. 鐖舵寚鏍囧繀椤诲瓨鍦ㄤ笖鏄垎缁勯」
+ if (!MesQcIndicatorDO.PARENT_ID_ROOT.equals(parentId)) {
+ if (Objects.equals(id, parentId)) {
+ throw exception(QC_INDICATOR_PARENT_SELF);
+ }
+ MesQcIndicatorDO parent = indicatorMapper.selectById(parentId);
+ if (parent == null) {
+ throw new ServiceException(QC_INDICATOR_PARENT_NOT_EXISTS.getCode(),
+ String.format("鎵�灞炲垎缁勪笉瀛樺湪锛堟寚鏍囩紪鍙� %d 鏌ユ棤姝ゆ寚鏍囷紝鍙兘宸茶鍒犻櫎锛夈�傝閲嶆柊閫夋嫨鎵�灞炲垎缁勶紝鎴栨竻绌鸿椤逛綔涓洪《绾ф寚鏍囥��",
+ parentId));
+ }
+ if (!MesQcIndicatorItemTypeEnum.isGroup(parent.getItemType())) {
+ throw new ServiceException(QC_INDICATOR_PARENT_NOT_GROUP.getCode(),
+ String.format("鎵�閫夌埗鎸囨爣[%s]涓嶆槸鍒嗙粍椤癸紙褰撳墠鏉$洰绫诲瀷涓篬%s]锛夛紝涓嶈兘浣滀负鎵�灞炲垎缁勩��"
+ + "璇锋敼閫変竴涓垎缁勯」锛屾垨鍏堝湪鎸囨爣鍒楄〃鎶奫%s]鐨勬潯鐩被鍨嬫敼涓哄垎缁勯」銆�",
+ defaultStr(parent.getName()), itemTypeNameOf(parent.getItemType()), defaultStr(parent.getName())));
+ }
+ }
+ // 3. 褰曞叆椤瑰繀椤绘湁缁撴灉鍊肩被鍨嬶紙鍒嗙粍椤规病鏈夌粨鏋滃�硷紝鐜扮綉鍒嗙粍琛� result_type 灏辨槸 NULL锛�
+ if (!MesQcIndicatorItemTypeEnum.isGroup(itemType) && reqVO.getResultType() == null) {
+ throw exception(QC_INDICATOR_RESULT_TYPE_REQUIRED);
+ }
+ // 4. 鑷繁宸茬粡鏈夊瓙椤规椂锛屼笉鑳藉啀琚埆浜烘敹缂栥�佷篃涓嶈兘鍙嶈繃鏉ュ彉鎴愬瓙椤�
+ if (id == null) {
+ return;
+ }
+ Long childCount = indicatorMapper.selectCountByParentId(id);
+ if (childCount <= 0) {
+ return;
+ }
+ if (!MesQcIndicatorDO.PARENT_ID_ROOT.equals(parentId)) {
+ throw new ServiceException(QC_INDICATOR_HAS_CHILDREN.getCode(),
+ String.format("鎸囨爣[%s]涓嬪凡鎸傛湁 %d 涓綍鍏ラ」锛屼笉鑳藉啀鎸傚埌鍏跺畠鍒嗙粍涓嬶紙鎸囨爣鍙敮鎸佷袱灞傦級銆�"
+ + "璇峰厛鍒犻櫎鎴栫Щ璧拌繖 %d 涓瓙椤癸紝鍐嶄慨鏀瑰畠鐨勬墍灞炲垎缁勩��",
+ defaultStr(reqVO.getName()), childCount, childCount));
+ }
+ if (!MesQcIndicatorItemTypeEnum.isGroup(itemType)) {
+ throw new ServiceException(QC_INDICATOR_HAS_CHILDREN.getCode(),
+ String.format("鎸囨爣[%s]涓嬪凡鎸傛湁 %d 涓綍鍏ラ」锛屼笉鑳藉啀鎶婂畠鐨勬潯鐩被鍨嬫敼涓哄綍鍏ラ」锛屽惁鍒欒繖浜涘瓙椤逛細澶卞幓鎵�灞炲垎缁勩��"
+ + "璇峰厛鍒犻櫎鎴栫Щ璧拌繖 %d 涓瓙椤癸紝鍐嶄慨鏀规潯鐩被鍨嬨��",
+ defaultStr(reqVO.getName()), childCount, childCount));
+ }
+ }
+
+ /**
+ * 钀藉簱鍓嶈ˉ榻愬眰绾у瓧娈碉細鍒嗙粍椤规竻绌虹粨鏋滃�硷紙鐜扮綉鍒嗙粍琛屾病鏈夌粨鏋滃�硷級锛屾帓搴忓彿鐣欑┖鍒欐帓鍒板悓绾ф湯灏�
+ */
+ private void normalizeHierarchy(MesQcIndicatorDO indicator) {
+ indicator.setParentId(ObjectUtils.defaultIfNull(indicator.getParentId(), MesQcIndicatorDO.PARENT_ID_ROOT));
+ indicator.setItemType(ObjectUtils.defaultIfNull(indicator.getItemType(), MesQcIndicatorItemTypeEnum.ENTRY.getType()));
+ if (MesQcIndicatorItemTypeEnum.isGroup(indicator.getItemType())) {
+ indicator.setResultType(null);
+ indicator.setResultSpecification(null);
+ }
+ if (indicator.getSortOrder() == null) {
+ Integer max = indicatorMapper.selectMaxSortOrder(indicator.getParentId());
+ indicator.setSortOrder((max == null ? 0 : max) + (MesQcIndicatorDO.PARENT_ID_ROOT.equals(indicator.getParentId()) ? 10 : 1));
+ }
+ }
+
+ private String nameOf(Long id) {
+ MesQcIndicatorDO indicator = id == null ? null : indicatorMapper.selectById(id);
+ return indicator == null ? String.valueOf(id) : defaultStr(indicator.getName());
+ }
+
+ private static String itemTypeNameOf(Integer itemType) {
+ return MesQcIndicatorItemTypeEnum.isGroup(itemType)
+ ? MesQcIndicatorItemTypeEnum.GROUP.getName() : MesQcIndicatorItemTypeEnum.ENTRY.getName();
+ }
+
+ private static String defaultStr(String value) {
+ return StrUtil.blankToDefault(value, "");
}
private void validateIndicatorExists(Long id) {
@@ -102,7 +205,11 @@
}
}
- private void validateResultSpecification(Integer resultType, String resultSpecification) {
+ private void validateResultSpecification(Integer itemType, Integer resultType, String resultSpecification) {
+ // 鍒嗙粍椤规病鏈夌粨鏋滃�硷紝钀藉簱鍓嶄細琚竻绌猴紝杩欓噷涓嶆牎楠�
+ if (MesQcIndicatorItemTypeEnum.isGroup(ObjectUtils.defaultIfNull(itemType, MesQcIndicatorItemTypeEnum.ENTRY.getType()))) {
+ return;
+ }
if (ObjectUtils.equalsAny(resultType, MesQcResultValueTypeEnum.FILE.getType(),
MesQcResultValueTypeEnum.DICT.getType())) {
if (StrUtil.isBlank(resultSpecification)) {
@@ -127,6 +234,11 @@
}
@Override
+ public List<MesQcIndicatorDO> getIndicatorGroupList() {
+ return indicatorMapper.selectListByItemType(MesQcIndicatorItemTypeEnum.GROUP.getType());
+ }
+
+ @Override
public List<MesQcIndicatorDO> getIndicatorList(Collection<Long> ids) {
if (CollUtil.isEmpty(ids)) {
return Collections.emptyList();
diff --git a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/indicator/MesQcIndicatorServiceImplTest.java b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/indicator/MesQcIndicatorServiceImplTest.java
new file mode 100644
index 0000000..f608cab
--- /dev/null
+++ b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/qc/indicator/MesQcIndicatorServiceImplTest.java
@@ -0,0 +1,323 @@
+package cn.iocoder.yudao.module.mes.service.qc.indicator;
+
+import cn.iocoder.yudao.framework.common.exception.ErrorCode;
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.indicator.vo.MesQcIndicatorSaveReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicator.MesQcIndicatorDO;
+import cn.iocoder.yudao.module.mes.dal.mysql.qc.indicator.MesQcIndicatorMapper;
+import cn.iocoder.yudao.module.mes.enums.qc.MesQcIndicatorItemTypeEnum;
+import cn.iocoder.yudao.module.mes.enums.qc.MesQcResultValueTypeEnum;
+import jakarta.annotation.Resource;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.function.Executable;
+import org.springframework.context.annotation.Import;
+
+import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
+import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * {@link MesQcIndicatorServiceImpl} 鐨勫崟鍏冩祴璇�
+ * <p>
+ * 瑕嗙洊鍒嗙粍灞傜骇锛氬眰绾ф牎楠屻�佹帓搴忓彿琛ラ綈銆佺粨鏋滃�煎瓧娈垫竻绌恒�佺骇鑱斿垹闄ゃ��
+ *
+ * @author 瓒呯骇绠$悊鍛�
+ */
+@Import(MesQcIndicatorServiceImpl.class)
+public class MesQcIndicatorServiceImplTest extends BaseDbUnitTest {
+
+ /**
+ * 妫�娴嬮」绫诲瀷锛堝瓧鍏� mes_indicator_type 鐨勩�屾�ц兘銆嶏紝鐜扮綉鍒嗙粍琛岀敤鐨勫氨鏄繖涓�硷級
+ */
+ private static final Integer TYPE_PERFORMANCE = 4;
+
+ @Resource
+ private MesQcIndicatorServiceImpl indicatorService;
+
+ @Resource
+ private MesQcIndicatorMapper indicatorMapper;
+
+ // ==================== 鍒涘缓锛氬垎缁勯」 ====================
+
+ @Test
+ public void testCreateGroup_clearsResultFields() {
+ // 鍑嗗鍙傛暟锛氬垎缁勯」鍗充娇甯︿簡 FILE 绫诲瀷涓庣┖鐨勭粨鏋滃�煎睘鎬э紝涔熶笉搴旇銆岀粨鏋滃�煎睘鎬т笉鑳戒负绌恒�嶆嫤浣�
+ MesQcIndicatorSaveReqVO reqVO = buildReqVO("T01-G", "姘村垎", MesQcIndicatorItemTypeEnum.GROUP.getType(),
+ null, MesQcResultValueTypeEnum.FILE.getType());
+ reqVO.setFormulaText("w = (m1 - m0) / m 脳 100%");
+
+ // 璋冪敤
+ Long id = indicatorService.createIndicator(reqVO);
+
+ // 鏂█锛氬垎缁勯」钀藉簱鏃剁粨鏋滃�煎瓧娈佃娓呯┖锛岀埗绾у綊 0锛屾帓搴忓彿鑷姩琛� 10锛堥涓《绾э級
+ MesQcIndicatorDO dbIndicator = indicatorMapper.selectById(id);
+ assertNotNull(dbIndicator);
+ assertEquals(MesQcIndicatorItemTypeEnum.GROUP.getType(), dbIndicator.getItemType());
+ assertEquals(MesQcIndicatorDO.PARENT_ID_ROOT, dbIndicator.getParentId());
+ assertNull(dbIndicator.getResultType());
+ assertNull(dbIndicator.getResultSpecification());
+ assertEquals("w = (m1 - m0) / m 脳 100%", dbIndicator.getFormulaText());
+ assertEquals(10, dbIndicator.getSortOrder());
+ }
+
+ @Test
+ public void testCreateGroup_cannotNest() {
+ // mock 鏁版嵁锛氫竴涓凡瀛樺湪鐨勫垎缁�
+ MesQcIndicatorDO parent = insertIndicator("T02-G1", "姘村垎", MesQcIndicatorItemTypeEnum.GROUP.getType(),
+ MesQcIndicatorDO.PARENT_ID_ROOT, null, 10);
+ // 鍑嗗鍙傛暟锛氬垎缁勯」鎸傚埌鍙︿竴涓垎缁勪笅
+ MesQcIndicatorSaveReqVO reqVO = buildReqVO("T02-G2", "鐏板垎", MesQcIndicatorItemTypeEnum.GROUP.getType(),
+ parent.getId(), null);
+
+ // 璋冪敤锛屽苟鏂█寮傚父
+ assertMessageException(() -> indicatorService.createIndicator(reqVO),
+ QC_INDICATOR_GROUP_CANNOT_NEST, "鐏板垎", "蹇呴』浣滀负椤剁骇鎸囨爣", "姘村垎");
+
+ // 鏂█锛氭湭鍏ュ簱
+ assertEquals(1, indicatorMapper.selectCount());
+ }
+
+ // ==================== 鍒涘缓锛氬綍鍏ラ」 ====================
+
+ @Test
+ public void testCreateEntry_defaultSortOrder() {
+ // mock 鏁版嵁锛氫竴涓《绾у垎缁勶紝鎺掑簭鍙� 30
+ MesQcIndicatorDO group = insertIndicator("T03-G", "姘村垎", MesQcIndicatorItemTypeEnum.GROUP.getType(),
+ MesQcIndicatorDO.PARENT_ID_ROOT, null, 30);
+
+ // 璋冪敤锛氱粍鍐呯涓�鏉″瓙椤癸紝鎺掑簭鍙风暀绌�
+ Long firstId = indicatorService.createIndicator(buildReqVO("T03-E1", "娓哥姘�",
+ MesQcIndicatorItemTypeEnum.ENTRY.getType(), group.getId(), MesQcResultValueTypeEnum.FLOAT.getType()));
+ // 璋冪敤锛氱粍鍐呯浜屾潯瀛愰」锛屾帓搴忓彿鐣欑┖
+ Long secondId = indicatorService.createIndicator(buildReqVO("T03-E2", "缁撳悎姘�",
+ MesQcIndicatorItemTypeEnum.ENTRY.getType(), group.getId(), MesQcResultValueTypeEnum.FLOAT.getType()));
+
+ // 鏂█锛氬瓙椤规闀夸负 1锛屼緷娆℃帓鍒板悓绾ф湯灏�
+ assertEquals(1, indicatorMapper.selectById(firstId).getSortOrder());
+ assertEquals(2, indicatorMapper.selectById(secondId).getSortOrder());
+ assertEquals(group.getId(), indicatorMapper.selectById(firstId).getParentId());
+ }
+
+ @Test
+ public void testCreateIndicator_defaultSortOrder_topLevelBlockStep() {
+ // mock 鏁版嵁锛氶《绾у垎缁勬帓搴忓彿 30
+ insertIndicator("T04-G", "姘村垎", MesQcIndicatorItemTypeEnum.GROUP.getType(),
+ MesQcIndicatorDO.PARENT_ID_ROOT, null, 30);
+
+ // 璋冪敤锛氶《绾ф柊鎸囨爣鎺掑簭鍙风暀绌猴紝椤剁骇姝ラ暱涓� 10
+ Long id = indicatorService.createIndicator(buildReqVO("T04-E", "澶栬",
+ MesQcIndicatorItemTypeEnum.ENTRY.getType(), null, MesQcResultValueTypeEnum.TEXT.getType()));
+
+ // 鏂█
+ MesQcIndicatorDO dbIndicator = indicatorMapper.selectById(id);
+ assertEquals(MesQcIndicatorDO.PARENT_ID_ROOT, dbIndicator.getParentId());
+ assertEquals(40, dbIndicator.getSortOrder());
+ }
+
+ @Test
+ public void testCreateEntry_parentNotGroup() {
+ // mock 鏁版嵁锛氫竴涓綍鍏ラ」琚嬁鏉ュ綋鐖剁骇
+ MesQcIndicatorDO entry = insertIndicator("T05-E1", "澶栬", MesQcIndicatorItemTypeEnum.ENTRY.getType(),
+ MesQcIndicatorDO.PARENT_ID_ROOT, MesQcResultValueTypeEnum.TEXT.getType(), 10);
+ // 鍑嗗鍙傛暟
+ MesQcIndicatorSaveReqVO reqVO = buildReqVO("T05-E2", "鑹叉辰", MesQcIndicatorItemTypeEnum.ENTRY.getType(),
+ entry.getId(), MesQcResultValueTypeEnum.TEXT.getType());
+
+ // 璋冪敤锛屽苟鏂█寮傚父
+ assertMessageException(() -> indicatorService.createIndicator(reqVO),
+ QC_INDICATOR_PARENT_NOT_GROUP, "澶栬", "涓嶆槸鍒嗙粍椤�", "褰曞叆椤�");
+ }
+
+ @Test
+ public void testCreateEntry_parentNotExists() {
+ // 鍑嗗鍙傛暟锛氱埗绾х紪鍙蜂笉瀛樺湪
+ Long notExistsParentId = randomLongId();
+ MesQcIndicatorSaveReqVO reqVO = buildReqVO("T06-E", "鑹叉辰", MesQcIndicatorItemTypeEnum.ENTRY.getType(),
+ notExistsParentId, MesQcResultValueTypeEnum.TEXT.getType());
+
+ // 璋冪敤锛屽苟鏂█寮傚父
+ assertMessageException(() -> indicatorService.createIndicator(reqVO),
+ QC_INDICATOR_PARENT_NOT_EXISTS, "鎵�灞炲垎缁勪笉瀛樺湪", String.valueOf(notExistsParentId));
+ }
+
+ @Test
+ public void testCreateEntry_resultTypeRequired() {
+ // 鍑嗗鍙傛暟锛氬綍鍏ラ」娌℃湁缁撴灉鍊肩被鍨�
+ MesQcIndicatorSaveReqVO reqVO = buildReqVO("T07-E", "鑹叉辰", MesQcIndicatorItemTypeEnum.ENTRY.getType(),
+ null, null);
+
+ // 璋冪敤锛屽苟鏂█寮傚父
+ assertServiceException(() -> indicatorService.createIndicator(reqVO), QC_INDICATOR_RESULT_TYPE_REQUIRED);
+
+ // 鏂█锛氭湭鍏ュ簱
+ assertEquals(0, indicatorMapper.selectCount());
+ }
+
+ @Test
+ public void testCreateEntry_fileResultSpecificationRequired() {
+ // 鍑嗗鍙傛暟锛氬綍鍏ラ」涓� FILE 绫诲瀷浣嗘病濉粨鏋滃�煎睘鎬�
+ MesQcIndicatorSaveReqVO reqVO = buildReqVO("T08-E", "澶栬鐓х墖", MesQcIndicatorItemTypeEnum.ENTRY.getType(),
+ null, MesQcResultValueTypeEnum.FILE.getType());
+
+ // 璋冪敤锛屽苟鏂█寮傚父
+ assertServiceException(() -> indicatorService.createIndicator(reqVO), QC_INDICATOR_RESULT_SPECIFICATION_REQUIRED);
+ }
+
+ // ==================== 淇敼 ====================
+
+ @Test
+ public void testUpdateEntry_parentSelf() {
+ // mock 鏁版嵁锛氫竴涓綍鍏ラ」
+ MesQcIndicatorDO entry = insertIndicator("T09-E", "澶栬", MesQcIndicatorItemTypeEnum.ENTRY.getType(),
+ MesQcIndicatorDO.PARENT_ID_ROOT, MesQcResultValueTypeEnum.TEXT.getType(), 10);
+ // 鍑嗗鍙傛暟锛氭妸鑷繁褰撶埗绾�
+ MesQcIndicatorSaveReqVO reqVO = buildReqVO("T09-E", "澶栬", MesQcIndicatorItemTypeEnum.ENTRY.getType(),
+ entry.getId(), MesQcResultValueTypeEnum.TEXT.getType());
+ reqVO.setId(entry.getId());
+
+ // 璋冪敤锛屽苟鏂█寮傚父
+ assertServiceException(() -> indicatorService.updateIndicator(reqVO), QC_INDICATOR_PARENT_SELF);
+ }
+
+ @Test
+ public void testUpdateIndicator_toGroup_clearsResultFields() {
+ // mock 鏁版嵁锛氫竴涓� FILE 绫诲瀷鐨勫綍鍏ラ」
+ MesQcIndicatorDO entry = insertIndicator("T10-E", "閰稿惈閲�", MesQcIndicatorItemTypeEnum.ENTRY.getType(),
+ MesQcIndicatorDO.PARENT_ID_ROOT, MesQcResultValueTypeEnum.FILE.getType(), 10);
+ entry.setResultSpecification("IMG");
+ indicatorMapper.updateById(entry);
+ // 鍑嗗鍙傛暟锛氭妸瀹冩敼鎴愬垎缁勯」
+ MesQcIndicatorSaveReqVO reqVO = buildReqVO("T10-E", "閰稿惈閲�", MesQcIndicatorItemTypeEnum.GROUP.getType(),
+ null, MesQcResultValueTypeEnum.FILE.getType());
+ reqVO.setId(entry.getId());
+ reqVO.setFormulaText("c = V 脳 N / m");
+
+ // 璋冪敤
+ indicatorService.updateIndicator(reqVO);
+
+ // 鏂█锛氭潯鐩被鍨嬪凡鏀癸紝缁撴灉鍊煎瓧娈佃娓呯┖锛屽叕寮忓啓鍏�
+ MesQcIndicatorDO dbIndicator = indicatorMapper.selectById(entry.getId());
+ assertEquals(MesQcIndicatorItemTypeEnum.GROUP.getType(), dbIndicator.getItemType());
+ assertNull(dbIndicator.getResultType());
+ assertNull(dbIndicator.getResultSpecification());
+ assertEquals("c = V 脳 N / m", dbIndicator.getFormulaText());
+ }
+
+ @Test
+ public void testUpdateIndicator_hasChildrenCannotChangeToEntry() {
+ // mock 鏁版嵁锛氫竴涓甫瀛愰」鐨勫垎缁�
+ MesQcIndicatorDO group = insertIndicator("T11-G", "姘村垎", MesQcIndicatorItemTypeEnum.GROUP.getType(),
+ MesQcIndicatorDO.PARENT_ID_ROOT, null, 10);
+ insertIndicator("T11-E1", "娓哥姘�", MesQcIndicatorItemTypeEnum.ENTRY.getType(), group.getId(),
+ MesQcResultValueTypeEnum.FLOAT.getType(), 1);
+ // 鍑嗗鍙傛暟锛氭妸鍒嗙粍鏀规垚褰曞叆椤�
+ MesQcIndicatorSaveReqVO reqVO = buildReqVO("T11-G", "姘村垎", MesQcIndicatorItemTypeEnum.ENTRY.getType(),
+ null, MesQcResultValueTypeEnum.FLOAT.getType());
+ reqVO.setId(group.getId());
+
+ // 璋冪敤锛屽苟鏂█寮傚父
+ assertMessageException(() -> indicatorService.updateIndicator(reqVO),
+ QC_INDICATOR_HAS_CHILDREN, "涓嶈兘鍐嶆妸瀹冪殑鏉$洰绫诲瀷鏀逛负褰曞叆椤�", "姘村垎");
+
+ // 鏂█锛氭潯鐩被鍨嬫湭琚敼鍔�
+ assertEquals(MesQcIndicatorItemTypeEnum.GROUP.getType(), indicatorMapper.selectById(group.getId()).getItemType());
+ }
+
+ @Test
+ public void testUpdateIndicator_hasChildrenCannotReparent() {
+ // mock 鏁版嵁锛氫竴涓甫瀛愰」鐨勬潯鐩紙鍘嗗彶鑴忔暟鎹細褰曞叆椤逛篃鍙兘琚寕杩囧瓙椤癸紝鎶ュ憡渚у彧璁� parent_id锛�
+ MesQcIndicatorDO entry = insertIndicator("T12-E", "鏉傝川", MesQcIndicatorItemTypeEnum.ENTRY.getType(),
+ MesQcIndicatorDO.PARENT_ID_ROOT, MesQcResultValueTypeEnum.FLOAT.getType(), 10);
+ insertIndicator("T12-E1", "涓嶆憾鐗�", MesQcIndicatorItemTypeEnum.ENTRY.getType(), entry.getId(),
+ MesQcResultValueTypeEnum.FLOAT.getType(), 1);
+ MesQcIndicatorDO group = insertIndicator("T12-G", "姘村垎", MesQcIndicatorItemTypeEnum.GROUP.getType(),
+ MesQcIndicatorDO.PARENT_ID_ROOT, null, 20);
+ // 鍑嗗鍙傛暟锛氭妸甯﹀瓙椤圭殑鎸囨爣鎸傚埌鍒嗙粍涓�
+ MesQcIndicatorSaveReqVO reqVO = buildReqVO("T12-E", "鏉傝川", MesQcIndicatorItemTypeEnum.ENTRY.getType(),
+ group.getId(), MesQcResultValueTypeEnum.FLOAT.getType());
+ reqVO.setId(entry.getId());
+
+ // 璋冪敤锛屽苟鏂█寮傚父
+ assertMessageException(() -> indicatorService.updateIndicator(reqVO),
+ QC_INDICATOR_HAS_CHILDREN, "涓嶈兘鍐嶆寕鍒板叾瀹冨垎缁勪笅", "鏉傝川");
+
+ // 鏂█锛氱埗绾ф湭琚敼鍔�
+ assertEquals(MesQcIndicatorDO.PARENT_ID_ROOT, indicatorMapper.selectById(entry.getId()).getParentId());
+ }
+
+ // ==================== 鍒犻櫎 ====================
+
+ @Test
+ public void testDeleteGroup_cascadeChildren() {
+ // mock 鏁版嵁锛氫竴涓垎缁� + 涓や釜瀛愰」 + 涓�涓笉鐩稿叧鐨勯《绾ф寚鏍�
+ MesQcIndicatorDO group = insertIndicator("T13-G", "姘村垎", MesQcIndicatorItemTypeEnum.GROUP.getType(),
+ MesQcIndicatorDO.PARENT_ID_ROOT, null, 10);
+ Long child1Id = insertIndicator("T13-E1", "娓哥姘�", MesQcIndicatorItemTypeEnum.ENTRY.getType(),
+ group.getId(), MesQcResultValueTypeEnum.FLOAT.getType(), 1).getId();
+ Long child2Id = insertIndicator("T13-E2", "缁撳悎姘�", MesQcIndicatorItemTypeEnum.ENTRY.getType(),
+ group.getId(), MesQcResultValueTypeEnum.FLOAT.getType(), 2).getId();
+ Long otherId = insertIndicator("T13-E3", "澶栬", MesQcIndicatorItemTypeEnum.ENTRY.getType(),
+ MesQcIndicatorDO.PARENT_ID_ROOT, MesQcResultValueTypeEnum.TEXT.getType(), 20).getId();
+
+ // 璋冪敤
+ indicatorService.deleteIndicator(group.getId());
+
+ // 鏂█锛氬垎缁勪笌鍏跺瓙椤逛竴骞跺垹闄わ紝涓嶇浉鍏崇殑鎸囨爣淇濈暀
+ assertNull(indicatorMapper.selectById(group.getId()));
+ assertNull(indicatorMapper.selectById(child1Id));
+ assertNull(indicatorMapper.selectById(child2Id));
+ assertNotNull(indicatorMapper.selectById(otherId));
+ }
+
+ @Test
+ public void testDeleteIndicator_notExists() {
+ // 璋冪敤锛屽苟鏂█寮傚父
+ assertServiceException(() -> indicatorService.deleteIndicator(randomLongId()), QC_INDICATOR_NOT_EXISTS);
+ }
+
+ // ==================== 杈呭姪鏂规硶 ====================
+
+ private MesQcIndicatorSaveReqVO buildReqVO(String code, String name, Integer itemType, Long parentId,
+ Integer resultType) {
+ MesQcIndicatorSaveReqVO reqVO = new MesQcIndicatorSaveReqVO();
+ reqVO.setCode(code);
+ reqVO.setName(name);
+ reqVO.setType(TYPE_PERFORMANCE);
+ reqVO.setItemType(itemType);
+ reqVO.setParentId(parentId);
+ reqVO.setResultType(resultType);
+ return reqVO;
+ }
+
+ private MesQcIndicatorDO insertIndicator(String code, String name, Integer itemType, Long parentId,
+ Integer resultType, Integer sortOrder) {
+ MesQcIndicatorDO indicator = new MesQcIndicatorDO();
+ indicator.setCode(code);
+ indicator.setName(name);
+ indicator.setType(TYPE_PERFORMANCE);
+ indicator.setItemType(itemType);
+ indicator.setParentId(parentId);
+ indicator.setResultType(resultType);
+ indicator.setSortOrder(sortOrder);
+ indicatorMapper.insert(indicator);
+ return indicator;
+ }
+
+ /**
+ * 鏂█鎶涘嚭鐨勪笟鍔″紓甯搁敊璇爜姝g‘锛屼笖鎻愮ず鏂囨鍖呭惈缁欏畾鐨勫叧閿墖娈点��
+ * <p>
+ * 灞傜骇鏍¢獙鐨勬枃妗堝甫鍒嗙粍鍚� / 鐖舵寚鏍囧悕 / 瀛愰」鏉℃暟锛屾棤娉曠敤
+ * {@link cn.iocoder.yudao.framework.test.core.util.AssertUtils#assertServiceException} 閫愬瓧姣斿銆�
+ */
+ private void assertMessageException(Executable executable, ErrorCode errorCode, String... messageFragments) {
+ ServiceException exception = assertThrows(ServiceException.class, executable);
+ assertEquals(errorCode.getCode(), exception.getCode(), "閿欒鐮佷笉鍖归厤");
+ for (String fragment : messageFragments) {
+ assertTrue(exception.getMessage().contains(fragment),
+ String.format("閿欒鎻愮ず[%s]鏈寘鍚玔%s]", exception.getMessage(), fragment));
+ }
+ }
+
+}
diff --git a/yudao-module-mes/src/test/resources/sql/clean.sql b/yudao-module-mes/src/test/resources/sql/clean.sql
index 8cb28c3..a43fac9 100644
--- a/yudao-module-mes/src/test/resources/sql/clean.sql
+++ b/yudao-module-mes/src/test/resources/sql/clean.sql
@@ -21,3 +21,4 @@
DELETE FROM "mes_pro_task";
DELETE FROM "mes_pro_route_process";
DELETE FROM "mes_qc_indicator_result";
+DELETE FROM "mes_qc_indicator";
diff --git a/yudao-module-mes/src/test/resources/sql/create_tables.sql b/yudao-module-mes/src/test/resources/sql/create_tables.sql
index fd73613..780ff99 100644
--- a/yudao-module-mes/src/test/resources/sql/create_tables.sql
+++ b/yudao-module-mes/src/test/resources/sql/create_tables.sql
@@ -830,3 +830,29 @@
"tenant_id" bigint NOT NULL DEFAULT 0,
PRIMARY KEY ("id")
);
+
+-- ----------------------------
+-- MES 璐ㄦ鎸囨爣
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS "mes_qc_indicator" (
+ "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+ "code" varchar(100) DEFAULT NULL,
+ "name" varchar(100) DEFAULT NULL,
+ "parent_id" bigint NOT NULL DEFAULT 0,
+ "item_type" tinyint NOT NULL DEFAULT 1,
+ "formula_text" varchar(500) DEFAULT NULL,
+ "unit_text" varchar(50) DEFAULT NULL,
+ "sort_order" int NOT NULL DEFAULT 0,
+ "type" int DEFAULT NULL,
+ "tool" varchar(255) DEFAULT NULL,
+ "result_type" int DEFAULT NULL,
+ "result_specification" varchar(255) DEFAULT NULL,
+ "remark" varchar(255) DEFAULT NULL,
+ "creator" varchar(64) DEFAULT '',
+ "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updater" varchar(64) DEFAULT '',
+ "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "deleted" bit NOT NULL DEFAULT FALSE,
+ "tenant_id" bigint NOT NULL DEFAULT 0,
+ PRIMARY KEY ("id")
+);
diff --git a/yudao-module-qcreport/pom.xml b/yudao-module-qcreport/pom.xml
new file mode 100644
index 0000000..72f6e7f
--- /dev/null
+++ b/yudao-module-qcreport/pom.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>cn.iocoder.boot</groupId>
+ <artifactId>yudao</artifactId>
+ <version>${revision}</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>yudao-module-qcreport</artifactId>
+ <packaging>jar</packaging>
+
+ <name>${project.artifactId}</name>
+ <description>
+ qcreport 妯″潡涓嬶紝鏅鸿兘璐ㄦ鎶ュ憡璁捐骞冲彴銆�
+ 鍙鍖栨姤鍛婃ā鏉胯璁″櫒 + 妯℃澘 Schema + 鏁版嵁缁戝畾寮曟搸 + 鍒ゅ畾瑙勫垯寮曟搸 + HTML/PDF 娓叉煋寮曟搸銆�
+ </description>
+
+ <dependencies>
+ <!-- System锛氭潈闄愩�佺敤鎴枫�佹枃浠跺瓨鍌紙storage-blob / storage-attachment锛� -->
+ <dependency>
+ <groupId>cn.iocoder.boot</groupId>
+ <artifactId>yudao-module-system</artifactId>
+ <version>${revision}</version>
+ </dependency>
+
+ <!-- MES锛氳川妫�鍗曪紙鏉ユ枡/杩囩▼/鍑鸿揣/閫�璐э級鍙姤鍛婃暟鎹帴鍙� -->
+ <dependency>
+ <groupId>cn.iocoder.boot</groupId>
+ <artifactId>yudao-module-mes-api</artifactId>
+ <version>${revision}</version>
+ </dependency>
+
+ <!-- Web 鐩稿叧 -->
+ <dependency>
+ <groupId>cn.iocoder.boot</groupId>
+ <artifactId>yudao-spring-boot-starter-web</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>cn.iocoder.boot</groupId>
+ <artifactId>yudao-spring-boot-starter-security</artifactId>
+ </dependency>
+
+ <!-- DB 鐩稿叧 -->
+ <dependency>
+ <groupId>cn.iocoder.boot</groupId>
+ <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>cn.iocoder.boot</groupId>
+ <artifactId>yudao-spring-boot-starter-redis</artifactId>
+ </dependency>
+
+ <!-- 宸ュ叿绫荤浉鍏� -->
+ <dependency>
+ <groupId>cn.iocoder.boot</groupId>
+ <artifactId>yudao-spring-boot-starter-excel</artifactId>
+ </dependency>
+
+ <!-- PDF 鍑轰欢锛氭湇鍔$璋冪敤 Chromium 鎶婃姤鍛� HTML 鎵撳嵃鎴� PDF -->
+ <dependency>
+ <groupId>com.microsoft.playwright</groupId>
+ <artifactId>playwright</artifactId>
+ </dependency>
+
+ <!-- AI 瀵煎叆锛氬彧渚濊禆 -api锛堥噷闈㈠彧鏈� AiChatApi锛夛紝涓嶄緷璧� yudao-module-ai 鏈綋 -->
+ <dependency>
+ <groupId>cn.iocoder.boot</groupId>
+ <artifactId>yudao-module-ai-api</artifactId>
+ <version>${revision}</version>
+ </dependency>
+
+ <!-- AI 瀵煎叆锛歅DF 鏂囨湰鎶藉彇涓庢壂鎻忛〉娓叉煋 -->
+ <dependency>
+ <groupId>org.apache.pdfbox</groupId>
+ <artifactId>pdfbox</artifactId>
+ <version>3.0.4</version>
+ </dependency>
+
+ <!-- AI 瀵煎叆锛歐ord(.docx) / Excel(.xlsx) 鏂囨湰鎶藉彇 -->
+ <dependency>
+ <groupId>org.apache.poi</groupId>
+ <artifactId>poi-ooxml</artifactId>
+ <version>5.4.0</version>
+ </dependency>
+
+ <!-- Test 娴嬭瘯鐩稿叧 -->
+ <dependency>
+ <groupId>cn.iocoder.boot</groupId>
+ <artifactId>yudao-spring-boot-starter-test</artifactId>
+ </dependency>
+
+ </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/config/QcReportAiImportProperties.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/config/QcReportAiImportProperties.java
new file mode 100644
index 0000000..fc350e9
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/config/QcReportAiImportProperties.java
@@ -0,0 +1,66 @@
+package cn.iocoder.yudao.module.qcreport.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * AI 瀵煎叆妯℃澘鑽夌閰嶇疆
+ * <p>
+ * 瀵瑰簲 application.yml 涓殑 yudao.qcreport.ai-import 鍓嶇紑閰嶇疆銆�
+ * <p>
+ * 杩欓噷鐨勬瘡涓�椤归兘鏄�**纭笂闄�**锛屼笉鏄�ц兘璋冧紭鍙傛暟锛氭瘡娆″鍏ヤ細鐪熺殑鍙戝嚭 1锝�5 娆″ぇ妯″瀷璋冪敤锛�
+ * 鎵弿浠舵寜鍥捐璐癸紝鏃犱笂闄愭剰鍛崇潃涓�娆¤鎿嶄綔灏辫兘鐑ф帀涓�鏁村ぉ鐨勯搴︺�傛墍浠ュ畞鍙姤閿欒鐢ㄦ埛鍒嗘壒锛�
+ * 涔熶笉瑕侀潤榛樻埅鏂�斺�旈潤榛樻埅鏂繕浼氳鐢ㄦ埛浠ヤ负鏁翠唤鏂囦欢閮借瘑鍒繃浜嗐��
+ */
+@Component
+@ConfigurationProperties(prefix = "yudao.qcreport.ai-import", ignoreUnknownFields = true)
+@Data
+public class QcReportAiImportProperties {
+
+ /** 鏄惁鍚敤 AI 瀵煎叆銆傞渶瑕佽兘鍑虹綉璁块棶澶фā鍨嬫湇鍔★紱鍐呯綉閮ㄧ讲鏃跺叧鎺夊畠锛屾帴鍙d細鏄庣‘鎶ャ�屾湭鍚敤銆嶈�屼笉鏄寕浣� */
+ private Boolean enabled = true;
+
+ /** 涓�娆¤姹傛渶澶氬嚑涓枃浠� */
+ private Integer maxFiles = 3;
+
+ /** 鍗曚釜鏂囦欢鏈�澶氬嚑椤点�傝秴鍑虹洿鎺ユ姤閿欙紝涓嶉潤榛樻埅鏂� */
+ private Integer maxPagesPerFile = 5;
+
+ /** 涓�娆¤姹傜殑绱椤垫暟涓婇檺銆傚鏂囦欢鍙犲姞鍚庣殑鎬婚椄锛岄槻姝€�屾瘡涓枃浠堕兘娌¤秴銆佸姞璧锋潵鍗村緢澶氥�� */
+ private Integer maxPagesPerRequest = 8;
+
+ /**
+ * 涓�娆″鍏ョ殑鎬昏�楁椂涓婇檺锛堢锛夛紝鍦ㄤ袱娆℃ā鍨嬭皟鐢ㄤ箣闂存鏌ャ��
+ * <p>
+ * 椤垫暟涓庢枃浠舵暟涓婇檺鍙害鏉熶簡璋冪敤**娆℃暟**锛屾病绾︽潫**鏃堕暱**锛氭ā鍨嬫帓闃熸椂姣忔璋冪敤閮借兘鑰楁弧
+ * {@code yudao.ai.timeout}锛�8 娆″彔鍔犺兘鎶婁竴娆¤鎿嶄綔鎷栨垚濂藉嚑鍒嗛挓鐨勪粯璐硅皟鐢ㄣ��
+ * <p>
+ * 鍗曟璋冪敤鏃犳硶涓�旀墦鏂紙{@code AiChatApi} 涓嶆帴鍙楄秴鏃跺弬鏁帮級锛屾墍浠ュ彧鑳藉湪涓ゆ璋冪敤涔嬮棿鍏抽棬锛�
+ * 鏈�鍧忎細澶氬嚭涓�涓崟娆¤皟鐢ㄨ秴鏃躲�傚墠绔� axios 瓒呮椂蹇呴』姣斻�屾湰椤� + yudao.ai.timeout銆嶆洿瀹斤紝
+ * 鍚﹀垯鐢ㄦ埛鍏堢湅鍒版祻瑙堝櫒鏂紑锛岃�屼笉鏄繖閲岀殑鏄庣‘鎻愮ず銆傚彇 180 绉掞細甯歌 8 娆′互鍐呯殑璋冪敤閮借窇寰楀畬锛�
+ * 鍙湁妯″瀷鏄庢樉鍙樻參鏃舵墠浼氳Е鍙戙��
+ */
+ private Integer maxDurationSeconds = 180;
+
+ /** 鍗曚釜鏂囦欢澶у皬涓婇檺锛圡B锛� */
+ private Integer maxFileSizeMb = 20;
+
+ /** 璇嗗埆鍑虹殑缁勪欢鎬绘暟涓婇檺锛岃秴鍑烘埅鏂苟鍦� warnings 閲屾彁绀鸿ˉ褰� */
+ private Integer maxComponents = 200;
+
+ /**
+ * PDF 鍒ゅ畾璧版枃鏈�氶亾杩樻槸鍥剧墖閫氶亾鐨勯槇鍊硷細骞冲潎姣忛〉瀛楃鏁般��
+ * <p>
+ * 渚濇嵁鏄�岃繖浠� PDF 鏈夋病鏈夋枃鏈眰銆嶈�屼笉鏄�屽畠鏄笉鏄� PDF銆嶃�傞槇鍊煎彇 30 鏄粡楠屽�硷細
+ * 鐪熸鏈夋枃鏈眰鐨勬姤鍛婃瘡椤佃嚦灏戝嚑鍗佸瓧锛岃�屾壂鎻忎欢鍗充究甯︿笂 OCR 灞備篃寰�寰�鍙湁闆舵槦鍑犱釜瀛楃銆�
+ */
+ private Integer pdfTextPageThreshold = 30;
+
+ /** 鎵弿椤佃浆鍥炬椂鐨� DPI銆備綆浜� 200 鏃朵腑鏂囧瓧褰細绯婏紝澶氭ā鎬佹ā鍨嬪鏄撹閿欙紱璋冮珮鍒欐瘡娆¤皟鐢ㄦ洿璐� */
+ private Integer renderDpi = 200;
+
+ /** Excel 鍗曡〃鏈�澶氳鍙栫殑琛屾暟锛岄槻姝㈣秴澶ц〃鎶婃彁绀鸿瘝鎾戠垎 */
+ private Integer maxXlsxRows = 300;
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/config/QcReportPdfProperties.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/config/QcReportPdfProperties.java
new file mode 100644
index 0000000..816baea
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/config/QcReportPdfProperties.java
@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.qcreport.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * PDF 鍑轰欢閰嶇疆
+ * <p>
+ * 瀵瑰簲 application.yml 涓殑 yudao.qcreport.pdf 鍓嶇紑閰嶇疆銆�
+ */
+@Component
+@ConfigurationProperties(prefix = "yudao.qcreport.pdf", ignoreUnknownFields = true)
+@Data
+public class QcReportPdfProperties {
+
+ /** 鏄惁鍚敤 PDF 鍑轰欢銆傞儴缃茬幆澧冩病鏈夋祻瑙堝櫒鏃跺叧鎺夊畠锛屾帴鍙d細鏄庣‘鎶ャ�屾湭鍚敤銆嶈�屼笉鏄姏 500 */
+ private Boolean enabled = true;
+
+ /**
+ * 娴忚鍣ㄩ�氶亾锛屽 chrome / msedge锛涚暀绌哄垯鐢� Playwright 鑷甫鐨� Chromium
+ * 锛堝悗鑰呴渶瑕佸厛鎵ц {@code playwright install chromium} 涓嬭浇锛岀害 150MB锛夈��
+ */
+ private String channel = "chrome";
+
+ /** 娴忚鍣ㄥ彲鎵ц鏂囦欢璺緞銆傞厤浜嗗氨浼樺厛浜� {@link #channel}锛岀敤浜庤鍦ㄩ潪鏍囧噯浣嶇疆鐨勬祻瑙堝櫒 */
+ private String executablePath = "";
+
+ /** 鍚屾椂杩涜鐨� PDF 娓叉煋涓婇檺銆侰hromium 寰堝悆鍐呭瓨锛屽苟鍙戝繀椤昏闂� */
+ private Integer concurrency = 2;
+
+ /** 鍗曟娓叉煋瓒呮椂锛堟绉掞級锛屽悓鏃剁敤浜庣瓑寰呴〉闈㈣祫婧愪笌绛夊緟骞跺彂鍚嶉 */
+ private Long timeoutMs = 30000L;
+
+ /** 椤佃剼鏄惁鎵撳嵃銆岀 N 椤� / 鍏� M 椤点�� */
+ private Boolean showPageNumber = true;
+
+ /** 棰濆鐨勬祻瑙堝櫒鍚姩鍙傛暟锛屽 Linux 浠� root 杩愯闇�鍔� --no-sandbox */
+ private List<String> browserArgs = new ArrayList<>();
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/aiimport/QcReportAiImportController.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/aiimport/QcReportAiImportController.java
new file mode 100644
index 0000000..02b1c35
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/aiimport/QcReportAiImportController.java
@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.qcreport.controller.admin.aiimport;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.module.qcreport.controller.admin.aiimport.vo.QcReportAiDraftReqVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.aiimport.vo.QcReportAiDraftRespVO;
+import cn.iocoder.yudao.module.qcreport.service.aiimport.QcReportAiImportService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+/**
+ * 鏅鸿兘璐ㄦ鎶ュ憡 AI 瀵煎叆 Controller銆�
+ * <p>
+ * 鍙湁涓�涓鐐癸紝涓�<b>涓嶆帴鏀舵枃浠�</b>锛氭枃浠跺厛鐢卞墠绔紶鍒� system 妯″潡鎷垮埌 blobId锛屽啀杩炲悓缁勪欢娓呭崟涓�璧锋彁浜ゃ��
+ * 涓氬姟妯″潡鑷缓涓婁紶閫氶亾浼氱粫寮�缁熶竴鐨勫瓨鍌ㄩ厤缃笌闄勪欢褰掑睘锛堣 file-upload.md锛夛紝
+ * 鎵�浠ヨ繖閲岃繛 {@code MultipartFile} 閮戒笉鍑虹幇鍦ㄧ鍚嶉噷銆�
+ */
+@Tag(name = "绠$悊鍚庡彴 - 鏅鸿兘璐ㄦ鎶ュ憡 AI 瀵煎叆")
+@RestController
+@RequestMapping("/qc-report/ai-import")
+@Validated
+public class QcReportAiImportController {
+
+ @Resource
+ private QcReportAiImportService aiImportService;
+
+ @PostMapping("/draft")
+ @Operation(summary = "璇嗗埆鏂囦欢鐢熸垚妯℃澘鑽夌",
+ description = "鍚屾杩斿洖锛屼笉钀藉簱銆傝瘑鍒嚭鐨勫彧鏄崏绋匡紝闇�鍦ㄨ璁″櫒浜哄伐纭鍚庣敱銆屼繚瀛樸�嶈惤涓烘寮忕増鏈�")
+ @PreAuthorize("@ss.hasPermission('qc-report:template:ai-import')")
+ public CommonResult<QcReportAiDraftRespVO> generateDraft(@Valid @RequestBody QcReportAiDraftReqVO reqVO) {
+ return success(aiImportService.generateDraft(reqVO));
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/aiimport/vo/QcReportAiDraftReqVO.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/aiimport/vo/QcReportAiDraftReqVO.java
new file mode 100644
index 0000000..e581aeb
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/aiimport/vo/QcReportAiDraftReqVO.java
@@ -0,0 +1,52 @@
+package cn.iocoder.yudao.module.qcreport.controller.admin.aiimport.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * AI 璇嗗埆鏂囦欢鐢熸垚妯℃澘鑽夌鐨勫叆鍙傘��
+ * <p>
+ * 鏂囦欢涓嶈蛋杩欓噷涓婁紶锛氬厛鐢卞墠绔皟 system 妯″潡鐨� {@code /system/storage-blob/upload} 鎷垮埌 blobId锛�
+ * 鍐嶆妸 blobId 浜ょ粰鏈帴鍙c�備笟鍔℃ā鍧椾笉鑷缓涓婁紶閫氶亾锛屼篃涓嶇 MultipartFile锛堣 file-upload.md锛夈��
+ * <p>
+ * 杩斿洖鐨勫彧鏄�**鑽夌**锛屼笉钀藉簱銆備汉宸ュ湪璁捐鍣ㄩ噷纭銆佽皟鏁村苟鐐逛繚瀛橈紝鎵嶄細鐪熸鍐欏叆妯℃澘鐗堟湰銆�
+ */
+@Schema(description = "绠$悊鍚庡彴 - 鏅鸿兘璐ㄦ鎶ュ憡 AI 妯℃澘鑽夌 Request VO")
+@Data
+public class QcReportAiDraftReqVO {
+
+ /**
+ * 鏂囦欢鏁伴噺涓婇檺**涓嶅湪娉ㄨВ閲屽啓姝�**锛氬畠鐢� {@code yudao.qcreport.ai-import.max-files} 鍐冲畾锛�
+ * 鏈嶅姟灞傚湪璇诲彇浠讳綍鏂囦欢涔嬪墠鍏堟瘮瀵归厤缃�煎苟缁欏嚭甯︿袱涓疄闄呭�肩殑鎻愮ず銆�
+ * 杩欓噷鍐嶅啓涓�涓暟瀛楀氨鏄浜屼釜鐪熺浉鏉ユ簮鈥斺�斿畠涓庨厤缃笉鍚屾鏃讹紝鐢ㄦ埛鐪嬪埌鐨勪笂闄愪笌鐪熸鐢熸晥鐨勪笂闄愬涓嶄笂锛�
+ * 鑰屼笖娉ㄨВ姘歌繙鍙細鏇翠弗锛岄厤缃究鍙暍寰�涓嬭皟銆�
+ */
+ @Schema(description = "涓婁紶鏂囦欢瀵瑰簲鐨� blobId 鍒楄〃锛岄『搴忓嵆鏂囨。椤靛簭銆備釜鏁颁笂闄愯 yudao.qcreport.ai-import.max-files",
+ requiredMode = Schema.RequiredMode.REQUIRED, example = "[2048, 2049]")
+ @NotEmpty(message = "璇疯嚦灏戜笂浼犱竴涓枃浠�")
+ private List<Long> blobIds;
+
+ @Schema(description = "鐩爣妯℃澘缂栧彿锛岀敤浜庢棩蹇楃暀鐥曚笌闄勪欢褰掑睘", requiredMode = Schema.RequiredMode.REQUIRED,
+ example = "5")
+ @NotNull(message = "妯℃澘缂栧彿涓嶈兘涓虹┖")
+ private Long templateId;
+
+ @Schema(description = "鍓嶇缁勪欢娓呭崟鐨� Schema 鐗堟湰銆備袱绔笉涓�鑷存椂鐩存帴鎶ラ敊锛�"
+ + "閬垮厤妯″瀷鍩轰簬杩囨湡鐨勭Н鏈ㄦ竻鍗曠紪鍑烘敞鍐岃〃閲屼笉瀛樺湪鐨勭粍浠�",
+ requiredMode = Schema.RequiredMode.REQUIRED, example = "1.1")
+ @NotBlank(message = "Schema 鐗堟湰涓嶈兘涓虹┖")
+ private String schemaVersion;
+
+ @Schema(description = "鍙敤缁勪欢绉湪娓呭崟锛岀敱鍓嶇浠庢椿娉ㄥ唽琛ㄧ敓鎴�", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotEmpty(message = "缁勪欢娓呭崟涓嶈兘涓虹┖")
+ private List<QcReportComponentSpecVO> catalog;
+
+ @Schema(description = "鐢ㄦ埛琛ュ厖璇存槑锛屼細鎷艰繘鎻愮ず璇嶅府鍔╂ā鍨嬬悊瑙f枃妗�", example = "杩欐槸 IQC 鏉ユ枡妫�楠屾姤鍛�")
+ private String hint;
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/aiimport/vo/QcReportAiDraftRespVO.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/aiimport/vo/QcReportAiDraftRespVO.java
new file mode 100644
index 0000000..f9d699a
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/aiimport/vo/QcReportAiDraftRespVO.java
@@ -0,0 +1,69 @@
+package cn.iocoder.yudao.module.qcreport.controller.admin.aiimport.vo;
+
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.version.ReportTemplateSchema;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * AI 璇嗗埆缁撴灉锛氫竴浠�**妯℃澘鑽夌**锛屼笉钀藉簱銆�
+ * <p>
+ * 鍒绘剰涓嶈繑鍥� {@link ReportTemplateSchema}锛氳崏绋垮彧鏄�屼竴涓茬粍浠� + 鍚勮嚜鐨勫睘鎬с�嶈繖涓洿灏忕殑鐗╁寲褰㈡�侊紝
+ * 鐢卞墠绔閰嶅櫒閰嶄笂娲绘敞鍐岃〃鎵嶈兘缂栬瘧鎴愮敾甯冩暟鎹紙{@code grapes}锛夈�傝鍚庣浜у嚭瀹屾暣 Schema
+ * 灏卞緱鍦ㄨ繖閲屽啀瀹炵幇涓�閬嶇粍浠剁殑 canvas 缁撴瀯锛岀瓑浜庢妸娓叉煋寮曟搸鐨勮亴璐f妱杩� AI 妯″潡锛岃繕浼氳
+ * Schema 濂戠害涓轰簡 AI 鑰岃啫鑳�鈥斺�旇涔夊眰鏄埢鎰忔敹绐勭殑瀛愰泦锛屼笉璇ヤ负杩欐潯璺紑鍙e瓙銆�
+ * <p>
+ * 鍥犳鑽夌鐨勬秷璐硅�呭彧鏈夊墠绔閰嶅櫒锛氬畠閫愰」鏌ユ敞鍐岃〃锛屾湭娉ㄥ唽鐨� type 鐩存帴璺宠繃銆�
+ * 鍗充究妯″瀷缂栧嚭娓呭崟澶栫殑缁勪欢锛屼篃姘歌繙鍙樹笉鎴愪换鎰� HTML銆�
+ *
+ * <h3>涓轰粈涔堟病鏈� rawText 瀛楁</h3>
+ * 娌¤В鏋愬嚭鏉ユ椂鏈帴鍙g洿鎺ユ姏閿欙紙{@code AI_IMPORT_RESPONSE_UNPARSEABLE}锛夛紝鍝嶅簲浣撴槸閿欒缁撴瀯鑰岄潪鏈� VO锛�
+ * 濉炰竴涓亽涓� null 鐨勫瓧娈靛彧浼氳鍚庢潵浜轰互涓恒�岃В鏋愬け璐ユ椂鍓嶇鑳芥嬁鍒板師鏂囥�嶃�傛ā鍨嬪師鏂囧啓杩涗簡鏈嶅姟绔棩蹇椼��
+ */
+@Schema(description = "绠$悊鍚庡彴 - 鏅鸿兘璐ㄦ鎶ュ憡 AI 妯℃澘鑽夌 Response VO")
+@Data
+public class QcReportAiDraftRespVO {
+
+ @Schema(description = "AI 璇嗗埆鍑虹殑缁勪欢鑽夌锛屾寜鎶ュ憡浠庝笂鍒颁笅鐨勯『搴忥紱宸插仛杩囧悎骞跺幓閲嶄笌闈炴硶椤硅繃婊�",
+ requiredMode = Schema.RequiredMode.REQUIRED)
+ private List<DraftComponent> components;
+
+ @Schema(description = "AI 鐚滄祴鐨勭焊寮犻厤缃紝鍙兘涓虹┖锛堜负绌鸿〃绀烘寜褰撳墠妯℃澘鐨勭焊寮犺蛋锛�")
+ private ReportTemplateSchema.Page page;
+
+ @Schema(description = "AI 瀵硅繖浠芥枃妗g殑涓�鍙ヨ瘽璇存槑锛屽睍绀哄湪棰勮寮圭獥椤堕儴")
+ private String summary;
+
+ /**
+ * 杞け璐ユ竻鍗曪細琚烦杩囩殑椤点�佹棤娉曡〃杈剧殑鍖哄潡銆佽涓㈠純鐨勬湭鐭ョ粍浠剁瓑銆�
+ * <p>
+ * 涓庛�屾暣浣撳け璐ユ姏寮傚父銆嶆槸涓ゅ洖浜嬶細杩欎簺鎯呭喌涓嶅奖鍝嶈崏绋垮彲鐢紝浣嗗繀椤昏鐢ㄦ埛鐪嬭锛�
+ * 鍚﹀垯浼氫互涓烘枃浠堕噷鐨勫唴瀹归兘璇嗗埆鍒颁簡銆�
+ */
+ @Schema(description = "璇嗗埆杩囩▼涓殑杞彁绀猴紝闇�鍦ㄧ晫闈笂灞曠ず缁欑敤鎴�")
+ private List<String> warnings;
+
+ @Schema(description = "璇嗗埆鎬昏�楁椂锛堟绉掞級锛屽惈澶氭妯″瀷璋冪敤", example = "12400")
+ private Long durationMs;
+
+ /**
+ * 涓�涓粍浠惰崏绋裤��
+ * <p>
+ * 缁撴瀯瀹屽叏鎵佸钩锛氭病鏈� children銆佹病鏈夊祵濂椼�俻rops 鐨� key 鐢卞墠绔Н鏈ㄦ竻鍗曞畾涔夛紝
+ * 鍥犳杩欓噷鐢� {@code Map} 鑰屼笉鏄己绫诲瀷鈥斺�斿悎娉� key 鐨勬潈濞佸湪鍓嶇娉ㄥ唽琛紝鍚庣涓嶈閲嶅澹版槑涓�閬嶃��
+ */
+ @Schema(description = "绠$悊鍚庡彴 - AI 鑽夌閲岀殑涓�涓粍浠�")
+ @Data
+ public static class DraftComponent {
+
+ @Schema(description = "缁勪欢绫诲瀷锛屽繀椤绘槸绉湪娓呭崟閲屽0鏄庤繃鐨� type", example = "QualityTable")
+ private String type;
+
+ @Schema(description = "缁勪欢灞炴�э紱娓呭崟閲屾湭澹版槑鐨� key 宸茶鍚庣涓㈠純")
+ private Map<String, Object> props;
+
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/aiimport/vo/QcReportComponentSpecVO.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/aiimport/vo/QcReportComponentSpecVO.java
new file mode 100644
index 0000000..7a2f7f6
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/aiimport/vo/QcReportComponentSpecVO.java
@@ -0,0 +1,67 @@
+package cn.iocoder.yudao.module.qcreport.controller.admin.aiimport.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 缁勪欢绉湪娓呭崟鐨勪竴椤癸細鍓嶇娉ㄥ唽琛ㄧ殑**娲剧敓瑙嗗浘**锛屽杺缁欏ぇ妯″瀷褰撱�屽彲鐢ㄧН鏈ㄣ�嶃��
+ * <p>
+ * 鐢卞墠绔粠娲绘敞鍐岃〃鐢熸垚锛堝墺鎺� icon / buildContent / validate 杩欎簺涓嶅彲搴忓垪鍖栫殑鎴愬憳锛夊悗闅忚姹備笂浼犮��
+ * <b>鍚庣鍒绘剰涓嶇‖缂栫爜杩欎唤娓呭崟</b>锛氭敞鍐岃〃鍦ㄥ墠绔槸鍞竴鐪熺浉鏉ユ簮锛屽悗绔妱涓�浠藉氨鏄浜屼釜鐪熺浉鏉ユ簮锛�
+ * 鍓嶇鍔犱簡缁勪欢銆佹敼浜嗗繀濉瓧娈垫椂鍚庣鍓湰浼氶潤榛樿繃鏈燂紝澶фā鍨嬮殢鍗充細缂栧嚭娉ㄥ唽琛ㄩ噷鏍规湰涓嶅瓨鍦ㄧ殑 type銆�
+ * <p>
+ * 绉湪娓呭崟鍙敤浜庢嫾 prompt銆傚悗绔�**涓嶆嵁姝ゅ仛浠讳綍娓叉煋鎴栧悎娉曟�ф帹鏂�**鈥斺��
+ * 鐪熸鎶婂叧鐨勬槸鍓嶇瑁呴厤鍣ㄦ煡璇㈡椿娉ㄥ唽琛紱鏈敞鍐岀殑 type 鍦ㄩ偅閲屼細琚洿鎺ヨ烦杩囷紝浜т笉鍑轰换鎰� HTML銆�
+ */
+@Schema(description = "绠$悊鍚庡彴 - 鏅鸿兘璐ㄦ鎶ュ憡 AI 绉湪娓呭崟椤�")
+@Data
+public class QcReportComponentSpecVO {
+
+ @Schema(description = "缁勪欢绫诲瀷锛屽 ReportHeader / QualityTable", requiredMode = Schema.RequiredMode.REQUIRED,
+ example = "QualityTable")
+ private String type;
+
+ @Schema(description = "缁勪欢鏄剧ず鍚嶏紝渚涙ā鍨嬬悊瑙h涔�", example = "妫�楠岄」鐩〃鏍�")
+ private String label;
+
+ @Schema(description = "缁勪欢鍒嗙被锛屽 basic / data / result", example = "data")
+ private String category;
+
+ @Schema(description = "閫夊瀷璇存槑锛氳繖涓粍浠剁敤鏉ユ斁浠�涔堛�佷笉瑕佺敤鏉ユ斁浠�涔�",
+ example = "鏂囨。鏈�椤堕儴鐨勬姮澶村潡锛氬叕鍙稿悕绉般�佹姤鍛婃爣棰樸�佹姤鍛婄紪鍙�")
+ private String hint;
+
+ @Schema(description = "璇ョ粍浠跺厑璁稿~鍐欑殑灞炴�у瓧娈碉紱鏈湪姝ゅ0鏄庣殑 key 涓�寰嬩細琚涪寮�")
+ private List<Field> fields;
+
+ /**
+ * 涓�涓彲濉睘鎬с�傚彧淇濈暀妯″瀷闇�瑕佺煡閬撶殑閮ㄥ垎锛屽瓧娈电被鍨嬪悓鏍风敱鍓嶇娉ㄥ唽琛ㄧ粰鍑恒��
+ */
+ @Schema(description = "绠$悊鍚庡彴 - AI 绉湪娓呭崟鐨勫瓧娈甸」")
+ @Data
+ public static class Field {
+
+ @Schema(description = "灞炴�� key锛屽 itemsPath / title", requiredMode = Schema.RequiredMode.REQUIRED,
+ example = "itemsPath")
+ private String key;
+
+ @Schema(description = "瀛楁鏄剧ず鍚�", example = "妫�楠岄」鏁版嵁婧�")
+ private String label;
+
+ @Schema(description = "瀛楁绫诲瀷锛屽 text / number / boolean / enum / dataPath", example = "dataPath")
+ private String type;
+
+ @Schema(description = "鏄惁蹇呭~锛涘繀濉湭缁欐椂鍚庣浼氬湪 warnings 閲屾彁绀�")
+ private Boolean required;
+
+ @Schema(description = "鏄惁鏀寔鏁版嵁缁戝畾", example = "true")
+ private Boolean bindable;
+
+ @Schema(description = "鏋氫妇鍙�夊�硷紝浠呭湪 type=enum 鏃舵湁鎰忎箟")
+ private List<Object> enumOptions;
+
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/QcReportInstanceController.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/QcReportInstanceController.java
new file mode 100644
index 0000000..5268391
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/QcReportInstanceController.java
@@ -0,0 +1,172 @@
+package cn.iocoder.yudao.module.qcreport.controller.admin.instance;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo.QcReportInstanceGenerateFromQcReqVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo.QcReportInstanceGenerateFromQcRespVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo.QcReportInstanceGenerateReqVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo.QcReportInstanceGenerateRespVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo.QcReportInstancePageReqVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo.QcReportInstancePdfRespVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo.QcReportInstancePreviewRespVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo.QcReportInstanceRegenerateRespVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo.QcReportInstanceRespVO;
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.instance.QcReportInstanceDO;
+import cn.iocoder.yudao.module.qcreport.engine.render.RenderOutcome;
+import cn.iocoder.yudao.module.qcreport.service.instance.GenerateFromQcResult;
+import cn.iocoder.yudao.module.qcreport.service.instance.GenerateResult;
+import cn.iocoder.yudao.module.qcreport.service.instance.PdfArchiveResult;
+import cn.iocoder.yudao.module.qcreport.service.instance.QcReportInstanceService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+/**
+ * 鏅鸿兘璐ㄦ鎶ュ憡瀹炰緥 Controller銆�
+ * <p>
+ * 杩欓噷鏄�屾ā鏉� 鈫� 鎶ュ憡銆嶇殑瀵瑰鍏ュ彛锛氶瑙堝彧娓蹭笉瀛橈紝鍑轰欢鎵嶈惤搴撳苟鍐荤粨鏁版嵁蹇収銆�
+ * 鏁版嵁鐢辫皟鐢ㄦ柟浼犲叆锛屾湰妯″潡涓嶈璇嗕换浣曚笟鍔″崟鎹��
+ */
+@Tag(name = "绠$悊鍚庡彴 - 鏅鸿兘璐ㄦ鎶ュ憡瀹炰緥")
+@RestController
+@RequestMapping("/qc-report/instance")
+@Validated
+public class QcReportInstanceController {
+
+ @Resource
+ private QcReportInstanceService instanceService;
+
+ @PostMapping("/preview")
+ @Operation(summary = "棰勮鎶ュ憡锛堝彧娓叉煋锛屼笉钀藉簱銆佷笉娑堣�楁姤鍛婄紪鍙凤級")
+ @PreAuthorize("@ss.hasPermission('qc-report:instance:query')")
+ public CommonResult<QcReportInstancePreviewRespVO> preview(@Valid @RequestBody QcReportInstanceGenerateReqVO reqVO) {
+ RenderOutcome outcome = instanceService.preview(reqVO);
+ QcReportInstancePreviewRespVO respVO = new QcReportInstancePreviewRespVO();
+ respVO.setReportNo(outcome.context().getReport() == null ? null : outcome.context().getReport().getReportNo());
+ respVO.setHtml(outcome.html());
+ respVO.setErrors(outcome.errors());
+ return success(respVO);
+ }
+
+ @PostMapping("/generate")
+ @Operation(summary = "鍑轰欢锛氭覆鏌� + 钀藉簱 + 鍐荤粨鏁版嵁蹇収")
+ @PreAuthorize("@ss.hasPermission('qc-report:instance:create')")
+ public CommonResult<QcReportInstanceGenerateRespVO> generate(
+ @Valid @RequestBody QcReportInstanceGenerateReqVO reqVO) {
+ return success(toGenerateRespVO(instanceService.generate(reqVO)));
+ }
+
+ @PostMapping("/generate-from-qc")
+ @Operation(summary = "鐢辫川妫�鍗曠敓鎴愭姤鍛婏紙鏁版嵁浠� MES 鍙栵紝妯℃澘鐢辩敤鎴烽�夋嫨锛�")
+ @PreAuthorize("@ss.hasPermission('qc-report:instance:generate')")
+ public CommonResult<QcReportInstanceGenerateFromQcRespVO> generateFromQc(
+ @Valid @RequestBody QcReportInstanceGenerateFromQcReqVO reqVO) {
+ GenerateFromQcResult result = instanceService.generateFromQc(reqVO);
+ QcReportInstanceGenerateFromQcRespVO respVO = new QcReportInstanceGenerateFromQcRespVO();
+ respVO.setId(result.instance().getId());
+ respVO.setReportNo(result.instance().getReportNo());
+ respVO.setTemplateVersion(result.instance().getTemplateVersion());
+ respVO.setItemCount(result.itemCount());
+ respVO.setUndecidableCount(result.undecidableCount());
+ respVO.setWarnings(result.warnings());
+ respVO.setErrors(result.errors());
+ return success(respVO);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "鑾峰緱鎶ュ憡瀹炰緥锛堝惈娓叉煋浜х墿 HTML锛屼笉鍚暟鎹揩鐓э級")
+ @Parameter(name = "id", description = "瀹炰緥缂栧彿", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('qc-report:instance:query')")
+ public CommonResult<QcReportInstanceRespVO> getInstance(@RequestParam("id") Long id) {
+ QcReportInstanceDO instance = instanceService.getInstance(id);
+ return success(BeanUtils.toBean(instance, QcReportInstanceRespVO.class));
+ }
+
+ @GetMapping("/snapshot")
+ @Operation(summary = "鑾峰緱鎶ュ憡瀹炰緥鍐荤粨鐨勬暟鎹揩鐓�")
+ @Parameter(name = "id", description = "瀹炰緥缂栧彿", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('qc-report:instance:query')")
+ public CommonResult<Map<String, Object>> getSnapshot(@RequestParam("id") Long id) {
+ return success(instanceService.getSnapshot(id));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "鑾峰緱鎶ュ憡瀹炰緥鍒嗛〉")
+ @PreAuthorize("@ss.hasPermission('qc-report:instance:query')")
+ public CommonResult<PageResult<QcReportInstanceRespVO>> getInstancePage(
+ @Valid QcReportInstancePageReqVO pageReqVO) {
+ PageResult<QcReportInstanceDO> pageResult = instanceService.getInstancePage(pageReqVO);
+ return success(BeanUtils.toBean(pageResult, QcReportInstanceRespVO.class));
+ }
+
+ @PostMapping("/regenerate")
+ @Operation(summary = "閲嶆柊鐢熸垚鎶ュ憡锛堢敤鍐荤粨鐨勬暟鎹揩鐓� + 鍚屼竴妯℃澘鐗堟湰閲嶆覆锛岃鐩栦骇鐗� HTML锛�")
+ @Parameter(name = "id", description = "瀹炰緥缂栧彿", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('qc-report:instance:create')")
+ public CommonResult<QcReportInstanceRegenerateRespVO> regenerate(@RequestParam("id") Long id) {
+ GenerateResult result = instanceService.regenerate(id);
+ QcReportInstanceRegenerateRespVO respVO = new QcReportInstanceRegenerateRespVO();
+ respVO.setId(result.instance().getId());
+ respVO.setReportNo(result.instance().getReportNo());
+ respVO.setErrors(result.errors());
+ return success(respVO);
+ }
+
+ @PostMapping("/pdf")
+ @Operation(summary = "瀵煎嚭 PDF锛堟墦鍗板疄渚嬪凡瀛樼殑浜х墿 HTML 骞跺綊妗e埌闄勪欢搴擄紝鍙噸澶嶈皟鐢級")
+ @Parameter(name = "id", description = "瀹炰緥缂栧彿", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('qc-report:instance:export')")
+ public CommonResult<QcReportInstancePdfRespVO> exportPdf(@RequestParam("id") Long id) {
+ PdfArchiveResult result = instanceService.exportPdf(id);
+ QcReportInstancePdfRespVO respVO = new QcReportInstancePdfRespVO();
+ respVO.setId(result.instanceId());
+ respVO.setReportNo(result.reportNo());
+ respVO.setFileName(result.fileName());
+ respVO.setByteSize(result.byteSize());
+ respVO.setBlobId(result.blobId());
+ respVO.setAttachmentId(result.attachmentId());
+ respVO.setPreviewURL(result.previewURL());
+ respVO.setDownloadURL(result.downloadURL());
+ respVO.setDurationMs(result.durationMs());
+ respVO.setPdfDurationMs(result.pdfDurationMs());
+ respVO.setBrowserStatus(result.browserStatus());
+ return success(respVO);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "鍒犻櫎鎶ュ憡瀹炰緥")
+ @Parameter(name = "id", description = "瀹炰緥缂栧彿", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('qc-report:instance:delete')")
+ public CommonResult<Boolean> deleteInstance(@RequestParam("id") Long id) {
+ instanceService.deleteInstance(id);
+ return success(true);
+ }
+
+ private QcReportInstanceGenerateRespVO toGenerateRespVO(GenerateResult result) {
+ QcReportInstanceDO instance = result.instance();
+ QcReportInstanceGenerateRespVO respVO = new QcReportInstanceGenerateRespVO();
+ respVO.setId(instance.getId());
+ respVO.setReportNo(instance.getReportNo());
+ respVO.setTemplateVersion(instance.getTemplateVersion());
+ respVO.setStatus(instance.getStatus());
+ respVO.setErrors(result.errors());
+ return respVO;
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceGenerateFromQcReqVO.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceGenerateFromQcReqVO.java
new file mode 100644
index 0000000..60f9125
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceGenerateFromQcReqVO.java
@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+/**
+ * 鐢辫川妫�鍗曠敓鎴愭姤鍛婄殑鍏ュ弬銆�
+ * <p>
+ * 涓� {@link QcReportInstanceGenerateReqVO} 鐨勫尯鍒細閭d釜鏀剁殑鏄凡缁忔嫾濂界殑鎶ュ憡涓婁笅鏂囷紝
+ * 杩欎釜鍙敹銆屽摢寮犺川妫�鍗� + 鐢ㄥ摢涓ā鏉裤�嶏紝鏁版嵁鐢辨湇鍔$浠� MES 鍙栥��
+ * 浜哄伐閫夋ā鏉挎槸鏃㈠畾鍙e緞 鈥斺�� 鍚屼竴寮犺川妫�鍗曞彲浠ョ敤涓嶅悓妯℃澘鍑轰笉鍚岀敤閫旂殑鎶ュ憡锛堝唴閮ㄧ増 / 瀹㈡埛鐗堬級銆�
+ */
+@Schema(description = "绠$悊鍚庡彴 - 鐢辫川妫�鍗曠敓鎴愭姤鍛� Request VO")
+@Data
+public class QcReportInstanceGenerateFromQcReqVO {
+
+ @Schema(description = "璐ㄦ绫诲瀷锛�1 鏉ユ枡 2 杩囩▼ 3 鍑鸿揣 4 閫�璐�", requiredMode = Schema.RequiredMode.REQUIRED,
+ example = "1")
+ @NotNull(message = "璐ㄦ绫诲瀷涓嶈兘涓虹┖")
+ private Integer qcType;
+
+ @Schema(description = "璐ㄦ鍗曠紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @NotNull(message = "璐ㄦ鍗曠紪鍙蜂笉鑳戒负绌�")
+ private Long qcId;
+
+ @Schema(description = "鎶ュ憡妯℃澘缂栧彿锛岀敱鐢ㄦ埛閫夋嫨", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "鎶ュ憡妯℃澘缂栧彿涓嶈兘涓虹┖")
+ private Long templateId;
+
+ @Schema(description = "鎶ュ憡妯℃澘鐗堟湰鍙枫�備笉浼犲垯鐢ㄦā鏉垮綋鍓嶅凡鍙戝竷鐨勭増鏈�", example = "v1.0")
+ private String version;
+
+ @Schema(description = "鎶ュ憡缂栧彿銆備笉浼犲垯鎸� QR+鏃ユ湡+娴佹按 鑷姩鐢熸垚", example = "QR20260919-0001")
+ private String reportNo;
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceGenerateFromQcRespVO.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceGenerateFromQcRespVO.java
new file mode 100644
index 0000000..b9571af
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceGenerateFromQcRespVO.java
@@ -0,0 +1,41 @@
+package cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 鐢辫川妫�鍗曠敓鎴愭姤鍛婄殑鍝嶅簲銆�
+ * <p>
+ * 闄や簡銆岀敓鎴愪簡鍝唤鎶ュ憡銆嶏紝杩樺繀椤绘妸銆岃繖浠芥姤鍛婃湁浠�涔堟瘺鐥呫�嶄竴璧峰甫鍥炴潵锛�
+ * {@link #undecidableCount} 鏄叾涓渶鍏抽敭鐨勪竴鏉� 鈥斺�� 妫�楠屾ā鏉块噷娌¢厤瑙勬牸涓婁笅闄愭椂锛�
+ * 妫�楠岄」浼氭垚鐗囧垽涓嶅嚭鏉ワ紝鎶ュ憡鐪嬭捣鏉ュ儚鍧忎簡锛屽叾瀹炴槸鏁版嵁娌¢厤鍏ㄣ�傚墠绔繀椤绘嵁姝ゆ彁绀恒��
+ */
+@Schema(description = "绠$悊鍚庡彴 - 鐢辫川妫�鍗曠敓鎴愭姤鍛� Response VO")
+@Data
+public class QcReportInstanceGenerateFromQcRespVO {
+
+ @Schema(description = "鎶ュ憡瀹炰緥缂栧彿", example = "2048")
+ private Long id;
+
+ @Schema(description = "鎶ュ憡缂栧彿", example = "QR20260919-0001")
+ private String reportNo;
+
+ @Schema(description = "瀹為檯浣跨敤鐨勬ā鏉跨増鏈�", example = "v1.0")
+ private String templateVersion;
+
+ @Schema(description = "鏈鍐欏叆鐨勬楠岄」鏉℃暟", example = "13")
+ private Integer itemCount;
+
+ @Schema(description = "娌℃湁鍒ゅ畾缁撹鐨勯」鏁帮紙銆屾棤鍒ゅ畾瑙勫垯銆�+ 瑙勫垯鎵ц澶辫触鐨勩�屽緟鍒ゅ畾銆嶏級", example = "13")
+ private Integer undecidableCount;
+
+ @Schema(description = "杞彁绀猴細鏍峰搧鐨勫彇鑸嶃�佽烦杩囩殑鍒嗙粍椤广�佸皻鏈綍鍏ュ疄娴嬪�肩殑椤�")
+ private List<String> warnings = new ArrayList<>();
+
+ @Schema(description = "娓叉煋鏈熸暟鎹己鍙o細妯℃澘缁戝畾浜嗕絾褰撴椂娌℃湁鍊肩殑瀛楁")
+ private List<String> errors = new ArrayList<>();
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceGenerateReqVO.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceGenerateReqVO.java
new file mode 100644
index 0000000..2bde83f
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceGenerateReqVO.java
@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo;
+
+import cn.iocoder.yudao.module.qcreport.engine.context.ReportContext;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+/**
+ * 鍑轰欢锛堟覆鏌撳苟钀藉簱鎶ュ憡瀹炰緥锛夌殑鍏ュ弬锛岄瑙堟帴鍙d篃澶嶇敤瀹冦��
+ * <p>
+ * {@link #context} 鐩存帴鐢ㄥ紩鎿庣殑 {@link ReportContext}锛屼笉鍙﹂�犱竴涓暅鍍� VO锛�
+ * 閭e氨鏄繖涓钩鍙板澶栧敮涓�鐨勬暟鎹绾︼紝闀滃儚鍑烘潵鍙槸澶氫竴浠介渶瑕佸悓姝ョ淮鎶ょ殑瀛楁娓呭崟銆�
+ * 瀛楁绾х殑杈圭晫鏍¢獙鏀惧湪 Service 閲屽仛锛屽紩鎿庡疄浣撴湰韬笉鎸傛牎楠屾敞瑙c��
+ */
+@Schema(description = "绠$悊鍚庡彴 - 鏅鸿兘璐ㄦ鎶ュ憡鍑轰欢 Request VO")
+@Data
+public class QcReportInstanceGenerateReqVO {
+
+ @Schema(description = "妯℃澘缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
+ @NotNull(message = "妯℃澘缂栧彿涓嶈兘涓虹┖")
+ private Long templateId;
+
+ @Schema(description = "妯℃澘鐗堟湰鍙枫�備笉浼犲垯鐢ㄦā鏉垮綋鍓嶅凡鍙戝竷鐨勭増鏈�", example = "v1.0")
+ private String version;
+
+ @Schema(description = "鎶ュ憡缂栧彿銆備笉浼犲垯鎸� QR+鏃ユ湡+娴佹按 鑷姩鐢熸垚", example = "QR20260918-0001")
+ private String reportNo;
+
+ @Schema(description = "涓氬姟鍗曟嵁缂栧彿锛岀敤浜庡皢鏉ユ寜鍗曟嵁鍙嶆煡鎶ュ憡", example = "1024")
+ private String businessId;
+
+ @Schema(description = "涓氬姟鍗曟嵁绫诲瀷锛屽 mes_qc_iqc / mes_qc_ipqc / mes_qc_oqc / mes_qc_rqc", example = "mes_qc_oqc")
+ private String businessType;
+
+ @Schema(description = "鎶ュ憡鏁版嵁涓婁笅鏂囷細鎶ュ憡绾у瓧娈� + 妫�楠岄」鍒楄〃", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotNull(message = "鎶ュ憡鏁版嵁涓嶈兘涓虹┖")
+ private ReportContext context;
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceGenerateRespVO.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceGenerateRespVO.java
new file mode 100644
index 0000000..5794b58
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceGenerateRespVO.java
@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 鍑轰欢缁撴灉銆�
+ * <p>
+ * 涓嶅洖 HTML锛堝彲鑳藉緢闀匡級锛岃姝f枃璇锋嬁 {@link #id} 鍘绘煡璇︽儏銆�
+ */
+@Schema(description = "绠$悊鍚庡彴 - 鏅鸿兘璐ㄦ鎶ュ憡鍑轰欢 Response VO")
+@Data
+public class QcReportInstanceGenerateRespVO {
+
+ @Schema(description = "瀹炰緥缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "鎶ュ憡缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "QR20260918-0001")
+ private String reportNo;
+
+ @Schema(description = "鐢熸垚鏃朵娇鐢ㄧ殑妯℃澘鐗堟湰鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "v1.0")
+ private String templateVersion;
+
+ @Schema(description = "鎶ュ憡鐘舵�侊細0鐢熸垚涓� 1鐢熸垚鎴愬姛 2鐢熸垚澶辫触", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Integer status;
+
+ @Schema(description = "鏁版嵁缂哄彛娓呭崟锛氭姤鍛婂凡缁忓嚭鏉ヤ簡锛屼絾杩欎簺瀛楁褰撴椂娌℃湁鍊�")
+ private List<String> errors;
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstancePageReqVO.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstancePageReqVO.java
new file mode 100644
index 0000000..18c3a98
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstancePageReqVO.java
@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "绠$悊鍚庡彴 - 鏅鸿兘璐ㄦ鎶ュ憡瀹炰緥鍒嗛〉 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class QcReportInstancePageReqVO extends PageParam {
+
+ @Schema(description = "妯℃澘缂栧彿", example = "5")
+ private Long templateId;
+
+ @Schema(description = "鎶ュ憡缂栧彿锛堟ā绯婂尮閰嶏級", example = "QR20260918")
+ private String reportNo;
+
+ @Schema(description = "涓氬姟鍗曟嵁绫诲瀷", example = "mes_qc_oqc")
+ private String businessType;
+
+ @Schema(description = "涓氬姟鍗曟嵁缂栧彿", example = "1024")
+ private String businessId;
+
+ @Schema(description = "鎶ュ憡鐘舵�侊細0鐢熸垚涓� 1鐢熸垚鎴愬姛 2鐢熸垚澶辫触", example = "1")
+ private Integer status;
+
+ @Schema(description = "鍒涘缓鏃堕棿")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstancePdfRespVO.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstancePdfRespVO.java
new file mode 100644
index 0000000..23ae0bb
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstancePdfRespVO.java
@@ -0,0 +1,46 @@
+package cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * PDF 鍑轰欢缁撴灉锛氭妸瀹炰緥閲屽凡瀛樼殑娓叉煋浜х墿 HTML 鎵撳嵃鎴� PDF 骞跺綊妗e埌闄勪欢搴撱��
+ */
+@Schema(description = "绠$悊鍚庡彴 - 鏅鸿兘璐ㄦ鎶ュ憡 PDF 鍑轰欢 Response VO")
+@Data
+public class QcReportInstancePdfRespVO {
+
+ @Schema(description = "瀹炰緥缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "鎶ュ憡缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "QR20260918-0001")
+ private String reportNo;
+
+ @Schema(description = "PDF 鏂囦欢鍚�", requiredMode = Schema.RequiredMode.REQUIRED, example = "QR20260918-0001.pdf")
+ private String fileName;
+
+ @Schema(description = "PDF 瀛楄妭鏁�", requiredMode = Schema.RequiredMode.REQUIRED, example = "58214")
+ private Long byteSize;
+
+ @Schema(description = "鏂囦欢缂栧彿锛坰ystem_storage_blob 涓婚敭锛�", example = "2048")
+ private Long blobId;
+
+ @Schema(description = "闄勪欢鍏宠仈缂栧彿锛坰ystem_storage_attachment 涓婚敭锛�", example = "4096")
+ private Long attachmentId;
+
+ @Schema(description = "棰勮鍦板潃锛堜复鏃剁鍚嶏紝浼氳繃鏈燂紱瑕侀暱鏈熷彲鐢ㄨ閲嶆柊鏌ヨ闄勪欢鍒楄〃锛�")
+ private String previewURL;
+
+ @Schema(description = "涓嬭浇鍦板潃锛堜复鏃剁鍚嶏紝浼氳繃鏈燂紱瑕侀暱鏈熷彲鐢ㄨ閲嶆柊鏌ヨ闄勪欢鍒楄〃锛�")
+ private String downloadURL;
+
+ @Schema(description = "鏈鍑轰欢鎬昏�楁椂锛堟绉掞級", example = "1820")
+ private Long durationMs;
+
+ @Schema(description = "鎵撳嵃鑰楁椂锛堟绉掞級锛屼粎鍚瓑椤甸潰璧勬簮涓庢墦鍗帮紝涓庢�昏�楁椂涔嬪樊涓烘帓闃�/鍚姩绛夊緟", example = "940")
+ private Long pdfDurationMs;
+
+ @Schema(description = "娴忚鍣ㄧ姸鎬侊細READY锛堝鐢ㄥ凡鏈夊疄渚嬶級/ RESTARTED锛堟湰娆¢噸鍚簡娴忚鍣級", example = "READY")
+ private String browserStatus;
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstancePreviewRespVO.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstancePreviewRespVO.java
new file mode 100644
index 0000000..7fc00cb
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstancePreviewRespVO.java
@@ -0,0 +1,27 @@
+package cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 棰勮缁撴灉锛氬彧娓叉煋锛屼笉钀藉簱銆�
+ * <p>
+ * 棰勮**涓嶇敓鎴愩�佷笉娑堣��**鎶ュ憡缂栧彿娴佹按锛氭嬁鍒扮殑 {@link #reportNo} 鏄叆鍙傞噷甯﹁繃鏉ョ殑閭d釜锛�
+ * 娌″甫灏辨槸绌恒�傜湡姝g殑缂栧彿鍦ㄧ敓鎴愭椂纭畾銆�
+ */
+@Schema(description = "绠$悊鍚庡彴 - 鏅鸿兘璐ㄦ鎶ュ憡棰勮 Response VO")
+@Data
+public class QcReportInstancePreviewRespVO {
+
+ @Schema(description = "鏈娓叉煋浣跨敤鐨勬姤鍛婄紪鍙凤紙鏉ヨ嚜鍏ュ弬锛岄瑙堜笉鐢熸垚缂栧彿锛�", example = "QR20260918-0001")
+ private String reportNo;
+
+ @Schema(description = "娓叉煋浜х墿 HTML")
+ private String html;
+
+ @Schema(description = "鏁版嵁缂哄彛娓呭崟锛氭ā鏉跨粦瀹氫簡浣嗘暟鎹噷娌℃湁鐨勫瓧娈点�佽鎷︿笅鐨勪笉瀹夊叏灞炴�х瓑")
+ private List<String> errors;
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceRegenerateRespVO.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceRegenerateRespVO.java
new file mode 100644
index 0000000..8114493
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceRegenerateRespVO.java
@@ -0,0 +1,26 @@
+package cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 閲嶆柊鐢熸垚缁撴灉锛氱敤鍐荤粨鐨勬暟鎹揩鐓� + 鍚屼竴妯℃澘鐗堟湰閲嶆覆銆�
+ * <p>
+ * 鎶ュ憡缂栧彿涓庢暟鎹兘涓嶅彉锛屼骇鐗╂寜澶嶇幇鎬у簲褰撲笌棣栨鐢熸垚閫愬瓧鐩稿悓銆�
+ */
+@Schema(description = "绠$悊鍚庡彴 - 鏅鸿兘璐ㄦ鎶ュ憡閲嶆柊鐢熸垚 Response VO")
+@Data
+public class QcReportInstanceRegenerateRespVO {
+
+ @Schema(description = "瀹炰緥缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "鎶ュ憡缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "QR20260918-0001")
+ private String reportNo;
+
+ @Schema(description = "鏁版嵁缂哄彛娓呭崟")
+ private List<String> errors;
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceRespVO.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceRespVO.java
new file mode 100644
index 0000000..8bb1994
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/instance/vo/QcReportInstanceRespVO.java
@@ -0,0 +1,51 @@
+package cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 鎶ュ憡瀹炰緥鐨勫睍绀哄瓧娈点��
+ * <p>
+ * 鏈夋剰涓嶅惈 {@code dataSnapshot}锛氶偅鏄帓鏌ャ�岃繖浠藉巻鍙叉姤鍛婂綋鏃剁敤鐨勪粈涔堟暟鎹�嶇敤鐨勶紝
+ * 浣撶Н澶с�佸墠绔篃涓嶉渶瑕侊紝鍙栧畠璇疯蛋 {@code /qc-report/instance/snapshot}銆�
+ */
+@Schema(description = "绠$悊鍚庡彴 - 鏅鸿兘璐ㄦ鎶ュ憡瀹炰緥 Response VO")
+@Data
+public class QcReportInstanceRespVO {
+
+ @Schema(description = "瀹炰緥缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "鎶ュ憡缂栧彿锛堜笟鍔″敮涓�锛�", requiredMode = Schema.RequiredMode.REQUIRED, example = "QR20260918-0001")
+ private String reportNo;
+
+ @Schema(description = "妯℃澘缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
+ private Long templateId;
+
+ @Schema(description = "鐢熸垚鏃朵娇鐢ㄧ殑妯℃澘鐗堟湰鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "v1.0")
+ private String templateVersion;
+
+ @Schema(description = "涓氬姟鍗曟嵁缂栧彿", example = "1024")
+ private String businessId;
+
+ @Schema(description = "涓氬姟鍗曟嵁绫诲瀷", example = "mes_qc_oqc")
+ private String businessType;
+
+ @Schema(description = "娓叉煋浜х墿 HTML")
+ private String renderHtml;
+
+ @Schema(description = "鎶ュ憡鐘舵�侊細0鐢熸垚涓� 1鐢熸垚鎴愬姛 2鐢熸垚澶辫触", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Integer status;
+
+ @Schema(description = "鍒涘缓浜�", example = "1")
+ private String creator;
+
+ @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+ @Schema(description = "鏇存柊鏃堕棿")
+ private LocalDateTime updateTime;
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/template/QcReportTemplateController.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/template/QcReportTemplateController.java
new file mode 100644
index 0000000..3878e4f
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/template/QcReportTemplateController.java
@@ -0,0 +1,94 @@
+package cn.iocoder.yudao.module.qcreport.controller.admin.template;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.qcreport.controller.admin.template.vo.QcReportTemplatePageReqVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.template.vo.QcReportTemplateRespVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.template.vo.QcReportTemplateSaveReqVO;
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.template.QcReportTemplateDO;
+import cn.iocoder.yudao.module.qcreport.service.template.QcReportTemplateService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "绠$悊鍚庡彴 - 鏅鸿兘璐ㄦ鎶ュ憡妯℃澘")
+@RestController
+@RequestMapping("/qc-report/template")
+@Validated
+public class QcReportTemplateController {
+
+ @Resource
+ private QcReportTemplateService templateService;
+
+ @PostMapping("/create")
+ @Operation(summary = "鍒涘缓鎶ュ憡妯℃澘")
+ @PreAuthorize("@ss.hasPermission('qc-report:template:create')")
+ public CommonResult<Long> createTemplate(@Valid @RequestBody QcReportTemplateSaveReqVO createReqVO) {
+ return success(templateService.createTemplate(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "鏇存柊鎶ュ憡妯℃澘")
+ @PreAuthorize("@ss.hasPermission('qc-report:template:update')")
+ public CommonResult<Boolean> updateTemplate(@Valid @RequestBody QcReportTemplateSaveReqVO updateReqVO) {
+ templateService.updateTemplate(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "鍒犻櫎鎶ュ憡妯℃澘")
+ @Parameter(name = "id", description = "缂栧彿", required = true)
+ @PreAuthorize("@ss.hasPermission('qc-report:template:delete')")
+ public CommonResult<Boolean> deleteTemplate(@RequestParam("id") Long id) {
+ templateService.deleteTemplate(id);
+ return success(true);
+ }
+
+ @PostMapping("/copy")
+ @Operation(summary = "澶嶅埗鎶ュ憡妯℃澘")
+ @Parameter(name = "id", description = "缂栧彿", required = true)
+ @PreAuthorize("@ss.hasPermission('qc-report:template:create')")
+ public CommonResult<Long> copyTemplate(@RequestParam("id") Long id) {
+ return success(templateService.copyTemplate(id));
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "鑾峰緱鎶ュ憡妯℃澘")
+ @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('qc-report:template:query')")
+ public CommonResult<QcReportTemplateRespVO> getTemplate(@RequestParam("id") Long id) {
+ QcReportTemplateDO template = templateService.getTemplate(id);
+ return success(BeanUtils.toBean(template, QcReportTemplateRespVO.class));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "鑾峰緱鎶ュ憡妯℃澘鍒嗛〉")
+ @PreAuthorize("@ss.hasPermission('qc-report:template:query')")
+ public CommonResult<PageResult<QcReportTemplateRespVO>> getTemplatePage(@Valid QcReportTemplatePageReqVO pageReqVO) {
+ PageResult<QcReportTemplateDO> pageResult = templateService.getTemplatePage(pageReqVO);
+ return success(BeanUtils.toBean(pageResult, QcReportTemplateRespVO.class));
+ }
+
+ @GetMapping("/selectable")
+ @Operation(summary = "鑾峰緱鍙敤浜庡嚭浠剁殑妯℃澘鍒楄〃",
+ description = "涓変釜鏉′欢鍚屾椂婊¤冻鎵嶄細杩斿洖锛氭姤鍛婄被鍨嬩竴鑷淬�佹ā鏉垮凡鍚敤銆佸綋鍓嶇増鏈凡鍙戝竷涓旂敾甯冩湁鍙覆鏌撶殑鍐呭銆�"
+ + "鏈�鍚庝竴鏉℃尅鐨勬槸銆屾墦寮�杩囪璁″櫒浣嗘病鏀剧粍浠躲�嶇殑鐗堟湰鈥斺�斿畠娓叉煋鍑烘潵鏄竴寮犵櫧绾镐笖涓嶆姤閿欍��")
+ @Parameter(name = "reportType", description = "鎶ュ憡绫诲瀷锛屽嵆 mes_qc_type 鐨勬暟鍊煎瓧绗︿覆", required = true, example = "1")
+ @PreAuthorize("@ss.hasPermission('qc-report:template:query')")
+ public CommonResult<List<QcReportTemplateRespVO>> getSelectableTemplateList(
+ @RequestParam("reportType") String reportType) {
+ List<QcReportTemplateDO> list = templateService.getSelectableTemplates(reportType);
+ return success(BeanUtils.toBean(list, QcReportTemplateRespVO.class));
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/template/vo/QcReportTemplatePageReqVO.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/template/vo/QcReportTemplatePageReqVO.java
new file mode 100644
index 0000000..5179d9d
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/template/vo/QcReportTemplatePageReqVO.java
@@ -0,0 +1,45 @@
+package cn.iocoder.yudao.module.qcreport.controller.admin.template.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "绠$悊鍚庡彴 - 鏅鸿兘璐ㄦ鎶ュ憡妯℃澘鍒嗛〉 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class QcReportTemplatePageReqVO extends PageParam {
+
+ @Schema(description = "妯℃澘缂栫爜", example = "QC_REPORT_IQC")
+ private String templateCode;
+
+ @Schema(description = "妯℃澘鍚嶇О", example = "鏉ユ枡妫�楠屾姤鍛�")
+ private String templateName;
+
+ @Schema(description = "鎵�灞炶涓�", example = "manufacturing")
+ private String industry;
+
+ @Schema(description = "鎶ュ憡绫诲瀷", example = "IQC")
+ private String reportType;
+
+ @Schema(description = "妯℃澘鐘舵�侊細0鍚敤 1鍋滅敤", example = "0")
+ private Integer status;
+
+ @Schema(description = "褰撳墠鐗堟湰鍙�", example = "v1.0")
+ private String currentVersion;
+
+ @Schema(description = "鍒涘缓浜�", example = "1")
+ private String creator;
+
+ @Schema(description = "鍒涘缓鏃堕棿")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/template/vo/QcReportTemplateRespVO.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/template/vo/QcReportTemplateRespVO.java
new file mode 100644
index 0000000..e7aa195
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/template/vo/QcReportTemplateRespVO.java
@@ -0,0 +1,51 @@
+package cn.iocoder.yudao.module.qcreport.controller.admin.template.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - 鏅鸿兘璐ㄦ鎶ュ憡妯℃澘 Response VO")
+@Data
+public class QcReportTemplateRespVO {
+
+ @Schema(description = "妯℃澘缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "妯℃澘缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "QC_REPORT_IQC_A4")
+ private String templateCode;
+
+ @Schema(description = "妯℃澘鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "鏉ユ枡妫�楠屾姤鍛�")
+ private String templateName;
+
+ @Schema(description = "鎵�灞炶涓�", example = "manufacturing")
+ private String industry;
+
+ @Schema(description = "鎶ュ憡绫诲瀷", example = "IQC")
+ private String reportType;
+
+ @Schema(description = "绾稿紶灏哄", example = "A4")
+ private String pageSize;
+
+ @Schema(description = "绾稿紶鏂瑰悜", example = "portrait")
+ private String orientation;
+
+ @Schema(description = "妯℃澘鐘舵�侊細0鍚敤 1鍋滅敤", example = "0")
+ private Integer status;
+
+ @Schema(description = "褰撳墠鐗堟湰鍙�", example = "v1.0")
+ private String currentVersion;
+
+ @Schema(description = "妯℃澘鎻忚堪", example = "鐢ㄤ簬鏉ユ枡妫�楠屽崟鐨� A4 鎶ュ憡妯℃澘")
+ private String description;
+
+ @Schema(description = "鍒涘缓浜�", example = "1")
+ private String creator;
+
+ @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+ @Schema(description = "鏇存柊鏃堕棿")
+ private LocalDateTime updateTime;
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/template/vo/QcReportTemplateSaveReqVO.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/template/vo/QcReportTemplateSaveReqVO.java
new file mode 100644
index 0000000..0725c37
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/template/vo/QcReportTemplateSaveReqVO.java
@@ -0,0 +1,57 @@
+package cn.iocoder.yudao.module.qcreport.controller.admin.template.vo;
+
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.qcreport.enums.QcReportEnums.OrientationEnum;
+import cn.iocoder.yudao.module.qcreport.enums.QcReportEnums.PageSizeEnum;
+import cn.iocoder.yudao.module.qcreport.enums.QcReportEnums.TemplateStatusEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.Pattern;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - 鏅鸿兘璐ㄦ鎶ュ憡妯℃澘 鍒涘缓/淇敼 Request VO")
+@Data
+public class QcReportTemplateSaveReqVO {
+
+ @Schema(description = "妯℃澘缂栧彿", example = "1024")
+ private Long id;
+
+ @Schema(description = "妯℃澘缂栫爜", requiredMode = Schema.RequiredMode.REQUIRED, example = "QC_REPORT_IQC_A4")
+ @NotEmpty(message = "妯℃澘缂栫爜涓嶈兘涓虹┖")
+ @Size(max = 64, message = "妯℃澘缂栫爜闀垮害涓嶈兘瓒呰繃 64 涓瓧绗�")
+ @Pattern(regexp = "^[A-Za-z0-9_-]+$", message = "妯℃澘缂栫爜鍙兘鍖呭惈瀛楁瘝銆佹暟瀛椼�佷笅鍒掔嚎鍜岀煭妯嚎")
+ private String templateCode;
+
+ @Schema(description = "妯℃澘鍚嶇О", requiredMode = Schema.RequiredMode.REQUIRED, example = "鏉ユ枡妫�楠屾姤鍛�")
+ @NotEmpty(message = "妯℃澘鍚嶇О涓嶈兘涓虹┖")
+ @Size(max = 128, message = "妯℃澘鍚嶇О闀垮害涓嶈兘瓒呰繃 128 涓瓧绗�")
+ private String templateName;
+
+ @Schema(description = "鎵�灞炶涓�", example = "manufacturing")
+ @Size(max = 32, message = "鎵�灞炶涓氶暱搴︿笉鑳借秴杩� 32 涓瓧绗�")
+ private String industry;
+
+ @Schema(description = "鎶ュ憡绫诲瀷", example = "IQC")
+ @Size(max = 32, message = "鎶ュ憡绫诲瀷闀垮害涓嶈兘瓒呰繃 32 涓瓧绗�")
+ private String reportType;
+
+ @Schema(description = "绾稿紶灏哄", requiredMode = Schema.RequiredMode.REQUIRED, example = "A4")
+ @NotEmpty(message = "绾稿紶灏哄涓嶈兘涓虹┖")
+ @InEnum(PageSizeEnum.class)
+ private String pageSize;
+
+ @Schema(description = "绾稿紶鏂瑰悜", requiredMode = Schema.RequiredMode.REQUIRED, example = "portrait")
+ @NotEmpty(message = "绾稿紶鏂瑰悜涓嶈兘涓虹┖")
+ @InEnum(OrientationEnum.class)
+ private String orientation;
+
+ @Schema(description = "妯℃澘鐘舵�侊細0鍚敤 1鍋滅敤", example = "0")
+ @InEnum(TemplateStatusEnum.class)
+ private Integer status;
+
+ @Schema(description = "妯℃澘鎻忚堪", example = "鐢ㄤ簬鏉ユ枡妫�楠屽崟鐨� A4 鎶ュ憡妯℃澘")
+ @Size(max = 512, message = "妯℃澘鎻忚堪闀垮害涓嶈兘瓒呰繃 512 涓瓧绗�")
+ private String description;
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/version/QcReportTemplateVersionController.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/version/QcReportTemplateVersionController.java
new file mode 100644
index 0000000..adf0b28
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/version/QcReportTemplateVersionController.java
@@ -0,0 +1,113 @@
+package cn.iocoder.yudao.module.qcreport.controller.admin.version;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.qcreport.controller.admin.version.vo.QcReportTemplateVersionPageReqVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.version.vo.QcReportTemplateVersionRespVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.version.vo.QcReportTemplateVersionSaveReqVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.version.vo.QcReportTemplateVersionUpdateReqVO;
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.version.QcReportTemplateVersionDO;
+import cn.iocoder.yudao.module.qcreport.service.version.QcReportTemplateVersionService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "绠$悊鍚庡彴 - 鏅鸿兘璐ㄦ鎶ュ憡妯℃澘鐗堟湰")
+@RestController
+@RequestMapping("/qc-report/template-version")
+@Validated
+public class QcReportTemplateVersionController {
+
+ @Resource
+ private QcReportTemplateVersionService versionService;
+
+ @PostMapping("/create")
+ @Operation(summary = "鍒涘缓妯℃澘鐗堟湰")
+ @PreAuthorize("@ss.hasPermission('qc-report:template:update')")
+ public CommonResult<Long> createVersion(@Valid @RequestBody QcReportTemplateVersionSaveReqVO createReqVO) {
+ return success(versionService.createVersion(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "鏇存柊妯℃澘鐗堟湰锛堝凡鍙戝竷鐨勭増鏈笉鍙慨鏀癸級")
+ @PreAuthorize("@ss.hasPermission('qc-report:template:update')")
+ public CommonResult<Boolean> updateVersion(@Valid @RequestBody QcReportTemplateVersionUpdateReqVO updateReqVO) {
+ versionService.updateVersion(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "鍒犻櫎妯℃澘鐗堟湰锛堜粎鑽夌鍙垹闄わ級")
+ @Parameter(name = "id", description = "缂栧彿", required = true)
+ @PreAuthorize("@ss.hasPermission('qc-report:template:delete')")
+ public CommonResult<Boolean> deleteVersion(@RequestParam("id") Long id) {
+ versionService.deleteVersion(id);
+ return success(true);
+ }
+
+ @PostMapping("/publish")
+ @Operation(summary = "鍙戝竷妯℃澘鐗堟湰")
+ @Parameter(name = "id", description = "缂栧彿", required = true)
+ @PreAuthorize("@ss.hasPermission('qc-report:template:publish')")
+ public CommonResult<Boolean> publishVersion(@RequestParam("id") Long id) {
+ versionService.publishVersion(id);
+ return success(true);
+ }
+
+ @PostMapping("/rollback")
+ @Operation(summary = "鍥炴粴鍒版寚瀹氬巻鍙茬増鏈�")
+ @Parameter(name = "id", description = "缂栧彿", required = true)
+ @PreAuthorize("@ss.hasPermission('qc-report:template:publish')")
+ public CommonResult<Boolean> rollbackVersion(@RequestParam("id") Long id) {
+ versionService.rollbackVersion(id);
+ return success(true);
+ }
+
+ @PostMapping("/disable")
+ @Operation(summary = "鍋滅敤妯℃澘鐗堟湰")
+ @Parameter(name = "id", description = "缂栧彿", required = true)
+ @PreAuthorize("@ss.hasPermission('qc-report:template:publish')")
+ public CommonResult<Boolean> disableVersion(@RequestParam("id") Long id) {
+ versionService.disableVersion(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "鑾峰緱妯℃澘鐗堟湰")
+ @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('qc-report:template:query')")
+ public CommonResult<QcReportTemplateVersionRespVO> getVersion(@RequestParam("id") Long id) {
+ QcReportTemplateVersionDO version = versionService.getVersion(id);
+ return success(BeanUtils.toBean(version, QcReportTemplateVersionRespVO.class));
+ }
+
+ @GetMapping("/list-by-template")
+ @Operation(summary = "鑾峰緱妯℃澘鐨勬墍鏈夌増鏈�")
+ @Parameter(name = "templateId", description = "妯℃澘缂栧彿", required = true)
+ @PreAuthorize("@ss.hasPermission('qc-report:template:query')")
+ public CommonResult<List<QcReportTemplateVersionRespVO>> getVersionListByTemplateId(
+ @RequestParam("templateId") Long templateId) {
+ List<QcReportTemplateVersionDO> list = versionService.getVersionListByTemplateId(templateId);
+ return success(BeanUtils.toBean(list, QcReportTemplateVersionRespVO.class));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "鑾峰緱妯℃澘鐗堟湰鍒嗛〉")
+ @PreAuthorize("@ss.hasPermission('qc-report:template:query')")
+ public CommonResult<PageResult<QcReportTemplateVersionRespVO>> getVersionPage(
+ @Valid QcReportTemplateVersionPageReqVO pageReqVO) {
+ PageResult<QcReportTemplateVersionDO> pageResult = versionService.getVersionPage(pageReqVO);
+ return success(BeanUtils.toBean(pageResult, QcReportTemplateVersionRespVO.class));
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/version/vo/QcReportTemplateVersionPageReqVO.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/version/vo/QcReportTemplateVersionPageReqVO.java
new file mode 100644
index 0000000..1bf1d5b
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/version/vo/QcReportTemplateVersionPageReqVO.java
@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.module.qcreport.controller.admin.version.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "绠$悊鍚庡彴 - 鏅鸿兘璐ㄦ鎶ュ憡妯℃澘鐗堟湰鍒嗛〉 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class QcReportTemplateVersionPageReqVO extends PageParam {
+
+ @Schema(description = "妯℃澘缂栧彿", example = "1024")
+ private Long templateId;
+
+ @Schema(description = "鐗堟湰鍙�", example = "v1.0")
+ private String version;
+
+ @Schema(description = "鐗堟湰鐘舵�侊細0鑽夌 1宸插彂甯� 2宸插仠鐢�", example = "1")
+ private Integer status;
+
+ @Schema(description = "鍒涘缓鏃堕棿")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/version/vo/QcReportTemplateVersionRespVO.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/version/vo/QcReportTemplateVersionRespVO.java
new file mode 100644
index 0000000..b81cf13
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/version/vo/QcReportTemplateVersionRespVO.java
@@ -0,0 +1,40 @@
+package cn.iocoder.yudao.module.qcreport.controller.admin.version.vo;
+
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.version.ReportTemplateSchema;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - 鏅鸿兘璐ㄦ鎶ュ憡妯℃澘鐗堟湰 Response VO")
+@Data
+public class QcReportTemplateVersionRespVO {
+
+ @Schema(description = "鐗堟湰缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "妯℃澘缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long templateId;
+
+ @Schema(description = "鐗堟湰鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "v1.0")
+ private String version;
+
+ @Schema(description = "妯℃澘 Schema锛堣璁″櫒浜х墿锛�")
+ private ReportTemplateSchema schema;
+
+ @Schema(description = "鐗堟湰鐘舵�侊細0鑽夌 1宸插彂甯� 2宸插仠鐢�", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ private Integer status;
+
+ @Schema(description = "鐗堟湰璇存槑", example = "澧炲姞鎶芥牱妫�娴嬭〃鏍�")
+ private String description;
+
+ @Schema(description = "鍒涘缓浜�", example = "1")
+ private String creator;
+
+ @Schema(description = "鍒涘缓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+ @Schema(description = "鏇存柊鏃堕棿")
+ private LocalDateTime updateTime;
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/version/vo/QcReportTemplateVersionSaveReqVO.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/version/vo/QcReportTemplateVersionSaveReqVO.java
new file mode 100644
index 0000000..f2e4a8b
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/version/vo/QcReportTemplateVersionSaveReqVO.java
@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.module.qcreport.controller.admin.version.vo;
+
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.version.ReportTemplateSchema;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Pattern;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+@Schema(description = "绠$悊鍚庡彴 - 鏅鸿兘璐ㄦ鎶ュ憡妯℃澘鐗堟湰 鍒涘缓 Request VO")
+@Data
+public class QcReportTemplateVersionSaveReqVO {
+
+ @Schema(description = "鐗堟湰缂栧彿", example = "1024")
+ private Long id;
+
+ @Schema(description = "妯℃澘缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @NotNull(message = "妯℃澘缂栧彿涓嶈兘涓虹┖")
+ private Long templateId;
+
+ @Schema(description = "鐗堟湰鍙凤紝鐣欑┖鍒欐寜鏈�鏂扮増鏈嚜鍔ㄩ�掑锛堝 v1.0 -> v1.1锛�", example = "v1.0")
+ @Pattern(regexp = "^v\\d+(\\.\\d+)*$", message = "鐗堟湰鍙锋牸寮忓繀椤诲舰濡� v1.0")
+ @Size(max = 32, message = "鐗堟湰鍙烽暱搴︿笉鑳借秴杩� 32 涓瓧绗�")
+ private String version;
+
+ @Schema(description = "妯℃澘 Schema锛堣璁″櫒浜х墿锛�")
+ private ReportTemplateSchema schema;
+
+ @Schema(description = "鐗堟湰璇存槑", example = "澧炲姞鎶芥牱妫�娴嬭〃鏍�")
+ @Size(max = 512, message = "鐗堟湰璇存槑闀垮害涓嶈兘瓒呰繃 512 涓瓧绗�")
+ private String description;
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/version/vo/QcReportTemplateVersionUpdateReqVO.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/version/vo/QcReportTemplateVersionUpdateReqVO.java
new file mode 100644
index 0000000..560bfbf
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/controller/admin/version/vo/QcReportTemplateVersionUpdateReqVO.java
@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.module.qcreport.controller.admin.version.vo;
+
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.version.ReportTemplateSchema;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+/**
+ * 妯℃澘鐗堟湰淇敼 Request VO
+ * <p>
+ * 涓庡垱寤� VO 鍒嗙锛氬綊灞炴ā鏉夸笌鐗堟湰鍙峰湪鍒涘缓鍚庝笉鍙彉鏇达紝鏇存柊鍙厑璁告敼璁捐鍐呭涓庤鏄�
+ */
+@Schema(description = "绠$悊鍚庡彴 - 鏅鸿兘璐ㄦ鎶ュ憡妯℃澘鐗堟湰 淇敼 Request VO")
+@Data
+public class QcReportTemplateVersionUpdateReqVO {
+
+ @Schema(description = "鐗堟湰缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @NotNull(message = "鐗堟湰缂栧彿涓嶈兘涓虹┖")
+ private Long id;
+
+ @Schema(description = "妯℃澘 Schema锛堣璁″櫒浜х墿锛�")
+ private ReportTemplateSchema schema;
+
+ @Schema(description = "鐗堟湰璇存槑", example = "澧炲姞鎶芥牱妫�娴嬭〃鏍�")
+ @Size(max = 512, message = "鐗堟湰璇存槑闀垮害涓嶈兘瓒呰繃 512 涓瓧绗�")
+ private String description;
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/instance/QcReportInstanceDO.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/instance/QcReportInstanceDO.java
new file mode 100644
index 0000000..9ca65e1
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/instance/QcReportInstanceDO.java
@@ -0,0 +1,72 @@
+package cn.iocoder.yudao.module.qcreport.dal.dataobject.instance;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.handlers.Jackson3TypeHandler;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+
+import java.util.Map;
+
+/**
+ * 鎶ュ憡瀹炰緥 DO
+ * <p>
+ * 鐢熸垚鎶ュ憡鏃跺繀椤讳繚瀛� dataSnapshot锛氬巻鍙叉姤鍛婁笉鑳藉洜涓轰笟鍔℃暟鎹彉鍖栬�屽彂鐢熷彉鍖栥��
+ */
+@TableName(value = "qc_report_instance", autoResultMap = true)
+@KeySequence("qc_report_instance_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class QcReportInstanceDO extends BaseDO {
+
+ /**
+ * 瀹炰緥缂栧彿
+ */
+ @TableId
+ private Long id;
+ /**
+ * 鎶ュ憡缂栧彿锛堜笟鍔″敮涓�锛�
+ */
+ private String reportNo;
+ /**
+ * 妯℃澘缂栧彿
+ */
+ private Long templateId;
+ /**
+ * 鐢熸垚鏃朵娇鐢ㄧ殑妯℃澘鐗堟湰鍙�
+ */
+ private String templateVersion;
+ /**
+ * 涓氬姟鍗曟嵁缂栧彿锛屽璐ㄦ鍗� ID
+ */
+ private String businessId;
+ /**
+ * 涓氬姟鍗曟嵁绫诲瀷锛屽 mes_qc_iqc
+ */
+ private String businessType;
+ /**
+ * 鏁版嵁蹇収锛氭覆鏌撴椂鐨勫畬鏁存暟鎹笂涓嬫枃锛屼繚璇佸巻鍙叉姤鍛婂彲澶嶇幇
+ */
+ @TableField(typeHandler = Jackson3TypeHandler.class)
+ private Map<String, Object> dataSnapshot;
+ /**
+ * 娓叉煋浜х墿 HTML
+ */
+ private String renderHtml;
+ /**
+ * 鎶ュ憡鐘舵�併�傝 QcReportInstanceStatusEnum
+ */
+ private Integer status;
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/render/QcReportRenderRecordDO.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/render/QcReportRenderRecordDO.java
new file mode 100644
index 0000000..2642be5
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/render/QcReportRenderRecordDO.java
@@ -0,0 +1,63 @@
+package cn.iocoder.yudao.module.qcreport.dal.dataobject.render;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+
+import java.time.LocalDateTime;
+
+/**
+ * 鏅鸿兘璐ㄦ鎶ュ憡娓叉煋璁板綍 DO
+ * <p>
+ * 鍙负鎺掓煡鐢細涓�娆� PDF 鍑轰欢鍗犱簡澶氫箙銆佹祻瑙堝櫒浠�涔堢姸鎬併�佸け璐ユ椂寮傚父鏍堟槸浠�涔堛��
+ * 鎶ュ憡姝f枃涓嶅湪杩欓噷锛屾垚鍔熶笌鍚︿篃涓嶅奖鍝嶆姤鍛婃湰韬��
+ */
+@TableName("qc_report_render_record")
+@KeySequence("qc_report_render_record_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class QcReportRenderRecordDO extends BaseDO {
+
+ /** 缂栧彿 */
+ @TableId
+ private Long id;
+
+ /** 鎶ュ憡瀹炰緥缂栧彿 */
+ private Long reportId;
+
+ /** 妯℃澘缂栧彿 */
+ private Long templateId;
+
+ /** 涓氬姟鍗曟嵁缂栧彿 */
+ private String businessId;
+
+ /** 娓叉煋寮�濮嬫椂闂� */
+ private LocalDateTime renderStartTime;
+
+ /** 娓叉煋缁撴潫鏃堕棿 */
+ private LocalDateTime renderEndTime;
+
+ /** 娓叉煋鑰楁椂锛堟绉掞級锛氫粠寮�濮嬫墦鍗板埌 PDF 瀛楄妭鍒版墜 */
+ private Long renderDuration;
+
+ /** PDF 鐢熸垚鑰楁椂锛堟绉掞級 */
+ private Long pdfDuration;
+
+ /** 娴忚鍣ㄧ姸鎬侊細READY锛堝鐢ㄥ凡鏈夊疄渚嬶級/ RESTARTED锛堟湰娆¢噸鍚簡娴忚鍣級/ FAILED锛堝惎鍔ㄥけ璐ワ級 */
+ private String browserStatus;
+
+ /** 寮傚父鍫嗘爤锛屾垚鍔熸椂涓虹┖ */
+ private String errorStack;
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/template/QcReportTemplateDO.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/template/QcReportTemplateDO.java
new file mode 100644
index 0000000..992872d
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/template/QcReportTemplateDO.java
@@ -0,0 +1,69 @@
+package cn.iocoder.yudao.module.qcreport.dal.dataobject.template;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+
+/**
+ * 鎶ュ憡妯℃澘 DO
+ */
+@TableName("qc_report_template")
+@KeySequence("qc_report_template_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class QcReportTemplateDO extends BaseDO {
+
+ /**
+ * 妯℃澘缂栧彿
+ */
+ @TableId
+ private Long id;
+ /**
+ * 妯℃澘缂栫爜
+ */
+ private String templateCode;
+ /**
+ * 妯℃澘鍚嶇О
+ */
+ private String templateName;
+ /**
+ * 鎵�灞炶涓氥�傝 QcReportIndustryEnum
+ */
+ private String industry;
+ /**
+ * 鎶ュ憡绫诲瀷銆傝 QcReportTypeEnum
+ */
+ private String reportType;
+ /**
+ * 绾稿紶灏哄銆傝 QcReportPageSizeEnum锛屽 A4
+ */
+ private String pageSize;
+ /**
+ * 绾稿紶鏂瑰悜銆傝 QcReportOrientationEnum锛歱ortrait / landscape
+ */
+ private String orientation;
+ /**
+ * 妯℃澘鐘舵�併�傝 QcReportTemplateStatusEnum
+ */
+ private Integer status;
+ /**
+ * 褰撳墠鐗堟湰鍙凤紝濡� v1.0
+ */
+ private String currentVersion;
+ /**
+ * 妯℃澘鎻忚堪
+ */
+ private String description;
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/version/QcReportTemplateVersionDO.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/version/QcReportTemplateVersionDO.java
new file mode 100644
index 0000000..2d2fde9
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/version/QcReportTemplateVersionDO.java
@@ -0,0 +1,58 @@
+package cn.iocoder.yudao.module.qcreport.dal.dataobject.version;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.handlers.Jackson3TypeHandler;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+
+/**
+ * 鎶ュ憡妯℃澘鐗堟湰 DO
+ * <p>
+ * 鐗堟湰鍙戝竷鍚庝笉鍏佽瑕嗙洊锛屽彧鑳芥柊寤虹増鏈紝淇濊瘉鍘嗗彶鎶ュ憡鍙鐜般��
+ */
+@TableName(value = "qc_report_template_version", autoResultMap = true)
+@KeySequence("qc_report_template_version_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class QcReportTemplateVersionDO extends BaseDO {
+
+ /**
+ * 鐗堟湰缂栧彿
+ */
+ @TableId
+ private Long id;
+ /**
+ * 妯℃澘缂栧彿
+ */
+ private Long templateId;
+ /**
+ * 鐗堟湰鍙凤紝濡� v1.0
+ */
+ private String version;
+ /**
+ * 妯℃澘 Schema锛圙rapesJS JSON + Quality Component JSON + 鏁版嵁婧� + 缁戝畾 + 瑙勫垯 + 鏍峰紡锛�
+ */
+ @TableField(value = "schema_json", typeHandler = Jackson3TypeHandler.class)
+ private ReportTemplateSchema schema;
+ /**
+ * 鐗堟湰鐘舵�併�傝 QcReportVersionStatusEnum
+ */
+ private Integer status;
+ /**
+ * 鐗堟湰璇存槑
+ */
+ private String description;
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/version/ReportTemplateSchema.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/version/ReportTemplateSchema.java
new file mode 100644
index 0000000..8b8c697
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/version/ReportTemplateSchema.java
@@ -0,0 +1,145 @@
+package cn.iocoder.yudao.module.qcreport.dal.dataobject.version;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 鎶ュ憡妯℃澘 Schema 鈥斺�� 璁捐鍣ㄤ骇鐗╋紝涔熸槸鎶ュ憡鍑轰欢鐨勫敮涓�杈撳叆銆�
+ * <p>
+ * 妯℃澘涓嶄繚瀛樿8 HTML銆備繚瀛樼殑鏄�岀敾甯冩暟鎹� + 涓氬姟璇箟銆嶏紝鐢辨覆鏌撳紩鎿庢嵁姝ょ敓鎴� HTML锛�
+ * 杩欐牱鍚屼竴浠芥ā鏉垮湪涓嶅悓娓叉煋鐜涓嬩骇鐗╀竴鑷达紝涔熸墠鏈夊彲鑳藉仛鏈嶅姟绔� Sanitization銆�
+ *
+ * <h3>瀛楁鍒嗗伐</h3>
+ * <table>
+ * <tr><td>{@link #grapes}</td><td>GrapesJS 鍘熷椤圭洰鏁版嵁銆傝璁″櫒闈犲畠鏃犳崯杩樺師鐢诲竷锛�<b>娓叉煋寮曟搸涔熻瀹�</b>锛堟鏂囩粨鏋勫湪杩欓噷锛�</td></tr>
+ * <tr><td>{@link #components}</td><td>璐ㄩ噺缁勪欢涓氬姟璇箟娓呭崟銆傛覆鏌撲笉璇伙紝渚涜璁″櫒瀹氫綅缁勪欢銆佷緵鍚庣画 AI 鐢熸垚妯℃澘鏃剁悊瑙g粨鏋�</td></tr>
+ * <tr><td>{@link #rules}</td><td>鍒ゅ畾瑙勫垯銆傛覆鏌撳墠鐢卞垽瀹氬櫒姹傚�硷紝鍐冲畾姣忛」 PASS/FAIL 涓庢姤鍛婄粨璁�</td></tr>
+ * <tr><td>{@link #page}</td><td>绾稿紶涓庨〉杈硅窛锛屾覆鏌撴椂鎹㈢畻鎴� CSS {@code @page}</td></tr>
+ * </table>
+ *
+ * <h3>璇箟灞傛槸<strong>鏈夋剰鐨勫瓙闆�</strong>锛堥噸瑕侊級</h3>
+ * {@link #components} 鍙〃杈俱�岀敤宸叉敞鍐岀殑璐ㄩ噺缁勪欢鎼嚭鏉ョ殑鎵佸钩缁撴瀯銆嶏紝
+ * <b>涓嶈〃杈句换鎰� HTML</b>鈥斺�旂敤鎴锋墜宸ユ嫋杩涚敾甯冪殑瑁歌〃鏍笺�佽嚜瀹氫箟 div 涓嶅湪鍏跺唴銆�
+ * 杩欐槸鏈夋剰鏀剁獎鐨勮竟鐣岋紝涓嶆槸瀹炵幇鐤忔紡锛氭湁杩欐潯杈圭晫锛孉I 鐢熸垚妯℃澘鏃舵墠鑳借绾︽潫鎴�
+ * 銆屽彧鑳界敤宸叉敞鍐岀粍浠跺綋绉湪銆嶏紝鑰屼笉鏄悙涓�娈佃皝涔熶笉鏁㈡覆鏌撶殑 HTML銆�
+ * 浠讳綍銆岀粰璇箟灞傚姞涓竾鑳� customHtml 瀛楁銆嶇殑鏀瑰姩閮藉湪鎷嗚繖鏉¤竟鐣岋紝闇�瑕佸厛璁ㄨ銆�
+ *
+ * <h3>鍏煎鎬�</h3>
+ * <p>
+ * {@code schema_json} 鍒楅噷宸茬粡瀛樼潃鍚� 1.0 瀛楁锛坉ataSources / bindings / styles锛夌殑鍘嗗彶 JSON锛�
+ * 鎵�浠ヨ繖閲屾樉寮忔爣娉� {@link JsonIgnoreProperties} 瀹归敊銆�
+ * <p>
+ * 璇存槑涓�鍙ワ紝鍏嶅緱鍚庝汉浠ヤ负瀹冨繀涓嶅彲灏戯細<b>鍘绘帀杩欎釜娉ㄨВ锛屽吋瀹规�ф祴璇曚篃鏄豢鐨�</b>鈥斺��
+ * 璇诲簱閭f潯閾捐矾鐢ㄧ殑 {@code Jackson3TypeHandler} 鑷繁 new 鐨� ObjectMapper锛�
+ * 鑰� Jackson 3 鐨� {@code FAIL_ON_UNKNOWN_PROPERTIES} 榛樿灏辨槸鍏崇殑銆�
+ * 鐪熸闇�瑕佸畠闃茬殑鏄彟澶栦袱鏉★細Spring 鍙嶅簭鍒楀寲璇锋眰浣撴椂鐢ㄧ殑 ObjectMapper锛堥厤缃笉鍙楁湰妯″潡鎺у埗锛夛紝
+ * 浠ュ強灏嗘潵鏈変汉缁欑被鍨嬪鐞嗗櫒鎹竴涓洿涓ユ牸鐨� Mapper銆傜暀鐫�鏄妸鎰忓浘鍐欐槑锛屼笉鏄憜璁俱��
+ *
+ * <h3>鐗堟湰鍘嗗彶</h3>
+ * <ul>
+ * <li><b>1.0</b>锛氬垵鐗堛�傚惈 dataSources / bindings / styles 涓変釜瀛楁锛屼絾瀹冧滑濮嬬粓鏄┖鏁扮粍锛�
+ * 鏃㈡棤浜哄啓鍏ヤ篃鏃犱汉璇诲彇锛屽睘姝绘暟鎹��</li>
+ * <li><b>1.1</b>锛氬垹闄や笂杩颁笁涓瀛楁锛寋@code components} 鐢� {@code Map} 鏀逛负寮虹被鍨�
+ * {@link QualityComponentNode}銆傚洜姝诲瓧娈靛師鏈氨鎭掍负绌烘暟缁勶紝1.0 鈫� 1.1 鏃犻渶鏁版嵁杩佺Щ銆�</li>
+ * </ul>
+ */
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ReportTemplateSchema {
+
+ /**
+ * 褰撳墠 Schema 鐗堟湰鍙枫��
+ * <p>
+ * 涓庡墠绔� {@code designer/constants.ts} 鐨� {@code SCHEMA_VERSION} 蹇呴』涓�鑷达細
+ * 涓ょ鍚勫啓涓�浠芥槸鍘嗗彶鍘熷洜锛堝悗绔笉鍙備笌璁捐鍣ㄦ瀯寤猴級锛屾敼杩欓噷灏辫鍚屾鏀归偅杈广��
+ */
+ public static final String SCHEMA_VERSION = "1.1";
+
+ /**
+ * Schema 鐗堟湰锛岀敤浜庡悗缁吋瀹瑰崌绾�
+ */
+ private String schemaVersion;
+ /**
+ * 绾稿紶涓庨〉杈硅窛閰嶇疆
+ */
+ private Page page;
+ /**
+ * GrapesJS 鍘熷鐢诲竷鏁版嵁锛堜繚鐣欎互渚胯璁″櫒鏃犳崯杩樺師锛�
+ */
+ private Map<String, Object> grapes;
+ /**
+ * 璐ㄩ噺缁勪欢涓氬姟璇箟娓呭崟锛屾寜鏂囨。椤哄簭鎺掑垪
+ */
+ private List<QualityComponentNode> components;
+ /**
+ * 鍒ゅ畾瑙勫垯瀹氫箟銆�
+ * <p>
+ * 鍏冪礌褰㈢姸涓� {@code {id, name, scope, expression, enabled}}锛岀敱
+ * {@code QualityRuleDefinition.from(Map)} 瀹芥澗璇诲彇鈥斺�斿巻鍙叉暟鎹噷鍙兘鏈夌己瀛楁鐨勮鍒欙紝
+ * 璇讳笉鍔ㄧ殑璺宠繃鑰屼笉鏄鏁翠唤妯℃澘鎵撲笉寮�銆�
+ */
+ private List<Map<String, Object>> rules;
+
+ /**
+ * 绾稿紶涓庨〉杈硅窛閰嶇疆
+ */
+ @Data
+ public static class Page {
+
+ /**
+ * 绾稿紶灏哄锛欰3 / A4 / A5 / Letter
+ */
+ private String size;
+ /**
+ * 绾稿紶鏂瑰悜锛歱ortrait / landscape
+ */
+ private String orientation;
+ /**
+ * 椤佃竟璺濓紝鍗曚綅 mm
+ */
+ private Margin margin;
+
+ }
+
+ /**
+ * 椤佃竟璺濓紝鍗曚綅 mm
+ */
+ @Data
+ public static class Margin {
+
+ private Double top;
+ private Double right;
+ private Double bottom;
+ private Double left;
+
+ }
+
+ /**
+ * 鐢诲竷涓婄殑涓�涓川閲忕粍浠惰妭鐐广��
+ * <p>
+ * 鍙銆屾槸璋併�佸湪鍝�佷粈涔堝睘鎬с�嶏紝涓嶈瀛愯妭鐐光�斺�旂敾甯冪殑宓屽缁撴瀯浠� {@link #grapes} 涓哄噯锛�
+ * 杩欓噷鍐嶅瓨涓�浠芥爲灏卞嚭鐜颁袱涓湡鐩告潵婧愶紝杩熸棭瀵逛笉涓娿��
+ */
+ @Data
+ public static class QualityComponentNode {
+
+ /** 鐢诲竷鍐呯粍浠� id */
+ private String id;
+ /** 缁勪欢鍦ㄦ枃妗d腑鐨勯『搴忥紝渚涚粦瀹氫笌瀹氫綅浣跨敤 */
+ private Integer index;
+ /** 缁勪欢绫诲瀷锛屽嵆鐢诲竷鑺傜偣涓婄殑 data-quality-type */
+ private String qualityType;
+ /**
+ * 缁勪欢鐨勪笟鍔″睘鎬с��
+ * <p>
+ * 鍙栧�肩粺涓�鏄� {@code data-qc-*} / {@code data-quality-type} 杩欑被瀛楃涓插睘鎬э紝
+ * 鐢� Object 鏄洜涓� GrapesJS 鐨� getAttributes() 鍘熸牱甯﹀嚭锛屽彲鑳芥湁闈炲瓧绗︿覆鍊笺��
+ */
+ private Map<String, Object> attributes;
+
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/mysql/instance/QcReportInstanceMapper.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/mysql/instance/QcReportInstanceMapper.java
new file mode 100644
index 0000000..18db15f
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/mysql/instance/QcReportInstanceMapper.java
@@ -0,0 +1,49 @@
+package cn.iocoder.yudao.module.qcreport.dal.mysql.instance;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo.QcReportInstancePageReqVO;
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.instance.QcReportInstanceDO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+@Mapper
+public interface QcReportInstanceMapper extends BaseMapperX<QcReportInstanceDO> {
+
+ default PageResult<QcReportInstanceDO> selectPage(QcReportInstancePageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX<QcReportInstanceDO>()
+ .eqIfPresent(QcReportInstanceDO::getTemplateId, reqVO.getTemplateId())
+ .likeIfPresent(QcReportInstanceDO::getReportNo, reqVO.getReportNo())
+ .eqIfPresent(QcReportInstanceDO::getBusinessType, reqVO.getBusinessType())
+ .eqIfPresent(QcReportInstanceDO::getBusinessId, reqVO.getBusinessId())
+ .eqIfPresent(QcReportInstanceDO::getStatus, reqVO.getStatus())
+ .betweenIfPresent(QcReportInstanceDO::getCreateTime, reqVO.getCreateTime())
+ .orderByDesc(QcReportInstanceDO::getId));
+ }
+
+ default QcReportInstanceDO selectByReportNo(String reportNo) {
+ return selectOne(new LambdaQueryWrapperX<QcReportInstanceDO>()
+ .eq(QcReportInstanceDO::getReportNo, reportNo));
+ }
+
+ /**
+ * 鍙栧綋澶╂祦姘存渶澶х殑閭f潯缂栧彿锛岀敤浜庢帹鍑轰笅涓�涓簭鍙枫��
+ * <p>
+ * **蹇呴』璧版墜鍐� SQL銆佹妸杞垹闄ょ殑琛屼篃绠楄繘鏉�**锛氭潯浠舵瀯閫犲櫒浼氳嚜鍔ㄥ甫涓� {@code deleted = 0}锛�
+ * 鑰� {@code uk_report_no} 鍞竴绱㈠紩涓嶈 {@code deleted}銆傚垹鎺夊綋澶╂渶澶у彿鐨勯偅浠芥姤鍛婂悗锛�
+ * 鏉′欢鏋勯�犲櫒鐪嬩笉鍒板畠銆佺畻鍥炲悓涓�涓彿銆佹彃鍏ュ繀鐒舵挒鍞竴绱㈠紩锛涢噸璇曞張鏄悓涓�濂楁煡璇㈠悓涓�涓粨鏋滐紝
+ * 杩炴挒 5 娆″悗鎶ャ�岀紪鍙峰啿绐併�嶁�斺�旂敤鎴蜂細浠ヤ负鏄嚜宸辨墜姘斿樊锛屽疄闄呮槸鍒犺繃涓�浠芥姤鍛婂氨鍐嶅嚭涓嶄簡杩欎竴澶╃殑浠躲��
+ * <p>
+ * 鎺掑簭**涓嶈兘**鍙啓 {@code ORDER BY report_no DESC}锛氬簭鍙疯ˉ闆跺埌 4 浣嶏紝
+ * 褰撳ぉ涓�鏃﹁秴杩� 9999 鏉′綅瀹藉氨浼氬彉闀匡紝瀛楀吀搴忎細鎶� {@code ...-9999} 鎺掑埌 {@code ...-10000} 鍓嶉潰銆�
+ * 鍏堟瘮闀垮害鍐嶆瘮瀛楀吀搴忥紝涓ょ瀵归綈鎵嶆槸鐪熺殑銆屾渶澶с�嶃��
+ * <p>
+ * 鍙彇缂栧彿鏈韩锛氳皟鐢ㄦ柟瑕佺殑灏辨槸瀹冪殑灏鹃儴娴佹按锛屼笉蹇呮妸 JSON 蹇収涓�鏁翠釜鍒楁嫿鍑烘潵銆�
+ */
+ @Select("SELECT report_no FROM qc_report_instance WHERE report_no LIKE CONCAT(#{prefix}, '%') "
+ + "ORDER BY CHAR_LENGTH(report_no) DESC, report_no DESC LIMIT 1")
+ String selectLatestReportNoByPrefix(@Param("prefix") String prefix);
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/mysql/render/QcReportRenderRecordMapper.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/mysql/render/QcReportRenderRecordMapper.java
new file mode 100644
index 0000000..44f40f8
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/mysql/render/QcReportRenderRecordMapper.java
@@ -0,0 +1,14 @@
+package cn.iocoder.yudao.module.qcreport.dal.mysql.render;
+
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.render.QcReportRenderRecordDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 鏅鸿兘璐ㄦ鎶ュ憡娓叉煋璁板綍 Mapper
+ * <p>
+ * 鍙啓涓嶈锛氭帓鏌ユ椂鐩存帴鐢� SQL 鏌ュ簱锛屼笉涓烘鍋氭帴鍙c��
+ */
+@Mapper
+public interface QcReportRenderRecordMapper extends BaseMapperX<QcReportRenderRecordDO> {
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/mysql/template/QcReportTemplateMapper.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/mysql/template/QcReportTemplateMapper.java
new file mode 100644
index 0000000..e351323
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/mysql/template/QcReportTemplateMapper.java
@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.qcreport.dal.mysql.template;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.qcreport.controller.admin.template.vo.QcReportTemplatePageReqVO;
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.template.QcReportTemplateDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface QcReportTemplateMapper extends BaseMapperX<QcReportTemplateDO> {
+
+ default PageResult<QcReportTemplateDO> selectPage(QcReportTemplatePageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX<QcReportTemplateDO>()
+ .likeIfPresent(QcReportTemplateDO::getTemplateCode, reqVO.getTemplateCode())
+ .likeIfPresent(QcReportTemplateDO::getTemplateName, reqVO.getTemplateName())
+ .eqIfPresent(QcReportTemplateDO::getIndustry, reqVO.getIndustry())
+ .eqIfPresent(QcReportTemplateDO::getReportType, reqVO.getReportType())
+ .eqIfPresent(QcReportTemplateDO::getStatus, reqVO.getStatus())
+ .eqIfPresent(QcReportTemplateDO::getCurrentVersion, reqVO.getCurrentVersion())
+ .eqIfPresent(QcReportTemplateDO::getCreator, reqVO.getCreator())
+ .betweenIfPresent(QcReportTemplateDO::getCreateTime, reqVO.getCreateTime())
+ .orderByDesc(QcReportTemplateDO::getId));
+ }
+
+ default List<QcReportTemplateDO> selectListByReportTypeAndStatus(String reportType, Integer status) {
+ return selectList(new LambdaQueryWrapperX<QcReportTemplateDO>()
+ .eq(QcReportTemplateDO::getReportType, reportType)
+ .eq(QcReportTemplateDO::getStatus, status)
+ .orderByDesc(QcReportTemplateDO::getId));
+ }
+
+ default QcReportTemplateDO selectByCode(String templateCode) {
+ return selectOne(QcReportTemplateDO::getTemplateCode, templateCode);
+ }
+
+ default QcReportTemplateDO selectByName(String templateName) {
+ return selectOne(QcReportTemplateDO::getTemplateName, templateName);
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/mysql/version/QcReportTemplateVersionMapper.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/mysql/version/QcReportTemplateVersionMapper.java
new file mode 100644
index 0000000..1f364f4
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/dal/mysql/version/QcReportTemplateVersionMapper.java
@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.qcreport.dal.mysql.version;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.qcreport.controller.admin.version.vo.QcReportTemplateVersionPageReqVO;
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.version.QcReportTemplateVersionDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.Collection;
+import java.util.List;
+
+@Mapper
+public interface QcReportTemplateVersionMapper extends BaseMapperX<QcReportTemplateVersionDO> {
+
+ default PageResult<QcReportTemplateVersionDO> selectPage(QcReportTemplateVersionPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX<QcReportTemplateVersionDO>()
+ .eqIfPresent(QcReportTemplateVersionDO::getTemplateId, reqVO.getTemplateId())
+ .likeIfPresent(QcReportTemplateVersionDO::getVersion, reqVO.getVersion())
+ .eqIfPresent(QcReportTemplateVersionDO::getStatus, reqVO.getStatus())
+ .betweenIfPresent(QcReportTemplateVersionDO::getCreateTime, reqVO.getCreateTime())
+ .orderByDesc(QcReportTemplateVersionDO::getId));
+ }
+
+ default List<QcReportTemplateVersionDO> selectListByTemplateId(Long templateId) {
+ return selectList(new LambdaQueryWrapperX<QcReportTemplateVersionDO>()
+ .eq(QcReportTemplateVersionDO::getTemplateId, templateId)
+ .orderByDesc(QcReportTemplateVersionDO::getId));
+ }
+
+ default List<QcReportTemplateVersionDO> selectListByTemplateIdsAndStatus(Collection<Long> templateIds,
+ Integer status) {
+ return selectList(new LambdaQueryWrapperX<QcReportTemplateVersionDO>()
+ .in(QcReportTemplateVersionDO::getTemplateId, templateIds)
+ .eq(QcReportTemplateVersionDO::getStatus, status));
+ }
+
+ default QcReportTemplateVersionDO selectByTemplateIdAndVersion(Long templateId, String version) {
+ return selectOne(new LambdaQueryWrapperX<QcReportTemplateVersionDO>()
+ .eq(QcReportTemplateVersionDO::getTemplateId, templateId)
+ .eq(QcReportTemplateVersionDO::getVersion, version));
+ }
+
+ /**
+ * 鏌ヨ妯℃澘鐨勬渶鏂颁竴涓増鏈紙鎸� id 鍊掑簭鍙栫涓�鏉★級
+ */
+ default QcReportTemplateVersionDO selectLatestByTemplateId(Long templateId) {
+ List<QcReportTemplateVersionDO> list = selectList(new LambdaQueryWrapperX<QcReportTemplateVersionDO>()
+ .eq(QcReportTemplateVersionDO::getTemplateId, templateId)
+ .orderByDesc(QcReportTemplateVersionDO::getId)
+ .last("LIMIT 1"));
+ return list.isEmpty() ? null : list.get(0);
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/Bindings.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/Bindings.java
new file mode 100644
index 0000000..6800b73
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/Bindings.java
@@ -0,0 +1,88 @@
+package cn.iocoder.yudao.module.qcreport.engine;
+
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 鏁版嵁缁戝畾锛氭ā鏉挎枃鏈噷鐨� {@code {{path}}}銆�
+ * <p>
+ * 鍙仛鍙栧�间笌鏇挎崲锛屼笉鍋氫换浣曡〃杈惧紡姹傚�硷紱闇�瑕佽绠楃殑鍦烘櫙浜ょ粰瑙勫垯寮曟搸銆�
+ * 鍙栦笉鍒扮殑璺緞娓叉煋涓虹┖瀛楃涓测�斺�旀姤鍛婁笂涓嶈鍑虹幇鐢ㄦ埛鐪嬩笉鎳傜殑 {@code {{}}}銆�
+ * <p>
+ * 涓庡墠绔� {@code engine/binding.ts} 涓�涓�瀵瑰簲锛屼袱杈瑰繀椤诲悓璇箟銆�
+ */
+public final class Bindings {
+
+ /** 缁戝畾琛ㄨ揪寮忥細{{ report.reportNo }} */
+ private static final Pattern BINDING_PATTERN = Pattern.compile("\\{\\{\\s*([^{}]+?)\\s*\\}\\}");
+
+ /** 鏁存灏辨槸涓�涓粦瀹氳〃杈惧紡 */
+ private static final Pattern SINGLE_BINDING_PATTERN = Pattern.compile("^\\{\\{\\s*([^{}]+?)\\s*\\}\\}$");
+
+ private Bindings() {
+ }
+
+ /** 鎻愬彇鏂囨湰閲屽嚭鐜扮殑鎵�鏈夌粦瀹氳矾寰勶紙鍘婚噸銆佷繚鎸佸嚭鐜伴『搴忥級锛岀敤浜庢覆鏌撳墠鐨勬暟鎹緷璧栨鏌� */
+ public static List<String> listPaths(String template) {
+ Set<String> paths = new LinkedHashSet<>();
+ if (template == null) {
+ return List.of();
+ }
+ Matcher matcher = BINDING_PATTERN.matcher(template);
+ while (matcher.find()) {
+ String path = matcher.group(1).trim();
+ if (!path.isEmpty()) {
+ paths.add(path);
+ }
+ }
+ return List.copyOf(paths);
+ }
+
+ /** 瑙f瀽鍗曚釜缁戝畾璺緞锛屽彇涓嶅埌杩斿洖 null */
+ public static Object resolve(String path, Object context) {
+ return path == null ? null : Paths.readPath(context, path.trim());
+ }
+
+ /**
+ * 鏇挎崲鏂囨湰閲岀殑鍏ㄩ儴缁戝畾琛ㄨ揪寮忥紝骞跺洖鎶ュ彇涓嶅埌鍊肩殑璺緞銆�
+ * <p>
+ * 缁戝畾涓嶄笂閫氬父鎰忓懗鐫�鏁版嵁缂哄彛锛岄潤榛樻覆鏌撴垚绌轰細璁╂姤鍛婄湅璧锋潵銆屾甯镐絾缂哄唴瀹广�嶏紝
+ * 鎵�浠ユ妸缂哄彛浜ょ粰璋冪敤鏂癸紝鐢辨覆鏌撳紩鎿庢眹鎬绘垚鍙鐨勯棶棰樻竻鍗曘��
+ */
+ public static String resolveText(String template, Object context, Consumer<String> onMissing) {
+ if (template == null) {
+ return "";
+ }
+ Matcher matcher = BINDING_PATTERN.matcher(template);
+ StringBuilder result = new StringBuilder();
+ while (matcher.find()) {
+ String path = matcher.group(1).trim();
+ Object value = Paths.readPath(context, path);
+ if (value == null && onMissing != null) {
+ onMissing.accept(path);
+ }
+ matcher.appendReplacement(result, Matcher.quoteReplacement(Paths.formatValue(value)));
+ }
+ matcher.appendTail(result);
+ return result.toString();
+ }
+
+ /** 鏇挎崲鏂囨湰閲岀殑鍏ㄩ儴缁戝畾琛ㄨ揪寮忥紱鏈粦瀹氱殑璺緞娓叉煋涓虹┖ */
+ public static String resolveText(String template, Object context) {
+ return resolveText(template, context, null);
+ }
+
+ /** 鍒ゆ柇涓�娈垫枃鏈槸鍚︽槸绾粦瀹氳〃杈惧紡锛坽{path}} 鍗曞崰涓�娈碉級锛屾槸鍒欒繑鍥炶矾寰勶紝鍚﹀垯杩斿洖 null */
+ public static String asSingleBinding(String template) {
+ if (template == null) {
+ return null;
+ }
+ Matcher matcher = SINGLE_BINDING_PATTERN.matcher(template.trim());
+ return matcher.matches() ? matcher.group(1).trim() : null;
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/JsValues.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/JsValues.java
new file mode 100644
index 0000000..21136da
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/JsValues.java
@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.qcreport.engine;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * JS 鍊艰涔夈��
+ * <p>
+ * 娓叉煋涓庤鍒欐眰鍊肩殑浜х墿瑕佽窡鍓嶇閫愬瓧涓�鑷达紝鑰� Java 鐨勯粯璁ょ被鍨嬭浆鎹㈠拰 JS 鏈夊嚑澶勫涓嶄笂
+ * 锛坽@code String.valueOf(60.0D)} 鏄� "60.0"銆亄@code String.valueOf(true)} 鏄� "true"銆�
+ * 鏁扮粍 toString 鏄� "[1, 2]"锛夈�傚嚒鏄嬁鍊煎綋鏂囨湰鐢ㄧ殑鍦版柟閮借蛋杩欓噷锛屽埆鐢� Java 鐨勯粯璁よ浆鎹€��
+ */
+public final class JsValues {
+
+ private JsValues() {
+ }
+
+ /** {@code String(value)}锛歯ull 寰楃┖涓层�佸竷灏斿緱 true/false銆佹暟缁勬寜閫楀彿杩炴帴 */
+ public static String asText(Object value) {
+ if (value == null) {
+ return "";
+ }
+ if (value instanceof Boolean bool) {
+ return bool ? "true" : "false";
+ }
+ if (value instanceof Double || value instanceof Float || value instanceof BigDecimal) {
+ return Numbers.toString(((Number) value).doubleValue());
+ }
+ if (value instanceof Integer || value instanceof Long) {
+ return String.valueOf(value);
+ }
+ if (value instanceof List<?> list) {
+ List<String> parts = new ArrayList<>(list.size());
+ for (Object element : list) {
+ parts.add(element == null ? "" : asText(element));
+ }
+ return String.join(",", parts);
+ }
+ return String.valueOf(value);
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/Numbers.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/Numbers.java
new file mode 100644
index 0000000..f4b6f9d
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/Numbers.java
@@ -0,0 +1,26 @@
+package cn.iocoder.yudao.module.qcreport.engine;
+
+/**
+ * 鏁板�艰緭鍑烘牸寮忋��
+ * <p>
+ * Java 鐨� {@code String.valueOf(210.0D)} 寰楀埌 "210.0"锛岃�� JS 鐨� {@code String(210)} 鏄� "210"銆�
+ * 娓叉煋浜х墿锛坽@code @page} 灏哄銆佺粦瀹氬�笺�佹瘮杈冩椂鐨勬枃鏈舰鎬侊級蹇呴』涓庡墠绔�愬瓧涓�鑷达紝
+ * 鍚﹀垯鍚屼竴浠芥ā鏉垮湪涓ょ浼氳緭鍑轰笉鍚岀殑 HTML銆�
+ */
+public final class Numbers {
+
+ /** 鍙岀簿搴﹁兘绮剧‘琛ㄧず鎴愭暣鏁扮殑涓婄晫锛岃秴杩囧畠灏变笉鍐嶅綋鏁存暟澶勭悊 */
+ private static final double MAX_SAFE_INTEGER = 9.007199254740992E15;
+
+ private Numbers() {
+ }
+
+ /** 鏁存暟鍊肩殑娴偣鏁版敹鎴愭暣鏁拌緭鍑猴紙60.0 鈫� "60"锛夛紝鍏朵綑鍘熸牱杈撳嚭 */
+ public static String toString(double value) {
+ if (Double.isFinite(value) && value == Math.rint(value) && Math.abs(value) <= MAX_SAFE_INTEGER) {
+ return String.valueOf((long) value);
+ }
+ return String.valueOf(value);
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/PageMargin.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/PageMargin.java
new file mode 100644
index 0000000..662abe5
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/PageMargin.java
@@ -0,0 +1,16 @@
+package cn.iocoder.yudao.module.qcreport.engine;
+
+/**
+ * 椤佃竟璺濓紙姣背锛夛紝鍗曚綅涓庡墠绔� {@code engine/page.ts} 涓�鑷淬��
+ * <p>
+ * 瀛楁鐢ㄥ寘瑁呯被鍨嬶細涓� null 琛ㄧず璇ラ」娌¢厤杩囷紝鐢� {@link PageSizes} 钀藉埌榛樿杈硅窛锛�
+ * 涓庡墠绔� {@code margin?.top ?? DEFAULT_MARGIN_MM} 鐨勮涔変繚鎸佷竴鑷淬��
+ */
+public record PageMargin(Double top, Double right, Double bottom, Double left) {
+
+ /** 鍏ㄩ儴鏈厤缃� */
+ public static PageMargin none() {
+ return new PageMargin(null, null, null, null);
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/PageSetting.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/PageSetting.java
new file mode 100644
index 0000000..a310989
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/PageSetting.java
@@ -0,0 +1,15 @@
+package cn.iocoder.yudao.module.qcreport.engine;
+
+/**
+ * 绾稿紶閰嶇疆锛岀粨鏋勭瓑浠蜂簬 Schema.page锛屼絾涓嶄緷璧栧叿浣撴帴鍙g被鍨嬪畾涔夈��
+ * <p>
+ * 鍓嶇 {@code engine/page.ts} 鐨� PageSetting 涓庝箣涓�涓�瀵瑰簲銆�
+ */
+public record PageSetting(String size, String orientation, PageMargin margin) {
+
+ /** 鏈厤缃换浣曠焊寮犱俊鎭椂浣跨敤 */
+ public static PageSetting defaultSetting() {
+ return new PageSetting(null, null, null);
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/PageSizes.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/PageSizes.java
new file mode 100644
index 0000000..bbd944d
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/PageSizes.java
@@ -0,0 +1,48 @@
+package cn.iocoder.yudao.module.qcreport.engine;
+
+import java.util.Map;
+
+/**
+ * 绾稿紶灏哄鎹㈢畻銆�
+ * <p>
+ * 涓庡墠绔� {@code engine/page.ts} 涓�涓�瀵瑰簲锛屽彇鍊煎悓 {@code QcReportEnums.PageSizeEnum}銆�
+ * 璁捐鍣ㄦ崲绠楃敾甯冨儚绱犮�佹覆鏌撳紩鎿庢崲绠� {@code @page} 閮界敤杩欎竴浠斤紝閬垮厤涓ゅ鍚勫啓涓�閬嶅悗瀵逛笉涓娿��
+ */
+public final class PageSizes {
+
+ /** 绾稿紶灏哄锛堟绫筹級锛屾暟缁勪负 {瀹�, 楂榼 */
+ private static final Map<String, double[]> SIZE_MM = Map.of(
+ "A3", new double[]{297, 420},
+ "A4", new double[]{210, 297},
+ "A5", new double[]{148, 210},
+ "Letter", new double[]{215.9, 279.4});
+
+ /** 榛樿绾稿紶锛屾湭鍒楀嚭鐨勫昂瀵稿洖閫�鍒板畠 */
+ public static final String DEFAULT_SIZE = "A4";
+
+ /** 榛樿椤佃竟璺濓紙姣背锛� */
+ public static final double DEFAULT_MARGIN_MM = 10;
+
+ private PageSizes() {
+ }
+
+ /** 瑙f瀽绾稿紶灏哄涓庨〉杈硅窛锛堟绫筹級锛屾í鍚戞椂缈昏浆瀹介珮 */
+ public static ResolvedPage resolve(PageSetting page) {
+ String size = page == null || page.size() == null ? DEFAULT_SIZE : page.size();
+ double[] base = SIZE_MM.getOrDefault(size, SIZE_MM.get(DEFAULT_SIZE));
+ boolean landscape = page != null && "landscape".equals(page.orientation());
+ PageMargin margin = page == null ? null : page.margin();
+ return new ResolvedPage(
+ landscape ? base[1] : base[0],
+ landscape ? base[0] : base[1],
+ marginOf(margin == null ? null : margin.top()),
+ marginOf(margin == null ? null : margin.right()),
+ marginOf(margin == null ? null : margin.bottom()),
+ marginOf(margin == null ? null : margin.left()));
+ }
+
+ private static double marginOf(Double value) {
+ return value == null ? DEFAULT_MARGIN_MM : value;
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/Paths.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/Paths.java
new file mode 100644
index 0000000..70c066b
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/Paths.java
@@ -0,0 +1,199 @@
+package cn.iocoder.yudao.module.qcreport.engine;
+
+import java.math.BigDecimal;
+import java.time.temporal.TemporalAccessor;
+import java.time.format.DateTimeFormatter;
+import java.time.ZoneId;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 涓婁笅鏂囧彇鍊笺��
+ * <p>
+ * 鍙仛鐧藉悕鍗曞紡鐨勫睘鎬у鑸紝涓嶈В鏋愩�佷笉鎵ц浠讳綍浠g爜锛�
+ * 鏀寔 a.b.c 涓� a.b[0].c 涓ょ鍐欐硶锛岃矾寰勫湪鏁扮粍涓婄户缁彇灞炴�ф椂鎸夊厓绱犻�愪釜鍙栧�硷紙pluck锛夈��
+ * <p>
+ * 涓庡墠绔� {@code src/components/quality/engine/path.ts} 涓�涓�瀵瑰簲锛屼袱杈瑰繀椤诲悓璇箟銆�
+ */
+public final class Paths {
+
+ /** 璺緞鐗囨锛氭櫘閫氬睘鎬у悕鎴栨暟缁勪笅鏍� */
+ private static final Pattern TOKEN_PATTERN = Pattern.compile("[^.\\[\\]]+");
+
+ /** 绂佹璁块棶鐨勫睘鎬у悕锛岄伩鍏嶉『鐫�鍘熷瀷閾捐鍒版瀯閫犲櫒 */
+ private static final Set<String> BLOCKED_KEYS = Set.of("__proto__", "constructor", "prototype");
+
+ private static final Pattern INTEGER_TEXT = Pattern.compile("^\\d+$");
+
+ private static final DateTimeFormatter DATE_TIME_FORMAT =
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+ private Paths() {
+ }
+
+ /**
+ * 鎶婅矾寰勬媶鎴愮墖娈碉細inspectionItems[0].actualValue 鈫� [inspectionItems, 0, actualValue]
+ */
+ public static List<String> parsePath(String path) {
+ List<String> tokens = new ArrayList<>();
+ if (path == null) {
+ return tokens;
+ }
+ Matcher matcher = TOKEN_PATTERN.matcher(path);
+ while (matcher.find()) {
+ tokens.add(matcher.group());
+ }
+ return tokens;
+ }
+
+ /**
+ * 鎸夎矾寰勫彇鍊硷紝鍙栦笉鍒拌繑鍥� null銆�
+ */
+ public static Object readPath(Object source, String path) {
+ return readTokens(source, parsePath(path), 0);
+ }
+
+ private static Object readTokens(Object source, List<String> tokens, int start) {
+ Object current = source;
+ for (int index = start; index < tokens.size(); index++) {
+ String token = tokens.get(index);
+ if (current == null) {
+ return null;
+ }
+ if (current instanceof List<?> list) {
+ Integer arrayIndex = toIndex(token);
+ if (arrayIndex == null) {
+ // 鏁扮粍涓婄户缁彇灞炴�э細閫愬厓绱犲彇鍊硷紝寰楀埌鍚岄暱搴︾殑鏁扮粍
+ List<Object> plucked = new ArrayList<>(list.size());
+ for (Object element : list) {
+ plucked.add(readTokens(element, tokens, index));
+ }
+ return plucked;
+ }
+ current = arrayIndex < list.size() ? list.get(arrayIndex) : null;
+ continue;
+ }
+ if (current instanceof Map<?, ?> map) {
+ if (BLOCKED_KEYS.contains(token)) {
+ return null;
+ }
+ current = map.get(token);
+ continue;
+ }
+ // 鏍囬噺鍚庨潰杩樻湁璺緞鐗囨锛岃鏄庤矾寰勫啓閿欎簡
+ return null;
+ }
+ return current;
+ }
+
+ private static Integer toIndex(String token) {
+ return INTEGER_TEXT.matcher(token).matches() ? Integer.valueOf(token) : null;
+ }
+
+ /**
+ * 灞曠ず鐢ㄦ牸寮忓寲锛氱┖鍊兼覆鏌撲负绌哄瓧绗︿覆锛屽竷灏斿�艰浆涓枃锛屾棩鏈熷彧淇濈暀鍒扮銆�
+ * <p>
+ * 鏁存暟鍊肩殑鍙岀簿搴︽暟锛堝 60.0锛夋寜鏁存暟杈撳嚭锛屼笌 JS 鐨� {@code String(60)} 淇濇寔涓�鑷达紝
+ * 鍚﹀垯鎶ュ憡涓婁細鍑虹幇銆屾爣鍑嗗�� 60.0銆嶈繖绉嶄笉璇ユ湁鐨勫熬鏁般��
+ */
+ public static String formatValue(Object value) {
+ if (value == null) {
+ return "";
+ }
+ if (value instanceof Boolean bool) {
+ return bool ? "鏄�" : "鍚�";
+ }
+ if (value instanceof Date date) {
+ return DATE_TIME_FORMAT.format(date.toInstant().atZone(ZoneId.systemDefault()));
+ }
+ if (value instanceof TemporalAccessor temporal) {
+ return DATE_TIME_FORMAT.format(temporal);
+ }
+ if (value instanceof Collection<?> collection) {
+ List<String> parts = new ArrayList<>(collection.size());
+ for (Object element : collection) {
+ parts.add(formatValue(element));
+ }
+ return String.join("銆�", parts);
+ }
+ return formatNumberAware(value);
+ }
+
+ private static String formatNumberAware(Object value) {
+ if (value instanceof Double || value instanceof Float || value instanceof BigDecimal) {
+ return Numbers.toString(((Number) value).doubleValue());
+ }
+ return String.valueOf(value);
+ }
+
+ /**
+ * 鏁板�煎寲锛氶潪鏁板�艰繑鍥� NaN锛岀敱璋冪敤鏂瑰喅瀹氬浣曞鐞嗐��
+ */
+ public static double toNumber(Object value) {
+ if (value instanceof Number number) {
+ return number.doubleValue();
+ }
+ if (value instanceof Boolean bool) {
+ return bool ? 1D : 0D;
+ }
+ if (value instanceof String text && !text.isBlank()) {
+ try {
+ return Double.parseDouble(text.trim());
+ } catch (NumberFormatException ignored) {
+ return Double.NaN;
+ }
+ }
+ return Double.NaN;
+ }
+
+ /**
+ * 鎶婁换鎰忓彇鍊兼敹鏁涙垚鏁板�兼暟缁勶紝渚涚粺璁″嚱鏁颁娇鐢ㄣ��
+ */
+ public static List<Double> toNumberArray(Object value) {
+ List<Double> numbers = new ArrayList<>();
+ if (value instanceof Collection<?> collection) {
+ flattenInto(collection, numbers);
+ return numbers;
+ }
+ double single = toNumber(value);
+ if (Double.isFinite(single)) {
+ numbers.add(single);
+ }
+ return numbers;
+ }
+
+ private static void flattenInto(Object value, List<Double> target) {
+ if (value instanceof Collection<?> collection) {
+ for (Object element : collection) {
+ flattenInto(element, target);
+ }
+ return;
+ }
+ double numeric = toNumber(value);
+ if (Double.isFinite(numeric)) {
+ target.add(numeric);
+ }
+ }
+
+ /**
+ * 鎶婁换鎰忓彇鍊兼寜涓�灞備竴灞傛憡骞虫垚鍒楄〃锛屼繚鐣欏師濮嬪厓绱狅紙涓嶅仛鏁板�艰浆鎹級锛屼緵 PASS_RATE 杩欑被鍑芥暟浣跨敤銆�
+ */
+ public static List<Object> flatten(Object value) {
+ List<Object> result = new ArrayList<>();
+ if (value instanceof Collection<?> collection) {
+ for (Object element : collection) {
+ result.addAll(flatten(element));
+ }
+ return result;
+ }
+ result.add(value);
+ return result;
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/QualityReportEngine.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/QualityReportEngine.java
new file mode 100644
index 0000000..c456b96
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/QualityReportEngine.java
@@ -0,0 +1,115 @@
+package cn.iocoder.yudao.module.qcreport.engine;
+
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.version.ReportTemplateSchema;
+import cn.iocoder.yudao.module.qcreport.engine.context.ReportContext;
+import cn.iocoder.yudao.module.qcreport.engine.render.HtmlRenderer;
+import cn.iocoder.yudao.module.qcreport.engine.render.RenderOutcome;
+import cn.iocoder.yudao.module.qcreport.engine.rule.RuleEngine;
+import cn.iocoder.yudao.module.qcreport.engine.rule.RuleEvaluator;
+import cn.iocoder.yudao.module.qcreport.engine.rule.QualityRuleDefinition;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 娓叉煋寮曟搸鍏ュ彛銆�
+ * <p>
+ * 鍙仛涓�浠朵簨锛氭妸钀藉簱鐨勬ā鏉� Schema 缈昏瘧鎴愬紩鎿庣殑鍐呴儴缁撴瀯锛岀劧鍚庢覆鏌撱��
+ * 寮曟搸鏈韩涓嶄緷璧� Spring銆佷笉钀藉簱銆佷笉鍋氭潈闄愨�斺�斿畠鍙悆銆孲chema + 涓婁笅鏂囥�嶅悙 HTML锛�
+ * 杩欐牱鎵归噺鐢熸垚銆佸畾鏃朵换鍔°�佸叾瀹冩ā鍧楄皟鐢ㄩ兘鑳借蛋鍚屼竴涓叆鍙c��
+ */
+public final class QualityReportEngine {
+
+ private QualityReportEngine() {
+ }
+
+ /** 娓叉煋鎶ュ憡锛氬垽瀹� 鈫� 鐢熸垚姝f枃 鈫� 缁勮鏂囨。 */
+ public static RenderOutcome render(ReportTemplateSchema schema, ReportContext context) {
+ return HtmlRenderer.render(grapesOf(schema), pageOf(schema), context, rulesOf(schema));
+ }
+
+ /**
+ * 妯℃澘鏄惁宸茬粡鏈�<b>鍙覆鏌撶殑</b>鐢诲竷鍐呭銆�
+ * <p>
+ * 鍒ゆ嵁涓庢覆鏌撳櫒璇荤敾甯冪殑閭d竴琛屼弗鏍间竴鑷粹�斺�攞@link HtmlRenderer#render} 鍙栫殑鏄�
+ * {@code pages[0].frames[0].component}锛岃繖閲屽氨鐢� {@link Paths#readPath} 鍙栧悓涓�涓綅缃紝
+ * 鑰屼笉鏄��鍖栨垚銆実rapes 杩欎釜 Map 闈炵┖銆嶃��
+ * <p>
+ * <b>涓轰粈涔堜笉鑳藉彧鐪嬮潪绌�</b>锛欸rapesJS 鎶娿�屾墦寮�杩囦絾涓�涓粍浠堕兘娌℃斁銆嶇殑椤圭洰瀛樻垚
+ * {@code {"assets":[],"styles":[]}}锛屽畠闈炵┖銆佸嵈娌℃湁 frames锛涙覆鏌撳櫒鍙栦笉鍒版牴缁勪欢鏃�
+ * 鐩存帴鎶� body 娓叉煋鎴愮┖涓测�斺�斾笉鎶ラ敊锛岀敤鎴锋嬁鍒颁竴寮犵櫧绾� PDF銆傚嚭浠跺墠鐨勮繖涓鏌ュ氨鏄负浜�
+ * 鎶婅繖绉嶇増鏈尅鍦ㄦ覆鏌撲箣鍓嶏紝鍒ゆ嵁蹇呴』鍜屾覆鏌撳櫒瀵归綈锛屽惁鍒欐尅涓嶄綇銆�
+ */
+ public static boolean hasCanvas(ReportTemplateSchema schema) {
+ return Paths.readPath(grapesOf(schema), "pages[0].frames[0].component") instanceof Map<?, ?>;
+ }
+
+ /** GrapesJS 椤圭洰鏁版嵁 */
+ public static Map<String, Object> grapesOf(ReportTemplateSchema schema) {
+ return schema == null ? null : schema.getGrapes();
+ }
+
+ /** 绾稿紶涓庨〉杈硅窛锛屾湭閰嶇疆鏃惰惤鍒伴粯璁� A4 涓庨粯璁よ竟璺� */
+ public static PageSetting pageOf(ReportTemplateSchema schema) {
+ ReportTemplateSchema.Page page = schema == null ? null : schema.getPage();
+ if (page == null) {
+ return PageSetting.defaultSetting();
+ }
+ ReportTemplateSchema.Margin margin = page.getMargin();
+ PageMargin pageMargin = margin == null
+ ? PageMargin.none()
+ : new PageMargin(margin.getTop(), margin.getRight(), margin.getBottom(), margin.getLeft());
+ return new PageSetting(page.getSize(), page.getOrientation(), pageMargin);
+ }
+
+ /** 鍒ゅ畾瑙勫垯瀹氫箟锛孲chema 閲屾病閰嶆椂杩斿洖绌烘竻鍗� */
+ public static List<QualityRuleDefinition> rulesOf(ReportTemplateSchema schema) {
+ List<QualityRuleDefinition> rules = new ArrayList<>();
+ if (schema == null || schema.getRules() == null) {
+ return rules;
+ }
+ for (Map<String, Object> raw : schema.getRules()) {
+ QualityRuleDefinition rule = QualityRuleDefinition.from(raw);
+ if (rule != null) {
+ rules.add(rule);
+ }
+ }
+ return rules;
+ }
+
+ /**
+ * 淇濆瓨鍓嶆牎楠屾ā鏉块噷鐨勫叏閮ㄥ垽瀹氳鍒欙紝杩斿洖闂娓呭崟锛岀┖娓呭崟琛ㄧず閫氳繃銆�
+ * <p>
+ * 闄や簡璇硶锛岃繕鎷︾櫧鍚嶅崟澶栫殑鍑芥暟璋冪敤锛氳繖绫昏鍒欎竴鏃﹀瓨涓嬪幓锛�
+ * 姣忓紶鎶ュ憡閮戒細甯︿笂涓�鏉°�屾棤娉曟墽琛屻�嶏紝涓嶅鍦ㄨ璁¢樁娈靛氨閫�鍥炲幓銆�
+ * <p>
+ * <b>绌鸿〃杈惧紡鐨勮鍒欎篃閫�鍥炲幓銆�</b>杩欐潯鏇剧粡鏄斁琛岀殑鈥斺�斿綋鏃惰璁″櫒杩樻病鏈夎鍒欑紪杈戠晫闈紝
+ * 鎶ヤ簡閿欑敤鎴锋棤澶勫彲鏀癸紝鍙細鍗″湪淇濆瓨涓嶄簡锛岀瓑浜庢妸銆屼竴鏉″潖鏁版嵁銆嶅崌绾ф垚銆屾暣浠芥ā鏉夸笉鑳戒繚瀛樸�嶃��
+ * 瑙勫垯缂栬緫鐣岄潰鍋氬嚭鏉ヤ箣鍚庤繖涓悊鐢变笉鎴愮珛浜嗭細鐢ㄦ埛鍦ㄨ璁″櫒閲屽垹鎺夎繖鏉¤鍒欏氨鑳界户缁繚瀛橈紝
+ * 鎵�浠ユ敼鎴愭槑纭姤閿欍�傝鍙栦粛鐒跺瀹癸紙{@link #rulesOf} 涓嶄細鍥犱负涓�鏉″潖瑙勫垯璁╂暣浠芥ā鏉挎墦涓嶅紑锛夛紝
+ * 鎵ц鏈熶篃鐓у父鎶婂畠鎶ュ嚭鏉ワ紙銆岀 N 椤广�孹銆嶇殑瑙勫垯銆孻銆嶆棤娉曟墽琛岋細瑙勫垯琛ㄨ揪寮忎负绌恒�嶏級銆�
+ */
+ public static List<String> validateRules(ReportTemplateSchema schema) {
+ List<String> errors = new ArrayList<>();
+ for (QualityRuleDefinition rule : rulesOf(schema)) {
+ errors.addAll(RuleEngine.validate(rule));
+ String expression = rule.expression();
+ if (expression == null || expression.trim().isEmpty()) {
+ // 绌鸿〃杈惧紡涓婁竴姝ュ凡缁忔姤杩囷紝涔熸病浠�涔堝彲闈欐�佹鏌ョ殑
+ continue;
+ }
+ try {
+ String unknown = RuleEvaluator.findUnknownFunction(RuleEngine.parse(expression));
+ if (unknown != null) {
+ errors.add("瑙勫垯銆�" + rule.label() + "銆嶈皟鐢ㄤ簡涓嶆敮鎸佺殑鍑芥暟 " + unknown
+ + "锛屽彲鐢ㄥ嚱鏁帮細" + String.join("銆�", RuleEvaluator.functionNames()));
+ }
+ } catch (RuntimeException ignored) {
+ // 璇硶閿欒宸茬粡鍦ㄤ笂涓�姝ユ姤杩囷紝涓嶉噸澶嶅埛灞�
+ }
+ }
+ return errors;
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/QualityResult.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/QualityResult.java
new file mode 100644
index 0000000..d30fbc0
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/QualityResult.java
@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.qcreport.engine;
+
+/**
+ * 鍒ゅ畾缁撴灉銆�
+ * <p>
+ * 涓庡墠绔� {@code engine/context.ts} 鐨� QUALITY_RESULT 涓�涓�瀵瑰簲锛屽彇鍊煎悓鏃舵槸
+ * {@code QcReportEnums.CheckResultEnum} 鐨勮惤搴撳�笺��
+ */
+public enum QualityResult {
+
+ PASS("鍚堟牸"),
+ FAIL("涓嶅悎鏍�");
+
+ /**
+ * 瑙勫垯鏈韩鍑洪敊鏃剁殑鍗犱綅鏂囨銆�
+ * <p>
+ * 娌¢獙杩囦笉鑳借鍚堟牸锛屾病璇佹嵁涔熶笉鑳借涓嶅悎鏍硷紝鎵�浠ャ�屾棤缁撹銆嶅繀椤绘槸涓�涓拰 PASS/FAIL 骞跺垪鐨勬樉寮忕姸鎬併��
+ * 杩欑被椤逛粛鐣欏湪鍚堟牸鐜囧垎姣嶉噷锛屼竴涓窇鎸傜殑瑙勫垯搴旇鎶婂悎鏍肩粨璁哄帇浣忋��
+ */
+ public static final String PENDING_TEXT = "寰呭垽瀹�";
+
+ /**
+ * 鏃㈡病鏈夎鍒欍�佷篃娌℃湁瑙勬牸涓婁笅闄愭椂鐨勫崰浣嶆枃妗堛��
+ * <p>
+ * 鍜� {@link #PENDING_TEXT} 鍒绘剰鍒嗗紑锛氭姤鍛婇噷甯告湁銆岃瘯鏍疯川閲� m銆嶃�岀О閲忕摱 m0銆嶈繖绫诲彧渚涘叕寮忓彇鏁扮殑杩囩▼鍙傛暟锛�
+ * 瀹冧滑娌℃湁瑙勬牸涔熷氨鏃犱粠鍒ゅ畾锛涜繖绫婚」涓嶈鍏ュ悎鏍肩巼鍒嗘瘝锛屼篃涓嶅弬涓庢姤鍛婄粨璁恒��
+ */
+ public static final String UNDECIDABLE_TEXT = "鏃犲垽瀹氳鍒�";
+
+ /** 鍒ゅ畾缁撴灉瀵瑰簲鐨勫睍绀烘枃瀛� */
+ private final String text;
+
+ QualityResult(String text) {
+ this.text = text;
+ }
+
+ public String text() {
+ return text;
+ }
+
+ /** 灞曠ず鏂囧瓧/钀藉簱鍊� 鈫� 鏋氫妇锛岃瘑鍒笉鍑鸿繑鍥� null */
+ public static QualityResult of(String value) {
+ if (value == null) {
+ return null;
+ }
+ String normalized = value.trim().toUpperCase();
+ for (QualityResult result : values()) {
+ if (result.name().equals(normalized)) {
+ return result;
+ }
+ }
+ return null;
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/ResolvedPage.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/ResolvedPage.java
new file mode 100644
index 0000000..c68dd76
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/ResolvedPage.java
@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.qcreport.engine;
+
+/**
+ * 瑙f瀽鍚庣殑绾稿紶灏哄涓庨〉杈硅窛锛堟绫筹級锛屾í鍚戝凡缈昏浆瀹介珮銆�
+ */
+public record ResolvedPage(double widthMm, double heightMm,
+ double marginTopMm, double marginRightMm,
+ double marginBottomMm, double marginLeftMm) {
+
+ /** {@code @page { size: ... } } 鐨勫�� */
+ public String cssSize() {
+ return Numbers.toString(widthMm) + "mm " + Numbers.toString(heightMm) + "mm";
+ }
+
+ /** {@code @page { margin: ... } } 鐨勫�硷紝椤哄簭涓� 涓� 鍙� 涓� 宸� */
+ public String cssMargin() {
+ return Numbers.toString(marginTopMm) + "mm " + Numbers.toString(marginRightMm) + "mm "
+ + Numbers.toString(marginBottomMm) + "mm " + Numbers.toString(marginLeftMm) + "mm";
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/context/InspectionItem.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/context/InspectionItem.java
new file mode 100644
index 0000000..d090360
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/context/InspectionItem.java
@@ -0,0 +1,113 @@
+package cn.iocoder.yudao.module.qcreport.engine.context;
+
+import cn.iocoder.yudao.module.qcreport.engine.QualityResult;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * 鍗曚釜妫�楠岄」銆�
+ * <p>
+ * 瀛楁鍚嶄笌鍓嶇 {@code engine/context.ts} 鐨� ReportContextItem 淇濇寔涓�鑷达紝
+ * 閲嶅琛岀殑琛屽唴缁戝畾鍐欎綔 {@code {{item.itemName}}}銆�
+ */
+@Data
+@Accessors(chain = true)
+public class InspectionItem {
+
+ private int index;
+ private String itemCode = "";
+ private String itemName = "";
+ private String standardValue = "";
+ private String actualValue = "";
+ private String unit = "";
+ /**
+ * 銆屾娴嬭姹傘�嶆枃鏈細鍒嗙粍鐖堕」 = 鎸囨爣涓婄殑鍏紡锛屽叾浣� = 鍗曟嵁涓婄殑鏍囧噯瑕佹眰銆�
+ * <p>
+ * 涓� {@link #standardValue} 骞跺瓨鑰屼笉鍚堝苟锛氫袱鑰呯殑鏉ユ簮涓嶅悓锛堝崟鎹 vs 鎸囨爣涓绘暟鎹級锛�
+ * 鑰屽垎缁勭埗瀛愰」鍘嬫牴娌℃湁瑙勬牸锛屽彧鏈夊叕寮忋��
+ */
+ private String requirement = "";
+ /**
+ * 妫�娴嬫柟娉曪紝鏉ヨ嚜鍗曟嵁琛岋紙濡� {@code GB 5009.3-2016} / {@code ANA.MTH-000036}锛夈��
+ * <p>
+ * 涓� {@link #requirement} 骞跺瓨鑰屼笉鍚堝苟锛氭娴嬭姹傝鐨勬槸銆岃繖涓�椤硅杈惧埌浠�涔堛�嶏紝
+ * 妫�娴嬫柟娉曡鐨勬槸銆岀敤浠�涔堝姙娉曟祴鐨勩�嶏紝鍘熶欢閲屽父鍚勫崰涓�鍒椼��
+ */
+ private String checkMethod = "";
+ /**
+ * 鍒嗙粍淇℃伅锛屽彧鏈夋楠屽崟甯﹀垎缁勭粨鏋勬椂鎵嶆湁鍊笺��
+ * <p>
+ * null 琛ㄧず銆岃繖浠芥姤鍛婃病鏈夊垎缁勩�嶏紝{@link ReportContext#itemMap} 鍦ㄨ繖绉嶆儏鍐典笅涓嶆斁杩欎釜閿紝
+ * 鍏嶅緱缁欐病鏈夊垎缁勭殑鎶ュ憡锛堜互鍙婂喕缁撶殑瀵规媿 fixture锛夊甫涓婁竴涓亽涓虹┖鐨勫瓧娈点��
+ */
+ private Group group;
+ /** 瑙勬牸涓婇檺锛屽垽瀹氬櫒鍋氬尯闂村垽瀹氭椂浣跨敤 */
+ private Double upperLimit;
+ /** 瑙勬牸涓嬮檺 */
+ private Double lowerLimit;
+ /** PASS / FAIL */
+ private String result = "";
+ /** 鍚堟牸 / 涓嶅悎鏍� / 寰呭垽瀹� / 鏃犲垽瀹氳鍒� */
+ private String resultText = "";
+ private String remark = "";
+
+ /**
+ * 鍒嗙粍淇℃伅锛氭姤鍛婅鎶婄粍鍚嶈法浣忔暣缁勬墍闇�鐨勪笁涓�笺��
+ * <p>
+ * 娓叉煋鏈熺畻涓嶅嚭杩欎簺锛氱粦瀹氱殑璺緞鍦ㄦ暟缁勪笂缁х画鍙栧睘鎬т細鎸夊厓绱� pluck锛坄group.children.length`
+ * 鍙栦笉鍒板�硷級锛屾墍浠ャ�岃繖涓�缁勬湁鍑犺銆嶃�岃繖涓�鏍艰涓嶈璁╀綅銆嶅彧鑳界敱涓婃父閫愰」涓嬪彂銆�
+ * 瀛楁鍦�**姣忎竴涓�**妫�楠岄」涓婇兘瑕佹湁鍊硷紙鍝�曟槸绌轰覆锛夛細缁戝畾鐨勫瓧娈电己甯椂灞炴�т細琚烦杩囷紝
+ * 鏈闅愯棌鐨勫悎骞舵牸鍙嶈�屼細闇插嚭鏉ャ��
+ */
+ @Data
+ @Accessors(chain = true)
+ public static class Group {
+
+ /** 銆屽瓙椤广�嶅垪鏂囨湰锛氱粍鍐呭瓙椤� = 鑷繁鐨勫悕瀛楋紝缁勫ご琛屼笌鐙珛椤� = 绌轰覆 */
+ private String childName = "";
+ /** 缁勫悕鏍肩殑绾靛悜鍚堝苟琛屾暟锛氱粍鐨勭涓�琛� = 鏁寸粍鐨勮鏁帮紝缁勫唴鍏朵綑琛屼笌鐙珛椤� = 1 */
+ private int span = 1;
+ /**
+ * 缁勫悕鏍肩殑闅愯棌鍊硷細缁勫唴绗竴琛� = 绌轰覆锛堝彲瑙侊紝甯﹀悎骞惰鏁帮級锛屽叾浣欒 = `hidden`銆�
+ * <p>
+ * 瀛楃涓茶�屼笉鏄竷灏旓細`hidden` 灞炴�ч潬銆屽湪涓嶅湪銆嶈捣浣滅敤锛坄hidden="false"` 鐓ф牱闅愯棌锛夛紝
+ * 鍙湁绌轰覆鑳借〃杈俱�屼笉杈撳嚭杩欎釜灞炴�� = 杩欎竴鏍煎彲瑙併�嶃��
+ */
+ private String hidden = "";
+
+ public Group copy() {
+ return new Group().setChildName(childName).setSpan(span).setHidden(hidden);
+ }
+ }
+
+ public InspectionItem copy() {
+ return new InspectionItem()
+ .setIndex(index).setItemCode(itemCode).setItemName(itemName)
+ .setStandardValue(standardValue).setActualValue(actualValue).setUnit(unit)
+ .setRequirement(requirement)
+ .setCheckMethod(checkMethod)
+ .setGroup(group == null ? null : group.copy())
+ .setUpperLimit(upperLimit).setLowerLimit(lowerLimit)
+ .setResult(result).setResultText(resultText).setRemark(remark);
+ }
+
+ /** 鎸夊垽瀹氱粨鏋滃啓鍥� result / resultText锛寁erdict 涓� null 鏃剁疆涓哄緟鍒ゅ畾 */
+ public InspectionItem applyResult(QualityResult verdict) {
+ this.result = verdict == null ? "" : verdict.name();
+ this.resultText = verdict == null ? QualityResult.PENDING_TEXT : verdict.text();
+ return this;
+ }
+
+ /**
+ * 娌℃湁鍒ゅ畾渚濇嵁锛氱疆涓恒�屾棤鍒ゅ畾瑙勫垯銆嶃��
+ * <p>
+ * 鎶ュ憡閲屽父鏈夈�岃瘯鏍疯川閲� m銆嶃�岀О閲忕摱 m0銆嶈繖绫诲彧渚涘叕寮忓彇鏁扮殑杩囩▼鍙傛暟锛屽畠浠病鏈夎鏍间篃灏辨棤浠庡垽瀹氾紱
+ * 鑻ョ収甯哥畻杩涘垎姣嶏紝涓�浠芥湰鏉ュ叏鍚堟牸鐨勬姤鍛婁細鍥犱负鍑犱釜杩囩▼鍙傛暟琚帇鎴愩�屽緟鍒ゅ畾銆嶃��
+ */
+ public InspectionItem applyUndecidable() {
+ this.result = "";
+ this.resultText = QualityResult.UNDECIDABLE_TEXT;
+ return this;
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/context/ReportContext.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/context/ReportContext.java
new file mode 100644
index 0000000..3a757a0
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/context/ReportContext.java
@@ -0,0 +1,120 @@
+package cn.iocoder.yudao.module.qcreport.engine.context;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 鎶ュ憡涓婁笅鏂囥��
+ * <p>
+ * 妯℃澘閲岀殑 {@code {{path}}} 鍏ㄩ儴鐩稿杩欎釜缁撴瀯瑙f瀽锛歳eport 鏄姤鍛婄骇瀛楁锛宨nspectionItems 鏄楠岄」鏁扮粍銆�
+ * 涓氬姟鍗曟嵁 鈫� 涓婁笅鏂囩殑鏄犲皠鐢辫皟鐢ㄦ柟璐熻矗锛屾ā鏉挎湰韬彧璁よ繖涓爣鍑嗙粨鏋勶紝
+ * 鎹㈣涓氥�佹崲鍗曟嵁鏉ユ簮閮戒笉闇�瑕佹敼妯℃澘涓庣粍浠躲��
+ * <p>
+ * 鍙栧�兼椂鍏堟憡骞虫垚 Map锛坽@link #toScope()}锛夛紝涓嶉潬鍙嶅皠璇� POJO 灞炴�э細
+ * 鍙毚闇茶繖閲屾樉寮忔斁杩涘幓鐨勫瓧娈碉紝妯℃澘璺緞涓嶅彲鑳介『鐫� getClass 涔嬬被璇诲埌涓嶈缁欑殑涓滆タ銆�
+ */
+@Data
+@Accessors(chain = true)
+public class ReportContext {
+
+ private ReportFields report = new ReportFields();
+ private List<InspectionItem> inspectionItems = new ArrayList<>();
+
+ /** 绌虹櫧涓婁笅鏂囷細瀛楁榻愬叏浣嗘病鏈夊�硷紝渚夸簬閫愰」濉厖 */
+ public static ReportContext empty() {
+ return new ReportContext();
+ }
+
+ /** 鎶ュ憡绾у瓧娈� 鈫� Map */
+ public Map<String, Object> reportMap() {
+ Map<String, Object> map = new LinkedHashMap<>();
+ map.put("reportNo", report.getReportNo());
+ map.put("reportName", report.getReportName());
+ map.put("sampleNo", report.getSampleNo());
+ map.put("productCode", report.getProductCode());
+ map.put("productName", report.getProductName());
+ map.put("spec", report.getSpec());
+ map.put("batchNo", report.getBatchNo());
+ map.put("workOrderNo", report.getWorkOrderNo());
+ map.put("inspectType", report.getInspectType());
+ map.put("inspector", report.getInspector());
+ map.put("inspectDate", report.getInspectDate());
+ map.put("department", report.getDepartment());
+ map.put("customerName", report.getCustomerName());
+ map.put("supplierName", report.getSupplierName());
+ map.put("result", report.getResult());
+ map.put("resultText", report.getResultText());
+ map.put("conclusion", report.getConclusion());
+ map.put("passRate", report.getPassRate());
+ map.put("qcResult", report.getQcResult());
+ map.put("qcResultText", report.getQcResultText());
+ map.put("total", report.getTotal());
+ map.put("passCount", report.getPassCount());
+ map.put("failCount", report.getFailCount());
+ return map;
+ }
+
+ /** 妫�楠岄」鍒楄〃 鈫� Map锛屾覆鏌撲笌瑙勫垯姹傚�奸兘浠庤繖閲屽彇鍊� */
+ public static List<Object> itemMaps(List<InspectionItem> items) {
+ List<Object> maps = new ArrayList<>(items.size());
+ for (InspectionItem item : items) {
+ maps.add(itemMap(item));
+ }
+ return maps;
+ }
+
+ /** 娓叉煋浣滅敤鍩熺殑鏍癸細{ report, inspectionItems } */
+ public Map<String, Object> toScope() {
+ return scope(inspectionItems);
+ }
+
+ /**
+ * 鎸囧畾妫�楠岄」鍒楄〃鐨勪綔鐢ㄥ煙锛歿 report, inspectionItems }銆�
+ * <p>
+ * 閫愰」鍒ゅ畾瑕佺敤鍘熷鍒楄〃銆佹姤鍛婄骇鍒ゅ畾瑕佺敤鍒ゅ畾鍚庣殑鍒楄〃锛屼袱鑰呬笉鑳藉叡鐢ㄤ竴浠斤紝
+ * 鎵�浠ヨ繖閲屾妸銆岀敤鍝唤鍒楄〃銆嶅仛鎴愭樉寮忓弬鏁帮紝閬垮厤鍙栭敊銆�
+ */
+ public Map<String, Object> scope(List<InspectionItem> items) {
+ Map<String, Object> scope = new LinkedHashMap<>();
+ scope.put("report", reportMap());
+ scope.put("inspectionItems", itemMaps(items));
+ return scope;
+ }
+
+ public static Map<String, Object> itemMap(InspectionItem item) {
+ Map<String, Object> map = new LinkedHashMap<>();
+ map.put("index", item.getIndex());
+ map.put("itemCode", item.getItemCode());
+ map.put("itemName", item.getItemName());
+ map.put("standardValue", item.getStandardValue());
+ map.put("actualValue", item.getActualValue());
+ map.put("unit", item.getUnit());
+ map.put("requirement", item.getRequirement());
+ map.put("checkMethod", item.getCheckMethod());
+ // 娌℃湁鍒嗙粍鐨勬姤鍛婁笉鏀捐繖涓敭锛氭ā鏉块噷涓�涓� {{item.group.x}} 閮芥病鏈夛紝鏀句釜绌虹殑绌烘牸瀛愬彧浼氱櫧鍗犱綔鐢ㄥ煙
+ if (item.getGroup() != null) {
+ map.put("group", groupMap(item.getGroup()));
+ }
+ map.put("upperLimit", item.getUpperLimit());
+ map.put("lowerLimit", item.getLowerLimit());
+ map.put("result", item.getResult());
+ map.put("resultText", item.getResultText());
+ map.put("remark", item.getRemark());
+ return map;
+ }
+
+ /** 鍒嗙粍淇℃伅 鈫� Map锛氫笁涓瓧娈典竴涓兘涓嶈兘灏戯紝鍚﹀垯妯℃澘閲屽搴旂殑缁戝畾浼氬彇涓嶅埌鍊� */
+ public static Map<String, Object> groupMap(InspectionItem.Group group) {
+ Map<String, Object> map = new LinkedHashMap<>();
+ map.put("childName", group.getChildName());
+ map.put("span", group.getSpan());
+ map.put("hidden", group.getHidden());
+ return map;
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/context/ReportContextCodec.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/context/ReportContextCodec.java
new file mode 100644
index 0000000..24eda82
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/context/ReportContextCodec.java
@@ -0,0 +1,137 @@
+package cn.iocoder.yudao.module.qcreport.engine.context;
+
+import cn.iocoder.yudao.module.qcreport.engine.JsValues;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 鎶ュ憡涓婁笅鏂囦笌銆屾暟鎹揩鐓с�嶄箣闂寸殑缂栬В鐮併��
+ * <p>
+ * 鎶ュ憡瀹炰緥钀藉簱鏃惰鍐荤粨涓�浠� {@code data_snapshot}锛屼繚璇佸巻鍙叉姤鍛婁笉鍥犱笟鍔℃暟鎹彉鍖栬�屾敼鍙樸��
+ * 蹇収灏辨槸 {@link ReportContext#toScope()} 閭d唤缁撴瀯锛坽@code {report, inspectionItems}}锛夛紝
+ * 鑳界洿鎺ヤ氦缁� JSON 鍒楃殑绫诲瀷澶勭悊鍣紱鍙嶈繃鏉ヨ閲嶆柊鐢熸垚鏃讹紝寰楁妸瀹冭鍥� {@link ReportContext}銆�
+ * <p>
+ * <b>涓轰粈涔堟墜鍐� fromMap 鑰屼笉鐢� Jackson 鍙嶅簭鍒楀寲锛�</b>涓�鏄笌寮曟搸鍏朵綑閮ㄥ垎椋庢牸涓�鑷�
+ * 锛坽@link ReportContext#reportMap()}銆亄@link ReportContext#itemMap} 閮芥槸鏄惧紡瀛楁娓呭崟锛�
+ * 鍔犲瓧娈垫椂鏀逛竴澶勫氨鑳界湅鍑烘潵锛夛紱浜屾槸杩欎釜妯″潡閲� Jackson 3锛圝SON 鍒楃被鍨嬪鐞嗗櫒锛変笌 Jackson 2
+ * 锛圫pring 璇锋眰浣擄級骞跺瓨锛岄潬鍙嶅皠鏄犲皠绛変簬鎶娿�屽彇鍝閰嶇疆銆嶅彉鎴愪竴浠剁杩愭皵鐨勪簨銆�
+ * 杩欓噷鏄巻鍙叉姤鍛婅兘鍚﹀鐜扮殑鍞竴璺緞锛屽�煎緱鍐欐銆�
+ */
+public final class ReportContextCodec {
+
+ private static final String REPORT = "report";
+ private static final String INSPECTION_ITEMS = "inspectionItems";
+
+ private ReportContextCodec() {
+ }
+
+ /**
+ * 涓婁笅鏂� 鈫� 蹇収銆�
+ * <p>
+ * 浼犺繘鏉ョ殑閫氬父宸茬粡鏄垽瀹氬悗鐨勪笂涓嬫枃锛坽@code RenderOutcome.context()}锛夛紝
+ * 鍐荤粨鐨勫簲褰撴槸銆屼骇鍑鸿繖浠� HTML 鐨勯偅浠芥暟鎹�嶏紝鍖呭惈绠楀ソ鐨� PASS/FAIL 涓庡悎鏍肩巼銆�
+ */
+ public static Map<String, Object> toMap(ReportContext context) {
+ return context == null ? ReportContext.empty().toScope() : context.toScope();
+ }
+
+ /** 蹇収 鈫� 涓婁笅鏂囥�傜己瀛楁銆佺被鍨嬩笉瀵归兘鎸夈�岃繖涓瓧娈垫病鏈夊�笺�嶅鐞嗭紝涓嶆姏寮傚父 */
+ public static ReportContext fromMap(Map<String, Object> snapshot) {
+ ReportContext context = ReportContext.empty();
+ if (snapshot == null) {
+ return context;
+ }
+ if (snapshot.get(REPORT) instanceof Map<?, ?> report) {
+ context.setReport(reportOf(report));
+ }
+ if (snapshot.get(INSPECTION_ITEMS) instanceof List<?> items) {
+ context.setInspectionItems(itemsOf(items));
+ }
+ return context;
+ }
+
+ private static ReportFields reportOf(Map<?, ?> report) {
+ return new ReportFields()
+ .setReportNo(text(report.get("reportNo")))
+ .setReportName(text(report.get("reportName")))
+ .setSampleNo(text(report.get("sampleNo")))
+ .setProductCode(text(report.get("productCode")))
+ .setProductName(text(report.get("productName")))
+ .setSpec(text(report.get("spec")))
+ .setBatchNo(text(report.get("batchNo")))
+ .setWorkOrderNo(text(report.get("workOrderNo")))
+ .setInspectType(text(report.get("inspectType")))
+ .setInspector(text(report.get("inspector")))
+ .setInspectDate(text(report.get("inspectDate")))
+ .setDepartment(text(report.get("department")))
+ .setCustomerName(text(report.get("customerName")))
+ .setSupplierName(text(report.get("supplierName")))
+ .setResult(text(report.get("result")))
+ .setResultText(text(report.get("resultText")))
+ .setConclusion(text(report.get("conclusion")))
+ .setPassRate(text(report.get("passRate")))
+ .setQcResult(text(report.get("qcResult")))
+ .setQcResultText(text(report.get("qcResultText")))
+ .setTotal(integer(report.get("total")))
+ .setPassCount(integer(report.get("passCount")))
+ .setFailCount(integer(report.get("failCount")));
+ }
+
+ private static List<InspectionItem> itemsOf(List<?> items) {
+ List<InspectionItem> result = new ArrayList<>(items.size());
+ for (Object element : items) {
+ if (element instanceof Map<?, ?> item) {
+ result.add(itemOf(item));
+ }
+ }
+ return result;
+ }
+
+ private static InspectionItem itemOf(Map<?, ?> item) {
+ return new InspectionItem()
+ .setIndex(integer(item.get("index")))
+ .setItemCode(text(item.get("itemCode")))
+ .setItemName(text(item.get("itemName")))
+ .setStandardValue(text(item.get("standardValue")))
+ .setActualValue(text(item.get("actualValue")))
+ .setUnit(text(item.get("unit")))
+ .setRequirement(text(item.get("requirement")))
+ .setCheckMethod(text(item.get("checkMethod")))
+ .setGroup(item.get("group") instanceof Map<?, ?> group ? groupOf(group) : null)
+ .setUpperLimit(decimal(item.get("upperLimit")))
+ .setLowerLimit(decimal(item.get("lowerLimit")))
+ .setResult(text(item.get("result")))
+ .setResultText(text(item.get("resultText")))
+ .setRemark(text(item.get("remark")));
+ }
+
+ /** 鍒嗙粍淇℃伅鍥炶锛氫涪浜嗗畠锛屽巻鍙叉姤鍛婇噸鍑烘椂缁勫悕灏辫法涓嶄綇鏁寸粍浜� */
+ private static InspectionItem.Group groupOf(Map<?, ?> group) {
+ return new InspectionItem.Group()
+ .setChildName(text(group.get("childName")))
+ .setSpan(span(group.get("span")))
+ .setHidden(text(group.get("hidden")));
+ }
+
+ /** 鏂囨湰瀛楁锛歯ull 寰楃┖涓层�備笌 {@link ReportFields} 鐨勯粯璁ゅ�艰涔変竴鑷粹�斺�旂┖涓叉槸銆屾病鍊笺�嶏紝涓嶆槸銆岀己瀛楁銆� */
+ private static String text(Object value) {
+ return JsValues.asText(value);
+ }
+
+ private static int integer(Object value) {
+ return value instanceof Number number ? number.intValue() : 0;
+ }
+
+ /** 鍚堝苟琛屾暟鍙栦笉鍒板�兼椂鎸� 1 绠楋細0 浼氭覆鏌撴垚 rowspan="0"锛屾妸鏁磋鐨勫垪瀵归綈鎼炲潖 */
+ private static int span(Object value) {
+ return value instanceof Number number ? number.intValue() : 1;
+ }
+
+ /** 涓婁笅闄愬彲浠ヤ负绌猴紙娌℃湁瑙勬牸鍖洪棿锛夛紝绌哄�艰鍘熸牱淇濈暀鎴� null锛屼笉鑳藉彉鎴� 0 */
+ private static Double decimal(Object value) {
+ return value instanceof Number number ? number.doubleValue() : null;
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/context/ReportFields.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/context/ReportFields.java
new file mode 100644
index 0000000..fb464e2
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/context/ReportFields.java
@@ -0,0 +1,85 @@
+package cn.iocoder.yudao.module.qcreport.engine.context;
+
+import cn.iocoder.yudao.module.qcreport.engine.QualityResult;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * 鎶ュ憡绾у瓧娈点��
+ * <p>
+ * 妯℃澘閲岀殑 {@code {{report.xxx}}} 鍏ㄩ儴鐩稿瀹冨彇鍊硷紝瀛楁鍚嶄笌鍓嶇
+ * {@code engine/context.ts} 鐨� ReportContextReport 淇濇寔涓�鑷淬��
+ * <p>
+ * 鍏朵腑鐨� result / resultText / conclusion / passRate / total / passCount / failCount
+ * 鐢卞垽瀹氬櫒绠楀嚭鍚庡啓鍥烇紝璋冪敤鏂逛笉蹇呰嚜宸卞~銆�
+ * <p>
+ * 鏂囨湰瀛楁榛樿绌轰覆鑰屼笉鏄� null锛氭ā鏉块噷 {@code {{report.xxx}}} 鍙栧埌绌轰覆鏄�岃繖涓瓧娈垫病鏈夊�笺�嶏紝
+ * 鍙栧埌 null 鏄�岃矾寰勪笉瀛樺湪銆嶏紝鍚庤�呬細琚覆鏌撳紩鎿庡綋鎴愭暟鎹己鍙f姤鍑烘潵銆�
+ * 娌″~鐨勫瓧娈靛簲璇ヨ蛋鍓嶈�咃紝鍚﹀垯姣忓紶鎶ュ憡閮戒細鍒蜂竴鍫嗗苟涓嶅瓨鍦ㄧ殑缂哄彛銆�
+ */
+@Data
+@Accessors(chain = true)
+public class ReportFields {
+
+ private String reportNo = "";
+ private String reportName = "";
+ private String sampleNo = "";
+ private String productCode = "";
+ private String productName = "";
+ private String spec = "";
+ private String batchNo = "";
+ private String workOrderNo = "";
+ private String inspectType = "";
+ private String inspector = "";
+ private String inspectDate = "";
+ private String department = "";
+ private String customerName = "";
+ private String supplierName = "";
+
+ /** PASS / FAIL */
+ private String result = "";
+ /** 鍚堟牸 / 涓嶅悎鏍� / 寰呭垽瀹� */
+ private String resultText = "";
+ /** 鎶ュ憡缁撹锛屼笌 {@link #resultText} 鍚屾簮锛涙棤缁撹鏃朵负銆屽緟鍒ゅ畾銆� */
+ private String conclusion = "";
+ /** 鍚堟牸鐜囷紝褰㈠ 96.67% */
+ private String passRate = "";
+
+ /**
+ * 涓氬姟鍗曟嵁鑷韩鐨勬楠屽垽瀹氾紙MES 鐨勫洓鍊硷細鍚堟牸 / 鐗归噰 / 涓嶅悎鏍奸��璐� / 涓嶅悎鏍兼姤搴燂級锛岄潪鍒ゅ畾寮曟搸浜у嚭銆�
+ * <p>
+ * 涓庝笂闈㈢殑 result / resultText / conclusion 鏄袱鍥炰簨锛屽埢鎰忓垎寮�锛�
+ * 寮曟搸鍙湁銆屽悎鏍� / 涓嶅悎鏍� / 寰呭垽瀹氥�嶄笁鎬侊紝瑁呬笉涓嬨�岀壒閲囥�嶃�屼笉鍚堟牸閫�璐с�嶈繖绫诲缃彛寰勶紱
+ * 鑰岃川妫�鍗曚笂鐨勫垽瀹氭槸浜哄伐鎷嶇殑鏉匡紝鎶ュ憡瑕佸瀹炵収鐧汇�備袱鑰呴兘鍙兘鍑虹幇鍦ㄥ悓涓�寮犳姤鍛婁笂銆�
+ */
+ private String qcResult = "";
+ private String qcResultText = "";
+
+ private int total;
+ private int passCount;
+ private int failCount;
+
+ /** 澶嶅埗涓�浠斤紝鍒ゅ畾鍣ㄤ笉淇敼璋冪敤鏂逛紶杩涙潵鐨勪笂涓嬫枃 */
+ public ReportFields copy() {
+ return new ReportFields()
+ .setReportNo(reportNo).setReportName(reportName).setSampleNo(sampleNo)
+ .setProductCode(productCode).setProductName(productName).setSpec(spec)
+ .setBatchNo(batchNo).setWorkOrderNo(workOrderNo).setInspectType(inspectType)
+ .setInspector(inspector).setInspectDate(inspectDate).setDepartment(department)
+ .setCustomerName(customerName).setSupplierName(supplierName)
+ .setResult(result).setResultText(resultText).setConclusion(conclusion)
+ .setPassRate(passRate)
+ .setQcResult(qcResult).setQcResultText(qcResultText)
+ .setTotal(total).setPassCount(passCount).setFailCount(failCount);
+ }
+
+ /** 鎸夊垽瀹氱粨鏋滃啓鍥� result / resultText / conclusion锛宺esult 涓� null 鏃剁疆涓哄緟鍒ゅ畾 */
+ public ReportFields applyResult(QualityResult verdict) {
+ this.result = verdict == null ? "" : verdict.name();
+ String text = verdict == null ? QualityResult.PENDING_TEXT : verdict.text();
+ this.resultText = text;
+ this.conclusion = text;
+ return this;
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/render/CanvasSafety.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/render/CanvasSafety.java
new file mode 100644
index 0000000..301b5aa
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/render/CanvasSafety.java
@@ -0,0 +1,268 @@
+package cn.iocoder.yudao.module.qcreport.engine.render;
+
+import cn.hutool.core.util.StrUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+/**
+ * 鐢诲竷瀹夊叏鎬ф牎楠岋細妯℃澘淇濆瓨鏃舵妸銆屾覆鏌撴椂浼氬師鏍锋嫾杩� HTML 鐨勫唴瀹广�嶅厛鍗′竴閬嶃��
+ * <p>
+ * 鎶ュ憡浜х墿鏄嫾瀛楃涓叉嫾鍑烘潵鐨勶紙{@link HtmlRenderer}锛夛紝妯℃澘鐢诲竷鍙堟槸鐢ㄦ埛鍙紪杈戞暟鎹紝
+ * 鎵�浠ョ敾甯冮噷鍑℃槸<b>鏈粡杞箟灏辫繘鍏ヤ骇鐗�</b>鐨勫唴瀹归兘鏄敞鍏ラ潰銆傞�愭潯鍒楁槑瀹冧滑锛屾敼鍔ㄦ覆鏌撴垨鏈被鏃朵袱杈逛竴璧风湅锛�
+ * <ul>
+ * <li>{@code resolveTag} 鈥斺�� 鑺傜偣鐨� {@code tagName} 鐩存帴鎷兼垚 {@code <tag>}锛屾湰绫绘寜<b>鐧藉悕鍗�</b>鍗°��</li>
+ * <li>{@code renderAttributes} 鈥斺�� 鍙灞炴��<b>鍊�</b>鍋氳浆涔夛紝灞炴��<b>鍚�</b>鏄洿鎺ユ嫾涓婂幓鐨勶紝
+ * 涓�涓惈寮曞彿鐨勫睘鎬у悕灏辫兘鎶婂悗闈㈢殑鍐呭椤舵垚鏂板睘鎬э紝鏈被鎸夊瓧绗﹂泦鍗°��</li>
+ * <li>{@code buildCss} 鈥斺�� {@code styles} 鑻ユ槸瀛楃涓蹭細琚�<b>鍘熸牱杩斿洖</b>锛堟暣涓� {@code <style>} 鐨勫唴瀹癸級锛�
+ * 鑰� {@code <style>} 鍧楅噷鍑虹幇 {@code </style} 灏辫兘鎻愬墠闂悎銆佹妸鍚庨潰鍙樻垚鐪� HTML锛�
+ * 鏈被瑕佹眰 {@code styles} 蹇呴』鏄鍒欐暟缁勶紝骞剁姝㈤�夋嫨鍣�/灞炴�у悕/灞炴�у��/mediaText 閲屽嚭鐜� {@code <}銆�</li>
+ * </ul>
+ * <p>
+ * <b>涓轰粈涔堝湪淇濆瓨鏃跺崱鑰屼笉鏄覆鏌撴椂鍗�</b>锛氭覆鏌撻摼璺笂鐨� {@link HtmlRenderer} 涓庡墠绔�
+ * {@code engine/render.ts} 蹇呴』閫愬瓧涓�鑷达紝鏀瑰畠灏辫閲嶇畻瀵规媿浜х墿銆佸苟璁╁瓨閲忔姤鍛婄殑 {@code regenerate}
+ * 涓嶅啀閫愬瓧澶嶇幇锛涜�屻�屽叆绔欏唴瀹规槸鍚﹀彲淇°�嶆湰鏉ュ氨鏄啓鍏ヤ晶鐨勯棶棰橈紝鍦ㄦ暟鎹繘搴撳墠鎷︽帀锛屾覆鏌撲晶鍙互缁х画
+ * 淇濇寔涓庡墠绔畬鍏ㄥ绉般�備唬浠锋槸<b>瀵规牎楠屼笂绾垮墠灏卞凡鍏ュ簱鐨勮剰鏁版嵁娌℃湁鍏滃簳</b>鈥斺�斿瓨閲忕増鏈渶瑕佸彟琛屾牳鏌ャ��
+ * <p>
+ * <b>涓轰粈涔堣蛋鐨勬槸鐧藉悕鍗曡�屼笉鏄繃婊ゅ嵄闄╂爣绛�</b>锛氶粦鍚嶅崟姘歌繙婕忥紝鑰屾姤鍛婃帓鐗堢敤寰楀埌鐨勬爣绛炬槸鏈夐檺鐨勩��
+ * 鍙灇涓剧殑銆傛甯告ā鏉夸笉浼氬洜涓鸿繖鏉$櫧鍚嶅崟琚嫆锛堝凡瀵瑰簱閲屽叏閮ㄥ瓨閲忕増鏈疄娴嬭繃锛夈��
+ */
+public final class CanvasSafety {
+
+ /**
+ * 鍏佽鍑虹幇鍦ㄧ敾甯冮噷鐨勬爣绛俱��
+ * <p>
+ * 鍙敹銆屾帓鐗堜笌鏂囨湰銆嶇被鏍囩锛氱粍浠舵敞鍐岃〃鑳戒骇鍑虹殑锛坽@code div/p/span/hr/img/h1~h6} 涓庤〃鏍间竴鏃忥級
+ * 鍔犱笂 GrapesJS 鍩虹缁勪欢涓庡父瑙佽鍐呰涔夋爣绛俱�傚埢鎰忔帓闄ゅ洓绫烩�斺��
+ * 鍙墽琛岋紙{@code script}锛夈�佸彲娉ㄥ叆鏍峰紡锛坽@code style}锛夈�佸彲宓屽叆澶栭儴鍐呭锛坽@code iframe/object/embed}锛夈��
+ * 鍙彁浜ゆ暟鎹紙{@code form} 鍙婂叾鎺т欢锛夛紝浠ュ強 {@code svg/math} 杩欑被鑷甫鑴氭湰鑳藉姏鐨勫懡鍚嶇┖闂存爣绛俱��
+ * <p>
+ * GrapesJS 浼氬湪缁勪欢涓婃寕 {@code docEl: {tagName: "html"}}銆亄@code head: {type: "head"}} 杩欑被
+ * <b>涓嶄細娓叉煋</b>鐨勫厓鏁版嵁锛屾墍浠ユ湰绫诲彧娌� {@code components} 璧帮紙涓� {@code RenderNode.children()} 涓�鑷达級锛�
+ * 鐧藉悕鍗曢噷涔熷氨涓嶉渶瑕� {@code html}/{@code head}銆�
+ */
+ private static final Set<String> ALLOWED_TAGS = Set.of(
+ // 鍖哄潡涓庡鍣�
+ "div", "span", "section", "article", "header", "footer", "main", "aside", "nav",
+ "figure", "figcaption", "blockquote", "pre", "address", "center",
+ // 鏂囨湰涓庢爣棰�
+ "p", "br", "hr", "h1", "h2", "h3", "h4", "h5", "h6",
+ "b", "i", "u", "s", "strong", "em", "small", "big", "sub", "sup", "mark",
+ "code", "kbd", "samp", "var", "tt", "strike", "font", "wbr", "bdi", "bdo", "ruby", "rt", "rp",
+ "abbr", "cite", "q", "time", "del", "ins",
+ // 鍒楄〃
+ "ul", "ol", "li", "dl", "dt", "dd",
+ // 琛ㄦ牸
+ "table", "thead", "tbody", "tfoot", "tr", "td", "th", "caption", "col", "colgroup",
+ // 鍥剧墖涓庨摼鎺�
+ "img", "a", "label");
+
+ /** 鍚堟硶鐨勫睘鎬у悕锛氬瓧姣�/涓嬪垝绾�/鍐掑彿寮�澶达紝鍏跺悗瀛楁瘝鏁板瓧涓� {@code - _ : .}銆傚惈寮曞彿鎴栫┖鏍肩殑灞炴�у悕涓�寰嬫嫆缁� */
+ private static final Pattern ATTRIBUTE_NAME = Pattern.compile("^[A-Za-z_:][-A-Za-z0-9_:.]*$");
+
+ /** 鏈�澶氭姤鍑犳潯锛氫竴鏉℃姤閿欎俊鎭噷鍫嗗嚑鍗佹潯娌′汉鐪嬪緱涓嬪幓锛屾敼瀹屽啀瀛樹竴娆″氨鑳界湅鍒颁笅涓�鎵� */
+ private static final int MAX_PROBLEMS = 8;
+
+ /** 璺緞灞曠ず鐨勬渶澶у眰鏁帮紝鍐嶆繁灏辨姌鍙犳垚 鈥︼紝閬垮厤涓�鏉℃彁绀洪噷鍑虹幇涓�闀夸覆銆岀 N 涓粍浠躲�� */
+ private static final int MAX_PATH_DEPTH = 6;
+
+ private static final String UNSAFE_LT = "<";
+
+ private CanvasSafety() {
+ }
+
+ /**
+ * 鏍¢獙涓�浠界敾甯冦��
+ *
+ * @param grapes GradesJS 椤圭洰鏁版嵁锛堟ā鏉� Schema 鐨� {@code grapes} 瀛楁锛夛紝鍙负 null
+ * @return 闂娓呭崟锛岀┖鍒楄〃浠h〃閫氳繃銆傛枃妗堝凡鍙洿鎺ユ嫾缁欑敤鎴风湅
+ */
+ public static List<String> validate(Map<String, Object> grapes) {
+ List<String> problems = new ArrayList<>();
+ if (grapes == null) {
+ return problems;
+ }
+ validateComponentTree(grapes, problems);
+ validateStyles(grapes.get("styles"), problems);
+ return problems;
+ }
+
+ /* ------------------------------ 缁勪欢鏍� ------------------------------ */
+
+ private static void validateComponentTree(Map<String, Object> grapes, List<String> problems) {
+ for (Map<String, Object> frameComponent : frameComponents(grapes)) {
+ walk(frameComponent, "鏍�", 0, problems);
+ }
+ }
+
+ /** 鍙栨墍鏈夐〉鎵�鏈� frame 鐨勬牴缁勪欢銆傛覆鏌撳櫒鍙 {@code pages[0].frames[0]}锛岃繖閲屽叏鏌ヤ竴閬嶏細澶氬嚭鏉ョ殑閮ㄥ垎涔熶笉鑳借棌鑴忎笢瑗� */
+ private static List<Map<String, Object>> frameComponents(Map<String, Object> grapes) {
+ List<Map<String, Object>> result = new ArrayList<>();
+ collectFrames(grapes.get("pages"), result);
+ return result;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static void collectFrames(Object pages, List<Map<String, Object>> result) {
+ if (!(pages instanceof List<?> pageList)) {
+ return;
+ }
+ for (Object rawPage : pageList) {
+ if (!(rawPage instanceof Map<?, ?> page)) {
+ continue;
+ }
+ Object frames = ((Map<String, Object>) page).get("frames");
+ if (!(frames instanceof List<?> frameList)) {
+ continue;
+ }
+ for (Object rawFrame : frameList) {
+ if (rawFrame instanceof Map<?, ?> frame
+ && ((Map<String, Object>) frame).get("component") instanceof Map<?, ?> component) {
+ result.add((Map<String, Object>) component);
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private static void walk(Map<String, Object> node, String path, int depth, List<String> problems) {
+ if (problems.size() >= MAX_PROBLEMS) {
+ return;
+ }
+ validateNodeTag(node, path, problems);
+ validateNodeAttributes(node, path, problems);
+
+ if (!(node.get("components") instanceof List<?> children)) {
+ return;
+ }
+ int index = 0;
+ for (Object raw : children) {
+ if (!(raw instanceof Map<?, ?> child)) {
+ continue;
+ }
+ index++;
+ walk((Map<String, Object>) child, path + " > 绗� " + index + " 涓粍浠�", depth + 1, problems);
+ if (problems.size() >= MAX_PROBLEMS) {
+ return;
+ }
+ }
+ }
+
+ private static void validateNodeTag(Map<String, Object> node, String path, List<String> problems) {
+ Object raw = node.get("tagName");
+ String tagName = raw == null ? null : String.valueOf(raw).trim();
+ // textnode 涓嶄骇鐢熸爣绛撅紙HtmlRenderer 瀵瑰畠鍗曠嫭澶勭悊锛夛紝瀹冭韩涓婄殑 tagName 娓叉煋鏃惰蹇界暐锛屼笉蹇呮嫤
+ if (StrUtil.isBlank(tagName) || "textnode".equals(node.get("type"))) {
+ return;
+ }
+ if (ALLOWED_TAGS.contains(tagName.toLowerCase(Locale.ROOT))) {
+ return;
+ }
+ problems.add(StrUtil.format(
+ "{} 鐨勬爣绛炬槸銆寋}銆嶏紝鎶ュ憡涓嶆敮鎸佽鏍囩銆傚彲鐢ㄧ殑鍙湁甯歌鎺掔増鏍囩"
+ + "锛坉iv/p/span/h1~h6/img/hr 涓庤〃鏍笺�佸垪琛ㄣ�佽鍐呮枃鏈爣绛撅級锛�"
+ + "鑴氭湰銆佹牱寮忋�佸唴宓岄〉闈€�佽〃鍗曠被鏍囩涓�寰嬩笉鍏佽",
+ displayPath(path), tagName));
+ }
+
+ @SuppressWarnings("unchecked")
+ private static void validateNodeAttributes(Map<String, Object> node, String path, List<String> problems) {
+ if (!(node.get("attributes") instanceof Map<?, ?> attributes)) {
+ return;
+ }
+ for (Object key : ((Map<String, Object>) attributes).keySet()) {
+ String name = String.valueOf(key);
+ if (!ATTRIBUTE_NAME.matcher(name).matches()) {
+ problems.add(StrUtil.format(
+ "{} 鐨勫睘鎬у悕銆寋}銆嶄笉鏄悎娉曠殑灞炴�у悕锛堝彧鑳界敱瀛楁瘝銆佹暟瀛椼��- _ : . 缁勬垚锛屼笖涓嶈兘浠ユ暟瀛楀紑澶达級锛�"
+ + "璇ュ睘鎬т細璁╂姤鍛婁骇鐗╃粨鏋勯敊涔�",
+ displayPath(path), name));
+ continue;
+ }
+ if (name.toLowerCase(Locale.ROOT).startsWith("on")) {
+ problems.add(StrUtil.format(
+ "{} 鐨勫睘鎬с�寋}銆嶆槸浜嬩欢灞炴�э紝鎶ュ憡涓嶆敮鎸�",
+ displayPath(path), name));
+ }
+ }
+ }
+
+ /* ------------------------------ 鏍峰紡 ------------------------------ */
+
+ @SuppressWarnings("unchecked")
+ private static void validateStyles(Object styles, List<String> problems) {
+ if (styles == null) {
+ return;
+ }
+ if (styles instanceof String text) {
+ if (StrUtil.isNotBlank(text)) {
+ // buildCss 浼氭妸瀹冨師鏍峰杩� <style>锛岀瓑浜庤妯℃澘鑷甫涓�鏁存涓嶅彈鎺х殑 CSS锛堣繕鑳芥彁鍓嶉棴鍚� <style>锛�
+ problems.add("鐢诲竷鐨� styles 鏄竴娈� CSS 鏂囨湰锛屾姤鍛婁笉鎺ュ彈鏁存 CSS锛�"
+ + "璇锋敼鐢ㄨ璁″櫒鐨勬牱寮忛潰鏉块�愭潯璁剧疆鏍峰紡锛堜繚瀛樺悗鏄牱寮忚鍒欐暟缁勶級");
+ }
+ return;
+ }
+ if (!(styles instanceof List<?> rules)) {
+ problems.add("鐢诲竷鐨� styles 鏃笉鏄牱寮忚鍒欐暟缁勪篃涓嶆槸 CSS 鏂囨湰锛屾棤娉曡瘑鍒紝璇烽噸鏂颁繚瀛樻ā鏉�");
+ return;
+ }
+ for (int i = 0; i < rules.size() && problems.size() < MAX_PROBLEMS; i++) {
+ if (!(rules.get(i) instanceof Map<?, ?> rule)) {
+ continue;
+ }
+ Map<String, Object> ruleMap = (Map<String, Object>) rule;
+ validateStyleFragments(ruleMap.get("selectors"), "鏍峰紡瑙勫垯 " + (i + 1) + " 鐨勯�夋嫨鍣�", problems);
+ validateStyleFragments(ruleMap.get("mediaText"), "鏍峰紡瑙勫垯 " + (i + 1) + " 鐨勫獟浣撴煡璇㈡潯浠�", problems);
+ Object style = ruleMap.get("style");
+ if (style instanceof Map<?, ?> styleMap) {
+ for (Map.Entry<?, ?> entry : ((Map<String, Object>) styleMap).entrySet()) {
+ String where = StrUtil.format("鏍峰紡瑙勫垯 {} 鐨勫睘鎬с�寋}銆�",
+ i + 1, String.valueOf(entry.getKey()));
+ if (String.valueOf(entry.getKey()).contains(UNSAFE_LT)) {
+ problems.add(where + "鍚嶅瓧閲屽惈鏈夈��<銆嶏紝鎶ュ憡涓嶆敮鎸�");
+ continue;
+ }
+ validateStyleFragments(entry.getValue(), where, problems);
+ }
+ }
+ }
+ }
+
+ /** 閫夋嫨鍣�/濯掍綋鏌ヨ/鏍峰紡鍊奸兘杩� {@code <style>}锛屽嚭鐜� {@code <} 灏卞彲鑳介棴鍚� style 鍧� */
+ private static void validateStyleFragments(Object raw, String where, List<String> problems) {
+ if (raw instanceof List<?> list) {
+ for (Object item : list) {
+ validateStyleFragments(item, where, problems);
+ }
+ return;
+ }
+ if (raw == null || problems.size() >= MAX_PROBLEMS) {
+ return;
+ }
+ String text = String.valueOf(raw);
+ if (text.contains(UNSAFE_LT)) {
+ problems.add(StrUtil.format("{}銆寋}銆嶉噷鍚湁銆�<銆嶏紝鎶ュ憡涓嶆敮鎸侊紝璇峰湪璁捐鍣ㄩ噷鏀规帀",
+ where, StrUtil.maxLength(text, 60)));
+ }
+ }
+
+ /* ------------------------------ 灞曠ず ------------------------------ */
+
+ /** 璺緞澶繁灏辨姌鍙犱腑娈碉紝鎶ラ敊淇℃伅閲屽嚭鐜颁竴闀夸覆銆岀 N 涓粍浠躲�嶅瀹氫綅娌℃湁甯姪 */
+ private static String displayPath(String path) {
+ String[] segments = path.split(" > ");
+ if (segments.length <= MAX_PATH_DEPTH) {
+ return "鐢诲竷銆�" + path + "銆�";
+ }
+ List<String> shown = new ArrayList<>(List.of(segments[0], segments[1], "鈥�"));
+ for (int i = segments.length - 3; i < segments.length; i++) {
+ shown.add(segments[i]);
+ }
+ return "鐢诲竷銆�" + String.join(" > ", shown) + "銆�";
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/render/HtmlRenderer.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/render/HtmlRenderer.java
new file mode 100644
index 0000000..b44a050
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/render/HtmlRenderer.java
@@ -0,0 +1,408 @@
+package cn.iocoder.yudao.module.qcreport.engine.render;
+
+import cn.iocoder.yudao.module.qcreport.engine.Bindings;
+import cn.iocoder.yudao.module.qcreport.engine.PageSetting;
+import cn.iocoder.yudao.module.qcreport.engine.PageSizes;
+import cn.iocoder.yudao.module.qcreport.engine.Paths;
+import cn.iocoder.yudao.module.qcreport.engine.ResolvedPage;
+import cn.iocoder.yudao.module.qcreport.engine.context.ReportContext;
+import cn.iocoder.yudao.module.qcreport.engine.report.EvaluationOutcome;
+import cn.iocoder.yudao.module.qcreport.engine.report.ReportEvaluator;
+import cn.iocoder.yudao.module.qcreport.engine.rule.QualityRuleDefinition;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+/**
+ * 鎶ュ憡娓叉煋寮曟搸銆�
+ * <p>
+ * 杈撳叆銆屾ā鏉� Schema + 鎶ュ憡涓婁笅鏂囥�嶏紝杈撳嚭鍙洿鎺ユ墦鍗扮殑 HTML 鏂囨。銆�
+ * 娓叉煋椤哄簭鍥哄畾涓恒�屽厛鍒ゅ畾銆佸悗娓叉煋銆嶏細PASS/FAIL 鐢� {@link ReportEvaluator} 绠楀ソ鍐欒繘涓婁笅鏂囷紝
+ * 妯℃澘閲屽彧鍋氬彇鍊硷紝鍥犳鍚屼竴浠芥暟鎹湪浠讳綍妯℃澘涓嬪垽瀹氫竴鑷达紝妯℃澘涔熸棤娉曞乏鍙冲垽瀹氱粨鏋溿��
+ * <p>
+ * 杩欓噷涓嶈璇嗗叿浣撶粍浠剁被鍨嬶紝鍙悆 GrapesJS 瀵煎嚭鐨勯」鐩暟鎹紙缁勪欢鏍� + 鏍峰紡锛夛紝
+ * 鍙涓夊鍗忚锛歿@code data-qc-repeat} 閲嶅琛屻�亄@code {{璺緞}}} 缁戝畾銆亄@code schema.rules} 鍒ゅ畾瑙勫垯銆�
+ * 涓庡墠绔� {@code engine/render.ts} 涓�涓�瀵瑰簲锛屼袱杈逛骇鍑虹殑 HTML 蹇呴』涓�鑷淬��
+ */
+public final class HtmlRenderer {
+
+ /** 璁捐鍣ㄦ爣璁帮紝涓嶈繘鍏ヤ骇鐗� */
+ private static final String QUALITY_TYPE_ATTR = "data-quality-type";
+ private static final String QUALITY_PROP_PREFIX = "data-qc-";
+ private static final String QUALITY_REPEAT_ATTR = "data-qc-repeat";
+ private static final String QUALITY_REPEAT_ROW_ATTR = "data-qc-repeat-row";
+ /** GrapesJS 鐨勭粍浠� id 鎹㈡垚 data 灞炴�э細閲嶅琛岄噷 id 浼氶噸鍚嶏紝data 灞炴�т笉浼� */
+ private static final String QUALITY_ID_ATTR = "data-qc-id";
+
+ /** 鑷棴鍚堟爣绛撅紝涓嶈兘鐢熸垚缁撴潫鏍囩 */
+ private static final Set<String> VOID_TAGS = Set.of(
+ "br", "col", "hr", "img", "input", "link", "meta", "source", "track", "wbr");
+
+ /**
+ * GrapesJS 缁勪欢绫诲瀷 鈫� HTML 鏍囩銆�
+ * <p>
+ * 椤圭洰鏁版嵁鍙湪鏍囩涓庣被鍨嬮粯璁ゅ�间笉鍚屾椂鎵嶅啓 tagName锛堜緥濡� th銆乻pan銆乭2锛夛紝
+ * 琛ㄦ牸缁撴瀯锛坱able/thead/tbody/row/cell锛夊湪鏁版嵁閲岄兘鍙湁 type锛�
+ * 鎵�浠ユ紡鎺夎繖寮犺〃灏变細鎶婃暣寮犺〃鏍兼覆鏌撴垚涓�鍫� div銆傛湭鏀跺綍鐨勭被鍨嬪洖閫�鍒� div锛�
+ * 涓� GrapesJS 鍩虹缁勪欢鐨勯粯璁ゆ爣绛句竴鑷淬��
+ */
+ private static final Map<String, String> TYPE_TAGS = Map.of(
+ "cell", "td",
+ "row", "tr",
+ "table", "table",
+ "tbody", "tbody",
+ "tfoot", "tfoot",
+ "thead", "thead",
+ "text", "div",
+ "wrapper", "div");
+
+ /** 娓叉煋浜х墿鐨勫熀纭�鎺掔増銆傛祻瑙堝櫒榛樿鐨勮〃鏍间笌椤佃竟璺濅細璁╂姤鍛婅蛋鏍凤紝杩欓噷鏀舵暃鎴愭墦鍗板弸濂界殑鍩虹嚎 */
+ private static final String BASE_CSS = """
+ * { box-sizing: border-box; }
+ body { margin: 0; color: #000; font-family: "Microsoft YaHei", "PingFang SC", sans-serif; font-size: 12px; line-height: 1.5; }
+ table { border-collapse: collapse; width: 100%; }
+ img { max-width: 100%; }
+ tr, td, th { page-break-inside: avoid; }""";
+
+ /** 鎵胯浇澶栭儴鍦板潃鐨勫睘鎬э紝鍊奸噷鍑虹幇鍙墽琛屽崗璁竴寰嬫嫤鎺� */
+ private static final Set<String> URL_ATTRIBUTES = Set.of(
+ "href", "src", "xlink:href", "action", "formaction", "background", "poster");
+
+ /** 鍙墽琛� / 鍙敞鍏ョ殑 URL 鍗忚 */
+ private static final Pattern DANGEROUS_SCHEME =
+ Pattern.compile("^\\s*(?:javascript|vbscript|data)\\s*:", Pattern.CASE_INSENSITIVE);
+
+ /** data: 閲屽彧鏈夊浘鐗囨槸姝e綋鐢ㄩ�旓紝鍏朵綑锛坱ext/html 绛夛級浼氬彉鎴愭敞鍏ラ潰 */
+ private static final Pattern DATA_IMAGE = Pattern.compile("^\\s*data:image/", Pattern.CASE_INSENSITIVE);
+
+ /** GrapesJS 鐢� #缁勪欢id 閫夋嫨鍣紝杩欓噷鏀瑰啓鎴� data 灞炴�ч�夋嫨鍣� */
+ private static final Pattern ID_SELECTOR = Pattern.compile("#([\\w-]+)");
+
+ private HtmlRenderer() {
+ }
+
+ /**
+ * 娓叉煋鎶ュ憡锛氬垽瀹� 鈫� 鐢熸垚姝f枃 鈫� 鎷兼牱寮� 鈫� 缁勮鏂囨。銆�
+ *
+ * @param grapes GrapesJS 椤圭洰鏁版嵁锛堟ā鏉� Schema 鐨� grapes 瀛楁锛�
+ * @param page 绾稿紶涓庨〉杈硅窛閰嶇疆
+ * @param context 鎶ュ憡涓婁笅鏂�
+ * @param rules 鍒ゅ畾瑙勫垯锛屽彲涓虹┖
+ */
+ public static RenderOutcome render(Map<String, Object> grapes, PageSetting page,
+ ReportContext context, List<QualityRuleDefinition> rules) {
+ EvaluationOutcome evaluated = ReportEvaluator.evaluate(context, rules);
+ RenderState state = new RenderState(evaluated.context().toScope(), "妯℃澘",
+ new ArrayList<>(evaluated.errors()), new LinkedHashSet<>());
+
+ RenderNode root = RenderNode.of(Paths.readPath(grapes, "pages[0].frames[0].component"));
+ String body = root == null ? "" : renderNode(root, state);
+ String css = buildCss(grapes == null ? null : grapes.get("styles"));
+ String html = buildDocument(page, body, css, evaluated.context());
+ return new RenderOutcome(html, body, evaluated.context(), state.errors);
+ }
+
+ /* ------------------------------ 鑺傜偣灞曞紑 ------------------------------ */
+
+ /** 娓叉煋鍗曚釜鑺傜偣锛氭枃鏈妭鐐逛笌閲嶅瀹瑰櫒鍗曠嫭澶勭悊锛屽叾浣欐寜銆屾爣绛� + 灞炴�� + 瀛愯妭鐐广�嶅睍寮� */
+ private static String renderNode(RenderNode node, RenderState state) {
+ // 鏂囨湰鑺傜偣鍙础鐚枃鏈紝鑷韩涓嶄骇鐢熸爣绛�
+ if ("textnode".equals(node.type())) {
+ return renderText(node.content() == null ? "" : node.content(), state);
+ }
+
+ String repeatPath = node.attribute(QUALITY_REPEAT_ATTR);
+ if (repeatPath != null && !repeatPath.isEmpty()) {
+ return renderRepeat(node, repeatPath, state);
+ }
+
+ String tag = resolveTag(node);
+ String attributes = renderAttributes(node, state);
+ String style = renderStyle(node);
+ if (VOID_TAGS.contains(tag)) {
+ return "<" + tag + attributes + style + ">";
+ }
+ return "<" + tag + attributes + style + ">" + renderChildren(node, state) + "</" + tag + ">";
+ }
+
+ /** 鏍囩浼樺厛鍙栨暟鎹噷鐨� tagName锛屽叾娆℃寜缁勪欢绫诲瀷鎺ㄦ柇 */
+ private static String resolveTag(RenderNode node) {
+ String tagName = node.tagName();
+ if (tagName != null && !tagName.isEmpty()) {
+ return tagName;
+ }
+ String type = node.type();
+ String byType = type == null ? null : TYPE_TAGS.get(type);
+ return byType == null ? "div" : byType;
+ }
+
+ /**
+ * 瀛愯妭鐐规寜澹版槑椤哄簭灞曞紑銆�
+ * <p>
+ * 鏈夊瓙缁勪欢鏃跺拷鐣� content鈥斺�斾笌 GrapesJS 涓�鑷达細寰�涓�涓甫鏂囨湰鐨勭粍浠堕噷鍐嶆嫋鍏ョ粍浠跺悗锛�
+ * 鏂囨湰灏辫浣嶇粰瀛愮粍浠讹紝杩欓噷蹇呴』鍚岃鍒欙紝鍚﹀垯娓叉煋浜х墿浼氬拰璁捐鍣ㄧ湅鍒扮殑涓嶄竴鏍枫��
+ */
+ private static String renderChildren(RenderNode node, RenderState state) {
+ List<RenderNode> children = node.children();
+ if (!children.isEmpty()) {
+ StringBuilder builder = new StringBuilder();
+ for (RenderNode child : children) {
+ builder.append(renderNode(child, state));
+ }
+ return builder.toString();
+ }
+ String content = node.content();
+ return content == null ? "" : renderText(content, state);
+ }
+
+ /**
+ * 閲嶅瀹瑰櫒锛氭寜鏁扮粍璺緞灞曞紑琛屾ā鏉匡紝鍏朵綑瀛愯妭鐐瑰湪鍘熶綅缃覆鏌撲竴娆°��
+ * <p>
+ * 琛屾ā鏉夸笂鐨� {@code data-qc-repeat-row} 澹版槑浜嗚鍐呯殑寰幆鍙橀噺鍚嶏紙濡� item锛夛紝
+ * 琛屽唴瀹圭敤 {@code {{item.xxx}}} 鍙栧�硷紝涓庤璁℃湡鍦ㄧ粍浠堕噷绾﹀畾鐨勭粦瀹氳矾寰勪竴鑷淬��
+ */
+ private static String renderRepeat(RenderNode node, String path, RenderState state) {
+ List<Object> rows = toRowList(Paths.readPath(state.scope, path));
+ StringBuilder inner = new StringBuilder();
+ for (RenderNode child : node.children()) {
+ String rowVar = child.attribute(QUALITY_REPEAT_ROW_ATTR);
+ if (rowVar == null || rowVar.isEmpty()) {
+ inner.append(renderNode(child, state));
+ continue;
+ }
+ for (int index = 0; index < rows.size(); index++) {
+ Map<String, Object> rowScope = new LinkedHashMap<>(state.scope);
+ rowScope.put(rowVar, rows.get(index));
+ // index 鐢遍噸澶嶅鍣ㄦ敞鍏ワ紝琛屽唴鍙啓 {{index}}锛屼粠 1 寮�濮�
+ rowScope.put("index", index + 1);
+ inner.append(renderNode(child, state.withScope(rowScope, "绗� " + (index + 1) + " 琛�")));
+ }
+ }
+
+ String tag = resolveTag(node);
+ return "<" + tag + renderAttributes(node, state) + renderStyle(node) + ">" + inner + "</" + tag + ">";
+ }
+
+ /** 闈炴暟缁勬寜鍗曡澶勭悊锛岀┖鍊煎緱鍒扮┖琛紱姣旀姏閿欐洿璐村悎銆屾暟鎹病濉叏銆嶇殑鎶ュ憡鍦烘櫙 */
+ private static List<Object> toRowList(Object value) {
+ if (value instanceof List<?> list) {
+ return new ArrayList<>(list);
+ }
+ if (value == null) {
+ return List.of();
+ }
+ return List.of(value);
+ }
+
+ /* ------------------------------ 灞炴�т笌鏍峰紡 ------------------------------ */
+
+ /**
+ * 娓叉煋鑺傜偣灞炴�с��
+ * <p>
+ * 璁捐鍣ㄦ爣璁帮紙data-quality-type / data-qc-*锛変笉杩涘叆浜х墿锛�
+ * 灞炴�у�奸噷鐨� {@code {{path}}} 涓�骞惰В鏋愶紝鍥剧墖鍦板潃銆侀摼鎺ョ瓑涔熻兘缁戝畾鏁版嵁銆�
+ * <p>
+ * 姣斿墠绔涓�閬撻椄锛氫簨浠跺睘鎬т笌鍙墽琛屽崗璁笉杩涗骇鐗┿�備骇鐗╂槸缁欎汉鎵撳嵃鐨勬枃妗o紝
+ * on* 涔嬬被鐨勫睘鎬ф病鏈夋褰撶敤閫旓紝鏀捐绛変簬缁欐ā鏉垮紑浜嗕釜鎵ц鍙e瓙銆�
+ */
+ private static String renderAttributes(RenderNode node, RenderState state) {
+ StringBuilder builder = new StringBuilder();
+ for (Map.Entry<String, String> entry : node.attributes().entrySet()) {
+ String name = entry.getKey();
+ if (QUALITY_TYPE_ATTR.equals(name) || name.startsWith(QUALITY_PROP_PREFIX)) {
+ continue;
+ }
+ String text = renderText(entry.getValue() == null ? "" : entry.getValue(), state);
+ if (text.isEmpty()) {
+ continue;
+ }
+ if (!isSafeAttribute(name, text, state)) {
+ continue;
+ }
+ builder.append(' ').append("id".equals(name) ? QUALITY_ID_ATTR : name)
+ .append("=\"").append(escapeHtml(text)).append('"');
+ }
+ return builder.toString();
+ }
+
+ /** 灞炴�у悕/鍊煎畨鍏ㄩ椄锛屾嫤涓嬬殑鍐欒繘闂娓呭崟锛岃妯℃澘浣滆�呯湅寰楄鑰屼笉鏄倓鎮勫皯涓睘鎬� */
+ private static boolean isSafeAttribute(String name, String value, RenderState state) {
+ String lower = name.toLowerCase(Locale.ROOT);
+ if (lower.length() > 2 && lower.startsWith("on")) {
+ state.errors.add(state.where + "灞炴�с��" + name + "銆嶆槸浜嬩欢灞炴�э紝鎶ュ憡浜х墿涓嶈緭鍑猴紝宸插拷鐣�");
+ return false;
+ }
+ if (URL_ATTRIBUTES.contains(lower) && DANGEROUS_SCHEME.matcher(value).find()
+ && !DATA_IMAGE.matcher(value).find()) {
+ state.errors.add(state.where + "灞炴�с��" + name + "銆嶇殑鍦板潃鍗忚涓嶅畨鍏紝鎶ュ憡浜х墿涓嶈緭鍑猴紝宸插拷鐣�");
+ return false;
+ }
+ return true;
+ }
+
+ /** 鑺傜偣鑷韩鐨勮鍐呮牱寮� */
+ private static String renderStyle(RenderNode node) {
+ String style = cssStyle(node.style());
+ return style.isEmpty() ? "" : " style=\"" + escapeHtml(style) + "\"";
+ }
+
+ /** 鍙栨枃鏈噷鐨勭粦瀹氬�硷紝鍙栦笉鍒扮殑璺緞璁拌繘闂娓呭崟锛堟湭瑙f瀽鐨� {{}} 涓嶄細鐣欏湪浜х墿閲岋級 */
+ private static String renderText(String template, RenderState state) {
+ return Bindings.resolveText(template, state.scope, path -> {
+ if (state.reported.add(state.where + "|" + path)) {
+ state.errors.add(state.where + "缁戝畾銆寋{" + path + "}}銆嶅湪褰撳墠鏁版嵁涓彇涓嶅埌鍊硷紝宸叉覆鏌撲负绌�");
+ }
+ });
+ }
+
+ /** 鎷间竴娈靛唴鑱旀牱寮忥紝杩囨护鎺夌┖鍊� */
+ private static String cssStyle(Map<String, String> style) {
+ List<String> parts = new ArrayList<>(style.size());
+ for (Map.Entry<String, String> entry : style.entrySet()) {
+ String value = entry.getValue();
+ if (value == null || value.isEmpty()) {
+ continue;
+ }
+ parts.add(entry.getKey() + ":" + value);
+ }
+ return String.join(";", parts);
+ }
+
+ /* ------------------------------ 鏍峰紡涓庢枃妗� ------------------------------ */
+
+ /** 鏍峰紡瑙勫垯鏁扮粍 鈫� CSS 鏂囨湰锛汫rapesJS 鐢� #缁勪欢id 閫夋嫨鍣紝杩欓噷鏀瑰啓鎴� data 灞炴�ч�夋嫨鍣� */
+ private static String buildCss(Object styles) {
+ if (styles instanceof String text) {
+ return text;
+ }
+ if (!(styles instanceof List<?> rules)) {
+ return "";
+ }
+
+ List<String> blocks = new ArrayList<>();
+ Map<String, List<String>> mediaBlocks = new LinkedHashMap<>();
+ for (Object raw : rules) {
+ if (!(raw instanceof Map<?, ?> rule)) {
+ continue;
+ }
+ String selector = buildSelector(rule.get("selectors"));
+ String body = cssStyle(textMap(rule.get("style")));
+ if (selector.isEmpty() || body.isEmpty()) {
+ continue;
+ }
+ String line = selector + " { " + body + " }";
+ String mediaText = textOf(rule.get("mediaText")).trim();
+ if (!mediaText.isEmpty()) {
+ mediaBlocks.computeIfAbsent(mediaText, key -> new ArrayList<>()).add(line);
+ continue;
+ }
+ blocks.add(line);
+ }
+
+ mediaBlocks.forEach((mediaText, lines) -> {
+ String atRule = mediaText.startsWith("@") ? mediaText : "@media " + mediaText;
+ blocks.add(atRule + " { " + String.join(" ", lines) + " }");
+ });
+ return String.join("\n", blocks);
+ }
+
+ private static String buildSelector(Object rawSelectors) {
+ if (!(rawSelectors instanceof List<?> selectors)) {
+ return "";
+ }
+ List<String> parts = new ArrayList<>(selectors.size());
+ for (Object raw : selectors) {
+ String selector = toSafeSelector(textOf(raw));
+ if (!selector.isEmpty()) {
+ parts.add(selector);
+ }
+ }
+ return String.join(", ", parts);
+ }
+
+ /** #缁勪欢id 鈫� [data-qc-id="缁勪欢id"]锛岄噸澶嶈澶嶅埗鍚庢牱寮忎粛鐒跺懡涓� */
+ private static String toSafeSelector(String selector) {
+ return ID_SELECTOR.matcher(selector).replaceAll("[" + QUALITY_ID_ATTR + "=\"$1\"]");
+ }
+
+ private static Map<String, String> textMap(Object raw) {
+ Map<String, String> result = new LinkedHashMap<>();
+ if (raw instanceof Map<?, ?> map) {
+ for (Map.Entry<?, ?> entry : map.entrySet()) {
+ result.put(String.valueOf(entry.getKey()),
+ entry.getValue() == null ? null : String.valueOf(entry.getValue()));
+ }
+ }
+ return result;
+ }
+
+ private static String textOf(Object value) {
+ return value == null ? "" : String.valueOf(value);
+ }
+
+ /** 缁勮鏈�缁堟枃妗o細绾稿紶涓庨〉杈硅窛浜ょ粰 @page锛屾鏂囬噷涓嶅啀閲嶅鐣欑櫧锛屾墠鑳戒繚璇佹瘡椤甸兘鏈夎竟璺� */
+ private static String buildDocument(PageSetting page, String body, String css, ReportContext context) {
+ ResolvedPage resolved = PageSizes.resolve(page);
+ String title = context.getReport().getReportName();
+ if (title == null || title.isEmpty()) {
+ title = context.getReport().getReportNo();
+ }
+ if (title == null || title.isEmpty()) {
+ title = "璐ㄦ鎶ュ憡";
+ }
+ return String.join("\n",
+ "<!doctype html>",
+ "<html lang=\"zh-CN\">",
+ "<head>",
+ "<meta charset=\"utf-8\" />",
+ "<title>" + escapeHtml(title) + "</title>",
+ "<style>",
+ "@page { size: " + resolved.cssSize() + "; margin: " + resolved.cssMargin() + "; }",
+ BASE_CSS,
+ css,
+ "</style>",
+ "</head>",
+ "<body>" + body + "</body>",
+ "</html>");
+ }
+
+ /** 浠讳綍鏉ヨ嚜鐢ㄦ埛锛堣璁″櫒灞炴�ч潰鏉匡級鐨勬枃鏈兘蹇呴』鍏堣浆涔夊啀鎷艰繘鏍囩锛屽惁鍒欐覆鏌撴湡灏辨槸娉ㄥ叆鐐� */
+ private static String escapeHtml(String value) {
+ return value.replace("&", "&")
+ .replace("<", "<")
+ .replace(">", ">")
+ .replace("\"", """)
+ .replace("'", "'");
+ }
+
+ /** 涓�娆℃覆鏌撶殑琛岃蛋鐘舵�侊細浣滅敤鍩� + 褰撳墠浣嶇疆 + 闂娓呭崟锛岃鍐呭鍒舵椂鍏变韩鍚庝袱鑰� */
+ private static final class RenderState {
+
+ private final Map<String, Object> scope;
+ /** 褰撳墠娓叉煋浣嶇疆鐨勬弿杩帮紝鐢ㄤ簬鎶婇棶棰樺畾浣嶅埌鍏蜂綋琛� */
+ private final String where;
+ private final List<String> errors;
+ /** 宸蹭笂鎶ョ殑缂哄彛锛屽悓涓�澶勫彧鎻愮ず涓�娆� */
+ private final Set<String> reported;
+
+ private RenderState(Map<String, Object> scope, String where,
+ List<String> errors, Set<String> reported) {
+ this.scope = scope;
+ this.where = where;
+ this.errors = errors;
+ this.reported = reported;
+ }
+
+ private RenderState withScope(Map<String, Object> scope, String where) {
+ return new RenderState(scope, where, errors, reported);
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/render/RenderNode.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/render/RenderNode.java
new file mode 100644
index 0000000..56b71b0
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/render/RenderNode.java
@@ -0,0 +1,88 @@
+package cn.iocoder.yudao.module.qcreport.engine.render;
+
+import cn.iocoder.yudao.module.qcreport.engine.JsValues;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * GrapesJS 椤圭洰鏁版嵁鑺傜偣銆�
+ * <p>
+ * 鍙0鏄庢覆鏌撻渶瑕佺殑瀛楁锛岀洿鎺ヨ鍘熷 Map锛歿@code components} 鏃㈠彲鑳芥槸鏁扮粍涔熷彲鑳芥槸瀛楃涓诧紝
+ * 鐢� POJO 鍙嶅簭鍒楀寲瑕侀澶栧鐞嗚仈鍚堢被鍨嬶紝涓嶅鎸夐渶鍙栧�兼潵寰楃洿鐧斤紝涔熺渷涓�娆℃嫹璐濄��
+ */
+public final class RenderNode {
+
+ private final Map<String, Object> data;
+
+ private RenderNode(Map<String, Object> data) {
+ this.data = data;
+ }
+
+ /** 涓嶆槸瀵硅薄鑺傜偣鏃惰繑鍥� null锛堝鏁扮粍閲屾贩鍏ヤ簡瀛楃涓诧級 */
+ @SuppressWarnings("unchecked")
+ public static RenderNode of(Object raw) {
+ return raw instanceof Map<?, ?> ? new RenderNode((Map<String, Object>) raw) : null;
+ }
+
+ public String type() {
+ return text(data.get("type"));
+ }
+
+ public String tagName() {
+ return text(data.get("tagName"));
+ }
+
+ /** 鍙湪 content 鏈韩鏄瓧绗︿覆鏃惰繑鍥烇紝涓庡墠绔� {@code typeof node.content === 'string'} 涓�鑷� */
+ public String content() {
+ return data.get("content") instanceof String content ? content : null;
+ }
+
+ /** 鍙栦竴涓睘鎬у�硷紝鍙栦笉鍒拌繑鍥� null */
+ public String attribute(String name) {
+ return attributes().get(name);
+ }
+
+ /** 灞炴�ц〃锛屽�肩粺涓�鎴愭枃鏈� */
+ public Map<String, String> attributes() {
+ Map<String, String> result = new LinkedHashMap<>();
+ if (data.get("attributes") instanceof Map<?, ?> attributes) {
+ for (Map.Entry<?, ?> entry : attributes.entrySet()) {
+ result.put(String.valueOf(entry.getKey()), JsValues.asText(entry.getValue()));
+ }
+ }
+ return result;
+ }
+
+ /** 琛屽唴鏍峰紡琛紝鍊肩粺涓�鎴愭枃鏈� */
+ public Map<String, String> style() {
+ Map<String, String> result = new LinkedHashMap<>();
+ if (data.get("style") instanceof Map<?, ?> style) {
+ for (Map.Entry<?, ?> entry : style.entrySet()) {
+ result.put(String.valueOf(entry.getKey()), JsValues.asText(entry.getValue()));
+ }
+ }
+ return result;
+ }
+
+ /** 瀛愮粍浠讹紱components 鏄瓧绗︿覆锛堟棫鏁版嵁/绾枃鏈粍浠讹級鏃惰繑鍥炵┖鍒楄〃 */
+ public List<RenderNode> children() {
+ List<RenderNode> result = new ArrayList<>();
+ if (data.get("components") instanceof List<?> components) {
+ for (Object raw : components) {
+ RenderNode child = of(raw);
+ if (child != null) {
+ result.add(child);
+ }
+ }
+ }
+ return result;
+ }
+
+ private static String text(Object value) {
+ return value == null ? null : String.valueOf(value);
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/render/RenderOutcome.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/render/RenderOutcome.java
new file mode 100644
index 0000000..48e1ab4
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/render/RenderOutcome.java
@@ -0,0 +1,16 @@
+package cn.iocoder.yudao.module.qcreport.engine.render;
+
+import cn.iocoder.yudao.module.qcreport.engine.context.ReportContext;
+
+import java.util.List;
+
+/**
+ * 娓叉煋缁撴灉銆�
+ *
+ * @param html 瀹屾暣 HTML 鏂囨。锛屾墦鍗�/PDF 鐩存帴浣跨敤
+ * @param body 姝f枃鐗囨锛屼究浜庡祵鍏ラ〉闈㈤瑙�
+ * @param context 鍒ゅ畾鍚庣殑涓婁笅鏂囷紙鍚� PASS/FAIL 鍒ゅ畾涓庡悎鏍肩巼锛�
+ * @param errors 瑙勫垯涓庣粦瀹氱殑闂娓呭崟锛岃皟鐢ㄦ柟蹇呴』鏄惧紡鏆撮湶锛屼笉鑳芥倓鎮勫悶鎺�
+ */
+public record RenderOutcome(String html, String body, ReportContext context, List<String> errors) {
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/report/EvaluationOutcome.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/report/EvaluationOutcome.java
new file mode 100644
index 0000000..6348a52
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/report/EvaluationOutcome.java
@@ -0,0 +1,14 @@
+package cn.iocoder.yudao.module.qcreport.engine.report;
+
+import cn.iocoder.yudao.module.qcreport.engine.context.ReportContext;
+
+import java.util.List;
+
+/**
+ * 鍒ゅ畾缁撴灉銆�
+ *
+ * @param context 鍒ゅ畾鍚庣殑涓婁笅鏂囷紙鍚悇椤� PASS/FAIL 涓庢姤鍛婄粨璁恒�佸悎鏍肩巼锛�
+ * @param errors 瑙勫垯鐨勯棶棰樻竻鍗曪紝娓叉煋鏃跺繀椤诲湪鎶ュ憡涓婃樉寮忔毚闇诧紝涓嶈兘鎮勬倓鍚炴帀
+ */
+public record EvaluationOutcome(ReportContext context, List<String> errors) {
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/report/ReportEvaluator.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/report/ReportEvaluator.java
new file mode 100644
index 0000000..4f1b3d9
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/report/ReportEvaluator.java
@@ -0,0 +1,190 @@
+package cn.iocoder.yudao.module.qcreport.engine.report;
+
+import cn.iocoder.yudao.module.qcreport.engine.Paths;
+import cn.iocoder.yudao.module.qcreport.engine.QualityResult;
+import cn.iocoder.yudao.module.qcreport.engine.context.InspectionItem;
+import cn.iocoder.yudao.module.qcreport.engine.context.ReportContext;
+import cn.iocoder.yudao.module.qcreport.engine.context.ReportFields;
+import cn.iocoder.yudao.module.qcreport.engine.rule.QualityRuleDefinition;
+import cn.iocoder.yudao.module.qcreport.engine.rule.RuleEngine;
+import cn.iocoder.yudao.module.qcreport.engine.rule.RuleScope;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * 鎶ュ憡鍒ゅ畾銆�
+ * <p>
+ * 鍦ㄦ覆鏌撳墠鎶婃楠岄」绠楁垚 PASS/FAIL锛屽苟姹囨�诲嚭鎶ュ憡缁撹涓庡悎鏍肩巼銆�
+ * 鍒ゅ畾鍙彂鐢熷湪杩欓噷锛岀粍浠朵笌妯℃澘閮戒笉鍋氳绠楋紝淇濊瘉鍚屼竴浠芥暟鎹湪浠讳綍妯℃澘涓嬪垽瀹氫竴鑷淬��
+ * <p>
+ * 涓庡墠绔� {@code engine/report-evaluator.ts} 涓�涓�瀵瑰簲锛屼袱杈瑰繀椤荤畻鍑哄悓涓�缁撴灉銆�
+ */
+public final class ReportEvaluator {
+
+ private ReportEvaluator() {
+ }
+
+ /**
+ * 璁$畻妫�楠岄」鍒ゅ畾涓庢姤鍛婃眹鎬汇��
+ * <p>
+ * 鍗曚釜妫�楠岄」鐨勫垽瀹氫紭鍏堢骇锛歩tem 浣滅敤鍩熻鍒� 鈫� 瑙勬牸涓婁笅闄� 鈫� 鏁版嵁鑷甫缁撴灉銆�
+ * 鎶ュ憡绾у垽瀹氶粯璁ゅ彇銆屽叏閮ㄦ楠岄」鍚堟牸銆嶏紝鏈� report 浣滅敤鍩熻鍒欐椂浠ヨ鍒欎负鍑嗐��
+ * <p>
+ * 涓嶄慨鏀逛紶鍏ョ殑涓婁笅鏂囷紝鍒ゅ畾鍚庣殑缁撴灉鏀惧湪杩斿洖鍊奸噷銆�
+ */
+ public static EvaluationOutcome evaluate(ReportContext context, List<QualityRuleDefinition> rules) {
+ List<String> errors = new ArrayList<>();
+ List<QualityRuleDefinition> itemRules = new ArrayList<>();
+ List<QualityRuleDefinition> reportRules = new ArrayList<>();
+ for (QualityRuleDefinition rule : rules == null ? List.<QualityRuleDefinition>of() : rules) {
+ if (rule == null || !rule.active()) {
+ continue;
+ }
+ if (rule.scope() == RuleScope.REPORT) {
+ reportRules.add(rule);
+ } else {
+ itemRules.add(rule);
+ }
+ }
+
+ List<InspectionItem> source = context.getInspectionItems() == null ? List.of() : context.getInspectionItems();
+ List<InspectionItem> items = new ArrayList<>(source.size());
+ for (InspectionItem item : source) {
+ items.add(item.copy());
+ }
+
+ // 鏃犲垽瀹氫緷鎹殑椤规暟锛屽彧鐢ㄦ潵鎶婅繖绫婚」浠庡悎鏍肩巼鍒嗘瘝涓庢姤鍛婄粨璁洪噷鎽樺嚭鍘�
+ int undecidableCount = 0;
+
+ for (int index = 0; index < items.size(); index++) {
+ InspectionItem item = items.get(index);
+ if (!itemRules.isEmpty()) {
+ // 閫愰」瑙勫垯鍦ㄣ�屽崟椤逛笂涓嬫枃銆嶉噷姹傚�硷細item 鎸囧悜褰撳墠琛岋紝index 浠� 1 寮�濮嬩笌鎶ュ憡搴忓彿涓�鑷�
+ Map<String, Object> scoped = context.toScope();
+ scoped.put("item", ReportContext.itemMap(item));
+ scoped.put("index", index + 1);
+ boolean passed = true;
+ boolean failed = false;
+ for (QualityRuleDefinition rule : itemRules) {
+ try {
+ if (!RuleEngine.test(rule.expression(), scoped)) {
+ passed = false;
+ }
+ } catch (RuntimeException error) {
+ failed = true;
+ errors.add("绗� " + (index + 1) + " 椤广��" + orEmpty(item.getItemName()) + "銆嶇殑瑙勫垯銆�"
+ + rule.rawLabel() + "銆嶆棤娉曟墽琛岋細" + error.getMessage());
+ }
+ }
+ item.applyResult(failed ? null : (passed ? QualityResult.PASS : QualityResult.FAIL));
+ continue;
+ }
+
+ QualityResult byLimit = evaluateByLimit(item);
+ if (byLimit != null) {
+ item.applyResult(byLimit);
+ continue;
+ }
+
+ QualityResult existing = QualityResult.of(item.getResult());
+ if (existing == null) {
+ // 鏃㈡病鏈夎鍒欍�佷篃娌℃湁鍒ゅ畾渚濇嵁锛氬瀹炴爣鍑烘潵锛屼笉瑕侀粯璁ゅ悎鏍�
+ item.applyUndecidable();
+ undecidableCount++;
+ errors.add("绗� " + (index + 1) + " 椤广��"
+ + (isBlank(item.getItemName()) ? "鏈懡鍚�" : item.getItemName())
+ + "銆嶆病鏈夎鏍间笂涓嬮檺涔熸病鏈夊垽瀹氳鍒欙紝鏃犳硶鍒ゅ畾");
+ continue;
+ }
+ item.applyResult(existing);
+ }
+
+ int passCount = 0;
+ int failCount = 0;
+ for (InspectionItem item : items) {
+ if (QualityResult.PASS.name().equals(item.getResult())) {
+ passCount++;
+ } else if (QualityResult.FAIL.name().equals(item.getResult())) {
+ failCount++;
+ }
+ }
+ int total = items.size();
+ // 鍚堟牸鐜囩殑鍒嗘瘝鍙畻銆岃兘鍒ゅ畾銆嶇殑椤癸紝鏃犲垽瀹氳鍒欑殑椤规棦涓嶅姞鍒嗕篃涓嶅噺鍒�
+ int decidableCount = total - undecidableCount;
+
+ QualityResult verdict = null;
+ if (!reportRules.isEmpty()) {
+ Map<String, Object> scoped = context.scope(items);
+ scoped.put("index", 0);
+ boolean passed = true;
+ boolean failed = false;
+ for (QualityRuleDefinition rule : reportRules) {
+ try {
+ if (!RuleEngine.test(rule.expression(), scoped)) {
+ passed = false;
+ }
+ } catch (RuntimeException error) {
+ failed = true;
+ errors.add("鎶ュ憡绾ц鍒欍��" + rule.rawLabel() + "銆嶆棤娉曟墽琛岋細" + error.getMessage());
+ }
+ }
+ verdict = failed ? null : (passed ? QualityResult.PASS : QualityResult.FAIL);
+ } else if (decidableCount > 0) {
+ // 鍙湁銆屽叏閮ㄥ彲鍒ゅ畾椤归兘鍚堟牸銆嶆墠缁欏悎鏍肩粨璁恒�傛棤鍒ゅ畾瑙勫垯鐨勯」涓嶅弬涓庯紝瀹冧滑娌℃湁瀵归敊鍙█銆�
+ // 瀛樺湪寰呭垽瀹氶」锛堣鍒欒窇鎸傦級鏃朵笉缁欑粨璁猴細娌¢獙杩囦笉鑳借鍚堟牸锛屾病璇佹嵁涔熶笉鑳借涓嶅悎鏍硷紝
+ // 鍚﹀垯浼氬嚭鐜般�岀粨璁哄悎鏍笺�佸悎鏍肩巼 0%銆嶈繖绉嶈嚜鐩哥煕鐩剧殑鎶ュ憡銆�
+ if (failCount > 0) {
+ verdict = QualityResult.FAIL;
+ } else if (passCount == decidableCount) {
+ verdict = QualityResult.PASS;
+ }
+ }
+
+ ReportFields report = context.getReport().copy()
+ .setTotal(total)
+ .setPassCount(passCount)
+ .setFailCount(failCount)
+ .setPassRate(formatPassRate(passCount, decidableCount))
+ .applyResult(verdict);
+ return new EvaluationOutcome(new ReportContext().setReport(report).setInspectionItems(items), errors);
+ }
+
+ /** 鐢ㄨ鏍间笂涓嬮檺鍒ゅ畾鍗曢」锛氬疄娴嬪�间笉鍦ㄥ尯闂村唴鍗充笉鍚堟牸 */
+ private static QualityResult evaluateByLimit(InspectionItem item) {
+ double actual = Paths.toNumber(item.getActualValue());
+ if (!Double.isFinite(actual)) {
+ return null;
+ }
+ boolean hasUpper = item.getUpperLimit() != null && Double.isFinite(item.getUpperLimit());
+ boolean hasLower = item.getLowerLimit() != null && Double.isFinite(item.getLowerLimit());
+ if (!hasUpper && !hasLower) {
+ return null;
+ }
+ if (hasUpper && actual > item.getUpperLimit()) {
+ return QualityResult.FAIL;
+ }
+ if (hasLower && actual < item.getLowerLimit()) {
+ return QualityResult.FAIL;
+ }
+ return QualityResult.PASS;
+ }
+
+ private static String formatPassRate(int passCount, int total) {
+ if (total == 0) {
+ return "";
+ }
+ return String.format(Locale.ROOT, "%.2f%%", (double) passCount / total * 100);
+ }
+
+ private static String orEmpty(String value) {
+ return value == null ? "" : value;
+ }
+
+ private static boolean isBlank(String value) {
+ return value == null || value.isEmpty();
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/QualityRuleDefinition.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/QualityRuleDefinition.java
new file mode 100644
index 0000000..6b7dd82
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/QualityRuleDefinition.java
@@ -0,0 +1,79 @@
+package cn.iocoder.yudao.module.qcreport.engine.rule;
+
+import java.util.Map;
+
+/**
+ * 鍒ゅ畾瑙勫垯瀹氫箟銆�
+ * <p>
+ * 涓庡墠绔� {@code engine/report-evaluator.ts} 鐨� QualityRuleDefinition 涓�涓�瀵瑰簲锛�
+ * 涔熷氨鏄ā鏉� Schema 鐨� {@code rules} 鏁扮粍閲屾瘡涓�椤圭殑濂戠害锛�
+ * {@code { id, name, scope: 'item' | 'report', expression, enabled }}銆�
+ *
+ * @param id 瑙勫垯鏍囪瘑锛岀敤浜庡嚭閿欐椂瀹氫綅
+ * @param name 瑙勫垯鍚嶇О
+ * @param scope 浣滅敤鍩燂細閫愰」鍒ゅ畾 / 鎶ュ憡绾ф眹鎬�
+ * @param expression 鍒ゅ畾琛ㄨ揪寮忥紝姹傚�间负鐪熻涓哄悎鏍�
+ * @param enabled 鏄惁鍙備笌鍒ゅ畾锛宯ull 绛夊悓 true
+ */
+public record QualityRuleDefinition(String id, String name, RuleScope scope,
+ String expression, Boolean enabled) {
+
+ /** 鏄惁鍙備笌鍒ゅ畾锛屼笌鍓嶇 {@code rule.enabled !== false} 鍚岃涔� */
+ public boolean active() {
+ return enabled == null || enabled;
+ }
+
+ /** 鍑洪敊鎻愮ず閲岀敤鐨勫師濮嬪悕锛屼袱鑰呴兘缂烘椂涓虹┖涓诧紙涓庡墠绔� {@code rule.name ?? rule.id ?? ''} 涓�鑷达級 */
+ public String rawLabel() {
+ if (name != null) {
+ return name;
+ }
+ return id == null ? "" : id;
+ }
+
+ /** 鍑洪敊鎻愮ず閲岀敤鐨勮鍒欏悕 */
+ public String label() {
+ String trimmed = name == null ? "" : name.trim();
+ if (!trimmed.isEmpty()) {
+ return trimmed;
+ }
+ return id == null || id.isEmpty() ? "鏈懡鍚嶈鍒�" : id;
+ }
+
+ /**
+ * 浠� Schema 鐨� rules 椤硅В鏋愶紝缂哄瓧娈电殑鎸夐粯璁ゅ�煎厹搴曘��
+ * <p>
+ * 鍙仛鍙栧�间笉鍋氭牎楠岋細Schema 鏄璁″櫒瀛樼殑锛屾牸寮忛棶棰樹細鍦ㄦ墽琛屾椂鎶ュ嚭鏉ワ紝
+ * 璇荤殑鏃跺�欏啀鎶涗竴娆″紓甯稿彧浼氭妸銆屼竴澶勫潖鏁版嵁銆嶆斁澶ф垚銆屾暣浠芥ā鏉挎墦涓嶅紑銆嶃��
+ */
+ public static QualityRuleDefinition from(Map<?, ?> raw) {
+ if (raw == null) {
+ return null;
+ }
+ return new QualityRuleDefinition(
+ text(raw.get("id")),
+ text(raw.get("name")),
+ RuleScope.of(text(raw.get("scope"))),
+ text(raw.get("expression")),
+ flag(raw.get("enabled")));
+ }
+
+ private static String text(Object value) {
+ return value == null ? null : String.valueOf(value);
+ }
+
+ /** 鍙妸鏄庣‘鐨� false / "false" / 0 褰撲綔鍋滅敤锛岀己鐪佽涓哄惎鐢� */
+ private static Boolean flag(Object value) {
+ if (value instanceof Boolean bool) {
+ return bool;
+ }
+ if (value instanceof Number number) {
+ return number.intValue() != 0;
+ }
+ if (value instanceof String text) {
+ return !"false".equalsIgnoreCase(text.trim());
+ }
+ return null;
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleEngine.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleEngine.java
new file mode 100644
index 0000000..a4c9b89
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleEngine.java
@@ -0,0 +1,101 @@
+package cn.iocoder.yudao.module.qcreport.engine.rule;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 鍒ゅ畾瑙勫垯寮曟搸鍏ュ彛銆�
+ * <p>
+ * 瑙勫垯鏂囨湰鏉ヨ嚜鐢ㄦ埛锛屽叏绋嬪彧鐢ㄨ嚜寤虹殑璇嶆硶/璇硶鍒嗘瀽涓庣櫧鍚嶅崟鍑芥暟姹傚�硷紝
+ * 涓嶇 eval銆佷笉纰拌剼鏈紩鎿庘�斺�旇繖鏄‖绾︽潫锛屼笉鏄鏍煎亸濂姐��
+ * <p>
+ * 涓庡墠绔� {@code engine/rule-engine.ts} 涓�涓�瀵瑰簲锛屽悓涓�浠借鍒欎袱绔繀椤荤畻鍑哄悓涓�缁撴灉銆�
+ */
+public final class RuleEngine {
+
+ /** 宸茶В鏋愮殑璇硶鏍戠紦瀛橈細鍚屼竴鏉¤鍒欒鍦ㄥ琛屾楠岄」涓婇噸澶嶆眰鍊硷紝涓嶅繀鍙嶅瑙f瀽 */
+ private static final Map<String, RuleNode> CACHE = new ConcurrentHashMap<>();
+
+ /**
+ * 缂撳瓨鏉℃暟涓婇檺銆�
+ * <p>
+ * 瑙勫垯鏉ヨ嚜淇濆瓨涓嬫潵鐨勬ā鏉匡紝鏉℃暟澶╃劧鏈夐檺锛涗絾鏍¢獙鎺ュ彛浼氳鍙嶅璋冪敤锛�
+ * 娌℃湁涓婇檺鐨勯潤鎬佺紦瀛樼瓑浜庢妸鐢ㄦ埛杈撳叆鏀掑湪鍫嗛噷锛岃繖閲屽埌閲忓氨涓嶅啀寰�閲屾斁銆�
+ */
+ private static final int MAX_CACHE_SIZE = 512;
+
+ private RuleEngine() {
+ }
+
+ /** 瑙f瀽瑙勫垯鏂囨湰锛岃娉曢敊璇姏 {@link RuleSyntaxException} */
+ public static RuleNode parse(String expression) {
+ return RuleParser.parse(expression);
+ }
+
+ /** 瑙f瀽骞剁紦瀛橈紝渚涙覆鏌撴椂鍙嶅姹傚�间娇鐢� */
+ public static RuleNode compiled(String expression) {
+ if (expression == null) {
+ throw new RuleSyntaxException("瑙勫垯琛ㄨ揪寮忎负绌�", 0);
+ }
+ RuleNode cached = CACHE.get(expression);
+ if (cached != null) {
+ return cached;
+ }
+ RuleNode node = RuleParser.parse(expression);
+ if (CACHE.size() < MAX_CACHE_SIZE) {
+ CACHE.put(expression, node);
+ }
+ return node;
+ }
+
+ /**
+ * 鏍¢獙瑙勫垯鏂囨湰鐨勮娉曪紝杩斿洖閿欒娓呭崟锛岀┖鍒楄〃琛ㄧず閫氳繃銆�
+ * <p>
+ * 杩欓噷<b>鍙煡璇硶</b>锛涘嚱鏁扮櫧鍚嶅崟浜ょ粰 {@link RuleEvaluator#findUnknownFunction}锛�
+ * 鐢� {@link cn.iocoder.yudao.module.qcreport.engine.QualityReportEngine#validateRules}
+ * 鎶婁袱鑰呮嫾鎴愬畬鏁寸殑淇濆瓨鍓嶆牎楠屻��
+ * 鍓嶇鎶婅繖涓ゆ鍚堝湪浜� {@code validateRule} 涓�涓嚱鏁伴噷锛屼絾鎶ラ敊鏂囨涓ょ閫愬瓧涓�鑷粹�斺��
+ * 鍙e緞涓嶄竴鑷翠細鍙樻垚銆岃璁″櫒鑳藉瓨銆佸悗绔瓨涓嶄簡銆嶈繖绉嶄簰鐩告墦鏋剁殑鍦洪潰銆�
+ */
+ public static List<String> validate(QualityRuleDefinition rule) {
+ List<String> errors = new ArrayList<>();
+ String label = rule.label();
+ String expression = rule.expression();
+ if (expression == null || expression.trim().isEmpty()) {
+ errors.add("瑙勫垯銆�" + label + "銆嶇殑琛ㄨ揪寮忎负绌�");
+ return errors;
+ }
+ try {
+ RuleParser.parse(expression);
+ } catch (RuleSyntaxException error) {
+ errors.add("瑙勫垯銆�" + label + "銆嶈娉曢敊璇細" + error.getMessage()
+ + "锛堢 " + (error.position() + 1) + " 涓瓧绗︼級");
+ } catch (RuntimeException error) {
+ errors.add("瑙勫垯銆�" + label + "銆嶆棤娉曡В鏋愶細" + error.getMessage());
+ }
+ return errors;
+ }
+
+ /** 姹傚�硷紝杩斿洖鍘熷缁撴灉锛堝彲鑳芥槸鏁板瓧銆佸瓧绗︿覆銆佸竷灏旓級 */
+ public static Object evaluate(String expression, Object context) {
+ return RuleEvaluator.evaluateNode(parse(expression), context);
+ }
+
+ /** 姹傚�煎苟杞垚甯冨皵鍒ゅ畾锛岀敤浜庛�屾槸鍚﹀悎鏍笺�嶈繖绫绘潯浠� */
+ public static boolean test(String expression, Object context) {
+ return RuleEvaluator.evaluateCondition(parse(expression), context);
+ }
+
+ /** 闈欐�佹鏌ヨ〃杈惧紡閲岃皟鐢ㄧ殑鍑芥暟鏄惁鍦ㄧ櫧鍚嶅崟鍐咃紝涓嶅湪鍒欒繑鍥炲嚱鏁板悕 */
+ public static String findUnknownFunction(String expression) {
+ return RuleEvaluator.findUnknownFunction(parse(expression));
+ }
+
+ /** 琛ㄨ揪寮忎緷璧栫殑涓婁笅鏂囪矾寰勶紝娓叉煋鍓嶅彲鎹妫�鏌ユ暟鎹槸鍚﹂綈澶� */
+ public static List<String> listPaths(String expression) {
+ return RuleEvaluator.listPaths(parse(expression));
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleEvaluator.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleEvaluator.java
new file mode 100644
index 0000000..ad9de51
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleEvaluator.java
@@ -0,0 +1,415 @@
+package cn.iocoder.yudao.module.qcreport.engine.rule;
+
+import cn.iocoder.yudao.module.qcreport.engine.JsValues;
+import cn.iocoder.yudao.module.qcreport.engine.Paths;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 瑙勫垯姹傚�笺��
+ * <p>
+ * 鍙 {@link RuleNode} 涓庣櫧鍚嶅崟鍑芥暟锛岃鍒欐枃鏈噷鐨勪换浣曞唴瀹归兘涓嶄細鍙樻垚鍙墽琛屼唬鐮併��
+ * 涓庡墠绔� {@code engine/rule-engine.ts} 鐨勬眰鍊兼涓�涓�瀵瑰簲锛屼袱杈圭粨鏋滃繀椤讳竴鑷淬��
+ */
+public final class RuleEvaluator {
+
+ /** 鍒ゅ畾缁撴灉绫诲彇鍊肩粺涓�鎴� PASS / FAIL锛氬吋瀹逛腑鏂囥�佸竷灏斾笌鏁板瓧 1/0 */
+ private static final Set<String> PASS_TOKENS = Set.of("PASS", "TRUE", "鍚堟牸", "OK", "1", "鏄�");
+ private static final Set<String> FAIL_TOKENS = Set.of("FAIL", "FALSE", "涓嶅悎鏍�", "NG", "0", "鍚�");
+
+ private RuleEvaluator() {
+ }
+
+ /* ------------------------------ 鍩虹鍒ゅ畾 ------------------------------ */
+
+ /**
+ * JS {@code String(value)} 鐨勭瓑浠峰疄鐜般��
+ * <p>
+ * 瑙勫垯閲岀殑鏂囨湰姣旇緝涓庢嫾鎺ラ兘瑕佽蛋杩欓噷锛屽惁鍒欎袱绔細绠楀嚭涓嶅悓缁撴灉銆�
+ */
+ public static String asText(Object value) {
+ return JsValues.asText(value);
+ }
+
+ /** 绌哄�硷細null 鎴栫┖涓诧紙绌烘暟缁勪笉绠楃┖锛� */
+ public static boolean isBlank(Object value) {
+ return value == null || "".equals(value);
+ }
+
+ /** 鐪熷�煎垽瀹氾紝涓� JS 鐗� truthy 鍚岃涔� */
+ public static boolean truthy(Object value) {
+ if (value instanceof List<?> list) {
+ return !list.isEmpty();
+ }
+ if (isBlank(value)) {
+ return false;
+ }
+ if (value instanceof Boolean bool) {
+ return bool;
+ }
+ double numeric = Paths.toNumber(value);
+ if (Double.isFinite(numeric)) {
+ return numeric != 0;
+ }
+ return true;
+ }
+
+ /** 涓や晶閮借兘褰撴暟瀛楁椂鎸夋暟鍊兼瘮杈冿紝鍚﹀垯鎸夊瓧绗︿覆姣旇緝 */
+ public static int compare(Object left, Object right) {
+ double leftNumber = Paths.toNumber(left);
+ double rightNumber = Paths.toNumber(right);
+ if (Double.isFinite(leftNumber) && Double.isFinite(rightNumber)) {
+ return Double.compare(leftNumber, rightNumber);
+ }
+ return asText(left).compareTo(asText(right));
+ }
+
+ /** 鍒ゅ畾缁撴灉绫诲彇鍊肩粺涓�鎴� PASS / FAIL锛岃瘑鍒笉鍑鸿繑鍥炵┖涓� */
+ public static String normalizeResultToken(Object value) {
+ if (value instanceof Boolean bool) {
+ return bool ? "PASS" : "FAIL";
+ }
+ String text = asText(value).trim().toUpperCase(Locale.ROOT);
+ if (PASS_TOKENS.contains(text)) {
+ return "PASS";
+ }
+ return FAIL_TOKENS.contains(text) ? "FAIL" : "";
+ }
+
+ /* ------------------------------ 鐧藉悕鍗曞嚱鏁� ------------------------------ */
+
+ /** 鐧藉悕鍗曞嚱鏁拌〃锛岃鍒欐枃鏈彧鑳借皟鐢ㄨ繖閲岄潰鐨勫嚱鏁� */
+ private static final Map<String, RuleFunction> FUNCTIONS = buildFunctions();
+
+ private static Map<String, RuleFunction> buildFunctions() {
+ Map<String, RuleFunction> functions = new LinkedHashMap<>();
+ functions.put("ABS", args -> Math.abs(requireNumber("ABS", arg(args, 0))));
+ functions.put("AVG", args -> mean(requireNumbers("AVG", arg(args, 0))));
+ functions.put("COUNT", args -> arg(args, 0) instanceof List<?> list
+ ? list.size()
+ : Paths.toNumberArray(arg(args, 0)).size());
+ // 杩囩▼鑳藉姏鎸囨暟 CP=(USL-LSL)/(6蟽)
+ functions.put("CP", args -> {
+ List<Double> values = requireNumbers("CP", arg(args, 0));
+ double deviation = standardDeviation(values);
+ if (!Double.isFinite(deviation) || deviation == 0) {
+ return Double.NaN;
+ }
+ return (requireNumber("CP", arg(args, 1)) - requireNumber("CP", arg(args, 2))) / (6 * deviation);
+ });
+ // 杩囩▼鑳藉姏鎸囨暟 CPK=min(USL-渭, 渭-LSL)/(3蟽)
+ functions.put("CPK", args -> {
+ List<Double> values = requireNumbers("CPK", arg(args, 0));
+ double deviation = standardDeviation(values);
+ if (!Double.isFinite(deviation) || deviation == 0) {
+ return Double.NaN;
+ }
+ double upper = requireNumber("CPK", arg(args, 1));
+ double lower = requireNumber("CPK", arg(args, 2));
+ double average = mean(values);
+ return Math.min(upper - average, average - lower) / (3 * deviation);
+ });
+ // 涓嶅悎鏍肩巼锛堢櫨鍒嗘瘮锛夛紝鍙e緞涓� PASS_RATE 涓�鑷�
+ functions.put("FAIL_RATE", args -> rate(arg(args, 0), "FAIL"));
+ functions.put("MAX", args -> extreme(requireNumbers("MAX", arg(args, 0)), true));
+ functions.put("MIN", args -> extreme(requireNumbers("MIN", arg(args, 0)), false));
+ // 鍚堟牸鐜囷紙鐧惧垎姣旓紝淇濈暀涓や綅锛�
+ functions.put("PASS_RATE", args -> rate(arg(args, 0), "PASS"));
+ functions.put("ROUND", args -> {
+ double digits = args.size() > 1 ? requireNumber("ROUND", arg(args, 1)) : 0;
+ double factor = Math.pow(10, digits);
+ return Math.round(requireNumber("ROUND", arg(args, 0)) * factor) / factor;
+ });
+ functions.put("STDDEV", args -> standardDeviation(requireNumbers("STDDEV", arg(args, 0))));
+ functions.put("SUM", args -> {
+ double sum = 0;
+ for (Double value : requireNumbers("SUM", arg(args, 0))) {
+ sum += value;
+ }
+ return sum;
+ });
+ // 涓嶈兘鎹㈡垚 Map.copyOf锛氬畠涓嶄繚璇侀亶鍘嗛『搴忥紝鎶ラ敊閲屽垪鍑虹殑鍙敤鍑芥暟浼氶殢鏈烘帓
+ return Collections.unmodifiableMap(functions);
+ }
+
+ /**
+ * 鍙栫 index 涓疄鍙傦紝缂哄弬杩斿洖 null銆�
+ * <p>
+ * 灏戜簡杩欎釜鍏滃簳锛寋@code SUM()} 杩欑鍐欓敊鐨勮鍒欎細鐩存帴鎶� IndexOutOfBoundsException 绌块�忓埌鎺ュ彛灞傦紝
+ * 鐢ㄦ埛鐪嬪埌鐨勬槸銆岀郴缁熷紓甯搞�嶈�屼笉鏄�岃繖鏉¤鍒欏啓閿欎簡銆嶃��
+ */
+ private static Object arg(List<Object> args, int index) {
+ return index < args.size() ? args.get(index) : null;
+ }
+
+ /** 鐧藉悕鍗曞嚱鏁板悕锛岄『搴忕ǔ瀹氾紝鐢ㄤ簬鎶ラ敊鏃跺垪鍑哄彲鐢ㄥ嚱鏁� */
+ public static List<String> functionNames() {
+ return List.copyOf(FUNCTIONS.keySet());
+ }
+
+ /** 涓�娆℃�ф眰鍊煎叏閮ㄥ悎鏍�/涓嶅悎鏍煎崰姣旓紝鍙e緞涓庡墠绔竴鑷� */
+ private static double rate(Object value, String expected) {
+ List<Object> values = Paths.flatten(value);
+ if (values.isEmpty()) {
+ return Double.NaN;
+ }
+ int hit = 0;
+ for (Object element : values) {
+ if (expected.equals(normalizeResultToken(element))) {
+ hit++;
+ }
+ }
+ return toFixed2((double) hit / values.size() * 100);
+ }
+
+ /** JS toFixed(2) 鍚庡啀鍙栧洖鏁板�硷細淇濈暀涓や綅鐨勭櫨鍒嗘瘮 */
+ private static double toFixed2(double value) {
+ return Math.round(value * 100) / 100.0;
+ }
+
+ private static double extreme(List<Double> values, boolean max) {
+ double result = values.get(0);
+ for (Double value : values) {
+ result = max ? Math.max(result, value) : Math.min(result, value);
+ }
+ return result;
+ }
+
+ private static double mean(List<Double> values) {
+ double sum = 0;
+ for (Double value : values) {
+ sum += value;
+ }
+ return sum / values.size();
+ }
+
+ /** 鏍锋湰鏍囧噯宸紙n-1锛夛紝SPC 璁$畻 CP/CPK 鐢ㄨ繖涓彛寰� */
+ private static double standardDeviation(List<Double> values) {
+ if (values.size() < 2) {
+ return Double.NaN;
+ }
+ double average = mean(values);
+ double variance = 0;
+ for (Double value : values) {
+ variance += Math.pow(value - average, 2);
+ }
+ return Math.sqrt(variance / (values.size() - 1));
+ }
+
+ private static List<Double> requireNumbers(String name, Object value) {
+ List<Double> values = Paths.toNumberArray(value);
+ if (values.isEmpty()) {
+ throw new RuleRuntimeException("鍑芥暟 " + name + " 闇�瑕佹暟鍊煎瀷鍙傛暟锛屽疄闄呭彇鍒般��" + asText(value) + "銆�");
+ }
+ return values;
+ }
+
+ private static double requireNumber(String name, Object value) {
+ double numeric = Paths.toNumber(value);
+ if (!Double.isFinite(numeric)) {
+ throw new RuleRuntimeException("鍑芥暟 " + name + " 闇�瑕佹暟瀛楀弬鏁帮紝瀹為檯鍙栧埌銆�" + asText(value) + "銆�");
+ }
+ return numeric;
+ }
+
+ /* ------------------------------ 姹傚�� ------------------------------ */
+
+ /** 姹傚�硷紝杩斿洖鍘熷缁撴灉锛堝彲鑳芥槸鏁板瓧銆佸瓧绗︿覆銆佸竷灏旓級 */
+ public static Object evaluateNode(RuleNode node, Object context) {
+ return switch (node) {
+ case RuleNode.Literal literal -> literal.value();
+ case RuleNode.Path path -> Paths.readPath(context, path.path());
+ case RuleNode.Call call -> evaluateCall(call, context);
+ case RuleNode.Unary unary -> evaluateUnary(unary, context);
+ case RuleNode.Between between -> evaluateBetween(between, context);
+ case RuleNode.In inNode -> evaluateIn(inNode, context);
+ case RuleNode.Binary binary -> evaluateBinary(binary, context);
+ };
+ }
+
+ /** 姹傚�煎苟杞垚甯冨皵鍒ゅ畾锛岀敤浜庛�屾槸鍚﹀悎鏍笺�嶈繖绫绘潯浠� */
+ public static boolean evaluateCondition(RuleNode node, Object context) {
+ return truthy(evaluateNode(node, context));
+ }
+
+ private static Object evaluateCall(RuleNode.Call call, Object context) {
+ RuleFunction handler = FUNCTIONS.get(call.name());
+ if (handler == null) {
+ throw new RuleRuntimeException(
+ "涓嶆敮鎸佸嚱鏁� " + call.name() + "锛屽彲鐢ㄥ嚱鏁帮細" + String.join("銆�", FUNCTIONS.keySet()));
+ }
+ List<Object> args = new ArrayList<>(call.args().size());
+ for (RuleNode arg : call.args()) {
+ args.add(evaluateNode(arg, context));
+ }
+ return handler.apply(args);
+ }
+
+ private static Object evaluateUnary(RuleNode.Unary unary, Object context) {
+ Object value = evaluateNode(unary.operand(), context);
+ return "!".equals(unary.operator()) ? !truthy(value) : -Paths.toNumber(value);
+ }
+
+ private static Object evaluateBetween(RuleNode.Between between, Object context) {
+ Object value = evaluateNode(between.value(), context);
+ boolean hit = compare(value, evaluateNode(between.lower(), context)) >= 0
+ && compare(value, evaluateNode(between.upper(), context)) <= 0;
+ return between.negated() != hit;
+ }
+
+ private static Object evaluateIn(RuleNode.In inNode, Object context) {
+ Object value = evaluateNode(inNode.value(), context);
+ boolean hit = false;
+ for (RuleNode item : inNode.items()) {
+ if (compare(value, evaluateNode(item, context)) == 0) {
+ hit = true;
+ break;
+ }
+ }
+ return inNode.negated() != hit;
+ }
+
+ private static Object evaluateBinary(RuleNode.Binary binary, Object context) {
+ if ("AND".equals(binary.operator())) {
+ return truthy(evaluateNode(binary.left(), context)) && truthy(evaluateNode(binary.right(), context));
+ }
+ if ("OR".equals(binary.operator())) {
+ return truthy(evaluateNode(binary.left(), context)) || truthy(evaluateNode(binary.right(), context));
+ }
+
+ Object left = evaluateNode(binary.left(), context);
+ Object right = evaluateNode(binary.right(), context);
+
+ return switch (binary.operator()) {
+ case "=" -> compare(left, right) == 0;
+ case "!=" -> compare(left, right) != 0;
+ case ">" -> compare(left, right) > 0;
+ case ">=" -> compare(left, right) >= 0;
+ case "<" -> compare(left, right) < 0;
+ case "<=" -> compare(left, right) <= 0;
+ case "+" -> add(left, right);
+ case "-" -> Paths.toNumber(left) - Paths.toNumber(right);
+ case "*" -> Paths.toNumber(left) * Paths.toNumber(right);
+ case "/" -> divide(left, right);
+ default -> throw new RuleRuntimeException("涓嶆敮鎸佺殑杩愮畻绗� " + binary.operator());
+ };
+ }
+
+ /** 涓や晶閮芥槸鏁板�兼墠鍋氬姞娉曪紝鍚﹀垯鎸夋枃鏈嫾鎺ワ紙缂栧彿绫诲瓧娈靛父鐢級 */
+ private static Object add(Object left, Object right) {
+ double leftNumber = Paths.toNumber(left);
+ double rightNumber = Paths.toNumber(right);
+ if (Double.isFinite(leftNumber) && Double.isFinite(rightNumber)) {
+ return leftNumber + rightNumber;
+ }
+ return asText(left) + asText(right);
+ }
+
+ private static Object divide(Object left, Object right) {
+ double divisor = Paths.toNumber(right);
+ if (divisor == 0) {
+ throw new RuleRuntimeException("瑙勫垯閲屽嚭鐜颁簡闄や互 0");
+ }
+ return Paths.toNumber(left) / divisor;
+ }
+
+ /* ------------------------------ 闈欐�佸垎鏋� ------------------------------ */
+
+ /** 琛ㄨ揪寮忛噷璋冪敤鐨勫嚱鏁板悕锛堝惈宓屽锛夛紝鐢ㄤ簬淇濆瓨鍓嶆牎楠岀櫧鍚嶅崟 */
+ public static List<String> listFunctionNames(RuleNode node) {
+ List<String> names = new ArrayList<>();
+ collectFunctionNames(node, names);
+ return names;
+ }
+
+ private static void collectFunctionNames(RuleNode node, List<String> names) {
+ switch (node) {
+ case RuleNode.Call call -> {
+ names.add(call.name());
+ call.args().forEach(arg -> collectFunctionNames(arg, names));
+ }
+ case RuleNode.Unary unary -> collectFunctionNames(unary.operand(), names);
+ case RuleNode.Binary binary -> {
+ collectFunctionNames(binary.left(), names);
+ collectFunctionNames(binary.right(), names);
+ }
+ case RuleNode.Between between -> {
+ collectFunctionNames(between.value(), names);
+ collectFunctionNames(between.lower(), names);
+ collectFunctionNames(between.upper(), names);
+ }
+ case RuleNode.In inNode -> {
+ collectFunctionNames(inNode.value(), names);
+ inNode.items().forEach(item -> collectFunctionNames(item, names));
+ }
+ default -> {
+ }
+ }
+ }
+
+ /** 鏈煡鍑芥暟鍚嶈繑鍥� null锛屼緵璋冪敤鏂圭粰鍑哄彲璇绘姤閿� */
+ public static String findUnknownFunction(RuleNode node) {
+ for (String name : listFunctionNames(node)) {
+ if (!FUNCTIONS.containsKey(name)) {
+ return name;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 瑙f瀽鍚庣殑璺緞渚濊禆锛屾覆鏌撳墠鍙嵁姝ゆ鏌ユ暟鎹槸鍚﹂綈澶囥��
+ * <p>
+ * 缁熻鍑芥暟浣滅敤鍦ㄦ暟缁勮矾寰勪笂锛岃繖閲屽幓鎺夋湯绔瓧娈靛彧淇濈暀鏁扮粍鏈韩銆�
+ */
+ public static List<String> listPaths(RuleNode node) {
+ Set<String> paths = new LinkedHashSet<>();
+ collectPaths(node, paths);
+ Set<String> normalized = new LinkedHashSet<>();
+ for (String path : paths) {
+ normalized.add(String.join(".", Paths.parsePath(path)));
+ }
+ return List.copyOf(normalized);
+ }
+
+ private static void collectPaths(RuleNode node, Set<String> paths) {
+ switch (node) {
+ case RuleNode.Path path -> {
+ paths.add(path.path());
+ }
+ case RuleNode.Call call -> call.args().forEach(arg -> collectPaths(arg, paths));
+ case RuleNode.Unary unary -> collectPaths(unary.operand(), paths);
+ case RuleNode.Binary binary -> {
+ collectPaths(binary.left(), paths);
+ collectPaths(binary.right(), paths);
+ }
+ case RuleNode.Between between -> {
+ collectPaths(between.value(), paths);
+ collectPaths(between.lower(), paths);
+ collectPaths(between.upper(), paths);
+ }
+ case RuleNode.In inNode -> {
+ collectPaths(inNode.value(), paths);
+ inNode.items().forEach(item -> collectPaths(item, paths));
+ }
+ default -> {
+ }
+ }
+ }
+
+ /** 鐧藉悕鍗曞嚱鏁� */
+ @FunctionalInterface
+ public interface RuleFunction {
+
+ Object apply(List<Object> args);
+
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleNode.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleNode.java
new file mode 100644
index 0000000..229a226
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleNode.java
@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.module.qcreport.engine.rule;
+
+import java.util.List;
+
+/**
+ * 瑙勫垯璇硶鏍戣妭鐐广��
+ * <p>
+ * 涓庡墠绔� {@code engine/rule-engine.ts} 鐨� RuleNode 鑱斿悎绫诲瀷涓�涓�瀵瑰簲锛�
+ * 閫掑綊涓嬮檷瑙f瀽鎴愯繖妫垫爲鍚庤嚜宸辨眰鍊硷紝鍏ㄧ▼涓嶇 eval / 鑴氭湰寮曟搸鈥斺��
+ * 瑙勫垯鏂囨湰鏉ヨ嚜鐢ㄦ埛锛屼竴鏃﹁兘琚綋浣滀唬鐮佹墽琛屽氨鏄敞鍏ュ彛瀛愩��
+ */
+public sealed interface RuleNode {
+
+ /** 瀛楅潰閲忥細鏁板瓧锛圖ouble锛�/ 瀛楃涓� / 甯冨皵 / null */
+ record Literal(Object value) implements RuleNode {
+ }
+
+ /** 涓婁笅鏂囪矾寰勫彇鍊硷紝濡� item.actualValue */
+ record Path(String path) implements RuleNode {
+ }
+
+ /** 鐧藉悕鍗曞嚱鏁拌皟鐢� */
+ record Call(String name, List<RuleNode> args) implements RuleNode {
+ }
+
+ /** 涓�鍏冭繍绠楋細- 鎴� ! */
+ record Unary(String operator, RuleNode operand) implements RuleNode {
+ }
+
+ /** 浜屽厓杩愮畻锛欰ND / OR / = / != / > / >= / < / <= / + / - / * / / */
+ record Binary(String operator, RuleNode left, RuleNode right) implements RuleNode {
+ }
+
+ /** value BETWEEN lower AND upper */
+ record Between(RuleNode value, RuleNode lower, RuleNode upper, boolean negated) implements RuleNode {
+ }
+
+ /** value IN (items) / value NOT IN (items) */
+ record In(RuleNode value, List<RuleNode> items, boolean negated) implements RuleNode {
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleParser.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleParser.java
new file mode 100644
index 0000000..f5b97b5
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleParser.java
@@ -0,0 +1,372 @@
+package cn.iocoder.yudao.module.qcreport.engine.rule;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+/**
+ * 瑙勫垯鏂囨湰 鈫� 璇硶鏍戙��
+ * <p>
+ * 涓庡墠绔� {@code engine/rule-engine.ts} 鐨� tokenize + Parser 涓�涓�瀵瑰簲锛�
+ * 鏀寔鐨勮娉曡 docs/鏅鸿兘璐ㄦ鎶ュ憡骞冲彴-鏂规璁捐.md 搂13銆�
+ */
+public final class RuleParser {
+
+ private static final Set<String> KEYWORDS = Set.of(
+ "AND", "BETWEEN", "FALSE", "IN", "NOT", "NOT_IN", "NULL", "OR", "TRUE");
+
+ private static final Set<String> TWO_CHAR_OPERATORS = Set.of("<=", ">=", "!=", "<>", "==");
+
+ private static final String SINGLE_CHAR_OPERATORS = "><=+-*/!";
+
+ private static final Pattern NUMBER_TEXT = Pattern.compile("^\\d+(?:\\.\\d+)?$");
+
+ private static final Pattern DIGIT_TEXT = Pattern.compile("^\\d+$");
+
+ private RuleParser() {
+ }
+
+ /** 瑙f瀽瑙勫垯鏂囨湰锛岃娉曢敊璇姏 {@link RuleSyntaxException} */
+ public static RuleNode parse(String expression) {
+ String trimmed = expression == null ? "" : expression.trim();
+ if (trimmed.isEmpty()) {
+ throw new RuleSyntaxException("瑙勫垯琛ㄨ揪寮忎负绌�", 0);
+ }
+ return new Parser(tokenize(trimmed)).parse();
+ }
+
+ /* ------------------------------ 璇嶆硶鍒嗘瀽 ------------------------------ */
+
+ private static List<RuleToken> tokenize(String source) {
+ List<RuleToken> tokens = new ArrayList<>();
+ int length = source.length();
+ int index = 0;
+
+ while (index < length) {
+ char ch = source.charAt(index);
+
+ if (Character.isWhitespace(ch)) {
+ index++;
+ continue;
+ }
+
+ if (ch == '\'' || ch == '"') {
+ index = readString(source, index, ch, tokens);
+ continue;
+ }
+
+ if (ch >= '0' && ch <= '9') {
+ int cursor = index;
+ while (cursor < length && isDigitOrDot(source.charAt(cursor))) {
+ cursor++;
+ }
+ String text = source.substring(index, cursor);
+ if (!NUMBER_TEXT.matcher(text).matches()) {
+ throw new RuleSyntaxException("鏁板瓧鏍煎紡涓嶆纭細" + text, index);
+ }
+ tokens.add(new RuleToken(TokenType.NUMBER, text, index));
+ index = cursor;
+ continue;
+ }
+
+ if (isIdentStart(ch)) {
+ index = readWord(source, index, tokens);
+ continue;
+ }
+
+ if (index + 2 <= length && TWO_CHAR_OPERATORS.contains(source.substring(index, index + 2))) {
+ tokens.add(new RuleToken(TokenType.OPERATOR, source.substring(index, index + 2), index));
+ index += 2;
+ continue;
+ }
+
+ if (ch == '(' || ch == ')') {
+ tokens.add(new RuleToken(ch == '(' ? TokenType.LPAREN : TokenType.RPAREN, String.valueOf(ch), index));
+ index++;
+ continue;
+ }
+ if (ch == ',') {
+ tokens.add(new RuleToken(TokenType.COMMA, String.valueOf(ch), index));
+ index++;
+ continue;
+ }
+ if (SINGLE_CHAR_OPERATORS.indexOf(ch) >= 0) {
+ tokens.add(new RuleToken(TokenType.OPERATOR, String.valueOf(ch), index));
+ index++;
+ continue;
+ }
+
+ throw new RuleSyntaxException("鏃犳硶璇嗗埆鐨勫瓧绗︺��" + ch + "銆�", index);
+ }
+
+ tokens.add(new RuleToken(TokenType.EOF, "", length));
+ return tokens;
+ }
+
+ /** 璇讳竴涓瓧绗︿覆瀛楅潰閲忥紝杩斿洖缁撴潫鍚庣殑涓嬫爣 */
+ private static int readString(String source, int start, char quote, List<RuleToken> tokens) {
+ int length = source.length();
+ StringBuilder value = new StringBuilder();
+ int cursor = start + 1;
+ while (cursor < length && source.charAt(cursor) != quote) {
+ if (source.charAt(cursor) == '\\' && cursor + 1 < length) {
+ value.append(source.charAt(cursor + 1));
+ cursor += 2;
+ continue;
+ }
+ value.append(source.charAt(cursor));
+ cursor++;
+ }
+ if (cursor >= length) {
+ throw new RuleSyntaxException("瀛楃涓茬己灏戠粨灏惧紩鍙�", start);
+ }
+ tokens.add(new RuleToken(TokenType.STRING, value.toString(), start));
+ return cursor + 1;
+ }
+
+ /**
+ * 璇讳竴涓爣璇嗙/璺緞锛岃繑鍥炵粨鏉熷悗鐨勪笅鏍囥��
+ * <p>
+ * 璺緞灏惧反锛�.灞炴�� 涓� [涓嬫爣]锛夊湪璇嶆硶闃舵灏卞苟杩涘悓涓�涓瘝锛屽彇鍊兼椂鏁存潯璺緞涓�娆¤В鏋愩��
+ */
+ private static int readWord(String source, int start, List<RuleToken> tokens) {
+ int length = source.length();
+ int cursor = start;
+ while (cursor < length && isIdentPart(source.charAt(cursor))) {
+ cursor++;
+ }
+ StringBuilder value = new StringBuilder(source.substring(start, cursor));
+ while (cursor < length) {
+ char next = source.charAt(cursor);
+ if (next == '.' && cursor + 1 < length && isIdentStart(source.charAt(cursor + 1))) {
+ int end = cursor + 1;
+ while (end < length && isIdentPart(source.charAt(end))) {
+ end++;
+ }
+ value.append(source, cursor, end);
+ cursor = end;
+ continue;
+ }
+ if (next == '[') {
+ int close = source.indexOf(']', cursor);
+ if (close == -1) {
+ throw new RuleSyntaxException("鏁扮粍涓嬫爣缂哄皯 ]", cursor);
+ }
+ String inner = source.substring(cursor + 1, close).trim();
+ if (!DIGIT_TEXT.matcher(inner).matches()) {
+ throw new RuleSyntaxException("鏁扮粍涓嬫爣鍙兘鏄暟瀛楋細" + inner, cursor);
+ }
+ value.append('[').append(inner).append(']');
+ cursor = close + 1;
+ continue;
+ }
+ break;
+ }
+ tokens.add(new RuleToken(TokenType.WORD, value.toString(), start));
+ return cursor;
+ }
+
+ private static boolean isIdentStart(char ch) {
+ return ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z' || ch == '_' || ch == '$';
+ }
+
+ private static boolean isIdentPart(char ch) {
+ return isIdentStart(ch) || ch >= '0' && ch <= '9';
+ }
+
+ private static boolean isDigitOrDot(char ch) {
+ return ch >= '0' && ch <= '9' || ch == '.';
+ }
+
+ /* ------------------------------ 璇硶鍒嗘瀽 ------------------------------ */
+
+ private static final class Parser {
+
+ private final List<RuleToken> tokens;
+ private int cursor;
+
+ private Parser(List<RuleToken> tokens) {
+ this.tokens = tokens;
+ }
+
+ private RuleNode parse() {
+ RuleNode node = parseOr();
+ RuleToken token = peek();
+ if (token.type() != TokenType.EOF) {
+ throw new RuleSyntaxException("澶氫綑鐨勫唴瀹癸細" + token.value(), token.position());
+ }
+ return node;
+ }
+
+ private RuleNode parseOr() {
+ RuleNode left = parseAnd();
+ while (matchWord("OR")) {
+ left = new RuleNode.Binary("OR", left, parseAnd());
+ }
+ return left;
+ }
+
+ private RuleNode parseAnd() {
+ RuleNode left = parseComparison();
+ while (matchWord("AND")) {
+ left = new RuleNode.Binary("AND", left, parseComparison());
+ }
+ return left;
+ }
+
+ private RuleNode parseComparison() {
+ RuleNode left = parseAdditive();
+
+ if (matchWord("BETWEEN")) {
+ RuleNode lower = parseAdditive();
+ if (!matchWord("AND")) {
+ throw new RuleSyntaxException("BETWEEN 缂哄皯 AND 涓庝笂鐣�", peek().position());
+ }
+ RuleNode upper = parseAdditive();
+ return new RuleNode.Between(left, lower, upper, false);
+ }
+
+ if (matchWord("NOT")) {
+ if (matchWord("IN") || matchWord("NOT_IN")) {
+ return new RuleNode.In(left, parseList(), true);
+ }
+ throw new RuleSyntaxException("NOT 鍙兘鐢ㄤ簬 NOT IN", peek().position());
+ }
+
+ if (matchWord("IN")) {
+ return new RuleNode.In(left, parseList(), false);
+ }
+
+ RuleToken token = peek();
+ if (token.type() == TokenType.OPERATOR
+ && "< <= = == != <> > >=".contains(token.value())) {
+ cursor++;
+ return new RuleNode.Binary(normalizeOperator(token.value()), left, parseAdditive());
+ }
+
+ return left;
+ }
+
+ /** == 缁熶竴鎴� =銆�<> 缁熶竴鎴� !=锛屾眰鍊奸樁娈靛彧璁や竴绉嶅啓娉� */
+ private static String normalizeOperator(String operator) {
+ if ("==".equals(operator)) {
+ return "=";
+ }
+ return "<>".equals(operator) ? "!=" : operator;
+ }
+
+ private List<RuleNode> parseList() {
+ expect(TokenType.LPAREN);
+ List<RuleNode> items = new ArrayList<>();
+ if (peek().type() != TokenType.RPAREN) {
+ items.add(parseOr());
+ while (peek().type() == TokenType.COMMA) {
+ cursor++;
+ items.add(parseOr());
+ }
+ }
+ expect(TokenType.RPAREN);
+ return items;
+ }
+
+ private RuleNode parseAdditive() {
+ RuleNode left = parseMultiplicative();
+ for (; ; ) {
+ RuleToken token = peek();
+ if (token.type() != TokenType.OPERATOR || !"+".equals(token.value()) && !"-".equals(token.value())) {
+ return left;
+ }
+ cursor++;
+ left = new RuleNode.Binary(token.value(), left, parseMultiplicative());
+ }
+ }
+
+ private RuleNode parseMultiplicative() {
+ RuleNode left = parseUnary();
+ for (; ; ) {
+ RuleToken token = peek();
+ if (token.type() != TokenType.OPERATOR || !"*".equals(token.value()) && !"/".equals(token.value())) {
+ return left;
+ }
+ cursor++;
+ left = new RuleNode.Binary(token.value(), left, parseUnary());
+ }
+ }
+
+ private RuleNode parseUnary() {
+ RuleToken token = peek();
+ if (token.type() == TokenType.OPERATOR && ("-".equals(token.value()) || "!".equals(token.value()))) {
+ cursor++;
+ return new RuleNode.Unary(token.value(), parseUnary());
+ }
+ return parsePrimary();
+ }
+
+ private RuleNode parsePrimary() {
+ RuleToken token = peek();
+
+ if (token.type() == TokenType.NUMBER) {
+ cursor++;
+ return new RuleNode.Literal(Double.valueOf(token.value()));
+ }
+ if (token.type() == TokenType.STRING) {
+ cursor++;
+ return new RuleNode.Literal(token.value());
+ }
+ if (token.type() == TokenType.LPAREN) {
+ cursor++;
+ RuleNode node = parseOr();
+ expect(TokenType.RPAREN);
+ return node;
+ }
+ if (token.type() == TokenType.WORD) {
+ cursor++;
+ String upper = token.value().toUpperCase();
+ if ("TRUE".equals(upper)) {
+ return new RuleNode.Literal(Boolean.TRUE);
+ }
+ if ("FALSE".equals(upper)) {
+ return new RuleNode.Literal(Boolean.FALSE);
+ }
+ if ("NULL".equals(upper)) {
+ return new RuleNode.Literal(null);
+ }
+ if (peek().type() == TokenType.LPAREN) {
+ return new RuleNode.Call(upper, parseList());
+ }
+ if (KEYWORDS.contains(upper)) {
+ throw new RuleSyntaxException("鍏抽敭瀛� " + upper + " 鐨勪綅缃笉姝g‘", token.position());
+ }
+ return new RuleNode.Path(token.value());
+ }
+
+ throw new RuleSyntaxException(
+ token.type() == TokenType.EOF ? "琛ㄨ揪寮忎笉瀹屾暣" : "鏃犳硶瑙f瀽鐨勫唴瀹癸細" + token.value(),
+ token.position());
+ }
+
+ private RuleToken peek() {
+ return tokens.get(cursor);
+ }
+
+ private boolean matchWord(String word) {
+ RuleToken token = peek();
+ if (token.type() == TokenType.WORD && token.value().toUpperCase().equals(word)) {
+ cursor++;
+ return true;
+ }
+ return false;
+ }
+
+ private void expect(TokenType type) {
+ RuleToken token = peek();
+ if (token.type() != type) {
+ throw new RuleSyntaxException(
+ "搴旇鏄� " + type.label() + "锛屽疄闄呮槸銆�" + token.value() + "銆�", token.position());
+ }
+ cursor++;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleRuntimeException.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleRuntimeException.java
new file mode 100644
index 0000000..ecca408
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleRuntimeException.java
@@ -0,0 +1,12 @@
+package cn.iocoder.yudao.module.qcreport.engine.rule;
+
+/**
+ * 瑙勫垯杩愯鏈熼敊璇細鍑芥暟涓嶅湪鐧藉悕鍗曘�佸弬鏁扮被鍨嬩笉瀵广�侀櫎浠� 0 绛夈��
+ */
+public class RuleRuntimeException extends RuntimeException {
+
+ public RuleRuntimeException(String message) {
+ super(message);
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleScope.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleScope.java
new file mode 100644
index 0000000..7095508
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleScope.java
@@ -0,0 +1,28 @@
+package cn.iocoder.yudao.module.qcreport.engine.rule;
+
+/**
+ * 瑙勫垯浣滅敤鍩熴��
+ */
+public enum RuleScope {
+
+ /** 閫愰」鍒ゅ畾锛氬姣忎竴琛屾楠岄」鍒嗗埆姹傚�� */
+ ITEM("item"),
+ /** 鎶ュ憡绾ф眹鎬诲垽瀹� */
+ REPORT("report");
+
+ private final String label;
+
+ RuleScope(String label) {
+ this.label = label;
+ }
+
+ public String label() {
+ return label;
+ }
+
+ /** 钀藉簱/鍓嶇鍙栧�� 鈫� 鏋氫妇锛岃瘑鍒笉鍑烘寜閫愰」澶勭悊 */
+ public static RuleScope of(String value) {
+ return REPORT.label.equalsIgnoreCase(value == null ? "" : value.trim()) ? REPORT : ITEM;
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleSyntaxException.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleSyntaxException.java
new file mode 100644
index 0000000..ba338ab
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleSyntaxException.java
@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.qcreport.engine.rule;
+
+/**
+ * 瑙勫垯鏂囨湰瀛樺湪璇硶閿欒銆�
+ */
+public class RuleSyntaxException extends RuntimeException {
+
+ /** 鍑洪敊浣嶇疆鍦ㄨ鍒欐枃鏈腑鐨勪笅鏍囷紙浠� 0 寮�濮嬶級 */
+ private final transient int position;
+
+ public RuleSyntaxException(String message, int position) {
+ super(message);
+ this.position = position;
+ }
+
+ public int position() {
+ return position;
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleToken.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleToken.java
new file mode 100644
index 0000000..409fe14
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/RuleToken.java
@@ -0,0 +1,11 @@
+package cn.iocoder.yudao.module.qcreport.engine.rule;
+
+/**
+ * 璇嶆硶鍗曞厓銆�
+ *
+ * @param type 绫诲瀷
+ * @param value 鍘熷鏂囨湰锛堝瓧绗︿覆宸插幓鎺夊紩鍙峰苟瑙h浆涔夛級
+ * @param position 鍦ㄨ鍒欐枃鏈腑鐨勮捣濮嬩笅鏍囷紝鍑洪敊鏃剁敤浜庡畾浣�
+ */
+public record RuleToken(TokenType type, String value, int position) {
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/TokenType.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/TokenType.java
new file mode 100644
index 0000000..71e2ceb
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/engine/rule/TokenType.java
@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.qcreport.engine.rule;
+
+/**
+ * 璇嶆硶鍗曞厓绫诲瀷銆�
+ * <p>
+ * label 淇濈暀鍓嶇 {@code engine/rule-engine.ts} 鐨勫皬鍐欏啓娉曪紝
+ * 璇硶閿欒鎻愮ず瑕佸湪涓ょ閫愬瓧涓�鑷达紝鐢ㄦ埛鎵嶄笉浼氬鍚屼竴浠借鍒欑湅鍒颁袱绉嶈娉曘��
+ */
+public enum TokenType {
+
+ COMMA("comma"),
+ EOF("eof"),
+ LPAREN("lparen"),
+ NUMBER("number"),
+ OPERATOR("operator"),
+ RPAREN("rparen"),
+ STRING("string"),
+ WORD("word");
+
+ private final String label;
+
+ TokenType(String label) {
+ this.label = label;
+ }
+
+ public String label() {
+ return label;
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/enums/ErrorCodeConstants.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/enums/ErrorCodeConstants.java
new file mode 100644
index 0000000..0996313
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/enums/ErrorCodeConstants.java
@@ -0,0 +1,117 @@
+package cn.iocoder.yudao.module.qcreport.enums;
+
+import cn.iocoder.yudao.framework.common.exception.ErrorCode;
+
+/**
+ * qcreport 鏅鸿兘璐ㄦ鎶ュ憡璁捐骞冲彴 閿欒鐮佹灇涓剧被
+ * <p>
+ * qcreport 绯荤粺锛屼娇鐢� 1-070-000-000 娈�
+ */
+public interface ErrorCodeConstants {
+
+ // ========== 鎶ュ憡妯℃澘锛�1-070-100-000锛� ==========
+ ErrorCode TEMPLATE_NOT_EXISTS = new ErrorCode(1_070_100_000, "鎶ュ憡妯℃澘涓嶅瓨鍦�");
+ ErrorCode TEMPLATE_CODE_DUPLICATE = new ErrorCode(1_070_100_001, "鎶ュ憡妯℃澘缂栫爜宸插瓨鍦�");
+ ErrorCode TEMPLATE_STATUS_DISABLED = new ErrorCode(1_070_100_002, "鎶ュ憡妯℃澘宸插仠鐢紝鏃犳硶鎵ц璇ユ搷浣�");
+
+ // ========== 妯℃澘鐗堟湰锛�1-070-101-000锛� ==========
+ ErrorCode TEMPLATE_VERSION_NOT_EXISTS = new ErrorCode(1_070_101_000, "妯℃澘鐗堟湰涓嶅瓨鍦�");
+ ErrorCode TEMPLATE_VERSION_DUPLICATE = new ErrorCode(1_070_101_001, "璇ョ増鏈彿宸插瓨鍦紝璇蜂娇鐢ㄦ柊鐨勭増鏈彿");
+ ErrorCode TEMPLATE_VERSION_PUBLISHED_CANNOT_MODIFY = new ErrorCode(1_070_101_002, "妯℃澘鐗堟湰宸插彂甯冿紝涓嶅厑璁镐慨鏀癸紝璇峰垱寤烘柊鐗堟湰");
+ ErrorCode TEMPLATE_VERSION_NOT_PUBLISHED = new ErrorCode(1_070_101_003, "妯℃澘鐗堟湰鏈彂甯冿紝鏃犳硶鐢熸垚鎶ュ憡");
+ ErrorCode TEMPLATE_VERSION_SCHEMA_INVALID = new ErrorCode(1_070_101_004, "妯℃澘 Schema 鏍煎紡涓嶆纭紝璇锋鏌ヨ璁″櫒淇濆瓨鐨勬ā鏉垮唴瀹�");
+ ErrorCode TEMPLATE_VERSION_SCHEMA_EMPTY = new ErrorCode(1_070_101_005, "妯℃澘 Schema 涓虹┖锛岃鍏堝湪璁捐鍣ㄤ腑璁捐妯℃澘鍐呭骞朵繚瀛橈紝鍐嶅彂甯冪増鏈�");
+ ErrorCode TEMPLATE_VERSION_RULE_INVALID = new ErrorCode(1_070_101_006, "妯℃澘閲岀殑鍒ゅ畾瑙勫垯涓嶅悎娉曪紝璇蜂慨鏀瑰悗閲嶈瘯");
+ ErrorCode TEMPLATE_NO_PUBLISHED_VERSION = new ErrorCode(1_070_101_007, "璇ユā鏉胯繕娌℃湁宸插彂甯冪殑鐗堟湰锛屾棤娉曠敓鎴愭姤鍛婏紝璇峰厛鍦ㄨ璁″櫒涓彂甯冧竴涓増鏈�");
+ ErrorCode TEMPLATE_VERSION_CANVAS_EMPTY = new ErrorCode(1_070_101_008, "璇ユā鏉跨増鏈病鏈夌敾甯冨唴瀹癸紝鏃犳硶鐢熸垚鎶ュ憡锛岃鍏堝湪璁捐鍣ㄤ腑璁捐骞朵繚瀛樻ā鏉垮唴瀹�");
+ ErrorCode TEMPLATE_VERSION_CANVAS_UNSAFE = new ErrorCode(1_070_101_009,
+ "妯℃澘鐢诲竷閲屾湁涓嶅厑璁稿嚭鐜扮殑鍐呭锛屽凡鎷掔粷淇濆瓨锛歿}銆傝鍦ㄨ璁″櫒涓垹鎺夎繖浜涘唴瀹瑰悗閲嶆柊淇濆瓨");
+ ErrorCode TEMPLATE_VERSION_CURRENT_CANNOT_DISABLE = new ErrorCode(1_070_101_010,
+ "鐗堟湰銆寋}銆嶆槸妯℃澘銆寋}銆嶅綋鍓嶆鍦ㄤ娇鐢ㄧ殑鐗堟湰锛屼笉鑳藉仠鐢ㄣ��"
+ + "璇峰厛鍒拌妯℃澘鐨勭増鏈垪琛ㄩ噷瀵瑰彟涓�涓凡鍙戝竷鐗堟湰鎵ц銆屽洖婊氥�嶏紝鎶婂綋鍓嶇増鏈垏璧帮紝鍐嶅仠鐢ㄦ湰鐗堟湰锛�"
+ + "鑻ヨ璁╂暣涓ā鏉垮仠姝娇鐢紝璇锋敼涓哄仠鐢ㄦā鏉挎湰韬�");
+
+ // ========== 鎶ュ憡瀹炰緥锛�1-070-102-000锛� ==========
+ ErrorCode REPORT_INSTANCE_NOT_EXISTS = new ErrorCode(1_070_102_000, "鎶ュ憡瀹炰緥涓嶅瓨鍦�");
+ ErrorCode REPORT_INSTANCE_NO_DUPLICATE = new ErrorCode(1_070_102_001, "鎶ュ憡缂栧彿宸插瓨鍦�");
+ ErrorCode REPORT_INSTANCE_DATA_SNAPSHOT_MISSING = new ErrorCode(1_070_102_002, "鎶ュ憡瀹炰緥缂哄皯鏁版嵁蹇収锛屾棤娉曢噸鏂版覆鏌�");
+ ErrorCode REPORT_INSTANCE_HTML_MISSING = new ErrorCode(1_070_102_003, "鎶ュ憡瀹炰緥娌℃湁娓叉煋浜х墿 HTML锛屾棤娉曠敓鎴� PDF锛岃鍏堝璇ユ姤鍛婃墽琛屻�岄噸鏂扮敓鎴愩��");
+
+ // ========== 娓叉煋涓庤鍒欙紙1-070-103-000锛� ==========
+ ErrorCode RENDER_BUSINESS_DATA_MISSING = new ErrorCode(1_070_103_000, "涓氬姟鏁版嵁涓虹┖锛屾棤娉曟覆鏌撴姤鍛�");
+ ErrorCode RENDER_DATA_FIELD_NOT_EXISTS = new ErrorCode(1_070_103_001, "鏁版嵁缁戝畾瀛楁涓嶅瓨鍦�");
+ ErrorCode RENDER_RULE_PARSE_FAILED = new ErrorCode(1_070_103_002, "鍒ゅ畾瑙勫垯瑙f瀽澶辫触");
+ ErrorCode RENDER_HTML_FAILED = new ErrorCode(1_070_103_003, "鎶ュ憡 HTML 娓叉煋澶辫触");
+ ErrorCode RENDER_PDF_BROWSER_LAUNCH_FAILED = new ErrorCode(1_070_103_004, "PDF 娓叉煋娴忚鍣ㄥ惎鍔ㄥけ璐ワ紝璇锋鏌� Chromium 鏄惁宸插畨瑁�");
+ ErrorCode RENDER_PDF_FAILED = new ErrorCode(1_070_103_005, "PDF 鐢熸垚澶辫触");
+ ErrorCode RENDER_PDF_ARCHIVE_FAILED = new ErrorCode(1_070_103_006, "PDF 宸茬敓鎴愶紝浣嗗綊妗e埌闄勪欢搴撳け璐�");
+ ErrorCode RENDER_PDF_BUSY = new ErrorCode(1_070_103_007, "褰撳墠 PDF 娓叉煋浠诲姟宸茶揪涓婇檺锛岃绋嶅悗閲嶈瘯");
+ ErrorCode RENDER_PDF_DISABLED = new ErrorCode(1_070_103_008, "PDF 鍑轰欢鍔熻兘鏈惎鐢紝璇疯仈绯荤鐞嗗憳");
+
+ // ========== AI 瀵煎叆妯℃澘鑽夌锛�1-070-104-000锛� ==========
+ ErrorCode AI_IMPORT_DISABLED = new ErrorCode(1_070_104_000,
+ "AI 瀵煎叆鍔熻兘鏈惎鐢紙yudao.qcreport.ai-import.enabled 褰撳墠涓� false锛夛紝璇疯仈绯荤鐞嗗憳寮�鍚悗鍐嶈瘯");
+ ErrorCode AI_IMPORT_BLOB_NOT_FOUND = new ErrorCode(1_070_104_001,
+ "涓婁紶鐨勬枃浠讹紙blobId={}锛変笉瀛樺湪鎴栧凡琚竻鐞嗭紝璇烽噸鏂颁笂浼犲悗鍐嶈瘯");
+ ErrorCode AI_IMPORT_FILE_UNSUPPORTED = new ErrorCode(1_070_104_002,
+ "涓嶆敮鎸佺殑鏂囦欢銆寋}銆嶏紙鎵╁睍鍚嶏細{}锛夈�備粎鏀寔 PDF銆乄ord(.docx)銆丒xcel(.xlsx)銆�"
+ + "鍥剧墖(png/jpg/jpeg/bmp/gif/webp) 涓庢枃鏈�(txt/csv)锛岃杞崲鏍煎紡鍚庨噸鏂板鍏�");
+ ErrorCode AI_IMPORT_FILE_LEGACY_OFFICE = new ErrorCode(1_070_104_003,
+ "涓嶆敮鎸佺殑鏂囦欢銆寋}銆嶏紙鏃х増 Office 鏍煎紡.{}锛夈�傝鐢� Office 鎵撳紑鍚庛�屽彟瀛樹负銆�.docx 鎴� .xlsx 鍐嶉噸鏂板鍏�");
+ ErrorCode AI_IMPORT_FILE_TOO_LARGE = new ErrorCode(1_070_104_004,
+ "鏂囦欢銆寋}銆嶅ぇ灏� {}MB锛岃秴杩囧崟鏂囦欢涓婇檺 {}MB锛岃鍘嬬缉鎴栨媶鍒嗗悗閲嶆柊瀵煎叆");
+ ErrorCode AI_IMPORT_FILE_EMPTY = new ErrorCode(1_070_104_005,
+ "鏂囦欢銆寋}銆嶆湭瑙f瀽鍑轰换浣曞彲鐢ㄥ唴瀹癸紙鍏� {} 椤碉級銆傝嫢鏄壂鎻忎欢锛岃纭鍒嗚鲸鐜囦笉浣庝簬 200 DPI銆�"
+ + "鏂囧瓧鏃犱弗閲嶅�炬枩鎴栭伄鎸★紱鎺ㄨ崘鏀圭敤鐢靛瓙鐗� PDF 鎴� Word/Excel");
+ ErrorCode AI_IMPORT_TOO_MANY_FILES = new ErrorCode(1_070_104_006,
+ "涓�娆℃渶澶氬鍏� {} 涓枃浠讹紝鏈鎻愪氦浜� {} 涓紝璇峰垎鎵瑰鍏�");
+ ErrorCode AI_IMPORT_TOO_MANY_PAGES = new ErrorCode(1_070_104_007,
+ "鏂囦欢銆寋}銆嶅叡 {} 椤碉紝瓒呰繃鍗曟璇嗗埆涓婇檺 {} 椤碉紝璇锋媶鍒嗗悗鍒嗘壒瀵煎叆");
+ ErrorCode AI_IMPORT_CATALOG_INVALID = new ErrorCode(1_070_104_008,
+ "缁勪欢娓呭崟鍙傛暟涓嶅悎娉曪紙{}锛夛紝璇峰埛鏂伴〉闈㈠悗閲嶈瘯");
+ ErrorCode AI_IMPORT_SCHEMA_VERSION_UNSUPPORTED = new ErrorCode(1_070_104_009,
+ "缁勪欢娓呭崟鐨� Schema 鐗堟湰涓恒�寋}銆嶏紝鏈嶅姟绔彧鎺ュ彈銆寋}銆嶏紝璇峰埛鏂伴〉闈㈠悗閲嶈瘯");
+ ErrorCode AI_IMPORT_AI_UNAVAILABLE = new ErrorCode(1_070_104_010,
+ "AI 璇嗗埆璋冪敤澶辫触锛堝凡鑰楁椂 {}ms锛夛細{}銆傝鍒般�孉I 澶фā鍨嬨�嶄腑纭瀵硅瘽妯″瀷宸插惎鐢ㄤ笖瀵嗛挜鏈夋晥锛屾垨绋嶅悗閲嶈瘯");
+ ErrorCode AI_IMPORT_AI_TIMEOUT = new ErrorCode(1_070_104_011,
+ "AI 璇嗗埆瓒呮椂锛堟湰娆″凡绛� {} 绉掞級銆傛枃浠堕〉鏁版垨鏁伴噺杈冨鏃惰�楁椂鏇撮暱锛�"
+ + "璇峰噺灏戞枃浠舵暟閲忥紝鎴栨敼鐢ㄧ數瀛愮増 PDF / Word / Excel");
+ ErrorCode AI_IMPORT_RESPONSE_UNPARSEABLE = new ErrorCode(1_070_104_012,
+ "AI 杩斿洖鐨勫唴瀹规棤娉曡В鏋愪负妯℃澘鑽夌锛堝凡鏀跺埌 {} 涓瓧绗︼級銆傝嫢鏂囦欢鍐呭寰堥暱锛岃鎷嗗垎鍚庡垎鎵瑰鍏ワ紱"
+ + "鑻ユ寔缁け璐ワ紝璇锋敼鐢ㄦ墜宸ヨ璁�");
+ ErrorCode AI_IMPORT_DRAFT_EMPTY = new ErrorCode(1_070_104_013,
+ "AI 鏈兘浠庢枃浠躲�寋}銆嶄腑璇嗗埆鍑轰换浣曞彲鐢ㄧ粍浠躲�傝纭璇ユ枃浠舵槸妫�楠屾姤鍛婏紱"
+ + "鑻ョ‘瀹炴槸锛岃鏀圭敤鎵嬪伐璁捐妯℃澘");
+ ErrorCode AI_IMPORT_TOO_MANY_PAGES_TOTAL = new ErrorCode(1_070_104_014,
+ "鏈鎻愪氦鐨勬枃浠跺悎璁� {} 椤碉紝瓒呰繃鍗曟璇嗗埆涓婇檺 {} 椤碉紙鍗曟枃浠朵笂闄� {} 椤碉級锛�"
+ + "璇峰噺灏戞枃浠舵暟閲忔垨鍒嗘壒瀵煎叆");
+ ErrorCode AI_IMPORT_OFFICE_CORRUPT = new ErrorCode(1_070_104_015,
+ "鏂囦欢銆寋}銆嶆棤娉曚綔涓� .{} 鎵撳紑锛屽唴瀹瑰凡鎹熷潖鎴栧彈瀵嗙爜淇濇姢銆�"
+ + "璇峰厛鐢� Office 鎵撳紑璇ユ枃浠讹紝纭鑳芥甯告樉绀哄悗銆屽彟瀛樹负銆�.docx / .xlsx 鍐嶉噸鏂板鍏ワ紱"
+ + "鑻ユ枃浠舵湁鎵撳紑瀵嗙爜锛岃鍏堣В闄ゅ瘑鐮佷繚鎶�");
+ ErrorCode AI_IMPORT_AI_BUDGET_EXCEEDED = new ErrorCode(1_070_104_016,
+ "鏈璇嗗埆宸茶揪鍒板崟娆″鍏ヨ�楁椂涓婇檺锛坽} 绉掞紝宸茬敤鏃� {} 绉掞級骞舵彁鍓嶅仠姝紝"
+ + "鍦ㄦ枃浠躲�寋}銆嶄腑鏈瘑鍒嚭浠讳綍鍙敤缁勪欢銆傝鍑忓皯鏂囦欢鏁伴噺鎴栭〉鏁板悗鍒嗘壒瀵煎叆锛�"
+ + "鑻ュ崟涓枃浠朵篃涓嶅ぇ锛岃鍒般�孉I 澶фā鍨嬨�嶄腑妫�鏌ュ璇濇ā鍨嬫槸鍚﹀搷搴旂紦鎱�");
+
+ // ========== 鐢辫川妫�鍗曠敓鎴愭姤鍛婏紙1-070-105-000锛� ==========
+ ErrorCode QC_GENERATE_TYPE_INVALID = new ErrorCode(1_070_105_000,
+ "璐ㄦ绫诲瀷銆寋}銆嶄笉鍚堟硶锛屽彧鏀寔 IQC锛堟潵鏂欐楠岋級銆両PQC锛堣繃绋嬫楠岋級銆丱QC锛堝嚭璐ф楠岋級銆丷QC锛堥��璐ф楠岋級");
+ ErrorCode QC_GENERATE_ORDER_NOT_EXISTS = new ErrorCode(1_070_105_001,
+ "{}鐨勮川妫�鍗曪紙ID={}锛変笉瀛樺湪鎴栧凡琚垹闄わ紝璇峰埛鏂板垪琛ㄥ悗閲嶆柊閫夋嫨");
+ ErrorCode QC_GENERATE_ORDER_NOT_FINISHED = new ErrorCode(1_070_105_002,
+ "{}鐨勮川妫�鍗曘�寋}銆嶅綋鍓嶇姸鎬佷负銆寋}銆嶏紝灏氭湭瀹屾垚妫�楠岋紝涓嶈兘鐢熸垚鎶ュ憡銆�"
+ + "璇峰厛鎶婅鍗曟嵁鎻愪氦骞跺畬鎴愭楠屽垽瀹氬悗鍐嶇敓鎴�");
+ ErrorCode QC_GENERATE_ORDER_NOT_JUDGED = new ErrorCode(1_070_105_003,
+ "{}鐨勮川妫�鍗曘�寋}銆嶅皻鏈~鍐欐楠屽垽瀹氾紙鍒ゅ畾涓虹┖锛夛紝涓嶈兘鐢熸垚鎶ュ憡銆�"
+ + "璇峰厛鍦ㄨ鍗曟嵁涓婂~鍐欏垽瀹氱粨璁猴紙鍚堟牸 / 鐗归噰 / 涓嶅悎鏍奸��璐� / 涓嶅悎鏍兼姤搴燂級鍚庡啀鐢熸垚");
+ // 105_004 / 105_007 涓ゆ潯璺緞澶嶇敤鏃㈡湁鐨� TEMPLATE_NOT_EXISTS / TEMPLATE_STATUS_DISABLED /
+ // TEMPLATE_NO_PUBLISHED_VERSION锛氶偅鍑犳潯鏂囨鏈潵灏辨槸绮剧‘鐨勶紝鍐嶉�犱竴閬嶅彧浼氬涓ゆ潯浼氭紓绉荤殑鍓湰
+ ErrorCode QC_GENERATE_TEMPLATE_TYPE_MISMATCH = new ErrorCode(1_070_105_005,
+ "鎶ュ憡妯℃澘鐨勬姤鍛婄被鍨嬫槸銆寋}銆嶏紝涓庢湰娆¤川妫�鍗曠殑绫诲瀷銆寋}銆嶄笉涓�鑷达紝鏃犳硶鐢熸垚鎶ュ憡銆�"
+ + "璇烽噸鏂伴�夋嫨涓�寮爗}鐨勬姤鍛婃ā鏉�");
+ ErrorCode QC_GENERATE_NO_ITEM = new ErrorCode(1_070_105_006,
+ "{}鐨勮川妫�鍗曘�寋}銆嶆病鏈夊彲鐢ㄤ簬鍑烘姤鍛婄殑妫�楠岄」锛坽}锛夛紝鏃犳硶鐢熸垚鎶ュ憡銆�"
+ + "璇峰厛鍦ㄨ鍗曟嵁涓婂綍鍏ユ楠屾寚鏍囦笌瀹炴祴鍊煎悗鍐嶇敓鎴�");
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/enums/QcReportEnums.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/enums/QcReportEnums.java
new file mode 100644
index 0000000..5aae0d2
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/enums/QcReportEnums.java
@@ -0,0 +1,156 @@
+package cn.iocoder.yudao.module.qcreport.enums;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * 鏅鸿兘璐ㄦ鎶ュ憡璁捐骞冲彴 鏋氫妇闆嗗悎
+ */
+public interface QcReportEnums {
+
+ /**
+ * 妯℃澘鐘舵��
+ */
+ @Getter
+ @AllArgsConstructor
+ enum TemplateStatusEnum implements ArrayValuable<Integer> {
+
+ ENABLE(0, "鍚敤"),
+ DISABLE(1, "鍋滅敤");
+
+ private final Integer status;
+ private final String name;
+
+ public static final Integer[] ARRAYS = Arrays.stream(values())
+ .map(TemplateStatusEnum::getStatus).toArray(Integer[]::new);
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+ }
+
+ /**
+ * 妯℃澘鐗堟湰鐘舵��
+ */
+ @Getter
+ @AllArgsConstructor
+ enum VersionStatusEnum implements ArrayValuable<Integer> {
+
+ DRAFT(0, "鑽夌"),
+ PUBLISHED(1, "宸插彂甯�"),
+ DISABLED(2, "宸插仠鐢�");
+
+ private final Integer status;
+ private final String name;
+
+ public static final Integer[] ARRAYS = Arrays.stream(values())
+ .map(VersionStatusEnum::getStatus).toArray(Integer[]::new);
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+ }
+
+ /**
+ * 鎶ュ憡瀹炰緥鐘舵��
+ */
+ @Getter
+ @AllArgsConstructor
+ enum InstanceStatusEnum implements ArrayValuable<Integer> {
+
+ GENERATING(0, "鐢熸垚涓�"),
+ SUCCESS(1, "鐢熸垚鎴愬姛"),
+ FAILED(2, "鐢熸垚澶辫触");
+
+ private final Integer status;
+ private final String name;
+
+ public static final Integer[] ARRAYS = Arrays.stream(values())
+ .map(InstanceStatusEnum::getStatus).toArray(Integer[]::new);
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+ }
+
+ /**
+ * 绾稿紶灏哄
+ */
+ @Getter
+ @AllArgsConstructor
+ enum PageSizeEnum implements ArrayValuable<String> {
+
+ A3("A3", "A3"),
+ A4("A4", "A4"),
+ A5("A5", "A5"),
+ LETTER("Letter", "Letter");
+
+ private final String size;
+ private final String name;
+
+ public static final String[] ARRAYS = Arrays.stream(values())
+ .map(PageSizeEnum::getSize).toArray(String[]::new);
+
+ @Override
+ public String[] array() {
+ return ARRAYS;
+ }
+
+ }
+
+ /**
+ * 绾稿紶鏂瑰悜
+ */
+ @Getter
+ @AllArgsConstructor
+ enum OrientationEnum implements ArrayValuable<String> {
+
+ PORTRAIT("portrait", "绾靛悜"),
+ LANDSCAPE("landscape", "妯悜");
+
+ private final String orientation;
+ private final String name;
+
+ public static final String[] ARRAYS = Arrays.stream(values())
+ .map(OrientationEnum::getOrientation).toArray(String[]::new);
+
+ @Override
+ public String[] array() {
+ return ARRAYS;
+ }
+
+ }
+
+ /**
+ * 鍒ゅ畾缁撴灉
+ */
+ @Getter
+ @AllArgsConstructor
+ enum CheckResultEnum implements ArrayValuable<String> {
+
+ PASS("PASS", "鍚堟牸"),
+ FAIL("FAIL", "涓嶅悎鏍�");
+
+ private final String result;
+ private final String name;
+
+ public static final String[] ARRAYS = Arrays.stream(values())
+ .map(CheckResultEnum::getResult).toArray(String[]::new);
+
+ @Override
+ public String[] array() {
+ return ARRAYS;
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/enums/QcReportSourceTypeEnum.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/enums/QcReportSourceTypeEnum.java
new file mode 100644
index 0000000..eaa35cf
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/enums/QcReportSourceTypeEnum.java
@@ -0,0 +1,54 @@
+package cn.iocoder.yudao.module.qcreport.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Objects;
+
+/**
+ * 鎶ュ憡鏉ユ簮鍗曟嵁绫诲瀷锛圡ES 鐨勫洓绫昏川妫�鍗曪級銆�
+ * <p>
+ * 杩欓噷鍚屾椂閽夋涓変欢浜掔浉缁戝畾鐨勪簨锛岄伩鍏嶆暎钀芥垚涓夊瀛楃涓插瓧闈㈤噺锛�
+ * 璐ㄦ鍗曠殑绫诲瀷鍊硷紙浼犵粰 MES 鎺ュ彛鐢級銆佹ā鏉� {@code report_type} 鐨勫彇鍊硷紙涓庡墠绔笅鎷夊悓婧愶紝鏄暟瀛楀瓧绗︿覆锛夈��
+ * 浠ュ強鎶ュ憡瀹炰緥钀藉簱鏃剁殑 {@code business_type}銆�
+ * <p>
+ * {@code businessType} 鐢ㄧ殑 {@code mes_qc_*} 鏄簨瀹炰笂鐨勫绾� 鈥斺��
+ * 銆屾寜鍗曟嵁鍙嶆煡鎶ュ憡銆嶉潬瀹冭繃婊わ紝鏀逛竴涓瓧绗﹀氨鏌ヤ笉鍒板巻鍙叉姤鍛娿��
+ */
+@Getter
+@AllArgsConstructor
+public enum QcReportSourceTypeEnum {
+
+ IQC(1, "鏉ユ枡妫�楠�", "mes_qc_iqc"),
+ IPQC(2, "杩囩▼妫�楠�", "mes_qc_ipqc"),
+ OQC(3, "鍑鸿揣妫�楠�", "mes_qc_oqc"),
+ RQC(4, "閫�璐ф楠�", "mes_qc_rqc");
+
+ /** 璐ㄦ绫诲瀷鍊硷紝瑙� MES 鐨� MesQcTypeEnum */
+ private final Integer type;
+ /** 绫诲瀷鍚嶏紝涓� MES 鍒楄〃涓婄殑鍙硶涓�鑷� */
+ private final String name;
+ /** 鎶ュ憡瀹炰緥鐨� business_type */
+ private final String businessType;
+
+ /** 璇嗗埆涓嶅嚭杩斿洖 null锛岀敱璋冪敤鏂瑰喅瀹氭�庝箞鎶ラ敊 */
+ public static QcReportSourceTypeEnum of(Integer type) {
+ for (QcReportSourceTypeEnum value : values()) {
+ if (Objects.equals(value.type, type)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 妯℃澘涓婄殑鎶ュ憡绫诲瀷鏄惁鎸囧悜鏈被鍨嬨��
+ * <p>
+ * 妯℃澘鐨� {@code report_type} 瀛樼殑鏄暟瀛楀瓧绗︿覆锛堝墠绔笅鎷夊彇 mes_qc_type 瀛楀吀鐨� string 鍊硷級锛�
+ * 鎵�浠ユ瘮鐨勬槸 {@code "1"} 鑰屼笉鏄� {@code "IQC"}銆�
+ */
+ public boolean matchesTemplateReportType(String reportType) {
+ return reportType != null && reportType.trim().equals(String.valueOf(type));
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/QcReportAiImportService.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/QcReportAiImportService.java
new file mode 100644
index 0000000..46800ce
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/QcReportAiImportService.java
@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.module.qcreport.service.aiimport;
+
+import cn.iocoder.yudao.module.qcreport.controller.admin.aiimport.vo.QcReportAiDraftReqVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.aiimport.vo.QcReportAiDraftRespVO;
+
+/**
+ * AI 瀵煎叆 Service 鎺ュ彛锛氳鏂囦欢 鈫� 鍑烘ā鏉胯崏绋裤��
+ *
+ * <h3>涓轰粈涔堟槸鍚屾鎺ュ彛</h3>
+ * 涓�娆″鍏ヨ绛� 10锝�60 绉掋�傚仛鎴愬紓姝ラ渶瑕佷换鍔¤〃 + 杞 + 绾跨▼姹狅紝鑰屽畠鎹㈡潵鐨勫彧鏄�岀敤鎴峰彲浠ュ厛鍘诲共鍒殑銆嶁�斺��
+ * 浣嗚崏绋垮彧浣滃弬鑰冿紝鐢ㄦ埛绛夌粨鏋滃拰鍘诲共鍒殑鍐嶅洖鏉ワ紝鎷垮埌鐨勮涓哄畬鍏ㄤ竴鏍枫�備负涓�涓笉鏀瑰彉缁撴灉鐨勪綋楠�
+ * 寮曞叆涓�寮犺〃鍜屼竴涓嚎绋嬫睜锛屼笉鍒掔畻銆�
+ *
+ * <h3>涓轰粈涔堜笉钀藉簱</h3>
+ * 鑽夌鍙粰浜哄湪璁捐鍣ㄩ噷纭锛屼笉闇�瑕佷竴涓兘鎸� ID 鍥炴煡鐨勫疄浣撱�備笉钀藉簱鎰忓懗鐫�澶辫触銆侀噸璇曘�佹斁寮�
+ * 閮戒笉鐣欎笅浠讳綍闇�瑕佹竻鐞嗙殑琛岋紱鑰屻�屼繚瀛樸�嶄粛鐒舵槸鏃㈡湁鐨� {@code createVersion} / {@code updateVersion}锛�
+ * Schema 鏍¢獙锛堝惈鍒ゅ畾瑙勫垯锛夐偅閬撻椄闂ㄨ嚜鍔ㄧ敓鏁堬紝涓嶅瓨鍦ㄧ浜屾潯钀藉簱璺緞銆�
+ */
+public interface QcReportAiImportService {
+
+ /**
+ * 璇嗗埆鏂囦欢锛岃繑鍥炴ā鏉胯崏绋裤��
+ *
+ * @param reqVO 璇锋眰鍙傛暟锛堟枃浠� blobId銆佺粍浠舵竻鍗曘�佽ˉ鍏呰鏄庯級
+ * @return 妯℃澘鑽夌锛屽惈杞彁绀�
+ */
+ QcReportAiDraftRespVO generateDraft(QcReportAiDraftReqVO reqVO);
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/QcReportAiImportServiceImpl.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/QcReportAiImportServiceImpl.java
new file mode 100644
index 0000000..c8ae611
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/QcReportAiImportServiceImpl.java
@@ -0,0 +1,323 @@
+package cn.iocoder.yudao.module.qcreport.service.aiimport;
+
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.module.ai.api.chat.AiChatApi;
+import cn.iocoder.yudao.module.qcreport.config.QcReportAiImportProperties;
+import cn.iocoder.yudao.module.qcreport.controller.admin.aiimport.vo.QcReportAiDraftReqVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.aiimport.vo.QcReportAiDraftRespVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.aiimport.vo.QcReportComponentSpecVO;
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.version.ReportTemplateSchema;
+import cn.iocoder.yudao.module.qcreport.service.aiimport.document.QcReportDocumentExtract;
+import cn.iocoder.yudao.module.qcreport.service.aiimport.document.QcReportDocumentExtractService;
+import cn.iocoder.yudao.module.qcreport.service.aiimport.llm.QcReportAiDraftNormalizer;
+import cn.iocoder.yudao.module.qcreport.service.aiimport.llm.QcReportAiDraftParser;
+import cn.iocoder.yudao.module.qcreport.service.aiimport.llm.QcReportLlmCall;
+import cn.iocoder.yudao.module.qcreport.service.aiimport.llm.QcReportLlmCallPlanner;
+import cn.iocoder.yudao.module.qcreport.service.aiimport.llm.QcReportTemplatePromptBuilder;
+import cn.iocoder.yudao.module.system.dal.dataobject.storage.SystemStorageBlobDO;
+import cn.iocoder.yudao.module.system.service.storage.SystemStorageBlobService;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.AI_IMPORT_AI_BUDGET_EXCEEDED;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.AI_IMPORT_AI_TIMEOUT;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.AI_IMPORT_AI_UNAVAILABLE;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.AI_IMPORT_BLOB_NOT_FOUND;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.AI_IMPORT_CATALOG_INVALID;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.AI_IMPORT_DISABLED;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.AI_IMPORT_DRAFT_EMPTY;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.AI_IMPORT_FILE_TOO_LARGE;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.AI_IMPORT_SCHEMA_VERSION_UNSUPPORTED;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.AI_IMPORT_TOO_MANY_FILES;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.AI_IMPORT_TOO_MANY_PAGES_TOTAL;
+
+/**
+ * AI 瀵煎叆 Service 瀹炵幇绫汇��
+ * <p>
+ * 娴佺▼鍥哄畾涓猴細鏍¢獙 鈫� 閫愪釜鏂囦欢鎶藉彇 鈫� 鎺掕皟鐢ㄨ鍒� 鈫� 鎵ц 鈫� 閫愭褰掍竴 鈫� 鍚堝苟鍘婚噸 鈫� 缁勮銆�
+ * 姣忎竴姝ョ殑澶辫触閮藉搴斾竴涓‘瀹氱殑閿欒鐮侊紝鍓嶇鎷垮埌鐨勬案杩滄槸銆屽摢涓�姝ャ�佷负浠�涔堛�佹�庝箞鍔炪�嶏紝
+ * 鑰屼笉鏄竴涓� 500 鍔犱竴鍙ャ�孉I 璇嗗埆澶辫触銆嶃��
+ * <p>
+ * <b>涓� ERP / CRM 閭d笁澶� AI 璋冪敤鐨勪竴澶勫埢鎰忓亸绂�</b>锛氬畠浠妸閿欒濉炶繘鍝嶅簲浣撶殑 {@code rawText} 涓旇繑鍥� HTTP 200锛�
+ * 鍓嶇闈犮�宺awText 鏈夋病鏈夊�笺�嶅梾鎺㈠け璐ャ�傛湰瀹炵幇鏀圭敤鐪熸鐨� ServiceException + 鍒嗛敊璇爜鈥斺��
+ * 闈犲瓧娈垫湁娌℃湁鍊兼潵鍒ゆ柇鎴愯触锛屼竴鏃︽煇澶╂甯歌繑鍥炰篃甯︿笂浜� rawText锛屽墠绔細绔嬪埢璇垽銆�
+ */
+@Slf4j
+@Service
+@Validated
+public class QcReportAiImportServiceImpl implements QcReportAiImportService {
+
+ /**
+ * 缁勪欢娓呭崟鐨勯」鏁颁笂闄愩��
+ * <p>
+ * 鍓嶇娉ㄥ唽琛ㄧ幇鏈� 12 涓粍浠讹紝鐣欏嚭涓夊�嶄綑閲忋�傜湡姝g殑闃茬嚎鏄Н鏈ㄦ竻鍗曠殑搴忓垪鍖栭暱搴︿笂闄�
+ * 锛堝湪 {@link QcReportTemplatePromptBuilder} 閲岋級锛岃繖鏉″彧鏄彁鍓嶆嫤浣忔槑鏄惧紓甯哥殑鍏ュ弬銆�
+ */
+ private static final int MAX_CATALOG_ITEMS = 40;
+
+ @Resource
+ private QcReportAiImportProperties properties;
+
+ @Resource
+ private QcReportDocumentExtractService extractService;
+
+ @Resource
+ private AiChatApi aiChatApi;
+
+ @Resource
+ private SystemStorageBlobService storageBlobService;
+
+ @Override
+ public QcReportAiDraftRespVO generateDraft(QcReportAiDraftReqVO reqVO) {
+ long startedAt = System.currentTimeMillis();
+ validateEnabled();
+ validateCatalog(reqVO);
+ validateSchemaVersion(reqVO.getSchemaVersion());
+ validateFileCount(reqVO.getBlobIds().size());
+
+ String systemPrompt = QcReportTemplatePromptBuilder.buildSystemPrompt(reqVO.getCatalog());
+ List<QcReportAiDraftNormalizer.Result> perCall = new ArrayList<>();
+ List<String> warnings = new ArrayList<>();
+ List<String> fileNames = new ArrayList<>();
+ ReportTemplateSchema.Page page = null;
+ String summary = null;
+ int totalPages = 0;
+ int callCount = 0;
+ boolean budgetExceeded = false;
+ long budgetMs = properties.getMaxDurationSeconds() * 1000L;
+
+ for (Long blobId : reqVO.getBlobIds()) {
+ // 杩涙枃浠跺墠鍏堢湅棰勭畻锛氬凡缁忚秴浜嗗氨涓嶈鍐嶆妸涓嬩竴浠芥枃浠惰杩涙潵銆佹洿涓嶈娓叉煋瀹冪殑椤碉紝
+ // 閭d簺閮芥槸鐧借姳鐨� CPU 鍜屽唴瀛�
+ if (System.currentTimeMillis() - startedAt >= budgetMs) {
+ budgetExceeded = true;
+ break;
+ }
+ LoadedBlob blob = loadBlob(blobId);
+ QcReportDocumentExtract extract = extractService.extract(blob.content(), blob.originalFilename(),
+ blob.contentType());
+ fileNames.add(blob.originalFilename());
+ totalPages += extract.pageCount();
+ validateTotalPages(totalPages);
+ warnings.addAll(extract.notes());
+
+ for (QcReportLlmCall call : QcReportLlmCallPlanner.plan(extract, blob.originalFilename())) {
+ // 涓ゆ璋冪敤涔嬮棿鍏抽棬銆傚崟娆¤皟鐢ㄦ棤娉曟墦鏂紙AiChatApi 涓嶆敹瓒呮椂鍙傛暟锛夛紝
+ // 鎵�浠ヨ繖閲屾嫤涓嶄綇銆屾渶鍚庝竴娆¤皟鐢ㄥ張鑰楁弧涓�涓� yudao.ai.timeout銆嶁�斺��
+ // 鍓嶇瓒呮椂鍥犳蹇呴』姣斻�屾湰棰勭畻 + 鍗曟瓒呮椂銆嶆洿瀹斤紝鍚﹀垯鐢ㄦ埛鐪嬪埌鐨勬槸娴忚鍣ㄦ柇寮�鑰岄潪杩欐潯鎻愮ず
+ if (System.currentTimeMillis() - startedAt >= budgetMs) {
+ budgetExceeded = true;
+ break;
+ }
+ QcReportAiDraftRespVO raw = execute(systemPrompt, reqVO.getHint(), call, startedAt);
+ callCount++;
+ if (page == null) {
+ page = raw.getPage();
+ }
+ if (summary == null && StrUtil.isNotBlank(raw.getSummary())) {
+ summary = raw.getSummary();
+ }
+ perCall.add(QcReportAiDraftNormalizer.normalize(
+ raw.getComponents(), reqVO.getCatalog(), call.sourceLabel()));
+ }
+ if (budgetExceeded) {
+ break;
+ }
+ }
+
+ long elapsedSeconds = (System.currentTimeMillis() - startedAt) / 1000;
+ if (budgetExceeded) {
+ // 宸茬粡璇嗗埆鍑烘潵鐨勯儴鍒嗙収甯歌繑鍥烇細鍗婁唤鑽夌瀵圭敤鎴蜂粛鐒舵湁鐢紝
+ // 涓旇繖閲屾妸銆屽悗缁病璇嗗埆銆嶆槑鍐欏嚭鏉ワ紝涓嶆槸闈欓粯鎴柇
+ warnings.add(StrUtil.format(
+ "鏈璇嗗埆宸茶揪鍒板崟娆″鍏ヨ�楁椂涓婇檺锛坽} 绉掞紝宸茬敤鏃� {} 绉掞級锛屽悗缁唴瀹规湭鍐嶈瘑鍒紝"
+ + "浠ヤ笂鏄凡璇嗗埆鍒扮殑閮ㄥ垎銆傝鍑忓皯鏂囦欢鏁伴噺鎴栭〉鏁板悗鍒嗘壒瀵煎叆",
+ properties.getMaxDurationSeconds(), elapsedSeconds));
+ }
+
+ QcReportAiDraftNormalizer.Result merged =
+ QcReportAiDraftNormalizer.mergeAndDedup(perCall, properties.getMaxComponents());
+ warnings.addAll(merged.warnings());
+ if (merged.components().isEmpty()) {
+ // 涓�涓粍浠堕兘娌¤瘑鍒嚭鏉ユ椂锛屾姤閿欐枃妗堣璇存竻鍒板簳鏄洜涓鸿�楀敖浜嗛绠楋紝
+ // 杩樻槸妯″瀷纭疄璁や笉鍑衡�斺�斾袱鑰呯敤鎴疯閲囧彇鐨勫姩浣滃畬鍏ㄤ笉鍚�
+ if (budgetExceeded) {
+ throw exception(AI_IMPORT_AI_BUDGET_EXCEEDED, properties.getMaxDurationSeconds(),
+ elapsedSeconds, String.join("銆�", fileNames));
+ }
+ throw exception(AI_IMPORT_DRAFT_EMPTY, String.join("銆�", fileNames));
+ }
+
+ QcReportAiDraftRespVO resp = new QcReportAiDraftRespVO();
+ resp.setComponents(merged.components());
+ resp.setPage(page);
+ resp.setSummary(summary);
+ resp.setWarnings(warnings);
+ resp.setDurationMs(System.currentTimeMillis() - startedAt);
+ log.info("AI 瀵煎叆璇嗗埆瀹屾垚锛歠iles={}, pages={}, calls={}, components={}, budgetExceeded={}, durationMs={}",
+ fileNames, totalPages, callCount, merged.components().size(), budgetExceeded, resp.getDurationMs());
+ return resp;
+ }
+
+ /* ------------------------------ 璋冪敤鎵ц ------------------------------ */
+
+ /**
+ * 鍙戜竴娆℃ā鍨嬭皟鐢ㄥ苟瑙f瀽鍥炲銆�
+ * <p>
+ * 鎵�鏈夊紓甯搁兘鍦ㄨ繖閲屾敹鍙f垚涓�涓‘瀹氱殑閿欒鐮侊細瓒呮椂涓庡叾瀹冨け璐ュ垎寮�锛屽洜涓虹敤鎴风殑涓嬩竴姝ュ姩浣滃畬鍏ㄤ笉鍚屸�斺��
+ * 鍓嶈�呰鍑忔枃浠讹紝鍚庤�呰鍘绘煡 AI 妯″瀷閰嶇疆銆傛妸瀹冧滑娣锋垚銆孉I 璇嗗埆澶辫触銆嶏紝鐢ㄦ埛鍙兘涓や欢浜嬮兘璇曚竴閬嶃��
+ */
+ private QcReportAiDraftRespVO execute(String systemPrompt, String hint, QcReportLlmCall call, long startedAt) {
+ String userMessage = QcReportTemplatePromptBuilder.buildUserMessage(hint, call.sourceLabel(), call.text());
+ String reply;
+ try {
+ reply = call.kind() == QcReportLlmCall.Kind.IMAGE
+ ? aiChatApi.chatWithImage(systemPrompt, userMessage, call.imageBase64(), call.mimeType())
+ : aiChatApi.chat(systemPrompt, userMessage);
+ } catch (Exception e) {
+ long elapsed = System.currentTimeMillis() - startedAt;
+ log.warn("AI 瀵煎叆璋冪敤澶辫触锛歴ource={}, kind={}, elapsedMs={}", call.sourceLabel(), call.kind(), elapsed, e);
+ if (isTimeout(e)) {
+ throw exception(AI_IMPORT_AI_TIMEOUT, elapsed / 1000);
+ }
+ throw exception(AI_IMPORT_AI_UNAVAILABLE, elapsed, StrUtil.maxLength(String.valueOf(e.getMessage()), 200));
+ }
+ try {
+ return QcReportAiDraftParser.parse(reply);
+ } catch (ServiceException e) {
+ // 妯″瀷杩斿洖浜嗕粈涔堬紝鏄帓鏌ヨ繖鏉¤矾涓婂敮涓�鐨勭嚎绱€�傚啓杩涙棩蹇楄�屼笉鏄杩涘搷搴旓細
+ // 涓�鍧ㄦā鍨嬪師鏂囩粰鐢ㄦ埛鐪嬫病鏈夋剰涔夛紝鑰岄敊璇爜宸茬粡璁叉竻浜嗐�屾�庝箞鍔炪��
+ log.warn("AI 瀵煎叆瑙f瀽鍥炲澶辫触锛歴ource={}, reply={}",
+ call.sourceLabel(), QcReportAiDraftParser.truncate(reply), e);
+ throw e;
+ }
+ }
+
+ /**
+ * 鍒ゆ柇寮傚父閾鹃噷鏈夋病鏈夎秴鏃躲��
+ * <p>
+ * {@code AiChatApi} 涓嶆毚闇插簳灞� HTTP 瀹㈡埛绔紝瓒呮椂鏈�缁堜細浠� {@link InterruptedIOException}
+ * 锛圤kHttp 鐨勮鍐欒秴鏃堕兘鏄畠鐨勫瓙绫伙級鎴栧甫鏈� "timeout" 瀛楁牱鐨勫紓甯稿嚭鐜板湪鍘熷洜閾句笂銆�
+ * 娌块摼鎵捐�屼笉鏄彧鐪嬫渶澶栧眰锛氫腑闂撮殧浜嗗嚑灞傚寘瑁呮槸甯告�併��
+ */
+ private static boolean isTimeout(Throwable e) {
+ for (Throwable cause = e; cause != null; cause = cause.getCause()) {
+ if (cause instanceof InterruptedIOException) {
+ return true;
+ }
+ if (cause.getMessage() != null && cause.getMessage().toLowerCase().contains("timeout")) {
+ return true;
+ }
+ if (cause.getCause() == cause) {
+ break;
+ }
+ }
+ return false;
+ }
+
+ /* ------------------------------ 璇诲彇鏂囦欢 ------------------------------ */
+
+ /**
+ * 璇讳竴涓� blob 鐨勫瓧鑺傘��
+ * <p>
+ * <b>鍒绘剰涓嶅垹闄ゅ彇鍒扮殑鏂囦欢銆�</b> {@code getPublicFile} 杩斿洖鐨勬槸纾佺洏涓婄湡瀹炲瓨鍌ㄧ殑閭d唤 blob锛�
+ * 涓嶆槸涓存椂鍓湰鈥斺�斿垹浜嗗氨鏄垹鐢ㄦ埛鐨勭湡瀹炰笂浼犳暟鎹��
+ * 锛圗RP 閲囪喘鏉ョエ AI 涓� CRM 鎶ヤ环 AI 鏇惧湪 {@code finally} 閲岀姱杩欎釜閿欙紝宸蹭慨锛涙湰瀹炵幇缁濅笉澶嶅埗銆傦級
+ */
+ private LoadedBlob loadBlob(Long blobId) {
+ SystemStorageBlobDO blob = storageBlobService.getStorageBlob(blobId);
+ if (blob == null) {
+ throw exception(AI_IMPORT_BLOB_NOT_FOUND, blobId);
+ }
+ String originalFilename = StrUtil.blankToDefault(blob.getOriginalFilename(), "file");
+ try {
+ File file = storageBlobService.getPublicFile(blob.getUidFilename(), blob.getResourceKey());
+ byte[] content = Files.readAllBytes(file.toPath());
+ long maxBytes = properties.getMaxFileSizeMb() * 1024L * 1024L;
+ if (content.length > maxBytes) {
+ throw exception(AI_IMPORT_FILE_TOO_LARGE, originalFilename,
+ content.length / 1024L / 1024L, properties.getMaxFileSizeMb());
+ }
+ return new LoadedBlob(content, originalFilename, blob.getContentType());
+ } catch (IOException e) {
+ log.warn("璇诲彇涓婁紶鏂囦欢澶辫触锛宐lobId={}", blobId, e);
+ throw exception(AI_IMPORT_BLOB_NOT_FOUND, blobId);
+ }
+ }
+
+ private record LoadedBlob(byte[] content, String originalFilename, String contentType) {
+ }
+
+ /* ------------------------------ 鏍¢獙 ------------------------------ */
+
+ private void validateEnabled() {
+ if (!Boolean.TRUE.equals(properties.getEnabled())) {
+ throw exception(AI_IMPORT_DISABLED);
+ }
+ }
+
+ private void validateCatalog(QcReportAiDraftReqVO reqVO) {
+ if (reqVO.getCatalog() == null || reqVO.getCatalog().isEmpty()) {
+ throw exception(AI_IMPORT_CATALOG_INVALID, "缁勪欢娓呭崟涓虹┖");
+ }
+ if (reqVO.getCatalog().size() > MAX_CATALOG_ITEMS) {
+ throw exception(AI_IMPORT_CATALOG_INVALID,
+ StrUtil.format("缁勪欢娓呭崟鍏� {} 椤癸紝瓒呰繃涓婇檺 {} 椤�", reqVO.getCatalog().size(), MAX_CATALOG_ITEMS));
+ }
+ for (QcReportComponentSpecVO spec : reqVO.getCatalog()) {
+ if (spec == null || StrUtil.isBlank(spec.getType())) {
+ throw exception(AI_IMPORT_CATALOG_INVALID, "瀛樺湪娌℃湁 type 鐨勭粍浠堕」");
+ }
+ }
+ }
+
+ /**
+ * 鏍¢獙 Schema 鐗堟湰銆�
+ * <p>
+ * 杩欐潯妫�鏌ユ妸銆岀Н鏈ㄦ竻鍗曟潵鑷� 1.1 璇箟灞傘�嶈繖涓殣寮忚�﹀悎鍙樻垚鏄惧紡澶辫触锛氱増鏈笉涓�鑷磋鏄庡墠绔槸鏃у寘锛�
+ * 瀹冪敓鎴愬嚭鏉ョ殑娓呭崟鍙兘涓庢湇鍔$鐞嗚В鐨勮涔夊眰瀵逛笉涓婏紝姝ゆ椂鎶ラ敊璁╃敤鎴峰埛鏂帮紝姣旇妯″瀷鍩轰簬杩囨湡娓呭崟缂栫粍浠跺畨鍏ㄣ��
+ */
+ private void validateSchemaVersion(String schemaVersion) {
+ if (!ReportTemplateSchema.SCHEMA_VERSION.equals(schemaVersion)) {
+ throw exception(AI_IMPORT_SCHEMA_VERSION_UNSUPPORTED, schemaVersion,
+ ReportTemplateSchema.SCHEMA_VERSION);
+ }
+ }
+
+ /**
+ * 鏍¢獙鏂囦欢涓暟銆�**杩欐槸鏂囦欢鏁颁笂闄愮殑鍞竴闂搁棬**锛屽叆鍙� VO 涓婂埢鎰忎笉鍐嶆寕 {@code @Size}銆�
+ * <p>
+ * 璋冪敤浣嶇疆鍦� {@link #generateDraft} 鐨勬渶鍓嶆銆佷换浣� blob 璇诲彇涔嬪墠锛屾墍浠ユ斁澶ф枃浠舵暟涓嶄細甯︽潵
+ * 棰濆鐨勭鐩�/鍐呭瓨寮�閿�锛屾敞瑙i偅灞傛嫤鎴苟鏃犲繀瑕侊紱鑰屼袱涓暟瀛楀苟瀛樼殑缁撴灉鍙細鏄敞瑙f洿涓ャ�侀厤缃け鍘诲彲璋冩�с��
+ */
+ private void validateFileCount(int fileCount) {
+ if (fileCount > properties.getMaxFiles()) {
+ throw exception(AI_IMPORT_TOO_MANY_FILES, properties.getMaxFiles(), fileCount);
+ }
+ }
+
+ /**
+ * 鏍¢獙绱椤垫暟銆�
+ * <p>
+ * 鍗曟枃浠堕〉鏁板湪閫傞厤鍣ㄩ噷宸茬粡鍗¤繃浜嗭紝杩欓噷鍗$殑鏄�屾瘡涓枃浠堕兘娌¤秴銆佸姞璧锋潵鍗村緢澶氥�嶁�斺��
+ * 涓変釜鍚� 5 椤电殑鎵弿浠朵細鍙樻垚 15 娆″妯℃�佽皟鐢紝浠d环涓庤�楁椂閮借繙瓒呴鏈熴��
+ */
+ private void validateTotalPages(int totalPages) {
+ if (totalPages > properties.getMaxPagesPerRequest()) {
+ throw exception(AI_IMPORT_TOO_MANY_PAGES_TOTAL, totalPages,
+ properties.getMaxPagesPerRequest(), properties.getMaxPagesPerFile());
+ }
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/ImageImportAdapter.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/ImageImportAdapter.java
new file mode 100644
index 0000000..121c251
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/ImageImportAdapter.java
@@ -0,0 +1,62 @@
+package cn.iocoder.yudao.module.qcreport.service.aiimport.document;
+
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Set;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.AI_IMPORT_FILE_EMPTY;
+
+/**
+ * 鍥剧墖锛堢収鐗� / 鎴浘锛夋娊鍙栧櫒銆�
+ * <p>
+ * 涓夌閫傞厤鍣ㄩ噷鍞竴銆屼粈涔堥兘涓嶇敤鍋氥�嶇殑涓�涓細瀛楄妭鍘熸牱浜ょ粰澶氭ā鎬佹ā鍨嬶紝涓嶈В鐮併�佷笉缂╂斁銆佷笉杞爜銆�
+ * 鍒绘剰涓嶅湪杩欓噷鐢� {@code ImageIO} 璇讳竴閬嶁�斺�旈偅涓嶄粎澶氫竴娆″唴瀛樻嫹璐濓紝杩樹細鍦ㄩ亣鍒� webp 杩欑被
+ * JDK 鍘熺敓涓嶆敮鎸佺殑鏍煎紡鏃剁櫧鐧藉け璐ワ紝鑰屾ā鍨嬮偅杈瑰叾瀹炲畬鍏ㄨ兘璁ゃ��
+ * <p>
+ * 鎺掑湪绗竴浣嶏細瀹冨彧璁ゅ浘鐗囨墿灞曞悕锛屼笌鍙﹀涓や釜鐨勫尮閰嶉泦涓嶇浉浜わ紝鏀惧摢閮戒笉浼氬紩璧锋涔夛紝
+ * 浣嗘斁鍦ㄦ渶鍓嶉潰鑳借銆屼竴寮犵収鐗囥�嶈繖鏉℃渶甯歌鐨勮矾寰勪互鏈�鐭殑璺蛋鍒板ご銆�
+ */
+@Component
+@Order(1)
+public class ImageImportAdapter implements QcReportImportAdapter {
+
+ private static final Set<String> EXTENSIONS = Set.of("png", "jpg", "jpeg", "bmp", "gif", "webp");
+
+ @Override
+ public boolean supports(String extension, String contentType) {
+ return EXTENSIONS.contains(extension);
+ }
+
+ @Override
+ public QcReportDocumentExtract extract(byte[] content, String originalFilename) {
+ if (content == null || content.length == 0) {
+ throw exception(AI_IMPORT_FILE_EMPTY, originalFilename, 1);
+ }
+ String mimeType = mimeTypeOf(extensionOf(originalFilename));
+ return QcReportDocumentExtract.ofImages(
+ List.of(new QcReportDocumentExtract.ImagePart(content, mimeType, "绗� 1 椤�")),
+ 1, "raw-image", List.of());
+ }
+
+ /**
+ * PDF 閫傞厤鍣ㄩ渶瑕佸悓涓�濂楁槧灏勬潵鏍囨敞娓叉煋鍑烘潵鐨� PNG锛屾墍浠ュ叕寮�鍑烘潵澶嶇敤銆�
+ */
+ static String mimeTypeOf(String extension) {
+ return switch (extension) {
+ case "jpg", "jpeg" -> "image/jpeg";
+ case "gif" -> "image/gif";
+ case "bmp" -> "image/bmp";
+ case "webp" -> "image/webp";
+ default -> "image/png";
+ };
+ }
+
+ private static String extensionOf(String filename) {
+ int dot = filename == null ? -1 : filename.lastIndexOf('.');
+ return dot < 0 ? "" : filename.substring(dot + 1).toLowerCase();
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/OfficeImportAdapter.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/OfficeImportAdapter.java
new file mode 100644
index 0000000..814d386
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/OfficeImportAdapter.java
@@ -0,0 +1,372 @@
+package cn.iocoder.yudao.module.qcreport.service.aiimport.document;
+
+import cn.iocoder.yudao.module.qcreport.config.QcReportAiImportProperties;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.DataFormatter;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.poi.xwpf.usermodel.IBodyElement;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFHeaderFooter;
+import org.apache.poi.xwpf.usermodel.XWPFParagraph;
+import org.apache.poi.xwpf.usermodel.XWPFTable;
+import org.apache.poi.xwpf.usermodel.XWPFTableCell;
+import org.apache.poi.xwpf.usermodel.XWPFTableRow;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVMerge;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.AI_IMPORT_FILE_EMPTY;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.AI_IMPORT_FILE_LEGACY_OFFICE;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.AI_IMPORT_OFFICE_CORRUPT;
+
+/**
+ * Word / Excel / 绾枃鏈娊鍙栧櫒銆�
+ * <p>
+ * <b>鐢� POI 鑰屼笉鏄� Tika</b>锛屼袱涓師鍥狅紝缂轰竴涓嶅彲锛�
+ * 妫�楠屾姤鍛婄殑鏍稿績淇℃伅鍦ㄨ〃鏍奸噷锛岃鍒楃粨鏋勪竴鏃﹁ Tika 鎷嶅钩鎴愪竴娈垫枃瀛楀氨鍐嶄篃鎵句笉鍥炴潵锛�
+ * 鑰� {@code tika-parsers-standard-package} 浼氭嫋杩涘嚑鐧� MB 鐨勮В鏋愬櫒渚濊禆锛�
+ * 涓�涓彧澶勭悊鍥涚鏍煎紡鐨勬ā鍧楁病蹇呰鑳岃繖涓寘琚便��
+ *
+ * <h3>椤电湁椤佃剼</h3>
+ * .docx 鐨� page header / footer 瀛樺湪姝f枃涔嬪锛寋@code getBodyElements()} 鐪嬩笉鍒板畠浠��
+ * 鍙湅姝f枃鐨勬枃浠讹紝銆屽叕鍙告姮澶村湪椤电湁銆佸巶鍧�鐢佃瘽鍦ㄩ〉鑴氥�嶈繖绫绘姤鍛婁細鎶婁袱澶撮兘涓㈡帀鈥斺��
+ * 妯″瀷杩炴枃瀛楅兘娌¤杩囷紝鑷劧涔熶笉浼氭兂鍒扮敤 {@code ReportHeader} / {@code ReportFooter}銆�
+ * 鎵�浠ラ〉鐪夐〉鑴氫竴骞惰鍏ワ紝鐢� {@code [椤电湁]} / {@code [椤佃剼]} 鏍囪涓庢鏂囧尯鍒嗐��
+ * PDF 涓庡浘鐗囦笉闇�瑕佽繖濂楁爣璁帮細閭d袱绉嶉�氶亾閲岄〉鐪夐〉鑴氭湰鏉ュ氨鏄〉闈㈠唴瀹圭殑涓�閮ㄥ垎銆�
+ *
+ * <h3>鏃ф牸寮� .doc / .xls</h3>
+ * 鍦� {@link #supports} 閲�<b>璁ら</b>銆佸湪 {@link #extract} 閲�<b>鎷掔粷</b>銆�
+ * 璁╁畠璧板埌銆屾牸寮忎笉鏀寔銆嶉偅鏉¢�氱敤閿欒鍘绘槸涓嶈鐨勶細閭h竟鍙細鍛婅瘔鐢ㄦ埛銆屼粎鏀寔 PDF / Word / Excel銆嶏紝
+ * 鑰岀敤鎴锋墜涓婄殑鏂囦欢鎵╁睍鍚嶇湅璧锋潵瀹屽叏鍚堣锛�.doc 涔熸槸 Word锛夛紝鎻愮ず绛変簬娌¤銆�
+ * 璁ら涔嬪悗灏辫兘缁欏嚭鐪熸鐨勫嚭璺�斺�斿彟瀛樹负 .docx銆�
+ */
+@Slf4j
+@Component
+@Order(3)
+public class OfficeImportAdapter implements QcReportImportAdapter {
+
+ private static final Set<String> EXTENSIONS = Set.of("docx", "xlsx", "txt", "csv", "doc", "xls");
+
+ /** 鍙惈绌虹櫧瀛楃鐨� UTF-8 BOM锛岃В鐮佸墠瑕佸厛鍓ユ帀锛屽惁鍒欑涓�琛岀殑绗竴涓崟鍏冩牸浼氬甫涓�涓笉鍙瀛楃 */
+ private static final byte[] BOM_UTF_8 = {(byte) 0xEF, (byte) 0xBB, (byte) 0xBF};
+
+ /** 椤电湁/椤佃剼鏍囪锛氫笉鏍囪鐨勮瘽锛屾ā鍨嬫棤浠庡垽鏂繖娈垫槸姣忛〉閲嶅鐨勬姮澶磋繕鏄鏂囬噷鐨勬櫘閫氭枃鏈� */
+ private static final String HEADER_MARK = "[椤电湁]";
+
+ private static final String FOOTER_MARK = "[椤佃剼]";
+
+ /** 椤电湁/椤佃剼鍙槸杞彁绀猴紙杩� warnings锛夛紝瑕佷笉瑕佸彉鎴愮粍浠剁敱妯″瀷鎸夌粍浠� hint 鍒ゆ柇锛岀敤鎴峰啀纭 */
+ private static final String HEADER_FOOTER_NOTE =
+ "鍘熶欢甯︽湁椤电湁/椤佃剼锛屽凡鐢� [椤电湁] / [椤佃剼] 鏍囪骞跺叆璇嗗埆鍐呭";
+
+ @Resource
+ private QcReportAiImportProperties properties;
+
+ @Override
+ public boolean supports(String extension, String contentType) {
+ return EXTENSIONS.contains(extension);
+ }
+
+ @Override
+ public QcReportDocumentExtract extract(byte[] content, String originalFilename) {
+ String extension = extensionOf(originalFilename);
+ if ("doc".equals(extension) || "xls".equals(extension)) {
+ throw exception(AI_IMPORT_FILE_LEGACY_OFFICE, originalFilename, extension);
+ }
+ if (content == null || content.length == 0) {
+ throw exception(AI_IMPORT_FILE_EMPTY, originalFilename, 1);
+ }
+ List<String> notes = List.of();
+ String text;
+ if ("docx".equals(extension)) {
+ DocxRead read = readDocx(content, originalFilename);
+ text = read.text();
+ notes = read.notes();
+ } else {
+ text = switch (extension) {
+ case "xlsx" -> readXlsx(content, originalFilename);
+ case "txt", "csv" -> readPlainText(content);
+ default -> "";
+ };
+ }
+ if (text.isBlank()) {
+ throw exception(AI_IMPORT_FILE_EMPTY, originalFilename, 1);
+ }
+ return QcReportDocumentExtract.ofText(text, 1, extractorNameOf(extension), notes);
+ }
+
+ /**
+ * 璇� .docx锛屾鏂囦笌椤电湁/椤佃剼涓�璧疯銆�
+ * <p>
+ * 姝f枃鎸� {@code getBodyElements()} 杩唬鑰屼笉鏄�屽厛鎵�鏈夋钀姐�佸啀鎵�鏈夎〃鏍笺�嶏細鎶ュ憡閲岃〃鏍煎す鍦ㄦ钀戒箣闂达紝
+ * 鍒嗗紑鏀堕泦浼氭妸鐗堥潰椤哄簭褰诲簳鎵撲贡锛屾ā鍨嬬湅鍒扮殑鏄竴鍫嗘爣棰樺爢鍦ㄥ紑澶淬�佽〃鏍煎爢鍦ㄧ粨灏俱��
+ * <p>
+ * 琛ㄦ牸鐢� Tab 鍒嗛殧鍗曞厓鏍笺�佹崲琛屽垎闅旇锛屽苟鍦ㄥ墠鍚庡姞鏍囪鈥斺�旀爣璁扮殑浣滅敤鏄妯″瀷鐭ラ亾
+ * 銆岃繖鍑犺灞炰簬鍚屼竴涓〃鏍笺�嶏紝娌℃湁瀹冿紝涓�娈电敤 Tab 鎷艰捣鏉ョ殑鏂囨湰鍜屾櫘閫氭钀芥棤浠庡尯鍒嗐��
+ * 琛ㄦ牸鍐呴儴鐨勫悎骞跺崟鍏冩牸鐢� {@link #appendTable} 褰掍竴鍖栨垚瀵归綈鐨勭綉鏍硷紝鍚堝苟淇℃伅鍥犳涓嶄細涓㈠け銆�
+ * <p>
+ * <b>椤电湁/椤佃剼蹇呴』璇�</b>锛氭姤鍛婄殑鎶ご锛堝叕鍙稿悕銆佹姤鍛婂悕锛夊拰钀芥锛堝巶鍧�銆佺數璇濓級閫氬父灏变綇鍦ㄨ繖閲岋紝
+ * 鑰� {@code getBodyElements()} 鍙湅姝f枃锛屼笉璇荤殑璇濇ā鍨嬪帇鏍规病瑙佽繃杩欎簺鏂囧瓧锛�
+ * 涔熷氨涓嶅彲鑳芥妸瀹冧滑璁ゆ垚 {@code ReportHeader} / {@code ReportFooter}銆傝鍒扮殑鍐呭鐢�
+ * {@code [椤电湁]} / {@code [椤佃剼]} 鍖呬綇锛岄『搴忎笌鏂囨。瑙嗚椤哄簭涓�鑷达紙椤电湁鍦ㄥ墠銆侀〉鑴氬湪鍚庯級銆�
+ */
+ private DocxRead readDocx(byte[] content, String originalFilename) {
+ try (XWPFDocument document = new XWPFDocument(new ByteArrayInputStream(content))) {
+ StringBuilder sb = new StringBuilder();
+ String header = collectHeaderFooter(document.getHeaderList());
+ String footer = collectHeaderFooter(document.getFooterList());
+ if (!header.isBlank()) {
+ sb.append(HEADER_MARK).append('\n').append(header);
+ }
+ appendBodyElements(sb, document.getBodyElements());
+ if (!footer.isBlank()) {
+ sb.append(FOOTER_MARK).append('\n').append(footer);
+ }
+ List<String> notes = header.isBlank() && footer.isBlank() ? List.of() : List.of(HEADER_FOOTER_NOTE);
+ return new DocxRead(sb.toString(), notes);
+ } catch (IOException | RuntimeException e) {
+ log.warn("docx 瑙f瀽澶辫触锛宖ile={}", originalFilename, e);
+ throw exception(AI_IMPORT_OFFICE_CORRUPT, originalFilename, "docx");
+ }
+ }
+
+ /**
+ * 鏀朵竴涓枃妗g殑椤电湁鎴栭〉鑴氥��
+ * <p>
+ * 涓や欢浜嬪繀椤诲仛锛屽皯涓�浠堕兘浼氭妸鍣0褰撲俊鍙凤細
+ * <ul>
+ * <li><b>绌虹櫧杩囨护</b>锛氭枃妗f牴鏈病鏈夐〉鐪夋椂锛孭OI 鐨勯粯璁ょ瓥鐣ヤ粛浼氳繑鍥炰竴涓┖ header锛�
+ * 涓嶈繃婊ゅ氨浼氬嚟绌哄鍑轰竴涓� {@code [椤电湁]} 鏍囪锛岃妯″瀷浠ヤ负鍘熶欢鏈夋姮澶淬��</li>
+ * <li><b>鍘婚噸</b>锛歐ord 鍏佽棣栭〉/濂囨暟椤�/鍋舵暟椤靛悇閰嶄竴濂楋紝瀹為檯鏂囦欢閲岃繖鍑犲甯稿父閫愬瓧鐩稿悓锛�
+ * 涓嶅幓閲嶄細鎶婂悓涓�娈垫姮澶撮噸澶嶅嚑閬嶅杺缁欐ā鍨嬶紝鏃㈡氮璐逛笂涓嬫枃鍙堝儚鏄湪寮鸿皟瀹冦��</li>
+ * </ul>
+ */
+ private static String collectHeaderFooter(List<? extends XWPFHeaderFooter> parts) {
+ Set<String> distinct = new LinkedHashSet<>();
+ for (XWPFHeaderFooter part : parts) {
+ StringBuilder sb = new StringBuilder();
+ appendBodyElements(sb, part.getBodyElements());
+ String text = sb.toString().trim();
+ if (!text.isEmpty()) {
+ distinct.add(text);
+ }
+ }
+ return String.join("\n", distinct);
+ }
+
+ /**
+ * 鎸夐『搴忔妸娈佃惤涓庤〃鏍煎啓杩涚紦鍐插尯銆傛鏂囥�侀〉鐪夈�侀〉鑴氬叡鐢ㄤ竴浠斤紝閬垮厤涓ゅ琛ㄦ牸閫昏緫鍚勮嚜婕傜Щ銆�
+ */
+ private static void appendBodyElements(StringBuilder sb, List<IBodyElement> elements) {
+ for (IBodyElement element : elements) {
+ if (element instanceof XWPFParagraph paragraph) {
+ appendLine(sb, paragraph.getText());
+ } else if (element instanceof XWPFTable table) {
+ appendTable(sb, table);
+ }
+ }
+ }
+
+ /**
+ * 鎶婁竴寮犺〃褰掍竴鍖栨垚绋冲畾缃戞牸鍚庡啀杈撳嚭銆�
+ * <p>
+ * 鐩存帴鎸� {@code row.getTableCells()} 鎷� Tab 鏄笉澶熺殑锛氬悎骞跺崟鍏冩牸浼氳姣忚鐨勫垪鏁板悇涓嶇浉鍚岋紝
+ * 妯″瀷鏀跺埌鐨勬槸涓�寮犺鍒楅敊浣嶃�佸弬宸笉榻愮殑銆岃〃銆嶃��
+ * <ul>
+ * <li>{@code w:gridSpan} 妯悜鍚堝苟鐨勬牸瀛愶紝POI 鍙繑鍥炰竴涓� {@code XWPFTableCell}锛�
+ * 琚畠鐩栦綇鐨勫悗鍑犲垪鍑┖娑堝け 鈬� 鍚屼竴琛岀殑鍒椾笌琛ㄥご瀵逛笉涓婏紱</li>
+ * <li>{@code w:vMerge} 绾靛悜鍚堝苟鐨勭画鏍硷紝POI 鍙栧埌鐨勬枃瀛楁槸绌轰覆 鈬� 鍒嗙粍鍚嶅彧鍦ㄧ涓�琛屽嚭鐜帮紝
+ * 鍚庨潰鍑犺鐪嬭捣鏉ユ槸銆屾病鏈夊垎缁勭殑鐙珛妫�楠岄」銆嶏紝妯″瀷鑷劧鎯充笉鍒拌繖鏄袱灞傜粨鏋勩��</li>
+ * </ul>
+ * 鍚庢灉涓嶅彧鏄帓鐗堥毦鐪嬶細妯″瀷鐪嬩笉鍒颁袱灞傜粨鏋勶紝灏变笉浼氬幓鎸戙�屽垎缁勬楠岄」琛ㄣ�嶇粍浠讹紝
+ * 鍙兘閫�鑰屾眰鍏舵鎸戝钩閾虹殑妫�楠岃〃锛屾妸鍒嗙粍淇℃伅鏁翠釜涓㈡帀銆�
+ * <p>
+ * 鎵�浠ヨ繖閲屾妸鍚堝苟淇℃伅缈昏瘧鎴愭ā鍨嬬湅寰楄鐨勫瓧绗︼細
+ * <ul>
+ * <li>{@code gridSpan=N} 鐨勬枃瀛楄惤鍦ㄨ缁勭 1 鏍硷紝鍏跺悗琛� N-1 涓┖鍗犱綅锛屽垪浣嶄笌琛ㄥご瀵归綈锛�</li>
+ * <li>{@code vMerge} 缁牸杈撳嚭 {@link QcReportDocumentExtract#VERTICAL_MERGE_MARK}锛屾槑璇淬�屽悓涓婁竴琛屻�嶏紱</li>
+ * <li>姣忚灏鹃儴琛ラ綈鍒版暣琛ㄧ綉鏍煎搴︼紝鐭涓嶅啀琚綋鎴愩�屽垪鏁板氨杩欎箞澶氥�嶃��</li>
+ * </ul>
+ * 缁牸鑷韩甯︽枃瀛楁椂浠ユ枃瀛椾负鍑嗭細缁牸鍦� Word 閲屾湰涓嶈鏈夊唴瀹癸紝鐪熸湁灏辫鏄庡埗琛ㄤ笉瑙勮寖锛�
+ * 姝ゆ椂涓㈡枃瀛楁瘮涓㈢粨鏋勬洿鍙儨銆傛暣琛ㄧ綉鏍煎搴﹀彇鎵�鏈夎鐨勬渶澶у�硷紝鑰屼笉鏄涓�琛岀殑鍒楁暟鈥斺��
+ * 琛ㄥご甯稿父甯︽í鍚戝悎骞讹紝鎸夎〃澶村搴﹀垏浼氭妸涓嬮潰鍑犺鎴柇銆�
+ */
+ private static void appendTable(StringBuilder sb, XWPFTable table) {
+ List<List<String>> gridRows = new ArrayList<>();
+ int width = 0;
+ for (XWPFTableRow row : table.getRows()) {
+ List<String> grid = new ArrayList<>();
+ for (XWPFTableCell cell : row.getTableCells()) {
+ grid.add(cellText(cell));
+ for (int i = 1; i < gridSpanOf(cell); i++) {
+ grid.add("");
+ }
+ }
+ width = Math.max(width, grid.size());
+ gridRows.add(grid);
+ }
+ sb.append("[琛ㄦ牸寮�濮媇\n");
+ for (List<String> grid : gridRows) {
+ while (grid.size() < width) {
+ grid.add("");
+ }
+ appendLine(sb, String.join("\t", grid));
+ }
+ sb.append("[琛ㄦ牸缁撴潫]\n");
+ }
+
+ /** 鍗曞厓鏍兼枃瀛楋紱绌虹櫧涓旀槸绾靛悜鍚堝苟缁牸鏃剁粰鍑� {@code 鈫戝悓涓妢 鑰屼笉鏄┖涓� */
+ private static String cellText(XWPFTableCell cell) {
+ String text = cell.getText().replaceAll("[\\r\\n]+", " ").trim();
+ if (text.isEmpty() && isVerticalMergeContinuation(cell)) {
+ return QcReportDocumentExtract.VERTICAL_MERGE_MARK;
+ }
+ return text;
+ }
+
+ /**
+ * 鏄惁鏄旱鍚戝悎骞剁殑銆岀画鏍笺�嶃��
+ * <p>
+ * {@code <w:vMerge/>} 涓嶅甫 val 涓� {@code w:val="continue"} 閮借〃绀虹画鏍硷紙鍓嶈�呮槸 Word 鐨勫父瑙佸啓娉曪級锛�
+ * {@code w:val="restart"} 鏄悎骞剁殑璧峰鏍硷紝瀹冨甫鐫�鐪熸鐨勬枃瀛楋紝涓嶇畻缁牸銆�
+ */
+ private static boolean isVerticalMergeContinuation(XWPFTableCell cell) {
+ CTTcPr tcPr = cellPropertiesOf(cell);
+ if (tcPr == null || !tcPr.isSetVMerge()) {
+ return false;
+ }
+ CTVMerge vMerge = tcPr.getVMerge();
+ return !vMerge.isSetVal() || vMerge.getVal() == STMerge.CONTINUE;
+ }
+
+ /** 妯悜鍚堝苟鐨勫垪鏁帮紝闈炲悎骞舵牸涓� 1锛涘�煎紓甯告椂涓�寰嬫寜 1 澶勭悊锛屽畞鍙皯琛ュ崰浣嶄篃涓嶈鍑┖澶氬嚭鍒� */
+ private static int gridSpanOf(XWPFTableCell cell) {
+ CTTcPr tcPr = cellPropertiesOf(cell);
+ if (tcPr == null || !tcPr.isSetGridSpan()) {
+ return 1;
+ }
+ BigInteger span = tcPr.getGridSpan().getVal();
+ return span == null || span.intValue() < 1 ? 1 : span.intValue();
+ }
+
+ /** 鍙栨牸灞炴�э紱POI 瀵规病鏈� {@code <w:tcPr>} 鐨勫崟鍏冩牸杩斿洖 null锛屼笉鑳界洿鎺ラ摼寮忚皟鐢� */
+ private static CTTcPr cellPropertiesOf(XWPFTableCell cell) {
+ CTTc ctTc = cell.getCTTc();
+ return ctTc == null ? null : ctTc.getTcPr();
+ }
+
+ /** docx 鎶藉彇缁撴灉锛氭鏂囨枃鏈� + 瑕佽繘 warnings 鐨勮蒋鎻愮ず */
+ private record DocxRead(String text, List<String> notes) {
+ }
+
+ /**
+ * 璇� .xlsx銆�
+ * <p>
+ * 鐢� {@link DataFormatter} 鍙�<b>鏄剧ず鍊�</b>鑰屼笉鏄師濮嬪�硷細鍘熷鍊奸噷 {@code 1} 浼氬彉鎴� {@code 1.0}銆�
+ * 鏃ユ湡浼氬彉鎴愪竴涓插簭鍒楀彿锛屾ā鍨嬬湅鍒拌繖浜涘熀鏈彧鑳界瀻鐚溿�傜敤鎴风溂閲岀湅鍒扮殑鏄粈涔堬紝灏辫缁欐ā鍨嬩粈涔堛��
+ * <p>
+ * 琛屾暟鎸� {@code maxXlsxRows} 灏侀《锛岀┖鐧借鏁磋涓㈠純鈥斺�旇秴澶ц〃閲屽ぇ閲忕┖鐧借浼氭妸鎻愮ず璇嶇亴婊″櫔澹般��
+ */
+ private String readXlsx(byte[] content, String originalFilename) {
+ try (XSSFWorkbook workbook = new XSSFWorkbook(new ByteArrayInputStream(content))) {
+ StringBuilder sb = new StringBuilder();
+ DataFormatter formatter = new DataFormatter();
+ for (int sheetIndex = 0; sheetIndex < workbook.getNumberOfSheets(); sheetIndex++) {
+ Sheet sheet = workbook.getSheetAt(sheetIndex);
+ sb.append("[宸ヤ綔琛�: ").append(sheet.getSheetName()).append("]\n");
+ int lastRow = sheet.getLastRowNum();
+ int written = 0;
+ for (int rowIndex = 0; rowIndex <= lastRow && written < properties.getMaxXlsxRows(); rowIndex++) {
+ Row row = sheet.getRow(rowIndex);
+ if (row == null) {
+ continue;
+ }
+ List<String> cells = new ArrayList<>();
+ boolean hasValue = false;
+ for (int cellIndex = 0; cellIndex < row.getLastCellNum(); cellIndex++) {
+ Cell cell = row.getCell(cellIndex);
+ String value = cell == null ? "" : formatter.formatCellValue(cell).trim();
+ if (!value.isEmpty()) {
+ hasValue = true;
+ }
+ cells.add(value);
+ }
+ if (!hasValue) {
+ continue;
+ }
+ appendLine(sb, String.join("\t", cells));
+ written++;
+ }
+ if (written >= properties.getMaxXlsxRows() && lastRow + 1 > written) {
+ sb.append("[鏈伐浣滆〃瓒呰繃 ").append(properties.getMaxXlsxRows())
+ .append(" 琛岋紝鍚庣画鍐呭鏈鍙朷\n");
+ }
+ }
+ return sb.toString();
+ } catch (IOException | RuntimeException e) {
+ log.warn("xlsx 瑙f瀽澶辫触锛宖ile={}", originalFilename, e);
+ throw exception(AI_IMPORT_OFFICE_CORRUPT, originalFilename, "xlsx");
+ }
+ }
+
+ private String readPlainText(byte[] content) {
+ if (startsWith(content, BOM_UTF_8)) {
+ return new String(content, BOM_UTF_8.length, content.length - BOM_UTF_8.length,
+ StandardCharsets.UTF_8);
+ }
+ if (content.length >= 2 && (content[0] & 0xFF) == 0xFF && (content[1] & 0xFF) == 0xFE) {
+ return new String(content, 2, content.length - 2, StandardCharsets.UTF_16LE);
+ }
+ if (content.length >= 2 && (content[0] & 0xFF) == 0xFE && (content[1] & 0xFF) == 0xFF) {
+ return new String(content, 2, content.length - 2, StandardCharsets.UTF_16BE);
+ }
+ // 娌℃湁 BOM 鏃朵竴寰嬫寜 UTF-8 璇汇�侴BK 鍦ㄨ繖閲屼細琚鎴愪贡鐮侊紝浣嗛偅鏄�岃鍑轰竴鍫嗛棶鍙枫�嶈�屼笉鏄け璐ワ紝
+ // 鐢ㄦ埛鑳戒粠棰勮閲岀湅鍑烘潵锛屾瘮寮鸿鐚滅紪鐮佺寽閿欐洿鍙帶
+ return new String(content, StandardCharsets.UTF_8);
+ }
+
+ private static void appendLine(StringBuilder sb, String line) {
+ if (line != null && !line.isBlank()) {
+ sb.append(line).append('\n');
+ }
+ }
+
+ private static String extractorNameOf(String extension) {
+ return "txt".equals(extension) || "csv".equals(extension) ? "plain-text" : "poi-" + extension;
+ }
+
+ private static boolean startsWith(byte[] content, byte[] prefix) {
+ if (content.length < prefix.length) {
+ return false;
+ }
+ for (int i = 0; i < prefix.length; i++) {
+ if (content[i] != prefix[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static String extensionOf(String filename) {
+ int dot = filename == null ? -1 : filename.lastIndexOf('.');
+ return dot < 0 ? "" : filename.substring(dot + 1).toLowerCase();
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/PdfImportAdapter.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/PdfImportAdapter.java
new file mode 100644
index 0000000..58d4c3e
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/PdfImportAdapter.java
@@ -0,0 +1,146 @@
+package cn.iocoder.yudao.module.qcreport.service.aiimport.document;
+
+import cn.iocoder.yudao.module.qcreport.config.QcReportAiImportProperties;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.pdfbox.Loader;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.rendering.ImageType;
+import org.apache.pdfbox.rendering.PDFRenderer;
+import org.apache.pdfbox.text.PDFTextStripper;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.AI_IMPORT_FILE_EMPTY;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.AI_IMPORT_TOO_MANY_PAGES;
+
+/**
+ * PDF 鎶藉彇鍣紝鍙岄�氶亾銆�
+ * <p>
+ * <b>閫氶亾鍒ゅ畾渚濇嵁鏄�岃繖浠� PDF 鏈夋病鏈夋枃鏈眰銆嶏紝涓嶆槸銆屽畠鏄笉鏄� PDF銆嶃��</b>
+ * 杩欎釜鍖哄埆寰堝疄闄咃細鐢靛瓙鐗� PDF 鎶藉嚭鏂囨湰鍙鍑犲崄 KB銆佽寰椾篃鍑嗭紱鎵弿鐗� PDF 鎶藉嚭鏉ユ槸绌虹殑锛�
+ * 鍙兘鎶婇〉闈㈡覆鏌撴垚鍥句氦缁欏妯℃�佹ā鍨嬧�斺�旀垚鏈珮涓�涓暟閲忕骇锛屼絾杩欐槸鍞竴鑳借鍑哄瓧鐨勫姙娉曘��
+ * 鍒ゆ嵁鏄钩鍧囨瘡椤靛瓧绗︽暟瓒呰繃闃堝�笺��
+ * <p>
+ * 鍒绘剰<b>涓�</b>鍋氭贩鍚堝瀷 PDF 鐨勯�愰〉閫氳矾锛堟湁鐨勯〉鏈夋枃鏈眰銆佹湁鐨勬病鏈夛級锛氶偅闇�瑕佹寜椤靛喅瀹氶�氶亾锛�
+ * 璋冪敤娆℃暟缈诲�嶈�屾敹鐩婂彧鍦ㄥ皯鏁版枃浠朵笂銆傛暣浠芥枃浠舵寜涓�涓�氶亾璧帮紝琛屼负鍙鏈熴��
+ */
+@Slf4j
+@Component
+@Order(2)
+public class PdfImportAdapter implements QcReportImportAdapter {
+
+ @Resource
+ private QcReportAiImportProperties properties;
+
+ @Override
+ public boolean supports(String extension, String contentType) {
+ return "pdf".equals(extension) || "application/pdf".equalsIgnoreCase(contentType);
+ }
+
+ @Override
+ public QcReportDocumentExtract extract(byte[] content, String originalFilename) {
+ if (content == null || content.length == 0) {
+ throw exception(AI_IMPORT_FILE_EMPTY, originalFilename, 0);
+ }
+ try (PDDocument document = Loader.loadPDF(content)) {
+ int pageCount = document.getNumberOfPages();
+ if (pageCount <= 0) {
+ throw exception(AI_IMPORT_FILE_EMPTY, originalFilename, 0);
+ }
+ // 瓒呴檺鐩存帴鎶ラ敊鑰屼笉鏄埅鏂細闈欓粯鎴柇浼氳鐢ㄦ埛浠ヤ负鏁翠唤鏂囦欢閮借瘑鍒繃浜嗭紝
+ // 鎷垮埌鐨勬ā鏉垮皯浜嗗嚑椤靛嵈娌℃湁浠讳綍鎻愮ず锛屾瘮鎶ラ敊鍗遍櫓寰楀
+ if (pageCount > properties.getMaxPagesPerFile()) {
+ throw exception(AI_IMPORT_TOO_MANY_PAGES, originalFilename, pageCount,
+ properties.getMaxPagesPerFile());
+ }
+ List<String> pageTexts = extractPageTexts(document, pageCount);
+ int totalChars = pageTexts.stream().mapToInt(t -> t.replaceAll("\\s", "").length()).sum();
+ int threshold = properties.getPdfTextPageThreshold() * pageCount;
+ if (totalChars >= threshold) {
+ return QcReportDocumentExtract.ofText(joinPages(pageTexts), pageCount, "pdfbox-text", List.of());
+ }
+ // 璧板浘鐗囬�氶亾锛氭妸銆屼负浠�涔堟參/涓轰粈涔堣吹銆嶈娓呮锛岀敤鎴锋墠鐭ラ亾鎹㈢數瀛愮増 PDF 鑳藉揩寰堝
+ return renderPages(document, pageCount, originalFilename,
+ List.of("鏂囦欢銆�" + originalFilename + "銆嶆病鏈夋枃鏈眰锛堝叡 " + pageCount
+ + " 椤碉級锛屽凡鎸夋壂鎻忎欢閫愰〉璇嗗埆锛屼細姣旇緝鎱�"));
+ } catch (IOException e) {
+ log.warn("PDF 瑙f瀽澶辫触锛宖ile={}", originalFilename, e);
+ throw exception(AI_IMPORT_FILE_EMPTY, originalFilename, 0);
+ }
+ }
+
+ /**
+ * 閫愰〉鎶芥枃鏈�傜敤 {@code setSortByPosition(true)} 璁╅槄璇婚『搴忔寜鐗堥潰鍧愭爣鎺掞紝
+ * 鍚﹀垯琛ㄦ牸閲岀殑鏂囧瓧浼氭寜 PDF 鍐呴儴缁樺埗椤哄簭涔卞簭鎶藉嚭锛屾ā鍨嬬湅鍒扮殑鍒楀氨閿欎綅浜嗐��
+ */
+ private List<String> extractPageTexts(PDDocument document, int pageCount) throws IOException {
+ List<String> pageTexts = new ArrayList<>(pageCount);
+ for (int i = 0; i < pageCount; i++) {
+ PDFTextStripper stripper = new PDFTextStripper();
+ stripper.setSortByPosition(true);
+ stripper.setStartPage(i + 1);
+ stripper.setEndPage(i + 1);
+ pageTexts.add(stripper.getText(document).trim());
+ }
+ return pageTexts;
+ }
+
+ private String joinPages(List<String> pageTexts) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < pageTexts.size(); i++) {
+ if (i > 0) {
+ sb.append("\n--- 绗� ").append(i + 1).append(" 椤� ---\n");
+ }
+ sb.append(pageTexts.get(i));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * 閫愰〉娓叉煋鎴� PNG銆�
+ * <p>
+ * 娓叉煋澶辫触涓嶅悶锛氬洖钀藉幓璇曟枃鏈�氶亾锛屼袱鏉¤矾閮戒笉閫氭墠鎶ャ�屾湭瑙f瀽鍑轰换浣曞彲鐢ㄥ唴瀹广�嶃��
+ * 涔嬫墍浠ヨ鍥炶惤锛屾槸鍥犱负銆屽瓧绗︽暟浣庝簬闃堝�笺�嶅彲鑳藉彧鏄枃浠剁敤鐨勫瓧浣撴病甯� ToUnicode 琛�
+ * 锛堟娊鍑烘潵鏄贡鐮佹垨绌猴級锛屼絾娓叉煋鏈韩杩樻槸濂界殑鈥斺�斾笉杩囬偅绉嶆儏鍐典笅鍥炶惤鍙栧埌鐨勬枃鏈篃鏄┖鐨勶紝
+ * 鎵�浠ョ湡姝d細钀藉埌 {@link #extractPageTexts} 鐨勫満鏅槸娓叉煋鍣ㄥ杩欎釜鏂囦欢涓嶅伐浣溿��
+ */
+ private QcReportDocumentExtract renderPages(PDDocument document, int pageCount,
+ String originalFilename, List<String> notes) {
+ List<QcReportDocumentExtract.ImagePart> images = new ArrayList<>(pageCount);
+ try {
+ PDFRenderer renderer = new PDFRenderer(document);
+ for (int i = 0; i < pageCount; i++) {
+ BufferedImage image = renderer.renderImageWithDPI(i, properties.getRenderDpi(), ImageType.RGB);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ImageIO.write(image, "png", out);
+ images.add(new QcReportDocumentExtract.ImagePart(
+ out.toByteArray(), "image/png", "绗� " + (i + 1) + " 椤�"));
+ }
+ return QcReportDocumentExtract.ofImages(images, pageCount, "pdfbox-render", notes);
+ } catch (IOException | RuntimeException e) {
+ log.warn("PDF 娓叉煋鎵弿椤靛け璐ワ紝灏濊瘯鍥炶惤鏂囨湰閫氶亾锛宖ile={}", originalFilename, e);
+ try {
+ List<String> pageTexts = extractPageTexts(document, pageCount);
+ if (pageTexts.stream().anyMatch(t -> !t.isBlank())) {
+ List<String> fallbackNotes = new ArrayList<>(notes);
+ fallbackNotes.add("鏂囦欢銆�" + originalFilename + "銆嶇殑椤甸潰鏃犳硶娓叉煋鎴愬浘鐗囷紝宸叉敼涓鸿鍙栧叾鏂囨湰灞�");
+ return QcReportDocumentExtract.ofText(joinPages(pageTexts), pageCount,
+ "pdfbox-text-fallback", fallbackNotes);
+ }
+ } catch (IOException ignored) {
+ // 鍥炶惤涔熻涓嶅嚭鏉ワ紝璧颁笅闈㈢殑缁熶竴鎶ラ敊
+ }
+ throw exception(AI_IMPORT_FILE_EMPTY, originalFilename, pageCount);
+ }
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/QcReportDocumentExtract.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/QcReportDocumentExtract.java
new file mode 100644
index 0000000..e0cd638
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/QcReportDocumentExtract.java
@@ -0,0 +1,83 @@
+package cn.iocoder.yudao.module.qcreport.service.aiimport.document;
+
+import java.util.List;
+
+/**
+ * 涓�涓枃浠惰閫傞厤鍣ㄦ娊鍙栧悗鐨勪腑闂寸粨鏋溿��
+ * <p>
+ * <b>鍒绘剰涓嶆槸鏍戙�佷篃涓嶆槸 HTML</b>锛氬畠鍙槸銆岃繖浠芥枃浠惰兘浜ょ粰妯″瀷鐨勪笢瑗挎槸浠�涔堛�嶈繖涓洿灏忕殑闂鐨勭瓟妗堛��
+ * 鏍戣琛ㄨ揪鐗堝紡锛孒TML 瑕佽〃杈炬牱寮忥紝涓よ�呴兘浼氭妸銆屾ā鍨嬭兘鐪嬭浠�涔堛�嶆斁澶у埌涓嶅彲鎺э紱杩欓噷鍙暀涓や釜閫氶亾锛�
+ * 杩娇涓嬫父锛堟彁绀鸿瘝鏋勯�犮�佽皟鐢ㄨ鍒掞級涓嶅繀鍐嶈�冭檻绗笁绉嶅舰鎬併��
+ *
+ * <h3>涓轰粈涔堟槸鍙岄�氶亾鑰屼笉鏄竴绉�</h3>
+ * 鐢靛瓙鐗� PDF / Word / Excel 鏈夌湡瀹炴枃鏈眰锛屾娊鍙栨垚瀛楃涓叉渶鐪� token锛屾ā鍨嬩篃璇诲緱鏈�鍑嗭紱
+ * 鎵弿浠朵笌鐓х墖娌℃湁鏂囨湰灞傦紝鍙兘鎶婇〉闈㈡覆鏌撴垚鍥句氦缁欏妯℃�佹ā鍨嬨��
+ * 杩欎袱鏉¤矾鐨勮皟鐢ㄦ柟寮忥紙{@code chat} 涓� {@code chatWithImage}锛夈�佽璐瑰彛寰勩�佸け璐ユā寮忛兘涓嶅悓锛�
+ * 鎵�浠ュ繀椤诲湪绫诲瀷涓婂垎寮�锛岃�屼笉鏄杩涗竴涓瓧娈甸噷闈犵寽銆�
+ *
+ * @param channel 閫氶亾绫诲瀷锛岃 {@link Channel}
+ * @param text TEXT 閫氶亾鐨勬鏂囷紝澶氶〉鏃堕〉闂翠互 {@code --- 绗� N 椤� ---} 鍒嗛殧锛汭MAGES 閫氶亾鎭掍负绌轰覆
+ * @param images IMAGES 閫氶亾鐨勫浘鐗囷紝姣忛〉涓�寮狅紱TEXT 閫氶亾鎭掍负绌哄垪琛�
+ * @param pageCount 椤垫暟锛岀敤浜庤秴闄愭牎楠屼笌鎻愮ず鏂囨
+ * @param extractor 瀹為檯鐢熸晥鐨勬娊鍙栧櫒鏍囪瘑锛堝 {@code pdfbox-text}锛夛紝浼氬啓杩涙棩蹇椾究浜庢帓鏌�
+ * @param notes 鎶藉彇闃舵鐨勮蒋鎻愮ず锛岀洿鎺ヨ繘鍝嶅簲鐨� warnings 灞曠ず缁欑敤鎴�
+ */
+public record QcReportDocumentExtract(
+ Channel channel,
+ String text,
+ List<ImagePart> images,
+ int pageCount,
+ String extractor,
+ List<String> notes) {
+
+ /**
+ * 绾靛悜鍚堝苟缁牸鐨勫崰浣嶆爣璁般��
+ * <p>
+ * 瀹冨睘浜庛�屾娊鍙栧嚭鏉ョ殑鏂囨湰闀夸粈涔堟牱銆嶈繖鏉″绾︼紝鎵�浠ュ拰 {@code text} 鏀惧湪涓�澶勶紝
+ * 鐢辩敓浜ц�咃紙{@link OfficeImportAdapter}锛変笌瑙i噴鑰咃紙{@code QcReportTemplatePromptBuilder}锛�
+ * 鍏辩敤涓�浠斤紝閬垮厤涓よ竟鍚勫啓涓�涓瓧闈㈤噺鍚庡悇鑷紓绉汇��
+ * <p>
+ * 涓轰粈涔堜笉鑳界暀绌猴細{@code w:vMerge} 鐨勭画鏍煎湪 Word 閲岃〃绀恒�岃繖涓�鏍间笌涓婁竴琛屾槸鍚屼竴涓�笺�嶏紝
+ * 浣� POI 鍙栧嚭鏉ュ氨鏄┖涓层�傜暀绌虹殑璇濓紝妯″瀷鍖哄垎涓嶅嚭銆屽悎骞剁画鏍笺�嶄笌銆屽師浠舵湰鏉ュ氨娌″~銆嶏紝
+ * 浜庢槸鏁村紶琛ㄧ湅璧锋潵鏄竴灞傚钩閾虹殑妫�楠岄」锛岀湅涓嶅嚭鍒嗙粍缁撴瀯銆�
+ */
+ public static final String VERTICAL_MERGE_MARK = "鈫戝悓涓�";
+
+ /**
+ * 鎶藉彇閫氶亾銆�
+ */
+ public enum Channel {
+ /** 鏈夋枃鏈眰锛屾暣浠芥枃浠舵嫾鎴愪竴娈垫枃鏈紝涓�娆℃ā鍨嬭皟鐢� */
+ TEXT,
+ /** 鏃犳枃鏈眰锛堟壂鎻忎欢/鐓х墖锛夛紝閫愰〉杞浘锛屾瘡椤典竴娆℃ā鍨嬭皟鐢� */
+ IMAGES
+ }
+
+ /**
+ * IMAGES 閫氶亾閲岀殑涓�椤靛浘銆�
+ *
+ * @param bytes 鍥剧墖瀛楄妭锛屾墽琛屽櫒璐熻矗杞垚瑁� base64
+ * @param mimeType 褰㈠ {@code image/png} 鐨勮8绫诲瀷锛屼笉甯� {@code data:} 鍓嶇紑
+ * @param label 椤垫爣绛撅紝鐢ㄤ簬鎷奸敊璇笌鎻愮ず鏂囨锛屼緥濡傘�屾壂鎻忎欢.pdf 绗� 2 椤点��
+ */
+ public record ImagePart(byte[] bytes, String mimeType, String label) {
+ }
+
+ /**
+ * 鏂囨湰閫氶亾鐨勫伐鍘傘�倇@code notes} 鍏佽涓虹┖琛ㄧず娌℃湁杞彁绀恒��
+ */
+ public static QcReportDocumentExtract ofText(String text, int pageCount, String extractor,
+ List<String> notes) {
+ return new QcReportDocumentExtract(Channel.TEXT, text, List.of(), pageCount, extractor, notes);
+ }
+
+ /**
+ * 鍥剧墖閫氶亾鐨勫伐鍘傘��
+ */
+ public static QcReportDocumentExtract ofImages(List<ImagePart> images, int pageCount,
+ String extractor, List<String> notes) {
+ return new QcReportDocumentExtract(Channel.IMAGES, "", List.copyOf(images), pageCount,
+ extractor, notes);
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/QcReportDocumentExtractService.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/QcReportDocumentExtractService.java
new file mode 100644
index 0000000..792f4b8
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/QcReportDocumentExtractService.java
@@ -0,0 +1,52 @@
+package cn.iocoder.yudao.module.qcreport.service.aiimport.document;
+
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.AI_IMPORT_FILE_UNSUPPORTED;
+
+/**
+ * 鎶藉彇闂ㄩ潰锛氭寜鍥哄畾椤哄簭鎵剧涓�涓兘澶勭悊璇ユ枃浠剁殑閫傞厤鍣ㄣ��
+ * <p>
+ * 椤哄簭鐢卞悇閫傞厤鍣ㄧ殑 {@code @Order} 鍐冲畾锛堝浘鐗� 鈫� PDF 鈫� Office锛夛紝涓嶆槸銆岃皝鏇村悎閫傘�嶇殑鎷╀紭锛�
+ * 鑰屾槸娑堥櫎姝т箟鐨勫畾搴忋�傜湡瀹炵殑姝т箟鏄� PDF锛氬畠鏃㈠彲鑳借 PDF 閫傞厤鍣ㄨ棰嗭紝
+ * 涔熷彲鑳藉洜涓� {@code contentType} 涓婃姤鎴� {@code application/pdf} 涔嬪鐨勬��艰�岃惤鍒� Office 鐨勫厹搴曞垽鏂笂锛�
+ * 瀹氬簭涔嬪悗璋佸厛璋佸悗鏄‘瀹氱殑锛屼笉浼氶殢 Bean 娉ㄥ唽椤哄簭婕傜Щ銆�
+ * <p>
+ * 鍙仛鍒嗗彂锛屼笉鍋氥�岃涓嶅嚭鏉ュ氨鎹釜閫傞厤鍣ㄥ啀璇曘�嶇殑鍏滃簳鈥斺�旀瘡涓�傞厤鍣ㄥ唴閮ㄥ凡缁忔妸璇ヨ瘯鐨勮矾寰勮瘯杩囦簡
+ * 锛圥DF 鐨勬覆鏌撳け璐ヤ細鍥炶惤鏂囨湰閫氶亾锛夛紝鍦ㄨ繖閲屽啀鍙犱竴灞傚彧浼氳澶辫触鍘熷洜鍙樺緱璇翠笉娓呫��
+ */
+@Service
+public class QcReportDocumentExtractService {
+
+ @Resource
+ private List<QcReportImportAdapter> adapters;
+
+ /**
+ * 鎶藉彇鏂囦欢鍐呭銆�
+ *
+ * @param content 鏂囦欢瀛楄妭
+ * @param originalFilename 鍘熷鏂囦欢鍚嶏紙鍚墿灞曞悕锛�
+ * @param contentType 涓婁紶鏃惰褰曠殑 MIME 绫诲瀷锛屽彲鑳戒负 null
+ * @throws cn.iocoder.yudao.framework.common.exception.ServiceException 娌℃湁閫傞厤鍣ㄨ棰嗚鏍煎紡鏃�
+ */
+ public QcReportDocumentExtract extract(byte[] content, String originalFilename, String contentType) {
+ String extension = extensionOf(originalFilename);
+ for (QcReportImportAdapter adapter : adapters) {
+ if (adapter.supports(extension, contentType)) {
+ return adapter.extract(content, originalFilename);
+ }
+ }
+ throw exception(AI_IMPORT_FILE_UNSUPPORTED, originalFilename,
+ extension.isBlank() ? "鏃�" : "." + extension);
+ }
+
+ private static String extensionOf(String filename) {
+ int dot = filename == null ? -1 : filename.lastIndexOf('.');
+ return dot < 0 ? "" : filename.substring(dot + 1).toLowerCase();
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/QcReportImportAdapter.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/QcReportImportAdapter.java
new file mode 100644
index 0000000..2aa4b83
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/QcReportImportAdapter.java
@@ -0,0 +1,36 @@
+package cn.iocoder.yudao.module.qcreport.service.aiimport.document;
+
+/**
+ * 涓�绉嶈緭鍏ユ牸寮忕殑鎶藉彇鍣ㄣ��
+ * <p>
+ * 涔嬫墍浠ュ仛閫傞厤鍣ㄨ�屼笉鏄湪涓�涓ぇ绫婚噷 {@code switch (extension)}锛氫笁绫昏緭鍏ョ殑鎶芥硶姣棤鍏卞悓鐐�
+ * 锛堝浘鐗囦粈涔堥兘涓嶇敤鍋氥�丳DF 瑕佸厛鍒ゆ柇鏈夋病鏈夋枃鏈眰銆丱ffice 瑕佹寜鏍煎紡瑙f瀽琛ㄦ牸锛夛紝
+ * 濉炶繘涓�涓被浼氬緱鍒颁竴涓棦璇讳笉浜嗕篃鏀逛笉鍔ㄧ殑鍒嗘敮濉斻��
+ * <p>
+ * 瀹炵幇鎸� {@code @Order} 鍥哄畾椤哄簭鎺掑垪锛岄棬闈㈠彇<b>绗竴涓�</b> {@link #supports} 涓虹湡鐨勨�斺��
+ * 椤哄簭鍥哄畾鏄负浜嗘秷闄ゆ涔夛紙PDF 鍙兘鍚屾椂琚� PDF 閫傞厤鍣ㄥ拰 Office 閫傞厤鍣ㄣ�岃棰嗐�嶏級锛�
+ * 鑰屼笉鏄负浜嗘嫨浼樸��
+ */
+public interface QcReportImportAdapter {
+
+ /**
+ * 鏄惁鑳藉鐞嗚繖涓枃浠躲��
+ *
+ * @param extension 灏忓啓銆佸幓鐐圭殑鎵╁睍鍚嶏紝濡� {@code pdf}锛涙病鏈夋墿灞曞悕鏃朵负绌轰覆
+ * @param contentType 娴忚鍣ㄤ笂鎶ョ殑 MIME 绫诲瀷锛屽彲鑳戒负 null锛堟湰鍦版枃浠跺父瑙侊級
+ */
+ boolean supports(String extension, String contentType);
+
+ /**
+ * 鎶藉彇銆�
+ * <p>
+ * 涓嶅仛銆岃繑鍥� null 琛ㄧず澶辫触銆嶈繖绉嶇害瀹氾細璇讳笉鍑哄唴瀹广�佹牸寮忎笉鏀寔銆侀〉鏁拌秴闄愰兘鏄�**纭畾鐨勫け璐ュ師鍥�**锛�
+ * 鍚勮嚜瀵瑰簲涓�涓敊璇爜锛岃鐢ㄦ埛鐭ラ亾涓嬩竴姝ヨ鍋氫粈涔堬紙鎹釜鏍煎紡 / 鎷嗛〉 / 閲嶆柊鎵弿锛夈��
+ *
+ * @param content 鏂囦欢瀛楄妭
+ * @param originalFilename 鍘熷鏂囦欢鍚嶏紝鐢ㄤ簬閿欒涓庢彁绀烘枃妗�
+ * @return 鎶藉彇缁撴灉
+ */
+ QcReportDocumentExtract extract(byte[] content, String originalFilename);
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportAiDraftNormalizer.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportAiDraftNormalizer.java
new file mode 100644
index 0000000..91d27fd
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportAiDraftNormalizer.java
@@ -0,0 +1,227 @@
+package cn.iocoder.yudao.module.qcreport.service.aiimport.llm;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
+import cn.iocoder.yudao.module.qcreport.controller.admin.aiimport.vo.QcReportAiDraftRespVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.aiimport.vo.QcReportComponentSpecVO;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+/**
+ * 鎶婃ā鍨嬭В鏋愬嚭鏉ョ殑鑽夌褰掍竴鎴愩�屽彧鍚悎娉曠粍浠躲�佸悎娉曞睘鎬с�嶇殑娓呭崟銆�
+ * <p>
+ * 涓夌骇闃茬嚎鐨勭涓夌骇锛屼篃鏄棦鏈夎寖寮忥紙ERP / CRM / MES 鐨� AI 璋冪敤锛�<b>娌℃湁</b>鐨勪竴娈点��
+ * 閭d笁澶勬槸鎵佸钩鍗曞眰缁撴瀯銆佸瓧娈靛啓姝诲湪浠g爜閲岋紝閿欎簡灏辨槸閿欎簡锛涜繖娆¤鍠傜粰涓嶅彲淇$殑妯″瀷鍘讳骇鍑哄祵濂楃粨鏋勶紝
+ * 灏戣繖涓�灞傚氨浼氬嚭鐜般�屾ā鍨嬬紪浜嗕釜缁勪欢绫诲瀷锛屽墠绔閰嶅櫒璺宠繃瀹冿紝鐢ㄦ埛鐪嬪埌鐨勭敾甯冨拰棰勮瀵逛笉涓娿�嶃��
+ *
+ * <h3>鍘熷垯锛氬崟涓厓绱犲潖鎺変笉鑳借鏁翠釜璇锋眰澶辫触</h3>
+ * 鍧忓厓绱犺繘 warnings銆佸叾浣欑殑鐓у父杩斿洖銆傛暣浣撳け璐ュ彧鍦ㄦ湇鍔″眰鍒ゆ柇锛堟渶缁堜竴椤归兘涓嶅墿 鈫� DRAFT_EMPTY锛夛紝
+ * 鍥犱负銆屽ぇ閮ㄥ垎璇嗗埆瀵逛簡銆嶅拰銆屽叏閮芥病璇嗗埆鍑烘潵銆嶅鐢ㄦ埛鐨勫惈涔夊畬鍏ㄤ笉鍚屻��
+ *
+ * <h3>涓轰粈涔堝悗绔篃瑕佽繃婊や竴閬嶏紙鍓嶇瑁呴厤鍣ㄥ凡缁忚繃婊や簡锛�</h3>
+ * 鍓嶇杩囨护鍙戠敓鍦ㄨ閰嶉偅涓�鍒伙紝鐢ㄦ埛鐪嬪埌鐨勬槸銆屾垜涓婁紶浜� 5 涓粍浠讹紝鐢诲竷涓婂彧鍑烘潵 3 涓�嶁�斺�旀病鏈夎В閲娿��
+ * 鍚庣鍦ㄩ瑙堥樁娈靛氨鎶娿�屽摢涓�椤硅涓簡銆佷负浠�涔堛�嶈鍑烘潵锛岀敤鎴锋墠鐭ラ亾璇ヨˉ浠�涔堛��
+ * 杩欎笉鏄噸澶嶉槻绾匡紝鏄妸闈欓粯澶辫触鍙樻垚鍙澶辫触銆�
+ */
+public class QcReportAiDraftNormalizer {
+
+ private QcReportAiDraftNormalizer() {
+ }
+
+ /**
+ * 褰掍竴缁撴灉銆�
+ *
+ * @param components 杩囨护鍚庣殑缁勪欢锛屽彲鑳戒负绌猴紙绌虹殑鏈�缁堢敱鏈嶅姟灞傛姤 DRAFT_EMPTY锛�
+ * @param warnings 闇�瑕佸睍绀虹粰鐢ㄦ埛鐨勮蒋鎻愮ず
+ */
+ public record Result(List<QcReportAiDraftRespVO.DraftComponent> components, List<String> warnings) {
+ }
+
+ /**
+ * 褰掍竴涓�娆℃ā鍨嬪洖澶嶅緱鍒扮殑缁勪欢銆�
+ *
+ * @param raw 瑙f瀽鍑烘潵鐨勫師濮嬬粍浠讹紝鍏佽鍚� null 鍏冪礌
+ * @param catalog 鍙敤缁勪欢娓呭崟锛屽喅瀹氬摢浜� type 涓� prop key 鍚堟硶
+ * @param sourceLabel 鏉ユ簮鏍囩锛堟枃浠跺悕 / 鏂囦欢鍚�+椤电爜锛夛紝浼氭嫾杩涙彁绀烘枃妗�
+ */
+ public static Result normalize(List<QcReportAiDraftRespVO.DraftComponent> raw,
+ List<QcReportComponentSpecVO> catalog,
+ String sourceLabel) {
+ Map<String, QcReportComponentSpecVO> specByType = new TreeMap<>();
+ for (QcReportComponentSpecVO spec : catalog) {
+ if (spec != null && StrUtil.isNotBlank(spec.getType())) {
+ specByType.put(spec.getType(), spec);
+ }
+ }
+ List<QcReportAiDraftRespVO.DraftComponent> kept = new ArrayList<>();
+ List<String> warnings = new ArrayList<>();
+ String prefix = StrUtil.isBlank(sourceLabel) ? "" : sourceLabel + "锛�";
+
+ if (raw == null) {
+ return new Result(kept, warnings);
+ }
+ for (int i = 0; i < raw.size(); i++) {
+ QcReportAiDraftRespVO.DraftComponent item = raw.get(i);
+ int no = i + 1;
+ if (item == null) {
+ warnings.add(prefix + "绗� " + no + " 椤逛笉鏄竴涓湁鏁堢殑缁勪欢瀵硅薄锛屽凡蹇界暐");
+ continue;
+ }
+ String type = item.getType();
+ if (StrUtil.isBlank(type)) {
+ warnings.add(prefix + "绗� " + no + " 椤圭己灏戠粍浠剁被鍨嬶紝宸插拷鐣�");
+ continue;
+ }
+ QcReportComponentSpecVO spec = specByType.get(type);
+ if (spec == null) {
+ warnings.add(prefix + "AI 杈撳嚭浜嗙粍浠舵竻鍗曞鐨勭粍浠剁被鍨嬨��" + type + "銆嶏紝宸插拷鐣�");
+ continue;
+ }
+ Map<String, Object> props = item.getProps();
+ if (props == null || props.isEmpty()) {
+ warnings.add(prefix + "缁勪欢銆�" + displayName(spec) + "銆嶆湭璇嗗埆鍑轰换浣曞睘鎬э紝宸插拷鐣�");
+ continue;
+ }
+ Map<String, Object> filtered = filterProps(props, spec, prefix, warnings);
+ if (filtered.isEmpty()) {
+ warnings.add(prefix + "缁勪欢銆�" + displayName(spec)
+ + "銆嶇殑灞炴�ч兘涓嶅湪娓呭崟澹版槑鑼冨洿鍐咃紝宸插拷鐣�");
+ continue;
+ }
+ warnMissingRequired(filtered, spec, prefix, warnings);
+ QcReportAiDraftRespVO.DraftComponent draft = new QcReportAiDraftRespVO.DraftComponent();
+ draft.setType(type);
+ draft.setProps(filtered);
+ kept.add(draft);
+ }
+ return new Result(kept, warnings);
+ }
+
+ /**
+ * 鍚堝苟澶氭璋冪敤鐨勭粨鏋滃苟鍘婚噸锛屾渶鍚庢寜涓婇檺鎴柇銆�
+ * <p>
+ * 鍘婚噸鏄椤垫壂鎻忎欢鐨勫繀闇�鍝侊細椤电湁銆佹姤鍛婃爣棰樸�佽〃澶村湪姣忎竴椤甸兘浼氬嚭鐜帮紝閫愰〉璇嗗埆灏变細寰楀埌 N 浠斤紝
+ * 涓嶅幓閲嶇殑璇濈敾甯冧笂浼氭湁 5 涓竴鏍风殑鎶ご銆傚垽瀹氬悓涓�鏄�
+ * {@code (type, props 鐨勭ǔ瀹� JSON)}鈥斺�攑rops 鍏堟寜 key 鎺掑簭锛屽洜涓轰笉鍚岄〉杩斿洖鐨� key 椤哄簭
+ * 涓嶄繚璇佷竴鑷达紝鐩存帴姣斿師濮嬮『搴忎細鎶婂悓涓�涓粍浠跺綋鎴愪袱涓��
+ *
+ * @param perCallResults 鍚勬璋冪敤褰掍竴鍚庣殑缁撴灉锛屾寜鎵ц椤哄簭
+ * @param maxComponents 缁勪欢鎬绘暟涓婇檺锛岃秴鍑烘埅鏂�
+ */
+ public static Result mergeAndDedup(List<Result> perCallResults, int maxComponents) {
+ List<QcReportAiDraftRespVO.DraftComponent> merged = new ArrayList<>();
+ Set<String> seen = new LinkedHashSet<>();
+ for (Result result : perCallResults) {
+ for (QcReportAiDraftRespVO.DraftComponent component : result.components()) {
+ if (seen.add(dedupKey(component))) {
+ merged.add(component);
+ }
+ }
+ }
+ int total = merged.size();
+ List<String> warnings = new ArrayList<>();
+ for (Result result : perCallResults) {
+ warnings.addAll(result.warnings());
+ }
+ if (perCallResults.size() > 1 && total < countRaw(perCallResults)) {
+ warnings.add(StrUtil.format(
+ "澶氶〉璇嗗埆鍏卞緱鍒� {} 椤圭粍浠讹紝鍏朵腑鏈� {} 椤瑰湪鍏跺畠椤靛凡鍑虹幇锛堥〉鐪夈�佹爣棰樸�佽〃澶寸瓑閲嶅鍐呭锛夛紝宸插悎骞�",
+ countRaw(perCallResults), countRaw(perCallResults) - total));
+ }
+ if (maxComponents > 0 && total > maxComponents) {
+ warnings.add(StrUtil.format("璇嗗埆鍑虹殑缁勪欢鍏� {} 椤癸紝瓒呰繃鍗曟涓婇檺 {} 椤癸紝宸蹭繚鐣欏墠 {} 椤癸紝鍏朵綑璇锋墜宸ヨˉ鍏�",
+ total, maxComponents, maxComponents));
+ merged = new ArrayList<>(merged.subList(0, maxComponents));
+ }
+ return new Result(merged, warnings);
+ }
+
+ private static int countRaw(List<Result> results) {
+ return results.stream().mapToInt(r -> r.components().size()).sum();
+ }
+
+ /**
+ * 涓㈡帀娓呭崟鏈0鏄庣殑 prop key銆�
+ * <p>
+ * {@code fields} 涓� <b>null</b>锛堟竻鍗曞帇鏍规病澹版槑锛変笌涓� <b>绌哄垪琛�</b>锛堟槑纭0鏄庛�岃繖涓粍浠朵笉鍚冧换浣曞睘鎬с�嶏級
+ * 鏄袱鍥炰簨锛氬墠鑰呮棤浠庡垽鏂紝鍘熸牱鏀捐锛涘悗鑰呮墠鏄湡鐨勮涓�涓釜涓㈡帀銆�
+ * 娣蜂负涓�璋堜細鍦ㄥ墠绔紡浼� fields 鏃舵妸鐢ㄦ埛璇嗗埆鍑烘潵鐨勫睘鎬ч潤榛樻姽骞炽��
+ */
+ private static Map<String, Object> filterProps(Map<String, Object> props, QcReportComponentSpecVO spec,
+ String prefix, List<String> warnings) {
+ if (spec.getFields() == null) {
+ return props;
+ }
+ Set<String> allowed = new LinkedHashSet<>();
+ for (QcReportComponentSpecVO.Field field : spec.getFields()) {
+ if (field != null && StrUtil.isNotBlank(field.getKey())) {
+ allowed.add(field.getKey());
+ }
+ }
+ Map<String, Object> filtered = new TreeMap<>();
+ List<String> dropped = new ArrayList<>();
+ for (Map.Entry<String, Object> entry : props.entrySet()) {
+ if (allowed.contains(entry.getKey())) {
+ filtered.put(entry.getKey(), entry.getValue());
+ } else {
+ dropped.add(entry.getKey());
+ }
+ }
+ if (!dropped.isEmpty()) {
+ warnings.add(prefix + "缁勪欢銆�" + displayName(spec) + "銆嶄腑涓嶅睘浜庤缁勪欢鐨勫睘鎬� "
+ + String.join("銆�", dropped) + " 宸蹭涪寮�");
+ }
+ return filtered;
+ }
+
+ private static void warnMissingRequired(Map<String, Object> props, QcReportComponentSpecVO spec,
+ String prefix, List<String> warnings) {
+ if (spec.getFields() == null) {
+ return;
+ }
+ for (QcReportComponentSpecVO.Field field : spec.getFields()) {
+ if (field == null || !Boolean.TRUE.equals(field.getRequired())) {
+ continue;
+ }
+ if (isBlankValue(props.get(field.getKey()))) {
+ warnings.add(prefix + "缁勪欢銆�" + displayName(spec) + "銆嶇己灏戝繀濉睘鎬с��"
+ + fieldLabel(field) + "銆嶏紝璇峰湪璁捐鍣ㄥ睘鎬ч潰鏉夸腑琛ヤ笂鍚庡啀淇濆瓨");
+ }
+ }
+ }
+
+ private static boolean isBlankValue(Object value) {
+ if (value == null) {
+ return true;
+ }
+ if (value instanceof CharSequence cs) {
+ return StrUtil.isBlank(cs.toString());
+ }
+ return value instanceof Collection<?> collection && collection.isEmpty();
+ }
+
+ /**
+ * 鍘婚噸閿細type + props 鐨勭ǔ瀹氬簭鍒楀寲銆�
+ * <p>
+ * props 鍏堟寜 key 鎺掑簭鍐嶇敤 {@link TreeMap}锛屼繚璇併�屽悓鏍风殑缁勪欢銆佷笉鍚岀殑 key 椤哄簭銆嶄篃鑳藉垽涓哄悓涓�涓��
+ */
+ private static String dedupKey(QcReportAiDraftRespVO.DraftComponent component) {
+ Map<String, Object> props = component.getProps();
+ return component.getType() + "" + JSONUtil.toJsonStr(props == null ? Map.of() : new TreeMap<>(props));
+ }
+
+ private static String displayName(QcReportComponentSpecVO spec) {
+ return StrUtil.isNotBlank(spec.getLabel()) ? spec.getLabel() : spec.getType();
+ }
+
+ private static String fieldLabel(QcReportComponentSpecVO.Field field) {
+ return StrUtil.isNotBlank(field.getLabel()) ? field.getLabel() : field.getKey();
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportAiDraftParser.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportAiDraftParser.java
new file mode 100644
index 0000000..e1cfdd0
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportAiDraftParser.java
@@ -0,0 +1,140 @@
+package cn.iocoder.yudao.module.qcreport.service.aiimport.llm;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import cn.iocoder.yudao.module.qcreport.controller.admin.aiimport.vo.QcReportAiDraftRespVO;
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.version.ReportTemplateSchema;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.AI_IMPORT_RESPONSE_UNPARSEABLE;
+
+/**
+ * 鎶婃ā鍨嬪洖澶嶇殑瀛楃涓茶В鏋愭垚鑽夌銆�
+ * <p>
+ * 涓夌骇闃茬嚎閲岀殑绗竴銆佷簩绾э細<b>鍒囩墖</b>锛堟嬁绗竴涓� {@code {} 鍒版渶鍚庝竴涓� {@code }}锛�
+ * 澶╃劧澶勭悊 markdown 鍥存爮涓庡墠鍚庡瘨鏆勶級+ <b>鍙嶅簭鍒楀寲</b>銆�
+ * 绗笁绾с�屽綊涓�銆嶅湪 {@link QcReportAiDraftNormalizer}銆�
+ * <p>
+ * 鐢ㄥ瓧绗︿覆鍒囩墖鑰屼笉鏄妯″瀷杈撳嚭涓ユ牸 JSON锛屾槸鍥犱负鏈」鐩粠 {@code -api} 澶熶笉鐫� Spring AI 鐨�
+ * {@code BeanOutputConverter}锛坽@code ChatClient} / {@code ChatModel} 閮藉湪 {@code yudao-module-ai}
+ * 鍐呴儴锛夛紝鍙兘璧拌繖鏉¤矾鈥斺�旇繖鏄棦鏈夎寖寮忥紝涓嶆槸鍋锋噿銆�
+ * <p>
+ * <b>杩欎竴灞備笉鍋氫换浣曡繃婊�</b>锛氭ā鍨嬬粰浠�涔堝氨瑙f瀽鍑轰粈涔堬紝鍚堟硶鎬у垽鏂叏閮ㄧ暀缁欏綊涓�鍣紝
+ * 杩欐牱銆岃В鏋愬け璐ャ�嶄笌銆岃В鏋愭垚鍔熶絾鍐呭涓嶅悎瑙勩�嶆槸涓や欢鍙垎杈ㄧ殑浜嬶紝閿欒鐮佷篃鎵嶅垎寰楀紑銆�
+ */
+public class QcReportAiDraftParser {
+
+ /** 鍥炲~ {@code rawText} 鏃剁殑鎴柇闀垮害锛氬鎺掓煡锛屽張涓嶄細鎶婃暣娈靛洖澶嶇亴杩涘搷搴斾綋 */
+ private static final int RAW_TEXT_LIMIT = 4000;
+
+ private QcReportAiDraftParser() {
+ }
+
+ /**
+ * 瑙f瀽妯″瀷鍥炲銆�
+ *
+ * @param aiResponse 妯″瀷鍘熷鍥炲
+ * @return 鏈繃婊ょ殑鑽夌锛岃嚦灏� components 瀛楁闈� null
+ * @throws cn.iocoder.yudao.framework.common.exception.ServiceException 瀹屽叏瑙f瀽涓嶅嚭 JSON 瀵硅薄鏃�
+ */
+ public static QcReportAiDraftRespVO parse(String aiResponse) {
+ String sliced = sliceJsonObject(aiResponse);
+ JSONObject json;
+ try {
+ json = JSONUtil.parseObj(sliced);
+ } catch (Exception e) {
+ throw exception(AI_IMPORT_RESPONSE_UNPARSEABLE, StrUtil.length(aiResponse));
+ }
+ QcReportAiDraftRespVO resp = new QcReportAiDraftRespVO();
+ resp.setSummary(json.getStr("summary"));
+ resp.setComponents(readComponents(json));
+ resp.setPage(readPage(json));
+ return resp;
+ }
+
+ /**
+ * 鏁翠綋瑙f瀽澶辫触鏃跺洖濉粰鍓嶇鐨勬埅鏂師鏂囷紝渚夸簬鎺掓煡妯″瀷鍒板簳杩斿洖浜嗕粈涔堛��
+ */
+ public static String truncate(String raw) {
+ if (raw == null) {
+ return null;
+ }
+ return raw.length() <= RAW_TEXT_LIMIT ? raw : raw.substring(0, RAW_TEXT_LIMIT) + "鈥︼紙宸叉埅鏂級";
+ }
+
+ /**
+ * 鍙栫涓�涓� <code>{</code> 鍒版渶鍚庝竴涓� <code>}</code>銆�
+ */
+ private static String sliceJsonObject(String aiResponse) {
+ if (StrUtil.isBlank(aiResponse)) {
+ throw exception(AI_IMPORT_RESPONSE_UNPARSEABLE, 0);
+ }
+ int start = aiResponse.indexOf('{');
+ int end = aiResponse.lastIndexOf('}');
+ if (start < 0 || end <= start) {
+ throw exception(AI_IMPORT_RESPONSE_UNPARSEABLE, aiResponse.length());
+ }
+ return aiResponse.substring(start, end + 1);
+ }
+
+ /**
+ * 璇� components 鏁扮粍銆�
+ * <p>
+ * 瀹瑰繊妯″瀷鎶婃暟缁勪簩娆$紪鐮佹垚瀛楃涓诧紙銆屽洖澶嶉噷濂椾竴灞� JSON 瀛楃涓层�嶆槸甯歌澶辫触妯″紡锛夛紝
+ * 鍥犱负瀹冧究瀹滀笖鏃犳崯锛涢櫎姝や箣澶栫殑浠讳綍褰㈢姸閮藉彧鏄�岃繖涓�椤规病鏈夈�嶏紝涓嶅湪杩欓噷鎶涢敊鈥斺��
+ * 绌烘暟缁勬渶缁堢敱鏈嶅姟灞傜殑 {@code AI_IMPORT_DRAFT_EMPTY} 鎶ュ嚭锛屾瘮鍦ㄨ繖閲屾姤閿欐枃妗堟洿璐村垏銆�
+ */
+ private static List<QcReportAiDraftRespVO.DraftComponent> readComponents(JSONObject json) {
+ Object raw = json.get("components");
+ JSONArray array = null;
+ if (raw instanceof CharSequence cs && StrUtil.isNotBlank(cs)) {
+ try {
+ array = JSONUtil.parseArray(cs.toString());
+ } catch (Exception ignored) {
+ // 瑙f瀽涓嶅嚭鏉ュ氨鎸夈�屾病鏈夌粍浠躲�嶅鐞嗭紝鏈�缁堢敱 DRAFT_EMPTY 缁熶竴鎶ュ嚭
+ }
+ } else if (raw instanceof JSONArray ja) {
+ array = ja;
+ }
+ if (array == null) {
+ return new ArrayList<>();
+ }
+ List<QcReportAiDraftRespVO.DraftComponent> components = new ArrayList<>(array.size());
+ for (Object item : array) {
+ if (item instanceof JSONObject obj) {
+ components.add(obj.toBean(QcReportAiDraftRespVO.DraftComponent.class));
+ }
+ }
+ return components;
+ }
+
+ /**
+ * 璇� page銆傛ā鍨嬪彧缁� size 鎴栧彧缁� orientation 閮界畻鏁帮紝缂虹殑閮ㄥ垎璁╄璁″櫒鎸夊綋鍓嶆ā鏉胯蛋銆�
+ */
+ private static ReportTemplateSchema.Page readPage(JSONObject json) {
+ Object raw = json.get("page");
+ if (!(raw instanceof JSONObject pageObj)) {
+ return null;
+ }
+ ReportTemplateSchema.Page page = new ReportTemplateSchema.Page();
+ page.setSize(pageObj.getStr("size"));
+ page.setOrientation(pageObj.getStr("orientation"));
+ Object margin = pageObj.get("margin");
+ if (margin instanceof JSONObject marginObj) {
+ ReportTemplateSchema.Margin m = new ReportTemplateSchema.Margin();
+ m.setTop(marginObj.getDouble("top"));
+ m.setRight(marginObj.getDouble("right"));
+ m.setBottom(marginObj.getDouble("bottom"));
+ m.setLeft(marginObj.getDouble("left"));
+ page.setMargin(m);
+ }
+ return (page.getSize() == null && page.getOrientation() == null && page.getMargin() == null)
+ ? null : page;
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportLlmCall.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportLlmCall.java
new file mode 100644
index 0000000..e546dcd
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportLlmCall.java
@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.qcreport.service.aiimport.llm;
+
+/**
+ * 涓�娆″緟鎵ц鐨勫ぇ妯″瀷璋冪敤銆�
+ * <p>
+ * 鐢� {@link QcReportLlmCallPlanner} 绾嚱鏁扮畻鍑猴紝浜ょ粰钖勬墽琛屽櫒鐪熸鍙戝嚭鍘汇��
+ * 鎷嗘垚銆屽厛绠楄鍒掋�佸啀鎵ц銆嶆槸涓轰簡璁╁椤� / 澶氭枃浠� / 瓒呴绠楄繖浜涙帶鍒舵祦鍙互琚崟娴嬪畬鏁磋鐩栤�斺��
+ * 鍚﹀垯鍙兘闈� mock 鎺� {@code AiChatApi} 鎵嶈兘娴嬶紝閭f祴鐨勬槸 mock 涓嶆槸閫昏緫銆�
+ * <p>
+ * 姣忎釜璋冪敤鑷甫鍏ㄩ儴鍏ュ弬锛堝惈 TEXT 閫氶亾鐨勬鏂囷級锛屾墽琛屽櫒涓嶉渶瑕佸洖鐪嬫娊鍙栫粨鏋溿��
+ *
+ * @param kind 璋冪敤鏂瑰紡锛屽喅瀹氳蛋 {@code chat} 杩樻槸 {@code chatWithImage}
+ * @param sourceLabel 鏉ユ簮鏍囩锛屽舰濡傘�屾壂鎻忎欢.pdf 绗� 2 椤点�嶏紝鐢ㄤ簬杞彁绀轰笌閿欒鏂囨
+ * @param text TEXT 閫氶亾鐨勬鏂囷紱IMAGE 閫氶亾鎭掍负绌轰覆
+ * @param imageBase64 IMAGE 閫氶亾鐨�**瑁� base64**锛堜笉鍚� {@code data:image/png;base64,} 鍓嶇紑锛�
+ * 鍥犱负 {@code AiChatApiImpl} 鐩存帴瀵瑰畠鍋� Base64 瑙g爜锛夛紱TEXT 閫氶亾鎭掍负绌轰覆
+ * @param mimeType IMAGE 閫氶亾鐨勮8 MIME 绫诲瀷锛屽 {@code image/png}
+ */
+public record QcReportLlmCall(
+ Kind kind,
+ String sourceLabel,
+ String text,
+ String imageBase64,
+ String mimeType) {
+
+ /**
+ * 璋冪敤鏂瑰紡銆�
+ */
+ public enum Kind {
+ /** 绾枃鏈紝涓�娆¤皟鐢ㄦ悶瀹氭暣浠芥枃浠� */
+ TEXT,
+ /** 澶氭ā鎬侊紝涓�娆¤皟鐢ㄥ彧璁や竴寮犲浘锛屾墍浠ラ�愰〉涓�璋� */
+ IMAGE
+ }
+
+ public static QcReportLlmCall ofText(String sourceLabel, String text) {
+ return new QcReportLlmCall(Kind.TEXT, sourceLabel, text, "", "");
+ }
+
+ public static QcReportLlmCall ofImage(String sourceLabel, String imageBase64, String mimeType) {
+ return new QcReportLlmCall(Kind.IMAGE, sourceLabel, "", imageBase64, mimeType);
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportLlmCallPlanner.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportLlmCallPlanner.java
new file mode 100644
index 0000000..d70f23b
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportLlmCallPlanner.java
@@ -0,0 +1,47 @@
+package cn.iocoder.yudao.module.qcreport.service.aiimport.llm;
+
+import cn.iocoder.yudao.module.qcreport.service.aiimport.document.QcReportDocumentExtract;
+
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.List;
+
+/**
+ * 鎶婃娊鍙栫粨鏋滅炕璇戞垚銆岃鍙戝嚑娆℃ā鍨嬭皟鐢ㄣ�佹瘡娆″彂浠�涔堛�嶃��
+ * <p>
+ * 绾嚱鏁帮細娌℃湁 IO銆佹病鏈� Spring銆佹病鏈� {@code AiChatApi}銆傚椤� / 澶氭枃浠� / 瓒呴绠楄繖浜涙帶鍒舵祦
+ * 鍥犳鑳藉湪鍗曟祴閲岃瀹屾暣瑕嗙洊锛岃�屼笉蹇� mock 鎺夌湡姝g殑澶栭儴渚濊禆銆�
+ */
+public class QcReportLlmCallPlanner {
+
+ private QcReportLlmCallPlanner() {
+ }
+
+ /**
+ * 涓轰竴涓枃浠舵帓璋冪敤璁″垝銆�
+ * <p>
+ * TEXT 閫氶亾鏁翠唤鏂囦欢涓�娆¤皟鐢紱IMAGES 閫氶亾閫愰〉涓�娆♀�斺�斿妯℃�佹帴鍙d竴娆″彧鏀朵竴寮犲浘锛�
+ * 杩欐槸鎺ュ彛绾︽潫鑰屼笉鏄彇鑸嶃��
+ * <p>
+ * 杩欓噷**涓嶅仛椤垫暟涓婇檺鍒ゆ柇**锛氳秴闄愮敱閫傞厤鍣ㄥ湪鎶藉彇闃舵灏辨姏閿欙紝鍥犱负闈欓粯鎴柇浼氳鐢ㄦ埛
+ * 浠ヤ负鏁翠唤鏂囦欢閮借瘑鍒繃浜嗭紝姣旂洿鎺ユ姤閿欏嵄闄╁緱澶氥��
+ *
+ * @param extract 鎶藉彇缁撴灉
+ * @param sourceLabel 鏉ユ簮鏍囩锛岄�氬父鏄師濮嬫枃浠跺悕锛屼細鎷艰繘姣忛〉鐨勬爣绛鹃噷
+ * @return 鎸夋墽琛岄『搴忔帓鍒楃殑璋冪敤鍒楄〃锛岃嚦灏戜竴椤�
+ */
+ public static List<QcReportLlmCall> plan(QcReportDocumentExtract extract, String sourceLabel) {
+ if (extract.channel() == QcReportDocumentExtract.Channel.TEXT) {
+ return List.of(QcReportLlmCall.ofText(sourceLabel, extract.text()));
+ }
+ List<QcReportLlmCall> calls = new ArrayList<>(extract.images().size());
+ for (QcReportDocumentExtract.ImagePart image : extract.images()) {
+ calls.add(QcReportLlmCall.ofImage(
+ sourceLabel + " " + image.label(),
+ Base64.getEncoder().encodeToString(image.bytes()),
+ image.mimeType()));
+ }
+ return calls;
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportTemplatePromptBuilder.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportTemplatePromptBuilder.java
new file mode 100644
index 0000000..1fd0fb6
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportTemplatePromptBuilder.java
@@ -0,0 +1,247 @@
+package cn.iocoder.yudao.module.qcreport.service.aiimport.llm;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
+import cn.iocoder.yudao.module.qcreport.controller.admin.aiimport.vo.QcReportComponentSpecVO;
+import cn.iocoder.yudao.module.qcreport.engine.context.ReportFields;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.AI_IMPORT_CATALOG_INVALID;
+
+/**
+ * 鎷笺�屾枃浠� 鈫� 妯℃澘鑽夌銆嶇殑鎻愮ず璇嶃��
+ * <p>
+ * 绾嚱鏁帮細鍚屾牱鐨勫叆鍙傛案杩滅粰鍚屾牱鐨勫瓧绗︿覆锛屽洜姝ゆ彁绀鸿瘝閲岃鏈夌殑绾︽潫鏄惁鍦ㄥ満鍙互琚崟娴嬮�愭潯鏂█锛�
+ * 鑰屼笉蹇呯湡鐨勮皟涓�娆℃ā鍨嬪幓銆屾劅瑙変竴涓嬨�嶃��
+ *
+ * <h3>涓轰粈涔堢Н鏈ㄦ竻鍗曟槸鍏ュ弬鑰屼笉鏄父閲�</h3>
+ * 缁勪欢娉ㄥ唽琛ㄧ殑鍞竴鐪熺浉鏉ユ簮鍦ㄥ墠绔紙{@code components/quality/index.ts}锛夈�傚悗绔‖缂栫爜涓�浠�
+ * 灏辨槸绗簩涓湡鐩告潵婧愶紝涓旀槸鏈�鍧忕殑閭g锛氬墠绔姞缁勪欢銆佹敼蹇呭~瀛楁鏃跺墠绔珛鍒荤敓鏁堛�佸悗绔壇鏈潤榛樿繃鏈燂紝
+ * 妯″瀷闅忓嵆浼氱紪鍑烘敞鍐岃〃閲屾牴鏈笉瀛樺湪鐨� type銆傛墍浠ユ竻鍗曢殢璇锋眰浼犱笂鏉ワ紝杩欓噷鍙礋璐e簭鍒楀寲杩涙彁绀鸿瘝銆�
+ *
+ * <h3>杈圭晫娌℃湁鍥犳琚墛寮�</h3>
+ * 娓呭崟杩涙彁绀鸿瘝鍚庣殑鍞竴鍑哄彛鏄�岃妯″瀷鎶勬垚 JSON 瀛楃涓层�嶃�傜湡姝f妸鍏崇殑鏄墠绔閰嶅櫒瀵圭潃娲绘敞鍐岃〃鏌�
+ * {@code getQualityComponent}锛氭湭娉ㄥ唽鐨� type 鍦ㄩ偅杈逛細琚烦杩囷紝浜т笉鍑轰换鎰� HTML銆傚氨绠楁湁浜轰吉閫犱竴浠�
+ * 鍚� {@code CustomHtml} 鐨勬竻鍗曪紝涔熷彧浼氬湪瑁呴厤闃舵琚涪寮冦��
+ */
+public class QcReportTemplatePromptBuilder {
+
+ /**
+ * 绉湪娓呭崟搴忓垪鍖栧悗鐨勯暱搴︿笂闄愩��
+ * <p>
+ * 娓呭崟鏄�屾ā鍨嬭兘鐢ㄧ殑绉湪銆嶇殑瀹屾暣鎻忚堪锛屾甯稿崄鍑犻」缁勪欢涔熷氨鍑� KB銆傝秴杩� 32KB 璇存槑璋冪敤鏂逛紶閿欎簡涓滆タ
+ * 锛堟瘮濡傛妸鏁翠釜娉ㄥ唽琛ㄨ繛鍚屽疄鐜颁竴璧峰簭鍒楀寲涓婃潵锛夛紝姝ゆ椂鐩存帴鎶ラ敊姣旇鎻愮ず璇嶆倓鎮勬拺鐖嗕笂涓嬫枃瀹夊叏銆�
+ */
+ public static final int MAX_CATALOG_JSON_LENGTH = 32 * 1024;
+
+ /**
+ * 閾佸緥銆傝繖鏄暣濂楄璁$殑鍦板熀锛屼笉鏄�屽缓璁�嶁�斺�斿畠鎶婃ā鍨嬮檺鍒跺湪銆屽彧鑳界敤宸叉敞鍐岀粍浠舵惌鎵佸钩缁撴瀯銆嶄箣鍐呫��
+ */
+ private static final String IRON_RULES = """
+ 銆愬繀椤婚伒瀹堢殑纭�х害鏉熴��
+ 1. 浣犲彧鑳戒娇鐢ㄣ�婂彲鐢ㄧ粍浠舵竻鍗曘�嬮噷鍒楀嚭鐨� type锛屽ぇ灏忓啓鏁忔劅锛屼竴涓瓧閮戒笉鑳芥敼銆�
+ 2. 涓ョ杈撳嚭 HTML / CSS / script / style / 鑷畾涔� div銆乼able 鏍囩銆備綘浜у嚭鐨勪笉鏄綉椤碉紝鏄粍浠舵竻鍗曘��
+ 3. 缁撴瀯蹇呴』瀹屽叏鎵佸钩锛氫竴涓� components 鏁扮粍锛屽厓绱犳病鏈� children銆佹病鏈夊祵濂椼�傛暟缁勯『搴忓嵆鎶ュ憡浠庝笂鍒颁笅鐨勯『搴忋��
+ 4. 姣忎釜缁勪欢鍙兘濉竻鍗曢噷涓鸿 type 澹版槑杩囩殑 props 鐨� key銆傛湭澹版槑鐨� key 浼氳涓㈠純锛�
+ 涓嶇‘瀹氱殑瀛楁涓嶈缂栭�狅紝鏁翠釜 key 鐪佺暐鍗冲彲銆�
+ 5. 鏃犳硶鐢ㄦ竻鍗曠粍浠惰〃杈剧殑鍐呭锛堣嚜鐢辨帓鐗堢殑鍥惧舰銆侀潪鏍囧噯琛ㄦ牸鐨勫叿浣撴暟鎹锛夎涓㈠純锛�
+ 骞跺湪 summary 閲岃鏄庝涪寮冧簡浠�涔堬紝涓嶈鐢� HTML 纭噾銆�
+ """;
+
+ /**
+ * 鎶藉彇瑙勫垯銆傚墠涓ゆ潯鐩存帴鏉ヨ嚜銆岃涔夊眰鏄埢鎰忔敹绐勭殑瀛愰泦銆嶈繖鏉¤竟鐣屻��
+ */
+ private static final String EXTRACTION_RULES = """
+ 銆愭娊鍙栬鍒欍��
+ 1. 鍙繚鐣欐姤鍛婄殑**缁撴瀯**锛氭爣棰樸�佹爮鐩�佽〃澶淬�佸瓧娈靛悕銆傛枃浠堕噷鐨�**鍏蜂綋鏁版嵁琛屼笉瑕佸啓杩涙ā鏉�**鈥斺��
+ 鍑℃槸甯︽楠岄」鐨勮〃鏍肩粍浠讹紝itemsPath 涓�寰嬪~ "inspectionItems"锛�
+ 鐪熷疄鏁版嵁鍦ㄥ嚭浠舵椂鐢变笟鍔″崟鎹彁渚涖��
+ 2. 褰㈠ {{report.reportNo}}銆亄{report.conclusion}} 鐨勬槸**鏁版嵁缁戝畾鍗犱綅绗�**锛岃鍘熸牱淇濈暀锛�
+ 涓嶈鏇挎崲鎴愪綘鍦ㄦ枃浠堕噷鐪嬪埌鐨勫瓧闈㈠�笺��
+ 3. 鎵弿浠�/鐓х墖鍙兘鏈夊椤碉紝椤电湁銆佹爣棰樸�佽〃澶村湪澶氶〉閲嶅鍑虹幇鏃跺彧淇濈暀涓�浠姐��
+ 4. 璁や笉鍑虹殑鍐呭瀹佸彲鐪佺暐涔熶笉瑕佺寽锛氱渷鐣ュ彧浼氬皯涓�涓粍浠讹紝鐚滈敊浼氳鐢ㄦ埛浠ヤ负璇嗗埆瀵逛簡銆�
+ 5. 娓呭崟閲屾瘡涓�椤圭殑 hint 瀛楁鍐欐槑璇ョ粍浠剁敤鏉ユ斁浠�涔堛�佷笉瑕佺敤鏉ユ斁浠�涔堬紝閫夊瀷鏃朵互 hint 涓哄噯锛�
+ 鍑℃槸娓呭崟閲屽瓨鍦ㄤ笓闂ㄧ粍浠剁殑鍐呭锛屽氨涓嶈閫�鑰岀敤 Text / Heading 杩欑被閫氱敤缁勪欢鍑戞暟銆�
+ 鏂囦欢閲屽甫 [椤电湁] / [椤佃剼] 鏍囪鐨勯儴鍒嗘槸鍘熶欢姣忛〉閲嶅鐨勬姮澶翠笌钀芥锛屽悓鏍锋寜 hint 鍒ゆ柇銆�
+ 6. 鎶ュ憡鏈熬鐨勮惤娆�**绛剧讲琛�**锛堟楠屽憳銆佸鏍镐汉銆佹壒鍑嗕汉銆佹棩鏈熺瓑鏍忕洰锛変笉鏄楠屾暟鎹紝
+ 鍗充娇瀹冩帓鍦ㄦ楠岃〃鏍肩殑鏈�鍚庝竴琛屼篃涓�鏍凤細璇锋妸瀹冨彇鍑烘潵鏀捐繘 ReportFooter锛屼笌鍘熶欢椤佃剼鍚堟垚涓�澶勶紝
+ 涓嶈鍥犱负銆屽畠澶瑰湪琛ㄦ牸閲屻�嶅氨鎸夌 1 鏉″綋鎴愭暟鎹涓㈡帀銆�
+ 浣嗙缃茶鐨勪汉鍚嶄笌鏃ユ湡灞炰簬姣忎竴浠芥姤鍛婂悇鑷殑鏁版嵁锛屼笉瑕佸啓姝诲師浠朵笂鐨勯偅鍑犱釜浜衡�斺��
+ 璇�**淇濈暀鏍忕洰鍚嶃�佸�肩暀绌�**锛屽啓鎴愩�屾楠屽憳锛歘_________銆�瀹℃牳浜猴細__________銆�鏃ユ湡锛歘_________銆�
+ 杩欐牱鐣欏嚭濉啓浣嶅嵆鍙紝鎵撳嵃鍑烘潵鐢变汉鎵嬪~銆�
+ 7. 鍙繚鐣欏師浠堕噷**鏈潵灏辨湁**鐨� {{...}} 鍗犱綅绗︼紝涓嶈鑷繁鍙戞槑鏂扮殑缁戝畾閿細
+ 鎶ュ憡涓婁笅鏂囬噷鏈夊摢浜涘瓧娈佃涓婇潰銆愭姤鍛婁笂涓嬫枃鐨勫瓧娈点�戯紝缂栧嚭鏉ョ殑閿覆鏌撴椂鍙栦笉鍒板�硷紝
+ 鎶ュ憡涓婂彧浼氱暀涓�鐗囩┖鐧藉拰涓�鏉°�岀粦瀹氬彇涓嶅埌鍊笺�嶇殑鍛婅銆�
+ 8. 琛ㄦ牸閲岀殑銆屸啈鍚屼笂銆嶄笉鏄唴瀹癸紝鑰屾槸鏍囨敞銆岃繖涓�鏍间笌**涓婁竴琛屾槸鍚屼竴涓�笺�嶁�斺�斿師浠堕噷瀹冩槸涓�涓�
+ 绾靛悜鍚堝苟鐨勫崟鍏冩牸銆傝鎶婂畠褰撲綔銆屽悎骞躲�嶆潵璇伙紝涓嶈褰撴垚鍥涗釜瀛楃殑鏅�氭枃瀛楀啓杩涙ā鏉裤��
+ 9. 鐢辨鍙互鏂畾锛�**鍚屼竴鍒楅噷杩炵画鍑虹幇銆屸啈鍚屼笂銆嶏紝杩欏紶琛ㄥ氨鏄袱灞傜粨鏋�**鈥斺�旀渶涓婇潰閭d釜鍊兼槸
+ 妫�楠岄」鐩悕锛屾爣浜嗐�屸啈鍚屼笂銆嶇殑杩欏嚑琛岄兘鏄畠鐨勫瓙椤广�傝繖涓嶆槸鐚滄祴锛屾槸鍘熶欢閲岀湡瀹炲瓨鍦ㄧ殑灞傜骇锛�
+ 鍥犺�屽繀椤诲綋鎴愪簨瀹炲弬涓庨�夊瀷锛氭竻鍗曢噷鍝竴绉嶈〃鏍艰兘琛ㄨ揪銆岄」鐩� + 瀛愰」銆嶄袱绾э紝灏遍�夊摢涓�绉�
+ 锛堜互璇ョ粍浠剁殑 hint 涓哄噯锛夈�傚彧鏀惧緱涓嬮」鐩悕鐨勫崟灞傛楠岃〃浼氭妸瀛愰」鏁存潯涓㈡帀锛�
+ 鑰屽瓙椤瑰線寰�鎵嶆槸鏍囧噯鐪熸鑰冩牳鐨勫璞★紝涓㈡帀绛変簬鎶ュ憡澶辩湡銆�
+ 鍝�曡〃閲屽彧鏈変竴閮ㄥ垎椤圭洰甯﹀瓙椤广�佸彟涓�閮ㄥ垎涓嶅甫锛屽悓鏍锋寜涓ゅ眰缁撴瀯澶勭悊銆�
+ 10. 鍘熶欢鐨勬楠岃〃**鍒楁瘮缁勪欢榛樿鐨勫**鏃讹紙渚嬪杩樻湁銆屾娴嬫柟娉曘�嶃�岀粨璁恒�嶃�屽娉ㄣ�嶅垪锛夛紝
+ 涓嶈涓㈠垪銆佷篃涓嶈涓轰簡鍑戝垪鍘绘崲缁勪欢锛氭妸杩欏紶琛ㄧ殑鍏ㄩ儴鍒楀啓杩涜缁勪欢 columns 灞炴�х殑鍊奸噷銆�
+ 鍊兼槸涓�琛屽瓧绗︿覆锛屾瘡鍒楀啓浣� `鍒楁爣棰�=缁戝畾琛ㄨ揪寮廯锛屽垪涓庡垪涔嬮棿鐢� `|` 鍒嗛殧锛屼緥濡傦細
+ 搴忓彿={{index}}|妫�楠岄」鐩�={{item.itemName}}|妫�娴嬫柟娉�={{item.checkMethod}}|鏍囧噯瑕佹眰={{item.standardValue}}|瀹炴祴鍊�={{item.actualValue}}|鍗曚綅={{item.unit}}|鍒ゅ畾={{item.resultText}}
+ 鍒楁爣棰樺墠鍔� `#` 琛ㄧず杩欎竴鍒楄绾靛悜鍚堝苟璺ㄤ綇鏁寸粍锛堝垎缁勮〃閲屾斁缁勫悕鐨勯偅涓�鍒楋級銆�
+ columns 鐨勭粦瀹氳〃杈惧紡**鍙厑璁哥敤涓嬮潰杩欎簺璺緞锛屼笉璁稿彂鏄庢柊鐨�**锛�
+ {{index}} 琛屽簭鍙枫�亄{item.itemName}} 妫�楠岄」鐩悕銆亄{item.group.childName}} 瀛愰」鍚嶃��
+ {{item.checkMethod}} 妫�娴嬫柟娉曘�亄{item.requirement}} 妫�娴嬭姹傘�亄{item.standardValue}} 鏍囧噯鍊笺��
+ {{item.actualValue}} 瀹炴祴鍊笺�亄{item.unit}} 鍗曚綅銆亄{item.resultText}} 鍒ゅ畾缁撹銆亄{item.remark}} 澶囨敞銆�
+ 鍘熶欢鐨勫垪涓庢竻鍗曢噷璇ョ粍浠� hint 鍐欐槑鐨勯粯璁ゅ垪涓�鑷存椂**涓嶈鍐� columns**锛岃瀹冪敤榛樿鍒楀嵆鍙��
+ 缁�**鍒嗙粍妫�楠岄」琛�**鍐� columns 鏃跺彟鏈変竴鏉$‖瑕佹眰锛氬師浠堕噷鏀惧瓙椤瑰悕鐨勯偅涓�鍒�
+ 锛堟爣浜嗐�屸啈鍚屼笂銆嶇殑閭e嚑琛屾梺杈广�佸啓鐫�銆�20鐩笂銆嶃��40鐩笂銆嶈繖绫诲瓙椤瑰悕鐨勫垪锛�
+ **蹇呴』**淇濈暀锛屽啓鎴� `瀛愰」={{item.group.childName}}`锛屼笖**涓嶈**鍔� `#`锛�
+ 鍒嗙粍琛ㄧ殑榛樿鍒楅噷鏈潵灏辨湁杩欎竴鍒楋紝鎶� columns 鍐欏叏鏃舵渶瀹规槗婕忔帀瀹冿紝
+ 涓�婕忓瓙椤瑰悕鏁村垪浠庢姤鍛婁笂娑堝け鈥斺�旇�屽瓙椤瑰線寰�鎵嶆槸鏍囧噯鐪熸鑰冩牳鐨勫璞°�備緥濡傦細
+ #妫�楠岄」鐩�={{item.itemName}}|瀛愰」={{item.group.childName}}|妫�娴嬫柟娉�={{item.checkMethod}}|鏍囧噯瑕佹眰={{item.standardValue}}|缁撴灉={{item.actualValue}}|鍒ゅ畾={{item.resultText}}
+ 11. 琛ㄥご鏄�**涓ゅ眰**鐨勶紙涓婇潰涓�灞傛槸銆屾楠岀粨鏋溿�嶈繖绫诲垎缁勬爣棰樸�佷笅闈竴灞傛墠鏄悇鍒楀悕锛夋椂锛�
+ 鎶婁笂闈㈤偅涓�灞傚啓杩涜缁勪欢 headerSpans 灞炴�х殑鍊奸噷锛屾牸寮忓悓鏍锋槸 `|` 鍒嗛殧銆�
+ 姣忎釜鍗曞厓鏍煎啓浣� `鏍囬^璺ㄨ秺鍒楁暟`锛屼緥濡傦細妫�楠岀粨鏋淾5|缁撹^1
+ 涓嬮潰閭d竴灞傜敱 columns 鍚勫垪鐨勬爣棰樿嚜鍔ㄦ嫾鍑猴紝涓嶈閲嶅鍐欍��
+ 鍚勬 `^` 鍚庨潰鐨勬暟瀛椾箣鍜屽繀椤荤瓑浜庡垪鏁帮紝瀵逛笉涓婂氨璇存槑鍐欓敊浜嗭紝璇烽噸鏂版暟涓�閬嶃��
+ 鏈�鍙宠竟閭d竴鍒椼�岀粨璁恒��/銆屽垽瀹氥�嶅湪鍘熶欢閲屼笉灞炰簬涓婂眰閭d釜鍒嗙粍鏍囬锛堝畠鐨勪笂鏂瑰氨鏄�岀粨璁恒��
+ 浜屽瓧锛屼笉鏄�屾楠岀粨鏋溿�嶏級鏃惰**鍗曠嫭鍐欐垚涓�娈�**锛堝 `缁撹^1`锛夛紝
+ 涓嶈鍥剧渷浜嬫妸瀹冪殑鍒楁暟骞惰繘銆屾楠岀粨鏋溿�嶏紝閭f牱琛ㄥご浼氭妸缁撹鍒楃敾杩涙楠岀粨鏋滃簳涓嬨��
+ 杩欑鍒楀湪鍘熶欢閲屾槸**涓�鏍肩旱鍚戝悎骞躲�佽嚜宸卞崰婊′笂涓嬩袱灞傝〃澶�**锛堟彁鍙栨枃鏈噷琛ㄧ幇涓轰笅灞�
+ 琛ㄥご閭d竴鏍煎啓鐫�銆屸啈鍚屼笂銆嶏級鈥斺�斿畠鑷繁鏃㈡槸鍒楀悕鍙堟槸涓婃牸銆傚啓瀹冩椂璇ユ鐨勬爣棰樺繀椤讳笌
+ columns 閲岃繖涓�鍒楃殑鍒楁爣棰�**涓�瀛椾笉宸�**锛氭姤鍛婅鍑轰袱鑰呯浉鍚屾椂浼氭妸瀹冨悎鍑轰竴鏍艰法涓よ锛�
+ 涓�鏃︽爣棰樹笌鍒楀悕涓嶄竴鑷达紝灏变細琚綋鎴愬彟涓�灞傜殑鏂板垎缁勬爣棰橈紝銆岀粨璁恒�嶄簩瀛楀湪琛ㄥご涓婂嵃涓ら亶銆�
+ 鎵�浠ュ師浠堕偅涓�鍒楀彨銆岀粨璁恒�嶏紝columns 閲屽氨鐓у啓銆岀粨璁恒�嶏紝杩欎竴娈电殑鏍囬涔熷啓銆岀粨璁恒�嶏紝
+ 涓嶈鑷綔涓诲紶鎶婂畠鏀瑰悕鎴愩�屽垽瀹氥�嶈繖绫昏繎涔夎瘝鈥斺�旀敼鍚嶄箣鍚庝袱杈瑰涓嶄笂锛屽氨浼氬鍗颁竴涓〃澶淬��
+ 12. 鏍峰搧淇℃伅鍧楋紙SampleInfo锛夎灞曠ず鐨勫瓧娈典笌娓呭崟閲岃缁勪欢鐨勯粯璁ゅ瓧娈典笉涓�鑷存椂锛�
+ 鎶婂叏閮ㄥ瓧娈靛啓杩涘畠鐨� fields 灞炴�э紝璇硶涓� columns 鐩稿悓锛堝瓧娈靛悕=缁戝畾琛ㄨ揪寮忥紝
+ 澶氭鐢� `|` 鍒嗛殧锛夛紝渚嬪锛�
+ 鏍峰搧缂栧彿={{report.sampleNo}}|浜у搧鍚嶇О={{report.productName}}|瑙勬牸={{report.spec}}|鎵瑰彿={{report.batchNo}}|妫�楠屾棩鏈�={{report.inspectDate}}|妫�楠屽憳={{report.inspector}}
+ 瀛楁鍚嶅墠**涓嶅厑璁�**鍔� `#`锛堥偅鏄垎缁勮〃鏀剧粍鍚嶉偅涓�鍒椾笓鐢ㄧ殑锛夈��
+ fields 鐨勭粦瀹氳〃杈惧紡鍚屾牱鍙楃 7 鏉$害鏉燂細鍙兘鍐欐姤鍛婁笂涓嬫枃閲岀‘瀹炲瓨鍦ㄧ殑瀛楁锛�
+ 鍘熶欢閲屾湁銆佷笂涓嬫枃閲屾病鏈夌殑锛堝銆屼骇鍝佹暟閲忋�嶃�屽湡璞嗗搧绉嶃�嶏級璇锋寜绗� 5 鏉′涪寮冨苟鍦� summary 閲岃鏄庛��
+ """;
+
+ /**
+ * 鎶ュ憡绾у彲缁戝畾瀛楁鐨勭櫧鍚嶅崟锛屽彇鑷� {@link ReportFields} 鐨勫瓧娈靛悕銆�
+ * <p>
+ * 涓嶆墜鍐欏父閲忥細鎵嬪啓鐨勬竻鍗曚細鍦ㄥ埆浜虹粰鎶ュ憡鍔犲瓧娈垫椂闈欓粯杩囨湡锛岃�屾ā鍨嬫鏄潬杩欎唤娓呭崟鎵嶇煡閬�
+ * {@code {{report.xxx}}} 閲岃兘鍐欎粈涔堛�傛竻鍗曢噷灏戜竴涓敭锛岀敤鎴峰氨浼氬湪鎶ュ憡涓婄湅鍒颁竴鐗囩┖鐧藉拰
+ * 涓�鏉°�岀粦瀹氬彇涓嶅埌鍊笺�嶇殑鍛婅锛屼笖鐪嬩笉鍑烘槸鎻愮ず璇嶈繃鏈熼�犳垚鐨勩��
+ */
+ private static final String REPORT_FIELD_KEYS = reportFieldKeys();
+
+ /**
+ * 鎶ュ憡瀛楁鐧藉悕鍗曘�傜 7 鏉″彧鍐欍�屼笉瑕佽嚜宸卞彂鏄庢柊鐨勭粦瀹氶敭銆嶏紝鍗翠笉璇寸┒绔熸湁鍝簺閿紝
+ * 妯″瀷灏卞彧鑳介潬鐚溾�斺�斿疄娴嬬洿杩� 5 杞紝5 杞兘缂栧嚭浜� {@code {{report.productionDate}}} /
+ * {@code {{report.expiryDate}}} 杩欑被涓婁笅鏂囬噷涓嶅瓨鍦ㄧ殑閿�傜姝㈢紪閫犵殑鍓嶆彁鏄妸鍙�夐泦鍚堟憡寮�缁欏畠鐪嬨��
+ */
+ private static final String REPORT_FIELDS_RULE = """
+ 銆愭姤鍛婁笂涓嬫枃鐨勫瓧娈点��
+ 鎶ュ憡涓婁笅鏂囬噷纭疄瀛樺湪鐨勫瓧娈靛彧鏈変笅闈㈣繖浜涳紝涓嶅涓嶅皯锛�
+ %s
+ 绗� 7 鏉¤姹傘�屼笉瑕佽嚜宸卞彂鏄庢柊鐨勭粦瀹氶敭銆嶏紝璇寸殑灏辨槸鍙兘浠庝笂闈㈣繖浜涢噷鎸戙��
+ 鍘熶欢閲屽嚭鐜般�佷笂闈㈡病鏈夌殑鏍忕洰锛堝銆屼骇鍝佹暟閲忋�嶃�屽湡璞嗗搧绉嶃�嶃�岀敓浜ф棩鏈熴�嶃�屾湁鏁堟棩鏈熴�嶏級
+ 涓�寰嬩笉瑕佸啓杩涙ā鏉匡紝鎸夌 5 鏉′涪寮冨苟鍦� summary 閲岃鏄庛��
+ """;
+
+ private static String reportFieldKeys() {
+ List<String> keys = new ArrayList<>();
+ // 涓嶆寜绫诲瀷绛涳細婕忔帀涓�涓彲缁戝畾鐨勫瓧娈碉紙濡傚師濮� int 鐨� total锛夋瘮澶氬垪涓�涓笉鑳界粦鐨勫瓧娈靛嵄闄╁緱澶氣�斺��
+ // 鍓嶈�呰妯″瀷浠ヤ负杩欎釜閿笉瀛樺湪銆佸彧鑳介潬鐚滐紝鍚庤�呭彧鏄缁欎竴涓敤涓嶄笂鐨勫悕瀛�
+ for (Field field : ReportFields.class.getDeclaredFields()) {
+ if (Modifier.isStatic(field.getModifiers())) {
+ continue;
+ }
+ keys.add("{{report." + field.getName() + "}}");
+ }
+ return String.join("銆�", keys);
+ }
+
+ /**
+ * 杈撳嚭鏍煎紡鐨勫瓧闈㈢ず渚嬨��
+ * <p>
+ * 鐢ㄧず渚嬭�屼笉鏄� JSON Schema锛氭湰椤圭洰浠� {@code -api} 澶熶笉鐫� Spring AI 鐨�
+ * {@code BeanOutputConverter}锛屽彧鑳介潬銆屾彁绀鸿瘝閲岀粰瓒虫牱瀛� + 鎷垮埌鍥炲鍚庡垏鐗囧弽搴忓垪鍖栥�嶈繖鏉¤矾锛�
+ * 杩欐槸鏃㈡湁鑼冨紡锛圗RP / CRM / MES 涓夊 AI 璋冪敤锛夌殑缁熶竴鍋氭硶銆�
+ */
+ private static final String OUTPUT_FORMAT = """
+ 銆愯緭鍑烘牸寮忋��
+ 鍙緭鍑轰竴涓� JSON 瀵硅薄锛屼笉瑕佹湁浠讳綍瑙i噴鏂囧瓧銆佷笉瑕佺敤 markdown 浠g爜鍧楀寘瑁广�傚瓧娈靛涓嬶細
+ {
+ "summary": "涓�鍙ヨ瘽璇存槑杩欎唤鏂囦欢鏄粈涔堟姤鍛婏紝浠ュ強鏈夋病鏈変涪寮冩棤娉曡〃杈剧殑鍐呭",
+ "page": { "size": "A4", "orientation": "portrait" },
+ "components": [
+ { "type": "ReportHeader", "props": { "title": "鏉ユ枡妫�楠屾姤鍛�" } },
+ { "type": "QualityTable", "props": { "itemsPath": "inspectionItems" } },
+ { "type": "ReportFooter", "props": {} }
+ ]
+ }
+ 璇存槑锛歱age 鍙互鐪佺暐锛堢渷鐣ヨ〃绀烘部鐢ㄥ綋鍓嶆ā鏉跨殑绾稿紶锛夛紱size 鍙栧�� A3/A4/A5/Letter锛�
+ orientation 鍙栧�� portrait/landscape锛沜omponents 鑷冲皯瑕佹湁涓�椤广��
+ 涓婇潰绀轰緥閲岀殑 type **鍙槸鏍煎紡绀烘剰**锛岄�夊瀷涓�寰嬩互銆婂彲鐢ㄧ粍浠舵竻鍗曘�嬮噷鍚勭粍浠� hint 涓哄噯锛�
+ 涓嶈鍥犱负绀轰緥閲屽啓浜嗘煇涓� type 灏辩収鎶勫畠銆�
+ """;
+
+ private QcReportTemplatePromptBuilder() {
+ }
+
+ /**
+ * 鎷肩郴缁熸彁绀鸿瘝銆�
+ *
+ * @param catalog 鍙敤缁勪欢绉湪娓呭崟锛岀敱鍓嶇浠庢椿娉ㄥ唽琛ㄧ敓鎴�
+ * @return 绯荤粺鎻愮ず璇�
+ * @throws cn.iocoder.yudao.framework.common.exception.ServiceException 娓呭崟涓虹┖鎴栧簭鍒楀寲鍚庤秴闀挎椂
+ */
+ public static String buildSystemPrompt(List<QcReportComponentSpecVO> catalog) {
+ if (catalog == null || catalog.isEmpty()) {
+ throw exception(AI_IMPORT_CATALOG_INVALID, "缁勪欢娓呭崟涓虹┖");
+ }
+ String catalogJson = JSONUtil.toJsonStr(catalog);
+ if (catalogJson.length() > MAX_CATALOG_JSON_LENGTH) {
+ throw exception(AI_IMPORT_CATALOG_INVALID,
+ StrUtil.format("缁勪欢娓呭崟搴忓垪鍖栧悗 {} 瀛楃锛岃秴杩囦笂闄� {} 瀛楃",
+ catalogJson.length(), MAX_CATALOG_JSON_LENGTH));
+ }
+ return """
+ 浣犳槸涓�鍚嶈川妫�鎶ュ憡妯℃澘缁撴瀯鍒嗘瀽鍔╂墜銆傜敤鎴蜂細缁欎綘涓�浠藉凡鏈夌殑妫�楠屾姤鍛婃枃浠跺唴瀹癸紙鍙兘鏄枃鏈紝
+ 涔熷彲鑳芥槸鎵弿浠�/鐓х墖锛夛紝浣犺鎶婂畠鎷嗚В鎴愩�婂彲鐢ㄧ粍浠舵竻鍗曘�嬮噷鐨勭粍浠讹紝渚涚敤鎴峰湪璁捐鍣ㄩ噷纭鍚庝娇鐢ㄣ��
+
+ %s
+ 銆愬彲鐢ㄧ粍浠舵竻鍗曘��
+ 涓嬮潰姣忎釜 type 灏辨槸涓�涓彲鐢ㄧН鏈紱fields 閲屽0鏄庝簡璇ョН鏈ㄥ厑璁稿~鍐欑殑灞炴�с��
+ %s
+
+ %s
+
+ %s
+
+ %s
+ """.formatted(IRON_RULES, catalogJson,
+ REPORT_FIELDS_RULE.formatted(REPORT_FIELD_KEYS), EXTRACTION_RULES, OUTPUT_FORMAT);
+ }
+
+ /**
+ * 鎷肩敤鎴锋秷鎭��
+ *
+ * @param hint 鐢ㄦ埛琛ュ厖璇存槑锛屽彲涓虹┖
+ * @param sourceLabel 鏉ユ簮鏍囩锛堟枃浠跺悕 / 鏂囦欢鍚�+椤电爜锛夛紝渚夸簬妯″瀷鐞嗚В涓婁笅鏂�
+ * @param content 鏂囨。姝f枃锛圱EXT 閫氶亾锛夋垨瀵瑰浘鐗囩殑璇嗗埆鎸囦护锛圛MAGE 閫氶亾锛�
+ * @return 鐢ㄦ埛娑堟伅
+ */
+ public static String buildUserMessage(String hint, String sourceLabel, String content) {
+ StringBuilder sb = new StringBuilder();
+ if (StrUtil.isNotBlank(sourceLabel)) {
+ sb.append("鏉ユ簮锛�").append(sourceLabel).append('\n');
+ }
+ if (StrUtil.isNotBlank(hint)) {
+ sb.append("鐢ㄦ埛琛ュ厖璇存槑锛�").append(hint).append('\n');
+ }
+ sb.append("浠ヤ笅鏄枃浠跺唴瀹癸紝璇锋寜绯荤粺鎻愮ず鐨勮鍒欒緭鍑� JSON锛歕n");
+ sb.append(content);
+ return sb.toString();
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/GenerateFromQcResult.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/GenerateFromQcResult.java
new file mode 100644
index 0000000..eef785e
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/GenerateFromQcResult.java
@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.qcreport.service.instance;
+
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.instance.QcReportInstanceDO;
+
+import java.util.List;
+
+/**
+ * 鐢辫川妫�鍗曞嚭浠剁殑缁撴灉銆�
+ *
+ * @param instance 钀藉簱鐨勬姤鍛婂疄渚�
+ * @param itemCount 鍐欏叆鐨勬楠岄」鏉℃暟
+ * @param undecidableCount 娌℃湁鍒ゅ畾缁撹鐨勯」鏁帮細銆屾棤鍒ゅ畾瑙勫垯銆嶏紙缂鸿鏍间笂涓嬮檺鍙堟病瑙勫垯锛�
+ * 鍔犱笂瑙勫垯鎵ц澶辫触鐨勩�屽緟鍒ゅ畾銆�
+ * @param warnings 杞彁绀猴細鏍峰搧鐨勫彇鑸嶃�佽烦杩囩殑鍒嗙粍椤广�佸皻鏈綍鍏ュ疄娴嬪�肩殑椤�
+ * @param errors 娓叉煋鏈熸暟鎹己鍙o紙鏃㈡湁鏈哄埗锛�
+ */
+public record GenerateFromQcResult(QcReportInstanceDO instance, int itemCount, int undecidableCount,
+ List<String> warnings, List<String> errors) {
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/GenerateResult.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/GenerateResult.java
new file mode 100644
index 0000000..deb0f06
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/GenerateResult.java
@@ -0,0 +1,14 @@
+package cn.iocoder.yudao.module.qcreport.service.instance;
+
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.instance.QcReportInstanceDO;
+
+import java.util.List;
+
+/**
+ * 鍑轰欢缁撴灉銆�
+ *
+ * @param instance 钀藉簱鐨勬姤鍛婂疄渚嬶紙閲嶆柊鐢熸垚鏃舵槸鏇存柊鍓嶇殑瀹炰緥锛�
+ * @param errors 鏁版嵁缂哄彛娓呭崟鈥斺�旀姤鍛婂嚭鏉ヤ簡锛屼絾杩欎簺瀛楁褰撴椂娌℃湁鍊�
+ */
+public record GenerateResult(QcReportInstanceDO instance, List<String> errors) {
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/MesQcReportContextMapper.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/MesQcReportContextMapper.java
new file mode 100644
index 0000000..d668d17
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/MesQcReportContextMapper.java
@@ -0,0 +1,218 @@
+package cn.iocoder.yudao.module.qcreport.service.instance;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.module.mes.api.qc.dto.MesQcReportItemRespDTO;
+import cn.iocoder.yudao.module.mes.api.qc.dto.MesQcReportRespDTO;
+import cn.iocoder.yudao.module.qcreport.engine.context.InspectionItem;
+import cn.iocoder.yudao.module.qcreport.engine.context.ReportContext;
+import cn.iocoder.yudao.module.qcreport.engine.context.ReportFields;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
+/**
+ * 璐ㄦ鍗曟暟鎹� 鈫� 鎶ュ憡涓婁笅鏂囥��
+ * <p>
+ * 绾嚱鏁帮細鍙仛瀛楁鎼繍涓庢枃妗堟嫾瑁咃紝涓嶆煡搴撱�佷笉娓叉煋銆佷笉鐭ラ亾妯℃澘闀夸粈涔堟牱銆�
+ * 涔嬫墍浠ユ娊鍑烘潵锛屾槸鍥犱负銆屽摢浜涘瓧娈靛埌鍝効鍘汇�嶆槸杩欐瀵规帴鏈�瀹规槗鍑洪敊涔熸渶鍊煎緱鍗曟祴鐨勯儴鍒嗭紝
+ * 鏀惧湪 Service 閲屽氨鍙兘闈犵鍒扮鑱旇皟鎵嶅彂鐜版惉閿欎簡鍒椼��
+ * <p>
+ * <b>涓嶄慨鏀瑰紩鎿�</b>锛氭姤鍛婄粨璁轰粛鐢� {@code ReportEvaluator} 鎸夎鍒�/瑙勬牸涓婁笅闄愮畻锛�
+ * 璐ㄦ鍗曚笂浜哄伐鎷嶇殑閭d釜鍒ゅ畾璧� {@code report.qcResult} 鍗曠嫭鎵胯浇锛屼袱鑰呬簰涓嶈鐩栥��
+ */
+public final class MesQcReportContextMapper {
+
+ /** 妫�楠屾棩鏈熸部鐢ㄥ紩鎿庡叾浣欏湴鏂圭殑鍐欐硶锛岄伩鍏嶅悓涓�浠芥姤鍛婇噷鍑虹幇涓ょ鏃ユ湡鏍煎紡 */
+ private static final DateTimeFormatter INSPECT_DATE_FORMAT =
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.ROOT);
+
+ /** 鎶ュ憡澶淬�屾牱鍝佺紪鍙枫�嶅彧鍦ㄤ竴涓牱鍝佹椂鎵嶆湁纭畾鍚箟锛涜秴杩囪繖涓暟灏变笉寰�澶翠笂鍫嗕簡 */
+ private static final int SAMPLE_NO_JOIN_LIMIT = 3;
+
+ private MesQcReportContextMapper() {
+ }
+
+ /**
+ * 鏄犲皠缁撴灉銆�
+ *
+ * @param context 鎶ュ憡涓婁笅鏂囷紙妫�楠岄」宸插氨浣嶏紝鍒ゅ畾缁撴灉鐢卞紩鎿庡~锛�
+ * @param warnings 杞彁绀猴細鍙栨牱鍝佺殑鍙栬垗銆佹病鎴愮粍鐨勫垎缁勯」銆佷负缁勫ご琛ュ嚭鏉ョ殑琛屻�佸皻鏈綍鍏ュ疄娴嬪�肩殑椤�
+ */
+ public record Mapped(ReportContext context, List<String> warnings) {
+ }
+
+ /**
+ * @param data 璐ㄦ鍗曟暟鎹紝鏉ヨ嚜 MES
+ * @param reportNo 鏈鎶ュ憡缂栧彿锛堝嚭浠舵椂浼氭崲鎴愭渶缁堢敓鏁堢紪鍙凤紝杩欓噷鍙负棰勮/娓叉煋鏃剁焊闈笂鏈変釜鍙凤級
+ */
+ public static Mapped map(MesQcReportRespDTO data, String reportNo) {
+ List<String> warnings = new ArrayList<>();
+ List<MesQcReportItemRespDTO> sourceItems =
+ data.getItems() == null ? List.of() : data.getItems();
+
+ // 鍗曟嵁涓婂彲鑳芥湁澶氫釜鏍峰搧锛堝悓涓�鎸囨爣鍦ㄤ笉鍚屾牱鍝佷笂鍚勬祴涓�娆★級锛屾姤鍛婂ご鍙斁寰椾笅涓�涓�屾牱鍝佺紪鍙枫��
+ List<String> samples = distinctSamples(sourceItems);
+
+ ReportFields report = new ReportFields()
+ .setReportNo(StrUtil.nullToEmpty(reportNo))
+ .setReportName(StrUtil.nullToEmpty(data.getQcName()))
+ .setSampleNo(reportSampleNo(samples, data.getQcCode(), warnings))
+ .setProductCode(StrUtil.nullToEmpty(data.getItemCode()))
+ .setProductName(StrUtil.nullToEmpty(data.getItemName()))
+ .setSpec(StrUtil.nullToEmpty(data.getItemSpecification()))
+ // 鏉ユ枡妫�楠岀殑鎵规鍦ㄤ緵搴斿晢鎵瑰彿涓婏紝鍑鸿揣/閫�璐у湪鎵规鍙蜂笂锛岃繃绋嬫楠屼袱鑰呴兘娌℃湁锛堝彧鏈夊伐鍗曪級
+ .setBatchNo(firstNonBlank(data.getBatchCode(), data.getVendorBatch()))
+ .setWorkOrderNo(StrUtil.nullToEmpty(data.getWorkOrderCode()))
+ .setInspectType(StrUtil.nullToEmpty(data.getQcTypeName()))
+ .setInspector(StrUtil.nullToEmpty(data.getInspectorName()))
+ .setInspectDate(formatDate(data.getInspectDate()))
+ // 璐ㄦ鍗曚笂娌℃湁銆岄儴闂ㄣ�嶈繖涓�缁村害锛岀暀绌鸿�屼笉鏄嬁鍒殑瀛楁纭噾
+ .setCustomerName(StrUtil.nullToEmpty(data.getClientName()))
+ .setSupplierName(StrUtil.nullToEmpty(data.getVendorName()))
+ // 浜哄伐鎷嶇殑妫�楠屽垽瀹氾紝涓庡紩鎿庣畻鍑虹殑 result/resultText/conclusion 鍒嗗垪涓ゅ
+ .setQcResult(data.getCheckResult() == null ? "" : String.valueOf(data.getCheckResult()))
+ .setQcResultText(StrUtil.nullToEmpty(data.getCheckResultText()));
+
+ boolean foldSampleIntoRemark = samples.size() > 1;
+ // 鏁翠唤鎶ュ憡鏈夋病鏈夊垎缁勬槸涓暣浣撳垽鏂細鍒嗙粍淇℃伅瑕侀�愰」涓嬪彂锛堟覆鏌撴湡绠椾笉鍑恒�岃繖涓�缁勫嚑琛屻�嶏級锛�
+ // 娌℃湁鍒嗙粍鐨勬姤鍛婁竴涓敭閮戒笉鏀撅紝鍒妯℃澘閲屾病鍐欑殑璺緞鍑┖澶氬嚭涓�灞傜┖鏍煎瓙
+ boolean grouped = sourceItems.stream().anyMatch(MesQcReportContextMapper::grouped);
+ List<InspectionItem> items = new ArrayList<>(sourceItems.size());
+ for (MesQcReportItemRespDTO source : sourceItems) {
+ items.add(toItem(source, foldSampleIntoRemark, grouped, warnings));
+ }
+
+ appendSkipWarnings(data, warnings);
+ return new Mapped(new ReportContext().setReport(report).setInspectionItems(items), warnings);
+ }
+
+ /** 涓�涓� (鏍峰搧, 鎸囨爣) 缁勫悎 = 涓�琛屾楠岄」锛涙牱鍝佸彿鍦ㄥ鏍峰搧鏃跺苟杩涘娉紝涓嶄涪鏁版嵁 */
+ private static InspectionItem toItem(MesQcReportItemRespDTO source, boolean foldSampleIntoRemark,
+ boolean grouped, List<String> warnings) {
+ int index = source.getIndex() == null ? 0 : source.getIndex();
+ String itemName = StrUtil.nullToEmpty(source.getIndicatorName());
+ if (StrUtil.isBlank(source.getActualValue()) && !isGroupAnchor(source)) {
+ // 鍗曟嵁琛屽缓濂戒簡浣嗗疄娴嬪�艰繕娌″綍锛氳繖涓�琛屽湪鎶ュ憡涓婂繀鐒舵槸銆屽緟鍒ゅ畾銆嶏紝鍏堣娓呮鏄摢涓�椤广��
+ // 缁勫ご鐨勯敋鐐硅闄ゅ 鈥斺�� 缁勫ご鎸夊畾涔夋病鏈夊疄娴嬪�硷紝鍊奸兘鍦ㄥ畠鐨勫瓙椤硅涓婏紝鎶ヤ簡灏辨槸璇姤
+ warnings.add("绗� " + index + " 椤广��" + (StrUtil.isBlank(itemName) ? "鏈懡鍚�" : itemName)
+ + "銆嶅皻鏈綍鍏ュ疄娴嬪�硷紝鎶ュ憡涓椤瑰皢鏃犲垽瀹氱粨璁�");
+ }
+ return new InspectionItem()
+ .setIndex(index)
+ .setItemCode(StrUtil.nullToEmpty(source.getIndicatorCode()))
+ .setItemName(itemName)
+ .setStandardValue(StrUtil.nullToEmpty(source.getStandardValue()))
+ .setActualValue(StrUtil.nullToEmpty(source.getActualValue()))
+ .setUnit(StrUtil.nullToEmpty(source.getUnit()))
+ .setRequirement(StrUtil.nullToEmpty(source.getRequirement()))
+ .setCheckMethod(StrUtil.nullToEmpty(source.getCheckMethod()))
+ .setGroup(grouped ? groupOf(source) : null)
+ .setUpperLimit(toDouble(source.getUpperLimit()))
+ .setLowerLimit(toDouble(source.getLowerLimit()))
+ .setRemark(mergeRemark(source, foldSampleIntoRemark));
+ }
+
+ /** 杩欎竴琛屾槸涓嶆槸鏌愪釜鍒嗙粍鐨勫瓙椤硅锛堝瓙椤瑰垪涓婃湁鍚嶅瓧锛� */
+ private static boolean grouped(MesQcReportItemRespDTO source) {
+ return StrUtil.isNotBlank(source.getGroupChildName()) || isGroupAnchor(source);
+ }
+
+ /**
+ * 杩欎竴琛屾槸涓嶆槸鍒嗙粍鐨勯敋鐐硅锛堢粍鍚嶅悎骞舵牸鐨勮惤鐐癸級銆�
+ * <p>
+ * 鍒ゆ嵁鏄悎骞惰鏁板ぇ浜� 1锛氱嫭绔嬮」涓庣粍鍐呭叾浣欒鐨勮繖涓�奸兘鏄� 1銆�
+ */
+ private static boolean isGroupAnchor(MesQcReportItemRespDTO source) {
+ return source.getGroupSpan() != null && source.getGroupSpan() > 1;
+ }
+
+ /** 鍒嗙粍淇℃伅閫愰」涓嬪彂锛氫笁涓瓧娈电己涓�涓紝妯℃澘閲屽搴旂殑缁戝畾灏变細鍙栦笉鍒板�� */
+ private static InspectionItem.Group groupOf(MesQcReportItemRespDTO source) {
+ return new InspectionItem.Group()
+ .setChildName(StrUtil.nullToEmpty(source.getGroupChildName()))
+ .setSpan(source.getGroupSpan() == null ? 1 : source.getGroupSpan())
+ .setHidden(StrUtil.nullToEmpty(source.getGroupHidden()));
+ }
+
+ /**
+ * 妫�楠岄」澶囨敞 = 鍗曟嵁琛屽娉� + 瀹炴祴鍊煎娉� + 锛堝鏍峰搧鏃讹級鏍峰搧鍙枫��
+ * <p>
+ * 鏍峰搧鍙峰彧鍦ㄥ鏍峰搧鏃舵墠骞惰繘鏉ワ細鍗曟牱鍝佹椂鎶ュ憡澶村凡缁忓啓浜嗭紝姣忚鍐嶉噸澶嶄竴閬嶇函灞炲櫔澹般��
+ */
+ private static String mergeRemark(MesQcReportItemRespDTO source, boolean foldSampleIntoRemark) {
+ List<String> parts = new ArrayList<>(3);
+ if (foldSampleIntoRemark && StrUtil.isNotBlank(source.getSampleNo())) {
+ parts.add("鏍峰搧 " + source.getSampleNo());
+ }
+ if (StrUtil.isNotBlank(source.getRemark())) {
+ parts.add(source.getRemark().trim());
+ }
+ return String.join("锛�", parts);
+ }
+
+ /** 鎶ュ憡澶淬�屾牱鍝佺紪鍙枫�嶏細鍗曟牱鍝佺洿鎺ユ斁锛屽鏍峰搧鏀惧緱涓嬪氨骞跺垪锛屾斁涓嶄笅灏变氦缁欏娉ㄥ苟鍦ㄦ彁绀洪噷璇存槑 */
+ private static String reportSampleNo(List<String> samples, String qcCode, List<String> warnings) {
+ if (samples.isEmpty()) {
+ return "";
+ }
+ if (samples.size() == 1) {
+ return samples.get(0);
+ }
+ if (samples.size() <= SAMPLE_NO_JOIN_LIMIT) {
+ return String.join("銆�", samples);
+ }
+ warnings.add("璐ㄦ鍗曘��" + StrUtil.nullToEmpty(qcCode) + "銆嶅叡鏈� " + samples.size()
+ + " 涓牱鍝侊紙" + String.join("銆�", samples.subList(0, SAMPLE_NO_JOIN_LIMIT)) + " 绛夛級锛�"
+ + "鎶ュ憡澶淬�屾牱鍝佺紪鍙枫�嶇暀绌猴紝鍚勬牱鍝佺殑瀹炴祴鍊艰瀵瑰簲妫�楠岄」鐨勫娉�");
+ return "";
+ }
+
+ /** 鍒嗙粍娌℃垚缁勩�佽琛ヤ簡琛屻�佹寚鏍囧凡琚垹闄よ繖涓夌鎯呭喌锛氭姤鍛婁笂澶氫簡浠�涔堝皯浜嗕粈涔堥兘瑕佸瀹炶 */
+ private static void appendSkipWarnings(MesQcReportRespDTO data, List<String> warnings) {
+ if (CollUtil.isNotEmpty(data.getChildlessGroupNames())) {
+ warnings.add("浠ヤ笅 " + data.getChildlessGroupNames().size() + " 涓寚鏍囨槸鎸囨爣搴撻噷鐨勫垎缁勯」锛�"
+ + "浣嗘湰鍗曟病鏈夊睘浜庡畠浠殑瀛愰」锛屾姤鍛婇噷鎸夌嫭绔嬫楠岄」鍒楀嚭銆佺粍鍚嶄笉鍚堝苟锛氥��"
+ + String.join("銆�", data.getChildlessGroupNames()) + "銆�");
+ }
+ if (CollUtil.isNotEmpty(data.getSynthesizedGroupNames())) {
+ warnings.add("浠ヤ笅 " + data.getSynthesizedGroupNames().size() + " 涓垎缁勯」鍦ㄦ湰鍗曠殑妫�楠屾槑缁嗛噷娌℃湁鑷繁鐨勮"
+ + "锛堝鍗婃槸妫�楠屾ā鏉垮彧閫変簡瀛愰」锛夛紝鎶ュ憡閲屼负瀹冧滑鍚勮ˉ浜嗕竴琛屾潵鏄剧ず缁勫悕涓庡叕寮忥細銆�"
+ + String.join("銆�", data.getSynthesizedGroupNames()) + "銆�");
+ }
+ if (data.getMissingIndicatorCount() > 0) {
+ warnings.add("鍗曟嵁涓湁 " + data.getMissingIndicatorCount()
+ + " 鏉℃槑缁嗘墍寮曠敤鐨勬楠屾寚鏍囧凡琚垹闄わ紝鏃犳硶杩樺師鎴愭楠岄」锛屽凡璺宠繃");
+ }
+ }
+
+ private static List<String> distinctSamples(List<MesQcReportItemRespDTO> items) {
+ Set<String> samples = new LinkedHashSet<>();
+ for (MesQcReportItemRespDTO item : items) {
+ if (StrUtil.isNotBlank(item.getSampleNo())) {
+ samples.add(item.getSampleNo().trim());
+ }
+ }
+ return new ArrayList<>(samples);
+ }
+
+ private static String formatDate(LocalDateTime value) {
+ return value == null ? "" : INSPECT_DATE_FORMAT.format(value);
+ }
+
+ /** 瑙勬牸涓婁笅闄愬彲浠ヤ负绌猴紙娌℃湁鍖洪棿瑕佹眰锛夛紝绌哄�间繚鎸� null锛屼笉鑳藉彉鎴� 0 */
+ private static Double toDouble(BigDecimal value) {
+ return value == null ? null : value.doubleValue();
+ }
+
+ private static String firstNonBlank(String first, String second) {
+ return StrUtil.isNotBlank(first) ? first.trim() : StrUtil.nullToEmpty(second);
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/PdfArchiveResult.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/PdfArchiveResult.java
new file mode 100644
index 0000000..1709598
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/PdfArchiveResult.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.qcreport.service.instance;
+
+/**
+ * PDF 鍑轰欢缁撴灉銆�
+ *
+ * @param instanceId 鎶ュ憡瀹炰緥缂栧彿
+ * @param reportNo 鎶ュ憡缂栧彿锛堜篃灏辨槸 PDF 鏂囦欢鍚嶏級
+ * @param fileName PDF 鏂囦欢鍚�
+ * @param byteSize PDF 瀛楄妭鏁�
+ * @param blobId 鏂囦欢缂栧彿锛坰ystem_storage_blob锛夛紝鎹㈢粦/鎺掓煡鏃剁敤
+ * @param attachmentId 闄勪欢鍏宠仈缂栧彿锛坰ystem_storage_attachment锛�
+ * @param previewURL 棰勮鍦板潃锛堜复鏃剁鍚嶏紝浼氳繃鏈燂級
+ * @param downloadURL 涓嬭浇鍦板潃锛堜复鏃剁鍚嶏紝浼氳繃鏈燂級
+ * @param durationMs 鏈鍑轰欢鎬昏�楁椂锛堟绉掞級锛氬惈鎺掗槦绛夊苟鍙戝悕棰濄�佸繀瑕佹椂閲嶅惎娴忚鍣ㄧ殑绛夊緟
+ * @param pdfDurationMs 鎵撳嵃鑰楁椂锛堟绉掞級锛氫粎鍚瓑椤甸潰璧勬簮涓� {@code page.pdf()}锛�
+ * 涓� {@code durationMs} 涔嬪樊鍗崇瓑寰呮垚鏈�
+ * @param browserStatus 鏈娴忚鍣ㄧ姸鎬侊細READY锛堝鐢ㄥ疄渚嬶級/ RESTARTED锛堟湰娆¢噸鍚簡娴忚鍣級
+ */
+public record PdfArchiveResult(Long instanceId, String reportNo, String fileName, Long byteSize,
+ Long blobId, Long attachmentId, String previewURL, String downloadURL,
+ Long durationMs, Long pdfDurationMs, String browserStatus) {
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/QcReportInstanceService.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/QcReportInstanceService.java
new file mode 100644
index 0000000..ba57d19
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/QcReportInstanceService.java
@@ -0,0 +1,117 @@
+package cn.iocoder.yudao.module.qcreport.service.instance;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo.QcReportInstanceGenerateFromQcReqVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo.QcReportInstanceGenerateReqVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo.QcReportInstancePageReqVO;
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.instance.QcReportInstanceDO;
+import cn.iocoder.yudao.module.qcreport.engine.render.RenderOutcome;
+
+import java.util.Map;
+
+/**
+ * 鏅鸿兘璐ㄦ鎶ュ憡瀹炰緥 Service 鎺ュ彛銆�
+ * <p>
+ * 杩欓噷鏄�屾ā鏉� 鈫� 鎶ュ憡銆嶇殑鍑轰欢閾捐矾锛氬彇宸插彂甯冪増鏈� 鈫� 娓叉煋 鈫� 钀藉簱骞跺喕缁撴暟鎹揩鐓с��
+ * 鏁版嵁鐢辫皟鐢ㄦ柟浼犺繘鏉ワ紝鏈ā鍧椾笉璁よ瘑浠讳綍涓氬姟鍗曟嵁锛圡ES 璐ㄦ鍗曠殑褰掍竴鍖栫敱 MES 渚ф彁渚涳級銆�
+ */
+public interface QcReportInstanceService {
+
+ /**
+ * 棰勮锛氬彧娓叉煋锛屼笉钀藉簱銆佷笉鐢熸垚缂栧彿銆�
+ *
+ * @param reqVO 鍑轰欢鍏ュ弬
+ * @return 娓叉煋浜х墿锛涙姤鍛婄紪鍙峰彇鍏ュ弬閲屽甫杩囨潵鐨勯偅涓紝娌″甫鍒欎负绌�
+ */
+ RenderOutcome preview(QcReportInstanceGenerateReqVO reqVO);
+
+ /**
+ * 鍑轰欢锛氭覆鏌� + 钀藉簱 + 鍐荤粨鏁版嵁蹇収銆�
+ *
+ * @param reqVO 鍑轰欢鍏ュ弬
+ * @return 鎶ュ憡瀹炰緥涓庢暟鎹己鍙f竻鍗�
+ */
+ GenerateResult generate(QcReportInstanceGenerateReqVO reqVO);
+
+ /**
+ * 鐢辫川妫�鍗曞嚭浠讹細浠� MES 鍙栬川妫�鍗曟暟鎹� 鈫� 鏄犲皠鎴愭姤鍛婁笂涓嬫枃 鈫� 璧版棦鏈夌殑鍑轰欢娴佺▼銆�
+ * <p>
+ * 鍒绘剰涓嶆柊寮�涓�鏉¤惤搴撹矾寰勶細鍐呴儴灏辨槸璋� {@link #generate}锛屼簬鏄増鏈彂甯冩牎楠屻��
+ * 缂栧彿鐢熸垚涓庢挒鍙烽噸璇曘�佹暟鎹揩鐓у喕缁撱�佸垽瀹氬紩鎿庡叏閮ㄧ収鏃х敓鏁堬紝涓�鏉¢兘娌$粫寮�銆�
+ * <p>
+ * 鍑轰欢鍓嶇殑鏍¢獙鎸変笟鍔′紭鍏堢骇鍙姤绗竴澶勶細绫诲瀷涓嶅悎娉� 鈫� 鍗曟嵁涓嶅瓨鍦� 鈫� 鏈畬鎴� 鈫� 鏈垽瀹� 鈫�
+ * 妯℃澘绫诲瀷涓嶇 鈫� 娌℃湁鍙敤妫�楠岄」銆備竴娆℃姏澶氭潯浼氳鐢ㄦ埛鎶撲笉浣忛噸鐐广��
+ *
+ * @param reqVO 璐ㄦ鍗� + 妯℃澘閫夋嫨
+ * @return 鎶ュ憡瀹炰緥涓庢湰娆″嚭浠剁殑鎻愮ず淇℃伅
+ */
+ GenerateFromQcResult generateFromQc(QcReportInstanceGenerateFromQcReqVO reqVO);
+
+ /**
+ * 閲嶆柊鐢熸垚锛氱敤瀹炰緥閲屽喕缁撶殑鏁版嵁蹇収涓庡悓涓�妯℃澘鐗堟湰閲嶆覆锛岃鐩栦骇鐗� HTML銆�
+ * <p>
+ * 蹇収涓庢姤鍛婄紪鍙烽兘涓嶅彉銆傞噸鏂扮敓鎴愮殑鏄�屾帓鐗堛�嶏紝涓嶆槸銆屾暟鎹�嶁�斺�旀暟鎹互蹇収涓哄噯锛�
+ * 涓氬姟绯荤粺閲岀殑鏁版嵁鍚庢潵鎬庝箞鍙橀兘涓嶄細褰卞搷杩欎唤鍘嗗彶鎶ュ憡銆�
+ * <p>
+ * <b>宸插綊妗g殑 PDF 浼氳涓�骞朵綔搴�</b>锛氫骇鐗� HTML 鎹簡锛屽啀鐣欑潃鏃� PDF 灏辨槸銆岄〉闈㈡槸鏂版帓鐗堛��
+ * 涓嬭浇鍒扮殑鏄棫鏂囦欢銆嶇殑闈欓粯涓嶄竴鑷淬�傚畞鍙浜х墿娑堝け锛堥殢鏃跺彲鍐嶅涓�娆★級锛屼篃涓嶇暀杩欑閿欓厤銆�
+ *
+ * @param id 瀹炰緥缂栧彿
+ * @return 鎶ュ憡瀹炰緥涓庢暟鎹己鍙f竻鍗�
+ */
+ GenerateResult regenerate(Long id);
+
+ /**
+ * 瀵煎嚭 PDF锛氭妸瀹炰緥閲�**宸插瓨鐨�**娓叉煋浜х墿 HTML 浜ょ粰 Chromium 鎵撳嵃锛屽苟褰掓。鍒伴檮浠跺簱銆�
+ * <p>
+ * 鍒绘剰涓嶉噸娓诧細璁捐鍣�/璇︽儏椤电湅鍒扮殑 HTML 涓� PDF 蹇呴』鍑鸿嚜鍚屼竴浠藉瓧鑺傦紝
+ * 鍚﹀垯灏变細鍑虹幇銆岄〉闈笂濂藉ソ鐨勩�佹墦鍑烘潵鍙樺舰銆嶈繖绫诲涓嶄笂璐︾殑闂銆傝鎹㈡帓鐗堣鍏堛�岄噸鏂扮敓鎴愩�嶃��
+ * <p>
+ * 褰掓。璧� system 妯″潡鐨勯檮浠朵腑闂磋〃锛坽@code recordType = qc_report_instance}锛夛紝
+ * 鍥犳銆岃繖浠芥姤鍛婃湁娌℃湁 PDF銆佸幓鍝効涓嬭浇銆嶇敤鏍囧噯鐨勯檮浠跺垪琛ㄦ帴鍙e嵆鍙煡鍒般��
+ *
+ * @param id 瀹炰緥缂栧彿
+ * @return 褰掓。鍚庣殑 PDF 淇℃伅涓庤�楁椂
+ */
+ PdfArchiveResult exportPdf(Long id);
+
+ /**
+ * 鏍¢獙瀹炰緥瀛樺湪锛屽苟杩斿洖
+ *
+ * @param id 瀹炰緥缂栧彿
+ * @return 鎶ュ憡瀹炰緥
+ */
+ QcReportInstanceDO validateInstanceExists(Long id);
+
+ /**
+ * 鑾峰緱鎶ュ憡瀹炰緥
+ *
+ * @param id 瀹炰緥缂栧彿
+ * @return 鎶ュ憡瀹炰緥
+ */
+ QcReportInstanceDO getInstance(Long id);
+
+ /**
+ * 鑾峰緱瀹炰緥鍐荤粨鐨勬暟鎹揩鐓�
+ *
+ * @param id 瀹炰緥缂栧彿
+ * @return 鏁版嵁蹇収锛屽舰濡� {@code {report, inspectionItems}}
+ */
+ Map<String, Object> getSnapshot(Long id);
+
+ /**
+ * 鑾峰緱鎶ュ憡瀹炰緥鍒嗛〉
+ *
+ * @param pageReqVO 鍒嗛〉鏌ヨ
+ * @return 瀹炰緥鍒嗛〉
+ */
+ PageResult<QcReportInstanceDO> getInstancePage(QcReportInstancePageReqVO pageReqVO);
+
+ /**
+ * 鍒犻櫎鎶ュ憡瀹炰緥銆傚凡褰掓。鐨� PDF 涓�骞舵竻鐞嗭紝涓嶇暀涓嬫煡涓嶅埌涓讳汉鐨勬枃浠朵笌闄勪欢璁板綍銆�
+ *
+ * @param id 瀹炰緥缂栧彿
+ */
+ void deleteInstance(Long id);
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/QcReportInstanceServiceImpl.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/QcReportInstanceServiceImpl.java
new file mode 100644
index 0000000..3648777
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/QcReportInstanceServiceImpl.java
@@ -0,0 +1,531 @@
+package cn.iocoder.yudao.module.qcreport.service.instance;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.mes.api.qc.MesQcReportApi;
+import cn.iocoder.yudao.module.mes.api.qc.dto.MesQcReportRespDTO;
+import cn.iocoder.yudao.module.qcreport.config.QcReportPdfProperties;
+import cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo.QcReportInstanceGenerateFromQcReqVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo.QcReportInstanceGenerateReqVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.instance.vo.QcReportInstancePageReqVO;
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.instance.QcReportInstanceDO;
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.render.QcReportRenderRecordDO;
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.template.QcReportTemplateDO;
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.version.QcReportTemplateVersionDO;
+import cn.iocoder.yudao.module.qcreport.dal.mysql.instance.QcReportInstanceMapper;
+import cn.iocoder.yudao.module.qcreport.dal.mysql.render.QcReportRenderRecordMapper;
+import cn.iocoder.yudao.module.qcreport.engine.PageSetting;
+import cn.iocoder.yudao.module.qcreport.engine.QualityReportEngine;
+import cn.iocoder.yudao.module.qcreport.engine.context.InspectionItem;
+import cn.iocoder.yudao.module.qcreport.engine.context.ReportContext;
+import cn.iocoder.yudao.module.qcreport.engine.context.ReportContextCodec;
+import cn.iocoder.yudao.module.qcreport.engine.context.ReportFields;
+import cn.iocoder.yudao.module.qcreport.enums.QcReportSourceTypeEnum;
+import cn.iocoder.yudao.module.qcreport.engine.render.RenderOutcome;
+import cn.iocoder.yudao.module.qcreport.service.render.PdfRenderService;
+import cn.iocoder.yudao.module.qcreport.service.render.PdfRenderService.PdfResult;
+import cn.iocoder.yudao.module.qcreport.service.template.QcReportTemplateService;
+import cn.iocoder.yudao.module.qcreport.service.version.QcReportTemplateVersionService;
+import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi;
+import cn.iocoder.yudao.module.system.api.storage.StorageBlobApi;
+import cn.iocoder.yudao.module.system.api.storage.dto.StorageBlobRespDTO;
+import cn.iocoder.yudao.module.system.enums.storage.StorageApplicationTypeEnum;
+import cn.iocoder.yudao.module.system.enums.storage.StorageRecordTypeEnum;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.module.qcreport.enums.QcReportEnums.InstanceStatusEnum.SUCCESS;
+import static cn.iocoder.yudao.module.qcreport.enums.QcReportEnums.TemplateStatusEnum.ENABLE;
+
+/**
+ * 鏅鸿兘璐ㄦ鎶ュ憡瀹炰緥 Service 瀹炵幇绫�
+ */
+@Slf4j
+@Service
+@Validated
+public class QcReportInstanceServiceImpl implements QcReportInstanceService {
+
+ /**
+ * 鑷姩缂栧彿鎾炲彿鍚庣殑閲嶈瘯娆℃暟銆�
+ * <p>
+ * 骞跺彂涓嬩袱涓姹備細绠楀嚭鍚屼竴涓簭鍙凤紝闈� {@code uk_report_no} 鍞竴绱㈠紩鎸′笅鏉ラ噸绠楀嵆鍙紱
+ * 杩炴挒 5 娆″凡缁忚繙瓒呫�屽悓鏃跺嚭涓�浠芥姤鍛娿�嶇殑姝e父骞跺彂锛屽啀澶辫触灏卞瀹炴姤閿欙紝涓嶅仛鏃犻檺閲嶈瘯銆�
+ */
+ private static final int REPORT_NO_MAX_ATTEMPTS = 5;
+
+ /** PDF 鍑轰欢鐨勬枃浠剁被鍨� */
+ private static final String PDF_CONTENT_TYPE = "application/pdf";
+
+ /** 鎶ュ憡 PDF 鎸傚湪闄勪欢搴撻噷鐨勪笟鍔¤褰曠被鍨嬶細涓庡墠绔煡璇㈤檮浠剁敤鐨勬槸鍚屼竴涓�� */
+ private static final String RECORD_TYPE = StorageRecordTypeEnum.QC_REPORT_INSTANCE.getType();
+
+ /** 闄勪欢鐢ㄩ�旓細涓庡墠绔笂浼犺蛋鍚屼竴涓粯璁ゅ�硷紝闄勪欢鍒楄〃鎺ュ彛涔熸槸鎸夊畠杩囨护鐨� */
+ private static final String APPLICATION = StorageApplicationTypeEnum.FILE.getType();
+
+ @Resource
+ private QcReportInstanceMapper instanceMapper;
+
+ @Resource
+ private QcReportTemplateService templateService;
+
+ @Resource
+ private QcReportTemplateVersionService versionService;
+
+ @Resource
+ private QcReportRenderRecordMapper renderRecordMapper;
+
+ @Resource
+ private PdfRenderService pdfRenderService;
+
+ @Resource
+ private QcReportPdfProperties pdfProperties;
+
+ @Resource
+ private StorageBlobApi storageBlobApi;
+
+ @Resource
+ private StorageAttachmentApi storageAttachmentApi;
+
+ @Resource
+ private MesQcReportApi mesQcReportApi;
+
+ @Override
+ public RenderOutcome preview(QcReportInstanceGenerateReqVO reqVO) {
+ QcReportTemplateVersionDO version = resolveVersion(reqVO, false);
+ ReportContext context = prepareContext(reqVO);
+ // 棰勮涓嶇敓鎴愮紪鍙凤細缂栧彿鏄嚭浠舵椂鎵嶇‘瀹氱殑娴佹按鍙凤紝棰勮涓嶈娑堣�楀畠
+ String reportNo = resolveExplicitReportNo(reqVO);
+ if (reportNo != null) {
+ context.getReport().setReportNo(reportNo);
+ }
+ return QualityReportEngine.render(version.getSchema(), context);
+ }
+
+ /**
+ * 鍑轰欢銆�
+ * <p>
+ * 鍒绘剰**涓嶅姞 {@code @Transactional}**锛氭暣娈靛彧鏈変竴娆� insert锛屾病鏈夊璇彞涓�鑷存�ч渶姹傦紱
+ * 涓�鏃﹀寘涓婁簨鍔★紝涓嬮潰閲嶈瘯璺緞閲岃 catch 鎺夌殑 {@link DuplicateKeyException}
+ * 鍙兘鎶婁簨鍔℃爣璁版垚 rollback-only锛屽弽鑰屾妸銆岄噸璇曘�嶅彉鎴愩�屽繀瀹氬け璐ャ�嶃��
+ */
+ @Override
+ public GenerateResult generate(QcReportInstanceGenerateReqVO reqVO) {
+ QcReportTemplateVersionDO version = resolveVersion(reqVO, true);
+ ReportContext context = prepareContext(reqVO);
+
+ String explicitNo = resolveExplicitReportNo(reqVO);
+ if (explicitNo != null) {
+ // 鎸囧畾浜嗙紪鍙凤細姣忔閮芥槸鍚屼竴涓彿锛岄噸璇曟病鏈夋剰涔夛紝鎾炲彿灏辨槑纭姤鍑烘潵
+ if (instanceMapper.selectByReportNo(explicitNo) != null) {
+ throw reportNoTaken(explicitNo);
+ }
+ try {
+ return renderAndPersist(reqVO, version, context, explicitNo);
+ } catch (DuplicateKeyException race) {
+ throw reportNoTaken(explicitNo);
+ }
+ }
+
+ LocalDate day = LocalDate.now();
+ String prefix = ReportNoGenerator.prefix(day);
+ for (int attempt = 0; attempt < REPORT_NO_MAX_ATTEMPTS; attempt++) {
+ String latest = instanceMapper.selectLatestReportNoByPrefix(prefix);
+ String reportNo = ReportNoGenerator.format(day,
+ ReportNoGenerator.nextSequence(latest, day));
+ try {
+ return renderAndPersist(reqVO, version, context, reportNo);
+ } catch (DuplicateKeyException conflict) {
+ // 骞跺彂涓嬪埆鐨勮姹傚垰鎶㈣蛋杩欎釜鍙凤紝閲嶇畻搴忓彿鍐嶈瘯
+ }
+ }
+ throw new ServiceException(REPORT_INSTANCE_NO_DUPLICATE.getCode(),
+ "鑷姩鐢熸垚鎶ュ憡缂栧彿鏃惰繛缁� " + REPORT_NO_MAX_ATTEMPTS + " 娆′笌宸叉湁鎶ュ憡鍐茬獊锛岃绋嶅悗閲嶈瘯锛�"
+ + "涔熷彲鍦ㄨ姹傞噷鏄惧紡鎸囧畾涓�涓湭琚崰鐢ㄧ殑鎶ュ憡缂栧彿");
+ }
+
+ @Override
+ public GenerateFromQcResult generateFromQc(QcReportInstanceGenerateFromQcReqVO reqVO) {
+ QcReportSourceTypeEnum sourceType = validateQcType(reqVO.getQcType());
+ MesQcReportRespDTO data = mesQcReportApi.getQcReportData(reqVO.getQcType(), reqVO.getQcId());
+ if (data == null) {
+ throw new ServiceException(QC_GENERATE_ORDER_NOT_EXISTS.getCode(),
+ sourceType.getName() + "鐨勮川妫�鍗曪紙ID=" + reqVO.getQcId() + "锛変笉瀛樺湪鎴栧凡琚垹闄わ紝"
+ + "璇峰埛鏂板垪琛ㄥ悗閲嶆柊閫夋嫨");
+ }
+ validateOrderUsable(data, sourceType);
+ validateTemplateType(reqVO.getTemplateId(), sourceType);
+
+ if (CollUtil.isEmpty(data.getItems())) {
+ throw new ServiceException(QC_GENERATE_NO_ITEM.getCode(),
+ sourceType.getName() + "鐨勮川妫�鍗曘��" + data.getQcCode() + "銆�"
+ + "锛圛D=" + data.getQcId() + "锛夋病鏈変换浣曟楠屾寚鏍�"
+ + (data.getMissingIndicatorCount() > 0
+ ? "锛堝叾涓� " + data.getMissingIndicatorCount()
+ + " 鏉℃槑缁嗘墍寮曠敤鐨勬楠屾寚鏍囧凡琚垹闄わ級" : "")
+ + "锛屾棤娉曠敓鎴愭姤鍛娿�傝鍏堝湪璇ュ崟鎹笂褰曞叆妫�楠屾寚鏍囦笌瀹炴祴鍊煎悗鍐嶇敓鎴�");
+ }
+
+ MesQcReportContextMapper.Mapped mapped =
+ MesQcReportContextMapper.map(data, StrUtil.trimToNull(reqVO.getReportNo()));
+
+ QcReportInstanceGenerateReqVO generateReq = new QcReportInstanceGenerateReqVO()
+ .setTemplateId(reqVO.getTemplateId())
+ .setVersion(reqVO.getVersion())
+ .setReportNo(reqVO.getReportNo())
+ .setBusinessId(String.valueOf(data.getQcId()))
+ .setBusinessType(sourceType.getBusinessType())
+ .setContext(mapped.context());
+ GenerateResult result = generate(generateReq);
+
+ // 銆屾棤鍒ゅ畾瑙勫垯銆嶄笌銆屽緟鍒ゅ畾銆嶅湪蹇収閲岄兘琛ㄧ幇涓� result 涓虹┖涓诧紙寮曟搸娌$畻鍑虹粨璁猴級锛屾嵁姝ゅ瀹炶鏁般��
+ // 涓嶅彟绠椾竴閬嶅垽瀹氭潯浠讹細閭f牱浼氬拰寮曟搸鐨勫垽瀹氫緷鎹悇璇村悇璇濓紝杩樻紡鎺変簡銆屽崱鍦ㄨ鍒欐姤閿欎笂銆嶇殑椤广��
+ ReportContext frozen = ReportContextCodec.fromMap(result.instance().getDataSnapshot());
+ List<InspectionItem> items = frozen.getInspectionItems();
+ int undecidable = 0;
+ for (InspectionItem item : items) {
+ if (StrUtil.isBlank(item.getResult())) {
+ undecidable++;
+ }
+ }
+ return new GenerateFromQcResult(result.instance(), items.size(), undecidable,
+ mapped.warnings(), result.errors());
+ }
+
+ /** 璐ㄦ绫诲瀷蹇呴』鏄洓绫讳箣涓�锛涗笉鍚堟硶鏃舵妸鏀跺埌鐨勫�煎拰鍏佽鐨勫�奸兘鎽嗗嚭鏉� */
+ private QcReportSourceTypeEnum validateQcType(Integer qcType) {
+ QcReportSourceTypeEnum sourceType = QcReportSourceTypeEnum.of(qcType);
+ if (sourceType == null) {
+ throw new ServiceException(QC_GENERATE_TYPE_INVALID.getCode(),
+ "璐ㄦ绫诲瀷銆�" + qcType + "銆嶄笉鍚堟硶锛屽彧鏀寔 IQC锛堟潵鏂欐楠岋紝鍊� 1锛夈�両PQC锛堣繃绋嬫楠岋紝鍊� 2锛夈��"
+ + "OQC锛堝嚭璐ф楠岋紝鍊� 3锛夈�丷QC锛堥��璐ф楠岋紝鍊� 4锛�");
+ }
+ return sourceType;
+ }
+
+ /** 鍗曟嵁寰楄蛋瀹屾楠屽苟涓旀湁浜烘媿杩囧垽瀹氾紝鎶ュ憡鎵嶆湁鍐呭鍙櫥 */
+ private void validateOrderUsable(MesQcReportRespDTO data, QcReportSourceTypeEnum sourceType) {
+ if (!data.isFinished()) {
+ throw new ServiceException(QC_GENERATE_ORDER_NOT_FINISHED.getCode(),
+ sourceType.getName() + "鐨勮川妫�鍗曘��" + data.getQcCode() + "銆嶏紙ID=" + data.getQcId()
+ + "锛夊綋鍓嶇姸鎬佷负銆�" + data.getStatusName() + "銆嶏紝灏氭湭瀹屾垚妫�楠岋紝涓嶈兘鐢熸垚鎶ュ憡銆�"
+ + "璇峰厛鎶婅鍗曟嵁鎻愪氦骞跺畬鎴愭楠屽垽瀹氬悗鍐嶇敓鎴�");
+ }
+ if (data.getCheckResult() == null) {
+ throw new ServiceException(QC_GENERATE_ORDER_NOT_JUDGED.getCode(),
+ sourceType.getName() + "鐨勮川妫�鍗曘��" + data.getQcCode() + "銆嶏紙ID=" + data.getQcId()
+ + "锛夊皻鏈~鍐欐楠屽垽瀹氾紙褰撳墠涓虹┖锛夛紝涓嶈兘鐢熸垚鎶ュ憡銆�"
+ + "璇峰厛鍦ㄨ鍗曟嵁涓婂~鍐欏垽瀹氱粨璁猴紙鍚堟牸 / 鐗归噰 / 涓嶅悎鏍奸��璐� / 涓嶅悎鏍兼姤搴燂級鍚庡啀鐢熸垚");
+ }
+ }
+
+ /**
+ * 妯℃澘鐨勬姤鍛婄被鍨嬪繀椤讳笌璐ㄦ鍗曚竴鑷淬��
+ * <p>
+ * 鎷﹀湪杩欓噷鏄负浜嗛槻姝€�屾潵鏂欐楠屽崟鍑烘垚鍑鸿揣鎶ュ憡銆嶈繖绉嶄竴鐪奸敊鍒板鎴锋墜閲岀殑浣庣骇閿欒锛�
+ * 鍓嶇閫夋ā鏉挎椂涔熶細鎸夌被鍨嬭繃婊わ紝浣嗚繃婊ゆ槸浣撻獙銆佹牎楠屾墠鏄簳绾裤��
+ */
+ private void validateTemplateType(Long templateId, QcReportSourceTypeEnum sourceType) {
+ QcReportTemplateDO template = templateService.validateTemplateExists(templateId);
+ String reportType = StrUtil.trimToNull(template.getReportType());
+ if (reportType == null) {
+ throw new ServiceException(QC_GENERATE_TEMPLATE_TYPE_MISMATCH.getCode(),
+ "鎶ュ憡妯℃澘銆�" + template.getTemplateName() + "銆嶏紙ID=" + templateId
+ + "锛夋病鏈夎缃姤鍛婄被鍨嬶紝鏃犳硶纭瀹冩槸鍚﹂�傜敤浜�" + sourceType.getName() + "銆�"
+ + "璇峰厛鍒版姤鍛婃ā鏉夸腑鎶娿�屾姤鍛婄被鍨嬨�嶈涓恒��" + sourceType.getName() + "銆嶅悗鍐嶇敓鎴�");
+ }
+ if (!sourceType.matchesTemplateReportType(reportType)) {
+ QcReportSourceTypeEnum templateType = QcReportSourceTypeEnum.of(parseType(reportType));
+ throw new ServiceException(QC_GENERATE_TEMPLATE_TYPE_MISMATCH.getCode(),
+ "鎶ュ憡妯℃澘銆�" + template.getTemplateName() + "銆嶏紙ID=" + templateId + "锛夌殑鎶ュ憡绫诲瀷鏄��"
+ + (templateType == null ? reportType : templateType.getName())
+ + "銆嶏紝涓庢湰娆¤川妫�鍗曠殑绫诲瀷銆�" + sourceType.getName() + "銆嶄笉涓�鑷达紝鏃犳硶鐢熸垚鎶ュ憡銆�"
+ + "璇烽噸鏂伴�夋嫨涓�寮�" + sourceType.getName() + "鐨勬姤鍛婃ā鏉�");
+ }
+ }
+
+ /** 妯℃澘涓婄殑鎶ュ憡绫诲瀷鏄暟瀛楀瓧绗︿覆锛涜В鏋愪笉鍑猴紙鍘嗗彶鑴忔暟鎹級灏辫繑鍥� null锛屼氦缁欒皟鐢ㄦ柟鍥為��灞曠ず鍘熸枃 */
+ private Integer parseType(String reportType) {
+ try {
+ return Integer.valueOf(reportType);
+ } catch (NumberFormatException ignored) {
+ return null;
+ }
+ }
+
+ @Override
+ public GenerateResult regenerate(Long id) {
+ QcReportInstanceDO instance = validateInstanceExists(id);
+ if (CollUtil.isEmpty(instance.getDataSnapshot())) {
+ throw exception(REPORT_INSTANCE_DATA_SNAPSHOT_MISSING);
+ }
+ // 鐢ㄧ敓鎴愭椂鐨勯偅涓増鏈紝涓�**涓嶈姹傚畠鐜板湪浠嶆槸宸插彂甯�**锛氬凡鍙戝竷鐗堟湰鐨勫唴瀹规敼涓嶄簡锛�
+ // 浣嗗畠鍙兘鍚庢潵琚仠鐢紱涓�浠藉凡缁忓嚭杩囩殑鍘嗗彶鎶ュ憡涓嶈鍥犳鍙樻垚鎵撲笉寮�銆�
+ QcReportTemplateVersionDO version = versionService.getVersionByTemplateIdAndVersion(
+ instance.getTemplateId(), instance.getTemplateVersion());
+ if (version == null) {
+ throw exception(TEMPLATE_VERSION_NOT_EXISTS);
+ }
+
+ ReportContext context = ReportContextCodec.fromMap(instance.getDataSnapshot());
+ RenderOutcome outcome = QualityReportEngine.render(version.getSchema(), context);
+
+ QcReportInstanceDO updateObj = new QcReportInstanceDO();
+ updateObj.setId(id);
+ updateObj.setRenderHtml(outcome.html());
+ // 鏈夋剰涓嶈鐩� data_snapshot锛氬喕缁撶殑鏁版嵁鏄巻鍙叉姤鍛婄殑渚濇嵁锛�
+ // 閲嶆柊鐢熸垚鍔ㄧ殑鍙槸鎺掔増浜х墿銆傚紩鎿庡崌绾у悗閲嶆覆鍙兘寰楀埌涓嶅悓鐨� HTML锛岄偅姝f槸銆岄噸鏂扮敓鎴愩�嶈鏈夌殑鏁堟灉銆�
+ instanceMapper.updateById(updateObj);
+
+ // 鎺掔増浜х墿鎹簡锛屼箣鍓嶅綊妗g殑 PDF 灏辨槸鐢ㄦ棫 HTML 鎵撶殑锛氱暀鐫�瀹冪瓑浜庤鐢ㄦ埛涓嬭浇鍒颁竴浠戒笌椤甸潰瀵逛笉涓婄殑鏂囦欢銆�
+ // 瀹佸彲浣滃簾锛堥殢鏃惰兘鍐嶅涓�娆★級锛屼篃涓嶇暀杩欑闈欓粯涓嶄竴鑷淬��
+ storageAttachmentApi.deleteAttachmentsByRecord(RECORD_TYPE, id);
+
+ return new GenerateResult(instance, outcome.errors());
+ }
+
+ @Override
+ public PdfArchiveResult exportPdf(Long id) {
+ QcReportInstanceDO instance = validateInstanceExists(id);
+ if (StrUtil.isBlank(instance.getRenderHtml())) {
+ throw exception(REPORT_INSTANCE_HTML_MISSING);
+ }
+ // 涓� regenerate 鍚屼竴鍙e緞锛氱敤鐢熸垚鏃剁殑閭d釜鐗堟湰锛屼笖涓嶈姹傚畠鐜板湪浠嶆槸宸插彂甯冿紝
+ // 鍘嗗彶鎶ュ憡涓嶈鍥犱负鐗堟湰鍚庢潵琚仠鐢ㄥ氨瀵间笉鍑�
+ QcReportTemplateVersionDO version = versionService.getVersionByTemplateIdAndVersion(
+ instance.getTemplateId(), instance.getTemplateVersion());
+ if (version == null) {
+ throw exception(TEMPLATE_VERSION_NOT_EXISTS);
+ }
+ // 绾稿紶鍑犱綍涓� HTML 閲岄偅琛� @page 鍚屾簮锛孭DF 绾搁潰涓嶅彲鑳藉拰椤甸潰棰勮瀵逛笉涓�
+ PageSetting page = QualityReportEngine.pageOf(version.getSchema());
+
+ LocalDateTime startTime = LocalDateTime.now();
+ long startedAt = System.currentTimeMillis();
+ try {
+ // 鎵撶殑鏄疄渚嬮噷宸插瓨鐨� HTML锛屼笉閲嶆覆锛氳繖鏍枫�岃鎯呴〉鐪嬪埌鐨勩�嶄笌銆屾墦鍑烘潵鐨勩�嶅繀鐒跺嚭鑷悓涓�浠藉瓧鑺�
+ PdfResult pdf = pdfRenderService.render(instance.getRenderHtml(), page,
+ Boolean.TRUE.equals(pdfProperties.getShowPageNumber()));
+
+ String fileName = instance.getReportNo() + ".pdf";
+ Long blobId = storageBlobApi.saveBlob(pdf.content(), fileName, PDF_CONTENT_TYPE);
+ if (blobId == null) {
+ throw new ServiceException(RENDER_PDF_ARCHIVE_FAILED.getCode(),
+ RENDER_PDF_ARCHIVE_FAILED.getMsg() + "锛氭枃浠跺悕銆�" + fileName
+ + "銆嶏紝瀛樻。鍚庢湭鍙栧緱鏂囦欢缂栧彿锛岃绋嶅悗閲嶈瘯");
+ }
+ // 涓夋椤哄簭鏄埢鎰忕殑锛歜indAttachments 鍙崲鍏宠仈銆佷笉鍒犳棫 blob锛屼笉鍏堝垹灏变細姣忓涓�娆�
+ // 鍦ㄧ鐩樹笂澶氱暀涓�浠芥病浜鸿棰嗙殑 PDF锛涜�屻�屽厛鍒犲悗瀛樸�嶅張浼氬湪瀛樻。澶辫触鏃舵妸杩樺ソ鐨勬棫 PDF 涓�璧峰紕涓€��
+ // 鎵�浠ヨ鏂� blob 鍏堣惤鍦帮紝鍐嶅垹鏃х殑锛屾渶鍚庣粦瀹氥��
+ storageAttachmentApi.deleteAttachmentsByRecord(RECORD_TYPE, id);
+ storageAttachmentApi.bindAttachments(APPLICATION, RECORD_TYPE, id, List.of(blobId));
+
+ long durationMs = System.currentTimeMillis() - startedAt;
+ StorageBlobRespDTO archived = findArchived(id, blobId);
+ saveRenderRecord(instance, startTime, durationMs, pdf.pdfDurationMs(), pdf.browserStatus(), null);
+ return new PdfArchiveResult(id, instance.getReportNo(),
+ archived != null && StrUtil.isNotBlank(archived.getName()) ? archived.getName() : fileName,
+ (long) pdf.content().length,
+ blobId,
+ archived == null ? null : archived.getStorageAttachmentId(),
+ archived == null ? null : archived.getPreviewURL(),
+ archived == null ? null : archived.getDownloadURL(),
+ durationMs, pdf.pdfDurationMs(), pdf.browserStatus());
+ } catch (RuntimeException e) {
+ // 澶辫触涔熻鐣欑棔锛埪�41锛夛細鍏堝啓涓�鏉″甫寮傚父鏍堢殑璁板綍锛屽啀鎶婂紓甯稿師鏍锋姏鍑猴紝涓嶅悶
+ saveRenderRecord(instance, startTime,
+ System.currentTimeMillis() - startedAt, null, null, stackTrace(e));
+ throw e;
+ }
+ }
+
+ @Override
+ public QcReportInstanceDO validateInstanceExists(Long id) {
+ QcReportInstanceDO instance = instanceMapper.selectById(id);
+ if (instance == null) {
+ throw exception(REPORT_INSTANCE_NOT_EXISTS);
+ }
+ return instance;
+ }
+
+ @Override
+ public QcReportInstanceDO getInstance(Long id) {
+ return instanceMapper.selectById(id);
+ }
+
+ @Override
+ public Map<String, Object> getSnapshot(Long id) {
+ return validateInstanceExists(id).getDataSnapshot();
+ }
+
+ @Override
+ public PageResult<QcReportInstanceDO> getInstancePage(QcReportInstancePageReqVO pageReqVO) {
+ return instanceMapper.selectPage(pageReqVO);
+ }
+
+ @Override
+ public void deleteInstance(Long id) {
+ validateInstanceExists(id);
+ // 鍏堟竻闄勪欢鍐嶅垹瀹炰緥锛氬疄渚嬩竴娌★紝褰掓。鐨� PDF 灏辨垚浜嗘煡涓嶅埌涓讳汉鐨勬枃浠讹紙闄勪欢琛� + 纾佺洏鏂囦欢鍙屼唤瀛ゅ効锛夈��
+ // 椤哄簭鍙嶈繃鏉ョ殑璇濓紝娓呯悊澶辫触灏卞啀涔熸病鏈轰細琛ユ晳浜嗭紙瀹炰緥宸蹭笉瀛樺湪锛屼笉鐭ラ亾瑕佸垹璋佺殑闄勪欢锛夈��
+ storageAttachmentApi.deleteAttachmentsByRecord(RECORD_TYPE, id);
+ instanceMapper.deleteById(id);
+ }
+
+ /* ------------------------------ 鍐呴儴 ------------------------------ */
+
+ /**
+ * 鍙栧垰缁戝畾鐨勯偅鏉¢檮浠躲��
+ * <p>
+ * 棰勮/涓嬭浇鍦板潃鐢� system 妯″潡绛惧悕鐢熸垚锛屾湰妯″潡涓嶈嚜宸辨嫾 URL锛岀敤瀹屽嵆鍙紙绛惧悕浼氳繃鏈燂紝
+ * 鍓嶇瑕侀暱鏈熷彲鐢ㄧ殑鍦板潃搴旈噸鏂版煡闄勪欢鍒楄〃锛夈��
+ */
+ private StorageBlobRespDTO findArchived(Long id, Long blobId) {
+ List<StorageBlobRespDTO> attachments = storageAttachmentApi.listAttachments(RECORD_TYPE, id);
+ if (CollUtil.isEmpty(attachments)) {
+ return null;
+ }
+ return attachments.stream()
+ .filter(blob -> blobId.equals(blob.getId()))
+ .findFirst()
+ .orElse(attachments.get(0));
+ }
+
+ /**
+ * 鍐欐覆鏌撹褰曪紙搂41锛夈��
+ * <p>
+ * 鍙负鎺掓煡鐢細涓�娆″嚭浠跺崰浜嗗涔呫�佹祻瑙堝櫒浠�涔堢姸鎬併�佸け璐ユ椂寮傚父鏍堟槸浠�涔堛��
+ * 鍥犳**鍐欎笉杩涘幓涓嶈璁╁嚭浠跺け璐�**锛岃繖閲屽悶鎺夊苟璁版棩蹇椼��
+ */
+ private void saveRenderRecord(QcReportInstanceDO instance, LocalDateTime startTime, long durationMs,
+ Long pdfDurationMs, String browserStatus, String errorStack) {
+ try {
+ renderRecordMapper.insert(QcReportRenderRecordDO.builder()
+ .reportId(instance.getId())
+ .templateId(instance.getTemplateId())
+ .businessId(instance.getBusinessId())
+ .renderStartTime(startTime)
+ .renderEndTime(LocalDateTime.now())
+ .renderDuration(durationMs)
+ .pdfDuration(pdfDurationMs)
+ .browserStatus(browserStatus)
+ .errorStack(errorStack)
+ .build());
+ } catch (Exception e) {
+ log.warn("[saveRenderRecord][鎶ュ憡瀹炰緥({}) 鐨勬覆鏌撹褰曞啓鍏ュけ璐ワ紝蹇界暐]", instance.getId(), e);
+ }
+ }
+
+ private String stackTrace(Throwable e) {
+ StringWriter writer = new StringWriter();
+ e.printStackTrace(new PrintWriter(writer));
+ return writer.toString();
+ }
+
+ /**
+ * 瀹氬嚭銆岀敤鍝釜妯℃澘鐗堟湰娓叉煋銆嶏紝骞舵牎楠屽畠鐪熺殑鏈夊唴瀹瑰彲娓层��
+ *
+ * @param requirePublished 鏄惁瑕佹眰鐗堟湰蹇呴』宸插彂甯冦��**鍑轰欢瑕侊紝棰勮涓嶈**锛�
+ * 鍑轰欢浼氭妸鐗堟湰鍙峰喕缁撹繘鎶ュ憡瀹炰緥锛岃�屽疄渚嬮噷鍙鐗堟湰鍙枫�佷笉璁板唴瀹癸紝
+ * 鐢ㄨ崏绋垮嚭浠剁瓑浜庣粰鍘嗗彶鎶ュ憡鍩嬩竴棰椼�岀増鏈彿瀵瑰緱涓娿�佸唴瀹瑰凡缁忓彉浜嗐�嶇殑闆凤紱
+ * 棰勮涓嶈惤搴撱�佷笉鍐荤粨鏁版嵁銆佷笉娑堣�楃紪鍙凤紝鑽夌浼氬彉鍦ㄨ繖閲屾病鏈変换浣曞悗鏋滐紝
+ * 鍙嶈�屻�屼繚瀛樿崏绋� 鈫� 鐐归瑙堛�嶆鏄璁″櫒鐨勪富娴佺▼銆�
+ */
+ private QcReportTemplateVersionDO resolveVersion(QcReportInstanceGenerateReqVO reqVO, boolean requirePublished) {
+ QcReportTemplateDO template = templateService.validateTemplateExists(reqVO.getTemplateId());
+ if (!ENABLE.getStatus().equals(template.getStatus())) {
+ // 涓� createVersion 淇濇寔涓�鑷达細鍋滅敤鐨勬ā鏉夸笉鍐嶄骇鍑烘柊鎶ュ憡锛堝巻鍙叉姤鍛婄殑閲嶆柊鐢熸垚涓嶈蛋杩欐潯璺緞锛�
+ throw exception(TEMPLATE_STATUS_DISABLED);
+ }
+ String version = StrUtil.trimToNull(reqVO.getVersion());
+ if (version == null) {
+ version = StrUtil.trimToNull(template.getCurrentVersion());
+ if (version == null) {
+ throw exception(TEMPLATE_NO_PUBLISHED_VERSION);
+ }
+ }
+ QcReportTemplateVersionDO versionDO = requirePublished
+ ? versionService.getPublishedVersion(template.getId(), version)
+ // 涓嶆牎楠屽彂甯冪姸鎬佹椂鎸夈�屾ā鏉�+鐗堟湰鍙枫�嶇洿鎺ュ彇锛涘彇涓嶅埌浼氳繑鍥� null锛坓etPublishedVersion 鍒欐槸鎶涢敊锛�
+ : versionService.getVersionByTemplateIdAndVersion(template.getId(), version);
+ if (versionDO == null) {
+ throw exception(TEMPLATE_VERSION_NOT_EXISTS);
+ }
+ if (!QualityReportEngine.hasCanvas(versionDO.getSchema())) {
+ // 鐢诲竷鏄┖鐨勶細娓叉煋鍑烘潵浼氭槸涓�寮犵櫧绾革紝涓嶅鐜板湪灏辫娓呮
+ throw exception(TEMPLATE_VERSION_CANVAS_EMPTY);
+ }
+ return versionDO;
+ }
+
+ /** 鏍¢獙娓叉煋鍏ュ弬锛氭病鏈夋楠岄」鐨勩�屾姤鍛娿�嶆病鏈夋剰涔夛紝鎶ュ嚭鏉ユ瘮缁欎竴寮犵┖琛ㄥソ */
+ private ReportContext prepareContext(QcReportInstanceGenerateReqVO reqVO) {
+ ReportContext context = reqVO.getContext();
+ // 璇锋眰浣撻噷鏄惧紡浼� "report": null 浼氭妸瀹冪疆绌猴紝杩欓噷鍏滃洖榛樿瀛楁闆嗭紝
+ // 鍚﹀垯 reportMap() 浼氬湪娓叉煋娣卞鎶� NPE锛岀敤鎴峰彧鐪嬪埌銆岀郴缁熷紓甯搞��
+ if (context.getReport() == null) {
+ context.setReport(new ReportFields());
+ }
+ if (CollUtil.isEmpty(context.getInspectionItems())) {
+ throw new ServiceException(RENDER_BUSINESS_DATA_MISSING.getCode(),
+ "妫�楠岄」鍒楄〃涓虹┖锛屾病鏈夊彲鍒ゅ畾鐨勫唴瀹癸細璇疯嚦灏戜紶鍏ヤ竴涓楠岄」锛坕nspectionItems锛夊啀鍑轰欢");
+ }
+ return context;
+ }
+
+ /** 璋冪敤鏂规寚瀹氱殑缂栧彿锛氶《灞� reportNo 浼樺厛锛屽叾娆℃姤鍛婂瓧娈甸噷鐨� reportNo */
+ private String resolveExplicitReportNo(QcReportInstanceGenerateReqVO reqVO) {
+ String fromRequest = StrUtil.trimToNull(reqVO.getReportNo());
+ if (fromRequest != null) {
+ return fromRequest;
+ }
+ ReportFields report = reqVO.getContext().getReport();
+ return report == null ? null : StrUtil.trimToNull(report.getReportNo());
+ }
+
+ /**
+ * 娓叉煋骞惰惤搴撱��
+ * <p>
+ * 鐢熸晥缂栧彿瑕佸啓鍥炰笂涓嬫枃鍐嶆覆鏌撯�斺�旂焊闈笂鐨勬姤鍛婄紪鍙蜂笌瀹炰緥缂栧彿蹇呴』鏄悓涓�涓紝
+ * 涓嶈兘鍑虹幇銆屾姤鍛婁笂鍗扮潃涓�涓彿銆佺郴缁熼噷瀛樼潃鍙︿竴涓彿銆嶃��
+ */
+ private GenerateResult renderAndPersist(QcReportInstanceGenerateReqVO reqVO, QcReportTemplateVersionDO version,
+ ReportContext context, String reportNo) {
+ context.getReport().setReportNo(reportNo);
+ RenderOutcome outcome = QualityReportEngine.render(version.getSchema(), context);
+
+ QcReportInstanceDO instance = QcReportInstanceDO.builder()
+ .reportNo(reportNo)
+ .templateId(version.getTemplateId())
+ .templateVersion(version.getVersion())
+ .businessId(reqVO.getBusinessId())
+ .businessType(reqVO.getBusinessType())
+ // 鍐荤粨銆屽垽瀹氬悗銆嶇殑涓婁笅鏂囷細杩欐墠鏄骇鍑鸿繖浠� HTML 鐨勯偅浠芥暟鎹紝鍚畻濂界殑 PASS/FAIL 涓庡悎鏍肩巼
+ .dataSnapshot(outcome.context().toScope())
+ .renderHtml(outcome.html())
+ .status(SUCCESS.getStatus())
+ .build();
+ instanceMapper.insert(instance);
+
+ return new GenerateResult(instance, outcome.errors());
+ }
+
+ private ServiceException reportNoTaken(String reportNo) {
+ return new ServiceException(REPORT_INSTANCE_NO_DUPLICATE.getCode(),
+ "鎶ュ憡缂栧彿銆�" + reportNo + "銆嶅凡琚崰鐢紝璇锋崲涓�涓紪鍙凤紝鎴栫暀绌虹敱绯荤粺鎸� QR+鏃ユ湡+娴佹按 鑷姩鐢熸垚");
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/ReportNoGenerator.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/ReportNoGenerator.java
new file mode 100644
index 0000000..40b2b4f
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/instance/ReportNoGenerator.java
@@ -0,0 +1,85 @@
+package cn.iocoder.yudao.module.qcreport.service.instance;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Locale;
+
+/**
+ * 鎶ュ憡缂栧彿鐢熸垚銆�
+ * <p>
+ * 鏍煎紡 {@code QR + yyyyMMdd + "-" + 4 浣嶆祦姘磢锛屼緥濡� {@code QR20260918-0001}銆�
+ * 娴佹按鎸夊ぉ鐙珛锛岃法澶╀粠 0001 閲嶆柊寮�濮嬧�斺�旀姤鍛婄紪鍙锋槸缁欎汉鐪嬬殑鍗曟嵁鍙凤紝鎸夊ぉ鍒嗘鏈�濂藉康銆佹渶濂芥壘銆�
+ * <p>
+ * 杩欓噷鍙礋璐c�岀畻銆嶏細鍙栧綋澶╂祦姘淬�佹嫾瀛楃涓层�傝惤搴撴椂鐨勫苟鍙戝啿绐佺敱璋冪敤鏂归噸璇曞厹搴曪紝
+ * 鎵�浠ヨ繖涓被涓嶄緷璧栨暟鎹簱銆佷笉渚濊禆 Spring锛屽彲浠ョ洿鎺ュ崟娴嬨��
+ */
+public final class ReportNoGenerator {
+
+ /** 缂栧彿鍓嶇紑銆俀R = Quality Report */
+ private static final String PREFIX = "QR";
+
+ /**
+ * 鍚屾牱閿� {@link Locale#ROOT}锛歿@code ofPattern} 鍙栭粯璁� locale锛�
+ * 鑰岄粯璁� locale 鑷甫鍘嗘硶锛堝娉板巻锛夛紝浼氳骞翠唤鏁翠綋鍋忕Щ銆�
+ */
+ private static final DateTimeFormatter DAY_FORMAT =
+ DateTimeFormatter.ofPattern("yyyyMMdd", Locale.ROOT);
+
+ /** 搴忓彿浣嶆暟涓嶈冻鏃惰ˉ鍒拌繖涓暱搴� */
+ private static final int SEQUENCE_WIDTH = 4;
+
+ /**
+ * 搴忓彿鏈�澶氳杩欎箞闀裤�傜紪鍙风敱鏈被鐢熸垚锛屾甯稿氨鏄� 4~6 浣嶏紱
+ * 鍑虹幇鏇撮暱鐨勫熬宸磋鏄庡瓨杩涘幓鐨勪笉鏄湰鐢熸垚鍣ㄧ殑浜х墿锛屽綋浣溿�屼笉璁よ瘑銆嶈�屼笉鏄‖瑙f瀽銆�
+ */
+ private static final int MAX_SEQUENCE_DIGITS = 9;
+
+ private ReportNoGenerator() {
+ }
+
+ /** 鏌愬ぉ鐨勭紪鍙峰墠缂�锛屽舰濡� {@code QR20260918-} */
+ public static String prefix(LocalDate day) {
+ return PREFIX + DAY_FORMAT.format(day) + "-";
+ }
+
+ /**
+ * 鎷煎嚭瀹屾暣鎶ュ憡缂栧彿锛屽舰濡� {@code QR20260918-0001}锛涘簭鍙疯秴杩� 9999 鏃惰嚜鐒跺姞瀹姐��
+ * <p>
+ * 閿� {@link Locale#ROOT}锛歿@code %d} 浼氳窡闅忛粯璁� locale 閫夋暟瀛楀瓧褰紝
+ * 鏈嶅姟鍣� locale 涓�鏃︿笉鏄媺涓佽绯伙紝缂栧彿閲屽氨浼氬嚭鐜伴樋鎷変集-鍗板害鏁板瓧涔嬬被鐨勯潪 ASCII 瀛楃銆�
+ */
+ public static String format(LocalDate day, int sequence) {
+ return prefix(day) + String.format(Locale.ROOT, "%0" + SEQUENCE_WIDTH + "d", sequence);
+ }
+
+ /**
+ * 鐢便�屽綋澶╁凡鏈夌殑鏈�澶х紪鍙枫�嶆帹鍑轰笅涓�涓簭鍙枫��
+ * <p>
+ * 涓嶆槸鍚屼竴澶┿�佹牸寮忎笉璁よ瘑銆佹垨杩樻病鏈変换浣曠紪鍙锋椂锛岄兘浠� 1 寮�濮嬶細杩欎簺鎯呭喌閮芥剰鍛崇潃
+ * 銆屼粖澶╂槸绗竴澶┿�嶏紝鑰屼笉鏄嚭閿欌�斺�旀瘮濡備紶杩涙潵鐨勬槸鏄ㄥぉ鐨勫彿銆�
+ *
+ * @param latestReportNo 褰撳ぉ宸叉湁鐨勬渶澶ф姤鍛婄紪鍙凤紝鍙负 null
+ * @param day 鍑轰欢褰撳ぉ
+ * @return 涓嬩竴涓簭鍙凤紝鑷冲皯涓� 1
+ */
+ public static int nextSequence(String latestReportNo, LocalDate day) {
+ if (latestReportNo == null) {
+ return 1;
+ }
+ String prefix = prefix(day);
+ if (!latestReportNo.startsWith(prefix)) {
+ return 1;
+ }
+ String tail = latestReportNo.substring(prefix.length());
+ if (tail.length() < SEQUENCE_WIDTH || tail.length() > MAX_SEQUENCE_DIGITS) {
+ return 1;
+ }
+ for (int i = 0; i < tail.length(); i++) {
+ if (!Character.isDigit(tail.charAt(i))) {
+ return 1;
+ }
+ }
+ return Integer.parseInt(tail) + 1;
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/render/BrowserManager.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/render/BrowserManager.java
new file mode 100644
index 0000000..b5306ec
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/render/BrowserManager.java
@@ -0,0 +1,229 @@
+package cn.iocoder.yudao.module.qcreport.service.render;
+
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.module.qcreport.config.QcReportPdfProperties;
+import com.microsoft.playwright.Browser;
+import com.microsoft.playwright.BrowserType;
+import com.microsoft.playwright.Page;
+import com.microsoft.playwright.Playwright;
+import com.microsoft.playwright.PlaywrightException;
+import jakarta.annotation.PostConstruct;
+import jakarta.annotation.PreDestroy;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+
+import java.nio.file.Path;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.RENDER_PDF_BROWSER_LAUNCH_FAILED;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.RENDER_PDF_BUSY;
+
+/**
+ * PDF 娓叉煋鐢ㄧ殑娴忚鍣ㄦ寔鏈夎��
+ * <p>
+ * 鏁翠釜杩涚▼鍙惎涓�涓� {@link Playwright} 涓庝竴涓� {@link Browser}锛氳璁℃枃妗� 搂30 鏄庢枃绂佹
+ * 銆屾瘡娆¤姹� launch 鈫� 鐢熸垚 鈫� close銆嶁�斺�擟hromium 鍐峰惎鍔ㄤ互绉掕锛屾瘡娆¢噸鍚細璁╁嚭浠舵參鍒颁笉鍙敤锛�
+ * 涔熷鏄撴妸鍐呭瓨鍚冨厜銆傚惎鍔ㄦ槸鎳掔殑锛氭病鏈� PDF 闇�姹傚氨涓嶈鎷夎捣涓�涓祻瑙堝櫒杩涚▼銆�
+ * <p>
+ * 鍊熷嚭鏈熼棿鐢� {@link Semaphore} 璁鹃椄锛埪�30/搂39 瑕佹眰鎺у埗 Playwright 骞跺彂锛夛紝
+ * 鎺掗槦瓒呰繃 {@code timeoutMs} 鐩存帴鎶ュ繖锛屼笉鏃犻檺鍫嗙Н锛涙瘡娆″�熷嚭鍓嶆鏌� {@link Browser#isConnected()}锛�
+ * 鏂繛锛堟祻瑙堝櫒宕╂簝/琚閮ㄦ潃鎺夛級灏遍噸鍚竴涓紝涓嶈涓�娆″穿婧冩妸鍚庣画鎵�鏈夊嚭浠堕兘鎷栨銆�
+ */
+@Slf4j
+@Component
+public class BrowserManager {
+
+ /** 鏈澶嶇敤浜嗗凡鍦ㄨ繍琛岀殑娴忚鍣ㄥ疄渚� */
+ public static final String STATUS_READY = "READY";
+ /** 鏈鍙戠幇娴忚鍣ㄤ笉鍙敤锛堣繕娌″惎杩囷紝鎴栧凡鏂紑锛夛紝閲嶆柊鍚姩浜嗕竴涓� */
+ public static final String STATUS_RESTARTED = "RESTARTED";
+
+ /**
+ * Playwright 璁ょ殑銆屽埆涓嬭浇鑷甫娴忚鍣ㄣ�嶅紑鍏炽��
+ * <p>
+ * 閫氳繃 {@link Playwright.CreateOptions#setEnv} 浼犵粰椹卞姩杩涚▼锛屾晥鏋滅瓑鍚屼簬鍦ㄦ満鍣ㄤ笂璁捐繖涓幆澧冨彉閲忥紝
+ * 浣嗕笉闇�瑕佽繍缁村幓鏀瑰惎鍔ㄨ剼鏈� 鈥斺�� 椤圭洰鍦ㄥ摢鍙版満鍣ㄤ笂璺戦兘涓�鑷淬��
+ */
+ private static final String SKIP_BROWSER_DOWNLOAD_ENV = "PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD";
+
+ @Resource
+ private QcReportPdfProperties properties;
+
+ /** 骞跺彂鍚嶉銆傚�熷嚭鏈熼棿鍗犱竴涓紝鐢ㄥ畬褰掕繕 */
+ private volatile Semaphore slots;
+
+ /** 淇濇姢 {@link #playwright} / {@link #browser} 鐨勫惎鍔ㄣ�侀噸鍚笌鍏抽棴 */
+ private final Object browserLock = new Object();
+
+ private Playwright playwright;
+ private Browser browser;
+
+ @PostConstruct
+ public void init() {
+ Integer concurrency = properties.getConcurrency();
+ this.slots = new Semaphore(concurrency == null || concurrency < 1 ? 1 : concurrency);
+ }
+
+ /**
+ * 鍊熶竴涓〉闈㈡墽琛� {@code action}锛氳礋璐e苟鍙戣闂搞�佹祻瑙堝櫒淇濇椿銆侀〉闈㈠叧闂笌鍚嶉褰掕繕銆�
+ *
+ * @return 鍔ㄤ綔杩斿洖鍊� + 鏈娴忚鍣ㄧ姸鎬侊紙{@link #STATUS_READY} / {@link #STATUS_RESTARTED}锛夛紝鍚庤�呬緵娓叉煋璁板綍鐣欑棔
+ */
+ public <T> PageResult<T> withPage(Function<Page, T> action) {
+ if (!tryAcquire()) {
+ throw new ServiceException(RENDER_PDF_BUSY.getCode(),
+ RENDER_PDF_BUSY.getMsg() + "锛堝綋鍓嶅苟鍙戜笂闄� " + properties.getConcurrency()
+ + "锛岃绛夊墠涓�涓换鍔$粨鏉熷悗閲嶈瘯锛�");
+ }
+ try {
+ boolean restarted = false;
+ Browser target;
+ synchronized (browserLock) {
+ if (browser != null && browser.isConnected()) {
+ target = browser;
+ } else {
+ target = launchBrowser();
+ restarted = true;
+ }
+ }
+ Page page = target.newPage();
+ try {
+ return new PageResult<>(action.apply(page), restarted ? STATUS_RESTARTED : STATUS_READY);
+ } finally {
+ closePage(page);
+ }
+ } finally {
+ slots.release();
+ }
+ }
+
+ @PreDestroy
+ public void destroy() {
+ synchronized (browserLock) {
+ closeBrowser();
+ if (playwright != null) {
+ try {
+ playwright.close();
+ } catch (Exception e) {
+ log.warn("[destroy][鍏抽棴 Playwright 澶辫触]", e);
+ }
+ playwright = null;
+ }
+ }
+ }
+
+ private boolean tryAcquire() {
+ Long configured = properties.getTimeoutMs();
+ long timeoutMs = configured == null || configured < 1 ? 30000L : configured;
+ try {
+ return slots.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return false;
+ }
+ }
+
+ /**
+ * 鍚姩娴忚鍣ㄣ�傝皟鐢ㄦ柟蹇呴』鎸佹湁 {@link #browserLock}銆�
+ * <p>
+ * 鍚姩鍙傛暟浼樺厛绾э細{@code executable-path} > {@code channel} > Playwright 鑷甫鐨� Chromium銆�
+ */
+ private Browser launchBrowser() {
+ closeBrowser();
+ BrowserType.LaunchOptions options = new BrowserType.LaunchOptions().setHeadless(true);
+ String executablePath = text(properties.getExecutablePath());
+ String channel = text(properties.getChannel());
+ if (executablePath != null) {
+ options.setExecutablePath(Path.of(executablePath));
+ } else if (channel != null) {
+ options.setChannel(channel);
+ }
+ List<String> args = properties.getBrowserArgs();
+ if (args != null && !args.isEmpty()) {
+ options.setArgs(args);
+ }
+ try {
+ if (playwright == null) {
+ playwright = createPlaywright(channel, executablePath);
+ }
+ Browser launched = playwright.chromium().launch(options);
+ this.browser = launched;
+ log.info("[launchBrowser][PDF 娓叉煋娴忚鍣ㄥ凡鍚姩锛屾潵婧�({})锛岀増鏈�({})]",
+ describeSource(channel, executablePath), launched.version());
+ return launched;
+ } catch (PlaywrightException e) {
+ closeBrowser();
+ throw new ServiceException(RENDER_PDF_BROWSER_LAUNCH_FAILED.getCode(),
+ RENDER_PDF_BROWSER_LAUNCH_FAILED.getMsg() + "锛氭祻瑙堝櫒鏉ユ簮涓�"
+ + describeSource(channel, executablePath) + "锛屽疄闄呭師鍥犳槸銆�" + e.getMessage()
+ + "銆嶃�傝纭璇ユ祻瑙堝櫒宸插畨瑁呭湪璇ユ満鍣ㄤ笂骞跺湪 yudao.qcreport.pdf.executable-path 涓寚鍚戝叾鍙墽琛屾枃浠讹紱"
+ + "鎴栨妸 channel 鐣欑┖銆佹墽琛� playwright install chromium 鍚庝娇鐢� Playwright 鑷甫鐨� Chromium銆�");
+ }
+ }
+
+ /**
+ * 鍚姩 Playwright 椹卞姩銆�
+ * <p>
+ * <b>鐢ㄦ満鍣ㄨ嚜甯︾殑娴忚鍣ㄦ椂锛屽繀椤昏瀹冭烦杩囥�屼笅杞� Playwright 鑷甫娴忚鍣ㄣ�嶈繖涓�姝ャ��</b>
+ * 鍚﹀垯 {@code Playwright.create()} 浼氬悓姝ユ墽琛屼竴娆� {@code playwright install}锛坈hromium + firefox + webkit锛�
+ * 鍑犵櫨 MB锛夛紱澶栫綉涓嶉�氱殑鐜涓嬪畠浼氬厛鍗℃弧 10 鍒嗛挓鍐嶆姏
+ * {@code Timed out waiting for browsers to install} 鈥斺�� 棣栨瀵煎嚭鐩存帴鍙樻垚涓�娆″崄鍒嗛挓鐨勬寕璧枫��
+ * 鎴戜滑鏃㈢劧宸茬粡鏈� Chrome 鍙墦锛坽@code executable-path} 鎴� {@code channel}锛夛紝杩欎唤鑷甫娴忚鍣ㄥ氨鏄浣欑殑銆�
+ * <p>
+ * 鍙嶄箣锛屼袱鑰呴兘娌¢厤锛堝嵆鏄庣‘瑕佺敤鑷甫 Chromium锛夋椂涓嶅姞杩欎釜鍙橀噺锛氶偅鏃剁‘瀹為渶瑕� Playwright 鑷繁鍘昏锛�
+ * 瑁呬笉涓婁細鍦� {@link com.microsoft.playwright.BrowserType#launch} 澶勬姤鏄庣‘閿欒銆�
+ */
+ private Playwright createPlaywright(String channel, String executablePath) {
+ Playwright.CreateOptions options = new Playwright.CreateOptions();
+ if (channel != null || executablePath != null) {
+ options.setEnv(Map.of(SKIP_BROWSER_DOWNLOAD_ENV, "1"));
+ }
+ return Playwright.create(options);
+ }
+
+ private String describeSource(String channel, String executablePath) {
+ if (executablePath != null) {
+ return "executable-path=" + executablePath;
+ }
+ if (channel != null) {
+ return "channel=" + channel;
+ }
+ return "Playwright 鑷甫 Chromium";
+ }
+
+ private static String text(String value) {
+ return StringUtils.hasText(value) ? value.trim() : null;
+ }
+
+ private void closeBrowser() {
+ if (browser != null) {
+ try {
+ browser.close();
+ } catch (Exception e) {
+ log.warn("[closeBrowser][鍏抽棴娴忚鍣ㄥけ璐ワ紝蹇界暐骞堕噸寤篯", e);
+ }
+ browser = null;
+ }
+ }
+
+ private void closePage(Page page) {
+ try {
+ page.close();
+ } catch (Exception e) {
+ log.warn("[closePage][鍏抽棴椤甸潰澶辫触锛屽拷鐣", e);
+ }
+ }
+
+ /**
+ * 鍊熷嚭缁撴灉锛氬姩浣滆繑鍥炲�� + 鏈娴忚鍣ㄧ姸鎬併��
+ */
+ public record PageResult<T>(T value, String browserStatus) {
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/render/PdfPrintOptions.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/render/PdfPrintOptions.java
new file mode 100644
index 0000000..a2f0fa4
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/render/PdfPrintOptions.java
@@ -0,0 +1,76 @@
+package cn.iocoder.yudao.module.qcreport.service.render;
+
+import cn.iocoder.yudao.module.qcreport.engine.Numbers;
+import cn.iocoder.yudao.module.qcreport.engine.PageSetting;
+import cn.iocoder.yudao.module.qcreport.engine.PageSizes;
+import cn.iocoder.yudao.module.qcreport.engine.ResolvedPage;
+
+/**
+ * 鎵撳嵃鍙傛暟锛氭妸绾稿紶閰嶇疆鎹㈢畻鎴� Chromium 鎵撳嵃 PDF 闇�瑕佺殑鍑犱綍涓庢牱寮忋��
+ * <p>
+ * 绾嚱鏁般�佷笉渚濊禆 Spring 涓� Playwright锛屼究浜庡崟娴嬨��
+ * <p>
+ * 鍑犱綍**涓�寰�**浠� {@link PageSizes#resolve} 鍙栵紝涓� {@code HtmlRenderer} 鍐欒繘 HTML 鐨勯偅琛�
+ * {@code @page { size: 鈥�; margin: 鈥�; }} 鍚屼竴涓潵婧愩�佸悓涓�涓暟瀛楁牸寮忓寲鍑芥暟
+ * 锛坽@link Numbers#toString(double)}锛夛紝鍥犳涓嶅瓨鍦ㄣ�孭DF 绾搁潰涓庨〉闈㈤瑙堝涓嶄笂銆嶇殑鍙兘銆�
+ * 鐢� {@code String.format} 浼氬紩鍏� locale 宸紓骞惰緭鍑� {@code 210.0} 杩欑被涓庡墠绔笉涓�鑷寸殑鏂囨湰銆�
+ */
+public record PdfPrintOptions(String widthCss, String heightCss,
+ String marginTopCss, String marginRightCss,
+ String marginBottomCss, String marginLeftCss,
+ String footerTemplate, String printCss) {
+
+ /**
+ * 浠呬緵鎵撳嵃鐨勫姞鍥烘牱寮忥紝鐢� Playwright {@code addStyleTag} 娉ㄥ叆銆�
+ * <p>
+ * <b>涓嶈兘鍐欒繘娓叉煋寮曟搸鐨� BASE_CSS</b>锛氫骇鐗� HTML 涓庡墠绔喕缁撴牱渚嬫槸閫愬瓧姣斿鐨勶紝
+ * 鍔ㄥ畠浼氳瀛橀噺鎶ュ憡鐨勩�岄噸鏂扮敓鎴愩�嶇粨鏋滃彉鏍枫��
+ * <p>
+ * <b>{@code break-inside: avoid} 缁濅笉鑳藉姞鍦� {@code table} 涓�</b>锛氶偅鏄�屾暣寮犺〃涓嶈璺ㄩ〉銆嶏紝
+ * 闀胯〃鍦ㄤ竴椤垫斁涓嶄笅鏃朵細琚暣浣撴惉鍒颁笅涓�椤碉紝绗� 1 椤靛彧鍓╅〉鐪変笌澶х墖绌虹櫧锛堝凡瀹為檯瑙傛祴鍒帮紝
+ * 60 琛屾楠岄」鐨勮〃灏辨槸濡傛锛夈�傞暱琛ㄨ法椤甸潬鐨勬槸 {@code thead} 鍦ㄦ瘡椤甸噸澶嶈〃澶� + 琛屽唴涓嶆柇椤碉紝
+ * 鎵�浠ュ悕鍗曢噷淇濈暀 {@code tr/td/th/img}銆佸幓鎺� {@code table}銆�
+ */
+ public static final String PRINT_CSS = """
+ thead { display: table-header-group; }
+ tfoot { display: table-footer-group; }
+ tr, td, th, img { break-inside: avoid; page-break-inside: avoid; }
+ body { -webkit-print-color-adjust: exact; print-color-adjust: exact; }""";
+
+ /**
+ * 椤佃剼妯℃澘銆侾laywright 鐨� header/footer 妯℃澘涓嶈繘娴忚鍣ㄩ粯璁ゆ牱寮忥紝
+ * 蹇呴』鑷甫鍐呰仈鏍峰紡涓庡瓧鍙凤紝鍚﹀垯鏄� 0 鍙峰瓧鐪嬩笉瑙併��
+ */
+ private static final String FOOTER_TEMPLATE = """
+ <div style="width:100%;font-size:9px;font-family:'Microsoft YaHei',sans-serif;\
+ color:#333;text-align:center;padding:0 10mm;">绗� <span class="pageNumber"></span> \
+ 椤� / 鍏� <span class="totalPages"></span> 椤�</div>""";
+
+ /**
+ * 椤电湁妯℃澘锛氫竴涓┖ div銆�
+ * <p>
+ * 蹇呴』鏄惧紡缁欎竴涓�<b>闈� null</b> 鐨勫�笺�傚紑浜� {@code displayHeaderFooter} 鍗存妸 headerTemplate
+ * 鐣欑┖鏃讹紝Chromium 浼氱敤瀹冭嚜宸辩殑榛樿椤电湁 鈥斺�� 宸︿笂瑙掓墦鍗版棩鏈燂紙{@code 2026/9/18 21:34}锛夈��
+ * 鍙充笂瑙掓枃妗f爣棰樸�傞偅涓や覆涓滆タ娌′汉瑕佽繃锛岄〉鐪夋椂闂磋繕瀹规槗琚褰撴垚鎶ュ憡鍑哄叿鏃堕棿锛�
+ * 鎵�浠ヨ繖閲岀敤涓�涓┖ div 鎶婂畠椤舵帀锛岄〉闈笂鍙繚鐣欐垜浠嚜宸辩殑椤佃剼椤电爜銆�
+ */
+ public static final String HEADER_TEMPLATE = "<div></div>";
+
+ public static PdfPrintOptions of(PageSetting page, boolean withPageNumber) {
+ ResolvedPage resolved = PageSizes.resolve(page);
+ return new PdfPrintOptions(
+ mm(resolved.widthMm()),
+ mm(resolved.heightMm()),
+ mm(resolved.marginTopMm()),
+ mm(resolved.marginRightMm()),
+ mm(resolved.marginBottomMm()),
+ mm(resolved.marginLeftMm()),
+ withPageNumber ? FOOTER_TEMPLATE : "",
+ PRINT_CSS);
+ }
+
+ private static String mm(double value) {
+ return Numbers.toString(value) + "mm";
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/render/PdfRenderService.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/render/PdfRenderService.java
new file mode 100644
index 0000000..080cb32
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/render/PdfRenderService.java
@@ -0,0 +1,104 @@
+package cn.iocoder.yudao.module.qcreport.service.render;
+
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.module.qcreport.config.QcReportPdfProperties;
+import cn.iocoder.yudao.module.qcreport.engine.PageSetting;
+import com.microsoft.playwright.Page;
+import com.microsoft.playwright.PlaywrightException;
+import com.microsoft.playwright.options.Margin;
+import com.microsoft.playwright.options.WaitUntilState;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.RENDER_PDF_DISABLED;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.RENDER_PDF_FAILED;
+
+/**
+ * PDF 娓叉煋锛氭妸鎶ュ憡 HTML 浜ょ粰 Chromium 鎵撳嵃
+ * <p>
+ * 鎵撳嵃鐨勬槸**璋冪敤鏂圭粰鐨� HTML 鍘熸枃**锛岃繖閲屼笉閲嶆覆銆佷笉纰版覆鏌撳紩鎿庛�傛姤鍛婂疄渚嬪瓨鐫�浠�涔� HTML锛�
+ * PDF 灏辨槸浠�涔堟牱瀛� 鈥斺�� 璁捐鏂囨。 搂32 瑕佹眰銆屼笉瑕佸嚭鐜拌璁″櫒鏄剧ず姝e父浣� PDF 涓ラ噸鍙樺舰銆嶏紝
+ * 鑰屼繚璇佽繖涓�鐐圭殑鍞竴鍔炴硶灏辨槸璁╀袱鑰呭嚭鑷悓涓�浠藉瓧鑺傦紱HTML 闇�瑕侀噸鎺掓槸銆岄噸鏂扮敓鎴愩�嶇殑鑱岃矗銆�
+ */
+@Service
+public class PdfRenderService {
+
+ @Resource
+ private QcReportPdfProperties properties;
+
+ @Resource
+ private BrowserManager browserManager;
+
+ /**
+ * 娓叉煋 PDF
+ *
+ * @param html 鎶ュ憡 HTML 鍘熸枃锛堝疄渚嬮噷宸插瓨鐨勬覆鏌撲骇鐗╋級
+ * @param page 绾稿紶閰嶇疆锛岀獥鍙eぇ灏忎笌椤佃竟璺濈敱瀹冩崲绠楄�屾潵锛屼笌 HTML 閲岀殑 {@code @page} 鍚屾簮
+ * @param withPageNumber 鏄惁鎵撳嵃椤佃剼銆岀 N 椤� / 鍏� M 椤点��
+ */
+ public PdfResult render(String html, PageSetting page, boolean withPageNumber) {
+ if (!Boolean.TRUE.equals(properties.getEnabled())) {
+ throw new ServiceException(RENDER_PDF_DISABLED.getCode(),
+ RENDER_PDF_DISABLED.getMsg() + "锛坹udao.qcreport.pdf.enabled 褰撳墠涓� false锛�");
+ }
+ PdfPrintOptions options = PdfPrintOptions.of(page, withPageNumber);
+ long start = System.currentTimeMillis();
+ BrowserManager.PageResult<byte[]> result =
+ browserManager.withPage(p -> print(p, html, options, withPageNumber));
+ long pdfDuration = System.currentTimeMillis() - start;
+
+ byte[] content = result.value();
+ if (content == null || content.length == 0) {
+ throw new ServiceException(RENDER_PDF_FAILED.getCode(),
+ RENDER_PDF_FAILED.getMsg() + "锛氭祻瑙堝櫒鏈繑鍥炰换浣� PDF 瀛楄妭锛岃妫�鏌ヨ鎶ュ憡瀹炰緥鐨� HTML 鏄惁鍙敤鍚庨噸璇曘��");
+ }
+ return new PdfResult(content, pdfDuration, result.browserStatus());
+ }
+
+ private byte[] print(Page page, String html, PdfPrintOptions options, boolean withPageNumber) {
+ try {
+ page.setContent(html, new Page.SetContentOptions()
+ .setWaitUntil(WaitUntilState.NETWORKIDLE)
+ .setTimeout(timeout()));
+ // 鍔犲浐鏍峰紡鍦ㄨ繖閲屾敞鍏ワ紝涓嶅啓杩涙覆鏌撳紩鎿庣殑 BASE_CSS锛氫骇鐗� HTML 涓庡墠绔喕缁撴牱渚嬫槸閫愬瓧姣斿鐨�
+ page.addStyleTag(new Page.AddStyleTagOptions().setContent(options.printCss()));
+ return page.pdf(new Page.PdfOptions()
+ .setWidth(options.widthCss())
+ .setHeight(options.heightCss())
+ .setMargin(new Margin()
+ .setTop(options.marginTopCss())
+ .setRight(options.marginRightCss())
+ .setBottom(options.marginBottomCss())
+ .setLeft(options.marginLeftCss()))
+ // PASS/FAIL 杩欑被鍒ゅ畾搴曡壊鏄潬鑳屾櫙鑹茶〃杈剧殑锛屼笉鎵撹儗鏅壊灏卞叏鐧�
+ .setPrintBackground(true)
+ .setDisplayHeaderFooter(withPageNumber)
+ // 蹇呴』鏄惧紡缁欓〉鐪夛紝鍚﹀垯 Chromium 浼氳ˉ涓婂畠鑷甫鐨勩�屾墦鍗版棩鏈� + 鏂囨。鏍囬銆�
+ .setHeaderTemplate(PdfPrintOptions.HEADER_TEMPLATE)
+ .setFooterTemplate(options.footerTemplate())
+ // 璁� HTML 鑷甫鐨� @page 鍋氱焊闈㈠嚑浣曠殑鍞竴鏉冨▉锛屼笂闈㈢殑鏄惧紡瀹介珮鍙綔鍏滃簳
+ .setPreferCSSPageSize(true));
+ } catch (PlaywrightException e) {
+ throw new ServiceException(RENDER_PDF_FAILED.getCode(),
+ RENDER_PDF_FAILED.getMsg() + "锛氭墦鍗拌繃绋嬩腑娴忚鍣ㄦ姤閿欙紝瀹為檯鍘熷洜鏄��" + e.getMessage()
+ + "銆嶃�傚彲鍏堝璇ユ姤鍛婃墽琛屻�岄噸鏂扮敓鎴愩�嶅啀瀵煎嚭锛岃嫢浠嶅け璐ヨ鑱旂郴绠$悊鍛樻煡鐪嬫覆鏌撹褰曘��");
+ }
+ }
+
+ private double timeout() {
+ Long configured = properties.getTimeoutMs();
+ return configured == null || configured < 1 ? 30000L : configured;
+ }
+
+ /**
+ * PDF 娓叉煋缁撴灉銆�
+ *
+ * @param content PDF 瀛楄妭
+ * @param pdfDurationMs 鎵撳嵃鑰楁椂锛堟绉掞級锛氫粎鍚瓑椤甸潰璧勬簮涓� {@code page.pdf()}锛�
+ * 涓庤皟鐢ㄦ柟缁熻鐨勩�屾�昏�楁椂銆嶄箣宸嵆鎺掗槦涓庢祻瑙堝櫒鍚姩鐨勭瓑寰�
+ * @param browserStatus 鏈娴忚鍣ㄧ姸鎬侊紙{@code READY} / {@code RESTARTED}锛�
+ */
+ public record PdfResult(byte[] content, long pdfDurationMs, String browserStatus) {
+ }
+
+}
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/template/QcReportTemplateService.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/template/QcReportTemplateService.java
new file mode 100644
index 0000000..12f6245
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/template/QcReportTemplateService.java
@@ -0,0 +1,98 @@
+package cn.iocoder.yudao.module.qcreport.service.template;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.qcreport.controller.admin.template.vo.QcReportTemplatePageReqVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.template.vo.QcReportTemplateSaveReqVO;
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.template.QcReportTemplateDO;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 鏅鸿兘璐ㄦ鎶ュ憡妯℃澘 Service 鎺ュ彛
+ */
+public interface QcReportTemplateService {
+
+ /**
+ * 鍒涘缓鎶ュ憡妯℃澘
+ *
+ * @param createReqVO 鍒涘缓淇℃伅
+ * @return 妯℃澘缂栧彿
+ */
+ Long createTemplate(QcReportTemplateSaveReqVO createReqVO);
+
+ /**
+ * 鏇存柊鎶ュ憡妯℃澘
+ *
+ * @param updateReqVO 鏇存柊淇℃伅
+ */
+ void updateTemplate(QcReportTemplateSaveReqVO updateReqVO);
+
+ /**
+ * 鍒犻櫎鎶ュ憡妯℃澘锛堝悓鏃跺垹闄ゅ叾涓嬫墍鏈夌増鏈級
+ *
+ * @param id 妯℃澘缂栧彿
+ */
+ void deleteTemplate(Long id);
+
+ /**
+ * 澶嶅埗鎶ュ憡妯℃澘锛氬鍒舵ā鏉垮厓鏁版嵁锛屽苟鎶婂綋鍓嶆渶鏂扮増鏈殑 Schema 澶嶅埗涓哄壇鏈殑 v1.0 鑽夌
+ *
+ * @param id 琚鍒剁殑妯℃澘缂栧彿
+ * @return 鏂版ā鏉跨紪鍙�
+ */
+ Long copyTemplate(Long id);
+
+ /**
+ * 鏍¢獙妯℃澘瀛樺湪锛屽苟杩斿洖
+ *
+ * @param id 妯℃澘缂栧彿
+ * @return 妯℃澘
+ */
+ QcReportTemplateDO validateTemplateExists(Long id);
+
+ /**
+ * 鑾峰緱鎶ュ憡妯℃澘
+ *
+ * @param id 妯℃澘缂栧彿
+ * @return 妯℃澘
+ */
+ QcReportTemplateDO getTemplate(Long id);
+
+ /**
+ * 鑾峰緱鎶ュ憡妯℃澘鍒嗛〉
+ *
+ * @param pageReqVO 鍒嗛〉鏌ヨ
+ * @return 妯℃澘鍒嗛〉
+ */
+ PageResult<QcReportTemplateDO> getTemplatePage(QcReportTemplatePageReqVO pageReqVO);
+
+ /**
+ * 鑾峰緱妯℃澘鍒楄〃
+ *
+ * @param ids 妯℃澘缂栧彿闆嗗悎
+ * @return 妯℃澘鍒楄〃
+ */
+ List<QcReportTemplateDO> getTemplateList(Collection<Long> ids);
+
+ /**
+ * 鑾峰緱銆屽彲鐢ㄤ簬鍑轰欢銆嶇殑妯℃澘鍒楄〃锛氭寚瀹氭姤鍛婄被鍨嬨�佹ā鏉垮凡鍚敤銆佷笖褰撳墠鐗堟湰澶勪簬宸插彂甯冪姸鎬併��
+ * <p>
+ * 渚涜川妫�鍗曘�屽嚭鎶ュ憡銆嶅脊绐楅�夋ā鏉跨敤銆傚鏌ヨ繖涓�灞傜増鏈姸鎬侊紝鏄负浜嗕笉鎶�
+ * 銆岄�夊嚭鏉ュ繀鐒惰鎷掋�嶇殑妯℃澘鎽嗗埌鐢ㄦ埛闈㈠墠鈥斺�旀ā鏉跨殑 current_version 鍙兘鎸囧悜涓�涓凡鍋滅敤鐨勭増鏈紝
+ * 鍋滅敤鐗堟湰涓嶄細娓呯┖ current_version锛岃繖绉嶆ā鏉夸竴鏃﹁閫夛紝鍑轰欢蹇呮姤 1_070_101_003銆�
+ *
+ * @param reportType 鎶ュ憡绫诲瀷锛屽嵆 mes_qc_type 鐨勬暟鍊煎瓧绗︿覆锛屽 "1"
+ * @return 鍙敤妯℃澘鍒楄〃
+ */
+ List<QcReportTemplateDO> getSelectableTemplates(String reportType);
+
+ /**
+ * 鏇存柊妯℃澘鐨勫綋鍓嶇増鏈彿
+ *
+ * @param id 妯℃澘缂栧彿
+ * @param version 鐗堟湰鍙�
+ */
+ void updateCurrentVersion(Long id, String version);
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/template/QcReportTemplateServiceImpl.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/template/QcReportTemplateServiceImpl.java
new file mode 100644
index 0000000..fcd4144
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/template/QcReportTemplateServiceImpl.java
@@ -0,0 +1,229 @@
+package cn.iocoder.yudao.module.qcreport.service.template;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.qcreport.controller.admin.template.vo.QcReportTemplatePageReqVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.template.vo.QcReportTemplateSaveReqVO;
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.template.QcReportTemplateDO;
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.version.QcReportTemplateVersionDO;
+import cn.iocoder.yudao.module.qcreport.dal.mysql.template.QcReportTemplateMapper;
+import cn.iocoder.yudao.module.qcreport.dal.mysql.version.QcReportTemplateVersionMapper;
+import cn.iocoder.yudao.module.qcreport.engine.QualityReportEngine;
+import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi;
+import cn.iocoder.yudao.module.system.enums.storage.StorageRecordTypeEnum;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.TEMPLATE_CODE_DUPLICATE;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.TEMPLATE_NOT_EXISTS;
+import static cn.iocoder.yudao.module.qcreport.enums.QcReportEnums.TemplateStatusEnum.ENABLE;
+import static cn.iocoder.yudao.module.qcreport.enums.QcReportEnums.VersionStatusEnum.DRAFT;
+import static cn.iocoder.yudao.module.qcreport.enums.QcReportEnums.VersionStatusEnum.PUBLISHED;
+
+/**
+ * 鏅鸿兘璐ㄦ鎶ュ憡妯℃澘 Service 瀹炵幇绫�
+ */
+@Service
+@Validated
+public class QcReportTemplateServiceImpl implements QcReportTemplateService {
+
+ /**
+ * 澶嶅埗妯℃澘鏃讹紝缂栫爜鍐茬獊鐨勯噸璇曚笂闄�
+ */
+ private static final int COPY_CODE_MAX_RETRY = 50;
+
+ @Resource
+ private QcReportTemplateMapper templateMapper;
+
+ @Resource
+ private QcReportTemplateVersionMapper versionMapper;
+
+ @Resource
+ private StorageAttachmentApi storageAttachmentApi;
+
+ @Override
+ public Long createTemplate(QcReportTemplateSaveReqVO createReqVO) {
+ validateTemplateCodeUnique(null, createReqVO.getTemplateCode());
+
+ QcReportTemplateDO template = BeanUtils.toBean(createReqVO, QcReportTemplateDO.class);
+ if (template.getStatus() == null) {
+ template.setStatus(ENABLE.getStatus());
+ }
+ templateMapper.insert(template);
+ return template.getId();
+ }
+
+ @Override
+ public void updateTemplate(QcReportTemplateSaveReqVO updateReqVO) {
+ validateTemplateExists(updateReqVO.getId());
+ validateTemplateCodeUnique(updateReqVO.getId(), updateReqVO.getTemplateCode());
+
+ QcReportTemplateDO updateObj = BeanUtils.toBean(updateReqVO, QcReportTemplateDO.class);
+ templateMapper.updateById(updateObj);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void deleteTemplate(Long id) {
+ validateTemplateExists(id);
+
+ // 鍏堟竻闄勪欢鍐嶅垹妯℃澘锛氭ā鏉夸竴娌★紝AI 瀵煎叆鏃朵笂浼犵殑婧愭枃浠跺氨鎴愪簡鏌ヤ笉鍒颁富浜虹殑瀛ゅ効
+ // 锛堥檮浠惰 + 纾佺洏鏂囦欢鍙屼唤锛夈�傞『搴忓弽杩囨潵鐨勮瘽锛屾竻鐞嗗け璐ュ氨鍐嶄篃娌℃満浼氳ˉ鏁戜簡鈥斺��
+ // 妯℃澘宸蹭笉瀛樺湪锛屾棤浠庣煡閬撹鍒犺皝鐨勯檮浠躲�備笌 deleteInstance 鍚屾瀯銆�
+ storageAttachmentApi.deleteAttachmentsByRecord(StorageRecordTypeEnum.QC_REPORT_TEMPLATE.getType(), id);
+
+ // 閫昏緫鍒犻櫎妯℃澘
+ templateMapper.deleteById(id);
+ // 绾ц仈閫昏緫鍒犻櫎鍏朵笅鎵�鏈夌増鏈�
+ versionMapper.delete(new LambdaQueryWrapperX<QcReportTemplateVersionDO>()
+ .eq(QcReportTemplateVersionDO::getTemplateId, id));
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Long copyTemplate(Long id) {
+ QcReportTemplateDO source = validateTemplateExists(id);
+
+ // 澶嶅埗妯℃澘鍏冩暟鎹紝缂栫爜涓庡悕绉伴渶閬胯宸插瓨鍦ㄧ殑璁板綍
+ QcReportTemplateDO target = BeanUtils.toBean(source, QcReportTemplateDO.class);
+ target.setId(null);
+ target.setTemplateCode(generateCopyCode(source.getTemplateCode()));
+ target.setTemplateName(source.getTemplateName() + "锛堝壇鏈級");
+ target.setStatus(ENABLE.getStatus());
+ target.setCurrentVersion(null);
+ resetAuditFields(target);
+ templateMapper.insert(target);
+
+ // 鎶婃簮妯℃澘鐨勬渶鏂扮増鏈� Schema 澶嶅埗涓哄壇鏈殑 v1.0 鑽夌锛岄伩鍏嶅鍒跺嚭鏉ユ槸涓┖妯℃澘
+ QcReportTemplateVersionDO latestVersion = versionMapper.selectLatestByTemplateId(id);
+ if (latestVersion != null) {
+ QcReportTemplateVersionDO copiedVersion = BeanUtils.toBean(latestVersion, QcReportTemplateVersionDO.class);
+ copiedVersion.setId(null);
+ copiedVersion.setTemplateId(target.getId());
+ copiedVersion.setVersion("v1.0");
+ copiedVersion.setStatus(DRAFT.getStatus());
+ copiedVersion.setSchema(latestVersion.getSchema());
+ resetAuditFields(copiedVersion);
+ versionMapper.insert(copiedVersion);
+ }
+ return target.getId();
+ }
+
+ @Override
+ public QcReportTemplateDO validateTemplateExists(Long id) {
+ QcReportTemplateDO template = templateMapper.selectById(id);
+ if (template == null) {
+ throw exception(TEMPLATE_NOT_EXISTS);
+ }
+ return template;
+ }
+
+ @Override
+ public QcReportTemplateDO getTemplate(Long id) {
+ return templateMapper.selectById(id);
+ }
+
+ @Override
+ public PageResult<QcReportTemplateDO> getTemplatePage(QcReportTemplatePageReqVO pageReqVO) {
+ return templateMapper.selectPage(pageReqVO);
+ }
+
+ @Override
+ public List<QcReportTemplateDO> getTemplateList(Collection<Long> ids) {
+ if (CollUtil.isEmpty(ids)) {
+ return Collections.emptyList();
+ }
+ return templateMapper.selectByIds(ids);
+ }
+
+ @Override
+ public List<QcReportTemplateDO> getSelectableTemplates(String reportType) {
+ // 妯℃澘灞傝繃婊わ細鎶ュ憡绫诲瀷涓�鑷� + 妯℃澘宸插惎鐢�
+ List<QcReportTemplateDO> templates = templateMapper.selectListByReportTypeAndStatus(
+ reportType, ENABLE.getStatus());
+ if (CollUtil.isEmpty(templates)) {
+ return Collections.emptyList();
+ }
+ // 鐗堟湰灞傝繃婊わ細current_version 鎸囧悜鐨勯偅涓増鏈繀椤汇�屽凡鍙戝竷銆嶏紝涓旂敾甯冪湡鐨勮兘娓叉煋鍑轰笢瑗裤��
+ // 涓や欢浜嬮兘瑕佸湪杩欓噷鎸★細鍋滅敤鐗堟湰涓嶄細娓呯┖ current_version锛岀敤鎴蜂竴鏃﹂�変腑锛屽嚭浠跺繀鐒舵姤 1_070_101_003锛�
+ // 鑰屻�屾墦寮�杩囪璁″櫒浣嗕竴涓粍浠堕兘娌℃斁銆嶇殑鐗堟湰鐢诲竷闈炵┖鍗存病鏈夋牴缁勪欢锛屽嚭浠朵笉鎶ラ敊銆佺洿鎺ョ粰涓�寮犵櫧绾� PDF銆�
+ // 涓ょ閮芥槸宸茬煡浼氬け璐ョ殑缁勫悎锛屼笉璇ユ憜鍒板嚭鎶ュ憡寮圭獥閲岃鐢ㄦ埛鍘昏俯銆�
+ //
+ // 杩欎竴灞備笉棰濆鏌ュ簱锛氫笅闈㈣繖鏉℃煡璇㈡湰鏉ュ氨瑕佹妸鍊欓�夌増鏈暣琛岃鍑烘潵锛堝惈 schema_json锛夛紝
+ // 鐢ㄥ畠姣� hasCanvas 鏄櫧鎹$殑锛涜嫢鏀圭敤 exists 瀛愭煡璇紝鍙嶈�岃澶氫竴娆″線杩斻��
+ List<Long> templateIds = templates.stream().map(QcReportTemplateDO::getId).collect(Collectors.toList());
+ Map<Long, Map<String, QcReportTemplateVersionDO>> publishedVersions = versionMapper
+ .selectListByTemplateIdsAndStatus(templateIds, PUBLISHED.getStatus())
+ .stream()
+ .collect(Collectors.groupingBy(QcReportTemplateVersionDO::getTemplateId,
+ Collectors.toMap(QcReportTemplateVersionDO::getVersion, Function.identity())));
+ return templates.stream()
+ .filter(template -> {
+ QcReportTemplateVersionDO current = StrUtil.isBlank(template.getCurrentVersion())
+ ? null
+ : publishedVersions.getOrDefault(template.getId(), Collections.emptyMap())
+ .get(template.getCurrentVersion());
+ return current != null && QualityReportEngine.hasCanvas(current.getSchema());
+ })
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public void updateCurrentVersion(Long id, String version) {
+ QcReportTemplateDO updateObj = new QcReportTemplateDO();
+ updateObj.setId(id);
+ updateObj.setCurrentVersion(version);
+ templateMapper.updateById(updateObj);
+ }
+
+ private void validateTemplateCodeUnique(Long id, String templateCode) {
+ QcReportTemplateDO template = templateMapper.selectByCode(templateCode);
+ if (template == null) {
+ return;
+ }
+ if (ObjUtil.notEqual(template.getId(), id)) {
+ throw exception(TEMPLATE_CODE_DUPLICATE);
+ }
+ }
+
+ /**
+ * 鐢熸垚鍓湰缂栫爜锛氭簮缂栫爜 + _COPY锛岃嫢宸茶鍗犵敤鍒欒拷鍔犲簭鍙�
+ */
+ private String generateCopyCode(String sourceCode) {
+ String baseCode = sourceCode + "_COPY";
+ for (int i = 0; i < COPY_CODE_MAX_RETRY; i++) {
+ String candidate = i == 0 ? baseCode : baseCode + (i + 1);
+ if (templateMapper.selectByCode(candidate) == null) {
+ return candidate;
+ }
+ }
+ // 鏋佺鎯呭喌涓嬩粛鍐茬獊锛岀敤鏃堕棿鎴冲厹搴曪紝閬垮厤澶嶅埗鍔熻兘鐩存帴涓嶅彲鐢�
+ return baseCode + System.currentTimeMillis();
+ }
+
+ /**
+ * 娓呯┖瀹¤瀛楁锛岃妗嗘灦鍦ㄦ彃鍏ユ椂鎸夋柊璁板綍閲嶆柊濉厖锛岄伩鍏嶅壇鏈部鐢ㄦ簮璁板綍鐨勫垱寤轰汉/鍒涘缓鏃堕棿
+ */
+ private void resetAuditFields(BaseDO baseDO) {
+ baseDO.setCreator(null);
+ baseDO.setCreateTime(null);
+ baseDO.setUpdater(null);
+ baseDO.setUpdateTime(null);
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/version/QcReportTemplateVersionService.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/version/QcReportTemplateVersionService.java
new file mode 100644
index 0000000..b455bbf
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/version/QcReportTemplateVersionService.java
@@ -0,0 +1,113 @@
+package cn.iocoder.yudao.module.qcreport.service.version;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.qcreport.controller.admin.version.vo.QcReportTemplateVersionPageReqVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.version.vo.QcReportTemplateVersionSaveReqVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.version.vo.QcReportTemplateVersionUpdateReqVO;
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.version.QcReportTemplateVersionDO;
+
+import java.util.List;
+
+/**
+ * 鏅鸿兘璐ㄦ鎶ュ憡妯℃澘鐗堟湰 Service 鎺ュ彛
+ */
+public interface QcReportTemplateVersionService {
+
+ /**
+ * 鍒涘缓妯℃澘鐗堟湰
+ *
+ * @param createReqVO 鍒涘缓淇℃伅
+ * @return 鐗堟湰缂栧彿
+ */
+ Long createVersion(QcReportTemplateVersionSaveReqVO createReqVO);
+
+ /**
+ * 鏇存柊妯℃澘鐗堟湰锛堝凡鍙戝竷鐨勭増鏈笉鍏佽淇敼锛�
+ *
+ * @param updateReqVO 鏇存柊淇℃伅
+ */
+ void updateVersion(QcReportTemplateVersionUpdateReqVO updateReqVO);
+
+ /**
+ * 鍒犻櫎妯℃澘鐗堟湰锛堜粎鑽夌鍙垹闄わ級
+ *
+ * @param id 鐗堟湰缂栧彿
+ */
+ void deleteVersion(Long id);
+
+ /**
+ * 鍙戝竷妯℃澘鐗堟湰锛屽苟鎶婃ā鏉跨殑褰撳墠鐗堟湰鍙锋寚鍚戝畠
+ *
+ * @param id 鐗堟湰缂栧彿
+ */
+ void publishVersion(Long id);
+
+ /**
+ * 鍥炴粴锛氭妸妯℃澘鐨勫綋鍓嶇増鏈彿鍒囧洖鎸囧畾鐨勫巻鍙茬増鏈紙鐗堟湰鍐呭涓嶄細琚慨鏀癸級
+ *
+ * @param id 鐗堟湰缂栧彿
+ */
+ void rollbackVersion(Long id);
+
+ /**
+ * 鍋滅敤妯℃澘鐗堟湰
+ *
+ * @param id 鐗堟湰缂栧彿
+ */
+ void disableVersion(Long id);
+
+ /**
+ * 鏍¢獙鐗堟湰瀛樺湪锛屽苟杩斿洖
+ *
+ * @param id 鐗堟湰缂栧彿
+ * @return 鐗堟湰
+ */
+ QcReportTemplateVersionDO validateVersionExists(Long id);
+
+ /**
+ * 鑾峰緱妯℃澘鐗堟湰
+ *
+ * @param id 鐗堟湰缂栧彿
+ * @return 鐗堟湰
+ */
+ QcReportTemplateVersionDO getVersion(Long id);
+
+ /**
+ * 鑾峰緱鎸囧畾妯℃澘鐨勬寚瀹氱増鏈紙瑕佹眰宸插彂甯冿級锛屼緵娓叉煋浣跨敤
+ *
+ * @param templateId 妯℃澘缂栧彿
+ * @param version 鐗堟湰鍙�
+ * @return 鐗堟湰
+ */
+ QcReportTemplateVersionDO getPublishedVersion(Long templateId, String version);
+
+ /**
+ * 鎸夈�屾ā鏉跨紪鍙� + 鐗堟湰鍙枫�嶅彇鐗堟湰锛�**涓嶈姹傚凡鍙戝竷**锛屼笉瀛樺湪鏃惰繑鍥� null銆�
+ * <p>
+ * 涓� {@link #getPublishedVersion} 鐨勫垎宸ワ細閭d釜鐢ㄤ簬銆岀涓�娆″嚭浠躲�嶏紝蹇呴』鏄凡鍙戝竷鐗堟湰锛�
+ * 杩欎釜鐢ㄤ簬銆岄噸鏂扮敓鎴愬巻鍙叉姤鍛娿�嶁�斺�斿凡鍙戝竷鐗堟湰鐨勫唴瀹逛笉鍙敼锛屼絾鐘舵�佸彲鑳借鍋滅敤锛�
+ * 涓嶈鍥犳璁╀竴浠藉凡缁忓嚭杩囩殑鎶ュ憡鍙樻垚鎵撲笉寮�銆�
+ *
+ * @param templateId 妯℃澘缂栧彿
+ * @param version 鐗堟湰鍙�
+ * @return 鐗堟湰锛屼笉瀛樺湪鏃惰繑鍥� null
+ */
+ QcReportTemplateVersionDO getVersionByTemplateIdAndVersion(Long templateId, String version);
+
+ /**
+ * 鑾峰緱妯℃澘鐗堟湰鍒嗛〉
+ *
+ * @param pageReqVO 鍒嗛〉鏌ヨ
+ * @return 鐗堟湰鍒嗛〉
+ */
+ PageResult<QcReportTemplateVersionDO> getVersionPage(QcReportTemplateVersionPageReqVO pageReqVO);
+
+ /**
+ * 鑾峰緱妯℃澘鐨勬墍鏈夌増鏈�
+ *
+ * @param templateId 妯℃澘缂栧彿
+ * @return 鐗堟湰鍒楄〃
+ */
+ List<QcReportTemplateVersionDO> getVersionListByTemplateId(Long templateId);
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/version/QcReportTemplateVersionServiceImpl.java b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/version/QcReportTemplateVersionServiceImpl.java
new file mode 100644
index 0000000..7136b24
--- /dev/null
+++ b/yudao-module-qcreport/src/main/java/cn/iocoder/yudao/module/qcreport/service/version/QcReportTemplateVersionServiceImpl.java
@@ -0,0 +1,238 @@
+package cn.iocoder.yudao.module.qcreport.service.version;
+
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.qcreport.controller.admin.version.vo.QcReportTemplateVersionPageReqVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.version.vo.QcReportTemplateVersionSaveReqVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.version.vo.QcReportTemplateVersionUpdateReqVO;
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.template.QcReportTemplateDO;
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.version.QcReportTemplateVersionDO;
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.version.ReportTemplateSchema;
+import cn.iocoder.yudao.module.qcreport.dal.mysql.version.QcReportTemplateVersionMapper;
+import cn.iocoder.yudao.module.qcreport.engine.QualityReportEngine;
+import cn.iocoder.yudao.module.qcreport.engine.render.CanvasSafety;
+import cn.iocoder.yudao.module.qcreport.service.template.QcReportTemplateService;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.qcreport.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.module.qcreport.enums.QcReportEnums.TemplateStatusEnum.ENABLE;
+import static cn.iocoder.yudao.module.qcreport.enums.QcReportEnums.VersionStatusEnum.*;
+
+/**
+ * 鏅鸿兘璐ㄦ鎶ュ憡妯℃澘鐗堟湰 Service 瀹炵幇绫�
+ */
+@Service
+@Validated
+public class QcReportTemplateVersionServiceImpl implements QcReportTemplateVersionService {
+
+ private static final Pattern VERSION_PATTERN = Pattern.compile("^v(\\d+)(?:\\.(\\d+))*$");
+
+ @Resource
+ private QcReportTemplateVersionMapper versionMapper;
+
+ @Resource
+ private QcReportTemplateService templateService;
+
+ @Override
+ public Long createVersion(QcReportTemplateVersionSaveReqVO createReqVO) {
+ QcReportTemplateDO template = templateService.validateTemplateExists(createReqVO.getTemplateId());
+ if (!ENABLE.getStatus().equals(template.getStatus())) {
+ throw exception(TEMPLATE_STATUS_DISABLED);
+ }
+
+ // 鏈寚瀹氱増鏈彿鏃讹紝鎸夋渶鏂扮増鏈嚜鍔ㄩ�掑锛坴1.0 -> v1.1锛�
+ String version = StrUtil.blankToDefault(createReqVO.getVersion(), null);
+ if (version == null) {
+ QcReportTemplateVersionDO latest = versionMapper.selectLatestByTemplateId(createReqVO.getTemplateId());
+ version = nextVersion(latest == null ? null : latest.getVersion());
+ }
+ validateVersionUnique(createReqVO.getTemplateId(), version, null);
+
+ validateSchema(createReqVO.getSchema());
+
+ QcReportTemplateVersionDO createObj = BeanUtils.toBean(createReqVO, QcReportTemplateVersionDO.class);
+ createObj.setVersion(version);
+ createObj.setStatus(DRAFT.getStatus());
+ versionMapper.insert(createObj);
+ return createObj.getId();
+ }
+
+ @Override
+ public void updateVersion(QcReportTemplateVersionUpdateReqVO updateReqVO) {
+ QcReportTemplateVersionDO version = validateVersionExists(updateReqVO.getId());
+ // 宸插彂甯冪殑鐗堟湰涓嶅厑璁镐慨鏀癸紝鍙兘鏂板缓鐗堟湰锛屼繚璇佸巻鍙叉姤鍛婂彲澶嶇幇
+ if (PUBLISHED.getStatus().equals(version.getStatus())) {
+ throw exception(TEMPLATE_VERSION_PUBLISHED_CANNOT_MODIFY);
+ }
+ validateSchema(updateReqVO.getSchema());
+
+ QcReportTemplateVersionDO updateObj = BeanUtils.toBean(updateReqVO, QcReportTemplateVersionDO.class);
+ versionMapper.updateById(updateObj);
+ }
+
+ @Override
+ public void deleteVersion(Long id) {
+ QcReportTemplateVersionDO version = validateVersionExists(id);
+ if (!DRAFT.getStatus().equals(version.getStatus())) {
+ throw exception(TEMPLATE_VERSION_PUBLISHED_CANNOT_MODIFY);
+ }
+ versionMapper.deleteById(id);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void publishVersion(Long id) {
+ QcReportTemplateVersionDO version = validateVersionExists(id);
+ if (version.getSchema() == null) {
+ throw exception(TEMPLATE_VERSION_SCHEMA_EMPTY);
+ }
+
+ QcReportTemplateVersionDO updateObj = new QcReportTemplateVersionDO();
+ updateObj.setId(id);
+ updateObj.setStatus(PUBLISHED.getStatus());
+ versionMapper.updateById(updateObj);
+
+ // 妯℃澘鐨勫綋鍓嶇増鏈寚鍚戝垰鍙戝竷鐨勭増鏈�
+ templateService.updateCurrentVersion(version.getTemplateId(), version.getVersion());
+ }
+
+ @Override
+ public void rollbackVersion(Long id) {
+ QcReportTemplateVersionDO version = validateVersionExists(id);
+ if (!PUBLISHED.getStatus().equals(version.getStatus())) {
+ throw exception(TEMPLATE_VERSION_NOT_PUBLISHED);
+ }
+ // 鍙垏鎹㈡ā鏉跨殑褰撳墠鐗堟湰鍙凤紝涓嶆敼鍔ㄤ换浣曠増鏈唴瀹�
+ templateService.updateCurrentVersion(version.getTemplateId(), version.getVersion());
+ }
+
+ @Override
+ public void disableVersion(Long id) {
+ QcReportTemplateVersionDO version = validateVersionExists(id);
+
+ // 鍋滅敤銆屽綋鍓嶇増鏈�嶄細閫犲嚭涓�浠借嚜鐩哥煕鐩剧殑妯℃澘锛歵emplate.current_version 杩樻寚鐫�瀹冿紝瀹冨嵈宸茬粡涓嶅彲鐢紝
+ // 浜庢槸杩欎釜妯℃澘鑷鍑轰笉浜嗘姤鍛婏紙鍒板嚭浠堕偅涓�鍒绘墠鎶� 1_070_101_003锛夛紝鑰岀敤鎴蜂笉浼氭兂鍒拌捣鍥犳槸鍒氭墠閭f鍋滅敤銆�
+ // 杩欓噷鐩存帴鎷掔粷锛岃�屼笉鏄『鎵嬫妸 current_version 鏀规帀鈥斺�斻�屾敼鍝釜鐗堟湰銆嶆槸鐢ㄦ埛鐨勫喅瀹氾紝
+ // 涓嶈鐢卞仠鐢ㄨ繖涓姩浣滄倓鎮勪唬鍔筹紱瑕佹暣涓ā鏉垮仠涓嬫潵锛屽彟鏈夈�屽仠鐢ㄦā鏉裤�嶈繖涓叆鍙c��
+ QcReportTemplateDO template = templateService.getTemplate(version.getTemplateId());
+ if (template != null && version.getVersion().equals(template.getCurrentVersion())) {
+ throw exception(TEMPLATE_VERSION_CURRENT_CANNOT_DISABLE,
+ version.getVersion(), template.getTemplateName());
+ }
+
+ QcReportTemplateVersionDO updateObj = new QcReportTemplateVersionDO();
+ updateObj.setId(id);
+ updateObj.setStatus(DISABLED.getStatus());
+ versionMapper.updateById(updateObj);
+ }
+
+ @Override
+ public QcReportTemplateVersionDO validateVersionExists(Long id) {
+ QcReportTemplateVersionDO version = versionMapper.selectById(id);
+ if (version == null) {
+ throw exception(TEMPLATE_VERSION_NOT_EXISTS);
+ }
+ return version;
+ }
+
+ @Override
+ public QcReportTemplateVersionDO getVersion(Long id) {
+ return versionMapper.selectById(id);
+ }
+
+ @Override
+ public QcReportTemplateVersionDO getPublishedVersion(Long templateId, String version) {
+ QcReportTemplateVersionDO versionDO = versionMapper.selectByTemplateIdAndVersion(templateId, version);
+ if (versionDO == null) {
+ throw exception(TEMPLATE_VERSION_NOT_EXISTS);
+ }
+ if (!PUBLISHED.getStatus().equals(versionDO.getStatus())) {
+ throw exception(TEMPLATE_VERSION_NOT_PUBLISHED);
+ }
+ return versionDO;
+ }
+
+ @Override
+ public QcReportTemplateVersionDO getVersionByTemplateIdAndVersion(Long templateId, String version) {
+ return versionMapper.selectByTemplateIdAndVersion(templateId, version);
+ }
+
+ @Override
+ public PageResult<QcReportTemplateVersionDO> getVersionPage(QcReportTemplateVersionPageReqVO pageReqVO) {
+ return versionMapper.selectPage(pageReqVO);
+ }
+
+ @Override
+ public List<QcReportTemplateVersionDO> getVersionListByTemplateId(Long templateId) {
+ return versionMapper.selectListByTemplateId(templateId);
+ }
+
+ /**
+ * 鏍¢獙璁捐鍣ㄦ彁浜ょ殑 Schema 缁撴瀯銆係chema 鍏佽涓虹┖锛堝厛寤虹増鏈悗璁捐锛夛紝
+ * 浣嗕竴鏃︽彁渚涘氨蹇呴』甯� schemaVersion锛岄伩鍏嶅瓨鍏ユ棤娉曡瘑鍒殑鍐呭
+ */
+ /**
+ * 鏍¢獙妯℃澘 Schema锛屼笉鍚堟牸鐨勭洿鎺ラ��鍥烇紝涓嶈瀹冭惤搴撱��
+ * <p>
+ * 瑙勫垯蹇呴』鍦ㄨ繖閲屾嫤锛氳鍒欏啓閿欎簡瑕佸埌鍑轰欢鏃舵墠鐐革紝鐢ㄦ埛鐪嬪埌鐨勬槸銆屾姤鍛婂嚭涓嶆潵銆嶏紝
+ * 鍗翠笉鐭ラ亾鏄ā鏉块噷鍝潯瑙勫垯鍐欏潖鐨勩�傚瓨鐨勬椂鍊欏氨璇存竻妤氾紝鏀硅捣鏉ユ墠鏈夌潃钀姐��
+ */
+ private void validateSchema(ReportTemplateSchema schema) {
+ if (schema == null) {
+ return;
+ }
+ if (StrUtil.isBlank(schema.getSchemaVersion())) {
+ throw exception(TEMPLATE_VERSION_SCHEMA_INVALID);
+ }
+ List<String> ruleErrors = QualityReportEngine.validateRules(schema);
+ if (!ruleErrors.isEmpty()) {
+ // 閫愭潯鍒楀嚭鍏蜂綋瑙勫垯涓庡師鍥狅細鍙姤銆岃鍒欎笉鍚堟硶銆嶇瓑浜庤鐢ㄦ埛鑷繁鍘荤寽鏄摢鏉�
+ throw new ServiceException(TEMPLATE_VERSION_RULE_INVALID.getCode(),
+ TEMPLATE_VERSION_RULE_INVALID.getMsg() + "锛�" + String.join("锛�", ruleErrors));
+ }
+ // 鐢诲竷閲屾湁娓叉煋鏃朵細鍘熸牱鎷艰繘浜х墿鐨勫唴瀹癸紙鏍囩鍚嶃�佸睘鎬у悕銆佹暣娈� CSS锛夛紝鍦ㄨ繖閲屽崱浣忥紱
+ // 浣嶇疆鏀惧湪娓叉煋渚у氨鍔ㄤ簡 HtmlRenderer锛屼細璁╁鎷嶄骇鐗╀笌瀛橀噺鎶ュ憡鐨勯�愬瓧澶嶇幇涓�璧峰彉锛岃 CanvasSafety 绫绘敞閲�
+ List<String> canvasProblems = CanvasSafety.validate(schema.getGrapes());
+ if (!canvasProblems.isEmpty()) {
+ throw new ServiceException(TEMPLATE_VERSION_CANVAS_UNSAFE.getCode(),
+ StrUtil.format(TEMPLATE_VERSION_CANVAS_UNSAFE.getMsg(),
+ String.join("锛�", canvasProblems)));
+ }
+ }
+
+ private void validateVersionUnique(Long templateId, String version, Long id) {
+ QcReportTemplateVersionDO exists = versionMapper.selectByTemplateIdAndVersion(templateId, version);
+ if (exists != null && !exists.getId().equals(id)) {
+ throw exception(TEMPLATE_VERSION_DUPLICATE);
+ }
+ }
+
+ /**
+ * 璁$畻涓嬩竴涓増鏈彿锛歷1.0 -> v1.1锛涙棤鍘嗗彶鎴栨牸寮忔棤娉曡瘑鍒椂浠� v1.0 寮�濮�
+ */
+ private String nextVersion(String currentVersion) {
+ if (StrUtil.isBlank(currentVersion)) {
+ return "v1.0";
+ }
+ Matcher matcher = VERSION_PATTERN.matcher(currentVersion);
+ if (!matcher.matches()) {
+ return "v1.0";
+ }
+ // 鍙� "v" 涔嬪悗鐨勭 1 娈典綔涓轰富鐗堟湰锛岀 2 娈典綔涓烘鐗堟湰
+ String[] segments = currentVersion.substring(1).split("\\.");
+ int major = Integer.parseInt(segments[0]);
+ int minor = segments.length > 1 ? Integer.parseInt(segments[1]) : 0;
+ return "v" + major + "." + (minor + 1);
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/version/ReportTemplateSchemaCompatibilityTest.java b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/version/ReportTemplateSchemaCompatibilityTest.java
new file mode 100644
index 0000000..32d5dfd
--- /dev/null
+++ b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/dal/dataobject/version/ReportTemplateSchemaCompatibilityTest.java
@@ -0,0 +1,104 @@
+package cn.iocoder.yudao.module.qcreport.dal.dataobject.version;
+
+import com.baomidou.mybatisplus.extension.handlers.Jackson3TypeHandler;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.lang.reflect.Field;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+/**
+ * Schema 璇诲啓鍏煎鎬ф祴璇曘��
+ * <p>
+ * 璧扮殑鏄敓浜у悓娆捐鍙栬矾寰勨�斺�擬yBatis-Plus 鐨� {@link Jackson3TypeHandler} 閰�
+ * {@code QcReportTemplateVersionDO.schema} 瀛楁锛岃�屼笉鏄祴璇曡嚜宸� new 涓�涓� ObjectMapper锛�
+ * 鍥犱负瑕侀槻鐨勫氨鏄�屽弽搴忓垪鍖栬鍙栥�嶈繖鏉¢摼璺細{@code schema_json} 鍒楅噷瀛樼殑閮芥槸鍘嗗彶 JSON銆�
+ * <p>
+ * 濂戠害 1.1 鍒犳帀浜� dataSources / bindings / styles 涓変釜浠庢湭浣跨敤鐨勫瓧娈碉紝搴撻噷宸茬粡瀛樼潃甯﹁繖涓変釜閿殑
+ * 鏃ц褰曘�傝繖閲屽畧鐨勬槸銆屾棫 JSON 浠嶇劧璇诲緱鍑恒�佷笖璇ユ湁鐨勫瓧娈典竴涓笉灏戙�嶁�斺�斿嚭闂鐨勮〃鐜版槸
+ * 銆岃�佹ā鏉跨偣杩涘幓鎶ョ郴缁熷紓甯搞�嶏紝鍙湁瀛橀噺鏁版嵁浼氫腑鎷涳紝浜嬪悗寰堥毦鏌ャ��
+ * <p>
+ * 瀹�<b>涓�</b>璐熻矗璇佹槑 {@code ReportTemplateSchema} 涓� {@code @JsonIgnoreProperties} 鐨勫繀瑕佹�э細
+ * 瀹炴祴鎶婇偅琛屾敞瑙e幓鎺夋湰娴嬭瘯鐓ф牱閫氳繃锛圝ackson 3 榛樿灏卞拷鐣ユ湭鐭ュ睘鎬э級銆�
+ * 娉ㄨВ鐨勬剰涔夊啓鍦ㄩ偅涓被涓婏紝鍒妸杩欐潯娴嬭瘯褰撴垚瀹冪殑瀹堝崼銆�
+ */
+class ReportTemplateSchemaCompatibilityTest {
+
+ /** 1.0 鏃舵湡瀛樿繘鍘荤殑 Schema锛氬惈宸插垹闄ょ殑涓変釜瀛楁锛宑omponents 杩樻槸鏃犵被鍨嬬殑 Map */
+ private static final String LEGACY_JSON = """
+ {
+ "schemaVersion": "1.0",
+ "page": { "size": "A4", "orientation": "portrait", "margin": { "top": 12, "right": 8, "bottom": 12, "left": 8 } },
+ "grapes": { "pages": [ { "frames": [] } ] },
+ "components": [ { "id": "abc", "index": 0, "qualityType": "quality-table", "attributes": { "data-qc-repeat": "inspectionItems" } } ],
+ "dataSources": [],
+ "bindings": [],
+ "rules": [ { "id": "r1", "name": "瀹炴祴鍊煎湪瑙勬牸鍐�", "scope": "item", "expression": "item.actualValue >= item.lowerLimit", "enabled": true } ],
+ "styles": []
+ }""";
+
+ @Test
+ @DisplayName("鍚凡鍒犻櫎瀛楁鐨勬棫 Schema 浠嶈兘璇诲嚭鏉ワ紙鍚﹀垯鑰佹ā鏉挎墦涓嶅紑锛�")
+ void readsLegacySchemaWithRemovedFields() throws Exception {
+ ReportTemplateSchema schema = parse(LEGACY_JSON);
+
+ assertNotNull(schema);
+ assertEquals("1.0", schema.getSchemaVersion(), "鏃ц褰曠殑鐗堟湰鍙疯鍘熸牱璇诲嚭鏉ワ紝涓嶈兘鍥犱负鐗堟湰鍗囩骇灏变涪鎺�");
+ assertEquals("A4", schema.getPage().getSize());
+ assertEquals(12.0, schema.getPage().getMargin().getTop().doubleValue());
+ assertFalse(schema.getGrapes().isEmpty(), "鐢诲竷鏁版嵁涓嶈兘涓紝涓簡妯℃澘灏卞彧鍓╃┖澹�");
+
+ List<ReportTemplateSchema.QualityComponentNode> components = schema.getComponents();
+ assertEquals(1, components.size());
+ assertEquals("quality-table", components.get(0).getQualityType());
+ assertEquals(0, components.get(0).getIndex().intValue());
+ assertEquals("inspectionItems", components.get(0).getAttributes().get("data-qc-repeat"));
+
+ assertEquals(1, schema.getRules().size(), "瑙勫垯鏄璁″櫒绠′笉鍒扮殑瀛楁锛岃鐨勬椂鍊欑粷涓嶈兘灏�");
+ Map<String, Object> rule = schema.getRules().get(0);
+ assertEquals("item", rule.get("scope"));
+ assertEquals("item.actualValue >= item.lowerLimit", rule.get("expression"));
+ }
+
+ @Test
+ @DisplayName("鍐欏叆鍐嶈鍑猴細褰撳墠鏍煎紡寰�杩斾笉涓㈠唴瀹�")
+ void roundTripsCurrentSchema() throws Exception {
+ ReportTemplateSchema schema = parse(LEGACY_JSON);
+
+ Jackson3TypeHandler handler = handler();
+ ReportTemplateSchema reloaded = (ReportTemplateSchema) handler.parse(handler.toJson(schema));
+
+ assertEquals(schema.getSchemaVersion(), reloaded.getSchemaVersion());
+ assertEquals("quality-table", reloaded.getComponents().get(0).getQualityType());
+ assertEquals("item.actualValue >= item.lowerLimit",
+ reloaded.getRules().get(0).get("expression"));
+ assertEquals(1, reloaded.getRules().size());
+ }
+
+ @Test
+ @DisplayName("缂哄瓧娈电殑鏃� Schema 涔熻兘璇伙細鍙湁 schemaVersion 涓嶆姤閿�")
+ void readsSchemaMissingOptionalFields() throws Exception {
+ ReportTemplateSchema schema = parse("{\"schemaVersion\":\"1.0\"}");
+
+ assertEquals("1.0", schema.getSchemaVersion());
+ assertNull(schema.getPage());
+ assertNull(schema.getGrapes());
+ }
+
+ /** 璧� MyBatis 瀹炰緥鍖栫被鍨嬪鐞嗗櫒鐨勬柟寮忥細甯﹀瓧娈碉紝genericType 涓�骞跺甫涓� */
+ private static ReportTemplateSchema parse(String json) throws Exception {
+ return (ReportTemplateSchema) handler().parse(json);
+ }
+
+ private static Jackson3TypeHandler handler() throws NoSuchFieldException {
+ Field field = QcReportTemplateVersionDO.class.getDeclaredField("schema");
+ return new Jackson3TypeHandler(QcReportTemplateVersionDO.class, field);
+ }
+
+}
diff --git a/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/engine/FrontendConformanceTest.java b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/engine/FrontendConformanceTest.java
new file mode 100644
index 0000000..c6e0e52
--- /dev/null
+++ b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/engine/FrontendConformanceTest.java
@@ -0,0 +1,172 @@
+package cn.iocoder.yudao.module.qcreport.engine;
+
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.version.ReportTemplateSchema;
+import cn.iocoder.yudao.module.qcreport.engine.context.InspectionItem;
+import cn.iocoder.yudao.module.qcreport.engine.context.ReportContext;
+import cn.iocoder.yudao.module.qcreport.engine.render.RenderOutcome;
+import cn.iocoder.yudao.module.qcreport.engine.report.EvaluationOutcome;
+import cn.iocoder.yudao.module.qcreport.engine.report.ReportEvaluator;
+import cn.iocoder.yudao.module.qcreport.engine.rule.QualityRuleDefinition;
+import cn.iocoder.yudao.module.qcreport.engine.rule.RuleEngine;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * 涓庡墠绔紩鎿庣殑涓�鑷存�ф祴璇曘��
+ * <p>
+ * 娓叉煋寮曟搸涓庤鍒欏紩鎿庡湪鍓嶇锛坽@code src/components/quality/engine}锛夊悇鏈変竴濂楀疄鐜帮紝
+ * 璁捐鍣ㄩ瑙堢敤鍓嶇閭e銆佹湇鍔$鐢熸垚鎶ュ憡鐢ㄨ繖濂楋紝涓よ竟缁撴灉涓嶄竴鑷村氨绛変簬銆岄瑙堜笌鍑轰欢涓嶇銆嶏紝
+ * 閭f槸姣斿皯涓姛鑳芥洿闅炬煡鐨勯棶棰樸�傛墍浠ヨ繖閲岀敤鍚屼竴浠� fixture 璺戜袱杈癸紝閫愬瓧姣斿浜х墿銆�
+ * <p>
+ * fixture 涓庢湡鏈涗骇鐗╅兘鍦� {@code src/test/resources/qcreport/}锛�
+ * schema.json / context.json 鏄緭鍏ワ紝expected-html.html 涓� expected-rules.json 鏄墠绔紩鎿庣殑浜х墿銆�
+ * 鏈熸湜浜х墿鐢卞墠绔紩鎿庤窇 {@code mom-pro2-before/.qc-conformance/render-ts.ts} 鐢熸垚鍚庡喕缁擄紱
+ * 鏀瑰姩浠讳綍涓�渚х殑寮曟搸鍚庤閲嶆柊鐢熸垚锛屽啀璁╄繖涓祴璇曟妸宸紓椤跺嚭鏉ャ��
+ */
+class FrontendConformanceTest {
+
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+
+ private static final String FIXTURE = "qcreport/";
+
+ @Test
+ @DisplayName("娓叉煋浜х墿涓庡墠绔紩鎿庨�愬瓧涓�鑷�")
+ void renderMatchesFrontendEngine() throws IOException {
+ ReportTemplateSchema schema = readSchema();
+ ReportContext context = readContext();
+
+ RenderOutcome outcome = QualityReportEngine.render(schema, context);
+
+ assertEquals(readFixture("expected-html.html"), outcome.html(),
+ "鏈嶅姟绔覆鏌撶殑 HTML 涓庡墠绔紩鎿庝笉涓�鑷达紝棰勮鍜屽嚭浠朵細瀵逛笉涓�");
+ assertEquals(readErrors(), outcome.errors(), "鏁版嵁缂哄彛娓呭崟涓庡墠绔紩鎿庝笉涓�鑷�");
+ }
+
+ @Test
+ @DisplayName("鍒ゅ畾缁撴灉涓庡墠绔紩鎿庝竴鑷�")
+ void evaluationMatchesFrontendEngine() throws IOException {
+ ReportTemplateSchema schema = readSchema();
+ ReportContext context = readContext();
+
+ EvaluationOutcome evaluated = ReportEvaluator.evaluate(context, QualityReportEngine.rulesOf(schema));
+
+ assertEquals("FAIL", evaluated.context().getReport().getResult());
+ assertEquals("涓嶅悎鏍�", evaluated.context().getReport().getResultText());
+ assertEquals(3, evaluated.context().getReport().getTotal());
+ assertEquals(1, evaluated.context().getReport().getPassCount());
+ assertEquals(2, evaluated.context().getReport().getFailCount());
+ assertEquals("33.33%", evaluated.context().getReport().getPassRate());
+
+ List<InspectionItem> items = evaluated.context().getInspectionItems();
+ assertEquals(List.of("FAIL", "PASS", "FAIL"), List.of(
+ items.get(0).getResult(), items.get(1).getResult(), items.get(2).getResult()),
+ "澶栬鏃犱笂涓嬮檺浣嗘湁瑙勫垯銆侀暱搴﹀湪瑙勬牸鍐呫�佺‖搴﹁秴涓婇檺");
+ }
+
+ @Test
+ @DisplayName("瑙勫垯姹傚�间笌鍓嶇寮曟搸涓�鑷达紙鍚姤閿欐枃妗堬級")
+ void rulesMatchFrontendEngine() throws IOException {
+ ReportTemplateSchema schema = readSchema();
+ List<QualityRuleDefinition> rules = QualityReportEngine.rulesOf(schema);
+ ReportContext evaluated = ReportEvaluator.evaluate(readContext(), rules).context();
+
+ Map<String, Map<String, Object>> scopes = buildScopes(evaluated);
+ JsonNode expected = MAPPER.readTree(readFixture("expected-rules.json"));
+
+ for (JsonNode item : expected.get("results")) {
+ String expression = item.get("expression").asText();
+ String scope = item.get("scope").asText();
+ Map<String, Object> context = scopes.get(scope);
+ String label = scope + " / " + expression;
+
+ if (item.has("error")) {
+ RuntimeException error = assertThrows(RuntimeException.class,
+ () -> RuleEngine.evaluate(expression, context), label);
+ assertEquals(item.get("error").asText(), error.getMessage(), label);
+ continue;
+ }
+ Object value = RuleEngine.evaluate(expression, context);
+ assertEquals(item.get("kind").asText(), kindOf(value), label + " 鐨勭粨鏋滅被鍨嬩笉涓�鑷�");
+ assertEquals(item.get("text").asText(), JsValues.asText(value), label + " 鐨勭粨鏋滄枃鏈笉涓�鑷�");
+ }
+ }
+
+ /* ------------------------------ 杈呭姪 ------------------------------ */
+
+ private static Map<String, Map<String, Object>> buildScopes(ReportContext evaluated) {
+ List<InspectionItem> items = evaluated.getInspectionItems();
+
+ Map<String, Object> report = evaluated.toScope();
+ report.put("index", 0);
+
+ Map<String, Object> item2 = evaluated.toScope();
+ item2.put("item", ReportContext.itemMap(items.get(1)));
+ item2.put("index", 2);
+
+ Map<String, Object> item3 = evaluated.toScope();
+ item3.put("item", ReportContext.itemMap(items.get(2)));
+ item3.put("index", 3);
+
+ Map<String, Map<String, Object>> scopes = new LinkedHashMap<>();
+ scopes.put("report", report);
+ scopes.put("item2", item2);
+ scopes.put("item3", item3);
+ return scopes;
+ }
+
+ /** 涓� JS 鐨� typeof 瀵归綈锛歯ull/undefined 璁颁负 nil锛屾暟缁勪笌瀵硅薄閮芥槸 object */
+ private static String kindOf(Object value) {
+ if (value == null) {
+ return "nil";
+ }
+ if (value instanceof Boolean) {
+ return "boolean";
+ }
+ if (value instanceof Number) {
+ return "number";
+ }
+ if (value instanceof String) {
+ return "string";
+ }
+ return "object";
+ }
+
+ private static List<String> readErrors() throws IOException {
+ JsonNode node = MAPPER.readTree(readFixture("expected-rules.json")).get("errors");
+ List<String> errors = new ArrayList<>();
+ node.forEach(item -> errors.add(item.asText()));
+ return errors;
+ }
+
+ private static ReportTemplateSchema readSchema() throws IOException {
+ return MAPPER.readValue(readFixture("schema.json"), ReportTemplateSchema.class);
+ }
+
+ private static ReportContext readContext() throws IOException {
+ return MAPPER.readValue(readFixture("context.json"), ReportContext.class);
+ }
+
+ private static String readFixture(String name) throws IOException {
+ try (InputStream in = FrontendConformanceTest.class.getClassLoader()
+ .getResourceAsStream(FIXTURE + name)) {
+ if (in == null) {
+ throw new IOException("娴嬭瘯 fixture 缂哄け锛�" + FIXTURE + name);
+ }
+ return new String(in.readAllBytes(), StandardCharsets.UTF_8);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/engine/QualityReportEngineTest.java b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/engine/QualityReportEngineTest.java
new file mode 100644
index 0000000..bb02ac9
--- /dev/null
+++ b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/engine/QualityReportEngineTest.java
@@ -0,0 +1,96 @@
+package cn.iocoder.yudao.module.qcreport.engine;
+
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.version.ReportTemplateSchema;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * {@link QualityReportEngine#hasCanvas} 鐨勫垽鎹祴璇曘��
+ * <p>
+ * 杩欐潯鍒ゆ嵁鍚屾椂瀹堢潃涓ゅ锛氬嚭鎶ュ憡寮圭獥瑕佷笉瑕佹妸杩欎釜妯℃澘鎽嗗嚭鏉ワ紙{@code getSelectableTemplates}锛夛紝
+ * 浠ュ強鍑轰欢鍓嶈涓嶈鐩存帴鎷掔粷锛坽@code resolveVersion}锛夈�傚畠蹇呴』涓庢覆鏌撳櫒璇荤敾甯冪殑閭d竴琛�
+ * 锛坽@code pages[0].frames[0].component}锛変弗鏍间竴鑷粹�斺�旀斁瀹戒竴鐐癸紝鐢ㄦ埛灏变細鎷垮埌涓�寮犱笉鎶ラ敊鐨勭櫧绾� PDF銆�
+ */
+class QualityReportEngineTest {
+
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+
+ private static final String CANVAS_DIR = "qcreport/canvas/";
+
+ @Test
+ @DisplayName("鍙湁鍏冩暟鎹殑鐢诲竷涓嶇畻鏈夊唴瀹癸細瀹冩槸闈炵┖ Map锛屼絾娓叉煋鍣ㄥ彇涓嶅埌鏍圭粍浠讹紝娓叉煋鍑烘潵鏄櫧绾�")
+ void metadataOnlyGrapesIsNotCanvas() {
+ // GrapesJS 鎶娿�屾墦寮�杩囪璁″櫒浣嗕竴涓粍浠堕兘娌℃斁銆嶇殑椤圭洰瀛樻垚杩欎釜鏍峰瓙
+ assertFalse(QualityReportEngine.hasCanvas(schema(Map.of("assets", List.of(), "styles", List.of()))));
+ // 鍙浜� pages 浣嗘病鏈� frames 涔熶笉琛�
+ assertFalse(QualityReportEngine.hasCanvas(schema(Map.of("pages", List.of()))));
+ // 鏈� frame 浣嗘病鏈� component 鍚屾牱涓嶈
+ assertFalse(QualityReportEngine.hasCanvas(schema(Map.of("pages",
+ List.of(Map.of("frames", List.of(Map.of("id", "f1"))))))));
+ }
+
+ @Test
+ @DisplayName("frame 涓婃湁鏍圭粍浠舵墠绠楁湁鍐呭")
+ void frameComponentIsCanvas() {
+ assertTrue(QualityReportEngine.hasCanvas(schema(Map.of("pages",
+ List.of(Map.of("frames", List.of(Map.of("component",
+ Map.of("type", "wrapper", "components", List.of())))))))));
+ }
+
+ @Test
+ @DisplayName("Schema 鎴� grapes 涓� null 涓嶇畻鏈夊唴瀹癸紝涓斾笉鎶涢敊")
+ void nullSchemaOrGrapesIsNotCanvas() {
+ assertFalse(QualityReportEngine.hasCanvas(null));
+ assertFalse(QualityReportEngine.hasCanvas(new ReportTemplateSchema()));
+ assertFalse(QualityReportEngine.hasCanvas(schema(null)));
+ }
+
+ @ParameterizedTest(name = "瀛橀噺鐢诲竷 {0} 鏈夊唴瀹�")
+ @ValueSource(strings = {"canvas-t5-v1.0.json", "canvas-t3-v1.0.json", "canvas-t5-v1.1.json", "canvas-t5-v1.2.json"})
+ @DisplayName("杩愯搴撻噷鐪熸鐢讳簡涓滆タ鐨勭増鏈紝鍒ゆ嵁涓虹湡")
+ void realStoredCanvasIsCanvas(String fileName) throws IOException {
+ assertTrue(QualityReportEngine.hasCanvas(schema(realGrapes(fileName))), fileName);
+ }
+
+ @ParameterizedTest(name = "瀛橀噺绌虹敾甯� {0} 鏃犲唴瀹�")
+ @ValueSource(strings = {"canvas-t1-v1.0.json", "canvas-t1-v1.1.json"})
+ @DisplayName("杩愯搴撻噷銆屾墦寮�杩囦絾娌℃斁缁勪欢銆嶇殑鐗堟湰锛屽垽鎹负鍋囷紙瀹冨氨鏄櫧绾� PDF 鐨勬潵婧愶級")
+ void realStoredEmptyCanvasIsNotCanvas(String fileName) throws IOException {
+ assertFalse(QualityReportEngine.hasCanvas(schema(realGrapes(fileName))), fileName);
+ }
+
+ private static ReportTemplateSchema schema(Map<String, Object> grapes) {
+ ReportTemplateSchema schema = new ReportTemplateSchema();
+ schema.setGrapes(grapes);
+ return schema;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static Map<String, Object> realGrapes(String fileName) throws IOException {
+ String path = CANVAS_DIR + fileName;
+ try (InputStream in = QualityReportEngineTest.class.getClassLoader().getResourceAsStream(path)) {
+ if (in == null) {
+ throw new IOException("鎵句笉鍒扮敾甯冨す鍏凤細" + path);
+ }
+ Map<String, Object> full = MAPPER.readValue(new String(in.readAllBytes(), StandardCharsets.UTF_8),
+ new TypeReference<Map<String, Object>>() {
+ });
+ Object grapes = full.get("grapes");
+ return grapes instanceof Map<?, ?> ? (Map<String, Object>) grapes : null;
+ }
+ }
+
+}
diff --git a/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/engine/ReportEvaluatorTest.java b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/engine/ReportEvaluatorTest.java
new file mode 100644
index 0000000..bb2446f
--- /dev/null
+++ b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/engine/ReportEvaluatorTest.java
@@ -0,0 +1,399 @@
+package cn.iocoder.yudao.module.qcreport.engine;
+
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.version.ReportTemplateSchema;
+import cn.iocoder.yudao.module.qcreport.engine.context.InspectionItem;
+import cn.iocoder.yudao.module.qcreport.engine.context.ReportContext;
+import cn.iocoder.yudao.module.qcreport.engine.report.EvaluationOutcome;
+import cn.iocoder.yudao.module.qcreport.engine.report.ReportEvaluator;
+import cn.iocoder.yudao.module.qcreport.engine.rule.QualityRuleDefinition;
+import cn.iocoder.yudao.module.qcreport.engine.rule.RuleEngine;
+import cn.iocoder.yudao.module.qcreport.engine.rule.RuleEvaluator;
+import cn.iocoder.yudao.module.qcreport.engine.rule.RuleRuntimeException;
+import cn.iocoder.yudao.module.qcreport.engine.rule.RuleScope;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * 鍒ゅ畾璇箟娴嬭瘯銆�
+ * <p>
+ * {@link FrontendConformanceTest} 淇濊瘉鍚庣寮曟搸涓庡墠绔紩鎿庣畻寰椾竴鏍凤紝
+ * 杩欓噷绠$殑鏄�岀畻寰楀涓嶅銆嶏細鍒ゅ畾浼樺厛绾с�佷负浠�涔堜笉缁欑粨璁恒�佽鍒欏啓閿欐椂鎶ヤ粈涔堛��
+ * 鍏朵腑銆屽緟鍒ゅ畾涓嶇粰鍚堟牸缁撹銆嶆槸 Phase 2 淇繃鐨勪竴涓湡瀹炵己闄凤紝涓嬮潰鏈夌敤渚嬪畧鐫�銆�
+ */
+class ReportEvaluatorTest {
+
+ /* ------------------------------ 鍗曢」鍒ゅ畾 ------------------------------ */
+
+ @Test
+ @DisplayName("瀹炴祴鍊煎湪瑙勬牸涓婁笅闄愬唴鍒ゅ悎鏍硷紝瓒呭嚭鍒や笉鍚堟牸")
+ void judgesItemByLimits() {
+ ReportContext context = ReportContext.empty().setInspectionItems(List.of(
+ item("闀垮害", "10.2", 10.5, 9.5),
+ item("纭害", "62", 60.0, 50.0),
+ item("瀹藉害", "4.9", 5.0, 5.0)));
+
+ List<InspectionItem> items = ReportEvaluator.evaluate(context, List.of()).context().getInspectionItems();
+
+ assertEquals("PASS", items.get(0).getResult());
+ assertEquals("鍚堟牸", items.get(0).getResultText());
+ assertEquals("FAIL", items.get(1).getResult());
+ assertEquals("涓嶅悎鏍�", items.get(1).getResultText());
+ assertEquals("FAIL", items.get(2).getResult(), "浣庝簬涓嬮檺鍚屾牱鍒や笉鍚堟牸");
+ }
+
+ @Test
+ @DisplayName("鍙湁鍗曚晶瑙勬牸鏃跺彧鎸夋湁鐨勪竴渚у垽")
+ void judgesItemWithOneSidedLimit() {
+ ReportContext context = ReportContext.empty().setInspectionItems(List.of(
+ item("鍘氬害", "0.9", null, 1.0),
+ item("閲嶉噺", "3", 5.0, null)));
+
+ List<InspectionItem> items = ReportEvaluator.evaluate(context, List.of()).context().getInspectionItems();
+
+ assertEquals("FAIL", items.get(0).getResult(), "鍙粰浜嗕笅闄愶紝0.9 浣庝簬 1.0");
+ assertEquals("PASS", items.get(1).getResult(), "鍙粰浜嗕笂闄愶紝3 娌¤秴 5.0");
+ }
+
+ @Test
+ @DisplayName("閫愰」瑙勫垯浼樺厛浜庤鏍间笂涓嬮檺")
+ void itemRuleWinsOverLimits() {
+ // 瀹炴祴鍊兼槑鏄庡湪涓婁笅闄愬唴锛屼絾瑙勫垯瑕佹眰瀹炴祴鍊尖墺50锛屾墍浠ュ簲鍒や笉鍚堟牸
+ ReportContext context = ReportContext.empty().setInspectionItems(List.of(item("纭害", "10.2", 10.5, 9.5)));
+ List<QualityRuleDefinition> rules = List.of(itemRule("瀹炴祴鍊艰揪鏍�", "item.actualValue >= 50"));
+
+ List<InspectionItem> items = ReportEvaluator.evaluate(context, rules).context().getInspectionItems();
+
+ assertEquals("FAIL", items.get(0).getResult(), "鏈夎鍒欐椂浠ヨ鍒欎负鍑嗭紝涓嶅啀鐪嬩笂涓嬮檺");
+ }
+
+ @Test
+ @DisplayName("娌℃湁瑙勫垯涔熸病鏈変笂涓嬮檺鏃跺彇鏁版嵁鑷甫鐨勭粨鏋�")
+ void fallsBackToDataSuppliedResult() {
+ InspectionItem appearance = item("澶栬", "鍚堟牸", null, null).setResult("FAIL");
+ ReportContext context = ReportContext.empty().setInspectionItems(List.of(appearance));
+
+ List<InspectionItem> items = ReportEvaluator.evaluate(context, List.of()).context().getInspectionItems();
+
+ assertEquals("FAIL", items.get(0).getResult(), "鏁版嵁閲屽凡缁忓~浜嗗垽瀹氬�煎氨鐩存帴鐢�");
+ assertEquals("涓嶅悎鏍�", items.get(0).getResultText());
+ }
+
+ @Test
+ @DisplayName("鏃㈡棤瑙勫垯涔熸棤涓婁笅闄愩�佹暟鎹噷涔熸病缁撴灉鏃舵爣涓烘棤鍒ゅ畾瑙勫垯骞惰杩涢棶棰樻竻鍗�")
+ void marksUndecidableItemWithoutVerdict() {
+ ReportContext context = ReportContext.empty()
+ .setInspectionItems(List.of(item("澶栬", "鏃犲垝鐥�", null, null)));
+
+ EvaluationOutcome outcome = ReportEvaluator.evaluate(context, List.of());
+ InspectionItem item = outcome.context().getInspectionItems().get(0);
+
+ assertEquals("", item.getResult());
+ assertEquals(QualityResult.UNDECIDABLE_TEXT, item.getResultText());
+ assertEquals(1, outcome.errors().size());
+ assertEquals("绗� 1 椤广�屽瑙傘�嶆病鏈夎鏍间笂涓嬮檺涔熸病鏈夊垽瀹氳鍒欙紝鏃犳硶鍒ゅ畾", outcome.errors().get(0));
+ assertEquals(1, outcome.context().getReport().getTotal(), "鎬绘暟鐓у疄绠楋紝涓嶅洜涓哄垽涓嶄簡灏变笉绠�");
+ assertEquals("", outcome.context().getReport().getPassRate(), "涓�椤归兘鍒や笉浜嗘椂鍚堟牸鐜囩暀绌鸿�屼笉鏄� 0.00%");
+ }
+
+ @Test
+ @DisplayName("鏃犲垽瀹氳鍒欑殑椤逛笉璁″叆鍚堟牸鐜囧垎姣嶏紝涔熶笉鍘嬩綇鍚堟牸缁撹")
+ void undecidableItemIsExcludedFromPassRate() {
+ // 銆岃瘯鏍疯川閲� m銆嶈繖绫昏繃绋嬪弬鏁板彧渚涘叕寮忓彇鏁帮紝娌℃湁瑙勬牸涔熷氨鏃犱粠鍒ゅ畾
+ ReportContext context = ReportContext.empty().setInspectionItems(List.of(
+ item("闀垮害", "10.2", 10.5, 9.5),
+ item("璇曟牱璐ㄩ噺 m", "50.2", null, null)));
+
+ EvaluationOutcome outcome = ReportEvaluator.evaluate(context, List.of());
+
+ assertEquals("PASS", outcome.context().getReport().getResult(), "杩囩▼鍙傛暟涓嶈鎶婂叏鍚堟牸鐨勬姤鍛婂帇鎴愬緟鍒ゅ畾");
+ assertEquals(2, outcome.context().getReport().getTotal(), "鎬绘暟浠嶆槸鐪熷疄鐨勬楠岄」鏁�");
+ assertEquals(1, outcome.context().getReport().getPassCount());
+ assertEquals("100.00%", outcome.context().getReport().getPassRate(), "鍒嗘瘝鍙畻鍙垽瀹氶」");
+ assertEquals(QualityResult.UNDECIDABLE_TEXT,
+ outcome.context().getInspectionItems().get(1).getResultText());
+ }
+
+ @Test
+ @DisplayName("瑙勫垯鎵ц鎶ラ敊鏃惰椤逛笉缁欑粨璁猴紝閿欒閲屽甫涓婇」鍚嶄笌瑙勫垯鍚�")
+ void reportsRuleFailureWithoutVerdict() {
+ ReportContext context = ReportContext.empty().setInspectionItems(List.of(item("纭害", "62", 60.0, 50.0)));
+ List<QualityRuleDefinition> rules = List.of(itemRule("闄ら浂瑙勫垯", "item.actualValue / 0 > 0"));
+
+ EvaluationOutcome outcome = ReportEvaluator.evaluate(context, rules);
+ InspectionItem item = outcome.context().getInspectionItems().get(0);
+
+ assertEquals("", item.getResult(), "瑙勫垯璺戜笉閫氬氨涓嶈兘璇村悎鏍间篃涓嶈兘璇翠笉鍚堟牸");
+ assertEquals(QualityResult.PENDING_TEXT, item.getResultText());
+ assertEquals(List.of("绗� 1 椤广�岀‖搴︺�嶇殑瑙勫垯銆岄櫎闆惰鍒欍�嶆棤娉曟墽琛岋細瑙勫垯閲屽嚭鐜颁簡闄や互 0"), outcome.errors());
+ }
+
+ /* ------------------------------ 鎶ュ憡姹囨�� ------------------------------ */
+
+ @Test
+ @DisplayName("鍏ㄩ儴妫�楠岄」鍚堟牸鎵嶇粰鍚堟牸缁撹锛屽悎鏍肩巼 100%")
+ void allPassGivesPassVerdict() {
+ ReportContext context = ReportContext.empty().setInspectionItems(List.of(
+ item("闀垮害", "10.2", 10.5, 9.5),
+ item("瀹藉害", "4.9", 5.0, 4.0)));
+
+ EvaluationOutcome outcome = ReportEvaluator.evaluate(context, List.of());
+
+ assertEquals("PASS", outcome.context().getReport().getResult());
+ assertEquals("鍚堟牸", outcome.context().getReport().getConclusion());
+ assertEquals(2, outcome.context().getReport().getTotal());
+ assertEquals(2, outcome.context().getReport().getPassCount());
+ assertEquals("100.00%", outcome.context().getReport().getPassRate());
+ }
+
+ @Test
+ @DisplayName("鏈変笉鍚堟牸椤瑰氨缁欎笉鍚堟牸缁撹锛屽悎鏍肩巼鎸夋瘮渚嬬畻")
+ void anyFailGivesFailVerdict() {
+ ReportContext context = ReportContext.empty().setInspectionItems(List.of(
+ item("闀垮害", "10.2", 10.5, 9.5),
+ item("纭害", "62", 60.0, 50.0),
+ item("瀹藉害", "4.9", 5.0, 4.0)));
+
+ EvaluationOutcome outcome = ReportEvaluator.evaluate(context, List.of());
+
+ assertEquals("FAIL", outcome.context().getReport().getResult());
+ assertEquals(2, outcome.context().getReport().getPassCount());
+ assertEquals(1, outcome.context().getReport().getFailCount());
+ assertEquals("66.67%", outcome.context().getReport().getPassRate());
+ }
+
+ /**
+ * Phase 2 鐨勭湡瀹炵己闄凤細涓夐」閲屼袱椤瑰悎鏍笺�佷竴椤规病楠屽嚭缁撹锛屾棫閫昏緫鍙暟銆屾湁娌℃湁涓嶅悎鏍笺�嶏紝
+ * 浜庢槸缁欏嚭銆岀粨璁哄悎鏍笺�佸悎鏍肩巼 66.67%銆嶈繖绉嶈嚜鐩哥煕鐩剧殑鎶ュ憡銆傛病楠岃繃鐨勯」涓嶈兘璁╂姤鍛婅儗鍚堟牸銆�
+ * <p>
+ * 銆屾棤鍒ゅ畾瑙勫垯銆嶆媶鍒嗗嚭鍘讳箣鍚庯紝銆屽緟鍒ゅ畾銆嶅彧鍓╀竴涓潵婧愶細椤硅鍒欒窇鎸備簡銆�
+ * 锛堟病瑙勫垯鍙堟病涓婁笅闄愮殑閭g鏄�屾棤鍒ゅ畾瑙勫垯銆嶏紝宸蹭笉璁″叆鍒嗘瘝銆傦級鎵�浠ヨ繖鏉$敤渚嬫敼鐢�
+ * 涓�鏉″湪銆屽瑙傘�嶄笂绠椾笉鍑烘潵鐨勮鍒欐潵澶嶇幇銆�
+ */
+ @Test
+ @DisplayName("瀛樺湪寰呭垽瀹氶」鏃朵笉缁欏悎鏍肩粨璁猴紙鍥炲綊锛氫笉寰楀嚭鐜般�屽悎鏍� + 鍚堟牸鐜囦笉瓒� 100%銆嶏級")
+ void pendingItemBlocksPassVerdict() {
+ ReportContext context = ReportContext.empty().setInspectionItems(List.of(
+ item("闀垮害", "10.2", 10.5, 9.5),
+ item("瀹藉害", "4.9", 5.0, 4.0),
+ item("澶栬", "鏃犲垝鐥�", null, null)));
+ // 澶栬瀹炴祴鍊兼槸銆屾棤鍒掔棔銆嶏紝鏁板�煎嚱鏁板湪瀹冭韩涓婄畻涓嶅嚭鏉� 鈫� 璇ラ」寰呭垽瀹�
+ List<QualityRuleDefinition> rules = List.of(itemRule("瀹炴祴鍊煎彲绠�", "ABS(item.actualValue) >= 0"));
+
+ EvaluationOutcome outcome = ReportEvaluator.evaluate(context, rules);
+
+ assertEquals("", outcome.context().getReport().getResult());
+ assertEquals(QualityResult.PENDING_TEXT, outcome.context().getReport().getConclusion());
+ assertEquals(2, outcome.context().getReport().getPassCount());
+ assertEquals(0, outcome.context().getReport().getFailCount(), "寰呭垽瀹氭棦涓嶇畻鍚堟牸涔熶笉绠椾笉鍚堟牸");
+ assertEquals(3, outcome.context().getReport().getTotal());
+ assertEquals("66.67%", outcome.context().getReport().getPassRate(), "寰呭垽瀹氶」浠嶇暀鍦ㄥ悎鏍肩巼鍒嗘瘝閲�");
+ }
+
+ @Test
+ @DisplayName("涓�椤归兘娌℃湁鏃朵笉缁欑粨璁猴紝鍚堟牸鐜囩暀绌鸿�屼笉鏄� 0.00%")
+ void emptyReportHasNoVerdict() {
+ EvaluationOutcome outcome = ReportEvaluator.evaluate(ReportContext.empty(), List.of());
+
+ assertEquals("", outcome.context().getReport().getResult());
+ assertEquals(0, outcome.context().getReport().getTotal());
+ assertEquals("", outcome.context().getReport().getPassRate());
+ assertTrue(outcome.errors().isEmpty());
+ }
+
+ @Test
+ @DisplayName("鏈夋姤鍛婄骇瑙勫垯鏃朵互瑙勫垯涓哄噯锛屼笉鍐嶇湅閫愰」姹囨��")
+ void reportRuleWinsOverAggregation() {
+ // 閫愰」鍏ㄥ悎鏍硷紝浣嗘姤鍛婄骇瑙勫垯瑕佹眰鍚堟牸鐜団墺150%锛屽繀鐒朵笉鎴愮珛
+ ReportContext context = ReportContext.empty().setInspectionItems(List.of(item("闀垮害", "10.2", 10.5, 9.5)));
+ List<QualityRuleDefinition> rules = List.of(
+ new QualityRuleDefinition("r", "鏁翠綋鍚堟牸", RuleScope.REPORT, "PASS_RATE(inspectionItems.result) >= 150", true));
+
+ EvaluationOutcome outcome = ReportEvaluator.evaluate(context, rules);
+
+ assertEquals("FAIL", outcome.context().getReport().getResult());
+ assertEquals(1, outcome.context().getReport().getPassCount(), "姹囨�绘暟鎹収甯哥畻鍑烘潵锛屽彧鏄笉鎷挎潵瀹氱粨璁�");
+ }
+
+ @Test
+ @DisplayName("鍋滅敤鐨勮鍒欎笉鍙備笌鍒ゅ畾")
+ void disabledRuleIsIgnored() {
+ ReportContext context = ReportContext.empty().setInspectionItems(List.of(item("闀垮害", "10.2", 10.5, 9.5)));
+ List<QualityRuleDefinition> rules = List.of(
+ new QualityRuleDefinition("r", "瀹炴祴鍊艰揪鏍�", RuleScope.ITEM, "item.actualValue >= 50", false));
+
+ EvaluationOutcome outcome = ReportEvaluator.evaluate(context, rules);
+
+ assertEquals("PASS", outcome.context().getInspectionItems().get(0).getResult(), "瑙勫垯琚仠鐢紝閫�鍥炴寜涓婁笅闄愬垽");
+ assertTrue(outcome.errors().isEmpty());
+ }
+
+ @Test
+ @DisplayName("鍒ゅ畾涓嶄慨鏀逛紶杩涙潵鐨勪笂涓嬫枃")
+ void doesNotMutateInputContext() {
+ ReportContext context = ReportContext.empty().setInspectionItems(List.of(item("纭害", "62", 60.0, 50.0)));
+
+ ReportEvaluator.evaluate(context, List.of());
+
+ assertEquals("", context.getInspectionItems().get(0).getResult(), "鍘熶笂涓嬫枃鐨勬楠岄」涓嶈琚啓鍥炲垽瀹氬��");
+ assertEquals("", context.getReport().getResult());
+ assertEquals(0, context.getReport().getTotal());
+ }
+
+ /* ------------------------------ 瑙勫垯姹傚�肩殑鍋ュ.鎬� ------------------------------ */
+
+ @Test
+ @DisplayName("鍑芥暟缂哄弬鎶ュ彲璇婚敊璇紝鑰屼笉鏄姏涓嬫爣瓒婄晫绌块�忓埌鎺ュ彛灞�")
+ void missingArgumentGivesReadableError() {
+ RuleRuntimeException error = assertThrows(RuleRuntimeException.class,
+ () -> RuleEngine.evaluate("SUM()", ReportContext.empty().toScope()));
+
+ assertEquals("鍑芥暟 SUM 闇�瑕佹暟鍊煎瀷鍙傛暟锛屽疄闄呭彇鍒般�屻��", error.getMessage());
+ }
+
+ @Test
+ @DisplayName("鏈煡鍑芥暟鎶ラ敊閲屽垪鍑哄叏閮ㄥ彲鐢ㄥ嚱鏁帮紝椤哄簭绋冲畾")
+ void unknownFunctionListsAvailableFunctions() {
+ RuleRuntimeException error = assertThrows(RuleRuntimeException.class,
+ () -> RuleEngine.evaluate("FOO(1)", ReportContext.empty().toScope()));
+
+ assertEquals("涓嶆敮鎸佸嚱鏁� FOO锛屽彲鐢ㄥ嚱鏁帮細ABS銆丄VG銆丆OUNT銆丆P銆丆PK銆丗AIL_RATE銆丮AX銆丮IN銆丳ASS_RATE銆丷OUND銆丼TDDEV銆丼UM",
+ error.getMessage());
+ }
+
+ @Test
+ @DisplayName("淇濆瓨鍓嶆牎楠岋細璇硶閿欒涓庢湭鐭ュ嚱鏁伴兘鑳借鎷︿笅")
+ void validateCatchesSyntaxAndUnknownFunction() {
+ assertEquals(List.of("瑙勫垯銆屽啓寰椾笉瀵广�嶈娉曢敊璇細琛ㄨ揪寮忎笉瀹屾暣锛堢 20 涓瓧绗︼級"),
+ RuleEngine.validate(itemRule("鍐欏緱涓嶅", "item.actualValue >= ")));
+ assertTrue(RuleEngine.validate(itemRule("鍐欏緱瀵�", "item.actualValue >= item.lowerLimit")).isEmpty());
+ assertEquals("FOO", RuleEngine.findUnknownFunction("FOO(item.actualValue)"));
+ assertNull(RuleEngine.findUnknownFunction("ABS(item.actualValue)"));
+ }
+
+ @Test
+ @DisplayName("绌鸿〃杈惧紡鍗曠嫭缁欎竴鏉℃彁绀猴紝涓嶅啀褰撴垚璇硶閿欒")
+ void validateReportsEmptyExpression() {
+ assertEquals(List.of("瑙勫垯銆岀┖瑙勫垯銆嶇殑琛ㄨ揪寮忎负绌�"), RuleEngine.validate(itemRule("绌鸿鍒�", " ")));
+ }
+
+ /**
+ * 淇濆瓨鍓嶇殑鏁翠唤妯℃澘鏍¢獙銆傝娉曚笌鐧藉悕鍗曚袱鍧楅兘瑕佹嫤锛氬彧鎷﹁娉曠殑璇濓紝
+ * {@code FOO(1)} 杩欑璋冪敤浼氫竴璺瓨杩涘簱閲岋紝涔嬪悗姣忓紶鎶ュ憡閮藉甫涓�鏉°�屾棤娉曟墽琛屻�嶃��
+ */
+ @Test
+ @DisplayName("妯℃澘绾ц鍒欐牎楠岋細璇硶閿欎笌鐧藉悕鍗曞鐨勫嚱鏁伴兘瑕佹嫤涓嬶紝骞舵寚鏄庢槸鍝潯瑙勫垯")
+ void validatesAllRulesBeforeSave() {
+ ReportTemplateSchema schema = new ReportTemplateSchema();
+ schema.setSchemaVersion(ReportTemplateSchema.SCHEMA_VERSION);
+ schema.setRules(List.of(
+ Map.of("id", "r1", "name", "璇硶鍐欓敊", "scope", "item", "expression", "item.actualValue >= "),
+ Map.of("id", "r2", "name", "鍑芥暟涓嶅瓨鍦�", "scope", "report", "expression", "FOO(inspectionItems)"),
+ Map.of("id", "r3", "name", "姝e父瑙勫垯", "scope", "item", "expression", "item.actualValue > 0")));
+
+ assertEquals(List.of(
+ "瑙勫垯銆岃娉曞啓閿欍�嶈娉曢敊璇細琛ㄨ揪寮忎笉瀹屾暣锛堢 20 涓瓧绗︼級",
+ "瑙勫垯銆屽嚱鏁颁笉瀛樺湪銆嶈皟鐢ㄤ簡涓嶆敮鎸佺殑鍑芥暟 FOO锛屽彲鐢ㄥ嚱鏁帮細ABS銆丄VG銆丆OUNT銆丆P銆丆PK銆丗AIL_RATE銆丮AX銆丮IN銆丳ASS_RATE銆丷OUND銆丼TDDEV銆丼UM"),
+ QualityReportEngine.validateRules(schema));
+ }
+
+ @Test
+ @DisplayName("瑙勫垯閮藉悎瑙勬椂鏍¢獙杩斿洖绌烘竻鍗�")
+ void validatePassesWhenRulesAreFine() {
+ ReportTemplateSchema schema = new ReportTemplateSchema();
+ schema.setRules(List.of(
+ Map.of("id", "r1", "name", "瑙勬牸鍐�", "scope", "item", "expression", "item.actualValue BETWEEN item.lowerLimit AND item.upperLimit"),
+ Map.of("id", "r2", "name", "鍚堟牸鐜�", "scope", "report", "expression", "PASS_RATE(inspectionItems.result) >= 60")));
+
+ assertTrue(QualityReportEngine.validateRules(schema).isEmpty());
+ }
+
+ /**
+ * 鍘嗗彶鑴忔暟鎹噷鍙兘鏈夌己 expression 鐨勮鍒欓」銆傝鐨勬椂鍊欏瀹瑰湴鐣欑潃锛堟墽琛屾湡浼氭姤鍑烘潵锛夛紝
+ * 浣嗕繚瀛樺墠鏍¢獙瑕佹嫤涓嬫潵锛氳鍒欑紪杈戠晫闈㈠凡缁忓仛鍑烘潵浜嗭紝鐢ㄦ埛鍦ㄨ璁″櫒閲屽垹鎺夎繖鏉″氨鑳界户缁繚瀛樸��
+ * 鍦ㄦ涔嬪墠杩欐潯鏄斁琛岀殑鈥斺�斿綋鏃舵病鏈夎鍒欑晫闈紝鎶ラ敊鍙細璁╀汉鍗″湪淇濆瓨涓嶄簡锛屾棤澶勫彲鏀广��
+ */
+ @Test
+ @DisplayName("缂� expression 鐨勮鍒欎細琚鍙栧埌锛屼絾闃绘柇淇濆瓨锛堣鍒欑晫闈㈤噷鍒犲緱鎺夛紝涓嶅啀鏄璺級")
+ void blankExpressionRuleBlocksSave() {
+ ReportTemplateSchema schema = new ReportTemplateSchema();
+ schema.setRules(List.of(
+ Map.of("scope", "item"),
+ Map.of("id", "r2", "name", "鍚堟牸鐜�", "scope", "report", "expression", "PASS_RATE(inspectionItems.result) >= 60")));
+
+ assertEquals(2, QualityReportEngine.rulesOf(schema).size(), "瀹芥澗璇诲彇锛氫袱涓兘鐣欑潃");
+ assertEquals(List.of("瑙勫垯銆屾湭鍛藉悕瑙勫垯銆嶇殑琛ㄨ揪寮忎负绌�"), QualityReportEngine.validateRules(schema),
+ "绌鸿〃杈惧紡涔熻鎷︿綇锛屼笖涓嶈兘鍥犳鎶婂彟涓�鏉℃甯歌鍒欎篃鎶ユ垚閿欑殑");
+ }
+
+ @Test
+ @DisplayName("绌鸿〃杈惧紡鐨勮鍒欏湪鎵ц鏈熶細琚姤鍑烘潵锛屼笉鑷充簬闈欓粯澶辨晥")
+ void blankExpressionRuleSurfacesAtExecution() {
+ ReportTemplateSchema schema = new ReportTemplateSchema();
+ schema.setRules(List.of(Map.of("id", "r1", "name", "绌鸿鍒�", "scope", "item")));
+
+ EvaluationOutcome outcome = ReportEvaluator.evaluate(
+ ReportContext.empty().setInspectionItems(List.of(item("澶栬", "鏃犲垝鐥�", null, null))),
+ QualityReportEngine.rulesOf(schema));
+
+ assertEquals(List.of("绗� 1 椤广�屽瑙傘�嶇殑瑙勫垯銆岀┖瑙勫垯銆嶆棤娉曟墽琛岋細瑙勫垯琛ㄨ揪寮忎负绌�"), outcome.errors());
+ assertEquals(QualityResult.PENDING_TEXT, outcome.context().getInspectionItems().get(0).getResultText());
+ }
+
+ @Test
+ @DisplayName("鍒ゅ畾缁撴灉鍙栧�煎吋瀹逛腑鏂囥�佸竷灏斾笌 1/0")
+ void normalizesResultTokens() {
+ assertEquals("PASS", RuleEvaluator.normalizeResultToken("鍚堟牸"));
+ assertEquals("PASS", RuleEvaluator.normalizeResultToken(true));
+ assertEquals("PASS", RuleEvaluator.normalizeResultToken("1"));
+ assertEquals("FAIL", RuleEvaluator.normalizeResultToken("NG"));
+ assertEquals("FAIL", RuleEvaluator.normalizeResultToken(false));
+ assertEquals("FAIL", RuleEvaluator.normalizeResultToken("鍚�"));
+ assertEquals("", RuleEvaluator.normalizeResultToken("涔熻"), "璁や笉鍑烘潵鐨勫彇鍊间笉鑳界瀻鐚�");
+ }
+
+ /**
+ * 杩欓噷鐨勭湡鍊煎彛寰勬槸銆屽紩鎿庡彛寰勩�嶄笉鏄�孞S Boolean() 鍙e緞銆嶏細
+ * 鑳藉綋鏁板瓧鐪嬬殑鍙栧�肩粺涓�鎸� {@code !== 0} 鍒ょ湡锛屾墍浠ュ瓧绗︿覆 "0" 鏄亣鍊硷紝
+ * 鑰屽師鐢� JS 鐨� {@code Boolean("0")} 鏄湡鍊笺�傚墠绔紩鎿庡氨鏄繖涔堝啓鐨勶紝鍚庣鐓ф惉鎵嶆湁涓�鑷存�э紝
+ * 鏀瑰姩鍓嶅繀椤诲厛鏀瑰墠绔紝鍚﹀垯棰勮涓庡嚭浠朵細鍒嗗弶銆�
+ */
+ @Test
+ @DisplayName("鐪熷�煎垽瀹氫笌鍓嶇寮曟搸鍚屽彛寰�")
+ void truthinessMatchesEngine() {
+ assertFalse(RuleEvaluator.truthy(null));
+ assertFalse(RuleEvaluator.truthy(""));
+ assertFalse(RuleEvaluator.truthy(0));
+ assertFalse(RuleEvaluator.truthy(false));
+ assertFalse(RuleEvaluator.truthy("0"), "鑳藉綋鏁板瓧鐪嬶紝鎵�浠ユ槸鍋囧�尖�斺�斾笌鍘熺敓 JS Boolean(\"0\") 涓嶅悓");
+ assertTrue(RuleEvaluator.truthy("abc"), "褰撲笉鎴愭暟瀛楃殑瀛楃涓叉槸鐪熷��");
+ assertTrue(RuleEvaluator.truthy(1));
+ assertFalse(RuleEvaluator.truthy(List.of()), "绌烘暟缁勫垽鍋囷細娌℃湁妫�楠岄」涓嶈兘绠椼�屾湁鏁版嵁銆�");
+ assertTrue(RuleEvaluator.truthy(List.of("PASS")));
+ assertTrue(RuleEvaluator.isBlank(null));
+ assertTrue(RuleEvaluator.isBlank(""));
+ // 绌哄�间笌鐪熷�兼槸涓ょ爜浜嬶細绌烘暟缁勩�屼笉绌恒�嶄絾銆屽亣銆�
+ assertFalse(RuleEvaluator.isBlank(List.of()), "绌烘暟缁勪笉绠楃┖");
+ }
+
+ /* ------------------------------ 杈呭姪 ------------------------------ */
+
+ private static InspectionItem item(String name, String actual, Double upper, Double lower) {
+ return new InspectionItem()
+ .setItemName(name).setActualValue(actual)
+ .setUpperLimit(upper).setLowerLimit(lower);
+ }
+
+ private static QualityRuleDefinition itemRule(String name, String expression) {
+ return new QualityRuleDefinition("rule-" + name, name, RuleScope.ITEM, expression, true);
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/engine/context/ReportContextCodecTest.java b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/engine/context/ReportContextCodecTest.java
new file mode 100644
index 0000000..e7fd464
--- /dev/null
+++ b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/engine/context/ReportContextCodecTest.java
@@ -0,0 +1,198 @@
+package cn.iocoder.yudao.module.qcreport.engine.context;
+
+import cn.iocoder.yudao.module.qcreport.dal.dataobject.version.ReportTemplateSchema;
+import cn.iocoder.yudao.module.qcreport.engine.QualityReportEngine;
+import cn.iocoder.yudao.module.qcreport.engine.render.RenderOutcome;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * 鏁版嵁蹇収鐨勭紪瑙g爜銆�
+ * <p>
+ * 杩欓噷鏄�屽巻鍙叉姤鍛婂彲澶嶇幇銆嶇殑鍞竴瀹炵幇璺緞锛屾墍浠ョ涓�鏉$敤渚嬩笉鏄瘮瀵瑰揩鐓ф湰韬紝
+ * 鑰屾槸<b>璧板畬鏁撮摼璺�</b>锛氬嚭浠� 鈫� 鍐荤粨蹇収 鈫� 浠庡揩鐓ц鍥� 鈫� 閲嶆覆锛屼骇鐗╁繀椤讳笌棣栨閫愬瓧鐩稿悓銆�
+ * 鍙杩欐潯鏂簡锛屾姤鍛婂疄渚嬪氨浼氬嚭鐜般�岀敓鎴愭椂涓�涓牱銆侀噸鏂扮敓鎴愬悗鍙︿竴涓牱銆嶏紝
+ * 鑰屽簱閲岀殑鏁版嵁鐪嬩笉鍑轰换浣曞紓甯糕�斺�旇繖绉嶉棶棰樹簨鍚庢瀬闅捐拷銆�
+ * <p>
+ * 鐢ㄧ殑鏄笌瀵规媿鍚屼竴浠� fixture锛坽@code schema.json} / {@code context.json} /
+ * {@code expected-html.html}锛夛紝鎵�浠ャ�岄噸娓蹭竴鑷淬�嶄笌銆屽墠鍚庣涓�鑷淬�嶅湪杩欓噷鏄竴娆℃�ч獙璇佺殑銆�
+ */
+class ReportContextCodecTest {
+
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+
+ private static final String FIXTURE = "qcreport/";
+
+ @Test
+ @DisplayName("鍐荤粨蹇収璇诲洖鍚庨噸娓诧紝浜х墿涓庨娆″嚭浠堕�愬瓧鐩稿悓")
+ void roundTripReproducesHtml() throws IOException {
+ ReportTemplateSchema schema = readSchema();
+
+ // 1. 棣栨鍑轰欢锛氬垽瀹� + 娓叉煋
+ RenderOutcome first = QualityReportEngine.render(schema, readContext());
+ assertEquals(readFixture("expected-html.html"), first.html(), "棣栨鍑轰欢灏变笌鍓嶇寮曟搸涓嶄竴鑷�");
+
+ // 2. 鍐荤粨蹇収锛堝瓨鐨勫氨鏄垽瀹氬悗鐨勪笂涓嬫枃锛�
+ Map<String, Object> snapshot = ReportContextCodec.toMap(first.context());
+
+ // 3. 浠庡揩鐓ц鍥烇紝閲嶆覆
+ RenderOutcome second = QualityReportEngine.render(schema, ReportContextCodec.fromMap(snapshot));
+
+ assertEquals(first.html(), second.html(),
+ "浠庢暟鎹揩鐓ч噸娓茬殑 HTML 涓庨娆″嚭浠朵笉涓�鑷达紝鍘嗗彶鎶ュ憡涓嶅啀鍙鐜�");
+ assertEquals(first.errors(), second.errors(), "閲嶆覆鐨勬暟鎹己鍙f竻鍗曚笌棣栨鍑轰欢涓嶄竴鑷�");
+ }
+
+ @Test
+ @DisplayName("蹇収閲屽甫鐫�绠楀ソ鐨勫垽瀹氱粨鏋滀笌鍚堟牸鐜�")
+ void snapshotCarriesEvaluation() throws IOException {
+ RenderOutcome outcome = QualityReportEngine.render(readSchema(), readContext());
+
+ Map<String, Object> snapshot = ReportContextCodec.toMap(outcome.context());
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> report = (Map<String, Object>) snapshot.get("report");
+ assertEquals("FAIL", report.get("result"));
+ assertEquals(3, report.get("total"));
+ assertEquals("33.33%", report.get("passRate"));
+
+ @SuppressWarnings("unchecked")
+ List<Object> items = (List<Object>) snapshot.get("inspectionItems");
+ assertEquals(3, items.size());
+ assertEquals("FAIL", ((Map<?, ?>) items.get(0)).get("result"));
+ assertEquals("PASS", ((Map<?, ?>) items.get(1)).get("result"));
+ }
+
+ @Test
+ @DisplayName("缂栬В鐮佸線杩斾笉涓㈠瓧娈碉細鏂囨湰銆佹暣鏁般�佷笂涓嬮檺銆佺┖鍊奸兘鍘熸牱鍥炴潵")
+ void roundTripIsLossless() {
+ InspectionItem item = new InspectionItem()
+ .setIndex(7)
+ .setItemCode("LEN")
+ .setItemName("闀垮害")
+ .setStandardValue("10卤0.5")
+ .setActualValue("10.2")
+ .setUnit("mm")
+ // 妫�娴嬭姹備笌妫�娴嬫柟娉曞悇鍗犱竴澶勶細妯℃澘閲屽父鍚勫啓涓�鍒楋紝寰�杩旀椂蹇呴』閮戒笉涓�
+ .setRequirement("10卤0.5")
+ .setCheckMethod("GB/T 1804-2000")
+ .setUpperLimit(10.5D)
+ .setLowerLimit(9.5D)
+ .setResult("PASS")
+ .setResultText("鍚堟牸")
+ .setRemark("鎶芥");
+ ReportContext original = new ReportContext()
+ .setReport(new ReportFields()
+ .setReportNo("QR20260918-0001")
+ .setReportName("鍑鸿揣妫�楠屾姤鍛�")
+ .setProductName("娉曞叞")
+ .setInspector("寮犱笁")
+ .setResult("PASS")
+ .setResultText("鍚堟牸")
+ .setConclusion("鍑嗕簣鍑鸿揣")
+ .setPassRate("100.00%")
+ .setTotal(1)
+ .setPassCount(1)
+ .setFailCount(0))
+ .setInspectionItems(new ArrayList<>(List.of(item)));
+
+ ReportContext restored = ReportContextCodec.fromMap(ReportContextCodec.toMap(original));
+
+ assertEquals(original, restored, "寰�杩斿悗鏈夊瓧娈靛彉浜�");
+ }
+
+ @Test
+ @DisplayName("娌℃湁瑙勬牸鍖洪棿鐨勯」锛屼笂涓嬮檺淇濇寔涓� null锛屼笉浼氳濉垚 0")
+ void absentLimitsStayNull() {
+ String itemName = "澶栬";
+ InspectionItem original = new InspectionItem().setIndex(1).setItemName(itemName);
+
+ ReportContext restored = ReportContextCodec.fromMap(
+ ReportContextCodec.toMap(new ReportContext().setInspectionItems(new ArrayList<>(List.of(original)))));
+
+ InspectionItem item = restored.getInspectionItems().get(0);
+ assertEquals(itemName, item.getItemName());
+ assertNull(item.getUpperLimit(), "娌″啓涓婇檺鐨勯」琚垽鎴愩�屼笂闄� 0銆嶏紝瑙勬牸鍒ゅ畾浼氬叏閿�");
+ assertNull(item.getLowerLimit());
+ }
+
+ @Test
+ @DisplayName("瀛楁涓嶅叏鐨勫揩鐓х収甯歌鍥烇細缂虹殑瀛楁鏄�屾病鍊笺�嶏紙绌轰覆锛夛紝涓嶆槸鎶ラ敊")
+ void partialSnapshotReadsAsEmpty() {
+ Map<String, Object> snapshot = new LinkedHashMap<>();
+ Map<String, Object> report = new LinkedHashMap<>();
+ report.put("reportNo", "QR20260918-0001");
+ report.put("reportName", "鏉ユ枡妫�楠屾姤鍛�");
+ snapshot.put("report", report);
+ snapshot.put("inspectionItems", List.of(Map.of("index", 1, "itemName", "澶栬")));
+
+ ReportContext context = ReportContextCodec.fromMap(snapshot);
+
+ assertEquals("QR20260918-0001", context.getReport().getReportNo());
+ assertEquals("鏉ユ枡妫�楠屾姤鍛�", context.getReport().getReportName());
+ assertEquals("", context.getReport().getProductName(), "缂虹殑瀛楁搴斿綋鏄┖涓�");
+ assertEquals(0, context.getReport().getTotal());
+ assertEquals(1, context.getInspectionItems().size());
+ assertEquals("", context.getInspectionItems().get(0).getActualValue());
+ }
+
+ @Test
+ @DisplayName("绌哄揩鐓ц鍥炵┖鐧戒笂涓嬫枃锛屼笉鎶涘紓甯�")
+ void nullAndEmptySnapshotYieldEmptyContext() {
+ assertNotNull(ReportContextCodec.fromMap(null).getReport());
+ assertTrue(ReportContextCodec.fromMap(null).getInspectionItems().isEmpty());
+ assertTrue(ReportContextCodec.fromMap(new LinkedHashMap<>()).getInspectionItems().isEmpty());
+ assertNotNull(ReportContextCodec.toMap(null).get("report"));
+ }
+
+ @Test
+ @DisplayName("妫�楠岄」鏁扮粍閲屾贩杩涢潪瀵硅薄鍏冪礌鏃惰烦杩囪鍏冪礌锛屼笉璁╂暣浠芥姤鍛婃墦涓嶅紑")
+ void malformedItemIsSkipped() {
+ Map<String, Object> snapshot = new LinkedHashMap<>();
+ snapshot.put("inspectionItems", List.of(
+ Map.of("index", 1, "itemName", "澶栬"),
+ "涓嶆槸瀵硅薄",
+ Map.of("index", 3, "itemName", "纭害")));
+
+ ReportContext context = ReportContextCodec.fromMap(snapshot);
+
+ assertEquals(2, context.getInspectionItems().size());
+ assertEquals("澶栬", context.getInspectionItems().get(0).getItemName());
+ assertEquals("纭害", context.getInspectionItems().get(1).getItemName());
+ }
+
+ /* ------------------------------ 杈呭姪 ------------------------------ */
+
+ private static ReportTemplateSchema readSchema() throws IOException {
+ return MAPPER.readValue(readFixture("schema.json"), ReportTemplateSchema.class);
+ }
+
+ private static ReportContext readContext() throws IOException {
+ return MAPPER.readValue(readFixture("context.json"), ReportContext.class);
+ }
+
+ private static String readFixture(String name) throws IOException {
+ try (InputStream in = ReportContextCodecTest.class.getClassLoader()
+ .getResourceAsStream(FIXTURE + name)) {
+ if (in == null) {
+ throw new IOException("娴嬭瘯 fixture 缂哄け锛�" + FIXTURE + name);
+ }
+ return new String(in.readAllBytes(), StandardCharsets.UTF_8);
+ }
+ }
+
+}
diff --git a/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/engine/render/CanvasSafetyTest.java b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/engine/render/CanvasSafetyTest.java
new file mode 100644
index 0000000..c80a278
--- /dev/null
+++ b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/engine/render/CanvasSafetyTest.java
@@ -0,0 +1,242 @@
+package cn.iocoder.yudao.module.qcreport.engine.render;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * 鐢诲竷瀹夊叏鎬ф牎楠屾祴璇曘��
+ * <p>
+ * 涓ょ被鏂█鍚勫畧涓�浠朵簨锛�
+ * <ul>
+ * <li><b>瀹夊叏</b>锛氬嚒鏄覆鏌撴椂浼氬師鏍锋嫾杩涗骇鐗╃殑鑴忓唴瀹癸紙鏍囩鍚嶃�佸睘鎬у悕銆佹暣娈� CSS锛夐兘瑕佽鎷︿笅锛�
+ * 鍚﹀垯妯℃澘浣滆�呭氨鑳藉線鎶ュ憡閲屽鑴氭湰鎴栨彁鍓嶉棴鍚� {@code <style>}銆�</li>
+ * <li><b>涓嶈鏉�</b>锛氬簱閲屽叏閮ㄧ湡瀹炲瓨閲忕敾甯冮兘蹇呴』閫氳繃锛坽@code qcreport/canvas/*.json} 鏄粠杩愯搴撳鍑虹殑鍘熸牱鏁版嵁锛夛紝
+ * 鐧藉悕鍗曚竴鏃︽敹寰楄繃绱э紝姝e父妯℃澘浼氱獊鐒朵繚瀛樹笉浜嗐��</li>
+ * </ul>
+ * <p>
+ * 鐢ㄤ緥閲岀殑鐢诲竷涓�寰嬪啓鎴�<b>鐪熷疄褰㈢姸</b>锛坽@code pages[0].frames[0].component} 鏄牴 wrapper锛岃剰鑺傜偣鎸傚湪瀹冪殑
+ * {@code components} 閲岋級銆傝嫢鎶� {@code components} 鎽嗗湪 grapes 鏍逛笂锛屾牎楠屽櫒璧颁笉鍒板畠銆佹柇瑷�浼氥�屽洜涓轰粈涔堥兘娌℃鏌ャ��
+ * 鑰屽亣閫氳繃鈥斺�斿畨鍏ㄦ祴璇曠殑鍋囬�氳繃姣斾笉鍐欐洿鍗遍櫓銆�
+ */
+class CanvasSafetyTest {
+
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+
+ private static final String CANVAS_DIR = "qcreport/canvas/";
+
+ /** 涓�浠芥渶灏忔甯稿寘瑁咃細鏍� wrapper + 涓�涓� h2 + 涓�寮犱袱琛岀殑琛紝tags 鍏ㄥ湪鐧藉悕鍗曞唴 */
+ private static final String VALID_WRAPPER = """
+ {
+ "type": "wrapper",
+ "components": [
+ { "type": "text", "tagName": "h2", "components": [ { "type": "textnode", "content": "鏉ユ枡妫�楠屾姤鍛�" } ] },
+ {
+ "type": "table",
+ "components": [ {
+ "type": "row",
+ "components": [
+ { "type": "cell", "tagName": "th", "attributes": { "colspan": "2" }, "components": [] },
+ { "type": "cell", "components": [ { "type": "textnode", "content": "鍚堟牸" } ] }
+ ]
+ } ]
+ }
+ ]
+ }""";
+
+ @Test
+ @DisplayName("姝e父鐢诲竷涓嶆斁琛屼换浣曢棶棰�")
+ void acceptsNormalCanvas() {
+ assertEquals(List.of(), CanvasSafety.validate(canvas(VALID_WRAPPER)));
+
+ // 鏍峰紡涔熻蛋涓�閬嶆甯歌矾寰勶細瑙勫垯鏁扮粍锛堥�夋嫨鍣� + 灞炴�� + 濯掍綋鏌ヨ锛夋槸璁捐鍣ㄤ繚瀛樺悗鐨勬爣鍑嗗舰鎬侊紝涓嶈兘琚鍒�
+ assertEquals(List.of(), CanvasSafety.validate(grapes("""
+ {
+ "pages": [ { "frames": [ { "component": { "type": "wrapper", "components": [] } } ] } ],
+ "styles": [ {
+ "selectors": [ "#ih35" ], "style": { "padding": "0" },
+ "mediaText": "(max-width: 794px)", "atRuleType": "media"
+ } ]
+ }""")));
+ }
+
+ @ParameterizedTest(name = "瀛橀噺鐢诲竷 {0} 蹇呴』閫氳繃")
+ @ValueSource(strings = {
+ "canvas-t1-v1.0.json", "canvas-t1-v1.1.json", "canvas-t5-v1.0.json",
+ "canvas-t3-v1.0.json", "canvas-t5-v1.1.json", "canvas-t5-v1.2.json"})
+ @DisplayName("杩愯搴撳鍑虹殑鐪熷疄瀛橀噺鐢诲竷鍏ㄩ儴閫氳繃锛堢櫧鍚嶅崟涓嶈兘璇潃姝e父妯℃澘锛�")
+ void acceptsRealStoredCanvases(String fileName) throws IOException {
+ Map<String, Object> grapes = grapesFromFixture(fileName);
+
+ assertEquals(List.of(), CanvasSafety.validate(grapes),
+ fileName + " 鏄繍琛屽簱閲岀湡瀹炵殑妯℃澘鐢诲竷锛岃鏂版牎楠屾嫤涓嬭鏄庣櫧鍚嶅崟鎴栬鍒欐敹寰楄繃绱�");
+ }
+
+ @Test
+ @DisplayName("鍙墽琛�/宓屽叆寮忔爣绛捐鎷掞紝涓旀彁绀洪噷鐐瑰悕鏄摢涓爣绛�")
+ void rejectsDangerousTag() {
+ List<String> problems = CanvasSafety.validate(canvas("""
+ { "type": "wrapper", "components": [
+ { "type": "text", "tagName": "script", "components": [] } ] }"""));
+
+ assertEquals(1, problems.size());
+ assertTrue(problems.get(0).contains("script"), "鎻愮ず瑕佺偣鏄庢槸鍝釜鏍囩锛屽惁鍒欑敤鎴蜂笉鐭ラ亾鍘诲垹浠�涔�");
+ assertTrue(problems.get(0).contains("绗� 1 涓粍浠�"), "鎻愮ず瑕佺粰鍑轰綅缃細" + problems.get(0));
+ }
+
+ @Test
+ @DisplayName("tagName 閲屽灞炴�т篃鎷﹀緱浣忥紙鏍囩鍚嶆槸鐩存帴鎷艰繘浜х墿鐨勶紝涓嶈浆涔夛級")
+ void rejectsAttributeSmuggledInTagName() {
+ // 鑻ユ爣绛惧悕涓嶈繃鐧藉悕鍗曪紝杩欎竴鎵嬩細娓叉煋鎴� <img src=x onerror=alert(1)> 鈥斺�� 浜嬩欢灞炴�х粫杩囦簡灞炴�у悕鐨勬鏌�
+ List<String> problems = CanvasSafety.validate(canvas("""
+ { "type": "wrapper", "components": [
+ { "type": "image", "tagName": "img src=x onerror=alert(1)", "components": [] } ] }"""));
+
+ assertFalse(problems.isEmpty(), "甯︾┖鏍煎拰绛夊彿鐨勩�屾爣绛惧悕銆嶅繀椤昏鎷掞紝鍚﹀垯绛変簬鏀捐涓�涓簨浠跺睘鎬�");
+ assertTrue(problems.get(0).contains("img src=x onerror=alert(1)"), problems.get(0));
+ }
+
+ @Test
+ @DisplayName("灞炴�у悕鍚紩鍙�/绌烘牸琚嫆锛堝睘鎬у悕涓嶈浆涔夛紝鍙《鍑烘柊灞炴�э級")
+ void rejectsIllegalAttributeName() {
+ List<String> problems = CanvasSafety.validate(canvas("""
+ { "type": "wrapper", "components": [
+ { "type": "text", "tagName": "p", "attributes": { "x\\" onload\\"alert(1)": "1" }, "components": [] } ] }"""));
+
+ assertEquals(1, problems.size());
+ assertTrue(problems.get(0).contains("涓嶆槸鍚堟硶鐨勫睘鎬у悕"), problems.get(0));
+ }
+
+ @Test
+ @DisplayName("浜嬩欢灞炴�ц鎷�")
+ void rejectsEventAttribute() {
+ List<String> problems = CanvasSafety.validate(canvas("""
+ { "type": "wrapper", "components": [
+ { "type": "image", "tagName": "img", "attributes": { "onerror": "alert(1)" }, "components": [] } ] }"""));
+
+ assertEquals(1, problems.size());
+ assertTrue(problems.get(0).contains("onerror") && problems.get(0).contains("浜嬩欢灞炴��"), problems.get(0));
+ }
+
+ @Test
+ @DisplayName("鏁存 CSS 瀛楃涓茶鎷掞紙buildCss 浼氬師鏍峰杩� <style>锛岃兘鎻愬墠闂悎锛�")
+ void rejectsRawCssString() {
+ List<String> problems = CanvasSafety.validate(grapes("""
+ {
+ "pages": [ { "frames": [ { "component": { "type": "wrapper", "components": [] } } ] } ],
+ "styles": "</style><script>alert(1)</script>"
+ }"""));
+
+ assertEquals(1, problems.size());
+ assertTrue(problems.get(0).contains("鏁存 CSS"), problems.get(0));
+ }
+
+ @Test
+ @DisplayName("鏍峰紡瑙勫垯閲屽嚭鐜般��<銆嶈鎷掞細閫夋嫨鍣ㄣ�佸睘鎬у�笺�佸獟浣撴煡璇㈡潯浠堕兘绠�")
+ void rejectsAngleBracketInStyleFragments() {
+ List<String> bySelector = CanvasSafety.validate(grapes("""
+ { "pages": [ { "frames": [ { "component": { "type": "wrapper", "components": [] } } ] } ],
+ "styles": [ { "selectors": [ "a</style><script>x</script>" ], "style": { "color": "red" } } ] }"""));
+ assertTrue(bySelector.stream().anyMatch(p -> p.contains("閫夋嫨鍣�")), bySelector.toString());
+
+ List<String> byValue = CanvasSafety.validate(grapes("""
+ { "pages": [ { "frames": [ { "component": { "type": "wrapper", "components": [] } } ] } ],
+ "styles": [ { "selectors": [ "p" ], "style": { "content": "</style>" } } ] }"""));
+ assertTrue(byValue.stream().anyMatch(p -> p.contains("content")), byValue.toString());
+
+ List<String> byMedia = CanvasSafety.validate(grapes("""
+ { "pages": [ { "frames": [ { "component": { "type": "wrapper", "components": [] } } ] } ],
+ "styles": [ { "selectors": [ "p" ], "mediaText": "print</style>x", "style": { "color": "red" } } ] }"""));
+ assertTrue(byMedia.stream().anyMatch(p -> p.contains("濯掍綋鏌ヨ")), byMedia.toString());
+ }
+
+ @Test
+ @DisplayName("textnode 涓婄殑 tagName 涓嶅弬涓庢牎楠岋細娓叉煋鍣ㄦ牴鏈笉璇诲畠锛屼笉璇ュ洜姝ゆ嫤浣忎繚瀛�")
+ void ignoresTagNameOfTextNode() {
+ assertEquals(List.of(), CanvasSafety.validate(canvas("""
+ { "type": "wrapper", "components": [
+ { "type": "textnode", "tagName": "script", "content": "绾枃鏈�" } ] }""")));
+ }
+
+ @Test
+ @DisplayName("鍙部 components 璧帮細GrapesJS 鎸傚湪鑺傜偣涓婄殑 docEl / head 鍏冩暟鎹笉瑙﹀彂璇垽")
+ void ignoresNonRenderedMetadata() {
+ // 鐪熷疄鐢诲竷閲� frame 鐨勬牴缁勪欢涓婂氨鎸傜潃 docEl:{tagName:"html"} 涓� head:{type:"head"}锛屾覆鏌撳櫒涓や釜閮戒笉璇�
+ assertEquals(List.of(), CanvasSafety.validate(grapes("""
+ { "pages": [ { "frames": [ { "component": {
+ "type": "wrapper",
+ "docEl": { "tagName": "html" },
+ "head": { "type": "head", "components": [ { "type": "text", "tagName": "style" } ] },
+ "components": [ { "type": "text", "tagName": "p", "components": [] } ] } } ] } ] }""")));
+ }
+
+ @Test
+ @DisplayName("闂鏉℃暟鏈変笂闄愶細鑴忓唴瀹瑰緢澶氭椂涔熶笉瑕佸悙涓�灞忔彁绀�")
+ void capsProblemCount() {
+ StringBuilder components = new StringBuilder();
+ for (int i = 0; i < 20; i++) {
+ components.append(i == 0 ? "" : ",").append("{ \"type\": \"text\", \"tagName\": \"script\" }");
+ }
+ List<String> problems = CanvasSafety.validate(canvas(
+ "{ \"type\": \"wrapper\", \"components\": [ " + components + " ] }"));
+
+ assertEquals(8, problems.size(), "涓婇檺鏄� 8 鏉★紝鏀瑰畬鍐嶅瓨涓�娆″氨鑳界湅鍒颁笅涓�鎵�");
+ }
+
+ @Test
+ @DisplayName("grapes 涓虹┖涓嶆姤閿欙紙鏂板缓妯℃澘杩樻病鐢讳笢瑗匡級")
+ void toleratesNullGrapes() {
+ assertEquals(List.of(), CanvasSafety.validate(Map.of()));
+ assertEquals(List.of(), CanvasSafety.validate(Map.of("pages", List.of())));
+ }
+
+ /** 鎶婄敤渚嬪啓鐨勬牴 wrapper 鍖呮垚鐪熷疄鐢诲竷褰㈢姸锛歡rapes.pages[0].frames[0].component */
+ private static Map<String, Object> canvas(String wrapperJson) {
+ return grapes("{\"pages\":[{\"frames\":[{\"component\":" + wrapperJson + "}]}]}");
+ }
+
+ private static Map<String, Object> grapes(String grapesJson) {
+ try {
+ return MAPPER.readValue(grapesJson, new TypeReference<Map<String, Object>>() {
+ });
+ } catch (IOException e) {
+ throw new IllegalArgumentException("娴嬭瘯鐢ㄤ緥鐨� JSON 鍐欓敊浜嗭細" + grapesJson, e);
+ }
+ }
+
+ private static String readCanvasFixture(String fileName) throws IOException {
+ try (InputStream in = CanvasSafetyTest.class.getClassLoader().getResourceAsStream(CANVAS_DIR + fileName)) {
+ if (in == null) {
+ throw new IOException("鎵句笉鍒扮敾甯冨す鍏凤細" + CANVAS_DIR + fileName);
+ }
+ return new String(in.readAllBytes(), StandardCharsets.UTF_8);
+ }
+ }
+
+ /** 澶瑰叿鏄畬鏁� Schema锛屾牎楠屽櫒鍙悆閲岄潰鐨� grapes */
+ private static Map<String, Object> grapesFromFixture(String fileName) throws IOException {
+ Map<String, Object> schema = grapes(readCanvasFixture(fileName));
+ Object grapes = schema.get("grapes");
+ assertTrue(grapes instanceof Map<?, ?>, fileName + " 閲屾病鏈� grapes锛屽す鍏峰彲鑳藉閿欎簡");
+ return asMap(grapes);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static Map<String, Object> asMap(Object value) {
+ return (Map<String, Object>) value;
+ }
+
+}
diff --git a/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/AiImportFixtures.java b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/AiImportFixtures.java
new file mode 100644
index 0000000..cc7b95c
--- /dev/null
+++ b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/AiImportFixtures.java
@@ -0,0 +1,241 @@
+package cn.iocoder.yudao.module.qcreport.service.aiimport.document;
+
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.PDPageContentStream;
+import org.apache.pdfbox.pdmodel.common.PDRectangle;
+import org.apache.pdfbox.pdmodel.font.PDType1Font;
+import org.apache.pdfbox.pdmodel.font.Standard14Fonts;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFTable;
+import org.apache.poi.xwpf.usermodel.XWPFTableCell;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.math.BigInteger;
+
+/**
+ * 娴嬭瘯鐢ㄧ殑浜岃繘鍒舵牱鏈紝<b>鍦ㄥ唴瀛橀噷鐜板満鐢熸垚</b>锛屼笉钀藉湴鎴愯祫婧愭枃浠躲��
+ * <p>
+ * 鍒绘剰涓嶅線 {@code src/test/resources} 鏀� .pdf / .docx 浜岃繘鍒讹細閭g鏂囦欢鍦ㄤ粨搴撻噷鏃� review 涓嶄簡涔熸敼涓嶅姩锛�
+ * 鎯崇煡閬撳畠閲岄潰鍐欎簡浠�涔堣繕寰椾笓闂ㄦ墦寮�鐪嬨�傜幇鍦虹敓鎴愬垯璁┿�屾牱鏈噷鏈変粈涔堝唴瀹广�嶇洿鎺ュ啓鍦ㄦ祴璇曚唬鐮侀噷锛�
+ * 涓�鐪煎氨鑳界湅鍑烘柇瑷�涓轰粈涔堟垚绔嬨��
+ * <p>
+ * 浠d环鏄牱鏈敤浜嗕笌鐢熶骇鍚屾簮鐨勫簱锛圥DFBox / POI锛夋潵鍐欌�斺�旇繖纭疄鏄嚜璇併��
+ * 浣嗚繖閲岃楠岃瘉鐨勬湰鏉ュ氨涓嶆槸銆孭DFBox 鑳戒笉鑳借В鏋� PDF銆嶏紝鑰屾槸<b>閫傞厤鍣ㄦ嬁鍒颁竴浠借繖鏍风殑鏂囦欢浼氳蛋鍝潯閫氶亾銆�
+ * 鎶藉嚭浠�涔堢粨鏋�</b>锛岄偅姝f槸杩欎簺鏍锋湰鑳藉洖绛旂殑闂銆�
+ */
+final class AiImportFixtures {
+
+ private AiImportFixtures() {
+ }
+
+ /**
+ * 鏈夋枃鏈眰鐨勭數瀛愮増 PDF锛屾瘡椤靛啓涓�娈佃冻澶熼暱鐨� ASCII 鏂囨湰锛堣秴杩囬粯璁ら槇鍊� 30 瀛楃锛夈��
+ * <p>
+ * 鐢� ASCII 鑰屼笉鏄腑鏂囷細PDF 鐨� 14 鍙锋爣鍑嗗瓧浣撲笉鍚腑鏂囧瓧褰紝鍐欎腑鏂囪涔堟姤閿欒涔堝彉鎴愪竴涓查棶鍙凤紝
+ * 鑰屾湰鐢ㄤ緥鍙叧蹇冦�屾湁娌℃湁鏂囨湰灞傘�嶏紝涓嶅叧蹇冧腑鏂囨覆鏌撱��
+ */
+ static byte[] textPdf(int pageCount) {
+ try (PDDocument document = new PDDocument()) {
+ for (int i = 1; i <= pageCount; i++) {
+ PDPage page = new PDPage(PDRectangle.A4);
+ document.addPage(page);
+ try (PDPageContentStream stream = new PDPageContentStream(document, page)) {
+ stream.beginText();
+ stream.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA), 12);
+ stream.newLineAtOffset(50, 700);
+ stream.showText("Incoming Inspection Report page " + i);
+ stream.newLineAtOffset(0, -20);
+ stream.showText("Item Size Tolerance Result Qty Remark Inspector");
+ stream.endText();
+ }
+ }
+ return save(document);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ /**
+ * 鍙湁椤甸潰銆佹病鏈夋枃瀛楃殑 PDF鈥斺�旂瓑浠蜂簬涓�浠芥壂鎻忎欢锛氭娊涓嶅嚭鏂囨湰灞傦紝鍙兘娓叉煋鎴愬浘銆�
+ */
+ static byte[] imageOnlyPdf(int pageCount) {
+ try (PDDocument document = new PDDocument()) {
+ for (int i = 0; i < pageCount; i++) {
+ document.addPage(new PDPage(PDRectangle.A4));
+ }
+ return save(document);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ /**
+ * 娈佃惤涓庤〃鏍�<b>浜ゆ浛</b>鎺掑垪鐨� .docx锛岀敤浜庨獙璇佹娊鍙栦繚鐣欑増闈㈤『搴忚�屼笉鏄�屾墍鏈夋钀� 鈫� 鎵�鏈夎〃鏍笺�嶃��
+ */
+ static byte[] docx(String beforeTable, String[][] table, String afterTable) {
+ try (XWPFDocument document = new XWPFDocument()) {
+ document.createParagraph().createRun().setText(beforeTable);
+ XWPFTable xwpfTable = document.createTable(table.length, table[0].length);
+ for (int r = 0; r < table.length; r++) {
+ for (int c = 0; c < table[r].length; c++) {
+ xwpfTable.getRow(r).getCell(c).setText(table[r][c]);
+ }
+ }
+ document.createParagraph().createRun().setText(afterTable);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ document.write(out);
+ return out.toByteArray();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ /**
+ * 甯�<b>绾靛悜鍚堝苟</b>鐨� .docx锛氬悓涓�妫�楠岄」鐩笅鐨勫瓙椤归�愯灞曞紑锛岄」鐩悕鍙湪绗竴琛屽嚭鐜帮紝
+ * 涓嬮潰鍑犺鏄� {@code <w:vMerge/>} 缁牸銆�
+ * <p>
+ * 杩欐鏄�屼竴涓楠岄」鐩笅鎸傝嫢骞插瓙椤广�嶇殑鐪熷疄鎶ュ憡褰㈡�侊細鍚堝苟淇℃伅涓嶈繕鍘熺殑璇濓紝
+ * 鎶藉嚭鏉ョ殑鏄竴鍫嗙湅涓嶅嚭鐖跺瓙鍏崇郴鐨勫钩閾鸿銆�
+ */
+ static byte[] docxWithVerticalMerge() {
+ String[][] cells = {
+ {"妫�楠岄」鐩�", "瀛愰」", "妫�娴嬫柟娉�", "鏍囧噯鍊�", "瀹炴祴鍊�", "鍒ゅ畾"},
+ {"绮掑害-绛涗笂鐗╂瘮渚嬶紙%锛�", "20鐩笂", "ANA.MTH-000034", "0-5", "", "鍚堟牸"},
+ {"", "40鐩笂", "ANA.MTH-000034", "20-40", "", "鍚堟牸"},
+ {"姘村垎", "甯稿帇骞茬嚗娉�", "ANA.MTH-000035", "鈮�14.0", "", "鍚堟牸"},
+ };
+ try (XWPFDocument document = new XWPFDocument()) {
+ XWPFTable table = createFilledTable(document, cells);
+ mergeDown(table, 1, 2, 0);
+ return write(document);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ /**
+ * 甯�<b>妯悜鍚堝苟</b>鐨� .docx锛氳〃澶寸涓�鏍艰法涓ゅ垪锛坽@code w:gridSpan="2"}锛夈��
+ * <p>
+ * 鍙叧蹇冨垪浣嶅榻愯繖涓粨鏋勯棶棰橈紝鍒楀悕涓嶈拷姹備笌鐪熷疄鎶ュ憡涓�涓�瀵瑰簲銆傝〃澶磋鍥犳姣旀暟鎹澶氬崰涓�鏍硷紝
+ * 鏁版嵁琛屽皯鐨勯偅鏍肩敱閫傞厤鍣ㄨˉ榻愨�斺�斾笉琛ョ殑璇濊〃澶翠笌鏁版嵁琛岀殑鍒椾粠姝ら敊寮�锛屾ā鍨嬩細寮犲啝鏉庢埓銆�
+ */
+ static byte[] docxWithGridSpanHeader() {
+ String[][] cells = {
+ {"妫�楠岄」鐩�", "鏍囧噯鍊�", "瀹炴祴鍊�"},
+ {"澶栬", "鏃犲垝鐥�", "鍚堟牸"},
+ };
+ try (XWPFDocument document = new XWPFDocument()) {
+ XWPFTable table = createFilledTable(document, cells);
+ cellPropertiesOf(table.getRow(0).getCell(0)).addNewGridSpan().setVal(BigInteger.valueOf(2));
+ return write(document);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ /**
+ * 甯﹂〉鐪夐〉鑴氱殑 .docx锛氭姮澶翠笌钀芥浣忓湪姝f枃涔嬪锛寋@code getBodyElements()} 鐪嬩笉鍒板畠浠��
+ */
+ static byte[] docxWithHeaderFooter(String bodyText, String headerText, String footerText) {
+ try (XWPFDocument document = new XWPFDocument()) {
+ document.createParagraph().createRun().setText(bodyText);
+ XWPFHeaderFooterPolicy policy = document.createHeaderFooterPolicy();
+ policy.createHeader(XWPFHeaderFooterPolicy.DEFAULT).createParagraph().createRun().setText(headerText);
+ policy.createFooter(XWPFHeaderFooterPolicy.DEFAULT).createParagraph().createRun().setText(footerText);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ document.write(out);
+ return out.toByteArray();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ /**
+ * 鍚垪澶寸殑 .xlsx銆�
+ */
+ static byte[] xlsx(String sheetName, String[][] rows) {
+ try (XSSFWorkbook workbook = new XSSFWorkbook()) {
+ Sheet sheet = workbook.createSheet(sheetName);
+ for (int r = 0; r < rows.length; r++) {
+ Row row = sheet.createRow(r);
+ for (int c = 0; c < rows[r].length; c++) {
+ row.createCell(c).setCellValue(rows[r][c]);
+ }
+ }
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ workbook.write(out);
+ return out.toByteArray();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ /**
+ * 甯� UTF-8 BOM 鐨勬枃鏈紝鐢ㄤ簬楠岃瘉 BOM 琚墺鎺夛紙鍚﹀垯绗竴涓崟鍏冩牸浼氬甫涓�涓湅涓嶈鐨勫瓧绗︼級銆�
+ */
+ static byte[] textWithBom(String text) {
+ byte[] body = text.getBytes(java.nio.charset.StandardCharsets.UTF_8);
+ byte[] result = new byte[body.length + 3];
+ result[0] = (byte) 0xEF;
+ result[1] = (byte) 0xBB;
+ result[2] = (byte) 0xBF;
+ System.arraycopy(body, 0, result, 3, body.length);
+ return result;
+ }
+
+ private static byte[] save(PDDocument document) throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ document.save(out);
+ return out.toByteArray();
+ }
+
+ /** 寤轰竴寮犳瘡鏍奸兘濉ソ鏂囧瓧鐨勮鍒欒〃鏍硷紝鍚庣画鍐嶆寜闇�鎵撲笂鍚堝苟鏍囪 */
+ private static XWPFTable createFilledTable(XWPFDocument document, String[][] cells) {
+ XWPFTable table = document.createTable(cells.length, cells[0].length);
+ for (int r = 0; r < cells.length; r++) {
+ for (int c = 0; c < cells[r].length; c++) {
+ table.getRow(r).getCell(c).setText(cells[r][c]);
+ }
+ }
+ return table;
+ }
+
+ /**
+ * 鎶婄 {@code fromRow} 琛屽埌绗� {@code toRow} 琛岀殑绗� {@code column} 鍒楃旱鍚戝悎骞舵垚涓�涓崟鍏冩牸銆�
+ * <p>
+ * 璧峰鏍兼墦 {@code w:val="restart"}銆佸悗缁牸鎵撲笉甯� val 鐨� {@code <w:vMerge/>}锛圵ord 鐨勫父瑙佸啓娉曪級锛�
+ * 涓棿鏍兼竻绌烘枃瀛椻�斺�旂湡瀹炴枃浠堕噷缁牸鏈潵灏辨槸绌虹殑锛屽悎骞朵俊鎭叏鍦ㄩ偅涓爣绛句笂銆�
+ */
+ private static void mergeDown(XWPFTable table, int fromRow, int toRow, int column) {
+ cellPropertiesOf(table.getRow(fromRow).getCell(column))
+ .addNewVMerge().setVal(STMerge.RESTART);
+ for (int r = fromRow + 1; r <= toRow; r++) {
+ XWPFTableCell cell = table.getRow(r).getCell(column);
+ cell.setText("");
+ cellPropertiesOf(cell).addNewVMerge();
+ }
+ }
+
+ /** 鍙栨牸灞炴�э紝娌℃湁 {@code <w:tcPr>} 灏辫ˉ涓�涓� */
+ private static CTTcPr cellPropertiesOf(XWPFTableCell cell) {
+ return cell.getCTTc().isSetTcPr()
+ ? cell.getCTTc().getTcPr()
+ : cell.getCTTc().addNewTcPr();
+ }
+
+ private static byte[] write(XWPFDocument document) throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ document.write(out);
+ return out.toByteArray();
+ }
+
+}
diff --git a/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/QcReportImportAdapterTest.java b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/QcReportImportAdapterTest.java
new file mode 100644
index 0000000..848f07f
--- /dev/null
+++ b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/document/QcReportImportAdapterTest.java
@@ -0,0 +1,312 @@
+package cn.iocoder.yudao.module.qcreport.service.aiimport.document;
+
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.module.qcreport.config.QcReportAiImportProperties;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * 杈撳叆閫傞厤鍣細璺敱涓庢娊鍙栥��
+ * <p>
+ * 瀹堢殑鏄笁浠朵簨锛�
+ * <ol>
+ * <li><b>璺敱涓嶈兘鏈夋涔�</b>鈥斺�斿悓涓�浠芥枃浠跺繀椤荤ǔ瀹氬湴钀藉埌鍚屼竴涓�傞厤鍣紝鍚﹀垯銆屽悓涓�寮犵収鐗囦粖澶╄蛋鏂囨湰銆�
+ * 鏄庡ぉ璧板浘鐗囥�嶈繖绉嶆紓绉讳細鍦ㄦ帓鏌ユ椂鎶婁汉缁曟銆�</li>
+ * <li><b>閫氶亾鍒ゅ畾渚濇嵁鏄�屾湁娌℃湁鏂囨湰灞傘��</b>锛屼笉鏄墿灞曞悕銆傝繖涓よ�呰鎼炴贩鏃讹紝鎵弿鐗� PDF 浼氳褰撴垚
+ * 鐢靛瓙鐗堝幓鎶芥枃鏈紝鎶藉嚭涓�鐗囩┖鐧斤紝鑰岀敤鎴风湅鍒扮殑鍙槸銆孉I 浠�涔堥兘娌¤瘑鍒嚭鏉ャ�嶃��</li>
+ * <li><b>鏃ф牸寮� .doc/.xls 瑕佺粰鍑虹簿纭嚭璺�</b>鈥斺�旇蛋閫氱敤銆屾牸寮忎笉鏀寔銆嶇殑鏂囨绛変簬娌¤锛�
+ * 鍥犱负鐢ㄦ埛鐨勬枃浠舵墿灞曞悕鐪嬭捣鏉ュ畬鍏ㄥ悎瑙勩��</li>
+ * </ol>
+ * <p>
+ * 杩欎簺鐢ㄤ緥閮戒笉闇�瑕� Spring 瀹瑰櫒锛氶�傞厤鍣ㄥ彧渚濊禆涓�涓厤缃璞★紝鐢� {@code ReflectionTestUtils} 娉ㄥ叆鍗冲彲銆�
+ * 璧峰鍣ㄦ祴杩欎簺銆岀函杈撳叆 鈫� 绾緭鍑恒�嶇殑绫伙紝鎱笖涓嶈锛岃繕浼氭妸澶辫触鍘熷洜鍩嬪湪瀹瑰櫒鍚姩鏃ュ織閲屻��
+ */
+class QcReportImportAdapterTest {
+
+ @Test
+ @DisplayName("鍥剧墖閫傞厤鍣ㄨ棰嗗父瑙佸浘鐗囨墿灞曞悕锛屼笖鍘熷瓧鑺傜洿閫氫笉瑙g爜")
+ void imageAdapterSupports() {
+ ImageImportAdapter adapter = new ImageImportAdapter();
+ for (String extension : List.of("png", "jpg", "jpeg", "bmp", "gif", "webp")) {
+ assertTrue(adapter.supports(extension, null), extension + " 搴斿綋琚浘鐗囬�傞厤鍣ㄨ棰�");
+ }
+ assertFalse(adapter.supports("pdf", null));
+ assertFalse(adapter.supports("", null), "娌℃湁鎵╁睍鍚嶆椂涓嶈琚换浣曢�傞厤鍣ㄨ棰�");
+ }
+
+ @Test
+ @DisplayName("鍥剧墖璧� IMAGES 閫氶亾锛屽崟椤碉紝MIME 鐢辨墿灞曞悕鎺ㄥ嚭")
+ void imageAdapterExtractsSinglePage() {
+ byte[] bytes = "鍋囪杩欐槸鐓х墖瀛楄妭".getBytes();
+ QcReportDocumentExtract extract = new ImageImportAdapter().extract(bytes, "鐜板満鐓х墖.JPG");
+
+ assertEquals(QcReportDocumentExtract.Channel.IMAGES, extract.channel());
+ assertEquals(1, extract.pageCount());
+ assertEquals("raw-image", extract.extractor());
+ assertEquals(1, extract.images().size());
+ assertEquals("image/jpeg", extract.images().get(0).mimeType());
+ assertArrayEquals(bytes, extract.images().get(0).bytes(),
+ "鍥剧墖蹇呴』鍘熷瓧鑺傜洿閫氾細涓棿瑙g爜鍐嶇紪鐮佷竴娆′細涓㈡帀鍏冩暟鎹紝涔熺櫧鐧藉涓�娆″唴瀛樻嫹璐�");
+ }
+
+ @Test
+ @DisplayName("鏈夋枃鏈眰鐨� PDF 璧� TEXT 閫氶亾锛氫竴娆¤皟鐢紝涓嶆覆鏌撻〉闈�")
+ void pdfWithTextLayerGoesTextChannel() {
+ QcReportDocumentExtract extract = pdfAdapter().extract(AiImportFixtures.textPdf(2), "鎶ュ憡.pdf");
+
+ assertEquals(QcReportDocumentExtract.Channel.TEXT, extract.channel());
+ assertEquals(2, extract.pageCount());
+ assertEquals("pdfbox-text", extract.extractor());
+ assertTrue(extract.text().contains("Incoming Inspection Report page 1"));
+ assertTrue(extract.text().contains("--- 绗� 2 椤� ---"),
+ "澶氶〉鏂囨湰瑕佸甫椤靛垎闅旀爣璁帮紝鍚﹀垯妯″瀷鍒嗕笉娓呭摢閲屾槸鏂扮殑涓�椤�");
+ }
+
+ @Test
+ @DisplayName("娌℃湁鏂囨湰灞傜殑 PDF 璧� IMAGES 閫氶亾閫愰〉杞浘锛屽苟鎻愮ず鐢ㄦ埛杩欐槸鎸夋壂鎻忎欢澶勭悊鐨�")
+ void pdfWithoutTextLayerGoesImageChannel() {
+ QcReportDocumentExtract extract = pdfAdapter().extract(AiImportFixtures.imageOnlyPdf(2), "鎵弿浠�.pdf");
+
+ assertEquals(QcReportDocumentExtract.Channel.IMAGES, extract.channel(),
+ "鎶戒笉鍑烘枃鏈眰鍗翠粛璧� TEXT锛岀粨鏋滄槸妯″瀷鏀跺埌涓�鐗囩┖鐧斤紝鐢ㄦ埛鍙細鐪嬪埌銆屼粈涔堥兘娌¤瘑鍒嚭鏉ャ��");
+ assertEquals(2, extract.pageCount());
+ assertEquals("pdfbox-render", extract.extractor());
+ assertEquals(2, extract.images().size(), "閫愰〉涓�寮犲浘锛岄〉鏁板氨鏄浘鐗囨暟涓庤皟鐢ㄦ暟");
+ assertEquals("image/png", extract.images().get(0).mimeType());
+ assertEquals("绗� 1 椤�", extract.images().get(0).label());
+ assertFalse(extract.notes().isEmpty(), "蹇呴』鍛婅瘔鐢ㄦ埛杩欐鏄寜鎵弿浠跺鐞嗙殑锛屽惁鍒欒В閲婁笉浜嗕负浠�涔堣繖涔堟參");
+ }
+
+ @Test
+ @DisplayName("椤垫暟瓒呰繃涓婇檺鐩存帴鎶ラ敊锛屼笉闈欓粯鎴柇")
+ void pdfTooManyPagesThrows() {
+ QcReportAiImportProperties properties = new QcReportAiImportProperties();
+ properties.setMaxPagesPerFile(2);
+
+ ServiceException e = assertThrows(ServiceException.class,
+ () -> pdfAdapter(properties).extract(AiImportFixtures.textPdf(3), "闀挎姤鍛�.pdf"));
+ assertTrue(e.getMessage().contains("3 椤�") && e.getMessage().contains("涓婇檺 2 椤�"),
+ "鎶ラ敊瑕佽娓呭疄闄呭嚑椤点�佷笂闄愬嚑椤碉紝鐢ㄦ埛鎵嶇煡閬撹鎷嗘垚鍑犱唤锛涘疄闄呮枃妗堬細" + e.getMessage());
+ }
+
+ @Test
+ @DisplayName("docx 淇濈暀娈佃惤涓庤〃鏍肩殑鐗堥潰椤哄簭锛岃〃鏍肩敤 Tab 鍒嗛殧鍗曞厓鏍煎苟鍔犺竟鐣屾爣璁�")
+ void docxKeepsLayoutOrder() {
+ byte[] bytes = AiImportFixtures.docx("鏉ユ枡妫�楠屾姤鍛�", new String[][]{
+ {"妫�楠岄」鐩�", "瑙勬牸", "瀹炴祴", "鍒ゅ畾"},
+ {"澶栬", "鏃犲垝鐥�", "鍚堟牸", "PASS"}}, "妫�楠屽憳锛氬紶涓�");
+
+ String text = officeAdapter().extract(bytes, "鎶ュ憡.docx").text();
+
+ int heading = text.indexOf("鏉ユ枡妫�楠屾姤鍛�");
+ int tableStart = text.indexOf("[琛ㄦ牸寮�濮媇");
+ int tableEnd = text.indexOf("[琛ㄦ牸缁撴潫]");
+ int footer = text.indexOf("妫�楠屽憳锛氬紶涓�");
+ assertTrue(heading >= 0 && tableStart > heading && tableEnd > tableStart && footer > tableEnd,
+ "椤哄簭搴旀槸 娈佃惤 鈫� 琛ㄦ牸 鈫� 娈佃惤锛涗贡搴忚鏄庢娊鍙栨槸銆屽厛鎵�鏈夋钀姐�佸啀鎵�鏈夎〃鏍笺�嶏紝"
+ + "妯″瀷浼氱湅鍒颁竴鍫嗘爣棰樺爢鍦ㄥ紑澶淬�傚疄闄咃細" + text);
+ assertTrue(text.contains("妫�楠岄」鐩甛t瑙勬牸\t瀹炴祴\t鍒ゅ畾"),
+ "鍗曞厓鏍煎繀椤荤敤 Tab 鍒嗛殧锛屽惁鍒欐ā鍨嬪垎涓嶆竻鍝嚑娈垫枃瀛楀睘浜庡悓涓�琛屻�傚疄闄咃細" + text);
+ assertTrue(text.contains("澶栬\t鏃犲垝鐥昞t鍚堟牸\tPASS"), "鏁版嵁琛屽悓鏍疯鎸夎鎷艰捣鏉ャ�傚疄闄咃細" + text);
+ }
+
+ @Test
+ @DisplayName("绾靛悜鍚堝苟鐨勭画鏍兼爣鎴� 鈫戝悓涓婏細妯″瀷鎵嶇湅寰楀嚭銆屼竴涓楠岄」鐩笅鎸傝嫢骞插瓙椤广��")
+ void docxKeepsVerticalMergeAsGroupMark() {
+ String text = officeAdapter()
+ .extract(AiImportFixtures.docxWithVerticalMerge(), "鏉ユ枡妫�楠屾姤鍛�.docx").text();
+
+ List<String> rows = tableRows(text);
+ assertEquals(4, rows.size(), "琛ㄥご + 涓夎鏁版嵁閮借杈撳嚭銆傚疄闄咃細" + text);
+ for (String row : rows) {
+ assertEquals(6, row.split("\t", -1).length,
+ "姣忚鐨勫垪鏁板繀椤讳笌琛ㄥご瀵归綈锛屽惁鍒欐ā鍨嬩細鎶婂�兼寕鍒伴敊鐨勫垪涓娿�傚疄闄呰锛�" + row);
+ }
+ assertTrue(rows.get(1).startsWith("绮掑害-绛涗笂鐗╂瘮渚嬶紙%锛塡t20鐩笂"),
+ "鍚堝苟鐨勮捣濮嬫牸甯︾潃鐪熷疄鍒嗙粍鍚嶃�傚疄闄咃細" + rows.get(1));
+ assertTrue(rows.get(2).startsWith(QcReportDocumentExtract.VERTICAL_MERGE_MARK + "\t40鐩笂"),
+ "缁牸蹇呴』鏍囧嚭銆屼笌涓婁竴琛屽悓鍊笺�嶃�傜暀绌虹殑璇濓紝妯″瀷鍒嗕笉娓呭畠鏄悎骞剁画鏍艰繕鏄師浠舵病濉紝"
+ + "鏁村紶琛ㄥ氨閫�鍖栨垚涓�鍫嗗钩閾虹殑妫�楠岄」锛屽垎缁勪俊鎭叏涓€�傚疄闄咃細" + rows.get(2));
+ assertTrue(rows.get(3).startsWith("姘村垎\t"),
+ "鎹簡涓�涓柊鐨勫垎缁勫悕锛岀収甯歌緭鍑恒�傚疄闄咃細" + rows.get(3));
+ }
+
+ @Test
+ @DisplayName("妯悜鍚堝苟鐨勮〃澶存寜鍗犵敤鐨勫垪鏁拌ˉ鍗犱綅锛屼笌鏁版嵁琛岀殑鍒椾綅瀵归綈")
+ void docxPadsGridSpanHeaderToUniformWidth() {
+ String text = officeAdapter()
+ .extract(AiImportFixtures.docxWithGridSpanHeader(), "鎶ュ憡.docx").text();
+
+ List<String> rows = tableRows(text);
+ assertEquals("妫�楠岄」鐩甛t\t鏍囧噯鍊糪t瀹炴祴鍊�", rows.get(0),
+ "璺� 2 鍒楃殑琛ㄥご瑕佸崰婊� 2 涓垪浣嶏紝鍚﹀垯瀹冨悗闈㈢殑鍒楁暣浣撳乏绉讳竴鏍硷紝琛ㄥご涓庢暟鎹涓嶄笂銆傚疄闄咃細" + text);
+ assertEquals("澶栬\t鏃犲垝鐥昞t鍚堟牸\t", rows.get(1),
+ "鏁版嵁琛屾寜鏁磋〃缃戞牸瀹藉害琛ュ埌绛夐暱锛岀煭鐨勫嚑琛屾墠涓嶄細琚綋鎴愩�屽垪鏁板氨杩欎箞澶氥�嶃�傚疄闄咃細" + text);
+ }
+
+ @Test
+ @DisplayName("docx 鐨勯〉鐪夐〉鑴氫竴骞惰鍏ュ苟鍔犳爣璁帮紝椤哄簭涓� 椤电湁 鈫� 姝f枃 鈫� 椤佃剼")
+ void docxReadsHeaderAndFooter() {
+ byte[] bytes = AiImportFixtures.docxWithHeaderFooter("妫� 楠� 鎶� 鍛�",
+ "鏂扮枂澶х綏绱犻┈閾冭柉鍒跺搧鏈夐檺鍏徃", "鍒堕�犲晢锛氭煇鏌愬叕鍙搞��鍘傚潃锛氭柊鐤嗗寳灞競宸ヤ笟鍥尯閲戣緣璺�555鍙�");
+
+ QcReportDocumentExtract extract = officeAdapter().extract(bytes, "鎶ュ憡.docx");
+ String text = extract.text();
+
+ int header = text.indexOf("[椤电湁]");
+ int body = text.indexOf("妫� 楠� 鎶� 鍛�");
+ int footerMark = text.indexOf("[椤佃剼]");
+ assertTrue(header >= 0 && body > header && footerMark > body,
+ "椤哄簭搴旀槸 椤电湁 鈫� 姝f枃 鈫� 椤佃剼锛屼笌鏂囨。瑙嗚椤哄簭涓�鑷淬�傚疄闄咃細" + text);
+ assertTrue(text.contains("鏂扮枂澶х綏绱犻┈閾冭柉鍒跺搧鏈夐檺鍏徃"),
+ "椤电湁鏂囧瓧蹇呴』鐪熺殑杩涘唴瀹癸細妯″瀷娌¤杩囪繖娈垫枃瀛楋紝灏变笉鍙兘鎶婂畠璁ゆ垚 ReportHeader銆傚疄闄咃細" + text);
+ assertTrue(text.contains("閲戣緣璺�555鍙�"), "椤佃剼鍚岀悊锛屽搴� ReportFooter銆傚疄闄咃細" + text);
+ assertFalse(extract.notes().isEmpty(),
+ "瑕佽繘 warnings 鎻愮ず鍘熶欢甯﹂〉鐪夐〉鑴氾紝鍚﹀垯鐢ㄦ埛涓嶆槑鐧借崏绋块噷涓轰粈涔堝鍑轰竴涓姮澶寸粍浠�");
+ }
+
+ @Test
+ @DisplayName("娌℃湁椤电湁椤佃剼鐨� docx 涓嶄細鍑┖澶氬嚭鏍囪涓庡憡璀�")
+ void docxWithoutHeaderFooterStaysClean() {
+ byte[] bytes = AiImportFixtures.docx("鏉ユ枡妫�楠屾姤鍛�",
+ new String[][]{{"妫�楠岄」鐩�"}, {"澶栬"}}, "妫�楠屽憳锛氬紶涓�");
+
+ QcReportDocumentExtract extract = officeAdapter().extract(bytes, "鎶ュ憡.docx");
+
+ assertFalse(extract.text().contains("[椤电湁]") || extract.text().contains("[椤佃剼]"),
+ "POI 鍦ㄦ病鏈夐〉鐪夋椂浠嶅彲鑳借繑鍥炰竴涓┖ header锛屾护涓嶆帀灏变細璁╂ā鍨嬩互涓哄師浠舵湁鎶ご銆�"
+ + "瀹為檯锛�" + extract.text());
+ assertTrue(extract.notes().isEmpty(), "娌℃湁椤电湁椤佃剼灏变笉璇ユ姤杩欐潯璀﹀憡");
+ }
+
+ @Test
+ @DisplayName("xlsx 甯﹀伐浣滆〃鍚嶄笌鍒楀ご锛岀┖鐧借涓嶈緭鍑�")
+ void xlsxKeepsHeaders() {
+ byte[] bytes = AiImportFixtures.xlsx("妫�楠岄」鐩�", new String[][]{
+ {"妫�楠岄」鐩�", "瑙勬牸", "瀹炴祴", "鍒ゅ畾"},
+ {"澶栬", "鏃犲垝鐥�", "鍚堟牸", "PASS"},
+ {"", "", "", ""}});
+
+ String text = officeAdapter().extract(bytes, "椤圭洰.xlsx").text();
+
+ assertTrue(text.contains("[宸ヤ綔琛�: 妫�楠岄」鐩甝"), "涓嶅甫宸ヤ綔琛ㄥ悕鏃跺 sheet 鏂囦欢鐨勮緭鍑轰細绯婂湪涓�璧�");
+ assertTrue(text.contains("妫�楠岄」鐩甛t瑙勬牸\t瀹炴祴\t鍒ゅ畾"), "鍒楀ご椤哄簭涓嶈兘鍙橈紝璇箟鍏ㄩ潬瀹�");
+ assertEquals(3, text.lines().count(),
+ "宸ヤ綔琛ㄥ悕 + 鍒楀ご + 涓�琛屾暟鎹濂戒笁琛岋紱澶氬嚭鏉ヨ鏄庢暣琛岀┖鐧芥病琚涪鎺夛紝"
+ + "瓒呭ぇ琛ㄩ噷澶ч噺绌鸿浼氭妸鎻愮ず璇嶇亴婊″櫔澹般�傚疄闄咃細" + text);
+ }
+
+ @Test
+ @DisplayName("Excel 鏄剧ず鍊艰�岄潪鍘熷鍊硷細DataFormatter 涔嬩笅 1 涓嶄細鍙樻垚 1.0")
+ void xlsxUsesDisplayValue() {
+ byte[] bytes = AiImportFixtures.xlsx("鏁伴噺", new String[][]{{"鏁伴噺"}, {"100"}});
+ String text = officeAdapter().extract(bytes, "鏁伴噺.xlsx").text();
+
+ assertTrue(text.contains("100"), "瀹為檯锛�" + text);
+ assertFalse(text.contains("100.0"), "鍙栦簡鍘熷鍊肩殑璇濇暣鏁颁細鍙� 100.0锛屾ā鍨嬪鏄撳綋鎴愬皬鏁�");
+ }
+
+ @Test
+ @DisplayName(".doc / .xls 缁欏嚭銆屽彟瀛樹负銆嶇殑绮剧‘鍑鸿矾锛岃�屼笉鏄缁熺殑銆屾牸寮忎笉鏀寔銆�")
+ void legacyOfficeThrowsPreciseError() {
+ OfficeImportAdapter adapter = officeAdapter();
+
+ ServiceException doc = assertThrows(ServiceException.class,
+ () -> adapter.extract(new byte[]{1, 2, 3}, "鑰佹姤鍛�.doc"));
+ assertTrue(doc.getMessage().contains("鍙﹀瓨涓�") && doc.getMessage().contains(".docx"),
+ "鎵╁睍鍚嶇湅璧锋潵瀹屽叏鍚堣锛屽彧璇淬�屼笉鏀寔銆嶇敤鎴锋棤浠庝笅鎵嬨�傚疄闄咃細" + doc.getMessage());
+
+ ServiceException xls = assertThrows(ServiceException.class,
+ () -> adapter.extract(new byte[]{1, 2, 3}, "鑰佸彴璐�.xls"));
+ assertTrue(xls.getMessage().contains(".xlsx"), "瀹為檯锛�" + xls.getMessage());
+ }
+
+ @Test
+ @DisplayName("甯� BOM 鐨勬枃鏈墺鎺� BOM锛岄琛岄瀛楁涓嶅甫闅愬舰瀛楃")
+ void textWithBomIsStripped() {
+ String text = officeAdapter()
+ .extract(AiImportFixtures.textWithBom("妫�楠岄」鐩�,瑙勬牸\n澶栬,鏃犲垝鐥�"), "娓呭崟.csv").text();
+
+ assertTrue(text.startsWith("妫�楠岄」鐩�"),
+ "BOM 娌″墺鎺夋椂棣栧瓧娈典細甯︿竴涓湅涓嶈鐨勫瓧绗︼紝妯″瀷鎷煎嚭鏉ョ殑 key 灏卞涓嶄笂浜嗐�傚疄闄咃細" + text);
+ }
+
+ @Test
+ @DisplayName("闂ㄩ潰鎸夋墿灞曞悕璺敱锛屽ぇ鍐欐墿灞曞悕璧板悓涓�鏉¤矾")
+ void facadeRoutesCaseInsensitively() {
+ QcReportDocumentExtractService facade = facade();
+ assertEquals("raw-image", facade.extract("鍥剧墖".getBytes(), "鐜板満鐓х墖.PNG", null).extractor());
+ assertEquals("pdfbox-text", facade.extract(AiImportFixtures.textPdf(1), "鎶ュ憡.PDF", null).extractor());
+ }
+
+ @Test
+ @DisplayName("娌′汉璁ら鐨勬墿灞曞悕鎶ャ�屾牸寮忎笉鏀寔銆嶏紝骞跺甫涓婂彲鐢ㄦ牸寮忔竻鍗�")
+ void facadeRejectsUnknownExtension() {
+ ServiceException e = assertThrows(ServiceException.class,
+ () -> facade().extract(new byte[]{1}, "鑽夌.pages", null));
+
+ assertTrue(e.getMessage().contains("鎵╁睍鍚嶏細.pages"), "瀹為檯锛�" + e.getMessage());
+ assertTrue(e.getMessage().contains("txt/csv"), "瑕佸垪鍑哄彲鐢ㄦ牸寮忥紝鐢ㄦ埛鎵嶇煡閬撹杞垚浠�涔�");
+ }
+
+ @Test
+ @DisplayName("娌℃湁鎵╁睍鍚嶆椂鎶ャ�屾墿灞曞悕锛氭棤銆嶏紝涓嶇暀涓嬪崐涓偣")
+ void facadeHandlesMissingExtension() {
+ ServiceException e = assertThrows(ServiceException.class,
+ () -> facade().extract(new byte[]{1}, "鏃犲悗缂�鍚嶇殑鏂囦欢", null));
+
+ assertTrue(e.getMessage().contains("鎵╁睍鍚嶏細鏃�"), "瀹為檯锛�" + e.getMessage());
+ }
+
+ // ==================== 澶瑰叿 ====================
+
+ /** 鍙栧嚭 [琛ㄦ牸寮�濮媇 涓� [琛ㄦ牸缁撴潫] 涔嬮棿鐨勮锛屾寜鍑虹幇椤哄簭 */
+ private static List<String> tableRows(String text) {
+ List<String> rows = new ArrayList<>();
+ boolean inside = false;
+ for (String line : text.split("\n")) {
+ if ("[琛ㄦ牸寮�濮媇".equals(line)) {
+ inside = true;
+ } else if ("[琛ㄦ牸缁撴潫]".equals(line)) {
+ inside = false;
+ } else if (inside) {
+ rows.add(line);
+ }
+ }
+ return rows;
+ }
+
+ private static PdfImportAdapter pdfAdapter() {
+ return pdfAdapter(new QcReportAiImportProperties());
+ }
+
+ private static PdfImportAdapter pdfAdapter(QcReportAiImportProperties properties) {
+ PdfImportAdapter adapter = new PdfImportAdapter();
+ ReflectionTestUtils.setField(adapter, "properties", properties);
+ return adapter;
+ }
+
+ private static OfficeImportAdapter officeAdapter() {
+ OfficeImportAdapter adapter = new OfficeImportAdapter();
+ ReflectionTestUtils.setField(adapter, "properties", new QcReportAiImportProperties());
+ return adapter;
+ }
+
+ private static QcReportDocumentExtractService facade() {
+ QcReportDocumentExtractService facade = new QcReportDocumentExtractService();
+ ReflectionTestUtils.setField(facade, "adapters",
+ List.of(new ImageImportAdapter(), pdfAdapter(), officeAdapter()));
+ return facade;
+ }
+
+}
diff --git a/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportAiDraftNormalizerTest.java b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportAiDraftNormalizerTest.java
new file mode 100644
index 0000000..23f9d06
--- /dev/null
+++ b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportAiDraftNormalizerTest.java
@@ -0,0 +1,230 @@
+package cn.iocoder.yudao.module.qcreport.service.aiimport.llm;
+
+import cn.iocoder.yudao.module.qcreport.controller.admin.aiimport.vo.QcReportAiDraftRespVO;
+import cn.iocoder.yudao.module.qcreport.controller.admin.aiimport.vo.QcReportComponentSpecVO;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * 鑽夌褰掍竴锛氭妸涓嶅彲淇$殑妯″瀷杈撳嚭鏀舵暃鎴愩�屽彧鍚悎娉曠粍浠躲�佸悎娉曞睘鎬с�嶇殑娓呭崟銆�
+ * <p>
+ * 瀹堢殑鏄竴鏉¤璁″師鍒欙細<b>鍗曚釜鍏冪礌鍧忔帀涓嶈兘璁╂暣涓姹傚け璐�</b>銆傛ā鍨嬬殑杈撳嚭鏄竴鏉¢暱 JSON锛�
+ * 閲岄潰娣疯繘涓�涓病瑙佽繃鐨� type 鏄父鎬侊紱姝ゆ椂姝g‘鐨勫弽搴旀槸涓㈡帀閭d竴椤瑰苟鍛婅瘔鐢ㄦ埛锛�
+ * 鑰屼笉鏄妸鏁村宸茬粡璇嗗埆瀵圭殑缁勪欢涓�璧锋墧鎺夛紝涔熶笉鏄鎺ュ彛 500銆�
+ * <p>
+ * 鍥犳杩欓噷鐨勬柇瑷�鍑犱箮閮芥垚瀵瑰嚭鐜帮細琚涪鎺夌殑閭i」鍑轰簡闂锛�<b>鍏朵綑椤逛粛鐒跺畬濂�</b>銆�
+ */
+class QcReportAiDraftNormalizerTest {
+
+ @Test
+ @DisplayName("娓呭崟澶栫殑缁勪欢绫诲瀷琚涪鎺夛紝鍚屾椂浜у嚭鍙鎻愮ず")
+ void unknownTypeDropped() {
+ QcReportAiDraftNormalizer.Result result = normalize(List.of(
+ component("CustomHtml", Map.of("html", "<b>x</b>")),
+ component("Heading", Map.of("text", "妫�楠岄」鐩�"))));
+
+ assertEquals(1, result.components().size(), "娓呭崟澶栫殑绫诲瀷蹇呴』琚涪鎺�");
+ assertEquals("Heading", result.components().get(0).getType());
+ assertTrue(hasWarning(result, "CustomHtml"), "蹇呴』鍛婅瘔鐢ㄦ埛涓㈡帀浜嗕粈涔堢被鍨嬶紝鍚﹀垯浼氫互涓烘枃浠堕噷鐨勫唴瀹归兘璇嗗埆鍒颁簡");
+ }
+
+ @Test
+ @DisplayName("娓呭崟鏈0鏄庣殑灞炴�� key 琚涪鎺夛紝澹版槑杩囩殑鍘熸牱淇濈暀")
+ void undeclaredPropsDropped() {
+ QcReportAiDraftNormalizer.Result result = normalize(List.of(
+ component("Heading", Map.of("text", "妫�楠岄」鐩�", "fontSize", 20, "color", "red"))));
+
+ assertEquals(1, result.components().size());
+ Map<String, Object> props = result.components().get(0).getProps();
+ assertEquals(Map.of("text", "妫�楠岄」鐩�"), props);
+ assertTrue(hasWarning(result, "fontSize") && hasWarning(result, "color"),
+ "琚涪寮冪殑灞炴�� key 瑕侀�愪釜鍐欐槑锛岀敤鎴锋墠鐭ラ亾鍓嶇涓轰粈涔堟病娓叉煋鍑烘潵");
+ }
+
+ @Test
+ @DisplayName("娓呭崟娌″0鏄� fields 鏃朵笉鍋氳繃婊わ細鏃犱粠鍒ゆ柇涓嶇瓑浜庡叏閮介潪娉�")
+ void nullFieldsMeansNoFiltering() {
+ QcReportComponentSpecVO spec = new QcReportComponentSpecVO();
+ spec.setType("Heading");
+ spec.setLabel("鏍囬");
+ // 鍒绘剰涓� setFields
+
+ Map<String, Object> props = Map.of("text", "妫�楠岄」鐩�");
+ QcReportAiDraftNormalizer.Result result =
+ QcReportAiDraftNormalizer.normalize(List.of(component("Heading", props)), List.of(spec), "f.pdf");
+
+ assertEquals(1, result.components().size());
+ assertSame(props, result.components().get(0).getProps(),
+ "fields 涓� null 琛ㄧず娓呭崟鍘嬫牴娌″0鏄庯紝姝ゆ椂杩囨护浼氭妸璇嗗埆瀵圭殑灞炴�ч潤榛樻姽骞�");
+ }
+
+ @Test
+ @DisplayName("娓呭崟鏄庣‘澹版槑銆屼笉鍚冧换浣曞睘鎬с�嶆椂锛屽睘鎬х‘瀹炶涓㈠厜锛岀粍浠堕殢涔嬭涓㈡帀")
+ void emptyFieldsDropsEverything() {
+ QcReportComponentSpecVO spec = new QcReportComponentSpecVO();
+ spec.setType("Divider");
+ spec.setLabel("鍒嗛殧绾�");
+ spec.setFields(List.of());
+
+ QcReportAiDraftNormalizer.Result result = QcReportAiDraftNormalizer.normalize(
+ List.of(component("Divider", Map.of("thickness", 1))), List.of(spec), "f.pdf");
+
+ assertTrue(result.components().isEmpty(), "灞炴�у叏琚繃婊ゅ悗缁勪欢娌℃湁鎰忎箟锛屽簲褰撲竴骞朵涪鎺�");
+ assertTrue(hasWarning(result, "鍒嗛殧绾�"));
+ }
+
+ @Test
+ @DisplayName("缂虹被鍨嬨�佺己灞炴�с�佺┖鍏冪礌鍚勮嚜琚涪鎺夛紝鍏朵綑缁勪欢涓嶅彈褰卞搷")
+ void malformedItemsAreIsolated() {
+ List<QcReportAiDraftRespVO.DraftComponent> raw = new ArrayList<>();
+ raw.add(null);
+ raw.add(component(" ", Map.of("text", "x")));
+ raw.add(component("Heading", null));
+ raw.add(component("Heading", Map.of()));
+ raw.add(component("Heading", Map.of("text", "濂界殑涓�椤�")));
+
+ QcReportAiDraftNormalizer.Result result = normalize(raw);
+
+ assertEquals(1, result.components().size(), "鍥涗釜鍧忓厓绱犱笉璇ュ甫璧板敮涓�涓�涓ソ鍏冪礌");
+ assertEquals("濂界殑涓�椤�", result.components().get(0).getProps().get("text"));
+ assertEquals(4, result.warnings().size(), "姣忎竴涓涓㈡帀鐨勫厓绱犻兘瑕佹湁瀵瑰簲鐨勬彁绀猴紝涓嶈兘闈欓粯");
+ }
+
+ @Test
+ @DisplayName("蹇呭~灞炴�х己澶辨椂鎻愮ず锛屼絾涓嶄涪鎺夌粍浠垛�斺�旂敤鎴峰彲浠ュ湪璁捐鍣ㄩ噷琛�")
+ void missingRequiredWarnsButKeeps() {
+ QcReportAiDraftNormalizer.Result result = normalize(
+ List.of(component("QualityTable", Map.of("title", "妫�楠岄」鐩�"))));
+
+ assertEquals(1, result.components().size(), "缂哄繀濉笉璇ヤ涪缁勪欢锛氳璁″櫒閲岃繕鑳借ˉ锛屼涪浜嗙敤鎴峰緱閲嶆柊鎷�");
+ assertTrue(hasWarning(result, "妫�楠岄」鏁版嵁婧�"),
+ "鎻愮ず瑕佺敤瀛楁鏄剧ず鍚嶈�屼笉鏄� key锛岀敤鎴风湅鍒扮殑鏄睘鎬ч潰鏉夸笂鐨勪腑鏂囨爣绛�");
+ }
+
+ @Test
+ @DisplayName("蹇呭~灞炴�у�间负绌虹櫧涓茬瓑鍚屼簬缂哄け")
+ void blankRequiredCountsAsMissing() {
+ assertTrue(hasWarning(normalize(List.of(component("QualityTable", Map.of("itemsPath", " ")))),
+ "妫�楠岄」鏁版嵁婧�"));
+ }
+
+ @Test
+ @DisplayName("澶氶〉缁撴灉鎸� (type, props) 鍘婚噸锛歱rops 鐨� key 椤哄簭涓嶅悓涔熺畻鍚屼竴涓粍浠�")
+ void mergeDedupsAcrossPages() {
+ Map<String, Object> pageOne = new LinkedHashMap<>();
+ pageOne.put("title", "鏉ユ枡妫�楠屾姤鍛�");
+ pageOne.put("showLogo", true);
+ Map<String, Object> pageTwo = new LinkedHashMap<>();
+ pageTwo.put("showLogo", true);
+ pageTwo.put("title", "鏉ユ枡妫�楠屾姤鍛�");
+
+ QcReportAiDraftNormalizer.Result merged = QcReportAiDraftNormalizer.mergeAndDedup(List.of(
+ normalize(List.of(component("ReportHeader", pageOne))),
+ normalize(List.of(component("ReportHeader", pageTwo))),
+ normalize(List.of(component("Heading", Map.of("text", "妫�楠岄」鐩�"))))), 200);
+
+ assertEquals(2, merged.components().size(), "椤电湁鍦ㄤ笁椤甸噷閮藉嚭鐜帮紝鏈�缁堝彧璇ョ暀涓�浠�");
+ assertEquals("ReportHeader", merged.components().get(0).getType());
+ assertTrue(merged.warnings().stream().anyMatch(w -> w.contains("閲嶅") || w.contains("宸插悎骞�")),
+ "鍚堝苟浜嗛噸澶嶉」瑕佽涓�澹帮紝鍚﹀垯鐢ㄦ埛浼氬鎬负浠�涔堜笂浼犱笁椤靛彧鍑轰竴涓〉鐪�");
+ }
+
+ @Test
+ @DisplayName("鍗曟璋冪敤涓嶅仛閲嶅鎻愮ず锛氬彧鏈変竴涓潵婧愭椂娌℃湁銆屽椤甸噸澶嶃�嶅彲瑷�")
+ void noDedupWarningForSingleCall() {
+ QcReportAiDraftNormalizer.Result merged = QcReportAiDraftNormalizer.mergeAndDedup(
+ List.of(normalize(List.of(component("Heading", Map.of("text", "妫�楠岄」鐩�"))))), 200);
+
+ assertFalse(merged.warnings().stream().anyMatch(w -> w.contains("宸插悎骞�")));
+ }
+
+ @Test
+ @DisplayName("瓒呰繃涓婇檺鏃舵埅鏂苟鎻愮ず琛ュ綍锛岃�屼笉鏄潤榛樹涪寮�")
+ void capTruncatesWithWarning() {
+ List<QcReportAiDraftRespVO.DraftComponent> many = new ArrayList<>();
+ for (int i = 0; i < 5; i++) {
+ many.add(component("Heading", Map.of("text", "鏍囬" + i)));
+ }
+ QcReportAiDraftNormalizer.Result merged = QcReportAiDraftNormalizer.mergeAndDedup(
+ List.of(normalize(many)), 3);
+
+ assertEquals(3, merged.components().size());
+ assertTrue(merged.warnings().stream().anyMatch(w -> w.contains("瓒呰繃鍗曟涓婇檺")),
+ "鎴柇蹇呴』鎻愮ず锛氬惁鍒欑敤鎴蜂互涓烘枃浠堕噷灏卞彧鏈� 3 涓粍浠�");
+ }
+
+ @Test
+ @DisplayName("鎻愮ず閮藉甫鏉ユ簮鏍囩锛屽鏂囦欢鏃舵墠鍒嗗緱娓呮槸鍝竴浠藉嚭鐨勯棶棰�")
+ void warningsCarrySourceLabel() {
+ QcReportAiDraftNormalizer.Result result = QcReportAiDraftNormalizer.normalize(
+ List.of(component("CustomHtml", Map.of("html", "x"))), catalog(), "鎵弿浠�.pdf 绗� 2 椤�");
+
+ assertEquals(1, result.warnings().size());
+ assertTrue(result.warnings().get(0).startsWith("鎵弿浠�.pdf 绗� 2 椤碉細"),
+ "涓嶅甫鏉ユ簮鐨勬彁绀哄湪銆屼竴娆′紶涓変釜鏂囦欢銆嶆椂绛変簬娌¤");
+ }
+
+ // ==================== 澶瑰叿 ====================
+
+ private static QcReportAiDraftNormalizer.Result normalize(List<QcReportAiDraftRespVO.DraftComponent> raw) {
+ return QcReportAiDraftNormalizer.normalize(raw, catalog(), "鎵弿浠�.pdf");
+ }
+
+ private static boolean hasWarning(QcReportAiDraftNormalizer.Result result, String fragment) {
+ return result.warnings().stream().anyMatch(w -> w.contains(fragment));
+ }
+
+ private static QcReportAiDraftRespVO.DraftComponent component(String type, Map<String, Object> props) {
+ QcReportAiDraftRespVO.DraftComponent component = new QcReportAiDraftRespVO.DraftComponent();
+ component.setType(type);
+ component.setProps(props);
+ return component;
+ }
+
+ private static List<QcReportComponentSpecVO> catalog() {
+ QcReportComponentSpecVO heading = spec("Heading", "鏍囬", field("text", "鏍囬鏂囧瓧", true));
+ QcReportComponentSpecVO table = spec("QualityTable", "妫�楠岄」鐩〃鏍�",
+ field("title", "琛ㄦ牸鏍囬", false),
+ requiredField("itemsPath", "妫�楠岄」鏁版嵁婧�"),
+ field("showIndex", "鏄剧ず搴忓彿", false));
+ QcReportComponentSpecVO header = spec("ReportHeader", "鎶ュ憡鎶ご",
+ field("title", "鎶ュ憡鏍囬", false),
+ field("showLogo", "鏄剧ず logo", false));
+ QcReportComponentSpecVO divider = new QcReportComponentSpecVO();
+ divider.setType("Divider");
+ divider.setLabel("鍒嗛殧绾�");
+ divider.setFields(List.of());
+ return List.of(heading, table, header, divider);
+ }
+
+ private static QcReportComponentSpecVO spec(String type, String label, QcReportComponentSpecVO.Field... fields) {
+ QcReportComponentSpecVO spec = new QcReportComponentSpecVO();
+ spec.setType(type);
+ spec.setLabel(label);
+ spec.setFields(List.of(fields));
+ return spec;
+ }
+
+ private static QcReportComponentSpecVO.Field field(String key, String label, boolean required) {
+ QcReportComponentSpecVO.Field field = new QcReportComponentSpecVO.Field();
+ field.setKey(key);
+ field.setLabel(label);
+ field.setRequired(required);
+ return field;
+ }
+
+ private static QcReportComponentSpecVO.Field requiredField(String key, String label) {
+ return field(key, label, true);
+ }
+
+}
diff --git a/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportAiDraftParserTest.java b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportAiDraftParserTest.java
new file mode 100644
index 0000000..4ee5188
--- /dev/null
+++ b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportAiDraftParserTest.java
@@ -0,0 +1,132 @@
+package cn.iocoder.yudao.module.qcreport.service.aiimport.llm;
+
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.module.qcreport.controller.admin.aiimport.vo.QcReportAiDraftRespVO;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * 妯″瀷鍥炲鐨勮В鏋愩��
+ * <p>
+ * 鍏ㄩ儴鍠�<b>缃愬ご瀛楃涓�</b>锛屼笉 mock {@code AiChatApi}鈥斺�旇繖閲屾槸銆屽瓧绗︿覆 鈫� 鑽夌銆嶇殑绾嚱鏁帮紝
+ * mock 鎺夋ā鍨嬪啀鏂█瑙f瀽姝g‘锛屾祴鐨勬槸 mock 鐨勮繑鍥炲�艰�屼笉鏄В鏋愰�昏緫銆�
+ * <p>
+ * 缃愬ご鐢ㄤ緥鎸戠殑閮芥槸鐪熷疄浼氶亣鍒扮殑鍥炲褰㈢姸锛氭ā鍨嬩範鎯妸 JSON 鍖呰繘 markdown 鍥存爮銆佷範鎯湪鍓嶅悗鍔犱竴鍙�
+ * 銆屽ソ鐨勶紝杩欐槸璇嗗埆缁撴灉銆嶏紝涔熶範鎯湪杈撳嚭琚埅鏂椂鐣欎笅鍗婁釜瀵硅薄銆傝繖涓夌蹇呴』鍦ㄥ垏鐗囪繖涓�姝ュ氨琚悆鎺夛紝
+ * 鍚﹀垯鐢ㄦ埛鐪嬪埌鐨勬槸銆孉I 杩斿洖鐨勫唴瀹规棤娉曡В鏋愩�嶁�斺�旇�屽叾瀹炲洖澶嶉噷鍐呭鏄叏鐨勩��
+ */
+class QcReportAiDraftParserTest {
+
+ @Test
+ @DisplayName("瑁� JSON 鍘熸牱瑙f瀽")
+ void plainJson() {
+ QcReportAiDraftRespVO resp = QcReportAiDraftParser.parse("""
+ {"summary":"鏉ユ枡妫�楠屾姤鍛�","page":{"size":"A4","orientation":"portrait"},
+ "components":[{"type":"ReportHeader","props":{"title":"鏉ユ枡妫�楠屾姤鍛�"}}]}""");
+
+ assertEquals("鏉ユ枡妫�楠屾姤鍛�", resp.getSummary());
+ assertEquals("A4", resp.getPage().getSize());
+ assertEquals("portrait", resp.getPage().getOrientation());
+ assertEquals(1, resp.getComponents().size());
+ assertEquals("ReportHeader", resp.getComponents().get(0).getType());
+ assertEquals("鏉ユ枡妫�楠屾姤鍛�", resp.getComponents().get(0).getProps().get("title"));
+ }
+
+ @Test
+ @DisplayName("markdown 鍥存爮鍖呰9鐨� JSON 鐓ф牱瑙f瀽锛堟ā鍨嬫渶甯歌鐨勮緭鍑哄舰鐘讹級")
+ void markdownFenced() {
+ QcReportAiDraftRespVO resp = QcReportAiDraftParser.parse("""
+ ```json
+ {"summary":"鎵弿浠�","components":[{"type":"Heading","props":{"text":"妫�楠岄」鐩�"}}]}
+ ```""");
+
+ assertEquals(1, resp.getComponents().size());
+ assertEquals("Heading", resp.getComponents().get(0).getType());
+ }
+
+ @Test
+ @DisplayName("鍓嶅悗甯﹀瘨鏆勭殑 JSON 鐓ф牱瑙f瀽")
+ void withChatterAround() {
+ QcReportAiDraftRespVO resp = QcReportAiDraftParser.parse("""
+ 濂界殑锛屾垜宸茬粡鍒嗘瀽浜嗚繖浠芥枃浠躲�傝瘑鍒粨鏋滃涓嬶細
+ {"summary":"璇嗗埆瀹屾垚","components":[{"type":"Result","props":{"conclusion":"鍚堟牸"}}]}
+ 濡傛灉闇�瑕佽皟鏁磋鍛婅瘔鎴戙��""");
+
+ assertEquals("璇嗗埆瀹屾垚", resp.getSummary());
+ assertEquals("Result", resp.getComponents().get(0).getType());
+ }
+
+ @Test
+ @DisplayName("props 閲屾湁宓屽鐨勬暟缁勪笌瀵硅薄涔熶笉鐐糕�斺�攑rops 鐨勫悎娉� key 鐢卞墠绔竻鍗曞喅瀹氾紝鍚庣涓嶈寮虹被鍨嬪寲")
+ void nestedPropValues() {
+ QcReportAiDraftRespVO resp = QcReportAiDraftParser.parse("""
+ {"components":[{"type":"QualityTable","props":{
+ "itemsPath":"inspectionItems",
+ "columns":[{"key":"size","label":"灏哄"}],
+ "meta":{"source":"iqc"}}}]}""");
+
+ Map<String, Object> props = resp.getComponents().get(0).getProps();
+ assertTrue(props.get("columns") instanceof List, "鏁扮粍鍨嬪睘鎬у簲褰撳師鏍蜂繚鐣欎负闆嗗悎");
+ assertTrue(props.get("meta") instanceof Map, "瀵硅薄鍨嬪睘鎬у簲褰撳師鏍蜂繚鐣欎负 Map");
+ }
+
+ @Test
+ @DisplayName("components 琚簩娆$紪鐮佹垚瀛楃涓叉椂涔熻兘璇诲嚭鏉�")
+ void doubleEncodedComponents() {
+ QcReportAiDraftRespVO resp = QcReportAiDraftParser.parse("""
+ {"summary":"x","components":"[{\\"type\\":\\"Heading\\",\\"props\\":{\\"text\\":\\"鏍囬\\"}}]"}""");
+
+ assertEquals(1, resp.getComponents().size());
+ assertEquals("Heading", resp.getComponents().get(0).getType());
+ }
+
+ @Test
+ @DisplayName("components 涓虹┖鏁扮粍涓嶇畻瑙f瀽澶辫触锛氳繖鏄�岃В鏋愭垚鍔熶絾鍐呭涓虹┖銆嶏紝鐢辨湇鍔″眰鎶ユ洿璐村垏鐨勯敊")
+ void emptyComponentsIsNotAParseFailure() {
+ QcReportAiDraftRespVO resp = QcReportAiDraftParser.parse("{\"summary\":\"娌¤瘑鍒嚭鏉",\"components\":[]}");
+
+ assertNotNull(resp.getComponents());
+ assertTrue(resp.getComponents().isEmpty());
+ }
+
+ @Test
+ @DisplayName("娌℃湁 page 瀛楁鏃朵负 null锛屼氦缁欒璁″櫒娌跨敤褰撳墠妯℃澘绾稿紶")
+ void missingPageIsNull() {
+ assertNull(QcReportAiDraftParser.parse("{\"components\":[{\"type\":\"X\",\"props\":{}}]}").getPage());
+ // 鍙粰浜� size 涔熺畻鏈夋晥锛岀己鐨勯儴鍒嗚璁捐鍣ㄨˉ
+ assertEquals("A3", QcReportAiDraftParser.parse(
+ "{\"page\":{\"size\":\"A3\"},\"components\":[]}").getPage().getSize());
+ }
+
+ @Test
+ @DisplayName("瀹屽叏涓嶅惈 JSON 瀵硅薄銆佺┖涓层�佹埅鏂垚鍗婁釜瀵硅薄鏃剁粺涓�鎶涢敊")
+ void unparseableThrows() {
+ assertThrows(ServiceException.class, () -> QcReportAiDraftParser.parse("鎴戜笉澶槑鐧戒綘鐨勬剰鎬�"));
+ assertThrows(ServiceException.class, () -> QcReportAiDraftParser.parse(""));
+ assertThrows(ServiceException.class, () -> QcReportAiDraftParser.parse(null));
+ assertThrows(ServiceException.class, () -> QcReportAiDraftParser.parse("{\"components\": ["),
+ "琚� max_tokens 鎴柇鐨勫洖澶嶄細鍦ㄥ垏鐗囧悗鎷垮埌鐣稿舰 JSON锛屽繀椤绘姏閿欒�屼笉鏄粰鍑哄崐浠借崏绋�");
+ }
+
+ @Test
+ @DisplayName("鍥炲~鍘熸枃鎸� 4000 瀛楃鎴柇锛屽鎺掓煡鍙堜笉鐏岀垎鍝嶅簲浣�")
+ void rawTextTruncation() {
+ assertNull(QcReportAiDraftParser.truncate(null));
+ assertEquals("abc", QcReportAiDraftParser.truncate("abc"));
+
+ String truncated = QcReportAiDraftParser.truncate("x".repeat(5000));
+ assertTrue(truncated.startsWith("x".repeat(100)));
+ assertTrue(truncated.contains("宸叉埅鏂�"));
+ assertTrue(truncated.length() < 4100);
+ }
+
+}
diff --git a/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportLlmCallPlannerTest.java b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportLlmCallPlannerTest.java
new file mode 100644
index 0000000..7c865b8
--- /dev/null
+++ b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportLlmCallPlannerTest.java
@@ -0,0 +1,85 @@
+package cn.iocoder.yudao.module.qcreport.service.aiimport.llm;
+
+import cn.iocoder.yudao.module.qcreport.service.aiimport.document.QcReportDocumentExtract;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * 璋冪敤璁″垝銆�
+ * <p>
+ * 杩欐槸銆屼竴涓枃浠惰鍙戝嚑娆℃ā鍨嬭皟鐢ㄣ�嶈繖涓帶鍒舵祦鐨勫敮涓�钀界偣锛屾墍浠ュ畠琚娊鎴愮函鍑芥暟銆佸彲浠ュ湪杩欓噷琚畬鏁磋窇涓�閬嶏紝
+ * 鑰屼笉蹇呭湪鍗曟祴閲� mock 鎺夌湡姝g殑澶栭儴渚濊禆銆�
+ * <p>
+ * 鍙︽湁涓�鏉℃帴鍙g粏鑺傚繀椤婚拤姝伙細浜ょ粰 {@code AiChatApi.chatWithImage} 鐨勫繀椤绘槸<b>瑁� base64</b>銆�
+ * 閭h竟鎷垮埌鍙傛暟鐩存帴 {@code Base64.getDecoder().decode(...)}锛屽甫 {@code data:image/png;base64,}
+ * 鍓嶇紑灏变細鎶� {@code IllegalArgumentException}鈥斺�旇繖涓け璐ュ湪鑱旇皟鏃舵墠鏆撮湶锛屼笖鎶ラ敊淇℃伅涓嶄細鎻愬埌鍓嶇紑銆�
+ */
+class QcReportLlmCallPlannerTest {
+
+ @Test
+ @DisplayName("鏈夋枃鏈眰鐨勬枃浠舵暣浠芥嫾涓�娆¤皟鐢紝涓嶉�愰〉")
+ void textChannelMakesSingleCall() {
+ QcReportDocumentExtract extract = QcReportDocumentExtract.ofText(
+ "绗竴椤靛唴瀹筡n--- 绗� 2 椤� ---\n绗簩椤靛唴瀹�", 2, "pdfbox-text", List.of());
+
+ List<QcReportLlmCall> calls = QcReportLlmCallPlanner.plan(extract, "鎶ュ憡.pdf");
+
+ assertEquals(1, calls.size(), "鏂囨湰閫氶亾閫愰〉鍙戣皟鐢ㄦ棦璐归搴﹀張浼氳椤甸棿涓婁笅鏂囨柇鎺�");
+ assertEquals(QcReportLlmCall.Kind.TEXT, calls.get(0).kind());
+ assertEquals("鎶ュ憡.pdf", calls.get(0).sourceLabel());
+ assertTrue(calls.get(0).text().contains("绗簩椤靛唴瀹�"), "鏁翠唤姝f枃蹇呴』涓�娆″甫涓�");
+ }
+
+ @Test
+ @DisplayName("鎵弿浠堕�愰〉涓�娆¤皟鐢紝鏍囩甯﹂〉鐮佷互渚垮畾浣嶆槸鍝竴椤靛嚭鐨勯棶棰�")
+ void imageChannelMakesOneCallPerPage() {
+ QcReportDocumentExtract extract = QcReportDocumentExtract.ofImages(List.of(
+ image("绗� 1 椤�"),
+ image("绗� 2 椤�"),
+ image("绗� 3 椤�")), 3, "pdfbox-render", List.of());
+
+ List<QcReportLlmCall> calls = QcReportLlmCallPlanner.plan(extract, "鎵弿浠�.pdf");
+
+ assertEquals(3, calls.size(), "澶氭ā鎬佹帴鍙d竴娆″彧鏀朵竴寮犲浘锛岄〉鏁板氨鏄皟鐢ㄦ暟");
+ for (QcReportLlmCall call : calls) {
+ assertEquals(QcReportLlmCall.Kind.IMAGE, call.kind());
+ assertTrue(call.sourceLabel().startsWith("鎵弿浠�.pdf 绗�"), "鏍囩蹇呴』鑳藉畾浣嶅埌鍏蜂綋椤�");
+ assertEquals("image/png", call.mimeType());
+ assertTrue(call.text().isEmpty(), "鍥剧墖璋冪敤涓嶈鍐嶅甫姝f枃");
+ }
+ assertEquals(List.of("鎵弿浠�.pdf 绗� 1 椤�", "鎵弿浠�.pdf 绗� 2 椤�", "鎵弿浠�.pdf 绗� 3 椤�"),
+ calls.stream().map(QcReportLlmCall::sourceLabel).toList());
+ }
+
+ @Test
+ @DisplayName("鍥剧墖鏄8 base64锛氬甫 data: 鍓嶇紑浼氳 AiChatApiImpl 鐨� Base64 瑙g爜鐩存帴鎶涘紓甯�")
+ void imageBase64IsRaw() {
+ byte[] png = "鍋囪杩欐槸 PNG 瀛楄妭".getBytes(StandardCharsets.UTF_8);
+ QcReportDocumentExtract extract = QcReportDocumentExtract.ofImages(
+ List.of(new QcReportDocumentExtract.ImagePart(png, "image/png", "绗� 1 椤�")),
+ 1, "raw-image", List.of());
+
+ String base64 = QcReportLlmCallPlanner.plan(extract, "a.png").get(0).imageBase64();
+
+ assertEquals(Base64.getEncoder().encodeToString(png), base64,
+ "蹇呴』鏄8 base64锛氭帴鍙i偅杈逛笉鍋氬墺鍓嶇紑澶勭悊灏辩洿鎺ヨВ鐮侊紝澶氫竴涓瓧绗﹂兘浼氱偢");
+ assertArrayEquals(png, Base64.getDecoder().decode(base64), "瑙g爜鍥炴潵蹇呴』杩樻槸鍘熷瓧鑺�");
+ assertThrows(IllegalArgumentException.class,
+ () -> Base64.getDecoder().decode("data:image/png;base64," + base64),
+ "甯﹀墠缂�浼氳В鐮佸け璐モ�斺�旇繖鏉℃柇瑷�鎶婇偅涓潙閽夊湪鍗曟祴閲岋紝鍏嶅緱鑱旇皟鏃舵墠鍙戠幇");
+ }
+
+ private static QcReportDocumentExtract.ImagePart image(String label) {
+ return new QcReportDocumentExtract.ImagePart(label.getBytes(StandardCharsets.UTF_8), "image/png", label);
+ }
+
+}
diff --git a/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportTemplatePromptBuilderTest.java b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportTemplatePromptBuilderTest.java
new file mode 100644
index 0000000..f81d579
--- /dev/null
+++ b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/aiimport/llm/QcReportTemplatePromptBuilderTest.java
@@ -0,0 +1,244 @@
+package cn.iocoder.yudao.module.qcreport.service.aiimport.llm;
+
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.module.qcreport.controller.admin.aiimport.vo.QcReportComponentSpecVO;
+import cn.iocoder.yudao.module.qcreport.engine.context.ReportFields;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * 鎻愮ず璇嶆瀯閫犮��
+ * <p>
+ * 瀹堢殑鏄�岀害鏉熸湁娌℃湁琚啓杩涘幓銆嶈繖浠朵簨鏈韩銆傛彁绀鸿瘝鏄繖濂� AI 瀵煎叆鐨勫敮涓�闃茬嚎涓渶闈犲墠鐨勪竴鐜細
+ * 閾佸緥灏戝啓涓�鏉★紝妯″瀷灏变細寮�濮嬭緭鍑� HTML 鎴栧祵濂楃粨鏋勶紝鑰岄偅鏃朵笅娓哥殑杩囨护鍙兘涓㈡帀缁撴灉銆�
+ * 鏃犳硶鎶婁涪鎺夌殑姝g‘鍐呭鎵惧洖鏉ャ�傛墍浠ラ�愭潯鏂█锛岃�屼笉鏄潬銆岃窇涓�娆$湅鐪嬪儚涓嶅儚銆嶃��
+ * <p>
+ * 鍙︿竴鏉¢拤姝荤殑鏄�**绉湪娓呭崟蹇呴』瀹屾暣杩涙彁绀鸿瘝**锛氭竻鍗曟槸妯″瀷鐨勮璇嗚竟鐣岋紝
+ * 灏戜簡鏌愪釜缁勪欢鐨勬弿杩帮紝妯″瀷灏辨案杩滀笉浼氳緭鍑哄畠銆�
+ */
+class QcReportTemplatePromptBuilderTest {
+
+ @Test
+ @DisplayName("绉湪娓呭崟瀹屾暣杩涙彁绀鸿瘝锛歵ype銆佹樉绀哄悕銆佸睘鎬� key 涓�涓兘涓嶈兘灏�")
+ void catalogIsFullySerialized() {
+ String prompt = QcReportTemplatePromptBuilder.buildSystemPrompt(catalog());
+
+ assertTrue(prompt.contains("QualityTable"), "娓呭崟閲岀殑 type 娌¤繘鎻愮ず璇嶏紝妯″瀷涓嶅彲鑳借緭鍑哄畠");
+ assertTrue(prompt.contains("妫�楠岄」鐩〃鏍�"), "缁勪欢鐨勬樉绀哄悕娌¤繘鎻愮ず璇嶏紝妯″瀷鍙兘闈� type 鐚滆涔�");
+ assertTrue(prompt.contains("itemsPath"), "灞炴�х殑 key 娌¤繘鎻愮ず璇嶏紝妯″瀷涓嶇煡閬撹兘濉粈涔�");
+ assertTrue(prompt.contains("妫�楠岄」鏁版嵁婧�"), "灞炴�х殑鏄剧ず鍚嶆病杩涙彁绀鸿瘝");
+ assertTrue(prompt.contains("dataPath"), "灞炴�х殑绫诲瀷娌¤繘鎻愮ず璇嶏紝妯″瀷浼氭嬁鏁板瓧濉枃鏈瓧娈�");
+ }
+
+ @Test
+ @DisplayName("浜旀潯閾佸緥閫愭潯鍦ㄥ満")
+ void ironRulesAreAllPresent() {
+ String prompt = QcReportTemplatePromptBuilder.buildSystemPrompt(catalog());
+
+ assertTrue(prompt.contains("鍙兘浣跨敤銆婂彲鐢ㄧ粍浠舵竻鍗曘�嬮噷鍒楀嚭鐨� type"), "缂哄皯銆屽彧鑳界敤娓呭崟鍐� type銆嶈繖鏉�");
+ assertTrue(prompt.contains("涓ョ杈撳嚭 HTML"), "缂哄皯绂佹 HTML 杩欐潯锛屾ā鍨嬩細寮�濮嬪悙鏍囩");
+ assertTrue(prompt.contains("瀹屽叏鎵佸钩"), "缂哄皯鎵佸钩缁撴瀯杩欐潯锛屾ā鍨嬩細杈撳嚭宓屽鐨� children");
+ assertTrue(prompt.contains("鏈0鏄庣殑 key 浼氳涓㈠純"), "缂哄皯灞炴�х櫧鍚嶅崟杩欐潯");
+ assertTrue(prompt.contains("涓嶈鐢� HTML 纭噾"), "缂哄皯鍏滃簳涓㈠純杩欐潯");
+ }
+
+ @Test
+ @DisplayName("涓ゆ潯鏉ヨ嚜璇箟灞傝竟鐣岀殑鎶藉彇瑙勫垯鍦ㄥ満锛歩temsPath 鍥哄畾鍊笺�佺粦瀹氬崰浣嶇鍘熸牱淇濈暀")
+ void extractionRulesCoverSemanticBoundary() {
+ String prompt = QcReportTemplatePromptBuilder.buildSystemPrompt(catalog());
+
+ assertTrue(prompt.contains("inspectionItems"),
+ "缂哄皯 itemsPath 鐨勫浐瀹氬彇鍊兼寚瀵硷紝妯″瀷浼氭妸鏂囦欢閲岀殑鏁版嵁琛屽啓杩涙ā鏉库�斺�旇涔夊眰娌″湴鏂规斁");
+ assertTrue(prompt.contains("{{report.reportNo}}") && prompt.contains("鍘熸牱淇濈暀"),
+ "缂哄皯缁戝畾鍗犱綅绗﹀師鏍蜂繚鐣欒繖鏉★紝妯″瀷浼氭妸 {{report.reportNo}} 鏇挎崲鎴愭牱渚嬫姤鍛婂彿");
+ assertTrue(prompt.contains("鍏蜂綋鏁版嵁琛屼笉瑕佸啓杩涙ā鏉�"),
+ "杩欐潯涓�鏃︾己澶憋紝妯″瀷鍚愬嚭鏉ョ殑妯℃澘浼氬甫鐫�鏌愪竴浠芥姤鍛婄殑瀛楅潰鏁版嵁");
+ }
+
+ @Test
+ @DisplayName("钀芥绛剧讲琛屾湁璞佸厤锛氬す鍦ㄦ楠岃〃鏈涔熺畻钀芥锛屼絾浜哄悕涓庢棩鏈熺暀绌烘墜濉�")
+ void signatureRowIsCarvedOutOfTheDataRowRule() {
+ String prompt = QcReportTemplatePromptBuilder.buildSystemPrompt(catalog());
+
+ assertTrue(prompt.contains("钀芥**绛剧讲琛�**"),
+ "缂哄皯钀芥绛剧讲琛岃繖鏉★細绛剧讲琛屽す鍦ㄦ楠岃〃鏈�鍚庝竴琛岋紝鍙寜銆屽叿浣撴暟鎹涓嶈鍐欒繘妯℃澘銆嶄細琚暣琛屼涪鎺夛紝"
+ + "钀芥灏卞啀涔熸壘涓嶅洖鏉�");
+ assertTrue(prompt.contains("鍗充娇瀹冩帓鍦ㄦ楠岃〃鏍肩殑鏈�鍚庝竴琛屼篃涓�鏍�"),
+ "瑕佺偣鍚嶃�岃〃鏍兼渶鍚庝竴琛屻�嶈繖涓綅缃紝鍚﹀垯妯″瀷浠嶄細鎶婂畠褰撴垚妫�楠屾暟鎹殑涓�閮ㄥ垎");
+ assertTrue(prompt.contains("浜哄悕涓庢棩鏈熷睘浜�"),
+ "璞佸厤鐨勬槸鏍忕洰涓嶆槸鍙栧�硷細涓嶅啓鏄庣殑璇濇ā鍨嬩細鎶娿�屾楠屽憳锛氬紶涓夈�嶈繛浜哄甫鏃ユ湡鍒昏繘妯℃澘锛�"
+ + "鎵�鏈夋姤鍛婇兘浼氬嵃鎴愬悓涓�涓楠屽憳");
+ assertTrue(prompt.contains("鎵撳嵃鍑烘潵鐢变汉鎵嬪~"),
+ "鐣欑┖鐨勭洰鐨勮璇存竻锛堟墦鍗板悗鎵嬪~锛夛紝鍚﹀垯妯″瀷浼氶��鍥炲幓濉畠鐪嬪埌鐨勯偅涓悕瀛�");
+ }
+
+ @Test
+ @DisplayName("绂佹鑷�犲崰浣嶇锛氭ā鍨嬩笉鐭ラ亾涓婁笅鏂囨湁鍝簺瀛楁锛岀紪鍑烘潵鐨勯敭鍙細鍦ㄦ姤鍛婁笂鐣欑櫧")
+ void inventedPlaceholdersAreForbidden() {
+ String prompt = QcReportTemplatePromptBuilder.buildSystemPrompt(catalog());
+
+ assertTrue(prompt.contains("涓嶈鑷繁鍙戞槑鏂扮殑缁戝畾閿�"),
+ "瀹炴祴妯″瀷浼氱粰绛剧讲琛岀紪鍑� {{report.auditor}} / {{report.date}} 杩欑被涓嶅瓨鍦ㄧ殑閿�"
+ + "锛堜笂涓嬫枃閲屽彧鏈� inspector 涓� inspectDate锛屾病鏈� auditor锛夛紝娓叉煋鎴愮┖鐧藉苟瑙﹀彂鍛婅");
+ }
+
+ @Test
+ @DisplayName("鎶ュ憡涓婁笅鏂囩殑瀛楁鍏ㄩ噺杩涙彁绀鸿瘝锛氬彧绂佺紪閫犮�佷笉缁欏彲閫夐泦鍚堬紝绛変簬璁╂ā鍨嬮潬鐚�")
+ void reportFieldWhitelistIsEnumerated() {
+ String prompt = QcReportTemplatePromptBuilder.buildSystemPrompt(catalog());
+
+ assertTrue(prompt.contains("銆愭姤鍛婁笂涓嬫枃鐨勫瓧娈点��"),
+ "绗� 7 鏉″彧鍐欍�屼笉瑕佸彂鏄庢柊閿�嶅嵈涓嶈鏈夊摢浜涢敭锛屾ā鍨嬪彧鑳界寽鈥斺��"
+ + "瀹炴祴鐩磋繛 5 杞紝5 杞兘缂栧嚭浜� {{report.productionDate}} / {{report.expiryDate}}");
+ // 閫愪釜瀛楁鏍稿鑰屼笉鏄娊鏌ヤ袱涓細鐧藉悕鍗曚竴鏃︿粠 ReportFields 鍙嶅皠鏀规垚鎵嬪啓甯搁噺灏变細闈欓粯杩囨湡锛�
+ // 閭f椂妯″瀷鐓ф牱銆屼笉鐭ラ亾銆嶆柊澧炲瓧娈碉紝鐢ㄦ埛鍙細鍦ㄦ姤鍛婁笂鐪嬪埌涓�鐗囩┖鐧�
+ for (Field field : ReportFields.class.getDeclaredFields()) {
+ if (Modifier.isStatic(field.getModifiers())) {
+ continue;
+ }
+ assertTrue(prompt.contains("{{report." + field.getName() + "}}"),
+ "鎶ュ憡瀛楁 " + field.getName() + " 娌¤繘鐧藉悕鍗曪紝妯″瀷鍐欎簡瀹冩覆鏌撴椂涔熷彇涓嶅埌鍊�");
+ }
+ assertFalse(prompt.contains("{{report.productionDate}}"),
+ "鐧藉悕鍗曢噷娣疯繘浜� ReportFields 閲屼笉瀛樺湪鐨勯敭锛岀瓑浜庡湪鏁欐ā鍨嬬紪閫�");
+ }
+
+ @Test
+ @DisplayName("杈撳嚭鏍煎紡绀轰緥鍦ㄥ満锛屼笖鏄庣‘绂佹 markdown 鍥存爮")
+ void outputFormatExample() {
+ String prompt = QcReportTemplatePromptBuilder.buildSystemPrompt(catalog());
+
+ assertTrue(prompt.contains("\"components\""), "缂哄皯杈撳嚭绀轰緥閲岀殑 components 瀛楁");
+ assertTrue(prompt.contains("\"summary\""), "缂哄皯杈撳嚭绀轰緥閲岀殑 summary 瀛楁");
+ assertTrue(prompt.contains("\"ReportFooter\""),
+ "绀轰緥閲屽彧鏈夐《閮ㄧ粍浠舵椂锛屾ā鍨嬭嚜鐒舵兂涓嶅埌鎶ュ憡搴曢儴杩樻湁钀芥锛屼細鎶婅惤娆惧啓鎴愭枃鏈粍浠�");
+ assertTrue(prompt.contains("涓嶈鐢� markdown 浠g爜鍧楀寘瑁�"),
+ "涓嶅啓鏄庣殑璇濇ā鍨嬪父鎶� JSON 鍖呭湪 ```json 閲岋紝铏界劧鍚庣画鍒囩墖鑳藉厹浣忥紝浣嗙櫧鐧藉涓�灞傞闄�");
+ }
+
+ @Test
+ @DisplayName("缁勪欢閫夊瀷璇存槑杩涗簡鎻愮ず璇嶏紝骞舵槑纭姝㈡嬁閫氱敤缁勪欢鍑戞暟")
+ void componentHintAndSelectionRule() {
+ String prompt = QcReportTemplatePromptBuilder.buildSystemPrompt(catalog());
+
+ assertTrue(prompt.contains("鎶ュ憡鏈�椤堕儴鐨勬姮澶村潡"),
+ "缁勪欢鐨� hint 娌¤繘鎻愮ず璇嶏紝妯″瀷闈㈠銆屾姤鍛婃姮澶淬�嶅彧浼氬湪 Text / Heading / ReportHeader 涔嬮棿鐬庣寽");
+ assertTrue(prompt.contains("閫夊瀷鏃朵互 hint 涓哄噯"),
+ "瑕佹寚鏄庣湅 hint 杩欎釜瀛楁锛屽惁鍒欏畠鍙槸娓呭崟閲屼竴娈典笉璧风溂鐨勬枃瀛�");
+ assertTrue(prompt.contains("Text / Heading"),
+ "瑕佺偣鍚嶉�氱敤缁勪欢锛氬彧璁蹭笓闂ㄧ粍浠剁殑鐢ㄩ�旀尅涓嶄綇璇敤锛屾ā鍨嬩粛浼氭寫瀛楁鏈�绠�鍗曠殑閭d釜");
+ assertTrue(prompt.contains("[椤电湁]") && prompt.contains("[椤佃剼]"),
+ "docx 鎶藉彇鍑虹殑 [椤电湁] / [椤佃剼] 鏍囪瑕佸湪杩欓噷琚В閲婏紝妯″瀷鎵嶇煡閬撻偅娈垫槸姣忛〉閲嶅鐨勬姮澶磋惤娆�");
+ }
+
+ @Test
+ @DisplayName("娓呭崟涓虹┖鎴栬秴闀挎椂鐩存帴鎶涢敊锛岃�屼笉鏄妸鐣稿舰鎻愮ず璇嶅彂鍑哄幓")
+ void invalidCatalogThrows() {
+ assertThrows(ServiceException.class,
+ () -> QcReportTemplatePromptBuilder.buildSystemPrompt(List.of()),
+ "娓呭崟涓虹┖鏃跺簲褰撴姤閿欙細妯″瀷娌℃湁浠讳綍绉湪鍙�夌敤锛屽彂鍑哄幓鍙細寰楀埌骞昏");
+ assertThrows(ServiceException.class,
+ () -> QcReportTemplatePromptBuilder.buildSystemPrompt(null));
+
+ String big = "x".repeat(QcReportTemplatePromptBuilder.MAX_CATALOG_JSON_LENGTH);
+ List<QcReportComponentSpecVO> oversized = new ArrayList<>();
+ for (int i = 0; i < 40; i++) {
+ QcReportComponentSpecVO spec = new QcReportComponentSpecVO();
+ spec.setType("T" + i);
+ spec.setLabel(big);
+ oversized.add(spec);
+ }
+ assertThrows(ServiceException.class,
+ () -> QcReportTemplatePromptBuilder.buildSystemPrompt(oversized),
+ "娓呭崟瓒呴暱搴斿綋鎶ラ敊锛氭拺鐖嗘彁绀鸿瘝涓婁笅鏂囩殑琛ㄧ幇鏄ā鍨嬪紑濮嬪拷鐣ュ悗鍗婃锛岃�屼笉鏄姤閿�");
+ }
+
+ @Test
+ @DisplayName("鐢ㄦ埛娑堟伅甯︽潵婧愪笌琛ュ厖璇存槑锛涗袱鑰呴兘涓虹┖鏃朵笉鍑虹幇绌鸿鍣煶")
+ void userMessage() {
+ String withHint = QcReportTemplatePromptBuilder.buildUserMessage(
+ "杩欐槸 IQC 鏉ユ枡妫�楠屾姤鍛�", "鎵弿浠�.pdf 绗� 2 椤�", "姝f枃鍐呭");
+ assertTrue(withHint.contains("杩欐槸 IQC 鏉ユ枡妫�楠屾姤鍛�"));
+ assertTrue(withHint.contains("鎵弿浠�.pdf 绗� 2 椤�"));
+ assertTrue(withHint.contains("姝f枃鍐呭"));
+
+ String bare = QcReportTemplatePromptBuilder.buildUserMessage(null, null, "姝f枃鍐呭");
+ assertFalse(bare.contains("鏉ユ簮锛�"), "鏉ユ簮涓虹┖鏃朵笉璇ョ暀涓嬩竴涓┖鐨勩�屾潵婧愶細銆嶈");
+ assertFalse(bare.contains("鐢ㄦ埛琛ュ厖璇存槑锛�"));
+ assertTrue(bare.endsWith("姝f枃鍐呭"));
+ }
+
+ @Test
+ @DisplayName("鍒�/瀛楁鍙鐩栫殑瑙勫垯鍦ㄥ満锛氬垪澶氬嚭榛樿鍒楁椂鍐� columns锛屼袱灞傝〃澶村啓 headerSpans")
+ void columnOverrideRulesArePresent() {
+ String prompt = QcReportTemplatePromptBuilder.buildSystemPrompt(catalog());
+
+ assertTrue(prompt.contains("columns"),
+ "缂哄皯 columns 杩欐潯锛氬師浠舵楠岃〃鐨勫垪姣旂粍浠堕粯璁ゅ鏃讹紙妫�娴嬫柟娉�/缁撹/澶囨敞锛夛紝妯″瀷浼氭妸鏁村垪涓㈡帀");
+ assertTrue(prompt.contains("鍒楁爣棰�=缁戝畾琛ㄨ揪寮�"),
+ "璇硶绀轰緥缂哄け鏃舵ā鍨嬩細鑷繁鍙戞槑涓�绉嶆牸寮忥紝瑙f瀽鍣ㄨ涓嶅嚭鏉ワ紝绛変簬娌″啓杩欐潯瑙勫垯");
+ assertTrue(prompt.contains("{{item.checkMethod}}"),
+ "鍙敤缁戝畾璺緞鐨勭櫧鍚嶅崟瑕佸啓鍑烘潵锛屽惁鍒欐ā鍨嬩細鐜扮紪 {{item.method}} 杩欑被鍙栦笉鍒板�肩殑閿紝"
+ + "鎶ュ憡涓婂彧鐣欎竴鐗囩┖鐧�");
+ assertTrue(prompt.contains("涓嶈涓㈠垪"),
+ "瑕佹槑纭�屽垪澶氬嚭鏉ヤ篃涓嶈鎹㈢粍浠躲�嶏細涓婁竴杞�夊瀷涓嶇ǔ鐨勬牴鍥犲氨鏄彁绀鸿瘝閲屽浜嗕竴澶勬寚鍚戝钩閾鸿〃鐨勬帾杈�");
+ assertTrue(prompt.contains("瀛愰」={{item.group.childName}}"),
+ "鍒嗙粍琛ㄥ啓 columns 鏃跺繀椤荤偣鍚嶄繚鐣欏瓙椤瑰垪锛氬疄娴嬫ā鍨嬬粰鍒嗙粍琛ㄥ啓鑷畾鍒楁椂鎶娿�屽瓙椤广�嶆暣鍒椾涪浜�"
+ + "锛�3/3 杞兘鍙啓 4 鍒楋級锛岃�屽垎缁勮〃鐨勯粯璁ゅ垪鏈潵灏辨湁杩欎竴鍒椻�斺�旇鐩栧弽鑰屾瘮涓嶈鐩栨洿宸�");
+ assertTrue(prompt.contains("涓�婕忓瓙椤瑰悕鏁村垪浠庢姤鍛婁笂娑堝け"),
+ "鍙銆岃淇濈暀瀛愰」鍒椼�嶉晣涓嶄綇妯″瀷锛氳鍐欐竻婕忔帀鐨勫悗鏋滄槸瀛愰」鍚嶆暣鍒椾粠鎶ュ憡涓婃秷澶憋紝"
+ + "瀹冩墠浼氳鐪熸暟杩欎竴鍒�");
+ assertTrue(prompt.contains("headerSpans") && prompt.contains("鏍囬^璺ㄨ秺鍒楁暟"),
+ "缂哄皯涓ゅ眰琛ㄥご杩欐潯锛氬師浠躲�屾楠岀粨鏋� | 缁撹銆嶄笂闈㈤偅涓�灞備細琚媿骞�");
+ assertTrue(prompt.contains("涔嬪拰蹇呴』绛変簬鍒楁暟"),
+ "璺ㄥ垪鏁板悎璁¤繖鏉′笉鍐欙紝妯″瀷缁欑殑 headerSpans 浼氬湪鏍¢獙閲岃鏁村眰涓㈡帀銆侀��鍥炲崟灞傝〃澶�");
+ assertTrue(prompt.contains("妫�楠岀粨鏋淾5|缁撹^1") && prompt.contains("瑕�**鍗曠嫭鍐欐垚涓�娈�**"),
+ "瀹炴祴妯″瀷浼氭妸銆岀粨璁恒�嶅垪鐨勮法鍒楁暟骞惰繘銆屾楠岀粨鏋溿�嶏紙鍐欐垚 妫�楠岀粨鏋淾6锛夛紝"
+ + "琛ㄥご灏变細鎶婄粨璁哄垪鐢诲埌妫�楠岀粨鏋滃簳涓嬶紱瑕佺偣鍚嶇粨璁哄垪鍗曠嫭鎴愭");
+ assertTrue(prompt.contains("涓�瀛椾笉宸�") && prompt.contains("鍚堝嚭涓�鏍艰法涓よ"),
+ "銆岀粨璁恒�嶈繖绫诲垪鍦ㄥ師浠堕噷鏄竴鏍艰法浣忎笂涓嬩袱灞傦紝璇ユ鏍囬蹇呴』涓庡垪鍚嶄竴瀛椾笉宸墠鑳借璁ゆ垚"
+ + "绾靛悜鍚堝苟鏍硷紱涓嶈娓呰繖涓�鐐癸紝妯″瀷鍐欏嚭鐨勪笂鏍间細琚綋鎴愬彟涓�灞傚垎缁勬爣棰橈紝"
+ + "銆岀粨璁恒�嶄簩瀛楀湪琛ㄥご涓婂嵃涓ら亶鈥斺�旂敤鎴风湅鍒扮殑灏辨槸銆屽浜嗕竴涓粨璁恒��");
+ assertTrue(prompt.contains("涓嶈鑷綔涓诲紶鎶婂畠鏀瑰悕"),
+ "鍙銆屼袱杈硅涓�瀛椾笉宸�嶆尅涓嶄綇 1/5 杞細妯″瀷浼氭妸 columns 閲岄偅涓�鍒楁敼鍚嶆垚銆屽垽瀹氥�嶏紝"
+ + "headerSpans 鍗磋繕鍐欑潃鍘熶欢涓婄殑銆岀粨璁恒�嶏紝涓よ竟瀵逛笉涓婂張閫�鍥炲幓澶氬嵃涓�涓〃澶淬��"
+ + "瑕佹槑璇村埆鏀瑰悕锛屽苟缁欏嚭鏀瑰悕鐨勫悗鏋�");
+ assertTrue(prompt.contains("fields"),
+ "缂哄皯 SampleInfo 鐨� fields 杩欐潯锛氭牱鍝佷俊鎭殑瀛楁涓庨粯璁や笉涓�鑷存椂浠嶄細涓㈠瓧娈�");
+ assertTrue(prompt.contains("瀛楁鍚嶅墠**涓嶅厑璁�**鍔�"),
+ "`#` 鐨勯�傜敤鑼冨洿瑕佸啓娓咃紝鍚﹀垯妯″瀷浼氱粰鏍峰搧淇℃伅鐨勫瓧娈典篃鍔犱笂鍚堝苟鏍囪");
+ }
+
+ private static List<QcReportComponentSpecVO> catalog() {
+ QcReportComponentSpecVO table = new QcReportComponentSpecVO();
+ table.setType("QualityTable");
+ table.setLabel("妫�楠岄」鐩〃鏍�");
+ table.setCategory("data");
+ table.setHint("澶氳妫�楠屾暟鎹殑琛ㄦ牸銆傛姤鍛婃鏂囨渶涓昏鐨勭粍浠躲��");
+ QcReportComponentSpecVO.Field itemsPath = new QcReportComponentSpecVO.Field();
+ itemsPath.setKey("itemsPath");
+ itemsPath.setLabel("妫�楠岄」鏁版嵁婧�");
+ itemsPath.setType("dataPath");
+ itemsPath.setRequired(true);
+ itemsPath.setBindable(true);
+ table.setFields(List.of(itemsPath));
+
+ QcReportComponentSpecVO header = new QcReportComponentSpecVO();
+ header.setType("ReportHeader");
+ header.setLabel("鎶ュ憡鎶ご");
+ header.setCategory("basic");
+ header.setHint("鎶ュ憡鏈�椤堕儴鐨勬姮澶村潡锛氬叕鍙稿悕绉般�佹姤鍛婃爣棰樸�佹姤鍛婄紪鍙枫��");
+ return List.of(header, table);
+ }
+
+}
diff --git a/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/instance/MesQcReportContextMapperTest.java b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/instance/MesQcReportContextMapperTest.java
new file mode 100644
index 0000000..8cf2270
--- /dev/null
+++ b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/instance/MesQcReportContextMapperTest.java
@@ -0,0 +1,364 @@
+package cn.iocoder.yudao.module.qcreport.service.instance;
+
+import cn.iocoder.yudao.module.mes.api.qc.dto.MesQcReportItemRespDTO;
+import cn.iocoder.yudao.module.mes.api.qc.dto.MesQcReportRespDTO;
+import cn.iocoder.yudao.module.qcreport.engine.context.InspectionItem;
+import cn.iocoder.yudao.module.qcreport.engine.context.ReportContext;
+import cn.iocoder.yudao.module.qcreport.engine.context.ReportFields;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Locale;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * 璐ㄦ鍗� 鈫� 鎶ュ憡涓婁笅鏂囩殑瀛楁鎼繍銆�
+ * <p>
+ * 杩欓噷瀹堢殑鏄�屽摢涓�鍒楁惉鍒板摢鍎裤�嶏細鎼敊浜嗕笉浼氭湁寮傚父锛屽彧浼氳鎶ュ憡涓婂嵃鐫�鍒汉鐨勬暟鎹紝
+ * 鑰岃繖绫婚敊璇湪绔埌绔仈璋冮噷寰堥毦涓�鐪肩湅鍑烘潵銆傛墍浠ユ瘡鏉℃惉杩愬姩浣滈兘鍦ㄨ繖閲岄拤姝汇��
+ */
+class MesQcReportContextMapperTest {
+
+ @Test
+ @DisplayName("鍗曞ご瀛楁鍚勫綊鍚勪綅")
+ void mapsHeaderFields() {
+ MesQcReportRespDTO data = baseOrder()
+ .setQcCode("IQC_20260917001")
+ .setQcName("绮捐悩鏉ユ枡妫�楠�-0917")
+ .setQcTypeName("鏉ユ枡妫�楠�")
+ .setCheckResult(2)
+ .setCheckResultText("鐗归噰")
+ .setItemCode("M-001")
+ .setItemName("绮捐悩")
+ .setItemSpecification("宸ヤ笟绾� 99%")
+ .setVendorBatch("VB-2026-0917")
+ .setBatchCode("")
+ .setVendorName("鍗楅�氬寲宸�")
+ .setInspectorName("寮犱笁")
+ .setInspectDate(LocalDateTime.of(2026, 9, 17, 14, 30, 5))
+ .setItems(List.of(item(1, "S1", "0.09")));
+
+ ReportFields report = MesQcReportContextMapper.map(data, "QR20260919-0001").context().getReport();
+
+ assertEquals("QR20260919-0001", report.getReportNo());
+ assertEquals("绮捐悩鏉ユ枡妫�楠�-0917", report.getReportName());
+ assertEquals("M-001", report.getProductCode());
+ assertEquals("绮捐悩", report.getProductName());
+ assertEquals("宸ヤ笟绾� 99%", report.getSpec());
+ // 鏉ユ枡妫�楠屽彧鏈変緵搴斿晢鎵瑰彿锛屾壒娆″彿涓虹┖锛屾姤鍛婂ご銆屾壒娆°�嶈钀藉埌渚涘簲鍟嗘壒鍙蜂笂
+ assertEquals("VB-2026-0917", report.getBatchNo());
+ assertEquals("鏉ユ枡妫�楠�", report.getInspectType());
+ assertEquals("寮犱笁", report.getInspector());
+ assertEquals("2026-09-17 14:30:05", report.getInspectDate());
+ assertEquals("鍗楅�氬寲宸�", report.getSupplierName());
+ // 浜哄伐鎷嶇殑鍒ゅ畾璧� qcResult锛屼笉鏄紩鎿庣殑 result
+ assertEquals("2", report.getQcResult());
+ assertEquals("鐗归噰", report.getQcResultText());
+ }
+
+ @Test
+ @DisplayName("寮曟搸璐熻矗鐨勫瓧娈垫槧灏勫櫒涓�寰嬩笉纰�")
+ void leavesEngineFieldsUntouched() {
+ MesQcReportRespDTO data = baseOrder().setItems(List.of(item(1, "S1", "0.09")));
+
+ ReportFields report = MesQcReportContextMapper.map(data, "QR1").context().getReport();
+
+ // 鍒ゅ畾缁撴灉銆佺粨璁恒�佸悎鏍肩巼銆佽鏁伴兘璇ョ敱 ReportEvaluator 绠楀畬鍐欏洖锛�
+ // 鏄犲皠鍣ㄨ嫢鍦ㄨ繖閲屽~浜嗗�硷紝绛変簬璁┿�屾病楠岃繃銆嶇殑鎶ュ憡鏄剧ず鍚堟牸
+ assertEquals("", report.getResult());
+ assertEquals("", report.getResultText());
+ assertEquals("", report.getConclusion());
+ assertEquals("", report.getPassRate());
+ assertEquals(0, report.getTotal());
+ assertEquals(0, report.getPassCount());
+ assertEquals(0, report.getFailCount());
+ }
+
+ @Test
+ @DisplayName("妫�楠岄」瀛楁鏄犲皠锛屽惈涓婁笅闄愪笌鍗曚綅")
+ void mapsItemFields() {
+ MesQcReportRespDTO data = baseOrder().setItems(List.of(
+ item(1, "S1", "0.09")
+ .setIndicatorCode("IND-30")
+ .setIndicatorName("姝d竵閱囧惈閲�")
+ .setStandardValue("鈮�0.10")
+ .setUnit("%")
+ .setUpperLimit(new BigDecimal("0.10"))
+ .setLowerLimit(new BigDecimal("0.05"))
+ .setRemark("澶嶆祴")));
+
+ InspectionItem item = onlyItem(MesQcReportContextMapper.map(data, "QR1"));
+
+ assertEquals(1, item.getIndex());
+ assertEquals("IND-30", item.getItemCode());
+ assertEquals("姝d竵閱囧惈閲�", item.getItemName());
+ assertEquals("鈮�0.10", item.getStandardValue());
+ assertEquals("0.09", item.getActualValue());
+ assertEquals("%", item.getUnit());
+ assertEquals(0.10, item.getUpperLimit());
+ assertEquals(0.05, item.getLowerLimit());
+ assertEquals("澶嶆祴", item.getRemark());
+ }
+
+ @Test
+ @DisplayName("妫�娴嬫柟娉曢�愯鎼繘涓婁笅鏂囷紝涓庢娴嬭姹傚悇鍗犱竴澶�")
+ void mapsCheckMethod() {
+ MesQcReportRespDTO data = baseOrder().setItems(List.of(
+ item(1, "S1", "0.09")
+ .setIndicatorName("姘村垎")
+ .setCheckMethod("GB 5009.3-2016")
+ .setRequirement("w = (m1 - m0) / m 脳 100%")));
+
+ InspectionItem item = onlyItem(MesQcReportContextMapper.map(data, "QR1"));
+
+ // 妯℃澘閲屽啓 {{item.checkMethod}} 鐨勩�屾娴嬫柟娉曘�嶅垪鑳戒笉鑳藉彇鍒板�硷紝鍏ㄧ湅杩欎竴澶勬湁娌℃湁鎼紱
+ // 婕忔惉涓嶄細鎶ラ敊锛屽彧浼氳閭d竴鏁村垪鍗版垚绌虹櫧骞跺湪闂娓呭崟閲屾寕涓�鏉°�岀粦瀹氬彇涓嶅埌鍊笺��
+ assertEquals("GB 5009.3-2016", item.getCheckMethod());
+ assertEquals("w = (m1 - m0) / m 脳 100%", item.getRequirement());
+ }
+
+ @Test
+ @DisplayName("妫�娴嬫柟娉曚负绌哄緱绌轰覆锛屼笉浼氬嵃鎴� null")
+ void blankCheckMethodIsEmptyString() {
+ MesQcReportRespDTO data = baseOrder().setItems(List.of(item(1, "S1", "0.09")));
+
+ assertEquals("", onlyItem(MesQcReportContextMapper.map(data, "QR1")).getCheckMethod());
+ }
+
+ @Test
+ @DisplayName("娌℃湁瑙勬牸涓婁笅闄愭椂淇濇寔 null锛屼笉鑳藉彉鎴� 0")
+ void keepsMissingLimitsNull() {
+ MesQcReportRespDTO data = baseOrder().setItems(List.of(item(1, "S1", "婢勬竻閫忔槑娑蹭綋")));
+
+ InspectionItem item = onlyItem(MesQcReportContextMapper.map(data, "QR1"));
+
+ // 鍙樻垚 0 鐨勮瘽锛屽疄娴嬪�� 0.09 浼氳鍒ゆ垚銆岃秴涓婇檺涓嶅悎鏍笺�嶁�斺�斿嚟绌洪�犲嚭涓�涓笉鍚堟牸
+ assertNull(item.getUpperLimit());
+ assertNull(item.getLowerLimit());
+ }
+
+ @Test
+ @DisplayName("鍗曟牱鍝侊細鏍峰搧鍙疯繘鎶ュ憡澶达紝涓嶅繀姣忚閲嶅")
+ void singleSampleGoesToHeaderOnly() {
+ MesQcReportRespDTO data = baseOrder().setItems(List.of(
+ item(1, "S1", "0.09"),
+ item(2, "S1", "0.10")));
+
+ MesQcReportContextMapper.Mapped mapped = MesQcReportContextMapper.map(data, "QR1");
+
+ assertEquals("S1", mapped.context().getReport().getSampleNo());
+ assertEquals("", mapped.context().getInspectionItems().get(0).getRemark());
+ assertTrue(mapped.warnings().isEmpty(), "鍗曟牱鍝佷笉璇ヤ骇鐢熸牱鍝佸彇鑸嶆彁绀猴細" + mapped.warnings());
+ }
+
+ @Test
+ @DisplayName("澶氭牱鍝侊細鏍峰搧鍙峰苟鍒楄繘鎶ュ憡澶达紝鍚屾椂鍐欒繘姣忚澶囨敞锛屼竴琛岄兘涓嶄涪")
+ void multipleSamplesFoldIntoRemark() {
+ MesQcReportRespDTO data = baseOrder().setItems(List.of(
+ item(1, "S1", "0.09"),
+ item(2, "S2", "0.12").setRemark("澶嶆祴")));
+
+ MesQcReportContextMapper.Mapped mapped = MesQcReportContextMapper.map(data, "QR1");
+
+ assertEquals("S1銆丼2", mapped.context().getReport().getSampleNo());
+ List<InspectionItem> items = mapped.context().getInspectionItems();
+ assertEquals(2, items.size());
+ assertEquals("鏍峰搧 S1", items.get(0).getRemark());
+ assertEquals("鏍峰搧 S2锛涘娴�", items.get(1).getRemark());
+ }
+
+ @Test
+ @DisplayName("鏍峰搧澶氫簬涓変釜锛氭姤鍛婂ご鐣欑┖骞舵妸鍙栬垗璇存竻妤�")
+ void tooManySamplesLeaveHeaderBlank() {
+ MesQcReportRespDTO data = baseOrder().setQcCode("OQC_20260917001").setItems(List.of(
+ item(1, "S1", "0.09"),
+ item(2, "S2", "0.09"),
+ item(3, "S3", "0.09"),
+ item(4, "S4", "0.09")));
+
+ MesQcReportContextMapper.Mapped mapped = MesQcReportContextMapper.map(data, "QR1");
+
+ assertEquals("", mapped.context().getReport().getSampleNo());
+ String warning = mapped.warnings().stream()
+ .filter(w -> w.contains("鏍峰搧")).findFirst().orElse("");
+ assertTrue(warning.contains("4 涓牱鍝�"), warning);
+ assertTrue(warning.contains("S1銆丼2銆丼3"), warning);
+ // 鎶ュ憡澶存斁涓嶄笅锛屼絾姣忎竴琛岀殑瀹炴祴鍊间粛鍦�
+ assertEquals(4, mapped.context().getInspectionItems().size());
+ }
+
+ @Test
+ @DisplayName("灏氭湭褰曞叆瀹炴祴鍊肩殑椤硅鍑烘彁绀猴紝鑰屼笉鏄畨闈欏湴鍑轰竴琛岀┖鐧�")
+ void warnsOnMissingActualValue() {
+ MesQcReportRespDTO data = baseOrder().setItems(List.of(
+ item(1, "S1", "").setIndicatorName("閰稿惈閲�")));
+
+ MesQcReportContextMapper.Mapped mapped = MesQcReportContextMapper.map(data, "QR1");
+
+ assertEquals("", onlyItem(mapped).getActualValue());
+ assertTrue(mapped.warnings().stream().anyMatch(w -> w.contains("閰稿惈閲�") && w.contains("灏氭湭褰曞叆瀹炴祴鍊�")),
+ "搴旀彁绀烘槸鍝竴椤规病褰曞疄娴嬪�硷細" + mapped.warnings());
+ }
+
+ @Test
+ @DisplayName("鍒嗙粍淇℃伅閫愰」涓嬪彂锛氱粍澶存嬁鍚堝苟琛屾暟涓庡叕寮忥紝瀛愰」鎷胯嚜宸辩殑鍚嶅瓧骞惰鍑哄悎骞舵牸")
+ void mapsGroupStructure() {
+ MesQcReportRespDTO data = baseOrder().setItems(List.of(
+ anchor(1, "姘村垎").setRequirement("w = (m1 - m0) / m 脳 100%").setGroupSpan(3),
+ child(2, "璇曟牱璐ㄩ噺 m").setActualValue("100.5"),
+ child(3, "姘村垎缁撴灉 w").setActualValue("12.3")));
+
+ List<InspectionItem> items = MesQcReportContextMapper.map(data, "QR1").context().getInspectionItems();
+
+ // 缁勫ご锛氬叕寮忚繘銆屾娴嬭姹傘�嶏紝缁勫悕鏍艰法浣忔暣缁勪笁琛�
+ assertEquals("w = (m1 - m0) / m 脳 100%", items.get(0).getRequirement());
+ assertEquals("", items.get(0).getGroup().getChildName());
+ assertEquals(3, items.get(0).getGroup().getSpan());
+ assertEquals("", items.get(0).getGroup().getHidden());
+ // 瀛愰」锛氬悕瀛楄繘銆屽瓙椤广�嶅垪锛岀粍鍚嶆牸璁╃粰涓婇潰閭d竴琛�
+ assertEquals("璇曟牱璐ㄩ噺 m", items.get(1).getGroup().getChildName());
+ assertEquals(1, items.get(1).getGroup().getSpan());
+ assertEquals("hidden", items.get(1).getGroup().getHidden());
+ assertEquals("姘村垎缁撴灉 w", items.get(2).getGroup().getChildName());
+ }
+
+ @Test
+ @DisplayName("缁勫ご鐨勯敋鐐硅鎸夊畾涔夋病鏈夊疄娴嬪�硷紝涓嶈鎶ャ�屽皻鏈綍鍏ュ疄娴嬪�笺��")
+ void groupAnchorDoesNotWarnAboutMissingActualValue() {
+ MesQcReportRespDTO data = baseOrder().setItems(List.of(
+ anchor(1, "姘村垎").setGroupSpan(2),
+ child(2, "璇曟牱璐ㄩ噺 m").setActualValue("100.5")));
+
+ MesQcReportContextMapper.Mapped mapped = MesQcReportContextMapper.map(data, "QR1");
+
+ // 鍊奸兘鍦ㄥ瓙椤硅涓婏紝缁勫ご鎶ヤ簡灏辨槸璇姤锛涘瓙椤硅鑷繁娌″綍鍊间粛鐒惰鎶�
+ assertTrue(mapped.warnings().stream().noneMatch(w -> w.contains("姘村垎") && w.contains("灏氭湭褰曞叆瀹炴祴鍊�")),
+ "缁勫ご涓嶈琚畻鎴愭紡褰曞疄娴嬪�硷細" + mapped.warnings());
+ }
+
+ @Test
+ @DisplayName("娌℃湁鍒嗙粍鐨勬姤鍛婁笉甯﹀垎缁勫瓧娈碉紝鍏嶅緱缁欐病鍐欒繖浜涜矾寰勭殑妯℃澘甯︿笂绌烘牸瀛�")
+ void noGroupingLeavesGroupNull() {
+ MesQcReportRespDTO data = baseOrder().setItems(List.of(item(1, "S1", "0.09")));
+
+ assertNull(onlyItem(MesQcReportContextMapper.map(data, "QR1")).getGroup());
+ }
+
+ @Test
+ @DisplayName("娌℃垚缁勭殑鍒嗙粍椤广�佽琛ヤ簡琛屾潵鏀剧粍鍚嶄笌鍏紡鐨勫垎缁勯」銆佸凡鍒犻櫎鐨勬寚鏍囬兘瑕佸瀹炴彁绀�")
+ void warnsOnSkippedRows() {
+ MesQcReportRespDTO data = baseOrder()
+ .setChildlessGroupNames(List.of("姝d竵閱囧惈閲�"))
+ .setSynthesizedGroupNames(List.of("姘村垎", "閰稿惈閲�"))
+ .setMissingIndicatorCount(2)
+ .setItems(List.of(item(1, "S1", "0.09")));
+
+ MesQcReportContextMapper.Mapped mapped = MesQcReportContextMapper.map(data, "QR1");
+
+ assertTrue(mapped.warnings().stream().anyMatch(
+ w -> w.contains("姝d竵閱囧惈閲�") && w.contains("娌℃湁灞炰簬瀹冧滑鐨勫瓙椤�")),
+ "搴旇鏄庡摢涓垎缁勯」娌¤兘鍚堝苟鎴愮粍锛�" + mapped.warnings());
+ assertTrue(mapped.warnings().stream().anyMatch(
+ w -> w.contains("姘村垎銆侀吀鍚噺") && w.contains("琛ヤ簡涓�琛�")),
+ "搴旇鏄庝负鍝簺缁勫ご琛ヤ簡琛屻�佷负浠�涔堬細" + mapped.warnings());
+ assertTrue(mapped.warnings().stream().anyMatch(w -> w.contains("2 鏉℃槑缁�")),
+ "搴旇鏄庢湁澶氬皯鏉℃槑缁嗙殑鎸囨爣宸茶鍒犻櫎锛�" + mapped.warnings());
+ }
+
+ @Test
+ @DisplayName("娌℃湁鏍峰搧鍙锋椂鎶ュ憡澶翠笌澶囨敞閮界暀绌猴紝涓嶇‖閫犱竴涓彿鍑烘潵")
+ void blankSampleNoStaysBlank() {
+ MesQcReportRespDTO data = baseOrder().setItems(List.of(item(1, "", "0.09")));
+
+ MesQcReportContextMapper.Mapped mapped = MesQcReportContextMapper.map(data, "QR1");
+
+ assertEquals("", mapped.context().getReport().getSampleNo());
+ assertEquals("", onlyItem(mapped).getRemark());
+ }
+
+ @Test
+ @DisplayName("妫�楠屾棩鏈熶负绌哄緱绌轰覆锛屾棩鏈熸牸寮忎笉鍙楁湇鍔″櫒 locale 褰卞搷")
+ void formatsDateWithoutLocaleDrift() {
+ MesQcReportRespDTO noDate = baseOrder().setItems(List.of(item(1, "S1", "0.09")));
+ assertEquals("", MesQcReportContextMapper.map(noDate, "QR1").context().getReport().getInspectDate());
+
+ MesQcReportRespDTO data = baseOrder()
+ .setInspectDate(LocalDateTime.of(2026, 9, 17, 14, 30, 5))
+ .setItems(List.of(item(1, "S1", "0.09")));
+ Locale original = Locale.getDefault();
+ try {
+ // 娉板巻浼氭妸 2026 骞村啓鎴� 2569
+ Locale.setDefault(Locale.forLanguageTag("th-TH-u-ca-buddhist-nu-thai"));
+ assertEquals("2026-09-17 14:30:05",
+ MesQcReportContextMapper.map(data, "QR1").context().getReport().getInspectDate());
+ } finally {
+ Locale.setDefault(original);
+ }
+ }
+
+ @Test
+ @DisplayName("鎶ュ憡缂栧彿涓虹┖鏃剁暀绌猴紝鐢卞嚭浠舵祦绋嬬粰缁堝��")
+ void blankReportNoStaysBlank() {
+ MesQcReportRespDTO data = baseOrder().setItems(List.of(item(1, "S1", "0.09")));
+
+ assertEquals("", MesQcReportContextMapper.map(data, null).context().getReport().getReportNo());
+ }
+
+ /* ------------------------------ 鏋勯�� ------------------------------ */
+
+ private static MesQcReportRespDTO baseOrder() {
+ return new MesQcReportRespDTO()
+ .setQcType(1)
+ .setQcId(1024L)
+ .setQcCode("IQC_20260917001")
+ .setQcName("璐ㄦ鍗�-0917")
+ .setQcTypeName("鏉ユ枡妫�楠�")
+ .setItemCode("")
+ .setItemName("")
+ .setItemSpecification("")
+ .setUnitName("");
+ }
+
+ private static MesQcReportItemRespDTO item(int index, String sampleNo, String actualValue) {
+ return new MesQcReportItemRespDTO()
+ .setIndex(index)
+ .setIndicatorCode("IND-" + index)
+ .setIndicatorName("鎸囨爣" + index)
+ .setStandardValue("")
+ .setActualValue(actualValue)
+ .setUnit("")
+ .setSampleNo(sampleNo)
+ // MES 渚ф瘡涓�椤归兘浼氬甫涓婅繖鍑犱釜鍒嗙粍瀛楁锛堝摢鎬曟槸绌轰覆锛夛紝
+ // 娓叉煋鏈熼潬銆岀┖涓� = 涓嶈緭鍑鸿灞炴�с�嶅尯鍒嗗彲瑙佷笌闅愯棌锛岀己涓�涓兘浼氱敾閿�
+ .setRequirement("")
+ .setCheckMethod("")
+ .setGroupChildName("")
+ .setGroupSpan(1)
+ .setGroupHidden("")
+ .setRemark("");
+ }
+
+ /** 鍒嗙粍鐨勭粍澶磋锛堥敋鐐硅锛夛紝瀹炴祴鍊兼寜瀹氫箟鏄┖鐨勶紝鍚堝苟琛屾暟鐢� MES 渚х畻濂戒笅鍙� */
+ private static MesQcReportItemRespDTO anchor(int index, String name) {
+ return item(index, "S1", "").setIndicatorName(name);
+ }
+
+ /** 鍒嗙粍閲岀殑涓�琛屽瓙椤癸細鍚嶅瓧杩涖�屽瓙椤广�嶅垪锛岀粍鍚嶆牸璁╃粰涓婇潰閭d竴琛� */
+ private static MesQcReportItemRespDTO child(int index, String childName) {
+ return item(index, "S1", "").setIndicatorName(childName).setGroupChildName(childName)
+ .setGroupHidden("hidden");
+ }
+
+ private static InspectionItem onlyItem(MesQcReportContextMapper.Mapped mapped) {
+ ReportContext context = mapped.context();
+ assertEquals(1, context.getInspectionItems().size());
+ return context.getInspectionItems().get(0);
+ }
+
+}
diff --git a/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/instance/ReportNoGeneratorTest.java b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/instance/ReportNoGeneratorTest.java
new file mode 100644
index 0000000..d03cb7c
--- /dev/null
+++ b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/instance/ReportNoGeneratorTest.java
@@ -0,0 +1,94 @@
+package cn.iocoder.yudao.module.qcreport.service.instance;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDate;
+import java.util.Locale;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * 鎶ュ憡缂栧彿鐢熸垚瑙勫垯銆�
+ * <p>
+ * 杩欓噷瀹堢殑鏄�岀紪鍙蜂竴瀹氳兘琚嚜宸辫鎳傘�嶏細{@link ReportNoGenerator#nextSequence} 鏄
+ * {@link ReportNoGenerator#format} 鐨勯�嗚繍绠楋紝涓よ�呮牸寮忎竴鏃﹀涓嶄笂锛�
+ * 琛ㄧ幇鏄祦姘村彿鎮勬倓浠� 1 閲嶆潵锛岀劧鍚庢挒鍞竴绱㈠紩銆侀噸璇� 5 娆″悗鎶ャ�岀紪鍙峰啿绐併�嶁�斺��
+ * 鐢ㄦ埛鐪嬪埌鐨勬槸銆屽嚭涓嶄簡浠躲�嶏紝寰堥毦鑱旀兂鍒版槸缂栧彿鏍煎紡鐨勯棶棰樸��
+ */
+class ReportNoGeneratorTest {
+
+ private static final LocalDate DAY = LocalDate.of(2026, 9, 18);
+
+ @Test
+ @DisplayName("鍓嶇紑涓庣紪鍙锋牸寮�")
+ void prefixAndFormat() {
+ assertEquals("QR20260918-", ReportNoGenerator.prefix(DAY));
+ assertEquals("QR20260918-0001", ReportNoGenerator.format(DAY, 1));
+ assertEquals("QR20260918-0042", ReportNoGenerator.format(DAY, 42));
+ assertEquals("QR20260918-9999", ReportNoGenerator.format(DAY, 9999));
+ }
+
+ @Test
+ @DisplayName("搴忓彿瓒呰繃 9999 鏃朵綅瀹借嚜鐒跺姞瀹斤紝涓嶆埅鏂篃涓嶅洖缁�")
+ void formatWidensBeyondFourDigits() {
+ assertEquals("QR20260918-10000", ReportNoGenerator.format(DAY, 10_000));
+ assertEquals("QR20260918-100000", ReportNoGenerator.format(DAY, 100_000));
+ }
+
+ @Test
+ @DisplayName("缂栧彿閲岀殑鏁板瓧涓庡勾浠戒笉鍙楁湇鍔″櫒 locale 褰卞搷")
+ void independentOfDefaultLocale() {
+ Locale original = Locale.getDefault();
+ try {
+ // 娉板巻浼氭妸 2026 骞村啓鎴� 2569锛涢潪鎷変竵鏁板瓧瀛楀舰浼氬啓鍑洪樋鎷変集-鍗板害鏁板瓧
+ Locale.setDefault(Locale.forLanguageTag("th-TH-u-ca-buddhist-nu-thai"));
+ assertEquals("QR20260918-0007", ReportNoGenerator.format(DAY, 7));
+ } finally {
+ Locale.setDefault(original);
+ }
+ }
+
+ @Test
+ @DisplayName("鍚屼竴澶╂湁缂栧彿鏃跺簭鍙烽�掑")
+ void nextSequenceIncrements() {
+ assertEquals(2, ReportNoGenerator.nextSequence("QR20260918-0001", DAY));
+ assertEquals(43, ReportNoGenerator.nextSequence("QR20260918-0042", DAY));
+ assertEquals(10_000, ReportNoGenerator.nextSequence("QR20260918-9999", DAY));
+ // 浣嶅鍔犲涔嬪悗浠嶈鑳芥帴鐫�寰�涓嬭蛋
+ assertEquals(100_001, ReportNoGenerator.nextSequence("QR20260918-100000", DAY));
+ }
+
+ @Test
+ @DisplayName("杩樻病鏈夌紪鍙锋椂浠� 1 寮�濮�")
+ void nextSequenceStartsAtOneWhenAbsent() {
+ assertEquals(1, ReportNoGenerator.nextSequence(null, DAY));
+ }
+
+ @Test
+ @DisplayName("鎷垮埌鐨勭紪鍙峰睘浜庡埆鐨勬棩鏈熸椂锛屾寜鏂扮殑涓�澶╀粠 1 寮�濮�")
+ void nextSequenceResetsOnOtherDay() {
+ assertEquals(1, ReportNoGenerator.nextSequence("QR20260917-0042", DAY));
+ assertEquals(1, ReportNoGenerator.nextSequence("QR20260919-0042", DAY));
+ }
+
+ @Test
+ @DisplayName("鏍煎紡涓嶈璇嗙殑缂栧彿涓�寰嬪綊 1锛岃�屼笉鏄姏寮傚父鎴栫‖瑙f瀽")
+ void nextSequenceFallsBackOnUnknownFormat() {
+ // 涓嶆槸鏈敓鎴愬櫒鐨勫墠缂�
+ assertEquals(1, ReportNoGenerator.nextSequence("QC-2026-0001", DAY));
+ // 灏鹃儴涓嶆槸鏁板瓧
+ assertEquals(1, ReportNoGenerator.nextSequence("QR20260918-ABCD", DAY));
+ // 灏鹃儴娣蜂簡鏁板瓧涓庡瓧姣�
+ assertEquals(1, ReportNoGenerator.nextSequence("QR20260918-00A1", DAY));
+ // 浣嶆暟涓嶈冻 4 浣�
+ assertEquals(1, ReportNoGenerator.nextSequence("QR20260918-1", DAY));
+ // 浣嶆暟瓒呰繃涓婇檺锛堟湰鐢熸垚鍣ㄤ骇鍑轰笉浜嗚繖涔堥暱鐨勫熬宸达紝璇存槑涓嶆槸瀹冨啓鐨勶級
+ assertEquals(1, ReportNoGenerator.nextSequence("QR20260918-1234567890", DAY));
+ // 鍙湁鍓嶇紑銆佹病鏈夋祦姘�
+ assertEquals(1, ReportNoGenerator.nextSequence("QR20260918-", DAY));
+ // 绌轰覆
+ assertEquals(1, ReportNoGenerator.nextSequence("", DAY));
+ }
+
+}
diff --git a/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/render/PdfPrintOptionsTest.java b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/render/PdfPrintOptionsTest.java
new file mode 100644
index 0000000..326a8df
--- /dev/null
+++ b/yudao-module-qcreport/src/test/java/cn/iocoder/yudao/module/qcreport/service/render/PdfPrintOptionsTest.java
@@ -0,0 +1,158 @@
+package cn.iocoder.yudao.module.qcreport.service.render;
+
+import cn.iocoder.yudao.module.qcreport.engine.PageMargin;
+import cn.iocoder.yudao.module.qcreport.engine.PageSetting;
+import cn.iocoder.yudao.module.qcreport.engine.PageSizes;
+import cn.iocoder.yudao.module.qcreport.engine.ResolvedPage;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * 鎵撳嵃鍙傛暟鎹㈢畻銆�
+ * <p>
+ * 杩欓噷瀹堢殑鏄竴鏉″緢瀹规槗鎮勬倓鍧忔帀鐨勭害鏉燂細**PDF 鐨勭焊闈㈠嚑浣曞繀椤讳笌 HTML 閲岄偅琛� @page 閫愬瓧鐩稿悓**銆�
+ * 涓よ�呬竴鏃︽紓绉伙紝琛ㄧ幇涓嶆槸鎶ラ敊锛岃�屾槸銆岄〉闈㈤瑙堟甯搞�佹墦鍑烘潵瑁佹帀涓�鎴�嶁�斺��
+ * 杩欑鍋忓樊鑲夌溂寰堥毦鍦ㄥ嚑鍗佷釜椤圭洰閲屽彂鐜帮紝鎵�浠ョ敤鍚屾簮鏂█鎶婂畠閽夋鍦ㄥ崟娴嬮噷銆�
+ */
+class PdfPrintOptionsTest {
+
+ @Test
+ @DisplayName("甯歌绾稿紶涓庢柟鍚戞崲绠楁垚 mm")
+ void sizes() {
+ assertEquals(List.of("210mm", "297mm"), size(PdfPrintOptions.of(a4(), true)));
+ assertEquals(List.of("420mm", "297mm"), size(PdfPrintOptions.of(a3Landscape(), true)));
+ assertEquals(List.of("148mm", "210mm"), size(PdfPrintOptions.of(a5(), true)));
+ }
+
+ @Test
+ @DisplayName("Letter 鐨� 215.9mm 涓嶈鏀舵垚鏁存暟")
+ void letterKeepsDecimal() {
+ PageSetting page = new PageSetting("Letter", "portrait", PageMargin.none());
+ assertEquals(List.of("215.9mm", "279.4mm"), size(PdfPrintOptions.of(page, true)));
+ }
+
+ @Test
+ @DisplayName("鏈厤绾稿紶鏃跺洖閫�鍒伴粯璁� A4 绾靛悜")
+ void fallbackToDefault() {
+ assertEquals(List.of("210mm", "297mm"),
+ size(PdfPrintOptions.of(PageSetting.defaultSetting(), true)));
+ }
+
+ @Test
+ @DisplayName("鏈厤椤佃竟璺濇椂鍥涘懆閮芥槸榛樿 10mm锛岄厤浜嗗氨鍘熸牱閫忎紶")
+ void margins() {
+ assertEquals(List.of("10mm", "10mm", "10mm", "10mm"), margins(PdfPrintOptions.of(a4(), true)));
+
+ PageSetting custom = new PageSetting("A4", "portrait", new PageMargin(5.5, 20.0, 12.0, 20.5));
+ assertEquals(List.of("5.5mm", "20mm", "12mm", "20.5mm"),
+ margins(PdfPrintOptions.of(custom, true)));
+
+ // 鍙厤浜嗕竴杈癸紝鍏朵綑浠嶈惤鍒伴粯璁ゅ�硷細涓庡墠绔� margin?.top ?? DEFAULT 鐨勮涔変竴鑷�
+ PageSetting partial = new PageSetting("A4", "portrait", new PageMargin(25.0, null, null, null));
+ assertEquals(List.of("25mm", "10mm", "10mm", "10mm"), margins(PdfPrintOptions.of(partial, true)));
+ }
+
+ @Test
+ @DisplayName("绾搁潰鍑犱綍涓� @page 鍚屾簮锛氬搴�+楂樺害涓庡洓杈硅窛蹇呴』閫愬瓧绛変簬 ResolvedPage 鐨勮緭鍑�")
+ void geometryMatchesCssPage() {
+ List<PageSetting> cases = List.of(
+ PageSetting.defaultSetting(), a4(), a3Landscape(), a5(),
+ new PageSetting("Letter", "landscape", new PageMargin(3.0, 4.5, 5.0, 6.0)),
+ new PageSetting("A4", "portrait", new PageMargin(0.0, 0.0, 0.0, 0.0)));
+ for (PageSetting page : cases) {
+ PdfPrintOptions options = PdfPrintOptions.of(page, true);
+ ResolvedPage resolved = PageSizes.resolve(page);
+ assertEquals(resolved.cssSize(), options.widthCss() + " " + options.heightCss(),
+ "绾搁潰瀹介珮涓� @page 鐨� size 涓嶄竴鑷达紝page=" + page);
+ assertEquals(resolved.cssMargin(), options.marginTopCss() + " " + options.marginRightCss()
+ + " " + options.marginBottomCss() + " " + options.marginLeftCss(),
+ "椤佃竟璺濅笌 @page 鐨� margin 涓嶄竴鑷达紝page=" + page);
+ }
+ }
+
+ @Test
+ @DisplayName("椤佃剼妯℃澘锛氬紑鍚椂甯﹂〉鐮佸崰浣嶇锛屽叧闂椂涓虹┖涓�")
+ void footerTemplate() {
+ String withPageNumber = PdfPrintOptions.of(a4(), true).footerTemplate();
+ assertTrue(withPageNumber.contains("pageNumber"), "椤佃剼缂哄皯褰撳墠椤电爜鍗犱綅绗�");
+ assertTrue(withPageNumber.contains("totalPages"), "椤佃剼缂哄皯鎬婚〉鏁板崰浣嶇");
+ assertTrue(withPageNumber.contains("font-size"), "椤佃剼娌″甫瀛楀彿锛屾祻瑙堝櫒浼氭寜 0 鍙峰瓧澶勭悊锛岀瓑浜庣湅涓嶈");
+
+ assertEquals("", PdfPrintOptions.of(a4(), false).footerTemplate());
+ }
+
+ @Test
+ @DisplayName("椤电湁妯℃澘闈炵┖锛氱暀绌轰細璁� Chromium 琛ヤ笂瀹冭嚜甯︾殑銆屾墦鍗版棩鏈� + 鏂囨。鏍囬銆�")
+ void headerTemplateMustNotBeEmpty() {
+ String header = PdfPrintOptions.HEADER_TEMPLATE;
+ assertTrue(header != null && !header.isBlank(),
+ "椤电湁妯℃澘涓虹┖/null 鏃� Chromium 浼氭墦鍗拌嚜甯︾殑鏃ユ湡涓庢爣棰橈紝鎶ュ憡涓婁細澶氬嚭娌′汉瑕佺殑鏃堕棿鎴�");
+ assertFalse(header.contains("class=\"date\""), "椤电湁閲屼笉璇ュ嚭鐜� Chromium 鐨勬棩鏈熷崰浣嶇被");
+ assertFalse(header.contains("class=\"title\""), "椤电湁閲屼笉璇ュ嚭鐜� Chromium 鐨勬爣棰樺崰浣嶇被");
+ }
+
+ @Test
+ @DisplayName("鎵撳嵃鍔犲浐鏍峰紡锛氳法椤甸噸澶嶈〃澶� + 鎵撳嵃鑳屾櫙鑹�")
+ void printCss() {
+ String printCss = PdfPrintOptions.of(a4(), true).printCss();
+ assertTrue(printCss.contains("table-header-group"), "缂哄皯璺ㄩ〉閲嶅琛ㄥご锛岄暱琛ㄦ牸绗簩椤典細娌℃湁琛ㄥご");
+ assertTrue(printCss.contains("break-inside"), "缂哄皯绂佹琛屽唴鏂〉锛屼竴琛屼細浠庝腑闂村妶寮�");
+ assertTrue(printCss.contains("print-color-adjust"), "缂哄皯鎵撳嵃鑳屾櫙鑹诧紝鍒ゅ畾缁撴灉鐨勫簳鑹叉墦涓嶅嚭鏉�");
+ assertFalse(printCss.contains("@page"), "鎵撳嵃鏍峰紡閲屼笉璇ュ啀鍐� @page锛氱焊闈㈠嚑浣曠殑鍞竴鏉冨▉鏄� HTML 閲岄偅涓�琛�");
+ }
+
+ @Test
+ @DisplayName("闀胯〃鍏佽璺ㄩ〉锛歜reak-inside:avoid 鍙姞鍦ㄨ/鍗曞厓鏍�/鍥剧墖涓婏紝缁濅笉鑳藉姞鍦ㄦ暣寮犺〃涓�")
+ void longTableMayBreakAcrossPages() {
+ List<String> guarded = selectorsDeclaring(PdfPrintOptions.of(a4(), true).printCss(), "break-inside");
+ assertFalse(guarded.contains("table"),
+ "鏁村紶琛ㄧ姝㈡柇椤典細鎶婃斁涓嶄笅鐨勯暱琛ㄦ暣浣撴帹鍒颁笅涓�椤碉紝绗� 1 椤靛彧鍓╅〉鐪変笌澶х墖绌虹櫧锛�"
+ + "璺ㄩ〉瑕侀潬 thead 姣忛〉閲嶅琛ㄥご + 琛屽唴涓嶆柇椤碉紝涓嶈兘闈犳妸鏁村紶琛ㄦ惉璧�");
+ assertTrue(guarded.contains("tr"), "琛屽唴绂佹鏂〉涓嶈兘涓�骞跺幓鎺夛紝鍚﹀垯涓�琛屼細浠庝腑闂村妶寮�");
+ assertTrue(guarded.contains("thead") || PdfPrintOptions.of(a4(), true).printCss()
+ .contains("table-header-group"),
+ "琛ㄥご蹇呴』鍦ㄦ瘡椤甸噸澶嶏紝鍚﹀垯绗� 2 椤佃捣鐨勮〃鏍兼病鏈夊垪鍚�");
+ }
+
+ /** 鍙栧嚭澹版槑浜嗘寚瀹氬睘鎬х殑閭f潯瑙勫垯鐨勩�岄�夋嫨鍣ㄥ垪琛ㄣ�嶏紱娌℃湁杩欐牱鐨勮鍒欐椂杩斿洖绌哄垪琛ㄣ�� */
+ private static List<String> selectorsDeclaring(String css, String property) {
+ for (String rule : css.split("}")) {
+ int brace = rule.indexOf('{');
+ if (brace < 0 || !rule.substring(brace + 1).contains(property + ":")) {
+ continue;
+ }
+ return Arrays.stream(rule.substring(0, brace).split(","))
+ .map(String::trim).filter(selector -> !selector.isEmpty()).toList();
+ }
+ return List.of();
+ }
+
+ private static PageSetting a4() {
+ return new PageSetting("A4", "portrait", PageMargin.none());
+ }
+
+ private static PageSetting a3Landscape() {
+ return new PageSetting("A3", "landscape", PageMargin.none());
+ }
+
+ private static PageSetting a5() {
+ return new PageSetting("A5", "portrait", PageMargin.none());
+ }
+
+ private static List<String> size(PdfPrintOptions options) {
+ return List.of(options.widthCss(), options.heightCss());
+ }
+
+ private static List<String> margins(PdfPrintOptions options) {
+ return List.of(options.marginTopCss(), options.marginRightCss(),
+ options.marginBottomCss(), options.marginLeftCss());
+ }
+
+}
diff --git a/yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t1-v1.0.json b/yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t1-v1.0.json
new file mode 100644
index 0000000..10d6932
--- /dev/null
+++ b/yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t1-v1.0.json
@@ -0,0 +1 @@
+{"bindings":[],"components":[{"id":"c1","type":"ReportHeader","props":{"title":"鏉ユ枡妫�楠屾姤鍛�"}}],"dataSources":[],"grapes":{"assets":[],"styles":[]},"page":{"margin":{"bottom":10.0,"left":10.0,"right":10.0,"top":10.0},"orientation":"portrait","size":"A4"},"rules":[],"schemaVersion":"1.0","styles":[]}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t1-v1.1.json b/yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t1-v1.1.json
new file mode 100644
index 0000000..48b946a
--- /dev/null
+++ b/yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t1-v1.1.json
@@ -0,0 +1 @@
+{"bindings":[],"components":[],"dataSources":[],"grapes":{"assets":[],"styles":[]},"page":{"margin":{"bottom":8.0,"left":8.0,"right":8.0,"top":8.0},"orientation":"landscape","size":"A4"},"rules":[],"schemaVersion":"1.0","styles":[]}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t3-v1.0.json b/yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t3-v1.0.json
new file mode 100644
index 0000000..6b31f07
--- /dev/null
+++ b/yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t3-v1.0.json
@@ -0,0 +1 @@
+{"components":[{"attributes":{"data-quality-type":"ReportHeader","id":"ismd","data-qc-align":"center","data-qc-showReportNo":"true"},"id":"ismd","index":0,"qualityType":"ReportHeader"},{"attributes":{"data-quality-type":"Table","id":"iaw4o","data-qc-rows":"2"},"id":"iaw4o","index":1,"qualityType":"Table"},{"attributes":{"data-quality-type":"Heading","data-qc-text":"鏉ユ枡妫�楠屾姤鍛�","data-qc-level":"2","data-qc-align":"center","id":"i4nxp"},"id":"i4nxp","index":2,"qualityType":"Heading"},{"attributes":{"data-quality-type":"SampleInfo","data-qc-title":"鏍峰搧淇℃伅","data-qc-pairsPerRow":"2","data-qc-showBorder":"true","id":"inuyc"},"id":"inuyc","index":3,"qualityType":"SampleInfo"},{"attributes":{"data-quality-type":"Result","data-qc-label":"鍒ゅ畾缁撹","data-qc-conclusion":"{{report.conclusion}}","data-qc-showPassRate":"true","data-qc-passRateLabel":"鍚堟牸鐜�","id":"iip7l"},"id":"iip7l","index":4,"qualityType":"Result"},{"attributes":{"data-quality-type":"QualityTable","data-qc-title":"妫�楠岄」鐩�","data-qc-itemsPath":"inspectionItems","data-qc-showIndex":"true","data-qc-showStandard":"true","data-qc-showActual":"true","data-qc-showUnit":"true","data-qc-showResult":"true","id":"icjek"},"id":"icjek","index":5,"qualityType":"QualityTable"}],"grapes":{"dataSources":[],"assets":[],"styles":[{"selectors":["#in03"],"style":{"padding":"0"}},{"selectors":["#izqh"],"style":{"font-size":"16px","font-weight":"600","text-align":"center","padding":"8px 0","border-bottom":"2px solid #1677ff"}},{"selectors":["#ismd"],"style":{"margin":"0 0 12px"}},{"selectors":["#ipuuc"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#it2f7"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#in34p"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#i0bb6"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#iom84"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ih1ua"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i07mx"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i5ncy"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ina54"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i4zrl"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i4ufr"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#iknsi"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#iwj64"],"style":{"width":"100%","border-collapse":"collapse","font-size":"12px"}},{"selectors":["#iaw4o"],"style":{"margin":"0 0 8px"}},{"selectors":["#i4nxp"],"style":{"margin":"0 0 8px","font-size":"20px","font-weight":"600","text-align":"center"}},{"selectors":["#ijjnh"],"style":{"font-size":"13px","font-weight":"600","margin":"0 0 4px"}},{"selectors":["#i1to1"],"style":{"border":"1px solid #d9d9d9","padding":"5px 8px","background":"#fafafa","font-weight":"600","width":"90px"}},{"selectors":["#iid2g"],"style":{"border":"1px solid #d9d9d9","padding":"5px 8px"}},{"selectors":["#il55f"],"style":{"border":"1px solid #d9d9d9","padding":"5px 8px","background":"#fafafa","font-weight":"600","width":"90px"}},{"selectors":["#itpd2"],"style":{"border":"1px solid #d9d9d9","padding":"5px 8px"}},{"selectors":["#i2x05"],"style":{"border":"1px solid #d9d9d9","padding":"5px 8px","background":"#fafafa","font-weight":"600","width":"90px"}},{"selectors":["#i2kty"],"style":{"border":"1px solid #d9d9d9","padding":"5px 8px"}},{"selectors":["#ibrcx"],"style":{"border":"1px solid #d9d9d9","padding":"5px 8px","background":"#fafafa","font-weight":"600","width":"90px"}},{"selectors":["#izkmx"],"style":{"border":"1px solid #d9d9d9","padding":"5px 8px"}},{"selectors":["#i7y4a"],"style":{"border":"1px solid #d9d9d9","padding":"5px 8px","background":"#fafafa","font-weight":"600","width":"90px"}},{"selectors":["#ioafb"],"style":{"border":"1px solid #d9d9d9","padding":"5px 8px"}},{"selectors":["#i1z3x"],"style":{"border":"1px solid #d9d9d9","padding":"5px 8px","background":"#fafafa","font-weight":"600","width":"90px"}},{"selectors":["#imvt4"],"style":{"border":"1px solid #d9d9d9","padding":"5px 8px"}},{"selectors":["#in32t"],"style":{"width":"100%","border-collapse":"collapse","font-size":"12px"}},{"selectors":["#inuyc"],"style":{"margin":"0 0 10px"}},{"selectors":["#iu8k1"],"style":{"font-weight":"600"}},{"selectors":["#i4jej"],"style":{"font-size":"13px","line-height":"1.9"}},{"selectors":["#icay8"],"style":{"font-size":"12px","color":"#595959","line-height":"1.9"}},{"selectors":["#iip7l"],"style":{"margin":"0 0 10px","padding":"8px 10px","border":"1px solid #b7eb8f","background":"#f6ffed"}},{"selectors":["#ib8wh"],"style":{"font-size":"13px","font-weight":"600","margin":"0 0 4px"}},{"selectors":["#i4xxf"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600","width":"48px"}},{"selectors":["#iovfh"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#i0r1u"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#iysyu"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600","width":"40%"}},{"selectors":["#idrxg"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600","width":"60px"}},{"selectors":["#iujht"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600","width":"72px"}},{"selectors":["#isgbk2"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ib094g"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#iiobnh"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i3xwl8"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i2plsi"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i9s3pi"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#iebwj"],"style":{"width":"100%","border-collapse":"collapse","font-size":"12px"}},{"selectors":["#icjek"],"style":{"margin":"0 0 10px"}}],"pages":[{"frames":[{"component":{"type":"wrapper","stylable":["background","background-color","background-image","background-repeat","background-attachment","background-position","background-size"],"attributes":{"id":"in03"},"components":[{"attributes":{"data-quality-type":"ReportHeader","id":"ismd","data-qc-align":"center","data-qc-showReportNo":"true"},"components":[{"type":"text","attributes":{"id":"izqh"},"components":[{"type":"textnode","content":"鏅鸿兘璐ㄦ鎶ュ憡"}]},{"attributes":{"data-quality-type":"Table","id":"iaw4o","data-qc-rows":"2"},"components":[{"type":"table","droppable":["tbody","thead","tfoot"],"attributes":{"id":"iwj64"},"components":[{"type":"thead","draggable":["table"],"droppable":["tr"],"components":[{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"components":[{"type":"cell","draggable":["tr"],"attributes":{"id":"ipuuc"},"components":[{"type":"textnode","content":"椤圭洰"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"it2f7"},"components":[{"type":"textnode","content":"鏍囧噯鍊�"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"in34p"},"components":[{"type":"textnode","content":"瀹炴祴鍊�"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i0bb6"},"components":[{"type":"textnode","content":"鍒ゅ畾"}]}]}]},{"type":"tbody","draggable":["table"],"droppable":["tr"],"components":[{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"components":[{"type":"cell","draggable":["tr"],"attributes":{"id":"iom84"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ih1ua"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i07mx"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i5ncy"},"components":[{"type":"textnode","content":"聽"}]}]},{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"components":[{"type":"cell","draggable":["tr"],"attributes":{"id":"ina54"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i4zrl"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i4ufr"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"iknsi"},"components":[{"type":"textnode","content":"聽"}]}]}]}]}]}]},{"tagName":"h2","content":"鏉ユ枡妫�楠屾姤鍛�","attributes":{"data-quality-type":"Heading","data-qc-text":"鏉ユ枡妫�楠屾姤鍛�","data-qc-level":"2","data-qc-align":"center","id":"i4nxp"},"components":[{"attributes":{"data-quality-type":"SampleInfo","data-qc-title":"鏍峰搧淇℃伅","data-qc-pairsPerRow":"2","data-qc-showBorder":"true","id":"inuyc"},"components":[{"type":"text","attributes":{"id":"ijjnh"},"components":[{"type":"textnode","content":"鏍峰搧淇℃伅"}]},{"type":"table","droppable":["tbody","thead","tfoot"],"attributes":{"id":"in32t"},"components":[{"type":"tbody","draggable":["table"],"droppable":["tr"],"components":[{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"components":[{"type":"cell","draggable":["tr"],"attributes":{"id":"i1to1"},"components":[{"type":"textnode","content":"鏍峰搧缂栧彿"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"iid2g"},"components":[{"type":"textnode","content":"{{report.sampleNo}}"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"il55f"},"components":[{"type":"textnode","content":"浜у搧鍚嶇О"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"itpd2"},"components":[{"type":"textnode","content":"{{report.productName}}"}]}]},{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"components":[{"type":"cell","draggable":["tr"],"attributes":{"id":"i2x05"},"components":[{"type":"textnode","content":"瑙勬牸鍨嬪彿"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i2kty"},"components":[{"type":"textnode","content":"{{report.spec}}"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ibrcx"},"components":[{"type":"textnode","content":"鎵规鍙�"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"izkmx"},"components":[{"type":"textnode","content":"{{report.batchNo}}"}]}]},{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"components":[{"type":"cell","draggable":["tr"],"attributes":{"id":"i7y4a"},"components":[{"type":"textnode","content":"妫�楠屾棩鏈�"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ioafb"},"components":[{"type":"textnode","content":"{{report.inspectDate}}"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i1z3x"},"components":[{"type":"textnode","content":"妫�楠屽憳"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"imvt4"},"components":[{"type":"textnode","content":"{{report.inspector}}"}]}]}]}]},{"attributes":{"data-quality-type":"Result","data-qc-label":"鍒ゅ畾缁撹","data-qc-conclusion":"{{report.conclusion}}","data-qc-showPassRate":"true","data-qc-passRateLabel":"鍚堟牸鐜�","id":"iip7l"},"components":[{"type":"text","attributes":{"id":"i4jej"},"components":[{"type":"textnode","content":"鍒ゅ畾缁撹锛�"},{"tagName":"span","type":"text","attributes":{"id":"iu8k1"},"components":[{"type":"textnode","content":"{{report.conclusion}}"}]}]},{"type":"text","attributes":{"id":"icay8"},"components":[{"type":"textnode","content":"鍚堟牸鐜囷細"},{"tagName":"span","type":"text","components":[{"type":"textnode","content":"{{report.passRate}}"}]}]}]}]}]},{"attributes":{"data-quality-type":"QualityTable","data-qc-title":"妫�楠岄」鐩�","data-qc-itemsPath":"inspectionItems","data-qc-showIndex":"true","data-qc-showStandard":"true","data-qc-showActual":"true","data-qc-showUnit":"true","data-qc-showResult":"true","id":"icjek"},"components":[{"type":"text","attributes":{"id":"ib8wh"},"components":[{"type":"textnode","content":"妫�楠岄」鐩�"}]},{"type":"table","droppable":["tbody","thead","tfoot"],"attributes":{"id":"iebwj"},"components":[{"type":"thead","draggable":["table"],"droppable":["tr"],"components":[{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"components":[{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"i4xxf"},"components":[{"type":"textnode","content":"搴忓彿"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"iovfh"},"components":[{"type":"textnode","content":"妫�楠岄」鐩�"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"i0r1u"},"components":[{"type":"textnode","content":"鏍囧噯鍊�"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"iysyu"},"components":[{"type":"textnode","content":"瀹炴祴鍊�"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"idrxg"},"components":[{"type":"textnode","content":"鍗曚綅"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"iujht"},"components":[{"type":"textnode","content":"鍒ゅ畾"}]}]}]},{"type":"tbody","draggable":["table"],"droppable":["tr"],"attributes":{"data-qc-repeat":"inspectionItems"},"components":[{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"attributes":{"data-qc-repeat-row":"item"},"components":[{"type":"cell","draggable":["tr"],"attributes":{"id":"isgbk2"},"components":[{"type":"textnode","content":"{{item.index}}"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ib094g"},"components":[{"type":"textnode","content":"{{item.itemName}}"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"iiobnh"},"components":[{"type":"textnode","content":"{{item.standardValue}}"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i3xwl8"},"components":[{"type":"textnode","content":"{{item.actualValue}}"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i2plsi"},"components":[{"type":"textnode","content":"{{item.unit}}"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i9s3pi"},"components":[{"type":"textnode","content":"{{item.resultText}}"}]}]}]}]}]}],"head":{"type":"head"},"docEl":{"tagName":"html"}},"id":"neBrMRJwQpUYOdku"}],"id":"O0elRFEagkB84rEc"}],"symbols":[]},"page":{"margin":{"bottom":10.0,"left":10.0,"right":10.0,"top":10.0},"orientation":"portrait","size":"A4"},"rules":[],"schemaVersion":"1.1"}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t5-v1.0.json b/yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t5-v1.0.json
new file mode 100644
index 0000000..e671f72
--- /dev/null
+++ b/yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t5-v1.0.json
@@ -0,0 +1 @@
+{"components":[],"grapes":{"dataSources":[],"assets":[],"styles":[{"selectors":["#ih35"],"style":{"padding":"0"},"mediaText":"(max-width: 794px)","atRuleType":"media"}],"pages":[{"frames":[{"component":{"type":"wrapper","stylable":["background","background-color","background-image","background-repeat","background-attachment","background-position","background-size"],"attributes":{"id":"ih35"},"head":{"type":"head"},"docEl":{"tagName":"html"}},"id":"nUYgLqBjjHi0I7pG"}],"id":"vLhiDv8172gReaLe"}],"symbols":[]},"page":{"margin":{"bottom":10.0,"left":10.0,"right":10.0,"top":10.0},"orientation":"landscape","size":"A4"},"rules":[{"id":"rule-1789725335230-1","name":"瀹炴祴鍊煎湪瑙勬牸鍐�","scope":"item","expression":"item.actualValue >= item.lowerLimit AND item.actualValue <= item.upperLimit","enabled":true},{"id":"rule-1789725358261-2","name":"鏁翠綋鍚堟牸鐜囦笉浣庝簬 90%","scope":"report","expression":"PASS_RATE(inspectionItems.result) >= 90","enabled":true}],"schemaVersion":"1.1"}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t5-v1.1.json b/yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t5-v1.1.json
new file mode 100644
index 0000000..bf57ed6
--- /dev/null
+++ b/yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t5-v1.1.json
@@ -0,0 +1 @@
+{"components":[{"attributes":{"data-quality-type":"ReportHeader","data-qc-title":"鏉ユ枡妫�楠屾姤鍛�","data-qc-align":"center","data-qc-showReportNo":"true","data-qc-reportNo":"{{report.reportNo}}","id":"i945"},"id":"i945","index":0,"qualityType":"ReportHeader"},{"attributes":{"data-quality-type":"Table","data-qc-headers":"鎶ュ憡缂栧彿,渚涘簲鍟�,鐗╂枡鍚嶇О,鍒拌揣鏁伴噺,妫�楠岀被鍨�,妫�楠屾棩鏈�,鐗╂枡缂栫爜,鎶芥鏁伴噺","data-qc-rows":"7","id":"iv85z"},"id":"iv85z","index":1,"qualityType":"Table"},{"attributes":{"data-quality-type":"QualityTable","data-qc-title":"妫�楠岄」鐩〃鏍�","data-qc-itemsPath":"inspectionItems","data-qc-showIndex":"true","data-qc-showStandard":"true","data-qc-showActual":"true","data-qc-showUnit":"true","data-qc-showResult":"true","id":"iq1nj4"},"id":"iq1nj4","index":2,"qualityType":"QualityTable"},{"attributes":{"data-quality-type":"Text","data-qc-text":"妫�楠岀粨璁猴細鏈壒鎶芥32浠讹紝鍚堟牸31浠讹紝涓嶅悎鏍�1浠讹紝鍚堟牸鐜�96.9%锛岀‖搴﹂」瓒呬笂闄愶紝鍒ゅ畾涓轰笉鍚堟牸锛岃浆NCR璇勫銆�","data-qc-align":"left","id":"ivzr7f"},"id":"ivzr7f","index":3,"qualityType":"Text"},{"attributes":{"data-quality-type":"Text","data-qc-text":"妫�楠屽憳锛氬紶浼� 瀹℃牳锛氭潕闈� 鏃ユ湡锛�2026-09-18","data-qc-align":"left","id":"i9p5dc"},"id":"i9p5dc","index":4,"qualityType":"Text"}],"grapes":{"dataSources":[],"assets":[],"styles":[{"selectors":["#ivltq"],"style":{"font-size":"18px","font-weight":"600","text-align":"center","padding":"8px 0","border":"none","border-bottom":"2px solid #1677ff"}},{"selectors":["#ifdiq"],"style":{"font-size":"11px","color":"#8c8c8c","text-align":"center","padding":"4px 0 0"}},{"selectors":["#i945"],"style":{"margin":"0 0 12px"}},{"selectors":["#iel85"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#iijsh"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#ify1x"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#i0ai7"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#i8of2"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#ijsuh"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#i6d25"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#ik1na"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#i5xku"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i5ku1"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#imvly"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ixnsd"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ij176"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ici6o"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i9cql"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#it5m2"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#iywpn"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#iuo7e"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ihdjm"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#iihu8"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#iec5p"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#id243"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i18eu"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ipojd"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#irz9i"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i3c5f"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ij8hg"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ijgel"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i2jh2"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ip22o"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#io4br"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#il95h"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ipusj"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#il5im"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#iywso"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ieurt"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i4gh6"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ikcqk"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#iyahk"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ivexoc"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i3ttfo"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ic6l4u"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#in5usj"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i5qiip"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ilznm3"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#idn8pj"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ie77t6"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#isx1o3"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#idxyp7"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i9ocgu"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#igt8pu"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#iqm8qy"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#iaglfn"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#izckyf"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i87gzl"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#inv4xq"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ilb8mo"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ijmp6g"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#itj3yh"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#izftkk"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ijdlyz"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#iemb9g"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#idep2l"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i36acp"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#io5ji"],"style":{"width":"100%","border-collapse":"collapse","font-size":"12px"}},{"selectors":["#iv85z"],"style":{"margin":"0 0 8px"}},{"selectors":["#ii4mbh"],"style":{"font-size":"13px","font-weight":"600","margin":"0 0 4px"}},{"selectors":["#ikkfvu"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600","width":"48px"}},{"selectors":["#i6hkng"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#ihlrpv"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#ibfak6"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600","width":"40%"}},{"selectors":["#ixuakv"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600","width":"60px"}},{"selectors":["#i5j54t"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600","width":"72px"}},{"selectors":["#icn3a5"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ighxcj"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#is4ojz"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ive7ho"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ir1w7o"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ismom6"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#irdai1"],"style":{"width":"100%","border-collapse":"collapse","font-size":"12px"}},{"selectors":["#iq1nj4"],"style":{"margin":"0 0 10px"}},{"selectors":["#ivzr7f"],"style":{"margin":"0 0 8px","font-size":"12px","line-height":"1.6","text-align":"left"}},{"selectors":["#i9p5dc"],"style":{"margin":"0 0 8px","font-size":"12px","line-height":"1.6","text-align":"left"}},{"selectors":["#ij5s"],"style":{"padding":"0"}}],"pages":[{"frames":[{"component":{"type":"wrapper","stylable":["background","background-color","background-image","background-repeat","background-attachment","background-position","background-size"],"attributes":{"id":"ij5s"},"components":[{"attributes":{"data-quality-type":"ReportHeader","data-qc-title":"鏉ユ枡妫�楠屾姤鍛�","data-qc-align":"center","data-qc-showReportNo":"true","data-qc-reportNo":"{{report.reportNo}}","id":"i945"},"components":[{"type":"text","attributes":{"id":"ivltq"},"components":[{"type":"textnode","content":"鏉ユ枡妫�楠屾姤鍛�"}]},{"type":"text","attributes":{"id":"ifdiq"},"components":[{"type":"textnode","content":"鎶ュ憡缂栧彿锛歿{report.reportNo}}"}]}]},{"attributes":{"data-quality-type":"Table","data-qc-headers":"鎶ュ憡缂栧彿,渚涘簲鍟�,鐗╂枡鍚嶇О,鍒拌揣鏁伴噺,妫�楠岀被鍨�,妫�楠屾棩鏈�,鐗╂枡缂栫爜,鎶芥鏁伴噺","data-qc-rows":"7","id":"iv85z"},"components":[{"type":"table","droppable":["tbody","thead","tfoot"],"attributes":{"id":"io5ji"},"components":[{"type":"thead","draggable":["table"],"droppable":["tr"],"components":[{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"components":[{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"iel85"},"components":[{"type":"textnode","content":"鎶ュ憡缂栧彿"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"iijsh"},"components":[{"type":"textnode","content":"渚涘簲鍟�"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"ify1x"},"components":[{"type":"textnode","content":"鐗╂枡鍚嶇О"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"i0ai7"},"components":[{"type":"textnode","content":"鍒拌揣鏁伴噺"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"i8of2"},"components":[{"type":"textnode","content":"妫�楠岀被鍨�"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"ijsuh"},"components":[{"type":"textnode","content":"妫�楠屾棩鏈�"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"i6d25"},"components":[{"type":"textnode","content":"鐗╂枡缂栫爜"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"ik1na"},"components":[{"type":"textnode","content":"鎶芥鏁伴噺"}]}]}]},{"type":"tbody","draggable":["table"],"droppable":["tr"],"components":[{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"components":[{"type":"cell","draggable":["tr"],"attributes":{"id":"i5xku"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i5ku1"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"imvly"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ixnsd"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ij176"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ici6o"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i9cql"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"it5m2"},"components":[{"type":"textnode","content":"聽"}]}]},{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"components":[{"type":"cell","draggable":["tr"],"attributes":{"id":"iywpn"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"iuo7e"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ihdjm"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"iihu8"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"iec5p"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"id243"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i18eu"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ipojd"},"components":[{"type":"textnode","content":"聽"}]}]},{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"components":[{"type":"cell","draggable":["tr"],"attributes":{"id":"irz9i"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i3c5f"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ij8hg"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ijgel"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i2jh2"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ip22o"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"io4br"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"il95h"},"components":[{"type":"textnode","content":"聽"}]}]},{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"components":[{"type":"cell","draggable":["tr"],"attributes":{"id":"ipusj"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"il5im"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"iywso"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ieurt"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i4gh6"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ikcqk"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"iyahk"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ivexoc"},"components":[{"type":"textnode","content":"聽"}]}]},{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"components":[{"type":"cell","draggable":["tr"],"attributes":{"id":"i3ttfo"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ic6l4u"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"in5usj"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i5qiip"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ilznm3"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"idn8pj"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ie77t6"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"isx1o3"},"components":[{"type":"textnode","content":"聽"}]}]},{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"components":[{"type":"cell","draggable":["tr"],"attributes":{"id":"idxyp7"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i9ocgu"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"igt8pu"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"iqm8qy"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"iaglfn"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"izckyf"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i87gzl"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"inv4xq"},"components":[{"type":"textnode","content":"聽"}]}]},{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"components":[{"type":"cell","draggable":["tr"],"attributes":{"id":"ilb8mo"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ijmp6g"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"itj3yh"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"izftkk"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ijdlyz"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"iemb9g"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"idep2l"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i36acp"},"components":[{"type":"textnode","content":"聽"}]}]}]}]}]},{"attributes":{"data-quality-type":"QualityTable","data-qc-title":"妫�楠岄」鐩〃鏍�","data-qc-itemsPath":"inspectionItems","data-qc-showIndex":"true","data-qc-showStandard":"true","data-qc-showActual":"true","data-qc-showUnit":"true","data-qc-showResult":"true","id":"iq1nj4"},"components":[{"type":"text","attributes":{"id":"ii4mbh"},"components":[{"type":"textnode","content":"妫�楠岄」鐩〃鏍�"}]},{"type":"table","droppable":["tbody","thead","tfoot"],"attributes":{"id":"irdai1"},"components":[{"type":"thead","draggable":["table"],"droppable":["tr"],"components":[{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"components":[{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"ikkfvu"},"components":[{"type":"textnode","content":"搴忓彿"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"i6hkng"},"components":[{"type":"textnode","content":"妫�楠岄」鐩�"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"ihlrpv"},"components":[{"type":"textnode","content":"鏍囧噯鍊�"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"ibfak6"},"components":[{"type":"textnode","content":"瀹炴祴鍊�"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"ixuakv"},"components":[{"type":"textnode","content":"鍗曚綅"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"i5j54t"},"components":[{"type":"textnode","content":"鍒ゅ畾"}]}]}]},{"type":"tbody","draggable":["table"],"droppable":["tr"],"attributes":{"data-qc-repeat":"inspectionItems"},"components":[{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"attributes":{"data-qc-repeat-row":"item"},"components":[{"type":"cell","draggable":["tr"],"attributes":{"id":"icn3a5"},"components":[{"type":"textnode","content":"{{index}}"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ighxcj"},"components":[{"type":"textnode","content":"{{item.itemName}}"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"is4ojz"},"components":[{"type":"textnode","content":"{{item.standardValue}}"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ive7ho"},"components":[{"type":"textnode","content":"{{item.actualValue}}"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ir1w7o"},"components":[{"type":"textnode","content":"{{item.unit}}"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ismom6"},"components":[{"type":"textnode","content":"{{item.resultText}}"}]}]}]}]}]},{"tagName":"p","content":"妫�楠岀粨璁猴細鏈壒鎶芥32浠讹紝鍚堟牸31浠讹紝涓嶅悎鏍�1浠讹紝鍚堟牸鐜�96.9%锛岀‖搴﹂」瓒呬笂闄愶紝鍒ゅ畾涓轰笉鍚堟牸锛岃浆NCR璇勫銆�","attributes":{"data-quality-type":"Text","data-qc-text":"妫�楠岀粨璁猴細鏈壒鎶芥32浠讹紝鍚堟牸31浠讹紝涓嶅悎鏍�1浠讹紝鍚堟牸鐜�96.9%锛岀‖搴﹂」瓒呬笂闄愶紝鍒ゅ畾涓轰笉鍚堟牸锛岃浆NCR璇勫銆�","data-qc-align":"left","id":"ivzr7f"}},{"tagName":"p","content":"妫�楠屽憳锛氬紶浼� 瀹℃牳锛氭潕闈� 鏃ユ湡锛�2026-09-18","attributes":{"data-quality-type":"Text","data-qc-text":"妫�楠屽憳锛氬紶浼� 瀹℃牳锛氭潕闈� 鏃ユ湡锛�2026-09-18","data-qc-align":"left","id":"i9p5dc"}}],"head":{"type":"head"},"docEl":{"tagName":"html"}},"id":"9i6ygnM8gmSdRGTl"}],"id":"eiQPni1g7IpHFZBk"}],"symbols":[]},"page":{"margin":{"bottom":10.0,"left":10.0,"right":10.0,"top":10.0},"orientation":"portrait","size":"A4"},"rules":[{"id":"rule-1789725335230-1","name":"瀹炴祴鍊煎湪瑙勬牸鍐�","scope":"item","expression":"item.actualValue >= item.lowerLimit AND item.actualValue <= item.upperLimit","enabled":true},{"id":"rule-1789725358261-2","name":"鏁翠綋鍚堟牸鐜囦笉浣庝簬 90%","scope":"report","expression":"PASS_RATE(inspectionItems.result) >= 90","enabled":true}],"schemaVersion":"1.1"}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t5-v1.2.json b/yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t5-v1.2.json
new file mode 100644
index 0000000..282c6ee
--- /dev/null
+++ b/yudao-module-qcreport/src/test/resources/qcreport/canvas/canvas-t5-v1.2.json
@@ -0,0 +1 @@
+{"components":[{"attributes":{"data-quality-type":"ReportHeader","data-qc-title":"宸ヤ笟鐢ㄦ涓侀唶浜у搧璐ㄩ噺妫�楠屽崟","data-qc-align":"center","data-qc-showReportNo":"false","data-qc-reportNo":"{{report.reportNo}}","id":"iciied"},"id":"iciied","index":0,"qualityType":"ReportHeader"},{"attributes":{"data-quality-type":"Text","data-qc-text":"鐢熶骇鍗曚綅锛氬畞澶忎節娉撳寲宸ョ鎶�鏈夐檺鍏徃","data-qc-align":"left","id":"iyqd5f"},"id":"iyqd5f","index":1,"qualityType":"Text"},{"attributes":{"data-quality-type":"Table","data-qc-headers":"鐢熶骇鏃堕棿,鎵瑰彿,鐢熶骇鏃堕棿,閲囨牱鍦扮偣,鎵归噷锛堝惃锛�,閲囨牱鑰�,鍙栨牱鏃ユ湡,鎵ц鏍囧噯,妫�楠屾棩鏈�","data-qc-rows":"1","id":"i2736c"},"id":"i2736c","index":2,"qualityType":"Table"},{"attributes":{"data-quality-type":"Table","data-qc-headers":"I鍨�,II鍨�","data-qc-rows":"1","id":"iy1xe1"},"id":"iy1xe1","index":3,"qualityType":"Table"},{"attributes":{"data-quality-type":"QualityTable","data-qc-title":"妫�楠岄」鐩�","data-qc-itemsPath":"inspectionItems","data-qc-showIndex":"true","data-qc-showStandard":"true","data-qc-showActual":"true","data-qc-showUnit":"true","data-qc-showResult":"false","id":"ic7hv8"},"id":"ic7hv8","index":4,"qualityType":"QualityTable"},{"attributes":{"data-quality-type":"Text","data-qc-text":"鍒ゅ畾缁撹锛氳川妫�涓撶敤绔�","data-qc-align":"left","id":"iif722"},"id":"iif722","index":5,"qualityType":"Text"},{"attributes":{"data-quality-type":"Text","data-qc-text":"澶囨敞锛氭楠岀粨鏋滀粎瀵规牱鍝佹湰韬垨鏈壒娆¤礋璐c��","data-qc-align":"left","id":"inavjg"},"id":"inavjg","index":6,"qualityType":"Text"},{"attributes":{"data-quality-type":"Spacer","data-qc-height":"20","id":"i8igoh"},"id":"i8igoh","index":7,"qualityType":"Spacer"},{"attributes":{"data-quality-type":"Text","data-qc-text":"妫�楠岋細鏉庡崥 澶嶆牳锛氬懆浜氶檰 鎵瑰噯锛氬寘缈犺悕","data-qc-align":"left","id":"i768pk"},"id":"i768pk","index":8,"qualityType":"Text"}],"grapes":{"dataSources":[],"assets":[],"styles":[{"selectors":["#i12zmm"],"style":{"font-size":"18px","font-weight":"600","text-align":"center","padding":"8px 0","border":"none","border-bottom":"2px solid #1677ff"}},{"selectors":["#iciied"],"style":{"margin":"0 0 12px"}},{"selectors":["#iyqd5f"],"style":{"margin":"0 0 8px","font-size":"12px","line-height":"1.6","text-align":"left"}},{"selectors":["#i11eca"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#iu6ud3"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#i3kjlg"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#i2mbe8"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#igekdg"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#iys9ei"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#i9ityy"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#i72i13"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#iev2r4"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#i8xfar"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i3le5b"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#igr6z6"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ilupj9"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i6rvgg"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i4te8b"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i8grff"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#iav3ul"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ixervh"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#izak7a"],"style":{"width":"100%","border-collapse":"collapse","font-size":"12px"}},{"selectors":["#i2736c"],"style":{"margin":"0 0 8px"}},{"selectors":["#iwxcni"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#ipn512"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#i98hnq"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i88mmo"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i1gdx4"],"style":{"width":"100%","border-collapse":"collapse","font-size":"12px"}},{"selectors":["#iy1xe1"],"style":{"margin":"0 0 8px"}},{"selectors":["#isxkwf"],"style":{"font-size":"13px","font-weight":"600","margin":"0 0 4px"}},{"selectors":["#i1hqf7"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600","width":"48px"}},{"selectors":["#im35no"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#ictkx9"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600"}},{"selectors":["#i1n22r"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600","width":"40%"}},{"selectors":["#iwjziy"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px","background":"#fafafa","font-weight":"600","width":"60px"}},{"selectors":["#i94xnm"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#inbse5"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ifdhwj"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#i7s0gt"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#ivcu3p"],"style":{"border":"1px solid #d9d9d9","padding":"6px 8px"}},{"selectors":["#izp1u1"],"style":{"width":"100%","border-collapse":"collapse","font-size":"12px"}},{"selectors":["#ic7hv8"],"style":{"margin":"0 0 10px"}},{"selectors":["#iif722"],"style":{"margin":"0 0 8px","font-size":"12px","line-height":"1.6","text-align":"left"}},{"selectors":["#inavjg"],"style":{"margin":"0 0 8px","font-size":"12px","line-height":"1.6","text-align":"left"}},{"selectors":["#i8igoh"],"style":{"height":"20px"}},{"selectors":["#i768pk"],"style":{"margin":"0 0 8px","font-size":"12px","line-height":"1.6","text-align":"left"}},{"selectors":["#i39xi1"],"style":{"padding":"0"},"wrapper":1}],"pages":[{"frames":[{"component":{"type":"wrapper","stylable":["background","background-color","background-image","background-repeat","background-attachment","background-position","background-size"],"attributes":{"id":"i39xi1"},"components":[{"attributes":{"data-quality-type":"ReportHeader","data-qc-title":"宸ヤ笟鐢ㄦ涓侀唶浜у搧璐ㄩ噺妫�楠屽崟","data-qc-align":"center","data-qc-showReportNo":"false","data-qc-reportNo":"{{report.reportNo}}","id":"iciied"},"components":[{"type":"text","attributes":{"id":"i12zmm"},"components":[{"type":"textnode","content":"宸ヤ笟鐢ㄦ涓侀唶浜у搧璐ㄩ噺妫�楠屽崟"}]}]},{"tagName":"p","content":"鐢熶骇鍗曚綅锛氬畞澶忎節娉撳寲宸ョ鎶�鏈夐檺鍏徃","attributes":{"data-quality-type":"Text","data-qc-text":"鐢熶骇鍗曚綅锛氬畞澶忎節娉撳寲宸ョ鎶�鏈夐檺鍏徃","data-qc-align":"left","id":"iyqd5f"}},{"attributes":{"data-quality-type":"Table","data-qc-headers":"鐢熶骇鏃堕棿,鎵瑰彿,鐢熶骇鏃堕棿,閲囨牱鍦扮偣,鎵归噷锛堝惃锛�,閲囨牱鑰�,鍙栨牱鏃ユ湡,鎵ц鏍囧噯,妫�楠屾棩鏈�","data-qc-rows":"1","id":"i2736c"},"components":[{"type":"table","droppable":["tbody","thead","tfoot"],"attributes":{"id":"izak7a"},"components":[{"type":"thead","draggable":["table"],"droppable":["tr"],"components":[{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"components":[{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"i11eca"},"components":[{"type":"textnode","content":"鐢熶骇鏃堕棿"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"iu6ud3"},"components":[{"type":"textnode","content":"鎵瑰彿"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"i3kjlg"},"components":[{"type":"textnode","content":"鐢熶骇鏃堕棿"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"i2mbe8"},"components":[{"type":"textnode","content":"閲囨牱鍦扮偣"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"igekdg"},"components":[{"type":"textnode","content":"鎵归噷锛堝惃锛�"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"iys9ei"},"components":[{"type":"textnode","content":"閲囨牱鑰�"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"i9ityy"},"components":[{"type":"textnode","content":"鍙栨牱鏃ユ湡"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"i72i13"},"components":[{"type":"textnode","content":"鎵ц鏍囧噯"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"iev2r4"},"components":[{"type":"textnode","content":"妫�楠屾棩鏈�"}]}]}]},{"type":"tbody","draggable":["table"],"droppable":["tr"],"components":[{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"components":[{"type":"cell","draggable":["tr"],"attributes":{"id":"i8xfar"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i3le5b"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"igr6z6"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ilupj9"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i6rvgg"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i4te8b"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i8grff"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"iav3ul"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ixervh"},"components":[{"type":"textnode","content":"聽"}]}]}]}]}]},{"attributes":{"data-quality-type":"Table","data-qc-headers":"I鍨�,II鍨�","data-qc-rows":"1","id":"iy1xe1"},"components":[{"type":"table","droppable":["tbody","thead","tfoot"],"attributes":{"id":"i1gdx4"},"components":[{"type":"thead","draggable":["table"],"droppable":["tr"],"components":[{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"components":[{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"iwxcni"},"components":[{"type":"textnode","content":"I鍨�"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"ipn512"},"components":[{"type":"textnode","content":"II鍨�"}]}]}]},{"type":"tbody","draggable":["table"],"droppable":["tr"],"components":[{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"components":[{"type":"cell","draggable":["tr"],"attributes":{"id":"i98hnq"},"components":[{"type":"textnode","content":"聽"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i88mmo"},"components":[{"type":"textnode","content":"聽"}]}]}]}]}]},{"attributes":{"data-quality-type":"QualityTable","data-qc-title":"妫�楠岄」鐩�","data-qc-itemsPath":"inspectionItems","data-qc-showIndex":"true","data-qc-showStandard":"true","data-qc-showActual":"true","data-qc-showUnit":"true","data-qc-showResult":"false","id":"ic7hv8"},"components":[{"type":"text","attributes":{"id":"isxkwf"},"components":[{"type":"textnode","content":"妫�楠岄」鐩�"}]},{"type":"table","droppable":["tbody","thead","tfoot"],"attributes":{"id":"izp1u1"},"components":[{"type":"thead","draggable":["table"],"droppable":["tr"],"components":[{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"components":[{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"i1hqf7"},"components":[{"type":"textnode","content":"搴忓彿"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"im35no"},"components":[{"type":"textnode","content":"妫�楠岄」鐩�"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"ictkx9"},"components":[{"type":"textnode","content":"鏍囧噯鍊�"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"i1n22r"},"components":[{"type":"textnode","content":"瀹炴祴鍊�"}]},{"tagName":"th","type":"cell","draggable":["tr"],"attributes":{"id":"iwjziy"},"components":[{"type":"textnode","content":"鍗曚綅"}]}]}]},{"type":"tbody","draggable":["table"],"droppable":["tr"],"attributes":{"data-qc-repeat":"inspectionItems"},"components":[{"type":"row","draggable":["thead","tbody","tfoot"],"droppable":["th","td"],"attributes":{"data-qc-repeat-row":"item"},"components":[{"type":"cell","draggable":["tr"],"attributes":{"id":"i94xnm"},"components":[{"type":"textnode","content":"{{index}}"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"inbse5"},"components":[{"type":"textnode","content":"{{item.itemName}}"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ifdhwj"},"components":[{"type":"textnode","content":"{{item.standardValue}}"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"i7s0gt"},"components":[{"type":"textnode","content":"{{item.actualValue}}"}]},{"type":"cell","draggable":["tr"],"attributes":{"id":"ivcu3p"},"components":[{"type":"textnode","content":"{{item.unit}}"}]}]}]}]}]},{"tagName":"p","content":"鍒ゅ畾缁撹锛氳川妫�涓撶敤绔�","attributes":{"data-quality-type":"Text","data-qc-text":"鍒ゅ畾缁撹锛氳川妫�涓撶敤绔�","data-qc-align":"left","id":"iif722"}},{"tagName":"p","content":"澶囨敞锛氭楠岀粨鏋滀粎瀵规牱鍝佹湰韬垨鏈壒娆¤礋璐c��","attributes":{"data-quality-type":"Text","data-qc-text":"澶囨敞锛氭楠岀粨鏋滀粎瀵规牱鍝佹湰韬垨鏈壒娆¤礋璐c��","data-qc-align":"left","id":"inavjg"}},{"attributes":{"data-quality-type":"Spacer","data-qc-height":"20","id":"i8igoh"}},{"tagName":"p","content":"妫�楠岋細鏉庡崥 澶嶆牳锛氬懆浜氶檰 鎵瑰噯锛氬寘缈犺悕","attributes":{"data-quality-type":"Text","data-qc-text":"妫�楠岋細鏉庡崥 澶嶆牳锛氬懆浜氶檰 鎵瑰噯锛氬寘缈犺悕","data-qc-align":"left","id":"i768pk"}}],"head":{"type":"head"},"docEl":{"tagName":"html"}},"id":"i6uvZx1BxJiEGLIn"}],"id":"F7Tk9bRkV8zTQjiN"}],"symbols":[]},"page":{"margin":{"bottom":10.0,"left":10.0,"right":10.0,"top":10.0},"orientation":"portrait","size":"A4"},"rules":[{"id":"rule-1789725335230-1","name":"瀹炴祴鍊煎湪瑙勬牸鍐�","scope":"item","expression":"item.actualValue >= item.lowerLimit AND item.actualValue <= item.upperLimit","enabled":true},{"id":"rule-1789725358261-2","name":"鏁翠綋鍚堟牸鐜囦笉浣庝簬 90%","scope":"report","expression":"PASS_RATE(inspectionItems.result) >= 90","enabled":true}],"schemaVersion":"1.1"}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/test/resources/qcreport/context.json b/yudao-module-qcreport/src/test/resources/qcreport/context.json
new file mode 100644
index 0000000..c42abbd
--- /dev/null
+++ b/yudao-module-qcreport/src/test/resources/qcreport/context.json
@@ -0,0 +1,32 @@
+{
+ "report": {
+ "reportNo": "QC-2026-0001",
+ "reportName": "鏉ユ枡妫�楠屾姤鍛�",
+ "spec": "M8脳20",
+ "inspectType": "IQC"
+ },
+ "inspectionItems": [
+ {
+ "index": 1,
+ "itemName": "澶栬",
+ "standardValue": "鏃犲垝鐥�",
+ "actualValue": "鍚堟牸"
+ },
+ {
+ "index": 2,
+ "itemName": "闀垮害",
+ "standardValue": "10卤0.5",
+ "actualValue": 10.2,
+ "upperLimit": 10.5,
+ "lowerLimit": 9.5
+ },
+ {
+ "index": 3,
+ "itemName": "纭害",
+ "standardValue": "50~60",
+ "actualValue": 62,
+ "upperLimit": 60,
+ "lowerLimit": 50
+ }
+ ]
+}
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/test/resources/qcreport/expected-html.html b/yudao-module-qcreport/src/test/resources/qcreport/expected-html.html
new file mode 100644
index 0000000..b358a8b
--- /dev/null
+++ b/yudao-module-qcreport/src/test/resources/qcreport/expected-html.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<html lang="zh-CN">
+<head>
+<meta charset="utf-8" />
+<title>鏉ユ枡妫�楠屾姤鍛�</title>
+<style>
+@page { size: 210mm 297mm; margin: 12mm 8mm 12mm 8mm; }
+* { box-sizing: border-box; }
+body { margin: 0; color: #000; font-family: "Microsoft YaHei", "PingFang SC", sans-serif; font-size: 12px; line-height: 1.5; }
+table { border-collapse: collapse; width: 100%; }
+img { max-width: 100%; }
+tr, td, th { page-break-inside: avoid; }
+[data-qc-id="qc-rate"] { font-weight:600;color:#333333 }
+[data-qc-id="qc-row-main"] td { border:1px solid #d9d9d9;padding:4px 6px }
+.qc-table { border-collapse:collapse }
+</style>
+</head>
+<body><div>鎶ュ憡缂栧彿锛歈C-2026-0001锛岀粨璁猴細涓嶅悎鏍�<table class="qc-table" style="width:100%"><thead><tr><th style="border:1px solid #d9d9d9">搴忓彿</th><th>妫�楠岄」鐩�</th></tr></thead><tbody><tr data-qc-id="qc-row-main"><td>1</td><td>澶栬</td><td>鍚堟牸</td><td>涓嶅悎鏍�</td></tr><tr data-qc-id="qc-row-main"><td>2</td><td>闀垮害</td><td>10.2</td><td>鍚堟牸</td></tr><tr data-qc-id="qc-row-main"><td>3</td><td>纭害</td><td>62</td><td>涓嶅悎鏍�</td></tr></tbody></table><div data-qc-id="qc-rate" title="鍚堟牸鐜�" style="margin:6px 0 0">鍚堟牸鐜囷細33.33%锛屽叡 3 椤�</div><div>瀹㈡埛锛氾綔渚涙柟缂栧彿锛�</div><div>鐗规畩瀛楃锛�<鍘熸牱>&"寮曞彿"</div></div></body>
+</html>
\ No newline at end of file
diff --git a/yudao-module-qcreport/src/test/resources/qcreport/expected-rules.json b/yudao-module-qcreport/src/test/resources/qcreport/expected-rules.json
new file mode 100644
index 0000000..0d0616b
--- /dev/null
+++ b/yudao-module-qcreport/src/test/resources/qcreport/expected-rules.json
@@ -0,0 +1,247 @@
+{
+ "errors": [
+ "妯℃澘缁戝畾銆寋{report.supplierCode}}銆嶅湪褰撳墠鏁版嵁涓彇涓嶅埌鍊硷紝宸叉覆鏌撲负绌�"
+ ],
+ "results": [
+ {
+ "expression": "report.reportNo",
+ "scope": "report",
+ "kind": "string",
+ "text": "QC-2026-0001"
+ },
+ {
+ "expression": "report.inspectType IN ('IQC', 'IPQC')",
+ "scope": "report",
+ "kind": "boolean",
+ "text": "true"
+ },
+ {
+ "expression": "report.inspectType NOT IN ('OQC')",
+ "scope": "report",
+ "kind": "boolean",
+ "text": "true"
+ },
+ {
+ "expression": "PASS_RATE(inspectionItems.result)",
+ "scope": "report",
+ "kind": "number",
+ "text": "33.33"
+ },
+ {
+ "expression": "FAIL_RATE(inspectionItems.result)",
+ "scope": "report",
+ "kind": "number",
+ "text": "66.67"
+ },
+ {
+ "expression": "COUNT(inspectionItems)",
+ "scope": "report",
+ "kind": "number",
+ "text": "3"
+ },
+ {
+ "expression": "AVG(inspectionItems.actualValue)",
+ "scope": "report",
+ "kind": "number",
+ "text": "36.1"
+ },
+ {
+ "expression": "ROUND(AVG(inspectionItems.actualValue), 1)",
+ "scope": "report",
+ "kind": "number",
+ "text": "36.1"
+ },
+ {
+ "expression": "STDDEV(inspectionItems.actualValue)",
+ "scope": "report",
+ "kind": "number",
+ "text": "36.62813126546316"
+ },
+ {
+ "expression": "SUM(inspectionItems.actualValue)",
+ "scope": "report",
+ "kind": "number",
+ "text": "72.2"
+ },
+ {
+ "expression": "MAX(inspectionItems.actualValue)",
+ "scope": "report",
+ "kind": "number",
+ "text": "62"
+ },
+ {
+ "expression": "MIN(inspectionItems.actualValue)",
+ "scope": "report",
+ "kind": "number",
+ "text": "10.2"
+ },
+ {
+ "expression": "ABS(-3.5)",
+ "scope": "report",
+ "kind": "number",
+ "text": "3.5"
+ },
+ {
+ "expression": "CP(inspectionItems.actualValue, 70, 30)",
+ "scope": "report",
+ "kind": "number",
+ "text": "0.18200946748688485"
+ },
+ {
+ "expression": "CPK(inspectionItems.actualValue, 70, 30)",
+ "scope": "report",
+ "kind": "number",
+ "text": "0.05551288758349989"
+ },
+ {
+ "expression": "ROUND(10 / 3, 4)",
+ "scope": "report",
+ "kind": "number",
+ "text": "3.3333"
+ },
+ {
+ "expression": "3 * 2 - 1",
+ "scope": "report",
+ "kind": "number",
+ "text": "5"
+ },
+ {
+ "expression": "report.reportNo + '-' + report.spec",
+ "scope": "report",
+ "kind": "string",
+ "text": "QC-2026-0001-M8脳20"
+ },
+ {
+ "expression": "report.total = 3 AND report.passCount = 1",
+ "scope": "report",
+ "kind": "boolean",
+ "text": "true"
+ },
+ {
+ "expression": "report.passRate = '33.33%'",
+ "scope": "report",
+ "kind": "boolean",
+ "text": "true"
+ },
+ {
+ "expression": "report.supplierCode = NULL",
+ "scope": "report",
+ "kind": "boolean",
+ "text": "true"
+ },
+ {
+ "expression": "TRUE AND NOT FALSE",
+ "scope": "report",
+ "error": "鍏抽敭瀛� NOT 鐨勪綅缃笉姝g‘"
+ },
+ {
+ "expression": "!report.total",
+ "scope": "report",
+ "kind": "boolean",
+ "text": "false"
+ },
+ {
+ "expression": "1 / 0",
+ "scope": "report",
+ "error": "瑙勫垯閲屽嚭鐜颁簡闄や互 0"
+ },
+ {
+ "expression": "FOO(1)",
+ "scope": "report",
+ "error": "涓嶆敮鎸佸嚱鏁� FOO锛屽彲鐢ㄥ嚱鏁帮細ABS銆丄VG銆丆OUNT銆丆P銆丆PK銆丗AIL_RATE銆丮AX銆丮IN銆丳ASS_RATE銆丷OUND銆丼TDDEV銆丼UM"
+ },
+ {
+ "expression": "report.reportNo >= ",
+ "scope": "report",
+ "error": "琛ㄨ揪寮忎笉瀹屾暣"
+ },
+ {
+ "expression": "AVG('abc')",
+ "scope": "report",
+ "error": "鍑芥暟 AVG 闇�瑕佹暟鍊煎瀷鍙傛暟锛屽疄闄呭彇鍒般�宎bc銆�"
+ },
+ {
+ "expression": "item.actualValue >= item.lowerLimit AND item.actualValue <= item.upperLimit",
+ "scope": "item2",
+ "kind": "boolean",
+ "text": "true"
+ },
+ {
+ "expression": "item.itemName IN ('闀垮害', '纭害')",
+ "scope": "item2",
+ "kind": "boolean",
+ "text": "true"
+ },
+ {
+ "expression": "item.itemName NOT IN ('澶栬')",
+ "scope": "item2",
+ "kind": "boolean",
+ "text": "true"
+ },
+ {
+ "expression": "-item.index",
+ "scope": "item2",
+ "kind": "number",
+ "text": "-2"
+ },
+ {
+ "expression": "item.actualValue = 10.2",
+ "scope": "item2",
+ "kind": "boolean",
+ "text": "true"
+ },
+ {
+ "expression": "item.result",
+ "scope": "item2",
+ "kind": "string",
+ "text": "PASS"
+ },
+ {
+ "expression": "item.actualValue BETWEEN item.lowerLimit AND item.upperLimit",
+ "scope": "item3",
+ "kind": "boolean",
+ "text": "false"
+ },
+ {
+ "expression": "item.actualValue NOT BETWEEN item.lowerLimit AND item.upperLimit",
+ "scope": "item3",
+ "error": "NOT 鍙兘鐢ㄤ簬 NOT IN"
+ },
+ {
+ "expression": "!0",
+ "scope": "report",
+ "kind": "boolean",
+ "text": "true"
+ },
+ {
+ "expression": "!1",
+ "scope": "report",
+ "kind": "boolean",
+ "text": "false"
+ },
+ {
+ "expression": "!\"0\"",
+ "scope": "report",
+ "kind": "boolean",
+ "text": "true"
+ },
+ {
+ "expression": "!\"abc\"",
+ "scope": "report",
+ "kind": "boolean",
+ "text": "false"
+ },
+ {
+ "expression": "!\"\"",
+ "scope": "report",
+ "kind": "boolean",
+ "text": "true"
+ },
+ {
+ "expression": "-0",
+ "scope": "report",
+ "kind": "number",
+ "text": "0"
+ }
+ ]
+}
diff --git a/yudao-module-qcreport/src/test/resources/qcreport/schema.json b/yudao-module-qcreport/src/test/resources/qcreport/schema.json
new file mode 100644
index 0000000..20d5a8b
--- /dev/null
+++ b/yudao-module-qcreport/src/test/resources/qcreport/schema.json
@@ -0,0 +1,107 @@
+{
+ "schemaVersion": "1.1",
+ "page": {
+ "size": "A4",
+ "orientation": "portrait",
+ "margin": { "top": 12, "right": 8, "bottom": 12, "left": 8 }
+ },
+ "grapes": {
+ "pages": [
+ {
+ "frames": [
+ {
+ "component": {
+ "type": "wrapper",
+ "components": [
+ {
+ "type": "textnode",
+ "content": "鎶ュ憡缂栧彿锛歿{report.reportNo}}锛岀粨璁猴細{{report.conclusion}}"
+ },
+ {
+ "type": "table",
+ "attributes": { "class": "qc-table" },
+ "style": { "width": "100%" },
+ "components": [
+ {
+ "type": "thead",
+ "components": [
+ {
+ "type": "row",
+ "components": [
+ {
+ "type": "cell",
+ "tagName": "th",
+ "content": "搴忓彿",
+ "style": { "border": "1px solid #d9d9d9" }
+ },
+ { "type": "cell", "tagName": "th", "content": "妫�楠岄」鐩�" }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "tbody",
+ "attributes": { "data-qc-repeat": "inspectionItems" },
+ "components": [
+ {
+ "type": "row",
+ "attributes": { "data-qc-repeat-row": "item", "id": "qc-row-main" },
+ "components": [
+ { "type": "cell", "tagName": "td", "content": "{{index}}" },
+ { "type": "cell", "tagName": "td", "content": "{{item.itemName}}" },
+ { "type": "cell", "tagName": "td", "content": "{{item.actualValue}}" },
+ { "type": "cell", "tagName": "td", "content": "{{item.resultText}}" }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "text",
+ "content": "鍚堟牸鐜囷細{{report.passRate}}锛屽叡 {{report.total}} 椤�",
+ "attributes": { "id": "qc-rate", "title": "鍚堟牸鐜�" },
+ "style": { "margin": "6px 0 0" }
+ },
+ {
+ "type": "text",
+ "content": "瀹㈡埛锛歿{report.customerName}}锝滀緵鏂圭紪鍙凤細{{report.supplierCode}}",
+ "attributes": {}
+ },
+ {
+ "type": "text",
+ "content": "鐗规畩瀛楃锛�<鍘熸牱>&\"寮曞彿\"",
+ "attributes": {}
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ],
+ "styles": [
+ { "selectors": ["#qc-rate"], "style": { "font-weight": "600", "color": "#333333" } },
+ {
+ "selectors": ["#qc-row-main td"],
+ "style": { "border": "1px solid #d9d9d9", "padding": "4px 6px" }
+ },
+ { "selectors": [".qc-table"], "style": { "border-collapse": "collapse" } },
+ { "selectors": [".empty-rule"], "style": {} }
+ ]
+ },
+ "rules": [
+ {
+ "id": "rule-item-limit",
+ "name": "瀹炴祴鍊煎湪瑙勬牸鍐�",
+ "scope": "item",
+ "expression": "item.actualValue >= item.lowerLimit AND item.actualValue <= item.upperLimit",
+ "enabled": true
+ },
+ {
+ "id": "rule-report-rate",
+ "name": "鏁翠綋鍚堟牸锛堝悎鏍肩巼鈮�60锛�",
+ "scope": "report",
+ "expression": "PASS_RATE(inspectionItems) >= 60"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/storage/StorageBlobApi.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/storage/StorageBlobApi.java
new file mode 100644
index 0000000..2e6fc31
--- /dev/null
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/storage/StorageBlobApi.java
@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.system.api.storage;
+
+/**
+ * 鏂囦欢锛坆lob锛堿PI 鎺ュ彛
+ * <p>
+ * 渚涗笟鍔℃ā鍧楀瓨鏀俱�屽悗绔嚜宸辩敓鎴愩�嶇殑鏂囦欢锛堟墦鍗板嚭鐨� PDF銆佸鍑虹殑鎶ヨ〃绛夛級銆�
+ * 鍓嶇涓婁紶浠嶈蛋 {@code /system/storage-blob/upload}锛屾湰鎺ュ彛鍙В鍐虫湇鍔$娌℃湁瀛楄妭鍏ュ弬鍏ュ彛鐨勯棶棰樸��
+ */
+public interface StorageBlobApi {
+
+ /**
+ * 淇濆瓨鍐呭瓨涓殑瀛楄妭鍐呭涓轰竴涓枃浠�
+ *
+ * @param content 鏂囦欢鍐呭锛屼笉鑳戒负绌�
+ * @param originalFileName 鍘熷鏂囦欢鍚嶏紙涓嬭浇鏃跺睍绀猴級
+ * @param contentType 璧勬簮绫诲瀷锛屽 application/pdf
+ * @return 鏂囦欢缂栧彿锛坰ystem_storage_blob 涓婚敭锛夛紝鎷垮埌鍚庤繕闇�鑷涓庝笟鍔¤褰曞缓绔嬮檮浠跺叧鑱�
+ */
+ Long saveBlob(byte[] content, String originalFileName, String contentType);
+
+}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/storage/StorageBlobApiImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/storage/StorageBlobApiImpl.java
new file mode 100644
index 0000000..15b63e9
--- /dev/null
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/api/storage/StorageBlobApiImpl.java
@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.system.api.storage;
+
+import cn.iocoder.yudao.module.system.controller.admin.storage.vo.SystemStorageBlobRespVO;
+import cn.iocoder.yudao.module.system.service.storage.SystemStorageBlobService;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+@Service
+public class StorageBlobApiImpl implements StorageBlobApi {
+
+ @Resource
+ private SystemStorageBlobService systemStorageBlobService;
+
+ @Override
+ public Long saveBlob(byte[] content, String originalFileName, String contentType) {
+ // 涓氬姟鏂囦欢涓嶈繘鍏叡鐩綍锛氳蛋涓存椂绛惧悕鍦板潃锛屼笌鍓嶇涓婁紶鐨勯粯璁よ涓轰繚鎸佷竴鑷�
+ SystemStorageBlobRespVO blob = systemStorageBlobService.saveBlob(content, originalFileName, contentType, false);
+ return blob == null ? null : blob.getId();
+ }
+
+}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/storage/StorageRecordTypeEnum.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/storage/StorageRecordTypeEnum.java
index d0e1d22..fe7437d 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/storage/StorageRecordTypeEnum.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/enums/storage/StorageRecordTypeEnum.java
@@ -67,7 +67,11 @@
// ===== SRM =====
SRM_SUPPLIER_CERTIFICATE("srm_supplier_certificate", "SRM 渚涘簲鍟嗚祫璐ㄨ瘉涔�"),
- SRM_TENDER_PROJECT("srm_tender_project", "SRM 鎷涙爣椤圭洰");
+ SRM_TENDER_PROJECT("srm_tender_project", "SRM 鎷涙爣椤圭洰"),
+
+ // ===== 鏅鸿兘璐ㄦ鎶ュ憡 =====
+ QC_REPORT_INSTANCE("qc_report_instance", "璐ㄦ鎶ュ憡瀹炰緥"),
+ QC_REPORT_TEMPLATE("qc_report_template", "璐ㄦ鎶ュ憡妯℃澘");
private final String type;
private final String description;
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/storage/SystemStorageBlobService.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/storage/SystemStorageBlobService.java
index ee92fe0..bec3dd6 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/storage/SystemStorageBlobService.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/storage/SystemStorageBlobService.java
@@ -24,6 +24,19 @@
List<SystemStorageBlobRespVO> upload(List<MultipartFile> files, Boolean isPublic);
/**
+ * 淇濆瓨鍐呭瓨涓殑瀛楄妭鍐呭涓轰竴涓枃浠讹紙鍚庣鑷繁鐢熸垚鐨勬枃浠惰蛋杩欎釜鍏ュ彛锛屽鎵撳嵃鍑虹殑 PDF锛夈��
+ * <p>
+ * 涓嶇粡杩� HTTP 涓婁紶锛屽洜姝や笉浜х敓銆屼笂浼犺�呫�嶆蹇碉紱钀界洏涓庤惤搴撹鍒欎笌 {@link #upload} 涓�鑷淬��
+ *
+ * @param content 鏂囦欢鍐呭锛屼笉鑳戒负绌�
+ * @param originalFileName 鍘熷鏂囦欢鍚嶏紙涓嬭浇鏃跺睍绀猴級
+ * @param contentType 璧勬簮绫诲瀷锛屽 application/pdf
+ * @param isPublic 鏄惁鍏叡鏂囦欢锛坱rue=姘镐箙鏈夋晥锛宖alse=涓存椂token鎺у埗锛�
+ * @return 涓婁紶缁撴灉锛堝惈棰勮/涓嬭浇鍦板潃锛�
+ */
+ SystemStorageBlobRespVO saveBlob(byte[] content, String originalFileName, String contentType, Boolean isPublic);
+
+ /**
* 閫氳繃token鑾峰彇鏂囦欢
*
* @param fileName 鍞竴鏂囦欢鍚�
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/storage/SystemStorageBlobServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/storage/SystemStorageBlobServiceImpl.java
index 9592b09..2eb18d3 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/storage/SystemStorageBlobServiceImpl.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/storage/SystemStorageBlobServiceImpl.java
@@ -20,6 +20,7 @@
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@@ -84,6 +85,43 @@
result.add(blobRespVO);
}
return result;
+ }
+
+ @Override
+ public SystemStorageBlobRespVO saveBlob(byte[] content, String originalFileName, String contentType, Boolean isPublic) {
+ if (content == null || content.length == 0) {
+ throw exception(STORAGE_FILE_EMPTY);
+ }
+ // 鏂囦欢鍚嶆潵鑷皟鐢ㄦ柟锛屼粛瑕� cleanPath锛氬畠浼氭嫾杩涜惤鐩樻枃浠跺悕锛屼笉鑳藉甫鍑虹洰褰曞眰绾�
+ String safeName = StringUtils.hasText(originalFileName)
+ ? StringUtils.cleanPath(originalFileName)
+ : UUID.randomUUID().toString();
+ String fileName = UUID.randomUUID() + "_" + safeName;
+ String relativePath = fileUtil.buildRelativePath();
+ File targetDirectory = new File(properties.getPath(), relativePath);
+ if (!targetDirectory.exists() && !targetDirectory.mkdirs()) {
+ throw exception(STORAGE_BLOB_UPLOAD_FAILED);
+ }
+ File dest = new File(targetDirectory, fileName);
+ try {
+ Files.write(dest.toPath(), content);
+ SystemStorageBlobRespVO blobRespVO = persistBlob(contentType, safeName, fileName,
+ relativePath, content.length, isPublic);
+ if (blobRespVO == null || blobRespVO.getId() == null) {
+ throw exception(STORAGE_BLOB_UPLOAD_FAILED);
+ }
+ return blobRespVO;
+ } catch (RuntimeException e) {
+ if (dest.exists()) {
+ dest.delete();
+ }
+ throw e;
+ } catch (IOException e) {
+ if (dest.exists()) {
+ dest.delete();
+ }
+ throw exception(STORAGE_BLOB_UPLOAD_FAILED);
+ }
}
@Override
@@ -157,12 +195,24 @@
private SystemStorageBlobRespVO createStorageBlob(MultipartFile file, String originalFileName,
String fileName, String relativePath, Boolean isPublic) {
+ return persistBlob(file.getContentType(), originalFileName, fileName,
+ relativePath, file.getSize(), isPublic);
+ }
+
+ /**
+ * 钀藉簱 + 鎷奸瑙�/涓嬭浇鍦板潃銆�
+ * <p>
+ * 涓ゆ潯涓婁紶璺緞锛坽@link #upload} 鐨� MultipartFile銆亄@link #saveBlob} 鐨� byte[]锛夊叡鐢ㄨ繖涓�姝ワ紝
+ * 鍙湪杩欓噷缁存姢绛惧悕 URL 鐨勬嫾娉曪紝閬垮厤涓ゅ鍚勫啓涓�閬嶅悗鍦板潃鏍煎紡璧板亸銆�
+ */
+ private SystemStorageBlobRespVO persistBlob(String contentType, String originalFileName, String fileName,
+ String relativePath, long byteSize, Boolean isPublic) {
SystemStorageBlobDO blob = new SystemStorageBlobDO();
blob.setResourceKey(UUID.randomUUID().toString().replace("-", ""));
- blob.setContentType(file.getContentType());
+ blob.setContentType(contentType);
blob.setOriginalFilename(originalFileName);
blob.setUidFilename(fileName);
- blob.setByteSize(file.getSize());
+ blob.setByteSize(byteSize);
blob.setPath(relativePath);
storageBlobMapper.insert(blob);
diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml
index 7302f33..1763130 100644
--- a/yudao-server/pom.xml
+++ b/yudao-server/pom.xml
@@ -164,6 +164,13 @@
<version>${revision}</version>
</dependency>
+ <!-- 鏅鸿兘璐ㄦ鎶ュ憡璁捐骞冲彴妯″潡 -->
+ <dependency>
+ <groupId>cn.iocoder.boot</groupId>
+ <artifactId>yudao-module-qcreport</artifactId>
+ <version>${revision}</version>
+ </dependency>
+
<!-- spring boot 閰嶇疆鎵�闇�渚濊禆 -->
<dependency>
<groupId>org.springframework.boot</groupId>
diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml
index c169c66..4bf33fa 100644
--- a/yudao-server/src/main/resources/application-local.yaml
+++ b/yudao-server/src/main/resources/application-local.yaml
@@ -168,6 +168,7 @@
yudao:
ai:
+ timeout: 60s # 鍗曟澶фā鍨嬭皟鐢ㄨ秴鏃讹紱涓嶈鐨勮瘽妯″瀷鎺掗槦鏃惰姹備細涓�鐩存寕璧�
vector-store:
type: milvus # 鍚戦噺搴撶被鍨嬶細milvus
milvus:
@@ -191,13 +192,33 @@
storage: # 鏂囦欢涓婁紶閰嶇疆
path: D:/uploads # 鏂囦欢瀛樺偍鏍圭洰褰曪紙鎸夊疄闄呮湇鍔″櫒璺緞閰嶇疆锛�
url-prefix: /admin-api/system/storage-blob # URL璺緞鍓嶇紑
- domain: http://192.168.0.10:48080 # 鍩熷悕鍓嶇紑锛堟寜瀹為檯鍩熷悕閰嶇疆锛�
+ domain: http://192.168.1.6:48080 # 鍩熷悕鍓嶇紑锛堟寜瀹為檯鍩熷悕閰嶇疆锛�
expired: 120 # token杩囨湡鏃堕棿锛堝垎閽燂級
use-limit: 10 # token浣跨敤娆℃暟涓婇檺
jwt-secret: abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG # JWT瀵嗛挜锛堣嚦灏�32瀛楃锛�
compress: true # 鏄惁鍘嬬缉鍥剧墖
need-compress-size: 10MB # 瑙﹀彂鍘嬬缉鐨勬枃浠跺ぇ灏忛槇鍊�
compress-quality: 0.5 # 鍘嬬缉璐ㄩ噺(0.0-1.0)
+ qcreport: # 鏅鸿兘璐ㄦ鎶ュ憡
+ pdf: # PDF 鍑轰欢锛氭湇鍔$璋� Chromium 鎶婃姤鍛� HTML 鎵撳嵃鎴� PDF
+ enabled: true # 鍏虫帀鍚庡鍑烘帴鍙d細鏄庣‘鎶ャ�屾湭鍚敤銆嶏紝鑰屼笉鏄姏 500
+ channel: chrome # 娴忚鍣ㄩ�氶亾锛屾湰鏈哄凡瑁� Chrome锛涚暀绌哄垯鐢� Playwright 鑷甫鐨� Chromium锛堥渶鍏堟墽琛� playwright install chromium锛岀害 150MB锛�
+ executable-path: '' # 娴忚鍣ㄥ彲鎵ц鏂囦欢璺緞锛岄厤浜嗗氨浼樺厛浜� channel锛岀敤浜庤鍦ㄩ潪鏍囧噯浣嶇疆鐨勬祻瑙堝櫒
+ concurrency: 2 # 鍚屾椂杩涜鐨� PDF 娓叉煋涓婇檺锛孋hromium 寰堝悆鍐呭瓨锛屼笉瑕佹斁寮�
+ timeout-ms: 30000 # 鍗曟娓叉煋瓒呮椂锛堟绉掞級锛屽悓鏃朵篃鏄帓闃熺瓑骞跺彂鍚嶉鐨勪笂闄�
+ show-page-number: true # 椤佃剼鎵撳嵃銆岀 N 椤� / 鍏� M 椤点��
+ browser-args: [ ] # 棰濆鐨勬祻瑙堝櫒鍚姩鍙傛暟锛屽 Linux 浠� root 杩愯闇�鍔� --no-sandbox
+ ai-import: # AI 瀵煎叆锛氫笂浼犳棦鏈夋姤鍛婃枃浠讹紝璇嗗埆鎴愭ā鏉胯崏绋裤�傞渶瑕佽兘鍑虹綉璁块棶 DashScope
+ enabled: true # 鍏虫帀鍚庢帴鍙d細鏄庣‘鎶ャ�屾湭鍚敤銆嶏紝鑰屼笉鏄竴鐩寸瓑鍒� AI 瓒呮椂
+ max-files: 3 # 涓�娆℃渶澶氬嚑涓枃浠�
+ max-pages-per-file: 5 # 鍗曟枃浠堕〉鏁颁笂闄愶紝瓒呭嚭鎶ラ敊鑰屼笉鏄潤榛樻埅鏂�
+ max-pages-per-request: 8 # 涓�娆¤姹傜疮璁¢〉鏁颁笂闄愶紙澶氭枃浠跺彔鍔犲悗鐨勬�婚椄锛�
+ max-duration-seconds: 180 # 涓�娆″鍏ユ�昏�楁椂涓婇檺锛堜袱娆¤皟鐢ㄤ箣闂存鏌ワ級锛涘墠绔秴鏃堕』姣斿畠鍔犱笂 yudao.ai.timeout 鏇村
+ max-file-size-mb: 20 # 鍗曟枃浠跺ぇ灏忎笂闄�
+ max-components: 200 # 璇嗗埆鍑虹殑缁勪欢鎬绘暟涓婇檺锛岃秴鍑烘埅鏂苟鍦ㄦ彁绀洪噷璇存槑
+ pdf-text-page-threshold: 30 # 骞冲潎姣忛〉瀛楃鏁颁綆浜庢鍊煎嵆鎸夋壂鎻忎欢閫愰〉杞浘璇嗗埆
+ render-dpi: 200 # 鎵弿椤佃浆鍥剧殑 DPI锛屼綆浜� 200 涓枃瀛楀舰浼氱硦
+ max-xlsx-rows: 300 # Excel 鍗曡〃鏈�澶氳鍙栫殑琛屾暟
database-backup: # 鏁版嵁搴撳浠介厤缃�
host: localhost # 澶囦唤鐩爣 MySQL 涓绘満锛岀暀绌鸿嚜鍔ㄤ粠鏁版嵁婧� JDBC URL 瑙f瀽
port: 3306 # 澶囦唤鐩爣 MySQL 绔彛锛岀暀绌鸿嚜鍔ㄤ粠鏁版嵁婧� JDBC URL 瑙f瀽
diff --git a/yudao-server/src/main/resources/application-test.yaml b/yudao-server/src/main/resources/application-test.yaml
index 55c7ba0..af05078 100644
--- a/yudao-server/src/main/resources/application-test.yaml
+++ b/yudao-server/src/main/resources/application-test.yaml
@@ -190,6 +190,7 @@
yudao:
ai:
+ timeout: 60s # 鍗曟澶фā鍨嬭皟鐢ㄨ秴鏃讹紱涓嶈鐨勮瘽妯″瀷鎺掗槦鏃惰姹備細涓�鐩存寕璧�
vector-store:
type: milvus # 鍚戦噺搴撶被鍨嬶細milvus
milvus:
@@ -220,6 +221,33 @@
compress: true # 鏄惁鍘嬬缉鍥剧墖
need-compress-size: 10MB # 瑙﹀彂鍘嬬缉鐨勬枃浠跺ぇ灏忛槇鍊�
compress-quality: 0.5 # 鍘嬬缉璐ㄩ噺(0.0-1.0)
+ qcreport: # 鏅鸿兘璐ㄦ鎶ュ憡
+ pdf: # PDF 鍑轰欢锛氭湇鍔$璋� Chromium 鎶婃姤鍛� HTML 鎵撳嵃鎴� PDF
+ # 閮ㄧ讲鍓嶇疆锛圠inux 鏈嶅姟鍣級锛�
+ # 1) 娴忚鍣細鏈」 channel 榛樿 chrome锛岄渶瑕佹湇鍔″櫒涓婅浜� Chrome锛涙病瑁呭氨鏀规垚 '' 骞舵墽琛�
+ # playwright install chromium 鐢ㄨ嚜甯︾殑 Chromium锛屾垨鎶� executable-path 鎸囧悜鏈嶅姟鍣ㄤ笂鐨勬祻瑙堝櫒
+ # 2) 涓枃瀛椾綋锛氭姤鍛婃鏂囨槸涓枃锛屾湇鍔″櫒缂� CJK 瀛椾綋浼氭墦鎴愭柟妗嗭紝闇�瑁� fonts-wqy-zenhei / Noto Sans CJK
+ # 3) 浠� root 杩愯锛欳hromium 闇�瑕� --no-sandbox锛屽姞鍒� browser-args 閲�
+ enabled: true # 鍏虫帀鍚庡鍑烘帴鍙d細鏄庣‘鎶ャ�屾湭鍚敤銆嶏紝鑰屼笉鏄姏 500
+ channel: chrome # 娴忚鍣ㄩ�氶亾锛涚暀绌� = Playwright 鑷甫 Chromium锛堥渶鍏� playwright install chromium锛�
+ executable-path: '' # 娴忚鍣ㄥ彲鎵ц鏂囦欢璺緞锛岄厤浜嗗氨浼樺厛浜� channel
+ concurrency: 2 # 鍚屾椂杩涜鐨� PDF 娓叉煋涓婇檺锛孋hromium 寰堝悆鍐呭瓨锛屼笉瑕佹斁寮�
+ timeout-ms: 30000 # 鍗曟娓叉煋瓒呮椂锛堟绉掞級锛屽悓鏃朵篃鏄帓闃熺瓑骞跺彂鍚嶉鐨勪笂闄�
+ show-page-number: true # 椤佃剼鎵撳嵃銆岀 N 椤� / 鍏� M 椤点��
+ browser-args: [ ] # 棰濆鐨勬祻瑙堝櫒鍚姩鍙傛暟锛屽 Linux 浠� root 杩愯闇�鍔� --no-sandbox
+ ai-import: # AI 瀵煎叆锛氫笂浼犳棦鏈夋姤鍛婃枃浠讹紝璇嗗埆鎴愭ā鏉胯崏绋�
+ # 閮ㄧ讲鍓嶇疆锛氬簲鐢ㄦ湇鍔″櫒闇�鑳藉嚭缃戣闂� DashScope锛堥�氫箟鍗冮棶锛夈�傚唴缃戦儴缃茶鎶� enabled 缃� false锛�
+ # 鎺ュ彛浼氭槑纭姤銆屾湭鍚敤銆嶈�屼笉鏄竴鐩寸瓑鍒� AI 瓒呮椂銆傛澶栬繕闇�鍦ㄣ�孉I 澶фā鍨嬨�嶉噷閰嶅ソ瀵硅瘽妯″瀷涓庡瘑閽ャ��
+ enabled: true
+ max-files: 3 # 涓�娆℃渶澶氬嚑涓枃浠�
+ max-pages-per-file: 5 # 鍗曟枃浠堕〉鏁颁笂闄愶紝瓒呭嚭鎶ラ敊鑰屼笉鏄潤榛樻埅鏂�
+ max-pages-per-request: 8 # 涓�娆¤姹傜疮璁¢〉鏁颁笂闄愶紙澶氭枃浠跺彔鍔犲悗鐨勬�婚椄锛�
+ max-duration-seconds: 180 # 涓�娆″鍏ユ�昏�楁椂涓婇檺锛堜袱娆¤皟鐢ㄤ箣闂存鏌ワ級锛涘墠绔秴鏃堕』姣斿畠鍔犱笂 yudao.ai.timeout 鏇村
+ max-file-size-mb: 20 # 鍗曟枃浠跺ぇ灏忎笂闄�
+ max-components: 200 # 璇嗗埆鍑虹殑缁勪欢鎬绘暟涓婇檺锛岃秴鍑烘埅鏂苟鍦ㄦ彁绀洪噷璇存槑
+ pdf-text-page-threshold: 30 # 骞冲潎姣忛〉瀛楃鏁颁綆浜庢鍊煎嵆鎸夋壂鎻忎欢閫愰〉杞浘璇嗗埆
+ render-dpi: 200 # 鎵弿椤佃浆鍥剧殑 DPI锛屼綆浜� 200 涓枃瀛楀舰浼氱硦
+ max-xlsx-rows: 300 # Excel 鍗曡〃鏈�澶氳鍙栫殑琛屾暟
database-backup: # 鏁版嵁搴撳浠介厤缃�
host: 172.17.0.1 # 澶囦唤鐩爣 MySQL 涓绘満锛岀暀绌鸿嚜鍔ㄤ粠鏁版嵁婧� JDBC URL 瑙f瀽
port: 11101 # 澶囦唤鐩爣 MySQL 绔彛锛岀暀绌鸿嚜鍔ㄤ粠鏁版嵁婧� JDBC URL 瑙f瀽
--
Gitblit v1.9.3