Merge branch 'develop' of https://bdgit.educoder.net/hnu202326010229/ArtifactLLM into limengyuan_branch

limengyuan_branch
李梦源 5 months ago
commit 5a79489e9c

@ -4,8 +4,8 @@
**姓  名:** 李梦源
**团队名称:** 2班-老师指定的组队
**开始时间:** 2023-10-13
**结束时间:** 2023-10-20
**开始时间:** 2025-10-13
**结束时间:** 2025-10-20
## 本周任务计划安排

@ -7,9 +7,9 @@
**团队名称:** 2班-老师指定的组队
**开始时间:** 2023-10-13
**开始时间:** 2025-10-13
**结束时间:** 2023-10-20
**结束时间:** 2025-10-20
## 本周任务完成情况

@ -11,14 +11,13 @@
**结束时间:** 2025-10-27
## 本周任务计划安排
## 本周任务完成情况
| 序号 | 总结内容 | 是否完成 | 情况说明 |
|----|----------|------|-------------------------------------------------------|
| 1 | 配置项目开发环境 | 完成 | 配置前端Vue后端SpringBoot的相关开发环境 |
| 2 | 学习后端知识 | 完成 | 周内持续学习SpringBoot开发的相关知识 |
| 1 | 配置项目开发环境 | 完成 | 作为后端人员,配置后端SpringBoot的相关开发环境 |
| 2 | 学习后端知识 | 完成 | 学习SpringBoot框架controller,service,mapper方面基础知识 |
| 3 | 确定分工 | 完成 | 2025-10-20 开会细分确定团队分工,统一开发工具 |
| 4 | 完成项目原型 | 完成 | 组员通过学习借鉴优秀的原型界面设计模板利用墨刀平台协作按照与老师沟通的需求设计Web端系统原型Demo |
## 小结

@ -16,11 +16,11 @@
| 序号 | 计划内容| 是否完成 | 情况说明 |
| ----| ------ | ------| ------- |
| 1 |持续学习前端知识 | 完成 | 持续学习前端vue相关知识不断提升项目技能 |
| 2 |持续学习界面原型开发知识 | 完成 | 持续学习墨刀的使用,熟练掌握墨刀开发技巧 |
| 3 | 确定分工 | 完成 | 2025-10-20 开会细分确定团队分工,统一开发工具 |
| 4 | 确定需求 | 完成 | 2025-10-25通过视频会议用原型法与彭鹏老师不断的沟通确定需求 |
| 5 | 设计项目原型界面 | 完成 | 通过学习借鉴优秀的原型界面设计模板借助墨刀工具按照与老师沟通的需求设计Web端系统原型界面 |
| 1 |持续学习前端知识 | 完成 | 本周完成了Vue基础语法和组件生命周期的学习掌握了数据绑定和事件处理的核心概念 |
| 2 |持续学习界面原型开发知识 | 完成 | 深入学习了墨刀的高级功能,包括动态效果实现 |
| 3 | 确定分工 | 完成 | 2025-10-20召开团队会议明确了我负责前端界面设计和原型开发前端统一了使用Vue 3的技术栈 |
| 4 | 确定需求 | 完成 | 2025-10-25与彭鹏老师进行了的视频会议,通过交互式原型演示明确了系统的核心功能和用户流程,记录了关键需求变更 |
| 5 | 设计项目原型界面 | 完成 | 结合老师反馈和团队讨论,设计了系统原型,实现了基础交互逻辑 |
## 小结

@ -1,4 +1,4 @@
# 个人周计划-第6周
# 个人周总结-第6周
## 姓名和起止时间
@ -11,7 +11,7 @@
**结束时间:** 2025-11-03
## 本周任务计划安排
## 本周任务完成情况
| 序号 | 总结内容 | 是否完成 | 情况说明 |
|----|---------------|------|-------------------------------|

@ -1,4 +1,4 @@
# 个人周计划-第6周
# 个人周总结-第6周
## 姓名和起止时间
@ -15,9 +15,9 @@
| 序号 | 计划内容| 是否完成 | 情况说明 |
| ----| ------ | ------| ------- |
| 1 |持续学习前端知识 | 完成 | 持续学习前端vue相关知识不断提升项目技能 ,不断分析往届学生作品,汲取开发经验 |
| 2 | 确定分工 | 完成 | 2023-10-27 开会细分确定团队分工,明确周任务 |
| 3 | 用例文档撰写 | 完成 | 学习并完成系统用例文档的撰写,并为需求文档其他部分做准备 |
| 1 |持续学习前端知识 | 完成 | 本周深入学习了Vue组件化开发和状态管理通过分析往届优秀项目总结了前端开发的最佳实践 |
| 2 | 确定分工 | 完成 | 2025-10-27召开小组会议明确了各成员的具体职责我主要负责前端界面开发和原型设计 |
| 3 | 用例文档撰写 | 完成 | 与团队成员协作完成了系统用例文档的撰写,详细描述了用户交互流程和功能需求 |
| 4 | 改进项目原型界面 | 完成 | 根据指导老师的建议借助墨刀工具不断改进Web端系统原型界面 |

@ -10,16 +10,14 @@
**结束时间:** 2025-11-10
## 本周任务计划安排
| 序号 | 总结内容 | 是否完成 | 情况说明 |
|----|-------------|------|--------------------------------------------------|
| 1 | 学习后端知识 | 完成 | 周内持续学习SpringBoot开发的相关知识 |
| 2 | 确定分工 | 完成 | 2025-11-03开会细分确定团队分工明确周任务 |
| 3 | 完善原型界面与用例文档 | 完成 | 2025-11-07 前,完善原型界面,学习并完成系统用例文档的撰写,并为需求文档其他部分做准备 |
| 4 | 撰写项目前景和范围文档 | 完成 | 2025-11-07前学习并撰写项目前景和范围文档 |
| 5 | 开始数据库设计 | 完成 | 2025-11-05前学习并开始数据库设计制作数据库表绘制ER图 |
| 6 | 撰写需求规格说明书 | 完成 | 2025-11-07前学习并撰写需求规格说明书第一稿 |
## 本周任务完成情况
| 序号 | 总结内容 | 是否完成 | 情况说明 |
|----|-----------|------|-------------------------------------------------------------------|
| 1 | 学习后端知识 | 完成 | 学习springboot框架的demo项目构建 |
| 2 | 完成各种文档 | 完成 | 2025-11-07 前,完善原型界面,学习并完成系统用例文档以及项目前景和范围文档的撰写,并为需求文档其他部分做准备 |
| 3 | 开始数据库设计 | 完成 | 2025-11-05前学习并开始数据库设计制作数据库表绘制ER图 |
| 4 | 撰写需求规格说明书 | 完成 | 2025-11-07前学习并撰写需求规格说明书第一稿 |
## 小结

@ -14,15 +14,15 @@
| 序号 | 计划内容 | 完成情况 | 情况说明 |
|----|-------------|-----|--------------------------------------------------|
| 1 | 学习前端知识 | 完成 | 周内持续学习vue开发的相关知识 |
| 2 | 确定分工 | 完成 | 2025-11-03,开会细分确定团队分工,明确周任务 |
| 3 | 完善原型界面与用例文档 | 完成 | 2025-11-07前 ,完善了原型界面,学习并完成了系统用例文档的撰写,并为需求文档其他部分做准备 |
| 4 | 撰写需求规格说明书 | 完成 | 2025-11-07,学习并撰写了需求规格说明书第一稿 |
| 1 | 学习前端知识 | 完成 | 本周深入学习了Vue 3的Composition API完成了组件通信和状态管理的实践练习反复练习了setup语法的核心用法 |
| 2 | 确定分工 | 完成 | 2025-11-03召开团队会议,细化了各成员在需求分析和前端开发阶段的具体职责,制定了详细的任务时间表和交付标准 |
| 3 | 完善原型界面与用例文档 | 完成 | 2025-11-07前完成了原型界面的优化,并为需求文档其他部分做准备 |
| 4 | 撰写需求规格说明书 | 完成 | 2025-11-07与团队协作完成了需求规格说明书第一稿,详细描述了系统功能、非功能需求和数据模型,为后续开发提供了完整的技术指导 |
## 小结
1. **学习需求:** 希望能有对于原型设计以及vue开发的教学
2. **知识储备:** 提前学习后续需要使用的知识,为后续的前端开发做准备
1. **专业成长:** 通过本周的学习和实践在Vue 3新特性应用方面有了更深入的理解
2. **项目成果:** 成功完成了原型界面优化和用例文档撰写
3. **技术预研:** 根据需求了解后续进行开发可能遇到的相关技术难点
4. **撰写需求规格说明书** 学习并参与撰写需求规格说明书

@ -10,15 +10,14 @@
**结束时间:** 2025-11-17
## 本周任务计划安排
| 序号 | 总结内容 | 是否完成 | 情况说明 |
|----|---------|------|----------------------------------------------------|
| 1 | 学习后端知识 | 完成 | 周内持续学习SpringBoot开发的相关知识 |
| 2 | 完善数据库设计 | 完成 | 2025-11-16 22:00之前完善数据库设计确认数据库表与ER图 |
| 3 | 数据库设计文档 | 完成 | 2025-11-16 22:00之前完成数据库设计文档的编写为后续开发提供准确的数据库实现依据。 |
| 4 | 确认迭代计划 | 完成 | 2025-11-11 14:30与指导老师确认迭代开发计划 |
| 5 | 学习uml设计 | 完成 | 学习编写系统总的用例图,编写该迭代的主要业务功能的活动图、顺序图和类图 |
## 本周任务完成情况
| 序号 | 总结内容 | 是否完成 | 情况说明 |
|----|-------|------|----------------------------------------------------|
| 1 | 学习后端知识 | 完成 | 学习mybatis框架的使用 |
| 2 | 数据库设计 | 完成 |完善数据库设计确认数据库表与ER图,并完成数据库设计文档的编写,为后续开发提供准确的数据库实现依据。 |
| 3 | 确认迭代计划 | 完成 | 2025-11-11 14:30与指导老师确认迭代开发计划 |
| 4 | 学习uml设计 | 完成 | 学习编写系统总的用例图,编写该迭代的主要业务功能的活动图、顺序图和类图 |
## 小结

@ -15,16 +15,16 @@
| 序号 | 计划内容 | 是否完成 | 情况说明 |
|----|---------|------|----------------------------------------------------|
| 1 | 学习前端知识 | 完成 | 周内持续学习vue开发的相关知识 |
| 2 | uml设计文档 | 完成 | 2025-11-14学习uml相关知识并完成uml设计文档 |
| 3 | 确认迭代计划 | 完成 | 2025-11-11 14:30与指导老师确认迭代开发计划 |
| 4 | 完成迭代开发计划第一稿 | 完成 | 2025-11-16根据老师的要求完成开发计划第一稿 |
| 1 | 学习前端知识 | 完成 | 本周系统学习了Vue 3的Composition API、组件通信和路由管理对前端开发有了更深入的理解。 |
| 2 | uml设计文档 | 完成 | 2025-11-14学习UML核心概念完成了系统活动图和顺序图的初步设计 |
| 3 | 确认迭代计划 | 完成 | 2025-11-11 14:30与指导老师确认迭代开发计划 |
| 4 | 完成迭代开发计划第一稿 | 完成 | 2025-11-16根据老师的要求完成开发计划第一稿 |
## 小结
1. **学习需求:** 希望能有对于uml以及vue开发的教学
1. **技能提升:** 本周通过系统学习在Vue开发和UML建模方面有了提升为后续开发奠定了理论基础。
2. **知识储备:** 提前学习后续需要使用的知识,为后续的前端开发做准备;
3. **撰写uml设计文档** 学习并撰写uml设计文档。

