classroom-setting.vue 15 KB

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