Просмотр исходного кода

修改发送短信,根据新模板进行发送

DESKTOP-3Q5PM1M\896986 19 часов назад
Родитель
Сommit
4c6124c634

+ 0 - 310
GIT-MIGRATION-GUIDE.md

@@ -1,310 +0,0 @@
-# 🚀 教育投诉平台 Git 仓库迁移指南
-
-## 📋 **前置检查清单**
-
-✅ 确认已创建新的 Git 仓库(如 GitHub/GitLab)
-✅ 备份当前代码到本地压缩文件
-✅ 确认所有重要代码已提交到本地
-
----
-
-## 🔧 **步骤 1: 清理旧的 Git 历史**
-
-### 方案 A: 完全重建 Git 仓库(推荐)
-
-```bash
-# 1️⃣ 进入项目根目录
-cd e:\complaint-system
-
-# 2️⃣ 删除旧的 Git 仓库
-rm -rf .git
-
-# 3️⃣ 初始化全新的 Git 仓库
-git init
-
-# 4️⃣ 添加所有忽略规则生效后的文件
-git add .
-
-# 5️⃣ 第一次提交
-git commit -m "Initial commit: 教育投诉平台源码"
-
-# 6️⃣ 重命名主分支为 main(可选)
-git branch -M main
-
-# 7️⃣ 连接到远程仓库
-git remote add origin <您的新仓库地址>
-
-# 8️⃣ 推送到远程仓库
-git push -u --force origin main
-```
-
----
-
-### 方案 B: 保留历史但清理大文件
-
-如果需要在保持提交历史的同时清理某些文件:
-
-```bash
-cd e:\complaint-system
-
-# 查看所有可能被误提交的文件
-git ls-files | grep -E "(reasonix|Demo|doc/)"
-
-# 如果要移除特定文件但不删除历史记录
-git rm --cached .reasonix/*
-git rm --cached Demo/*
-git rm --cached doc/*
-
-# 提交更改
-git commit -m "Remove non-code files from tracking"
-
-# 然后重新关联新仓库
-git remote set-url origin <您的新仓库地址>
-git push -u --force origin main
-```
-
----
-
-## 🎯 **步骤 2: 验证 Git 忽略配置**
-
-### 检查 `.gitignore` 是否生效
-
-```bash
-# 查看未被追踪的文件
-git status --ignored
-
-# 应该看到以下标记为 'ignored' 的文件/文件夹:
-# ? ignored/.reasonix/
-# ? ignored/Demo/
-# ? ignored/doc/
-# ? ignored/h5-app/node_modules/
-```
-
-### 手动测试忽略规则
-
-```bash
-# 测试 h5-app 的 node_modules 是否被忽略
-cd h5-app
-ls node_modules  # 应该是空输出或显示为 ignored
-
-# 返回根目录
-cd ..
-```
-
----
-
-## 🔒 **步骤 3: 确保敏感信息不泄露**
-
-### 检查配置文件中的敏感数据
-
-```bash
-# 在 git commit 之前运行以下检查
-grep -r "password" --include="*.yml" --include="*.yaml" --include="*.properties" src/
-grep -r "secret" --include="*.env*" src/
-```
-
-### 推荐的敏感信息管理
-
-1. **使用环境变量文件** (不被 Git 追踪):
-   ```
-   complaint-admin/src/main/resources/application-dev.yml
-   ```
-   
-   应包含占位符:
-   ```yaml
-   spring:
-     datasource:
-       username: ${DB_USERNAME}
-       password: ${DB_PASSWORD}
-       url: jdbc:dm://localhost:5236?useSSL=false
-   ```
-
-2. **本地覆盖配置文件**:
-   创建 `application-local.yml` 并放入个人配置(加入.gitignore):
-   ```yaml
-   # 本地开发配置
-   spring:
-     datasource:
-       username: admin
-       password: your_password_here
-   ```
-
----
-
-## 📝 **步骤 4: 推送前最终检查**
-
-```bash
-# 1. 查看即将提交的所有文件
-git status
-
-# 2. 确认未包含的文件
-git check-ignore -v .reasonix/
-git check-ignore -v Demo/
-git check-ignore -v doc/
-git check-ignore -v h5-app/node_modules/
-
-# 预期输出:
-# ignore:.reasonix/
-# ignore:Demo/
-# ignore:doc/
-# ignore:h5-app/node_modules/
-```
-
----
-
-## 🌟 **步骤 5: 推送到远程仓库**
-
-### 连接到新仓库
-
-```bash
-# 替换为您的实际仓库地址
-git remote add origin git@github.com:your-username/complaint-system.git
-
-# 或者 HTTPS 方式
-# git remote add origin https://github.com/your-username/complaint-system.git
-
-# 推送
-git push -u origin main
-
-# 如果是首次推送到私有仓库
-git push -u origin main --force
-```
-
----
-
-## ✅ **验证列表**
-
-推送后,请在新克隆的仓库中验证:
-
-```bash
-# 1. 全新克隆(在其他机器上)
-git clone <您的仓库地址>
-cd complaint-system
-
-# 2. 确认不包含以下文件
-ls .reasonix      # ❌ 应该不存在
-ls Demo           # ❌ 应该不存在  
-ls doc/           # ❌ 应该不存在
-ls h5-app/node_modules/  # ❌ 应该不存在
-
-# 3. 确认核心文件存在
-ls pom.xml        # ✅
-ls h5-app/package.json   # ✅
-ls ruoyi-ui/package.json # ✅
-```
-
----
-
-## 🛠️ **常见问题的解决方案**
-
-### Q1: Git 提示文件已缓存,无法被忽略?
-
-```bash
-# 强制从缓存中移除文件
-git rm --cached -r .reasonix/
-git rm --cached -r Demo/
-git rm --cached -r doc/
-
-# 重新提交
-git commit -m "Update gitignore to exclude non-code files"
-```
-
-### Q2: 不小心提交了大文件怎么办?
-
-```bash
-# 使用 git-filter-repo 工具(推荐)
-pip install git-filter-repo
-git filter-repo --path .reasonix/ --invert-paths
-git filter-repo --path Demo/ --invert-paths
-
-# 或者手动清理历史
-git filter-branch --prune-empty --path .reasonix/ HEAD~10..HEAD
-```
-
-### Q3: 多个前端项目的 node_modules 导致仓库过大?
-
-```bash
-# 使用 git-lfs(可选)
-# 如果必须存储某些构建产物,可以使用 LFS
-git lfs install
-git lfs track "*.lock"
-
-# 但推荐完全不追踪 node_modules
-echo "node_modules/" >> .gitignore
-git rm -r --cached node_modules/
-```
-
----
-
-## 📊 **推荐的项目结构**
-
-成功迁移后的项目树(`.gitignore` 生效状态):
-
-```
-complaint-system/
-├── .gitignore          ✅
-├── pom.xml            ✅
-├── sql/               ✅ (数据库脚本)
-├── complaint-admin/   ✅
-├── complaint-common/  ✅
-├── complaint-workorder/ ✅
-├── ruoyi-ui/
-│   ├── node_modules/  ❌ (被忽略)
-│   ├── .gitignore     ✅
-│   └── src/           ✅
-├── h5-app/
-│   ├── node_modules/  ❌ (被忽略)
-│   ├── .gitignore     ✅
-│   └── src/           ✅
-├── Demo/              ❌ (被忽略)
-├── reasonix/          ❌ (被忽略)
-├── doc/               ❌ (被忽略)
-└── ...其他源代码       ✅
-```
-
----
-
-## 🎯 **最后一步:创建 README**
-
-建议添加项目说明:
-
-```markdown
-# 教育投诉平台
-
-## 技术架构
-- 后端:Spring Boot + MyBatis + 达梦数据库
-- PC 前端:Vue3 + Element Plus + Vite
-- H5 前端:Vue3 + Vant
-
-## 快速开始
-```bash
-# 启动后端
-./ry.sh start
-
-# 启动 PC 前端
-cd ruoyi-ui && npm run dev
-
-# 启动 H5 前端
-cd h5-app && npm run dev
-```
-
-## 注意事项
-- `node_modules/` 不会被 Git 追踪
-- 数据库配置请在本地 `application-local.yml` 中设置
-- 详见 SQL 文档和开发规范文档
-```
-
----
-
-## 📞 **需要帮助?**
-
-如果遇到任何 Git 相关问题,请提供:
-
-```bash
-# 获取调试信息
-git version
-git config --global --list
-git remote -v
-```
-
-祝您的项目顺利迁移到新仓库!🎉