@ -10,15 +10,14 @@
**结束时间:** 2025-11-24
## 本周任务计划安排
| 序号 | 总结内容 | 是否完成 | 情况说明 |
|----|------------|------|-------------------------------------|
| 1 | 学习后端知识 | 完成 | 周内持续学习SpringBoot开发的相关知识 |
| 2 | 确定项目后端代码结构 | 完成 | 根据先前编写的需求文档以及老师给出的参考确定后续开发的代码的结构 |
| 3 | 工程创建 | 完成 | 创建后端项目工程,根据配置的相关环境导入相应依赖 |
| 4 | 确认迭代计划第二稿 | 完成 | 根据反馈意见修改迭代开发计划 |
| 5 | 学习uml设计 | 完成 | 学习编写系统总的用例图,编写该迭代的主要业务功能的活动图、顺序图和类图 |
## 本周任务完成情况
| 序号 | 总结内容 | 是否完成 | 情况说明 |
|----|-----------|------|------------------------------------------------------------|
| 1 | 学习后端知识 | 完成 | 学习mybatisPlus框架的使用 |
| 2 | 项目后端代码构建 | 完成 | 根据先前编写的需求文档以及老师给出的参考确定后续开发的代码的结构,并创建后端项目工程,根据配置的相关环境导入相应依赖 |
| 3 | 确认迭代计划第二稿 | 完成 | 根据反馈意见修改迭代开发计划 |
| 4 | 学习uml设计 | 完成 | 学习编写用例图,完善该迭代的主要业务功能的活动图、顺序图和类图 |
## 小结

@ -1,4 +1,4 @@
# 个人周计划-第9周
# 个人周总结-第9周
## 姓名和起止时间
@ -14,11 +14,11 @@
| 序号 | 计划内容 | 是否完成 | 情况说明 |
|----|---------|------|----------------------------------------------------|
| 1 | 学习前端知识 | 完成 | 周内持续学习vue开发的相关知识不断从学长的代码获取开发经验 |
| 1 | 学习前端知识 | 完成 | 深入学习了Vue 3的响应式原理和生命周期分析了学长提供的代码案例学习了组件复用和状态管理的最佳实践 |
| 2 | 确定分工 | 完成 | 2025-11-17开会细分确定团队分工明确周任务 |
| 2 | 完善uml设计文档 | 完成 | 学习uml相关知识并完善uml设计文档活动图顺序图的部分 |
| 3 | 确认迭代计划第二稿 | 完成 | 根据指导老师的意见完成迭代开发计划第二稿 |
| 4 | 前端开发 | 完成 | 根据进度安排开始项目的编码,根据原型进行前端的编码 |
| 3 | 完善uml设计文档 | 完成 | 学习uml相关知识并完善uml设计文档活动图顺序图的部分 |
| 4 | 确认迭代计划第二稿 | 完成 | 根据指导老师的意见完成迭代开发计划第二稿 |
| 5 | 前端开发 | 完成 | 根据进度安排开始项目的编码,根据原型进行前端的编码 |
## 小结

@ -0,0 +1,35 @@
# 小组周总结-第10周
## 团队名称和起止时间
**团队名称:** 2班-老师指定的组队
**开始时间:** 2025-11-24
**结束时间:** 2025-12-01
## 本周任务完成情况
| 序号 | 总结内容 | 是否完成 | 情况说明 |
|----|------------|------|--------------------------------------------------|
| 1 | 项目编码实施 | 部分完成 | 前端功能开发基本完成,后端功能实现部分完成 |
| 2 | 前后端联调测试 | 未完成 | 由于后端功能尚未完全实现,前后端联调测试未能如期进行 |
| 3 | 系统测试用例设计 | 未完成 | 测试用例设计工作尚未开展 |
| 4 | 项目文档更新完善 | 部分完成 | 根据实际开发进度更新了部分文档包括UML图等 |
| 5 | 代码审查与优化 | 部分完成 | 对已完成的前端代码进行了优化,后端代码正在进行中 |
## 小结
1. **前端进展顺利:** 前端功能开发按计划完成,成功实现了文物信息展示页面及相关功能;
2. **后端仍在进行:** 后端开发虽有所进展,但尚未完成全部核心功能,影响了整体进度;
3. **协同有待加强:** 前后端开发进度不匹配,需要加强团队内部沟通与协调;
4. **后续重点明确:** 下一步需要加快推进后端开发进度,尽快完成前后端联调测试。
---
## 【注】
1. 在小结一栏中写出希望得到如何的帮助,如讲座等;
2. 请将个人计划和总结提前发给负责人;
3. 周任务总结与计划是项目小组评分考核的重要依据,将直接记入平时成绩,请各位同学按要求认真填写并按时提交;
4. PM综合本小组成员工作情况提交小组周计划、周总结报告按时上传至代码托管平台。

@ -0,0 +1,34 @@
# 个人周总结-第10周
## 姓名和起止时间
**姓  名:** 符晋康
**团队名称:** 2班-老师指定的组队
**开始时间:** 2025-11-24
**结束时间:** 2025-12-01
## 本周任务完成情况
| 序号 | 总结内容 | 是否完成 | 情况说明 |
|----|------------|------|-------------------------------------|
| 1 | 学习后端开发相关知识 | 完成 | 学习postman知识 能够简单测试接口 |
| 2 | 项目部分功能实现 | 完成 | 根据先前编写的需求文档,进行项目的后端开发,完成了部分核心功能 |
| 3 | 学习uml设计 | 完成 | 学习编写系统总的用例图,编写该迭代的主要业务功能的活动图、顺序图和类图 |
## 小结
1. **学习需求:** 希望能有对于原型设计以及SpringBoot开发的教学
2. **功能实现:** 利用学到的开发知识完成了部分核心功能的实现;
3. **uml设计** 学习uml设计为后续的uml设计做准备。
---
## 【注】
1. 在小结一栏中写出希望得到如何的帮助,如讲座等;
2. 请将个人计划和总结提前发给负责人;
3. 周任务总结与计划是项目小组评分考核的重要依据,将直接记入平时成绩,请各位同学按要求认真填写并按时提交;
4. 所有组员都需提交个人周计划、周总结文档,按时上传至代码托管平台;

@ -0,0 +1,37 @@
# 个人周总结-第10周
## 姓名和起止时间
**姓  名:** 哈俊元
**团队名称:** 2班-老师指定的组队
**开始时间:** 2025-11-24
**结束时间:** 2025-12-01
## 本周任务完成情况
| 序号 | 总结内容 | 是否完成 | 情况说明 |
|------|----------|--------|----------|
| 1 | 前端功能开发 | 完成 | 成功完善了前端页面功能,实现了文物信息展示页面 |
| 2 | 前后端联调 | 未完成 | 由于后端功能尚未完全实现,未能进行前后端联调 |
| 3 | 代码优化 | 完成 | 对现有代码结构进行了优化,提高了代码可读性和可维护性 |
| 4 | 文档更新 | 完成 | 根据最新开发进度更新了相关技术文档 |
| 5 | 团队协作 | 完成 | 积极参与团队会议,汇报开发进度,讨论解决方案 |
## 小结
1. **技能提升:** 通过项目实践进一步掌握了Vue3开发技巧和工程化实践
2. **成果显著:** 成功完成了前端功能开发和代码优化任务;
3. **协同合作:** 积极参与团队协作,但由于后端进度原因,联调工作未能如期完成;
4. **质量保证:** 注重代码质量和可维护性,编写了清晰的注释和文档。
---
## 【注】
1. 在小结一栏中写出希望得到如何的帮助,如讲座等;
2. 请将个人计划和总结提前发给负责人;
3. 周任务总结与计划是项目小组评分考核的重要依据,将直接记入平时成绩,请各位同学按要求认真填写并按时提交;
4. 所有组员都需提交个人周计划、周总结文档,按时上传至代码托管平台;

@ -0,0 +1,34 @@
# 个人周总结-第10周
## 姓名和起止时间
**姓  名:** 李梦源
**团队名称:** 2班-老师指定的组队
**开始时间:** 2025-11-24
**结束时间:** 2025-12-01
## 本周任务完成情况
| 序号 | 计划内容 | 是否完成 | 情况说明 |
|----|-----------|------|-------------------|
| 1 | 学习前端知识 | 完成 | 本周深入学习了Vue 3的Pinia状态管理和Axios网络请求学习了表单验证和动画效果实现。 |
| 2 | 前端持续开发 | 完成 | 成功合作完成了前端α版本的界面开发,实现了核心功能模块,界面符合设计原型要求,交互流畅。 |
| 3 | 学习uml设计 | 完成 | 完成了系统总的用例图、活动图、顺序图和类图设计UML文档更加完整和规范。 |
## 小结
1. **知识储备:** 提前学习后续需要使用的知识,为后续的前端开发做准备
2. **项目推进:** 前端α版本界面开发顺利完成。
3. **uml设计** 学习uml设计为后续的uml设计修改做准备。
---
## 【注】
1. 在小结一栏中写出希望得到如何的帮助,如讲座等;
2. 请将个人计划和总结提前发给负责人;
3. 周任务总结与计划是项目小组评分考核的重要依据,将直接记入平时成绩,请各位同学按要求认真填写并按时提交;
4. 所有组员都需提交个人周计划、周总结文档,按时上传至代码托管平台;

@ -0,0 +1,33 @@
# 个人周总结-第10周
## 姓名和起止时间
**姓  名:** 袁明霜涛
**团队名称:** 2班-老师指定的组队
**开始时间:** 2025-11-24
**结束时间:** 2025-12-01
## 本周任务计划安排
| 序号 | 总结内容 | 完成情况 | 情况说明 |
|----|---------|------|--------------------------------------------------------------|
| 1 | 学习后端知识 | 完成 | 周内持续学习SpringBoot开发的相关知识在开发过程中补充缺失的知识 |
| 2 | 后端持续开发 | 完成 | 根据先前编写的需求文档以及老师给出的参考确定后续开发的代码的结构,本周完成两个模块的内容,并将相应模块的接口设计与前端同步 |
| 3 | 学习uml设计 | 完成 | 学习编写系统总的用例图,编写该迭代的主要业务功能的活动图、顺序图和类图 |
## 小结
1. **学习来源:** 参考网络上javaweb相关SpringBoot开发的教学
2. **开发进度:** 完成了两个模块的后端代码,并与前端同步接口设计。
---
## 【注】
1. 在小结一栏中写出希望得到如何的帮助,如讲座等;
2. 请将个人计划和总结提前发给负责人;
3. 周任务总结与计划是项目小组评分考核的重要依据,将直接记入平时成绩,请各位同学按要求认真填写并按时提交;
4. 所有组员都需提交个人周计划、周总结文档,按时上传至代码托管平台;

