初始化
This commit is contained in:
@@ -0,0 +1,339 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="card block">
|
||||
<view class="row between">
|
||||
<view class="name">{{ vm.project.name }}</view>
|
||||
<view class="price">¥{{ vm.amount }}</view>
|
||||
</view>
|
||||
<view class="muted meta" v-if="vm.type === 'booking'">
|
||||
{{ vm.date }} {{ vm.slot }} · {{ vm.techName }}
|
||||
</view>
|
||||
<view class="muted meta" v-else>{{ vm.planLabel }} · {{ vm.validText }}</view>
|
||||
</view>
|
||||
|
||||
<view class="card block">
|
||||
<view class="title">订单信息</view>
|
||||
<view class="line row between">
|
||||
<view class="muted">类型</view>
|
||||
<view>{{ vm.type === 'booking' ? '预约订单' : '购买卡券' }}</view>
|
||||
</view>
|
||||
<view class="line row between">
|
||||
<view class="muted">单价</view>
|
||||
<view>¥{{ vm.amount }}</view>
|
||||
</view>
|
||||
<view class="line row between">
|
||||
<view class="muted">数量</view>
|
||||
<view>1</view>
|
||||
</view>
|
||||
<view class="line row between">
|
||||
<view class="muted">合计</view>
|
||||
<view class="sum">¥{{ vm.amount }}</view>
|
||||
</view>
|
||||
<view class="line row between" v-if="vm.note">
|
||||
<view class="muted">备注</view>
|
||||
<view class="note">{{ vm.note }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card block">
|
||||
<view class="title">规则摘要</view>
|
||||
<view class="muted rline" v-if="vm.type === 'booking'">改约:可在“我的预约”中发起改约(原型演示)。</view>
|
||||
<view class="muted rline" v-if="vm.type === 'booking'">取消:支持取消预约,取消后订单状态变为已取消。</view>
|
||||
<view class="muted rline" v-if="vm.type === 'booking'">爽约:商用版可按门店策略收取爽约金(此处占位)。</view>
|
||||
<view class="muted rline" v-if="vm.type !== 'booking'">有效期:以卡券类型展示为准,过期后不可核销(原型演示)。</view>
|
||||
<view class="muted rline" v-if="vm.type !== 'booking'">核销:到店出示核销码,核销后自动扣次。</view>
|
||||
</view>
|
||||
|
||||
<view class="card block" v-if="vm.type !== 'booking'">
|
||||
<view class="title">订单类型</view>
|
||||
<view class="plans">
|
||||
<view
|
||||
v-for="p in plans"
|
||||
:key="p.key"
|
||||
class="plan"
|
||||
:class="{ on: p.key === vm.planKey }"
|
||||
@tap="selectPlan(p.key)"
|
||||
>
|
||||
<view class="p1">{{ p.label }}</view>
|
||||
<view class="muted p2">{{ p.validText }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="muted hint">购买后可在“我的卡券/次卡”里查看,预约后到店核销。</view>
|
||||
</view>
|
||||
|
||||
<view class="card block">
|
||||
<view class="title">支付方式</view>
|
||||
<view class="pay row between">
|
||||
<view class="row">
|
||||
<view class="p-icon">W</view>
|
||||
<view class="p-text">微信支付(原型模拟)</view>
|
||||
</view>
|
||||
<view class="tag">默认</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="btn btn-primary submit" @tap="mockPay">去支付</view>
|
||||
<view class="btn btn-ghost submit2" @tap="saveUnpaid">先保存为待付款</view>
|
||||
<AiFloat />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AiFloat from '@/components/AiFloat.vue'
|
||||
import { projects } from '@/common/mockData'
|
||||
|
||||
const fallbackProjects = [
|
||||
{
|
||||
id: 'p1',
|
||||
categoryId: 'c1',
|
||||
name: '水氧净透体验',
|
||||
price: 99,
|
||||
originPrice: 199,
|
||||
durationMin: 60,
|
||||
fitFor: '初次体验、暗沉、出油',
|
||||
taboo: '近期激光/微针术后 7 天内不建议',
|
||||
cover: '',
|
||||
desc: '轻盈水氧 + 净透护理,适合快速提升肤感与通透度。'
|
||||
}
|
||||
]
|
||||
|
||||
function safeJsonParse(s) {
|
||||
try {
|
||||
return JSON.parse(s)
|
||||
} catch (e) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
components: { AiFloat },
|
||||
data() {
|
||||
const safeProjects = Array.isArray(projects) && projects.length ? projects : fallbackProjects
|
||||
const initProject = safeProjects[0]
|
||||
const initPlan = { key: 'single', label: '单次券', validText: '有效期 30 天', times: 1, mul: 1 }
|
||||
return {
|
||||
safeProjects,
|
||||
vm: {
|
||||
type: 'coupon',
|
||||
project: initProject,
|
||||
note: '',
|
||||
planKey: initPlan.key,
|
||||
planLabel: initPlan.label,
|
||||
validText: initPlan.validText,
|
||||
times: initPlan.times,
|
||||
amount: initProject ? Math.round(initProject.price * initPlan.mul) : 99
|
||||
},
|
||||
plans: [
|
||||
{ key: 'single', label: '单次券', validText: '有效期 30 天', times: 1, mul: 1 },
|
||||
{ key: 'times5', label: '次卡 5 次', validText: '有效期 180 天', times: 5, mul: 4.2 },
|
||||
{ key: 'package', label: '套餐', validText: '有效期 90 天', times: 3, mul: 2.6 }
|
||||
]
|
||||
}
|
||||
},
|
||||
onLoad(query) {
|
||||
try {
|
||||
const payload = query.payload ? safeJsonParse(decodeURIComponent(query.payload)) : null
|
||||
const safeProjects = Array.isArray(this.safeProjects) && this.safeProjects.length ? this.safeProjects : fallbackProjects
|
||||
|
||||
if (payload && payload.type === 'booking') {
|
||||
const p = safeProjects.find((x) => x.id === payload.projectId) || safeProjects[0]
|
||||
const amount = p ? p.price : 99
|
||||
this.vm = {
|
||||
type: 'booking',
|
||||
project: p || fallbackProjects[0],
|
||||
amount,
|
||||
planKey: '',
|
||||
planLabel: '预约订单',
|
||||
validText: '',
|
||||
times: 0,
|
||||
date: payload.date || '',
|
||||
slot: payload.slot || '',
|
||||
techId: payload.techId || '',
|
||||
techName: payload.techName || '自动分配',
|
||||
note: payload.note || ''
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const projectId = query.projectId || ''
|
||||
const p = safeProjects.find((x) => x.id === projectId) || safeProjects.find((x) => x.categoryId === 'c5') || safeProjects[0]
|
||||
const basePlanKey = p && p.categoryId === 'c5' ? 'times5' : 'single'
|
||||
const plan = this.plans.find((x) => x.key === basePlanKey) || this.plans[0]
|
||||
const price = p ? p.price : 99
|
||||
const amount = Math.round(price * plan.mul)
|
||||
this.vm = {
|
||||
type: 'coupon',
|
||||
project: p || fallbackProjects[0],
|
||||
note: '',
|
||||
planKey: plan.key,
|
||||
planLabel: plan.label,
|
||||
validText: plan.validText,
|
||||
times: plan.times,
|
||||
amount
|
||||
}
|
||||
} catch (e) {
|
||||
const p = (Array.isArray(this.safeProjects) && this.safeProjects[0]) || fallbackProjects[0]
|
||||
const plan = this.plans[0]
|
||||
this.vm = {
|
||||
type: 'coupon',
|
||||
project: p,
|
||||
note: '',
|
||||
planKey: plan.key,
|
||||
planLabel: plan.label,
|
||||
validText: plan.validText,
|
||||
times: plan.times,
|
||||
amount: Math.round((p ? p.price : 99) * plan.mul)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
selectPlan(key) {
|
||||
const p = this.plans.find((x) => x.key === key) || this.plans[0]
|
||||
const amount = Math.round(this.vm.project.price * p.mul)
|
||||
this.vm = {
|
||||
...this.vm,
|
||||
planKey: p.key,
|
||||
planLabel: p.label,
|
||||
validText: p.validText,
|
||||
times: p.times,
|
||||
amount
|
||||
}
|
||||
},
|
||||
buildOrder(status) {
|
||||
const now = Date.now()
|
||||
const id = `ord_demo_${now}`
|
||||
const base = {
|
||||
id,
|
||||
createdAt: now,
|
||||
status,
|
||||
amount: this.vm.amount,
|
||||
projectId: this.vm.project.id,
|
||||
projectName: this.vm.project.name,
|
||||
durationMin: this.vm.project.durationMin
|
||||
}
|
||||
if (this.vm.type === 'booking') {
|
||||
return {
|
||||
...base,
|
||||
orderType: 'booking',
|
||||
appointmentDate: this.vm.date,
|
||||
appointmentSlot: this.vm.slot,
|
||||
technicianName: this.vm.techName,
|
||||
note: this.vm.note || '',
|
||||
verifyCode: `VC${now}`
|
||||
}
|
||||
}
|
||||
return {
|
||||
...base,
|
||||
orderType: 'coupon',
|
||||
couponTitle: this.vm.project.name,
|
||||
couponPlanKey: this.vm.planKey,
|
||||
couponPlanLabel: this.vm.planLabel,
|
||||
validText: this.vm.validText,
|
||||
remainingTimes: this.vm.times || 1,
|
||||
verifyCode: `VC${now}`
|
||||
}
|
||||
},
|
||||
mockPay() {
|
||||
const order = this.buildOrder('待核销')
|
||||
const payload = encodeURIComponent(JSON.stringify(order))
|
||||
uni.redirectTo({ url: `/pages/verify/code?payload=${payload}` })
|
||||
},
|
||||
saveUnpaid() {
|
||||
const order = this.buildOrder('待付款')
|
||||
const payload = encodeURIComponent(JSON.stringify(order))
|
||||
uni.redirectTo({ url: `/pages/orders/detail?payload=${payload}` })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.block {
|
||||
padding: 22rpx;
|
||||
margin-bottom: 18rpx;
|
||||
}
|
||||
.name {
|
||||
font-size: 34rpx;
|
||||
font-weight: 950;
|
||||
max-width: 520rpx;
|
||||
}
|
||||
.price {
|
||||
font-size: 32rpx;
|
||||
font-weight: 950;
|
||||
}
|
||||
.meta {
|
||||
margin-top: 10rpx;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
.title {
|
||||
font-weight: 950;
|
||||
font-size: 30rpx;
|
||||
margin-bottom: 14rpx;
|
||||
}
|
||||
.line {
|
||||
padding: 12rpx 0;
|
||||
}
|
||||
.sum {
|
||||
font-weight: 950;
|
||||
}
|
||||
.note {
|
||||
max-width: 520rpx;
|
||||
text-align: right;
|
||||
}
|
||||
.plans {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 12rpx;
|
||||
}
|
||||
.plan {
|
||||
padding: 14rpx 12rpx;
|
||||
border-radius: 18rpx;
|
||||
border: 1rpx solid rgba(17, 24, 39, 0.08);
|
||||
background: rgba(17, 24, 39, 0.03);
|
||||
}
|
||||
.on {
|
||||
background: rgba(59, 130, 246, 0.12);
|
||||
border-color: rgba(59, 130, 246, 0.35);
|
||||
}
|
||||
.p1 {
|
||||
font-size: 26rpx;
|
||||
font-weight: 950;
|
||||
}
|
||||
.p2 {
|
||||
margin-top: 8rpx;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
.hint {
|
||||
margin-top: 14rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
.rline {
|
||||
margin-top: 10rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
.pay {
|
||||
padding: 14rpx 0;
|
||||
}
|
||||
.p-icon {
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
border-radius: 16rpx;
|
||||
background: rgba(16, 185, 129, 0.16);
|
||||
color: #059669;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 900;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
.p-text {
|
||||
font-weight: 800;
|
||||
}
|
||||
.submit {
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
.submit2 {
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user