lrf402788946 4 years ago
parent
commit
b5bf072fcc
2 changed files with 348 additions and 157 deletions
  1. 174 118
      src/views/new-plan/arrange/arrange.vue
  2. 174 39
      src/views/new-plan/arrange/arrange/table.vue

+ 174 - 118
src/views/new-plan/arrange/arrange.vue

@@ -12,7 +12,12 @@
             :vacation="vacation"
             :events="events"
           ></calendar> -->
-          <table-cal :vacation="vacation"></table-cal>
+          <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>
         </el-card>
       </el-col>
     </el-row>
@@ -27,27 +32,67 @@
         @delete="toDelete"
       ></event>
     </el-drawer>
-    <el-dialog :visible.sync="dialog" title="模板计划" width="30%" :close-on-click-modal="false">
+    <el-dialog :visible.sync="dialog" title="模板计划" width="40%" :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-tooltip content="第X期 此处为填写X" placement="right">
-            <el-input-number v-model="input.termnum"></el-input-number>
-          </el-tooltip>
-        </el-form-item>
-        <el-form-item label="请选择开始日期">
-          <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-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-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>
+                </el-col>
+              </el-row> -->
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="请输入开始的期数">
+              <el-tooltip content="第X期 此处为填写X" placement="right">
+                <el-input-number v-model="input.termnum"></el-input-number>
+              </el-tooltip>
+            </el-form-item>
+            <el-form-item label="请选择开始日期">
+              <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-item label="请选择结束日期">
+              <el-date-picker
+                :picker-options="pickerOptions"
+                v-model="input.end"
+                type="date"
+                placeholder="请选择结束日期"
+                format="yyyy-MM-dd"
+                value-format="yyyy-MM-dd"
+              >
+              </el-date-picker>
+            </el-form-item>
+          </el-col>
+        </el-row>
       </el-form>
       <template #footer>
         <el-row :gutter="20" type="flex" justify="center" align="middle">
@@ -95,8 +140,79 @@ export default {
         year: '2020',
       },
       form: {},
-      selectList: [],
-      events: [],
+      events: [
+        {
+          term: 1,
+          batch: 1,
+          startdate: '2020-07-01',
+          enddate: '2020-07-06',
+          color: 'purple',
+          //class的信息
+          name: 1,
+          number: 56,
+          type: 0,
+        },
+        {
+          term: 1,
+          batch: 1,
+          startdate: '2020-07-01',
+          enddate: '2020-07-06',
+          color: 'purple',
+          name: 2,
+          number: 56,
+          type: 0,
+        },
+        {
+          term: 1,
+          batch: 2,
+          startdate: '2020-07-01',
+          enddate: '2020-07-06',
+          color: 'purple',
+          name: 1,
+          number: 56,
+          type: 0,
+        },
+        {
+          term: 1,
+          batch: 2,
+          startdate: '2020-07-01',
+          enddate: '2020-07-06',
+          color: 'purple',
+          name: 2,
+          number: 56,
+          type: 0,
+        },
+        {
+          term: 1,
+          batch: 3,
+          startdate: '2020-07-01',
+          enddate: '2020-07-06',
+          color: 'purple',
+          name: 1,
+          number: 56,
+          type: 0,
+        },
+        {
+          term: 1,
+          batch: 3,
+          startdate: '2020-07-01',
+          enddate: '2020-07-06',
+          color: 'purple',
+          name: 2,
+          number: 56,
+          type: 0,
+        },
+        {
+          term: 1,
+          batch: 3,
+          startdate: '2020-07-01',
+          enddate: '2020-07-06',
+          color: 'purple',
+          name: 3,
+          number: 56,
+          type: 0,
+        },
+      ],
       vacation: undefined,
       dialog: false,
       selfBtn: {
@@ -111,9 +227,7 @@ export default {
           position: 'right',
         },
       },
-      input: {
-        term: 0,
-      },
+      input: {},
       pickerOptions: {
         disabledDate: time => that.checkDate(time),
       },
@@ -121,11 +235,10 @@ export default {
       collapse: '',
       drawer: false,
       formIsNew: true,
+      options: {},
     };
   },
-  created() {
-    this.search();
-  },
+  created() {},
   methods: {
     ...mapActions(['fetch', 'update']),
     ...trainTemplate({ trainTemplate: 'query' }),
@@ -171,8 +284,7 @@ export default {
           i.index = index;
           return i;
         });
-        this.$set(this, `events`, events);
-        this.$set(this, `selectList`, events);
+        // this.$set(this, `events`, events);
       }
       this.searchTemplate();
     },
