classroom-setting.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  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 { sysConfigList } from "@/api/generalSettings";
  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. ],
  213. components: {
  214. courseItem,
  215. "classrome-preview": classromePreview,
  216. },
  217. data() {
  218. return {
  219. form: {
  220. coreTeacher: "",
  221. assistant: "",
  222. classs: {},
  223. },
  224. allClasss: {},
  225. prices: {},
  226. collapses: [0],
  227. courseTimes: {},
  228. courseTypeListByName: {},
  229. classTimeListByType,
  230. musicCourseSettings: {},
  231. musicSurplus: {},
  232. previewVisible: false,
  233. previewList: [],
  234. holidays: [],
  235. };
  236. },
  237. watch: {
  238. courseTypeList() {
  239. this.setCourseTypeListByName();
  240. },
  241. studentSubmitedData() {
  242. this.formatClasss();
  243. },
  244. detail() {
  245. this.formatClasss();
  246. },
  247. },
  248. computed: {
  249. surplustime() {
  250. const _ = {};
  251. for (const key in this.form.classs) {
  252. if (this.form.classs.hasOwnProperty(key)) {
  253. const item = this.form.classs[key];
  254. // - plusNum(item.cycle, "time");
  255. _[key] = item.courseTotalMinuties;
  256. }
  257. }
  258. return _;
  259. },
  260. isEmpty() {
  261. return isEmpty(this.form.classs);
  262. },
  263. musicGroup() {
  264. return MusicStore.state.musicGroup;
  265. },
  266. },
  267. async mounted() {
  268. try {
  269. await MusicStore.dispatch("getBaseInfo", {
  270. data: { musicGroupId: this.musicGroupId },
  271. });
  272. const res = await queryByOrganIdAndCourseType({
  273. organId: this.musicGroup.organId,
  274. });
  275. this.prices = res.data;
  276. } catch (error) {}
  277. this.setCourseTypeListByName();
  278. this.formatClasss();
  279. this.FetchHoliday();
  280. },
  281. methods: {
  282. async FetchHoliday() {
  283. try {
  284. const res = await sysConfigList({
  285. group: "holiday",
  286. });
  287. this.holidays = JSON.parse(res.data[0].paranValue);
  288. } catch (error) {}
  289. },
  290. setCourseTypeListByName() {
  291. const courseTypeListByName = {};
  292. for (const item of this.courseTypeList) {
  293. courseTypeListByName[item.value] = item.label;
  294. }
  295. this.courseTypeListByName = courseTypeListByName;
  296. },
  297. async formatClasss() {
  298. this.coreid = "";
  299. this.assistant = [];
  300. if (this.detail) {
  301. const { classGroupTeacherMapperList } = this.detail;
  302. for (const item of classGroupTeacherMapperList || []) {
  303. if (item.teacherRole === "BISHOP") {
  304. this.coreid = String(item.userId);
  305. }
  306. if (item.teacherRole === "TEACHING") {
  307. this.assistant.push(item.userId);
  308. }
  309. }
  310. this.$set(this.form, "coreTeacher", String(this.coreid));
  311. this.$set(this.form, "assistant", this.assistant);
  312. }
  313. const studentIds = this.detail
  314. ? undefined
  315. : this.studentSubmitedData?.seleched.join(",");
  316. const classGroupId = this.detail?.id;
  317. if (!studentIds && !classGroupId) {
  318. return;
  319. }
  320. let res = {};
  321. if (this.classType == 5) {
  322. // res = await findClassCourseMinute(this.classIdList);
  323. res.data = this.classCouresTimeList;
  324. } else {
  325. try {
  326. res = await getMusicCourseSettingsWithStudents({
  327. musicGroupId: this.musicGroupId,
  328. studentIds,
  329. classGroupId,
  330. });
  331. } catch (error) {
  332. console.log(error);
  333. }
  334. }
  335. // console.log(res);
  336. if (Object.keys(res).length <= 0) return;
  337. this.musicCourseSettings = res.data;
  338. for (let key in this.musicCourseSettings) {
  339. this.musicSurplus[key] = 0;
  340. }
  341. const classs = {};
  342. for (const item of this.courseTypeList) {
  343. const key = item.value;
  344. if (res.data[key]) {
  345. classs[key] = {
  346. courseTotalMinuties: res.data[key],
  347. cycle: [
  348. {
  349. time: this.selectPrices ? this.selectPrices[key] : undefined,
  350. coreTeacher: this.coreid,
  351. assistant: this.assistant,
  352. },
  353. ],
  354. };
  355. }
  356. }
  357. this.allClasss = { ...classs };
  358. this.$set(this.form, "classs", classs);
  359. // this.courseTimes = courseTimes
  360. },
  361. changeTag(key) {
  362. const clas = { ...this.form.classs };
  363. if (clas[key]) {
  364. delete clas[key];
  365. } else {
  366. clas[key] = this.allClasss[key];
  367. }
  368. this.$set(this.form, "classs", clas);
  369. },
  370. submit(type) {
  371. for (const key in this.musicCourseSettings) {
  372. if (Object.hasOwnProperty.call(this.musicCourseSettings, key)) {
  373. const allTime = this.musicCourseSettings[key];
  374. const useTime = this.musicSurplus[key];
  375. if (useTime > allTime) {
  376. this.$message.error(
  377. this.courseTypeListByName[key] + " 课程时长不足"
  378. );
  379. return;
  380. }
  381. }
  382. }
  383. this.$refs.form.validate(async (valid) => {
  384. if (valid) {
  385. const list = [];
  386. for (const key in this.form.classs) {
  387. if (this.form.classs.hasOwnProperty(key)) {
  388. const item = this.form.classs[key];
  389. const data = {
  390. type: this.detail ? undefined : this.activeType,
  391. courseType: key,
  392. classGroupName:
  393. this.studentSubmitedData?.name ||
  394. this.detail?.name ||
  395. this.form.className,
  396. classGroupId: this.detail?.id,
  397. musicGroupId: this.musicGroupId,
  398. startDate: item.courseTime,
  399. classGroupTeacherMapperList: formatClassGroupTeacherMapperList(
  400. this.form.coreTeacher,
  401. this.form.assistant
  402. ),
  403. holiday: item.holiday,
  404. students: this.studentSubmitedData?.seleched,
  405. courseTimes: item.cycle.length,
  406. courseTimeDtoList: item.cycle.map((_) => ({
  407. classGroupTeacherMapperList: this.formatTeacher(_),
  408. courseType: key,
  409. dayOfWeek: _.dayOfWeek,
  410. endClassTime: _.endClassTime,
  411. startClassTime: _.startClassTime,
  412. startDate: _.startDate,
  413. endDate: _.endDate,
  414. holiday: _.holiday,
  415. expectCourseNum: _.expectCourseNum,
  416. })),
  417. };
  418. if (type && typeof type === "string") {
  419. data[type] = true;
  420. }
  421. list.push(data);
  422. }
  423. }
  424. try {
  425. if (this.detail) {
  426. let result = await classGroupUpdate(list);
  427. this.previewVisible = false;
  428. if (result.code == 207) {
  429. await this.$confirm(
  430. result.msg || `当前课程课酬预计为0,是否继续`,
  431. "提示",
  432. {
  433. type: "warning",
  434. }
  435. );
  436. // obj.allowZeroSalary = true;
  437. list.forEach((item) => {
  438. item.allowZeroSalary = true;
  439. });
  440. await classGroupUpdate(list);
  441. this.$listeners.submited();
  442. this.$listeners.close();
  443. return;
  444. }
  445. if (result.code == 206) {
  446. this.previewVisible = true;
  447. this.previewList = result.data;
  448. return;
  449. }
  450. this.$message.success("排课修改成功");
  451. } else {
  452. if (this.classType == 1) {
  453. // 0新建班级 2 3 4新增班级修改
  454. await revisionClassGroup(list);
  455. this.$message.success("排课成功");
  456. } else if (
  457. this.classType == 2 ||
  458. this.classType == 3 ||
  459. this.classType == 4
  460. ) {
  461. await revisionAddClassGroup(list);
  462. this.$message.success("排课成功");
  463. } else if (this.classType == 5) {
  464. // 这里是合班拆班
  465. let obj = {};
  466. obj.musicGroupPaymentCalenderDtos = this.musicGroupPaymentCalenderDtos;
  467. obj.classGroup4MixDtos = list;
  468. obj.classGroupIds = this.classIdList;
  469. obj.studentIds = this.studentSubmitedData.seleched;
  470. obj.classGroupStudents = this.classGroupStudents;
  471. obj.classCourseMinuteMap = this.selectPrices;
  472. await mergeClassSplitClassAffirm(obj);
  473. let grend = this.$parent.$parent.$parent.$parent.$parent.$parent
  474. .$parent;
  475. grend.closeStudentReset();
  476. grend.getList();
  477. return;
  478. }
  479. }
  480. this.$listeners.submited();
  481. this.$listeners.close();
  482. } catch (error) {
  483. console.log(error);
  484. }
  485. } else {
  486. this.$message.error("请先填写所有表单");
  487. }
  488. });
  489. },
  490. collapseChange(val) {
  491. this.collapses = val;
  492. },
  493. changecoreTeacher(val) {},
  494. updateMusicSurplus() {},
  495. setUserTime(time, type) {
  496. // console.log(time, type)
  497. this.$set(this.musicSurplus, type, time || 0);
  498. // console.log(this.musicSurplus)
  499. this.$forceUpdate();
  500. // this.$nextTick(res=>{
  501. // this.musicSurplus[type] = time;
  502. // console.log(this.musicSurplus[type])
  503. // })
  504. },
  505. formatTeacher(row) {
  506. console.log(row);
  507. let arr = [];
  508. if (row.coreTeacher) {
  509. let obj = {};
  510. obj.teacherRole = "BISHOP";
  511. obj.userId = row.coreTeacher;
  512. arr.push(obj);
  513. }
  514. if (row.assistant?.length > 0) {
  515. row.assistant.forEach((ass) => {
  516. arr.push({ teacherRole: "TEACHING", userId: ass });
  517. });
  518. }
  519. return arr;
  520. },
  521. },
  522. // watch:{
  523. // musicSurplus(){
  524. // deep
  525. // }
  526. // }
  527. };
  528. </script>
  529. <style lang="less" scoped>
  530. .dialog-footer {
  531. margin-top: 20px;
  532. display: block;
  533. text-align: right;
  534. }
  535. .title {
  536. font-size: 16px;
  537. padding: 10px;
  538. font-weight: normal;
  539. > span {
  540. color: tomato;
  541. font-size: 14px;
  542. }
  543. }
  544. .tag {
  545. margin-right: 5px;
  546. cursor: pointer;
  547. }
  548. </style>