NewSimulatedVolunteer.vue 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. <template>
  2. <div class="bg-page fx-column fx-cen-cen">
  3. <div class="index-block bg-white fx-column pt30 pb30 sticky-container">
  4. <div class="bar">
  5. <!-- 步骤条-->
  6. <div class="step-list line">
  7. <div v-for="(item, index) in topStep" :key="index" class="step-item right">
  8. <div v-if="active.index < item.index" class="step-number" :class="{'curindex':currentStep==index}">
  9. {{ item.index + 1 }}
  10. </div>
  11. <i v-else class="el-icon-check" />
  12. <div class="step-label">{{ item.label }}</div>
  13. </div>
  14. </div>
  15. <div class="text-center f-primary f24 bold">
  16. {{ active.title }}
  17. </div>
  18. </div>
  19. <div class="content">
  20. <score
  21. v-show="active.index==0"
  22. ref="score"
  23. :form="form"
  24. :disable-watch="active.index>0"
  25. :province-name="currentUser.provinceName"
  26. :keep-value="true"
  27. @voluntary-ready="keepVoluntaryData"
  28. />
  29. <phase v-if="active.index==1" :list="zytbBatchesList" :form-subject="form" @onFillIn="onFillIn" />
  30. <recommend
  31. v-if="active.index==2"
  32. ref="recommend"
  33. :batch.sync="batch"
  34. :batch-list.sync="zytbBatchesList"
  35. :form-subject.sync="form"
  36. :selected-list="selectedList"
  37. />
  38. </div>
  39. <div class="text-center" :class="{'mt30':currentStep>0}">
  40. <el-button plain @click="toReport">查看记录</el-button>
  41. <el-button v-if="currentStep>0" type="primary" @click="toBackPage">上一步</el-button>
  42. <el-button v-if="currentStep<=1" type="primary" @click="next">下一步</el-button>
  43. <el-button v-if="currentStep==2" :loading="saving" type="primary" @click="confirmSave">保存</el-button>
  44. </div>
  45. <div v-if="currentStep==0" class="fx-column">
  46. <el-divider />
  47. <div class="f18 bold pf f-primary pl100">
  48. 模拟志愿填报须知
  49. <i class="el-icon el-icon-info" />
  50. </div>
  51. <div class="txt f-333 f14">
  52. <div v-for="(item,index) in tips" :key="index">
  53. <i>{{ index + 1 }}</i>
  54. {{ item }}
  55. </div>
  56. </div>
  57. </div>
  58. </div>
  59. </div>
  60. </template>
  61. <script>
  62. import { mapGetters } from 'vuex'
  63. import Score from './components/SimulateScore'
  64. import Phase from './components/phase'
  65. import Recommend from './components/recommend'
  66. import { zytbBatches } from '@/api/webApi/webQue'
  67. import TransferMixin from '@/components/TransferMixin'
  68. import SearchMajorProviderMixin from '@/views/career/zhiyuan/components/SearchMajorProviderMixin'
  69. import VoluntarySaveRouteGuard from '@/views/career/zhiyuan/components/VoluntarySaveRouteGuard'
  70. import VoluntaryIdentifierProvider from '@/views/career/zhiyuan/components/VoluntaryIdentifierProvider'
  71. import MxConst from "@/common/MxConst";
  72. import MxConfig from "@/common/MxConfig";
  73. import {MessageBox} from "element-ui";
  74. import router from "@/router";
  75. import {debounce} from "@/utils";
  76. export default {
  77. components: {
  78. Recommend,
  79. Phase,
  80. Score
  81. },
  82. mixins: [TransferMixin, SearchMajorProviderMixin, VoluntarySaveRouteGuard, VoluntaryIdentifierProvider],
  83. data() {
  84. return {
  85. input: '',
  86. show: false,
  87. topStep: [
  88. { index: 0, label: '高考分数', title: '(一)输入高考的成绩' },
  89. { index: 1, label: '填报批次', title: '(二)选择填报批次' },
  90. { index: 2, label: '院校专业', title: '(三)选择院校专业' },
  91. { index: 3, label: '保存志愿', title: '(四)我的志愿' }
  92. ],
  93. voluntaryData: null,
  94. batch: {},
  95. form: {
  96. score: '',
  97. firstSubject: '',
  98. lastSubject: [],
  99. rank: '',
  100. seatInput: '',
  101. init: false
  102. },
  103. zytbBatchesList: [],
  104. currentStep: 0,
  105. // add for edit feature
  106. selectedList: [],
  107. id: 0,
  108. subTitle: '',
  109. defaultSort: [],
  110. saving: false,
  111. //
  112. tips: [
  113. '当系统在非正式志愿模拟填报阶段,您可输入不同分数进行多次志愿智能模拟,找准自己的目标院校和专业。当系统在正式填报阶段,您可以修改和保存一次成绩,但填报次数不受限制。',
  114. '期中、期末考试是对阶段性学习成果的考验,也是检验自己的目标院校或专业是否设定合理,请阶段性进行志愿模拟填报以便及时调整目标院校和专业。',
  115. '各地的高考政策不同,模拟志愿填报会根据当前注册用户所属地自动匹配。',
  116. '模拟填报共有四个步骤。'
  117. ]
  118. }
  119. },
  120. computed: {
  121. ...mapGetters(['currentUser', 'scoreLocked']),
  122. active() {
  123. return this.topStep.find(item => item.index == this.currentStep)
  124. },
  125. voluntaryDataCalculate() {
  126. // NOTE: will override by history voluntary data in edit mode
  127. const param = this.voluntaryData || {}
  128. const defaultLimit = { groups: 9999, profession: 9999 }
  129. // noinspection JSUnresolvedVariable
  130. const firedLimit = param.batches?.find(i => i.batch == this.batch.batch) || defaultLimit
  131. return {
  132. ...param,
  133. firedLimit
  134. }
  135. },
  136. batchScoreRangeCalculate() {
  137. return this.calculateScoreBatchRange()
  138. }
  139. },
  140. provide() {
  141. return {
  142. fetchVoluntaryData: () => this.voluntaryDataCalculate,
  143. fetchScoreBatchRange: () => this.batchScoreRangeCalculate
  144. }
  145. },
  146. mounted() {
  147. this.prepareData()
  148. this.reloadScoreAndMode()
  149. },
  150. methods: {
  151. prepareData() {
  152. // do nothing, hook for edit mode
  153. },
  154. calculateScoreBatchRange() {
  155. // for re-use
  156. if (!this.voluntaryData || !this.batch.batch) return [0, 0]
  157. const maxScore = this.voluntaryData.maxScore
  158. const minBatch = this.batch.score2 || this.batch.score1
  159. let maxBatch = maxScore
  160. const batchIndex = this.zytbBatchesList.indexOf(this.batch)
  161. if (batchIndex > 0) {
  162. const upBatch = this.zytbBatchesList[batchIndex - 1]
  163. maxBatch = upBatch.score2 || upBatch.score1
  164. }
  165. return [minBatch, Math.min(maxScore, maxBatch)]
  166. },
  167. reloadScoreAndMode() {
  168. if (this.prevData.score && this.prevData.firstSubject) {
  169. this.form = this.prevData
  170. this.currentStep = 0
  171. // this.next() 暂不用跳下一步,因为无法输入位次
  172. } else {
  173. const modeParams = this.currentUser.mode?.split(',') || []
  174. this.form.score = this.currentUser.score
  175. this.form.firstSubject = modeParams.first()
  176. this.form.lastSubject = modeParams.slice(1)
  177. }
  178. // Fill seatInput with current user's cached seat. This value may be changed by setRankByScore feature
  179. this.$set(this.form, 'seatInput', this.currentUser.seatInput || 0) // init reactive seatInput
  180. if (!this.form.seatInput * 1 || this.scoreLocked) this.form.init = true
  181. else setTimeout(() => this.form.init = true, 800)
  182. },
  183. keepVoluntaryData(data) {
  184. this.voluntaryData = data
  185. },
  186. toReport() {
  187. this.transferTo('/zhiyuan/volunteerList')
  188. },
  189. onFillIn(item) {
  190. this.batch = item
  191. this.selectedList = [] // reset the selected list
  192. this.currentStep = 2
  193. },
  194. next() {
  195. const currentActive = this.currentStep
  196. switch (currentActive) {
  197. case 0:
  198. this.submitScore()
  199. break
  200. case 1:
  201. this.$message.warning('请点击批次按钮进行填写')
  202. break
  203. }
  204. },
  205. async submitScore() {
  206. await this.$refs.score.validate()
  207. this.loadRecommendBatchList()
  208. },
  209. toBackPage() {
  210. if (this.currentStep <= 0) {
  211. this.$router.back()
  212. return
  213. }
  214. const next = () => this.currentStep--
  215. if (this.currentStep < 2) {
  216. next()
  217. return
  218. }
  219. this.processConfirmThenSave(next)
  220. },
  221. loadRecommendBatchList() {
  222. const mode = [this.form.firstSubject, ...this.form.lastSubject].filter(i => !!i).toString()
  223. zytbBatches({
  224. score: this.form.score,
  225. mode: mode
  226. }).then((res) => {
  227. this.zytbBatchesList = res.rows
  228. this.currentStep = 1
  229. })
  230. },
  231. isSelectedListChanged() {
  232. // judge whether the selected list is modified by the user
  233. return this.selectedList.length > 0
  234. },
  235. async confirmSave() {
  236. if (!this.isSelectedListChanged()) {
  237. this.msgError('还未填报任何院校/专业组')
  238. return
  239. }
  240. this.saving = true
  241. try {
  242. await this.processSave()
  243. } finally {
  244. this.saving = false
  245. }
  246. }
  247. }
  248. }
  249. </script>
  250. <style lang="scss" scoped>
  251. .bar {
  252. padding: 0 100px 20px;
  253. border-bottom: 1px solid #d6d6d6;
  254. }
  255. .step-list {
  256. display: flex;
  257. justify-content: space-between;
  258. position: relative;
  259. margin-bottom: 50px;
  260. }
  261. .step-list.line::before {
  262. position: absolute;
  263. content: "";
  264. width: 100%;
  265. height: 2px;
  266. top: 50%;
  267. background: var(--themeColor);
  268. z-index: 0;
  269. }
  270. .step-item {
  271. position: relative;
  272. background: #fff;
  273. z-index: 2;
  274. border: 1px solid var(--themeColor);
  275. border-radius: 50%;
  276. color: var(--themeColor);
  277. width: 36px;
  278. height: 36px;
  279. line-height: 36px;
  280. display: flex;
  281. align-items: center;
  282. justify-content: center;
  283. }
  284. .step-label {
  285. font-weight: bolder;
  286. color: #555555;
  287. width: 100px;
  288. text-align: center;
  289. font-size: 14px;
  290. position: absolute;
  291. bottom: -40px;
  292. }
  293. .step-number {
  294. line-height: 36px;
  295. text-align: center;
  296. }
  297. .step-number.curindex {
  298. width: 36px;
  299. height: 36px;
  300. flex-shrink: 0;
  301. background: var(--themeColor);
  302. border-radius: 50%;
  303. color: #fff;
  304. }
  305. .sticky-container {
  306. overflow-y: scroll;
  307. height: calc(100vh - 70px);
  308. }
  309. .txt {
  310. padding: 20px 100px;
  311. }
  312. .txt div {
  313. display: flex;
  314. align-items: flex-start;
  315. margin-bottom: 15px;
  316. line-height: 1.6;
  317. }
  318. .txt div i {
  319. display: block;
  320. flex-shrink: 0;
  321. width: 24px;
  322. height: 24px;
  323. margin-right: 30px;
  324. text-align: center;
  325. line-height: 24px;
  326. color: #fff;
  327. border-radius: 50%;
  328. background-color: var(--themeColor);
  329. }
  330. </style>