@ -0,0 +1,80 @@
# 小组会议纪要-第11周
## 会议记录概要
**团队名称:** 2班-老师指定的组队
**指导老师:** 彭鹏
**主 持 人:** 李梦源
**记录人员:** 李梦源
**会议主题:** 本周计划与分工
**会议地点:** 线上会议
**会议时间:** 2025-12-1 16:30-16:50
**纪录时间:** 2025年12月1日 19:00
**参与人员:** 李梦源、符晋康、哈俊元、袁明霜涛
---
## 会议内容
### 1.阿尔法版本迭代开发
本周任务为持续推进阿尔法版本的迭代开发并需提交相应的UML图。
### 2.确认开发进度
目前后端部分模块仍在开发中,需加快进度以确保整体项目按时推进。
### 3.本周任务安排
本周主要任务为完成阿尔法版本的开发所有UML图需于本周五晚上十点前完成提交。
### 4.后续会议安排
需要自行联系指导老师,就第二次迭代开发计划的具体调整进行确认。
---
## 问题总结
### 已解决问题:
1. 完成了项目前后端基础框架搭建,以及前端界面、后端部分核心功能模块的编码工作
2. 完善了接口文档并与实际编码保持一致
3. 完成了用例图、活动图、顺序图和类图在uml设计文档中的初稿。
### 待解决问题:
1. 需要根据老师反馈完善第二次迭代开发计划的部分内容。
2. 后端需要加快进度完成阿尔法版本剩余模块的开发
3. 前后端需要根据接口文档进行协作开发。
4. 按时提交UML-活动图-顺序图-类图.pdf
---
## 小组协作情况总结
1. **协作情况:** 小组成员积极参与,全员到会,对项目需求和功能模块有较深入的理解,协作氛围良好。
---
## 一周纪律情况总结
1. **纪律情况:** 小组成员按时参加会议,积极参与讨论,无迟到早退现象。
---
## 备注
1. 本周重点任务是阿尔法版本的开发工作
2. 需要尽快完善uml图的设计
---
## 【注】
1. 本文档为"老师指定的组队"小组软件过程会议记录记录人员必须在会议后一个工作日之内如实填写并汇报给PM、Lead及相关人员。
2. 文档内容已经标上编号,记录人员如有增加或者减少编号的需要,在保证文档格式正确的前提下修改。
3. 本文档内容在填写完毕之后,在已有的文件名称后面加上"(会议记录-第几周)",如"meeting-minutes-03",如果一周有多次会议,命名为"meeting-minutes-03-01"。

@ -0,0 +1,38 @@
# 小组周计划-第11周
## 团队名称和起止时间
**团队名称:** 2班-老师指定的组队
**开始时间:** 2025-12-01
**结束时间:** 2025-12-07
## 本周任务计划安排
| 序号 | 计划内容 | 执行人 | 情况说明 |
|----|------------------------|----------|---------------------------------------------------|
| 1 | 阿尔法版本迭代开发 | 全体成员 | 持续推进阿尔法版本的迭代开发工作。 |
| 2 | 继续模块开发 | 符晋康、袁明霜涛 | 加快完成阿尔法版本中仍在开发的后端模块。 |
| 3 | UML图设计与提交 | 哈俊元、李梦源 | 完善并提交UML活动图、顺序图、类图于本周五22:00前完成。 |
| 4 | 联系指导老师确认计划的调整 | 全体成员 | 根据老师反馈,对第二次迭代开发计划的内容进行修改与完善。 |
| 5 | 前后端协作联调 | 全体成员 | 根据已完善的接口文档,进行前后端协作开发与联合调试。 |
| 6 | 项目文档更新 | 全体成员 | 根据最新的开发进展更新迭代开发计划及相关的UML设计文档并完善前十一周存在问题的文档。 |
## 小结
1. **核心交付**本周首要目标是完成阿尔法版本的开发核心内容并准时提交全套UML设计图。
2. **持续推进** 本周重点是持续推进项目编码工作,确保按照既定计划完成各项功能实现。
3. **协同与沟通**:加强前后端基于接口文档的协作,并主动与指导老师沟通,确保计划调整得到及时确认。
---
## 【注】
1. 在小结一栏中写出希望得到如何的帮助,如讲座等;
2. 请将个人计划和总结提前发给负责人;
3. 周任务总结与计划是项目小组评分考核的重要依据,将直接记入平时成绩,请各位同学按要求认真填写并按时提交;
4. PM综合本小组成员工作情况提交小组周计划、周总结报告按时上传至代码托管平台。

@ -0,0 +1,34 @@
# 个人周计划-第11周
## 姓名和起止时间
**姓  名:** 符晋康
**团队名称:** 2班-老师指定的组队
**开始时间:** 2025-12-01
**结束时间:** 2025-12-07
## 本周任务计划安排
| 序号 | 计划内容 | 执行人 | 情况说明 |
|----|--------|------|--------------------------|
| 1 | 学习后端知识 | 个人 | 周内持续学习SpringBoot开发的相关知识 |
| 2 | 后端持续开发 | 个人 | 根据目前的项目代码,继续完成核心功能的开发和完善 |
| 3 | 学习ES搜索 | 个人 | 学习ES搜索为后续的模糊搜索功能做准备 |
## 小结
1. **学习需求:** 希望能有对于原型设计以及SpringBoot开发的教学
2. **知识储备:** 提前学习后续需要使用的知识,为后续的后端开发做准备;
3. **ES学习** 学习ES搜索为后续的模糊搜索功能做准备
---
## 【注】
1. 在小结一栏中写出希望得到如何的帮助,如讲座等;
2. 请将个人计划和总结提前发给负责人;
3. 周任务总结与计划是项目小组评分考核的重要依据,将直接记入平时成绩,请各位同学按要求认真填写并按时提交;
4. 所有组员都需提交个人周计划、周总结文档,按时上传至代码托管平台;

@ -0,0 +1,37 @@
# 个人周计划-第11周
## 姓名和起止时间
**姓  名:** 哈俊元
**团队名称:** 2班-老师指定的组队
**开始时间:** 2025-12-01
**结束时间:** 2025-12-08
## 本周任务计划安排
| 序号 | 计划内容 | 协作人 | 情况说明 |
|------|----------|--------|----------|
| 1 | 前端代码优化 | 个人 | 继续优化前端代码结构和性能,提高用户体验 |
| 2 | 前后端联调准备 | 个人 | 等待后端开发完成,准备进行前后端联调 |
| 3 | Bug修复 | 个人 | 根据测试结果修复前端可能存在的问题 |
| 4 | 文档完善 | 个人 | 更新和完善相关技术文档 |
| 5 | 团队协作 | 全体成员 | 参与团队会议,协调联调工作安排 |
## 小结
1. **持续优化:** 通过不断优化前端代码提升系统性能和用户体验;
2. **联调准备:** 积极准备前后端联调工作,确保接口对接顺利;
3. **团队协作:** 密切关注后端开发进度,及时进行沟通协调;
4. **质量保证:** 注重代码质量和系统稳定性,做好充分的测试准备。
---
## 【注】
1. 在小结一栏中写出希望得到如何的帮助,如讲座等;
2. 请将个人计划和总结提前发给负责人;
3. 周任务总结与计划是项目小组评分考核的重要依据,将直接记入平时成绩,请各位同学按要求认真填写并按时提交;
4. 所有组员都需提交个人周计划、周总结文档,按时上传至代码托管平台;

@ -0,0 +1,35 @@
# 个人周计划-第11周
## 姓名和起止时间
**姓  名:** 李梦源
**团队名称:** 2班-老师指定的组队
**开始时间:** 2025-12-01
**结束时间:** 2025-12-07
## 本周任务计划安排
| 序号 | 计划内容 | 执行人 | 情况说明 |
|----|--------|------|--------------------------|
| 1 | 学习前端知识 | 个人 | 周内持续学习vue开发的相关知识 |
| 2 | 前端持续开发 | 个人 | 根据接口文档,继续完成前端接口部分的编码 |
| 3 | 前端代码优化 | 个人 | 优化已经完成的代码,提升代码质量 |
| 4 | 前后端联调准备 | 个人 | 学习相关知识,为前后端联调做准备 |
## 小结
1. **学习需求:** 希望能有对于vue开发的教学
2. **知识储备:** 提前学习后续需要使用的知识,为后续的前端开发做准备;
3. **代码优化** 优化前端代码,提升代码质量,增强代码可靠性;
---
## 【注】
1. 在小结一栏中写出希望得到如何的帮助,如讲座等;
2. 请将个人计划和总结提前发给负责人;
3. 周任务总结与计划是项目小组评分考核的重要依据,将直接记入平时成绩,请各位同学按要求认真填写并按时提交;
4. 所有组员都需提交个人周计划、周总结文档,按时上传至代码托管平台;

@ -0,0 +1,34 @@
# 个人周计划-第11周
## 姓名和起止时间
**姓  名:** 袁明霜涛
**团队名称:** 2班-老师指定的组队
**开始时间:** 2025-12-01
**结束时间:** 2025-12-08
## 本周任务计划安排
| 序号 | 计划内容 | 执行人 | 情况说明 |
|----|--------|------|-------------------------------|
| 1 | 学习后端知识 | 个人 | 周内持续学习SpringBoot开发的相关知识 |
| 2 | 后端持续开发 | 个人 | 根据先前编写的需求文档以及此前完成的代码进行进一步开发 |
| 3 | 学习代码测试 | 个人 | 学习代码测试相关流程与方法,测试此前交付的功能能否正确相应 |
## 小结
1. **学习需求:** 希望能有对于图数据库以及SpringBoot开发的教学
2. **知识储备:** 提前学习后续需要使用的知识,为后续的后端开发做准备;
3. **代码测试:** 学习代码测试相关的流程与方法,审查相应功能。
---
## 【注】
1. 在小结一栏中写出希望得到如何的帮助,如讲座等;
2. 请将个人计划和总结提前发给负责人;
3. 周任务总结与计划是项目小组评分考核的重要依据,将直接记入平时成绩,请各位同学按要求认真填写并按时提交;
4. 所有组员都需提交个人周计划、周总结文档,按时上传至代码托管平台;

@ -0,0 +1,41 @@
package cn.edu.hnu.artifactcommon.constant;
/**
*
*/
public class SystemConstant {
/**
*
*/
public static final String ROLE_GUEST = "guest";
public static final String ROLE_USER = "user";
public static final String ROLE_ADVANCED = "advanced";
public static final String ROLE_ADMIN = "admin";
/**
*
*/
public static final Integer STATUS_NORMAL = 0; // 正常
public static final Integer STATUS_DISABLED = 1; // 禁用
/**
* JWT
*/
public static final String JWT_HEADER = "Authorization";
public static final String JWT_PREFIX = "Bearer ";
public static final String JWT_SECRET = "artifact-system-secret-key";
public static final Long JWT_EXPIRATION = 7 * 24 * 60 * 60 * 1000L; // 7天
/**
* Redis
*/
public static final String REDIS_KEY_PREFIX = "artifact:";
public static final String REDIS_KEY_CAPTCHA = "captcha:";
public static final String REDIS_KEY_USER = "user:";
public static final String REDIS_KEY_TOKEN = "token:";
private SystemConstant() {
// 私有构造方法,防止实例化
}
}

