feat: 抖音核销接入小泥人API、公告详情页、景区预约人选人等多处优化

抖音核销(douyin-verify):
- 对接小泥人 OAuth2 token 与 voucher-list 券码接口,按 code 分组展示订单券号及可激活次数
- 支持手动输入券码验证券码;核销流程改为先调后端 sendAndBind 发卡绑定,再验证券码
- 购卡须知改为富文本渲染,新增无可核销订单提示弹窗、客服电话拨打
- 增加 product_id 过滤与 per-page=100,验证券码命中后仅展示不弹提示

公告模块:
- 首页/公告列表点击跳转到新增公告详情页(notice-detail),展示标题、发布时间、富文本内容及视频
- 公告列表卡片改为标题+发布时间+查看详情按钮,时间与按钮同排
- 富文本支持内嵌 video 解析播放;content 为空不显示分隔线;标题取公告 title 而非类型

首页与价格:
- 首页大卡价格/划线价/立省改为商品详情接口动态获取
- 热门景区列表扩展至8条,支持优惠/折扣标签与默认占位图

预约/景区:
- 预约页改为选择预约人(可选/已预约置灰),预约参数改用预约人信息
- 景区列表与详情支持优惠类型、折扣、特惠价展示,富文本图片防溢出
- 景区列表移除自定义导航改用原生导航

订单/绑卡:
- 订单列表/详情增加抖音核销单号(thirdOrderNo)展示,核销订单隐藏金额与退款入口
- 绑卡页移除人脸可选开关,照片必传改为拍照
- 其他:图片域名统一为 hn12301,tabBar'旅游卡'改名,登录页支持 redirect 回跳
This commit is contained in:
lcj
2026-08-07 10:45:53 +08:00
parent 40cebaa3a5
commit f0911c67a0
18 changed files with 1076 additions and 421 deletions
+4 -23
View File
@@ -20,7 +20,6 @@
placeholder="请输入卡号"
placeholder-class="placeholder"
:disabled="faceBindMode"
@blur="onCardNoBlur"
/>
</view>
<view class="divider" />
@@ -75,7 +74,7 @@
<view class="divider" />
<!-- 持卡人照片 -->
<view v-if="needFaceBind" class="form-row form-row--photo">
<view class="form-row form-row--photo">
<text class="form-label form-label--top">持卡人照片</text>
<view class="upload-area" @tap="photoUrl ? previewPhoto() : chooseImage()">
<image v-if="photoUrl" class="upload-preview" :src="photoUrl" mode="aspectFit" />
@@ -152,7 +151,7 @@
<script setup lang="ts">
import { ref, reactive, computed, watch } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { checkFaceFlag, uploadImage, bindCard as apiBindCard, bindFaceImg } from '../api/card'
import { uploadImage, bindCard as apiBindCard, bindFaceImg } from '../api/card'
const faceBindMode = ref(false)
@@ -187,7 +186,6 @@ const photoUrl = ref('')
const agreed = ref(false)
const submitting = ref(false)
const uploading = ref(false)
const needFaceBind = ref(false)
const showIdTypePicker = ref(false)
const idTypePopup = ref<any>(null)
@@ -200,15 +198,8 @@ onLoad(async (options) => {
const idType = options.idType || ''
docType.value = idType || '1'
form.idCard = options.idNo || ''
needFaceBind.value = true
} else if (options?.redeemCode) {
form.cardNo = options.redeemCode
try {
const res = await checkFaceFlag(options.redeemCode)
needFaceBind.value = !!res
} catch {
needFaceBind.value = false
}
}
})
@@ -227,22 +218,12 @@ function selectIdType(value: string) {
showIdTypePicker.value = false
}
async function onCardNoBlur() {
if (!form.cardNo.trim()) return
try {
const res = await checkFaceFlag(form.cardNo.trim())
needFaceBind.value = !!res
} catch {
needFaceBind.value = false
}
}
function chooseImage() {
if (uploading.value) return
uni.chooseImage({
count: 1,
sizeType: ['original'],
sourceType: ['album', 'camera'],
sourceType: ['camera'],
success: (res) => handleImage(res.tempFilePaths[0]),
fail: (err) => {
if (!err.errMsg.includes('cancel')) console.log('选择图片失败:', err)
@@ -316,7 +297,7 @@ function validateForm() {
if (!/^1[3-9]\d{9}$/.test(form.phone)) return '手机号格式不正确'
if (!form.idCard.trim()) return `请输入${idTypeLabel.value}号码`
if (docType.value === '1' && !/^\d{17}[\dXx]$/.test(form.idCard)) return '身份证号格式不正确'
if (needFaceBind.value && !photoUrl.value) return '请上传持卡人照片'
if (!photoUrl.value) return '请上传持卡人照片'
return ''
}