完成consumer端同步

This commit is contained in:
2026-05-14 15:28:09 +08:00
parent 612fb3d360
commit 0ffbc53902
197 changed files with 92657 additions and 7564 deletions

View File

@@ -11,31 +11,31 @@
<view v-else class="list">
<view class="card" v-for="s in items" :key="s['id']">
<view class="row between">
<text class="name">{{ s['plan']?.['name'] != null ? s['plan']?.['name'] : '订阅' }}</text>
<text class="status" :class="'st-' + (s['status'] != null ? s['status'] : 'active')">{{ statusText(s['status'] as string) }}</text>
<text class="name">{{ getPlanName(s) }}</text>
<text class="status" :class="'st-' + getSubscriptionStatus(s)">{{ statusText(getSubscriptionStatus(s)) }}</text>
</view>
<view class="row">
<text class="label">周期</text>
<text class="value">{{ (s['plan']?.['billing_period'] === 'yearly') ? '年付' : '月付' }}</text>
<text class="value">{{ getBillingPeriodText(s) }}</text>
</view>
<view class="row">
<text class="label">价格</text>
<text class="value">¥{{ s['plan']?.['price'] }}</text>
<text class="value">¥{{ getPlanPrice(s) }}</text>
</view>
<view class="row">
<text class="label">开始</text>
<text class="value">{{ fmt(s['start_date'] as string) }}</text>
<text class="value">{{ fmt(s.getString('start_date')) }}</text>
</view>
<view class="row">
<text class="label">下次扣费</text>
<text class="value">{{ fmt(s['next_billing_date'] as string) }}</text>
<text class="value">{{ fmt(s.getString('next_billing_date')) }}</text>
</view>
<view class="actions">
<label class="toggle">
<switch :checked="!!s['auto_renew']" @change="e => toggleAutoRenew(s, e.detail.value as boolean)" />
<switch :checked="getAutoRenew(s)" @change="(e: UniSwitchChangeEvent) => toggleAutoRenew(s, e.detail.value as boolean)" />
<text class="toggle-text">自动续费</text>
</label>
<button class="danger" @click="cancelAtPeriodEnd(s)" :disabled="(s['status'] as string) !== 'active'">到期取消</button>
<button class="danger" @click="cancelAtPeriodEnd(s)" :disabled="getSubscriptionStatus(s) !== 'active'">到期取消</button>
</view>
</view>
</view>
@@ -50,17 +50,52 @@ import { getCurrentUserId } from '@/utils/store.uts'
const loading = ref<boolean>(true)
const items = ref<Array<UTSJSONObject>>([])
function getPlanObj(s: UTSJSONObject): UTSJSONObject | null {
const planRaw = s.get('plan')
if (planRaw == null) return null
if (planRaw instanceof UTSJSONObject) return planRaw as UTSJSONObject
return JSON.parse(JSON.stringify(planRaw)) as UTSJSONObject
}
function getPlanName(s: UTSJSONObject): string {
const planObj = getPlanObj(s)
return planObj != null ? (planObj.getString('name') ?? '订阅') : '订阅'
}
function getSubscriptionStatus(s: UTSJSONObject): string {
return s.getString('status') ?? 'active'
}
function getBillingPeriodText(s: UTSJSONObject): string {
const planObj = getPlanObj(s)
const period = planObj != null ? (planObj.getString('billing_period') ?? 'monthly') : 'monthly'
return period === 'yearly' ? '年付' : '月付'
}
function getPlanPrice(s: UTSJSONObject): string {
const planObj = getPlanObj(s)
const price = planObj != null ? (planObj.getNumber('price') ?? 0) : 0
return price.toString()
}
function getAutoRenew(s: UTSJSONObject): boolean {
return s.getBoolean('auto_renew') ?? false
}
const fmt = (s: string | null): string => {
if (s == null || s.length === 0) return '-'
const d = new Date(s)
if (isNaN(d.getTime())) return '-'
return `${d.getFullYear()}-${(d.getMonth()+1).toString().padStart(2,'0')}-${d.getDate().toString().padStart(2,'0')}`
if (Number.isNaN(d.getTime())) return '-'
return `${d.getFullYear()}-${(d.getMonth()+1).toString().padStart(2,"0")}-${d.getDate().toString().padStart(2,"0")}`
}
const statusText = (st: string): string => {
const map: UTSJSONObject = { trial: '试用', active: '生效', past_due: '逾期', canceled: '已取消', expired: '已过期' } as UTSJSONObject
const val = map[st] as string | null
return val != null ? val : st
if (st === 'trial') return '试用'
if (st === 'active') return '生效'
if (st === 'past_due') return '逾期'
if (st === 'canceled') return '已取消'
if (st === 'expired') return '已过期'
return st
}
const loadSubs = async () => {
@@ -89,14 +124,14 @@ const loadSubs = async () => {
const toggleAutoRenew = async (s: UTSJSONObject, value: boolean) => {
try {
const id = (s['id'] ?? '') as string
const id = s.getString('id') ?? ''
const res = await supaClient
.from('ml_user_subscriptions')
.update({ auto_renew: value })
.eq('id', id)
.execute()
if (res.error != null) throw new Error(res.error?.message ?? '未知错误')
s['auto_renew'] = value
s.set('auto_renew', value)
uni.showToast({ title: value ? '已开启自动续费' : '已关闭自动续费', icon: 'success' })
} catch (e) {
console.error('更新自动续费失败:', e)
@@ -106,15 +141,15 @@ const toggleAutoRenew = async (s: UTSJSONObject, value: boolean) => {
const cancelAtPeriodEnd = async (s: UTSJSONObject) => {
try {
const id = (s['id'] ?? '') as string
const id = s.getString('id') ?? ''
const res = await supaClient
.from('ml_user_subscriptions')
.update({ cancel_at_period_end: true })
.eq('id', id)
.execute()
if (res.error != null) throw new Error(res.error?.message ?? '未知错误')
s['cancel_at_period_end'] = true
s['status'] = 'active' // 保持到期前仍为active
s.set('cancel_at_period_end', true)
s.set('status', 'active')
uni.showToast({ title: '已设置到期取消', icon: 'success' })
} catch (e) {
console.error('设置到期取消失败:', e)
@@ -126,7 +161,9 @@ const goPlanList = () => {
uni.navigateTo({ url: '/pages/mall/consumer/subscription/plan-list' })
}
onMounted(loadSubs)
onMounted(() => {
loadSubs()
})
// 注意uni-app x 的 <script setup> 中不支持 onShow使用 onMounted 代替
// 如果需要页面显示时刷新,可以在页面选项中定义 onShow
</script>