AppDetail.vue 24 KB

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