prizeDraw.vue 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. <template>
  2. <div class="prizeDrawBox">
  3. <div class="d-flex flex-column align-center">
  4. <CtDialog :visible="showDialog" :widthType="3" :footer="false" titleClass="text-h6" title="房券抽奖" @close="showDialog = false">
  5. <div class="d-flex flex-column align-center">
  6. <div class="numberBox mb-5">房券抽奖</div>
  7. <gridPage v-if="props.type === '1'" :lotteryId="props.lotteryId" :disabled="disabled" @start="disabled = true" @end="endCallback"></gridPage>
  8. <slotMachinePage v-if="props.type === '2'" :lotteryId="props.lotteryId" height="120" :class="{'mb-3': disabled}" :disabled="disabled" @start="disabled = true" @end="endCallback"></slotMachinePage>
  9. </div>
  10. </CtDialog>
  11. <v-card min-height="300" width="700" class="pa-5" :class="{'mt-3': !disabled}" style="position: relative;">
  12. <div v-if="showPrize">
  13. <p v-for="(k, i) in prizeData" :key="i" class="color-primary">
  14. {{ k.prize.prompt }}
  15. <span class="color-999">(10天内未领取的,则视为主动放弃当前奖品)</span>
  16. </p>
  17. <p>凭此房券在规定有效期内可享受免费住宿一晚。</p>
  18. <p class="mb-5">请提供收货地址,以便安排房券派送。</p>
  19. <!-- 收货地址 -->
  20. <div>
  21. <v-radio-group v-model="addressSelect" color="primary">
  22. <v-radio v-for="val in address" :key="val.id" :label="val.id === 9999 ? val.label : (val.name + ',' + val.mobile + ',' + val.areaName + val.detailAddress)" :value="val.id"></v-radio>
  23. </v-radio-group>
  24. <v-form v-if="addressSelect === 9999" ref="addressFormRef">
  25. <v-row>
  26. <v-col :cols="6">
  27. <v-text-field v-model="newAddress.name" label="收货人名称 *" color="primary" density="compact" variant="outlined"></v-text-field>
  28. </v-col>
  29. <v-col :cols="6">
  30. <v-text-field v-model="newAddress.mobile" :rules="phoneRules" label="收货人手机号码 *" color="primary" density="compact" variant="outlined"></v-text-field>
  31. </v-col>
  32. </v-row>
  33. <div class="d-flex" style="width: 100%;">
  34. <div class="mt-2" style="color: #777; width: 100px;">省市区 *</div>
  35. <el-cascader
  36. ref="cascaderAddr"
  37. v-model="newAddress.areaId"
  38. size="large"
  39. clearable
  40. class="mb-5"
  41. placeholder="省市区 *"
  42. style="flex: 1;"
  43. :props="{ value: 'id', label: 'name', emitPath: false }"
  44. :options="areaTreeData"
  45. @change="handleChangeArea(item)"
  46. ></el-cascader>
  47. </div>
  48. <v-text-field v-model="newAddress.detailAddress" label="详情地址 *" color="primary" density="compact" variant="outlined"></v-text-field>
  49. </v-form>
  50. <div class="text-center mt-3">
  51. <v-btn color="primary" class="elevation-5" width="180" @click.stop="handleSubmit">确 认</v-btn>
  52. </div>
  53. </div>
  54. </div>
  55. <div v-else class="color-warning text-center" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);">请先进行抽奖</div>
  56. </v-card>
  57. </div>
  58. </div>
  59. </template>
  60. <script setup>
  61. defineOptions({ name: 'prizeDraw'})
  62. import gridPage from './prizeDraw/grid.vue'
  63. import slotMachinePage from './prizeDraw/slotMachine.vue'
  64. import { onMounted, ref } from 'vue'
  65. import { getLuckLotteryRecordByOrderId } from '@/api/mall/prize'
  66. import { getMallUserAddressList } from '@/api/mall/address'
  67. import Snackbar from '@/plugins/snackbar'
  68. import { luckyLotteryRecordReceive } from '@/api/mall/prize'
  69. import { useRouter } from 'vue-router'
  70. import { getDict } from '@/hooks/web/useDictionaries'
  71. const emit = defineEmits(['success'])
  72. const props = defineProps({
  73. lotteryId: [Number, String],
  74. orderId: [Number, String],
  75. type: {
  76. type: String,
  77. default: '1'
  78. }
  79. })
  80. const showDialog = ref(false)
  81. onMounted(() =>{
  82. if (localStorage.getItem('showLotteryBefore')) {
  83. // 已经点击过抽奖按钮,直接展示奖品。例如刷新支付完成页面
  84. showPrize.value = true
  85. } else {
  86. // 刚进入支付完成页面
  87. showDialog.value = true
  88. }
  89. })
  90. const router = useRouter()
  91. const newAddress = ref({
  92. name: '',
  93. areaId: '',
  94. areaName: '',
  95. mobile: '',
  96. detailAddress: ''
  97. })
  98. const addressSelect = ref()
  99. const disabled = ref(false)
  100. const addressFormRef = ref()
  101. const cascaderAddr = ref()
  102. const areaTreeData = ref([])
  103. getDict('areaTreeData', null, 'areaTreeData').then(({ data }) => {
  104. data = data?.length && data || []
  105. areaTreeData.value = data
  106. })
  107. const phoneRules = ref([
  108. value => {
  109. if (value) return true
  110. return t('login.mobileNumberPlaceholder')
  111. },
  112. value => {
  113. if (value?.length <= 11 && /^1[3456789]\d{9}$/.test(value)) return true
  114. return t('login.correctPhoneNumber')
  115. }
  116. ])
  117. // 地区选择
  118. const handleChangeArea = () => {
  119. const node = cascaderAddr.value.getCheckedNodes() ? cascaderAddr.value.getCheckedNodes()[0] : null
  120. if (!node) return
  121. newAddress.value.areaName = node.pathLabels.join(' ')
  122. }
  123. // 获取中奖记录、收货地址
  124. const address = ref([])
  125. const prizeData = ref({})
  126. const getRecord = async () => {
  127. const data = await getLuckLotteryRecordByOrderId(props.orderId)
  128. prizeData.value = data || []
  129. if (!data || !data.length) disabled.value = true
  130. const addressData = await getMallUserAddressList()
  131. address.value = [...addressData, { id: 9999, label: '使用新地址' }] || []
  132. if (addressData && addressData.length) addressSelect.value = addressData[0].id
  133. }
  134. if (props.orderId) getRecord()
  135. const showPrize = ref(false)
  136. const endCallback = () => {
  137. localStorage.setItem('showLotteryBefore', true) // 标记已抽奖
  138. showDialog.value = false
  139. showPrize.value = true
  140. }
  141. function checkValue(obj) {
  142. for (let key in obj) {
  143. if (obj.hasOwnProperty(key) && !obj[key]) {
  144. return false
  145. }
  146. }
  147. return true
  148. }
  149. // 领取
  150. const handleSubmit = async () => {
  151. let query = {}
  152. if (addressSelect.value === 9999) {
  153. if (!checkValue(newAddress.value)) return Snackbar.warning('请完善收货信息')
  154. query = newAddress.value
  155. } else query = address.value.find(item => item.id === addressSelect.value)
  156. await luckyLotteryRecordReceive({ id: prizeData.value[0].record.id, receiveInfo: JSON.stringify(query) })
  157. localStorage.removeItem('showLotteryBefore') // 清空已抽奖痕迹
  158. Snackbar.success('奖品领取成功,待商家发货')
  159. router.replace('/recruit/personal/personalCenter/tradeOrder?key=1')
  160. }
  161. </script>
  162. <style scoped lang="scss">
  163. .prizeDrawBox {
  164. padding: 20px 40px;
  165. background-color: var(--default-bgc);
  166. }
  167. .prizeDraw {
  168. margin: 0 auto;
  169. }
  170. .numberBox {
  171. font-size: 20px;
  172. font-weight: bold;
  173. padding: 2px 38px;
  174. border-bottom: 3px solid var(--v-primary-base);
  175. }
  176. .colorBase {
  177. color: var(--v-primary-base);
  178. margin: 0 6px;
  179. font-size: 22px;
  180. }
  181. </style>