|
@@ -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: {
|