+ 1 - 1
complaint-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java

@@ -53,7 +53,7 @@ public class SwaggerConfig
     {
         return new Info()
             // 设置标题
-            .title("标题:乌教解忧管理系统_接口文档")
+            .title("标题:校长信箱管理系统_接口文档")
             // 描述
             .description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...")
             // 作者信息

+ 6 - 4
complaint-admin/src/main/resources/application-prod.yml

@@ -121,6 +121,7 @@ ums:
         tp-name: jytspt
         sys-id: mp
         module-id: sms
+        namespace: http://sms.webservice.com             # 短信服务命名空间
         secret-key-raw: a4tfSrXgg6uTyi66S/OmWFOcU5o=  # 【涉密】短信密钥
         interface-method: sms
         operator-unit-id: 4d99b438044d4238bc240b3a15a66bf
@@ -133,6 +134,7 @@ ums:
         tp-name: jytspt
         sys-id: mp
         module-id: wechatOA
+        namespace: http://wechatoa.webservice.com        # 公众号服务命名空间
         secret-key-raw: a4tfSrXgg6uTyi66S/OmWFOcU5o=  # 【涉密】公众号密钥
         interface-method: saveWechatOAInfo
         templet-id: rPqN-9T5xdnsL8-BhDUOQrMWHIrKs2TI41XnEMSzpdA
@@ -167,10 +169,10 @@ complaint:
     demo-data:
         enabled: false                        # 【重要】生产环境必须关闭演示数据
     msg-template:
-        sms-new-workorder: '【乌教解忧】{name}您好,{school}有一条新的投诉工单({no}),处置链接:{link}'
-        sms-citizen-closed: '【乌教解忧】您投诉的{school}工单{no}已办结,结论:{conclusion}'
-        sms-citizen-rejected: '【乌教解忧】您投诉的{school}工单{no}已驳回,理由:{reason}'
-        sms-citizen-review-result: '【乌教解忧】您的工单{no}复核结果:{result}'
+        sms-new-workorder: '【校长信箱】{name}您好,{school}有一条新的投诉工单({no}),处置链接:{link}'
+        sms-citizen-closed: '【校长信箱】您投诉的{school}工单{no}已办结,结论:{conclusion}'
+        sms-citizen-rejected: '【校长信箱】您投诉的{school}工单{no}已驳回,理由:{reason}'
+        sms-citizen-review-result: '【校长信箱】您的工单{no}复核结果:{result}'
         wx-new-workorder: '您有一条新的投诉工单待处理,请及时处置。处置链接:{link}'
         wx-closed: '您提交的教育投诉已办结,处置结论:{conclusion}'
         wx-rejected: '您提交的教育投诉已被驳回,理由:{reason}'

+ 7 - 5
complaint-admin/src/main/resources/application.yml

@@ -172,6 +172,7 @@ ums:
     tp-name: jytspt
     sys-id: mp
     module-id: sms
+    namespace: http://sms.webservice.com                     # 短信服务命名空间(按东软WSDL)
     secret-key-raw: a4tfSrXgg6uTyi66S/OmWFOcU5o=          # ⚠️ 涉密,部署时用外部配置覆盖,勿外泄
     interface-method: sms
     operator-unit-id: 4d99b438044d4238bc240b3a15a66bfb
@@ -184,10 +185,11 @@ ums:
     tp-name: jytspt
     sys-id: mp
     module-id: wechatOA
+    namespace: http://wechatoa.webservice.com                # 公众号服务命名空间(按东软WSDL)
     secret-key-raw: a4tfSrXgg6uTyi66S/OmWFOcU5o=
     interface-method: saveWechatOAInfo
     templet-id: rPqN-9T5xdnsL8-BhDUOQrMWHIrKs2TI41XnEMSzpdA   # 公众号消息模板(模板编号 53745)
-    send-sys-name: 乌教解忧
+    send-sys-name: 校长信箱
     send-priority: 3
   retry:
     max-attempts: 3
@@ -223,10 +225,10 @@ complaint:
   demo-data:
     enabled: true                                          # 预置演示数据开关:true=预制数据;验证通过或真实数据到位后置 false
   msg-template:
-    sms-new-workorder: '【乌教解忧】{name}您好,{school}有一条新的投诉工单({no}),处置链接:{link}'
-    sms-citizen-closed: '【乌教解忧】您投诉的{school}工单{no}已办结,结论:{conclusion}'
-    sms-citizen-rejected: '【乌教解忧】您投诉的{school}工单{no}已驳回,理由:{reason}'
-    sms-citizen-review-result: '【乌教解忧】您的工单{no}复核结果:{result}'
+    sms-new-workorder: '【校长信箱】{name}您好,{school}有一条新的投诉工单({no}),处置链接:{link}'
+    sms-citizen-closed: '【校长信箱】您投诉的{school}工单{no}已办结,结论:{conclusion}'
+    sms-citizen-rejected: '【校长信箱】您投诉的{school}工单{no}已驳回,理由:{reason}'
+    sms-citizen-review-result: '【校长信箱】您的工单{no}复核结果:{result}'
     wx-new-workorder: '您有一条新的投诉工单待处理,请及时处置。处置链接:{link}'
     wx-closed: '您提交的教育投诉已办结,处置结论:{conclusion}'
     wx-rejected: '您提交的教育投诉已被驳回,理由:{reason}'

+ 1 - 1
complaint-ui/index.html

@@ -2,7 +2,7 @@
 <html lang="zh-CN">
 <head>
   <meta charset="UTF-8">
-  <title>乌教解忧 · 投诉管理后台</title>
+  <title>校长信箱 · 投诉管理后台</title>
 </head>
 <body>
   <div id="app"></div>

+ 1 - 1
complaint-ui/src/views/login.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="login-wrap">
     <el-card class="login-card">
-      <h2>乌教解忧 · 投诉管理后台</h2>
+      <h2>校长信箱 · 投诉管理后台</h2>
       <el-form :model="form" @keyup.enter="onLogin">
         <el-form-item>
           <el-input v-model="form.username" placeholder="用户名" size="large" />

+ 1 - 1
complaint-workorder/src/main/java/com/complaint/workorder/config/UmsProperties.java

@@ -84,7 +84,7 @@ public class UmsProperties
         /** 短信配额机构名称 */
         private String operatorUnitName;
 
-        /** 系统厂商名称(乌教解忧) */
+        /** 系统厂商名称(校长信箱) */
         private String sendSysName;
 
         /** 发送优先级:2=验证码(测试期),3=立即发送(东软放开后) */

+ 121 - 2
complaint-workorder/src/main/java/com/complaint/workorder/push/UmsSmsClient.java

@@ -4,6 +4,8 @@ import java.util.HashMap;
 import java.util.Map;
 import com.alibaba.fastjson2.JSON;
 import com.complaint.workorder.config.UmsProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Component;
 
 /**
@@ -12,6 +14,8 @@ import org.springframework.stereotype.Component;
 @Component
 public class UmsSmsClient
 {
+    private static final Logger log = LoggerFactory.getLogger(UmsSmsClient.class);
+
     private final UmsProperties properties;
     private final UmsSoapClient soapClient;
 
@@ -25,7 +29,7 @@ public class UmsSmsClient
      * 发送短信
      *
      * @param personInfo 接收人,格式:姓名|学工号|部门ID|部门名称|电话号码,多人用 ^@^ 分隔
-     * @param smsInfo    短信内容(开头固定【乌教解忧】签名)
+     * @param smsInfo    短信内容(开头固定【校长信箱】签名)
      * @param operatorId 发送人学工号(可空)
      * @param operatorName 发送人姓名(可空)
      * @return 平台返回 {result, msg, msg_id}
@@ -60,6 +64,121 @@ public class UmsSmsClient
         params.put("send_sys_id", "1");
         params.put("send_sys_name", cfg.getSendSysName());
         params.put("user_browser", "");
-        return soapClient.call(cfg.getWsdl(), cfg.getNamespace(), "saveSmsInfo", JSON.toJSONString(params));
+        String jsonParams = JSON.toJSONString(params);
+        log.info("========== 短信发送参数 ==========");
+        log.info("【旧版sendSms方法 - 直接传sms_info字符串】");
+        log.info("接口地址(wsdl): {}", cfg.getWsdl());
+        log.info("命名空间(namespace): {}", cfg.getNamespace());
+        log.info("方法名: saveSmsInfo");
+        log.info("tp_name: {}", cfg.getTpName());
+        log.info("sys_id: {}", cfg.getSysId());
+        log.info("module_id: {}", cfg.getModuleId());
+        log.info("secret_key(加密后): {}", UmsCrypto.encode(cfg.getSecretKeyRaw()));
+        log.info("interface_method: {}", cfg.getInterfaceMethod());
+        log.info("person_info: {}", personInfo);
+        log.info("sms_info: {}", smsInfo);
+        log.info("send_priority: {}", cfg.getSendPriority());
+        log.info("operator_id: {}", operatorId);
+        log.info("operator_name: {}", operatorName);
+        log.info("operator_unit_id: {}", cfg.getOperatorUnitId());
+        log.info("operator_unit_name: {}", cfg.getOperatorUnitName());
+        log.info("templet_id: 0");
+        log.info("send_sys_id: 1");
+        log.info("send_sys_name: {}", cfg.getSendSysName());
+        log.info("完整JSON参数: {}", jsonParams);
+        log.info("==================================");
+
+        Map<String, Object> result = soapClient.call(cfg.getWsdl(), cfg.getNamespace(), "saveSmsInfo", jsonParams);
+        log.info("短信发送结果: {}", result);
+        return result;
+    }
+
+    /**
+     * 发送给学校管理员短信(新格式)
+     * <p>
+     * sms_info 字段为JSON字符串,包含以下字段:
+     * - teacher_name: 短信接收人姓名
+     * - school: 投诉工单中的学校
+     * - complaint_number: 投诉工单号
+     * - complaint: 投诉分类
+     * - template_code: 短信模板id(固定为 SMS_512120647)
+     *
+     * @param personInfo       接收人,格式:姓名|学工号|部门ID|部门名称|电话号码,多人用 ^@^ 分隔
+     * @param teacherName      短信接收人姓名
+     * @param school           投诉工单中的学校
+     * @param complaintNumber  投诉工单号
+     * @param complaint        投诉分类
+     * @param templateCode     短信模板id(固定为 SMS_512120647)
+     * @param operatorId       发送人学工号(可空)
+     * @param operatorName     发送人姓名(可空)
+     * @return 平台返回 {result, msg, msg_id}
+     */
+    public Map<String, Object> sendSmsByTemplate(String personInfo, String teacherName,
+            String school, String complaintNumber, String complaint,
+            String templateCode, String operatorId, String operatorName)
+    {
+        // 构造sms_info的JSON字符串
+        Map<String, String> smsInfoMap = new HashMap<>();
+        smsInfoMap.put("teacher_name", teacherName == null ? "" : teacherName);
+        smsInfoMap.put("school", school == null ? "" : school);
+        smsInfoMap.put("complaint_number", complaintNumber == null ? "" : complaintNumber);
+        smsInfoMap.put("complaint", complaint == null ? "" : complaint);
+        smsInfoMap.put("template_code", templateCode == null ? "SMS_512120647" : templateCode);
+        String smsInfoJson = JSON.toJSONString(smsInfoMap);
+
+        log.info("========== 模板短信发送参数 ==========");
+        log.info("【新版sendSmsByTemplate方法 - sms_info为JSON字符串】");
+        log.info("teacher_name: {}", teacherName);
+        log.info("school: {}", school);
+        log.info("complaint_number: {}", complaintNumber);
+        log.info("complaint: {}", complaint);
+        log.info("template_code: {}", templateCode);
+        log.info("sms_info(JSON): {}", smsInfoJson);
+        log.info("======================================");
+
+        // 调用原有的sendSms方法,传入构造好的sms_info JSON字符串
+        return sendSms(personInfo, smsInfoJson, operatorId, operatorName);
+    }
+
+    /**
+     * 发送群众短信(办结/驳回/复核结果等场景)
+     * <p>
+     * sms_info 字段为JSON字符串,包含以下字段:
+     * - school: 投诉的学校名称
+     * - complaint_type: 投诉分类
+     * - complaint_result: 投诉处理结果(办结/驳回/复核结果等)
+     * - template_code: 短信模板id(固定为 SMS_512265662)
+     *
+     * @param personInfo       接收人,格式:姓名|学工号|部门ID|部门名称|电话号码
+     * @param school           投诉的学校名称
+     * @param complaintType    投诉分类
+     * @param complaintResult  投诉处理结果
+     * @param templateCode     短信模板id(固定为 SMS_512265662)
+     * @param operatorId       发送人学工号(可空)
+     * @param operatorName     发送人姓名(可空)
+     * @return 平台返回 {result, msg, msg_id}
+     */
+    public Map<String, Object> sendSmsToCitizen(String personInfo, String school,
+            String complaintType, String complaintResult,
+            String templateCode, String operatorId, String operatorName)
+    {
+        // 构造sms_info的JSON字符串
+        Map<String, String> smsInfoMap = new HashMap<>();
+        smsInfoMap.put("school", school == null ? "" : school);
+        smsInfoMap.put("complaint_type", complaintType == null ? "" : complaintType);
+        smsInfoMap.put("complaint_result", complaintResult == null ? "" : complaintResult);
+        smsInfoMap.put("template_code", templateCode == null ? "SMS_512265662" : templateCode);
+        String smsInfoJson = JSON.toJSONString(smsInfoMap);
+
+        log.info("========== 群众短信发送参数 ==========");
+        log.info("school: {}", school);
+        log.info("complaint_type: {}", complaintType);
+        log.info("complaint_result: {}", complaintResult);
+        log.info("template_code: {}", templateCode);
+        log.info("sms_info(JSON): {}", smsInfoJson);
+        log.info("======================================");
+
+        // 调用原有的sendSms方法,传入构造好的sms_info JSON字符串
+        return sendSms(personInfo, smsInfoJson, operatorId, operatorName);
     }
 }