@ -0,0 +1,34 @@
package cn.edu.hnu.artifactcommon.context;
/**
*
*/
public class UserContext {
/**
* 使ThreadLocal线
*/
private static final ThreadLocal<String> USER_THREAD_LOCAL = new ThreadLocal<>();
/**
* 线
*/
public static void setCurrentUsername(String username) {
USER_THREAD_LOCAL.set(username);
}
/**
* 线
*/
public static String getCurrentUsername() {
return USER_THREAD_LOCAL.get();
}
/**
* 线
*/
public static void clear() {
USER_THREAD_LOCAL.remove();
}
}

@ -0,0 +1,55 @@
package cn.edu.hnu.artifactcommon.exception;
/**
*
*/
public class BusinessException extends RuntimeException {
private static final long serialVersionUID = 1L;
/**
*
*/
private Integer code;
/**
*
*/
private String message;
public BusinessException(String message) {
super(message);
this.message = message;
this.code = 500;
}
public BusinessException(Integer code, String message) {
super(message);
this.code = code;
this.message = message;
}
public BusinessException(String message, Throwable e) {
super(message, e);
this.message = message;
this.code = 500;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

@ -0,0 +1,35 @@
package cn.edu.hnu.artifactcommon.pojo.dto;
import lombok.Data;
/**
*
*/
@Data
public class UserDTO {
/**
*
*/
private String username;
/**
*
*/
private String password;
/**
*
*/
private String email;
/**
*
*/
private String captcha;
/**
* UUID
*/
private String captchaUuid;
}

@ -0,0 +1,20 @@
package cn.edu.hnu.artifactcommon.pojo.vo;
import lombok.Data;
/**
*
*/
@Data
public class LoginVO {
/**
* JWT
*/
private String token;
/**
*
*/
private UserVO user;
}

@ -0,0 +1,47 @@
package cn.edu.hnu.artifactcommon.pojo.vo;
import lombok.Data;
import java.time.LocalDateTime;
/**
*
*/
@Data
public class UserVO {
/**
* ID
*/
private Long id;
/**
*
*/
private String username;
/**
*
*/
private String email;
/**
*
*/
private String role;
/**
* 0-1-
*/
private Integer status;
/**
*
*/
private LocalDateTime createTime;
/**
*
*/
private LocalDateTime lastLoginTime;
}

@ -0,0 +1,100 @@
package cn.edu.hnu.artifactcommon.result;
import lombok.Data;
/**
*
*/
@Data
public class Result<T> {
/**
*
*/
private Integer code;
/**
*
*/
private String message;
/**
*
*/
private T data;
/**
*
*/
private Long timestamp;
private Result() {
this.timestamp = System.currentTimeMillis();
}
/**
*
*/
public static <T> Result<T> success() {
Result<T> result = new Result<>();
result.setCode(200);
result.setMessage("操作成功");
return result;
}
/**
*
*/
public static <T> Result<T> success(String message) {
Result<T> result = success();
result.setMessage(message);
return result;
}
/**
*
*/
public static <T> Result<T> success(T data) {
Result<T> result = success();
result.setData(data);
return result;
}
/**
*
*/
public static <T> Result<T> success(String message, T data) {
Result<T> result = success(message);
result.setData(data);
return result;
}
/**
*
*/
public static <T> Result<T> error() {
Result<T> result = new Result<>();
result.setCode(500);
result.setMessage("操作失败");
return result;
}
/**
*
*/
public static <T> Result<T> error(String message) {
Result<T> result = error();
result.setMessage(message);
return result;
}
/**
*
*/
public static <T> Result<T> error(Integer code, String message) {
Result<T> result = new Result<>();
result.setCode(code);
result.setMessage(message);
return result;
}
}

@ -0,0 +1,175 @@
package cn.edu.hnu.artifactcommon.utils;
import cn.edu.hnu.artifactcommon.constant.SystemConstant;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.Random;
import java.util.concurrent.TimeUnit;
/**
*
*/
@Component
public class CaptchaUtil {
@Resource
private RedisUtil redisUtil;
/**
*
*/
private static final String CAPTCHA_CHARS = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
/**
*
*/
private static final int CAPTCHA_LENGTH = 4;
/**
*
*/
private static final int CAPTCHA_EXPIRE_MINUTES = 5;
/**
*
* @param uuid
* @return Base64
* @throws IOException IO
*/
public String generateCaptcha(String uuid) throws IOException {
// 生成随机验证码
String captcha = generateRandomCaptcha();
// 将验证码存储到Redis设置过期时间
String redisKey = SystemConstant.REDIS_KEY_CAPTCHA + uuid;
redisUtil.set(redisKey, captcha, CAPTCHA_EXPIRE_MINUTES, TimeUnit.MINUTES);
// 生成验证码图片
BufferedImage image = createCaptchaImage(captcha);
// 将图片转换为Base64字符串
return imageToBase64(image);
}
/**
*
* @param uuid
* @param captcha
* @return
*/
public boolean validateCaptcha(String uuid, String captcha) {
if (StringUtils.isEmpty(uuid) || StringUtils.isEmpty(captcha)) {
return false;
}
String redisKey = SystemConstant.REDIS_KEY_CAPTCHA + uuid;
String storedCaptcha = redisUtil.get(redisKey).toString();
if (storedCaptcha == null) {
return false;
}
// 验证成功后删除验证码
redisUtil.del(redisKey);
// 不区分大小写比较
return storedCaptcha.equalsIgnoreCase(captcha);
}
/**
*
* @return
*/
private String generateRandomCaptcha() {
Random random = new Random();
StringBuilder captcha = new StringBuilder();
for (int i = 0; i < CAPTCHA_LENGTH; i++) {
captcha.append(CAPTCHA_CHARS.charAt(random.nextInt(CAPTCHA_CHARS.length())));
}
return captcha.toString();
}
/**
*
* @param captcha
* @return
*/
private BufferedImage createCaptchaImage(String captcha) {
int width = 120;
int height = 40;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics graphics = image.getGraphics();
// 设置背景色
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, width, height);
// 设置字体
graphics.setFont(new Font("Arial", Font.BOLD, 20));
// 绘制验证码
Random random = new Random();
for (int i = 0; i < captcha.length(); i++) {
// 设置随机颜色
graphics.setColor(new Color(
random.nextInt(110),
random.nextInt(110),
random.nextInt(110)
));
// 绘制字符
graphics.drawString(
String.valueOf(captcha.charAt(i)),
20 * i + 10,
25
);
}
// 绘制干扰线
for (int i = 0; i < 8; i++) {
graphics.setColor(new Color(
random.nextInt(256),
random.nextInt(256),
random.nextInt(256)
));
int x1 = random.nextInt(width);
int y1 = random.nextInt(height);
int x2 = random.nextInt(width);
int y2 = random.nextInt(height);
graphics.drawLine(x1, y1, x2, y2);
}
graphics.dispose();
return image;
}
/**
* Base64
* @param image
* @return Base64
* @throws IOException IO
*/
private String imageToBase64(BufferedImage image) throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
javax.imageio.ImageIO.write(image, "png", outputStream);
byte[] imageBytes = outputStream.toByteArray();
return "data:image/png;base64," + Base64.getEncoder().encodeToString(imageBytes);
}
}

@ -0,0 +1,88 @@
package cn.edu.hnu.artifactcommon.utils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.util.DigestUtils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;
/**
*
*/
public class EncryptUtil {
/**
* MD5
* @param text
* @return
*/
public static String md5(String text) {
return DigestUtils.md5DigestAsHex(text.getBytes());
}
/**
* MD5
* @param text
* @param salt
* @return
*/
public static String md5(String text, String salt) {
return md5(text + salt);
}
/**
*
* @return
*/
public static String generateSalt() {
return UUID.randomUUID().toString().replace("-", "");
}
/**
* BCrypt
* @param password
* @return
*/
public static String bcrypt(String password) {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder.encode(password);
}
/**
* BCrypt
* @param password
* @param encodedPassword
* @return
*/
public static boolean bcryptMatch(String password, String encodedPassword) {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder.matches(password, encodedPassword);
}
/**
* SHA256
* @param text
* @return
*/
public static String sha256(String text) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(text.getBytes());
StringBuilder hexString = new StringBuilder();
for (byte b : hash) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("SHA-256加密失败", e);
}
}
}

@ -0,0 +1,100 @@
package cn.edu.hnu.artifactcommon.utils;
import cn.edu.hnu.artifactcommon.constant.SystemConstant;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.stereotype.Component;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
/**
* JWT
*/
@Component
public class JwtUtil {
/**
*
*/
private Key getSigningKey() {
return Keys.hmacShaKeyFor(SystemConstant.JWT_SECRET.getBytes());
}
/**
* token
*/
public String getUsernameFromToken(String token) {
return getClaimFromToken(token, Claims::getSubject);
}
/**
* token
*/
public Date getExpirationDateFromToken(String token) {
return getClaimFromToken(token, Claims::getExpiration);
}
/**
* token
*/
public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
final Claims claims = getAllClaimsFromToken(token);
return claimsResolver.apply(claims);
}
/**
* token
*/
private Claims getAllClaimsFromToken(String token) {
return Jwts.parserBuilder()
.setSigningKey(getSigningKey())
.build()
.parseClaimsJws(token)
.getBody();
}
/**
* token
*/
private Boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
}
/**
* token
*/
public String generateToken(String username, String role) {
Map<String, Object> claims = new HashMap<>();
claims.put("role", role);
return doGenerateToken(claims, username);
}
/**
* token
*/
private String doGenerateToken(Map<String, Object> claims, String subject) {
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + SystemConstant.JWT_EXPIRATION))
.signWith(getSigningKey(), SignatureAlgorithm.HS256)
.compact();
}
/**
* token
*/
public Boolean validateToken(String token, String username) {
final String tokenUsername = getUsernameFromToken(token);
return (tokenUsername.equals(username) && !isTokenExpired(token));
}
}

@ -0,0 +1,157 @@
package cn.edu.hnu.artifactcommon.utils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import jakarta.annotation.Resource;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
/**
* Redis
*/
@Component
public class RedisUtil {
@Resource
private RedisTemplate<String, Object> redisTemplate;
/**
*
*/
private static final int CAPTCHA_EXPIRE_MINUTES = 5;
/**
*
* @param key
* @param time ()
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* key
* @param key null
* @return () 0
*/
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* key
* @param key
* @return true false
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
*
* @param key
*/
@SuppressWarnings("unchecked")
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
}
}
}
/**
*
* @param key
* @return
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
*
*
* @param redisKey
* @param key
* @param captchaExpireMinutes
* @param value
* @return true false
*/
public boolean set(String redisKey, String key, int captchaExpireMinutes, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
*
* @param key
* @param value
* @param time () time0 time0
* @return true false
*/
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
// 修改这里,调整参数顺序
set(key, value, CAPTCHA_EXPIRE_MINUTES * 60L);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
*
* @param key
* @param delta (0)
*/
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
/**
*
* @param key
* @param delta (0)
*/
public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
}

