修正消息中心不显示
This commit is contained in:
@@ -69,8 +69,8 @@ INSERT INTO `tb_sys_permission` (id,permission_id, name, code, description, modu
|
|||||||
('19','perm_sensitive_manage', '敏感词管理', 'sensitive:manage', '敏感词管理权限', 'module_sensitive', '1', now());
|
('19','perm_sensitive_manage', '敏感词管理', 'sensitive:manage', '敏感词管理权限', 'module_sensitive', '1', now());
|
||||||
|
|
||||||
-- 插入角色-权限关联数据
|
-- 插入角色-权限关联数据
|
||||||
INSERT INTO `tb_sys_role_permission` (id, role_id, permission_id, creator, create_time) VALUES
|
|
||||||
-- 超级管理员:拥有所有权限
|
-- 超级管理员:拥有所有权限
|
||||||
|
INSERT INTO `tb_sys_role_permission` (id, role_id, permission_id, creator, create_time) VALUES
|
||||||
('1', 'superadmin', 'perm_default', '1', now()),
|
('1', 'superadmin', 'perm_default', '1', now()),
|
||||||
('2', 'superadmin', 'perm_system_manage', '1', now()),
|
('2', 'superadmin', 'perm_system_manage', '1', now()),
|
||||||
('3', 'superadmin', 'perm_system_dept_manage', '1', now()),
|
('3', 'superadmin', 'perm_system_dept_manage', '1', now()),
|
||||||
@@ -116,8 +116,8 @@ INSERT INTO `tb_sys_role_permission` (id, role_id, permission_id, creator, creat
|
|||||||
('45', 'freedom', 'perm_message_view', '1', now());
|
('45', 'freedom', 'perm_message_view', '1', now());
|
||||||
|
|
||||||
-- 插入前端菜单数据
|
-- 插入前端菜单数据
|
||||||
INSERT INTO `tb_sys_menu` VALUES
|
|
||||||
-- 用户前端菜单 (100-699)
|
-- 用户前端菜单 (100-699)
|
||||||
|
INSERT INTO `tb_sys_menu` VALUES
|
||||||
('100', 'menu_home', '首页', NULL, '/home', 'user/home/HomeView', NULL, 1, 1, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:49:56', NULL, 0),
|
('100', 'menu_home', '首页', NULL, '/home', 'user/home/HomeView', NULL, 1, 1, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:49:56', NULL, 0),
|
||||||
('101', 'menu_resource_hot', '热门资源', NULL, '/resource-hot', 'user/resource-center/HotResourceView', NULL, 2, 3, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:49:56', NULL, 0),
|
('101', 'menu_resource_hot', '热门资源', NULL, '/resource-hot', 'user/resource-center/HotResourceView', NULL, 2, 3, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:49:56', NULL, 0),
|
||||||
('200', 'menu_resource_center', '资源中心', NULL, '/resource-center', 'user/resource-center/ResourceCenterView', NULL, 2, 1, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:49:56', NULL, 0),
|
('200', 'menu_resource_center', '资源中心', NULL, '/resource-center', 'user/resource-center/ResourceCenterView', NULL, 2, 1, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:49:56', NULL, 0),
|
||||||
@@ -128,13 +128,13 @@ INSERT INTO `tb_sys_menu` VALUES
|
|||||||
('304', 'menu_course_detail', '课程详情', 'menu_study_plan', '/study-plan/course-detail', 'user/study-plan/CourseDetailView', NULL, 4, 3, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:48:39', NULL, 0),
|
('304', 'menu_course_detail', '课程详情', 'menu_study_plan', '/study-plan/course-detail', 'user/study-plan/CourseDetailView', NULL, 4, 3, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:48:39', NULL, 0),
|
||||||
('305', 'menu_course_study', '课程学习', 'menu_study_plan', '/study-plan/course-study', 'user/study-plan/CourseStudyView', NULL, 5, 3, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:48:39', NULL, 0),
|
('305', 'menu_course_study', '课程学习', 'menu_study_plan', '/study-plan/course-study', 'user/study-plan/CourseStudyView', NULL, 5, 3, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:48:39', NULL, 0),
|
||||||
('400', 'menu_user_dropdown', '用户下拉菜单', NULL, '', '', NULL, 4, 0, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:49:56', NULL, 0),
|
('400', 'menu_user_dropdown', '用户下拉菜单', NULL, '', '', NULL, 4, 0, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:49:56', NULL, 0),
|
||||||
('401', 'menu_user_center', '个人中心', 'menu_user_dropdown', '/user-center', 'user/user-center/UserCenterView', NULL, 4, 1, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:49:56', NULL, 0),
|
('401', 'menu_user_center', '个人中心', 'menu_user_dropdown', '/user-center', 'user/user-center/UserCenterLayout', NULL, 4, 1, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:49:56', NULL, 0),
|
||||||
('402', 'menu_learning_records', '学习记录', 'menu_user_center', '/user-center/learning-records', 'user/user-center/LearningRecordsView', NULL, 1, 0, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:49:56', NULL, 0),
|
('402', 'menu_learning_records', '学习记录', 'menu_user_center', '/user-center/learning-records', 'user/user-center/LearningRecordsView', NULL, 1, 0, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:49:56', NULL, 0),
|
||||||
('403', 'menu_my_favorites', '我的收藏', 'menu_user_center', '/user-center/favorites', 'user/user-center/MyFavoritesView', NULL, 2, 0, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:49:56', NULL, 0),
|
('403', 'menu_my_favorites', '我的收藏', 'menu_user_center', '/user-center/favorites', 'user/user-center/MyFavoritesView', NULL, 2, 0, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:49:56', NULL, 0),
|
||||||
('404', 'menu_my_achievements', '我的成就', 'menu_user_center', '/user-center/achievements', 'user/user-center/MyAchievementsView', NULL, 3, 0, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:49:56', NULL, 0),
|
('404', 'menu_my_achievements', '我的成就', 'menu_user_center', '/user-center/achievements', 'user/user-center/MyAchievementsView', NULL, 3, 0, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:49:56', NULL, 0),
|
||||||
('500', 'menu_profile', '账号中心', 'menu_user_dropdown', '/profile', 'user/profile/ProfileView', NULL, 5, 1, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:49:56', NULL, 0),
|
('500', 'menu_profile', '账号中心', 'menu_user_dropdown', '/profile', 'user/user-center/UserCenterLayout', NULL, 5, 1, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:49:56', NULL, 0),
|
||||||
('501', 'menu_personal_info', '个人信息', 'menu_profile', '/profile/personal-info', 'user/profile/PersonalInfoView', NULL, 1, 0, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:48:39', NULL, 0),
|
('501', 'menu_personal_info', '个人信息', 'menu_profile', '/profile/personal-info', 'user/user-center/profile/PersonalInfoView', NULL, 1, 0, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:48:39', NULL, 0),
|
||||||
('502', 'menu_account_settings', '账号设置', 'menu_profile', '/profile/account-settings', 'user/profile/AccountSettingsView', NULL, 2, 0, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:48:39', NULL, 0),
|
('502', 'menu_account_settings', '账号设置', 'menu_profile', '/profile/account-settings', 'user/user-center/profile/AccountSettingsView', NULL, 2, 0, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:48:39', NULL, 0),
|
||||||
('503', 'menu_search', '搜索', NULL, '/search', 'user/resource-center/SearchView', NULL, 3, 0, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:48:39', NULL, 0),
|
('503', 'menu_search', '搜索', NULL, '/search', 'user/resource-center/SearchView', NULL, 3, 0, 'NavigationLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:48:39', NULL, 0),
|
||||||
-- 管理后台菜单 (1000-8999)
|
-- 管理后台菜单 (1000-8999)
|
||||||
('1000', 'menu_admin_overview', '系统总览', NULL, '/admin/overview', 'admin/overview/SystemOverviewView', 'admin/overview.svg', 1, 0, 'SidebarLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:52:32', NULL, 0),
|
('1000', 'menu_admin_overview', '系统总览', NULL, '/admin/overview', 'admin/overview/SystemOverviewView', 'admin/overview.svg', 1, 0, 'SidebarLayout', '1', NULL, '2025-10-27 17:26:06', '2025-10-29 11:52:32', NULL, 0),
|
||||||
@@ -177,8 +177,8 @@ INSERT INTO `tb_sys_menu` VALUES
|
|||||||
('651', 'menu_user_message_detail', '消息详情', 'menu_user_message_center', '/user/message/detail/:messageID', 'user/message/MyMessageDetailView', NULL, 1, 3, 'NavigationLayout', '1', NULL, '2025-11-13 10:00:00', '2025-11-13 10:00:00', NULL, 0);
|
('651', 'menu_user_message_detail', '消息详情', 'menu_user_message_center', '/user/message/detail/:messageID', 'user/message/MyMessageDetailView', NULL, 1, 3, 'NavigationLayout', '1', NULL, '2025-11-13 10:00:00', '2025-11-13 10:00:00', NULL, 0);
|
||||||
|
|
||||||
-- 插入菜单权限关联数据
|
-- 插入菜单权限关联数据
|
||||||
INSERT INTO `tb_sys_menu_permission` (id, permission_id, menu_id, creator, create_time) VALUES
|
|
||||||
-- 前端菜单权限关联
|
-- 前端菜单权限关联
|
||||||
|
INSERT INTO `tb_sys_menu_permission` (id, permission_id, menu_id, creator, create_time) VALUES
|
||||||
('100', 'perm_default', 'menu_home', '1', now()),
|
('100', 'perm_default', 'menu_home', '1', now()),
|
||||||
('102', 'perm_default', 'menu_resource_hot', '1', now()),
|
('102', 'perm_default', 'menu_resource_hot', '1', now()),
|
||||||
('101', 'perm_default', 'menu_resource_center', '1', now()),
|
('101', 'perm_default', 'menu_resource_center', '1', now()),
|
||||||
@@ -241,11 +241,7 @@ INSERT INTO `tb_sys_menu_permission` (id, permission_id, menu_id, creator, creat
|
|||||||
|
|
||||||
-- 消息通知管理菜单权限关联
|
-- 消息通知管理菜单权限关联
|
||||||
('240', 'perm_message_manage', 'menu_admin_message_manage', '1', now()),
|
('240', 'perm_message_manage', 'menu_admin_message_manage', '1', now()),
|
||||||
('241', 'perm_message_manage', 'menu_admin_message_list', '1', now()),
|
|
||||||
('242', 'perm_message_send', 'menu_admin_message_create', '1', now()),
|
|
||||||
('243', 'perm_message_manage', 'menu_admin_message_detail', '1', now()),
|
|
||||||
|
|
||||||
-- 用户端消息中心权限关联
|
-- 用户端消息中心权限关联
|
||||||
('250', 'perm_message_view', 'menu_user_message_center', '1', now()),
|
('250', 'perm_default', 'menu_user_message_center', '1', now()),
|
||||||
('251', 'perm_message_view', 'menu_user_message_detail', '1', now());
|
('251', 'perm_default', 'menu_user_message_detail', '1', now());
|
||||||
|
|
||||||
|
|||||||
@@ -97,6 +97,51 @@ execute_init_script() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 执行敏感词导入
|
||||||
|
import_sensitive_words() {
|
||||||
|
print_message $BLUE "开始导入敏感词数据..."
|
||||||
|
|
||||||
|
# 检查conda是否可用
|
||||||
|
if ! command -v conda &> /dev/null; then
|
||||||
|
print_message $YELLOW "conda命令未找到,跳过敏感词导入"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 检查schoolNewsCrawler环境是否存在
|
||||||
|
if ! conda env list | grep -q "schoolNewsCrawler"; then
|
||||||
|
print_message $YELLOW "conda环境 'schoolNewsCrawler' 不存在,跳过敏感词导入"
|
||||||
|
print_message $YELLOW "提示: 可以使用以下命令创建环境: conda create -n schoolNewsCrawler python=3.10"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 切换到敏感词脚本目录
|
||||||
|
local sensitive_dir="$SCRIPT_DIR/sensitiveData"
|
||||||
|
if [ ! -d "$sensitive_dir" ]; then
|
||||||
|
print_message $YELLOW "敏感词脚本目录不存在: $sensitive_dir"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$sensitive_dir/writeWord.py" ]; then
|
||||||
|
print_message $YELLOW "敏感词脚本不存在: $sensitive_dir/writeWord.py"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_message $BLUE "激活conda环境: schoolNewsCrawler"
|
||||||
|
cd "$sensitive_dir"
|
||||||
|
|
||||||
|
# 使用conda run来在指定环境中执行命令,添加-y参数自动确认
|
||||||
|
conda run -n schoolNewsCrawler python writeWord.py -y
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
print_message $GREEN "敏感词数据导入成功"
|
||||||
|
else
|
||||||
|
print_message $YELLOW "敏感词数据导入失败,但不影响系统运行"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 返回脚本目录
|
||||||
|
cd "$SCRIPT_DIR"
|
||||||
|
}
|
||||||
|
|
||||||
# 验证初始化结果
|
# 验证初始化结果
|
||||||
verify_initialization() {
|
verify_initialization() {
|
||||||
print_message $BLUE "验证初始化结果..."
|
print_message $BLUE "验证初始化结果..."
|
||||||
@@ -120,6 +165,14 @@ verify_initialization() {
|
|||||||
else
|
else
|
||||||
print_message $YELLOW "默认用户创建失败"
|
print_message $YELLOW "默认用户创建失败"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# 检查敏感词数量
|
||||||
|
local sensitive_count=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASSWORD" -D"$DB_NAME" -e "SELECT COUNT(*) FROM tb_sensitive_word;" 2>/dev/null | tail -n 1)
|
||||||
|
if [ -n "$sensitive_count" ] && [ "$sensitive_count" -gt 0 ]; then
|
||||||
|
print_message $GREEN "敏感词数据: $sensitive_count 个"
|
||||||
|
else
|
||||||
|
print_message $YELLOW "敏感词数据: 0 个 (可能未导入或表不存在)"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# 显示初始化信息
|
# 显示初始化信息
|
||||||
@@ -146,6 +199,8 @@ show_initialization_info() {
|
|||||||
print_message $YELLOW " - AI智能体"
|
print_message $YELLOW " - AI智能体"
|
||||||
print_message $YELLOW " - 系统配置"
|
print_message $YELLOW " - 系统配置"
|
||||||
print_message $YELLOW " - 文件管理"
|
print_message $YELLOW " - 文件管理"
|
||||||
|
print_message $YELLOW " - 敏感词过滤"
|
||||||
|
print_message $YELLOW " - 消息通知"
|
||||||
print_message $BLUE "====================================================="
|
print_message $BLUE "====================================================="
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +208,7 @@ show_initialization_info() {
|
|||||||
main() {
|
main() {
|
||||||
print_message $BLUE "====================================================="
|
print_message $BLUE "====================================================="
|
||||||
print_message $BLUE "校园思政新闻平台数据库重新初始化脚本"
|
print_message $BLUE "校园思政新闻平台数据库重新初始化脚本"
|
||||||
print_message $BLUE "版本: 1.0.0"
|
print_message $BLUE "版本: 1.1.0"
|
||||||
print_message $BLUE "====================================================="
|
print_message $BLUE "====================================================="
|
||||||
|
|
||||||
# 检查MySQL连接
|
# 检查MySQL连接
|
||||||
@@ -170,12 +225,15 @@ main() {
|
|||||||
# 执行初始化脚本
|
# 执行初始化脚本
|
||||||
execute_init_script
|
execute_init_script
|
||||||
|
|
||||||
|
# 导入敏感词数据
|
||||||
|
|
||||||
# 验证初始化结果
|
# 验证初始化结果
|
||||||
verify_initialization
|
verify_initialization
|
||||||
|
|
||||||
# 显示初始化信息
|
# 显示初始化信息
|
||||||
show_initialization_info
|
show_initialization_info
|
||||||
|
import_sensitive_words
|
||||||
|
|
||||||
print_message $GREEN "初始化完成!"
|
print_message $GREEN "初始化完成!"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
import pymysql
|
import pymysql
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import argparse
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
# 数据库配置
|
# 数据库配置
|
||||||
@@ -110,13 +111,25 @@ def check_duplicates(connection, words):
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""主函数"""
|
"""主函数"""
|
||||||
|
# 解析命令行参数
|
||||||
|
parser = argparse.ArgumentParser(description='敏感词批量导入工具')
|
||||||
|
parser.add_argument('-y', '--yes', action='store_true',
|
||||||
|
help='自动确认导入,跳过交互式确认')
|
||||||
|
parser.add_argument('--file', type=str,
|
||||||
|
help='指定敏感词文件路径(默认: sensitive_word_dict.txt)')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
print("=" * 50)
|
print("=" * 50)
|
||||||
print("敏感词批量导入工具")
|
print("敏感词批量导入工具")
|
||||||
print("=" * 50)
|
print("=" * 50)
|
||||||
|
|
||||||
# 获取脚本所在目录
|
# 获取敏感词文件路径
|
||||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
if args.file:
|
||||||
dict_file = os.path.join(script_dir, 'sensitive_word_dict.txt')
|
dict_file = args.file
|
||||||
|
else:
|
||||||
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
dict_file = os.path.join(script_dir, 'sensitive_word_dict.txt')
|
||||||
|
|
||||||
# 检查敏感词文件是否存在
|
# 检查敏感词文件是否存在
|
||||||
if not os.path.exists(dict_file):
|
if not os.path.exists(dict_file):
|
||||||
@@ -150,11 +163,20 @@ def main():
|
|||||||
|
|
||||||
# 确认导入
|
# 确认导入
|
||||||
print(f"准备导入 {len(words)} 个敏感词到数据库")
|
print(f"准备导入 {len(words)} 个敏感词到数据库")
|
||||||
confirm = input("是否继续?(y/N): ").strip().lower()
|
|
||||||
|
|
||||||
if confirm != 'y':
|
if args.yes:
|
||||||
print("用户取消导入")
|
print("自动确认模式,开始导入...")
|
||||||
return
|
else:
|
||||||
|
try:
|
||||||
|
confirm = input("是否继续?(y/N): ").strip().lower()
|
||||||
|
if confirm != 'y':
|
||||||
|
print("用户取消导入")
|
||||||
|
return
|
||||||
|
except EOFError:
|
||||||
|
print("检测到非交互式环境,自动确认导入...")
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\n用户中断导入")
|
||||||
|
return
|
||||||
|
|
||||||
# 批量插入
|
# 批量插入
|
||||||
print("开始批量导入敏感词...")
|
print("开始批量导入敏感词...")
|
||||||
@@ -1,331 +0,0 @@
|
|||||||
# 成就模块迁移指南
|
|
||||||
|
|
||||||
## 📝 迁移概述
|
|
||||||
|
|
||||||
成就相关功能已从 `usercenter` 模块迁移到独立的 `achievement` 模块。
|
|
||||||
|
|
||||||
### 迁移日期
|
|
||||||
2025-10-24
|
|
||||||
|
|
||||||
### 迁移原因
|
|
||||||
- ✅ **模块职责分离** - usercenter负责用户中心,achievement专注于成就系统
|
|
||||||
- ✅ **更好的可维护性** - 独立模块易于管理和扩展
|
|
||||||
- ✅ **清晰的依赖关系** - 减少模块间的耦合
|
|
||||||
- ✅ **可扩展性** - 便于添加新的成就类型和功能
|
|
||||||
|
|
||||||
## 🔄 包路径变更
|
|
||||||
|
|
||||||
### API接口变更
|
|
||||||
|
|
||||||
**旧路径(已删除):**
|
|
||||||
```java
|
|
||||||
org.xyzh.api.usercenter.achievement.UserAchievementService
|
|
||||||
```
|
|
||||||
|
|
||||||
**新路径:**
|
|
||||||
```java
|
|
||||||
org.xyzh.api.achievement.AchievementService
|
|
||||||
```
|
|
||||||
|
|
||||||
### 服务实现变更
|
|
||||||
|
|
||||||
**旧路径(已删除):**
|
|
||||||
```java
|
|
||||||
org.xyzh.usercenter.service.UCUserAchievementService
|
|
||||||
org.xyzh.usercenter.service.impl.UCUserAchievementServiceImpl
|
|
||||||
```
|
|
||||||
|
|
||||||
**新路径:**
|
|
||||||
```java
|
|
||||||
org.xyzh.api.achievement.AchievementService
|
|
||||||
org.xyzh.achievement.service.impl.ACHAchievementServiceImpl
|
|
||||||
```
|
|
||||||
|
|
||||||
### Mapper变更
|
|
||||||
|
|
||||||
**旧路径(已删除):**
|
|
||||||
```java
|
|
||||||
org.xyzh.usercenter.mapper.AchievementMapper
|
|
||||||
org.xyzh.usercenter.mapper.UserAchievementMapper
|
|
||||||
```
|
|
||||||
|
|
||||||
**新路径:**
|
|
||||||
```java
|
|
||||||
org.xyzh.achievement.mapper.AchievementMapper
|
|
||||||
org.xyzh.achievement.mapper.UserAchievementMapper
|
|
||||||
org.xyzh.achievement.mapper.UserAchievementProgressMapper // 新增
|
|
||||||
```
|
|
||||||
|
|
||||||
### Controller变更
|
|
||||||
|
|
||||||
**旧路径(已删除):**
|
|
||||||
```java
|
|
||||||
org.xyzh.usercenter.controller.UserAchievementController
|
|
||||||
```
|
|
||||||
|
|
||||||
**新路径:**
|
|
||||||
```java
|
|
||||||
org.xyzh.achievement.controller.AchievementController
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📦 依赖变更
|
|
||||||
|
|
||||||
### 如果你的模块之前依赖了成就功能
|
|
||||||
|
|
||||||
#### 旧的依赖配置(需要删除):
|
|
||||||
```xml
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.xyzh</groupId>
|
|
||||||
<artifactId>api-usercenter</artifactId> <!-- 包含成就接口 -->
|
|
||||||
<version>1.0.0</version>
|
|
||||||
</dependency>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 新的依赖配置(需要添加):
|
|
||||||
```xml
|
|
||||||
<!-- API接口依赖 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.xyzh</groupId>
|
|
||||||
<artifactId>api-achievement</artifactId>
|
|
||||||
<version>1.0.0</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- 如果需要使用实现类(通常不需要,使用Dubbo远程调用) -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.xyzh</groupId>
|
|
||||||
<artifactId>achievement</artifactId>
|
|
||||||
<version>1.0.0</version>
|
|
||||||
</dependency>
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔧 代码迁移步骤
|
|
||||||
|
|
||||||
### 1. 更新导入语句
|
|
||||||
|
|
||||||
**旧代码:**
|
|
||||||
```java
|
|
||||||
import org.xyzh.api.usercenter.achievement.UserAchievementService;
|
|
||||||
```
|
|
||||||
|
|
||||||
**新代码:**
|
|
||||||
```java
|
|
||||||
import org.xyzh.api.achievement.AchievementService;
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 更新服务注入
|
|
||||||
|
|
||||||
**旧代码:**
|
|
||||||
```java
|
|
||||||
@Autowired
|
|
||||||
private UserAchievementService userAchievementService;
|
|
||||||
```
|
|
||||||
|
|
||||||
**新代码:**
|
|
||||||
```java
|
|
||||||
@Autowired
|
|
||||||
private AchievementService achievementService;
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 更新方法调用
|
|
||||||
|
|
||||||
大部分方法签名保持不变,只需更新服务名称:
|
|
||||||
|
|
||||||
**旧代码:**
|
|
||||||
```java
|
|
||||||
ResultDomain<TbUserAchievement> result = userAchievementService.getUserAchievements(userID, type);
|
|
||||||
```
|
|
||||||
|
|
||||||
**新代码:**
|
|
||||||
```java
|
|
||||||
ResultDomain<TbUserAchievement> result = achievementService.getUserAchievements(userID, type);
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. 新增功能调用
|
|
||||||
|
|
||||||
新的成就系统增加了事件驱动机制:
|
|
||||||
|
|
||||||
```java
|
|
||||||
// 发布成就事件
|
|
||||||
AchievementEvent event = AchievementEvent.builder(userID, AchievementEventType.COURSE_COMPLETED)
|
|
||||||
.value(1)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// 方式1:使用Spring事件发布(推荐)
|
|
||||||
eventPublisher.publishEvent(event);
|
|
||||||
|
|
||||||
// 方式2:直接调用服务
|
|
||||||
achievementService.processAchievementEvent(event);
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🗄️ 数据库变更
|
|
||||||
|
|
||||||
### 新增表
|
|
||||||
|
|
||||||
```sql
|
|
||||||
-- 用户成就进度表(新增)
|
|
||||||
CREATE TABLE tb_user_achievement_progress (
|
|
||||||
id VARCHAR(32) NOT NULL,
|
|
||||||
user_id VARCHAR(32) NOT NULL,
|
|
||||||
achievement_id VARCHAR(32) NOT NULL,
|
|
||||||
current_value INT DEFAULT 0,
|
|
||||||
target_value INT DEFAULT 0,
|
|
||||||
progress_percentage INT DEFAULT 0,
|
|
||||||
completed TINYINT(1) DEFAULT 0,
|
|
||||||
last_update_time DATETIME,
|
|
||||||
create_time DATETIME,
|
|
||||||
PRIMARY KEY (id),
|
|
||||||
UNIQUE KEY uk_user_achievement_progress (user_id, achievement_id)
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
### 已有表
|
|
||||||
|
|
||||||
`tb_achievement` 和 `tb_user_achievement` 表结构保持不变,无需迁移数据。
|
|
||||||
|
|
||||||
## 🌐 REST API变更
|
|
||||||
|
|
||||||
### 接口路径变更
|
|
||||||
|
|
||||||
**旧路径:**
|
|
||||||
```
|
|
||||||
/usercenter/achievement/*
|
|
||||||
```
|
|
||||||
|
|
||||||
**新路径:**
|
|
||||||
```
|
|
||||||
/achievement/*
|
|
||||||
```
|
|
||||||
|
|
||||||
### 具体接口映射
|
|
||||||
|
|
||||||
| 功能 | 旧接口 | 新接口 | 变化 |
|
|
||||||
|-----|-------|-------|-----|
|
|
||||||
| 获取所有成就 | GET /usercenter/achievement/list | GET /achievement/list | 路径变更 |
|
|
||||||
| 获取用户成就 | GET /usercenter/achievement/user/{userID} | GET /achievement/user/{userID} | 路径变更 |
|
|
||||||
| 获取我的成就 | - | GET /achievement/my | **新增** |
|
|
||||||
| 授予成就 | POST /usercenter/achievement/grant | POST /achievement/grant | 路径变更 |
|
|
||||||
| 检查条件 | GET /usercenter/achievement/condition/{userID}/{achievementID} | GET /achievement/condition/check/{userID}/{achievementID} | 路径变更 |
|
|
||||||
| 获取进度 | - | GET /achievement/progress/{userID} | **新增** |
|
|
||||||
| 处理事件 | - | POST /achievement/event/process | **新增** |
|
|
||||||
| 获取统计 | - | GET /achievement/statistics/{userID} | **新增** |
|
|
||||||
| 排行榜 | - | GET /achievement/ranking | **新增** |
|
|
||||||
|
|
||||||
## ✨ 新增功能
|
|
||||||
|
|
||||||
### 1. 事件驱动机制
|
|
||||||
```java
|
|
||||||
// 自动监听业务事件并触发成就检测
|
|
||||||
@Autowired
|
|
||||||
private ApplicationEventPublisher eventPublisher;
|
|
||||||
|
|
||||||
AchievementEvent event = AchievementEvent.builder(userID, eventType)
|
|
||||||
.value(value)
|
|
||||||
.build();
|
|
||||||
eventPublisher.publishEvent(event);
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 成就进度追踪
|
|
||||||
```java
|
|
||||||
// 查询用户的成就进度
|
|
||||||
ResultDomain<TbUserAchievementProgress> result =
|
|
||||||
achievementService.getMyAchievementProgress(achievementID);
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 策略模式检测器
|
|
||||||
- 可扩展的成就检测器
|
|
||||||
- 支持多种成就类型
|
|
||||||
- 易于添加新的成就类型
|
|
||||||
|
|
||||||
### 4. 统计和排行榜
|
|
||||||
```java
|
|
||||||
// 获取用户统计
|
|
||||||
ResultDomain<Map<String, Object>> stats =
|
|
||||||
achievementService.getUserAchievementStatistics(userID);
|
|
||||||
|
|
||||||
// 获取排行榜
|
|
||||||
ResultDomain<Map<String, Object>> ranking =
|
|
||||||
achievementService.getAchievementRanking(10);
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🚨 注意事项
|
|
||||||
|
|
||||||
### 1. 破坏性变更
|
|
||||||
|
|
||||||
#### ❌ 已删除的类(不再可用)
|
|
||||||
- `org.xyzh.api.usercenter.achievement.UserAchievementService`
|
|
||||||
- `org.xyzh.usercenter.service.UCUserAchievementService`
|
|
||||||
- `org.xyzh.usercenter.mapper.AchievementMapper`
|
|
||||||
- `org.xyzh.usercenter.controller.UserAchievementController`
|
|
||||||
|
|
||||||
#### ✅ 对应的新类
|
|
||||||
- `org.xyzh.api.achievement.AchievementService`
|
|
||||||
- `org.xyzh.achievement.service.impl.ACHAchievementServiceImpl`
|
|
||||||
- `org.xyzh.achievement.mapper.AchievementMapper`
|
|
||||||
- `org.xyzh.achievement.controller.AchievementController`
|
|
||||||
|
|
||||||
### 2. 接口变化
|
|
||||||
|
|
||||||
新的 `AchievementService` 接口方法更多、更完善:
|
|
||||||
- ✅ 所有旧方法都有对应的新方法
|
|
||||||
- ✅ 新增了事件处理、进度查询、统计等功能
|
|
||||||
- ✅ 方法签名大部分保持兼容
|
|
||||||
|
|
||||||
### 3. 前端调用
|
|
||||||
|
|
||||||
如果你的前端代码调用了成就相关API,需要:
|
|
||||||
1. 更新API路径:`/usercenter/achievement/*` → `/achievement/*`
|
|
||||||
2. 检查返回数据格式(大部分保持兼容)
|
|
||||||
3. 利用新增的API(进度、统计、排行榜等)
|
|
||||||
|
|
||||||
## 📋 迁移检查清单
|
|
||||||
|
|
||||||
迁移时请检查以下项目:
|
|
||||||
|
|
||||||
- [ ] 更新 pom.xml 依赖
|
|
||||||
- [ ] 更新 import 语句
|
|
||||||
- [ ] 更新服务注入
|
|
||||||
- [ ] 更新方法调用
|
|
||||||
- [ ] 测试成就创建功能
|
|
||||||
- [ ] 测试成就授予功能
|
|
||||||
- [ ] 测试成就查询功能
|
|
||||||
- [ ] 测试事件触发功能(如有)
|
|
||||||
- [ ] 更新前端API路径(如有)
|
|
||||||
- [ ] 更新相关文档
|
|
||||||
- [ ] 执行集成测试
|
|
||||||
|
|
||||||
## 🆘 常见问题
|
|
||||||
|
|
||||||
### Q1: 编译报错找不到 UserAchievementService
|
|
||||||
**A:** 更新 import 语句为:
|
|
||||||
```java
|
|
||||||
import org.xyzh.api.achievement.AchievementService;
|
|
||||||
```
|
|
||||||
|
|
||||||
### Q2: 旧的成就数据会丢失吗?
|
|
||||||
**A:** 不会。数据库表结构保持不变,所有数据完整保留。
|
|
||||||
|
|
||||||
### Q3: 需要修改数据库吗?
|
|
||||||
**A:** 需要执行新表创建SQL(`tb_user_achievement_progress`),见 `.bin/mysql/sql/createTableAchievement.sql`。
|
|
||||||
|
|
||||||
### Q4: 如何使用新的事件驱动功能?
|
|
||||||
**A:** 参考 `README.md` 中的"使用方法"章节。
|
|
||||||
|
|
||||||
### Q5: admin模块已经自动配置好了吗?
|
|
||||||
**A:** 是的,admin模块的pom.xml已自动添加achievement依赖。
|
|
||||||
|
|
||||||
## 📚 相关文档
|
|
||||||
|
|
||||||
- [成就系统使用文档](../README.md)
|
|
||||||
- [数据库建表SQL](../../.bin/mysql/sql/createTableAchievement.sql)
|
|
||||||
|
|
||||||
## 👥 联系支持
|
|
||||||
|
|
||||||
如果在迁移过程中遇到问题,请联系:
|
|
||||||
- 开发者:yslg
|
|
||||||
- 创建Issue或PR
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**迁移完成日期**: 2025-10-24
|
|
||||||
**版本**: 1.0.0
|
|
||||||
|
|
||||||
@@ -18,6 +18,7 @@ import org.xyzh.common.core.event.AchievementEvent;
|
|||||||
import org.xyzh.common.core.page.PageDomain;
|
import org.xyzh.common.core.page.PageDomain;
|
||||||
import org.xyzh.common.core.page.PageParam;
|
import org.xyzh.common.core.page.PageParam;
|
||||||
import org.xyzh.common.dto.user.TbSysUser;
|
import org.xyzh.common.dto.user.TbSysUser;
|
||||||
|
import org.xyzh.common.dto.user.TbSysUserInfo;
|
||||||
import org.xyzh.common.dto.usercenter.TbAchievement;
|
import org.xyzh.common.dto.usercenter.TbAchievement;
|
||||||
import org.xyzh.common.dto.usercenter.TbUserAchievement;
|
import org.xyzh.common.dto.usercenter.TbUserAchievement;
|
||||||
import org.xyzh.common.dto.usercenter.TbUserAchievementProgress;
|
import org.xyzh.common.dto.usercenter.TbUserAchievementProgress;
|
||||||
@@ -26,6 +27,7 @@ import org.xyzh.common.utils.IDUtils;
|
|||||||
import org.xyzh.common.vo.AchievementVO;
|
import org.xyzh.common.vo.AchievementVO;
|
||||||
import org.xyzh.system.utils.LoginUtil;
|
import org.xyzh.system.utils.LoginUtil;
|
||||||
import org.xyzh.api.system.permission.ResourcePermissionService;
|
import org.xyzh.api.system.permission.ResourcePermissionService;
|
||||||
|
import org.xyzh.system.mapper.UserInfoMapper;
|
||||||
import org.xyzh.common.vo.UserDeptRoleVO;
|
import org.xyzh.common.vo.UserDeptRoleVO;
|
||||||
import org.xyzh.common.core.enums.ResourceType;
|
import org.xyzh.common.core.enums.ResourceType;
|
||||||
|
|
||||||
@@ -62,6 +64,9 @@ public class ACHAchievementServiceImpl implements AchievementService {
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private RedisService redisService;
|
private RedisService redisService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserInfoMapper userInfoMapper;
|
||||||
|
|
||||||
// ==================== 成就定义管理 ====================
|
// ==================== 成就定义管理 ====================
|
||||||
|
|
||||||
@@ -551,7 +556,7 @@ public class ACHAchievementServiceImpl implements AchievementService {
|
|||||||
|
|
||||||
// 检查是否达成
|
// 检查是否达成
|
||||||
if (checker.check(event, achievement, currentProgress)) {
|
if (checker.check(event, achievement, currentProgress)) {
|
||||||
TbUserAchievement userAchievement = grantAchievementInternal(event.getUserID(), achievement.getAchievementID());
|
TbUserAchievement userAchievement = grantAchievementInternal(event.getUserID(), achievement);
|
||||||
if (userAchievement != null) {
|
if (userAchievement != null) {
|
||||||
newAchievements.add(userAchievement);
|
newAchievements.add(userAchievement);
|
||||||
logger.info("用户 {} 通过事件 {} 获得成就: {}", event.getUserID(), event.getEventType(), achievement.getName());
|
logger.info("用户 {} 通过事件 {} 获得成就: {}", event.getUserID(), event.getEventType(), achievement.getName());
|
||||||
@@ -748,17 +753,21 @@ public class ACHAchievementServiceImpl implements AchievementService {
|
|||||||
/**
|
/**
|
||||||
* 内部授予成就方法(不检查是否已获得)
|
* 内部授予成就方法(不检查是否已获得)
|
||||||
*/
|
*/
|
||||||
private TbUserAchievement grantAchievementInternal(String userID, String achievementID) {
|
private TbUserAchievement grantAchievementInternal(String userID, TbAchievement achievement) {
|
||||||
try {
|
try {
|
||||||
TbUserAchievement userAchievement = new TbUserAchievement();
|
TbUserAchievement userAchievement = new TbUserAchievement();
|
||||||
userAchievement.setID(IDUtils.generateID());
|
userAchievement.setID(IDUtils.generateID());
|
||||||
userAchievement.setUserID(userID);
|
userAchievement.setUserID(userID);
|
||||||
userAchievement.setAchievementID(achievementID);
|
userAchievement.setAchievementID(achievement.getAchievementID());
|
||||||
userAchievement.setObtainTime(new Date());
|
userAchievement.setObtainTime(new Date());
|
||||||
|
|
||||||
int result = userAchievementMapper.insertUserAchievement(userAchievement);
|
int result = userAchievementMapper.insertUserAchievement(userAchievement);
|
||||||
if (result > 0) {
|
if (result > 0) {
|
||||||
updateProgressToCompleted(userID, achievementID);
|
updateProgressToCompleted(userID, achievement.getAchievementID());
|
||||||
|
|
||||||
|
// 检查是否需要更新用户等级(learning_time开头的成就)
|
||||||
|
updateUserLevelIfNeeded(userID, achievement);
|
||||||
|
|
||||||
return userAchievement;
|
return userAchievement;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -824,5 +833,56 @@ public class ACHAchievementServiceImpl implements AchievementService {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查并更新用户等级(仅针对learning_time开头的成就)
|
||||||
|
* @param userID 用户ID
|
||||||
|
* @param achievement 成就对象
|
||||||
|
*/
|
||||||
|
private void updateUserLevelIfNeeded(String userID, TbAchievement achievement) {
|
||||||
|
try {
|
||||||
|
// 检查成就ID是否以learning_time开头
|
||||||
|
if (achievement == null || achievement.getAchievementID() == null ||
|
||||||
|
!achievement.getAchievementID().startsWith("learning_time")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查成就是否有等级信息
|
||||||
|
if (achievement.getLevel() == null) {
|
||||||
|
logger.warn("成就没有等级信息: {}", achievement.getAchievementID());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户当前信息
|
||||||
|
TbSysUserInfo userInfo = userInfoMapper.selectById(userID);
|
||||||
|
if (userInfo == null) {
|
||||||
|
logger.warn("用户信息不存在: {}", userID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否需要更新等级(只有当成就等级高于当前用户等级时才更新)
|
||||||
|
Integer currentLevel = userInfo.getLevel() != null ? userInfo.getLevel() : 0;
|
||||||
|
Integer achievementLevel = achievement.getLevel();
|
||||||
|
|
||||||
|
if (achievementLevel > currentLevel) {
|
||||||
|
userInfo.setLevel(achievementLevel);
|
||||||
|
int updateResult = userInfoMapper.updateUserInfo(userInfo);
|
||||||
|
|
||||||
|
if (updateResult > 0) {
|
||||||
|
logger.info("用户 {} 通过成就 {} 等级从 {} 提升到 {}",
|
||||||
|
userID, achievement.getAchievementID(), currentLevel, achievementLevel);
|
||||||
|
} else {
|
||||||
|
logger.error("更新用户等级失败: userID={}, achievementID={}", userID, achievement.getAchievementID());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.debug("用户 {} 当前等级 {} 已达到或超过成就等级 {},无需更新",
|
||||||
|
userID, currentLevel, achievementLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("更新用户等级时发生异常: userID={}, achievementID={}, error={}",
|
||||||
|
userID, achievement.getAchievementID(), e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -272,8 +272,8 @@ public class NewsCrawlerTask extends PythonCommandTask {
|
|||||||
// 状态和时间
|
// 状态和时间
|
||||||
item.setStatus(0); // 未处理
|
item.setStatus(0); // 未处理
|
||||||
item.setCrawlTime(now);
|
item.setCrawlTime(now);
|
||||||
ResultDomain<Boolean> pass = auditService.auditText(item.getContent());
|
ResultDomain<String> pass = auditService.auditText(item.getContent());
|
||||||
if(pass.isSuccess() && pass.getData()){
|
if(pass.isSuccess()){
|
||||||
item.setIsAudited(true);
|
item.setIsAudited(true);
|
||||||
passList.add(item);
|
passList.add(item);
|
||||||
}else{
|
}else{
|
||||||
|
|||||||
@@ -265,15 +265,15 @@ public class SysMenuServiceImpl implements SysMenuService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查菜单名称是否已存在(排除自身)
|
// 检查菜单名称是否已存在(排除自身)
|
||||||
ResultDomain<Boolean> checkResult = checkMenuNameExists(menu.getName(), menu.getID());
|
// ResultDomain<Boolean> checkResult = checkMenuNameExists(menu.getName(), menu.getID());
|
||||||
if (!checkResult.isSuccess()) {
|
// if (!checkResult.isSuccess()) {
|
||||||
resultDomain.fail(checkResult.getMessage());
|
// resultDomain.fail(checkResult.getMessage());
|
||||||
return resultDomain;
|
// return resultDomain;
|
||||||
}
|
// }
|
||||||
if (checkResult.getData()) {
|
// if (checkResult.getData()) {
|
||||||
resultDomain.fail("菜单名称已存在");
|
// resultDomain.fail("菜单名称已存在");
|
||||||
return resultDomain;
|
// return resultDomain;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 设置更新时间
|
// 设置更新时间
|
||||||
menu.setUpdateTime(new Date());
|
menu.setUpdateTime(new Date());
|
||||||
|
|||||||
@@ -139,7 +139,7 @@
|
|||||||
SELECT COUNT(1)
|
SELECT COUNT(1)
|
||||||
FROM tb_sys_menu m
|
FROM tb_sys_menu m
|
||||||
WHERE deleted = 0
|
WHERE deleted = 0
|
||||||
AND m.name = #{name}
|
AND m.name = #{menuName}
|
||||||
<if test="excludeId != null and excludeId != ''">
|
<if test="excludeId != null and excludeId != ''">
|
||||||
AND m.id != #{excludeId}
|
AND m.id != #{excludeId}
|
||||||
</if>
|
</if>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ export const menuApi = {
|
|||||||
* @returns Promise<ResultDomain<string>> 返回菜单ID
|
* @returns Promise<ResultDomain<string>> 返回菜单ID
|
||||||
*/
|
*/
|
||||||
async createMenu(menu: SysMenu): Promise<ResultDomain<string>> {
|
async createMenu(menu: SysMenu): Promise<ResultDomain<string>> {
|
||||||
const response = await api.post<string>('/menu', menu);
|
const response = await api.post<string>('/menus/menu', menu);
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ export const menuApi = {
|
|||||||
* @returns Promise<ResultDomain<boolean>>
|
* @returns Promise<ResultDomain<boolean>>
|
||||||
*/
|
*/
|
||||||
async updateMenu(menu: SysMenu): Promise<ResultDomain<boolean>> {
|
async updateMenu(menu: SysMenu): Promise<ResultDomain<boolean>> {
|
||||||
const response = await api.put<boolean>(`/menus`, menu);
|
const response = await api.put<boolean>(`/menus/menu`, menu);
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ export const menuApi = {
|
|||||||
* @returns Promise<ResultDomain<boolean>>
|
* @returns Promise<ResultDomain<boolean>>
|
||||||
*/
|
*/
|
||||||
async deleteMenu(menuID: string): Promise<ResultDomain<boolean>> {
|
async deleteMenu(menuID: string): Promise<ResultDomain<boolean>> {
|
||||||
const response = await api.delete<boolean>(`/menus`, { menuID });
|
const response = await api.delete<boolean>(`/menus/menu`, { menuID });
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ $spacing-xxl: 24px;
|
|||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: $spacing-md 0;
|
padding: $spacing-md 0;
|
||||||
margin-top: 32px;
|
margin-top: auto; // 自动推到底部
|
||||||
// background: #F9FAFB;
|
// background: #F9FAFB;
|
||||||
border-radius: $border-radius-large;
|
border-radius: $border-radius-large;
|
||||||
|
|
||||||
|
|||||||
@@ -195,7 +195,6 @@ function handleWheel(event: WheelEvent) {
|
|||||||
// 处理导航点击
|
// 处理导航点击
|
||||||
function handleNavClick(menu: SysMenu) {
|
function handleNavClick(menu: SysMenu) {
|
||||||
activeDropdown.value = null;
|
activeDropdown.value = null;
|
||||||
|
|
||||||
if (menu.url) {
|
if (menu.url) {
|
||||||
router.push(menu.url);
|
router.push(menu.url);
|
||||||
} else if (menu.children && menu.children.length > 0) {
|
} else if (menu.children && menu.children.length > 0) {
|
||||||
|
|||||||
@@ -161,14 +161,41 @@ function generateRouteFromMenu(menu: SysMenu, isTopLevel = true): RouteRecordRaw
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 处理子路由
|
// 处理子路由
|
||||||
if (layout && LAYOUT_MAP[layout] && !hasChildren && menu.component && isTopLevel) {
|
if (layout && LAYOUT_MAP[layout] && menu.component && isTopLevel) {
|
||||||
// 如果指定了布局但没有子菜单,将页面组件作为子路由
|
// 如果指定了布局,将页面组件作为子路由
|
||||||
route.children = [{
|
route.children = [{
|
||||||
path: '',
|
path: '',
|
||||||
name: `${menu.menuID}_page`,
|
name: `${menu.menuID}_page`,
|
||||||
component: getComponent(menu.component),
|
component: getComponent(menu.component),
|
||||||
meta: route.meta
|
meta: route.meta
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
// 如果还有其他子菜单,继续添加
|
||||||
|
if (hasChildren) {
|
||||||
|
const pageChildren: SysMenu[] = [];
|
||||||
|
const normalChildren: SysMenu[] = [];
|
||||||
|
|
||||||
|
menu.children!.forEach(child => {
|
||||||
|
if (child.type === MenuType.PAGE) {
|
||||||
|
pageChildren.push(child);
|
||||||
|
} else {
|
||||||
|
normalChildren.push(child);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加普通子菜单
|
||||||
|
normalChildren.forEach(child => {
|
||||||
|
const childRoute = generateRouteFromMenu(child, false);
|
||||||
|
if (childRoute) {
|
||||||
|
route.children!.push(childRoute);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// PAGE 类型的菜单保存到 meta
|
||||||
|
if (pageChildren.length > 0) {
|
||||||
|
route.meta.pageChildren = pageChildren;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (hasChildren) {
|
} else if (hasChildren) {
|
||||||
// 处理有子菜单的情况
|
// 处理有子菜单的情况
|
||||||
route.children = [];
|
route.children = [];
|
||||||
@@ -290,6 +317,11 @@ function getComponent(componentName: string) {
|
|||||||
return module;
|
return module;
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
|
console.error('[路由生成] 组件加载失败:', {
|
||||||
|
原始组件名: componentName,
|
||||||
|
最终路径: componentPath,
|
||||||
|
错误: error
|
||||||
|
});
|
||||||
// 返回404组件
|
// 返回404组件
|
||||||
return import('@/views/public/error/404.vue').catch(() =>
|
return import('@/views/public/error/404.vue').catch(() =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
|
|||||||
@@ -346,10 +346,12 @@ onMounted(() => {
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
.my-message-list {
|
.my-message-list {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
max-width: 1200px;
|
max-width: 1200px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
min-height: calc(100vh - 76px - 40px);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
.header {
|
.header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|||||||
113
消息中心调试步骤.md
Normal file
113
消息中心调试步骤.md
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
# 消息中心前端加载问题调试步骤
|
||||||
|
|
||||||
|
## 问题描述
|
||||||
|
- 用户端消息中心页面空白(白屏)
|
||||||
|
- 消息详情页可以正常渲染
|
||||||
|
- 管理端消息管理页可以正常渲染
|
||||||
|
|
||||||
|
## 已完成的修改
|
||||||
|
|
||||||
|
### 1. 路由生成器添加调试日志
|
||||||
|
文件:`schoolNewsWeb/src/utils/route-generator.ts`
|
||||||
|
- 在 `generateRoutes()` 函数中添加了路由生成日志
|
||||||
|
- 在 `getComponent()` 函数中添加了组件加载日志
|
||||||
|
|
||||||
|
### 2. 添加分页容器样式
|
||||||
|
文件:`schoolNewsWeb/src/views/user/message/MyMessageListView.vue`
|
||||||
|
- 添加了 `.pagination-container` 样式
|
||||||
|
|
||||||
|
## 调试步骤
|
||||||
|
|
||||||
|
### 步骤1:重启前端开发服务器
|
||||||
|
```bash
|
||||||
|
cd f:\Project\schoolNews\schoolNewsWeb
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### 步骤2:打开浏览器控制台
|
||||||
|
1. 打开浏览器(Chrome/Edge)
|
||||||
|
2. 按 F12 打开开发者工具
|
||||||
|
3. 切换到 Console(控制台)标签页
|
||||||
|
|
||||||
|
### 步骤3:访问消息中心页面
|
||||||
|
访问: `http://localhost:8080/schoolNewsWeb/user/message`
|
||||||
|
|
||||||
|
### 步骤4:查看控制台输出
|
||||||
|
查找以下日志:
|
||||||
|
- `[路由生成] 生成路由:` - 确认消息中心路由是否被生成
|
||||||
|
- `[路由生成] 尝试加载组件:` - 查看组件路径是否正确
|
||||||
|
- `[路由生成] 组件加载成功:` - 确认组件是否加载成功
|
||||||
|
- `[路由生成] 组件加载失败:` - 如果失败,查看详细错误信息
|
||||||
|
|
||||||
|
### 步骤5:检查网络请求
|
||||||
|
1. 切换到 Network(网络)标签页
|
||||||
|
2. 刷新页面
|
||||||
|
3. 查看是否有失败的请求
|
||||||
|
4. 特别关注 `/api/message/my/page` 接口的响应
|
||||||
|
|
||||||
|
## 可能的问题和解决方案
|
||||||
|
|
||||||
|
### 问题1:组件路径错误
|
||||||
|
**症状**:控制台显示 `[路由生成] 组件加载失败`
|
||||||
|
|
||||||
|
**解决方案**:
|
||||||
|
检查数据库中 `tb_sys_menu` 表的 `component` 字段:
|
||||||
|
```sql
|
||||||
|
SELECT menu_id, name, url, component
|
||||||
|
FROM tb_sys_menu
|
||||||
|
WHERE menu_id = 'menu_user_message_center';
|
||||||
|
```
|
||||||
|
|
||||||
|
应该是:`user/message/MyMessageListView`
|
||||||
|
|
||||||
|
### 问题2:API接口返回错误
|
||||||
|
**症状**:网络请求返回 4xx 或 5xx 错误
|
||||||
|
|
||||||
|
**解决方案**:
|
||||||
|
1. 检查后端服务是否正常运行
|
||||||
|
2. 检查用户是否已登录
|
||||||
|
3. 检查权限配置
|
||||||
|
|
||||||
|
### 问题3:组件导入错误
|
||||||
|
**症状**:控制台显示 `Cannot find module` 或类似错误
|
||||||
|
|
||||||
|
**解决方案**:
|
||||||
|
检查 `MessagePriorityBadge` 组件是否正确导出:
|
||||||
|
```typescript
|
||||||
|
// src/components/message/index.ts
|
||||||
|
export { default as MessagePriorityBadge } from './MessagePriorityBadge.vue';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 问题4:数据为空但没有错误
|
||||||
|
**症状**:页面显示"暂无消息",但实际数据库中有数据
|
||||||
|
|
||||||
|
**解决方案**:
|
||||||
|
1. 检查API返回的数据结构
|
||||||
|
2. 在 `MyMessageListView.vue` 的 `loadMessages()` 函数中添加 console.log
|
||||||
|
|
||||||
|
## 常见错误代码对照
|
||||||
|
|
||||||
|
### 路径转换示例
|
||||||
|
数据库配置:`user/message/MyMessageListView`
|
||||||
|
↓
|
||||||
|
添加前缀:`@/views/user/message/MyMessageListView`
|
||||||
|
↓
|
||||||
|
转换别名:`../views/user/message/MyMessageListView.vue`
|
||||||
|
↓
|
||||||
|
最终解析:`src/views/user/message/MyMessageListView.vue`
|
||||||
|
|
||||||
|
### 路由配置示例
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
path: '/user/message',
|
||||||
|
name: 'menu_user_message_center',
|
||||||
|
component: () => import('../views/user/message/MyMessageListView.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '消息中心',
|
||||||
|
requiresAuth: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 下一步操作
|
||||||
|
根据控制台输出的错误信息,确定具体问题后再进行针对性修复。
|
||||||
Reference in New Issue
Block a user