+ 11 - 0
complaint-workorder/src/main/java/com/complaint/workorder/push/UmsSoapClient.java

@@ -55,7 +55,18 @@ public class UmsSoapClient
         // 参数 JSON 转义进 XML(& < > 需转义)
         String escaped = jsonParams.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;");
         String soap = String.format(SOAP_TEMPLATE, namespace, method, escaped, method);
+        log.info("========== SOAP请求报文 ==========");
+        log.info("请求地址: {}", endpoint);
+        log.info("命名空间: {}", namespace);
+        log.info("方法名: {}", method);
+        log.info("SOAP报文: {}", soap);
+        log.info("==================================");
+
         String responseXml = post(endpoint, soap);
+        log.info("========== SOAP响应报文 ==========");
+        log.info("响应内容: {}", responseXml);
+        log.info("==================================");
+
         String returnJson = extractReturn(responseXml);
         JSONObject json = JSON.parseObject(returnJson);
         return json;

+ 123 - 34
complaint-workorder/src/main/java/com/complaint/workorder/service/impl/PushServiceImpl.java

@@ -1,5 +1,7 @@
 package com.complaint.workorder.service.impl;
 
+import java.text.SimpleDateFormat;
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import com.complaint.workorder.config.ComplaintProperties;
@@ -86,7 +88,7 @@ public class PushServiceImpl implements IPushService
         }
 
         String smsTemplate = complaintProperties.getMsgTemplate().getOrDefault("sms-new-workorder",
-                "【乌教解忧】{name}您好,{school}有一条新的投诉工单({no}),处置链接:{link}");
+                "【校长信箱】{name}您好,{school}有一条新的投诉工单({no}),处置链接:{link}");
 
         // 合并多个管理员的信息为一条消息(姓名 | 学工号|部门ID|部门名称 | 电话 ^@^ 分隔)
         StringBuilder personInfos = new StringBuilder();