@ -37,8 +37,14 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>cn.edu.hnu</groupId>
<artifactId>artifact-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
</dependencies>
<build>
<plugins>

@ -0,0 +1,107 @@
package cn.edu.hnu.artifactsystem.controller;
import cn.edu.hnu.artifactsystem.entity.Permission;
import cn.edu.hnu.artifactsystem.service.IPermissionService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.util.List;
/**
*
*/
@RestController
@RequestMapping("/api/permissions")
public class PermissionController {
@Resource
private IPermissionService permissionService;
/**
*
*/
@GetMapping
public Page<Permission> getPermissionPage(
@RequestParam(defaultValue = "1") int current,
@RequestParam(defaultValue = "10") int size,
@RequestParam(required = false) String name,
@RequestParam(required = false) Integer type,
@RequestParam(required = false) Integer status) {
return permissionService.getPermissionPage(current, size, name, type, status);
}
/**
* ID
*/
@GetMapping("/{id}")
public Permission getPermissionById(@PathVariable Long id) {
return permissionService.getPermissionById(id);
}
/**
*
*/
@GetMapping("/all")
public List<Permission> getAllPermissions() {
return permissionService.getAllPermissions();
}
/**
*
*/
@GetMapping("/tree")
public List<Permission> getPermissionTree() {
return permissionService.getPermissionTree();
}
/**
*
*/
@PostMapping
public Permission addPermission(@RequestBody Permission permission) {
return permissionService.addPermission(permission);
}
/**
*
*/
@PutMapping("/{id}")
public boolean updatePermission(@PathVariable Long id, @RequestBody Permission permission) {
permission.setId(id);
return permissionService.updatePermission(permission);
}
/**
*
*/
@DeleteMapping("/{id}")
public boolean deletePermission(@PathVariable Long id) {
return permissionService.deletePermission(id);
}
/**
*
*/
@DeleteMapping("/batch")
public boolean batchDeletePermissions(@RequestBody List<Long> ids) {
return permissionService.batchDeletePermissions(ids);
}
/**
* ID
*/
@GetMapping("/user/{userId}")
public List<Permission> getPermissionsByUserId(@PathVariable Long userId) {
return permissionService.getPermissionsByUserId(userId);
}
/**
* ID
*/
@GetMapping("/role/{roleId}")
public List<Permission> getPermissionsByRoleId(@PathVariable Long roleId) {
return permissionService.getPermissionsByRoleId(roleId);
}
}

@ -0,0 +1,114 @@
package cn.edu.hnu.artifactsystem.controller;
import cn.edu.hnu.artifactsystem.entity.Role;
import cn.edu.hnu.artifactsystem.service.IRoleService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.util.List;
/**
*
*/
@RestController
@RequestMapping("/api/roles")
public class RoleController {
@Resource
private IRoleService roleService;
/**
*
*/
@GetMapping
public Page<Role> getRolePage(
@RequestParam(defaultValue = "1") int current,
@RequestParam(defaultValue = "10") int size,
@RequestParam(required = false) String name,
@RequestParam(required = false) Integer status) {
return roleService.getRolePage(current, size, name, status);
}
/**
* ID
*/
@GetMapping("/{id}")
public Role getRoleById(@PathVariable Long id) {
return roleService.getRoleById(id);
}
/**
*
*/
@GetMapping("/all")
public List<Role> getAllRoles() {
return roleService.getAllRoles();
}
/**
*
*/
@PostMapping
public Role addRole(@RequestBody Role role) {
return roleService.addRole(role);
}
/**
*
*/
@PutMapping("/{id}")
public boolean updateRole(@PathVariable Long id, @RequestBody Role role) {
role.setId(id);
return roleService.updateRole(role);
}
/**
*
*/
@DeleteMapping("/{id}")
public boolean deleteRole(@PathVariable Long id) {
return roleService.deleteRole(id);
}
/**
*
*/
@DeleteMapping("/batch")
public boolean batchDeleteRoles(@RequestBody List<Long> ids) {
return roleService.batchDeleteRoles(ids);
}
/**
* ID
*/
@GetMapping("/user/{userId}")
public List<Role> getRolesByUserId(@PathVariable Long userId) {
return roleService.getRolesByUserId(userId);
}
/**
*
*/
@PostMapping("/user/{userId}")
public boolean assignRolesToUser(@PathVariable Long userId, @RequestBody List<Long> roleIds) {
return roleService.assignRolesToUser(userId, roleIds);
}
/**
* IDID
*/
@GetMapping("/{roleId}/permissions")
public List<Long> getPermissionIdsByRoleId(@PathVariable Long roleId) {
return roleService.getPermissionIdsByRoleId(roleId);
}
/**
*
*/
@PostMapping("/{roleId}/permissions")
public boolean assignPermissionsToRole(@PathVariable Long roleId, @RequestBody List<Long> permissionIds) {
return roleService.assignPermissionsToRole(roleId, permissionIds);
}
}

@ -0,0 +1,89 @@
package cn.edu.hnu.artifactsystem.controller;
import cn.edu.hnu.artifactcommon.pojo.dto.UserDTO;
import cn.edu.hnu.artifactcommon.pojo.vo.LoginVO;
import cn.edu.hnu.artifactcommon.pojo.vo.UserVO;
import cn.edu.hnu.artifactcommon.utils.CaptchaUtil;
import cn.edu.hnu.artifactsystem.service.IUserService;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
*
*/
@RestController
@RequestMapping("/api/user")
public class UserController {
@Resource
private IUserService userService;
@Resource
private CaptchaUtil captchaUtil;
/**
*
*/
@PostMapping("/register")
public UserVO register(@RequestBody UserDTO userDTO) {
return userService.register(userDTO);
}
/**
*
*/
@PostMapping("/login")
public LoginVO login(@RequestBody UserDTO userDTO) {
return userService.login(userDTO);
}
/**
*
*/
@GetMapping("/captcha")
public Map<String, String> getCaptcha() throws IOException {
// 生成UUID作为验证码标识
String uuid = UUID.randomUUID().toString();
// 生成验证码图片
String captchaImage = captchaUtil.generateCaptcha(uuid);
// 返回验证码图片和UUID
Map<String, String> result = new HashMap<>();
result.put("uuid", uuid);
result.put("image", captchaImage);
return result;
}
/**
*
*/
@GetMapping("/info")
public UserVO getCurrentUser(HttpServletRequest request) {
// 从请求属性中获取用户名
String username = (String) request.getAttribute("username");
if (username == null || username.isEmpty()) {
throw new RuntimeException("未登录或令牌已过期");
}
return userService.getUserByUsername(username);
}
/**
*
*/
@PostMapping("/logout")
public String logout() {
// 实际应用中可以在这里处理令牌黑名单等逻辑
return "登出成功";
}
}

@ -0,0 +1,96 @@
package cn.edu.hnu.artifactsystem.controller;
import cn.edu.hnu.artifactsystem.entity.User;
import cn.edu.hnu.artifactsystem.service.IUserService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
*/
@RestController
@RequestMapping("/api/users")
public class UserManagementController {
@Resource
private IUserService userService;
/**
*
*/
@GetMapping
public Map<String, Object> getUserPage(
@RequestParam(defaultValue = "1") int current,
@RequestParam(defaultValue = "10") int size,
@RequestParam(required = false) String username) {
Page<User> page = new Page<>(current, size);
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
if (username != null && !username.isEmpty()) {
queryWrapper.like("username", username);
}
queryWrapper.orderByDesc("create_time");
Page<User> userPage = userService.page(page, queryWrapper);
Map<String, Object> result = new HashMap<>();
result.put("items", userPage.getRecords());
result.put("total", userPage.getTotal());
return result;
}
/**
* ID
*/
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
return userService.getById(id);
}
/**
*
*/
@PutMapping("/{id}")
public boolean updateUser(@PathVariable Long id, @RequestBody User user) {
user.setId(id);
return userService.updateById(user);
}
/**
*
*/
@DeleteMapping("/{id}")
public boolean deleteUser(@PathVariable Long id) {
return userService.removeById(id);
}
/**
*
*/
@DeleteMapping("/batch")
public boolean batchDeleteUsers(@RequestBody List<Long> ids) {
return userService.removeByIds(ids);
}
/**
*
*/
@PutMapping("/{id}/status")
public boolean toggleUserStatus(@PathVariable Long id, @RequestParam Integer status) {
User user = userService.getById(id);
if (user != null) {
user.setStatus(status);
return userService.updateById(user);
}
return false;
}
}

@ -0,0 +1,83 @@
package cn.edu.hnu.artifactsystem.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
/**
*
*/
@Data
@TableName("sys_permission")
public class Permission {
/**
* ID
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
*
*/
private String name;
/**
*
*/
private String code;
/**
* 1-2-3-
*/
private Integer type;
/**
* ID
*/
private Long parentId;
/**
*
*/
private String path;
/**
*
*/
private String component;
/**
*
*/
private String icon;
/**
*
*/
private Integer sortOrder;
/**
* 0-1-
*/
private Integer status;
/**
*
*/
private LocalDateTime createTime;
/**
*
*/
private LocalDateTime updateTime;
/**
*
*/
private List<Permission> children;
}

@ -0,0 +1,57 @@
package cn.edu.hnu.artifactsystem.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
/**
*
*/
@Data
@TableName("sys_role")
public class Role {
/**
* ID
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
*
*/
private String name;
/**
*
*/
private String code;
/**
*
*/
private String description;
/**
*
*/
private Integer sortOrder;
/**
* 0-1-
*/
private Integer status;
/**
*
*/
private LocalDateTime createTime;
/**
*
*/
private LocalDateTime updateTime;
}

@ -0,0 +1,29 @@
package cn.edu.hnu.artifactsystem.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
/**
*
*/
@Data
@TableName("sys_role_permission")
public class RolePermission {
/**
* ID
*/
private Long roleId;
/**
* ID
*/
private Long permissionId;
/**
*
*/
private LocalDateTime createTime;
}

@ -0,0 +1,57 @@
package cn.edu.hnu.artifactsystem.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
/**
*
*/
@Data
@TableName("sys_user")
public class User {
/**
* ID
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
*
*/
private String username;
/**
*
*/
private String password;
/**
*
*/
private String email;
/**
*
*/
private String role;
/**
* 0-1-
*/
private Integer status;
/**
*
*/
private LocalDateTime createTime;
/**
*
*/
private LocalDateTime lastLoginTime;
}

@ -0,0 +1,29 @@
package cn.edu.hnu.artifactsystem.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
/**
*
*/
@Data
@TableName("sys_user_role")
public class UserRole {
/**
* ID
*/
private Long userId;
/**
* ID
*/
private Long roleId;
/**
*
*/
private LocalDateTime createTime;
}

@ -0,0 +1,15 @@
package cn.edu.hnu.artifactsystem.mapper;
import cn.edu.hnu.artifactsystem.entity.Permission;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
*
*/
@Mapper
public interface PermissionMapper extends BaseMapper<Permission> {
// 继承BaseMapper后基本的CRUD操作已由MyBatis-Plus提供
// 如需自定义SQL可在此添加方法并使用@Select、@Insert等注解
}

