Compare commits
2 Commits
4330584af3
...
d440ad0008
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d440ad0008 | ||
|
|
e50e03dcc6 |
2
.env.dev
2
.env.dev
@ -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"
|
||||||
|
|
||||||
|
|||||||
@ -21,4 +21,10 @@ export const getMyCouponTotal = () => request.get('/v1/voucher/voucher_value')
|
|||||||
export const getRecommendList = () => request.get('/v1/voucher/voucher_list')
|
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)
|
||||||
@ -57,12 +57,7 @@ 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: '费用中心',
|
||||||
icon: MoneyCollectOutlined,
|
icon: MoneyCollectOutlined,
|
||||||
@ -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])
|
||||||
|
|||||||
@ -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);
|
||||||
return Promise.reject(error.response.data);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export default request;
|
export default request;
|
||||||
|
|||||||
@ -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>
|
||||||
@ -247,19 +192,20 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, onUnmounted, watch,onBeforeMount } from 'vue';
|
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' }]);
|
||||||
const userInfo=ref<any>({})
|
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');
|
||||||
|
|
||||||
@ -320,10 +266,10 @@ const isVerificationValid = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const isChangeValid = computed(() => {
|
const isChangeValid = computed(() => {
|
||||||
return newPhoneNumber.value.length === 11 &&
|
return newPhoneNumber.value.length === 11 &&
|
||||||
/^1[3-9]\d{9}$/.test(newPhoneNumber.value) &&
|
/^1[3-9]\d{9}$/.test(newPhoneNumber.value) &&
|
||||||
newVerificationCode.value.length === 6 &&
|
newVerificationCode.value.length === 6 &&
|
||||||
/^\d+$/.test(newVerificationCode.value);
|
/^\d+$/.test(newVerificationCode.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 密码强度验证
|
// 密码强度验证
|
||||||
@ -331,7 +277,7 @@ const passwordStrength = computed(() => {
|
|||||||
const lengthValid = newPassword.value.length >= 6 && newPassword.value.length <= 20;
|
const lengthValid = newPassword.value.length >= 6 && newPassword.value.length <= 20;
|
||||||
const hasLetter = /[a-zA-Z]/.test(newPassword.value);
|
const hasLetter = /[a-zA-Z]/.test(newPassword.value);
|
||||||
const hasNumber = /\d/.test(newPassword.value);
|
const hasNumber = /\d/.test(newPassword.value);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
lengthValid,
|
lengthValid,
|
||||||
hasLetter,
|
hasLetter,
|
||||||
@ -341,11 +287,11 @@ const passwordStrength = computed(() => {
|
|||||||
|
|
||||||
const isPasswordValid = computed(() => {
|
const isPasswordValid = computed(() => {
|
||||||
const isOldPasswordValid = oldPassword.value.length >= 6;
|
const isOldPasswordValid = oldPassword.value.length >= 6;
|
||||||
const isNewPasswordValid = passwordStrength.value.lengthValid &&
|
const isNewPasswordValid = passwordStrength.value.lengthValid &&
|
||||||
passwordStrength.value.hasLetter &&
|
passwordStrength.value.hasLetter &&
|
||||||
passwordStrength.value.hasNumber;
|
passwordStrength.value.hasNumber;
|
||||||
const isConfirmValid = confirmPassword.value === newPassword.value && confirmPassword.value.length > 0;
|
const isConfirmValid = confirmPassword.value === newPassword.value && confirmPassword.value.length > 0;
|
||||||
|
|
||||||
return isOldPasswordValid && isNewPasswordValid && isConfirmValid;
|
return isOldPasswordValid && isNewPasswordValid && isConfirmValid;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -358,7 +304,7 @@ watch(newPassword, (newVal) => {
|
|||||||
} else {
|
} else {
|
||||||
newPasswordError.value = '';
|
newPasswordError.value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新确认密码错误提示
|
// 更新确认密码错误提示
|
||||||
if (confirmPassword.value && confirmPassword.value !== newVal) {
|
if (confirmPassword.value && confirmPassword.value !== newVal) {
|
||||||
confirmPasswordError.value = '两次输入的密码不一致';
|
confirmPasswordError.value = '两次输入的密码不一致';
|
||||||
@ -460,7 +406,7 @@ const handleCodeInput = (e: Event) => {
|
|||||||
// 只允许数字
|
// 只允许数字
|
||||||
const numbersOnly = value.replace(/\D/g, '');
|
const numbersOnly = value.replace(/\D/g, '');
|
||||||
verificationCode.value = numbersOnly.slice(0, 6);
|
verificationCode.value = numbersOnly.slice(0, 6);
|
||||||
|
|
||||||
// 清除错误提示
|
// 清除错误提示
|
||||||
if (codeError.value) {
|
if (codeError.value) {
|
||||||
codeError.value = '';
|
codeError.value = '';
|
||||||
@ -470,19 +416,19 @@ const handleCodeInput = (e: Event) => {
|
|||||||
// 发送当前手机号验证码
|
// 发送当前手机号验证码
|
||||||
const sendVerificationCode = async () => {
|
const sendVerificationCode = async () => {
|
||||||
if (countdown.value > 0 || sendingCode.value) return;
|
if (countdown.value > 0 || sendingCode.value) return;
|
||||||
|
|
||||||
sendingCode.value = true;
|
sendingCode.value = true;
|
||||||
sendStatus.value = '发送中...';
|
sendStatus.value = '发送中...';
|
||||||
codeError.value = '';
|
codeError.value = '';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 模拟API调用
|
// 模拟API调用
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
|
||||||
// 假设发送成功
|
// 假设发送成功
|
||||||
sendStatus.value = '发送成功';
|
sendStatus.value = '发送成功';
|
||||||
countdown.value = 60;
|
countdown.value = 60;
|
||||||
|
|
||||||
// 开始倒计时
|
// 开始倒计时
|
||||||
timer = setInterval(() => {
|
timer = setInterval(() => {
|
||||||
countdown.value--;
|
countdown.value--;
|
||||||
@ -493,7 +439,7 @@ const sendVerificationCode = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
message.success('验证码已发送');
|
message.success('验证码已发送');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
codeError.value = '发送失败,请稍后重试';
|
codeError.value = '发送失败,请稍后重试';
|
||||||
@ -509,26 +455,24 @@ 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) {
|
||||||
verifyVisible.value = false;
|
successCode.value = res.success_code
|
||||||
|
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 = '验证码错误,请重新输入';
|
||||||
verificationCode.value = '';
|
verificationCode.value = '';
|
||||||
@ -565,7 +509,7 @@ const handlePhoneInput = (e: Event) => {
|
|||||||
// 只允许数字
|
// 只允许数字
|
||||||
const numbersOnly = value.replace(/\D/g, '');
|
const numbersOnly = value.replace(/\D/g, '');
|
||||||
newPhoneNumber.value = numbersOnly.slice(0, 11);
|
newPhoneNumber.value = numbersOnly.slice(0, 11);
|
||||||
|
|
||||||
// 清除错误提示
|
// 清除错误提示
|
||||||
if (phoneError.value) {
|
if (phoneError.value) {
|
||||||
phoneError.value = '';
|
phoneError.value = '';
|
||||||
@ -582,7 +526,7 @@ const handleNewCodeInput = (e: Event) => {
|
|||||||
// 只允许数字
|
// 只允许数字
|
||||||
const numbersOnly = value.replace(/\D/g, '');
|
const numbersOnly = value.replace(/\D/g, '');
|
||||||
newVerificationCode.value = numbersOnly.slice(0, 6);
|
newVerificationCode.value = numbersOnly.slice(0, 6);
|
||||||
|
|
||||||
// 清除错误提示
|
// 清除错误提示
|
||||||
if (newCodeError.value) {
|
if (newCodeError.value) {
|
||||||
newCodeError.value = '';
|
newCodeError.value = '';
|
||||||
@ -596,29 +540,29 @@ const sendNewVerificationCode = async () => {
|
|||||||
phoneError.value = '请输入11位手机号';
|
phoneError.value = '请输入11位手机号';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!/^1[3-9]\d{9}$/.test(newPhoneNumber.value)) {
|
if (!/^1[3-9]\d{9}$/.test(newPhoneNumber.value)) {
|
||||||
phoneError.value = '请输入正确的手机号格式';
|
phoneError.value = '请输入正确的手机号格式';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newPhoneNumber.value === currentPhone.value) {
|
if (newPhoneNumber.value === currentPhone.value) {
|
||||||
phoneError.value = '新手机号不能与当前手机号相同';
|
phoneError.value = '新手机号不能与当前手机号相同';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newCountdown.value > 0 || sendingNewCode.value) return;
|
if (newCountdown.value > 0 || sendingNewCode.value) return;
|
||||||
|
|
||||||
sendingNewCode.value = true;
|
sendingNewCode.value = true;
|
||||||
newCodeError.value = '';
|
newCodeError.value = '';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 模拟API调用
|
// 模拟API调用
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
|
||||||
// 假设发送成功
|
// 假设发送成功
|
||||||
newCountdown.value = 60;
|
newCountdown.value = 60;
|
||||||
|
|
||||||
// 开始倒计时
|
// 开始倒计时
|
||||||
newTimer = setInterval(() => {
|
newTimer = setInterval(() => {
|
||||||
newCountdown.value--;
|
newCountdown.value--;
|
||||||
@ -629,7 +573,7 @@ const sendNewVerificationCode = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
message.success('验证码已发送到新手机号');
|
message.success('验证码已发送到新手机号');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
newCodeError.value = '发送失败,请稍后重试';
|
newCodeError.value = '发送失败,请稍后重试';
|
||||||
@ -660,24 +604,24 @@ const handleChangePhone = async () => {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
changing.value = true;
|
changing.value = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 模拟API调用修改手机号
|
// 模拟API调用修改手机号
|
||||||
await new Promise(resolve => setTimeout(resolve, 1500));
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
||||||
|
|
||||||
// 更新当前手机号
|
// 更新当前手机号
|
||||||
currentPhone.value = newPhoneNumber.value;
|
currentPhone.value = newPhoneNumber.value;
|
||||||
|
|
||||||
// 关闭对话框
|
// 关闭对话框
|
||||||
changePhoneVisible.value = false;
|
changePhoneVisible.value = false;
|
||||||
|
|
||||||
// 重置所有状态
|
// 重置所有状态
|
||||||
resetAllStates();
|
resetAllStates();
|
||||||
|
|
||||||
message.success('手机号修改成功');
|
message.success('手机号修改成功');
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
newCodeError.value = '修改失败,请稍后重试';
|
newCodeError.value = '修改失败,请稍后重试';
|
||||||
} finally {
|
} finally {
|
||||||
@ -687,6 +631,7 @@ const handleChangePhone = async () => {
|
|||||||
|
|
||||||
// 显示修改密码对话框
|
// 显示修改密码对话框
|
||||||
const showChangePasswordDialog = () => {
|
const showChangePasswordDialog = () => {
|
||||||
|
console.log(111)
|
||||||
// 重置状态
|
// 重置状态
|
||||||
oldPassword.value = '';
|
oldPassword.value = '';
|
||||||
newPassword.value = '';
|
newPassword.value = '';
|
||||||
@ -707,7 +652,7 @@ const handleOldPasswordInput = (e: Event) => {
|
|||||||
const target = e.target as HTMLInputElement;
|
const target = e.target as HTMLInputElement;
|
||||||
const value = target.value;
|
const value = target.value;
|
||||||
oldPassword.value = value;
|
oldPassword.value = value;
|
||||||
|
|
||||||
// 清除错误提示
|
// 清除错误提示
|
||||||
if (oldPasswordError.value) {
|
if (oldPasswordError.value) {
|
||||||
oldPasswordError.value = '';
|
oldPasswordError.value = '';
|
||||||
@ -719,7 +664,7 @@ const handleNewPasswordInput = (e: Event) => {
|
|||||||
const target = e.target as HTMLInputElement;
|
const target = e.target as HTMLInputElement;
|
||||||
const value = target.value;
|
const value = target.value;
|
||||||
newPassword.value = value;
|
newPassword.value = value;
|
||||||
|
|
||||||
// 清除错误提示
|
// 清除错误提示
|
||||||
if (newPasswordError.value) {
|
if (newPasswordError.value) {
|
||||||
newPasswordError.value = '';
|
newPasswordError.value = '';
|
||||||
@ -731,7 +676,7 @@ const handleConfirmPasswordInput = (e: Event) => {
|
|||||||
const target = e.target as HTMLInputElement;
|
const target = e.target as HTMLInputElement;
|
||||||
const value = target.value;
|
const value = target.value;
|
||||||
confirmPassword.value = value;
|
confirmPassword.value = value;
|
||||||
|
|
||||||
// 清除错误提示
|
// 清除错误提示
|
||||||
if (confirmPasswordError.value) {
|
if (confirmPasswordError.value) {
|
||||||
confirmPasswordError.value = '';
|
confirmPasswordError.value = '';
|
||||||
@ -764,21 +709,22 @@ const handleChangePassword = async () => {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
||||||
// 重置所有状态
|
message.success('密码修改成功');
|
||||||
resetPasswordStates();
|
localStorage.clear()
|
||||||
|
router.replace('/login')
|
||||||
message.success('密码修改成功');
|
|
||||||
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
oldPasswordError.value = '原密码错误或修改失败';
|
oldPasswordError.value = '原密码错误或修改失败';
|
||||||
} finally {
|
} finally {
|
||||||
@ -797,7 +743,7 @@ const resetAllStates = () => {
|
|||||||
timer = null;
|
timer = null;
|
||||||
}
|
}
|
||||||
countdown.value = 0;
|
countdown.value = 0;
|
||||||
|
|
||||||
// 修改手机号状态重置
|
// 修改手机号状态重置
|
||||||
newPhoneNumber.value = '';
|
newPhoneNumber.value = '';
|
||||||
newVerificationCode.value = '';
|
newVerificationCode.value = '';
|
||||||
@ -820,21 +766,21 @@ const resetPasswordStates = () => {
|
|||||||
confirmPasswordError.value = '';
|
confirmPasswordError.value = '';
|
||||||
};
|
};
|
||||||
const getCertificationInfo = async () => {
|
const getCertificationInfo = async () => {
|
||||||
try {
|
try {
|
||||||
const res=await certificationInfoApi();
|
const res = await certificationInfoApi();
|
||||||
certificationInfo.value=res;
|
certificationInfo.value = res;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
message.error('获取认证信息失败');
|
message.error('获取认证信息失败');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
onBeforeMount(()=>{
|
onBeforeMount(() => {
|
||||||
const userInfoStr = localStorage.getItem('userInfo');
|
const userInfoStr = localStorage.getItem('userInfo');
|
||||||
if (userInfoStr) {
|
if (userInfoStr) {
|
||||||
userInfo.value=JSON.parse(userInfoStr);
|
userInfo.value = JSON.parse(userInfoStr);
|
||||||
if(userInfo.value.certificationStatus==='CERTIFICATION_PASSED'){
|
if (userInfo.value.certificationStatus === 'CERTIFICATION_PASSED') {
|
||||||
getCertificationInfo();
|
getCertificationInfo();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -874,11 +820,11 @@ onBeforeMount(()=>{
|
|||||||
span:first-child {
|
span:first-child {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
}
|
}
|
||||||
|
|
||||||
div[style*="color:#1677ff"] {
|
div[style*="color:#1677ff"] {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: color 0.3s;
|
transition: color 0.3s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #0958d9;
|
color: #0958d9;
|
||||||
}
|
}
|
||||||
@ -1074,11 +1020,11 @@ onBeforeMount(()=>{
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #8c8c8c;
|
color: #8c8c8c;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.valid {
|
&.valid {
|
||||||
color: #52c41a;
|
color: #52c41a;
|
||||||
}
|
}
|
||||||
@ -1099,7 +1045,7 @@ onBeforeMount(()=>{
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.send-code-btn {
|
.send-code-btn {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,28 +4,25 @@
|
|||||||
<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>
|
||||||
|
|
||||||
<!-- 右侧:算力点和算力券卡片 -->
|
<!-- 右侧:算力点和算力券卡片 -->
|
||||||
<a-col :span="16">
|
<a-col :span="16">
|
||||||
<!-- 算力点卡片 -->
|
<!-- 算力点卡片 -->
|
||||||
<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,44 +48,27 @@
|
|||||||
<!-- 底部账单区域 -->
|
<!-- 底部账单区域 -->
|
||||||
<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'">
|
||||||
<span class="serial-number">{{ record.serialNumber }}</span>
|
<span class="serial-number">{{ record.serialNumber }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 交易类型列 -->
|
<!-- 交易类型列 -->
|
||||||
<template v-else-if="column.key === 'transactionType'">
|
<template v-else-if="column.key === 'transactionType'">
|
||||||
<a-tag :color="getTransactionTypeColor(record.transactionType)">
|
<a-tag :color="getTransactionTypeColor(record.transactionType)">
|
||||||
{{ record.transactionType }}
|
{{ record.transactionType }}
|
||||||
</a-tag>
|
</a-tag>
|
||||||
</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()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -255,7 +237,7 @@ const handleDateChange = (dates: [Dayjs, Dayjs] | null) => {
|
|||||||
const handleTableChange: TableProps['onChange'] = (pag, filters, sorter) => {
|
const handleTableChange: TableProps['onChange'] = (pag, filters, sorter) => {
|
||||||
pagination.value.current = pag.current!
|
pagination.value.current = pag.current!
|
||||||
pagination.value.pageSize = pag.pageSize!
|
pagination.value.pageSize = pag.pageSize!
|
||||||
|
|
||||||
// 这里应该根据排序和筛选条件重新加载数据
|
// 这里应该根据排序和筛选条件重新加载数据
|
||||||
fetchBillData()
|
fetchBillData()
|
||||||
}
|
}
|
||||||
@ -263,7 +245,7 @@ const handleTableChange: TableProps['onChange'] = (pag, filters, sorter) => {
|
|||||||
// 模拟获取账单数据
|
// 模拟获取账单数据
|
||||||
const fetchBillData = () => {
|
const fetchBillData = () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
|
|
||||||
// 模拟API调用延迟
|
// 模拟API调用延迟
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// 模拟数据
|
// 模拟数据
|
||||||
@ -341,7 +323,7 @@ const fetchBillData = () => {
|
|||||||
voucherDeduction: 0.00
|
voucherDeduction: 0.00
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
billData.value = mockData
|
billData.value = mockData
|
||||||
pagination.value.total = mockData.length
|
pagination.value.total = mockData.length
|
||||||
loading.value = false
|
loading.value = false
|
||||||
@ -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>
|
||||||
@ -377,8 +374,9 @@ 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;
|
||||||
}
|
}
|
||||||
@ -390,12 +388,12 @@ const goToExchange = () => {
|
|||||||
background: #fff;
|
background: #fff;
|
||||||
border: 1px solid #e8e8e8;
|
border: 1px solid #e8e8e8;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
:deep(.ant-card-head) {
|
:deep(.ant-card-head) {
|
||||||
border-bottom: 1px solid #f0f0f0;
|
border-bottom: 1px solid #f0f0f0;
|
||||||
min-height: 48px;
|
min-height: 48px;
|
||||||
background: #fafafa;
|
background: #fafafa;
|
||||||
|
|
||||||
.ant-card-head-title {
|
.ant-card-head-title {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@ -403,7 +401,7 @@ const goToExchange = () => {
|
|||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ant-card-body) {
|
:deep(.ant-card-body) {
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
}
|
}
|
||||||
@ -417,62 +415,62 @@ const goToExchange = () => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fee-title {
|
.fee-title {
|
||||||
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 {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #1890ff;
|
color: #1890ff;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ant-divider) {
|
:deep(.ant-divider) {
|
||||||
margin: 16px 0;
|
margin: 16px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.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) {
|
||||||
width: 100px;
|
width: 100px;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
|
||||||
&.ant-btn-primary {
|
&.ant-btn-primary {
|
||||||
background: #1890ff;
|
background: #1890ff;
|
||||||
border-color: #1890ff;
|
border-color: #1890ff;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: #40a9ff;
|
background: #40a9ff;
|
||||||
border-color: #40a9ff;
|
border-color: #40a9ff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(.ant-btn-primary) {
|
&:not(.ant-btn-primary) {
|
||||||
color: #666;
|
color: #666;
|
||||||
border-color: #d9d9d9;
|
border-color: #d9d9d9;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #1890ff;
|
color: #1890ff;
|
||||||
border-color: #1890ff;
|
border-color: #1890ff;
|
||||||
@ -484,48 +482,50 @@ const goToExchange = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 右侧算力点卡片
|
// 右侧算力点卡片
|
||||||
.computing-card, .coupon-card {
|
.computing-card,
|
||||||
|
.coupon-card {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.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;
|
||||||
}
|
}
|
||||||
|
|
||||||
.amount-unit {
|
.amount-unit {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
color: #666;
|
color: #666;
|
||||||
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;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
|
||||||
&.ant-btn-primary {
|
&.ant-btn-primary {
|
||||||
background: #1890ff;
|
background: #1890ff;
|
||||||
border-color: #1890ff;
|
border-color: #1890ff;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: #40a9ff;
|
background: #40a9ff;
|
||||||
border-color: #40a9ff;
|
border-color: #40a9ff;
|
||||||
@ -551,32 +551,32 @@ const goToExchange = () => {
|
|||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
padding-bottom: 16px;
|
padding-bottom: 16px;
|
||||||
border-bottom: 1px solid #f0f0f0;
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
|
||||||
.bill-title {
|
.bill-title {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #333;
|
color: #333;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.date-range {
|
.date-range {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
.date-label {
|
.date-label {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #666;
|
color: #666;
|
||||||
margin-right: 12px;
|
margin-right: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ant-picker) {
|
:deep(.ant-picker) {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
border-color: #d9d9d9;
|
border-color: #d9d9d9;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
border-color: #40a9ff;
|
border-color: #40a9ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.ant-picker-focused {
|
&.ant-picker-focused {
|
||||||
border-color: #1890ff;
|
border-color: #1890ff;
|
||||||
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
|
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
|
||||||
@ -590,48 +590,48 @@ const goToExchange = () => {
|
|||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: 1px solid #f0f0f0;
|
border: 1px solid #f0f0f0;
|
||||||
|
|
||||||
.ant-table-thead > tr > th {
|
.ant-table-thead>tr>th {
|
||||||
background: #fafafa;
|
background: #fafafa;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #333;
|
color: #333;
|
||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
border-bottom: 1px solid #f0f0f0;
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
|
||||||
&:not(:last-child) {
|
&:not(:last-child) {
|
||||||
border-right: 1px solid #f0f0f0;
|
border-right: 1px solid #f0f0f0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-table-tbody > tr > td {
|
.ant-table-tbody>tr>td {
|
||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
border-bottom: 1px solid #f0f0f0;
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
|
||||||
&:not(:last-child) {
|
&:not(:last-child) {
|
||||||
border-right: 1px solid #f0f0f0;
|
border-right: 1px solid #f0f0f0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: #fafafa;
|
background: #fafafa;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-table-tbody > tr:last-child > td {
|
.ant-table-tbody>tr:last-child>td {
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.serial-number {
|
.serial-number {
|
||||||
font-family: 'Courier New', monospace;
|
font-family: 'Courier New', monospace;
|
||||||
color: #1890ff;
|
color: #1890ff;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.amount-positive {
|
.amount-positive {
|
||||||
color: #52c41a;
|
color: #52c41a;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.amount-negative {
|
.amount-negative {
|
||||||
color: #ff4d4f;
|
color: #ff4d4f;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@ -643,36 +643,39 @@ const goToExchange = () => {
|
|||||||
.home-page {
|
.home-page {
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.asset-cards {
|
.asset-cards {
|
||||||
.ant-col-8, .ant-col-16 {
|
|
||||||
|
.ant-col-8,
|
||||||
|
.ant-col-16 {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-col-8 {
|
.ant-col-8 {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.bill-header {
|
.bill-header {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
|
|
||||||
.date-range {
|
.date-range {
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
:deep(.ant-picker) {
|
:deep(.ant-picker) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.money {
|
.money {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.computing-content, .coupon-content {
|
.computing-content,
|
||||||
|
.coupon-content {
|
||||||
.amount-value {
|
.amount-value {
|
||||||
font-size: 32px;
|
font-size: 32px;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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> <span>{{ certificationInfo.certificationType }}</span></p>
|
<p><span>认证类型</span> <span>{{ certificationInfo.certificationType }}</span></p>
|
||||||
<p><span>认证类型</span> <span></span><span>{{ certificationInfo.idCard }}</span></p>
|
<p><span>证件类型</span> <span></span><span>{{ certificationInfo.documentType }}</span></p>
|
||||||
<p><span>认证人</span> <span></span><span>{{ certificationInfo.name }}</span></p>
|
<p><span>认证人</span> <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'
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
<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 />
|
||||||
</template>
|
</template>
|
||||||
总览
|
总览
|
||||||
</a-button>
|
</a-button>
|
||||||
@ -23,8 +25,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { h, reactive, computed,watch } from 'vue';
|
import { h, reactive, computed, watch } from 'vue';
|
||||||
import { useRouter,useRoute } from 'vue-router';
|
import { useRouter, useRoute } from 'vue-router';
|
||||||
import {
|
import {
|
||||||
HomeOutlined,
|
HomeOutlined,
|
||||||
ConsoleSqlOutlined,
|
ConsoleSqlOutlined,
|
||||||
@ -53,9 +55,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: '',
|
path: '',
|
||||||
name: '费用中心',
|
name: '费用中心',
|
||||||
@ -72,7 +73,7 @@ const menuItems: MenuItem[] = [
|
|||||||
{ path: '/layout/admin/myOrder', name: '订单明细', visible: true, disabled: false },
|
{ path: '/layout/admin/myOrder', name: '订单明细', visible: true, disabled: false },
|
||||||
// { path: '/layout/admin/flow', name: '账单明细', visible: true, disabled: false },
|
// { path: '/layout/admin/flow', name: '账单明细', visible: true, disabled: false },
|
||||||
// { path: '/layout/admin/coupon', name: '优惠券(待开发)', disabled: true, visible: true },
|
// { path: '/layout/admin/coupon', name: '优惠券(待开发)', disabled: true, visible: true },
|
||||||
|
|
||||||
// { path: '/layout/admin/voucher', name: '代金券(待开发)', disabled: true, visible: true },
|
// { path: '/layout/admin/voucher', name: '代金券(待开发)', disabled: true, visible: true },
|
||||||
// { path: '/layout/admin/contract', name: '合同(待开发)', disabled: true, visible: true },
|
// { path: '/layout/admin/contract', name: '合同(待开发)', disabled: true, visible: true },
|
||||||
],
|
],
|
||||||
@ -94,6 +95,10 @@ const menuItems: MenuItem[] = [
|
|||||||
{ path: '/layout/admin/invoices', name: '发票抬头管理', visible: true },
|
{ path: '/layout/admin/invoices', 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 },
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// 状态
|
// 状态
|
||||||
@ -138,43 +143,43 @@ const items = computed(() => {
|
|||||||
.filter(child => child.visible !== false)
|
.filter(child => child.visible !== false)
|
||||||
.map((child) =>
|
.map((child) =>
|
||||||
getItem(
|
getItem(
|
||||||
child.name,
|
child.name,
|
||||||
child.path,
|
child.path,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
child.disabled
|
child.disabled
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.filter(Boolean) as MenuItemType[];
|
.filter(Boolean) as MenuItemType[];
|
||||||
|
|
||||||
// 如果子项全部被过滤掉了,则显示父项但不显示子菜单
|
// 如果子项全部被过滤掉了,则显示父项但不显示子菜单
|
||||||
if (childItems.length === 0) {
|
if (childItems.length === 0) {
|
||||||
return getItem(
|
return getItem(
|
||||||
item.name,
|
item.name,
|
||||||
item.path,
|
item.path,
|
||||||
h(item.icon),
|
h(item.icon),
|
||||||
undefined, // 没有子项
|
undefined, // 没有子项
|
||||||
undefined,
|
undefined,
|
||||||
item.disabled
|
item.disabled
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return getItem(
|
return getItem(
|
||||||
item.name,
|
item.name,
|
||||||
item.path,
|
item.path,
|
||||||
h(item.icon),
|
h(item.icon),
|
||||||
childItems,
|
childItems,
|
||||||
undefined,
|
undefined,
|
||||||
item.disabled
|
item.disabled
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return getItem(
|
return getItem(
|
||||||
item.name,
|
item.name,
|
||||||
item.path,
|
item.path,
|
||||||
h(item.icon),
|
h(item.icon),
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
item.disabled
|
item.disabled
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -186,7 +191,7 @@ const handleMenuSelect = ({ key }: { key: string }) => {
|
|||||||
// 递归查找菜单项(需要包含所有项,包括隐藏的)
|
// 递归查找菜单项(需要包含所有项,包括隐藏的)
|
||||||
const allItems = flattenMenuItems(menuItems);
|
const allItems = flattenMenuItems(menuItems);
|
||||||
const targetItem = allItems.find(item => item.path === key);
|
const targetItem = allItems.find(item => item.path === key);
|
||||||
|
|
||||||
// 检查是否禁用或不可见
|
// 检查是否禁用或不可见
|
||||||
if (targetItem?.disabled || targetItem?.visible === false) {
|
if (targetItem?.disabled || targetItem?.visible === false) {
|
||||||
return;
|
return;
|
||||||
@ -197,14 +202,14 @@ const handleMenuSelect = ({ key }: { key: string }) => {
|
|||||||
// 辅助函数:扁平化所有菜单项
|
// 辅助函数:扁平化所有菜单项
|
||||||
function flattenMenuItems(items: MenuItem[]): MenuItem[] {
|
function flattenMenuItems(items: MenuItem[]): MenuItem[] {
|
||||||
let result: MenuItem[] = [];
|
let result: MenuItem[] = [];
|
||||||
|
|
||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
result.push(item);
|
result.push(item);
|
||||||
if (item.children) {
|
if (item.children) {
|
||||||
result = result.concat(flattenMenuItems(item.children));
|
result = result.concat(flattenMenuItems(item.children));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user