소스 검색

根据学校上报时间,自动分配学校名额

lrf402788946 5 년 전
부모
커밋
d56f2b9cb8
6개의 변경된 파일608개의 추가작업 그리고 68개의 파일을 삭제
  1. 19 1
      src/plugins/dateM.js
  2. 216 66
      src/views/new-plan/arrange.vue
  3. 129 0
      src/views/new-plan/parts/event.vue
  4. 231 0
      src/views/new-plan/parts/school-arrange.vue
  5. 7 1
      src/views/new-plan/template.vue
  6. 6 0
      src/views/school/detail.vue

+ 19 - 1
src/plugins/dateM.js

@@ -3,7 +3,7 @@ import _ from 'lodash';
 var moment = require('moment');
 const Plugin = {
   install(Vue, options) {
-    Vue.prototype.$checkDate = ({ startStr, endStr, vacation = [] }) => {
+    Vue.prototype.$checkDate = (startStr, endStr, vacation = []) => {
       let res = true;
       let cbt = (time, vs, ve) => {
         let r = moment(time).isBetween(vs, ve, null, '[]');
@@ -25,6 +25,24 @@ const Plugin = {
       }
       return res;
     };
+    Vue.prototype.$tqInRange = (start, end, ranges) => {
+      let res = { result: false };
+      //开始时间
+      for (const range of ranges) {
+        let { start: s, end: e } = range;
+        //开始时间在范围开始前=>说明检测的时间段不在这个范围内;继续循环
+        if (moment(start).isBefore(s)) continue;
+        //开始时间是否在范围内=>true:说明在,继续检查end在不在范围内;false:不在范围内;继续循环
+        if (!moment(start).isBetween(s, e, null, '[]')) continue;
+        //结束时间是否在范围内=>true:说明检测的时间段在该范围内,break;false=>说明不行;继续循环
+        if (moment(end).isBetween(s, e, null, '[]')) {
+          res.result = true;
+          res.checkData = { start, end };
+          res.range = range;
+        }
+      }
+      return res;
+    };
     Vue.prototype.$plusDay = (date, day = 1) => {
       return moment(date)
         .add(day, 'days')

+ 216 - 66
src/views/new-plan/arrange.vue

@@ -1,7 +1,7 @@
 <template>
   <div id="arrange">
-    <detail-frame :title="pageTitle" returns="./index">
-      <el-row :gutter="10" type="flex">
+    <detail-frame :title="pageTitle" :returns="returns">
+      <el-row :gutter="10" type="flex" v-if="view == 'plan'">
         <el-col :span="12">
           <el-card header="全年计划信息">
             <el-form :model="info" :rules="rules" :isNew="isNew" label-width="60px" size="small" @submit.native.prevent>
@@ -33,14 +33,36 @@
           </el-card>
         </el-col>
       </el-row>
+      <template v-else>
+        <sch-arr :events="events" :year="info.year" :template="template"></sch-arr>
+      </template>
     </detail-frame>
+    <el-drawer :visible.sync="drawer" direction="rtl" title="安排计划" @close="toClose">
+      <event
+        :data="form"
+        :year="info.year"
+        :vacation="vacation"
+        :isNew="formIsNew"
+        :predefineColors="template.color"
+        @save="setEvent"
+        @delete="toDelete"
+      ></event>
+    </el-drawer>
     <el-dialog :visible.sync="dialog" title="模板计划" width="30%" :close-on-click-modal="false">
       <el-form>
         <el-form-item label="请输入您要生成的期数">
           <el-input v-model="input.term"></el-input>
         </el-form-item>
         <el-form-item label="请选择开始日期">
-          <el-date-picker v-model="input.start" type="date" placeholder="请选择开始日期" format="yyyy-MM-dd" value-format="yyyy-MM-dd"> </el-date-picker>
+          <el-date-picker
+            :picker-options="pickerOptions"
+            v-model="input.start"
+            type="date"
+            placeholder="请选择开始日期"
+            format="yyyy-MM-dd"
+            value-format="yyyy-MM-dd"
+          >
+          </el-date-picker>
         </el-form-item>
       </el-form>
       <template #footer>
@@ -63,18 +85,22 @@ var moment = require('moment');
 import detailFrame from '@frame/layout/admin/detail-frame';
 import calendar from '@frame/components/calendar';
 import dataTable from '@frame/components/data-table';
+import event from './parts/event';
+import schArr from './parts/school-arrange';
 import { mapState, createNamespacedHelpers } from 'vuex';
 const { mapActions } = createNamespacedHelpers('trainplan');
 const { mapActions: trainTemplate } = createNamespacedHelpers('trainTemplate');
 export default {
   name: 'arrange',
   props: {},
-  components: { detailFrame, calendar, dataTable },
+  components: { detailFrame, calendar, dataTable, event, schArr },
   data: function() {
     var that = this;
     return {
+      view: 'plan',
       template: {},
       info: {},
+      form: {},
       selectList: [],
       events: [],
       vacation: [],
@@ -111,17 +137,26 @@ export default {
       selfBtn: {
         term: {
           text: '生成模板计划',
-          //设置假期
           click: () => (that.dialog = true),
           position: 'left',
         },
+        school: {
+          text: '学校安排',
+          click: () => (that.view = 'school'),
+          position: 'left',
+        },
       },
       input: {
-        term: 50,
-        start: '2020-01-01',
+        term: 55,
+        start: '2020-03-01',
+      },
+      pickerOptions: {
+        disabledDate: time => that.checkDate(time),
       },
       heights: 250,
       collapse: '',
+      drawer: false,
+      formIsNew: true,
     };
   },
   created() {
@@ -150,70 +185,144 @@ export default {
         this.$set(this, `info`, res.data);
       }
     },
+    //模板事件开始
+    //生成默认模板
     setDefaultPlan() {
+      this.$set(this, `events`, []);
+      this.$set(this, `selectList`, []);
       this.dialog = false;
       let { term, start } = this.input;
       let { day, batchnum, classnum } = this.template;
       let event = []; //处理成功事件的存储
-      let qb = 0; //剩余没有满足之前的批数
-      let qt = 0; //剩余没有满足之前的期数
       //第一次正常安排
-      let arrange = (t, v) => {
-        let arr = [];
-        for (let it = 1; it <= t; it++) {
-          for (let ib = 1; ib <= v; ib++) {
-            let end = this.$plusDay(start, day - 1);
-            let object = { startStr: start, endStr: end, vacation: this.vacation };
-            let res = this.$checkDate(object);
-            if (res == true) {
-              let batch = {
-                term: it - qt,
-                batch: ib,
-                class: classnum,
-                start,
-                end,
-                type: '0',
-                title: `第${it - qt}期第${ib}批次`,
-                color: this.getColor(it, ib),
-              };
-              start = this.$plusDay(start);
-              arr.push(batch);
-            } else {
-              if (ib == 1) qt += 1;
-              else qb += batchnum - ib + 1;
-              start = this.$plusDay(res.end);
-              break;
-            }
-          }
-        }
-        return arr;
-      };
-      event = arrange(term, batchnum);
-      while (qb > 0) {
-        qt = qt + Math.ceil(qb / batchnum);
-        let sb = qb % batchnum;
-        let lessArr = arrange(qt, batchnum);
-        let last = _.last(event);
-        let lessNArr = _.chunk(lessArr, 3).map((i, index) => {
-          i.map(ii => {
-            ii.term = last.term + index + 1;
-            ii.title = `第${ii.term}期第${ii.batch}批次`;
-            return ii;
-          });
-          return i;
-        });
-        lessArr = _.flatten(lessNArr);
-        //TODO需要判断是否还有剩余的批次,有的话还需要处理
-      }
-
+      //qb:剩余没有满足之前的批数 qt:剩余没有满足之前的期数
+      let { list, qb, start: rstart } = this.arrange(term, start);
+      event = list;
+      start = rstart;
+      event = this.otherArrange(qb, start, event);
       //最后赋值回去
+      event.map((i, index) => {
+        i.index = index;
+        return i;
+      });
       this.$set(this, `events`, event);
       this.$set(this, `selectList`, event);
     },
-    setHeight() {
-      let heights = this.$refs.card.$el.clientHeight * 0.63;
-      this.$set(this, `heights`, heights);
+    //默认安排事件
+    arrange(t, start, part) {
+      let qt = 0;
+      let qb = 0;
+      let { day, batchnum, classnum } = this.template;
+      if (!part) part = batchnum;
+      let list = [];
+      for (let it = 1; it <= t; it++) {
+        for (let ib = 1; ib <= part; ib++) {
+          let end = this.$plusDay(start, day - 1);
+          let res = this.$checkDate(start, end, this.vacation);
+          if (res == true) {
+            let batch = {
+              term: it - qt,
+              batch: ib,
+              class: classnum,
+              start,
+              end,
+              type: '0',
+              title: `第${it - qt}期第${ib}批次`,
+              color: this.getColor(it, ib),
+            };
+            start = this.$plusDay(start);
+            list.push(batch);
+          } else {
+            if (ib == 1) qt += 1;
+            qb += batchnum - ib + 1;
+            start = this.$plusDay(res.end);
+            break;
+          }
+        }
+      }
+      return { list, qb, start };
+    },
+    //默认处理未安排的事件
+    otherArrange(qb, start, event) {
+      let { day, batchnum, classnum } = this.template;
+      //将剩余的批数转换成局部变量,然后赋0重置qb,为了在arrange中重新计算是否有接触假期
+      let tta = Math.ceil(qb / batchnum);
+      let part = qb % batchnum;
+      qb = 0;
+      let { list, qb: rqb, start: rstart } = this.arrange(tta, start, part);
+      start = rstart;
+      let last = _.last(event);
+      let arr = [];
+      if (last) arr = this.sortOtherData(last, list);
+      else arr = list;
+      event = event.concat(arr);
+      //判断是否还有剩余的批次,期;有的话还需要处理
+      if (rqb > 0) {
+        return this.otherArrange(rqb, start, event);
+      } else {
+        return event;
+      }
+    },
+    //默认事件排序
+    sortOtherData(last, data) {
+      let arr = _.chunk(data, 3).map((i, index) => {
+        i.map(ii => {
+          ii.term = last.term + index + 1;
+          ii.title = `第${ii.term}期第${ii.batch}批次`;
+          return ii;
+        });
+        return i;
+      });
+      return _.flatten(arr);
     },
+    //模板事件结束
+
+    //手动操作事件开始
+    setEvent({ data, isNew }) {
+      console.log(data);
+      data = JSON.parse(JSON.stringify(data));
+      if (data.type == 0) {
+        data.title = `第${data.term}期第${data.batch}批次`;
+      } else {
+        let { name } = data;
+        data = { ...data, title: name };
+      }
+      this.$set(this.events, data.index, data);
+      this.$set(this.selectList, data.index, data);
+      // 需要根据班级类型把数据分开
+      // let { start, end, term, type, number, color, id } = data;
+      // let object = {};
+      // if (data.type === '0') {
+      //   // 正常班级
+      //   let { batch, class: classes } = data;
+      //   object = { start, end, term, type, number, color, batch, class: classes };
+      //   object.title = `第${JSON.parse(JSON.stringify(term))}期第${JSON.parse(JSON.stringify(batch))}批次`;
+      //   object.name = JSON.parse(JSON.stringify(object.title));
+      // } else {
+      //   let { name } = data;
+      //   object = { ...data, title: name };
+      // }
+      // if (isNew) {
+      //   object.id = `eve${new Date().getTime()}`;
+      //   this.events.push(object);
+      //   this.selectList.push(object);
+      // } else {
+      //   object.id = id;
+      //   this.$set(
+      //     this.events,
+      //     _.findIndex(this.events, item => item.id == object.id),
+      //     object
+      //   );
+      //   this.$set(
+      //     this.selectList,
+      //     _.findIndex(this.selectList, item => item.id == object.id),
+      //     object
+      //   );
+      // }
+      // if (_.findIndex(this.predefineColors, item => item == data.color) < 0) this.predefineColors.push(data.color);
+      this.toClose();
+    },
+
     //列表编辑事件
     toEdit({ data, index }) {
       this.$set(this, `form`, JSON.parse(JSON.stringify(data)));
@@ -225,17 +334,35 @@ export default {
       this.$set(
         this,
         `events`,
-        this.events.filter(f => f.id !== data.id)
+        this.events.filter(f => f.index !== data.index)
       );
-      // this.events.splice(index, 1);
       this.selectList.splice(index, 1);
+      this.toClose();
     },
     //计划保存
     savePlan() {},
+    //选择时间的事件
+    selectDate(object) {
+      let start = JSON.parse(JSON.stringify(object.startStr));
+      let end = JSON.parse(JSON.stringify(object.endStr));
+      this.$set(this.form, `start`, start);
+      this.$set(this.form, `end`, end);
+      this.$set(this.form, `index`, this.events.length);
+      this.drawer = true;
+      this.formIsNew = true;
+    },
     //
-    selectDate() {},
-    //
-    eventClick() {},
+    eventClick({ event }) {
+      let obj = _.get(event, `extendedProps`);
+      if (!obj) {
+        console.warn(`无对应事件`);
+        return;
+      }
+      let e = this.events.find(f => f.index == obj.index);
+      if (e) this.$set(this, `form`, e);
+      this.drawer = true;
+      this.formIsNew = false;
+    },
     //
     async searchTemplate() {
       let res = await this.trainTemplate();
@@ -245,13 +372,36 @@ export default {
         }
       }
     },
+    //其他事件(无关紧要)
+    //关闭抽屉函数
+    toClose() {
+      this.drawer = false;
+      this.formIsNew = true;
+      this.setHeight();
+    },
+    setHeight() {
+      let heights = this.$refs.card.$el.clientHeight * 0.63;
+      this.$set(this, `heights`, heights);
+    },
+    //设置事件颜色
     getColor(it, ib) {
       let { color, batchnum } = this.template;
       if (color.length > 0) {
-        let num = ((it - 1) * batchnum + ib) % color.length;
+        // let num = ((it - 1) * batchnum + ib) % color.length;
+        let num = (it - 1) % color.length;
         return color[num];
       } else return '#004499';
     },
+
+    checkDate(date) {
+      let year = JSON.parse(JSON.stringify(this.info.year));
+      let res = moment(date).isBetween(`${year}-01-01`, `${year}-12-31`, null, '[]');
+      return !res;
+    },
+    returns() {
+      if (this.view == 'plan') this.$router.push({ path: './index' });
+      else this.view = 'plan';
+    },
   },
   computed: {
     ...mapState(['user']),

+ 129 - 0
src/views/new-plan/parts/event.vue

@@ -0,0 +1,129 @@
+<template>
+  <div id="event">
+    <el-form :model="form" ref="form" :rules="formRules" label-width="80px" size="small" @submit.native.prevent style="padding: 15px;">
+      <el-form-item label="开始时间" prop="start" required>
+        <el-date-picker readonly v-model="form.start" type="date" format="yyyy-MM-dd" value-format="yyyy-MM-dd"> </el-date-picker>
+      </el-form-item>
+      <el-form-item label="结束时间" prop="end" required>
+        <el-date-picker readonly v-model="form.end" type="date" format="yyyy-MM-dd" value-format="yyyy-MM-dd"> </el-date-picker>
+      </el-form-item>
+      <el-form-item label="期数" prop="term" required> <el-input v-model="form.term"></el-input> </el-form-item>
+      <el-form-item label="班级类型" prop="type" required>
+        <el-radio-group v-model="form.type">
+          <el-radio label="0">正常班级</el-radio>
+          <el-radio label="1">特殊班级</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="批次" prop="batch" v-if="form.type === '0'"> <el-input v-model="form.batch"></el-input> </el-form-item>
+      <el-form-item label="班级数量" prop="class" v-if="form.type === '0'"> <el-input v-model="form.class"></el-input> </el-form-item>
+      <el-form-item label="每班人数" prop="number" required> <el-input v-model="form.number"></el-input> </el-form-item>
+      <el-form-item label="班级名称" prop="name" v-if="form.type === '1'"> <el-input v-model="form.name"></el-input> </el-form-item>
+      <el-form-item label="颜色" prop="color">
+        <el-color-picker v-model="form.color" :predefine="predefineColors" size="mini"></el-color-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-row type="flex" align="middle" justify="space-around">
+          <el-col :span="6">
+            <el-button type="primary" @click="saveForm">保存</el-button>
+          </el-col>
+          <el-col :span="6">
+            <el-button @click="resetForm">重置</el-button>
+          </el-col>
+          <el-col :span="6">
+            <el-button @click="toDelete" type="danger">删除</el-button>
+          </el-col>
+        </el-row>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+
+<script>
+import _ from 'lodash';
+export default {
+  name: 'event',
+  props: {
+    data: { type: Object, default: () => {} }, //数据
+    isNew: { type: Boolean, default: true }, //是不是修改
+    predefineColors: { type: Array, default: () => [] }, //颜色列表
+    year: { type: null, default: new Date().getFullYear() },
+    vacation: { type: Array, default: () => [] },
+  },
+  components: {},
+  data() {
+    return {
+      form: { color: '#409EFF' },
+      formRules: {
+        start: [{ required: true, message: '请选择开始时间', trigger: 'change' }],
+        end: [{ required: true, message: '请选择结束时间', trigger: 'change' }],
+        term: [{ required: true, message: '请输入期数' }],
+        number: [{ required: true, message: '请输入每班人数' }],
+        type: [{ required: true, message: '请选择班级类型' }],
+      },
+      pickerOptions: {
+        disabledDate: time => this.setDisabledDate(time),
+      },
+    };
+  },
+  created() {},
+  methods: {
+    //保存表单函数
+    saveForm() {
+      this.$refs['form'].validate(valid => {
+        if (valid) {
+          let data = JSON.parse(JSON.stringify(this.form));
+          this.resetForm();
+          this.$emit('save', { isNew: this.isNew, data });
+        } else {
+          console.warn('form validate error!!!');
+        }
+      });
+    },
+    //重置表单函数
+    resetForm() {
+      this.$refs.form.resetFields();
+    },
+    //删除
+    toDelete() {
+      this.$emit('delete', { index: this.form.index, data: { index: this.form.index } });
+    },
+    //禁用时间
+    setDisabledDate(time) {
+      let thisTime = time.getTime();
+      let start = new Date(`${this.year}-01-01`).getTime();
+      let end = new Date(`${this.year}-12-31`).getTime();
+      if (thisTime < start) return true;
+      else if (thisTime > end) return true;
+      else {
+        //循环假期列表,判断这个时间是不是在假期时间外:
+        // 此刻=假期开始时间||此刻=假期结束时间 return true(不能选)
+        // 此刻<假期开始时间 => return false(继续判断下个假期)
+        // 此刻>假期开始时间 => 此刻<假期结束时间 ? 在假期中,return true(不允许选择): return false(继续判断下个假期)
+        let res = false;
+        for (const vac of this.vacation) {
+          let vacS = new Date(vac.start).setDate(new Date(vac.start).getDate() - 1); //减一天匹配日历
+          let vacE = new Date(vac.end).setDate(new Date(vac.end).getDate() - 1);
+          if (thisTime > vacS) {
+            if (thisTime < vacE) {
+              res = true;
+              break;
+            }
+          }
+        }
+        return res;
+      }
+    },
+  },
+  watch: {
+    data: {
+      immediate: true,
+      deep: true,
+      handler(val) {
+        if (val) this.$set(this, `form`, _.cloneDeep(this.data));
+      },
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 231 - 0
src/views/new-plan/parts/school-arrange.vue

@@ -0,0 +1,231 @@
+<template>
+  <div id="school-arrange">
+    <el-row type="flex" align="middle" justify="end" style="padding-bottom:10px">
+      <el-col :span="2">
+        <el-button type="primary" size="mini" @click="toArrange">一键分配</el-button>
+      </el-col>
+      <el-col :span="2">
+        <el-button type="primary" size="mini" plain @click="dialog = true">查看汇总</el-button>
+      </el-col>
+    </el-row>
+
+    <!-- 大表 -->
+    <el-card>
+      <el-table :data="list" border stripe size="mini" height="700px">
+        <el-table-column label="学校" fixed align="center" prop="name" width="180">
+          <template v-slot="{ row }">
+            <el-row>
+              <el-col :span="24">
+                {{ row.name }}
+              </el-col>
+              <el-col :span="24" v-if="row.number"> 名额:{{ row.number }} </el-col>
+            </el-row>
+          </template>
+        </el-table-column>
+        <el-table-column align="center" v-for="(i, index) in termList" :key="index" :label="`第${i.term}期`">
+          <el-table-column align="center" width="150" :prop="`term${index + 1}`">
+            <template #header>
+              <el-row>
+                <el-col :span="24">{{ i.start }}</el-col>
+                <el-col :span="24">至</el-col>
+                <el-col :span="24">{{ i.end }}</el-col>
+              </el-row>
+            </template>
+          </el-table-column>
+        </el-table-column>
+      </el-table>
+    </el-card>
+
+    <!-- 数据汇总 -->
+    <el-dialog :visible.sync="dialog" title="数据汇总">
+      <el-card header="各期情况">
+        <el-table :data="totalList" border stripe size="mini">
+          <el-table-column prop="type"></el-table-column>
+          <el-table-column v-for="(i, index) in termList" align="center" :key="index" :label="`第${i.term}期`" :prop="`term${i.term}`"> </el-table-column>
+        </el-table>
+      </el-card>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import _ from 'lodash';
+var moment = require('moment');
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: school } = createNamespacedHelpers('school');
+const { mapActions: schPlan } = createNamespacedHelpers('schPlan');
+export default {
+  name: 'school-arrange',
+  props: {
+    events: { type: Array, default: () => [] },
+    year: { type: String, default: `${new Date().getFullYear()}` },
+    template: { type: Object, default: () => {} },
+  },
+  components: {},
+  data: () => {
+    return {
+      list: [],
+      termList: [],
+      totalList: [
+        {
+          type: '已分配',
+          term1: 1,
+          term2: 2,
+        },
+        {
+          type: '未分配',
+          term1: 1,
+          term2: 2,
+        },
+      ],
+      dialog: false,
+    };
+  },
+  async created() {
+    await this.getSchool();
+  },
+  methods: {
+    ...school(['query']),
+    ...schPlan({ schPlanQuery: 'query', createSchPlan: 'create', updateSchPlan: 'update' }),
+    async getSchool() {
+      const res = await this.query();
+      if (this.$checkRes(res)) {
+        let school = res.data.map(i => {
+          i = _.omit(i, ['meta', 'id', '_id', 'logourl']);
+          if (i.number) i.remaining = JSON.parse(JSON.stringify(i.number));
+          else i.remaining = 0;
+          return i;
+        });
+        this.$set(this, `list`, school);
+        this.getSchoolPlan();
+        this.getTotal();
+      }
+    },
+    toArrange() {
+      let school = this.list.filter(f => f.daterange);
+      //整理之后的学校列表
+      school = _.reverse(_.sortBy(school, ['level', 'hascar']));
+      //整理每个学校的daterange:[{start,end}]的形式
+      school = this.changeRange(school);
+      let termList = JSON.parse(JSON.stringify(this.termList));
+      for (const sch of school) {
+        for (const t of termList) {
+          if (t.remaining && t.remaining <= 0) continue;
+          let { result } = this.$tqInRange(t.start, t.end, sch.daterange);
+          //result为true:说明该期复合要求
+          if (result) {
+            if (sch.remaining > t.remaining) {
+              //学校名额>本期剩余名额:
+              //学校剩余名额 = 学校剩余名额(原) - 本期剩余名额
+              //学校在该期的名额数量 = 本期剩余名额
+              //本期剩余名额=0;
+              sch.remaining = sch.remaining - t.remaining;
+              sch[`term${t.term}`] = t.remaining;
+              t.remaining = 0;
+              continue;
+            } else if (sch.remaining <= t.remaining) {
+              //学校名额<=本期剩余名额:
+              //本期剩余名额 = 本期剩余名额(原) - 学校剩余名额;
+              //学校在该期的名额数量 = 学校剩余名额
+              //学校剩余名额 = 0
+              t.remaining = t.remaining - sch.remaining;
+              sch[`term${t.term}`] = sch.remaining;
+              sch.remaining = 0;
+              break;
+            }
+          }
+        }
+        let index = _.findIndex(this.list, f => f.code == sch.code);
+        if (index >= 0) this.$set(this.list, index, sch);
+      }
+      this.$set(this, `termList`, termList);
+      this.getTotal();
+    },
+    changeRange(data) {
+      data = data.map(i => {
+        let daterange = _.get(i, `daterange`, []); //['4','5','6']形式
+        i.daterange = daterange.map(mon => {
+          let start = moment()
+            .year(this.year)
+            .month(mon * 1 - 1)
+            .date('1')
+            .format('YYYY-MM-DD');
+          let end = moment()
+            .year(this.year)
+            .month(mon * 1)
+            .date('1')
+            .subtract(1, 'days')
+            .format('YYYY-MM-DD');
+          return { start, end };
+        });
+        return i;
+      });
+      return data;
+    },
+    async getSchoolPlan() {
+      const res = await this.schPlanQuery({ planid: this.id });
+      if (this.$checkRes(res)) {
+        this.list.map(i => {
+          let r = res.data.find(f => f.schid == i.code);
+          if (r) i.daterange = r.daterange;
+          return i;
+        });
+      }
+    },
+    getTermList() {
+      let arr = _.toPairs(_.groupBy(this.events, 'term'));
+      let res = arr.map(i => {
+        i = _.flatten(_.remove(i, r => _.isArray(r)));
+        let tpt = i.reduce((prev, next) => {
+          let num = next.number ? next.number * 1 : next.class * _.get(this.template, 'stunum', 0);
+          return prev + num;
+        }, 0);
+        let { start, term } = _.head(i);
+        let { end } = _.last(i);
+        return { start, end, term, tpt, remaining: tpt }; //tpt:该期总人数 ,remaining:剩余人数
+      });
+      this.$set(this, `termList`, res);
+    },
+    getTotal() {
+      let res = this.termList.map((i, index) => {
+        i.total = this.list.reduce((prev, next) => prev + (next[`term${i.term}`] * 1 || 0), 0);
+        return i;
+      });
+      let aObject = { type: '已分配' };
+      let rObject = { type: '未分配' };
+      res.map(i => {
+        aObject[`term${i.term}`] = i.total || 0;
+        rObject[`term${i.term}`] = i.remaining || 0;
+      });
+      this.$set(this, `totalList`, [aObject, rObject]);
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  watch: {
+    events: {
+      handler(val) {
+        if (val.length > 0) this.getTermList();
+      },
+      deep: true,
+      immediate: true,
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.el-table {
+  overflow: visible !important;
+}
+</style>

+ 7 - 1
src/views/new-plan/template.vue

@@ -7,7 +7,7 @@
             <el-row type="flex" align="middle">
               <el-col :span="1">
                 <el-color-picker v-model="color" :predefine="info.color" @change="toChange" color-format="hex"></el-color-picker>
-                <el-button type="primary" @click="toClear" size="mini">重置默认颜色</el-button>
+                <!-- <el-button type="primary" @click="toClear" size="mini">重置默认颜色</el-button> -->
               </el-col>
             </el-row>
           </template>
@@ -37,6 +37,7 @@ export default {
         { label: '每批所需天数', required: true, model: 'day', type: 'number' },
         { label: '默认每期中的批次数', required: true, model: 'batchnum', type: 'number' },
         { label: '默认每批次中的班级数', required: true, model: 'classnum', type: 'number' },
+        { label: '默认每班中的人数', required: true, model: 'stunum', type: 'number' },
         { label: '默认颜色', model: 'color', custom: true },
       ],
       rules: {
@@ -44,6 +45,7 @@ export default {
         day: [{ required: true, message: '请输入每批所需天数' }],
         batchnum: [{ required: true, message: '请输入默认每期中的批次数' }],
         classnum: [{ required: true, message: '请输入默认每批次中的班级数' }],
+        stunum: [{ required: true, message: '请输入默认每班中的人数' }],
       },
     };
   },
@@ -71,6 +73,10 @@ export default {
       this.$checkRes(res, '保存成功', res.errmsg || '保存失败');
     },
     toChange(data) {
+      if (!data) {
+        this.toClear();
+        return;
+      }
       let colors = _.get(this.info, 'color');
       if (colors && colors.length >= 8) {
         this.$message.error('只能选择8个预存颜色');

+ 6 - 0
src/views/school/detail.vue

@@ -3,6 +3,10 @@
     <detail-frame :title="pageTitle" returns="./index">
       <data-form :data="info" :fields="fields" :rules="rules" @save="handleSave" :isNew="isNew">
         <template #radios="{item}">
+          <template v-if="item.model === 'level'">
+            <el-radio label="本科">本科</el-radio>
+            <el-radio label="专科">专科</el-radio>
+          </template>
           <template v-if="item.model === 'hascar'">
             <el-radio label="0">否</el-radio>
             <el-radio label="1">是</el-radio>
@@ -31,6 +35,7 @@ export default {
         { label: '学校地点', required: true, model: 'address' },
         { label: '学校简称', required: true, model: 'shortname' },
         { label: '每期人数', required: true, model: 'number', type: 'number' },
+        { label: '高校层次', required: true, model: 'level', type: 'radio' },
         { label: '是否派车', required: true, model: 'hascar', type: 'radio' },
       ],
       rules: {
@@ -39,6 +44,7 @@ export default {
         address: [{ required: true, message: '请选择学校地点' }],
         shortname: [{ required: true, message: '请输入学校简称' }],
         number: [{ required: true, message: '请输入每期人数' }],
+        level: [{ required: true, message: '请选择高校层次' }],
         hascar: [{ required: true, message: '请选择是否派车' }],
       },
     };