Просмотр исходного кода

student elective - table re-construction

hare8999@163.com 2 лет назад
Родитель
Сommit
d58ea39e33

+ 3 - 0
src/common/mx-extension.js

@@ -52,6 +52,9 @@ export default {
       })
       return result
     }
+    Array.prototype.clear = function() {
+      this.splice(0, this.length)
+    }
 
     // String
     String.prototype.castObject = function() {

+ 0 - 2
src/views/system/user/profile/components/ai-analysis-dialog.vue

@@ -11,7 +11,6 @@
     <span slot="footer" class="dialog-footer">
         <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
     </span>
-<!--    <single-subject-report :admissionInfo="prevPreferencesInfo"  :reportInfo="formatRows"  ref="SingleSubjectReport"></single-subject-report>-->
   </el-dialog>
 </template>
 <script>
@@ -25,7 +24,6 @@ export default {
   },
   props: {
     generation: Object,
-    prevPreferencesInfo: String,
     optionalMajors: { type: Array, default: () => [] }
   },
   data() {

+ 0 - 2
src/views/system/user/profile/components/ai-table.vue

@@ -76,8 +76,6 @@ export default {
       row.subjects = optionalMajors.map(m => m['majorCategoryName'])
       return row
     })
-
-
   },
   computed: {
     resolveTablePrefix() {

+ 82 - 0
src/views/system/user/profile/components/elective-preference-command.vue

@@ -0,0 +1,82 @@
+<template>
+  <span v-if="!group.allowSelect">{{ group.disabledReason || '无法报名' }}</span>
+  <span v-else-if="group.selected" class="f-red btn-red" @click="handleCancel">取消报名</span>
+  <span v-else-if="isRejected">已拒绝</span>
+  <span v-else-if="enableCommit" class="f-warning">被锁定</span>
+  <span v-else class="btn-green" @click="handleCommit">报名</span>
+</template>
+
+<script>
+import ElectiveToolsMixin from './elective-tools-mixins'
+import { submitElectiveModels } from '@/api/webApi/elective/selected-subject'
+
+export default {
+  mixins: [ElectiveToolsMixin],
+  name: 'elective-preference-command',
+  props: ['generation', 'group'],
+  inject: {
+    refreshData: {
+      default: function() {
+      }
+    }
+  },
+  computed: {
+    selectedList() {
+      return this.generation.activeModel.selectedList
+    },
+    isRejected() {
+      return this.selectedList.some(this.isGroupRejected)
+    },
+    enableCommit() {
+      return this.selectedList.length >= this.generation.activeModel.preferenceCount
+    },
+    preferenceCount() {
+      return this.generation.activeModel.preferenceCount
+    }
+  },
+  methods: {
+    async handleCommit() {
+      if (this.enableCommit) {
+        this.$message.error(this.preferenceCount == 1 ? `只能填报1个志愿` : `最多只能填报${this.preferenceCount}个志愿`)
+        return
+      }
+      if (this.preferenceCount > 1) {
+        // 多志愿在elective-preference-drag中有确认环节,这里直接操作即可
+        this.group.selected = true
+        this.selectedList.push(this.group)
+      } else {
+        await this.$confirm(`确认填报 ${this.group.groupName}`)
+        this.group.selected = true
+        this.selectedList.push(this.group)
+        try {
+          await submitElectiveModels({ models: this.selectedList.map(g => g.groupId) })
+          this.$message.success('报名成功')
+        } finally {
+          this.refreshData()
+        }
+      }
+    },
+    async handleCancel() {
+      if (this.preferenceCount > 1) {
+        // 同上
+        this.group.selected = false
+        this.selectedList.remove(this.group)
+      } else {
+        await this.$confirm(`确认取消填报 ${this.group.groupName}`)
+        this.group.selected = false
+        this.selectedList.remove(this.group)
+        try {
+          await submitElectiveModels({ models: this.selectedList.map(g => g.groupId) })
+          this.$message.success('报名取消成功,您可以重新填报')
+        } finally {
+          this.refreshData()
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 23 - 38
src/views/system/user/profile/components/test-drage.vue → src/views/system/user/profile/components/elective-preference-drag.vue

@@ -1,22 +1,16 @@
 <template>
   <!--  拖拽demo-->
-  <transition-group name="drag"
-                    class="list"
-                    tag="ul"
-  >
-    <li
-      v-for="(item, index) in sortList"
-      :key="item.groupId"
-    >
-      <span>{{`第${index + 1}志愿:`}}</span>
-      <span v-if="!btnDisabled" @dragenter="dragenter($event, index)"
+  <transition-group name="drag" class="list" tag="ul">
+    <li v-for="(item, index) in selectedList" :key="item.groupId">
+      <span>{{ `第${index + 1}志愿:` }}</span>
+      <span class="list-item"
+            @dragenter="dragenter($event, index)"
             @dragover="dragover($event, index)"
             @dragstart="dragstart(index)"
-            class="list-item move"
-            draggable
-            >{{ item.groupName }}</span>
-      <span class="list-item" v-else>{{ item.groupName }}</span>
-      <el-button style="cursor: pointer" @click="del(index)" size="mini" v-if="!btnDisabled"  type="danger">删除</el-button>
+            :class="{'move': !disabled}"
+            :draggable="!disabled"
+      >{{ item.groupName }}</span>
+      <el-button style="cursor: pointer" @click="del(index)" size="mini" v-if="!disabled" type="danger">删除</el-button>
     </li>
   </transition-group>
 </template>
@@ -24,24 +18,15 @@
 export default {
   props: {
     selectedList: Array,
-    btnDisabled: {
+    disabled: {
       type: Boolean,
       default: false
-    },
+    }
   },
   data() {
     return {
       dragIndex: '',
-      enterIndex: '',
-      sortList: [],
-    }
-  },
-  watch: {
-    selectedList: {
-      immediate:true,
-      handler(val){
-        this.sortList = val
-      }
+      enterIndex: ''
     }
   },
   methods: {
@@ -52,19 +37,16 @@ export default {
       e.preventDefault()
       // 避免源对象触发自身的dragenter事件
       if (this.dragIndex !== index) {
-        const source = this.sortList[this.dragIndex]
-        this.sortList.splice(this.dragIndex, 1)
-        this.sortList.splice(index, 0, source)
+        const source = this.selectedList[this.dragIndex]
+        this.selectedList.splice(this.dragIndex, 1)
+        this.selectedList.splice(index, 0, source)
         // 排序变化后目标对象的索引变成源对象的索引
         this.dragIndex = index
       }
     },
-    shuffle() {
-      this.sortList = this.$shuffle(this.sortList)
-    },
     del(index) {
-      this.sortList[index].selected = false
-      this.sortList.splice(index,1)
+      this.selectedList[index].selected = false
+      this.selectedList.splice(index, 1)
     },
     dragover(e, index) {
       e.preventDefault()
@@ -80,16 +62,19 @@ export default {
   .drag-move {
     transition: transform .3s;
   }
-  li{
+
+  li {
     font-size: 14px;
     margin-bottom: 6px;
   }
-  .move{
+
+  .move {
     cursor: move;
   }
+
   .list-item {
 
-    display:inline-block ;
+    display: inline-block;
     margin: 0 10px;
     width: 160px;
     background: #42b983;

+ 35 - 0
src/views/system/user/profile/components/elective-preference-info.vue

@@ -0,0 +1,35 @@
+<template>
+  <div>
+    <div v-if="generation.activeOpt.decisionMaking">
+      <span>您在{{ appliedModel.option.title }}阶段</span>
+      <span v-if="!appliedModel.selectedList.length">未填报志愿</span>
+      <span v-else-if="appliedModel.selectedList.some(isGroupRejected)">拒绝了系统推荐组合</span>
+      <span v-else-if="appliedModel.selectedList.length">填报了 {{ allSelectedGroupNames }}</span>
+      <elective-preference-drag :selected-list="appliedModel.selectedList" disabled></elective-preference-drag>
+    </div>
+  </div>
+</template>
+
+<script>
+import ElectiveToolsMixin from './elective-tools-mixins'
+import ElectivePreferenceDrag from '@/views/system/user/profile/components/elective-preference-drag'
+
+export default {
+  components: { ElectivePreferenceDrag },
+  mixins: [ElectiveToolsMixin],
+  name: 'elective-preference-info',
+  props: ['generation'],
+  computed: {
+    appliedModel() {
+      return this.generation.activeModel.prevModel
+    },
+    allSelectedGroupNames() {
+      return this.appliedModel.selectedList.map(g => g.groupName).join(' ')
+    }
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 90 - 0
src/views/system/user/profile/components/elective-preference-reject.vue

@@ -0,0 +1,90 @@
+<template>
+  <div class="mb5 mt10 text-right">
+    <el-popover v-if="!this.isSelected" ref="pop" placement="right" width="300" trigger="click">
+      <div>
+        <el-input type="textarea" :rows="4" placeholder="请输入原因" v-model="recommendGroup.rejectedReason"></el-input>
+        <p class="fx-row jc-between mt10">
+          <el-button type="primary" size="mini" @click="handlePopClose">取消</el-button>
+          <el-button type="danger" size="mini" @click="handleRejected">提交</el-button>
+        </p>
+      </div>
+      <el-button slot="reference" type="danger">不同意</el-button>
+    </el-popover>
+    <el-button v-if="isRejected" type="primary" @click="handleCancelRejected">撤销拒绝</el-button>
+  </div>
+</template>
+
+<script>
+import ElectiveToolsMixin from './elective-tools-mixins'
+import { rejectRecommend, submitElectiveModels } from '@/api/webApi/elective/selected-subject'
+
+export default {
+  mixins: [ElectiveToolsMixin],
+  name: 'elective-preference-reject',
+  props: ['generation'],
+  inject: {
+    refreshData: {
+      default: function() {
+      }
+    }
+  },
+  computed: {
+    selectedList() {
+      return this.generation.activeModel.selectedList
+    },
+    recommendGroup() {
+      return this.generation.activeModel.models.find(g => g.isRecommend) || {}
+    },
+    isSelected() {
+      return this.selectedList.some(this.isGroupSelected)
+    },
+    isRejected() {
+      return this.selectedList.some(this.isGroupRejected)
+    }
+  },
+  methods: {
+    handlePopClose() {
+      this.$refs.pop.doClose()
+    },
+    async handleCancelRejected() {
+      try {
+        this.selectedList.clear()
+        await submitElectiveModels({ models: [] })
+        this.$message.success('撤销成功,您可以重新报名')
+      } finally {
+        this.refreshData()
+      }
+    },
+    async handleRejected() {
+      if (!this.recommendGroup.rejectedReason) {
+        this.$message.error('拒绝原因不能为空')
+        return
+      }
+      try {
+        const rejects = this.generation.activeModel.models
+          .filter(g => g.allowSelect)
+          .map(g => g.groupName).join(' ')
+        await this.$confirm(`确认拒绝填报 ${rejects}`)
+        this.recommendGroup.rejected = true
+        this.selectedList.clear()
+        this.selectedList.push(this.recommendGroup)
+        await rejectRecommend({
+          models: this.selectedList.map(g => ({
+            groupId: g.groupId,
+            rejected: g.rejected,
+            rejectedReason: g.rejectedReason
+          }))
+        })
+        this.handlePopClose()
+        this.$message.warning('拒绝成功,您未填报任何组合。您可以撤销后重新填报。')
+      } finally {
+        this.refreshData()
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 50 - 0
src/views/system/user/profile/components/elective-tools-mixins.js

@@ -0,0 +1,50 @@
+export default {
+  methods: {
+    isModelEnrolled(model) {
+      // 代录取
+      return model.models?.some(this.isGroupEnrolled)
+    },
+    isModelSelected(model) {
+      // 代组合填报
+      return model.models?.some(this.isGroupSelected)
+    },
+    isModelRejected(model) {
+      return model.models?.some(this.isGroupRejected)
+    },
+    isModelApproved(model) {
+      // 代正常录取
+      return model.models?.some(this.isGroupApproved)
+    },
+    isModelForceAdjusted(model) {
+      // 代强制调剂
+      return model.models?.some(this.isGroupForceAdjusted)
+    },
+    isGroupEnrolled(group) {
+      // 组合录取 = 正常录取 | 强制调剂
+      return group.approved || group.forceAdjusted
+    },
+    isGroupSelected(group) {
+      // 组合填报 = 同意 | 改选 | 拒绝
+      return group.selected || group.rejected
+    },
+    isGroupRejected(group) {
+      // 组合填报拒绝
+      return group.rejected
+    },
+    isGroupApproved(group) {
+      // 组合正常录取
+      return group.approved
+    },
+    isGroupForceAdjusted(group) {
+      // 组合强制调剂
+      return group.forceAdjusted
+    },
+    combineGroupStatus(group, model) {
+      // 逻辑同elective-preference-command
+      if (!group.allowSelect) return group.disabledReason || '无法报名'
+      if (group.selected) return '已报名'
+      if (this.isModelRejected(model)) return '已拒绝'
+      return '报名中'
+    }
+  }
+}

+ 100 - 327
src/views/system/user/profile/components/report-table.vue

@@ -14,32 +14,16 @@
         <over-under-badge :value="value"></over-under-badge>
       </template>
       <template #group="{row}">
-        <over-under-badge :value="row.isRecommend?1:0" over-text="荐" over-type="success">
-          <el-tag size="medium" :type="row.allowSelect ? 'warning' : 'danger'">{{ row.groupName }}</el-tag>
+        <over-under-badge :value="groupRecommend(row)?1:0" over-text="荐" over-type="success">
+          <el-tag size="medium" :type="groupAllowSelect(row)?'warning':'danger'">{{ row.groupName }}</el-tag>
         </over-under-badge>
       </template>
       <template #temp="{row}">
         <span class="btn-blue mr5" @click="toSelectSub(row)">选择</span>
         <span class="btn-green" @click="toReport">查看记录</span>
-        <!--        <el-button>查看</el-button>-->
       </template>
       <template #signUp="{row}">
-        <div v-if="!row.allowSelect">
-          <div v-if="row.selected">
-            <span class="btn-red" v-if="!row.rejected" @click="singleCommit('','取消报名')">取消报名</span>
-            <span v-else>已拒绝</span>
-          </div>
-          <span v-else>{{ row.disabledReason || '无法报名' }}</span>
-        </div>
-        <div v-else>
-          <!-- 初录后报名代 -->
-          <span v-if="generation.current > 1" @click="singleCommit(row)" class="btn-green">报名</span>
-          <!-- 初录报名代 -->
-          <div v-else>
-            <span class="f-red btn-red" v-if="row.selected" @click="toUnSelect(row)">取消报名</span>
-            <span class="btn-green" v-else @click="toSelect(row)">报名</span>
-          </div>
-        </div>
+        <elective-preference-command :generation="generation" :group="row"></elective-preference-command>
       </template>
       <template #subjects="{row}">
         <el-row>
@@ -76,78 +60,38 @@
         </el-row>
       </template>
     </mx-table>
+    <elective-preference-info :generation="generation"></elective-preference-info>
     <!-- 初录 多志愿拖拽 -->
-    <div
-      v-if="this.generation.active == generation.options.primary.value || this.generation.active == generation.options.primaryDM.value">
-      <p>您的选科志愿: <span v-for="(item,index) in activeModels.generation.selectedList">
-        {{ item.groupName }}
-      </span>
-      </p>
-      <div>
-        <test-drage ref="drage" :btnDisabled="this.generation.current != generation.options.primary.value"
-                    :selectedList="activeModels.generation.selectedList"
-        ></test-drage>
-        <el-button @click="commit" type="primary" v-if="this.generation.current == generation.options.primary.value">
-          提交
-        </el-button>
-      </div>
-    </div>
-    <div v-if="generation.current > generation.active && generation.active > generation.options.primaryDM.value">
-      <!--  补录报名和二次补录报名和调剂报名历史报名信息 -->
-      {{ historySupply }}
-    </div>
-    <!--  补录报名和二次补录报名和调剂报名 -->
-    <div v-if="flagShow">
-      <div class="mb5 mt10 text-right">
-        <el-popover
-          v-if="activeModels.generation.models.filter(item => {return item.selected}).length == 0"
-          placement="right"
-          width="300"
-          v-model="popoShow"
-          trigger="click"
-        >
-          <div>
-            <!--            确定拒绝<span class="f-primary">{{recommendGroup.groupName}}</span>组合么?-->
-            <!--            确定拒绝系统给您推荐的<span class="f-primary">{{ recommendGroup.groupName }}</span>组合么?-->
-            <el-input
-              type="textarea"
-              :rows="4"
-              placeholder="请输入原因"
-              v-model="regInfo"
-            >
-            </el-input>
-            <p class="fx-row jc-between mt10">
-              <el-button type="primary" size="mini" @click="popoShow = false">取消</el-button>
-              <el-button type="danger" size="mini" @click="handleRejectRecommend">提交</el-button>
-            </p>
-          </div>
-          <el-button slot="reference" type="danger">不同意</el-button>
-        </el-popover>
-        <el-button v-if="activeModels.generation.models.filter(item => {return item.rejected}).length > 0"
-                   type="primary" @click="singleCommit('','撤销拒绝报名')">撤销拒绝报名
-        </el-button>
-      </div>
+    <div v-if="enableMultipleDrag">
+      <span v-if="selectedList.length">您填报了 {{ allSelectedGroupNames }}</span>
+      <elective-preference-drag :disabled="!enableSelect" :selected-list="selectedList"></elective-preference-drag>
+      <el-button v-if="enableSelect" @click="commitBatch" type="primary" :disabled="!enableCommit">提交</el-button>
     </div>
+    <elective-preference-reject v-if="enableReject" :generation="generation"></elective-preference-reject>
     <esign-dialog ref="esignDialog"></esign-dialog>
     <choose-subject-dialog ref="chooseDialog"></choose-subject-dialog>
     <select-subject-report-dialog ref="reportDialog"></select-subject-report-dialog>
-    <Ai-dialog ref="aiDialog" :optionalMajors="optionalMajors" :prevPreferencesInfo="currentSupplyInfo"
-               :generation="generation"></Ai-dialog>
+    <ai-analysis-dialog ref="aiDialog" :optionalMajors="optionalMajors" :prevPreferencesInfo="currentSupplyInfo"
+                        :generation="generation"></ai-analysis-dialog>
   </div>
 </template>
 <script>
-import AiDialog from './ai-analysis-dialog'
 import MxSelectTranslate from '@/components/Cache/modules/mx-select-translate-mixin.js'
-import TestDrage from './test-drage'
+import ElectivePreferenceDrag from './elective-preference-drag'
 import ChooseSubjectDialog from './choose-subject-dialog'
 import SelectSubjectReportDialog from '@/views/system/user/profile/components/select-subject-report-dialog'
 import EsignDialog from '@/views/system/user/profile/components/esign-dialog'
 import ReportStep from './report-step'
 import OverUnderBadge from '@/views/elective/publish/components/steps/fauclty/over-under-badge'
-import { rejectRecommend, submitElectiveModels } from '@/api/webApi/elective/selected-subject'
+import { submitElectiveModels } from '@/api/webApi/elective/selected-subject'
 import consts from '@/common/mx-const'
 import { mapGetters } from 'vuex'
 import ElectiveEnrollInfo from '@/views/system/user/profile/components/elective-enroll-info'
+import ElectiveToolsMixin from './elective-tools-mixins'
+import ElectivePreferenceInfo from '@/views/system/user/profile/components/elective-preference-info'
+import ElectivePreferenceReject from '@/views/system/user/profile/components/elective-preference-reject'
+import ElectivePreferenceCommand from '@/views/system/user/profile/components/elective-preference-command'
+import AiAnalysisDialog from '@/views/system/user/profile/components/ai-analysis-dialog'
 
 const resolverModules = require.context('./round-select-resolvers', false, /\.js$/)
 const resolvers = resolverModules.keys().map(key => resolverModules(key).default)
@@ -159,44 +103,43 @@ export default {
     optionalMajors: { type: Array, default: () => [] }
   },
   components: {
+    AiAnalysisDialog,
+    ElectivePreferenceCommand,
+    ElectivePreferenceReject,
+    ElectivePreferenceInfo,
     ElectiveEnrollInfo,
     OverUnderBadge,
     SelectSubjectReportDialog,
     ReportStep,
     EsignDialog,
-    TestDrage,
-    ChooseSubjectDialog,
-    AiDialog
+    ElectivePreferenceDrag,
+    ChooseSubjectDialog
   },
   inject: {
-    'refreshData': {
+    refreshData: {
       default: function() {
       }
     }
   },
-  mixins: [MxSelectTranslate, ...resolvers],
-  data() {
-    return {
-      popoShow: false,
-      regInfo: '', // 拒绝原因
-      dialogVisible: false,
-      singleList: [], // 单志愿列表
-      rows: []
-    }
-  },
+  mixins: [ElectiveToolsMixin, MxSelectTranslate, ...resolvers],
   computed: {
     ...mapGetters(['hasPermissions']),
     enrollInfoVisible() {
       return this.generation.active > this.generation.options.primary.value
     },
     enrollStatus() {
-      const enrolledGroup = this.generation.activeModel.models?.find(m => m.approved || m.forceAdjusted)
+      const enrolledGroup = this.generation.activeModel.models?.find(this.isGroupEnrolled)
       if (enrolledGroup) {
         let enrolledModel = this.generation.activeModel
         do {
-          const matched = enrolledModel.models?.find(m => m.groupId == enrolledGroup.groupId && (m.approved || m.forceAdjusted))
-          if (matched && enrolledModel.selectedList.includes(matched)) {
-            return { enrolledGroup, enrolledModel }
+          const matched = enrolledModel.models?.find(this.isGroupEnrolled)
+          if (matched
+            && matched.groupId == enrolledGroup.groupId
+            && enrolledModel.selectedList.includes(matched)) {
+            return {
+              enrolledGroup,
+              enrolledModel
+            }
           }
           enrolledModel = enrolledModel.prevModel
         }
@@ -204,92 +147,32 @@ export default {
       }
       return { enrolledGroup, enrolledModel: null }
     },
-    historySupply() {
-      // 当前代历史报名信息
-      if (!this.generation.models.length) return ''
-      // 填报 || 拒绝  || 未选择
-      // 当前代
-      const activeModels = this.generation.models.find(item => item.generation == this.generation.active)
-      const isRefuse = activeModels.models.filter(item => item.rejected)
-      if (isRefuse.length > 0) {
-        // 拒绝了
-        return '您拒绝了填报志愿'
-      } else {
-        //  填报 or 未选择
-        const supply = activeModels.models.filter(item => item.selected)
-        if (supply.length > 0) {
-          return `填报志愿为${supply[0].groupName}`
-        } else {
-          return '您未填报志愿'
-        }
-      }
+    stepMatched() {
+      return this.generation.active == this.generation.current
     },
-    // 不符
-    currentSupplyInfo() {
-      if (!this.generation.models.length) return ''
-      // console.log(this.generation)
-      if (this.generation.active < this.generation.options.primaryDM.value) return ''
-      let info = ''
-      const activeModels = this.generation.models.find(item => item.generation == this.generation.active)
-      // 当前代是否被录取?
-      const approved = activeModels.models.filter(item => {
-        return item.approved
-      })
-      if (approved.length) {
-        // 查找在哪一阶段被录取 ? 根据selected 和 approved 都为true
-        const model = this.generation.activeModels.filter(model => {
-          const flag = model.models.some(item => {
-            return item.selected && item.approved
-          })
-          if (flag) return model
-        })
-        const admissionAgent = Object.values(this.generation.options).find(item => item.value == model[0].generation - 1)
-        // 已被录取
-        info = `你在${admissionAgent.title}所选择的${approved[0].groupName}已被录取`
-      } else {
-        // 已报名未被录取的group 取当前models的前一个
-        const prevModels = this.generation.models.find(item => item.generation == activeModels.generation - 1)
-
-        // 是否拒绝 ?
-        const isRefuse = prevModels.models.filter(item => item.rejected)
-        if (isRefuse.length > 0) {
-          // 拒绝报名
-          let tips = ''
-          const prevGen = Object.values(this.generation.options).find(item => item.value == prevModels.generation)
-          if (prevGen.decisionMaking) {
-            tips = Object.values(this.generation.options).find(item => item.value == prevModels.generation - 1).title
-          } else {
-            tips = prevGen.title
-          }
-          const isSupply = prevGen.decisionMaking ? ',现有以下标黄组合可以重新报名' : ''
-          info = `<p>你在${tips}时拒绝填报志愿 ${isSupply} </p>`
-        } else {
-          // 没被录取的组合
-          const refuseGroup = prevModels.models.filter(item => {
-            return item.selected
-          })
-          // 获取报名的阶段
-          let tips = ''
-          const prevGen = Object.values(this.generation.options).find(item => item.value == prevModels.generation)
-          if (prevGen.decisionMaking) {
-            tips = Object.values(this.generation.options).find(item => item.value == prevModels.generation - 1).title
-          } else {
-            tips = prevGen.title
-          }
-          const isSupply = prevGen.decisionMaking ? ',现有以下标黄组合可以重新报名' : ''
-          if (refuseGroup.length > 0) {
-            info = `<p>你在${tips}所选择的 <span class="f-red">${refuseGroup.map(g => g.groupName).join(',').toString()}</span> 不符合条件${isSupply} </p>`
-          } else {
-            info = `<p>你在${tips}时未填报志愿 ${isSupply} </p>`
-          }
-        }
-      }
-      return info
+    selectStep() {
+      return !this.generation.activeOpt.decisionMaking
     },
-    flagShow() {
-      const stepMatched = this.generation.active == this.generation.current
-      const selectStep = !this.generation.activeOpt.decisionMaking
-      return stepMatched && selectStep && !this.readonly && !this.activeModels.isAdmission
+    enableSelect() {
+      return this.stepMatched && this.selectStep && !!!this.enrollStatus.enrolledGroup && !this.readonly
+    },
+    selectedList() {
+      return this.generation.activeModel.selectedList
+    },
+    allSelectedGroupNames() {
+      return this.selectedList.map(g => g.groupName).join(' ')
+    },
+    enableCommit() {
+      return this.selectedList.length == this.generation.status.preferenceCount
+    },
+    multipleSelect() {
+      return this.generation.activeModel.preferenceCount > 1
+    },
+    enableMultipleDrag() {
+      return this.selectStep && this.multipleSelect
+    },
+    enableReject() {
+      return this.enableSelect && this.generation.active > this.generation.options.primary.value
     },
     enableAIFeature() {
       if (!this.generation.activeOpt) return false
@@ -379,32 +262,14 @@ export default {
       }
       return dynamicColumns
     },
-    activeModels() {
-      if (!this.generation) return {}
-      const generation = this.generation.models.find(item => item.generation == this.generation.active)
-      // 是否被录取
-      const isAdmission = generation.models.some(item => item.approved || item.forceAdjusted)
-      console.log(isAdmission)
-      // generation.selectedList = generation.models.filter(item => {
-      //   return item.selected
-      // })
-      return {
-        isAdmission,
-        generation
-      }
-    },
-    recommendGroup() {
-      return this.activeModels?.generation.models?.find(m => m.isRecommend) || {}
-    },
-    // 初始化 rows 填充固定数据
     formatRows() {
       if (!this.optionalMajors) return []
       if (!this.generation.roundGroups?.length) return []
       if (!this.generation.activeModels?.length) return []
-      const generationModels = this.generation.activeModels.last()?.models || []
+      const activeModel = this.generation.activeModel
       return this.generation.roundGroups.map(rg => {
-        const row = generationModels.find(item => item.groupId == rg.groupId) || {}
-        row.allowSelectTips = row.rejected ? '已拒绝' : row.allowSelect ? '报名中' : row.selected ? '已报名' : row.disabledReason || '无法报名'
+        const row = activeModel.models?.find(item => item.groupId == rg.groupId) || {}
+        row.allowSelectTips = this.combineGroupStatus(row, activeModel)
         const matchedMajors = this.optionalMajors.filter(college => college.matchedGroupIds.includes(row.groupId))
         row.colleges = matchedMajors.map(m => ({ college: m.collegeName, major: m.majorCategoryName }))
         row.subjects = matchedMajors.map(m => m['majorCategoryName'])
@@ -420,149 +285,57 @@ export default {
     }
   },
   methods: {
-    getModelsByStep() {
-      return this.models.findIndex()
-    },
-    isGroupOverSetting(row) {
-      if (this.generation.activeOpt.decisionMaking) {
-        return row.groupApprovedCount >= row.personCount
-      } else {
-        return row.actualCount >= row.groupIndicator
-      }
-    },
-    toReport() {
-      // 是否更改了报名数据 ?
-      const flag = this.activeModels.generation.models.filter(item => item.selected).length == this.activeModels.generation.selectedList.length
-      if (!flag) {
-        this.$message.warning('请先提交更改过的志愿')
-        return
-      }
-      this.$refs.reportDialog.open()
+    groupRecommend(group) {
+      return this.selectStep ? group.isRecommend : group['nextRecommend']
     },
-    toAiAnalysis() {
-      // AI 分析 跳转
-      this.$refs.aiDialog.open(this.formatRows)
+    groupAllowSelect(group) {
+      return this.selectStep ? group.allowSelect : group['nextAllowSelect']
     },
-    singleCommit(row, tips) {
-      const type = row == '' ? tips : '提交报名'
-      // 补录及之后
-      this.$confirm(`是否要${type}`, {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
-      }).then(() => {
-        const arrRow = row == '' ? [] : [row]
-        submitElectiveModels({
-          models: arrRow
-          // esign:this.base64Img
-        }).then(res => {
-          if (res.code == 200) {
-            this.$message.success('操作成功')
-            this.refreshData()
-          }
+    preventSelectedListChanged() {
+      if (!this.enableSelect) return Promise.resolve(true)
+      const from = this.generation.activeModel.selectedList
+      const to = this.generation.activeModel.selectedListSnapshot
+      let changedMsg = '请先提交更改过的志愿', changed = false
+      if (from.length != to.length) {
+        changed = true
+      } else if (from.length) {
+        const elementCheckFields = ['selected', 'rejected', 'groupId']
+        from.forEach((eleFrom, idx) => {
+          const eleTo = to[idx]
+          const eleChanged = elementCheckFields.some(f => eleFrom[f] != eleTo[f])
+          if (eleChanged) changed = true
         })
-      }).catch(() => {
-        this.$message({
-          type: 'info',
-          message: `已取消${type}`
-        })
-      })
-    },
-    commit(row) {
-      // 初录
-      const real = this.activeModels.generation.selectedList.filter(item => {
-        return item.selected == true
-      })
-      if (real.length < this.generation.status.preferenceCount) {
-        this.$message.warning(`需要选择${this.generation.status.preferenceCount}个志愿`)
-        return
       }
-      this.$confirm(`是否要提交报名`, {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
-      }).then(() => {
-        submitElectiveModels({
-          models: this.activeModels.generation.selectedList
-          // esign:this.base64Img
-        }).then(res => {
-          if (res.code == 200) {
-            this.$message.success('报名成功')
-            this.refreshData()
-          }
-        })
-      }).catch(() => {
-        this.$message({
-          type: 'info',
-          message: '已取消提交'
-        })
-      })
-
-      //
-      // this.$refs.esignDialog.open(this.activeModels.selectedList)
+      if (changed) this.$message.warning(changedMsg)
+      return changed ? Promise.reject(changedMsg) : Promise.resolve(true)
     },
-    toSelect(row) {
-      const preferenceCount = this.generation.status.preferenceCount
-      const count = this.formatRows.reduce((prev, cur) => {
-        return prev += cur.selected ? 1 : 0
-      }, 0)
-      if (count >= preferenceCount) {
-        this.$message.warning(`最多选择${preferenceCount}个志愿`)
-        return
-      }
-      this.activeModels.generation.models.find(item => item.groupId == row.groupId).selected = true
-      row.selected = true
-      if (!this.activeModels.selectedList.includes(row)) this.activeModels.generation.selectedList.push(row)
-    },
-    toUnSelect(row) {
-      this.$confirm(`是否解除选科组合【${row.groupName}】`, '警告', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
-      }).then(() => {
-        this.activeModels.generation.models.find(item => item.groupId == row.groupId).selected = false
-        row.selected = false
-        const start = this.activeModels.generation.selectedList.findIndex(item => item.groupId == row.groupId)
-        this.activeModels.generation.selectedList.splice(start, 1)
-      }).catch(() => {
-        this.$message({
-          type: 'info',
-          message: '已取消解除报名'
-        })
-      })
+    async toReport() {
+      await this.preventSelectedListChanged()
+      this.$refs.reportDialog.open()
     },
-    toSelectSub(row) {
-      // 是否更改了报名数据 ?
-      const flag = this.activeModels.generation.models.filter(item => item.selected).length == this.activeModels.generation.selectedList.length
-      if (!flag) {
-        this.$message.warning('请先提交更改过的志愿')
-        return
-      }
+    async toSelectSub(row) {
+      await this.preventSelectedListChanged()
       // 打开选科弹窗
       const course0 = this.translateCourse0(row.groupId)
       const course1 = this.translateCourse1(row.groupId)
       this.$refs.chooseDialog.open(course0, course1)
     },
-    async handleRejectRecommend() {
-      if (!this.regInfo.length) {
-        this.$message.error('拒绝原因不能为空')
+    toAiAnalysis() {
+      // AI 分析 跳转
+      this.$refs.aiDialog.open(this.formatRows)
+    },
+    async commitBatch() {
+      if (this.selectedList.length != this.generation.status.preferenceCount) {
+        this.$message.warning(`需要选择${this.generation.status.preferenceCount}个志愿`)
         return
       }
-      const rejectRow = this.activeModels.generation.models.filter(item => item.allowSelect)
-      await this.$confirm(`是否拒绝报名${rejectRow.map(item => item.groupName).join(',')}?`)
-      // 可以报名的组合都拒绝
-      rejectRecommend({
-        models: rejectRow
-      }).then(res => {
-        if (res.code == 200) {
-          this.refreshData()
-        }
-      }).finally(_ => {
-        this.regInfo = ''
-      })
-    },
-    initOption(optionalMajors) {
-      this.optionalMajors = optionalMajors
+      await this.$confirm(`确认填报 ${this.allSelectedGroupNames}`)
+      try {
+        await submitElectiveModels({ models: this.selectedList.map(g => g.groupId) })
+        this.$message.success('报名成功')
+      } finally {
+        this.refreshData()
+      }
     }
   }
 }

+ 4 - 2
src/views/system/user/profile/round-select.vue

@@ -53,6 +53,7 @@ import SelectSubject from '@/views/system/user/profile/components/select-subject
 import ReportTable from '@/views/system/user/profile/components/report-table'
 import ElectiveGenerationSteps from '@/views/elective/generation/components/elective-generation-steps'
 import TransferMixin from '@/components/mx-transfer-mixin'
+import ElectiveToolsMixin from './components/elective-tools-mixins'
 import config from '@/common/mx-config'
 import {
   getStudentElectiveModels,
@@ -62,7 +63,7 @@ import {
 } from '@/api/webApi/elective/selected-subject'
 
 export default {
-  mixins: [TransferMixin],
+  mixins: [TransferMixin, ElectiveToolsMixin],
   provide() {
     return {
       optionalMajors: this.getOptionalMajors,
@@ -171,9 +172,10 @@ export default {
       getStudentElectiveModels().then(res => {
         // NOTE: create local selected list !!important
         res.data.forEach(gen => {
-          const localSelected = gen.models?.filter(m => m.selected || m.rejected)
+          const localSelected = gen.models?.filter(this.isGroupSelected)
           localSelected?.sort((l, r) => l.selectedRank - r.selectedRank)
           gen.selectedList = localSelected || []
+          gen.selectedListSnapshot = this.deepClone(gen.selectedList) // 快照,用于对比变更
           gen.option = Object.values(this.stepOptions).find(opt => opt.value == gen.generation)
           gen.prevModel = res.data.find(m => m.generation == gen.generation - 1)
           gen.nextModel = res.data.find(m => m.generation == gen.generation + 1)