@ -0,0 +1,15 @@
package cn.edu.hnu.artifactsystem.mapper;
import cn.edu.hnu.artifactsystem.entity.Role;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
*
*/
@Mapper
public interface RoleMapper extends BaseMapper<Role> {
// 继承BaseMapper后基本的CRUD操作已由MyBatis-Plus提供
// 如需自定义SQL可在此添加方法并使用@Select、@Insert等注解
}

@ -0,0 +1,29 @@
package cn.edu.hnu.artifactsystem.mapper;
import cn.edu.hnu.artifactsystem.entity.RolePermission;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
*
*/
@Mapper
public interface RolePermissionMapper extends BaseMapper<RolePermission> {
/**
* IDID
*/
@Select("SELECT permission_id FROM sys_role_permission WHERE role_id = #{roleId}")
List<Long> selectPermissionIdsByRoleId(@Param("roleId") Long roleId);
/**
* IDID
*/
@Select("SELECT role_id FROM sys_role_permission WHERE permission_id = #{permissionId}")
List<Long> selectRoleIdsByPermissionId(@Param("permissionId") Long permissionId);
}

@ -0,0 +1,15 @@
package cn.edu.hnu.artifactsystem.mapper;
import cn.edu.hnu.artifactsystem.entity.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
*
*/
@Mapper
public interface UserMapper extends BaseMapper<User> {
// 继承BaseMapper后基本的CRUD操作已由MyBatis-Plus提供
// 如需自定义SQL可在此添加方法并使用@Select、@Insert等注解
}

@ -0,0 +1,29 @@
package cn.edu.hnu.artifactsystem.mapper;
import cn.edu.hnu.artifactsystem.entity.UserRole;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
*
*/
@Mapper
public interface UserRoleMapper extends BaseMapper<UserRole> {
/**
* IDID
*/
@Select("SELECT role_id FROM sys_user_role WHERE user_id = #{userId}")
List<Long> selectRoleIdsByUserId(@Param("userId") Long userId);
/**
* IDID
*/
@Select("SELECT user_id FROM sys_user_role WHERE role_id = #{roleId}")
List<Long> selectUserIdsByRoleId(@Param("roleId") Long roleId);
}

@ -0,0 +1,64 @@
package cn.edu.hnu.artifactsystem.service;
import cn.edu.hnu.artifactsystem.entity.Permission;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
*
*/
public interface IPermissionService extends IService<Permission> {
/**
*
*/
Page<Permission> getPermissionPage(int current, int size, String name, Integer type, Integer status);
/**
* ID
*/
Permission getPermissionById(Long id);
/**
*
*/
Permission addPermission(Permission permission);
/**
*
*/
boolean updatePermission(Permission permission);
/**
*
*/
boolean deletePermission(Long id);
/**
*
*/
boolean batchDeletePermissions(List<Long> ids);
/**
*
*/
List<Permission> getAllPermissions();
/**
*
*/
List<Permission> getPermissionTree();
/**
* ID
*/
List<Permission> getPermissionsByUserId(Long userId);
/**
* ID
*/
List<Permission> getPermissionsByRoleId(Long roleId);
}

@ -0,0 +1,69 @@
package cn.edu.hnu.artifactsystem.service;
import cn.edu.hnu.artifactsystem.entity.Role;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
*
*/
public interface IRoleService extends IService<Role> {
/**
*
*/
Page<Role> getRolePage(int current, int size, String name, Integer status);
/**
* ID
*/
Role getRoleById(Long id);
/**
*
*/
Role addRole(Role role);
/**
*
*/
boolean updateRole(Role role);
/**
*
*/
boolean deleteRole(Long id);
/**
*
*/
boolean batchDeleteRoles(List<Long> ids);
/**
*
*/
List<Role> getAllRoles();
/**
* ID
*/
List<Role> getRolesByUserId(Long userId);
/**
*
*/
boolean assignRolesToUser(Long userId, List<Long> roleIds);
/**
* IDID
*/
List<Long> getPermissionIdsByRoleId(Long roleId);
/**
*
*/
boolean assignPermissionsToRole(Long roleId, List<Long> permissionIds);
}

@ -0,0 +1,44 @@
package cn.edu.hnu.artifactsystem.service;
import cn.edu.hnu.artifactsystem.entity.User;
import cn.edu.hnu.artifactcommon.pojo.dto.UserDTO;
import cn.edu.hnu.artifactcommon.pojo.vo.LoginVO;
import cn.edu.hnu.artifactcommon.pojo.vo.UserVO;
import com.baomidou.mybatisplus.extension.service.IService;
/**
*
*/
public interface IUserService extends IService<User> {
/**
*
*/
UserVO register(UserDTO userDTO);
/**
*
*/
LoginVO login(UserDTO userDTO);
/**
*
*/
User findByUsername(String username);
/**
* IDVO
*/
UserVO getUserById(Long id);
/**
*
*/
boolean checkUsernameExists(String username);
/**
* VO
*/
UserVO getUserByUsername(String username);
}

@ -0,0 +1,179 @@
package cn.edu.hnu.artifactsystem.service.impl;
import cn.edu.hnu.artifactsystem.entity.Permission;
import cn.edu.hnu.artifactsystem.entity.RolePermission;
import cn.edu.hnu.artifactsystem.entity.UserRole;
import cn.edu.hnu.artifactsystem.mapper.PermissionMapper;
import cn.edu.hnu.artifactsystem.mapper.RolePermissionMapper;
import cn.edu.hnu.artifactsystem.mapper.UserRoleMapper;
import cn.edu.hnu.artifactsystem.service.IPermissionService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
*
*/
@Service
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements IPermissionService {
@Resource
private PermissionMapper permissionMapper;
@Resource
private UserRoleMapper userRoleMapper;
@Resource
private RolePermissionMapper rolePermissionMapper;
@Override
public Page<Permission> getPermissionPage(int current, int size, String name, Integer type, Integer status) {
Page<Permission> page = new Page<>(current, size);
QueryWrapper<Permission> queryWrapper = new QueryWrapper<>();
if (name != null && !name.isEmpty()) {
queryWrapper.like("name", name);
}
if (type != null) {
queryWrapper.eq("type", type);
}
if (status != null) {
queryWrapper.eq("status", status);
}
queryWrapper.orderByAsc("sort_order");
return permissionMapper.selectPage(page, queryWrapper);
}
@Override
public Permission getPermissionById(Long id) {
return permissionMapper.selectById(id);
}
@Override
public Permission addPermission(Permission permission) {
permission.setCreateTime(LocalDateTime.now());
permissionMapper.insert(permission);
return permission;
}
@Override
public boolean updatePermission(Permission permission) {
permission.setUpdateTime(LocalDateTime.now());
return permissionMapper.updateById(permission) > 0;
}
@Override
public boolean deletePermission(Long id) {
// 删除权限前,先检查是否有角色使用该权限
List<Long> roleIds = rolePermissionMapper.selectRoleIdsByPermissionId(id);
if (roleIds != null && !roleIds.isEmpty()) {
throw new RuntimeException("该权限已被角色使用,无法删除");
}
// 删除权限
return permissionMapper.deleteById(id) > 0;
}
@Override
public boolean batchDeletePermissions(List<Long> ids) {
if (ids == null || ids.isEmpty()) {
return false;
}
for (Long id : ids) {
deletePermission(id);
}
return true;
}
@Override
public List<Permission> getAllPermissions() {
QueryWrapper<Permission> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("status", 0); // 只查询正常状态的权限
queryWrapper.orderByAsc("sort_order");
return permissionMapper.selectList(queryWrapper);
}
@Override
public List<Permission> getPermissionTree() {
List<Permission> allPermissions = getAllPermissions();
// 构建父子关系
Map<Long, Permission> permissionMap = new HashMap<>();
for (Permission permission : allPermissions) {
permissionMap.put(permission.getId(), permission);
}
List<Permission> rootPermissions = new ArrayList<>();
for (Permission permission : allPermissions) {
if (permission.getParentId() == null || permission.getParentId() == 0) {
rootPermissions.add(permission);
} else {
Permission parent = permissionMap.get(permission.getParentId());
if (parent != null) {
if (parent.getChildren() == null) {
parent.setChildren(new ArrayList<>());
}
parent.getChildren().add(permission);
}
}
}
return rootPermissions;
}
@Override
public List<Permission> getPermissionsByUserId(Long userId) {
// 先获取用户的所有角色ID
List<Long> roleIds = userRoleMapper.selectRoleIdsByUserId(userId);
if (roleIds == null || roleIds.isEmpty()) {
return new ArrayList<>();
}
// 再获取这些角色的所有权限ID
List<Long> permissionIds = new ArrayList<>();
for (Long roleId : roleIds) {
List<Long> ids = rolePermissionMapper.selectPermissionIdsByRoleId(roleId);
if (ids != null) {
permissionIds.addAll(ids);
}
}
// 去重
permissionIds = permissionIds.stream().distinct().collect(Collectors.toList());
// 最后根据权限ID获取权限信息
if (permissionIds.isEmpty()) {
return new ArrayList<>();
}
return permissionMapper.selectBatchIds(permissionIds);
}
@Override
public List<Permission> getPermissionsByRoleId(Long roleId) {
// 先获取角色的所有权限ID
List<Long> permissionIds = rolePermissionMapper.selectPermissionIdsByRoleId(roleId);
if (permissionIds == null || permissionIds.isEmpty()) {
return new ArrayList<>();
}
// 根据权限ID获取权限信息
return permissionMapper.selectBatchIds(permissionIds);
}
}

