lrf402788946 4 年之前
父節點
當前提交
9a7e3628e7
共有 3 個文件被更改,包括 324 次插入103 次删除
  1. 264 91
      src/views/new-plan/arrange/arrange.vue
  2. 17 3
      src/views/new-plan/arrange/arrange/table.vue
  3. 43 9
      src/views/new-plan/parts/event.vue

+ 264 - 91
src/views/new-plan/arrange/arrange.vue

@@ -1,23 +1,14 @@
 <template>
   <div id="arrange">
-    <!-- <detail-frame :title="pageTitle" :returns="returns"> -->
     <el-row type="flex" justify="center" v-if="view == 'plan'">
       <el-col :span="24" :style="`overflow:auto`">
         <el-card ref="card" v-if="info.year" height="800px">
-          <!-- <calendar
-            :year="`${info.year || '2020'}`"
-            :selfBtn="selfBtn"
-            @draft="selectDate"
-            @eventClick="eventClick"
-            :vacation="vacation"
-            :events="events"
-          ></calendar> -->
           <el-row type="flex" align="middle" style="padding:10px">
             <el-col :span="2">
               <el-button type="primary" size="mini" @click="dialog = true">生成模板计划</el-button>
             </el-col>
           </el-row>
-          <table-cal :events="events" :vacation="vacation"></table-cal>
+          <table-cal :events="events" :vacation="vacation" @cellClick="eventClick"></table-cal>
         </el-card>
       </el-col>
     </el-row>
@@ -37,30 +28,19 @@
         <el-row type="flex">
           <el-col :span="12">
             <el-form-item label="自动生成预估数据">
-              :
-              <ul style="margin-top:21px">
-                <li>至少 {{ template.term }} 期</li>
-                <li>至少需要 {{ template.leastDay }} 天 <span>(无假期等任何影响安排的因素)</span></li>
-                <li>每期有 {{ template | getBatchNum }} 批</li>
-                <li>每批需要 {{ template.day }} 天</li>
-                <li v-for="(b, index) in template.batchnum" :key="index">
-                  第{{ b.batch }}批:
-                  <ul>
-                    <li v-for="(c, cindex) in b.classnum" :key="cindex">{{ c.class }}班:{{ c.number }}人</li>
-                  </ul>
-                </li>
-              </ul>
-              <!-- <el-row>
-                <el-col :span="24"> 至少 {{ template.term }} 期  </el-col>
+              <el-row>
+                <el-col :span="24"> 至少 {{ template.term }} 期 </el-col>
                 <el-col :span="24">至少需要 {{ template.leastDay }} 天 <span>(无假期等任何影响安排的因素)</span></el-col>
                 <el-col :span="24">
                   <span>每期有 {{ template | getBatchNum }} 批</span>
                   <span>每批需要 {{ template.day }} 天</span>
                 </el-col>
                 <el-col :span="24" v-for="(b, index) in template.batchnum" :key="index">
-                  第{{ b.batch }}批:<span v-for="(c, cindex) in b.classnum" :key="cindex">{{ c.class }}班:{{ c.number }}人</span>
+                  第{{ b.batch }}批:<el-col style="padding-left:20px" :span="24" v-for="(c, cindex) in b.classnum" :key="cindex"
+                    >{{ c.class }}班:{{ c.number }}人</el-col
+                  >
                 </el-col>
