elective-table.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. <template>
  2. <div>
  3. <div class="mb10 fx-row fx-bet-cen">
  4. <div class="fx-row fx-end-cen">
  5. <el-button circle icon="el-icon-refresh" @click="refreshData" class="mr30"></el-button>
  6. <elective-enroll-info v-if="enrollInfoVisible" :generation="generation"
  7. :enroll-status="enrollStatus"></elective-enroll-info>
  8. </div>
  9. <el-button v-if="enableAIFeature" type="primary" @click="toAiAnalysis">AI分析</el-button>
  10. </div>
  11. <mx-table :propDefines="formatCols" :rows="formatRows">
  12. <template #underOver="{value}">
  13. <over-under-badge :value="value"></over-under-badge>
  14. </template>
  15. <template #group="{row}">
  16. <elective-table-group-tag :generation="generation" :group="row"></elective-table-group-tag>
  17. </template>
  18. <template #temp="{row}">
  19. <span class="btn-blue mr5" @click="toSelectSub(row)">选择</span>
  20. <span class="btn-green" @click="toReport">查看记录</span>
  21. </template>
  22. <template #signUp="{row}">
  23. <elective-preference-command :generation="generation" :group="row"></elective-preference-command>
  24. </template>
  25. <template #subjects="{row}">
  26. <elective-major-thumbnail :group="row"></elective-major-thumbnail>
  27. </template>
  28. <template #colleges="{row}">
  29. <elective-major-college :group="row"></elective-major-college>
  30. </template>
  31. </mx-table>
  32. <elective-preference-info :generation="generation"></elective-preference-info>
  33. <elective-preference-batch v-if="enableMultipleDrag" :generation="generation" :disabled="!enableSelect"></elective-preference-batch>
  34. <elective-preference-reject v-if="enableReject" :generation="generation"></elective-preference-reject>
  35. <elective-esign-dialog ref="esignDialog"></elective-esign-dialog>
  36. <choose-subject-dialog ref="chooseDialog"></choose-subject-dialog>
  37. <select-subject-report-dialog ref="reportDialog"></select-subject-report-dialog>
  38. <elective-ai-analysis-dialog ref="aiDialog" :optionalMajors="optionalMajors"
  39. :generation="generation"></elective-ai-analysis-dialog>
  40. </div>
  41. </template>
  42. <script>
  43. import consts from '@/common/mx-const'
  44. import { mapGetters } from 'vuex'
  45. import MxSelectTranslate from '@/components/Cache/modules/mx-select-translate-mixin.js'
  46. import ChooseSubjectDialog from '../../../system/user/profile/components/choose-subject-dialog'
  47. import SelectSubjectReportDialog from '@/views/system/user/profile/components/select-subject-report-dialog'
  48. import OverUnderBadge from '@/views/elective/publish/components/steps/fauclty/over-under-badge'
  49. import ElectiveEnrollInfo from '@/views/elective/select/components/elective-enroll-info'
  50. import ElectiveToolsMixin from './elective-tools-mixins'
  51. import ElectivePreferenceInfo from '@/views/elective/select/components/elective-preference-info'
  52. import ElectivePreferenceReject from '@/views/elective/select/components/elective-preference-reject'
  53. import ElectivePreferenceCommand from '@/views/elective/select/components/elective-preference-command'
  54. import ElectiveAiAnalysisDialog from '@/views/elective/select/components/elective-ai-analysis-dialog'
  55. import ElectiveEsignDialog from '@/views/elective/select/components/elective-esign-dialog'
  56. import ElectiveMajorThumbnail from '@/views/elective/select/components/elective-major-thumbnail'
  57. import ElectiveMajorCollege from '@/views/elective/select/components/elective-major-college'
  58. import ElectivePreferenceBatch from '@/views/elective/select/components/elective-preference-batch'
  59. import ElectiveTableGroupTag from '@/views/elective/select/components/elective-table-group-tag'
  60. const resolverModules = require.context('./round-select-resolvers', false, /\.js$/)
  61. const resolvers = resolverModules.keys().map(key => resolverModules(key).default)
  62. export default {
  63. mixins: [ElectiveToolsMixin, MxSelectTranslate, ...resolvers],
  64. name: 'elective-table',
  65. props: {
  66. generation: Object,
  67. readonly: Boolean, // 校长端不允许操作
  68. optionalMajors: { type: Array, default: () => [] }
  69. },
  70. components: {
  71. ElectiveTableGroupTag,
  72. ElectivePreferenceBatch,
  73. ElectiveMajorCollege,
  74. ElectiveMajorThumbnail,
  75. ElectiveEsignDialog,
  76. ElectiveAiAnalysisDialog,
  77. ElectivePreferenceCommand,
  78. ElectivePreferenceReject,
  79. ElectivePreferenceInfo,
  80. ElectiveEnrollInfo,
  81. OverUnderBadge,
  82. SelectSubjectReportDialog,
  83. ChooseSubjectDialog
  84. },
  85. inject: {
  86. refreshData: {
  87. default: function() {
  88. }
  89. }
  90. },
  91. computed: {
  92. ...mapGetters(['hasPermissions']),
  93. enrollInfoVisible() {
  94. return this.generation.active > this.generation.options.primary.value
  95. },
  96. enrollStatus() {
  97. const enrolledGroup = this.generation.activeModel.models?.find(this.isGroupEnrolled)
  98. if (enrolledGroup) {
  99. let enrolledModel = this.generation.activeModel
  100. do {
  101. const matched = enrolledModel.models?.find(this.isGroupEnrolled)
  102. if (matched
  103. && matched.groupId == enrolledGroup.groupId
  104. && enrolledModel.selectedList.includes(matched)) {
  105. return {
  106. enrolledGroup,
  107. enrolledModel
  108. }
  109. }
  110. enrolledModel = enrolledModel.prevModel
  111. }
  112. while (enrolledModel)
  113. }
  114. return { enrolledGroup, enrolledModel: null }
  115. },
  116. stepMatched() {
  117. return this.generation.active == this.generation.current
  118. },
  119. selectStep() {
  120. return !this.generation.activeOpt.decisionMaking
  121. },
  122. enableSelect() {
  123. return this.stepMatched && this.selectStep && !!!this.enrollStatus.enrolledGroup && !this.readonly
  124. },
  125. selectedList() {
  126. return this.generation.activeModel.selectedList
  127. },
  128. multipleSelect() {
  129. return this.generation.activeModel.preferenceCount > 1
  130. },
  131. enableMultipleDrag() {
  132. return this.selectStep && this.multipleSelect
  133. },
  134. enableReject() {
  135. return this.enableSelect && this.generation.active > this.generation.options.primary.value
  136. },
  137. enableAIFeature() {
  138. return !this.generation.activeOpt.decisionMaking
  139. && this.generation.activeOpt != this.generation.options.primary
  140. && !this.readonly
  141. },
  142. resolveTablePrefix() {
  143. return {
  144. index: {
  145. type: 'index',
  146. label: '编号'
  147. },
  148. groupName: {
  149. label: '选科组合',
  150. slot: 'group',
  151. width: '85px'
  152. },
  153. scoreSumGroup: {
  154. label: '组合成绩',
  155. hidden: this.hasPermissions([consts.enum.electivePermission.rankInGroup.scoreByGroup])
  156. },
  157. classCount: {
  158. label: '开设班级数'
  159. },
  160. personCount: {
  161. label: '人数设置'
  162. }
  163. }
  164. },
  165. resolveTableSuffix() {
  166. const stepMatched = this.generation.active == this.generation.current
  167. const enableApply = !this.generation.currentOpt.decisionMaking
  168. const enableSignUp = stepMatched && enableApply && !this.readonly
  169. return {
  170. rankInGroup: {
  171. label: '当前组合实时排名',
  172. hidden: this.hasPermissions([consts.enum.electivePermission.rankInGroup])
  173. },
  174. rankInGrade: {
  175. label: '选科全校排名',
  176. hidden: this.hasPermissions([consts.enum.electivePermission.rankInGrade])
  177. },
  178. allowSelectTips: {
  179. label: '报名状态'
  180. },
  181. temp: {
  182. label: '选择专业',
  183. width: '140',
  184. slot: 'temp',
  185. hidden: this.readonly
  186. },
  187. subjects: {
  188. label: '自选专业',
  189. slot: 'subjects',
  190. minWidth: '150'
  191. },
  192. colleges: {
  193. label: '院校',
  194. slot: 'colleges',
  195. minWidth: '250'
  196. },
  197. signUp: {
  198. label: '操作',
  199. slot: 'signUp',
  200. width: '100',
  201. fixed: 'right',
  202. hidden: !enableSignUp
  203. }
  204. }
  205. },
  206. resolveDynamicTable() {
  207. if (!Object.keys(this.formatRows).length) return {}
  208. const options = this.generation.options
  209. if (!options || !this.generation.active) return {}
  210. const optValues = Object.values(options)
  211. const dynamicColumns = {}
  212. for (let gen = options.primary.value; gen <= this.generation.active; gen++) {
  213. const opt = optValues.find(opt => opt.value == gen)
  214. const resolverKey = opt.key + 'Resolver'
  215. const resolver = this[resolverKey]
  216. if (typeof resolver === 'function') {
  217. const genColumns = resolver(gen, this.generation.active, dynamicColumns)
  218. Object.assign(dynamicColumns, genColumns)
  219. }
  220. }
  221. return dynamicColumns
  222. },
  223. formatRows() {
  224. if (!this.optionalMajors) return []
  225. if (!this.generation.roundGroups?.length) return []
  226. if (!this.generation.activeModels?.length) return []
  227. const activeModel = this.generation.activeModel
  228. return this.generation.roundGroups.map(rg => {
  229. const row = activeModel.models?.find(item => item.groupId == rg.groupId) || {}
  230. row.allowSelectTips = this.combineGroupStatus(row, activeModel)
  231. const matchedMajors = this.optionalMajors.filter(college => college.matchedGroupIds.includes(row.groupId))
  232. row.colleges = matchedMajors.map(m => ({ college: m.collegeName, major: m.majorCategoryName }))
  233. row.subjects = matchedMajors.map(m => m['majorCategoryName'])
  234. return row
  235. })
  236. },
  237. formatCols() {
  238. return {
  239. ...this.resolveTablePrefix,
  240. ...this.resolveDynamicTable,
  241. ...this.resolveTableSuffix
  242. }
  243. }
  244. },
  245. methods: {
  246. preventSelectedListChanged() {
  247. if (!this.enableSelect) return Promise.resolve(true)
  248. const from = this.generation.activeModel.selectedList
  249. const to = this.generation.activeModel.selectedListSnapshot
  250. let changedMsg = '请先提交更改过的志愿', changed = false
  251. if (from.length != to.length) {
  252. changed = true
  253. } else if (from.length) {
  254. const elementCheckFields = ['selected', 'rejected', 'groupId']
  255. from.forEach((eleFrom, idx) => {
  256. const eleTo = to[idx]
  257. const eleChanged = elementCheckFields.some(f => eleFrom[f] != eleTo[f])
  258. if (eleChanged) changed = true
  259. })
  260. }
  261. if (changed) this.$message.warning(changedMsg)
  262. return changed ? Promise.reject(changedMsg) : Promise.resolve(true)
  263. },
  264. async toReport() {
  265. await this.preventSelectedListChanged()
  266. this.$refs.reportDialog.open()
  267. },
  268. async toSelectSub(row) {
  269. await this.preventSelectedListChanged()
  270. // 打开选科弹窗
  271. const course0 = this.translateCourse0(row.groupId)
  272. const course1 = this.translateCourse1(row.groupId)
  273. this.$refs.chooseDialog.open(course0, course1)
  274. },
  275. toAiAnalysis() {
  276. // AI 分析 跳转
  277. this.$refs.aiDialog.open(this.formatRows)
  278. }
  279. }
  280. }
  281. </script>
  282. <style scoped>
  283. </style>