@ -0,0 +1,169 @@
package cn.edu.hnu.artifactsystem.service.impl;
import cn.edu.hnu.artifactsystem.entity.Role;
import cn.edu.hnu.artifactsystem.entity.RolePermission;
import cn.edu.hnu.artifactsystem.entity.UserRole;
import cn.edu.hnu.artifactsystem.mapper.RoleMapper;
import cn.edu.hnu.artifactsystem.mapper.RolePermissionMapper;
import cn.edu.hnu.artifactsystem.mapper.UserRoleMapper;
import cn.edu.hnu.artifactsystem.service.IRoleService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import jakarta.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
/**
*
*/
@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements IRoleService {
@Resource
private RoleMapper roleMapper;
@Resource
private UserRoleMapper userRoleMapper;
@Resource
private RolePermissionMapper rolePermissionMapper;
@Override
public Page<Role> getRolePage(int current, int size, String name, Integer status) {
Page<Role> page = new Page<>(current, size);
QueryWrapper<Role> queryWrapper = new QueryWrapper<>();
if (name != null && !name.isEmpty()) {
queryWrapper.like("name", name);
}
if (status != null) {
queryWrapper.eq("status", status);
}
queryWrapper.orderByAsc("sort_order");
return roleMapper.selectPage(page, queryWrapper);
}
@Override
public Role getRoleById(Long id) {
return roleMapper.selectById(id);
}
@Override
public Role addRole(Role role) {
role.setCreateTime(LocalDateTime.now());
roleMapper.insert(role);
return role;
}
@Override
public boolean updateRole(Role role) {
role.setUpdateTime(LocalDateTime.now());
return roleMapper.updateById(role) > 0;
}
@Override
public boolean deleteRole(Long id) {
// 删除角色前,先删除角色与用户的关联关系
QueryWrapper<UserRole> userRoleWrapper = new QueryWrapper<>();
userRoleWrapper.eq("role_id", id);
userRoleMapper.delete(userRoleWrapper);
// 删除角色前,先删除角色与权限的关联关系
QueryWrapper<RolePermission> rolePermissionWrapper = new QueryWrapper<>();
rolePermissionWrapper.eq("role_id", id);
rolePermissionMapper.delete(rolePermissionWrapper);
// 删除角色
return roleMapper.deleteById(id) > 0;
}
@Override
public boolean batchDeleteRoles(List<Long> ids) {
if (ids == null || ids.isEmpty()) {
return false;
}
for (Long id : ids) {
deleteRole(id);
}
return true;
}
@Override
public List<Role> getAllRoles() {
QueryWrapper<Role> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("status", 0); // 只查询正常状态的角色
queryWrapper.orderByAsc("sort_order");
return roleMapper.selectList(queryWrapper);
}
@Override
public List<Role> getRolesByUserId(Long userId) {
// 先查询用户拥有的角色ID
List<Long> roleIds = userRoleMapper.selectRoleIdsByUserId(userId);
if (roleIds == null || roleIds.isEmpty()) {
return new ArrayList<>();
}
// 再根据角色ID查询角色信息
return roleMapper.selectBatchIds(roleIds);
}
@Override
@Transactional
public boolean assignRolesToUser(Long userId, List<Long> roleIds) {
// 先删除用户原有的角色关系
QueryWrapper<UserRole> wrapper = new QueryWrapper<>();
wrapper.eq("user_id", userId);
userRoleMapper.delete(wrapper);
// 添加新的角色关系
if (roleIds != null && !roleIds.isEmpty()) {
for (Long roleId : roleIds) {
UserRole userRole = new UserRole();
userRole.setUserId(userId);
userRole.setRoleId(roleId);
userRole.setCreateTime(LocalDateTime.now());
userRoleMapper.insert(userRole);
}
}
return true;
}
@Override
public List<Long> getPermissionIdsByRoleId(Long roleId) {
return rolePermissionMapper.selectPermissionIdsByRoleId(roleId);
}
@Override
@Transactional
public boolean assignPermissionsToRole(Long roleId, List<Long> permissionIds) {
// 先删除角色原有的权限关系
QueryWrapper<RolePermission> wrapper = new QueryWrapper<>();
wrapper.eq("role_id", roleId);
rolePermissionMapper.delete(wrapper);
// 添加新的权限关系
if (permissionIds != null && !permissionIds.isEmpty()) {
for (Long permissionId : permissionIds) {
RolePermission rolePermission = new RolePermission();
rolePermission.setRoleId(roleId);
rolePermission.setPermissionId(permissionId);
rolePermission.setCreateTime(LocalDateTime.now());
rolePermissionMapper.insert(rolePermission);
}
}
return true;
}
}

@ -0,0 +1,143 @@
package cn.edu.hnu.artifactsystem.service.impl;
import cn.edu.hnu.artifactcommon.constant.SystemConstant;
import cn.edu.hnu.artifactcommon.pojo.dto.UserDTO;
import cn.edu.hnu.artifactcommon.pojo.vo.LoginVO;
import cn.edu.hnu.artifactcommon.pojo.vo.UserVO;
import cn.edu.hnu.artifactcommon.utils.CaptchaUtil;
import cn.edu.hnu.artifactcommon.utils.EncryptUtil;
import cn.edu.hnu.artifactcommon.utils.JwtUtil;
import cn.edu.hnu.artifactsystem.entity.User;
import cn.edu.hnu.artifactsystem.mapper.UserMapper;
import cn.edu.hnu.artifactsystem.service.IUserService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import java.time.LocalDateTime;
/**
*
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
@Resource
private UserMapper userMapper;
@Resource
private JwtUtil jwtUtil;
@Resource
private CaptchaUtil captchaUtil;
@Override
public UserVO register(UserDTO userDTO) {
// 验证验证码
if (!captchaUtil.validateCaptcha(userDTO.getCaptchaUuid(), userDTO.getCaptcha())) {
throw new RuntimeException("验证码错误");
}
// 检查用户名是否已存在
if (checkUsernameExists(userDTO.getUsername())) {
throw new RuntimeException("用户名已存在");
}
// 创建用户实体
User user = new User();
user.setUsername(userDTO.getUsername());
user.setPassword(encryptPassword(userDTO.getPassword()));
user.setEmail(userDTO.getEmail());
user.setRole(SystemConstant.ROLE_USER); // 默认角色为普通用户
user.setStatus(SystemConstant.STATUS_NORMAL); // 默认状态为正常
user.setCreateTime(LocalDateTime.now());
// 保存用户
userMapper.insert(user);
// 转换为VO并返回
return convertToVO(user);
}
@Override
public LoginVO login(UserDTO userDTO) {
// 验证验证码
if (!captchaUtil.validateCaptcha(userDTO.getCaptchaUuid(), userDTO.getCaptcha())) {
throw new RuntimeException("验证码错误");
}
// 根据用户名查询用户
User user = findByUsername(userDTO.getUsername());
if (user == null) {
throw new RuntimeException("用户不存在");
}
// 验证密码
if (!user.getPassword().equals(encryptPassword(userDTO.getPassword()))) {
throw new RuntimeException("密码错误");
}
// 检查用户状态
if (!SystemConstant.STATUS_NORMAL.equals(user.getStatus())) {
throw new RuntimeException("账户已被禁用");
}
// 更新最后登录时间
user.setLastLoginTime(LocalDateTime.now());
userMapper.updateById(user);
// 生成JWT令牌
String token = jwtUtil.generateToken(user.getUsername(), user.getRole());
// 构建登录响应
LoginVO loginVO = new LoginVO();
loginVO.setToken(token);
loginVO.setUser(convertToVO(user));
return loginVO;
}
@Override
public User findByUsername(String username) {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username", username);
return userMapper.selectOne(queryWrapper);
}
@Override
public UserVO getUserById(Long id) {
User user = userMapper.selectById(id);
return user != null ? convertToVO(user) : null;
}
@Override
public boolean checkUsernameExists(String username) {
return findByUsername(username) != null;
}
@Override
public UserVO getUserByUsername(String username) {
User user = findByUsername(username);
return user != null ? convertToVO(user) : null;
}
/**
*
*/
private String encryptPassword(String password) {
return EncryptUtil.md5(password);
}
/**
* VO
*/
private UserVO convertToVO(User user) {
UserVO userVO = new UserVO();
BeanUtils.copyProperties(user, userVO);
// 不返回密码
return userVO;
}
}

@ -38,6 +38,32 @@
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 添加对artifact-system模块的依赖 -->
<dependency>
<groupId>cn.edu.hnu</groupId>
<artifactId>artifact-system</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- 添加对其他业务模块的依赖 -->
<dependency>
<groupId>cn.edu.hnu</groupId>
<artifactId>artifact-ai</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.edu.hnu</groupId>
<artifactId>artifact-knowledge</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.edu.hnu</groupId>
<artifactId>artifact-relic</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>

@ -43,6 +43,7 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
@ -54,18 +55,69 @@
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter-test</artifactId>
<version>3.0.5</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version> <!-- 使用与项目兼容的最新版本 -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version> <!-- 使用与项目兼容的最新版本 -->
</dependency>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
<build>
<plugins>

@ -0,0 +1,120 @@
-- 创建数据库
CREATE DATABASE IF NOT EXISTS artifact_llm CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 使用数据库
USE artifact_llm;
/*==============================================================*/
/* DBMS name: MySQL 8.0 */
/* Created on: 2024/XX/XX 10:00:00 */
/*==============================================================*/
-- 删除所有表(按依赖关系逆序)
DROP TABLE IF EXISTS audit_trails;
DROP TABLE IF EXISTS user_management_logs;
DROP TABLE IF EXISTS content_review_logs;
DROP TABLE IF EXISTS model_review_records;
DROP TABLE IF EXISTS feedback;
DROP TABLE IF EXISTS user_favorites;
DROP TABLE IF EXISTS search_history;
DROP TABLE IF EXISTS messages;
DROP TABLE IF EXISTS kg_update_requests;
DROP TABLE IF EXISTS modeling_versions;
DROP TABLE IF EXISTS modeling_projects;
DROP TABLE IF EXISTS user_defined_relations;
DROP TABLE IF EXISTS user_defined_entities;
DROP TABLE IF EXISTS ai_research_reports;
DROP TABLE IF EXISTS ai_messages;
DROP TABLE IF EXISTS entity_relations;
DROP TABLE IF EXISTS relic_multi_mode;
DROP TABLE IF EXISTS cultural_relics;
DROP TABLE IF EXISTS login_operation_log;
DROP TABLE IF EXISTS users;
/*==============================================================*/
/* Table: users */
/*==============================================================*/
CREATE TABLE users
(
id INT NOT NULL AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(100),
real_name VARCHAR(50),
phone VARCHAR(20),
user_type VARCHAR(20) NOT NULL DEFAULT 'normal',
status VARCHAR(10) NOT NULL DEFAULT 'active',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
last_login DATETIME,
PRIMARY KEY (id),
UNIQUE KEY uk_username (username),
UNIQUE KEY uk_email (email)
);
/*==============================================================*/
/* Table: login_operation_log */
/*==============================================================*/
CREATE TABLE login_operation_log
(
id INT NOT NULL AUTO_INCREMENT,
user_id INT NOT NULL,
operation_type VARCHAR(50) NOT NULL,
operation_detail TEXT,
ip_address VARCHAR(45),
user_agent TEXT,
operation_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
status VARCHAR(10) NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES users (id)
);
/*==============================================================*/
/* Table: cultural_relics */
/*==============================================================*/
CREATE TABLE cultural_relics
(
id INT NOT NULL AUTO_INCREMENT,
relic_code VARCHAR(50) NOT NULL,
name VARCHAR(200) NOT NULL,
era VARCHAR(100),
material VARCHAR(100),
size VARCHAR(100),
discovery_site VARCHAR(200),
current_location VARCHAR(200),
description TEXT,
cultural_level VARCHAR(50),
preservation_status VARCHAR(50),
created_by INT NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_by INT NOT NULL,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY uk_relic_code (relic_code),
FOREIGN KEY (created_by) REFERENCES users (id),
FOREIGN KEY (updated_by) REFERENCES users (id)
);
/*==============================================================*/
/* Table: relic_multi_mode */
/*==============================================================*/
CREATE TABLE relic_multi_mode
(
id INT NOT NULL AUTO_INCREMENT,
relic_id INT NOT NULL,
resource_type VARCHAR(20) NOT NULL,
resource_name VARCHAR(200) NOT NULL,
resource_path VARCHAR(500) NOT NULL,
file_size BIGINT,
file_format VARCHAR(20),
description TEXT,
upload_by INT NOT NULL,
upload_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_approved TINYINT NOT NULL DEFAULT 0,
approved_by INT,
approved_time DATETIME,
PRIMARY KEY (id),
FOREIGN KEY (relic_id) REFERENCES cultural_relics (id),
FOREIGN KEY (upload_by) REFERENCES users (id),
FOREIGN KEY (approved_by) REFERENCES users (id)
);

