Przeglądaj źródła

完成卡管理前端编写

month-red-love 3 miesięcy temu
rodzic
commit
238299b0e6
98 zmienionych plików z 5924 dodań i 1280 usunięć
  1. BIN
      back-ui/admin.zip
  2. 565 70
      back-ui/package-lock.json
  3. 3 1
      back-ui/package.json
  4. 392 12
      back-ui/pnpm-lock.yaml
  5. 45 19
      back-ui/src/api/dz/cards.js
  6. 8 0
      back-ui/src/api/dz/classes.js
  7. 58 0
      back-ui/src/api/dz/papers.js
  8. 9 0
      back-ui/src/api/dz/school.js
  9. 17 0
      back-ui/src/api/dz/teacherclass.js
  10. 15 0
      back-ui/src/assets/icons/svg/share.svg
  11. 15 0
      back-ui/src/assets/styles/tailwind.css
  12. 41 15
      back-ui/src/components/AddressSelect/index.vue
  13. 25 5
      back-ui/src/components/Form/index.vue
  14. 37 0
      back-ui/src/components/SearchForm/index.vue
  15. 357 0
      back-ui/src/components/Table/index.vue
  16. 1 9
      back-ui/src/layout/components/Navbar.vue
  17. 1 0
      back-ui/src/main.js
  18. 36 7
      back-ui/src/views/dz/agent/index.vue
  19. 157 0
      back-ui/src/views/dz/cards/components/ApplyCardDialog.vue
  20. 237 0
      back-ui/src/views/dz/cards/components/AssignCardDialog.vue
  21. 166 0
      back-ui/src/views/dz/cards/components/AssociateCampusDialog.vue
  22. 225 0
      back-ui/src/views/dz/cards/components/CardGenerationDialog.vue
  23. 91 0
      back-ui/src/views/dz/cards/components/CloseCardDialog.vue
  24. 201 0
      back-ui/src/views/dz/cards/components/EditStudentDialog.vue
  25. 91 0
      back-ui/src/views/dz/cards/components/PaymentDialog.vue
  26. 91 0
      back-ui/src/views/dz/cards/components/RefundDialog.vue
  27. 91 0
      back-ui/src/views/dz/cards/components/ReopenCardDialog.vue
  28. 222 136
      back-ui/src/views/dz/cards/config/form.js
  29. 187 0
      back-ui/src/views/dz/cards/config/table.js
  30. 578 404
      back-ui/src/views/dz/cards/index.vue
  31. 0 1
      back-ui/src/views/dz/classes/index.vue
  32. 19 0
      back-ui/src/views/dz/papers/components/paper-by-hand.vue
  33. 19 0
      back-ui/src/views/dz/papers/components/paper-by-intelligent.vue
  34. 47 0
      back-ui/src/views/dz/papers/components/paper-exact-conditions.vue
  35. 18 0
      back-ui/src/views/dz/papers/components/paper-full-conditions.vue
  36. 21 0
      back-ui/src/views/dz/papers/components/paper-hand-exact.vue
  37. 21 0
      back-ui/src/views/dz/papers/components/paper-hand-full.vue
  38. 13 0
      back-ui/src/views/dz/papers/components/paper-intelligent-exact.vue
  39. 13 0
      back-ui/src/views/dz/papers/components/paper-intelligent-form.vue
  40. 13 0
      back-ui/src/views/dz/papers/components/paper-intelligent-full.vue
  41. 41 0
      back-ui/src/views/dz/papers/components/paper-knowledge-tree.vue
  42. 10 0
      back-ui/src/views/dz/papers/detail.vue
  43. 92 0
      back-ui/src/views/dz/papers/hooks/usePaperExactCondition.js
  44. 39 0
      back-ui/src/views/dz/papers/hooks/usePaperFullCondition.js
  45. 16 2
      back-ui/src/views/dz/papers/index.vue
  46. 5 4
      back-ui/src/views/dz/school/index.vue
  47. 118 1
      back-ui/src/views/dz/teacher/index.vue
  48. 8 8
      back-ui/src/views/dz/teacherclass/index.vue
  49. 11 1
      back-ui/src/views/system/user/index.vue
  50. 9 0
      back-ui/tailwind.config.cjs
  51. 2 1
      back-ui/vite.config.js
  52. 208 359
      back-ui/yarn.lock
  53. 50 2
      ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzAgentController.java
  54. 24 0
      ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzClassesController.java
  55. 38 1
      ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzSchoolController.java
  56. 70 3
      ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzTeacherClassController.java
  57. 5 1
      ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzTeacherController.java
  58. 79 0
      ie-admin/src/main/java/com/ruoyi/web/controller/front/FrontCustomerMarjorsController.java
  59. 103 0
      ie-admin/src/main/java/com/ruoyi/web/controller/front/FrontCustomerUniversityController.java
  60. 3 1
      ie-admin/src/main/java/com/ruoyi/web/controller/learn/LearnQuestionsController.java
  61. 28 5
      ie-admin/src/main/java/com/ruoyi/web/controller/learn/LearnTeacherController.java
  62. 4 4
      ie-admin/src/main/java/com/ruoyi/web/service/ExamService.java
  63. 266 2
      ie-admin/src/main/java/com/ruoyi/web/service/LearnTeacherService.java
  64. 9 28
      ie-admin/src/main/java/com/ruoyi/web/service/PaperService.java
  65. 2 0
      ie-admin/src/main/java/com/ruoyi/web/service/SysRegisterService.java
  66. 65 0
      ie-common/src/main/java/com/ruoyi/common/enums/BoolValues.java
  67. 24 0
      ie-system/src/main/java/com/ruoyi/dz/domain/DzAgent.java
  68. 18 0
      ie-system/src/main/java/com/ruoyi/dz/domain/DzClasses.java
  69. 12 1
      ie-system/src/main/java/com/ruoyi/dz/domain/DzSchool.java
  70. 2 1
      ie-system/src/main/java/com/ruoyi/dz/domain/DzTeacher.java
  71. 27 17
      ie-system/src/main/java/com/ruoyi/dz/domain/DzTeacherClass.java
  72. 9 9
      ie-system/src/main/java/com/ruoyi/dz/mapper/DzSchoolMapper.java
  73. 9 9
      ie-system/src/main/java/com/ruoyi/dz/mapper/DzTeacherClassMapper.java
  74. 9 9
      ie-system/src/main/java/com/ruoyi/dz/service/IDzSchoolService.java
  75. 9 8
      ie-system/src/main/java/com/ruoyi/dz/service/IDzTeacherClassService.java
  76. 14 8
      ie-system/src/main/java/com/ruoyi/dz/service/impl/DzSchoolServiceImpl.java
  77. 13 8
      ie-system/src/main/java/com/ruoyi/dz/service/impl/DzTeacherClassServiceImpl.java
  78. 1 0
      ie-system/src/main/java/com/ruoyi/ie/mapper/AMarjorPlanMapper.java
  79. 12 1
      ie-system/src/main/java/com/ruoyi/learn/domain/LearnDirectedKnowledge.java
  80. 22 0
      ie-system/src/main/java/com/ruoyi/learn/domain/LearnPaperQuestion.java
  81. 23 13
      ie-system/src/main/java/com/ruoyi/learn/domain/LearnTestPaper.java
  82. 70 14
      ie-system/src/main/java/com/ruoyi/learn/domain/TestPaperVO.java
  83. 2 0
      ie-system/src/main/java/com/ruoyi/learn/mapper/LearnDirectedKnowledgeMapper.java
  84. 4 0
      ie-system/src/main/java/com/ruoyi/learn/mapper/LearnStudentMapper.java
  85. 4 0
      ie-system/src/main/java/com/ruoyi/learn/mapper/LearnTestPaperMapper.java
  86. 9 8
      ie-system/src/main/java/com/ruoyi/system/mapper/SysAreaMapper.java
  87. 1 0
      ie-system/src/main/java/com/ruoyi/system/service/ISysAreaService.java
  88. 5 0
      ie-system/src/main/java/com/ruoyi/system/service/impl/SysAreaServiceImpl.java
  89. 22 19
      ie-system/src/main/resources/mapper/dz/DzAgentMapper.xml
  90. 14 1
      ie-system/src/main/resources/mapper/dz/DzSchoolMapper.xml
  91. 31 11
      ie-system/src/main/resources/mapper/dz/DzTeacherClassMapper.xml
  92. 5 0
      ie-system/src/main/resources/mapper/ie/AMarjorPlanMapper.xml
  93. 11 1
      ie-system/src/main/resources/mapper/learn/LearnDirectedKnowledgeMapper.xml
  94. 19 1
      ie-system/src/main/resources/mapper/learn/LearnStudentMapper.xml
  95. 20 10
      ie-system/src/main/resources/mapper/learn/LearnTestPaperMapper.xml
  96. 13 0
      ie-system/src/main/resources/mapper/learn/LearnTestStudentMapper.xml
  97. 10 0
      ie-system/src/main/resources/mapper/system/SysAreaMapper.xml
  98. 29 29
      sql/v_0.2_base.sql

BIN
back-ui/admin.zip


Plik diff jest za duży
+ 565 - 70
back-ui/package-lock.json


+ 3 - 1
back-ui/package.json

@@ -17,8 +17,9 @@
   },
   },
   "dependencies": {
   "dependencies": {
     "@element-plus/icons-vue": "2.3.1",
     "@element-plus/icons-vue": "2.3.1",
+    "@tailwindcss/vite": "^4.1.14",
     "@vueup/vue-quill": "1.2.0",
     "@vueup/vue-quill": "1.2.0",
-    "@vueuse/core": "13.3.0",
+    "@vueuse/core": "^13.3.0",
     "axios": "1.9.0",
     "axios": "1.9.0",
     "clipboard": "2.0.11",
     "clipboard": "2.0.11",
     "echarts": "5.6.0",
     "echarts": "5.6.0",
@@ -32,6 +33,7 @@
     "pinia": "3.0.2",
     "pinia": "3.0.2",
     "sortablejs": "^1.15.6",
     "sortablejs": "^1.15.6",
     "splitpanes": "4.0.4",
     "splitpanes": "4.0.4",
+    "tailwindcss": "^4.1.13",
     "vue": "3.5.16",
     "vue": "3.5.16",
     "vue-cropper": "1.1.1",
     "vue-cropper": "1.1.1",
     "vue-router": "4.5.1",
     "vue-router": "4.5.1",

+ 392 - 12
back-ui/pnpm-lock.yaml

@@ -11,11 +11,14 @@ importers:
       '@element-plus/icons-vue':
       '@element-plus/icons-vue':
         specifier: 2.3.1
         specifier: 2.3.1
         version: 2.3.1(vue@3.5.16)
         version: 2.3.1(vue@3.5.16)
+      '@tailwindcss/vite':
+        specifier: ^4.1.14
+        version: 4.1.14(vite@6.3.5(@types/node@24.6.1)(jiti@2.6.1)(lightningcss@1.30.1)(sass-embedded@1.89.1))
       '@vueup/vue-quill':
       '@vueup/vue-quill':
         specifier: 1.2.0
         specifier: 1.2.0
         version: 1.2.0(vue@3.5.16)
         version: 1.2.0(vue@3.5.16)
       '@vueuse/core':
       '@vueuse/core':
-        specifier: 13.3.0
+        specifier: ^13.3.0
         version: 13.3.0(vue@3.5.16)
         version: 13.3.0(vue@3.5.16)
       axios:
       axios:
         specifier: 1.9.0
         specifier: 1.9.0
@@ -56,6 +59,9 @@ importers:
       splitpanes:
       splitpanes:
         specifier: 4.0.4
         specifier: 4.0.4
         version: 4.0.4(vue@3.5.16)
         version: 4.0.4(vue@3.5.16)
+      tailwindcss:
+        specifier: ^4.1.13
+        version: 4.1.14
       vue:
       vue:
         specifier: 3.5.16
         specifier: 3.5.16
         version: 3.5.16
         version: 3.5.16
@@ -71,7 +77,7 @@ importers:
     devDependencies:
     devDependencies:
       '@vitejs/plugin-vue':
       '@vitejs/plugin-vue':
         specifier: 5.2.4
         specifier: 5.2.4
-        version: 5.2.4(vite@6.3.5(@types/node@24.6.1)(sass-embedded@1.89.1))(vue@3.5.16)
+        version: 5.2.4(vite@6.3.5(@types/node@24.6.1)(jiti@2.6.1)(lightningcss@1.30.1)(sass-embedded@1.89.1))(vue@3.5.16)
       sass-embedded:
       sass-embedded:
         specifier: 1.89.1
         specifier: 1.89.1
         version: 1.89.1
         version: 1.89.1
@@ -83,13 +89,13 @@ importers:
         version: 1.0.1
         version: 1.0.1
       vite:
       vite:
         specifier: 6.3.5
         specifier: 6.3.5
-        version: 6.3.5(@types/node@24.6.1)(sass-embedded@1.89.1)
+        version: 6.3.5(@types/node@24.6.1)(jiti@2.6.1)(lightningcss@1.30.1)(sass-embedded@1.89.1)
       vite-plugin-compression:
       vite-plugin-compression:
         specifier: 0.5.1
         specifier: 0.5.1
-        version: 0.5.1(vite@6.3.5(@types/node@24.6.1)(sass-embedded@1.89.1))
+        version: 0.5.1(vite@6.3.5(@types/node@24.6.1)(jiti@2.6.1)(lightningcss@1.30.1)(sass-embedded@1.89.1))
       vite-plugin-svg-icons:
       vite-plugin-svg-icons:
         specifier: 2.0.1
         specifier: 2.0.1
-        version: 2.0.1(vite@6.3.5(@types/node@24.6.1)(sass-embedded@1.89.1))
+        version: 2.0.1(vite@6.3.5(@types/node@24.6.1)(jiti@2.6.1)(lightningcss@1.30.1)(sass-embedded@1.89.1))
 
 
 packages:
 packages:
 
 
@@ -294,9 +300,26 @@ packages:
     resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
     resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
     engines: {node: '>=12'}
     engines: {node: '>=12'}
 
 
+  '@isaacs/fs-minipass@4.0.1':
+    resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==}
+    engines: {node: '>=18.0.0'}
+
+  '@jridgewell/gen-mapping@0.3.13':
+    resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
+
+  '@jridgewell/remapping@2.3.5':
+    resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
+
+  '@jridgewell/resolve-uri@3.1.2':
+    resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+    engines: {node: '>=6.0.0'}
+
   '@jridgewell/sourcemap-codec@1.5.5':
   '@jridgewell/sourcemap-codec@1.5.5':
     resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
     resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
 
 
+  '@jridgewell/trace-mapping@0.3.31':
+    resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
+
   '@nodelib/fs.scandir@2.1.5':
   '@nodelib/fs.scandir@2.1.5':
     resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
     resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
     engines: {node: '>= 8'}
     engines: {node: '>= 8'}
@@ -438,6 +461,96 @@ packages:
   '@sxzz/popperjs-es@2.11.7':
   '@sxzz/popperjs-es@2.11.7':
     resolution: {integrity: sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==}
     resolution: {integrity: sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==}
 
 
+  '@tailwindcss/node@4.1.14':
+    resolution: {integrity: sha512-hpz+8vFk3Ic2xssIA3e01R6jkmsAhvkQdXlEbRTk6S10xDAtiQiM3FyvZVGsucefq764euO/b8WUW9ysLdThHw==}
+
+  '@tailwindcss/oxide-android-arm64@4.1.14':
+    resolution: {integrity: sha512-a94ifZrGwMvbdeAxWoSuGcIl6/DOP5cdxagid7xJv6bwFp3oebp7y2ImYsnZBMTwjn5Ev5xESvS3FFYUGgPODQ==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [android]
+
+  '@tailwindcss/oxide-darwin-arm64@4.1.14':
+    resolution: {integrity: sha512-HkFP/CqfSh09xCnrPJA7jud7hij5ahKyWomrC3oiO2U9i0UjP17o9pJbxUN0IJ471GTQQmzwhp0DEcpbp4MZTA==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@tailwindcss/oxide-darwin-x64@4.1.14':
+    resolution: {integrity: sha512-eVNaWmCgdLf5iv6Qd3s7JI5SEFBFRtfm6W0mphJYXgvnDEAZ5sZzqmI06bK6xo0IErDHdTA5/t7d4eTfWbWOFw==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [darwin]
+
+  '@tailwindcss/oxide-freebsd-x64@4.1.14':
+    resolution: {integrity: sha512-QWLoRXNikEuqtNb0dhQN6wsSVVjX6dmUFzuuiL09ZeXju25dsei2uIPl71y2Ic6QbNBsB4scwBoFnlBfabHkEw==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [freebsd]
+
+  '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.14':
+    resolution: {integrity: sha512-VB4gjQni9+F0VCASU+L8zSIyjrLLsy03sjcR3bM0V2g4SNamo0FakZFKyUQ96ZVwGK4CaJsc9zd/obQy74o0Fw==}
+    engines: {node: '>= 10'}
+    cpu: [arm]
+    os: [linux]
+
+  '@tailwindcss/oxide-linux-arm64-gnu@4.1.14':
+    resolution: {integrity: sha512-qaEy0dIZ6d9vyLnmeg24yzA8XuEAD9WjpM5nIM1sUgQ/Zv7cVkharPDQcmm/t/TvXoKo/0knI3me3AGfdx6w1w==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@tailwindcss/oxide-linux-arm64-musl@4.1.14':
+    resolution: {integrity: sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@tailwindcss/oxide-linux-x64-gnu@4.1.14':
+    resolution: {integrity: sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [linux]
+
+  '@tailwindcss/oxide-linux-x64-musl@4.1.14':
+    resolution: {integrity: sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [linux]
+
+  '@tailwindcss/oxide-wasm32-wasi@4.1.14':
+    resolution: {integrity: sha512-uZYAsaW/jS/IYkd6EWPJKW/NlPNSkWkBlaeVBi/WsFQNP05/bzkebUL8FH1pdsqx4f2fH/bWFcUABOM9nfiJkQ==}
+    engines: {node: '>=14.0.0'}
+    cpu: [wasm32]
+    bundledDependencies:
+      - '@napi-rs/wasm-runtime'
+      - '@emnapi/core'
+      - '@emnapi/runtime'
+      - '@tybys/wasm-util'
+      - '@emnapi/wasi-threads'
+      - tslib
+
+  '@tailwindcss/oxide-win32-arm64-msvc@4.1.14':
+    resolution: {integrity: sha512-Az0RnnkcvRqsuoLH2Z4n3JfAef0wElgzHD5Aky/e+0tBUxUhIeIqFBTMNQvmMRSP15fWwmvjBxZ3Q8RhsDnxAA==}
+    engines: {node: '>= 10'}
+    cpu: [arm64]
+    os: [win32]
+
+  '@tailwindcss/oxide-win32-x64-msvc@4.1.14':
+    resolution: {integrity: sha512-ttblVGHgf68kEE4om1n/n44I0yGPkCPbLsqzjvybhpwa6mKKtgFfAzy6btc3HRmuW7nHe0OOrSeNP9sQmmH9XA==}
+    engines: {node: '>= 10'}
+    cpu: [x64]
+    os: [win32]
+
+  '@tailwindcss/oxide@4.1.14':
+    resolution: {integrity: sha512-23yx+VUbBwCg2x5XWdB8+1lkPajzLmALEfMb51zZUBYaYVPDQvBSD/WYDqiVyBIo2BZFa3yw1Rpy3G2Jp+K0dw==}
+    engines: {node: '>= 10'}
+
+  '@tailwindcss/vite@4.1.14':
+    resolution: {integrity: sha512-BoFUoU0XqgCUS1UXWhmDJroKKhNXeDzD7/XwabjkDIAbMnc4ULn5e2FuEuBbhZ6ENZoSYzKlzvZ44Yr6EUDUSA==}
+    peerDependencies:
+      vite: ^5.2.0 || ^6 || ^7
+
   '@trysound/sax@0.2.0':
   '@trysound/sax@0.2.0':
     resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
     resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
     engines: {node: '>=10.13.0'}
     engines: {node: '>=10.13.0'}
@@ -693,6 +806,10 @@ packages:
     resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
     resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
     engines: {node: '>=10'}
     engines: {node: '>=10'}
 
 
+  chownr@3.0.0:
+    resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==}
+    engines: {node: '>=18'}
+
   class-utils@0.3.6:
   class-utils@0.3.6:
     resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==}
     resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==}
     engines: {node: '>=0.10.0'}
     engines: {node: '>=0.10.0'}
@@ -843,6 +960,10 @@ packages:
   delegate@3.2.0:
   delegate@3.2.0:
     resolution: {integrity: sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==}
     resolution: {integrity: sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==}
 
 
+  detect-libc@2.1.1:
+    resolution: {integrity: sha512-ecqj/sy1jcK1uWrwpR67UhYrIFQ+5WlGxth34WquCbamhFA6hkkwiu37o6J5xCHdo1oixJRfVRw+ywV+Hq/0Aw==}
+    engines: {node: '>=8'}
+
   dom-serializer@0.2.2:
   dom-serializer@0.2.2:
     resolution: {integrity: sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==}
     resolution: {integrity: sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==}
 
 
@@ -898,6 +1019,10 @@ packages:
     resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==}
     resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==}
     engines: {node: '>= 4'}
     engines: {node: '>= 4'}
 
 
+  enhanced-resolve@5.18.3:
+    resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==}
+    engines: {node: '>=10.13.0'}
+
   entities@1.1.2:
   entities@1.1.2:
     resolution: {integrity: sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==}
     resolution: {integrity: sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==}
 
 
@@ -1360,6 +1485,10 @@ packages:
   jackspeak@3.4.3:
   jackspeak@3.4.3:
     resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
     resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
 
 
+  jiti@2.6.1:
+    resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
+    hasBin: true
+
   js-base64@2.6.4:
   js-base64@2.6.4:
     resolution: {integrity: sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==}
     resolution: {integrity: sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==}
 
 
@@ -1401,6 +1530,70 @@ packages:
     resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
     resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
     engines: {node: '>=0.10.0'}
     engines: {node: '>=0.10.0'}
 
 
+  lightningcss-darwin-arm64@1.30.1:
+    resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [arm64]
+    os: [darwin]
+
+  lightningcss-darwin-x64@1.30.1:
+    resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [x64]
+    os: [darwin]
+
+  lightningcss-freebsd-x64@1.30.1:
+    resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [x64]
+    os: [freebsd]
+
+  lightningcss-linux-arm-gnueabihf@1.30.1:
+    resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [arm]
+    os: [linux]
+
+  lightningcss-linux-arm64-gnu@1.30.1:
+    resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [arm64]
+    os: [linux]
+
+  lightningcss-linux-arm64-musl@1.30.1:
+    resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [arm64]
+    os: [linux]
+
+  lightningcss-linux-x64-gnu@1.30.1:
+    resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [x64]
+    os: [linux]
+
+  lightningcss-linux-x64-musl@1.30.1:
+    resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [x64]
+    os: [linux]
+
+  lightningcss-win32-arm64-msvc@1.30.1:
+    resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [arm64]
+    os: [win32]
+
+  lightningcss-win32-x64-msvc@1.30.1:
+    resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==}
+    engines: {node: '>= 12.0.0'}
+    cpu: [x64]
+    os: [win32]
+
+  lightningcss@1.30.1:
+    resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==}
+    engines: {node: '>= 12.0.0'}
+
   loader-utils@1.4.2:
   loader-utils@1.4.2:
     resolution: {integrity: sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==}
     resolution: {integrity: sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==}
     engines: {node: '>=4.0.0'}
     engines: {node: '>=4.0.0'}
@@ -1500,6 +1693,10 @@ packages:
     resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
     resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
     engines: {node: '>=16 || 14 >=14.17'}
     engines: {node: '>=16 || 14 >=14.17'}
 
 
+  minizlib@3.1.0:
+    resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==}
+    engines: {node: '>= 18'}
+
   mitt@3.0.1:
   mitt@3.0.1:
     resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
     resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
 
 
@@ -2061,6 +2258,17 @@ packages:
     resolution: {integrity: sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==}
     resolution: {integrity: sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==}
     engines: {node: '>=16.0.0'}
     engines: {node: '>=16.0.0'}
 
 
+  tailwindcss@4.1.14:
+    resolution: {integrity: sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==}
+
+  tapable@2.3.0:
+    resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
+    engines: {node: '>=6'}
+
+  tar@7.5.1:
+    resolution: {integrity: sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==}
+    engines: {node: '>=18'}
+
   tiny-emitter@2.1.0:
   tiny-emitter@2.1.0:
     resolution: {integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==}
     resolution: {integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==}
 
 
@@ -2290,6 +2498,10 @@ packages:
     resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
     resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
     engines: {node: '>=12'}
     engines: {node: '>=12'}
 
 
+  yallist@5.0.0:
+    resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==}
+    engines: {node: '>=18'}
+
   zrender@5.6.1:
   zrender@5.6.1:
     resolution: {integrity: sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==}
     resolution: {integrity: sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==}
 
 
@@ -2416,8 +2628,29 @@ snapshots:
       wrap-ansi: 8.1.0
       wrap-ansi: 8.1.0
       wrap-ansi-cjs: wrap-ansi@7.0.0
       wrap-ansi-cjs: wrap-ansi@7.0.0
 
 
+  '@isaacs/fs-minipass@4.0.1':
+    dependencies:
+      minipass: 7.1.2
+
+  '@jridgewell/gen-mapping@0.3.13':
+    dependencies:
+      '@jridgewell/sourcemap-codec': 1.5.5
+      '@jridgewell/trace-mapping': 0.3.31
+
+  '@jridgewell/remapping@2.3.5':
+    dependencies:
+      '@jridgewell/gen-mapping': 0.3.13
+      '@jridgewell/trace-mapping': 0.3.31
+
+  '@jridgewell/resolve-uri@3.1.2': {}
+
   '@jridgewell/sourcemap-codec@1.5.5': {}
   '@jridgewell/sourcemap-codec@1.5.5': {}
 
 
+  '@jridgewell/trace-mapping@0.3.31':
+    dependencies:
+      '@jridgewell/resolve-uri': 3.1.2
+      '@jridgewell/sourcemap-codec': 1.5.5
+
   '@nodelib/fs.scandir@2.1.5':
   '@nodelib/fs.scandir@2.1.5':
     dependencies:
     dependencies:
       '@nodelib/fs.stat': 2.0.5
       '@nodelib/fs.stat': 2.0.5
@@ -2511,6 +2744,77 @@ snapshots:
 
 
   '@sxzz/popperjs-es@2.11.7': {}
   '@sxzz/popperjs-es@2.11.7': {}
 
 
+  '@tailwindcss/node@4.1.14':
+    dependencies:
+      '@jridgewell/remapping': 2.3.5
+      enhanced-resolve: 5.18.3
+      jiti: 2.6.1
+      lightningcss: 1.30.1
+      magic-string: 0.30.19
+      source-map-js: 1.2.1
+      tailwindcss: 4.1.14
+
+  '@tailwindcss/oxide-android-arm64@4.1.14':
+    optional: true
+
+  '@tailwindcss/oxide-darwin-arm64@4.1.14':
+    optional: true
+
+  '@tailwindcss/oxide-darwin-x64@4.1.14':
+    optional: true
+
+  '@tailwindcss/oxide-freebsd-x64@4.1.14':
+    optional: true
+
+  '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.14':
+    optional: true
+
+  '@tailwindcss/oxide-linux-arm64-gnu@4.1.14':
+    optional: true
+
+  '@tailwindcss/oxide-linux-arm64-musl@4.1.14':
+    optional: true
+
+  '@tailwindcss/oxide-linux-x64-gnu@4.1.14':
+    optional: true
+
+  '@tailwindcss/oxide-linux-x64-musl@4.1.14':
+    optional: true
+
+  '@tailwindcss/oxide-wasm32-wasi@4.1.14':
+    optional: true
+
+  '@tailwindcss/oxide-win32-arm64-msvc@4.1.14':
+    optional: true
+
+  '@tailwindcss/oxide-win32-x64-msvc@4.1.14':
+    optional: true
+
+  '@tailwindcss/oxide@4.1.14':
+    dependencies:
+      detect-libc: 2.1.1
+      tar: 7.5.1
+    optionalDependencies:
+      '@tailwindcss/oxide-android-arm64': 4.1.14
+      '@tailwindcss/oxide-darwin-arm64': 4.1.14
+      '@tailwindcss/oxide-darwin-x64': 4.1.14
+      '@tailwindcss/oxide-freebsd-x64': 4.1.14
+      '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.14
+      '@tailwindcss/oxide-linux-arm64-gnu': 4.1.14
+      '@tailwindcss/oxide-linux-arm64-musl': 4.1.14
+      '@tailwindcss/oxide-linux-x64-gnu': 4.1.14
+      '@tailwindcss/oxide-linux-x64-musl': 4.1.14
+      '@tailwindcss/oxide-wasm32-wasi': 4.1.14
+      '@tailwindcss/oxide-win32-arm64-msvc': 4.1.14
+      '@tailwindcss/oxide-win32-x64-msvc': 4.1.14
+
+  '@tailwindcss/vite@4.1.14(vite@6.3.5(@types/node@24.6.1)(jiti@2.6.1)(lightningcss@1.30.1)(sass-embedded@1.89.1))':
+    dependencies:
+      '@tailwindcss/node': 4.1.14
+      '@tailwindcss/oxide': 4.1.14
+      tailwindcss: 4.1.14
+      vite: 6.3.5(@types/node@24.6.1)(jiti@2.6.1)(lightningcss@1.30.1)(sass-embedded@1.89.1)
+
   '@trysound/sax@0.2.0': {}
   '@trysound/sax@0.2.0': {}
 
 
   '@types/estree@1.0.8': {}
   '@types/estree@1.0.8': {}
@@ -2533,9 +2837,9 @@ snapshots:
 
 
   '@types/web-bluetooth@0.0.21': {}
   '@types/web-bluetooth@0.0.21': {}
 
 
-  '@vitejs/plugin-vue@5.2.4(vite@6.3.5(@types/node@24.6.1)(sass-embedded@1.89.1))(vue@3.5.16)':
+  '@vitejs/plugin-vue@5.2.4(vite@6.3.5(@types/node@24.6.1)(jiti@2.6.1)(lightningcss@1.30.1)(sass-embedded@1.89.1))(vue@3.5.16)':
     dependencies:
     dependencies:
-      vite: 6.3.5(@types/node@24.6.1)(sass-embedded@1.89.1)
+      vite: 6.3.5(@types/node@24.6.1)(jiti@2.6.1)(lightningcss@1.30.1)(sass-embedded@1.89.1)
       vue: 3.5.16
       vue: 3.5.16
 
 
   '@vue/compiler-core@3.5.16':
   '@vue/compiler-core@3.5.16':
@@ -2832,6 +3136,8 @@ snapshots:
       ansi-styles: 4.3.0
       ansi-styles: 4.3.0
       supports-color: 7.2.0
       supports-color: 7.2.0
 
 
+  chownr@3.0.0: {}
+
   class-utils@0.3.6:
   class-utils@0.3.6:
     dependencies:
     dependencies:
       arr-union: 3.1.0
       arr-union: 3.1.0
@@ -2985,6 +3291,8 @@ snapshots:
 
 
   delegate@3.2.0: {}
   delegate@3.2.0: {}
 
 
+  detect-libc@2.1.1: {}
+
   dom-serializer@0.2.2:
   dom-serializer@0.2.2:
     dependencies:
     dependencies:
       domelementtype: 2.3.0
       domelementtype: 2.3.0
@@ -3066,6 +3374,11 @@ snapshots:
 
 
   emojis-list@3.0.0: {}
   emojis-list@3.0.0: {}
 
 
+  enhanced-resolve@5.18.3:
+    dependencies:
+      graceful-fs: 4.2.11
+      tapable: 2.3.0
+
   entities@1.1.2: {}
   entities@1.1.2: {}
 
 
   entities@2.2.0: {}
   entities@2.2.0: {}
@@ -3612,6 +3925,8 @@ snapshots:
     optionalDependencies:
     optionalDependencies:
       '@pkgjs/parseargs': 0.11.0
       '@pkgjs/parseargs': 0.11.0
 
 
+  jiti@2.6.1: {}
+
   js-base64@2.6.4: {}
   js-base64@2.6.4: {}
 
 
   js-beautify@1.14.11:
   js-beautify@1.14.11:
@@ -3649,6 +3964,51 @@ snapshots:
 
 
   kind-of@6.0.3: {}
   kind-of@6.0.3: {}
 
 
+  lightningcss-darwin-arm64@1.30.1:
+    optional: true
+
+  lightningcss-darwin-x64@1.30.1:
+    optional: true
+
+  lightningcss-freebsd-x64@1.30.1:
+    optional: true
+
+  lightningcss-linux-arm-gnueabihf@1.30.1:
+    optional: true
+
+  lightningcss-linux-arm64-gnu@1.30.1:
+    optional: true
+
+  lightningcss-linux-arm64-musl@1.30.1:
+    optional: true
+
+  lightningcss-linux-x64-gnu@1.30.1:
+    optional: true
+
+  lightningcss-linux-x64-musl@1.30.1:
+    optional: true
+
+  lightningcss-win32-arm64-msvc@1.30.1:
+    optional: true
+
+  lightningcss-win32-x64-msvc@1.30.1:
+    optional: true
+
+  lightningcss@1.30.1:
+    dependencies:
+      detect-libc: 2.1.1
+    optionalDependencies:
+      lightningcss-darwin-arm64: 1.30.1
+      lightningcss-darwin-x64: 1.30.1
+      lightningcss-freebsd-x64: 1.30.1
+      lightningcss-linux-arm-gnueabihf: 1.30.1
+      lightningcss-linux-arm64-gnu: 1.30.1
+      lightningcss-linux-arm64-musl: 1.30.1
+      lightningcss-linux-x64-gnu: 1.30.1
+      lightningcss-linux-x64-musl: 1.30.1
+      lightningcss-win32-arm64-msvc: 1.30.1
+      lightningcss-win32-x64-msvc: 1.30.1
+
   loader-utils@1.4.2:
   loader-utils@1.4.2:
     dependencies:
     dependencies:
       big.js: 5.2.2
       big.js: 5.2.2
@@ -3749,6 +4109,10 @@ snapshots:
 
 
   minipass@7.1.2: {}
   minipass@7.1.2: {}
 
 
+  minizlib@3.1.0:
+    dependencies:
+      minipass: 7.1.2
+
   mitt@3.0.1: {}
   mitt@3.0.1: {}
 
 
   mixin-deep@1.3.2:
   mixin-deep@1.3.2:
@@ -4384,6 +4748,18 @@ snapshots:
 
 
   sync-message-port@1.1.3: {}
   sync-message-port@1.1.3: {}
 
 
+  tailwindcss@4.1.14: {}
+
+  tapable@2.3.0: {}
+
+  tar@7.5.1:
+    dependencies:
+      '@isaacs/fs-minipass': 4.0.1
+      chownr: 3.0.0
+      minipass: 7.1.2
+      minizlib: 3.1.0
+      yallist: 5.0.0
+
   tiny-emitter@2.1.0: {}
   tiny-emitter@2.1.0: {}
 
 
   tinyglobby@0.2.15:
   tinyglobby@0.2.15:
@@ -4545,16 +4921,16 @@ snapshots:
 
 
   vary@1.1.2: {}
   vary@1.1.2: {}
 
 
-  vite-plugin-compression@0.5.1(vite@6.3.5(@types/node@24.6.1)(sass-embedded@1.89.1)):
+  vite-plugin-compression@0.5.1(vite@6.3.5(@types/node@24.6.1)(jiti@2.6.1)(lightningcss@1.30.1)(sass-embedded@1.89.1)):
     dependencies:
     dependencies:
       chalk: 4.1.2
       chalk: 4.1.2
       debug: 4.4.3
       debug: 4.4.3
       fs-extra: 10.1.0
       fs-extra: 10.1.0
-      vite: 6.3.5(@types/node@24.6.1)(sass-embedded@1.89.1)
+      vite: 6.3.5(@types/node@24.6.1)(jiti@2.6.1)(lightningcss@1.30.1)(sass-embedded@1.89.1)
     transitivePeerDependencies:
     transitivePeerDependencies:
       - supports-color
       - supports-color
 
 
-  vite-plugin-svg-icons@2.0.1(vite@6.3.5(@types/node@24.6.1)(sass-embedded@1.89.1)):
+  vite-plugin-svg-icons@2.0.1(vite@6.3.5(@types/node@24.6.1)(jiti@2.6.1)(lightningcss@1.30.1)(sass-embedded@1.89.1)):
     dependencies:
     dependencies:
       '@types/svgo': 2.6.4
       '@types/svgo': 2.6.4
       cors: 2.8.5
       cors: 2.8.5