@@ -98,23 +100,21 @@ public class PushServiceImpl implements IPushService
             personInfos.append(buildPersonInfo(admin));
         }
 
-        // 发送一条合并的短信(包含所有管理员)
+        // 发送一条合并的短信(包含所有管理员)- 使用新模板格式
         String firstAdminName = admins.get(0).getNickName();
-        String smsContent = smsTemplate.replace("{name}", StringUtils.defaultString(firstAdminName))
-                .replace("{school}", StringUtils.defaultString(workorder.getSchoolName()))
-                .replace("{no}", workorder.getComplaintNo())
-                .replace("{link}", StringUtils.defaultString(adminLink));
-        sendSmsWithLog(workorder.getComplaintNo(), null, smsContent, personInfos.toString());
+        sendSmsWithLogByTemplate(workorder.getComplaintNo(), personInfos.toString(),
+                firstAdminName, workorder.getSchoolName(), workorder.getComplaintNo(),
+                workorder.getCategory(), "SMS_512120647");
 
         // 公众号:为每个管理员单独发送一条消息(平台限制)
+        String wechatInfo = buildNewWorkorderWechatInfo();
         for (SysUser admin : admins) {
             // 公众号按学工号匹配,无学工号时跳过
             if (StringUtils.isNotBlank(admin.getStaffNo()))
             {
                 String receiveInfo = buildReceiveInfo(admin);
                 sendWechatWithLog(workorder.getComplaintNo(), admin.getNickName(), admin.getStaffNo(),
-                        receiveInfo, "新投诉工单提醒",
-                        buildWechatInfo(workorder.getComplaintNo(), workorder.getSchoolName(), "新工单待受理,请及时处置"));
+                        receiveInfo, "新投诉工单提醒", wechatInfo);
             }
         }
     }
