1345 lines
30 KiB
Vue
1345 lines
30 KiB
Vue
<template>
|
||
<div class="personal-center">
|
||
<!-- 顶部区域:快速开始 + 常用功能 -->
|
||
<div class="top-section">
|
||
<!-- 如何开始 -->
|
||
<section class="section getting-started">
|
||
<h2 class="section-title">
|
||
<el-icon><MagicStick /></el-icon>
|
||
快速开始
|
||
</h2>
|
||
<div class="progress-steps">
|
||
<div
|
||
v-for="(step, index) in startSteps"
|
||
:key="index"
|
||
class="step-item"
|
||
:class="{ completed: step.completed, active: index === currentStep }"
|
||
>
|
||
<div class="step-icon">
|
||
<el-icon v-if="step.completed"><Check /></el-icon>
|
||
<span v-else>{{ index + 1 }}</span>
|
||
</div>
|
||
<div class="step-info">
|
||
<router-link :to="step.path" class="step-title">{{ step.title }}</router-link>
|
||
<span class="step-desc">{{ step.desc }}</span>
|
||
</div>
|
||
<div v-if="index < startSteps.length - 1" class="step-connector">
|
||
<div class="connector-line" :class="{ filled: step.completed }"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 常用功能 -->
|
||
<section class="section quick-actions">
|
||
<h2 class="section-title">
|
||
<el-icon><Grid /></el-icon>
|
||
常用功能
|
||
</h2>
|
||
<div class="action-cards">
|
||
<router-link
|
||
v-for="action in quickActions"
|
||
:key="action.id"
|
||
:to="action.path"
|
||
class="action-card"
|
||
>
|
||
<div class="card-icon" :style="{ background: action.bgColor }">
|
||
<el-icon :size="28" :color="action.iconColor">
|
||
<component :is="action.icon" />
|
||
</el-icon>
|
||
</div>
|
||
<div class="card-content">
|
||
<h3>{{ action.title }}</h3>
|
||
<p>{{ action.desc }}</p>
|
||
</div>
|
||
<div class="card-arrow">
|
||
<el-icon><ArrowRight /></el-icon>
|
||
</div>
|
||
</router-link>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
|
||
<!-- 中部区域:用户信息 + 钱包 -->
|
||
<div class="middle-section">
|
||
<!-- 用户信息面板 -->
|
||
<section class="section user-info-panel">
|
||
<div class="info-panel">
|
||
<div class="section-title">
|
||
<el-icon><User /></el-icon>
|
||
<span>当前用户</span>
|
||
</div>
|
||
<div class="panel-content">
|
||
<div class="user-info">
|
||
<div class="user-avatar">
|
||
<el-icon :size="32"><UserFilled /></el-icon>
|
||
</div>
|
||
<div class="user-details">
|
||
<span class="user-name">{{ userStore.userInfo?.username || '-' }}</span>
|
||
</div>
|
||
</div>
|
||
<div class="info-row">
|
||
<span class="info-label">用户ID</span>
|
||
<span class="info-value">{{ userStore.userInfo?.id || '-' }}</span>
|
||
</div>
|
||
<div class="info-row">
|
||
<span class="info-label">最后登录</span>
|
||
<span class="info-value">{{ userStore.userInfo?.last_login || '-' }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 我的钱包 -->
|
||
<section class="section my-wallet">
|
||
<h2 class="section-title">
|
||
<el-icon><Wallet /></el-icon>
|
||
我的钱包
|
||
<span class="wallet-badge">USD 主钱包</span>
|
||
</h2>
|
||
<div class="wallet-card" @click="handleWalletClick">
|
||
<div class="wallet-main">
|
||
<div class="balance-section">
|
||
<div class="balance-label">总金额 (USD)</div>
|
||
<div class="balance-value">
|
||
<AnimatedNumber :value="walletCapital.amount_total || 0" :decimals="2" />
|
||
</div>
|
||
</div>
|
||
<div class="balance-detail">
|
||
<div class="detail-item">
|
||
<span class="label">可用资金</span>
|
||
<span class="value">
|
||
<AnimatedNumber :value="walletCapital.amount || 0" :decimals="2" />
|
||
</span>
|
||
</div>
|
||
<div class="detail-item">
|
||
<span class="label">冻结点差</span>
|
||
<span class="value">{{ walletCapital.freeze || '0.00' }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="wallet-actions">
|
||
<router-link to="/capital/transfer" class="action-btn">
|
||
<el-icon><RefreshLeft /></el-icon>
|
||
转账
|
||
</router-link>
|
||
<router-link to="/capital/withdraw" class="action-btn">
|
||
<el-icon><Money /></el-icon>
|
||
取款
|
||
</router-link>
|
||
<router-link to="/capital/fundFlow" class="action-btn">
|
||
<el-icon><List /></el-icon>
|
||
资金明细
|
||
</router-link>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
</div>
|
||
<!-- {{ userInfo.role_id }} -->
|
||
<!-- 个人账户 -->
|
||
<section class="section my-accounts" v-if="(userInfo.type*1 !== 1 && userInfo.role_id * 1 === 5) || userInfo.role_id * 1 === 6" >
|
||
<h2 class="section-title">
|
||
<el-icon><User /></el-icon>
|
||
个人账户
|
||
<el-button type="primary" size="small" @click="handleAddSubAccount" v-auth="'user_createAccount'">
|
||
<el-icon><Plus /></el-icon>
|
||
添加子账户
|
||
</el-button>
|
||
</h2>
|
||
<div class="account-grid">
|
||
<div
|
||
v-for="item in accountList"
|
||
:key="item.id"
|
||
class="account-card"
|
||
@click="handleAccountClick(item)"
|
||
>
|
||
<div class="account-header">
|
||
<div class="account-name">
|
||
<span v-if="isEdit !== item.account_id">{{ item.account_name }}</span>
|
||
<el-input
|
||
v-else
|
||
v-model="editName"
|
||
size="small"
|
||
@blur="handleSave"
|
||
@keyup.enter="handleSave"
|
||
ref="inputRef"
|
||
/>
|
||
</div>
|
||
<div class="account-actions">
|
||
<el-icon size="18" @click.stop="handleEdit(item.account_name, item.account_id)">
|
||
<EditPen />
|
||
</el-icon>
|
||
<el-icon size="18" @click.stop="handleSetting(item.account_id)">
|
||
<Setting />
|
||
</el-icon>
|
||
</div>
|
||
</div>
|
||
<div class="account-body">
|
||
<div class="account-number">{{ item.account_id || '--' }}</div>
|
||
<div class="account-stats">
|
||
<div class="stat-item">
|
||
<span class="stat-label">净资产</span>
|
||
<span class="stat-value">
|
||
<AnimatedNumber :value="item?.wallets_trade?.amount || 0" :decimals="2" />
|
||
</span>
|
||
</div>
|
||
<div class="stat-item">
|
||
<span class="stat-label">余额</span>
|
||
<span class="stat-value">
|
||
<AnimatedNumber :value="item?.wallets_trade?.amount || 0" :decimals="2" />
|
||
</span>
|
||
</div>
|
||
<div class="stat-item">
|
||
<span class="stat-label">杠杆</span>
|
||
<span class="stat-value">1:{{ item?.wallets_trade?.lever || '--' }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 推广板块 -->
|
||
<section class="section promotion" v-if="userInfo.type * 1 === 2 && userInfo.role_id * 1 === 5">
|
||
<h2 class="section-title">
|
||
<el-icon><Share /></el-icon>
|
||
推广中心
|
||
</h2>
|
||
<div class="promotion-content">
|
||
<div class="promotion-link">
|
||
<h4>推广链接</h4>
|
||
<div class="link-box">
|
||
<input type="text" :value="copyText" readonly class="link-input" />
|
||
<el-button type="primary" size="small" @click="handleCopyUrl" class="copy-btn">
|
||
<el-icon><DocumentCopy /></el-icon>
|
||
复制
|
||
</el-button>
|
||
</div>
|
||
</div>
|
||
<div class="promotion-qrcode">
|
||
<h4>推广二维码</h4>
|
||
<div class="qrcode-card">
|
||
<canvas ref="qrCanvas"></canvas>
|
||
<p>扫码注册</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<!-- 添加/编辑子账户弹窗 -->
|
||
<AgentDialog
|
||
:visible="dialogVisible"
|
||
:title="dialogTitle"
|
||
:type="dialogType"
|
||
@confirm="handleSubmit"
|
||
@cancel="handleCancel"
|
||
@close="handleClose"
|
||
>
|
||
<div class="tab" v-if="dialogType !== 'add'"
|
||
style="margin-bottom: 20px;">
|
||
<el-button
|
||
:type="dialogType === 'setting' ? 'primary' : 'default'"
|
||
@click="dialogType = 'setting'"
|
||
>
|
||
账户设置
|
||
</el-button>
|
||
<el-button
|
||
:type="dialogType === 'leverage' ? 'primary' : 'default'"
|
||
@click="handleChangeToLeverage"
|
||
>
|
||
修改杠杆
|
||
</el-button>
|
||
</div>
|
||
<AgentForm
|
||
ref="subAccountFormRef"
|
||
:formData="subAccountForm"
|
||
:formItems="subAccountFormItem"
|
||
:formRules="subAccountRules"
|
||
:optionsMap="subAccountFormOptionsMap"
|
||
:rowGutter="rowGutter"
|
||
:colSpan="colSpan"
|
||
/>
|
||
</AgentDialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, computed, onMounted, watch, markRaw } from 'vue'
|
||
import { ElMessage } from 'element-plus'
|
||
import {
|
||
Check,
|
||
Grid,
|
||
Wallet,
|
||
User,
|
||
Share,
|
||
ArrowRight,
|
||
RefreshLeft,
|
||
Money,
|
||
List,
|
||
Plus,
|
||
EditPen,
|
||
Setting,
|
||
DocumentCopy,
|
||
MagicStick,
|
||
CircleCheckFilled,
|
||
TrendCharts,
|
||
UserFilled
|
||
} from '@element-plus/icons-vue'
|
||
import AgentDialog from '@/components/common/Dialog.vue'
|
||
import AgentForm from '@/components/common/Form.vue'
|
||
import { formItem, resetPasswordFormItem, leverageFormItem } from './options'
|
||
import { rules } from './rules'
|
||
import {
|
||
getLeverOptionsApi,
|
||
createAgentApi,
|
||
editAgentNameApi,
|
||
leverageLeverApi,
|
||
} from '@/api/modules/agent'
|
||
import { getAllAccount, getWalletCapital,editAccountPass } from '@/api/modules/dashboard.ts'
|
||
import { getStorage } from '@/utils/storage'
|
||
import { useUserStore } from '@/stores/modules/user.ts'
|
||
import QRCode from 'qrcode'
|
||
import AnimatedNumber from '@/views/agent/user/AnimatedNumber.vue'
|
||
|
||
const userStore = useUserStore()
|
||
|
||
// 判断是否为代理(role_id === 5)
|
||
|
||
// 如何开始步骤
|
||
const startSteps = ref([
|
||
{
|
||
title: '实名认证',
|
||
desc: '完成身份验证',
|
||
path: '/profile/kyc',
|
||
completed: true
|
||
},
|
||
{
|
||
title: '存款',
|
||
desc: '注入资金',
|
||
path: '/capital/rechange',
|
||
completed: true
|
||
},
|
||
{
|
||
title: '交易',
|
||
desc: '开始投资',
|
||
path: '/trade/exe',
|
||
completed: false
|
||
}
|
||
])
|
||
const currentStep = computed(() => {
|
||
const completedCount = startSteps.value.filter(s => s.completed).length
|
||
return Math.min(completedCount, startSteps.value.length - 1)
|
||
})
|
||
|
||
// 常用功能
|
||
const quickActions = ref([
|
||
{
|
||
id: 1,
|
||
title: '存款',
|
||
desc: '安全便捷的充值服务',
|
||
path: '/capital/rechange',
|
||
icon: markRaw(CircleCheckFilled),
|
||
bgColor: 'linear-gradient(135deg, #e6f4ff 0%, #bae0ff 100%)',
|
||
iconColor: '#165DFF'
|
||
},
|
||
{
|
||
id: 2,
|
||
title: '取款',
|
||
desc: '快速到账资金提取',
|
||
path: '/capital/withdraw',
|
||
icon: markRaw(Money),
|
||
bgColor: 'linear-gradient(135deg, #f6ffed 0%, #d9f7be 100%)',
|
||
iconColor: '#52c41a'
|
||
},
|
||
{
|
||
id: 3,
|
||
title: '交易',
|
||
desc: '全球金融产品交易',
|
||
path: '/trade/exe',
|
||
icon: markRaw(TrendCharts),
|
||
bgColor: 'linear-gradient(135deg, #fff7e6 0%, #ffd591 100%)',
|
||
iconColor: '#fa8c16'
|
||
}
|
||
])
|
||
|
||
// 钱包数据
|
||
const walletCapital = ref<any>({})
|
||
const getWalletCapitaInfo = async () => {
|
||
try {
|
||
const res = await getWalletCapital()
|
||
console.log('getWalletCapitaInfo', res)
|
||
walletCapital.value = res || {}
|
||
} catch (error) {
|
||
console.error('获取钱包信息失败', error)
|
||
}
|
||
}
|
||
|
||
// 账户列表
|
||
const accountList = ref<any[]>([])
|
||
const getAccoundList = async () => {
|
||
try {
|
||
const res = await getAllAccount({ username: '' })
|
||
console.log(res)
|
||
accountList.value = res || []
|
||
} catch (error) {
|
||
console.error('获取账户列表失败', error)
|
||
}
|
||
}
|
||
|
||
// 钱包点击
|
||
const handleWalletClick = () => {
|
||
console.log('钱包点击')
|
||
}
|
||
|
||
// 添加子账户
|
||
const handleAddSubAccount = () => {
|
||
dialogVisible.value = true
|
||
dialogTitle.value = '添加子账户'
|
||
dialogType.value = 'add'
|
||
}
|
||
|
||
// 账户点击
|
||
const handleAccountClick = (item: any) => {
|
||
console.log('账户点击', item)
|
||
}
|
||
|
||
// 编辑账户
|
||
let account_id = ''
|
||
const editName = ref('')
|
||
const isEdit = ref('')
|
||
const inputRef = ref()
|
||
|
||
const handleEdit = async (name: string, id: string) => {
|
||
if (isEdit.value) return (isEdit.value = '')
|
||
isEdit.value = id
|
||
editName.value = name
|
||
account_id = id
|
||
setTimeout(() => {
|
||
inputRef.value?.focus()
|
||
}, 100)
|
||
}
|
||
|
||
// 保存编辑
|
||
const handleSave = async () => {
|
||
if (account_id === '') return ElMessage.error('请先选择账户')
|
||
try {
|
||
await editAgentNameApi({
|
||
account_id,
|
||
account_name: editName.value
|
||
})
|
||
ElMessage.success('修改成功')
|
||
isEdit.value = ''
|
||
getAccoundList()
|
||
} catch (error) {
|
||
ElMessage.error('修改失败')
|
||
}
|
||
}
|
||
|
||
// 账户设置
|
||
const handleSetting = (id: string) => {
|
||
dialogVisible.value = true
|
||
dialogTitle.value = '账户设置'
|
||
dialogType.value = 'setting'
|
||
account_id = id
|
||
}
|
||
|
||
// 弹窗相关
|
||
const dialogVisible = ref(false)
|
||
const dialogTitle = ref('')
|
||
const dialogType = ref('add')
|
||
|
||
const subAccountForm = ref({
|
||
password: '',
|
||
leverage: null,
|
||
resetPassword: '',
|
||
confirmPassword: ''
|
||
})
|
||
const subAccountFormRef = ref()
|
||
const subAccountRules = ref(rules(subAccountForm.value))
|
||
const subAccountFormItem = computed(() => {
|
||
if (dialogType.value === 'setting') {
|
||
return resetPasswordFormItem
|
||
} else if (dialogType.value === 'leverage') {
|
||
return leverageFormItem
|
||
}
|
||
return formItem
|
||
})
|
||
const subAccountFormOptionsMap = ref({
|
||
leverage: []
|
||
})
|
||
const rowGutter = ref(20)
|
||
const colSpan = ref(12)
|
||
|
||
// 获取杠杆选项
|
||
const getLeverOptions = async () => {
|
||
try {
|
||
const data: any = await getLeverOptionsApi()
|
||
console.log(data)
|
||
subAccountFormOptionsMap.value.leverage = data.map((item: any) => ({
|
||
label: item.label,
|
||
value: item.value,
|
||
}))
|
||
} catch (error) {
|
||
console.error('获取杠杆选项失败', error)
|
||
}
|
||
}
|
||
|
||
// 切换到杠杆表单
|
||
const handleChangeToLeverage = () => {
|
||
const currentAccount = accountList.value.find((item: any) => item.account_id === account_id)
|
||
if (currentAccount?.wallets_trade?.lever) {
|
||
subAccountForm.value.leverage = currentAccount.wallets_trade.lever
|
||
}
|
||
dialogType.value = 'leverage'
|
||
}
|
||
|
||
// 提交表单
|
||
const handleSubmit = async () => {
|
||
console.log(dialogType.value)
|
||
await subAccountFormRef.value.validate()
|
||
|
||
if (dialogType.value === 'add') {
|
||
const params = {
|
||
password: subAccountForm.value.password,
|
||
lever: subAccountForm.value.leverage
|
||
}
|
||
await createAgentApi(params)
|
||
ElMessage.success('子账户创建成功')
|
||
} else if (dialogType.value === 'setting') {
|
||
const params = {
|
||
user_password: subAccountForm.value.resetPassword,
|
||
account_password: subAccountForm.value.confirmPassword,
|
||
account_id: account_id || ''
|
||
}
|
||
await editAccountPass(params)
|
||
ElMessage.success('修改成功')
|
||
subAccountForm.value.resetPassword = ''
|
||
subAccountForm.value.confirmPassword = ''
|
||
} else if (dialogType.value === 'leverage') {
|
||
const params = {
|
||
account_id: account_id || '',
|
||
lever: subAccountForm.value.leverage
|
||
}
|
||
await leverageLeverApi(params)
|
||
ElMessage.success('杠杆修改成功')
|
||
}
|
||
handleClose()
|
||
getAccoundList()
|
||
}
|
||
|
||
const handleClose = () => {
|
||
dialogVisible.value = false
|
||
}
|
||
const handleCancel = () => {
|
||
dialogVisible.value = false
|
||
}
|
||
|
||
// 推广相关
|
||
const userInfo = getStorage<any>('userInfo')
|
||
const copyText = ref(userInfo.invite_url)
|
||
const qrCanvas = ref()
|
||
const promotionStats = ref({
|
||
startTime: '2026-03-20'
|
||
})
|
||
|
||
// 生成二维码
|
||
const generateBasic = async () => {
|
||
const userInfoData = getStorage<any>('userInfo')
|
||
if (!userInfoData?.invite_url || !qrCanvas.value) return
|
||
try {
|
||
await QRCode.toCanvas(qrCanvas.value, userInfoData.invite_url, {
|
||
width: 120,
|
||
margin: 2,
|
||
color: {
|
||
dark: '#165DFF',
|
||
light: '#ffffff'
|
||
}
|
||
})
|
||
} catch (err) {
|
||
console.error('生成二维码失败', err)
|
||
}
|
||
}
|
||
|
||
// 复制链接
|
||
const handleCopyUrl = async () => {
|
||
const success = await copyToClipboard(copyText.value)
|
||
if (success) {
|
||
ElMessage.success('复制成功')
|
||
} else {
|
||
ElMessage.error('复制失败,请手动复制')
|
||
}
|
||
}
|
||
|
||
async function copyToClipboard(text: string) {
|
||
try {
|
||
if (navigator.clipboard && window.isSecureContext) {
|
||
await navigator.clipboard.writeText(text)
|
||
return true
|
||
}
|
||
// 降级方案
|
||
const textarea = document.createElement('textarea')
|
||
textarea.value = text
|
||
textarea.style.position = 'fixed'
|
||
textarea.style.opacity = '0'
|
||
document.body.appendChild(textarea)
|
||
textarea.select()
|
||
const success = document.execCommand('copy')
|
||
document.body.removeChild(textarea)
|
||
return success
|
||
} catch (err) {
|
||
console.error('复制失败:', err)
|
||
return false
|
||
}
|
||
}
|
||
|
||
// 初始化
|
||
onMounted(async () => {
|
||
await Promise.all([
|
||
getAccoundList(),
|
||
getWalletCapitaInfo(),
|
||
getLeverOptions()
|
||
])
|
||
if (userInfo.type * 1 === 2 && userInfo.role_id * 1 === 5) {
|
||
generateBasic()
|
||
}
|
||
})
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
// 变量
|
||
$primary-color: #165DFF;
|
||
$success-color: #52c41a;
|
||
$warning-color: #fa8c16;
|
||
$danger-color: #ff4d4f;
|
||
$text-primary: #1f1f1f;
|
||
$text-secondary: #666666;
|
||
$text-tertiary: #999999;
|
||
$border-color: #e8e8e8;
|
||
$bg-light: #f7f8fa;
|
||
$shadow-light: 0 2px 12px rgba(22, 93, 255, 0.08);
|
||
$shadow-hover: 0 8px 24px rgba(22, 93, 255, 0.12);
|
||
|
||
.personal-center {
|
||
padding: 24px;
|
||
background: $bg-light;
|
||
min-height: 100%;
|
||
}
|
||
|
||
// 顶部区域布局
|
||
.top-section {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1.2fr;
|
||
gap: 20px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
// 中部区域布局
|
||
.middle-section {
|
||
display: grid;
|
||
grid-template-columns: 0.8fr 1fr;
|
||
gap: 20px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.section {
|
||
background: #ffffff;
|
||
border-radius: 12px;
|
||
padding: 20px;
|
||
box-shadow: $shadow-light;
|
||
transition: box-shadow 0.3s ease;
|
||
|
||
&:hover {
|
||
box-shadow: $shadow-hover;
|
||
}
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: $text-primary;
|
||
margin-bottom: 20px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
|
||
.el-icon {
|
||
color: $primary-color;
|
||
}
|
||
|
||
.wallet-badge {
|
||
font-size: 12px;
|
||
font-weight: normal;
|
||
color: $text-tertiary;
|
||
background: $bg-light;
|
||
padding: 4px 12px;
|
||
border-radius: 4px;
|
||
margin-left: auto;
|
||
}
|
||
|
||
.el-button {
|
||
margin-left: auto;
|
||
}
|
||
}
|
||
|
||
// 如何开始 - 进度步骤
|
||
.getting-started {
|
||
.progress-steps {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 12px 0;
|
||
}
|
||
|
||
.step-item {
|
||
display: flex;
|
||
align-items: center;
|
||
position: relative;
|
||
flex: 1;
|
||
justify-content: center;
|
||
|
||
&:last-child {
|
||
.step-connector {
|
||
display: none;
|
||
}
|
||
}
|
||
}
|
||
|
||
.step-icon {
|
||
width: 40px;
|
||
height: 40px;
|
||
border-radius: 50%;
|
||
background: $bg-light;
|
||
border: 2px solid $border-color;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: $text-tertiary;
|
||
transition: all 0.3s ease;
|
||
z-index: 2;
|
||
|
||
.el-icon {
|
||
font-size: 20px;
|
||
color: #ffffff;
|
||
}
|
||
}
|
||
|
||
.step-info {
|
||
display: flex;
|
||
flex-direction: column;
|
||
margin-left: 10px;
|
||
}
|
||
|
||
.step-title {
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: $text-primary;
|
||
text-decoration: none;
|
||
transition: color 0.3s ease;
|
||
|
||
&:hover {
|
||
color: $primary-color;
|
||
}
|
||
}
|
||
|
||
.step-desc {
|
||
font-size: 11px;
|
||
color: $text-tertiary;
|
||
margin-top: 2px;
|
||
}
|
||
|
||
.step-connector {
|
||
flex: 0.5;
|
||
height: 2px;
|
||
background: $border-color;
|
||
margin: 0 12px;
|
||
position: relative;
|
||
margin-top: -20px;
|
||
}
|
||
|
||
.connector-line {
|
||
height: 100%;
|
||
width: 0;
|
||
background: $primary-color;
|
||
transition: width 0.5s ease;
|
||
|
||
&.filled {
|
||
width: 100%;
|
||
}
|
||
}
|
||
|
||
.step-item.completed {
|
||
.step-icon {
|
||
background: $primary-color;
|
||
border-color: $primary-color;
|
||
color: #ffffff;
|
||
}
|
||
|
||
.step-title {
|
||
color: $primary-color;
|
||
}
|
||
}
|
||
|
||
.step-item.active {
|
||
.step-icon {
|
||
background: $primary-color;
|
||
border-color: $primary-color;
|
||
color: #ffffff;
|
||
box-shadow: 0 0 0 4px rgba(22, 93, 255, 0.2);
|
||
}
|
||
|
||
.step-title {
|
||
color: $primary-color;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 常用功能 - 快捷卡片
|
||
.quick-actions {
|
||
.action-cards {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 12px;
|
||
}
|
||
|
||
.action-card {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 16px;
|
||
background: #ffffff;
|
||
border: 1px solid $border-color;
|
||
border-radius: 10px;
|
||
text-decoration: none;
|
||
transition: all 0.3s ease;
|
||
cursor: pointer;
|
||
|
||
&:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: $shadow-hover;
|
||
border-color: $primary-color;
|
||
|
||
.card-arrow {
|
||
transform: translateX(4px);
|
||
color: $primary-color;
|
||
}
|
||
}
|
||
}
|
||
|
||
.card-icon {
|
||
width: 48px;
|
||
height: 48px;
|
||
border-radius: 12px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.card-content {
|
||
flex: 1;
|
||
margin-left: 12px;
|
||
|
||
h3 {
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: $text-primary;
|
||
margin: 0 0 2px 0;
|
||
}
|
||
|
||
p {
|
||
font-size: 12px;
|
||
color: $text-tertiary;
|
||
margin: 0;
|
||
}
|
||
}
|
||
|
||
.card-arrow {
|
||
color: $text-tertiary;
|
||
transition: all 0.3s ease;
|
||
|
||
.el-icon {
|
||
font-size: 18px;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 我的钱包 - 通栏大卡片
|
||
.my-wallet {
|
||
.wallet-card {
|
||
background: linear-gradient(135deg, #f0f5ff 0%, #e6f0ff 100%);
|
||
border: 1px solid rgba(22, 93, 255, 0.1);
|
||
border-radius: 10px;
|
||
padding: 24px;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: flex-start;
|
||
transition: all 0.3s ease;
|
||
cursor: pointer;
|
||
|
||
&:hover {
|
||
box-shadow: $shadow-hover;
|
||
}
|
||
}
|
||
|
||
.wallet-main {
|
||
flex: 1;
|
||
}
|
||
|
||
.balance-section {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.balance-label {
|
||
font-size: 13px;
|
||
color: $text-tertiary;
|
||
margin-bottom: 6px;
|
||
}
|
||
|
||
.balance-value {
|
||
font-size: 32px;
|
||
font-weight: 700;
|
||
color: $primary-color;
|
||
letter-spacing: -1px;
|
||
|
||
:deep(.animated-number) {
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
}
|
||
|
||
.balance-detail {
|
||
display: flex;
|
||
gap: 32px;
|
||
}
|
||
|
||
.detail-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
|
||
.label {
|
||
font-size: 12px;
|
||
color: $text-tertiary;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.value {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: $text-primary;
|
||
}
|
||
}
|
||
|
||
.wallet-actions {
|
||
display: flex;
|
||
gap: 10px;
|
||
}
|
||
|
||
.action-btn {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 8px 16px;
|
||
background: #ffffff;
|
||
border: 1px solid $border-color;
|
||
border-radius: 6px;
|
||
color: $text-primary;
|
||
text-decoration: none;
|
||
font-size: 13px;
|
||
font-weight: 500;
|
||
transition: all 0.3s ease;
|
||
|
||
.el-icon {
|
||
font-size: 14px;
|
||
}
|
||
|
||
&:hover {
|
||
background: $primary-color;
|
||
border-color: $primary-color;
|
||
color: #ffffff;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 个人账户 - 横向卡片网格
|
||
.my-accounts {
|
||
margin-bottom: 20px;
|
||
.account-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
|
||
gap: 16px;
|
||
}
|
||
|
||
.account-card {
|
||
background: #ffffff;
|
||
border: 1px solid $border-color;
|
||
border-radius: 10px;
|
||
padding: 16px;
|
||
transition: all 0.3s ease;
|
||
cursor: pointer;
|
||
|
||
&:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: $shadow-hover;
|
||
border-color: $primary-color;
|
||
}
|
||
}
|
||
|
||
.account-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 12px;
|
||
padding-bottom: 10px;
|
||
border-bottom: 1px solid $border-color;
|
||
}
|
||
|
||
.account-name {
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: $text-primary;
|
||
|
||
.el-input {
|
||
width: 120px;
|
||
}
|
||
}
|
||
|
||
.account-actions {
|
||
display: flex;
|
||
gap: 6px;
|
||
|
||
.el-icon {
|
||
font-size: 14px;
|
||
color: $text-tertiary;
|
||
cursor: pointer;
|
||
padding: 4px;
|
||
border-radius: 4px;
|
||
transition: all 0.3s ease;
|
||
|
||
&:hover {
|
||
color: $primary-color;
|
||
background: rgba(22, 93, 255, 0.1);
|
||
}
|
||
}
|
||
}
|
||
|
||
.account-number {
|
||
font-size: 12px;
|
||
color: $text-tertiary;
|
||
margin-bottom: 12px;
|
||
font-family: 'Monaco', 'Menlo', monospace;
|
||
}
|
||
|
||
.account-stats {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 8px;
|
||
}
|
||
|
||
.stat-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
text-align: center;
|
||
}
|
||
|
||
.stat-label {
|
||
font-size: 11px;
|
||
color: $text-tertiary;
|
||
margin-bottom: 2px;
|
||
}
|
||
|
||
.stat-value {
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: $text-primary;
|
||
}
|
||
|
||
.account-loss {
|
||
margin-top: 12px;
|
||
padding: 10px;
|
||
background: rgba(255, 77, 79, 0.05);
|
||
border-radius: 6px;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
|
||
.loss-label {
|
||
font-size: 12px;
|
||
color: $danger-color;
|
||
}
|
||
|
||
.loss-value {
|
||
font-size: 16px;
|
||
font-weight: 700;
|
||
color: $danger-color;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 推广中心 - 左右布局
|
||
.promotion {
|
||
margin-bottom: 20px;
|
||
.promotion-content {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16px;
|
||
}
|
||
|
||
.promotion-link,
|
||
.promotion-qrcode {
|
||
h4 {
|
||
font-size: 13px;
|
||
color: $text-secondary;
|
||
margin: 0 0 10px 0;
|
||
font-weight: 500;
|
||
}
|
||
}
|
||
|
||
.link-box {
|
||
display: flex;
|
||
gap: 10px;
|
||
|
||
.link-input {
|
||
flex: 1;
|
||
padding: 10px 14px;
|
||
border: 1px solid $border-color;
|
||
border-radius: 6px;
|
||
font-size: 13px;
|
||
color: $text-primary;
|
||
background: $bg-light;
|
||
outline: none;
|
||
|
||
&:focus {
|
||
border-color: $primary-color;
|
||
}
|
||
}
|
||
|
||
.copy-btn {
|
||
flex-shrink: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
}
|
||
}
|
||
|
||
.qrcode-card {
|
||
background: $bg-light;
|
||
border-radius: 10px;
|
||
padding: 20px;
|
||
text-align: center;
|
||
|
||
canvas {
|
||
display: block;
|
||
margin: 0 auto 10px;
|
||
}
|
||
|
||
p {
|
||
margin: 0;
|
||
font-size: 12px;
|
||
color: $text-tertiary;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 弹窗样式
|
||
.dialog-tabs {
|
||
display: flex;
|
||
gap: 12px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
// 响应式适配
|
||
@media (max-width: 1400px) {
|
||
.top-section {
|
||
grid-template-columns: 1fr 1fr;
|
||
}
|
||
|
||
.middle-section {
|
||
grid-template-columns: 1fr 1fr;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 1200px) {
|
||
.top-section {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.middle-section {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.quick-actions {
|
||
.action-cards {
|
||
grid-template-columns: repeat(3, 1fr);
|
||
}
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.personal-center {
|
||
padding: 16px;
|
||
}
|
||
|
||
.section {
|
||
padding: 16px;
|
||
}
|
||
|
||
.top-section,
|
||
.middle-section {
|
||
grid-template-columns: 1fr;
|
||
gap: 16px;
|
||
}
|
||
|
||
.getting-started {
|
||
.progress-steps {
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 16px;
|
||
}
|
||
|
||
.step-item {
|
||
width: 100%;
|
||
max-width: 280px;
|
||
justify-content: flex-start;
|
||
padding-left: 20px;
|
||
}
|
||
|
||
.step-connector {
|
||
display: none;
|
||
}
|
||
}
|
||
|
||
.quick-actions {
|
||
.action-cards {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
|
||
.my-wallet {
|
||
.wallet-card {
|
||
flex-direction: column;
|
||
gap: 16px;
|
||
}
|
||
|
||
.balance-value {
|
||
font-size: 28px;
|
||
}
|
||
|
||
.balance-detail {
|
||
flex-wrap: wrap;
|
||
gap: 16px;
|
||
}
|
||
|
||
.wallet-actions {
|
||
width: 100%;
|
||
flex-wrap: wrap;
|
||
}
|
||
}
|
||
|
||
.my-accounts {
|
||
.account-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
|
||
.user-info-panel {
|
||
.info-panel {
|
||
height: 100%;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 用户信息面板样式
|
||
.user-info-panel {
|
||
.info-panel {
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.panel-header {
|
||
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding-bottom: 12px;
|
||
margin-bottom: 16px;
|
||
border-bottom: 1px solid $border-color;
|
||
|
||
.el-icon {
|
||
font-size: 18px;
|
||
color: $primary-color;
|
||
}
|
||
|
||
span {
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: $text-primary;
|
||
}
|
||
}
|
||
|
||
.panel-content {
|
||
flex:1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
|
||
.user-info {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.user-avatar {
|
||
width: 48px;
|
||
height: 48px;
|
||
border-radius: 50%;
|
||
background: linear-gradient(135deg, #e6f4ff 0%, #bae0ff 100%);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
.el-icon {
|
||
color: $primary-color;
|
||
}
|
||
}
|
||
|
||
.user-details {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 4px;
|
||
}
|
||
|
||
.user-name {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: $text-primary;
|
||
}
|
||
|
||
.info-row {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 8px 0;
|
||
border-bottom: 1px solid $bg-light;
|
||
|
||
&:last-child {
|
||
border-bottom: none;
|
||
}
|
||
}
|
||
|
||
.info-label {
|
||
font-size: 13px;
|
||
color: $text-tertiary;
|
||
}
|
||
|
||
.info-value {
|
||
font-size: 13px;
|
||
color: $text-primary;
|
||
font-weight: 500;
|
||
}
|
||
}
|
||
}
|
||
</style>
|