-              </el-row> -->
+              </el-row>
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -126,7 +106,6 @@ export default {
   props: {},
   components: {
     // detailFrame,
-    // calendar,
     // dataTable,
     event,
     tableCal,
@@ -143,77 +122,130 @@ export default {
       events: [
         {
           term: 1,
-          classnum: 7,
           batchnum: [
             {
-              batch: 1,
-              startdate: '2020-06-29',
-              enddate: '2020-07-06',
-              color: 'purple',
+              startdate: '2020-04-07',
+              enddate: '2020-04-12',
+              batch: '1',
               class: [
-                { name: 1, number: 56, type: 0 },
-                { name: 2, number: 56, type: 0 },
+                { class: '1', number: '56' },
+                { class: '2', number: '56' },
               ],
+              color: '#E60000',
             },
             {
-              batch: 2,
-              startdate: '2020-07-02',
-              enddate: '2020-07-07',
-              color: 'purple',
+              startdate: '2020-04-08',
+              enddate: '2020-04-13',
+              batch: '2',
               class: [
-                { name: 1, number: 56, type: 0 },
-                { name: 2, number: 56, type: 0 },
+                { class: '1', number: '56' },
+                { class: '2', number: '56' },
               ],
+              color: '#E60000',
             },
             {
-              batch: 3,
-              startdate: '2020-07-03',
-              enddate: '2020-07-08',
-              color: 'purple',
+              startdate: '2020-04-09',
+              enddate: '2020-04-14',
+              batch: '3',
               class: [
-                { name: 1, number: 56, type: 0 },
-                { name: 2, number: 56, type: 0 },
-                { name: 3, number: 56, type: 0 },
+                { class: '1', number: '56' },
+                { class: '2', number: '56' },
+                { class: '3', number: '56' },
               ],
+              color: '#E60000',
             },
           ],
+          classnum: 7,
         },
         {
           term: 2,
+          batchnum: [
+            {
+              startdate: '2020-04-13',
+              enddate: '2020-04-18',
+              batch: '1',
+              class: [
+                { class: '1', number: '56' },
+                { class: '2', number: '56' },
+              ],
+              color: '#FF7300',
+            },
+            {
+              startdate: '2020-04-14',
+              enddate: '2020-04-19',
+              batch: '2',
+              class: [
+                { class: '1', number: '56' },
+                { class: '2', number: '56' },
+              ],
+              color: '#FF7300',
+            },
+            {
+              startdate: '2020-04-15',
+              enddate: '2020-04-20',
+              batch: '3',
+              class: [
+                { class: '1', number: '56' },
+                { class: '2', number: '56' },
+                { class: '3', number: '56' },
+              ],
+              color: '#FF7300',
+            },
+          ],
           classnum: 7,
+        },
+        {
+          term: 3,
           batchnum: [
             {
-              batch: 1,
-              startdate: '2020-07-07',
-              enddate: '2020-07-12',
-              color: 'blue',
+              startdate: '2020-04-19',
+              enddate: '2020-04-24',
+              batch: '1',
+              class: [
+                { class: '1', number: '56' },
+                { class: '2', number: '56' },
+              ],
+              color: '#996B1F',
+            },
+            {
+              startdate: '2020-04-20',
+              enddate: '2020-04-25',
+              batch: '2',
               class: [
-                { name: 1, number: 56, type: 0 },
-                { name: 2, number: 56, type: 0 },
+                { class: '1', number: '56' },
+                { class: '2', number: '56' },
               ],
+              color: '#996B1F',
             },
             {
-              batch: 2,
-              startdate: '2020-07-08',
-              enddate: '2020-07-13',
-              color: 'blue',
+              startdate: '2020-04-21',
+              enddate: '2020-04-26',
+              batch: '3',
               class: [
-                { name: 1, number: 56, type: 0 },
-                { name: 2, number: 56, type: 0 },
+                { class: '1', number: '56' },
+                { class: '2', number: '56' },
+                { class: '3', number: '56' },
               ],
+              color: '#996B1F',
             },
+          ],
+          classnum: 7,
+        },
+        {
+          term: 4,
+          batchnum: [
             {
-              batch: 3,
-              startdate: '2020-07-09',
-              enddate: '2020-07-14',
-              color: 'blue',
+              startdate: '2020-04-25',
+              enddate: '2020-04-30',
+              batch: '1',
               class: [
-                { name: 1, number: 56, type: 0 },
-                { name: 2, number: 56, type: 0 },
-                { name: 3, number: 56, type: 0 },
+                { class: '1', number: '56' },
+                { class: '2', number: '56' },
               ],
+              color: '#FFD700',
             },
           ],
+          classnum: 2,
         },
       ],
       vacation: undefined,
@@ -230,7 +262,11 @@ export default {
           position: 'right',
         },
       },
-      input: {},
+      input: {
+        termnum: 1,
+        start: '2020-04-01',
+        end: '2020-10-31',
+      },
       pickerOptions: {
         disabledDate: time => that.checkDate(time),
       },
@@ -293,19 +329,108 @@ export default {
     },
     //模板事件开始
     //生成默认模板
-    setDefaultPlan() {
-      this.$set(this, `events`, []);
+    async setDefaultPlan() {
+      // this.$set(this, `events`, []);
+      this.$message('正在自动生成计划,请稍后...');
       this.dialog = false;
+      let isOk = false;
       let { start, end, termnum } = this.input;
-      let { day, batchnum, total } = this.template;
+      let { batchnum, term, total } = this.template;
       let event = []; //处理成功事件的存储
-      this.toArrange(start, end, termnum);
+      let wtotal = 0,
+        wtermnum = 0;
+      let { total: newTotal, termnum: newTerm, events } = this.toArrange(start, end, termnum, term, total);
+      if (newTotal == 0) isOk = true;
+      else {
+        wtotal = newTotal;
+        wtermnum = newTerm;
+        event = events;
+      }
+      while (!isOk) {
+        let nt = this.computedTerm(batchnum, wtotal);
+        let res = this.toArrange(start, end, wtermnum, nt, wtotal, event);
+        if (res.total == 0) isOk = true;
+        else {
+          wtotal = res.total;
+          wtermnum = res.termnum;
+          event = events;
+        }
+      }
+      this.$set(this, `events`, event);
     },
     //安排
-    toArrange(start, end, termnum) {
-      let events = [];
-      let { day, batchnum, total, term } = this.template;
-      // for (let i = 0; i < term; i++) {}
+    // start:选择的开始时间
+    // end:选择打的结束时间
+    // termnum:手动输入开始的期数
+    // total:剩余人数
+    // events:已有安排,第一次不用传,再安排需要
+    toArrange(start, end, termnum, term, total, events = []) {
+      let { day, batchnum } = this.template;
+      for (let i = 0; i < term; i++) {
+        if (total == 0) break;
+        let bnum = [];
+        for (const b of batchnum) {
+          if (total == 0) break;
+          let startdate;
+          let enddate;
+          //先查看是否是这期的批次正在排
+          if (bnum.length > 0) {
+            let last = _.last(bnum);
+            startdate = this.dayPlus(last.startdate, 1);
+          } else if (events.length == 0) {
+            //是第一期处理
+            startdate = start;
+            //此处应该处理startdate,如果startdate在假期中,就应该把时间约过假期再做
+            let res = this.getDateNotInVac(startdate, this.dayPlus(startdate, day - 1), day - 1);
+            startdate = res.start;
+          } else {
+            //不是第一期处理
+            //找到最后一期
+            let lastTerm = _.last(events);
+            //找到对应的批次(其实就是第一批次,因为第二批次已经走了if)
+            let fb = _.head(lastTerm.batchnum);
+            startdate = this.dayPlus(fb.enddate, 1);
+            //此处应该处理startdate,如果startdate在假期中,就应该把时间约过假期再做
+            let res = this.getDateNotInVac(startdate, this.dayPlus(startdate, day - 1), day - 1);
+            startdate = res.start;
+          }
+          enddate = this.dayPlus(startdate, day - 1);
+          let r = this.isInVac(startdate, enddate, day - 1);
+          //判断在不在假期
+          if (r) break;
+          let isInRange = this.isInRange(startdate, enddate, start, end);
+          let classes = [];
+          //判断不在手选的时间范围内
+          if (!isInRange) break;
+          let bobj = { startdate, enddate, batch: b.batch };
+          for (const c of b.classnum) {
+            if (total * 1 - c.number * 1 >= 0) {
+              let nc = _.omit(_.cloneDeep(c), ['_id']);
+              total = total * 1 - c.number * 1;
+              classes.push(nc);
+            } else {
+              let nc = _.omit(_.cloneDeep(c), ['_id']);
+              nc.number = total;
+              total = 0;
+              classes.push(nc);
+              break;
+            }
+          }
+          bobj.class = classes;
+          bnum.push(bobj);
+        }
+        //最后处理成期的数据
+        if (bnum.length > 0) {
+          let color = this.getColor(termnum);
+          bnum = bnum.map(i => ({ ...i, color }));
+          let classnum = bnum.reduce((p, n) => p + n.class.length, 0);
+          let obj = { term: termnum, batchnum: bnum, classnum: classnum };
+          termnum = termnum * 1 + 1;
+          events.push(obj);
+        }
+      }
+      let obj = { total, termnum, events };
+      return obj;
     },
     //默认事件排序
     sortOtherData(last, data) {
@@ -407,16 +532,17 @@ export default {
       this.formIsNew = true;
     },
     //
-    eventClick({ event }) {
-      let obj = _.get(event, `extendedProps`);
-      if (!obj) {
-        console.warn(`无对应事件`);
-        return;
+    eventClick(event) {
+      if (event) this.formIsNew = false;
+      let res = this.events.find(f => f.term == event.term);
+      if (res) {
+        let { term } = res;
+        res = res.batchnum.find(f => f.batch == event.batch);
+        let obj = { ...res, term };
+        this.$set(this, `form`, obj);
       }
-      let e = this.events.find(f => f.index == obj.index);
-      if (e) this.$set(this, `form`, e);
       this.drawer = true;
-      this.formIsNew = false;
+      // this.formIsNew = false;
     },
     //
     async searchTemplate() {
@@ -427,15 +553,22 @@ export default {
         if (res.data !== null) {
           let template = _.cloneDeep(res.data);
           let { total, batchnum, day } = template;
-          let termTotal = batchnum.reduce((p, n) => p + n.classnum.reduce((np, nn) => np + nn.number * 1, 0), 0);
-          let term = Math.ceil(total / termTotal);
-          template.term = term;
+          template.term = this.computedTerm(batchnum, total);
           let bn = _.get(batchnum, 'length', 0) - 1 >= 0 ? _.get(batchnum, 'length', 0) - 1 : 0;
-          template.leastDay = term * day + bn;
+          template.leastDay = template.term * day + bn;
           this.$set(this, `template`, template);
         }
       }
     },
+    //人数计算无假期的剩余期
+    // batchnum:模板的批次设置
+    // total:剩余人数(可用来重复计算)
+    computedTerm(batchnum, total) {
+      let termTotal = batchnum.reduce((p, n) => p + n.classnum.reduce((np, nn) => np + nn.number * 1, 0), 0);
+      let term = 0;
+      if (termTotal !== 0) term = Math.ceil(total / termTotal);
+      return term;
+    },
     //其他事件(无关紧要)
     //关闭抽屉函数
     toClose() {
@@ -448,7 +581,7 @@ export default {
       this.$set(this, `heights`, heights);
     },
     //设置事件颜色
-    getColor(it, ib) {
+    getColor(it) {
       let { color, batchnum } = this.template;
       if (color.length > 0) {
         // let num = ((it - 1) * batchnum + ib) % color.length;
@@ -468,8 +601,48 @@ export default {
         this.savePlan();
       }
     },
-    toDirector() {
-      this.view = 'director';
+    dayPlus(date, num) {
+      return moment(date)
+        .add(num, 'days')
+        .format('YYYY-MM-DD');
+    },
+    //若遇到假期,返回假期后的日期
+    getDateNotInVac(start, end, day) {
+      let res = false;
+      res = this.isInVac(start, end);
+      if (res) {
+        let ns = this.dayPlus(res.end, 1);
+        let ne = this.dayPlus(ns, day);
+        res = this.getDateNotInVac(ns, ne, day);
+      } else res = { start, end };
+
+      return res;
+    },
+    //如果在假期,就返回这个假期;不在假期,就
+    isInVac(start, end) {
+      let res = false;
+      for (const vac of this.vacation) {
+        let { start: vs, end: ve } = vac;
+        let sr = moment(start).isBetween(vs, ve, null, '[]');
+        let er = moment(end).isBetween(vs, ve, null, '[]');
+        let vsr = moment(vs).isBetween(start, end, null, '[]');
+        let ver = moment(ve).isBetween(start, end, null, '[]');
+        if (sr || er || vsr || ver) {
+          //返回这个假期
+          res = vac;
+          break;
+        }
+      }
+      return res;
+    },
+    //查看是否在要求的事件范围内
+    //start:当前开始时间;end:当前结束时间;rs:范围开始时间;re:范围结束时间
+    isInRange(start, end, rs, re) {
+      let sr = moment(start).isBetween(rs, re, null, '[]');
+      let er = moment(end).isBetween(rs, re, null, '[]');
+      let rsr = moment(rs).isBetween(start, end, null, '[]');
+      let rer = moment(re).isBetween(start, end, null, '[]');
+      return sr || er || rsr || rer;
     },
   },
   filters: {

+ 17 - 3
src/views/new-plan/arrange/arrange/table.vue

@@ -58,7 +58,7 @@ export default {
   components: {},
   data: function() {
     return {
-      list: { 7: [[], []], 8: [[]] },
+      list: {},
       has_it: false,
       it: {},
       already: false,
@@ -87,7 +87,8 @@ export default {
       return dlist;
     },
     cellClick(date, month, bi, ci) {
-      console.log(date, month, bi, ci);
+      let res = this.checkEvents(date, month, bi);
+      this.$emit('cellClick', res);
     },
     init() {
       let list = {};
@@ -504,6 +505,17 @@ export default {
     toDisplay(month) {
       return _.inRange(month, 1, 13);
     },
+    //没有事件的初始化
+    initNoEventTable() {
+      let obj = {};
+      for (let i = 1; i <= 12; i++) {
+        obj[i] = [];
+        for (let ind = 0; ind < 8; ind++) {
+          obj[i].push([]);
+        }
+      }
+      this.$set(this, `list`, obj);
+    },
   },
   filters: {
     getWord(month) {
@@ -539,8 +551,10 @@ export default {
     },
     events: {
       handler(val) {
-        if (val) {
+        if (val && val.length > 0) {
           this.init();
+        } else {
+          // this.initNoEventTable();
         }
       },
       immediate: true,

+ 43 - 9
src/views/new-plan/parts/event.vue

@@ -2,22 +2,46 @@
   <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-date-picker :readonly="!isNew" v-model="form.startdate" 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-date-picker :readonly="!isNew" v-model="form.enddate" 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-form-item label="期数" prop="term" required> <el-input v-model="form.term" :readonly="!isNew"></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="batch" v-if="form.type === '0'"> <el-input v-model="form.batch" :readonly="!isNew"></el-input> </el-form-item>
+      <el-form-item label="班级">
+        <el-row>
+          <el-col :span="24">
+            <el-button type="primary" icon="el-icon-plus" @click="addClass()">添加班级</el-button>
+          </el-col>
+          <el-table size="mini" :data="form.class">
+            <el-table-column align="center" label="班级">
+              <template v-slot="{ row }">
+                <el-input v-model="row.class"></el-input>
+              </template>
+            </el-table-column>
+            <el-table-column align="center" label="人数">
+              <template v-slot="{ row }">
+                <el-input v-model="row.number" type="number"></el-input>
+              </template>
+            </el-table-column>
+            <el-table-column align="center" label="操作">
+              <template v-slot="{ row, $index }">
+                <el-button type="text" icon="el-icon-delete" @click="toDeleteClass($index)"></el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-row>
+      </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="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>
@@ -54,8 +78,8 @@ export default {
     return {
       form: { color: '#409EFF' },
       formRules: {
-        start: [{ required: true, message: '请选择开始时间', trigger: 'change' }],
-        end: [{ required: true, message: '请选择结束时间', trigger: 'change' }],
+        startdate: [{ required: true, message: '请选择开始时间', trigger: 'change' }],
+        enddate: [{ required: true, message: '请选择结束时间', trigger: 'change' }],
         term: [{ required: true, message: '请输入期数' }],
         number: [{ required: true, message: '请输入每班人数' }],
         type: [{ required: true, message: '请选择班级类型' }],
@@ -84,6 +108,16 @@ export default {
     resetForm() {
       this.$refs.form.resetFields();
     },
+    addClass() {
+      this.form.class.push({});
+    },
+    //删除班级
+    toDeleteClass(index) {
+      let duplicate = _.cloneDeep(this.form.class);
+      //删除指定行
+      duplicate.splice(index, 1);
+      this.$set(this.form, `class`, duplicate);
+    },
     //删除
     toDelete() {
       this.$emit('delete', { index: this.form.index, data: this.form });