classroom-setting.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. <template>
  2. <div>
  3. <el-form
  4. :model="form"
  5. inline
  6. ref="form"
  7. label-suffix=": "
  8. label-width="130px"
  9. >
  10. <el-row v-if="classType == 5">
  11. <el-form-item
  12. label="班级名称"
  13. prop="className"
  14. label-width="88px"
  15. :rules="[{ required: true, message: '请填写班级名称' }]"
  16. >
  17. <el-input
  18. v-model.trim="form.className"
  19. placeholder="请输入班级名称"
  20. style="width: 180px"
  21. ></el-input>
  22. </el-form-item>
  23. </el-row>
  24. <!-- <el-form-item
  25. label="主教老师"
  26. prop="coreTeacher"
  27. label-width="88px"
  28. :rules="[{ required: true, message: '请选择主教老师' }]"
  29. >
  30. <el-select
  31. v-model.trim="form.coreTeacher"
  32. placeholder="请选择主教老师"
  33. clearable
  34. filterable
  35. @change="changecoreTeacher"
  36. >
  37. <el-option
  38. v-for="(item, index) in teacherList"
  39. :key="index"
  40. :label="item.realName"
  41. :value="String(item.id)"
  42. >
  43. <span style="float: left">{{ item.realName }}</span>
  44. <span style="float: right; color: #8492a6; font-size: 13px">{{
  45. String(item.id)
  46. }}</span>
  47. </el-option>
  48. </el-select>
  49. <remote-search :commit="'setTeachers'" v-model="form.coreTeacher" />
  50. </el-form-item> -->
  51. <!-- <el-form-item
  52. label="助教老师"
  53. prop="assistant"
  54. v-if="
  55. activeType != 'HIGH' &&
  56. activeType != 'HIGH_ONLINE' &&
  57. activeType != 'MUSIC_NETWORK'
  58. "
  59. >
  60. <el-select
  61. v-model.trim="form.assistant"
  62. placeholder="请选择助教老师"
  63. filterable
  64. clearable
  65. multiple
  66. >
  67. <el-option
  68. v-for="(item, index) in cooperationList"
  69. :key="index"
  70. :label="item.realName"
  71. :value="item.id"
  72. >
  73. <span style="float: left">{{ item.realName }}</span>
  74. <span style="float: right; color: #8492a6; font-size: 13px">{{
  75. String(item.id)
  76. }}</span>
  77. </el-option>
  78. </el-select>
  79. </el-form-item> -->
  80. <el-form-item
  81. v-if="!!Object.keys(allClasss).length"
  82. style="display: block"
  83. label="排课类型"
  84. label-width="88px"
  85. >
  86. <el-tag
  87. class="tag"
  88. :effect="form.classs[key] ? 'dark' : 'plain'"
  89. v-for="(item, key) in allClasss"
  90. :key="key"
  91. @click="changeTag(key)"
  92. >{{ courseTypeListByName[key] }}</el-tag
  93. >
  94. </el-form-item>
  95. <empty v-if="isEmpty" desc="暂无可排课时长" />
  96. <el-collapse v-model="collapses" @change="collapseChange">
  97. <el-collapse-item
  98. v-for="(item, key, index) in form.classs"
  99. :name="index"
  100. :key="key"
  101. >
  102. <template #title>
  103. <p class="title">
  104. {{ courseTypeListByName[key] }},
  105. <span>可排课时长:{{ musicCourseSettings[key] }}分钟</span>
  106. <span style="color: #333"
  107. >已排课时长:{{ musicSurplus[key] }}分钟</span
  108. >
  109. </p>
  110. </template>
  111. <courseItem
  112. :surplustime="surplustime[key]"
  113. @setUserTime="setUserTime"
  114. :teacherList="teacherList"
  115. :activeType="activeType"
  116. :cooperationList="cooperationList"
  117. :coreid="coreid"
  118. :assistant="assistant"
  119. :type="key"
  120. :form="item"
  121. :prices="prices"
  122. :holidays="holidays"
  123. :selectPrice="selectPrices ? selectPrices[key] : ''"
  124. />
  125. </el-collapse-item>
  126. </el-collapse>
  127. </el-form>
  128. <div slot="footer" class="dialog-footer" v-if="classType != 5">
  129. <el-button @click="$listeners.close">取 消</el-button>
  130. <el-button type="primary" :disabled="isEmpty" @click="submit"
  131. >下一步</el-button
  132. >
  133. </div>
  134. <el-dialog
  135. title="班级预览"
  136. :visible.sync="previewVisible"
  137. append-to-body
  138. width="900px"
  139. >
  140. <classrome-preview
  141. :types="form.classs"
  142. :details="previewList"
  143. :courseTypeListByName="courseTypeListByName"
  144. :teacherList="teacherList"
  145. :cooperationList="cooperationList"
  146. :coreTeacher="form.coreTeacher"
  147. :assistant="form.assistant"
  148. />
  149. <div slot="footer" class="dialog-footer" v-if="classType != 5">
  150. <el-button @click="previewVisible = false">取 消</el-button>
  151. <el-button type="primary" @click="submit('confirmGenerate')"
  152. >确认排课</el-button
  153. >
  154. </div>
  155. </el-dialog>
  156. </div>
  157. </template>
  158. <script>
  159. import {
  160. getMusicCourseSettingsWithStudents,
  161. classGroupUpdate,
  162. revisionClassGroup,
  163. revisionAddClassGroup,
  164. findClassCourseMinute,
  165. mergeClassSplitClassAffirm
  166. } from "@/api/buildTeam";
  167. import courseItem from "./classroom-setting-item";
  168. import { classTimeList } from "@/utils/searchArray";
  169. import MusicStore from "@/views/resetTeaming/store";
  170. import { getSysTenantConfig } from "@/views/courseRulersManager/api";
  171. import { queryByOrganIdAndCourseType } from "@/views/resetTeaming/api";
  172. import { isEmpty } from "lodash";
  173. import classromePreview from "./classroom-preview";
  174. const classTimeListByType = {};
  175. for (const item of classTimeList) {
  176. classTimeListByType[item.value] = item.label;
  177. }
  178. const formatClassGroupTeacherMapperList = (core, ass) => {
  179. const list = [];
  180. if (core) {
  181. list.push({ userId: core, teacherRole: "BISHOP" });
  182. }
  183. if (ass) {
  184. for (const item of ass) {
  185. list.push({ userId: item, teacherRole: "TEACHING" });
  186. }
  187. }
  188. return list;
  189. };
  190. const plusNum = (items = [], key) => {
  191. let money = 0;
  192. for (const item of items) {
  193. money += parseFloat(parseFloat(item[key] || 0).toFixed(2) || 0);
  194. }
  195. return money;
  196. };
  197. export default {
  198. props: [
  199. "activeType",
  200. "courseTypeList",
  201. "musicGroupId",
  202. "detail",
  203. "studentSubmitedData",
  204. "classType",
  205. "musicGroupPaymentCalenderDtos",
  206. "classIdList",
  207. "classGroupStudents",
  208. "selectPrices",
  209. "classCouresTimeList",
  210. "teacherList",
  211. "cooperationList",
  212. "isCourseNumType"
  213. ],
  214. components: {
  215. courseItem,
  216. "classrome-preview": classromePreview
  217. },
  218. data() {
  219. return {
  220. form: {
  221. coreTeacher: "",
  222. assistant: "",
  223. classs: {}
  224. },
  225. allClasss: {},
  226. prices: {}, //分部每种课程类型的时长
  227. collapses: [0],
  228. courseTimes: {},
  229. courseTypeListByName: {},
  230. classTimeListByType,
  231. musicCourseSettings: {},
  232. musicSurplus: {},
  233. previewVisible: false,
  234. previewList: [],
  235. holidays: []
  236. };
  237. },
  238. watch: {
  239. courseTypeList() {
  240. this.setCourseTypeListByName();
  241. },
  242. studentSubmitedData() {
  243. this.formatClasss();
  244. },
  245. detail() {
  246. this.formatClasss();
  247. }
  248. },
  249. computed: {
  250. surplustime() {
  251. console.log(this.form, "classssurplustime");
  252. const _ = {};
  253. for (const key in this.form.classs) {
  254. if (this.form.classs.hasOwnProperty(key)) {
  255. const item = this.form.classs[key];
  256. // - plusNum(item.cycle, "time");
  257. _[key] = item.courseTotalMinuties;
  258. }
  259. }
  260. return _;
  261. },
  262. isEmpty() {
  263. return isEmpty(this.form.classs);
  264. },
  265. musicGroup() {
  266. return MusicStore.state.musicGroup;
  267. }
  268. },
  269. async mounted() {
  270. this.setCourseTypeListByName();
  271. this.formatClasss();
  272. this.init();
  273. },
  274. methods: {
  275. async init() {
  276. try {
  277. await MusicStore.dispatch("getBaseInfo", {
  278. data: { musicGroupId: this.musicGroupId }
  279. });
  280. const res = await queryByOrganIdAndCourseType({
  281. organId: this.musicGroup.organId
  282. });
  283. const res1 = await getSysTenantConfig({
  284. group: "holiday"
  285. });
  286. this.holidays = JSON.parse(
  287. res1.data[0].paranValue ? res1.data[0].paranValue : "[]"
  288. );
  289. this.prices = res.data;
  290. let arr = [];
  291. if (JSON.stringify(this.prices) == "{}") {
  292. // 课程时长
  293. arr.push("teamCourseTimer");
  294. }
  295. if (this.holidays.length <= 0) {
  296. arr.push("holiday");
  297. }
  298. //
  299. if (arr.length > 0) {
  300. this.$bus.$emit("showguide", arr);
  301. return;
  302. }
  303. } catch (error) {
  304. console.log(error);
  305. }
  306. },
  307. setCourseTypeListByName() {
  308. const courseTypeListByName = {};
  309. for (const item of this.courseTypeList) {
  310. courseTypeListByName[item.value] = item.label;
  311. }
  312. this.courseTypeListByName = courseTypeListByName;
  313. },
  314. async formatClasss() {
  315. this.coreid = "";
  316. this.assistant = [];
  317. if (this.detail) {
  318. const { classGroupTeacherMapperList } = this.detail;
  319. for (const item of classGroupTeacherMapperList || []) {
  320. if (item.teacherRole === "BISHOP") {
  321. this.coreid = String(item.userId);
  322. }
  323. if (item.teacherRole === "TEACHING") {
  324. this.assistant.push(item.userId);
  325. }
  326. }
  327. this.$set(this.form, "coreTeacher", String(this.coreid));
  328. this.$set(this.form, "assistant", this.assistant);
  329. }
  330. const studentIds = this.detail
  331. ? undefined
  332. : this.studentSubmitedData?.seleched.join(",");
  333. const classGroupId = this.detail?.id;
  334. if (!studentIds && !classGroupId) {
  335. return;
  336. }
  337. let res = {};
  338. if (this.classType == 5) {
  339. // res = await findClassCourseMinute(this.classIdList);
  340. res.data = this.classCouresTimeList;
  341. } else {
  342. try {
  343. res = await getMusicCourseSettingsWithStudents({
  344. musicGroupId: this.musicGroupId,
  345. studentIds,
  346. classGroupId
  347. });
  348. if (res.data.checkCourseTimesFlag == 1) {
  349. this.$confirm("该班级学员剩余时长不一致是否继续?", "提示", {
  350. confirmButtonText: "确定",
  351. cancelButtonText: "取消",
  352. type: "warning"
  353. })
  354. .then(() => {})
  355. .catch(e => {
  356. this.$emit("close");
  357. });
  358. }
  359. } catch (error) {
  360. console.log(error);
  361. }
  362. }
  363. // console.log(res);
  364. if (Object.keys(res).length <= 0) return;
  365. this.musicCourseSettings = res.data;
  366. for (let key in this.musicCourseSettings) {
  367. this.musicSurplus[key] = 0;
  368. }
  369. const classs = {};
  370. for (const item of this.courseTypeList) {
  371. const key = item.value;
  372. if (res.data[key]) {
  373. classs[key] = {
  374. courseTotalMinuties: res.data[key],
  375. cycle: [
  376. {
  377. time: this.selectPrices ? this.selectPrices[key] : undefined,
  378. coreTeacher: this.coreid,
  379. assistant: this.assistant,
  380. intervalDays: 7
  381. }
  382. ]
  383. };
  384. }
  385. }
  386. this.allClasss = { ...classs };
  387. this.$set(this.form, "classs", classs);
  388. // this.courseTimes = courseTimes
  389. },
  390. changeTag(key) {
  391. const clas = { ...this.form.classs };
  392. if (clas[key]) {
  393. delete clas[key];
  394. } else {
  395. clas[key] = this.allClasss[key];
  396. }
  397. this.$set(this.form, "classs", clas);
  398. },
  399. submit(type) {
  400. for (const key in this.musicCourseSettings) {
  401. if (Object.hasOwnProperty.call(this.musicCourseSettings, key)) {
  402. const allTime = this.musicCourseSettings[key];
  403. const useTime = this.musicSurplus[key];
  404. if (useTime > allTime) {
  405. this.$message.error(
  406. this.courseTypeListByName[key] + " 课程时长不足"
  407. );
  408. return;
  409. }
  410. }
  411. }
  412. this.$refs.form.validate(async valid => {
  413. if (valid) {
  414. const list = [];
  415. for (const key in this.form.classs) {
  416. if (this.form.classs.hasOwnProperty(key)) {
  417. const item = this.form.classs[key];
  418. const data = {
  419. type: this.detail ? undefined : this.activeType,
  420. courseType: key,
  421. classGroupName:
  422. this.studentSubmitedData?.name ||
  423. this.detail?.name ||
  424. this.form.className,
  425. classGroupId: this.detail?.id,
  426. musicGroupId: this.musicGroupId,
  427. startDate: item.courseTime,
  428. classGroupTeacherMapperList: formatClassGroupTeacherMapperList(
  429. this.form.coreTeacher,
  430. this.form.assistant
  431. ),
  432. holiday: item.holiday,
  433. students: this.studentSubmitedData?.seleched,
  434. courseTimes: item.cycle.length,
  435. courseTimeDtoList: item.cycle.map(_ => ({
  436. classGroupTeacherMapperList: this.formatTeacher(_),
  437. courseType: key,
  438. dayOfWeek: _.dayOfWeek,
  439. endClassTime: _.endClassTime,
  440. startClassTime: _.startClassTime,
  441. startDate: _.startDate,
  442. endDate: _.endDate,
  443. holiday: _.holiday,
  444. expectCourseNum: _.expectCourseNum
  445. }))
  446. };
  447. if (type && typeof type === "string") {
  448. data[type] = true;
  449. }
  450. list.push(data);
  451. }
  452. }
  453. try {
  454. if (this.detail) {
  455. let result = await classGroupUpdate(list);
  456. this.previewVisible = false;
  457. if (result.code == 207) {
  458. await this.$confirm(
  459. result.msg || `当前课程课酬预计为0,是否继续`,
  460. "提示",
  461. {
  462. type: "warning"
  463. }
  464. );
  465. // obj.allowZeroSalary = true;
  466. list.forEach(item => {
  467. item.allowZeroSalary = true;
  468. });
  469. await classGroupUpdate(list);
  470. this.$listeners.submited();
  471. this.$listeners.close();
  472. return;
  473. }
  474. if (result.code == 208) {
  475. await this.$confirm(
  476. result.msg || `班级剩余排课时长不一致,请再次确认`,
  477. "提示",
  478. {
  479. type: "warning"
  480. }
  481. );
  482. // obj.allowZeroSalary = true;
  483. list.forEach(item => {
  484. item.checkCourseTimesFlag = true;
  485. });
  486. await classGroupUpdate(list);
  487. this.$listeners.submited();
  488. this.$listeners.close();
  489. return;
  490. }
  491. if (result.code == 206) {
  492. this.previewVisible = true;
  493. this.previewList = result.data;
  494. return;
  495. }
  496. this.$message.success("排课修改成功");
  497. } else {
  498. if (this.classType == 1) {
  499. // 0新建班级 2 3 4新增班级修改
  500. await revisionClassGroup(list);
  501. this.$message.success("排课成功");
  502. } else if (
  503. this.classType == 2 ||
  504. this.classType == 3 ||
  505. this.classType == 4
  506. ) {
  507. await revisionAddClassGroup(list);
  508. this.$message.success("排课成功");
  509. } else if (this.classType == 5) {
  510. // 这里是合班拆班
  511. let obj = {};
  512. obj.musicGroupPaymentCalenderDtos = this.musicGroupPaymentCalenderDtos;
  513. obj.classGroup4MixDtos = list;
  514. obj.classGroupIds = this.classIdList;
  515. obj.studentIds = this.studentSubmitedData.seleched;
  516. obj.classGroupStudents = this.classGroupStudents;
  517. obj.classCourseMinuteMap = this.selectPrices;
  518. await mergeClassSplitClassAffirm(obj);
  519. let grend = this.$parent.$parent.$parent.$parent.$parent.$parent
  520. .$parent;
  521. grend.closeStudentReset();
  522. grend.getList();
  523. return;
  524. }
  525. }
  526. this.$listeners.submited();
  527. this.$listeners.close();
  528. } catch (error) {
  529. console.log(error);
  530. }
  531. } else {
  532. this.$message.error("请先填写所有表单");
  533. }
  534. });
  535. },
  536. collapseChange(val) {
  537. this.collapses = val;
  538. },
  539. changecoreTeacher(val) {},
  540. updateMusicSurplus() {},
  541. setUserTime(time, type) {
  542. // console.log(time, type)
  543. this.$set(this.musicSurplus, type, time || 0);
  544. // console.log(this.musicSurplus)
  545. this.$forceUpdate();
  546. // this.$nextTick(res=>{
  547. // this.musicSurplus[type] = time;
  548. // console.log(this.musicSurplus[type])
  549. // })
  550. },
  551. formatTeacher(row) {
  552. let arr = [];
  553. if (row.coreTeacher) {
  554. let obj = {};
  555. obj.teacherRole = "BISHOP";
  556. obj.userId = row.coreTeacher;
  557. arr.push(obj);
  558. }
  559. if (row.assistant?.length > 0) {
  560. row.assistant.forEach(ass => {
  561. arr.push({ teacherRole: "TEACHING", userId: ass });
  562. });
  563. }
  564. return arr;
  565. }
  566. }
  567. // watch:{
  568. // musicSurplus(){
  569. // deep
  570. // }
  571. // }
  572. };
  573. </script>
  574. <style lang="less" scoped>
  575. .dialog-footer {
  576. margin-top: 20px;
  577. display: block;
  578. text-align: right;
  579. }
  580. .title {
  581. font-size: 16px;
  582. padding: 10px;
  583. font-weight: normal;
  584. > span {
  585. color: tomato;
  586. font-size: 14px;
  587. }
  588. }
  589. .tag {
  590. margin-right: 5px;
  591. cursor: pointer;
  592. }
  593. </style>