ArrangeWork.vue 13 KB

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