升级pro页:删除选择套餐,保留Pro/VIP方案卡;支付时校验金额匹配;修正product ID为下划线格式

This commit is contained in:
Yuzhiran Dev
2026-07-14 14:46:07 +08:00
parent 1094435b5f
commit de8ca9c420
17 changed files with 146 additions and 183 deletions
@@ -156,6 +156,12 @@ function formatDate(dateStr) {
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
// 微信小程序分享
onShareAppMessage(() => ({
title: 'AI 维度 - 你的AI知识助手',
path: '/pages/index/index'
}))
</script>
<style lang="scss" scoped>
+6
View File
@@ -112,6 +112,12 @@ function onLoad(fn) {
fn(page.$page.options || {})
}
}
// 微信小程序分享
onShareAppMessage(() => ({
title: 'AI 维度 - 你的AI知识助手',
path: '/pages/index/index'
}))
</script>
<style lang="scss" scoped>
+6
View File
@@ -195,6 +195,12 @@ function goShare() {
}
})
}
// 微信小程序右上角三点分享
onShareAppMessage(() => ({
title: 'AI 维度 - AI 问答',
path: '/pages/chat/chat'
}))
</script>
<style lang="scss" scoped>
+6
View File
@@ -188,6 +188,12 @@ function goBack() {
function goToAI() {
uni.switchTab({ url: '/pages/chat/chat' })
}
// 微信小程序分享
onShareAppMessage(() => ({
title: 'AI 维度 - 你的AI知识助手',
path: '/pages/index/index'
}))
</script>
<style lang="scss" scoped>
+6
View File
@@ -164,6 +164,12 @@ function goDetail(item) {
url: `/pages/detail/detail?id=${item._id}`
})
}
// 微信小程序分享
onShareAppMessage(() => ({
title: 'AI 维度 - 你的AI知识助手',
path: '/pages/index/index'
}))
</script>
<style lang="scss" scoped>
+6
View File
@@ -112,6 +112,12 @@ async function removeFav(id, idx) {
function goHome() {
uni.switchTab({ url: '/pages/index/index' })
}
// 微信小程序分享
onShareAppMessage(() => ({
title: 'AI 维度 - 你的AI知识助手',
path: '/pages/index/index'
}))
</script>
<style lang="scss" scoped>
+6
View File
@@ -226,6 +226,12 @@ onMounted(() => {
function goBack() {
uni.navigateBack()
}
// 微信小程序分享
onShareAppMessage(() => ({
title: 'AI 维度 - 你的AI知识助手',
path: '/pages/index/index'
}))
</script>
<style lang="scss" scoped>
+6
View File
@@ -151,6 +151,12 @@ function goNewsDetail(item) {
uni.setStorageSync('__news_item__', JSON.stringify(item))
uni.navigateTo({ url: '/pages/news/news' })
}
// 微信小程序分享
onShareAppMessage(() => ({
title: 'AI 维度 - 你的AI知识助手',
path: '/pages/index/index'
}))
</script>
<style lang="scss" scoped>
@@ -133,6 +133,12 @@ function dimDotColor(id) {
const dim = getDimension(id)
return dim ? dim.color : 'rgba(255,255,255,0.2)'
}
// 微信小程序分享
onShareAppMessage(() => ({
title: 'AI 维度 - 你的AI知识助手',
path: '/pages/index/index'
}))
</script>
<style lang="scss" scoped>
+6
View File
@@ -273,6 +273,12 @@ function openAgreement(type) {
}
uni.navigateTo({ url: pages[type] || pages.terms })
}
// 微信小程序分享
onShareAppMessage(() => ({
title: 'AI 维度 - 你的AI知识助手',
path: '/pages/index/index'
}))
</script>
<style lang="scss" scoped>
+6
View File
@@ -197,6 +197,12 @@ function openSource() {
onMounted(() => {
loadDetail()
})
// 微信小程序分享
onShareAppMessage(() => ({
title: 'AI 维度 - 你的AI知识助手',
path: '/pages/index/index'
}))
</script>
<style lang="scss" scoped>
+50 -183
View File
@@ -30,12 +30,15 @@
<text class="plan-name">Pro</text>
<view class="plan-badge" v-if="selectedPlan === 'pro'">推荐</view>
</view>
<text class="plan-price">¥19.9</text>
<text class="plan-unit">/ 月</text>
<view class="plan-price-row">
<text class="plan-price">¥19.9</text>
<text class="plan-unit">/ 月</text>
</view>
<view class="plan-features">
<text class="plan-feature">✓ AI 问答无限次</text>
<text class="plan-feature">✓ 全量知识解锁</text>
<text class="plan-feature">✓ 收藏无限容量</text>
<text class="plan-feature">✓ 趋势优先推送</text>
</view>
</view>
<view
@@ -47,52 +50,15 @@
<text class="plan-name">VIP</text>
<view class="plan-badge vip-badge" v-if="selectedPlan === 'vip'">尊享</view>
</view>
<text class="plan-price vip-price">¥39.9</text>
<text class="plan-unit">/ 月</text>
<view class="plan-price-row">
<text class="plan-price vip-price">¥39.9</text>
<text class="plan-unit">/ 月</text>
</view>
<view class="plan-features">
<text class="plan-feature">✓ 含 Pro 全部权益</text>
<text class="plan-feature">✓ 专属客服支持</text>
<text class="plan-feature">✓ 专属会员标识</text>
</view>
</view>
</view>
<!-- 套餐时长 -->
<view class="duration-section">
<text class="section-title">选择套餐</text>
<view class="duration-list">
<view
class="duration-item"
:class="{ active: selectedDuration === item.key }"
v-for="item in durationOptions"
:key="item.key"
@click="selectedDuration = item.key"
>
<text class="d-label">{{ item.label }}</text>
<text class="d-price">¥{{ item.price }}</text>
<text class="d-save" v-if="item.save">省 {{ item.save }}</text>
</view>
</view>
</view>
<!-- 权益清单 -->
<view class="benefits-section">
<text class="section-title">权益对比</text>
<view class="benefits-card">
<view
class="benefit-row"
v-for="(item, idx) in benefitList"
:key="idx"
>
<view class="benefit-left">
<text class="benefit-icon">{{ item.icon }}</text>
<text class="benefit-text">{{ item.text }}</text>
</view>
<view class="benefit-check">
<text class="check-mark" :class="{ 'pro-only': item.proOnly, 'vip-only': !item.proOnly }">
{{ item.proOnly ? 'Pro' : (item.hasPro ? 'Pro+VIP' : 'VIP') }}
</text>
</view>
<text class="plan-feature">✓ 工具教程 + 学习路径</text>
</view>
</view>
</view>
@@ -124,30 +90,16 @@ import { useUserStore } from '@/stores/user'
const userStore = useUserStore()
const selectedPlan = ref('pro')
const selectedDuration = ref('pro-monthly')
const selectedPlan = ref('pro') // 'pro' | 'vip'
const durationOptions = computed(() => {
const isPro = selectedPlan.value === 'pro'
return [
{ key: isPro ? 'pro-monthly' : 'vip-monthly', label: '月付', price: isPro ? 19.9 : 39.9 },
{ key: isPro ? 'pro-quarterly' : 'vip-quarterly', label: '季付', price: isPro ? 49.9 : 99.9, save: isPro ? '¥10' : '¥20' }
]
})
// 方案 → 对应数据库的商品 ID 和价格(单位:元)
const PLAN_MAP = {
pro: { productId: 'pro_monthly', price: 19.9 },
vip: { productId: 'vip_monthly', price: 39.9 }
}
const benefitList = ref([
{ icon: '🤖', text: 'AI 问答无限次', proOnly: true, hasPro: true },
{ icon: '📚', text: '全量知识内容解锁', proOnly: true, hasPro: true },
{ icon: '📡', text: '每日趋势优先推送', proOnly: true, hasPro: true },
{ icon: '⭐', text: '收藏夹无限容量', proOnly: true, hasPro: true },
{ icon: '💬', text: '专属客服支持', proOnly: false, hasPro: false },
{ icon: '🎁', text: '专属会员标识', proOnly: false, hasPro: false }
])
const currentPrice = computed(() => {
const item = durationOptions.value.find(d => d.key === selectedDuration.value)
return item ? item.price : 19.9
})
const currentPrice = computed(() => PLAN_MAP[selectedPlan.value].price)
const currentProductId = computed(() => PLAN_MAP[selectedPlan.value].productId)
const loading = ref(false)
@@ -157,7 +109,14 @@ async function handlePay() {
return
}
const productId = selectedDuration.value
const plan = PLAN_MAP[selectedPlan.value]
if (!plan || !plan.productId || plan.price <= 0) {
uni.showToast({ title: '请选择有效的套餐', icon: 'none' })
return
}
const productId = plan.productId
const amount = plan.price
loading.value = true
try {
@@ -165,6 +124,17 @@ async function handlePay() {
const payParam = data.payParams || data.wechatParam || data.paymentData
if (payParam) {
// 校验支付参数金额(分)与所选金额一致
// 微信返回的 amount 可能是 number 或 string
const payAmountFen = payParam.totalFee || payParam.amount || data.amount
const expectedFen = Math.round(amount * 100)
if (parseInt(payAmountFen, 10) !== expectedFen) {
console.error(`支付金额不匹配: 前端 ¥${amount} / 后端 ${payAmountFen} 分`)
uni.showToast({ title: '支付金额异常,请重试', icon: 'none' })
loading.value = false
return
}
uni.requestPayment({
provider: 'wxpay',
timeStamp: payParam.timeStamp || payParam.timestamp,
@@ -173,7 +143,7 @@ async function handlePay() {
signType: payParam.signType || 'MD5',
paySign: payParam.paySign,
success: () => {
uni.showToast({ title: '支付成功!', icon: 'success' })
uni.showToast({ title: `支付成功!金额 ¥${amount}`, icon: 'success' })
setTimeout(() => {
uni.navigateBack()
}, 1500)
@@ -200,6 +170,12 @@ async function handlePay() {
function goBack() {
uni.navigateBack()
}
// 微信小程序分享
onShareAppMessage(() => ({
title: 'AI 维度 - 你的AI知识助手',
path: '/pages/index/index'
}))
</script>
<style lang="scss" scoped>
@@ -341,7 +317,12 @@ function goBack() {
font-size: 28px;
font-weight: 700;
color: var(--dim1-color);
display: inline;
}
.plan-price-row {
display: flex;
align-items: baseline;
margin-bottom: 12px;
}
.plan-card.vip .plan-price {
@@ -367,120 +348,6 @@ function goBack() {
line-height: 1.5;
}
// 套餐时长
.duration-section {
margin-bottom: 24px;
}
.section-title {
font-size: 14px;
font-weight: 600;
color: var(--text-primary);
display: block;
margin-bottom: 12px;
}
.duration-list {
display: flex;
gap: 10px;
}
.duration-item {
flex: 1;
padding: 14px 12px;
background: var(--glass-bg);
border: 1.5px solid var(--glass-border);
border-radius: 14px;
text-align: center;
transition: all 0.3s;
&.active {
border-color: var(--dim1-color);
background: linear-gradient(135deg, rgba(99,102,241,0.1), rgba(99,102,241,0.05));
}
}
.d-label {
font-size: 13px;
color: var(--text-secondary);
display: block;
margin-bottom: 6px;
}
.d-price {
font-size: 18px;
font-weight: 700;
color: var(--text-primary);
display: block;
}
.d-save {
font-size: 11px;
font-weight: 600;
color: #4db6ac;
display: block;
margin-top: 4px;
}
// 权益对比
.benefits-section {
margin-bottom: 24px;
}
.benefits-card {
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: 14px;
overflow: hidden;
}
.benefit-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 14px 16px;
&:not(:last-child) {
border-bottom: 1px solid var(--glass-border);
}
}
.benefit-left {
display: flex;
align-items: center;
gap: 10px;
}
.benefit-icon {
font-size: 16px;
width: 24px;
text-align: center;
}
.benefit-text {
font-size: 13px;
color: var(--text-secondary);
}
.benefit-check {
.check-mark {
font-size: 11px;
font-weight: 600;
padding: 2px 10px;
border-radius: 8px;
&.pro-only {
background: rgba(99,102,241,0.1);
color: var(--dim1-color);
}
&.vip-only {
background: rgba(255,167,38,0.1);
color: #ffa726;
}
}
}
// 支付
.pay-section {
margin-bottom: 24px;
+6
View File
@@ -274,6 +274,12 @@ function goAbout() {
function goSettings() {
uni.navigateTo({ url: '/pages/settings/settings' })
}
// 微信小程序分享
onShareAppMessage(() => ({
title: 'AI 维度 - 你的AI知识助手',
path: '/pages/index/index'
}))
</script>
<style lang="scss" scoped>
+6
View File
@@ -223,6 +223,12 @@ onMounted(() => {
function goBack() {
uni.navigateBack()
}
// 微信小程序分享
onShareAppMessage(() => ({
title: 'AI 维度 - 你的AI知识助手',
path: '/pages/index/index'
}))
</script>
<style lang="scss" scoped>
+6
View File
@@ -186,6 +186,12 @@ onMounted(() => {
onUnmounted(() => {
if (debounceTimer) clearTimeout(debounceTimer)
})
// 微信小程序分享
onShareAppMessage(() => ({
title: 'AI 维度 - 你的AI知识助手',
path: '/pages/index/index'
}))
</script>
<style lang="scss" scoped>
+6
View File
@@ -137,6 +137,12 @@ function showAgreement() {
showCancel: false
})
}
// 微信小程序分享
onShareAppMessage(() => ({
title: 'AI 维度 - 你的AI知识助手',
path: '/pages/index/index'
}))
</script>
<style lang="scss" scoped>
+6
View File
@@ -179,6 +179,12 @@ function getSampleData() {
}
]
}
// 微信小程序分享
onShareAppMessage(() => ({
title: 'AI 维度 - 你的AI知识助手',
path: '/pages/index/index'
}))
</script>
<style lang="scss" scoped>