commit cf5790229a863dcd8ee6b0537889345ca60388c1
Author: 郭庆泰 <12369755+htcloud1@user.noreply.gitee.com>
Date: Sat Aug 15 12:41:10 2026 +0800
refactor: 合并 biz_support_unit/biz_execution_unit/biz_service_org 为 biz_org, 删除 2 张孤儿表, 改 biz_person.work_unit → org_id FK
主要改动:
- SQL: biz_support_unit → biz_org, 加 org_type, 加 business_nature; 删 biz_execution_unit, biz_service_org
- SQL: biz_project.support_unit_id/name + service_org_id/name → org_id/name/type
- SQL: biz_meeting.support_unit_name → org_name
- SQL: biz_person.work_unit → org_id (FK)
- 后端: 新 BizOrg entity/mapper/service/controller
- 后端: BizProject/BizMeeting 字段重命名
- 后端: 删 12 个 BizSupportUnit/BizExecutionUnit/BizServiceOrg Java 文件
- 后端: BizPersonImportVO.workUnit → orgName (导入时查 biz_org 取 org_id)
- 后端: BizAuthController.registerExecutor 完整实现 (原 registerSupplier stub)
- 前端: 新 admin/Orgs.vue + manager/Orgs.vue (原 SupportUnits)
- 前端: RegisterExecutor.vue (原 RegisterSupplier, 单页 2 步)
- 前端: sponsor/executor/manager 多个文件 workUnit → orgId/orgName 重命名
- 前端: 统一 supplier → executor, 业务命名 sponsor(赞助方) / executor(执行方=供应商)
- 前端: 全工程 execution → executor (company type / role / person unit_type)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4d5507e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,86 @@
+# ===== Java / Maven =====
+target/
+build/
+*.class
+*.jar
+*.war
+hs_err_pid*.log
+replay_pid*.log
+.mvn/
+mvnw
+mvnw.cmd
+
+# ===== Node / Vue =====
+node_modules/
+dist/
+.cache/
+.vite/
+*.local
+.npm
+.yarn
+
+# ===== IDE =====
+.idea/
+.vscode/
+*.iml
+*.iws
+*.ipr
+.project
+.classpath
+.settings/
+.factorypath
+
+# ===== OS =====
+.DS_Store
+Thumbs.db
+desktop.ini
+$RECYCLE.BIN/
+
+# ===== Logs =====
+logs/
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+
+# ===== Env =====
+.env
+.env.local
+.env.*.local
+
+# ===== Build outputs =====
+out/
+bin/
+*.exe
+*.dll
+*.so
+*.dylib
+
+# ===== Misc =====
+*.bak
+*.tmp
+*.swp
+*.swo
+*~
+.gradle/
+*.iml
+
+# ===== Session / planning 内部笔记 (不进版本库) =====
+.claude/
+.hermes/
+.planning/
+findings.md
+progress.md
+task_plan.md
+entity-config.json
+
+# ===== 大体积 / 二进制 / 备份 (不进版本库) =====
+RuoYi-Vue-master.zip
+apache-maven-3.9.16/
+apache-maven-3.9.16-bin.zip
+ry0808_mysql_dump.sql
+ry8080/
+ry8080.zip
+ry-console/
+ry-vue2/ # 旧 vue 控制台
diff --git a/proto/html/admin.html b/proto/html/admin.html
new file mode 100644
index 0000000..963d111
--- /dev/null
+++ b/proto/html/admin.html
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+ 后台管理 - 项目管理系统
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/account-info-expert.html b/proto/html/components/account-info-expert.html
new file mode 100644
index 0000000..9c9fa47
--- /dev/null
+++ b/proto/html/components/account-info-expert.html
@@ -0,0 +1,837 @@
+
+
+
+
+
+ 账号信息 - 项目管理系统
+
+
+
+
+
+
+
+
+
+
+ 账号信息
+
+
+
+
+ 个人信息
+
+
+ 修改密码
+
+
+
+
+
+
+
+
+
+
+
+
基本资料
+
+
+
+
银行信息
+
+
+
+
+
*专家可更新上传相应的证明文件及身份证照片
+
*签署劳务协议时,先验证是否有执业证书、职称证明、身份证照片,如果没有,必须先上传
+
+
+
+
资质证件
+
+
+
+
+
+
+
+
+
+
+
+
+ 保存
+ 取消
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/account-info.html b/proto/html/components/account-info.html
new file mode 100644
index 0000000..5526ca5
--- /dev/null
+++ b/proto/html/components/account-info.html
@@ -0,0 +1,247 @@
+
+
+
+
+
+ 账号信息 - 项目管理系统
+
+
+
+
+
+ 账号信息
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/account-manage.html b/proto/html/components/account-manage.html
new file mode 100644
index 0000000..8269362
--- /dev/null
+++ b/proto/html/components/account-manage.html
@@ -0,0 +1,229 @@
+
+
+
+
+
+ 账号管理
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/admin-execution-unit-manage.html b/proto/html/components/admin-execution-unit-manage.html
new file mode 100644
index 0000000..bc52356
--- /dev/null
+++ b/proto/html/components/admin-execution-unit-manage.html
@@ -0,0 +1,171 @@
+
+
+
+
+
+
+ 执行单位管理 - 后台
+
+
+
+
+
+
+
+ 执行单位管理
+
+
+
+
公司名称:
+
+
+ 合作状态:
+ 请选择 正常 禁用
+
+
公司地址:
+
税号/统一社会信用代码:
+
查找
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/admin-expert-manage.html b/proto/html/components/admin-expert-manage.html
new file mode 100644
index 0000000..06fc72d
--- /dev/null
+++ b/proto/html/components/admin-expert-manage.html
@@ -0,0 +1,276 @@
+
+
+
+
+
+
+ 专家管理 - 后台
+
+
+
+
+
+
+
+ 专家管理
+
+
+
+
+ 批量审核
+ 批量导入
+ 新建专家
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/admin-home.html b/proto/html/components/admin-home.html
new file mode 100644
index 0000000..74fe859
--- /dev/null
+++ b/proto/html/components/admin-home.html
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+ 首页 - 后台
+
+
+
+
+ 首页
+
+
+
+
+
+
+
+
+
用户注册待审核
3 位新用户提交了注册申请,请尽快审核。
1小时前
+
专家申请待处理
有 2 位专家申请待审批,材料已上传。
3小时前
+
系统权限变更
「合规人员」角色的权限配置已更新,请检查。
昨天
+
月度数据备份
2026 年 7 月系统数据备份已完成。
2026-08-01
+
系统升级公告
系统将于本周日 02:00-04:00 进行升级维护。
2026-07-28
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/admin-intent-support.html b/proto/html/components/admin-intent-support.html
new file mode 100644
index 0000000..c2e8a30
--- /dev/null
+++ b/proto/html/components/admin-intent-support.html
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+ 意向支持 - 后台
+
+
+
+
+
+
+
+ 意向支持管理
+
+
+
+
*项目公示中点击支持意向后, 显示在此
+
+
+
+
+
+
+ 意向项目编号 意向项目名称 姓名
+ 单位名称 部门 职务 手机号
+
+
+
+ ZH-2026-658 小牛血清创新应用研讨会 张三 北京XXXXXX公司 华北大区 项目负责人 13512321597
+ ZH-2026-658 小牛血清创新应用研讨会 李四 北京XXXXXX公司 华北大区 项目负责人 13512321597
+ ZH-2026-658 小牛血清创新应用研讨会 张三 北京XXXXXX公司 华北大区 项目负责人 13512321597
+ ZH-2026-658 小牛血清创新应用研讨会 李四 北京XXXXXX公司 华北大区 项目负责人 13512321597
+ ZH-2026-658 小牛血清创新应用研讨会 张三 北京XXXXXX公司 华北大区 项目负责人 13512321597
+ ZH-2026-658 小牛血清创新应用研讨会 李四 北京XXXXXX公司 华北大区 项目负责人 13512321597
+ ZH-2026-658 小牛血清创新应用研讨会 张三 北京XXXXXX公司 华北大区 项目负责人 13512321597
+ ZH-2026-658 小牛血清创新应用研讨会 李四 北京XXXXXX公司 华北大区 项目负责人 13512321597
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/admin-project-detail.html b/proto/html/components/admin-project-detail.html
new file mode 100644
index 0000000..015790c
--- /dev/null
+++ b/proto/html/components/admin-project-detail.html
@@ -0,0 +1,240 @@
+
+
+
+
+ 项目详情 - 后台
+
+
+
+
+
+ 项目详情
+
+
+
+
项目信息
+
+
项目编号:
+
项目名称:
+
总场次/总期数:
+
总金额:
+
管理费及税金:
+
支持单位:
+
服务机构:
+
项目形式:
+
+
+
*点击后可查看具体评价维度,评价标准与供应商系统保持一致
+
+
+
+
+
支持单位监督员
+
+
增加
+
*增加只显示已点支持意向的
+
+
+
+
+
角色劳务设置
+
+ 角色 劳务金额
+
+ 主席 5,000
+ 主持 3,000
+
+
+
+
+
+
+
+ *项目详情可修改,只有创建人可修改
+
+
+ 返回
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/admin-project-manage.html b/proto/html/components/admin-project-manage.html
new file mode 100644
index 0000000..43f55f8
--- /dev/null
+++ b/proto/html/components/admin-project-manage.html
@@ -0,0 +1,240 @@
+
+
+
+
+
+
+ 项目管理 - 后台
+
+
+
+
+
+
+
+ 项目管理
+
+
+
+
+
项目编号:
+
项目名称:
+
是否结题: 请选择 已结题 未结题
+
是否结算: 请选择 已结算 未结算
+
支持单位: 请选择
+
服务机构: 请选择
+
项目形式: 请选择 线上 线下 线上+线下 其他
+
查找
+
+
*支持多个支持单位筛选 / *支持多个服务机构筛选
+
+
+
+
+ 导出项目评价
+ 项目分配
+ 新建项目
+
+
+
+
+
+
+
+ 项目编号 项目名称 总场次/总期数
+ 已执行 未执行
+ 总金额 可用金额 已支付劳务费 已支付会务费
+ 项目评价分数 支持单位 服务机构
+ 项目形式 是否结题
+ 操作
+
+
+
+
+ ZH-2026-658
+ 小牛血清创新应用研讨会
+ 26 16 10
+ 3,112,000 1,112,000 1,000,000 1,000,000
+ 5.0
+ 北京XXXX有限公司 北京XXXX公司
+ 线上
+ 未结题
+ 分配
+ 结题
+ 查看
+ 编辑
+ 开通
+ 删除公告
+
+
+ ZH-2026-658
+ 小牛血清创新应用研讨会
+ 26 16 10
+ 3,112,000 1,112,000 1,000,000 1,000,000
+ 3.5
+ 北京XXXX有限公司 北京XXXX公司
+ 线下
+ 未结题
+ 分配
+ 结题
+ 查看
+ 编辑
+ 开通
+ 删除公告
+
+
+ ZH-2026-658
+ 小牛血清创新应用研讨会
+ 26 16 10
+ 3,112,000 1,112,000 1,000,000 1,000,000
+ 4.5
+ 北京XXXX有限公司 北京XXXX公司
+ 线上+线下
+ 已结题
+ 分配
+ 结题
+ 查看
+ 编辑
+ 开通
+ 删除公告
+
+
+ ZH-2026-658
+ 小牛血清创新应用研讨会
+ 26 16 10
+ 3,112,000 1,112,000 1,000,000 1,000,000
+ 3.0
+ 北京XXXX有限公司 北京XXXX公司
+ 其他
+ 未结题
+ 分配
+ 结题
+ 查看
+ 编辑
+ 开通
+ 删除公告
+
+
+ ZH-2026-658
+ 小牛血清创新应用研讨会
+ 26 16 10
+ 3,112,000 1,112,000 1,000,000 1,000,000
+ 5.0
+ 北京XXXX有限公司 北京XXXX公司
+ 线上
+ 未结题
+ 分配
+ 结题
+ 查看
+ 编辑
+ 开通
+ 删除公告
+
+
+ ZH-2026-658
+ 小牛血清创新应用研讨会
+ 26 16 10
+ 3,112,000 1,112,000 1,000,000 1,000,000
+ 3.5
+ 北京XXXX有限公司 北京XXXX公司
+ 线下
+ 已结题
+ 分配
+ 结题
+ 查看
+ 编辑
+ 开通
+ 删除公告
+
+
+
+
+ *可用金额=总金额*(1-管理费税费)-累计劳务-累计会务(总发票的金额) / *点击后可查看具体评价维度,评价标准与供应商系统保持一致
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/admin-project-plan-detail.html b/proto/html/components/admin-project-plan-detail.html
new file mode 100644
index 0000000..3aca53e
--- /dev/null
+++ b/proto/html/components/admin-project-plan-detail.html
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+ 项目计划详情 - 后台
+
+
+
+
+
+
+
+ 项目计划管理
+
+
+ 新建项目计划
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/admin-project-public.html b/proto/html/components/admin-project-public.html
new file mode 100644
index 0000000..ddb4b82
--- /dev/null
+++ b/proto/html/components/admin-project-public.html
@@ -0,0 +1,218 @@
+
+
+
+
+
+
+ 项目公示 - 后台
+
+
+
+
+
+
+
+ 项目公示
+
+
+
+
全部
+
邀请函
+
支持函
+
公告文件
+
+
+
+ 批量删除
+ 发布公示
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
类型: 邀请函 支持函 公告文件
+
公告文件:
+
发布时间:
+
标题名称:
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/admin-resource-manage.html b/proto/html/components/admin-resource-manage.html
new file mode 100644
index 0000000..6c2db8e
--- /dev/null
+++ b/proto/html/components/admin-resource-manage.html
@@ -0,0 +1,162 @@
+
+
+
+
+
+
+ 资料库管理 - 后台
+
+
+
+
+
+
+
+ 资料库管理
+
+
+
+
资料名称:
+
分类: 请选择 项目模板 会议材料 合规文档 专家库 培训资料 表单模板
+
上传人:
+
查找
+
+
+
+
+ 上传资料
+
+
+
+
+
+
+ 资料名称 分类 文件大小
+ 上传人 上传时间 状态 操作
+
+
+
+
+ 📄 项目策划模板 V2.0.docx
+ 项目模板
+ 2.3 MB
+ 张三 2026-07-15 10:30
+ 已发布
+ 下载 删除
+
+
+ 📄 会议材料模板 V1.5.docx
+ 会议材料
+ 1.8 MB
+ 李四 2026-07-12 14:20
+ 已发布
+ 下载 删除
+
+
+ 📄 合规审核要点手册.pdf
+ 合规文档
+ 5.6 MB
+ 王五 2026-07-08 09:15
+ 已发布
+ 下载 删除
+
+
+ 📄 专家评审标准 V3.0.pdf
+ 专家库
+ 3.2 MB
+ 赵六 2026-06-25 16:45
+ 已发布
+ 下载 删除
+
+
+ 📄 项目操作培训视频.mp4
+ 培训资料
+ 256 MB
+ 钱七 2026-06-15 11:00
+ 已发布
+ 下载 删除
+
+
+ 📄 劳务材料汇总表.xlsx
+ 表单模板
+ 0.5 MB
+ 孙八 2026-06-08 08:50
+ 已发布
+ 下载 删除
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/admin-role-manage.html b/proto/html/components/admin-role-manage.html
new file mode 100644
index 0000000..ff03528
--- /dev/null
+++ b/proto/html/components/admin-role-manage.html
@@ -0,0 +1,169 @@
+
+
+
+
+
+
+ 角色管理 - 后台
+
+
+
+
+
+
+
+ 角色管理
+
+
+
+
角色名称:
+
状态: 请选择 启用 禁用
+
查找
+
+
+
+
+ 新建角色
+
+
+
+
+
+
+ 角色名称 角色编码 描述
+ 权限数 状态 创建时间 操作
+
+
+
+
+ 后台管理员
+ admin
+ 系统超级管理员,拥有全部权限
+ 128
+ 启用
+ 2026-01-15 09:00
+ 权限配置 编辑 删除
+
+
+ 合规人员
+ compliance
+ 负责项目、会议、专家等合规审核
+ 45
+ 启用
+ 2026-01-15 09:00
+ 权限配置 编辑 删除
+
+
+ 项目负责人
+ project_leader
+ 负责项目的整体执行和会议管理
+ 28
+ 启用
+ 2026-01-15 09:00
+ 权限配置 编辑 删除
+
+
+ 执行方
+ executor
+ 负责项目的具体执行工作
+ 22
+ 启用
+ 2026-01-15 09:00
+ 权限配置 编辑 删除
+
+
+ 赞助方
+ sponsor
+ 提供资金支持,查看项目信息
+ 15
+ 启用
+ 2026-01-15 09:00
+ 权限配置 编辑 删除
+
+
+ 专家
+ expert
+ 项目设计投稿和会议参与
+ 18
+ 启用
+ 2026-01-15 09:00
+ 权限配置 编辑 删除
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/admin-service-manage.html b/proto/html/components/admin-service-manage.html
new file mode 100644
index 0000000..c618798
--- /dev/null
+++ b/proto/html/components/admin-service-manage.html
@@ -0,0 +1,179 @@
+
+
+
+
+
+
+ 服务机构管理 - 后台
+
+
+
+
+
+
+
+ 服务机构管理
+
+
+
+
+ 批量导入
+ 新建人员
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/admin-settings.html b/proto/html/components/admin-settings.html
new file mode 100644
index 0000000..655d3b7
--- /dev/null
+++ b/proto/html/components/admin-settings.html
@@ -0,0 +1,171 @@
+
+
+
+
+
+
+ 设置管理 - 后台
+
+
+
+
+
+
+
+ 设置管理
+
+
+
+
基本设置
+
安全设置
+
邮件设置
+
短信设置
+
通知设置
+
+
+
+
+
+
+
+
密码最小长度
+
会话超时(分钟)
+
登录失败锁定次数
+
+
保存设置
+
+
+
+
+
+
+
+
服务商 阿里云 腾讯云 华为云
+
AccessKey
+
短信签名
+
保存设置 发送测试短信
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/admin-user-manage.html b/proto/html/components/admin-user-manage.html
new file mode 100644
index 0000000..16c8759
--- /dev/null
+++ b/proto/html/components/admin-user-manage.html
@@ -0,0 +1,180 @@
+
+
+
+
+
+
+ 用户管理 - 后台
+
+
+
+
+
+
+
+ 用户管理
+
+
+
+
+
用户名:
+
姓名:
+
手机号:
+
角色: 请选择 合规人员 项目负责人 执行方 赞助方 专家 后台管理员
+
状态: 请选择 启用 禁用
+
查找
+
+
+
+
+
+ 批量重置密码
+ 新建用户
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/compliance-view-2.html b/proto/html/components/compliance-view-2.html
new file mode 100644
index 0000000..07f9e1b
--- /dev/null
+++ b/proto/html/components/compliance-view-2.html
@@ -0,0 +1,86 @@
+
+
+
+
+ 查看人员 v2
+
+
+
+
+
+ 查看人员
+
+
人员详情
+
姓名: 张三
+
手机号: 13534621147
+
工作单位: 北京XXXXXXX公司
+
部门: 华北大区
+
职务: 项目负责人
+
角色: 监察员
+
状态: 正常
+
+
+ 返回
+ 编辑
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/compliance-view.html b/proto/html/components/compliance-view.html
new file mode 100644
index 0000000..cc4db08
--- /dev/null
+++ b/proto/html/components/compliance-view.html
@@ -0,0 +1,86 @@
+
+
+
+
+ 查看人员
+
+
+
+
+
+ 查看人员
+
+
人员详情
+
姓名: 张三
+
手机号: 13534621147
+
工作单位: 北京XXXXXXX公司
+
部门: 华北大区
+
职务: 项目负责人
+
角色: 监察员
+
状态: 正常
+
+
+ 返回
+ 编辑
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/edit-meeting-labor.html b/proto/html/components/edit-meeting-labor.html
new file mode 100644
index 0000000..ccd8f8d
--- /dev/null
+++ b/proto/html/components/edit-meeting-labor.html
@@ -0,0 +1,79 @@
+
+
+
+
+ 编辑会议-劳务材料
+
+
+
+
+
+
首页
+
/
+
会议管理
+
/
+
编辑劳务材料
+
+ 编辑劳务材料
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/edit-meeting-materials.html b/proto/html/components/edit-meeting-materials.html
new file mode 100644
index 0000000..59da863
--- /dev/null
+++ b/proto/html/components/edit-meeting-materials.html
@@ -0,0 +1,79 @@
+
+
+
+
+ 编辑-会务材料
+
+
+
+
+
+
首页
+
/
+
会议管理
+
/
+
编辑会务材料
+
+ 编辑会务材料
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/edit-project-plan.html b/proto/html/components/edit-project-plan.html
new file mode 100644
index 0000000..b829c3f
--- /dev/null
+++ b/proto/html/components/edit-project-plan.html
@@ -0,0 +1,169 @@
+
+
+
+
+ 编辑项目策划方案
+
+
+
+
+
+ 编辑项目策划方案
+
+
基本信息
+
+
+ 策划方案名称*
+
+
+
+ 项目方向*
+
+ 请选择
+ 专项计划一:《规范化诊疗及医疗质量提升专项计划(2026-2030年)》
+ 专项计划二:《科研创新专项行动计划(2026-2030年)》
+
+
+
+ 项目类别*
+
+ 请选择
+ 会议项目
+ 科研项目
+ 学术项目
+ 指南
+ 共识
+ 对外交流
+
+
+
+ 项目形式*
+
+ 请选择
+ 线上
+ 线下
+ 线上+线下
+ 其他
+
+
+
+
+ 项目编号*
+
+
+
+ 备注
+
+
+
+
+ 状态
+ 待审核
+ (由审核流程决定,不可编辑)
+
+
+ 是否结算
+ 未结算
+ (由结算流程决定,不可编辑)
+
+
+ *策划方案名称 / 项目方向 / 项目类别 / 项目形式 / 设计文件 / 项目编号 均为必填项;重新上传文件后,请确认原文件版本已被归档
+
+
+ 保存
+ 取消
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/empty.html b/proto/html/components/empty.html
new file mode 100644
index 0000000..8565cef
--- /dev/null
+++ b/proto/html/components/empty.html
@@ -0,0 +1,59 @@
+
+
+
+
+
+ 开发中
+
+
+
+
+
+
🚧
+
开发中
+
该功能模块正在建设中,敬请期待
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/execution-intent.html b/proto/html/components/execution-intent.html
new file mode 100644
index 0000000..c7c7abb
--- /dev/null
+++ b/proto/html/components/execution-intent.html
@@ -0,0 +1,321 @@
+
+
+
+
+
+ 执行意向 - 项目管理系统
+
+
+
+
+
+
+
+
+
+
+
+
+ 意向项目名称:
+
+
+
+ 姓名:
+
+
+
+ 工作单位:
+
+
+
查找
+
导出
+
+
+
+
+
+ *项目公示中点击执行意向后,显示在此
+ *执行意向为在供应商系统已注册账号,并点击了执行申请的账号
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/execution-unit-view.html b/proto/html/components/execution-unit-view.html
new file mode 100644
index 0000000..7e104da
--- /dev/null
+++ b/proto/html/components/execution-unit-view.html
@@ -0,0 +1,136 @@
+
+
+
+
+
+
+ 执行单位查看
+
+
+
+
+
+
+
+
+
+ 单位查看
+
+
+
+
+
+
+
+
单位地址
+
北京市海淀区XXX路XXXX号
+
+
+
+
税号/统一社会信用代码
+
91330101MA2GPR961K
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 返回
+
+
+
+
+
+
diff --git a/proto/html/components/executor-units.html b/proto/html/components/executor-units.html
new file mode 100644
index 0000000..2153c23
--- /dev/null
+++ b/proto/html/components/executor-units.html
@@ -0,0 +1,375 @@
+
+
+
+
+
+
+ 执行单位管理
+
+
+
+
+
+
+
+
+
+
+
+ 单位名称:
+
+
+
+ 单位地址:
+
+
+
+ 税号/统一社会信用代码:
+
+
+
+
查找
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 单位名称
+ 单位地址
+ 税号/统一社会信用代码
+ 合作状态
+ 创建日期
+ 操作
+
+
+
+
+ 北京XXXXXXX公司
+ 北京市海淀区XXX路XXXX号
+ 91330101MA2GPR961K
+ 正常
+ 2026.05.22
+
+ 查看
+ 人员管理
+ 禁用
+
+
+
+ 北京XXXXXXX公司
+ 北京市海淀区XXX路XXXX号
+ 91330101MA2GPR961K
+ 正常
+ 2026.05.22
+
+ 查看
+ 人员管理
+ 禁用
+
+
+
+ 北京XXXXXXX公司
+ 北京市海淀区XXX路XXXX号
+ 91330101MA2GPR961K
+ 正常
+ 2026.05.22
+
+ 查看
+ 人员管理
+ 禁用
+
+
+
+ 北京XXXXXXX公司
+ 北京市海淀区XXX路XXXX号
+ 91330101MA2GPR961K
+ 正常
+ 2026.05.22
+
+ 查看
+ 人员管理
+ 禁用
+
+
+
+ 北京XXXXXXX公司
+ 北京市海淀区XXX路XXXX号
+ 91330101MA2GPR961K
+ 正常
+ 2026.05.22
+
+ 查看
+ 人员管理
+ 禁用
+
+
+
+ 北京XXXXXXX公司
+ 北京市海淀区XXX路XXXX号
+ 91330101MA2GPR961K
+ 已禁用
+ 2026.05.22
+
+ 查看
+ 启用
+
+
+
+ 北京XXXXXXX公司
+ 北京市海淀区XXX路XXXX号
+ 91330101MA2GPR961K
+ 正常
+ 2026.05.22
+
+ 查看
+ 人员管理
+ 禁用
+
+
+
+ 北京XXXXXXX公司
+ 北京市海淀区XXX路XXXX号
+ 91330101MA2GPR961K
+ 正常
+ 2026.05.22
+
+ 查看
+ 人员管理
+ 禁用
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/expert-review.html b/proto/html/components/expert-review.html
new file mode 100644
index 0000000..a3fdfaf
--- /dev/null
+++ b/proto/html/components/expert-review.html
@@ -0,0 +1,851 @@
+
+
+
+
+
+ 专家审核 - 项目管理系统
+
+
+
+
+
+
+
+
+
+
+
*新建和批量导入审核状态直接为审核通过
+
*退回后,如专家重新提交,则审核状态变为待审核
+
*审核通过后,进入专家库,管理后台可查看专家库
+
*禁用后则无法登录,提示您的账号已被禁用
+
+
+
+
+
筛选条件
+
+
+ 姓名:
+
+
+
+ 手机号:
+
+
+
+ 工作单位:
+
+
+
+ 审核状态:
+
+ 请选择
+ 待审核
+ 审核通过
+ 已退回
+
+
+
查找
+
+
+
+
+
+ + 新建专家
+ 批量审核
+ 批量导入
+ 批量导入执业证书/证明
+ 批量导入职称证明
+
+
+
+
+
全部
+
待审核 (50)
+
审核通过
+
已退回
+
+
+
+ *提示:需将证明文件名称修改为手机号进行导入
+
+
+
+
+
+
+
+
+
+
+
+
+ 选择文件
+
+ 上传
+
+
+
*批量导入模板xls与列表表项一致
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/home.html b/proto/html/components/home.html
new file mode 100644
index 0000000..97eeed8
--- /dev/null
+++ b/proto/html/components/home.html
@@ -0,0 +1,374 @@
+
+
+
+
+
+
+ 首页 - 项目管理系统
+
+
+
+
+
+
+
+
+
下午好,张三专家 👋
+
欢迎使用项目管理系统
+
+
+
+
+
+
+
+
+ 待参加的会议
+ 更多 →
+
+
+
+
+
📅
+
2024 年度临床医学研究项目专家评审会议
+
+ 09:00
+
+
+
+ 明天
+
+
+
+ 08-12
+
+
+
+ 08-18
+
+
+
+
+
+ 待签署的协议
+ 更多 →
+
+
+
+
+ 待签署
+
+
+
+ 待签署
+
+
+
+
📄
+
《基层卫生服务能力提升方案》保密协议
+
+ 已完成
+
+
+
+
+
+
+
+
+ 消息通知
+ 更多 →
+
+
+
+
+
+
系统通知: 您有新的会议邀请
+
2024 年度临床医学研究项目专家评审会议邀请已发出,请确认出席。
+
+ 2 小时前
+
+
+
+
+
审核结果: 投稿方案已通过初审
+
您提交的《基层卫生服务能力提升方案》已通过初审,请等待终审。
+
+ 昨天 16:30
+
+
+
+
+
项目动态: 新阶段开启
+
您参与的"基层医疗改革试点项目"已进入实施阶段,请关注后续任务安排。
+
+ 2026-08-01
+
+
+
+
+
系统升级公告
+
系统将于本周日 02:00 - 04:00 进行升级维护,请提前安排工作。
+
+ 2026-07-30
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/labor-voucher.html b/proto/html/components/labor-voucher.html
new file mode 100644
index 0000000..87b812f
--- /dev/null
+++ b/proto/html/components/labor-voucher.html
@@ -0,0 +1,78 @@
+
+
+
+
+ 劳务凭证
+
+
+
+
+
+ 劳务凭证
+
+
+
会议名称:
+
专家姓名:
+
审核状态:
+
+ 请选择
+ 待审核
+ 已审核
+ 已驳回
+
+
+
查找
+
+
+
+ 批量审核
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/leader-home.html b/proto/html/components/leader-home.html
new file mode 100644
index 0000000..7fb991f
--- /dev/null
+++ b/proto/html/components/leader-home.html
@@ -0,0 +1,125 @@
+
+
+
+
+
+
+ 首页 - 项目负责人
+
+
+
+
+ 首页
+
+
+
+
+
+
+
+
+
+
+
+
项目审核结果通知
ZH-2026-658 项目的合规审核已通过,可以进入执行阶段。
1小时前
+
执行单位反馈
北京XXXX公司 已确认承接 3 个项目的执行工作,请及时跟进。
3小时前
+
会议材料待提交
有 2 个会议的劳务材料尚未提交,请尽快上传。
昨天
+
月度项目进度
2026 年 7 月项目进度报告已生成,可前往下载。
2026-08-01
+
系统升级公告
系统将于本周日 02:00-04:00 进行升级维护。
2026-07-28
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/leader-projects.html b/proto/html/components/leader-projects.html
new file mode 100644
index 0000000..2989e48
--- /dev/null
+++ b/proto/html/components/leader-projects.html
@@ -0,0 +1,221 @@
+
+
+
+
+
+
+ 项目列表 - 项目负责人
+
+
+
+
+
+
+
+ 项目列表
+
+
+
+
+
项目编号:
+
项目名称:
+
+ 项目形式:
+
+ 请选择 线上 线下 线上+线下 其他
+
+
+
+ 是否结题:
+ 请选择 已结题 未结题
+
+
+ 是否结算:
+ 请选择 已结算 未结算
+
+
查找
+
+
*支持多个支持单位筛选 / *支持多个服务机构筛选
+
+
+
+
+
+
+
+ 项目编号 项目名称 总场次/总期数
+ 已执行 未执行
+ 总金额 可用金额 已支付劳务费 已支付会务费
+ 执行单位得分 支持单位 服务机构
+ 项目形式 当前阶段 是否结题
+ 执行单位得分(合规) 执行单位评价(支持方)
+ 操作
+
+
+
+
+ ZH-2026-658
+ 小牛血清创新应用研讨会
+ 26 16 10
+ 3,112,000 1,112,000 1,000,000 1,000,000
+ 5.0
+ 北京XXXX有限公司 北京XXXX公司
+ 线上
+ 执行中
+ 未结题
+ 5.0
+ 查看
+ 查看
+
+
+ ZH-2026-658
+ 小牛血清创新应用研讨会
+ 26 16 10
+ 3,112,000 1,112,000 1,000,000 1,000,000
+ 3.5
+ 北京XXXX有限公司 北京XXXX公司
+ 线下
+ 执行中
+ 未结题
+ —
+ 查看
+ 查看
+
+
+ ZH-2026-658
+ 小牛血清创新应用研讨会
+ 26 16 10
+ 3,112,000 1,112,000 1,000,000 1,000,000
+ 4.5
+ 北京XXXX有限公司 北京XXXX公司
+ 线上+线下
+ 已结题
+ 已结题
+ —
+ 查看
+ 查看
+
+
+ ZH-2026-658
+ 小牛血清创新应用研讨会
+ 26 16 10
+ 3,112,000 1,112,000 1,000,000 1,000,000
+ 3.0
+ 北京XXXX有限公司 北京XXXX公司
+ 其他
+ 筹备中
+ 未结题
+ —
+ 查看
+ 查看
+
+
+ ZH-2026-658
+ 小牛血清创新应用研讨会
+ 26 16 10
+ 3,112,000 1,112,000 1,000,000 1,000,000
+ —
+ 北京XXXX有限公司 北京XXXX公司
+ 线上
+ 执行中
+ 未结题
+ —
+ —
+ 查看
+
+
+ ZH-2026-658
+ 小牛血清创新应用研讨会
+ 26 16 10
+ 3,112,000 1,112,000 1,000,000 1,000,000
+ 3.5
+ 北京XXXX有限公司 北京XXXX公司
+ 线下
+ 已结题
+ 已结题
+ —
+ 查看
+ 查看
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/meeting-detail-executor.html b/proto/html/components/meeting-detail-executor.html
new file mode 100644
index 0000000..8f79026
--- /dev/null
+++ b/proto/html/components/meeting-detail-executor.html
@@ -0,0 +1,225 @@
+
+
+
+
+
+
+ 会议详情 - 项目管理系统
+
+
+
+
+
+
+
+ 会议详情
+
+
+
+
+
+
+
会议基本信息
+
+
项目编号: ZH-2026-658
+
会议名称: 小牛血清创新应用研讨会
+
项目名称: 小牛血清创新应用研讨会
+
期数: 3/26
+
总场次/总期数: 26
+
会议开始时间: 2026.05.13 11:30
+
支持单位: 北京XXXX有限公司
+
会议结束时间: 2026.05.15 11:30
+
创建时间: 2026.05.11 11:30
+
创建人员: 张三
+
+
+
+
+
材料管理
+
+ 会务材料
+ 劳务材料
+ 劳务凭证
+ 会务凭证
+
+
+
+
+
+
+
*结算后,已完结状态,执行方不能再进行编辑
+
+
+
+
+
+
审核时间轴
+
+
+
执行方提交材料
+
已提交 · 2026.05.15 11:30
+
+
+
会议已执行
+
2026.05.25 10:30
+
+
+
合规审核
+
已通过 · 材料完整 · 2026.05.30 14:30
+
+
+
监察意见
+
通过 · 材料完整 · 2026.06.03 15:30
+
+
+
+
+
+
+
+ 返回
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/meeting-detail-page-1.html b/proto/html/components/meeting-detail-page-1.html
new file mode 100644
index 0000000..70fd277
--- /dev/null
+++ b/proto/html/components/meeting-detail-page-1.html
@@ -0,0 +1,300 @@
+
+
+
+
+
+ 会议详情页 v1 (合规)
+
+
+
+
+
+
+
+
+
+
+ 会议基本信息
+
+
+
+
+
+ 项目编号:
+ ZH-2026-658
+
+
+ 会议名称:
+ 小牛血清创新应用研讨会
+
+
+ 项目名称:
+ 小牛血清创新应用研讨会
+
+
+ 期数:
+ 第 3 期
+
+
+ 总场次/总期数:
+ 26
+
+
+ 会议开始时间:
+ 2026.05.13 11:30
+
+
+ 支持单位:
+ 北京XXXX有限公司
+
+
+ 会议结束时间:
+ 2026.05.15 11:30
+
+
+ 创建时间:
+ 2026.05.11 11:30
+
+
+ 创建人员:
+ 张三
+
+
+
+
+
+ *点击缩略图可查看原图和下载
+
+
+
+
邀请函
+
+
+ 📄
+ 邀请函
+
+
+ 📄
+ 邀请函
+
+
+
+
+
+
+
+
会议日程
+
+
+ 📅
+ 会议日程
+
+
+ 📅
+ 会议日程
+
+
+
+
+
+
+
+ 返回
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/meeting-detail-page.html b/proto/html/components/meeting-detail-page.html
new file mode 100644
index 0000000..447dff3
--- /dev/null
+++ b/proto/html/components/meeting-detail-page.html
@@ -0,0 +1,300 @@
+
+
+
+
+
+ 会议详情页 (合规)
+
+
+
+
+
+
+
+
+
+
+ 会议基本信息
+
+
+
+
+
+ 项目编号:
+ ZH-2026-658
+
+
+ 会议名称:
+ 小牛血清创新应用研讨会
+
+
+ 项目名称:
+ 小牛血清创新应用研讨会
+
+
+ 期数:
+ 第 3 期
+
+
+ 总场次/总期数:
+ 26
+
+
+ 会议开始时间:
+ 2026.05.13 11:30
+
+
+ 支持单位:
+ 北京XXXX有限公司
+
+
+ 会议结束时间:
+ 2026.05.15 11:30
+
+
+ 创建时间:
+ 2026.05.11 11:30
+
+
+ 创建人员:
+ 张三
+
+
+
+
+
+ *点击缩略图可查看原图和下载
+
+
+
+
邀请函
+
+
+ 📄
+ 邀请函
+
+
+ 📄
+ 邀请函
+
+
+
+
+
+
+
+
会议日程
+
+
+ 📅
+ 会议日程
+
+
+ 📅
+ 会议日程
+
+
+
+
+
+
+
+ 返回
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/meeting-detail.html b/proto/html/components/meeting-detail.html
new file mode 100644
index 0000000..c2d54e9
--- /dev/null
+++ b/proto/html/components/meeting-detail.html
@@ -0,0 +1,300 @@
+
+
+
+
+
+ 会议详情
+
+
+
+
+
+
+
+
+
+
+ 会议基本信息
+
+
+
+
+
+ 项目编号:
+ ZH-2026-658
+
+
+ 会议名称:
+ 小牛血清创新应用研讨会
+
+
+ 项目名称:
+ 小牛血清创新应用研讨会
+
+
+ 期数:
+ 第 3 期
+
+
+ 总场次/总期数:
+ 26
+
+
+ 会议开始时间:
+ 2026.05.13 11:30
+
+
+ 支持单位:
+ 北京XXXX有限公司
+
+
+ 会议结束时间:
+ 2026.05.15 11:30
+
+
+ 创建时间:
+ 2026.05.11 11:30
+
+
+ 创建人员:
+ 张三
+
+
+
+
+
+ *点击缩略图可查看原图和下载
+
+
+
+
邀请函
+
+
+ 📄
+ 邀请函
+
+
+ 📄
+ 邀请函
+
+
+
+
+
+
+
+
会议日程
+
+
+ 📅
+ 会议日程
+
+
+ 📅
+ 会议日程
+
+
+
+
+
+
+
+ 返回
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/meeting-manage-1.html b/proto/html/components/meeting-manage-1.html
new file mode 100644
index 0000000..2685d6b
--- /dev/null
+++ b/proto/html/components/meeting-manage-1.html
@@ -0,0 +1,575 @@
+
+
+
+
+
+ 会议管理 - 项目管理系统
+
+
+
+
+
+
+
+ 会议管理
+
+
+
+
+
+ 项目编号:
+
+
+
+ 会议名称:
+
+
+
+ 备注:
+
+
+
+ 会议时间:
+
+
+
+
+ 项目形式:
+
+ 请选择
+ 线上
+ 线下
+ 线上+线下
+ 其他
+
+
+
+ 查找
+ 重置
+
+
+
+
+
+
+
+
+
+
+
+
*执行方只能在项目列表中进行建会
+
*执行方的当前阶段跟支持方基本一致
+
*提交审核后,在OA新建流程时,才能选择该场会,合规人员才能看到,是否为待审核状态时,OA才能看到该场会议
+
*点击复制后,则跳转到新建会议并将会议基本信息自动带入
+
*点击总期数,可以筛选出该系列会的所有会议
+
*提交后,返回提交成功的提示,三秒消失
+
*统一状态(当前阶段): 未执行=会议开始时间前; 执行中=会议开始时间后执行方未提交材料; 待审核=执行方提交材料后合规审核; 待结算=支持方审核通过后; 已完结=合规人员点击结算后; 冻结中=会议结束后未按时提交
+
*冻结中时,提交按钮置灰,无法点击
+
*增加最后期限,到期前24小时,每4小时,给执行方发送短信催促一次
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/meeting-manage.html b/proto/html/components/meeting-manage.html
new file mode 100644
index 0000000..908348e
--- /dev/null
+++ b/proto/html/components/meeting-manage.html
@@ -0,0 +1,618 @@
+
+
+
+
+
+ 会议管理 - 项目管理系统
+
+
+
+
+
+
+
+ 会议管理
+
+
+
+
+
+
+ 项目形式:
+
+ 请选择
+ 线上
+ 线下
+ 线上+线下
+ 其他
+
+
+
+ 当前阶段:
+
+ 请选择
+ 未执行
+ 执行中
+ 待审核
+ 待结算
+ 已完结
+ 冻结中
+
+
+
+ 备注:
+
+
+
+ 查找
+ 批量提交
+
+
+
+
+
+
+
+
+
+
*执行方只能在项目列表中进行建会
+
*执行方的当前阶段跟支持方基本一致
+
*提交审核后,在OA新建流程时,才能选择该场会,合规人员才能看到,是否为待审核状态时,OA才能看到该场会议
+
*点击复制后,则跳转到新建会议并将会议基本信息自动带入
+
*点击总期数,可以筛选出该系列会的所有会议
+
*提交后,返回提交成功的提示,三秒消失
+
*统一状态(当前阶段): 未执行=会议开始时间前; 执行中=会议开始时间后执行方未提交材料; 待审核=执行方提交材料后合规审核; 待结算=支持方审核通过后; 已完结=合规人员点击结算后; 冻结中=会议结束后未按时提交
+
*冻结中时,提交按钮置灰,无法点击
+
*增加最后期限,到期前24小时,每4小时,给执行方发送短信催促一次
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/meetings.html b/proto/html/components/meetings.html
new file mode 100644
index 0000000..d8beb3e
--- /dev/null
+++ b/proto/html/components/meetings.html
@@ -0,0 +1,546 @@
+
+
+
+
+
+ 我参与的会议
+
+
+
+
+
+
+
+
+
+
+
+
+
+
筛选条件
+
+
+ 项目编号:
+
+
+
+ 会议名称:
+
+
+
+ 当前阶段:
+
+ 请选择
+ 未开始
+ 已结束
+
+
+
+ 签署状态:
+
+ 请选择
+ 已签署
+ 未签署
+
+
+
查找
+
+
+
+
+ *邀请函根据执行方上传的邀请函模板和专家列表进行生成并显示到专家的会议列表中
+
+
+
+
+
+
+
*未签署时显示「签署劳务」,已签署后显示「查看劳务」
+
*在会议编辑中,导入专家信息,并点击推送电子签后,专家才可以查看到签署按钮
+
*点击签署劳务跳转到电子签
+
*签署劳务协议时,先验证是否有执业证书、职称证明、身份证照片,如果没有,必须先上传
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/messages.html b/proto/html/components/messages.html
new file mode 100644
index 0000000..a1b9415
--- /dev/null
+++ b/proto/html/components/messages.html
@@ -0,0 +1,431 @@
+
+
+
+
+
+ 消息通知
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2024 年度临床医学研究项目专家评审会议邀请已发出,时间:2026-08-05 09:00,请准时参加。会议链接将通过短信发送。
+
+
+
+
+
+
+
+
+
+
+ 您提交的《基层卫生服务能力提升方案》已通过初审,请等待终审结果。如需修改请在终审前完成。
+
+
+
+
+
+
+
+
+
+
+ 您参与的"基层医疗改革试点项目"已进入实施阶段,请关注后续任务安排。
+
+
+
+
+
+
+
+
+
+
+ 系统将于本周日 02:00 - 04:00 进行升级维护,请提前安排工作。升级期间可能无法访问。
+
+
+
+
+
+
+
+
+
+
+ 您报名的"智慧医院建设项目方案论证会"将于 2026-08-12 14:00 举行,请提前查看会议材料并准备发言。
+
+
+
+
+
+
+
+
+
+
+ 您提交的《远程医疗会诊系统方案》需要补充执行细节,已退回。请修改后重新提交。
+
+
+
+
+
+
+
+
+
+
+ 您的账号在异地登录,如非本人操作请及时修改密码。建议定期更换登录密码以保障账号安全。
+
+
+
+
+
+
+
+
+
+
+ 您的劳务协议已签署完成,可前往"我参与的会议"或"我的项目设计投稿"查看详情。
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/my-activities.html b/proto/html/components/my-activities.html
new file mode 100644
index 0000000..395fd37
--- /dev/null
+++ b/proto/html/components/my-activities.html
@@ -0,0 +1,413 @@
+
+
+
+
+
+ 我的执会
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 项目编号:
+
+
+
+ 会议名称:
+
+
+
+ 是否结题:
+
+ 请选择
+ 已结题
+ 未结题
+
+
+
+ 是否系列会:
+
+ 请选择
+ 是
+ 否
+
+
+
查找
+
+
+
+
+
+
+
+
已选 0 项
+
+ 批量复制
+ 批量执会
+ 批量推流码
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/my-registrations.html b/proto/html/components/my-registrations.html
new file mode 100644
index 0000000..3d4bb23
--- /dev/null
+++ b/proto/html/components/my-registrations.html
@@ -0,0 +1,317 @@
+
+
+
+
+
+ 我报名的项目
+
+
+
+
+
+
+
+
+
+ 我报名的项目
+ 查看您已报名的项目,跟踪项目状态
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/new-edit.html b/proto/html/components/new-edit.html
new file mode 100644
index 0000000..ad7991d
--- /dev/null
+++ b/proto/html/components/new-edit.html
@@ -0,0 +1,88 @@
+
+
+
+
+ 新建/编辑
+
+
+
+
+
+ 新建人员
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/new-expert.html b/proto/html/components/new-expert.html
new file mode 100644
index 0000000..ad34ec5
--- /dev/null
+++ b/proto/html/components/new-expert.html
@@ -0,0 +1,137 @@
+
+
+
+
+ 新建专家
+
+
+
+
+
+ 新建专家
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/new-meeting.html b/proto/html/components/new-meeting.html
new file mode 100644
index 0000000..17ceb6f
--- /dev/null
+++ b/proto/html/components/new-meeting.html
@@ -0,0 +1,248 @@
+
+
+
+
+
+
+ 新建会议 - 项目管理系统
+
+
+
+
+
+
+
+
+
+ 新建会议
+
+
+ *会议名称默认为项目名称,不可修改
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/new-person-2.html b/proto/html/components/new-person-2.html
new file mode 100644
index 0000000..4c0f52e
--- /dev/null
+++ b/proto/html/components/new-person-2.html
@@ -0,0 +1,118 @@
+
+
+
+
+ 新建人员 (合规) v2
+
+
+
+
+
+ 新建人员
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/new-person.html b/proto/html/components/new-person.html
new file mode 100644
index 0000000..5d8731c
--- /dev/null
+++ b/proto/html/components/new-person.html
@@ -0,0 +1,380 @@
+
+
+
+
+
+ 新建人员 - 项目管理系统
+
+
+
+
+
+
+
+
+
+
+ 新建人员
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/new-project.html b/proto/html/components/new-project.html
new file mode 100644
index 0000000..fbfc5c5
--- /dev/null
+++ b/proto/html/components/new-project.html
@@ -0,0 +1,645 @@
+
+
+
+
+
+ 新建项目 - 项目管理系统
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 同步数据
+
+
+
+
+
项目信息
+
+
+
+
+
+ * 项目负责人
+
+ 请选择
+ 张三
+ 李四
+
+
+
+ * 项目形式
+
+ 请选择
+ 线上
+ 线下
+ 线上+线下
+ 其他
+
+
+
+
+
+
+
+
+
+
+ * 是否招标项目
+
+ 请选择
+ 是
+ 否
+
+
+
+
+
+
+
+
角色劳务设置
+
+
+
*角色劳务设置针对该项目所有会议生效,
+
专家劳务明细当会议劳务金额超过角色劳务设置时,
+
该劳务金额为税后金额,则系统进行提示:该角色劳务金额已超
+
+
+
+
+
+ 增加角色
+ 删除角色
+
+
+
*当选择其他时,需手动填写角色名称,显示填写框
+
+
+
+
+
公告文件
+
+
+
+
*名称规则:公告文件类型+取项目编号的后两段+项目名称
+
+
+
+
+ 保存
+ 保存并发布公告
+ 取消
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/new-submission.html b/proto/html/components/new-submission.html
new file mode 100644
index 0000000..451a2f3
--- /dev/null
+++ b/proto/html/components/new-submission.html
@@ -0,0 +1,376 @@
+
+
+
+
+
+ 新建项目设计投稿
+
+
+
+
+
+
+
+
+
+
+ 新建项目设计投稿
+
+
+
+
*项目规划后台可配置,合规/战略/学术进行配置,待定
+
+
+
+
+
+
+
+
+ * 项目方向
+
+
+ 请选择
+ 专项计划一:《规范化诊疗及医疗质量提升专项计划(2026-2030年)》
+ 专项计划二:《科研创新专项行动计划(2026-2030年)》
+
+
+
+
+
+
+ * 策划方案名称
+
+
+
+
+
+
+
+ * 项目形式
+
+
+ 请选择
+ 线上
+ 线下
+ 线上+线下
+ 其他
+
+
+
+
+
+
+ * 项目类别
+
+
+ 请选择
+ 学术会议类
+ 专项科研类
+ 调研征集类
+ 慈善帮扶类
+ 标准制定类
+ 患者援助类
+ 专业培训类
+
+
+
+
+
+
+
+
+
+
+
+
+ *除备注外,其他均为必填项
+
+
+
+ 保存
+ 取消
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/overview.html b/proto/html/components/overview.html
new file mode 100644
index 0000000..855152c
--- /dev/null
+++ b/proto/html/components/overview.html
@@ -0,0 +1,293 @@
+
+
+
+
+
+
+ 首页 - 项目管理系统
+
+
+
+
+
+
+
+
+
+
+
+ *点击数字,跳转到相应的列表页
+
+
+
+
+ 消息通知
+ 更多 →
+
+
+
+
+
+
结算审核: ZH-2026-650 结算已通过
+
整合医学学会项目评审会结算单已通过财务审核,请查收。
+
+ 2 小时前
+
+
+
+
+
会议邀请: 您有一场新会议待确认
+
数字化医疗转型方案评审会邀请您担任评审专家,请确认出席。
+
+ 昨天 16:30
+
+
+
+
+
项目阶段: 智慧医院建设项目进入实施阶段
+
您执行的智慧医院建设项目方案已通过,进入实施阶段,请关注后续任务安排。
+
+ 2026-08-01
+
+
+
+
+
系统升级公告
+
系统将于本周日 02:00 - 04:00 进行升级维护,请提前安排工作。
+
+ 2026-07-30
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/people-1-1.html b/proto/html/components/people-1-1.html
new file mode 100644
index 0000000..60146de
--- /dev/null
+++ b/proto/html/components/people-1-1.html
@@ -0,0 +1,74 @@
+
+
+
+
+ 人员管理 v1.1 - 合规
+
+
+
+
+ 人员管理 (合规)
+
+
+
姓名:
+
手机号:
+
角色:
+
+ 请选择
+ 项目负责人
+ 会议执行
+ 监察员
+
+
+
查找
+
+
+
+ 新建人员
+ 批量导入
+ *新建人员时,管理员可指定角色:项目负责人 / 会议执行 / 监察员
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/people-1-2.html b/proto/html/components/people-1-2.html
new file mode 100644
index 0000000..709a598
--- /dev/null
+++ b/proto/html/components/people-1-2.html
@@ -0,0 +1,74 @@
+
+
+
+
+ 人员管理 v1.1 - 合规
+
+
+
+
+ 人员管理 v1.2 (合规)
+
+
+
姓名:
+
手机号:
+
角色:
+
+ 请选择
+ 项目负责人
+ 会议执行
+ 监察员
+
+
+
查找
+
+
+
+ 新建人员
+ 批量导入
+ *新建人员时,管理员可指定角色:项目负责人 / 会议执行 / 监察员
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/people.html b/proto/html/components/people.html
new file mode 100644
index 0000000..92f95a9
--- /dev/null
+++ b/proto/html/components/people.html
@@ -0,0 +1,434 @@
+
+
+
+
+
+
+ 人员管理 - 项目管理系统
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 新建人员
+ 批量导入
+
+
+
+
+
*角色:执行方管理员新建人员时,默认只有会议执行的角色
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/project-assign-1.html b/proto/html/components/project-assign-1.html
new file mode 100644
index 0000000..cb04f0f
--- /dev/null
+++ b/proto/html/components/project-assign-1.html
@@ -0,0 +1,602 @@
+
+
+
+
+
+ 项目分配 v1 - 项目管理系统
+
+
+
+
+
+
+
+
+
+
+
+
+
+
项目信息
+
+
+
+ 项目编号:
+ ZH-2026-658
+
+
+ 项目名称:
+ 小牛血清创新应用研讨会
+
+
+ 项目形式:
+ 线上
+
+
+ 总场次/总期数:
+ 26
+
+
+ 总金额:
+ 3,112,000
+
+
+ 管理费及税金:
+ 1,112,000
+
+
+
+
+
+
+
+ * 支持单位
+
+
+
*支持单位只有一个,支持模糊查找,选择项
+
+
+
+
+
+ * 执行单位
+
+
+
+
+
+
1.
+
+ 请选择执行单位
+ 北京XXXX公司
+ 上海XXXX公司
+
+
+ 场数:
+
+ 总金额:
+
+
+
+ 增加
+ 删除
+
+
+
+
+
2.
+
+ 请选择执行单位
+ 北京XXXX公司
+ 上海XXXX公司
+
+
+ 场数:
+
+ 总金额:
+
+
+
+ 增加
+ 删除
+
+
+
+
+
3.
+
+ 请选择执行单位
+ 北京XXXX公司
+ 上海XXXX公司
+
+
+ 场数:
+
+ 总金额:
+
+
+
+ 增加
+ 删除
+
+
+
+
+
+ 增加执行方
+
+
+ *支持多个执行方,给每个执行方分配场次和总金额;
+ 提交时验证多个执行方的总金额加起来是否超过项目总金额;
+ 执行方总金额显示在执行方的项目列表中对应项目的总金额
+
+
+
+ *如未选择执行单位,则场次和总金额为非必填项,如选择了执行单位,则为必填项
+ *可用金额=总金额×(1-管理费税费)-累计劳务-累计会务(总发票的金额)
+ *项目列表中的为该项目的总数,执行方项目列表中显示的为该执行方的总金额,计算公式保持一致
+ *选择后,该项目则出现在支持单位管理员的项目列表中
+
+
+
+
+
+
+ 提交材料截止时间
+
+ 天
+
+
*按照会议截止时间,自然日,往后推对应的天数。如果提交后,被退回了,则时间重新开始计算。
+
*天数最大不能超过100,超过后报错提示
+
*每天0点取一次,合同可能会有多个,显示多个
+
+ 合同文件2
+
+
+
+
+
+
+
*根据项目编号,同步OA的合同文件,可预览
+
+
+
+
+ 保存
+ 取消
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/project-assign.html b/proto/html/components/project-assign.html
new file mode 100644
index 0000000..7c33b86
--- /dev/null
+++ b/proto/html/components/project-assign.html
@@ -0,0 +1,663 @@
+
+
+
+
+
+ 项目分配 - 项目管理系统
+
+
+
+
+
+
+
+
+
+
+
+
+
+
项目信息
+
+
+
+ 项目编号:
+ ZH-2026-658
+
+
+ 项目名称:
+ 小牛血清创新应用研讨会
+
+
+ 项目形式:
+ 线上
+
+
+ 总场次/总期数:
+ 26
+
+
+ 总金额:
+ 3,112,000
+
+
+ 管理费及税金:
+ 1,112,000
+
+
+
+
+
+
+
+ * 支持单位
+
+
+
*支持单位只有一个,支持模糊查找,选择项
+
+
+
+
+
+ * 执行单位
+
+
+
+
+
+
1.
+
+ 请选择执行单位
+ 北京XXXX公司
+ 上海XXXX公司
+
+
+ 场数:
+
+ 总金额:
+
+
+
+ 增加
+ 删除
+
+
+
+
+
2.
+
+ 请选择执行单位
+ 北京XXXX公司
+ 上海XXXX公司
+
+
+ 场数:
+
+ 总金额:
+
+
+
+ 增加
+ 删除
+
+
+
+
+
3.
+
+ 请选择执行单位
+ 北京XXXX公司
+ 上海XXXX公司
+
+
+ 场数:
+
+ 总金额:
+
+
+
+ 增加
+ 删除
+
+
+
+
+
+ 增加执行方
+
+
+ *支持多个执行方,给每个执行方分配场次和总金额;
+ 提交时验证多个执行方的总金额加起来是否超过项目总金额;
+ 执行方总金额显示在执行方的项目列表中对应项目的总金额
+
+
+
+ *如未选择执行单位,则场次和总金额为非必填项,如选择了执行单位,则为必填项
+ *可用金额=总金额×(1-管理费税费)-累计劳务-累计会务(总发票的金额)
+ *项目列表中的为该项目的总数,执行方项目列表中显示的为该执行方的总金额,计算公式保持一致
+ *选择后,该项目则出现在支持单位管理员的项目列表中
+
+
+
+
+
+
+ 提交材料截止时间
+
+ 天
+
+
*按照会议截止时间,自然日,往后推对应的天数。如果提交后,被退回了,则时间重新开始计算。
+
*天数最大不能超过100,超过后报错提示
+
*每天0点取一次,合同可能会有多个,显示多个
+
+ 合同文件2
+
+
+
+
+
+
+
*根据项目编号,同步OA的合同文件,可预览
+
+
+
+
+ 保存
+ 取消
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/project-detail-compliance.html b/proto/html/components/project-detail-compliance.html
new file mode 100644
index 0000000..d369220
--- /dev/null
+++ b/proto/html/components/project-detail-compliance.html
@@ -0,0 +1,238 @@
+
+
+
+
+ 项目详情
+
+
+
+
+
+ 项目详情
+
+
+
+
项目信息
+
+
项目编号:
+
项目名称:
+
总场次/总期数:
+
总金额:
+
管理费及税金:
+
支持单位:
+
服务机构:
+
项目形式:
+
+
+
*点击后可查看具体评价维度,评价标准与供应商系统保持一致
+
+
+
+
+
支持单位监督员
+
+
增加
+
*增加只显示已点支持意向的
+
+
+
+
+
角色劳务设置
+
+ 角色 劳务金额
+
+ 主席 5,000
+ 主持 3,000
+
+
+
+
+
+
+
+ *项目详情可修改,只有创建人可修改
+
+
+ 返回
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/project-detail-executor.html b/proto/html/components/project-detail-executor.html
new file mode 100644
index 0000000..50263b9
--- /dev/null
+++ b/proto/html/components/project-detail-executor.html
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+ 项目详情 - 项目管理系统
+
+
+
+
+
+
+
+ 项目详情
+
+
+
+
项目基本信息
+
+
项目编号: ZH-2026-658
+
项目形式: 线上
+
项目名称: 小牛血清创新应用研讨会
+
支持单位: 北京XXXX有限公司
+
总场次/总期数: 26
+
服务机构: 北京XXXX公司
+
总金额: 3,112,000
+
项目开始时间: 2026.05.11
+
管理费及税金: 1,112,000
+
项目结束时间: 2026.06.30
+
+
+
+
+
+
项目评价
+
+
*点击后可查看具体评价维度,评价标准与供应商系统保持一致
+
+
+
+
+
角色劳务设置
+
+
+ 角色 劳务金额 操作
+
+
+ 主席 5000 查看 下载
+ 主持 3000 查看 下载
+
+
+
+
+
+
+
+
+
+ 返回
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/project-detail.html b/proto/html/components/project-detail.html
new file mode 100644
index 0000000..baa663e
--- /dev/null
+++ b/proto/html/components/project-detail.html
@@ -0,0 +1,219 @@
+
+
+
+
+
+ 项目详情 - 项目管理系统
+
+
+
+
+
+
+
+
+
+
+ 项目详情
+
+
+
+
+
+ 项目编号:
+ ZH-2026-658
+
+
+ 项目名称:
+ 小牛血清创新应用研讨会
+
+
+ 会议名称:
+ 小牛血清创新应用研讨会
+
+
+ 项目形式:
+ 线上
+
+
+ 状态:
+ 已报名
+
+
+
+
+
+
+
+
+
+ 返回
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/project-manage.html b/proto/html/components/project-manage.html
new file mode 100644
index 0000000..2c20163
--- /dev/null
+++ b/proto/html/components/project-manage.html
@@ -0,0 +1,676 @@
+
+
+
+
+ 项目管理
+
+
+
+
+
+
+
+
+
支持单位:
+
服务机构:
+
项目形式:
+ 请选择 线上 线下 线上+线下 其他
+
+
项目编号:
+
+
+
项目名称:
+
+
是否结题:
+ 请选择 已结题 未结题
+
+
评价得分:
+
+
+ 查找
+ 重置
+ 导出
+ 项目评价导出
+ 已报名专家信息导出
+
+
+
+ *项目分配给执行方,执行方管理员只能看到已分配的项目
+ *支持多个支持单位筛选
+ *支持按查询条件进行项目评价导出
+ *点击后可查看具体评价维度,评价标准与供应商系统保持一致
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 项目编号 项目名称
+ 总场次/总期数
+ 已执行 未执行
+ 总金额 可用金额
+ 已支付劳务费 已支付会务费
+ 执行单位得分(合规)
+ 执行单位评价(支持方)
+ 支持单位 服务机构
+ 项目形式
+ 是否结题
+ 项目开始时间 项目结束时间
+ 操作
+
+
+
+
+
+ ZH-2026-658
+ 小牛血清创新应用研讨会
+ 26
+ 16
+ 10
+ 3,112,000
+ 1,112,000
+ 1,000,000
+ 1,000,000
+ 5.0
+ -
+ 北京XXXX有限公司 北京XXXX公司
+ 线上
+ 未结题
+ 2026-05-11 2026-06.30
+
+ 建会
+ 分配
+ 结题
+ 查看
+ 编辑
+ 开通
+ 删除公告
+ 执行单位评分
+
+
+
+
+ ZH-2026-659
+ 整合医学学会项目评审
+ 18
+ 12
+ 6
+ 2,500,000
+ 980,000
+ 900,000
+ 620,000
+ 4.5
+ 3.5
+ 北京XXXX有限公司 北京XXXX公司
+ 线下
+ 未结题
+ 2026-05-11 2026-06.30
+
+ 建会
+ 分配
+ 结题
+ 查看
+ 编辑
+ 开通
+ 删除公告
+ 执行单位评分
+
+
+
+
+ ZH-2026-650
+ 智慧医院建设项目
+ 12
+ 7
+ 5
+ 1,800,000
+ 760,000
+ 700,000
+ 340,000
+ 4.0
+ 4.5
+ 北京XXXX有限公司 北京XXXX公司
+ 线上+线下
+ 未结题
+ 2026-05-11 2026-06.30
+
+ 建会
+ 分配
+ 结题
+ 查看
+ 编辑
+ 开通
+ 删除公告
+ 执行单位评分
+
+
+
+
+ ZH-2026-645
+ 基层医疗改革试点项目
+ 20
+ 14
+ 6
+ 2,800,000
+ 1,050,000
+ 950,000
+ 800,000
+ 4.8
+ 3.0
+ 北京XXXX有限公司 北京XXXX公司
+ 线下
+ 未结题
+ 2026-05-11 2026-06.30
+
+ 建会
+ 分配
+ 结题
+ 查看
+ 编辑
+ 开通
+ 删除公告
+ 执行单位评分
+
+
+
+
+ ZH-2026-640
+ 数字化医疗转型方案
+ 22
+ 15
+ 7
+ 3,000,000
+ 1,200,000
+ 1,100,000
+ 700,000
+ 4.2
+ 4.0
+ 北京XXXX有限公司 北京XXXX公司
+ 线上
+ 未结题
+ 2026-05-11 2026-06.30
+
+ 建会
+ 分配
+ 结题
+ 查看
+ 编辑
+ 开通
+ 删除公告
+ 执行单位评分
+
+
+
+
+ ZH-2026-635
+ 临床医学研究方案评议
+ 14
+ 9
+ 5
+ 2,200,000
+ 820,000
+ 740,000
+ 640,000
+ 4.6
+ 4.2
+ 北京XXXX有限公司 北京XXXX公司
+ 线下
+ 已结题
+ 2026-05-11 2026-06.30
+
+ 建会
+ 结题
+ 查看
+ 分配
+ 开通
+ 编辑
+ 删除公告
+ 执行单位评分
+
+
+
+
+ ZH-2026-628
+ 公共卫生应急体系建设项目
+ 16
+ 11
+ 5
+ 2,400,000
+ 900,000
+ 820,000
+ 680,000
+ 4.4
+ 3.8
+ 北京XXXX有限公司 北京XXXX公司
+ 线下
+ 未结题
+ 2026-05-11 2026-06.30
+
+ 建会
+ 分配
+ 结题
+ 查看
+ 编辑
+ 开通
+ 删除公告
+ 执行单位评分
+
+
+
+
+ ZH-2026-622
+ 中医诊疗标准化研究
+ 10
+ 6
+ 4
+ 1,500,000
+ 560,000
+ 500,000
+ 440,000
+ 4.7
+ 4.5
+ 北京XXXX有限公司 北京XXXX公司
+ 线下
+ 未结题
+ 2026-05-11 2026-06.30
+
+ 建会
+ 分配
+ 结题
+ 查看
+ 编辑
+ 开通
+ 删除公告
+ 执行单位评分
+
+
+
+
+ ZH-2026-618
+ 医疗 AI 辅助诊断应用论坛
+ 8
+ 4
+ 4
+ 1,200,000
+ 480,000
+ 420,000
+ 300,000
+ 4.9
+ 4.8
+ 北京XXXX有限公司 北京XXXX公司
+ 线上+线下
+ 未结题
+ 2026-05-11 2026-06.30
+
+ 建会
+ 分配
+ 结题
+ 查看
+ 编辑
+ 开通
+ 删除公告
+ 执行单位评分
+
+
+
+
+
+
+
+
+
+
+
您确定要结题吗?
+
+ 确定
+ 取消
+
+
+
+
+
+
+
+
您确定要开通吗?
+
+ 确定
+ 取消
+
+
+
+
+
+
+
+
您确定要删除公告吗?删除后无法恢复
+
+ 确定
+ 取消
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/project-plan.html b/proto/html/components/project-plan.html
new file mode 100644
index 0000000..1e1bdc6
--- /dev/null
+++ b/proto/html/components/project-plan.html
@@ -0,0 +1,644 @@
+
+
+
+
+
+ 项目策划方案管理
+
+
+
+
+
+
+
+
+
+
+
+ 策划方案名称:
+
+
+
+ 项目方向:
+
+ 请选择
+ 专项计划一:《规范化诊疗及医疗质量提升专项计划(2026-2030年)》
+ 专项计划二:《科研创新专项行动计划(2026-2030年)》
+
+
+
+ 结题状态:
+
+ 请选择
+ 已结题
+ 未结题
+
+
+
+ 备注:
+
+
+
+
+
+
+ 项目类别:
+
+ 请选择
+
+
+
+ 是否结算:
+
+ 请选择
+ 已结算
+ 未结算
+
+
+
+ 项目编号:
+
+
+
查找
+
+
+
+
+
+
*批量审核:策划案名称,投稿ID,审核结果,审核意见,只能审核不通过
+
+
+
+
+ 批量审核
+ 批量结算
+
+
+
+ *项目形式是否保留?
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 通过
+ 退回
+
+
+
+
*通过时,项目编号为必填;退回时,不显示项目编号;审核意见为非必填
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/projects.html b/proto/html/components/projects.html
new file mode 100644
index 0000000..ff806fa
--- /dev/null
+++ b/proto/html/components/projects.html
@@ -0,0 +1,430 @@
+
+
+
+
+
+
+ 项目列表 - 项目管理系统
+
+
+
+
+
+
+
+
+
+
+
+
+ 项目分配
+
+
+
+
+
*支持将项目分配给执行人员
+
*执行方看到的总金额是项目分配时设置的总金额,根据相同的公式进行计算可用金额
+
*执行方看到的总金额是项目分配时设置的总金额
+
+
+
+
+
+
+
+
+ 项目编号
+ 项目名称
+ 总场次/总期数
+ 已执行
+ 未执行
+ 总金额
+ 可用金额
+ 已支付劳务费
+ 已支付会务费
+ 项目开始时间
+ 项目结束时间
+ 操作
+
+
+
+
+
+ ZH-2026-658
+ 小牛血清创新应用研讨会
+ 26
+ 16
+ 10
+ 2,400,000
+ 900,000
+ 820,000
+ 680,000
+ 2026.05.13
+ 2026.06.15
+
+ 建会
+ 查看
+
+
+
+
+ ZH-2026-659
+ 整合医学学会项目评审
+ 18
+ 12
+ 6
+ 2,400,000
+ 900,000
+ 820,000
+ 680,000
+ 2026.05.13
+ 2026.06.15
+
+ 建会
+ 查看
+
+
+
+
+ ZH-2026-650
+ 智慧医院建设项目
+ 12
+ 7
+ 5
+ 1,500,000
+ 560,000
+ 500,000
+ 440,000
+ 2026.06.01
+ 2026.08.30
+
+ 建会
+ 查看
+
+
+
+
+ ZH-2026-645
+ 基层医疗改革试点项目
+ 20
+ 14
+ 6
+ 1,500,000
+ 560,000
+ 500,000
+ 440,000
+ 2026.06.01
+ 2026.08.30
+
+ 建会
+ 查看
+
+
+
+
+ ZH-2026-640
+ 数字化医疗转型方案
+ 22
+ 15
+ 7
+ 1,500,000
+ 560,000
+ 500,000
+ 440,000
+ 2026.06.01
+ 2026.08.30
+
+ 建会
+ 查看
+
+
+
+
+ ZH-2026-635
+ 临床医学研究方案评议
+ 14
+ 9
+ 5
+ 2,400,000
+ 900,000
+ 820,000
+ 680,000
+ 2026.05.13
+ 2026.06.15
+
+ 建会
+ 查看
+
+
+
+
+ ZH-2026-628
+ 公共卫生应急体系建设项目
+ 16
+ 11
+ 5
+ 1,500,000
+ 560,000
+ 500,000
+ 440,000
+ 2026.06.01
+ 2026.08.30
+
+ 建会
+ 查看
+
+
+
+
+ ZH-2026-622
+ 中医诊疗标准化研究
+ 10
+ 6
+ 4
+ 2,400,000
+ 900,000
+ 820,000
+ 680,000
+ 2026.05.13
+ 2026.06.15
+
+ 建会
+ 查看
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/settle-labor.html b/proto/html/components/settle-labor.html
new file mode 100644
index 0000000..9f35282
--- /dev/null
+++ b/proto/html/components/settle-labor.html
@@ -0,0 +1,84 @@
+
+
+
+
+ 结算-劳务
+
+
+
+
+
+
首页
+
/
+
会议管理
+
/
+
结算会务费用
+
+ 结算-会务
+
+
会议名称: 小牛血清创新应用研讨会
+
项目编号: ZH-2026-658
+
执行单位: 北京会务服务公司
+
会议期数: 第 3 期
+
会议时间: 2026-05-11 11:30 ~ 14:30
+
+
+
劳务费用明细
+
+
+ 费用项 单价 数量 小计 备注 审核状态
+
+ 专家劳务费 ¥ 5,000 1 ¥ 5,000 会议室 A 已审核
+ 评审费 ¥ 3,000 1 ¥ 3,000 投影+音响 已审核
+ 差旅费 ¥ 200 30 ¥ 6,000 工作午餐 已审核
+ 材料费 ¥ 50 40 ¥ 2,000 会议手册 待审核
+ 其他费用 ¥ 1,000 1 ¥ 1,000 茶水等 已审核
+
+
+
+
+
已审核 ¥ 16,000
+
待审核 ¥ 2,000
+
合计 ¥ 18,000
+
+
+
+ 提交结算
+ 返回
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/settle-meeting.html b/proto/html/components/settle-meeting.html
new file mode 100644
index 0000000..3f70e2b
--- /dev/null
+++ b/proto/html/components/settle-meeting.html
@@ -0,0 +1,84 @@
+
+
+
+
+ 结算-会务
+
+
+
+
+
+
首页
+
/
+
会议管理
+
/
+
结算会务费用
+
+ 结算-会务
+
+
会议名称: 小牛血清创新应用研讨会
+
项目编号: ZH-2026-658
+
执行单位: 北京会务服务公司
+
会议期数: 第 3 期
+
会议时间: 2026-05-11 11:30 ~ 14:30
+
+
+
会务费用明细
+
+
+ 费用项 单价 数量 小计 备注 审核状态
+
+ 场地租赁 ¥ 5,000 1 ¥ 5,000 会议室 A 已审核
+ 设备租赁 ¥ 3,000 1 ¥ 3,000 投影+音响 已审核
+ 餐饮服务 ¥ 200 30 ¥ 6,000 工作午餐 已审核
+ 资料印刷 ¥ 50 40 ¥ 2,000 会议手册 待审核
+ 其他杂费 ¥ 1,000 1 ¥ 1,000 茶水等 已审核
+
+
+
+
+
已审核 ¥ 16,000
+
待审核 ¥ 2,000
+
合计 ¥ 18,000
+
+
+
+ 提交结算
+ 返回
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/sponsor-account.html b/proto/html/components/sponsor-account.html
new file mode 100644
index 0000000..82d7cd6
--- /dev/null
+++ b/proto/html/components/sponsor-account.html
@@ -0,0 +1,40 @@
+
+
+
+
+ 账号信息
+
+
+
+
+ 账号信息
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/sponsor-home.html b/proto/html/components/sponsor-home.html
new file mode 100644
index 0000000..ab354ab
--- /dev/null
+++ b/proto/html/components/sponsor-home.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+ 首页 - 项目管理系统
+
+
+
+
+ 首页
+
+
+
+ *点击数字,跳转到相应的列表页
+
+
+
+
+
结算审核通知
ZH-2026-650 项目结算已通过审核,请查看。
2小时前
+
项目确认通知
整合医学学会项目评审会已确认,请尽快完成后续流程。
昨天
+
系统升级公告
系统将于本周日 02:00-04:00 进行升级维护。
2026-08-01
+
新功能上线
批量导入功能已上线,请前往人员管理页面体验。
2026-07-28
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/sponsor-meeting-detail.html b/proto/html/components/sponsor-meeting-detail.html
new file mode 100644
index 0000000..0a12d32
--- /dev/null
+++ b/proto/html/components/sponsor-meeting-detail.html
@@ -0,0 +1,34 @@
+
+
+
+
+ 会议详情
+
+
+
+
+
+ 会议详情
+ 会议基本信息
+
+
项目编号: ZH-2026-658
会议名称: 小牛血清创新应用研讨会
+
项目名称: 小牛血清创新应用研讨会
期数: 3/26
+
总场次/总期数: 26
会议开始时间: 2026.05.13 11:30
+
支持单位: 北京XXXX有限公司
会议结束时间: 2026.05.15 11:30
+
创建时间: 2026.05.11 11:30
创建人员: 张三
+
+ 返回
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/sponsor-meetings.html b/proto/html/components/sponsor-meetings.html
new file mode 100644
index 0000000..aa6b281
--- /dev/null
+++ b/proto/html/components/sponsor-meetings.html
@@ -0,0 +1,307 @@
+
+
+
+
+
+
+ 会议列表
+
+
+
+
+ 会议列表
+
+
+
项目编号:
+
会议名称:
+
+ 第
+
+ 期
+
+
+
当前阶段:
+
+ 请选择
+ 已执行
+ 未执行
+
+
+
查找
+
+
+
+
+ *支持方点击监察意见保存确认后,按钮变为查看监察意见
+
+
*会议详情页,增加学会已审核及审核意见,增加支持方监督意见详情,两个意见,合规人员能看到,执行方也可看到
+
+
+
*支持方状态(当前阶段):
+
未执行:会议开始时间前,显示为未执行;
+
已执行未传材料:合规人员未审核通过前,一直显示该状态;
+
待监管:支持方未填写监管意见时,显示该状态;
+
监管通过:支持方选择确认无误后,则显示该状态;监管通过默认只显示 1 个工作日,之后显示为待结算
+
待整改:监管未通过后,则显示该状态;
+
待结算:支持方监管通过后,1 个工作日后变为待结算,显示该状态;
+
已结算:合规人员当操作结算后,状态变为已结算;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 确认无误
+
+
+
+
+
+ 存在需整改的问题
+
+
+
+
+ *
+ 详细意见
+
+ 0 /500
+
+
+
+
*3个工作日之内如果未填写,则默认为确认无误
+
*点击存在需整改的问题时,才显示详细意见
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/sponsor-new-person.html b/proto/html/components/sponsor-new-person.html
new file mode 100644
index 0000000..f6c50a6
--- /dev/null
+++ b/proto/html/components/sponsor-new-person.html
@@ -0,0 +1,118 @@
+
+
+
+
+ 新建人员
+
+
+
+
+
+ 新建人员
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/sponsor-people.html b/proto/html/components/sponsor-people.html
new file mode 100644
index 0000000..424eefe
--- /dev/null
+++ b/proto/html/components/sponsor-people.html
@@ -0,0 +1,146 @@
+
+
+
+
+ 人员管理
+
+
+
+
+ 人员管理
+
+
+ 新建人员
+ 批量导入
+ *新建时,管理员只能新建监察员
+ *批量导入模板与列表表项一致
+
+
+ *点击禁用后,状态变为禁用,按钮变成恢复;禁用后,账号无法登录,提示请联系管理员
+
+
+
+
+
+
+
+
+
+
*批量导入模板xls与列表表项一致
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/sponsor-project-detail.html b/proto/html/components/sponsor-project-detail.html
new file mode 100644
index 0000000..400035f
--- /dev/null
+++ b/proto/html/components/sponsor-project-detail.html
@@ -0,0 +1,47 @@
+
+
+
+
+ 项目详情
+
+
+
+
+
+ 项目详情
+
+
项目基本信息
+
+
项目编号: ZH-2026-658
+
项目形式: 线上
+
项目名称: 小牛血清创新应用研讨会
+
支持单位: 北京XXXX有限公司
+
总场次/总期数: 26
+
服务机构: 北京XXXX公司
+
总金额: 3,112,000
+
项目开始时间: 2026.05.11
+
管理费及税金: 1,112,000
+
项目结束时间: 2026.06.30
+
+
+ 项目评价
*点击后可查看具体评价维度,评价标准与供应商系统保持一致
+
+ 返回
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/sponsor-projects.html b/proto/html/components/sponsor-projects.html
new file mode 100644
index 0000000..ba2ab36
--- /dev/null
+++ b/proto/html/components/sponsor-projects.html
@@ -0,0 +1,262 @@
+
+
+
+
+
+
+ 项目列表 - 项目管理系统
+
+
+
+
+ 项目列表
+
+
+
+
项目编号:
+
项目名称:
+
+
是否结题:
+ 请选择 已结题 未结题
+
+
查找
+
+
+
+
+ 项目分配
+ 批量评价
+ *支持方管理员在分配项目的时候,只能分配监察员
+
+
+
+
+
+
+
+ 项目编号
+ 项目名称
+ 总场次
+ 已执行
+ 未执行
+ 总金额
+ 可用金额
+ 劳务费
+ 会务费
+ 项目开始时间
+ 项目结束时间
+ 是否结题
+ 执行单位评价
+ 操作
+
+
+
+ ZH-2026-658 小牛血清创新应用研讨会 26 16 10 3,112,000 1,112,000 1,000,000 1,000,000 2026-05-11 2026-06-30 未结题 3.5 项目评价 分配 查看
+ ZH-2026-650 整合医学学会项目评审会 18 12 6 2,500,000 980,000 900,000 620,000 2026-04-01 2026-05-20 已结题 4.5 项目评价 分配 查看
+ ZH-2026-645 智慧医院建设项目方案论证 12 7 5 1,800,000 760,000 700,000 340,000 2026-03-15 2026-04-30 未结题 5.0 项目评价 分配 查看
+ ZH-2026-640 基层医疗改革试点中期评估 20 14 6 2,800,000 1,050,000 950,000 800,000 2026-02-01 2026-03-31 已结题 4.5 项目评价 分配 查看
+ ZH-2026-635 数字化医疗转型方案评审 22 15 7 3,000,000 1,200,000 1,100,000 700,000 2026-01-10 2026-02-28 已结题 5.0 项目评价 分配 查看
+
+
+
+
+ *点击后可查看具体评价维度,评价标准与供应商系统保持一致
+
+
+
+
+
+
+
+
+
+
+
+
+
分配给监察员
+
+
*支持方管理员在分配项目的时候,只能分配监察员
+
+
+
候选监察员
+
+ 张三
+ 李四
+ 王五
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/sponsor-view.html b/proto/html/components/sponsor-view.html
new file mode 100644
index 0000000..08813da
--- /dev/null
+++ b/proto/html/components/sponsor-view.html
@@ -0,0 +1,86 @@
+
+
+
+
+ 查看人员
+
+
+
+
+
+ 查看人员
+
+
人员详情
+
姓名: 张三
+
手机号: 13534621147
+
工作单位: 北京XXXXXXX公司
+
部门: 华北大区
+
职务: 项目负责人
+
角色: 监察员
+
状态: 正常
+
+
+ 返回
+ 编辑
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/submission-detail-compliance.html b/proto/html/components/submission-detail-compliance.html
new file mode 100644
index 0000000..889c630
--- /dev/null
+++ b/proto/html/components/submission-detail-compliance.html
@@ -0,0 +1,207 @@
+
+
+
+
+
+ 投稿详情 (合规)
+
+
+
+
+
+
+
+
+
+
+ 新建项目设计投稿
+
+
+
+
+
+
+
+ 项目方向:
+ 小牛血清创新应用研讨会
+
+
+
+
+ 策划方案名称:
+ 临床医学交流会
+
+
+
+
+ 项目形式:
+ 线上+线下
+
+
+
+
+ 项目类别:
+ 学术会议类
+
+
+
+
+
+
+
+ 备注:
+ —
+
+
+
+
+
+
+
+ 返回
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/submission-detail.html b/proto/html/components/submission-detail.html
new file mode 100644
index 0000000..937f899
--- /dev/null
+++ b/proto/html/components/submission-detail.html
@@ -0,0 +1,207 @@
+
+
+
+
+
+ 投稿详情
+
+
+
+
+
+
+
+
+
+
+ 新建项目设计投稿
+
+
+
+
+
+
+
+ 项目方向:
+ 小牛血清创新应用研讨会
+
+
+
+
+ 策划方案名称:
+ 临床医学交流会
+
+
+
+
+ 项目形式:
+ 线上+线下
+
+
+
+
+ 项目类别:
+ 学术会议类
+
+
+
+
+
+
+
+ 备注:
+ —
+
+
+
+
+
+
+
+ 返回
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/submissions.html b/proto/html/components/submissions.html
new file mode 100644
index 0000000..b169296
--- /dev/null
+++ b/proto/html/components/submissions.html
@@ -0,0 +1,482 @@
+
+
+
+
+
+ 我的项目设计投稿
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 投稿名称:
+
+
+
+ 学科方向:
+
+
+
+ 形式:
+
+ 请选择
+ 线上
+ 线下
+ 线上+线下
+
+
+
+ 状态:
+
+ 请选择
+ 已结题
+ 未结题
+
+
+
+ 备注:
+
+
+
查找
+
+
+
+
+
+ 新建投稿
+ 批量提交
+
+
+
+ *点击查看可进行预览
+
+
+
+
+
+ *待审核和审核通过后,操作只显示查看按钮,无法进行修改
+
+
+
+
+
+
+
您确定要提交吗?
+
+ 确定
+ 取消
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/support-intent.html b/proto/html/components/support-intent.html
new file mode 100644
index 0000000..8e22458
--- /dev/null
+++ b/proto/html/components/support-intent.html
@@ -0,0 +1,322 @@
+
+
+
+
+
+ 支持意向
+
+
+
+
+
+
+
+
+
+
+
+ 意向项目名称:
+
+
+
+ 姓名:
+
+
+
+ 工作单位:
+
+
+
查找
+
导出
+
+
+
+ *项目公示中点击支持意向后,显示在此
+ *根据手机号与系统账号进行匹配
+ *支持意向不需要注册,但是如果已经注册账号,则显示账号状态
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/support-unit-manage-1-1.html b/proto/html/components/support-unit-manage-1-1.html
new file mode 100644
index 0000000..76c63d2
--- /dev/null
+++ b/proto/html/components/support-unit-manage-1-1.html
@@ -0,0 +1,66 @@
+
+
+
+
+ 支持单位管理 v1.1
+
+
+
+
+ 支持单位管理 v1.1
+
+
+
单位名称:
+
联系人:
+
状态:
+
+ 请选择
+ 合作中
+ 待签约
+ 已停用
+
+
+
查找
+
+
+
+ 新增支持单位
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/support-unit-manage.html b/proto/html/components/support-unit-manage.html
new file mode 100644
index 0000000..f5e4c43
--- /dev/null
+++ b/proto/html/components/support-unit-manage.html
@@ -0,0 +1,458 @@
+
+
+
+
+
+
+ 支持单位管理 - 项目管理系统
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 单位名称:
+
+
+
+
+ 合作状态:
+
+ 请选择
+ 正常
+ 禁用
+
+
+
+ 单位地址:
+
+
+
+ 税号/统一社会信用代码:
+
+
+
查找
+
+
+
+
+
+
+
+
+ 单位名称
+ 单位地址
+ 税号/统一社会信用代码
+ 合作状态
+ 创建日期
+ 操作
+
+
+
+
+ 北京XXXXXXX公司
+ 北京市海淀区XXX路XXXX号
+ 91330101MA2GPR961K
+ 正常
+ 2026.05.22
+
+ 人员管理
+ 查看
+ 禁用
+
+
+
+ 北京XXXXXXX公司
+ 北京市海淀区XXX路XXXX号
+ 91330101MA2GPR961K
+ 禁用
+ 2026.05.22
+
+ 人员管理
+ 查看
+ 恢复
+
+
+
+ 北京XXXXXXX公司
+ 北京市海淀区XXX路XXXX号
+ 91330101MA2GPR961K
+ 正常
+ 2026.05.22
+
+ 人员管理
+ 查看
+ 禁用
+
+
+
+ 北京XXXXXXX公司
+ 北京市海淀区XXX路XXXX号
+ 91330101MA2GPR961K
+ 禁用
+ 2026.05.22
+
+ 人员管理
+ 查看
+ 恢复
+
+
+
+ 北京XXXXXXX公司
+ 北京市海淀区XXX路XXXX号
+ 91330101MA2GPR961K
+ 正常
+ 2026.05.22
+
+ 人员管理
+ 查看
+ 禁用
+
+
+
+ 北京XXXXXXX公司
+ 北京市海淀区XXX路XXXX号
+ 91330101MA2GPR961K
+ 禁用
+ 2026.05.22
+
+ 人员管理
+ 查看
+ 恢复
+
+
+
+ 北京XXXXXXX公司
+ 北京市海淀区XXX路XXXX号
+ 91330101MA2GPR961K
+ 正常
+ 2026.05.22
+
+ 人员管理
+ 查看
+ 禁用
+
+
+
+ 北京XXXXXXX公司
+ 北京市海淀区XXX路XXXX号
+ 91330101MA2GPR961K
+ 正常
+ 2026.05.22
+
+ 人员管理
+ 查看
+ 恢复
+
+
+
+
+
+
+
+ *点击禁用后,该企业下所有账号则均不可登录
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/support-unit-view-1.html b/proto/html/components/support-unit-view-1.html
new file mode 100644
index 0000000..b2e8efc
--- /dev/null
+++ b/proto/html/components/support-unit-view-1.html
@@ -0,0 +1,49 @@
+
+
+
+
+ 支持单位查看 v1
+
+
+
+
+ 支持单位查看 v1
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/support-unit-view.html b/proto/html/components/support-unit-view.html
new file mode 100644
index 0000000..e96bd6d
--- /dev/null
+++ b/proto/html/components/support-unit-view.html
@@ -0,0 +1,49 @@
+
+
+
+
+ 支持单位查看
+
+
+
+
+ 支持单位查看
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/view-person.html b/proto/html/components/view-person.html
new file mode 100644
index 0000000..c95270e
--- /dev/null
+++ b/proto/html/components/view-person.html
@@ -0,0 +1,272 @@
+
+
+
+
+
+ 查看人员 - 项目管理系统
+
+
+
+
+
+
+
+
+
+
+ 查看人员
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 返回
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/components/workbench.html b/proto/html/components/workbench.html
new file mode 100644
index 0000000..9309235
--- /dev/null
+++ b/proto/html/components/workbench.html
@@ -0,0 +1,67 @@
+
+
+
+
+ 工作台 - 合规
+
+
+
+
+ 工作台
+
+
+
+
+
+
+
合规审核通知
ZH-2026-650 项目的会议材料已提交合规审核,请尽快处理。
1小时前
+
结算到期提醒
5 个会议的会务费用结算已到期,请及时处理。
3小时前
+
劳务凭证待复核
有 3 份劳务凭证需要合规人员复核签字。
昨天
+
月度合规报告
2026 年 7 月合规审核报告已生成,可前往下载。
2026-08-01
+
系统升级公告
系统将于本周日 02:00-04:00 进行升级维护。
2026-07-28
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/doctor.html b/proto/html/doctor.html
new file mode 100644
index 0000000..1e558fa
--- /dev/null
+++ b/proto/html/doctor.html
@@ -0,0 +1,252 @@
+
+
+
+
+
+ 专家工作台 - 项目管理系统
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/doubao_html_20260807_194253.html b/proto/html/doubao_html_20260807_194253.html
new file mode 100644
index 0000000..290913f
--- /dev/null
+++ b/proto/html/doubao_html_20260807_194253.html
@@ -0,0 +1,104 @@
+
+
+
+
+
+2025-2030健康规划弧形时间轴
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
01
+
+
触达100万+家医 疗卫生服务机构
+
+
+
+
02
+
+
300万+专业医护 人员广泛参与
+
+
+
+
03
+
+
培训100万+名健 康科普创作志愿 者
+
+
+
+
04
+
+
赋能10万+名健康 科普传播志愿者
+
+
+
+
05
+
+
知识普及10亿+ 人次人民群众
+
+
+
+
+
+
07
+
+
1000万个流量平 台(用户数10万+)
+
+
+
+
+
+
diff --git a/proto/html/executor.html b/proto/html/executor.html
new file mode 100644
index 0000000..176dba9
--- /dev/null
+++ b/proto/html/executor.html
@@ -0,0 +1,251 @@
+
+
+
+
+
+ 执行人员工作台 - 项目管理系统
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/images/index/u1.png b/proto/html/images/index/u1.png
new file mode 100644
index 0000000..7eec7e0
Binary files /dev/null and b/proto/html/images/index/u1.png differ
diff --git a/proto/html/images/index/u18_menu.png b/proto/html/images/index/u18_menu.png
new file mode 100644
index 0000000..e351626
Binary files /dev/null and b/proto/html/images/index/u18_menu.png differ
diff --git a/proto/html/images/index/u215.png b/proto/html/images/index/u215.png
new file mode 100644
index 0000000..83e5b9b
Binary files /dev/null and b/proto/html/images/index/u215.png differ
diff --git a/proto/html/images/index/u217.png b/proto/html/images/index/u217.png
new file mode 100644
index 0000000..4a94f74
Binary files /dev/null and b/proto/html/images/index/u217.png differ
diff --git a/proto/html/images/index/u225.png b/proto/html/images/index/u225.png
new file mode 100644
index 0000000..3268e16
Binary files /dev/null and b/proto/html/images/index/u225.png differ
diff --git a/proto/html/images/index/u229.png b/proto/html/images/index/u229.png
new file mode 100644
index 0000000..dca1546
Binary files /dev/null and b/proto/html/images/index/u229.png differ
diff --git a/proto/html/images/index/u22_menu.png b/proto/html/images/index/u22_menu.png
new file mode 100644
index 0000000..0b9fda2
Binary files /dev/null and b/proto/html/images/index/u22_menu.png differ
diff --git a/proto/html/images/index/u24.png b/proto/html/images/index/u24.png
new file mode 100644
index 0000000..9db7542
Binary files /dev/null and b/proto/html/images/index/u24.png differ
diff --git a/proto/html/images/index/u267.png b/proto/html/images/index/u267.png
new file mode 100644
index 0000000..19ca5d3
Binary files /dev/null and b/proto/html/images/index/u267.png differ
diff --git a/proto/html/images/index/u277.png b/proto/html/images/index/u277.png
new file mode 100644
index 0000000..c2b39fd
Binary files /dev/null and b/proto/html/images/index/u277.png differ
diff --git a/proto/html/images/index/u279.png b/proto/html/images/index/u279.png
new file mode 100644
index 0000000..f44f221
Binary files /dev/null and b/proto/html/images/index/u279.png differ
diff --git a/proto/html/images/index/u283.png b/proto/html/images/index/u283.png
new file mode 100644
index 0000000..13bd95c
Binary files /dev/null and b/proto/html/images/index/u283.png differ
diff --git a/proto/html/images/index/u287.png b/proto/html/images/index/u287.png
new file mode 100644
index 0000000..0391b2f
Binary files /dev/null and b/proto/html/images/index/u287.png differ
diff --git a/proto/html/images/index/u291.png b/proto/html/images/index/u291.png
new file mode 100644
index 0000000..e11bee7
Binary files /dev/null and b/proto/html/images/index/u291.png differ
diff --git a/proto/html/images/index/u295.png b/proto/html/images/index/u295.png
new file mode 100644
index 0000000..4c987c5
Binary files /dev/null and b/proto/html/images/index/u295.png differ
diff --git a/proto/html/images/index/u299.png b/proto/html/images/index/u299.png
new file mode 100644
index 0000000..aefc21c
Binary files /dev/null and b/proto/html/images/index/u299.png differ
diff --git a/proto/html/images/index/u3.png b/proto/html/images/index/u3.png
new file mode 100644
index 0000000..bcbf2c2
Binary files /dev/null and b/proto/html/images/index/u3.png differ
diff --git a/proto/html/images/index/u35_menu.png b/proto/html/images/index/u35_menu.png
new file mode 100644
index 0000000..dd19fbb
Binary files /dev/null and b/proto/html/images/index/u35_menu.png differ
diff --git a/proto/html/images/index/u53_menu.png b/proto/html/images/index/u53_menu.png
new file mode 100644
index 0000000..7e4e015
Binary files /dev/null and b/proto/html/images/index/u53_menu.png differ
diff --git a/proto/html/images/index/u71_menu.png b/proto/html/images/index/u71_menu.png
new file mode 100644
index 0000000..3770847
Binary files /dev/null and b/proto/html/images/index/u71_menu.png differ
diff --git a/proto/html/images/index/u75_menu.png b/proto/html/images/index/u75_menu.png
new file mode 100644
index 0000000..1b4a8bc
Binary files /dev/null and b/proto/html/images/index/u75_menu.png differ
diff --git a/proto/html/images/index/u77.png b/proto/html/images/index/u77.png
new file mode 100644
index 0000000..34b28bd
Binary files /dev/null and b/proto/html/images/index/u77.png differ
diff --git a/proto/html/images/index/u79.png b/proto/html/images/index/u79.png
new file mode 100644
index 0000000..4fd4cbe
Binary files /dev/null and b/proto/html/images/index/u79.png differ
diff --git a/proto/html/images/index/u83.png b/proto/html/images/index/u83.png
new file mode 100644
index 0000000..b3a6bb1
Binary files /dev/null and b/proto/html/images/index/u83.png differ
diff --git a/proto/html/images/index/u90_menu.png b/proto/html/images/index/u90_menu.png
new file mode 100644
index 0000000..0a80e02
Binary files /dev/null and b/proto/html/images/index/u90_menu.png differ
diff --git a/proto/html/images/index/学会系统_u20.png b/proto/html/images/index/学会系统_u20.png
new file mode 100644
index 0000000..db2578e
Binary files /dev/null and b/proto/html/images/index/学会系统_u20.png differ
diff --git a/proto/html/images/index/学会项目_u73.png b/proto/html/images/index/学会项目_u73.png
new file mode 100644
index 0000000..0cbafd0
Binary files /dev/null and b/proto/html/images/index/学会项目_u73.png differ
diff --git a/proto/html/images/公示详情/u552.jpg b/proto/html/images/公示详情/u552.jpg
new file mode 100644
index 0000000..c83628b
Binary files /dev/null and b/proto/html/images/公示详情/u552.jpg differ
diff --git a/proto/html/images/年度项目计划/u320.png b/proto/html/images/年度项目计划/u320.png
new file mode 100644
index 0000000..1904feb
Binary files /dev/null and b/proto/html/images/年度项目计划/u320.png differ
diff --git a/proto/html/images/年度项目计划/u333.png b/proto/html/images/年度项目计划/u333.png
new file mode 100644
index 0000000..7a4d32a
Binary files /dev/null and b/proto/html/images/年度项目计划/u333.png differ
diff --git a/proto/html/images/年度项目计划/u337.png b/proto/html/images/年度项目计划/u337.png
new file mode 100644
index 0000000..2c1c929
Binary files /dev/null and b/proto/html/images/年度项目计划/u337.png differ
diff --git a/proto/html/images/年度项目计划/u359.png b/proto/html/images/年度项目计划/u359.png
new file mode 100644
index 0000000..bcf009b
Binary files /dev/null and b/proto/html/images/年度项目计划/u359.png differ
diff --git a/proto/html/images/年度项目计划/u376.png b/proto/html/images/年度项目计划/u376.png
new file mode 100644
index 0000000..a65f3cb
Binary files /dev/null and b/proto/html/images/年度项目计划/u376.png differ
diff --git a/proto/html/index2.html b/proto/html/index2.html
new file mode 100644
index 0000000..1ca4202
--- /dev/null
+++ b/proto/html/index2.html
@@ -0,0 +1,850 @@
+
+
+
+
+
+ 年度项目计划 - 北京整合医学学会
+
+
+
+
+
+
+
+
+
+
+
+
+
+
2025-2030
+
年度项目规划
+
七 大 专 项
+
+ 围绕健康中国战略,聚焦医学整合创新,系统推进七大专项计划,
+ 全面构建覆盖诊疗、科研、人才、管理、公益、政学协作与组织建设的协同发展体系。
+
+
+
+ 项目提案
+
+
+
+
+
+ 年度项目规划概述
+
+ 依托国家战略层面《"健康中国2030"规划纲要》和健康中国行动的统领力量,切合《全民健康素养提升三年行动方案(2024-2027年)》的契机,践行学会的公益性服务的责任和使命,全方位、全领域、体系性、系统性、持续性地开展健康科普活动,通过征集全国范围300个病种的健康科普短视频、科普讲座、科普文章,进行整个医疗系统的健康科普总动员,以科普内容征集促进科普活动走近、走深、走实。
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 01
+ 02
+ 03
+ 04
+ 05
+ 06
+ 07
+ 08
+
+
+
+
+
+
+
+ 2025-2030年
+
+
+
+ 触达100万+家 医疗卫生服务机构
+ 300万+专业医护 人员广泛参与
+ 培训100万+名 健康科普创作志愿者
+ 赋能10万+名 健康科普传播志愿者
+ 知识普及10亿+ 人次人民群众
+ 覆盖4万+个 乡镇、街道
+ 1000万个流量平台 (用户数10万+)
+ 建设1万个 健康小屋
+
+
+
+
+
+
+
+
+
七大专项计划
+
+
+
01
+
+
《规范化诊疗及医疗质量提升专项计划(2026年)》
+
聚焦临床诊疗规范制定与质量提升,推动各级医疗机构诊疗标准化、同质化。
+
+ 查看详情
+ 项目提案
+
+
+
+
+
02
+
+
《科研创新专项行动计划(2026-2030年)》
+
支持医学科研创新,推动整合医学研究成果转化与产业化应用,构建协同创新生态。
+
+ 查看详情
+ 项目提案
+
+
+
+
+
03
+
+
《医疗卫生人才培育专项行动计划(2026-2030年)》
+
建立多层次医学人才培养体系,重点加强基层医疗人才与跨学科复合型人才建设。
+
+ 查看详情
+ 项目提案
+
+
+
+
+
04
+
+
《医院管理及高质量发展促进专项计划(2026-2030年)》
+
推动医院管理现代化,提升运营效率与服务水平,助力公立医院高质量发展。
+
+ 查看详情
+ 项目提案
+
+
+
+
+
05
+
+
《社会公益与可及性提升专项计划(2026-2030年)》
+
聚焦医疗服务的可及性与公平性,开展公益救助、基层帮扶与健康科普活动。
+
+ 查看详情
+ 项目提案
+
+
+
+
+
06
+
+
《政学协作综合项目专项计划(2026-2030年)》
+
搭建政府与学术机构协同平台,推动政策研究与决策支持,促进政产学研用深度融合。
+
+ 查看详情
+ 项目提案
+
+
+
+
+
07
+
+
《组织建设与内部治理专项计划(2026-2030年)》
+
完善学会组织架构,健全内部治理机制,提升规范化、专业化、信息化管理水平。
+
+ 查看详情
+ 项目提案
+
+
+
+
+
+
+
+
+
+ 参与说明
+
+
+ 登录要求 · 点击计划详情及项目提案,需先登录系统;
+ 支持方注册 · 注册后默认为监察员角色,合规人员可配置支持方的管理员账号;
+ 支持方管理 · 注册时选择的企业为主单位,默认进入该企业的人员管理页,由企业管理员进行管理,管理员账号可新建监督员账号;
+ 执行方注册 · 注册跳转至供应商系统,走入库流程,注册成功后该账号默认为管理员账号,管理员账号可新建执行人员账号。
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/proto/html/leader.html b/proto/html/leader.html
new file mode 100644
index 0000000..8d8707c
--- /dev/null
+++ b/proto/html/leader.html
@@ -0,0 +1,248 @@
+
+
+
+
+
+ 项目负责人工作台 - 项目管理系统
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/manager.html b/proto/html/manager.html
new file mode 100644
index 0000000..6ee2db2
--- /dev/null
+++ b/proto/html/manager.html
@@ -0,0 +1,256 @@
+
+
+
+
+
+ 合规人员工作台 - 项目管理系统
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/sponsor.html b/proto/html/sponsor.html
new file mode 100644
index 0000000..6580bd2
--- /dev/null
+++ b/proto/html/sponsor.html
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+ 赞助方工作台 - 项目管理系统
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/proto/html/专家注册.html b/proto/html/专家注册.html
new file mode 100644
index 0000000..ed993a7
--- /dev/null
+++ b/proto/html/专家注册.html
@@ -0,0 +1,579 @@
+
+
+
+
+
+ 专家注册 - 项目管理系统
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/proto/html/供应商注册.html b/proto/html/供应商注册.html
new file mode 100644
index 0000000..a867934
--- /dev/null
+++ b/proto/html/供应商注册.html
@@ -0,0 +1,518 @@
+
+
+
+
+
+ 供应商注册 - 项目管理系统
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/proto/html/公示详情.html b/proto/html/公示详情.html
new file mode 100644
index 0000000..7d2f9e1
--- /dev/null
+++ b/proto/html/公示详情.html
@@ -0,0 +1,739 @@
+
+
+
+
+
+ 公示详情 - 北京整合医学学会
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 返回项目公示
+
+
+
+
+
+
+
+
+
+ 立即报名
+ 分享二维码
+
+
+
+
+
+
+
+
+
+
+
分享邀请函
+
+
扫码查看并分享本邀请函
+
关 闭
+
+
+
+
+
+
+
diff --git a/proto/html/支持函详情.html b/proto/html/支持函详情.html
new file mode 100644
index 0000000..97f9c4e
--- /dev/null
+++ b/proto/html/支持函详情.html
@@ -0,0 +1,755 @@
+
+
+
+
+
+ 支持函详情 - 北京整合医学学会
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 返回项目公示
+
+
+
+
+
+
+
+
+
+ 公益支持
+ 分享二维码
+
+
+
+
+
*支持不需要登录,只记录留痕
+
*已点支持的,记录在管理后台中,显示对应项目以及支持人员信息
+
*支持成功后隐藏我要支持按钮,并显示为已报名支持
+
+
+
+
+
+
+
+
+
+
+
分享邀请函
+
+
扫码查看并分享本邀请函
+
关 闭
+
+
+
+
+
+
+
diff --git a/proto/html/登录.html b/proto/html/登录.html
new file mode 100644
index 0000000..dde7189
--- /dev/null
+++ b/proto/html/登录.html
@@ -0,0 +1,563 @@
+
+
+
+
+
+ 登录 - 项目管理系统
+
+
+
+
+
+
+
+
+
+
+
+
+
+
BAHIM
+
规范化项目 协同管理平台
+
+
+ 为专家、供应商、支持单位提供统一的 项目协同管理平台,实现项目从立项到 结题的全流程数字化管理。
+
+
+
+
+
+
+
+
账号登录
+
请输入您的账号信息
+
+
+
+
+
+
+
+
+ 登 录
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
选择用户类别
+
+
+
+
+
+
+
+
+
项目执行单位(供应商)
+
承担项目执行,需走入库流程
+
+
+
+
+
+
+
+
+ 取消
+ 确定
+
+
+
+
+
+
+
+
diff --git a/proto/html/赞助方注册.html b/proto/html/赞助方注册.html
new file mode 100644
index 0000000..0cc8c21
--- /dev/null
+++ b/proto/html/赞助方注册.html
@@ -0,0 +1,533 @@
+
+
+
+
+
+ 赞助方注册 - 项目管理系统
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/proto/html/项目公示.html b/proto/html/项目公示.html
new file mode 100644
index 0000000..3c74b47
--- /dev/null
+++ b/proto/html/项目公示.html
@@ -0,0 +1,787 @@
+
+
+
+
+
+ 项目公示 - 北京整合医学学会
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 类型:
+
+ 请选择
+ 邀请函
+ 支持函
+ 通知
+ 日程
+
+
+
+
+ 查询
+ 重置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/proto/html/首页.html b/proto/html/首页.html
new file mode 100644
index 0000000..7394de7
--- /dev/null
+++ b/proto/html/首页.html
@@ -0,0 +1,1292 @@
+
+
+
+
+
+ 首页 - 北京整合医学学会
+
+
+
+
+
+
+
+
+
+
+
+
+
+
BAHIM
+
健康中国 · 整合医学
+
+ 依托大政方针,整合医学资源,推动健康科普与公益事业,
+ 助力全民健康素养提升,共建共享健康中国。
+
+
了解年度计划
+
+
+
+
+
+
+ 项目方案招募
+
+
+
+ 招募中
+ 01
+
+
+
百姓巡常行
+
面向社区开展健康科普巡讲,提升基层健康素养水平。
+
第一季度
+
+
+
+
+ 招募中
+ 02
+
+
+
专病联盟暨全国专家智库
+
汇聚全国专家力量,共建专病诊疗协同网络。
+
第二季度
+
+
+
+
+ 招募中
+ 03
+
+
+
乡村幸福安康
+
聚焦乡村振兴,推进乡村健康服务体系建设。
+
第三季度
+
+
+
+
+ 招募中
+ 04
+
+
+
临床科研资助计划
+
支持临床科研创新,推动整合医学成果转化应用。
+
第四季度
+
+
+
+
+
+
+
+
+
+
+
NEWS
+
+ 头条
+
健康中国行动 — 百姓健康卫士公益科普"百姓巡常行"项目试点成果发布
+ 2023-01-06
+
+
+
+
+ XXXXXXXXXXXXXXXXX项目正式启动
+ 2023-01-06
+
+
+ 健康中国行动 — 百姓健康卫士公益科普"百姓巡常行"项目试点成果发布
+ 2023-01-06
+
+
+ XXXXXXXXXXXXXXXXX项目圆满完成
+ 2023-01-06
+
+
+ 乡村振兴 健康先行 | 北京整合医学学会2024年度慈善医疗帮扶
+ 2023-01-06
+
+
+ 健康中国行动 — 百姓健康卫士公益科普"百姓巡常行"项目试点成果发布
+ 2023-01-06
+
+
+ "前腺守护"上线!用数字化为患者提供支持
+ 2023-01-06
+
+
+
+
+
+
+
+
+
+
+ 依托国家战略层面《"健康中国2030"规划纲要》和健康中国行动的统领力量,切合《全民健康素养提升三年行动方案(2024-2027年)》的契机,践行学会的公益性服务的责任和使命,全方位、全领域、体系性、系统性、持续性地开展健康科普活动,通过征集全国范围300个病种的健康科普短视频、科普讲座、科普文章,进行整个医疗系统的健康科普总动员,以科普内容征集促进科普活动走近、走深、走实。
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 01
+
+
+
+ 02
+
+
+
+ 03
+
+
+
+ 04
+
+
+
+ 05
+
+
+
+ 06
+
+
+
+ 07
+
+
+
+ 08
+
+
+
+
+
+
+
+
+
+
+
+
+ 2025-2030年
+
+
+
+
+
+
+ 触达100万+家
+ 医疗卫生服务机构
+
+
+ 300万+专业医护
+ 人员广泛参与
+
+
+ 培训100万+名
+ 健康科普创作志愿者
+
+
+ 赋能10万+名
+ 健康科普传播志愿者
+
+
+ 知识普及10亿+
+ 人次人民群众
+
+
+ 覆盖4万+个
+ 乡镇、街道
+
+
+ 1000万个流量平台
+ (用户数10万+)
+
+
+ 建设1万个
+ 健康小屋
+
+
+
+
+
+
+
+
+
+ 项目解读
+
+
+
+
+ 依托国家战略层面《"健康中国2030"规划纲要》和健康中国行动的统领力量,切合《全民健康素养提升三年行动方案(2024-2027年)》的锲机,践行学会的公益性服务的责任和使命,全方位、全领域、体系性、系统性、持续性地开展健康科普活动。
+
+
+
+
+
+
+ 征集的科普内容经过专家评审、剪辑制作、编辑后,将发表到项目专属云平台、北京整合医学学会官方公众号、视频号,并同步转载至相关权威大健康科普媒体平台、项目支持单位官方媒体平台。优质科普作品,将由有关国家级出版社编辑出版科普图书,正式出版发行。
+
+
+
+
+
+
+ 科普短视频、科普讲座和科普图书内容相互依联,互为导入,观看科普视频和科普讲座,会链接导入科普图书,阅读科普图书,会通过图书内文的二维码链接导入到科普视频,触达项目专属云平台,实现健康内容按需查看,使科普形式和内容适用于不同的人群和偏好。
+
+
+
+
+
+
+ 在健康知识传播的同时,还将邀请权威专家讲解国家有关方针政策,穿插在科普活动中,增强人民群众对国家方针政策的理解和认可度,促进百姓对医疗机构和医务工作者的理解和认可,降低医患矛盾,调和医患关系,减少医疗纠纷。
+
+
+
+
+
+
+ 在健康知识传播的同时,也会对当前及未来可能出现的生命科学研究成果进行宣讲和展望,涉及到新的诊疗技术、新的药品、器械、新的研究方向等方面,使人民群众树立起强大的生活信心和对美好生活向往的决心和勇气。
+
+
+
+
+
+
+ 在健康知识传播的同时,结合现代移动互联的技术进步,绘制医疗服务机构地图,提供医疗专家资源的动态分布信息,使人民群众能够及时就医,精准就医,就近就医,减少不必要的隐性医疗支出和经济负担,节约医疗资源,助推分级诊疗政策的贯彻实施。
+
+
+
+
+
+
+ 立即参与
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ry-api/.github/FUNDING.yml b/ry-api/.github/FUNDING.yml
new file mode 100644
index 0000000..fbcab77
--- /dev/null
+++ b/ry-api/.github/FUNDING.yml
@@ -0,0 +1 @@
+custom: http://doc.ruoyi.vip/ruoyi-vue/other/donate.html
diff --git a/ry-api/.gitignore b/ry-api/.gitignore
new file mode 100644
index 0000000..ed8368a
--- /dev/null
+++ b/ry-api/.gitignore
@@ -0,0 +1,47 @@
+######################################################################
+# Build Tools
+
+.gradle
+/build/
+!gradle/wrapper/gradle-wrapper.jar
+
+target/
+!.mvn/wrapper/maven-wrapper.jar
+
+######################################################################
+# IDE
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### JRebel ###
+rebel.xml
+
+### NetBeans ###
+nbproject/private/
+build/*
+nbbuild/
+dist/
+nbdist/
+.nb-gradle/
+
+######################################################################
+# Others
+*.log
+*.xml.versionsBackup
+*.swp
+
+!*/build/*.java
+!*/build/*.html
+!*/build/*.xml
diff --git a/ry-api/LICENSE b/ry-api/LICENSE
new file mode 100644
index 0000000..8564f29
--- /dev/null
+++ b/ry-api/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2018 RuoYi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/ry-api/README.md b/ry-api/README.md
new file mode 100644
index 0000000..0b41120
--- /dev/null
+++ b/ry-api/README.md
@@ -0,0 +1,115 @@
+
+
+
+RuoYi v3.9.2
+基于SpringBoot+Vue前后端分离的Java快速开发框架
+
+
+
+
+
+
+## 平台简介
+
+若依是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。
+
+* 前端采用Vue、Element UI。
+* 后端采用Spring Boot、Spring Security、Redis & Jwt。
+* 权限认证使用Jwt,支持多终端认证系统。
+* 支持加载动态权限菜单,多方式轻松权限控制。
+* 高效率开发,使用代码生成器可以一键生成前后端代码。
+* 阿里云折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip)
+
+# 版本分支
+
+RuoYi-Vue 后端项目提供 Spring Boot 2.x / 3.x / 4.x 多版本分支的并行维护。
+
+| 名称 | 说明 | 地址 |
+| :---------------- | :------------------------ | :------------------------------------------------------ |
+| master 默认分支 | Spring Boot 4.x (JDK 17+) | https://gitee.com/y_project/RuoYi-Vue |
+| springboot3 分支 | Spring Boot 3.x (JDK 17+) | https://gitee.com/y_project/RuoYi-Vue/tree/springboot3 |
+| springboot2 分支 | Spring Boot 2.x (JDK 8+) | https://gitee.com/y_project/RuoYi-Vue/tree/springboot2 |
+
+RuoYi-Vue 前端项目提供 Vue 2.x / 3.x / JavaScript TypeScript 版本均可混用搭配
+
+| 项目名称 | **RuoYi-Vue** | **RuoYi-Vue3** | **RuoYi-Vue3-TypeScript** |
+| :--- | :--- | :--- | :--- |
+| **前端框架** | Vue 2 | Vue 3 | Vue 3 |
+| **脚本语言** | JavaScript | JavaScript | TypeScript |
+| **构建工具** | Vue CLI | Vite | Vite |
+| **UI 组件库** | Element UI | Element Plus | Element Plus |
+| **状态管理** | Vuex | Pinia | Pinia |
+| **路由管理** | Vue Router 3 | Vue Router 4 | Vue Router 4 |
+| **核心特点** | 1. 技术栈经典稳定 2. 社区资料丰富 3. 当前维护重心已转移 | 1. 现代前端技术栈 2. 开发体验与性能更优 3. 官方主推的活跃版本 | 1. 类型加持,减少沟通成本 2. 开发时有提示,效率更高 3. 多人协作企业级开发项目 |
+| **仓库地址** | [RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue) | [RuoYi-Vue3](https://gitcode.com/yangzongzhuan/RuoYi-Vue3) | [RuoYi-Vue3-TypeScript](https://gitcode.com/yangzongzhuan/RuoYi-Vue3/tree/typescript) |
+
+## 内置功能
+
+1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。
+2. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。
+3. 岗位管理:配置系统用户所属担任职务。
+4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。
+5. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。
+6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。
+7. 参数管理:对系统动态配置常用参数。
+8. 通知公告:系统通知公告信息发布维护。
+9. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
+10. 登录日志:系统登录日志记录查询包含登录异常。
+11. 在线用户:当前系统中活跃用户状态监控。
+12. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。
+13. 代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载 。
+14. 系统接口:根据业务代码自动生成相关的api接口文档。
+15. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。
+16. 缓存监控:对系统的缓存信息查询,命令统计等。
+17. 在线构建器:拖动表单元素生成相应的HTML代码。
+18. 连接池监视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。
+
+## 在线体验
+
+- admin/admin123
+- 陆陆续续收到一些打赏,为了更好的体验已用于演示服务器升级。谢谢各位小伙伴。
+
+演示地址:http://vue.ruoyi.vip
+文档地址:http://doc.ruoyi.vip
+
+## 演示图
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## 若依前后端分离交流群
+
+QQ群: [](https://jq.qq.com/?_wv=1027&k=5bVB1og) [](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [](https://jq.qq.com/?_wv=1027&k=51G72yr) [](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) [](https://jq.qq.com/?_wv=1027&k=EI9an8lJ) [](https://jq.qq.com/?_wv=1027&k=SWCtLnMz) [](https://jq.qq.com/?_wv=1027&k=96Dkdq0k) [](https://jq.qq.com/?_wv=1027&k=0fsNiYZt) [](https://jq.qq.com/?_wv=1027&k=7xw4xUG1) [](https://jq.qq.com/?_wv=1027&k=eCx8eyoJ) [](https://jq.qq.com/?_wv=1027&k=SpyH2875) [](https://jq.qq.com/?_wv=1027&k=tKEt51dz) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=0vBbSb0ztbBgVtn3kJS-Q4HUNYwip89G&authKey=8irq5PhutrZmWIvsUsklBxhj57l%2F1nOZqjzigkXZVoZE451GG4JHPOqW7AW6cf0T&noverify=0&group_code=143961921) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=ZFAPAbp09S2ltvwrJzp7wGlbopsc0rwi&authKey=HB2cxpxP2yspk%2Bo3WKTBfktRCccVkU26cgi5B16u0KcAYrVu7sBaE7XSEqmMdFQp&noverify=0&group_code=174951577) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Fn2aF5IHpwsy8j6VlalNJK6qbwFLFHat&authKey=uyIT%2B97x2AXj3odyXpsSpVaPMC%2Bidw0LxG5MAtEqlrcBcWJUA%2FeS43rsF1Tg7IRJ&noverify=0&group_code=161281055) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=XIzkm_mV2xTsUtFxo63bmicYoDBA6Ifm&authKey=dDW%2F4qsmw3x9govoZY9w%2FoWAoC4wbHqGal%2BbqLzoS6VBarU8EBptIgPKN%2FviyC8j&noverify=0&group_code=138988063) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=DkugnCg68PevlycJSKSwjhFqfIgrWWwR&authKey=pR1Pa5lPIeGF%2FFtIk6d%2FGB5qFi0EdvyErtpQXULzo03zbhopBHLWcuqdpwY241R%2F&noverify=0&group_code=151450850) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=F58bgRa-Dp-rsQJThiJqIYv8t4-lWfXh&authKey=UmUs4CVG5OPA1whvsa4uSespOvyd8%2FAr9olEGaWAfdLmfKQk%2FVBp2YU3u2xXXt76&noverify=0&group_code=224622315) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Nxb2EQ5qozWa218Wbs7zgBnjLSNk_tVT&authKey=obBKXj6SBKgrFTJZx0AqQnIYbNOvBB2kmgwWvGhzxR67RoRr84%2Bus5OadzMcdJl5&noverify=0&group_code=287842588) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=numtK1M_I4eVd2Gvg8qtbuL8JgX42qNh&authKey=giV9XWMaFZTY%2FqPlmWbkB9g3fi0Ev5CwEtT9Tgei0oUlFFCQLDp4ozWRiVIzubIm&noverify=0&group_code=187944233) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=G6r5KGCaa3pqdbUSXNIgYloyb8e0_L0D&authKey=4w8tF1eGW7%2FedWn%2FHAypQksdrML%2BDHolQSx7094Agm7Luakj9EbfPnSTxSi2T1LQ&noverify=0&group_code=228578329) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=GsOo-OLz53J8y_9TPoO6XXSGNRTgbFxA&authKey=R7Uy%2Feq%2BZsoKNqHvRKhiXpypW7DAogoWapOawUGHokJSBIBIre2%2FoiAZeZBSLuBc&noverify=0&group_code=191164766) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=PmYavuzsOthVqfdAPbo4uAeIbu7Ttjgc&authKey=p52l8%2FXa4PS1JcEmS3VccKSwOPJUZ1ZfQ69MEKzbrooNUljRtlKjvsXf04bxNp3G&noverify=0&group_code=174569686) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=M9y5NjAl44lAL_Vh2crmEehZU_PMU6KS&authKey=ZSDz8hEREWSaPuxQV3gEwqGIaGjfRNnkB4rJjf0IvXhrSUGSGwQFmBA%2Boe8HFxyl&noverify=0&group_code=127358632) 点击按钮入群。
\ No newline at end of file
diff --git a/ry-api/doc/若依环境使用手册.docx b/ry-api/doc/若依环境使用手册.docx
new file mode 100644
index 0000000..19d2fc3
Binary files /dev/null and b/ry-api/doc/若依环境使用手册.docx differ
diff --git a/ry-api/pom.xml b/ry-api/pom.xml
new file mode 100644
index 0000000..8dfdedc
--- /dev/null
+++ b/ry-api/pom.xml
@@ -0,0 +1,243 @@
+
+
+ 4.0.0
+
+ com.ruoyi
+ ruoyi
+ 3.9.2
+
+ ruoyi
+ http://www.ruoyi.vip
+ 若依管理系统
+
+
+ 3.9.2
+ UTF-8
+ UTF-8
+ 17
+ 4.0.6
+ 4.0.1
+ 1.2.28
+ 8.1.1
+ 2.3.3
+ 4.1.0
+ 2.0.64
+ 7.3.0
+ 2.22.0
+ 4.1.2
+ 2.3
+ 0.9.1
+ 2.3.1
+ 3.0.3
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot.version}
+ pom
+ import
+
+
+
+
+ com.alibaba
+ druid-spring-boot-4-starter
+ ${druid.version}
+
+
+
+
+ nl.basjes.parse.useragent
+ yauaa
+ ${yauaa.version}
+
+
+
+
+ com.github.pagehelper
+ pagehelper-spring-boot-starter
+ ${pagehelper.boot.version}
+
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+ ${mybatis-spring-boot.version}
+
+
+
+ javax.xml.bind
+ jaxb-api
+ ${jaxb-api.version}
+
+
+
+
+ com.github.oshi
+ oshi-core
+ ${oshi.version}
+
+
+
+
+ org.springdoc
+ springdoc-openapi-starter-webmvc-ui
+ ${springdoc.version}
+
+
+
+
+ commons-io
+ commons-io
+ ${commons.io.version}
+
+
+
+
+ org.apache.poi
+ poi-ooxml
+ ${poi.version}
+
+
+
+
+ org.apache.velocity
+ velocity-engine-core
+ ${velocity.version}
+
+
+
+
+ com.alibaba.fastjson2
+ fastjson2
+ ${fastjson.version}
+
+
+
+
+ io.jsonwebtoken
+ jjwt
+ ${jwt.version}
+
+
+
+
+ pro.fessional
+ kaptcha
+ ${kaptcha.version}
+
+
+
+
+ com.ruoyi
+ ruoyi-quartz
+ ${ruoyi.version}
+
+
+
+
+ com.ruoyi
+ ruoyi-generator
+ ${ruoyi.version}
+
+
+
+
+ com.ruoyi
+ ruoyi-framework
+ ${ruoyi.version}
+
+
+
+
+ com.ruoyi
+ ruoyi-system
+ ${ruoyi.version}
+
+
+
+
+ com.ruoyi
+ ruoyi-business
+ ${ruoyi.version}
+
+
+
+
+ com.ruoyi
+ ruoyi-common
+ ${ruoyi.version}
+
+
+
+
+
+
+ ruoyi-admin
+ ruoyi-framework
+ ruoyi-system
+ ruoyi-business
+ ruoyi-quartz
+ ruoyi-generator
+ ruoyi-common
+
+ pom
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.13.0
+
+ true
+ ${java.version}
+ ${java.version}
+ ${project.build.sourceEncoding}
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot.version}
+
+ com.ruoyi.RuoYiApplication
+
+
+
+
+
+
+
+ public
+ aliyun nexus
+ https://maven.aliyun.com/repository/public
+
+ true
+
+
+
+
+
+
+ public
+ aliyun nexus
+ https://maven.aliyun.com/repository/public
+
+ true
+
+
+ false
+
+
+
+
+
\ No newline at end of file
diff --git a/ry-api/ruoyi-admin/pom.xml b/ry-api/ruoyi-admin/pom.xml
new file mode 100644
index 0000000..42f8acb
--- /dev/null
+++ b/ry-api/ruoyi-admin/pom.xml
@@ -0,0 +1,95 @@
+
+
+
+ ruoyi
+ com.ruoyi
+ 3.9.2
+
+ 4.0.0
+ jar
+ ruoyi-admin
+
+
+ web服务入口
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ true
+
+
+
+
+ org.springdoc
+ springdoc-openapi-starter-webmvc-ui
+
+
+
+
+ com.mysql
+ mysql-connector-j
+
+
+
+
+ com.ruoyi
+ ruoyi-framework
+
+
+
+
+ com.ruoyi
+ ruoyi-quartz
+
+
+
+
+ com.ruoyi
+ ruoyi-generator
+
+
+
+
+ com.ruoyi
+ ruoyi-business
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ true
+ com.ruoyi.RuoYiApplication
+
+
+
+
+ repackage
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-war-plugin
+ 3.1.0
+
+ false
+ ${project.artifactId}
+
+
+
+ ${project.artifactId}
+
+
+
\ No newline at end of file
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
new file mode 100644
index 0000000..d6f9167
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
@@ -0,0 +1,30 @@
+package com.ruoyi;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;
+
+/**
+ * 启动程序
+ *
+ * @author ruoyi
+ */
+@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
+public class RuoYiApplication
+{
+ public static void main(String[] args)
+ {
+ // System.setProperty("spring.devtools.restart.enabled", "false");
+ SpringApplication.run(RuoYiApplication.class, args);
+ System.out.println("(♥◠‿◠)ノ゙ 若依启动成功 ლ(´ڡ`ლ)゙ \n" +
+ " .-------. ____ __ \n" +
+ " | _ _ \\ \\ \\ / / \n" +
+ " | ( ' ) | \\ _. / ' \n" +
+ " |(_ o _) / _( )_ .' \n" +
+ " | (_,_).' __ ___(_ o _)' \n" +
+ " | |\\ \\ | || |(_,_)' \n" +
+ " | | \\ `' /| `-' / \n" +
+ " | | \\ / \\ / \n" +
+ " ''-' `'-' `-..-' ");
+ }
+}
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/RuoYiServletInitializer.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/RuoYiServletInitializer.java
new file mode 100644
index 0000000..6de67dc
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/RuoYiServletInitializer.java
@@ -0,0 +1,18 @@
+package com.ruoyi;
+
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+
+/**
+ * web容器中进行部署
+ *
+ * @author ruoyi
+ */
+public class RuoYiServletInitializer extends SpringBootServletInitializer
+{
+ @Override
+ protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
+ {
+ return application.sources(RuoYiApplication.class);
+ }
+}
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
new file mode 100644
index 0000000..d6dcf06
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
@@ -0,0 +1,94 @@
+package com.ruoyi.web.controller.common;
+
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import jakarta.annotation.Resource;
+import javax.imageio.ImageIO;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.FastByteArrayOutputStream;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.google.code.kaptcha.Producer;
+import com.ruoyi.common.config.RuoYiConfig;
+import com.ruoyi.common.constant.CacheConstants;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.redis.RedisCache;
+import com.ruoyi.common.utils.sign.Base64;
+import com.ruoyi.common.utils.uuid.IdUtils;
+import com.ruoyi.system.service.ISysConfigService;
+
+/**
+ * 验证码操作处理
+ *
+ * @author ruoyi
+ */
+@RestController
+public class CaptchaController
+{
+ @Resource(name = "captchaProducer")
+ private Producer captchaProducer;
+
+ @Resource(name = "captchaProducerMath")
+ private Producer captchaProducerMath;
+
+ @Autowired
+ private RedisCache redisCache;
+
+ @Autowired
+ private ISysConfigService configService;
+ /**
+ * 生成验证码
+ */
+ @GetMapping("/captchaImage")
+ public AjaxResult getCode(HttpServletResponse response) throws IOException
+ {
+ AjaxResult ajax = AjaxResult.success();
+ boolean captchaEnabled = configService.selectCaptchaEnabled();
+ ajax.put("captchaEnabled", captchaEnabled);
+ if (!captchaEnabled)
+ {
+ return ajax;
+ }
+
+ // 保存验证码信息
+ String uuid = IdUtils.simpleUUID();
+ String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
+
+ String capStr = null, code = null;
+ BufferedImage image = null;
+
+ // 生成验证码
+ String captchaType = RuoYiConfig.getCaptchaType();
+ if ("math".equals(captchaType))
+ {
+ String capText = captchaProducerMath.createText();
+ capStr = capText.substring(0, capText.lastIndexOf("@"));
+ code = capText.substring(capText.lastIndexOf("@") + 1);
+ image = captchaProducerMath.createImage(capStr);
+ }
+ else if ("char".equals(captchaType))
+ {
+ capStr = code = captchaProducer.createText();
+ image = captchaProducer.createImage(capStr);
+ }
+
+ redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
+ // 转换流信息写出
+ FastByteArrayOutputStream os = new FastByteArrayOutputStream();
+ try
+ {
+ ImageIO.write(image, "jpg", os);
+ }
+ catch (IOException e)
+ {
+ return AjaxResult.error(e.getMessage());
+ }
+
+ ajax.put("uuid", uuid);
+ ajax.put("img", Base64.encode(os.toByteArray()));
+ return ajax;
+ }
+}
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
new file mode 100644
index 0000000..a2333d5
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
@@ -0,0 +1,162 @@
+package com.ruoyi.web.controller.common;
+
+import java.util.ArrayList;
+import java.util.List;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+import com.ruoyi.common.config.RuoYiConfig;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.file.FileUploadUtils;
+import com.ruoyi.common.utils.file.FileUtils;
+import com.ruoyi.framework.config.ServerConfig;
+
+/**
+ * 通用请求处理
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/common")
+public class CommonController
+{
+ private static final Logger log = LoggerFactory.getLogger(CommonController.class);
+
+ @Autowired
+ private ServerConfig serverConfig;
+
+ private static final String FILE_DELIMITER = ",";
+
+ /**
+ * 通用下载请求
+ *
+ * @param fileName 文件名称
+ * @param delete 是否删除
+ */
+ @GetMapping("/download")
+ public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request)
+ {
+ try
+ {
+ if (!FileUtils.checkAllowDownload(fileName))
+ {
+ throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName));
+ }
+ String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
+ String filePath = RuoYiConfig.getDownloadPath() + fileName;
+
+ response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
+ FileUtils.setAttachmentResponseHeader(response, realFileName);
+ FileUtils.writeBytes(filePath, response.getOutputStream());
+ if (delete)
+ {
+ FileUtils.deleteFile(filePath);
+ }
+ }
+ catch (Exception e)
+ {
+ log.error("下载文件失败", e);
+ }
+ }
+
+ /**
+ * 通用上传请求(单个)
+ */
+ @PostMapping("/upload")
+ public AjaxResult uploadFile(MultipartFile file) throws Exception
+ {
+ try
+ {
+ // 上传文件路径
+ String filePath = RuoYiConfig.getUploadPath();
+ // 上传并返回新文件名称
+ String fileName = FileUploadUtils.upload(filePath, file);
+ String url = serverConfig.getUrl() + fileName;
+ AjaxResult ajax = AjaxResult.success();
+ ajax.put("url", url);
+ ajax.put("fileName", fileName);
+ ajax.put("newFileName", FileUtils.getName(fileName));
+ ajax.put("originalFilename", file.getOriginalFilename());
+ return ajax;
+ }
+ catch (Exception e)
+ {
+ return AjaxResult.error(e.getMessage());
+ }
+ }
+
+ /**
+ * 通用上传请求(多个)
+ */
+ @PostMapping("/uploads")
+ public AjaxResult uploadFiles(List files) throws Exception
+ {
+ try
+ {
+ // 上传文件路径
+ String filePath = RuoYiConfig.getUploadPath();
+ List urls = new ArrayList();
+ List fileNames = new ArrayList();
+ List newFileNames = new ArrayList();
+ List originalFilenames = new ArrayList();
+ for (MultipartFile file : files)
+ {
+ // 上传并返回新文件名称
+ String fileName = FileUploadUtils.upload(filePath, file);
+ String url = serverConfig.getUrl() + fileName;
+ urls.add(url);
+ fileNames.add(fileName);
+ newFileNames.add(FileUtils.getName(fileName));
+ originalFilenames.add(file.getOriginalFilename());
+ }
+ AjaxResult ajax = AjaxResult.success();
+ ajax.put("urls", StringUtils.join(urls, FILE_DELIMITER));
+ ajax.put("fileNames", StringUtils.join(fileNames, FILE_DELIMITER));
+ ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMITER));
+ ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMITER));
+ return ajax;
+ }
+ catch (Exception e)
+ {
+ return AjaxResult.error(e.getMessage());
+ }
+ }
+
+ /**
+ * 本地资源通用下载
+ */
+ @GetMapping("/download/resource")
+ public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response)
+ throws Exception
+ {
+ try
+ {
+ if (!FileUtils.checkAllowDownload(resource))
+ {
+ throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource));
+ }
+ // 本地资源路径
+ String localPath = RuoYiConfig.getProfile();
+ // 数据库资源地址
+ String downloadPath = localPath + FileUtils.stripPrefix(resource);
+ // 下载名称
+ String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
+ response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
+ FileUtils.setAttachmentResponseHeader(response, downloadName);
+ FileUtils.writeBytes(downloadPath, response.getOutputStream());
+ }
+ catch (Exception e)
+ {
+ log.error("下载文件失败", e);
+ }
+ }
+}
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/OssController.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/OssController.java
new file mode 100644
index 0000000..944838f
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/OssController.java
@@ -0,0 +1,170 @@
+package com.ruoyi.web.controller.common;
+
+import java.nio.charset.StandardCharsets;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URLConnection;
+import java.util.Date;
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.config.RuoYiConfig;
+import com.ruoyi.common.config.RuoYiConfig.OssProperties;
+import com.ruoyi.common.core.domain.AjaxResult;
+
+/**
+ * 阿里云 OSS 签名服务
+ *
+ * 用于前端 直传 OSS: 前端先 GET /common/oss/sign?dir=xxx
+ * 拿到 {host, dir, accessKeyId, policy, signature} 后直接 POST 到 OSS,
+ * 不再走后端中转. secretKey 不下发到前端.
+ *
+ * 配置项 (ruoyi.oss.*):
+ * enabled: 是否启用 OSS (false 时返回空, 前端 fallback 到 /common/upload 本地存储)
+ * endpoint: https://.oss-cn-beijing.aliyuncs.com
+ * bucket: bucket 名称
+ * accessKeyId: AK
+ * accessKeySecret: SK (仅后端使用)
+ * dirPrefix: 上传目录前缀, 默认 "ry8080/"
+ * expireSeconds: 签名失效时间, 默认 3600
+ */
+@RestController
+@RequestMapping("/common/oss")
+public class OssController
+{
+ @org.springframework.beans.factory.annotation.Autowired
+ private RuoYiConfig ruoyiConfig;
+
+ @GetMapping("/sign")
+ public AjaxResult sign(String dir)
+ {
+ OssProperties props = ruoyiConfig.getOss();
+ if (props == null || !props.isEnabled())
+ {
+ return AjaxResult.error("OSS 未启用 (ruoyi.oss.enabled=false)");
+ }
+ if (dir == null || dir.isEmpty())
+ {
+ dir = props.getDirPrefix();
+ }
+ // 不允许目录穿越
+ if (dir.contains(".."))
+ {
+ return AjaxResult.error("非法目录");
+ }
+ long expire = props.getExpireSeconds() * 1000L;
+ Date expiration = new Date(System.currentTimeMillis() + expire);
+
+ // OSS PostObject policy 文档: https://help.aliyun.com/document_detail/31988.html
+ // expiration 格式: yyyy-MM-ddTHH:mm:ss.SSSZ (OSS 严格解析, 毫秒必须 3 位)
+ // 注: OSS conditions 是 AND 关系, 不支持 OR 嵌套; Content-Type 不在 policy 中限制,
+ // 由前端 FormData 字段 'Content-Type' 携带, OSS 按此存文件元数据
+ String policyText = "{\"expiration\":\"" + toISO8601(expiration)
+ + "\",\"conditions\":["
+ + "[\"content-length-range\",0,104857600],"
+ + "[\"starts-with\",\"$key\",\"" + dir + "\"]"
+ + "]}";
+ String policyBase64 = java.util.Base64.getEncoder().encodeToString(
+ policyText.getBytes(StandardCharsets.UTF_8));
+ String signature = hmacSha1Base64(props.getAccessKeySecret(), policyBase64);
+
+ AjaxResult ajax = AjaxResult.success();
+ ajax.put("host", props.getEndpoint());
+ ajax.put("dir", dir);
+ ajax.put("accessKeyId", props.getAccessKeyId());
+ ajax.put("policy", policyBase64);
+ ajax.put("signature", signature);
+ ajax.put("expire", expiration.getTime());
+ return ajax;
+ }
+
+ /** OSS 期望 ISO8601 (yyyy-MM-ddTHH:mm:ss.SSS'Z') GMT 时间 */
+ private static String toISO8601(Date d)
+ {
+ java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
+ sdf.setTimeZone(java.util.TimeZone.getTimeZone("GMT"));
+ return sdf.format(d);
+ }
+
+ private static String hmacSha1Base64(String key, String data)
+ {
+ try
+ {
+ Mac mac = Mac.getInstance("HmacSHA1");
+ mac.init(new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA1"));
+ byte[] bytes = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
+ return java.util.Base64.getEncoder().encodeToString(bytes);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("OSS 签名失败", e);
+ }
+ }
+
+ /**
+ * OSS 文件代理: OSS bucket 设置了 Content-Disposition: attachment,
+ * 直接 iframe/embed 会被强制下载. 此接口转发 OSS 字节流并重写 header,
+ * 让浏览器内嵌预览 (PDF/图片).
+ * 公开访问, 无需 token (SecurityConfig 已对 /common/oss/** 公开).
+ *
+ * @param url 完整 OSS URL (前端从 biz_project.invitationUrl 等字段拿到)
+ */
+ @GetMapping("/proxy")
+ public void ossProxy(@RequestParam String url, HttpServletResponse response) throws Exception
+ {
+ // 安全: 仅允许代理 hwtossbamlorgcn bucket (防止 SSRF 攻击)
+ if (url == null || !url.contains("hwtossbamlorgcn.oss-cn-beijing.aliyuncs.com"))
+ {
+ response.setStatus(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+ URI uri = URI.create(url);
+ URLConnection conn = uri.toURL().openConnection();
+ conn.setConnectTimeout(10000);
+ conn.setReadTimeout(30000);
+
+ String origCt = conn.getContentType();
+ String path = uri.getPath();
+ String filename = path.substring(path.lastIndexOf('/') + 1);
+
+ // 重写 Content-Type: OSS 可能返回 octet-stream, 按扩展名强制给正确 mime
+ String ct = origCt;
+ if (ct == null || ct.contains("octet-stream") || ct.isEmpty())
+ {
+ String lower = filename.toLowerCase();
+ if (lower.endsWith(".pdf")) ct = "application/pdf";
+ else if (lower.endsWith(".png")) ct = "image/png";
+ else if (lower.endsWith(".jpg") || lower.endsWith(".jpeg")) ct = "image/jpeg";
+ else if (lower.endsWith(".gif")) ct = "image/gif";
+ else if (lower.endsWith(".webp")) ct = "image/webp";
+ else ct = origCt != null ? origCt : "application/octet-stream";
+ }
+
+ // 关键: 重写 Content-Disposition 为 inline (OSS 默认是 attachment)
+ response.setContentType(ct);
+ response.setHeader("Content-Disposition", "inline; filename=\"" + filename + "\"");
+ response.setHeader("Cache-Control", "public, max-age=3600");
+
+ try (InputStream in = conn.getInputStream())
+ {
+ byte[] buf = new byte[8192];
+ int n;
+ while ((n = in.read(buf)) > 0)
+ {
+ response.getOutputStream().write(buf, 0, n);
+ }
+ }
+ catch (java.io.FileNotFoundException e)
+ {
+ // OSS 返回 404 (文件不存在) - 返回 404 而非 500 + application/json
+ // 避免前端 embed 拿到 JSON 后误渲染
+ response.setStatus(HttpServletResponse.SC_NOT_FOUND);
+ response.setContentType("text/plain;charset=utf-8");
+ response.getWriter().write("FILE_NOT_FOUND");
+ }
+ }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java
new file mode 100644
index 0000000..d17bd66
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java
@@ -0,0 +1,122 @@
+package com.ruoyi.web.controller.monitor;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeSet;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisCallback;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.constant.CacheConstants;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.system.domain.SysCache;
+
+/**
+ * 缓存监控
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/monitor/cache")
+public class CacheController
+{
+ @Autowired
+ private RedisTemplate redisTemplate;
+
+ private final static List caches = new ArrayList();
+ {
+ caches.add(new SysCache(CacheConstants.LOGIN_TOKEN_KEY, "用户信息"));
+ caches.add(new SysCache(CacheConstants.SYS_CONFIG_KEY, "配置信息"));
+ caches.add(new SysCache(CacheConstants.SYS_DICT_KEY, "数据字典"));
+ caches.add(new SysCache(CacheConstants.CAPTCHA_CODE_KEY, "验证码"));
+ caches.add(new SysCache(CacheConstants.REPEAT_SUBMIT_KEY, "防重提交"));
+ caches.add(new SysCache(CacheConstants.RATE_LIMIT_KEY, "限流处理"));
+ caches.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "密码错误次数"));
+ }
+
+ @SuppressWarnings("deprecation")
+ @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+ @GetMapping()
+ public AjaxResult getInfo() throws Exception
+ {
+ Properties info = (Properties) redisTemplate.execute((RedisCallback) connection -> connection.info());
+ Properties commandStats = (Properties) redisTemplate.execute((RedisCallback) connection -> connection.info("commandstats"));
+ Object dbSize = redisTemplate.execute((RedisCallback) connection -> connection.dbSize());
+
+ Map result = new HashMap<>(3);
+ result.put("info", info);
+ result.put("dbSize", dbSize);
+
+ List> pieList = new ArrayList<>();
+ commandStats.stringPropertyNames().forEach(key -> {
+ Map data = new HashMap<>(2);
+ String property = commandStats.getProperty(key);
+ data.put("name", StringUtils.removeStart(key, "cmdstat_"));
+ data.put("value", StringUtils.substringBetween(property, "calls=", ",usec"));
+ pieList.add(data);
+ });
+ result.put("commandStats", pieList);
+ return AjaxResult.success(result);
+ }
+
+ @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+ @GetMapping("/getNames")
+ public AjaxResult cache()
+ {
+ return AjaxResult.success(caches);
+ }
+
+ @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+ @GetMapping("/getKeys/{cacheName}")
+ public AjaxResult getCacheKeys(@PathVariable String cacheName)
+ {
+ Set cacheKeys = redisTemplate.keys(cacheName + "*");
+ return AjaxResult.success(new TreeSet<>(cacheKeys));
+ }
+
+ @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+ @GetMapping("/getValue/{cacheName}/{cacheKey}")
+ public AjaxResult getCacheValue(@PathVariable String cacheName, @PathVariable String cacheKey)
+ {
+ String cacheValue = redisTemplate.opsForValue().get(cacheKey);
+ SysCache sysCache = new SysCache(cacheName, cacheKey, cacheValue);
+ return AjaxResult.success(sysCache);
+ }
+
+ @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+ @DeleteMapping("/clearCacheName/{cacheName}")
+ public AjaxResult clearCacheName(@PathVariable String cacheName)
+ {
+ Collection cacheKeys = redisTemplate.keys(cacheName + "*");
+ redisTemplate.delete(cacheKeys);
+ return AjaxResult.success();
+ }
+
+ @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+ @DeleteMapping("/clearCacheKey/{cacheKey}")
+ public AjaxResult clearCacheKey(@PathVariable String cacheKey)
+ {
+ redisTemplate.delete(cacheKey);
+ return AjaxResult.success();
+ }
+
+ @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+ @DeleteMapping("/clearCacheAll")
+ public AjaxResult clearCacheAll()
+ {
+ Collection cacheKeys = redisTemplate.keys("*");
+ redisTemplate.delete(cacheKeys);
+ return AjaxResult.success();
+ }
+}
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/ServerController.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/ServerController.java
new file mode 100644
index 0000000..cc805ad
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/ServerController.java
@@ -0,0 +1,27 @@
+package com.ruoyi.web.controller.monitor;
+
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.framework.web.domain.Server;
+
+/**
+ * 服务器监控
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/monitor/server")
+public class ServerController
+{
+ @PreAuthorize("@ss.hasPermi('monitor:server:list')")
+ @GetMapping()
+ public AjaxResult getInfo() throws Exception
+ {
+ Server server = new Server();
+ server.copyTo();
+ return AjaxResult.success(server);
+ }
+}
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java
new file mode 100644
index 0000000..f6fac71
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java
@@ -0,0 +1,82 @@
+package com.ruoyi.web.controller.monitor;
+
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.framework.web.service.SysPasswordService;
+import com.ruoyi.system.domain.SysLogininfor;
+import com.ruoyi.system.service.ISysLogininforService;
+
+/**
+ * 系统访问记录
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/monitor/logininfor")
+public class SysLogininforController extends BaseController
+{
+ @Autowired
+ private ISysLogininforService logininforService;
+
+ @Autowired
+ private SysPasswordService passwordService;
+
+ @PreAuthorize("@ss.hasPermi('monitor:logininfor:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(SysLogininfor logininfor)
+ {
+ startPage();
+ List list = logininforService.selectLogininforList(logininfor);
+ return getDataTable(list);
+ }
+
+ @Log(title = "登录日志", businessType = BusinessType.EXPORT)
+ @PreAuthorize("@ss.hasPermi('monitor:logininfor:export')")
+ @PostMapping("/export")
+ public void export(HttpServletResponse response, SysLogininfor logininfor)
+ {
+ List list = logininforService.selectLogininforList(logininfor);
+ ExcelUtil util = new ExcelUtil(SysLogininfor.class);
+ util.exportExcel(response, list, "登录日志");
+ }
+
+ @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
+ @Log(title = "登录日志", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{infoIds}")
+ public AjaxResult remove(@PathVariable Long[] infoIds)
+ {
+ return toAjax(logininforService.deleteLogininforByIds(infoIds));
+ }
+
+ @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
+ @Log(title = "登录日志", businessType = BusinessType.CLEAN)
+ @DeleteMapping("/clean")
+ public AjaxResult clean()
+ {
+ logininforService.cleanLogininfor();
+ return success();
+ }
+
+ @PreAuthorize("@ss.hasPermi('monitor:logininfor:unlock')")
+ @Log(title = "账户解锁", businessType = BusinessType.OTHER)
+ @GetMapping("/unlock/{userName}")
+ public AjaxResult unlock(@PathVariable("userName") String userName)
+ {
+ passwordService.clearLoginRecordCache(userName);
+ return success();
+ }
+}
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java
new file mode 100644
index 0000000..f056d65
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java
@@ -0,0 +1,69 @@
+package com.ruoyi.web.controller.monitor;
+
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.system.domain.SysOperLog;
+import com.ruoyi.system.service.ISysOperLogService;
+
+/**
+ * 操作日志记录
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/monitor/operlog")
+public class SysOperlogController extends BaseController
+{
+ @Autowired
+ private ISysOperLogService operLogService;
+
+ @PreAuthorize("@ss.hasPermi('monitor:operlog:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(SysOperLog operLog)
+ {
+ startPage();
+ List list = operLogService.selectOperLogList(operLog);
+ return getDataTable(list);
+ }
+
+ @Log(title = "操作日志", businessType = BusinessType.EXPORT)
+ @PreAuthorize("@ss.hasPermi('monitor:operlog:export')")
+ @PostMapping("/export")
+ public void export(HttpServletResponse response, SysOperLog operLog)
+ {
+ List list = operLogService.selectOperLogList(operLog);
+ ExcelUtil util = new ExcelUtil(SysOperLog.class);
+ util.exportExcel(response, list, "操作日志");
+ }
+
+ @Log(title = "操作日志", businessType = BusinessType.DELETE)
+ @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
+ @DeleteMapping("/{operIds}")
+ public AjaxResult remove(@PathVariable Long[] operIds)
+ {
+ return toAjax(operLogService.deleteOperLogByIds(operIds));
+ }
+
+ @Log(title = "操作日志", businessType = BusinessType.CLEAN)
+ @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
+ @DeleteMapping("/clean")
+ public AjaxResult clean()
+ {
+ operLogService.cleanOperLog();
+ return success();
+ }
+}
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java
new file mode 100644
index 0000000..a442863
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java
@@ -0,0 +1,83 @@
+package com.ruoyi.web.controller.monitor;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.constant.CacheConstants;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.model.LoginUser;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.core.redis.RedisCache;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.system.domain.SysUserOnline;
+import com.ruoyi.system.service.ISysUserOnlineService;
+
+/**
+ * 在线用户监控
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/monitor/online")
+public class SysUserOnlineController extends BaseController
+{
+ @Autowired
+ private ISysUserOnlineService userOnlineService;
+
+ @Autowired
+ private RedisCache redisCache;
+
+ @PreAuthorize("@ss.hasPermi('monitor:online:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(String ipaddr, String userName)
+ {
+ Collection keys = redisCache.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
+ List userOnlineList = new ArrayList();
+ for (String key : keys)
+ {
+ LoginUser user = redisCache.getCacheObject(key);
+ if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName))
+ {
+ userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
+ }
+ else if (StringUtils.isNotEmpty(ipaddr))
+ {
+ userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
+ }
+ else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser()))
+ {
+ userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
+ }
+ else
+ {
+ userOnlineList.add(userOnlineService.loginUserToUserOnline(user));
+ }
+ }
+ Collections.reverse(userOnlineList);
+ userOnlineList.removeAll(Collections.singleton(null));
+ return getDataTable(userOnlineList);
+ }
+
+ /**
+ * 强退用户
+ */
+ @PreAuthorize("@ss.hasPermi('monitor:online:forceLogout')")
+ @Log(title = "在线用户", businessType = BusinessType.FORCE)
+ @DeleteMapping("/{tokenId}")
+ public AjaxResult forceLogout(@PathVariable String tokenId)
+ {
+ redisCache.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId);
+ return success();
+ }
+}
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java
new file mode 100644
index 0000000..91a854f
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java
@@ -0,0 +1,133 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.system.domain.SysConfig;
+import com.ruoyi.system.service.ISysConfigService;
+
+/**
+ * 参数配置 信息操作处理
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/config")
+public class SysConfigController extends BaseController
+{
+ @Autowired
+ private ISysConfigService configService;
+
+ /**
+ * 获取参数配置列表
+ */
+ @PreAuthorize("@ss.hasPermi('system:config:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(SysConfig config)
+ {
+ startPage();
+ List list = configService.selectConfigList(config);
+ return getDataTable(list);
+ }
+
+ @Log(title = "参数管理", businessType = BusinessType.EXPORT)
+ @PreAuthorize("@ss.hasPermi('system:config:export')")
+ @PostMapping("/export")
+ public void export(HttpServletResponse response, SysConfig config)
+ {
+ List list = configService.selectConfigList(config);
+ ExcelUtil util = new ExcelUtil(SysConfig.class);
+ util.exportExcel(response, list, "参数数据");
+ }
+
+ /**
+ * 根据参数编号获取详细信息
+ */
+ @PreAuthorize("@ss.hasPermi('system:config:query')")
+ @GetMapping(value = "/{configId}")
+ public AjaxResult getInfo(@PathVariable Long configId)
+ {
+ return success(configService.selectConfigById(configId));
+ }
+
+ /**
+ * 根据参数键名查询参数值
+ */
+ @GetMapping(value = "/configKey/{configKey}")
+ public AjaxResult getConfigKey(@PathVariable String configKey)
+ {
+ return success(configService.selectConfigByKey(configKey));
+ }
+
+ /**
+ * 新增参数配置
+ */
+ @PreAuthorize("@ss.hasPermi('system:config:add')")
+ @Log(title = "参数管理", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@Validated @RequestBody SysConfig config)
+ {
+ if (!configService.checkConfigKeyUnique(config))
+ {
+ return error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在");
+ }
+ config.setCreateBy(getUsername());
+ return toAjax(configService.insertConfig(config));
+ }
+
+ /**
+ * 修改参数配置
+ */
+ @PreAuthorize("@ss.hasPermi('system:config:edit')")
+ @Log(title = "参数管理", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@Validated @RequestBody SysConfig config)
+ {
+ if (!configService.checkConfigKeyUnique(config))
+ {
+ return error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在");
+ }
+ config.setUpdateBy(getUsername());
+ return toAjax(configService.updateConfig(config));
+ }
+
+ /**
+ * 删除参数配置
+ */
+ @PreAuthorize("@ss.hasPermi('system:config:remove')")
+ @Log(title = "参数管理", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{configIds}")
+ public AjaxResult remove(@PathVariable Long[] configIds)
+ {
+ configService.deleteConfigByIds(configIds);
+ return success();
+ }
+
+ /**
+ * 刷新参数缓存
+ */
+ @PreAuthorize("@ss.hasPermi('system:config:remove')")
+ @Log(title = "参数管理", businessType = BusinessType.CLEAN)
+ @DeleteMapping("/refreshCache")
+ public AjaxResult refreshCache()
+ {
+ configService.resetConfigCache();
+ return success();
+ }
+}
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java
new file mode 100644
index 0000000..343503c
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java
@@ -0,0 +1,147 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.lang3.ArrayUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.entity.SysDept;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.system.service.ISysDeptService;
+
+/**
+ * 部门信息
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/dept")
+public class SysDeptController extends BaseController
+{
+ @Autowired
+ private ISysDeptService deptService;
+
+ /**
+ * 获取部门列表
+ */
+ @PreAuthorize("@ss.hasPermi('system:dept:list')")
+ @GetMapping("/list")
+ public AjaxResult list(SysDept dept)
+ {
+ List depts = deptService.selectDeptList(dept);
+ return success(depts);
+ }
+
+ /**
+ * 查询部门列表(排除节点)
+ */
+ @PreAuthorize("@ss.hasPermi('system:dept:list')")
+ @GetMapping("/list/exclude/{deptId}")
+ public AjaxResult excludeChild(@PathVariable(value = "deptId", required = false) Long deptId)
+ {
+ List depts = deptService.selectDeptList(new SysDept());
+ depts.removeIf(d -> d.getDeptId().intValue() == deptId || ArrayUtils.contains(StringUtils.split(d.getAncestors(), ","), deptId + ""));
+ return success(depts);
+ }
+
+ /**
+ * 根据部门编号获取详细信息
+ */
+ @PreAuthorize("@ss.hasPermi('system:dept:query')")
+ @GetMapping(value = "/{deptId}")
+ public AjaxResult getInfo(@PathVariable Long deptId)
+ {
+ deptService.checkDeptDataScope(deptId);
+ return success(deptService.selectDeptById(deptId));
+ }
+
+ /**
+ * 新增部门
+ */
+ @PreAuthorize("@ss.hasPermi('system:dept:add')")
+ @Log(title = "部门管理", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@Validated @RequestBody SysDept dept)
+ {
+ if (!deptService.checkDeptNameUnique(dept))
+ {
+ return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在");
+ }
+ dept.setCreateBy(getUsername());
+ return toAjax(deptService.insertDept(dept));
+ }
+
+ /**
+ * 修改部门
+ */
+ @PreAuthorize("@ss.hasPermi('system:dept:edit')")
+ @Log(title = "部门管理", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@Validated @RequestBody SysDept dept)
+ {
+ Long deptId = dept.getDeptId();
+ deptService.checkDeptDataScope(deptId);
+ if (!deptService.checkDeptNameUnique(dept))
+ {
+ return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");
+ }
+ else if (dept.getParentId().equals(deptId))
+ {
+ return error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己");
+ }
+ else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0)
+ {
+ return error("该部门包含未停用的子部门!");
+ }
+ dept.setUpdateBy(getUsername());
+ return toAjax(deptService.updateDept(dept));
+ }
+
+ /**
+ * 保存部门排序
+ */
+ @PreAuthorize("@ss.hasPermi('system:dept:edit')")
+ @Log(title = "保存部门排序", businessType = BusinessType.UPDATE)
+ @PutMapping("/updateSort")
+ public AjaxResult updateSort(@RequestBody Map params)
+ {
+ String[] deptIds = params.get("deptIds").split(",");
+ String[] orderNums = params.get("orderNums").split(",");
+ deptService.updateDeptSort(deptIds, orderNums);
+ return success();
+ }
+
+ /**
+ * 删除部门
+ */
+ @PreAuthorize("@ss.hasPermi('system:dept:remove')")
+ @Log(title = "部门管理", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{deptId}")
+ public AjaxResult remove(@PathVariable Long deptId)
+ {
+ if (deptService.hasChildByDeptId(deptId))
+ {
+ return warn("存在下级部门,不允许删除");
+ }
+ if (deptService.checkDeptExistUser(deptId))
+ {
+ return warn("部门存在用户,不允许删除");
+ }
+ deptService.checkDeptDataScope(deptId);
+ return toAjax(deptService.deleteDeptById(deptId));
+ }
+}
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java
new file mode 100644
index 0000000..f65492b
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java
@@ -0,0 +1,121 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.ArrayList;
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.entity.SysDictData;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.system.service.ISysDictDataService;
+import com.ruoyi.system.service.ISysDictTypeService;
+
+/**
+ * 数据字典信息
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/dict/data")
+public class SysDictDataController extends BaseController
+{
+ @Autowired
+ private ISysDictDataService dictDataService;
+
+ @Autowired
+ private ISysDictTypeService dictTypeService;
+
+ @PreAuthorize("@ss.hasPermi('system:dict:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(SysDictData dictData)
+ {
+ startPage();
+ List list = dictDataService.selectDictDataList(dictData);
+ return getDataTable(list);
+ }
+
+ @Log(title = "字典数据", businessType = BusinessType.EXPORT)
+ @PreAuthorize("@ss.hasPermi('system:dict:export')")
+ @PostMapping("/export")
+ public void export(HttpServletResponse response, SysDictData dictData)
+ {
+ List list = dictDataService.selectDictDataList(dictData);
+ ExcelUtil util = new ExcelUtil(SysDictData.class);
+ util.exportExcel(response, list, "字典数据");
+ }
+
+ /**
+ * 查询字典数据详细
+ */
+ @PreAuthorize("@ss.hasPermi('system:dict:query')")
+ @GetMapping(value = "/{dictCode}")
+ public AjaxResult getInfo(@PathVariable Long dictCode)
+ {
+ return success(dictDataService.selectDictDataById(dictCode));
+ }
+
+ /**
+ * 根据字典类型查询字典数据信息
+ */
+ @GetMapping(value = "/type/{dictType}")
+ public AjaxResult dictType(@PathVariable String dictType)
+ {
+ List data = dictTypeService.selectDictDataByType(dictType);
+ if (StringUtils.isNull(data))
+ {
+ data = new ArrayList();
+ }
+ return success(data);
+ }
+
+ /**
+ * 新增字典类型
+ */
+ @PreAuthorize("@ss.hasPermi('system:dict:add')")
+ @Log(title = "字典数据", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@Validated @RequestBody SysDictData dict)
+ {
+ dict.setCreateBy(getUsername());
+ return toAjax(dictDataService.insertDictData(dict));
+ }
+
+ /**
+ * 修改保存字典类型
+ */
+ @PreAuthorize("@ss.hasPermi('system:dict:edit')")
+ @Log(title = "字典数据", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@Validated @RequestBody SysDictData dict)
+ {
+ dict.setUpdateBy(getUsername());
+ return toAjax(dictDataService.updateDictData(dict));
+ }
+
+ /**
+ * 删除字典类型
+ */
+ @PreAuthorize("@ss.hasPermi('system:dict:remove')")
+ @Log(title = "字典类型", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{dictCodes}")
+ public AjaxResult remove(@PathVariable Long[] dictCodes)
+ {
+ dictDataService.deleteDictDataByIds(dictCodes);
+ return success();
+ }
+}
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java
new file mode 100644
index 0000000..3ff314c
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java
@@ -0,0 +1,131 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.entity.SysDictType;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.system.service.ISysDictTypeService;
+
+/**
+ * 数据字典信息
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/dict/type")
+public class SysDictTypeController extends BaseController
+{
+ @Autowired
+ private ISysDictTypeService dictTypeService;
+
+ @PreAuthorize("@ss.hasPermi('system:dict:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(SysDictType dictType)
+ {
+ startPage();
+ List list = dictTypeService.selectDictTypeList(dictType);
+ return getDataTable(list);
+ }
+
+ @Log(title = "字典类型", businessType = BusinessType.EXPORT)
+ @PreAuthorize("@ss.hasPermi('system:dict:export')")
+ @PostMapping("/export")
+ public void export(HttpServletResponse response, SysDictType dictType)
+ {
+ List list = dictTypeService.selectDictTypeList(dictType);
+ ExcelUtil util = new ExcelUtil(SysDictType.class);
+ util.exportExcel(response, list, "字典类型");
+ }
+
+ /**
+ * 查询字典类型详细
+ */
+ @PreAuthorize("@ss.hasPermi('system:dict:query')")
+ @GetMapping(value = "/{dictId}")
+ public AjaxResult getInfo(@PathVariable Long dictId)
+ {
+ return success(dictTypeService.selectDictTypeById(dictId));
+ }
+
+ /**
+ * 新增字典类型
+ */
+ @PreAuthorize("@ss.hasPermi('system:dict:add')")
+ @Log(title = "字典类型", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@Validated @RequestBody SysDictType dict)
+ {
+ if (!dictTypeService.checkDictTypeUnique(dict))
+ {
+ return error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在");
+ }
+ dict.setCreateBy(getUsername());
+ return toAjax(dictTypeService.insertDictType(dict));
+ }
+
+ /**
+ * 修改字典类型
+ */
+ @PreAuthorize("@ss.hasPermi('system:dict:edit')")
+ @Log(title = "字典类型", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@Validated @RequestBody SysDictType dict)
+ {
+ if (!dictTypeService.checkDictTypeUnique(dict))
+ {
+ return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在");
+ }
+ dict.setUpdateBy(getUsername());
+ return toAjax(dictTypeService.updateDictType(dict));
+ }
+
+ /**
+ * 删除字典类型
+ */
+ @PreAuthorize("@ss.hasPermi('system:dict:remove')")
+ @Log(title = "字典类型", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{dictIds}")
+ public AjaxResult remove(@PathVariable Long[] dictIds)
+ {
+ dictTypeService.deleteDictTypeByIds(dictIds);
+ return success();
+ }
+
+ /**
+ * 刷新字典缓存
+ */
+ @PreAuthorize("@ss.hasPermi('system:dict:remove')")
+ @Log(title = "字典类型", businessType = BusinessType.CLEAN)
+ @DeleteMapping("/refreshCache")
+ public AjaxResult refreshCache()
+ {
+ dictTypeService.resetDictCache();
+ return success();
+ }
+
+ /**
+ * 获取字典选择框列表
+ */
+ @GetMapping("/optionselect")
+ public AjaxResult optionselect()
+ {
+ List dictTypes = dictTypeService.selectDictTypeAll();
+ return success(dictTypes);
+ }
+}
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java
new file mode 100644
index 0000000..f2ce93c
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java
@@ -0,0 +1,64 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.Map;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.config.RuoYiConfig;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.system.service.ISysUserService;
+
+/**
+ * 首页
+ *
+ * @author ruoyi
+ */
+@RestController
+public class SysIndexController
+{
+ /** 系统基础配置 */
+ @Autowired
+ private RuoYiConfig ruoyiConfig;
+
+ @Autowired
+ private ISysUserService userService;
+
+ /**
+ * 访问首页,提示语
+ */
+ @RequestMapping("/")
+ public String index()
+ {
+ return StringUtils.format("欢迎使用{}后台管理框架,当前版本:v{},请通过前端地址访问。", ruoyiConfig.getName(), ruoyiConfig.getVersion());
+ }
+
+ /**
+ * 解锁屏幕
+ */
+ @PostMapping("/unlockscreen")
+ public AjaxResult unlockScreen(@RequestBody Map body)
+ {
+ String password = body.get("password");
+ if (StringUtils.isEmpty(password))
+ {
+ return AjaxResult.error("密码不能为空");
+ }
+ String username = SecurityUtils.getUsername();
+ SysUser user = userService.selectUserByUserName(username);
+ if (user == null)
+ {
+ return AjaxResult.error("服务器超时,请重新登录");
+ }
+ if (!SecurityUtils.matchesPassword(password, user.getPassword()))
+ {
+ return AjaxResult.error("密码错误,请重新输入");
+ }
+
+ return AjaxResult.success("解锁成功");
+ }
+}
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
new file mode 100644
index 0000000..7719c89
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
@@ -0,0 +1,138 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.entity.SysMenu;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.core.domain.model.LoginBody;
+import com.ruoyi.common.core.domain.model.LoginUser;
+import com.ruoyi.common.core.text.Convert;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.web.service.SysLoginService;
+import com.ruoyi.framework.web.service.SysPermissionService;
+import com.ruoyi.framework.web.service.TokenService;
+import com.ruoyi.system.service.ISysConfigService;
+import com.ruoyi.system.service.ISysMenuService;
+
+/**
+ * 登录验证
+ *
+ * @author ruoyi
+ */
+@RestController
+public class SysLoginController
+{
+ @Autowired
+ private SysLoginService loginService;
+
+ @Autowired
+ private ISysMenuService menuService;
+
+ @Autowired
+ private SysPermissionService permissionService;
+
+ @Autowired
+ private TokenService tokenService;
+
+ @Autowired
+ private ISysConfigService configService;
+
+ /**
+ * 登录方法
+ *
+ * @param loginBody 登录信息
+ * @return 结果
+ */
+ @PostMapping("/login")
+ public AjaxResult login(@RequestBody LoginBody loginBody)
+ {
+ AjaxResult ajax = AjaxResult.success();
+ // 生成令牌
+ String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
+ loginBody.getUuid());
+ ajax.put(Constants.TOKEN, token);
+ return ajax;
+ }
+
+ /**
+ * 获取用户信息
+ *
+ * @return 用户信息
+ */
+ @GetMapping("getInfo")
+ public AjaxResult getInfo()
+ {
+ LoginUser loginUser = SecurityUtils.getLoginUser();
+ SysUser user = loginUser.getUser();
+ // 角色集合
+ Set roles = permissionService.getRolePermission(user);
+ // 权限集合
+ Set permissions = permissionService.getMenuPermission(user);
+ if (!loginUser.getPermissions().equals(permissions))
+ {
+ loginUser.setPermissions(permissions);
+ tokenService.refreshToken(loginUser);
+ }
+ AjaxResult ajax = AjaxResult.success();
+ ajax.put("user", user);
+ ajax.put("roles", roles);
+ ajax.put("permissions", permissions);
+ ajax.put("pwdChrtype", getSysAccountChrtype());
+ ajax.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate()));
+ ajax.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate()));
+ return ajax;
+ }
+
+ /**
+ * 获取路由信息
+ *
+ * @return 路由信息
+ */
+ @GetMapping("getRouters")
+ public AjaxResult getRouters()
+ {
+ Long userId = SecurityUtils.getUserId();
+ List menus = menuService.selectMenuTreeByUserId(userId);
+ return AjaxResult.success(menuService.buildMenus(menus));
+ }
+
+ // 获取用户密码自定义配置规则
+ public String getSysAccountChrtype()
+ {
+ return Convert.toStr(configService.selectConfigByKey("sys.account.chrtype"), "0");
+ }
+
+ // 检查初始密码是否提醒修改
+ public boolean initPasswordIsModify(Date pwdUpdateDate)
+ {
+ Integer initPasswordModify = Convert.toInt(configService.selectConfigByKey("sys.account.initPasswordModify"));
+ return initPasswordModify != null && initPasswordModify == 1 && pwdUpdateDate == null;
+ }
+
+ // 检查密码是否过期
+ public boolean passwordIsExpiration(Date pwdUpdateDate)
+ {
+ Integer passwordValidateDays = Convert.toInt(configService.selectConfigByKey("sys.account.passwordValidateDays"));
+ if (passwordValidateDays != null && passwordValidateDays > 0)
+ {
+ if (StringUtils.isNull(pwdUpdateDate))
+ {
+ // 如果从未修改过初始密码,直接提醒过期
+ return true;
+ }
+ Date nowDate = DateUtils.getNowDate();
+ return DateUtils.differentDaysByMillisecond(nowDate, pwdUpdateDate) > passwordValidateDays;
+ }
+ return false;
+ }
+}
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java
new file mode 100644
index 0000000..9d9fab6
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java
@@ -0,0 +1,165 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.List;
+import java.util.Map;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.entity.SysMenu;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.system.service.ISysMenuService;
+
+/**
+ * 菜单信息
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/menu")
+public class SysMenuController extends BaseController
+{
+ @Autowired
+ private ISysMenuService menuService;
+
+ /**
+ * 获取菜单列表
+ */
+ @PreAuthorize("@ss.hasPermi('system:menu:list')")
+ @GetMapping("/list")
+ public AjaxResult list(SysMenu menu)
+ {
+ List menus = menuService.selectMenuList(menu, getUserId());
+ return success(menus);
+ }
+
+ /**
+ * 根据菜单编号获取详细信息
+ */
+ @PreAuthorize("@ss.hasPermi('system:menu:query')")
+ @GetMapping(value = "/{menuId}")
+ public AjaxResult getInfo(@PathVariable Long menuId)
+ {
+ return success(menuService.selectMenuById(menuId));
+ }
+
+ /**
+ * 获取菜单下拉树列表
+ */
+ @GetMapping("/treeselect")
+ public AjaxResult treeselect(SysMenu menu)
+ {
+ List menus = menuService.selectMenuList(menu, getUserId());
+ return success(menuService.buildMenuTreeSelect(menus));
+ }
+
+ /**
+ * 加载对应角色菜单列表树
+ */
+ @GetMapping(value = "/roleMenuTreeselect/{roleId}")
+ public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId)
+ {
+ List menus = menuService.selectMenuList(getUserId());
+ AjaxResult ajax = AjaxResult.success();
+ ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId));
+ ajax.put("menus", menuService.buildMenuTreeSelect(menus));
+ return ajax;
+ }
+
+ /**
+ * 新增菜单
+ */
+ @PreAuthorize("@ss.hasPermi('system:menu:add')")
+ @Log(title = "菜单管理", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@Validated @RequestBody SysMenu menu)
+ {
+ if (!menuService.checkMenuNameUnique(menu))
+ {
+ return error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
+ }
+ else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
+ {
+ return error("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头");
+ }
+ else if (!menuService.checkRouteConfigUnique(menu))
+ {
+ return error("新增菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在");
+ }
+ menu.setCreateBy(getUsername());
+ return toAjax(menuService.insertMenu(menu));
+ }
+
+ /**
+ * 修改菜单
+ */
+ @PreAuthorize("@ss.hasPermi('system:menu:edit')")
+ @Log(title = "菜单管理", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@Validated @RequestBody SysMenu menu)
+ {
+ if (!menuService.checkMenuNameUnique(menu))
+ {
+ return error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
+ }
+ else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
+ {
+ return error("修改菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头");
+ }
+ else if (menu.getMenuId().equals(menu.getParentId()))
+ {
+ return error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己");
+ }
+ else if (!menuService.checkRouteConfigUnique(menu))
+ {
+ return error("修改菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在");
+ }
+ menu.setUpdateBy(getUsername());
+ return toAjax(menuService.updateMenu(menu));
+ }
+
+ /**
+ * 保存菜单排序
+ */
+ @PreAuthorize("@ss.hasPermi('system:menu:edit')")
+ @Log(title = "保存菜单排序", businessType = BusinessType.UPDATE)
+ @PutMapping("/updateSort")
+ public AjaxResult updateSort(@RequestBody Map params)
+ {
+ String[] menuIds = params.get("menuIds").split(",");
+ String[] orderNums = params.get("orderNums").split(",");
+ menuService.updateMenuSort(menuIds, orderNums);
+ return success();
+ }
+
+ /**
+ * 删除菜单
+ */
+ @PreAuthorize("@ss.hasPermi('system:menu:remove')")
+ @Log(title = "菜单管理", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{menuId}")
+ public AjaxResult remove(@PathVariable("menuId") Long menuId)
+ {
+ if (menuService.hasChildByMenuId(menuId))
+ {
+ return warn("存在子菜单,不允许删除");
+ }
+ if (menuService.checkMenuExistRole(menuId))
+ {
+ return warn("菜单已分配,不允许删除");
+ }
+ return toAjax(menuService.deleteMenuById(menuId));
+ }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java
new file mode 100644
index 0000000..84a3c73
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java
@@ -0,0 +1,150 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.core.text.Convert;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.system.domain.SysNotice;
+import com.ruoyi.system.service.ISysNoticeReadService;
+import com.ruoyi.system.service.ISysNoticeService;
+
+/**
+ * 公告 信息操作处理
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/notice")
+public class SysNoticeController extends BaseController
+{
+ @Autowired
+ private ISysNoticeService noticeService;
+
+ @Autowired
+ private ISysNoticeReadService noticeReadService;
+
+ /**
+ * 获取通知公告列表
+ */
+ @PreAuthorize("@ss.hasPermi('system:notice:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(SysNotice notice)
+ {
+ startPage();
+ List list = noticeService.selectNoticeList(notice);
+ return getDataTable(list);
+ }
+
+ /**
+ * 根据通知公告编号获取详细信息
+ */
+ @GetMapping(value = "/{noticeId}")
+ public AjaxResult getInfo(@PathVariable Long noticeId)
+ {
+ return success(noticeService.selectNoticeById(noticeId));
+ }
+
+ /**
+ * 新增通知公告
+ */
+ @PreAuthorize("@ss.hasPermi('system:notice:add')")
+ @Log(title = "通知公告", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@Validated @RequestBody SysNotice notice)
+ {
+ notice.setCreateBy(getUsername());
+ return toAjax(noticeService.insertNotice(notice));
+ }
+
+ /**
+ * 修改通知公告
+ */
+ @PreAuthorize("@ss.hasPermi('system:notice:edit')")
+ @Log(title = "通知公告", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@Validated @RequestBody SysNotice notice)
+ {
+ notice.setUpdateBy(getUsername());
+ return toAjax(noticeService.updateNotice(notice));
+ }
+
+ /**
+ * 首页顶部公告列表(返回全部正常公告,带当前用户已读标记,最多5条)
+ */
+ @GetMapping("/listTop")
+ @ResponseBody
+ public AjaxResult listTop()
+ {
+ Long userId = getUserId();
+ List list = noticeReadService.selectNoticeListWithReadStatus(userId, 5);
+ long unreadCount = list.stream().filter(n -> !n.getIsRead()).count();
+ AjaxResult result = AjaxResult.success(list);
+ result.put("unreadCount", unreadCount);
+ return result;
+ }
+
+ /**
+ * 标记公告已读
+ */
+ @PostMapping("/markRead")
+ @ResponseBody
+ public AjaxResult markRead(Long noticeId)
+ {
+ Long userId = getUserId();
+ noticeReadService.markRead(noticeId, userId);
+ return success();
+ }
+
+ /**
+ * 批量标记已读
+ */
+ @PostMapping("/markReadAll")
+ @ResponseBody
+ public AjaxResult markReadAll(String ids)
+ {
+ Long userId = getUserId();
+ Long[] noticeIds = Convert.toLongArray(ids);
+ noticeReadService.markReadBatch(userId, noticeIds);
+ return success();
+ }
+
+ /**
+ * 已读用户列表数据
+ */
+ @PreAuthorize("@ss.hasPermi('system:notice:list')")
+ @GetMapping("/readUsers/list")
+ @ResponseBody
+ public TableDataInfo readUsersList(Long noticeId, String searchValue)
+ {
+ startPage();
+ List> list = noticeReadService.selectReadUsersByNoticeId(noticeId, searchValue);
+ return getDataTable(list);
+ }
+
+ /**
+ * 删除通知公告
+ */
+ @PreAuthorize("@ss.hasPermi('system:notice:remove')")
+ @Log(title = "通知公告", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{noticeIds}")
+ public AjaxResult remove(@PathVariable Long[] noticeIds)
+ {
+ noticeReadService.deleteByNoticeIds(noticeIds);
+ return toAjax(noticeService.deleteNoticeByIds(noticeIds));
+ }
+}
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java
new file mode 100644
index 0000000..5b604cf
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java
@@ -0,0 +1,129 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.system.domain.SysPost;
+import com.ruoyi.system.service.ISysPostService;
+
+/**
+ * 岗位信息操作处理
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/post")
+public class SysPostController extends BaseController
+{
+ @Autowired
+ private ISysPostService postService;
+
+ /**
+ * 获取岗位列表
+ */
+ @PreAuthorize("@ss.hasPermi('system:post:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(SysPost post)
+ {
+ startPage();
+ List list = postService.selectPostList(post);
+ return getDataTable(list);
+ }
+
+ @Log(title = "岗位管理", businessType = BusinessType.EXPORT)
+ @PreAuthorize("@ss.hasPermi('system:post:export')")
+ @PostMapping("/export")
+ public void export(HttpServletResponse response, SysPost post)
+ {
+ List list = postService.selectPostList(post);
+ ExcelUtil util = new ExcelUtil(SysPost.class);
+ util.exportExcel(response, list, "岗位数据");
+ }
+
+ /**
+ * 根据岗位编号获取详细信息
+ */
+ @PreAuthorize("@ss.hasPermi('system:post:query')")
+ @GetMapping(value = "/{postId}")
+ public AjaxResult getInfo(@PathVariable Long postId)
+ {
+ return success(postService.selectPostById(postId));
+ }
+
+ /**
+ * 新增岗位
+ */
+ @PreAuthorize("@ss.hasPermi('system:post:add')")
+ @Log(title = "岗位管理", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@Validated @RequestBody SysPost post)
+ {
+ if (!postService.checkPostNameUnique(post))
+ {
+ return error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在");
+ }
+ else if (!postService.checkPostCodeUnique(post))
+ {
+ return error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在");
+ }
+ post.setCreateBy(getUsername());
+ return toAjax(postService.insertPost(post));
+ }
+
+ /**
+ * 修改岗位
+ */
+ @PreAuthorize("@ss.hasPermi('system:post:edit')")
+ @Log(title = "岗位管理", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@Validated @RequestBody SysPost post)
+ {
+ if (!postService.checkPostNameUnique(post))
+ {
+ return error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在");
+ }
+ else if (!postService.checkPostCodeUnique(post))
+ {
+ return error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在");
+ }
+ post.setUpdateBy(getUsername());
+ return toAjax(postService.updatePost(post));
+ }
+
+ /**
+ * 删除岗位
+ */
+ @PreAuthorize("@ss.hasPermi('system:post:remove')")
+ @Log(title = "岗位管理", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{postIds}")
+ public AjaxResult remove(@PathVariable Long[] postIds)
+ {
+ return toAjax(postService.deletePostByIds(postIds));
+ }
+
+ /**
+ * 获取岗位选择框列表
+ */
+ @GetMapping("/optionselect")
+ public AjaxResult optionselect()
+ {
+ List posts = postService.selectPostAll();
+ return success(posts);
+ }
+}
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java
new file mode 100644
index 0000000..dd2926f
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java
@@ -0,0 +1,216 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.Map;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.config.RuoYiConfig;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.core.domain.model.LoginUser;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.file.FileUploadUtils;
+import com.ruoyi.common.utils.file.FileUtils;
+import com.ruoyi.common.utils.file.MimeTypeUtils;
+import com.ruoyi.framework.web.service.TokenService;
+import com.ruoyi.system.service.ISysUserService;
+import com.ruoyi.business.dto.SmsValidForm;
+import com.ruoyi.business.service.SysSmsService;
+
+/**
+ * 个人信息 业务处理
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/user/profile")
+public class SysProfileController extends BaseController
+{
+ @Autowired
+ private ISysUserService userService;
+
+ @Autowired
+ private TokenService tokenService;
+
+ @Autowired
+ private SysSmsService smsService;
+
+ /**
+ * 个人信息
+ */
+ @GetMapping
+ public AjaxResult profile()
+ {
+ LoginUser loginUser = getLoginUser();
+ SysUser user = loginUser.getUser();
+ AjaxResult ajax = AjaxResult.success(user);
+ ajax.put("roleGroup", userService.selectUserRoleGroup(loginUser.getUsername()));
+ ajax.put("postGroup", userService.selectUserPostGroup(loginUser.getUsername()));
+ return ajax;
+ }
+
+ /**
+ * 修改用户
+ */
+ @Log(title = "个人信息", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult updateProfile(@RequestBody SysUser user)
+ {
+ LoginUser loginUser = getLoginUser();
+ SysUser currentUser = loginUser.getUser();
+ currentUser.setNickName(user.getNickName());
+ currentUser.setEmail(user.getEmail());
+ currentUser.setPhonenumber(user.getPhonenumber());
+ currentUser.setSex(user.getSex());
+ if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(currentUser))
+ {
+ return error("修改用户'" + loginUser.getUsername() + "'失败,手机号码已存在");
+ }
+ if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(currentUser))
+ {
+ return error("修改用户'" + loginUser.getUsername() + "'失败,邮箱账号已存在");
+ }
+ if (userService.updateUserProfile(currentUser) > 0)
+ {
+ // 更新缓存用户信息
+ tokenService.setLoginUser(loginUser);
+ return success();
+ }
+ return error("修改个人信息异常,请联系管理员");
+ }
+
+ /**
+ * 重置密码
+ */
+ @Log(title = "个人信息", businessType = BusinessType.UPDATE)
+ @PutMapping("/updatePwd")
+ public AjaxResult updatePwd(@RequestBody Map params)
+ {
+ String oldPassword = params.get("oldPassword");
+ String newPassword = params.get("newPassword");
+ LoginUser loginUser = getLoginUser();
+ Long userId = loginUser.getUserId();
+ SysUser user = userService.selectUserById(userId);
+ String password = user.getPassword();
+ if (!SecurityUtils.matchesPassword(oldPassword, password))
+ {
+ return error("修改密码失败,旧密码错误");
+ }
+ if (SecurityUtils.matchesPassword(newPassword, password))
+ {
+ return error("新密码不能与旧密码相同");
+ }
+ newPassword = SecurityUtils.encryptPassword(newPassword);
+ if (userService.resetUserPwd(userId, newPassword) > 0)
+ {
+ // 更新缓存用户密码&密码最后更新时间
+ loginUser.getUser().setPwdUpdateDate(DateUtils.getNowDate());
+ loginUser.getUser().setPassword(newPassword);
+ tokenService.setLoginUser(loginUser);
+ return success();
+ }
+ return error("修改密码异常,请联系管理员");
+ }
+
+ /**
+ * 修改手机号 (需短信验证码)
+ * 参数: { phone, smsCode, uuid }
+ */
+ @Log(title = "个人信息", businessType = BusinessType.UPDATE)
+ @PostMapping("/changePhone")
+ public AjaxResult changePhone(@RequestBody SmsValidForm form)
+ {
+ if (StringUtils.isEmpty(form.getPhone()) || StringUtils.isEmpty(form.getSmsCode()) || StringUtils.isEmpty(form.getUuid()))
+ {
+ return error("参数不完整");
+ }
+ // 1. 校验短信验证码
+ try
+ {
+ smsService.verifyCode(form);
+ }
+ catch (RuntimeException e)
+ {
+ return error(e.getMessage());
+ }
+ // 2. 更新当前用户手机号
+ LoginUser loginUser = getLoginUser();
+ SysUser currentUser = loginUser.getUser();
+ currentUser.setPhonenumber(form.getPhone());
+ if (!userService.checkPhoneUnique(currentUser))
+ {
+ return error("手机号码已被占用");
+ }
+ if (userService.updateUserProfile(currentUser) > 0)
+ {
+ // 同步缓存
+ tokenService.setLoginUser(loginUser);
+ return success();
+ }
+ return error("修改手机号失败");
+ }
+
+ /**
+ * 头像上传 (本地, RuoYi 默认)
+ */
+ @Log(title = "用户头像", businessType = BusinessType.UPDATE)
+ @PostMapping("/avatar")
+ public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws Exception
+ {
+ if (!file.isEmpty())
+ {
+ LoginUser loginUser = getLoginUser();
+ String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION, true);
+ if (userService.updateUserAvatar(loginUser.getUserId(), avatar))
+ {
+ String oldAvatar = loginUser.getUser().getAvatar();
+ if (StringUtils.isNotEmpty(oldAvatar))
+ {
+ FileUtils.deleteFile(RuoYiConfig.getProfile() + FileUtils.stripPrefix(oldAvatar));
+ }
+ AjaxResult ajax = AjaxResult.success();
+ ajax.put("imgUrl", avatar);
+ // 更新缓存用户头像
+ loginUser.getUser().setAvatar(avatar);
+ tokenService.setLoginUser(loginUser);
+ return ajax;
+ }
+ }
+ return error("上传图片异常,请联系管理员");
+ }
+
+ /**
+ * OSS 直传头像 (前端已上传到 OSS, 后端只负责写 sys_user.avatar 字段)
+ * 入参: { avatarUrl }
+ */
+ @Log(title = "用户头像", businessType = BusinessType.UPDATE)
+ @PutMapping("/avatarUrl")
+ public AjaxResult updateAvatarUrl(@RequestBody Map body)
+ {
+ String avatarUrl = body.get("avatarUrl");
+ if (StringUtils.isEmpty(avatarUrl))
+ {
+ return error("avatarUrl 不能为空");
+ }
+ LoginUser loginUser = getLoginUser();
+ if (userService.updateUserAvatar(loginUser.getUserId(), avatarUrl))
+ {
+ // 更新缓存用户头像
+ loginUser.getUser().setAvatar(avatarUrl);
+ tokenService.setLoginUser(loginUser);
+ return success();
+ }
+ return error("更新头像失败");
+ }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java
new file mode 100644
index 0000000..fe19249
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java
@@ -0,0 +1,38 @@
+package com.ruoyi.web.controller.system;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.model.RegisterBody;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.web.service.SysRegisterService;
+import com.ruoyi.system.service.ISysConfigService;
+
+/**
+ * 注册验证
+ *
+ * @author ruoyi
+ */
+@RestController
+public class SysRegisterController extends BaseController
+{
+ @Autowired
+ private SysRegisterService registerService;
+
+ @Autowired
+ private ISysConfigService configService;
+
+ @PostMapping("/register")
+ public AjaxResult register(@RequestBody RegisterBody user)
+ {
+ if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser"))))
+ {
+ return error("当前系统没有开启注册功能!");
+ }
+ String msg = registerService.register(user);
+ return StringUtils.isEmpty(msg) ? success() : error(msg);
+ }
+}
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java
new file mode 100644
index 0000000..a5643a0
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java
@@ -0,0 +1,254 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.entity.SysDept;
+import com.ruoyi.common.core.domain.entity.SysRole;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.framework.web.service.SysPermissionService;
+import com.ruoyi.framework.web.service.TokenService;
+import com.ruoyi.system.domain.SysUserRole;
+import com.ruoyi.system.service.ISysDeptService;
+import com.ruoyi.system.service.ISysRoleService;
+import com.ruoyi.system.service.ISysUserService;
+
+/**
+ * 角色信息
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/role")
+public class SysRoleController extends BaseController
+{
+ @Autowired
+ private ISysRoleService roleService;
+
+ @Autowired
+ private TokenService tokenService;
+
+ @Autowired
+ private SysPermissionService permissionService;
+
+ @Autowired
+ private ISysUserService userService;
+
+ @Autowired
+ private ISysDeptService deptService;
+
+ @PreAuthorize("@ss.hasPermi('system:role:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(SysRole role)
+ {
+ startPage();
+ List list = roleService.selectRoleList(role);
+ return getDataTable(list);
+ }
+
+ @Log(title = "角色管理", businessType = BusinessType.EXPORT)
+ @PreAuthorize("@ss.hasPermi('system:role:export')")
+ @PostMapping("/export")
+ public void export(HttpServletResponse response, SysRole role)
+ {
+ List list = roleService.selectRoleList(role);
+ ExcelUtil util = new ExcelUtil(SysRole.class);
+ util.exportExcel(response, list, "角色数据");
+ }
+
+ /**
+ * 根据角色编号获取详细信息
+ */
+ @PreAuthorize("@ss.hasPermi('system:role:query')")
+ @GetMapping(value = "/{roleId}")
+ public AjaxResult getInfo(@PathVariable Long roleId)
+ {
+ roleService.checkRoleDataScope(roleId);
+ return success(roleService.selectRoleById(roleId));
+ }
+
+ /**
+ * 新增角色
+ */
+ @PreAuthorize("@ss.hasPermi('system:role:add')")
+ @Log(title = "角色管理", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@Validated @RequestBody SysRole role)
+ {
+ if (!roleService.checkRoleNameUnique(role))
+ {
+ return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在");
+ }
+ else if (!roleService.checkRoleKeyUnique(role))
+ {
+ return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在");
+ }
+ role.setCreateBy(getUsername());
+ return toAjax(roleService.insertRole(role));
+
+ }
+
+ /**
+ * 修改保存角色
+ */
+ @PreAuthorize("@ss.hasPermi('system:role:edit')")
+ @Log(title = "角色管理", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@Validated @RequestBody SysRole role)
+ {
+ roleService.checkRoleAllowed(role);
+ roleService.checkRoleDataScope(role.getRoleId());
+ if (!roleService.checkRoleNameUnique(role))
+ {
+ return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在");
+ }
+ else if (!roleService.checkRoleKeyUnique(role))
+ {
+ return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在");
+ }
+ role.setUpdateBy(getUsername());
+
+ if (roleService.updateRole(role) > 0)
+ {
+ // 刷新所有持有该角色的在线用户权限
+ tokenService.refreshPermissionByRoleId(role.getRoleId(), permissionService);
+ return success();
+ }
+ return error("修改角色'" + role.getRoleName() + "'失败,请联系管理员");
+ }
+
+ /**
+ * 修改保存数据权限
+ */
+ @PreAuthorize("@ss.hasPermi('system:role:edit')")
+ @Log(title = "角色管理", businessType = BusinessType.UPDATE)
+ @PutMapping("/dataScope")
+ public AjaxResult dataScope(@RequestBody SysRole role)
+ {
+ roleService.checkRoleAllowed(role);
+ roleService.checkRoleDataScope(role.getRoleId());
+ return toAjax(roleService.authDataScope(role));
+ }
+
+ /**
+ * 状态修改
+ */
+ @PreAuthorize("@ss.hasPermi('system:role:edit')")
+ @Log(title = "角色管理", businessType = BusinessType.UPDATE)
+ @PutMapping("/changeStatus")
+ public AjaxResult changeStatus(@RequestBody SysRole role)
+ {
+ roleService.checkRoleAllowed(role);
+ roleService.checkRoleDataScope(role.getRoleId());
+ role.setUpdateBy(getUsername());
+ return toAjax(roleService.updateRoleStatus(role));
+ }
+
+ /**
+ * 删除角色
+ */
+ @PreAuthorize("@ss.hasPermi('system:role:remove')")
+ @Log(title = "角色管理", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{roleIds}")
+ public AjaxResult remove(@PathVariable Long[] roleIds)
+ {
+ return toAjax(roleService.deleteRoleByIds(roleIds));
+ }
+
+ /**
+ * 获取角色选择框列表
+ */
+ @PreAuthorize("@ss.hasPermi('system:role:query')")
+ @GetMapping("/optionselect")
+ public AjaxResult optionselect()
+ {
+ return success(roleService.selectRoleAll());
+ }
+
+ /**
+ * 查询已分配用户角色列表
+ */
+ @PreAuthorize("@ss.hasPermi('system:role:list')")
+ @GetMapping("/authUser/allocatedList")
+ public TableDataInfo allocatedList(SysUser user)
+ {
+ startPage();
+ List list = userService.selectAllocatedList(user);
+ return getDataTable(list);
+ }
+
+ /**
+ * 查询未分配用户角色列表
+ */
+ @PreAuthorize("@ss.hasPermi('system:role:list')")
+ @GetMapping("/authUser/unallocatedList")
+ public TableDataInfo unallocatedList(SysUser user)
+ {
+ startPage();
+ List list = userService.selectUnallocatedList(user);
+ return getDataTable(list);
+ }
+
+ /**
+ * 取消授权用户
+ */
+ @PreAuthorize("@ss.hasPermi('system:role:edit')")
+ @Log(title = "角色管理", businessType = BusinessType.GRANT)
+ @PutMapping("/authUser/cancel")
+ public AjaxResult cancelAuthUser(@RequestBody SysUserRole userRole)
+ {
+ return toAjax(roleService.deleteAuthUser(userRole));
+ }
+
+ /**
+ * 批量取消授权用户
+ */
+ @PreAuthorize("@ss.hasPermi('system:role:edit')")
+ @Log(title = "角色管理", businessType = BusinessType.GRANT)
+ @PutMapping("/authUser/cancelAll")
+ public AjaxResult cancelAuthUserAll(Long roleId, Long[] userIds)
+ {
+ return toAjax(roleService.deleteAuthUsers(roleId, userIds));
+ }
+
+ /**
+ * 批量选择用户授权
+ */
+ @PreAuthorize("@ss.hasPermi('system:role:edit')")
+ @Log(title = "角色管理", businessType = BusinessType.GRANT)
+ @PutMapping("/authUser/selectAll")
+ public AjaxResult selectAuthUserAll(Long roleId, Long[] userIds)
+ {
+ roleService.checkRoleDataScope(roleId);
+ return toAjax(roleService.insertAuthUsers(roleId, userIds));
+ }
+
+ /**
+ * 获取对应角色部门树列表
+ */
+ @PreAuthorize("@ss.hasPermi('system:role:query')")
+ @GetMapping(value = "/deptTree/{roleId}")
+ public AjaxResult deptTree(@PathVariable("roleId") Long roleId)
+ {
+ AjaxResult ajax = AjaxResult.success();
+ ajax.put("checkedKeys", deptService.selectDeptListByRoleId(roleId));
+ ajax.put("depts", deptService.selectDeptTreeList(new SysDept()));
+ return ajax;
+ }
+}
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
new file mode 100644
index 0000000..c4bf05e
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
@@ -0,0 +1,256 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import jakarta.servlet.http.HttpServletResponse;
+import org.apache.commons.lang3.ArrayUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.entity.SysDept;
+import com.ruoyi.common.core.domain.entity.SysRole;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.system.service.ISysDeptService;
+import com.ruoyi.system.service.ISysPostService;
+import com.ruoyi.system.service.ISysRoleService;
+import com.ruoyi.system.service.ISysUserService;
+
+/**
+ * 用户信息
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/user")
+public class SysUserController extends BaseController
+{
+ @Autowired
+ private ISysUserService userService;
+
+ @Autowired
+ private ISysRoleService roleService;
+
+ @Autowired
+ private ISysDeptService deptService;
+
+ @Autowired
+ private ISysPostService postService;
+
+ /**
+ * 获取用户列表
+ */
+ @PreAuthorize("@ss.hasPermi('system:user:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(SysUser user)
+ {
+ startPage();
+ List list = userService.selectUserList(user);
+ return getDataTable(list);
+ }
+
+ @Log(title = "用户管理", businessType = BusinessType.EXPORT)
+ @PreAuthorize("@ss.hasPermi('system:user:export')")
+ @PostMapping("/export")
+ public void export(HttpServletResponse response, SysUser user)
+ {
+ List list = userService.selectUserList(user);
+ ExcelUtil util = new ExcelUtil(SysUser.class);
+ util.exportExcel(response, list, "用户数据");
+ }
+
+ @Log(title = "用户管理", businessType = BusinessType.IMPORT)
+ @PreAuthorize("@ss.hasPermi('system:user:import')")
+ @PostMapping("/importData")
+ public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
+ {
+ ExcelUtil util = new ExcelUtil(SysUser.class);
+ List userList = util.importExcel(file.getInputStream());
+ String operName = getUsername();
+ String message = userService.importUser(userList, updateSupport, operName);
+ return success(message);
+ }
+
+ @PostMapping("/importTemplate")
+ public void importTemplate(HttpServletResponse response)
+ {
+ ExcelUtil util = new ExcelUtil(SysUser.class);
+ util.importTemplateExcel(response, "用户数据");
+ }
+
+ /**
+ * 根据用户编号获取详细信息
+ */
+ @PreAuthorize("@ss.hasPermi('system:user:query')")
+ @GetMapping(value = { "/", "/{userId}" })
+ public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId)
+ {
+ AjaxResult ajax = AjaxResult.success();
+ if (StringUtils.isNotNull(userId))
+ {
+ userService.checkUserDataScope(userId);
+ SysUser sysUser = userService.selectUserById(userId);
+ ajax.put(AjaxResult.DATA_TAG, sysUser);
+ ajax.put("postIds", postService.selectPostListByUserId(userId));
+ ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
+ }
+ List roles = roleService.selectRoleAll();
+ ajax.put("roles", SecurityUtils.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
+ ajax.put("posts", postService.selectPostAll());
+ return ajax;
+ }
+
+ /**
+ * 新增用户
+ */
+ @PreAuthorize("@ss.hasPermi('system:user:add')")
+ @Log(title = "用户管理", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@Validated @RequestBody SysUser user)
+ {
+ deptService.checkDeptDataScope(user.getDeptId());
+ roleService.checkRoleDataScope(user.getRoleIds());
+ if (!userService.checkUserNameUnique(user))
+ {
+ return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
+ }
+ else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
+ {
+ return error("新增用户'" + user.getUserName() + "'失败,手机号码已存在");
+ }
+ else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
+ {
+ return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
+ }
+ user.setCreateBy(getUsername());
+ user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
+ return toAjax(userService.insertUser(user));
+ }
+
+ /**
+ * 修改用户
+ */
+ @PreAuthorize("@ss.hasPermi('system:user:edit')")
+ @Log(title = "用户管理", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@Validated @RequestBody SysUser user)
+ {
+ userService.checkUserAllowed(user);
+ userService.checkUserDataScope(user.getUserId());
+ deptService.checkDeptDataScope(user.getDeptId());
+ roleService.checkRoleDataScope(user.getRoleIds());
+ if (!userService.checkUserNameUnique(user))
+ {
+ return error("修改用户'" + user.getUserName() + "'失败,登录账号已存在");
+ }
+ else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
+ {
+ return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
+ }
+ else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
+ {
+ return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
+ }
+ user.setUpdateBy(getUsername());
+ return toAjax(userService.updateUser(user));
+ }
+
+ /**
+ * 删除用户
+ */
+ @PreAuthorize("@ss.hasPermi('system:user:remove')")
+ @Log(title = "用户管理", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{userIds}")
+ public AjaxResult remove(@PathVariable Long[] userIds)
+ {
+ if (ArrayUtils.contains(userIds, getUserId()))
+ {
+ return error("当前用户不能删除");
+ }
+ return toAjax(userService.deleteUserByIds(userIds));
+ }
+
+ /**
+ * 重置密码
+ */
+ @PreAuthorize("@ss.hasPermi('system:user:resetPwd')")
+ @Log(title = "用户管理", businessType = BusinessType.UPDATE)
+ @PutMapping("/resetPwd")
+ public AjaxResult resetPwd(@RequestBody SysUser user)
+ {
+ userService.checkUserAllowed(user);
+ userService.checkUserDataScope(user.getUserId());
+ user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
+ user.setUpdateBy(getUsername());
+ return toAjax(userService.resetPwd(user));
+ }
+
+ /**
+ * 状态修改
+ */
+ @PreAuthorize("@ss.hasPermi('system:user:edit')")
+ @Log(title = "用户管理", businessType = BusinessType.UPDATE)
+ @PutMapping("/changeStatus")
+ public AjaxResult changeStatus(@RequestBody SysUser user)
+ {
+ userService.checkUserAllowed(user);
+ userService.checkUserDataScope(user.getUserId());
+ user.setUpdateBy(getUsername());
+ return toAjax(userService.updateUserStatus(user));
+ }
+
+ /**
+ * 根据用户编号获取授权角色
+ */
+ @PreAuthorize("@ss.hasPermi('system:user:query')")
+ @GetMapping("/authRole/{userId}")
+ public AjaxResult authRole(@PathVariable("userId") Long userId)
+ {
+ AjaxResult ajax = AjaxResult.success();
+ SysUser user = userService.selectUserById(userId);
+ List roles = roleService.selectRolesByUserId(userId);
+ ajax.put("user", user);
+ ajax.put("roles", SecurityUtils.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
+ return ajax;
+ }
+
+ /**
+ * 用户授权角色
+ */
+ @PreAuthorize("@ss.hasPermi('system:user:edit')")
+ @Log(title = "用户管理", businessType = BusinessType.GRANT)
+ @PutMapping("/authRole")
+ public AjaxResult insertAuthRole(Long userId, Long[] roleIds)
+ {
+ userService.checkUserDataScope(userId);
+ roleService.checkRoleDataScope(roleIds);
+ userService.insertUserAuth(userId, roleIds);
+ return success();
+ }
+
+ /**
+ * 获取部门树列表
+ */
+ @PreAuthorize("@ss.hasPermi('system:user:list')")
+ @GetMapping("/deptTree")
+ public AjaxResult deptTree(SysDept dept)
+ {
+ return success(deptService.selectDeptTreeList(dept));
+ }
+}
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/TestController.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/TestController.java
new file mode 100644
index 0000000..586e1b8
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/TestController.java
@@ -0,0 +1,175 @@
+package com.ruoyi.web.controller.tool;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.utils.StringUtils;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+/**
+ * swagger 用户测试方法
+ *
+ * @author ruoyi
+ */
+@Tag(name = "用户信息管理")
+@RestController
+@RequestMapping("/test/user")
+public class TestController extends BaseController
+{
+ private final static Map users = new LinkedHashMap();
+ {
+ users.put(1, new UserEntity(1, "admin", "admin123", "15888888888"));
+ users.put(2, new UserEntity(2, "ry", "admin123", "15666666666"));
+ }
+
+ @Operation(summary = "获取用户列表")
+ @GetMapping("/list")
+ public R> userList()
+ {
+ List userList = new ArrayList(users.values());
+ return R.ok(userList);
+ }
+
+ @Operation(summary = "获取用户详细")
+ @GetMapping("/{userId}")
+ public R getUser(@PathVariable(name = "userId")
+ Integer userId)
+ {
+ if (!users.isEmpty() && users.containsKey(userId))
+ {
+ return R.ok(users.get(userId));
+ }
+ else
+ {
+ return R.fail("用户不存在");
+ }
+ }
+
+ @Operation(summary = "新增用户")
+ @PostMapping("/save")
+ public R save(UserEntity user)
+ {
+ if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
+ {
+ return R.fail("用户ID不能为空");
+ }
+ users.put(user.getUserId(), user);
+ return R.ok();
+ }
+
+ @Operation(summary = "更新用户")
+ @PutMapping("/update")
+ public R update(@RequestBody
+ UserEntity user)
+ {
+ if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
+ {
+ return R.fail("用户ID不能为空");
+ }
+ if (users.isEmpty() || !users.containsKey(user.getUserId()))
+ {
+ return R.fail("用户不存在");
+ }
+ users.remove(user.getUserId());
+ users.put(user.getUserId(), user);
+ return R.ok();
+ }
+
+ @Operation(summary = "删除用户信息")
+ @DeleteMapping("/{userId}")
+ public R delete(@PathVariable(name = "userId")
+ Integer userId)
+ {
+ if (!users.isEmpty() && users.containsKey(userId))
+ {
+ users.remove(userId);
+ return R.ok();
+ }
+ else
+ {
+ return R.fail("用户不存在");
+ }
+ }
+}
+
+@Schema(description = "用户实体")
+class UserEntity
+{
+ @Schema(title = "用户ID")
+ private Integer userId;
+
+ @Schema(title = "用户名称")
+ private String username;
+
+ @Schema(title = "用户密码")
+ private String password;
+
+ @Schema(title = "用户手机")
+ private String mobile;
+
+ public UserEntity()
+ {
+
+ }
+
+ public UserEntity(Integer userId, String username, String password, String mobile)
+ {
+ this.userId = userId;
+ this.username = username;
+ this.password = password;
+ this.mobile = mobile;
+ }
+
+ public Integer getUserId()
+ {
+ return userId;
+ }
+
+ public void setUserId(Integer userId)
+ {
+ this.userId = userId;
+ }
+
+ public String getUsername()
+ {
+ return username;
+ }
+
+ public void setUsername(String username)
+ {
+ this.username = username;
+ }
+
+ public String getPassword()
+ {
+ return password;
+ }
+
+ public void setPassword(String password)
+ {
+ this.password = password;
+ }
+
+ public String getMobile()
+ {
+ return mobile;
+ }
+
+ public void setMobile(String mobile)
+ {
+ this.mobile = mobile;
+ }
+}
diff --git a/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java
new file mode 100644
index 0000000..9ab7c24
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java
@@ -0,0 +1,64 @@
+package com.ruoyi.web.core.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import com.ruoyi.common.config.RuoYiConfig;
+import io.swagger.v3.oas.models.Components;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Contact;
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.security.SecurityRequirement;
+import io.swagger.v3.oas.models.security.SecurityScheme;
+
+/**
+ * Swagger2的接口配置
+ *
+ * @author ruoyi
+ */
+@Configuration
+public class SwaggerConfig
+{
+ /** 系统基础配置 */
+ @Autowired
+ private RuoYiConfig ruoyiConfig;
+
+ /**
+ * 自定义的 OpenAPI 对象
+ */
+ @Bean
+ public OpenAPI customOpenApi()
+ {
+ return new OpenAPI().components(new Components()
+ // 设置认证的请求头
+ .addSecuritySchemes("apikey", securityScheme()))
+ .addSecurityItem(new SecurityRequirement().addList("apikey"))
+ .info(getApiInfo());
+ }
+
+ @Bean
+ public SecurityScheme securityScheme()
+ {
+ return new SecurityScheme()
+ .type(SecurityScheme.Type.APIKEY)
+ .name("Authorization")
+ .in(SecurityScheme.In.HEADER)
+ .scheme("Bearer");
+ }
+
+ /**
+ * 添加摘要信息
+ */
+ public Info getApiInfo()
+ {
+ return new Info()
+ // 设置标题
+ .title("标题:若依管理系统_接口文档")
+ // 描述
+ .description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...")
+ // 作者信息
+ .contact(new Contact().name(ruoyiConfig.getName()))
+ // 版本
+ .version("版本号:" + ruoyiConfig.getVersion());
+ }
+}
diff --git a/ry-api/ruoyi-admin/src/main/resources/META-INF/spring-devtools.properties b/ry-api/ruoyi-admin/src/main/resources/META-INF/spring-devtools.properties
new file mode 100644
index 0000000..37e7b58
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/resources/META-INF/spring-devtools.properties
@@ -0,0 +1 @@
+restart.include.json=/com.alibaba.fastjson2.*.jar
\ No newline at end of file
diff --git a/ry-api/ruoyi-admin/src/main/resources/application-druid.yml b/ry-api/ruoyi-admin/src/main/resources/application-druid.yml
new file mode 100644
index 0000000..95480d3
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/resources/application-druid.yml
@@ -0,0 +1,50 @@
+# 数据源配置
+spring:
+ datasource:
+ type: com.alibaba.druid.pool.DruidDataSource
+ driverClassName: com.mysql.cj.jdbc.Driver
+ druid:
+ master:
+ url: jdbc:mysql://127.0.0.1:3306/guoju0808?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+ username: root
+ password: cu2oh2co3
+ slave:
+ enabled: false
+ url:
+ username:
+ password:
+ initialSize: 5
+ minIdle: 10
+ maxActive: 20
+ maxWait: 60000
+ connectTimeout: 30000
+ socketTimeout: 60000
+ timeBetweenEvictionRunsMillis: 60000
+ minEvictableIdleTimeMillis: 300000
+ maxEvictableIdleTimeMillis: 900000
+ validationQuery: SELECT 1 FROM DUAL
+ testWhileIdle: true
+ testOnBorrow: false
+ testOnReturn: false
+ webStatFilter:
+ enabled: true
+ statViewServlet:
+ enabled: true
+ allow:
+ url-pattern: /druid/*
+ login-username: ruoyi
+ login-password: 123456
+ filter:
+ stat:
+ enabled: true
+ log-slow-sql: true
+ slow-sql-millis: 1000
+ merge-sql: true
+ wall:
+ config:
+ multi-statement-allow: true
+
+xss:
+ enabled: true
+ excludes: /system/notice
+ urlPatterns: /system/*,/monitor/*,/tool/*
\ No newline at end of file
diff --git a/ry-api/ruoyi-admin/src/main/resources/application.yml b/ry-api/ruoyi-admin/src/main/resources/application.yml
new file mode 100644
index 0000000..aec7500
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/resources/application.yml
@@ -0,0 +1,167 @@
+# 项目相关配置
+ruoyi:
+ # 名称
+ name: RuoYi
+ # 版本
+ version: 3.9.2
+ # 版权年份
+ copyrightYear: 2026
+ # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
+ profile: D:/ruoyi/uploadPath
+ # 获取ip地址开关
+ addressEnabled: false
+ # 验证码类型 math 数字计算 char 字符验证
+ captchaType: math
+ # OSS 配置 (前端直传签名, secretKey 仅后端使用)
+ oss:
+ enabled: true
+ endpoint: https://hwtossbamlorgcn.oss-cn-beijing.aliyuncs.com
+ bucket: hwtossbamlorgcn
+ accessKeyId: LTAI5tQKWWu96ihmg2VChQsY
+ accessKeySecret: gA0fTFa8arUYaYA5Us2ClPKVSM1Ypv
+ dirPrefix: ry8080/
+ expireSeconds: 3600
+ # 阿里云短信配置 (hwt-code ali.sms 模式)
+ # dev/prod 区分走代码: phone 以 "10" 开头视为 dev 测试 (固定码 1234), 其它走 aliyun 真发
+ sms:
+ accessKeyId: LTAI5t7S88DmdTxHPzPtJTwG
+ accessKeySecret: UIkwjMpmlYjgX5IMLjPj8FQNPthdlR
+ signName: 北京仙仁掌医学科技发展
+ template: SMS_321560247
+ inviteTemplate: SMS_492460505
+ endpoint: dysmsapi.aliyuncs.com
+ regionId: cn-hangzhou
+
+# 开发环境配置
+server:
+ # 服务器的HTTP端口,默认为8080
+ port: 8080
+ servlet:
+ # 应用的访问路径
+ context-path: /
+ tomcat:
+ # tomcat的URI编码
+ uri-encoding: UTF-8
+ # 连接数满后的排队数,默认为100
+ accept-count: 1000
+ threads:
+ # tomcat最大线程数,默认为200
+ max: 800
+ # Tomcat启动初始化的线程数,默认值10
+ min-spare: 100
+
+# 日志配置
+logging:
+ level:
+ com.ruoyi: debug
+ org.springframework: debug
+ com.ruoyi.business: debug
+
+# 用户配置
+user:
+ password:
+ # 密码最大错误次数
+ maxRetryCount: 5
+ # 密码锁定时间(默认10分钟)
+ lockTime: 10
+
+# Spring配置
+spring:
+ # 资源信息
+ messages:
+ # 国际化资源文件路径
+ basename: i18n/messages
+ profiles:
+ active: druid
+ # 文件上传
+ servlet:
+ multipart:
+ # 单个文件大小
+ max-file-size: 10MB
+ # 设置总上传的文件大小
+ max-request-size: 20MB
+ jackson:
+ time-zone: GMT+8
+ date-format: yyyy-MM-dd HH:mm:ss
+ # 服务模块
+ devtools:
+ restart:
+ # 热部署开关
+ enabled: true
+ data:
+ # redis 配置
+ redis:
+ # 地址
+ host: localhost
+ # 端口,默认为6379
+ port: 6379
+ # 数据库索引
+ database: 0
+ # 密码
+ password:
+ # 连接超时时间
+ timeout: 10s
+ lettuce:
+ pool:
+ # 连接池中的最小空闲连接
+ min-idle: 0
+ # 连接池中的最大空闲连接
+ max-idle: 8
+ # 连接池的最大数据库连接数
+ max-active: 8
+ # #连接池最大阻塞等待时间(使用负值表示没有限制)
+ max-wait: -1ms
+
+# token配置
+token:
+ # 令牌自定义标识
+ header: Authorization
+ # 令牌密钥
+ secret: abcdefghijklmnopqrstuvwxyz
+ # 令牌有效期(默认30分钟)
+ expireTime: 30
+
+# MyBatis配置
+mybatis:
+ # 搜索指定包别名
+ typeAliasesPackage: com.ruoyi.**.domain
+ # 配置mapper的扫描,找到所有的mapper.xml映射文件
+ mapperLocations: classpath*:mapper/**/*Mapper.xml
+ # 加载全局的配置文件
+ configLocation: classpath:mybatis/mybatis-config.xml
+
+# PageHelper分页插件
+pagehelper:
+ helperDialect: mysql
+ supportMethodsArguments: true
+ params: count=countSql
+
+# Springdoc配置
+springdoc:
+ api-docs:
+ path: /v3/api-docs
+ swagger-ui:
+ enabled: true
+ path: /swagger-ui.html
+ tags-sorter: alpha
+ group-configs:
+ - group: 'default'
+ display-name: '测试模块'
+ paths-to-match: '/**'
+ packages-to-scan: com.ruoyi.web.controller.tool
+
+# 防盗链配置
+referer:
+ # 防盗链开关
+ enabled: false
+ # 允许的域名列表
+ allowed-domains: localhost,127.0.0.1,ruoyi.vip,www.ruoyi.vip
+
+# 防止XSS攻击
+xss:
+ # 过滤开关
+ enabled: true
+ # 排除链接(多个用逗号分隔)
+ excludes: /system/notice
+ # 匹配链接
+ urlPatterns: /system/*,/monitor/*,/tool/*
\ No newline at end of file
diff --git a/ry-api/ruoyi-admin/src/main/resources/banner.txt b/ry-api/ruoyi-admin/src/main/resources/banner.txt
new file mode 100644
index 0000000..0931cb8
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/resources/banner.txt
@@ -0,0 +1,24 @@
+Application Version: ${ruoyi.version}
+Spring Boot Version: ${spring-boot.version}
+////////////////////////////////////////////////////////////////////
+// _ooOoo_ //
+// o8888888o //
+// 88" . "88 //
+// (| ^_^ |) //
+// O\ = /O //
+// ____/`---'\____ //
+// .' \\| |// `. //
+// / \\||| : |||// \ //
+// / _||||| -:- |||||- \ //
+// | | \\\ - /// | | //
+// | \_| ''\---/'' | | //
+// \ .-\__ `-` ___/-. / //
+// ___`. .' /--.--\ `. . ___ //
+// ."" '< `.___\_<|>_/___.' >'"". //
+// | | : `- \`.;`\ _ /`;.`/ - ` : | | //
+// \ \ `-. \_ __\ /__ _/ .-` / / //
+// ========`-.____`-.___\_____/___.-`____.-'======== //
+// `=---=' //
+// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //
+// 佛祖保佑 永不宕机 永无BUG //
+////////////////////////////////////////////////////////////////////
\ No newline at end of file
diff --git a/ry-api/ruoyi-admin/src/main/resources/i18n/messages.properties b/ry-api/ruoyi-admin/src/main/resources/i18n/messages.properties
new file mode 100644
index 0000000..93de005
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/resources/i18n/messages.properties
@@ -0,0 +1,38 @@
+#错误消息
+not.null=* 必须填写
+user.jcaptcha.error=验证码错误
+user.jcaptcha.expire=验证码已失效
+user.not.exists=用户不存在/密码错误
+user.password.not.match=用户不存在/密码错误
+user.password.retry.limit.count=密码输入错误{0}次
+user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟
+user.password.delete=对不起,您的账号已被删除
+user.blocked=用户已封禁,请联系管理员
+role.blocked=角色已封禁,请联系管理员
+login.blocked=很遗憾,访问IP已被列入系统黑名单
+user.logout.success=退出成功
+
+length.not.valid=长度必须在{min}到{max}个字符之间
+
+user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头
+user.password.not.valid=* 5-50个字符
+
+user.email.not.valid=邮箱格式错误
+user.mobile.phone.number.not.valid=手机号格式错误
+user.login.success=登录成功
+user.register.success=注册成功
+user.notfound=请重新登录
+user.forcelogout=管理员强制退出,请重新登录
+user.unknown.error=未知错误,请重新登录
+
+##文件上传消息
+upload.exceed.maxSize=上传的文件大小超出限制的文件大小! 允许的文件最大大小是:{0}MB!
+upload.filename.exceed.length=上传的文件名最长{0}个字符
+
+##权限
+no.permission=您没有数据的权限,请联系管理员添加权限 [{0}]
+no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}]
+no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}]
+no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}]
+no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}]
+no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}]
diff --git a/ry-api/ruoyi-admin/src/main/resources/logback.xml b/ry-api/ruoyi-admin/src/main/resources/logback.xml
new file mode 100644
index 0000000..a360583
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/resources/logback.xml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+ ${log.pattern}
+
+
+
+
+
+ ${log.path}/sys-info.log
+
+
+
+ ${log.path}/sys-info.%d{yyyy-MM-dd}.log
+
+ 60
+
+
+ ${log.pattern}
+
+
+
+ INFO
+
+ ACCEPT
+
+ DENY
+
+
+
+
+ ${log.path}/sys-error.log
+
+
+
+ ${log.path}/sys-error.%d{yyyy-MM-dd}.log
+
+ 60
+
+
+ ${log.pattern}
+
+
+
+ ERROR
+
+ ACCEPT
+
+ DENY
+
+
+
+
+
+ ${log.path}/sys-user.log
+
+
+ ${log.path}/sys-user.%d{yyyy-MM-dd}.log
+
+ 60
+
+
+ ${log.pattern}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ry-api/ruoyi-admin/src/main/resources/mybatis/mybatis-config.xml b/ry-api/ruoyi-admin/src/main/resources/mybatis/mybatis-config.xml
new file mode 100644
index 0000000..ac47c03
--- /dev/null
+++ b/ry-api/ruoyi-admin/src/main/resources/mybatis/mybatis-config.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ry-api/ruoyi-business/pom.xml b/ry-api/ruoyi-business/pom.xml
new file mode 100644
index 0000000..519e7fe
--- /dev/null
+++ b/ry-api/ruoyi-business/pom.xml
@@ -0,0 +1,40 @@
+
+
+
+ ruoyi
+ com.ruoyi
+ 3.9.2
+
+ 4.0.0
+
+ ruoyi-business
+
+
+ 业务模块 - 北京整合医学学会项目管理系统
+
+
+
+
+ com.ruoyi
+ ruoyi-common
+
+
+ com.ruoyi
+ ruoyi-system
+
+
+
+ com.aliyun
+ aliyun-java-sdk-dysmsapi
+ 2.2.1
+
+
+ com.aliyun
+ aliyun-java-sdk-core
+ 4.6.4
+
+
+
+
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizAuthController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizAuthController.java
new file mode 100644
index 0000000..aa1078a
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizAuthController.java
@@ -0,0 +1,130 @@
+package com.ruoyi.business.controller;
+
+import java.util.Map;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.business.domain.BizOrg;
+import com.ruoyi.business.dto.SmsValidForm;
+import com.ruoyi.business.service.IBizOrgService;
+import com.ruoyi.business.service.SysSmsService;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.system.service.ISysUserService;
+
+/**
+ * 业务登录 - 角色选择
+ * registerExecutor 完整实现 (2026-08-15 重构, 原 registerSupplier):
+ * 1. 校验短信验证码
+ * 2. 检查手机号/用户名是否已注册
+ * 3. 加密密码
+ * 4. 插入 sys_user (用户名=前端传入, role_type=executor, 主账号)
+ * 5. 插入 biz_org (executor 类型, business_nature/contact_phone 从表单)
+ * 注: 主账号不建 biz_person, 跟 sponsor 主账号保持一致
+ */
+@RestController
+@RequestMapping("/business/auth")
+public class BizAuthController extends BaseController {
+
+ @Autowired
+ private SysSmsService smsService;
+
+ @Autowired
+ private ISysUserService userService;
+
+ @Autowired
+ private IBizOrgService bizOrgService;
+
+ @Autowired
+ private BCryptPasswordEncoder passwordEncoder;
+
+ @PostMapping("/login")
+ public AjaxResult login(@RequestBody Map body) {
+ String username = (String) body.get("username");
+ String password = (String) body.get("password");
+ String roleType = (String) body.get("roleType");
+ return success().put("roleType", roleType).put("token", "mock-token");
+ }
+
+ @PostMapping("/registerExecutor")
+ public AjaxResult registerExecutor(@RequestBody Map body) {
+ String username = (String) body.get("username");
+ String unitName = (String) body.get("unitName");
+ String businessNature = (String) body.get("businessNature");
+ String phone = (String) body.get("phone");
+ String code = (String) body.get("smsCode");
+ String password = (String) body.get("password");
+ String confirmPassword = (String) body.get("confirmPassword");
+ String uuid = (String) body.get("uuid");
+
+ // 1. 基础校验
+ if (username == null || username.length() < 4 || username.length() > 20) return error("用户名长度 4-20 位");
+ if (!username.matches("^[A-Za-z0-9_]+$")) return error("用户名只能包含字母/数字/下划线");
+ if (unitName == null || unitName.isEmpty()) return error("企业名称不能为空");
+ if (businessNature == null || businessNature.isEmpty()) return error("企业性质不能为空");
+ if (phone == null || !phone.matches("^1\\d{10}$")) return error("手机号格式错误");
+ if (code == null || code.isEmpty()) return error("请输入短信验证码");
+ if (password == null || password.length() < 6 || password.length() > 20) return error("密码长度 6-20 位");
+ if (!password.equals(confirmPassword)) return error("两次密码输入不一致");
+
+ // 2. 校验短信验证码
+ SmsValidForm smsForm = new SmsValidForm();
+ smsForm.setPhone(phone);
+ smsForm.setSmsCode(code);
+ smsForm.setUuid(uuid);
+ try {
+ smsService.verifyCode(smsForm);
+ } catch (RuntimeException e) {
+ return error("验证码错误或已过期: " + e.getMessage());
+ }
+
+ // 3. 检查手机号/用户名是否已注册
+ if (userService.isPhoneRegistered(phone)) {
+ return error("该手机号已注册, 请直接登录");
+ }
+ SysUser nameCheck = new SysUser();
+ nameCheck.setUserName(username);
+ if (!userService.checkUserNameUnique(nameCheck)) {
+ return error("用户名已被占用: " + username);
+ }
+
+ // 4. 加密密码 + 插入 sys_user (用户名=userName 字段, 主账号)
+ SysUser user = new SysUser();
+ user.setUserName(username);
+ user.setNickName(unitName); // 默认昵称用公司名, 用户后续可在账号页改
+ user.setPhonenumber(phone);
+ user.setPassword(passwordEncoder.encode(password));
+ user.setStatus("0");
+ userService.insertUser(user);
+ Long userId = user.getUserId();
+ // sys_user.role_type 字段需 = executor
+ userService.updateRoleType(userId, "executor");
+
+ // 5. 插入 biz_org (executor 类型, 主账号自己当 contact)
+ BizOrg org = new BizOrg();
+ org.setOrgId(null);
+ org.setOrgName(unitName);
+ org.setOrgType("executor");
+ org.setBusinessNature(businessNature);
+ org.setContactPhone(phone);
+ org.setContactName(unitName); // 联系人默认 = 公司名
+ org.setStatus("0");
+ bizOrgService.insert(org);
+ Long orgId = org.getOrgId();
+
+ // 注: 主账号不建 biz_person (与 sponsor 主账号保持一致, 见 sponsor/Account.vue)
+ // 后续主账号在 [账号信息] 看到 [所属公司] 时, 后端可通过 sys_user.role_type 关联 biz_org 取 org_name
+ // 子账号 (biz_person.unit_type='sponsor' + user_id 关联 sys_user.parent_user_id) 由 [人员管理] 创建
+
+ return success("注册成功, 请等待审核").put("userId", userId).put("orgId", orgId);
+ }
+
+ @PostMapping("/registerSponsor")
+ public AjaxResult registerSponsor(@RequestBody Map body) {
+ return success();
+ }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizDashboardController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizDashboardController.java
new file mode 100644
index 0000000..4e09462
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizDashboardController.java
@@ -0,0 +1,56 @@
+package com.ruoyi.business.controller;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.business.domain.BizProject;
+import com.ruoyi.business.domain.BizMeeting;
+import com.ruoyi.business.domain.BizExpert;
+import com.ruoyi.business.service.IBizProjectService;
+import com.ruoyi.business.service.IBizMeetingService;
+import com.ruoyi.business.service.IBizExpertService;
+
+/**
+ * 工作台统计
+ */
+@RestController
+@RequestMapping("/business/dashboard")
+public class BizDashboardController extends BaseController {
+
+ @Autowired private IBizProjectService bizProjectService;
+ @Autowired private IBizMeetingService bizMeetingService;
+ @Autowired private IBizExpertService bizExpertService;
+
+ @GetMapping("/manager")
+ public AjaxResult managerDashboard() {
+ Map map = new HashMap<>();
+ List projects = bizProjectService.selectList(new BizProject());
+ List meetings = bizMeetingService.selectList(new BizMeeting());
+ List experts = bizExpertService.selectList(new BizExpert());
+ map.put("totalProjects", projects.size());
+ map.put("totalMeetings", meetings.size());
+ map.put("totalExperts", experts.size());
+ map.put("todoMeetings", meetings.stream().filter(m -> "未执行".equals(m.getCurrentStage())).count());
+ map.put("doingMeetings", meetings.stream().filter(m -> "待监管".equals(m.getCurrentStage()) || "待整改".equals(m.getCurrentStage())).count());
+ map.put("doneMeetings", meetings.stream().filter(m -> "已结算".equals(m.getCurrentStage()) || "已结题".equals(m.getCurrentStage())).count());
+ return success(map);
+ }
+
+ @GetMapping("/leader")
+ public AjaxResult leaderDashboard() {
+ Map map = new HashMap<>();
+ List projects = bizProjectService.selectList(new BizProject());
+ List meetings = bizMeetingService.selectList(new BizMeeting());
+ map.put("totalProjects", projects.size());
+ map.put("totalMeetings", meetings.size());
+ map.put("finishedProjects", projects.stream().filter(p -> "1".equals(p.getIsFinished())).count());
+ map.put("finishedMeetings", meetings.stream().filter(m -> "已结题".equals(m.getCurrentStage())).count());
+ return success(map);
+ }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizDictController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizDictController.java
new file mode 100644
index 0000000..4da8694
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizDictController.java
@@ -0,0 +1,142 @@
+package com.ruoyi.business.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.business.domain.BizDepartment;
+import com.ruoyi.business.domain.BizDoctorTitle;
+import com.ruoyi.business.service.IBizDepartmentService;
+import com.ruoyi.business.service.IBizDoctorTitleService;
+
+/**
+ * 业务字典管理 (科室 + 医生职称)
+ * 仅管理员可维护; 其它角色可访问 /active 接口拉启用的列表
+ */
+@RestController
+@RequestMapping("/business/dict")
+public class BizDictController extends BaseController
+{
+ @Autowired
+ private IBizDepartmentService departmentService;
+ @Autowired
+ private IBizDoctorTitleService doctorTitleService;
+
+ // ============== 科室 ==============
+
+ @PreAuthorize("@ss.hasRole('admin')")
+ @GetMapping("/department/list")
+ public TableDataInfo listDept(BizDepartment entity)
+ {
+ startPage();
+ return getDataTable(departmentService.selectList(entity));
+ }
+
+ @GetMapping("/department/active")
+ public AjaxResult activeDept()
+ {
+ return success(departmentService.selectActive());
+ }
+
+ @GetMapping("/department/{deptId}")
+ public AjaxResult getDept(@PathVariable Long deptId)
+ {
+ return success(departmentService.getById(deptId));
+ }
+
+ @PreAuthorize("@ss.hasRole('admin')")
+ @Log(title = "科室字典", businessType = BusinessType.INSERT)
+ @PostMapping("/department")
+ public AjaxResult addDept(@RequestBody BizDepartment entity)
+ {
+ if (entity.getName() == null || entity.getName().trim().isEmpty()) {
+ return error("科室名称不能为空");
+ }
+ if (entity.getStatus() == null || entity.getStatus().isEmpty()) entity.setStatus("0");
+ entity.setCreateBy(SecurityUtils.getUsername());
+ return toAjax(departmentService.insert(entity));
+ }
+
+ @PreAuthorize("@ss.hasRole('admin')")
+ @Log(title = "科室字典", businessType = BusinessType.UPDATE)
+ @PutMapping("/department")
+ public AjaxResult editDept(@RequestBody BizDepartment entity)
+ {
+ if (entity.getDeptId() == null) return error("ID 不能为空");
+ if (entity.getName() == null || entity.getName().trim().isEmpty()) {
+ return error("科室名称不能为空");
+ }
+ entity.setUpdateBy(SecurityUtils.getUsername());
+ return toAjax(departmentService.updateByPrimaryKey(entity));
+ }
+
+ @PreAuthorize("@ss.hasRole('admin')")
+ @Log(title = "科室字典", businessType = BusinessType.DELETE)
+ @DeleteMapping("/department/{ids}")
+ public AjaxResult removeDept(@PathVariable Long[] ids)
+ {
+ return toAjax(departmentService.deleteByPrimaryKeys(ids));
+ }
+
+ // ============== 医生职称 ==============
+
+ @PreAuthorize("@ss.hasRole('admin')")
+ @GetMapping("/title/list")
+ public TableDataInfo listTitle(BizDoctorTitle entity)
+ {
+ startPage();
+ return getDataTable(doctorTitleService.selectList(entity));
+ }
+
+ @GetMapping("/title/active")
+ public AjaxResult activeTitle()
+ {
+ return success(doctorTitleService.selectActive());
+ }
+
+ @GetMapping("/title/{titleId}")
+ public AjaxResult getTitle(@PathVariable Long titleId)
+ {
+ return success(doctorTitleService.getById(titleId));
+ }
+
+ @PreAuthorize("@ss.hasRole('admin')")
+ @Log(title = "医生职称字典", businessType = BusinessType.INSERT)
+ @PostMapping("/title")
+ public AjaxResult addTitle(@RequestBody BizDoctorTitle entity)
+ {
+ if (entity.getName() == null || entity.getName().trim().isEmpty()) {
+ return error("职称名称不能为空");
+ }
+ if (entity.getStatus() == null || entity.getStatus().isEmpty()) entity.setStatus("0");
+ entity.setCreateBy(SecurityUtils.getUsername());
+ return toAjax(doctorTitleService.insert(entity));
+ }
+
+ @PreAuthorize("@ss.hasRole('admin')")
+ @Log(title = "医生职称字典", businessType = BusinessType.UPDATE)
+ @PutMapping("/title")
+ public AjaxResult editTitle(@RequestBody BizDoctorTitle entity)
+ {
+ if (entity.getTitleId() == null) return error("ID 不能为空");
+ if (entity.getName() == null || entity.getName().trim().isEmpty()) {
+ return error("职称名称不能为空");
+ }
+ entity.setUpdateBy(SecurityUtils.getUsername());
+ return toAjax(doctorTitleService.updateByPrimaryKey(entity));
+ }
+
+ @PreAuthorize("@ss.hasRole('admin')")
+ @Log(title = "医生职称字典", businessType = BusinessType.DELETE)
+ @DeleteMapping("/title/{ids}")
+ public AjaxResult removeTitle(@PathVariable Long[] ids)
+ {
+ return toAjax(doctorTitleService.deleteByPrimaryKeys(ids));
+ }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizExecutionIntentController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizExecutionIntentController.java
new file mode 100644
index 0000000..ee72093
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizExecutionIntentController.java
@@ -0,0 +1,122 @@
+package com.ruoyi.business.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.system.mapper.SysUserMapper;
+import com.ruoyi.business.domain.BizExecutionIntent;
+import com.ruoyi.business.domain.BizProject;
+import com.ruoyi.business.service.IBizExecutionIntentService;
+import com.ruoyi.business.service.IBizProjectService;
+
+/**
+ * 执行意向Controller
+ */
+@RestController
+@RequestMapping("/business/executionIntent")
+public class BizExecutionIntentController extends BaseController
+{
+ @Autowired
+ private SysUserMapper sysUserMapper;
+ @Autowired
+ private IBizExecutionIntentService bizExecutionIntentService;
+ @Autowired
+ private IBizProjectService bizProjectService;
+
+ /**
+ * 公开门户点击"立即报名" — 写入意向 (user_id = 当前登录用户)
+ * POST /business/executionIntent/signup
+ * body: { projectId } (后端按 id 查项目回填 no/name)
+ * 返回 { intentId, projectNo, projectName, onboardStatus }
+ */
+ @Log(title = "执行意向", businessType = BusinessType.INSERT)
+ @PostMapping("/signup")
+ public AjaxResult signup(@RequestBody BizExecutionIntent bizExecutionIntent)
+ {
+ // 入参只接受 projectId (项目主键)
+ // BizExecutionIntent 没有 projectId 字段, 用 params 暂存
+ Object pidRaw = bizExecutionIntent.getParams().get("projectId");
+ Long projectId = null;
+ if (pidRaw != null) {
+ try { projectId = Long.parseLong(String.valueOf(pidRaw)); } catch (Exception e) { return error("项目ID格式错误"); }
+ }
+ if (projectId == null) return error("项目ID不能为空");
+ BizProject proj = bizProjectService.getById(String.valueOf(projectId));
+ if (proj == null) return error("项目不存在");
+ // 查重: 当前用户是否已报过这个项目
+ BizExecutionIntent q = new BizExecutionIntent();
+ q.setUserId(SecurityUtils.getUserId());
+ q.setProjectNo(proj.getProjectNo());
+ List exists = bizExecutionIntentService.selectList(q);
+ if (exists != null && !exists.isEmpty()) return error("您已报名过该项目,无需重复报名");
+ bizExecutionIntent.setProjectNo(proj.getProjectNo());
+ bizExecutionIntent.setProjectName(proj.getProjectName());
+ Long uid = SecurityUtils.getUserId();
+ bizExecutionIntent.setUserId(uid);
+ // 默认按用户表信息补全 name/phone (意向表历史字段, 方便后续审核流使用)
+ SysUser u = sysUserMapper.selectUserById(uid);
+ if (u != null) {
+ if (bizExecutionIntent.getName() == null || bizExecutionIntent.getName().isEmpty())
+ bizExecutionIntent.setName(u.getUserName());
+ if (bizExecutionIntent.getPhone() == null || bizExecutionIntent.getPhone().isEmpty())
+ bizExecutionIntent.setPhone(u.getPhonenumber());
+ }
+ if (bizExecutionIntent.getOnboardStatus() == null) bizExecutionIntent.setOnboardStatus("未入库");
+ bizExecutionIntent.setCreateBy(SecurityUtils.getUsername());
+ int n = bizExecutionIntentService.insert(bizExecutionIntent);
+ if (n == 0) return error("报名失败");
+ return success(bizExecutionIntent);
+ }
+
+ /** 当前用户是否已报过该项目 */
+ @GetMapping("/hasSigned")
+ public AjaxResult hasSigned(@RequestParam("projectId") Long projectId)
+ {
+ if (projectId == null) return success(false);
+ BizProject proj = bizProjectService.getById(String.valueOf(projectId));
+ if (proj == null) return success(false);
+ BizExecutionIntent q = new BizExecutionIntent();
+ q.setUserId(SecurityUtils.getUserId());
+ q.setProjectNo(proj.getProjectNo());
+ List exists = bizExecutionIntentService.selectList(q);
+ return success(exists != null && !exists.isEmpty());
+ }
+
+ @GetMapping("/list")
+ public TableDataInfo list(BizExecutionIntent bizExecutionIntent)
+ {
+ startPage();
+ List list = bizExecutionIntentService.selectList(bizExecutionIntent);
+ return getDataTable(list);
+ }
+ @GetMapping("/{intentId}")
+ public AjaxResult getInfo(@PathVariable("intentId") String intentId)
+ {
+ return success(bizExecutionIntentService.getById(intentId));
+ }
+ @Log(title = "执行意向", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody BizExecutionIntent bizExecutionIntent)
+ {
+ return toAjax(bizExecutionIntentService.insert(bizExecutionIntent));
+ }
+ @Log(title = "执行意向", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody BizExecutionIntent bizExecutionIntent)
+ {
+ return toAjax(bizExecutionIntentService.updateByPrimaryKey(bizExecutionIntent));
+ }
+ @Log(title = "执行意向", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public AjaxResult remove(@PathVariable String[] ids)
+ {
+ return toAjax(bizExecutionIntentService.deleteByPrimaryKeys(ids));
+ }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizExecutorController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizExecutorController.java
new file mode 100644
index 0000000..b0a1226
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizExecutorController.java
@@ -0,0 +1,74 @@
+package com.ruoyi.business.controller;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+
+/**
+ * 执行方用户查询 Controller
+ * 绕开 RuoYi 的 sys_user:list 权限(manager01 等普通用户被 data_scope 过滤看不到)。
+ * 按 sys_user.role_type = 'executor' 过滤真正的执行方用户。
+ */
+@RestController
+@RequestMapping("/business/executor")
+public class BizExecutorController extends BaseController
+{
+ @Autowired
+ private JdbcTemplate jdbcTemplate;
+
+ /**
+ * 查询指定角色用户列表 (支持 executor / sponsor / manager / leader / doctor / admin)
+ * @param roleType 角色类型 (默认 'executor')
+ * @param userName 用户名模糊搜索 (可选)
+ * @param userId 精确匹配 (可选)
+ * @param pageSize 限制返回行数 (默认 50)
+ */
+ @GetMapping("/list")
+ public AjaxResult list(@RequestParam(required = false, defaultValue = "executor") String roleType,
+ @RequestParam(required = false) String userName,
+ @RequestParam(required = false) Long userId,
+ @RequestParam(required = false, defaultValue = "50") Integer pageSize)
+ {
+ StringBuilder sql = new StringBuilder()
+ .append("SELECT user_id, dept_id, user_name, nick_name, email, phonenumber, role_type, status, create_time ")
+ .append("FROM sys_user WHERE del_flag = '0' AND status = '0' AND role_type = ?");
+ List args = new ArrayList<>();
+ args.add(roleType);
+ if (userId != null) {
+ sql.append(" AND user_id = ?");
+ args.add(userId);
+ }
+ if (userName != null && !userName.isEmpty()) {
+ sql.append(" AND user_name LIKE ?");
+ args.add("%" + userName + "%");
+ }
+ sql.append(" ORDER BY user_id ASC LIMIT ?");
+ args.add(pageSize);
+
+ List> rows = jdbcTemplate.queryForList(sql.toString(), args.toArray());
+ // 标准化为前端 el-select 友好的字段
+ List> result = new ArrayList<>();
+ for (Map r : rows) {
+ Map u = new HashMap<>();
+ u.put("userId", r.get("user_id"));
+ u.put("deptId", r.get("dept_id"));
+ u.put("userName", r.get("user_name"));
+ u.put("nickName", r.get("nick_name"));
+ u.put("email", r.get("email"));
+ u.put("phonenumber", r.get("phonenumber"));
+ u.put("roleType", r.get("role_type"));
+ u.put("status", r.get("status"));
+ result.add(u);
+ }
+ return success(result);
+ }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizExpertController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizExpertController.java
new file mode 100644
index 0000000..e926f80
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizExpertController.java
@@ -0,0 +1,74 @@
+package com.ruoyi.business.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.business.domain.BizExpert;
+import com.ruoyi.business.service.IBizExpertService;
+
+/**
+ * 专家Controller
+ */
+@RestController
+@RequestMapping("/business/expert")
+public class BizExpertController extends BaseController
+{
+ @Autowired
+ private IBizExpertService bizExpertService;
+ @GetMapping("/list")
+ public TableDataInfo list(BizExpert bizExpert)
+ {
+ startPage();
+ List list = bizExpertService.selectList(bizExpert);
+ return getDataTable(list);
+ }
+ @GetMapping("/{expertId}")
+ public AjaxResult getInfo(@PathVariable("expertId") String expertId)
+ {
+ return success(bizExpertService.getById(expertId));
+ }
+ /**
+ * 查当前登录用户的专家信息 (按 userId 路由)
+ */
+ @GetMapping("/profile")
+ public AjaxResult getProfile()
+ {
+ return success(bizExpertService.getByUserId(SecurityUtils.getUserId()));
+ }
+ @Log(title = "专家", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody BizExpert bizExpert)
+ {
+ return toAjax(bizExpertService.insert(bizExpert));
+ }
+ @Log(title = "专家", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody BizExpert bizExpert)
+ {
+ return toAjax(bizExpertService.updateByPrimaryKey(bizExpert));
+ }
+ /**
+ * 个人专家信息更新 (走 userId 路由, 后端强制注入当前登录用户)
+ * 不依赖前端传 expertId; 找不到 expert 行时自动 insert
+ */
+ @Log(title = "专家个人信息", businessType = BusinessType.UPDATE)
+ @PutMapping("/profile")
+ public AjaxResult updateProfile(@RequestBody BizExpert bizExpert)
+ {
+ bizExpert.setUserId(SecurityUtils.getUserId());
+ bizExpert.setCreateBy(SecurityUtils.getUsername());
+ return toAjax(bizExpertService.updateProfileByUserId(bizExpert));
+ }
+ @Log(title = "专家", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public AjaxResult remove(@PathVariable String[] ids)
+ {
+ return toAjax(bizExpertService.deleteByPrimaryKeys(ids));
+ }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizInvitationController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizInvitationController.java
new file mode 100644
index 0000000..a6716f8
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizInvitationController.java
@@ -0,0 +1,53 @@
+package com.ruoyi.business.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.business.domain.BizInvitation;
+import com.ruoyi.business.service.IBizInvitationService;
+
+/**
+ * 邀请函Controller
+ */
+@RestController
+@RequestMapping("/business/invitation")
+public class BizInvitationController extends BaseController
+{
+ @Autowired
+ private IBizInvitationService bizInvitationService;
+ @GetMapping("/list")
+ public TableDataInfo list(BizInvitation bizInvitation)
+ {
+ startPage();
+ List list = bizInvitationService.selectList(bizInvitation);
+ return getDataTable(list);
+ }
+ @GetMapping("/{invitationId}")
+ public AjaxResult getInfo(@PathVariable("invitationId") String invitationId)
+ {
+ return success(bizInvitationService.getById(invitationId));
+ }
+ @Log(title = "邀请函", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody BizInvitation bizInvitation)
+ {
+ return toAjax(bizInvitationService.insert(bizInvitation));
+ }
+ @Log(title = "邀请函", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody BizInvitation bizInvitation)
+ {
+ return toAjax(bizInvitationService.updateByPrimaryKey(bizInvitation));
+ }
+ @Log(title = "邀请函", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public AjaxResult remove(@PathVariable String[] ids)
+ {
+ return toAjax(bizInvitationService.deleteByPrimaryKeys(ids));
+ }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizLaborVoucherController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizLaborVoucherController.java
new file mode 100644
index 0000000..61ec3f5
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizLaborVoucherController.java
@@ -0,0 +1,53 @@
+package com.ruoyi.business.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.business.domain.BizLaborVoucher;
+import com.ruoyi.business.service.IBizLaborVoucherService;
+
+/**
+ * 劳务凭证Controller
+ */
+@RestController
+@RequestMapping("/business/laborVoucher")
+public class BizLaborVoucherController extends BaseController
+{
+ @Autowired
+ private IBizLaborVoucherService bizLaborVoucherService;
+ @GetMapping("/list")
+ public TableDataInfo list(BizLaborVoucher bizLaborVoucher)
+ {
+ startPage();
+ List list = bizLaborVoucherService.selectList(bizLaborVoucher);
+ return getDataTable(list);
+ }
+ @GetMapping("/{voucherId}")
+ public AjaxResult getInfo(@PathVariable("voucherId") String voucherId)
+ {
+ return success(bizLaborVoucherService.getById(voucherId));
+ }
+ @Log(title = "劳务凭证", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody BizLaborVoucher bizLaborVoucher)
+ {
+ return toAjax(bizLaborVoucherService.insert(bizLaborVoucher));
+ }
+ @Log(title = "劳务凭证", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody BizLaborVoucher bizLaborVoucher)
+ {
+ return toAjax(bizLaborVoucherService.updateByPrimaryKey(bizLaborVoucher));
+ }
+ @Log(title = "劳务凭证", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public AjaxResult remove(@PathVariable String[] ids)
+ {
+ return toAjax(bizLaborVoucherService.deleteByPrimaryKeys(ids));
+ }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizMeetingController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizMeetingController.java
new file mode 100644
index 0000000..50ea44f
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizMeetingController.java
@@ -0,0 +1,53 @@
+package com.ruoyi.business.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.business.domain.BizMeeting;
+import com.ruoyi.business.service.IBizMeetingService;
+
+/**
+ * 会议Controller
+ */
+@RestController
+@RequestMapping("/business/meeting")
+public class BizMeetingController extends BaseController
+{
+ @Autowired
+ private IBizMeetingService bizMeetingService;
+ @GetMapping("/list")
+ public TableDataInfo list(BizMeeting bizMeeting)
+ {
+ startPage();
+ List list = bizMeetingService.selectList(bizMeeting);
+ return getDataTable(list);
+ }
+ @GetMapping("/{meetingId}")
+ public AjaxResult getInfo(@PathVariable("meetingId") String meetingId)
+ {
+ return success(bizMeetingService.getById(meetingId));
+ }
+ @Log(title = "会议", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody BizMeeting bizMeeting)
+ {
+ return toAjax(bizMeetingService.insert(bizMeeting));
+ }
+ @Log(title = "会议", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody BizMeeting bizMeeting)
+ {
+ return toAjax(bizMeetingService.updateByPrimaryKey(bizMeeting));
+ }
+ @Log(title = "会议", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public AjaxResult remove(@PathVariable String[] ids)
+ {
+ return toAjax(bizMeetingService.deleteByPrimaryKeys(ids));
+ }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizMeetingSettlementController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizMeetingSettlementController.java
new file mode 100644
index 0000000..b2d3d9b
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizMeetingSettlementController.java
@@ -0,0 +1,53 @@
+package com.ruoyi.business.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.business.domain.BizMeetingSettlement;
+import com.ruoyi.business.service.IBizMeetingSettlementService;
+
+/**
+ * 会议结算Controller
+ */
+@RestController
+@RequestMapping("/business/meetingSettlement")
+public class BizMeetingSettlementController extends BaseController
+{
+ @Autowired
+ private IBizMeetingSettlementService bizMeetingSettlementService;
+ @GetMapping("/list")
+ public TableDataInfo list(BizMeetingSettlement bizMeetingSettlement)
+ {
+ startPage();
+ List list = bizMeetingSettlementService.selectList(bizMeetingSettlement);
+ return getDataTable(list);
+ }
+ @GetMapping("/{settlementId}")
+ public AjaxResult getInfo(@PathVariable("settlementId") String settlementId)
+ {
+ return success(bizMeetingSettlementService.getById(settlementId));
+ }
+ @Log(title = "会议结算", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody BizMeetingSettlement bizMeetingSettlement)
+ {
+ return toAjax(bizMeetingSettlementService.insert(bizMeetingSettlement));
+ }
+ @Log(title = "会议结算", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody BizMeetingSettlement bizMeetingSettlement)
+ {
+ return toAjax(bizMeetingSettlementService.updateByPrimaryKey(bizMeetingSettlement));
+ }
+ @Log(title = "会议结算", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public AjaxResult remove(@PathVariable String[] ids)
+ {
+ return toAjax(bizMeetingSettlementService.deleteByPrimaryKeys(ids));
+ }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizMessageController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizMessageController.java
new file mode 100644
index 0000000..d5d0355
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizMessageController.java
@@ -0,0 +1,128 @@
+package com.ruoyi.business.controller;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.business.domain.BizMessage;
+import com.ruoyi.business.service.IBizMessageService;
+
+/**
+ * 个人消息Controller
+ */
+@RestController
+@RequestMapping("/business/message")
+public class BizMessageController extends BaseController
+{
+ @Autowired
+ private IBizMessageService bizMessageService;
+
+ /**
+ * 列表 (管理员视角: 全量 + 过滤)
+ */
+ @PreAuthorize("@ss.hasPermi('business:message:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(BizMessage bizMessage)
+ {
+ startPage();
+ List list = bizMessageService.selectList(bizMessage);
+ return getDataTable(list);
+ }
+
+ /**
+ * 当前登录用户的最近消息 (含未读统计)
+ * GET /business/message/my?limit=50
+ * 返回 {rows: [...], unread: 12}
+ */
+ @GetMapping("/my")
+ public AjaxResult my(@RequestParam(value = "limit", required = false, defaultValue = "50") Integer limit)
+ {
+ Long uid = SecurityUtils.getUserId();
+ List rows = bizMessageService.selectMyRecent(uid, limit);
+ int unread = 0;
+ for (BizMessage m : rows) {
+ if ("0".equals(m.getIsRead())) unread++;
+ }
+ Map data = new HashMap<>();
+ data.put("rows", rows);
+ data.put("unread", unread);
+ data.put("total", rows.size());
+ return success(data);
+ }
+
+ /**
+ * 标记单条已读 (校验归属)
+ */
+ @PutMapping("/read/{msgId}")
+ public AjaxResult markRead(@PathVariable Long msgId)
+ {
+ Long uid = SecurityUtils.getUserId();
+ int n = bizMessageService.markRead(msgId, uid);
+ return n > 0 ? success() : error("消息不存在或无权操作");
+ }
+
+ /**
+ * 当前用户全部标记已读
+ */
+ @PutMapping("/readAll")
+ public AjaxResult markAllRead()
+ {
+ Long uid = SecurityUtils.getUserId();
+ int n = bizMessageService.markAllRead(uid);
+ return success(n);
+ }
+
+ /**
+ * 详情 (校验归属)
+ */
+ @GetMapping("/{msgId}")
+ public AjaxResult getInfo(@PathVariable Long msgId)
+ {
+ BizMessage m = bizMessageService.getById(msgId);
+ if (m == null) return error("消息不存在");
+ // 非管理员只能看自己的
+ if (!SecurityUtils.isAdmin() && !m.getReceiverUserId().equals(SecurityUtils.getUserId())) {
+ return error("无权查看");
+ }
+ // 自动标记已读
+ if ("0".equals(m.getIsRead()) && m.getReceiverUserId().equals(SecurityUtils.getUserId())) {
+ bizMessageService.markRead(msgId, SecurityUtils.getUserId());
+ m.setIsRead("1");
+ }
+ return success(m);
+ }
+
+ /**
+ * 发送消息给某用户 (管理员)
+ */
+ @PreAuthorize("@ss.hasPermi('business:message:add')")
+ @Log(title = "个人消息", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody BizMessage bizMessage)
+ {
+ if (bizMessage.getReceiverUserId() == null) return error("接收人不能为空");
+ if (bizMessage.getTitle() == null || bizMessage.getTitle().isEmpty()) return error("标题不能为空");
+ bizMessage.setCreateBy(SecurityUtils.getUsername());
+ return toAjax(bizMessageService.insert(bizMessage));
+ }
+
+ /**
+ * 批量删除 (管理员)
+ */
+ @PreAuthorize("@ss.hasPermi('business:message:remove')")
+ @Log(title = "个人消息", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public AjaxResult remove(@PathVariable Long[] ids)
+ {
+ return toAjax(bizMessageService.deleteByPrimaryKeys(ids));
+ }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizOrgController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizOrgController.java
new file mode 100644
index 0000000..24434b4
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizOrgController.java
@@ -0,0 +1,53 @@
+package com.ruoyi.business.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.business.domain.BizOrg;
+import com.ruoyi.business.service.IBizOrgService;
+
+/**
+ * 公司Controller (赞助方 + 执行方 共用)
+ * GET /business/org/list?orgType=sponsor|execution
+ */
+@RestController
+@RequestMapping("/business/org")
+public class BizOrgController extends BaseController {
+ @Autowired
+ private IBizOrgService bizOrgService;
+
+ @GetMapping("/list")
+ public TableDataInfo list(BizOrg bizOrg) {
+ startPage();
+ List list = bizOrgService.selectList(bizOrg);
+ return getDataTable(list);
+ }
+
+ @GetMapping("/{orgId}")
+ public AjaxResult getInfo(@PathVariable("orgId") Long orgId) {
+ return success(bizOrgService.getById(orgId));
+ }
+
+ @Log(title = "公司管理", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody BizOrg bizOrg) {
+ return toAjax(bizOrgService.insert(bizOrg));
+ }
+
+ @Log(title = "公司管理", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody BizOrg bizOrg) {
+ return toAjax(bizOrgService.updateByPrimaryKey(bizOrg));
+ }
+
+ @Log(title = "公司管理", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{orgIds}")
+ public AjaxResult remove(@PathVariable Long[] orgIds) {
+ return toAjax(bizOrgService.deleteByPrimaryKeys(orgIds));
+ }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizPersonController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizPersonController.java
new file mode 100644
index 0000000..d3d2c72
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizPersonController.java
@@ -0,0 +1,172 @@
+package com.ruoyi.business.controller;
+
+import java.util.ArrayList;
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.business.domain.BizOrg;
+import com.ruoyi.business.domain.BizPerson;
+import com.ruoyi.business.domain.BizPersonImportVO;
+import com.ruoyi.business.mapper.BizOrgMapper;
+import com.ruoyi.business.service.IBizPersonService;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.exception.ServiceException;
+
+/**
+ * 人员Controller
+ */
+@RestController
+@RequestMapping("/business/person")
+public class BizPersonController extends BaseController
+{
+ @Autowired
+ private IBizPersonService bizPersonService;
+
+ @Autowired
+ private BizOrgMapper bizOrgMapper;
+ @GetMapping("/list")
+ public TableDataInfo list(BizPerson bizPerson)
+ {
+ startPage();
+ List list = bizPersonService.selectList(bizPerson);
+ return getDataTable(list);
+ }
+
+ /**
+ * sponsor 端专属人员列表 (走专属 mapper, 利用 biz_person.user_id -> sys_user.parent_user_id 做归属过滤)
+ * 公共 /list 方法不被 sponsor 专属逻辑污染
+ */
+ @GetMapping("/sponsorList")
+ public TableDataInfo sponsorList(BizPerson bizPerson)
+ {
+ Long mainUid = getUserId();
+ bizPerson.getParams().put("sponsorOwnerUid", mainUid);
+ startPage();
+ List list = bizPersonService.selectSponsorList(bizPerson);
+ return getDataTable(list);
+ }
+ @GetMapping("/{personId}")
+ public AjaxResult getInfo(@PathVariable("personId") String personId)
+ {
+ return success(bizPersonService.getById(personId));
+ }
+ @Log(title = "人员", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody BizPerson bizPerson)
+ {
+ bizPerson.setCreateBy(getUsername());
+ bizPerson.setUpdateBy(getUsername());
+ // sponsor 端新建人员 = 创建 sys_user 子账号 (SUB, parent=当前登录主账号)
+ // service 内: 创建 sys_user + 创建 biz_person + 把 sys_user.user_id 绑到 biz_person.user_id
+ SysUser created = bizPersonService.insert(bizPerson, getUserId());
+ AjaxResult ajax = success(created);
+ // SysUser.password 是 @JsonProperty WRITE_ONLY 不会序列化,这里额外 put 明文密码给前端 toast
+ ajax.put("password", bizPerson.getLoginPassword());
+ return ajax;
+ }
+ @Log(title = "人员", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody BizPerson bizPerson)
+ {
+ bizPerson.setUpdateBy(getUsername());
+ return toAjax(bizPersonService.updateByPrimaryKey(bizPerson));
+ }
+ @Log(title = "人员", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public AjaxResult remove(@PathVariable String[] ids)
+ {
+ return toAjax(bizPersonService.deleteByPrimaryKeys(ids));
+ }
+
+ // ========== sponsor 端 Excel 批量导入 ==========
+
+ /**
+ * 下载 sponsor 端人员导入模板 (.xlsx)
+ * 模板列头按 BizPersonImportVO @Excel 注解自动生成 (中文: 姓名/手机号/工作单位/部门/职务/角色/状态)
+ */
+ @GetMapping("/sponsorImportTemplate")
+ public void sponsorImportTemplate(HttpServletResponse response)
+ {
+ ExcelUtil util = new ExcelUtil<>(BizPersonImportVO.class);
+ util.importTemplateExcel(response, "人员导入");
+ }
+
+ /**
+ * sponsor 端批量导入人员 (上传 .xlsx)
+ * 每行创建一个 biz_person + 一个 sys_user 子账号 (parent_user_id=当前主账号, loginUsername=手机号, 默认密码 123456)
+ * 失败行记录在返回结果的 errorRows 字段, 不影响其他行
+ */
+ @Log(title = "人员批量导入", businessType = BusinessType.INSERT)
+ @PostMapping("/sponsorImport")
+ public AjaxResult sponsorImport(@RequestParam("file") MultipartFile file) throws Exception
+ {
+ if (file == null || file.isEmpty()) {
+ throw new ServiceException("请选择要上传的文件");
+ }
+ ExcelUtil util = new ExcelUtil<>(BizPersonImportVO.class);
+ List rows = util.importExcel(file.getInputStream(), 0);
+ if (rows == null || rows.isEmpty()) {
+ throw new ServiceException("导入文件无有效数据");
+ }
+ Long mainUid = getUserId();
+ List> results = new ArrayList<>();
+ int ok = 0;
+ for (int i = 0; i < rows.size(); i++) {
+ BizPersonImportVO row = rows.get(i);
+ java.util.Map r = new java.util.LinkedHashMap<>();
+ r.put("rowNo", i + 2); // Excel 行号 (含标题行)
+ r.put("name", row.getName());
+ r.put("phone", row.getPhone());
+ try {
+ // 1. orgName → orgId (按 orgType='sponsor' 精确匹配, 查不到就报错)
+ String orgName = row.getOrgName();
+ if (orgName == null || orgName.trim().isEmpty()) {
+ throw new ServiceException("所属公司不能为空");
+ }
+ BizOrg orgQuery = new BizOrg();
+ orgQuery.setOrgName(orgName.trim());
+ orgQuery.setOrgType("sponsor");
+ List matched = bizOrgMapper.selectList(orgQuery);
+ if (matched == null || matched.isEmpty()) {
+ throw new ServiceException("找不到所属公司: " + orgName + " (需先在 [公司管理] 录入 orgType=sponsor 的公司)");
+ }
+ Long orgId = matched.get(0).getOrgId();
+
+ BizPerson p = new BizPerson();
+ p.setName(row.getName());
+ p.setPhone(row.getPhone());
+ p.setOrgId(orgId);
+ p.setDepartment(row.getDepartment());
+ p.setPosition(row.getPosition());
+ p.setRole(row.getRole());
+ p.setStatus("0"); // 默认正常
+ p.setUnitType("sponsor");
+ p.setLoginUsername(row.getPhone()); // 用户名 = 手机号 (要求唯一)
+ p.setLoginPassword("123456"); // 默认密码
+ p.setCreateBy(getUsername());
+ p.setUpdateBy(getUsername());
+ bizPersonService.insert(p, mainUid);
+ ok++;
+ r.put("ok", true);
+ r.put("message", "成功");
+ } catch (Exception e) {
+ r.put("ok", false);
+ r.put("message", e.getMessage());
+ }
+ results.add(r);
+ }
+ AjaxResult ajax = success();
+ ajax.put("total", rows.size());
+ ajax.put("ok", ok);
+ ajax.put("results", results);
+ return ajax;
+ }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizProjectController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizProjectController.java
new file mode 100644
index 0000000..8dd0ea8
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizProjectController.java
@@ -0,0 +1,214 @@
+package com.ruoyi.business.controller;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.business.domain.BizExecutionIntent;
+import com.ruoyi.business.domain.BizProject;
+import com.ruoyi.business.domain.BizProjectAssign;
+import com.ruoyi.business.domain.BizProjectRating;
+import com.ruoyi.business.service.IBizProjectService;
+import com.ruoyi.business.service.IBizExecutionIntentService;
+import com.ruoyi.business.domain.BizProjectSponsorAssign;
+import com.ruoyi.business.service.IBizProjectAssignService;
+import com.ruoyi.business.service.IBizProjectRatingService;
+import com.ruoyi.business.service.IBizProjectSponsorAssignService;
+
+/**
+ * 项目Controller
+ *
+ * 评分说明: 评分公开 (无可见性), 由 rater_role 字段区分角色 (sponsor/executor/compliance)
+ * 一律走 biz_project_rating 中间表 (BizProjectRatingController 已提供完整 CRUD)
+ */
+@RestController
+@RequestMapping("/business/project")
+public class BizProjectController extends BaseController
+{
+ @Autowired
+ private IBizProjectService bizProjectService;
+ @Autowired
+ private IBizExecutionIntentService bizExecutionIntentService;
+ @Autowired
+ private IBizProjectAssignService bizProjectAssignService;
+ @Autowired
+ private IBizProjectRatingService bizProjectRatingService;
+ @Autowired
+ private IBizProjectSponsorAssignService bizProjectSponsorAssignService;
+
+ /**
+ * 我报名的项目 (当前用户在 biz_execution_intent 里有意向的项目)
+ * GET /business/project/myProjects
+ */
+ @GetMapping("/myProjects")
+ public TableDataInfo myProjects(BizProject bizProject)
+ {
+ Long uid = SecurityUtils.getUserId();
+ BizExecutionIntent q = new BizExecutionIntent();
+ q.setUserId(uid);
+ List intents = bizExecutionIntentService.selectList(q);
+ if (intents == null || intents.isEmpty()) {
+ TableDataInfo r = new TableDataInfo();
+ r.setRows(new ArrayList<>());
+ r.setTotal(0);
+ return r;
+ }
+ java.util.Set noSet = new java.util.LinkedHashSet<>();
+ for (BizExecutionIntent it : intents) {
+ if (it.getProjectNo() != null && !it.getProjectNo().isEmpty()) noSet.add(it.getProjectNo());
+ }
+ startPage();
+ BizProject bp = new BizProject();
+ bp.getParams().put("projectNos", new ArrayList<>(noSet));
+ if (bizProject.getProjectNo() != null) bp.setProjectNo(bizProject.getProjectNo());
+ if (bizProject.getProjectName() != null) bp.setProjectName(bizProject.getProjectName());
+ List list = bizProjectService.selectList(bp);
+ return getDataTable(list);
+ }
+
+ @GetMapping("/list")
+ public TableDataInfo list(BizProject bizProject)
+ {
+ startPage();
+ List list = bizProjectService.selectList(bizProject);
+ return getDataTable(list);
+ }
+ @GetMapping("/{projectId}")
+ public AjaxResult getInfo(@PathVariable("projectId") String projectId)
+ {
+ return success(bizProjectService.getById(projectId));
+ }
+ @Log(title = "项目", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody BizProject bizProject)
+ {
+ return toAjax(bizProjectService.insert(bizProject));
+ }
+ @Log(title = "项目", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody BizProject bizProject)
+ {
+ return toAjax(bizProjectService.updateByPrimaryKey(bizProject));
+ }
+ @Log(title = "项目", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public AjaxResult remove(@PathVariable String[] ids)
+ {
+ return toAjax(bizProjectService.deleteByPrimaryKeys(ids));
+ }
+
+ // ========== 项目执行方分配 sub-resource ==========
+ @GetMapping("/{projectId}/assigns")
+ public AjaxResult getAssigns(@PathVariable("projectId") Long projectId)
+ {
+ return success(bizProjectAssignService.selectByProjectId(projectId));
+ }
+
+ @Log(title = "项目执行方分配", businessType = BusinessType.INSERT)
+ @PostMapping("/{projectId}/assigns")
+ public AjaxResult saveAssigns(@PathVariable("projectId") Long projectId, @RequestBody List assigns)
+ {
+ if (assigns == null) assigns = new ArrayList<>();
+ bizProjectAssignService.deleteByProjectId(projectId);
+ for (BizProjectAssign a : assigns) {
+ a.setProjectId(projectId);
+ if (a.getStatus() == null) a.setStatus("0");
+ bizProjectAssignService.insert(a);
+ }
+ return success();
+ }
+
+ @Log(title = "项目执行方分配", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{projectId}/assigns")
+ public AjaxResult clearAssigns(@PathVariable("projectId") Long projectId)
+ {
+ return toAjax(bizProjectAssignService.deleteByProjectId(projectId));
+ }
+
+ /**
+ * 通用评分 upsert (任何角色: sponsor / executor / compliance)
+ * POST /business/project/rate
+ * 不做可见性校验 — 评分公开
+ */
+ @Log(title = "项目评分", businessType = BusinessType.UPDATE)
+ @PostMapping("/rate")
+ public AjaxResult rate(@RequestBody BizProjectRating body)
+ {
+ if (body.getProjectId() == null || body.getRaterId() == null || body.getRaterRole() == null) {
+ return error("projectId / raterId / raterRole 必填");
+ }
+ body.setCreateBy(SecurityUtils.getUsername());
+ body.setUpdateBy(SecurityUtils.getUsername());
+ int rows = bizProjectRatingService.upsertRating(body);
+ return toAjax(rows);
+ }
+
+ /**
+ * 查某项目的所有评分 (公开, 任何角色可读)
+ * GET /business/project/ratings?projectId=X
+ */
+ @GetMapping("/ratings")
+ public AjaxResult ratings(@RequestParam("projectId") Long projectId)
+ {
+ BizProjectRating q = new BizProjectRating();
+ q.setProjectId(projectId);
+ return success(bizProjectRatingService.selectList(q));
+ }
+
+ /**
+ * 赞助方分配监察员 (写 biz_project_sponsor_assign)
+ * POST /business/project/sponsorAssign
+ */
+ @Log(title = "赞助方分配监察员", businessType = BusinessType.INSERT)
+ @PostMapping("/sponsorAssign")
+ public AjaxResult sponsorAssign(@RequestBody BizProjectSponsorAssign body)
+ {
+ body.setCreateBy(SecurityUtils.getUsername());
+ body.setSponsorUserId(SecurityUtils.getUserId());
+ int rows = bizProjectSponsorAssignService.insertAssign(body);
+ return toAjax(rows);
+ }
+
+ /**
+ * 赞助方批量分配监察员 (多个项目, 同一个监察员 + 同一份说明)
+ * POST /business/project/sponsorAssignBatch
+ * body: List (每个 item.projectId / monitorUserId / assignDesc / assignPoints)
+ */
+ @Log(title = "赞助方批量分配监察员", businessType = BusinessType.INSERT)
+ @PostMapping("/sponsorAssignBatch")
+ public AjaxResult sponsorAssignBatch(@RequestBody List bodies)
+ {
+ if (bodies == null || bodies.isEmpty()) {
+ return error("请提供至少一个分配记录");
+ }
+ String loginName = SecurityUtils.getUsername();
+ Long loginUid = SecurityUtils.getUserId();
+ int ok = 0;
+ List errors = new ArrayList<>();
+ for (int i = 0; i < bodies.size(); i++) {
+ BizProjectSponsorAssign body = bodies.get(i);
+ try {
+ if (body.getProjectId() == null || body.getMonitorUserId() == null) {
+ throw new IllegalArgumentException("projectId / monitorUserId 必填");
+ }
+ body.setCreateBy(loginName);
+ body.setSponsorUserId(loginUid);
+ bizProjectSponsorAssignService.insertAssign(body);
+ ok++;
+ } catch (Exception e) {
+ errors.add("第" + (i + 1) + "条 (projectId=" + body.getProjectId() + "): " + e.getMessage());
+ }
+ }
+ AjaxResult ajax = success();
+ ajax.put("total", bodies.size());
+ ajax.put("ok", ok);
+ ajax.put("errors", errors);
+ return ajax;
+ }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizProjectPlanController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizProjectPlanController.java
new file mode 100644
index 0000000..3b62532
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizProjectPlanController.java
@@ -0,0 +1,53 @@
+package com.ruoyi.business.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.business.domain.BizProjectPlan;
+import com.ruoyi.business.service.IBizProjectPlanService;
+
+/**
+ * 项目策划方案Controller
+ */
+@RestController
+@RequestMapping("/business/projectPlan")
+public class BizProjectPlanController extends BaseController
+{
+ @Autowired
+ private IBizProjectPlanService BizProjectPlanService;
+ @GetMapping("/list")
+ public TableDataInfo list(BizProjectPlan BizProjectPlan)
+ {
+ startPage();
+ List list = BizProjectPlanService.selectList(BizProjectPlan);
+ return getDataTable(list);
+ }
+ @GetMapping("/{planId}")
+ public AjaxResult getInfo(@PathVariable("planId") String planId)
+ {
+ return success(BizProjectPlanService.getById(planId));
+ }
+ @Log(title = "项目策划方案", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody BizProjectPlan BizProjectPlan)
+ {
+ return toAjax(BizProjectPlanService.insert(BizProjectPlan));
+ }
+ @Log(title = "项目策划方案", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody BizProjectPlan BizProjectPlan)
+ {
+ return toAjax(BizProjectPlanService.updateByPrimaryKey(BizProjectPlan));
+ }
+ @Log(title = "项目策划方案", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public AjaxResult remove(@PathVariable String[] ids)
+ {
+ return toAjax(BizProjectPlanService.deleteByPrimaryKeys(ids));
+ }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizProjectRatingController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizProjectRatingController.java
new file mode 100644
index 0000000..b467c17
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizProjectRatingController.java
@@ -0,0 +1,71 @@
+package com.ruoyi.business.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.business.domain.BizProjectRating;
+import com.ruoyi.business.service.IBizProjectRatingService;
+
+/**
+ * 项目评分Controller
+ */
+@RestController
+@RequestMapping("/business/projectRating")
+public class BizProjectRatingController extends BaseController
+{
+ @Autowired
+ private IBizProjectRatingService bizProjectRatingService;
+ @GetMapping("/list")
+ public TableDataInfo list(BizProjectRating bizProjectRating)
+ {
+ startPage();
+ List list = bizProjectRatingService.selectList(bizProjectRating);
+ return getDataTable(list);
+ }
+ @GetMapping("/{ratingId}")
+ public AjaxResult getInfo(@PathVariable("ratingId") String ratingId)
+ {
+ return success(bizProjectRatingService.getById(ratingId));
+ }
+ @Log(title = "项目评分", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody BizProjectRating bizProjectRating)
+ {
+ return toAjax(bizProjectRatingService.insert(bizProjectRating));
+ }
+
+ /**
+ * 执行单位评分 upsert (按 project_id + rater_id + rater_role 唯一)
+ * POST /business/projectRating/rate
+ */
+ @Log(title = "执行单位评分", businessType = BusinessType.UPDATE)
+ @PostMapping("/rate")
+ public AjaxResult rate(@RequestBody BizProjectRating body)
+ {
+ if (body.getProjectId() == null || body.getRaterId() == null || body.getRaterRole() == null) {
+ return error("projectId / raterId / raterRole 必填");
+ }
+ body.setCreateBy(getUsername());
+ body.setUpdateBy(getUsername());
+ int rows = bizProjectRatingService.upsertRating(body);
+ return toAjax(rows);
+ }
+
+ @Log(title = "项目评分", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody BizProjectRating bizProjectRating)
+ {
+ return toAjax(bizProjectRatingService.updateByPrimaryKey(bizProjectRating));
+ }
+ @Log(title = "项目评分", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public AjaxResult remove(@PathVariable String[] ids)
+ {
+ return toAjax(bizProjectRatingService.deleteByPrimaryKeys(ids));
+ }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizPublicController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizPublicController.java
new file mode 100644
index 0000000..f43fc1e
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizPublicController.java
@@ -0,0 +1,74 @@
+package com.ruoyi.business.controller;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.business.domain.BizProject;
+import com.ruoyi.business.domain.BizSupportLetter;
+import com.ruoyi.business.domain.BizInvitation;
+import com.ruoyi.business.domain.BizProjectPlan;
+import com.ruoyi.business.service.IBizProjectService;
+import com.ruoyi.business.service.IBizSupportLetterService;
+import com.ruoyi.business.service.IBizInvitationService;
+import com.ruoyi.business.service.IBizProjectPlanService;
+
+/**
+ * 公开门户接口(无需登录)
+ */
+@RestController
+@RequestMapping("/business/public")
+public class BizPublicController extends BaseController {
+
+ @Autowired private IBizProjectService projectService;
+ @Autowired private IBizSupportLetterService supportLetterService;
+ @Autowired private IBizInvitationService invitationService;
+ @Autowired private IBizProjectPlanService projectPlanService;
+
+ @GetMapping("/index")
+ public AjaxResult index() {
+ Map map = new HashMap<>();
+ BizProject publishedQuery = new BizProject();
+ publishedQuery.setIsPublished("1");
+ List announcements = projectService.selectList(publishedQuery);
+ List plans = projectPlanService.selectList(new BizProjectPlan());
+ map.put("announcements", announcements);
+ map.put("plans", plans);
+ map.put("about", "北京整合医学学会(BAHIM)是一家专注于整合医学学术研究、项目合作与人才培养的省级学术组织。");
+ return success(map);
+ }
+
+ @GetMapping("/announcements")
+ public AjaxResult announcements() {
+ BizProject query = new BizProject();
+ query.setIsPublished("1");
+ List list = projectService.selectList(query);
+ return success(list);
+ }
+
+ @GetMapping("/project/{projectId}")
+ public AjaxResult projectDetail(@PathVariable String projectId) {
+ return success(projectService.getById(projectId));
+ }
+
+ @GetMapping("/supportLetter/{annId}")
+ public AjaxResult supportLetterDetail(@PathVariable String annId) {
+ return success(supportLetterService.getById(annId));
+ }
+
+ @GetMapping("/invitation/{annId}")
+ public AjaxResult invitationDetail(@PathVariable String annId) {
+ return success(invitationService.getById(annId));
+ }
+
+ @GetMapping("/apply")
+ public AjaxResult apply(String annId) {
+ return success();
+ }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizPublicityController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizPublicityController.java
new file mode 100644
index 0000000..023e15e
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizPublicityController.java
@@ -0,0 +1,66 @@
+package com.ruoyi.business.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.business.domain.BizPublicity;
+import com.ruoyi.business.service.IBizPublicityService;
+import com.ruoyi.common.utils.SecurityUtils;
+
+/**
+ * 项目公告Controller (与前端 bizList('publicity', ...) 对接)
+ */
+@RestController
+@RequestMapping("/business/publicity")
+public class BizPublicityController extends BaseController
+{
+ @Autowired
+ private IBizPublicityService bizPublicityService;
+
+ @GetMapping("/list")
+ public TableDataInfo list(BizPublicity entity)
+ {
+ startPage();
+ // 按 project_id 过滤
+ entity.setStatus(null);
+ List list = bizPublicityService.selectList(entity);
+ return getDataTable(list);
+ }
+
+ @GetMapping("/{id}")
+ public AjaxResult getInfo(@PathVariable("id") Long id)
+ {
+ return success(bizPublicityService.getById(id));
+ }
+
+ @Log(title = "项目公告", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody BizPublicity entity)
+ {
+ entity.setCreateBy(SecurityUtils.getUsername());
+ entity.setUpdateBy(SecurityUtils.getUsername());
+ if (entity.getStatus() == null) entity.setStatus("1");
+ int rows = bizPublicityService.insert(entity);
+ return toAjax(rows);
+ }
+
+ @Log(title = "项目公告", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody BizPublicity entity)
+ {
+ entity.setUpdateBy(SecurityUtils.getUsername());
+ return toAjax(bizPublicityService.updateByPrimaryKey(entity));
+ }
+
+ @Log(title = "项目公告", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public AjaxResult remove(@PathVariable Long[] ids)
+ {
+ return toAjax(bizPublicityService.deleteByPrimaryKeys(ids));
+ }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizRegisterController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizRegisterController.java
new file mode 100644
index 0000000..e7a8e72
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizRegisterController.java
@@ -0,0 +1,109 @@
+package com.ruoyi.business.controller;
+
+import java.util.Map;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.business.domain.BizExpert;
+import com.ruoyi.business.dto.SmsValidForm;
+import com.ruoyi.business.service.IBizExpertService;
+import com.ruoyi.business.service.SysSmsService;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.utils.uuid.UUID;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.system.service.ISysUserService;
+
+/**
+ * 专家注册 (完整实现)
+ * 流程:
+ * 1. 校验短信验证码
+ * 2. 检查用户名(=手机号)是否已注册
+ * 3. 加密密码
+ * 4. 插入 sys_user (role_type=doctor, user_type=01)
+ * 5. 插入 biz_expert (user_id 关联)
+ */
+@RestController
+@RequestMapping("/business/auth")
+public class BizRegisterController extends BaseController {
+
+ @Autowired
+ private SysSmsService smsService;
+
+ @Autowired
+ private ISysUserService userService;
+
+ @Autowired
+ private IBizExpertService expertService;
+
+ @Autowired
+ private BCryptPasswordEncoder passwordEncoder;
+
+ @PostMapping("/registerExpert")
+ public AjaxResult registerExpert(@RequestBody Map body) {
+ String realName = (String) body.get("realName");
+ String workUnit = (String) body.get("workUnit");
+ String department = (String) body.get("department");
+ String doctorTitle = (String) body.get("doctorTitle");
+ String phone = (String) body.get("phone");
+ String code = (String) body.get("code");
+ String password = (String) body.get("password");
+ String uuid = (String) body.get("uuid");
+ String licenseCertUrl = (String) body.get("licenseCertUrl");
+ String titleCertUrl = (String) body.get("titleCertUrl");
+
+ if (realName == null || realName.isEmpty()) return error("姓名不能为空");
+ if (workUnit == null || workUnit.isEmpty()) return error("工作单位不能为空");
+ if (phone == null || !phone.matches("^1\\d{10}$")) return error("手机号格式错误");
+ if (code == null || code.isEmpty()) return error("请输入短信验证码");
+ if (password == null || password.length() < 6 || password.length() > 20) return error("密码长度 6-20 位");
+
+ // 1. 校验短信验证码
+ SmsValidForm smsForm = new SmsValidForm();
+ smsForm.setPhone(phone);
+ smsForm.setSmsCode(code);
+ smsForm.setUuid(uuid);
+ try {
+ smsService.verifyCode(smsForm);
+ } catch (RuntimeException e) {
+ return error("验证码错误或已过期: " + e.getMessage());
+ }
+
+ // 2. 用户名=手机号, 检查是否已注册
+ if (userService.isPhoneRegistered(phone)) {
+ return error("该手机号已注册, 请直接登录");
+ }
+
+ // 3. 加密密码 + 4. 插入 sys_user (用户名=phone)
+ SysUser user = new SysUser();
+ user.setUserName(phone);
+ user.setNickName(realName);
+ user.setPhonenumber(phone);
+ user.setPassword(passwordEncoder.encode(password));
+ user.setStatus("0");
+ userService.insertUser(user);
+ Long userId = user.getUserId();
+ // sys_user.role_type 表字段 (DB 默认 executor, 专家需 = doctor), 用 mapper 更新
+ userService.updateRoleType(userId, "doctor");
+
+ // 5. 插入 biz_expert
+ BizExpert expert = new BizExpert();
+ expert.setExpertId(UUID.fastUUID().toString());
+ expert.setUserId(userId);
+ expert.setName(realName);
+ expert.setPhone(phone);
+ expert.setWorkUnit(workUnit);
+ expert.setDepartment(department);
+ expert.setTitle(doctorTitle);
+ expert.setPracticeCertUrl(licenseCertUrl);
+ expert.setTitleCertUrl(titleCertUrl);
+ expert.setAuditStatus("0");
+ expert.setStatus("0");
+ expertService.insert(expert);
+
+ return success("注册成功, 请等待审核").put("userId", userId);
+ }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizRegisterSmsController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizRegisterSmsController.java
new file mode 100644
index 0000000..a6eae5d
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizRegisterSmsController.java
@@ -0,0 +1,40 @@
+package com.ruoyi.business.controller;
+
+import com.ruoyi.business.service.SysSmsService;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.system.service.ISysUserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+/**
+ * 注册专用 - 发送短信验证码
+ * 校验: 手机号未被注册过, 否则报错
+ * 匿名访问 (前端 register-* 页面调用, 登录前)
+ */
+@RestController
+@RequestMapping("/business/auth")
+public class BizRegisterSmsController extends BaseController {
+
+ @Autowired
+ private SysSmsService smsService;
+
+ @Autowired
+ private com.ruoyi.system.service.ISysUserService userService;
+
+ @PostMapping("/registerSendSms")
+ public AjaxResult registerSendSms(@RequestBody Map body) {
+ String phone = body == null ? null : body.get("phone");
+ if (phone == null || !phone.matches("^1\\d{10}$")) {
+ return error("请输入正确的手机号");
+ }
+ // 手机号已注册则报错
+ if (userService.isPhoneRegistered(phone)) {
+ return error("该手机号已注册, 请直接登录");
+ }
+ String uuid = smsService.sendCode(phone);
+ return AjaxResult.success("验证码已发送", uuid);
+ }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizResourceController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizResourceController.java
new file mode 100644
index 0000000..8d5955e
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizResourceController.java
@@ -0,0 +1,53 @@
+package com.ruoyi.business.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.business.domain.BizResource;
+import com.ruoyi.business.service.IBizResourceService;
+
+/**
+ * 资源Controller
+ */
+@RestController
+@RequestMapping("/business/resource")
+public class BizResourceController extends BaseController
+{
+ @Autowired
+ private IBizResourceService bizResourceService;
+ @GetMapping("/list")
+ public TableDataInfo list(BizResource bizResource)
+ {
+ startPage();
+ List list = bizResourceService.selectList(bizResource);
+ return getDataTable(list);
+ }
+ @GetMapping("/{resourceId}")
+ public AjaxResult getInfo(@PathVariable("resourceId") String resourceId)
+ {
+ return success(bizResourceService.getById(resourceId));
+ }
+ @Log(title = "资源", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody BizResource bizResource)
+ {
+ return toAjax(bizResourceService.insert(bizResource));
+ }
+ @Log(title = "资源", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody BizResource bizResource)
+ {
+ return toAjax(bizResourceService.updateByPrimaryKey(bizResource));
+ }
+ @Log(title = "资源", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public AjaxResult remove(@PathVariable String[] ids)
+ {
+ return toAjax(bizResourceService.deleteByPrimaryKeys(ids));
+ }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizSubmissionController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizSubmissionController.java
new file mode 100644
index 0000000..ff1bca0
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizSubmissionController.java
@@ -0,0 +1,79 @@
+package com.ruoyi.business.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.business.domain.BizSubmission;
+import com.ruoyi.business.enums.SubmissionStatus;
+import com.ruoyi.business.service.IBizSubmissionService;
+
+/**
+ * 投稿Controller
+ */
+@RestController
+@RequestMapping("/business/submission")
+public class BizSubmissionController extends BaseController
+{
+ @Autowired
+ private IBizSubmissionService bizSubmissionService;
+ @GetMapping("/list")
+ public TableDataInfo list(BizSubmission bizSubmission)
+ {
+ // 后端兜底: 只查当前登录用户提交的; admin 跳过此限制
+ if (!SecurityUtils.isAdmin()) {
+ bizSubmission.setSubmitterId(SecurityUtils.getUserId());
+ }
+ startPage();
+ List list = bizSubmissionService.selectList(bizSubmission);
+ return getDataTable(list);
+ }
+ @GetMapping("/{submissionId}")
+ public AjaxResult getInfo(@PathVariable("submissionId") String submissionId)
+ {
+ return success(bizSubmissionService.getById(submissionId));
+ }
+ @Log(title = "投稿", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody BizSubmission bizSubmission)
+ {
+ // 后端兜底: 强制写入当前登录用户, 防止前端漏传/绕过导致列表过滤查不到
+ bizSubmission.setSubmitterId(SecurityUtils.getUserId());
+ bizSubmission.setSubmitterName(SecurityUtils.getUsername());
+ bizSubmission.setCreateBy(getUsername());
+ bizSubmission.setUpdateBy(getUsername());
+ // 状态: 新建默认 DRAFT(待提交); 校验必须是英文 code 之一
+ if (bizSubmission.getStatus() == null || bizSubmission.getStatus().isEmpty()) {
+ bizSubmission.setStatus(SubmissionStatus.DRAFT.getCode());
+ } else if (!SubmissionStatus.isValid(bizSubmission.getStatus())) {
+ return AjaxResult.error("状态值非法: " + bizSubmission.getStatus());
+ }
+ return toAjax(bizSubmissionService.insert(bizSubmission));
+ }
+ @Log(title = "投稿", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody BizSubmission bizSubmission)
+ {
+ // 修改时也强制覆盖 submitterId/submitterName, 防止越权篡改为他人
+ bizSubmission.setSubmitterId(SecurityUtils.getUserId());
+ bizSubmission.setSubmitterName(SecurityUtils.getUsername());
+ bizSubmission.setUpdateBy(getUsername());
+ // 状态校验 (英文 code)
+ if (bizSubmission.getStatus() != null && !bizSubmission.getStatus().isEmpty()
+ && !SubmissionStatus.isValid(bizSubmission.getStatus())) {
+ return AjaxResult.error("状态值非法: " + bizSubmission.getStatus());
+ }
+ return toAjax(bizSubmissionService.updateByPrimaryKey(bizSubmission));
+ }
+ @Log(title = "投稿", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public AjaxResult remove(@PathVariable String[] ids)
+ {
+ return toAjax(bizSubmissionService.deleteByPrimaryKeys(ids));
+ }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizSupportIntentController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizSupportIntentController.java
new file mode 100644
index 0000000..0512234
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizSupportIntentController.java
@@ -0,0 +1,53 @@
+package com.ruoyi.business.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.business.domain.BizSupportIntent;
+import com.ruoyi.business.service.IBizSupportIntentService;
+
+/**
+ * 支持意向Controller
+ */
+@RestController
+@RequestMapping("/business/supportIntent")
+public class BizSupportIntentController extends BaseController
+{
+ @Autowired
+ private IBizSupportIntentService bizSupportIntentService;
+ @GetMapping("/list")
+ public TableDataInfo list(BizSupportIntent bizSupportIntent)
+ {
+ startPage();
+ List list = bizSupportIntentService.selectList(bizSupportIntent);
+ return getDataTable(list);
+ }
+ @GetMapping("/{intentId}")
+ public AjaxResult getInfo(@PathVariable("intentId") String intentId)
+ {
+ return success(bizSupportIntentService.getById(intentId));
+ }
+ @Log(title = "支持意向", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody BizSupportIntent bizSupportIntent)
+ {
+ return toAjax(bizSupportIntentService.insert(bizSupportIntent));
+ }
+ @Log(title = "支持意向", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody BizSupportIntent bizSupportIntent)
+ {
+ return toAjax(bizSupportIntentService.updateByPrimaryKey(bizSupportIntent));
+ }
+ @Log(title = "支持意向", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public AjaxResult remove(@PathVariable String[] ids)
+ {
+ return toAjax(bizSupportIntentService.deleteByPrimaryKeys(ids));
+ }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizSupportLetterController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizSupportLetterController.java
new file mode 100644
index 0000000..2f8a281
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/BizSupportLetterController.java
@@ -0,0 +1,53 @@
+package com.ruoyi.business.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.business.domain.BizSupportLetter;
+import com.ruoyi.business.service.IBizSupportLetterService;
+
+/**
+ * 支持函Controller
+ */
+@RestController
+@RequestMapping("/business/supportLetter")
+public class BizSupportLetterController extends BaseController
+{
+ @Autowired
+ private IBizSupportLetterService bizSupportLetterService;
+ @GetMapping("/list")
+ public TableDataInfo list(BizSupportLetter bizSupportLetter)
+ {
+ startPage();
+ List list = bizSupportLetterService.selectList(bizSupportLetter);
+ return getDataTable(list);
+ }
+ @GetMapping("/{letterId}")
+ public AjaxResult getInfo(@PathVariable("letterId") String letterId)
+ {
+ return success(bizSupportLetterService.getById(letterId));
+ }
+ @Log(title = "支持函", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody BizSupportLetter bizSupportLetter)
+ {
+ return toAjax(bizSupportLetterService.insert(bizSupportLetter));
+ }
+ @Log(title = "支持函", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody BizSupportLetter bizSupportLetter)
+ {
+ return toAjax(bizSupportLetterService.updateByPrimaryKey(bizSupportLetter));
+ }
+ @Log(title = "支持函", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public AjaxResult remove(@PathVariable String[] ids)
+ {
+ return toAjax(bizSupportLetterService.deleteByPrimaryKeys(ids));
+ }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/SmsController.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/SmsController.java
new file mode 100644
index 0000000..55754ed
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/controller/SmsController.java
@@ -0,0 +1,41 @@
+package com.ruoyi.business.controller;
+
+import com.ruoyi.business.dto.SmsValidForm;
+import com.ruoyi.business.service.SysSmsService;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 短信验证码接口
+ * 参考 hwt-code BizAuthApi.sendSmsOnLogin 模式
+ */
+@RestController
+@RequestMapping("/business/sms")
+public class SmsController extends BaseController {
+
+ @Autowired
+ private SysSmsService smsService;
+
+ /** 发送验证码, 返回 uuid (前端 form 校验时回传) */
+ @GetMapping("/send")
+ public AjaxResult send(@RequestParam(required = false) String phone) {
+ if (phone == null || phone.trim().isEmpty()) {
+ return error("手机号码不能为空");
+ }
+ String uuid = smsService.sendCode(phone);
+ return AjaxResult.success("ok", uuid);
+ }
+
+ /** 校验验证码 */
+ @PostMapping("/verify")
+ public AjaxResult verify(@RequestBody SmsValidForm form) {
+ try {
+ smsService.verifyCode(form);
+ } catch (RuntimeException e) {
+ return error(e.getMessage());
+ }
+ return success("ok");
+ }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizDepartment.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizDepartment.java
new file mode 100644
index 0000000..76921b2
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizDepartment.java
@@ -0,0 +1,35 @@
+package com.ruoyi.business.domain;
+
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/** 科室字典 */
+public class BizDepartment extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ @Excel(name = "ID")
+ private Long deptId;
+
+ @Excel(name = "科室名称")
+ private String name;
+
+ @Excel(name = "排序")
+ private Integer sort;
+
+ /** 0=启用 1=停用 */
+ @Excel(name = "状态", readConverterExp = "0=启用,1=停用")
+ private String status;
+
+ public Long getDeptId() { return deptId; }
+ public void setDeptId(Long deptId) { this.deptId = deptId; }
+
+ public String getName() { return name; }
+ public void setName(String name) { this.name = name; }
+
+ public Integer getSort() { return sort; }
+ public void setSort(Integer sort) { this.sort = sort; }
+
+ public String getStatus() { return status; }
+ public void setStatus(String status) { this.status = status; }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizDoctorTitle.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizDoctorTitle.java
new file mode 100644
index 0000000..86f45b3
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizDoctorTitle.java
@@ -0,0 +1,35 @@
+package com.ruoyi.business.domain;
+
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/** 医生职称字典 */
+public class BizDoctorTitle extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ @Excel(name = "ID")
+ private Long titleId;
+
+ @Excel(name = "职称名称")
+ private String name;
+
+ @Excel(name = "排序")
+ private Integer sort;
+
+ /** 0=启用 1=停用 */
+ @Excel(name = "状态", readConverterExp = "0=启用,1=停用")
+ private String status;
+
+ public Long getTitleId() { return titleId; }
+ public void setTitleId(Long titleId) { this.titleId = titleId; }
+
+ public String getName() { return name; }
+ public void setName(String name) { this.name = name; }
+
+ public Integer getSort() { return sort; }
+ public void setSort(Integer sort) { this.sort = sort; }
+
+ public String getStatus() { return status; }
+ public void setStatus(String status) { this.status = status; }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizExecutionIntent.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizExecutionIntent.java
new file mode 100644
index 0000000..0316013
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizExecutionIntent.java
@@ -0,0 +1,82 @@
+package com.ruoyi.business.domain;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/** 执行意向对象 BizExecutionIntent */
+public class BizExecutionIntent extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+ /** intentId */
+ private String intentId;
+ /** 用户ID (关联 sys_user.user_id) */
+ private Long userId;
+ /** project_no */
+ @Excel(name = "project_no")
+ private String projectNo;
+ /** project_name */
+ @Excel(name = "project_name")
+ private String projectName;
+ /** name */
+ @Excel(name = "name")
+ private String name;
+ /** work_unit */
+ @Excel(name = "work_unit")
+ private String workUnit;
+ /** department */
+ @Excel(name = "department")
+ private String department;
+ /** position */
+ @Excel(name = "position")
+ private String position;
+ /** phone */
+ @Excel(name = "phone")
+ private String phone;
+ /** onboard_status */
+ @Excel(name = "onboard_status")
+ private String onboardStatus;
+ /** create_by */
+ @Excel(name = "create_by")
+ private String createBy;
+ /** create_time */
+ @Excel(name = "create_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+ /** update_by */
+ @Excel(name = "update_by")
+ private String updateBy;
+ /** update_time */
+ @Excel(name = "update_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date updateTime;
+ public String getIntentId() { return intentId; }
+ public void setIntentId(String intentId) { this.intentId = intentId; }
+ public Long getUserId() { return userId; }
+ public void setUserId(Long userId) { this.userId = userId; }
+ public String getProjectNo() { return projectNo; }
+ public void setProjectNo(String projectNo) { this.projectNo = projectNo; }
+ public String getProjectName() { return projectName; }
+ public void setProjectName(String projectName) { this.projectName = projectName; }
+ public String getName() { return name; }
+ public void setName(String name) { this.name = name; }
+ public String getWorkUnit() { return workUnit; }
+ public void setWorkUnit(String workUnit) { this.workUnit = workUnit; }
+ public String getDepartment() { return department; }
+ public void setDepartment(String department) { this.department = department; }
+ public String getPosition() { return position; }
+ public void setPosition(String position) { this.position = position; }
+ public String getPhone() { return phone; }
+ public void setPhone(String phone) { this.phone = phone; }
+ public String getOnboardStatus() { return onboardStatus; }
+ public void setOnboardStatus(String onboardStatus) { this.onboardStatus = onboardStatus; }
+ public String getCreateBy() { return createBy; }
+ public void setCreateBy(String createBy) { this.createBy = createBy; }
+ public Date getCreateTime() { return createTime; }
+ public void setCreateTime(Date createTime) { this.createTime = createTime; }
+ public String getUpdateBy() { return updateBy; }
+ public void setUpdateBy(String updateBy) { this.updateBy = updateBy; }
+ public Date getUpdateTime() { return updateTime; }
+ public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizExpert.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizExpert.java
new file mode 100644
index 0000000..e4b8e4d
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizExpert.java
@@ -0,0 +1,137 @@
+package com.ruoyi.business.domain;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/** 专家对象 BizExpert */
+public class BizExpert extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+ /** expertId */
+ private String expertId;
+ /** name */
+ @Excel(name = "name")
+ private String name;
+ /** phone */
+ @Excel(name = "phone")
+ private String phone;
+ /** work_unit */
+ @Excel(name = "work_unit")
+ private String workUnit;
+ /** department */
+ @Excel(name = "department")
+ private String department;
+ /** title */
+ @Excel(name = "title")
+ private String title;
+ /** practice_cert_url */
+ @Excel(name = "practice_cert_url")
+ private String practiceCertUrl;
+ /** title_cert_url */
+ @Excel(name = "title_cert_url")
+ private String titleCertUrl;
+ /** audit_status */
+ @Excel(name = "audit_status")
+ private String auditStatus;
+ /** audit_by */
+ @Excel(name = "audit_by")
+ private String auditBy;
+ /** audit_time */
+ @Excel(name = "audit_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date auditTime;
+ /** create_by */
+ @Excel(name = "create_by")
+ private String createBy;
+ /** create_time */
+ @Excel(name = "create_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+ /** update_by */
+ @Excel(name = "update_by")
+ private String updateBy;
+ /** update_time */
+ @Excel(name = "update_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date updateTime;
+ /** 关联系统用户ID */
+ private Long userId;
+ /** 地区 */
+ private String region;
+ /** 证件号码 */
+ private String idCard;
+ /** 银行卡号 */
+ private String bankCard;
+ /** 银行名称 */
+ private String bankName;
+ /** 开户行省份 */
+ private String bankProvince;
+ /** 开户行城市 */
+ private String bankCity;
+ /** 开户行地址 */
+ private String bankAddress;
+ /** 身份证正面URL */
+ private String idCardFrontUrl;
+ /** 身份证反面URL */
+ private String idCardBackUrl;
+ /** 审核意见 */
+ private String auditOpinion;
+ /** 状态 0正常 1禁用 */
+ private String status;
+ public String getExpertId() { return expertId; }
+ public void setExpertId(String expertId) { this.expertId = expertId; }
+ public String getName() { return name; }
+ public void setName(String name) { this.name = name; }
+ public String getPhone() { return phone; }
+ public void setPhone(String phone) { this.phone = phone; }
+ public String getWorkUnit() { return workUnit; }
+ public void setWorkUnit(String workUnit) { this.workUnit = workUnit; }
+ public String getDepartment() { return department; }
+ public void setDepartment(String department) { this.department = department; }
+ public String getTitle() { return title; }
+ public void setTitle(String title) { this.title = title; }
+ public String getPracticeCertUrl() { return practiceCertUrl; }
+ public void setPracticeCertUrl(String practiceCertUrl) { this.practiceCertUrl = practiceCertUrl; }
+ public String getTitleCertUrl() { return titleCertUrl; }
+ public void setTitleCertUrl(String titleCertUrl) { this.titleCertUrl = titleCertUrl; }
+ public String getAuditStatus() { return auditStatus; }
+ public void setAuditStatus(String auditStatus) { this.auditStatus = auditStatus; }
+ public String getAuditBy() { return auditBy; }
+ public void setAuditBy(String auditBy) { this.auditBy = auditBy; }
+ public Date getAuditTime() { return auditTime; }
+ public void setAuditTime(Date auditTime) { this.auditTime = auditTime; }
+ public String getCreateBy() { return createBy; }
+ public void setCreateBy(String createBy) { this.createBy = createBy; }
+ public Date getCreateTime() { return createTime; }
+ public void setCreateTime(Date createTime) { this.createTime = createTime; }
+ public String getUpdateBy() { return updateBy; }
+ public void setUpdateBy(String updateBy) { this.updateBy = updateBy; }
+ public Date getUpdateTime() { return updateTime; }
+ public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }
+ public Long getUserId() { return userId; }
+ public void setUserId(Long userId) { this.userId = userId; }
+ public String getStatus() { return status; }
+ public void setStatus(String status) { this.status = status; }
+ public String getAuditOpinion() { return auditOpinion; }
+ public void setAuditOpinion(String auditOpinion) { this.auditOpinion = auditOpinion; }
+ public String getRegion() { return region; }
+ public void setRegion(String region) { this.region = region; }
+ public String getIdCard() { return idCard; }
+ public void setIdCard(String idCard) { this.idCard = idCard; }
+ public String getBankCard() { return bankCard; }
+ public void setBankCard(String bankCard) { this.bankCard = bankCard; }
+ public String getBankName() { return bankName; }
+ public void setBankName(String bankName) { this.bankName = bankName; }
+ public String getBankProvince() { return bankProvince; }
+ public void setBankProvince(String bankProvince) { this.bankProvince = bankProvince; }
+ public String getBankCity() { return bankCity; }
+ public void setBankCity(String bankCity) { this.bankCity = bankCity; }
+ public String getBankAddress() { return bankAddress; }
+ public void setBankAddress(String bankAddress) { this.bankAddress = bankAddress; }
+ public String getIdCardFrontUrl() { return idCardFrontUrl; }
+ public void setIdCardFrontUrl(String idCardFrontUrl) { this.idCardFrontUrl = idCardFrontUrl; }
+ public String getIdCardBackUrl() { return idCardBackUrl; }
+ public void setIdCardBackUrl(String idCardBackUrl) { this.idCardBackUrl = idCardBackUrl; }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizInvitation.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizInvitation.java
new file mode 100644
index 0000000..d9e1c3b
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizInvitation.java
@@ -0,0 +1,78 @@
+package com.ruoyi.business.domain;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/** 邀请函对象 BizInvitation */
+public class BizInvitation extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+ /** annId */
+ private String annId;
+ /** title */
+ @Excel(name = "title")
+ private String title;
+ /** meeting_name */
+ @Excel(name = "meeting_name")
+ private String meetingName;
+ /** expert_name */
+ @Excel(name = "expert_name")
+ private String expertName;
+ /** content */
+ @Excel(name = "content")
+ private String content;
+ /** issue_date */
+ @Excel(name = "issue_date")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date issueDate;
+ /** create_by */
+ @Excel(name = "create_by")
+ private String createBy;
+ /** create_time */
+ @Excel(name = "create_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+ /** update_by */
+ @Excel(name = "update_by")
+ private String updateBy;
+ /** update_time */
+ @Excel(name = "update_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date updateTime;
+ /** 邀请函ID */
+ private Long inviteId;
+ /** 项目ID */
+ private Long projectId;
+ /** 项目编号 */
+ private String projectNo;
+ /** 邀请函模板URL */
+ private String templateUrl;
+ /** 二维码URL */
+ private String qrCodeUrl;
+ /** 分享URL */
+ private String shareUrl;
+ /** 发布时间 */
+ private String publishTime;
+ public String getAnnId() { return annId; }
+ public void setAnnId(String annId) { this.annId = annId; }
+ public String getTitle() { return title; }
+ public void setTitle(String title) { this.title = title; }
+ public String getMeetingName() { return meetingName; }
+ public void setMeetingName(String meetingName) { this.meetingName = meetingName; }
+ public String getExpertName() { return expertName; }
+ public void setExpertName(String expertName) { this.expertName = expertName; }
+ public String getContent() { return content; }
+ public void setContent(String content) { this.content = content; }
+ public Date getIssueDate() { return issueDate; }
+ public void setIssueDate(Date issueDate) { this.issueDate = issueDate; }
+ public String getCreateBy() { return createBy; }
+ public void setCreateBy(String createBy) { this.createBy = createBy; }
+ public Date getCreateTime() { return createTime; }
+ public void setCreateTime(Date createTime) { this.createTime = createTime; }
+ public String getUpdateBy() { return updateBy; }
+ public void setUpdateBy(String updateBy) { this.updateBy = updateBy; }
+ public Date getUpdateTime() { return updateTime; }
+ public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizLaborVoucher.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizLaborVoucher.java
new file mode 100644
index 0000000..5d0561c
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizLaborVoucher.java
@@ -0,0 +1,87 @@
+package com.ruoyi.business.domain;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/** 劳务凭证对象 BizLaborVoucher */
+public class BizLaborVoucher extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+ /** voucherId */
+ private String voucherId;
+ /** voucher_no */
+ @Excel(name = "voucher_no")
+ private String voucherNo;
+ /** meeting_name */
+ @Excel(name = "meeting_name")
+ private String meetingName;
+ /** expert_name */
+ @Excel(name = "expert_name")
+ private String expertName;
+ /** id_card */
+ @Excel(name = "id_card")
+ private String idCard;
+ /** bank_account */
+ @Excel(name = "bank_account")
+ private String bankAccount;
+ /** amount */
+ @Excel(name = "amount")
+ private BigDecimal amount;
+ /** submit_date */
+ @Excel(name = "submit_date")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date submitDate;
+ /** audit_status */
+ @Excel(name = "audit_status")
+ private String auditStatus;
+ /** create_by */
+ @Excel(name = "create_by")
+ private String createBy;
+ /** create_time */
+ @Excel(name = "create_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+ /** update_by */
+ @Excel(name = "update_by")
+ private String updateBy;
+ /** update_time */
+ @Excel(name = "update_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date updateTime;
+ /** 会议ID */
+ private Long meetingId;
+ /** 审核意见 */
+ private String auditOpinion;
+ /** 审核人 */
+ private String auditBy;
+ /** 审核时间 */
+ private String auditTime;
+ public String getVoucherId() { return voucherId; }
+ public void setVoucherId(String voucherId) { this.voucherId = voucherId; }
+ public String getVoucherNo() { return voucherNo; }
+ public void setVoucherNo(String voucherNo) { this.voucherNo = voucherNo; }
+ public String getMeetingName() { return meetingName; }
+ public void setMeetingName(String meetingName) { this.meetingName = meetingName; }
+ public String getExpertName() { return expertName; }
+ public void setExpertName(String expertName) { this.expertName = expertName; }
+ public String getIdCard() { return idCard; }
+ public void setIdCard(String idCard) { this.idCard = idCard; }
+ public String getBankAccount() { return bankAccount; }
+ public void setBankAccount(String bankAccount) { this.bankAccount = bankAccount; }
+ public BigDecimal getAmount() { return amount; }
+ public void setAmount(BigDecimal amount) { this.amount = amount; }
+ public Date getSubmitDate() { return submitDate; }
+ public void setSubmitDate(Date submitDate) { this.submitDate = submitDate; }
+ public String getAuditStatus() { return auditStatus; }
+ public void setAuditStatus(String auditStatus) { this.auditStatus = auditStatus; }
+ public String getCreateBy() { return createBy; }
+ public void setCreateBy(String createBy) { this.createBy = createBy; }
+ public Date getCreateTime() { return createTime; }
+ public void setCreateTime(Date createTime) { this.createTime = createTime; }
+ public String getUpdateBy() { return updateBy; }
+ public void setUpdateBy(String updateBy) { this.updateBy = updateBy; }
+ public Date getUpdateTime() { return updateTime; }
+ public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizMeeting.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizMeeting.java
new file mode 100644
index 0000000..5f725f6
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizMeeting.java
@@ -0,0 +1,103 @@
+package com.ruoyi.business.domain;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/** 会议对象 BizMeeting */
+public class BizMeeting extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+ /** meetingId */
+ private String meetingId;
+ /** project_no */
+ @Excel(name = "project_no")
+ private String projectNo;
+ /** business_id */
+ @Excel(name = "business_id")
+ private String businessId;
+ /** project_form */
+ @Excel(name = "project_form")
+ private String projectForm;
+ /** meeting_name */
+ @Excel(name = "meeting_name")
+ private String meetingName;
+ /** start_time */
+ @Excel(name = "start_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date startTime;
+ /** end_time */
+ @Excel(name = "end_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date endTime;
+ /** total_periods */
+ @Excel(name = "total_periods")
+ private Long totalPeriods;
+ /** period_no */
+ @Excel(name = "period_no")
+ private Long periodNo;
+ /** current_stage */
+ @Excel(name = "current_stage")
+ private String currentStage;
+ /** create_by */
+ @Excel(name = "create_by")
+ private String createBy;
+ /** create_time */
+ @Excel(name = "create_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+ /** update_by */
+ @Excel(name = "update_by")
+ private String updateBy;
+ /** update_time */
+ @Excel(name = "update_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date updateTime;
+ /** 所属项目ID */
+ private Long projectId;
+ /** 项目名称 */
+ private String projectName;
+ /** 所属公司名称 (冗余字段, 由 biz_project.org_name 同步) */
+ private String orgName;
+ /** 监察意见 */
+ private String supervisionOpinion;
+ /** 监察人 */
+ private String supervisionBy;
+ /** 监察时间 */
+ private String supervisionTime;
+ /** 邀请函URL */
+ private String invitationUrl;
+ /** 日程海报URL */
+ private String scheduleUrl;
+ /** 签署劳务 0未签 1已签 */
+ private String laborSigned;
+ public String getMeetingId() { return meetingId; }
+ public void setMeetingId(String meetingId) { this.meetingId = meetingId; }
+ public String getProjectNo() { return projectNo; }
+ public void setProjectNo(String projectNo) { this.projectNo = projectNo; }
+ public String getBusinessId() { return businessId; }
+ public void setBusinessId(String businessId) { this.businessId = businessId; }
+ public String getProjectForm() { return projectForm; }
+ public void setProjectForm(String projectForm) { this.projectForm = projectForm; }
+ public String getMeetingName() { return meetingName; }
+ public void setMeetingName(String meetingName) { this.meetingName = meetingName; }
+ public Date getStartTime() { return startTime; }
+ public void setStartTime(Date startTime) { this.startTime = startTime; }
+ public Date getEndTime() { return endTime; }
+ public void setEndTime(Date endTime) { this.endTime = endTime; }
+ public Long getTotalPeriods() { return totalPeriods; }
+ public void setTotalPeriods(Long totalPeriods) { this.totalPeriods = totalPeriods; }
+ public Long getPeriodNo() { return periodNo; }
+ public void setPeriodNo(Long periodNo) { this.periodNo = periodNo; }
+ public String getCurrentStage() { return currentStage; }
+ public void setCurrentStage(String currentStage) { this.currentStage = currentStage; }
+ public String getCreateBy() { return createBy; }
+ public void setCreateBy(String createBy) { this.createBy = createBy; }
+ public Date getCreateTime() { return createTime; }
+ public void setCreateTime(Date createTime) { this.createTime = createTime; }
+ public String getUpdateBy() { return updateBy; }
+ public void setUpdateBy(String updateBy) { this.updateBy = updateBy; }
+ public Date getUpdateTime() { return updateTime; }
+ public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizMeetingSettlement.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizMeetingSettlement.java
new file mode 100644
index 0000000..ace4b15
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizMeetingSettlement.java
@@ -0,0 +1,87 @@
+package com.ruoyi.business.domain;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/** 会议结算明细对象 BizMeetingSettlement */
+public class BizMeetingSettlement extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+ /** id */
+ private String id;
+ /** project_no */
+ @Excel(name = "project_no")
+ private String projectNo;
+ /** meeting_id */
+ @Excel(name = "meeting_id")
+ private Long meetingId;
+ /** fee_type */
+ @Excel(name = "fee_type")
+ private String feeType;
+ /** unit_price */
+ @Excel(name = "unit_price")
+ private BigDecimal unitPrice;
+ /** qty */
+ @Excel(name = "qty")
+ private Long qty;
+ /** subtotal */
+ @Excel(name = "subtotal")
+ private BigDecimal subtotal;
+ /** remark */
+ @Excel(name = "remark")
+ private String remark;
+ /** audit_status */
+ @Excel(name = "audit_status")
+ private String auditStatus;
+ /** settlement_type */
+ @Excel(name = "settlement_type")
+ private String settlementType;
+ /** create_by */
+ @Excel(name = "create_by")
+ private String createBy;
+ /** create_time */
+ @Excel(name = "create_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+ /** update_by */
+ @Excel(name = "update_by")
+ private String updateBy;
+ /** update_time */
+ @Excel(name = "update_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date updateTime;
+ /** 会议名称 */
+ private String projectName;
+ /** 执行单位 */
+ private String execUnit;
+ public String getId() { return id; }
+ public void setId(String id) { this.id = id; }
+ public String getProjectNo() { return projectNo; }
+ public void setProjectNo(String projectNo) { this.projectNo = projectNo; }
+ public Long getMeetingId() { return meetingId; }
+ public void setMeetingId(Long meetingId) { this.meetingId = meetingId; }
+ public String getFeeType() { return feeType; }
+ public void setFeeType(String feeType) { this.feeType = feeType; }
+ public BigDecimal getUnitPrice() { return unitPrice; }
+ public void setUnitPrice(BigDecimal unitPrice) { this.unitPrice = unitPrice; }
+ public Long getQty() { return qty; }
+ public void setQty(Long qty) { this.qty = qty; }
+ public BigDecimal getSubtotal() { return subtotal; }
+ public void setSubtotal(BigDecimal subtotal) { this.subtotal = subtotal; }
+ public String getRemark() { return remark; }
+ public void setRemark(String remark) { this.remark = remark; }
+ public String getAuditStatus() { return auditStatus; }
+ public void setAuditStatus(String auditStatus) { this.auditStatus = auditStatus; }
+ public String getSettlementType() { return settlementType; }
+ public void setSettlementType(String settlementType) { this.settlementType = settlementType; }
+ public String getCreateBy() { return createBy; }
+ public void setCreateBy(String createBy) { this.createBy = createBy; }
+ public Date getCreateTime() { return createTime; }
+ public void setCreateTime(Date createTime) { this.createTime = createTime; }
+ public String getUpdateBy() { return updateBy; }
+ public void setUpdateBy(String updateBy) { this.updateBy = updateBy; }
+ public Date getUpdateTime() { return updateTime; }
+ public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizMessage.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizMessage.java
new file mode 100644
index 0000000..632044a
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizMessage.java
@@ -0,0 +1,78 @@
+package com.ruoyi.business.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/** 个人通知消息对象 biz_message */
+public class BizMessage extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ /** msg_id */
+ private Long msgId;
+
+ /** 接收人 user_id */
+ @Excel(name = "接收人")
+ private Long receiverUserId;
+
+ /** 接收人姓名 (联表显示) */
+ @Excel(name = "接收人")
+ private String receiverName;
+
+ /** 消息类型 1通知 2待办 3系统 */
+ @Excel(name = "类型")
+ private String msgType;
+
+ /** 标题 */
+ @Excel(name = "标题")
+ private String title;
+
+ /** 内容 */
+ private String content;
+
+ /** 业务类型 auth/project/meeting/agreement */
+ private String bizType;
+
+ /** 关联业务ID */
+ private Long bizId;
+
+ /** 已读 0否 1是 */
+ @Excel(name = "已读")
+ private String isRead;
+
+ /** 已读时间 */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date readTime;
+
+ public Long getMsgId() { return msgId; }
+ public void setMsgId(Long msgId) { this.msgId = msgId; }
+
+ public Long getReceiverUserId() { return receiverUserId; }
+ public void setReceiverUserId(Long receiverUserId) { this.receiverUserId = receiverUserId; }
+
+ public String getReceiverName() { return receiverName; }
+ public void setReceiverName(String receiverName) { this.receiverName = receiverName; }
+
+ public String getMsgType() { return msgType; }
+ public void setMsgType(String msgType) { this.msgType = msgType; }
+
+ public String getTitle() { return title; }
+ public void setTitle(String title) { this.title = title; }
+
+ public String getContent() { return content; }
+ public void setContent(String content) { this.content = content; }
+
+ public String getBizType() { return bizType; }
+ public void setBizType(String bizType) { this.bizType = bizType; }
+
+ public Long getBizId() { return bizId; }
+ public void setBizId(Long bizId) { this.bizId = bizId; }
+
+ public String getIsRead() { return isRead; }
+ public void setIsRead(String isRead) { this.isRead = isRead; }
+
+ public Date getReadTime() { return readTime; }
+ public void setReadTime(Date readTime) { this.readTime = readTime; }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizOrg.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizOrg.java
new file mode 100644
index 0000000..89276ee
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizOrg.java
@@ -0,0 +1,75 @@
+package com.ruoyi.business.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 公司对象 biz_org
+ * 用途: 赞助方(sponsor) + 执行方(execution) 共用
+ * 重构说明: 原 biz_support_unit + biz_execution_unit 合并, 通过 org_type 区分
+ */
+public class BizOrg extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+ /** org_id */
+ private Long orgId;
+ /** org_name */
+ @Excel(name = "org_name")
+ private String orgName;
+ /** org_type: sponsor赞助方 / execution执行方 */
+ @Excel(name = "org_type")
+ private String orgType;
+ /** 企业性质 私营/国营/中外合资/外资/其他 */
+ @Excel(name = "business_nature")
+ private String businessNature;
+ /** address */
+ @Excel(name = "address")
+ private String address;
+ /** tax_no */
+ @Excel(name = "tax_no")
+ private String taxNo;
+ /** contact_name */
+ @Excel(name = "contact_name")
+ private String contactName;
+ /** contact_phone */
+ @Excel(name = "contact_phone")
+ private String contactPhone;
+ /** intent_count (仅赞助方用) */
+ @Excel(name = "intent_count")
+ private Integer intentCount;
+ /** status */
+ @Excel(name = "status")
+ private String status;
+ /** create_time */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+ /** update_time */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date updateTime;
+
+ public Long getOrgId() { return orgId; }
+ public void setOrgId(Long orgId) { this.orgId = orgId; }
+ public String getOrgName() { return orgName; }
+ public void setOrgName(String orgName) { this.orgName = orgName; }
+ public String getOrgType() { return orgType; }
+ public void setOrgType(String orgType) { this.orgType = orgType; }
+ public String getBusinessNature() { return businessNature; }
+ public void setBusinessNature(String businessNature) { this.businessNature = businessNature; }
+ public String getAddress() { return address; }
+ public void setAddress(String address) { this.address = address; }
+ public String getTaxNo() { return taxNo; }
+ public void setTaxNo(String taxNo) { this.taxNo = taxNo; }
+ public String getContactName() { return contactName; }
+ public void setContactName(String contactName) { this.contactName = contactName; }
+ public String getContactPhone() { return contactPhone; }
+ public void setContactPhone(String contactPhone) { this.contactPhone = contactPhone; }
+ public Integer getIntentCount() { return intentCount; }
+ public void setIntentCount(Integer intentCount) { this.intentCount = intentCount; }
+ public String getStatus() { return status; }
+ public void setStatus(String status) { this.status = status; }
+ public Date getCreateTime() { return createTime; }
+ public void setCreateTime(Date createTime) { this.createTime = createTime; }
+ public Date getUpdateTime() { return updateTime; }
+ public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizPerson.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizPerson.java
new file mode 100644
index 0000000..f130758
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizPerson.java
@@ -0,0 +1,108 @@
+package com.ruoyi.business.domain;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/** 人员对象 BizPerson */
+public class BizPerson extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+ /** personId */
+ private String personId;
+ /** name */
+ @Excel(name = "name")
+ private String name;
+ /** phone */
+ @Excel(name = "phone")
+ private String phone;
+ /** 所属公司ID (FK: biz_org.org_id) */
+ private Long orgId;
+ /** 所属公司名 (LEFT JOIN biz_org, 仅展示, 不入库) */
+ private String orgName;
+ /** 所属公司类型 (LEFT JOIN biz_org, 仅展示, 不入库) */
+ private String orgType;
+ /** department */
+ @Excel(name = "department")
+ private String department;
+ /** position */
+ @Excel(name = "position")
+ private String position;
+ /** role */
+ @Excel(name = "role")
+ private String role;
+ /** status */
+ @Excel(name = "status")
+ private String status;
+ /** 逻辑删除 0正常 1已删 */
+ private String delFlag;
+ /** create_by */
+ @Excel(name = "create_by")
+ private String createBy;
+ /** create_time */
+ @Excel(name = "create_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+ /** update_by */
+ @Excel(name = "update_by")
+ private String updateBy;
+ /** update_time */
+ @Excel(name = "update_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date updateTime;
+ /** 关联系统用户ID */
+ private Long userId;
+ /** 所属单位类型 execution执行/sponsor支持 */
+ private String unitType;
+ /** 账号类型 (来自 sys_user.account_type, MAIN=主账号 / SUB=子账号) - 仅展示用,不入库 */
+ private String accountType;
+ /** 主账号ID (来自 sys_user.parent_user_id, 子账号指向其主账号) - 仅展示用 */
+ private Long parentUserId;
+ /** 子账号登录账号 (前端传入, 用于创建 sys_user 子账号) - 非持久化字段 */
+ private transient String loginUsername;
+ /** 子账号初始密码 (前端传入, 明文, 创建后不存储明文) - 非持久化字段 */
+ private transient String loginPassword;
+ public String getPersonId() { return personId; }
+ public void setPersonId(String personId) { this.personId = personId; }
+ public String getName() { return name; }
+ public void setName(String name) { this.name = name; }
+ public String getPhone() { return phone; }
+ public void setPhone(String phone) { this.phone = phone; }
+ public Long getOrgId() { return orgId; }
+ public void setOrgId(Long orgId) { this.orgId = orgId; }
+ public String getOrgName() { return orgName; }
+ public void setOrgName(String orgName) { this.orgName = orgName; }
+ public String getOrgType() { return orgType; }
+ public void setOrgType(String orgType) { this.orgType = orgType; }
+ public String getDepartment() { return department; }
+ public void setDepartment(String department) { this.department = department; }
+ public String getPosition() { return position; }
+ public void setPosition(String position) { this.position = position; }
+ public String getRole() { return role; }
+ public void setRole(String role) { this.role = role; }
+ public String getStatus() { return status; }
+ public void setStatus(String status) { this.status = status; }
+ public String getDelFlag() { return delFlag; }
+ public void setDelFlag(String delFlag) { this.delFlag = delFlag; }
+ public String getCreateBy() { return createBy; }
+ public void setCreateBy(String createBy) { this.createBy = createBy; }
+ public Date getCreateTime() { return createTime; }
+ public void setCreateTime(Date createTime) { this.createTime = createTime; }
+ public String getUpdateBy() { return updateBy; }
+ public void setUpdateBy(String updateBy) { this.updateBy = updateBy; }
+ public Date getUpdateTime() { return updateTime; }
+ public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }
+ public Long getUserId() { return userId; }
+ public void setUserId(Long userId) { this.userId = userId; }
+ public String getUnitType() { return unitType; }
+ public void setUnitType(String unitType) { this.unitType = unitType; }
+ public String getAccountType() { return accountType; }
+ public void setAccountType(String accountType) { this.accountType = accountType; }
+ public Long getParentUserId() { return parentUserId; }
+ public void setParentUserId(Long parentUserId) { this.parentUserId = parentUserId; }
+ public String getLoginUsername() { return loginUsername; }
+ public void setLoginUsername(String loginUsername) { this.loginUsername = loginUsername; }
+ public String getLoginPassword() { return loginPassword; }
+ public void setLoginPassword(String loginPassword) { this.loginPassword = loginPassword; }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizPersonImportVO.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizPersonImportVO.java
new file mode 100644
index 0000000..d819fb5
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizPersonImportVO.java
@@ -0,0 +1,51 @@
+package com.ruoyi.business.domain;
+
+import com.ruoyi.common.annotation.Excel;
+
+/**
+ * sponsor 端人员批量导入 VO (中文列头, 用 ruoyi ExcelUtil 解析)
+ *
+ * 区别于 BizPerson 实体: 这里只暴露用户能填写的业务字段, 不包含内部 id/审计字段,
+ * 列头按原型 sponsor-new-person.html: 姓名/手机号/所属公司/部门/职务/角色/状态.
+ *
+ *
导入后端会按以下规则创建 sys_user 子账号 (parent_user_id=当前登录主账号):
+ *
+ * loginUsername = 手机号 (要求唯一)
+ * loginPassword = "123456" (默认密码, 前端 toast 提示用户)
+ * unitType = "sponsor"
+ * orgId = 业务层按 orgName 查 biz_org 取 org_id (TODO: SponsorPeople 那边 import 接口需补这步)
+ *
+ */
+public class BizPersonImportVO
+{
+ @Excel(name = "姓名", sort = 1)
+ private String name;
+
+ @Excel(name = "手机号", sort = 2)
+ private String phone;
+
+ @Excel(name = "所属公司", sort = 3)
+ private String orgName;
+
+ @Excel(name = "部门", sort = 4)
+ private String department;
+
+ @Excel(name = "职务", sort = 5)
+ private String position;
+
+ @Excel(name = "角色", sort = 6)
+ private String role;
+
+ public String getName() { return name; }
+ public void setName(String name) { this.name = name; }
+ public String getPhone() { return phone; }
+ public void setPhone(String phone) { this.phone = phone; }
+ public String getOrgName() { return orgName; }
+ public void setOrgName(String orgName) { this.orgName = orgName; }
+ public String getDepartment() { return department; }
+ public void setDepartment(String department) { this.department = department; }
+ public String getPosition() { return position; }
+ public void setPosition(String position) { this.position = position; }
+ public String getRole() { return role; }
+ public void setRole(String role) { this.role = role; }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProject.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProject.java
new file mode 100644
index 0000000..49b56d7
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProject.java
@@ -0,0 +1,212 @@
+package com.ruoyi.business.domain;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/** 项目对象 BizProject */
+public class BizProject extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+ /** projectId */
+ private String projectId;
+ /** project_no */
+ @Excel(name = "project_no")
+ private String projectNo;
+ /** project_name */
+ @Excel(name = "project_name")
+ private String projectName;
+ /** total_sessions */
+ @Excel(name = "total_sessions")
+ private Long totalSessions;
+ /** done_sessions */
+ @Excel(name = "done_sessions")
+ private Long doneSessions;
+ /** todo_sessions */
+ @Excel(name = "todo_sessions")
+ private Long todoSessions;
+ /** total_amount */
+ @Excel(name = "total_amount")
+ private BigDecimal totalAmount;
+ /** available_amount */
+ @Excel(name = "available_amount")
+ private BigDecimal availableAmount;
+ /** paid_labor_amount */
+ @Excel(name = "paid_labor_amount")
+ private BigDecimal paidLaborAmount;
+ /** paid_meeting_amount */
+ @Excel(name = "paid_meeting_amount")
+ private BigDecimal paidMeetingAmount;
+ /** rating_score (平均分) */
+ @Excel(name = "rating_score")
+ private BigDecimal ratingScore;
+ /** 评分维度: 履约质量 */
+ private BigDecimal ratingQ1;
+ /** 评分维度: 时效响应 */
+ private BigDecimal ratingQ2;
+ /** 评分维度: 配合度 */
+ private BigDecimal ratingQ3;
+ /** 评分维度: 合规安全 */
+ private BigDecimal ratingQ4;
+ /** org_name (赞助方/执行方, 由 org_type 区分) */
+ @Excel(name = "org_name")
+ private String orgName;
+ /** org_type: sponsor 赞助方 / execution 执行方 */
+ @Excel(name = "org_type")
+ private String orgType;
+ /** project_form */
+ @Excel(name = "project_form")
+ private String projectForm;
+ /** is_finished */
+ @Excel(name = "is_finished")
+ private String isFinished;
+ /** is_settled */
+ @Excel(name = "is_settled")
+ private String isSettled;
+ /** org_id (赞助方/执行方, 由 org_type 区分) */
+ @Excel(name = "org_id")
+ private Long orgId;
+ /** create_by */
+ @Excel(name = "create_by")
+ private String createBy;
+ /** create_time */
+ @Excel(name = "create_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+ /** update_by */
+ @Excel(name = "update_by")
+ private String updateBy;
+ /** update_time */
+ @Excel(name = "update_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date updateTime;
+ /** 管理费及税金 */
+ private BigDecimal manageFee;
+ /** 项目开始时间 */
+ private String startTime;
+ /** 项目结束时间 */
+ private String endTime;
+ /** 提交材料截止天数 */
+ private Integer submitDeadlineDays;
+ /** 支持合同文件URL */
+ private String supportContractUrl;
+ /** 执行合同文件URL */
+ private String executeContractUrl;
+ /** 邀请函文件URL */
+ private String invitationUrl;
+ /** 支持函文件URL */
+ private String supportLetterUrl;
+ /** 已发布公告URL */
+ private String publishUrl;
+ /** 通知文件URL */
+ private String noticeUrl;
+ /** 日程文件URL */
+ private String scheduleUrl;
+ /** 是否已发布公示 0否 1是 */
+ private String isPublished;
+ /** 发布时间 */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date publishTime;
+ /** 公告类型 (邀请函/支持函/通知/日程/公示) */
+ private String announcementType;
+
+ /* ============ 赞助方评分字段 (来自 biz_project_sponsor 中间表, 仅展示用) ============ */
+ /** 当前 login 用户对该项目的平均分 */
+ private BigDecimal sponsorRating;
+ private Integer sponsorQ1;
+ private Integer sponsorQ2;
+ private Integer sponsorQ3;
+ private Integer sponsorQ4;
+ private String sponsorRemark;
+ public String getProjectId() { return projectId; }
+ public void setProjectId(String projectId) { this.projectId = projectId; }
+ public String getProjectNo() { return projectNo; }
+ public void setProjectNo(String projectNo) { this.projectNo = projectNo; }
+ public String getProjectName() { return projectName; }
+ public void setProjectName(String projectName) { this.projectName = projectName; }
+ public Long getTotalSessions() { return totalSessions; }
+ public void setTotalSessions(Long totalSessions) { this.totalSessions = totalSessions; }
+ public Long getDoneSessions() { return doneSessions; }
+ public void setDoneSessions(Long doneSessions) { this.doneSessions = doneSessions; }
+ public Long getTodoSessions() { return todoSessions; }
+ public void setTodoSessions(Long todoSessions) { this.todoSessions = todoSessions; }
+ public BigDecimal getTotalAmount() { return totalAmount; }
+ public void setTotalAmount(BigDecimal totalAmount) { this.totalAmount = totalAmount; }
+ public BigDecimal getAvailableAmount() { return availableAmount; }
+ public void setAvailableAmount(BigDecimal availableAmount) { this.availableAmount = availableAmount; }
+ public BigDecimal getPaidLaborAmount() { return paidLaborAmount; }
+ public void setPaidLaborAmount(BigDecimal paidLaborAmount) { this.paidLaborAmount = paidLaborAmount; }
+ public BigDecimal getPaidMeetingAmount() { return paidMeetingAmount; }
+ public void setPaidMeetingAmount(BigDecimal paidMeetingAmount) { this.paidMeetingAmount = paidMeetingAmount; }
+ public BigDecimal getRatingScore() { return ratingScore; }
+ public void setRatingScore(BigDecimal ratingScore) { this.ratingScore = ratingScore; }
+ public BigDecimal getRatingQ1() { return ratingQ1; }
+ public void setRatingQ1(BigDecimal ratingQ1) { this.ratingQ1 = ratingQ1; }
+ public BigDecimal getRatingQ2() { return ratingQ2; }
+ public void setRatingQ2(BigDecimal ratingQ2) { this.ratingQ2 = ratingQ2; }
+ public BigDecimal getRatingQ3() { return ratingQ3; }
+ public void setRatingQ3(BigDecimal ratingQ3) { this.ratingQ3 = ratingQ3; }
+ public BigDecimal getRatingQ4() { return ratingQ4; }
+ public void setRatingQ4(BigDecimal ratingQ4) { this.ratingQ4 = ratingQ4; }
+ public String getOrgName() { return orgName; }
+ public void setOrgName(String orgName) { this.orgName = orgName; }
+ public String getOrgType() { return orgType; }
+ public void setOrgType(String orgType) { this.orgType = orgType; }
+ public String getProjectForm() { return projectForm; }
+ public void setProjectForm(String projectForm) { this.projectForm = projectForm; }
+ public String getIsFinished() { return isFinished; }
+ public void setIsFinished(String isFinished) { this.isFinished = isFinished; }
+ public String getIsSettled() { return isSettled; }
+ public void setIsSettled(String isSettled) { this.isSettled = isSettled; }
+ public Long getOrgId() { return orgId; }
+ public void setOrgId(Long orgId) { this.orgId = orgId; }
+ public String getCreateBy() { return createBy; }
+ public void setCreateBy(String createBy) { this.createBy = createBy; }
+ public Date getCreateTime() { return createTime; }
+ public void setCreateTime(Date createTime) { this.createTime = createTime; }
+ public String getUpdateBy() { return updateBy; }
+ public void setUpdateBy(String updateBy) { this.updateBy = updateBy; }
+ public Date getUpdateTime() { return updateTime; }
+ public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }
+ public BigDecimal getManageFee() { return manageFee; }
+ public void setManageFee(BigDecimal manageFee) { this.manageFee = manageFee; }
+ public String getStartTime() { return startTime; }
+ public void setStartTime(String startTime) { this.startTime = startTime; }
+ public String getEndTime() { return endTime; }
+ public void setEndTime(String endTime) { this.endTime = endTime; }
+ public Integer getSubmitDeadlineDays() { return submitDeadlineDays; }
+ public void setSubmitDeadlineDays(Integer submitDeadlineDays) { this.submitDeadlineDays = submitDeadlineDays; }
+ public String getSupportContractUrl() { return supportContractUrl; }
+ public void setSupportContractUrl(String supportContractUrl) { this.supportContractUrl = supportContractUrl; }
+ public String getExecuteContractUrl() { return executeContractUrl; }
+ public void setExecuteContractUrl(String executeContractUrl) { this.executeContractUrl = executeContractUrl; }
+ public String getInvitationUrl() { return invitationUrl; }
+ public void setInvitationUrl(String invitationUrl) { this.invitationUrl = invitationUrl; }
+ public String getSupportLetterUrl() { return supportLetterUrl; }
+ public void setSupportLetterUrl(String supportLetterUrl) { this.supportLetterUrl = supportLetterUrl; }
+ public String getPublishUrl() { return publishUrl; }
+ public void setPublishUrl(String publishUrl) { this.publishUrl = publishUrl; }
+ public String getNoticeUrl() { return noticeUrl; }
+ public void setNoticeUrl(String noticeUrl) { this.noticeUrl = noticeUrl; }
+ public String getScheduleUrl() { return scheduleUrl; }
+ public void setScheduleUrl(String scheduleUrl) { this.scheduleUrl = scheduleUrl; }
+ public String getIsPublished() { return isPublished; }
+ public void setIsPublished(String isPublished) { this.isPublished = isPublished; }
+ public Date getPublishTime() { return publishTime; }
+ public void setPublishTime(Date publishTime) { this.publishTime = publishTime; }
+ public String getAnnouncementType() { return announcementType; }
+ public void setAnnouncementType(String announcementType) { this.announcementType = announcementType; }
+ public BigDecimal getSponsorRating() { return sponsorRating; }
+ public void setSponsorRating(BigDecimal sponsorRating) { this.sponsorRating = sponsorRating; }
+ public Integer getSponsorQ1() { return sponsorQ1; }
+ public void setSponsorQ1(Integer sponsorQ1) { this.sponsorQ1 = sponsorQ1; }
+ public Integer getSponsorQ2() { return sponsorQ2; }
+ public void setSponsorQ2(Integer sponsorQ2) { this.sponsorQ2 = sponsorQ2; }
+ public Integer getSponsorQ3() { return sponsorQ3; }
+ public void setSponsorQ3(Integer sponsorQ3) { this.sponsorQ3 = sponsorQ3; }
+ public Integer getSponsorQ4() { return sponsorQ4; }
+ public void setSponsorQ4(Integer sponsorQ4) { this.sponsorQ4 = sponsorQ4; }
+ public String getSponsorRemark() { return sponsorRemark; }
+ public void setSponsorRemark(String sponsorRemark) { this.sponsorRemark = sponsorRemark; }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProjectAssign.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProjectAssign.java
new file mode 100644
index 0000000..b5c496f
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProjectAssign.java
@@ -0,0 +1,50 @@
+package com.ruoyi.business.domain;
+
+import java.math.BigDecimal;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/** 项目执行方分配对象 BizProjectAssign */
+public class BizProjectAssign extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+ /** assign_id */
+ private String assignId;
+ /** project_id */
+ private Long projectId;
+ /** 执行方用户ID (sys_user.user_id) */
+ private Long execUserId;
+ /** 执行方用户名 (denormalized) */
+ private String execUserName;
+ /** 执行方昵称 (denormalized) */
+ private String execNickName;
+ /** 执行方所属机构 (denormalized) */
+ private String execOrg;
+ /** 分配场次 */
+ private Integer sessions;
+ /** 分配金额 */
+ private BigDecimal amount;
+ /** 备注 */
+ private String remark;
+ /** 状态 0正常 1已撤销 */
+ private String status;
+
+ public String getAssignId() { return assignId; }
+ public void setAssignId(String assignId) { this.assignId = assignId; }
+ public Long getProjectId() { return projectId; }
+ public void setProjectId(Long projectId) { this.projectId = projectId; }
+ public Long getExecUserId() { return execUserId; }
+ public void setExecUserId(Long execUserId) { this.execUserId = execUserId; }
+ public String getExecUserName() { return execUserName; }
+ public void setExecUserName(String execUserName) { this.execUserName = execUserName; }
+ public String getExecNickName() { return execNickName; }
+ public void setExecNickName(String execNickName) { this.execNickName = execNickName; }
+ public String getExecOrg() { return execOrg; }
+ public void setExecOrg(String execOrg) { this.execOrg = execOrg; }
+ public Integer getSessions() { return sessions; }
+ public void setSessions(Integer sessions) { this.sessions = sessions; }
+ public BigDecimal getAmount() { return amount; }
+ public void setAmount(BigDecimal amount) { this.amount = amount; }
+ public String getRemark() { return remark; }
+ public void setRemark(String remark) { this.remark = remark; }
+ public String getStatus() { return status; }
+ public void setStatus(String status) { this.status = status; }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProjectPlan.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProjectPlan.java
new file mode 100644
index 0000000..cece1ed
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProjectPlan.java
@@ -0,0 +1,94 @@
+package com.ruoyi.business.domain;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/** 项目策划方案对象 BizProjectPlan */
+public class BizProjectPlan extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+ /** planId */
+ private String planId;
+ /** plan_name */
+ @Excel(name = "plan_name")
+ private String planName;
+ /** plan_direction */
+ @Excel(name = "plan_direction")
+ private String planDirection;
+ /** plan_category */
+ @Excel(name = "plan_category")
+ private String planCategory;
+ /** project_form */
+ @Excel(name = "project_form")
+ private String projectForm;
+ /** design_file_url */
+ @Excel(name = "design_file_url")
+ private String designFileUrl;
+ /** status */
+ @Excel(name = "status")
+ private String status;
+ /** is_settled */
+ @Excel(name = "is_settled")
+ private String isSettled;
+ /** project_no */
+ @Excel(name = "project_no")
+ private String projectNo;
+ /** remark */
+ @Excel(name = "remark")
+ private String remark;
+ /** is_finished */
+ @Excel(name = "is_finished")
+ private String isFinished;
+ /** create_by */
+ @Excel(name = "create_by")
+ private String createBy;
+ /** create_time */
+ @Excel(name = "create_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+ /** update_by */
+ @Excel(name = "update_by")
+ private String updateBy;
+ /** update_time */
+ @Excel(name = "update_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date updateTime;
+ /** 审核意见 */
+ private String auditOpinion;
+ /** 审核人 */
+ private String auditBy;
+ /** 审核时间 */
+ private String auditTime;
+ public String getPlanId() { return planId; }
+ public void setPlanId(String planId) { this.planId = planId; }
+ public String getPlanName() { return planName; }
+ public void setPlanName(String planName) { this.planName = planName; }
+ public String getPlanDirection() { return planDirection; }
+ public void setPlanDirection(String planDirection) { this.planDirection = planDirection; }
+ public String getPlanCategory() { return planCategory; }
+ public void setPlanCategory(String planCategory) { this.planCategory = planCategory; }
+ public String getProjectForm() { return projectForm; }
+ public void setProjectForm(String projectForm) { this.projectForm = projectForm; }
+ public String getDesignFileUrl() { return designFileUrl; }
+ public void setDesignFileUrl(String designFileUrl) { this.designFileUrl = designFileUrl; }
+ public String getStatus() { return status; }
+ public void setStatus(String status) { this.status = status; }
+ public String getIsSettled() { return isSettled; }
+ public void setIsSettled(String isSettled) { this.isSettled = isSettled; }
+ public String getProjectNo() { return projectNo; }
+ public void setProjectNo(String projectNo) { this.projectNo = projectNo; }
+ public String getRemark() { return remark; }
+ public void setRemark(String remark) { this.remark = remark; }
+ public String getIsFinished() { return isFinished; }
+ public void setIsFinished(String isFinished) { this.isFinished = isFinished; }
+ public String getCreateBy() { return createBy; }
+ public void setCreateBy(String createBy) { this.createBy = createBy; }
+ public Date getCreateTime() { return createTime; }
+ public void setCreateTime(Date createTime) { this.createTime = createTime; }
+ public String getUpdateBy() { return updateBy; }
+ public void setUpdateBy(String updateBy) { this.updateBy = updateBy; }
+ public Date getUpdateTime() { return updateTime; }
+ public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProjectRating.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProjectRating.java
new file mode 100644
index 0000000..881fd43
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProjectRating.java
@@ -0,0 +1,100 @@
+package com.ruoyi.business.domain;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/** 项目评分对象 BizProjectRating */
+public class BizProjectRating extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+ /** ratingId */
+ private String ratingId;
+ /** project_no */
+ @Excel(name = "project_no")
+ private String projectNo;
+ /** project_name */
+ @Excel(name = "project_name")
+ private String projectName;
+ /** rater_name */
+ @Excel(name = "rater_name")
+ private String raterName;
+ /** rater_role */
+ @Excel(name = "rater_role")
+ private String raterRole;
+ /** quality_score */
+ @Excel(name = "quality_score")
+ private String qualityScore;
+ /** response_score */
+ @Excel(name = "response_score")
+ private Long responseScore;
+ /** cooperation_score */
+ @Excel(name = "cooperation_score")
+ private Long cooperationScore;
+ /** compliance_score */
+ @Excel(name = "compliance_score")
+ private Long complianceScore;
+ /** total_score */
+ @Excel(name = "total_score")
+ private BigDecimal totalScore;
+ /** remark */
+ @Excel(name = "remark")
+ private String remark;
+ /** create_by */
+ @Excel(name = "create_by")
+ private String createBy;
+ /** create_time */
+ @Excel(name = "create_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+ /** update_by */
+ @Excel(name = "update_by")
+ private String updateBy;
+ /** update_time */
+ @Excel(name = "update_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date updateTime;
+ /** 项目ID */
+ private Long projectId;
+ /** 评分人ID */
+ private Long raterId;
+ /** 评分时间 */
+ private String ratingTime;
+ public String getRatingId() { return ratingId; }
+ public void setRatingId(String ratingId) { this.ratingId = ratingId; }
+ public String getProjectNo() { return projectNo; }
+ public void setProjectNo(String projectNo) { this.projectNo = projectNo; }
+ public String getProjectName() { return projectName; }
+ public void setProjectName(String projectName) { this.projectName = projectName; }
+ public String getRaterName() { return raterName; }
+ public void setRaterName(String raterName) { this.raterName = raterName; }
+ public String getRaterRole() { return raterRole; }
+ public void setRaterRole(String raterRole) { this.raterRole = raterRole; }
+ public String getQualityScore() { return qualityScore; }
+ public void setQualityScore(String qualityScore) { this.qualityScore = qualityScore; }
+ public Long getResponseScore() { return responseScore; }
+ public void setResponseScore(Long responseScore) { this.responseScore = responseScore; }
+ public Long getCooperationScore() { return cooperationScore; }
+ public void setCooperationScore(Long cooperationScore) { this.cooperationScore = cooperationScore; }
+ public Long getComplianceScore() { return complianceScore; }
+ public void setComplianceScore(Long complianceScore) { this.complianceScore = complianceScore; }
+ public BigDecimal getTotalScore() { return totalScore; }
+ public void setTotalScore(BigDecimal totalScore) { this.totalScore = totalScore; }
+ public String getRemark() { return remark; }
+ public void setRemark(String remark) { this.remark = remark; }
+ public String getCreateBy() { return createBy; }
+ public void setCreateBy(String createBy) { this.createBy = createBy; }
+ public Date getCreateTime() { return createTime; }
+ public void setCreateTime(Date createTime) { this.createTime = createTime; }
+ public String getUpdateBy() { return updateBy; }
+ public void setUpdateBy(String updateBy) { this.updateBy = updateBy; }
+ public Date getUpdateTime() { return updateTime; }
+ public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }
+ public Long getProjectId() { return projectId; }
+ public void setProjectId(Long projectId) { this.projectId = projectId; }
+ public Long getRaterId() { return raterId; }
+ public void setRaterId(Long raterId) { this.raterId = raterId; }
+ public String getRatingTime() { return ratingTime; }
+ public void setRatingTime(String ratingTime) { this.ratingTime = ratingTime; }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProjectSponsorAssign.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProjectSponsorAssign.java
new file mode 100644
index 0000000..6e6863d
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizProjectSponsorAssign.java
@@ -0,0 +1,42 @@
+package com.ruoyi.business.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/** 项目-赞助方-监察员分配记录 (biz_project_sponsor_assign) */
+public class BizProjectSponsorAssign extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+ private Long id;
+ private String projectId;
+ private Long sponsorUserId;
+ private Long monitorUserId;
+ private String assignDesc;
+ private String assignPoints;
+
+ /** 关联展示字段 (非持久化) */
+ private String sponsorUserName;
+ private String monitorUserName;
+
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+
+ public Long getId() { return id; }
+ public void setId(Long id) { this.id = id; }
+ public String getProjectId() { return projectId; }
+ public void setProjectId(String projectId) { this.projectId = projectId; }
+ public Long getSponsorUserId() { return sponsorUserId; }
+ public void setSponsorUserId(Long sponsorUserId) { this.sponsorUserId = sponsorUserId; }
+ public Long getMonitorUserId() { return monitorUserId; }
+ public void setMonitorUserId(Long monitorUserId) { this.monitorUserId = monitorUserId; }
+ public String getAssignDesc() { return assignDesc; }
+ public void setAssignDesc(String assignDesc) { this.assignDesc = assignDesc; }
+ public String getAssignPoints() { return assignPoints; }
+ public void setAssignPoints(String assignPoints) { this.assignPoints = assignPoints; }
+ public String getSponsorUserName() { return sponsorUserName; }
+ public void setSponsorUserName(String sponsorUserName) { this.sponsorUserName = sponsorUserName; }
+ public String getMonitorUserName() { return monitorUserName; }
+ public void setMonitorUserName(String monitorUserName) { this.monitorUserName = monitorUserName; }
+ public Date getCreateTime() { return createTime; }
+ public void setCreateTime(Date createTime) { this.createTime = createTime; }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizPublicity.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizPublicity.java
new file mode 100644
index 0000000..7555948
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizPublicity.java
@@ -0,0 +1,61 @@
+package com.ruoyi.business.domain;
+
+import java.util.Date;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/** 项目公告对象 BizPublicity */
+public class BizPublicity extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+ /** PK */
+ private Long id;
+ /** 项目ID */
+ @Excel(name = "project_id")
+ private Long projectId;
+ /** 项目编号 */
+ @Excel(name = "project_no")
+ private String projectNo;
+ /** 项目名称 */
+ @Excel(name = "project_name")
+ private String projectName;
+ /** 公告类型 (invitation/support/notice/agenda) */
+ @Excel(name = "announce_type")
+ private String announceType;
+ /** 公告标题 */
+ @Excel(name = "title")
+ private String title;
+ /** 公告文件URL */
+ @Excel(name = "file_url")
+ private String fileUrl;
+ /** 备注 */
+ @Excel(name = "remark")
+ private String remark;
+ /** 状态 0保存 1发布 */
+ @Excel(name = "status")
+ private String status;
+ /** 发布时间 */
+ @Excel(name = "rating_time")
+ private Date ratingTime;
+
+ public Long getId() { return id; }
+ public void setId(Long id) { this.id = id; }
+ public Long getProjectId() { return projectId; }
+ public void setProjectId(Long projectId) { this.projectId = projectId; }
+ public String getProjectNo() { return projectNo; }
+ public void setProjectNo(String projectNo) { this.projectNo = projectNo; }
+ public String getProjectName() { return projectName; }
+ public void setProjectName(String projectName) { this.projectName = projectName; }
+ public String getAnnounceType() { return announceType; }
+ public void setAnnounceType(String announceType) { this.announceType = announceType; }
+ public String getTitle() { return title; }
+ public void setTitle(String title) { this.title = title; }
+ public String getFileUrl() { return fileUrl; }
+ public void setFileUrl(String fileUrl) { this.fileUrl = fileUrl; }
+ public String getRemark() { return remark; }
+ public void setRemark(String remark) { this.remark = remark; }
+ public String getStatus() { return status; }
+ public void setStatus(String status) { this.status = status; }
+ public Date getRatingTime() { return ratingTime; }
+ public void setRatingTime(Date ratingTime) { this.ratingTime = ratingTime; }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizResource.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizResource.java
new file mode 100644
index 0000000..056a374
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizResource.java
@@ -0,0 +1,69 @@
+package com.ruoyi.business.domain;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/** 资料对象 BizResource */
+public class BizResource extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+ /** resourceId */
+ private String resourceId;
+ /** name */
+ @Excel(name = "name")
+ private String name;
+ /** category */
+ @Excel(name = "category")
+ private String category;
+ /** file_size */
+ @Excel(name = "file_size")
+ private String fileSize;
+ /** uploader_name */
+ @Excel(name = "uploader_name")
+ private String uploaderName;
+ /** upload_time */
+ @Excel(name = "upload_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date uploadTime;
+ /** status */
+ @Excel(name = "status")
+ private String status;
+ /** create_by */
+ @Excel(name = "create_by")
+ private String createBy;
+ /** create_time */
+ @Excel(name = "create_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+ /** update_by */
+ @Excel(name = "update_by")
+ private String updateBy;
+ /** update_time */
+ @Excel(name = "update_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date updateTime;
+ public String getResourceId() { return resourceId; }
+ public void setResourceId(String resourceId) { this.resourceId = resourceId; }
+ public String getName() { return name; }
+ public void setName(String name) { this.name = name; }
+ public String getCategory() { return category; }
+ public void setCategory(String category) { this.category = category; }
+ public String getFileSize() { return fileSize; }
+ public void setFileSize(String fileSize) { this.fileSize = fileSize; }
+ public String getUploaderName() { return uploaderName; }
+ public void setUploaderName(String uploaderName) { this.uploaderName = uploaderName; }
+ public Date getUploadTime() { return uploadTime; }
+ public void setUploadTime(Date uploadTime) { this.uploadTime = uploadTime; }
+ public String getStatus() { return status; }
+ public void setStatus(String status) { this.status = status; }
+ public String getCreateBy() { return createBy; }
+ public void setCreateBy(String createBy) { this.createBy = createBy; }
+ public Date getCreateTime() { return createTime; }
+ public void setCreateTime(Date createTime) { this.createTime = createTime; }
+ public String getUpdateBy() { return updateBy; }
+ public void setUpdateBy(String updateBy) { this.updateBy = updateBy; }
+ public Date getUpdateTime() { return updateTime; }
+ public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizSubmission.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizSubmission.java
new file mode 100644
index 0000000..d6e5f5b
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizSubmission.java
@@ -0,0 +1,86 @@
+package com.ruoyi.business.domain;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/** 投稿对象 BizSubmission */
+public class BizSubmission extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+ /** subId */
+ private String subId;
+ /** title */
+ @Excel(name = "title")
+ private String title;
+ /** direction */
+ @Excel(name = "direction")
+ private String direction;
+ /** project_form */
+ @Excel(name = "project_form")
+ private String projectForm;
+ /** design_file_url */
+ @Excel(name = "design_file_url")
+ private String designFileUrl;
+ /** status */
+ @Excel(name = "status")
+ private String status;
+ /** remark */
+ @Excel(name = "remark")
+ private String remark;
+ /** create_by */
+ @Excel(name = "create_by")
+ private String createBy;
+ /** create_time */
+ @Excel(name = "create_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+ /** update_by */
+ @Excel(name = "update_by")
+ private String updateBy;
+ /** update_time */
+ @Excel(name = "update_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date updateTime;
+ /** 投稿人用户ID */
+ private Long submitterId;
+ /** 投稿人姓名 */
+ private String submitterName;
+ /** 项目类别 学术会议类/专项科研类/调研征集类/慈善帮扶类/标准制定类/患者援助类/专业培训类 */
+ private String projectCategory;
+ /** 审核意见 */
+ private String auditOpinion;
+ /** 审核人 */
+ private String auditBy;
+ /** 审核时间 */
+ private String auditTime;
+ public String getSubId() { return subId; }
+ public void setSubId(String subId) { this.subId = subId; }
+ public String getTitle() { return title; }
+ public void setTitle(String title) { this.title = title; }
+ public String getDirection() { return direction; }
+ public void setDirection(String direction) { this.direction = direction; }
+ public String getProjectForm() { return projectForm; }
+ public void setProjectForm(String projectForm) { this.projectForm = projectForm; }
+ public String getProjectCategory() { return projectCategory; }
+ public void setProjectCategory(String projectCategory) { this.projectCategory = projectCategory; }
+ public String getDesignFileUrl() { return designFileUrl; }
+ public void setDesignFileUrl(String designFileUrl) { this.designFileUrl = designFileUrl; }
+ public String getStatus() { return status; }
+ public void setStatus(String status) { this.status = status; }
+ public String getRemark() { return remark; }
+ public void setRemark(String remark) { this.remark = remark; }
+ public Long getSubmitterId() { return submitterId; }
+ public void setSubmitterId(Long submitterId) { this.submitterId = submitterId; }
+ public String getSubmitterName() { return submitterName; }
+ public void setSubmitterName(String submitterName) { this.submitterName = submitterName; }
+ public String getCreateBy() { return createBy; }
+ public void setCreateBy(String createBy) { this.createBy = createBy; }
+ public Date getCreateTime() { return createTime; }
+ public void setCreateTime(Date createTime) { this.createTime = createTime; }
+ public String getUpdateBy() { return updateBy; }
+ public void setUpdateBy(String updateBy) { this.updateBy = updateBy; }
+ public Date getUpdateTime() { return updateTime; }
+ public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizSupportIntent.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizSupportIntent.java
new file mode 100644
index 0000000..423b5ab
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizSupportIntent.java
@@ -0,0 +1,78 @@
+package com.ruoyi.business.domain;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/** 支持意向对象 BizSupportIntent */
+public class BizSupportIntent extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+ /** intentId */
+ private String intentId;
+ /** project_no */
+ @Excel(name = "project_no")
+ private String projectNo;
+ /** project_name */
+ @Excel(name = "project_name")
+ private String projectName;
+ /** name */
+ @Excel(name = "name")
+ private String name;
+ /** work_unit */
+ @Excel(name = "work_unit")
+ private String workUnit;
+ /** department */
+ @Excel(name = "department")
+ private String department;
+ /** position */
+ @Excel(name = "position")
+ private String position;
+ /** phone */
+ @Excel(name = "phone")
+ private String phone;
+ /** account_status */
+ @Excel(name = "account_status")
+ private String accountStatus;
+ /** create_by */
+ @Excel(name = "create_by")
+ private String createBy;
+ /** create_time */
+ @Excel(name = "create_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+ /** update_by */
+ @Excel(name = "update_by")
+ private String updateBy;
+ /** update_time */
+ @Excel(name = "update_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date updateTime;
+ public String getIntentId() { return intentId; }
+ public void setIntentId(String intentId) { this.intentId = intentId; }
+ public String getProjectNo() { return projectNo; }
+ public void setProjectNo(String projectNo) { this.projectNo = projectNo; }
+ public String getProjectName() { return projectName; }
+ public void setProjectName(String projectName) { this.projectName = projectName; }
+ public String getName() { return name; }
+ public void setName(String name) { this.name = name; }
+ public String getWorkUnit() { return workUnit; }
+ public void setWorkUnit(String workUnit) { this.workUnit = workUnit; }
+ public String getDepartment() { return department; }
+ public void setDepartment(String department) { this.department = department; }
+ public String getPosition() { return position; }
+ public void setPosition(String position) { this.position = position; }
+ public String getPhone() { return phone; }
+ public void setPhone(String phone) { this.phone = phone; }
+ public String getAccountStatus() { return accountStatus; }
+ public void setAccountStatus(String accountStatus) { this.accountStatus = accountStatus; }
+ public String getCreateBy() { return createBy; }
+ public void setCreateBy(String createBy) { this.createBy = createBy; }
+ public Date getCreateTime() { return createTime; }
+ public void setCreateTime(Date createTime) { this.createTime = createTime; }
+ public String getUpdateBy() { return updateBy; }
+ public void setUpdateBy(String updateBy) { this.updateBy = updateBy; }
+ public Date getUpdateTime() { return updateTime; }
+ public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizSupportLetter.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizSupportLetter.java
new file mode 100644
index 0000000..c0f3be7
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/domain/BizSupportLetter.java
@@ -0,0 +1,76 @@
+package com.ruoyi.business.domain;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/** 支持函对象 BizSupportLetter */
+public class BizSupportLetter extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+ /** annId */
+ private String annId;
+ /** title */
+ @Excel(name = "title")
+ private String title;
+ /** content */
+ @Excel(name = "content")
+ private String content;
+ /** unit_name */
+ @Excel(name = "unit_name")
+ private String unitName;
+ /** amount */
+ @Excel(name = "amount")
+ private BigDecimal amount;
+ /** issue_date */
+ @Excel(name = "issue_date")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date issueDate;
+ /** create_by */
+ @Excel(name = "create_by")
+ private String createBy;
+ /** create_time */
+ @Excel(name = "create_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+ /** update_by */
+ @Excel(name = "update_by")
+ private String updateBy;
+ /** update_time */
+ @Excel(name = "update_time")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date updateTime;
+ /** 支持函ID */
+ private Long letterId;
+ /** 项目ID */
+ private Long projectId;
+ /** 项目编号 */
+ private String projectNo;
+ /** 支持函图片URL */
+ private String fileUrl;
+ /** 发布时间 */
+ private String publishTime;
+ /** 支持次数 */
+ private Integer supportCount;
+ public String getAnnId() { return annId; }
+ public void setAnnId(String annId) { this.annId = annId; }
+ public String getTitle() { return title; }
+ public void setTitle(String title) { this.title = title; }
+ public String getContent() { return content; }
+ public void setContent(String content) { this.content = content; }
+ public String getUnitName() { return unitName; }
+ public void setUnitName(String unitName) { this.unitName = unitName; }
+ public BigDecimal getAmount() { return amount; }
+ public void setAmount(BigDecimal amount) { this.amount = amount; }
+ public Date getIssueDate() { return issueDate; }
+ public void setIssueDate(Date issueDate) { this.issueDate = issueDate; }
+ public String getCreateBy() { return createBy; }
+ public void setCreateBy(String createBy) { this.createBy = createBy; }
+ public Date getCreateTime() { return createTime; }
+ public void setCreateTime(Date createTime) { this.createTime = createTime; }
+ public String getUpdateBy() { return updateBy; }
+ public void setUpdateBy(String updateBy) { this.updateBy = updateBy; }
+ public Date getUpdateTime() { return updateTime; }
+ public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/dto/SmsValidForm.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/dto/SmsValidForm.java
new file mode 100644
index 0000000..485e71a
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/dto/SmsValidForm.java
@@ -0,0 +1,22 @@
+package com.ruoyi.business.dto;
+
+/**
+ * 短信验证码校验表单
+ * 参考 hwt-code SmsValidForm: phone + smsCode + uuid
+ */
+public class SmsValidForm {
+ private String phone;
+ private String smsCode;
+ private String uuid;
+ /** 是否免校验(预留, 默认 false) */
+ private boolean free;
+
+ public String getPhone() { return phone; }
+ public void setPhone(String phone) { this.phone = phone; }
+ public String getSmsCode() { return smsCode; }
+ public void setSmsCode(String smsCode) { this.smsCode = smsCode; }
+ public String getUuid() { return uuid; }
+ public void setUuid(String uuid) { this.uuid = uuid; }
+ public boolean isFree() { return free; }
+ public void setFree(boolean free) { this.free = free; }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/enums/SubmissionStatus.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/enums/SubmissionStatus.java
new file mode 100644
index 0000000..ba3bc0d
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/enums/SubmissionStatus.java
@@ -0,0 +1,43 @@
+package com.ruoyi.business.enums;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 投稿状态枚举
+ *
+ * 数据库存储英文 code (PENDING/APPROVED/REJECTED/DRAFT), 不存中文也不存数字.
+ * 字典映射集中在这里避免散落. 前端 utils/submissionStatus.js 同步这份字典.
+ */
+public enum SubmissionStatus
+{
+ PENDING("PENDING", "待审核"),
+ APPROVED("APPROVED", "审核通过"),
+ REJECTED("REJECTED", "已退回"),
+ DRAFT("DRAFT", "待提交");
+
+ private final String code;
+ private final String label;
+
+ SubmissionStatus(String code, String label) {
+ this.code = code;
+ this.label = label;
+ }
+
+ public String getCode() { return code; }
+ public String getLabel() { return label; }
+
+ private static final Map BY_CODE = new HashMap<>();
+ static {
+ for (SubmissionStatus s : values()) BY_CODE.put(s.code, s);
+ }
+
+ public static SubmissionStatus fromCode(String val) {
+ if (val == null) return null;
+ return BY_CODE.get(val.trim().toUpperCase());
+ }
+
+ public static boolean isValid(String val) {
+ return fromCode(val) != null;
+ }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizDepartmentMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizDepartmentMapper.java
new file mode 100644
index 0000000..2d3c01b
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizDepartmentMapper.java
@@ -0,0 +1,22 @@
+package com.ruoyi.business.mapper;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizDepartment;
+
+public interface BizDepartmentMapper
+{
+ BizDepartment selectByPrimaryKey(Long deptId);
+
+ List selectList(BizDepartment entity);
+
+ /** 全部启用的字典 (给前端下拉用) */
+ List selectActive();
+
+ int insert(BizDepartment entity);
+
+ int updateByPrimaryKey(BizDepartment entity);
+
+ int deleteByPrimaryKey(Long deptId);
+
+ int deleteByPrimaryKeys(Long[] deptIds);
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizDoctorTitleMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizDoctorTitleMapper.java
new file mode 100644
index 0000000..2a763dd
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizDoctorTitleMapper.java
@@ -0,0 +1,22 @@
+package com.ruoyi.business.mapper;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizDoctorTitle;
+
+public interface BizDoctorTitleMapper
+{
+ BizDoctorTitle selectByPrimaryKey(Long titleId);
+
+ List selectList(BizDoctorTitle entity);
+
+ /** 全部启用的字典 */
+ List selectActive();
+
+ int insert(BizDoctorTitle entity);
+
+ int updateByPrimaryKey(BizDoctorTitle entity);
+
+ int deleteByPrimaryKey(Long titleId);
+
+ int deleteByPrimaryKeys(Long[] titleIds);
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizExecutionIntentMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizExecutionIntentMapper.java
new file mode 100644
index 0000000..e285acc
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizExecutionIntentMapper.java
@@ -0,0 +1,16 @@
+package com.ruoyi.business.mapper;
+import java.util.List;
+import com.ruoyi.business.domain.BizExecutionIntent;
+
+/**
+ * 执行意向Mapper接口
+ */
+public interface BizExecutionIntentMapper
+{
+ BizExecutionIntent selectByPrimaryKey(String intentId);
+ List selectList(BizExecutionIntent entity);
+ int insert(BizExecutionIntent entity);
+ int updateByPrimaryKey(BizExecutionIntent entity);
+ int deleteByPrimaryKey(String intentId);
+ int deleteByPrimaryKeys(String[] intentIds);
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizExpertMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizExpertMapper.java
new file mode 100644
index 0000000..4c4289b
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizExpertMapper.java
@@ -0,0 +1,19 @@
+package com.ruoyi.business.mapper;
+import java.util.List;
+import com.ruoyi.business.domain.BizExpert;
+
+/**
+ * 专家Mapper接口
+ */
+public interface BizExpertMapper
+{
+ BizExpert selectByPrimaryKey(String expertId);
+ BizExpert selectByUserId(Long userId);
+ List selectList(BizExpert entity);
+ int insert(BizExpert entity);
+ int insertWithUserId(BizExpert entity);
+ int updateByPrimaryKey(BizExpert entity);
+ int updateByUserId(BizExpert entity);
+ int deleteByPrimaryKey(String expertId);
+ int deleteByPrimaryKeys(String[] expertIds);
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizInvitationMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizInvitationMapper.java
new file mode 100644
index 0000000..76b82cb
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizInvitationMapper.java
@@ -0,0 +1,11 @@
+package com.ruoyi.business.mapper;
+import java.util.List;
+import com.ruoyi.business.domain.BizInvitation;
+public interface BizInvitationMapper {
+ BizInvitation selectByPrimaryKey(String annId);
+ List selectList(BizInvitation entity);
+ int insert(BizInvitation entity);
+ int updateByPrimaryKey(BizInvitation entity);
+ int deleteByPrimaryKey(String annId);
+ int deleteByPrimaryKeys(String[] annIds);
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizLaborVoucherMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizLaborVoucherMapper.java
new file mode 100644
index 0000000..4ab0605
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizLaborVoucherMapper.java
@@ -0,0 +1,16 @@
+package com.ruoyi.business.mapper;
+import java.util.List;
+import com.ruoyi.business.domain.BizLaborVoucher;
+
+/**
+ * 劳务凭证Mapper接口
+ */
+public interface BizLaborVoucherMapper
+{
+ BizLaborVoucher selectByPrimaryKey(String voucherId);
+ List selectList(BizLaborVoucher entity);
+ int insert(BizLaborVoucher entity);
+ int updateByPrimaryKey(BizLaborVoucher entity);
+ int deleteByPrimaryKey(String voucherId);
+ int deleteByPrimaryKeys(String[] voucherIds);
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizMeetingMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizMeetingMapper.java
new file mode 100644
index 0000000..506d9e3
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizMeetingMapper.java
@@ -0,0 +1,16 @@
+package com.ruoyi.business.mapper;
+import java.util.List;
+import com.ruoyi.business.domain.BizMeeting;
+
+/**
+ * 会议Mapper接口
+ */
+public interface BizMeetingMapper
+{
+ BizMeeting selectByPrimaryKey(String meetingId);
+ List selectList(BizMeeting entity);
+ int insert(BizMeeting entity);
+ int updateByPrimaryKey(BizMeeting entity);
+ int deleteByPrimaryKey(String meetingId);
+ int deleteByPrimaryKeys(String[] meetingIds);
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizMeetingSettlementMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizMeetingSettlementMapper.java
new file mode 100644
index 0000000..66a0cba
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizMeetingSettlementMapper.java
@@ -0,0 +1,16 @@
+package com.ruoyi.business.mapper;
+import java.util.List;
+import com.ruoyi.business.domain.BizMeetingSettlement;
+
+/**
+ * 会议结算明细Mapper接口
+ */
+public interface BizMeetingSettlementMapper
+{
+ BizMeetingSettlement selectByPrimaryKey(String id);
+ List selectList(BizMeetingSettlement entity);
+ int insert(BizMeetingSettlement entity);
+ int updateByPrimaryKey(BizMeetingSettlement entity);
+ int deleteByPrimaryKey(String id);
+ int deleteByPrimaryKeys(String[] ids);
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizMessageMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizMessageMapper.java
new file mode 100644
index 0000000..9e75e1b
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizMessageMapper.java
@@ -0,0 +1,31 @@
+package com.ruoyi.business.mapper;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizMessage;
+
+/**
+ * 个人消息Mapper接口
+ */
+public interface BizMessageMapper
+{
+ BizMessage selectByPrimaryKey(Long msgId);
+
+ List selectList(BizMessage entity);
+
+ /** 某人的未读 + 最近消息 (按时间倒序, limit 由调用方控制) */
+ List selectMyRecent(BizMessage entity);
+
+ int insert(BizMessage entity);
+
+ int updateByPrimaryKey(BizMessage entity);
+
+ /** 单条标记已读 */
+ int markRead(BizMessage entity);
+
+ /** 全部标记已读 (按接收人) */
+ int markAllRead(Long receiverUserId);
+
+ int deleteByPrimaryKey(Long msgId);
+
+ int deleteByPrimaryKeys(Long[] msgIds);
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizOrgMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizOrgMapper.java
new file mode 100644
index 0000000..3b90ce6
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizOrgMapper.java
@@ -0,0 +1,12 @@
+package com.ruoyi.business.mapper;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizOrg;
+
+public interface BizOrgMapper {
+ BizOrg selectByPrimaryKey(Long orgId);
+ List selectList(BizOrg entity);
+ int insert(BizOrg entity);
+ int updateByPrimaryKey(BizOrg entity);
+ int deleteByPrimaryKeys(Long[] orgIds);
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizPersonMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizPersonMapper.java
new file mode 100644
index 0000000..8710397
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizPersonMapper.java
@@ -0,0 +1,20 @@
+package com.ruoyi.business.mapper;
+import java.util.List;
+import com.ruoyi.business.domain.BizPerson;
+
+/**
+ * 人员Mapper接口
+ */
+public interface BizPersonMapper
+{
+ BizPerson selectByPrimaryKey(String personId);
+ List selectList(BizPerson entity);
+ /** sponsor 专属: 通过 sys_user.parent_user_id 过滤主账号归属, INNER JOIN 自然排除游离 person */
+ List selectSponsorList(BizPerson entity);
+ int insert(BizPerson entity);
+ int updateByPrimaryKey(BizPerson entity);
+ int deleteByPrimaryKey(String personId);
+ int deleteByPrimaryKeys(String[] personIds);
+ /** 联动: person 逻辑删除后, 把对应 sys_user 子账号也逻辑删除 */
+ int softDeleteSysUserByPersonIds(String[] personIds);
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizProjectAssignMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizProjectAssignMapper.java
new file mode 100644
index 0000000..581ab24
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizProjectAssignMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.business.mapper;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizProjectAssign;
+
+/**
+ * 项目执行方分配Mapper接口
+ */
+public interface BizProjectAssignMapper
+{
+ BizProjectAssign selectByPrimaryKey(String assignId);
+ List selectByProjectId(Long projectId);
+ List selectList(BizProjectAssign entity);
+ int insert(BizProjectAssign entity);
+ int updateByPrimaryKey(BizProjectAssign entity);
+ int deleteByPrimaryKey(String assignId);
+ int deleteByProjectId(Long projectId);
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizProjectMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizProjectMapper.java
new file mode 100644
index 0000000..63cd33b
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizProjectMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.business.mapper;
+import java.util.List;
+import com.ruoyi.business.domain.BizProject;
+
+/**
+ * 项目Mapper接口
+ */
+public interface BizProjectMapper
+{
+ BizProject selectByPrimaryKey(String projectId);
+ List selectList(BizProject entity);
+ /** sponsor 端专属: projectIds + LEFT JOIN 当前 login 用户评分, 用于评分回显 */
+ List selectSponsorList(BizProject entity);
+ int insert(BizProject entity);
+ int updateByPrimaryKey(BizProject entity);
+ int deleteByPrimaryKey(String projectId);
+ int deleteByPrimaryKeys(String[] projectIds);
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizProjectPlanMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizProjectPlanMapper.java
new file mode 100644
index 0000000..e40f33f
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizProjectPlanMapper.java
@@ -0,0 +1,16 @@
+package com.ruoyi.business.mapper;
+import java.util.List;
+import com.ruoyi.business.domain.BizProjectPlan;
+
+/**
+ * 项目策划方案Mapper接口
+ */
+public interface BizProjectPlanMapper
+{
+ BizProjectPlan selectByPrimaryKey(String planId);
+ List selectList(BizProjectPlan entity);
+ int insert(BizProjectPlan entity);
+ int updateByPrimaryKey(BizProjectPlan entity);
+ int deleteByPrimaryKey(String planId);
+ int deleteByPrimaryKeys(String[] planIds);
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizProjectRatingMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizProjectRatingMapper.java
new file mode 100644
index 0000000..c6cd0f5
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizProjectRatingMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.business.mapper;
+import java.util.List;
+import com.ruoyi.business.domain.BizProjectRating;
+
+/**
+ * 项目评分Mapper接口
+ */
+public interface BizProjectRatingMapper
+{
+ BizProjectRating selectByPrimaryKey(String ratingId);
+ List selectList(BizProjectRating entity);
+ int insert(BizProjectRating entity);
+ int updateByPrimaryKey(BizProjectRating entity);
+ /** 按 (project_id + rater_id + rater_role) upsert 评分 */
+ int upsertRating(BizProjectRating entity);
+ int deleteByPrimaryKey(String ratingId);
+ int deleteByPrimaryKeys(String[] ratingIds);
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizProjectSponsorAssignMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizProjectSponsorAssignMapper.java
new file mode 100644
index 0000000..f14a075
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizProjectSponsorAssignMapper.java
@@ -0,0 +1,11 @@
+package com.ruoyi.business.mapper;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizProjectSponsorAssign;
+
+public interface BizProjectSponsorAssignMapper {
+ int insertAssign(BizProjectSponsorAssign entity);
+ List selectByProjectId(String projectId);
+ /** 按 project_id 全删 (赞助方分配: 先删后插策略) */
+ int deleteByProjectId(String projectId);
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizPublicityMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizPublicityMapper.java
new file mode 100644
index 0000000..e4aa472
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizPublicityMapper.java
@@ -0,0 +1,15 @@
+package com.ruoyi.business.mapper;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizPublicity;
+
+public interface BizPublicityMapper
+{
+ BizPublicity selectByPrimaryKey(Long id);
+ List selectList(BizPublicity entity);
+ List selectByProjectId(Long projectId);
+ int insert(BizPublicity entity);
+ int updateByPrimaryKey(BizPublicity entity);
+ int deleteByPrimaryKey(Long id);
+ int deleteByPrimaryKeys(Long[] ids);
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizResourceMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizResourceMapper.java
new file mode 100644
index 0000000..43a44b7
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizResourceMapper.java
@@ -0,0 +1,16 @@
+package com.ruoyi.business.mapper;
+import java.util.List;
+import com.ruoyi.business.domain.BizResource;
+
+/**
+ * 资料Mapper接口
+ */
+public interface BizResourceMapper
+{
+ BizResource selectByPrimaryKey(String resourceId);
+ List selectList(BizResource entity);
+ int insert(BizResource entity);
+ int updateByPrimaryKey(BizResource entity);
+ int deleteByPrimaryKey(String resourceId);
+ int deleteByPrimaryKeys(String[] resourceIds);
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizSubmissionMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizSubmissionMapper.java
new file mode 100644
index 0000000..9821935
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizSubmissionMapper.java
@@ -0,0 +1,16 @@
+package com.ruoyi.business.mapper;
+import java.util.List;
+import com.ruoyi.business.domain.BizSubmission;
+
+/**
+ * 投稿Mapper接口
+ */
+public interface BizSubmissionMapper
+{
+ BizSubmission selectByPrimaryKey(String subId);
+ List selectList(BizSubmission entity);
+ int insert(BizSubmission entity);
+ int updateByPrimaryKey(BizSubmission entity);
+ int deleteByPrimaryKey(String subId);
+ int deleteByPrimaryKeys(String[] subIds);
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizSupportIntentMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizSupportIntentMapper.java
new file mode 100644
index 0000000..6799f57
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizSupportIntentMapper.java
@@ -0,0 +1,16 @@
+package com.ruoyi.business.mapper;
+import java.util.List;
+import com.ruoyi.business.domain.BizSupportIntent;
+
+/**
+ * 支持意向Mapper接口
+ */
+public interface BizSupportIntentMapper
+{
+ BizSupportIntent selectByPrimaryKey(String intentId);
+ List selectList(BizSupportIntent entity);
+ int insert(BizSupportIntent entity);
+ int updateByPrimaryKey(BizSupportIntent entity);
+ int deleteByPrimaryKey(String intentId);
+ int deleteByPrimaryKeys(String[] intentIds);
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizSupportLetterMapper.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizSupportLetterMapper.java
new file mode 100644
index 0000000..c6f2ad3
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/mapper/BizSupportLetterMapper.java
@@ -0,0 +1,11 @@
+package com.ruoyi.business.mapper;
+import java.util.List;
+import com.ruoyi.business.domain.BizSupportLetter;
+public interface BizSupportLetterMapper {
+ BizSupportLetter selectByPrimaryKey(String annId);
+ List selectList(BizSupportLetter entity);
+ int insert(BizSupportLetter entity);
+ int updateByPrimaryKey(BizSupportLetter entity);
+ int deleteByPrimaryKey(String annId);
+ int deleteByPrimaryKeys(String[] annIds);
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizDepartmentService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizDepartmentService.java
new file mode 100644
index 0000000..a95d1c8
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizDepartmentService.java
@@ -0,0 +1,21 @@
+package com.ruoyi.business.service;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizDepartment;
+
+public interface IBizDepartmentService
+{
+ BizDepartment getById(Long deptId);
+
+ List selectList(BizDepartment entity);
+
+ List selectActive();
+
+ int insert(BizDepartment entity);
+
+ int updateByPrimaryKey(BizDepartment entity);
+
+ int deleteByPrimaryKey(Long deptId);
+
+ int deleteByPrimaryKeys(Long[] deptIds);
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizDoctorTitleService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizDoctorTitleService.java
new file mode 100644
index 0000000..ca42c5b
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizDoctorTitleService.java
@@ -0,0 +1,21 @@
+package com.ruoyi.business.service;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizDoctorTitle;
+
+public interface IBizDoctorTitleService
+{
+ BizDoctorTitle getById(Long titleId);
+
+ List selectList(BizDoctorTitle entity);
+
+ List selectActive();
+
+ int insert(BizDoctorTitle entity);
+
+ int updateByPrimaryKey(BizDoctorTitle entity);
+
+ int deleteByPrimaryKey(Long titleId);
+
+ int deleteByPrimaryKeys(Long[] titleIds);
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizExecutionIntentService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizExecutionIntentService.java
new file mode 100644
index 0000000..32c80fd
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizExecutionIntentService.java
@@ -0,0 +1,17 @@
+package com.ruoyi.business.service;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizExecutionIntent;
+
+/**
+ * 执行意向Service接口
+ */
+public interface IBizExecutionIntentService
+{
+ BizExecutionIntent getById(String intentId);
+ List selectList(BizExecutionIntent entity);
+ int insert(BizExecutionIntent entity);
+ int updateByPrimaryKey(BizExecutionIntent entity);
+ int deleteByPrimaryKey(String intentId);
+ int deleteByPrimaryKeys(String[] intentId);
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizExpertService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizExpertService.java
new file mode 100644
index 0000000..814ec30
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizExpertService.java
@@ -0,0 +1,20 @@
+package com.ruoyi.business.service;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizExpert;
+
+/**
+ * 专家Service接口
+ */
+public interface IBizExpertService
+{
+ BizExpert getById(String expertId);
+ BizExpert getByUserId(Long userId);
+ List selectList(BizExpert entity);
+ int insert(BizExpert entity);
+ int updateByPrimaryKey(BizExpert entity);
+ /** 按 userId 更新或新建 (upsert) */
+ int updateProfileByUserId(BizExpert entity);
+ int deleteByPrimaryKey(String expertId);
+ int deleteByPrimaryKeys(String[] expertId);
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizInvitationService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizInvitationService.java
new file mode 100644
index 0000000..fe03200
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizInvitationService.java
@@ -0,0 +1,17 @@
+package com.ruoyi.business.service;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizInvitation;
+
+/**
+ * 邀请函Service接口
+ */
+public interface IBizInvitationService
+{
+ BizInvitation getById(String invitationId);
+ List selectList(BizInvitation entity);
+ int insert(BizInvitation entity);
+ int updateByPrimaryKey(BizInvitation entity);
+ int deleteByPrimaryKey(String invitationId);
+ int deleteByPrimaryKeys(String[] invitationId);
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizLaborVoucherService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizLaborVoucherService.java
new file mode 100644
index 0000000..d334db3
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizLaborVoucherService.java
@@ -0,0 +1,17 @@
+package com.ruoyi.business.service;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizLaborVoucher;
+
+/**
+ * 劳务凭证Service接口
+ */
+public interface IBizLaborVoucherService
+{
+ BizLaborVoucher getById(String voucherId);
+ List selectList(BizLaborVoucher entity);
+ int insert(BizLaborVoucher entity);
+ int updateByPrimaryKey(BizLaborVoucher entity);
+ int deleteByPrimaryKey(String voucherId);
+ int deleteByPrimaryKeys(String[] voucherId);
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizMeetingService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizMeetingService.java
new file mode 100644
index 0000000..4a58959
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizMeetingService.java
@@ -0,0 +1,17 @@
+package com.ruoyi.business.service;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizMeeting;
+
+/**
+ * 会议Service接口
+ */
+public interface IBizMeetingService
+{
+ BizMeeting getById(String meetingId);
+ List selectList(BizMeeting entity);
+ int insert(BizMeeting entity);
+ int updateByPrimaryKey(BizMeeting entity);
+ int deleteByPrimaryKey(String meetingId);
+ int deleteByPrimaryKeys(String[] meetingId);
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizMeetingSettlementService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizMeetingSettlementService.java
new file mode 100644
index 0000000..7c94ea1
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizMeetingSettlementService.java
@@ -0,0 +1,17 @@
+package com.ruoyi.business.service;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizMeetingSettlement;
+
+/**
+ * 会议结算Service接口
+ */
+public interface IBizMeetingSettlementService
+{
+ BizMeetingSettlement getById(String settlementId);
+ List selectList(BizMeetingSettlement entity);
+ int insert(BizMeetingSettlement entity);
+ int updateByPrimaryKey(BizMeetingSettlement entity);
+ int deleteByPrimaryKey(String settlementId);
+ int deleteByPrimaryKeys(String[] settlementId);
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizMessageService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizMessageService.java
new file mode 100644
index 0000000..6e919b7
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizMessageService.java
@@ -0,0 +1,31 @@
+package com.ruoyi.business.service;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizMessage;
+
+/**
+ * 个人消息Service接口
+ */
+public interface IBizMessageService
+{
+ BizMessage getById(Long msgId);
+
+ List selectList(BizMessage entity);
+
+ /** 收件人的最近消息 (含未读) */
+ List selectMyRecent(Long receiverUserId, Integer limit);
+
+ int insert(BizMessage entity);
+
+ int updateByPrimaryKey(BizMessage entity);
+
+ /** 收件人标记单条已读 (会校验归属) */
+ int markRead(Long msgId, Long receiverUserId);
+
+ /** 收件人标记全部已读 */
+ int markAllRead(Long receiverUserId);
+
+ int deleteByPrimaryKey(Long msgId);
+
+ int deleteByPrimaryKeys(Long[] msgIds);
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizOrgService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizOrgService.java
new file mode 100644
index 0000000..7bcbb9b
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizOrgService.java
@@ -0,0 +1,12 @@
+package com.ruoyi.business.service;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizOrg;
+
+public interface IBizOrgService {
+ BizOrg getById(Long orgId);
+ List selectList(BizOrg entity);
+ int insert(BizOrg entity);
+ int updateByPrimaryKey(BizOrg entity);
+ int deleteByPrimaryKeys(Long[] orgIds);
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizPersonService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizPersonService.java
new file mode 100644
index 0000000..d3470d8
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizPersonService.java
@@ -0,0 +1,24 @@
+package com.ruoyi.business.service;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizPerson;
+import com.ruoyi.common.core.domain.entity.SysUser;
+
+/**
+ * 人员Service接口
+ *
+ * insert(entity, mainUserId):
+ * - 新建 biz_person 同时创建 sys_user 子账号 (account_type='SUB', parent_user_id=mainUserId)
+ * - 返回新 sys_user 信息 (含 username + 明文 password, 仅创建时一次性回传给前端 toast 显示)
+ */
+public interface IBizPersonService
+{
+ BizPerson getById(String personId);
+ List selectList(BizPerson entity);
+ /** sponsor 专属: 走 BizPersonMapper.selectSponsorList, 用 sys_user.parent_user_id 做归属过滤 */
+ List selectSponsorList(BizPerson entity);
+ SysUser insert(BizPerson entity, Long mainUserId);
+ int updateByPrimaryKey(BizPerson entity);
+ int deleteByPrimaryKey(String personId);
+ int deleteByPrimaryKeys(String[] personId);
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizProjectAssignService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizProjectAssignService.java
new file mode 100644
index 0000000..2b8eee0
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizProjectAssignService.java
@@ -0,0 +1,18 @@
+package com.ruoyi.business.service;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizProjectAssign;
+
+/**
+ * 项目执行方分配 Service 接口
+ */
+public interface IBizProjectAssignService
+{
+ BizProjectAssign getById(String assignId);
+ List selectByProjectId(Long projectId);
+ List selectList(BizProjectAssign entity);
+ int insert(BizProjectAssign entity);
+ int updateByPrimaryKey(BizProjectAssign entity);
+ int deleteByPrimaryKey(String assignId);
+ int deleteByProjectId(Long projectId);
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizProjectPlanService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizProjectPlanService.java
new file mode 100644
index 0000000..f29a3c4
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizProjectPlanService.java
@@ -0,0 +1,17 @@
+package com.ruoyi.business.service;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizProjectPlan;
+
+/**
+ * 项目策划方案Service接口
+ */
+public interface IBizProjectPlanService
+{
+ BizProjectPlan getById(String planId);
+ List selectList(BizProjectPlan entity);
+ int insert(BizProjectPlan entity);
+ int updateByPrimaryKey(BizProjectPlan entity);
+ int deleteByPrimaryKey(String planId);
+ int deleteByPrimaryKeys(String[] planId);
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizProjectRatingService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizProjectRatingService.java
new file mode 100644
index 0000000..5a5276c
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizProjectRatingService.java
@@ -0,0 +1,19 @@
+package com.ruoyi.business.service;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizProjectRating;
+
+/**
+ * 项目评分Service接口
+ */
+public interface IBizProjectRatingService
+{
+ BizProjectRating getById(String ratingId);
+ List selectList(BizProjectRating entity);
+ /** 按 projectId + raterId + raterRole upsert 评分 */
+ int upsertRating(BizProjectRating entity);
+ int insert(BizProjectRating entity);
+ int updateByPrimaryKey(BizProjectRating entity);
+ int deleteByPrimaryKey(String ratingId);
+ int deleteByPrimaryKeys(String[] ratingId);
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizProjectService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizProjectService.java
new file mode 100644
index 0000000..87fb106
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizProjectService.java
@@ -0,0 +1,19 @@
+package com.ruoyi.business.service;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizProject;
+
+/**
+ * 项目Service接口
+ */
+public interface IBizProjectService
+{
+ BizProject getById(String projectId);
+ List selectList(BizProject entity);
+ /** sponsor 端专属: LEFT JOIN 当前 login 用户评分回显 */
+ List selectSponsorList(BizProject entity);
+ int insert(BizProject entity);
+ int updateByPrimaryKey(BizProject entity);
+ int deleteByPrimaryKey(String projectId);
+ int deleteByPrimaryKeys(String[] projectId);
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizProjectSponsorAssignService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizProjectSponsorAssignService.java
new file mode 100644
index 0000000..6a6313c
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizProjectSponsorAssignService.java
@@ -0,0 +1,11 @@
+package com.ruoyi.business.service;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizProjectSponsorAssign;
+
+public interface IBizProjectSponsorAssignService {
+ /** 赞助方分配 (策略: 按 project_id 先删后插, 一个项目只分配一个 sponsor) */
+ int insertAssign(BizProjectSponsorAssign entity);
+ List listByProjectId(String projectId);
+ int deleteByProjectId(String projectId);
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizPublicityService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizPublicityService.java
new file mode 100644
index 0000000..4f4941f
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizPublicityService.java
@@ -0,0 +1,17 @@
+package com.ruoyi.business.service;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizPublicity;
+
+/**
+ * 项目公告Service接口
+ */
+public interface IBizPublicityService
+{
+ BizPublicity getById(Long id);
+ List selectList(BizPublicity entity);
+ int insert(BizPublicity entity);
+ int updateByPrimaryKey(BizPublicity entity);
+ int deleteByPrimaryKey(Long id);
+ int deleteByPrimaryKeys(Long[] ids);
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizResourceService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizResourceService.java
new file mode 100644
index 0000000..6838834
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizResourceService.java
@@ -0,0 +1,17 @@
+package com.ruoyi.business.service;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizResource;
+
+/**
+ * 资源Service接口
+ */
+public interface IBizResourceService
+{
+ BizResource getById(String resourceId);
+ List selectList(BizResource entity);
+ int insert(BizResource entity);
+ int updateByPrimaryKey(BizResource entity);
+ int deleteByPrimaryKey(String resourceId);
+ int deleteByPrimaryKeys(String[] resourceId);
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizSubmissionService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizSubmissionService.java
new file mode 100644
index 0000000..b73fae6
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizSubmissionService.java
@@ -0,0 +1,17 @@
+package com.ruoyi.business.service;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizSubmission;
+
+/**
+ * 投稿Service接口
+ */
+public interface IBizSubmissionService
+{
+ BizSubmission getById(String submissionId);
+ List selectList(BizSubmission entity);
+ int insert(BizSubmission entity);
+ int updateByPrimaryKey(BizSubmission entity);
+ int deleteByPrimaryKey(String submissionId);
+ int deleteByPrimaryKeys(String[] submissionId);
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizSupportIntentService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizSupportIntentService.java
new file mode 100644
index 0000000..8a50cfc
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizSupportIntentService.java
@@ -0,0 +1,17 @@
+package com.ruoyi.business.service;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizSupportIntent;
+
+/**
+ * 支持意向Service接口
+ */
+public interface IBizSupportIntentService
+{
+ BizSupportIntent getById(String intentId);
+ List selectList(BizSupportIntent entity);
+ int insert(BizSupportIntent entity);
+ int updateByPrimaryKey(BizSupportIntent entity);
+ int deleteByPrimaryKey(String intentId);
+ int deleteByPrimaryKeys(String[] intentId);
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizSupportLetterService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizSupportLetterService.java
new file mode 100644
index 0000000..79351d1
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/IBizSupportLetterService.java
@@ -0,0 +1,17 @@
+package com.ruoyi.business.service;
+
+import java.util.List;
+import com.ruoyi.business.domain.BizSupportLetter;
+
+/**
+ * 支持函Service接口
+ */
+public interface IBizSupportLetterService
+{
+ BizSupportLetter getById(String letterId);
+ List selectList(BizSupportLetter entity);
+ int insert(BizSupportLetter entity);
+ int updateByPrimaryKey(BizSupportLetter entity);
+ int deleteByPrimaryKey(String letterId);
+ int deleteByPrimaryKeys(String[] letterId);
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/SysSmsService.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/SysSmsService.java
new file mode 100644
index 0000000..d353c99
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/SysSmsService.java
@@ -0,0 +1,111 @@
+package com.ruoyi.business.service;
+
+import com.ruoyi.business.dto.SmsValidForm;
+import com.ruoyi.business.sms.AliyunSmsSender;
+import com.ruoyi.common.core.redis.RedisCache;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 短信验证码服务
+ *
+ * 参考 hwt-code SysSmsService 模式:
+ * - 验证码存 Redis 10 分钟 (SMSCODE:uuid -> phone+code)
+ * - dev 模式不真发短信, 仅 log + 返回固定 1234 (开发期用户测试用)
+ * - 同一 IP 1 分钟内不可重复发送 (SMS:ip)
+ *
+ * 当前 sys0808 不接入阿里云, dev 模式 = 固定码 1234, 实际部署时接入 aliyun dysmsapi
+ */
+@Service
+public class SysSmsService {
+
+ private static final Logger log = LoggerFactory.getLogger(SysSmsService.class);
+
+ /** 用于验证SMS是否频繁发送, 1 分钟有效 */
+ public static final String SMS_PREFIX = "SMS:";
+
+ /** 用于验证手机号+验证码, 10 分钟有效 */
+ public static final String SMS_CAPTCHA_CODE_KEY = "SMSCODE:";
+
+ @Autowired
+ private RedisCache redisCache;
+
+ @Autowired
+ private AliyunSmsSender aliyunSmsSender;
+
+ /**
+ * dev 模式判断: 手机号以 "10" 开头视为开发测试 (固定码 1234), 其它走 aliyun 真发
+ * 该逻辑不依赖 application.yml 配置, 确保开发/生产两种手机号能并存
+ */
+ private boolean isDev(String phone) {
+ return phone.startsWith("10");
+ }
+
+ /** 发送短信验证码, 返回 uuid (前端提交验证时回传) */
+ public String sendCode(String phone) {
+ if (phone == null || phone.trim().isEmpty()) {
+ throw new RuntimeException("手机号码不能为空");
+ }
+ if (phone.startsWith(" ")) {
+ throw new RuntimeException("手机号不能以空格开头");
+ }
+
+ String code;
+ if (isDev(phone)) {
+ // dev 模式 (10 开头): 固定码 1234 (供内部测试)
+ code = "1234";
+ log.info("[SMS][DEV][phone-prefix=10] 向 {} 发送验证码: {}", phone, code);
+ } else {
+ // prod 模式: aliyun 真发
+ code = generateCode(4);
+ log.info("[SMS][PROD] 向 {} 发送验证码: {}", phone, code);
+ boolean ok = aliyunSmsSender.sendCode(phone, code);
+ if (!ok) {
+ throw new RuntimeException("短信发送失败, 请稍后再试");
+ }
+ }
+
+ // 存 redis: SMSCODE: -> phone+code, 10 分钟有效
+ String uuid = UUID.randomUUID().toString();
+ redisCache.setCacheObject(SMS_CAPTCHA_CODE_KEY + uuid, phone + code, 10, TimeUnit.MINUTES);
+ log.info("[SMS] 已存入 redis, uuid={}, ttl=10min", uuid);
+ return uuid;
+ }
+
+ /**
+ * 生成 4 位数字验证码
+ */
+ private String generateCode(int length) {
+ StringBuilder sb = new StringBuilder();
+ java.util.Random random = new java.util.Random();
+ for (int i = 0; i < length; i++) {
+ sb.append(random.nextInt(10));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * 校验验证码, 失败抛出 RuntimeException
+ */
+ public void verifyCode(SmsValidForm form) {
+ if (form == null || form.getPhone() == null || form.getSmsCode() == null || form.getUuid() == null) {
+ throw new RuntimeException("校验参数不完整");
+ }
+ String key = SMS_CAPTCHA_CODE_KEY + form.getUuid();
+ String value = redisCache.getCacheObject(key);
+ if (value == null) {
+ if (form.isFree()) return;
+ throw new RuntimeException("验证码已过期");
+ }
+ if (!value.equals(form.getPhone() + form.getSmsCode())) {
+ throw new RuntimeException("验证码错误");
+ }
+ // 校验成功后删除 (防止重用)
+ redisCache.deleteObject(key);
+ }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizDepartmentServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizDepartmentServiceImpl.java
new file mode 100644
index 0000000..74e3bcb
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizDepartmentServiceImpl.java
@@ -0,0 +1,43 @@
+package com.ruoyi.business.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.business.domain.BizDepartment;
+import com.ruoyi.business.mapper.BizDepartmentMapper;
+import com.ruoyi.business.service.IBizDepartmentService;
+
+@Service
+public class BizDepartmentServiceImpl implements IBizDepartmentService
+{
+ @Autowired
+ private BizDepartmentMapper bizDepartmentMapper;
+
+ @Override
+ public BizDepartment getById(Long deptId)
+ { return bizDepartmentMapper.selectByPrimaryKey(deptId); }
+
+ @Override
+ public List selectList(BizDepartment entity)
+ { return bizDepartmentMapper.selectList(entity); }
+
+ @Override
+ public List selectActive()
+ { return bizDepartmentMapper.selectActive(); }
+
+ @Override
+ public int insert(BizDepartment entity)
+ { return bizDepartmentMapper.insert(entity); }
+
+ @Override
+ public int updateByPrimaryKey(BizDepartment entity)
+ { return bizDepartmentMapper.updateByPrimaryKey(entity); }
+
+ @Override
+ public int deleteByPrimaryKey(Long deptId)
+ { return bizDepartmentMapper.deleteByPrimaryKey(deptId); }
+
+ @Override
+ public int deleteByPrimaryKeys(Long[] deptIds)
+ { return bizDepartmentMapper.deleteByPrimaryKeys(deptIds); }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizDoctorTitleServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizDoctorTitleServiceImpl.java
new file mode 100644
index 0000000..f363f22
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizDoctorTitleServiceImpl.java
@@ -0,0 +1,43 @@
+package com.ruoyi.business.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.business.domain.BizDoctorTitle;
+import com.ruoyi.business.mapper.BizDoctorTitleMapper;
+import com.ruoyi.business.service.IBizDoctorTitleService;
+
+@Service
+public class BizDoctorTitleServiceImpl implements IBizDoctorTitleService
+{
+ @Autowired
+ private BizDoctorTitleMapper bizDoctorTitleMapper;
+
+ @Override
+ public BizDoctorTitle getById(Long titleId)
+ { return bizDoctorTitleMapper.selectByPrimaryKey(titleId); }
+
+ @Override
+ public List selectList(BizDoctorTitle entity)
+ { return bizDoctorTitleMapper.selectList(entity); }
+
+ @Override
+ public List selectActive()
+ { return bizDoctorTitleMapper.selectActive(); }
+
+ @Override
+ public int insert(BizDoctorTitle entity)
+ { return bizDoctorTitleMapper.insert(entity); }
+
+ @Override
+ public int updateByPrimaryKey(BizDoctorTitle entity)
+ { return bizDoctorTitleMapper.updateByPrimaryKey(entity); }
+
+ @Override
+ public int deleteByPrimaryKey(Long titleId)
+ { return bizDoctorTitleMapper.deleteByPrimaryKey(titleId); }
+
+ @Override
+ public int deleteByPrimaryKeys(Long[] titleIds)
+ { return bizDoctorTitleMapper.deleteByPrimaryKeys(titleIds); }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizExecutionIntentServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizExecutionIntentServiceImpl.java
new file mode 100644
index 0000000..56ad398
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizExecutionIntentServiceImpl.java
@@ -0,0 +1,33 @@
+package com.ruoyi.business.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.business.domain.BizExecutionIntent;
+import com.ruoyi.business.mapper.BizExecutionIntentMapper;
+import com.ruoyi.business.service.IBizExecutionIntentService;
+
+@Service
+public class BizExecutionIntentServiceImpl implements IBizExecutionIntentService
+{
+ @Autowired
+ private BizExecutionIntentMapper bizExecutionIntentMapper;
+
+ @Override
+ public BizExecutionIntent getById(String intentId)
+ { return bizExecutionIntentMapper.selectByPrimaryKey(intentId); }
+ @Override
+ public List selectList(BizExecutionIntent entity)
+ { return bizExecutionIntentMapper.selectList(entity); }
+ @Override
+ public int insert(BizExecutionIntent entity) { com.ruoyi.common.utils.id.SnowflakeId.injectIfEmpty(entity, "intentId"); return bizExecutionIntentMapper.insert(entity); }
+ @Override
+ public int updateByPrimaryKey(BizExecutionIntent entity)
+ { return bizExecutionIntentMapper.updateByPrimaryKey(entity); }
+ @Override
+ public int deleteByPrimaryKey(String intentId)
+ { return bizExecutionIntentMapper.deleteByPrimaryKey(intentId); }
+ @Override
+ public int deleteByPrimaryKeys(String[] intentId)
+ { return bizExecutionIntentMapper.deleteByPrimaryKeys(intentId); }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizExpertServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizExpertServiceImpl.java
new file mode 100644
index 0000000..49ef70c
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizExpertServiceImpl.java
@@ -0,0 +1,45 @@
+package com.ruoyi.business.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.business.domain.BizExpert;
+import com.ruoyi.business.mapper.BizExpertMapper;
+import com.ruoyi.business.service.IBizExpertService;
+
+@Service
+public class BizExpertServiceImpl implements IBizExpertService
+{
+ @Autowired
+ private BizExpertMapper bizExpertMapper;
+
+ @Override
+ public BizExpert getById(String expertId)
+ { return bizExpertMapper.selectByPrimaryKey(expertId); }
+ @Override
+ public BizExpert getByUserId(Long userId)
+ { return bizExpertMapper.selectByUserId(userId); }
+ @Override
+ public List selectList(BizExpert entity)
+ { return bizExpertMapper.selectList(entity); }
+ @Override
+ public int insert(BizExpert entity) { com.ruoyi.common.utils.id.SnowflakeId.injectIfEmpty(entity, "expertId"); return bizExpertMapper.insert(entity); }
+ @Override
+ public int updateByPrimaryKey(BizExpert entity)
+ { return bizExpertMapper.updateByPrimaryKey(entity); }
+ @Override
+ public int updateProfileByUserId(BizExpert entity)
+ {
+ BizExpert existed = bizExpertMapper.selectByUserId(entity.getUserId());
+ if (existed == null) {
+ return bizExpertMapper.insertWithUserId(entity);
+ }
+ return bizExpertMapper.updateByUserId(entity);
+ }
+ @Override
+ public int deleteByPrimaryKey(String expertId)
+ { return bizExpertMapper.deleteByPrimaryKey(expertId); }
+ @Override
+ public int deleteByPrimaryKeys(String[] expertId)
+ { return bizExpertMapper.deleteByPrimaryKeys(expertId); }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizInvitationServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizInvitationServiceImpl.java
new file mode 100644
index 0000000..ff92451
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizInvitationServiceImpl.java
@@ -0,0 +1,33 @@
+package com.ruoyi.business.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.business.domain.BizInvitation;
+import com.ruoyi.business.mapper.BizInvitationMapper;
+import com.ruoyi.business.service.IBizInvitationService;
+
+@Service
+public class BizInvitationServiceImpl implements IBizInvitationService
+{
+ @Autowired
+ private BizInvitationMapper bizInvitationMapper;
+
+ @Override
+ public BizInvitation getById(String invitationId)
+ { return bizInvitationMapper.selectByPrimaryKey(invitationId); }
+ @Override
+ public List selectList(BizInvitation entity)
+ { return bizInvitationMapper.selectList(entity); }
+ @Override
+ public int insert(BizInvitation entity) { com.ruoyi.common.utils.id.SnowflakeId.injectIfEmpty(entity, "annId"); return bizInvitationMapper.insert(entity); }
+ @Override
+ public int updateByPrimaryKey(BizInvitation entity)
+ { return bizInvitationMapper.updateByPrimaryKey(entity); }
+ @Override
+ public int deleteByPrimaryKey(String invitationId)
+ { return bizInvitationMapper.deleteByPrimaryKey(invitationId); }
+ @Override
+ public int deleteByPrimaryKeys(String[] invitationId)
+ { return bizInvitationMapper.deleteByPrimaryKeys(invitationId); }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizLaborVoucherServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizLaborVoucherServiceImpl.java
new file mode 100644
index 0000000..ac042d2
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizLaborVoucherServiceImpl.java
@@ -0,0 +1,33 @@
+package com.ruoyi.business.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.business.domain.BizLaborVoucher;
+import com.ruoyi.business.mapper.BizLaborVoucherMapper;
+import com.ruoyi.business.service.IBizLaborVoucherService;
+
+@Service
+public class BizLaborVoucherServiceImpl implements IBizLaborVoucherService
+{
+ @Autowired
+ private BizLaborVoucherMapper bizLaborVoucherMapper;
+
+ @Override
+ public BizLaborVoucher getById(String voucherId)
+ { return bizLaborVoucherMapper.selectByPrimaryKey(voucherId); }
+ @Override
+ public List selectList(BizLaborVoucher entity)
+ { return bizLaborVoucherMapper.selectList(entity); }
+ @Override
+ public int insert(BizLaborVoucher entity) { com.ruoyi.common.utils.id.SnowflakeId.injectIfEmpty(entity, "voucherId"); return bizLaborVoucherMapper.insert(entity); }
+ @Override
+ public int updateByPrimaryKey(BizLaborVoucher entity)
+ { return bizLaborVoucherMapper.updateByPrimaryKey(entity); }
+ @Override
+ public int deleteByPrimaryKey(String voucherId)
+ { return bizLaborVoucherMapper.deleteByPrimaryKey(voucherId); }
+ @Override
+ public int deleteByPrimaryKeys(String[] voucherId)
+ { return bizLaborVoucherMapper.deleteByPrimaryKeys(voucherId); }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizMeetingServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizMeetingServiceImpl.java
new file mode 100644
index 0000000..4dc2939
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizMeetingServiceImpl.java
@@ -0,0 +1,33 @@
+package com.ruoyi.business.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.business.domain.BizMeeting;
+import com.ruoyi.business.mapper.BizMeetingMapper;
+import com.ruoyi.business.service.IBizMeetingService;
+
+@Service
+public class BizMeetingServiceImpl implements IBizMeetingService
+{
+ @Autowired
+ private BizMeetingMapper bizMeetingMapper;
+
+ @Override
+ public BizMeeting getById(String meetingId)
+ { return bizMeetingMapper.selectByPrimaryKey(meetingId); }
+ @Override
+ public List selectList(BizMeeting entity)
+ { return bizMeetingMapper.selectList(entity); }
+ @Override
+ public int insert(BizMeeting entity) { com.ruoyi.common.utils.id.SnowflakeId.injectIfEmpty(entity, "meetingId"); return bizMeetingMapper.insert(entity); }
+ @Override
+ public int updateByPrimaryKey(BizMeeting entity)
+ { return bizMeetingMapper.updateByPrimaryKey(entity); }
+ @Override
+ public int deleteByPrimaryKey(String meetingId)
+ { return bizMeetingMapper.deleteByPrimaryKey(meetingId); }
+ @Override
+ public int deleteByPrimaryKeys(String[] meetingId)
+ { return bizMeetingMapper.deleteByPrimaryKeys(meetingId); }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizMeetingSettlementServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizMeetingSettlementServiceImpl.java
new file mode 100644
index 0000000..90cefdf
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizMeetingSettlementServiceImpl.java
@@ -0,0 +1,33 @@
+package com.ruoyi.business.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.business.domain.BizMeetingSettlement;
+import com.ruoyi.business.mapper.BizMeetingSettlementMapper;
+import com.ruoyi.business.service.IBizMeetingSettlementService;
+
+@Service
+public class BizMeetingSettlementServiceImpl implements IBizMeetingSettlementService
+{
+ @Autowired
+ private BizMeetingSettlementMapper bizMeetingSettlementMapper;
+
+ @Override
+ public BizMeetingSettlement getById(String settlementId)
+ { return bizMeetingSettlementMapper.selectByPrimaryKey(settlementId); }
+ @Override
+ public List selectList(BizMeetingSettlement entity)
+ { return bizMeetingSettlementMapper.selectList(entity); }
+ @Override
+ public int insert(BizMeetingSettlement entity) { com.ruoyi.common.utils.id.SnowflakeId.injectIfEmpty(entity, "id"); return bizMeetingSettlementMapper.insert(entity); }
+ @Override
+ public int updateByPrimaryKey(BizMeetingSettlement entity)
+ { return bizMeetingSettlementMapper.updateByPrimaryKey(entity); }
+ @Override
+ public int deleteByPrimaryKey(String settlementId)
+ { return bizMeetingSettlementMapper.deleteByPrimaryKey(settlementId); }
+ @Override
+ public int deleteByPrimaryKeys(String[] settlementId)
+ { return bizMeetingSettlementMapper.deleteByPrimaryKeys(settlementId); }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizMessageServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizMessageServiceImpl.java
new file mode 100644
index 0000000..c0f5bc8
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizMessageServiceImpl.java
@@ -0,0 +1,69 @@
+package com.ruoyi.business.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.business.domain.BizMessage;
+import com.ruoyi.business.mapper.BizMessageMapper;
+import com.ruoyi.business.service.IBizMessageService;
+import com.ruoyi.common.utils.id.SnowflakeId;
+
+@Service
+public class BizMessageServiceImpl implements IBizMessageService
+{
+ @Autowired
+ private BizMessageMapper bizMessageMapper;
+
+ @Override
+ public BizMessage getById(Long msgId)
+ { return bizMessageMapper.selectByPrimaryKey(msgId); }
+
+ @Override
+ public List selectList(BizMessage entity)
+ { return bizMessageMapper.selectList(entity); }
+
+ @Override
+ public List selectMyRecent(Long receiverUserId, Integer limit)
+ {
+ BizMessage q = new BizMessage();
+ q.setReceiverUserId(receiverUserId);
+ if (limit != null) {
+ // 利用 rowBounds 在 mapper 里分页, 这里简单传 limit
+ q.getParams().put("limit", limit);
+ }
+ return bizMessageMapper.selectMyRecent(q);
+ }
+
+ @Override
+ public int insert(BizMessage entity)
+ {
+ SnowflakeId.injectIfEmpty(entity, "msgId");
+ return bizMessageMapper.insert(entity);
+ }
+
+ @Override
+ public int updateByPrimaryKey(BizMessage entity)
+ { return bizMessageMapper.updateByPrimaryKey(entity); }
+
+ @Override
+ public int markRead(Long msgId, Long receiverUserId)
+ {
+ BizMessage q = new BizMessage();
+ q.setMsgId(msgId);
+ q.setReceiverUserId(receiverUserId);
+ q.setIsRead("1");
+ return bizMessageMapper.markRead(q);
+ }
+
+ @Override
+ public int markAllRead(Long receiverUserId)
+ { return bizMessageMapper.markAllRead(receiverUserId); }
+
+ @Override
+ public int deleteByPrimaryKey(Long msgId)
+ { return bizMessageMapper.deleteByPrimaryKey(msgId); }
+
+ @Override
+ public int deleteByPrimaryKeys(Long[] msgIds)
+ { return bizMessageMapper.deleteByPrimaryKeys(msgIds); }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizOrgServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizOrgServiceImpl.java
new file mode 100644
index 0000000..59fcb09
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizOrgServiceImpl.java
@@ -0,0 +1,37 @@
+package com.ruoyi.business.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.business.domain.BizOrg;
+import com.ruoyi.business.mapper.BizOrgMapper;
+import com.ruoyi.business.service.IBizOrgService;
+import com.ruoyi.common.utils.id.SnowflakeId;
+
+@Service
+public class BizOrgServiceImpl implements IBizOrgService {
+ @Autowired
+ private BizOrgMapper bizOrgMapper;
+
+ @Override
+ public BizOrg getById(Long orgId) { return bizOrgMapper.selectByPrimaryKey(orgId); }
+
+ @Override
+ public List selectList(BizOrg entity) { return bizOrgMapper.selectList(entity); }
+
+ @Override
+ public int insert(BizOrg entity) {
+ // 主键由 AUTO_INCREMENT 自增, 不需要 Snowflake
+ return bizOrgMapper.insert(entity);
+ }
+
+ @Override
+ public int updateByPrimaryKey(BizOrg entity) { return bizOrgMapper.updateByPrimaryKey(entity); }
+
+ @Override
+ public int deleteByPrimaryKeys(Long[] orgIds) {
+ int rows = 0;
+ for (Long id : orgIds) { rows += bizOrgMapper.deleteByPrimaryKeys(new Long[]{id}); }
+ return rows;
+ }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizPersonServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizPersonServiceImpl.java
new file mode 100644
index 0000000..8a56c04
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizPersonServiceImpl.java
@@ -0,0 +1,89 @@
+package com.ruoyi.business.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.business.domain.BizPerson;
+import com.ruoyi.business.mapper.BizPersonMapper;
+import com.ruoyi.business.service.IBizPersonService;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.system.mapper.SysUserMapper;
+
+@Service
+public class BizPersonServiceImpl implements IBizPersonService
+{
+ @Autowired
+ private BizPersonMapper bizPersonMapper;
+ @Autowired
+ private SysUserMapper sysUserMapper;
+
+ @Override
+ public BizPerson getById(String personId)
+ { return bizPersonMapper.selectByPrimaryKey(personId); }
+
+ @Override
+ public List selectList(BizPerson entity)
+ { return bizPersonMapper.selectList(entity); }
+
+ @Override
+ public List selectSponsorList(BizPerson entity)
+ { return bizPersonMapper.selectSponsorList(entity); }
+
+ /**
+ * sponsor 端新建人员 = 同时创建 sys_user 子账号 (account_type='SUB', parent_user_id=主账号 user_id)
+ * 返回新 SysUser 含 username + 明文 password (前端 toast 显示后即丢)
+ */
+ @Override
+ public SysUser insert(BizPerson entity, Long mainUserId) {
+ // 0. 校验 username 唯一 (UK 约束, 先查更友好)
+ SysUser exist = sysUserMapper.selectUserByUserName(entity.getLoginUsername());
+ if (exist != null) {
+ throw new ServiceException("登录账号已存在");
+ }
+ // 1. 创建 sys_user 子账号
+ SysUser newUser = new SysUser();
+ newUser.setUserName(entity.getLoginUsername());
+ newUser.setNickName(entity.getName());
+ newUser.setPhonenumber(entity.getPhone());
+ newUser.setPassword(SecurityUtils.encryptPassword(entity.getLoginPassword()));
+ newUser.setAccountType("SUB");
+ newUser.setParentUserId(mainUserId);
+ newUser.setStatus("0");
+ newUser.setDelFlag("0");
+ newUser.setCreateBy(SecurityUtils.getUsername());
+ // mybatis useGeneratedKeys 自动回填 userId
+ sysUserMapper.insertUser(newUser);
+
+ // 2. 创建 biz_person + user_id 绑定 + SnowflakeId
+ entity.setUserId(newUser.getUserId());
+ com.ruoyi.common.utils.id.SnowflakeId.injectIfEmpty(entity, "personId");
+ entity.setCreateBy(SecurityUtils.getUsername());
+ bizPersonMapper.insert(entity);
+
+ // 3. 把明文 password 临时塞回去 (仅本次返回,前端 toast 用完即丢)
+ newUser.setPassword(entity.getLoginPassword());
+ return newUser;
+ }
+
+ @Override
+ public int updateByPrimaryKey(BizPerson entity)
+ { return bizPersonMapper.updateByPrimaryKey(entity); }
+
+ @Override
+ public int deleteByPrimaryKey(String personId)
+ {
+ int n = bizPersonMapper.deleteByPrimaryKey(personId);
+ if (n > 0) bizPersonMapper.softDeleteSysUserByPersonIds(new String[]{ personId });
+ return n;
+ }
+
+ @Override
+ public int deleteByPrimaryKeys(String[] personIds)
+ {
+ int n = bizPersonMapper.deleteByPrimaryKeys(personIds);
+ if (n > 0) bizPersonMapper.softDeleteSysUserByPersonIds(personIds);
+ return n;
+ }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizProjectAssignServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizProjectAssignServiceImpl.java
new file mode 100644
index 0000000..b130174
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizProjectAssignServiceImpl.java
@@ -0,0 +1,40 @@
+package com.ruoyi.business.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.business.domain.BizProjectAssign;
+import com.ruoyi.business.mapper.BizProjectAssignMapper;
+import com.ruoyi.business.service.IBizProjectAssignService;
+
+@Service
+public class BizProjectAssignServiceImpl implements IBizProjectAssignService
+{
+ @Autowired
+ private BizProjectAssignMapper bizProjectAssignMapper;
+
+ @Override
+ public BizProjectAssign getById(String assignId) { return bizProjectAssignMapper.selectByPrimaryKey(assignId); }
+
+ @Override
+ public List selectByProjectId(Long projectId) { return bizProjectAssignMapper.selectByProjectId(projectId); }
+
+ @Override
+ public List selectList(BizProjectAssign entity) { return bizProjectAssignMapper.selectList(entity); }
+
+ @Override
+ public int insert(BizProjectAssign entity) {
+ com.ruoyi.common.utils.id.SnowflakeId.injectIfEmpty(entity, "assignId");
+ if (entity.getStatus() == null) entity.setStatus("0");
+ return bizProjectAssignMapper.insert(entity);
+ }
+
+ @Override
+ public int updateByPrimaryKey(BizProjectAssign entity) { return bizProjectAssignMapper.updateByPrimaryKey(entity); }
+
+ @Override
+ public int deleteByPrimaryKey(String assignId) { return bizProjectAssignMapper.deleteByPrimaryKey(assignId); }
+
+ @Override
+ public int deleteByProjectId(Long projectId) { return bizProjectAssignMapper.deleteByProjectId(projectId); }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizProjectPlanServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizProjectPlanServiceImpl.java
new file mode 100644
index 0000000..827e793
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizProjectPlanServiceImpl.java
@@ -0,0 +1,33 @@
+package com.ruoyi.business.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.business.domain.BizProjectPlan;
+import com.ruoyi.business.mapper.BizProjectPlanMapper;
+import com.ruoyi.business.service.IBizProjectPlanService;
+
+@Service
+public class BizProjectPlanServiceImpl implements IBizProjectPlanService
+{
+ @Autowired
+ private BizProjectPlanMapper bizProjectPlanMapper;
+
+ @Override
+ public BizProjectPlan getById(String planId)
+ { return bizProjectPlanMapper.selectByPrimaryKey(planId); }
+ @Override
+ public List selectList(BizProjectPlan entity)
+ { return bizProjectPlanMapper.selectList(entity); }
+ @Override
+ public int insert(BizProjectPlan entity) { com.ruoyi.common.utils.id.SnowflakeId.injectIfEmpty(entity, "planId"); return bizProjectPlanMapper.insert(entity); }
+ @Override
+ public int updateByPrimaryKey(BizProjectPlan entity)
+ { return bizProjectPlanMapper.updateByPrimaryKey(entity); }
+ @Override
+ public int deleteByPrimaryKey(String planId)
+ { return bizProjectPlanMapper.deleteByPrimaryKey(planId); }
+ @Override
+ public int deleteByPrimaryKeys(String[] planId)
+ { return bizProjectPlanMapper.deleteByPrimaryKeys(planId); }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizProjectRatingServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizProjectRatingServiceImpl.java
new file mode 100644
index 0000000..e66394a
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizProjectRatingServiceImpl.java
@@ -0,0 +1,42 @@
+package com.ruoyi.business.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.business.domain.BizProjectRating;
+import com.ruoyi.business.mapper.BizProjectRatingMapper;
+import com.ruoyi.business.service.IBizProjectRatingService;
+
+@Service
+public class BizProjectRatingServiceImpl implements IBizProjectRatingService {
+ @Autowired
+ private BizProjectRatingMapper bizProjectRatingMapper;
+
+ @Override
+ public BizProjectRating getById(String ratingId)
+ { return bizProjectRatingMapper.selectByPrimaryKey(ratingId); }
+
+ @Override
+ public List selectList(BizProjectRating entity)
+ { return bizProjectRatingMapper.selectList(entity); }
+
+ @Override
+ public int insert(BizProjectRating entity)
+ { com.ruoyi.common.utils.id.SnowflakeId.injectIfEmpty(entity, "ratingId"); return bizProjectRatingMapper.insert(entity); }
+
+ @Override
+ public int updateByPrimaryKey(BizProjectRating entity)
+ { return bizProjectRatingMapper.updateByPrimaryKey(entity); }
+
+ @Override
+ public int upsertRating(BizProjectRating entity)
+ { return bizProjectRatingMapper.upsertRating(entity); }
+
+ @Override
+ public int deleteByPrimaryKey(String ratingId)
+ { return bizProjectRatingMapper.deleteByPrimaryKey(ratingId); }
+
+ @Override
+ public int deleteByPrimaryKeys(String[] ratingId)
+ { return bizProjectRatingMapper.deleteByPrimaryKeys(ratingId); }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizProjectServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizProjectServiceImpl.java
new file mode 100644
index 0000000..a909b83
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizProjectServiceImpl.java
@@ -0,0 +1,36 @@
+package com.ruoyi.business.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.business.domain.BizProject;
+import com.ruoyi.business.mapper.BizProjectMapper;
+import com.ruoyi.business.service.IBizProjectService;
+
+@Service
+public class BizProjectServiceImpl implements IBizProjectService
+{
+ @Autowired
+ private BizProjectMapper bizProjectMapper;
+
+ @Override
+ public BizProject getById(String projectId)
+ { return bizProjectMapper.selectByPrimaryKey(projectId); }
+ @Override
+ public List selectList(BizProject entity)
+ { return bizProjectMapper.selectList(entity); }
+ @Override
+ public List selectSponsorList(BizProject entity)
+ { return bizProjectMapper.selectSponsorList(entity); }
+ @Override
+ public int insert(BizProject entity) { com.ruoyi.common.utils.id.SnowflakeId.injectIfEmpty(entity, "projectId"); return bizProjectMapper.insert(entity); }
+ @Override
+ public int updateByPrimaryKey(BizProject entity)
+ { return bizProjectMapper.updateByPrimaryKey(entity); }
+ @Override
+ public int deleteByPrimaryKey(String projectId)
+ { return bizProjectMapper.deleteByPrimaryKey(projectId); }
+ @Override
+ public int deleteByPrimaryKeys(String[] projectId)
+ { return bizProjectMapper.deleteByPrimaryKeys(projectId); }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizProjectSponsorAssignServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizProjectSponsorAssignServiceImpl.java
new file mode 100644
index 0000000..3985e11
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizProjectSponsorAssignServiceImpl.java
@@ -0,0 +1,31 @@
+package com.ruoyi.business.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.business.domain.BizProjectSponsorAssign;
+import com.ruoyi.business.mapper.BizProjectSponsorAssignMapper;
+import com.ruoyi.business.service.IBizProjectSponsorAssignService;
+
+@Service
+public class BizProjectSponsorAssignServiceImpl implements IBizProjectSponsorAssignService {
+ @Autowired
+ private BizProjectSponsorAssignMapper mapper;
+
+ @Override
+ public int insertAssign(BizProjectSponsorAssign entity) {
+ // 赞助方分配策略: 一个项目只分配一个 sponsor, 先按 project_id 删, 再插
+ mapper.deleteByProjectId(entity.getProjectId());
+ return mapper.insertAssign(entity);
+ }
+
+ @Override
+ public List listByProjectId(String projectId) {
+ return mapper.selectByProjectId(projectId);
+ }
+
+ @Override
+ public int deleteByProjectId(String projectId) {
+ return mapper.deleteByProjectId(projectId);
+ }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizPublicityServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizPublicityServiceImpl.java
new file mode 100644
index 0000000..2f5e11d
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizPublicityServiceImpl.java
@@ -0,0 +1,39 @@
+package com.ruoyi.business.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.business.domain.BizPublicity;
+import com.ruoyi.business.mapper.BizPublicityMapper;
+import com.ruoyi.business.service.IBizPublicityService;
+
+@Service
+public class BizPublicityServiceImpl implements IBizPublicityService
+{
+ @Autowired
+ private BizPublicityMapper bizPublicityMapper;
+
+ @Override
+ public BizPublicity getById(Long id)
+ { return bizPublicityMapper.selectByPrimaryKey(id); }
+
+ @Override
+ public List selectList(BizPublicity entity)
+ { return bizPublicityMapper.selectList(entity); }
+
+ @Override
+ public int insert(BizPublicity entity)
+ { return bizPublicityMapper.insert(entity); }
+
+ @Override
+ public int updateByPrimaryKey(BizPublicity entity)
+ { return bizPublicityMapper.updateByPrimaryKey(entity); }
+
+ @Override
+ public int deleteByPrimaryKey(Long id)
+ { return bizPublicityMapper.deleteByPrimaryKey(id); }
+
+ @Override
+ public int deleteByPrimaryKeys(Long[] ids)
+ { return bizPublicityMapper.deleteByPrimaryKeys(ids); }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizResourceServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizResourceServiceImpl.java
new file mode 100644
index 0000000..4a2bcf2
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizResourceServiceImpl.java
@@ -0,0 +1,33 @@
+package com.ruoyi.business.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.business.domain.BizResource;
+import com.ruoyi.business.mapper.BizResourceMapper;
+import com.ruoyi.business.service.IBizResourceService;
+
+@Service
+public class BizResourceServiceImpl implements IBizResourceService
+{
+ @Autowired
+ private BizResourceMapper bizResourceMapper;
+
+ @Override
+ public BizResource getById(String resourceId)
+ { return bizResourceMapper.selectByPrimaryKey(resourceId); }
+ @Override
+ public List selectList(BizResource entity)
+ { return bizResourceMapper.selectList(entity); }
+ @Override
+ public int insert(BizResource entity) { com.ruoyi.common.utils.id.SnowflakeId.injectIfEmpty(entity, "resourceId"); return bizResourceMapper.insert(entity); }
+ @Override
+ public int updateByPrimaryKey(BizResource entity)
+ { return bizResourceMapper.updateByPrimaryKey(entity); }
+ @Override
+ public int deleteByPrimaryKey(String resourceId)
+ { return bizResourceMapper.deleteByPrimaryKey(resourceId); }
+ @Override
+ public int deleteByPrimaryKeys(String[] resourceId)
+ { return bizResourceMapper.deleteByPrimaryKeys(resourceId); }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizSubmissionServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizSubmissionServiceImpl.java
new file mode 100644
index 0000000..86ac9bc
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizSubmissionServiceImpl.java
@@ -0,0 +1,33 @@
+package com.ruoyi.business.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.business.domain.BizSubmission;
+import com.ruoyi.business.mapper.BizSubmissionMapper;
+import com.ruoyi.business.service.IBizSubmissionService;
+
+@Service
+public class BizSubmissionServiceImpl implements IBizSubmissionService
+{
+ @Autowired
+ private BizSubmissionMapper bizSubmissionMapper;
+
+ @Override
+ public BizSubmission getById(String submissionId)
+ { return bizSubmissionMapper.selectByPrimaryKey(submissionId); }
+ @Override
+ public List selectList(BizSubmission entity)
+ { return bizSubmissionMapper.selectList(entity); }
+ @Override
+ public int insert(BizSubmission entity) { com.ruoyi.common.utils.id.SnowflakeId.injectIfEmpty(entity, "subId"); return bizSubmissionMapper.insert(entity); }
+ @Override
+ public int updateByPrimaryKey(BizSubmission entity)
+ { return bizSubmissionMapper.updateByPrimaryKey(entity); }
+ @Override
+ public int deleteByPrimaryKey(String submissionId)
+ { return bizSubmissionMapper.deleteByPrimaryKey(submissionId); }
+ @Override
+ public int deleteByPrimaryKeys(String[] submissionId)
+ { return bizSubmissionMapper.deleteByPrimaryKeys(submissionId); }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizSupportIntentServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizSupportIntentServiceImpl.java
new file mode 100644
index 0000000..c74850b
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizSupportIntentServiceImpl.java
@@ -0,0 +1,33 @@
+package com.ruoyi.business.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.business.domain.BizSupportIntent;
+import com.ruoyi.business.mapper.BizSupportIntentMapper;
+import com.ruoyi.business.service.IBizSupportIntentService;
+
+@Service
+public class BizSupportIntentServiceImpl implements IBizSupportIntentService
+{
+ @Autowired
+ private BizSupportIntentMapper bizSupportIntentMapper;
+
+ @Override
+ public BizSupportIntent getById(String intentId)
+ { return bizSupportIntentMapper.selectByPrimaryKey(intentId); }
+ @Override
+ public List selectList(BizSupportIntent entity)
+ { return bizSupportIntentMapper.selectList(entity); }
+ @Override
+ public int insert(BizSupportIntent entity) { com.ruoyi.common.utils.id.SnowflakeId.injectIfEmpty(entity, "intentId"); return bizSupportIntentMapper.insert(entity); }
+ @Override
+ public int updateByPrimaryKey(BizSupportIntent entity)
+ { return bizSupportIntentMapper.updateByPrimaryKey(entity); }
+ @Override
+ public int deleteByPrimaryKey(String intentId)
+ { return bizSupportIntentMapper.deleteByPrimaryKey(intentId); }
+ @Override
+ public int deleteByPrimaryKeys(String[] intentId)
+ { return bizSupportIntentMapper.deleteByPrimaryKeys(intentId); }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizSupportLetterServiceImpl.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizSupportLetterServiceImpl.java
new file mode 100644
index 0000000..93b35c6
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/service/impl/BizSupportLetterServiceImpl.java
@@ -0,0 +1,33 @@
+package com.ruoyi.business.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.business.domain.BizSupportLetter;
+import com.ruoyi.business.mapper.BizSupportLetterMapper;
+import com.ruoyi.business.service.IBizSupportLetterService;
+
+@Service
+public class BizSupportLetterServiceImpl implements IBizSupportLetterService
+{
+ @Autowired
+ private BizSupportLetterMapper bizSupportLetterMapper;
+
+ @Override
+ public BizSupportLetter getById(String letterId)
+ { return bizSupportLetterMapper.selectByPrimaryKey(letterId); }
+ @Override
+ public List selectList(BizSupportLetter entity)
+ { return bizSupportLetterMapper.selectList(entity); }
+ @Override
+ public int insert(BizSupportLetter entity) { com.ruoyi.common.utils.id.SnowflakeId.injectIfEmpty(entity, "annId"); return bizSupportLetterMapper.insert(entity); }
+ @Override
+ public int updateByPrimaryKey(BizSupportLetter entity)
+ { return bizSupportLetterMapper.updateByPrimaryKey(entity); }
+ @Override
+ public int deleteByPrimaryKey(String letterId)
+ { return bizSupportLetterMapper.deleteByPrimaryKey(letterId); }
+ @Override
+ public int deleteByPrimaryKeys(String[] letterId)
+ { return bizSupportLetterMapper.deleteByPrimaryKeys(letterId); }
+}
diff --git a/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/sms/AliyunSmsSender.java b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/sms/AliyunSmsSender.java
new file mode 100644
index 0000000..10c5ea7
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/java/com/ruoyi/business/sms/AliyunSmsSender.java
@@ -0,0 +1,89 @@
+package com.ruoyi.business.sms;
+
+import com.aliyuncs.DefaultAcsClient;
+import com.aliyuncs.IAcsClient;
+import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
+import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
+import com.aliyuncs.profile.DefaultProfile;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+/**
+ * 阿里云短信发送器
+ * 参考 hwt-code SysSmsService 模式: cn-hangzhou region + 强制 endpoint dysmsapi.aliyuncs.com
+ *
+ * 关键: 必须 addEndpoint(product, domain), 否则 SDK 自动加 dysmsapi-proxy.cn-.aliyuncs.com
+ * 该代理在服务器网络下不可达 (内网 IP 100.67.x), 而 dysmsapi.aliyuncs.com 可达
+ */
+@Service
+public class AliyunSmsSender {
+
+ private static final Logger log = LoggerFactory.getLogger(AliyunSmsSender.class);
+
+ private static final String PRODUCT = "Dysmsapi";
+ private static final String DOMAIN = "dysmsapi.aliyuncs.com";
+
+ @Value("${ruoyi.sms.accessKeyId}")
+ private String accessKeyId;
+
+ @Value("${ruoyi.sms.accessKeySecret}")
+ private String accessKeySecret;
+
+ @Value("${ruoyi.sms.signName}")
+ private String signName;
+
+ @Value("${ruoyi.sms.template}")
+ private String template;
+
+ @Value("${ruoyi.sms.regionId:cn-hangzhou}")
+ private String regionId;
+
+ private static volatile boolean endpointAdded = false;
+ private volatile IAcsClient client;
+
+ private IAcsClient getClient() {
+ if (client == null) {
+ synchronized (this) {
+ if (client == null) {
+ DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
+ if (!endpointAdded) {
+ try {
+ DefaultProfile.addEndpoint(regionId, regionId, PRODUCT, DOMAIN);
+ endpointAdded = true;
+ } catch (com.aliyuncs.exceptions.ClientException e) {
+ log.warn("[SMS] addEndpoint failed: {}", e.getMessage());
+ }
+ }
+ client = new DefaultAcsClient(profile);
+ }
+ }
+ }
+ return client;
+ }
+
+ /**
+ * 真发送短信验证码, 成功返回 true
+ */
+ public boolean sendCode(String phone, String code) {
+ try {
+ SendSmsRequest req = new SendSmsRequest();
+ req.setPhoneNumbers(phone);
+ req.setSignName(signName);
+ req.setTemplateCode(template);
+ req.setTemplateParam("{\"code\":\"" + code + "\"}");
+ SendSmsResponse resp = getClient().getAcsResponse(req);
+ if ("OK".equalsIgnoreCase(resp.getCode())) {
+ log.info("[SMS] aliyun 发送成功 phone={}, bizId={}", phone, resp.getBizId());
+ return true;
+ }
+ log.error("[SMS] aliyun 发送失败 phone={}, code={}, msg={}, requestId={}",
+ phone, resp.getCode(), resp.getMessage(), resp.getRequestId());
+ return false;
+ } catch (Exception e) {
+ log.error("[SMS] aliyun 异常 phone={}", phone, e);
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizDepartmentMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizDepartmentMapper.xml
new file mode 100644
index 0000000..eceb552
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizDepartmentMapper.xml
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select d.dept_id, d.name, d.sort, d.status,
+ d.create_by, d.create_time, d.update_by, d.update_time
+ from biz_department d
+
+
+
+
+ where d.dept_id = #{deptId}
+
+
+
+
+
+ and d.name like concat('%', #{name}, '%')
+ and d.status = #{status}
+
+ order by d.sort asc, d.dept_id asc
+
+
+
+
+ where d.status = '0'
+ order by d.sort asc, d.dept_id asc
+
+
+
+ insert into biz_department
+
+ name,
+ sort,
+ status,
+ create_by,
+ create_time,
+ update_time,
+
+
+ #{name},
+ #{sort},
+ #{status},
+ #{createBy},
+ sysdate(),
+ sysdate(),
+
+
+
+
+ update biz_department
+
+ name = #{name},
+ sort = #{sort},
+ status = #{status},
+ update_by = #{updateBy},
+ update_time = sysdate(),
+
+ where dept_id = #{deptId}
+
+
+
+ delete from biz_department where dept_id = #{deptId}
+
+
+
+ delete from biz_department where dept_id in
+
+ #{deptId}
+
+
+
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizDoctorTitleMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizDoctorTitleMapper.xml
new file mode 100644
index 0000000..163fda6
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizDoctorTitleMapper.xml
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select t.title_id, t.name, t.sort, t.status,
+ t.create_by, t.create_time, t.update_by, t.update_time
+ from biz_doctor_title t
+
+
+
+
+ where t.title_id = #{titleId}
+
+
+
+
+
+ and t.name like concat('%', #{name}, '%')
+ and t.status = #{status}
+
+ order by t.sort asc, t.title_id asc
+
+
+
+
+ where t.status = '0'
+ order by t.sort asc, t.title_id asc
+
+
+
+ insert into biz_doctor_title
+
+ name,
+ sort,
+ status,
+ create_by,
+ create_time,
+ update_time,
+
+
+ #{name},
+ #{sort},
+ #{status},
+ #{createBy},
+ sysdate(),
+ sysdate(),
+
+
+
+
+ update biz_doctor_title
+
+ name = #{name},
+ sort = #{sort},
+ status = #{status},
+ update_by = #{updateBy},
+ update_time = sysdate(),
+
+ where title_id = #{titleId}
+
+
+
+ delete from biz_doctor_title where title_id = #{titleId}
+
+
+
+ delete from biz_doctor_title where title_id in
+
+ #{titleId}
+
+
+
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizExecutionIntentMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizExecutionIntentMapper.xml
new file mode 100644
index 0000000..850454b
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizExecutionIntentMapper.xml
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select intent_id, user_id, project_no, project_name, name, work_unit, department, position, phone, onboard_status, create_by, create_time, update_by, update_time
+ from biz_execution_intent
+
+
+
+ where intent_id = #{intentId}
+
+
+
+
+ and user_id = #{userId}
+ and project_no = #{projectNo}
+ and project_name = #{projectName}
+ and name = #{name}
+ and department = #{department}
+ and position = #{position}
+ and phone = #{phone}
+
+ order by intent_id desc
+
+
+ insert into biz_execution_intent
+
+ intent_id,
+ user_id,
+ project_no,
+ project_name,
+ work_unit,
+ onboard_status,
+ name,
+ department,
+ position,
+ phone,
+ create_by,
+ create_time,
+
+
+ #{intentId},
+ #{userId},
+ #{projectNo},
+ #{projectName},
+ #{workUnit},
+ #{onboardStatus},
+ #{name},
+ #{department},
+ #{position},
+ #{phone},
+ #{createBy},
+ sysdate(),
+
+
+
+ update biz_execution_intent
+
+ project_no = #{projectNo},
+ project_name = #{projectName},
+ work_unit = #{workUnit},
+ onboard_status = #{onboardStatus},
+ name = #{name},
+ department = #{department},
+ position = #{position},
+ phone = #{phone},
+
+ where intent_id = #{intentId}
+
+
+ delete from biz_execution_intent where intent_id = #{intentId}
+
+
+ delete from biz_execution_intent where intent_id in
+
+ #{intentId}
+
+
+
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizExpertMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizExpertMapper.xml
new file mode 100644
index 0000000..fae1603
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizExpertMapper.xml
@@ -0,0 +1,218 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select expert_id, user_id, name, phone, region, id_card, work_unit, department, title, practice_cert_url, title_cert_url, bank_card, bank_name, bank_province, bank_city, bank_address, id_card_front_url, id_card_back_url, audit_status, audit_by, audit_time, create_by, create_time, update_by, update_time
+ from biz_expert
+
+
+
+ where user_id = #{userId} limit 1
+
+
+
+ where expert_id = #{expertId}
+
+
+
+
+ and name = #{name}
+ and phone = #{phone}
+ and department = #{department}
+ and title = #{title}
+
+ order by expert_id desc
+
+
+ insert into biz_expert
+
+ expert_id,
+ user_id,
+ name,
+ phone,
+ region,
+ id_card,
+ work_unit,
+ department,
+ title,
+ id_card_front_url,
+ id_card_back_url,
+ practice_cert_url,
+ title_cert_url,
+ bank_card,
+ bank_name,
+ bank_province,
+ bank_city,
+ bank_address,
+ audit_status,
+ audit_by,
+ audit_time,
+ status,
+ create_by,
+ create_time,
+ update_by,
+ update_time,
+
+
+ #{expertId},
+ #{userId},
+ #{name},
+ #{phone},
+ #{region},
+ #{idCard},
+ #{workUnit},
+ #{department},
+ #{title},
+ #{idCardFrontUrl},
+ #{idCardBackUrl},
+ #{practiceCertUrl},
+ #{titleCertUrl},
+ #{bankCard},
+ #{bankName},
+ #{bankProvince},
+ #{bankCity},
+ #{bankAddress},
+ #{auditStatus},
+ #{auditBy},
+ #{auditTime},
+ #{status},
+ #{createBy},
+ #{createTime},
+ #{updateBy},
+ #{updateTime},
+
+
+
+ update biz_expert
+
+ name = #{name},
+ phone = #{phone},
+ work_unit = #{workUnit},
+ department = #{department},
+ title = #{title},
+ region = #{region},
+ id_card = #{idCard},
+ bank_card = #{bankCard},
+ bank_name = #{bankName},
+ bank_province = #{bankProvince},
+ bank_city = #{bankCity},
+ bank_address = #{bankAddress},
+ id_card_front_url = #{idCardFrontUrl},
+ id_card_back_url = #{idCardBackUrl},
+ practice_cert_url = #{practiceCertUrl},
+ title_cert_url = #{titleCertUrl},
+ audit_opinion = #{auditOpinion},
+ audit_by = #{auditBy},
+ audit_time = #{auditTime},
+ status = #{status},
+
+ where user_id = #{userId}
+
+
+ insert into biz_expert
+
+ expert_id,
+ user_id,
+ name,
+ phone,
+ work_unit,
+ department,
+ title,
+ region,
+ id_card,
+ bank_card,
+ bank_name,
+ bank_province,
+ bank_city,
+ bank_address,
+ id_card_front_url,
+ id_card_back_url,
+ practice_cert_url,
+ title_cert_url,
+
+
+ #{expertId},
+ #{userId},
+ #{name},
+ #{phone},
+ #{workUnit},
+ #{department},
+ #{title},
+ #{region},
+ #{idCard},
+ #{bankCard},
+ #{bankName},
+ #{bankProvince},
+ #{bankCity},
+ #{bankAddress},
+ #{idCardFrontUrl},
+ #{idCardBackUrl},
+ #{practiceCertUrl},
+ #{titleCertUrl},
+
+
+
+ update biz_expert
+
+ user_id = #{userId},
+ work_unit = #{workUnit},
+ region = #{region},
+ id_card = #{idCard},
+ bank_card = #{bankCard},
+ bank_name = #{bankName},
+ bank_province = #{bankProvince},
+ bank_city = #{bankCity},
+ bank_address = #{bankAddress},
+ id_card_front_url = #{idCardFrontUrl},
+ id_card_back_url = #{idCardBackUrl},
+ practice_cert_url = #{practiceCertUrl},
+ title_cert_url = #{titleCertUrl},
+ audit_status = #{auditStatus},
+ audit_opinion = #{auditOpinion},
+ audit_by = #{auditBy},
+ audit_time = #{auditTime},
+ status = #{status},
+ name = #{name},
+ phone = #{phone},
+ department = #{department},
+ title = #{title},
+
+ where expert_id = #{expertId}
+
+
+ delete from biz_expert where expert_id = #{expertId}
+
+
+ delete from biz_expert where expert_id in
+
+ #{expertId}
+
+
+
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizInvitationMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizInvitationMapper.xml
new file mode 100644
index 0000000..adcc9e4
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizInvitationMapper.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+ select invite_id as ann_id, title from biz_invitation
+
+ where invite_id = #{annId}
+
+
+
+
+ title = #{title}
+ meeting_name = #{meetingName}
+ expert_name = #{expertName}
+ content = #{content}
+ create_by = #{createBy}
+ update_by = #{updateBy}
+
+ order by invite_id desc
+
+
+ insert into biz_invitation
+
+ ann_id,
+ title,
+
+
+ #{annId},
+ #{title},
+
+
+
+ update biz_invitation
+
+ project_id = #{projectId},
+ project_no = #{projectNo},
+ template_url = #{templateUrl},
+ qr_code_url = #{qrCodeUrl},
+ share_url = #{shareUrl},
+ publish_time = #{publishTime},
+ remark = #{remark},
+ title = #{title},
+
+ where invite_id = #{annId}
+
+
+ delete from biz_invitation where invite_id = #{annId}
+
+
+ delete from biz_invitation where invite_id in
+
+ #{annId}
+
+
+
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizLaborVoucherMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizLaborVoucherMapper.xml
new file mode 100644
index 0000000..98f6674
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizLaborVoucherMapper.xml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select voucher_id, voucher_no, meeting_name, expert_name, id_card, bank_account, amount, submit_date, audit_status, create_by, create_time, update_by, update_time
+ from biz_labor_voucher
+
+
+
+ where voucher_id = #{voucherId}
+
+
+
+
+ and amount = #{amount}
+
+ order by voucher_id desc
+
+
+ insert into biz_labor_voucher
+
+ voucher_id,
+ amount,
+
+
+ #{voucherId},
+ #{amount},
+
+
+
+ update biz_labor_voucher
+
+ voucher_no = #{voucherNo},
+ meeting_id = #{meetingId},
+ meeting_name = #{meetingName},
+ expert_name = #{expertName},
+ id_card = #{idCard},
+ bank_account = #{bankAccount},
+ submit_date = #{submitDate},
+ audit_status = #{auditStatus},
+ audit_opinion = #{auditOpinion},
+ audit_by = #{auditBy},
+ audit_time = #{auditTime},
+ amount = #{amount},
+
+ where voucher_id = #{voucherId}
+
+
+ delete from biz_labor_voucher where voucher_id = #{voucherId}
+
+
+ delete from biz_labor_voucher where voucher_id in
+
+ #{voucherId}
+
+
+
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizMeetingMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizMeetingMapper.xml
new file mode 100644
index 0000000..83c0ddc
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizMeetingMapper.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select meeting_id, project_no, business_id, project_form, meeting_name, start_time, end_time, total_periods, period_no, current_stage, create_by, create_time, update_by, update_time
+ from biz_meeting
+
+
+
+ where meeting_id = #{meetingId}
+
+
+
+
+
+ order by meeting_id desc
+
+
+ insert into biz_meeting
+
+ meeting_id,
+
+
+ #{meetingId},
+
+
+
+ update biz_meeting
+
+ business_id = #{businessId},
+ project_id = #{projectId},
+ project_no = #{projectNo},
+ project_name = #{projectName},
+ meeting_name = #{meetingName},
+ period_no = #{periodNo},
+ total_periods = #{totalPeriods},
+ project_form = #{projectForm},
+ start_time = #{startTime},
+ end_time = #{endTime},
+ org_name = #{orgName},
+ current_stage = #{currentStage},
+ supervision_opinion = #{supervisionOpinion},
+ supervision_by = #{supervisionBy},
+ supervision_time = #{supervisionTime},
+ invitation_url = #{invitationUrl},
+ schedule_url = #{scheduleUrl},
+ labor_signed = #{laborSigned},
+
+ where meeting_id = #{meetingId}
+
+
+ delete from biz_meeting where meeting_id = #{meetingId}
+
+
+ delete from biz_meeting where meeting_id in
+
+ #{meetingId}
+
+
+
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizMeetingSettlementMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizMeetingSettlementMapper.xml
new file mode 100644
index 0000000..754475a
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizMeetingSettlementMapper.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select id, project_no, meeting_id, fee_type, unit_price, qty, subtotal, remark, audit_status, settlement_type, create_by, create_time, update_by, update_time
+ from biz_meeting_settlement
+
+
+
+ where id = #{id}
+
+
+
+
+ and qty = #{qty}
+ and subtotal = #{subtotal}
+ and remark = #{remark}
+
+ order by id desc
+
+
+ insert into biz_meeting_settlement
+
+ id,
+ qty,
+ subtotal,
+ remark,
+
+
+ #{id},
+ #{qty},
+ #{subtotal},
+ #{remark},
+
+
+
+ update biz_meeting_settlement
+
+ meeting_id = #{meetingId},
+ project_no = #{projectNo},
+ project_name = #{projectName},
+ exec_unit = #{execUnit},
+ fee_type = #{feeType},
+ unit_price = #{unitPrice},
+ audit_status = #{auditStatus},
+ settlement_type = #{settlementType},
+ qty = #{qty},
+ subtotal = #{subtotal},
+ remark = #{remark},
+
+ where id = #{id}
+
+
+ delete from biz_meeting_settlement where id = #{id}
+
+
+ delete from biz_meeting_settlement where id in
+
+ #{id}
+
+
+
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizMessageMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizMessageMapper.xml
new file mode 100644
index 0000000..9001944
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizMessageMapper.xml
@@ -0,0 +1,131 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select m.msg_id, m.receiver_user_id, m.msg_type, m.title, m.content, m.biz_type, m.biz_id,
+ m.is_read, m.read_time, m.create_by, m.create_time, m.update_by, m.update_time,
+ u.user_name as receiver_name
+ from biz_message m
+ left join sys_user u on u.user_id = m.receiver_user_id
+
+
+
+
+ where m.msg_id = #{msgId}
+
+
+
+
+
+ and m.receiver_user_id = #{receiverUserId}
+ and m.msg_type = #{msgType}
+ and m.is_read = #{isRead}
+ and m.biz_type = #{bizType}
+ and m.title like concat('%', #{title}, '%')
+
+ order by m.msg_id desc
+
+
+
+
+
+ m.receiver_user_id = #{receiverUserId}
+
+ order by m.is_read asc, m.msg_id desc
+
+ limit #{params.limit}
+
+
+
+
+ insert into biz_message
+
+ msg_id,
+ receiver_user_id,
+ msg_type,
+ title,
+ content,
+ biz_type,
+ biz_id,
+ is_read,
+ read_time,
+ create_by,
+ create_time,
+ update_time,
+
+
+ #{msgId},
+ #{receiverUserId},
+ #{msgType},
+ #{title},
+ #{content},
+ #{bizType},
+ #{bizId},
+ #{isRead},
+ #{readTime},
+ #{createBy},
+ #{createTime},
+ sysdate(),
+
+
+
+
+ update biz_message
+
+ receiver_user_id = #{receiverUserId},
+ msg_type = #{msgType},
+ title = #{title},
+ content = #{content},
+ biz_type = #{bizType},
+ biz_id = #{bizId},
+ is_read = #{isRead},
+ read_time = #{readTime},
+ update_by = #{updateBy},
+ update_time = sysdate(),
+
+ where msg_id = #{msgId}
+
+
+
+ update biz_message
+ set is_read = '1', read_time = sysdate(), update_time = sysdate()
+ where msg_id = #{msgId}
+ and receiver_user_id = #{receiverUserId}
+ and is_read = '0'
+
+
+
+ update biz_message
+ set is_read = '1', read_time = sysdate(), update_time = sysdate()
+ where receiver_user_id = #{receiverUserId}
+ and is_read = '0'
+
+
+
+ delete from biz_message where msg_id = #{msgId}
+
+
+
+ delete from biz_message where msg_id in
+
+ #{msgId}
+
+
+
diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizOrgMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizOrgMapper.xml
new file mode 100644
index 0000000..c7487fb
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizOrgMapper.xml
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select org_id, org_name, org_type, business_nature, address, tax_no, status, create_time,
+ contact_name, contact_phone, intent_count,
+ create_by, update_by, update_time
+ from biz_org
+
+
+
+
+ where org_id = #{orgId}
+
+
+
+
+
+ and org_type = #{orgType}
+ and org_name like concat('%', #{orgName}, '%')
+ and tax_no = #{taxNo}
+ and status = #{status}
+
+ order by org_id desc
+
+
+
+ insert into biz_org
+
+ org_name,
+ org_type,
+ business_nature,
+ address,
+ tax_no,
+ contact_name,
+ contact_phone,
+ intent_count,
+ status,
+ create_by,
+ create_time,
+
+
+ #{orgName},
+ #{orgType},
+ #{businessNature},
+ #{address},
+ #{taxNo},
+ #{contactName},
+ #{contactPhone},
+ #{intentCount},
+ #{status},
+ #{createBy},
+ sysdate(),
+
+
+
+
+ update biz_org
+
+ org_name = #{orgName},
+ org_type = #{orgType},
+ business_nature = #{businessNature},
+ address = #{address},
+ tax_no = #{taxNo},
+ contact_name = #{contactName},
+ contact_phone = #{contactPhone},
+ intent_count = #{intentCount},
+ status = #{status},
+ update_by = #{updateBy},
+ update_time = sysdate(),
+
+ where org_id = #{orgId}
+
+
+
+ delete from biz_org where org_id in
+
+ #{orgId}
+
+
+
diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizPersonMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizPersonMapper.xml
new file mode 100644
index 0000000..e7dbe92
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizPersonMapper.xml
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select person_id, name, phone, org_id, department, position, role, unit_type, status, del_flag, user_id, create_by, create_time, update_by, update_time
+ from biz_person
+
+
+
+
+ select p.person_id, p.name, p.phone, p.org_id, o.org_name, o.org_type,
+ p.department, p.position, p.role, p.unit_type, p.status, p.del_flag, p.user_id,
+ p.create_by, p.create_time, p.update_by, p.update_time,
+ u.account_type, u.parent_user_id, u.del_flag as user_del_flag
+ from biz_person p
+ left join biz_org o on p.org_id = o.org_id
+ left join sys_user u on p.user_id = u.user_id
+
+
+
+
+ where p.person_id = #{personId}
+
+
+
+
+
+ p.del_flag = '0'
+ and p.unit_type = #{unitType}
+ and p.name = #{name}
+ and p.phone = #{phone}
+ and p.org_id = #{orgId}
+ and o.org_type = #{orgType}
+ and p.department = #{department}
+ and p.position = #{position}
+ and p.role = #{role}
+ and p.status = #{status}
+ and u.parent_user_id = #{parentUserId}
+
+ order by p.person_id desc
+
+
+
+ insert into biz_person
+
+ person_id,
+ name,
+ phone,
+ org_id,
+ department,
+ position,
+ role,
+ unit_type,
+ status,
+ user_id,
+ create_by,
+ create_time,
+ update_by,
+ update_time,
+
+
+ #{personId},
+ #{name},
+ #{phone},
+ #{orgId},
+ #{department},
+ #{position},
+ #{role},
+ #{unitType},
+ #{status},
+ #{userId},
+ #{createBy},
+ sysdate(),
+ #{updateBy},
+ sysdate(),
+
+
+
+
+ update biz_person
+
+ user_id = #{userId},
+ org_id = #{orgId},
+ unit_type = #{unitType},
+ name = #{name},
+ phone = #{phone},
+ department = #{department},
+ position = #{position},
+ role = #{role},
+ status = #{status},
+ update_by = #{updateBy},
+ update_time = sysdate(),
+
+ where person_id = #{personId}
+
+
+
+
+ update biz_person set del_flag='1', update_time=sysdate()
+ where person_id = #{personId} and del_flag='0'
+
+
+ update biz_person set del_flag='1', update_time=sysdate()
+ where del_flag='0' and person_id in
+
+ #{personId}
+
+
+
+
+
+ update sys_user u inner join biz_person p on u.user_id = p.user_id
+ set u.del_flag='1'
+ where u.del_flag='0' and p.del_flag='1' and p.person_id in
+
+ #{personId}
+
+
+
+
+
+
+
diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectAssignMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectAssignMapper.xml
new file mode 100644
index 0000000..2169a51
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectAssignMapper.xml
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select assign_id, project_id, exec_user_id, exec_user_name, exec_nick_name, exec_org,
+ sessions, amount, remark, status, create_by, create_time, update_by, update_time
+ from biz_project_assign
+
+
+
+
+ where assign_id = #{assignId}
+
+
+
+
+ where project_id = #{projectId} and status = '0'
+ order by assign_id asc
+
+
+
+
+
+ and project_id = #{projectId}
+ and exec_user_id = #{execUserId}
+ and status = #{status}
+
+ order by assign_id desc
+
+
+
+ insert into biz_project_assign
+
+ assign_id,
+ project_id,
+ exec_user_id,
+ exec_user_name,
+ exec_nick_name,
+ exec_org,
+ sessions,
+ amount,
+ remark,
+ status,
+ create_by,
+ create_time,
+
+
+ #{assignId},
+ #{projectId},
+ #{execUserId},
+ #{execUserName},
+ #{execNickName},
+ #{execOrg},
+ #{sessions},
+ #{amount},
+ #{remark},
+ #{status},
+ #{createBy},
+ sysdate(),
+
+
+
+
+ update biz_project_assign
+
+ exec_user_id = #{execUserId},
+ exec_user_name = #{execUserName},
+ exec_nick_name = #{execNickName},
+ exec_org = #{execOrg},
+ sessions = #{sessions},
+ amount = #{amount},
+ remark = #{remark},
+ status = #{status},
+ update_by = #{updateBy},
+ update_time = sysdate(),
+
+ where assign_id = #{assignId}
+
+
+
+ delete from biz_project_assign where assign_id = #{assignId}
+
+
+
+ delete from biz_project_assign where project_id = #{projectId}
+
+
diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectMapper.xml
new file mode 100644
index 0000000..af5e028
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectMapper.xml
@@ -0,0 +1,256 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select project_id, project_no, project_name, total_sessions, done_sessions, todo_sessions, total_amount, available_amount, paid_labor_amount, paid_meeting_amount, rating_score, rating_q1, rating_q2, rating_q3, rating_q4, org_name, org_type, project_form, is_finished, is_settled, org_id, create_by, create_time, update_by, update_time, manage_fee, start_time, end_time, submit_deadline_days, support_contract_url, execute_contract_url, invitation_url, support_letter_url, publish_url, notice_url, schedule_url, is_published, publish_time, announcement_type
+ from biz_project
+
+
+
+
+
+
+ where project_id = #{projectId}
+
+
+
+
+
+
+
+
+ and project_id in
+
+ #{id}
+
+
+
+ and project_no in
+
+ #{no}
+
+
+ and project_no like concat('%', #{projectNo}, '%')
+ and project_name like concat('%', #{projectName}, '%')
+ and project_form = #{projectForm}
+ and org_name like concat('%', #{orgName}, '%')
+ and org_type = #{orgType}
+ and is_finished = #{isFinished}
+ and is_settled = #{isSettled}
+ and is_published = #{isPublished}
+
+ order by project_id desc
+
+
+ insert into biz_project
+
+ project_id,
+ project_no,
+ project_name,
+ total_sessions,
+ done_sessions,
+ todo_sessions,
+ total_amount,
+ available_amount,
+ paid_labor_amount,
+ paid_meeting_amount,
+ rating_score,
+ rating_q1,
+ rating_q2,
+ rating_q3,
+ rating_q4,
+ org_name,
+ org_type,
+ project_form,
+ is_finished,
+ is_settled,
+ org_id,
+ create_by,
+ create_time,
+ update_by,
+ update_time,
+ manage_fee,
+ start_time,
+ end_time,
+ submit_deadline_days,
+ support_contract_url,
+ execute_contract_url,
+ invitation_url,
+ support_letter_url,
+ publish_url,
+ notice_url,
+ schedule_url,
+ is_published,
+ publish_time,
+ announcement_type,
+
+
+ #{projectId},
+ #{projectNo},
+ #{projectName},
+ #{totalSessions},
+ #{doneSessions},
+ #{todoSessions},
+ #{totalAmount},
+ #{availableAmount},
+ #{paidLaborAmount},
+ #{paidMeetingAmount},
+ #{ratingScore},
+ #{ratingQ1},
+ #{ratingQ2},
+ #{ratingQ3},
+ #{ratingQ4},
+ #{orgName},
+ #{orgType},
+ #{projectForm},
+ #{isFinished},
+ #{isSettled},
+ #{orgId},
+ #{createBy},
+ #{createTime},
+ #{updateBy},
+ #{updateTime},
+ #{manageFee},
+ #{startTime},
+ #{endTime},
+ #{submitDeadlineDays},
+ #{supportContractUrl},
+ #{executeContractUrl},
+ #{invitationUrl},
+ #{supportLetterUrl},
+ #{publishUrl},
+ #{noticeUrl},
+ #{scheduleUrl},
+ #{isPublished},
+ #{publishTime},
+ #{announcementType},
+
+
+
+ update biz_project
+
+ manage_fee = #{manageFee},
+ start_time = #{startTime},
+ end_time = #{endTime},
+ submit_deadline_days = #{submitDeadlineDays},
+ support_contract_url = #{supportContractUrl},
+ execute_contract_url = #{executeContractUrl},
+ invitation_url = #{invitationUrl},
+ support_letter_url = #{supportLetterUrl},
+ publish_url = #{publishUrl},
+ notice_url = #{noticeUrl},
+ schedule_url = #{scheduleUrl},
+ is_published = #{isPublished},
+ publish_time = #{publishTime},
+ announcement_type = #{announcementType},
+ project_no = #{projectNo},
+ project_name = #{projectName},
+ total_sessions = #{totalSessions},
+ done_sessions = #{doneSessions},
+ todo_sessions = #{todoSessions},
+ total_amount = #{totalAmount},
+ available_amount = #{availableAmount},
+ paid_labor_amount = #{paidLaborAmount},
+ paid_meeting_amount = #{paidMeetingAmount},
+ rating_score = #{ratingScore},
+ rating_q1 = #{ratingQ1},
+ rating_q2 = #{ratingQ2},
+ rating_q3 = #{ratingQ3},
+ rating_q4 = #{ratingQ4},
+ org_name = #{orgName},
+ org_type = #{orgType},
+ project_form = #{projectForm},
+ is_finished = #{isFinished},
+ is_settled = #{isSettled},
+ org_id = #{orgId},
+ create_by = #{createBy},
+ create_time = #{createTime},
+ update_by = #{updateBy},
+ update_time = #{updateTime},
+
+ where project_id = #{projectId}
+
+
+ delete from biz_project where project_id = #{projectId}
+
+
+ delete from biz_project where project_id in
+
+ #{projectId}
+
+
+
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectPlanMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectPlanMapper.xml
new file mode 100644
index 0000000..5a9fc66
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectPlanMapper.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select plan_id, plan_name, plan_direction, plan_category, project_form, design_file_url, status, is_settled, project_no, remark, create_by, create_time, update_by, update_time
+ from biz_project_plan
+
+
+
+ where plan_id = #{planId}
+
+
+
+
+ and status = #{status}
+ and remark = #{remark}
+
+ order by plan_id desc
+
+
+ insert into biz_project_plan
+
+ plan_id,
+ status,
+ remark,
+
+
+ #{planId},
+ #{status},
+ #{remark},
+
+
+
+ update biz_project_plan
+
+ plan_name = #{planName},
+ plan_direction = #{planDirection},
+ plan_category = #{planCategory},
+ project_form = #{projectForm},
+ design_file_url = #{designFileUrl},
+ is_settled = #{isSettled},
+ project_no = #{projectNo},
+ audit_opinion = #{auditOpinion},
+ audit_by = #{auditBy},
+ audit_time = #{auditTime},
+ status = #{status},
+ remark = #{remark},
+
+ where plan_id = #{planId}
+
+
+ delete from biz_project_plan where plan_id = #{planId}
+
+
+ delete from biz_project_plan where plan_id in
+
+ #{planId}
+
+
+
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectRatingMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectRatingMapper.xml
new file mode 100644
index 0000000..7b54150
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectRatingMapper.xml
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select rating_id, project_no, project_name, rater_name, rater_role, quality_score, response_score, cooperation_score, compliance_score, total_score, remark, create_by, create_time, update_by, update_time
+ from biz_project_rating
+
+
+
+ where rating_id = #{ratingId}
+
+
+
+
+ and remark = #{remark}
+
+ order by rating_id desc
+
+
+ insert into biz_project_rating
+
+ rating_id,
+ remark,
+
+
+ #{ratingId},
+ #{remark},
+
+
+
+ update biz_project_rating
+
+ project_id = #{projectId},
+ project_no = #{projectNo},
+ project_name = #{projectName},
+ rater_id = #{raterId},
+ rater_name = #{raterName},
+ rater_role = #{raterRole},
+ quality_score = #{qualityScore},
+ response_score = #{responseScore},
+ cooperation_score = #{cooperationScore},
+ compliance_score = #{complianceScore},
+ total_score = #{totalScore},
+ rating_time = #{ratingTime},
+ remark = #{remark},
+
+ where rating_id = #{ratingId}
+
+
+ delete from biz_project_rating where rating_id = #{ratingId}
+
+
+ delete from biz_project_rating where rating_id in
+
+ #{ratingId}
+
+
+
+
+
+ INSERT INTO biz_project_rating
+ (project_id, project_no, project_name, rater_id, rater_name, rater_role,
+ quality_score, response_score, cooperation_score, compliance_score, total_score,
+ remark, create_by, create_time, update_by, update_time)
+ VALUES
+ (#{projectId}, #{projectNo}, #{projectName}, #{raterId}, #{raterName}, #{raterRole},
+ #{qualityScore}, #{responseScore}, #{cooperationScore}, #{complianceScore}, #{totalScore},
+ #{remark}, #{createBy}, sysdate(), #{updateBy}, sysdate())
+ ON DUPLICATE KEY UPDATE
+ project_no = VALUES(project_no),
+ project_name = VALUES(project_name),
+ rater_name = VALUES(rater_name),
+ quality_score = VALUES(quality_score),
+ response_score = VALUES(response_score),
+ cooperation_score= VALUES(cooperation_score),
+ compliance_score = VALUES(compliance_score),
+ total_score = VALUES(total_score),
+ remark = VALUES(remark),
+ update_by = VALUES(update_by),
+ update_time = sysdate()
+
+
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectSponsorAssignMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectSponsorAssignMapper.xml
new file mode 100644
index 0000000..7f37a31
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizProjectSponsorAssignMapper.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO biz_project_sponsor_assign
+ (project_id, sponsor_user_id, monitor_user_id, assign_desc, assign_points, create_by, create_time)
+ VALUES
+ (#{projectId}, #{sponsorUserId}, #{monitorUserId}, #{assignDesc}, #{assignPoints}, #{createBy}, sysdate())
+
+
+
+
+ delete from biz_project_sponsor_assign where project_id = #{projectId}
+
+
+
+ SELECT a.*,
+ s.user_name AS sponsor_user_name,
+ m.user_name AS monitor_user_name
+ FROM biz_project_sponsor_assign a
+ LEFT JOIN sys_user s ON a.sponsor_user_id = s.user_id
+ LEFT JOIN sys_user m ON a.monitor_user_id = m.user_id
+ WHERE a.project_id = #{projectId}
+ ORDER BY a.create_time DESC
+
+
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizPublicityMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizPublicityMapper.xml
new file mode 100644
index 0000000..d7e936d
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizPublicityMapper.xml
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select id, project_id, project_no, project_name, announce_type, title, file_url, remark, status, rating_time, create_by, create_time, update_by, update_time
+ from biz_publicity
+
+
+
+
+ where id = #{id}
+
+
+
+
+
+ and project_id = #{projectId}
+ and announce_type = #{announceType}
+ and title like concat('%', #{title}, '%')
+
+ order by create_time desc
+
+
+
+
+ where project_id = #{projectId}
+ order by create_time desc
+
+
+
+ insert into biz_publicity
+
+ project_id,
+ project_no,
+ project_name,
+ announce_type,
+ title,
+ file_url,
+ remark,
+ status,
+ rating_time,
+ create_by,
+ create_time,
+ update_by,
+ update_time,
+
+
+ #{projectId},
+ #{projectNo},
+ #{projectName},
+ #{announceType},
+ #{title},
+ #{fileUrl},
+ #{remark},
+ #{status},
+ #{ratingTime},
+ #{createBy},
+ sysdate(),
+ #{updateBy},
+ sysdate(),
+
+
+
+
+ update biz_publicity
+
+ project_id = #{projectId},
+ project_no = #{projectNo},
+ project_name = #{projectName},
+ announce_type = #{announceType},
+ title = #{title},
+ file_url = #{fileUrl},
+ remark = #{remark},
+ status = #{status},
+ rating_time = #{ratingTime},
+ update_by = #{updateBy},
+ update_time = sysdate(),
+
+ where id = #{id}
+
+
+
+ delete from biz_publicity where id = #{id}
+
+
+
+ delete from biz_publicity where id in
+
+ #{id}
+
+
+
diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizResourceMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizResourceMapper.xml
new file mode 100644
index 0000000..73e22cd
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizResourceMapper.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select resource_id, name, category, file_size, uploader_name, upload_time, status, create_by, create_time, update_by, update_time
+ from biz_resource
+
+
+
+ where resource_id = #{resourceId}
+
+
+
+
+ and name = #{name}
+ and category = #{category}
+ and status = #{status}
+
+ order by resource_id desc
+
+
+ insert into biz_resource
+
+ resource_id,
+ name,
+ category,
+ status,
+
+
+ #{resourceId},
+ #{name},
+ #{category},
+ #{status},
+
+
+
+ update biz_resource
+
+ name = #{name},
+ category = #{category},
+ status = #{status},
+
+ where resource_id = #{resourceId}
+
+
+ delete from biz_resource where resource_id = #{resourceId}
+
+
+ delete from biz_resource where resource_id in
+
+ #{resourceId}
+
+
+
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizSubmissionMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizSubmissionMapper.xml
new file mode 100644
index 0000000..0db7bbb
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizSubmissionMapper.xml
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select sub_id, title, direction, project_form, project_category, design_file_url, submitter_id, submitter_name, status, remark, create_by, create_time, update_by, update_time
+ from biz_submission
+
+
+
+ where sub_id = #{subId}
+
+
+
+
+ and submitter_id = #{submitterId}
+ and title = #{title}
+ and direction = #{direction}
+ and status = #{status}
+ and remark = #{remark}
+
+ order by sub_id desc
+
+
+ insert into biz_submission
+
+ sub_id,
+ title,
+ direction,
+ project_form,
+ project_category,
+ design_file_url,
+ submitter_id,
+ submitter_name,
+ status,
+ remark,
+ create_by,
+ create_time,
+ update_by,
+ update_time,
+
+
+ #{subId},
+ #{title},
+ #{direction},
+ #{projectForm},
+ #{projectCategory},
+ #{designFileUrl},
+ #{submitterId},
+ #{submitterName},
+ #{status},
+ #{remark},
+ #{createBy},
+ sysdate(),
+ #{updateBy},
+ sysdate(),
+
+
+
+ update biz_submission
+
+ submitter_id = #{submitterId},
+ submitter_name = #{submitterName},
+ project_form = #{projectForm},
+ project_category = #{projectCategory},
+ design_file_url = #{designFileUrl},
+ audit_opinion = #{auditOpinion},
+ audit_by = #{auditBy},
+ audit_time = #{auditTime},
+ title = #{title},
+ direction = #{direction},
+ status = #{status},
+ remark = #{remark},
+ update_by = #{updateBy},
+ update_time = sysdate(),
+
+ where sub_id = #{subId}
+
+
+ delete from biz_submission where sub_id = #{subId}
+
+
+ delete from biz_submission where sub_id in
+
+ #{subId}
+
+
+
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizSupportIntentMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizSupportIntentMapper.xml
new file mode 100644
index 0000000..dad35db
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizSupportIntentMapper.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select intent_id, project_no, project_name, name, work_unit, department, position, phone, account_status, create_by, create_time, update_by, update_time
+ from biz_support_intent
+
+
+
+ where intent_id = #{intentId}
+
+
+
+
+ and name = #{name}
+ and department = #{department}
+ and position = #{position}
+ and phone = #{phone}
+
+ order by intent_id desc
+
+
+ insert into biz_support_intent
+
+ intent_id,
+ name,
+ department,
+ position,
+ phone,
+
+
+ #{intentId},
+ #{name},
+ #{department},
+ #{position},
+ #{phone},
+
+
+
+ update biz_support_intent
+
+ project_no = #{projectNo},
+ project_name = #{projectName},
+ work_unit = #{workUnit},
+ account_status = #{accountStatus},
+ name = #{name},
+ department = #{department},
+ position = #{position},
+ phone = #{phone},
+
+ where intent_id = #{intentId}
+
+
+ delete from biz_support_intent where intent_id = #{intentId}
+
+
+ delete from biz_support_intent where intent_id in
+
+ #{intentId}
+
+
+
\ No newline at end of file
diff --git a/ry-api/ruoyi-business/src/main/resources/mapper/business/BizSupportLetterMapper.xml b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizSupportLetterMapper.xml
new file mode 100644
index 0000000..b011f85
--- /dev/null
+++ b/ry-api/ruoyi-business/src/main/resources/mapper/business/BizSupportLetterMapper.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+ select letter_id as ann_id, title from biz_support_letter
+
+ where letter_id = #{annId}
+
+
+
+
+ title = #{title}
+ content = #{content}
+ unit_name = #{unitName}
+ create_by = #{createBy}
+ update_by = #{updateBy}
+
+ order by ann_id desc
+
+
+ insert into biz_support_letter
+
+ ann_id,
+ title,
+
+
+ #{annId},
+ #{title},
+
+
+
+ update biz_support_letter
+
+ project_id = #{projectId},
+ project_no = #{projectNo},
+ file_url = #{fileUrl},
+ publish_time = #{publishTime},
+ support_count = #{supportCount},
+ title = #{title},
+
+ where letter_id = #{annId}
+
+
+ delete from biz_support_letter where letter_id = #{annId}
+
+
+ delete from biz_support_letter where letter_id in
+
+ #{annId}
+
+
+
\ No newline at end of file
diff --git a/ry-api/ruoyi-common/pom.xml b/ry-api/ruoyi-common/pom.xml
new file mode 100644
index 0000000..d67fa45
--- /dev/null
+++ b/ry-api/ruoyi-common/pom.xml
@@ -0,0 +1,123 @@
+
+
+
+ ruoyi
+ com.ruoyi
+ 3.9.2
+
+ 4.0.0
+
+ ruoyi-common
+
+
+ common通用工具
+
+
+
+
+
+
+ org.springframework
+ spring-context-support
+
+
+
+
+ org.springframework
+ spring-web
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+
+ com.github.pagehelper
+ pagehelper-spring-boot-starter
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+
+ tools.jackson.core
+ jackson-databind
+
+
+
+
+ com.alibaba.fastjson2
+ fastjson2
+
+
+
+
+ commons-io
+ commons-io
+
+
+
+
+ org.apache.poi
+ poi-ooxml
+
+
+
+
+ io.jsonwebtoken
+ jjwt
+
+
+
+
+ javax.xml.bind
+ jaxb-api
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+
+ org.springframework.boot
+ spring-boot-starter-cache
+
+
+
+
+ org.apache.commons
+ commons-pool2
+
+
+
+
+ nl.basjes.parse.useragent
+ yauaa
+
+
+
+
+ jakarta.servlet
+ jakarta.servlet-api
+
+
+
+
+
\ No newline at end of file
diff --git a/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Anonymous.java b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Anonymous.java
new file mode 100644
index 0000000..1d6d4f4
--- /dev/null
+++ b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Anonymous.java
@@ -0,0 +1,19 @@
+package com.ruoyi.common.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 匿名访问不鉴权注解
+ *
+ * @author ruoyi
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Anonymous
+{
+}
diff --git a/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScope.java b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScope.java
new file mode 100644
index 0000000..36163ae
--- /dev/null
+++ b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScope.java
@@ -0,0 +1,43 @@
+package com.ruoyi.common.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 数据权限过滤注解
+ *
+ * @author ruoyi
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface DataScope
+{
+ /**
+ * 用户表的别名
+ */
+ public String userAlias() default "";
+
+ /**
+ * 部门表的别名
+ */
+ public String deptAlias() default "";
+
+ /**
+ * 用户字段名
+ */
+ public String userField() default "user_id";
+
+ /**
+ * 部门字段名
+ */
+ public String deptField() default "dept_id";
+
+ /**
+ * 权限字符(用于多个角色匹配符合要求的权限)默认根据权限注解@ss获取,多个权限用逗号分隔开来
+ */
+ public String permission() default "";
+}
diff --git a/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java
new file mode 100644
index 0000000..79cd191
--- /dev/null
+++ b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java
@@ -0,0 +1,28 @@
+package com.ruoyi.common.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import com.ruoyi.common.enums.DataSourceType;
+
+/**
+ * 自定义多数据源切换注解
+ *
+ * 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准
+ *
+ * @author ruoyi
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+public @interface DataSource
+{
+ /**
+ * 切换数据源名称
+ */
+ public DataSourceType value() default DataSourceType.MASTER;
+}
diff --git a/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java
new file mode 100644
index 0000000..57c08b1
--- /dev/null
+++ b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java
@@ -0,0 +1,198 @@
+package com.ruoyi.common.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.math.BigDecimal;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import com.ruoyi.common.utils.poi.ExcelHandlerAdapter;
+
+/**
+ * 自定义导出Excel数据注解
+ *
+ * @author ruoyi
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Excel
+{
+ /**
+ * 导出时在excel中排序
+ */
+ public int sort() default Integer.MAX_VALUE;
+
+ /**
+ * 导出到Excel中的名字.
+ */
+ public String name() default "";
+
+ /**
+ * 日期格式, 如: yyyy-MM-dd
+ */
+ public String dateFormat() default "";
+
+ /**
+ * 如果是字典类型,请设置字典的type值 (如: sys_user_sex)
+ */
+ public String dictType() default "";
+
+ /**
+ * 读取内容转表达式 (如: 0=男,1=女,2=未知)
+ */
+ public String readConverterExp() default "";
+
+ /**
+ * 分隔符,读取字符串组内容
+ */
+ public String separator() default ",";
+
+ /**
+ * BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化)
+ */
+ public int scale() default -1;
+
+ /**
+ * BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN
+ */
+ @SuppressWarnings("deprecation")
+ public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
+
+ /**
+ * 导出时在excel中每个列的高度
+ */
+ public double height() default 14;
+
+ /**
+ * 导出时在excel中每个列的宽度
+ */
+ public double width() default 16;
+
+ /**
+ * 文字后缀,如% 90 变成90%
+ */
+ public String suffix() default "";
+
+ /**
+ * 当值为空时,字段的默认值
+ */
+ public String defaultValue() default "";
+
+ /**
+ * 提示信息
+ */
+ public String prompt() default "";
+
+ /**
+ * 是否允许内容换行
+ */
+ public boolean wrapText() default false;
+
+ /**
+ * 设置只能选择不能输入的列内容.
+ */
+ public String[] combo() default {};
+
+ /**
+ * 是否从字典读数据到combo,默认不读取,如读取需要设置dictType注解.
+ */
+ public boolean comboReadDict() default false;
+
+ /**
+ * 是否需要纵向合并单元格,应对需求:含有list集合单元格)
+ */
+ public boolean needMerge() default false;
+
+ /**
+ * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
+ */
+ public boolean isExport() default true;
+
+ /**
+ * 另一个类中的属性名称,支持多级获取,以小数点隔开
+ */
+ public String targetAttr() default "";
+
+ /**
+ * 是否自动统计数据,在最后追加一行统计数据总和
+ */
+ public boolean isStatistics() default false;
+
+ /**
+ * 导出类型(0数字 1字符串 2图片)
+ */
+ public ColumnType cellType() default ColumnType.STRING;
+
+ /**
+ * 导出列头背景颜色
+ */
+ public IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT;
+
+ /**
+ * 导出列头字体颜色
+ */
+ public IndexedColors headerColor() default IndexedColors.WHITE;
+
+ /**
+ * 导出单元格背景颜色
+ */
+ public IndexedColors backgroundColor() default IndexedColors.WHITE;
+
+ /**
+ * 导出单元格字体颜色
+ */
+ public IndexedColors color() default IndexedColors.BLACK;
+
+ /**
+ * 导出字段对齐方式
+ */
+ public HorizontalAlignment align() default HorizontalAlignment.CENTER;
+
+ /**
+ * 自定义数据处理器
+ */
+ public Class> handler() default ExcelHandlerAdapter.class;
+
+ /**
+ * 自定义数据处理器参数
+ */
+ public String[] args() default {};
+
+ /**
+ * 字段类型(0:导出导入;1:仅导出;2:仅导入)
+ */
+ Type type() default Type.ALL;
+
+ public enum Type
+ {
+ ALL(0), EXPORT(1), IMPORT(2);
+ private final int value;
+
+ Type(int value)
+ {
+ this.value = value;
+ }
+
+ public int value()
+ {
+ return this.value;
+ }
+ }
+
+ public enum ColumnType
+ {
+ NUMERIC(0), STRING(1), IMAGE(2), TEXT(3);
+ private final int value;
+
+ ColumnType(int value)
+ {
+ this.value = value;
+ }
+
+ public int value()
+ {
+ return this.value;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excels.java b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excels.java
new file mode 100644
index 0000000..1f1cc81
--- /dev/null
+++ b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excels.java
@@ -0,0 +1,18 @@
+package com.ruoyi.common.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Excel注解集
+ *
+ * @author ruoyi
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Excels
+{
+ public Excel[] value();
+}
diff --git a/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java
new file mode 100644
index 0000000..1eb8e49
--- /dev/null
+++ b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java
@@ -0,0 +1,51 @@
+package com.ruoyi.common.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.enums.OperatorType;
+
+/**
+ * 自定义操作日志记录注解
+ *
+ * @author ruoyi
+ *
+ */
+@Target({ ElementType.PARAMETER, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Log
+{
+ /**
+ * 模块
+ */
+ public String title() default "";
+
+ /**
+ * 功能
+ */
+ public BusinessType businessType() default BusinessType.OTHER;
+
+ /**
+ * 操作人类别
+ */
+ public OperatorType operatorType() default OperatorType.MANAGE;
+
+ /**
+ * 是否保存请求的参数
+ */
+ public boolean isSaveRequestData() default true;
+
+ /**
+ * 是否保存响应的参数
+ */
+ public boolean isSaveResponseData() default true;
+
+ /**
+ * 排除指定的请求参数
+ */
+ public String[] excludeParamNames() default {};
+}
diff --git a/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java
new file mode 100644
index 0000000..0f024c7
--- /dev/null
+++ b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java
@@ -0,0 +1,40 @@
+package com.ruoyi.common.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import com.ruoyi.common.constant.CacheConstants;
+import com.ruoyi.common.enums.LimitType;
+
+/**
+ * 限流注解
+ *
+ * @author ruoyi
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RateLimiter
+{
+ /**
+ * 限流key
+ */
+ public String key() default CacheConstants.RATE_LIMIT_KEY;
+
+ /**
+ * 限流时间,单位秒
+ */
+ public int time() default 60;
+
+ /**
+ * 限流次数
+ */
+ public int count() default 100;
+
+ /**
+ * 限流类型
+ */
+ public LimitType limitType() default LimitType.DEFAULT;
+}
diff --git a/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java
new file mode 100644
index 0000000..b769748
--- /dev/null
+++ b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java
@@ -0,0 +1,31 @@
+package com.ruoyi.common.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 自定义注解防止表单重复提交
+ *
+ * @author ruoyi
+ *
+ */
+@Inherited
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RepeatSubmit
+{
+ /**
+ * 间隔时间(ms),小于此时间视为重复提交
+ */
+ public int interval() default 5000;
+
+ /**
+ * 提示消息
+ */
+ public String message() default "不允许重复提交,请稍候再试";
+}
diff --git a/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Sensitive.java b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Sensitive.java
new file mode 100644
index 0000000..b33c961
--- /dev/null
+++ b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Sensitive.java
@@ -0,0 +1,24 @@
+package com.ruoyi.common.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
+import tools.jackson.databind.annotation.JsonSerialize;
+import com.ruoyi.common.config.serializer.SensitiveJsonSerializer;
+import com.ruoyi.common.enums.DesensitizedType;
+
+/**
+ * 数据脱敏注解
+ *
+ * @author ruoyi
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.FIELD, ElementType.METHOD })
+@JacksonAnnotationsInside
+@JsonSerialize(using = SensitiveJsonSerializer.class)
+public @interface Sensitive
+{
+ DesensitizedType desensitizedType();
+}
diff --git a/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java
new file mode 100644
index 0000000..260c945
--- /dev/null
+++ b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java
@@ -0,0 +1,164 @@
+package com.ruoyi.common.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 读取项目相关配置
+ *
+ * @author ruoyi
+ */
+@Component
+@ConfigurationProperties(prefix = "ruoyi")
+public class RuoYiConfig
+{
+ /** 项目名称 */
+ private String name;
+
+ /** 版本 */
+ private String version;
+
+ /** 版权年份 */
+ private String copyrightYear;
+
+ /** 上传路径 */
+ private static String profile;
+
+ /** 获取地址开关 */
+ private static boolean addressEnabled;
+
+ /** 验证码类型 */
+ private static String captchaType;
+
+ /** OSS 配置 (可选) */
+ private OssProperties oss = new OssProperties();
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ public String getVersion()
+ {
+ return version;
+ }
+
+ public void setVersion(String version)
+ {
+ this.version = version;
+ }
+
+ public String getCopyrightYear()
+ {
+ return copyrightYear;
+ }
+
+ public void setCopyrightYear(String copyrightYear)
+ {
+ this.copyrightYear = copyrightYear;
+ }
+
+ public static String getProfile()
+ {
+ return profile;
+ }
+
+ public void setProfile(String profile)
+ {
+ RuoYiConfig.profile = profile;
+ }
+
+ public static boolean isAddressEnabled()
+ {
+ return addressEnabled;
+ }
+
+ public void setAddressEnabled(boolean addressEnabled)
+ {
+ RuoYiConfig.addressEnabled = addressEnabled;
+ }
+
+ public static String getCaptchaType() {
+ return captchaType;
+ }
+
+ public void setCaptchaType(String captchaType) {
+ RuoYiConfig.captchaType = captchaType;
+ }
+
+ /**
+ * 获取导入上传路径
+ */
+ public static String getImportPath()
+ {
+ return getProfile() + "/import";
+ }
+
+ /**
+ * 获取头像上传路径
+ */
+ public static String getAvatarPath()
+ {
+ return getProfile() + "/avatar";
+ }
+
+ /**
+ * 获取下载路径
+ */
+ public static String getDownloadPath()
+ {
+ return getProfile() + "/download/";
+ }
+
+ /**
+ * 获取上传路径
+ */
+ public static String getUploadPath()
+ {
+ return getProfile() + "/upload";
+ }
+
+ public OssProperties getOss()
+ {
+ return oss;
+ }
+
+ public void setOss(OssProperties oss)
+ {
+ this.oss = oss;
+ }
+
+ /**
+ * OSS 配置 (前端直传签名用)
+ */
+ public static class OssProperties
+ {
+ private boolean enabled;
+ private String endpoint;
+ private String bucket;
+ private String accessKeyId;
+ private String accessKeySecret;
+ private String dirPrefix = "ry8080/";
+ private int expireSeconds = 3600;
+
+ public boolean isEnabled() { return enabled; }
+ public void setEnabled(boolean enabled) { this.enabled = enabled; }
+ public String getEndpoint() { return endpoint; }
+ public void setEndpoint(String endpoint) { this.endpoint = endpoint; }
+ public String getBucket() { return bucket; }
+ public void setBucket(String bucket) { this.bucket = bucket; }
+ public String getAccessKeyId() { return accessKeyId; }
+ public void setAccessKeyId(String accessKeyId) { this.accessKeyId = accessKeyId; }
+ public String getAccessKeySecret() { return accessKeySecret; }
+ public void setAccessKeySecret(String accessKeySecret) { this.accessKeySecret = accessKeySecret; }
+ public String getDirPrefix() { return dirPrefix; }
+ public void setDirPrefix(String dirPrefix) { this.dirPrefix = dirPrefix; }
+ public int getExpireSeconds() { return expireSeconds; }
+ public void setExpireSeconds(int expireSeconds) { this.expireSeconds = expireSeconds; }
+ }
+}
\ No newline at end of file
diff --git a/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/config/serializer/SensitiveJsonSerializer.java b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/config/serializer/SensitiveJsonSerializer.java
new file mode 100644
index 0000000..df676da
--- /dev/null
+++ b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/config/serializer/SensitiveJsonSerializer.java
@@ -0,0 +1,77 @@
+package com.ruoyi.common.config.serializer;
+
+import java.util.Objects;
+import tools.jackson.core.JacksonException;
+import tools.jackson.core.JsonGenerator;
+import tools.jackson.databind.BeanProperty;
+import tools.jackson.databind.DatabindException;
+import tools.jackson.databind.SerializationContext;
+import tools.jackson.databind.ValueSerializer;
+import tools.jackson.databind.ser.std.StdSerializer;
+import com.ruoyi.common.annotation.Sensitive;
+import com.ruoyi.common.core.domain.model.LoginUser;
+import com.ruoyi.common.enums.DesensitizedType;
+import com.ruoyi.common.utils.SecurityUtils;
+
+/**
+ * 数据脱敏序列化过滤
+ *
+ * @author ruoyi
+ */
+public class SensitiveJsonSerializer extends StdSerializer
+{
+ private final DesensitizedType desensitizedType;
+
+ public SensitiveJsonSerializer()
+ {
+ super(String.class);
+ this.desensitizedType = null;
+ }
+
+ public SensitiveJsonSerializer(DesensitizedType desensitizedType)
+ {
+ super(String.class);
+ this.desensitizedType = desensitizedType;
+ }
+
+ @Override
+ public void serialize(String value, JsonGenerator gen, SerializationContext ctxt) throws JacksonException
+ {
+ if (desensitizedType != null && desensitization())
+ {
+ gen.writeString(desensitizedType.desensitizer().apply(value));
+ }
+ else
+ {
+ gen.writeString(value);
+ }
+ }
+
+ @Override
+ public ValueSerializer> createContextual(SerializationContext ctxt, BeanProperty property) throws DatabindException
+ {
+ Sensitive annotation = property.getAnnotation(Sensitive.class);
+ if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass()))
+ {
+ return new SensitiveJsonSerializer(annotation.desensitizedType());
+ }
+ return ctxt.findValueSerializer(property.getType());
+ }
+
+ /**
+ * 是否需要脱敏处理
+ */
+ private boolean desensitization()
+ {
+ try
+ {
+ LoginUser securityUser = SecurityUtils.getLoginUser();
+ // 管理员不脱敏
+ return !securityUser.getUser().isAdmin();
+ }
+ catch (Exception e)
+ {
+ return true;
+ }
+ }
+}
diff --git a/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java
new file mode 100644
index 0000000..0080343
--- /dev/null
+++ b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java
@@ -0,0 +1,44 @@
+package com.ruoyi.common.constant;
+
+/**
+ * 缓存的key 常量
+ *
+ * @author ruoyi
+ */
+public class CacheConstants
+{
+ /**
+ * 登录用户 redis key
+ */
+ public static final String LOGIN_TOKEN_KEY = "login_tokens:";
+
+ /**
+ * 验证码 redis key
+ */
+ public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
+
+ /**
+ * 参数管理 cache key
+ */
+ public static final String SYS_CONFIG_KEY = "sys_config:";
+
+ /**
+ * 字典管理 cache key
+ */
+ public static final String SYS_DICT_KEY = "sys_dict:";
+
+ /**
+ * 防重提交 redis key
+ */
+ public static final String REPEAT_SUBMIT_KEY = "repeat_submit:";
+
+ /**
+ * 限流 redis key
+ */
+ public static final String RATE_LIMIT_KEY = "rate_limit:";
+
+ /**
+ * 登录账户密码错误次数 redis key
+ */
+ public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
+}
diff --git a/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
new file mode 100644
index 0000000..51d7f56
--- /dev/null
+++ b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
@@ -0,0 +1,204 @@
+package com.ruoyi.common.constant;
+
+import java.util.Locale;
+import io.jsonwebtoken.Claims;
+
+/**
+ * 通用常量信息
+ *
+ * @author ruoyi
+ */
+public class Constants
+{
+ /**
+ * UTF-8 字符集
+ */
+ public static final String UTF8 = "UTF-8";
+
+ /**
+ * GBK 字符集
+ */
+ public static final String GBK = "GBK";
+
+ /**
+ * 系统语言
+ */
+ public static final Locale DEFAULT_LOCALE = Locale.SIMPLIFIED_CHINESE;
+
+ /**
+ * www主域
+ */
+ public static final String WWW = "www.";
+
+ /**
+ * http请求
+ */
+ public static final String HTTP = "http://";
+
+ /**
+ * https请求
+ */
+ public static final String HTTPS = "https://";
+
+ /**
+ * 通用成功标识
+ */
+ public static final String SUCCESS = "0";
+
+ /**
+ * 通用失败标识
+ */
+ public static final String FAIL = "1";
+
+ /**
+ * 登录成功
+ */
+ public static final String LOGIN_SUCCESS = "Success";
+
+ /**
+ * 注销
+ */
+ public static final String LOGOUT = "Logout";
+
+ /**
+ * 注册
+ */
+ public static final String REGISTER = "Register";
+
+ /**
+ * 登录失败
+ */
+ public static final String LOGIN_FAIL = "Error";
+
+ /**
+ * 所有权限标识
+ */
+ public static final String ALL_PERMISSION = "*:*:*";
+
+ /**
+ * 管理员角色权限标识
+ */
+ public static final String SUPER_ADMIN = "admin";
+
+ /**
+ * 角色权限分隔符
+ */
+ public static final String ROLE_DELIMITER = ",";
+
+ /**
+ * 权限标识分隔符
+ */
+ public static final String PERMISSION_DELIMITER = ",";
+
+ /**
+ * 验证码有效期(分钟)
+ */
+ public static final Integer CAPTCHA_EXPIRATION = 2;
+
+ /**
+ * 令牌
+ */
+ public static final String TOKEN = "token";
+
+ /**
+ * 令牌前缀
+ */
+ public static final String TOKEN_PREFIX = "Bearer ";
+
+ /**
+ * 令牌前缀
+ */
+ public static final String LOGIN_USER_KEY = "login_user_key";
+
+ /**
+ * 用户ID
+ */
+ public static final String JWT_USERID = "userid";
+
+ /**
+ * 用户名称
+ */
+ public static final String JWT_USERNAME = Claims.SUBJECT;
+
+ /**
+ * 用户头像
+ */
+ public static final String JWT_AVATAR = "avatar";
+
+ /**
+ * 创建时间
+ */
+ public static final String JWT_CREATED = "created";
+
+ /**
+ * 用户权限
+ */
+ public static final String JWT_AUTHORITIES = "authorities";
+
+ /**
+ * 资源映射路径 前缀
+ */
+ public static final String RESOURCE_PREFIX = "/profile";
+
+ /**
+ * RMI 远程方法调用
+ */
+ public static final String LOOKUP_RMI = "rmi:";
+
+ /**
+ * LDAP 远程方法调用
+ */
+ public static final String LOOKUP_LDAP = "ldap:";
+
+ /**
+ * LDAPS 远程方法调用
+ */
+ public static final String LOOKUP_LDAPS = "ldaps:";
+
+ /**
+ * 自动识别json对象白名单配置(仅允许解析的包名,范围越小越安全)
+ */
+ public static final String[] JSON_WHITELIST_STR = { "com.ruoyi" };
+
+ /**
+ * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
+ */
+ public static final String[] JOB_WHITELIST_STR = { "com.ruoyi.quartz.task" };
+
+ /**
+ * 定时任务违规的字符
+ */
+ public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
+ "org.springframework", "org.apache", "com.ruoyi.common.utils.file", "com.ruoyi.common.config", "com.ruoyi.generator" };
+
+ /**
+ * 部门相关常量
+ */
+ public static class Dept
+ {
+ /**
+ * 全部数据权限
+ */
+ public static final String DATA_SCOPE_ALL = "1";
+
+ /**
+ * 自定数据权限
+ */
+ public static final String DATA_SCOPE_CUSTOM = "2";
+
+ /**
+ * 部门数据权限
+ */
+ public static final String DATA_SCOPE_DEPT = "3";
+
+ /**
+ * 部门及以下数据权限
+ */
+ public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";
+
+ /**
+ * 仅本人数据权限
+ */
+ public static final String DATA_SCOPE_SELF = "5";
+ }
+}
diff --git a/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java
new file mode 100644
index 0000000..ea1e117
--- /dev/null
+++ b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java
@@ -0,0 +1,120 @@
+package com.ruoyi.common.constant;
+
+/**
+ * 代码生成通用常量
+ *
+ * @author ruoyi
+ */
+public class GenConstants
+{
+ /** 单表(增删改查) */
+ public static final String TPL_CRUD = "crud";
+
+ /** 树表(增删改查) */
+ public static final String TPL_TREE = "tree";
+
+ /** 主子表(增删改查) */
+ public static final String TPL_SUB = "sub";
+
+ /** 树编码字段 */
+ public static final String TREE_CODE = "treeCode";
+
+ /** 树父编码字段 */
+ public static final String TREE_PARENT_CODE = "treeParentCode";
+
+ /** 树名称字段 */
+ public static final String TREE_NAME = "treeName";
+
+ /** 上级菜单ID字段 */
+ public static final String PARENT_MENU_ID = "parentMenuId";
+
+ /** 上级菜单名称字段 */
+ public static final String PARENT_MENU_NAME = "parentMenuName";
+
+ /** 生成详情页开关 */
+ public static final String GEN_VIEW = "genView";
+
+ /** 数据库字符串类型 */
+ public static final String[] COLUMNTYPE_STR = { "char", "varchar", "nvarchar", "varchar2" };
+
+ /** 数据库文本类型 */
+ public static final String[] COLUMNTYPE_TEXT = { "tinytext", "text", "mediumtext", "longtext" };
+
+ /** 数据库时间类型 */
+ public static final String[] COLUMNTYPE_TIME = { "datetime", "time", "date", "timestamp" };
+
+ /** 数据库数字类型 */
+ public static final String[] COLUMNTYPE_NUMBER = { "tinyint", "smallint", "mediumint", "int", "number", "integer",
+ "bit", "bigint", "float", "double", "decimal" };
+
+ /** 页面不需要编辑字段 */
+ public static final String[] COLUMNNAME_NOT_EDIT = { "id", "create_by", "create_time", "del_flag" };
+
+ /** 页面不需要显示的列表字段 */
+ public static final String[] COLUMNNAME_NOT_LIST = { "id", "create_by", "create_time", "del_flag", "update_by",
+ "update_time" };
+
+ /** 页面不需要查询字段 */
+ public static final String[] COLUMNNAME_NOT_QUERY = { "id", "create_by", "create_time", "del_flag", "update_by",
+ "update_time", "remark" };
+
+ /** Entity基类字段 */
+ public static final String[] BASE_ENTITY = { "createBy", "createTime", "updateBy", "updateTime", "remark" };
+
+ /** Tree基类字段 */
+ public static final String[] TREE_ENTITY = { "parentName", "parentId", "orderNum", "ancestors", "children" };
+
+ /** 文本框 */
+ public static final String HTML_INPUT = "input";
+
+ /** 文本域 */
+ public static final String HTML_TEXTAREA = "textarea";
+
+ /** 下拉框 */
+ public static final String HTML_SELECT = "select";
+
+ /** 单选框 */
+ public static final String HTML_RADIO = "radio";
+
+ /** 复选框 */
+ public static final String HTML_CHECKBOX = "checkbox";
+
+ /** 日期控件 */
+ public static final String HTML_DATETIME = "datetime";
+
+ /** 图片上传控件 */
+ public static final String HTML_IMAGE_UPLOAD = "imageUpload";
+
+ /** 文件上传控件 */
+ public static final String HTML_FILE_UPLOAD = "fileUpload";
+
+ /** 富文本控件 */
+ public static final String HTML_EDITOR = "editor";
+
+ /** 字符串类型 */
+ public static final String TYPE_STRING = "String";
+
+ /** 整型 */
+ public static final String TYPE_INTEGER = "Integer";
+
+ /** 长整型 */
+ public static final String TYPE_LONG = "Long";
+
+ /** 浮点型 */
+ public static final String TYPE_DOUBLE = "Double";
+
+ /** 高精度计算类型 */
+ public static final String TYPE_BIGDECIMAL = "BigDecimal";
+
+ /** 时间类型 */
+ public static final String TYPE_DATE = "Date";
+
+ /** 模糊查询 */
+ public static final String QUERY_LIKE = "LIKE";
+
+ /** 相等查询 */
+ public static final String QUERY_EQ = "EQ";
+
+ /** 需要 */
+ public static final String REQUIRE = "1";
+}
diff --git a/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/constant/HttpStatus.java b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/constant/HttpStatus.java
new file mode 100644
index 0000000..a983c77
--- /dev/null
+++ b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/constant/HttpStatus.java
@@ -0,0 +1,94 @@
+package com.ruoyi.common.constant;
+
+/**
+ * 返回状态码
+ *
+ * @author ruoyi
+ */
+public class HttpStatus
+{
+ /**
+ * 操作成功
+ */
+ public static final int SUCCESS = 200;
+
+ /**
+ * 对象创建成功
+ */
+ public static final int CREATED = 201;
+
+ /**
+ * 请求已经被接受
+ */
+ public static final int ACCEPTED = 202;
+
+ /**
+ * 操作已经执行成功,但是没有返回数据
+ */
+ public static final int NO_CONTENT = 204;
+
+ /**
+ * 资源已被移除
+ */
+ public static final int MOVED_PERM = 301;
+
+ /**
+ * 重定向
+ */
+ public static final int SEE_OTHER = 303;
+
+ /**
+ * 资源没有被修改
+ */
+ public static final int NOT_MODIFIED = 304;
+
+ /**
+ * 参数列表错误(缺少,格式不匹配)
+ */
+ public static final int BAD_REQUEST = 400;
+
+ /**
+ * 未授权
+ */
+ public static final int UNAUTHORIZED = 401;
+
+ /**
+ * 访问受限,授权过期
+ */
+ public static final int FORBIDDEN = 403;
+
+ /**
+ * 资源,服务未找到
+ */
+ public static final int NOT_FOUND = 404;
+
+ /**
+ * 不允许的http方法
+ */
+ public static final int BAD_METHOD = 405;
+
+ /**
+ * 资源冲突,或者资源被锁
+ */
+ public static final int CONFLICT = 409;
+
+ /**
+ * 不支持的数据,媒体类型
+ */
+ public static final int UNSUPPORTED_TYPE = 415;
+
+ /**
+ * 系统内部错误
+ */
+ public static final int ERROR = 500;
+
+ /**
+ * 接口未实现
+ */
+ public static final int NOT_IMPLEMENTED = 501;
+
+ /**
+ * 系统警告消息
+ */
+ public static final int WARN = 601;
+}
diff --git a/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java
new file mode 100644
index 0000000..62ad815
--- /dev/null
+++ b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java
@@ -0,0 +1,50 @@
+package com.ruoyi.common.constant;
+
+/**
+ * 任务调度通用常量
+ *
+ * @author ruoyi
+ */
+public class ScheduleConstants
+{
+ public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME";
+
+ /** 执行目标key */
+ public static final String TASK_PROPERTIES = "TASK_PROPERTIES";
+
+ /** 默认 */
+ public static final String MISFIRE_DEFAULT = "0";
+
+ /** 立即触发执行 */
+ public static final String MISFIRE_IGNORE_MISFIRES = "1";
+
+ /** 触发一次执行 */
+ public static final String MISFIRE_FIRE_AND_PROCEED = "2";
+
+ /** 不触发立即执行 */
+ public static final String MISFIRE_DO_NOTHING = "3";
+
+ public enum Status
+ {
+ /**
+ * 正常
+ */
+ NORMAL("0"),
+ /**
+ * 暂停
+ */
+ PAUSE("1");
+
+ private String value;
+
+ private Status(String value)
+ {
+ this.value = value;
+ }
+
+ public String getValue()
+ {
+ return value;
+ }
+ }
+}
diff --git a/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java
new file mode 100644
index 0000000..8dc7faa
--- /dev/null
+++ b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java
@@ -0,0 +1,81 @@
+package com.ruoyi.common.constant;
+
+/**
+ * 用户常量信息
+ *
+ * @author ruoyi
+ */
+public class UserConstants
+{
+ /**
+ * 平台内系统用户的唯一标志
+ */
+ public static final String SYS_USER = "SYS_USER";
+
+ /** 正常状态 */
+ public static final String NORMAL = "0";
+
+ /** 异常状态 */
+ public static final String EXCEPTION = "1";
+
+ /** 用户封禁状态 */
+ public static final String USER_DISABLE = "1";
+
+ /** 角色正常状态 */
+ public static final String ROLE_NORMAL = "0";
+
+ /** 角色封禁状态 */
+ public static final String ROLE_DISABLE = "1";
+
+ /** 部门正常状态 */
+ public static final String DEPT_NORMAL = "0";
+
+ /** 部门停用状态 */
+ public static final String DEPT_DISABLE = "1";
+
+ /** 字典正常状态 */
+ public static final String DICT_NORMAL = "0";
+
+ /** 是否为系统默认(是) */
+ public static final String YES = "Y";
+
+ /** 是否菜单外链(是) */
+ public static final String YES_FRAME = "0";
+
+ /** 是否菜单外链(否) */
+ public static final String NO_FRAME = "1";
+
+ /** 菜单类型(目录) */
+ public static final String TYPE_DIR = "M";
+
+ /** 菜单类型(菜单) */
+ public static final String TYPE_MENU = "C";
+
+ /** 菜单类型(按钮) */
+ public static final String TYPE_BUTTON = "F";
+
+ /** Layout组件标识 */
+ public final static String LAYOUT = "Layout";
+
+ /** ParentView组件标识 */
+ public final static String PARENT_VIEW = "ParentView";
+
+ /** InnerLink组件标识 */
+ public final static String INNER_LINK = "InnerLink";
+
+ /** 校验是否唯一的返回标识 */
+ public final static boolean UNIQUE = true;
+ public final static boolean NOT_UNIQUE = false;
+
+ /**
+ * 用户名长度限制
+ */
+ public static final int USERNAME_MIN_LENGTH = 2;
+ public static final int USERNAME_MAX_LENGTH = 20;
+
+ /**
+ * 密码长度限制
+ */
+ public static final int PASSWORD_MIN_LENGTH = 5;
+ public static final int PASSWORD_MAX_LENGTH = 20;
+}
diff --git a/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java
new file mode 100644
index 0000000..a685e06
--- /dev/null
+++ b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java
@@ -0,0 +1,202 @@
+package com.ruoyi.common.core.controller;
+
+import java.beans.PropertyEditorSupport;
+import java.util.Date;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.WebDataBinder;
+import org.springframework.web.bind.annotation.InitBinder;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import com.ruoyi.common.constant.HttpStatus;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.model.LoginUser;
+import com.ruoyi.common.core.page.PageDomain;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.core.page.TableSupport;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.PageUtils;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.sql.SqlUtil;
+
+/**
+ * web层通用数据处理
+ *
+ * @author ruoyi
+ */
+public class BaseController
+{
+ protected final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ /**
+ * 将前台传递过来的日期格式的字符串,自动转化为Date类型
+ */
+ @InitBinder
+ public void initBinder(WebDataBinder binder)
+ {
+ // Date 类型转换
+ binder.registerCustomEditor(Date.class, new PropertyEditorSupport()
+ {
+ @Override
+ public void setAsText(String text)
+ {
+ setValue(DateUtils.parseDate(text));
+ }
+ });
+ }
+
+ /**
+ * 设置请求分页数据
+ */
+ protected void startPage()
+ {
+ PageUtils.startPage();
+ }
+
+ /**
+ * 设置请求排序数据
+ */
+ protected void startOrderBy()
+ {
+ PageDomain pageDomain = TableSupport.buildPageRequest();
+ if (StringUtils.isNotEmpty(pageDomain.getOrderBy()))
+ {
+ String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
+ PageHelper.orderBy(orderBy);
+ }
+ }
+
+ /**
+ * 清理分页的线程变量
+ */
+ protected void clearPage()
+ {
+ PageUtils.clearPage();
+ }
+
+ /**
+ * 响应请求分页数据
+ */
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ protected TableDataInfo getDataTable(List> list)
+ {
+ TableDataInfo rspData = new TableDataInfo();
+ rspData.setCode(HttpStatus.SUCCESS);
+ rspData.setMsg("查询成功");
+ rspData.setRows(list);
+ rspData.setTotal(new PageInfo(list).getTotal());
+ return rspData;
+ }
+
+ /**
+ * 返回成功
+ */
+ public AjaxResult success()
+ {
+ return AjaxResult.success();
+ }
+
+ /**
+ * 返回失败消息
+ */
+ public AjaxResult error()
+ {
+ return AjaxResult.error();
+ }
+
+ /**
+ * 返回成功消息
+ */
+ public AjaxResult success(String message)
+ {
+ return AjaxResult.success(message);
+ }
+
+ /**
+ * 返回成功消息
+ */
+ public AjaxResult success(Object data)
+ {
+ return AjaxResult.success(data);
+ }
+
+ /**
+ * 返回失败消息
+ */
+ public AjaxResult error(String message)
+ {
+ return AjaxResult.error(message);
+ }
+
+ /**
+ * 返回警告消息
+ */
+ public AjaxResult warn(String message)
+ {
+ return AjaxResult.warn(message);
+ }
+
+ /**
+ * 响应返回结果
+ *
+ * @param rows 影响行数
+ * @return 操作结果
+ */
+ protected AjaxResult toAjax(int rows)
+ {
+ return rows > 0 ? AjaxResult.success() : AjaxResult.error();
+ }
+
+ /**
+ * 响应返回结果
+ *
+ * @param result 结果
+ * @return 操作结果
+ */
+ protected AjaxResult toAjax(boolean result)
+ {
+ return result ? success() : error();
+ }
+
+ /**
+ * 页面跳转
+ */
+ public String redirect(String url)
+ {
+ return StringUtils.format("redirect:{}", url);
+ }
+
+ /**
+ * 获取用户缓存信息
+ */
+ public LoginUser getLoginUser()
+ {
+ return SecurityUtils.getLoginUser();
+ }
+
+ /**
+ * 获取登录用户id
+ */
+ public Long getUserId()
+ {
+ return getLoginUser().getUserId();
+ }
+
+ /**
+ * 获取登录部门id
+ */
+ public Long getDeptId()
+ {
+ return getLoginUser().getDeptId();
+ }
+
+ /**
+ * 获取登录用户名
+ */
+ public String getUsername()
+ {
+ return getLoginUser().getUsername();
+ }
+}
diff --git a/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java
new file mode 100644
index 0000000..a7abfe4
--- /dev/null
+++ b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java
@@ -0,0 +1,216 @@
+package com.ruoyi.common.core.domain;
+
+import java.util.HashMap;
+import java.util.Objects;
+import com.ruoyi.common.constant.HttpStatus;
+import com.ruoyi.common.utils.StringUtils;
+
+/**
+ * 操作消息提醒
+ *
+ * @author ruoyi
+ */
+public class AjaxResult extends HashMap
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 状态码 */
+ public static final String CODE_TAG = "code";
+
+ /** 返回内容 */
+ public static final String MSG_TAG = "msg";
+
+ /** 数据对象 */
+ public static final String DATA_TAG = "data";
+
+ /**
+ * 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
+ */
+ public AjaxResult()
+ {
+ }
+
+ /**
+ * 初始化一个新创建的 AjaxResult 对象
+ *
+ * @param code 状态码
+ * @param msg 返回内容
+ */
+ public AjaxResult(int code, String msg)
+ {
+ super.put(CODE_TAG, code);
+ super.put(MSG_TAG, msg);
+ }
+
+ /**
+ * 初始化一个新创建的 AjaxResult 对象
+ *
+ * @param code 状态码
+ * @param msg 返回内容
+ * @param data 数据对象
+ */
+ public AjaxResult(int code, String msg, Object data)
+ {
+ super.put(CODE_TAG, code);
+ super.put(MSG_TAG, msg);
+ if (StringUtils.isNotNull(data))
+ {
+ super.put(DATA_TAG, data);
+ }
+ }
+
+ /**
+ * 返回成功消息
+ *
+ * @return 成功消息
+ */
+ public static AjaxResult success()
+ {
+ return AjaxResult.success("操作成功");
+ }
+
+ /**
+ * 返回成功数据
+ *
+ * @return 成功消息
+ */
+ public static AjaxResult success(Object data)
+ {
+ return AjaxResult.success("操作成功", data);
+ }
+
+ /**
+ * 返回成功消息
+ *
+ * @param msg 返回内容
+ * @return 成功消息
+ */
+ public static AjaxResult success(String msg)
+ {
+ return AjaxResult.success(msg, null);
+ }
+
+ /**
+ * 返回成功消息
+ *
+ * @param msg 返回内容
+ * @param data 数据对象
+ * @return 成功消息
+ */
+ public static AjaxResult success(String msg, Object data)
+ {
+ return new AjaxResult(HttpStatus.SUCCESS, msg, data);
+ }
+
+ /**
+ * 返回警告消息
+ *
+ * @param msg 返回内容
+ * @return 警告消息
+ */
+ public static AjaxResult warn(String msg)
+ {
+ return AjaxResult.warn(msg, null);
+ }
+
+ /**
+ * 返回警告消息
+ *
+ * @param msg 返回内容
+ * @param data 数据对象
+ * @return 警告消息
+ */
+ public static AjaxResult warn(String msg, Object data)
+ {
+ return new AjaxResult(HttpStatus.WARN, msg, data);
+ }
+
+ /**
+ * 返回错误消息
+ *
+ * @return 错误消息
+ */
+ public static AjaxResult error()
+ {
+ return AjaxResult.error("操作失败");
+ }
+
+ /**
+ * 返回错误消息
+ *
+ * @param msg 返回内容
+ * @return 错误消息
+ */
+ public static AjaxResult error(String msg)
+ {
+ return AjaxResult.error(msg, null);
+ }
+
+ /**
+ * 返回错误消息
+ *
+ * @param msg 返回内容
+ * @param data 数据对象
+ * @return 错误消息
+ */
+ public static AjaxResult error(String msg, Object data)
+ {
+ return new AjaxResult(HttpStatus.ERROR, msg, data);
+ }
+
+ /**
+ * 返回错误消息
+ *
+ * @param code 状态码
+ * @param msg 返回内容
+ * @return 错误消息
+ */
+ public static AjaxResult error(int code, String msg)
+ {
+ return new AjaxResult(code, msg, null);
+ }
+
+ /**
+ * 是否为成功消息
+ *
+ * @return 结果
+ */
+ public boolean isSuccess()
+ {
+ return Objects.equals(HttpStatus.SUCCESS, this.get(CODE_TAG));
+ }
+
+ /**
+ * 是否为警告消息
+ *
+ * @return 结果
+ */
+ public boolean isWarn()
+ {
+ return Objects.equals(HttpStatus.WARN, this.get(CODE_TAG));
+ }
+
+ /**
+ * 是否为错误消息
+ *
+ * @return 结果
+ */
+ public boolean isError()
+ {
+ return Objects.equals(HttpStatus.ERROR, this.get(CODE_TAG));
+ }
+
+ /**
+ * 方便链式调用
+ *
+ * @param key 键
+ * @param value 值
+ * @return 数据对象
+ */
+ @Override
+ public AjaxResult put(String key, Object value)
+ {
+ super.put(key, value);
+ return this;
+ }
+}
diff --git a/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java
new file mode 100644
index 0000000..15bf66b
--- /dev/null
+++ b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java
@@ -0,0 +1,118 @@
+package com.ruoyi.common.core.domain;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+/**
+ * Entity基类
+ *
+ * @author ruoyi
+ */
+public class BaseEntity implements Serializable
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 搜索值 */
+ @JsonIgnore
+ private String searchValue;
+
+ /** 创建者 */
+ private String createBy;
+
+ /** 创建时间 */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date createTime;
+
+ /** 更新者 */
+ private String updateBy;
+
+ /** 更新时间 */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date updateTime;
+
+ /** 备注 */
+ private String remark;
+
+ /** 请求参数 */
+ @JsonInclude(JsonInclude.Include.NON_EMPTY)
+ private Map params;
+
+ public String getSearchValue()
+ {
+ return searchValue;
+ }
+
+ public void setSearchValue(String searchValue)
+ {
+ this.searchValue = searchValue;
+ }
+
+ public String getCreateBy()
+ {
+ return createBy;
+ }
+
+ public void setCreateBy(String createBy)
+ {
+ this.createBy = createBy;
+ }
+
+ public Date getCreateTime()
+ {
+ return createTime;
+ }
+
+ public void setCreateTime(Date createTime)
+ {
+ this.createTime = createTime;
+ }
+
+ public String getUpdateBy()
+ {
+ return updateBy;
+ }
+
+ public void setUpdateBy(String updateBy)
+ {
+ this.updateBy = updateBy;
+ }
+
+ public Date getUpdateTime()
+ {
+ return updateTime;
+ }
+
+ public void setUpdateTime(Date updateTime)
+ {
+ this.updateTime = updateTime;
+ }
+
+ public String getRemark()
+ {
+ return remark;
+ }
+
+ public void setRemark(String remark)
+ {
+ this.remark = remark;
+ }
+
+ public Map getParams()
+ {
+ if (params == null)
+ {
+ params = new HashMap<>();
+ }
+ return params;
+ }
+
+ public void setParams(Map params)
+ {
+ this.params = params;
+ }
+}
diff --git a/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/R.java b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/R.java
new file mode 100644
index 0000000..ef15802
--- /dev/null
+++ b/ry-api/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/R.java
@@ -0,0 +1,115 @@
+package com.ruoyi.common.core.domain;
+
+import java.io.Serializable;
+import com.ruoyi.common.constant.HttpStatus;
+
+/**
+ * 响应信息主体
+ *
+ * @author ruoyi
+ */
+public class R implements Serializable
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 成功 */
+ public static final int SUCCESS = HttpStatus.SUCCESS;
+
+ /** 失败 */
+ public static final int FAIL = HttpStatus.ERROR;
+
+ private int code;
+
+ private String msg;
+
+ private T data;
+
+ public static R ok()
+ {
+ return restResult(null, SUCCESS, "操作成功");
+ }
+
+ public static R ok(T data)
+ {
+ return restResult(data, SUCCESS, "操作成功");
+ }
+
+ public static R ok(T data, String msg)
+ {
+ return restResult(data, SUCCESS, msg);
+ }
+
+ public static R fail()
+ {
+ return restResult(null, FAIL, "操作失败");
+ }
+
+ public static R fail(String msg)
+ {
+ return restResult(null, FAIL, msg);
+ }
+
+ public static R