diff --git a/.onedev-buildspec.yml b/.onedev-buildspec.yml deleted file mode 100644 index dc9f815..0000000 --- a/.onedev-buildspec.yml +++ /dev/null @@ -1,76 +0,0 @@ -version: 8 -jobs: - - name: Build and Deploy mqtt_power on myagent - agentMatcher: name_is("myagent") # 确保 "myagent" 是您 OneDev 中 agent 的确切名称 - # 如果 myagent 是通过标签选择的,请使用类似 agentMatcher: has_tag("your-agent-tag") 的形式 - jobSecrets: # <-- 添加此部分以声明 Job 需要的 Secrets - - name: DB_ROOT_PASSWORD - - name: DB_NAME - - name: DB_USER - - name: DB_PASSWORD - - name: MQTT_USER - - name: MQTT_PASSWORD - steps: - - checkout # OneDev 会自动检出与触发事件相关的代码 - - group: "Prepare Environment and Build" - steps: - - shell: "sh" # 或者 powershell -Command,取决于您的 agent 环境 - # 如果 agent 是 Windows,并且您希望使用 PowerShell,请将 shell 改为 "powershell" - # 并在下面的 commands 中使用 PowerShell 语法 - commands: | - echo "Running on agent: $ONEDEV_AGENT_NAME" - echo "Workspace: $ONEDEV_WORKSPACE" - - echo "Generating .env file for Docker Compose..." - # 使用 @secret:SECRET_NAME@ 语法从 OneDev Job Secrets 获取值 - # 确保在 OneDev 项目的 Job Secrets 中定义了这些 secret,并且名称与此处一致 - echo "MYSQL_ROOT_PASSWORD=@secret:DB_ROOT_PASSWORD@" > .env - echo "MYSQL_DATABASE=@secret:DB_NAME@" >> .env - echo "MYSQL_USER=@secret:DB_USER@" >> .env - echo "MYSQL_PASSWORD=@secret:DB_PASSWORD@" >> .env - - echo "SPRING_DATASOURCE_URL=jdbc:mysql://mysql-db:3306/@secret:DB_NAME@?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false" >> .env - echo "SPRING_DATASOURCE_USERNAME=@secret:DB_USER@" >> .env - echo "SPRING_DATASOURCE_PASSWORD=@secret:DB_PASSWORD@" >> .env - - echo "SPRING_MQTT_BROKER_HOST=emqx-broker" >> .env # docker-compose 服务名 - echo "SPRING_MQTT_BROKER_PORT=1883" >> .env - echo "SPRING_MQTT_USERNAME=@secret:MQTT_USER@" >> .env - echo "SPRING_MQTT_PASSWORD=@secret:MQTT_PASSWORD@" >> .env - # 使用 $ONEDEV_BUILD_NUMBER 保证客户端 ID 唯一性 - echo "SPRING_MQTT_CLIENT_ID_BACKEND=springboot-mqtt-client-backend-$ONEDEV_BUILD_NUMBER" >> .env - echo "SPRING_MQTT_LOG_CLIENT_ID=springboot-mqtt-log-client-$ONEDEV_BUILD_NUMBER" >> .env - - echo ".env file generated." - # cat .env # 可选: 在构建日志中打印 .env 内容以供调试 - - echo "Ensuring docker-compose.yml is present..." - if [ ! -f docker-compose.yml ]; then - echo "ERROR: docker-compose.yml not found in workspace root ($ONEDEV_WORKSPACE/docker-compose.yml)!" - exit 1 - fi - - echo "Stopping existing services (if any)..." - docker-compose -f docker-compose.yml down --remove-orphans || echo "No services were running or an error occurred during down, continuing..." - - echo "Building Docker images locally for springboot-app and nextjs-app..." - # 确保 docker-compose.yml 中的 build context 指向正确 - # 例如: springboot-init-main 和 charging_web_app - # 并且服务名称 'springboot-app' 和 'nextjs-app' 与 docker-compose.yml 中的定义一致 - docker-compose -f docker-compose.yml build --no-cache springboot-app nextjs-app - - echo "Starting all services via Docker Compose..." - docker-compose -f docker-compose.yml up -d - - echo "Deployment process finished." - docker-compose -f docker-compose.yml ps # 显示正在运行的服务状态 - triggers: - - type: "BRANCH_UPDATE" # 当分支有代码推送时触发 - params: - branches: "main,master" # 监听的分支,请根据您的实际主分支名称修改 - # paths: # 可选:仅当特定路径下的文件发生变化时才触发 - # includes: - # - "springboot-init-main/**" - # - "charging_web_app/**" - # - "docker-compose.yml" - # - ".onedev-buildspec.yml" \ No newline at end of file diff --git a/LogBook.md b/docs/系统开发日志/LogBook.md similarity index 100% rename from LogBook.md rename to docs/系统开发日志/LogBook.md diff --git a/LogBook4.md b/docs/系统开发日志/LogBook4.md similarity index 100% rename from LogBook4.md rename to docs/系统开发日志/LogBook4.md diff --git a/LogBook_Phase1.md b/docs/系统开发日志/LogBook_Phase1.md similarity index 100% rename from LogBook_Phase1.md rename to docs/系统开发日志/LogBook_Phase1.md diff --git a/LogBook_Phase2-3.md b/docs/系统开发日志/LogBook_Phase2-3.md similarity index 100% rename from LogBook_Phase2-3.md rename to docs/系统开发日志/LogBook_Phase2-3.md diff --git a/springboot-init-main/doc/development_stages/stage_5_admin_session_management.md b/springboot-init-main/doc/development_stages/stage_5_admin_session_management.md new file mode 100644 index 0000000..86414e1 --- /dev/null +++ b/springboot-init-main/doc/development_stages/stage_5_admin_session_management.md @@ -0,0 +1,203 @@ +# 第五阶段:管理员会话管理功能开发方案 + +## 1. 目标与范围 + +### 1.1. 目标 +为系统管理员提供对充电会话(Charging Sessions)的全面查看、监控和有限管理能力,以确保系统运营的透明度和可控性。 + +### 1.2. 功能范围 +* **查询与浏览 (Read)**: + * 分页列出所有充电会话。 + * 支持多种条件筛选(如用户、机器人、车位、状态、时间范围等)。 + * 支持按关键字段排序。 + * 查看单个充电会话的完整详细信息。 +* **更新 (Update)**: + * **谨慎引入**。主要考虑场景:对异常会话进行状态纠正(例如,系统未能自动更新的会话,管理员可手动标记为 `ERROR` 或 `CANCELLED_BY_SYSTEM`)。 + * 所有手动更新操作必须记录详细的操作审计日志(操作人、时间、原因、变更前后状态)。 +* **删除 (Delete)**: + * **谨慎引入**。通常仅支持逻辑删除,用于隐藏无效或测试产生的会话数据。 + * 物理删除会话记录通常不推荐,以保证数据完整性和可追溯性。 +* **创建 (Create)**: + * 管理员**不直接创建**充电会话。会话由用户通过前端发起,或由系统在特定业务流程中自动创建。 + +### 1.3. 非范围 +* 自动化的会话处理逻辑(这部分属于核心业务模块,已在第三阶段实现)。 +* 复杂的统计报表(可作为后续独立模块)。 + +## 2. 后端实现 (`springboot-init-main`) + +### 2.1. 数据模型 (Entity, VO, DTO) +* **Entity**: `com.yupi.project.model.entity.ChargingSession` (已存在) + * 确认所有必要字段已包含,参考 `mqtt_power.sql` 中的 `charging_session` 表。 +* **View Object (VO)**: `com.yupi.project.model.vo.ChargingSessionAdminVO` (如果现有VO不满足,则创建或增强) + * 在现有 `ChargingSessionVO` 基础上,确保包含以下信息,或提供途径方便前端获取: + * `id` (会话ID) + * `userId` + * `username` (关联查询 `user` 表得到) + * `robotId` + * `robotUidSnapshot` (来自 `charging_session` 表) + * `spotId` + * `spotUidSnapshot` (来自 `charging_session` 表) + * `status` (会话状态) + * `requestTime`, `chargeStartTime`, `chargeEndTime` + * `totalDurationSeconds` + * `energyConsumedKwh` + * `cost` + * `paymentStatus` + * `errorCode`, `errorMessage` + * `relatedRobotTaskId` + * `createTime`, `updateTime` +* **Data Transfer Object (DTO)**: + * `com.yupi.project.model.dto.chargingsession.ChargingSessionAdminQueryRequest`: (可基于现有 `PageRequest` 扩展) + * 分页参数 (`current`, `pageSize`) + * 筛选条件: + * `userId` (Long) + * `username` (String, 支持模糊查询) + * `robotUid` (String, 支持模糊查询) + * `spotUid` (String, 支持模糊查询) + * `status` (String, 对应 `ChargingSessionStatusEnum`) + * `paymentStatus` (String, 对应 `PaymentStatusEnum`) + * `requestTimeStart`, `requestTimeEnd` (Date or String) + * `chargeEndTimeStart`, `chargeEndTimeEnd` (Date or String) + * `id` (Long, 精确查询会话ID) + * 排序字段 (`sortField`, 例如 `createTime`, `cost`) + * 排序顺序 (`sortOrder`, `ascend` 或 `descend`) + * `com.yupi.project.model.dto.chargingsession.ChargingSessionAdminUpdateStatusRequest`: + * `newStatus` (String, 对应 `ChargingSessionStatusEnum`) + * `reason` (String, 管理员操作原因) + +### 2.2. Service 层 (`com.yupi.project.service.ChargingSessionService`) +* **Read (查询)**: + * `Page pageAdminSessions(ChargingSessionAdminQueryRequest queryRequest)`: + * 实现复杂条件组合查询、分页和排序。 + * 内部需要调用 `UserMapper` 或 `UserService` 来根据 `userId` 填充 `username` 到 `ChargingSessionAdminVO`。 + * (此功能可能部分已由现有 `/admin/session/list/page` 接口的 Service 方法覆盖,需检查并增强)。 + * `ChargingSessionAdminVO getAdminSessionDetailsById(Long sessionId)`: + * 获取单个会话的详细信息,并转换为 `ChargingSessionAdminVO`。 +* **Update (更新)**: + * `boolean adminUpdateSessionStatus(Long sessionId, ChargingSessionStatusEnum newStatus, String reason, Long adminUserId)`: + * 检查会话是否存在。 + * 校验状态转换的合法性(例如,不能将已完成的会话改回进行中)。 + * 更新会话状态、`update_time`。 + * 记录操作日志(可考虑引入操作日志表或利用现有日志框架)。 + * `adminUserId` 用于审计。 +* **Delete (删除)**: + * `boolean adminMarkSessionAsDeleted(Long sessionId, Long adminUserId)`: + * 逻辑删除,设置 `is_deleted = 1`。 + * 记录操作日志。 + +### 2.3. Controller 层 (`com.yupi.project.controller.ChargingSessionAdminController`) +* `POST /api/admin/session/list/page`: (已存在,需审视是否需要修改请求体和响应体以满足 `ChargingSessionAdminQueryRequest` 和 `Page`) + * 调用 `chargingSessionService.pageAdminSessions(queryRequest)`。 + * 权限: `@AuthCheck(mustRole = UserConstant.ADMIN_ROLE)`。 +* `GET /api/admin/session/{sessionId}`: + * 调用 `chargingSessionService.getAdminSessionDetailsById(sessionId)`。 + * 权限: `@AuthCheck(mustRole = UserConstant.ADMIN_ROLE)`。 +* `PUT /api/admin/session/{sessionId}/status`: + * 请求体: `ChargingSessionAdminUpdateStatusRequest` + * 调用 `chargingSessionService.adminUpdateSessionStatus(sessionId, newStatus, reason, adminUserId)`。 + * `adminUserId` 从当前登录用户上下文获取。 + * 权限: `@AuthCheck(mustRole = UserConstant.ADMIN_ROLE)`。 +* `DELETE /api/admin/session/{sessionId}`: + * 调用 `chargingSessionService.adminMarkSessionAsDeleted(sessionId, adminUserId)`。 + * 权限: `@AuthCheck(mustRole = UserConstant.ADMIN_ROLE)`。 + +## 3. 前端实现 (`charging_web_app`) + +### 3.1. 页面与路由 +* **主页面**: `src/app/(authenticated)/admin/sessions/page.tsx` + * 此页面已在 `AdminDashboardPage` 中有导航链接,需具体实现。 + +### 3.2. UI 组件 (Ant Design) +* `Card`: 用于整体布局和分块。 +* `Form`, `Input`, `Select`, `DatePicker`, `Button`: 用于构建查询筛选表单。 +* `Table`: 用于展示会话列表,支持分页、排序。 +* `Modal`: 用于展示会话详情、执行状态更新操作。 +* `Tag`: 用于美化状态显示。 +* `Tooltip`, `Typography.Text`: 用于辅助信息展示。 +* `Descriptions`: 用于在详情模态框中展示会话信息。 +* `Popconfirm`: 用于删除或敏感操作前的确认。 +* `message`, `notification`: 用于操作结果反馈。 + +### 3.3. 主要功能实现 +* **列表展示**: + * **数据获取**: 调用后端 `/api/admin/session/list/page` 接口。 + * **列定义**: 参考 `ChargingSessionAdminVO`,合理展示关键信息,例如:会话ID, 用户名, 机器人UID, 车位UID, 请求时间, 开始时间, 结束时间, 总时长, 费用, 会话状态 (Tag), 支付状态 (Tag), 操作。 + * **分页**: 实现前端分页组件与后端分页数据的同步。 + * **排序**: 表格列头点击排序,将排序参数传递给后端。 + * **操作列**: + * "详情"按钮:点击打开会话详情模态框。 + * "修改状态"按钮 (如果实现该功能):打开状态修改模态框。 + * "删除"按钮 (如果实现该功能):触发删除确认。 +* **查询筛选**: + * 表单元素对应 `ChargingSessionAdminQueryRequest` 中的筛选字段。 + * "查询"按钮触发 API 请求,更新表格数据。 + * "重置"按钮清除筛选条件并重新加载数据。 +* **会话详情 (Modal)**: + * 调用后端 `/api/admin/session/{sessionId}` 接口获取数据。 + * 使用 `Descriptions` 组件清晰展示所有会话信息。 +* **修改状态 (Modal)** (如果实现): + * 表单包含可选的新状态和操作原因。 + * 提交时调用后端 `/api/admin/session/{sessionId}/status` 接口。 +* **删除会话** (如果实现): + * 使用 `Popconfirm` 提示。 + * 确认后调用后端 `DELETE /api/admin/session/{sessionId}` 接口。 + +### 3.4. API 服务层 +* 在 `charging_web_app/src/services/` 目录下创建 `sessionAdminService.ts` (或类似名称)。 +* 封装对上述后端管理员会话管理 API 的调用函数。 + * `fetchAdminSessions(query: ChargingSessionAdminQueryRequest): Promise>>` + * `fetchAdminSessionDetails(sessionId: number): Promise>` + * `updateAdminSessionStatus(sessionId: number, data: ChargingSessionAdminUpdateStatusRequest): Promise>` + * `deleteAdminSession(sessionId: number): Promise>` + +### 3.5. 状态管理 (React Context / Zustand / Redux Toolkit - 根据项目现有方式) +* 管理会话列表数据、加载状态、错误信息。 +* 管理分页参数 (`current`, `pageSize`, `total`)。 +* 管理筛选表单的条件。 +* 管理模态框的显示/隐藏状态及当前操作的会话数据。 + +## 4. 数据库变更 +* 当前 `charging_session` 表结构基本满足需求。 +* **可选**: 如果需要详细的管理员操作审计,可以考虑新增一个 `admin_operation_log` 表,记录管理员对会话等关键数据的修改操作。 + +## 5. 测试要点 +* **后端**: + * 各 API 接口的参数校验、权限控制。 + * 筛选条件(特别是组合条件和边界值)的正确性。 + * 分页和排序逻辑的正确性。 + * 状态更新和删除操作的业务逻辑和数据一致性。 + * 并发操作下的数据准确性(如果适用)。 +* **前端**: + * 页面数据能否正确加载和展示。 + * 查询、分页、排序功能是否按预期工作。 + * 操作按钮(详情、修改、删除)的交互和功能是否正常。 + * 表单校验和用户提示。 + * 不同屏幕尺寸下的响应式布局。 +* **整体**: + * 数据在前后端之间的一致性。 + * 错误处理和用户友好提示。 + +## 6. 开发阶段与交付物 +1. **后端开发 (预计 X 天)**: + * 完善/创建 DTO, VO。 + * 实现 Service 层逻辑。 + * 实现 Controller 层 API 接口。 + * 编写单元测试/集成测试。 + * API 文档更新 (如使用 Swagger,则自动生成并校验)。 +2. **前端开发 (预计 Y 天)**: + * 创建/完善页面组件。 + * 实现 API 服务调用。 + * 实现核心功能逻辑 (列表、筛选、分页、详情、操作等)。 + * 编写组件测试 (如果项目有要求)。 +3. **联调测试 (预计 Z 天)**: + * 前后端集成测试。 + * 问题修复和优化。 +4. **文档更新**: + * 更新 `LogBook.md` 记录开发过程。 + * 本方案文档根据实际开发情况进行调整。 + +## 7. 注意事项 +* **权限控制**: 严格确保所有管理接口仅管理员可访问。 +* **数据安全**: 对于手动修改会话状态等敏感操作,务必谨慎,并有充分的理由和记录。 +* **用户体验**: 管理界面应清晰易用,方便管理员快速找到所需信息并执行操作。 \ No newline at end of file diff --git a/springboot-init-main/doc/system_settings_plan.md b/springboot-init-main/doc/system_settings_plan.md new file mode 100644 index 0000000..2583ca9 --- /dev/null +++ b/springboot-init-main/doc/system_settings_plan.md @@ -0,0 +1,224 @@ +# 系统设置模块开发方案 + +## 1. 引言 + +### 1.1. 目的 +本文档旨在为"MQTT智能充电桩管理系统"的"系统设置"模块提供详细的开发方案。该模块的目标是允许管理员通过用户界面方便地配置系统级的关键参数和业务规则,特别是充电费率。 + +### 1.2. 背景与依据 +根据项目需求文档 (`requirements.md`) 和开发计划 (`development_plan.md`),系统需要提供管理员配置充电费率及其他关键参数的功能。当前管理界面已预留"系统设置"入口,描述为"配置系统参数、费率等"。本方案将在现有项目结构和技术栈基础上进行设计。 + +### 1.3. 范围 +本方案覆盖"系统设置"模块的后端和前端设计,包括: +* 充电费率管理 +* MQTT 相关参数配置 +* 激活码默认参数配置 +* (可选) 系统维护模式配置 + +## 2. 功能需求 + +### 2.1. 充电费率管理 +* **FR2.1.1**: 管理员能够配置当前生效的充电费率。 + * 至少支持按电量计费,例如:X 元/kWh (度)。 + * (可选扩展) 支持按时长计费,例如:Y 元/分钟,或阶梯计费、分时段计费。本期方案优先实现基础的单一电量费率。 +* **FR2.1.2**: 费率修改后,新发起的充电会话应按新费率计算。已在进行的会话按其开始时应用的费率计算(或根据最终业务决策调整)。 +* **FR2.1.3**: 系统界面应清晰展示当前的生效费率。 +* **FR2.1.4**: (可选扩展) 系统应能记录费率的变更历史。 + +### 2.2. 系统参数配置 + +#### 2.2.1. MQTT 相关参数 +* **FR2.2.1.1**: 管理员能够配置机器人任务的默认超时时间(单位:秒)。 + * 对应原 `application.yml` 中的 `mqtt.task.timeoutSeconds`。 +* **FR2.2.1.2**: 管理员能够启用或禁用MQTT通信日志的记录功能。 + * 对应原 `application.yml` 中的 `mqtt.logger.enabled`。 +* **FR2.2.1.3**: 管理员能够配置MQTT通信日志的保留天数。 + * 对应原 `application.yml` 中的 `mqtt.logger.retain-days`。 + +#### 2.2.2. 激活码默认参数 +* **FR2.2.2.1**: 管理员能够配置生成激活码时的默认有效天数(当批量生成未指定时使用)。 +* **FR2.2.2.2**: 管理员能够配置生成激活码时的默认面额(当批量生成未指定时使用)。 + +#### 2.2.3. (可选) 系统维护模式 +* **FR2.2.3.1**: 管理员能够开启或关闭系统维护模式。 +* **FR2.2.3.2**: 系统处于维护模式时,普通用户在前端应看到明确提示,并且核心业务功能(如发起充电请求)应受限。 + +## 3. 后端设计 (`springboot-init-main`) + +### 3.1. 数据模型 + +#### 3.1.1. 系统配置表 (`system_config`) +用于存储各类可配置的系统参数。 + +```sql +CREATE TABLE `system_config` ( + `id` BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', + `config_key` VARCHAR(100) NOT NULL UNIQUE COMMENT '配置键,例如: mqtt.task.timeoutSeconds', + `config_value` VARCHAR(500) COMMENT '配置值', + `config_name` VARCHAR(100) COMMENT '配置项名称/标签,用于UI显示', + `description` VARCHAR(255) COMMENT '配置项描述', + `data_type` VARCHAR(20) DEFAULT 'STRING' COMMENT '数据类型 (STRING, INTEGER, BOOLEAN, DECIMAL)', + `config_group` VARCHAR(50) COMMENT '配置分组 (例如: MQTT, ACTIVATION_CODE, GENERAL)', + `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `is_deleted` TINYINT DEFAULT 0 COMMENT '逻辑删除标志 (0:未删除, 1:已删除)' +) COMMENT '系统配置表'; +``` +**预置数据/示例**: +* `mqtt.task.timeoutSeconds`, `mqtt.logger.enabled`, `mqtt.logger.retain-days` +* `activation_code.default.duration_days`, `activation_code.default.value` +* `system.maintenance_mode` (value: '0' or '1') + +#### 3.1.2. 充电费率表 (`charging_rate`) +用于管理充电费率。初期简化,只管理一个当前全局有效的电量费率。 + +```sql +CREATE TABLE `charging_rate` ( + `id` BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', + `rate_per_kwh` DECIMAL(10, 4) NOT NULL COMMENT '每度电的费率 (元/kWh)', + `description` VARCHAR(255) COMMENT '费率描述', + `is_active` TINYINT DEFAULT 1 COMMENT '是否当前生效 (1:是, 0:否) - 初期只有一个active的', + `effective_from` DATETIME NOT NULL COMMENT '此费率生效起始时间', + `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `is_deleted` TINYINT DEFAULT 0 COMMENT '逻辑删除标志' +) COMMENT '充电费率表'; +``` +**说明**: `is_active` 和 `effective_from` 字段用于管理费率版本。简单实现下,可以只允许一条 `is_active=1` 的记录。 + +### 3.2. Service 层 + +#### 3.2.1. `SystemConfigService` +* `String getConfigValue(String key)`: 获取指定键的配置值。 +* `List getAllConfigs()`: 获取所有配置项。 +* `List getConfigsByGroup(String group)`: 按组获取配置。 +* `boolean updateConfigs(List requests)`: 批量更新配置项。 +* **缓存**: 实现配置的读取缓存 (例如使用 Spring Cache),更新时清除缓存。 + +#### 3.2.2. `ChargingRateService` +* `ChargingRate getCurrentActiveRate()`: 获取当前生效的充电费率。 +* `ChargingRate setRate(ChargingRate newRate)`: 设置或更新充电费率。旧费率设为`is_active=0`,新费率`is_active=1`。 +* `List getRateHistory()`: (可选) 获取费率变更历史。 + +### 3.3. Controller 层 + +#### 3.3.1. `SystemConfigAdminController` (`/api/admin/config`) +* `GET /`: 获取所有系统配置项,按组分类返回。 + * 响应: `BaseResponse>>` +* `PUT /`: 批量更新系统配置项。 + * 响应: `BaseResponse` + * 参数: `List` (包含 `configKey`, `configValue`) + +#### 3.3.2. `ChargingRateAdminController` (`/api/admin/rate`) +* `GET /current`: 获取当前生效的充电费率。 + * 响应: `BaseResponse` +* `POST /`: 设置新的充电费率。 + * 请求: `ChargingRateUpdateRequest` (包含 `ratePerKwh`, `description`, `effectiveFrom`) + * 响应: `BaseResponse` +* `GET /history`: (可选) 获取费率变更历史。 + +### 3.4. 对现有模块的修改 + +* **`ChargingSessionServiceImpl`**: + * 在 `calculateAndSetFee` 或相关计费方法中,需从 `ChargingRateService.getCurrentActiveRate()` 获取费率,替换当前的计费逻辑。 +* **`MqttServiceImpl` / `TaskTimeoutHandler` / `MqttCommunicationLogServiceImpl`**: + * 涉及 `mqtt.task.timeoutSeconds`, `mqtt.logger.enabled`, `mqtt.logger.retain-days` 的地方,应改为从 `SystemConfigService` 获取配置值。 + * 例如,通过 `@Value` 注入配置时,可以提供一个默认值,然后服务初始化时或每次使用时从 `SystemConfigService` 读取覆盖。 +* **`ActivationCodeServiceImpl`**: + * 在 `generateCodes` 方法中,当请求未提供 `expireTime` 或 `value` 时,从 `SystemConfigService` 读取 `activation_code.default.duration_days` 和 `activation_code.default.value` 作为默认值。 +* **(可选) 权限/全局拦截器**: + * 如果实现系统维护模式,可能需要在全局请求拦截器或权限校验处增加判断,如果维护模式开启,则对普通用户操作返回特定提示或状态码。 + +## 4. 前端设计 (`charging_web_app`) + +### 4.1. 页面与路由 +* 在管理员界面下创建新页面,例如: `/admin/settings`。 +* 在 `src/app/(authenticated)/admin/settings/page.tsx` 实现。 +* 在管理员导航栏 (`AuthenticatedLayout.tsx`) 中添加入口。 + +### 4.2. UI 结构 +使用 Ant Design 的 `Tabs` 组件将不同类型的设置分组显示: +* **Tab 1: "费率设置"** +* **Tab 2: "MQTT 设置"** +* **Tab 3: "激活码设置"** +* **Tab 4: "其他设置" (例如:系统维护模式)** + +#### 4.2.1. 费率设置 Tab +* **显示当前费率**: + * 只读文本展示当前 `ratePerKwh` 和描述。 +* **修改费率表单**: + * `Form` 包含: + * `InputNumber` 用于新的 `ratePerKwh` (元/度)。 + * `Input.TextArea` 用于描述。 + * `DatePicker` 用于 `effectiveFrom` (生效日期,默认为当前或次日)。 + * "保存" 按钮,触发表单提交。 +* **(可选)** `Table` 展示费率历史。 + +#### 4.2.2. MQTT 设置 Tab +* `Form` 包含: + * "机器人任务超时时间 (秒)": `InputNumber` (对应 `mqtt.task.timeoutSeconds`)。 + * "启用MQTT通信日志": `Switch` (对应 `mqtt.logger.enabled`)。 + * "MQTT日志保留天数": `InputNumber` (对应 `mqtt.logger.retain-days`)。 +* "保存设置" 按钮。 + +#### 4.2.3. 激活码设置 Tab +* `Form` 包含: + * "默认有效天数": `InputNumber` (对应 `activation_code.default.duration_days`)。 + * "默认面额 (元)": `InputNumber` (对应 `activation_code.default.value`)。 +* "保存设置" 按钮。 + +#### 4.2.4. 其他设置 Tab +* `Form` 包含: + * "系统维护模式": `Switch` (对应 `system.maintenance_mode`)。 + * 旁边可有文字说明维护模式的影响。 +* "保存设置" 按钮。 + +### 4.3. 状态管理与API调用 +* 使用 `useState` 和 `useEffect` 管理表单数据、加载状态和从API获取的配置数据。 +* 页面加载时,调用后端API (`GET /api/admin/config` 和 `GET /api/admin/rate/current`) 获取所有配置的当前值并填充表单。 +* 用户点击各Tab下的"保存"按钮时: + * 调用对应的后端API (`PUT /api/admin/config` 或 `POST /api/admin/rate`)。 + * 成功后提示用户,并刷新显示的数据。 + * 统一处理API错误并向用户展示。 + +### 4.4. 类型定义 (`src/types/`) +* `SystemConfig.ts`: 定义 `SystemConfigVO`, `SystemConfigUpdateRequest`。 +* `Rate.ts`: 定义 `ChargingRateVO`, `ChargingRateUpdateRequest`。 + +## 5. 开发步骤概要 +1. **后端**: + 1. 数据库设计与SQL脚本编写 (`system_config`, `charging_rate` 表)。 + 2. 实体类、VO、DTO 定义。 + 3. Mapper 接口编写。 + 4. `SystemConfigService` 及 `SystemConfigServiceImpl` 实现。 + 5. `ChargingRateService` 及 `ChargingRateServiceImpl` 实现。 + 6. `SystemConfigAdminController` 和 `ChargingRateAdminController` 实现。 + 7. 修改现有Service层代码,使其依赖新的配置服务。 + 8. 编写单元测试和API接口测试。 +2. **前端**: + 1. 创建 `/admin/settings` 页面及路由。 + 2. 实现各配置Tab的UI布局 (使用Ant Design组件)。 + 3. 实现API服务调用逻辑,用于获取和更新配置。 + 4. 实现表单数据绑定、提交和验证。 + 5. 在管理员导航栏添加链接。 +3. **联调与测试**: + 1. 前后端联调,确保数据流正确。 + 2. 全面测试各项配置的生效情况,特别是对现有功能的影响。 + 3. UI/UX 测试和调整。 +4. **文档**: + 1. 更新 `README.md` 或相关部署文档,说明新增的配置项。 + 2. 更新API文档。 + +## 6. 风险与注意事项 +* **配置生效机制**: 部分系统参数(如日志开关)可能需要特定的机制使其在修改后能被应用动态感知,而不是仅在服务重启后生效。Service层中读取配置的逻辑需要考虑这一点,缓存机制是关键。 +* **数据一致性**: 费率等关键业务数据的修改需要保证事务性。 +* **权限控制**: 确保所有系统设置的API接口都受到严格的管理员权限保护。 +* **用户体验**: 配置项应有清晰的名称和描述,重要的修改操作最好有二次确认。 +* **向后兼容**: 如果某些配置项被移除或重命名,需要考虑旧数据的迁移或兼容。 + +## 7. 未来扩展 +* **分时段/阶梯费率**: `charging_rate` 表已为分时段费率预留 `start_time_segment`, `end_time_segment` 字段,未来可扩展。 +* **更细致的权限控制**: 例如,不同管理员角色管理不同的配置模块。 +* **操作日志**: 对系统设置的修改操作记录审计日志。 + +This concludes the development plan for the System Settings module. \ No newline at end of file