classroom-setting-item.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. <template>
  2. <div>
  3. <!-- <el-form-item
  4. label="跳过节假日"
  5. :prop="'classs.' + type + '.holiday'"
  6. :rules="[{ required: true, message: '否跳过节假日' }]"
  7. >
  8. <el-radio-group v-model="form.holiday">
  9. <el-radio :label="true">是</el-radio>
  10. <el-radio :label="false">否</el-radio>
  11. </el-radio-group>
  12. </el-form-item> -->
  13. <el-table v-if="form && form.cycle&&form.cycle.length>0" :data="form.cycle" :show-header="false">
  14. <el-table-column>
  15. <template slot-scope="scope">
  16. <div>
  17. <el-form-item
  18. :prop="
  19. 'classs.' + type + '.cycle.' + scope.$index + '.coreTeacher'
  20. "
  21. label-width="88px"
  22. :rules="[{ required: true, message: '请选择主教老师' }]"
  23. >
  24. <el-select
  25. v-model.trim="scope.row.coreTeacher"
  26. placeholder="请选择主教老师"
  27. clearable
  28. filterable
  29. >
  30. <el-option
  31. v-for="(item, index) in teacherList"
  32. :key="index"
  33. :label="item.realName"
  34. :value="String(item.id)"
  35. >
  36. <span style="float: left">{{ item.realName }}</span>
  37. <span style="float: right; color: #8492a6; font-size: 13px">{{
  38. String(item.id)
  39. }}</span>
  40. </el-option>
  41. </el-select>
  42. </el-form-item>
  43. <el-form-item
  44. prop="assistant"
  45. v-if="
  46. activeType != 'HIGH' &&
  47. activeType != 'HIGH_ONLINE' &&
  48. activeType != 'MUSIC_NETWORK' &&
  49. type != 'HIGH' &&
  50. type != 'HIGH_ONLINE' &&
  51. type != 'MUSIC_NETWORK'
  52. "
  53. >
  54. <el-select
  55. v-model.trim="scope.row.assistant"
  56. placeholder="请选择助教老师"
  57. filterable
  58. clearable
  59. multiple
  60. collapse-tags
  61. >
  62. <el-option
  63. v-for="(item, index) in cooperationList"
  64. :key="index"
  65. :label="item.realName"
  66. :value="item.id"
  67. >
  68. <span style="float: left">{{ item.realName }}</span>
  69. <span style="float: right; color: #8492a6; font-size: 13px">{{
  70. String(item.id)
  71. }}</span>
  72. </el-option>
  73. </el-select>
  74. </el-form-item>
  75. <el-form-item
  76. :prop="'classs.' + type + '.cycle.' + scope.$index + '.time'"
  77. :rules="[{ required: true, message: '请选择课程时长' }]"
  78. inline-message
  79. >
  80. <el-select
  81. v-model.trim="scope.row.time"
  82. style="width: 180px !important"
  83. placeholder="请选择课程时长"
  84. clearable
  85. :disabled="!!selectPrice"
  86. @change="
  87. (val) => {
  88. startTimeChange(scope, val);
  89. }
  90. "
  91. filterable
  92. >
  93. <el-option
  94. v-for="(item, index) in pricesArray"
  95. :key="index"
  96. :disabled="
  97. surplustime + (parseFloat(scope.row.time) || 0) < item
  98. "
  99. :label="item"
  100. :value="item"
  101. >
  102. </el-option>
  103. </el-select>
  104. </el-form-item>
  105. <el-form-item
  106. :prop="
  107. 'classs.' + type + '.cycle.' + scope.$index + '.expectCourseNum'
  108. "
  109. :rules="[
  110. { required: true, message: '请输入预计课时数' },
  111. { pattern: /^\+?[1-9]\d*$/, message: '请输入大于0的正整数' },
  112. { validator: validateNum },
  113. ]"
  114. inline-message
  115. >
  116. <el-input
  117. style="width: 180px !important"
  118. type="number"
  119. v-model.trim="scope.row.expectCourseNum"
  120. placeholder="请输入预计课数"
  121. @input="
  122. (val) => {
  123. getUseTime(scope.row);
  124. }
  125. "
  126. >
  127. </el-input>
  128. </el-form-item>
  129. <el-form-item
  130. inline-message
  131. :rules="[{ required: true, message: '请选择循环周期' }]"
  132. :prop="'classs.' + type + '.cycle.' + scope.$index + '.dayOfWeek'"
  133. >
  134. <el-select
  135. v-model.trim="scope.row.dayOfWeek"
  136. style="width: 180px !important"
  137. placeholder="请选择循环周期"
  138. clearable
  139. filterable
  140. @change="
  141. (val) => {
  142. getUseTime(scope.row);
  143. }
  144. "
  145. >
  146. <el-option
  147. v-for="(item, index) in weekDateList"
  148. :key="index"
  149. :label="item.label"
  150. :value="item.value"
  151. >
  152. </el-option>
  153. </el-select>
  154. </el-form-item>
  155. <el-form-item
  156. :prop="
  157. 'classs.' + type + '.cycle.' + scope.$index + '.startClassTime'
  158. "
  159. :rules="[{ required: true, message: '请选择开始时间' }]"
  160. inline-message
  161. >
  162. <el-time-picker
  163. style="width: 180px !important"
  164. v-model.trim="scope.row.startClassTime"
  165. format="HH:mm"
  166. value-format="HH:mm"
  167. placeholder="请选择开始时间"
  168. @change="timeChange(scope.row)"
  169. :picker-options="{
  170. selectableRange: ['04:30:00 - 23:59:59'],
  171. }"
  172. >
  173. </el-time-picker>
  174. </el-form-item>
  175. <el-form-item
  176. :prop="
  177. 'classs.' + type + '.cycle.' + scope.$index + '.endClassTime'
  178. "
  179. inline-message
  180. >
  181. <el-time-picker
  182. style="width: 180px !important"
  183. v-model.trim="scope.row.endClassTime"
  184. format="HH:mm"
  185. disabled
  186. value-format="HH:mm"
  187. placeholder="请选择结束时间"
  188. :picker-options="{
  189. selectableRange: [
  190. scope.row.startClassTime + ':00 - 23:59:59',
  191. ],
  192. }"
  193. >
  194. </el-time-picker>
  195. </el-form-item>
  196. <el-form-item
  197. :prop="'classs.' + type + '.cycle.' + scope.$index + '.holiday'"
  198. :rules="[{ required: true, message: '请选择是否跳过节假日' }]"
  199. inline-message
  200. >
  201. <el-select
  202. v-model.trim="scope.row.holiday"
  203. style="width: 180px !important"
  204. placeholder="是否跳过节假日"
  205. filterable
  206. @change="holidayChange(scope.row)"
  207. >
  208. <el-option label="是" :value="true"></el-option>
  209. <el-option label="否" :value="false"> </el-option>
  210. </el-select>
  211. </el-form-item>
  212. <el-form-item
  213. inline-message
  214. :prop="'classs.' + type + '.cycle.' + scope.$index + '.startDate'"
  215. :rules="[{ required: true, message: '请选择排课起始日期' }]"
  216. >
  217. <el-date-picker
  218. v-model.trim="scope.row.startDate"
  219. :picker-options="pickerOptions"
  220. style="width: 180px !important"
  221. type="date"
  222. value-format="yyyy-MM-dd"
  223. placeholder="排课起始日期"
  224. @change="
  225. (val) => {
  226. changeStartDate(val, scope.row);
  227. }
  228. "
  229. >
  230. </el-date-picker>
  231. </el-form-item>
  232. <el-form-item
  233. inline-message
  234. :prop="'classs.' + type + '.cycle.' + scope.$index + '.endDate'"
  235. :rules="[
  236. { required: true, message: '请选择排课结束日期' },
  237. { required: true, trigger: 'change', validator: validatePass },
  238. ]"
  239. >
  240. <el-date-picker
  241. v-model.trim="scope.row.endDate"
  242. :disabled="true"
  243. :picker-options="pickerOptions"
  244. style="width: 180px !important"
  245. type="date"
  246. value-format="yyyy-MM-dd"
  247. placeholder="排课结束日期"
  248. >
  249. </el-date-picker>
  250. </el-form-item>
  251. <i
  252. @click="remove(scope.$index, scope)"
  253. v-if="form.cycle.length > 1"
  254. class="close-icon el-icon-circle-close"
  255. ></i>
  256. </div>
  257. </template>
  258. </el-table-column>
  259. </el-table>
  260. <el-button
  261. icon="el-icon-circle-plus-outline"
  262. type="info"
  263. plain
  264. :disabled="surplustime < (selectPrice || 0 || Math.min(...pricesArray))"
  265. @click="create"
  266. style="margin-top: 10px; width: 100%"
  267. >添加循环</el-button
  268. >
  269. </div>
  270. </template>
  271. <script>
  272. import { diffTimerFormMinute, addTimerFormMinute } from "@/utils/date";
  273. import { classTimeList } from "@/utils/searchArray";
  274. import dayjs from "dayjs";
  275. const classTimeListByType = {};
  276. for (const item of classTimeList) {
  277. classTimeListByType[item.value] = item.label;
  278. }
  279. export default {
  280. props: [
  281. "form",
  282. "type",
  283. "surplustime",
  284. "prices",
  285. "selectPrice",
  286. "holidays",
  287. "teacherList",
  288. "activeType",
  289. "cooperationList",
  290. "coreid",
  291. "assistant",
  292. "endSchoolTerm",
  293. "startCourseDate",
  294. ],
  295. data() {
  296. const validatePass = (rule, value, callback) => {
  297. // console.log(this.endSchoolTerm, "结束", value);
  298. let timer = dayjs(this.endSchoolTerm).valueOf() - dayjs(value).valueOf();
  299. if (this.endSchoolTerm && timer < 0) {
  300. callback(new Error(`结束时间不能超过${this.endSchoolTerm}`));
  301. } else {
  302. callback();
  303. }
  304. };
  305. const validateNum = (rule, value, callback) => {
  306. // validUsername
  307. if (this.surplustime < 0) {
  308. callback(new Error("排课时长超过规则限制"));
  309. } else {
  310. callback();
  311. }
  312. };
  313. return {
  314. classTimeListByType,
  315. useTime: 0,
  316. validatePass,
  317. validateNum,
  318. pickerOptions: this.getPickerOptions(),
  319. };
  320. },
  321. mounted() {
  322. this.updateUseTime()
  323. },
  324. computed: {
  325. weekDateList() {
  326. return [
  327. { value: "1", label: "星期一" },
  328. { value: "2", label: "星期二" },
  329. { value: "3", label: "星期三" },
  330. { value: "4", label: "星期四" },
  331. { value: "5", label: "星期五" },
  332. { value: "6", label: "星期六" },
  333. { value: "7", label: "星期日" },
  334. ];
  335. },
  336. pricesArray() {
  337. return (this.prices[this.type] || "").split(",").filter((item) => !!item);
  338. },
  339. },
  340. methods: {
  341. updateUseTime() {
  342. let time = 0;
  343. for (const item of this.form.cycle) {
  344. time += (item.time || 0) * (item.expectCourseNum || 0);
  345. }
  346. this.useTime = time;
  347. this.$emit("setUserTime", time, this.type);
  348. },
  349. create() {
  350. if (this.endSchoolTerm) {
  351. if (this.surplustime <= 0) {
  352. this.$message.error("已排课时长使用完毕,请修改预计课时数");
  353. return;
  354. }
  355. } else {
  356. if (this.surplustime <= this.useTime) {
  357. this.$message.error("已排课时长使用完毕,请修改预计课时数");
  358. return;
  359. }
  360. }
  361. const initVal = { coreTeacher: this.coreid, assistant: this.assistant };
  362. if (this.selectPrice) {
  363. initVal.time = this.selectPrice;
  364. }
  365. this.form.cycle.push(initVal);
  366. this.updateUseTime();
  367. },
  368. remove(index) {
  369. this.form.cycle.splice(index, 1);
  370. this.updateUseTime();
  371. },
  372. startTimeChange(item, val) {
  373. this.getUseTime(item.row);
  374. if (item.row.time && item.row.startClassTime) {
  375. let str = dayjs(new Date()).format("YYYY-MM-DD");
  376. this.$set(
  377. item.row,
  378. "endClassTime",
  379. addTimerFormMinute(str, item.row.startClassTime, item.row.time)
  380. );
  381. } else {
  382. this.$set(item.row, "endClassTime", "");
  383. }
  384. if (val) {
  385. let activeTime = val * Math.max(item.row.expectCourseNum || 0, 0);
  386. if (this.endSchoolTerm) {
  387. this.$set(
  388. item.row,
  389. "expectCourseNum",
  390. parseInt((this.surplustime + activeTime) / val)
  391. );
  392. } else {
  393. this.$set(
  394. item.row,
  395. "expectCourseNum",
  396. parseInt((this.surplustime - this.useTime + activeTime) / val)
  397. );
  398. }
  399. // this.surplusTime
  400. } else {
  401. this.$set(item.row, "expectCourseNum", 0);
  402. }
  403. this.getUseTime(item.row);
  404. },
  405. timeChange(item) {
  406. if (item.time && item.startClassTime) {
  407. let str = dayjs(new Date()).format("YYYY-MM-DD");
  408. this.$set(
  409. item,
  410. "endClassTime",
  411. addTimerFormMinute(str, item.startClassTime, item.time)
  412. );
  413. } else {
  414. this.$set(item, "endClassTime", "");
  415. }
  416. this.updateUseTime();
  417. },
  418. holidayChange(row) {
  419. this.updateEndTime(row);
  420. },
  421. getUseTime(row) {
  422. this.updateEndTime(row);
  423. this.useTime = 0;
  424. this.form.cycle.forEach((item) => {
  425. this.useTime +=
  426. (item.expectCourseNum ? parseInt(item.expectCourseNum) : 0) *
  427. parseInt(item.time);
  428. });
  429. this.updateUseTime();
  430. // this.$emit('setUserTime', this.useTime, this.type)
  431. },
  432. addData(startDate, dayOfWeek) {
  433. let num;
  434. let dayjs = this.$helpers.dayjs;
  435. let date = dayjs(startDate).toDate();
  436. dayOfWeek - date.getDay() >= 0
  437. ? (num = dayOfWeek - date.getDay())
  438. : (num = dayOfWeek - date.getDay() + 7);
  439. return num;
  440. },
  441. updateEndTime(row) {
  442. if (row.dayOfWeek && row.startDate && typeof row.holiday === "boolean") {
  443. // const num = this.addData(row.startDate, row.dayOfWeek)
  444. // const week = dayjs(row.startDate).get('day') == 0 ? 7 : dayjs(row.startDate).get('day')
  445. const selectWeek = row.dayOfWeek == 7 ? 0 : row.dayOfWeek;
  446. let exp = Math.max(row.expectCourseNum, 0);
  447. let end = dayjs(row.startDate);
  448. // console.log(selectWeek, end.get('day'))
  449. if (row.holiday) {
  450. // exp >0 还有未排的课
  451. while (exp > 0) {
  452. if (
  453. selectWeek == end.get("day") &&
  454. !this.holidays.includes(end.format("YYYY-MM-DD"))
  455. ) {
  456. exp--;
  457. }
  458. end = end.add(1, "day");
  459. if (exp === 0) {
  460. end = end.subtract(1, "day");
  461. }
  462. }
  463. } else {
  464. while (exp > 0) {
  465. if (selectWeek == end.get("day")) {
  466. exp--;
  467. }
  468. end = end.add(1, "day");
  469. if (exp === 0) {
  470. end = end.subtract(1, "day");
  471. }
  472. }
  473. }
  474. const enumd = this.addData(end.format("YYYY-MM-DD"), row.dayOfWeek);
  475. console.log(enumd);
  476. // end = end.add(enumd, 'day')
  477. this.$set(row, "endDate", end.format("YYYY-MM-DD"));
  478. } else {
  479. this.$set(row, "endDate", "");
  480. }
  481. // if (row.dayOfWeek && row.startDate && typeof row.holiday === 'boolean') {
  482. // // const num = this.addData(row.startDate, row.dayOfWeek)
  483. // const week = dayjs(row.startDate).get('day') == 0 ? 7 : dayjs(row.startDate).get('day')
  484. // const selectWeek = row.dayOfWeek
  485. // const exp = Math.max(row.expectCourseNum - (selectWeek >= week ? 1 : 0), 0)
  486. // let end = dayjs(row.startDate).add((exp*7), 'day')
  487. // if (row.holiday) {
  488. // for (const d of this.holidays) {
  489. // if (dayjs(d).isBetween(row.startDate, end.format('YYYY-MM-DD'), null, '[]') && row.dayOfWeek - 1 == dayjs(d).get('day')) {
  490. // end = end.add(7, 'day')
  491. // }
  492. // }
  493. // }
  494. // const enumd = this.addData(end.format('YYYY-MM-DD'), row.dayOfWeek)
  495. // end = end.add(enumd, 'day')
  496. // this.$set(
  497. // row,
  498. // "endDate",
  499. // end.format('YYYY-MM-DD')
  500. // );
  501. // } else {
  502. // this.$set(
  503. // row,
  504. // "endDate",
  505. // ''
  506. // );
  507. // }
  508. },
  509. changeStartDate(val, row) {
  510. this.updateEndTime(row);
  511. this.updateUseTime();
  512. },
  513. getPickerOptions() {
  514. let that = this;
  515. return {
  516. firstDayOfWeek: 1,
  517. disabledDate(time) {
  518. if (that.startCourseDate) {
  519. // 对比时间
  520. let startTime = dayjs(that.startCourseDate).valueOf();
  521. let nowDate = new Date().getTime();
  522. let minTime;
  523. startTime - nowDate > 0
  524. ? (minTime = startTime)
  525. : (minTime = nowDate);
  526. let maxTime = dayjs(that.endSchoolTerm).valueOf();
  527. return (
  528. time.getTime() + 86400000 <= minTime ||
  529. maxTime <= time.getTime() - 86400000
  530. );
  531. } else {
  532. return time.getTime() + 86400000 <= new Date().getTime();
  533. }
  534. },
  535. };
  536. },
  537. },
  538. };
  539. </script>
  540. <style lang="less" scoped>
  541. ::v-deep .close-icon {
  542. cursor: pointer;
  543. font-size: 16px;
  544. margin-bottom: 24px;
  545. line-height: 40px;
  546. }
  547. </style>