feat: 年卡相关页面(列表/详情/购买/激活/入园码/绑定)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
jacobxu666
2026-06-14 17:35:33 +08:00
co-authored by Claude Opus 4.8
parent 2293e67f8c
commit b4981587a2
6 changed files with 552 additions and 6 deletions
+104 -1
View File
@@ -1,3 +1,106 @@
<template>
<view><text>页面占位 - 后续任务实现</text></view>
<view class="page">
<!-- 年卡信息头部 -->
<view class="card-info">
<text class="card-name">{{ cardName }}</text>
<text class="card-tip">请填写实名信息以激活年卡</text>
</view>
<!-- 实名表单 -->
<view class="form-card">
<view class="form-item">
<text class="label">真实姓名</text>
<input class="input" v-model="form.realName" placeholder="请输入真实姓名" />
</view>
<view class="form-item">
<text class="label">身份证号</text>
<input class="input" v-model="form.idCard" placeholder="请输入身份证号" />
</view>
<view class="form-item">
<text class="label">手机号码</text>
<input class="input" v-model="form.phone" placeholder="请输入手机号码" type="number" />
</view>
</view>
<!-- 激活按钮 -->
<view class="btn-area">
<button class="btn-activate" @click="handleActivate" :disabled="activating">
{{ activating ? '激活中...' : '立即激活' }}
</button>
</view>
</view>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { useCardStore } from '../../../../store/card'
import { showToast } from '../../../../utils'
const cardStore = useCardStore()
const cardId = ref('')
const cardName = ref('')
const activating = ref(false)
/** 实名信息表单 */
const form = reactive({
realName: '',
idCard: '',
phone: ''
})
/** 页面加载时解析路由参数 */
onLoad((options) => {
cardId.value = options?.cardId || ''
cardName.value = decodeURIComponent(options?.name || '')
})
/** 表单校验 */
function validate(): boolean {
if (!form.realName.trim()) {
showToast('请输入真实姓名')
return false
}
if (!/^\d{17}[\dXx]$/.test(form.idCard)) {
showToast('请输入正确的身份证号')
return false
}
if (!/^1\d{10}$/.test(form.phone)) {
showToast('请输入正确的手机号码')
return false
}
return true
}
/** 提交激活 */
async function handleActivate() {
if (!validate()) return
if (!cardId.value) return
activating.value = true
try {
await cardStore.activateCard(cardId.value, form)
showToast('激活成功', 'success')
// 激活成功后跳转入园码页
setTimeout(() => {
uni.redirectTo({ url: `/packages/user/pages/card/qrcode?cardId=${cardId.value}` })
}, 1500)
} catch (err: any) {
showToast(err.message || '激活失败')
} finally {
activating.value = false
}
}
</script>
<style scoped>
.page { min-height: 100vh; background: #f5f5f5; padding: 20rpx; box-sizing: border-box; }
.card-info { background: #4A90D9; border-radius: 16rpx; padding: 30rpx; margin-bottom: 20rpx; }
.card-name { font-size: 34rpx; font-weight: bold; color: #fff; display: block; margin-bottom: 8rpx; }
.card-tip { font-size: 24rpx; color: rgba(255,255,255,0.8); }
.form-card { background: #fff; border-radius: 16rpx; padding: 10rpx 30rpx; }
.form-item { padding: 24rpx 0; border-bottom: 1rpx solid #f0f0f0; }
.form-item:last-child { border-bottom: none; }
.label { display: block; font-size: 26rpx; color: #666; margin-bottom: 12rpx; }
.input { width: 100%; height: 80rpx; font-size: 30rpx; color: #333; box-sizing: border-box; }
.btn-area { padding: 40rpx 20rpx; }
.btn-activate { width: 100%; height: 96rpx; line-height: 96rpx; background: #4A90D9; color: #fff; border-radius: 48rpx; font-size: 32rpx; border: none; }
.btn-activate[disabled] { background: #A5C8E8; }
</style>