@ -0,0 +1,98 @@
/*==============================================================*/
/* Table: entity_relations */
/*==============================================================*/
CREATE TABLE entity_relations
(
id INT NOT NULL AUTO_INCREMENT,
source_entity_id INT NOT NULL,
target_entity_id INT NOT NULL,
relation_type VARCHAR(50) NOT NULL,
relation_name VARCHAR(100) NOT NULL,
description TEXT,
confidence DECIMAL(3,2),
created_by INT NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_by INT NOT NULL,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
FOREIGN KEY (source_entity_id) REFERENCES cultural_relics (id),
FOREIGN KEY (target_entity_id) REFERENCES cultural_relics (id),
FOREIGN KEY (created_by) REFERENCES users (id),
FOREIGN KEY (updated_by) REFERENCES users (id)
);
/*==============================================================*/
/* Table: ai_messages */
/*==============================================================*/
CREATE TABLE ai_messages
(
id INT NOT NULL AUTO_INCREMENT,
user_id INT NOT NULL,
session_id VARCHAR(100) NOT NULL,
message_type VARCHAR(10) NOT NULL,
message_content TEXT NOT NULL,
ai_response TEXT,
response_time INT,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_satisfied TINYINT,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES users (id)
);
/*==============================================================*/
/* Table: ai_research_reports */
/*==============================================================*/
CREATE TABLE ai_research_reports
(
id INT NOT NULL AUTO_INCREMENT,
report_title VARCHAR(200) NOT NULL,
report_type VARCHAR(50) NOT NULL,
report_content TEXT NOT NULL,
generated_by INT NOT NULL,
generated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
data_source TEXT,
keywords VARCHAR(500),
download_count INT NOT NULL DEFAULT 0,
is_public TINYINT NOT NULL DEFAULT 0,
PRIMARY KEY (id),
FOREIGN KEY (generated_by) REFERENCES users (id)
);
/*==============================================================*/
/* Table: user_defined_entities */
/*==============================================================*/
CREATE TABLE user_defined_entities
(
id INT NOT NULL AUTO_INCREMENT,
entity_name VARCHAR(200) NOT NULL,
entity_type VARCHAR(50) NOT NULL,
description TEXT,
properties JSON,
created_by INT NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_by INT NOT NULL,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
status VARCHAR(10) NOT NULL DEFAULT 'pending',
PRIMARY KEY (id),
FOREIGN KEY (created_by) REFERENCES users (id),
FOREIGN KEY (updated_by) REFERENCES users (id)
);
/*==============================================================*/
/* Table: user_defined_relations */
/*==============================================================*/
CREATE TABLE user_defined_relations
(
id INT NOT NULL AUTO_INCREMENT,
source_entity_id INT NOT NULL,
target_entity_id INT NOT NULL,
relation_name VARCHAR(100) NOT NULL,
relation_description TEXT,
created_by INT NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
status VARCHAR(10) NOT NULL DEFAULT 'pending',
PRIMARY KEY (id),
FOREIGN KEY (source_entity_id) REFERENCES user_defined_entities (id),
FOREIGN KEY (target_entity_id) REFERENCES user_defined_entities (id),
FOREIGN KEY (created_by) REFERENCES users (id)
);

@ -0,0 +1,57 @@
/*==============================================================*/
/* Table: modeling_projects */
/*==============================================================*/
CREATE TABLE modeling_projects
(
id INT NOT NULL AUTO_INCREMENT,
project_name VARCHAR(200) NOT NULL,
project_description TEXT,
created_by INT NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
status VARCHAR(20) NOT NULL DEFAULT 'drafting',
is_collaborative TINYINT NOT NULL DEFAULT 0,
collaborators JSON,
PRIMARY KEY (id),
FOREIGN KEY (created_by) REFERENCES users (id)
);
/*==============================================================*/
/* Table: modeling_versions */
/*==============================================================*/
CREATE TABLE modeling_versions
(
id INT NOT NULL AUTO_INCREMENT,
project_id INT NOT NULL,
version_number VARCHAR(20) NOT NULL,
version_description TEXT,
model_data JSON NOT NULL,
created_by INT NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_current TINYINT NOT NULL DEFAULT 1,
PRIMARY KEY (id),
FOREIGN KEY (project_id) REFERENCES modeling_projects (id),
FOREIGN KEY (created_by) REFERENCES users (id)
);
/*==============================================================*/
/* Table: kg_update_requests */
/*==============================================================*/
CREATE TABLE kg_update_requests
(
id INT NOT NULL AUTO_INCREMENT,
request_type VARCHAR(20) NOT NULL,
target_type VARCHAR(20) NOT NULL,
target_id INT,
request_data JSON,
request_reason TEXT,
requested_by INT NOT NULL,
requested_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
status VARCHAR(20) NOT NULL DEFAULT 'pending',
processed_by INT,
processed_at DATETIME,
process_comment TEXT,
PRIMARY KEY (id),
FOREIGN KEY (requested_by) REFERENCES users (id),
FOREIGN KEY (processed_by) REFERENCES users (id)
);

@ -0,0 +1,50 @@
/*==============================================================*/
/* Table: messages */
/*==============================================================*/
CREATE TABLE messages
(
id INT NOT NULL AUTO_INCREMENT,
sender_id INT NOT NULL,
receiver_id INT NOT NULL,
message_type VARCHAR(20) NOT NULL,
message_title VARCHAR(200),
message_content TEXT NOT NULL,
sent_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_read TINYINT NOT NULL DEFAULT 0,
read_at DATETIME,
PRIMARY KEY (id),
FOREIGN KEY (sender_id) REFERENCES users (id),
FOREIGN KEY (receiver_id) REFERENCES users (id)
);
/*==============================================================*/
/* Table: search_history */
/*==============================================================*/
CREATE TABLE search_history
(
id INT NOT NULL AUTO_INCREMENT,
user_id INT NOT NULL,
search_keywords VARCHAR(500) NOT NULL,
search_filters JSON,
search_results INT,
search_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
search_duration INT,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES users (id)
);
/*==============================================================*/
/* Table: user_favorites */
/*==============================================================*/
CREATE TABLE user_favorites
(
id INT NOT NULL AUTO_INCREMENT,
user_id INT NOT NULL,
favorite_type VARCHAR(20) NOT NULL,
favorite_target_id INT NOT NULL,
favorite_title VARCHAR(200) NOT NULL,
favorite_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
tags VARCHAR(500),
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES users (id)
);

@ -0,0 +1,54 @@
/*==============================================================*/
/* Table: feedback */
/*==============================================================*/
CREATE TABLE feedback
(
id INT NOT NULL AUTO_INCREMENT,
user_id INT NOT NULL,
feedback_type VARCHAR(20) NOT NULL,
feedback_title VARCHAR(200) NOT NULL,
feedback_content TEXT NOT NULL,
contact_info VARCHAR(100),
submitted_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
status VARCHAR(20) NOT NULL DEFAULT 'pending',
processed_by INT,
processed_at DATETIME,
process_result TEXT,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES users (id),
FOREIGN KEY (processed_by) REFERENCES users (id)
);
/*==============================================================*/
/* Table: model_review_records */
/*==============================================================*/
CREATE TABLE model_review_records
(
id INT NOT NULL AUTO_INCREMENT,
project_id INT NOT NULL,
reviewer_id INT NOT NULL,
review_result VARCHAR(20) NOT NULL,
review_comment TEXT,
reviewed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
revision_required TINYINT NOT NULL DEFAULT 0,
revision_deadline DATETIME,
PRIMARY KEY (id),
FOREIGN KEY (project_id) REFERENCES modeling_projects (id),
FOREIGN KEY (reviewer_id) REFERENCES users (id)
);
/*==============================================================*/
/* Table: content_review_logs */
/*==============================================================*/
CREATE TABLE content_review_logs
(
id INT NOT NULL AUTO_INCREMENT,
content_type VARCHAR(20) NOT NULL,
content_id INT NOT NULL,
reviewer_id INT NOT NULL,
review_result VARCHAR(20) NOT NULL,
review_comment TEXT,
reviewed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
FOREIGN KEY (reviewer_id) REFERENCES users (id)
);

@ -0,0 +1,54 @@
/*==============================================================*/
/* Table: user_management_logs */
/*==============================================================*/
CREATE TABLE user_management_logs
(
id INT NOT NULL AUTO_INCREMENT,
admin_id INT NOT NULL,
target_user_id INT NOT NULL,
operation_type VARCHAR(20) NOT NULL,
operation_detail TEXT,
operation_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
ip_address VARCHAR(45),
PRIMARY KEY (id),
FOREIGN KEY (admin_id) REFERENCES users (id),
FOREIGN KEY (target_user_id) REFERENCES users (id)
);
/*==============================================================*/
/* Table: audit_trails */
/*==============================================================*/
CREATE TABLE audit_trails
(
id INT NOT NULL AUTO_INCREMENT,
user_id INT NOT NULL,
event_type VARCHAR(50) NOT NULL,
event_description TEXT,
event_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
ip_address VARCHAR(45),
user_agent TEXT,
resource_accessed VARCHAR(500),
operation_result VARCHAR(20) NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES users (id)
);
-- 创建索引以提高查询性能
CREATE INDEX idx_users_user_type ON users(user_type);
CREATE INDEX idx_users_status ON users(status);
CREATE INDEX idx_login_operation_log_user_id ON login_operation_log(user_id);
CREATE INDEX idx_login_operation_log_operation_time ON login_operation_log(operation_time);
CREATE INDEX idx_cultural_relics_relic_code ON cultural_relics(relic_code);
CREATE INDEX idx_cultural_relics_era ON cultural_relics(era);
CREATE INDEX idx_relic_multi_mode_relic_id ON relic_multi_mode(relic_id);
CREATE INDEX idx_relic_multi_mode_resource_type ON relic_multi_mode(resource_type);
CREATE INDEX idx_entity_relations_source_target ON entity_relations(source_entity_id, target_entity_id);
CREATE INDEX idx_ai_messages_user_id ON ai_messages(user_id);
CREATE INDEX idx_ai_messages_session_id ON ai_messages(session_id);
CREATE INDEX idx_ai_research_reports_generated_by ON ai_research_reports(generated_by);
CREATE INDEX idx_ai_research_reports_is_public ON ai_research_reports(is_public);
CREATE INDEX idx_user_favorites_user_id ON user_favorites(user_id);
CREATE INDEX idx_search_history_user_id ON search_history(user_id);
CREATE INDEX idx_search_history_search_time ON search_history(search_time);
CREATE INDEX idx_audit_trails_user_id ON audit_trails(user_id);
CREATE INDEX idx_audit_trails_event_time ON audit_trails(event_time);
Loading…
Cancel
Save