report-table.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. <template>
  2. <div>
  3. <div class="mb10 fx-row fx-end-base jc-between">
  4. <div class="fx-row fx-end-cen">
  5. <slot name="header-prefix"></slot>
  6. <p v-if="generation.active > 1" v-html="currentSupplyInfo"></p>
  7. </div>
  8. <div>
  9. <el-button v-if="aiButtonShow" type="primary" @click="toAiAnalysis">AI分析</el-button>
  10. <!-- <el-button>选科历史记录</el-button>-->
  11. </div>
  12. </div>
  13. <mx-table :propDefines="formatCols" :rows="formatRows">
  14. <template #underOver="{value}">
  15. <over-under-badge :value="value"></over-under-badge>
  16. </template>
  17. <template #group="{row}">
  18. <el-badge class="group" value="荐" :hidden="!row.isRecommend" type="success">
  19. <el-tag size="medium" :type="isGroupOverSetting(row) ? 'danger' : 'warning'">{{ row.groupName }}</el-tag>
  20. </el-badge>
  21. </template>
  22. <template #temp="{row}">
  23. <span class="btn-blue mr5" @click="toSelectSub(row)">选择</span>
  24. <span class="btn-green" @click="toReport">查看记录</span>
  25. <!-- <el-button>查看</el-button>-->
  26. </template>
  27. <template #signUp="{row}">
  28. <span class="f-red" v-if="!row.allowSelect">无法报名</span>
  29. <div v-else>
  30. <span v-if="generation.current > 1" @click="commit(row)" class="btn-green">报名</span>
  31. <div v-else>
  32. <span class="f-red btn-red" v-if="row.selected" @click="toUnSelect(row)">取消报名</span>
  33. <span class="btn-green" v-else @click="toSelect(row)">报名</span>
  34. </div>
  35. </div>
  36. </template>
  37. <template #subjects="{row}">
  38. <el-row>
  39. <el-col :span="8" v-for="subject in row.subjects">
  40. <el-popover
  41. placement="top"
  42. popper-class="zero-padding-popover"
  43. trigger="hover"
  44. >
  45. <div class="fx-column">
  46. <el-button plain type="text">{{ subject }}</el-button>
  47. </div>
  48. <el-tag type="success" slot="reference" class="mr10 mb10">{{ subject[0] }}</el-tag>
  49. </el-popover>
  50. </el-col>
  51. </el-row>
  52. </template>
  53. <template #colleges="{row}">
  54. <el-row>
  55. <el-col :span="12" v-for="college in row.colleges">
  56. <el-popover
  57. placement="top"
  58. popper-class="zero-padding-popover"
  59. trigger="hover"
  60. >
  61. <div class="fx-column">
  62. <el-button plain type="text">{{ college.major }}</el-button>
  63. </div>
  64. <el-tag type="success" slot="reference" class="mr10 mb10">{{ college.major[0] }}</el-tag>
  65. </el-popover>
  66. :
  67. <span>{{ college.college }}</span>
  68. </el-col>
  69. </el-row>
  70. </template>
  71. </mx-table>
  72. <!-- 初录 多志愿拖拽 -->
  73. <div
  74. v-if="this.generation.active == generation.options.primary.value || this.generation.active == generation.options.primaryDM.value">
  75. <p>您的选科志愿: <span v-for="(item,index) in activeModels.selectedList">
  76. {{ item.groupName }}
  77. </span>
  78. </p>
  79. <div>
  80. <test-drage ref="drage" :btnDisabled="this.generation.current != generation.options.primary.value"
  81. :selectedList="activeModels.selectedList"
  82. ></test-drage>
  83. <el-button @click="commit" type="primary" v-if="this.generation.current == generation.options.primary.value">
  84. 提交
  85. </el-button>
  86. </div>
  87. </div>
  88. <div v-if="generation.current > generation.active && generation.active > generation.options.primaryDM.value">
  89. <!-- 补录报名和二次补录报名和调剂报名历史报名信息 -->
  90. {{ historySupply }}
  91. </div>
  92. <!-- 补录报名和二次补录报名和调剂报名 -->
  93. <div v-if="flagShow">
  94. <div class="mb5 mt10 text-right">
  95. <el-popover
  96. placement="right"
  97. width="300"
  98. v-model="popoShow"
  99. trigger="click"
  100. >
  101. <div>
  102. 确定拒绝系统给您推荐的<span class="f-primary">{{recommendGroup.groupName}}</span>组合么?
  103. <el-input
  104. type="textarea"
  105. :rows="4"
  106. placeholder="请输入原因"
  107. v-model="regInfo"
  108. >
  109. </el-input>
  110. <p class="fx-row jc-between mt10">
  111. <el-button type="primary" size="mini" @click="popoShow = false">取消</el-button>
  112. <el-button type="danger" size="mini" @click="handleRejectRecommend">提交</el-button>
  113. </p>
  114. </div>
  115. <el-button slot="reference" type="danger">不同意</el-button>
  116. </el-popover>
  117. </div>
  118. </div>
  119. <esign-dialog ref="esignDialog"></esign-dialog>
  120. <choose-subject-dialog ref="chooseDialog"></choose-subject-dialog>
  121. <select-subject-report-dialog ref="reportDialog"></select-subject-report-dialog>
  122. <Ai-dialog ref="aiDialog" :prevPreferencesInfo="currentSupplyInfo" :generation="generation"></Ai-dialog>
  123. </div>
  124. </template>
  125. <script>
  126. import AiDialog from './ai-analysis-dialog'
  127. import MxSelectTranslate from '@/components/Cache/modules/mx-select-translate-mixin.js'
  128. import TestDrage from './test-drage'
  129. import ChooseSubjectDialog from './choose-subject-dialog'
  130. import SelectSubjectReportDialog from '@/views/system/user/profile/components/select-subject-report-dialog'
  131. import EsignDialog from '@/views/system/user/profile/components/esign-dialog'
  132. import ReportStep from './report-step'
  133. import OverUnderBadge from '@/views/elective/publish/components/steps/fauclty/over-under-badge'
  134. import { submitElectiveModels } from '@/api/webApi/elective/selected-subject'
  135. const resolverModules = require.context('./round-select-resolvers', false, /\.js$/)
  136. const resolvers = resolverModules.keys().map(key => resolverModules(key).default)
  137. export default {
  138. props: {
  139. generation: Object,
  140. readonly: Boolean, // 校长端不允许操作
  141. optionalMajors: { type: Array, default: () => [] }
  142. },
  143. components: {
  144. OverUnderBadge,
  145. SelectSubjectReportDialog,
  146. ReportStep,
  147. EsignDialog,
  148. TestDrage,
  149. ChooseSubjectDialog,
  150. AiDialog
  151. },
  152. inject: {
  153. 'refreshData': {
  154. default: function() {
  155. // do nothing
  156. }
  157. }
  158. },
  159. mixins: [MxSelectTranslate, ...resolvers],
  160. data() {
  161. return {
  162. popoShow: false,
  163. activeStep: '',
  164. regInfo: '',
  165. dialogVisible: false,
  166. singleList: [], // 单志愿列表
  167. rows: []
  168. }
  169. },
  170. computed: {
  171. historySupply() {
  172. // 当前代历史报名信息
  173. if (!this.generation.models.length) return ''
  174. // 填报 || 拒绝 || 未选择
  175. // 当前代
  176. const activeModels = this.generation.models.find(item => item.generation == this.generation.active)
  177. const isRefuse = activeModels.models.filter(item => item.rejected)
  178. if (isRefuse.length > 0) {
  179. // 拒绝了
  180. return '您拒绝了填报志愿'
  181. } else {
  182. // 填报 or 未选择
  183. const supply = activeModels.models.filter(item => item.selected)
  184. if (supply.length > 0) {
  185. return `填报志愿为${supply[0].groupName}`
  186. } else {
  187. return '您未填报志愿'
  188. }
  189. }
  190. },
  191. // 不符
  192. currentSupplyInfo() {
  193. if (!this.generation.models.length) return ''
  194. // console.log(this.generation)
  195. if (this.generation.active < this.generation.options.primaryDM.value) return ''
  196. let info = ''
  197. const activeModels = this.generation.models.find(item => item.generation == this.generation.active)
  198. // 是否被录取?
  199. const approved = activeModels.models.filter(item => {
  200. return item.approved
  201. })
  202. if (approved.length) {
  203. // 查找
  204. // 已被录取
  205. info = `同学,你好,你之前所选择的${approved.groupName}已被录取`
  206. } else {
  207. // 已报名未被录取的group 取当前models的前一个
  208. const prevModels = this.generation.models.find(item => item.generation == activeModels.generation - 1)
  209. // 是否拒绝 ?
  210. const isRefuse = prevModels.models.filter(item => item.rejected)
  211. if (isRefuse.length > 0) {
  212. // 拒绝报名
  213. let tips = ''
  214. const prevGen = Object.values(this.generation.options).find(item => item.value == prevModels.generation)
  215. if (prevGen.decisionMaking) {
  216. tips = Object.values(this.generation.options).find(item => item.value == prevModels.generation - 1).title
  217. } else {
  218. tips = prevGen.title
  219. }
  220. const isSupply = prevGen.decisionMaking ? ',现有以下标黄组合可以重新报名' : ''
  221. info = `<p>同学,你好,你在${tips}时拒绝填报志愿 ${isSupply} </p>`
  222. } else {
  223. // 没被录取的组合
  224. const refuseGroup = prevModels.models.filter(item => {
  225. return item.selected
  226. })
  227. // 获取报名的阶段
  228. let tips = ''
  229. const prevGen = Object.values(this.generation.options).find(item => item.value == prevModels.generation)
  230. if (prevGen.decisionMaking) {
  231. tips = Object.values(this.generation.options).find(item => item.value == prevModels.generation - 1).title
  232. } else {
  233. tips = prevGen.title
  234. }
  235. const isSupply = prevGen.decisionMaking ? ',现有以下标黄组合可以重新报名' : ''
  236. if (refuseGroup.length > 0) {
  237. info = `<p>同学,你好,你在${tips}所选择的 <span class="f-red">${refuseGroup.map(g => g.groupName).join(',').toString()}</span> 不符合条件${isSupply} </p>`
  238. } else {
  239. info = `<p>同学,你好,你在${tips}时未填报志愿 ${isSupply} </p>`
  240. }
  241. }
  242. }
  243. return info
  244. },
  245. flagShow() {
  246. const stepMatched = this.generation.active == this.generation.current
  247. const selectStep = !this.generation.activeOpt.decisionMaking
  248. return stepMatched && selectStep && !this.readonly
  249. },
  250. aiButtonShow() {
  251. if (!this.generation.activeOpt) return false
  252. const options = this.generation.options
  253. return !this.generation.activeOpt.decisionMaking &&
  254. this.generation.activeOpt != options.primary &&
  255. !this.readonly
  256. },
  257. resolveTablePrefix() {
  258. return {
  259. index: {
  260. type: 'index',
  261. label: '编号'
  262. },
  263. groupName: {
  264. label: '选科组合',
  265. slot: 'group',
  266. width: '85px'
  267. },
  268. scoreSumGroup: {
  269. label: '组合成绩'
  270. },
  271. classCount: {
  272. label: '开设班级数'
  273. },
  274. personCount: {
  275. label: '人数设置'
  276. }
  277. }
  278. },
  279. resolveTableSuffix() {
  280. const stepMatched = this.generation.active == this.generation.current
  281. const enableApply = !this.generation.currentOpt.decisionMaking
  282. const enableSignUp = stepMatched && enableApply && !this.readonly
  283. return {
  284. allowSelectTips: {
  285. label: '报名状态'
  286. },
  287. temp: {
  288. label: '选择专业',
  289. width: '140',
  290. slot: 'temp',
  291. hidden: this.readonly
  292. },
  293. subjects: {
  294. label: '自选专业',
  295. slot: 'subjects',
  296. minWidth: '150'
  297. },
  298. colleges: {
  299. label: '院校',
  300. slot: 'colleges',
  301. minWidth: '250'
  302. },
  303. signUp: {
  304. label: '操作',
  305. slot: 'signUp',
  306. width: '100',
  307. fixed: 'right',
  308. hidden: !enableSignUp
  309. }
  310. }
  311. },
  312. resolveDynamicTable() {
  313. if (!Object.keys(this.formatRows).length) return {}
  314. const options = this.generation.options
  315. if (!options || !this.generation.active) return {}
  316. const optValues = Object.values(options)
  317. const dynamicColumns = {}
  318. for (let gen = options.primary.value; gen <= this.generation.active; gen++) {
  319. const opt = optValues.find(opt => opt.value == gen)
  320. const resolverKey = opt.key + 'Resolver'
  321. const resolver = this[resolverKey]
  322. if (typeof resolver === 'function') {
  323. const genColumns = resolver(gen, this.generation.active, dynamicColumns)
  324. Object.assign(dynamicColumns, genColumns)
  325. }
  326. }
  327. return dynamicColumns
  328. },
  329. activeModels() {
  330. if (!this.generation) return {}
  331. const generation = this.generation.models.find(item => item.generation == this.generation.active)
  332. // generation.selectedList = generation.models.filter(item => {
  333. // return item.selected
  334. // })
  335. return generation
  336. },
  337. recommendGroup() {
  338. return this.activeModels?.models?.find(m => m.isRecommend) || {}
  339. },
  340. // 初始化 rows 填充固定数据
  341. formatRows() {
  342. if (!this.optionalMajors) return []
  343. if (!this.generation.roundGroups?.length) return []
  344. if (!this.generation.activeModels?.length) return []
  345. const generationModels = this.generation.activeModels.last()?.models || []
  346. return this.generation.roundGroups.map(rg => {
  347. const row = generationModels.find(item => item.groupId == rg.groupId) || {}
  348. row.allowSelectTips = row.allowSelect ? '报名中' : row.disabledReason || '无法报名'
  349. const matchedMajors = this.optionalMajors.filter(college => college.matchedGroupIds.includes(row.groupId))
  350. row.colleges = matchedMajors.map(m => ({ college: m.collegeName, major: m.majorCategoryName }))
  351. row.subjects = matchedMajors.map(m => m['majorCategoryName'])
  352. // this.$set(row,'colleges',matchedMajors.map(m => ({ college: m.collegeName, major: m.majorCategoryName })))
  353. // this.$set(row,'subjects',matchedMajors.map(m => m['majorCategoryName']))
  354. return row
  355. })
  356. },
  357. formatCols() {
  358. return {
  359. ...this.resolveTablePrefix,
  360. ...this.resolveDynamicTable,
  361. ...this.resolveTableSuffix
  362. }
  363. }
  364. },
  365. methods: {
  366. getModelsByStep() {
  367. return this.models.findIndex()
  368. },
  369. isGroupOverSetting(row) {
  370. if (this.generation.activeOpt.decisionMaking) {
  371. console.log('isGroupOverSetting decisionMaking', row.groupApprovedCount >= row.personCount, row)
  372. return row.groupApprovedCount >= row.personCount
  373. } else {
  374. console.log('isGroupOverSetting', row.actualCount >= row.groupIndicator, row)
  375. return row.actualCount >= row.groupIndicator
  376. }
  377. },
  378. toReport() {
  379. // 是否更改了报名数据 ?
  380. const flag = this.activeModels.models.filter(item => item.selected).length == this.activeModels.selectedList.length
  381. if (!flag) {
  382. this.$message.warning('请先提交更改过的志愿')
  383. return
  384. }
  385. this.$refs.reportDialog.open()
  386. },
  387. toAiAnalysis() {
  388. // AI 分析 跳转
  389. this.$refs.aiDialog.open(this.formatRows)
  390. },
  391. commit(row) {
  392. if (this.generation.current == 1) {
  393. const real = this.activeModels.selectedList.filter(item => {
  394. return item.selected == true
  395. })
  396. if (real.length < this.generation.status.preferenceCount) {
  397. this.$message.warning(`初录报名需要选择${this.generation.status.preferenceCount}个志愿`)
  398. return
  399. }
  400. } else {
  401. this.toSelect(row)
  402. }
  403. this.$confirm(`是否要提交报名`, {
  404. confirmButtonText: '确定',
  405. cancelButtonText: '取消',
  406. type: 'warning'
  407. }).then(() => {
  408. submitElectiveModels({
  409. models: this.activeModels.selectedList
  410. // esign:this.base64Img
  411. }).then(res => {
  412. if (res.code == 200) {
  413. this.$message.success('报名成功')
  414. this.refreshData()
  415. }
  416. console.log(res)
  417. })
  418. }).catch(() => {
  419. this.$message({
  420. type: 'info',
  421. message: '已取消提交'
  422. })
  423. })
  424. //
  425. // this.$refs.esignDialog.open(this.activeModels.selectedList)
  426. },
  427. toSelect(row) {
  428. const preferenceCount = this.generation.status.preferenceCount
  429. const count = this.formatRows.reduce((prev, cur) => {
  430. return prev += cur.selected ? 1 : 0
  431. }, 0)
  432. if (count >= preferenceCount) {
  433. this.$message.warning(`最多选择${preferenceCount}个志愿`)
  434. return
  435. }
  436. this.activeModels.models.find(item => item.groupId == row.groupId).selected = true
  437. row.selected = true
  438. if (!this.activeModels.selectedList.includes(row)) this.activeModels.selectedList.push(row)
  439. },
  440. toUnSelect(row) {
  441. this.$confirm(`是否解除选科组合【${row.groupName}】`, '警告', {
  442. confirmButtonText: '确定',
  443. cancelButtonText: '取消',
  444. type: 'warning'
  445. }).then(() => {
  446. this.activeModels.models.find(item => item.groupId == row.groupId).selected = false
  447. row.selected = false
  448. const start = this.activeModels.selectedList.findIndex(item => item.groupId == row.groupId)
  449. console.log(start)
  450. this.activeModels.selectedList.splice(start, 1)
  451. }).catch(() => {
  452. this.$message({
  453. type: 'info',
  454. message: '已取消解除报名'
  455. })
  456. })
  457. },
  458. toSelectSub(row) {
  459. // 是否更改了报名数据 ?
  460. const flag = this.activeModels.models.filter(item => item.selected).length == this.activeModels.selectedList.length
  461. if (!flag) {
  462. this.$message.warning('请先提交更改过的志愿')
  463. return
  464. }
  465. // 打开选科弹窗
  466. const course0 = this.translateCourse0(row.groupId)
  467. const course1 = this.translateCourse1(row.groupId)
  468. this.$refs.chooseDialog.open(course0, course1)
  469. },
  470. async handleRejectRecommend() {
  471. await this.$confirm(`拒绝系统给您推荐的${this.recommendGroup.groupName}组合可能会导致您无法正常录取,确认继续?`)
  472. },
  473. initOption(optionalMajors) {
  474. console.log(optionalMajors)
  475. this.optionalMajors = optionalMajors
  476. }
  477. }
  478. }
  479. </script>
  480. <style scoped>
  481. .cell .el-tag {
  482. margin-right: 5px;
  483. }
  484. .group /deep/ .el-badge__content.is-fixed {
  485. top: 8px;
  486. right: 14px;
  487. }
  488. </style>