@@ -180,82 +292,17 @@ export default {
     //生成默认模板
     setDefaultPlan() {
       this.$set(this, `events`, []);
-      this.$set(this, `selectList`, []);
       this.dialog = false;
-      let { term, start, termnum } = this.input;
-      let { day, batchnum, classnum } = this.template;
+      let { start, end, termnum } = this.input;
+      let { day, batchnum, total } = this.template;
       let event = []; //处理成功事件的存储
-      //第一次正常安排
-      //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;
-      });
-      //整理期数为输入的期数,将班级
-      event = this.nameTerm(event, termnum);
-      this.$set(this, `events`, event);
-      this.$set(this, `selectList`, event);
+      this.toArrange(start, end, termnum);
     },
-    //默认安排事件
-    arrange(t, start, part) {
-      let qt = 0;
-      let qb = 0;
-      let { day, batchnum, classnum, stunum } = 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',
-              number: stunum,
-              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;
-      }
+    //安排
+    toArrange(start, end, termnum) {
+      let events = [];
+      let { day, batchnum, total, term } = this.template;
+      // for (let i = 0; i < term; i++) {}
     },
     //默认事件排序
     sortOtherData(last, data) {
@@ -290,7 +337,6 @@ export default {
         data = { ...data, title: name };
       }
       this.$set(this.events, data.index, data);
-      this.$set(this.selectList, data.index, data);
       this.toClose();
     },
 
@@ -307,13 +353,12 @@ export default {
         `events`,
         this.events.filter(f => f.index !== data.index)
       );
