502 lines
10 KiB
Vue
502 lines
10 KiB
Vue
<template>
|
||
<div class="page-purchase">
|
||
<h2 class="page-title">如何购买</h2>
|
||
|
||
<!-- 联系方式 -->
|
||
<div class="contact-section">
|
||
<Card class="contact-card">
|
||
<template #title>联系购买</template>
|
||
<template #content>
|
||
<p class="contact-desc">扫描下方二维码或添加微信号联系我们</p>
|
||
<div class="contact-content">
|
||
<div class="qr-code-wrapper">
|
||
<div class="qr-code-placeholder">
|
||
<img v-if="wechatQRCode" :src="wechatQRCode" alt="微信二维码" class="qr-code-image" />
|
||
<div v-else class="qr-code-placeholder-text">
|
||
<span>微信二维码</span>
|
||
<small>请上传二维码图片</small>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="contact-info">
|
||
<div class="info-item">
|
||
<span class="info-label">微信号:</span>
|
||
<span class="info-value">{{ wechatNumber }}</span>
|
||
<Button label="复制" size="small" @click="handleCopyWechat" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
</Card>
|
||
</div>
|
||
|
||
<!-- 价格套餐 -->
|
||
<div class="pricing-section">
|
||
<h3 class="section-title">价格套餐</h3>
|
||
<div class="pricing-grid">
|
||
<Card
|
||
v-for="plan in pricingPlans"
|
||
:key="plan.id"
|
||
:class="['pricing-card', { 'featured': plan.featured }]"
|
||
>
|
||
<template #header>
|
||
<Badge v-if="plan.featured" value="推荐" severity="success" />
|
||
</template>
|
||
<template #content>
|
||
<div class="plan-header">
|
||
<h4 class="plan-name">{{ plan.name }}</h4>
|
||
<div class="plan-duration">{{ plan.duration }}</div>
|
||
</div>
|
||
<div class="plan-price">
|
||
<div v-if="plan.originalPrice && plan.originalPrice > plan.price" class="original-price">
|
||
<span class="original-price-text">原价 ¥{{ plan.originalPrice }}</span>
|
||
</div>
|
||
<div class="current-price">
|
||
<span class="price-symbol">¥</span>
|
||
<span class="price-amount">{{ plan.price }}</span>
|
||
<span class="price-unit" v-if="plan.unit">{{ plan.unit }}</span>
|
||
</div>
|
||
<Badge v-if="plan.discount" :value="plan.discount" severity="danger" class="discount-badge" />
|
||
</div>
|
||
<div class="plan-features">
|
||
<div class="feature-item" v-for="feature in plan.features" :key="feature">
|
||
<span class="feature-icon">✓</span>
|
||
<span>{{ feature }}</span>
|
||
</div>
|
||
</div>
|
||
<div class="plan-action">
|
||
<Button label="立即购买" @click="handleContact(plan)" class="btn-full-width" />
|
||
</div>
|
||
</template>
|
||
</Card>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 购买说明 -->
|
||
<div class="notice-section">
|
||
<Card class="notice-card">
|
||
<template #title>购买说明</template>
|
||
<template #content>
|
||
<ul class="notice-list">
|
||
<li>购买后请联系客服激活账号</li>
|
||
<li>终生套餐享受永久使用权限</li>
|
||
<li>如有疑问,请添加微信号咨询</li>
|
||
</ul>
|
||
</template>
|
||
</Card>
|
||
</div>
|
||
|
||
<!-- 成功提示 -->
|
||
<Message
|
||
v-if="showSuccess"
|
||
severity="success"
|
||
:closable="true"
|
||
@close="showSuccess = false"
|
||
class="success-message"
|
||
>
|
||
{{ successMessage }}
|
||
</Message>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import configAPI from '../api/config.js';
|
||
import { Card, Button, Badge, Message } from '../components/PrimeVue';
|
||
import logMixin from '../mixins/logMixin.js';
|
||
|
||
export default {
|
||
name: 'PurchasePage',
|
||
mixins: [logMixin],
|
||
components: {
|
||
Card,
|
||
Button,
|
||
Badge,
|
||
Message
|
||
},
|
||
data() {
|
||
return {
|
||
wechatNumber: '', // 从配置中获取
|
||
wechatQRCode: '', // 从配置中获取
|
||
showSuccess: false,
|
||
successMessage: '',
|
||
loading: false,
|
||
pricingPlans: [] // 从接口获取
|
||
};
|
||
},
|
||
mounted() {
|
||
this.loadWechatConfig();
|
||
this.loadPricingPlans();
|
||
},
|
||
methods: {
|
||
/**
|
||
* 加载微信配置
|
||
*/
|
||
async loadWechatConfig() {
|
||
this.loading = true;
|
||
try {
|
||
const config = await configAPI.getWechatConfig();
|
||
if (config.wechatNumber) {
|
||
this.wechatNumber = config.wechatNumber;
|
||
}
|
||
if (config.wechatQRCode) {
|
||
this.wechatQRCode = config.wechatQRCode;
|
||
}
|
||
} catch (error) {
|
||
console.error('加载微信配置失败:', error);
|
||
if (this.addLog) {
|
||
this.addLog('error', '加载微信配置失败: ' + (error.message || '未知错误'));
|
||
}
|
||
} finally {
|
||
this.loading = false;
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 加载价格套餐列表
|
||
*/
|
||
async loadPricingPlans() {
|
||
try {
|
||
const plans = await configAPI.getPricingPlans();
|
||
if (plans && plans.length > 0) {
|
||
this.pricingPlans = plans;
|
||
}
|
||
} catch (error) {
|
||
console.error('加载价格套餐失败:', error);
|
||
if (this.addLog) {
|
||
this.addLog('error', '加载价格套餐失败: ' + (error.message || '未知错误'));
|
||
}
|
||
}
|
||
},
|
||
/**
|
||
* 复制微信号
|
||
*/
|
||
async handleCopyWechat() {
|
||
try {
|
||
if (window.electronAPI && window.electronAPI.clipboard) {
|
||
await window.electronAPI.clipboard.writeText(this.wechatNumber);
|
||
this.showSuccessMessage('微信号已复制到剪贴板');
|
||
} else {
|
||
throw new Error('electronAPI 不可用,无法复制');
|
||
}
|
||
} catch (error) {
|
||
console.error('复制失败:', error);
|
||
if (this.addLog) {
|
||
this.addLog('error', '复制失败: ' + (error.message || '未知错误'));
|
||
}
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 联系购买
|
||
*/
|
||
handleContact(plan) {
|
||
const message = `我想购买【${plan.name}】(${plan.duration}),价格:¥${plan.price}${plan.unit}`;
|
||
this.showSuccessMessage(`请添加微信号 ${this.wechatNumber} 并发送:"${message}"`);
|
||
},
|
||
|
||
/**
|
||
* 显示成功消息
|
||
*/
|
||
showSuccessMessage(message) {
|
||
this.successMessage = message;
|
||
this.showSuccess = true;
|
||
setTimeout(() => {
|
||
this.showSuccess = false;
|
||
}, 3000);
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style lang="less" scoped>
|
||
.page-purchase {
|
||
padding: 15px;
|
||
height: 100%;
|
||
overflow-y: auto;
|
||
background: #f5f5f5;
|
||
}
|
||
|
||
.page-title {
|
||
margin: 0 0 20px 0;
|
||
font-size: 24px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
text-align: center;
|
||
}
|
||
|
||
.contact-section {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.contact-card {
|
||
max-width: 600px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.contact-desc {
|
||
text-align: center;
|
||
margin: 0 0 15px 0;
|
||
color: #666;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.contact-content {
|
||
display: flex;
|
||
gap: 20px;
|
||
align-items: flex-start;
|
||
}
|
||
|
||
.qr-code-wrapper {
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.qr-code-placeholder {
|
||
width: 150px;
|
||
height: 150px;
|
||
border: 2px dashed #ddd;
|
||
border-radius: 6px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: #fafafa;
|
||
|
||
.qr-code-image {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: contain;
|
||
border-radius: 6px;
|
||
}
|
||
|
||
.qr-code-placeholder-text {
|
||
text-align: center;
|
||
color: #999;
|
||
|
||
span {
|
||
display: block;
|
||
font-size: 14px;
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
small {
|
||
display: block;
|
||
font-size: 12px;
|
||
}
|
||
}
|
||
|
||
.qr-code-loading {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 100%;
|
||
color: #999;
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
|
||
.contact-info {
|
||
flex: 1;
|
||
}
|
||
|
||
.info-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
margin-bottom: 10px;
|
||
padding: 10px;
|
||
background: #f9f9f9;
|
||
border-radius: 6px;
|
||
|
||
.info-label {
|
||
font-weight: 600;
|
||
color: #333;
|
||
min-width: 70px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.info-value {
|
||
flex: 1;
|
||
color: #666;
|
||
font-size: 14px;
|
||
}
|
||
|
||
}
|
||
|
||
.pricing-section {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.section-title {
|
||
text-align: center;
|
||
font-size: 20px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
margin: 0 0 20px 0;
|
||
}
|
||
|
||
.pricing-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||
gap: 15px;
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.pricing-card {
|
||
position: relative;
|
||
text-align: center;
|
||
transition: transform 0.3s, box-shadow 0.3s;
|
||
|
||
&:hover {
|
||
transform: translateY(-5px);
|
||
}
|
||
|
||
&.featured {
|
||
border: 2px solid #4CAF50;
|
||
transform: scale(1.05);
|
||
}
|
||
}
|
||
|
||
.plan-header {
|
||
margin-bottom: 15px;
|
||
|
||
.plan-name {
|
||
margin: 0 0 6px 0;
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
}
|
||
|
||
.plan-duration {
|
||
font-size: 13px;
|
||
color: #999;
|
||
}
|
||
}
|
||
|
||
.plan-price {
|
||
margin-bottom: 15px;
|
||
padding-bottom: 15px;
|
||
border-bottom: 1px solid #eee;
|
||
position: relative;
|
||
|
||
.original-price {
|
||
margin-bottom: 8px;
|
||
|
||
.original-price-text {
|
||
font-size: 14px;
|
||
color: #999;
|
||
text-decoration: line-through;
|
||
}
|
||
}
|
||
|
||
.current-price {
|
||
.price-symbol {
|
||
font-size: 18px;
|
||
color: #4CAF50;
|
||
vertical-align: top;
|
||
}
|
||
|
||
.price-amount {
|
||
font-size: 40px;
|
||
font-weight: 700;
|
||
color: #4CAF50;
|
||
line-height: 1;
|
||
}
|
||
|
||
.price-unit {
|
||
font-size: 14px;
|
||
color: #666;
|
||
margin-left: 4px;
|
||
}
|
||
}
|
||
|
||
.discount-badge {
|
||
position: absolute;
|
||
top: -8px;
|
||
right: 0;
|
||
}
|
||
}
|
||
|
||
.plan-features {
|
||
margin-bottom: 15px;
|
||
text-align: left;
|
||
}
|
||
|
||
.feature-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
margin-bottom: 8px;
|
||
font-size: 13px;
|
||
color: #666;
|
||
|
||
.feature-icon {
|
||
color: #4CAF50;
|
||
font-weight: 700;
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
|
||
.plan-action {
|
||
:deep(.p-button) {
|
||
width: 100%;
|
||
}
|
||
}
|
||
|
||
.notice-section {
|
||
max-width: 800px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.notice-card {
|
||
// Card 组件已包含样式
|
||
}
|
||
|
||
.notice-list {
|
||
margin: 0;
|
||
padding-left: 18px;
|
||
list-style: none;
|
||
|
||
li {
|
||
position: relative;
|
||
padding-left: 20px;
|
||
margin-bottom: 8px;
|
||
color: #666;
|
||
line-height: 1.5;
|
||
font-size: 13px;
|
||
|
||
&::before {
|
||
content: '•';
|
||
position: absolute;
|
||
left: 0;
|
||
color: #4CAF50;
|
||
font-weight: 700;
|
||
font-size: 18px;
|
||
}
|
||
}
|
||
}
|
||
|
||
.success-message {
|
||
position: fixed;
|
||
top: 20px;
|
||
right: 20px;
|
||
z-index: 1000;
|
||
max-width: 400px;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.contact-content {
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
|
||
.pricing-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.pricing-card.featured {
|
||
transform: scale(1);
|
||
}
|
||
}
|
||
</style>
|
||
|