fix: 协议勾选控制+news详情页样式修复+支付页重做
This commit is contained in:
@@ -148,7 +148,8 @@ function onNotify() {
|
||||
}
|
||||
|
||||
function goNewsDetail(item) {
|
||||
uni.switchTab({ url: '/pages/trend/trend' })
|
||||
uni.setStorageSync('__news_item__', JSON.stringify(item))
|
||||
uni.navigateTo({ url: '/pages/news/news' })
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -133,6 +133,10 @@ const BASE_URL = 'https://wdkj.yuzhiran.com.cn'
|
||||
|
||||
/** 发送邮箱验证码 */
|
||||
async function handleSendCode() {
|
||||
if (!agreed.value) {
|
||||
uni.showToast({ title: '请先阅读并同意用户协议和隐私政策', icon: 'none' })
|
||||
return
|
||||
}
|
||||
const email = registerForm.value.email
|
||||
if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
||||
uni.showToast({ title: '请先输入正确的邮箱', icon: 'none' })
|
||||
@@ -170,6 +174,10 @@ async function handleSendCode() {
|
||||
}
|
||||
|
||||
const wechatLogin = async () => {
|
||||
if (!loginAgreed.value) {
|
||||
uni.showToast({ title: '请先阅读并同意用户协议和隐私政策', icon: 'none' })
|
||||
return
|
||||
}
|
||||
try {
|
||||
const loginRes = await new Promise((resolve, reject) => {
|
||||
uni.login({ success: resolve, fail: reject })
|
||||
|
||||
@@ -198,7 +198,7 @@ onMounted(() => {
|
||||
|
||||
.nav-back {
|
||||
font-size: 28px;
|
||||
color: #fff;
|
||||
color: var(--text-primary);
|
||||
padding: 0 8px;
|
||||
line-height: 1;
|
||||
}
|
||||
@@ -209,7 +209,7 @@ onMounted(() => {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.nav-share { font-size: 22px; color: rgba(255,255,255,0.5); }
|
||||
.nav-share { font-size: 22px; color: var(--text-muted); }
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
@@ -218,18 +218,19 @@ onMounted(() => {
|
||||
|
||||
// Hero
|
||||
.news-hero {
|
||||
height: 180px;
|
||||
height: 160px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 0 0 24px 24px;
|
||||
margin: 0 20px;
|
||||
}
|
||||
|
||||
.hero-emoji { font-size: 72px; }
|
||||
.hero-emoji { font-size: 64px; }
|
||||
|
||||
// Category
|
||||
.category-tag {
|
||||
margin: 24px 20px 0;
|
||||
margin: 20px 20px 0;
|
||||
}
|
||||
|
||||
.tag-text {
|
||||
@@ -270,19 +271,19 @@ onMounted(() => {
|
||||
|
||||
.meta-label {
|
||||
font-size: 11px;
|
||||
color: rgba(255,255,255,0.35);
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
.meta-label.hot { font-size: 13px; }
|
||||
|
||||
.meta-value { font-size: 12px; color: rgba(255,255,255,0.7); }
|
||||
.meta-value { font-size: 12px; color: var(--text-secondary); }
|
||||
|
||||
// Summary
|
||||
.summary-card {
|
||||
margin: 0 20px 20px;
|
||||
padding: 16px;
|
||||
background: linear-gradient(135deg, rgba(179,136,255,0.08), rgba(77,208,225,0.05));
|
||||
border: 1px solid rgba(179,136,255,0.12);
|
||||
background: linear-gradient(135deg, rgba(99,102,241,0.06), rgba(0,188,212,0.04));
|
||||
border: 1px solid rgba(99,102,241,0.1);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
@@ -297,7 +298,7 @@ onMounted(() => {
|
||||
.summary-text {
|
||||
font-size: 14px;
|
||||
line-height: 1.7;
|
||||
color: rgba(255,255,255,0.85);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
// Body
|
||||
@@ -305,7 +306,7 @@ onMounted(() => {
|
||||
margin: 0 20px 20px;
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
color: rgba(255,255,255,0.7);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
// Related tags
|
||||
@@ -316,7 +317,7 @@ onMounted(() => {
|
||||
.related-label {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
color: rgba(255,255,255,0.4);
|
||||
color: var(--text-tertiary);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
@@ -329,7 +330,7 @@ onMounted(() => {
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.tag-text { font-size: 12px; color: rgba(255,255,255,0.6); }
|
||||
.tag-item .tag-text { font-size: 12px; color: var(--text-secondary); }
|
||||
|
||||
// Action bar
|
||||
.action-bar {
|
||||
@@ -351,7 +352,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.action-icon { font-size: 18px; }
|
||||
.action-text { font-size: 13px; color: rgba(255,255,255,0.7); }
|
||||
.action-text { font-size: 13px; color: var(--text-secondary); }
|
||||
|
||||
.footer-spacer { height: 60px; }
|
||||
</style>
|
||||
|
||||
@@ -9,72 +9,111 @@
|
||||
<view class="nav-placeholder"></view>
|
||||
</view>
|
||||
|
||||
<!-- 头部 -->
|
||||
<view class="payment-header">
|
||||
<text class="header-title">解锁 AI 维度 Pro</text>
|
||||
<text class="header-desc">无限 AI 问答 · 全量知识解锁 · 每日趋势优先推送</text>
|
||||
</view>
|
||||
|
||||
<!-- 方案选择 -->
|
||||
<view class="plan-selector">
|
||||
<view
|
||||
class="plan-tag"
|
||||
:class="{ active: selectedPlan === 'pro' }"
|
||||
@click="selectedPlan = 'pro'"
|
||||
>
|
||||
<text class="plan-name">Pro</text>
|
||||
<text class="plan-price">¥19.9<span class="unit">/月</span></text>
|
||||
<text class="plan-badge">推荐</text>
|
||||
<scroll-view scroll-y class="scroll-area">
|
||||
<!-- 头部 -->
|
||||
<view class="payment-header">
|
||||
<view class="header-icon-wrap">
|
||||
<text class="header-icon">✦</text>
|
||||
</view>
|
||||
<text class="header-title">解锁 AI 维度 Pro</text>
|
||||
<text class="header-desc">无限 AI 问答 · 全量知识 · 趋势优先推送</text>
|
||||
</view>
|
||||
<view
|
||||
class="plan-tag vip"
|
||||
:class="{ active: selectedPlan === 'vip' }"
|
||||
@click="selectedPlan = 'vip'"
|
||||
>
|
||||
<text class="plan-name">VIP</text>
|
||||
<text class="plan-price">¥39.9<span class="unit">/月</span></text>
|
||||
<text class="plan-desc">含 Pro 全部权益</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 权益对比 -->
|
||||
<view class="benefits">
|
||||
<view class="benefit-item" v-for="(item, idx) in benefits" :key="idx">
|
||||
<text class="b-icon">{{ item.icon }}</text>
|
||||
<text class="b-text">{{ item.text }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 套餐选择 -->
|
||||
<view class="duration-section">
|
||||
<text class="duration-title">选择套餐</text>
|
||||
<view class="duration-list">
|
||||
<!-- 方案选择卡片 -->
|
||||
<view class="plan-selector">
|
||||
<view
|
||||
class="duration-item"
|
||||
:class="{ active: selectedDuration === item.key }"
|
||||
v-for="item in durations"
|
||||
:key="item.key"
|
||||
@click="selectedDuration = item.key"
|
||||
class="plan-card"
|
||||
:class="{ active: selectedPlan === 'pro' }"
|
||||
@click="selectedPlan = 'pro'"
|
||||
>
|
||||
<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 class="plan-top">
|
||||
<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-features">
|
||||
<text class="plan-feature">✓ AI 问答无限次</text>
|
||||
<text class="plan-feature">✓ 全量知识解锁</text>
|
||||
<text class="plan-feature">✓ 收藏无限容量</text>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
class="plan-card vip"
|
||||
:class="{ active: selectedPlan === 'vip' }"
|
||||
@click="selectedPlan = 'vip'"
|
||||
>
|
||||
<view class="plan-top">
|
||||
<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-features">
|
||||
<text class="plan-feature">✓ 含 Pro 全部权益</text>
|
||||
<text class="plan-feature">✓ 专属客服支持</text>
|
||||
<text class="plan-feature">✓ 专属会员标识</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 支付按钮 -->
|
||||
<view class="pay-section">
|
||||
<button class="pay-btn" :loading="loading" @click="handlePay">
|
||||
立即支付 ¥{{ currentPrice }}
|
||||
</button>
|
||||
<text class="pay-agreement">
|
||||
点击支付即同意《用户协议》和《隐私政策》
|
||||
</text>
|
||||
</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>
|
||||
|
||||
<!-- 底部 -->
|
||||
<text class="footer-text">如有问题请联系客服 · 支持 7 天无理由退款</text>
|
||||
<!-- 权益清单 -->
|
||||
<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>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 支付按钮 -->
|
||||
<view class="pay-section">
|
||||
<button
|
||||
class="pay-btn"
|
||||
:loading="loading"
|
||||
:disabled="loading"
|
||||
@click="handlePay"
|
||||
>
|
||||
<text class="pay-btn-text">立即支付 ¥{{ currentPrice }}</text>
|
||||
</button>
|
||||
<text class="pay-agreement">
|
||||
点击支付即表示同意《用户协议》和《隐私政策》
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view class="footer-spacer"></view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -85,32 +124,28 @@ import { useUserStore } from '@/stores/user'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 方案
|
||||
const selectedPlan = ref('pro')
|
||||
|
||||
// 套餐时长
|
||||
const durations = ref([
|
||||
{ key: 'pro-monthly', label: 'Pro 月付', price: 19.9 },
|
||||
{ key: 'pro-quarterly', label: 'Pro 季付', price: 49.9, save: '省 ¥10' },
|
||||
{ key: 'vip-monthly', label: 'VIP 月付', price: 39.9 },
|
||||
{ key: 'vip-quarterly', label: 'VIP 季付', price: 99.9, save: '省 ¥20' }
|
||||
])
|
||||
|
||||
const selectedDuration = ref('pro-monthly')
|
||||
|
||||
// 权益
|
||||
const benefits = ref([
|
||||
{ icon: '🤖', text: 'AI 问答无限次' },
|
||||
{ icon: '📚', text: '全量知识内容解锁' },
|
||||
{ icon: '📡', text: '每日趋势优先推送' },
|
||||
{ icon: '⭐', text: '收藏夹无限容量' },
|
||||
{ icon: '🎁', text: '专属会员标识' },
|
||||
{ icon: '💬', text: '专属客服支持' }
|
||||
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' }
|
||||
]
|
||||
})
|
||||
|
||||
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 = durations.value.find(d => d.key === selectedDuration.value)
|
||||
const item = durationOptions.value.find(d => d.key === selectedDuration.value)
|
||||
return item ? item.price : 19.9
|
||||
})
|
||||
|
||||
@@ -122,24 +157,14 @@ async function handlePay() {
|
||||
return
|
||||
}
|
||||
|
||||
// 找到对应的 productId
|
||||
const productMap = {
|
||||
'pro-monthly': 'pro-monthly',
|
||||
'pro-quarterly': 'pro-quarterly',
|
||||
'vip-monthly': 'vip-monthly',
|
||||
'vip-quarterly': 'vip-quarterly'
|
||||
}
|
||||
const productId = selectedDuration.value
|
||||
|
||||
loading.value = true
|
||||
try {
|
||||
// 调用后端创建订单
|
||||
const data = await paymentApi.createOrder(productMap[selectedDuration.value], userStore.token)
|
||||
|
||||
// 获取微信支付参数
|
||||
const data = await paymentApi.createOrder(productId, userStore.token)
|
||||
const payParam = data.payParams || data.wechatParam || data.paymentData
|
||||
|
||||
if (payParam) {
|
||||
// 调起微信支付
|
||||
uni.requestPayment({
|
||||
provider: 'wxpay',
|
||||
timeStamp: payParam.timeStamp || payParam.timestamp,
|
||||
@@ -154,7 +179,7 @@ async function handlePay() {
|
||||
}, 1500)
|
||||
},
|
||||
fail: (err) => {
|
||||
if (err.errMsg.includes('cancel')) {
|
||||
if (err.errMsg && err.errMsg.includes('cancel')) {
|
||||
uni.showToast({ title: '已取消支付', icon: 'none' })
|
||||
} else {
|
||||
uni.showToast({ title: '支付失败,请重试', icon: 'none' })
|
||||
@@ -179,19 +204,20 @@ function goBack() {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page-payment {
|
||||
min-height: 100vh;
|
||||
padding: 0 20px;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--bg-primary);
|
||||
}
|
||||
|
||||
.status-bar-placeholder { height: 44px; }
|
||||
|
||||
// 导航
|
||||
.nav-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12px 0;
|
||||
padding: 12px 20px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.nav-back {
|
||||
@@ -214,23 +240,45 @@ function goBack() {
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
.scroll-area {
|
||||
flex: 1;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
// 头部
|
||||
.payment-header {
|
||||
text-align: center;
|
||||
padding: 10px 0 20px;
|
||||
padding: 10px 0 24px;
|
||||
}
|
||||
|
||||
.header-icon-wrap {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 16px;
|
||||
background: linear-gradient(135deg, var(--dim1-color), var(--dim3-color));
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0 auto 16px;
|
||||
box-shadow: 0 8px 24px rgba(99,102,241,0.25);
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
font-size: 28px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 22px;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.header-desc {
|
||||
font-size: 12px;
|
||||
font-size: 13px;
|
||||
color: var(--text-tertiary);
|
||||
margin-top: 6px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
@@ -238,181 +286,235 @@ function goBack() {
|
||||
.plan-selector {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.plan-tag {
|
||||
.plan-card {
|
||||
flex: 1;
|
||||
padding: 16px;
|
||||
padding: 20px 16px;
|
||||
background: var(--glass-bg);
|
||||
border: 1px solid var(--glass-border);
|
||||
border-radius: 14px;
|
||||
text-align: center;
|
||||
border: 1.5px solid var(--glass-border);
|
||||
border-radius: 16px;
|
||||
position: relative;
|
||||
transition: all 0.3s;
|
||||
|
||||
&.active {
|
||||
border-color: var(--dim1-color);
|
||||
box-shadow: 0 0 0 1px rgba(99,102,241,0.2), 0 8px 24px rgba(99,102,241,0.1);
|
||||
background: linear-gradient(135deg, rgba(99,102,241,0.06), rgba(99,102,241,0.02));
|
||||
}
|
||||
|
||||
&.vip.active {
|
||||
border-color: #ffa726;
|
||||
box-shadow: 0 0 0 1px rgba(255,167,38,0.2), 0 8px 24px rgba(255,167,38,0.1);
|
||||
background: linear-gradient(135deg, rgba(255,167,38,0.06), rgba(255,167,38,0.02));
|
||||
}
|
||||
}
|
||||
|
||||
.plan-tag.active {
|
||||
background: linear-gradient(135deg, rgba(124, 77, 255, 0.15), rgba(0, 0, 0, 0.2));
|
||||
border-color: rgba(124, 77, 255, 0.3);
|
||||
}
|
||||
|
||||
.plan-tag.vip.active {
|
||||
background: linear-gradient(135deg, rgba(255, 152, 0, 0.15), rgba(0, 0, 0, 0.2));
|
||||
border-color: rgba(255, 152, 0, 0.3);
|
||||
.plan-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.plan-name {
|
||||
font-size: 18px;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.plan-price {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: var(--dim1-color);
|
||||
display: block;
|
||||
}
|
||||
|
||||
.plan-tag.vip .plan-price {
|
||||
color: #ffa726;
|
||||
}
|
||||
|
||||
.unit {
|
||||
font-size: 12px;
|
||||
color: var(--text-tertiary);
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.plan-badge {
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
right: 12px;
|
||||
background: linear-gradient(135deg, #ff9800, #ff5722);
|
||||
color: white;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
padding: 2px 10px;
|
||||
border-radius: 10px;
|
||||
background: linear-gradient(135deg, var(--dim1-color), #7c4dff);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.plan-desc {
|
||||
font-size: 11px;
|
||||
color: var(--text-muted);
|
||||
margin-top: 4px;
|
||||
display: block;
|
||||
.vip-badge {
|
||||
background: linear-gradient(135deg, #ffa726, #ff7043);
|
||||
}
|
||||
|
||||
// 权益
|
||||
.benefits {
|
||||
background: var(--glass-bg);
|
||||
border: 1px solid var(--glass-border);
|
||||
border-radius: 14px;
|
||||
padding: 16px;
|
||||
margin-bottom: 20px;
|
||||
.plan-price {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
color: var(--dim1-color);
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.benefit-item {
|
||||
.plan-card.vip .plan-price {
|
||||
color: #ffa726;
|
||||
}
|
||||
|
||||
.plan-unit {
|
||||
font-size: 12px;
|
||||
color: var(--text-tertiary);
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.plan-features {
|
||||
margin-top: 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 8px 0;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.benefit-item:not(:last-child) {
|
||||
border-bottom: 1px solid var(--glass-border);
|
||||
}
|
||||
|
||||
.b-icon { font-size: 16px; }
|
||||
|
||||
.b-text {
|
||||
font-size: 13px;
|
||||
.plan-feature {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
// 套餐时长
|
||||
.duration-section {
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.duration-title {
|
||||
.section-title {
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
margin-bottom: 10px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
display: block;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.duration-list {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.duration-item {
|
||||
flex: 1;
|
||||
padding: 12px 8px;
|
||||
padding: 14px 12px;
|
||||
background: var(--glass-bg);
|
||||
border: 1px solid var(--glass-border);
|
||||
border-radius: 12px;
|
||||
border: 1.5px solid var(--glass-border);
|
||||
border-radius: 14px;
|
||||
text-align: center;
|
||||
}
|
||||
transition: all 0.3s;
|
||||
|
||||
.duration-item.active {
|
||||
background: rgba(124, 77, 255, 0.12);
|
||||
border-color: rgba(124, 77, 255, 0.3);
|
||||
&.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: 12px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
font-size: 13px;
|
||||
color: var(--text-secondary);
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.d-price {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--dim1-color);
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
display: block;
|
||||
}
|
||||
|
||||
.d-save {
|
||||
font-size: 10px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: #4db6ac;
|
||||
display: block;
|
||||
margin-top: 2px;
|
||||
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-top: 20px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.pay-btn {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
height: 52px;
|
||||
background: linear-gradient(135deg, var(--dim1-color), var(--dim3-color));
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
border-radius: 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 6px 20px rgba(99,102,241,0.3);
|
||||
|
||||
&[disabled] {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
.pay-btn-text {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
box-shadow: 0 4px 16px rgba(179, 136, 255, 0.3);
|
||||
}
|
||||
|
||||
.pay-agreement {
|
||||
font-size: 10px;
|
||||
font-size: 11px;
|
||||
color: var(--text-muted);
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
margin-top: 12px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.footer-text {
|
||||
font-size: 10px;
|
||||
color: var(--text-muted);
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
display: block;
|
||||
}
|
||||
.footer-spacer { height: 40px; }
|
||||
</style>
|
||||
@@ -39,9 +39,9 @@ async function sendVerificationCode(to, code) {
|
||||
}
|
||||
try {
|
||||
await transport.sendMail({
|
||||
from: `"AI维度" <${SMTP_FROM}>`,
|
||||
from: `"宇之然AI维度" <${SMTP_FROM}>`,
|
||||
to,
|
||||
subject: '【AI维度】邮箱验证码',
|
||||
subject: '【宇之然AI维度】邮箱验证码',
|
||||
html: `
|
||||
<div style="max-width:480px;margin:0 auto;padding:24px;font-family:sans-serif;">
|
||||
<h2 style="color:#6366f1;">AI 维度 - 邮箱验证</h2>
|
||||
|
||||
Reference in New Issue
Block a user