program.vue 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012
  1. <template>
  2. <div class="program">
  3. <van-cell-group class="van-cell-group--inset">
  4. <van-cell :title="vipGroup.name" class="titleContent" title-class="titleStyle" label-class="labelStyle">
  5. <template #label>
  6. <p>{{ vipGroup.description }}</p>
  7. <!-- <p>排课时间范围:{{ vipGroup.coursesStartTime }} 至 {{ vipGroup.coursesEndTime }}</p> -->
  8. </template>
  9. </van-cell>
  10. </van-cell-group>
  11. <h2 class="van-block__title">{{ typeStatus ? '付费' : '赠送' }}课程排课</h2>
  12. <van-cell-group>
  13. <van-field
  14. :value="typeStatus ? courseType[vipGroup.courseType] : courseType[vipGroup.giveCourseType]"
  15. label="课程类型"
  16. :readonly="true"
  17. input-align="right"
  18. size="large"
  19. placeholder="请选择"
  20. />
  21. <van-field
  22. :value="typeStatus ? vipGroup.vipGroupCategoryNames : vipGroup.giveCategoryName"
  23. label="课程形式"
  24. v-if="courseTypeIsVip"
  25. :readonly="true"
  26. input-align="right"
  27. size="large"
  28. placeholder="请选择"
  29. />
  30. <van-field
  31. v-model="formName.subjectListName"
  32. @click="onGetSheetList('subjectList')"
  33. label="排课声部"
  34. :readonly="true"
  35. input-align="right"
  36. is-link
  37. size="large"
  38. placeholder="请选择"
  39. />
  40. <van-field
  41. v-model="formName.educationalTeacherName"
  42. @click="onGetSheetList('teacherList')"
  43. label="乐团主管"
  44. :readonly="true"
  45. input-align="right"
  46. is-link
  47. size="large"
  48. placeholder="请选择"
  49. />
  50. </van-cell-group>
  51. <template v-if="studentList.length > 0">
  52. <h2 class="van-block__title">上课学员</h2>
  53. <van-cell-group>
  54. <van-cell title-style="flex: 1 auto; color: #1A1A1A;" size="large" v-for="(item, index) in studentList" :key="index">
  55. <template #title>
  56. {{ item.username }} - {{ item.phone }}
  57. </template>
  58. <template #default>
  59. <span @click="onDelete('student', item)"><van-icon name="delete-o" size=".14rem" /> <span style="font-size: .12rem;">删除</span></span>
  60. </template>
  61. </van-cell>
  62. </van-cell-group>
  63. </template>
  64. <div class="addButton" @click="studentStatus = true">
  65. <van-icon name="plus" /> 添加学员
  66. </div>
  67. <h2 class="van-block__title">课时组成</h2>
  68. <van-cell-group>
  69. <van-field
  70. v-if="statusList.hasOnline && teachMode == -1"
  71. v-model="form.onlineClassesNums"
  72. @keyup="onClassKeyUp"
  73. label="线上课次数"
  74. input-align="right"
  75. size="large"
  76. placeholder="请输入次数"
  77. type="number"
  78. />
  79. <van-field
  80. v-if="statusList.hasOffline && teachMode == -1"
  81. v-model="form.offlineClassesNums"
  82. @keyup="onClassKeyUp('offLine')"
  83. label="线下课次数"
  84. input-align="right"
  85. size="large"
  86. placeholder="请输入次数"
  87. type="number"
  88. />
  89. <van-field
  90. v-if="tempOfflineNum > 0"
  91. v-model="formName.teacherSchoolName"
  92. @click="onGetSheetList('teacherSchool')"
  93. label="线下课地址"
  94. :readonly="true"
  95. input-align="right"
  96. is-link
  97. size="large"
  98. placeholder="请选择"
  99. />
  100. <van-field
  101. :value="(form.studentNum || 0) + '人'"
  102. label="班级人数"
  103. :readonly="true"
  104. input-align="right"
  105. size="large"
  106. />
  107. <van-field
  108. :value="(form.singleClassMinutes || 0) + '分钟'"
  109. label="单课时时长"
  110. :readonly="true"
  111. input-align="right"
  112. size="large"
  113. />
  114. </van-cell-group>
  115. <h2 class="van-block__title">课时安排</h2>
  116. <van-cell-group>
  117. <van-cell
  118. title="最早排课时间"
  119. :readonly="true"
  120. v-if="vipGroup.coursesStartTime"
  121. input-align="right"
  122. size="large"
  123. value-class="showText"
  124. :value="vipGroup.coursesStartTime"
  125. >
  126. </van-cell>
  127. <van-cell
  128. title="最晚排课时间"
  129. :readonly="true"
  130. v-if="vipGroup.coursesEndTime"
  131. input-align="right"
  132. size="large"
  133. value-class="showText"
  134. :value="vipGroup.coursesEndTime"
  135. >
  136. </van-cell>
  137. <!-- 为了处理,付费网管课程 -->
  138. <!-- {{ !courseTypeIsVip && isLimitNum && typeStatus ? false : true }} -->
  139. <van-field
  140. v-model="form.totalClassTime"
  141. label="课时总数"
  142. :readonly="!courseTypeIsVip && !isLimitNum && typeStatus ? false : true"
  143. input-align="right"
  144. size="large"
  145. placeholder="请输入排课课时数"
  146. >
  147. <template #extra v-if="form.totalClassTime">
  148. <span style="color: #808080; font-size: 16px;">课时</span>
  149. </template>
  150. </van-field>
  151. <van-field
  152. v-model="form.courseStart"
  153. label="排课开始时间"
  154. :readonly="true"
  155. input-align="right"
  156. is-link
  157. size="large"
  158. placeholder="请选择"
  159. @click="dataForm.status = true"
  160. />
  161. </van-cell-group>
  162. <van-cell-group :border="false" style="margin-top: .1rem">
  163. <van-cell
  164. title-class="title-time"
  165. v-for="(item, index) in scheduleList"
  166. :key="index"
  167. >
  168. <template slot="title">
  169. <span class="online">{{ item.type }}</span>
  170. <span class="week">{{ item.weekStr }}</span>
  171. <span class="timer">{{ item.startTime + "~" + item.endTime }}</span>
  172. </template>
  173. <template slot="default">
  174. <span @click="onDelete('class', item)"><van-icon name="delete-o" size=".14rem" /> <span style="font-size: .12rem;">删除</span></span>
  175. </template>
  176. </van-cell>
  177. </van-cell-group>
  178. <div class="addButton" @click="teachingStatus = true">
  179. <van-icon name="plus" /> 添加课时安排
  180. </div>
  181. <van-cell-group>
  182. <van-field
  183. label="排课列表"
  184. v-if="scheduleList.length > 0"
  185. disabled
  186. input-align="right"
  187. @click="onShowTimeTable"
  188. is-link
  189. size="large"
  190. />
  191. </van-cell-group>
  192. <div class="button-group">
  193. <van-button type="primary" @click="onSubmit" round size="large">确认</van-button>
  194. </div>
  195. <!-- 选择上课学员 -->
  196. <van-popup
  197. v-model="studentStatus"
  198. :lock-scroll="true"
  199. position="bottom"
  200. :style="{ height: '80%' }"
  201. class="studentChose"
  202. >
  203. <student-list
  204. @close="studentStatus = false"
  205. :studentList="studentList"
  206. :activityId="activityId"
  207. :studentNum="form.studentNum"
  208. :courseTypeIsVip="courseTypeIsVip"
  209. :typeStatus="typeStatus"
  210. :isMusicTheory="isMusicTheory"
  211. @submit="onSelectStudent" />
  212. </van-popup>
  213. <!-- 排课开始时间 -->
  214. <van-popup v-model="dataForm.status" position="bottom">
  215. <van-datetime-picker
  216. v-model="dataForm.currentDate"
  217. type="date"
  218. :min-date="dataForm.minDate"
  219. :max-date="dataForm.maxDate"
  220. :formatter="formatter"
  221. @cancel="dataForm.status = false"
  222. @confirm="onCurrentConfirm"
  223. />
  224. </van-popup>
  225. <!-- 课时安排 -->
  226. <van-popup v-model="teachingStatus" position="bottom">
  227. <course-modal :scheduleList="scheduleList" :singleClassMinutes="form.singleClassMinutes" @close="teachingStatus = false" />
  228. </van-popup>
  229. <van-popup v-model="sheetForm.sheetStatus" position="bottom">
  230. <van-picker
  231. :loading="sheetForm.loading"
  232. :default-index="sheetForm.index"
  233. :columns="sheetForm.columns"
  234. show-toolbar
  235. @cancel="sheetForm.sheetStatus = false"
  236. @confirm="onSheetConfirm"
  237. />
  238. </van-popup>
  239. <!-- 课表展示 -->
  240. <van-popup v-model="statusList.classTime" position="bottom" >
  241. <van-row>
  242. <van-col span="12">上课类型</van-col>
  243. <van-col span="12">上课时间</van-col>
  244. </van-row>
  245. <div class="tableContainer">
  246. <van-row v-for="(item, index) in timeTable" :key="index">
  247. <van-col span="12">
  248. {{ item.teachMode == "ONLINE" ? "线上" : "线下" }}
  249. </van-col>
  250. <van-col span="12">
  251. {{ item.classDate }} {{ item.startClassTimeStr }}
  252. </van-col>
  253. </van-row>
  254. </div>
  255. </van-popup>
  256. </div>
  257. </template>
  258. <script>
  259. import dayjs from 'dayjs'
  260. import studentList from './modal/studentList'
  261. import courseModal from './modal/course'
  262. import { courseType } from '../../constant'
  263. import { getActivityWaitCourseStudentNum, createVipGroup, createPracticeGroup } from './api'
  264. import { findSubSubjects, findEducationUsers, findVipSchoolByTeacher2 } from "@/api/teacher";
  265. export default {
  266. components: { studentList, courseModal },
  267. data() {
  268. const query = this.$route.query
  269. return {
  270. courseType,
  271. type: query.type,
  272. activityId: query.activityId,
  273. vipDetail: {},
  274. vipGroup: {},
  275. studentStatus: false,
  276. studentList: [],
  277. checkboxSelectIds: [],
  278. teachMode: null, // -1:所有;0:线上;1:线下"
  279. sheetForm: {
  280. // 上拉弹窗
  281. currentType: null, // 当前选择的类型
  282. sheetStatus: false,
  283. loading: true, // 加载数据
  284. index: 0, // 选中的索引值
  285. columns: [],
  286. },
  287. timeTable: [], // 生成的课表
  288. loadData: {
  289. // 下拉加载数据
  290. subjectList: [], // 声部列表
  291. teacherList: [],
  292. teacherSchool: [], // 线下课地址
  293. },
  294. tempOfflineNum: 0, // 临时存放线下课次数
  295. form: {
  296. vipGroupCategoryId: null,
  297. subjectIdList: null,
  298. educationalTeacherId: null,
  299. singleClassMinutes: null,
  300. onlineClassesNums: null,
  301. offlineClassesNums: null,
  302. totalClassTime: null, // 总课时数
  303. studentNum: null, // 每班人数
  304. courseStart: null, // 排课开始时间
  305. teacherSchoolId: null,
  306. vipGroupActivityId: query.activityId,
  307. },
  308. formName: {
  309. vipGroupCategoryId: null,
  310. subjectListName: null,
  311. subjectListIndex: 0, // 声部名称
  312. educationalTeacherName: null, // 乐团主管
  313. educationalTeacherIndex: 0,
  314. teacherSchoolName: null,
  315. teacherSchoolIndex: 0, // 线下课地址
  316. },
  317. statusList: {
  318. hasOnline: false, // 是否显示线上
  319. hasOffline: false, // 是否显示线下
  320. classTime: false, // 查看排课列表
  321. },
  322. scheduleList: [],
  323. // 排课弹窗
  324. teachingStatus: false, // 课时安排状态
  325. dataForm: {
  326. // 时间下拉框
  327. status: false,
  328. minDate: new Date(),
  329. maxDate: new Date(2035, 10, 1),
  330. currentDate: new Date(),
  331. },
  332. isMusicTheory: false,
  333. }
  334. },
  335. computed: {
  336. typeStatus() { // 是否是付费课程
  337. return this.type == 'pay' ? true : false
  338. },
  339. courseTypeIsVip() { // 目前只有两种课程,VIP 网管课,则可以这样判断
  340. const type = this.typeStatus ? this.vipGroup.courseType : this.vipGroup.giveCourseType
  341. return type == 'VIP' ? true : false
  342. },
  343. isLimitNum() { // 是否限制排课
  344. return this.vipGroup.minCourseNum > 0 ? true : false
  345. }
  346. },
  347. mounted() {
  348. this.__init()
  349. },
  350. methods: {
  351. async __init() {
  352. try {
  353. let res = await getActivityWaitCourseStudentNum({ activityId: this.activityId })
  354. this.vipDetail = res.data
  355. let vipGroup = res.data.vipGroupActivity
  356. vipGroup.coursesStartTime = vipGroup.coursesStartTime ? dayjs(vipGroup.coursesStartTime).format('YYYY-MM-DD') : null
  357. vipGroup.coursesEndTime = vipGroup.coursesEndTime ? dayjs(vipGroup.coursesEndTime).format('YYYY-MM-DD') : null
  358. this.vipGroup = vipGroup
  359. let form = this.form
  360. // 课程形式
  361. form.vipGroupCategoryId = this.typeStatus ? vipGroup.vipGroupCategoryIdList : vipGroup.giveCategoryId
  362. // 单课时长
  363. form.singleClassMinutes = this.typeStatus ? vipGroup.singleCourseTime : vipGroup.giveSingleCourseTime
  364. this.isMusicTheory = vipGroup.giveCategoryName === '乐理课'
  365. if(this.courseTypeIsVip) {
  366. // 每班人数
  367. form.studentNum = this.typeStatus ? vipGroup.vipGroupCategoryNum : vipGroup.giveCategoryNum
  368. this.statusList.hasOnline = this.typeStatus ? this.formatStatus('online', vipGroup.teachMode) : this.formatStatus('online', vipGroup.giveTeachMode)
  369. this.statusList.hasOffline = this.typeStatus ? this.formatStatus('offline', vipGroup.teachMode) : this.formatStatus('offline', vipGroup.giveTeachMode)
  370. } else {
  371. form.totalClassTime = null
  372. form.studentNum = 1
  373. this.statusList.hasOnLine = false
  374. this.statusList.hasOffLine = false
  375. }
  376. if(this.isLimitNum || !this.typeStatus) { // 是否限制了排课
  377. // 排课次数,活动排课没有范围一说,最大次数和最小次数必须一致
  378. form.totalClassTime = this.typeStatus ? vipGroup.minCourseNum : vipGroup.giveCourseNum
  379. }
  380. // 如果
  381. if(this.teachMode == 0) {
  382. form.onlineClassesNums = form.totalClassTime || 0
  383. form.offlineClassesNums = 0
  384. } else if(this.teachMode == 1) {
  385. form.onlineClassesNums = 0
  386. form.offlineClassesNums = form.totalClassTime || 0
  387. this.tempOfflineNum = form.totalClassTime || 0
  388. }
  389. } catch {
  390. //
  391. }
  392. },
  393. onGetSheetList(name) {
  394. // 获取科目列表
  395. let sheetForm = this.sheetForm;
  396. sheetForm.columns = [];
  397. sheetForm.sheetStatus = true;
  398. sheetForm.loading = true;
  399. sheetForm.currentType = name;
  400. sheetForm.index = 0;
  401. let arr = this.loadData[name];
  402. if (arr.length > 0) {
  403. sheetForm.columns = arr;
  404. sheetForm.index = this.formName[name + "Index"];
  405. sheetForm.loading = false;
  406. } else {
  407. this.onLoadingData(name);
  408. }
  409. },
  410. onLoadingData() {
  411. // 加载数据
  412. let sheetForm = this.sheetForm;
  413. if (sheetForm.currentType == "subjectList") {
  414. // 声部列表
  415. findSubSubjects().then((res) => {
  416. let result = res.data;
  417. if (result.code == 200 && result.data.length > 0) {
  418. let tempArr = [];
  419. result.data.forEach((item) => {
  420. item.value = item.id;
  421. item.text = item.name;
  422. tempArr.push(item);
  423. });
  424. this.loadData.subjectList = tempArr;
  425. sheetForm.columns = tempArr;
  426. sheetForm.loading = false;
  427. } else {
  428. this.$toast("暂无科目列表");
  429. sheetForm.loading = false;
  430. }
  431. });
  432. } else if (sheetForm.currentType == "teacherSchool") {
  433. // 教师教学点
  434. findVipSchoolByTeacher2().then((res) => {
  435. let result = res.data;
  436. if (result.code == 200 && result.data.length > 0) {
  437. let tempArr = [];
  438. result.data.forEach((item) => {
  439. item.value = item.id;
  440. item.text = item.name;
  441. tempArr.push(item);
  442. });
  443. this.loadData.teacherSchool = tempArr;
  444. sheetForm.columns = tempArr;
  445. sheetForm.loading = false;
  446. } else {
  447. this.$toast("暂无教学点");
  448. sheetForm.loading = false;
  449. }
  450. });
  451. } else if (sheetForm.currentType == "teacherList") {
  452. // 乐团主管
  453. findEducationUsers().then((res) => {
  454. let result = res.data;
  455. if (result.code == 200 && result.data.length > 0) {
  456. let tempArr = [];
  457. result.data.forEach((item) => {
  458. item.value = item.userId;
  459. item.text = item.userName;
  460. tempArr.push(item);
  461. });
  462. this.loadData.teacherList = tempArr;
  463. sheetForm.columns = tempArr;
  464. sheetForm.loading = false;
  465. } else {
  466. this.$toast("暂无乐团主管");
  467. sheetForm.loading = false;
  468. }
  469. });
  470. }
  471. },
  472. onSheetConfirm(value, index) {
  473. // 上拉弹窗
  474. let sheetForm = this.sheetForm,
  475. form = this.form,
  476. formName = this.formName
  477. if (sheetForm.currentType == "subjectList") {
  478. // 科目名称赋值
  479. form.subjectIdList = value.value;
  480. formName.subjectListName = value.text;
  481. formName.subjectListIndex = index;
  482. } else if (sheetForm.currentType == "teacherSchool") {
  483. // 线下课地址
  484. form.teacherSchoolId = value.value;
  485. formName.teacherSchoolName = value.text;
  486. formName.teacherSchoolIndex = index;
  487. } else if (sheetForm.currentType == "teacherList") {
  488. // 乐团主管
  489. form.educationalTeacherId = value.value;
  490. formName.educationalTeacherName = value.text;
  491. formName.educationalTeacherIndex = index;
  492. }
  493. sheetForm.sheetStatus = false;
  494. },
  495. async onSubmit() {
  496. // 次数限制是否可以继续创建
  497. let form = this.form;
  498. let statusList = this.statusList;
  499. if (!form.subjectIdList) {
  500. this.$toast("请选择排课声部");
  501. return false;
  502. }
  503. if (!form.educationalTeacherId) {
  504. this.$toast("请选择乐团主管");
  505. return;
  506. }
  507. if (this.checkboxSelectIds.length <= 0) {
  508. this.$toast("请选择上课学员");
  509. return;
  510. }
  511. if (this.isMusicTheory) {
  512. if (!(this.checkboxSelectIds.length >= 1 && this.checkboxSelectIds.length <= this.form.studentNum)) {
  513. this.$toast(`请选择1-${this.form.studentNum}名学生,当前选择${this.checkboxSelectIds.length}名`);
  514. return;
  515. }
  516. } else {
  517. if (this.checkboxSelectIds.length != this.form.studentNum) {
  518. this.$toast(`请选择学生${this.form.studentNum}名,当前选择${this.checkboxSelectIds.length}名`);
  519. return;
  520. }
  521. }
  522. let onlineClassesStatus = !form.onlineClassesNums && form.onlineClassesNums <= 0 ? true : false;
  523. let offlineClassesStatus = !form.offlineClassesNums && form.offlineClassesNums <= 0 ? true : false;
  524. if (statusList.hasOnline && onlineClassesStatus) {
  525. this.$toast("请输入线上课次数");
  526. return false;
  527. }
  528. if (statusList.hasOffline && !statusList.hasOnline) {
  529. if (offlineClassesStatus) {
  530. this.$toast("请输入线下课次数");
  531. return false;
  532. }
  533. // 判断是否有线下
  534. if (form.offlineClassesNums > 0 && !form.teacherSchoolId) {
  535. this.$toast("请选择线下课地址");
  536. return false;
  537. }
  538. }
  539. if (
  540. statusList.hasOffline &&
  541. statusList.hasOnline &&
  542. parseFloat(form.onlineClassesNums || 0) + parseFloat(form.offlineClassesNums || 0) != this.form.totalClassTime
  543. ) {
  544. this.$toast('线上课次数+线下课次数不等于总课次数')
  545. return
  546. }
  547. if (this.scheduleList.length <= 0) {
  548. this.$toast("课时安排不能为空");
  549. return false;
  550. }
  551. if (!this.checkCourseList()) {
  552. return;
  553. }
  554. // 排课
  555. this.setTimeTable();
  556. form.studentIdList = this.checkboxSelectIds.join(",");
  557. form.firstStudentId = this.studentList.length > 0 ? this.studentList[0].userId : null;
  558. form.onlineClassesNum = Number(form.onlineClassesNums);
  559. form.offlineClassesNum = Number(form.offlineClassesNums);
  560. let params = {
  561. courseSchedules: this.timeTable
  562. }
  563. if(this.courseTypeIsVip) {
  564. params.vipGroupApplyBaseInfo = form
  565. params.giveFlag = !this.typeStatus
  566. await this.onPayVip(params)
  567. } else {
  568. params.practiceGroupApplyBaseInfoDto = form
  569. params.practiceGroupApplyBaseInfoDto.studentId = form.studentIdList
  570. params.practiceGroupApplyBaseInfoDto.allCourseNum = form.totalClassTime
  571. params.practiceGroupApplyBaseInfoDto.subjectId = form.subjectIdList
  572. params.giveFlag = !this.typeStatus
  573. await this.onPayPractice(params)
  574. }
  575. },
  576. async onPayVip(params) {
  577. try {
  578. await createVipGroup(params)
  579. this.$toast("排课成功");
  580. setTimeout(() => {
  581. this.$router.back()
  582. }, 1000);
  583. } catch {
  584. //
  585. }
  586. },
  587. async onPayPractice(params) {
  588. try {
  589. await createPracticeGroup(params)
  590. this.$toast("排课成功");
  591. setTimeout(() => {
  592. this.$router.back()
  593. }, 1000);
  594. } catch {
  595. //
  596. }
  597. },
  598. onSelectStudent(items) {
  599. // 选中的数据
  600. const tempItems = items || []
  601. this.studentList = tempItems
  602. // if(tempItems.length <= 0) { // 判断是否有选择学员
  603. this.checkboxSelectIds = []
  604. // }
  605. tempItems.forEach(item => {
  606. this.checkboxSelectIds.push(item.userId)
  607. })
  608. this.studentStatus = false
  609. },
  610. onDelete(type, item) {
  611. if(type == 'student') {
  612. // 删除上课学员
  613. this.$dialog.confirm({
  614. title: '提示',
  615. message: '是否删除该学员?',
  616. confirmButtonText: '确定',
  617. confirmButtonColor: '#269a93',
  618. cancelButtonText: '取消'
  619. }).then(() => {
  620. let index = this.studentList.indexOf(item);
  621. if (index !== -1) {
  622. this.studentList.splice(index, 1);
  623. this.checkboxSelectIds.splice(index, 1);
  624. }
  625. })
  626. } else if(type == 'class') {
  627. // 删除上课学员
  628. this.$dialog.confirm({
  629. title: '提示',
  630. message: '是否删除该课时安排?',
  631. confirmButtonText: '确定',
  632. confirmButtonColor: '#269a93',
  633. cancelButtonText: '取消'
  634. }).then(() => {
  635. let index = this.scheduleList.indexOf(item);
  636. if (index !== -1) {
  637. this.scheduleList.splice(index, 1);
  638. }
  639. })
  640. }
  641. },
  642. onCurrentConfirm(value) {
  643. // 排课开始时间
  644. this.form.courseStart = dayjs(value).format('YYYY-MM-DD')
  645. this.dataForm.status = false;
  646. },
  647. onClassKeyUp(type) {
  648. // 线上课&线下课修改时
  649. if(this.teachMode != -1) return
  650. let form = this.form
  651. let onlineNum = form.onlineClassesNums
  652. let offLineNum = form.offlineClassesNums
  653. // 重置次数,不能
  654. if(parseInt(onlineNum || 0) + parseInt(offLineNum || 0) >= form.totalClassTime) {
  655. if(type == 'offLine') {
  656. let diffNum = form.totalClassTime - parseInt(onlineNum || 0)
  657. offLineNum = diffNum < 0 ? 0 : diffNum
  658. } else {
  659. let diffNum = form.totalClassTime - parseInt(offLineNum || 0)
  660. onlineNum = diffNum < 0 ? 0 : diffNum
  661. }
  662. }
  663. this.form.onlineClassesNums = onlineNum
  664. this.form.offlineClassesNums = offLineNum
  665. this.tempOfflineNum = offLineNum || 0
  666. },
  667. onShowTimeTable() {
  668. // 显示排课列表
  669. if (!this.checkCourseList()) {
  670. return;
  671. }
  672. const checkmMsg = this.checkTimeTable()
  673. if (checkmMsg) {
  674. this.$toast(checkmMsg)
  675. return
  676. }
  677. this.statusList.classTime = true;
  678. this.setTimeTable();
  679. },
  680. checkTimeTable() {
  681. let form = this.form,
  682. scheduleList = this.scheduleList;
  683. let online = parseInt(
  684. form.onlineClassesNums ? form.onlineClassesNums : 0
  685. );
  686. let offline = parseInt(
  687. form.offlineClassesNums ? form.offlineClassesNums : 0
  688. );
  689. // 网管课默认只有线上课次
  690. if(!this.courseTypeIsVip) {
  691. online = parseInt(form.totalClassTime || 0)
  692. }
  693. // let totalCount = Number(online) + Number(offline)
  694. let hasOnlineSchedule = false,
  695. hasOfflineSchedule = false
  696. for (let i = 0; i < scheduleList.length; i++) {
  697. const item = scheduleList[i];
  698. if (item.type == '线上') {
  699. hasOnlineSchedule = true;
  700. }
  701. if (item.type == '线下') {
  702. hasOfflineSchedule = true;
  703. }
  704. if (hasOnlineSchedule && hasOfflineSchedule) {
  705. break;
  706. }
  707. }
  708. if (online > 0 && !hasOnlineSchedule) {
  709. return '请添加线上课时安排';
  710. }
  711. if (offline > 0 && !hasOfflineSchedule) {
  712. return '请添加线下课时安排';
  713. }
  714. console.log({...form}, online, offline, hasOnlineSchedule, hasOfflineSchedule)
  715. },
  716. setTimeTable() {
  717. if (!this.checkCourseList(false)) {
  718. return;
  719. }
  720. // 重置排课列表
  721. this.timeTable = [];
  722. let form = this.form,
  723. scheduleList = this.scheduleList;
  724. // 拿到线上课数与线下课数 以及
  725. let online = parseInt(
  726. form.onlineClassesNums ? form.onlineClassesNums : 0
  727. );
  728. let offline = parseInt(
  729. form.offlineClassesNums ? form.offlineClassesNums : 0
  730. );
  731. // 网管课默认只有线上课次
  732. if(!this.courseTypeIsVip) {
  733. online = parseInt(form.totalClassTime || 0)
  734. }
  735. // 判断是否有课程安排
  736. if (scheduleList.length <= 0) {
  737. return;
  738. }
  739. let totalCount = Number(online) + Number(offline);
  740. let tempCourseStart = form.courseStart.replace(/-/gi, "/");
  741. let dateOperation = new Date(tempCourseStart);
  742. let forMark = 0;
  743. while (totalCount && totalCount > 0) {
  744. for (let i = 0; i < scheduleList.length; i++) {
  745. if (online == 0 && offline == 0) break;
  746. let num = scheduleList[i].weekIndex - dateOperation.getDay();
  747. // 如果是同一天一个周期会出现排课都排到一天
  748. if (forMark > 0 && num == 0 && i == 0) {
  749. num = num + 7;
  750. }
  751. if (num < 0) {
  752. // 如果为负数则为下周
  753. num = num + 7;
  754. }
  755. let dataStr = this.getThinkDate(dateOperation, num);
  756. // 判断是否大于当前时间
  757. let nowGetTime = new Date().getTime();
  758. let courseTime = new Date(dataStr.replace(/-/gi, "/") +" " + scheduleList[i].startTime + ":00").getTime();
  759. if (nowGetTime < courseTime) {
  760. let tempArr = {
  761. classDate: dataStr,
  762. startClassTimeStr: scheduleList[i].startTime,
  763. endClassTimeStr: scheduleList[i].endTime,
  764. };
  765. // console.log(scheduleList[i].type, online, offline)
  766. if (scheduleList[i].type == "线上" && online > 0) {
  767. tempArr.teachMode = "ONLINE";
  768. this.timeTable.push(tempArr);
  769. online--;
  770. totalCount--;
  771. } else if (scheduleList[i].type == "线下" && offline > 0) {
  772. tempArr.teachMode = "OFFLINE";
  773. this.timeTable.push(tempArr);
  774. offline--;
  775. totalCount--;
  776. }
  777. }
  778. }
  779. // 加一周
  780. if (scheduleList.length == 1) {
  781. dateOperation.setDate(dateOperation.getDate() + 7);
  782. } else if (
  783. scheduleList.every((item) => item.weekStr === scheduleList[0].weekStr)
  784. ) {
  785. // 标记循环次数(标记判断课程安排是不是同一天)
  786. forMark++;
  787. }
  788. }
  789. this.timeTable.sort((a, b) => {
  790. let aStr = dayjs(dayjs(a.classDate).format("YYYY-MM-DD") + " " + a.startClassTimeStr + ":00").valueOf();
  791. let bStr = dayjs(dayjs(b.classDate).format("YYYY-MM-DD") + " " + b.startClassTimeStr + ":00").valueOf();
  792. return aStr - bStr;
  793. });
  794. },
  795. getThinkDate(date, num) {
  796. let Stamp = date;
  797. Stamp.setDate(date.getDate() + num); // 获取当前月数的第几天
  798. return dayjs(Stamp).format('YYYY-MM-DD')
  799. },
  800. checkCourseList(isShowToast = true) {
  801. let form = this.form;
  802. let scheduleList = this.scheduleList || [];
  803. let hasOnLine = false; // 是否有线上课时安排
  804. let hasOffLine = false;
  805. scheduleList.forEach((item) => {
  806. if (item.type == "线上") {
  807. hasOnLine = true;
  808. }
  809. if (item.type == "线下") {
  810. hasOffLine = true;
  811. }
  812. });
  813. let statusList = this.statusList;
  814. let onlineClassesStatus = !form.onlineClassesNums && form.onlineClassesNums <= 0 ? true : false;
  815. let offlineClassesStatus = !form.offlineClassesNums && form.offlineClassesNums <= 0 ? true : false;
  816. if (statusList.hasOnline) {
  817. if (onlineClassesStatus) {
  818. if (isShowToast) {
  819. this.$toast("请输入线上课次数");
  820. }
  821. return false;
  822. }
  823. if (!onlineClassesStatus && !hasOnLine && form.onlineClassesNums > 0) {
  824. if (isShowToast) {
  825. this.$toast("课时安排缺少线上课类型");
  826. }
  827. return false;
  828. }
  829. }
  830. if (statusList.hasOffline) {
  831. if (offlineClassesStatus) {
  832. if (isShowToast) {
  833. this.$toast("请输入线下课次数");
  834. }
  835. return false;
  836. }
  837. if (
  838. !offlineClassesStatus &&
  839. !hasOffLine &&
  840. form.offlineClassesNums > 0
  841. ) {
  842. if (isShowToast) {
  843. this.$toast("课时安排缺少线下课类型");
  844. }
  845. return false;
  846. }
  847. }
  848. return true;
  849. },
  850. formatStatus(type, teachMode) {
  851. // -1:所有;0:线上;1:线下
  852. this.teachMode = teachMode
  853. if(type == 'online' && teachMode == 0) {
  854. return true
  855. } else if(type == 'offline' && teachMode == 1) {
  856. return true
  857. } else if(teachMode == -1) {
  858. return true
  859. } else {
  860. return false
  861. }
  862. },
  863. formatter(type, value) {
  864. if (type === "year") {
  865. return `${value}年`;
  866. } else if (type === "month") {
  867. return `${value}月`;
  868. } else if (type === "day") {
  869. return `${value}日`;
  870. }
  871. return value;
  872. },
  873. }
  874. }
  875. </script>
  876. <style lang="less" scoped>
  877. @import url("../../assets/commonLess/variable.less");
  878. .program {
  879. background-color: #F5F5F5;
  880. min-height: 100vh;
  881. overflow: hidden;
  882. }
  883. .van-cell-group--inset {
  884. margin: .12rem .12rem 0;
  885. overflow: hidden;
  886. border-radius: 8px;
  887. .titleContent {
  888. padding: .14rem .16rem;
  889. }
  890. .titleStyle {
  891. font-size: .2rem;
  892. color: #333333;
  893. font-size: 500;
  894. }
  895. .labelStyle {
  896. padding-top: .08rem;
  897. color: #666666;
  898. font-size: .13rem;
  899. line-height: .2rem;
  900. }
  901. }
  902. .van-row {
  903. line-height: 0.4rem;
  904. border-top: 1px solid #edeef0;
  905. text-align: center;
  906. font-size: 0.14rem;
  907. &:first-child {
  908. border-top: 0;
  909. background: #edeef0;
  910. color: #444;
  911. font-size: 0.15rem;
  912. }
  913. }
  914. .tableContainer {
  915. max-height: 2.44rem;
  916. overflow: auto;
  917. .van-row {
  918. color: #444;
  919. &:first-child {
  920. border-top: 0;
  921. background: #fff;
  922. font-size: 0.14rem;
  923. }
  924. }
  925. }
  926. .van-block__title {
  927. padding: .12rem .14rem .06rem;
  928. color: #808080;
  929. font-size: .14rem;
  930. line-height: .2rem;
  931. }
  932. .button-group {
  933. margin: 0.3rem 0.26rem 0.2rem;
  934. .van-button--primary {
  935. background: @mColor;
  936. border-color: @mColor;
  937. font-size: 0.18rem;
  938. }
  939. }
  940. .title-time {
  941. display: flex;
  942. align-items: center;
  943. flex: 1 auto;
  944. color: #1A1A1A;
  945. font-size: .16rem;
  946. .week {
  947. padding-left: 0.4rem;
  948. padding-right: 0.15rem;
  949. }
  950. }
  951. /deep/.studentChose {
  952. border-radius: .1rem .1rem 0px 0px;
  953. overflow: auto;
  954. background: #F5F5F5;
  955. }
  956. /deep/.van-field__label {
  957. color: #1A1A1A;
  958. }
  959. /deep/.van-field__control, .showText {
  960. font-size: 16px;
  961. color: #808080;
  962. }
  963. .addButton {
  964. margin: .1rem .28rem;
  965. border: 1px dashed #CFCFCF;
  966. line-height: .42rem;
  967. text-align: center;
  968. background: #FBFBFB;
  969. color: #666666;
  970. font-size: .14rem;
  971. border-radius: .05rem;
  972. }
  973. </style>