Merge branch 'main' of https://gitlab.guxuan.icu/Leo_Ding/GPU_Web
This commit is contained in:
commit
10a9268bbb
@ -46,10 +46,10 @@ export const getBankCardInfo = (params:any) => request.get('/v1/bank_card/bank_c
|
|||||||
export const delBankCard = (params:any) => request.post('/v1/bank_card/delete_bank_card',params)
|
export const delBankCard = (params:any) => request.post('/v1/bank_card/delete_bank_card',params)
|
||||||
|
|
||||||
// 发票管理-开票记录
|
// 发票管理-开票记录
|
||||||
export const invoiceList = (params:any) => request.get('/v1/order/invoice_list',{params})
|
export const invoiceList = (params:any) => request.get('/v1/invoice/invoice_list',{params})
|
||||||
|
|
||||||
// 发票管理-开发记录详情
|
// 发票管理-开发记录详情
|
||||||
export const invoiceDetail = (id:any) => request.delete(`/v1/order/invoice_detail/${id}`)
|
export const invoiceDetail = (id:any) => request.delete(`/v1/invoice/invoice_detail/${id}`)
|
||||||
|
|
||||||
// 获取订单列表
|
// 获取订单列表
|
||||||
export const getOrderList = (params:any) => request.get('/v1/order/order_list',{params})
|
export const getOrderList = (params:any) => request.get('/v1/order/order_list',{params})
|
||||||
@ -8,197 +8,178 @@
|
|||||||
<a-breadcrumb-item>算力点兑换</a-breadcrumb-item>
|
<a-breadcrumb-item>算力点兑换</a-breadcrumb-item>
|
||||||
</a-breadcrumb>
|
</a-breadcrumb>
|
||||||
|
|
||||||
<!-- 页面标题 -->
|
|
||||||
<div class="page-header">
|
<!-- 余额卡片 -->
|
||||||
<h1 class="page-title">算力点兑换</h1>
|
<a-card class="balance-card" :bordered="false">
|
||||||
<p class="page-description">使用余额兑换算力点,提升计算能力</p>
|
<div class="balance-info">
|
||||||
</div>
|
<div class="balance-item">
|
||||||
|
<div class="balance-label">
|
||||||
|
|
||||||
|
<span class="label-text">我的余额</span>
|
||||||
|
</div>
|
||||||
|
<div class="balance-value">
|
||||||
|
<span class="currency">¥</span>
|
||||||
|
<span class="amount">{{ formatCurrency(balance) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="balance-item">
|
||||||
|
<div class="balance-label">
|
||||||
|
|
||||||
|
<span class="label-text">算力点</span>
|
||||||
|
</div>
|
||||||
|
<div class="balance-value">
|
||||||
|
<span class="points">{{ formatPoints(points) }}</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</a-card>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- 兑换卡片 -->
|
||||||
|
<a-card class="exchange-card" title="兑换算力点">
|
||||||
|
<div class="exchange-content">
|
||||||
|
<!-- 兑换金额选择 -->
|
||||||
|
<div class="exchange-section">
|
||||||
|
<div class="amount-options">
|
||||||
|
<div class="section-title">选择兑换金额</div>
|
||||||
|
<a-button v-for="option in amountOptions" :key="option.value"
|
||||||
|
:class="['amount-option', { 'selected': selectedAmount === option.value }]"
|
||||||
|
@click="selectAmount(option.value)" size="large">
|
||||||
|
<div class="amount-option-content">
|
||||||
|
<div class="amount-number">{{ option.value }}</div>
|
||||||
|
</div>
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 自定义输入 -->
|
||||||
|
<div class="custom-amount">
|
||||||
|
<a-input-group compact>
|
||||||
|
<a-input v-model:value="customAmount" placeholder="输入其他金额" size="large" style="width: calc(100% - 120px)"
|
||||||
|
@change="handleCustomAmountChange" :disabled="loading" />
|
||||||
|
<!-- <a-button type="primary" size="large" style="width: 120px" :disabled="!isCustomAmountValid || loading"
|
||||||
|
@click="handleCustomAmountConfirm">
|
||||||
|
确认
|
||||||
|
</a-button> -->
|
||||||
|
</a-input-group>
|
||||||
|
<p class="input-name">用户自定义输入算力点数量</p>
|
||||||
|
<div v-if="customAmountError" class="error-text">
|
||||||
|
<ExclamationCircleOutlined />
|
||||||
|
{{ customAmountError }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 兑换规则说明 -->
|
||||||
|
<div class="exchange-section">
|
||||||
|
<h3 class="section-title">兑换规则</h3>
|
||||||
|
<div class="exchange-rules">
|
||||||
|
<div class="rule-item">
|
||||||
|
<CheckCircleOutlined class="rule-icon" />
|
||||||
|
<span>算力点兑换比例为人民币 <strong>1元 = 1算力点</strong></span>
|
||||||
|
</div>
|
||||||
|
<div class="rule-item">
|
||||||
|
<ExclamationCircleOutlined class="rule-icon" />
|
||||||
|
<span><strong>算力点不可退</strong>,兑换前请确认需求</span>
|
||||||
|
</div>
|
||||||
|
<div class="rule-item">
|
||||||
|
<InfoCircleOutlined class="rule-icon" />
|
||||||
|
<span>兑换后算力点立即生效,可用于平台所有计算服务</span>
|
||||||
|
</div>
|
||||||
|
<div class="rule-item">
|
||||||
|
<SafetyOutlined class="rule-icon" />
|
||||||
|
<span>兑换过程安全加密,保障您的资金安全</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 兑换信息展示 -->
|
||||||
|
<div v-if="selectedExchangeAmount > 0" class="exchange-preview">
|
||||||
|
<div class="preview-card">
|
||||||
|
<div class="preview-header">
|
||||||
|
<div class="preview-title">兑换明细</div>
|
||||||
|
<a-button type="text" @click="clearSelection">
|
||||||
|
<CloseOutlined />
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
<div class="preview-content">
|
||||||
|
<div class="preview-item">
|
||||||
|
<span class="preview-label">兑换金额:</span>
|
||||||
|
<span class="preview-value">¥{{ selectedExchangeAmount }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="preview-item">
|
||||||
|
<span class="preview-label">获得算力点:</span>
|
||||||
|
<span class="preview-value points-value">{{ selectedExchangeAmount }} 算力点</span>
|
||||||
|
</div>
|
||||||
|
<div class="preview-item">
|
||||||
|
<span class="preview-label">兑换后余额:</span>
|
||||||
|
<span class="preview-value">¥{{ formatCurrency(balance - selectedExchangeAmount) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="preview-item">
|
||||||
|
<span class="preview-label">兑换后算力点:</span>
|
||||||
|
<span class="preview-value points-value">{{ formatPoints(points + selectedExchangeAmount) }}
|
||||||
|
算力点</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 用户协议确认 -->
|
||||||
|
<div class="agreement-section">
|
||||||
|
<a-checkbox v-model:checked="agreementChecked" :disabled="loading">
|
||||||
|
在确认兑换算力点前,我已阅读并确认
|
||||||
|
<a @click="showAgreementModal" class="agreement-link">《用户协议》</a>
|
||||||
|
</a-checkbox>
|
||||||
|
<div v-if="!agreementChecked && showAgreementError" class="error-text">
|
||||||
|
请阅读并确认用户协议
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 操作按钮 -->
|
||||||
|
<div class="action-buttons">
|
||||||
|
<a-button type="primary" size="large" :loading="loading" :disabled="!canExchange" @click="handleExchange"
|
||||||
|
class="exchange-button">
|
||||||
|
<template #icon>
|
||||||
|
<ThunderboltOutlined />
|
||||||
|
</template>
|
||||||
|
确认兑换
|
||||||
|
</a-button>
|
||||||
|
<a-button size="large" @click="handleCancel" :disabled="loading" class="cancel-button">
|
||||||
|
取消
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
|
||||||
<!-- 主要内容区域 -->
|
<!-- 主要内容区域 -->
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<!-- 余额卡片 -->
|
<a-card class="history-card" title="算力点兑换历史">
|
||||||
<a-card class="balance-card" :bordered="false">
|
<a-table :columns="historyColumns" :data-source="exchangeHistory" row-key="key" :pagination="false">
|
||||||
<div class="balance-info">
|
<!-- 自定义状态列的渲染 -->
|
||||||
<div class="balance-item">
|
<template #bodyCell="{ column, record }">
|
||||||
<div class="balance-label">
|
<template v-if="column.key === 'status'">
|
||||||
<span class="icon-wrapper">
|
<span :style="{ color: getStatusColor(record.status) }">{{ getStatusText(record.status) }}</span>
|
||||||
<DollarCircleOutlined />
|
</template>
|
||||||
</span>
|
<template v-else-if="column.key === 'amount' || column.key === 'points'">
|
||||||
<span class="label-text">我的余额</span>
|
<span>{{ formatCurrency(record.amount) }}</span>
|
||||||
</div>
|
</template>
|
||||||
<div class="balance-value">
|
<template v-else>
|
||||||
<span class="currency">¥</span>
|
{{ record[column.dataIndex] }}
|
||||||
<span class="amount">{{ formatCurrency(balance) }}</span>
|
</template>
|
||||||
</div>
|
</template>
|
||||||
</div>
|
</a-table>
|
||||||
<div class="balance-item">
|
|
||||||
<div class="balance-label">
|
|
||||||
<span class="icon-wrapper">
|
|
||||||
<ThunderboltOutlined />
|
|
||||||
</span>
|
|
||||||
<span class="label-text">当前算力点</span>
|
|
||||||
</div>
|
|
||||||
<div class="balance-value">
|
|
||||||
<span class="points">{{ formatPoints(points) }}</span>
|
|
||||||
<span class="points-unit">算力点</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="balance-tips">
|
|
||||||
<InfoCircleOutlined />
|
|
||||||
<span>余额可用于兑换算力点,算力点可用于平台计算服务</span>
|
|
||||||
</div>
|
|
||||||
</a-card>
|
</a-card>
|
||||||
|
|
||||||
<!-- 兑换卡片 -->
|
|
||||||
<a-card class="exchange-card" title="兑换算力点">
|
|
||||||
<div class="exchange-content">
|
|
||||||
<!-- 兑换金额选择 -->
|
|
||||||
<div class="exchange-section">
|
|
||||||
<h3 class="section-title">选择兑换金额</h3>
|
|
||||||
<p class="section-subtitle">请选择或输入要兑换的金额</p>
|
|
||||||
|
|
||||||
<div class="amount-options">
|
|
||||||
<a-button
|
|
||||||
v-for="option in amountOptions"
|
|
||||||
:key="option.value"
|
|
||||||
:class="['amount-option', { 'selected': selectedAmount === option.value }]"
|
|
||||||
@click="selectAmount(option.value)"
|
|
||||||
size="large"
|
|
||||||
>
|
|
||||||
<div class="amount-option-content">
|
|
||||||
<div class="amount-number">¥{{ option.value }}</div>
|
|
||||||
<div class="amount-points">= {{ option.value }} 算力点</div>
|
|
||||||
</div>
|
|
||||||
</a-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 自定义输入 -->
|
|
||||||
<div class="custom-amount">
|
|
||||||
<a-input-group compact>
|
|
||||||
<a-input
|
|
||||||
v-model:value="customAmount"
|
|
||||||
placeholder="输入其他金额"
|
|
||||||
size="large"
|
|
||||||
style="width: calc(100% - 120px)"
|
|
||||||
@change="handleCustomAmountChange"
|
|
||||||
:disabled="loading"
|
|
||||||
/>
|
|
||||||
<a-button
|
|
||||||
type="primary"
|
|
||||||
size="large"
|
|
||||||
style="width: 120px"
|
|
||||||
:disabled="!isCustomAmountValid || loading"
|
|
||||||
@click="handleCustomAmountConfirm"
|
|
||||||
>
|
|
||||||
确认
|
|
||||||
</a-button>
|
|
||||||
</a-input-group>
|
|
||||||
<div v-if="customAmountError" class="error-text">
|
|
||||||
<ExclamationCircleOutlined />
|
|
||||||
{{ customAmountError }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 兑换规则说明 -->
|
|
||||||
<div class="exchange-section">
|
|
||||||
<h3 class="section-title">兑换规则</h3>
|
|
||||||
<div class="exchange-rules">
|
|
||||||
<div class="rule-item">
|
|
||||||
<CheckCircleOutlined class="rule-icon" />
|
|
||||||
<span>算力点兑换比例为人民币 <strong>1元 = 1算力点</strong></span>
|
|
||||||
</div>
|
|
||||||
<div class="rule-item">
|
|
||||||
<ExclamationCircleOutlined class="rule-icon" />
|
|
||||||
<span><strong>算力点不可退</strong>,兑换前请确认需求</span>
|
|
||||||
</div>
|
|
||||||
<div class="rule-item">
|
|
||||||
<InfoCircleOutlined class="rule-icon" />
|
|
||||||
<span>兑换后算力点立即生效,可用于平台所有计算服务</span>
|
|
||||||
</div>
|
|
||||||
<div class="rule-item">
|
|
||||||
<SafetyOutlined class="rule-icon" />
|
|
||||||
<span>兑换过程安全加密,保障您的资金安全</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 兑换信息展示 -->
|
|
||||||
<div v-if="selectedExchangeAmount > 0" class="exchange-preview">
|
|
||||||
<div class="preview-card">
|
|
||||||
<div class="preview-header">
|
|
||||||
<div class="preview-title">兑换明细</div>
|
|
||||||
<a-button type="text" @click="clearSelection">
|
|
||||||
<CloseOutlined />
|
|
||||||
</a-button>
|
|
||||||
</div>
|
|
||||||
<div class="preview-content">
|
|
||||||
<div class="preview-item">
|
|
||||||
<span class="preview-label">兑换金额:</span>
|
|
||||||
<span class="preview-value">¥{{ selectedExchangeAmount }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="preview-item">
|
|
||||||
<span class="preview-label">获得算力点:</span>
|
|
||||||
<span class="preview-value points-value">{{ selectedExchangeAmount }} 算力点</span>
|
|
||||||
</div>
|
|
||||||
<div class="preview-item">
|
|
||||||
<span class="preview-label">兑换后余额:</span>
|
|
||||||
<span class="preview-value">¥{{ formatCurrency(balance - selectedExchangeAmount) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="preview-item">
|
|
||||||
<span class="preview-label">兑换后算力点:</span>
|
|
||||||
<span class="preview-value points-value">{{ formatPoints(points + selectedExchangeAmount) }} 算力点</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 用户协议确认 -->
|
|
||||||
<div class="agreement-section">
|
|
||||||
<a-checkbox v-model:checked="agreementChecked" :disabled="loading">
|
|
||||||
在确认兑换算力点前,我已阅读并确认
|
|
||||||
<a @click="showAgreementModal" class="agreement-link">《用户协议》</a>
|
|
||||||
</a-checkbox>
|
|
||||||
<div v-if="!agreementChecked && showAgreementError" class="error-text">
|
|
||||||
请阅读并确认用户协议
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 操作按钮 -->
|
|
||||||
<div class="action-buttons">
|
|
||||||
<a-button
|
|
||||||
type="primary"
|
|
||||||
size="large"
|
|
||||||
:loading="loading"
|
|
||||||
:disabled="!canExchange"
|
|
||||||
@click="handleExchange"
|
|
||||||
class="exchange-button"
|
|
||||||
>
|
|
||||||
<template #icon><ThunderboltOutlined /></template>
|
|
||||||
确认兑换
|
|
||||||
</a-button>
|
|
||||||
<a-button
|
|
||||||
size="large"
|
|
||||||
@click="handleCancel"
|
|
||||||
:disabled="loading"
|
|
||||||
class="cancel-button"
|
|
||||||
>
|
|
||||||
取消
|
|
||||||
</a-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a-card>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 用户协议模态框 -->
|
<!-- 用户协议模态框 -->
|
||||||
<a-modal
|
<a-modal v-model:visible="agreementModalVisible" title="用户协议" width="800px" :footer="null">
|
||||||
v-model:visible="agreementModalVisible"
|
|
||||||
title="用户协议"
|
|
||||||
width="800px"
|
|
||||||
:footer="null"
|
|
||||||
>
|
|
||||||
<div class="agreement-content">
|
<div class="agreement-content">
|
||||||
<h3>算力点兑换服务协议</h3>
|
<h3>算力点兑换服务协议</h3>
|
||||||
<p>欢迎使用算力点兑换服务。在兑换算力点前,请您仔细阅读以下协议内容:</p>
|
<p>欢迎使用算力点兑换服务。在兑换算力点前,请您仔细阅读以下协议内容:</p>
|
||||||
@ -221,11 +202,7 @@
|
|||||||
<a-checkbox v-model:checked="modalAgreementChecked">
|
<a-checkbox v-model:checked="modalAgreementChecked">
|
||||||
我已阅读并同意以上协议
|
我已阅读并同意以上协议
|
||||||
</a-checkbox>
|
</a-checkbox>
|
||||||
<a-button
|
<a-button type="primary" @click="handleAgreementConfirm" :disabled="!modalAgreementChecked">
|
||||||
type="primary"
|
|
||||||
@click="handleAgreementConfirm"
|
|
||||||
:disabled="!modalAgreementChecked"
|
|
||||||
>
|
|
||||||
确认并关闭
|
确认并关闭
|
||||||
</a-button>
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
@ -235,7 +212,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, computed, onMounted } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
import {
|
import {
|
||||||
DollarCircleOutlined,
|
DollarCircleOutlined,
|
||||||
ThunderboltOutlined,
|
ThunderboltOutlined,
|
||||||
@ -245,47 +222,21 @@ import {
|
|||||||
SafetyOutlined,
|
SafetyOutlined,
|
||||||
CloseOutlined
|
CloseOutlined
|
||||||
} from '@ant-design/icons-vue'
|
} from '@ant-design/icons-vue'
|
||||||
import { message, Modal } from 'ant-design-vue'
|
import { message, Modal, Divider } from 'ant-design-vue'
|
||||||
|
|
||||||
// 用户余额和算力点
|
// 用户余额和算力点
|
||||||
const balance = ref(3568.50)
|
const balance = ref(3568.5)
|
||||||
const points = ref(1250)
|
const points = ref(1250)
|
||||||
|
|
||||||
// 金额选项
|
// 金额选项
|
||||||
const amountOptions = ref([
|
const amountOptions = ref([
|
||||||
{ value: 100, label: '100元' },
|
{ value: 100, label: '100' },
|
||||||
{ value: 200, label: '200元' },
|
{ value: 200, label: '200' },
|
||||||
{ value: 500, label: '500元' },
|
{ value: 1000, label: '1000' },
|
||||||
{ value: 1000, label: '1000元' },
|
{ value: 5000, label: '5000' }
|
||||||
{ value: 2000, label: '2000元' },
|
|
||||||
{ value: 5000, label: '5000元' }
|
|
||||||
])
|
|
||||||
|
|
||||||
// 选择的金额
|
|
||||||
const selectedAmount = ref(0)
|
|
||||||
const customAmount = ref('')
|
|
||||||
const customAmountError = ref('')
|
|
||||||
|
|
||||||
// 用户协议确认
|
|
||||||
const agreementChecked = ref(false)
|
|
||||||
const showAgreementError = ref(false)
|
|
||||||
|
|
||||||
// 加载状态
|
|
||||||
const loading = ref(false)
|
|
||||||
|
|
||||||
// 模态框
|
|
||||||
const agreementModalVisible = ref(false)
|
|
||||||
const modalAgreementChecked = ref(false)
|
|
||||||
|
|
||||||
// 兑换记录
|
|
||||||
const exchangeHistory = ref([
|
|
||||||
{ key: 1, amount: 1000, points: 1000, time: '2024-03-15 14:30:22', status: 'success' },
|
|
||||||
{ key: 2, amount: 500, points: 500, time: '2024-03-10 09:15:45', status: 'success' },
|
|
||||||
{ key: 3, amount: 2000, points: 2000, time: '2024-03-05 16:20:33', status: 'success' },
|
|
||||||
{ key: 4, amount: 100, points: 100, time: '2024-02-28 11:45:12', status: 'success' },
|
|
||||||
{ key: 5, amount: 5000, points: 5000, time: '2024-02-20 13:05:27', status: 'success' }
|
|
||||||
])
|
])
|
||||||
|
|
||||||
|
// 注意:这里只定义 columns 结构,不包含 customRender
|
||||||
const historyColumns = [
|
const historyColumns = [
|
||||||
{
|
{
|
||||||
title: '兑换金额',
|
title: '兑换金额',
|
||||||
@ -312,6 +263,31 @@ const historyColumns = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// 选择的金额
|
||||||
|
const selectedAmount = ref(0)
|
||||||
|
const customAmount = ref('')
|
||||||
|
const customAmountError = ref('')
|
||||||
|
|
||||||
|
// 用户协议确认
|
||||||
|
const agreementChecked = ref(false)
|
||||||
|
const showAgreementError = ref(false)
|
||||||
|
|
||||||
|
// 加载状态
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
// 模态框
|
||||||
|
const agreementModalVisible = ref(false)
|
||||||
|
const modalAgreementChecked = ref(false)
|
||||||
|
|
||||||
|
// 兑换记录
|
||||||
|
const exchangeHistory = ref([
|
||||||
|
{ key: 1, amount: 1000, points: 1000, time: '2024-03-15 14:30:22', status: 'success' },
|
||||||
|
{ key: 2, amount: 500, points: 500, time: '2024-03-10 09:15:45', status: 'success' },
|
||||||
|
{ key: 3, amount: 2000, points: 2000, time: '2024-03-05 16:20:33', status: 'success' },
|
||||||
|
{ key: 4, amount: 100, points: 100, time: '2024-02-28 11:45:12', status: 'success' },
|
||||||
|
{ key: 5, amount: 5000, points: 5000, time: '2024-02-20 13:05:27', status: 'success' }
|
||||||
|
])
|
||||||
|
|
||||||
// 计算选中的兑换金额
|
// 计算选中的兑换金额
|
||||||
const selectedExchangeAmount = computed(() => {
|
const selectedExchangeAmount = computed(() => {
|
||||||
if (selectedAmount.value > 0) {
|
if (selectedAmount.value > 0) {
|
||||||
@ -324,9 +300,9 @@ const selectedExchangeAmount = computed(() => {
|
|||||||
// 检查是否可以兑换
|
// 检查是否可以兑换
|
||||||
const canExchange = computed(() => {
|
const canExchange = computed(() => {
|
||||||
return selectedExchangeAmount.value > 0 &&
|
return selectedExchangeAmount.value > 0 &&
|
||||||
agreementChecked.value &&
|
agreementChecked.value &&
|
||||||
selectedExchangeAmount.value <= balance.value &&
|
selectedExchangeAmount.value <= balance.value &&
|
||||||
!loading.value
|
!loading.value
|
||||||
})
|
})
|
||||||
|
|
||||||
// 检查自定义金额是否有效
|
// 检查自定义金额是否有效
|
||||||
@ -447,11 +423,9 @@ const performExchange = () => {
|
|||||||
|
|
||||||
// 模拟API请求
|
// 模拟API请求
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// 更新余额和算力点
|
|
||||||
balance.value -= selectedExchangeAmount.value
|
balance.value -= selectedExchangeAmount.value
|
||||||
points.value += selectedExchangeAmount.value
|
points.value += selectedExchangeAmount.value
|
||||||
|
|
||||||
// 添加兑换记录
|
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const timeStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`
|
const timeStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`
|
||||||
|
|
||||||
@ -463,10 +437,8 @@ const performExchange = () => {
|
|||||||
status: 'success'
|
status: 'success'
|
||||||
})
|
})
|
||||||
|
|
||||||
// 重置选择
|
|
||||||
clearSelection()
|
clearSelection()
|
||||||
agreementChecked.value = false
|
agreementChecked.value = false
|
||||||
|
|
||||||
loading.value = false
|
loading.value = false
|
||||||
|
|
||||||
message.success(`兑换成功!获得 ${selectedExchangeAmount.value} 算力点`)
|
message.success(`兑换成功!获得 ${selectedExchangeAmount.value} 算力点`)
|
||||||
@ -480,11 +452,6 @@ const handleCancel = () => {
|
|||||||
showAgreementError.value = false
|
showAgreementError.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 格式化时间
|
|
||||||
const formatTime = (timeStr) => {
|
|
||||||
return timeStr
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取状态颜色
|
// 获取状态颜色
|
||||||
const getStatusColor = (status) => {
|
const getStatusColor = (status) => {
|
||||||
const colors = {
|
const colors = {
|
||||||
@ -505,14 +472,13 @@ const getStatusText = (status) => {
|
|||||||
return texts[status] || status
|
return texts[status] || status
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化加载
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 可以在这里加载用户余额和算力点数据
|
|
||||||
console.log('页面加载完成')
|
console.log('页面加载完成')
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
/* 你的样式保持不变 */
|
||||||
.points-exchange-page {
|
.points-exchange-page {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
background-color: #f0f2f5;
|
background-color: #f0f2f5;
|
||||||
@ -540,10 +506,7 @@ onMounted(() => {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-content {
|
.main-content {}
|
||||||
max-width: 1200px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.balance-card {
|
.balance-card {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
@ -581,24 +544,25 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.label-text {
|
.label-text {
|
||||||
font-size: 14px;
|
font-size: 20px;
|
||||||
color: rgba(0, 0, 0, 0.45);
|
font-weight: 500;
|
||||||
|
color: rgba(56, 56, 56, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.balance-value {
|
.balance-value {
|
||||||
font-size: 28px;
|
font-size: 18px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: rgba(0, 0, 0, 0.85);
|
color: rgba(0, 0, 0, 0.85);
|
||||||
}
|
}
|
||||||
|
|
||||||
.balance-value .currency {
|
.balance-value .currency {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
color: #52c41a;
|
color: rgba(56, 56, 56, 1);
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.balance-value .points {
|
.balance-value .points {
|
||||||
color: #722ed1;
|
color: rgba(56, 56, 56, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.balance-value .points-unit {
|
.balance-value .points-unit {
|
||||||
@ -648,8 +612,8 @@ onMounted(() => {
|
|||||||
|
|
||||||
.amount-options {
|
.amount-options {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(3, 1fr);
|
grid-template-columns: repeat(8, 1fr);
|
||||||
gap: 16px;
|
gap: 6px;
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -661,7 +625,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
.amount-option {
|
.amount-option {
|
||||||
height: auto !important;
|
height: auto !important;
|
||||||
padding: 16px !important;
|
/* padding: 6px !important; */
|
||||||
border-radius: 8px !important;
|
border-radius: 8px !important;
|
||||||
border: 2px solid #f0f0f0 !important;
|
border: 2px solid #f0f0f0 !important;
|
||||||
background: #fff !important;
|
background: #fff !important;
|
||||||
@ -696,7 +660,24 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.custom-amount {
|
.custom-amount {
|
||||||
|
width: 460px;
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
|
margin-left: 170px;
|
||||||
|
|
||||||
|
input {
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-name {
|
||||||
|
width: 350px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: rgba(166, 166, 166, 1);
|
||||||
|
height: 35px;
|
||||||
|
line-height: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.error-text {
|
.error-text {
|
||||||
@ -888,7 +869,6 @@ onMounted(() => {
|
|||||||
border-top: 1px solid #f0f0f0;
|
border-top: 1px solid #f0f0f0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 加载状态 */
|
|
||||||
:deep(.ant-btn-loading) {
|
:deep(.ant-btn-loading) {
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,13 +38,13 @@
|
|||||||
<div class="batch-operations" style="margin-bottom: 16px;">
|
<div class="batch-operations" style="margin-bottom: 16px;">
|
||||||
<a-space>
|
<a-space>
|
||||||
<!-- :disabled="selectedRowKeys.length === 0" -->
|
<!-- :disabled="selectedRowKeys.length === 0" -->
|
||||||
<a-button
|
<!-- <a-button
|
||||||
type="primary"
|
type="primary"
|
||||||
@click="handleBatchInvoice"
|
@click="handleBatchInvoice"
|
||||||
|
|
||||||
>
|
>
|
||||||
批量去开票
|
批量去开票
|
||||||
</a-button>
|
</a-button> -->
|
||||||
<span v-if="selectedRowKeys.length > 0">
|
<span v-if="selectedRowKeys.length > 0">
|
||||||
已选择 {{ selectedRowKeys.length }} 条记录
|
已选择 {{ selectedRowKeys.length }} 条记录
|
||||||
</span>
|
</span>
|
||||||
@ -95,9 +95,9 @@
|
|||||||
{{ getPayStatusText(record.pay_status) }}
|
{{ getPayStatusText(record.pay_status) }}
|
||||||
</a-tag>
|
</a-tag>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="column.key === 'action'">
|
<!-- <template v-if="column.key === 'action'">
|
||||||
<a-space>
|
<a-space>
|
||||||
<!-- :disabled="!canApplyInvoice(record)" -->
|
|
||||||
<a-button
|
<a-button
|
||||||
type="link"
|
type="link"
|
||||||
size="small"
|
size="small"
|
||||||
@ -107,7 +107,7 @@
|
|||||||
去开票
|
去开票
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-space>
|
</a-space>
|
||||||
</template>
|
</template> -->
|
||||||
</template>
|
</template>
|
||||||
</a-table>
|
</a-table>
|
||||||
</a-card>
|
</a-card>
|
||||||
@ -485,12 +485,12 @@ const columns = ref([
|
|||||||
key: 'amount',
|
key: 'amount',
|
||||||
width: 120
|
width: 120
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
title: '操作',
|
// title: '操作',
|
||||||
key: 'action',
|
// key: 'action',
|
||||||
width: 100,
|
// width: 100,
|
||||||
align: 'center'
|
// align: 'center'
|
||||||
}
|
// }
|
||||||
])
|
])
|
||||||
|
|
||||||
// 行选择配置
|
// 行选择配置
|
||||||
|
|||||||
@ -1,255 +1,345 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="file-storage-page">
|
||||||
<!-- 标题 -->
|
<div class="page-header">
|
||||||
<div class="header">
|
<h2 class="page-title">文件存储</h2>
|
||||||
<h1>文件存储</h1>
|
<a-button type="primary" @click="showModal" class="create-btn">
|
||||||
|
<template #icon><PlusOutlined /></template>
|
||||||
|
新建存储
|
||||||
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 区域选择 -->
|
<!-- 表格 -->
|
||||||
<div class="region-section">
|
<div class="table-container">
|
||||||
<h2 class="section-title">选择存储区域</h2>
|
<a-table
|
||||||
<div class="region-tabs">
|
:columns="columns"
|
||||||
<button
|
:data-source="storageList"
|
||||||
v-for="region in regions"
|
:row-key="record => record.id"
|
||||||
:key="region.id"
|
:pagination="{ pageSize: 8 }"
|
||||||
:class="['region-tab', { active: selectedRegion === region.id }]"
|
class="storage-table"
|
||||||
@click="selectRegion(region.id)"
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'size'">
|
||||||
|
<span class="data-cell">{{ record.size }} GB</span>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'duration'">
|
||||||
|
<span class="data-cell">{{ record.duration }} 天</span>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'cost'">
|
||||||
|
<span class="cost-cell">¥{{ record.cost.toFixed(2) }}</span>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'name'">
|
||||||
|
<div class="name-cell">
|
||||||
|
<FolderOutlined class="folder-icon" />
|
||||||
|
<span>{{ record.name }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 创建弹窗 -->
|
||||||
|
<a-modal
|
||||||
|
v-model:open="modalVisible"
|
||||||
|
title="创建存储空间"
|
||||||
|
@ok="handleCreate"
|
||||||
|
@cancel="modalVisible = false"
|
||||||
|
:width="520"
|
||||||
|
class="create-modal"
|
||||||
|
>
|
||||||
|
<a-form
|
||||||
|
:model="createForm"
|
||||||
|
:label-col="{ span: 6 }"
|
||||||
|
:wrapper-col="{ span: 18 }"
|
||||||
|
ref="createFormRef"
|
||||||
|
class="create-form"
|
||||||
|
>
|
||||||
|
<a-form-item label="存储名称" name="name" :rules="[{ required: true, message: '请输入存储名称' }]">
|
||||||
|
<a-input
|
||||||
|
v-model:value="createForm.name"
|
||||||
|
placeholder="请输入存储空间名称"
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item
|
||||||
|
label="存储大小"
|
||||||
|
name="size"
|
||||||
|
:rules="[{ required: true, message: '请输入存储大小' }, { type: 'number', min: 1, message: '至少1GB' }]"
|
||||||
>
|
>
|
||||||
{{ region.name }}
|
<a-input-number
|
||||||
</button>
|
v-model:value="createForm.size"
|
||||||
</div>
|
:min="1"
|
||||||
</div>
|
:max="10000"
|
||||||
|
style="width: 100%"
|
||||||
|
size="large"
|
||||||
|
addon-after="GB"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
<!-- 中心图标 -->
|
<a-form-item
|
||||||
<div class="center-section">
|
label="购买时长"
|
||||||
<div class="center-icon">
|
name="duration"
|
||||||
<i class="icon-book"></i>
|
:rules="[{ required: true, message: '请输入购买时长' }, { type: 'number', min: 1, message: '至少1天' }]"
|
||||||
</div>
|
>
|
||||||
</div>
|
<a-input-number
|
||||||
|
v-model:value="createForm.duration"
|
||||||
|
:min="1"
|
||||||
|
:max="365"
|
||||||
|
style="width: 100%"
|
||||||
|
size="large"
|
||||||
|
addon-after="天"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
<!-- 主要操作按钮 -->
|
<div class="cost-summary">
|
||||||
<div class="action-section">
|
<div class="cost-label">费用合计</div>
|
||||||
<button class="btn-primary" @click="initializeStorage">
|
<div class="cost-amount">
|
||||||
初始化文件存储
|
<span class="amount">¥{{ totalCost }}</span>
|
||||||
</button>
|
<span class="cost-note">(0.1元/GB/天)</span>
|
||||||
<p class="action-hint">将在 {{ getSelectedRegionName() }} 创建存储空间</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</a-form>
|
||||||
|
|
||||||
<!-- 底部帮助链接 -->
|
<template #footer>
|
||||||
<div class="help-section">
|
<a-button @click="modalVisible = false">取消</a-button>
|
||||||
<div class="help-links">
|
<a-button type="primary" @click="handleCreate" :loading="creating">确认创建</a-button>
|
||||||
<a href="#" class="link" @click.prevent="viewHelp">文件存储使用介绍</a>
|
</template>
|
||||||
<a href="#" class="link" @click.prevent="viewPricing">查看计费规则</a>
|
</a-modal>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref, reactive, computed } from 'vue'
|
||||||
|
import { PlusOutlined, FolderOutlined } from '@ant-design/icons-vue'
|
||||||
|
|
||||||
// 定义区域选项
|
// 表格列定义
|
||||||
interface Region {
|
const columns = [
|
||||||
id: string
|
{
|
||||||
name: string
|
title: '名称',
|
||||||
}
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
const regions = [
|
width: '30%'
|
||||||
{ id: 'a100', name: 'A100专区' },
|
},
|
||||||
{ id: 'v100', name: 'V100专区' },
|
{
|
||||||
{ id: 'foshan', name: '佛山区' },
|
title: '存储大小',
|
||||||
{ id: 'beijing', name: '北京B区' }
|
dataIndex: 'size',
|
||||||
|
key: 'size',
|
||||||
|
align: 'right'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '购买时长',
|
||||||
|
dataIndex: 'duration',
|
||||||
|
key: 'duration',
|
||||||
|
align: 'right'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '费用',
|
||||||
|
dataIndex: 'cost',
|
||||||
|
key: 'cost',
|
||||||
|
align: 'right'
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const selectedRegion = ref('a100') // 默认选中 A100
|
// 存储列表(模拟数据)
|
||||||
|
const storageList = ref([
|
||||||
|
{ id: 1, name: '项目A存储', size: 100, duration: 30, cost: 300 },
|
||||||
|
{ id: 2, name: '备份存储', size: 500, duration: 7, cost: 350 }
|
||||||
|
])
|
||||||
|
|
||||||
// 方法:获取选中区域名称
|
// 弹窗控制
|
||||||
const getSelectedRegionName = () => {
|
const modalVisible = ref(false)
|
||||||
const region = regions.find(r => r.id === selectedRegion.value)
|
const creating = ref(false)
|
||||||
return region ? region.name : ''
|
|
||||||
|
// 表单数据
|
||||||
|
const createForm = reactive({
|
||||||
|
name: '',
|
||||||
|
size: 50,
|
||||||
|
duration: 30
|
||||||
|
})
|
||||||
|
|
||||||
|
// 计算费用:0.1 元 / GB / 天
|
||||||
|
const totalCost = computed(() => {
|
||||||
|
return (createForm.size * createForm.duration * 0.1).toFixed(2)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 表单引用(用于校验)
|
||||||
|
const createFormRef = ref()
|
||||||
|
|
||||||
|
// 显示弹窗
|
||||||
|
const showModal = () => {
|
||||||
|
createForm.name = ''
|
||||||
|
createForm.size = 50
|
||||||
|
createForm.duration = 30
|
||||||
|
modalVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 方法:选择区域
|
// 创建存储
|
||||||
const selectRegion = (id: string) => {
|
const handleCreate = async () => {
|
||||||
selectedRegion.value = id
|
try {
|
||||||
}
|
await createFormRef.value.validateFields()
|
||||||
|
creating.value = true
|
||||||
|
|
||||||
// 方法:初始化存储
|
// 模拟API调用延迟
|
||||||
const initializeStorage = () => {
|
await new Promise(resolve => setTimeout(resolve, 800))
|
||||||
alert(`正在初始化 ${selectedRegion.value} 的文件存储...`)
|
|
||||||
// 这里可以跳转到下一步流程
|
|
||||||
}
|
|
||||||
|
|
||||||
// 方法:查看帮助
|
// 添加到列表
|
||||||
const viewHelp = () => {
|
const newStorage = {
|
||||||
alert('文件存储使用介绍')
|
id: Date.now(),
|
||||||
}
|
name: createForm.name,
|
||||||
|
size: createForm.size,
|
||||||
|
duration: createForm.duration,
|
||||||
|
cost: parseFloat(totalCost.value)
|
||||||
|
}
|
||||||
|
storageList.value.unshift(newStorage)
|
||||||
|
modalVisible.value = false
|
||||||
|
|
||||||
// 方法:查看计费规则
|
// 可在此处调用 API
|
||||||
const viewPricing = () => {
|
console.log('创建成功:', newStorage)
|
||||||
alert('计费规则详情')
|
} catch (error) {
|
||||||
|
console.log('校验失败:', error)
|
||||||
|
} finally {
|
||||||
|
creating.value = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.container {
|
.file-storage-page {
|
||||||
/* max-width: 800px;
|
padding: 24px;
|
||||||
margin: 0 auto; */
|
background: #f5f7fa;
|
||||||
padding: 40px 30px;
|
min-height: 100vh;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
||||||
color: #333;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 标题区域 */
|
.page-header {
|
||||||
.header {
|
|
||||||
margin-bottom: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 2rem;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #1a1a1a;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 区域选择 */
|
|
||||||
.region-section {
|
|
||||||
margin-bottom: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-title {
|
|
||||||
font-size: 1.1rem;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #555;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.region-tabs {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.region-tab {
|
|
||||||
padding: 12px 24px;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
background: white;
|
|
||||||
border-radius: 6px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s;
|
|
||||||
font-size: 14px;
|
|
||||||
min-width: 140px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.region-tab:hover {
|
|
||||||
border-color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.region-tab.active {
|
|
||||||
background-color: #3498db;
|
|
||||||
color: white;
|
|
||||||
border-color: #3498db;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 中心图标区域 */
|
|
||||||
.center-section {
|
|
||||||
margin: 40px 0;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.center-icon {
|
|
||||||
width: 80px;
|
|
||||||
height: 80px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
margin-bottom: 24px;
|
||||||
background: #f5f5f5;
|
padding-bottom: 16px;
|
||||||
|
border-bottom: 1px solid #e8e8e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1f2d3d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-btn {
|
||||||
|
height: 40px;
|
||||||
|
padding: 0 20px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-container {
|
||||||
|
background: white;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.storage-table {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-book {
|
.storage-table :deep(.ant-table-thead > tr > th) {
|
||||||
font-size: 36px;
|
background: #fafbfc;
|
||||||
color: #3498db;
|
font-weight: 600;
|
||||||
|
color: #5e6d82;
|
||||||
|
border-bottom: 2px solid #e8e8e8;
|
||||||
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-book::before {
|
.storage-table :deep(.ant-table-tbody > tr > td) {
|
||||||
content: "📁";
|
padding: 16px;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
transition: background-color 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 操作区域 */
|
.storage-table :deep(.ant-table-tbody > tr:hover > td) {
|
||||||
.action-section {
|
background-color: #f9fafc;
|
||||||
margin: 40px 0;
|
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary {
|
.name-cell {
|
||||||
background-color: #3498db;
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
padding: 14px 32px;
|
|
||||||
border-radius: 6px;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 500;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary:hover {
|
|
||||||
background-color: #2980b9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-hint {
|
|
||||||
margin-top: 12px;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 帮助区域 */
|
|
||||||
.help-section {
|
|
||||||
margin-top: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.help-links {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 30px;
|
align-items: center;
|
||||||
justify-content: center;
|
gap: 10px;
|
||||||
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link {
|
.folder-icon {
|
||||||
text-decoration: none;
|
color: #1890ff;
|
||||||
color: #3498db;
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-cell {
|
||||||
|
color: #5e6d82;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cost-cell {
|
||||||
|
color: #1890ff;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-form {
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-form :deep(.ant-form-item-label) {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-form :deep(.ant-input-number),
|
||||||
|
.create-form :deep(.ant-input) {
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cost-summary {
|
||||||
|
background: #f8f9fa;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 16px 20px;
|
||||||
|
margin-top: 8px;
|
||||||
|
border: 1px solid #e8e8e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cost-label {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
transition: color 0.2s;
|
color: #5e6d82;
|
||||||
|
margin-bottom: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link:hover {
|
.cost-amount {
|
||||||
color: #2980b9;
|
display: flex;
|
||||||
text-decoration: underline;
|
align-items: baseline;
|
||||||
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 响应式设计 */
|
.amount {
|
||||||
@media (max-width: 768px) {
|
font-size: 24px;
|
||||||
.container {
|
font-weight: 600;
|
||||||
padding: 30px 20px;
|
color: #1890ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.region-tabs {
|
.cost-note {
|
||||||
flex-direction: column;
|
font-size: 13px;
|
||||||
}
|
color: #8c98ae;
|
||||||
|
}
|
||||||
|
|
||||||
.region-tab {
|
.create-modal :deep(.ant-modal-header) {
|
||||||
width: 100%;
|
border-bottom: 1px solid #e8e8e8;
|
||||||
max-width: 100%;
|
padding: 20px 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.help-links {
|
.create-modal :deep(.ant-modal-title) {
|
||||||
flex-direction: column;
|
font-size: 18px;
|
||||||
gap: 15px;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.center-section {
|
.create-modal :deep(.ant-modal-footer) {
|
||||||
justify-content: center;
|
border-top: 1px solid #e8e8e8;
|
||||||
}
|
padding: 16px 24px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
Loading…
x
Reference in New Issue
Block a user