exchange.vue 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. <!-- 积分兑换 -->
  2. <template>
  3. <div class="listBox">
  4. <div v-for="(item, index) in dataList" :key="'exchange' + index">
  5. <div class="cursor-pointer mx-5 mb-4" style="width: 180px;" @click="handleShowDetail(item)">
  6. <v-img width="180" height="180" :src="item.url || 'https://minio.citupro.com/dev/menduner/7.png'"></v-img>
  7. <div class="ellipsis mt-2" style="font-size: 14px;">{{ item.name }}</div>
  8. <div class="ellipsis mt-1" style="font-size: 13px;">消耗积分<span class="ml-1" style="color: var(--v-primary-base)">{{ item.point }}</span></div>
  9. </div>
  10. </div>
  11. </div>
  12. <Dialog :visible="showDetail" titleClass="text-h6" :footer="point >= detailItem?.point" :widthType="3" title="详情说明" @submit="handleSubmit" @close="showDetail = false">
  13. <div class="color-primary font-size-20">{{ detailItem.name }}</div>
  14. <div class="tips">
  15. <div>使用说明:积分一经兑换概不退回,敬请谅解。</div>
  16. </div>
  17. <div class="d-flex align-center my-5">
  18. <div class="mr-1">消耗积分</div>
  19. <div class="color-primary">{{ detailItem.point }}</div>
  20. </div>
  21. <div v-if="point >= detailItem.point">
  22. <div class="color-666 mb-5 mt-10">{{ detailItem?.type ? '收货人信息填写' : '联系电话填写' }}</div>
  23. <CtForm ref="CtFormRef" :items="formItems"></CtForm>
  24. </div>
  25. <div v-if="point < detailItem.point" class="text-end color-error font-size-14 cursor-pointer text-decoration-underline" @click="emit('toTaskCenter')">积分不足,快去赚取积分吧</div>
  26. </Dialog>
  27. </template>
  28. <script setup>
  29. defineOptions({name: 'mall-exchange'})
  30. import { ref } from 'vue'
  31. import { getToken } from '@/utils/auth'
  32. import Dialog from '@/components/CtDialog'
  33. import Snackbar from '@/plugins/snackbar'
  34. import { redeemSubmit } from '@/api/mall'
  35. import { useUserStore } from '@/store/user'
  36. import { getDict } from '@/hooks/web/useDictionaries'
  37. import { checkPersonBaseInfo } from '@/utils/check'
  38. import dialogExtend from '@/plugins/dialogExtend'
  39. const emit = defineEmits(['login', 'toTaskCenter'])
  40. defineProps({
  41. point: {
  42. type: Number,
  43. default: 0
  44. }
  45. })
  46. const CtFormRef = ref()
  47. const formItems = ref({
  48. options: [
  49. {
  50. type: 'text',
  51. key: 'contactName',
  52. value: localStorage.getItem('baseInfo') ? JSON.parse(localStorage.getItem('baseInfo')).name : '',
  53. hide: false,
  54. label: '收货人姓名 *',
  55. rules: [v => !!v || '请输入收货人姓名'],
  56. },
  57. {
  58. type: 'text',
  59. key: 'contactPhone',
  60. value: localStorage.getItem('userInfo') ? JSON.parse(localStorage.getItem('userInfo')).phone : '',
  61. label: '收货人联系电话 *',
  62. outlined: true,
  63. rules: [v => !!v || '请填写收货人联系电话']
  64. },
  65. {
  66. type: 'cascade',
  67. key: 'address',
  68. value: [],
  69. label: '收货地址',
  70. itemText: 'name',
  71. itemValue: 'name',
  72. required: true,
  73. clearable: false,
  74. emitPath: true,
  75. items: []
  76. },
  77. {
  78. type: 'textarea',
  79. key: 'contactAddress',
  80. value: '',
  81. hide: false,
  82. label: '收货详细地址 *',
  83. rules: [ v => !!v || '请填写收货详细地址' ]
  84. }
  85. ]
  86. })
  87. // 数据
  88. const dataList = ref([
  89. { name: '房券-高端酒店房券', point: 12000, url: 'https://minio.menduner.com/dev/menduner/hotalRoomVoucher.png', type: 1 },
  90. { name: '门墩儿酒店英语学习年卡', point: 8000, url: 'https://minio.citupro.com/dev/menduner/englishCourses.jpg', type: 0 },
  91. { name: '红酒-经典年份葡萄酒', point: 5000, url: 'https://minio.menduner.com/dev/menduner/redWine.png', type: 1 },
  92. { name: '瑞幸咖啡券-瑞幸咖啡精致享受券', point: 2000, url: 'https://minio.menduner.com/dev/menduner/coffee.png', type: 0 },
  93. { name: '减压捏捏乐', point: 500, url: 'https://minio.menduner.com/dev/menduner/pinchMusic.png', type: 1 }
  94. ])
  95. // 期望城市、其它感兴趣的城市
  96. getDict('areaTreeData', null, 'areaTreeData').then(({ data }) => {
  97. data = data?.length && data || []
  98. formItems.value.options.find(e => e.key === 'address').items = data
  99. })
  100. // 详情说明弹窗
  101. const showDetail = ref(false)
  102. const detailItem = ref({})
  103. const handleShowDetail = (item) =>{
  104. if (!getToken()) {
  105. Snackbar.warning('请先登录')
  106. emit('login')
  107. return
  108. }
  109. if (!checkPersonBaseInfo()) { // 强制填写个人信息
  110. dialogExtend('necessaryInfoDialog').then(() => {
  111. handleShowDetail()
  112. })
  113. return
  114. }
  115. detailItem.value = item
  116. formItems.value.options.forEach(e => {
  117. if (e.key !== 'contactPhone') e.hide = item.type ? false : true
  118. })
  119. showDetail.value = true
  120. }
  121. // 兑换提交
  122. const handleSubmit = async () =>{
  123. const { valid } = await CtFormRef.value.formRef.validate()
  124. if (!valid) return
  125. const obj = {
  126. ...detailItem.value
  127. }
  128. formItems.value.options.forEach(e => {
  129. if (!e.hide) obj[e.key] = e.value
  130. })
  131. if (obj.type && (!obj.address || !obj.address.length)) return Snackbar.warning('请选择收货地址')
  132. if (obj.type) obj.contactAddress = obj.address.join('') + obj.contactAddress
  133. delete obj.address
  134. if (!obj.contactName) obj.contactName = localStorage.getItem('baseInfo') ? JSON.parse(localStorage.getItem('baseInfo')).name : '--'
  135. await redeemSubmit(obj)
  136. Snackbar.success('提交成功')
  137. showDetail.value = false
  138. detailItem.value = {}
  139. await useUserStore().getUserAccountInfo()
  140. }
  141. </script>
  142. <style lang="scss" scoped>
  143. .listBox {
  144. display: flex;
  145. flex-wrap: wrap;
  146. }
  147. .ellipsis {
  148. width: 100%;
  149. }
  150. .tips {
  151. margin-top: 20px;
  152. padding: 12px 20px;
  153. border-radius: 5px;
  154. background-color: var(--default-bgc);
  155. // width: 400px;
  156. div {
  157. font-size: 15px;
  158. margin-bottom: 4px;
  159. }
  160. span {
  161. display: inline-block;
  162. font-size: 14px;
  163. margin-bottom: 20px;
  164. }
  165. }
  166. </style>