zhiyuan-list.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. <template>
  2. <dynamic-table ref="table" :rows="tableList" :columns="columns" row-class-name="recommend-voluntary-row" @expand-change="expand">
  3. <template #wrap-header="{columnDef: col}">
  4. <div>{{ col.label.replace(col.wrapBy, '') }}</div>
  5. <div>{{ col.wrapBy }}</div>
  6. </template>
  7. <template #推荐类型="{row}">
  8. <type-cell :row="row" />
  9. </template>
  10. <template #院校="{row}">
  11. <college-cell :row="row" />
  12. </template>
  13. <template #招生计划="{row}">
  14. <recruit-cell :row="row" />
  15. </template>
  16. <template #投档线年份="{row}">
  17. <shift-line-cell :row="row" />
  18. </template>
  19. <template #年份="{row, columnDef:col}">
  20. <history-year-cell :row="row" :col="col" />
  21. </template>
  22. <template #最低分="{row, columnDef:col}">
  23. <lowest-score-cell :row="row" :col="col" />
  24. </template>
  25. <template #位次="{row, columnDef:col}">
  26. <ranking-cell :row="row" :col="col" />
  27. </template>
  28. <template #录取人数="{row, columnDef:col}">
  29. <enroll-plan-cell :row="row" :col="col" />
  30. </template>
  31. <template #填报="{row}">
  32. <form-status-cell :row="row" @click="handleExpand(row)" />
  33. </template>
  34. <template #expand="{row: recommend}">
  35. <!-- although we used table-draggable here, the outer `sortable` props controls the draggable column. -->
  36. <table-draggable v-loading="recommend.loading" :drag-options="{handle: '.move-group'}" class="pl50 pr50">
  37. <dynamic-table :columns="majorCol" :show-header="false" :rows="recommend.majors" class="major-table">
  38. <template #推荐类型="{row}">
  39. <div class="pl25">
  40. <type-cell :row="row" tag-disabled dark-style />
  41. </div>
  42. </template>
  43. <template #院校="{row}">
  44. <major-cell :row="row" />
  45. </template>
  46. <template #招生计划="{row}">
  47. <recruit-major-cell :row="row" />
  48. </template>
  49. <template #投档线年份="{row}">
  50. <shift-line-major-cell :row="row" />
  51. </template>
  52. <template #录取人数="{row}">
  53. <enroll-plan-cell :row="row" />
  54. </template>
  55. <template #年份="{row, columnDef:col}">
  56. <history-year-cell :row="row" :col="col" />
  57. </template>
  58. <template #最低分="{row, columnDef:col}">
  59. <lowest-score-cell :row="row" :col="col" />
  60. </template>
  61. <template #位次="{row, columnDef:col}">
  62. <ranking-cell :row="row" :col="col" />
  63. </template>
  64. <template #录取人数="{row, columnDef:col}">
  65. <enroll-plan-cell :row="row" :col="col" />
  66. </template>
  67. <template v-if="!readonly" #填报="{row}">
  68. <el-button :type="row.selected ? 'danger' : 'primary'" @click="apply(row,recommend)">
  69. {{ row.selected ? '取消' : '填报' }}
  70. </el-button>
  71. <div v-if="shouldDisplayLimitationTags(row)" class="f-red mt5">有填报要求</div>
  72. </template>
  73. <template #sort="{row, $index}">
  74. <div class="fx-column">
  75. <!-- NOTE:说明此处排序不支持分页方式 -->
  76. <el-button :disabled="$index==0" type="text" class="el-icon-caret-top" @click="handleMajorMove(recommend, row, $index, $index-1)" />
  77. <i class="el-icon-rank move move-group f-primary" />
  78. <el-button :disabled="$index==recommend.majors.length-1" type="text" class="el-icon-caret-bottom" @click="handleMajorMove(recommend, row, $index, $index+1)" />
  79. </div>
  80. </template>
  81. </dynamic-table>
  82. </table-draggable>
  83. </template>
  84. <template #sort="{row, $index}">
  85. <div class="fx-column">
  86. <!-- NOTE:说明此处排序不支持分页方式 -->
  87. <el-button :disabled="$index==0" type="text" class="el-icon-caret-top" @click="handleMove(row, $index, $index-1)" />
  88. <i class="el-icon-rank move move-group f-primary" />
  89. <el-button :disabled="$index==tableList.length-1" type="text" class="el-icon-caret-bottom" @click="handleMove(row, $index, $index+1)" />
  90. </div>
  91. </template>
  92. <template #sequence="{row, $index}">
  93. <span v-if="!sortable">{{ generateSeq($index) }}</span>
  94. <el-select v-else :value="$index" @change="$emit('sequence-change', $index, $event)">
  95. <el-option v-for="opt in sequenceOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
  96. </el-select>
  97. </template>
  98. </dynamic-table>
  99. </template>
  100. <script>
  101. import DynamicTable from '@/components/dynamic-table'
  102. import TypeCell from '@/views/career/zhiyuan/components/PreferenceCells/TypeCell'
  103. import CollegeCell from '@/views/career/zhiyuan/components/PreferenceCells/CollegeCell'
  104. import RecruitCell from '@/views/career/zhiyuan/components/PreferenceCells/RecruitCell'
  105. import ShiftLineCell from '@/views/career/zhiyuan/components/PreferenceCells/ShiftLineCell'
  106. import EnrollPlanCell from '@/views/career/zhiyuan/components/PreferenceCells/EnrollPlanCell'
  107. import HistoryYearCell from '@/views/career/zhiyuan/components/PreferenceCells/HistoryYearCell'
  108. import LowestScoreCell from '@/views/career/zhiyuan/components/PreferenceCells/LowestScoreCell'
  109. import RankingCell from '@/views/career/zhiyuan/components/PreferenceCells/RankingCell'
  110. import FormStatusCell from '@/views/career/zhiyuan/components/PreferenceCells/FormStatusCell'
  111. import MajorCell from '@/views/career/zhiyuan/components/PreferenceCells/MajorCell'
  112. import RecruitMajorCell from '@/views/career/zhiyuan/components/PreferenceCells/RecruitMajorCell'
  113. import ShiftLineMajorCell from '@/views/career/zhiyuan/components/PreferenceCells/ShiftLineMajorCell'
  114. import TableDraggable from '@/components/TableDraggable/index.vue'
  115. export default {
  116. components: {
  117. TableDraggable,
  118. ShiftLineMajorCell,
  119. RecruitMajorCell,
  120. MajorCell,
  121. FormStatusCell,
  122. RankingCell,
  123. LowestScoreCell,
  124. HistoryYearCell,
  125. EnrollPlanCell,
  126. ShiftLineCell,
  127. RecruitCell,
  128. CollegeCell,
  129. TypeCell,
  130. DynamicTable
  131. },
  132. inject: {
  133. 'fetchVoluntaryData': { default: () => ({}) },
  134. 'fetchVoluntaryFilter': { default: () => ({}) }
  135. },
  136. props: {
  137. tableList: {
  138. type: Array,
  139. default: () => []
  140. },
  141. cols: {
  142. type: Array,
  143. default: () => []
  144. },
  145. loading: {
  146. type: Boolean,
  147. default: () => []
  148. },
  149. readonly: {
  150. type: Boolean,
  151. default: false
  152. },
  153. sortable: {
  154. type: Boolean,
  155. default: false
  156. },
  157. showSequence: {
  158. type: Boolean,
  159. default: false
  160. }
  161. },
  162. data() {
  163. return {
  164. show: false,
  165. input: '',
  166. selectedList: []
  167. }
  168. },
  169. computed: {
  170. commonColumns() {
  171. const result = []
  172. const ignoreCols = ['投档线年份']
  173. const historyCols = this.cols.filter(c => c.includes('&'))
  174. const scoreAndRankCols = ['最低分', '位次', '录取人数']
  175. const shortNameCols = ['招生计划']
  176. const wrapHeaderCols = [
  177. { matcher: (col) => col.slotBody === '招生计划', wrapBy: '招生计划' },
  178. { matcher: (col) => col.slotBody === '投档线年份', wrapBy: '年份' }
  179. ]
  180. this.cols.forEach((c, idx) => {
  181. if (ignoreCols.includes(c)) return
  182. if (historyCols.includes(c)) return
  183. const slotName = shortNameCols.find(sc => c.includes(sc))
  184. const def = {
  185. label: c,
  186. slotBody: slotName || c
  187. }
  188. const wrapConfig = wrapHeaderCols.find(w => w.matcher(def))
  189. if (wrapConfig) {
  190. def.slotHeader = 'wrap-header'
  191. def.wrapBy = wrapConfig.wrapBy
  192. }
  193. if (scoreAndRankCols.includes(c)) def.subCols = historyCols
  194. if (idx != 1) def.width = '90px'
  195. if (idx == 2) def.width = '120px'
  196. if (idx == 4) def.width = '110px' // 最低在同时显示`分+?+collect`时宽度不够
  197. result.push(def)
  198. })
  199. result.splice(3, 0, {
  200. width: '90px',
  201. label: '年份',
  202. slotBody: '年份',
  203. subCols: historyCols
  204. })
  205. if (this.showSequence) {
  206. result.unshift({
  207. width: this.sortable ? '80px' : '60px',
  208. label: '序号',
  209. slotBody: 'sequence'
  210. })
  211. }
  212. if (this.sortable) {
  213. result.unshift({
  214. width: '60px',
  215. label: '排序',
  216. slotBody: 'sort'
  217. })
  218. }
  219. return result
  220. },
  221. columns() {
  222. const result = [...this.commonColumns]
  223. result.push({
  224. type: 'expand',
  225. slotBody: 'expand',
  226. label: '查看'
  227. })
  228. return result
  229. },
  230. majorCol() {
  231. return this.commonColumns
  232. },
  233. voluntaryData() {
  234. // noinspection JSUnresolvedFunction
  235. return this.fetchVoluntaryData()
  236. },
  237. sequenceOptions() {
  238. return this.tableList.map((item, index) => ({
  239. value: index,
  240. label: this.generateSeq(index)
  241. }))
  242. },
  243. filterLimitationTags() {
  244. return this.fetchVoluntaryFilter()?.limitationTags || []
  245. }
  246. },
  247. methods: {
  248. shouldDisplayLimitationTags(item) {
  249. // 志愿表详情下,全显;推荐列表时,根据筛选条件显示
  250. if (this.readonly) {
  251. return item.limitationTags?.length > 0
  252. }
  253. if (!item.limitationTags) return false
  254. const safeTags = item.limitationTags?.split(',') || []
  255. if (!safeTags.length) return false
  256. return safeTags.some(t => this.filterLimitationTags.includes(t))
  257. },
  258. generateSeq(index) {
  259. switch (this.voluntaryData.sort) {
  260. case 'letter':
  261. return String.fromCharCode(65 + index)
  262. default:
  263. return index + 1
  264. }
  265. },
  266. expand(item) {
  267. this.$emit('expand', item)
  268. },
  269. apply(item, parent) {
  270. this.$emit('apply', item, parent)
  271. },
  272. handleMove(row, index, target) {
  273. // directly change the order of tableList
  274. const temp = this.tableList[index]
  275. this.tableList.splice(index, 1)
  276. this.tableList.splice(target, 0, temp)
  277. this.$emit('move-change', row, index, target)
  278. },
  279. handleMajorMove(group, major, index, target) {
  280. // directly change the order of group.majors
  281. const temp = group.majors[index]
  282. group.majors.splice(index, 1)
  283. group.majors.splice(target, 0, temp)
  284. this.$emit('move-major-change', group, major, index, target)
  285. },
  286. handleExpand(row) {
  287. this.$refs.table.tableCore.toggleRowExpansion(row)
  288. }
  289. }
  290. }
  291. </script>
  292. <style scoped lang="scss">
  293. .f-9b {
  294. color: #9b9b9b;
  295. }
  296. ::v-deep .el-table__expanded-cell {
  297. padding-top: 0;
  298. //padding-right: 50;
  299. padding-bottom: 0;
  300. padding-left: 0;
  301. }
  302. ::v-deep .el-table__expand-icon {
  303. font-size: 18px;
  304. color: #666;
  305. .el-icon-arrow-right {
  306. font-weight: bold;
  307. }
  308. }
  309. </style>
  310. <style lang="scss">
  311. @import "~@/assets/styles/variables.scss";
  312. .el-table .major-table td {
  313. background-color: mix($--color-primary, #fff, 5%);
  314. }
  315. .recommend-voluntary-row .history-item {
  316. height: 32px;
  317. line-height: 32px;
  318. }
  319. </style>