lrf402788946 5 年之前
父节点
当前提交
1ef287d150

+ 6 - 0
src/router/index.js

@@ -24,6 +24,12 @@ const newPlan = [
     meta: { title: '计划安排' },
     component: () => import('@/views/new-plan/arrange.vue'),
   },
+  {
+    path: '/newPlan/classes',
+    name: 'newPlan_classes',
+    meta: { title: '班级安排' },
+    component: () => import('@/views/new-plan/classes.vue'),
+  },
 ];
 
 const routes = [

+ 82 - 38
src/views/new-plan/arrange.vue

@@ -1,6 +1,10 @@
 <template>
   <div id="arrange">
     <detail-frame :title="pageTitle" :returns="returns">
+      <el-steps :active="view == 'plan' ? 1 : 2" align-center style="padding-bottom:10px">
+        <el-step title="安排培训计划"></el-step>
+        <el-step title="安排学校计划"></el-step>
+      </el-steps>
       <el-row :gutter="10" type="flex" v-if="view == 'plan'">
         <el-col :span="12">
           <el-card header="全年计划信息">
@@ -34,7 +38,7 @@
         </el-col>
       </el-row>
       <template v-else>
-        <sch-arr :events="events" :year="info.year" :template="template"></sch-arr>
+        <sch-arr :events="events" :year="info.year" :template="template" @toSave="toSave"></sch-arr>
       </template>
     </detail-frame>
     <el-drawer :visible.sync="drawer" direction="rtl" title="安排计划" @close="toClose">
@@ -90,6 +94,7 @@ import schArr from './parts/school-arrange';
 import { mapState, createNamespacedHelpers } from 'vuex';
 const { mapActions } = createNamespacedHelpers('trainplan');
 const { mapActions: trainTemplate } = createNamespacedHelpers('trainTemplate');
+const { mapActions: schPlan } = createNamespacedHelpers('schPlan');
 export default {
   name: 'arrange',
   props: {},
@@ -142,13 +147,13 @@ export default {
         },
         school: {
           text: '学校安排',
-          click: () => (that.view = 'school'),
+          click: () => that.changeView(),
           position: 'left',
         },
       },
       input: {
-        term: 55,
-        start: '2020-03-01',
+        term: 5,
+        start: '2020-01-01',
       },
       pickerOptions: {
         disabledDate: time => that.checkDate(time),
@@ -166,6 +171,7 @@ export default {
   methods: {
     ...mapActions(['fetch', 'update']),
     ...trainTemplate({ trainTemplate: 'query' }),
+    ...schPlan({ setSchPlan: 'schArrange' }),
     async search() {
       const res = await this.fetch(this.id);
       if (this.$checkRes(res)) {
@@ -183,6 +189,26 @@ export default {
         });
         this.$set(this, `vacation`, vac);
         this.$set(this, `info`, res.data);
+        let midArr = JSON.parse(JSON.stringify(res.data));
+        let events = [];
+        events = _.flatten(
+          midArr.termnum.map(item => {
+            item.batchnum.map((i, index) => {
+              i.termid = item._id;
+              i.term = item.term;
+              i.id = i._id;
+              i.start = JSON.parse(JSON.stringify(i.startdate));
+              i.end = JSON.parse(JSON.stringify(i.enddate));
+              i.title = JSON.parse(JSON.stringify(i.name));
+              delete i.startdate, delete i.enddate;
+              i.index = index;
+              return i;
+            });
+            return item.batchnum;
+          })
+        );
+        this.$set(this, `events`, events);
+        this.$set(this, `selectList`, events);
       }
     },
     //模板事件开始
@@ -212,7 +238,7 @@ export default {
     arrange(t, start, part) {
       let qt = 0;
       let qb = 0;
-      let { day, batchnum, classnum } = this.template;
+      let { day, batchnum, classnum, stunum } = this.template;
       if (!part) part = batchnum;
       let list = [];
       for (let it = 1; it <= t; it++) {
@@ -227,6 +253,7 @@ export default {
               start,
               end,
               type: '0',
+              number: stunum,
               title: `第${it - qt}期第${ib}批次`,
               color: this.getColor(it, ib),
             };
@@ -279,7 +306,6 @@ export default {
 
     //手动操作事件开始
     setEvent({ data, isNew }) {
-      console.log(data);
       data = JSON.parse(JSON.stringify(data));
       if (data.type == 0) {
         data.title = `第${data.term}期第${data.batch}批次`;
@@ -289,37 +315,6 @@ export default {
       }
       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();
     },
 
@@ -340,7 +335,46 @@ export default {
       this.toClose();
     },
     //计划保存
-    savePlan() {},
+    savePlan(is_return) {
+      let data = JSON.parse(JSON.stringify(this.info));
+      let plan = JSON.parse(JSON.stringify(this.selectList));
+      let termnum = [];
+      termnum = _.uniqBy(
+        plan.map(item => {
+          let obj = { term: item.term };
+          if (item.termid) obj._id = item.termid;
+          return obj;
+        }),
+        'term'
+      ).map(i => {
+        let object = _.cloneDeep(i);
+        object.batchnum = plan
+          .filter(fil => fil.term === i.term)
+          .map(b => {
+            b = _.pickBy(b, (val, key) => key !== 'term');
+            b.startdate = JSON.parse(JSON.stringify(b.start));
+            b.enddate = JSON.parse(JSON.stringify(b.end));
+            b.name ? b.name : (b.name = JSON.parse(JSON.stringify(b.title)));
+            delete b.start, delete b.end;
+            if (_.startsWith(b.id, 'eve') || _.startsWith(b.id, 'vac')) delete b.id;
+            return b;
+          });
+        object.classnum = object.batchnum.reduce((pre, cur) => {
+          if (cur.type === '0') return pre + parseInt(cur.class);
+          else return pre + 1;
+        }, 0);
+        return object;
+      });
+      data.termnum = termnum;
+      let res;
+      let msg;
+      res = this.update(data);
+      msg = `计划保存成功`;
+      if (this.$checkRes(res, msg)) {
+        if (is_return) this.$router.push({ path: './index' });
+        else this.search();
+      }
+    },
     //选择时间的事件
     selectDate(object) {
       let start = JSON.parse(JSON.stringify(object.startStr));
@@ -402,6 +436,16 @@ export default {
       if (this.view == 'plan') this.$router.push({ path: './index' });
       else this.view = 'plan';
     },
+    changeView() {
+      this.savePlan();
+      this.view = 'school';
+    },
+    async toSave(schPlan) {
+      const res = await this.setSchPlan(schPlan);
+      if (this.$checkRes(res)) {
+        this.savePlan();
+      }
+    },
   },
   computed: {
     ...mapState(['user']),

+ 212 - 0
src/views/new-plan/classes.vue

@@ -0,0 +1,212 @@
+<template>
+  <div id="plan">
+    <!-- 根据计划,获取所有期数及期数下批次,然后提供选择期数;查询出该期数下学校上报的学生,选择学生手动分班 -->
+    <list-frame :title="mainTitle" @query="stuSearch" :total="total" :filter="filterFields" :needAdd="false" returns="./index">
+      <template #options="{item}">
+        <template v-if="item.model === 'termid'">
+          <el-option v-for="(i, index) in termList" :key="index" :label="`第${i.term}期`" :value="i._id"></el-option>
+        </template>
+      </template>
+      <el-card>
+        <el-row type="flex" justify="space-around" :gutter="10" align="middle" style="padding:10px 0;">
+          <el-col :span="7">班级需求:{{ selectInfo.personReq }}人</el-col>
+          <el-col :span="7">已选择学生:{{ selected.length }}人</el-col>
+          <el-col :span="7">男性:{{ selectInfo.male }}人</el-col>
+          <el-col :span="7">女性:{{ selectInfo.female }}人</el-col>
+        </el-row>
+        <el-row>
+          <el-form :inline="true" size="mini">
+            <el-form-item label="批次">
+              <el-select v-model="selectInfo.batchid" placeholder="请先选择期数" @change="getClasses">
+                <el-option v-for="(i, index) in batchList" :key="index" :label="i.name" :value="i._id"></el-option>
+              </el-select>
+            </el-form-item>
+            <el-form-item label="班级">
+              <el-select v-model="selectInfo.classname" placeholder="请先选择批次">
+                <el-option v-for="(i, index) in classList" :key="index" :label="i.name" :value="i.name"></el-option>
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" @click="toSetClass">确认分班</el-button>
+            </el-form-item>
+          </el-form>
+        </el-row>
+      </el-card>
+      <data-table
+        ref="table"
+        :fields="fields"
+        :data="list"
+        :opera="opera"
+        :select="true"
+        :selected="selected"
+        @edit="toEdit"
+        @delete="toDelete"
+        @handleSelect="toSelect"
+      ></data-table>
+    </list-frame>
+  </div>
+</template>
+
+<script>
+import listFrame from '@frame/layout/admin/list-frame';
+import dataTable from '@frame/components/data-table';
+import _ from 'lodash';
+import { mapStatem, createNamespacedHelpers } from 'vuex';
+const { mapActions: trainPlan } = createNamespacedHelpers('trainplan');
+const { mapActions: schPlan } = createNamespacedHelpers('schPlan');
+const { mapActions: student } = createNamespacedHelpers('student');
+const { mapActions: classes } = createNamespacedHelpers('classes');
+const { mapActions: director } = createNamespacedHelpers('director');
+const { mapActions: dept } = createNamespacedHelpers('dept');
+export default {
+  metaInfo: { title: '安排班级' },
+  name: 'plan',
+  props: {},
+  components: { listFrame, dataTable },
+  data: () => ({
+    opera: [],
+    fields: [
+      { label: '学生姓名', prop: 'name' },
+      { label: '学校', prop: 'school_name' },
+      { label: '性别', prop: 'gender' },
+    ],
+    filterFields: [{ label: '期数', model: 'termid', type: 'select' }],
+    list: [],
+    selected: [],
+    selectedTest: [],
+    total: 0,
+    selectInfo: {
+      male: 0,
+      female: 0,
+      personReq: 0,
+    },
+    termList: [],
+    batchList: [],
+    classList: [],
+    directorList: [],
+    deptList: [],
+  }),
+  created() {
+    this.search();
+  },
+  methods: {
+    ...trainPlan(['fetch']),
+    ...schPlan({ schQuery: 'query' }),
+    ...student({ getStudentList: 'noClass' }), //noClass
+    ...classes({ getClassesList: 'query', createClass: 'divide' }),
+    ...director({ getDirectorList: 'query' }),
+    ...dept({ getDeptList: 'query' }),
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      const res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        let { termnum } = res.data;
+        this.$set(this, `termList`, termnum);
+      }
+    },
+    //查询选择期上报的学生,提供批次选择
+    async stuSearch({ skip = 0, limit = 10, ...info } = {}) {
+      let { termid } = info;
+      this.selectInfo.termid = termid;
+      const res = await this.getStudentList({ termid: termid, skip, limit });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+      }
+      if (skip !== 0) return;
+      this.getBatch(termid);
+    },
+    getBatch(termid) {
+      let batchs = this.termList.filter(f => f._id === termid);
+      if (batchs.length > 0) {
+        let { batchnum } = batchs[0];
+        this.$set(this, `batchList`, batchnum);
+      }
+    },
+    //根据批次id,查询下面的班级
+    async getClasses(data) {
+      //查询班级
+      if (!data) return;
+      const res = await this.getClassesList({ batchid: data });
+      // gc1 因为已经限制了分班人数,所以不允许出现班级人数不够的情况,查出来的班级就不应该生成,可以使用name过滤掉选项
+      let classList = [];
+      if (this.$checkRes(res)) {
+        if (res.data.length > 0) classList = res.data;
+      }
+      //整理班级数据,根据批次中的class数量,人数,创建班级
+      let batch = this.batchList.find(f => f._id === data);
+      let { name, class: classnum = 1, type, number } = batch;
+      this.selectInfo.type = type;
+      this.$set(this.selectInfo, `personReq`, number);
+      let arr = [];
+      for (let i = 1; i <= classnum; i++) {
+        let object = { name: `${name}${type === '0' ? `${i}班` : ''}` };
+        arr.push(object);
+      }
+      // gc1 过滤掉
+      arr = arr.filter(f => !classList.find(c => c.name == f.name));
+      this.$set(this, `classList`, arr);
+    },
+    toEdit({ data }) {
+      this.$router.push({ path: '/dept/detail', query: { id: data.id } });
+    },
+    async toDelete({ data }) {
+      const res = await this.delete(data.id);
+      this.$checkRes(res, '删除成功', '删除失败');
+      this.search();
+    },
+    toSelect(selecteds) {
+      this.$set(this, `selected`, selecteds);
+      let male = 0,
+        female = 0;
+      for (const i of selecteds) {
+        if (i.gender === '1' || i.gender === '男') male++;
+        else female++;
+      }
+      this.$set(this.selectInfo, `male`, male);
+      this.$set(this.selectInfo, `female`, female);
+    },
+    async toSetClass() {
+      // 整理数据生成班级;将学生列表重新查询=>为了将已经有班级的学生剔除,以便继续分班(重新查询)
+      let info = JSON.parse(JSON.stringify(_.omit(this.selectInfo, ['male', 'female', 'personReq'])));
+      let stuList = JSON.parse(JSON.stringify(this.selected));
+      if (this.isOutRange(stuList)) return;
+      info.students = stuList;
+      let res = await this.createClass(info);
+      if (this.$checkRes(res, '分班成功', '分班失败')) this.$router.push({ path: '/plan/index' });
+      //重置信息
+      // this.selectInfo = {
+      //   male: 0,
+      //   female: 0,
+      // };
+      // this.selected = [];
+      // this.$refs.table.selectReset();
+    },
+    isOutRange(selected) {
+      let res = true;
+      if (selected.length <= 0) this.$message.warning('请选择学生');
+      else if (_.inRange(selected.length, 1, this.selectInfo.personReq * 1)) this.$message.error('选择人数不足');
+      else if (selected.length > this.selectInfo.personReq * 1) this.$message('超出班级规定人数');
+      else res = false;
+      return res;
+    },
+  },
+  computed: {
+    mainTitle() {
+      let meta = this.$route.meta;
+      let main = meta.title || '';
+      let sub = meta.sub || '';
+      return `${main}${sub}`;
+    },
+    keyWord() {
+      let meta = this.$route.meta;
+      let main = meta.title || '';
+      return main;
+    },
+    id() {
+      return this.$route.query.id;
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 10 - 1
src/views/new-plan/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div id="index">
     <list-frame :title="pageTitle" @query="search" :total="total" :needFilter="false" @add="toAdd">
-      <data-table :fields="fields" :data="list" :opera="opera" @edit="toEdit" @delete="toDelete" @date="date"></data-table>
+      <data-table :fields="fields" :data="list" :opera="opera" @edit="toEdit" @delete="toDelete" @date="date" @classes="toClasses"></data-table>
     </list-frame>
     <el-dialog title="年度信息" width="30%" :visible.sync="dialog" center :destroy-on-close="true" @close="handleClose" :reset="false">
       <data-form :data="info" :fields="Ffields" :rules="rules" @save="handleSave" :isNew="!info.id" :styles="{ padding: 0 }" labelWidth="60px">
@@ -52,6 +52,12 @@ export default {
           icon: 'el-icon-date',
           method: 'date',
         },
+        {
+          label: '安排班级',
+          icon: 'el-icon-school',
+          display: i => i.status === '1',
+          method: 'classes',
+        },
         {
           label: '删除',
           icon: 'el-icon-delete',
@@ -170,6 +176,9 @@ export default {
     date({ data }) {
       this.$router.push({ path: './arrange', query: { id: data.id } });
     },
+    toClasses({ data }) {
+      this.$router.push({ path: './classes', query: { id: data.id } });
+    },
   },
   computed: {
     ...mapState(['user']),

+ 290 - 29
src/views/new-plan/parts/school-arrange.vue

@@ -1,6 +1,9 @@
 <template>
   <div id="school-arrange">
     <el-row type="flex" align="middle" justify="end" style="padding-bottom:10px">
+      <el-col :span="2">
+        <el-button type="success" size="mini" @click="toSave">保存计划</el-button>
+      </el-col>
       <el-col :span="2">
         <el-button type="primary" size="mini" @click="toArrange">一键分配</el-button>
       </el-col>
@@ -10,8 +13,18 @@
     </el-row>
 
     <!-- 大表 -->
-    <el-card>
-      <el-table :data="list" border stripe size="mini" height="700px" @cell-click="cellClick">
+    <el-card v-loading="!already" style="min-height:500px">
+      <el-table
+        :data="list"
+        border
+        stripe
+        size="mini"
+        height="650px"
+        @cell-click="cellClick"
+        :cell-style="cellStyle"
+        :cell-class-name="cellClass"
+        v-if="already"
+      >
         <el-table-column label="学校" fixed align="center" prop="name" width="180">
           <template v-slot="{ row }">
             <el-row>
@@ -23,7 +36,7 @@
           </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}`">
+          <el-table-column align="center" width="95" :prop="`term${index + 1}`">
             <template #header>
               <el-row>
                 <el-col :span="24">{{ i.start }}</el-col>
@@ -36,6 +49,62 @@
       </el-table>
     </el-card>
 
+    <el-drawer :visible.sync="drawer" direction="rtl" title="名额分配" @close="toClose">
+      <el-row type="flex" align="middle" justify="center" style="padding:20px" :gutter="20">
+        <el-col :span="12">
+          <el-card>
+            <el-form size="mini">
+              <el-form-item label="学校">{{ form | getProp('sch.name') }}</el-form-item>
+              <el-form-item label="学校层次">{{ form | getProp('sch.level') }}</el-form-item>
+              <el-form-item label="需要派车">{{ form | getProp('sch.hascar') }}</el-form-item>
+              <el-form-item label="总名额">{{ form | getProp('sch.number') }}</el-form-item>
+              <el-form-item label="剩余名额">{{ form | getProp('sch.remaining') }}</el-form-item>
+            </el-form>
+          </el-card>
+        </el-col>
+        <el-col :span="12">
+          <el-card>
+            <el-form size="mini">
+              <el-form-item label="期数">{{ form | getProp('term.term') }}</el-form-item>
+              <el-form-item label="开始时间">{{ form | getProp('term.start') }}</el-form-item>
+              <el-form-item label="结束时间">{{ form | getProp('term.end') }}</el-form-item>
+              <el-form-item label="总名额">{{ form | getProp('term.tpt') }}</el-form-item>
+              <el-form-item label="剩余名额">{{ form | getProp('term.remaining') }}</el-form-item>
+            </el-form>
+          </el-card>
+        </el-col>
+      </el-row>
+      <el-card style="padding:20px">
+        <el-row type="flex" align="middle" justify="center" :gutter="20">
+          <el-col :span="24">
+            <el-form size="mini" label-width="150px">
+              <el-form-item label="分配给该期的名额">
+                <el-input-number
+                  v-model="form.num"
+                  type="number"
+                  placeholder="请输入分配给该期的名额"
+                  :max="dGetMax(form)"
+                  :min="0"
+                  style="width:250px"
+                  @change="dComputed"
+                ></el-input-number>
+              </el-form-item>
+              <el-form-item>
+                <el-row type="flex" align="middle" justify="start" :gutter="20">
+                  <el-col :span="4">
+                    <el-button type="primary" @click="toSend">分配</el-button>
+                  </el-col>
+                  <el-col :span="4">
+                    <el-button @click="toClose">取消</el-button>
+                  </el-col>
+                </el-row>
+              </el-form-item>
+            </el-form>
+          </el-col>
+        </el-row>
+      </el-card>
+    </el-drawer>
+
     <!-- 数据汇总 -->
     <el-dialog :visible.sync="dialog" title="数据汇总">
       <el-collapse v-model="activeName" accordion>
@@ -90,7 +159,10 @@ export default {
       totalList: [],
       carList: [],
       dialog: false,
+      drawer: false,
+      form: {},
       activeName: '1',
+      already: false,
     };
   },
   async created() {
@@ -99,6 +171,7 @@ export default {
   methods: {
     ...school(['query']),
     ...schPlan({ schPlanQuery: 'query', createSchPlan: 'create', updateSchPlan: 'update' }),
+    //请求,处理学校列表
     async getSchool() {
       const res = await this.query();
       if (this.$checkRes(res)) {
@@ -109,11 +182,13 @@ export default {
           return i;
         });
         this.$set(this, `list`, school);
-        this.getSchoolPlan();
-        this.getTotal();
+        await this.getSchoolPlan();
+        await this.getTotal();
       }
     },
+    //自动安排
     toArrange() {
+      this.toReset();
       let school = this.list.filter(f => f.daterange);
       //整理之后的学校列表
       school = _.reverse(_.sortBy(school, ['level', 'hascar']));
@@ -133,6 +208,7 @@ export default {
               //本期剩余名额=0;
               sch.remaining = sch.remaining - t.remaining;
               sch[`term${t.term}`] = t.remaining;
+              sch[`id_term${t.term}`] = t.termid;
               t.remaining = 0;
               continue;
             } else if (sch.remaining <= t.remaining) {
@@ -142,6 +218,7 @@ export default {
               //学校剩余名额 = 0
               t.remaining = t.remaining - sch.remaining;
               sch[`term${t.term}`] = sch.remaining;
+              sch[`id_term${t.term}`] = t.termid;
               sch.remaining = 0;
               break;
             }
@@ -150,13 +227,74 @@ export default {
         let index = _.findIndex(this.list, f => f.code == sch.code);
         if (index >= 0) this.$set(this.list, index, sch);
       }
+      this.listClear();
       this.$set(this, `termList`, termList);
       this.getTotal();
       this.getCarTotal();
     },
+    //保存整体计划
+    toSave() {
+      //修改学校上报计划,整理数据
+      let schPlan = this.list.map(i => {
+        let plan = _.cloneDeep(i.plan);
+        let keys = Object.keys(i).filter(f => _.startsWith(f, 'term'));
+        for (const key of keys) {
+          let object = {};
+          object.termnum = key.match(/\d+(.\d+)?/g)[0];
+          object.number = i[`term${object.termnum}`];
+          object.termid = i[`id_term${object.termnum}`];
+          if (i.carTerm) {
+            let car = i.carTerm.find(f => f.term == object.termnum);
+            if (car) object.carnum = car.num;
+          }
+          plan.term.push(object);
+        }
+        if (plan) return plan;
+      });
+      schPlan = _.compact(schPlan);
+      schPlan = schPlan.map(i => {
+        i.term = this.checkTerm(i.term);
+        return i;
+      });
+      this.$emit('toSave', schPlan);
+    },
+    //手动更改
+    cellClick(row, column) {
+      //获取指定期
+      let term = this.termList.find(f => f.term == column.property.match(/\d+(.\d+)?/g)[0]);
+      //学校上报时间转换
+      row = this.changeRange(row);
+      let { result } = this.$tqInRange(term.start, term.end, row.daterange);
+      if (result) {
+        this.form.term = JSON.parse(JSON.stringify(term));
+        this.form.sch = JSON.parse(JSON.stringify(row));
+        this.$set(this.form, `num`, row[`term${term.term}`] * 1 || 0);
+        this.drawer = true;
+        //可以输入,整理显示数据
+      } else this.$message.error(`第 ${term.term} 期(${term.start} 至 ${term.end})不在 ${row.name} 上报的时间内!`);
+    },
+    toSend() {
+      let num = _.get(this.form, 'num');
+      let term = _.get(this.form, 'term');
+      let sch = _.get(this.form, 'sch');
+      let tn = term.term;
+      sch[`term${tn}`] = num;
+      sch[`id_term${tn}`] = term.termid;
+      // sch[`remaining`] = sch.remaining;
+      // term.remaining = term.remaining;
+      let si = _.findIndex(this.list, f => f.code == sch.code);
+      let ti = _.findIndex(this.termList, f => f.term == term.term);
+      this.$set(this.list, si, sch);
+      this.$set(this.termList, ti, term);
+      this.toClose();
+      this.getTotal();
+      this.getCarTotal();
+    },
+    //将学校上报的月份数组[String]=>[{start,end}]方法
     changeRange(data) {
       let c = r => {
         return r.map(mon => {
+          if (_.isObject(mon)) return mon;
           let start = moment()
             .year(this.year)
             .month(mon * 1 - 1)
@@ -171,52 +309,68 @@ export default {
           return { start, end };
         });
       };
-      if (_.isArray(data)) {
-        data = data.map(i => {
+      let duplicate = JSON.parse(JSON.stringify(data));
+      if (_.isArray(duplicate)) {
+        duplicate = duplicate.map(i => {
           let daterange = _.get(i, `daterange`, []); //['4','5','6']形式
           i.daterange = c(daterange);
           return i;
         });
-      } else if (_.isObject(data)) {
-        data.daterange = c(data.daterange);
+      } else if (_.isObject(duplicate)) {
+        duplicate.daterange = c(duplicate.daterange);
       }
 
-      return data;
-    },
-    //手动更改
-    cellClick(row, column) {
-      //获取指定期
-      let term = this.termList.find(f => f.term == column.property.match(/\d+(.\d+)?/g)[0]);
-      //学校上报时间转换
-      row = this.changeRange(row);
-      let { result } = this.$tqInRange(term.start, term.end, row.daterange);
-      console.log(result);
-      if (result) {
-        //可以输入,整理显示数据
-      } else this.$message.error('');
+      return duplicate;
     },
-
+    //学校匹配学校计划
     async getSchoolPlan() {
       const res = await this.schPlanQuery({ planid: this.id });
       if (this.$checkRes(res)) {
-        this.list.map(i => {
+        let nl = this.list.map(i => {
           let r = res.data.find(f => f.schid == i.code);
-          if (r) i.daterange = r.daterange;
+          if (r) {
+            i.daterange = r.daterange;
+            i = this.changeRange(i);
+            let term = _.get(r, `term`);
+            term = this.checkTerm(term);
+            if (term) {
+              i.carTerm = [];
+              for (const t of term) {
+                i[`term${t.termnum}`] = t.number;
+                i[`id_term${t.termnum}`] = t.termid;
+                i.carTerm.push({ term: t.termnum, num: t.carnum });
+              }
+              i.remaining = i.remaining - term.reduce((prev, next) => prev + (next.number * 1 || 0), 0);
+            }
+            i.plan = r;
+          }
           return i;
         });
+        this.$set(this, `list`, nl);
       }
+      this.$set(this, `already`, true);
     },
+    //检查已分配的数据是否与现在的期对应
+    checkTerm(term) {
+      let res = term.map(i => {
+        let r = this.termList.find(f => f.termid == i.termid);
+        if (r) return i;
+      });
+      res = _.compact(res);
+      return res;
+    },
+    //整理期(事件)列表
     getTermList() {
-      let arr = _.toPairs(_.groupBy(this.events, 'term'));
+      let arr = _.toPairs(_.groupBy(this.events, 'termid'));
       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);
+          let num = next.number ? next.number * 1 * next.class : next.class * _.get(this.template, 'stunum', 0);
           return prev + num;
         }, 0);
-        let { start, term } = _.head(i);
+        let { start, term, termid } = _.head(i);
         let { end } = _.last(i);
-        return { start, end, term, tpt, remaining: tpt }; //tpt:该期总人数 ,remaining:剩余人数
+        return { start, end, term, tpt, remaining: tpt, termid }; //tpt:该期总人数 ,remaining:剩余人数
       });
       this.$set(this, `termList`, res);
     },
@@ -230,6 +384,7 @@ export default {
       let rObject = { type: '未分配' };
       res.map(i => {
         aObject[`term${i.term}`] = i.total || 0;
+        i.remaining = i.tpt - i.total || 0;
         rObject[`term${i.term}`] = i.remaining || 0;
       });
       this.$set(this, `totalList`, [aObject, rObject]);
@@ -256,6 +411,7 @@ export default {
         return prev + (next.num || 0);
       }, 0);
     },
+    //所有车辆和计算
     getAllCarTotal() {
       return this.carList.reduce((prev, next) => {
         let num = next.carTerm.reduce((p, n) => p + (n.num || 0), 0);
@@ -278,6 +434,106 @@ export default {
 
       return res;
     },
+    //分配重置
+    async toReset() {
+      this.getTermList();
+      let list = this.list.map(i => {
+        let object = _.pick(i, ['address', 'code', 'daterange', 'hascar', 'level', 'name', 'shortname', 'number', 'plan']);
+        object.remaining = object.number;
+        return object;
+      });
+      this.$set(this, `list`, list);
+    },
+    //将分配为0的数据清除
+    listClear() {
+      let list = this.list.map(i => {
+        let keys = Object.keys(i).filter(f => _.startsWith(f, 'term'));
+        for (const key of keys) {
+          if (i[key] == 0) {
+            delete i[key];
+            delete i[`id_${key}`];
+          }
+        }
+        return i;
+      });
+      this.$set(this, `list`, list);
+    },
+    //抽屉名额响应式计算
+    dComputed(cv, ov) {
+      let sch = this.form.sch;
+      let term = this.form.term;
+      let keys = Object.keys(sch)
+        .filter(f => _.startsWith(f, 'term'))
+        .filter(f => f != `term${term.term}`);
+      let sr = keys.reduce((prev, next) => prev - sch[next], sch.number) - cv;
+      let tr = this.list.reduce((prev, next) => {
+        if (next.code != sch.code) return prev - (next[`term${term.term}`] * 1 || 0);
+        else return prev;
+      }, term.tpt);
+      tr = tr - cv;
+      this.$set(this.form.sch, `remaining`, sr);
+      this.$set(this.form.term, `remaining`, tr);
+    },
+    //计算抽屉最大值
+    dGetMax(data) {
+      if (!this.drawer) return 0;
+      let res = 0;
+      let t = this.termList.find(f => f.termid == this.form.term.termid);
+      let sch = this.list.find(f => f.code == this.form.sch.code);
+      let s = _.get(data, 'sch');
+      let tr = _.get(data, 'term.remaining', 0) * 1;
+      let sr = _.get(data, 'sch.remaining', 0) * 1;
+      let num = this.form.num;
+      if (s.remaining == 0) return num;
+      if (tr > sr) {
+        res = sch.number * 1 || 0;
+      } else if (tr == sr) {
+        let keys = Object.keys(s)
+          .filter(f => _.startsWith(f, 'term'))
+          .filter(f => f != `term${t.term}`);
+        let nsr = keys.reduce((prev, next) => prev - s[next], s.number);
+        res = nsr;
+      } else {
+        res = t.tpt * 1 - t.total * 1 || 0;
+      }
+      return res * 1;
+    },
+    //关闭抽屉
+    toClose() {
+      this.drawer = false;
+      this.form = {};
+    },
+    //单元格样式
+    cellStyle({ row, column, rowIndex, columnIndex }) {
+      let disabled = { background: '#F56C6C' }; //{ background: '#F56C6C' }  ' disabled'
+      if (column.property == 'name') return '';
+      if (!_.get(row, 'daterange')) return disabled;
+      let term = this.termList.find(f => f.term == column.property.match(/\d+(.\d+)?/g)[0]);
+      //学校上报时间转换
+      row = this.changeRange(row);
+      let { result } = this.$tqInRange(term.start, term.end, row.daterange);
+      if (!result) return disabled;
+      else return '';
+    },
+    cellClass({ row, column, rowIndex, columnIndex }) {
+      let disabled = ' disabled_point';
+      if (column.property == 'name') return '';
+      if (!_.get(row, 'daterange')) return disabled;
+      let term = this.termList.find(f => f.term == column.property.match(/\d+(.\d+)?/g)[0]);
+      //学校上报时间转换
+      row = this.changeRange(row);
+      let { result } = this.$tqInRange(term.start, term.end, row.daterange);
+      if (!result) return disabled;
+      else return '';
+    },
+  },
+  filters: {
+    getProp(data, prop) {
+      if (prop.includes('hascar')) {
+        let res = _.get(data, prop);
+        return res == '1' ? '需要' : '不需要';
+      } else return _.get(data, prop);
+    },
   },
   computed: {
     ...mapState(['user']),
@@ -308,3 +564,8 @@ export default {
   overflow: visible !important;
 }
 </style>
+<style>
+.disabled_point {
+  cursor: not-allowed;
+}
+</style>