فهرست منبع

登陆注册接口及单招卡管理初始生成

mingfu 8 ساعت پیش
والد
کامیت
9815b3bb59
100فایلهای تغییر یافته به همراه10418 افزوده شده و 238 حذف شده
  1. 2 2
      back-ui/.env.development
  2. 2 2
      back-ui/.env.production
  3. 2 2
      back-ui/.env.staging
  4. 1 1
      back-ui/index.html
  5. 2 2
      back-ui/package.json
  6. 44 0
      back-ui/src/api/dz/agent.js
  7. 44 0
      back-ui/src/api/dz/cards.js
  8. 44 0
      back-ui/src/api/dz/classes.js
  9. 44 0
      back-ui/src/api/dz/control.js
  10. 44 0
      back-ui/src/api/dz/open.js
  11. 44 0
      back-ui/src/api/dz/orders.js
  12. 44 0
      back-ui/src/api/dz/school.js
  13. 44 0
      back-ui/src/api/dz/teacher.js
  14. 44 0
      back-ui/src/api/dz/teacherclass.js
  15. 44 0
      back-ui/src/api/system/blacklist.js
  16. 44 0
      back-ui/src/api/system/sms.js
  17. 280 0
      back-ui/src/views/dz/agent/index.vue
  18. 747 0
      back-ui/src/views/dz/cards/index.vue
  19. 277 0
      back-ui/src/views/dz/classes/index.vue
  20. 314 0
      back-ui/src/views/dz/control/index.vue
  21. 393 0
      back-ui/src/views/dz/open/index.vue
  22. 619 0
      back-ui/src/views/dz/orders/index.vue
  23. 310 0
      back-ui/src/views/dz/school/index.vue
  24. 244 0
      back-ui/src/views/dz/teacher/index.vue
  25. 272 0
      back-ui/src/views/dz/teacherclass/index.vue
  26. 6 25
      back-ui/src/views/index.vue
  27. 1 1
      back-ui/src/views/login.vue
  28. 228 0
      back-ui/src/views/system/blacklist/index.vue
  29. 17 11
      back-ui/src/views/system/dept/index.vue
  30. 278 0
      back-ui/src/views/system/sms/index.vue
  31. 102 0
      ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzAgentController.java
  32. 104 0
      ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzCardsController.java
  33. 104 0
      ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzCardsOpenController.java
  34. 104 0
      ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzClassesController.java
  35. 104 0
      ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzControlController.java
  36. 104 0
      ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzPaymentOrdersController.java
  37. 104 0
      ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzSchoolController.java
  38. 104 0
      ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzTeacherClassController.java
  39. 104 0
      ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzTeacherController.java
  40. 144 0
      ie-admin/src/main/java/com/ruoyi/web/controller/front/CommController.java
  41. 131 0
      ie-admin/src/main/java/com/ruoyi/web/controller/front/UserController.java
  42. 14 36
      ie-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
  43. 19 8
      ie-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java
  44. 104 0
      ie-admin/src/main/java/com/ruoyi/web/controller/system/SysSmsBlacklistController.java
  45. 104 0
      ie-admin/src/main/java/com/ruoyi/web/controller/system/SysSmsLogController.java
  46. 43 0
      ie-admin/src/main/java/com/ruoyi/web/service/CommService.java
  47. 60 13
      ie-admin/src/main/java/com/ruoyi/web/service/SysLoginService.java
  48. 182 0
      ie-admin/src/main/java/com/ruoyi/web/service/SysRegisterService.java
  49. 30 8
      ie-admin/src/main/java/com/ruoyi/web/service/UserDetailsServiceImpl.java
  50. 64 0
      ie-admin/src/main/resources/application.yml
  51. 30 1
      ie-common/pom.xml
  52. 5 0
      ie-common/src/main/java/com/ruoyi/common/constant/UserConstants.java
  53. 1 0
      ie-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java
  54. 107 0
      ie-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
  55. 15 2
      ie-common/src/main/java/com/ruoyi/common/core/domain/model/LoginBody.java
  56. 29 0
      ie-common/src/main/java/com/ruoyi/common/core/domain/model/LoginCard.java
  57. 29 3
      ie-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java
  58. 24 1
      ie-common/src/main/java/com/ruoyi/common/core/domain/model/RegisterBody.java
  59. 22 0
      ie-common/src/main/java/com/ruoyi/common/enums/ExamType.java
  60. 37 0
      ie-common/src/main/java/com/ruoyi/common/enums/SubjectType.java
  61. 23 0
      ie-common/src/main/java/com/ruoyi/common/enums/UserRegStatus.java
  62. 43 0
      ie-common/src/main/java/com/ruoyi/common/utils/PhoneUtils.java
  63. 223 0
      ie-common/src/main/java/com/ruoyi/common/utils/QRCodeUtils.java
  64. 241 0
      ie-common/src/main/java/com/ruoyi/common/utils/VerifyCodeUtils.java
  65. 60 0
      ie-common/src/main/java/com/ruoyi/common/utils/WXPayConstants.java
  66. 295 0
      ie-common/src/main/java/com/ruoyi/common/utils/WXPayUtil.java
  67. 30 0
      ie-common/src/main/java/com/ruoyi/common/utils/WXPayXmlUtil.java
  68. 49 0
      ie-common/src/main/java/com/ruoyi/common/utils/dz/SubjectScore.java
  69. 2 2
      ie-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
  70. 18 0
      ie-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java
  71. 19 0
      ie-framework/src/main/java/com/ruoyi/framework/security/provider/MyDaoAuthenticationProvider.java
  72. 0 117
      ie-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java
  73. 8 1
      ie-system/pom.xml
  74. 99 0
      ie-system/src/main/java/com/ruoyi/dz/domain/DzAgent.java
  75. 440 0
      ie-system/src/main/java/com/ruoyi/dz/domain/DzCards.java
  76. 176 0
      ie-system/src/main/java/com/ruoyi/dz/domain/DzCardsOpen.java
  77. 82 0
      ie-system/src/main/java/com/ruoyi/dz/domain/DzClasses.java
  78. 142 0
      ie-system/src/main/java/com/ruoyi/dz/domain/DzControl.java
  79. 433 0
      ie-system/src/main/java/com/ruoyi/dz/domain/DzPaymentOrders.java
  80. 145 0
      ie-system/src/main/java/com/ruoyi/dz/domain/DzSchool.java
  81. 82 0
      ie-system/src/main/java/com/ruoyi/dz/domain/DzTeacher.java
  82. 101 0
      ie-system/src/main/java/com/ruoyi/dz/domain/DzTeacherClass.java
  83. 61 0
      ie-system/src/main/java/com/ruoyi/dz/mapper/DzAgentMapper.java
  84. 61 0
      ie-system/src/main/java/com/ruoyi/dz/mapper/DzCardsMapper.java
  85. 61 0
      ie-system/src/main/java/com/ruoyi/dz/mapper/DzCardsOpenMapper.java
  86. 61 0
      ie-system/src/main/java/com/ruoyi/dz/mapper/DzClassesMapper.java
  87. 61 0
      ie-system/src/main/java/com/ruoyi/dz/mapper/DzControlMapper.java
  88. 61 0
      ie-system/src/main/java/com/ruoyi/dz/mapper/DzPaymentOrdersMapper.java
  89. 61 0
      ie-system/src/main/java/com/ruoyi/dz/mapper/DzSchoolMapper.java
  90. 61 0
      ie-system/src/main/java/com/ruoyi/dz/mapper/DzTeacherClassMapper.java
  91. 61 0
      ie-system/src/main/java/com/ruoyi/dz/mapper/DzTeacherMapper.java
  92. 61 0
      ie-system/src/main/java/com/ruoyi/dz/service/IDzAgentService.java
  93. 61 0
      ie-system/src/main/java/com/ruoyi/dz/service/IDzCardsOpenService.java
  94. 63 0
      ie-system/src/main/java/com/ruoyi/dz/service/IDzCardsService.java
  95. 61 0
      ie-system/src/main/java/com/ruoyi/dz/service/IDzClassesService.java
  96. 61 0
      ie-system/src/main/java/com/ruoyi/dz/service/IDzControlService.java
  97. 61 0
      ie-system/src/main/java/com/ruoyi/dz/service/IDzPaymentOrdersService.java
  98. 61 0
      ie-system/src/main/java/com/ruoyi/dz/service/IDzSchoolService.java
  99. 61 0
      ie-system/src/main/java/com/ruoyi/dz/service/IDzTeacherClassService.java
  100. 61 0
      ie-system/src/main/java/com/ruoyi/dz/service/IDzTeacherService.java

+ 2 - 2
back-ui/.env.development

@@ -1,8 +1,8 @@
 # 页面标题
-VITE_APP_TITLE = 若依管理系统
+VITE_APP_TITLE = 单招管理系统
 
 # 开发环境配置
 VITE_APP_ENV = 'development'
 
-# 若依管理系统/开发环境
+# 单招管理系统/开发环境
 VITE_APP_BASE_API = '/dev-api'

+ 2 - 2
back-ui/.env.production

@@ -1,10 +1,10 @@
 # 页面标题
-VITE_APP_TITLE = 若依管理系统
+VITE_APP_TITLE = 单招管理系统
 
 # 生产环境配置
 VITE_APP_ENV = 'production'
 
-# 若依管理系统/生产环境
+# 单招管理系统/生产环境
 VITE_APP_BASE_API = '/prod-api'
 
 # 是否在打包时开启压缩,支持 gzip 和 brotli

+ 2 - 2
back-ui/.env.staging

@@ -1,10 +1,10 @@
 # 页面标题
-VITE_APP_TITLE = 若依管理系统
+VITE_APP_TITLE = 单招管理系统
 
 # 生产环境配置
 VITE_APP_ENV = 'staging'
 
-# 若依管理系统/生产环境
+# 单招管理系统/生产环境
 VITE_APP_BASE_API = '/stage-api'
 
 # 是否在打包时开启压缩,支持 gzip 和 brotli

+ 1 - 1
back-ui/index.html

@@ -7,7 +7,7 @@
   <meta name="renderer" content="webkit">
   <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
   <link rel="icon" href="/favicon.ico">
-  <title>若依管理系统</title>
+  <title>单招管理系统</title>
   <!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
   <style>
     html,

+ 2 - 2
back-ui/package.json