-      this.selectList.splice(index, 1);
       this.toClose();
     },
     //计划保存
     savePlan() {
       let data = JSON.parse(JSON.stringify(this.info));
-      let plan = JSON.parse(JSON.stringify(this.selectList));
+      let plan = JSON.parse(JSON.stringify(this.events));
       let termnum = [];
       termnum = _.uniqBy(
         plan.map(item => {
@@ -377,7 +422,14 @@ export default {
       let res = await this.modelFetch({ model: 'trainmodel', planyearid, planid });
       if (this.$checkRes(res)) {
         if (res.data !== null) {
-          this.$set(this, `template`, res.data);
+          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;
+          let bn = _.get(batchnum, 'length', 0) - 1 >= 0 ? _.get(batchnum, 'length', 0) - 1 : 0;
+          template.leastDay = term * day + bn;
+          this.$set(this, `template`, template);
         }
       }
     },
@@ -407,15 +459,6 @@ export default {
       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 if (this.view == 'school') this.view = 'plan';
-    //   else this.view = 'school';
-    // },
-    // changeView() {
-    //   this.savePlan();
-    //   this.view = 'school';
-    // },
     async toSave(schPlan) {
       const res = await this.setSchPlan(schPlan);
       if (this.$checkRes(res)) {
@@ -426,10 +469,23 @@ export default {
       this.view = 'director';
     },
   },
+  filters: {
+    getBatchNum: template => _.get(template.batchnum, 'length', 0),
+  },
   watch: {
     defaultOption: {
       handler(val) {
-        this.search();
+        if (!_.get(this, 'options')) {
+          this.$set(this, `options`, _.cloneDeep(val));
+          this.search();
+        } else {
+          let nplanid = _.get(val, 'planid');
+          let oplanid = _.get(this.options, 'planid');
+          if (nplanid && !_.isEqual(nplanid, oplanid)) {
+            this.$set(this, `options`, _.cloneDeep(val));
+            this.search();
+          }
+        }
       },
       deep: true,
     },

+ 174 - 39
src/views/new-plan/arrange/arrange/table.vue

@@ -2,12 +2,12 @@
   <div id="tableCal">
     <template v-if="already">
       <table border="1" class="table" style="zoom:0.8" v-for="month in 12" :key="month">
-        <template>
+        <template v-if="toDisplay(month)">
           <tr>
-            <th :rowspan="list[`${month}`].length + 1" class="mouthTitle" style="width:58px;">{{ getWord(month) }}月</th>
+            <th :rowspan="getRowNumber(month)" class="mouthTitle" style="width:58px;">{{ month | getWord }}月</th>
             <th class="th" v-for="(item, index) in makeCalendar(month)" :key="index">
               <p>{{ item }}</p>
-              <p>{{ getWeekDay(item) }}</p>
+              <p>{{ item | getWeekDay }}</p>
             </th>
             <th class="th"><p>备注</p></th>
             <th class="th"><p>备注</p></th>
@@ -24,8 +24,8 @@
               {{ getContent(date, month, di, ci) || '' }}
             </td>
             <template v-if="di == 0">
-              <td :rowspan="list[`${month}`].length + 1" :style="{ height: (list[`${month}`].length + 1) * 15 }"></td>
-              <td :rowspan="list[`${month}`].length + 1"></td>
+              <td :rowspan="getRowNumber(month)" :style="{ height: getRowNumber(month) * 15 }"></td>
+              <td :rowspan="getRowNumber(month)"></td>
             </template>
           </tr>
         </template>
@@ -50,20 +50,20 @@ export default {
   name: 'tableCal',
   props: {
     year: { type: Number, default: new Date().getFullYear() },
+    events: { type: Array },
     vacation: { type: Array },
   },
   components: {},
   data: function() {
     return {
-      value: '2020-07-20',
       list: {},
       has_it: false,
       it: {},
-      already: true,
+      already: false,
     };
   },
   created() {
-    this.init();
+    // this.init();
   },
   methods: {
     makeCalendar(month = 1) {
@@ -86,26 +86,22 @@ export default {
       }
       return dlist;
     },
-    getWeekDay(datestr) {
-      let weekday = moment(datestr).weekday();
-      if (weekday || weekday == 0) {
-        let arr = ['一', '二', '三', '四', '五', '六', '日'];
-        return `星期${arr[weekday]}`;
-      }
-      return '';
-    },
     cellClick(date, month, di, ci) {
       console.log(date, month, di, ci);
     },
-    getWord(month) {
-      let arr = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'];
-      return arr[month - 1];
-    },
     init() {
       let list = {};
-      let arr = [{}, {}, {}, {}, {}, {}, {}, {}];
-      for (let index = 1; index <= 12; index++) {
-        list[index] = arr;
+      for (let month = 1; month <= 12; month++) {
+        if (_.isArray(this.events) && this.events.length > 0) {
+          let r = this.events.filter(f => {
+            let sm = moment(f.startdate).month() + 1;
+            let em = moment(f.enddate).month() + 1;
+            let res = _.inRange(month, sm, em + 1);
+            return res;
+          });
+          r.push({});
+          list[month] = r;
+        } else list[month] = [{}];
       }
       this.$set(this, `list`, list);
     },
@@ -116,13 +112,21 @@ export default {
         style['pointer-events'] = 'none';
         return style;
       }
+      //查看当天是否在假期中
       let res = this.checkVacation(date);
       if (res) {
         style = { cursor: 'not-allowed' };
         style['pointer-events'] = 'none';
         if (date != '') style['background'] = 'red';
+        return style;
+      }
+      //查看时间是否在事件中
+      res = this.checkEvents(date);
+      if (res) {
+        let { color } = res;
+        style = { background: color };
+        return style;
       }
-      return style;
     },
     toRowspan(date, month, di, ci) {
       let res = this.checkVacation(date);
@@ -145,7 +149,7 @@ export default {
         let r = this.pure(date, ir);
         result = r;
       } else {
-        this.crossPro(date, ir);
+        result = this.crossPro(date, ir);
       }
       return result;
     },
@@ -156,13 +160,11 @@ export default {
       let { start, end } = vac;
       //先判断是否跨月
       let omr = this.outMonth(start, end);
-      if (omr) {
-        //跨月了
-        result = this.outLotsMonth(date, start, end, omr);
-      } else {
-        //没跨越
-        result = this.notOutMonthPro(date, start, end);
-      }
+      //跨月了
+      if (omr) result = this.outLotsMonth(date, start, end, omr);
+      //没跨越
+      else result = this.notOutMonthPro(date, start, end);
+
       return result;
     },
     //查询假期是否有交集,返回有交集的假期
@@ -195,7 +197,11 @@ export default {
         let arr = f.split('/');
         return moment(date).isBetween(arr[0], arr[1], null, '[]');
       });
-      if (r) return io[r];
+      if (r) {
+        let res = io[r];
+        res = _.orderBy(res, ['start'], ['asc']);
+        return res;
+      }
     },
     // '.' 日期转换 '-' 日期
     pointToCross(date) {
@@ -219,7 +225,7 @@ export default {
       for (let i = 0; i <= omr; i++) {
         marr.push(sm + i);
       }
-      if (date == start && dm == sm) {
+      if (date == start) {
         //该天的月份在开始时间的月份中
         let sub = moment(start)
           .endOf('month')
@@ -241,6 +247,7 @@ export default {
       return result;
     },
     //无跨月处理
+    //date:当前日期;start:合并开始日期;end:合并结束日期
     notOutMonthPro(date, start, end) {
       let result = 0;
       if (date == start) {
@@ -249,14 +256,98 @@ export default {
       }
       return result;
     },
+    //假期重叠处理
     crossPro(date, ir) {
-      console.log(date);
-      console.log(ir);
+      let result = 0;
+      let head = _.head(ir);
+      let { start: hs, id } = head;
+      if (hs == date) {
+        let he = this.getNearPoint(hs, ir, id);
+        let omr = this.outMonth(hs, he);
+        //跨月了
+        if (omr) result = this.outLotsMonth(date, hs, he, omr);
+        //没跨越
+        else result = this.notOutMonthPro(date, hs, he);
+      } else {
+        //判断:当前时间是否是某段的开始时间
+        let sres = ir.find(f => f.start == date);
+        let eres = ir.find(f => f.end == date);
+        if (sres) {
+          //找到最近的止点
+          let he = this.getNearPoint(date, ir);
+          // console.log(he);
+          let omr = this.outMonth(date, he, sres.id);
+          //跨月了
+          if (omr) result = this.outLotsMonth(date, date, he, omr);
+          //没跨越
+          else result = this.notOutMonthPro(date, date, he);
+        } else {
+          //中间过程时间点,需要判断前一天是否是结束时间点
+          let yesterday = moment(date)
+            .subtract(1, 'days')
+            .format('YYYY-MM-DD');
+          let yres = ir.find(f => f.end == yesterday);
+          if (yres) {
+            let he = this.getNearPoint(date, ir);
+            let omr = this.outMonth(date, he);
+            //跨月了
+            if (omr > 0) result = this.outLotsMonth(date, date, he, omr);
+            //没跨越
+            else result = this.notOutMonthPro(date, date, he);
+          }
+        }
+      }
+      // console.log(result);
+      return result;
     },
+    //假期重叠:获取根据传来的日期获取最近的止点
+    getNearPoint(start, list, id) {
+      let result;
+      let arr = [];
+      //确定arr中 所有的日期都是在start之后的
+      arr = list.map(i => {
+        let obj = {};
+        if (moment(i.end).isAfter(start)) obj['end'] = i.end;
+        if (!id && moment(i.start).isAfter(start)) obj['start'] = i.start;
+        else if (id != i.id && moment(i.start).isAfter(start)) obj['start'] = i.start;
+        return obj;
+      });
+      let type, value;
+      for (const i of arr) {
+        let { start: si, end: ei } = i;
+        let sm;
+        if (si) sm = moment(si).diff(start);
+        let em;
+        if (ei) em = moment(ei).diff(start);
+        if (si || em) {
+          let { type: t, value: v } = this.getMin(sm, em, value);
+          if (t != 'value') {
+            type = t;
+            value = v;
+            result = i[type];
+          }
+        }
+      }
+      //开始减一天,因为result获取的是重叠中的时间点,然而开始时间点是属于下一段的合并td,不属于此段的,所以是start的时间点需要减一天
+      if (type == 'start') {
+        result = moment(result)
+          .subtract(1, 'days')
+          .format('YYYY-MM-DD');
+      }
+      return result;
+    },
+    //计算最小值返回 值和提示
+    getMin(sm, em, value) {
+      let obj = [{ type: 'value', value: value }];
+      if (sm) obj.push({ type: 'start', value: sm });
+      if (em) obj.push({ type: 'end', value: em });
+      let min = _.minBy(obj, i => i.value);
+      return min;
+    },
+    //查看日期是否在假日中
     checkVacation(date) {
       let res = false;
       if (!this.vacation) return res;
-      let style = { cursor: 'default' };
       for (const vac of this.vacation) {
         let start = vac.start;
         let end = _.get(vac, `end`, moment(start).format('YYYY-MM-DD'));
@@ -268,6 +359,21 @@ export default {
       }
       return res;
     },
+    //查看日期是否在事件中
+    checkEvents(date) {
+      let res;
+      if (!this.events) return res;
+      for (const e of this.events) {
+        let start = e.startdate;
+        let end = _.get(e, `enddate`, moment(start).format('YYYY-MM-DD'));
+        let r = moment(moment(`${this.year}-${date}`).format('YYYY-MM-DD')).isBetween(start, end, null, '[]');
+        if (r) {
+          res = e;
+          break;
+        }
+      }
+      return res;
+    },
     getContent(date, month, di, ci) {
       let res = this.vacation.filter(f => {
         let start = f.start;
@@ -280,8 +386,28 @@ export default {
       }
       return '';
     },
+    //以下是html获取参数方法
+    getRowNumber(month) {
+      let num = _.get(_.get(this.list, month, []), 'length', 0) + 1;
+      return num;
+    },
+
     toDisplay(month) {
-      return _.inRange(month, 0, 4);
+      return _.inRange(month, 7, 9);
+    },
+  },
+  filters: {
+    getWord(month) {
+      let arr = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'];
+      return arr[month - 1];
+    },
+    getWeekDay(datestr) {
+      let weekday = moment(datestr).weekday();
+      if (weekday || weekday == 0) {
+        let arr = ['一', '二', '三', '四', '五', '六', '日'];
+        return `星期${arr[weekday]}`;
+      }
+      return '';
     },
   },
   computed: {
@@ -299,8 +425,17 @@ export default {
     },
     vacation: {
       handler(val) {
-        if (val && this.year) this.already = true;
+        if (val && this.year && this.events) this.already = true;
+      },
+    },
+    events: {
+      handler(val) {
+        if (val) {
+          this.init();
+        }
       },
+      immediate: true,
+      deep: true,
     },
   },
   metaInfo() {