@@ -122,13 +122,8 @@ public class PushServiceImpl implements IPushService
     @Override
     public void pushClosedToCitizen(ComplaintWorkorder workorder)
     {
-        // 短信通知群众(主通道,确保触达)
-        String template = complaintProperties.getMsgTemplate().getOrDefault("sms-citizen-closed",
-                "【乌教解忧】您投诉的{school}工单{no}已办结,结论:{conclusion}");
-        String content = template.replace("{school}", StringUtils.defaultString(workorder.getSchoolName()))
-                .replace("{no}", StringUtils.defaultString(workorder.getComplaintNo()))
-                .replace("{conclusion}", StringUtils.abbreviate(StringUtils.defaultString(workorder.getConclusion()), 50));
-        sendSmsToCitizen(workorder, content);
+        // 短信通知群众(新模板格式)
+        sendSmsToCitizen(workorder, "办结");
         // 公众号(待平台支持 openid 直发,记录日志占位)
         String info = buildWechatInfo(workorder.getComplaintNo(), workorder.getSchoolName(),
                 "已办结:" + StringUtils.abbreviate(StringUtils.defaultString(workorder.getConclusion()), 100));
@@ -138,13 +133,8 @@ public class PushServiceImpl implements IPushService
     @Override
     public void pushRejectedToCitizen(ComplaintWorkorder workorder)
     {
-        // 短信通知群众(主通道)
-        String template = complaintProperties.getMsgTemplate().getOrDefault("sms-citizen-rejected",
-                "【乌教解忧】您投诉的{school}工单{no}已驳回,理由:{reason}");
-        String content = template.replace("{school}", StringUtils.defaultString(workorder.getSchoolName()))
-                .replace("{no}", StringUtils.defaultString(workorder.getComplaintNo()))
-                .replace("{reason}", StringUtils.abbreviate(StringUtils.defaultString(workorder.getRejectReason()), 50));
-        sendSmsToCitizen(workorder, content);
+        // 短信通知群众(新模板格式)
+        sendSmsToCitizen(workorder, "驳回");
         // 公众号(待平台支持,记录日志占位)
         String info = buildWechatInfo(workorder.getComplaintNo(), workorder.getSchoolName(),
                 "已驳回:" + StringUtils.abbreviate(StringUtils.defaultString(workorder.getRejectReason()), 100));
@@ -183,7 +173,7 @@ public class PushServiceImpl implements IPushService
             personInfos.append(buildPersonInfo(admin));
         }
 
-        String smsContent = "【乌教解忧】工单 " + workorder.getComplaintNo() + " 收到群众异议复核申请,请及时处理";
+        String smsContent = "【校长信箱】工单 " + workorder.getComplaintNo() + " 收到群众异议复核申请,请及时处理";
         sendSmsWithLog(workorder.getComplaintNo(), null, smsContent, personInfos.toString());
 
         // 公众号:逐人推送复核提醒(按学工号匹配)
@@ -204,12 +194,8 @@ public class PushServiceImpl implements IPushService
     {
         String resultText = review.getStatus() != null && review.getStatus() == ComplaintConstants.REVIEW_PASS
                 ? "复核通过,工单将重新处置" : "复核维持原判";
-        // 短信通知群众(主通道)
-        String template = complaintProperties.getMsgTemplate().getOrDefault("sms-citizen-review-result",
-                "【乌教解忧】您的工单{no}复核结果:{result}");
-        String content = template.replace("{no}", StringUtils.defaultString(workorder.getComplaintNo()))
-                .replace("{result}", StringUtils.abbreviate(resultText, 30));
-        sendSmsToCitizen(workorder, content);
+        // 短信通知群众(新模板格式)
+        sendSmsToCitizen(workorder, resultText);
         // 公众号(待平台支持,记录日志占位)
         String info = buildWechatInfo(workorder.getComplaintNo(), workorder.getSchoolName(), resultText);
         sendWechatToCitizen(workorder, "异议复核处理结果", info);
@@ -224,6 +210,17 @@ public class PushServiceImpl implements IPushService
                 + "|||" + StringUtils.defaultString(result);
     }
 
+    /**
+     * 新工单提醒公众号内容:固定文案 + 当前时间
+     * 格式:您有一条新的投诉工单待处理|||yyyy-MM-dd HH:mm
+     */
+    private String buildNewWorkorderWechatInfo()
+    {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+        String currentTime = sdf.format(new Date());
+        return "您有一条新的投诉工单待处理|||" + currentTime;
+    }
+
     /**
      * 发短信并写日志(带重试)
      * @param receiverInfo 接收人信息(可以是合并的多个人,用^@^分隔)
@@ -257,6 +254,56 @@ public class PushServiceImpl implements IPushService
         messageLogMapper.insertComplaintMessageLog(messageLog);
     }
 
+    /**
+     * 发模板短信并写日志(带重试)- 新格式
+     * sms_info为JSON字符串,包含teacher_name/school/complaint_number/complaint/template_code
+     *
+     * @param receiverInfo 接收人信息(可以是合并的多个人,用^@^分隔)
+     * @param teacherName  短信接收人姓名
+     * @param school       学校名称
+     * @param complaintNumber 投诉工单号
+     * @param complaint    投诉分类
+     * @param templateCode 短信模板id
+     */
+    private void sendSmsWithLogByTemplate(String complaintNo, String receiverInfo,
+            String teacherName, String school, String complaintNumber,
+            String complaint, String templateCode)
+    {
+        if (!umsProperties.getSms().isEnabled())
+        {
+            log.info("短信通道未启用,跳过短信推送 complaintNo={}", complaintNo);
+            return;
+        }
+        // 构造sms_info的JSON字符串(用于日志记录)
+        String smsInfoJson = "{\"teacher_name\":\"" + StringUtils.defaultString(teacherName)
+                + "\",\"school\":\"" + StringUtils.defaultString(school)
+                + "\",\"complaint_number\":\"" + StringUtils.defaultString(complaintNumber)
+                + "\",\"complaint\":\"" + StringUtils.defaultString(complaint)
+                + "\",\"template_code\":\"" + StringUtils.defaultString(templateCode) + "\"}";
+
+        ComplaintMessageLog messageLog = new ComplaintMessageLog();
+        messageLog.setComplaintNo(complaintNo);
+        messageLog.setMsgType(ComplaintConstants.MSG_TYPE_SMS);
+        messageLog.setReceiver(receiverInfo);
+        messageLog.setTempletId(templateCode);
+        messageLog.setContent(smsInfoJson);
+        try
+        {
+            Map<String, Object> resp = retry(() -> smsClient.sendSmsByTemplate(
+                    receiverInfo, teacherName, school, complaintNumber,
+                    complaint, templateCode, null, null));
+            messageLog.setResult(1);
+            messageLog.setMsgId(resp == null ? "" : String.valueOf(resp.getOrDefault("msg_id", "")));
+        }
+        catch (Exception e)
+        {
+            log.error("模板短信推送失败 complaintNo={}", complaintNo, e);
+            messageLog.setResult(0);
+            messageLog.setErrorMsg(StringUtils.abbreviate(e.getMessage(), 450));
+        }
+        messageLogMapper.insertComplaintMessageLog(messageLog);
+    }
+
     /**
      * 发公众号消息并写日志(带重试)
      */
@@ -291,18 +338,60 @@ public class PushServiceImpl implements IPushService
     }
 
     /**
-     * 短信通知群众(按手机号发送,无需学工号)
-     * person_info 格式:姓名|学工号|部门ID|部门名称|电话号码(群众无学工号/部门,中间字段传空)
+     * 短信通知群众(新模板格式)
+     * sms_info为JSON字符串,包含school/complaint_type/complaint_result/template_code
+     *
+     * @param workorder       工单对象
+     * @param complaintResult 投诉处理结果(办结/驳回/复核结果等)
      */
