feat: 添加实名认证功能,更新路由和组件,优化个人设置页面
This commit is contained in:
4
components.d.ts
vendored
4
components.d.ts
vendored
@@ -17,6 +17,7 @@ declare module 'vue' {
|
|||||||
IonApp: typeof import('@ionic/vue')['IonApp']
|
IonApp: typeof import('@ionic/vue')['IonApp']
|
||||||
IonAvatar: typeof import('@ionic/vue')['IonAvatar']
|
IonAvatar: typeof import('@ionic/vue')['IonAvatar']
|
||||||
IonButton: typeof import('@ionic/vue')['IonButton']
|
IonButton: typeof import('@ionic/vue')['IonButton']
|
||||||
|
IonButtons: typeof import('@ionic/vue')['IonButtons']
|
||||||
IonCheckbox: typeof import('@ionic/vue')['IonCheckbox']
|
IonCheckbox: typeof import('@ionic/vue')['IonCheckbox']
|
||||||
IonContent: typeof import('@ionic/vue')['IonContent']
|
IonContent: typeof import('@ionic/vue')['IonContent']
|
||||||
IonDatetime: typeof import('@ionic/vue')['IonDatetime']
|
IonDatetime: typeof import('@ionic/vue')['IonDatetime']
|
||||||
@@ -27,6 +28,7 @@ declare module 'vue' {
|
|||||||
IonInput: typeof import('@ionic/vue')['IonInput']
|
IonInput: typeof import('@ionic/vue')['IonInput']
|
||||||
IonItem: typeof import('@ionic/vue')['IonItem']
|
IonItem: typeof import('@ionic/vue')['IonItem']
|
||||||
IonLabel: typeof import('@ionic/vue')['IonLabel']
|
IonLabel: typeof import('@ionic/vue')['IonLabel']
|
||||||
|
IonList: typeof import('@ionic/vue')['IonList']
|
||||||
IonPage: typeof import('@ionic/vue')['IonPage']
|
IonPage: typeof import('@ionic/vue')['IonPage']
|
||||||
IonRouterOutlet: typeof import('@ionic/vue')['IonRouterOutlet']
|
IonRouterOutlet: typeof import('@ionic/vue')['IonRouterOutlet']
|
||||||
IonSpinner: typeof import('@ionic/vue')['IonSpinner']
|
IonSpinner: typeof import('@ionic/vue')['IonSpinner']
|
||||||
@@ -48,6 +50,7 @@ declare global {
|
|||||||
const IonApp: typeof import('@ionic/vue')['IonApp']
|
const IonApp: typeof import('@ionic/vue')['IonApp']
|
||||||
const IonAvatar: typeof import('@ionic/vue')['IonAvatar']
|
const IonAvatar: typeof import('@ionic/vue')['IonAvatar']
|
||||||
const IonButton: typeof import('@ionic/vue')['IonButton']
|
const IonButton: typeof import('@ionic/vue')['IonButton']
|
||||||
|
const IonButtons: typeof import('@ionic/vue')['IonButtons']
|
||||||
const IonCheckbox: typeof import('@ionic/vue')['IonCheckbox']
|
const IonCheckbox: typeof import('@ionic/vue')['IonCheckbox']
|
||||||
const IonContent: typeof import('@ionic/vue')['IonContent']
|
const IonContent: typeof import('@ionic/vue')['IonContent']
|
||||||
const IonDatetime: typeof import('@ionic/vue')['IonDatetime']
|
const IonDatetime: typeof import('@ionic/vue')['IonDatetime']
|
||||||
@@ -58,6 +61,7 @@ declare global {
|
|||||||
const IonInput: typeof import('@ionic/vue')['IonInput']
|
const IonInput: typeof import('@ionic/vue')['IonInput']
|
||||||
const IonItem: typeof import('@ionic/vue')['IonItem']
|
const IonItem: typeof import('@ionic/vue')['IonItem']
|
||||||
const IonLabel: typeof import('@ionic/vue')['IonLabel']
|
const IonLabel: typeof import('@ionic/vue')['IonLabel']
|
||||||
|
const IonList: typeof import('@ionic/vue')['IonList']
|
||||||
const IonPage: typeof import('@ionic/vue')['IonPage']
|
const IonPage: typeof import('@ionic/vue')['IonPage']
|
||||||
const IonRouterOutlet: typeof import('@ionic/vue')['IonRouterOutlet']
|
const IonRouterOutlet: typeof import('@ionic/vue')['IonRouterOutlet']
|
||||||
const IonSpinner: typeof import('@ionic/vue')['IonSpinner']
|
const IonSpinner: typeof import('@ionic/vue')['IonSpinner']
|
||||||
|
|||||||
BIN
src/assets/images/header.jpg
Normal file
BIN
src/assets/images/header.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
@@ -42,10 +42,22 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
{
|
{
|
||||||
path: "/check_in",
|
path: "/check_in",
|
||||||
component: () => import("@/views/check_in/index.vue"),
|
component: () => import("@/views/check_in/index.vue"),
|
||||||
|
meta: { requiresAuth: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/invite",
|
path: "/invite",
|
||||||
component: () => import("@/views/invite/index.vue"),
|
component: () => import("@/views/invite/index.vue"),
|
||||||
|
meta: { requiresAuth: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/settings",
|
||||||
|
component: () => import("@/views/settings/index.vue"),
|
||||||
|
meta: { requiresAuth: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/real_name",
|
||||||
|
component: () => import("@/views/real_name/index.vue"),
|
||||||
|
meta: { requiresAuth: true },
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -131,6 +131,7 @@
|
|||||||
} */
|
} */
|
||||||
|
|
||||||
.ion-toolbar {
|
.ion-toolbar {
|
||||||
--background: var(--ion-color-primary-contrast);
|
--background: var(--ion-color-primary);
|
||||||
--min-height: 50px;
|
--min-height: 58px;
|
||||||
|
--color: white;
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,7 @@ export const myApps = [
|
|||||||
name: "实名认证",
|
name: "实名认证",
|
||||||
icon: shieldCheckmarkOutline,
|
icon: shieldCheckmarkOutline,
|
||||||
color: "#c32120",
|
color: "#c32120",
|
||||||
path: "/real-name",
|
path: "/real_name",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "address",
|
id: "address",
|
||||||
@@ -27,7 +27,7 @@ export const myApps = [
|
|||||||
name: "在线客服",
|
name: "在线客服",
|
||||||
icon: chatbubblesOutline,
|
icon: chatbubblesOutline,
|
||||||
color: "#c32120",
|
color: "#c32120",
|
||||||
path: "/customer-service",
|
path: "/customer_service",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "settings",
|
id: "settings",
|
||||||
@@ -48,7 +48,7 @@ export const myApps = [
|
|||||||
name: "资产明细",
|
name: "资产明细",
|
||||||
icon: listOutline,
|
icon: listOutline,
|
||||||
color: "#c32120",
|
color: "#c32120",
|
||||||
path: "/asset-details",
|
path: "/asset_details",
|
||||||
},
|
},
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
|
|||||||
396
src/views/real_name/index.vue
Normal file
396
src/views/real_name/index.vue
Normal file
@@ -0,0 +1,396 @@
|
|||||||
|
<script lang='ts' setup>
|
||||||
|
import { Camera, CameraResultType, CameraSource } from "@capacitor/camera";
|
||||||
|
import { actionSheetController, toastController } from "@ionic/vue";
|
||||||
|
import { cameraOutline, cardOutline, checkmarkCircleOutline, imageOutline, personOutline } from "ionicons/icons";
|
||||||
|
import zod from "zod";
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const formData = ref({
|
||||||
|
realName: "",
|
||||||
|
idCard: "",
|
||||||
|
idCardFrontImage: "",
|
||||||
|
idCardBackImage: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
const isSubmitting = ref(false);
|
||||||
|
|
||||||
|
// 表单验证 Schema
|
||||||
|
const RealNameSchema = zod.object({
|
||||||
|
realName: zod
|
||||||
|
.string()
|
||||||
|
.min(2, "请输入真实姓名")
|
||||||
|
.max(10, "姓名长度不能超过10个字符"),
|
||||||
|
|
||||||
|
idCard: zod
|
||||||
|
.string()
|
||||||
|
.min(1, "请输入身份证号码")
|
||||||
|
.regex(
|
||||||
|
/(^\d{15}$)|(^\d{18}$)|(^\d{17}([\dX])$)/i,
|
||||||
|
"请输入正确的身份证号码",
|
||||||
|
),
|
||||||
|
|
||||||
|
idCardFrontImage: zod
|
||||||
|
.string()
|
||||||
|
.min(1, "请上传身份证正面照片"),
|
||||||
|
|
||||||
|
idCardBackImage: zod
|
||||||
|
.string()
|
||||||
|
.min(1, "请上传身份证反面照片"),
|
||||||
|
});
|
||||||
|
|
||||||
|
async function showToast(message: string, color: "success" | "danger" | "warning" = "danger") {
|
||||||
|
const toast = await toastController.create({
|
||||||
|
message,
|
||||||
|
duration: 2000,
|
||||||
|
position: "top",
|
||||||
|
color,
|
||||||
|
});
|
||||||
|
await toast.present();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function takePicture(type: "front" | "back") {
|
||||||
|
try {
|
||||||
|
const image = await Camera.getPhoto({
|
||||||
|
quality: 80,
|
||||||
|
allowEditing: false,
|
||||||
|
resultType: CameraResultType.DataUrl,
|
||||||
|
source: CameraSource.Camera,
|
||||||
|
width: 1200,
|
||||||
|
height: 800,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (image.dataUrl) {
|
||||||
|
if (type === "front") {
|
||||||
|
formData.value.idCardFrontImage = image.dataUrl;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
formData.value.idCardBackImage = image.dataUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error: any) {
|
||||||
|
if (error?.message !== "User cancelled photos app") {
|
||||||
|
await showToast("拍照失败,请重试", "danger");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function selectFromGallery(type: "front" | "back") {
|
||||||
|
try {
|
||||||
|
const image = await Camera.getPhoto({
|
||||||
|
quality: 80,
|
||||||
|
allowEditing: false,
|
||||||
|
resultType: CameraResultType.DataUrl,
|
||||||
|
source: CameraSource.Photos,
|
||||||
|
width: 1200,
|
||||||
|
height: 800,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (image.dataUrl) {
|
||||||
|
if (type === "front") {
|
||||||
|
formData.value.idCardFrontImage = image.dataUrl;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
formData.value.idCardBackImage = image.dataUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error: any) {
|
||||||
|
if (error?.message !== "User cancelled photos app") {
|
||||||
|
await showToast("选择图片失败,请重试", "danger");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function showImageSourceOptions(type: "front" | "back") {
|
||||||
|
const actionSheet = await actionSheetController.create({
|
||||||
|
header: "选择图片来源",
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
text: "拍照",
|
||||||
|
handler: () => takePicture(type),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "从相册选择",
|
||||||
|
handler: () => selectFromGallery(type),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "取消",
|
||||||
|
role: "cancel",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await actionSheet.present();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleSubmit() {
|
||||||
|
const result = RealNameSchema.safeParse(formData.value);
|
||||||
|
if (!result.success) {
|
||||||
|
const first = result.error.issues[0];
|
||||||
|
await showToast(first.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isSubmitting.value = true;
|
||||||
|
try {
|
||||||
|
// TODO: 调用实名认证 API
|
||||||
|
// const { data } = await safeClient(client.api.realname.post(formData.value));
|
||||||
|
|
||||||
|
// 模拟 API 调用
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
||||||
|
|
||||||
|
await showToast("实名认证提交成功,等待审核", "success");
|
||||||
|
router.back();
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
await showToast("提交失败,请重试", "danger");
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
isSubmitting.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ion-page>
|
||||||
|
<ion-header class="ion-no-border">
|
||||||
|
<ion-toolbar class="ion-toolbar">
|
||||||
|
<ion-buttons slot="start">
|
||||||
|
<back-button />
|
||||||
|
</ion-buttons>
|
||||||
|
<ion-title>实名认证</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
|
||||||
|
<ion-content class="ion-padding">
|
||||||
|
<div class="space-y-5">
|
||||||
|
<!-- 提示信息 -->
|
||||||
|
<div class="info-card">
|
||||||
|
<ion-icon :icon="checkmarkCircleOutline" class="text-2xl text-[#c41e3a]" />
|
||||||
|
<div class="text-sm text-[#666] leading-relaxed">
|
||||||
|
为了保障您的账户安全,请完成实名认证。您的个人信息将严格保密。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 表单卡片 -->
|
||||||
|
<div class="form-card">
|
||||||
|
<div class="space-y-4">
|
||||||
|
<!-- 真实姓名 -->
|
||||||
|
<div class="form-item">
|
||||||
|
<div class="flex items-center gap-2 mb-2">
|
||||||
|
<ion-icon :icon="personOutline" class="text-lg text-primary" />
|
||||||
|
<label class="form-label">真实姓名</label>
|
||||||
|
</div>
|
||||||
|
<ion-item lines="none" class="input-item">
|
||||||
|
<ion-input
|
||||||
|
v-model="formData.realName"
|
||||||
|
type="text"
|
||||||
|
placeholder="请输入真实姓名"
|
||||||
|
class="custom-input"
|
||||||
|
/>
|
||||||
|
</ion-item>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 身份证号码 -->
|
||||||
|
<div class="form-item">
|
||||||
|
<div class="flex items-center gap-2 mb-2">
|
||||||
|
<ion-icon :icon="cardOutline" class="text-lg text-primary" />
|
||||||
|
<label class="form-label">身份证号码</label>
|
||||||
|
</div>
|
||||||
|
<ion-item lines="none" class="input-item">
|
||||||
|
<ion-input
|
||||||
|
v-model="formData.idCard"
|
||||||
|
type="text"
|
||||||
|
placeholder="请输入身份证号码"
|
||||||
|
class="custom-input"
|
||||||
|
:maxlength="18"
|
||||||
|
/>
|
||||||
|
</ion-item>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 身份证正面 -->
|
||||||
|
<div class="form-item">
|
||||||
|
<div class="flex items-center gap-2 mb-2">
|
||||||
|
<ion-icon :icon="cardOutline" class="text-lg text-primary" />
|
||||||
|
<label class="form-label">身份证正面</label>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="upload-box"
|
||||||
|
@click="showImageSourceOptions('front')"
|
||||||
|
>
|
||||||
|
<div v-if="!formData.idCardFrontImage" class="upload-placeholder">
|
||||||
|
<ion-icon :icon="cameraOutline" class="text-4xl text-[#999]" />
|
||||||
|
<div class="text-sm text-[#999] mt-2">
|
||||||
|
点击拍照或选择照片
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-[#bbb] mt-1">
|
||||||
|
请上传人像面
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<img
|
||||||
|
v-else
|
||||||
|
:src="formData.idCardFrontImage"
|
||||||
|
alt="身份证正面"
|
||||||
|
class="uploaded-image"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 身份证反面 -->
|
||||||
|
<div class="form-item">
|
||||||
|
<div class="flex items-center gap-2 mb-2">
|
||||||
|
<ion-icon :icon="cardOutline" class="text-lg text-primary" />
|
||||||
|
<label class="form-label">身份证反面</label>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="upload-box"
|
||||||
|
@click="showImageSourceOptions('back')"
|
||||||
|
>
|
||||||
|
<div v-if="!formData.idCardBackImage" class="upload-placeholder">
|
||||||
|
<ion-icon :icon="cameraOutline" class="text-4xl text-[#999]" />
|
||||||
|
<div class="text-sm text-[#999] mt-2">
|
||||||
|
点击拍照或选择照片
|
||||||
|
</div>
|
||||||
|
<div class="text-xs text-[#bbb] mt-1">
|
||||||
|
请上传国徽面
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<img
|
||||||
|
v-else
|
||||||
|
:src="formData.idCardBackImage"
|
||||||
|
alt="身份证反面"
|
||||||
|
class="uploaded-image"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 提交按钮 -->
|
||||||
|
<ion-button
|
||||||
|
expand="block"
|
||||||
|
class="submit-button"
|
||||||
|
:disabled="isSubmitting"
|
||||||
|
@click="handleSubmit"
|
||||||
|
>
|
||||||
|
<ion-spinner v-if="isSubmitting" name="crescent" />
|
||||||
|
<span v-else>提交认证</span>
|
||||||
|
</ion-button>
|
||||||
|
|
||||||
|
<!-- 注意事项 -->
|
||||||
|
<div class="notice-card">
|
||||||
|
<div class="text-sm font-semibold text-[#333] mb-2">
|
||||||
|
注意事项:
|
||||||
|
</div>
|
||||||
|
<ul class="text-xs text-[#666] space-y-1 pl-4">
|
||||||
|
<li>• 请确保身份证照片清晰完整,信息可见</li>
|
||||||
|
<li>• 身份证必须在有效期内</li>
|
||||||
|
<li>• 一个身份证只能认证一个账号</li>
|
||||||
|
<li>• 认证信息提交后将无法修改</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ion-content>
|
||||||
|
</ion-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang='css' scoped>
|
||||||
|
.info-card {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 16px;
|
||||||
|
background: linear-gradient(135deg, #fff5f5 0%, #ffffff 100%);
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid #ffe0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-label {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-item {
|
||||||
|
--background: #f7f8fa;
|
||||||
|
--border-radius: 12px;
|
||||||
|
--padding-start: 16px;
|
||||||
|
--padding-end: 16px;
|
||||||
|
--min-height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-input {
|
||||||
|
--placeholder-color: #999;
|
||||||
|
--placeholder-opacity: 1;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-box {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
aspect-ratio: 16/10;
|
||||||
|
background: #f7f8fa;
|
||||||
|
border: 2px dashed #ddd;
|
||||||
|
border-radius: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-box:active {
|
||||||
|
transform: scale(0.98);
|
||||||
|
border-color: var(--ion-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-placeholder {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uploaded-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-button {
|
||||||
|
--background: linear-gradient(135deg, #c41e3a 0%, #8b1a2e 100%);
|
||||||
|
--background-activated: linear-gradient(135deg, #8b1a2e 0%, #c41e3a 100%);
|
||||||
|
--border-radius: 12px;
|
||||||
|
--padding-top: 14px;
|
||||||
|
--padding-bottom: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 16px;
|
||||||
|
margin-top: 8px;
|
||||||
|
text-transform: none;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-card {
|
||||||
|
background: #f9fafb;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 16px;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-card ul li {
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
87
src/views/settings/index.vue
Normal file
87
src/views/settings/index.vue
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<script lang='ts' setup>
|
||||||
|
import { callOutline, cardOutline, keyOutline, personOutline } from "ionicons/icons";
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const { userProfile } = storeToRefs(userStore);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ion-page>
|
||||||
|
<ion-header class="ion-no-border">
|
||||||
|
<ion-toolbar class="ion-toolbar">
|
||||||
|
<back-button slot="start" />
|
||||||
|
<ion-title>个人设置</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
|
||||||
|
<ion-content class="ion-padding">
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="space-y-4">
|
||||||
|
<!-- UID -->
|
||||||
|
<div class="info-item">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<ion-icon :icon="keyOutline" class="text-xl text-primary" />
|
||||||
|
<span class="label">用户UID</span>
|
||||||
|
</div>
|
||||||
|
<span class="value">{{ userProfile?.uid || '-' }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 姓名 -->
|
||||||
|
<div class="info-item">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<ion-icon :icon="personOutline" class="text-xl text-primary" />
|
||||||
|
<span class="label">真实姓名</span>
|
||||||
|
</div>
|
||||||
|
<span class="value">{{ userProfile?.fullName || '-' }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 手机号 -->
|
||||||
|
<div class="info-item">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<ion-icon :icon="callOutline" class="text-xl text-primary" />
|
||||||
|
<span class="label">手机号码</span>
|
||||||
|
</div>
|
||||||
|
<span class="value">{{ userProfile?.user.username || '-' }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 身份证号 -->
|
||||||
|
<div class="info-item">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<ion-icon :icon="cardOutline" class="text-xl text-primary" />
|
||||||
|
<span class="label">身份证号</span>
|
||||||
|
</div>
|
||||||
|
<span class="value">{{ (userProfile as any)?.idCard || '-' }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ion-content>
|
||||||
|
</ion-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang='css' scoped>
|
||||||
|
.card {
|
||||||
|
background: linear-gradient(180deg, #ffeef1, #ffffff 15%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
font-size: 15px;
|
||||||
|
color: #666;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user