change-voice.vue 15 KB

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