From a217dbfc7378ff9cf5b6d3ca8b229a2b9d932e51 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期二, 02 六月 2026 11:52:19 +0800
Subject: [PATCH] feat(device): 添加设备保养验收功能和年度定时任务支持
---
src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java | 22
src/main/resources/mapper/device/DeviceMaintenanceMapper.xml | 6
src/main/java/com/ruoyi/device/dto/DeviceMaintenanceDto.java | 2
src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskScheduleUtils.java | 26
src/main/java/com/ruoyi/device/dto/DeviceRepairDto.java | 3
pom.xml | 7
src/main/java/com/ruoyi/device/controller/MaintenanceTaskController.java | 7
docs/maintenance_task_api.md | 317 +++++++++
src/main/resources/static/伟龙模版.doc | 0
src/main/java/com/ruoyi/device/service/MaintenanceTaskService.java | 2
doc/20260602_device_maintenance_acceptance.sql | 9
src/main/java/com/ruoyi/device/service/impl/DeviceMaintenanceServiceImpl.java | 63 +
classpath.txt | 1
src/main/resources/static/百事模版.doc | 0
doc/前端联调文档-设备保养验收人功能.md | 232 +++++++
src/main/java/com/ruoyi/device/controller/DeviceMaintenanceController.java | 10
src/main/java/com/ruoyi/quality/utils/QualityInspectTemplateExportHelper.java | 489 ++++++++++++++
src/main/java/com/ruoyi/device/service/IDeviceMaintenanceService.java | 4
src/main/resources/static/达利模版.doc | 0
doc/前端联调文档-设备报修验收审批功能.md | 361 ++++++++++
src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java | 11
src/main/java/com/ruoyi/quality/service/IQualityInspectService.java | 11
src/main/java/com/ruoyi/device/pojo/MaintenanceTask.java | 3
src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskScheduler.java | 18
src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskServiceImpl.java | 43 +
src/main/java/com/ruoyi/quality/controller/QualityInspectController.java | 31
doc/前端联调文档-过程检验模板导出功能.md | 275 ++++++++
src/main/java/com/ruoyi/device/pojo/DeviceMaintenance.java | 13
28 files changed, 1,958 insertions(+), 8 deletions(-)
diff --git a/classpath.txt b/classpath.txt
new file mode 100644
index 0000000..cd566cb
--- /dev/null
+++ b/classpath.txt
@@ -0,0 +1 @@
+D:\Maven3.6.3\myRepository\com\github\xiaoymin\knife4j-openapi3-jakarta-spring-boot-starter\4.5.0\knife4j-openapi3-jakarta-spring-boot-starter-4.5.0.jar;D:\Maven3.6.3\myRepository\com\github\xiaoymin\knife4j-core\4.5.0\knife4j-core-4.5.0.jar;D:\Maven3.6.3\myRepository\com\github\xiaoymin\knife4j-openapi3-ui\4.5.0\knife4j-openapi3-ui-4.5.0.jar;D:\Maven3.6.3\myRepository\org\springdoc\springdoc-openapi-starter-webmvc-ui\2.8.17\springdoc-openapi-starter-webmvc-ui-2.8.17.jar;D:\Maven3.6.3\myRepository\org\springdoc\springdoc-openapi-starter-webmvc-api\2.8.17\springdoc-openapi-starter-webmvc-api-2.8.17.jar;D:\Maven3.6.3\myRepository\org\springdoc\springdoc-openapi-starter-common\2.8.17\springdoc-openapi-starter-common-2.8.17.jar;D:\Maven3.6.3\myRepository\io\swagger\core\v3\swagger-core-jakarta\2.2.47\swagger-core-jakarta-2.2.47.jar;D:\Maven3.6.3\myRepository\io\swagger\core\v3\swagger-annotations-jakarta\2.2.47\swagger-annotations-jakarta-2.2.47.jar;D:\Maven3.6.3\myRepository\io\swagger\core\v3\swagger-models-jakarta\2.2.47\swagger-models-jakarta-2.2.47.jar;D:\Maven3.6.3\myRepository\com\fasterxml\jackson\dataformat\jackson-dataformat-yaml\2.18.3\jackson-dataformat-yaml-2.18.3.jar;D:\Maven3.6.3\myRepository\org\webjars\swagger-ui\5.32.2\swagger-ui-5.32.2.jar;D:\Maven3.6.3\myRepository\org\webjars\webjars-locator-lite\1.1.3\webjars-locator-lite-1.1.3.jar;D:\Maven3.6.3\myRepository\org\jspecify\jspecify\1.0.0\jspecify-1.0.0.jar;D:\Maven3.6.3\myRepository\org\springframework\boot\spring-boot-starter\3.5.13\spring-boot-starter-3.5.13.jar;D:\Maven3.6.3\myRepository\org\springframework\boot\spring-boot\3.5.13\spring-boot-3.5.13.jar;D:\Maven3.6.3\myRepository\org\springframework\boot\spring-boot-autoconfigure\3.5.13\spring-boot-autoconfigure-3.5.13.jar;D:\Maven3.6.3\myRepository\org\springframework\boot\spring-boot-starter-logging\3.5.13\spring-boot-starter-logging-3.5.13.jar;D:\Maven3.6.3\myRepository\org\apache\logging\log4j\log4j-to-slf4j\2.24.3\log4j-to-slf4j-2.24.3.jar;D:\Maven3.6.3\myRepository\org\slf4j\jul-to-slf4j\2.0.17\jul-to-slf4j-2.0.17.jar;D:\Maven3.6.3\myRepository\jakarta\annotation\jakarta.annotation-api\2.1.1\jakarta.annotation-api-2.1.1.jar;D:\Maven3.6.3\myRepository\org\springframework\spring-core\6.2.17\spring-core-6.2.17.jar;D:\Maven3.6.3\myRepository\org\springframework\spring-jcl\6.2.17\spring-jcl-6.2.17.jar;D:\Maven3.6.3\myRepository\org\yaml\snakeyaml\2.4\snakeyaml-2.4.jar;D:\Maven3.6.3\myRepository\org\springframework\boot\spring-boot-starter-aop\3.5.13\spring-boot-starter-aop-3.5.13.jar;D:\Maven3.6.3\myRepository\org\springframework\spring-aop\6.2.17\spring-aop-6.2.17.jar;D:\Maven3.6.3\myRepository\org\aspectj\aspectjweaver\1.9.25.1\aspectjweaver-1.9.25.1.jar;D:\Maven3.6.3\myRepository\org\springframework\boot\spring-boot-starter-web\3.5.13\spring-boot-starter-web-3.5.13.jar;D:\Maven3.6.3\myRepository\org\springframework\boot\spring-boot-starter-json\3.5.13\spring-boot-starter-json-3.5.13.jar;D:\Maven3.6.3\myRepository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.18.3\jackson-datatype-jdk8-2.18.3.jar;D:\Maven3.6.3\myRepository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.18.3\jackson-module-parameter-names-2.18.3.jar;D:\Maven3.6.3\myRepository\org\springframework\boot\spring-boot-starter-tomcat\3.5.13\spring-boot-starter-tomcat-3.5.13.jar;D:\Maven3.6.3\myRepository\org\apache\tomcat\embed\tomcat-embed-core\10.1.53\tomcat-embed-core-10.1.53.jar;D:\Maven3.6.3\myRepository\org\apache\tomcat\embed\tomcat-embed-websocket\10.1.53\tomcat-embed-websocket-10.1.53.jar;D:\Maven3.6.3\myRepository\org\springframework\spring-web\6.2.17\spring-web-6.2.17.jar;D:\Maven3.6.3\myRepository\io\micrometer\micrometer-observation\1.15.10\micrometer-observation-1.15.10.jar;D:\Maven3.6.3\myRepository\io\micrometer\micrometer-commons\1.15.10\micrometer-commons-1.15.10.jar;D:\Maven3.6.3\myRepository\org\springframework\spring-webmvc\6.2.17\spring-webmvc-6.2.17.jar;D:\Maven3.6.3\myRepository\org\springframework\spring-expression\6.2.17\spring-expression-6.2.17.jar;D:\Maven3.6.3\myRepository\org\springframework\boot\spring-boot-devtools\3.5.13\spring-boot-devtools-3.5.13.jar;D:\Maven3.6.3\myRepository\org\springframework\boot\spring-boot-starter-security\3.5.13\spring-boot-starter-security-3.5.13.jar;D:\Maven3.6.3\myRepository\org\springframework\security\spring-security-config\6.5.9\spring-security-config-6.5.9.jar;D:\Maven3.6.3\myRepository\org\springframework\security\spring-security-core\6.5.9\spring-security-core-6.5.9.jar;D:\Maven3.6.3\myRepository\org\springframework\security\spring-security-crypto\6.5.9\spring-security-crypto-6.5.9.jar;D:\Maven3.6.3\myRepository\org\springframework\security\spring-security-web\6.5.9\spring-security-web-6.5.9.jar;D:\Maven3.6.3\myRepository\org\springframework\boot\spring-boot-starter-data-redis\3.5.13\spring-boot-starter-data-redis-3.5.13.jar;D:\Maven3.6.3\myRepository\io\lettuce\lettuce-core\6.6.0.RELEASE\lettuce-core-6.6.0.RELEASE.jar;D:\Maven3.6.3\myRepository\redis\clients\authentication\redis-authx-core\0.1.1-beta2\redis-authx-core-0.1.1-beta2.jar;D:\Maven3.6.3\myRepository\io\netty\netty-common\4.1.119.Final\netty-common-4.1.119.Final.jar;D:\Maven3.6.3\myRepository\io\netty\netty-handler\4.1.119.Final\netty-handler-4.1.119.Final.jar;D:\Maven3.6.3\myRepository\io\netty\netty-resolver\4.1.119.Final\netty-resolver-4.1.119.Final.jar;D:\Maven3.6.3\myRepository\io\netty\netty-buffer\4.1.119.Final\netty-buffer-4.1.119.Final.jar;D:\Maven3.6.3\myRepository\io\netty\netty-transport-native-unix-common\4.1.119.Final\netty-transport-native-unix-common-4.1.119.Final.jar;D:\Maven3.6.3\myRepository\io\netty\netty-codec\4.1.119.Final\netty-codec-4.1.119.Final.jar;D:\Maven3.6.3\myRepository\io\netty\netty-transport\4.1.119.Final\netty-transport-4.1.119.Final.jar;D:\Maven3.6.3\myRepository\org\springframework\data\spring-data-redis\3.5.10\spring-data-redis-3.5.10.jar;D:\Maven3.6.3\myRepository\org\springframework\data\spring-data-keyvalue\3.5.10\spring-data-keyvalue-3.5.10.jar;D:\Maven3.6.3\myRepository\org\springframework\spring-tx\6.2.17\spring-tx-6.2.17.jar;D:\Maven3.6.3\myRepository\org\springframework\spring-oxm\6.2.17\spring-oxm-6.2.17.jar;D:\Maven3.6.3\myRepository\org\springframework\boot\spring-boot-starter-data-mongodb\3.5.13\spring-boot-starter-data-mongodb-3.5.13.jar;D:\Maven3.6.3\myRepository\org\mongodb\mongodb-driver-sync\5.5.2\mongodb-driver-sync-5.5.2.jar;D:\Maven3.6.3\myRepository\org\mongodb\bson\5.5.2\bson-5.5.2.jar;D:\Maven3.6.3\myRepository\org\mongodb\mongodb-driver-core\5.5.2\mongodb-driver-core-5.5.2.jar;D:\Maven3.6.3\myRepository\org\springframework\data\spring-data-mongodb\4.5.10\spring-data-mongodb-4.5.10.jar;D:\Maven3.6.3\myRepository\org\springframework\data\spring-data-commons\3.5.10\spring-data-commons-3.5.10.jar;D:\Maven3.6.3\myRepository\org\apache\commons\commons-pool2\2.12.1\commons-pool2-2.12.1.jar;D:\Maven3.6.3\myRepository\dev\langchain4j\langchain4j-spring-boot-starter\1.0.0-beta3\langchain4j-spring-boot-starter-1.0.0-beta3.jar;D:\Maven3.6.3\myRepository\dev\langchain4j\langchain4j\1.0.0-beta3\langchain4j-1.0.0-beta3.jar;D:\Maven3.6.3\myRepository\org\apache\opennlp\opennlp-tools\1.9.4\opennlp-tools-1.9.4.jar;D:\Maven3.6.3\myRepository\dev\langchain4j\langchain4j-pinecone\1.0.0-beta3\langchain4j-pinecone-1.0.0-beta3.jar;D:\Maven3.6.3\myRepository\dev\langchain4j\langchain4j-core\1.0.0-beta3\langchain4j-core-1.0.0-beta3.jar;D:\Maven3.6.3\myRepository\io\pinecone\pinecone-client\3.1.0\pinecone-client-3.1.0.jar;D:\Maven3.6.3\myRepository\io\grpc\grpc-protobuf\1.60.2\grpc-protobuf-1.60.2.jar;D:\Maven3.6.3\myRepository\io\grpc\grpc-api\1.60.2\grpc-api-1.60.2.jar;D:\Maven3.6.3\myRepository\io\grpc\grpc-protobuf-lite\1.60.2\grpc-protobuf-lite-1.60.2.jar;D:\Maven3.6.3\myRepository\io\grpc\grpc-stub\1.60.2\grpc-stub-1.60.2.jar;D:\Maven3.6.3\myRepository\io\grpc\grpc-netty\1.60.2\grpc-netty-1.60.2.jar;D:\Maven3.6.3\myRepository\io\grpc\grpc-core\1.60.2\grpc-core-1.60.2.jar;D:\Maven3.6.3\myRepository\io\netty\netty-codec-http2\4.1.119.Final\netty-codec-http2-4.1.119.Final.jar;D:\Maven3.6.3\myRepository\io\netty\netty-codec-http\4.1.119.Final\netty-codec-http-4.1.119.Final.jar;D:\Maven3.6.3\myRepository\com\google\api\grpc\proto-google-common-protos\2.14.3\proto-google-common-protos-2.14.3.jar;D:\Maven3.6.3\myRepository\com\squareup\okhttp3\logging-interceptor\4.12.0\logging-interceptor-4.12.0.jar;D:\Maven3.6.3\myRepository\com\google\protobuf\protobuf-java\3.25.2\protobuf-java-3.25.2.jar;D:\Maven3.6.3\myRepository\dev\langchain4j\langchain4j-open-ai-spring-boot-starter\1.0.0-beta3\langchain4j-open-ai-spring-boot-starter-1.0.0-beta3.jar;D:\Maven3.6.3\myRepository\dev\langchain4j\langchain4j-open-ai\1.0.0-beta3\langchain4j-open-ai-1.0.0-beta3.jar;D:\Maven3.6.3\myRepository\com\knuddels\jtokkit\1.1.0\jtokkit-1.1.0.jar;D:\Maven3.6.3\myRepository\dev\langchain4j\langchain4j-http-client-spring-restclient\1.0.0-beta3\langchain4j-http-client-spring-restclient-1.0.0-beta3.jar;D:\Maven3.6.3\myRepository\dev\langchain4j\langchain4j-http-client\1.0.0-beta3\langchain4j-http-client-1.0.0-beta3.jar;D:\Maven3.6.3\myRepository\dev\langchain4j\langchain4j-reactor\1.0.0-beta3\langchain4j-reactor-1.0.0-beta3.jar;D:\Maven3.6.3\myRepository\io\projectreactor\reactor-core\3.7.3\reactor-core-3.7.3.jar;D:\Maven3.6.3\myRepository\org\reactivestreams\reactive-streams\1.0.4\reactive-streams-1.0.4.jar;D:\Maven3.6.3\myRepository\dev\langchain4j\langchain4j-ollama-spring-boot-starter\1.0.0-beta3\langchain4j-ollama-spring-boot-starter-1.0.0-beta3.jar;D:\Maven3.6.3\myRepository\dev\langchain4j\langchain4j-ollama\1.0.0-beta3\langchain4j-ollama-1.0.0-beta3.jar;D:\Maven3.6.3\myRepository\dev\langchain4j\langchain4j-community-dashscope-spring-boot-starter\1.0.0-beta3\langchain4j-community-dashscope-spring-boot-starter-1.0.0-beta3.jar;D:\Maven3.6.3\myRepository\dev\langchain4j\langchain4j-community-dashscope\1.0.0-beta3\langchain4j-community-dashscope-1.0.0-beta3.jar;D:\Maven3.6.3\myRepository\com\alibaba\dashscope-sdk-java\2.18.5\dashscope-sdk-java-2.18.5.jar;D:\Maven3.6.3\myRepository\io\reactivex\rxjava2\rxjava\2.2.21\rxjava-2.2.21.jar;D:\Maven3.6.3\myRepository\com\github\victools\jsonschema-generator\4.31.1\jsonschema-generator-4.31.1.jar;D:\Maven3.6.3\myRepository\ch\qos\logback\logback-classic\1.5.32\logback-classic-1.5.32.jar;D:\Maven3.6.3\myRepository\ch\qos\logback\logback-core\1.5.32\logback-core-1.5.32.jar;D:\Maven3.6.3\myRepository\dev\langchain4j\langchain4j-mcp\1.0.0-beta3\langchain4j-mcp-1.0.0-beta3.jar;D:\Maven3.6.3\myRepository\com\fasterxml\jackson\core\jackson-databind\2.18.3\jackson-databind-2.18.3.jar;D:\Maven3.6.3\myRepository\com\squareup\okhttp3\okhttp-sse\4.12.0\okhttp-sse-4.12.0.jar;D:\Maven3.6.3\myRepository\org\jetbrains\kotlin\kotlin-stdlib-jdk8\1.9.25\kotlin-stdlib-jdk8-1.9.25.jar;D:\Maven3.6.3\myRepository\org\jetbrains\kotlin\kotlin-stdlib-jdk7\1.9.25\kotlin-stdlib-jdk7-1.9.25.jar;D:\Maven3.6.3\myRepository\org\freemarker\freemarker\2.3.33\freemarker-2.3.33.jar;D:\Maven3.6.3\myRepository\com\github\pagehelper\pagehelper-spring-boot-starter\2.1.1\pagehelper-spring-boot-starter-2.1.1.jar;D:\Maven3.6.3\myRepository\org\mybatis\spring\boot\mybatis-spring-boot-starter\2.3.2\mybatis-spring-boot-starter-2.3.2.jar;D:\Maven3.6.3\myRepository\org\mybatis\spring\boot\mybatis-spring-boot-autoconfigure\2.3.2\mybatis-spring-boot-autoconfigure-2.3.2.jar;D:\Maven3.6.3\myRepository\com\github\pagehelper\pagehelper-spring-boot-autoconfigure\2.1.1\pagehelper-spring-boot-autoconfigure-2.1.1.jar;D:\Maven3.6.3\myRepository\com\github\pagehelper\pagehelper\6.1.1\pagehelper-6.1.1.jar;D:\Maven3.6.3\myRepository\com\alibaba\druid-spring-boot-3-starter\1.2.23\druid-spring-boot-3-starter-1.2.23.jar;D:\Maven3.6.3\myRepository\com\alibaba\druid\1.2.23\druid-1.2.23.jar;D:\Maven3.6.3\myRepository\org\slf4j\slf4j-api\2.0.17\slf4j-api-2.0.17.jar;D:\Maven3.6.3\myRepository\org\mybatis\mybatis\3.5.16\mybatis-3.5.16.jar;D:\Maven3.6.3\myRepository\com\baomidou\mybatis-plus-spring-boot3-starter\3.5.16\mybatis-plus-spring-boot3-starter-3.5.16.jar;D:\Maven3.6.3\myRepository\com\baomidou\mybatis-plus\3.5.16\mybatis-plus-3.5.16.jar;D:\Maven3.6.3\myRepository\com\baomidou\mybatis-plus-core\3.5.16\mybatis-plus-core-3.5.16.jar;D:\Maven3.6.3\myRepository\com\baomidou\mybatis-plus-annotation\3.5.16\mybatis-plus-annotation-3.5.16.jar;D:\Maven3.6.3\myRepository\com\baomidou\mybatis-plus-spring\3.5.16\mybatis-plus-spring-3.5.16.jar;D:\Maven3.6.3\myRepository\org\mybatis\mybatis-spring\3.0.5\mybatis-spring-3.0.5.jar;D:\Maven3.6.3\myRepository\com\baomidou\mybatis-plus-spring-boot-autoconfigure\3.5.16\mybatis-plus-spring-boot-autoconfigure-3.5.16.jar;D:\Maven3.6.3\myRepository\org\springframework\boot\spring-boot-starter-jdbc\3.5.13\spring-boot-starter-jdbc-3.5.13.jar;D:\Maven3.6.3\myRepository\com\zaxxer\HikariCP\6.3.3\HikariCP-6.3.3.jar;D:\Maven3.6.3\myRepository\org\springframework\spring-jdbc\6.2.17\spring-jdbc-6.2.17.jar;D:\Maven3.6.3\myRepository\com\baomidou\mybatis-plus-jsqlparser\3.5.16\mybatis-plus-jsqlparser-3.5.16.jar;D:\Maven3.6.3\myRepository\com\baomidou\mybatis-plus-jsqlparser-common\3.5.16\mybatis-plus-jsqlparser-common-3.5.16.jar;D:\Maven3.6.3\myRepository\com\baomidou\mybatis-plus-extension\3.5.16\mybatis-plus-extension-3.5.16.jar;D:\Maven3.6.3\myRepository\com\baomidou\mybatis-plus-generator\3.5.16\mybatis-plus-generator-3.5.16.jar;D:\Maven3.6.3\myRepository\com\github\jsqlparser\jsqlparser\4.9\jsqlparser-4.9.jar;D:\Maven3.6.3\myRepository\org\springframework\boot\spring-boot-starter-validation\3.5.13\spring-boot-starter-validation-3.5.13.jar;D:\Maven3.6.3\myRepository\org\apache\tomcat\embed\tomcat-embed-el\10.1.53\tomcat-embed-el-10.1.53.jar;D:\Maven3.6.3\myRepository\org\hibernate\validator\hibernate-validator\8.0.3.Final\hibernate-validator-8.0.3.Final.jar;D:\Maven3.6.3\myRepository\jakarta\validation\jakarta.validation-api\3.0.2\jakarta.validation-api-3.0.2.jar;D:\Maven3.6.3\myRepository\org\jboss\logging\jboss-logging\3.6.3.Final\jboss-logging-3.6.3.Final.jar;D:\Maven3.6.3\myRepository\com\fasterxml\classmate\1.7.3\classmate-1.7.3.jar;D:\Maven3.6.3\myRepository\org\apache\commons\commons-lang3\3.17.0\commons-lang3-3.17.0.jar;D:\Maven3.6.3\myRepository\commons-io\commons-io\2.13.0\commons-io-2.13.0.jar;D:\Maven3.6.3\myRepository\eu\bitwalker\UserAgentUtils\1.21\UserAgentUtils-1.21.jar;D:\Maven3.6.3\myRepository\com\alibaba\fastjson2\fastjson2\2.0.53\fastjson2-2.0.53.jar;D:\Maven3.6.3\myRepository\org\springframework\spring-context-support\6.2.17\spring-context-support-6.2.17.jar;D:\Maven3.6.3\myRepository\org\springframework\spring-beans\6.2.17\spring-beans-6.2.17.jar;D:\Maven3.6.3\myRepository\org\springframework\spring-context\6.2.17\spring-context-6.2.17.jar;D:\Maven3.6.3\myRepository\io\jsonwebtoken\jjwt-api\0.13.0\jjwt-api-0.13.0.jar;D:\Maven3.6.3\myRepository\jakarta\xml\bind\jakarta.xml.bind-api\4.0.4\jakarta.xml.bind-api-4.0.4.jar;D:\Maven3.6.3\myRepository\jakarta\activation\jakarta.activation-api\2.1.4\jakarta.activation-api-2.1.4.jar;D:\Maven3.6.3\myRepository\io\swagger\swagger-annotations\1.6.15\swagger-annotations-1.6.15.jar;D:\Maven3.6.3\myRepository\com\github\oshi\oshi-core\6.6.5\oshi-core-6.6.5.jar;D:\Maven3.6.3\myRepository\net\java\dev\jna\jna\5.15.0\jna-5.15.0.jar;D:\Maven3.6.3\myRepository\net\java\dev\jna\jna-platform\5.15.0\jna-platform-5.15.0.jar;D:\Maven3.6.3\myRepository\org\apache\poi\poi-ooxml\5.2.3\poi-ooxml-5.2.3.jar;D:\Maven3.6.3\myRepository\org\apache\poi\poi\5.2.3\poi-5.2.3.jar;D:\Maven3.6.3\myRepository\commons-codec\commons-codec\1.18.0\commons-codec-1.18.0.jar;D:\Maven3.6.3\myRepository\org\apache\commons\commons-math3\3.6.1\commons-math3-3.6.1.jar;D:\Maven3.6.3\myRepository\com\zaxxer\SparseBitSet\1.2\SparseBitSet-1.2.jar;D:\Maven3.6.3\myRepository\org\apache\poi\poi-ooxml-lite\5.2.3\poi-ooxml-lite-5.2.3.jar;D:\Maven3.6.3\myRepository\org\apache\xmlbeans\xmlbeans\5.1.1\xmlbeans-5.1.1.jar;D:\Maven3.6.3\myRepository\org\apache\commons\commons-compress\1.21\commons-compress-1.21.jar;D:\Maven3.6.3\myRepository\com\github\virtuald\curvesapi\1.07\curvesapi-1.07.jar;D:\Maven3.6.3\myRepository\org\apache\logging\log4j\log4j-api\2.24.3\log4j-api-2.24.3.jar;D:\Maven3.6.3\myRepository\org\apache\commons\commons-collections4\4.4\commons-collections4-4.4.jar;D:\Maven3.6.3\myRepository\org\apache\velocity\velocity-engine-core\2.3\velocity-engine-core-2.3.jar;D:\Maven3.6.3\myRepository\org\quartz-scheduler\quartz\2.5.2\quartz-2.5.2.jar;D:\Maven3.6.3\myRepository\pro\fessional\kaptcha\2.3.3\kaptcha-2.3.3.jar;D:\Maven3.6.3\myRepository\com\jhlabs\filters\2.0.235-1\filters-2.0.235-1.jar;D:\Maven3.6.3\myRepository\org\projectlombok\lombok\1.18.44\lombok-1.18.44.jar;D:\Maven3.6.3\myRepository\io\minio\minio\8.4.3\minio-8.4.3.jar;D:\Maven3.6.3\myRepository\com\carrotsearch\thirdparty\simple-xml-safe\2.7.1\simple-xml-safe-2.7.1.jar;D:\Maven3.6.3\myRepository\com\google\guava\guava\30.1.1-jre\guava-30.1.1-jre.jar;D:\Maven3.6.3\myRepository\com\google\guava\failureaccess\1.0.1\failureaccess-1.0.1.jar;D:\Maven3.6.3\myRepository\com\google\guava\listenablefuture\9999.0-empty-to-avoid-conflict-with-guava\listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar;D:\Maven3.6.3\myRepository\com\google\code\findbugs\jsr305\3.0.2\jsr305-3.0.2.jar;D:\Maven3.6.3\myRepository\org\checkerframework\checker-qual\3.8.0\checker-qual-3.8.0.jar;D:\Maven3.6.3\myRepository\com\google\errorprone\error_prone_annotations\2.5.1\error_prone_annotations-2.5.1.jar;D:\Maven3.6.3\myRepository\com\google\j2objc\j2objc-annotations\1.3\j2objc-annotations-1.3.jar;D:\Maven3.6.3\myRepository\com\fasterxml\jackson\core\jackson-annotations\2.18.3\jackson-annotations-2.18.3.jar;D:\Maven3.6.3\myRepository\com\fasterxml\jackson\core\jackson-core\2.18.3\jackson-core-2.18.3.jar;D:\Maven3.6.3\myRepository\org\bouncycastle\bcprov-jdk15on\1.69\bcprov-jdk15on-1.69.jar;D:\Maven3.6.3\myRepository\org\xerial\snappy\snappy-java\1.1.8.4\snappy-java-1.1.8.4.jar;D:\Maven3.6.3\myRepository\com\squareup\okhttp3\okhttp\4.9.0\okhttp-4.9.0.jar;D:\Maven3.6.3\myRepository\com\squareup\okio\okio\2.8.0\okio-2.8.0.jar;D:\Maven3.6.3\myRepository\org\jetbrains\kotlin\kotlin-stdlib-common\1.9.25\kotlin-stdlib-common-1.9.25.jar;D:\Maven3.6.3\myRepository\org\jetbrains\kotlin\kotlin-stdlib\1.9.25\kotlin-stdlib-1.9.25.jar;D:\Maven3.6.3\myRepository\org\jetbrains\annotations\13.0\annotations-13.0.jar;D:\Maven3.6.3\myRepository\com\deepoove\poi-tl\1.12.2\poi-tl-1.12.2.jar;D:\Maven3.6.3\myRepository\org\apache\xmlgraphics\batik-transcoder\1.17\batik-transcoder-1.17.jar;D:\Maven3.6.3\myRepository\org\apache\xmlgraphics\batik-anim\1.17\batik-anim-1.17.jar;D:\Maven3.6.3\myRepository\org\apache\xmlgraphics\batik-css\1.17\batik-css-1.17.jar;D:\Maven3.6.3\myRepository\org\apache\xmlgraphics\batik-ext\1.17\batik-ext-1.17.jar;D:\Maven3.6.3\myRepository\org\apache\xmlgraphics\batik-parser\1.17\batik-parser-1.17.jar;D:\Maven3.6.3\myRepository\org\apache\xmlgraphics\batik-svg-dom\1.17\batik-svg-dom-1.17.jar;D:\Maven3.6.3\myRepository\org\apache\xmlgraphics\batik-awt-util\1.17\batik-awt-util-1.17.jar;D:\Maven3.6.3\myRepository\org\apache\xmlgraphics\xmlgraphics-commons\2.9\xmlgraphics-commons-2.9.jar;D:\Maven3.6.3\myRepository\org\apache\xmlgraphics\batik-bridge\1.17\batik-bridge-1.17.jar;D:\Maven3.6.3\myRepository\org\apache\xmlgraphics\batik-script\1.17\batik-script-1.17.jar;D:\Maven3.6.3\myRepository\org\apache\xmlgraphics\batik-dom\1.17\batik-dom-1.17.jar;D:\Maven3.6.3\myRepository\xml-apis\xml-apis\1.4.01\xml-apis-1.4.01.jar;D:\Maven3.6.3\myRepository\org\apache\xmlgraphics\batik-gvt\1.17\batik-gvt-1.17.jar;D:\Maven3.6.3\myRepository\org\apache\xmlgraphics\batik-shared-resources\1.17\batik-shared-resources-1.17.jar;D:\Maven3.6.3\myRepository\org\apache\xmlgraphics\batik-svggen\1.17\batik-svggen-1.17.jar;D:\Maven3.6.3\myRepository\org\apache\xmlgraphics\batik-util\1.17\batik-util-1.17.jar;D:\Maven3.6.3\myRepository\org\apache\xmlgraphics\batik-constants\1.17\batik-constants-1.17.jar;D:\Maven3.6.3\myRepository\org\apache\xmlgraphics\batik-i18n\1.17\batik-i18n-1.17.jar;D:\Maven3.6.3\myRepository\org\apache\xmlgraphics\batik-xml\1.17\batik-xml-1.17.jar;D:\Maven3.6.3\myRepository\xml-apis\xml-apis-ext\1.3.04\xml-apis-ext-1.3.04.jar;D:\Maven3.6.3\myRepository\org\apache\xmlgraphics\batik-codec\1.17\batik-codec-1.17.jar;D:\Maven3.6.3\myRepository\com\alibaba\easyexcel\4.0.3\easyexcel-4.0.3.jar;D:\Maven3.6.3\myRepository\com\alibaba\easyexcel-core\4.0.3\easyexcel-core-4.0.3.jar;D:\Maven3.6.3\myRepository\com\alibaba\easyexcel-support\3.3.4\easyexcel-support-3.3.4.jar;D:\Maven3.6.3\myRepository\org\apache\commons\commons-csv\1.11.0\commons-csv-1.11.0.jar;D:\Maven3.6.3\myRepository\org\ehcache\ehcache\3.10.9\ehcache-3.10.9.jar;D:\Maven3.6.3\myRepository\javax\cache\cache-api\1.1.1\cache-api-1.1.1.jar;D:\Maven3.6.3\myRepository\com\google\zxing\core\3.3.3\core-3.3.3.jar;D:\Maven3.6.3\myRepository\com\getui\push\restful-sdk\1.0.7.0\restful-sdk-1.0.7.0.jar;D:\Maven3.6.3\myRepository\org\apache\httpcomponents\httpclient\4.5.13\httpclient-4.5.13.jar;D:\Maven3.6.3\myRepository\org\apache\httpcomponents\httpcore\4.4.16\httpcore-4.4.16.jar;D:\Maven3.6.3\myRepository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;D:\Maven3.6.3\myRepository\com\google\code\gson\gson\2.13.2\gson-2.13.2.jar;D:\Maven3.6.3\myRepository\cn\hutool\hutool-all\5.8.43\hutool-all-5.8.43.jar;D:\Maven3.6.3\myRepository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.18.3\jackson-datatype-jsr310-2.18.3.jar;D:\Maven3.6.3\myRepository\net\coobird\thumbnailator\0.4.20\thumbnailator-0.4.20.jar
\ No newline at end of file
diff --git a/doc/20260602_device_maintenance_acceptance.sql b/doc/20260602_device_maintenance_acceptance.sql
new file mode 100644
index 0000000..24ccd4e
--- /dev/null
+++ b/doc/20260602_device_maintenance_acceptance.sql
@@ -0,0 +1,9 @@
+-- 璁惧淇濆吇琛ㄦ柊澧為獙鏀朵汉鐩稿叧瀛楁
+ALTER TABLE `device_maintenance`
+ ADD COLUMN `acceptance_name` VARCHAR(100) NULL COMMENT '楠屾敹浜�' AFTER `spare_parts_ids`,
+ ADD COLUMN `acceptance_time` DATETIME NULL COMMENT '楠屾敹鏃堕棿' AFTER `acceptance_name`,
+ ADD COLUMN `acceptance_remark` VARCHAR(500) NULL COMMENT '楠屾敹澶囨敞' AFTER `acceptance_time`;
+
+-- 璁惧淇濆吇瀹氭椂浠诲姟琛ㄦ柊澧炴槸鍚﹀惎鐢ㄥ瓧娈�
+ALTER TABLE `maintenance_task`
+ ADD COLUMN `is_enabled` TINYINT(1) NULL DEFAULT 1 COMMENT '鏄惁鍚敤 0-绂佺敤 1-鍚敤' AFTER `is_active`;
\ No newline at end of file
diff --git "a/doc/\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243-\350\256\276\345\244\207\344\277\235\345\205\273\351\252\214\346\224\266\344\272\272\345\212\237\350\203\275.md" "b/doc/\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243-\350\256\276\345\244\207\344\277\235\345\205\273\351\252\214\346\224\266\344\272\272\345\212\237\350\203\275.md"
new file mode 100644
index 0000000..13f0b51
--- /dev/null
+++ "b/doc/\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243-\350\256\276\345\244\207\344\277\235\345\205\273\351\252\214\346\224\266\344\272\272\345\212\237\350\203\275.md"
@@ -0,0 +1,232 @@
+# 鍓嶇鑱旇皟鏂囨。 - 璁惧淇濆吇楠屾敹浜哄姛鑳�
+
+## 1. 鍙樻洿姒傝堪
+
+鏈鍙樻洿娑夊強璁惧淇濆吇妯″潡鏂板楠屾敹瀹℃壒娴佺▼锛屼笌璁惧鎶ヤ慨楠屾敹娴佺▼淇濇寔涓�鑷达細
+
+- 璁惧淇濆吇纭鍚庢柊澧為獙鏀跺鎵圭幆鑺�
+- 楠屾敹閫氳繃鍚庢墠绠楀畬缁�
+- 鏂板楠屾敹浜恒�侀獙鏀舵椂闂淬�侀獙鏀跺娉ㄥ瓧娈�
+
+---
+
+## 2. 鎺ュ彛娓呭崟
+
+### 2.1 璁惧淇濆吇
+
+鍩虹璺緞锛歚/device/maintenance`
+
+#### 鐘舵�佸畾涔�
+
+| 鐘舵�佸�� | 鍚箟 |
+|---|---|
+| `0` | 寰呬繚鍏� |
+| `3` | 寰呴獙鏀� |
+| `1` | 瀹岀粨 |
+| `2` | 澶辫触 |
+
+---
+
+### 2.2 纭淇濆吇锛堟柊澧烇級
+
+- **POST** `/device/maintenance/maintenance`
+- 璇存槑锛氭彁浜ゅ悗鐘舵�佷粠 `寰呬繚鍏�(0)` 杩涘叆 `寰呴獙鏀�(3)`锛屼笉鍐嶇洿鎺ュ畬缁撱��
+
+#### 璇锋眰鍙傛暟锛圔ody锛�
+
+| 瀛楁 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|---|---|---|---|
+| `id` | long | 鏄� | 淇濆吇璁板綍ID |
+| `maintenanceActuallyName` | string | 鍚� | 瀹為檯淇濆吇浜� |
+| `maintenanceActuallyTime` | string | 鍚� | 瀹為檯淇濆吇鏃堕棿锛屾牸寮� `yyyy-MM-dd HH:mm:ss` |
+| `maintenanceResult` | string | 鍚� | 淇濆吇缁撴灉 0-缁翠慨 1-瀹屽ソ |
+| `sparePartsUseList` | array | 鍚� | 浣跨敤澶囦欢鍒楄〃 |
+
+#### 璇锋眰绀轰緥
+
+```json
+{
+ "id": 10001,
+ "maintenanceActuallyName": "寮犱笁",
+ "maintenanceActuallyTime": "2026-06-02 10:30:00",
+ "maintenanceResult": "1",
+ "sparePartsUseList": [
+ {
+ "id": 501,
+ "quantity": 2
+ }
+ ]
+}
+```
+
+#### 甯歌澶辫触鎻愮ず
+
+- `淇濆吇璁板綍涓嶅瓨鍦╜
+- `璇ヤ繚鍏诲凡瀹岀粨锛屼笉鑳介噸澶嶇‘璁や繚鍏籤
+- `璇ヤ繚鍏诲凡鎻愪氦楠屾敹瀹℃壒`
+- `澶囦欢 xxx 鏁伴噺涓嶈冻`
+
+---
+
+### 2.3 楠屾敹瀹℃壒锛堟柊澧烇級
+
+- **POST** `/device/maintenance/acceptance`
+- 璇存槑锛氫粎 `寰呴獙鏀�(3)` 鍙鎵癸紱瀹℃壒閫氳繃鍚庣姸鎬佹敼涓� `瀹岀粨(1)`銆�
+
+#### 璇锋眰鍙傛暟锛圔ody锛�
+
+| 瀛楁 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|---|---|---|---|
+| `id` | long | 鏄� | 淇濆吇璁板綍ID |
+| `acceptanceName` | string | 鏄� | 楠屾敹浜� |
+| `acceptanceTime` | string | 鏄� | 楠屾敹鏃堕棿锛屾牸寮� `yyyy-MM-dd HH:mm:ss` |
+| `acceptanceRemark` | string | 鏄� | 楠屾敹澶囨敞 |
+
+#### 璇锋眰绀轰緥
+
+```json
+{
+ "id": 10001,
+ "acceptanceName": "鏉庡洓",
+ "acceptanceTime": "2026-06-02 11:00:00",
+ "acceptanceRemark": "淇濆吇椤规牳楠岄�氳繃锛岃澶囪繍琛屾甯�"
+}
+```
+
+#### 甯歌澶辫触鎻愮ず
+
+- `淇濆吇璁板綍id涓嶈兘涓虹┖`
+- `淇濆吇璁板綍涓嶅瓨鍦╜
+- `璇ヤ繚鍏绘湭杩涘叆寰呴獙鏀剁姸鎬侊紝涓嶈兘瀹℃壒`
+- `楠屾敹浜轰笉鑳戒负绌篳
+- `楠屾敹鏃堕棿涓嶈兘涓虹┖`
+- `楠屾敹澶囨敞涓嶈兘涓虹┖`
+
+---
+
+### 2.4 鏅�氭洿鏂版帴鍙i檺鍒�
+
+- **PUT** `/device/maintenance`
+- 闄愬埗锛氫笉鑳介�氳繃鏅�氭洿鏂扮洿鎺ユ妸鐘舵�佹敼鎴� `瀹岀粨(1)`锛堝繀椤昏蛋楠屾敹瀹℃壒鎺ュ彛锛夈��
+- 澶辫触鎻愮ず锛歚璇峰厛鎻愪氦楠屾敹瀹℃壒锛岄獙鏀堕�氳繃鍚庢墠鍙畬缁揱
+
+---
+
+## 3. 杩斿洖瀛楁鍙樻洿
+
+浠ヤ笅鎺ュ彛杩斿洖宸叉柊澧為獙鏀跺瓧娈碉細
+
+- **GET** `/device/maintenance/page`
+- **GET** `/device/maintenance/{id}`
+
+### 鏂板杩斿洖瀛楁
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|---|---|---|
+| `acceptanceName` | string | 楠屾敹浜� |
+| `acceptanceTime` | string | 楠屾敹鏃堕棿锛屾牸寮� `yyyy-MM-dd HH:mm:ss` |
+| `acceptanceRemark` | string | 楠屾敹澶囨敞 |
+
+---
+
+## 4. 璁惧鎶ヤ慨楠屾敹娴佺▼锛堝弬鑰冿級
+
+璁惧鎶ヤ慨妯″潡宸叉湁鐩稿悓閫昏緫锛屽彲鍙傝�冨疄鐜帮細
+
+| 鐘舵�佸�� | 鍚箟 |
+|---|---|
+| `0` | 寰呯淮淇� |
+| `3` | 寰呴獙鏀� |
+| `1` | 瀹岀粨 |
+| `2` | 澶辫触 |
+
+### 鎶ヤ慨鐩稿叧鎺ュ彛
+
+| 鎺ュ彛 | 璇存槑 |
+|---|---|
+| **POST** `/device/repair/repair` | 纭缁翠慨锛岀姸鎬� 0鈫�3 |
+| **POST** `/device/repair/acceptance` | 楠屾敹瀹℃壒锛岀姸鎬� 3鈫�1 |
+
+### 鎶ヤ慨楠屾敹璇锋眰绀轰緥
+
+```json
+{
+ "id": 10001,
+ "acceptanceName": "鐜嬩簲",
+ "acceptanceTime": "2026-05-14 11:00:00",
+ "acceptanceRemark": "缁翠慨椤规牳楠岄�氳繃锛岃澶囪繍琛屾甯�"
+}
+```
+
+---
+
+## 5. 鍓嶇鏀归�犲缓璁�
+
+### 5.1 璁惧淇濆吇椤甸潰
+
+1. 鍒楄〃澧炲姞鐘舵�佸�� `3=寰呴獙鏀禶 鐨勫睍绀烘枃妗堜笌绛涢�夐」銆�
+2. "纭淇濆吇"鎸夐挳璋冪敤 `/device/maintenance/maintenance`锛屾垚鍔熷悗鍒锋柊涓哄緟楠屾敹鐘舵�併��
+3. 鏂板"楠屾敹瀹℃壒"寮圭獥锛屽繀濉細
+ - 楠屾敹浜�
+ - 楠屾敹鏃堕棿
+ - 楠屾敹澶囨敞
+4. 绂佹鍦ㄦ櫘閫氱紪杈戦〉鐩存帴灏嗙姸鎬佺疆涓哄畬缁撱��
+
+### 5.2 璁惧鎶ヤ慨椤甸潰
+
+宸叉湁楠屾敹娴佺▼锛岀‘璁ら�昏緫涓庝繚鍏讳竴鑷达細
+- 鐘舵�佹祦杞細`0寰呯淮淇� -> 3寰呴獙鏀� -> 1瀹岀粨`
+- 楠屾敹鎺ュ彛锛歚/device/repair/acceptance`
+
+---
+
+## 6. 鑱旇皟妫�鏌ユ竻鍗�
+
+### 璁惧淇濆吇
+
+1. 淇濆吇鍗曟祦绋嬶細`0寰呬繚鍏� -> 3寰呴獙鏀� -> 1瀹岀粨`銆�
+2. 寰呴獙鏀跺崟鎹湭濉獙鏀朵汉/楠屾敹鏃堕棿/楠屾敹澶囨敞鏃讹紝鍚庣杩斿洖瀵瑰簲閿欒鎻愮ず銆�
+3. 灏濊瘯閫氳繃 `PUT /device/maintenance` 鐩存帴璁句负瀹岀粨鏃讹紝鍚庣杩斿洖鎷︽埅鎻愮ず銆�
+4. 鍒楄〃/璇︽儏鎺ュ彛鑳芥纭繑鍥� `acceptanceName`銆乣acceptanceTime`銆乣acceptanceRemark`銆�
+
+### 璁惧鎶ヤ慨
+
+1. 鎶ヤ慨鍗曟祦绋嬶細`0寰呯淮淇� -> 3寰呴獙鏀� -> 1瀹岀粨`銆�
+2. 寰呴獙鏀跺崟鎹湭濉獙鏀朵汉/楠屾敹鏃堕棿/楠屾敹澶囨敞鏃讹紝鍚庣杩斿洖瀵瑰簲閿欒鎻愮ず銆�
+3. 灏濊瘯閫氳繃 `PUT /device/repair` 鐩存帴璁句负瀹岀粨鏃讹紝鍚庣杩斿洖鎷︽埅鎻愮ず銆�
+
+---
+
+## 7. 鏁版嵁搴撳彉鏇�
+
+鎵ц浠ヤ笅SQL鍓嶈澶囦唤鏁版嵁锛�
+
+```sql
+-- 璁惧淇濆吇琛ㄦ柊澧為獙鏀朵汉鐩稿叧瀛楁
+ALTER TABLE `device_maintenance`
+ ADD COLUMN `acceptance_name` VARCHAR(100) NULL COMMENT '楠屾敹浜�' AFTER `spare_parts_ids`,
+ ADD COLUMN `acceptance_time` DATETIME NULL COMMENT '楠屾敹鏃堕棿' AFTER `acceptance_name`,
+ ADD COLUMN `acceptance_remark` VARCHAR(500) NULL COMMENT '楠屾敹澶囨敞' AFTER `acceptance_time`;
+```
+
+> 鑻ユ湭鎵ц浠ヤ笂SQL锛岀浉鍏虫帴鍙d細鍑虹幇瀛楁涓嶅瓨鍦ㄥ紓甯搞��
+
+---
+
+## 8. 瀛楁瀵圭収琛�
+
+### 璁惧淇濆吇锛坉evice_maintenance锛�
+
+| 鏁版嵁搴撳瓧娈� | Java瀛楁 | 绫诲瀷 | 璇存槑 |
+|---|---|---|---|
+| `acceptance_name` | `acceptanceName` | String | 楠屾敹浜� |
+| `acceptance_time` | `acceptanceTime` | LocalDateTime | 楠屾敹鏃堕棿 |
+| `acceptance_remark` | `acceptanceRemark` | String | 楠屾敹澶囨敞 |
+
+### 璁惧鎶ヤ慨锛坉evice_repair锛�
+
+| 鏁版嵁搴撳瓧娈� | Java瀛楁 | 绫诲瀷 | 璇存槑 |
+|---|---|---|---|
+| `acceptance_name` | `acceptanceName` | String | 楠屾敹浜� |
+| `acceptance_time` | `acceptanceTime` | LocalDateTime | 楠屾敹鏃堕棿 |
+| `acceptance_remark` | `acceptanceRemark` | String | 楠屾敹澶囨敞 |
\ No newline at end of file
diff --git "a/doc/\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243-\350\256\276\345\244\207\346\212\245\344\277\256\351\252\214\346\224\266\345\256\241\346\211\271\345\212\237\350\203\275.md" "b/doc/\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243-\350\256\276\345\244\207\346\212\245\344\277\256\351\252\214\346\224\266\345\256\241\346\211\271\345\212\237\350\203\275.md"
new file mode 100644
index 0000000..8469456
--- /dev/null
+++ "b/doc/\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243-\350\256\276\345\244\207\346\212\245\344\277\256\351\252\214\346\224\266\345\256\241\346\211\271\345\212\237\350\203\275.md"
@@ -0,0 +1,361 @@
+# 鍓嶇鑱旇皟鏂囨。 - 璁惧鎶ヤ慨楠屾敹瀹℃壒鍔熻兘
+
+## 1. 鍔熻兘姒傝堪
+
+璁惧鎶ヤ慨妯″潡瀹炵幇浜嗗畬鏁寸殑楠屾敹瀹℃壒娴佺▼锛�
+
+- 缁翠慨纭鍚庤繘鍏ュ緟楠屾敹鐘舵��
+- 楠屾敹瀹℃壒閫氳繃鍚庢墠绠楀畬缁�
+- 璁板綍楠屾敹浜恒�侀獙鏀舵椂闂淬�侀獙鏀跺娉�
+
+---
+
+## 2. 鐘舵�佸畾涔�
+
+| 鐘舵�佸�� | 鍚箟 | 璇存槑 |
+|---|---|---|
+| `0` | 寰呯淮淇� | 鎶ヤ慨鍗曞垵濮嬬姸鎬� |
+| `3` | 寰呴獙鏀� | 缁翠慨纭鍚庣瓑寰呴獙鏀� |
+| `1` | 瀹岀粨 | 楠屾敹閫氳繃 |
+| `2` | 澶辫触 | 缁翠慨澶辫触 |
+
+### 鐘舵�佹祦杞浘
+
+```
+寰呯淮淇�(0) --> 寰呴獙鏀�(3) --> 瀹岀粨(1)
+ |
+ +--> 澶辫触(2)
+```
+
+---
+
+## 3. 鎺ュ彛娓呭崟
+
+### 3.1 缁翠慨纭
+
+- **POST** `/device/repair/repair`
+- 璇存槑锛氱淮淇汉鍛樺畬鎴愮淮淇悗鎻愪氦锛岀姸鎬佷粠 `寰呯淮淇�(0)` 杩涘叆 `寰呴獙鏀�(3)`
+
+#### 璇锋眰鍙傛暟锛圔ody锛�
+
+| 瀛楁 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|---|---|---|---|
+| `id` | Long | 鏄� | 鎶ヤ慨璁板綍ID |
+| `maintenanceName` | String | 鍚� | 缁翠慨浜� |
+| `maintenanceTime` | String | 鍚� | 缁翠慨鏃堕棿锛屾牸寮� `yyyy-MM-dd HH:mm:ss` |
+| `maintenanceResult` | String | 鍚� | 缁翠慨缁撴灉鎻忚堪 |
+| `sparePartsUseList` | Array | 鍚� | 浣跨敤澶囦欢鍒楄〃 |
+| `sparePartsUseList[].id` | Long | 鏄� | 澶囦欢ID |
+| `sparePartsUseList[].quantity` | Integer | 鏄� | 浣跨敤鏁伴噺 |
+
+#### 璇锋眰绀轰緥
+
+```json
+{
+ "id": 10001,
+ "maintenanceName": "鏉庡洓",
+ "maintenanceTime": "2026-06-02 10:30:00",
+ "maintenanceResult": "鏇存崲杞存壙骞惰瘯杩愯姝e父",
+ "sparePartsUseList": [
+ {
+ "id": 501,
+ "quantity": 2
+ },
+ {
+ "id": 502,
+ "quantity": 1
+ }
+ ]
+}
+```
+
+#### 杩斿洖绀轰緥
+
+```json
+{
+ "code": 200,
+ "msg": "鎿嶄綔鎴愬姛"
+}
+```
+
+#### 閿欒鎻愮ず
+
+| 閿欒淇℃伅 | 鍦烘櫙 |
+|---|---|
+| `鎶ヤ慨璁板綍涓嶅瓨鍦╜ | 浼犲叆鐨処D鏃犳晥 |
+| `璇ユ姤淇凡瀹岀粨锛屼笉鑳介噸澶嶇‘璁ょ淮淇甡 | 鐘舵�佸凡涓哄畬缁�(1) |
+| `璇ユ姤淇凡鎻愪氦楠屾敹瀹℃壒` | 鐘舵�佸凡涓哄緟楠屾敹(3) |
+| `澶囦欢 xxx 鏁伴噺涓嶈冻` | 澶囦欢搴撳瓨涓嶈冻 |
+
+---
+
+### 3.2 楠屾敹瀹℃壒
+
+- **POST** `/device/repair/acceptance`
+- 璇存槑锛氶獙鏀朵汉鍛樺寰呴獙鏀跺崟鎹繘琛屽鎵癸紝瀹℃壒閫氳繃鍚庣姸鎬佹敼涓� `瀹岀粨(1)`
+
+#### 璇锋眰鍙傛暟锛圔ody锛�
+
+| 瀛楁 | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|---|---|---|---|
+| `id` | Long | 鏄� | 鎶ヤ慨璁板綍ID |
+| `acceptanceName` | String | 鏄� | 楠屾敹浜哄鍚� |
+| `acceptanceTime` | String | 鏄� | 楠屾敹鏃堕棿锛屾牸寮� `yyyy-MM-dd HH:mm:ss` |
+| `acceptanceRemark` | String | 鏄� | 楠屾敹澶囨敞 |
+
+#### 璇锋眰绀轰緥
+
+```json
+{
+ "id": 10001,
+ "acceptanceName": "鐜嬩簲",
+ "acceptanceTime": "2026-06-02 11:00:00",
+ "acceptanceRemark": "缁翠慨椤规牳楠岄�氳繃锛岃澶囪繍琛屾甯�"
+}
+```
+
+#### 杩斿洖绀轰緥
+
+```json
+{
+ "code": 200,
+ "msg": "鎿嶄綔鎴愬姛"
+}
+```
+
+#### 閿欒鎻愮ず
+
+| 閿欒淇℃伅 | 鍦烘櫙 |
+|---|---|
+| `鎶ヤ慨璁板綍id涓嶈兘涓虹┖` | 鏈紶鍏d鍙傛暟 |
+| `鎶ヤ慨璁板綍涓嶅瓨鍦╜ | 浼犲叆鐨処D鏃犳晥 |
+| `璇ユ姤淇湭杩涘叆寰呴獙鏀剁姸鎬侊紝涓嶈兘瀹℃壒` | 鐘舵�佷笉鏄緟楠屾敹(3) |
+| `楠屾敹浜轰笉鑳戒负绌篳 | acceptanceName涓虹┖ |
+| `楠屾敹鏃堕棿涓嶈兘涓虹┖` | acceptanceTime涓虹┖ |
+| `楠屾敹澶囨敞涓嶈兘涓虹┖` | acceptanceRemark涓虹┖ |
+| `楠屾敹瀹℃壒澶辫触` | 鏁版嵁搴撴洿鏂板け璐� |
+
+---
+
+### 3.3 鏅�氭洿鏂版帴鍙i檺鍒�
+
+- **PUT** `/device/repair`
+- 璇存槑锛氭櫘閫氱殑鏇存柊鎺ュ彛锛岀敤浜庝慨鏀规姤淇熀鏈俊鎭�
+
+#### 闄愬埗瑙勫垯
+
+- 涓嶈兘閫氳繃姝ゆ帴鍙g洿鎺ュ皢鐘舵�佹敼涓� `瀹岀粨(1)`
+- 蹇呴』璧� `POST /device/repair/repair` -> `POST /device/repair/acceptance` 娴佺▼
+
+#### 閿欒鎻愮ず
+
+| 閿欒淇℃伅 | 鍦烘櫙 |
+|---|---|
+| `璇峰厛鎻愪氦楠屾敹瀹℃壒锛岄獙鏀堕�氳繃鍚庢墠鍙畬缁揱 | 灏濊瘯鐩存帴璁剧疆status=1 |
+
+---
+
+### 3.4 鏌ヨ鎺ュ彛杩斿洖瀛楁
+
+浠ヤ笅鎺ュ彛杩斿洖鏁版嵁涓寘鍚獙鏀剁浉鍏冲瓧娈碉細
+
+- **GET** `/device/repair/page` - 鍒嗛〉鍒楄〃
+- **GET** `/device/repair/{id}` - 璇︽儏
+
+#### 楠屾敹鐩稿叧杩斿洖瀛楁
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|---|---|---|
+| `acceptanceName` | String | 楠屾敹浜� |
+| `acceptanceTime` | String | 楠屾敹鏃堕棿锛屾牸寮� `yyyy-MM-dd HH:mm:ss` |
+| `acceptanceRemark` | String | 楠屾敹澶囨敞 |
+
+#### 鍒楄〃杩斿洖绀轰緥
+
+```json
+{
+ "code": 200,
+ "msg": "鎿嶄綔鎴愬姛",
+ "data": {
+ "records": [
+ {
+ "id": 10001,
+ "deviceLedgerId": 100,
+ "deviceName": "绌哄帇鏈篈",
+ "deviceModel": "KR-500",
+ "areaId": 1,
+ "areaName": "鐢熶骇杞﹂棿",
+ "repairTime": "2026-06-01 09:00:00",
+ "repairName": "寮犱笁",
+ "remark": "璁惧杩愯寮傚搷",
+ "machineryCategory": "鍔ㄥ姏璁惧",
+ "maintenanceName": "鏉庡洓",
+ "maintenanceTime": "2026-06-02 10:30:00",
+ "maintenanceResult": "鏇存崲杞存壙骞惰瘯杩愯姝e父",
+ "acceptanceName": "鐜嬩簲",
+ "acceptanceTime": "2026-06-02 11:00:00",
+ "acceptanceRemark": "缁翠慨椤规牳楠岄�氳繃锛岃澶囪繍琛屾甯�",
+ "status": 1,
+ "createTime": "2026-06-01 08:30:00",
+ "updateTime": "2026-06-02 11:00:00"
+ }
+ ],
+ "total": 1,
+ "size": 10,
+ "current": 1
+ }
+}
+```
+
+---
+
+## 4. 鍓嶇瀹炵幇寤鸿
+
+### 4.1 鍒楄〃椤甸潰
+
+1. **鐘舵�佺瓫閫�**锛氬鍔� `寰呴獙鏀�(3)` 鐘舵�佺殑绛涢�夐」
+2. **鐘舵�佸睍绀�**锛氭牴鎹畇tatus鍊兼樉绀哄搴旀枃妗堝拰棰滆壊
+
+| 鐘舵�佸�� | 鏂囨 | 寤鸿棰滆壊 |
+|---|---|---|
+| 0 | 寰呯淮淇� | 姗欒壊/璀﹀憡 |
+| 3 | 寰呴獙鏀� | 钃濊壊/淇℃伅 |
+| 1 | 瀹岀粨 | 缁胯壊/鎴愬姛 |
+| 2 | 澶辫触 | 绾㈣壊/閿欒 |
+
+### 4.2 璇︽儏椤甸潰
+
+1. **寰呯淮淇姸鎬�(0)**锛�
+ - 鏄剧ず"纭缁翠慨"鎸夐挳
+ - 鍙紪杈戠淮淇汉銆佺淮淇椂闂淬�佺淮淇粨鏋�
+ - 鍙�夋嫨浣跨敤鐨勫浠�
+
+2. **寰呴獙鏀剁姸鎬�(3)**锛�
+ - 鏄剧ず"楠屾敹瀹℃壒"鎸夐挳
+ - 寮圭獥濉啓锛氶獙鏀朵汉銆侀獙鏀舵椂闂淬�侀獙鏀跺娉�
+
+3. **瀹岀粨鐘舵��(1)**锛�
+ - 鏄剧ず楠屾敹淇℃伅锛堥獙鏀朵汉銆侀獙鏀舵椂闂淬�侀獙鏀跺娉級
+ - 鍙灞曠ず
+
+### 4.3 楠屾敹瀹℃壒寮圭獥
+
+```html
+<!-- 绀轰緥琛ㄥ崟 -->
+<el-form :model="acceptanceForm" :rules="rules">
+ <el-form-item label="楠屾敹浜�" prop="acceptanceName">
+ <el-input v-model="acceptanceForm.acceptanceName" placeholder="璇疯緭鍏ラ獙鏀朵汉" />
+ </el-form-item>
+ <el-form-item label="楠屾敹鏃堕棿" prop="acceptanceTime">
+ <el-date-picker
+ v-model="acceptanceForm.acceptanceTime"
+ type="datetime"
+ placeholder="閫夋嫨楠屾敹鏃堕棿"
+ format="yyyy-MM-dd HH:mm:ss"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ />
+ </el-form-item>
+ <el-form-item label="楠屾敹澶囨敞" prop="acceptanceRemark">
+ <el-input
+ v-model="acceptanceForm.acceptanceRemark"
+ type="textarea"
+ placeholder="璇疯緭鍏ラ獙鏀跺娉�"
+ :rows="3"
+ />
+ </el-form-item>
+</el-form>
+```
+
+### 4.4 琛ㄥ崟楠岃瘉瑙勫垯
+
+```javascript
+const rules = {
+ acceptanceName: [
+ { required: true, message: '楠屾敹浜轰笉鑳戒负绌�', trigger: 'blur' }
+ ],
+ acceptanceTime: [
+ { required: true, message: '楠屾敹鏃堕棿涓嶈兘涓虹┖', trigger: 'change' }
+ ],
+ acceptanceRemark: [
+ { required: true, message: '楠屾敹澶囨敞涓嶈兘涓虹┖', trigger: 'blur' }
+ ]
+}
+```
+
+---
+
+## 5. 鎿嶄綔鎸夐挳鎺у埗
+
+### 5.1 鎸夐挳鏄剧ず閫昏緫
+
+| 鐘舵�� | 纭缁翠慨 | 楠屾敹瀹℃壒 | 缂栬緫 | 鍒犻櫎 |
+|---|---|---|---|---|
+| 寰呯淮淇�(0) | 鉁� 鏄剧ず | 鉂� 闅愯棌 | 鉁� 鏄剧ず | 鉁� 鏄剧ず |
+| 寰呴獙鏀�(3) | 鉂� 闅愯棌 | 鉁� 鏄剧ず | 鉁� 鏄剧ず | 鉁� 鏄剧ず |
+| 瀹岀粨(1) | 鉂� 闅愯棌 | 鉂� 闅愯棌 | 鉂� 绂佺敤 | 鉂� 绂佺敤 |
+| 澶辫触(2) | 鉂� 闅愯棌 | 鉂� 闅愯棌 | 鉁� 鏄剧ず | 鉁� 鏄剧ず |
+
+### 5.2 鐘舵�佹祦杞帶鍒�
+
+```javascript
+// 纭缁翠慨
+async function handleRepair(row) {
+ const res = await post('/device/repair/repair', {
+ id: row.id,
+ maintenanceName: form.maintenanceName,
+ maintenanceTime: form.maintenanceTime,
+ maintenanceResult: form.maintenanceResult,
+ sparePartsUseList: form.sparePartsUseList
+ })
+ if (res.code === 200) {
+ // 鐘舵�佸彉涓哄緟楠屾敹(3)锛屽埛鏂板垪琛�
+ refreshList()
+ }
+}
+
+// 楠屾敹瀹℃壒
+async function handleAcceptance(row) {
+ const res = await post('/device/repair/acceptance', {
+ id: row.id,
+ acceptanceName: form.acceptanceName,
+ acceptanceTime: form.acceptanceTime,
+ acceptanceRemark: form.acceptanceRemark
+ })
+ if (res.code === 200) {
+ // 鐘舵�佸彉涓哄畬缁�(1)锛屽埛鏂板垪琛�
+ refreshList()
+ }
+}
+```
+
+---
+
+## 6. 鏁版嵁搴撳瓧娈�
+
+### device_repair 琛�
+
+| 瀛楁鍚� | 绫诲瀷 | 璇存槑 |
+|---|---|---|
+| `acceptance_name` | VARCHAR(100) | 楠屾敹浜� |
+| `acceptance_time` | DATETIME | 楠屾敹鏃堕棿 |
+| `acceptance_remark` | VARCHAR(500) | 楠屾敹澶囨敞 |
+
+### SQL锛堝凡鎵ц锛�
+
+```sql
+ALTER TABLE device_repair
+ ADD COLUMN acceptance_name VARCHAR(100) NULL COMMENT '楠屾敹浜�',
+ ADD COLUMN acceptance_time DATETIME NULL COMMENT '楠屾敹鏃堕棿',
+ ADD COLUMN acceptance_remark VARCHAR(500) NULL COMMENT '楠屾敹澶囨敞';
+```
+
+---
+
+## 7. 鑱旇皟妫�鏌ユ竻鍗�
+
+- [ ] 寰呯淮淇姸鎬佺殑鎶ヤ慨鍗曪紝鐐瑰嚮"纭缁翠慨"鍚庣姸鎬佸彉涓哄緟楠屾敹(3)
+- [ ] 寰呴獙鏀剁姸鎬佺殑鎶ヤ慨鍗曪紝鐐瑰嚮"楠屾敹瀹℃壒"鍚庣姸鎬佸彉涓哄畬缁�(1)
+- [ ] 楠屾敹瀹℃壒鏃讹紝楠屾敹浜�/楠屾敹鏃堕棿/楠屾敹澶囨敞涓虹┖锛屽悗绔繑鍥炲搴旈敊璇彁绀�
+- [ ] 灏濊瘯閫氳繃鏅�氱紪杈戞帴鍙g洿鎺ュ皢鐘舵�佹敼涓哄畬缁擄紝鍚庣杩斿洖鎷︽埅鎻愮ず
+- [ ] 鍒楄〃/璇︽儏鎺ュ彛姝g‘杩斿洖楠屾敹鐩稿叧瀛楁
+- [ ] 瀹岀粨鐘舵�佺殑鎶ヤ慨鍗曪紝璇︽儏椤靛睍绀洪獙鏀朵俊鎭�
\ No newline at end of file
diff --git "a/doc/\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243-\350\277\207\347\250\213\346\243\200\351\252\214\346\250\241\346\235\277\345\257\274\345\207\272\345\212\237\350\203\275.md" "b/doc/\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243-\350\277\207\347\250\213\346\243\200\351\252\214\346\250\241\346\235\277\345\257\274\345\207\272\345\212\237\350\203\275.md"
new file mode 100644
index 0000000..67fa537
--- /dev/null
+++ "b/doc/\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243-\350\277\207\347\250\213\346\243\200\351\252\214\346\250\241\346\235\277\345\257\274\345\207\272\345\212\237\350\203\275.md"
@@ -0,0 +1,275 @@
+# 鍓嶇鑱旇皟鏂囨。 - 杩囩▼妫�楠屾ā鏉垮鍑哄姛鑳�
+
+## 1. 鍔熻兘姒傝堪
+
+杩囩▼妫�楠屾ā鍧楁敮鎸佷笁绉嶅鎴锋ā鏉跨殑妫�楠岀粨鏋滃鍑猴細
+- **浼熼緳妯℃澘** - 浼熼緳瀹㈡埛涓撶敤妫�楠屾姤鍛婃牸寮�
+- **鐧句簨妯℃澘** - 鐧句簨瀹㈡埛涓撶敤妫�楠屾姤鍛婃牸寮�
+- **杈惧埄妯℃澘** - 杈惧埄瀹㈡埛涓撶敤妫�楠屾姤鍛婃牸寮�
+
+瀵煎嚭鍔熻兘浼氳嚜鍔ㄥ~鍏呮ā鏉夸腑鐨�"缁撴灉"鍒楋紝鏍规嵁妫�楠屽弬鏁颁腑鐨�"椤圭洰鍒�"杩涜鍖归厤銆�
+
+---
+
+## 2. 鎺ュ彛娓呭崟
+
+### 2.1 瀵煎嚭浼熼緳妯℃澘妫�楠岀粨鏋�
+
+- **GET** `/quality/qualityInspect/export/weilong/{id}`
+- 璇存槑锛氬鍑烘寚瀹氳繃绋嬫楠屽崟鐨勪紵榫欐牸寮忔楠屾姤鍛�
+
+#### 璇锋眰鍙傛暟
+
+| 鍙傛暟鍚� | 绫诲瀷 | 浣嶇疆 | 蹇呭~ | 璇存槑 |
+|--------|------|------|------|------|
+| `id` | Long | Path | 鏄� | 杩囩▼妫�楠屽崟ID |
+
+#### 璇锋眰绀轰緥
+
+```
+GET /quality/qualityInspect/export/weilong/123
+```
+
+#### 杩斿洖缁撴灉
+
+杩斿洖Word鏂囨。鏂囦欢娴侊紝鏂囦欢鍚嶏細`浼熼緳妯$増妫�楠岀粨鏋�.doc`
+
+---
+
+### 2.2 瀵煎嚭鐧句簨妯℃澘妫�楠岀粨鏋�
+
+- **GET** `/quality/qualityInspect/export/baishi/{id}`
+- 璇存槑锛氬鍑烘寚瀹氳繃绋嬫楠屽崟鐨勭櫨浜嬫牸寮忔楠屾姤鍛�
+
+#### 璇锋眰鍙傛暟
+
+| 鍙傛暟鍚� | 绫诲瀷 | 浣嶇疆 | 蹇呭~ | 璇存槑 |
+|--------|------|------|------|------|
+| `id` | Long | Path | 鏄� | 杩囩▼妫�楠屽崟ID |
+
+#### 璇锋眰绀轰緥
+
+```
+GET /quality/qualityInspect/export/baishi/123
+```
+
+#### 杩斿洖缁撴灉
+
+杩斿洖Word鏂囨。鏂囦欢娴侊紝鏂囦欢鍚嶏細`鐧句簨妯$増妫�楠岀粨鏋�.doc`
+
+---
+
+### 2.3 瀵煎嚭杈惧埄妯℃澘妫�楠岀粨鏋�
+
+- **GET** `/quality/qualityInspect/export/dali/{id}`
+- 璇存槑锛氬鍑烘寚瀹氳繃绋嬫楠屽崟鐨勮揪鍒╂牸寮忔楠屾姤鍛�
+
+#### 璇锋眰鍙傛暟
+
+| 鍙傛暟鍚� | 绫诲瀷 | 浣嶇疆 | 蹇呭~ | 璇存槑 |
+|--------|------|------|------|------|
+| `id` | Long | Path | 鏄� | 杩囩▼妫�楠屽崟ID |
+
+#### 璇锋眰绀轰緥
+
+```
+GET /quality/qualityInspect/export/dali/123
+```
+
+#### 杩斿洖缁撴灉
+
+杩斿洖Word鏂囨。鏂囦欢娴侊紝鏂囦欢鍚嶏細`杈惧埄妯$増妫�楠岀粨鏋�.doc`
+
+---
+
+## 3. 鏁版嵁鍖归厤瑙勫垯
+
+### 3.1 妯℃澘濉厖閫昏緫
+
+瀵煎嚭鏃剁郴缁熶細鑷姩鍖归厤妫�楠屽弬鏁颁笌妯℃澘涓殑妫�楠岄」鐩細
+
+1. **椤圭洰鍖归厤**锛氭牴鎹楠屽弬鏁拌〃锛坄quality_inspect_param`锛変腑鐨刞parameterItem`锛堟楠岄」鐩級瀛楁涓庢ā鏉胯〃鏍煎乏渚х殑椤圭洰鍒楄繘琛屽尮閰�
+2. **缁撴灉濉厖**锛氬尮閰嶆垚鍔熷悗锛屽皢`testValue`锛堟楠屽�硷級濉厖鍒版ā鏉垮搴旇鐨�"缁撴灉"鍒�
+3. **妫�楠岀粨璁�**锛氱壒娈婅锛堝"璐ㄩ噺璇勫畾"銆�"妫�楠岀粨鏋�"銆�"妫�楠岀粨璁�"锛変細濉厖妫�楠屽崟鐨刞checkResult`瀛楁
+
+### 3.2 鍖归厤浼樺厛绾�
+
+| 浼樺厛绾� | 鍖归厤瑙勫垯 | 璇存槑 |
+|--------|----------|------|
+| 1 | 瀹屽叏鍖归厤 | 椤圭洰鍚嶇О瀹屽叏涓�鑷� |
+| 2 | 鍖呭惈鍖归厤 | 椤圭洰鍚嶇О鍖呭惈鍏崇郴 |
+| 3 | 缁勫悎鍖归厤 | 绗竴鍒�+绗簩鍒楃粍鍚堝尮閰� |
+| 4 | 鍒嗙粍鍖归厤 | 鍒嗙粍鏍囩+椤圭洰鍚嶇О缁勫悎鍖归厤 |
+
+### 3.3 鐗规畩澶勭悊
+
+浠ヤ笅琛屼細鑷姩濉厖妫�楠岀粨璁猴紙`checkResult`锛夛細
+- 璐ㄩ噺璇勫畾
+- 妫�楠岀粨鏋�
+- 妫�楠岀粨璁�
+- Grade estimation
+- Test Results
+
+---
+
+## 4. 鍓嶇瀹炵幇绀轰緥
+
+### 4.1 Vue + Axios 瀵煎嚭绀轰緥
+
+```javascript
+// 瀵煎嚭浼熼緳妯℃澘
+exportWeiLong(row) {
+ const id = row.id;
+ axios({
+ method: 'get',
+ url: `/quality/qualityInspect/export/weilong/${id}`,
+ responseType: 'blob'
+ }).then(response => {
+ const blob = new Blob([response.data], { type: 'application/msword' });
+ const link = document.createElement('a');
+ link.href = URL.createObjectURL(blob);
+ link.download = '浼熼緳妯$増妫�楠岀粨鏋�.doc';
+ link.click();
+ URL.revokeObjectURL(link.href);
+ }).catch(error => {
+ console.error('瀵煎嚭澶辫触', error);
+ });
+}
+
+// 瀵煎嚭鐧句簨妯℃澘
+exportBaiShi(row) {
+ const id = row.id;
+ axios({
+ method: 'get',
+ url: `/quality/qualityInspect/export/baishi/${id}`,
+ responseType: 'blob'
+ }).then(response => {
+ const blob = new Blob([response.data], { type: 'application/msword' });
+ const link = document.createElement('a');
+ link.href = URL.createObjectURL(blob);
+ link.download = '鐧句簨妯$増妫�楠岀粨鏋�.doc';
+ link.click();
+ URL.revokeObjectURL(link.href);
+ }).catch(error => {
+ console.error('瀵煎嚭澶辫触', error);
+ });
+}
+
+// 瀵煎嚭杈惧埄妯℃澘
+exportDaLi(row) {
+ const id = row.id;
+ axios({
+ method: 'get',
+ url: `/quality/qualityInspect/export/dali/${id}`,
+ responseType: 'blob'
+ }).then(response => {
+ const blob = new Blob([response.data], { type: 'application/msword' });
+ const link = document.createElement('a');
+ link.href = URL.createObjectURL(blob);
+ link.download = '杈惧埄妯$増妫�楠岀粨鏋�.doc';
+ link.click();
+ URL.revokeObjectURL(link.href);
+ }).catch(error => {
+ console.error('瀵煎嚭澶辫触', error);
+ });
+}
+```
+
+### 4.2 鎸夐挳閰嶇疆绀轰緥
+
+```html
+<el-table-column label="鎿嶄綔" width="200">
+ <template #default="{ row }">
+ <!-- 鍙湁杩囩▼妫�楠�(inspectType=1)鎵嶆樉绀烘ā鏉垮鍑烘寜閽� -->
+ <el-button v-if="row.inspectType === 1" size="small" @click="exportWeiLong(row)">
+ 浼熼緳妯℃澘
+ </el-button>
+ <el-button v-if="row.inspectType === 1" size="small" @click="exportBaiShi(row)">
+ 鐧句簨妯℃澘
+ </el-button>
+ <el-button v-if="row.inspectType === 1" size="small" @click="exportDaLi(row)">
+ 杈惧埄妯℃澘
+ </el-button>
+ </template>
+</el-table-column>
+```
+
+---
+
+## 5. 閿欒澶勭悊
+
+### 5.1 閿欒鍝嶅簲
+
+| 閿欒淇℃伅 | 鍦烘櫙 |
+|----------|------|
+| `妫�楠屽崟ID涓嶈兘涓虹┖` | 鏈紶鍏d鍙傛暟 |
+| `妫�楠屽崟涓嶅瓨鍦╜ | 浼犲叆鐨処D鏃犳晥 |
+| `妯℃澘鏂囦欢涓嶅瓨鍦╜ | 妯℃澘鏂囦欢缂哄け |
+| `瀵煎嚭澶辫触` | 鏂囦欢澶勭悊寮傚父 |
+
+### 5.2 鍓嶇閿欒澶勭悊
+
+```javascript
+.catch(error => {
+ if (error.response) {
+ // 璇诲彇閿欒淇℃伅
+ const reader = new FileReader();
+ reader.onload = () => {
+ const message = JSON.parse(reader.result).msg || '瀵煎嚭澶辫触';
+ this.$message.error(message);
+ };
+ reader.readAsText(error.response.data);
+ } else {
+ this.$message.error('瀵煎嚭澶辫触锛岃绋嶅悗閲嶈瘯');
+ }
+});
+```
+
+---
+
+## 6. 涓氬姟璇存槑
+
+### 6.1 妫�楠岀被鍨嬪尯鍒�
+
+| inspectType | 绫诲瀷 | 璇存槑 |
+|-------------|------|------|
+| 0 | 鍘熸潗鏂欐楠� | 杩涙枡妫�楠� |
+| 1 | 杩囩▼妫�楠� | 鐢熶骇杩囩▼妫�楠岋紙鏀寔妯℃澘瀵煎嚭锛� |
+| 2 | 鍑哄巶妫�楠� | 鎴愬搧鍑哄巶妫�楠� |
+
+### 6.2 妯℃澘瀵煎嚭閫傜敤鑼冨洿
+
+妯℃澘瀵煎嚭鍔熻兘涓昏鐢ㄤ簬**杩囩▼妫�楠�**锛坄inspectType=1`锛夛紝鍓嶇搴旀牴鎹楠岀被鍨嬪垽鏂槸鍚︽樉绀烘ā鏉垮鍑烘寜閽��
+
+### 6.3 妫�楠屽弬鏁版暟鎹粨鏋�
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+|------|------|------|
+| `parameterItem` | String | 妫�楠岄」鐩悕绉帮紙鐢ㄤ簬鍖归厤妯℃澘锛� |
+| `testValue` | String | 妫�楠屽�硷紙濉厖鍒扮粨鏋滃垪锛� |
+| `standardValue` | String | 鏍囧噯鍊� |
+| `controlValue` | String | 鍐呮帶鍊� |
+| `unit` | String | 鍗曚綅 |
+
+---
+
+## 7. 鑱旇皟妫�鏌ユ竻鍗�
+
+- [ ] 杩囩▼妫�楠屽崟瀵煎嚭浼熼緳妯℃澘鎴愬姛锛屾枃浠跺彲姝e父鎵撳紑
+- [ ] 杩囩▼妫�楠屽崟瀵煎嚭鐧句簨妯℃澘鎴愬姛锛屾枃浠跺彲姝e父鎵撳紑
+- [ ] 杩囩▼妫�楠屽崟瀵煎嚭杈惧埄妯℃澘鎴愬姛锛屾枃浠跺彲姝e父鎵撳紑
+- [ ] 瀵煎嚭鏂囦欢涓楠岀粨鏋滃垪姝g‘濉厖
+- [ ] 妫�楠岀粨璁鸿姝g‘鏄剧ず`checkResult`鍊�
+- [ ] 浼犲叆涓嶅瓨鍦ㄧ殑ID鏃惰繑鍥為敊璇彁绀�
+- [ ] 鍘熸潗鏂欐楠�/鍑哄巶妫�楠屼笉鏄剧ず妯℃澘瀵煎嚭鎸夐挳
+- [ ] 鏂囦欢鍚嶇紪鐮佹纭紝涓枃鏃犱贡鐮�
+
+---
+
+## 8. 妯℃澘鏂囦欢浣嶇疆
+
+| 妯℃澘 | 璺緞 |
+|------|------|
+| 浼熼緳妯$増.doc | `/static/浼熼緳妯$増.doc` |
+| 鐧句簨妯$増.doc | `/static/鐧句簨妯$増.doc` |
+| 杈惧埄妯$増.doc | `/static/杈惧埄妯$増.doc` |
\ No newline at end of file
diff --git a/docs/maintenance_task_api.md b/docs/maintenance_task_api.md
new file mode 100644
index 0000000..91b9224
--- /dev/null
+++ b/docs/maintenance_task_api.md
@@ -0,0 +1,317 @@
+# 璁惧淇濆吇浠诲姟鎺ュ彛鏂囨。
+
+## 姒傝堪
+
+璁惧淇濆吇浠诲姟妯″潡鐢ㄤ簬绠$悊璁惧鐨勫畾鏃朵繚鍏昏鍒掞紝鏀寔澶氱棰戠巼绫诲瀷锛堟瘡鏃ャ�佹瘡鍛ㄣ�佹瘡鏈堛�佹瘡瀛e害銆佹瘡骞达級锛屽苟鍙惎鐢ㄦ垨绂佺敤浠诲姟銆�
+
+---
+
+## 鎺ュ彛鍒楄〃
+
+### 1. 鍒嗛〉鏌ヨ淇濆吇浠诲姟鍒楄〃
+
+**璇锋眰鍦板潃**: `GET /deviceMaintenanceTask/listPage`
+
+**璇锋眰鍙傛暟**:
+
+| 鍙傛暟鍚� | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|--------|------|------|------|
+| current | Long | 鍚� | 褰撳墠椤电爜锛岄粯璁�1 |
+| size | Long | 鍚� | 姣忛〉鏉℃暟锛岄粯璁�10 |
+| taskName | String | 鍚� | 浠诲姟鍚嶇О锛堟ā绯婃煡璇級 |
+| areaId | Long | 鍚� | 璁惧鍖哄煙ID |
+| isEnabled | Integer | 鍚� | 鏄惁鍚敤锛�1=鍚敤锛�0=绂佺敤锛� |
+
+**鍝嶅簲绀轰緥**:
+
+```json
+{
+ "code": 200,
+ "msg": "鎿嶄綔鎴愬姛",
+ "data": {
+ "records": [
+ {
+ "id": 1,
+ "taskName": "璁惧A,璁惧B",
+ "taskId": 100,
+ "areaId": 10,
+ "areaName": "鐢熶骇杞﹂棿",
+ "deviceModel": "鍨嬪彿A,鍨嬪彿B",
+ "deviceLedgerIdsStr": "100,101",
+ "frequencyType": "WEEKLY",
+ "frequencyDetail": "MON,14:30",
+ "nextExecutionTime": "2026-06-08T14:30:00",
+ "lastExecutionTime": "2026-06-01T14:30:00",
+ "isEnabled": 1,
+ "remarks": "澶囨敞淇℃伅",
+ "registrantId": 1,
+ "registrant": "寮犱笁",
+ "registrationDate": "2026-06-01",
+ "createTime": "2026-06-01T10:00:00",
+ "updateTime": "2026-06-01T10:00:00"
+ }
+ ],
+ "total": 100,
+ "current": 1,
+ "size": 10
+ }
+}
+```
+
+---
+
+### 2. 鏂板淇濆吇浠诲姟
+
+**璇锋眰鍦板潃**: `POST /deviceMaintenanceTask/add`
+
+**璇锋眰澶�**: `Content-Type: application/json`
+
+**璇锋眰鍙傛暟**:
+
+| 鍙傛暟鍚� | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|--------|------|------|------|
+| taskName | String | 鍚� | 浠诲姟鍚嶇О锛堝涓嶄紶鍒欐牴鎹澶囧悕绉拌嚜鍔ㄧ敓鎴愶級 |
+| taskId | Long | 鍚� | 璁惧ID锛堝崟涓澶囨椂浣跨敤锛� |
+| deviceLedgerIds | Long[] | 鍚� | 璁惧ID鏁扮粍锛堝涓澶囨椂浣跨敤锛� |
+| deviceLedgerIdsStr | String | 鍚� | 璁惧ID瀛楃涓诧紝閫楀彿鍒嗛殧 |
+| areaId | Long | 鍚� | 璁惧鍖哄煙ID |
+| frequencyType | String | 鏄� | 棰戞绫诲瀷锛岃涓嬫柟璇存槑 |
+| frequencyDetail | String | 鏄� | 棰戞璇︽儏锛屾牸寮忚涓嬫柟璇存槑 |
+| isEnabled | Integer | 鍚� | 鏄惁鍚敤锛�1=鍚敤锛�0=绂佺敤锛夛紝榛樿1 |
+| remarks | String | 鍚� | 澶囨敞 |
+
+**鍝嶅簲绀轰緥**:
+
+```json
+{
+ "code": 200,
+ "msg": "娣诲姞鎴愬姛"
+}
+```
+
+---
+
+### 3. 鏇存柊淇濆吇浠诲姟
+
+**璇锋眰鍦板潃**: `POST /deviceMaintenanceTask/update`
+
+**璇锋眰澶�**: `Content-Type: application/json`
+
+**璇锋眰鍙傛暟**: 鍚屾柊澧炴帴鍙o紝闇�棰濆浼犲叆 `id` 瀛楁
+
+| 鍙傛暟鍚� | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|--------|------|------|------|
+| id | Long | 鏄� | 浠诲姟ID |
+| ... | ... | ... | 鍏朵粬瀛楁鍚屾柊澧炴帴鍙� |
+
+**鍝嶅簲绀轰緥**:
+
+```json
+{
+ "code": 200,
+ "msg": "鏇存柊鎴愬姛"
+}
+```
+
+---
+
+### 4. 鍚敤/绂佺敤淇濆吇浠诲姟
+
+**璇锋眰鍦板潃**: `POST /deviceMaintenanceTask/changeEnable`
+
+**璇锋眰澶�**: `Content-Type: application/json`
+
+**璇锋眰鍙傛暟**:
+
+| 鍙傛暟鍚� | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|--------|------|------|------|
+| id | Long | 鏄� | 浠诲姟ID |
+| isEnabled | Integer | 鏄� | 鏄惁鍚敤锛�1=鍚敤锛�0=绂佺敤锛� |
+
+**鍝嶅簲绀轰緥**:
+
+```json
+{
+ "code": 200,
+ "msg": "鏇存柊鎴愬姛"
+}
+```
+
+**涓氬姟閫昏緫璇存槑**:
+- 鍚敤浠诲姟鏃朵細鑷姩鎭㈠瀹氭椂璋冨害
+- 绂佺敤浠诲姟鏃朵細鏆傚仠瀹氭椂璋冨害
+- 濡傛灉浠诲姟娌℃湁涓嬫鎵ц鏃堕棿锛屼細鑷姩璁$畻
+
+---
+
+### 5. 鍒犻櫎淇濆吇浠诲姟
+
+**璇锋眰鍦板潃**: `DELETE /deviceMaintenanceTask/delete`
+
+**璇锋眰澶�**: `Content-Type: application/json`
+
+**璇锋眰鍙傛暟**:
+
+| 鍙傛暟鍚� | 绫诲瀷 | 蹇呭~ | 璇存槑 |
+|--------|------|------|------|
+| - | Long[] | 鏄� | 浠诲姟ID鏁扮粍锛堣姹備綋鐩存帴浼犳暟缁勶級 |
+
+**璇锋眰绀轰緥**:
+
+```json
+[1, 2, 3]
+```
+
+**鍝嶅簲绀轰緥**:
+
+```json
+{
+ "code": 200,
+ "msg": "鍒犻櫎鎴愬姛"
+}
+```
+
+---
+
+## 棰戠巼绫诲瀷璇存槑
+
+### frequencyType 鍙�夊��
+
+| 鍊� | 璇存槑 | frequencyDetail 鏍煎紡 |
+|----|------|---------------------|
+| DAILY | 姣忔棩 | `HH:mm` |
+| WEEKLY | 姣忓懆 | `鏄熸湡,HH:mm` |
+| MONTHLY | 姣忔湀 | `鏃�,HH:mm` |
+| QUARTERLY | 姣忓搴� | `璧峰鏈堜唤,鏃�,HH:mm` |
+| YEARLY | 姣忓勾 | `鏈堜唤,鏃�,HH:mm` |
+
+### frequencyDetail 鏍煎紡璇﹁В
+
+#### 1. 姣忔棩锛圖AILY锛�
+
+鏍煎紡锛歚HH:mm`
+
+绀轰緥锛�
+- `14:30` - 姣忓ぉ 14:30 鎵ц
+
+#### 2. 姣忓懆锛圵EEKLY锛�
+
+鏍煎紡锛歚鏄熸湡,HH:mm`
+
+鏄熸湡鍙�夊�硷細`MON`, `TUE`, `WED`, `THU`, `FRI`, `SAT`, `SUN`
+
+绀轰緥锛�
+- `MON,14:30` - 姣忓懆涓� 14:30 鎵ц
+- `FRI,09:00` - 姣忓懆浜� 09:00 鎵ц
+
+#### 3. 姣忔湀锛圡ONTHLY锛�
+
+鏍煎紡锛歚鏃�,HH:mm`
+
+绀轰緥锛�
+- `15,14:30` - 姣忔湀15鏃� 14:30 鎵ц
+- `01,09:00` - 姣忔湀1鏃� 09:00 鎵ц
+- `31,18:00` - 姣忔湀鏈�鍚庝竴澶╋紙濡傛湀浠戒笉瓒�31澶╁垯鍙栨渶鍚庝竴澶╋級
+
+#### 4. 姣忓搴︼紙QUARTERLY锛�
+
+鏍煎紡锛歚璧峰鏈堜唤,鏃�,HH:mm`
+
+璇存槑锛氫粠鎸囧畾鏈堜唤寮�濮嬶紝姣忛殧3涓湀鎵ц涓�娆�
+
+绀轰緥锛�
+- `1,15,14:30` - 1鏈堛��4鏈堛��7鏈堛��10鏈堢殑15鏃� 14:30 鎵ц
+- `3,10,09:00` - 3鏈堛��6鏈堛��9鏈堛��12鏈堢殑10鏃� 09:00 鎵ц
+
+#### 5. 姣忓勾锛圷EARLY锛�
+
+鏍煎紡锛歚鏈堜唤,鏃�,HH:mm`
+
+绀轰緥锛�
+- `6,15,14:30` - 姣忓勾6鏈�15鏃� 14:30 鎵ц
+- `12,31,23:59` - 姣忓勾12鏈�31鏃� 23:59 鎵ц
+
+---
+
+## 鍓嶇浣跨敤绀轰緥
+
+### 鏂板姣忓懆淇濆吇浠诲姟
+
+```javascript
+const task = {
+ deviceLedgerIds: [100, 101], // 璁惧ID鏁扮粍
+ areaId: 10, // 鍖哄煙ID
+ frequencyType: 'WEEKLY', // 姣忓懆
+ frequencyDetail: 'MON,14:30', // 姣忓懆涓�14:30
+ isEnabled: 1, // 鍚敤
+ remarks: '姣忓懆渚嬭淇濆吇'
+};
+
+fetch('/deviceMaintenanceTask/add', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(task)
+});
+```
+
+### 鍚敤/绂佺敤浠诲姟
+
+```javascript
+// 鍚敤浠诲姟
+fetch('/deviceMaintenanceTask/changeEnable', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ id: 1, isEnabled: 1 })
+});
+
+// 绂佺敤浠诲姟
+fetch('/deviceMaintenanceTask/changeEnable', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ id: 1, isEnabled: 0 })
+});
+```
+
+---
+
+## 鏁版嵁瀛楀吀
+
+### isEnabled 瀛楁
+
+| 鍊� | 璇存槑 |
+|----|------|
+| 0 | 绂佺敤 |
+| 1 | 鍚敤 |
+
+### 杩斿洖瀛楁璇存槑
+
+| 瀛楁鍚� | 绫诲瀷 | 璇存槑 |
+|--------|------|------|
+| id | Long | 浠诲姟ID |
+| taskName | String | 浠诲姟鍚嶇О锛堝涓澶囩敤閫楀彿鍒嗛殧锛� |
+| taskId | Long | 涓昏澶嘔D |
+| areaId | Long | 璁惧鍖哄煙ID |
+| areaName | String | 璁惧鍖哄煙鍚嶇О |
+| deviceModel | String | 璁惧鍨嬪彿锛堝涓敤閫楀彿鍒嗛殧锛� |
+| deviceLedgerIdsStr | String | 璁惧ID瀛楃涓诧紙閫楀彿鍒嗛殧锛� |
+| frequencyType | String | 棰戞绫诲瀷 |
+| frequencyDetail | String | 棰戞璇︽儏 |
+| nextExecutionTime | DateTime | 涓嬫鎵ц鏃堕棿 |
+| lastExecutionTime | DateTime | 鏈�鍚庢墽琛屾椂闂� |
+| isEnabled | Integer | 鏄惁鍚敤 |
+| remarks | String | 澶囨敞 |
+| registrantId | Long | 褰曞叆浜篒D |
+| registrant | String | 褰曞叆浜哄鍚� |
+| registrationDate | Date | 褰曞叆鏃ユ湡 |
+| createTime | DateTime | 鍒涘缓鏃堕棿 |
+| updateTime | DateTime | 鏇存柊鏃堕棿 |
+
+---
+
+## 娉ㄦ剰浜嬮」
+
+1. **璁惧閫夋嫨**锛氬彲浠ヤ紶鍏� `deviceLedgerIds` 鏁扮粍鎴� `deviceLedgerIdsStr` 瀛楃涓叉寚瀹氬涓澶�
+2. **浠诲姟鍚嶇О**锛氬涓嶄紶 `taskName`锛岀郴缁熶細鏍规嵁璁惧鍚嶇О鑷姩鐢熸垚
+3. **涓嬫鎵ц鏃堕棿**锛氭柊澧炴垨鏇存柊鏃朵細鑷姩璁$畻涓嬫鎵ц鏃堕棿
+4. **鍚敤/绂佺敤**锛氱鐢ㄤ换鍔′笉浼氬垹闄ゅ畾鏃跺櫒锛屽彧鏄殏鍋滄墽琛岋紱鍚敤鍚庝細鎭㈠
+5. **鍒犻櫎浠诲姟**锛氬垹闄や换鍔′細鍚屾椂绉婚櫎鐩稿叧鐨勫畾鏃惰皟搴�
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index e840acd..af88718 100644
--- a/pom.xml
+++ b/pom.xml
@@ -326,6 +326,13 @@
<version>${poi.version}</version>
</dependency>
+ <!-- word doc鏍煎紡澶勭悊(HWPF) -->
+ <dependency>
+ <groupId>org.apache.poi</groupId>
+ <artifactId>poi-scratchpad</artifactId>
+ <version>${poi.version}</version>
+ </dependency>
+
<!-- velocity浠g爜鐢熸垚浣跨敤妯℃澘 -->
<dependency>
diff --git a/src/main/java/com/ruoyi/device/controller/DeviceMaintenanceController.java b/src/main/java/com/ruoyi/device/controller/DeviceMaintenanceController.java
index e34fc37..0f13f80 100644
--- a/src/main/java/com/ruoyi/device/controller/DeviceMaintenanceController.java
+++ b/src/main/java/com/ruoyi/device/controller/DeviceMaintenanceController.java
@@ -57,9 +57,15 @@
}
@PostMapping ("maintenance")
- @Operation(summary = "淇敼璁惧淇濆吇")
+ @Operation(summary = "纭璁惧淇濆吇")
public AjaxResult maintenance(@RequestBody DeviceMaintenanceDto deviceMaintenance) {
- return deviceMaintenanceService.updateDeviceDeviceMaintenance(deviceMaintenance);
+ return deviceMaintenanceService.confirmMaintenance(deviceMaintenance);
+ }
+
+ @PostMapping ("/acceptance")
+ @Operation(summary = "璁惧淇濆吇楠屾敹瀹℃壒")
+ public AjaxResult acceptance(@RequestBody DeviceMaintenanceDto deviceMaintenance) {
+ return deviceMaintenanceService.approveMaintenanceAcceptance(deviceMaintenance);
}
diff --git a/src/main/java/com/ruoyi/device/controller/MaintenanceTaskController.java b/src/main/java/com/ruoyi/device/controller/MaintenanceTaskController.java
index b6f8c27..955df5d 100644
--- a/src/main/java/com/ruoyi/device/controller/MaintenanceTaskController.java
+++ b/src/main/java/com/ruoyi/device/controller/MaintenanceTaskController.java
@@ -57,5 +57,12 @@
return maintenanceTaskService.delete(ids);
}
+ @PostMapping("/changeEnable")
+ @Operation(summary = "鍚敤/绂佺敤璁惧淇濆吇瀹氭椂浠诲姟")
+ @Log(title = "璁惧淇濆吇瀹氭椂浠诲姟", businessType = BusinessType.UPDATE)
+ public AjaxResult changeEnable(@RequestBody MaintenanceTask maintenanceTask) {
+ return maintenanceTaskService.changeEnable(maintenanceTask.getId(), maintenanceTask.getIsEnabled());
+ }
+
}
diff --git a/src/main/java/com/ruoyi/device/dto/DeviceMaintenanceDto.java b/src/main/java/com/ruoyi/device/dto/DeviceMaintenanceDto.java
index f344cb3..929603a 100644
--- a/src/main/java/com/ruoyi/device/dto/DeviceMaintenanceDto.java
+++ b/src/main/java/com/ruoyi/device/dto/DeviceMaintenanceDto.java
@@ -54,7 +54,7 @@
private String createUserName;
@Schema(description = "淇濆吇鍥剧墖")
- private List<StorageBlobDTO> storageBlobDTOs;
+ private List<StorageBlobDTO> storageBlobDTOs = new java.util.ArrayList<>();
}
diff --git a/src/main/java/com/ruoyi/device/dto/DeviceRepairDto.java b/src/main/java/com/ruoyi/device/dto/DeviceRepairDto.java
index 12def24..75bcf72 100644
--- a/src/main/java/com/ruoyi/device/dto/DeviceRepairDto.java
+++ b/src/main/java/com/ruoyi/device/dto/DeviceRepairDto.java
@@ -5,6 +5,7 @@
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
+import java.util.ArrayList;
import java.util.List;
@Data
@@ -16,5 +17,5 @@
@Schema(description = "缁翠慨鏃堕棿瀛楃涓�")
private String maintenanceTimeStr;
- private List<StorageBlobDTO> storageBlobDTOs;
+ private List<StorageBlobDTO> storageBlobDTOs = new ArrayList<>();
}
diff --git a/src/main/java/com/ruoyi/device/pojo/DeviceMaintenance.java b/src/main/java/com/ruoyi/device/pojo/DeviceMaintenance.java
index f4ebc48..c8f6728 100644
--- a/src/main/java/com/ruoyi/device/pojo/DeviceMaintenance.java
+++ b/src/main/java/com/ruoyi/device/pojo/DeviceMaintenance.java
@@ -64,9 +64,20 @@
@Schema(description = "淇濆吇缁撴灉 0 缁翠慨 1 瀹屽ソ")
private String maintenanceResult;
- @Schema(description = "鐘舵�� 0 寰呬繚鍏� 1 瀹岀粨 2 澶辫触")
+ @Schema(description = "鐘舵�� 0 寰呬繚鍏� 1 瀹岀粨 2 澶辫触 3 寰呴獙鏀�")
private Integer status;
+ @Schema(description = "楠屾敹浜�")
+ private String acceptanceName;
+
+ @Schema(description = "楠屾敹鏃堕棿")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime acceptanceTime;
+
+ @Schema(description = "楠屾敹澶囨敞")
+ private String acceptanceRemark;
+
@Schema(description = "鍒涘缓鏃堕棿")
@TableField(fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
diff --git a/src/main/java/com/ruoyi/device/pojo/MaintenanceTask.java b/src/main/java/com/ruoyi/device/pojo/MaintenanceTask.java
index 0f1e7ee..e149638 100644
--- a/src/main/java/com/ruoyi/device/pojo/MaintenanceTask.java
+++ b/src/main/java/com/ruoyi/device/pojo/MaintenanceTask.java
@@ -68,6 +68,9 @@
@Schema(description = "鏄惁婵�娲�")
private boolean isActive;
+ @Schema(description = "鏄惁鍚敤 0-绂佺敤 1-鍚敤")
+ private Integer isEnabled;
+
@Schema(description = "澶囨敞")
@Excel(name = "澶囨敞")
private String remarks;
diff --git a/src/main/java/com/ruoyi/device/service/IDeviceMaintenanceService.java b/src/main/java/com/ruoyi/device/service/IDeviceMaintenanceService.java
index e5a4080..41c6866 100644
--- a/src/main/java/com/ruoyi/device/service/IDeviceMaintenanceService.java
+++ b/src/main/java/com/ruoyi/device/service/IDeviceMaintenanceService.java
@@ -18,6 +18,10 @@
AjaxResult updateDeviceDeviceMaintenance(DeviceMaintenanceDto deviceMaintenance);
+ AjaxResult confirmMaintenance(DeviceMaintenanceDto deviceMaintenanceDto);
+
+ AjaxResult approveMaintenanceAcceptance(DeviceMaintenanceDto deviceMaintenanceDto);
+
void export(HttpServletResponse response, Long[] ids);
DeviceMaintenanceVo detailById(Long id);
diff --git a/src/main/java/com/ruoyi/device/service/MaintenanceTaskService.java b/src/main/java/com/ruoyi/device/service/MaintenanceTaskService.java
index 19cb6ed..8b4a671 100644
--- a/src/main/java/com/ruoyi/device/service/MaintenanceTaskService.java
+++ b/src/main/java/com/ruoyi/device/service/MaintenanceTaskService.java
@@ -19,4 +19,6 @@
AjaxResult updateByMaintenanceTaskId(MaintenanceTask maintenanceTask);
AjaxResult delete(List<Long> ids);
+
+ AjaxResult changeEnable(Long id, Integer isEnabled);
}
diff --git a/src/main/java/com/ruoyi/device/service/impl/DeviceMaintenanceServiceImpl.java b/src/main/java/com/ruoyi/device/service/impl/DeviceMaintenanceServiceImpl.java
index 803450a..0190984 100644
--- a/src/main/java/com/ruoyi/device/service/impl/DeviceMaintenanceServiceImpl.java
+++ b/src/main/java/com/ruoyi/device/service/impl/DeviceMaintenanceServiceImpl.java
@@ -45,6 +45,11 @@
private final FileUtil fileUtil;
private final ISysNoticeService sysNoticeService;
+ private static final int STATUS_PENDING_MAINTENANCE = 0;
+ private static final int STATUS_COMPLETED = 1;
+ private static final int STATUS_FAILED = 2;
+ private static final int STATUS_PENDING_ACCEPTANCE = 3;
+
@Override
public IPage<DeviceMaintenanceDto> queryPage(Page page, DeviceMaintenanceDto deviceMaintenanceDto) {
@@ -81,6 +86,12 @@
deviceMaintenance.setDeviceName(byId.getDeviceName());
deviceMaintenance.setDeviceModel(byId.getDeviceModel());
deviceMaintenance.setAreaId(byId.getAreaId());
+ }
+ if (deviceMaintenance.getStatus() != null
+ && deviceMaintenance.getStatus() == STATUS_COMPLETED
+ && (oldDeviceMaintenance.getStatus() == null
+ || oldDeviceMaintenance.getStatus() != STATUS_COMPLETED)) {
+ return AjaxResult.error("璇峰厛鎻愪氦楠屾敹瀹℃壒锛岄獙鏀堕�氳繃鍚庢墠鍙畬缁�");
}
// 澶勭悊澶囦欢浣跨敤鎯呭喌
if (com.github.xiaoymin.knife4j.core.util.CollectionUtils.isNotEmpty(deviceMaintenance.getSparePartsUseList())) {
@@ -156,4 +167,56 @@
vo.setStorageBlobVOs(fileUtil.getStorageBlobVOsByRecordTypeAndRecordId(RecordTypeEnum.DEVICE_MAINTENANCE, id));
return vo;
}
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public AjaxResult confirmMaintenance(DeviceMaintenanceDto deviceMaintenanceDto) {
+ DeviceMaintenance oldDeviceMaintenance = this.getById(deviceMaintenanceDto.getId());
+ if (oldDeviceMaintenance == null) {
+ return AjaxResult.error("淇濆吇璁板綍涓嶅瓨鍦�");
+ }
+ if (oldDeviceMaintenance.getStatus() != null && oldDeviceMaintenance.getStatus() == STATUS_COMPLETED) {
+ return AjaxResult.error("璇ヤ繚鍏诲凡瀹岀粨锛屼笉鑳介噸澶嶇‘璁や繚鍏�");
+ }
+ if (oldDeviceMaintenance.getStatus() != null && oldDeviceMaintenance.getStatus() == STATUS_PENDING_ACCEPTANCE) {
+ return AjaxResult.error("璇ヤ繚鍏诲凡鎻愪氦楠屾敹瀹℃壒");
+ }
+ deviceMaintenanceDto.setStatus(STATUS_PENDING_ACCEPTANCE);
+ return updateDeviceDeviceMaintenance(deviceMaintenanceDto);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public AjaxResult approveMaintenanceAcceptance(DeviceMaintenanceDto deviceMaintenanceDto) {
+ if (deviceMaintenanceDto.getId() == null) {
+ return AjaxResult.error("淇濆吇璁板綍id涓嶈兘涓虹┖");
+ }
+ DeviceMaintenance oldDeviceMaintenance = this.getById(deviceMaintenanceDto.getId());
+ if (oldDeviceMaintenance == null) {
+ return AjaxResult.error("淇濆吇璁板綍涓嶅瓨鍦�");
+ }
+ if (oldDeviceMaintenance.getStatus() == null || oldDeviceMaintenance.getStatus() != STATUS_PENDING_ACCEPTANCE) {
+ return AjaxResult.error("璇ヤ繚鍏绘湭杩涘叆寰呴獙鏀剁姸鎬侊紝涓嶈兘瀹℃壒");
+ }
+ if (StringUtils.isBlank(deviceMaintenanceDto.getAcceptanceName())) {
+ return AjaxResult.error("楠屾敹浜轰笉鑳戒负绌�");
+ }
+ if (deviceMaintenanceDto.getAcceptanceTime() == null) {
+ return AjaxResult.error("楠屾敹鏃堕棿涓嶈兘涓虹┖");
+ }
+ if (StringUtils.isBlank(deviceMaintenanceDto.getAcceptanceRemark())) {
+ return AjaxResult.error("楠屾敹澶囨敞涓嶈兘涓虹┖");
+ }
+
+ DeviceMaintenance update = new DeviceMaintenance();
+ update.setId(deviceMaintenanceDto.getId());
+ update.setAcceptanceName(deviceMaintenanceDto.getAcceptanceName());
+ update.setAcceptanceTime(deviceMaintenanceDto.getAcceptanceTime());
+ update.setAcceptanceRemark(deviceMaintenanceDto.getAcceptanceRemark());
+ update.setStatus(STATUS_COMPLETED);
+ if (this.updateById(update)) {
+ return AjaxResult.success();
+ }
+ return AjaxResult.error("楠屾敹瀹℃壒澶辫触");
+ }
}
diff --git a/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskScheduler.java b/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskScheduler.java
index ec7a8e3..6fd5a8d 100644
--- a/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskScheduler.java
+++ b/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskScheduler.java
@@ -160,6 +160,8 @@
return convertMonthlyToCron(task.getFrequencyDetail());
case "QUARTERLY":
return convertQuarterlyToCron(task.getFrequencyDetail());
+ case "YEARLY":
+ return convertYearlyToCron(task.getFrequencyDetail());
default:
throw new IllegalArgumentException("涓嶆敮鎸佺殑棰戠巼绫诲瀷: " + task.getFrequencyType());
}
@@ -204,6 +206,22 @@
quarterStartMonth);
}
+ // 姣忓勾浠诲姟杞崲
+ private String convertYearlyToCron(String frequencyDetail) {
+ String[] parts = validateAndSplit(frequencyDetail, ",", 3);
+ int month = validateMonth(parts[0]); // 楠岃瘉鏈堜唤(1-12)
+ int day = validateDayOfMonth(parts[1]); // 楠岃瘉鏃ユ湡
+ LocalTime time = parseTime(parts[2]); // 瑙f瀽鏃堕棿
+
+ // Cron琛ㄨ揪寮�: 绉� 鍒� 鏃� 鏃� 鏈� 鍛�
+ // 姣忓勾鎸囧畾鏈堜唤鐨勬寚瀹氭棩鎵ц
+ return String.format("0 %d %d %d %d ?",
+ time.getMinute(),
+ time.getHour(),
+ day,
+ month);
+ }
+
// 鏂板楠岃瘉鏈堜唤鐨勬柟娉�(1-12)
private int validateMonth(String monthStr) {
try {
diff --git a/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskServiceImpl.java b/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskServiceImpl.java
index 1450a35..8aa02aa 100644
--- a/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskServiceImpl.java
+++ b/src/main/java/com/ruoyi/device/service/impl/MaintenanceTaskServiceImpl.java
@@ -147,4 +147,47 @@
}
return AjaxResult.success("鍒犻櫎鎴愬姛");
}
+
+ @Override
+ public AjaxResult changeEnable(Long id, Integer isEnabled) {
+ MaintenanceTask oldTask = maintenanceTaskMapper.selectById(id);
+ if (oldTask == null) {
+ return AjaxResult.error("淇濆吇浠诲姟涓嶅瓨鍦�");
+ }
+
+ MaintenanceTask update = new MaintenanceTask();
+ update.setId(id);
+ update.setIsEnabled(isEnabled);
+ update.setActive(isEnabled != null && isEnabled == 1);
+
+ int result = maintenanceTaskMapper.updateById(update);
+ if (result > 0) {
+ try {
+ if (isEnabled != null && isEnabled == 1) {
+ // 鍚敤锛氭仮澶嶆垨閲嶆柊璋冨害
+ if (oldTask.getIsEnabled() != null && oldTask.getIsEnabled() == 0) {
+ // 浠庣鐢ㄦ敼涓哄惎鐢紝閲嶆柊璁$畻涓嬫鎵ц鏃堕棿锛堝鏋滄病鏈夛級
+ if (oldTask.getNextExecutionTime() == null || oldTask.getNextExecutionTime().isBefore(LocalDateTime.now())) {
+ TimingTask tempTask = new TimingTask();
+ tempTask.setFrequencyType(oldTask.getFrequencyType());
+ tempTask.setFrequencyDetail(oldTask.getFrequencyDetail());
+ LocalDateTime nextTime = timingTaskService.calculateFirstExecutionTime(tempTask);
+ update.setNextExecutionTime(nextTime);
+ maintenanceTaskMapper.updateById(update);
+ }
+ maintenanceTaskScheduler.scheduleMaintenanceTask(oldTask);
+ } else {
+ maintenanceTaskScheduler.resumeMaintenanceTask(id);
+ }
+ } else {
+ // 绂佺敤锛氭殏鍋滆皟搴�
+ maintenanceTaskScheduler.pauseMaintenanceTask(id);
+ }
+ } catch (Exception e) {
+ log.error("璋冩暣淇濆吇浠诲姟璋冨害鐘舵�佸け璐�", e);
+ }
+ return AjaxResult.success("鏇存柊鎴愬姛");
+ }
+ return AjaxResult.error("鏇存柊澶辫触");
+ }
}
diff --git a/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskScheduleUtils.java b/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskScheduleUtils.java
index 5c488d2..1200c31 100644
--- a/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskScheduleUtils.java
+++ b/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskScheduleUtils.java
@@ -33,6 +33,8 @@
return calculateMonthlyNextTime(frequencyDetail, currentTime);
case "QUARTERLY":
return calculateQuarterlyNextTime(frequencyDetail, currentTime);
+ case "YEARLY":
+ return calculateYearlyNextTime(frequencyDetail, currentTime);
default:
throw new IllegalArgumentException("涓嶆敮鎸佺殑棰戠巼绫诲瀷: " + frequencyType);
}
@@ -105,6 +107,30 @@
throw new IllegalArgumentException("鏃犳硶鎵惧埌涓嬩竴娆℃墽琛屾椂闂�");
}
+ private static LocalDateTime calculateYearlyNextTime(String detail, LocalDateTime current) {
+ String[] parts = validateAndSplit(detail, ",", 3);
+ int month = validateMonth(parts[0]);
+ int dayOfMonth = validateDayOfMonth(parts[1]);
+ LocalTime time = parseTime(parts[2]);
+
+ for (int i = 0; i < 5; i++) {
+ int year = current.getYear() + i;
+ YearMonth targetYearMonth = YearMonth.of(year, month);
+ int adjustedDay = Math.min(dayOfMonth, targetYearMonth.lengthOfMonth());
+ LocalDateTime target = LocalDateTime.of(
+ year,
+ month,
+ adjustedDay,
+ time.getHour(),
+ time.getMinute()
+ );
+ if (target.isAfter(current)) {
+ return target;
+ }
+ }
+ throw new IllegalArgumentException("鏃犳硶鎵惧埌涓嬩竴娆℃墽琛屾椂闂�");
+ }
+
private static LocalTime parseTime(String timeStr) {
try {
return LocalTime.parse(timeStr, TIME_FORMATTER);
diff --git a/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java b/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java
index 4508625..3ad8951 100644
--- a/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java
+++ b/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java
@@ -247,8 +247,11 @@
// 濡傛灉鏄瘡鏈堟墽琛岋紝璁$畻涓嬩釜鏈堢殑鍏蜂綋鏃ユ湡
return calculateMonthlyFirstExecution(task.getFrequencyDetail());
} else if ("QUARTERLY".equals(frequencyType)) {
- // 鑷畾涔夐鐜囷紝濡傛瘡灏忔椂銆佹瘡30鍒嗛挓绛�
- return calculateCustomFirstExecution(task.getFrequencyDetail());
+ // 姣忓搴︽墽琛�
+ return TimingTaskScheduleUtils.calculateFirstExecutionTime("QUARTERLY", task.getFrequencyDetail());
+ } else if ("YEARLY".equals(frequencyType)) {
+ // 姣忓勾鎵ц
+ return TimingTaskScheduleUtils.calculateFirstExecutionTime("YEARLY", task.getFrequencyDetail());
} else {
throw new IllegalArgumentException("涓嶆敮鎸佺殑棰戠巼绫诲瀷: " + task.getFrequencyType());
}
@@ -409,7 +412,9 @@
case "MONTHLY":
return calculateMonthlyNextTime(frequencyDetail, currentTime);
case "QUARTERLY":
- return calculateQuarterlyNextTime(frequencyDetail, currentTime);
+ return TimingTaskScheduleUtils.calculateNextExecutionTime("QUARTERLY", frequencyDetail, currentTime);
+ case "YEARLY":
+ return TimingTaskScheduleUtils.calculateNextExecutionTime("YEARLY", frequencyDetail, currentTime);
default:
throw new IllegalArgumentException("涓嶆敮鎸佺殑棰戠巼绫诲瀷: " + frequencyType);
}
diff --git a/src/main/java/com/ruoyi/quality/controller/QualityInspectController.java b/src/main/java/com/ruoyi/quality/controller/QualityInspectController.java
index 676c915..9e26990 100644
--- a/src/main/java/com/ruoyi/quality/controller/QualityInspectController.java
+++ b/src/main/java/com/ruoyi/quality/controller/QualityInspectController.java
@@ -130,12 +130,33 @@
qualityInspectService.qualityInspectExport(response, qualityInspect);
}
+ @GetMapping("/export/weilong/{id}")
+ @Operation(summary = "瀵煎嚭浼熼緳妯$増妫�楠岀粨鏋�")
+ @Log(title = "瀵煎嚭浼熼緳妯$増妫�楠岀粨鏋�", businessType = BusinessType.EXPORT)
+ public void exportWeiLong(HttpServletResponse response, @PathVariable("id") Long id) {
+ qualityInspectService.exportWeiLong(response, id);
+ }
+
/**
* 鎻愪氦
*
* @param qualityInspect
* @return
*/
+ @GetMapping("/export/baishi/{id}")
+ @Operation(summary = "瀵煎嚭鐧句簨妯$増妫�楠岀粨鏋�")
+ @Log(title = "瀵煎嚭鐧句簨妯$増妫�楠岀粨鏋�", businessType = BusinessType.EXPORT)
+ public void exportBaiShi(HttpServletResponse response, @PathVariable("id") Long id) {
+ qualityInspectService.exportBaiShi(response, id);
+ }
+
+ @GetMapping("/export/dali/{id}")
+ @Operation(summary = "瀵煎嚭杈惧埄妯$増妫�楠岀粨鏋�")
+ @Log(title = "瀵煎嚭杈惧埄妯$増妫�楠岀粨鏋�", businessType = BusinessType.EXPORT)
+ public void exportDaLi(HttpServletResponse response, @PathVariable("id") Long id) {
+ qualityInspectService.exportDaLi(response, id);
+ }
+
@PostMapping("/submit")
@Operation(summary = "鎻愪氦妫�楠�")
@Log(title = "鎻愪氦妫�楠�", businessType = BusinessType.OTHER)
@@ -165,4 +186,14 @@
public void down(HttpServletResponse response, @RequestBody QualityInspect qualityInspect) {
qualityInspectService.down(response, qualityInspect);
}
+
+ /**
+ * 璋冭瘯鎺ュ彛锛氬垎鏋愭ā鏉跨粨鏋�
+ */
+ @GetMapping("/analyzeTemplate")
+ @Operation(summary = "鍒嗘瀽妯℃澘缁撴瀯(璋冭瘯)")
+ public R<?> analyzeTemplate(@RequestParam String template) {
+ String templatePath = "/static/" + template + ".doc";
+ return R.ok(qualityInspectService.analyzeTemplate(templatePath));
+ }
}
diff --git a/src/main/java/com/ruoyi/quality/service/IQualityInspectService.java b/src/main/java/com/ruoyi/quality/service/IQualityInspectService.java
index 2562995..2969972 100644
--- a/src/main/java/com/ruoyi/quality/service/IQualityInspectService.java
+++ b/src/main/java/com/ruoyi/quality/service/IQualityInspectService.java
@@ -21,6 +21,12 @@
void qualityInspectExport(HttpServletResponse response, QualityInspect qualityInspect);
+ void exportWeiLong(HttpServletResponse response, Long id);
+
+ void exportBaiShi(HttpServletResponse response, Long id);
+
+ void exportDaLi(HttpServletResponse response, Long id);
+
QualityInspectDto getDetailById(Integer id);
int submit(QualityInspect qualityInspect);
@@ -33,4 +39,9 @@
R batchQuickInspect(BatchQuickInspectRequest request);
void down(HttpServletResponse response, QualityInspect qualityInspect);
+
+ /**
+ * 鍒嗘瀽妯℃澘缁撴瀯
+ */
+ String analyzeTemplate(String templatePath);
}
diff --git a/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java b/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
index effb6af..2842878 100644
--- a/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
+++ b/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
@@ -25,6 +25,7 @@
import com.ruoyi.quality.pojo.QualityInspect;
import com.ruoyi.quality.pojo.QualityInspectParam;
import com.ruoyi.quality.pojo.QualityUnqualified;
+import com.ruoyi.quality.utils.QualityInspectTemplateExportHelper;
import com.ruoyi.stock.pojo.StockInRecord;
import com.ruoyi.stock.service.StockInRecordService;
import com.ruoyi.quality.service.IQualityInspectParamService;
@@ -71,6 +72,8 @@
private SalesLedgerProductMapper salesLedgerProductMapper;
private ProcurementRecordService procurementRecordService;
+
+ private final QualityInspectTemplateExportHelper qualityInspectTemplateExportHelper;
@Override
public int add(QualityInspectDto qualityInspectDto) {
@@ -444,5 +447,24 @@
}
+ @Override
+ public void exportWeiLong(HttpServletResponse response, Long id) {
+ qualityInspectTemplateExportHelper.exportWeiLong(response, id);
+ }
+
+ @Override
+ public void exportBaiShi(HttpServletResponse response, Long id) {
+ qualityInspectTemplateExportHelper.exportBaiShi(response, id);
+ }
+
+ @Override
+ public void exportDaLi(HttpServletResponse response, Long id) {
+ qualityInspectTemplateExportHelper.exportDaLi(response, id);
+ }
+
+ @Override
+ public String analyzeTemplate(String templatePath) {
+ return qualityInspectTemplateExportHelper.analyzeTemplate(templatePath);
+ }
}
diff --git a/src/main/java/com/ruoyi/quality/utils/QualityInspectTemplateExportHelper.java b/src/main/java/com/ruoyi/quality/utils/QualityInspectTemplateExportHelper.java
new file mode 100644
index 0000000..54ad922
--- /dev/null
+++ b/src/main/java/com/ruoyi/quality/utils/QualityInspectTemplateExportHelper.java
@@ -0,0 +1,489 @@
+package com.ruoyi.quality.utils;
+
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.quality.mapper.QualityInspectMapper;
+import com.ruoyi.quality.pojo.QualityInspect;
+import com.ruoyi.quality.pojo.QualityInspectParam;
+import com.ruoyi.quality.service.IQualityInspectParamService;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.poi.hwpf.HWPFDocument;
+import org.apache.poi.hwpf.usermodel.Range;
+import org.apache.poi.hwpf.usermodel.Table;
+import org.apache.poi.hwpf.usermodel.TableCell;
+import org.apache.poi.hwpf.usermodel.TableIterator;
+import org.apache.poi.hwpf.usermodel.TableRow;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Word template export helper for process inspection.
+ */
+@Component
+@RequiredArgsConstructor
+public class QualityInspectTemplateExportHelper {
+
+ private static final String WEILONG_TEMPLATE = "/static/浼熼緳妯$増.doc";
+ private static final String BAISHI_TEMPLATE = "/static/鐧句簨妯$増.doc";
+ private static final String DALI_TEMPLATE = "/static/杈惧埄妯$増.doc";
+
+ private final QualityInspectMapper qualityInspectMapper;
+ private final IQualityInspectParamService qualityInspectParamService;
+
+ public void exportWeiLong(HttpServletResponse response, Long inspectId) {
+ export(response, inspectId, WEILONG_TEMPLATE, "浼熼緳妯$増妫�楠岀粨鏋�");
+ }
+
+ public void exportBaiShi(HttpServletResponse response, Long inspectId) {
+ export(response, inspectId, BAISHI_TEMPLATE, "鐧句簨妯$増妫�楠岀粨鏋�");
+ }
+
+ public void exportDaLi(HttpServletResponse response, Long inspectId) {
+ export(response, inspectId, DALI_TEMPLATE, "杈惧埄妯$増妫�楠岀粨鏋�");
+ }
+
+ private void export(HttpServletResponse response, Long inspectId, String templatePath, String fileName) {
+ if (inspectId == null) {
+ throw new ServiceException("妫�楠屽崟ID涓嶈兘涓虹┖");
+ }
+
+ QualityInspect inspect = qualityInspectMapper.selectById(inspectId);
+ if (inspect == null) {
+ throw new ServiceException("妫�楠屽崟涓嶅瓨鍦�");
+ }
+
+ List<QualityInspectParam> paramList = qualityInspectParamService.list(
+ Wrappers.<QualityInspectParam>lambdaQuery()
+ .eq(QualityInspectParam::getInspectId, inspectId)
+ .orderByAsc(QualityInspectParam::getId));
+ Map<String, String> valueMap = buildValueMap(paramList, inspect);
+
+ try (InputStream inputStream = getClass().getResourceAsStream(templatePath)) {
+ if (inputStream == null) {
+ throw new ServiceException("妯℃澘鏂囦欢涓嶅瓨鍦細" + templatePath);
+ }
+
+ HWPFDocument document = new HWPFDocument(inputStream);
+ fillDocument(document, valueMap);
+
+ response.reset();
+ response.setContentType("application/msword");
+ response.setCharacterEncoding("UTF-8");
+ String encodedName = URLEncoder.encode(fileName, StandardCharsets.UTF_8).replace("+", "%20");
+ response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
+ response.setHeader("Content-Disposition", "attachment;filename=" + encodedName + ".doc");
+
+ try (OutputStream outputStream = response.getOutputStream()) {
+ document.write(outputStream);
+ outputStream.flush();
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("瀵煎嚭澶辫触", e);
+ }
+ }
+
+ private void fillDocument(HWPFDocument document, Map<String, String> valueMap) {
+ Range range = document.getRange();
+ TableIterator iterator = new TableIterator(range);
+ while (iterator.hasNext()) {
+ Table table = iterator.next();
+ fillTable(table, valueMap);
+ }
+ }
+
+ private void fillTable(Table table, Map<String, String> valueMap) {
+ String currentGroupLabel = "";
+ // 璁板綍缁撹鍒楃殑浣嶇疆锛岄伩鍏嶅湪缁撹鍒椾笅闈㈢户缁~鍏�
+ int conclusionCellIndex = -1;
+
+ for (int rowIndex = 0; rowIndex < table.numRows(); rowIndex++) {
+ TableRow row = table.getRow(rowIndex);
+ String firstCellText = getCellText(row, 0);
+ String secondCellText = getCellText(row, 1);
+
+ if (StringUtils.isNotBlank(firstCellText)) {
+ currentGroupLabel = firstCellText;
+ }
+
+ // 鍏堝垽鏂槸鍚︿负缁撹琛�
+ String normalizedFirstCell = normalizeKey(firstCellText);
+ boolean isConclusionRow = matchesSummaryRow(normalizedFirstCell);
+
+ // 濡傛灉鏄粨璁鸿锛岀粨璁哄垪濮嬬粓鏄渶鍚庝竴鍒�
+ if (isConclusionRow) {
+ conclusionCellIndex = row.numCells() - 1;
+ }
+
+ String value = resolveValue(valueMap, currentGroupLabel, firstCellText, secondCellText, isConclusionRow);
+ if (StringUtils.isBlank(value)) {
+ continue;
+ }
+
+ // 鏌ユ壘缁撴灉鍒椾綅缃�
+ int resultCellIndex;
+ if (isConclusionRow) {
+ resultCellIndex = conclusionCellIndex;
+ } else {
+ // 鏅�氳锛氭壘绗竴涓┖鐧藉崟鍏冩牸浣滀负缁撴灉鍒楋紝浣嗚鎺掗櫎缁撹鍒�
+ resultCellIndex = findResultCellIndex(row, conclusionCellIndex);
+ if (resultCellIndex < 0) {
+ // 涓嶄娇鐢ㄦ渶鍚庝竴鍒楋紝閬垮厤涓庣粨璁哄垪鍐茬獊
+ int lastCellIndex = row.numCells() - 1;
+ if (lastCellIndex > 1 && lastCellIndex != conclusionCellIndex) {
+ resultCellIndex = lastCellIndex - 1;
+ }
+ }
+ }
+
+ if (resultCellIndex < 0 || resultCellIndex == conclusionCellIndex && !isConclusionRow) {
+ continue;
+ }
+
+ TableCell resultCell = row.getCell(resultCellIndex);
+ String cellText = cleanCellText(resultCell.text());
+
+ // 涓ユ牸妫�鏌ワ細鍙湁绌虹櫧鎴栧崰浣嶇鎵嶅~鍏�
+ if (!isBlankLike(cellText) && !isPlaceholder(cellText)) {
+ continue;
+ }
+
+ // 浣跨敤鏇村畨鍏ㄧ殑濉厖鏂瑰紡
+ safeWriteCellText(resultCell, value);
+ }
+ }
+
+ /**
+ * 鏌ユ壘缁撴灉鍒楋紝鎺掗櫎缁撹鍒�
+ */
+ private int findResultCellIndex(TableRow row, int excludeIndex) {
+ for (int i = 1; i < row.numCells(); i++) {
+ if (i == excludeIndex) {
+ continue;
+ }
+ String cellText = cleanCellText(row.getCell(i).text());
+ if (isBlankLike(cellText) || isPlaceholder(cellText)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * 瀹夊叏鍐欏叆鍗曞厓鏍兼枃鏈紝閬垮厤褰卞搷鍏朵粬琛�
+ */
+ private void safeWriteCellText(TableCell cell, String value) {
+ if (StringUtils.isBlank(value)) {
+ return;
+ }
+
+ String originalText = cell.text();
+ String cleanedOriginal = cleanCellText(originalText);
+
+ // 濡傛灉鍗曞厓鏍煎凡鏈夊唴瀹逛笖涓嶆槸鍗犱綅绗︼紝涓嶅啓鍏�
+ if (StringUtils.isNotBlank(cleanedOriginal) && !isPlaceholder(cleanedOriginal)) {
+ return;
+ }
+
+ // 鍙娇鐢╮eplaceText锛屼笉浣跨敤insertBefore
+ try {
+ if (StringUtils.isNotBlank(originalText)) {
+ cell.replaceText(originalText, value);
+ } else {
+ // 绌哄崟鍏冩牸鐩存帴璁剧疆鏂囨湰
+ cell.insertBefore(value);
+ }
+ } catch (Exception e) {
+ // 澶囩敤鏂规锛氫娇鐢╣etRange鏂瑰紡
+ try {
+// cell.getRange().insertAfter(value);
+ } catch (Exception ignored) {}
+ }
+ }
+
+ /**
+ * 鍒ゆ柇鏄惁涓哄崰浣嶇
+ */
+ private boolean isPlaceholder(String text) {
+ if (StringUtils.isBlank(text)) {
+ return false;
+ }
+ String cleaned = text.trim();
+ // 甯歌鍗犱綅绗︽ā寮�
+ return cleaned.equals("鈥�") ||
+ cleaned.equals("-") ||
+ cleaned.equals("_") ||
+ cleaned.equals("/") ||
+ cleaned.equals("\\") ||
+ cleaned.equals("鈻�") ||
+ cleaned.equals("鈻�") ||
+ cleaned.equals("鈼�") ||
+ cleaned.equals("鈼�") ||
+ cleaned.equals("鈥�") ||
+ cleaned.equals("*") ||
+ cleaned.matches("^\\.{2,}$") || // 澶氫釜鐐�
+ cleaned.matches("^{2,}$") || // 澶氫釜澶ф嫭鍙�
+ cleaned.equalsIgnoreCase("N/A") ||
+ cleaned.equalsIgnoreCase("NA") ||
+ cleaned.equals("寰呮") ||
+ cleaned.equals("寰呭~") ||
+ cleaned.equals("绌虹櫧");
+ }
+
+ private int findResultCellIndex(TableRow row) {
+ for (int i = 1; i < row.numCells(); i++) {
+ if (isBlankLike(row.getCell(i).text())) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private String resolveValue(Map<String, String> valueMap,
+ String currentGroupLabel,
+ String firstCellText,
+ String secondCellText,
+ boolean isConclusionRow) {
+ LinkedHashSet<String> candidates = new LinkedHashSet<>();
+ addCandidate(candidates, firstCellText);
+ addCandidate(candidates, secondCellText);
+ addCandidate(candidates, firstCellText + secondCellText);
+ if (StringUtils.isNotBlank(currentGroupLabel) && StringUtils.isNotBlank(secondCellText)) {
+ addCandidate(candidates, currentGroupLabel + secondCellText);
+ }
+ if (StringUtils.isNotBlank(currentGroupLabel)
+ && StringUtils.isNotBlank(firstCellText)
+ && StringUtils.isBlank(secondCellText)) {
+ addCandidate(candidates, currentGroupLabel);
+ }
+
+
+ // 缁撹琛屼笉濉厖锛屼繚鐣欐ā鏉垮師濮嬫暟鎹�
+ if (isConclusionRow) {
+ return null;
+ }
+
+ // 鏅�氳锛氬厛鏌ユ楠屽弬鏁板�硷紝鏈�鍚庢墠鍖归厤缁撹琛屽叧閿瘝
+ for (String candidate : candidates) {
+ String normalized = normalizeKey(candidate);
+ // 鏅�氳璺宠繃缁撹鍏抽敭璇嶅尮閰�
+ if (matchesSummaryRow(normalized)) {
+ continue;
+ }
+ String value = lookupValue(valueMap, normalized);
+ if (StringUtils.isNotBlank(value)) {
+ return value;
+ }
+ }
+
+ return null;
+ }
+
+ private boolean matchesSummaryRow(String normalizedText) {
+ if (StringUtils.isBlank(normalizedText)) {
+ return false;
+ }
+ return normalizedText.contains("璐ㄩ噺璇勫畾")
+ || normalizedText.contains("妫�楠岀粨璁�")
+ || normalizedText.contains("Gradeestimation")
+ || normalizedText.contains("Conclusion")
+ || normalizedText.contains("Evaluation")
+ || normalizedText.contains("璇勫畾")
+ || normalizedText.contains("缁撹");
+ }
+
+ private String lookupValue(Map<String, String> valueMap, String normalizedCandidate) {
+ if (StringUtils.isBlank(normalizedCandidate)) {
+ return null;
+ }
+
+ String value = valueMap.get(normalizedCandidate);
+ if (StringUtils.isNotBlank(value)) {
+ return value;
+ }
+
+ String chineseCandidate = stripEnglishLetters(normalizedCandidate);
+ value = valueMap.get(chineseCandidate);
+ if (StringUtils.isNotBlank(value)) {
+ return value;
+ }
+
+ for (Map.Entry<String, String> entry : valueMap.entrySet()) {
+ String key = entry.getKey();
+ if (StringUtils.contains(key, normalizedCandidate)
+ || StringUtils.contains(normalizedCandidate, key)
+ || StringUtils.contains(key, chineseCandidate)
+ || StringUtils.contains(chineseCandidate, key)) {
+ return entry.getValue();
+ }
+ }
+ return null;
+ }
+
+ private Map<String, String> buildValueMap(List<QualityInspectParam> paramList, QualityInspect inspect) {
+ Map<String, String> valueMap = new LinkedHashMap<>();
+ for (QualityInspectParam param : paramList) {
+ String value = StringUtils.trimToNull(param.getTestValue());
+ if (StringUtils.isBlank(value)) {
+ continue;
+ }
+ putValue(valueMap, param.getParameterItem(), value);
+ }
+
+ String checkResult = StringUtils.trimToNull(inspect.getCheckResult());
+ if (StringUtils.isNotBlank(checkResult)) {
+ putValue(valueMap, "璐ㄩ噺璇勫畾", checkResult);
+ putValue(valueMap, "妫�楠岀粨鏋�", checkResult);
+ putValue(valueMap, "妫�楠岀粨璁�", checkResult);
+ putValue(valueMap, "Grade estimation", checkResult);
+ putValue(valueMap, "Test Results", checkResult);
+ }
+ return valueMap;
+ }
+
+ private void putValue(Map<String, String> valueMap, String key, String value) {
+ String normalizedKey = normalizeKey(key);
+ if (StringUtils.isBlank(normalizedKey)) {
+ return;
+ }
+ valueMap.put(normalizedKey, value);
+
+ String chineseKey = stripEnglishLetters(normalizedKey);
+ if (StringUtils.isNotBlank(chineseKey)) {
+ valueMap.putIfAbsent(chineseKey, value);
+ }
+ }
+
+ private void writeCellText(TableCell cell, String value) {
+ if (StringUtils.isBlank(value)) {
+ return;
+ }
+
+ String originalText = cell.text();
+ try {
+ cell.replaceText(originalText, value);
+ } catch (Exception ignored) {
+ // Fallback below.
+ }
+
+ String cleanedText = cleanCellText(cell.text());
+ if (!cleanedText.contains(value)) {
+ cell.insertBefore(value);
+ }
+ }
+
+ private String getCellText(TableRow row, int index) {
+ if (row.numCells() <= index) {
+ return "";
+ }
+ return cleanCellText(row.getCell(index).text());
+ }
+
+ private String cleanCellText(String text) {
+ if (text == null) {
+ return "";
+ }
+ return text.replace("\u0007", "")
+ .replace("\r", "")
+ .replace("\n", "")
+ .trim();
+ }
+
+ private boolean isBlankLike(String text) {
+ String cleaned = cleanCellText(text);
+ return StringUtils.isBlank(cleaned)
+ || "-".equals(cleaned)
+ || "_".equals(cleaned)
+ || "鈥�".equals(cleaned)
+ || "路".equals(cleaned);
+ }
+
+ private void addCandidate(LinkedHashSet<String> candidates, String text) {
+ if (StringUtils.isBlank(text)) {
+ return;
+ }
+ candidates.add(text);
+ }
+
+ private String normalizeKey(String text) {
+ String value = cleanCellText(text);
+ if (StringUtils.isBlank(value)) {
+ return "";
+ }
+ value = value.replace("\u00A0", "");
+ value = value.replaceAll("\\s+", "");
+ value = value.replace("锛�", "");
+ value = value.replace("锛�", "");
+ value = value.replace("(", "");
+ value = value.replace(")", "");
+ value = value.replace("锛�", "");
+ value = value.replace(",", "");
+ value = value.replace("銆�", "");
+ value = value.replace("锛�", "");
+ value = value.replace(":", "");
+ value = value.replace("锛�", "");
+ value = value.replace(";", "");
+ value = value.replace("銆�", "");
+ value = value.replace("鈥�", "");
+ value = value.replace("鈥�", "");
+ value = value.replace("銆�", "");
+ value = value.replace("銆�", "");
+ value = value.replace("%", "");
+ return value;
+ }
+
+ private String stripEnglishLetters(String text) {
+ if (StringUtils.isBlank(text)) {
+ return "";
+ }
+ return text.replaceAll("[A-Za-z]", "");
+ }
+
+ /**
+ * 璋冭瘯鏂规硶锛氬垎鏋愭ā鏉胯〃鏍肩粨鏋�
+ */
+ public String analyzeTemplate(String templatePath) {
+ StringBuilder sb = new StringBuilder();
+ try (InputStream inputStream = getClass().getResourceAsStream(templatePath)) {
+ if (inputStream == null) {
+ return "妯℃澘鏂囦欢涓嶅瓨鍦細" + templatePath;
+ }
+
+ HWPFDocument document = new HWPFDocument(inputStream);
+ Range range = document.getRange();
+ TableIterator iterator = new TableIterator(range);
+
+ int tableIndex = 0;
+ while (iterator.hasNext()) {
+ Table table = iterator.next();
+ sb.append("=== 琛ㄦ牸 ").append(tableIndex++).append(" ===\n");
+ sb.append("琛屾暟: ").append(table.numRows()).append("\n");
+
+ for (int rowIndex = 0; rowIndex < table.numRows(); rowIndex++) {
+ TableRow row = table.getRow(rowIndex);
+ sb.append("琛�").append(rowIndex).append(": ");
+ for (int cellIndex = 0; cellIndex < row.numCells(); cellIndex++) {
+ String cellText = cleanCellText(row.getCell(cellIndex).text());
+ sb.append("[鍒�").append(cellIndex).append(": ").append(cellText).append("] ");
+ }
+ sb.append("\n");
+ }
+ sb.append("\n");
+ }
+ } catch (Exception e) {
+ sb.append("鍒嗘瀽澶辫触: ").append(e.getMessage());
+ }
+ return sb.toString();
+ }
+}
diff --git a/src/main/resources/mapper/device/DeviceMaintenanceMapper.xml b/src/main/resources/mapper/device/DeviceMaintenanceMapper.xml
index a25d13a..995c16a 100644
--- a/src/main/resources/mapper/device/DeviceMaintenanceMapper.xml
+++ b/src/main/resources/mapper/device/DeviceMaintenanceMapper.xml
@@ -13,6 +13,9 @@
dm.maintenance_actually_time,
dm.maintenance_result,
dm.status,
+ dm.acceptance_name,
+ dm.acceptance_time,
+ dm.acceptance_remark,
dm.create_time,
dm.update_time,
dm.create_user,
@@ -65,6 +68,9 @@
dm.maintenance_actually_time,
dm.maintenance_result,
dm.status,
+ dm.acceptance_name,
+ dm.acceptance_time,
+ dm.acceptance_remark,
dm.create_time,
dm.update_time,
dm.create_user,
diff --git "a/src/main/resources/static/\344\274\237\351\276\231\346\250\241\347\211\210.doc" "b/src/main/resources/static/\344\274\237\351\276\231\346\250\241\347\211\210.doc"
new file mode 100644
index 0000000..5d5eba9
--- /dev/null
+++ "b/src/main/resources/static/\344\274\237\351\276\231\346\250\241\347\211\210.doc"
Binary files differ
diff --git "a/src/main/resources/static/\347\231\276\344\272\213\346\250\241\347\211\210.doc" "b/src/main/resources/static/\347\231\276\344\272\213\346\250\241\347\211\210.doc"
new file mode 100644
index 0000000..521a62e
--- /dev/null
+++ "b/src/main/resources/static/\347\231\276\344\272\213\346\250\241\347\211\210.doc"
Binary files differ
diff --git "a/src/main/resources/static/\350\276\276\345\210\251\346\250\241\347\211\210.doc" "b/src/main/resources/static/\350\276\276\345\210\251\346\250\241\347\211\210.doc"
new file mode 100644
index 0000000..4a9e75c
--- /dev/null
+++ "b/src/main/resources/static/\350\276\276\345\210\251\346\250\241\347\211\210.doc"
Binary files differ
--
Gitblit v1.9.3