AppDetail.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. <template>
  2. <div class="appDetail">
  3. <!-- <m-header v-if="headerStatus" /> -->
  4. <van-cell-group>
  5. <!-- <van-field v-model="form.paymentOrderNo" disabled label="订单编号" /> -->
  6. <van-field v-model="form.examBaseName" disabled label="考级名称" />
  7. <van-cell disabled title="缴费状态">
  8. <div v-if="form.status">
  9. <p class="noPass" v-if="form.status === 'PAY_WAIT'">未缴费</p>
  10. <p class="pass" v-else>已缴费</p>
  11. </div>
  12. </van-cell>
  13. <van-field v-model="form.examTime" disabled label="预计考试日期" />
  14. <van-cell title="专业等级" >
  15. {{ form.subjectName ? form.subjectName : '通用' }}<span v-if="form.level">({{ form.level | formatLevel }})</span>
  16. </van-cell>
  17. <van-cell v-for="(item, index) in practiceInfo" :key="index" :title="`练习曲${numberToCN(index)}`" @click="onOpen('practice', index)" :is-link="form.practiceSongIdList ? false : true" >
  18. {{ item.songName }} {{ item.songAuthor ? '-' + item.songAuthor : item.songAuthor }}
  19. </van-cell>
  20. <van-cell v-for="(item, index) in performInfo" :key="index" :title="`演奏曲${numberToCN(index)}`" @click="onOpen('perform', index)" :is-link="form.performSongIdList ? false : true" >
  21. {{ item.songName }} {{ item.songAuthor ? '-' + item.songAuthor : item.songAuthor }}
  22. </van-cell>
  23. <van-field v-model="form.name" disabled label="考级证书" >
  24. <template #input>
  25. <van-uploader
  26. name="certificate"
  27. :before-read="beforeRead"
  28. :before-delete="beforeDelete"
  29. :after-read="afterRead"
  30. accept="image/*"
  31. :disabled="!form.editStatus"
  32. :deletable="form.editStatus"
  33. v-model="uploadCertificate"
  34. :max-count="1" />
  35. </template>
  36. </van-field>
  37. <van-cell disabled title="乐理等级" >
  38. {{ form.examMusicTheoryLevel | formatLevel }}
  39. </van-cell>
  40. <van-field v-model="form.name" disabled label="乐理证书" >
  41. <template #input>
  42. <van-uploader
  43. name="certificate2"
  44. :before-read="beforeRead"
  45. :before-delete="beforeDelete"
  46. :after-read="afterRead"
  47. v-model="uploadCertificate2"
  48. accept="image/*"
  49. :disabled="!form.editStatus"
  50. :deletable="form.editStatus"
  51. :max-count="1" />
  52. </template>
  53. </van-field>
  54. </van-cell-group>
  55. <van-cell-group class="memos" v-if="form.status != 'AUDIT_REJECT' && !form.memo">
  56. <van-cell disabled title="报名审核" v-if="form.status == 'AUDIT_REJECT'">
  57. <div v-if="form.status">
  58. <p class="pass" v-if="form.status === 'AUDIT_PASS'">已通过</p>
  59. <p v-else-if="form.status === 'AUDIT_WAIT'">等待审核</p>
  60. <p class="noPass" v-else>未通过</p>
  61. </div>
  62. </van-cell>
  63. <van-cell title="备注" v-if="form.memo">
  64. {{ form.memo }}
  65. </van-cell>
  66. </van-cell-group>
  67. <van-button type="primary" v-if="form.editStatus" @click="onSubmit" round block>重新提交</van-button>
  68. <van-popup class="van-popup-song" v-model="songUpload.songStatus" :close-on-click-overlay="false">
  69. <div class="song-popup">
  70. <div class="title">自定义曲目</div>
  71. <van-field name="songName" v-model="songUpload.songName" :disabled="!form.editStatus" label="曲名" placeholder="请输入曲名" >
  72. <template #label><i style="color: #ee0a24">*</i>曲名</template>
  73. </van-field>
  74. <van-field name="songAuthor" :disabled="!form.editStatus" v-model="songUpload.songAuthor" label="作者" placeholder="请输入作者" >
  75. <template #label><i style="color: #ffffff">*</i>作者</template>
  76. </van-field>
  77. <van-field readonly clearable >
  78. <template #input>
  79. <van-uploader
  80. v-if="songUpload.indexName == 'practice'"
  81. :name="songUpload.indexName + '-' + songUpload.index"
  82. :before-read="beforeRead"
  83. :before-delete="beforeDelete"
  84. :after-read="afterRead"
  85. v-model.trim="practiceUpload[songUpload.index]"
  86. multiple
  87. :disabled="!form.editStatus"
  88. :deletable="form.editStatus"
  89. accept="image/*"
  90. :max-count="5" >
  91. </van-uploader>
  92. <van-uploader
  93. v-if="songUpload.indexName == 'perform'"
  94. :name="songUpload.indexName + '-' + songUpload.index"
  95. :before-read="beforeRead"
  96. :before-delete="beforeDelete"
  97. :after-read="afterRead"
  98. v-model.trim="performUpload[songUpload.index]"
  99. multiple
  100. :disabled="!form.editStatus"
  101. :deletable="form.editStatus"
  102. accept="image/*"
  103. :max-count="5" >
  104. </van-uploader>
  105. </template>
  106. </van-field>
  107. <p class="song-popup-tips"><i style="color: #ee0a24">*</i>支持格式:png,jpg,bmp</p>
  108. <div class="popup-group">
  109. <span @click="onSaveCancel">取消</span>
  110. <span @click="onSaveUpload" class="popup-sure">确定</span>
  111. </div>
  112. </div>
  113. </van-popup>
  114. </div>
  115. </template>
  116. <script>
  117. import { browser } from '@/utils/common'
  118. import dayjs from 'dayjs'
  119. import setLoading from '@/utils/loading'
  120. // import fileUtil from '@/utils/fileUtil'
  121. import { uploadFile, examRegistrationUpdate } from '../signup/SignUpApi'
  122. import { applyList } from './appApi'
  123. export default {
  124. name: 'appDetail',
  125. data () {
  126. const query = this.$route.query
  127. return {
  128. headerStatus: false,
  129. examRegistrationId: query.examRegistrationId,
  130. form: {
  131. id: null,
  132. paymentOrderNo: null,
  133. examBaseName: null,
  134. subjectName: null,
  135. level: null,
  136. status: null,
  137. examStartTime: null,
  138. lastExamCertificateUrl: null,
  139. examMusicTheoryLevel: null,
  140. lastMusicTheoryCertificateUrl: null,
  141. memo: null,
  142. practiceSongIdList: null,
  143. performSongIdList: null,
  144. editStatus: false
  145. },
  146. uploadCertificate: [],
  147. uploadCertificate2: [],
  148. songUpload: {
  149. songStatus: false, // 曲目状态
  150. indexName: null,
  151. index: null, // 索引
  152. songName: null, // 曲名
  153. songAuthor: null // 作者
  154. },
  155. practiceNum: null,
  156. performUpload: [], // 演奏曲
  157. performUploadTemp: [], // 演奏曲
  158. performInfo: [], // 演奏曲基本信息
  159. performNum: null,
  160. practiceUpload: [], // 练习曲
  161. practiceUploadTemp: [], // 练习曲
  162. practiceInfo: [], // 练习曲基本信息
  163. }
  164. },
  165. mounted() {
  166. // 插入token
  167. let params = this.$route.query
  168. if(params.Authorization) {
  169. localStorage.setItem('Authorization', decodeURI(params.Authorization))
  170. }
  171. // 判断是否在app里面
  172. if(!browser().android && !browser().iPhone) {
  173. this.headerStatus = true
  174. } else {
  175. document.title = '报考详情'
  176. }
  177. this.__init()
  178. },
  179. methods: {
  180. async __init() {
  181. setLoading(true)
  182. try {
  183. const res = await applyList({
  184. page: 1,
  185. rows: 20,
  186. examRegistrationId: this.examRegistrationId
  187. })
  188. setLoading(false)
  189. const result = res.data
  190. if(result.code == 200) {
  191. const detail = result.data.rows ? result.data.rows[0] : {}
  192. this.form = {
  193. id: detail.id,
  194. paymentOrderNo: detail.paymentOrderNo,
  195. examBaseName: detail.examBaseName,
  196. subjectName: detail.subjectName,
  197. level: detail.level,
  198. status: detail.status,
  199. examStartTime: detail.examStartTime,
  200. examTime: dayjs(detail.examStartTime).format("YYYY-MM-DD") + '~' + dayjs(detail.examEndTime).format("YYYY-MM-DD"),
  201. lastExamCertificateUrl: detail.lastExamCertificateUrl,
  202. examMusicTheoryLevel: detail.examMusicTheoryLevel,
  203. lastMusicTheoryCertificateUrl: detail.lastMusicTheoryCertificateUrl,
  204. memo: detail.memo,
  205. practiceSongIdList: detail.practiceSongIdList,
  206. performSongIdList: detail.performSongIdList,
  207. editStatus: detail.status === "AUDIT_PASS" || detail.status === "AUDIT_WAIT" ? false : true
  208. }
  209. if(detail.lastExamCertificateUrl) {
  210. this.uploadCertificate = [{ url: detail.lastExamCertificateUrl }]
  211. }
  212. if(detail.lastMusicTheoryCertificateUrl) {
  213. this.uploadCertificate2 = [{ url: detail.lastMusicTheoryCertificateUrl }]
  214. }
  215. const songJson = detail.songJson ? JSON.parse(detail.songJson) : []
  216. songJson.forEach(item => {
  217. // 曲谱
  218. const uploadUrl = item.uploadUrl ? item.uploadUrl.split(',') : []
  219. let tempUrl = []
  220. uploadUrl.forEach(url => {
  221. tempUrl.push({
  222. url: url
  223. })
  224. })
  225. if(item.type === "PRACTICE") {
  226. this.practiceUpload.push(tempUrl)
  227. this.practiceUploadTemp.push(tempUrl)
  228. this.practiceInfo.push(item)
  229. } else if(item.type === "PERFORM") {
  230. this.performUpload.push(tempUrl)
  231. this.performUploadTemp.push(tempUrl)
  232. this.performInfo.push(item)
  233. }
  234. })
  235. this.practiceInfo.forEach((item, index) => {
  236. item.index = index
  237. })
  238. this.performInfo.forEach((item, index) => {
  239. item.index = index
  240. })
  241. this.practiceNum = this.practiceUpload.length
  242. this.performNum = this.performUpload.length
  243. }
  244. } catch(err) {
  245. //
  246. setLoading(false)
  247. }
  248. },
  249. onOpen(type, index) {
  250. let songUpload = this.songUpload
  251. let practiceSUL = this.practiceInfo[index]
  252. let performSUL = this.performInfo[index]
  253. const practiceSongIdList = this.form.practiceSongIdList
  254. const performSongIdList = this.form.performSongIdList
  255. if(type == "perform") {
  256. if(performSongIdList) {
  257. return
  258. }
  259. songUpload.songName = performSUL ? performSUL.songName : null
  260. songUpload.songAuthor = performSUL ? performSUL.songAuthor : null
  261. } else if(type == "practice") {
  262. if(practiceSongIdList) { // 判断是否是自定义
  263. return
  264. }
  265. songUpload.songName = practiceSUL ? practiceSUL.songName : null
  266. songUpload.songAuthor = practiceSUL ? practiceSUL.songAuthor : null
  267. }
  268. songUpload.indexName = type
  269. songUpload.index = index
  270. songUpload.songStatus = true
  271. },
  272. beforeRead(file) {
  273. const isLt2M = file.size / 1024 / 1024 < 5
  274. if (!isLt2M) {
  275. this.$toast('上传图片大小不能超过 5MB')
  276. return false
  277. }
  278. return true
  279. // return new Promise((resolve) => {
  280. // fileUtil.getOrientation(file).then((orient) => {
  281. // if (orient && orient != "" && orient != 1) {
  282. // let reader = new FileReader()
  283. // let img = new Image()
  284. // reader.onload = (e) => {
  285. // img.src = e.target.result
  286. // img.onload = function () {
  287. // const data = fileUtil.rotateImage(img, img.width, img.height, orient)
  288. // const newFile = fileUtil.dataURLtoFile(data, file.name)
  289. // resolve(newFile)
  290. // }
  291. // }
  292. // reader.readAsDataURL(file)
  293. // } else {
  294. // resolve(file)
  295. // }
  296. // })
  297. // })
  298. },
  299. beforeDelete(file, detail) {
  300. const obj = detail.name.split('-')
  301. let form = this.form
  302. if(obj[0] == "certificate2") {
  303. form.lastMusicTheoryCertificateUrl = "" // 上传图片地址为空
  304. } else if(obj[0] == "certificate") {
  305. form.lastExamCertificateUrl = ""
  306. }
  307. return true
  308. },
  309. async afterRead(file, detail) { // 上传头像
  310. const obj = detail.name.split('-')
  311. try {
  312. file.status = 'uploading'
  313. file.message = '上传中...'
  314. let formData = new FormData()
  315. formData.append('file', file.file)
  316. let res = await uploadFile(formData)
  317. let result = res.data
  318. if(result.code == 200) {
  319. file.status = 'done'
  320. let form = this.form
  321. if(obj[0] == "certificate2") {
  322. form.lastMusicTheoryCertificateUrl = result.data.url // 上传图片地址为空
  323. } else if(obj[0] == "certificate") {
  324. form.lastExamCertificateUrl = result.data.url
  325. } else if(obj[0] == 'practice') {
  326. file.url = result.data.url
  327. } else if(obj[0] == 'perform') {
  328. file.url = result.data.url
  329. }
  330. } else {
  331. file.status = 'failed'
  332. file.message = '上传失败'
  333. this.$toast(result.msg)
  334. return false
  335. }
  336. } catch (err) {
  337. return false
  338. }
  339. },
  340. async onSubmit() {
  341. if(!this.onCheckFields()) {
  342. return
  343. }
  344. let songJson = [] // json 数组
  345. // 练习课 "PRACTICE"
  346. const practiceUpload = this.practiceUpload
  347. this.practiceInfo.forEach(item => {
  348. let tempUrl = []
  349. practiceUpload[item.index].forEach(item => {
  350. tempUrl.push(item.url)
  351. })
  352. songJson.push({
  353. songName: item.songName,
  354. songAuthor: item.songAuthor,
  355. index: item.index,
  356. type: "PRACTICE",
  357. uploadUrl: tempUrl.join(',')
  358. })
  359. })
  360. // 演奏课 "PERFORM"
  361. const performUpload = this.performUpload
  362. this.performInfo.forEach(item => {
  363. let tempUrl = []
  364. performUpload[item.index].forEach(item => {
  365. tempUrl.push(item.url)
  366. })
  367. songJson.push({
  368. songName: item.songName,
  369. songAuthor: item.songAuthor,
  370. index: item.index,
  371. type: "PERFORM",
  372. uploadUrl: tempUrl.join(',')
  373. })
  374. })
  375. let form = this.form
  376. let params = {
  377. id: form.id,
  378. lastExamCertificateUrl: form.lastExamCertificateUrl,
  379. lastMusicTheoryCertificateUrl: form.lastMusicTheoryCertificateUrl,
  380. songJson: JSON.stringify(songJson),
  381. status: "AUDIT_WAIT"
  382. }
  383. setLoading(true)
  384. try {
  385. const res = await examRegistrationUpdate(params)
  386. setLoading(false)
  387. const result = res.data
  388. if(result.code == 200) {
  389. this.practiceUpload = []
  390. this.practiceUploadTemp = []
  391. this.practiceInfo = []
  392. this.performUpload = []
  393. this.performUploadTemp = []
  394. this.performInfo = []
  395. this.__init()
  396. } else {
  397. this.$toast(result.msg)
  398. }
  399. } catch(err) {
  400. //
  401. setLoading(false)
  402. }
  403. },
  404. onCheckFields() {
  405. // 校验数据
  406. let form = this.form
  407. // 有值说明是列表
  408. if(this.practiceUpload.length != this.practiceNum) {
  409. this.$toast('请上传练习曲')
  410. return false
  411. }
  412. if(this.performUpload.length != this.performNum) {
  413. this.$toast('请上传演奏曲')
  414. return false
  415. }
  416. if(form.level > 2 && form.examMusicTheoryLevel == 0 && !form.lastMusicTheoryCertificateUrl) {
  417. this.$toast("请上传乐理证书")
  418. return false
  419. }
  420. return true
  421. },
  422. onSaveCancel() {
  423. this.songUpload.songStatus = false
  424. this.performUpload = JSON.parse(JSON.stringify(this.performUploadTemp)) // 回填数据
  425. this.practiceUpload = JSON.parse(JSON.stringify(this.practiceUploadTemp)) // 回填数据
  426. },
  427. onSaveUpload() {
  428. let songUpload = this.songUpload
  429. if(!songUpload.songName) {
  430. this.$toast("请输入曲名")
  431. return
  432. }
  433. if(songUpload.indexName == "practice") {
  434. const practiceObj = this.practiceUpload[songUpload.index]
  435. const practiceLength = practiceObj ? practiceObj.length : 0
  436. if(practiceObj && practiceLength > 0 && practiceObj[0].url) {
  437. if(practiceObj[practiceLength - 1].url) {
  438. this.practiceInfo[songUpload.index] = JSON.parse(JSON.stringify(songUpload))
  439. this.practiceUploadTemp = JSON.parse(JSON.stringify(this.practiceUpload))
  440. } else {
  441. this.$toast("上传曲谱中,请稍等")
  442. return
  443. }
  444. } else {
  445. this.$toast("请上传文件")
  446. return
  447. }
  448. } else if(songUpload.indexName == "perform") {
  449. const performObj = this.performUpload[songUpload.index]
  450. const performLength = performObj ? performObj.length : 0
  451. if(performObj && performLength > 0) {
  452. if(performObj[performLength - 1].url) {
  453. this.performInfo[songUpload.index] = JSON.parse(JSON.stringify(songUpload))
  454. this.performUploadTemp = JSON.parse(JSON.stringify(this.performUpload))
  455. } else {
  456. this.$toast("上传曲谱中,请稍等")
  457. return
  458. }
  459. } else {
  460. this.$toast("请上传文件")
  461. return
  462. }
  463. }
  464. songUpload.songName = null
  465. songUpload.songAuthor = null
  466. songUpload.songStatus = false
  467. },
  468. numberToCN (value) {
  469. const tempNumber = {
  470. 0: '一',
  471. 1: '二',
  472. 2: '三',
  473. 3: '四',
  474. 4: '五',
  475. 5: '六',
  476. 6: '七',
  477. 7: '八',
  478. 8: '九',
  479. 9: '十'
  480. }
  481. return tempNumber[value]
  482. }
  483. },
  484. filters: {
  485. filterStatus(value) {
  486. const template = {
  487. PAY_WAIT: '未缴费',
  488. AUDIT_WAIT: '等待审核',
  489. AUDIT_PASS: '通过',
  490. AUDIT_REJECT: '拒绝',
  491. REFUNDED: '已退款'
  492. }
  493. return template[value]
  494. }
  495. }
  496. }
  497. </script>
  498. <style lang="less" scoped>
  499. @import url("../../assets/commonLess/variable");
  500. .appDetail {
  501. min-height: 100vh;
  502. overflow: hidden;
  503. }
  504. /deep/.van-cell {
  505. padding: 14px 16px;
  506. font-size: 16px;
  507. // color: @--font-main-color;
  508. .van-cell__title {
  509. margin-right: 12px;
  510. }
  511. .van-cell__value {
  512. width: calc(40% - .2rem);
  513. padding-right: .2rem;
  514. text-align: left;
  515. flex: auto;
  516. color: @--font-second-color;
  517. }
  518. .van-cell__right-icon {
  519. position: absolute;
  520. right: 16px;
  521. }
  522. .payTime {
  523. color: @--red-color;
  524. }
  525. &.van-field--disabled .van-field__label {
  526. color: @--font-main-color;
  527. }
  528. .van-field__control:disabled {
  529. color: @--font-second-color;
  530. }
  531. .noPass {
  532. color: @--red-color;
  533. .van-field__control:disabled {
  534. color: @--red-color;
  535. }
  536. }
  537. .pass {
  538. color: @--main-color;
  539. .van-field__control:disabled {
  540. color: @--main-color;
  541. }
  542. }
  543. }
  544. .van-popup-song {
  545. width: 80%;
  546. border-radius: .08rem;
  547. }
  548. .song-popup {
  549. text-align: center;
  550. .title {
  551. font-size: 18px;
  552. font-weight: 500;
  553. color: @--font-main-color;
  554. padding: .2rem 0 .15rem;
  555. }
  556. .song-upload {
  557. border-radius: .05rem;
  558. border: 1px solid #c5c7cb;
  559. background-position: 0 0, 100% 0, 0 0, 0 100%;
  560. font-size: .16rem;
  561. color: #777;
  562. width: 80px;
  563. height: 80px;
  564. display: flex;
  565. justify-content: center;
  566. align-items: center;
  567. text-align: center;
  568. .van-uploader__preview {
  569. margin: 0;
  570. }
  571. p {
  572. font-size: 13px;
  573. }
  574. }
  575. /deep/.van-uploader {
  576. margin: 0 auto;
  577. }
  578. /deep/.van-uploader__upload,
  579. /deep/.van-uploader__preview-image {
  580. width: 65px;
  581. height: 65px;
  582. }
  583. .song-popup-tips {
  584. font-size: .14rem;
  585. color: #808080;
  586. padding-bottom: .15rem
  587. // padding-top: .1rem;
  588. // padding-bottom: .25rem;
  589. }
  590. /deep/.van-cell {
  591. padding: 13px 35px;
  592. }
  593. /deep/.van-field__label {
  594. width: .8rem;
  595. text-align: left;
  596. }
  597. .popup-group {
  598. width: 100%;
  599. display: flex;
  600. color: @--main-color;
  601. background-color: #F0F0F0;
  602. font-size: .18rem;
  603. span {
  604. padding: .12rem 0;
  605. flex: 1;
  606. }
  607. .popup-sure {
  608. color: #ffffff;
  609. background-color: @--main-color;
  610. }
  611. }
  612. }
  613. .section {
  614. margin-top: 10px;
  615. }
  616. .memos {
  617. margin-top: 20px;
  618. margin-bottom: 20px;
  619. & + .van-button {
  620. margin-top: 0;
  621. }
  622. }
  623. .van-button--primary {
  624. margin: .15rem 0 .2rem;
  625. background-color: @--main-color;
  626. border: 1px solid @--main-color;
  627. color: #FFFFFF;
  628. font-size: .18rem;
  629. height: .5rem;
  630. line-height: .52rem;
  631. width: 90%;
  632. margin-left: 5%;
  633. }
  634. </style>