-    private void sendSmsToCitizen(ComplaintWorkorder workorder, String content)
+    private void sendSmsToCitizen(ComplaintWorkorder workorder, String complaintResult)
     {
         if (StringUtils.isBlank(workorder.getPhone()))
         {
             log.warn("工单 {} 群众未留手机号,跳过短信推送", workorder.getComplaintNo());
             return;
         }
+        if (!umsProperties.getSms().isEnabled())
+        {
+            log.info("短信通道未启用,跳过群众短信推送 complaintNo={}", workorder.getComplaintNo());
+            return;
+        }
+
         String receiverInfo = "||||" + workorder.getPhone();
-        sendSmsWithLog(workorder.getComplaintNo(), null, content, receiverInfo);
+        String templateCode = "SMS_512265662";
+
+        // 构造sms_info的JSON字符串(用于日志记录)
+        String smsInfoJson = "{\"school\":\"" + StringUtils.defaultString(workorder.getSchoolName())
+                + "\",\"complaint_type\":\"" + StringUtils.defaultString(workorder.getCategory())
+                + "\",\"complaint_result\":\"" + StringUtils.defaultString(complaintResult)
+                + "\",\"template_code\":\"" + templateCode + "\"}";
+
+        ComplaintMessageLog messageLog = new ComplaintMessageLog();
+        messageLog.setComplaintNo(workorder.getComplaintNo());
+        messageLog.setMsgType(ComplaintConstants.MSG_TYPE_SMS);
+        messageLog.setReceiver(receiverInfo);
+        messageLog.setTempletId(templateCode);
+        messageLog.setContent(smsInfoJson);
+        try
+        {
+            Map<String, Object> resp = retry(() -> smsClient.sendSmsToCitizen(
+                    receiverInfo,
+                    workorder.getSchoolName(),
+                    workorder.getCategory(),
+                    complaintResult,
+                    templateCode,
+                    null,
+                    null));
+            messageLog.setResult(1);
+            messageLog.setMsgId(resp == null ? "" : String.valueOf(resp.getOrDefault("msg_id", "")));
+        }
+        catch (Exception e)
+        {
+            log.error("群众短信推送失败 complaintNo={}", workorder.getComplaintNo(), e);
+            messageLog.setResult(0);
+            messageLog.setErrorMsg(StringUtils.abbreviate(e.getMessage(), 450));
+        }
+        messageLogMapper.insertComplaintMessageLog(messageLog);
     }
 
     /**

+ 1 - 1
complaint-workorder/src/main/java/com/complaint/workorder/task/WorkorderOverdueCheckTask.java

@@ -89,7 +89,7 @@ public class WorkorderOverdueCheckTask
     {
         String schoolName = StringUtils.defaultString(order.getSchoolName());
         String complaintNo = order.getComplaintNo();
-        String content = String.format("【乌教解忧】学校[%s]有一起投诉工单(编号:%s)已受理%d 天仍未办结,请及时处理", 
+        String content = String.format("【校长信箱】学校[%s]有一起投诉工单(编号:%s)已受理%d 天仍未办结,请及时处理", 
                 schoolName, complaintNo, overdueDays);
         
         // 获取该学校的所有启用管理员

+ 2 - 2
h5-app/src/pages/Home.vue

@@ -1,9 +1,9 @@
 <template>
   <div class="home-page">
-    <van-nav-bar title="乌教解忧" left-arrow @click-left="router.push('/auth-guide')" />
+    <van-nav-bar title="校长信箱" left-arrow @click-left="router.push('/auth-guide')" />
     <div class="hero">
       <div class="hero-icon">📋</div>
-      <h1>乌教解忧 - 教育监督热线</h1>
+      <h1>校长信箱 - 教育监督热线</h1>
       <p class="subtitle">乌海市教育投诉服务平台</p>
     </div>
     <div class="actions">

+ 1 - 1
ruoyi-ui/.env.development

@@ -1,5 +1,5 @@
 # 页面标题
-VITE_APP_TITLE = 乌教解忧
+VITE_APP_TITLE = 校长信箱
 
 # 开发环境配置
 VITE_APP_ENV = 'development'

+ 1 - 1
ruoyi-ui/.env.production

@@ -1,5 +1,5 @@
 # 页面标题
-VITE_APP_TITLE = 乌教解忧
+VITE_APP_TITLE = 校长信箱
 
 # 生产环境配置
 VITE_APP_ENV = 'production'

+ 1 - 1
ruoyi-ui/.env.staging

@@ -1,5 +1,5 @@
 # 页面标题
-VITE_APP_TITLE = 乌教解忧
+VITE_APP_TITLE = 校长信箱
 
 # 生产环境配置
 VITE_APP_ENV = 'staging'

+ 1 - 1
ruoyi-ui/index.html

@@ -7,7 +7,7 @@
   <meta name="renderer" content="webkit">
   <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
   <link rel="icon" href="/favicon.ico">
-  <title>乌教解忧 - 教育投诉平台</title>
+  <title>校长信箱 - 教育投诉平台</title>
   <!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
   <style>
     html,

+ 1 - 1
ruoyi-ui/package.json

@@ -1,7 +1,7 @@
 {
   "name": "wujiaojieyou",
   "version": "1.0.0",
-  "description": "乌教解忧 - 教育投诉平台",
+  "description": "校长信箱 - 教育投诉平台",
   "author": "乌海市教育信息中心",
   "license": "MIT",
   "type": "module",

+ 1 - 11
ruoyi-ui/src/layout/components/Navbar.vue

@@ -12,15 +12,7 @@
       <template v-if="appStore.device !== 'mobile'">
         <header-search id="header-search" class="right-menu-item" />
 
-        <!-- <el-tooltip content="源码地址" effect="dark" placement="bottom">
-          <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
-        </el-tooltip>
-
-        <el-tooltip content="文档地址" effect="dark" placement="bottom">
-          <ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
-        </el-tooltip>
-
-        <screenfull id="screenfull" class="right-menu-item hover-effect" />
+        <!-- <screenfull id="screenfull" class="right-menu-item hover-effect" />
 
         <el-tooltip content="主题模式" effect="dark" placement="bottom">
           <div class="right-menu-item hover-effect theme-switch-wrapper" @click="toggleTheme">
@@ -74,8 +66,6 @@ import Hamburger from '@/components/Hamburger'
 import Screenfull from '@/components/Screenfull'
 import SizeSelect from '@/components/SizeSelect'
 import HeaderSearch from '@/components/HeaderSearch'
-import RuoYiGit from '@/components/RuoYi/Git'
-import RuoYiDoc from '@/components/RuoYi/Doc'
 import useAppStore from '@/store/modules/app'
 import useUserStore from '@/store/modules/user'
 import useLockStore from '@/store/modules/lock'

+ 1 - 1
ruoyi-ui/src/settings.js

@@ -2,7 +2,7 @@ export default {
   /**
    * 网页标题
    */
-  title: '乌教解忧 - 教育投诉平台',
+  title: '校长信箱 - 教育投诉平台',
 
   /**
    * 侧边栏主题 深色主题 theme-dark,浅色主题 theme-light

Разница между файлами не показана из-за своего большого размера
+ 43 - 1067
ruoyi-ui/src/views/index.vue


Некоторые файлы не были показаны из-за большого количества измененных файлов