@@ -4564,11 +4940,11 @@ snapshots:
       pathe: 0.2.0
       pathe: 0.2.0
       svg-baker: 1.7.0
       svg-baker: 1.7.0
       svgo: 2.8.0
       svgo: 2.8.0
-      vite: 6.3.5(@types/node@24.6.1)(sass-embedded@1.89.1)
+      vite: 6.3.5(@types/node@24.6.1)(jiti@2.6.1)(lightningcss@1.30.1)(sass-embedded@1.89.1)
     transitivePeerDependencies:
     transitivePeerDependencies:
       - supports-color
       - supports-color
 
 
-  vite@6.3.5(@types/node@24.6.1)(sass-embedded@1.89.1):
+  vite@6.3.5(@types/node@24.6.1)(jiti@2.6.1)(lightningcss@1.30.1)(sass-embedded@1.89.1):
     dependencies:
     dependencies:
       esbuild: 0.25.10
       esbuild: 0.25.10
       fdir: 6.5.0(picomatch@4.0.3)
       fdir: 6.5.0(picomatch@4.0.3)
@@ -4579,6 +4955,8 @@ snapshots:
     optionalDependencies:
     optionalDependencies:
       '@types/node': 24.6.1
       '@types/node': 24.6.1
       fsevents: 2.3.3
       fsevents: 2.3.3
+      jiti: 2.6.1
+      lightningcss: 1.30.1
       sass-embedded: 1.89.1
       sass-embedded: 1.89.1
 
 
   vue-cropper@1.1.1: {}
   vue-cropper@1.1.1: {}
@@ -4664,6 +5042,8 @@ snapshots:
       string-width: 5.1.2
       string-width: 5.1.2
       strip-ansi: 7.1.2
       strip-ansi: 7.1.2
 
 
+  yallist@5.0.0: {}
+
   zrender@5.6.1:
   zrender@5.6.1:
     dependencies:
     dependencies:
       tslib: 2.3.0
       tslib: 2.3.0

+ 45 - 19
back-ui/src/api/dz/cards.js

@@ -1,44 +1,70 @@
-import request from '@/utils/request'
+import request from "@/utils/request";
 
 
 // 查询学习卡列表
 // 查询学习卡列表
 export function listCards(query) {
 export function listCards(query) {
   return request({
   return request({
-    url: '/dz/cards/list',
-    method: 'get',
-    params: query
-  })
+    url: "/dz/cards/list",
+    method: "get",
+    params: query,
+  });
 }
 }
 
 
 // 查询学习卡详细
 // 查询学习卡详细
 export function getCards(cardId) {
 export function getCards(cardId) {
   return request({
   return request({
-    url: '/dz/cards/' + cardId,
-    method: 'get'
-  })
+    url: "/dz/cards/" + cardId,
+    method: "get",
+  });
 }
 }
 
 
 // 新增学习卡
 // 新增学习卡
 export function addCards(data) {
 export function addCards(data) {
   return request({
   return request({
-    url: '/dz/cards',
-    method: 'post',
-    data: data
-  })
+    url: "/dz/cards",
+    method: "post",
+    data: data,
+  });
 }
 }
 
 
 // 修改学习卡
 // 修改学习卡
 export function updateCards(data) {
 export function updateCards(data) {
   return request({
   return request({
-    url: '/dz/cards',
-    method: 'put',
-    data: data
-  })
+    url: "/dz/cards",
+    method: "put",
+    data: data,
+  });
 }
 }
 
 
 // 删除学习卡
 // 删除学习卡
 export function delCards(cardId) {
 export function delCards(cardId) {
   return request({
   return request({
-    url: '/dz/cards/' + cardId,
-    method: 'delete'
-  })
+    url: "/dz/cards/" + cardId,
+    method: "delete",
+  });
+}
+
+// 制卡
+export function issueCard(institutionId, type, count) {
+  return request({
+    url: "/dz/cards/issueCard",
+    method: "post",
+    params: {
+      institutionId,
+      type,
+      count,
+    },
+  });
+}
+
+// 分配卡
+export function assignCard(agentId, begin, end) {
+  return request({
+    url: "/dz/cards/assignCard",
+    method: "post",
+    params: {
+      agentId,
+      begin,
+      end,
+    },
+  });
 }
 }

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

@@ -9,6 +9,14 @@ export function listClasses(query) {
   })
   })
 }
 }
 
 
