change-voice.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. <template>
  2. <div>
  3. <el-form :model="form" :rules="rules" ref="form" label-width="110px">
  4. <el-form-item label="原乐器" prop="name">
  5. <span>{{originalMusicalGoods || '无'}}</span>
  6. </el-form-item>
  7. <el-form-item label="原教辅" prop="name">
  8. <span>{{originalAccessoriesGoods || '无'}}</span>
  9. </el-form-item>
  10. <el-form-item
  11. label="更改声部"
  12. prop="subjectId"
  13. :rules="[
  14. { required: true, message: '请选择更改声部', trigger: 'change' }
  15. ]"
  16. >
  17. <el-select
  18. style="width: 100%!important"
  19. v-model="form.subjectId"
  20. clearable
  21. v-if="!changeInfo"
  22. @change="subjectChange"
  23. placeholder="请选择声部"
  24. >
  25. <el-option
  26. v-for="item in filterVoiceList"
  27. :key="item.subjectId"
  28. :label="item.subjectName"
  29. :value="item.subjectId">
  30. </el-option>
  31. </el-select>
  32. <span v-else>{{changeSubjectName}}</span>
  33. </el-form-item>
  34. <el-form-item
  35. label="更改乐器"
  36. prop="musicalGoods"
  37. :rules="[
  38. { required: true, message: '请选择更改乐器', trigger: 'change' }
  39. ]"
  40. >
  41. <el-select
  42. style="width: 100%!important"
  43. v-model="form.musicalGoods"
  44. clearable
  45. v-if="!changeInfo"
  46. @change="musicalGoodsChange"
  47. placeholder="请选择乐器"
  48. >
  49. <el-option
  50. v-for="item in musicalGoods"
  51. :key="item.goodsIdList"
  52. :label="item.name"
  53. :value="item.goodsIdList">
  54. </el-option>
  55. </el-select>
  56. <span v-else-if="changeInfo && changeInfo.changeMusicalGoods">{{changeInfo.changeMusicalGoods.name}}</span>
  57. </el-form-item>
  58. <el-form-item
  59. v-if="changeInfo || (form.musicalGoods && musicalGoodsById[form.musicalGoods] && musicalGoodsById[form.musicalGoods].kitGroupPurchaseTypeJsonParse)" label="乐器提供方式" prop="type"
  60. :rules="[
  61. { required: true, message: '请选择乐器提供方式', trigger: 'change' }
  62. ]"
  63. >
  64. <el-radio-group v-if="!changeInfo" v-model="form.type">
  65. <el-radio
  66. :label="key"
  67. v-for="(item, key) in musicalGoodsById[form.musicalGoods].kitGroupPurchaseTypeJsonParse"
  68. :key="key"
  69. >{{`${kitGroupPurchaseTypeFormater[key]} ${(musicalGoodsById[form.musicalGoods][typeAndprice[key]] || 0) > 0 ? musicalGoodsById[form.musicalGoods][typeAndprice[key]] + '元' : '免费'}`}}</el-radio>
  70. </el-radio-group>
  71. <span v-else-if="changeInfo && changeInfo.kitGroupPurchaseType">{{kitGroupPurchaseTypeFormater[changeInfo.kitGroupPurchaseType]}}</span>
  72. </el-form-item>
  73. <el-form-item v-if="(activeAccessories.length || groupList.length) || changeInfo" label="更换教辅" prop="name">
  74. <accessories
  75. :list.sync="activeAccessories"
  76. :groupList.sync="groupList"
  77. @change="accessoriesChange"
  78. v-if="!changeInfo"
  79. />
  80. <span v-else-if="changeInfo">{{changeAccessoriesGoods}}</span>
  81. <!-- <el-select style="width: 100%" v-model="form.accessories" clearable placeholder="请选择教辅">
  82. <el-option
  83. v-for="item in accessories"
  84. :key="item.id"
  85. :label="item.name"
  86. :value="item.id">
  87. </el-option>
  88. </el-select> -->
  89. </el-form-item>
  90. <el-form-item label="查看链接" prop="name" v-if="changeInfo">
  91. <div class="viewlink">
  92. <el-tooltip class="item" effect="dark" :content="copyLink" placement="top">
  93. <span class="link">{{copyLink}}</span>
  94. </el-tooltip>
  95. <el-popover
  96. placement="top"
  97. width="220"
  98. trigger="click">
  99. <div class="left-code">
  100. <div id="qrcode"
  101. class="qrcode code"
  102. ref="qrCodeUrl"></div>
  103. <p class="code-url"
  104. v-if="copyLink">{{ copyLink }} <el-link @click="copyUrl(copyLink)" class="linkbtn" type="primary">复制</el-link></p>
  105. </div>
  106. <el-button type="primary" class="btn" slot="reference" @click="onCreateQRCode">二维码</el-button>
  107. </el-popover>
  108. </div>
  109. </el-form-item>
  110. <el-form-item label="支付差价" prop="name">
  111. <span style="color: red;" v-if="!changeInfo">{{ spread | moneyFormat }}元</span>
  112. <span style="color: red;" v-else>{{ editSpread | moneyFormat }}元</span>
  113. </el-form-item>
  114. </el-form>
  115. <div
  116. slot="footer"
  117. class="dialog-footer"
  118. style="text-align: right;"
  119. >
  120. <el-button
  121. @click="$listeners.close"
  122. >取 消</el-button>
  123. <el-button
  124. @click="cancel"
  125. type="danger"
  126. v-permission="'subjectChange/cancel'"
  127. v-if="changeInfo && changeInfo.status !== 1"
  128. >取消订单</el-button>
  129. <el-button
  130. type="primary"
  131. v-if="!changeInfo"
  132. v-permission="'subjectChange/add'"
  133. @click="submit"
  134. >确 定</el-button>
  135. </div>
  136. </div>
  137. </template>
  138. <script>
  139. import QRCode from 'qrcodejs2'
  140. import copy from 'copy-to-clipboard'
  141. import numeral from 'numeral'
  142. import { getStudentOriginal, getSubjectGoodsAndInfo, subjectChangeAdd, subjectChangeCancel, getChangeInfo } from '@/api/buildTeam'
  143. import { vaildStudentUrl } from '@/utils/validate'
  144. import accessories from './accessories'
  145. import { kitGroupPurchaseType } from '@/constant'
  146. const formatAllGoods = (data, kitGroupPurchaseType) => {
  147. const accessories = []
  148. const accessoriesById = {}
  149. const musicalGoods = []
  150. const musicalGoodsById = {}
  151. const groupList = []
  152. const groupListById = {}
  153. const accessoriesByGoods = {}
  154. if (data) {
  155. const { musicGroupSubjectGoodsGroupList } = data
  156. const types = {}
  157. for (const item of musicGroupSubjectGoodsGroupList) {
  158. if (!types[item.type]) {
  159. types[item.type] = []
  160. }
  161. types[item.type].push(item)
  162. }
  163. const typesKeys = Object.keys(types)
  164. for (const key of typesKeys) {
  165. for (const item of types[key]) {
  166. if (key === 'INSTRUMENT') {
  167. let json = {}
  168. let courseJson = {}
  169. try {
  170. json = JSON.parse(item.kitGroupPurchaseTypeJson)
  171. } catch (error) {}
  172. try {
  173. courseJson = JSON.parse(item.coursePurchaseTypeJson)
  174. } catch (error) {}
  175. // if (json[kitGroupPurchaseType] !== undefined) {
  176. const _item = {
  177. ...item,
  178. kitGroupPurchaseTypeJsonParse: json,
  179. kitGroupPurchaseTypePrice: json[kitGroupPurchaseType] || 0,
  180. coursePurchaseTypeJsonTypePrice: courseJson[kitGroupPurchaseType] || 0,
  181. _calculated_price: (kitGroupPurchaseType === 'FREE' ? 0 : (kitGroupPurchaseType === 'LEASE' ? item.depositFee : item.price))
  182. }
  183. musicalGoods.push(_item)
  184. musicalGoodsById[item.goodsIdList] = _item
  185. if (!types.ACCESSORIES) {
  186. if (!accessoriesByGoods[item.goodsIdList]) {
  187. accessoriesByGoods[item.goodsIdList] = []
  188. }
  189. const acs = item.goodsList[0].goodsList ? item.goodsList[0].goodsList : []
  190. for (const goods of acs) {
  191. accessoriesByGoods[item.goodsIdList].push(goods)
  192. accessoriesById[goods.id] = goods
  193. }
  194. }
  195. // }
  196. } else if (item.type === 'ACCESSORIES') {
  197. groupList.push(item)
  198. groupListById[item.id] = item
  199. }
  200. }
  201. }
  202. }
  203. return {
  204. accessories,
  205. accessoriesById,
  206. musicalGoods,
  207. musicalGoodsById,
  208. groupList,
  209. groupListById,
  210. accessoriesByGoods
  211. }
  212. }
  213. const typeAndprice = {
  214. GROUP: 'price',
  215. LEASE: 'depositFee',
  216. }
  217. export default {
  218. props: ['detail', 'musicGroupId', 'voiceList'],
  219. components: {
  220. accessories
  221. },
  222. data() {
  223. return {
  224. typeAndprice,
  225. kitGroupPurchaseTypeFormater: kitGroupPurchaseType,
  226. changeInfo: null,
  227. oldAllMoney: 0,
  228. accessories: [],
  229. accessoriesByid: {},
  230. musicalGoods: [],
  231. musicalGoodsById: {},
  232. groupList: [],
  233. groupListById: {},
  234. accessoriesByGoods: {},
  235. selectAccessories: [],
  236. selectAccessoriesMoney: 0,
  237. kitGroupPurchaseTypePrice: 0,
  238. coursePurchaseTypeJsonTypePrice: 0,
  239. form: {
  240. subjectId: '',
  241. accessories: '',
  242. musicalGoods: '',
  243. type: '',
  244. },
  245. rules: {},
  246. item: {},
  247. originalMusicalGoods: '',
  248. originalAccessoriesGoods: '',
  249. originalAccessoriesPrice: 0,
  250. originalMusicalPrice: 0,
  251. originalCourseFee: 0,
  252. musicGroupSubjectPlanFee: 0,
  253. musicalPrice: 0,
  254. }
  255. },
  256. watch: {
  257. detail() {
  258. if (this.detail) {
  259. this.fetchDetail()
  260. }
  261. },
  262. 'form.musicalGoods'() {
  263. this.$set(this.form, 'type', '')
  264. },
  265. 'form.type'() {
  266. this.musicalGoodsChange(this.form.musicalGoods)
  267. }
  268. },
  269. computed: {
  270. copyLink() {
  271. if (this.changeInfo) {
  272. return vaildStudentUrl() + '/#/change-voice?id=' + this.changeInfo.id
  273. }
  274. return ''
  275. },
  276. filterVoiceList() {
  277. return this.voiceList.filter(item => item.subjectId !== this.detail.actualSubjectId)
  278. },
  279. activeAccessories() {
  280. const { musicalGoods } = this.form || {}
  281. return musicalGoods ? this.accessoriesByGoods[musicalGoods] || [] : []
  282. },
  283. changeSubjectName() {
  284. let name = ''
  285. if (this.item.changeSubjectId) {
  286. for (const item of this.voiceList) {
  287. if (item.subjectId === this.item.changeSubjectId) {
  288. name = item.subjectName
  289. break
  290. }
  291. }
  292. }
  293. return name
  294. },
  295. changeAccessoriesGoods() {
  296. const subjectChange = this.changeInfo || {}
  297. const items = (subjectChange.changeAccessoriesGoods || []).map(item => item.name).join(',')
  298. return items || '未选择教辅'
  299. },
  300. editSpread() {
  301. const data = this.changeInfo || {}
  302. const payed = (data.originalAccessoriesPrice || 0) + (data.originalCourseFee || 0) + (data.originalMusicalPrice || 0)
  303. // console.log(payed, data.changeMusicalPrice, data.changeAccessoriesPrice, data.changeCourseFee, {...data})
  304. return (data.changeMusicalPrice || 0) + (data.changeAccessoriesPrice || 0) + (data.changeCourseFee || 0) - payed
  305. },
  306. spread() {
  307. const money = (
  308. this.numFormat(
  309. this.musicalPrice +
  310. this.selectAccessoriesMoney +
  311. this.musicGroupSubjectPlanFee -
  312. this.originalAccessoriesPrice -
  313. this.originalMusicalPrice -
  314. this.originalCourseFee -
  315. this.coursePurchaseTypeJsonTypePrice -
  316. this.kitGroupPurchaseTypePrice
  317. )
  318. )
  319. // console.log(
  320. // this.item.kitGroupPurchaseType,
  321. // '乐器价格', this.musicalPrice,
  322. // '已选附件价格', this.selectAccessoriesMoney,
  323. // '选择课程费用', this.musicGroupSubjectPlanFee,
  324. // '原附件价格', this.originalAccessoriesPrice,
  325. // '原乐器价格', this.originalMusicalPrice,
  326. // '原课程费用', this.originalCourseFee,
  327. // '原课程减免费用', this.coursePurchaseTypeJsonTypePrice,
  328. // '乐器减免费用', this.kitGroupPurchaseTypePrice,
  329. // '结果价格', money
  330. // )
  331. return money
  332. }
  333. },
  334. mounted() {
  335. if (this.detail && this.detail.id) {
  336. this.fetchDetail()
  337. }
  338. },
  339. methods: {
  340. copyUrl(url) {
  341. copy(url)
  342. this.$message.success('复制成功')
  343. },
  344. async fetchDetail() {
  345. const setRes = res => {
  346. const { data } = res
  347. this.item = data || {}
  348. if (data) {
  349. this.$set(this.form, 'type', this.item.kitGroupPurchaseType)
  350. this.originalAccessoriesPrice = data.originalAccessoriesPrice
  351. this.originalMusicalPrice = data.originalMusicalPrice
  352. this.originalCourseFee = data.originalCourseFee
  353. this.originalMusicalGoods = data.originalMusicalGoods && data.originalMusicalGoods.name
  354. this.originalAccessoriesGoods = (data.originalAccessoriesGoods || []).map(item => item.name).join()
  355. }
  356. }
  357. if (this.detail.subjectChange) {
  358. await getChangeInfo({
  359. id: this.detail.subjectChange.id
  360. })
  361. .then(res => {
  362. setRes(res)
  363. this.changeInfo = res.data
  364. })
  365. } else {
  366. this.changeInfo = this.detail.subjectChange
  367. await getStudentOriginal({
  368. musicGroupId: this.musicGroupId,
  369. studentId: this.detail.studentId,
  370. })
  371. .then(setRes)
  372. }
  373. },
  374. async subjectChange(id) {
  375. this.$set(this.form, 'musicalGoods', '')
  376. let data = null
  377. if (id) {
  378. await getSubjectGoodsAndInfo({
  379. musicGroupId: this.musicGroupId,
  380. subjectId: id,
  381. })
  382. .then(res => {
  383. data = res.data
  384. this.musicGroupSubjectPlanFee = res.data.musicGroupSubjectPlan.fee
  385. })
  386. } else {
  387. this.musicGroupSubjectPlanFee = 0
  388. }
  389. const items = formatAllGoods(data, this.item.kitGroupPurchaseType)
  390. for (const key in items) {
  391. if (items.hasOwnProperty(key)) {
  392. const item = items[key]
  393. this[key] = item
  394. }
  395. }
  396. this.musicalGoodsChange()
  397. },
  398. musicalGoodsChange(val) {
  399. const item = this.musicalGoodsById[val]
  400. if (item) {
  401. this.musicalPrice = this.numFormat(item[typeAndprice[this.form.type]] || 0)
  402. // this.kitGroupPurchaseTypePrice = this.numFormat(item[typeAndprice[this.form.type]] || 0)
  403. this.coursePurchaseTypeJsonTypePrice = this.numFormat(item.coursePurchaseTypeJsonTypePrice)
  404. this.types = item.kitGroupPurchaseTypeJsonParse
  405. } else {
  406. this.musicalPrice = 0
  407. // this.kitGroupPurchaseTypePrice = 0
  408. this.coursePurchaseTypeJsonTypePrice = 0
  409. this.$set(this.form, 'type', '')
  410. }
  411. },
  412. accessoriesChange(ids, money) {
  413. this.selectAccessories = ids
  414. this.selectAccessoriesMoney = money
  415. },
  416. numFormat(num) {
  417. let _num = parseFloat(num)
  418. if (isNaN(_num)) {
  419. _num = 0
  420. }
  421. return parseFloat(_num.toFixed(2))
  422. },
  423. onCreateQRCode () {
  424. setTimeout(() => {
  425. this.$refs.qrCodeUrl.innerHTML = '';
  426. this.qrcode = new QRCode(this.$refs.qrCodeUrl, {
  427. width: 200,
  428. height: 200,
  429. colorDark: '#000000',
  430. colorLight: '#ffffff',
  431. correctLevel: QRCode.CorrectLevel.H
  432. })
  433. this.qrcode.makeCode(this.copyLink)
  434. this.codeUrl = this.copyLink
  435. }, 500)
  436. },
  437. submit() {
  438. this.$refs['form'].validate((valid) => {
  439. if (valid) {
  440. subjectChangeAdd({
  441. changeCourseFee: this.numFormat(this.musicGroupSubjectPlanFee - this.coursePurchaseTypeJsonTypePrice),
  442. changeAccessories: this.selectAccessories.join(','),
  443. changeAccessoriesPrice: this.numFormat(this.selectAccessoriesMoney),
  444. changeMusicalPrice: this.numFormat(this.musicalPrice),
  445. originalCourseFee: this.originalCourseFee,
  446. originalMusicalPrice: this.originalMusicalPrice,
  447. originalMusical: this.item.originalMusical,
  448. originalAccessories: this.item.originalAccessories,
  449. originalAccessoriesPrice: this.originalAccessoriesPrice,
  450. cooperationOrganId: this.item.cooperationOrganId,
  451. kitGroupPurchaseType: this.form.type,
  452. musicGroupId: this.musicGroupId,
  453. studentId: this.detail.studentId,
  454. changeMusical: this.form.musicalGoods,
  455. originalCost: this.item.originalCost,
  456. organId: this.item.organId,
  457. originalSubjectId: this.detail.actualSubjectId,
  458. changeSubjectId: this.form.subjectId,
  459. })
  460. .then(res => {
  461. this.$listeners.close()
  462. this.$listeners.submited()
  463. this.$message.success('提交成功!')
  464. })
  465. }
  466. })
  467. },
  468. cancel() {
  469. this.$confirm('是否确认取消订单?', '提示', {
  470. onfirmButtonText: '确定',
  471. cancelButtonText: '取消',
  472. type: 'warning'
  473. })
  474. .then(() => {
  475. subjectChangeCancel({
  476. id: this.detail.subjectChange.id
  477. })
  478. .then(res => {
  479. this.$listeners.close()
  480. this.$listeners.submited()
  481. this.$message.success('取消成功!')
  482. })
  483. })
  484. }
  485. },
  486. }
  487. </script>
  488. <style lang="less" scoped>
  489. .viewlink{
  490. display: flex;
  491. .link{
  492. flex: 1;
  493. overflow: hidden;
  494. text-overflow: ellipsis;
  495. display: block;
  496. white-space: nowrap;
  497. }
  498. .btn{
  499. width: 100px;
  500. margin-left: 20px;
  501. }
  502. }
  503. .left-code{
  504. height: 255px;
  505. .code-url{
  506. margin-top: 10px;
  507. .linkbtn{
  508. margin-top: 0;
  509. margin-bottom: 0;
  510. font-size: 12px;
  511. }
  512. }
  513. }
  514. </style>