Files
xdd-uniapp-new/pkg-video/views/county-claim-address.vue
T

747 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="claim-page">
<view class="custom-header" :style="{ paddingTop: `${statusBarHeight}px` }">
<view class="header-inner">
<view class="header-back" @click="goBack">
<text class="header-back-icon"></text>
</view>
<view class="header-title">填写收货地址</view>
<view class="header-right">
<view class="dot"></view>
<view class="ring"></view>
</view>
</view>
</view>
<scroll-view class="page-body" scroll-y :style="{ paddingTop: `calc(${statusBarHeight}px + 88rpx)` }">
<view class="section-title">奖品信息</view>
<view class="card prize-card">
<view class="prize-image-wrap">
<image class="prize-image" :src="prizeImage" mode="aspectFill" />
</view>
<view class="prize-info">
<view class="prize-name">{{ form.prizeName || '神秘奖品' }}</view>
<view class="prize-desc">颜色随机</view>
<view class="prize-code">抽奖码{{ form.ticketCode || '--' }}</view>
</view>
</view>
<view class="card form-card">
<view class="form-row">
<text class="label">收货人</text>
<input v-model="form.realName" class="input" placeholder="张三" placeholder-style="color:#999;" />
</view>
<view class="form-row">
<text class="label">手机号码</text>
<input
v-model="form.phone"
class="input"
type="number"
maxlength="11"
placeholder="12345678910"
placeholder-style="color:#999;"
/>
</view>
<view class="form-row">
<text class="label">所在地区</text>
<view class="city-wrap">
<view class="city-select" :class="{'has-val': !!addressText}">
<CitySelect
ref="cityselect"
:defaultValue="addressText || '请选择'"
:items="district"
@callback="onCityChange"
/>
</view>
<text class="iconfont icon-dizhi locate-icon" @click="getCurAddressFn"></text>
</view>
</view>
<view class="form-row no-border">
<text class="label">详细地址</text>
<input v-model="form.detail" class="input" placeholder="请填写具体地址" placeholder-style="color:#999;" />
</view>
<view class="analysis-box">
<textarea
:value="addressInput"
@input="onAddressInput"
placeholder="请粘贴收件人手机号、姓名、收货地址并用空格区分,系统将自动识别地址信息"
placeholder-style="font-size:24rpx;color:#999;"
class="analysis-textarea"
/>
<view class="analysis-actions">
<view class="action-btn btn-clear" @click="clearAddressInput">清空</view>
<view class="action-btn btn-recognize" :class="{ disabled: !addressInput }" @click="recognizeAddress">识别</view>
</view>
</view>
</view>
<view class="tips">*请仔细核对收货信息提交后不可修改奖品将在7个工作日内寄出</view>
</scroll-view>
<view class="submit-wrap">
<view class="submit-btn" @click="submit">确认提交</view>
</view>
<view class="popup-mask" v-if="showRealnamePopup" @click="closePopup">
<view class="popup-panel auth-panel" @click.stop>
<view class="popup-close" @click="closePopup">×</view>
<view class="popup-icon-wrap">
<text class="popup-icon">🪪</text>
</view>
<view class="popup-title">实名认证</view>
<view class="popup-desc">根据平台活动规则领取电子数码产品需要进行实名认证</view>
<view class="popup-actions">
<view class="popup-btn btn-confirm btn-wide" @click="goRealname">去实名认证</view>
</view>
</view>
</view>
<view class="popup-mask" v-if="showSubmitSuccessPopup" @click="closePopup">
<view class="popup-panel success-panel" @click.stop>
<view class="popup-close" @click="closePopup">×</view>
<view class="popup-icon-wrap">
<text class="popup-icon">🎉</text>
</view>
<view class="popup-title">提交成功</view>
<view class="popup-desc">奖品将在7个工作日内寄出</view>
<view class="popup-actions">
<view class="popup-btn btn-ghost" @click="confirmSuccess">返回</view>
<view class="popup-btn btn-confirm" @click="goMyTicket">查看</view>
</view>
</view>
</view>
</view>
</template>
<script>
import CitySelect from '@/components/CitySelect'
import { getCity, analysisAddress, postAddress } from '@/api/user'
import { claimCoupon, claimPrize, getDrawRealname } from '@/api/lottery'
import { getCurAddress, getLocation } from '@/utils/common'
export default {
name: 'CountyClaimAddressPage',
components: { CitySelect },
data() {
return {
statusBarHeight: 20,
district: [],
addressText: '',
addressInput: '',
address: {
province: '',
city: '',
district: ''
},
form: {
lotteryRecordId: '',
prizeName: '',
prizeType: '',
prizeTypeName: '',
ticketCode: '',
realName: '',
phone: '',
detail: ''
},
showRealnamePopup: true,
showSubmitSuccessPopup: false,
userInfo: {},
realnameStatus: 0,
waitSubmitAfterRealname: false,
submitting: false
}
},
computed: {
prizeImage() {
return 'https://img2.baidu.com/it/u=1255257059,3076495012&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800'
}
},
onLoad(options) {
this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight || 20
this.form.lotteryRecordId = options.lotteryRecordId || ''
this.form.prizeName = decodeURIComponent(options.prizeName || '')
this.form.prizeType = decodeURIComponent(options.prizeType || '')
this.form.prizeTypeName = decodeURIComponent(options.prizeTypeName || '')
this.form.ticketCode = decodeURIComponent(options.ticketCode || '')
this.getCityList()
this.fetchRealnameStatus()
},
onShow() {
const done = uni.getStorageSync('countyClaimAuthDone')
if (done && this.waitSubmitAfterRealname) {
uni.removeStorageSync('countyClaimAuthDone')
this.fetchRealnameStatus().then(() => {
this.submitPhysicalClaim()
})
}
},
methods: {
goBack() {
uni.navigateBack()
},
getCityList() {
getCity().then(res => {
this.district = res.data || []
})
},
fetchRealnameStatus() {
return getDrawRealname().then((res) => {
const data = (res && res.data) || {}
this.realnameStatus = Number(data.status || 0)
}).catch(() => {
this.realnameStatus = 0
})
},
isDigitalPrize() {
const typeVal = String(this.form.prizeType || '').toLowerCase()
const typeName = String(this.form.prizeTypeName || '').toLowerCase()
const prizeName = String(this.form.prizeName || '').toLowerCase()
if (['1', 'electronic', 'digital', 'electronics'].includes(typeVal)) return true
if (/电子|数码/.test(typeName)) return true
return /电子|数码/.test(prizeName)
},
hasRealNameAuth() {
if (Number(this.realnameStatus) === 1) return true
const user = this.userInfo || {}
const flag = [
user.isRealName,
user.realNameAuth,
user.isAuth,
user.authStatus,
user.realNameStatus,
user.idAuthStatus
]
if (flag.some(v => Number(v) === 1 || v === true || String(v).toUpperCase() === 'Y')) return true
if (Number(user.authStatus) === 2 || Number(user.realNameStatus) === 2 || Number(user.idAuthStatus) === 2) return true
return !!(String(user.realName || '').trim() && String(user.idCard || user.idcard || '').trim())
},
isCouponPrize() {
const typeVal = String(this.form.prizeType || '').toLowerCase()
const typeName = String(this.form.prizeTypeName || '')
const prizeName = String(this.form.prizeName || '')
if (['3', 'coupon'].includes(typeVal)) return true
return /券/.test(typeName) || /券/.test(prizeName)
},
async createAddress() {
const payload = {
id: '',
real_name: this.form.realName,
phone: this.form.phone,
address: this.address,
detail: this.form.detail,
is_default: false,
post_code: ''
}
const res = await postAddress(payload)
const addressId = Number(res && res.data && res.data.id)
if (!addressId) {
throw new Error('地址保存失败,请重试')
}
return addressId
},
validatePhysicalForm() {
if (!this.form.realName) {
uni.showToast({ title: '请填写收货人', icon: 'none' })
return false
}
if (!/^1\d{10}$/.test(this.form.phone)) {
uni.showToast({ title: '请输入正确手机号', icon: 'none' })
return false
}
if (!this.addressText) {
uni.showToast({ title: '请选择所在地区', icon: 'none' })
return false
}
if (!this.form.detail) {
uni.showToast({ title: '请填写详细地址', icon: 'none' })
return false
}
return true
},
async submitCouponClaim() {
const ticketId = Number(this.form.lotteryRecordId)
if (!ticketId) {
uni.showToast({ title: '缺少抽奖券ID', icon: 'none' })
return
}
await claimCoupon(ticketId)
this.showSubmitSuccessPopup = true
},
async submitPhysicalClaim() {
if (this.submitting) return
if (!this.validatePhysicalForm()) return
const ticketId = Number(this.form.lotteryRecordId)
if (!ticketId) {
uni.showToast({ title: '缺少抽奖券ID', icon: 'none' })
return
}
this.submitting = true
uni.showLoading({ title: '提交中...' })
try {
if (this.isDigitalPrize()) {
await this.fetchRealnameStatus()
if (!this.hasRealNameAuth()) {
this.waitSubmitAfterRealname = true
this.showRealnamePopup = true
return
}
}
const addressId = await this.createAddress()
await claimPrize(ticketId, addressId)
this.waitSubmitAfterRealname = false
this.showSubmitSuccessPopup = true
} catch (e) {
uni.showToast({
title: (e && e.msg) || (e && e.message) || '提交失败',
icon: 'none'
})
} finally {
uni.hideLoading()
this.submitting = false
}
},
onCityChange(values) {
this.address = {
province: values.province.name || '',
city: values.city.name || '',
district: values.district.name || '',
city_id: values.city.id
}
this.addressText = `${this.address.province} ${this.address.city} ${this.address.district}`
},
async getCurAddressFn() {
uni.showLoading({ title: '定位中...' })
try {
const map = await getLocation()
if (map.length > 1) {
const { latitude, longitude } = map[1]
getCurAddress(latitude, longitude, (addr) => {
this.address = {
province: addr.province || '',
city: addr.city || '',
district: addr.county || ''
}
this.addressText = `${this.address.province} ${this.address.city} ${this.address.district}`
this.form.detail = addr.formattedAddress || this.form.detail
})
}
} finally {
uni.hideLoading()
}
},
onAddressInput(e) {
this.addressInput = (e.detail && e.detail.value ? e.detail.value : '').trim()
},
clearAddressInput() {
this.addressInput = ''
},
recognizeAddress() {
if (!this.addressInput) return
uni.showLoading({ title: '识别中...' })
analysisAddress({ content: this.addressInput }).then((res) => {
uni.hideLoading()
const data = (res && res.data) || {}
this.form.realName = data.realName || this.form.realName
this.form.phone = data.phone || this.form.phone
this.form.detail = data.detail || this.form.detail
this.address = {
province: data.province || '',
city: data.city || '',
district: data.district || '',
city_id: data.cityId
}
this.addressText = `${this.address.province} ${this.address.city} ${this.address.district}`.trim()
}).catch(() => {
uni.hideLoading()
uni.showToast({
title: '识别失败,请手动填写',
icon: 'none'
})
})
},
async submit() {
if (this.isCouponPrize()) {
this.submitting = true
uni.showLoading({ title: '领取中...' })
try {
await this.submitCouponClaim()
} catch (e) {
uni.showToast({
title: (e && e.msg) || (e && e.message) || '领取失败',
icon: 'none'
})
} finally {
uni.hideLoading()
this.submitting = false
}
return
}
this.submitPhysicalClaim()
},
closePopup() {
this.showRealnamePopup = false
this.showSubmitSuccessPopup = false
},
goRealname() {
this.showRealnamePopup = false
uni.navigateTo({
url: '/pkg-video/views/county-realname'
})
},
confirmSuccess() {
this.showSubmitSuccessPopup = false
uni.navigateBack()
},
goMyTicket() {
this.showSubmitSuccessPopup = false
uni.navigateTo({
url: '/pkg-video/views/county-my-tickets'
})
}
}
}
</script>
<style scoped lang="less">
.claim-page {
min-height: 100vh;
background: #f5f6f8;
}
.custom-header {
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 20;
background: #fff;
}
.header-inner {
height: 88rpx;
display: flex;
align-items: center;
padding: 0 24rpx;
}
.header-back {
width: 56rpx;
height: 56rpx;
display: flex;
align-items: center;
justify-content: center;
}
.header-back-icon {
font-size: 60rpx;
color: #111;
line-height: 1;
}
.header-title {
flex: 1;
text-align: center;
font-size: 34rpx;
font-weight: 700;
color: #222;
}
.header-right {
width: 88rpx;
height: 44rpx;
border-radius: 24rpx;
border: 2rpx solid #d8d8d8;
background: #fff;
display: flex;
align-items: center;
justify-content: center;
}
.dot {
width: 8rpx;
height: 8rpx;
border-radius: 50%;
background: #111;
margin-right: 14rpx;
}
.ring {
width: 18rpx;
height: 18rpx;
border: 2rpx solid #111;
border-radius: 50%;
}
.page-body {
height: 100vh;
box-sizing: border-box;
padding: 20rpx 24rpx 220rpx;
}
.section-title {
color: #999;
font-size: 26rpx;
margin: 10rpx 4rpx 16rpx;
}
.card {
background: #fff;
border-radius: 24rpx;
margin-bottom: 24rpx;
}
.prize-card {
display: flex;
align-items: center;
padding: 24rpx;
}
.prize-image-wrap {
width: 140rpx;
height: 140rpx;
border-radius: 16rpx;
border: 2rpx solid #f0f0f0;
margin-right: 24rpx;
overflow: hidden;
flex-shrink: 0;
}
.prize-image {
width: 100%;
height: 100%;
}
.prize-info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
}
.prize-name {
font-size: 32rpx;
font-weight: 700;
color: #333;
margin-bottom: 12rpx;
}
.prize-desc,
.prize-code {
font-size: 24rpx;
color: #999;
margin-top: 6rpx;
}
.form-card {
padding: 10rpx 24rpx 24rpx;
}
.form-row {
min-height: 100rpx;
display: flex;
align-items: center;
border-bottom: 2rpx dashed #eee;
}
.form-row.no-border {
border-bottom: none;
}
.label {
width: 150rpx;
color: #333;
font-size: 28rpx;
}
.input {
flex: 1;
color: #333;
font-size: 28rpx;
}
.city-wrap {
flex: 1;
display: flex;
align-items: center;
}
.city-select {
flex: 1;
color: #999;
font-size: 28rpx;
}
.city-select.has-val {
color: #333;
}
.locate-icon {
color: #666;
font-size: 36rpx;
margin-left: 20rpx;
}
.analysis-box {
background: #f8f8f8;
border-radius: 16rpx;
padding: 20rpx;
margin-top: 10rpx;
}
.analysis-textarea {
width: 100%;
height: 100rpx;
color: #333;
font-size: 26rpx;
}
.analysis-actions {
display: flex;
justify-content: flex-end;
align-items: center;
margin-top: 16rpx;
}
.action-btn {
font-size: 24rpx;
border-radius: 30rpx;
text-align: center;
}
.btn-clear {
color: #BD3124;
border: 2rpx solid #BD3124;
padding: 6rpx 28rpx;
margin-right: 20rpx;
background: transparent;
}
.btn-recognize {
color: #fff;
background: #BD3124;
border: 2rpx solid #BD3124;
padding: 6rpx 30rpx;
}
.btn-recognize.disabled {
opacity: 0.6;
}
.tips {
color: #666;
font-size: 22rpx;
line-height: 1.5;
margin: 20rpx 10rpx;
}
.submit-wrap {
position: fixed;
left: 0;
right: 0;
bottom: 0;
background: #f5f6f8;
padding: 20rpx 40rpx calc(20rpx + env(safe-area-inset-bottom));
}
.submit-btn {
height: 90rpx;
border-radius: 45rpx;
background: #BD3124;
color: #fff;
text-align: center;
line-height: 90rpx;
font-size: 32rpx;
font-weight: 500;
}
.popup-mask {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.48);
display: flex;
align-items: center;
justify-content: center;
z-index: 100;
padding: 0 52rpx;
}
.popup-panel {
width: 100%;
background: #fff;
border-radius: 24rpx;
padding: 40rpx 32rpx 32rpx;
position: relative;
}
.popup-title {
text-align: center;
color: #222;
font-size: 34rpx;
font-weight: 700;
}
.popup-desc {
color: #666;
font-size: 26rpx;
line-height: 1.6;
text-align: center;
margin-top: 14rpx;
}
.popup-close {
position: absolute;
right: 20rpx;
top: 16rpx;
width: 44rpx;
height: 44rpx;
border: 2rpx solid #111;
border-radius: 50%;
font-size: 32rpx;
line-height: 38rpx;
text-align: center;
color: #111;
}
.popup-icon-wrap {
display: flex;
justify-content: center;
}
.popup-icon {
font-size: 54rpx;
}
.popup-actions {
display: flex;
align-items: center;
justify-content: center;
margin-top: 30rpx;
}
.popup-btn {
min-width: 180rpx;
height: 72rpx;
line-height: 72rpx;
border-radius: 36rpx;
text-align: center;
font-size: 28rpx;
}
.btn-confirm {
color: #fff;
background: #BD3124;
}
.btn-wide {
width: 100%;
}
.btn-ghost {
color: #BD3124;
border: 2rpx solid #BD3124;
background: #fff;
margin-right: 22rpx;
}
</style>