@@ -1,8 +1,8 @@
 {
   "name": "ruoyi",
   "version": "3.9.0",
-  "description": "若依管理系统",
-  "author": "若依",
+  "description": "单招管理系统",
+  "author": "单招",
   "license": "MIT",
   "type": "module",
   "scripts": {

+ 44 - 0
back-ui/src/api/dz/agent.js

@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询机构代理列表
+export function listAgent(query) {
+  return request({
+    url: '/dz/agent/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询机构代理详细
+export function getAgent(agentId) {
+  return request({
+    url: '/dz/agent/' + agentId,
+    method: 'get'
+  })
+}
+
+// 新增机构代理
+export function addAgent(data) {
+  return request({
+    url: '/dz/agent',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改机构代理
+export function updateAgent(data) {
+  return request({
+    url: '/dz/agent',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除机构代理
+export function delAgent(agentId) {
+  return request({
+    url: '/dz/agent/' + agentId,
+    method: 'delete'
+  })
+}

+ 44 - 0
back-ui/src/api/dz/cards.js

@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询学习卡列表
+export function listCards(query) {
+  return request({
+    url: '/dz/cards/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询学习卡详细
+export function getCards(cardId) {
+  return request({
+    url: '/dz/cards/' + cardId,
+    method: 'get'
+  })
+}
+
+// 新增学习卡
+export function addCards(data) {
+  return request({
+    url: '/dz/cards',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改学习卡
+export function updateCards(data) {
+  return request({
+    url: '/dz/cards',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除学习卡
+export function delCards(cardId) {
+  return request({
+    url: '/dz/cards/' + cardId,
+    method: 'delete'
+  })
+}

+ 44 - 0
back-ui/src/api/dz/classes.js

@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询机构班级列表
+export function listClasses(query) {
+  return request({
+    url: '/dz/classes/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询机构班级详细
+export function getClasses(id) {
+  return request({
+    url: '/dz/classes/' + id,
+    method: 'get'
+  })
+}
+
+// 新增机构班级
+export function addClasses(data) {
+  return request({
+    url: '/dz/classes',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改机构班级
+export function updateClasses(data) {
+  return request({
+    url: '/dz/classes',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除机构班级
+export function delClasses(id) {
+  return request({
+    url: '/dz/classes/' + id,
+    method: 'delete'
+  })
+}

+ 44 - 0
back-ui/src/api/dz/control.js

@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询单招省份状态列表
+export function listControl(query) {
+  return request({
+    url: '/dz/control/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询单招省份状态详细
+export function getControl(id) {
+  return request({
+    url: '/dz/control/' + id,
+    method: 'get'
+  })
+}
+
+// 新增单招省份状态
+export function addControl(data) {
+  return request({
+    url: '/dz/control',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改单招省份状态
+export function updateControl(data) {
+  return request({
+    url: '/dz/control',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除单招省份状态
+export function delControl(id) {
+  return request({
+    url: '/dz/control/' + id,
+    method: 'delete'
+  })
+}

+ 44 - 0
back-ui/src/api/dz/open.js

@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询开卡申请列表
+export function listOpen(query) {
+  return request({
+    url: '/dz/open/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询开卡申请详细
+export function getOpen(id) {
+  return request({
+    url: '/dz/open/' + id,
+    method: 'get'
+  })
+}
+
+// 新增开卡申请
+export function addOpen(data) {
+  return request({
+    url: '/dz/open',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改开卡申请
+export function updateOpen(data) {
+  return request({
+    url: '/dz/open',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除开卡申请
+export function delOpen(id) {
+  return request({
+    url: '/dz/open/' + id,
+    method: 'delete'
+  })
+}

+ 44 - 0
back-ui/src/api/dz/orders.js

@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询订单列表
+export function listOrders(query) {
+  return request({
+    url: '/dz/orders/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询订单详细
+export function getOrders(id) {
+  return request({
+    url: '/dz/orders/' + id,
+    method: 'get'
+  })
+}
+
+// 新增订单
+export function addOrders(data) {
+  return request({
+    url: '/dz/orders',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改订单
+export function updateOrders(data) {
+  return request({
+    url: '/dz/orders',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除订单
+export function delOrders(id) {
+  return request({
+    url: '/dz/orders/' + id,
+    method: 'delete'
+  })
+}

+ 44 - 0
back-ui/src/api/dz/school.js

@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询机构校区列表
+export function listSchool(query) {
+  return request({
+    url: '/dz/school/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询机构校区详细
+export function getSchool(id) {
+  return request({
+    url: '/dz/school/' + id,
+    method: 'get'
+  })
+}
+
+// 新增机构校区
+export function addSchool(data) {
+  return request({
+    url: '/dz/school',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改机构校区
+export function updateSchool(data) {
+  return request({
+    url: '/dz/school',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除机构校区
+export function delSchool(id) {
+  return request({
+    url: '/dz/school/' + id,
+    method: 'delete'
+  })
+}

+ 44 - 0
back-ui/src/api/dz/teacher.js

@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询老师列表
+export function listTeacher(query) {
+  return request({
+    url: '/dz/teacher/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询老师详细
+export function getTeacher(teacherId) {
+  return request({
+    url: '/dz/teacher/' + teacherId,
+    method: 'get'
+  })
+}
+
+// 新增老师
+export function addTeacher(data) {
+  return request({
+    url: '/dz/teacher',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改老师
+export function updateTeacher(data) {
+  return request({
+    url: '/dz/teacher',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除老师
+export function delTeacher(teacherId) {
+  return request({
+    url: '/dz/teacher/' + teacherId,
+    method: 'delete'
+  })
+}

+ 44 - 0
back-ui/src/api/dz/teacherclass.js

@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询教师班级关系列表
+export function listTeacherclass(query) {
+  return request({
+    url: '/dz/teacherclass/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询教师班级关系详细
+export function getTeacherclass(id) {
+  return request({
+    url: '/dz/teacherclass/' + id,
+    method: 'get'
+  })
+}
+
+// 新增教师班级关系
+export function addTeacherclass(data) {
+  return request({
+    url: '/dz/teacherclass',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改教师班级关系
+export function updateTeacherclass(data) {
+  return request({
+    url: '/dz/teacherclass',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除教师班级关系
+export function delTeacherclass(id) {
+  return request({
+    url: '/dz/teacherclass/' + id,
+    method: 'delete'
+  })
+}

+ 44 - 0
back-ui/src/api/system/blacklist.js

@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询短信手机黑名单列表
+export function listBlacklist(query) {
+  return request({
+    url: '/system/blacklist/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询短信手机黑名单详细
+export function getBlacklist(id) {
+  return request({
+    url: '/system/blacklist/' + id,
+    method: 'get'
+  })
+}
+
+// 新增短信手机黑名单
+export function addBlacklist(data) {
+  return request({
+    url: '/system/blacklist',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改短信手机黑名单
+export function updateBlacklist(data) {
+  return request({
+    url: '/system/blacklist',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除短信手机黑名单
+export function delBlacklist(id) {
+  return request({
+    url: '/system/blacklist/' + id,
+    method: 'delete'
+  })
+}

+ 44 - 0
back-ui/src/api/system/sms.js

@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询短信发送记录列表
+export function listSms(query) {
+  return request({
+    url: '/system/sms/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询短信发送记录详细
+export function getSms(id) {
+  return request({
+    url: '/system/sms/' + id,
+    method: 'get'
+  })
+}
+
+// 新增短信发送记录
+export function addSms(data) {
+  return request({
+    url: '/system/sms',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改短信发送记录
+export function updateSms(data) {
+  return request({
+    url: '/system/sms',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除短信发送记录
+export function delSms(id) {
+  return request({
+    url: '/system/sms/' + id,
+    method: 'delete'
+  })
+}

+ 280 - 0
back-ui/src/views/dz/agent/index.vue

@@ -0,0 +1,280 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="用户ID" prop="userId">
+        <el-input
+          v-model="queryParams.userId"
+          placeholder="请输入用户ID"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="代理商名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入代理商名称"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="联系电话" prop="phonenumber">
+        <el-input
+          v-model="queryParams.phonenumber"
+          placeholder="请输入联系电话"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="上级代理商ID" prop="parentId">
+        <el-input
+          v-model="queryParams.parentId"
+          placeholder="请输入上级代理商ID"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="负责校区列表" prop="schools">
+        <el-input
+          v-model="queryParams.schools"
+          placeholder="请输入负责校区列表"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="Plus"
+          @click="handleAdd"
+          v-hasPermi="['dz:agent:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="info"
+          plain
+          icon="Sort"
+          @click="toggleExpandAll"
+        >展开/折叠</el-button>
+      </el-col>
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table
+      v-if="refreshTable"
+      v-loading="loading"
+      :data="agentList"
+      row-key="agentId"
+      :default-expand-all="isExpandAll"
+      :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+    >
+      <el-table-column label="用户ID" prop="userId" />
+      <el-table-column label="代理商名称" align="center" prop="name" />
+      <el-table-column label="联系电话" align="center" prop="phonenumber" />
+      <el-table-column label="上级代理商ID" align="center" prop="parentId" />
+      <el-table-column label="负责校区列表" align="center" prop="schools" />
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['dz:agent:edit']">修改</el-button>
+          <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['dz:agent:add']">新增</el-button>
+          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['dz:agent:remove']">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 添加或修改机构代理对话框 -->
+    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
+      <el-form ref="agentRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="用户ID" prop="userId">
+          <el-input v-model="form.userId" placeholder="请输入用户ID" />
+        </el-form-item>
+        <el-form-item label="代理商名称" prop="name">
+          <el-input v-model="form.name" placeholder="请输入代理商名称" />
+        </el-form-item>
+        <el-form-item label="联系电话" prop="phonenumber">
+          <el-input v-model="form.phonenumber" placeholder="请输入联系电话" />
+        </el-form-item>
+        <el-form-item label="上级代理商ID" prop="parentId">
+          <el-tree-select
+            v-model="form.parentId"
+            :data="agentOptions"
+            :props="{ value: 'agentId', label: 'name', children: 'children' }"
+            value-key="agentId"
+            placeholder="请选择上级代理商ID"
+            check-strictly
+          />
+        </el-form-item>
+        <el-form-item label="负责校区列表" prop="schools">
+          <el-input v-model="form.schools" placeholder="请输入负责校区列表" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" placeholder="请输入备注" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Agent">
+import { listAgent, getAgent, delAgent, addAgent, updateAgent } from "@/api/dz/agent"
+
+const { proxy } = getCurrentInstance()
+
+const agentList = ref([])
+const agentOptions = ref([])
+const open = ref(false)
+const loading = ref(true)
+const showSearch = ref(true)
+const title = ref("")
+const isExpandAll = ref(true)
+const refreshTable = ref(true)
+
+const data = reactive({
+  form: {},
+  queryParams: {
+    userId: null,
+    name: null,
+    phonenumber: null,
+    parentId: null,
+    schools: null,
+  },
+  rules: {
+  }
+})
+
+const { queryParams, form, rules } = toRefs(data)
+
+/** 查询机构代理列表 */
+function getList() {
+  loading.value = true
+  listAgent(queryParams.value).then(response => {
+    agentList.value = proxy.handleTree(response.data, "agentId", "parentId")
+    loading.value = false
+  })
+}
+
+/** 查询机构代理下拉树结构 */
+function getTreeselect() {
+  listAgent().then(response => {
+    agentOptions.value = []
+    const data = { agentId: 0, name: '顶级节点', children: [] }
+    data.children = proxy.handleTree(response.data, "agentId", "parentId")
+    agentOptions.value.push(data)
+  })
+}
+	
+// 取消按钮
+function cancel() {
+  open.value = false
+  reset()
+}
+
+// 表单重置
+function reset() {
+  form.value = {
+    agentId: null,
+    userId: null,
+    name: null,
+    phonenumber: null,
+    parentId: null,
+    schools: null,
+    remark: null
+  }
+  proxy.resetForm("agentRef")
+}
+
+/** 搜索按钮操作 */
+function handleQuery() {
+  getList()
+}
+
+/** 重置按钮操作 */
+function resetQuery() {
+  proxy.resetForm("queryRef")
+  handleQuery()
+}
+
+/** 新增按钮操作 */
+function handleAdd(row) {
+  reset()
+  getTreeselect()
+  if (row != null && row.agentId) {
+    form.value.parentId = row.agentId
+  } else {
+    form.value.parentId = 0
+  }
+  open.value = true
+  title.value = "添加机构代理"
+}
+
+/** 展开/折叠操作 */
+function toggleExpandAll() {
+  refreshTable.value = false
+  isExpandAll.value = !isExpandAll.value
+  nextTick(() => {
+    refreshTable.value = true
+  })
+}
+
+/** 修改按钮操作 */
+async function handleUpdate(row) {
+  reset()
+  await getTreeselect()
+  if (row != null) {
+    form.value.parentId = row.parentId
+  }
+  getAgent(row.agentId).then(response => {
+    form.value = response.data
+    open.value = true
+    title.value = "修改机构代理"
+  })
+}
+
+/** 提交按钮 */
+function submitForm() {
+  proxy.$refs["agentRef"].validate(valid => {
+    if (valid) {
+      if (form.value.agentId != null) {
+        updateAgent(form.value).then(response => {
+          proxy.$modal.msgSuccess("修改成功")
+          open.value = false
+          getList()
+        })
+      } else {
+        addAgent(form.value).then(response => {
+          proxy.$modal.msgSuccess("新增成功")
+          open.value = false
+          getList()
+        })
+      }
+    }
+  })
+}
+
+/** 删除按钮操作 */
+function handleDelete(row) {
+  proxy.$modal.confirm('是否确认删除机构代理编号为"' + row.agentId + '"的数据项?').then(function() {
+    return delAgent(row.agentId)
+  }).then(() => {
+    getList()
+    proxy.$modal.msgSuccess("删除成功")
+  }).catch(() => {})
+}
+
+getList()
+</script>

+ 747 - 0
back-ui/src/views/dz/cards/index.vue

@@ -0,0 +1,747 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="账号" prop="cardNo">
+        <el-input
+          v-model="queryParams.cardNo"
+          placeholder="请输入账号"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="初始密码" prop="password">
+        <el-input
+          v-model="queryParams.password"
+          placeholder="请输入初始密码"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="0电子卡" prop="type">
+        <el-select v-model="queryParams.type" placeholder="请选择0电子卡" clearable>
+          <el-option
+            v-for="dict in card_status"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="0未开卡,1已开卡,2已激活," prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择0未开卡,1已开卡,2已激活," clearable>
+          <el-option
+            v-for="dict in card_status"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="0未分配,1已分配" prop="distributeStatus">
+        <el-select v-model="queryParams.distributeStatus" placeholder="请选择0未分配,1已分配" clearable>
+          <el-option
+            v-for="dict in card_status"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="9已过期,10已关卡,11已失效" prop="timeStatus">
+        <el-select v-model="queryParams.timeStatus" placeholder="请选择9已过期,10已关卡,11已失效" clearable>
+          <el-option
+            v-for="dict in card_status"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="0=未缴费,1=已缴费,2=已退费" prop="payStatus">
+        <el-select v-model="queryParams.payStatus" placeholder="请选择0=未缴费,1=已缴费,2=已退费" clearable>
+          <el-option
+            v-for="dict in card_status"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="是否结算(0:否,1:是)" prop="isSettlement">
+        <el-select v-model="queryParams.isSettlement" placeholder="请选择是否结算(0:否,1:是)" clearable>
+          <el-option
+            v-for="dict in sys_yes_no"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="一级代理商ID" prop="agentId">
+        <el-input
+          v-model="queryParams.agentId"
+          placeholder="请输入一级代理商ID"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="末级代理商ID" prop="leftAgentId">
+        <el-input
+          v-model="queryParams.leftAgentId"
+          placeholder="请输入末级代理商ID"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="安排校区" prop="campusId">
+        <el-input
+          v-model="queryParams.campusId"
+          placeholder="请输入安排校区"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="分配学校" prop="assignSchoolId">
+        <el-input
+          v-model="queryParams.assignSchoolId"
+          placeholder="请输入分配学校"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="校区id" prop="schoolId">
+        <el-input
+          v-model="queryParams.schoolId"
+          placeholder="请输入校区id"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="校区班级ID" prop="classesId">
+        <el-input
+          v-model="queryParams.classesId"
+          placeholder="请输入校区班级ID"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="班级/入学年份" prop="year">
+        <el-input
+          v-model="queryParams.year"
+          placeholder="请输入班级/入学年份"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="高考年份" prop="endYear">
+        <el-input
+          v-model="queryParams.endYear"
+          placeholder="请输入高考年份"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="开卡ID" prop="openId">
+        <el-input
+          v-model="queryParams.openId"
+          placeholder="请输入开卡ID"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="分配时间" prop="distributeTime">
+        <el-date-picker clearable
+          v-model="queryParams.distributeTime"
+          type="date"
+          value-format="YYYY-MM-DD"
+          placeholder="请选择分配时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="过期时间" prop="outDate">
+        <el-date-picker clearable
+          v-model="queryParams.outDate"
+          type="date"
+          value-format="YYYY-MM-DD"
+          placeholder="请选择过期时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="开卡时间" prop="openTime">
+        <el-date-picker clearable
+          v-model="queryParams.openTime"
+          type="date"
+          value-format="YYYY-MM-DD"
+          placeholder="请选择开卡时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="缴费时间" prop="payTime">
+        <el-date-picker clearable
+          v-model="queryParams.payTime"
+          type="date"
+          value-format="YYYY-MM-DD"
+          placeholder="请选择缴费时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="激活时间" prop="activeTime">
+        <el-date-picker clearable
+          v-model="queryParams.activeTime"
+          type="date"
+          value-format="YYYY-MM-DD"
+          placeholder="请选择激活时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="结算时间" prop="settlementTime">
+        <el-date-picker clearable
+          v-model="queryParams.settlementTime"
+          type="date"
+          value-format="YYYY-MM-DD"
+          placeholder="请选择结算时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="退费时间" prop="refundTime">
+        <el-date-picker clearable
+          v-model="queryParams.refundTime"
+          type="date"
+          value-format="YYYY-MM-DD"
+          placeholder="请选择退费时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="关卡时间" prop="closeTime">
+        <el-date-picker clearable
+          v-model="queryParams.closeTime"
+          type="date"
+          value-format="YYYY-MM-DD"
+          placeholder="请选择关卡时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="Plus"
+          @click="handleAdd"
+          v-hasPermi="['dz:cards:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="Edit"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['dz:cards:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="Delete"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['dz:cards:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="Download"
+          @click="handleExport"
+          v-hasPermi="['dz:cards:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="cardsList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="ID" align="center" prop="cardId" />
+      <el-table-column label="账号" align="center" prop="cardNo" />
+      <el-table-column label="初始密码" align="center" prop="password" />
+      <el-table-column label="0电子卡" align="center" prop="type">
+        <template #default="scope">
+          <dict-tag :options="card_status" :value="scope.row.type"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="0未开卡,1已开卡,2已激活," align="center" prop="status">
+        <template #default="scope">
+          <dict-tag :options="card_status" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="0未分配,1已分配" align="center" prop="distributeStatus">
+        <template #default="scope">
+          <dict-tag :options="card_status" :value="scope.row.distributeStatus"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="9已过期,10已关卡,11已失效" align="center" prop="timeStatus">
+        <template #default="scope">
+          <dict-tag :options="card_status" :value="scope.row.timeStatus"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="0=未缴费,1=已缴费,2=已退费" align="center" prop="payStatus">
+        <template #default="scope">
+          <dict-tag :options="card_status" :value="scope.row.payStatus"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="是否结算(0:否,1:是)" align="center" prop="isSettlement">
+        <template #default="scope">
+          <dict-tag :options="sys_yes_no" :value="scope.row.isSettlement"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="机构ID" align="center" prop="deptId" />
+      <el-table-column label="一级代理商ID" align="center" prop="agentId" />
+      <el-table-column label="末级代理商ID" align="center" prop="leftAgentId" />
+      <el-table-column label="安排校区" align="center" prop="campusId" />
+      <el-table-column label="分配学校" align="center" prop="assignSchoolId" />
+      <el-table-column label="校区id" align="center" prop="schoolId" />
+      <el-table-column label="校区班级ID" align="center" prop="classesId" />
+      <el-table-column label="班级/入学年份" align="center" prop="year" />
+      <el-table-column label="高考年份" align="center" prop="endYear" />
+      <el-table-column label="开卡ID" align="center" prop="openId" />
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="分配时间" align="center" prop="distributeTime" width="180">
+        <template #default="scope">
+          <span>{{ parseTime(scope.row.distributeTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="过期时间" align="center" prop="outDate" width="180">
+        <template #default="scope">
+          <span>{{ parseTime(scope.row.outDate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="开卡时间" align="center" prop="openTime" width="180">
+        <template #default="scope">
+          <span>{{ parseTime(scope.row.openTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="缴费时间" align="center" prop="payTime" width="180">
+        <template #default="scope">
+          <span>{{ parseTime(scope.row.payTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="激活时间" align="center" prop="activeTime" width="180">
+        <template #default="scope">
+          <span>{{ parseTime(scope.row.activeTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="结算时间" align="center" prop="settlementTime" width="180">
+        <template #default="scope">
+          <span>{{ parseTime(scope.row.settlementTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="退费时间" align="center" prop="refundTime" width="180">
+        <template #default="scope">
+          <span>{{ parseTime(scope.row.refundTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="关卡时间" align="center" prop="closeTime" width="180">
+        <template #default="scope">
+          <span>{{ parseTime(scope.row.closeTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['dz:cards:edit']">修改</el-button>
+          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['dz:cards:remove']">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    
+    <pagination
+      v-show="total>0"
+      :total="total"
+      v-model:page="queryParams.pageNum"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改学习卡对话框 -->
+    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
+      <el-form ref="cardsRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="账号" prop="cardNo">
+          <el-input v-model="form.cardNo" placeholder="请输入账号" />
+        </el-form-item>
+        <el-form-item label="初始密码" prop="password">
+          <el-input v-model="form.password" placeholder="请输入初始密码" />
+        </el-form-item>
+        <el-form-item label="0电子卡" prop="type">
+          <el-select v-model="form.type" placeholder="请选择0电子卡">
+            <el-option
+              v-for="dict in card_status"
+              :key="dict.value"
+              :label="dict.label"
+              :value="parseInt(dict.value)"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="0未开卡,1已开卡,2已激活," prop="status">
+          <el-select v-model="form.status" placeholder="请选择0未开卡,1已开卡,2已激活,">
+            <el-option
+              v-for="dict in card_status"
+              :key="dict.value"
+              :label="dict.label"
+              :value="parseInt(dict.value)"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="0未分配,1已分配" prop="distributeStatus">
+          <el-select v-model="form.distributeStatus" placeholder="请选择0未分配,1已分配">
+            <el-option
+              v-for="dict in card_status"
+              :key="dict.value"
+              :label="dict.label"
+              :value="parseInt(dict.value)"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="9已过期,10已关卡,11已失效" prop="timeStatus">
+          <el-select v-model="form.timeStatus" placeholder="请选择9已过期,10已关卡,11已失效">
+            <el-option
+              v-for="dict in card_status"
+              :key="dict.value"
+              :label="dict.label"
+              :value="parseInt(dict.value)"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="0=未缴费,1=已缴费,2=已退费" prop="payStatus">
+          <el-select v-model="form.payStatus" placeholder="请选择0=未缴费,1=已缴费,2=已退费">
+            <el-option
+              v-for="dict in card_status"
+              :key="dict.value"
+              :label="dict.label"
+              :value="parseInt(dict.value)"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="是否结算(0:否,1:是)" prop="isSettlement">
+          <el-radio-group v-model="form.isSettlement">
+            <el-radio
+              v-for="dict in sys_yes_no"
+              :key="dict.value"
+              :label="parseInt(dict.value)"
+            >{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="一级代理商ID" prop="agentId">
+          <el-input v-model="form.agentId" placeholder="请输入一级代理商ID" />
+        </el-form-item>
+        <el-form-item label="末级代理商ID" prop="leftAgentId">
+          <el-input v-model="form.leftAgentId" placeholder="请输入末级代理商ID" />
+        </el-form-item>
+        <el-form-item label="安排校区" prop="campusId">
+          <el-input v-model="form.campusId" placeholder="请输入安排校区" />
+        </el-form-item>
+        <el-form-item label="分配学校" prop="assignSchoolId">
+          <el-input v-model="form.assignSchoolId" placeholder="请输入分配学校" />
+        </el-form-item>
+        <el-form-item label="校区id" prop="schoolId">
+          <el-input v-model="form.schoolId" placeholder="请输入校区id" />
+        </el-form-item>
+        <el-form-item label="校区班级ID" prop="classesId">
+          <el-input v-model="form.classesId" placeholder="请输入校区班级ID" />
+        </el-form-item>
+        <el-form-item label="班级/入学年份" prop="year">
+          <el-input v-model="form.year" placeholder="请输入班级/入学年份" />
+        </el-form-item>
+        <el-form-item label="高考年份" prop="endYear">
+          <el-input v-model="form.endYear" placeholder="请输入高考年份" />
+        </el-form-item>
+        <el-form-item label="开卡ID" prop="openId">
+          <el-input v-model="form.openId" placeholder="请输入开卡ID" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" placeholder="请输入备注" />
+        </el-form-item>
+        <el-form-item label="分配时间" prop="distributeTime">
+          <el-date-picker clearable
+            v-model="form.distributeTime"
+            type="date"
+            value-format="YYYY-MM-DD"
+            placeholder="请选择分配时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="过期时间" prop="outDate">
+          <el-date-picker clearable
+            v-model="form.outDate"
+            type="date"
+            value-format="YYYY-MM-DD"
+            placeholder="请选择过期时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="开卡时间" prop="openTime">
+          <el-date-picker clearable
+            v-model="form.openTime"
+            type="date"
+            value-format="YYYY-MM-DD"
+            placeholder="请选择开卡时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="缴费时间" prop="payTime">
+          <el-date-picker clearable
+            v-model="form.payTime"
+            type="date"
+            value-format="YYYY-MM-DD"
+            placeholder="请选择缴费时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="激活时间" prop="activeTime">
+          <el-date-picker clearable
+            v-model="form.activeTime"
+            type="date"
+            value-format="YYYY-MM-DD"
+            placeholder="请选择激活时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="结算时间" prop="settlementTime">
+          <el-date-picker clearable
+            v-model="form.settlementTime"
+            type="date"
+            value-format="YYYY-MM-DD"
+            placeholder="请选择结算时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="退费时间" prop="refundTime">
+          <el-date-picker clearable
+            v-model="form.refundTime"
+            type="date"
+            value-format="YYYY-MM-DD"
+            placeholder="请选择退费时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="关卡时间" prop="closeTime">
+          <el-date-picker clearable
+            v-model="form.closeTime"
+            type="date"
+            value-format="YYYY-MM-DD"
+            placeholder="请选择关卡时间">
+          </el-date-picker>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Cards">
+import { listCards, getCards, delCards, addCards, updateCards } from "@/api/dz/cards"
+
+const { proxy } = getCurrentInstance()
+const { card_status, sys_yes_no } = proxy.useDict('card_status', 'sys_yes_no')
+
+const cardsList = ref([])
+const open = ref(false)
+const loading = ref(true)
+const showSearch = ref(true)
+const ids = ref([])
+const single = ref(true)
+const multiple = ref(true)
+const total = ref(0)
+const title = ref("")
+
+const data = reactive({
+  form: {},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    cardNo: null,
+    password: null,
+    type: null,
+    status: null,
+    distributeStatus: null,
+    timeStatus: null,
+    payStatus: null,
+    isSettlement: null,
+    deptId: null,
+    agentId: null,
+    leftAgentId: null,
+    campusId: null,
+    assignSchoolId: null,
+    schoolId: null,
+    classesId: null,
+    year: null,
+    endYear: null,
+    openId: null,
+    distributeTime: null,
+    outDate: null,
+    openTime: null,
+    payTime: null,
+    activeTime: null,
+    settlementTime: null,
+    refundTime: null,
+    closeTime: null,
+  },
+  rules: {
+    type: [
+      { required: true, message: "0电子卡不能为空", trigger: "change" }
+    ],
+    status: [
+      { required: true, message: "0未开卡,1已开卡,2已激活,不能为空", trigger: "change" }
+    ],
+    distributeStatus: [
+      { required: true, message: "0未分配,1已分配不能为空", trigger: "change" }
+    ],
+    timeStatus: [
+      { required: true, message: "9已过期,10已关卡,11已失效不能为空", trigger: "change" }
+    ],
+    payStatus: [
+      { required: true, message: "0=未缴费,1=已缴费,2=已退费不能为空", trigger: "change" }
+    ],
+    isSettlement: [
+      { required: true, message: "是否结算(0:否,1:是)不能为空", trigger: "change" }
+    ],
+    createTime: [
+      { required: true, message: "生成时间不能为空", trigger: "blur" }
+    ],
+    updateTime: [
+      { required: true, message: "更新时间不能为空", trigger: "blur" }
+    ]
+  }
+})
+
+const { queryParams, form, rules } = toRefs(data)
+
+/** 查询学习卡列表 */
+function getList() {
+  loading.value = true
+  listCards(queryParams.value).then(response => {
+    cardsList.value = response.rows
+    total.value = response.total
+    loading.value = false
+  })
+}
+
+// 取消按钮
+function cancel() {
+  open.value = false
+  reset()
+}
+
+// 表单重置
+function reset() {
+  form.value = {
+    cardId: null,
+    cardNo: null,
+    password: null,
+    type: null,
+    status: null,
+    distributeStatus: null,
+    timeStatus: null,
+    payStatus: null,
+    isSettlement: null,
+    deptId: null,
+    agentId: null,
+    leftAgentId: null,
+    campusId: null,
+    assignSchoolId: null,
+    schoolId: null,
+    classesId: null,
+    year: null,
+    endYear: null,
+    openId: null,
+    remark: null,
+    distributeTime: null,
+    outDate: null,
+    openTime: null,
+    payTime: null,
+    activeTime: null,
+    settlementTime: null,
+    refundTime: null,
+    closeTime: null,
+    createTime: null,
+    updateTime: null
+  }
+  proxy.resetForm("cardsRef")
+}
+
+/** 搜索按钮操作 */
+function handleQuery() {
+  queryParams.value.pageNum = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+function resetQuery() {
+  proxy.resetForm("queryRef")
+  handleQuery()
+}
+
+// 多选框选中数据
+function handleSelectionChange(selection) {
+  ids.value = selection.map(item => item.cardId)
+  single.value = selection.length != 1
+  multiple.value = !selection.length
+}
+
+/** 新增按钮操作 */
+function handleAdd() {
+  reset()
+  open.value = true
+  title.value = "添加学习卡"
+}
+
+/** 修改按钮操作 */
+function handleUpdate(row) {
+  reset()
+  const _cardId = row.cardId || ids.value
+  getCards(_cardId).then(response => {
+    form.value = response.data
+    open.value = true
+    title.value = "修改学习卡"
+  })
+}
+
+/** 提交按钮 */
+function submitForm() {
+  proxy.$refs["cardsRef"].validate(valid => {
+    if (valid) {
+      if (form.value.cardId != null) {
+        updateCards(form.value).then(response => {
+          proxy.$modal.msgSuccess("修改成功")
+          open.value = false
+          getList()
+        })
+      } else {
+        addCards(form.value).then(response => {
+          proxy.$modal.msgSuccess("新增成功")
+          open.value = false
+          getList()
+        })
+      }
+    }
+  })
+}
+
+/** 删除按钮操作 */
+function handleDelete(row) {
+  const _cardIds = row.cardId || ids.value
+  proxy.$modal.confirm('是否确认删除学习卡编号为"' + _cardIds + '"的数据项?').then(function() {
+    return delCards(_cardIds)
+  }).then(() => {
+    getList()
+    proxy.$modal.msgSuccess("删除成功")
+  }).catch(() => {})
+}
+
+/** 导出按钮操作 */
+function handleExport() {
+  proxy.download('dz/cards/export', {
+    ...queryParams.value
+  }, `cards_${new Date().getTime()}.xlsx`)
+}
+
+getList()
+</script>

+ 277 - 0
back-ui/src/views/dz/classes/index.vue

@@ -0,0 +1,277 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="班级名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入班级名称"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="所在校区" prop="schoolId">
+        <el-input
+          v-model="queryParams.schoolId"
+          placeholder="请输入所在校区"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="是否线上" prop="online">
+        <el-select v-model="queryParams.online" placeholder="请选择是否线上" clearable>
+          <el-option
+            v-for="dict in sys_yes_no"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="Plus"
+          @click="handleAdd"
+          v-hasPermi="['dz:classes:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="Edit"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['dz:classes:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="Delete"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['dz:classes:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="Download"
+          @click="handleExport"
+          v-hasPermi="['dz:classes:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="classesList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="班级id" align="center" prop="id" />
+      <el-table-column label="班级名称" align="center" prop="name" />
+      <el-table-column label="所在校区" align="center" prop="schoolId" />
+      <el-table-column label="是否线上" align="center" prop="online">
+        <template #default="scope">
+          <dict-tag :options="sys_yes_no" :value="scope.row.online"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['dz:classes:edit']">修改</el-button>
+          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['dz:classes:remove']">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    
+    <pagination
+      v-show="total>0"
+      :total="total"
+      v-model:page="queryParams.pageNum"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改机构班级对话框 -->
+    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
+      <el-form ref="classesRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="班级名称" prop="name">
+          <el-input v-model="form.name" placeholder="请输入班级名称" />
+        </el-form-item>
+        <el-form-item label="所在校区" prop="schoolId">
+          <el-input v-model="form.schoolId" placeholder="请输入所在校区" />
+        </el-form-item>
+        <el-form-item label="是否线上" prop="online">
+          <el-radio-group v-model="form.online">
+            <el-radio
+              v-for="dict in sys_yes_no"
+              :key="dict.value"
+              :label="parseInt(dict.value)"
+            >{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Classes">
+import { listClasses, getClasses, delClasses, addClasses, updateClasses } from "@/api/dz/classes"
+
+const { proxy } = getCurrentInstance()
+const { sys_yes_no } = proxy.useDict('sys_yes_no')
+
+const classesList = ref([])
+const open = ref(false)
+const loading = ref(true)
+const showSearch = ref(true)
+const ids = ref([])
+const single = ref(true)
+const multiple = ref(true)
+const total = ref(0)
+const title = ref("")
+
+const data = reactive({
+  form: {},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    name: null,
+    schoolId: null,
+    online: null
+  },
+  rules: {
+    name: [
+      { required: true, message: "班级名称不能为空", trigger: "blur" }
+    ],
+    schoolId: [
+      { required: true, message: "所在校区不能为空", trigger: "blur" }
+    ],
+    online: [
+      { required: true, message: "是否线上不能为空", trigger: "change" }
+    ]
+  }
+})
+
+const { queryParams, form, rules } = toRefs(data)
+
+/** 查询机构班级列表 */
+function getList() {
+  loading.value = true
+  listClasses(queryParams.value).then(response => {
+    classesList.value = response.rows
+    total.value = response.total
+    loading.value = false
+  })
+}
+
+// 取消按钮
+function cancel() {
+  open.value = false
+  reset()
+}
+
+// 表单重置
+function reset() {
+  form.value = {
+    id: null,
+    name: null,
+    schoolId: null,
+    online: null
+  }
+  proxy.resetForm("classesRef")
+}
+
+/** 搜索按钮操作 */
+function handleQuery() {
+  queryParams.value.pageNum = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+function resetQuery() {
+  proxy.resetForm("queryRef")
+  handleQuery()
+}
+
+// 多选框选中数据
+function handleSelectionChange(selection) {
+  ids.value = selection.map(item => item.id)
+  single.value = selection.length != 1
+  multiple.value = !selection.length
+}
+
+/** 新增按钮操作 */
+function handleAdd() {
+  reset()
+  open.value = true
+  title.value = "添加机构班级"
+}
+
+/** 修改按钮操作 */
+function handleUpdate(row) {
+  reset()
+  const _id = row.id || ids.value
+  getClasses(_id).then(response => {
+    form.value = response.data
+    open.value = true
+    title.value = "修改机构班级"
+  })
+}
+
+/** 提交按钮 */
+function submitForm() {
+  proxy.$refs["classesRef"].validate(valid => {
+    if (valid) {
+      if (form.value.id != null) {
+        updateClasses(form.value).then(response => {
+          proxy.$modal.msgSuccess("修改成功")
+          open.value = false
+          getList()
+        })
+      } else {
+        addClasses(form.value).then(response => {
+          proxy.$modal.msgSuccess("新增成功")
+          open.value = false
+          getList()
+        })
+      }
+    }
+  })
+}
+
+/** 删除按钮操作 */
+function handleDelete(row) {
+  const _ids = row.id || ids.value
+  proxy.$modal.confirm('是否确认删除机构班级编号为"' + _ids + '"的数据项?').then(function() {
+    return delClasses(_ids)
+  }).then(() => {
+    getList()
+    proxy.$modal.msgSuccess("删除成功")
+  }).catch(() => {})
+}
+
+/** 导出按钮操作 */
+function handleExport() {
+  proxy.download('dz/classes/export', {
+    ...queryParams.value
+  }, `classes_${new Date().getTime()}.xlsx`)
+}
+
+getList()
+</script>

+ 314 - 0
back-ui/src/views/dz/control/index.vue

@@ -0,0 +1,314 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="省份" prop="location">
+        <el-input
+          v-model="queryParams.location"
+          placeholder="请输入省份"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="开始时间" prop="startDate">
+        <el-input
+          v-model="queryParams.startDate"
+          placeholder="请输入开始时间"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="结束时间" prop="endDate">
+        <el-input
+          v-model="queryParams.endDate"
+          placeholder="请输入结束时间"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="是否生效(0:否,1:是)" prop="isValid">
+        <el-input
+          v-model="queryParams.isValid"
+          placeholder="请输入是否生效(0:否,1:是)"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="计划年度" prop="planYear">
+        <el-input
+          v-model="queryParams.planYear"
+          placeholder="请输入计划年度"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="录取年度" prop="submitYear">
+        <el-input
+          v-model="queryParams.submitYear"
+          placeholder="请输入录取年度"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="开启考生" prop="examTypes">
+        <el-input
+          v-model="queryParams.examTypes"
+          placeholder="请输入开启考生"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="Plus"
+          @click="handleAdd"
+          v-hasPermi="['dz:control:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="Edit"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['dz:control:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="Delete"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['dz:control:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="Download"
+          @click="handleExport"
+          v-hasPermi="['dz:control:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="controlList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="ID" align="center" prop="id" />
+      <el-table-column label="省份" align="center" prop="location" />
+      <el-table-column label="开始时间" align="center" prop="startDate" />
+      <el-table-column label="结束时间" align="center" prop="endDate" />
+      <el-table-column label="是否生效(0:否,1:是)" align="center" prop="isValid" />
+      <el-table-column label="计划年度" align="center" prop="planYear" />
+      <el-table-column label="录取年度" align="center" prop="submitYear" />
+      <el-table-column label="开启考生" align="center" prop="examTypes" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['dz:control:edit']">修改</el-button>
+          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['dz:control:remove']">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    
+    <pagination
+      v-show="total>0"
+      :total="total"
+      v-model:page="queryParams.pageNum"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改单招省份状态对话框 -->
+    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
+      <el-form ref="controlRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="省份" prop="location">
+          <el-input v-model="form.location" placeholder="请输入省份" />
+        </el-form-item>
+        <el-form-item label="开始时间" prop="startDate">
+          <el-input v-model="form.startDate" placeholder="请输入开始时间" />
+        </el-form-item>
+        <el-form-item label="结束时间" prop="endDate">
+          <el-input v-model="form.endDate" placeholder="请输入结束时间" />
+        </el-form-item>
+        <el-form-item label="是否生效(0:否,1:是)" prop="isValid">
+          <el-input v-model="form.isValid" placeholder="请输入是否生效(0:否,1:是)" />
+        </el-form-item>
+        <el-form-item label="计划年度" prop="planYear">
+          <el-input v-model="form.planYear" placeholder="请输入计划年度" />
+        </el-form-item>
+        <el-form-item label="录取年度" prop="submitYear">
+          <el-input v-model="form.submitYear" placeholder="请输入录取年度" />
+        </el-form-item>
+        <el-form-item label="开启考生" prop="examTypes">
+          <el-input v-model="form.examTypes" placeholder="请输入开启考生" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Control">
+import { listControl, getControl, delControl, addControl, updateControl } from "@/api/dz/control"
+
+const { proxy } = getCurrentInstance()
+
+const controlList = ref([])
+const open = ref(false)
+const loading = ref(true)
+const showSearch = ref(true)
+const ids = ref([])
+const single = ref(true)
+const multiple = ref(true)
+const total = ref(0)
+const title = ref("")
+
+const data = reactive({
+  form: {},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    location: null,
+    startDate: null,
+    endDate: null,
+    isValid: null,
+    planYear: null,
+    submitYear: null,
+    examTypes: null
+  },
+  rules: {
+    isValid: [
+      { required: true, message: "是否生效(0:否,1:是)不能为空", trigger: "blur" }
+    ],
+  }
+})
+
+const { queryParams, form, rules } = toRefs(data)
+
+/** 查询单招省份状态列表 */
+function getList() {
+  loading.value = true
+  listControl(queryParams.value).then(response => {
+    controlList.value = response.rows
+    total.value = response.total
+    loading.value = false
+  })
+}
+
+// 取消按钮
+function cancel() {
+  open.value = false
+  reset()
+}
+
+// 表单重置
+function reset() {
+  form.value = {
+    id: null,
+    location: null,
+    startDate: null,
+    endDate: null,
+    isValid: null,
+    planYear: null,
+    submitYear: null,
+    examTypes: null
+  }
+  proxy.resetForm("controlRef")
+}
+
+/** 搜索按钮操作 */
+function handleQuery() {
+  queryParams.value.pageNum = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+function resetQuery() {
+  proxy.resetForm("queryRef")
+  handleQuery()
+}
+
+// 多选框选中数据
+function handleSelectionChange(selection) {
+  ids.value = selection.map(item => item.id)
+  single.value = selection.length != 1
+  multiple.value = !selection.length
+}
+
+/** 新增按钮操作 */
+function handleAdd() {
+  reset()
+  open.value = true
+  title.value = "添加单招省份状态"
+}
+
+/** 修改按钮操作 */
+function handleUpdate(row) {
+  reset()
+  const _id = row.id || ids.value
+  getControl(_id).then(response => {
+    form.value = response.data
+    open.value = true
+    title.value = "修改单招省份状态"
+  })
+}
+
+/** 提交按钮 */
+function submitForm() {
+  proxy.$refs["controlRef"].validate(valid => {
+    if (valid) {
+      if (form.value.id != null) {
+        updateControl(form.value).then(response => {
+          proxy.$modal.msgSuccess("修改成功")
+          open.value = false
+          getList()
+        })
+      } else {
+        addControl(form.value).then(response => {
+          proxy.$modal.msgSuccess("新增成功")
+          open.value = false
+          getList()
+        })
+      }
+    }
+  })
+}
+
+/** 删除按钮操作 */
+function handleDelete(row) {
+  const _ids = row.id || ids.value
+  proxy.$modal.confirm('是否确认删除单招省份状态编号为"' + _ids + '"的数据项?').then(function() {
+    return delControl(_ids)
+  }).then(() => {
+    getList()
+    proxy.$modal.msgSuccess("删除成功")
+  }).catch(() => {})
+}
+
+/** 导出按钮操作 */
+function handleExport() {
+  proxy.download('dz/control/export', {
+    ...queryParams.value
+  }, `control_${new Date().getTime()}.xlsx`)
+}
+
+getList()
+</script>

+ 393 - 0
back-ui/src/views/dz/open/index.vue

@@ -0,0 +1,393 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="代理" prop="agentId">
+        <el-input
+          v-model="queryParams.agentId"
+          placeholder="请输入代理"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="起始卡号" prop="startNo">
+        <el-input
+          v-model="queryParams.startNo"
+          placeholder="请输入起始卡号"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="截至卡号" prop="endNo">
+        <el-input
+          v-model="queryParams.endNo"
+          placeholder="请输入截至卡号"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="结束日期" prop="endDate">
+        <el-date-picker clearable
+          v-model="queryParams.endDate"
+          type="date"
+          value-format="YYYY-MM-DD"
+          placeholder="请选择结束日期">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="校区" prop="schoolId">
+        <el-input
+          v-model="queryParams.schoolId"
+          placeholder="请输入校区"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="发件人" prop="sender">
+        <el-input
+          v-model="queryParams.sender"
+          placeholder="请输入发件人"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="重新开卡:0否,1是" prop="isReopen">
+        <el-select v-model="queryParams.isReopen" placeholder="请选择重新开卡:0否,1是" clearable>
+          <el-option
+            v-for="dict in sys_normal_disable"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="卡类型,对应card_type" prop="cardType">
+        <el-select v-model="queryParams.cardType" placeholder="请选择卡类型,对应card_type" clearable>
+          <el-option
+            v-for="dict in card_type"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="状态(0:无效,1:审核结束,2:审核中)" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择状态(0:无效,1:审核结束,2:审核中)" clearable>
+          <el-option
+            v-for="dict in sys_yes_no"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="Plus"
+          @click="handleAdd"
+          v-hasPermi="['dz:open:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="Edit"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['dz:open:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="Delete"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['dz:open:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="Download"
+          @click="handleExport"
+          v-hasPermi="['dz:open:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="openList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="标识" align="center" prop="id" />
+      <el-table-column label="代理" align="center" prop="agentId" />
+      <el-table-column label="起始卡号" align="center" prop="startNo" />
+      <el-table-column label="截至卡号" align="center" prop="endNo" />
+      <el-table-column label="结束日期" align="center" prop="endDate" width="180">
+        <template #default="scope">
+          <span>{{ parseTime(scope.row.endDate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="校区" align="center" prop="schoolId" />
+      <el-table-column label="发件人" align="center" prop="sender" />
+      <el-table-column label="重新开卡:0否,1是" align="center" prop="isReopen">
+        <template #default="scope">
+          <dict-tag :options="sys_normal_disable" :value="scope.row.isReopen"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="卡类型,对应card_type" align="center" prop="cardType">
+        <template #default="scope">
+          <dict-tag :options="card_type" :value="scope.row.cardType"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="状态(0:无效,1:审核结束,2:审核中)" align="center" prop="status">
+        <template #default="scope">
+          <dict-tag :options="sys_yes_no" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['dz:open:edit']">修改</el-button>
+          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['dz:open:remove']">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    
+    <pagination
+      v-show="total>0"
+      :total="total"
+      v-model:page="queryParams.pageNum"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改开卡申请对话框 -->
+    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
+      <el-form ref="openRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="代理" prop="agentId">
+          <el-input v-model="form.agentId" placeholder="请输入代理" />
+        </el-form-item>
+        <el-form-item label="起始卡号" prop="startNo">
+          <el-input v-model="form.startNo" placeholder="请输入起始卡号" />
+        </el-form-item>
+        <el-form-item label="截至卡号" prop="endNo">
+          <el-input v-model="form.endNo" placeholder="请输入截至卡号" />
+        </el-form-item>
+        <el-form-item label="结束日期" prop="endDate">
+          <el-date-picker clearable
+            v-model="form.endDate"
+            type="date"
+            value-format="YYYY-MM-DD"
+            placeholder="请选择结束日期">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="校区" prop="schoolId">
+          <el-input v-model="form.schoolId" placeholder="请输入校区" />
+        </el-form-item>
+        <el-form-item label="发件人" prop="sender">
+          <el-input v-model="form.sender" placeholder="请输入发件人" />
+        </el-form-item>
+        <el-form-item label="重新开卡:0否,1是" prop="isReopen">
+          <el-radio-group v-model="form.isReopen">
+            <el-radio
+              v-for="dict in sys_normal_disable"
+              :key="dict.value"
+              :label="parseInt(dict.value)"
+            >{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="卡类型,对应card_type" prop="cardType">
+          <el-select v-model="form.cardType" placeholder="请选择卡类型,对应card_type">
+            <el-option
+              v-for="dict in card_type"
+              :key="dict.value"
+              :label="dict.label"
+              :value="parseInt(dict.value)"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="状态(0:无效,1:审核结束,2:审核中)" prop="status">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in sys_yes_no"
+              :key="dict.value"
+              :label="parseInt(dict.value)"
+            >{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Open">
+import { listOpen, getOpen, delOpen, addOpen, updateOpen } from "@/api/dz/open"
+
+const { proxy } = getCurrentInstance()
+const { sys_yes_no, sys_normal_disable, card_type } = proxy.useDict('sys_yes_no', 'sys_normal_disable', 'card_type')
+
+const openList = ref([])
+const open = ref(false)
+const loading = ref(true)
+const showSearch = ref(true)
+const ids = ref([])
+const single = ref(true)
+const multiple = ref(true)
+const total = ref(0)
+const title = ref("")
+
+const data = reactive({
+  form: {},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    agentId: null,
+    startNo: null,
+    endNo: null,
+    endDate: null,
+    schoolId: null,
+    sender: null,
+    isReopen: null,
+    cardType: null,
+    status: null
+  },
+  rules: {
+    createTime: [
+      { required: true, message: "申请时间不能为空", trigger: "blur" }
+    ],
+    status: [
+      { required: true, message: "状态(0:无效,1:审核结束,2:审核中)不能为空", trigger: "change" }
+    ]
+  }
+})
+
+const { queryParams, form, rules } = toRefs(data)
+
+/** 查询开卡申请列表 */
+function getList() {
+  loading.value = true
+  listOpen(queryParams.value).then(response => {
+    openList.value = response.rows
+    total.value = response.total
+    loading.value = false
+  })
+}
+
+// 取消按钮
+function cancel() {
+  open.value = false
+  reset()
+}
+
+// 表单重置
+function reset() {
+  form.value = {
+    id: null,
+    agentId: null,
+    startNo: null,
+    endNo: null,
+    endDate: null,
+    schoolId: null,
+    sender: null,
+    createTime: null,
+    isReopen: null,
+    cardType: null,
+    status: null
+  }
+  proxy.resetForm("openRef")
+}
+
+/** 搜索按钮操作 */
+function handleQuery() {
+  queryParams.value.pageNum = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+function resetQuery() {
+  proxy.resetForm("queryRef")
+  handleQuery()
+}
+
+// 多选框选中数据
+function handleSelectionChange(selection) {
+  ids.value = selection.map(item => item.id)
+  single.value = selection.length != 1
+  multiple.value = !selection.length
+}
+
+/** 新增按钮操作 */
+function handleAdd() {
+  reset()
+  open.value = true
+  title.value = "添加开卡申请"
+}
+
+/** 修改按钮操作 */
+function handleUpdate(row) {
+  reset()
+  const _id = row.id || ids.value
+  getOpen(_id).then(response => {
+    form.value = response.data
+    open.value = true
+    title.value = "修改开卡申请"
+  })
+}
+
+/** 提交按钮 */
+function submitForm() {
+  proxy.$refs["openRef"].validate(valid => {
+    if (valid) {
+      if (form.value.id != null) {
+        updateOpen(form.value).then(response => {
+          proxy.$modal.msgSuccess("修改成功")
+          open.value = false
+          getList()
+        })
+      } else {
+        addOpen(form.value).then(response => {
+          proxy.$modal.msgSuccess("新增成功")
+          open.value = false
+          getList()
+        })
+      }
+    }
+  })
+}
+
+/** 删除按钮操作 */
+function handleDelete(row) {
+  const _ids = row.id || ids.value
+  proxy.$modal.confirm('是否确认删除开卡申请编号为"' + _ids + '"的数据项?').then(function() {
+    return delOpen(_ids)
+  }).then(() => {
+    getList()
+    proxy.$modal.msgSuccess("删除成功")
+  }).catch(() => {})
+}
+
+/** 导出按钮操作 */
+function handleExport() {
+  proxy.download('dz/open/export', {
+    ...queryParams.value
+  }, `open_${new Date().getTime()}.xlsx`)
+}
+
+getList()
+</script>

+ 619 - 0
back-ui/src/views/dz/orders/index.vue

@@ -0,0 +1,619 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="订单号" prop="code">
+        <el-input
+          v-model="queryParams.code"
+          placeholder="请输入订单号"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="传微信单号" prop="outTradeNo">
+        <el-input
+          v-model="queryParams.outTradeNo"
+          placeholder="请输入传微信单号"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="二维码标识" prop="qrcodeId">
+        <el-input
+          v-model="queryParams.qrcodeId"
+          placeholder="请输入二维码标识"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="电子卡" prop="cardId">
+        <el-input
+          v-model="queryParams.cardId"
+          placeholder="请输入电子卡"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="账号" prop="cardNo">
+        <el-input
+          v-model="queryParams.cardNo"
+          placeholder="请输入账号"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="价目标识" prop="year">
+        <el-input
+          v-model="queryParams.year"
+          placeholder="请输入价目标识"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="手机号码" prop="phonenumber">
+        <el-input
+          v-model="queryParams.phonenumber"
+          placeholder="请输入手机号码"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="微信订单号" prop="transactionId">
+        <el-input
+          v-model="queryParams.transactionId"
+          placeholder="请输入微信订单号"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="用户" prop="customerCode">
+        <el-input
+          v-model="queryParams.customerCode"
+          placeholder="请输入用户"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="失效期" prop="outTime">
+        <el-date-picker clearable
+          v-model="queryParams.outTime"
+          type="date"
+          value-format="YYYY-MM-DD"
+          placeholder="请选择失效期">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="单价" prop="price">
+        <el-input
+          v-model="queryParams.price"
+          placeholder="请输入单价"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="数量" prop="num">
+        <el-input
+          v-model="queryParams.num"
+          placeholder="请输入数量"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="金额" prop="fee">
+        <el-input
+          v-model="queryParams.fee"
+          placeholder="请输入金额"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="应付金额" prop="totalFee">
+        <el-input
+          v-model="queryParams.totalFee"
+          placeholder="请输入应付金额"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="实付金额" prop="payFee">
+        <el-input
+          v-model="queryParams.payFee"
+          placeholder="请输入实付金额"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createTime">
+        <el-date-picker clearable
+          v-model="queryParams.createTime"
+          type="date"
+          value-format="YYYY-MM-DD"
+          placeholder="请选择创建时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="创建者" prop="creator">
+        <el-input
+          v-model="queryParams.creator"
+          placeholder="请输入创建者"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="描述" prop="body">
+        <el-input
+          v-model="queryParams.body"
+          placeholder="请输入描述"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="附加数据" prop="attach">
+        <el-input
+          v-model="queryParams.attach"
+          placeholder="请输入附加数据"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="微信预支付标识" prop="prepayId">
+        <el-input
+          v-model="queryParams.prepayId"
+          placeholder="请输入微信预支付标识"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="支付者" prop="payer">
+        <el-input
+          v-model="queryParams.payer"
+          placeholder="请输入支付者"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="支付时间" prop="payTime">
+        <el-date-picker clearable
+          v-model="queryParams.payTime"
+          type="date"
+          value-format="YYYY-MM-DD"
+          placeholder="请选择支付时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="确认时间" prop="syncTime">
+        <el-date-picker clearable
+          v-model="queryParams.syncTime"
+          type="date"
+          value-format="YYYY-MM-DD"
+          placeholder="请选择确认时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="状态(-2:已退费,-1:支付失败,0:无效,1:未支付,2:已支付)" prop="status">
+        <el-input
+          v-model="queryParams.status"
+          placeholder="请输入状态(-2:已退费,-1:支付失败,0:无效,1:未支付,2:已支付)"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="Plus"
+          @click="handleAdd"
+          v-hasPermi="['dz:orders:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="Edit"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['dz:orders:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="Delete"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['dz:orders:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="Download"
+          @click="handleExport"
+          v-hasPermi="['dz:orders:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="ordersList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="${comment}" align="center" prop="id" />
+      <el-table-column label="订单号" align="center" prop="code" />
+      <el-table-column label="传微信单号" align="center" prop="outTradeNo" />
+      <el-table-column label="二维码标识" align="center" prop="qrcodeId" />
+      <el-table-column label="${comment}" align="center" prop="type" />
+      <el-table-column label="电子卡" align="center" prop="cardId" />
+      <el-table-column label="账号" align="center" prop="cardNo" />
+      <el-table-column label="价目标识" align="center" prop="year" />
+      <el-table-column label="手机号码" align="center" prop="phonenumber" />
+      <el-table-column label="微信订单号" align="center" prop="transactionId" />
+      <el-table-column label="用户" align="center" prop="customerCode" />
+      <el-table-column label="失效期" align="center" prop="outTime" width="180">
+        <template #default="scope">
+          <span>{{ parseTime(scope.row.outTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="单价" align="center" prop="price" />
+      <el-table-column label="数量" align="center" prop="num" />
+      <el-table-column label="金额" align="center" prop="fee" />
+      <el-table-column label="应付金额" align="center" prop="totalFee" />
+      <el-table-column label="实付金额" align="center" prop="payFee" />
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+        <template #default="scope">
+          <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建者" align="center" prop="creator" />
+      <el-table-column label="描述" align="center" prop="body" />
+      <el-table-column label="详情" align="center" prop="detail" />
+      <el-table-column label="附加数据" align="center" prop="attach" />
+      <el-table-column label="微信预支付标识" align="center" prop="prepayId" />
+      <el-table-column label="支付者" align="center" prop="payer" />
+      <el-table-column label="支付时间" align="center" prop="payTime" width="180">
+        <template #default="scope">
+          <span>{{ parseTime(scope.row.payTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="支付回调结果" align="center" prop="feedBack" />
+      <el-table-column label="确认时间" align="center" prop="syncTime" width="180">
+        <template #default="scope">
+          <span>{{ parseTime(scope.row.syncTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="状态(-2:已退费,-1:支付失败,0:无效,1:未支付,2:已支付)" align="center" prop="status" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['dz:orders:edit']">修改</el-button>
+          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['dz:orders:remove']">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    
+    <pagination
+      v-show="total>0"
+      :total="total"
+      v-model:page="queryParams.pageNum"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改订单对话框 -->
+    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
+      <el-form ref="ordersRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="订单号" prop="code">
+          <el-input v-model="form.code" placeholder="请输入订单号" />
+        </el-form-item>
+        <el-form-item label="传微信单号" prop="outTradeNo">
+          <el-input v-model="form.outTradeNo" placeholder="请输入传微信单号" />
+        </el-form-item>
+        <el-form-item label="二维码标识" prop="qrcodeId">
+          <el-input v-model="form.qrcodeId" placeholder="请输入二维码标识" />
+        </el-form-item>
+        <el-form-item label="电子卡" prop="cardId">
+          <el-input v-model="form.cardId" placeholder="请输入电子卡" />
+        </el-form-item>
+        <el-form-item label="账号" prop="cardNo">
+          <el-input v-model="form.cardNo" placeholder="请输入账号" />
+        </el-form-item>
+        <el-form-item label="价目标识" prop="year">
+          <el-input v-model="form.year" placeholder="请输入价目标识" />
+        </el-form-item>
+        <el-form-item label="手机号码" prop="phonenumber">
+          <el-input v-model="form.phonenumber" placeholder="请输入手机号码" />
+        </el-form-item>
+        <el-form-item label="微信订单号" prop="transactionId">
+          <el-input v-model="form.transactionId" placeholder="请输入微信订单号" />
+        </el-form-item>
+        <el-form-item label="用户" prop="customerCode">
+          <el-input v-model="form.customerCode" placeholder="请输入用户" />
+        </el-form-item>
+        <el-form-item label="失效期" prop="outTime">
+          <el-date-picker clearable
+            v-model="form.outTime"
+            type="date"
+            value-format="YYYY-MM-DD"
+            placeholder="请选择失效期">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="单价" prop="price">
+          <el-input v-model="form.price" placeholder="请输入单价" />
+        </el-form-item>
+        <el-form-item label="数量" prop="num">
+          <el-input v-model="form.num" placeholder="请输入数量" />
+        </el-form-item>
+        <el-form-item label="金额" prop="fee">
+          <el-input v-model="form.fee" placeholder="请输入金额" />
+        </el-form-item>
+        <el-form-item label="应付金额" prop="totalFee">
+          <el-input v-model="form.totalFee" placeholder="请输入应付金额" />
+        </el-form-item>
+        <el-form-item label="实付金额" prop="payFee">
+          <el-input v-model="form.payFee" placeholder="请输入实付金额" />
+        </el-form-item>
+        <el-form-item label="创建者" prop="creator">
+          <el-input v-model="form.creator" placeholder="请输入创建者" />
+        </el-form-item>
+        <el-form-item label="描述" prop="body">
+          <el-input v-model="form.body" placeholder="请输入描述" />
+        </el-form-item>
+        <el-form-item label="详情" prop="detail">
+          <el-input v-model="form.detail" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="附加数据" prop="attach">
+          <el-input v-model="form.attach" placeholder="请输入附加数据" />
+        </el-form-item>
+        <el-form-item label="微信预支付标识" prop="prepayId">
+          <el-input v-model="form.prepayId" placeholder="请输入微信预支付标识" />
+        </el-form-item>
+        <el-form-item label="支付者" prop="payer">
+          <el-input v-model="form.payer" placeholder="请输入支付者" />
+        </el-form-item>
+        <el-form-item label="支付时间" prop="payTime">
+          <el-date-picker clearable
+            v-model="form.payTime"
+            type="date"
+            value-format="YYYY-MM-DD"
+            placeholder="请选择支付时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="支付回调结果" prop="feedBack">
+          <el-input v-model="form.feedBack" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="确认时间" prop="syncTime">
+          <el-date-picker clearable
+            v-model="form.syncTime"
+            type="date"
+            value-format="YYYY-MM-DD"
+            placeholder="请选择确认时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="状态(-2:已退费,-1:支付失败,0:无效,1:未支付,2:已支付)" prop="status">
+          <el-input v-model="form.status" placeholder="请输入状态(-2:已退费,-1:支付失败,0:无效,1:未支付,2:已支付)" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Orders">
+import { listOrders, getOrders, delOrders, addOrders, updateOrders } from "@/api/dz/orders"
+
+const { proxy } = getCurrentInstance()
+
+const ordersList = ref([])
+const open = ref(false)
+const loading = ref(true)
+const showSearch = ref(true)
+const ids = ref([])
+const single = ref(true)
+const multiple = ref(true)
+const total = ref(0)
+const title = ref("")
+
+const data = reactive({
+  form: {},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    code: null,
+    outTradeNo: null,
+    qrcodeId: null,
+    type: null,
+    cardId: null,
+    cardNo: null,
+    year: null,
+    phonenumber: null,
+    transactionId: null,
+    customerCode: null,
+    outTime: null,
+    price: null,
+    num: null,
+    fee: null,
+    totalFee: null,
+    payFee: null,
+    createTime: null,
+    creator: null,
+    body: null,
+    detail: null,
+    attach: null,
+    prepayId: null,
+    payer: null,
+    payTime: null,
+    feedBack: null,
+    syncTime: null,
+    status: null
+  },
+  rules: {
+    code: [
+      { required: true, message: "订单号不能为空", trigger: "blur" }
+    ],
+    year: [
+      { required: true, message: "价目标识不能为空", trigger: "blur" }
+    ],
+    price: [
+      { required: true, message: "单价不能为空", trigger: "blur" }
+    ],
+    num: [
+      { required: true, message: "数量不能为空", trigger: "blur" }
+    ],
+    fee: [
+      { required: true, message: "金额不能为空", trigger: "blur" }
+    ],
+    totalFee: [
+      { required: true, message: "应付金额不能为空", trigger: "blur" }
+    ],
+    payFee: [
+      { required: true, message: "实付金额不能为空", trigger: "blur" }
+    ],
+    createTime: [
+      { required: true, message: "创建时间不能为空", trigger: "blur" }
+    ],
+    status: [
+      { required: true, message: "状态(-2:已退费,-1:支付失败,0:无效,1:未支付,2:已支付)不能为空", trigger: "blur" }
+    ]
+  }
+})
+
+const { queryParams, form, rules } = toRefs(data)
+
+/** 查询订单列表 */
+function getList() {
+  loading.value = true
+  listOrders(queryParams.value).then(response => {
+    ordersList.value = response.rows
+    total.value = response.total
+    loading.value = false
+  })
+}
+
+// 取消按钮
+function cancel() {
+  open.value = false
+  reset()
+}
+
+// 表单重置
+function reset() {
+  form.value = {
+    id: null,
+    code: null,
+    outTradeNo: null,
+    qrcodeId: null,
+    type: null,
+    cardId: null,
+    cardNo: null,
+    year: null,
+    phonenumber: null,
+    transactionId: null,
+    customerCode: null,
+    outTime: null,
+    price: null,
+    num: null,
+    fee: null,
+    totalFee: null,
+    payFee: null,
+    createTime: null,
+    creator: null,
+    body: null,
+    detail: null,
+    attach: null,
+    prepayId: null,
+    payer: null,
+    payTime: null,
+    feedBack: null,
+    syncTime: null,
+    status: null
+  }
+  proxy.resetForm("ordersRef")
+}
+
+/** 搜索按钮操作 */
+function handleQuery() {
+  queryParams.value.pageNum = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+function resetQuery() {
+  proxy.resetForm("queryRef")
+  handleQuery()
+}
+
+// 多选框选中数据
+function handleSelectionChange(selection) {
+  ids.value = selection.map(item => item.id)
+  single.value = selection.length != 1
+  multiple.value = !selection.length
+}
+
+/** 新增按钮操作 */
+function handleAdd() {
+  reset()
+  open.value = true
+  title.value = "添加订单"
+}
+
+/** 修改按钮操作 */
+function handleUpdate(row) {
+  reset()
+  const _id = row.id || ids.value
+  getOrders(_id).then(response => {
+    form.value = response.data
+    open.value = true
+    title.value = "修改订单"
+  })
+}
+
+/** 提交按钮 */
+function submitForm() {
+  proxy.$refs["ordersRef"].validate(valid => {
+    if (valid) {
+      if (form.value.id != null) {
+        updateOrders(form.value).then(response => {
+          proxy.$modal.msgSuccess("修改成功")
+          open.value = false
+          getList()
+        })
+      } else {
+        addOrders(form.value).then(response => {
+          proxy.$modal.msgSuccess("新增成功")
+          open.value = false
+          getList()
+        })
+      }
+    }
+  })
+}
+
+/** 删除按钮操作 */
+function handleDelete(row) {
+  const _ids = row.id || ids.value
+  proxy.$modal.confirm('是否确认删除订单编号为"' + _ids + '"的数据项?').then(function() {
+    return delOrders(_ids)
+  }).then(() => {
+    getList()
+    proxy.$modal.msgSuccess("删除成功")
+  }).catch(() => {})
+}
+
+/** 导出按钮操作 */
+function handleExport() {
+  proxy.download('dz/orders/export', {
+    ...queryParams.value
+  }, `orders_${new Date().getTime()}.xlsx`)
+}
+
+getList()
+</script>

+ 310 - 0
back-ui/src/views/dz/school/index.vue

@@ -0,0 +1,310 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入名称"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="机构ID" prop="deptId">
+        <el-input
+          v-model="queryParams.deptId"
+          placeholder="请输入机构ID"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="地域" prop="location">
+        <el-input
+          v-model="queryParams.location"
+          placeholder="请输入地域"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="省" prop="pro">
+        <el-input
+          v-model="queryParams.pro"
+          placeholder="请输入省"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="市" prop="city">
+        <el-input
+          v-model="queryParams.city"
+          placeholder="请输入市"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="区" prop="area">
+        <el-input
+          v-model="queryParams.area"
+          placeholder="请输入区"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="Plus"
+          @click="handleAdd"
+          v-hasPermi="['dz:school:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="Edit"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['dz:school:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="Delete"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['dz:school:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="Download"
+          @click="handleExport"
+          v-hasPermi="['dz:school:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="schoolList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="${comment}" align="center" prop="id" />
+      <el-table-column label="名称" align="center" prop="name" />
+      <el-table-column label="机构ID" align="center" prop="deptId" />
+      <el-table-column label="地域" align="center" prop="location" />
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="省" align="center" prop="pro" />
+      <el-table-column label="市" align="center" prop="city" />
+      <el-table-column label="区" align="center" prop="area" />
+      <el-table-column label="状态(0:无效,1:有效)" align="center" prop="status" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['dz:school:edit']">修改</el-button>
+          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['dz:school:remove']">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    
+    <pagination
+      v-show="total>0"
+      :total="total"
+      v-model:page="queryParams.pageNum"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改机构校区对话框 -->
+    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
+      <el-form ref="schoolRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="名称" prop="name">
+          <el-input v-model="form.name" placeholder="请输入名称" />
+        </el-form-item>
+        <el-form-item label="机构ID" prop="deptId">
+          <el-input v-model="form.deptId" placeholder="请输入机构ID" />
+        </el-form-item>
+        <el-form-item label="地域" prop="location">
+          <el-input v-model="form.location" placeholder="请输入地域" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" placeholder="请输入备注" />
+        </el-form-item>
+        <el-form-item label="省" prop="pro">
+          <el-input v-model="form.pro" placeholder="请输入省" />
+        </el-form-item>
+        <el-form-item label="市" prop="city">
+          <el-input v-model="form.city" placeholder="请输入市" />
+        </el-form-item>
+        <el-form-item label="区" prop="area">
+          <el-input v-model="form.area" placeholder="请输入区" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="School">
+import { listSchool, getSchool, delSchool, addSchool, updateSchool } from "@/api/dz/school"
+
+const { proxy } = getCurrentInstance()
+
+const schoolList = ref([])
+const open = ref(false)
+const loading = ref(true)
+const showSearch = ref(true)
+const ids = ref([])
+const single = ref(true)
+const multiple = ref(true)
+const total = ref(0)
+const title = ref("")
+
+const data = reactive({
+  form: {},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    name: null,
+    deptId: null,
+    location: null,
+    pro: null,
+    city: null,
+    area: null,
+    status: null,
+  },
+  rules: {
+    status: [
+      { required: true, message: "状态(0:无效,1:有效)不能为空", trigger: "change" }
+    ],
+  }
+})
+
+const { queryParams, form, rules } = toRefs(data)
+
+/** 查询机构校区列表 */
+function getList() {
+  loading.value = true
+  listSchool(queryParams.value).then(response => {
+    schoolList.value = response.rows
+    total.value = response.total
+    loading.value = false
+  })
+}
+
+// 取消按钮
+function cancel() {
+  open.value = false
+  reset()
+}
+
+// 表单重置
+function reset() {
+  form.value = {
+    id: null,
+    name: null,
+    deptId: null,
+    location: null,
+    remark: null,
+    pro: null,
+    city: null,
+    area: null,
+    status: null,
+    createTime: null,
+    updateTime: null
+  }
+  proxy.resetForm("schoolRef")
+}
+
+/** 搜索按钮操作 */
+function handleQuery() {
+  queryParams.value.pageNum = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+function resetQuery() {
+  proxy.resetForm("queryRef")
+  handleQuery()
+}
+
+// 多选框选中数据
+function handleSelectionChange(selection) {
+  ids.value = selection.map(item => item.id)
+  single.value = selection.length != 1
+  multiple.value = !selection.length
+}
+
+/** 新增按钮操作 */
+function handleAdd() {
+  reset()
+  open.value = true
+  title.value = "添加机构校区"
+}
+
+/** 修改按钮操作 */
+function handleUpdate(row) {
+  reset()
+  const _id = row.id || ids.value
+  getSchool(_id).then(response => {
+    form.value = response.data
+    open.value = true
+    title.value = "修改机构校区"
+  })
+}
+
+/** 提交按钮 */
+function submitForm() {
+  proxy.$refs["schoolRef"].validate(valid => {
+    if (valid) {
+      if (form.value.id != null) {
+        updateSchool(form.value).then(response => {
+          proxy.$modal.msgSuccess("修改成功")
+          open.value = false
+          getList()
+        })
+      } else {
+        addSchool(form.value).then(response => {
+          proxy.$modal.msgSuccess("新增成功")
+          open.value = false
+          getList()
+        })
+      }
+    }
+  })
+}
+
+/** 删除按钮操作 */
+function handleDelete(row) {
+  const _ids = row.id || ids.value
+  proxy.$modal.confirm('是否确认删除机构校区编号为"' + _ids + '"的数据项?').then(function() {
+    return delSchool(_ids)
+  }).then(() => {
+    getList()
+    proxy.$modal.msgSuccess("删除成功")
+  }).catch(() => {})
+}
+
+/** 导出按钮操作 */
+function handleExport() {
+  proxy.download('dz/school/export', {
+    ...queryParams.value
+  }, `school_${new Date().getTime()}.xlsx`)
+}
+
+getList()
+</script>

+ 244 - 0
back-ui/src/views/dz/teacher/index.vue

@@ -0,0 +1,244 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="用户ID" prop="userId">
+        <el-input
+          v-model="queryParams.userId"
+          placeholder="请输入用户ID"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="教师姓名" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入教师姓名"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="Plus"
+          @click="handleAdd"
+          v-hasPermi="['dz:teacher:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="Edit"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['dz:teacher:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="Delete"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['dz:teacher:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="Download"
+          @click="handleExport"
+          v-hasPermi="['dz:teacher:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="teacherList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="老师id" align="center" prop="teacherId" />
+      <el-table-column label="用户ID" align="center" prop="userId" />
+      <el-table-column label="所在校区" align="center" prop="schoolId" />
+      <el-table-column label="教师姓名" align="center" prop="name" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['dz:teacher:edit']">修改</el-button>
+          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['dz:teacher:remove']">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    
+    <pagination
+      v-show="total>0"
+      :total="total"
+      v-model:page="queryParams.pageNum"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改老师对话框 -->
+    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
+      <el-form ref="teacherRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="用户ID" prop="userId">
+          <el-input v-model="form.userId" placeholder="请输入用户ID" />
+        </el-form-item>
+        <el-form-item label="教师姓名" prop="name">
+          <el-input v-model="form.name" placeholder="请输入教师姓名" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Teacher">
+import { listTeacher, getTeacher, delTeacher, addTeacher, updateTeacher } from "@/api/dz/teacher"
+
+const { proxy } = getCurrentInstance()
+
+const teacherList = ref([])
+const open = ref(false)
+const loading = ref(true)
+const showSearch = ref(true)
+const ids = ref([])
+const single = ref(true)
+const multiple = ref(true)
+const total = ref(0)
+const title = ref("")
+
+const data = reactive({
+  form: {},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    userId: null,
+    schoolId: null,
+    name: null
+  },
+  rules: {
+  }
+})
+
+const { queryParams, form, rules } = toRefs(data)
+
+/** 查询老师列表 */
+function getList() {
+  loading.value = true
+  listTeacher(queryParams.value).then(response => {
+    teacherList.value = response.rows
+    total.value = response.total
+    loading.value = false
+  })
+}
+
+// 取消按钮
+function cancel() {
+  open.value = false
+  reset()
+}
+
+// 表单重置
+function reset() {
+  form.value = {
+    teacherId: null,
+    userId: null,
+    schoolId: null,
+    name: null
+  }
+  proxy.resetForm("teacherRef")
+}
+
+/** 搜索按钮操作 */
+function handleQuery() {
+  queryParams.value.pageNum = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+function resetQuery() {
+  proxy.resetForm("queryRef")
+  handleQuery()
+}
+
+// 多选框选中数据
+function handleSelectionChange(selection) {
+  ids.value = selection.map(item => item.teacherId)
+  single.value = selection.length != 1
+  multiple.value = !selection.length
+}
+
+/** 新增按钮操作 */
+function handleAdd() {
+  reset()
+  open.value = true
+  title.value = "添加老师"
+}
+
+/** 修改按钮操作 */
+function handleUpdate(row) {
+  reset()
+  const _teacherId = row.teacherId || ids.value
+  getTeacher(_teacherId).then(response => {
+    form.value = response.data
+    open.value = true
+    title.value = "修改老师"
+  })
+}
+
+/** 提交按钮 */
+function submitForm() {
+  proxy.$refs["teacherRef"].validate(valid => {
+    if (valid) {
+      if (form.value.teacherId != null) {
+        updateTeacher(form.value).then(response => {
+          proxy.$modal.msgSuccess("修改成功")
+          open.value = false
+          getList()
+        })
+      } else {
+        addTeacher(form.value).then(response => {
+          proxy.$modal.msgSuccess("新增成功")
+          open.value = false
+          getList()
+        })
+      }
+    }
+  })
+}
+
+/** 删除按钮操作 */
+function handleDelete(row) {
+  const _teacherIds = row.teacherId || ids.value
+  proxy.$modal.confirm('是否确认删除老师编号为"' + _teacherIds + '"的数据项?').then(function() {
+    return delTeacher(_teacherIds)
+  }).then(() => {
+    getList()
+    proxy.$modal.msgSuccess("删除成功")
+  }).catch(() => {})
+}
+
+/** 导出按钮操作 */
+function handleExport() {
+  proxy.download('dz/teacher/export', {
+    ...queryParams.value
+  }, `teacher_${new Date().getTime()}.xlsx`)
+}
+
+getList()
+</script>

+ 272 - 0
back-ui/src/views/dz/teacherclass/index.vue

@@ -0,0 +1,272 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="老师id" prop="teacherId">
+        <el-input
+          v-model="queryParams.teacherId"
+          placeholder="请输入老师id"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="班级id" prop="classesId">
+        <el-input
+          v-model="queryParams.classesId"
+          placeholder="请输入班级id"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="结束日期" prop="outDate">
+        <el-date-picker clearable
+          v-model="queryParams.outDate"
+          type="date"
+          value-format="YYYY-MM-DD"
+          placeholder="请选择结束日期">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="Plus"
+          @click="handleAdd"
+          v-hasPermi="['dz:teacherclass:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="Edit"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['dz:teacherclass:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="Delete"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['dz:teacherclass:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="Download"
+          @click="handleExport"
+          v-hasPermi="['dz:teacherclass:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="teacherclassList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="标识" align="center" prop="id" />
+      <el-table-column label="老师id" align="center" prop="teacherId" />
+      <el-table-column label="班级id" align="center" prop="classesId" />
+      <el-table-column label="有效状态" align="center" prop="status" />
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="结束日期" align="center" prop="outDate" width="180">
+        <template #default="scope">
+          <span>{{ parseTime(scope.row.outDate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['dz:teacherclass:edit']">修改</el-button>
+          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['dz:teacherclass:remove']">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    
+    <pagination
+      v-show="total>0"
+      :total="total"
+      v-model:page="queryParams.pageNum"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改教师班级关系对话框 -->
+    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
+      <el-form ref="teacherclassRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="老师id" prop="teacherId">
+          <el-input v-model="form.teacherId" placeholder="请输入老师id" />
+        </el-form-item>
+        <el-form-item label="班级id" prop="classesId">
+          <el-input v-model="form.classesId" placeholder="请输入班级id" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" placeholder="请输入备注" />
+        </el-form-item>
+        <el-form-item label="结束日期" prop="outDate">
+          <el-date-picker clearable
+            v-model="form.outDate"
+            type="date"
+            value-format="YYYY-MM-DD"
+            placeholder="请选择结束日期">
+          </el-date-picker>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Teacherclass">
+import { listTeacherclass, getTeacherclass, delTeacherclass, addTeacherclass, updateTeacherclass } from "@/api/dz/teacherclass"
+
+const { proxy } = getCurrentInstance()
+
+const teacherclassList = ref([])
+const open = ref(false)
+const loading = ref(true)
+const showSearch = ref(true)
+const ids = ref([])
+const single = ref(true)
+const multiple = ref(true)
+const total = ref(0)
+const title = ref("")
+
+const data = reactive({
+  form: {},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    teacherId: null,
+    classesId: null,
+    status: null,
+    outDate: null
+  },
+  rules: {
+  }
+})
+
+const { queryParams, form, rules } = toRefs(data)
+
+/** 查询教师班级关系列表 */
+function getList() {
+  loading.value = true
+  listTeacherclass(queryParams.value).then(response => {
+    teacherclassList.value = response.rows
+    total.value = response.total
+    loading.value = false
+  })
+}
+
+// 取消按钮
+function cancel() {
+  open.value = false
+  reset()
+}
+
+// 表单重置
+function reset() {
+  form.value = {
+    id: null,
+    teacherId: null,
+    classesId: null,
+    status: null,
+    remark: null,
+    outDate: null
+  }
+  proxy.resetForm("teacherclassRef")
+}
+
+/** 搜索按钮操作 */
+function handleQuery() {
+  queryParams.value.pageNum = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+function resetQuery() {
+  proxy.resetForm("queryRef")
+  handleQuery()
+}
+
+// 多选框选中数据
+function handleSelectionChange(selection) {
+  ids.value = selection.map(item => item.id)
+  single.value = selection.length != 1
+  multiple.value = !selection.length
+}
+
+/** 新增按钮操作 */
+function handleAdd() {
+  reset()
+  open.value = true
+  title.value = "添加教师班级关系"
+}
+
+/** 修改按钮操作 */
+function handleUpdate(row) {
+  reset()
+  const _id = row.id || ids.value
+  getTeacherclass(_id).then(response => {
+    form.value = response.data
+    open.value = true
+    title.value = "修改教师班级关系"
+  })
+}
+
+/** 提交按钮 */
+function submitForm() {
+  proxy.$refs["teacherclassRef"].validate(valid => {
+    if (valid) {
+      if (form.value.id != null) {
+        updateTeacherclass(form.value).then(response => {
+          proxy.$modal.msgSuccess("修改成功")
+          open.value = false
+          getList()
+        })
+      } else {
+        addTeacherclass(form.value).then(response => {
+          proxy.$modal.msgSuccess("新增成功")
+          open.value = false
+          getList()
+        })
+      }
+    }
+  })
+}
+
+/** 删除按钮操作 */
+function handleDelete(row) {
+  const _ids = row.id || ids.value
+  proxy.$modal.confirm('是否确认删除教师班级关系编号为"' + _ids + '"的数据项?').then(function() {
+    return delTeacherclass(_ids)
+  }).then(() => {
+    getList()
+    proxy.$modal.msgSuccess("删除成功")
+  }).catch(() => {})
+}
+
+/** 导出按钮操作 */
+function handleExport() {
+  proxy.download('dz/teacherclass/export', {
+    ...queryParams.value
+  }, `teacherclass_${new Date().getTime()}.xlsx`)
+}
+
+getList()
+</script>

+ 6 - 25
back-ui/src/views/index.vue

@@ -2,31 +2,10 @@
   <div class="app-container home">
     <el-row :gutter="20">
       <el-col :sm="24" :lg="12" style="padding-left: 20px">
-        <h2>若依后台管理框架</h2>
-        <p>
-          一直想做一款后台管理系统,看了很多优秀的开源项目但是发现没有合适自己的。于是利用空闲休息时间开始自己写一套后台系统。如此有了若依管理系统,她可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA等等,当然,您也可以对她进行深度定制,以做出更强系统。所有前端后台代码封装过后十分精简易上手,出错概率低。同时支持移动客户端访问。系统会陆续更新一些实用功能。
-        </p>
+        <h2>单招后台管理框架</h2>
         <p>
           <b>当前版本:</b> <span>v{{ version }}</span>
         </p>
-        <p>
-          <el-tag type="danger">&yen;免费开源</el-tag>
-        </p>
-        <p>
-          <el-button
-            type="primary"
-            icon="Cloudy"
-            plain
-            @click="goTarget('https://gitee.com/y_project/RuoYi-Vue')"
-            >访问码云</el-button
-          >
-          <el-button
-            icon="HomeFilled"
-            plain
-            @click="goTarget('http://ruoyi.vip')"
-            >访问主页</el-button
-          >
-        </p>
       </el-col>
 
       <el-col :sm="24" :lg="12" style="padding-left: 50px">
@@ -64,6 +43,7 @@
       </el-col>
     </el-row>
     <el-divider />
+    <!--
     <el-row :gutter="20">
       <el-col :xs="24" :sm="24" :md="12" :lg="8">
         <el-card class="update-log">
@@ -92,14 +72,14 @@
             <p>
               <i class="el-icon-chat-dot-round"></i> 微信:<a
                 href="javascript:;"
-                >/ *若依</a
+                >/ *单招</a
               >
             </p>
             <p>
               <i class="el-icon-money"></i> 支付宝:<a
                 href="javascript:;"
                 class="支付宝信息"
-                >/ *若依</a
+                >/ *单招</a
               >
             </p>
           </div>
@@ -1028,7 +1008,7 @@
             </el-collapse-item>
             <el-collapse-item title="v1.0.0 - 2019-10-08">
               <ol>
-                <li>若依前后端分离系统正式发布</li>
+                <li>单招前后端分离系统正式发布</li>
               </ol>
             </el-collapse-item>
           </el-collapse>
@@ -1054,6 +1034,7 @@
         </el-card>
       </el-col>
     </el-row>
+    -->
   </div>
 </template>
 

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

@@ -59,7 +59,7 @@
     </el-form>
     <!--  底部  -->
     <div class="el-login-footer">
-      <span>Copyright © 2018-2025 ruoyi.vip All Rights Reserved.</span>
+      <span>Copyright © 2023-2032 dz1kt.com All Rights Reserved.</span>
     </div>
   </div>
 </template>

+ 228 - 0
back-ui/src/views/system/blacklist/index.vue

@@ -0,0 +1,228 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="手机号" prop="phoneNo">
+        <el-input
+          v-model="queryParams.phoneNo"
+          placeholder="请输入手机号"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="Plus"
+          @click="handleAdd"
+          v-hasPermi="['system:blacklist:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="Edit"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['system:blacklist:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="Delete"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['system:blacklist:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="Download"
+          @click="handleExport"
+          v-hasPermi="['system:blacklist:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="blacklistList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="ID" align="center" prop="id" />
+      <el-table-column label="手机号" align="center" prop="phoneNo" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:blacklist:edit']">修改</el-button>
+          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:blacklist:remove']">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    
+    <pagination
+      v-show="total>0"
+      :total="total"
+      v-model:page="queryParams.pageNum"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改短信手机黑名单对话框 -->
+    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
+      <el-form ref="blacklistRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="手机号" prop="phoneNo">
+          <el-input v-model="form.phoneNo" placeholder="请输入手机号" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Blacklist">
+import { listBlacklist, getBlacklist, delBlacklist, addBlacklist, updateBlacklist } from "@/api/system/blacklist"
+
+const { proxy } = getCurrentInstance()
+
+const blacklistList = ref([])
+const open = ref(false)
+const loading = ref(true)
+const showSearch = ref(true)
+const ids = ref([])
+const single = ref(true)
+const multiple = ref(true)
+const total = ref(0)
+const title = ref("")
+
+const data = reactive({
+  form: {},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    phoneNo: null,
+  },
+  rules: {
+  }
+})
+
+const { queryParams, form, rules } = toRefs(data)
+
+/** 查询短信手机黑名单列表 */
+function getList() {
+  loading.value = true
+  listBlacklist(queryParams.value).then(response => {
+    blacklistList.value = response.rows
+    total.value = response.total
+    loading.value = false
+  })
+}
+
+// 取消按钮
+function cancel() {
+  open.value = false
+  reset()
+}
+
+// 表单重置
+function reset() {
+  form.value = {
+    id: null,
+    phoneNo: null,
+    createTime: null
+  }
+  proxy.resetForm("blacklistRef")
+}
+
+/** 搜索按钮操作 */
+function handleQuery() {
+  queryParams.value.pageNum = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+function resetQuery() {
+  proxy.resetForm("queryRef")
+  handleQuery()
+}
+
+// 多选框选中数据
+function handleSelectionChange(selection) {
+  ids.value = selection.map(item => item.id)
+  single.value = selection.length != 1
+  multiple.value = !selection.length
+}
+
+/** 新增按钮操作 */
+function handleAdd() {
+  reset()
+  open.value = true
+  title.value = "添加短信手机黑名单"
+}
+
+/** 修改按钮操作 */
+function handleUpdate(row) {
+  reset()
+  const _id = row.id || ids.value
+  getBlacklist(_id).then(response => {
+    form.value = response.data
+    open.value = true
+    title.value = "修改短信手机黑名单"
+  })
+}
+
+/** 提交按钮 */
+function submitForm() {
+  proxy.$refs["blacklistRef"].validate(valid => {
+    if (valid) {
+      if (form.value.id != null) {
+        updateBlacklist(form.value).then(response => {
+          proxy.$modal.msgSuccess("修改成功")
+          open.value = false
+          getList()
+        })
+      } else {
+        addBlacklist(form.value).then(response => {
+          proxy.$modal.msgSuccess("新增成功")
+          open.value = false
+          getList()
+        })
+      }
+    }
+  })
+}
+
+/** 删除按钮操作 */
+function handleDelete(row) {
+  const _ids = row.id || ids.value
+  proxy.$modal.confirm('是否确认删除短信手机黑名单编号为"' + _ids + '"的数据项?').then(function() {
+    return delBlacklist(_ids)
+  }).then(() => {
+    getList()
+    proxy.$modal.msgSuccess("删除成功")
+  }).catch(() => {})
+}
+
+/** 导出按钮操作 */
+function handleExport() {
+  proxy.download('system/blacklist/export', {
+    ...queryParams.value
+  }, `blacklist_${new Date().getTime()}.xlsx`)
+}
+
+getList()
+</script>

+ 17 - 11
back-ui/src/views/system/dept/index.vue

@@ -1,17 +1,17 @@
 <template>
    <div class="app-container">
       <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
-         <el-form-item label="部门名称" prop="deptName">
+         <el-form-item label="机构部门名称" prop="deptName">
             <el-input
                v-model="queryParams.deptName"
-               placeholder="请输入部门名称"
+               placeholder="请输入机构部门名称"
                clearable
                style="width: 200px"
                @keyup.enter="handleQuery"
             />
          </el-form-item>
          <el-form-item label="状态" prop="status">
-            <el-select v-model="queryParams.status" placeholder="部门状态" clearable style="width: 200px">
+            <el-select v-model="queryParams.status" placeholder="有效状态" clearable style="width: 200px">
                <el-option
                   v-for="dict in sys_normal_disable"
                   :key="dict.value"
@@ -55,7 +55,8 @@
          :default-expand-all="isExpandAll"
          :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
       >
-         <el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
+         <el-table-column prop="deptName" label="机构部门名称" width="260"></el-table-column>
+         <el-table-column prop="phone" label="机构电话" width="200"></el-table-column>
          <el-table-column prop="orderNum" label="排序" width="200"></el-table-column>
          <el-table-column prop="status" label="状态" width="100">
             <template #default="scope">
@@ -81,22 +82,27 @@
          <el-form ref="deptRef" :model="form" :rules="rules" label-width="80px">
             <el-row>
                <el-col :span="24" v-if="form.parentId !== 0">
-                  <el-form-item label="上级部门" prop="parentId">
+                  <el-form-item label="上级" prop="parentId">
                      <el-tree-select
                         v-model="form.parentId"
                         :data="deptOptions"
                         :props="{ value: 'deptId', label: 'deptName', children: 'children' }"
                         value-key="deptId"
-                        placeholder="选择上级部门"
+                        placeholder="选择上级"
                         check-strictly
                      />
                   </el-form-item>
                </el-col>
                <el-col :span="12">
-                  <el-form-item label="部门名称" prop="deptName">
-                     <el-input v-model="form.deptName" placeholder="请输入部门名称" />
+                  <el-form-item label="名称" prop="deptName">
+                     <el-input v-model="form.deptName" placeholder="请输入机构部门名称" />
                   </el-form-item>
                </el-col>
+              <el-col :span="12">
+                <el-form-item label="图标" prop="orderNum">
+                  <el-input controls-position="right" />
+                </el-form-item>
+              </el-col>
                <el-col :span="12">
                   <el-form-item label="显示排序" prop="orderNum">
                      <el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
@@ -108,8 +114,8 @@
                   </el-form-item>
                </el-col>
                <el-col :span="12">
-                  <el-form-item label="联系电话" prop="phone">
-                     <el-input v-model="form.phone" placeholder="请输入联系电话" maxlength="11" />
+                  <el-form-item label="服务电话" prop="phone">
+                     <el-input v-model="form.phone" placeholder="请输入服务电话" maxlength="11" />
                   </el-form-item>
                </el-col>
                <el-col :span="12">
@@ -118,7 +124,7 @@
                   </el-form-item>
                </el-col>
                <el-col :span="12">
-                  <el-form-item label="部门状态">
+                  <el-form-item label="状态">
                      <el-radio-group v-model="form.status">
                         <el-radio
                            v-for="dict in sys_normal_disable"

+ 278 - 0
back-ui/src/views/system/sms/index.vue

@@ -0,0 +1,278 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="手机号" prop="phoneNo">
+        <el-input
+          v-model="queryParams.phoneNo"
+          placeholder="请输入手机号"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="${comment}" prop="remarks">
+        <el-input
+          v-model="queryParams.remarks"
+          placeholder="请输入${comment}"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="是否使用(0:否,1:是)" prop="isUsed">
+        <el-input
+          v-model="queryParams.isUsed"
+          placeholder="请输入是否使用(0:否,1:是)"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="Plus"
+          @click="handleAdd"
+          v-hasPermi="['system:sms:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="Edit"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['system:sms:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="Delete"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['system:sms:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="Download"
+          @click="handleExport"
+          v-hasPermi="['system:sms:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="smsList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="${comment}" align="center" prop="id" />
+      <el-table-column label="手机号" align="center" prop="phoneNo" />
+      <el-table-column label="短信内容" align="center" prop="message" />
+      <el-table-column label="验证码" align="center" prop="code" />
+      <el-table-column label="1-成功 0-失败" align="center" prop="status" />
+      <el-table-column label="${comment}" align="center" prop="remarks" />
+      <el-table-column label="短信类型 1绑定用户信息 2修改密码 4电子卡" align="center" prop="type" />
+      <el-table-column label="是否使用(0:否,1:是)" align="center" prop="isUsed" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:sms:edit']">修改</el-button>
+          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:sms:remove']">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    
+    <pagination
+      v-show="total>0"
+      :total="total"
+      v-model:page="queryParams.pageNum"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改短信发送记录对话框 -->
+    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
+      <el-form ref="smsRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="手机号" prop="phoneNo">
+          <el-input v-model="form.phoneNo" placeholder="请输入手机号" />
+        </el-form-item>
+        <el-form-item label="短信内容" prop="message">
+          <el-input v-model="form.message" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="验证码" prop="code">
+          <el-input v-model="form.code" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="${comment}" prop="remarks">
+          <el-input v-model="form.remarks" placeholder="请输入${comment}" />
+        </el-form-item>
+        <el-form-item label="是否使用(0:否,1:是)" prop="isUsed">
+          <el-input v-model="form.isUsed" placeholder="请输入是否使用(0:否,1:是)" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Sms">
+import { listSms, getSms, delSms, addSms, updateSms } from "@/api/system/sms"
+
+const { proxy } = getCurrentInstance()
+
+const smsList = ref([])
+const open = ref(false)
+const loading = ref(true)
+const showSearch = ref(true)
+const ids = ref([])
+const single = ref(true)
+const multiple = ref(true)
+const total = ref(0)
+const title = ref("")
+
+const data = reactive({
+  form: {},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    phoneNo: null,
+    message: null,
+    code: null,
+    status: null,
+    remarks: null,
+    type: null,
+    isUsed: null
+  },
+  rules: {
+    isUsed: [
+      { required: true, message: "是否使用(0:否,1:是)不能为空", trigger: "blur" }
+    ]
+  }
+})
+
+const { queryParams, form, rules } = toRefs(data)
+
+/** 查询短信发送记录列表 */
+function getList() {
+  loading.value = true
+  listSms(queryParams.value).then(response => {
+    smsList.value = response.rows
+    total.value = response.total
+    loading.value = false
+  })
+}
+
+// 取消按钮
+function cancel() {
+  open.value = false
+  reset()
+}
+
+// 表单重置
+function reset() {
+  form.value = {
+    id: null,
+    phoneNo: null,
+    message: null,
+    code: null,
+    status: null,
+    remarks: null,
+    createTime: null,
+    updateTime: null,
+    type: null,
+    isUsed: null
+  }
+  proxy.resetForm("smsRef")
+}
+
+/** 搜索按钮操作 */
+function handleQuery() {
+  queryParams.value.pageNum = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+function resetQuery() {
+  proxy.resetForm("queryRef")
+  handleQuery()
+}
+
+// 多选框选中数据
+function handleSelectionChange(selection) {
+  ids.value = selection.map(item => item.id)
+  single.value = selection.length != 1
+  multiple.value = !selection.length
+}
+
+/** 新增按钮操作 */
+function handleAdd() {
+  reset()
+  open.value = true
+  title.value = "添加短信发送记录"
+}
+
+/** 修改按钮操作 */
+function handleUpdate(row) {
+  reset()
+  const _id = row.id || ids.value
+  getSms(_id).then(response => {
+    form.value = response.data
+    open.value = true
+    title.value = "修改短信发送记录"
+  })
+}
+
+/** 提交按钮 */
+function submitForm() {
+  proxy.$refs["smsRef"].validate(valid => {
+    if (valid) {
+      if (form.value.id != null) {
+        updateSms(form.value).then(response => {
+          proxy.$modal.msgSuccess("修改成功")
+          open.value = false
+          getList()
+        })
+      } else {
+        addSms(form.value).then(response => {
+          proxy.$modal.msgSuccess("新增成功")
+          open.value = false
+          getList()
+        })
+      }
+    }
+  })
+}
+
+/** 删除按钮操作 */
+function handleDelete(row) {
+  const _ids = row.id || ids.value
+  proxy.$modal.confirm('是否确认删除短信发送记录编号为"' + _ids + '"的数据项?').then(function() {
+    return delSms(_ids)
+  }).then(() => {
+    getList()
+    proxy.$modal.msgSuccess("删除成功")
+  }).catch(() => {})
+}
+
+/** 导出按钮操作 */
+function handleExport() {
+  proxy.download('system/sms/export', {
+    ...queryParams.value
+  }, `sms_${new Date().getTime()}.xlsx`)
+}
+
+getList()
+</script>

+ 102 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzAgentController.java

@@ -0,0 +1,102 @@
+package com.ruoyi.web.controller.dz;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+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.enums.BusinessType;
+import com.ruoyi.dz.domain.DzAgent;
+import com.ruoyi.dz.service.IDzAgentService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+
+/**
+ * 机构代理Controller
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+@RestController
+@RequestMapping("/dz/agent")
+public class DzAgentController extends BaseController
+{
+    @Autowired
+    private IDzAgentService dzAgentService;
+
+    /**
+     * 查询机构代理列表
+     */
+    @PreAuthorize("@ss.hasPermi('dz:agent:list')")
+    @GetMapping("/list")
+    public AjaxResult list(DzAgent dzAgent)
+    {
+        List<DzAgent> list = dzAgentService.selectDzAgentList(dzAgent);
+        return success(list);
+    }
+
+    /**
+     * 导出机构代理列表
+     */
+    @PreAuthorize("@ss.hasPermi('dz:agent:export')")
+    @Log(title = "机构代理", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, DzAgent dzAgent)
+    {
+        List<DzAgent> list = dzAgentService.selectDzAgentList(dzAgent);
+        ExcelUtil<DzAgent> util = new ExcelUtil<DzAgent>(DzAgent.class);
+        util.exportExcel(response, list, "机构代理数据");
+    }
+
+    /**
+     * 获取机构代理详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('dz:agent:query')")
+    @GetMapping(value = "/{agentId}")
+    public AjaxResult getInfo(@PathVariable("agentId") Long agentId)
+    {
+        return success(dzAgentService.selectDzAgentByAgentId(agentId));
+    }
+
+    /**
+     * 新增机构代理
+     */
+    @PreAuthorize("@ss.hasPermi('dz:agent:add')")
+    @Log(title = "机构代理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody DzAgent dzAgent)
+    {
+        return toAjax(dzAgentService.insertDzAgent(dzAgent));
+    }
+
+    /**
+     * 修改机构代理
+     */
+    @PreAuthorize("@ss.hasPermi('dz:agent:edit')")
+    @Log(title = "机构代理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody DzAgent dzAgent)
+    {
+        return toAjax(dzAgentService.updateDzAgent(dzAgent));
+    }
+
+    /**
+     * 删除机构代理
+     */
+    @PreAuthorize("@ss.hasPermi('dz:agent:remove')")
+    @Log(title = "机构代理", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{agentIds}")
+    public AjaxResult remove(@PathVariable Long[] agentIds)
+    {
+        return toAjax(dzAgentService.deleteDzAgentByAgentIds(agentIds));
+    }
+}

+ 104 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzCardsController.java

@@ -0,0 +1,104 @@
+package com.ruoyi.web.controller.dz;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+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.enums.BusinessType;
+import com.ruoyi.dz.domain.DzCards;
+import com.ruoyi.dz.service.IDzCardsService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 学习卡Controller
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+@RestController
+@RequestMapping("/dz/cards")
+public class DzCardsController extends BaseController
+{
+    @Autowired
+    private IDzCardsService dzCardsService;
+
+    /**
+     * 查询学习卡列表
+     */
+    @PreAuthorize("@ss.hasPermi('dz:cards:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(DzCards dzCards)
+    {
+        startPage();
+        List<DzCards> list = dzCardsService.selectDzCardsList(dzCards);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出学习卡列表
+     */
+    @PreAuthorize("@ss.hasPermi('dz:cards:export')")
+    @Log(title = "学习卡", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, DzCards dzCards)
+    {
+        List<DzCards> list = dzCardsService.selectDzCardsList(dzCards);
+        ExcelUtil<DzCards> util = new ExcelUtil<DzCards>(DzCards.class);
+        util.exportExcel(response, list, "学习卡数据");
+    }
+
+    /**
+     * 获取学习卡详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('dz:cards:query')")
+    @GetMapping(value = "/{cardId}")
+    public AjaxResult getInfo(@PathVariable("cardId") Long cardId)
+    {
+        return success(dzCardsService.selectDzCardsByCardId(cardId));
+    }
+
+    /**
+     * 新增学习卡
+     */
+    @PreAuthorize("@ss.hasPermi('dz:cards:add')")
+    @Log(title = "学习卡", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody DzCards dzCards)
+    {
+        return toAjax(dzCardsService.insertDzCards(dzCards));
+    }
+
+    /**
+     * 修改学习卡
+     */
+    @PreAuthorize("@ss.hasPermi('dz:cards:edit')")
+    @Log(title = "学习卡", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody DzCards dzCards)
+    {
+        return toAjax(dzCardsService.updateDzCards(dzCards));
+    }
+
+    /**
+     * 删除学习卡
+     */
+    @PreAuthorize("@ss.hasPermi('dz:cards:remove')")
+    @Log(title = "学习卡", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{cardIds}")
+    public AjaxResult remove(@PathVariable Long[] cardIds)
+    {
+        return toAjax(dzCardsService.deleteDzCardsByCardIds(cardIds));
+    }
+}

+ 104 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzCardsOpenController.java

@@ -0,0 +1,104 @@
+package com.ruoyi.web.controller.dz;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+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.enums.BusinessType;
+import com.ruoyi.dz.domain.DzCardsOpen;
+import com.ruoyi.dz.service.IDzCardsOpenService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 开卡申请Controller
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+@RestController
+@RequestMapping("/dz/open")
+public class DzCardsOpenController extends BaseController
+{
+    @Autowired
+    private IDzCardsOpenService dzCardsOpenService;
+
+    /**
+     * 查询开卡申请列表
+     */
+    @PreAuthorize("@ss.hasPermi('dz:open:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(DzCardsOpen dzCardsOpen)
+    {
+        startPage();
+        List<DzCardsOpen> list = dzCardsOpenService.selectDzCardsOpenList(dzCardsOpen);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出开卡申请列表
+     */
+    @PreAuthorize("@ss.hasPermi('dz:open:export')")
+    @Log(title = "开卡申请", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, DzCardsOpen dzCardsOpen)
+    {
+        List<DzCardsOpen> list = dzCardsOpenService.selectDzCardsOpenList(dzCardsOpen);
+        ExcelUtil<DzCardsOpen> util = new ExcelUtil<DzCardsOpen>(DzCardsOpen.class);
+        util.exportExcel(response, list, "开卡申请数据");
+    }
+
+    /**
+     * 获取开卡申请详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('dz:open:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return success(dzCardsOpenService.selectDzCardsOpenById(id));
+    }
+
+    /**
+     * 新增开卡申请
+     */
+    @PreAuthorize("@ss.hasPermi('dz:open:add')")
+    @Log(title = "开卡申请", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody DzCardsOpen dzCardsOpen)
+    {
+        return toAjax(dzCardsOpenService.insertDzCardsOpen(dzCardsOpen));
+    }
+
+    /**
+     * 修改开卡申请
+     */
+    @PreAuthorize("@ss.hasPermi('dz:open:edit')")
+    @Log(title = "开卡申请", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody DzCardsOpen dzCardsOpen)
+    {
+        return toAjax(dzCardsOpenService.updateDzCardsOpen(dzCardsOpen));
+    }
+
+    /**
+     * 删除开卡申请
+     */
+    @PreAuthorize("@ss.hasPermi('dz:open:remove')")
+    @Log(title = "开卡申请", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(dzCardsOpenService.deleteDzCardsOpenByIds(ids));
+    }
+}

+ 104 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzClassesController.java

@@ -0,0 +1,104 @@
+package com.ruoyi.web.controller.dz;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+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.enums.BusinessType;
+import com.ruoyi.dz.domain.DzClasses;
+import com.ruoyi.dz.service.IDzClassesService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 机构班级Controller
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+@RestController
+@RequestMapping("/dz/classes")
+public class DzClassesController extends BaseController
+{
+    @Autowired
+    private IDzClassesService dzClassesService;
+
+    /**
+     * 查询机构班级列表
+     */
+    @PreAuthorize("@ss.hasPermi('dz:classes:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(DzClasses dzClasses)
+    {
+        startPage();
+        List<DzClasses> list = dzClassesService.selectDzClassesList(dzClasses);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出机构班级列表
+     */
+    @PreAuthorize("@ss.hasPermi('dz:classes:export')")
+    @Log(title = "机构班级", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, DzClasses dzClasses)
+    {
+        List<DzClasses> list = dzClassesService.selectDzClassesList(dzClasses);
+        ExcelUtil<DzClasses> util = new ExcelUtil<DzClasses>(DzClasses.class);
+        util.exportExcel(response, list, "机构班级数据");
+    }
+
+    /**
+     * 获取机构班级详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('dz:classes:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return success(dzClassesService.selectDzClassesById(id));
+    }
+
+    /**
+     * 新增机构班级
+     */
+    @PreAuthorize("@ss.hasPermi('dz:classes:add')")
+    @Log(title = "机构班级", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody DzClasses dzClasses)
+    {
+        return toAjax(dzClassesService.insertDzClasses(dzClasses));
+    }
+
+    /**
+     * 修改机构班级
+     */
+    @PreAuthorize("@ss.hasPermi('dz:classes:edit')")
+    @Log(title = "机构班级", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody DzClasses dzClasses)
+    {
+        return toAjax(dzClassesService.updateDzClasses(dzClasses));
+    }
+
+    /**
+     * 删除机构班级
+     */
+    @PreAuthorize("@ss.hasPermi('dz:classes:remove')")
+    @Log(title = "机构班级", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(dzClassesService.deleteDzClassesByIds(ids));
+    }
+}

+ 104 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzControlController.java

@@ -0,0 +1,104 @@
+package com.ruoyi.web.controller.dz;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+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.enums.BusinessType;
+import com.ruoyi.dz.domain.DzControl;
+import com.ruoyi.dz.service.IDzControlService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 单招省份状态Controller
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+@RestController
+@RequestMapping("/dz/control")
+public class DzControlController extends BaseController
+{
+    @Autowired
+    private IDzControlService dzControlService;
+
+    /**
+     * 查询单招省份状态列表
+     */
+    @PreAuthorize("@ss.hasPermi('dz:control:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(DzControl dzControl)
+    {
+        startPage();
+        List<DzControl> list = dzControlService.selectDzControlList(dzControl);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出单招省份状态列表
+     */
+    @PreAuthorize("@ss.hasPermi('dz:control:export')")
+    @Log(title = "单招省份状态", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, DzControl dzControl)
+    {
+        List<DzControl> list = dzControlService.selectDzControlList(dzControl);
+        ExcelUtil<DzControl> util = new ExcelUtil<DzControl>(DzControl.class);
+        util.exportExcel(response, list, "单招省份状态数据");
+    }
+
+    /**
+     * 获取单招省份状态详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('dz:control:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return success(dzControlService.selectDzControlById(id));
+    }
+
+    /**
+     * 新增单招省份状态
+     */
+    @PreAuthorize("@ss.hasPermi('dz:control:add')")
+    @Log(title = "单招省份状态", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody DzControl dzControl)
+    {
+        return toAjax(dzControlService.insertDzControl(dzControl));
+    }
+
+    /**
+     * 修改单招省份状态
+     */
+    @PreAuthorize("@ss.hasPermi('dz:control:edit')")
+    @Log(title = "单招省份状态", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody DzControl dzControl)
+    {
+        return toAjax(dzControlService.updateDzControl(dzControl));
+    }
+
+    /**
+     * 删除单招省份状态
+     */
+    @PreAuthorize("@ss.hasPermi('dz:control:remove')")
+    @Log(title = "单招省份状态", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(dzControlService.deleteDzControlByIds(ids));
+    }
+}

+ 104 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzPaymentOrdersController.java

@@ -0,0 +1,104 @@
+package com.ruoyi.web.controller.dz;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+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.enums.BusinessType;
+import com.ruoyi.dz.domain.DzPaymentOrders;
+import com.ruoyi.dz.service.IDzPaymentOrdersService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 订单Controller
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+@RestController
+@RequestMapping("/dz/orders")
+public class DzPaymentOrdersController extends BaseController
+{
+    @Autowired
+    private IDzPaymentOrdersService dzPaymentOrdersService;
+
+    /**
+     * 查询订单列表
+     */
+    @PreAuthorize("@ss.hasPermi('dz:orders:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(DzPaymentOrders dzPaymentOrders)
+    {
+        startPage();
+        List<DzPaymentOrders> list = dzPaymentOrdersService.selectDzPaymentOrdersList(dzPaymentOrders);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出订单列表
+     */
+    @PreAuthorize("@ss.hasPermi('dz:orders:export')")
+    @Log(title = "订单", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, DzPaymentOrders dzPaymentOrders)
+    {
+        List<DzPaymentOrders> list = dzPaymentOrdersService.selectDzPaymentOrdersList(dzPaymentOrders);
+        ExcelUtil<DzPaymentOrders> util = new ExcelUtil<DzPaymentOrders>(DzPaymentOrders.class);
+        util.exportExcel(response, list, "订单数据");
+    }
+
+    /**
+     * 获取订单详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('dz:orders:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return success(dzPaymentOrdersService.selectDzPaymentOrdersById(id));
+    }
+
+    /**
+     * 新增订单
+     */
+    @PreAuthorize("@ss.hasPermi('dz:orders:add')")
+    @Log(title = "订单", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody DzPaymentOrders dzPaymentOrders)
+    {
+        return toAjax(dzPaymentOrdersService.insertDzPaymentOrders(dzPaymentOrders));
+    }
+
+    /**
+     * 修改订单
+     */
+    @PreAuthorize("@ss.hasPermi('dz:orders:edit')")
+    @Log(title = "订单", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody DzPaymentOrders dzPaymentOrders)
+    {
+        return toAjax(dzPaymentOrdersService.updateDzPaymentOrders(dzPaymentOrders));
+    }
+
+    /**
+     * 删除订单
+     */
+    @PreAuthorize("@ss.hasPermi('dz:orders:remove')")
+    @Log(title = "订单", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(dzPaymentOrdersService.deleteDzPaymentOrdersByIds(ids));
+    }
+}

+ 104 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzSchoolController.java

@@ -0,0 +1,104 @@
+package com.ruoyi.web.controller.dz;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+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.enums.BusinessType;
+import com.ruoyi.dz.domain.DzSchool;
+import com.ruoyi.dz.service.IDzSchoolService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 机构校区Controller
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+@RestController
+@RequestMapping("/dz/school")
+public class DzSchoolController extends BaseController
+{
+    @Autowired
+    private IDzSchoolService dzSchoolService;
+
+    /**
+     * 查询机构校区列表
+     */
+    @PreAuthorize("@ss.hasPermi('dz:school:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(DzSchool dzSchool)
+    {
+        startPage();
+        List<DzSchool> list = dzSchoolService.selectDzSchoolList(dzSchool);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出机构校区列表
+     */
+    @PreAuthorize("@ss.hasPermi('dz:school:export')")
+    @Log(title = "机构校区", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, DzSchool dzSchool)
+    {
+        List<DzSchool> list = dzSchoolService.selectDzSchoolList(dzSchool);
+        ExcelUtil<DzSchool> util = new ExcelUtil<DzSchool>(DzSchool.class);
+        util.exportExcel(response, list, "机构校区数据");
+    }
+
+    /**
+     * 获取机构校区详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('dz:school:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return success(dzSchoolService.selectDzSchoolById(id));
+    }
+
+    /**
+     * 新增机构校区
+     */
+    @PreAuthorize("@ss.hasPermi('dz:school:add')")
+    @Log(title = "机构校区", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody DzSchool dzSchool)
+    {
+        return toAjax(dzSchoolService.insertDzSchool(dzSchool));
+    }
+
+    /**
+     * 修改机构校区
+     */
+    @PreAuthorize("@ss.hasPermi('dz:school:edit')")
+    @Log(title = "机构校区", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody DzSchool dzSchool)
+    {
+        return toAjax(dzSchoolService.updateDzSchool(dzSchool));
+    }
+
+    /**
+     * 删除机构校区
+     */
+    @PreAuthorize("@ss.hasPermi('dz:school:remove')")
+    @Log(title = "机构校区", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(dzSchoolService.deleteDzSchoolByIds(ids));
+    }
+}

+ 104 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzTeacherClassController.java

@@ -0,0 +1,104 @@
+package com.ruoyi.web.controller.dz;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+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.enums.BusinessType;
+import com.ruoyi.dz.domain.DzTeacherClass;
+import com.ruoyi.dz.service.IDzTeacherClassService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 教师班级关系Controller
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+@RestController
+@RequestMapping("/dz/teacherclass")
+public class DzTeacherClassController extends BaseController
+{
+    @Autowired
+    private IDzTeacherClassService dzTeacherClassService;
+
+    /**
+     * 查询教师班级关系列表
+     */
+    @PreAuthorize("@ss.hasPermi('dz:teacherclass:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(DzTeacherClass dzTeacherClass)
+    {
+        startPage();
+        List<DzTeacherClass> list = dzTeacherClassService.selectDzTeacherClassList(dzTeacherClass);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出教师班级关系列表
+     */
+    @PreAuthorize("@ss.hasPermi('dz:teacherclass:export')")
+    @Log(title = "教师班级关系", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, DzTeacherClass dzTeacherClass)
+    {
+        List<DzTeacherClass> list = dzTeacherClassService.selectDzTeacherClassList(dzTeacherClass);
+        ExcelUtil<DzTeacherClass> util = new ExcelUtil<DzTeacherClass>(DzTeacherClass.class);
+        util.exportExcel(response, list, "教师班级关系数据");
+    }
+
+    /**
+     * 获取教师班级关系详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('dz:teacherclass:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") String id)
+    {
+        return success(dzTeacherClassService.selectDzTeacherClassById(id));
+    }
+
+    /**
+     * 新增教师班级关系
+     */
+    @PreAuthorize("@ss.hasPermi('dz:teacherclass:add')")
+    @Log(title = "教师班级关系", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody DzTeacherClass dzTeacherClass)
+    {
+        return toAjax(dzTeacherClassService.insertDzTeacherClass(dzTeacherClass));
+    }
+
+    /**
+     * 修改教师班级关系
+     */
+    @PreAuthorize("@ss.hasPermi('dz:teacherclass:edit')")
+    @Log(title = "教师班级关系", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody DzTeacherClass dzTeacherClass)
+    {
+        return toAjax(dzTeacherClassService.updateDzTeacherClass(dzTeacherClass));
+    }
+
+    /**
+     * 删除教师班级关系
+     */
+    @PreAuthorize("@ss.hasPermi('dz:teacherclass:remove')")
+    @Log(title = "教师班级关系", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable String[] ids)
+    {
+        return toAjax(dzTeacherClassService.deleteDzTeacherClassByIds(ids));
+    }
+}

+ 104 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzTeacherController.java

@@ -0,0 +1,104 @@
+package com.ruoyi.web.controller.dz;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+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.enums.BusinessType;
+import com.ruoyi.dz.domain.DzTeacher;
+import com.ruoyi.dz.service.IDzTeacherService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 老师Controller
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+@RestController
+@RequestMapping("/dz/teacher")
+public class DzTeacherController extends BaseController
+{
+    @Autowired
+    private IDzTeacherService dzTeacherService;
+
+    /**
+     * 查询老师列表
+     */
+    @PreAuthorize("@ss.hasPermi('dz:teacher:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(DzTeacher dzTeacher)
+    {
+        startPage();
+        List<DzTeacher> list = dzTeacherService.selectDzTeacherList(dzTeacher);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出老师列表
+     */
+    @PreAuthorize("@ss.hasPermi('dz:teacher:export')")
+    @Log(title = "老师", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, DzTeacher dzTeacher)
+    {
+        List<DzTeacher> list = dzTeacherService.selectDzTeacherList(dzTeacher);
+        ExcelUtil<DzTeacher> util = new ExcelUtil<DzTeacher>(DzTeacher.class);
+        util.exportExcel(response, list, "老师数据");
+    }
+
+    /**
+     * 获取老师详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('dz:teacher:query')")
+    @GetMapping(value = "/{teacherId}")
+    public AjaxResult getInfo(@PathVariable("teacherId") Long teacherId)
+    {
+        return success(dzTeacherService.selectDzTeacherByTeacherId(teacherId));
+    }
+
+    /**
+     * 新增老师
+     */
+    @PreAuthorize("@ss.hasPermi('dz:teacher:add')")
+    @Log(title = "老师", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody DzTeacher dzTeacher)
+    {
+        return toAjax(dzTeacherService.insertDzTeacher(dzTeacher));
+    }
+
+    /**
+     * 修改老师
+     */
+    @PreAuthorize("@ss.hasPermi('dz:teacher:edit')")
+    @Log(title = "老师", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody DzTeacher dzTeacher)
+    {
+        return toAjax(dzTeacherService.updateDzTeacher(dzTeacher));
+    }
+
+    /**
+     * 删除老师
+     */
+    @PreAuthorize("@ss.hasPermi('dz:teacher:remove')")
+    @Log(title = "老师", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{teacherIds}")
+    public AjaxResult remove(@PathVariable Long[] teacherIds)
+    {
+        return toAjax(dzTeacherService.deleteDzTeacherByTeacherIds(teacherIds));
+    }
+}

+ 144 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/front/CommController.java

@@ -0,0 +1,144 @@
+package com.ruoyi.web.controller.front;
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.common.annotation.Anonymous;
+import com.ruoyi.common.constant.CacheConstants;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.entity.SysDictData;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.core.redis.RedisCache;
+import com.ruoyi.common.utils.PhoneUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.dz.domain.DzCards;
+import com.ruoyi.dz.service.IDzCardsService;
+import com.ruoyi.system.service.ISysConfigService;
+import com.ruoyi.system.service.ISysDictTypeService;
+import com.ruoyi.system.service.ISysUserService;
+import com.ruoyi.system.service.ShortMessageService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+@RestController("/front/comm")
+@Api(tags = "前台-公共")
+public class CommController {
+    private final ISysDictTypeService dictTypeService;
+    private final ShortMessageService shortMessageService;
+    private final RedisCache redisCache;
+    private final ISysUserService userService;
+    private final ISysConfigService configService;
+    private final IDzCardsService cardsService;
+
+    public CommController(ISysDictTypeService dictTypeService, ShortMessageService shortMessageService, RedisCache redisCache, ISysUserService userService, ISysConfigService configService, IDzCardsService cardsService) {
+        this.dictTypeService = dictTypeService;
+        this.shortMessageService = shortMessageService;
+        this.redisCache = redisCache;
+        this.userService = userService;
+        this.configService = configService;
+        this.cardsService = cardsService;
+    }
+
+    @GetMapping(value = "dict/{dictTypes}")
+    @Anonymous
+    @ApiOperation("字典列表")
+    public AjaxResult dictType(@PathVariable String[] dictTypes)
+    {
+        Map<String, List<JSONObject>> dictTypeMap = new HashMap<>();
+        for(String dictType : dictTypes) {
+            List<SysDictData> data = dictTypeService.selectDictDataByType(dictType);
+            if (StringUtils.isNull(data))
+            {
+                dictTypeMap.put(dictType, Collections.emptyList());
+            } else {
+                dictTypeMap.put(dictType, data.stream().map(t -> {
+                    JSONObject o = new JSONObject();
+                    o.put("dictCode", t.getDictCode());
+                    o.put("dictValue", t.getDictValue());
+                    o.put("dictLabel", t.getDictLabel());
+                    return o;
+                }).collect(Collectors.toList()));
+            }
+        }
+        return AjaxResult.success(dictTypeMap);
+    }
+
+    @ApiOperation("验证卡密码")
+    @PostMapping(value = "validateCard")
+    public AjaxResult validateCard(String cardNo, String password) {
+        DzCards card = cardsService.selectDzCardsByCardNo(cardNo);
+        boolean isSuccess = null != card && card.getPassword().equals(password);
+        if (!isSuccess) {
+            return AjaxResult.error("验证失败");
+        }
+        return AjaxResult.success("验证成功");
+    }
+
+    @ApiOperation("发送验证码(验重,验证码,不登陆)")
+    @PostMapping(value = "sendSmsNoToken")
+    @Anonymous
+    public AjaxResult sendSmsNoToken(String mobile, Integer smsType, String uuid, String code){
+        if(!PhoneUtils.isPhoneNumber(mobile)){
+            return AjaxResult.error("手机号错误");
+        }
+        if (!checkCaptcha(uuid, code)) {
+            return AjaxResult.error("验证码错误");
+        }
+        SysUser sysUser = userService.selectUserByMobile(mobile);
+        if (StringUtils.isNotNull(sysUser)) {
+            return AjaxResult.error("手机号已存在");
+        }
+        if(shortMessageService.isBlacklist(mobile)){
+            return AjaxResult.error("发送频繁,请稍候再试");
+        }
+        return shortMessageService.sendVerifyCode(smsType, mobile);
+    }
+
+
+    @ApiOperation("发送验证码(不验重,验证码,不登陆)")
+    @PostMapping(value = "sendSmsNoValidationNoToken")
+    @Anonymous
+    public AjaxResult sendSmsNoValidationNoToken(String mobile, Integer smsType, String uuid, String code){
+        if(!PhoneUtils.isPhoneNumber(mobile)){
+            return AjaxResult.error("手机号错误");
+        }
+        if (!checkCaptcha(uuid, code)) {
+            return AjaxResult.error("验证码错误");
+        }
+        if(shortMessageService.isBlacklist(mobile)){
+            return AjaxResult.error("发送频繁,请稍候再试");
+        }
+        return shortMessageService.sendVerifyCode(smsType, mobile);
+    }
+
+    @ApiOperation("发送验证码(不验重,需登陆,无验证码)")
+    @PostMapping(value = "sendSms")
+    public AjaxResult sendSms(String mobile, Integer smsType){
+        return shortMessageService.sendVerifyCode(smsType, mobile);
+    }
+
+    @ApiOperation("验证码校验")
+    @PostMapping(value = "validateSms")
+    public AjaxResult validate(String mobile, String code){
+        boolean isSuccess = shortMessageService.checkCode(mobile, code);
+        if(!isSuccess){
+            return AjaxResult.error("验证失败");
+        }
+        return AjaxResult.success("验证成功");
+    }
+
+    private Boolean checkCaptcha(String uuid, String code) {
+        if (configService.isSmsCaptchaEnabled()) {
+            String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
+            String captcha = redisCache.getCacheObject(verifyKey);
+            redisCache.deleteObject(verifyKey);
+            if (null == code || !code.equalsIgnoreCase(captcha)) {
+                return false;
+            }
+        }
+        return true;
+    }
+}

+ 131 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/front/UserController.java

@@ -0,0 +1,131 @@
+package com.ruoyi.web.controller.front;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.common.annotation.Anonymous;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.core.domain.AjaxResult;
+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.enums.ExamType;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.dz.domain.DzControl;
+import com.ruoyi.dz.service.IDzControlService;
+import com.ruoyi.framework.web.service.SysPermissionService;
+import com.ruoyi.framework.web.service.TokenService;
+import com.ruoyi.web.service.CommService;
+import com.ruoyi.web.service.SysLoginService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+
+@RestController("/front/user")
+@Api(tags = "前台-用户")
+public class UserController {
+    private final IDzControlService dzControlService;
+    private final SysLoginService loginService;
+    private final SysPermissionService permissionService;
+    private final TokenService tokenService;
+    private final CommService commService;
+
+    public UserController(IDzControlService dzControlService, SysLoginService loginService, SysPermissionService permissionService, TokenService tokenService, CommService commService) {
+        this.dzControlService = dzControlService;
+        this.loginService = loginService;
+        this.permissionService = permissionService;
+        this.tokenService = tokenService;
+        this.commService = commService;
+    }
+
+    @GetMapping(value = "provinces")
+    @Anonymous
+    @ApiOperation("省份列表")
+    public AjaxResult provinces()
+    {
+        DzControl cond = new DzControl();
+        cond.setIsValid(1);
+        return AjaxResult.success(dzControlService.selectDzControlList(cond).stream().map(t -> {
+            JSONObject o = new JSONObject();
+            o.put("dictValue", t.getLocation());
+            o.put("dictLabel", t.getLocation());
+            return o;
+        }).collect(Collectors.toList()));
+    }
+
+    @GetMapping(value = "examTypes")
+    @Anonymous
+    @ApiOperation("考生列表")
+    public AjaxResult examTypes(@RequestParam String location)
+    {
+        DzControl cond = new DzControl();
+        cond.setIsValid(1);
+        cond.setLocation(location);
+        List<DzControl> list = dzControlService.selectDzControlList(cond);
+        String examTypes;
+        if(CollectionUtils.isEmpty(list) || StringUtils.isBlank(examTypes = list.get(0).getExamTypes())) {
+            return AjaxResult.success(Collections.emptyList());
+        }
+        return AjaxResult.success(Arrays.stream(examTypes.split(",")).map(t -> {
+            JSONObject o = new JSONObject();
+            o.put("dictValue", t);
+            o.put("dictLabel", ExamType.valueOf(t).title());
+            return o;
+        }).collect(Collectors.toList()));
+    }
+
+
+    /**
+     * 登录方法
+     *
+     * @param loginBody 登录信息
+     * @return 结果
+     */
+    @PostMapping("userLogin")
+    @ApiOperation("前台登陆")
+    public AjaxResult userLogin(@RequestBody LoginBody loginBody)
+    {
+        AjaxResult ajax = AjaxResult.success();
+        // 生成令牌
+        String token = loginService.login(loginBody.getMobile(), loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(), loginBody.getUuid());
+        ajax.put(Constants.TOKEN, token);
+        return ajax;
+    }
+
+    /**
+     * 获取用户信息
+     *
+     * @return 用户信息
+     */
+    @GetMapping("getUserInfo")
+    @ApiOperation("前台个人信息")
+    public AjaxResult getUserInfo()
+    {
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        SysUser user = loginUser.getUser();
+        // 角色集合
+        Set<String> roles = permissionService.getRolePermission(user);
+        // 权限集合
+        Set<String> 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("card", loginUser.getCard());
+        ajax.put("roles", roles);
+        ajax.put("permissions", permissions);
+        ajax.put("isDefaultModifyPwd", commService.initPasswordIsModify(user.getPwdUpdateDate()));
+        ajax.put("isPasswordExpired", commService.passwordIsExpiration(user.getPwdUpdateDate()));
+        return ajax;
+    }
+}

+ 14 - 36
ie-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java

@@ -1,8 +1,11 @@
 package com.ruoyi.web.controller.system;
 
-import java.util.Date;
 import java.util.List;
 import java.util.Set;
+
+import com.ruoyi.web.service.CommService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -14,14 +17,10 @@ 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.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;
 
 /**
@@ -29,6 +28,7 @@ import com.ruoyi.system.service.ISysMenuService;
  * 
  * @author ruoyi
  */
+@Api(tags = "系统-登陆")
 @RestController
 public class SysLoginController
 {
@@ -45,7 +45,7 @@ public class SysLoginController
     private TokenService tokenService;
 
     @Autowired
-    private ISysConfigService configService;
+    private CommService commService;
 
     /**
      * 登录方法
@@ -53,13 +53,13 @@ public class SysLoginController
      * @param loginBody 登录信息
      * @return 结果
      */
-    @PostMapping("/login")
+    @PostMapping("login")
+    @ApiOperation("登陆")
     public AjaxResult login(@RequestBody LoginBody loginBody)
     {
         AjaxResult ajax = AjaxResult.success();
         // 生成令牌
-        String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
-                loginBody.getUuid());
+        String token = loginService.login(loginBody.getMobile(), loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(), loginBody.getUuid());
         ajax.put(Constants.TOKEN, token);
         return ajax;
     }
@@ -70,6 +70,7 @@ public class SysLoginController
      * @return 用户信息
      */
     @GetMapping("getInfo")
+    @ApiOperation("个人信息")
     public AjaxResult getInfo()
     {
         LoginUser loginUser = SecurityUtils.getLoginUser();
@@ -85,10 +86,11 @@ public class SysLoginController
         }
         AjaxResult ajax = AjaxResult.success();
         ajax.put("user", user);
+        ajax.put("card", loginUser.getCard());
         ajax.put("roles", roles);
         ajax.put("permissions", permissions);
-        ajax.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate()));
-        ajax.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate()));
+        ajax.put("isDefaultModifyPwd", commService.initPasswordIsModify(user.getPwdUpdateDate()));
+        ajax.put("isPasswordExpired", commService.passwordIsExpiration(user.getPwdUpdateDate()));
         return ajax;
     }
 
@@ -104,28 +106,4 @@ public class SysLoginController
         List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
         return AjaxResult.success(menuService.buildMenus(menus));
     }
-    
-    // 检查初始密码是否提醒修改
-    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;
-    }
 }

+ 19 - 8
ie-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java

@@ -1,5 +1,9 @@
 package com.ruoyi.web.controller.system;
 
+import com.ruoyi.common.annotation.Anonymous;
+import com.ruoyi.common.utils.SecurityUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -8,7 +12,7 @@ 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.web.service.SysRegisterService;
 import com.ruoyi.system.service.ISysConfigService;
 
 /**
@@ -17,6 +21,7 @@ import com.ruoyi.system.service.ISysConfigService;
  * @author ruoyi
  */
 @RestController
+@Api(tags = "系统-完善信息")
 public class SysRegisterController extends BaseController
 {
     @Autowired
@@ -25,14 +30,20 @@ public class SysRegisterController extends BaseController
     @Autowired
     private ISysConfigService configService;
 
-    @PostMapping("/register")
-    public AjaxResult register(@RequestBody RegisterBody user)
+    @PostMapping("/registry")
+    @ApiOperation("注册完善")
+    @Anonymous
+    public AjaxResult registry(@RequestBody RegisterBody user)
     {
-        if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser"))))
-        {
-            return error("当前系统没有开启注册功能!");
-        }
-        String msg = registerService.register(user);
+        String msg = registerService.register(user, null);
+        return StringUtils.isEmpty(msg) ? success() : error(msg);
+    }
+
+    @PostMapping("/improve")
+    @ApiOperation("登陆完善")
+    public AjaxResult improve(@RequestBody RegisterBody user)
+    {
+        String msg = registerService.register(user, SecurityUtils.getLoginUser());
         return StringUtils.isEmpty(msg) ? success() : error(msg);
     }
 }

+ 104 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/system/SysSmsBlacklistController.java

@@ -0,0 +1,104 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+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.enums.BusinessType;
+import com.ruoyi.system.domain.SysSmsBlacklist;
+import com.ruoyi.system.service.ISysSmsBlacklistService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 短信手机黑名单Controller
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+@RestController
+@RequestMapping("/system/blacklist")
+public class SysSmsBlacklistController extends BaseController
+{
+    @Autowired
+    private ISysSmsBlacklistService sysSmsBlacklistService;
+
+    /**
+     * 查询短信手机黑名单列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:blacklist:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysSmsBlacklist sysSmsBlacklist)
+    {
+        startPage();
+        List<SysSmsBlacklist> list = sysSmsBlacklistService.selectSysSmsBlacklistList(sysSmsBlacklist);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出短信手机黑名单列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:blacklist:export')")
+    @Log(title = "短信手机黑名单", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysSmsBlacklist sysSmsBlacklist)
+    {
+        List<SysSmsBlacklist> list = sysSmsBlacklistService.selectSysSmsBlacklistList(sysSmsBlacklist);
+        ExcelUtil<SysSmsBlacklist> util = new ExcelUtil<SysSmsBlacklist>(SysSmsBlacklist.class);
+        util.exportExcel(response, list, "短信手机黑名单数据");
+    }
+
+    /**
+     * 获取短信手机黑名单详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('system:blacklist:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return success(sysSmsBlacklistService.selectSysSmsBlacklistById(id));
+    }
+
+    /**
+     * 新增短信手机黑名单
+     */
+    @PreAuthorize("@ss.hasPermi('system:blacklist:add')")
+    @Log(title = "短信手机黑名单", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody SysSmsBlacklist sysSmsBlacklist)
+    {
+        return toAjax(sysSmsBlacklistService.insertSysSmsBlacklist(sysSmsBlacklist));
+    }
+
+    /**
+     * 修改短信手机黑名单
+     */
+    @PreAuthorize("@ss.hasPermi('system:blacklist:edit')")
+    @Log(title = "短信手机黑名单", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody SysSmsBlacklist sysSmsBlacklist)
+    {
+        return toAjax(sysSmsBlacklistService.updateSysSmsBlacklist(sysSmsBlacklist));
+    }
+
+    /**
+     * 删除短信手机黑名单
+     */
+    @PreAuthorize("@ss.hasPermi('system:blacklist:remove')")
+    @Log(title = "短信手机黑名单", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(sysSmsBlacklistService.deleteSysSmsBlacklistByIds(ids));
+    }
+}

+ 104 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/system/SysSmsLogController.java

@@ -0,0 +1,104 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+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.enums.BusinessType;
+import com.ruoyi.system.domain.SysSmsLog;
+import com.ruoyi.system.service.ISysSmsLogService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 短信发送记录Controller
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+@RestController
+@RequestMapping("/system/sms")
+public class SysSmsLogController extends BaseController
+{
+    @Autowired
+    private ISysSmsLogService sysSmsLogService;
+
+    /**
+     * 查询短信发送记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:sms:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysSmsLog sysSmsLog)
+    {
+        startPage();
+        List<SysSmsLog> list = sysSmsLogService.selectSysSmsLogList(sysSmsLog);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出短信发送记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:sms:export')")
+    @Log(title = "短信发送记录", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysSmsLog sysSmsLog)
+    {
+        List<SysSmsLog> list = sysSmsLogService.selectSysSmsLogList(sysSmsLog);
+        ExcelUtil<SysSmsLog> util = new ExcelUtil<SysSmsLog>(SysSmsLog.class);
+        util.exportExcel(response, list, "短信发送记录数据");
+    }
+
+    /**
+     * 获取短信发送记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('system:sms:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return success(sysSmsLogService.selectSysSmsLogById(id));
+    }
+
+    /**
+     * 新增短信发送记录
+     */
+    @PreAuthorize("@ss.hasPermi('system:sms:add')")
+    @Log(title = "短信发送记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody SysSmsLog sysSmsLog)
+    {
+        return toAjax(sysSmsLogService.insertSysSmsLog(sysSmsLog));
+    }
+
+    /**
+     * 修改短信发送记录
+     */
+    @PreAuthorize("@ss.hasPermi('system:sms:edit')")
+    @Log(title = "短信发送记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody SysSmsLog sysSmsLog)
+    {
+        return toAjax(sysSmsLogService.updateSysSmsLog(sysSmsLog));
+    }
+
+    /**
+     * 删除短信发送记录
+     */
+    @PreAuthorize("@ss.hasPermi('system:sms:remove')")
+    @Log(title = "短信发送记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(sysSmsLogService.deleteSysSmsLogByIds(ids));
+    }
+}

+ 43 - 0
ie-admin/src/main/java/com/ruoyi/web/service/CommService.java

@@ -0,0 +1,43 @@
+package com.ruoyi.web.service;
+
+import com.ruoyi.common.core.text.Convert;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.system.service.ISysConfigService;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+
+@Service
+public class CommService {
+    private final ISysConfigService configService;
+
+    public CommService(ISysConfigService configService) {
+        this.configService = configService;
+    }
+
+
+    // 检查初始密码是否提醒修改
+    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;
+    }
+}

+ 60 - 13
ie-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java → ie-admin/src/main/java/com/ruoyi/web/service/SysLoginService.java

@@ -1,6 +1,11 @@
-package com.ruoyi.framework.web.service;
+package com.ruoyi.web.service;
 
 import javax.annotation.Resource;
+
+import com.ruoyi.common.utils.PhoneUtils;
+import com.ruoyi.framework.web.service.TokenService;
+import com.ruoyi.system.service.ShortMessageService;
+import org.apache.commons.lang3.tuple.Pair;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.BadCredentialsException;
@@ -27,6 +32,7 @@ import com.ruoyi.framework.manager.factory.AsyncFactory;
 import com.ruoyi.framework.security.context.AuthenticationContextHolder;
 import com.ruoyi.system.service.ISysConfigService;
 import com.ruoyi.system.service.ISysUserService;
+import org.springframework.transaction.annotation.Transactional;
 
 /**
  * 登录校验方法
@@ -51,21 +57,33 @@ public class SysLoginService
     @Autowired
     private ISysConfigService configService;
 
+    @Autowired
+    private ShortMessageService shortMessageService;
+
     /**
      * 登录验证
-     * 
-     * @param username 用户名
-     * @param password 密码
-     * @param code 验证码
-     * @param uuid 唯一标识
-     * @return 结果
+     * @param mobile
+     * @param username
+     * @param password
+     * @param code
+     * @param uuid
+     * @return
      */
-    public String login(String username, String password, String code, String uuid)
-    {
-        // 验证码校验
-        validateCaptcha(username, code, uuid);
-        // 登录前置校验
-        loginPreCheck(username, password);
+    public String login(String mobile, String username, String password, String code, String uuid) {
+        if (StringUtils.isNotBlank(mobile)) {
+            if (!shortMessageService.checkCode(mobile, password)) {
+                AsyncManager.me().execute(AsyncFactory.recordLogininfor(mobile, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
+                throw new CaptchaException();
+            }
+            loginMobilePreCheck(mobile, password);
+            username = mobile;
+            password = UserConstants.LOGIN_SMS_PASS;
+        } else {
+            // 验证码校验
+            validateCaptcha(username, code, uuid);
+            // 登录前置校验
+            loginPreCheck(username, password);
+        }
         // 用户验证
         Authentication authentication = null;
         try
@@ -164,6 +182,35 @@ public class SysLoginService
         }
     }
 
+    public void loginMobilePreCheck(String phoneNumber, String code)
+    {
+        // 用户名或密码为空 错误
+        if (StringUtils.isEmpty(phoneNumber) || StringUtils.isEmpty(code))
+        {
+            AsyncManager.me().execute(AsyncFactory.recordLogininfor(phoneNumber, Constants.LOGIN_FAIL, MessageUtils.message("not.null")));
+            throw new UserNotExistsException();
+        }
+        // 密码如果不在指定范围内 错误
+        if (code.length() != 4)
+        {
+            AsyncManager.me().execute(AsyncFactory.recordLogininfor(phoneNumber, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
+            throw new UserPasswordNotMatchException();
+        }
+        // 用户名不在指定范围内 错误
+        if (!PhoneUtils.isPhoneNumber(phoneNumber))
+        {
+            AsyncManager.me().execute(AsyncFactory.recordLogininfor(phoneNumber, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
+            throw new UserPasswordNotMatchException();
+        }
+        // IP黑名单校验
+        String blackStr = configService.selectConfigByKey("sys.login.blackIPList");
+        if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr()))
+        {
+            AsyncManager.me().execute(AsyncFactory.recordLogininfor(phoneNumber, Constants.LOGIN_FAIL, MessageUtils.message("login.blocked")));
+            throw new BlackListException();
+        }
+    }
+
     /**
      * 记录登录信息
      *

+ 182 - 0
ie-admin/src/main/java/com/ruoyi/web/service/SysRegisterService.java

@@ -0,0 +1,182 @@
+package com.ruoyi.web.service;
+
+import com.ruoyi.common.core.domain.model.LoginCard;
+import com.ruoyi.common.core.domain.model.LoginUser;
+import com.ruoyi.common.enums.UserRegStatus;
+import com.ruoyi.common.exception.base.BaseException;
+import com.ruoyi.common.utils.bean.BeanUtils;
+import com.ruoyi.dz.domain.DzCards;
+import com.ruoyi.dz.service.IDzCardsService;
+import com.ruoyi.framework.web.service.TokenService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import com.ruoyi.common.constant.CacheConstants;
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.core.domain.model.RegisterBody;
+import com.ruoyi.common.core.redis.RedisCache;
+import com.ruoyi.common.exception.user.CaptchaException;
+import com.ruoyi.common.exception.user.CaptchaExpireException;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.system.service.ISysConfigService;
+import com.ruoyi.system.service.ISysUserService;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * 注册校验方法
+ * 
+ * @author ruoyi
+ */
+@Component
+public class SysRegisterService
+{
+    @Autowired
+    private ISysUserService userService;
+
+    @Autowired
+    private ISysConfigService configService;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    @Autowired
+    private IDzCardsService cardsService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 注册
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public String register(RegisterBody registerBody, LoginUser loginUser)
+    {
+        String username = registerBody.getUsername(), mobile = registerBody.getMobile(), password = registerBody.getPassword();
+        DzCards upCard = null;
+        SysUser upUser = new SysUser();
+        upUser.setPhonenumber(mobile);
+        if(null == loginUser) { // 手机注册或卡注册
+            if (StringUtils.isBlank(mobile)) {
+                return "手机号不能为空";
+            }
+            if(StringUtils.isNotBlank(username)) { // 卡注册
+                DzCards exist = cardsService.selectDzCardsByCardNo(username);
+                if (StringUtils.isNull(exist)) {
+                    return "卡号不正确";
+                }
+                upCard = new DzCards();
+                upCard.setCardId(exist.getCardId());
+            } else {
+                username = mobile;
+                password = "123456";
+            }
+            upUser.setPassword(SecurityUtils.encryptPassword(password));
+            upUser.setPwdUpdateDate(DateUtils.getNowDate());
+        } else {// 注册用户完善 不能改手机, 不能改邀请码
+            DzCards exist = cardsService.selectDzCardsByCardNo(username);
+            if(null == exist) {
+                throw new BaseException("卡号不存在: " + username);
+            }
+            username = exist.getCardNo();
+            upCard = new DzCards();
+            upCard.setCardId(exist.getCardId());
+            upUser.setUserId(loginUser.getUserId());
+        }
+        upUser.setUserName(username);
+        if (StringUtils.isEmpty(username)) {
+            return "用户名不能为空";
+        }
+        else if (StringUtils.isEmpty(password))
+        {
+            return "用户密码不能为空";
+        }
+        else if (username.length() < UserConstants.USERNAME_MIN_LENGTH
+                || username.length() > UserConstants.USERNAME_MAX_LENGTH)
+        {
+            return "账户长度必须在2到20个字符之间";
+        }
+        else if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
+                || password.length() > UserConstants.PASSWORD_MAX_LENGTH)
+        {
+            return "密码长度必须在5到20个字符之间";
+        }
+        else if (!userService.checkUserNameUnique(upUser))
+        {
+            return "保存用户'" + username + "'失败,注册卡号已存在";
+        }
+        else if (!userService.checkPhoneUnique(upUser))
+        {
+            return "保存用户'" + username + "'失败,注册手机已存在" + mobile;
+        }
+        saveInfo(upUser, upCard, registerBody); // 注册或完善后刷新登陆信息
+        if(null != loginUser) {
+            BeanUtils.copyProperties(userService.selectUserById(loginUser.getUserId()), loginUser.getUser(), "password");
+            if(null != upCard.getCardId()) {
+                BeanUtils.copyProperties(cardsService.selectDzCardsByCardId(upCard.getCardId()), loginUser.getCard());
+            }
+            tokenService.refreshToken(loginUser);
+        }
+        return "";
+    }
+
+    private void saveInfo(SysUser user, DzCards card, RegisterBody register) {
+        user.setNickName(register.getNickName());
+        user.setLocation(register.getLocation());
+        user.setExamType(register.getExamType());
+        user.setEndYear(register.getEndYear());
+        user.setScores(register.getScores());
+
+        if(null == card) { // 手机注册时 无卡
+            user.setInviteCode(register.getInviteCode()); //
+            user.setRegStatus(UserRegStatus.User);
+        } else {
+            card.setEndYear(register.getEndYear());
+            card.setYear(register.getEndYear() - 3);
+            card.setSchoolId(register.getSchoolId());
+            card.setClassId(register.getClassId());
+
+            if(null == user.getCardId() || !user.getCardId().equals(card.getCardId())) { // 未绑定或换绑时激活卡
+                user.setCardId(card.getCardId());
+                user.setRegStatus(UserRegStatus.Student);
+                card.setActiveTime(DateUtils.getNowDate());
+            }
+        }
+        if(null == user.getUserId()) {
+            userService.insertUser(user);
+        } else {
+            userService.updateUser(user);
+        }
+        if(null != card) {
+            cardsService.updateDzCards(card);
+        }
+    }
+
+    /**
+     * 校验验证码
+     * 
+     * @param username 用户名
+     * @param code 验证码
+     * @param uuid 唯一标识
+     * @return 结果
+     */
+    public void validateCaptcha(String username, String code, String uuid)
+    {
+        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
+        String captcha = redisCache.getCacheObject(verifyKey);
+        redisCache.deleteObject(verifyKey);
+        if (captcha == null)
+        {
+            throw new CaptchaExpireException();
+        }
+        if (!code.equalsIgnoreCase(captcha))
+        {
+            throw new CaptchaException();
+        }
+    }
+
+    public void validateSmsCaptcha(String mobile, String code, String uuid) {
+
+    }
+}

+ 30 - 8
ie-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java → ie-admin/src/main/java/com/ruoyi/web/service/UserDetailsServiceImpl.java

@@ -1,7 +1,16 @@
-package com.ruoyi.framework.web.service;
+package com.ruoyi.web.service;
 
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.core.domain.model.LoginCard;
+import com.ruoyi.common.enums.UserRegStatus;
+import com.ruoyi.common.utils.PhoneUtils;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.dz.service.IDzCardsService;
+import com.ruoyi.framework.web.service.SysPasswordService;
+import com.ruoyi.framework.web.service.SysPermissionService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.core.userdetails.UserDetailsService;
@@ -34,10 +43,14 @@ public class UserDetailsServiceImpl implements UserDetailsService
     @Autowired
     private SysPermissionService permissionService;
 
+    @Autowired
+    private IDzCardsService dzCardsService;
+
     @Override
     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
     {
-        SysUser user = userService.selectUserByUserName(username);
+        boolean isPhoneLogin = PhoneUtils.isPhoneNumber(username);
+        SysUser user = isPhoneLogin ? userService.selectUserByMobile(username) : userService.selectUserByUserName(username);
         if (StringUtils.isNull(user))
         {
             log.info("登录用户:{} 不存在.", username);
@@ -53,14 +66,23 @@ public class UserDetailsServiceImpl implements UserDetailsService
             log.info("登录用户:{} 已被停用.", username);
             throw new ServiceException(MessageUtils.message("user.blocked"));
         }
-
-        passwordService.validate(user);
-
-        return createLoginUser(user);
+        if(!isPhoneLogin) {
+            passwordService.validate(user);
+        }
+        LoginCard card = new LoginCard();
+        if(null != user.getCardId() && UserRegStatus.Student.equals(user.getRegStatus())) {
+            BeanUtils.copyProperties(dzCardsService.selectDzCardsByCardId(user.getCardId()), card, "password");
+        }
+        LoginUser loginUser = createLoginUser(user, card);
+        if(isPhoneLogin) {
+            user.setPassword(UserConstants.LOGIN_SMS_PASS);
+            loginUser.setLoginUserName(user.getPhonenumber());
+        }
+        return loginUser;
     }
 
-    public UserDetails createLoginUser(SysUser user)
+    public LoginUser createLoginUser(SysUser user, LoginCard card)
     {
-        return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
+        return new LoginUser(user.getUserId(), user.getDeptId(), user, card, permissionService.getMenuPermission(user));
     }
 }

+ 64 - 0
ie-admin/src/main/resources/application.yml

@@ -134,3 +134,67 @@ xss:
   excludes: /system/notice
   # 匹配链接
   urlPatterns: /system/*,/monitor/*,/tool/*
+#名学
+oss:
+  endpoint: oss-cn-beijing.aliyuncs.com
+  bucket: mingxuejingbang
+  accessKeyId: LTAI5tShe4frXAuHPGMnEjjY
+  accessKeySecret: onbNqpaAfdcKU1fygjd2dQqJWPgpN2
+  endpointVod: vod.cn-shanghai.aliyuncs.com
+
+#阿里云短信配置
+aliyun:
+  sms:
+    ecardTemplateCode: SMS_248210300
+    templateCode: SMS_222545002
+    accessKeyId: LTAI5tShe4frXAuHPGMnEjjY
+    accessKeySecret: onbNqpaAfdcKU1fygjd2dQqJWPgpN2
+    defaultConnectTimeout: 1000
+    defaultReadTimeout: 1000
+    #300秒
+    duration: 300
+    #签名
+    signName: 单招一卡通
+  #耀图
+  vod:
+    accessKeyId:  LTAI4FpoeE88SWgavcYq5Soq
+    accessKeySecret:  ttU7YRLw6Bo3ph57f0m8ACXIwxfzfL
+    endpoint: vod.cn-shanghai.aliyuncs.com
+
+# 微信支付配置
+wxpay:
+  mchid: 1629698256
+  key: zhilongsanjiasanzhilongsanjiasan
+  mchKey: zhilongsanjiasanzhilongsanjiasan
+  apiV3Key: zhilongsanjiasanzhilongsanjiasan
+  appId: wx7b9ff116a897456a
+  keyPath: /app/art/wxpayCert/
+  mchsn: 21925f369f23cdf8ea3a913c541d4239d1bcc8af
+  privateKey: "-----BEGIN PRIVATE KEY-----\
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDXX/RVUCmSzv56\
+olpGvTTGG55CrZCJbLvQm7ESEtXhloSPVmoC1OoZqK13eP6vqgFr5CPc9V8xDXFr\
+g11we7rF2D2VzE6qCBe8+7DP/VdAU9yRqm3GjiLxPENah8+zZq7x9+E3WodygnJr\
+eJu053jchpjHKI/jkVYKPi9OuY9mcgz00T0qvZlL28gpR1sGRN2MELXWhMEHvWd/\
+7oCTnDSKaHO24h2H60l7W+5lb6AEm8H69LPzZLl55fYsQeZtOVY69dT8pAbb7wJp\
+6xCpKl8n+O8vtqck+DySWasQK/wS2WERRJ82dFlfS4ccNwhJSuJPGj/Oi0l+jyFd\
+G55exYW3AgMBAAECggEBAMI1LEWhu1s+fAppS65t/qCFVvgZOjQxcEpzmgAKLAL3\
+jyERcxaKl237xC/vUvlj+1QmrJAaUnQRAy1Hj4JWj9zHWQEy8dww3/bxnkZu07aV\
+6FcRr1tT3/5XsQR5YrkK5sYaF2OqpmiDaFmwr/c4oqt4U1uDH/y8mTEzUcVTXhOp\
+LLHoZ1gRea1bgIUAYMEOG5mWAAO45oSf9ZngMwA1+ewMGGagrsCKpeozCT5nPZSU\
+ves8UYvL2DdVnDhxx54iRdtpHeXCf3oldqUt/DOsRx6P0CdOh7Q9sXlC0YmX+mpT\
+YTw/IynRUKvHwcW6qN7zgfSEwHH9L13KBZUnsZWDdUECgYEA7iPV6V+YReUbiOsO\
++Vcdg4r2SH/8XDWiw29r/vubrFufV+tejazPNIjPo0qvor1vK71zrH+2zepgZflc\
+LRhQZlmdkvMPpqS6uMNYeWYa7otzzBuvwQr7uOX+AnMQHNSldULBtpM/+dKcC/5p\
+Jrg4L5/zB1sQpQo6LRpnEJyMKwMCgYEA54cKHqomdjw0zXeJWLPEkDTw3kXTK68/\
+S/ZavDqi0HcewfTIrSJssnhiIyzWiGc4bZ/G+lEjoJ8pKAhrHNPy3alYkG7XV5nY\
+1BZ9YC/trGE6qwA1sCGElObNoN3N2F8H9mmybIg5JRktSniVFjxs5vqsT4l+3U+p\
+DGJkZq3twj0CgYEAv5tv0y2KfLqB9CGFU9PnOF8IGH96EstJIcy17VyO/hheVkRY\
+ONARjCiEQNOoC94149C0kNfVw0rQs1v28YW9swxp/8G4FxI19tGej1c7VjI4QsMI\
+H9/xd+z9+wSPs1LZqkbDTF6gPCdcTT4vZusUsiUVSxbXhqN6+a1jvfbnxPcCgYAS\
+NFL+YECP8WHxeeGpwNDGyfLad0EIYUonzeIKhM3CeGtJstaIjnlfewm0XFUt+ne8\
+XuDFU9XqTjltNWQ+qwegmC0nhh+WerlKy83l3z7f2/FB+s094RTMpG0speQGjEpS\
+/LKTyA4+NYGTJnIKgovJiZI82sHH4viWybG9RRW5vQKBgQCIfKeAITbBuP6sYI5f\
+rpQDBIpbokTqehW4rdkSEVltjL9RAZkPuqeAkSJ6VMkHRfqnj8bOIpAQuTu9jO49\
+6CqZ1qBFENG2nfB+zNBHDzyE1zmNvMg3P0hD2/ENksfaMCSdSmFZn/8DQ6bosTil\
+zPS70hx3sko7wYw//SpB8vpXUA==\
+-----END PRIVATE KEY-----"

+ 30 - 1
ie-common/pom.xml

@@ -52,7 +52,25 @@
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-lang3</artifactId>
         </dependency>
-  
+
+        <dependency>
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.zxing</groupId>
+            <artifactId>core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.github.wechatpay-apiv3</groupId>
+            <artifactId>wechatpay-apache-httpclient</artifactId>
+        </dependency>
         <!-- JSON工具类 -->
         <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
@@ -118,6 +136,17 @@
             <groupId>javax.servlet</groupId>
             <artifactId>javax.servlet-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-annotations</artifactId>
+            <version>1.6.2</version>
+            <scope>compile</scope>
+        </dependency>
 
     </dependencies>
 

+ 5 - 0
ie-common/src/main/java/com/ruoyi/common/constant/UserConstants.java

@@ -78,4 +78,9 @@ public class UserConstants
      */
     public static final int PASSWORD_MIN_LENGTH = 5;
     public static final int PASSWORD_MAX_LENGTH = 20;
+
+    /**
+     * 应用常量
+     */
+    public static final String LOGIN_SMS_PASS = "PhoneSmsCheck823728";
 }

+ 1 - 0
ie-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java

@@ -40,6 +40,7 @@ public class BaseEntity implements Serializable
 
     /** 请求参数 */
     @JsonInclude(JsonInclude.Include.NON_EMPTY)
+    @JsonIgnore
     private Map<String, Object> params;
 
     public String getSearchValue()

+ 107 - 0
ie-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java

@@ -3,6 +3,11 @@ package com.ruoyi.common.core.domain.entity;
 import java.util.Date;
 import java.util.List;
 import javax.validation.constraints.*;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.ruoyi.common.enums.ExamType;
+import com.ruoyi.common.enums.UserRegStatus;
+import com.ruoyi.common.utils.dz.SubjectScore;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.common.annotation.Excel;
@@ -53,6 +58,7 @@ public class SysUser extends BaseEntity
     private String avatar;
 
     /** 密码 */
+    @JsonIgnore
     private String password;
 
     /** 账号状态(0正常 1停用) */
@@ -92,6 +98,35 @@ public class SysUser extends BaseEntity
     /** 角色ID */
     private Long roleId;
 
+    /** 省份 **/
+    private String location;
+
+    /** 考生类型 **/
+    private ExamType examType;
+
+    /**
+     * 注册状态
+     */
+    private UserRegStatus regStatus;
+
+    /**
+     * 毕业年份
+     */
+    private Integer endYear;
+
+    /** 邀请码 **/
+    private String inviteCode;
+
+    /** 考试成绩  {} **/
+    private SubjectScore scores;
+
+    /** 选科ID **/
+    private Integer selectSubject;
+
+    private String directedStudy;
+
+    private Long cardId;
+
     public SysUser()
     {
 
@@ -310,6 +345,78 @@ public class SysUser extends BaseEntity
         this.roleId = roleId;
     }
 
+    public String getLocation() {
+        return location;
+    }
+
+    public void setLocation(String location) {
+        this.location = location;
+    }
+
+    public ExamType getExamType() {
+        return examType;
+    }
+
+    public void setExamType(ExamType examType) {
+        this.examType = examType;
+    }
+
+    public UserRegStatus getRegStatus() {
+        return regStatus;
+    }
+
+    public void setRegStatus(UserRegStatus regStatus) {
+        this.regStatus = regStatus;
+    }
+
+    public Integer getEndYear() {
+        return endYear;
+    }
+
+    public void setEndYear(Integer endYear) {
+        this.endYear = endYear;
+    }
+
+    public String getInviteCode() {
+        return inviteCode;
+    }
+
+    public void setInviteCode(String inviteCode) {
+        this.inviteCode = inviteCode;
+    }
+
+    public SubjectScore getScores() {
+        return scores;
+    }
+
+    public void setScores(SubjectScore scores) {
+        this.scores = scores;
+    }
+
+    public Integer getSelectSubject() {
+        return selectSubject;
+    }
+
+    public void setSelectSubject(Integer selectSubject) {
+        this.selectSubject = selectSubject;
+    }
+
+    public String getDirectedStudy() {
+        return directedStudy;
+    }
+
+    public void setDirectedStudy(String directedStudy) {
+        this.directedStudy = directedStudy;
+    }
+
+    public Long getCardId() {
+        return cardId;
+    }
+
+    public void setCardId(Long cardId) {
+        this.cardId = cardId;
+    }
+
     @Override
     public String toString() {
         return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)

+ 15 - 2
ie-common/src/main/java/com/ruoyi/common/core/domain/model/LoginBody.java

@@ -8,17 +8,22 @@ package com.ruoyi.common.core.domain.model;
 public class LoginBody
 {
     /**
-     * 用户名
+     * 用户名或手机号码, 自动判断
      */
     private String username;
 
+    /**
+     * 手机号码
+     */
+    private String mobile;
+
     /**
      * 用户密码
      */
     private String password;
 
     /**
-     * 验证码
+     * 验证码(用户名=图形验证码, 手机号码=短信验证码)
      */
     private String code;
 
@@ -66,4 +71,12 @@ public class LoginBody
     {
         this.uuid = uuid;
     }
+
+    public String getMobile() {
+        return mobile;
+    }
+
+    public void setMobile(String mobile) {
+        this.mobile = mobile;
+    }
 }

+ 29 - 0
ie-common/src/main/java/com/ruoyi/common/core/domain/model/LoginCard.java

@@ -0,0 +1,29 @@
+package com.ruoyi.common.core.domain.model;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+@ApiModel("用户卡信息")
+public class LoginCard {
+    /** 安排校区 */
+    @ApiModelProperty(name = "安排校区")
+    private Long campusId;
+
+    /** 校区id */
+    @ApiModelProperty(name = "学校id")
+    private Long schoolId;
+
+    /** 校区班级ID */
+    @ApiModelProperty(name = "班级ID")
+    private Long classId;
+
+    /** 班级/入学年份 */
+    @ApiModelProperty(name = "班级/入学年份")
+    private Integer year;
+
+    /** 高考年份 */
+    @ApiModelProperty(name = "毕业年份")
+    private Integer endYear;
+}

+ 29 - 3
ie-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java

@@ -21,6 +21,11 @@ public class LoginUser implements UserDetails
      */
     private Long userId;
 
+    /**
+     * 登陆时的卡号或手机号
+     */
+    private String loginUserName;
+
     /**
      * 部门ID
      */
@@ -70,23 +75,28 @@ public class LoginUser implements UserDetails
      * 用户信息
      */
     private SysUser user;
+    private LoginCard card;
 
     public LoginUser()
     {
     }
 
-    public LoginUser(SysUser user, Set<String> permissions)
+    public LoginUser(SysUser user, LoginCard card, Set<String> permissions)
     {
         this.user = user;
+        this.card = card;
         this.permissions = permissions;
+        this.loginUserName = user.getUserName();
     }
 
-    public LoginUser(Long userId, Long deptId, SysUser user, Set<String> permissions)
+    public LoginUser(Long userId, Long deptId, SysUser user, LoginCard card, Set<String> permissions)
     {
         this.userId = userId;
         this.deptId = deptId;
         this.user = user;
+        this.card = card;
         this.permissions = permissions;
+        this.loginUserName = user.getUserName();
     }
 
     public Long getUserId()
@@ -129,7 +139,7 @@ public class LoginUser implements UserDetails
     @Override
     public String getUsername()
     {
-        return user.getUserName();
+        return loginUserName;
     }
 
     /**
@@ -258,6 +268,22 @@ public class LoginUser implements UserDetails
         this.user = user;
     }
 
+    public LoginCard getCard() {
+        return card;
+    }
+
+    public void setCard(LoginCard card) {
+        this.card = card;
+    }
+
+    public String getLoginUserName() {
+        return loginUserName;
+    }
+
+    public void setLoginUserName(String loginUserName) {
+        this.loginUserName = loginUserName;
+    }
+
     @Override
     public Collection<? extends GrantedAuthority> getAuthorities()
     {

+ 24 - 1
ie-common/src/main/java/com/ruoyi/common/core/domain/model/RegisterBody.java

@@ -1,11 +1,34 @@
 package com.ruoyi.common.core.domain.model;
 
+import com.ruoyi.common.enums.ExamType;
+import com.ruoyi.common.utils.dz.SubjectScore;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
 /**
  * 用户注册对象
  * 
  * @author ruoyi
  */
+@ApiModel("完善信息")
+@Data
 public class RegisterBody extends LoginBody
 {
-
+    @ApiModelProperty(value = "学生姓名", example = "张三")
+    String nickName;
+    @ApiModelProperty(value = "所在省份", example = "湖南")
+    String location;
+    @ApiModelProperty(value = "考生类型字典", example = "OHS")
+    ExamType examType;
+    @ApiModelProperty(value = "毕业年份", example = "2028")
+    Integer endYear;
+    @ApiModelProperty("邀请码")
+    String inviteCode;
+    @ApiModelProperty("多科成绩")
+    SubjectScore scores = new SubjectScore();
+    @ApiModelProperty(value = "学校ID", example = "1")
+    Long schoolId;
+    @ApiModelProperty(value = "班级ID", example = "1")
+    Long classId;
 }

+ 22 - 0
ie-common/src/main/java/com/ruoyi/common/enums/ExamType.java

@@ -0,0 +1,22 @@
+package com.ruoyi.common.enums;
+
+public enum ExamType {
+    OHS("单招(应届普高)", "Ordinary High School"),
+    SVS("单招(中职)", "Secondary Vocational School"),
+    VHS("职高对口升学", "Vocational High School");
+
+    public String title() {
+        return title;
+    }
+
+    public String nameEn() {
+        return nameEn;
+    }
+
+    private final String title;
+    private final String nameEn;
+    ExamType(String title, String nameEn) {
+        this.title = title;
+        this.nameEn = nameEn;
+    }
+}

+ 37 - 0
ie-common/src/main/java/com/ruoyi/common/enums/SubjectType.java

@@ -0,0 +1,37 @@
+package com.ruoyi.common.enums;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public enum SubjectType {
+    Physics("物理", "物"), History("历史", "历"), Chemistry("化学", "化"), Biology("生物", "生"), Geography("地理", "地"), Political("政治", "政"),
+    Chinese("语文", "语"), Mathematics("数学", "数"), English("英语", "英"), Foreign("外语", "外");
+
+    public String title() {
+        return title;
+    }
+
+    public static SubjectType parse(String name) {
+        SubjectType st = map.get(name);
+        if(null == st) {
+            throw new RuntimeException("Invalid SubjectType " + name);
+        }
+        return map.get(name.toLowerCase());
+    }
+
+    private final String title;
+    private final String abbr;
+    SubjectType(String title, String abbr) {
+        this.title = title;
+        this.abbr = abbr;
+    }
+
+    private static Map<String, SubjectType> map = new HashMap<>();
+    static {
+        for(SubjectType type : SubjectType.values()) {
+            map.put(type.title, type);
+            map.put(type.abbr, type);
+            map.put(type.name().toLowerCase(), type);
+        }
+    }
+}

+ 23 - 0
ie-common/src/main/java/com/ruoyi/common/enums/UserRegStatus.java

@@ -0,0 +1,23 @@
+package com.ruoyi.common.enums;
+
+/**
+ * 用户状态
+ * 
+ * @author ruoyi
+ */
+public enum UserRegStatus
+{
+    Visitor("游客"), User("用户"), Student("学生");
+
+    private final String info;
+
+    UserRegStatus(String info)
+    {
+        this.info = info;
+    }
+
+    public String getInfo()
+    {
+        return info;
+    }
+}

+ 43 - 0
ie-common/src/main/java/com/ruoyi/common/utils/PhoneUtils.java

@@ -0,0 +1,43 @@
+package com.ruoyi.common.utils;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class PhoneUtils {
+    /**
+     * 判断是不是合法的手机号码
+     * @param phoneNumber
+     * @return
+     */
+    public static boolean isPhoneNumber(String phoneNumber){
+        if(StringUtils.isEmpty(phoneNumber)){
+            return false;
+        }
+        //第一位是不是0
+        String phoneOne=phoneNumber.substring(0,1);
+        //是不是 +86形式
+        int is86=phoneNumber.indexOf("+86");
+        if(is86==0){
+            phoneNumber = phoneNumber.substring(3,phoneNumber.length());
+        }
+        //手机号码长度
+        int phoneLength=phoneNumber.length();
+        //是纯数字 并且长度等于11 并且第一位不是0 并且 不包含+86
+        return isNumeric(phoneNumber)&&phoneLength==11&&!phoneOne.equals("0");
+    }
+    /**
+     * 判断字符串是不是纯数字
+     */
+    public static boolean isNumeric(String str){
+        Pattern pattern = Pattern.compile("[0-9]*");
+        Matcher isNum = pattern.matcher(str);
+        if( !isNum.matches() ){
+            return false;
+        }
+        return true;
+    }
+
+    public static void main(String[] args) {
+        System.out.println(new PhoneUtils().isPhoneNumber("18500040805"));
+    }
+}

+ 223 - 0
ie-common/src/main/java/com/ruoyi/common/utils/QRCodeUtils.java

@@ -0,0 +1,223 @@
+package com.ruoyi.common.utils;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.EncodeHintType;
+import com.google.zxing.MultiFormatWriter;
+import com.google.zxing.common.BitMatrix;
+import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.geom.RoundRectangle2D;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.OutputStream;
+import java.util.Hashtable;
+import java.util.Random;
+
+public class QRCodeUtils {
+    private static final String CHARSET = "utf-8";
+    private static final String FORMAT_NAME = "JPG";
+    // 二维码尺寸
+    private static final int QRCODE_SIZE = 300;
+    // LOGO宽度
+    private static final int WIDTH = 60;
+    // LOGO高度
+    private static final int HEIGHT = 60;
+
+    private static BufferedImage createImage(String content, String imgPath, boolean needCompress) throws Exception {
+        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
+        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
+        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
+        hints.put(EncodeHintType.MARGIN, 1);
+        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE,hints);
+        int width = bitMatrix.getWidth();
+        int height = bitMatrix.getHeight();
+        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+        for (int x = 0; x < width; x++) {
+            for (int y = 0; y < height; y++) {
+                image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
+            }
+        }
+        if (imgPath == null || "".equals(imgPath)) {
+            return image;
+        }
+        // 插入图片
+        QRCodeUtils.insertImage(image, imgPath, needCompress);
+        return image;
+    }
+
+    /**
+     * 插入LOGO
+     *
+     * @param source
+     *            二维码图片
+     * @param imgPath
+     *            LOGO图片地址
+     * @param needCompress
+     *            是否压缩
+     * @throws Exception
+     */
+    private static void insertImage(BufferedImage source, String imgPath, boolean needCompress) throws Exception {
+        File file = new File(imgPath);
+        if (!file.exists()) {
+            System.err.println("" + imgPath + "   该文件不存在!");
+            return;
+        }
+        Image src = ImageIO.read(new File(imgPath));
+        insertImage(source, src, needCompress);
+    }
+    public static void insertImage(BufferedImage source, Image src, boolean needCompress) throws Exception {
+        int width = src.getWidth(null);
+        int height = src.getHeight(null);
+        if (needCompress) { // 压缩LOGO
+            if (width > WIDTH) {
+                width = WIDTH;
+            }
+            if (height > HEIGHT) {
+                height = HEIGHT;
+            }
+            Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
+            BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+            Graphics g = tag.getGraphics();
+            g.drawImage(image, 0, 0, null); // 绘制缩小后的图
+            g.dispose();
+            src = image;
+        }
+        // 插入LOGO
+        Graphics2D graph = source.createGraphics();
+        int x = (QRCODE_SIZE - width) / 2;
+        int y = (QRCODE_SIZE - height) / 2;
+        graph.drawImage(src, x, y, width, height, null);
+        Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
+        graph.setStroke(new BasicStroke(3f));
+        graph.draw(shape);
+        graph.dispose();
+    }
+
+    /**
+     * 生成二维码(内嵌LOGO)
+     *
+     * @param content
+     *            内容
+     * @param imgPath
+     *            LOGO地址
+     * @param destPath
+     *            存放目录
+     * @param needCompress
+     *            是否压缩LOGO
+     * @throws Exception
+     */
+    public static void encode(String content, String imgPath, String destPath, boolean needCompress) throws Exception {
+        BufferedImage image = QRCodeUtils.createImage(content, imgPath, needCompress);
+        mkdirs(destPath);
+        String file = new Random().nextInt(99999999) + ".jpg";
+        ImageIO.write(image, FORMAT_NAME, new File(destPath + "/" + file));
+    }
+
+    /**
+     * 当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir.(mkdir如果父目录不存在则会抛出异常)
+     *
+     * @author lanyuan Email: mmm333zzz520@163.com
+     * @date 2013-12-11 上午10:16:36
+     * @param destPath
+     *            存放目录
+     */
+    public static void mkdirs(String destPath) {
+        File file = new File(destPath);
+        // 当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir.(mkdir如果父目录不存在则会抛出异常)
+        if (!file.exists() && !file.isDirectory()) {
+            file.mkdirs();
+        }
+    }
+
+    /**
+     * 生成二维码(内嵌LOGO)
+     *
+     * @param content
+     *            内容
+     * @param imgPath
+     *            LOGO地址
+     * @param destPath
+     *            存储地址
+     * @throws Exception
+     */
+    public static void encode(String content, String imgPath, String destPath) throws Exception {
+        QRCodeUtils.encode(content, imgPath, destPath, false);
+    }
+
+    /**
+     * 生成二维码
+     *
+     * @param content
+     *            内容
+     * @param destPath
+     *            存储地址
+     * @param needCompress
+     *            是否压缩LOGO
+     * @throws Exception
+     */
+    public static void encode(String content, String destPath, boolean needCompress) throws Exception {
+        QRCodeUtils.encode(content, null, destPath, needCompress);
+    }
+
+    /**
+     * 生成二维码
+     *
+     * @param content
+     *            内容
+     * @param destPath
+     *            存储地址
+     * @throws Exception
+     */
+    public static void encode(String content, String destPath) throws Exception {
+        QRCodeUtils.encode(content, null, destPath, false);
+    }
+
+    /**
+     * 生成二维码(内嵌LOGO)
+     *
+     * @param content
+     *            内容
+     * @param imgPath
+     *            LOGO地址
+     * @param output
+     *            输出流
+     * @param needCompress
+     *            是否压缩LOGO
+     * @throws Exception
+     */
+    public static void encode(String content, String imgPath, OutputStream output, boolean needCompress)
+            throws Exception {
+        BufferedImage image = QRCodeUtils.createImage(content, imgPath, needCompress);
+        ImageIO.write(image, FORMAT_NAME, output);
+    }
+
+    /**
+     * 生成二维码
+     *
+     * @param content
+     *            内容
+     * @param output
+     *            输出流
+     * @throws Exception
+     */
+    public static void encode(String content, OutputStream output) throws Exception {
+        QRCodeUtils.encode(content, null, output, false);
+    }
+
+    public static void encode(String content, Image logo, OutputStream output) throws Exception {
+        BufferedImage image = QRCodeUtils.createImage(content, null, true);
+        if (null != logo) {
+            QRCodeUtils.insertImage(image, logo, true);
+        }
+        ImageIO.write(image, FORMAT_NAME, output);
+    }
+
+    public static void main(String[] args) throws Exception {
+        String text = "test";
+        QRCodeUtils.encode(text, "/Users/admin/Downloads/login_logo.48856221 (1).png",
+                "/Users/admin/Downloads", true);
+        // QRCodeUtil.encode(text, null, "/Users/noahshen/Downloads", true);
+    }
+}

+ 241 - 0
ie-common/src/main/java/com/ruoyi/common/utils/VerifyCodeUtils.java

@@ -0,0 +1,241 @@
+package com.ruoyi.common.utils;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.Random;
+
+/**
+ * 验证码工具类
+ * 
+ * @author ruoyi
+ */
+public class VerifyCodeUtils
+{
+    // 使用到Algerian字体,系统里没有的话需要安装字体,字体只显示大写,去掉了1,0,i,o几个容易混淆的字符
+    public static final String VERIFY_CODES = "123456789ABCDEFGHJKLMNPQRSTUVWXYZ";
+
+    private static Random random = new SecureRandom();
+
+
+    /**
+     * 返回指定长度随机数字组成的字符串
+     *
+     * @param length
+     *            指定长度
+     * @return 随机字符串
+     */
+    public static String captchaNumber(int length) {
+        StringBuilder sb = new StringBuilder();
+        Random rand = new Random();
+        for (int i = 0; i < length; i++) {
+            sb.append(rand.nextInt(10));
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 使用系统默认字符源生成验证码
+     * 
+     * @param verifySize 验证码长度
+     * @return
+     */
+    public static String generateVerifyCode(int verifySize)
+    {
+        return generateVerifyCode(verifySize, VERIFY_CODES);
+    }
+
+    /**
+     * 使用指定源生成验证码
+     * 
+     * @param verifySize 验证码长度
+     * @param sources 验证码字符源
+     * @return
+     */
+    public static String generateVerifyCode(int verifySize, String sources)
+    {
+        if (sources == null || sources.length() == 0)
+        {
+            sources = VERIFY_CODES;
+        }
+        int codesLen = sources.length();
+        Random rand = new Random(System.currentTimeMillis());
+        StringBuilder verifyCode = new StringBuilder(verifySize);
+        for (int i = 0; i < verifySize; i++)
+        {
+            verifyCode.append(sources.charAt(rand.nextInt(codesLen - 1)));
+        }
+        return verifyCode.toString();
+    }
+
+    /**
+     * 输出指定验证码图片流
+     * 
+     * @param w
+     * @param h
+     * @param os
+     * @param code
+     * @throws IOException
+     */
+    public static void outputImage(int w, int h, OutputStream os, String code) throws IOException
+    {
+        int verifySize = code.length();
+        BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+        Random rand = new Random();
+        Graphics2D g2 = image.createGraphics();
+        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        Color[] colors = new Color[5];
+        Color[] colorSpaces = new Color[] { Color.WHITE, Color.CYAN, Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA,
+                Color.ORANGE, Color.PINK, Color.YELLOW };
+        float[] fractions = new float[colors.length];
+        for (int i = 0; i < colors.length; i++)
+        {
+            colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)];
+            fractions[i] = rand.nextFloat();
+        }
+        Arrays.sort(fractions);
+
+        g2.setColor(Color.GRAY);// 设置边框色
+        g2.fillRect(0, 0, w, h);
+
+        Color c = getRandColor(200, 250);
+        g2.setColor(c);// 设置背景色
+        g2.fillRect(0, 2, w, h - 4);
+
+        // 绘制干扰线
+        Random random = new Random();
+        g2.setColor(getRandColor(160, 200));// 设置线条的颜色
+        for (int i = 0; i < 20; i++)
+        {
+            int x = random.nextInt(w - 1);
+            int y = random.nextInt(h - 1);
+            int xl = random.nextInt(6) + 1;
+            int yl = random.nextInt(12) + 1;
+            g2.drawLine(x, y, x + xl + 40, y + yl + 20);
+        }
+
+        // 添加噪点
+        float yawpRate = 0.05f;// 噪声率
+        int area = (int) (yawpRate * w * h);
+        for (int i = 0; i < area; i++)
+        {
+            int x = random.nextInt(w);
+            int y = random.nextInt(h);
+            int rgb = getRandomIntColor();
+            image.setRGB(x, y, rgb);
+        }
+
+        shear(g2, w, h, c);// 使图片扭曲
+
+        g2.setColor(getRandColor(100, 160));
+        int fontSize = h - 4;
+        Font font = new Font("Algerian", Font.ITALIC, fontSize);
+        g2.setFont(font);
+        char[] chars = code.toCharArray();
+        for (int i = 0; i < verifySize; i++)
+        {
+            AffineTransform affine = new AffineTransform();
+            affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1),
+                    (w / verifySize) * i + fontSize / 2, h / 2);
+            g2.setTransform(affine);
+            g2.drawChars(chars, i, 1, ((w - 10) / verifySize) * i + 5, h / 2 + fontSize / 2 - 10);
+        }
+
+        g2.dispose();
+        ImageIO.write(image, "jpg", os);
+    }
+
+    private static Color getRandColor(int fc, int bc)
+    {
+        if (fc > 255) {
+            fc = 255;
+        }
+        if (bc > 255) {
+            bc = 255;
+        }
+        int r = fc + random.nextInt(bc - fc);
+        int g = fc + random.nextInt(bc - fc);
+        int b = fc + random.nextInt(bc - fc);
+        return new Color(r, g, b);
+    }
+
+    private static int getRandomIntColor()
+    {
+        int[] rgb = getRandomRgb();
+        int color = 0;
+        for (int c : rgb)
+        {
+            color = color << 8;
+            color = color | c;
+        }
+        return color;
+    }
+
+    private static int[] getRandomRgb()
+    {
+        int[] rgb = new int[3];
+        for (int i = 0; i < 3; i++)
+        {
+            rgb[i] = random.nextInt(255);
+        }
+        return rgb;
+    }
+
+    private static void shear(Graphics g, int w1, int h1, Color color)
+    {
+        shearX(g, w1, h1, color);
+        shearY(g, w1, h1, color);
+    }
+
+    private static void shearX(Graphics g, int w1, int h1, Color color)
+    {
+
+        int period = random.nextInt(2);
+
+        boolean borderGap = true;
+        int frames = 1;
+        int phase = random.nextInt(2);
+
+        for (int i = 0; i < h1; i++)
+        {
+            double d = (double) (period >> 1)
+                    * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);
+            g.copyArea(0, i, w1, 1, (int) d, 0);
+            if (borderGap)
+            {
+                g.setColor(color);
+                g.drawLine((int) d, i, 0, i);
+                g.drawLine((int) d + w1, i, w1, i);
+            }
+        }
+
+    }
+
+    private static void shearY(Graphics g, int w1, int h1, Color color)
+    {
+
+        int period = random.nextInt(40) + 10; // 50;
+
+        boolean borderGap = true;
+        int frames = 20;
+        int phase = 7;
+        for (int i = 0; i < w1; i++)
+        {
+            double d = (double) (period >> 1)
+                    * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);
+            g.copyArea(i, 0, 1, h1, 0, (int) d);
+            if (borderGap)
+            {
+                g.setColor(color);
+                g.drawLine(i, (int) d, i, 0);
+                g.drawLine(i, (int) d + h1, i, h1);
+            }
+
+        }
+    }
+}

+ 60 - 0
ie-common/src/main/java/com/ruoyi/common/utils/WXPayConstants.java

@@ -0,0 +1,60 @@
+package com.ruoyi.common.utils;
+
+import org.apache.http.client.HttpClient;
+
+/**
+ * 常量
+ */
+public class WXPayConstants {
+
+    public static enum SignType {
+        MD5, HMACSHA256
+    }
+
+    public static final String DOMAIN_API = "api.mch.weixin.qq.com";
+    public static final String DOMAIN_API2 = "api2.mch.weixin.qq.com";
+    public static final String DOMAIN_APIHK = "apihk.mch.weixin.qq.com";
+    public static final String DOMAIN_APIUS = "apius.mch.weixin.qq.com";
+
+
+    public static final String FAIL     = "FAIL";
+    public static final String SUCCESS  = "SUCCESS";
+    public static final String HMACSHA256 = "HMAC-SHA256";
+    public static final String MD5 = "MD5";
+
+    public static final String FIELD_SIGN = "sign";
+    public static final String FIELD_SIGN_TYPE = "sign_type";
+
+    public static final String WXPAYSDK_VERSION = "WXPaySDK/3.0.9";
+    public static final String USER_AGENT = WXPAYSDK_VERSION +
+            " (" + System.getProperty("os.arch") + " " + System.getProperty("os.name") + " " + System.getProperty("os.version") +
+            ") Java/" + System.getProperty("java.version") + " HttpClient/" + HttpClient.class.getPackage().getImplementationVersion();
+
+    public static final String MICROPAY_URL_SUFFIX     = "/pay/micropay";
+    public static final String UNIFIEDORDER_URL_SUFFIX = "/pay/unifiedorder";
+    public static final String ORDERQUERY_URL_SUFFIX   = "/pay/orderquery";
+    public static final String REVERSE_URL_SUFFIX      = "/secapi/pay/reverse";
+    public static final String CLOSEORDER_URL_SUFFIX   = "/pay/closeorder";
+    public static final String REFUND_URL_SUFFIX       = "/secapi/pay/refund";
+    public static final String REFUNDQUERY_URL_SUFFIX  = "/pay/refundquery";
+    public static final String DOWNLOADBILL_URL_SUFFIX = "/pay/downloadbill";
+    public static final String REPORT_URL_SUFFIX       = "/payitil/report";
+    public static final String SHORTURL_URL_SUFFIX     = "/tools/shorturl";
+    public static final String AUTHCODETOOPENID_URL_SUFFIX = "/tools/authcodetoopenid";
+    public static final String TRANSFERS_URL_SUFFIX = "/mmpaymkttransfers/promotion/transfers";
+
+    // sandbox
+    public static final String SANDBOX_MICROPAY_URL_SUFFIX     = "/sandboxnew/pay/micropay";
+    public static final String SANDBOX_UNIFIEDORDER_URL_SUFFIX = "/sandboxnew/pay/unifiedorder";
+    public static final String SANDBOX_ORDERQUERY_URL_SUFFIX   = "/sandboxnew/pay/orderquery";
+    public static final String SANDBOX_REVERSE_URL_SUFFIX      = "/sandboxnew/secapi/pay/reverse";
+    public static final String SANDBOX_CLOSEORDER_URL_SUFFIX   = "/sandboxnew/pay/closeorder";
+    public static final String SANDBOX_REFUND_URL_SUFFIX       = "/sandboxnew/secapi/pay/refund";
+    public static final String SANDBOX_REFUNDQUERY_URL_SUFFIX  = "/sandboxnew/pay/refundquery";
+    public static final String SANDBOX_DOWNLOADBILL_URL_SUFFIX = "/sandboxnew/pay/downloadbill";
+    public static final String SANDBOX_REPORT_URL_SUFFIX       = "/sandboxnew/payitil/report";
+    public static final String SANDBOX_SHORTURL_URL_SUFFIX     = "/sandboxnew/tools/shorturl";
+    public static final String SANDBOX_AUTHCODETOOPENID_URL_SUFFIX = "/sandboxnew/tools/authcodetoopenid";
+
+}
+

+ 295 - 0
ie-common/src/main/java/com/ruoyi/common/utils/WXPayUtil.java

@@ -0,0 +1,295 @@
+package com.ruoyi.common.utils;
+
+import com.ruoyi.common.utils.WXPayConstants.SignType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.security.MessageDigest;
+import java.security.SecureRandom;
+import java.util.*;
+
+
+public class WXPayUtil {
+
+    private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+    private static final Random RANDOM = new SecureRandom();
+
+    /**
+     * XML格式字符串转换为Map
+     *
+     * @param strXML XML字符串
+     * @return XML数据转换后的Map
+     * @throws Exception
+     */
+    public static Map<String, String> xmlToMap(String strXML) throws Exception {
+        try {
+            Map<String, String> data = new HashMap<String, String>();
+            DocumentBuilder documentBuilder = WXPayXmlUtil.newDocumentBuilder();
+            InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
+            org.w3c.dom.Document doc = documentBuilder.parse(stream);
+            doc.getDocumentElement().normalize();
+            NodeList nodeList = doc.getDocumentElement().getChildNodes();
+            for (int idx = 0; idx < nodeList.getLength(); ++idx) {
+                Node node = nodeList.item(idx);
+                if (node.getNodeType() == Node.ELEMENT_NODE) {
+                    org.w3c.dom.Element element = (org.w3c.dom.Element) node;
+                    data.put(element.getNodeName(), element.getTextContent());
+                }
+            }
+            try {
+                stream.close();
+            } catch (Exception ex) {
+                // do nothing
+            }
+            return data;
+        } catch (Exception ex) {
+            WXPayUtil.getLogger().warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML);
+            throw ex;
+        }
+
+    }
+
+    /**
+     * 将Map转换为XML格式的字符串
+     *
+     * @param data Map类型数据
+     * @return XML格式的字符串
+     * @throws Exception
+     */
+    public static String mapToXml(Map<String, String> data) throws Exception {
+        org.w3c.dom.Document document = WXPayXmlUtil.newDocument();
+        org.w3c.dom.Element root = document.createElement("xml");
+        document.appendChild(root);
+        for (String key: data.keySet()) {
+            String value = data.get(key);
+            if (value == null) {
+                value = "";
+            }
+            value = value.trim();
+            org.w3c.dom.Element filed = document.createElement(key);
+            filed.appendChild(document.createTextNode(value));
+            root.appendChild(filed);
+        }
+        TransformerFactory tf = TransformerFactory.newInstance();
+        Transformer transformer = tf.newTransformer();
+        DOMSource source = new DOMSource(document);
+        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+        StringWriter writer = new StringWriter();
+        StreamResult result = new StreamResult(writer);
+        transformer.transform(source, result);
+        String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");
+        try {
+            writer.close();
+        }
+        catch (Exception ex) {
+        }
+        return output;
+    }
+
+
+    /**
+     * 生成带有 sign 的 XML 格式字符串
+     *
+     * @param data Map类型数据
+     * @param key API密钥
+     * @return 含有sign字段的XML
+     */
+    public static String generateSignedXml(final Map<String, String> data, String key) throws Exception {
+        return generateSignedXml(data, key, SignType.MD5);
+    }
+
+    /**
+     * 生成带有 sign 的 XML 格式字符串
+     *
+     * @param data Map类型数据
+     * @param key API密钥
+     * @param signType 签名类型
+     * @return 含有sign字段的XML
+     */
+    public static String generateSignedXml(final Map<String, String> data, String key, SignType signType) throws Exception {
+        String sign = generateSignature(data, key, signType);
+        data.put(WXPayConstants.FIELD_SIGN, sign);
+        return mapToXml(data);
+    }
+
+
+    /**
+     * 判断签名是否正确
+     *
+     * @param xmlStr XML格式数据
+     * @param key API密钥
+     * @return 签名是否正确
+     * @throws Exception
+     */
+    public static boolean isSignatureValid(String xmlStr, String key) throws Exception {
+        Map<String, String> data = xmlToMap(xmlStr);
+        if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) {
+            return false;
+        }
+        String sign = data.get(WXPayConstants.FIELD_SIGN);
+        return generateSignature(data, key).equals(sign);
+    }
+
+    /**
+     * 判断签名是否正确,必须包含sign字段,否则返回false。使用MD5签名。
+     *
+     * @param data Map类型数据
+     * @param key API密钥
+     * @return 签名是否正确
+     * @throws Exception
+     */
+    public static boolean isSignatureValid(Map<String, String> data, String key) throws Exception {
+        return isSignatureValid(data, key, SignType.MD5);
+    }
+
+    /**
+     * 判断签名是否正确,必须包含sign字段,否则返回false。
+     *
+     * @param data Map类型数据
+     * @param key API密钥
+     * @param signType 签名方式
+     * @return 签名是否正确
+     * @throws Exception
+     */
+    public static boolean isSignatureValid(Map<String, String> data, String key, SignType signType) throws Exception {
+        if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) {
+            return false;
+        }
+        String sign = data.get(WXPayConstants.FIELD_SIGN);
+        return generateSignature(data, key, signType).equals(sign);
+    }
+
+    /**
+     * 生成签名
+     *
+     * @param data 待签名数据
+     * @param key API密钥
+     * @return 签名
+     */
+    public static String generateSignature(final Map<String, String> data, String key) throws Exception {
+        return generateSignature(data, key, SignType.MD5);
+    }
+
+    /**
+     * 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。
+     *
+     * @param data 待签名数据
+     * @param key API密钥
+     * @param signType 签名方式
+     * @return 签名
+     */
+    public static String generateSignature(final Map<String, String> data, String key, SignType signType) throws Exception {
+        Set<String> keySet = data.keySet();
+        String[] keyArray = keySet.toArray(new String[keySet.size()]);
+        Arrays.sort(keyArray);
+        StringBuilder sb = new StringBuilder();
+        for (String k : keyArray) {
+            if (k.equals(WXPayConstants.FIELD_SIGN)) {
+                continue;
+            }
+            if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名
+                sb.append(k).append("=").append(data.get(k).trim()).append("&");
+        }
+        sb.append("key=").append(key);
+        if (SignType.MD5.equals(signType)) {
+            return MD5(sb.toString()).toUpperCase();
+        }
+        else if (SignType.HMACSHA256.equals(signType)) {
+            return HMACSHA256(sb.toString(), key);
+        }
+        else {
+            throw new Exception(String.format("Invalid sign_type: %s", signType));
+        }
+    }
+
+
+    /**
+     * 获取随机字符串 Nonce Str
+     *
+     * @return String 随机字符串
+     */
+    public static String generateNonceStr() {
+        char[] nonceChars = new char[32];
+        for (int index = 0; index < nonceChars.length; ++index) {
+            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
+        }
+        return new String(nonceChars);
+    }
+
+
+    /**
+     * 生成 MD5
+     *
+     * @param data 待处理数据
+     * @return MD5结果
+     */
+    public static String MD5(String data) throws Exception {
+        MessageDigest md = MessageDigest.getInstance("MD5");
+        byte[] array = md.digest(data.getBytes("UTF-8"));
+        StringBuilder sb = new StringBuilder();
+        for (byte item : array) {
+            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
+        }
+        return sb.toString().toUpperCase();
+    }
+
+    /**
+     * 生成 HMACSHA256
+     * @param data 待处理数据
+     * @param key 密钥
+     * @return 加密结果
+     * @throws Exception
+     */
+    public static String HMACSHA256(String data, String key) throws Exception {
+        Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
+        SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
+        sha256_HMAC.init(secret_key);
+        byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
+        StringBuilder sb = new StringBuilder();
+        for (byte item : array) {
+            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
+        }
+        return sb.toString().toUpperCase();
+    }
+
+    /**
+     * 日志
+     * @return
+     */
+    public static Logger getLogger() {
+        Logger logger = LoggerFactory.getLogger(WXPayUtil.class);
+        return logger;
+    }
+
+    /**
+     * 获取当前时间戳,单位秒
+     * @return
+     */
+    public static long getCurrentTimestamp() {
+        return System.currentTimeMillis()/1000;
+    }
+
+    /**
+     * 获取当前时间戳,单位毫秒
+     * @return
+     */
+    public static long getCurrentTimestampMs() {
+        return System.currentTimeMillis();
+    }
+
+}

+ 30 - 0
ie-common/src/main/java/com/ruoyi/common/utils/WXPayXmlUtil.java

@@ -0,0 +1,30 @@
+package com.ruoyi.common.utils;
+
+import org.w3c.dom.Document;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+/**
+ * 2018/7/3
+ */
+public final class WXPayXmlUtil {
+    public static DocumentBuilder newDocumentBuilder() throws ParserConfigurationException {
+        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+        documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+        documentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
+        documentBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+        documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+        documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+        documentBuilderFactory.setXIncludeAware(false);
+        documentBuilderFactory.setExpandEntityReferences(false);
+
+        return documentBuilderFactory.newDocumentBuilder();
+    }
+
+    public static Document newDocument() throws ParserConfigurationException {
+        return newDocumentBuilder().newDocument();
+    }
+}

+ 49 - 0
ie-common/src/main/java/com/ruoyi/common/utils/dz/SubjectScore.java

@@ -0,0 +1,49 @@
+package com.ruoyi.common.utils.dz;
+
+import com.ruoyi.common.enums.SubjectType;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.apache.commons.beanutils.PropertyUtils;
+
+import java.lang.reflect.InvocationTargetException;
+
+@Data
+@ApiModel("分科成绩")
+public class SubjectScore {
+    @ApiModelProperty(value = "物理", example = "80")
+    Double physics;
+    @ApiModelProperty(value = "历史", example = "80")
+    Double history;
+    @ApiModelProperty(value = "化学", example = "80")
+    Double chemistry;
+    @ApiModelProperty(value = "生物", example = "80")
+    Double biology;
+    @ApiModelProperty(value = "地理", example = "80")
+    Double geography;
+    @ApiModelProperty(value = "政治", example = "80")
+    Double political;
+    @ApiModelProperty(value = "语文", example = "80")
+    Double chinese;
+    @ApiModelProperty(value = "数学", example = "80")
+    Double mathematics;
+    @ApiModelProperty(value = "英语", example = "80")
+    Double english;
+    @ApiModelProperty(value = "外语", example = "80")
+    Double foreign;
+
+    /** 物化生历政地 语数英外 **/
+    public Double getSelectScore(String name) {
+        Double totalScore = 0.0;
+        for(String ch : name.split("")) {
+            SubjectType st = SubjectType.parse(ch);
+            try {
+                Object val = PropertyUtils.getProperty(this, st.name().toLowerCase());
+                totalScore += Double.valueOf(val.toString());
+            } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        return totalScore;
+    }
+}

+ 2 - 2
ie-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java

@@ -1,12 +1,12 @@
 package com.ruoyi.framework.config;
 
+import com.ruoyi.framework.security.provider.MyDaoAuthenticationProvider;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.http.HttpMethod;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.ProviderManager;
-import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
 import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.http.SessionCreationPolicy;
@@ -72,7 +72,7 @@ public class SecurityConfig
     @Bean
     public AuthenticationManager authenticationManager()
     {
-        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
+        MyDaoAuthenticationProvider daoAuthenticationProvider = new MyDaoAuthenticationProvider();
         daoAuthenticationProvider.setUserDetailsService(userDetailsService);
         daoAuthenticationProvider.setPasswordEncoder(bCryptPasswordEncoder());
         return new ProviderManager(daoAuthenticationProvider);

+ 18 - 0
ie-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java

@@ -1,10 +1,16 @@
 package com.ruoyi.framework.security.filter;
 
 import java.io.IOException;
+import java.util.Collections;
 import javax.servlet.FilterChain;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.core.domain.model.LoginCard;
+import com.ruoyi.common.enums.ExamType;
+import com.ruoyi.common.enums.UserRegStatus;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.context.SecurityContextHolder;
@@ -38,6 +44,18 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
             UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
             authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
             SecurityContextHolder.getContext().setAuthentication(authenticationToken);
+        } else {
+            SysUser user = new SysUser();
+            user.setUserId(0L);
+            user.setUserName("anonymous");
+            user.setLocation(request.getHeader("location"));
+            String examType = request.getHeader("examType");
+            user.setExamType(null == examType ? null : ExamType.valueOf(examType));
+            user.setRegStatus(UserRegStatus.Visitor);
+            LoginUser anonymous = new LoginUser(user.getUserId(), 0L, user, new LoginCard(), Collections.emptyNavigableSet());
+            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(anonymous, null, Collections.emptyList());
+            authenticationToken.setAuthenticated(false);
+            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
         }
         chain.doFilter(request, response);
     }

+ 19 - 0
ie-framework/src/main/java/com/ruoyi/framework/security/provider/MyDaoAuthenticationProvider.java

@@ -0,0 +1,19 @@
+package com.ruoyi.framework.security.provider;
+
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.utils.PhoneUtils;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.userdetails.UserDetails;
+
+public class MyDaoAuthenticationProvider extends DaoAuthenticationProvider {
+    @Override
+    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
+        if (PhoneUtils.isPhoneNumber(userDetails.getUsername()) && UserConstants.LOGIN_SMS_PASS.equals(userDetails.getPassword())) {
+            return;
+        }
+        super.additionalAuthenticationChecks(userDetails, authentication);
+    }
+}
+

+ 0 - 117
ie-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java

@@ -1,117 +0,0 @@
-package com.ruoyi.framework.web.service;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-import com.ruoyi.common.constant.CacheConstants;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.constant.UserConstants;
-import com.ruoyi.common.core.domain.entity.SysUser;
-import com.ruoyi.common.core.domain.model.RegisterBody;
-import com.ruoyi.common.core.redis.RedisCache;
-import com.ruoyi.common.exception.user.CaptchaException;
-import com.ruoyi.common.exception.user.CaptchaExpireException;
-import com.ruoyi.common.utils.DateUtils;
-import com.ruoyi.common.utils.MessageUtils;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.framework.manager.AsyncManager;
-import com.ruoyi.framework.manager.factory.AsyncFactory;
-import com.ruoyi.system.service.ISysConfigService;
-import com.ruoyi.system.service.ISysUserService;
-
-/**
- * 注册校验方法
- * 
- * @author ruoyi
- */
-@Component
-public class SysRegisterService
-{
-    @Autowired
-    private ISysUserService userService;
-
-    @Autowired
-    private ISysConfigService configService;
-
-    @Autowired
-    private RedisCache redisCache;
-
-    /**
-     * 注册
-     */
-    public String register(RegisterBody registerBody)
-    {
-        String msg = "", username = registerBody.getUsername(), password = registerBody.getPassword();
-        SysUser sysUser = new SysUser();
-        sysUser.setUserName(username);
-
-        // 验证码开关
-        boolean captchaEnabled = configService.selectCaptchaEnabled();
-        if (captchaEnabled)
-        {
-            validateCaptcha(username, registerBody.getCode(), registerBody.getUuid());
-        }
-
-        if (StringUtils.isEmpty(username))
-        {
-            msg = "用户名不能为空";
-        }
-        else if (StringUtils.isEmpty(password))
-        {
-            msg = "用户密码不能为空";
-        }
-        else if (username.length() < UserConstants.USERNAME_MIN_LENGTH
-                || username.length() > UserConstants.USERNAME_MAX_LENGTH)
-        {
-            msg = "账户长度必须在2到20个字符之间";
-        }
-        else if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
-                || password.length() > UserConstants.PASSWORD_MAX_LENGTH)
-        {
-            msg = "密码长度必须在5到20个字符之间";
-        }
-        else if (!userService.checkUserNameUnique(sysUser))
-        {
-            msg = "保存用户'" + username + "'失败,注册账号已存在";
-        }
-        else
-        {
-            sysUser.setNickName(username);
-            sysUser.setPwdUpdateDate(DateUtils.getNowDate());
-            sysUser.setPassword(SecurityUtils.encryptPassword(password));
-            boolean regFlag = userService.registerUser(sysUser);
-            if (!regFlag)
-            {
-                msg = "注册失败,请联系系统管理人员";
-            }
-            else
-            {
-                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.REGISTER, MessageUtils.message("user.register.success")));
-            }
-        }
-        return msg;
-    }
-
-    /**
-     * 校验验证码
-     * 
-     * @param username 用户名
-     * @param code 验证码
-     * @param uuid 唯一标识
-     * @return 结果
-     */
-    public void validateCaptcha(String username, String code, String uuid)
-    {
-        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
-        String captcha = redisCache.getCacheObject(verifyKey);
-        redisCache.deleteObject(verifyKey);
-        if (captcha == null)
-        {
-            throw new CaptchaExpireException();
-        }
-        if (!code.equalsIgnoreCase(captcha))
-        {
-            throw new CaptchaException();
-        }
-    }
-}

+ 8 - 1
ie-system/pom.xml

@@ -22,7 +22,14 @@
             <groupId>com.ie</groupId>
             <artifactId>ie-common</artifactId>
         </dependency>
-
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>aliyun-java-sdk-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
+        </dependency>
     </dependencies>
 
 </project>

+ 99 - 0
ie-system/src/main/java/com/ruoyi/dz/domain/DzAgent.java

@@ -0,0 +1,99 @@
+package com.ruoyi.dz.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.TreeEntity;
+
+/**
+ * 机构代理对象 dz_agent
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public class DzAgent extends TreeEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 代理商ID */
+    private Long agentId;
+
+    /** 用户ID */
+    @Excel(name = "用户ID")
+    private Long userId;
+
+    /** 代理商名称 */
+    @Excel(name = "代理商名称")
+    private String name;
+
+    /** 联系电话 */
+    @Excel(name = "联系电话")
+    private String phonenumber;
+
+    /** 负责校区列表 */
+    @Excel(name = "负责校区列表")
+    private String schools;
+
+    public void setAgentId(Long agentId) 
+    {
+        this.agentId = agentId;
+    }
+
+    public Long getAgentId() 
+    {
+        return agentId;
+    }
+
+    public void setUserId(Long userId) 
+    {
+        this.userId = userId;
+    }
+
+    public Long getUserId() 
+    {
+        return userId;
+    }
+
+    public void setName(String name) 
+    {
+        this.name = name;
+    }
+
+    public String getName() 
+    {
+        return name;
+    }
+
+    public void setPhonenumber(String phonenumber) 
+    {
+        this.phonenumber = phonenumber;
+    }
+
+    public String getPhonenumber() 
+    {
+        return phonenumber;
+    }
+
+    public void setSchools(String schools) 
+    {
+        this.schools = schools;
+    }
+
+    public String getSchools() 
+    {
+        return schools;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("agentId", getAgentId())
+            .append("userId", getUserId())
+            .append("name", getName())
+            .append("phonenumber", getPhonenumber())
+            .append("parentId", getParentId())
+            .append("schools", getSchools())
+            .append("remark", getRemark())
+            .toString();
+    }
+}

+ 440 - 0
ie-system/src/main/java/com/ruoyi/dz/domain/DzCards.java

@@ -0,0 +1,440 @@
+package com.ruoyi.dz.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 学习卡对象 dz_cards
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public class DzCards extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** ID */
+    private Long cardId;
+
+    /** 账号 */
+    @Excel(name = "账号")
+    private String cardNo;
+
+    /** 初始密码 */
+    @Excel(name = "初始密码")
+    private String password;
+
+    /** 0电子卡(0开头,8位),6vip卡,8测试卡(6位),9体验卡 */
+    @Excel(name = "0电子卡", readConverterExp = "0=开头,8位")
+    private Integer type;
+
+    /** 0未开卡,1已开卡,2已激活, */
+    @Excel(name = "0未开卡,1已开卡,2已激活,")
+    private Integer status;
+
+    /** 0未分配,1已分配 */
+    @Excel(name = "0未分配,1已分配")
+    private Integer distributeStatus;
+
+    /** 9已过期,10已关卡,11已失效 */
+    @Excel(name = "9已过期,10已关卡,11已失效")
+    private Integer timeStatus;
+
+    /** 0=未缴费,1=已缴费,2=已退费 */
+    @Excel(name = "0=未缴费,1=已缴费,2=已退费")
+    private Long payStatus;
+
+    /** 是否结算(0:否,1:是) */
+    @Excel(name = "是否结算(0:否,1:是)")
+    private Integer isSettlement;
+
+    /** 机构ID */
+    @Excel(name = "机构ID")
+    private Long deptId;
+
+    /** 一级代理商ID */
+    @Excel(name = "一级代理商ID")
+    private Long agentId;
+
+    /** 末级代理商ID */
+    @Excel(name = "末级代理商ID")
+    private Long leftAgentId;
+
+    /** 安排校区 */
+    @Excel(name = "安排校区")
+    private Long campusId;
+
+    /** 分配学校 */
+    @Excel(name = "分配学校")
+    private Long assignSchoolId;
+
+    /** 校区id */
+    @Excel(name = "校区id")
+    private Long schoolId;
+
+    /** 校区班级ID */
+    @Excel(name = "校区班级ID")
+    private Long classId;
+
+    /** 班级/入学年份 */
+    @Excel(name = "班级/入学年份")
+    private Integer year;
+
+    /** 高考年份 */
+    @Excel(name = "高考年份")
+    private Integer endYear;
+
+    /** 开卡ID */
+    @Excel(name = "开卡ID")
+    private Long openId;
+
+    /** 分配时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "分配时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date distributeTime;
+
+    /** 过期时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "过期时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date outDate;
+
+    /** 开卡时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "开卡时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date openTime;
+
+    /** 缴费时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "缴费时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date payTime;
+
+    /** 激活时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "激活时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date activeTime;
+
+    /** 结算时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "结算时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date settlementTime;
+
+    /** 退费时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "退费时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date refundTime;
+
+    /** 关卡时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "关卡时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date closeTime;
+
+    public void setCardId(Long cardId) 
+    {
+        this.cardId = cardId;
+    }
+
+    public Long getCardId() 
+    {
+        return cardId;
+    }
+
+    public void setCardNo(String cardNo) 
+    {
+        this.cardNo = cardNo;
+    }
+
+    public String getCardNo() 
+    {
+        return cardNo;
+    }
+
+    public void setPassword(String password) 
+    {
+        this.password = password;
+    }
+
+    public String getPassword() 
+    {
+        return password;
+    }
+
+    public void setType(Integer type) 
+    {
+        this.type = type;
+    }
+
+    public Integer getType() 
+    {
+        return type;
+    }
+
+    public void setStatus(Integer status) 
+    {
+        this.status = status;
+    }
+
+    public Integer getStatus() 
+    {
+        return status;
+    }
+
+    public void setDistributeStatus(Integer distributeStatus) 
+    {
+        this.distributeStatus = distributeStatus;
+    }
+
+    public Integer getDistributeStatus() 
+    {
+        return distributeStatus;
+    }
+
+    public void setTimeStatus(Integer timeStatus) 
+    {
+        this.timeStatus = timeStatus;
+    }
+
+    public Integer getTimeStatus() 
+    {
+        return timeStatus;
+    }
+
+    public void setPayStatus(Long payStatus) 
+    {
+        this.payStatus = payStatus;
+    }
+
+    public Long getPayStatus() 
+    {
+        return payStatus;
+    }
+
+    public void setIsSettlement(Integer isSettlement) 
+    {
+        this.isSettlement = isSettlement;
+    }
+
+    public Integer getIsSettlement() 
+    {
+        return isSettlement;
+    }
+
+    public void setDeptId(Long deptId) 
+    {
+        this.deptId = deptId;
+    }
+
+    public Long getDeptId() 
+    {
+        return deptId;
+    }
+
+    public void setAgentId(Long agentId) 
+    {
+        this.agentId = agentId;
+    }
+
+    public Long getAgentId() 
+    {
+        return agentId;
+    }
+
+    public void setLeftAgentId(Long leftAgentId) 
+    {
+        this.leftAgentId = leftAgentId;
+    }
+
+    public Long getLeftAgentId() 
+    {
+        return leftAgentId;
+    }
+
+    public void setCampusId(Long campusId) 
+    {
+        this.campusId = campusId;
+    }
+
+    public Long getCampusId() 
+    {
+        return campusId;
+    }
+
+    public void setAssignSchoolId(Long assignSchoolId) 
+    {
+        this.assignSchoolId = assignSchoolId;
+    }
+
+    public Long getAssignSchoolId() 
+    {
+        return assignSchoolId;
+    }
+
+    public void setSchoolId(Long schoolId) 
+    {
+        this.schoolId = schoolId;
+    }
+
+    public Long getSchoolId() 
+    {
+        return schoolId;
+    }
+
+    public void setClassId(Long classId)
+    {
+        this.classId = classId;
+    }
+
+    public Long getClassId()
+    {
+        return classId;
+    }
+
+    public void setYear(Integer year)
+    {
+        this.year = year;
+    }
+
+    public Integer getYear()
+    {
+        return year;
+    }
+
+    public void setEndYear(Integer endYear)
+    {
+        this.endYear = endYear;
+    }
+
+    public Integer getEndYear()
+    {
+        return endYear;
+    }
+
+    public void setOpenId(Long openId) 
+    {
+        this.openId = openId;
+    }
+
+    public Long getOpenId() 
+    {
+        return openId;
+    }
+
+    public void setDistributeTime(Date distributeTime) 
+    {
+        this.distributeTime = distributeTime;
+    }
+
+    public Date getDistributeTime() 
+    {
+        return distributeTime;
+    }
+
+    public void setOutDate(Date outDate) 
+    {
+        this.outDate = outDate;
+    }
+
+    public Date getOutDate() 
+    {
+        return outDate;
+    }
+
+    public void setOpenTime(Date openTime) 
+    {
+        this.openTime = openTime;
+    }
+
+    public Date getOpenTime() 
+    {
+        return openTime;
+    }
+
+    public void setPayTime(Date payTime) 
+    {
+        this.payTime = payTime;
+    }
+
+    public Date getPayTime() 
+    {
+        return payTime;
+    }
+
+    public void setActiveTime(Date activeTime) 
+    {
+        this.activeTime = activeTime;
+    }
+
+    public Date getActiveTime() 
+    {
+        return activeTime;
+    }
+
+    public void setSettlementTime(Date settlementTime) 
+    {
+        this.settlementTime = settlementTime;
+    }
+
+    public Date getSettlementTime() 
+    {
+        return settlementTime;
+    }
+
+    public void setRefundTime(Date refundTime) 
+    {
+        this.refundTime = refundTime;
+    }
+
+    public Date getRefundTime() 
+    {
+        return refundTime;
+    }
+
+    public void setCloseTime(Date closeTime) 
+    {
+        this.closeTime = closeTime;
+    }
+
+    public Date getCloseTime() 
+    {
+        return closeTime;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("cardId", getCardId())
+            .append("cardNo", getCardNo())
+            .append("password", getPassword())
+            .append("type", getType())
+            .append("status", getStatus())
+            .append("distributeStatus", getDistributeStatus())
+            .append("timeStatus", getTimeStatus())
+            .append("payStatus", getPayStatus())
+            .append("isSettlement", getIsSettlement())
+            .append("deptId", getDeptId())
+            .append("agentId", getAgentId())
+            .append("leftAgentId", getLeftAgentId())
+            .append("campusId", getCampusId())
+            .append("assignSchoolId", getAssignSchoolId())
+            .append("schoolId", getSchoolId())
+            .append("classId", getClassId())
+            .append("year", getYear())
+            .append("endYear", getEndYear())
+            .append("openId", getOpenId())
+            .append("remark", getRemark())
+            .append("distributeTime", getDistributeTime())
+            .append("outDate", getOutDate())
+            .append("openTime", getOpenTime())
+            .append("payTime", getPayTime())
+            .append("activeTime", getActiveTime())
+            .append("settlementTime", getSettlementTime())
+            .append("refundTime", getRefundTime())
+            .append("closeTime", getCloseTime())
+            .append("createTime", getCreateTime())
+            .append("updateTime", getUpdateTime())
+            .toString();
+    }
+}

+ 176 - 0
ie-system/src/main/java/com/ruoyi/dz/domain/DzCardsOpen.java

@@ -0,0 +1,176 @@
+package com.ruoyi.dz.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 开卡申请对象 dz_cards_open
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public class DzCardsOpen extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 标识 */
+    private Long id;
+
+    /** 代理 */
+    @Excel(name = "代理")
+    private Long agentId;
+
+    /** 起始卡号 */
+    @Excel(name = "起始卡号")
+    private String startNo;
+
+    /** 截至卡号 */
+    @Excel(name = "截至卡号")
+    private String endNo;
+
+    /** 结束日期 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "结束日期", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date endDate;
+
+    /** 校区 */
+    @Excel(name = "校区")
+    private Long schoolId;
+
+    /** 发件人 */
+    @Excel(name = "发件人")
+    private String sender;
+
+    /** 重新开卡:0否,1是 */
+    @Excel(name = "重新开卡:0否,1是")
+    private Long isReopen;
+
+    /** 卡类型,对应card_type */
+    @Excel(name = "卡类型,对应card_type")
+    private Long cardType;
+
+    /** 状态(0:无效,1:审核结束,2:审核中) */
+    @Excel(name = "状态(0:无效,1:审核结束,2:审核中)")
+    private Long status;
+
+    public void setId(Long id) 
+    {
+        this.id = id;
+    }
+
+    public Long getId() 
+    {
+        return id;
+    }
+
+    public void setAgentId(Long agentId) 
+    {
+        this.agentId = agentId;
+    }
+
+    public Long getAgentId() 
+    {
+        return agentId;
+    }
+
+    public void setStartNo(String startNo) 
+    {
+        this.startNo = startNo;
+    }
+
+    public String getStartNo() 
+    {
+        return startNo;
+    }
+
+    public void setEndNo(String endNo) 
+    {
+        this.endNo = endNo;
+    }
+
+    public String getEndNo() 
+    {
+        return endNo;
+    }
+
+    public void setEndDate(Date endDate) 
+    {
+        this.endDate = endDate;
+    }
+
+    public Date getEndDate() 
+    {
+        return endDate;
+    }
+
+    public void setSchoolId(Long schoolId) 
+    {
+        this.schoolId = schoolId;
+    }
+
+    public Long getSchoolId() 
+    {
+        return schoolId;
+    }
+
+    public void setSender(String sender) 
+    {
+        this.sender = sender;
+    }
+
+    public String getSender() 
+    {
+        return sender;
+    }
+
+    public void setIsReopen(Long isReopen) 
+    {
+        this.isReopen = isReopen;
+    }
+
+    public Long getIsReopen() 
+    {
+        return isReopen;
+    }
+
+    public void setCardType(Long cardType) 
+    {
+        this.cardType = cardType;
+    }
+
+    public Long getCardType() 
+    {
+        return cardType;
+    }
+
+    public void setStatus(Long status) 
+    {
+        this.status = status;
+    }
+
+    public Long getStatus() 
+    {
+        return status;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("agentId", getAgentId())
+            .append("startNo", getStartNo())
+            .append("endNo", getEndNo())
+            .append("endDate", getEndDate())
+            .append("schoolId", getSchoolId())
+            .append("sender", getSender())
+            .append("createTime", getCreateTime())
+            .append("isReopen", getIsReopen())
+            .append("cardType", getCardType())
+            .append("status", getStatus())
+            .toString();
+    }
+}

+ 82 - 0
ie-system/src/main/java/com/ruoyi/dz/domain/DzClasses.java

@@ -0,0 +1,82 @@
+package com.ruoyi.dz.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 机构班级对象 dz_classes
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public class DzClasses extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 班级id */
+    private Long id;
+
+    /** 班级名称 */
+    @Excel(name = "班级名称")
+    private String name;
+
+    /** 所在校区 */
+    @Excel(name = "所在校区")
+    private Long schoolId;
+
+    /** 是否线上 */
+    @Excel(name = "是否线上")
+    private Long online;
+
+    public void setId(Long id) 
+    {
+        this.id = id;
+    }
+
+    public Long getId() 
+    {
+        return id;
+    }
+
+    public void setName(String name) 
+    {
+        this.name = name;
+    }
+
+    public String getName() 
+    {
+        return name;
+    }
+
+    public void setSchoolId(Long schoolId) 
+    {
+        this.schoolId = schoolId;
+    }
+
+    public Long getSchoolId() 
+    {
+        return schoolId;
+    }
+
+    public void setOnline(Long online) 
+    {
+        this.online = online;
+    }
+
+    public Long getOnline() 
+    {
+        return online;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("name", getName())
+            .append("schoolId", getSchoolId())
+            .append("online", getOnline())
+            .toString();
+    }
+}

+ 142 - 0
ie-system/src/main/java/com/ruoyi/dz/domain/DzControl.java

@@ -0,0 +1,142 @@
+package com.ruoyi.dz.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 单招省份状态对象 dz_control
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public class DzControl extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** ID */
+    private Long id;
+
+    /** 省份 */
+    @Excel(name = "省份")
+    private String location;
+
+    /** 开始时间 */
+    @Excel(name = "开始时间")
+    private String startDate;
+
+    /** 结束时间 */
+    @Excel(name = "结束时间")
+    private String endDate;
+
+    /** 是否生效(0:否,1:是) */
+    @Excel(name = "是否生效(0:否,1:是)")
+    private Integer isValid;
+
+    /** 计划年度 */
+    @Excel(name = "计划年度")
+    private String planYear;
+
+    /** 录取年度 */
+    @Excel(name = "录取年度")
+    private String submitYear;
+
+    /** 开启考生 */
+    @Excel(name = "开启考生")
+    private String examTypes;
+
+    public void setId(Long id) 
+    {
+        this.id = id;
+    }
+
+    public Long getId() 
+    {
+        return id;
+    }
+
+    public void setLocation(String location) 
+    {
+        this.location = location;
+    }
+
+    public String getLocation() 
+    {
+        return location;
+    }
+
+    public void setStartDate(String startDate) 
+    {
+        this.startDate = startDate;
+    }
+
+    public String getStartDate() 
+    {
+        return startDate;
+    }
+
+    public void setEndDate(String endDate) 
+    {
+        this.endDate = endDate;
+    }
+
+    public String getEndDate() 
+    {
+        return endDate;
+    }
+
+    public void setIsValid(Integer isValid) 
+    {
+        this.isValid = isValid;
+    }
+
+    public Integer getIsValid() 
+    {
+        return isValid;
+    }
+
+    public void setPlanYear(String planYear) 
+    {
+        this.planYear = planYear;
+    }
+
+    public String getPlanYear() 
+    {
+        return planYear;
+    }
+
+    public void setSubmitYear(String submitYear) 
+    {
+        this.submitYear = submitYear;
+    }
+
+    public String getSubmitYear() 
+    {
+        return submitYear;
+    }
+
+    public void setExamTypes(String examTypes) 
+    {
+        this.examTypes = examTypes;
+    }
+
+    public String getExamTypes() 
+    {
+        return examTypes;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("location", getLocation())
+            .append("startDate", getStartDate())
+            .append("endDate", getEndDate())
+            .append("isValid", getIsValid())
+            .append("planYear", getPlanYear())
+            .append("submitYear", getSubmitYear())
+            .append("examTypes", getExamTypes())
+            .toString();
+    }
+}

+ 433 - 0
ie-system/src/main/java/com/ruoyi/dz/domain/DzPaymentOrders.java

@@ -0,0 +1,433 @@
+package com.ruoyi.dz.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 订单对象 dz_payment_orders
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public class DzPaymentOrders extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** $column.columnComment */
+    private Long id;
+
+    /** 订单号 */
+    @Excel(name = "订单号")
+    private String code;
+
+    /** 传微信单号 */
+    @Excel(name = "传微信单号")
+    private String outTradeNo;
+
+    /** 二维码标识 */
+    @Excel(name = "二维码标识")
+    private String qrcodeId;
+
+    /** $column.columnComment */
+    @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
+    private String type;
+
+    /** 电子卡 */
+    @Excel(name = "电子卡")
+    private Long cardId;
+
+    /** 账号 */
+    @Excel(name = "账号")
+    private String cardNo;
+
+    /** 价目标识 */
+    @Excel(name = "价目标识")
+    private String year;
+
+    /** 手机号码 */
+    @Excel(name = "手机号码")
+    private String phonenumber;
+
+    /** 微信订单号 */
+    @Excel(name = "微信订单号")
+    private String transactionId;
+
+    /** 用户 */
+    @Excel(name = "用户")
+    private String customerCode;
+
+    /** 失效期 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "失效期", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date outTime;
+
+    /** 单价 */
+    @Excel(name = "单价")
+    private Long price;
+
+    /** 数量 */
+    @Excel(name = "数量")
+    private Long num;
+
+    /** 金额 */
+    @Excel(name = "金额")
+    private Long fee;
+
+    /** 应付金额 */
+    @Excel(name = "应付金额")
+    private Long totalFee;
+
+    /** 实付金额 */
+    @Excel(name = "实付金额")
+    private Long payFee;
+
+    /** 创建者 */
+    @Excel(name = "创建者")
+    private String creator;
+
+    /** 描述 */
+    @Excel(name = "描述")
+    private String body;
+
+    /** 详情 */
+    @Excel(name = "详情")
+    private String detail;
+
+    /** 附加数据 */
+    @Excel(name = "附加数据")
+    private String attach;
+
+    /** 微信预支付标识 */
+    @Excel(name = "微信预支付标识")
+    private String prepayId;
+
+    /** 支付者 */
+    @Excel(name = "支付者")
+    private String payer;
+
+    /** 支付时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "支付时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date payTime;
+
+    /** 支付回调结果 */
+    @Excel(name = "支付回调结果")
+    private String feedBack;
+
+    /** 确认时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "确认时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date syncTime;
+
+    /** 状态(-2:已退费,-1:支付失败,0:无效,1:未支付,2:已支付) */
+    @Excel(name = "状态(-2:已退费,-1:支付失败,0:无效,1:未支付,2:已支付)")
+    private Integer status;
+
+    public void setId(Long id) 
+    {
+        this.id = id;
+    }
+
+    public Long getId() 
+    {
+        return id;
+    }
+
+    public void setCode(String code) 
+    {
+        this.code = code;
+    }
+
+    public String getCode() 
+    {
+        return code;
+    }
+
+    public void setOutTradeNo(String outTradeNo) 
+    {
+        this.outTradeNo = outTradeNo;
+    }
+
+    public String getOutTradeNo() 
+    {
+        return outTradeNo;
+    }
+
+    public void setQrcodeId(String qrcodeId) 
+    {
+        this.qrcodeId = qrcodeId;
+    }
+
+    public String getQrcodeId() 
+    {
+        return qrcodeId;
+    }
+
+    public void setType(String type) 
+    {
+        this.type = type;
+    }
+
+    public String getType() 
+    {
+        return type;
+    }
+
+    public void setCardId(Long cardId) 
+    {
+        this.cardId = cardId;
+    }
+
+    public Long getCardId() 
+    {
+        return cardId;
+    }
+
+    public void setCardNo(String cardNo) 
+    {
+        this.cardNo = cardNo;
+    }
+
+    public String getCardNo() 
+    {
+        return cardNo;
+    }
+
+    public void setYear(String year) 
+    {
+        this.year = year;
+    }
+
+    public String getYear() 
+    {
+        return year;
+    }
+
+    public void setPhonenumber(String phonenumber) 
+    {
+        this.phonenumber = phonenumber;
+    }
+
+    public String getPhonenumber() 
+    {
+        return phonenumber;
+    }
+
+    public void setTransactionId(String transactionId) 
+    {
+        this.transactionId = transactionId;
+    }
+
+    public String getTransactionId() 
+    {
+        return transactionId;
+    }
+
+    public void setCustomerCode(String customerCode) 
+    {
+        this.customerCode = customerCode;
+    }
+
+    public String getCustomerCode() 
+    {
+        return customerCode;
+    }
+
+    public void setOutTime(Date outTime) 
+    {
+        this.outTime = outTime;
+    }
+
+    public Date getOutTime() 
+    {
+        return outTime;
+    }
+
+    public void setPrice(Long price) 
+    {
+        this.price = price;
+    }
+
+    public Long getPrice() 
+    {
+        return price;
+    }
+
+    public void setNum(Long num) 
+    {
+        this.num = num;
+    }
+
+    public Long getNum() 
+    {
+        return num;
+    }
+
+    public void setFee(Long fee) 
+    {
+        this.fee = fee;
+    }
+
+    public Long getFee() 
+    {
+        return fee;
+    }
+
+    public void setTotalFee(Long totalFee) 
+    {
+        this.totalFee = totalFee;
+    }
+
+    public Long getTotalFee() 
+    {
+        return totalFee;
+    }
+
+    public void setPayFee(Long payFee) 
+    {
+        this.payFee = payFee;
+    }
+
+    public Long getPayFee() 
+    {
+        return payFee;
+    }
+
+    public void setCreator(String creator) 
+    {
+        this.creator = creator;
+    }
+
+    public String getCreator() 
+    {
+        return creator;
+    }
+
+    public void setBody(String body) 
+    {
+        this.body = body;
+    }
+
+    public String getBody() 
+    {
+        return body;
+    }
+
+    public void setDetail(String detail) 
+    {
+        this.detail = detail;
+    }
+
+    public String getDetail() 
+    {
+        return detail;
+    }
+
+    public void setAttach(String attach) 
+    {
+        this.attach = attach;
+    }
+
+    public String getAttach() 
+    {
+        return attach;
+    }
+
+    public void setPrepayId(String prepayId) 
+    {
+        this.prepayId = prepayId;
+    }
+
+    public String getPrepayId() 
+    {
+        return prepayId;
+    }
+
+    public void setPayer(String payer) 
+    {
+        this.payer = payer;
+    }
+
+    public String getPayer() 
+    {
+        return payer;
+    }
+
+    public void setPayTime(Date payTime) 
+    {
+        this.payTime = payTime;
+    }
+
+    public Date getPayTime() 
+    {
+        return payTime;
+    }
+
+    public void setFeedBack(String feedBack) 
+    {
+        this.feedBack = feedBack;
+    }
+
+    public String getFeedBack() 
+    {
+        return feedBack;
+    }
+
+    public void setSyncTime(Date syncTime) 
+    {
+        this.syncTime = syncTime;
+    }
+
+    public Date getSyncTime() 
+    {
+        return syncTime;
+    }
+
+    public void setStatus(Integer status) 
+    {
+        this.status = status;
+    }
+
+    public Integer getStatus() 
+    {
+        return status;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("code", getCode())
+            .append("outTradeNo", getOutTradeNo())
+            .append("qrcodeId", getQrcodeId())
+            .append("type", getType())
+            .append("cardId", getCardId())
+            .append("cardNo", getCardNo())
+            .append("year", getYear())
+            .append("phonenumber", getPhonenumber())
+            .append("transactionId", getTransactionId())
+            .append("customerCode", getCustomerCode())
+            .append("outTime", getOutTime())
+            .append("price", getPrice())
+            .append("num", getNum())
+            .append("fee", getFee())
+            .append("totalFee", getTotalFee())
+            .append("payFee", getPayFee())
+            .append("createTime", getCreateTime())
+            .append("creator", getCreator())
+            .append("body", getBody())
+            .append("detail", getDetail())
+            .append("attach", getAttach())
+            .append("prepayId", getPrepayId())
+            .append("payer", getPayer())
+            .append("payTime", getPayTime())
+            .append("feedBack", getFeedBack())
+            .append("syncTime", getSyncTime())
+            .append("status", getStatus())
+            .toString();
+    }
+}

+ 145 - 0
ie-system/src/main/java/com/ruoyi/dz/domain/DzSchool.java

@@ -0,0 +1,145 @@
+package com.ruoyi.dz.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 机构校区对象 dz_school
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public class DzSchool extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** $column.columnComment */
+    private Long id;
+
+    /** 名称 */
+    @Excel(name = "名称")
+    private String name;
+
+    /** 机构ID */
+    @Excel(name = "机构ID")
+    private Long deptId;
+
+    /** 地域 */
+    @Excel(name = "地域")
+    private String location;
+
+    /** 省 */
+    @Excel(name = "省")
+    private Long pro;
+
+    /** 市 */
+    @Excel(name = "市")
+    private Long city;
+
+    /** 区 */
+    @Excel(name = "区")
+    private Long area;
+
+    /** 状态(0:无效,1:有效) */
+    @Excel(name = "状态(0:无效,1:有效)")
+    private Integer status;
+
+    public void setId(Long id) 
+    {
+        this.id = id;
+    }
+
+    public Long getId() 
+    {
+        return id;
+    }
+
+    public void setName(String name) 
+    {
+        this.name = name;
+    }
+
+    public String getName() 
+    {
+        return name;
+    }
+
+    public void setDeptId(Long deptId) 
+    {
+        this.deptId = deptId;
+    }
+
+    public Long getDeptId() 
+    {
+        return deptId;
+    }
+
+    public void setLocation(String location) 
+    {
+        this.location = location;
+    }
+
+    public String getLocation() 
+    {
+        return location;
+    }
+
+    public void setPro(Long pro) 
+    {
+        this.pro = pro;
+    }
+
+    public Long getPro() 
+    {
+        return pro;
+    }
+
+    public void setCity(Long city) 
+    {
+        this.city = city;
+    }
+
+    public Long getCity() 
+    {
+        return city;
+    }
+
+    public void setArea(Long area) 
+    {
+        this.area = area;
+    }
+
+    public Long getArea() 
+    {
+        return area;
+    }
+
+    public void setStatus(Integer status) 
+    {
+        this.status = status;
+    }
+
+    public Integer getStatus() 
+    {
+        return status;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("name", getName())
+            .append("deptId", getDeptId())
+            .append("location", getLocation())
+            .append("remark", getRemark())
+            .append("pro", getPro())
+            .append("city", getCity())
+            .append("area", getArea())
+            .append("status", getStatus())
+            .append("createTime", getCreateTime())
+            .append("updateTime", getUpdateTime())
+            .toString();
+    }
+}

+ 82 - 0
ie-system/src/main/java/com/ruoyi/dz/domain/DzTeacher.java

@@ -0,0 +1,82 @@
+package com.ruoyi.dz.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 老师对象 dz_teacher
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public class DzTeacher extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 老师id */
+    private Long teacherId;
+
+    /** 用户ID */
+    @Excel(name = "用户ID")
+    private Long userId;
+
+    /** 所在校区 */
+    @Excel(name = "所在校区")
+    private Long schoolId;
+
+    /** 教师姓名 */
+    @Excel(name = "教师姓名")
+    private String name;
+
+    public void setTeacherId(Long teacherId) 
+    {
+        this.teacherId = teacherId;
+    }
+
+    public Long getTeacherId() 
+    {
+        return teacherId;
+    }
+
+    public void setUserId(Long userId) 
+    {
+        this.userId = userId;
+    }
+
+    public Long getUserId() 
+    {
+        return userId;
+    }
+
+    public void setSchoolId(Long schoolId) 
+    {
+        this.schoolId = schoolId;
+    }
+
+    public Long getSchoolId() 
+    {
+        return schoolId;
+    }
+
+    public void setName(String name) 
+    {
+        this.name = name;
+    }
+
+    public String getName() 
+    {
+        return name;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("teacherId", getTeacherId())
+            .append("userId", getUserId())
+            .append("schoolId", getSchoolId())
+            .append("name", getName())
+            .toString();
+    }
+}

+ 101 - 0
ie-system/src/main/java/com/ruoyi/dz/domain/DzTeacherClass.java

@@ -0,0 +1,101 @@
+package com.ruoyi.dz.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 教师班级关系对象 dz_teacher_class
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public class DzTeacherClass extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 标识 */
+    private String id;
+
+    /** 老师id */
+    @Excel(name = "老师id")
+    private Long teacherId;
+
+    /** 班级id */
+    @Excel(name = "班级id")
+    private Long classesId;
+
+    /** 有效状态 */
+    @Excel(name = "有效状态")
+    private Long status;
+
+    /** 结束日期 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "结束日期", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date outDate;
+
+    public void setId(String id) 
+    {
+        this.id = id;
+    }
+
+    public String getId() 
+    {
+        return id;
+    }
+
+    public void setTeacherId(Long teacherId) 
+    {
+        this.teacherId = teacherId;
+    }
+
+    public Long getTeacherId() 
+    {
+        return teacherId;
+    }
+
+    public void setClassesId(Long classesId) 
+    {
+        this.classesId = classesId;
+    }
+
+    public Long getClassesId() 
+    {
+        return classesId;
+    }
+
+    public void setStatus(Long status) 
+    {
+        this.status = status;
+    }
+
+    public Long getStatus() 
+    {
+        return status;
+    }
+
+    public void setOutDate(Date outDate) 
+    {
+        this.outDate = outDate;
+    }
+
+    public Date getOutDate() 
+    {
+        return outDate;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("teacherId", getTeacherId())
+            .append("classesId", getClassesId())
+            .append("status", getStatus())
+            .append("remark", getRemark())
+            .append("outDate", getOutDate())
+            .toString();
+    }
+}

+ 61 - 0
ie-system/src/main/java/com/ruoyi/dz/mapper/DzAgentMapper.java

@@ -0,0 +1,61 @@
+package com.ruoyi.dz.mapper;
+
+import java.util.List;
+import com.ruoyi.dz.domain.DzAgent;
+
+/**
+ * 机构代理Mapper接口
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public interface DzAgentMapper 
+{
+    /**
+     * 查询机构代理
+     * 
+     * @param agentId 机构代理主键
+     * @return 机构代理
+     */
+    public DzAgent selectDzAgentByAgentId(Long agentId);
+
+    /**
+     * 查询机构代理列表
+     * 
+     * @param dzAgent 机构代理
+     * @return 机构代理集合
+     */
+    public List<DzAgent> selectDzAgentList(DzAgent dzAgent);
+
+    /**
+     * 新增机构代理
+     * 
+     * @param dzAgent 机构代理
+     * @return 结果
+     */
+    public int insertDzAgent(DzAgent dzAgent);
+
+    /**
+     * 修改机构代理
+     * 
+     * @param dzAgent 机构代理
+     * @return 结果
+     */
+    public int updateDzAgent(DzAgent dzAgent);
+
+    /**
+     * 删除机构代理
+     * 
+     * @param agentId 机构代理主键
+     * @return 结果
+     */
+    public int deleteDzAgentByAgentId(Long agentId);
+
+    /**
+     * 批量删除机构代理
+     * 
+     * @param agentIds 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteDzAgentByAgentIds(Long[] agentIds);
+}

+ 61 - 0
ie-system/src/main/java/com/ruoyi/dz/mapper/DzCardsMapper.java

@@ -0,0 +1,61 @@
+package com.ruoyi.dz.mapper;
+
+import java.util.List;
+import com.ruoyi.dz.domain.DzCards;
+
+/**
+ * 学习卡Mapper接口
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public interface DzCardsMapper 
+{
+    /**
+     * 查询学习卡
+     * 
+     * @param cardId 学习卡主键
+     * @return 学习卡
+     */
+    public DzCards selectDzCardsByCardId(Long cardId);
+
+    /**
+     * 查询学习卡列表
+     * 
+     * @param dzCards 学习卡
+     * @return 学习卡集合
+     */
+    public List<DzCards> selectDzCardsList(DzCards dzCards);
+
+    /**
+     * 新增学习卡
+     * 
+     * @param dzCards 学习卡
+     * @return 结果
+     */
+    public int insertDzCards(DzCards dzCards);
+
+    /**
+     * 修改学习卡
+     * 
+     * @param dzCards 学习卡
+     * @return 结果
+     */
+    public int updateDzCards(DzCards dzCards);
+
+    /**
+     * 删除学习卡
+     * 
+     * @param cardId 学习卡主键
+     * @return 结果
+     */
+    public int deleteDzCardsByCardId(Long cardId);
+
+    /**
+     * 批量删除学习卡
+     * 
+     * @param cardIds 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteDzCardsByCardIds(Long[] cardIds);
+}

+ 61 - 0
ie-system/src/main/java/com/ruoyi/dz/mapper/DzCardsOpenMapper.java

@@ -0,0 +1,61 @@
+package com.ruoyi.dz.mapper;
+
+import java.util.List;
+import com.ruoyi.dz.domain.DzCardsOpen;
+
+/**
+ * 开卡申请Mapper接口
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public interface DzCardsOpenMapper 
+{
+    /**
+     * 查询开卡申请
+     * 
+     * @param id 开卡申请主键
+     * @return 开卡申请
+     */
+    public DzCardsOpen selectDzCardsOpenById(Long id);
+
+    /**
+     * 查询开卡申请列表
+     * 
+     * @param dzCardsOpen 开卡申请
+     * @return 开卡申请集合
+     */
+    public List<DzCardsOpen> selectDzCardsOpenList(DzCardsOpen dzCardsOpen);
+
+    /**
+     * 新增开卡申请
+     * 
+     * @param dzCardsOpen 开卡申请
+     * @return 结果
+     */
+    public int insertDzCardsOpen(DzCardsOpen dzCardsOpen);
+
+    /**
+     * 修改开卡申请
+     * 
+     * @param dzCardsOpen 开卡申请
+     * @return 结果
+     */
+    public int updateDzCardsOpen(DzCardsOpen dzCardsOpen);
+
+    /**
+     * 删除开卡申请
+     * 
+     * @param id 开卡申请主键
+     * @return 结果
+     */
+    public int deleteDzCardsOpenById(Long id);
+
+    /**
+     * 批量删除开卡申请
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteDzCardsOpenByIds(Long[] ids);
+}

+ 61 - 0
ie-system/src/main/java/com/ruoyi/dz/mapper/DzClassesMapper.java

@@ -0,0 +1,61 @@
+package com.ruoyi.dz.mapper;
+
+import java.util.List;
+import com.ruoyi.dz.domain.DzClasses;
+
+/**
+ * 机构班级Mapper接口
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public interface DzClassesMapper 
+{
+    /**
+     * 查询机构班级
+     * 
+     * @param id 机构班级主键
+     * @return 机构班级
+     */
+    public DzClasses selectDzClassesById(Long id);
+
+    /**
+     * 查询机构班级列表
+     * 
+     * @param dzClasses 机构班级
+     * @return 机构班级集合
+     */
+    public List<DzClasses> selectDzClassesList(DzClasses dzClasses);
+
+    /**
+     * 新增机构班级
+     * 
+     * @param dzClasses 机构班级
+     * @return 结果
+     */
+    public int insertDzClasses(DzClasses dzClasses);
+
+    /**
+     * 修改机构班级
+     * 
+     * @param dzClasses 机构班级
+     * @return 结果
+     */
+    public int updateDzClasses(DzClasses dzClasses);
+
+    /**
+     * 删除机构班级
+     * 
+     * @param id 机构班级主键
+     * @return 结果
+     */
+    public int deleteDzClassesById(Long id);
+
+    /**
+     * 批量删除机构班级
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteDzClassesByIds(Long[] ids);
+}

+ 61 - 0
ie-system/src/main/java/com/ruoyi/dz/mapper/DzControlMapper.java

@@ -0,0 +1,61 @@
+package com.ruoyi.dz.mapper;
+
+import java.util.List;
+import com.ruoyi.dz.domain.DzControl;
+
+/**
+ * 单招省份状态Mapper接口
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public interface DzControlMapper 
+{
+    /**
+     * 查询单招省份状态
+     * 
+     * @param id 单招省份状态主键
+     * @return 单招省份状态
+     */
+    public DzControl selectDzControlById(Long id);
+
+    /**
+     * 查询单招省份状态列表
+     * 
+     * @param dzControl 单招省份状态
+     * @return 单招省份状态集合
+     */
+    public List<DzControl> selectDzControlList(DzControl dzControl);
+
+    /**
+     * 新增单招省份状态
+     * 
+     * @param dzControl 单招省份状态
+     * @return 结果
+     */
+    public int insertDzControl(DzControl dzControl);
+
+    /**
+     * 修改单招省份状态
+     * 
+     * @param dzControl 单招省份状态
+     * @return 结果
+     */
+    public int updateDzControl(DzControl dzControl);
+
+    /**
+     * 删除单招省份状态
+     * 
+     * @param id 单招省份状态主键
+     * @return 结果
+     */
+    public int deleteDzControlById(Long id);
+
+    /**
+     * 批量删除单招省份状态
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteDzControlByIds(Long[] ids);
+}

+ 61 - 0
ie-system/src/main/java/com/ruoyi/dz/mapper/DzPaymentOrdersMapper.java

@@ -0,0 +1,61 @@
+package com.ruoyi.dz.mapper;
+
+import java.util.List;
+import com.ruoyi.dz.domain.DzPaymentOrders;
+
+/**
+ * 订单Mapper接口
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public interface DzPaymentOrdersMapper 
+{
+    /**
+     * 查询订单
+     * 
+     * @param id 订单主键
+     * @return 订单
+     */
+    public DzPaymentOrders selectDzPaymentOrdersById(Long id);
+
+    /**
+     * 查询订单列表
+     * 
+     * @param dzPaymentOrders 订单
+     * @return 订单集合
+     */
+    public List<DzPaymentOrders> selectDzPaymentOrdersList(DzPaymentOrders dzPaymentOrders);
+
+    /**
+     * 新增订单
+     * 
+     * @param dzPaymentOrders 订单
+     * @return 结果
+     */
+    public int insertDzPaymentOrders(DzPaymentOrders dzPaymentOrders);
+
+    /**
+     * 修改订单
+     * 
+     * @param dzPaymentOrders 订单
+     * @return 结果
+     */
+    public int updateDzPaymentOrders(DzPaymentOrders dzPaymentOrders);
+
+    /**
+     * 删除订单
+     * 
+     * @param id 订单主键
+     * @return 结果
+     */
+    public int deleteDzPaymentOrdersById(Long id);
+
+    /**
+     * 批量删除订单
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteDzPaymentOrdersByIds(Long[] ids);
+}

+ 61 - 0
ie-system/src/main/java/com/ruoyi/dz/mapper/DzSchoolMapper.java

@@ -0,0 +1,61 @@
+package com.ruoyi.dz.mapper;
+
+import java.util.List;
+import com.ruoyi.dz.domain.DzSchool;
+
+/**
+ * 机构校区Mapper接口
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public interface DzSchoolMapper 
+{
+    /**
+     * 查询机构校区
+     * 
+     * @param id 机构校区主键
+     * @return 机构校区
+     */
+    public DzSchool selectDzSchoolById(Long id);
+
+    /**
+     * 查询机构校区列表
+     * 
+     * @param dzSchool 机构校区
+     * @return 机构校区集合
+     */
+    public List<DzSchool> selectDzSchoolList(DzSchool dzSchool);
+
+    /**
+     * 新增机构校区
+     * 
+     * @param dzSchool 机构校区
+     * @return 结果
+     */
+    public int insertDzSchool(DzSchool dzSchool);
+
+    /**
+     * 修改机构校区
+     * 
+     * @param dzSchool 机构校区
+     * @return 结果
+     */
+    public int updateDzSchool(DzSchool dzSchool);
+
+    /**
+     * 删除机构校区
+     * 
+     * @param id 机构校区主键
+     * @return 结果
+     */
+    public int deleteDzSchoolById(Long id);
+
+    /**
+     * 批量删除机构校区
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteDzSchoolByIds(Long[] ids);
+}

+ 61 - 0
ie-system/src/main/java/com/ruoyi/dz/mapper/DzTeacherClassMapper.java

@@ -0,0 +1,61 @@
+package com.ruoyi.dz.mapper;
+
+import java.util.List;
+import com.ruoyi.dz.domain.DzTeacherClass;
+
+/**
+ * 教师班级关系Mapper接口
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public interface DzTeacherClassMapper 
+{
+    /**
+     * 查询教师班级关系
+     * 
+     * @param id 教师班级关系主键
+     * @return 教师班级关系
+     */
+    public DzTeacherClass selectDzTeacherClassById(String id);
+
+    /**
+     * 查询教师班级关系列表
+     * 
+     * @param dzTeacherClass 教师班级关系
+     * @return 教师班级关系集合
+     */
+    public List<DzTeacherClass> selectDzTeacherClassList(DzTeacherClass dzTeacherClass);
+
+    /**
+     * 新增教师班级关系
+     * 
+     * @param dzTeacherClass 教师班级关系
+     * @return 结果
+     */
+    public int insertDzTeacherClass(DzTeacherClass dzTeacherClass);
+
+    /**
+     * 修改教师班级关系
+     * 
+     * @param dzTeacherClass 教师班级关系
+     * @return 结果
+     */
+    public int updateDzTeacherClass(DzTeacherClass dzTeacherClass);
+
+    /**
+     * 删除教师班级关系
+     * 
+     * @param id 教师班级关系主键
+     * @return 结果
+     */
+    public int deleteDzTeacherClassById(String id);
+
+    /**
+     * 批量删除教师班级关系
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteDzTeacherClassByIds(String[] ids);
+}

+ 61 - 0
ie-system/src/main/java/com/ruoyi/dz/mapper/DzTeacherMapper.java

@@ -0,0 +1,61 @@
+package com.ruoyi.dz.mapper;
+
+import java.util.List;
+import com.ruoyi.dz.domain.DzTeacher;
+
+/**
+ * 老师Mapper接口
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public interface DzTeacherMapper 
+{
+    /**
+     * 查询老师
+     * 
+     * @param teacherId 老师主键
+     * @return 老师
+     */
+    public DzTeacher selectDzTeacherByTeacherId(Long teacherId);
+
+    /**
+     * 查询老师列表
+     * 
+     * @param dzTeacher 老师
+     * @return 老师集合
+     */
+    public List<DzTeacher> selectDzTeacherList(DzTeacher dzTeacher);
+
+    /**
+     * 新增老师
+     * 
+     * @param dzTeacher 老师
+     * @return 结果
+     */
+    public int insertDzTeacher(DzTeacher dzTeacher);
+
+    /**
+     * 修改老师
+     * 
+     * @param dzTeacher 老师
+     * @return 结果
+     */
+    public int updateDzTeacher(DzTeacher dzTeacher);
+
+    /**
+     * 删除老师
+     * 
+     * @param teacherId 老师主键
+     * @return 结果
+     */
+    public int deleteDzTeacherByTeacherId(Long teacherId);
+
+    /**
+     * 批量删除老师
+     * 
+     * @param teacherIds 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteDzTeacherByTeacherIds(Long[] teacherIds);
+}

+ 61 - 0
ie-system/src/main/java/com/ruoyi/dz/service/IDzAgentService.java

@@ -0,0 +1,61 @@
+package com.ruoyi.dz.service;
+
+import java.util.List;
+import com.ruoyi.dz.domain.DzAgent;
+
+/**
+ * 机构代理Service接口
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public interface IDzAgentService 
+{
+    /**
+     * 查询机构代理
+     * 
+     * @param agentId 机构代理主键
+     * @return 机构代理
+     */
+    public DzAgent selectDzAgentByAgentId(Long agentId);
+
+    /**
+     * 查询机构代理列表
+     * 
+     * @param dzAgent 机构代理
+     * @return 机构代理集合
+     */
+    public List<DzAgent> selectDzAgentList(DzAgent dzAgent);
+
+    /**
+     * 新增机构代理
+     * 
+     * @param dzAgent 机构代理
+     * @return 结果
+     */
+    public int insertDzAgent(DzAgent dzAgent);
+
+    /**
+     * 修改机构代理
+     * 
+     * @param dzAgent 机构代理
+     * @return 结果
+     */
+    public int updateDzAgent(DzAgent dzAgent);
+
+    /**
+     * 批量删除机构代理
+     * 
+     * @param agentIds 需要删除的机构代理主键集合
+     * @return 结果
+     */
+    public int deleteDzAgentByAgentIds(Long[] agentIds);
+
+    /**
+     * 删除机构代理信息
+     * 
+     * @param agentId 机构代理主键
+     * @return 结果
+     */
+    public int deleteDzAgentByAgentId(Long agentId);
+}

+ 61 - 0
ie-system/src/main/java/com/ruoyi/dz/service/IDzCardsOpenService.java

@@ -0,0 +1,61 @@
+package com.ruoyi.dz.service;
+
+import java.util.List;
+import com.ruoyi.dz.domain.DzCardsOpen;
+
+/**
+ * 开卡申请Service接口
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public interface IDzCardsOpenService 
+{
+    /**
+     * 查询开卡申请
+     * 
+     * @param id 开卡申请主键
+     * @return 开卡申请
+     */
+    public DzCardsOpen selectDzCardsOpenById(Long id);
+
+    /**
+     * 查询开卡申请列表
+     * 
+     * @param dzCardsOpen 开卡申请
+     * @return 开卡申请集合
+     */
+    public List<DzCardsOpen> selectDzCardsOpenList(DzCardsOpen dzCardsOpen);
+
+    /**
+     * 新增开卡申请
+     * 
+     * @param dzCardsOpen 开卡申请
+     * @return 结果
+     */
+    public int insertDzCardsOpen(DzCardsOpen dzCardsOpen);
+
+    /**
+     * 修改开卡申请
+     * 
+     * @param dzCardsOpen 开卡申请
+     * @return 结果
+     */
+    public int updateDzCardsOpen(DzCardsOpen dzCardsOpen);
+
+    /**
+     * 批量删除开卡申请
+     * 
+     * @param ids 需要删除的开卡申请主键集合
+     * @return 结果
+     */
+    public int deleteDzCardsOpenByIds(Long[] ids);
+
+    /**
+     * 删除开卡申请信息
+     * 
+     * @param id 开卡申请主键
+     * @return 结果
+     */
+    public int deleteDzCardsOpenById(Long id);
+}

+ 63 - 0
ie-system/src/main/java/com/ruoyi/dz/service/IDzCardsService.java

@@ -0,0 +1,63 @@
+package com.ruoyi.dz.service;
+
+import java.util.List;
+import com.ruoyi.dz.domain.DzCards;
+
+/**
+ * 学习卡Service接口
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public interface IDzCardsService 
+{
+    /**
+     * 查询学习卡
+     * 
+     * @param cardId 学习卡主键
+     * @return 学习卡
+     */
+    public DzCards selectDzCardsByCardId(Long cardId);
+
+    public DzCards selectDzCardsByCardNo(String cardNo);
+
+    /**
+     * 查询学习卡列表
+     * 
+     * @param dzCards 学习卡
+     * @return 学习卡集合
+     */
+    public List<DzCards> selectDzCardsList(DzCards dzCards);
+
+    /**
+     * 新增学习卡
+     * 
+     * @param dzCards 学习卡
+     * @return 结果
+     */
+    public int insertDzCards(DzCards dzCards);
+
+    /**
+     * 修改学习卡
+     * 
+     * @param dzCards 学习卡
+     * @return 结果
+     */
+    public int updateDzCards(DzCards dzCards);
+
+    /**
+     * 批量删除学习卡
+     * 
+     * @param cardIds 需要删除的学习卡主键集合
+     * @return 结果
+     */
+    public int deleteDzCardsByCardIds(Long[] cardIds);
+
+    /**
+     * 删除学习卡信息
+     * 
+     * @param cardId 学习卡主键
+     * @return 结果
+     */
+    public int deleteDzCardsByCardId(Long cardId);
+}

+ 61 - 0
ie-system/src/main/java/com/ruoyi/dz/service/IDzClassesService.java

@@ -0,0 +1,61 @@
+package com.ruoyi.dz.service;
+
+import java.util.List;
+import com.ruoyi.dz.domain.DzClasses;
+
+/**
+ * 机构班级Service接口
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public interface IDzClassesService 
+{
+    /**
+     * 查询机构班级
+     * 
+     * @param id 机构班级主键
+     * @return 机构班级
+     */
+    public DzClasses selectDzClassesById(Long id);
+
+    /**
+     * 查询机构班级列表
+     * 
+     * @param dzClasses 机构班级
+     * @return 机构班级集合
+     */
+    public List<DzClasses> selectDzClassesList(DzClasses dzClasses);
+
+    /**
+     * 新增机构班级
+     * 
+     * @param dzClasses 机构班级
+     * @return 结果
+     */
+    public int insertDzClasses(DzClasses dzClasses);
+
+    /**
+     * 修改机构班级
+     * 
+     * @param dzClasses 机构班级
+     * @return 结果
+     */
+    public int updateDzClasses(DzClasses dzClasses);
+
+    /**
+     * 批量删除机构班级
+     * 
+     * @param ids 需要删除的机构班级主键集合
+     * @return 结果
+     */
+    public int deleteDzClassesByIds(Long[] ids);
+
+    /**
+     * 删除机构班级信息
+     * 
+     * @param id 机构班级主键
+     * @return 结果
+     */
+    public int deleteDzClassesById(Long id);
+}

+ 61 - 0
ie-system/src/main/java/com/ruoyi/dz/service/IDzControlService.java

@@ -0,0 +1,61 @@
+package com.ruoyi.dz.service;
+
+import java.util.List;
+import com.ruoyi.dz.domain.DzControl;
+
+/**
+ * 单招省份状态Service接口
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public interface IDzControlService 
+{
+    /**
+     * 查询单招省份状态
+     * 
+     * @param id 单招省份状态主键
+     * @return 单招省份状态
+     */
+    public DzControl selectDzControlById(Long id);
+
+    /**
+     * 查询单招省份状态列表
+     * 
+     * @param dzControl 单招省份状态
+     * @return 单招省份状态集合
+     */
+    public List<DzControl> selectDzControlList(DzControl dzControl);
+
+    /**
+     * 新增单招省份状态
+     * 
+     * @param dzControl 单招省份状态
+     * @return 结果
+     */
+    public int insertDzControl(DzControl dzControl);
+
+    /**
+     * 修改单招省份状态
+     * 
+     * @param dzControl 单招省份状态
+     * @return 结果
+     */
+    public int updateDzControl(DzControl dzControl);
+
+    /**
+     * 批量删除单招省份状态
+     * 
+     * @param ids 需要删除的单招省份状态主键集合
+     * @return 结果
+     */
+    public int deleteDzControlByIds(Long[] ids);
+
+    /**
+     * 删除单招省份状态信息
+     * 
+     * @param id 单招省份状态主键
+     * @return 结果
+     */
+    public int deleteDzControlById(Long id);
+}

+ 61 - 0
ie-system/src/main/java/com/ruoyi/dz/service/IDzPaymentOrdersService.java

@@ -0,0 +1,61 @@
+package com.ruoyi.dz.service;
+
+import java.util.List;
+import com.ruoyi.dz.domain.DzPaymentOrders;
+
+/**
+ * 订单Service接口
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public interface IDzPaymentOrdersService 
+{
+    /**
+     * 查询订单
+     * 
+     * @param id 订单主键
+     * @return 订单
+     */
+    public DzPaymentOrders selectDzPaymentOrdersById(Long id);
+
+    /**
+     * 查询订单列表
+     * 
+     * @param dzPaymentOrders 订单
+     * @return 订单集合
+     */
+    public List<DzPaymentOrders> selectDzPaymentOrdersList(DzPaymentOrders dzPaymentOrders);
+
+    /**
+     * 新增订单
+     * 
+     * @param dzPaymentOrders 订单
+     * @return 结果
+     */
+    public int insertDzPaymentOrders(DzPaymentOrders dzPaymentOrders);
+
+    /**
+     * 修改订单
+     * 
+     * @param dzPaymentOrders 订单
+     * @return 结果
+     */
+    public int updateDzPaymentOrders(DzPaymentOrders dzPaymentOrders);
+
+    /**
+     * 批量删除订单
+     * 
+     * @param ids 需要删除的订单主键集合
+     * @return 结果
+     */
+    public int deleteDzPaymentOrdersByIds(Long[] ids);
+
+    /**
+     * 删除订单信息
+     * 
+     * @param id 订单主键
+     * @return 结果
+     */
+    public int deleteDzPaymentOrdersById(Long id);
+}

+ 61 - 0
ie-system/src/main/java/com/ruoyi/dz/service/IDzSchoolService.java

@@ -0,0 +1,61 @@
+package com.ruoyi.dz.service;
+
+import java.util.List;
+import com.ruoyi.dz.domain.DzSchool;
+
+/**
+ * 机构校区Service接口
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public interface IDzSchoolService 
+{
+    /**
+     * 查询机构校区
+     * 
+     * @param id 机构校区主键
+     * @return 机构校区
+     */
+    public DzSchool selectDzSchoolById(Long id);
+
+    /**
+     * 查询机构校区列表
+     * 
+     * @param dzSchool 机构校区
+     * @return 机构校区集合
+     */
+    public List<DzSchool> selectDzSchoolList(DzSchool dzSchool);
+
+    /**
+     * 新增机构校区
+     * 
+     * @param dzSchool 机构校区
+     * @return 结果
+     */
+    public int insertDzSchool(DzSchool dzSchool);
+
+    /**
+     * 修改机构校区
+     * 
+     * @param dzSchool 机构校区
+     * @return 结果
+     */
+    public int updateDzSchool(DzSchool dzSchool);
+
+    /**
+     * 批量删除机构校区
+     * 
+     * @param ids 需要删除的机构校区主键集合
+     * @return 结果
+     */
+    public int deleteDzSchoolByIds(Long[] ids);
+
+    /**
+     * 删除机构校区信息
+     * 
+     * @param id 机构校区主键
+     * @return 结果
+     */
+    public int deleteDzSchoolById(Long id);
+}

+ 61 - 0
ie-system/src/main/java/com/ruoyi/dz/service/IDzTeacherClassService.java

@@ -0,0 +1,61 @@
+package com.ruoyi.dz.service;
+
+import java.util.List;
+import com.ruoyi.dz.domain.DzTeacherClass;
+
+/**
+ * 教师班级关系Service接口
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public interface IDzTeacherClassService 
+{
+    /**
+     * 查询教师班级关系
+     * 
+     * @param id 教师班级关系主键
+     * @return 教师班级关系
+     */
+    public DzTeacherClass selectDzTeacherClassById(String id);
+
+    /**
+     * 查询教师班级关系列表
+     * 
+     * @param dzTeacherClass 教师班级关系
+     * @return 教师班级关系集合
+     */
+    public List<DzTeacherClass> selectDzTeacherClassList(DzTeacherClass dzTeacherClass);
+
+    /**
+     * 新增教师班级关系
+     * 
+     * @param dzTeacherClass 教师班级关系
+     * @return 结果
+     */
+    public int insertDzTeacherClass(DzTeacherClass dzTeacherClass);
+
+    /**
+     * 修改教师班级关系
+     * 
+     * @param dzTeacherClass 教师班级关系
+     * @return 结果
+     */
+    public int updateDzTeacherClass(DzTeacherClass dzTeacherClass);
+
+    /**
+     * 批量删除教师班级关系
+     * 
+     * @param ids 需要删除的教师班级关系主键集合
+     * @return 结果
+     */
+    public int deleteDzTeacherClassByIds(String[] ids);
+
+    /**
+     * 删除教师班级关系信息
+     * 
+     * @param id 教师班级关系主键
+     * @return 结果
+     */
+    public int deleteDzTeacherClassById(String id);
+}

+ 61 - 0
ie-system/src/main/java/com/ruoyi/dz/service/IDzTeacherService.java

@@ -0,0 +1,61 @@
+package com.ruoyi.dz.service;
+
+import java.util.List;
+import com.ruoyi.dz.domain.DzTeacher;
+
+/**
+ * 老师Service接口
+ * 
+ * @author ruoyi
+ * @date 2025-09-12
+ */
+public interface IDzTeacherService 
+{
+    /**
+     * 查询老师
+     * 
+     * @param teacherId 老师主键
+     * @return 老师
+     */
+    public DzTeacher selectDzTeacherByTeacherId(Long teacherId);
+
+    /**
+     * 查询老师列表
+     * 
+     * @param dzTeacher 老师
+     * @return 老师集合
+     */
+    public List<DzTeacher> selectDzTeacherList(DzTeacher dzTeacher);
+
+    /**
+     * 新增老师
+     * 
+     * @param dzTeacher 老师
+     * @return 结果
+     */
+    public int insertDzTeacher(DzTeacher dzTeacher);
+
+    /**
+     * 修改老师
+     * 
+     * @param dzTeacher 老师
+     * @return 结果
+     */
+    public int updateDzTeacher(DzTeacher dzTeacher);
+
+    /**
+     * 批量删除老师
+     * 
+     * @param teacherIds 需要删除的老师主键集合
+     * @return 结果
+     */
+    public int deleteDzTeacherByTeacherIds(Long[] teacherIds);
+
+    /**
+     * 删除老师信息
+     * 
+     * @param teacherId 老师主键
+     * @return 结果
+     */
+    public int deleteDzTeacherByTeacherId(Long teacherId);
+}

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است