diff --git a/sql/删除信息编号大于100的用户及相关数据.sql b/sql/删除信息编号大于100的用户及相关数据.sql new file mode 100644 index 00000000..bffe0a0c --- /dev/null +++ b/sql/删除信息编号大于100的用户及相关数据.sql @@ -0,0 +1,68 @@ +-- ===================================================== +-- 删除信息编号大于100的用户及其所有相关数据 +-- 同时清空所有测评记录和报告 +-- 执行前请先备份数据库! +-- ===================================================== + +-- ==================== 第一部分:清空所有测评数据 ==================== + +-- 1. 删除所有预警记录(关联测评的) +DELETE FROM psy_warning WHERE assessment_id IS NOT NULL; + +-- 2. 删除所有测评报告 +DELETE FROM psy_assessment_report; + +-- 3. 删除所有测评答案 +DELETE FROM psy_assessment_answer; + +-- 4. 删除所有测评记录 +DELETE FROM psy_assessment; + +-- 5. 删除所有问卷答案详情 +DELETE FROM psy_questionnaire_answer_detail; + +-- 6. 删除所有问卷答题记录 +DELETE FROM psy_questionnaire_answer; + +-- ==================== 第二部分:删除信息编号>100的用户 ==================== + +-- 7. 预览要删除的用户档案 +SELECT p.profile_id, p.user_id, u.nick_name AS user_name, p.info_number +FROM psy_user_profile p +LEFT JOIN sys_user u ON p.user_id = u.user_id +WHERE CAST(p.info_number AS UNSIGNED) > 100; + +-- 8. 删除预警记录(通过user_id关联) +DELETE FROM psy_warning WHERE user_id IN ( + SELECT user_id FROM psy_user_profile WHERE CAST(info_number AS UNSIGNED) > 100 AND user_id IS NOT NULL +); + +-- 9. 删除量表权限 +DELETE FROM psy_scale_permission WHERE user_id IN ( + SELECT user_id FROM psy_user_profile WHERE CAST(info_number AS UNSIGNED) > 100 AND user_id IS NOT NULL +); + +-- 10. 删除用户角色关联 +DELETE FROM sys_user_role WHERE user_id IN ( + SELECT user_id FROM psy_user_profile WHERE CAST(info_number AS UNSIGNED) > 100 AND user_id IS NOT NULL +); + +-- 11. 删除用户岗位关联 +DELETE FROM sys_user_post WHERE user_id IN ( + SELECT user_id FROM psy_user_profile WHERE CAST(info_number AS UNSIGNED) > 100 AND user_id IS NOT NULL +); + +-- 12. 删除系统用户 +DELETE FROM sys_user WHERE user_id IN ( + SELECT user_id FROM psy_user_profile WHERE CAST(info_number AS UNSIGNED) > 100 AND user_id IS NOT NULL +); + +-- 13. 删除用户档案 +DELETE FROM psy_user_profile WHERE CAST(info_number AS UNSIGNED) > 100; + +-- ==================== 第三部分:验证结果 ==================== + +SELECT COUNT(*) AS remaining_profiles FROM psy_user_profile WHERE CAST(info_number AS UNSIGNED) > 100; +SELECT COUNT(*) AS total_profiles FROM psy_user_profile; +SELECT COUNT(*) AS total_assessments FROM psy_assessment; +SELECT COUNT(*) AS total_reports FROM psy_assessment_report; diff --git a/xinli-ui/src/views/psychology/assessment/start.vue b/xinli-ui/src/views/psychology/assessment/start.vue index 64227305..a960da90 100644 --- a/xinli-ui/src/views/psychology/assessment/start.vue +++ b/xinli-ui/src/views/psychology/assessment/start.vue @@ -159,7 +159,7 @@ export default { // 如果是管理员,显示所有量表和问卷;否则只显示有权限的量表 if (isAdmin) { // 管理员显示所有量表和问卷 - listScale({ status: '0', includeQuestionnaire: true }).then(response => { + listScale({ status: '0', includeQuestionnaire: true, pageNum: 1, pageSize: 1000 }).then(response => { this.scaleList = response.rows.filter(scale => scale.itemCount > 0); // 如果URL中有scaleId,检查是否是问卷 if (this.form.scaleId) { @@ -195,7 +195,7 @@ export default { console.error("用户ID无效:", userId); // 如果userId无效,默认显示所有量表和问卷(可能是临时会话问题) console.warn("用户ID无效,尝试加载所有量表和问卷"); - listScale({ status: '0', includeQuestionnaire: true }).then(response => { + listScale({ status: '0', includeQuestionnaire: true, pageNum: 1, pageSize: 1000 }).then(response => { this.scaleList = response.rows.filter(scale => scale.itemCount > 0); // 如果URL中有scaleId,检查是否是问卷 if (this.form.scaleId) { @@ -231,7 +231,7 @@ export default { module.getUserScaleIds(userId).then(permissionResponse => { const allowedScaleIds = permissionResponse.data || []; // 获取所有量表和问卷,然后过滤 - listScale({ status: '0', includeQuestionnaire: true }).then(response => { + listScale({ status: '0', includeQuestionnaire: true, pageNum: 1, pageSize: 1000 }).then(response => { this.scaleList = response.rows.filter(scale => { if (scale.itemCount === 0) return false; // 量表和问卷都需要检查权限 diff --git a/内网环境ANR问题彻底解决方案.md b/内网环境ANR问题彻底解决方案.md new file mode 100644 index 00000000..8d02140a --- /dev/null +++ b/内网环境ANR问题彻底解决方案.md @@ -0,0 +1,431 @@ +# 🎯 内网环境ANR问题彻底解决方案 + +## 问题诊断 + +### 原始问题 +- App在内网环境下朗读按钮显示**灰色**(disabled) +- 点击无反应,无法使用朗读功能 +- 一段时间后出现**ANR**(Application Not Responding) +- 应用被系统强制关闭 + +### 根本原因 +1. **前端检测逻辑不完整**:只检查 `window.AndroidTTS` 是否存在,未调用 `isAvailable()` 方法 +2. **旧实现依赖外网**:使用百度在线TTS API (`https://fanyi.baidu.com/gettts`) +3. **内网无法访问外网**:网络请求超时导致主线程阻塞 +4. **导致ANR**:长时间等待响应,系统判定应用无响应 + +--- + +## ✅ 解决方案 + +### 核心改进 +1. **使用Android原生TextToSpeech引擎**:完全离线,不需要网络 +2. **修改前端检测逻辑**:正确调用 `isAvailable()` 方法检查TTS状态 +3. **添加延迟重试机制**:处理TTS异步初始化的时序问题 +4. **自动降级策略**:如果原生TTS不可用,自动切换到浏览器TTS + +--- + +## 📝 已修改的文件 + +### Android代码 + +#### 1. `TtsHelper.java` - 使用原生TTS引擎 +**文件位置**:`xinli-App/app/src/main/java/com/xinli/app/TtsHelper.java` + +**核心改动**: +```java +// 使用Android原生TextToSpeech引擎 +private TextToSpeech tts; + +private void initTts() { + tts = new TextToSpeech(context, new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + // 设置中文语言 + int result = tts.setLanguage(Locale.CHINESE); + isReady = true; + Log.i(TAG, "✅ Android原生TTS初始化成功(离线)"); + } + } + }); +} + +@JavascriptInterface +public void speak(String text) { + tts.speak(text, TextToSpeech.QUEUE_FLUSH, null, utteranceId); +} +``` + +**特性**: +- ✅ 完全离线工作 +- ✅ 使用系统内置TTS引擎 +- ✅ 支持中文朗读 +- ✅ 无网络超时风险 +- ✅ 不会导致ANR + +### 前端代码 + +#### 2. `assessment/taking.vue` - 测评答题页面 +**文件位置**:`xinli-ui/src/views/psychology/assessment/taking.vue` + +**核心改动**: +```javascript +initTts() { + // 检测 Android App 环境 + if (window.AndroidTTS && typeof window.AndroidTTS.isAvailable === 'function') { + // 调用 isAvailable() 方法检查 TTS 是否真的可用 + if (window.AndroidTTS.isAvailable()) { + this.isTtsSupported = true; + this.useAndroidTts = true; + console.log('✅ 使用Android原生TTS'); + return; + } else { + // TTS 可能还在初始化中,延迟重试 + console.log('⏳ Android TTS尚未就绪,延迟检查...'); + setTimeout(() => { + if (window.AndroidTTS && window.AndroidTTS.isAvailable()) { + this.isTtsSupported = true; + this.useAndroidTts = true; + console.log('✅ Android TTS 已就绪(延迟检测)'); + } else { + this.fallbackToBrowserTts(); + } + }, 500); + // 先启用按钮,避免用户等待 + this.isTtsSupported = true; + return; + } + } + // 浏览器环境 + this.fallbackToBrowserTts(); +} +``` + +**特性**: +- ✅ 调用 `isAvailable()` 验证TTS可用性 +- ✅ 500ms延迟重试处理异步初始化 +- ✅ 立即启用按钮,提升用户体验 +- ✅ 自动降级到浏览器TTS + +#### 3. `questionnaire/taking.vue` - 问卷答题页面 +**文件位置**:`xinli-ui/src/views/psychology/questionnaire/taking.vue` + +**改动**:与测评页面保持一致的检测逻辑 + +--- + +## 🚀 部署步骤 + +### 第1步:重新构建前端 + +```bash +cd c:\Users\Administrator\Desktop\Project\xinli\xinli-ui +npm run build:prod +``` + +**耗时**:约2-5分钟 + +### 第2步:部署前端到服务器 + +将 `xinli-ui/dist` 目录的所有文件复制到服务器的Web根目录。 + +### 第3步:打包Android APK + +```bash +cd c:\Users\Administrator\Desktop\Project\xinli\xinli-App +.\打包正式版APK.bat +``` + +**耗时**:约3-5分钟 + +### 第4步:查找生成的APK + +```bash +.\查找APK.bat +``` + +APK文件位置: +``` +xinli-App\app\build\outputs\apk\release\app-release.apk +``` + +### 第5步:部署到设备 + +#### 重要:必须先卸载旧版本! + +**方法1:通过手机设置卸载** +1. 设置 → 应用管理 → 找到"心理测评"App +2. 点击"卸载" + +**方法2:使用ADB命令** +```bash +adb uninstall com.xinli.app +``` + +#### 安装新版APK + +**方法1:直接安装** +1. 将APK文件复制到手机 +2. 点击文件安装 + +**方法2:使用ADB安装** +```bash +adb install app\build\outputs\apk\release\app-release.apk +``` + +--- + +## ✅ 验证测试 + +### 测试清单 + +#### 基础功能测试 +- [ ] App能正常启动,无崩溃 +- [ ] 能正常登录 +- [ ] 进入答题页面正常 + +#### TTS功能测试 +- [ ] 朗读按钮**不是灰色**(可点击) +- [ ] 点击"朗读全部"能听到声音 +- [ ] 点击"朗读题干"能听到声音 +- [ ] 点击选项旁的朗读按钮能听到声音 +- [ ] 可以正常停止朗读 +- [ ] 切换题目后朗读功能正常 + +#### ANR问题测试 +- [ ] **没有出现"应用无响应"对话框** +- [ ] 长时间使用不会卡死 +- [ ] 快速点击朗读按钮不会崩溃 + +### 查看日志(可选) + +使用ADB查看TTS日志: + +```bash +adb logcat | findstr TtsHelper +``` + +**预期日志**: +``` +TtsHelper: ✅ Android原生TTS初始化成功(离线) +TtsHelper: isAvailable: true +TtsHelper: ✅ 开始朗读: ... +``` + +**前端控制台日志**: +``` +✅ 使用Android原生TTS +``` +或 +``` +⏳ Android TTS尚未就绪,延迟检查... +✅ Android TTS 已就绪(延迟检测) +``` + +--- + +## 🔍 故障排除 + +### 问题1:按钮仍然是灰色 + +**原因**:未卸载旧版App,代码未更新 + +**解决**: +1. 完全卸载旧版App +2. 清除应用数据 +3. 重新安装新APK +4. 重启App + +### 问题2:没有声音 + +**检查项**: +1. **手机媒体音量**:确保不是0(注意不是铃声音量) +2. **TTS引擎**:检查系统是否安装了中文TTS引擎 + - 设置 → 辅助功能 → 文字转语音 + - 确认有可用的TTS引擎 +3. **查看日志**:运行 `adb logcat | findstr TTS` 查看错误信息 + +**改善音质**: +- 在手机设置中安装高质量TTS引擎 +- 推荐:Google文字转语音引擎 + +### 问题3:仍然出现ANR + +**检查**: +1. 确认安装的是新版APK(查看APK生成时间) +2. 确认前端代码已更新(检查dist目录修改时间) +3. 查看日志确认使用的是原生TTS: + ```bash + adb logcat | findstr "Android原生TTS" + ``` + +### 问题4:部分设备不支持中文TTS + +**解决**: +1. 引导用户安装中文TTS引擎 +2. 或在App中集成离线TTS SDK(如讯飞、百度) + +--- + +## 📊 修复对比 + +| 项目 | 修复前 | 修复后 | +|------|--------|--------| +| **朗读按钮状态** | ❌ 灰色禁用 | ✅ 正常可用 | +| **网络依赖** | ❌ 需要外网访问百度API | ✅ 完全离线 | +| **ANR问题** | ❌ 内网环境会ANR | ✅ 不会ANR | +| **TTS引擎** | ❌ 在线API | ✅ Android原生引擎 | +| **音质** | 一般(百度API) | 良好(取决于设备) | +| **检测逻辑** | ❌ 只检查对象存在 | ✅ 调用isAvailable()验证 | +| **降级策略** | ❌ 无 | ✅ 自动降级到浏览器TTS | +| **初始化处理** | ❌ 无延迟重试 | ✅ 500ms延迟重试 | + +--- + +## 🎉 技术优势 + +### 1. 完全离线 +- 不依赖任何外部API +- 内网环境正常工作 +- 无网络超时风险 + +### 2. 高可用性 +- 使用系统内置TTS引擎 +- 双重保障:原生TTS + 浏览器TTS +- 异步初始化不阻塞UI + +### 3. 用户体验 +- 朗读按钮立即可用 +- 无需等待网络响应 +- 不会出现ANR + +### 4. 维护性 +- 代码简洁清晰 +- 统一的检测逻辑 +- 完善的日志输出 + +--- + +## 📚 技术细节 + +### Android原生TTS工作流程 + +``` +1. App启动 + ↓ +2. 初始化TextToSpeech引擎(异步) + ↓ +3. onInit回调 → 设置中文语言 + ↓ +4. 设置isReady = true + ↓ +5. 前端调用isAvailable() → 返回true + ↓ +6. 前端启用朗读按钮 + ↓ +7. 用户点击朗读 → 调用speak() + ↓ +8. TTS引擎合成语音并播放 +``` + +### 前端检测流程 + +``` +1. 页面加载 → initTts() + ↓ +2. 检查window.AndroidTTS是否存在 + ↓ +3. 调用AndroidTTS.isAvailable() + ↓ +4. 如果返回false → 延迟500ms重试 + ↓ +5. 如果仍然false → 降级到浏览器TTS + ↓ +6. 设置isTtsSupported = true + ↓ +7. 朗读按钮可用 +``` + +### 为什么需要延迟重试? + +Android的TextToSpeech初始化是**异步**的: +- `new TextToSpeech()` 立即返回 +- 实际初始化在后台进行 +- `onInit()` 回调可能需要100-500ms +- 前端页面加载可能比TTS初始化更快 + +**解决方案**: +- 第一次检查失败 → 延迟500ms重试 +- 同时先启用按钮,提升用户体验 +- 用户点击时如果还未就绪 → 内部再延迟重试 + +--- + +## ⚠️ 注意事项 + +### 1. 必须卸载旧版 +新APK的签名可能与旧版不同,直接安装可能失败或代码不更新。 + +### 2. 前端也需要更新 +只更新APK不够,前端检测逻辑也必须更新,否则按钮仍然是灰色。 + +### 3. 设备TTS引擎差异 +不同品牌手机的TTS引擎音质有差异: +- **华为/小米/OPPO**:通常有高质量中文TTS +- **三星**:音质良好 +- **低端设备**:可能音质较差或不支持中文 + +### 4. 浏览器版本不受影响 +- Web版(PC浏览器)继续使用浏览器的Web Speech API +- 修改仅影响Android App + +--- + +## 🔄 未来优化方向 + +### 短期(可选) +1. **集成高质量离线TTS SDK** + - 讯飞语音SDK + - 百度语音SDK + - 提供更好的音质和更多音色选择 + +### 长期(可选) +2. **支持语速/音调调节** + - 在App中添加TTS设置界面 + - 让用户自定义语音参数 + +3. **多语言支持** + - 检测题目语言 + - 自动切换TTS语言 + +--- + +## 📞 技术支持 + +如果遇到问题: + +1. **查看日志** + ```bash + adb logcat | findstr "TtsHelper\|AndroidTTS" + ``` + +2. **检查TTS引擎** + - 手机设置 → 辅助功能 → 文字转语音 + - 确认有可用的中文TTS引擎 + +3. **验证安装** + ```bash + # 查看已安装App版本 + adb shell pm list packages -f | findstr xinli + + # 查看APK信息 + adb shell dumpsys package com.xinli.app | findstr version + ``` + +--- + +**修复完成日期**:2025-01-27 +**测试状态**:✅ 待部署验证 +**适用环境**:内网/外网均可使用