+export function listAllClass(query) {
+  return request({
+    url: '/dz/classes/listAll',
+    method: 'get',
+    params: query
+  })
+}
+
 // 查询学生班级列表
 // 查询学生班级列表
 export function listAllSchool(query) {
 export function listAllSchool(query) {
   return request({
   return request({

+ 58 - 0
back-ui/src/api/dz/papers.js

@@ -0,0 +1,58 @@
+import request from '@/utils/request'
+
+/// 科目列表
+export function getPaperSubjects(query) {
+    return request({
+        url: '/learn/teaching/subjects',
+        method: 'get',
+        params: query
+    })
+}
+
+/// 科目列表
+export function getPaperKnowledges(query) {
+    return request({
+        url: '/learn/teaching/knowledges',
+        method: 'get',
+        params: query
+    })
+}
+
+/// 省份列表
+export function getPaperProvinces(query) {
+    return request({
+        url: '/learn/teaching/provinces',
+        method: 'get',
+        params: query
+    })
+}
+
+/// 考生类型
+export function getPaperExamTypes(query) {
+    // query: {location}
+    return request({
+        url: '/learn/teaching/examTypes',
+        method: 'get',
+        params: query
+    })
+}
+
+/// 院校
+export function getPaperUniversities(query) {
+    // query: {batchId}
+    return request({
+        url: '/learn/teaching/universities',
+        method: 'get',
+        params: query
+    })
+}
+
+/// 专业组
+export function getPaperMajors(query) {
+    // query: {location, examType, batchId, universityId}
+    return request({
+        url: '/learn/teaching/majors',
+        method: 'get',
+        params: query
+    })
+}

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

@@ -1,5 +1,14 @@
 import request from '@/utils/request'
 import request from '@/utils/request'
 
 
+// 查询查询院校列表
+export function listUniversity(query) {
+  return request({
+    url: '/front/university/list',
+    method: 'get',
+    params: query
+  })
+}
+
 // 查询机构校区列表
 // 查询机构校区列表
 export function listAllSchool(query) {
 export function listAllSchool(query) {
   return request({
   return request({

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

@@ -9,6 +9,15 @@ export function listTeacherclass(query) {
   })
   })
 }
 }
 
 
+// 查询教师班级关系列表
+export function listAllTeacherClass(query) {
+  return request({
+    url: '/dz/teacherclass/listAllTeacherClass',
+    method: 'get',
+    params: query
+  })
+}
+
 // 查询教师班级关系详细
 // 查询教师班级关系详细
 export function getTeacherclass(id) {
 export function getTeacherclass(id) {
   return request({
   return request({
@@ -26,6 +35,14 @@ export function addTeacherclass(data) {
   })
   })
 }
 }
 
 
+export function batchBindTeacherClass(data) {
+  return request({
+    url: '/dz/teacherclass/batchBindTeacherClass',
+    method: 'post',
+    data: data
+  })
+}
+
 // 修改教师班级关系
 // 修改教师班级关系
 export function updateTeacherclass(data) {
 export function updateTeacherclass(data) {
   return request({
   return request({

+ 15 - 0
back-ui/src/assets/icons/svg/share.svg

@@ -0,0 +1,15 @@
+<svg width="1024" height="1024" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
+  <!-- 中心圆 -->
+  <circle cx="512" cy="512" r="64" fill="currentColor"/>
+  
+  <!-- 箭头线条 -->
+  <path d="M512 192L512 832" stroke="currentColor" stroke-width="8" stroke-linecap="round"/>
+  <path d="M192 512L832 512" stroke="currentColor" stroke-width="8" stroke-linecap="round"/>
+  
+  <!-- 对角线箭头 -->
+  <path d="M224 224L800 800" stroke="currentColor" stroke-width="8" stroke-linecap="round"/>
+  <path d="M800 224L224 800" stroke="currentColor" stroke-width="8" stroke-linecap="round"/>
+</svg>
+
+
+

+ 15 - 0
back-ui/src/assets/styles/tailwind.css

@@ -0,0 +1,15 @@
+@layer theme, base, components, utilities;
+@import "tailwindcss/theme.css" layer(theme);
+@import "tailwindcss/utilities.css" layer(utilities);
+/* 没有使用base, 禁用了preflight, 否则会和若依自己的样式有冲突 */
+
+@theme {
+    --color-main: '#303030';
+    --color-content: '#606060';
+    --color-tips: '#909090';
+    --color-primary: var(--el-color-primary);
+    --color-warning: var(--el-color-warning);
+    --color-danger: var(--el-color-danger);
+    --color-success: var(--el-color-success);
+    --color-info: var(--el-color-info);
+}

+ 41 - 15
back-ui/src/components/AddressSelect/index.vue

@@ -1,22 +1,48 @@
 <template>
 <template>
-  <el-cascader :options="data" :props="props" v-model="ids" clearable @change="handleChange" />
+  <el-cascader
+    :options="data"
+    :props="cascaderProps"
+    v-model="ids"
+    clearable
+    @change="handleChange"
+  />
 </template>
 </template>
 <script setup>
 <script setup>
+import { ref, watch } from "vue";
 import { cascaderAreaList } from "@/api/system/area";
 import { cascaderAreaList } from "@/api/system/area";
-const data = ref([]);
-const ids = ref('');
-const opts = defineProps({
-  value: String
-});
-watch(opts, (val) => {
-  ids.value = val;
+
+const props = defineProps({
+  modelValue: [String, Array],
 });
 });
-const emit = defineEmits(['update:value', 'change']);
-const props = {
+
+const emit = defineEmits(["update:modelValue", "change"]);
+
+const data = ref([]);
+const ids = ref(props.modelValue || []);
+
+// 监听父组件传入的值变化
+watch(
+  () => props.modelValue,
+  (newVal) => {
+    ids.value = newVal || [];
+  },
+  { immediate: true }
+);
+
+// 监听内部值变化并通知父组件
+watch(
+  ids,
+  (newVal) => {
+    emit("update:modelValue", newVal);
+  },
+  { deep: true }
+);
+
+const cascaderProps = {
   multiple: false,
   multiple: false,
   checkStrictly: true,
   checkStrictly: true,
-  label: 'areaName',
-  value: 'areaId',
+  label: "areaName",
+  value: "areaId",
   lazy: true,
   lazy: true,
   async lazyLoad(node, resolve) {
   async lazyLoad(node, resolve) {
     const { level, value } = node;
     const { level, value } = node;
@@ -31,9 +57,9 @@ const props = {
 async function getAreaList(parentId) {
 async function getAreaList(parentId) {
   return cascaderAreaList(parentId);
   return cascaderAreaList(parentId);
 }
 }
-function handleChange() {
-  emit('update:value', ids.value || []);
-  emit('change', ids.value || []);
+function handleChange(value) {
+  emit("update:modelValue", ids.value || []);
+  emit("change", ids.value || []);
 }
 }
 </script>
 </script>
 <style lang="scss" scoped></style>
 <style lang="scss" scoped></style>

+ 25 - 5
back-ui/src/components/Form/index.vue

@@ -177,11 +177,11 @@
       <el-col
       <el-col
         v-for="(item, index) in formConfig"
         v-for="(item, index) in formConfig"
         :key="index"
         :key="index"
-        :span="item.span || 24"
-        :xs="item.xs || 24"
-        :sm="item.sm || 12"
-        :md="item.md || 8"
-        :lg="item.lg || 6"
+        :span="item.span || 4"
+        :xs="item.xs || 12"
+        :sm="item.sm || 8"
+        :md="item.md || 6"
+        :lg="item.lg || 4"
         :xl="item.xl || 4"
         :xl="item.xl || 4"
       >
       >
         <el-form-item
         <el-form-item
@@ -398,6 +398,26 @@ const formRef = ref();
 const formData = reactive({});
 const formData = reactive({});
 const formRules = reactive({});
 const formRules = reactive({});
 
 
+// 监听父组件传入的modelValue变化,同步到formData
+watch(
+  () => props.modelValue,
+  (newValue) => {
+    if (newValue) {
+      Object.assign(formData, newValue);
+    }
+  },
+  { immediate: true, deep: true }
+);
+
+// 监听formData变化,同步回父组件
+watch(
+  formData,
+  (newData) => {
+    emit("update:modelValue", { ...newData });
+  },
+  { deep: true }
+);
+
 // 计算属性
 // 计算属性
 const formConfig = computed(() => props.config);
 const formConfig = computed(() => props.config);
 
 

+ 37 - 0
back-ui/src/components/SearchForm/index.vue

@@ -5,6 +5,7 @@
       ref="formRef"
       ref="formRef"
       :config="searchConfig"
       :config="searchConfig"
       :model-value="searchData"
       :model-value="searchData"
+      @update:model-value="handleFormUpdate"
       :inline="inline"
       :inline="inline"
       :size="size"
       :size="size"
       :label-width="labelWidth"
       :label-width="labelWidth"
@@ -126,6 +127,42 @@ const formRef = ref();
 const searchData = reactive({});
 const searchData = reactive({});
 const expandCollapse = ref(true);
 const expandCollapse = ref(true);
 
 
+// 处理Form组件update:model-value事件
+const handleFormUpdate = (newData) => {
+  Object.assign(searchData, newData);
+};
+
+// 监听父组件传入的modelValue变化,同步到searchData
+watch(
+  () => props.modelValue,
+  (newValue) => {
+    if (newValue) {
+      Object.assign(searchData, newValue);
+    }
+  },
+  { immediate: true, deep: true }
+);
+
+// 监听searchData变化,同步回父组件
+watch(
+  searchData,
+  (newData) => {
+    emit("update:modelValue", { ...newData });
+  },
+  { deep: true }
+);
+
+// 强制监听searchData中的areaIds字段
+watch(
+  () => searchData.areaIds,
+  (newAreaIds, oldAreaIds) => {
+    if (newAreaIds !== oldAreaIds) {
+      emit("update:modelValue", { ...searchData });
+    }
+  },
+  { immediate: false, deep: true }
+);
+
 // 计算属性 - 筛选出可搜索的字段
 // 计算属性 - 筛选出可搜索的字段
 const searchConfig = computed(() => {
 const searchConfig = computed(() => {
   let config = props.config.filter((item) => item.search !== false);
   let config = props.config.filter((item) => item.search !== false);

+ 357 - 0
back-ui/src/components/Table/index.vue

@@ -0,0 +1,357 @@
+<template>
+  <div class="table-container">
+    <el-table
+      v-loading="loading"
+      :data="tableData"
+      @selection-change="handleSelectionChange"
+      :stripe="stripe"
+      :border="border"
+      :height="height"
+      :max-height="maxHeight"
+      v-bind="$attrs"
+    >
+      <!-- 多选列 -->
+      <el-table-column
+        v-if="selectionMode === 'multiple'"
+        type="selection"
+        width="55"
+        align="center"
+      />
+
+      <!-- 单选列 -->
+      <el-table-column
+        v-if="selectionMode === 'single'"
+        width="55"
+        align="center"
+      >
+        <template #default="scope">
+          <el-radio
+            v-model="selectedRowKey"
+            :label="scope.row[rowKey]"
+            @change="handleSingleSelection(scope.row)"
+          >
+            &nbsp;
+          </el-radio>
+        </template>
+      </el-table-column>
+
+      <!-- 序号列 -->
+      <el-table-column
+        v-if="showIndex"
+        label="序号"
+        type="index"
+        width="80"
+        align="center"
+      />
+
+      <!-- 动态列 -->
+      <template v-for="column in columns" :key="column.prop || column.label">
+        <el-table-column
+          :label="column.label"
+          :prop="column.prop"
+          :align="column.align || 'center'"
+          :width="column.width"
+          :min-width="column.minWidth"
+          :fixed="column.fixed"
+          :show-overflow-tooltip="column.showOverflowTooltip !== false"
+          :type="column.type === 'index' ? 'index' : undefined"
+        >
+          <template #default="scope">
+            <!-- 序号列 - 使用Element Plus默认序号 -->
+            <template v-if="column.type === 'index'">
+              {{ scope.$index + 1 }}
+            </template>
+
+            <!-- 字典标签 -->
+            <template v-else-if="column.type === 'dict'">
+              <dict-tag
+                :options="column.options"
+                :value="scope.row[column.prop]"
+              />
+            </template>
+
+            <!-- 时间格式化 -->
+            <template v-else-if="column.type === 'time'">
+              <span>{{
+                parseTime(
+                  scope.row[column.prop],
+                  column.format || "{y}-{m}-{d}"
+                )
+              }}</span>
+            </template>
+
+            <!-- 图片 -->
+            <template v-else-if="column.type === 'image'">
+              <el-image
+                :src="scope.row[column.prop]"
+                :preview-src-list="
+                  column.previewList || [scope.row[column.prop]]
+                "
+                :style="{
+                  width: column.width || '50px',
+                  height: column.height || '50px',
+                }"
+                fit="cover"
+                v-if="scope.row[column.prop]"
+              />
+            </template>
+
+            <!-- 状态标签 -->
+            <template v-else-if="column.type === 'status'">
+              <el-tag
+                :type="getStatusTagType(scope.row, column)"
+                :size="column.tagSize || 'default'"
+              >
+                {{ getStatusText(scope.row, column) }}
+              </el-tag>
+            </template>
+
+            <!-- 自定义slot -->
+            <template v-else-if="column.type === 'slot'">
+              <slot :name="column.slotName" :row="scope.row" :column="column" />
+            </template>
+
+            <!-- 普通文本 -->
+            <template v-else>
+              <span :class="column.textClass">{{
+                scope.row[column.prop]
+              }}</span>
+            </template>
+          </template>
+        </el-table-column>
+      </template>
+
+      <!-- 操作列 -->
+      <el-table-column
+        v-if="actions && actions.length > 0"
+        label="操作"
+        align="center"
+        :width="actionWidth"
+        class-name="small-padding fixed-width"
+      >
+        <template #default="scope">
+          <template v-for="action in actions" :key="action.key">
+            <el-button
+              :link="action.link !== false"
+              :type="action.type || 'primary'"
+              :icon="action.icon"
+              :size="action.size || 'small'"
+              :disabled="getActionDisabled(scope.row, action)"
+              @click="handleAction(action, scope.row)"
+              v-hasPermi="action.permission"
+            >
+              {{ action.label }}
+            </el-button>
+            <el-divider
+              v-if="
+                action.showDivider !== false &&
+                action !== actions[actions.length - 1]
+              "
+              direction="vertical"
+            />
+          </template>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 分页 -->
+    <pagination
+      v-if="showPagination"
+      v-show="total > 0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script setup>
+import { ref, computed, watch } from "vue";
+import { parseTime } from "@/utils/ruoyi";
+// import { useDict } from '@/stores/modules/dict' // 不需要,父组件传递
+import Pagination from "@/components/Pagination/index.vue";
+
+const props = defineProps({
+  // 表格数据
+  data: {
+    type: Array,
+    default: () => [],
+  },
+  // 表格列配置
+  columns: {
+    type: Array,
+    default: () => [],
+  },
+  // 操作按钮配置
+  actions: {
+    type: Array,
+    default: () => [],
+  },
+  // 加载状态
+  loading: {
+    type: Boolean,
+    default: false,
+  },
+  // 总数
+  total: {
+    type: Number,
+    default: 0,
+  },
+  // 查询参数
+  queryParams: {
+    type: Object,
+    default: () => ({
+      pageNum: 1,
+      pageSize: 10,
+    }),
+  },
+  // 是否显示多选
+  showSelection: {
+    type: Boolean,
+    default: false,
+  },
+  // 是否显示序号
+  showIndex: {
+    type: Boolean,
+    default: false,
+  },
+  // 是否显示分页
+  showPagination: {
+    type: Boolean,
+    default: true,
+  },
+  // 表格属性
+  stripe: {
+    type: Boolean,
+    default: true,
+  },
+  border: {
+    type: Boolean,
+    default: false,
+  },
+  height: {
+    type: [String, Number],
+    default: null,
+  },
+  maxHeight: {
+    type: [String, Number],
+    default: null,
+  },
+  // 操作列宽度
+  actionWidth: {
+    type: [String, Number],
+    default: "auto",
+  },
+  // 选择模式:'single' | 'multiple' | 'none'
+  selectionMode: {
+    type: String,
+    default: "none",
+    validator: (value) => ["single", "multiple", "none"].includes(value),
+  },
+  // 当前选中的行
+  selectedRows: {
+    type: Array,
+    default: () => [],
+  },
+  // 选择键字段名
+  rowKey: {
+    type: String,
+    default: "id",
+  },
+});
+
+const emit = defineEmits(["selection-change", "action", "getList"]);
+
+// 计算属性
+const tableData = computed(() => props.data);
+
+// 单选相关
+const selectedRowKey = ref(null);
+
+// 监听选中行变化
+watch(
+  () => props.selectedRows,
+  (newRows) => {
+    if (props.selectionMode === "single" && newRows.length > 0) {
+      selectedRowKey.value = newRows[0][props.rowKey];
+    } else if (props.selectionMode === "single" && newRows.length === 0) {
+      selectedRowKey.value = null;
+    }
+  },
+  { immediate: true }
+);
+
+// 单选处理
+const handleSingleSelection = (row) => {
+  emit("selection-change", [row]);
+};
+
+// 多选处理
+const handleSelectionChange = (selection) => {
+  emit("selection-change", selection);
+};
+
+// 执行操作
+const handleAction = (action, row) => {
+  emit("action", action, row);
+};
+
+// 获取操作按钮禁用状态
+const getActionDisabled = (row, action) => {
+  if (typeof action.disabled === "function") {
+    return action.disabled(row);
+  }
+  return action.disabled || false;
+};
+
+// 获取状态标签类型
+const getStatusTagType = (row, column) => {
+  if (typeof column.statusType === "function") {
+    return column.statusType(row);
+  }
+
+  const value = row[column.prop];
+  if (column.statusMap) {
+    return column.statusMap[value]?.type || "info";
+  }
+
+  // 默认状态映射
+  const statusMap = {
+    0: "info",
+    1: "success",
+    2: "warning",
+    3: "danger",
+  };
+  return statusMap[value] || "info";
+};
+
+// 获取状态文本
+const getStatusText = (row, column) => {
+  if (typeof column.statusText === "function") {
+    return column.statusText(row);
+  }
+
+  const value = row[column.prop];
+  if (column.statusMap) {
+    return column.statusMap[value]?.text || value;
+  }
+
+  return value;
+};
+
+// 获取列表数据
+const getList = () => {
+  emit("getList");
+};
+</script>
+
+<style scoped>
+.table-container {
+  width: 100%;
+}
+
+.el-table {
+  width: 100%;
+}
+</style>

+ 1 - 9
back-ui/src/layout/components/Navbar.vue

@@ -8,14 +8,6 @@
       <template v-if="appStore.device !== 'mobile'">
       <template v-if="appStore.device !== 'mobile'">
         <header-search id="header-search" class="right-menu-item" />
         <header-search id="header-search" class="right-menu-item" />
 
 
-        <el-tooltip content="源码地址" effect="dark" placement="bottom">
-          <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
-        </el-tooltip>
-
-        <el-tooltip content="文档地址" effect="dark" placement="bottom">
-          <ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
-        </el-tooltip>
-
         <screenfull id="screenfull" class="right-menu-item hover-effect" />
         <screenfull id="screenfull" class="right-menu-item hover-effect" />
 
 
         <el-tooltip content="主题模式" effect="dark" placement="bottom">
         <el-tooltip content="主题模式" effect="dark" placement="bottom">
@@ -178,7 +170,7 @@ function toggleTheme() {
 
 
         svg {
         svg {
           transition: transform 0.3s;
           transition: transform 0.3s;
-          
+
           &:hover {
           &:hover {
             transform: scale(1.15);
             transform: scale(1.15);
           }
           }

+ 1 - 0
back-ui/src/main.js

@@ -7,6 +7,7 @@ import 'element-plus/dist/index.css'
 import 'element-plus/theme-chalk/dark/css-vars.css'
 import 'element-plus/theme-chalk/dark/css-vars.css'
 import locale from 'element-plus/es/locale/lang/zh-cn'
 import locale from 'element-plus/es/locale/lang/zh-cn'
 
 
+import '@/assets/styles/tailwind.css'
 import '@/assets/styles/index.scss' // global css
 import '@/assets/styles/index.scss' // global css
 
 
 import App from './App'
 import App from './App'

+ 36 - 7
back-ui/src/views/dz/agent/index.vue

@@ -76,7 +76,8 @@
                           <el-table-column label="归属机构" align="center" key="deptName" prop="dept.deptName" :show-overflow-tooltip="true" />
                           <el-table-column label="归属机构" align="center" key="deptName" prop="dept.deptName" :show-overflow-tooltip="true" />
                           <el-table-column label="联系电话" align="center" prop="phonenumber" />
                           <el-table-column label="联系电话" align="center" prop="phonenumber" />
                           <!--      <el-table-column label="上级代理商ID" align="center" prop="parentId" />-->
                           <!--      <el-table-column label="上级代理商ID" align="center" prop="parentId" />-->
-                          <el-table-column label="学校/校区" align="center" prop="schools" />
+<!--                          <el-table-column label="学校/校区" align="center" prop="schools" />-->
+                          <el-table-column label="学校/校区" align="center" prop="schoolName" />
                           <el-table-column label="备注" align="center" prop="remark" />
                           <el-table-column label="备注" align="center" prop="remark" />
                           <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
                           <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
                               <template #default="scope">
                               <template #default="scope">
@@ -95,7 +96,7 @@
     <el-dialog :title="title" v-model="open" width="500px" append-to-body>
     <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 ref="agentRef" :model="form" :rules="rules" label-width="80px">
         <el-form-item label="用户ID" prop="userId">
         <el-form-item label="用户ID" prop="userId">
-          <el-input v-model="form.userId" placeholder="请输入用户ID" />
+          <el-input v-model="form.userId" placeholder="请输入用户ID" disabled/>
         </el-form-item>
         </el-form-item>
           <el-form-item label="代理商" prop="name">
           <el-form-item label="代理商" prop="name">
               <el-input v-model="form.name" placeholder="请输入代理商" />
               <el-input v-model="form.name" placeholder="请输入代理商" />
@@ -117,9 +118,20 @@
             check-strictly
             check-strictly
           />
           />
         </el-form-item>
         </el-form-item>
-        <el-form-item label="负责校区" prop="schools">
-          <el-input v-model="form.schools" placeholder="请输入负责校区" />
-        </el-form-item>
+<!--        <el-form-item label="负责校区" prop="schools">-->
+<!--          <el-input v-model="form.schools" placeholder="请输入负责校区" />-->
+<!--        </el-form-item>-->
+
+          <el-form-item label="关联校区" prop="classIds">
+              <el-select v-model="form.schoolIds" multiple placeholder="请选择校区" style="width: 100%">
+                  <el-option
+                          v-for="item in schoolOptions"
+                          :key="item.id"
+                          :label="item.name"
+                          :value="item.id"
+                  />
+              </el-select>
+          </el-form-item>
         <el-form-item label="备注" prop="remark">
         <el-form-item label="备注" prop="remark">
           <el-input v-model="form.remark" placeholder="请输入备注" />
           <el-input v-model="form.remark" placeholder="请输入备注" />
         </el-form-item>
         </el-form-item>
@@ -140,6 +152,7 @@ import { deptTreeSelect } from "@/api/system/user"
 import useAppStore from '@/store/modules/app'
 import useAppStore from '@/store/modules/app'
 import { Splitpanes, Pane } from "splitpanes"
 import { Splitpanes, Pane } from "splitpanes"
 import "splitpanes/dist/splitpanes.css"
 import "splitpanes/dist/splitpanes.css"
+import { listAllSchool } from "@/api/dz/school"
 
 
 const { proxy } = getCurrentInstance()
 const { proxy } = getCurrentInstance()
 const appStore = useAppStore()
 const appStore = useAppStore()
@@ -155,6 +168,7 @@ const refreshTable = ref(true)
 const deptName = ref("")
 const deptName = ref("")
 const deptOptions = ref(undefined)
 const deptOptions = ref(undefined)
 const enabledDeptOptions = ref(undefined)
 const enabledDeptOptions = ref(undefined)
+const schoolOptions = ref(undefined)
 
 
 const data = reactive({
 const data = reactive({
   form: {},
   form: {},
@@ -164,7 +178,8 @@ const data = reactive({
     deptId: null,
     deptId: null,
     phonenumber: null,
     phonenumber: null,
     parentId: null,
     parentId: null,
-    schools: null,
+    // schools: null,
+    schoolIds: []
   },
   },
   rules: {
   rules: {
   }
   }
@@ -244,7 +259,8 @@ function reset() {
     name: null,
     name: null,
     phonenumber: null,
     phonenumber: null,
     parentId: null,
     parentId: null,
-    schools: null,
+    // schools: null,
+    schoolIds: [],
     remark: null
     remark: null
   }
   }
   proxy.resetForm("agentRef")
   proxy.resetForm("agentRef")
@@ -271,6 +287,8 @@ function resetQuery() {
 function handleAdd(row) {
 function handleAdd(row) {
   reset()
   reset()
   getTreeselect()
   getTreeselect()
+  //处理学校
+  getSchools(row)
   if (row != null && row.agentId) {
   if (row != null && row.agentId) {
     form.value.parentId = row.agentId
     form.value.parentId = row.agentId
   } else {
   } else {
@@ -298,11 +316,22 @@ async function handleUpdate(row) {
   }
   }
   getAgent(row.agentId).then(response => {
   getAgent(row.agentId).then(response => {
     form.value = response.data
     form.value = response.data
+    //处理学校
+    getSchools(row)
+
     open.value = true
     open.value = true
     title.value = "修改机构代理"
     title.value = "修改机构代理"
   })
   })
 }
 }
 
 
+function getSchools(row){
+    //处理学校
+    const deptId = row.deptId;
+    listAllSchool(deptId).then(response => {
+        schoolOptions.value= response.data
+    })
+}
+
 /** 提交按钮 */
 /** 提交按钮 */
 function submitForm() {
 function submitForm() {
   proxy.$refs["agentRef"].validate(valid => {
   proxy.$refs["agentRef"].validate(valid => {

+ 157 - 0
back-ui/src/views/dz/cards/components/ApplyCardDialog.vue

@@ -0,0 +1,157 @@
+<template>
+  <el-dialog
+    title="申请开卡"
+    v-model="visible"
+    width="500px"
+    append-to-body
+    align-center
+    :center="true"
+  >
+    <div class="apply-card-content">
+      <el-form
+        ref="applyCardFormRef"
+        :model="form"
+        :rules="rules"
+        label-width="100px"
+      >
+        <!-- 卡号段 -->
+        <el-form-item label="卡号段" prop="cardRange" :required="true">
+          <div style="display: flex; align-items: center; gap: 10px">
+            <el-input
+              v-model="form.beginCardNo"
+              placeholder="开始卡号"
+              style="flex: 1"
+            />
+            <span>-</span>
+            <el-input
+              v-model="form.endCardNo"
+              placeholder="结束卡号"
+              style="flex: 1"
+            />
+          </div>
+        </el-form-item>
+
+        <!-- 学校 -->
+        <el-form-item label="学校" prop="schoolId">
+          <el-select
+            v-model="form.schoolId"
+            placeholder="请选择学校"
+            style="width: 100%"
+          >
+            <el-option
+              v-for="school in schoolList"
+              :key="school.id"
+              :label="school.name"
+              :value="school.id"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+      </el-form>
+    </div>
+
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="handleCancel">取消</el-button>
+        <el-button type="primary" @click="handleSubmit">
+          <svg-icon
+            icon-class="lightning"
+            class="mr-1"
+            style="font-size: 14px"
+          />
+          提交
+        </el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { ref, computed, watch } from "vue";
+
+const props = defineProps({
+  modelValue: {
+    type: Boolean,
+    default: false,
+  },
+  schoolList: {
+    type: Array,
+    default: () => [],
+  },
+});
+
+const emit = defineEmits(["update:modelValue", "confirm"]);
+
+const visible = computed({
+  get: () => props.modelValue,
+  set: (value) => emit("update:modelValue", value),
+});
+
+const applyCardFormRef = ref();
+
+const form = ref({
+  beginCardNo: "",
+  endCardNo: "",
+  schoolId: null,
+});
+
+const rules = {
+  beginCardNo: [
+    { required: true, message: "开始卡号不能为空", trigger: "blur" },
+  ],
+  endCardNo: [{ required: true, message: "结束卡号不能为空", trigger: "blur" }],
+};
+
+// 重置表单
+function resetForm() {
+  form.value = {
+    beginCardNo: "",
+    endCardNo: "",
+    schoolId: null,
+  };
+}
+
+// 取消
+function handleCancel() {
+  visible.value = false;
+  resetForm();
+}
+
+// 提交申请
+async function handleSubmit() {
+  applyCardFormRef.value.validate(async (valid) => {
+    if (valid) {
+      try {
+        const data = {
+          beginCardNo: form.value.beginCardNo,
+          endCardNo: form.value.endCardNo,
+          schoolId: form.value.schoolId,
+        };
+
+        emit("confirm", data);
+        visible.value = false;
+        resetForm();
+      } catch (error) {
+        console.error("申请开卡失败:", error);
+        throw error;
+      }
+    }
+  });
+}
+
+// 监听弹窗关闭,重置表单
+watch(visible, (newVal) => {
+  if (!newVal) {
+    resetForm();
+  }
+});
+</script>
+
+<style scoped>
+.apply-card-content {
+  padding: 20px 0;
+}
+
+.dialog-footer {
+  text-align: right;
+}
+</style>

+ 237 - 0
back-ui/src/views/dz/cards/components/AssignCardDialog.vue

@@ -0,0 +1,237 @@
+<template>
+  <el-dialog
+    title="分配卡"
+    v-model="visible"
+    width="500px"
+    append-to-body
+    align-center
+    :center="true"
+  >
+    <el-form
+      ref="assignCardFormRef"
+      :model="form"
+      :rules="rules"
+      label-width="100px"
+    >
+      <!-- 卡类型 -->
+      <el-form-item label="卡类型" prop="cardType" :required="true">
+        <el-select
+          v-model="form.cardType"
+          placeholder="请选择卡类型"
+          style="width: 100%"
+        >
+          <el-option
+            v-for="dict in cardTypeOptions"
+            :key="dict.value"
+            :label="dict.label"
+            :value="parseInt(dict.value)"
+          ></el-option>
+        </el-select>
+      </el-form-item>
+
+      <!-- 卡号段 -->
+      <el-form-item label="卡号段" prop="cardRange" :required="true">
+        <div style="display: flex; align-items: center; gap: 10px">
+          <el-input
+            v-model="form.beginCardNo"
+            placeholder="开始卡号"
+            style="flex: 1"
+          />
+          <span>-</span>
+          <el-input
+            v-model="form.endCardNo"
+            placeholder="结束卡号"
+            style="flex: 1"
+          />
+        </div>
+      </el-form-item>
+
+      <!-- 代理商 -->
+      <el-form-item label="代理商" prop="agentId" :required="true">
+        <el-select
+          v-model="form.agentId"
+          placeholder="请选择代理商"
+          style="width: 100%"
+        >
+          <el-option
+            v-for="agent in agentList"
+            :key="agent.id"
+            :label="agent.name"
+            :value="agent.id"
+          ></el-option>
+        </el-select>
+      </el-form-item>
+
+      <!-- 省份 -->
+      <el-form-item label="省份" prop="province">
+        <el-select
+          v-model="form.province"
+          placeholder="请选择省份"
+          style="width: 100%"
+        >
+          <el-option label="全部" value="all"></el-option>
+          <el-option label="湖南" value="hunan"></el-option>
+          <el-option label="广东" value="guangdong"></el-option>
+          <el-option label="北京" value="beijing"></el-option>
+          <el-option label="上海" value="shanghai"></el-option>
+        </el-select>
+      </el-form-item>
+
+      <!-- 学校 -->
+      <el-form-item label="学校" prop="school">
+        <el-select
+          v-model="form.school"
+          placeholder="请选择学校"
+          style="width: 100%"
+        >
+          <el-option label="全部" value="all"></el-option>
+          <el-option
+            v-for="school in schoolList"
+            :key="school.id"
+            :label="school.name"
+            :value="school.id"
+          ></el-option>
+        </el-select>
+      </el-form-item>
+
+      <!-- 考生类别 -->
+      <el-form-item label="考生类别" prop="studentCategory">
+        <el-select
+          v-model="form.studentCategory"
+          placeholder="请选择考生类别"
+          style="width: 100%"
+        >
+          <el-option label="全部" value="all"></el-option>
+          <el-option label="普通考生" value="normal"></el-option>
+          <el-option label="艺术考生" value="art"></el-option>
+          <el-option label="体育考生" value="sports"></el-option>
+        </el-select>
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="handleCancel">取消</el-button>
+        <el-button type="primary" @click="handleSubmit">分配</el-button>
+        <el-button @click="handleReassign">重新分配</el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { ref, computed, watch } from "vue";
+import { assignCard } from "@/api/dz/cards";
+
+const props = defineProps({
+  modelValue: {
+    type: Boolean,
+    default: false,
+  },
+  agentList: {
+    type: Array,
+    default: () => [],
+  },
+  schoolList: {
+    type: Array,
+    default: () => [],
+  },
+  cardTypeOptions: {
+    type: Array,
+    default: () => [],
+  },
+});
+
+const emit = defineEmits(["update:modelValue", "success"]);
+
+const visible = computed({
+  get: () => props.modelValue,
+  set: (value) => emit("update:modelValue", value),
+});
+
+const assignCardFormRef = ref();
+
+const form = ref({
+  cardType: null,
+  beginCardNo: "",
+  endCardNo: "",
+  agentId: null,
+  province: "all",
+  school: "all",
+  studentCategory: "all",
+});
+
+const rules = {
+  cardType: [{ required: true, message: "卡类型不能为空", trigger: "change" }],
+  beginCardNo: [
+    { required: true, message: "开始卡号不能为空", trigger: "blur" },
+  ],
+  endCardNo: [{ required: true, message: "结束卡号不能为空", trigger: "blur" }],
+  agentId: [{ required: true, message: "代理商不能为空", trigger: "change" }],
+};
+
+// 重置表单
+function resetForm() {
+  form.value = {
+    cardType: null,
+    beginCardNo: "",
+    endCardNo: "",
+    agentId: null,
+    province: "all",
+    school: "all",
+    studentCategory: "all",
+  };
+}
+
+// 取消
+function handleCancel() {
+  visible.value = false;
+  resetForm();
+}
+
+// 提交
+async function handleSubmit() {
+  assignCardFormRef.value.validate(async (valid) => {
+    if (valid) {
+      try {
+        // 获取开始号和结束号
+        const begin = form.value.beginCardNo;
+        const end = form.value.endCardNo;
+
+        if (!begin || !end) {
+          throw new Error("请填写完整的卡号段");
+        }
+
+        // 调用分配卡API
+        await assignCard(form.value.agentId, begin, end);
+
+        emit("success", "分配卡成功!");
+        visible.value = false;
+        resetForm();
+      } catch (error) {
+        console.error("分配卡失败:", error);
+        throw error;
+      }
+    }
+  });
+}
+
+// 重新分配
+function handleReassign() {
+  resetForm();
+  emit("success", "已重置分配表单,请重新填写");
+}
+
+// 监听弹窗关闭,重置表单
+watch(visible, (newVal) => {
+  if (!newVal) {
+    resetForm();
+  }
+});
+</script>
+
+<style scoped>
+.dialog-footer {
+  text-align: right;
+}
+</style>

+ 166 - 0
back-ui/src/views/dz/cards/components/AssociateCampusDialog.vue

@@ -0,0 +1,166 @@
+<template>
+  <el-dialog
+    title="关联校区"
+    v-model="visible"
+    width="500px"
+    append-to-body
+    align-center
+    :center="true"
+  >
+    <div class="associate-campus-content">
+      <el-form
+        ref="associateCampusFormRef"
+        :model="form"
+        :rules="rules"
+        label-width="100px"
+      >
+        <!-- 卡号段 -->
+        <el-form-item label="卡号段" prop="cardRange" :required="true">
+          <div style="display: flex; align-items: center; gap: 10px">
+            <el-input
+              v-model="form.beginCardNo"
+              placeholder="开始卡号"
+              style="flex: 1"
+            />
+            <span>-</span>
+            <el-input
+              v-model="form.endCardNo"
+              placeholder="结束卡号"
+              style="flex: 1"
+            />
+          </div>
+        </el-form-item>
+
+        <!-- 校区 -->
+        <el-form-item label="校区" prop="campusId" :required="true">
+          <el-select
+            v-model="form.campusId"
+            placeholder="请选择校区"
+            style="width: 100%"
+          >
+            <el-option label="全部" value="all"></el-option>
+            <el-option
+              v-for="campus in campusList"
+              :key="campus.id"
+              :label="campus.name"
+              :value="campus.id"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+      </el-form>
+    </div>
+
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="handleCancel">取消</el-button>
+        <el-button type="primary" @click="handleConfirm">
+          <svg-icon
+            icon-class="lightning"
+            class="mr-1"
+            style="font-size: 14px"
+          />
+          确认
+        </el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { ref, computed, watch } from "vue";
+
+const props = defineProps({
+  modelValue: {
+    type: Boolean,
+    default: false,
+  },
+  campusList: {
+    type: Array,
+    default: () => [],
+  },
+});
+
+const emit = defineEmits(["update:modelValue", "confirm"]);
+
+const visible = computed({
+  get: () => props.modelValue,
+  set: (value) => emit("update:modelValue", value),
+});
+
+const associateCampusFormRef = ref();
+
+const form = ref({
+  beginCardNo: "",
+  endCardNo: "",
+  campusId: null,
+});
+
+const rules = {
+  beginCardNo: [
+    { required: true, message: "开始卡号不能为空", trigger: "blur" },
+  ],
+  endCardNo: [{ required: true, message: "结束卡号不能为空", trigger: "blur" }],
+  campusId: [{ required: true, message: "校区不能为空", trigger: "change" }],
+};
+
+// 重置表单
+function resetForm() {
+  form.value = {
+    beginCardNo: "",
+    endCardNo: "",
+    campusId: null,
+  };
+}
+
+// 取消
+function handleCancel() {
+  visible.value = false;
+  resetForm();
+}
+
+// 确认关联
+async function handleConfirm() {
+  associateCampusFormRef.value.validate(async (valid) => {
+    if (valid) {
+      try {
+        const data = {
+          beginCardNo: form.value.beginCardNo,
+          endCardNo: form.value.endCardNo,
+          campusId: form.value.campusId,
+        };
+
+        emit("confirm", data);
+        visible.value = false;
+        resetForm();
+      } catch (error) {
+        console.error("关联校区失败:", error);
+        throw error;
+      }
+    }
+  });
+}
+
+// 监听弹窗关闭,重置表单
+watch(visible, (newVal) => {
+  if (!newVal) {
+    resetForm();
+  }
+});
+</script>
+
+<style scoped>
+.associate-campus-content {
+  padding: 20px 0;
+}
+
+.hint-text {
+  color: #1890ff;
+  font-size: 12px;
+  margin-bottom: 20px;
+  padding-left: 100px;
+}
+
+.dialog-footer {
+  text-align: right;
+}
+</style>

+ 225 - 0
back-ui/src/views/dz/cards/components/CardGenerationDialog.vue

@@ -0,0 +1,225 @@
+<template>
+  <el-dialog
+    title="制卡"
+    v-model="visible"
+    width="500px"
+    append-to-body
+    align-center
+    :center="true"
+  >
+    <el-form
+      ref="cardGenerationFormRef"
+      :model="form"
+      :rules="rules"
+      label-width="100px"
+    >
+      <!-- 机构 -->
+      <el-form-item label="机构" prop="institutionId" :required="true">
+        <el-select
+          v-model="form.institutionId"
+          placeholder="请选择机构"
+          style="width: 100%"
+        >
+          <el-option
+            v-for="institution in institutionList"
+            :key="institution.deptId"
+            :label="institution.deptName"
+            :value="institution.deptId"
+          ></el-option>
+        </el-select>
+      </el-form-item>
+
+      <!-- 卡类型 -->
+      <el-form-item label="卡类型" prop="type" :required="true">
+        <el-select
+          v-model="form.type"
+          placeholder="请选择卡类型"
+          style="width: 100%"
+        >
+          <el-option
+            v-for="dict in cardTypeOptions"
+            :key="dict.value"
+            :label="dict.label"
+            :value="parseInt(dict.value)"
+          ></el-option>
+        </el-select>
+      </el-form-item>
+
+      <!-- 省份 -->
+      <el-form-item label="省份">
+        <el-select
+          v-model="form.province"
+          placeholder="请选择省份"
+          style="width: 100%"
+        >
+          <el-option label="全部" value="all"></el-option>
+          <el-option label="湖南" value="hunan"></el-option>
+          <el-option label="广东" value="guangdong"></el-option>
+          <el-option label="北京" value="beijing"></el-option>
+          <el-option label="上海" value="shanghai"></el-option>
+        </el-select>
+      </el-form-item>
+
+      <!-- 学校 -->
+      <el-form-item label="学校">
+        <el-select
+          v-model="form.school"
+          placeholder="请选择学校"
+          style="width: 100%"
+        >
+          <el-option label="全部" value="all"></el-option>
+          <el-option
+            v-for="school in schoolList"
+            :key="school.id"
+            :label="school.name"
+            :value="school.id"
+          ></el-option>
+        </el-select>
+      </el-form-item>
+
+      <!-- 卡数量 -->
+      <el-form-item label="卡数量" prop="cardQuantity" :required="true">
+        <el-input-number
+          v-model="form.cardQuantity"
+          :min="1"
+          :max="1000"
+          placeholder="请输入卡数量"
+          style="width: 100%"
+        />
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="handleCancel">取消</el-button>
+        <el-button type="primary" @click="handleSubmit">开始制卡</el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { ref, computed, watch } from "vue";
+import { issueCard } from "@/api/dz/cards";
+
+const props = defineProps({
+  modelValue: {
+    type: Boolean,
+    default: false,
+  },
+  institutionList: {
+    type: Array,
+    default: () => [],
+  },
+  schoolList: {
+    type: Array,
+    default: () => [],
+  },
+  cardTypeOptions: {
+    type: Array,
+    default: () => [],
+  },
+});
+
+const emit = defineEmits(["update:modelValue", "success"]);
+
+const visible = computed({
+  get: () => props.modelValue,
+  set: (value) => emit("update:modelValue", value),
+});
+
+const cardGenerationFormRef = ref();
+
+const form = ref({
+  institutionId: null,
+  type: null,
+  province: "all",
+  school: "all",
+  cardQuantity: 1,
+});
+
+const rules = {
+  institutionId: [
+    { required: true, message: "机构不能为空", trigger: "change" },
+  ],
+  type: [{ required: true, message: "卡类型不能为空", trigger: "change" }],
+  cardQuantity: [
+    { required: true, message: "卡数量不能为空", trigger: "blur" },
+    {
+      type: "number",
+      min: 1,
+      max: 1000,
+      message: "请输入正确的卡数量",
+      trigger: "blur",
+    },
+  ],
+};
+
+// 获取卡类型枚举
+function getCardTypeEnum(typeValue) {
+  const cardTypeMap = {
+    6: "Platform",
+    2: "Dept",
+    7: "ECard",
+    8: "Test",
+  };
+  return cardTypeMap[typeValue] || "ECard"; // 默认返回电子卡
+}
+
+// 重置表单
+function resetForm() {
+  form.value = {
+    institutionId: null,
+    type: null,
+    province: "all",
+    school: "all",
+    cardQuantity: 1,
+  };
+}
+
+// 取消
+function handleCancel() {
+  visible.value = false;
+  resetForm();
+}
+
+// 提交
+async function handleSubmit() {
+  cardGenerationFormRef.value.validate(async (valid) => {
+    if (valid) {
+      try {
+        const cardData = {
+          institutionId: form.value.institutionId,
+          type: form.value.type,
+          count: parseInt(form.value.cardQuantity),
+        };
+        await issueCard(
+          cardData.institutionId,
+          getCardTypeEnum(cardData.type),
+          cardData.count
+        );
+
+        emit("success", "制卡成功!");
+        visible.value = false;
+        resetForm();
+      } catch (error) {
+        console.error("制卡失败:", error);
+        throw error;
+      }
+    }
+  });
+}
+
+// 监听弹窗关闭,重置表单
+watch(visible, (newVal) => {
+  if (!newVal) {
+    resetForm();
+  }
+});
+</script>
+
+<style scoped>
+.dialog-footer {
+  text-align: right;
+}
+</style>

+ 91 - 0
back-ui/src/views/dz/cards/components/CloseCardDialog.vue

@@ -0,0 +1,91 @@
+<template>
+  <el-dialog
+    title="关卡"
+    v-model="visible"
+    width="400px"
+    append-to-body
+    align-center
+    :center="true"
+  >
+    <div class="close-card-confirm-content">
+      <div class="confirm-item">
+        <el-icon class="warning-icon">
+          <Warning />
+        </el-icon>
+        <span class="confirm-text">
+          是否确认关卡vip卡编号为{{ cardNo }}的数据项?
+        </span>
+      </div>
+    </div>
+
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="handleCancel">取消</el-button>
+        <el-button type="primary" @click="handleConfirm">确定</el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { ref, computed } from "vue";
+import { Warning } from "@element-plus/icons-vue";
+
+const props = defineProps({
+  modelValue: {
+    type: Boolean,
+    default: false,
+  },
+  cardNo: {
+    type: [String, Number],
+    default: "",
+  },
+});
+
+const emit = defineEmits(["update:modelValue", "confirm"]);
+
+const visible = computed({
+  get: () => props.modelValue,
+  set: (value) => emit("update:modelValue", value),
+});
+
+// 取消
+function handleCancel() {
+  visible.value = false;
+}
+
+// 确认关卡
+function handleConfirm() {
+  emit("confirm", props.cardNo);
+  visible.value = false;
+}
+</script>
+
+<style scoped>
+.close-card-confirm-content {
+  padding: 20px 0;
+}
+
+.confirm-item {
+  display: flex;
+  align-items: flex-start;
+  gap: 12px;
+}
+
+.warning-icon {
+  color: #e6a23c;
+  font-size: 20px;
+  margin-top: 2px;
+  flex-shrink: 0;
+}
+
+.confirm-text {
+  font-size: 14px;
+  line-height: 1.5;
+  color: #ffffff;
+}
+
+.dialog-footer {
+  text-align: right;
+}
+</style>

+ 201 - 0
back-ui/src/views/dz/cards/components/EditStudentDialog.vue

@@ -0,0 +1,201 @@
+<template>
+  <el-dialog title="编辑" v-model="visible" width="500px" append-to-body>
+    <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
+      <!-- 学校 -->
+      <el-form-item label="学校" prop="schoolId">
+        <el-select
+          v-model="form.schoolId"
+          placeholder="请选择学校"
+          style="width: 100%"
+        >
+          <el-option
+            v-for="school in schoolList"
+            :key="school.id"
+            :label="school.name"
+            :value="school.id"
+          ></el-option>
+        </el-select>
+      </el-form-item>
+
+      <!-- 班级 -->
+      <el-form-item label="班级" prop="classId">
+        <el-select
+          v-model="form.classId"
+          placeholder="请选择班级"
+          style="width: 100%"
+        >
+          <el-option
+            v-for="classItem in classList"
+            :key="classItem.id"
+            :label="classItem.name"
+            :value="classItem.id"
+          ></el-option>
+        </el-select>
+      </el-form-item>
+
+      <!-- 姓名 -->
+      <el-form-item label="姓名" prop="nickName">
+        <el-input v-model="form.nickName" placeholder="请输入姓名" />
+      </el-form-item>
+
+      <!-- 手机号 -->
+      <el-form-item label="手机号" prop="phone">
+        <el-input v-model="form.phone" placeholder="请输入手机号" />
+      </el-form-item>
+
+      <!-- 语数英 -->
+      <el-form-item label="语数英" prop="chineseMathEnglish">
+        <el-input
+          v-model="form.chineseMathEnglish"
+          placeholder="请输入语数英成绩"
+        />
+      </el-form-item>
+
+      <!-- 职业技能 -->
+      <el-form-item label="职业技能" prop="vocationalSkills">
+        <el-input
+          v-model="form.vocationalSkills"
+          placeholder="请输入职业技能成绩"
+        />
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button type="primary" @click="handleSubmit">保 存</el-button>
+        <el-button @click="handleCancel">取 消</el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { ref, computed, watch } from "vue";
+import { getCards, addCards, updateCards } from "@/api/dz/cards";
+
+const props = defineProps({
+  modelValue: {
+    type: Boolean,
+    default: false,
+  },
+  cardId: {
+    type: [String, Number],
+    default: null,
+  },
+  schoolList: {
+    type: Array,
+    default: () => [],
+  },
+  classList: {
+    type: Array,
+    default: () => [],
+  },
+});
+
+const emit = defineEmits(["update:modelValue", "success"]);
+
+const visible = computed({
+  get: () => props.modelValue,
+  set: (value) => emit("update:modelValue", value),
+});
+
+const formRef = ref();
+
+const form = ref({
+  cardId: null,
+  schoolId: null,
+  classId: null,
+  nickName: "",
+  phone: "",
+  chineseMathEnglish: "",
+  vocationalSkills: "",
+});
+
+const rules = {
+  schoolId: [{ required: true, message: "学校不能为空", trigger: "change" }],
+  classId: [{ required: true, message: "班级不能为空", trigger: "change" }],
+  nickName: [{ required: true, message: "姓名不能为空", trigger: "blur" }],
+  phone: [
+    { required: true, message: "手机号不能为空", trigger: "blur" },
+    {
+      pattern: /^1[3-9]\d{9}$/,
+      message: "请输入正确的手机号",
+      trigger: "blur",
+    },
+  ],
+  chineseMathEnglish: [
+    { required: true, message: "语数英成绩不能为空", trigger: "blur" },
+  ],
+  vocationalSkills: [
+    { required: true, message: "职业技能成绩不能为空", trigger: "blur" },
+  ],
+};
+
+// 重置表单
+function resetForm() {
+  form.value = {
+    cardId: null,
+    schoolId: null,
+    classId: null,
+    nickName: "",
+    phone: "",
+    chineseMathEnglish: "",
+    vocationalSkills: "",
+  };
+}
+
+// 取消
+function handleCancel() {
+  visible.value = false;
+  resetForm();
+}
+
+// 提交
+async function handleSubmit() {
+  formRef.value.validate(async (valid) => {
+    if (valid) {
+      try {
+        if (form.value.cardId != null) {
+          await updateCards(form.value);
+        } else {
+          await addCards(form.value);
+        }
+
+        emit("success", "保存成功!");
+        visible.value = false;
+        resetForm();
+      } catch (error) {
+        console.error("保存失败:", error);
+        throw error;
+      }
+    }
+  });
+}
+
+// 获取卡片数据
+async function fetchCardData() {
+  if (props.cardId) {
+    try {
+      const response = await getCards(props.cardId);
+      form.value = response.data;
+    } catch (error) {
+      console.error("获取卡片数据失败:", error);
+    }
+  }
+}
+
+// 监听弹窗打开,获取数据
+watch(visible, (newVal) => {
+  if (newVal && props.cardId) {
+    fetchCardData();
+  } else if (!newVal) {
+    resetForm();
+  }
+});
+</script>
+
+<style scoped>
+.dialog-footer {
+  text-align: right;
+}
+</style>

+ 91 - 0
back-ui/src/views/dz/cards/components/PaymentDialog.vue

@@ -0,0 +1,91 @@
+<template>
+  <el-dialog
+    title="缴费"
+    v-model="visible"
+    width="400px"
+    append-to-body
+    align-center
+    :center="true"
+  >
+    <div class="payment-confirm-content">
+      <div class="confirm-item">
+        <el-icon class="warning-icon">
+          <Warning />
+        </el-icon>
+        <span class="confirm-text">
+          是否确认缴费vip卡编号为{{ cardNo }}的数据项?
+        </span>
+      </div>
+    </div>
+
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="handleCancel">取消</el-button>
+        <el-button type="primary" @click="handleConfirm">确定</el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { ref, computed } from "vue";
+import { Warning } from "@element-plus/icons-vue";
+
+const props = defineProps({
+  modelValue: {
+    type: Boolean,
+    default: false,
+  },
+  cardNo: {
+    type: [String, Number],
+    default: "",
+  },
+});
+
+const emit = defineEmits(["update:modelValue", "confirm"]);
+
+const visible = computed({
+  get: () => props.modelValue,
+  set: (value) => emit("update:modelValue", value),
+});
+
+// 取消
+function handleCancel() {
+  visible.value = false;
+}
+
+// 确认缴费
+function handleConfirm() {
+  emit("confirm", props.cardNo);
+  visible.value = false;
+}
+</script>
+
+<style scoped>
+.payment-confirm-content {
+  padding: 20px 0;
+}
+
+.confirm-item {
+  display: flex;
+  align-items: flex-start;
+  gap: 12px;
+}
+
+.warning-icon {
+  color: #e6a23c;
+  font-size: 20px;
+  margin-top: 2px;
+  flex-shrink: 0;
+}
+
+.confirm-text {
+  font-size: 14px;
+  line-height: 1.5;
+  color: #ffffff;
+}
+
+.dialog-footer {
+  text-align: right;
+}
+</style>

+ 91 - 0
back-ui/src/views/dz/cards/components/RefundDialog.vue

@@ -0,0 +1,91 @@
+<template>
+  <el-dialog
+    title="退费"
+    v-model="visible"
+    width="400px"
+    append-to-body
+    align-center
+    :center="true"
+  >
+    <div class="refund-confirm-content">
+      <div class="confirm-item">
+        <el-icon class="warning-icon">
+          <Warning />
+        </el-icon>
+        <span class="confirm-text">
+          是否确认退费vip卡编号为{{ cardNo }}的数据项?
+        </span>
+      </div>
+    </div>
+
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="handleCancel">取消</el-button>
+        <el-button type="primary" @click="handleConfirm">确定</el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { ref, computed } from "vue";
+import { Warning } from "@element-plus/icons-vue";
+
+const props = defineProps({
+  modelValue: {
+    type: Boolean,
+    default: false,
+  },
+  cardNo: {
+    type: [String, Number],
+    default: "",
+  },
+});
+
+const emit = defineEmits(["update:modelValue", "confirm"]);
+
+const visible = computed({
+  get: () => props.modelValue,
+  set: (value) => emit("update:modelValue", value),
+});
+
+// 取消
+function handleCancel() {
+  visible.value = false;
+}
+
+// 确认退费
+function handleConfirm() {
+  emit("confirm", props.cardNo);
+  visible.value = false;
+}
+</script>
+
+<style scoped>
+.refund-confirm-content {
+  padding: 20px 0;
+}
+
+.confirm-item {
+  display: flex;
+  align-items: flex-start;
+  gap: 12px;
+}
+
+.warning-icon {
+  color: #e6a23c;
+  font-size: 20px;
+  margin-top: 2px;
+  flex-shrink: 0;
+}
+
+.confirm-text {
+  font-size: 14px;
+  line-height: 1.5;
+  color: #ffffff;
+}
+
+.dialog-footer {
+  text-align: right;
+}
+</style>

+ 91 - 0
back-ui/src/views/dz/cards/components/ReopenCardDialog.vue

@@ -0,0 +1,91 @@
+<template>
+  <el-dialog
+    title="重开"
+    v-model="visible"
+    width="400px"
+    append-to-body
+    align-center
+    :center="true"
+  >
+    <div class="reopen-card-confirm-content">
+      <div class="confirm-item">
+        <el-icon class="warning-icon">
+          <Warning />
+        </el-icon>
+        <span class="confirm-text">
+          是否确认重开VIP卡编号为{{ cardNo }}的数据项?
+        </span>
+      </div>
+    </div>
+
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="handleCancel">取消</el-button>
+        <el-button type="primary" @click="handleConfirm">确定</el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { ref, computed } from "vue";
+import { Warning } from "@element-plus/icons-vue";
+
+const props = defineProps({
+  modelValue: {
+    type: Boolean,
+    default: false,
+  },
+  cardNo: {
+    type: [String, Number],
+    default: "",
+  },
+});
+
+const emit = defineEmits(["update:modelValue", "confirm"]);
+
+const visible = computed({
+  get: () => props.modelValue,
+  set: (value) => emit("update:modelValue", value),
+});
+
+// 取消
+function handleCancel() {
+  visible.value = false;
+}
+
+// 确认重开
+function handleConfirm() {
+  emit("confirm", props.cardNo);
+  visible.value = false;
+}
+</script>
+
+<style scoped>
+.reopen-card-confirm-content {
+  padding: 20px 0;
+}
+
+.confirm-item {
+  display: flex;
+  align-items: flex-start;
+  gap: 12px;
+}
+
+.warning-icon {
+  color: #e6a23c;
+  font-size: 20px;
+  margin-top: 2px;
+  flex-shrink: 0;
+}
+
+.confirm-text {
+  font-size: 14px;
+  line-height: 1.5;
+  color: #ffffff;
+}
+
+.dialog-footer {
+  text-align: right;
+}
+</style>

+ 222 - 136
back-ui/src/views/dz/cards/config/form.js

@@ -1,206 +1,292 @@
 const info = [
 const info = [
+  // 第一行
   {
   {
-    label: '省市区',
-    name: 'areaIds',
+    label: "省市区",
+    name: "areaIds",
     value: [],
     value: [],
-    type: 'slot',
-    slotName: 'areaSelect',
+    type: "slot",
+    slotName: "areaSelect",
     search: true,
     search: true,
   },
   },
   {
   {
-    label: '分配学校',
-    name: 'assignSchoolId',
-    value: '',
-    type: 'select',
+    label: "分配学校",
+    name: "assignSchoolId",
+    value: "",
+    type: "select",
     option: [],
     option: [],
-    optionLabel: 'name',
-    optionValue: 'id',
+    optionLabel: "name",
+    optionValue: "id",
     search: true,
     search: true,
   },
   },
   {
   {
-    label: '卡状态',
-    name: 'status',
-    value: '',
-    type: 'select',
+    label: "注册学校",
+    name: "registerSchoolId",
+    value: "",
+    type: "select",
     option: [],
     option: [],
-    optionLabel: 'label',
-    optionValue: 'value',
+    optionLabel: "name",
+    optionValue: "id",
     search: true,
     search: true,
   },
   },
   {
   {
-    label: '分配状态',
-    name: 'distributeStatus',
-    value: '',
-    type: 'select',
+    label: "校区",
+    name: "campusId",
+    value: "",
+    type: "select",
     option: [],
     option: [],
-    optionLabel: 'label',
-    optionValue: 'value',
+    optionLabel: "name",
+    optionValue: "id",
     search: true,
     search: true,
   },
   },
   {
   {
-    label: '过期状态',
-    name: 'timeStatus',
-    value: '',
-    type: 'select',
+    label: "代理商",
+    name: "agentId",
+    value: "",
+    type: "select",
     option: [],
     option: [],
-    optionLabel: 'label',
-    optionValue: 'value',
+    optionLabel: "name",
+    optionValue: "id",
     search: true,
     search: true,
   },
   },
+
+  // 第二行
   {
   {
-    label: '缴费状态',
-    name: 'payStatus',
-    value: '',
-    type: 'select',
-    option: [],
-    optionLabel: 'label',
-    optionValue: 'value',
+    label: "账号",
+    name: "cardNo",
+    value: "",
+    type: "text",
     search: true,
     search: true,
   },
   },
   {
   {
-    label: '是否结算',
-    name: 'isSettlement',
-    value: '',
-    type: 'select',
-    option: [],
-    optionLabel: 'label',
-    optionValue: 'value',
+    label: "初始密码",
+    name: "password",
+    value: "",
+    type: "text",
     search: true,
     search: true,
   },
   },
   {
   {
-    label: '一级代理商ID',
-    name: 'agentId',
-    value: '',
-    type: 'text',
+    label: "卡号段",
+    name: "cardNoRange",
+    value: "",
+    type: "text",
     search: true,
     search: true,
+    placeholder: "开始卡号-结束卡号",
   },
   },
   {
   {
-    label: '末级代理商ID',
-    name: 'leftAgentId',
-    value: '',
-    type: 'text',
+    label: "卡类型",
+    name: "type",
+    value: "",
+    type: "select",
+    option: [],
+    optionLabel: "label",
+    optionValue: "value",
     search: true,
     search: true,
   },
   },
   {
   {
-    label: '安排校区',
-    name: 'campusId',
-    value: '',
-    type: 'text',
+    label: "分配考生类别",
+    name: "studentCategory",
+    value: "",
+    type: "select",
+    option: [],
+    optionLabel: "label",
+    optionValue: "value",
     search: true,
     search: true,
   },
   },
+
+  // 第三行
   {
   {
-    label: '分配学校',
-    name: 'assignSchoolId',
-    value: '',
-    type: 'text',
+    label: "分配状态",
+    name: "distributeStatus",
+    value: "",
+    type: "select",
+    option: [],
+    optionLabel: "label",
+    optionValue: "value",
     search: true,
     search: true,
   },
   },
   {
   {
-    label: '校区id',
-    name: 'schoolId',
-    value: '',
-    type: 'text',
+    label: "使用状态",
+    name: "status",
+    value: "",
+    type: "select",
+    option: [],
+    optionLabel: "label",
+    optionValue: "value",
     search: true,
     search: true,
   },
   },
   {
   {
-    label: '校区班级ID',
-    name: 'classesId',
-    value: '',
-    type: 'text',
+    label: "过期状态",
+    name: "timeStatus",
+    value: "",
+    type: "select",
+    option: [],
+    optionLabel: "label",
+    optionValue: "value",
     search: true,
     search: true,
   },
   },
   {
   {
-    label: '班级/入学年份',
-    name: 'year',
-    value: '',
-    type: 'text',
+    label: "结束状态",
+    name: "isSettlement",
+    value: "",
+    type: "select",
+    option: [
+      { label: "是", value: 1 },
+      { label: "否", value: 0 },
+    ],
+    optionLabel: "label",
+    optionValue: "value",
     search: true,
     search: true,
   },
   },
+
+  // 其他字段(不在搜索表单显示但保留的)
   {
   {
-    label: '高考年份',
-    name: 'endYear',
-    value: '',
-    type: 'text',
-    search: true,
+    label: "卡号",
+    name: "cardNo",
+    value: "",
+    type: "text",
+    search: false,
   },
   },
   {
   {
-    label: '开卡ID',
-    name: 'openId',
-    value: '',
-    type: 'text',
-    search: true,
+    label: "密码",
+    name: "password",
+    value: "",
+    type: "text",
+    search: false,
   },
   },
   {
   {
-    label: '分配时间',
-    name: 'distributeTime',
-    value: '',
-    type: 'date',
-    dateType: 'date',
-    valueFormat: 'YYYY-MM-DD',
-    search: true,
+    label: "末级代理商ID",
+    name: "leftAgentId",
+    value: "",
+    type: "select",
+    option: [],
+    optionLabel: "name",
+    optionValue: "id",
+    search: false,
   },
   },
   {
   {
-    label: '过期时间',
-    name: 'outDate',
-    value: '',
-    type: 'date',
-    dateType: 'date',
-    valueFormat: 'YYYY-MM-DD',
-    search: true,
+    label: "学校班级ID",
+    name: "schoolId",
+    value: "",
+    type: "text",
+    search: false,
   },
   },
   {
   {
-    label: '开卡时间',
-    name: 'openTime',
-    value: '',
-    type: 'date',
-    dateType: 'date',
-    valueFormat: 'YYYY-MM-DD',
-    search: true,
+    label: "班级ID",
+    name: "classId",
+    value: "",
+    type: "text",
+    search: false,
   },
   },
   {
   {
-    label: '缴费时间',
-    name: 'payTime',
-    value: '',
-    type: 'date',
-    dateType: 'date',
-    valueFormat: 'YYYY-MM-DD',
-    search: true,
+    label: "入学年份",
+    name: "year",
+    value: "",
+    type: "text",
+    search: false,
   },
   },
   {
   {
-    label: '激活时间',
-    name: 'activeTime',
-    value: '',
-    type: 'date',
-    dateType: 'date',
-    valueFormat: 'YYYY-MM-DD',
-    search: true,
+    label: "高考年份",
+    name: "endYear",
+    value: "",
+    type: "text",
+    search: false,
   },
   },
   {
   {
-    label: '结算时间',
-    name: 'settlementTime',
-    value: '',
-    type: 'date',
-    dateType: 'date',
-    valueFormat: 'YYYY-MM-DD',
-    search: true,
+    label: "开卡ID",
+    name: "openId",
+    value: "",
+    type: "text",
+    search: false,
   },
   },
   {
   {
-    label: '退费时间',
-    name: 'refundTime',
-    value: '',
-    type: 'date',
-    dateType: 'date',
-    valueFormat: 'YYYY-MM-DD',
-    search: true,
+    label: "分配时间",
+    name: "distributeTime",
+    value: "",
+    type: "date",
+    dateType: "date",
+    valueFormat: "YYYY-MM-DD",
+    search: false,
   },
   },
   {
   {
-    label: '关卡时间',
-    name: 'closeTime',
-    value: '',
-    type: 'date',
-    dateType: 'date',
-    valueFormat: 'YYYY-MM-DD',
-    search: true,
+    label: "过期时间",
+    name: "outDate",
+    value: "",
+    type: "date",
+    dateType: "date",
+    valueFormat: "YYYY-MM-DD",
+    search: false,
+  },
+  {
+    label: "开卡时间",
+    name: "openTime",
+    value: "",
+    type: "date",
+    dateType: "date",
+    valueFormat: "YYYY-MM-DD",
+    search: false,
+  },
+  {
+    label: "缴费时间",
+    name: "payTime",
+    value: "",
+    type: "date",
+    dateType: "date",
+    valueFormat: "YYYY-MM-DD",
+    search: false,
+  },
+  {
+    label: "激活时间",
+    name: "activeTime",
+    value: "",
+    type: "date",
+    dateType: "date",
+    valueFormat: "YYYY-MM-DD",
+    search: false,
+  },
+  {
+    label: "结算时间",
+    name: "settlementTime",
+    value: "",
+    type: "date",
+    dateType: "date",
+    valueFormat: "YYYY-MM-DD",
+    search: false,
+  },
+  {
+    label: "退费时间",
+    name: "refundTime",
+    value: "",
+    type: "date",
+    dateType: "date",
+    valueFormat: "YYYY-MM-DD",
+    search: false,
+  },
+  {
+    label: "关卡时间",
+    name: "closeTime",
+    value: "",
+    type: "date",
+    dateType: "date",
+    valueFormat: "YYYY-MM-DD",
+    search: false,
+  },
+  {
+    label: "创建时间",
+    name: "createTime",
+    value: "",
+    type: "date",
+    dateType: "date",
+    valueFormat: "YYYY-MM-DD",
+    search: false,
+  },
+  {
+    label: "更新时间",
+    name: "updateTime",
+    value: "",
+    type: "date",
+    dateType: "date",
+    valueFormat: "YYYY-MM-DD",
+    search: false,
   },
   },
 ];
 ];
 
 

+ 187 - 0
back-ui/src/views/dz/cards/config/table.js

@@ -0,0 +1,187 @@
+const tableConfig = {
+  // 表格列配置
+  columns: [
+    {
+      label: "序号",
+      type: "index",
+      align: "center",
+      width: 80,
+    },
+    {
+      label: "卡号",
+      prop: "cardNo",
+      align: "center",
+      width: 120,
+      showOverflowTooltip: true,
+    },
+    {
+      label: "密码",
+      prop: "password",
+      align: "center",
+      width: 100,
+    },
+    {
+      label: "姓名—手机",
+      prop: "studentInfo",
+      align: "center",
+      type: "slot",
+      slotName: "studentInfo", // 自定义插槽显示姓名-手机
+      width: 150,
+    },
+    {
+      label: "卡类型",
+      prop: "type",
+      align: "center",
+      type: "dict",
+      options: [], // 动态设置
+      width: 100,
+    },
+    {
+      label: "分配学校",
+      prop: "assignSchoolId",
+      align: "center",
+      type: "dict",
+      options: [], // 动态设置学校选项
+      width: 120,
+    },
+    {
+      label: "注册学校",
+      prop: "schoolName",
+      align: "center",
+      type: "dict",
+      options: [], // 动态设置学校选项
+      width: 120,
+    },
+    {
+      label: "班级",
+      prop: "classId",
+      align: "center",
+      type: "dict",
+      options: [], // 动态设置班级选项
+      width: 100,
+    },
+    {
+      label: "校区",
+      prop: "campusId",
+      align: "center",
+      type: "dict",
+      options: [], // 动态设置校区选项
+      width: 100,
+    },
+    {
+      label: "校区班级",
+      prop: "classId",
+      align: "center",
+      type: "dict",
+      options: [], // 动态设置校区班级选项
+      width: 120,
+    },
+    {
+      label: "分配考生类型",
+      prop: "assignExamType",
+      align: "center",
+      type: "dict",
+      options: [], // 动态设置
+      width: 120,
+    },
+    {
+      label: "分配状态",
+      prop: "distributeStatus",
+      align: "center",
+      type: "dict",
+      options: [], // 动态设置
+      width: 100,
+    },
+    {
+      label: "使用状态",
+      prop: "status",
+      align: "center",
+      type: "dict",
+      options: [], // 动态设置
+      width: 100,
+    },
+    {
+      label: "过期状态",
+      prop: "timeStatus",
+      align: "center",
+      type: "dict",
+      options: [], // 动态设置
+      width: 100,
+    },
+    {
+      label: "结算状态",
+      prop: "isSettlement",
+      align: "center",
+      type: "dict",
+      options: [], // 动态设置
+      width: 100,
+    },
+    {
+      label: "激活时间",
+      prop: "activeTime",
+      align: "center",
+      type: "time",
+      format: "{y}-{m}-{d}",
+      width: 120,
+    },
+    {
+      label: "到期时间",
+      prop: "outDate",
+      align: "center",
+      type: "time",
+      format: "{y}-{m}-{d}",
+      width: 120,
+    },
+    {
+      label: "缴费时间",
+      prop: "payTime",
+      align: "center",
+      type: "time",
+      format: "{y}-{m}-{d}",
+      width: 120,
+    },
+    {
+      label: "开卡时间",
+      prop: "openTime",
+      align: "center",
+      type: "time",
+      format: "{y}-{m}-{d}",
+      width: 120,
+    },
+  ],
+
+  // 操作按钮配置
+  actions: [
+    {
+      key: "edit",
+      label: "修改",
+      type: "primary",
+      icon: "Edit",
+      link: true,
+      permission: ["dz:cards:edit"],
+    },
+    {
+      key: "delete",
+      label: "删除",
+      type: "primary",
+      icon: "Delete",
+      link: true,
+      permission: ["dz:cards:remove"],
+    },
+  ],
+
+  // 表格属性配置
+  tableProps: {
+    stripe: true,
+    border: false,
+    showSelection: false, // 移除多选列
+    showIndex: false, // 使用自定义序号列
+    showPagination: true,
+    actionWidth: "auto",
+    // 选择模式配置
+    selectionMode: "multiple", // 'single' | 'multiple' | 'none'
+    rowKey: "cardId", // 选择键字段名
+  },
+};
+
+export default tableConfig;

Plik diff jest za duży
+ 578 - 404
back-ui/src/views/dz/cards/index.vue


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

@@ -195,7 +195,6 @@
   const { proxy } = getCurrentInstance()
   const { proxy } = getCurrentInstance()
   const { bool_values } = proxy.useDict('bool_values')
   const { bool_values } = proxy.useDict('bool_values')
 
 
-
   const classesList = ref([])
   const classesList = ref([])
   const schoolOptions = ref([])
   const schoolOptions = ref([])
   const open = ref(false)
   const open = ref(false)

+ 19 - 0
back-ui/src/views/dz/papers/components/paper-by-hand.vue

@@ -0,0 +1,19 @@
+<template>
+    <el-tabs type="border-card">
+        <el-tab-pane label="全量组卷">
+            <paper-hand-full />
+        </el-tab-pane>
+        <el-tab-pane label="定向组卷">
+            <paper-hand-exact />
+        </el-tab-pane>
+    </el-tabs>
+</template>
+
+<script setup name="PaperByHand">
+import PaperHandFull from "@/views/dz/papers/components/paper-hand-full.vue";
+import PaperHandExact from "@/views/dz/papers/components/paper-hand-exact.vue";
+</script>
+
+<style scoped>
+
+</style>

+ 19 - 0
back-ui/src/views/dz/papers/components/paper-by-intelligent.vue

@@ -0,0 +1,19 @@
+<template>
+    <el-tabs type="border-card">
+        <el-tab-pane label="全量组卷">
+            <paper-intelligent-full />
+        </el-tab-pane>
+        <el-tab-pane label="定向组卷">
+            <paper-intelligent-exact />
+        </el-tab-pane>
+    </el-tabs>
+</template>
+
+<script setup name="PaperByIntelligent">
+import PaperIntelligentFull from "@/views/dz/papers/components/paper-intelligent-full.vue";
+import PaperIntelligentExact from "@/views/dz/papers/components/paper-intelligent-exact.vue";
+</script>
+
+<style scoped>
+
+</style>

+ 47 - 0
back-ui/src/views/dz/papers/components/paper-exact-conditions.vue

@@ -0,0 +1,47 @@
+<template>
+    <div class="flex flex-row items-center gap-2">
+        <span :class="labelClass">省份:</span>
+        <el-select v-model="location" style="width: 280px">
+            <el-option v-for="p in provinces" :label="p.dictLabel" :value="p.dictValue"/>
+        </el-select>
+    </div>
+    <div class="flex flex-row items-center gap-2 mt-5">
+        <span :class="labelClass">考生类型:</span>
+        <el-select v-model="examType" style="width: 280px">
+            <el-option v-for="t in examTypes" :label="t.dictLabel" :value="t.dictValue"/>
+        </el-select>
+    </div>
+    <div class="flex flex-row items-center gap-2 mt-5">
+        <span :class="labelClass">院校:</span>
+        <el-select v-model="universityId" style="width: 280px">
+            <el-option v-for="u in universities" :label="u.name" :value="u.id"/>
+        </el-select>
+    </div>
+    <div class="flex flex-row items-center gap-2 mt-5">
+        <span :class="labelClass">专业组:</span>
+        <el-radio-group v-model="majorPlanId">
+            <el-radio-button v-for="m in majors" :label="m.majorGroup" :value="m.id"/>
+        </el-radio-group>
+    </div>
+    <div class="flex flex-row items-center gap-2 mt-5">
+        <span :class="labelClass">科目:</span>
+        <el-radio-group v-model="subjectId">
+            <el-radio-button v-for="s in subjects" :label="s.subjectName" :value="s.subjectId"/>
+        </el-radio-group>
+    </div>
+</template>
+
+<script setup name="PaperExactConditions">
+import {useInjectPaperExactCondition} from "@/views/dz/papers/hooks/usePaperExactCondition.js";
+
+const labelClass = 'break-keep text-sm font-bold w-[80px]'
+const {location, provinces,
+    examType, examTypes,
+    universityId, universities,
+    majorPlanId, majors,
+    subjectId, subjects} = useInjectPaperExactCondition()
+</script>
+
+<style scoped>
+
+</style>

+ 18 - 0
back-ui/src/views/dz/papers/components/paper-full-conditions.vue

@@ -0,0 +1,18 @@
+<template>
+    <div class="flex flex-row items-center gap-2">
+        <span class="break-keep text-sm font-bold">科目:</span>
+        <el-radio-group v-model="subjectId">
+            <el-radio-button v-for="s in subjects" :label="s.subjectName" :value="s.subjectId"/>
+        </el-radio-group>
+    </div>
+</template>
+
+<script setup name="PaperFullConditions">
+import {useInjectPaperFullCondition} from "@/views/dz/papers/hooks/usePaperFullCondition.js";
+
+const {subjectId, subjects} = useInjectPaperFullCondition()
+</script>
+
+<style scoped>
+
+</style>

+ 21 - 0
back-ui/src/views/dz/papers/components/paper-hand-exact.vue

@@ -0,0 +1,21 @@
+<template>
+    <paper-exact-conditions/>
+    <el-container class="mt-5">
+        <el-aside width="350px">
+            <paper-knowledge-tree exact-mode/>
+        </el-aside>
+        <el-main></el-main>
+    </el-container>
+</template>
+
+<script setup name="PaperHandExact">
+import PaperExactConditions from "@/views/dz/papers/components/paper-exact-conditions.vue";
+import PaperKnowledgeTree from "@/views/dz/papers/components/paper-knowledge-tree.vue";
+import {useProvidePaperExactCondition} from "@/views/dz/papers/hooks/usePaperExactCondition.js";
+
+useProvidePaperExactCondition()
+</script>
+
+<style scoped>
+
+</style>

+ 21 - 0
back-ui/src/views/dz/papers/components/paper-hand-full.vue

@@ -0,0 +1,21 @@
+<template>
+    <paper-full-conditions />
+    <el-container class="mt-5">
+        <el-aside width="350px">
+            <paper-knowledge-tree/>
+        </el-aside>
+        <el-main></el-main>
+    </el-container>
+</template>
+
+<script setup name="PaperHandFull">
+import PaperFullConditions from "@/views/dz/papers/components/paper-full-conditions.vue";
+import {useProvidePaperFullCondition} from "@/views/dz/papers/hooks/usePaperFullCondition.js";
+import PaperKnowledgeTree from "@/views/dz/papers/components/paper-knowledge-tree.vue";
+
+const {subjectId, knowledgeId} = useProvidePaperFullCondition()
+</script>
+
+<style scoped>
+
+</style>

+ 13 - 0
back-ui/src/views/dz/papers/components/paper-intelligent-exact.vue

@@ -0,0 +1,13 @@
+<template>
+
+</template>
+
+<script>
+export default {
+    name: "paper-intelligent-exact"
+}
+</script>
+
+<style scoped>
+
+</style>

+ 13 - 0
back-ui/src/views/dz/papers/components/paper-intelligent-form.vue

@@ -0,0 +1,13 @@
+<template>
+
+</template>
+
+<script>
+export default {
+    name: "paper-intelligent-form"
+}
+</script>
+
+<style scoped>
+
+</style>

+ 13 - 0
back-ui/src/views/dz/papers/components/paper-intelligent-full.vue

@@ -0,0 +1,13 @@
+<template>
+
+</template>
+
+<script>
+export default {
+    name: "paper-intelligent-full"
+}
+</script>
+
+<style scoped>
+
+</style>

+ 41 - 0
back-ui/src/views/dz/papers/components/paper-knowledge-tree.vue

@@ -0,0 +1,41 @@
+<template>
+    <el-input v-model="keyword" placeholder="请输入知识点名称" clearable prefix-icon="Search"
+              style="margin-bottom: 20px"/>
+    <el-tree :data="knowledges" :props="{ label: 'name', children: 'children' }" :expand-on-click-node="false"
+             :filter-node-method="filterNode" node-key="id" highlight-current default-expand-all
+             :show-checkbox="allowMultiple" @node-click="handleNodeClick" @check="handleNodeCheck"/>
+</template>
+
+<script setup name="PaperKnowledgeTree">
+import {useInjectPaperFullCondition} from "@/views/dz/papers/hooks/usePaperFullCondition.js";
+import {useInjectPaperExactCondition} from "@/views/dz/papers/hooks/usePaperExactCondition.js";
+
+const props = defineProps({
+    allowMultiple: Boolean,
+    exactMode: Boolean
+})
+
+const keyword = ref('')
+const {knowledgeId, knowledges, knowledgeCheckNodes} = props.exactMode
+    ? useInjectPaperExactCondition()
+    : useInjectPaperFullCondition()
+
+const filterNode = function (value, data) {
+    if (!value) return true
+    return data.name.indexOf(value) !== -1
+}
+
+const handleNodeClick = function (data) {
+    knowledgeId.value = data.id
+}
+
+const handleNodeCheck = function (data, {checkedNodes}) {
+    // 多选时,只保留叶子节点
+    knowledgeCheckNodes.value = checkedNodes.filter(k => !!!k.children?.length)
+    console.log('knowledgeCheckNodes', knowledgeCheckNodes.value)
+}
+</script>
+
+<style scoped>
+
+</style>

+ 10 - 0
back-ui/src/views/dz/papers/detail.vue

@@ -0,0 +1,10 @@
+<template>
+
+</template>
+
+<script setup name="PaperDetail">
+</script>
+
+<style scoped>
+
+</style>

+ 92 - 0
back-ui/src/views/dz/papers/hooks/usePaperExactCondition.js

@@ -0,0 +1,92 @@
+import {injectLocal, provideLocal} from "@vueuse/core";
+import {
+    getPaperExamTypes,
+    getPaperKnowledges,
+    getPaperMajors,
+    getPaperProvinces,
+    getPaperSubjects,
+    getPaperUniversities
+} from "@/api/dz/papers.js";
+
+const key = Symbol('PaperExactCondition')
+
+export const useProvidePaperExactCondition = function () {
+    const location = ref('')
+    const provinces = ref([])
+    const examType = ref('')
+    const examTypes = ref([])
+    const universityId = ref('')
+    const universities = ref([])
+    const majorPlanId = ref('')
+    const majors = ref([])
+
+    const subjects = ref([])
+    const subjectId = ref('')
+    const knowledges = ref([])
+    const knowledgeId = ref('') // 单选
+    const knowledgeCheckNodes = ref([]) // 多选的节点
+    const knowledgeIds = computed(() => knowledgeCheckNodes.value.map(k => k.id))
+
+    const payload = {
+        location, provinces, examType, examTypes, universityId, universities, majorPlanId, majors,
+        subjects, subjectId, knowledges, knowledgeId, knowledgeCheckNodes, knowledgeIds
+    }
+    provideLocal(key, payload)
+
+    // hooks
+    onMounted(async () => {
+        const res = await getPaperProvinces()
+        provinces.value = res.data
+    })
+    watch(location, async () => {
+        // clean
+        examType.value = ''
+        examTypes.value = []
+        universityId.value = ''
+        universities.value = []
+
+        if (!location.value) return
+        const resT = await getPaperExamTypes({location: toValue(location)})
+        examTypes.value = resT.data
+
+        const resU = await getPaperUniversities({location: toValue(location)})
+        universities.value = resU.data
+    })
+    watch([examType, universityId], async ([examType, universityId]) => {
+        // clean
+        majorPlanId.value = ''
+        majors.value = []
+
+        if (!examType || !universityId) return
+        const res = await getPaperMajors({location: toValue(location), examType, universityId})
+        majors.value = res.data
+        if (res.data.length) majorPlanId.value = res.data[0].id
+    })
+    watch(universityId, async (universityId) => {
+        // clean
+        subjects.value = []
+        subjectId.value = ''
+
+        if (!universityId) return
+        const res = await getPaperSubjects({universityId})
+        subjects.value = res.data
+        if (res.data.length) subjectId.value = res.data[0].subjectId
+    })
+    watch([majorPlanId, subjectId], async ([majorPlanId, subjectId]) => {
+        // clean
+        knowledges.value = []
+        knowledgeId.value = '' // 单选的情况
+        knowledgeCheckNodes.value = [] // 多选的情况
+
+        if (!subjectId || !majorPlanId) return
+        // 获取知识点数据
+        const res = await getPaperKnowledges({subjectId, majorPlanId})
+        knowledges.value = res.data
+    })
+
+    return payload
+}
+
+export const useInjectPaperExactCondition = function () {
+    return injectLocal(key)
+}

+ 39 - 0
back-ui/src/views/dz/papers/hooks/usePaperFullCondition.js

@@ -0,0 +1,39 @@
+import {injectLocal, provideLocal} from "@vueuse/core";
+import {getPaperKnowledges, getPaperSubjects} from "@/api/dz/papers.js";
+import {watch} from "vue";
+
+const key = Symbol('PaperFullCondition')
+
+export const useProvidePaperFullCondition = function () {
+    const subjects = ref([])
+    const subjectId = ref('')
+    const knowledges = ref([])
+    const knowledgeId = ref('') // 单选
+    const knowledgeCheckNodes = ref([]) // 多选的节点
+    const knowledgeIds = computed(() => knowledgeCheckNodes.value.map(k => k.id))
+
+    const payload = {subjectId, subjects, knowledgeId, knowledges, knowledgeCheckNodes, knowledgeIds}
+    provideLocal(key, payload)
+
+    onMounted(async () => {
+        const res = await getPaperSubjects()
+        subjects.value = res.data
+        // 给一个默认值
+        if (res.data.length) subjectId.value = res.data[0].subjectId
+    })
+    watch(subjectId, async () => {
+        // 先清空以前的知识点
+        knowledges.value = []
+        knowledgeId.value = '' // 单选的情况
+        knowledgeCheckNodes.value = [] // 多选的情况
+
+        // 获取知识点数据
+        const res = await getPaperKnowledges({subjectId: toValue(subjectId)})
+        knowledges.value = res.data
+    })
+    return payload
+}
+
+export const useInjectPaperFullCondition = function () {
+    return injectLocal(key)
+}

+ 16 - 2
back-ui/src/views/dz/papers/index.vue

@@ -1,5 +1,19 @@
 <template>
 <template>
-  <div>组卷功能</div>
+  <div class="app-container">
+    <el-tabs>
+      <el-tab-pane label="手动组卷">
+        <paper-by-hand />
+      </el-tab-pane>
+      <el-tab-pane label="智能组卷">
+        <paper-by-intelligent />
+      </el-tab-pane>
+    </el-tabs>
+  </div>
 </template>
 </template>
 
 
-<script setup></script>
+<script setup name="PaperIndex">
+import PaperByHand from "@/views/dz/papers/components/paper-by-hand.vue";
+import PaperByIntelligent from "@/views/dz/papers/components/paper-by-intelligent.vue";
+</script>
+
+<style scoped></style>

+ 5 - 4
back-ui/src/views/dz/school/index.vue

@@ -102,9 +102,10 @@
               <el-table-column label="归属机构" align="center" key="deptName" prop="dept.deptName" :show-overflow-tooltip="true" />
               <el-table-column label="归属机构" align="center" key="deptName" prop="dept.deptName" :show-overflow-tooltip="true" />
               <el-table-column label="省份" align="center" prop="location" />
               <el-table-column label="省份" align="center" prop="location" />
 
 
-              <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="省" align="center" prop="pro" />-->
+<!--              <el-table-column label="市" align="center" prop="city" />-->
+<!--              <el-table-column label="区" align="center" prop="area" />-->
+              <el-table-column label="所属地区" align="center" prop="proCityAreaName" />
               <el-table-column label="状态" align="center" prop="status">
               <el-table-column label="状态" align="center" prop="status">
                 <template #default="scope">
                 <template #default="scope">
                   <dict-tag :options="bool_values" :value="scope.row.status"/>
                   <dict-tag :options="bool_values" :value="scope.row.status"/>
@@ -226,7 +227,7 @@
     },
     },
     rules: {
     rules: {
       status: [
       status: [
-        { required: true, message: "状态(0:无效,1:有效)不能为空", trigger: "change" },
+        { required: true, message: "状态不能为空", trigger: "change" },
         { required: true, message: "机构不能为空", trigger: "change" }
         { required: true, message: "机构不能为空", trigger: "change" }
       ],
       ],
     }
     }

+ 118 - 1
back-ui/src/views/dz/teacher/index.vue

@@ -90,6 +90,7 @@
       <el-table-column label="用户ID" align="center" prop="userId" />
       <el-table-column label="用户ID" align="center" prop="userId" />
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template #default="scope">
         <template #default="scope">
+          <el-button link type="primary" icon="" @click="handleUpdateTeacherClass(scope.row)" v-hasPermi="['dz:teacher:edit']">关联班级</el-button>
           <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['dz:teacher:edit']">修改</el-button>
           <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>
           <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['dz:teacher:remove']">删除</el-button>
         </template>
         </template>
@@ -131,18 +132,50 @@
         </div>
         </div>
       </template>
       </template>
     </el-dialog>
     </el-dialog>
+
+      <!-- 关联班级 -->
+      <el-dialog :title="titleTeacherClass" v-model="openTeacherClass" width="500px" append-to-body>
+          <el-form ref="teacherClassRef" :model="formTeacherClass" :rules="rulesTeacherClass" label-width="80px">
+<!--              <el-form-item label="教师ID" v-show="false" prop="teacherId">-->
+<!--                  <el-input v-model="formTeacherClass.teacherId" placeholder="请输入教师ID" disabled/>-->
+<!--              </el-form-item>-->
+              <el-form-item label="教师姓名" prop="name">
+                  <el-input v-model="formTeacherClass.name" placeholder="请输入教师姓名" disabled/>
+              </el-form-item>
+              <el-form-item label="关联班级" prop="classIds">
+                  <el-select v-model="formTeacherClass.classIds" multiple placeholder="请选择班级" style="width: 100%">
+                      <el-option
+                              v-for="item in classOptions"
+                              :key="item.classId"
+                              :label="item.name"
+                              :value="item.classId"
+                      />
+                  </el-select>
+              </el-form-item>
+          </el-form>
+          <template #footer>
+              <div class="dialog-footer">
+                  <el-button type="primary" @click="submitFormTeacherClass">确 定</el-button>
+                  <el-button @click="cancelTeacherClass">取 消</el-button>
+              </div>
+          </template>
+      </el-dialog>
   </div>
   </div>
 </template>
 </template>
 
 
 <script setup name="Teacher">
 <script setup name="Teacher">
 import { listTeacher, getTeacher, delTeacher, addTeacher, updateTeacher } from "@/api/dz/teacher"
 import { listTeacher, getTeacher, delTeacher, addTeacher, updateTeacher } from "@/api/dz/teacher"
 import { listAllSchool } from "@/api/dz/school"
 import { listAllSchool } from "@/api/dz/school"
+import { listAllClass } from "@/api/dz/classes"
+import { batchBindTeacherClass,listAllTeacherClass } from "@/api/dz/teacherclass"
 
 
 const { proxy } = getCurrentInstance()
 const { proxy } = getCurrentInstance()
 
 
 const teacherList = ref([])
 const teacherList = ref([])
 const schoolOptions = ref([])
 const schoolOptions = ref([])
+const classOptions = ref([])
 const open = ref(false)
 const open = ref(false)
+const openTeacherClass = ref(false)
 const loading = ref(true)
 const loading = ref(true)
 const showSearch = ref(true)
 const showSearch = ref(true)
 const ids = ref([])
 const ids = ref([])
@@ -150,9 +183,15 @@ const single = ref(true)
 const multiple = ref(true)
 const multiple = ref(true)
 const total = ref(0)
 const total = ref(0)
 const title = ref("")
 const title = ref("")
+const titleTeacherClass = ref("")
 
 
 const data = reactive({
 const data = reactive({
   form: {},
   form: {},
+  formTeacherClass: {
+      teacherId: null,
+      name: null,
+      classIds: []
+  },
   queryParams: {
   queryParams: {
     pageNum: 1,
     pageNum: 1,
     pageSize: 10,
     pageSize: 10,
@@ -161,10 +200,16 @@ const data = reactive({
     name: null
     name: null
   },
   },
   rules: {
   rules: {
+  },
+  rulesTeacherClass: {
+      // 可以添加验证规则
+      classIds: [
+          { required: true, message: "请选择至少一个班级", trigger: "change" }
+      ]
   }
   }
 })
 })
 
 
-const { queryParams, form, rules } = toRefs(data)
+const { queryParams, form, formTeacherClass, rules, rulesTeacherClass } = toRefs(data)
 
 
 /** 查询老师列表 */
 /** 查询老师列表 */
 function getList() {
 function getList() {
@@ -183,12 +228,19 @@ function getSchoolList() {
   })
   })
 }
 }
 
 
+// function getClassListBySchool() {
+//     listAll().then(response => {
+//         classOptions.value = response.data || []
+//     })
+// }
+
 // 取消按钮
 // 取消按钮
 function cancel() {
 function cancel() {
   open.value = false
   open.value = false
   reset()
   reset()
 }
 }
 
 
+
 // 表单重置
 // 表单重置
 function reset() {
 function reset() {
   form.value = {
   form.value = {
@@ -200,6 +252,22 @@ function reset() {
   proxy.resetForm("teacherRef")
   proxy.resetForm("teacherRef")
 }
 }
 
 
+// 取消按钮
+function cancelTeacherClass() {
+    openTeacherClass.value = false
+    resetTeacherClass()
+}
+
+// 表单重置
+function resetTeacherClass() {
+    formTeacherClass.value = {
+        teacherId: null,
+        classIds: [],
+        name: null
+    }
+    proxy.resetForm("teacherClassRef")
+}
+
 /** 搜索按钮操作 */
 /** 搜索按钮操作 */
 function handleQuery() {
 function handleQuery() {
   queryParams.value.pageNum = 1
   queryParams.value.pageNum = 1
@@ -276,9 +344,58 @@ function handleExport() {
   }, `teacher_${new Date().getTime()}.xlsx`)
   }, `teacher_${new Date().getTime()}.xlsx`)
 }
 }
 
 
+/** 关联老师班级,按钮操作 */
+function handleUpdateTeacherClass(row) {
+    resetTeacherClass()
+    // const _schoolId = row.schoolId
+    const submitData = {
+        schoolId: row.schoolId,
+        teacherId: row.teacherId
+    }
+    listAllClass(submitData).then(response => {
+        classOptions.value = response.data || []
+
+        // 然后设置数据
+        formTeacherClass.value.teacherId = row.teacherId
+        formTeacherClass.value.name = row.name
+
+        listAllTeacherClass(submitData).then(response => {
+            formTeacherClass.value.classIds = (response.data || []).map(item => item.classId)
+        })
+
+        openTeacherClass.value = true
+        titleTeacherClass.value = "关联班级"
+    })
+}
+
+/** 关联老师班级,提交按钮 */
+function submitFormTeacherClass() {
+    proxy.$refs["teacherClassRef"].validate(valid => {
+        if (valid) {
+            // 构建提交参数
+            const submitData = {
+                teacherId: formTeacherClass.value.teacherId,
+                classIds: formTeacherClass.value.classIds
+            }
+            // console.log("submitData"+submitData)
+
+            // 调用关联班级的API
+            // 假设API函数名为 updateTeacherClassRelation
+            batchBindTeacherClass(submitData).then(response => {
+                proxy.$modal.msgSuccess("关联成功")
+                openTeacherClass.value = false
+                getList()
+            }).catch(() => {
+                proxy.$modal.msgError("关联失败")
+            })
+        }
+    })
+}
+
 onMounted(() => {
 onMounted(() => {
   getSchoolList()
   getSchoolList()
   getList()
   getList()
+  // getClassListBySchool()
 })
 })
 
 
 </script>
 </script>

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

@@ -9,9 +9,9 @@
           @keyup.enter="handleQuery"
           @keyup.enter="handleQuery"
         />
         />
       </el-form-item>
       </el-form-item>
-      <el-form-item label="班级id" prop="classesId">
+      <el-form-item label="班级id" prop="classId">
         <el-input
         <el-input
-          v-model="queryParams.classesId"
+          v-model="queryParams.classId"
           placeholder="请输入班级id"
           placeholder="请输入班级id"
           clearable
           clearable
           @keyup.enter="handleQuery"
           @keyup.enter="handleQuery"
@@ -77,7 +77,7 @@
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="标识" align="center" prop="id" />
       <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="teacherId" />
-      <el-table-column label="班级id" align="center" prop="classesId" />
+      <el-table-column label="班级id" align="center" prop="classId" />
       <el-table-column label="有效状态" align="center" prop="status" />
       <el-table-column label="有效状态" align="center" prop="status" />
       <el-table-column label="备注" align="center" prop="remark" />
       <el-table-column label="备注" align="center" prop="remark" />
       <el-table-column label="结束日期" align="center" prop="outDate" width="180">
       <el-table-column label="结束日期" align="center" prop="outDate" width="180">
@@ -92,7 +92,7 @@
         </template>
         </template>
       </el-table-column>
       </el-table-column>
     </el-table>
     </el-table>
-    
+
     <pagination
     <pagination
       v-show="total>0"
       v-show="total>0"
       :total="total"
       :total="total"
@@ -107,8 +107,8 @@
         <el-form-item label="老师id" prop="teacherId">
         <el-form-item label="老师id" prop="teacherId">
           <el-input v-model="form.teacherId" placeholder="请输入老师id" />
           <el-input v-model="form.teacherId" placeholder="请输入老师id" />
         </el-form-item>
         </el-form-item>
-        <el-form-item label="班级id" prop="classesId">
-          <el-input v-model="form.classesId" placeholder="请输入班级id" />
+        <el-form-item label="班级id" prop="classId">
+          <el-input v-model="form.classId" placeholder="请输入班级id" />
         </el-form-item>
         </el-form-item>
         <el-form-item label="备注" prop="remark">
         <el-form-item label="备注" prop="remark">
           <el-input v-model="form.remark" placeholder="请输入备注" />
           <el-input v-model="form.remark" placeholder="请输入备注" />
@@ -153,7 +153,7 @@ const data = reactive({
     pageNum: 1,
     pageNum: 1,
     pageSize: 10,
     pageSize: 10,
     teacherId: null,
     teacherId: null,
-    classesId: null,
+    classId: null,
     status: null,
     status: null,
     outDate: null
     outDate: null
   },
   },
@@ -184,7 +184,7 @@ function reset() {
   form.value = {
   form.value = {
     id: null,
     id: null,
     teacherId: null,
     teacherId: null,
-    classesId: null,
+    classId: null,
     status: null,
     status: null,
     remark: null,
     remark: null,
     outDate: null
     outDate: null

+ 11 - 1
back-ui/src/views/system/user/index.vue

@@ -20,6 +20,11 @@
               <el-form-item label="用户名称" prop="userName">
               <el-form-item label="用户名称" prop="userName">
                 <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
                 <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
               </el-form-item>
               </el-form-item>
+              <el-form-item label="用户类型" prop="userType">
+                <el-select v-model="queryParams.status" placeholder="用户状态" clearable style="width: 240px">
+                  <el-option v-for="dict in user_type" :key="dict.value" :label="dict.label" :value="dict.value" />
+                </el-select>
+              </el-form-item>
               <el-form-item label="手机号码" prop="phonenumber">
               <el-form-item label="手机号码" prop="phonenumber">
                 <el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px" @keyup.enter="handleQuery" />
                 <el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px" @keyup.enter="handleQuery" />
               </el-form-item>
               </el-form-item>
@@ -61,6 +66,11 @@
               <el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns.userId.visible" />
               <el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns.userId.visible" />
               <el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns.userName.visible" :show-overflow-tooltip="true" />
               <el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns.userName.visible" :show-overflow-tooltip="true" />
               <el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns.nickName.visible" :show-overflow-tooltip="true" />
               <el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns.nickName.visible" :show-overflow-tooltip="true" />
+              <el-table-column label="用户类型" align="center" key="userType" v-if="columns.status.visible">
+                <template #default="scope">
+                  <dict-tag :options="user_type" :value="scope.row.userType" />
+                </template>
+              </el-table-column>
               <el-table-column label="机构" align="center" key="deptName" prop="dept.deptName" v-if="columns.deptName.visible" :show-overflow-tooltip="true" />
               <el-table-column label="机构" align="center" key="deptName" prop="dept.deptName" v-if="columns.deptName.visible" :show-overflow-tooltip="true" />
               <el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns.phonenumber.visible" width="120" />
               <el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns.phonenumber.visible" width="120" />
               <el-table-column label="状态" align="center" key="status" v-if="columns.status.visible">
               <el-table-column label="状态" align="center" key="status" v-if="columns.status.visible">
@@ -223,7 +233,7 @@ import "splitpanes/dist/splitpanes.css"
 const router = useRouter()
 const router = useRouter()
 const appStore = useAppStore()
 const appStore = useAppStore()
 const { proxy } = getCurrentInstance()
 const { proxy } = getCurrentInstance()
-const { sys_normal_disable, sys_user_sex } = proxy.useDict("sys_normal_disable", "sys_user_sex")
+const { sys_normal_disable, sys_user_sex, user_type } = proxy.useDict("sys_normal_disable", "sys_user_sex", "user_type")
 
 
 const userList = ref([])
 const userList = ref([])
 const open = ref(false)
 const open = ref(false)

+ 9 - 0
back-ui/tailwind.config.cjs

@@ -0,0 +1,9 @@
+/** @type {import('tailwindcss').Config} */
+/* 这个文件在这个项目里没有实际作用,只是为了让tailwind的提示起作用,真实起作用的是assets/style/tailwind.css,注意与它保持一致 */
+module.exports = {
+  content: [
+    './index.html',
+    './src/**/*.{vue,js,ts,jsx,tsx}'
+  ]
+}
+

+ 2 - 1
back-ui/vite.config.js

@@ -1,6 +1,7 @@
 import { defineConfig, loadEnv } from 'vite'
 import { defineConfig, loadEnv } from 'vite'
 import path from 'path'
 import path from 'path'
 import createVitePlugins from './vite/plugins'
 import createVitePlugins from './vite/plugins'
+import tailwindcss from '@tailwindcss/vite'
 
 
 const baseUrl = 'https://dz.shineking.top/prod-api' // 后端接口
 const baseUrl = 'https://dz.shineking.top/prod-api' // 后端接口
 
 
@@ -13,7 +14,7 @@ export default defineConfig(({ mode, command }) => {
     // 默认情况下,vite 会假设你的应用是被部署在一个域名的根路径上
     // 默认情况下,vite 会假设你的应用是被部署在一个域名的根路径上
     // 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
     // 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
     base: VITE_APP_ENV === 'production' ? '/admin/' : '/admin/',
     base: VITE_APP_ENV === 'production' ? '/admin/' : '/admin/',
-    plugins: createVitePlugins(env, command === 'build'),
+    plugins: [createVitePlugins(env, command === 'build'), tailwindcss()],
     resolve: {
     resolve: {
       // https://cn.vitejs.dev/config/#resolve-alias
       // https://cn.vitejs.dev/config/#resolve-alias
       alias: {
       alias: {

Plik diff jest za duży
+ 208 - 359
back-ui/yarn.lock


+ 50 - 2
ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzAgentController.java

@@ -1,7 +1,16 @@
 package com.ruoyi.web.controller.dz;
 package com.ruoyi.web.controller.dz;
 
 
+import java.util.Arrays;
 import java.util.List;
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpServletResponse;
+
+import cn.hutool.core.collection.CollectionUtil;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.dz.domain.DzSchool;
+import com.ruoyi.dz.service.IDzSchoolService;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -22,7 +31,7 @@ import com.ruoyi.common.utils.poi.ExcelUtil;
 
 
 /**
 /**
  * 机构代理Controller
  * 机构代理Controller
- * 
+ *
  * @author ruoyi
  * @author ruoyi
  * @date 2025-09-12
  * @date 2025-09-12
  */
  */
@@ -32,6 +41,8 @@ public class DzAgentController extends BaseController
 {
 {
     @Autowired
     @Autowired
     private IDzAgentService dzAgentService;
     private IDzAgentService dzAgentService;
+    @Autowired
+    private IDzSchoolService schoolService;
 
 
     /**
     /**
      * 查询机构代理列表
      * 查询机构代理列表
@@ -41,6 +52,32 @@ public class DzAgentController extends BaseController
     public AjaxResult list(DzAgent dzAgent)
     public AjaxResult list(DzAgent dzAgent)
     {
     {
         List<DzAgent> list = dzAgentService.selectDzAgentList(dzAgent);
         List<DzAgent> list = dzAgentService.selectDzAgentList(dzAgent);
+        //处理关联学校的显示
+        List<Long> distinctSchoolIds = list.stream()
+                .map(DzAgent::getSchoolIds)
+                .filter(Objects::nonNull)        // 过滤null数组
+                .filter(array -> array.length > 0) // 过滤空数组
+                .flatMap(Arrays::stream).filter(Objects::nonNull)        // 过滤数组中的null元素
+                .distinct()
+                .collect(Collectors.toList());
+        //查询学校名称
+        if (CollectionUtil.isNotEmpty(distinctSchoolIds)){
+            Map<Long, DzSchool> schoolMap = schoolService.selectDzSchoolListByIds(distinctSchoolIds).stream().collect(Collectors.toMap(DzSchool::getId, school -> school));
+            for (DzAgent agent : list) {
+                if (agent.getSchoolIds() != null&&agent.getSchoolIds().length>0) {
+                    String schoolName = Arrays.stream(agent.getSchoolIds())
+                            .filter(Objects::nonNull)  // 过滤null值
+                            .map(schoolId -> schoolMap.get(schoolId))  // 根据ID获取学校对象
+                            .filter(Objects::nonNull)  // 过滤map中不存在的学校
+                            .map(DzSchool::getName)    // 获取学校名称
+                            .filter(name -> name != null && !name.trim().isEmpty())  // 过滤空名称
+                            .collect(Collectors.joining(", "));  // 用逗号连接
+
+                    agent.setSchoolName(schoolName);
+                }
+            }
+        }
+
         return success(list);
         return success(list);
     }
     }
 
 
@@ -75,6 +112,7 @@ public class DzAgentController extends BaseController
     @PostMapping
     @PostMapping
     public AjaxResult add(@RequestBody DzAgent dzAgent)
     public AjaxResult add(@RequestBody DzAgent dzAgent)
     {
     {
+        setSchools(dzAgent);
         return toAjax(dzAgentService.insertDzAgent(dzAgent));
         return toAjax(dzAgentService.insertDzAgent(dzAgent));
     }
     }
 
 
@@ -86,15 +124,25 @@ public class DzAgentController extends BaseController
     @PutMapping
     @PutMapping
     public AjaxResult edit(@RequestBody DzAgent dzAgent)
     public AjaxResult edit(@RequestBody DzAgent dzAgent)
     {
     {
+        setSchools(dzAgent);
         return toAjax(dzAgentService.updateDzAgent(dzAgent));
         return toAjax(dzAgentService.updateDzAgent(dzAgent));
     }
     }
 
 
+    private void setSchools(DzAgent dzAgent){
+        String schools = dzAgent.getSchools();
+        Long[] schoolIds = dzAgent.getSchoolIds();
+        if (null!=schoolIds&&schoolIds.length>0){
+            schools = Arrays.stream(schoolIds).filter(Objects::nonNull).map(String::valueOf) .collect(Collectors.joining(","));
+            dzAgent.setSchools(schools);
+        }
+    }
+
     /**
     /**
      * 删除机构代理
      * 删除机构代理
      */
      */
     @PreAuthorize("@ss.hasPermi('dz:agent:remove')")
     @PreAuthorize("@ss.hasPermi('dz:agent:remove')")
     @Log(title = "机构代理", businessType = BusinessType.DELETE)
     @Log(title = "机构代理", businessType = BusinessType.DELETE)
-	@DeleteMapping("/{agentIds}")
+    @DeleteMapping("/{agentIds}")
     public AjaxResult remove(@PathVariable Long[] agentIds)
     public AjaxResult remove(@PathVariable Long[] agentIds)
     {
     {
         return toAjax(dzAgentService.deleteDzAgentByAgentIds(agentIds));
         return toAjax(dzAgentService.deleteDzAgentByAgentIds(agentIds));

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

@@ -1,7 +1,13 @@
 package com.ruoyi.web.controller.dz;
 package com.ruoyi.web.controller.dz;
 
 
 import java.util.List;
 import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpServletResponse;
+
+import com.ruoyi.dz.domain.DzTeacher;
+import com.ruoyi.dz.domain.DzTeacherClass;
+import com.ruoyi.dz.service.IDzTeacherClassService;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -33,6 +39,8 @@ public class DzClassesController extends BaseController
 {
 {
     @Autowired
     @Autowired
     private IDzClassesService dzClassesService;
     private IDzClassesService dzClassesService;
+    @Autowired
+    private IDzTeacherClassService teacherClassService;
 
 
     /**
     /**
      * 查询学生班级列表
      * 查询学生班级列表
@@ -46,6 +54,22 @@ public class DzClassesController extends BaseController
         return getDataTable(list);
         return getDataTable(list);
     }
     }
 
 
+    @GetMapping("/listAll")
+    public AjaxResult listAll(DzClasses dzClasses)
+    {
+        List<DzClasses> list = dzClassesService.selectDzClassesList(dzClasses);
+//        if (null!=dzClasses.getTeacherId()){
+//            DzTeacherClass query = new DzTeacherClass().setTeacherId(dzClasses.getTeacherId());
+//            Long[] classIds = teacherClassService.selectDzTeacherClassList(query).stream()
+//                    .map(DzTeacherClass::getClassId)
+//                    .filter(Objects::nonNull)
+//                    .distinct() // 去重(如果需要)
+//                    .toArray(Long[]::new);
+//            list.stream().forEach(c->c.setClassIds(classIds));
+//        }
+        return AjaxResult.success(list);
+    }
+
     /**
     /**
      * 导出学生班级列表
      * 导出学生班级列表
      */
      */

+ 38 - 1
ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzSchoolController.java

@@ -1,7 +1,16 @@
 package com.ruoyi.web.controller.dz;
 package com.ruoyi.web.controller.dz;
 
 
 import java.util.List;
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpServletResponse;
+
+import cn.hutool.core.collection.CollectionUtil;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.system.domain.SysArea;
+import com.ruoyi.system.service.ISysAreaService;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -33,6 +42,8 @@ public class DzSchoolController extends BaseController
 {
 {
     @Autowired
     @Autowired
     private IDzSchoolService dzSchoolService;
     private IDzSchoolService dzSchoolService;
+    @Autowired
+    private ISysAreaService areaService;
 
 
     /**
     /**
      * 查询机构校区列表
      * 查询机构校区列表
@@ -42,7 +53,33 @@ public class DzSchoolController extends BaseController
     public TableDataInfo list(DzSchool dzSchool)
     public TableDataInfo list(DzSchool dzSchool)
     {
     {
         startPage();
         startPage();
-        List<DzSchool> list = dzSchoolService.selectDzSchoolList(dzSchool);
+        List<DzSchool> list= dzSchoolService.selectDzSchoolList(dzSchool);
+        //处理省市区
+        List<Long> areaIds = list.stream()
+                .flatMap(school -> Stream.of(
+                        school.getPro(),school.getCity(),school.getArea()
+                ))
+                .filter(Objects::nonNull).distinct().collect(Collectors.toList());
+        if (CollectionUtil.isNotEmpty(areaIds)){
+            Map<Long, SysArea> areaMap = areaService.selectSysAreaListByIds(areaIds)
+                    .stream().collect(Collectors.toMap(SysArea::getAreaId,area -> area));
+            list.forEach(school -> {
+                StringBuilder proCityAreaName = new StringBuilder();
+                if (null!=school.getPro()&&areaMap.containsKey(school.getPro())){
+                    proCityAreaName.append(areaMap.get(school.getPro()).getAreaName());
+                }
+                if (null!=school.getCity()&&areaMap.containsKey(school.getCity())){
+                    proCityAreaName.append(areaMap.get(school.getCity()).getAreaName());
+                }
+                if (null!=school.getArea()&&areaMap.containsKey(school.getArea())){
+                    proCityAreaName.append(areaMap.get(school.getArea()).getAreaName());
+                }
+                if (StringUtils.isNotEmpty(proCityAreaName.toString())){
+                    school.setProCityAreaName(proCityAreaName.toString());
+                }
+            });
+        }
+
         return getDataTable(list);
         return getDataTable(list);
     }
     }
 
 

+ 70 - 3
ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzTeacherClassController.java

@@ -1,7 +1,13 @@
 package com.ruoyi.web.controller.dz;
 package com.ruoyi.web.controller.dz;
 
 
+import java.util.Arrays;
 import java.util.List;
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpServletResponse;
+
+import com.ruoyi.common.enums.BoolValues;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -23,7 +29,7 @@ import com.ruoyi.common.core.page.TableDataInfo;
 
 
 /**
 /**
  * 教师班级关系Controller
  * 教师班级关系Controller
- * 
+ *
  * @author ruoyi
  * @author ruoyi
  * @date 2025-09-12
  * @date 2025-09-12
  */
  */
@@ -46,6 +52,13 @@ public class DzTeacherClassController extends BaseController
         return getDataTable(list);
         return getDataTable(list);
     }
     }
 
 
+    @GetMapping("/listAllTeacherClass")
+    public AjaxResult listAllTeacherClass(DzTeacherClass dzTeacherClass)
+    {
+        List<DzTeacherClass> list = dzTeacherClassService.selectDzTeacherClassList(dzTeacherClass);
+        return AjaxResult.success(list);
+    }
+
     /**
     /**
      * 导出教师班级关系列表
      * 导出教师班级关系列表
      */
      */
@@ -73,13 +86,67 @@ public class DzTeacherClassController extends BaseController
      * 新增教师班级关系
      * 新增教师班级关系
      */
      */
     @PreAuthorize("@ss.hasPermi('dz:teacherclass:add')")
     @PreAuthorize("@ss.hasPermi('dz:teacherclass:add')")
-    @Log(title = "教师班级关系", businessType = BusinessType.INSERT)
+    @Log(title = "关联教师班级关系", businessType = BusinessType.INSERT)
     @PostMapping
     @PostMapping
     public AjaxResult add(@RequestBody DzTeacherClass dzTeacherClass)
     public AjaxResult add(@RequestBody DzTeacherClass dzTeacherClass)
     {
     {
         return toAjax(dzTeacherClassService.insertDzTeacherClass(dzTeacherClass));
         return toAjax(dzTeacherClassService.insertDzTeacherClass(dzTeacherClass));
     }
     }
 
 
+    @Log(title = "批量关联教师班级关系", businessType = BusinessType.INSERT)
+    @PostMapping("/batchBindTeacherClass")
+    public AjaxResult batchBindTeacherClass(@RequestBody DzTeacherClass dzTeacherClass)
+    {
+        List<Long> insertClassIds = Arrays.stream(dzTeacherClass.getClassIds()).collect(Collectors.toList());
+
+        DzTeacherClass cond = new DzTeacherClass().setTeacherId(dzTeacherClass.getTeacherId());
+        List<DzTeacherClass> alreadyList = dzTeacherClassService.selectDzTeacherClassList(cond);
+        List<Long> dbClassIds = alreadyList.stream().map(DzTeacherClass::getClassId).collect(Collectors.toList());
+
+        // 2. 找出需要删除的班级ID(存在于dbClassIds但不存在于insertClassIds)
+        List<Long> deleteClassIds = dbClassIds.stream()
+                .filter(dbId -> !insertClassIds.contains(dbId))
+                .collect(Collectors.toList());
+
+        // 3. 找出需要新增的班级ID(存在于insertClassIds但不存在于dbClassIds)
+        List<Long> newClassIds = insertClassIds.stream()
+                .filter(insertId -> !dbClassIds.contains(insertId))
+                .collect(Collectors.toList());
+
+        // 4. 执行删除操作
+        if (!deleteClassIds.isEmpty()) {
+            //alreadyList转换为Map<Long,Long>,key为classesId,value为id(删除时需要用id)
+            Map<Long,Long> map = alreadyList.stream() .collect(Collectors.toMap( DzTeacherClass::getClassId, DzTeacherClass::getId, (existing, replacement) -> existing ));
+            Long[] deleteIds = deleteClassIds.stream()
+                    .map(classId -> map.get(classId))  // 通过classId获取对应的id
+                    .filter(Objects::nonNull)          // 过滤掉null值
+                    .toArray(Long[]::new);
+            if (deleteIds.length > 0) {
+                String[] stringDeleteIds = Arrays.stream(deleteIds)
+                        .map(id -> String.valueOf(id))  // Long 转 String
+                        .toArray(String[]::new);
+                dzTeacherClassService.deleteDzTeacherClassByIds(stringDeleteIds);
+            }
+        }
+
+        // 5. 执行新增操作
+        Long teacherId = dzTeacherClass.getTeacherId();
+        if (!newClassIds.isEmpty()) {
+            List<DzTeacherClass> insertList = newClassIds.stream()
+                    .map(classId -> {
+                        DzTeacherClass insert = new DzTeacherClass();
+                        insert.setTeacherId(teacherId);
+                        insert.setClassId(classId);
+                        insert.setStatus(BoolValues.yes.getValue()); // 设置有效状态
+                        return insert;
+                    })
+                    .collect(Collectors.toList());
+            dzTeacherClassService.insertBatch(insertList);
+        }
+
+        return AjaxResult.success();
+    }
+
     /**
     /**
      * 修改教师班级关系
      * 修改教师班级关系
      */
      */
@@ -96,7 +163,7 @@ public class DzTeacherClassController extends BaseController
      */
      */
     @PreAuthorize("@ss.hasPermi('dz:teacherclass:remove')")
     @PreAuthorize("@ss.hasPermi('dz:teacherclass:remove')")
     @Log(title = "教师班级关系", businessType = BusinessType.DELETE)
     @Log(title = "教师班级关系", businessType = BusinessType.DELETE)
-	@DeleteMapping("/{ids}")
+    @DeleteMapping("/{ids}")
     public AjaxResult remove(@PathVariable String[] ids)
     public AjaxResult remove(@PathVariable String[] ids)
     {
     {
         return toAjax(dzTeacherClassService.deleteDzTeacherClassByIds(ids));
         return toAjax(dzTeacherClassService.deleteDzTeacherClassByIds(ids));

+ 5 - 1
ie-admin/src/main/java/com/ruoyi/web/controller/dz/DzTeacherController.java

@@ -2,6 +2,8 @@ package com.ruoyi.web.controller.dz;
 
 
 import java.util.List;
 import java.util.List;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpServletResponse;
+
+import com.ruoyi.dz.service.IDzTeacherClassService;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -23,7 +25,7 @@ import com.ruoyi.common.core.page.TableDataInfo;
 
 
 /**
 /**
  * 老师Controller
  * 老师Controller
- * 
+ *
  * @author ruoyi
  * @author ruoyi
  * @date 2025-09-12
  * @date 2025-09-12
  */
  */
@@ -33,6 +35,8 @@ public class DzTeacherController extends BaseController
 {
 {
     @Autowired
     @Autowired
     private IDzTeacherService dzTeacherService;
     private IDzTeacherService dzTeacherService;
+    @Autowired
+    private IDzTeacherClassService teacherClassService;
 
 
     /**
     /**
      * 查询老师列表
      * 查询老师列表

+ 79 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/front/FrontCustomerMarjorsController.java

@@ -0,0 +1,79 @@
+package com.ruoyi.web.controller.front;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.sy.domain.SyMajor;
+import com.ruoyi.sy.service.ISyMajorService;
+import com.ruoyi.syzy.domain.BCustomerMarjors;
+import com.ruoyi.syzy.service.IBCustomerMarjorsService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+@Api(tags = "关注的专业")
+@RequestMapping("front/customer/marjors")
+public class FrontCustomerMarjorsController extends BaseController {
+
+    @Autowired
+    private IBCustomerMarjorsService customerMarjorsService;
+    @Autowired
+    private ISyMajorService majorService;
+
+    @GetMapping("list")
+    @ApiOperation("01 关注专业列表")
+    public TableDataInfo list(@ApiParam(value = "页数", example = "1") @RequestParam Integer pageNum,
+        @ApiParam(value = "页大小", example = "15") @RequestParam Integer pageSize) {
+        String customerCode = SecurityUtils.getLoginUser().getUser().getCode();
+        startPage();
+        List<JSONObject> arr = customerMarjorsService.listMyByPage(customerCode);
+        return getDataTable(arr);
+    }
+
+    @GetMapping("remove")
+    @ApiOperation("02 移除关注专业")
+    public AjaxResult remove(@ApiParam("数据Id") @RequestParam String code) {
+        String customerCode = SecurityUtils.getLoginUser().getUser().getCode();
+
+        SyMajor major = majorService.selectSyMajorByCode(code);
+        if(null==major){
+            return AjaxResult.error("未找到对应编码"+code);
+        }
+        Long marjorId = major.getId();
+
+        BCustomerMarjors customerMarjors= new BCustomerMarjors();
+        customerMarjors.setCustomerCode(customerCode);
+        customerMarjors.setMarjorId(marjorId);
+        List<BCustomerMarjors> customerMarjorsList=customerMarjorsService.selectBCustomerMarjorsList(customerMarjors);
+        customerMarjorsList.forEach(ll->{
+            Long id = ll.getId();
+            customerMarjorsService.remove(customerCode, id);
+        });
+
+        return success();
+    }
+
+    @GetMapping("add")
+    @ApiOperation("03 关注专业")
+    public AjaxResult add(@ApiParam("专业code") @RequestParam String code) {
+        String customerCode = SecurityUtils.getLoginUser().getUser().getCode();
+        SyMajor major = majorService.selectSyMajorByCode(code);
+        if(null==major){
+            return AjaxResult.error("未找到对应编码"+code);
+        }
+        Long marjorId = major.getId();
+        customerMarjorsService.add(customerCode, marjorId);
+        return success();
+    }
+
+}

+ 103 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/front/FrontCustomerUniversityController.java

@@ -0,0 +1,103 @@
+package com.ruoyi.web.controller.front;
+
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.system.service.ISysDictTypeService;
+import com.ruoyi.syzy.domain.BBusiWishUniversities;
+import com.ruoyi.syzy.domain.BCustomerUniversities;
+import com.ruoyi.syzy.service.IBBusiWishUniversitiesService;
+import com.ruoyi.syzy.service.IBCustomerUniversitiesService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+@Api(tags = "关注的院校")
+@RequestMapping("front/customer/university")
+public class FrontCustomerUniversityController extends BaseController {
+
+    @Autowired
+    private IBCustomerUniversitiesService customerUniversitiesService;
+    @Autowired
+    private IBBusiWishUniversitiesService wishUniversitiesService;
+    @Autowired
+    private ISysDictTypeService dictTypeService;
+
+    @GetMapping("list")
+    @ApiOperation("01 关注院校列表")
+    public TableDataInfo list(@ApiParam(value = "页数", example = "1") @RequestParam Integer pageNum,
+        @ApiParam(value = "页大小", example = "15") @RequestParam Integer pageSize) {
+        String customerCode = SecurityUtils.getLoginUser().getUser().getCode();
+        startPage();
+        List<BBusiWishUniversities> arr = wishUniversitiesService.listMyByPage(customerCode);
+        //处理院校星级竞争力
+        arr.stream().forEach(t -> {
+            if(StringUtils.isNotEmpty(t.getStar())){
+                t.setStar(dictTypeService.getDictDataByType("university_stars",t.getStar()));
+            }
+        });
+        return getDataTable(arr);
+    }
+
+    @GetMapping("remove")
+    @ApiOperation("02 移除关注院校")
+    public AjaxResult remove(@ApiParam("院校Id") @RequestParam Long universityId) {
+        String customerCode = SecurityUtils.getLoginUser().getUser().getCode();
+        BBusiWishUniversities universities = wishUniversitiesService.selectBBusiWishUniversitiesById(universityId);
+        if (null == universities) {
+            return AjaxResult.error("未找到对应id" + universityId);
+        }
+        BCustomerUniversities upd = new BCustomerUniversities();
+        BCustomerUniversities cond = new BCustomerUniversities();
+        cond.setCustomerCode(customerCode);
+        cond.setUniversityId(universityId);
+        cond.setStatus(1L);
+        List<BCustomerUniversities> list = customerUniversitiesService.selectBCustomerUniversitiesList(cond);
+        list.forEach(t -> {
+            upd.setId(t.getId());
+            upd.setStatus(0L);
+            customerUniversitiesService.updateBCustomerUniversities(upd);
+            wishUniversitiesService.updateCollect(universityId, -1);
+        });
+        return success();
+    }
+
+    @GetMapping("add")
+    @ApiOperation("03 关注院校")
+    public AjaxResult add(@ApiParam("院校id") @RequestParam Long universityId) {
+        String customerCode = SecurityUtils.getLoginUser().getUser().getCode();
+        BBusiWishUniversities universities = wishUniversitiesService.selectBBusiWishUniversitiesById(universityId);
+        if (null == universities) {
+            return AjaxResult.error("未找到对应id" + universityId);
+        }
+        BCustomerUniversities cond = new BCustomerUniversities();
+        cond.setCustomerCode(customerCode);
+        cond.setUniversityId(universityId);
+        List<BCustomerUniversities> list = customerUniversitiesService.selectBCustomerUniversitiesList(cond);
+        if (CollectionUtils.isNotEmpty(list)) {
+            if (list.get(0).getStatus() != 1L) {
+                BCustomerUniversities upd = new BCustomerUniversities();
+                upd.setId(list.get(0).getId());
+                upd.setStatus(1L);
+                customerUniversitiesService.updateBCustomerUniversities(upd);
+            }
+        } else {
+            cond.setStatus(1L);
+            customerUniversitiesService.insertBCustomerUniversities(cond);
+        }
+        wishUniversitiesService.updateCollect(universityId, 1);
+        return success();
+    }
+
+}

+ 3 - 1
ie-admin/src/main/java/com/ruoyi/web/controller/learn/LearnQuestionsController.java

@@ -4,6 +4,7 @@ import java.util.List;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpServletResponse;
 
 
 import io.swagger.annotations.Api;
 import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -31,7 +32,7 @@ import com.ruoyi.common.core.page.TableDataInfo;
  */
  */
 @RestController
 @RestController
 @RequestMapping("/learn/questions")
 @RequestMapping("/learn/questions")
-@Api("后台-学习 - 题")
+@Api(tags = "后台-学习 - 题")
 public class LearnQuestionsController extends BaseController
 public class LearnQuestionsController extends BaseController
 {
 {
     @Autowired
     @Autowired
@@ -42,6 +43,7 @@ public class LearnQuestionsController extends BaseController
      */
      */
     @PreAuthorize("@ss.hasPermi('learn:questions:list')")
     @PreAuthorize("@ss.hasPermi('learn:questions:list')")
     @GetMapping("/list")
     @GetMapping("/list")
+    @ApiOperation("查询列表")
     public TableDataInfo list(LearnQuestions learnQuestions)
     public TableDataInfo list(LearnQuestions learnQuestions)
     {
     {
         startPage();
         startPage();

+ 28 - 5
ie-admin/src/main/java/com/ruoyi/web/controller/learn/LearnTeacherController.java

@@ -1,6 +1,8 @@
 package com.ruoyi.web.controller.learn;
 package com.ruoyi.web.controller.learn;
 
 
+import cn.hutool.core.lang.Dict;
 import com.alibaba.fastjson2.JSONObject;
 import com.alibaba.fastjson2.JSONObject;
+import com.google.common.collect.Lists;
 import com.ruoyi.common.annotation.Anonymous;
 import com.ruoyi.common.annotation.Anonymous;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.domain.AjaxResult;
@@ -10,7 +12,6 @@ import com.ruoyi.dz.domain.DzControl;
 import com.ruoyi.dz.domain.DzSubject;
 import com.ruoyi.dz.domain.DzSubject;
 import com.ruoyi.dz.service.IDzControlService;
 import com.ruoyi.dz.service.IDzControlService;
 import com.ruoyi.dz.service.IDzSubjectService;
 import com.ruoyi.dz.service.IDzSubjectService;
-import com.ruoyi.ie.service.IAMarjorPlanService;
 import com.ruoyi.learn.domain.TestPaperVO;
 import com.ruoyi.learn.domain.TestPaperVO;
 import com.ruoyi.web.service.LearnTeacherService;
 import com.ruoyi.web.service.LearnTeacherService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.Api;
@@ -126,12 +127,34 @@ public class LearnTeacherController extends BaseController {
         return AjaxResult.success(learnTeacherService.getKnowledgeTree(subjectId, majorPlanIds));
         return AjaxResult.success(learnTeacherService.getKnowledgeTree(subjectId, majorPlanIds));
     }
     }
 
 
+    @GetMapping("/questionTypes")
+    @ApiOperation("题型列表")
+    public AjaxResult questionTypes(@ApiParam("科目ID") Long subjectId, @RequestParam(required = false) @ApiParam("专业计划ID") Long[] knowledgeIds)
+    {
+        List<Dict> dictList = Lists.newArrayList();
+        dictList.add(Dict.create().set("dictLabel", "单选题").set("dictValue", "1"));
+        dictList.add(Dict.create().set("dictLabel", "多选题").set("dictValue", "2"));
+        dictList.add(Dict.create().set("dictLabel", "判断题").set("dictValue", "3"));
+        dictList.add(Dict.create().set("dictLabel", "分析题").set("dictValue", "4"));
+        return AjaxResult.success(dictList);
+    }
+
     @PreAuthorize("@ss.hasPermi('learn:test_paper:add')")
     @PreAuthorize("@ss.hasPermi('learn:test_paper:add')")
-    @PostMapping("/build")
-    @ApiOperation("批量组卷")
-    public AjaxResult batchBuild(@RequestBody TestPaperVO.TestPapersBuildReq req)
+    @PostMapping("/build/auto")
+    @ApiOperation("批量自动组卷")
+    public AjaxResult batchBuildAuto(@RequestBody TestPaperVO.TestPapersBuildAutoReq req)
     {
     {
-        return toAjax(true);
+        req.setBuildType(TestPaperVO.PaperBuildType.Auto);
+        return AjaxResult.success(learnTeacherService.buildPapersAuto(req));
+    }
+
+    @PreAuthorize("@ss.hasPermi('learn:test_paper:add')")
+    @PostMapping("/build/manual")
+    @ApiOperation("批量手动组卷")
+    public AjaxResult batchBuildManual(@RequestBody TestPaperVO.TestPapersBuildManualReq req)
+    {
+        req.setBuildType(TestPaperVO.PaperBuildType.Manual);
+        return AjaxResult.success(learnTeacherService.buildPapersManual(req));
     }
     }
 
 
     @PreAuthorize("@ss.hasPermi('learn:test_paper:query')")
     @PreAuthorize("@ss.hasPermi('learn:test_paper:query')")

+ 4 - 4
ie-admin/src/main/java/com/ruoyi/web/service/ExamService.java

@@ -116,13 +116,13 @@ public class ExamService {
             paperMapper.updateLearnPaper(up);
             paperMapper.updateLearnPaper(up);
         }
         }
 
 
-        PaperService.PaperDef paperDef = new PaperService.PaperDef();
+        TestPaperVO.PaperDef paperDef = new TestPaperVO.PaperDef();
         paperDef.setTotal(15L);
         paperDef.setTotal(15L);
         paperDef.setFillExclude(true);
         paperDef.setFillExclude(true);
         paperDef.setKnowIds(Lists.newArrayList(knowledgeId));
         paperDef.setKnowIds(Lists.newArrayList(knowledgeId));
-        List<PaperService.TypeDef> typeDefList= Lists.newArrayList();
-        typeDefList.add(new PaperService.TypeDef("单选题", "单选题", 80, 1));
-        typeDefList.add(new PaperService.TypeDef("判断题", "判断题", 10, 2));
+        List<TestPaperVO.TypeDef> typeDefList= Lists.newArrayList();
+        typeDefList.add(new TestPaperVO.TypeDef("单选题", "单选题", 80, 1));
+        typeDefList.add(new TestPaperVO.TypeDef("判断题", "判断题", 10, 2));
         paperDef.setTypes(typeDefList);
         paperDef.setTypes(typeDefList);
         List<LearnPaperQuestion> pqList = paperService.getQuestions(studentId,  paperDef);
         List<LearnPaperQuestion> pqList = paperService.getQuestions(studentId,  paperDef);
 
 

+ 266 - 2
ie-admin/src/main/java/com/ruoyi/web/service/LearnTeacherService.java

@@ -1,34 +1,60 @@
 package com.ruoyi.web.service;
 package com.ruoyi.web.service;
 
 
 import cn.hutool.core.lang.Dict;
 import cn.hutool.core.lang.Dict;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.core.domain.TreeEntity;
 import com.ruoyi.common.core.domain.TreeEntity;
+import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.dz.domain.DzClasses;
 import com.ruoyi.dz.domain.DzClasses;
 import com.ruoyi.dz.mapper.DzClassesMapper;
 import com.ruoyi.dz.mapper.DzClassesMapper;
+import com.ruoyi.enums.PaperType;
+import com.ruoyi.ie.domain.AMarjorPlan;
 import com.ruoyi.ie.mapper.AMarjorPlanMapper;
 import com.ruoyi.ie.mapper.AMarjorPlanMapper;
-import com.ruoyi.learn.domain.LearnKnowledgeTree;
+import com.ruoyi.learn.domain.*;
+import com.ruoyi.learn.mapper.LearnDirectedKnowledgeMapper;
 import com.ruoyi.learn.mapper.LearnKnowledgeTreeMapper;
 import com.ruoyi.learn.mapper.LearnKnowledgeTreeMapper;
+import com.ruoyi.learn.mapper.LearnStudentMapper;
+import com.ruoyi.learn.mapper.LearnTestPaperMapper;
 import com.ruoyi.syzy.domain.BBusiWishUniversities;
 import com.ruoyi.syzy.domain.BBusiWishUniversities;
 import com.ruoyi.syzy.mapper.BBusiWishUniversitiesMapper;
 import com.ruoyi.syzy.mapper.BBusiWishUniversitiesMapper;
 import lombok.Data;
 import lombok.Data;
 import org.apache.commons.compress.utils.Lists;
 import org.apache.commons.compress.utils.Lists;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
 
 
+import javax.validation.ValidationException;
+import java.util.Calendar;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
+import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 
 @Service
 @Service
 public class LearnTeacherService {
 public class LearnTeacherService {
     private final DzClassesMapper dzClassesMapper;
     private final DzClassesMapper dzClassesMapper;
     private final LearnKnowledgeTreeMapper learnKnowledgeTreeMapper;
     private final LearnKnowledgeTreeMapper learnKnowledgeTreeMapper;
+    private final LearnStudentMapper learnStudentMapper;
     private final AMarjorPlanMapper marjorPlanMapper;
     private final AMarjorPlanMapper marjorPlanMapper;
     private final BBusiWishUniversitiesMapper busiWishUniversitiesMapper;
     private final BBusiWishUniversitiesMapper busiWishUniversitiesMapper;
+    private final LearnDirectedKnowledgeMapper learnDirectedKnowledgeMapper;
+    private final PaperService paperService;
+    private final LearnTestPaperMapper learnTestPaperMapper;
 
 
-    public LearnTeacherService(DzClassesMapper dzClassesMapper, LearnKnowledgeTreeMapper learnKnowledgeTreeMapper, AMarjorPlanMapper marjorPlanMapper, BBusiWishUniversitiesMapper busiWishUniversitiesMapper) {
+    public LearnTeacherService(DzClassesMapper dzClassesMapper, LearnKnowledgeTreeMapper learnKnowledgeTreeMapper, LearnStudentMapper learnStudentMapper, AMarjorPlanMapper marjorPlanMapper, BBusiWishUniversitiesMapper busiWishUniversitiesMapper, LearnDirectedKnowledgeMapper learnDirectedKnowledgeMapper, PaperService paperService, LearnTestPaperMapper learnTestPaperMapper) {
         this.dzClassesMapper = dzClassesMapper;
         this.dzClassesMapper = dzClassesMapper;
         this.learnKnowledgeTreeMapper = learnKnowledgeTreeMapper;
         this.learnKnowledgeTreeMapper = learnKnowledgeTreeMapper;
+        this.learnStudentMapper = learnStudentMapper;
         this.marjorPlanMapper = marjorPlanMapper;
         this.marjorPlanMapper = marjorPlanMapper;
         this.busiWishUniversitiesMapper = busiWishUniversitiesMapper;
         this.busiWishUniversitiesMapper = busiWishUniversitiesMapper;
+        this.learnDirectedKnowledgeMapper = learnDirectedKnowledgeMapper;
+        this.paperService = paperService;
+        this.learnTestPaperMapper = learnTestPaperMapper;
     }
     }
 
 
     public List<DzClasses> getClasses(Long teacherId)
     public List<DzClasses> getClasses(Long teacherId)
@@ -45,7 +71,220 @@ public class LearnTeacherService {
                 .set("majorName", t.getMajorName()).set("count", t.getXuefei()).set("total", t.getPlanTotal())).collect(Collectors.toList());
                 .set("majorName", t.getMajorName()).set("count", t.getXuefei()).set("total", t.getPlanTotal())).collect(Collectors.toList());
     }
     }
 
 
+    @Transactional(rollbackFor = Exception.class)
+    public String buildPapersAuto(TestPaperVO.TestPapersBuildAutoReq req) {
+        // 查询 院校,专业组,专业计划范围, 明细一级时只有一个,否则就是批量
+        List<LearnStudent> studentList = learnStudentMapper.selectLearnStudentsByMap(req.toMap());
+        if(CollectionUtils.isEmpty(studentList)) {
+            throw new ValidationException("无可用计划可检查");
+        }
+        Set<Long> planIdSet = Sets.newHashSet();
+        Map<Long, List<LearnStudent>> universityMap = Maps.newHashMap();
+        for(LearnStudent ls : studentList){
+            planIdSet.add(ls.getMajorPlanId());
+            List<LearnStudent> list = universityMap.get(ls.getUniversityId());
+            if(null == list) {
+                list = Lists.newArrayList();
+                universityMap.put(ls.getUniversityId(), list);
+            }
+            list.add(ls);
+        }
+        // 查询已经生成的
+        Map<Long, Map<String, LearnTestPaper>> universityDirectPaperMap = learnTestPaperMapper.selectByBatchAndUniversityIds(req.getBatchId(), universityMap.keySet()).stream()
+                .collect(Collectors.groupingBy(LearnTestPaper::getUniversityId, Collectors.toMap(LearnTestPaper::getDirectKey, a -> a)));
+        if(null == req.getDirectType() || !req.getDirectType()) { // 全量
+            LearnPaper paper = new LearnPaper();
+            paper.setPaperName(req.getTitle());
+            paper.setYear(Calendar.getInstance().get(Calendar.YEAR));
+            paper.setPaperType(PaperType.Test.name());
+            paper.setSubjectId(req.getSubjectId());
+            paper.setDirectKey("");
+            for(Long universityId : universityMap.keySet()) {
+                Map<String, LearnTestPaper> directPaperMap = universityDirectPaperMap.get(universityId);
+                if(null != directPaperMap && directPaperMap.containsKey("")) {
+                    continue;
+                }
+                if(null == paper.getId()) {
+                    Pair<LearnPaper, List<LearnPaperQuestion>> paperResult = paperService.buildPaper(null, paper, req.getPaperDef());
+                    paperService.savePaper(paper, paperResult.getRight());
+                }
+                LearnTestPaper testPaper = new LearnTestPaper();
+                testPaper.setBatchId(req.getBatchId());
+                testPaper.setUniversityId(universityId);
+                testPaper.setDirectKey("");
+                testPaper.setPaperId(paper.getId());
+                learnTestPaperMapper.insertLearnTestPaper(testPaper);
+            }
+            return "";
+        }
+        TestPaperVO.PaperDef paperDef = req.getPaperDef();
+        if(null != req.getPlanIds() && req.getPlanIds().size() == 1) {
+            if(!CollectionUtils.isEmpty(paperDef.getKnowIds())) {
+                throw new ValidationException("批量时不支持自定义知识点");
+            }
+        }
+        Map<Long, Map<String, LearnDirectedKnowledge>> universityDirectedKnowledgeMap = learnDirectedKnowledgeMapper.selectByUniversityIds(universityMap.keySet().toArray(new Long[universityMap.size()])).stream().collect(
+                Collectors.groupingBy(LearnDirectedKnowledge::getUniversityId, Collectors.toMap(LearnDirectedKnowledge::getDirectKey, a -> a)));
+        Map<Long, AMarjorPlan> planMap = marjorPlanMapper.selectAMarjorPlanByIds(planIdSet.toArray(new Long[planIdSet.size()])).stream().collect(Collectors.toMap(AMarjorPlan::getId, a -> a));
+
+        LearnDirectedKnowledge directedKnowledge = null;
+        String directedKey = null;
+
+        for(Long universityId : universityMap.keySet()) {
+            Map<String, LearnDirectedKnowledge> directedKnowledgeMap = universityDirectedKnowledgeMap.get(universityId);
+            for(LearnStudent ls : universityMap.get(universityId)) {
+                AMarjorPlan plan = planMap.get(ls.getMajorPlanId());
+                String groupName = StringUtils.trimToEmpty(plan.getMajorGroup());
+                if(CollectionUtils.isEmpty(paperDef.getKnowIds())) {
+                    if(null != (directedKnowledge = directedKnowledgeMap.get((directedKey = groupName + "_" + plan.getMajorName())))) {
+                        paperDef.setKnowIds(Stream.of(directedKnowledge.getKnowledges().split(",")).map(t -> Long.parseLong(t.trim())).collect(Collectors.toList()));
+                    } else if(null != (directedKnowledge = directedKnowledgeMap.get(directedKey = groupName))) {
+                        paperDef.setKnowIds(Stream.of(directedKnowledge.getKnowledges().split(",")).map(t -> Long.parseLong(t.trim())).collect(Collectors.toList()));
+                    } else {
+                        throw new ValidationException("院校没有配置定向知识点,生成失败: " + universityId + ":" + groupName + ":" + plan.getMajorName());
+                    }
+                } else if(null != directedKnowledgeMap) {
+                    if(null != (directedKnowledge = directedKnowledgeMap.get((directedKey = groupName + "_" + plan.getMajorName())))) {
+                    } else if(null != (directedKnowledge = directedKnowledgeMap.get(directedKey = groupName))) {
+                    } else {
+                        throw new ValidationException("院校没有配置定向知识点,生成失败" + universityId + ":" + directedKey);
+                    }
+                } else {
+                    throw new ValidationException("院校没有配置定向知识点,生成失败: " + universityId);
+                }
+                Map<String, LearnTestPaper> directPaperMap = universityDirectPaperMap.get(universityId);
+                if(null != directPaperMap && directPaperMap.containsKey(directedKey)) {
+                    continue;
+                }
+                LearnPaper paper = new LearnPaper();
+                paper.setSubjectId(req.getSubjectId());
+                paper.setPaperName(req.getTitle());
+                paper.setYear(plan.getYear());
+                paper.setPaperType(PaperType.Test.name());
+                paper.setDirectKey(directedKey);
+                Pair<LearnPaper, List<LearnPaperQuestion>> paperResult = paperService.buildPaper(null, paper, paperDef);
+                paperService.savePaper(paperResult.getKey(), paperResult.getValue());
+
+                LearnTestPaper testPaper = new LearnTestPaper();
+                testPaper.setBatchId(req.getBatchId());
+                testPaper.setUniversityId(universityId);
+                testPaper.setDirectKey(directedKey);
+                testPaper.setPaperId(paper.getId());
+                learnTestPaperMapper.insertLearnTestPaper(testPaper);
+                directPaperMap.put(directedKey, testPaper);
+            }
+        }
+        return "";
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public String buildPapersManual(TestPaperVO.TestPapersBuildManualReq req) {
+        if(null == req.getSubjectId()) {
+            throw new ValidationException("未选择科目");
+        }
+        // 查询 院校,专业组,专业计划范围, 明细一级时只有一个,否则就是批量
+        List<LearnStudent> studentList = learnStudentMapper.selectLearnStudentsByMap(req.toMap());
+        if(CollectionUtils.isEmpty(studentList)) {
+            throw new ValidationException("无可用计划可检查");
+        }
+        Set<Long> planIdSet = Sets.newHashSet();
+        Map<Long, List<LearnStudent>> universityMap = Maps.newHashMap();
+        for(LearnStudent ls : studentList){
+            planIdSet.add(ls.getMajorPlanId());
+            List<LearnStudent> list = universityMap.get(ls.getUniversityId());
+            if(null == list) {
+                list = Lists.newArrayList();
+                universityMap.put(ls.getUniversityId(), list);
+            }
+            list.add(ls);
+        }
+        // 查询已经生成的
+        Map<Long, Map<String, LearnTestPaper>> universityDirectPaperMap = learnTestPaperMapper.selectByBatchAndUniversityIds(req.getBatchId(), universityMap.keySet()).stream()
+                .collect(Collectors.groupingBy(LearnTestPaper::getUniversityId, Collectors.toMap(LearnTestPaper::getDirectKey, a -> a)));
+
+        LearnPaper paper = new LearnPaper();
+        paper.setPaperName(req.getTitle());
+        paper.setYear(Calendar.getInstance().get(Calendar.YEAR));
+        paper.setPaperType(PaperType.Test.name());
+        if(null == req.getDirectType() || !req.getDirectType()) { // 全量
+            paper.setSubjectId(req.getSubjectId());
+            paper.setDirectKey("");
+            for(Long universityId : universityMap.keySet()) {
+                Map<String, LearnTestPaper> directPaperMap = universityDirectPaperMap.get(universityId);
+                if(null != directPaperMap && directPaperMap.containsKey("")) {
+                    continue;
+                }
+                if(null == paper.getId()) {
+                    paperService.savePaper(paper, req.getQuestions());
+                }
+                LearnTestPaper testPaper = new LearnTestPaper();
+                testPaper.setBatchId(req.getBatchId());
+                testPaper.setUniversityId(universityId);
+                testPaper.setDirectKey("");
+                testPaper.setPaperId(paper.getId());
+                testPaper.setConditions("");
+                testPaper.setCreatorId(SecurityUtils.getUserId());
+                learnTestPaperMapper.insertLearnTestPaper(testPaper);
+            }
+            return "";
+        } // 定向
+        // 准备定向数据
+        Map<Long, Map<String, LearnDirectedKnowledge>> universityDirectedKnowledgeMap = learnDirectedKnowledgeMapper.selectByUniversityIds(universityMap.keySet().toArray(new Long[universityMap.size()])).stream().collect(
+                Collectors.groupingBy(LearnDirectedKnowledge::getUniversityId, Collectors.toMap(LearnDirectedKnowledge::getDirectKey, a -> a)));
+        Map<Long, AMarjorPlan> planMap = marjorPlanMapper.selectAMarjorPlanByIds(planIdSet.toArray(new Long[planIdSet.size()])).stream().collect(Collectors.toMap(AMarjorPlan::getId, a -> a));
+
+        String directedKey = null;
+        for(Long universityId : universityMap.keySet()) {
+            Map<String, LearnTestPaper> directPaperMap = universityDirectPaperMap.get(universityId);
+            Map<String, LearnDirectedKnowledge> directedKnowledgeMap = universityDirectedKnowledgeMap.get(universityId);
+            for(LearnStudent ls : universityMap.get(universityId)) { // Group+Name
+                AMarjorPlan plan = planMap.get(ls.getMajorPlanId());
+                String groupName = StringUtils.trimToEmpty(plan.getMajorGroup());
+                if(null != (directedKnowledgeMap.get(directedKey = groupName + "_" + plan.getMajorName()))) {
+                    if(null != directPaperMap.get(directedKey)) {
+                        continue;
+                    }
+                } else if(null != directedKnowledgeMap.get(directedKey = groupName)) {
+                    if(null != directPaperMap.get(directedKey)) {
+                        continue;
+                    }
+                } else {
+                    continue;
+                }
+                if(null == paper.getId()) {
+                    paperService.savePaper(paper, req.getQuestions());
+                }
+                LearnTestPaper testPaper = new LearnTestPaper();
+                testPaper.setBatchId(req.getBatchId());
+                testPaper.setUniversityId(universityId);
+                testPaper.setDirectKey(directedKey);
+                testPaper.setPaperId(paper.getId());
+                learnTestPaperMapper.insertLearnTestPaper(testPaper);
+                directPaperMap.put(directedKey, testPaper);
+            }
+        }
+        return "";
+    }
+
     public List<TreeNode> getKnowledgeTree(Long subjectId, Long[] planIds) {
     public List<TreeNode> getKnowledgeTree(Long subjectId, Long[] planIds) {
+        Set<Long> knowledgeIdSet = Sets.newHashSet();
+        if(ArrayUtils.isNotEmpty(planIds)) {
+            List<AMarjorPlan> planList = marjorPlanMapper.selectAMarjorPlanByIds(planIds);
+            AMarjorPlan curr = planList.get(0);
+            LearnDirectedKnowledge dkCond = new LearnDirectedKnowledge();
+            dkCond.setUniversityId(curr.getUniversityId());
+            dkCond.setYear(curr.getYear());
+            Map<String, LearnDirectedKnowledge> directedKnowledgeMap = learnDirectedKnowledgeMapper.selectLearnDirectedKnowledgeList(dkCond).stream().collect(Collectors.toMap(LearnDirectedKnowledge::getDirectKey, t -> t));
+            LearnDirectedKnowledge directedKnowledge = null;
+            for(AMarjorPlan plan : planList) {
+                String groupName = StringUtils.trimToEmpty(plan.getMajorGroup());
+                if(null != (directedKnowledge = directedKnowledgeMap.get(groupName + "_" + plan.getMajorName()))) {
+                    knowledgeIdSet.addAll(Stream.of(directedKnowledge.getKnowledges().split(",")).map(t -> Long.parseLong(t.trim())).collect(Collectors.toList()));
+                } else if(null != (directedKnowledge = directedKnowledgeMap.get(groupName))) {
+                    knowledgeIdSet.addAll(Stream.of(directedKnowledge.getKnowledges().split(",")).map(t -> Long.parseLong(t.trim())).collect(Collectors.toList()));
+                }
+            }
+        }
         LearnKnowledgeTree ktCond = new LearnKnowledgeTree();
         LearnKnowledgeTree ktCond = new LearnKnowledgeTree();
         ktCond.setSubjectId(subjectId);
         ktCond.setSubjectId(subjectId);
         List<LearnKnowledgeTree> ktList = learnKnowledgeTreeMapper.selectLearnKnowledgeTreeList(ktCond);
         List<LearnKnowledgeTree> ktList = learnKnowledgeTreeMapper.selectLearnKnowledgeTreeList(ktCond);
@@ -58,6 +297,9 @@ public class LearnTeacherService {
             }
             }
             teMap.get(kt.getPid()).getChildren().add(teMap.get(kt.getId()));
             teMap.get(kt.getPid()).getChildren().add(teMap.get(kt.getId()));
         }
         }
+        for(TreeNode tn : treeNodeList) {
+            tn.setChecked(knowledgeIdSet);
+        }
         return treeNodeList;
         return treeNodeList;
     }
     }
 
 
@@ -65,10 +307,32 @@ public class LearnTeacherService {
     public static class TreeNode {
     public static class TreeNode {
         private Long id;
         private Long id;
         private String name;
         private String name;
+        private Integer status;
         List<TreeNode> children = Lists.newArrayList();
         List<TreeNode> children = Lists.newArrayList();
         public TreeNode(Long id, String name) {
         public TreeNode(Long id, String name) {
             this.id = id;
             this.id = id;
             this.name = name;
             this.name = name;
+            this.status = 0;
+        }
+
+        public boolean setChecked(Set<Long> idSet) {
+            boolean checkSelf = idSet.contains(id);
+            if(CollectionUtils.isEmpty(children)) {
+                this.status = checkSelf ? 1 : 0;
+                return true;
+            }
+            int count = 0;
+            for(TreeNode tn : children) {
+                if(checkSelf || idSet.contains(tn.getId())) {
+                    tn.setStatus(1);
+                    count++;
+                }
+            }
+            if(children.size() == count) {
+                this.status = 1;
+                return true;
+            }
+            return false;
         }
         }
     }
     }
 }
 }

+ 9 - 28
ie-admin/src/main/java/com/ruoyi/web/service/PaperService.java

@@ -10,9 +10,7 @@ import com.ruoyi.enums.PaperStatus;
 import com.ruoyi.enums.PaperType;
 import com.ruoyi.enums.PaperType;
 import com.ruoyi.learn.domain.*;
 import com.ruoyi.learn.domain.*;
 import com.ruoyi.learn.mapper.*;
 import com.ruoyi.learn.mapper.*;
-import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.Data;
-import lombok.NoArgsConstructor;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.commons.lang3.tuple.Pair;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 
 
@@ -78,9 +76,9 @@ public class PaperService {
         paper.setStatus(PaperStatus.Valid.getVal());
         paper.setStatus(PaperStatus.Valid.getVal());
         paper.setDirectKey(directedKnowledge.getDirectKey());
         paper.setDirectKey(directedKnowledge.getDirectKey());
 
 
-        PaperService.PaperDef paperDef = JSONObject.parseObject(directedKnowledge.getConditions(), PaperDef.class);
+        TestPaperVO.PaperDef paperDef = JSONObject.parseObject(directedKnowledge.getConditions(), TestPaperVO.PaperDef.class);
         paperDef.setKnowIds(Stream.of(directedKnowledge.getKnowledges().split(",")).map(Long::valueOf).collect(Collectors.toList()));
         paperDef.setKnowIds(Stream.of(directedKnowledge.getKnowledges().split(",")).map(Long::valueOf).collect(Collectors.toList()));
-        paperDef.setTypes(JSONArray.parseArray(directedKnowledge.getQuestionTypes(), TypeDef.class));
+        paperDef.setTypes(JSONArray.parseArray(directedKnowledge.getQuestionTypes(), TestPaperVO.TypeDef.class));
         return buildPaper(null, paper, paperDef);
         return buildPaper(null, paper, paperDef);
     }
     }
 
 
@@ -91,7 +89,7 @@ public class PaperService {
      * @param paperDef
      * @param paperDef
      * @return
      * @return
      */
      */
-    public Pair<LearnPaper, List<LearnPaperQuestion>> buildPaper(Long studentId, LearnPaper paper, PaperService.PaperDef paperDef) {
+    public Pair<LearnPaper, List<LearnPaperQuestion>> buildPaper(Long studentId, LearnPaper paper, TestPaperVO.PaperDef paperDef) {
         if(null == studentId){
         if(null == studentId){
             paperDef.setFillExclude(false);
             paperDef.setFillExclude(false);
         }
         }
@@ -123,17 +121,17 @@ public class PaperService {
      * @param paperDef
      * @param paperDef
      * @return
      * @return
      */
      */
-    public List<LearnPaperQuestion> getQuestions(Long studentId, PaperDef paperDef) {
+    public List<LearnPaperQuestion> getQuestions(Long studentId, TestPaperVO.PaperDef paperDef) {
         // 题型分布定义, 知识点列表, 分值定义
         // 题型分布定义, 知识点列表, 分值定义
         // 统计知识点+类型的有效数量 TODO 总量可以缓存
         // 统计知识点+类型的有效数量 TODO 总量可以缓存
         Map<String, KnowTypeAssign> knowTypeAssignMap = Maps.newHashMap();
         Map<String, KnowTypeAssign> knowTypeAssignMap = Maps.newHashMap();
-        List<String> typeSet = paperDef.getTypes().stream().map(TypeDef::getType).collect(Collectors.toList());
+        List<String> typeSet = paperDef.getTypes().stream().map(TestPaperVO.TypeDef::getType).collect(Collectors.toList());
         Map cond = Maps.newHashMap();
         Map cond = Maps.newHashMap();
         cond.put("studentId", studentId);
         cond.put("studentId", studentId);
         cond.put("knowIds", paperDef.getKnowIds());
         cond.put("knowIds", paperDef.getKnowIds());
         cond.put("types", typeSet);
         cond.put("types", typeSet);
         setValue(knowTypeAssignMap, cond, 1); // 填充排除总量
         setValue(knowTypeAssignMap, cond, 1); // 填充排除总量
-        if (paperDef.fillExclude) {
+        if (paperDef.getFillExclude()) {
             cond.remove("studentId");
             cond.remove("studentId");
             setValue(knowTypeAssignMap, cond, 2); // 按需填充总量
             setValue(knowTypeAssignMap, cond, 2); // 按需填充总量
         }
         }
@@ -161,8 +159,8 @@ public class PaperService {
                     avgKnowTypeCount = 1L;
                     avgKnowTypeCount = 1L;
                 }
                 }
                 typeCount = 0;
                 typeCount = 0;
-                for (TypeDef typeDef : paperDef.getTypes()) {
-                    Long tmpMinKnowTypeCount = assignKnownCount(knowId, typeDef.getType(), knowTypeAssignMap, avgKnowTypeCount, paperDef.fillExclude, assignCount);
+                for (TestPaperVO.TypeDef typeDef : paperDef.getTypes()) {
+                    Long tmpMinKnowTypeCount = assignKnownCount(knowId, typeDef.getType(), knowTypeAssignMap, avgKnowTypeCount, paperDef.getFillExclude(), assignCount);
                     if (tmpMinKnowTypeCount > 0) {
                     if (tmpMinKnowTypeCount > 0) {
                         minKnowTypeCount = Math.min(minKnowTypeCount, tmpMinKnowTypeCount);
                         minKnowTypeCount = Math.min(minKnowTypeCount, tmpMinKnowTypeCount);
                         knowSet.add(knowId);
                         knowSet.add(knowId);
@@ -182,7 +180,7 @@ public class PaperService {
         Random random = new Random();
         Random random = new Random();
         List<LearnPaperQuestion> pqList = Lists.newArrayList();
         List<LearnPaperQuestion> pqList = Lists.newArrayList();
         Set<Long> existQuestionIdSet = Sets.newHashSet();
         Set<Long> existQuestionIdSet = Sets.newHashSet();
-        for (TypeDef typeDef : paperDef.getTypes()) {
+        for (TestPaperVO.TypeDef typeDef : paperDef.getTypes()) {
             for (Long knowId : paperDef.getKnowIds()) {
             for (Long knowId : paperDef.getKnowIds()) {
                 String key = knowId + "_" + typeDef.getType();
                 String key = knowId + "_" + typeDef.getType();
                 KnowTypeAssign ktc = knowTypeAssignMap.get(key);
                 KnowTypeAssign ktc = knowTypeAssignMap.get(key);
@@ -312,21 +310,4 @@ public class PaperService {
         Long exclCount; // 排除总数
         Long exclCount; // 排除总数
         Long total; // 全量总数
         Long total; // 全量总数
     }
     }
-
-    @Data
-    @AllArgsConstructor
-    @NoArgsConstructor
-    public static class TypeDef {
-        String title;
-        String type;
-        Integer count;
-        Integer score;
-    }
-    @Data
-    public static class PaperDef {
-        Long total;
-        List<Long> knowIds;
-        Boolean fillExclude; // 不足时是否填充排除的
-        List<TypeDef> types;
-    }
 }
 }

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

@@ -7,6 +7,7 @@ import com.ruoyi.common.exception.base.BaseException;
 import com.ruoyi.common.utils.bean.BeanUtils;
 import com.ruoyi.common.utils.bean.BeanUtils;
 import com.ruoyi.dz.domain.DzCards;
 import com.ruoyi.dz.domain.DzCards;
 import com.ruoyi.dz.service.IDzCardsService;
 import com.ruoyi.dz.service.IDzCardsService;
+import com.ruoyi.enums.UserTypeEnum;
 import com.ruoyi.framework.web.service.TokenService;
 import com.ruoyi.framework.web.service.TokenService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
@@ -147,6 +148,7 @@ public class SysRegisterService
             }
             }
         }
         }
         if(null == user.getUserId()) {
         if(null == user.getUserId()) {
+            user.setUserType(UserTypeEnum.Card.getVal());
             userService.insertUser(user);
             userService.insertUser(user);
         } else {
         } else {
             userService.updateUser(user);
             userService.updateUser(user);

+ 65 - 0
ie-common/src/main/java/com/ruoyi/common/enums/BoolValues.java

@@ -0,0 +1,65 @@
+package com.ruoyi.common.enums;
+
+import com.ruoyi.common.utils.StringUtils;
+
+/**
+ * 0否,1是
+ */
+public enum BoolValues {
+    other(-1, "其他"),
+    no(0, "否"),
+    yes(1, "是"),
+    ;
+
+    private Integer value;
+    private String remark;
+
+    private BoolValues(Integer value, String remark) {
+        this.value = value;
+        this.remark = remark;
+    }
+
+    public Integer getValue() {
+        return value;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public static BoolValues getByValue(String value) {
+        for (BoolValues o : BoolValues.values()) {
+            if (o.getValue().equals(value)) {
+                return o;
+            }
+        }
+        return null;
+    }
+
+    public static Boolean isTrue(Object value)
+    {
+        if(StringUtils.isNull(value)){
+            return false;
+        }
+        if(value instanceof Long||value instanceof Integer){
+            return BoolValues.yes.getValue()==Integer.parseInt(String.valueOf(value));
+        }
+        return false;
+    }
+
+    public static Boolean isOther(Object value)
+    {
+        if(StringUtils.isNull(value)){
+            return false;
+        }
+        if(value instanceof Long||value instanceof Integer){
+            return BoolValues.other.getValue()==Integer.parseInt(String.valueOf(value));
+        }
+        return false;
+    }
+
+    public static Boolean isFalse(Object value)
+    {
+        return !isTrue(value);
+    }
+}

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

@@ -1,11 +1,16 @@
 package com.ruoyi.dz.domain;
 package com.ruoyi.dz.domain;
 
 
 import com.ruoyi.common.core.domain.entity.SysDept;
 import com.ruoyi.common.core.domain.entity.SysDept;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
 import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.core.domain.TreeEntity;
 import com.ruoyi.common.core.domain.TreeEntity;
 
 
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
 /**
 /**
  * 机构代理对象 dz_agent
  * 机构代理对象 dz_agent
  *
  *
@@ -40,11 +45,30 @@ public class DzAgent extends TreeEntity
     /** 负责校区列表 */
     /** 负责校区列表 */
     @Excel(name = "负责校区列表")
     @Excel(name = "负责校区列表")
     private String schools;
     private String schools;
+    private Long[] schoolIds;
+    private String schoolName;
 
 
     private String username;
     private String username;
 
 
     private SysDept dept;
     private SysDept dept;
 
 
+    public String getSchoolName() {
+        return schoolName;
+    }
+
+    public void setSchoolName(String schoolName) {
+        this.schoolName = schoolName;
+    }
+
+    public Long[] getSchoolIds() {
+        return (null==schoolIds||schoolIds.length==0)?(StringUtils.isNotEmpty(schools)?
+                Arrays.stream(schools.split(",")).map(String::trim).filter(s -> !s.isEmpty()).map(Long::valueOf).toArray(Long[]::new):new Long[0]):schoolIds;
+    }
+
+    public void setSchoolIds(Long[] schoolIds) {
+        this.schoolIds = schoolIds;
+    }
+
     public SysDept getDept() {
     public SysDept getDept() {
         return dept;
         return dept;
     }
     }

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

@@ -17,6 +17,8 @@ public class DzClasses extends BaseEntity
 
 
     /** ID */
     /** ID */
     private Long classId;
     private Long classId;
+    private Long[] classIds;
+    private Long teacherId;
 
 
     /** 学校 */
     /** 学校 */
     @Excel(name = "学校")
     @Excel(name = "学校")
@@ -44,6 +46,22 @@ public class DzClasses extends BaseEntity
     @Excel(name = "统计数据")
     @Excel(name = "统计数据")
     private String stats;
     private String stats;
 
 
+    public Long[] getClassIds() {
+        return classIds;
+    }
+
+    public void setClassIds(Long[] classIds) {
+        this.classIds = classIds;
+    }
+
+    public Long getTeacherId() {
+        return teacherId;
+    }
+
+    public void setTeacherId(Long teacherId) {
+        this.teacherId = teacherId;
+    }
+
     public DzSchool getSchool() {
     public DzSchool getSchool() {
         return school;
         return school;
     }
     }

+ 12 - 1
ie-system/src/main/java/com/ruoyi/dz/domain/DzSchool.java

@@ -6,6 +6,8 @@ import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.core.domain.BaseEntity;
 import com.ruoyi.common.core.domain.BaseEntity;
 
 
+import java.util.List;
+
 /**
 /**
  * 机构校区对象 dz_school
  * 机构校区对象 dz_school
  *
  *
@@ -15,7 +17,6 @@ import com.ruoyi.common.core.domain.BaseEntity;
 public class DzSchool extends BaseEntity
 public class DzSchool extends BaseEntity
 {
 {
     private static final long serialVersionUID = 1L;
     private static final long serialVersionUID = 1L;
-
     /** $column.columnComment */
     /** $column.columnComment */
     private Long id;
     private Long id;
 
 
@@ -43,12 +44,22 @@ public class DzSchool extends BaseEntity
     @Excel(name = "区")
     @Excel(name = "区")
     private Long area;
     private Long area;
 
 
+    String proCityAreaName ;
+
     /** 状态(0:无效,1:有效) */
     /** 状态(0:无效,1:有效) */
     @Excel(name = "状态(0:无效,1:有效)")
     @Excel(name = "状态(0:无效,1:有效)")
     private Integer status;
     private Integer status;
 
 
     private SysDept dept;
     private SysDept dept;
 
 
+    public String getProCityAreaName() {
+        return proCityAreaName;
+    }
+
+    public void setProCityAreaName(String proCityAreaName) {
+        this.proCityAreaName = proCityAreaName;
+    }
+
     public SysDept getDept() {
     public SysDept getDept() {
         return dept;
         return dept;
     }
     }

+ 2 - 1
ie-system/src/main/java/com/ruoyi/dz/domain/DzTeacher.java

@@ -63,9 +63,10 @@ public class DzTeacher extends BaseEntity
         this.username = username;
         this.username = username;
     }
     }
 
 
-    public void setTeacherId(Long teacherId)
+    public DzTeacher setTeacherId(Long teacherId)
     {
     {
         this.teacherId = teacherId;
         this.teacherId = teacherId;
+        return this;
     }
     }
 
 
     public Long getTeacherId()
     public Long getTeacherId()

+ 27 - 17
ie-system/src/main/java/com/ruoyi/dz/domain/DzTeacherClass.java

@@ -9,7 +9,7 @@ import com.ruoyi.common.core.domain.BaseEntity;
 
 
 /**
 /**
  * 教师班级关系对象 dz_teacher_class
  * 教师班级关系对象 dz_teacher_class
- * 
+ *
  * @author ruoyi
  * @author ruoyi
  * @date 2025-09-12
  * @date 2025-09-12
  */
  */
@@ -18,7 +18,7 @@ public class DzTeacherClass extends BaseEntity
     private static final long serialVersionUID = 1L;
     private static final long serialVersionUID = 1L;
 
 
     /** 标识 */
     /** 标识 */
-    private String id;
+    private Long id;
 
 
     /** 老师id */
     /** 老师id */
     @Excel(name = "老师id")
     @Excel(name = "老师id")
@@ -26,73 +26,83 @@ public class DzTeacherClass extends BaseEntity
 
 
     /** 班级id */
     /** 班级id */
     @Excel(name = "班级id")
     @Excel(name = "班级id")
-    private Long classesId;
+    private Long classId;
+    private Long[] classIds;
 
 
     /** 有效状态 */
     /** 有效状态 */
     @Excel(name = "有效状态")
     @Excel(name = "有效状态")
-    private Long status;
+    private Integer status;
 
 
     /** 结束日期 */
     /** 结束日期 */
     @JsonFormat(pattern = "yyyy-MM-dd")
     @JsonFormat(pattern = "yyyy-MM-dd")
     @Excel(name = "结束日期", width = 30, dateFormat = "yyyy-MM-dd")
     @Excel(name = "结束日期", width = 30, dateFormat = "yyyy-MM-dd")
     private Date outDate;
     private Date outDate;
 
 
-    public void setId(String id) 
+    public void setId(Long id)
     {
     {
         this.id = id;
         this.id = id;
     }
     }
 
 
-    public String getId() 
+    public Long getId()
     {
     {
         return id;
         return id;
     }
     }
 
 
-    public void setTeacherId(Long teacherId) 
+    public DzTeacherClass setTeacherId(Long teacherId)
     {
     {
         this.teacherId = teacherId;
         this.teacherId = teacherId;
+        return this;
     }
     }
 
 
-    public Long getTeacherId() 
+    public Long getTeacherId()
     {
     {
         return teacherId;
         return teacherId;
     }
     }
 
 
-    public void setClassesId(Long classesId) 
+    public void setClassId(Long classId)
     {
     {
-        this.classesId = classesId;
+        this.classId = classId;
     }
     }
 
 
-    public Long getClassesId() 
+    public Long getClassId()
     {
     {
-        return classesId;
+        return classId;
     }
     }
 
 
-    public void setStatus(Long status) 
+    public void setStatus(Integer status)
     {
     {
         this.status = status;
         this.status = status;
     }
     }
 
 
-    public Long getStatus() 
+    public Integer getStatus()
     {
     {
         return status;
         return status;
     }
     }
 
 
-    public void setOutDate(Date outDate) 
+    public void setOutDate(Date outDate)
     {
     {
         this.outDate = outDate;
         this.outDate = outDate;
     }
     }
 
 
-    public Date getOutDate() 
+    public Date getOutDate()
     {
     {
         return outDate;
         return outDate;
     }
     }
 
 
+    public Long[] getClassIds() {
+        return classIds;
+    }
+
+    public void setClassIds(Long[] classIds) {
+        this.classIds = classIds;
+    }
+
     @Override
     @Override
     public String toString() {
     public String toString() {
         return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
         return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
             .append("id", getId())
             .append("id", getId())
             .append("teacherId", getTeacherId())
             .append("teacherId", getTeacherId())
-            .append("classesId", getClassesId())
+            .append("classId", getClassId())
             .append("status", getStatus())
             .append("status", getStatus())
             .append("remark", getRemark())
             .append("remark", getRemark())
             .append("outDate", getOutDate())
             .append("outDate", getOutDate())

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

@@ -5,15 +5,15 @@ import com.ruoyi.dz.domain.DzSchool;
 
 
 /**
 /**
  * 机构校区Mapper接口
  * 机构校区Mapper接口
- * 
+ *
  * @author ruoyi
  * @author ruoyi
  * @date 2025-09-12
  * @date 2025-09-12
  */
  */
-public interface DzSchoolMapper 
+public interface DzSchoolMapper
 {
 {
     /**
     /**
      * 查询机构校区
      * 查询机构校区
-     * 
+     *
      * @param id 机构校区主键
      * @param id 机构校区主键
      * @return 机构校区
      * @return 机构校区
      */
      */
@@ -21,15 +21,15 @@ public interface DzSchoolMapper
 
 
     /**
     /**
      * 查询机构校区列表
      * 查询机构校区列表
-     * 
+     *
      * @param dzSchool 机构校区
      * @param dzSchool 机构校区
      * @return 机构校区集合
      * @return 机构校区集合
      */
      */
     public List<DzSchool> selectDzSchoolList(DzSchool dzSchool);
     public List<DzSchool> selectDzSchoolList(DzSchool dzSchool);
-
+    public List<DzSchool> selectDzSchoolListByIds(List<Long> schoolIds);
     /**
     /**
      * 新增机构校区
      * 新增机构校区
-     * 
+     *
      * @param dzSchool 机构校区
      * @param dzSchool 机构校区
      * @return 结果
      * @return 结果
      */
      */
@@ -37,7 +37,7 @@ public interface DzSchoolMapper
 
 
     /**
     /**
      * 修改机构校区
      * 修改机构校区
-     * 
+     *
      * @param dzSchool 机构校区
      * @param dzSchool 机构校区
      * @return 结果
      * @return 结果
      */
      */
@@ -45,7 +45,7 @@ public interface DzSchoolMapper
 
 
     /**
     /**
      * 删除机构校区
      * 删除机构校区
-     * 
+     *
      * @param id 机构校区主键
      * @param id 机构校区主键
      * @return 结果
      * @return 结果
      */
      */
@@ -53,7 +53,7 @@ public interface DzSchoolMapper
 
 
     /**
     /**
      * 批量删除机构校区
      * 批量删除机构校区
-     * 
+     *
      * @param ids 需要删除的数据主键集合
      * @param ids 需要删除的数据主键集合
      * @return 结果
      * @return 结果
      */
      */

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

@@ -5,15 +5,15 @@ import com.ruoyi.dz.domain.DzTeacherClass;
 
 
 /**
 /**
  * 教师班级关系Mapper接口
  * 教师班级关系Mapper接口
- * 
+ *
  * @author ruoyi
  * @author ruoyi
  * @date 2025-09-12
  * @date 2025-09-12
  */
  */
-public interface DzTeacherClassMapper 
+public interface DzTeacherClassMapper
 {
 {
     /**
     /**
      * 查询教师班级关系
      * 查询教师班级关系
-     * 
+     *
      * @param id 教师班级关系主键
      * @param id 教师班级关系主键
      * @return 教师班级关系
      * @return 教师班级关系
      */
      */
@@ -21,7 +21,7 @@ public interface DzTeacherClassMapper
 
 
     /**
     /**
      * 查询教师班级关系列表
      * 查询教师班级关系列表
-     * 
+     *
      * @param dzTeacherClass 教师班级关系
      * @param dzTeacherClass 教师班级关系
      * @return 教师班级关系集合
      * @return 教师班级关系集合
      */
      */
@@ -29,15 +29,15 @@ public interface DzTeacherClassMapper
 
 
     /**
     /**
      * 新增教师班级关系
      * 新增教师班级关系
-     * 
+     *
      * @param dzTeacherClass 教师班级关系
      * @param dzTeacherClass 教师班级关系
      * @return 结果
      * @return 结果
      */
      */
     public int insertDzTeacherClass(DzTeacherClass dzTeacherClass);
     public int insertDzTeacherClass(DzTeacherClass dzTeacherClass);
-
+    public int insertBatch(List<DzTeacherClass> list);
     /**
     /**
      * 修改教师班级关系
      * 修改教师班级关系
-     * 
+     *
      * @param dzTeacherClass 教师班级关系
      * @param dzTeacherClass 教师班级关系
      * @return 结果
      * @return 结果
      */
      */
@@ -45,7 +45,7 @@ public interface DzTeacherClassMapper
 
 
     /**
     /**
      * 删除教师班级关系
      * 删除教师班级关系
-     * 
+     *
      * @param id 教师班级关系主键
      * @param id 教师班级关系主键
      * @return 结果
      * @return 结果
      */
      */
@@ -53,7 +53,7 @@ public interface DzTeacherClassMapper
 
 
     /**
     /**
      * 批量删除教师班级关系
      * 批量删除教师班级关系
-     * 
+     *
      * @param ids 需要删除的数据主键集合
      * @param ids 需要删除的数据主键集合
      * @return 结果
      * @return 结果
      */
      */

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

@@ -5,15 +5,15 @@ import com.ruoyi.dz.domain.DzSchool;
 
 
 /**
 /**
  * 机构校区Service接口
  * 机构校区Service接口
- * 
+ *
  * @author ruoyi
  * @author ruoyi
  * @date 2025-09-12
  * @date 2025-09-12
  */
  */
-public interface IDzSchoolService 
+public interface IDzSchoolService
 {
 {
     /**
     /**
      * 查询机构校区
      * 查询机构校区
-     * 
+     *
      * @param id 机构校区主键
      * @param id 机构校区主键
      * @return 机构校区
      * @return 机构校区
      */
      */
@@ -21,15 +21,15 @@ public interface IDzSchoolService
 
 
     /**
     /**
      * 查询机构校区列表
      * 查询机构校区列表
-     * 
+     *
      * @param dzSchool 机构校区
      * @param dzSchool 机构校区
      * @return 机构校区集合
      * @return 机构校区集合
      */
      */
     public List<DzSchool> selectDzSchoolList(DzSchool dzSchool);
     public List<DzSchool> selectDzSchoolList(DzSchool dzSchool);
-
+    public List<DzSchool> selectDzSchoolListByIds(List<Long> schoolIds);
     /**
     /**
      * 新增机构校区
      * 新增机构校区
-     * 
+     *
      * @param dzSchool 机构校区
      * @param dzSchool 机构校区
      * @return 结果
      * @return 结果
      */
      */
@@ -37,7 +37,7 @@ public interface IDzSchoolService
 
 
     /**
     /**
      * 修改机构校区
      * 修改机构校区
-     * 
+     *
      * @param dzSchool 机构校区
      * @param dzSchool 机构校区
      * @return 结果
      * @return 结果
      */
      */
@@ -45,7 +45,7 @@ public interface IDzSchoolService
 
 
     /**
     /**
      * 批量删除机构校区
      * 批量删除机构校区
-     * 
+     *
      * @param ids 需要删除的机构校区主键集合
      * @param ids 需要删除的机构校区主键集合
      * @return 结果
      * @return 结果
      */
      */
@@ -53,7 +53,7 @@ public interface IDzSchoolService
 
 
     /**
     /**
      * 删除机构校区信息
      * 删除机构校区信息
-     * 
+     *
      * @param id 机构校区主键
      * @param id 机构校区主键
      * @return 结果
      * @return 结果
      */
      */

+ 9 - 8
ie-system/src/main/java/com/ruoyi/dz/service/IDzTeacherClassService.java

@@ -5,15 +5,15 @@ import com.ruoyi.dz.domain.DzTeacherClass;
 
 
 /**
 /**
  * 教师班级关系Service接口
  * 教师班级关系Service接口
- * 
+ *
  * @author ruoyi
  * @author ruoyi
  * @date 2025-09-12
  * @date 2025-09-12
  */
  */
-public interface IDzTeacherClassService 
+public interface IDzTeacherClassService
 {
 {
     /**
     /**
      * 查询教师班级关系
      * 查询教师班级关系
-     * 
+     *
      * @param id 教师班级关系主键
      * @param id 教师班级关系主键
      * @return 教师班级关系
      * @return 教师班级关系
      */
      */
@@ -21,7 +21,7 @@ public interface IDzTeacherClassService
 
 
     /**
     /**
      * 查询教师班级关系列表
      * 查询教师班级关系列表
-     * 
+     *
      * @param dzTeacherClass 教师班级关系
      * @param dzTeacherClass 教师班级关系
      * @return 教师班级关系集合
      * @return 教师班级关系集合
      */
      */
@@ -29,15 +29,16 @@ public interface IDzTeacherClassService
 
 
     /**
     /**
      * 新增教师班级关系
      * 新增教师班级关系
-     * 
+     *
      * @param dzTeacherClass 教师班级关系
      * @param dzTeacherClass 教师班级关系
      * @return 结果
      * @return 结果
      */
      */
     public int insertDzTeacherClass(DzTeacherClass dzTeacherClass);
     public int insertDzTeacherClass(DzTeacherClass dzTeacherClass);
+    public int insertBatch(List<DzTeacherClass> list);
 
 
     /**
     /**
      * 修改教师班级关系
      * 修改教师班级关系
-     * 
+     *
      * @param dzTeacherClass 教师班级关系
      * @param dzTeacherClass 教师班级关系
      * @return 结果
      * @return 结果
      */
      */
@@ -45,7 +46,7 @@ public interface IDzTeacherClassService
 
 
     /**
     /**
      * 批量删除教师班级关系
      * 批量删除教师班级关系
-     * 
+     *
      * @param ids 需要删除的教师班级关系主键集合
      * @param ids 需要删除的教师班级关系主键集合
      * @return 结果
      * @return 结果
      */
      */
@@ -53,7 +54,7 @@ public interface IDzTeacherClassService
 
 
     /**
     /**
      * 删除教师班级关系信息
      * 删除教师班级关系信息
-     * 
+     *
      * @param id 教师班级关系主键
      * @param id 教师班级关系主键
      * @return 结果
      * @return 结果
      */
      */

+ 14 - 8
ie-system/src/main/java/com/ruoyi/dz/service/impl/DzSchoolServiceImpl.java

@@ -10,19 +10,19 @@ import com.ruoyi.dz.service.IDzSchoolService;
 
 
 /**
 /**
  * 机构校区Service业务层处理
  * 机构校区Service业务层处理
- * 
+ *
  * @author ruoyi
  * @author ruoyi
  * @date 2025-09-12
  * @date 2025-09-12
  */
  */
 @Service
 @Service
-public class DzSchoolServiceImpl implements IDzSchoolService 
+public class DzSchoolServiceImpl implements IDzSchoolService
 {
 {
     @Autowired
     @Autowired
     private DzSchoolMapper dzSchoolMapper;
     private DzSchoolMapper dzSchoolMapper;
 
 
     /**
     /**
      * 查询机构校区
      * 查询机构校区
-     * 
+     *
      * @param id 机构校区主键
      * @param id 机构校区主键
      * @return 机构校区
      * @return 机构校区
      */
      */
@@ -34,7 +34,7 @@ public class DzSchoolServiceImpl implements IDzSchoolService
 
 
     /**
     /**
      * 查询机构校区列表
      * 查询机构校区列表
-     * 
+     *
      * @param dzSchool 机构校区
      * @param dzSchool 机构校区
      * @return 机构校区
      * @return 机构校区
      */
      */
@@ -44,9 +44,15 @@ public class DzSchoolServiceImpl implements IDzSchoolService
         return dzSchoolMapper.selectDzSchoolList(dzSchool);
         return dzSchoolMapper.selectDzSchoolList(dzSchool);
     }
     }
 
 
+    @Override
+    public List<DzSchool> selectDzSchoolListByIds(List<Long> schoolIds)
+    {
+        return dzSchoolMapper.selectDzSchoolListByIds(schoolIds);
+    }
+
     /**
     /**
      * 新增机构校区
      * 新增机构校区
-     * 
+     *
      * @param dzSchool 机构校区
      * @param dzSchool 机构校区
      * @return 结果
      * @return 结果
      */
      */
@@ -59,7 +65,7 @@ public class DzSchoolServiceImpl implements IDzSchoolService
 
 
     /**
     /**
      * 修改机构校区
      * 修改机构校区
-     * 
+     *
      * @param dzSchool 机构校区
      * @param dzSchool 机构校区
      * @return 结果
      * @return 结果
      */
      */
@@ -72,7 +78,7 @@ public class DzSchoolServiceImpl implements IDzSchoolService
 
 
     /**
     /**
      * 批量删除机构校区
      * 批量删除机构校区
-     * 
+     *
      * @param ids 需要删除的机构校区主键
      * @param ids 需要删除的机构校区主键
      * @return 结果
      * @return 结果
      */
      */
@@ -84,7 +90,7 @@ public class DzSchoolServiceImpl implements IDzSchoolService
 
 
     /**
     /**
      * 删除机构校区信息
      * 删除机构校区信息
-     * 
+     *
      * @param id 机构校区主键
      * @param id 机构校区主键
      * @return 结果
      * @return 结果
      */
      */

+ 13 - 8
ie-system/src/main/java/com/ruoyi/dz/service/impl/DzTeacherClassServiceImpl.java

@@ -9,19 +9,19 @@ import com.ruoyi.dz.service.IDzTeacherClassService;
 
 
 /**
 /**
  * 教师班级关系Service业务层处理
  * 教师班级关系Service业务层处理
- * 
+ *
  * @author ruoyi
  * @author ruoyi
  * @date 2025-09-12
  * @date 2025-09-12
  */
  */
 @Service
 @Service
-public class DzTeacherClassServiceImpl implements IDzTeacherClassService 
+public class DzTeacherClassServiceImpl implements IDzTeacherClassService
 {
 {
     @Autowired
     @Autowired
     private DzTeacherClassMapper dzTeacherClassMapper;
     private DzTeacherClassMapper dzTeacherClassMapper;
 
 
     /**
     /**
      * 查询教师班级关系
      * 查询教师班级关系
-     * 
+     *
      * @param id 教师班级关系主键
      * @param id 教师班级关系主键
      * @return 教师班级关系
      * @return 教师班级关系
      */
      */
@@ -33,7 +33,7 @@ public class DzTeacherClassServiceImpl implements IDzTeacherClassService
 
 
     /**
     /**
      * 查询教师班级关系列表
      * 查询教师班级关系列表
-     * 
+     *
      * @param dzTeacherClass 教师班级关系
      * @param dzTeacherClass 教师班级关系
      * @return 教师班级关系
      * @return 教师班级关系
      */
      */
@@ -45,7 +45,7 @@ public class DzTeacherClassServiceImpl implements IDzTeacherClassService
 
 
     /**
     /**
      * 新增教师班级关系
      * 新增教师班级关系
-     * 
+     *
      * @param dzTeacherClass 教师班级关系
      * @param dzTeacherClass 教师班级关系
      * @return 结果
      * @return 结果
      */
      */
@@ -55,9 +55,14 @@ public class DzTeacherClassServiceImpl implements IDzTeacherClassService
         return dzTeacherClassMapper.insertDzTeacherClass(dzTeacherClass);
         return dzTeacherClassMapper.insertDzTeacherClass(dzTeacherClass);
     }
     }
 
 
+    @Override
+    public int insertBatch(List<DzTeacherClass> list) {
+        return dzTeacherClassMapper.insertBatch(list);
+    }
+
     /**
     /**
      * 修改教师班级关系
      * 修改教师班级关系
-     * 
+     *
      * @param dzTeacherClass 教师班级关系
      * @param dzTeacherClass 教师班级关系
      * @return 结果
      * @return 结果
      */
      */
@@ -69,7 +74,7 @@ public class DzTeacherClassServiceImpl implements IDzTeacherClassService
 
 
     /**
     /**
      * 批量删除教师班级关系
      * 批量删除教师班级关系
-     * 
+     *
      * @param ids 需要删除的教师班级关系主键
      * @param ids 需要删除的教师班级关系主键
      * @return 结果
      * @return 结果
      */
      */
@@ -81,7 +86,7 @@ public class DzTeacherClassServiceImpl implements IDzTeacherClassService
 
 
     /**
     /**
      * 删除教师班级关系信息
      * 删除教师班级关系信息
-     * 
+     *
      * @param id 教师班级关系主键
      * @param id 教师班级关系主键
      * @return 结果
      * @return 结果
      */
      */

+ 1 - 0
ie-system/src/main/java/com/ruoyi/ie/mapper/AMarjorPlanMapper.java

@@ -14,6 +14,7 @@ import org.apache.ibatis.annotations.Param;
  */
  */
 public interface AMarjorPlanMapper 
 public interface AMarjorPlanMapper 
 {
 {
+    public List<AMarjorPlan> selectAMarjorPlanByIds(Long[] ids);
     public List<AMarjorPlan>  selectMajorForUniversity(@Param("universityId") Long universityId, @Param("year") Integer year, @Param("batchId") Long batchId);
     public List<AMarjorPlan>  selectMajorForUniversity(@Param("universityId") Long universityId, @Param("year") Integer year, @Param("batchId") Long batchId);
     /**
     /**
      * 查询专业计划要求
      * 查询专业计划要求

+ 12 - 1
ie-system/src/main/java/com/ruoyi/learn/domain/LearnDirectedKnowledge.java

@@ -22,6 +22,9 @@ public class LearnDirectedKnowledge extends BaseEntity
     @Excel(name = "年度")
     @Excel(name = "年度")
     private Integer year;
     private Integer year;
 
 
+    @Excel(name = "院校ID")
+    private Long universityId;
+
     /** 定向Key */
     /** 定向Key */
     @Excel(name = "定向Key")
     @Excel(name = "定向Key")
     private String directKey;
     private String directKey;
@@ -82,7 +85,15 @@ public class LearnDirectedKnowledge extends BaseEntity
         return year;
         return year;
     }
     }
 
 
-    public void setDirectKey(String directKey) 
+    public Long getUniversityId() {
+        return universityId;
+    }
+
+    public void setUniversityId(Long universityId) {
+        this.universityId = universityId;
+    }
+
+    public void setDirectKey(String directKey)
     {
     {
         this.directKey = directKey;
         this.directKey = directKey;
     }
     }

+ 22 - 0
ie-system/src/main/java/com/ruoyi/learn/domain/LearnPaperQuestion.java

@@ -34,6 +34,12 @@ public class LearnPaperQuestion extends BaseEntity
     @Excel(name = "分值")
     @Excel(name = "分值")
     private Integer score;
     private Integer score;
 
 
+    @Excel(name = "题型")
+    private String type;
+
+    @Excel(name = "难度")
+    private Integer diff;
+
     public void setId(Long id) 
     public void setId(Long id) 
     {
     {
         this.id = id;
         this.id = id;
@@ -84,6 +90,22 @@ public class LearnPaperQuestion extends BaseEntity
         return score;
         return score;
     }
     }
 
 
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public Integer getDiff() {
+        return diff;
+    }
+
+    public void setDiff(Integer diff) {
+        this.diff = diff;
+    }
+
     @Override
     @Override
     public String toString() {
     public String toString() {
         return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
         return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)

+ 23 - 13
ie-system/src/main/java/com/ruoyi/learn/domain/LearnTestPaper.java

@@ -20,7 +20,11 @@ public class LearnTestPaper extends BaseEntity
 
 
     /** 批次id */
     /** 批次id */
     @Excel(name = "批次id")
     @Excel(name = "批次id")
-    private Long batchId;
+    private Integer batchId;
+
+    /** 院校id */
+    @Excel(name = "院校id")
+    private Long universityId;
 
 
     /** 定向key */
     /** 定向key */
     @Excel(name = "定向key")
     @Excel(name = "定向key")
@@ -32,7 +36,7 @@ public class LearnTestPaper extends BaseEntity
 
 
     /** 试卷生成条件 */
     /** 试卷生成条件 */
     @Excel(name = "试卷生成条件")
     @Excel(name = "试卷生成条件")
-    private String condions;
+    private String conditions;
 
 
     /** 创建人 */
     /** 创建人 */
     @Excel(name = "创建人")
     @Excel(name = "创建人")
@@ -48,17 +52,25 @@ public class LearnTestPaper extends BaseEntity
         return id;
         return id;
     }
     }
 
 
-    public void setBatchId(Long batchId) 
+    public void setBatchId(Integer batchId)
     {
     {
         this.batchId = batchId;
         this.batchId = batchId;
     }
     }
 
 
-    public Long getBatchId() 
+    public Integer getBatchId()
     {
     {
         return batchId;
         return batchId;
     }
     }
 
 
-    public void setDirectKey(String directKey) 
+    public Long getUniversityId() {
+        return universityId;
+    }
+
+    public void setUniversityId(Long universityId) {
+        this.universityId = universityId;
+    }
+
+    public void setDirectKey(String directKey)
     {
     {
         this.directKey = directKey;
         this.directKey = directKey;
     }
     }
@@ -78,17 +90,15 @@ public class LearnTestPaper extends BaseEntity
         return paperId;
         return paperId;
     }
     }
 
 
-    public void setCondions(String condions) 
-    {
-        this.condions = condions;
+    public String getConditions() {
+        return conditions;
     }
     }
 
 
-    public String getCondions() 
-    {
-        return condions;
+    public void setConditions(String conditions) {
+        this.conditions = conditions;
     }
     }
 
 
-    public void setCreatorId(Long creatorId) 
+    public void setCreatorId(Long creatorId)
     {
     {
         this.creatorId = creatorId;
         this.creatorId = creatorId;
     }
     }
@@ -105,7 +115,7 @@ public class LearnTestPaper extends BaseEntity
             .append("batchId", getBatchId())
             .append("batchId", getBatchId())
             .append("directKey", getDirectKey())
             .append("directKey", getDirectKey())
             .append("paperId", getPaperId())
             .append("paperId", getPaperId())
-            .append("condions", getCondions())
+            .append("conditions", getConditions())
             .append("creatorId", getCreatorId())
             .append("creatorId", getCreatorId())
             .append("createTime", getCreateTime())
             .append("createTime", getCreateTime())
             .toString();
             .toString();

+ 70 - 14
ie-system/src/main/java/com/ruoyi/learn/domain/TestPaperVO.java

@@ -1,38 +1,75 @@
 package com.ruoyi.learn.domain;
 package com.ruoyi.learn.domain;
 
 
+import com.google.common.collect.Maps;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.Data;
+import lombok.NoArgsConstructor;
 
 
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
 
 
 public class TestPaperVO {
 public class TestPaperVO {
-    enum PaperBuildType {
+    public static enum PaperBuildType {
         Manual, Auto
         Manual, Auto
     }
     }
 
 
-    @ApiModel("批量组卷请求")
+    @ApiModel("基本组卷请求")
     @Data
     @Data
     public static class TestPapersBuildReq {
     public static class TestPapersBuildReq {
-        @ApiModelProperty("班级")
-        List<Long> classIds;
-        @ApiModelProperty("考生类型")
-        List<String> examTypes;
-        @ApiModelProperty("组卷类型")
+        @ApiModelProperty("名称")
+        String title;
+        @ApiModelProperty("总分")
+        Integer total;
+
+        @ApiModelProperty("批次")
+        Integer batchId;
+        @ApiModelProperty("省份")
+        String location;
+        @ApiModelProperty("组卷方式")
         PaperBuildType buildType;
         PaperBuildType buildType;
-        @ApiModelProperty("定向类型 null是全部")
+        @ApiModelProperty("是否定向")
         Boolean directType;
         Boolean directType;
+
+        @ApiModelProperty("科目")
+        Long subjectId;
+
+        @ApiModelProperty("考生类型")
+        List<String> examTypes;
+        @ApiModelProperty("班级")
+        List<Long> classIds;
         @ApiModelProperty("院校")
         @ApiModelProperty("院校")
         List<Long> universityIds;
         List<Long> universityIds;
         @ApiModelProperty("专业组(单院校有效)")
         @ApiModelProperty("专业组(单院校有效)")
         List<String> groups;
         List<String> groups;
-        @ApiModelProperty("科目")
-        List<Integer> subjectIds;
-        @ApiModelProperty("知识点")
-        List<Long> knowledgeIds;
-        @ApiModelProperty("题型要求")
-        Map<String, Integer> questionTypeNum;
+        @ApiModelProperty("专业组(单专业组有效)")
+        List<Long> planIds;
+
+        public Map<String, Object> toMap() {
+            Map<String, Object> map = Maps.newHashMap();
+            map.put("batchId", batchId);
+            map.put("location", location);
+            map.put("examTypes", examTypes);
+            map.put("classIds", classIds);
+            map.put("universityIds", universityIds);
+            map.put("groups", groups);
+            map.put("planIds", planIds);
+            return map;
+        }
+    }
+
+    @ApiModel("手动组卷请求")
+    @Data
+    public static class TestPapersBuildManualReq extends TestPapersBuildReq {
+        @ApiModelProperty("试题列表")
+        List<LearnPaperQuestion> questions;
+    }
+    @ApiModel("智能组卷请求")
+    @Data
+    public static class TestPapersBuildAutoReq extends TestPapersBuildReq {
+        @ApiModelProperty("试卷要求")
+        PaperDef paperDef;
     }
     }
 
 
     @ApiModel("批量查询请求")
     @ApiModel("批量查询请求")
@@ -86,4 +123,23 @@ public class TestPaperVO {
         @ApiModelProperty("学生")
         @ApiModelProperty("学生")
         List<Long> studentIds;
         List<Long> studentIds;
     }
     }
+
+
+    @Data
+    public static class PaperDef {
+        Long total;
+        List<Long> knowIds;
+        Boolean fillExclude; // 不足时是否填充排除的
+        List<TestPaperVO.TypeDef> types;
+    }
+
+    @Data
+    @AllArgsConstructor
+    @NoArgsConstructor
+    public static class TypeDef {
+        String title;
+        String type;
+        Integer count;
+        Integer score;
+    }
 }
 }

+ 2 - 0
ie-system/src/main/java/com/ruoyi/learn/mapper/LearnDirectedKnowledgeMapper.java

@@ -11,6 +11,8 @@ import com.ruoyi.learn.domain.LearnDirectedKnowledge;
  */
  */
 public interface LearnDirectedKnowledgeMapper 
 public interface LearnDirectedKnowledgeMapper 
 {
 {
+    public List<LearnDirectedKnowledge> selectByUniversityIds(Long[] universityIds);
+
     /**
     /**
      * 查询定向知识点关系
      * 查询定向知识点关系
      * 
      * 

+ 4 - 0
ie-system/src/main/java/com/ruoyi/learn/mapper/LearnStudentMapper.java

@@ -1,6 +1,8 @@
 package com.ruoyi.learn.mapper;
 package com.ruoyi.learn.mapper;
 
 
 import java.util.List;
 import java.util.List;
+import java.util.Map;
+
 import com.ruoyi.learn.domain.LearnStudent;
 import com.ruoyi.learn.domain.LearnStudent;
 
 
 /**
 /**
@@ -11,6 +13,8 @@ import com.ruoyi.learn.domain.LearnStudent;
  */
  */
 public interface LearnStudentMapper 
 public interface LearnStudentMapper 
 {
 {
+    public List<LearnStudent> selectLearnStudentsByMap(Map cond);
+
     /**
     /**
      * 查询学生
      * 查询学生
      * 
      * 

+ 4 - 0
ie-system/src/main/java/com/ruoyi/learn/mapper/LearnTestPaperMapper.java

@@ -1,7 +1,9 @@
 package com.ruoyi.learn.mapper;
 package com.ruoyi.learn.mapper;
 
 
+import java.util.Collection;
 import java.util.List;
 import java.util.List;
 import com.ruoyi.learn.domain.LearnTestPaper;
 import com.ruoyi.learn.domain.LearnTestPaper;
+import org.apache.ibatis.annotations.Param;
 
 
 /**
 /**
  * 批次测试卷Mapper接口
  * 批次测试卷Mapper接口
@@ -11,6 +13,8 @@ import com.ruoyi.learn.domain.LearnTestPaper;
  */
  */
 public interface LearnTestPaperMapper 
 public interface LearnTestPaperMapper 
 {
 {
+    public List<LearnTestPaper> selectByBatchAndUniversityIds(@Param("batchId") Integer batchId, @Param("universityIds") Collection<Long> universityIds);
+
     /**
     /**
      * 查询批次测试卷
      * 查询批次测试卷
      * 
      * 

+ 9 - 8
ie-system/src/main/java/com/ruoyi/system/mapper/SysAreaMapper.java

@@ -5,15 +5,15 @@ import com.ruoyi.system.domain.SysArea;
 
 
 /**
 /**
  * 区域-省市区县Mapper接口
  * 区域-省市区县Mapper接口
- * 
+ *
  * @author ruoyi
  * @author ruoyi
  * @date 2025-09-29
  * @date 2025-09-29
  */
  */
-public interface SysAreaMapper 
+public interface SysAreaMapper
 {
 {
     /**
     /**
      * 查询区域-省市区县
      * 查询区域-省市区县
-     * 
+     *
      * @param areaId 区域-省市区县主键
      * @param areaId 区域-省市区县主键
      * @return 区域-省市区县
      * @return 区域-省市区县
      */
      */
@@ -21,15 +21,16 @@ public interface SysAreaMapper
 
 
     /**
     /**
      * 查询区域-省市区县列表
      * 查询区域-省市区县列表
-     * 
+     *
      * @param sysArea 区域-省市区县
      * @param sysArea 区域-省市区县
      * @return 区域-省市区县集合
      * @return 区域-省市区县集合
      */
      */
     public List<SysArea> selectSysAreaList(SysArea sysArea);
     public List<SysArea> selectSysAreaList(SysArea sysArea);
+    public List<SysArea> selectSysAreaListByIds(List<Long> ids);
 
 
     /**
     /**
      * 新增区域-省市区县
      * 新增区域-省市区县
-     * 
+     *
      * @param sysArea 区域-省市区县
      * @param sysArea 区域-省市区县
      * @return 结果
      * @return 结果
      */
      */
@@ -37,7 +38,7 @@ public interface SysAreaMapper
 
 
     /**
     /**
      * 修改区域-省市区县
      * 修改区域-省市区县
-     * 
+     *
      * @param sysArea 区域-省市区县
      * @param sysArea 区域-省市区县
      * @return 结果
      * @return 结果
      */
      */
@@ -45,7 +46,7 @@ public interface SysAreaMapper
 
 
     /**
     /**
      * 删除区域-省市区县
      * 删除区域-省市区县
-     * 
+     *
      * @param areaId 区域-省市区县主键
      * @param areaId 区域-省市区县主键
      * @return 结果
      * @return 结果
      */
      */
@@ -53,7 +54,7 @@ public interface SysAreaMapper
 
 
     /**
     /**
      * 批量删除区域-省市区县
      * 批量删除区域-省市区县
-     * 
+     *
      * @param areaIds 需要删除的数据主键集合
      * @param areaIds 需要删除的数据主键集合
      * @return 结果
      * @return 结果
      */
      */

+ 1 - 0
ie-system/src/main/java/com/ruoyi/system/service/ISysAreaService.java

@@ -26,6 +26,7 @@ public interface ISysAreaService
      * @return 区域-省市区县集合
      * @return 区域-省市区县集合
      */
      */
     public List<SysArea> selectSysAreaList(SysArea sysArea);
     public List<SysArea> selectSysAreaList(SysArea sysArea);
+    public List<SysArea> selectSysAreaListByIds(List<Long> ids);
     public List<SysArea> listTree(SysArea criteria);
     public List<SysArea> listTree(SysArea criteria);
     /**
     /**
      * 新增区域-省市区县
      * 新增区域-省市区县

+ 5 - 0
ie-system/src/main/java/com/ruoyi/system/service/impl/SysAreaServiceImpl.java

@@ -47,6 +47,11 @@ public class SysAreaServiceImpl implements ISysAreaService
     {
     {
         return sysAreaMapper.selectSysAreaList(sysArea);
         return sysAreaMapper.selectSysAreaList(sysArea);
     }
     }
+    @Override
+    public List<SysArea> selectSysAreaListByIds(List<Long> ids)
+    {
+        return sysAreaMapper.selectSysAreaListByIds(ids);
+    }
 
 
     @Override
     @Override
     public List<SysArea> listTree(SysArea criteria) {
     public List<SysArea> listTree(SysArea criteria) {

+ 22 - 19
ie-system/src/main/resources/mapper/dz/DzAgentMapper.xml

@@ -5,12 +5,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 <mapper namespace="com.ruoyi.dz.mapper.DzAgentMapper">
 <mapper namespace="com.ruoyi.dz.mapper.DzAgentMapper">
 
 
     <resultMap type="DzAgent" id="DzAgentResult">
     <resultMap type="DzAgent" id="DzAgentResult">
-        <result property="agentId"    column="agentId"    />
-        <result property="deptId"    column="deptId"    />
-        <result property="userId"    column="userId"    />
+        <result property="agentId"    column="agent_id"    />
+        <result property="deptId"    column="dept_id"    />
+        <result property="userId"    column="user_id"    />
         <result property="name"    column="name"    />
         <result property="name"    column="name"    />
         <result property="phonenumber"    column="phonenumber"    />
         <result property="phonenumber"    column="phonenumber"    />
-        <result property="parentId"    column="parentId"    />
+        <result property="parentId"    column="parent_id"    />
         <result property="schools"    column="schools"    />
         <result property="schools"    column="schools"    />
         <result property="remark"    column="remark"    />
         <result property="remark"    column="remark"    />
         <association property="dept"     javaType="SysDept"         resultMap="deptResult" />
         <association property="dept"     javaType="SysDept"         resultMap="deptResult" />
@@ -27,37 +27,40 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </resultMap>
     </resultMap>
 
 
     <sql id="selectDzAgentVo">
     <sql id="selectDzAgentVo">
-        select t1.agentId, t1.deptId, t1.userId, t1.name, t1.phonenumber, t1.parentId, t1.schools, t1.remark,
+        select t1.agent_id, t1.dept_id, t1.user_id, t1.name, t1.phonenumber, t1.parent_id, t1.schools, t1.remark,
         d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status
         d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status
         from dz_agent t1
         from dz_agent t1
-        left join sys_dept d on t1.deptId = d.dept_id
+        left join sys_dept d on t1.dept_id = d.dept_id
     </sql>
     </sql>
 
 
     <select id="selectDzAgentList" parameterType="DzAgent" resultMap="DzAgentResult">
     <select id="selectDzAgentList" parameterType="DzAgent" resultMap="DzAgentResult">
         <include refid="selectDzAgentVo"/>
         <include refid="selectDzAgentVo"/>
         <where>
         <where>
-            <if test="userId != null "> and t1.userId = #{userId}</if>
-            <if test="deptId != null "> and t1.deptId = #{deptId}</if>
+            <if test="userId != null "> and t1.user_id = #{userId}</if>
+<!--            <if test="deptId != null "> and t1.dept_id = #{deptId}</if>-->
+            <if test="deptId != null ">
+                AND (t1.dept_id = #{deptId} OR t1.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(#{deptId}, ancestors) ))
+            </if>
             <if test="name != null  and name != ''"> and t1.name like concat('%', #{name}, '%')</if>
             <if test="name != null  and name != ''"> and t1.name like concat('%', #{name}, '%')</if>
             <if test="phonenumber != null  and phonenumber != ''"> and t1.phonenumber  like concat('%', #{phonenumber}, '%')</if>
             <if test="phonenumber != null  and phonenumber != ''"> and t1.phonenumber  like concat('%', #{phonenumber}, '%')</if>
-            <if test="parentId != null "> and t1.parentId = #{parentId}</if>
+            <if test="parentId != null "> and t1.parent_id = #{parentId}</if>
             <if test="schools != null  and schools != ''"> and t1.schools = #{schools}</if>
             <if test="schools != null  and schools != ''"> and t1.schools = #{schools}</if>
         </where>
         </where>
     </select>
     </select>
 
 
     <select id="selectDzAgentByAgentId" parameterType="Long" resultMap="DzAgentResult">
     <select id="selectDzAgentByAgentId" parameterType="Long" resultMap="DzAgentResult">
         <include refid="selectDzAgentVo"/>
         <include refid="selectDzAgentVo"/>
-        where t1.agentId = #{agentId}
+        where t1.agent_id = #{agentId}
     </select>
     </select>
 
 
     <insert id="insertDzAgent" parameterType="DzAgent" useGeneratedKeys="true" keyProperty="agentId">
     <insert id="insertDzAgent" parameterType="DzAgent" useGeneratedKeys="true" keyProperty="agentId">
         insert into dz_agent
         insert into dz_agent
         <trim prefix="(" suffix=")" suffixOverrides=",">
         <trim prefix="(" suffix=")" suffixOverrides=",">
-            <if test="deptId != null">deptId,</if>
-            <if test="userId != null">userId,</if>
+            <if test="deptId != null">dept_id,</if>
+            <if test="userId != null">user_id,</if>
             <if test="name != null">name,</if>
             <if test="name != null">name,</if>
             <if test="phonenumber != null">phonenumber,</if>
             <if test="phonenumber != null">phonenumber,</if>
-            <if test="parentId != null">parentId,</if>
+            <if test="parentId != null">parent_id,</if>
             <if test="schools != null">schools,</if>
             <if test="schools != null">schools,</if>
             <if test="remark != null">remark,</if>
             <if test="remark != null">remark,</if>
          </trim>
          </trim>
@@ -75,23 +78,23 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <update id="updateDzAgent" parameterType="DzAgent">
     <update id="updateDzAgent" parameterType="DzAgent">
         update dz_agent
         update dz_agent
         <trim prefix="SET" suffixOverrides=",">
         <trim prefix="SET" suffixOverrides=",">
-            <if test="userId != null">userId = #{userId},</if>
-            <if test="deptId != null">deptId = #{deptId},</if>
+            <if test="userId != null">user_id = #{userId},</if>
+            <if test="deptId != null">dept_id = #{deptId},</if>
             <if test="name != null">name = #{name},</if>
             <if test="name != null">name = #{name},</if>
             <if test="phonenumber != null">phonenumber = #{phonenumber},</if>
             <if test="phonenumber != null">phonenumber = #{phonenumber},</if>
-            <if test="parentId != null">parentId = #{parentId},</if>
+            <if test="parentId != null">parent_id = #{parentId},</if>
             <if test="schools != null">schools = #{schools},</if>
             <if test="schools != null">schools = #{schools},</if>
             <if test="remark != null">remark = #{remark},</if>
             <if test="remark != null">remark = #{remark},</if>
         </trim>
         </trim>
-        where agentId = #{agentId}
+        where agent_id = #{agentId}
     </update>
     </update>
 
 
     <delete id="deleteDzAgentByAgentId" parameterType="Long">
     <delete id="deleteDzAgentByAgentId" parameterType="Long">
-        delete from dz_agent where agentId = #{agentId}
+        delete from dz_agent where agent_id = #{agentId}
     </delete>
     </delete>
 
 
     <delete id="deleteDzAgentByAgentIds" parameterType="String">
     <delete id="deleteDzAgentByAgentIds" parameterType="String">
-        delete from dz_agent where agentId in
+        delete from dz_agent where agent_id in
         <foreach item="agentId" collection="array" open="(" separator="," close=")">
         <foreach item="agentId" collection="array" open="(" separator="," close=")">
             #{agentId}
             #{agentId}
         </foreach>
         </foreach>

+ 14 - 1
ie-system/src/main/resources/mapper/dz/DzSchoolMapper.xml

@@ -40,7 +40,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <include refid="selectDzSchoolVo"/>
         <include refid="selectDzSchoolVo"/>
         <where>
         <where>
             <if test="name != null  and name != ''"> and t1.name like concat('%', #{name}, '%')</if>
             <if test="name != null  and name != ''"> and t1.name like concat('%', #{name}, '%')</if>
-            <if test="deptId != null "> and t1.dept_id = #{deptId}</if>
+<!--            <if test="deptId != null "> and t1.dept_id = #{deptId}</if>-->
+            <if test="deptId != null ">
+                AND (t1.dept_id = #{deptId} OR t1.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(#{deptId}, ancestors) ))
+            </if>
             <if test="location != null  and location != ''"> and t1.location = #{location}</if>
             <if test="location != null  and location != ''"> and t1.location = #{location}</if>
             <if test="pro != null "> and t1.pro = #{pro}</if>
             <if test="pro != null "> and t1.pro = #{pro}</if>
             <if test="city != null "> and t1.city = #{city}</if>
             <if test="city != null "> and t1.city = #{city}</if>
@@ -49,6 +52,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </where>
         </where>
     </select>
     </select>
 
 
+    <select id="selectDzSchoolListByIds" parameterType="list" resultMap="DzSchoolResult">
+        <include refid="selectDzSchoolVo"/>
+        WHERE 1=1
+        AND t1.id IN
+        <foreach collection="list" item="id" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+        ORDER BY t1.id ASC
+    </select>
+
     <select id="selectDzSchoolById" parameterType="Long" resultMap="DzSchoolResult">
     <select id="selectDzSchoolById" parameterType="Long" resultMap="DzSchoolResult">
         <include refid="selectDzSchoolVo"/>
         <include refid="selectDzSchoolVo"/>
         where t1.id = #{id}
         where t1.id = #{id}

+ 31 - 11
ie-system/src/main/resources/mapper/dz/DzTeacherClassMapper.xml

@@ -3,30 +3,30 @@
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.ruoyi.dz.mapper.DzTeacherClassMapper">
 <mapper namespace="com.ruoyi.dz.mapper.DzTeacherClassMapper">
-    
+
     <resultMap type="DzTeacherClass" id="DzTeacherClassResult">
     <resultMap type="DzTeacherClass" id="DzTeacherClassResult">
         <result property="id"    column="id"    />
         <result property="id"    column="id"    />
         <result property="teacherId"    column="teacher_id"    />
         <result property="teacherId"    column="teacher_id"    />
-        <result property="classesId"    column="classes_id"    />
+        <result property="classId"    column="class_id"    />
         <result property="status"    column="status"    />
         <result property="status"    column="status"    />
         <result property="remark"    column="remark"    />
         <result property="remark"    column="remark"    />
         <result property="outDate"    column="out_date"    />
         <result property="outDate"    column="out_date"    />
     </resultMap>
     </resultMap>
 
 
     <sql id="selectDzTeacherClassVo">
     <sql id="selectDzTeacherClassVo">
-        select id, teacher_id, classes_id, status, remark, out_date from dz_teacher_class
+        select id, teacher_id, class_id, status, remark, out_date from dz_teacher_class
     </sql>
     </sql>
 
 
     <select id="selectDzTeacherClassList" parameterType="DzTeacherClass" resultMap="DzTeacherClassResult">
     <select id="selectDzTeacherClassList" parameterType="DzTeacherClass" resultMap="DzTeacherClassResult">
         <include refid="selectDzTeacherClassVo"/>
         <include refid="selectDzTeacherClassVo"/>
-        <where>  
+        <where>
             <if test="teacherId != null "> and teacher_id = #{teacherId}</if>
             <if test="teacherId != null "> and teacher_id = #{teacherId}</if>
-            <if test="classesId != null "> and classes_id = #{classesId}</if>
+            <if test="classId != null "> and class_id = #{classId}</if>
             <if test="status != null "> and status = #{status}</if>
             <if test="status != null "> and status = #{status}</if>
             <if test="outDate != null "> and out_date = #{outDate}</if>
             <if test="outDate != null "> and out_date = #{outDate}</if>
         </where>
         </where>
     </select>
     </select>
-    
+
     <select id="selectDzTeacherClassById" parameterType="String" resultMap="DzTeacherClassResult">
     <select id="selectDzTeacherClassById" parameterType="String" resultMap="DzTeacherClassResult">
         <include refid="selectDzTeacherClassVo"/>
         <include refid="selectDzTeacherClassVo"/>
         where id = #{id}
         where id = #{id}
@@ -36,25 +36,45 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         insert into dz_teacher_class
         insert into dz_teacher_class
         <trim prefix="(" suffix=")" suffixOverrides=",">
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="teacherId != null">teacher_id,</if>
             <if test="teacherId != null">teacher_id,</if>
-            <if test="classesId != null">classes_id,</if>
+            <if test="classId != null">class_id,</if>
             <if test="status != null">status,</if>
             <if test="status != null">status,</if>
             <if test="remark != null">remark,</if>
             <if test="remark != null">remark,</if>
             <if test="outDate != null">out_date,</if>
             <if test="outDate != null">out_date,</if>
          </trim>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="teacherId != null">#{teacherId},</if>
             <if test="teacherId != null">#{teacherId},</if>
-            <if test="classesId != null">#{classesId},</if>
+            <if test="classId != null">#{classId},</if>
             <if test="status != null">#{status},</if>
             <if test="status != null">#{status},</if>
             <if test="remark != null">#{remark},</if>
             <if test="remark != null">#{remark},</if>
             <if test="outDate != null">#{outDate},</if>
             <if test="outDate != null">#{outDate},</if>
          </trim>
          </trim>
     </insert>
     </insert>
 
 
+    <!-- 批量插入教师班级关联关系 -->
+    <insert id="insertBatch" parameterType="java.util.List">
+        INSERT INTO dz_teacher_class (
+        teacher_id,
+        class_id,
+        status,
+        create_time,
+        create_by
+        ) VALUES
+        <foreach collection="list" item="item" separator=",">
+            (
+            #{item.teacherId},
+            #{item.classId},
+            #{item.status},
+            #{item.createTime},
+            #{item.createBy}
+            )
+        </foreach>
+    </insert>
+
     <update id="updateDzTeacherClass" parameterType="DzTeacherClass">
     <update id="updateDzTeacherClass" parameterType="DzTeacherClass">
         update dz_teacher_class
         update dz_teacher_class
         <trim prefix="SET" suffixOverrides=",">
         <trim prefix="SET" suffixOverrides=",">
             <if test="teacherId != null">teacher_id = #{teacherId},</if>
             <if test="teacherId != null">teacher_id = #{teacherId},</if>
-            <if test="classesId != null">classes_id = #{classesId},</if>
+            <if test="classId != null">class_id = #{classId},</if>
             <if test="status != null">status = #{status},</if>
             <if test="status != null">status = #{status},</if>
             <if test="remark != null">remark = #{remark},</if>
             <if test="remark != null">remark = #{remark},</if>
             <if test="outDate != null">out_date = #{outDate},</if>
             <if test="outDate != null">out_date = #{outDate},</if>
@@ -67,9 +87,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </delete>
     </delete>
 
 
     <delete id="deleteDzTeacherClassByIds" parameterType="String">
     <delete id="deleteDzTeacherClassByIds" parameterType="String">
-        delete from dz_teacher_class where id in 
+        delete from dz_teacher_class where id in
         <foreach item="id" collection="array" open="(" separator="," close=")">
         <foreach item="id" collection="array" open="(" separator="," close=")">
             #{id}
             #{id}
         </foreach>
         </foreach>
     </delete>
     </delete>
-</mapper>
+</mapper>

+ 5 - 0
ie-system/src/main/resources/mapper/ie/AMarjorPlanMapper.xml

@@ -107,6 +107,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         where id = #{id}
         where id = #{id}
     </select>
     </select>
 
 
+    <select id="selectAMarjorPlanByIds" parameterType="Long" resultMap="AMarjorPlanResult">
+        <include refid="selectAMarjorPlanVo"/>
+        where id in <foreach item="id" collection="array" open="(" separator="," close=")">#{id}</foreach>
+    </select>
+
     <select id="selectMajorCodesByIds" parameterType="String" resultType="String">
     <select id="selectMajorCodesByIds" parameterType="String" resultType="String">
         SELECT distinct m1.code majorCode
         SELECT distinct m1.code majorCode
         FROM `a_marjor_plan` p
         FROM `a_marjor_plan` p

+ 11 - 1
ie-system/src/main/resources/mapper/learn/LearnDirectedKnowledgeMapper.xml

@@ -7,6 +7,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <resultMap type="LearnDirectedKnowledge" id="LearnDirectedKnowledgeResult">
     <resultMap type="LearnDirectedKnowledge" id="LearnDirectedKnowledgeResult">
         <result property="id"    column="id"    />
         <result property="id"    column="id"    />
         <result property="year"    column="year"    />
         <result property="year"    column="year"    />
+        <result property="universityId"    column="university_id"    />
         <result property="directKey"    column="direct_key"    />
         <result property="directKey"    column="direct_key"    />
         <result property="enrollFormula"    column="enrollFormula"    />
         <result property="enrollFormula"    column="enrollFormula"    />
         <result property="cultural"    column="cultural"    />
         <result property="cultural"    column="cultural"    />
@@ -20,13 +21,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </resultMap>
     </resultMap>
 
 
     <sql id="selectLearnDirectedKnowledgeVo">
     <sql id="selectLearnDirectedKnowledgeVo">
-        select id, year, direct_key, enrollFormula, cultural, professional, subjects, question_types, knowledges, locations, examineeTypes, conditions from learn_directed_knowledge
+        select id, year, university_id, direct_key, enrollFormula, cultural, professional, subjects, question_types, knowledges, locations, examineeTypes, conditions from learn_directed_knowledge
     </sql>
     </sql>
 
 
     <select id="selectLearnDirectedKnowledgeList" parameterType="LearnDirectedKnowledge" resultMap="LearnDirectedKnowledgeResult">
     <select id="selectLearnDirectedKnowledgeList" parameterType="LearnDirectedKnowledge" resultMap="LearnDirectedKnowledgeResult">
         <include refid="selectLearnDirectedKnowledgeVo"/>
         <include refid="selectLearnDirectedKnowledgeVo"/>
         <where>  
         <where>  
             <if test="year != null "> and year = #{year}</if>
             <if test="year != null "> and year = #{year}</if>
+            <if test="universityId != null  and universityId != ''"> and university_id = #{universityId}</if>
             <if test="directKey != null  and directKey != ''"> and direct_key = #{directKey}</if>
             <if test="directKey != null  and directKey != ''"> and direct_key = #{directKey}</if>
             <if test="enrollFormula != null  and enrollFormula != ''"> and enrollFormula = #{enrollFormula}</if>
             <if test="enrollFormula != null  and enrollFormula != ''"> and enrollFormula = #{enrollFormula}</if>
             <if test="cultural != null  and cultural != ''"> and cultural = #{cultural}</if>
             <if test="cultural != null  and cultural != ''"> and cultural = #{cultural}</if>
@@ -45,10 +47,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         where id = #{id}
         where id = #{id}
     </select>
     </select>
 
 
+    <select id="selectByUniversityIds" parameterType="Long" resultMap="LearnDirectedKnowledgeResult">
+        <include refid="selectLearnDirectedKnowledgeVo"/>
+        where id in <foreach item="id" collection="array" open="(" separator="," close=")">#{id}</foreach>
+    </select>
+
     <insert id="insertLearnDirectedKnowledge" parameterType="LearnDirectedKnowledge" useGeneratedKeys="true" keyProperty="id">
     <insert id="insertLearnDirectedKnowledge" parameterType="LearnDirectedKnowledge" useGeneratedKeys="true" keyProperty="id">
         insert into learn_directed_knowledge
         insert into learn_directed_knowledge
         <trim prefix="(" suffix=")" suffixOverrides=",">
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="year != null">year,</if>
             <if test="year != null">year,</if>
+            <if test="universityId != null">university_id,</if>
             <if test="directKey != null">direct_key,</if>
             <if test="directKey != null">direct_key,</if>
             <if test="enrollFormula != null">enrollFormula,</if>
             <if test="enrollFormula != null">enrollFormula,</if>
             <if test="cultural != null">cultural,</if>
             <if test="cultural != null">cultural,</if>
@@ -62,6 +70,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
          </trim>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="year != null">#{year},</if>
             <if test="year != null">#{year},</if>
+            <if test="universityId != null">#{universityId},</if>
             <if test="directKey != null">#{directKey},</if>
             <if test="directKey != null">#{directKey},</if>
             <if test="enrollFormula != null">#{enrollFormula},</if>
             <if test="enrollFormula != null">#{enrollFormula},</if>
             <if test="cultural != null">#{cultural},</if>
             <if test="cultural != null">#{cultural},</if>
@@ -79,6 +88,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         update learn_directed_knowledge
         update learn_directed_knowledge
         <trim prefix="SET" suffixOverrides=",">
         <trim prefix="SET" suffixOverrides=",">
             <if test="year != null">year = #{year},</if>
             <if test="year != null">year = #{year},</if>
+            <if test="universityId != null">university_id = #{universityId},</if>
             <if test="directKey != null">direct_key = #{directKey},</if>
             <if test="directKey != null">direct_key = #{directKey},</if>
             <if test="enrollFormula != null">enrollFormula = #{enrollFormula},</if>
             <if test="enrollFormula != null">enrollFormula = #{enrollFormula},</if>
             <if test="cultural != null">cultural = #{cultural},</if>
             <if test="cultural != null">cultural = #{cultural},</if>

+ 19 - 1
ie-system/src/main/resources/mapper/learn/LearnStudentMapper.xml

@@ -9,11 +9,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="classId"    column="class_id"    />
         <result property="classId"    column="class_id"    />
         <result property="campusId"    column="campus_id"    />
         <result property="campusId"    column="campus_id"    />
         <result property="universityId"    column="university_id"    />
         <result property="universityId"    column="university_id"    />
+        <result property="majorGroup"    column="major_group"    />
         <result property="majorPlanId"    column="major_plan_id"    />
         <result property="majorPlanId"    column="major_plan_id"    />
     </resultMap>
     </resultMap>
 
 
     <sql id="selectLearnStudentVo">
     <sql id="selectLearnStudentVo">
-        select student_id, class_id, campus_id, university_id, major_plan_id from learn_student
+        select student_id, class_id, campus_id, university_id, major_group,major_plan_id from learn_student
     </sql>
     </sql>
 
 
     <select id="selectLearnStudentList" parameterType="LearnStudent" resultMap="LearnStudentResult">
     <select id="selectLearnStudentList" parameterType="LearnStudent" resultMap="LearnStudentResult">
@@ -22,6 +23,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="directKey != null  and directKey != ''"> and direct_key = #{directKey}</if>
             <if test="directKey != null  and directKey != ''"> and direct_key = #{directKey}</if>
         </where>
         </where>
     </select>
     </select>
+
+    <select id="selectLearnStudentsByMap" parameterType="map" resultMap="LearnStudentResult">
+        SELECT distinct ls.`university_id`, ls.`major_group`, ls.`major_plan_id`
+        FROM `learn_student` ls
+        LEFT JOIN `learn_test_student` ts ON ts.`student_id` = ls.`student_id` AND ts.`batch_id` = #{batchId}
+        JOIN `sys_user` u ON ls.`student_id` = u.`user_id`
+        <where> ts.`id` IS NULL and u.`location` = #{location}
+            <if test="examTypes != null  and examTypes.size() > 0"> AND u.`exam_type` in <foreach item="id" collection="examTypes" open="(" separator="," close=")">#{id}</foreach></if>
+            <if test="classIds != null  and classIds.size() > 0"> AND ls.`class_id` IN <foreach item="id" collection="classIds" open="(" separator="," close=")">#{id}</foreach></if>
+            <if test="universityIds != null  and universityIds.size() > 0"> AND ls.`university_id` IN <foreach item="id" collection="universityIds" open="(" separator="," close=")">#{id}</foreach></if>
+            <if test="groups != null  and groups.size() > 0"> AND ls.`major_group` IN <foreach item="id" collection="groups" open="(" separator="," close=")">#{id}</foreach></if>
+            <if test="planIds != null  and planIds.size() > 0"> AND ls.`major_plan_id` IN <foreach item="id" collection="planIds" open="(" separator="," close=")">#{id}</foreach></if>
+        </where>
+    </select>
     
     
     <select id="selectLearnStudentByStudentId" parameterType="Long" resultMap="LearnStudentResult">
     <select id="selectLearnStudentByStudentId" parameterType="Long" resultMap="LearnStudentResult">
         <include refid="selectLearnStudentVo"/>
         <include refid="selectLearnStudentVo"/>
@@ -35,6 +50,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="classId != null">class_id,</if>
             <if test="classId != null">class_id,</if>
             <if test="campusId != null">campus_id,</if>
             <if test="campusId != null">campus_id,</if>
             <if test="universityId != null">university_id,</if>
             <if test="universityId != null">university_id,</if>
+            <if test="majorGroup != null">major_group,</if>
             <if test="majorPlanId != null">major_plan_id,</if>
             <if test="majorPlanId != null">major_plan_id,</if>
          </trim>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
         <trim prefix="values (" suffix=")" suffixOverrides=",">
@@ -42,6 +58,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="classId != null">#{classId},</if>
             <if test="classId != null">#{classId},</if>
             <if test="campusId != null">#{campusId},</if>
             <if test="campusId != null">#{campusId},</if>
             <if test="universityId != null">#{universityId},</if>
             <if test="universityId != null">#{universityId},</if>
+            <if test="majorGroup != null">#{majorGroup},</if>
             <if test="majorPlanId != null">#{majorPlanId},</if>
             <if test="majorPlanId != null">#{majorPlanId},</if>
          </trim>
          </trim>
     </insert>
     </insert>
@@ -52,6 +69,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="classId != null">class_id = #{classId},</if>
             <if test="classId != null">class_id = #{classId},</if>
             <if test="campusId != null">campus_id = #{campusId},</if>
             <if test="campusId != null">campus_id = #{campusId},</if>
             <if test="universityId != null">university_id = #{universityId},</if>
             <if test="universityId != null">university_id = #{universityId},</if>
+            <if test="majorGroup != null">major_group = #{majorGroup},</if>
             <if test="majorPlanId != null">major_plan_id = #{majorPlanId},</if>
             <if test="majorPlanId != null">major_plan_id = #{majorPlanId},</if>
         </trim>
         </trim>
         where student_id = #{studentId}
         where student_id = #{studentId}

+ 20 - 10
ie-system/src/main/resources/mapper/learn/LearnTestPaperMapper.xml

@@ -7,28 +7,35 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <resultMap type="LearnTestPaper" id="LearnTestPaperResult">
     <resultMap type="LearnTestPaper" id="LearnTestPaperResult">
         <result property="id"    column="id"    />
         <result property="id"    column="id"    />
         <result property="batchId"    column="batch_id"    />
         <result property="batchId"    column="batch_id"    />
+        <result property="universityId"    column="university_id"    />
         <result property="directKey"    column="direct_key"    />
         <result property="directKey"    column="direct_key"    />
         <result property="paperId"    column="paper_id"    />
         <result property="paperId"    column="paper_id"    />
-        <result property="condions"    column="condions"    />
+        <result property="conditions"    column="conditions"    />
         <result property="creatorId"    column="creator_id"    />
         <result property="creatorId"    column="creator_id"    />
         <result property="createTime"    column="create_time"    />
         <result property="createTime"    column="create_time"    />
     </resultMap>
     </resultMap>
 
 
     <sql id="selectLearnTestPaperVo">
     <sql id="selectLearnTestPaperVo">
-        select id, batch_id, direct_key, paper_id, condions, creator_id, create_time from learn_test_paper
+        select id, batch_id, university_id, direct_key, paper_id, conditions, creator_id, create_time from learn_test_paper
     </sql>
     </sql>
 
 
     <select id="selectLearnTestPaperList" parameterType="LearnTestPaper" resultMap="LearnTestPaperResult">
     <select id="selectLearnTestPaperList" parameterType="LearnTestPaper" resultMap="LearnTestPaperResult">
         <include refid="selectLearnTestPaperVo"/>
         <include refid="selectLearnTestPaperVo"/>
         <where>  
         <where>  
             <if test="batchId != null "> and batch_id = #{batchId}</if>
             <if test="batchId != null "> and batch_id = #{batchId}</if>
+            <if test="universityId != null "> and university_id = #{universityId}</if>
             <if test="directKey != null  and directKey != ''"> and direct_key = #{directKey}</if>
             <if test="directKey != null  and directKey != ''"> and direct_key = #{directKey}</if>
             <if test="paperId != null "> and paper_id = #{paperId}</if>
             <if test="paperId != null "> and paper_id = #{paperId}</if>
-            <if test="condions != null  and condions != ''"> and condions = #{condions}</if>
+            <if test="conditions != null  and conditions != ''"> and conditions = #{conditions}</if>
             <if test="creatorId != null "> and creator_id = #{creatorId}</if>
             <if test="creatorId != null "> and creator_id = #{creatorId}</if>
         </where>
         </where>
     </select>
     </select>
-    
+
+    <select id="selectByBatchAndUniversityIds" resultMap="LearnTestPaperResult">
+        <include refid="selectLearnTestPaperVo"/>
+        where batch_id = #{batchId} and university_id in <foreach item="id" collection="universityIds" open="(" separator="," close=")">#{id}</foreach>
+    </select>
+
     <select id="selectLearnTestPaperById" parameterType="String" resultMap="LearnTestPaperResult">
     <select id="selectLearnTestPaperById" parameterType="String" resultMap="LearnTestPaperResult">
         <include refid="selectLearnTestPaperVo"/>
         <include refid="selectLearnTestPaperVo"/>
         where id = #{id}
         where id = #{id}
@@ -38,17 +45,19 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         insert into learn_test_paper
         insert into learn_test_paper
         <trim prefix="(" suffix=")" suffixOverrides=",">
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="batchId != null">batch_id,</if>
             <if test="batchId != null">batch_id,</if>
-            <if test="directKey != null and directKey != ''">direct_key,</if>
+            <if test="universityId != null">university_id,</if>
+            <if test="directKey != null ">direct_key,</if>
             <if test="paperId != null">paper_id,</if>
             <if test="paperId != null">paper_id,</if>
-            <if test="condions != null and condions != ''">condions,</if>
+            <if test="conditions != null">conditions,</if>
             <if test="creatorId != null">creator_id,</if>
             <if test="creatorId != null">creator_id,</if>
             <if test="createTime != null">create_time,</if>
             <if test="createTime != null">create_time,</if>
          </trim>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="batchId != null">#{batchId},</if>
             <if test="batchId != null">#{batchId},</if>
-            <if test="directKey != null and directKey != ''">#{directKey},</if>
+            <if test="universityId != null">#{universityId},</if>
+            <if test="directKey != null">#{directKey},</if>
             <if test="paperId != null">#{paperId},</if>
             <if test="paperId != null">#{paperId},</if>
-            <if test="condions != null and condions != ''">#{condions},</if>
+            <if test="conditions != null">#{conditions},</if>
             <if test="creatorId != null">#{creatorId},</if>
             <if test="creatorId != null">#{creatorId},</if>
             <if test="createTime != null">#{createTime},</if>
             <if test="createTime != null">#{createTime},</if>
          </trim>
          </trim>
@@ -58,9 +67,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         update learn_test_paper
         update learn_test_paper
         <trim prefix="SET" suffixOverrides=",">
         <trim prefix="SET" suffixOverrides=",">
             <if test="batchId != null">batch_id = #{batchId},</if>
             <if test="batchId != null">batch_id = #{batchId},</if>
-            <if test="directKey != null and directKey != ''">direct_key = #{directKey},</if>
+            <if test="universityId != null">university_id = #{universityId},</if>
+            <if test="directKey != null">direct_key = #{directKey},</if>
             <if test="paperId != null">paper_id = #{paperId},</if>
             <if test="paperId != null">paper_id = #{paperId},</if>
-            <if test="condions != null and condions != ''">condions = #{condions},</if>
+            <if test="conditions != null">conditions = #{conditions},</if>
             <if test="creatorId != null">creator_id = #{creatorId},</if>
             <if test="creatorId != null">creator_id = #{creatorId},</if>
             <if test="createTime != null">create_time = #{createTime},</if>
             <if test="createTime != null">create_time = #{createTime},</if>
         </trim>
         </trim>

+ 13 - 0
ie-system/src/main/resources/mapper/learn/LearnTestStudentMapper.xml

@@ -20,6 +20,19 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         select id, batch_id, student_id, direct_key, paper_id, class_id, examinee_id, status, create_time from learn_test_student
         select id, batch_id, student_id, direct_key, paper_id, class_id, examinee_id, status, create_time from learn_test_student
     </sql>
     </sql>
 
 
+    <select id="selectDirectedStudentList" parameterType="LearnTestStudent" resultMap="LearnTestStudentResult">
+        <include refid="selectLearnTestStudentVo"/>
+        <where>
+            <if test="batchId != null "> and batch_id = #{batchId}</if>
+            <if test="studentId != null "> and student_id = #{studentId}</if>
+            <if test="directKey != null  and directKey != ''"> and direct_key = #{directKey}</if>
+            <if test="paperId != null "> and paper_id = #{paperId}</if>
+            <if test="classId != null "> and class_id = #{classId}</if>
+            <if test="examineeId != null "> and examinee_id = #{examineeId}</if>
+            <if test="status != null "> and status = #{status}</if>
+        </where>
+    </select>
+
     <select id="selectLearnTestStudentList" parameterType="LearnTestStudent" resultMap="LearnTestStudentResult">
     <select id="selectLearnTestStudentList" parameterType="LearnTestStudent" resultMap="LearnTestStudentResult">
         <include refid="selectLearnTestStudentVo"/>
         <include refid="selectLearnTestStudentVo"/>
         <where>  
         <where>  

+ 10 - 0
ie-system/src/main/resources/mapper/system/SysAreaMapper.xml

@@ -71,6 +71,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         order by area_id asc
         order by area_id asc
     </select>
     </select>
 
 
+    <select id="selectSysAreaListByIds" parameterType="list" resultMap="SysAreaResult">
+        <include refid="selectSysAreaVo"/>
+        WHERE status = '0'
+        AND area_id IN
+        <foreach collection="list" item="id" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+        ORDER BY area_id ASC
+    </select>
+
     <select id="selectSysAreaByAreaId" parameterType="Long" resultMap="SysAreaResult">
     <select id="selectSysAreaByAreaId" parameterType="Long" resultMap="SysAreaResult">
         <include refid="selectSysAreaVo"/>
         <include refid="selectSysAreaVo"/>
         where area_id = #{areaId}
         where area_id = #{areaId}

+ 29 - 29
sql/v_0.2_base.sql

@@ -1,38 +1,38 @@
 -- ----------------------------
 -- ----------------------------
--- 1、部门
+-- 1、机构
 -- ----------------------------
 -- ----------------------------
 drop table if exists sys_dept;
 drop table if exists sys_dept;
 create table sys_dept (
 create table sys_dept (
-  dept_id           bigint(20)      not null auto_increment    comment '部门id',
-  parent_id         bigint(20)      default 0                  comment '父部门id',
+  dept_id           bigint(20)      not null auto_increment    comment '机构id',
+  parent_id         bigint(20)      default 0                  comment '父机构id',
   ancestors         varchar(50)     default ''                 comment '祖级列表',
   ancestors         varchar(50)     default ''                 comment '祖级列表',
-  dept_name         varchar(30)     default ''                 comment '部门名称',
+  dept_name         varchar(30)     default ''                 comment '机构名称',
   order_num         int(4)          default 0                  comment '显示顺序',
   order_num         int(4)          default 0                  comment '显示顺序',
   leader            varchar(20)     default null               comment '负责人',
   leader            varchar(20)     default null               comment '负责人',
   phone             varchar(11)     default null               comment '联系电话',
   phone             varchar(11)     default null               comment '联系电话',
   email             varchar(50)     default null               comment '邮箱',
   email             varchar(50)     default null               comment '邮箱',
-  status            char(1)         default '0'                comment '部门状态(0正常 1停用)',
+  status            char(1)         default '0'                comment '机构状态(0正常 1停用)',
   del_flag          char(1)         default '0'                comment '删除标志(0代表存在 2代表删除)',
   del_flag          char(1)         default '0'                comment '删除标志(0代表存在 2代表删除)',
   create_by         varchar(64)     default ''                 comment '创建者',
   create_by         varchar(64)     default ''                 comment '创建者',
   create_time 	    datetime                                   comment '创建时间',
   create_time 	    datetime                                   comment '创建时间',
   update_by         varchar(64)     default ''                 comment '更新者',
   update_by         varchar(64)     default ''                 comment '更新者',
   update_time       datetime                                   comment '更新时间',
   update_time       datetime                                   comment '更新时间',
   primary key (dept_id)
   primary key (dept_id)
-) engine=innodb auto_increment=200 comment = '部门表';
+) engine=innodb auto_increment=200 comment = '机构表';
 
 
 -- ----------------------------
 -- ----------------------------
--- 初始化-部门表数据
+-- 初始化-机构表数据
 -- ----------------------------
 -- ----------------------------
 insert into sys_dept values(100,  0,   '0',          '若依科技',   0, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
 insert into sys_dept values(100,  0,   '0',          '若依科技',   0, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
 insert into sys_dept values(101,  100, '0,100',      '深圳总公司', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
 insert into sys_dept values(101,  100, '0,100',      '深圳总公司', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
 insert into sys_dept values(102,  100, '0,100',      '长沙分公司', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
 insert into sys_dept values(102,  100, '0,100',      '长沙分公司', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
-insert into sys_dept values(103,  101, '0,100,101',  '研发部门',   1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
-insert into sys_dept values(104,  101, '0,100,101',  '市场部门',   2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
-insert into sys_dept values(105,  101, '0,100,101',  '测试部门',   3, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
-insert into sys_dept values(106,  101, '0,100,101',  '财务部门',   4, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
-insert into sys_dept values(107,  101, '0,100,101',  '运维部门',   5, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
-insert into sys_dept values(108,  102, '0,100,102',  '市场部门',   1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
-insert into sys_dept values(109,  102, '0,100,102',  '财务部门',   2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
+insert into sys_dept values(103,  101, '0,100,101',  '研发机构',   1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
+insert into sys_dept values(104,  101, '0,100,101',  '市场机构',   2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
+insert into sys_dept values(105,  101, '0,100,101',  '测试机构',   3, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
+insert into sys_dept values(106,  101, '0,100,101',  '财务机构',   4, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
+insert into sys_dept values(107,  101, '0,100,101',  '运维机构',   5, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
+insert into sys_dept values(108,  102, '0,100,102',  '市场机构',   1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
+insert into sys_dept values(109,  102, '0,100,102',  '财务机构',   2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
 
 
 
 
 -- ----------------------------
 -- ----------------------------
@@ -41,7 +41,7 @@ insert into sys_dept values(109,  102, '0,100,102',  '财务部门',   2, '若
 drop table if exists sys_user;
 drop table if exists sys_user;
 create table sys_user (
 create table sys_user (
   user_id           bigint(20)      not null auto_increment    comment '用户ID',
   user_id           bigint(20)      not null auto_increment    comment '用户ID',
-  dept_id           bigint(20)      default null               comment '部门ID',
+  dept_id           bigint(20)      default null               comment '机构ID',
   user_name         varchar(30)     not null                   comment '用户账号',
   user_name         varchar(30)     not null                   comment '用户账号',
   nick_name         varchar(30)     not null                   comment '用户昵称',
   nick_name         varchar(30)     not null                   comment '用户昵称',
   user_type         varchar(2)      default '00'               comment '用户类型(00系统用户)',
   user_type         varchar(2)      default '00'               comment '用户类型(00系统用户)',
@@ -107,9 +107,9 @@ create table sys_role (
   role_name            varchar(30)     not null                   comment '角色名称',
   role_name            varchar(30)     not null                   comment '角色名称',
   role_key             varchar(100)    not null                   comment '角色权限字符串',
   role_key             varchar(100)    not null                   comment '角色权限字符串',
   role_sort            int(4)          not null                   comment '显示顺序',
   role_sort            int(4)          not null                   comment '显示顺序',
-  data_scope           char(1)         default '1'                comment '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)',
+  data_scope           char(1)         default '1'                comment '数据范围(1:全部数据权限 2:自定数据权限 3:本机构数据权限 4:本机构及以下数据权限)',
   menu_check_strictly  tinyint(1)      default 1                  comment '菜单树选择项是否关联显示',
   menu_check_strictly  tinyint(1)      default 1                  comment '菜单树选择项是否关联显示',
-  dept_check_strictly  tinyint(1)      default 1                  comment '部门树选择项是否关联显示',
+  dept_check_strictly  tinyint(1)      default 1                  comment '机构树选择项是否关联显示',
   status               char(1)         not null                   comment '角色状态(0正常 1停用)',
   status               char(1)         not null                   comment '角色状态(0正常 1停用)',
   del_flag             char(1)         default '0'                comment '删除标志(0代表存在 2代表删除)',
   del_flag             char(1)         default '0'                comment '删除标志(0代表存在 2代表删除)',
   create_by            varchar(64)     default ''                 comment '创建者',
   create_by            varchar(64)     default ''                 comment '创建者',
@@ -167,7 +167,7 @@ insert into sys_menu values('4', '若依官网', '0', '4', 'http://ruoyi.vip', n
 insert into sys_menu values('100',  '用户管理', '1',   '1', 'user',       'system/user/index',        '', '', 1, 0, 'C', '0', '0', 'system:user:list',        'user',          'admin', sysdate(), '', null, '用户管理菜单');
 insert into sys_menu values('100',  '用户管理', '1',   '1', 'user',       'system/user/index',        '', '', 1, 0, 'C', '0', '0', 'system:user:list',        'user',          'admin', sysdate(), '', null, '用户管理菜单');
 insert into sys_menu values('101',  '角色管理', '1',   '2', 'role',       'system/role/index',        '', '', 1, 0, 'C', '0', '0', 'system:role:list',        'peoples',       'admin', sysdate(), '', null, '角色管理菜单');
 insert into sys_menu values('101',  '角色管理', '1',   '2', 'role',       'system/role/index',        '', '', 1, 0, 'C', '0', '0', 'system:role:list',        'peoples',       'admin', sysdate(), '', null, '角色管理菜单');
 insert into sys_menu values('102',  '菜单管理', '1',   '3', 'menu',       'system/menu/index',        '', '', 1, 0, 'C', '0', '0', 'system:menu:list',        'tree-table',    'admin', sysdate(), '', null, '菜单管理菜单');
 insert into sys_menu values('102',  '菜单管理', '1',   '3', 'menu',       'system/menu/index',        '', '', 1, 0, 'C', '0', '0', 'system:menu:list',        'tree-table',    'admin', sysdate(), '', null, '菜单管理菜单');
-insert into sys_menu values('103',  '部门管理', '1',   '4', 'dept',       'system/dept/index',        '', '', 1, 0, 'C', '0', '0', 'system:dept:list',        'tree',          'admin', sysdate(), '', null, '部门管理菜单');
+insert into sys_menu values('103',  '机构管理', '1',   '4', 'dept',       'system/dept/index',        '', '', 1, 0, 'C', '0', '0', 'system:dept:list',        'tree',          'admin', sysdate(), '', null, '机构管理菜单');
 insert into sys_menu values('104',  '岗位管理', '1',   '5', 'post',       'system/post/index',        '', '', 1, 0, 'C', '0', '0', 'system:post:list',        'post',          'admin', sysdate(), '', null, '岗位管理菜单');
 insert into sys_menu values('104',  '岗位管理', '1',   '5', 'post',       'system/post/index',        '', '', 1, 0, 'C', '0', '0', 'system:post:list',        'post',          'admin', sysdate(), '', null, '岗位管理菜单');
 insert into sys_menu values('105',  '字典管理', '1',   '6', 'dict',       'system/dict/index',        '', '', 1, 0, 'C', '0', '0', 'system:dict:list',        'dict',          'admin', sysdate(), '', null, '字典管理菜单');
 insert into sys_menu values('105',  '字典管理', '1',   '6', 'dict',       'system/dict/index',        '', '', 1, 0, 'C', '0', '0', 'system:dict:list',        'dict',          'admin', sysdate(), '', null, '字典管理菜单');
 insert into sys_menu values('106',  '参数设置', '1',   '7', 'config',     'system/config/index',      '', '', 1, 0, 'C', '0', '0', 'system:config:list',      'edit',          'admin', sysdate(), '', null, '参数设置菜单');
 insert into sys_menu values('106',  '参数设置', '1',   '7', 'config',     'system/config/index',      '', '', 1, 0, 'C', '0', '0', 'system:config:list',      'edit',          'admin', sysdate(), '', null, '参数设置菜单');
@@ -204,11 +204,11 @@ insert into sys_menu values('1012', '菜单查询', '102', '1',  '', '', '', '',
 insert into sys_menu values('1013', '菜单新增', '102', '2',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:add',            '#', 'admin', sysdate(), '', null, '');
 insert into sys_menu values('1013', '菜单新增', '102', '2',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:add',            '#', 'admin', sysdate(), '', null, '');
 insert into sys_menu values('1014', '菜单修改', '102', '3',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:edit',           '#', 'admin', sysdate(), '', null, '');
 insert into sys_menu values('1014', '菜单修改', '102', '3',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:edit',           '#', 'admin', sysdate(), '', null, '');
 insert into sys_menu values('1015', '菜单删除', '102', '4',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:remove',         '#', 'admin', sysdate(), '', null, '');
 insert into sys_menu values('1015', '菜单删除', '102', '4',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:remove',         '#', 'admin', sysdate(), '', null, '');
--- 部门管理按钮
-insert into sys_menu values('1016', '部门查询', '103', '1',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:query',          '#', 'admin', sysdate(), '', null, '');
-insert into sys_menu values('1017', '部门新增', '103', '2',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:add',            '#', 'admin', sysdate(), '', null, '');
-insert into sys_menu values('1018', '部门修改', '103', '3',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:edit',           '#', 'admin', sysdate(), '', null, '');
-insert into sys_menu values('1019', '部门删除', '103', '4',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:remove',         '#', 'admin', sysdate(), '', null, '');
+-- 机构管理按钮
+insert into sys_menu values('1016', '机构查询', '103', '1',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:query',          '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1017', '机构新增', '103', '2',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:add',            '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1018', '机构修改', '103', '3',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:edit',           '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1019', '机构删除', '103', '4',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:remove',         '#', 'admin', sysdate(), '', null, '');
 -- 岗位管理按钮
 -- 岗位管理按钮
 insert into sys_menu values('1020', '岗位查询', '104', '1',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:query',          '#', 'admin', sysdate(), '', null, '');
 insert into sys_menu values('1020', '岗位查询', '104', '1',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:query',          '#', 'admin', sysdate(), '', null, '');
 insert into sys_menu values('1021', '岗位新增', '104', '2',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:add',            '#', 'admin', sysdate(), '', null, '');
 insert into sys_menu values('1021', '岗位新增', '104', '2',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:add',            '#', 'admin', sysdate(), '', null, '');
@@ -378,17 +378,17 @@ insert into sys_role_menu values ('2', '1059');
 insert into sys_role_menu values ('2', '1060');
 insert into sys_role_menu values ('2', '1060');
 
 
 -- ----------------------------
 -- ----------------------------
--- 8、角色和部门关联表  角色1-N部门
+-- 8、角色和机构关联表  角色1-N机构
 -- ----------------------------
 -- ----------------------------
 drop table if exists sys_role_dept;
 drop table if exists sys_role_dept;
 create table sys_role_dept (
 create table sys_role_dept (
   role_id   bigint(20) not null comment '角色ID',
   role_id   bigint(20) not null comment '角色ID',
-  dept_id   bigint(20) not null comment '部门ID',
+  dept_id   bigint(20) not null comment '机构ID',
   primary key(role_id, dept_id)
   primary key(role_id, dept_id)
-) engine=innodb comment = '角色和部门关联表';
+) engine=innodb comment = '角色和机构关联表';
 
 
 -- ----------------------------
 -- ----------------------------
--- 初始化-角色和部门关联表数据
+-- 初始化-角色和机构关联表数据
 -- ----------------------------
 -- ----------------------------
 insert into sys_role_dept values ('2', '100');
 insert into sys_role_dept values ('2', '100');
 insert into sys_role_dept values ('2', '101');
 insert into sys_role_dept values ('2', '101');
@@ -425,7 +425,7 @@ create table sys_oper_log (
   request_method    varchar(10)     default ''                 comment '请求方式',
   request_method    varchar(10)     default ''                 comment '请求方式',
   operator_type     int(1)          default 0                  comment '操作类别(0其它 1后台用户 2手机端用户)',
   operator_type     int(1)          default 0                  comment '操作类别(0其它 1后台用户 2手机端用户)',
   oper_name         varchar(50)     default ''                 comment '操作人员',
   oper_name         varchar(50)     default ''                 comment '操作人员',
-  dept_name         varchar(50)     default ''                 comment '部门名称',
+  dept_name         varchar(50)     default ''                 comment '机构名称',
   oper_url          varchar(255)    default ''                 comment '请求URL',
   oper_url          varchar(255)    default ''                 comment '请求URL',
   oper_ip           varchar(128)    default ''                 comment '主机地址',
   oper_ip           varchar(128)    default ''                 comment '主机地址',
   oper_location     varchar(255)    default ''                 comment '操作地点',
   oper_location     varchar(255)    default ''                 comment '操作地点',
@@ -701,4 +701,4 @@ create table gen_table_column (
   update_by         varchar(64)     default ''                 comment '更新者',
   update_by         varchar(64)     default ''                 comment '更新者',
   update_time       datetime                                   comment '更新时间',
   update_time       datetime                                   comment '更新时间',
   primary key (column_id)
   primary key (column_id)
-) engine=innodb auto_increment=1 comment = '代码生成业务表字段';
+) engine=innodb auto_increment=1 comment = '代码生成业务表字段';

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików