This commit is contained in:
qiuyuan 2026-01-13 09:02:44 +08:00
commit 43d2966b20
9 changed files with 362 additions and 381 deletions

View File

@ -2,5 +2,5 @@
NODE_ENV=development NODE_ENV=development
# api # api
VITE_API_BASIC="http://10.10.1.35:8888" VITE_API_BASIC="http://10.10.1.32:8888"

View File

@ -22,3 +22,9 @@ export const getRecommendList = () => request.get('/v1/voucher/voucher_list')
//获取消息列表 //获取消息列表
export const getMessageList = (params:any) => request.get('/v1/message/message_list', { params }) export const getMessageList = (params:any) => request.get('/v1/message/message_list', { params })
//验证码合法性
export const CodeAuth=(params:any)=>request.put("/v1/auth/update_password_auth",params)
//提现
export const tixian=(params:any)=>request.put("/v1/balance/withdraw",params)

View File

@ -57,11 +57,6 @@ interface MenuItem {
} }
const menuItems: MenuItem[] = [ const menuItems: MenuItem[] = [
{ path: '/controlPanel/overview', name: '总览', icon: HomeOutlined },
{ path: '/controlPanel/container', name: '容器实例', icon: ConsoleSqlOutlined },
{ path: '/controlPanel/fileStore', name: '文件存储', icon: FolderOpenOutlined },
{ path: '/controlPanel/image', name: '镜像', icon: GlobalOutlined },
{ path: '/controlPanel/publicData', name: '公开数据', icon: LaptopOutlined },
{ {
path: '/contract', path: '/contract',
name: '费用中心', name: '费用中心',
@ -80,7 +75,12 @@ const menuItems: MenuItem[] = [
{ path: '/accountHistory', name: '访问记录' }, { path: '/accountHistory', name: '访问记录' },
// { path: '/controlPanel/account/security', name: '' } // { path: '/controlPanel/account/security', name: '' }
] ]
} },
{ path: '/controlPanel/container', name: '容器实例', icon: ConsoleSqlOutlined },
{ path: '/controlPanel/fileStore', name: '文件存储', icon: FolderOpenOutlined },
{ path: '/controlPanel/image', name: '镜像', icon: GlobalOutlined },
{ path: '/controlPanel/publicData', name: '公开数据', icon: LaptopOutlined },
] ]
const selectedKeys = computed(() => [route.path]) const selectedKeys = computed(() => [route.path])

View File

@ -1,17 +1,19 @@
// src/utils/request.ts // src/utils/request.ts
import axios, { AxiosInstance, InternalAxiosRequestConfig } from 'axios'; import axios, { AxiosInstance, InternalAxiosRequestConfig } from "axios";
import { message } from "ant-design-vue";
import { useRouter, useRoute } from "vue-router";
// 从环境变量读取基础 URL // 从环境变量读取基础 URL
const BASE_URL = import.meta.env.VITE_API_BASIC const BASE_URL = import.meta.env.VITE_API_BASIC;
console.log('API Basic URL:',import.meta.env.VITE_API_BASIC); console.log("API Basic URL:", import.meta.env.VITE_API_BASIC);
console.log('All env:', import.meta.env); console.log("All env:", import.meta.env);
const router = useRouter();
// 创建 axios 实例 // 创建 axios 实例
const request: AxiosInstance = axios.create({ const request: AxiosInstance = axios.create({
baseURL: BASE_URL, baseURL: BASE_URL,
timeout: 10000, // 10 秒超时 timeout: 10000, // 10 秒超时
withCredentials: false, // 跨域请求时发送 cookies withCredentials: false, // 跨域请求时发送 cookies
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
}, },
}); });
@ -19,7 +21,7 @@ const request: AxiosInstance = axios.create({
request.interceptors.request.use( request.interceptors.request.use(
(config: InternalAxiosRequestConfig) => { (config: InternalAxiosRequestConfig) => {
// 例如:从 localStorage 获取 token // 例如:从 localStorage 获取 token
const token = localStorage.getItem('token'); const token = localStorage.getItem("token");
if (token) { if (token) {
config.headers.Authorization = `Bearer ${token}`; config.headers.Authorization = `Bearer ${token}`;
} }
@ -33,22 +35,31 @@ request.interceptors.request.use(
// 响应拦截器统一处理错误、code 等) // 响应拦截器统一处理错误、code 等)
request.interceptors.response.use( request.interceptors.response.use(
(response) => { (response) => {
console.log("response", response);
// 假设后端返回格式为 { code: 200, data: ..., message: '' } // 假设后端返回格式为 { code: 200, data: ..., message: '' }
const { code, data, message } = response.data; const { code, data, message } = response.data;
console.log('Response Data:', response.data); console.log("Response Data:", response.data);
if (code === 1) { if (code === 1) {
return data; return data??code;
} else { } else {
// 可抛出业务错误 // 可抛出业务错误
return Promise.reject(new Error(message || '请求失败')); return Promise.reject(new Error(message || "请求失败"));
} }
}, },
(error) => { (error) => {
// 网络错误 or 超时等 // 网络错误 or 超时等
console.log(error);
const res = error.response;
if (res.status === 401) {
message.error("登录已过期,请重新登录");
localStorage.clear();
setTimeout(() => {
window.location.href = "/login";
}, 3000);
} else {
return Promise.reject(error.response.data); return Promise.reject(error.response.data);
} }
}
); );
export default request; export default request;

View File

@ -16,13 +16,18 @@
</div> </div>
</a-upload> </a-upload>
</div> </div>
<div class="info"><span>账户</span><span>17044054908</span></div> <div class="info"><span>账户</span><span>{{ userInfo.phone }}</span></div>
<div class="info"><span>账户ID</span><span>123456789123456789</span></div> <div class="info"><span>账户ID</span><span>{{ userInfo.id }}</span></div>
<div class="info" style="display: flex;justify-content: space-between;"> <div class="info" style="display: flex;justify-content: space-between;">
<div> <div v-if="userInfo.certificationStatus !== 'CERTIFICATION_PASSED'">
<span style="margin-right: 25px;">认证类型</span><span style="color: red;">未实名认证</span> <span style="margin-right: 25px;">认证类型</span><span style="color: red;">未实名认证</span>
</div> </div>
<div style="color:#1677ff;">前往认证</div> <div style="color:#1677ff;" v-if="userInfo.certificationStatus !== 'CERTIFICATION_PASSED'">前往认证
</div>
<div v-if="userInfo.certificationStatus == 'CERTIFICATION_PASSED'">
<span style="margin-right: 25px;">认证类型</span><span>{{ certificationInfo.certificationType
}}</span>
</div>
</div> </div>
</a-card> </a-card>
</a-col> </a-col>
@ -30,38 +35,30 @@
<a-card title="安全设置"> <a-card title="安全设置">
<div class="info" style="display: flex;justify-content: space-between;"> <div class="info" style="display: flex;justify-content: space-between;">
<div> <div>
<span style="margin-right: 25px;">手机号</span><span>{{ currentPhone }}</span> <span style="margin-right: 38px;width: 80px;">手机号</span><span>{{ userInfo.phone }}</span>
</div> </div>
<div style="color:#1677ff;" @click="handleModifyPhone">修改</div>
</div> </div>
<div class="info" style="display: flex;justify-content: space-between;"> <div class="info" style="display: flex;justify-content: space-between;">
<div> <div>
<span style="margin-right: 25px;">绑定微信</span><span style="color: #666;">未绑定微信</span> <span style="margin-right: 25px;">绑定微信</span><span style="color: #666;">未绑定微信</span>
</div> </div>
<div style="color:#1677ff;">绑定</div> <div style="color:#1677ff;cursor: pointer;">绑定</div>
</div> </div>
<div class="info" style="display: flex;justify-content: space-between;"> <div class="info" style="display: flex;justify-content: space-between;">
<div> <div>
<span style="margin-right: 25px;">登录密码</span><span>********</span> <span style="margin-right: 25px;cursor: pointer;">登录密码</span><span>********</span>
</div> </div>
<div style="color:#1677ff;" @click="handleModifyPassword">修改</div> <div style="color:#1677ff;cursor: pointer;" @click="handleModifyPassword">修改</div>
</div> </div>
</a-card> </a-card>
</a-col> </a-col>
</a-row> </a-row>
<!-- 第一步身份验证对话框共用 --> <!-- 第一步身份验证对话框共用 -->
<a-modal <a-modal v-model:visible="verifyVisible" title="身份验证" @ok="handleVerify" @cancel="handleCancelVerify"
v-model:visible="verifyVisible" :maskClosable="false" :width="480" :ok-button-props="{ disabled: !isVerificationValid }"
title="身份验证" :confirmLoading="verifying" okText="下一步">
@ok="handleVerify"
@cancel="handleCancelVerify"
:maskClosable="false"
:width="480"
:ok-button-props="{ disabled: !isVerificationValid }"
:confirmLoading="verifying"
okText="下一步"
>
<div class="verify-content"> <div class="verify-content">
<!-- 安全提示 --> <!-- 安全提示 -->
<div class="security-tip"> <div class="security-tip">
@ -77,7 +74,7 @@
<div class="phone-label">验证手机号</div> <div class="phone-label">验证手机号</div>
<div class="phone-number"> <div class="phone-number">
<!-- <span class="phone-icon">📱</span> --> <!-- <span class="phone-icon">📱</span> -->
<span class="phone-text">{{ maskedPhone }}</span> <span class="phone-text">{{ userInfo.phone }}</span>
</div> </div>
</div> </div>
@ -85,19 +82,10 @@
<div class="verification-code"> <div class="verification-code">
<div class="code-label">验证码</div> <div class="code-label">验证码</div>
<div class="code-input-group"> <div class="code-input-group">
<a-input <a-input v-model:value="verificationCode" placeholder="请输入6位验证码" :maxlength="6"
v-model:value="verificationCode" @input="handleCodeInput" class="code-input" />
placeholder="请输入6位验证码" <a-button type="link" @click="sendVerificationCode" :disabled="countdown > 0 || sendingCode"
:maxlength="6" class="send-code-btn">
@input="handleCodeInput"
class="code-input"
/>
<a-button
type="link"
@click="sendVerificationCode"
:disabled="countdown > 0 || sendingCode"
class="send-code-btn"
>
{{ countdownText }} {{ countdownText }}
</a-button> </a-button>
</div> </div>
@ -112,16 +100,9 @@
</a-modal> </a-modal>
<!-- 第二步修改手机号对话框 --> <!-- 第二步修改手机号对话框 -->
<a-modal <a-modal v-model:visible="changePhoneVisible" title="修改手机号" @ok="handleChangePhone"
v-model:visible="changePhoneVisible" @cancel="handleCancelChangePhone" :maskClosable="false" :width="480"
title="修改手机号" :ok-button-props="{ disabled: !isChangeValid }" :confirmLoading="changing">
@ok="handleChangePhone"
@cancel="handleCancelChangePhone"
:maskClosable="false"
:width="480"
:ok-button-props="{ disabled: !isChangeValid }"
:confirmLoading="changing"
>
<div class="change-phone-content"> <div class="change-phone-content">
<!-- 安全提示 --> <!-- 安全提示 -->
<div class="security-tip"> <div class="security-tip">
@ -134,13 +115,8 @@
<!-- 新手机号输入 --> <!-- 新手机号输入 -->
<div class="new-phone-section"> <div class="new-phone-section">
<div class="input-label">新手机号</div> <div class="input-label">新手机号</div>
<a-input <a-input v-model:value="newPhoneNumber" placeholder="请输入新手机号" :maxlength="11"
v-model:value="newPhoneNumber" @input="handlePhoneInput" class="phone-input" />
placeholder="请输入新手机号"
:maxlength="11"
@input="handlePhoneInput"
class="phone-input"
/>
<div v-if="phoneError" class="input-error">{{ phoneError }}</div> <div v-if="phoneError" class="input-error">{{ phoneError }}</div>
</div> </div>
@ -148,19 +124,10 @@
<div class="verification-code"> <div class="verification-code">
<div class="code-label">验证码</div> <div class="code-label">验证码</div>
<div class="code-input-group"> <div class="code-input-group">
<a-input <a-input v-model:value="newVerificationCode" placeholder="请输入6位验证码" :maxlength="6"
v-model:value="newVerificationCode" @input="handleNewCodeInput" class="code-input" />
placeholder="请输入6位验证码" <a-button type="link" @click="sendNewVerificationCode"
:maxlength="6" :disabled="newCountdown > 0 || sendingNewCode" class="send-code-btn">
@input="handleNewCodeInput"
class="code-input"
/>
<a-button
type="link"
@click="sendNewVerificationCode"
:disabled="newCountdown > 0 || sendingNewCode"
class="send-code-btn"
>
{{ newCountdownText }} {{ newCountdownText }}
</a-button> </a-button>
</div> </div>
@ -170,16 +137,9 @@
</a-modal> </a-modal>
<!-- 修改密码对话框 --> <!-- 修改密码对话框 -->
<a-modal <a-modal v-model:visible="changePasswordVisible" title="修改密码" @ok="handleChangePassword"
v-model:visible="changePasswordVisible" @cancel="handleCancelChangePassword" :maskClosable="false" :width="480"
title="修改密码" :ok-button-props="{ disabled: !isPasswordValid }" :confirmLoading="changingPassword">
@ok="handleChangePassword"
@cancel="handleCancelChangePassword"
:maskClosable="false"
:width="480"
:ok-button-props="{ disabled: !isPasswordValid }"
:confirmLoading="changingPassword"
>
<div class="change-password-content"> <div class="change-password-content">
<!-- 安全提示 --> <!-- 安全提示 -->
<div class="security-tip"> <div class="security-tip">
@ -192,26 +152,16 @@
<!-- 原密码输入 --> <!-- 原密码输入 -->
<div class="password-section"> <div class="password-section">
<div class="input-label">原密码</div> <div class="input-label">原密码</div>
<a-input-password <a-input-password v-model:value="oldPassword" placeholder="请输入原密码" @input="handleOldPasswordInput"
v-model:value="oldPassword" class="password-input" :visibilityToggle="true" />
placeholder="请输入原密码"
@input="handleOldPasswordInput"
class="password-input"
:visibilityToggle="true"
/>
<div v-if="oldPasswordError" class="input-error">{{ oldPasswordError }}</div> <div v-if="oldPasswordError" class="input-error">{{ oldPasswordError }}</div>
</div> </div>
<!-- 新密码输入 --> <!-- 新密码输入 -->
<div class="password-section"> <div class="password-section">
<div class="input-label">新密码</div> <div class="input-label">新密码</div>
<a-input-password <a-input-password v-model:value="newPassword" placeholder="请输入新密码6-20位字符"
v-model:value="newPassword" @input="handleNewPasswordInput" class="password-input" :visibilityToggle="true" />
placeholder="请输入新密码6-20位字符"
@input="handleNewPasswordInput"
class="password-input"
:visibilityToggle="true"
/>
<div v-if="newPasswordError" class="input-error">{{ newPasswordError }}</div> <div v-if="newPasswordError" class="input-error">{{ newPasswordError }}</div>
<div class="password-tip"> <div class="password-tip">
<div class="tip-item" :class="{ 'valid': passwordStrength.lengthValid }"> <div class="tip-item" :class="{ 'valid': passwordStrength.lengthValid }">
@ -232,13 +182,8 @@
<!-- 确认密码输入 --> <!-- 确认密码输入 -->
<div class="password-section"> <div class="password-section">
<div class="input-label">确认密码</div> <div class="input-label">确认密码</div>
<a-input-password <a-input-password v-model:value="confirmPassword" placeholder="请再次输入新密码"
v-model:value="confirmPassword" @input="handleConfirmPasswordInput" class="password-input" :visibilityToggle="true" />
placeholder="请再次输入新密码"
@input="handleConfirmPasswordInput"
class="password-input"
:visibilityToggle="true"
/>
<div v-if="confirmPasswordError" class="input-error">{{ confirmPasswordError }}</div> <div v-if="confirmPasswordError" class="input-error">{{ confirmPasswordError }}</div>
</div> </div>
</div> </div>
@ -251,7 +196,9 @@ import { ref, computed, onUnmounted, watch,onBeforeMount } from 'vue';
import { LoadingOutlined, PlusOutlined } from '@ant-design/icons-vue'; import { LoadingOutlined, PlusOutlined } from '@ant-design/icons-vue';
import { message, Modal as AModal, Input as AInput, InputPassword as AInputPassword, Button as AButton } from 'ant-design-vue'; import { message, Modal as AModal, Input as AInput, InputPassword as AInputPassword, Button as AButton } from 'ant-design-vue';
import { certificationInfoApi } from '@/apis/certification'; import { certificationInfoApi } from '@/apis/certification';
import { CodeAuth } from '@/apis/home'
import { updatePassword } from '@/apis/modules/login'
import router from '@/router';
const loading = ref(false); const loading = ref(false);
const imageUrl = ref<string | null>("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"); const imageUrl = ref<string | null>("https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png");
const fileList = ref<any[]>([{ url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png' }]); const fileList = ref<any[]>([{ url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png' }]);
@ -259,7 +206,6 @@ const userInfo=ref<any>({})
const certificationInfo = ref<any>({}) const certificationInfo = ref<any>({})
// //
const operationType = ref<'phone' | 'password'>('phone'); const operationType = ref<'phone' | 'password'>('phone');
// //
const verifyVisible = ref(false); const verifyVisible = ref(false);
const verificationCode = ref(''); const verificationCode = ref('');
@ -288,7 +234,7 @@ const oldPasswordError = ref('');
const newPasswordError = ref(''); const newPasswordError = ref('');
const confirmPasswordError = ref(''); const confirmPasswordError = ref('');
const changingPassword = ref(false); const changingPassword = ref(false);
const successCode = ref('')
// //
const currentPhone = ref('17044054908'); const currentPhone = ref('17044054908');
@ -509,25 +455,23 @@ const handleVerify = async () => {
codeError.value = '请输入有效的6位验证码'; codeError.value = '请输入有效的6位验证码';
return; return;
} }
verifying.value = true; verifying.value = true;
try { try {
// API
await new Promise(resolve => setTimeout(resolve, 1500));
// //
message.success('身份验证成功'); const res: any = await CodeAuth({ code: verificationCode.value, phone: userInfo.value.phone })
console.log(res)
// if (res) {
successCode.value = res.success_code
verifyVisible.value = false; verifyVisible.value = false;
// //
if (operationType.value === 'phone') { if (operationType.value === 'phone') {
showChangePhoneDialog(); showChangePhoneDialog();
} else if (operationType.value === 'password') { } else if (operationType.value === 'password') {
showChangePasswordDialog(); showChangePasswordDialog();
} }
} else {
message.error("验证码无效")
}
} catch (error) { } catch (error) {
codeError.value = '验证码错误,请重新输入'; codeError.value = '验证码错误,请重新输入';
@ -687,6 +631,7 @@ const handleChangePhone = async () => {
// //
const showChangePasswordDialog = () => { const showChangePasswordDialog = () => {
console.log(111)
// //
oldPassword.value = ''; oldPassword.value = '';
newPassword.value = ''; newPassword.value = '';
@ -768,16 +713,17 @@ const handleChangePassword = async () => {
changingPassword.value = true; changingPassword.value = true;
try { try {
// API const res = await updatePassword({ confirm_password: confirmPassword.value, new_password: newPassword.value, old_password: oldPassword.value, success_code: successCode.value })
await new Promise(resolve => setTimeout(resolve, 1500)); if (res) {
// //
changePasswordVisible.value = false; changePasswordVisible.value = false;
// //
resetPasswordStates(); resetPasswordStates();
message.success('密码修改成功'); message.success('密码修改成功');
localStorage.clear()
router.replace('/login')
}
} catch (error) { } catch (error) {
oldPasswordError.value = '原密码错误或修改失败'; oldPasswordError.value = '原密码错误或修改失败';

View File

@ -4,16 +4,13 @@
<a-row :gutter="24" class="asset-cards"> <a-row :gutter="24" class="asset-cards">
<!-- 左侧可用余额卡片 --> <!-- 左侧可用余额卡片 -->
<a-col :span="8"> <a-col :span="8">
<a-card :bordered="false" class="card balance-card"> <a-card :bordered="false" class="card balance-card" title="可用余额">
<div class="fee-header"> <template #extra><a-button type="link" size="small" class="fee-titleb"
<div class="fee-title">可用余额</div> @click="goToBills">查看消费明细</a-button></template>
<a-button type="link" size="small" class="fee-titleb" @click="goToBills">查看消费明细</a-button> <div class="money">¥ {{ formatAmount(userInfo.balance || 0) }}</div>
</div>
<a-divider />
<div class="money">¥ {{ formatAmount(balance) }}</div>
<div class="money-btn"> <div class="money-btn">
<div><a-button type="primary" size="small" @click="goToRecharge">充值</a-button></div> <div><a-button type="primary" size="small" @click="goToRecharge">充值</a-button></div>
<div><a-button size="small">提现</a-button></div> <div><a-button size="small" @click="dialogWithDrawal = true">提现</a-button></div>
</div> </div>
</a-card> </a-card>
</a-col> </a-col>
@ -24,8 +21,8 @@
<a-card title="算力点" :bordered="false" class="card computing-card"> <a-card title="算力点" :bordered="false" class="card computing-card">
<div class="computing-content"> <div class="computing-content">
<div class="computing-amount"> <div class="computing-amount">
<span class="amount-value">{{ formatComputingPoints(computingPoints) }}</span> <span class="amount-value">{{ '¥' + formatAmount(userInfo.computingPowerPoint || 0) }}</span>
<span class="amount-unit"></span> <!-- <span class="amount-unit"></span> -->
</div> </div>
<div class="computing-actions"> <div class="computing-actions">
<a-button type="primary" size="small" @click="goToExchange">去兑换</a-button> <a-button type="primary" size="small" @click="goToExchange">去兑换</a-button>
@ -37,7 +34,7 @@
<a-card title="算力券" :bordered="false" class="card coupon-card"> <a-card title="算力券" :bordered="false" class="card coupon-card">
<div class="coupon-content"> <div class="coupon-content">
<div class="coupon-amount"> <div class="coupon-amount">
<span class="amount-value">{{ availableCoupons }}</span> <span class="amount-value">{{ userInfo.voucherNum }}</span>
<span class="amount-unit"></span> <span class="amount-unit"></span>
</div> </div>
<div class="coupon-actions"> <div class="coupon-actions">
@ -51,29 +48,11 @@
<!-- 底部账单区域 --> <!-- 底部账单区域 -->
<div class="bill-section"> <div class="bill-section">
<div class="bill-header"> <div class="bill-header">
<h3 class="bill-title">账单明细</h3> <h3 class="bill-title">消费明细</h3>
<div class="date-range">
<span class="date-label">日期范围</span>
<a-range-picker
v-model:value="dateRange"
:placeholder="['开始时间', '结束时间']"
@change="handleDateChange"
style="width: 250px;"
/>
</div> </div>
</div>
<!-- 账单表格 --> <!-- 账单表格 -->
<a-table <a-table :columns="columns" :data-source="billData" :pagination="pagination" @change="handleTableChange"
:columns="columns" :loading="loading" class="bill-table" :scroll="{ x: 1200 }">
:data-source="billData"
:pagination="pagination"
@change="handleTableChange"
:loading="loading"
class="bill-table"
:scroll="{ x: 1200 }"
>
<!-- 流水号列 --> <!-- 流水号列 -->
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.key === 'serialNumber'"> <template v-if="column.key === 'serialNumber'">
@ -88,7 +67,8 @@
</template> </template>
<!-- 金额相关列 --> <!-- 金额相关列 -->
<template v-else-if="['transactionAmount', 'originalPrice', 'discountAmount', 'balancePayment', 'voucherDeduction'].includes(column.key)"> <template
v-else-if="['transactionAmount', 'originalPrice', 'discountAmount', 'balancePayment', 'voucherDeduction'].includes(column.key)">
<span :class="{ <span :class="{
'amount-positive': record[column.key] > 0, 'amount-positive': record[column.key] > 0,
'amount-negative': record[column.key] < 0 'amount-negative': record[column.key] < 0
@ -100,25 +80,29 @@
</a-table> </a-table>
</div> </div>
</div> </div>
<a-modal v-model:open="dialogWithDrawal" title="提现" @ok="handleOk">
<a-card>
<div style="display: flex;justify-content: flex-start;align-items: center;">
<span style="width: 120px;">提现金额</span>
<a-input-number id="inputNumber" v-model:value="withDrawalCount" placeholder="请输入提现金额" style="width: 100%;"/>
<a-button type="link" @click="withDrawalCount=userInfo.balance" :loading="btnLoading">全部提现</a-button>
</div>
</a-card>
</a-modal>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, computed } from 'vue' import { ref, onMounted, computed, } from 'vue'
import { import { useRouter } from 'vue-router'
message, import {message,TableProps} from 'ant-design-vue'
TableProps
} from 'ant-design-vue'
import type { Dayjs } from 'dayjs' import type { Dayjs } from 'dayjs'
import router from '@/router' import{tixian} from "@/apis/home"
import { fetchUserInfo } from '@/apis/modules/login';
const router = useRouter()
// //
const balance = ref<number>(5.00) const btnLoading=ref(false)
const computingPoints = ref<number>(1023) const dialogWithDrawal = ref(false)
const availableCoupons = ref<number>(3) const withDrawalCount = ref(0)
//
const dateRange = ref<[Dayjs, Dayjs]>()
// //
interface BillRecord { interface BillRecord {
key: string key: string
@ -134,6 +118,7 @@ interface BillRecord {
} }
const loading = ref(false) const loading = ref(false)
const userInfo = ref<any>({})
const billData = ref<BillRecord[]>([]) const billData = ref<BillRecord[]>([])
const pagination = ref({ const pagination = ref({
current: 1, current: 1,
@ -173,12 +158,19 @@ const columns = computed(() => [
] ]
}, },
{ {
title: '产品名称', title: '收支类型',
dataIndex: 'productName', dataIndex: 'productName',
key: 'productName', key: 'productName',
width: 150, width: 150,
ellipsis: true ellipsis: true
}, },
{
title: '交易渠道',
dataIndex: 'transactionAmount',
key: 'transactionAmount',
width: 120,
align: 'right'
},
{ {
title: '交易金额', title: '交易金额',
dataIndex: 'transactionAmount', dataIndex: 'transactionAmount',
@ -187,28 +179,14 @@ const columns = computed(() => [
align: 'right' align: 'right'
}, },
{ {
title: '原价', title: '账户余额',
dataIndex: 'originalPrice',
key: 'originalPrice',
width: 120,
align: 'right'
},
{
title: '优惠金额',
dataIndex: 'discountAmount',
key: 'discountAmount',
width: 120,
align: 'right'
},
{
title: '余额支付',
dataIndex: 'balancePayment', dataIndex: 'balancePayment',
key: 'balancePayment', key: 'balancePayment',
width: 120, width: 120,
align: 'right' align: 'right'
}, },
{ {
title: '代金券抵扣', title: '备注',
dataIndex: 'voucherDeduction', dataIndex: 'voucherDeduction',
key: 'voucherDeduction', key: 'voucherDeduction',
width: 120, width: 120,
@ -218,6 +196,10 @@ const columns = computed(() => [
// //
onMounted(() => { onMounted(() => {
const userInfoStr = localStorage.getItem('userInfo');
if (userInfoStr) {
userInfo.value = JSON.parse(userInfoStr);
}
fetchBillData() fetchBillData()
}) })
@ -358,7 +340,7 @@ const goToBills = () => {
} }
const goToCoupons = () => { const goToCoupons = () => {
router.push('/rights') router.push('/layout/admin/myCertificate')
} }
const goToExchange = () => { const goToExchange = () => {
@ -366,6 +348,21 @@ const goToExchange = () => {
// //
router.push('/layout/admin/exchange') router.push('/layout/admin/exchange')
} }
const handleOk=async ()=>{
try {
btnLoading.value=true
const res=await tixian({amount:withDrawalCount.value})
if(res){
message.success("提现成功")
const userRes = await fetchUserInfo();
localStorage.setItem('userInfo', JSON.stringify(userRes));
}
btnLoading.value=false
} catch (error:any) {
message.error(error)
btnLoading.value=false
}
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -378,7 +375,8 @@ const goToExchange = () => {
.asset-cards { .asset-cards {
margin-bottom: 24px; margin-bottom: 24px;
.ant-col-8, .ant-col-16 { .ant-col-8,
.ant-col-16 {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
@ -422,6 +420,7 @@ const goToExchange = () => {
font-size: 16px; font-size: 16px;
font-weight: 600; font-weight: 600;
color: #333; color: #333;
background: linear-gradient(90deg, rgba(240, 245, 255, 1) 0%, rgba(255, 255, 255, 0) 100%);
} }
.fee-titleb { .fee-titleb {
@ -438,19 +437,18 @@ const goToExchange = () => {
.money { .money {
font-size: 32px; font-size: 32px;
font-weight: 700; font-weight: 700;
color: #1890ff; color: #000000;
text-align: center; text-align: left;
margin: 20px 0 30px; margin: 20px 0 30px;
line-height: 1; line-height: 1;
} }
.money-btn { .money-btn {
display: flex; display: flex;
justify-content: center; justify-content: flex-end;
gap: 16px; gap: 16px;
div { div {
flex: 1;
text-align: center; text-align: center;
:deep(.ant-btn) { :deep(.ant-btn) {
@ -484,7 +482,8 @@ const goToExchange = () => {
} }
// //
.computing-card, .coupon-card { .computing-card,
.coupon-card {
margin-bottom: 16px; margin-bottom: 16px;
&:last-child { &:last-child {
@ -492,17 +491,17 @@ const goToExchange = () => {
} }
} }
.computing-content, .coupon-content { .computing-content,
.coupon-content {
display: flex; display: flex;
flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: space-between;
padding: 20px 0; // padding: 20px 0;
.amount-value { .amount-value {
font-size: 36px; font-size: 36px;
font-weight: 600; font-weight: 600;
color: #1890ff; // color: #000000; //
line-height: 1; line-height: 1;
margin-right: 8px; margin-right: 8px;
} }
@ -513,8 +512,9 @@ const goToExchange = () => {
font-weight: 500; font-weight: 500;
} }
.computing-actions, .coupon-actions { .computing-actions,
margin-top: 24px; .coupon-actions {
// margin-top: 24px;
:deep(.ant-btn) { :deep(.ant-btn) {
width: 100px; width: 100px;
@ -645,7 +645,9 @@ const goToExchange = () => {
} }
.asset-cards { .asset-cards {
.ant-col-8, .ant-col-16 {
.ant-col-8,
.ant-col-16 {
width: 100%; width: 100%;
} }
@ -672,7 +674,8 @@ const goToExchange = () => {
font-size: 28px; font-size: 28px;
} }
.computing-content, .coupon-content { .computing-content,
.coupon-content {
.amount-value { .amount-value {
font-size: 32px; font-size: 32px;
} }

View File

@ -3,7 +3,8 @@
<div class="real-name-auth-page"> <div class="real-name-auth-page">
<div class="header"> <div class="header">
<h1>实名认证</h1> <h1>实名认证</h1>
<p>请选择您的认证类型</p> <p v-if="userInfo.certificationStatus==='PENDING_CERTIFICATION'">请选择您的认证类型</p>
<p v-if="userInfo.certificationStatus==='CERTIFICATION_PASSED'">Fast亼算云严格遵守国家相关个人信息隐私保护规定并不存储使用您的个人信息查看<span style="color:#1677ff;cursor: pointer;">实名认证协议</span> </p>
</div> </div>
<div v-if="userInfo.certificationStatus==='CERTIFICATION_DFFILED'">认证审核中...</div> <div v-if="userInfo.certificationStatus==='CERTIFICATION_DFFILED'">认证审核中...</div>
<div v-if="userInfo.certificationStatus==='CERTIFICATION_FAILED'">认证失败</div> <div v-if="userInfo.certificationStatus==='CERTIFICATION_FAILED'">认证失败</div>
@ -16,15 +17,15 @@
<div class="auth-explanation" style="display: flex;justify-content: flex-start;gap: 100px;"> <div class="auth-explanation" style="display: flex;justify-content: flex-start;gap: 100px;">
<div> <div>
<p><span>认证类型</span>&nbsp;&nbsp;&nbsp;&nbsp;<span>{{ certificationInfo.certificationType }}</span></p> <p><span>认证类型</span>&nbsp;&nbsp;&nbsp;&nbsp;<span>{{ certificationInfo.certificationType }}</span></p>
<p><span>证类型</span>&nbsp;&nbsp;&nbsp;&nbsp;<span></span><span>{{ certificationInfo.idCard }}</span></p> <p><span>类型</span>&nbsp;&nbsp;&nbsp;&nbsp;<span></span><span>{{ certificationInfo.documentType }}</span></p>
<p><span>认证人</span>&nbsp;&nbsp;&nbsp;&nbsp;<span></span><span>{{ certificationInfo.name }}</span></p> <p><span>认证人</span>&nbsp;&nbsp;&nbsp;&nbsp;<span></span><span>{{ certificationInfo.name }}</span></p>
<p> <p>
<a-button type="primary">变更为企业认证</a-button> <a-button type="primary" v-if="certificationInfo.certificationType==='个人认证'" @click="transOpen=true">变更为企业认证</a-button>
</p> </p>
</div> </div>
<div> <div>
<p><span>认证时间</span><span>2025-11-18</span></p> <p><span>认证时间</span><span>{{ certificationInfo.certificationTime }}</span></p>
<p><span>身份证号</span><span>放假就佛法家</span></p> <p><span>身份证号</span><span>{{ certificationInfo.idCard }}</span></p>
<!-- <p><span>认证人</span><span>用户名</span></p> --> <!-- <p><span>认证人</span><span>用户名</span></p> -->
</div> </div>
<div> <div>
@ -86,6 +87,14 @@
</a-card> </a-card>
</div> </div>
</div> </div>
<a-modal v-model:open="transOpen" title="变更须知">
<a-card>
<p>1.您正在进行个人实名认证变更为企业实名认证操作变更后账号以及账号下资产将属于新的认证企业</p>
<p>2. 请知悉升级企业实名认证后该账号将无法再变更回个人实名认证请您谨慎操作</p>
<p><a-checkbox v-model:checked="checked">我已仔细阅读并代表同意 <span style="color: #1677ff;cursor: pointer;">申请账号主体变更协议</span></a-checkbox></p>
<a-button type="primary" @click="goEnterRealAuth" :disabled="!checked">下一步</a-button>
</a-card>
</a-modal>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -104,6 +113,8 @@ import{certificationInfoApi} from '@/apis/certification';
const router = useRouter(); const router = useRouter();
const certificationInfo = ref<any>({ const certificationInfo = ref<any>({
}); });
const checked=ref(false)
const transOpen=ref(false)
const userInfo=ref<any>({ const userInfo=ref<any>({
certificationStatus:'PENDING_CERTIFICATION' certificationStatus:'PENDING_CERTIFICATION'
}); });

View File

@ -1,7 +1,9 @@
<template> <template>
<div class="admin-layout"> <div class="admin-layout">
<div style="background-color: #ffffff;display: flex;flex-direction: column;align-items: center;border-right: 1px solid #e8e8e8;"> <div
<div style="height: 70px;width: 90%;display: flex;justify-content: center;border-bottom: 1px solid #e8e8e8;align-items: center;"> style="background-color: #ffffff;display: flex;flex-direction: column;align-items: center;border-right: 1px solid #e8e8e8;">
<div
style="height: 70px;width: 90%;display: flex;justify-content: center;border-bottom: 1px solid #e8e8e8;align-items: center;">
<a-button type="primary" style="width: 200px;" @click="router.push('/layout/admin/home')"> <a-button type="primary" style="width: 200px;" @click="router.push('/layout/admin/home')">
<template #icon> <template #icon>
<AppstoreAddOutlined /> <AppstoreAddOutlined />
@ -52,10 +54,8 @@ interface MenuItem {
} }
const menuItems: MenuItem[] = [ const menuItems: MenuItem[] = [
{ path: '/layout/admin/home', name: '总览', icon: HomeOutlined, visible: true }, // { path: '/layout/admin/home', name: '', icon: HomeOutlined, visible: true },
{ path: '/layout/admin/instance', name: '容器实例', icon: ConsoleSqlOutlined, visible: true },
{ path: '/layout/admin/image', name: '镜像', icon: GlobalOutlined, visible: true },
{ path: '/layout/admin/fileStore', name: '文件存储', icon: InboxOutlined, visible: true },
{ {
path: '', path: '',
name: '费用', name: '费用',
@ -93,6 +93,10 @@ const menuItems: MenuItem[] = [
{ path: '/layout/admin/bankCard', name: '银行卡管理', visible: true }, { path: '/layout/admin/bankCard', name: '银行卡管理', visible: true },
], ],
}, },
{ path: '/layout/admin/image', name: '镜像管理', icon: GlobalOutlined, visible: true },
{ path: '/layout/admin/instance', name: '实例管理', icon: ConsoleSqlOutlined, visible: true },
{ path: '/layout/admin/instance', name: '存储管理', icon: ConsoleSqlOutlined, visible: true },
]; ];
// //

View File

@ -238,7 +238,7 @@ const getDataList = async () => {
mockData.value = res.data mockData.value = res.data
loading.value = false loading.value = false
} catch (error) { } catch (error) {
console.error('获取实例列表失败:', error) console.log('获取实例列表失败:', error)
message.error('数据加载失败') message.error('数据加载失败')
loading.value = false loading.value = false
} }