recommend.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. <template>
  2. <div style="width: 90%; margin:0 auto">
  3. <div class="zhiyuan-filter">
  4. <div class="header">
  5. <h3 class="f-666">您的选考科目为:<em>{{ formSubject.firstSubject }}<em v-for="item in formSubject.lastSubject"
  6. >,{{ item }}</em> </em>, <span class="mr20">总分:<em class="f-primary">{{ formSubject.score }}</em></span>
  7. <span class="mr20">位次:<em class="f-primary">{{ formSubject.rank.lowestRank }}</em></span>请手动选择志愿</h3>
  8. </div>
  9. <div class="filters">
  10. <!-- 院校筛选条件 -->
  11. <filter-form :filter="filter_form" :levelHide="true"></filter-form>
  12. <!-- 专业 -->
  13. <el-row class="radioInput">
  14. <div>
  15. <span class="radiaTitle">专业类别:</span>
  16. </div>
  17. <el-radio-group v-model="currentMajor">
  18. <el-radio-button label="">
  19. <span @click="clear">所有</span></el-radio-button>
  20. <el-radio-button v-for="item in majorList" :key="item.code" :label="item.code" style="margin-bottom:10px">
  21. {{ item.name }}
  22. </el-radio-button>
  23. </el-radio-group>
  24. </el-row>
  25. <!-- 专业子类 -->
  26. <el-row class="radioInput filter" v-if="childrenMajors.length">
  27. <div>
  28. <span class="radiaTitle"></span>
  29. </div>
  30. <div class="items fx-row">
  31. <div class="no_limited">
  32. <el-checkbox @change="changeAll" v-model="isAll">全部</el-checkbox>
  33. </div>
  34. <el-checkbox-group v-model="checkedList" :max="10">
  35. <el-checkbox v-for="item in childrenMajors" :label="item.name" :key="item.name">{{ item.name }}
  36. </el-checkbox>
  37. </el-checkbox-group>
  38. </div>
  39. </el-row>
  40. </div>
  41. <div class="selected">
  42. <span class="f14 f-666">您已选择:</span>
  43. <div class="tags" style="width: 100%">
  44. <el-tag @close="handleClose(item)" type="success" class="mr5 mb5" closable v-for="item in checkedListName">
  45. {{ item.name }}
  46. </el-tag>
  47. </div>
  48. <el-button plain size="mini" @click="confirm">确认</el-button>
  49. <el-button plain size="mini" @click="clear">清除</el-button>
  50. </div>
  51. <div class="radioInput">
  52. <!--其他筛选 -->
  53. <el-row class="radioInput">
  54. <div>
  55. <span class="radiaTitle">推荐类型:</span>
  56. </div>
  57. <el-radio-group v-model="filter_form.pickType">
  58. <el-radio-button label="">所有</el-radio-button>
  59. <el-radio-button v-for="item in localFilters.picks" :key="item.value" :label="item.value"
  60. style="margin-bottom:10px"
  61. >
  62. {{ item.label }}
  63. </el-radio-button>
  64. </el-radio-group>
  65. </el-row>
  66. </div>
  67. <mx-search-group class="mb10" justify="end" :span="6" v-model="name" placeholder="请输入院校名称" @search="getListByName"
  68. ></mx-search-group>
  69. </div>
  70. <div class="zhiyuan-list">
  71. <zhiyuan-list :loading="loading" :tableList="rows" @apply="apply" :cols="cols" @expand="expand"></zhiyuan-list>
  72. </div>
  73. <div :class="{'active':show,'right_cart': true}">
  74. <div class="btn-wrap" @click="show = !show">
  75. 当前志愿表
  76. </div>
  77. <transition name="content">
  78. <div class="content-wrap">
  79. <!-- <el-input class="input" v-model="input" placeholder="院校/专业搜索"></el-input>-->
  80. <div class="content">
  81. <div class="list-item" v-for="(college,collegeIndex) in this.formatZhiyuan">
  82. <div class="head-college f16">
  83. <el-tag type="success" size="mini" class="mr12">{{ collegeIndex + 1 }}</el-tag>
  84. {{ `${college.university.name}(${college.recruitPlan.collegeCode})` }}
  85. </div>
  86. <div class="majors f12">
  87. <div class="major mt10" v-for="(major,majorIndex) in college.majors">
  88. <span class="mr12 ml10">{{ majorIndex + 1 }}</span>
  89. {{ major.marjorName }}
  90. <i class="el-icon-delete delete-icon" @click="deleteMajor(major)"></i>
  91. </div>
  92. </div>
  93. </div>
  94. </div>
  95. <div class="btn">
  96. <el-button style="width: 100%;height: 30px" type="primary" @click="save">保存志愿表</el-button>
  97. </div>
  98. </div>
  99. </transition>
  100. </div>
  101. </div>
  102. </template>
  103. <script>
  104. import FilterForm from '@/views/career/components/FilterForm'
  105. import ZhiyuanList from '@/views/career/zhiyuan/components/zhiyuan-list'
  106. import {
  107. allMajor,
  108. getRecommendVoluntary,
  109. getVoluntaryHeaders,
  110. getVoluntaryMarjors,
  111. saveZhiyuan
  112. } from '@/api/webApi/professlib'
  113. import MxSearchGroup from '@/components/MxSearch/mx-search-group'
  114. export default {
  115. props: {
  116. formSubject: {
  117. type: Object,
  118. default: {}
  119. },
  120. batch: {
  121. type: Object,
  122. default: {}
  123. }
  124. },
  125. components: {
  126. FilterForm,
  127. ZhiyuanList,
  128. MxSearchGroup
  129. },
  130. data() {
  131. return {
  132. indeterminate: false,
  133. checkedList: [],
  134. filter_form: {
  135. location: '',
  136. natureTypeCN: '',
  137. type: '',
  138. features: '',
  139. pickType: '',
  140. name: ''
  141. },
  142. name: '',
  143. currentMajor: '',
  144. majorList: [],
  145. show: false,
  146. localFilters: {
  147. picks: [
  148. { label: '冲刺型', value: 0 },
  149. { label: '稳妥型', value: 1 },
  150. { label: '保守型', value: 2 }
  151. ]
  152. },
  153. pageForm: {
  154. pageSize: 10,
  155. pageNum: 1
  156. },
  157. total: 0,
  158. rows: [],
  159. cols: [],
  160. selectedList: [],
  161. loading: false
  162. }
  163. },
  164. created() {
  165. this.$nextTick(_ => {
  166. this.getAllMajor()
  167. this.getList()
  168. this.getCols()
  169. })
  170. },
  171. mounted() {
  172. let dom = document.querySelector('.el-table__body-wrapper')
  173. console.log(dom)
  174. dom.addEventListener('scroll', (v) => {
  175. const scrollDistance = dom.scrollHeight - dom.scrollTop - dom.clientHeight
  176. // 判断是否到底,可以加载下一页
  177. if (scrollDistance <= 0.5) {
  178. this.load()
  179. }
  180. })
  181. },
  182. watch: {
  183. filter_form: {
  184. deep: true,
  185. handler() {
  186. this.confirm()
  187. }
  188. },
  189. selectedList: {
  190. deep: true,
  191. handler(selectedList) {
  192. const index = selectedList.findIndex(item => {
  193. return item.majors.filter(major => {
  194. return major.selected
  195. }).length <= 0
  196. })
  197. if (index != -1) {
  198. this.selectedList.splice(index, 1)
  199. }
  200. }
  201. }
  202. },
  203. computed: {
  204. mode() {
  205. if (!this.formSubject) return []
  206. return [this.formSubject.firstSubject, ...this.formSubject.lastSubject]
  207. },
  208. // 所有二级
  209. majorAllChildren() {
  210. let arr = []
  211. this.majorList.map(item => {
  212. arr = [...arr, ...item.children]
  213. })
  214. return arr
  215. },
  216. checkedListName() {
  217. return this.majorAllChildren.filter(item => {
  218. return this.checkedList.findIndex(name => name == item.name) != -1
  219. }) || []
  220. },
  221. childrenMajors() {
  222. if (!this.currentMajor) return []
  223. return this.majorList.find(item => {
  224. return item.code == this.currentMajor
  225. }).children || []
  226. },
  227. formatZhiyuan() {
  228. if (!this.selectedList.length) return []
  229. return this.selectedList.map(item => {
  230. return {
  231. university: item.university,
  232. majors: item.majors.filter(major => {
  233. return major.selected
  234. }),
  235. recruitPlan: item.recruitPlan
  236. }
  237. }).filter(item => {
  238. return item.majors.length > 0
  239. })
  240. },
  241. isAll: {
  242. get() {
  243. // 当前children 全选
  244. let count = 0
  245. const childrenMajors = this.childrenMajors
  246. this.checkedList.forEach(item => {
  247. if (childrenMajors.findIndex(major => {
  248. return major.name == item
  249. }) != -1) {
  250. count++
  251. }
  252. })
  253. console.log('选中数', count)
  254. return count == childrenMajors.length
  255. },
  256. set() {
  257. }
  258. }
  259. },
  260. methods: {
  261. getListByName() {
  262. this.filter_form.name = this.name
  263. },
  264. confirm() {
  265. this.pageForm.pageNum = 1
  266. this.getList()
  267. //在执行完跳转页码的数据请求后
  268. this.$nextTick(() => {
  269. document.querySelector('.el-table__body-wrapper').scrollTop = 0
  270. })
  271. },
  272. load() {
  273. if (Math.ceil(this.total / this.pageForm.pageSize) > this.pageForm.pageNum) {
  274. // 标识正在请求
  275. // 加载下一页方法
  276. if (!this.loading) {
  277. //当前页数小于总页数就请求
  278. this.pageForm.pageNum++ //当前页数自增
  279. this.getList('push')
  280. }
  281. } else {
  282. this.$message.warning('已经见底了 ~')
  283. }
  284. },
  285. save() {
  286. const wishes = this.selectedList.map(item => {
  287. return {
  288. universityId: item.university.id,
  289. collegeCode: item.recruitPlan.collegeCode,
  290. code: item.university.code,
  291. name: item.university.name,
  292. pickType: item.pickType,
  293. marjors: item.majors.filter(major => {
  294. return major.selected
  295. }).map(major => {
  296. return {
  297. id: major.id,
  298. code: major.marjorBelongs,
  299. name: major.marjorName,
  300. pickType: item.pickType,
  301. submitMajorId: major.history?.id
  302. }
  303. })
  304. }
  305. })
  306. if (wishes.length < 3) {
  307. this.$message.warning('至少选择三个专业组')
  308. return
  309. }
  310. const data = {
  311. batch: this.batch.batch,
  312. detail: {
  313. batch: {
  314. batch: this.batch.batch,
  315. name: this.batch.name,
  316. recommand: true,
  317. scores: [],
  318. wishes: wishes
  319. },
  320. mode: this.mode.toString(),
  321. score: this.formSubject.score
  322. },
  323. id: 0,
  324. name: ''
  325. }
  326. saveZhiyuan(data).then(res => {
  327. this.$router.push({ name: 'VolunteerList' })
  328. })
  329. },
  330. apply(major, recommend) {
  331. // 有无院校 ?
  332. const codeFlag = this.selectedList.find(item => item == recommend)
  333. if (!codeFlag) {
  334. this.selectedList.push(recommend)
  335. }
  336. major.selected = !major.selected
  337. },
  338. deleteMajor(major) {
  339. major.selected = false
  340. },
  341. expand(item) {
  342. console.log(item)
  343. if (item.isExpand) {
  344. // 取消
  345. return
  346. } else {
  347. item.isExpand = true
  348. this.getVoluntaryMarjors(item)
  349. }
  350. },
  351. getCols() {
  352. getVoluntaryHeaders({
  353. mode: this.mode.toString(),
  354. year: this.batch.year
  355. }).then(res => {
  356. this.cols = res.data
  357. })
  358. },
  359. getList(type) {
  360. this.loading = true
  361. const data = {
  362. batchName: this.batch.name,
  363. batch: this.batch.batch,
  364. majors: this.checkedList,
  365. mode: this.mode.toString(),
  366. // mode1: string,
  367. pickType: this.filter_form.pickType,
  368. // "rank": 0,
  369. score: this.formSubject.score,
  370. batchMinScore: this.batch.score2 || this.batch.score1,
  371. university: {
  372. // "code": "string",
  373. features: this.filter_form.features,
  374. level: this.filter_form.level,
  375. location: this.filter_form.location,
  376. type: this.filter_form.type,
  377. natureTypeCN: this.filter_form.natureTypeCN,
  378. name: this.filter_form.name
  379. // "status": 0,
  380. // "type": "string"
  381. }
  382. }
  383. getRecommendVoluntary({ ...data }, { ...this.pageForm }).then(res => {
  384. console.log(res)
  385. this.total = res.total
  386. let rows = {}
  387. rows = res.rows.map(item => {
  388. item.isExpand = false
  389. item.majors = []
  390. return item
  391. })
  392. // 回显
  393. if (this.selectedList.length) {
  394. rows = rows.map(row => {
  395. const flagIndex = this.selectedList.findIndex(selected => {
  396. return selected.recruitPlan.collegeCode == row.recruitPlan.collegeCode
  397. })
  398. if (flagIndex == -1) {
  399. return row
  400. } else {
  401. return this.selectedList[flagIndex]
  402. }
  403. })
  404. }
  405. if (type == 'push') {
  406. this.rows.push(...rows)
  407. return
  408. }
  409. this.rows = rows
  410. }).finally(_ => {
  411. this.loading = false
  412. })
  413. },
  414. getVoluntaryMarjors(item) {
  415. getVoluntaryMarjors(
  416. {
  417. batchName: this.batch.name,
  418. collegeCode: item.recruitPlan.collegeCode,
  419. mode: this.mode.toString(),
  420. universityId: item.recruitPlan.universityId,
  421. year: item.recruitPlan.year
  422. }
  423. ).then(res => {
  424. item.majors = res.data.map(item => {
  425. item.selected = false
  426. return item
  427. })
  428. console.log(res)
  429. })
  430. },
  431. handleClose(item) {
  432. const index = this.checkedList.findIndex(code => code == item.code)
  433. this.checkedList.splice(index, 1)
  434. },
  435. clear() {
  436. if (!this.checkedList.length) return
  437. this.checkedList = []
  438. this.getList()
  439. },
  440. changeAll(val) {
  441. const checkedList = this.checkedList
  442. if (val) {
  443. // 添加
  444. this.childrenMajors.forEach(item => {
  445. if (this.checkedList.length >= 10) {
  446. this.$message.warning('最多选择10个专业')
  447. throw Error('最多选择10个专业')
  448. }
  449. if (this.checkedList.findIndex(code => code == item.code) == -1) {
  450. this.checkedList.push(item.code)
  451. }
  452. })
  453. } else {
  454. // 移除
  455. this.childrenMajors.forEach(item => {
  456. for (let i = 0; i < checkedList.length; i++) {
  457. if (item.code == checkedList[i]) {
  458. this.checkedList.remove(item.code)
  459. }
  460. }
  461. })
  462. }
  463. console.log(val)
  464. },
  465. handleCheckAllChange(val) {
  466. this.isIndeterminate = false
  467. },
  468. getAllMajor() {
  469. allMajor({
  470. level: 2,
  471. batch: this.batch.batch
  472. }).then(res => {
  473. this.majorList = res.data
  474. console.log(res)
  475. })
  476. }
  477. }
  478. }
  479. </script>
  480. <style scoped lang="scss">
  481. .more span {
  482. margin-right: 10px;
  483. }
  484. .selected {
  485. display: flex;
  486. align-items: center;
  487. justify-content: space-between;
  488. padding: 10px;
  489. margin-bottom: 20px;
  490. background: #42b98340;
  491. span {
  492. flex-shrink: 0;
  493. }
  494. }
  495. .filters {
  496. padding: 10px 0px;
  497. border: 1px solid #eee;
  498. }
  499. .delete-icon {
  500. float: right;
  501. cursor: pointer;
  502. }
  503. .filter_name {
  504. box-sizing: border-box;
  505. width: 70px;
  506. font-size: 14px;
  507. line-height: 20px;
  508. flex: none;
  509. padding: 6px 0 6px 0;
  510. margin-right: 10px;
  511. }
  512. .zhiyuan-filter .filters .filter .items .no_limited {
  513. margin-right: 10px;
  514. }
  515. .zhiyuan-filter .filters .filter .items .no_limited ::v-deep .el-checkbox__input {
  516. display: none;
  517. }
  518. .filters .filter {
  519. padding: 10px 0;
  520. display: flex;
  521. border-bottom: 1px solid #eee;
  522. }
  523. .filters .filter:last-child {
  524. border-bottom: 0;
  525. }
  526. .zhiyuan-filter .filters .filter ::v-deep .el-checkbox, .zhiyuan-filter .filters .filter ::v-deep .el-radio {
  527. -webkit-box-sizing: border-box;
  528. box-sizing: border-box;
  529. height: 32px;
  530. padding: 8px 8px;
  531. margin: 0;
  532. }
  533. em {
  534. font-weight: 400;
  535. font-style: normal;
  536. }
  537. ::v-deep .el-input--medium .el-input__inner {
  538. height: 30px;
  539. line-height: 30px;
  540. }
  541. ::v-deep .el-input {
  542. width: 260px;
  543. }
  544. .radioInput ::v-deep {
  545. background-color: #ffffff;
  546. font-size: 14px;
  547. padding: 5px;
  548. .el-radio {
  549. .el-radio__input {
  550. display: none;
  551. }
  552. }
  553. }
  554. .radioInput ::v-deep {
  555. display: flex;
  556. .el-radio-button .el-radio-button__inner {
  557. border-radius: 4px !important;
  558. border: none;
  559. padding: 5px 10px !important;
  560. font-weight: 400;
  561. font-family: PingFangSC-Regular, PingFang SC;
  562. }
  563. .el-radio-button__orig-radio:checked + .el-radio-button__inner {
  564. box-shadow: none;
  565. }
  566. .radiaTitle {
  567. display: inline-block;
  568. width: 80px;
  569. font-size: 14px;
  570. text-align: right;
  571. margin-top: 2px;
  572. margin-right: 10px;
  573. }
  574. }
  575. .right_cart {
  576. position: fixed;
  577. top: 50%;
  578. right: -320px;
  579. transform: translate(0%, -50%);
  580. transition: all 1s ease;
  581. }
  582. .active {
  583. right: 0;
  584. }
  585. .right_cart {
  586. display: flex;
  587. z-index: 9999;
  588. }
  589. .right_cart .btn-wrap {
  590. cursor: pointer;
  591. align-self: baseline;
  592. border-radius: 5px 0 0 5px;
  593. color: white;
  594. background: #42b983;
  595. width: 30px;
  596. text-align: center;
  597. font-size: 16px;
  598. padding: 7px;
  599. }
  600. .content-wrap {
  601. padding: 10px 0;
  602. background: #fff;
  603. width: 320px;
  604. height: 400px;
  605. display: flex;
  606. flex-direction: column;
  607. border: 1px solid #f2f2f2;
  608. }
  609. .content {
  610. height: 100%;
  611. overflow-y: auto;
  612. padding: 0 20px
  613. }
  614. .content-wrap .input {
  615. padding: 0 15px;
  616. }
  617. .content-wrap .btn {
  618. width: 100%;
  619. padding: 0 15px;
  620. }
  621. .list-item {
  622. margin-bottom: 10px;
  623. border-bottom: 1px solid #e6e6e6;
  624. padding-bottom: 20px;
  625. }
  626. .mask {
  627. z-index: 2009;
  628. position: absolute;
  629. top: 0;
  630. right: 0;
  631. bottom: 0;
  632. left: 0;
  633. overflow: auto;
  634. opacity: 0.5;
  635. margin: 0;
  636. }
  637. </style>