ArrangeWork.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. <template>
  2. <div class="arrangeWork">
  3. <m-header v-if="headerStatus" />
  4. <van-cell
  5. :title="classGroupName"
  6. title-style="font-size: .18rem; color: #333333;"
  7. >
  8. <template #extra>
  9. <van-tag type="primary" plain style="background-color: #F1FCF9"
  10. >课后训练</van-tag
  11. >
  12. </template>
  13. </van-cell>
  14. <van-cell
  15. class="endTime"
  16. readonly
  17. is-link
  18. title-style="font-size: .16rem; color: #333333;"
  19. @click="studentStatus = true"
  20. >
  21. <template #title>
  22. <span style="padding-right: .3rem"
  23. >学员共<i style="font-style: normal; color: #01C1B5">{{
  24. params.studentCount
  25. }}</i
  26. >人</span
  27. >
  28. <span
  29. >会员
  30. <i style="font-style: normal; color: #FF802C">{{
  31. params.studentMemberCount
  32. }}</i
  33. >人</span
  34. >
  35. </template>
  36. </van-cell>
  37. <div class="container">
  38. <div class="formGroup">
  39. <div class="dot"></div>
  40. <div class="formTitle">训练标题</div>
  41. <van-field
  42. v-model="title"
  43. type="text"
  44. maxlength="25"
  45. show-word-limit
  46. placeholder="请输入训练标题"
  47. />
  48. </div>
  49. <div class="formGroup">
  50. <div class="dot"></div>
  51. <div class="formTitle">训练内容</div>
  52. <van-field
  53. rows="4"
  54. v-model="content"
  55. maxlength="600"
  56. show-word-limit
  57. type="textarea"
  58. placeholder="请输入训练内容"
  59. />
  60. </div>
  61. </div>
  62. <van-cell
  63. class="endTime"
  64. style="padding: 0.12rem 0.21rem;"
  65. title="训练提交截止时间"
  66. @click="onEndTime"
  67. is-link
  68. readonly
  69. placeholder="请选择截止时间"
  70. >
  71. <template #title>
  72. <div class="dot"></div>
  73. 训练提交截止时间
  74. </template>
  75. <template #default>
  76. {{ dateSection.showStartDate }}
  77. </template>
  78. </van-cell>
  79. <div class="accompanyHeader">
  80. 云教练曲目选择<span>(若作业内容非云教练曲目则无需选择)</span>
  81. </div>
  82. <van-tabs v-model="tabActive" color="#01C1B5">
  83. <van-tab
  84. v-for="(item, i) in params.subjectList"
  85. :title="item.subjectName"
  86. :name="item.id"
  87. :key="i"
  88. class="van-hairline--bottom"
  89. >
  90. <van-cell
  91. class="endTime"
  92. v-for="(music, index) in item.musicScoreIdList"
  93. :key="index"
  94. style="margin-top: 0;padding: 0.12rem 0.21rem;"
  95. title="训练曲目"
  96. @click="onSelectAccompany(item, index)"
  97. readonly
  98. is-link
  99. placeholder="请选择训练曲目"
  100. >
  101. <template #title>
  102. <div class="dot"></div>
  103. 训练曲目
  104. </template>
  105. <template #default>
  106. <template v-if="music.name">
  107. {{ music.name }}
  108. </template>
  109. <span v-else style="color: #808080;">请选择</span>
  110. </template>
  111. <template #right-icon>
  112. <span
  113. v-if="music.name"
  114. @click.stop="delAccompany(item.musicScoreIdList, index)"
  115. style="color: #999999; font-size: .12rem; padding-left: .12rem"
  116. ><van-icon size="14" name="delete-o" />删除</span
  117. >
  118. </template>
  119. <template #extra>
  120. <!-- <span><van-icon name="delete-o" />删除</span> -->
  121. <span
  122. style="height: 24px;font-size: 16px;line-height: 24px;color: #DADADA !important;"
  123. ><van-icon name="arrow"
  124. /></span>
  125. </template>
  126. </van-cell>
  127. <div
  128. class="addAccompaniment"
  129. v-if="item.musicScoreIdList.length < 3"
  130. @click="addCloud(item)"
  131. >
  132. <van-icon name="plus" size="16px" />增加云教练训练曲目
  133. </div>
  134. </van-tab>
  135. </van-tabs>
  136. <div class="button-group">
  137. <van-button type="primary" round size="large" @click="onSubmit"
  138. >确定</van-button
  139. >
  140. </div>
  141. <!-- 日期开始弹窗 -->
  142. <van-popup position="bottom" v-model="dateSection.status">
  143. <van-datetime-picker
  144. v-model="dateSection.currentDate"
  145. type="date"
  146. :min-date="dateSection.minDate"
  147. :max-date="dateSection.maxDate"
  148. :formatter="formatter"
  149. @confirm="confirmStartTime()"
  150. @cancel="dateSection.status = false"
  151. />
  152. </van-popup>
  153. <van-popup
  154. position="bottom"
  155. v-model="accompanimentStatus"
  156. :style="{ height: '100%' }"
  157. style=" border-radius: 0; overflow: inherit;"
  158. >
  159. <!-- <van-sticky>
  160. <m-header name="作业曲目" :backUrl="backUrl" />
  161. </van-sticky> -->
  162. <!-- <accompaniment-modal @onSelectMusic="onSelectMusic" ref="accompaniment" style="margin-bottom: 0.8rem;" :searchSubjectId="tabActive" /> -->
  163. <!-- style="margin-bottom: 0.8rem;" -->
  164. <workModel
  165. @onSelectMusic="onSelectMusic"
  166. @close="accompanimentStatus = false"
  167. ref="accompaniment"
  168. :searchSubjectId="tabActive"
  169. />
  170. <!-- <div class="button-group-popup">
  171. <span class="btn" @click="accompanimentStatus = false">关闭</span>
  172. </div> -->
  173. </van-popup>
  174. <van-popup
  175. v-model="studentStatus"
  176. :lock-scroll="true"
  177. position="bottom"
  178. :style="{ height: '180%' }"
  179. >
  180. <!-- <van-sticky>
  181. <m-header name="学员列表" :backUrl="backUrlStudent" />
  182. </van-sticky> -->
  183. <student-list-model
  184. :dataList="dataList"
  185. style="margin-bottom: 0.8rem;"
  186. @close="studentStatus = false"
  187. :dataSubjectList="dataSubjectList"
  188. ></student-list-model>
  189. </van-popup>
  190. </div>
  191. </template>
  192. <script>
  193. import MHeader from "@/components/MHeader";
  194. import { browser, _throttle } from "@/common/common";
  195. import dayjs from "dayjs";
  196. import { addHomeWork } from "@/api/audition";
  197. import { getCourseStudents } from "@/api/teacher";
  198. // import AccompanimentModal from './modal/accompanimentModal'
  199. import workModel from "./modal/workModel";
  200. import StudentListModel from "./modal/studentList";
  201. import cleanDeep from "clean-deep";
  202. import deepClone from "@/helpers/deep-clone";
  203. import { postMessage, listenerMessage } from "@/helpers/native-message";
  204. export default {
  205. name: "teacherList",
  206. components: { MHeader, workModel, StudentListModel },
  207. data() {
  208. let tempDate = new Date(); // 默认显示T+3
  209. tempDate.setDate(tempDate.getDate() + 3);
  210. let query = this.$route.query;
  211. return {
  212. headerStatus: true,
  213. backUrl: {
  214. status: true,
  215. callBack: () => {
  216. this.accompanimentStatus = false;
  217. },
  218. },
  219. backUrlStudent: {
  220. status: true,
  221. callBack: () => {
  222. this.studentStatus = false;
  223. },
  224. },
  225. classGroupName: query.classGroupName,
  226. courseId: query.courseId || query.id,
  227. dateSection: {
  228. status: false,
  229. minDate: new Date(),
  230. maxDate: new Date(2025, 10, 1),
  231. currentDate: tempDate,
  232. showStartDate: dayjs(tempDate).format("YYYY年MM月DD日"),
  233. musicScoreId: null,
  234. musicScoreName: null,
  235. },
  236. title: "",
  237. content: "", // 课程编号
  238. expiryDate: null, // 作业截止日期
  239. accompanimentStatus: false, // 伴奏弹窗
  240. tabActive: 0,
  241. tabOriginActive: 0,
  242. tabActiveList: {}, // 选中当前信息
  243. tabActiveIndex: 0,
  244. params: {
  245. studentCount: 0, // 学员总数
  246. studentMemberCount: 0, // 学员会员数
  247. subjectIdList: [],
  248. subjectList: [],
  249. },
  250. dataList: [],
  251. dataSubjectList: [],
  252. studentStatus: false,
  253. };
  254. },
  255. async mounted() {
  256. let params = this.$route.query;
  257. if (params.Authorization) {
  258. localStorage.setItem("Authorization", decodeURI(params.Authorization));
  259. localStorage.setItem("userInfo", decodeURI(params.Authorization));
  260. }
  261. document.title = "布置训练";
  262. if (browser().android || browser().iPhone) {
  263. this.headerStatus = false;
  264. }
  265. // 获取课程学员【根据接口初始化声部列表】
  266. await getCourseStudents({ courseScheduleId: this.courseId }).then((res) => {
  267. const result = res.data;
  268. if (result.code != 200) {
  269. return;
  270. }
  271. const tempData = result.data || [];
  272. let params = {
  273. studentCount: tempData.length, // 学员总数
  274. studentMemberCount: 0, // 学员会员数
  275. subjectIdList: [],
  276. subjectList: [],
  277. };
  278. tempData.forEach((item) => {
  279. // 判断当前学员是否有会员
  280. if (item.memberRankSettingId) {
  281. params.studentMemberCount++;
  282. }
  283. if (!params.subjectIdList.includes(item.subjectIdList || -1)) {
  284. params.subjectIdList.push(item.subjectIdList || -1);
  285. params.subjectList.push({
  286. id: item.subjectIdList || -1,
  287. subjectName: item.subjectName || "无声部",
  288. userIdList: [item.userId],
  289. musicScoreIdList: [
  290. {
  291. id: null,
  292. name: null,
  293. songPart: null,
  294. },
  295. ], // 默认加一个空的,做占位
  296. });
  297. } else {
  298. params.subjectList.forEach((subject) => {
  299. if (subject.id == item.subjectIdList) {
  300. subject.userIdList.push(item.userId);
  301. }
  302. if (!item.subjectIdList && subject.id == -1) {
  303. subject.userIdList.push(item.userId);
  304. }
  305. });
  306. }
  307. if (!item.subjectIdList) {
  308. item.subjectIdList = -1;
  309. }
  310. });
  311. this.dataList = tempData;
  312. // 默认选中第1条数据
  313. this.tabActive = params.subjectIdList[0];
  314. this.tabOriginActive = params.subjectIdList[0];
  315. this.dataSubjectList = deepClone(params.subjectList);
  316. this.params = params;
  317. });
  318. // 获取当前课程的作业列表
  319. let _this = this;
  320. listenerMessage("getAccompany", (res) => {
  321. if (res && res.content) {
  322. _this.tabActiveList.musicScoreIdList[this.tabActiveIndex] = {
  323. id: res.content.songId,
  324. name: res.content.songName,
  325. songPart: res.content.songPart,
  326. };
  327. _this.$forceUpdate();
  328. }
  329. });
  330. },
  331. methods: {
  332. onSelectAccompany(item, index) {
  333. // this.accompanimentStatus = true
  334. // 唤起弹窗
  335. postMessage({
  336. api: "openAccompany",
  337. content: {
  338. subjectId: item.id,
  339. },
  340. });
  341. this.tabActiveList = item;
  342. this.tabActiveIndex = index;
  343. },
  344. delAccompany(music, index) {
  345. if (music.length == 1) {
  346. music[0] = {
  347. id: null,
  348. name: null,
  349. };
  350. this.$forceUpdate();
  351. } else {
  352. music.splice(index, 1);
  353. }
  354. },
  355. addCloud(item) {
  356. if (item.musicScoreIdList.length < 3) {
  357. item.musicScoreIdList.push("");
  358. }
  359. },
  360. formatter(type, val) {
  361. if (type === "year") {
  362. return `${val}年`;
  363. } else if (type === "month") {
  364. return `${val}月`;
  365. } else if (type == "day") {
  366. return `${val}日`;
  367. }
  368. return val;
  369. },
  370. onSelectMusic(value) {
  371. this.tabActiveList.musicScoreIdList[this.tabActiveIndex] = {
  372. id: value.examSongId,
  373. name: value.name,
  374. };
  375. this.accompanimentStatus = false;
  376. },
  377. confirmStartTime() {
  378. this.dateSection.showStartDate = dayjs(
  379. this.dateSection.currentDate
  380. ).format("YYYY年MM月DD日");
  381. this.dateSection.status = false;
  382. },
  383. onEndTime() {
  384. this.dateSection.status = true;
  385. },
  386. onSubmit: _throttle(function(type) {
  387. if (!this.title) {
  388. this.$toast("请输入训练标题");
  389. return;
  390. }
  391. if (!this.content) {
  392. this.$toast("请输入训练内容");
  393. return;
  394. }
  395. let tempSubjectList = this.params.subjectList;
  396. let musicScoreSubjectDto = [];
  397. let notAccompanySong = []; // 用于判断没有设置训练曲目的数据
  398. let subjectLength = this.params.subjectIdList.length;
  399. tempSubjectList.forEach((subject) => {
  400. let scoreIdList = [];
  401. let scoreList = [];
  402. subject.musicScoreIdList.forEach((music) => {
  403. if (music.id) {
  404. scoreIdList.push(music.id);
  405. scoreList.push({
  406. musicScoreId: music.id,
  407. partIndex: music.songPart,
  408. });
  409. }
  410. });
  411. if (scoreIdList.length <= 0) {
  412. notAccompanySong.push(subject.subjectName);
  413. }
  414. musicScoreSubjectDto.push({
  415. musicScoreIdList: scoreIdList,
  416. userIdList: subject.userIdList,
  417. musicScoreHomeworkDtoList: scoreList,
  418. });
  419. });
  420. if (
  421. notAccompanySong.length - subjectLength <= 0 &&
  422. notAccompanySong != 0 &&
  423. type[0] != 1
  424. ) {
  425. // console.log('选择曲目')
  426. this.$dialog
  427. .confirm({
  428. message:
  429. notAccompanySong.join(",") +
  430. "声部未选择云教练训练曲目,是否继续布置作业?",
  431. confirmButtonColor: "#01C1B5",
  432. })
  433. .then(() => {
  434. // on confirm
  435. this.onSubmit(1);
  436. })
  437. .catch(() => {
  438. // on cancel
  439. });
  440. return;
  441. }
  442. // this.$toast.loading({
  443. // message: '加载中...',
  444. // duration: 10000,
  445. // forbidClick: true,
  446. // loadingType: 'spinner',
  447. // })
  448. let params = {
  449. title: this.title,
  450. content: this.content,
  451. courseScheduleId: this.courseId,
  452. expiryDate: dayjs(this.dateSection.currentDate).format("YYYY-MM-DD"),
  453. musicScoreSubjectDto: musicScoreSubjectDto,
  454. };
  455. console.log(params, "params");
  456. addHomeWork(cleanDeep({ ...params })).then((res) => {
  457. let result = res.data;
  458. this.$toast.clear();
  459. if (result.code == 200) {
  460. this.$toast("作业布置成功");
  461. setTimeout(() => {
  462. let query = this.$route.query;
  463. const path =
  464. query.isNewJoin == 1
  465. ? "/afterClassEvaluateDetail"
  466. : "/courseEvaluation";
  467. this.$router.replace({
  468. path,
  469. query: {
  470. id: query.id,
  471. reviewId: query.reviewId,
  472. isInside: query.isInside,
  473. work: 1,
  474. },
  475. });
  476. }, 500);
  477. } else {
  478. this.$toast(result.msg);
  479. }
  480. });
  481. }, 500),
  482. },
  483. };
  484. </script>
  485. <style lang="less" scoped>
  486. @import url("../../assets/commonLess/variable.less");
  487. .arrangeWork {
  488. min-height: 100vh;
  489. overflow-y: auto;
  490. overflow-x: hidden;
  491. background-color: #f3f4f8;
  492. }
  493. /deep/.van-cell {
  494. font-size: 0.14rem;
  495. padding: 0.12rem 0.16rem;
  496. line-height: 0.24rem;
  497. }
  498. .arrowDown {
  499. display: inline-block;
  500. margin-left: 0.1rem;
  501. width: 0.1rem;
  502. height: 0.07rem;
  503. background: url("../../assets/images/audition/arrow_down.png") no-repeat
  504. center center;
  505. background-size: 100%;
  506. }
  507. .container {
  508. .formGroup {
  509. position: relative;
  510. margin-top: 0.1rem;
  511. background: #ffffff;
  512. }
  513. .formTitle {
  514. padding: 0.12rem 0.21rem 0;
  515. font-size: 0.16rem;
  516. color: #333333;
  517. font-weight: 500;
  518. }
  519. }
  520. .endTime {
  521. margin-top: 0.1rem;
  522. .van-cell__title {
  523. font-size: 0.16rem;
  524. color: #1a1a1a;
  525. }
  526. /deep/.van-cell__value {
  527. // width: 30%;
  528. justify-content: flex-end;
  529. text-align: right;
  530. font-size: 0.16rem;
  531. color: #1a1a1a;
  532. display: flex;
  533. align-items: center;
  534. }
  535. }
  536. .button-group {
  537. margin: 0.3rem 0.26rem 0.2rem;
  538. .van-button--primary {
  539. background: @mColor;
  540. border: 1px solid @mColor;
  541. font-size: 0.18rem;
  542. }
  543. }
  544. .dot {
  545. width: 4px;
  546. height: 0.17rem;
  547. background: #01c1b5;
  548. border-radius: 3px;
  549. position: absolute;
  550. z-index: 98;
  551. top: 0.15rem;
  552. left: 0.12rem;
  553. }
  554. /deep/.van-tab {
  555. font-size: 16px;
  556. }
  557. /deep/.van-popup--bottom {
  558. border-radius: 0px 0px 0px 0px !important;
  559. overflow: auto !important;
  560. }
  561. .accompanyHeader {
  562. font-size: 0.14rem;
  563. padding: 0.16rem 0.08rem 0.14rem;
  564. color: #333;
  565. font-weight: 500;
  566. span {
  567. color: #808080;
  568. }
  569. }
  570. .addAccompaniment {
  571. width: 80%;
  572. height: 0.42rem;
  573. line-height: 0.42rem;
  574. text-align: center;
  575. margin: 0.1rem auto 0;
  576. border: 1px dashed #ccc;
  577. background: #fbfbfb;
  578. font-size: 0.14rem;
  579. color: #666666;
  580. }
  581. </style>