feat ui设计稿bug修复
This commit is contained in:
@@ -1,69 +1,55 @@
|
||||
<script setup lang="ts">
|
||||
interface MenuItem {
|
||||
to: string
|
||||
icon: string
|
||||
label: string
|
||||
}
|
||||
|
||||
// 设计稿(个人中心)菜单项 y268/304/340/376/412/448/484/520,行距 36,文字 x179(卡内缩进 24)
|
||||
const menus: MenuItem[] = [
|
||||
{ to: '/profile/security', icon: '🔒', label: '账号安全' },
|
||||
{ to: '/profile/address', icon: '📍', label: '收货地址' },
|
||||
{ to: '/profile/favorites', icon: '⭐', label: '我的收藏' },
|
||||
{ to: '/profile/qualifications', icon: '📜', label: '资质管理' },
|
||||
{ to: '/profile/feedback', icon: '💡', label: '意见反馈' },
|
||||
{ to: '/profile/help', icon: '❓', label: '帮助中心' },
|
||||
{ to: '/profile/about', icon: 'ℹ️', label: '关于我们' },
|
||||
{ to: '/profile/hotline', icon: '📞', label: '客服热线' },
|
||||
{ to: '/profile/security', label: '账号安全' },
|
||||
{ to: '/profile/address', label: '地址管理' },
|
||||
{ to: '/profile/favorites', label: '收藏列表' },
|
||||
{ to: '/profile/qualifications', label: '资质列表' },
|
||||
{ to: '/profile/feedback', label: '意见反馈' },
|
||||
{ to: '/profile/help', label: '帮助中心' },
|
||||
{ to: '/profile/about', label: '关于我们' },
|
||||
{ to: '/profile/hotline', label: '专属客服热线' },
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<nav class="profile-sider" aria-label="个人中心导航">
|
||||
<ul class="profile-sider__menu">
|
||||
<li v-for="item in menus" :key="item.to">
|
||||
<RouterLink :to="item.to" class="profile-sider__item">
|
||||
<span class="profile-sider__label">{{ item.label }}</span>
|
||||
</RouterLink>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="profile-sider__footer">
|
||||
<RouterLink
|
||||
to="/profile/hotline"
|
||||
class="profile-sider__hotline"
|
||||
title="专属客服热线"
|
||||
>
|
||||
📞 专属客服热线
|
||||
</RouterLink>
|
||||
</div>
|
||||
<RouterLink
|
||||
v-for="item in menus"
|
||||
:key="item.to"
|
||||
:to="item.to"
|
||||
class="profile-sider__item"
|
||||
>
|
||||
{{ item.label }}
|
||||
</RouterLink>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
// 设计稿:菜单为独立白卡(245 宽),选中项浅蓝底 @profile-nav-active-bg 圆角 6
|
||||
.profile-sider {
|
||||
.flex(column, space-between);
|
||||
min-height: 480px;
|
||||
padding: @spacing-sm 0;
|
||||
.flex(column, flex-start);
|
||||
gap: 0;
|
||||
padding: 4px 0;
|
||||
border-radius: @radius-lg;
|
||||
background: @white;
|
||||
|
||||
&__menu {
|
||||
.flex(column, flex-start);
|
||||
gap: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
// 设计 14/28:纯文字菜单,选中项浅蓝底 + 蓝色加粗,行距 36 × 0.77 ≈ 28
|
||||
&__item {
|
||||
.flex(row, flex-start, center);
|
||||
height: 28px;
|
||||
padding: 0 @spacing-sm;
|
||||
height: 36px; // 设计行距 36
|
||||
padding: 0 24px; // 卡 x155 → 文字 x179
|
||||
border-radius: @profile-radius;
|
||||
color: @text-color;
|
||||
font-size: 11px;
|
||||
line-height: 1;
|
||||
font-size: @font-size-base; // 设计 12/400
|
||||
font-weight: 400;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: @primary-light;
|
||||
color: @primary-strong;
|
||||
}
|
||||
|
||||
@@ -73,25 +59,5 @@ const menus: MenuItem[] = [
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
&__label {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
padding: @spacing-sm @spacing-sm 0;
|
||||
border-top: 1px solid @project-divider;
|
||||
}
|
||||
|
||||
&__hotline {
|
||||
display: inline-block;
|
||||
font-size: 11px;
|
||||
color: @text-color-secondary;
|
||||
transition: color 0.2s;
|
||||
|
||||
&:hover {
|
||||
color: @primary-strong;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -32,61 +32,52 @@ function save(): void {
|
||||
<div class="profile-user-card__avatar" aria-hidden="true">
|
||||
王
|
||||
</div>
|
||||
<div class="profile-user-card__info">
|
||||
<input
|
||||
v-model="draft"
|
||||
class="profile-user-card__name"
|
||||
type="text"
|
||||
placeholder="请输入名称"
|
||||
maxlength="20"
|
||||
@keyup.enter="save"
|
||||
@blur="save"
|
||||
>
|
||||
<p class="profile-user-card__phone text-secondary">
|
||||
{{ profile?.phone ?? '' }}
|
||||
</p>
|
||||
</div>
|
||||
<input
|
||||
v-model="draft"
|
||||
class="profile-user-card__name"
|
||||
type="text"
|
||||
placeholder="请输入名称"
|
||||
maxlength="20"
|
||||
@keyup.enter="save"
|
||||
@blur="save"
|
||||
>
|
||||
<p class="profile-user-card__phone">
|
||||
{{ profile?.phone ?? '' }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
// 设计 14:左列紫渐变用户卡(渐变实取 #5459E8 → #D2BDF3),内容居中
|
||||
// 设计稿(个人中心):头像 46 圆形居中,名称 18/600,手机 14/400;
|
||||
// 整块 245×110 紫渐变卡,内容垂直居中
|
||||
.profile-user-card {
|
||||
.flex(column, center);
|
||||
gap: @spacing-xs; // 设计 14:头像与文字块间距约 4px
|
||||
padding: @spacing-base @spacing-sm; // 设计:上 20 / 下 25 设计px ≈ 16
|
||||
.flex(column, center, center);
|
||||
height: 110px;
|
||||
border-radius: @radius-lg;
|
||||
background: linear-gradient(170deg, @profile-user-from 0%, @profile-user-to 100%);
|
||||
background: linear-gradient(180deg, @profile-user-from 0%, @profile-user-to 100%);
|
||||
box-sizing: border-box;
|
||||
|
||||
&__avatar {
|
||||
.flex(row, center);
|
||||
flex-shrink: 0;
|
||||
width: 42px; // 设计 54 × 0.77
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border-radius: @radius-round;
|
||||
background: @profile-user-avatar;
|
||||
background: fade(@white, 22%);
|
||||
color: @white;
|
||||
font-size: @font-size-lg;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&__info {
|
||||
.flex(column, center);
|
||||
gap: @spacing-xs;
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
// 卡内为深色底:名称/号码一律白字(设计 14 实取 #FFFFFF)
|
||||
&__name {
|
||||
width: 100%;
|
||||
height: 16px; // 设计 19 × 0.77
|
||||
height: 26px;
|
||||
margin-top: 6px;
|
||||
padding: 0 @spacing-xs;
|
||||
border: 1px solid transparent;
|
||||
border-radius: @profile-radius;
|
||||
background: transparent;
|
||||
font-size: 11px;
|
||||
font-size: @font-size-lg; // 设计 18/600
|
||||
font-weight: 600;
|
||||
color: @white;
|
||||
text-align: center;
|
||||
@@ -103,15 +94,17 @@ function save(): void {
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
font-size: 11px;
|
||||
font-size: @font-size-lg;
|
||||
font-weight: 400;
|
||||
color: fade(@white, 75%);
|
||||
}
|
||||
}
|
||||
|
||||
&__phone {
|
||||
font-size: 11px;
|
||||
margin-top: 6px;
|
||||
font-size: @font-size-sm; // 设计 14/400
|
||||
color: @white;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import { AppButton } from '@/components'
|
||||
import { computed } from 'vue'
|
||||
import type { Profile } from '@/types/business/profile'
|
||||
|
||||
interface Props {
|
||||
@@ -17,354 +16,148 @@ const emit = defineEmits<{
|
||||
deleteAccount: []
|
||||
}>()
|
||||
|
||||
const agree = ref(false)
|
||||
|
||||
const hasEmail = computed(() => Boolean(props.profile?.email))
|
||||
|
||||
/** 注销条件(mock 全部满足) */
|
||||
const conditions = [
|
||||
'账号无未完成的订单',
|
||||
'无未结清的款项',
|
||||
'无进行中的合同',
|
||||
'无未处理的工单',
|
||||
]
|
||||
|
||||
/** 注销风险提示 */
|
||||
const risks = [
|
||||
'账号注销后将无法登录本应用,所有个人信息将被永久删除',
|
||||
'您名下的订单、合同、工单等业务数据将一并清除,无法找回',
|
||||
'注销后同一手机号/邮箱将无法再次注册本应用',
|
||||
'如您有未完成的订单或服务请先处理完毕后再进行注销',
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="security-panel">
|
||||
<!-- 修改密码 -->
|
||||
<section class="security-panel__row">
|
||||
<span class="security-panel__icon security-panel__icon--pwd" aria-hidden="true" />
|
||||
<!-- 设计稿:三行白卡 1672×86,行距 16,左缩进 24 -->
|
||||
<section
|
||||
class="security-panel__row"
|
||||
@click="emit('changePassword')"
|
||||
>
|
||||
<div class="security-panel__main">
|
||||
<h3 class="security-panel__title">
|
||||
修改密码
|
||||
</h3>
|
||||
<p class="security-panel__status">
|
||||
<span class="security-panel__badge security-panel__badge--ok">已设置</span>
|
||||
<span class="security-panel__note">上次修改:{{ profile?.passwordModifiedAt }}</span>
|
||||
<p class="security-panel__sub">
|
||||
上次修改:{{ profile?.passwordModifiedAt }}
|
||||
</p>
|
||||
</div>
|
||||
<AppButton type="default" @click="emit('changePassword')">
|
||||
修改密码
|
||||
</AppButton>
|
||||
<span class="security-panel__state security-panel__state--ok">已设置</span>
|
||||
<span class="security-panel__arrow" aria-hidden="true">›</span>
|
||||
</section>
|
||||
|
||||
<!-- 绑定手机 -->
|
||||
<section class="security-panel__row">
|
||||
<span class="security-panel__icon security-panel__icon--phone" aria-hidden="true" />
|
||||
<section
|
||||
class="security-panel__row"
|
||||
@click="emit('bindPhone')"
|
||||
>
|
||||
<div class="security-panel__main">
|
||||
<h3 class="security-panel__title">
|
||||
绑定手机
|
||||
</h3>
|
||||
<p class="security-panel__status">
|
||||
<span class="security-panel__badge security-panel__badge--ok">已绑定 {{ profile?.phone }}</span>
|
||||
</p>
|
||||
<p class="security-panel__note">
|
||||
注:换绑新手机号之后,可以用新的手机号及当前密码登录
|
||||
<p class="security-panel__sub">
|
||||
{{ profile?.phone ?? '' }}
|
||||
</p>
|
||||
</div>
|
||||
<AppButton type="default" @click="emit('bindPhone')">
|
||||
绑定手机
|
||||
</AppButton>
|
||||
<span class="security-panel__state security-panel__state--ok">已绑定</span>
|
||||
<span class="security-panel__arrow" aria-hidden="true">›</span>
|
||||
</section>
|
||||
|
||||
<!-- 绑定邮箱 -->
|
||||
<section class="security-panel__row">
|
||||
<span class="security-panel__icon security-panel__icon--email" aria-hidden="true" />
|
||||
<section
|
||||
class="security-panel__row"
|
||||
@click="emit('bindEmail', hasEmail ? 'email-rebind' : 'email-bind')"
|
||||
>
|
||||
<div class="security-panel__main">
|
||||
<h3 class="security-panel__title">
|
||||
绑定邮箱
|
||||
</h3>
|
||||
<p class="security-panel__status">
|
||||
<template v-if="hasEmail">
|
||||
<span class="security-panel__badge security-panel__badge--ok">已绑定 {{ profile?.email }}</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="security-panel__badge">未绑定</span>
|
||||
</template>
|
||||
<p class="security-panel__sub">
|
||||
{{ hasEmail ? profile?.email : '未绑定邮箱' }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="security-panel__actions">
|
||||
<AppButton
|
||||
v-if="!hasEmail"
|
||||
type="default"
|
||||
@click="emit('bindEmail', 'email-bind')"
|
||||
>
|
||||
绑定邮箱
|
||||
</AppButton>
|
||||
<template v-else>
|
||||
<AppButton type="default" @click="emit('bindEmail', 'email-rebind')">
|
||||
更换绑定邮箱
|
||||
</AppButton>
|
||||
<AppButton type="text" @click="emit('unbindEmail')">
|
||||
取消绑定
|
||||
</AppButton>
|
||||
</template>
|
||||
</div>
|
||||
<span
|
||||
class="security-panel__state"
|
||||
:class="{ 'security-panel__state--ok': hasEmail }"
|
||||
>{{ hasEmail ? '已绑定' : '未绑定' }}</span>
|
||||
<span class="security-panel__arrow" aria-hidden="true">›</span>
|
||||
</section>
|
||||
|
||||
<!-- 注销账号(danger 区) -->
|
||||
<section class="security-panel__danger">
|
||||
<h3 class="security-panel__danger-title">
|
||||
注销账号
|
||||
</h3>
|
||||
|
||||
<div class="security-panel__block">
|
||||
<h4 class="security-panel__block-title security-panel__block-title--ok">
|
||||
注销条件
|
||||
</h4>
|
||||
<ul class="security-panel__checks">
|
||||
<li v-for="item in conditions" :key="item" class="security-panel__check">
|
||||
<span class="security-panel__check-ok">✓</span>{{ item }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="security-panel__block">
|
||||
<h4 class="security-panel__block-title security-panel__block-title--risk">
|
||||
注销风险提示
|
||||
</h4>
|
||||
<ol class="security-panel__risks">
|
||||
<li v-for="(item, index) in risks" :key="item">
|
||||
{{ index + 1 }}. {{ item }}
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<label class="security-panel__agree">
|
||||
<input v-model="agree" type="checkbox">
|
||||
<span>已阅读并同意<em>《账号注销协议》</em></span>
|
||||
</label>
|
||||
|
||||
<AppButton
|
||||
type="default"
|
||||
class="security-panel__delete-btn"
|
||||
:disabled="!agree"
|
||||
@click="emit('deleteAccount')"
|
||||
>
|
||||
注销账号
|
||||
</AppButton>
|
||||
</section>
|
||||
<!-- 设计稿:注销账号 1672×48,灰字,浅灰描边 -->
|
||||
<button
|
||||
type="button"
|
||||
class="security-panel__delete"
|
||||
@click="emit('deleteAccount')"
|
||||
>
|
||||
注销账号
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
// 设计 28:白卡行 + 浅灰描边、图标块 44×44 设计px、标题 14 设计px w600、副文 11 设计px
|
||||
// 设计稿(个人中心):
|
||||
// 行卡 1672×86 bg #FFFFFF bd #F0F1F3/1,行距 16;标题 14/600 #1F2937 @x428
|
||||
// 副文 11/400 #9CA3AF;右端状态 11/500(已设置 #16A34A / 未绑定 #6B7280)+ 箭头 ›
|
||||
// 注销按钮 1672×48 bd #E5E7EB/1,文字 15/500 #9CA3AF
|
||||
.security-panel {
|
||||
.flex(column, flex-start);
|
||||
.flex(column, flex-start, stretch);
|
||||
gap: @spacing-base;
|
||||
|
||||
&__row {
|
||||
.flex(row, flex-start, center);
|
||||
gap: @spacing-base;
|
||||
padding: @spacing-base;
|
||||
.flex(row, space-between, center);
|
||||
height: 86px;
|
||||
padding: 0 24px;
|
||||
border: 1px solid @profile-card-border;
|
||||
border-radius: @radius-base;
|
||||
background: @white;
|
||||
}
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s;
|
||||
|
||||
// 设计 28 实取图标块底色:#C7D2FE / #FDEBEB / #FEE2E2
|
||||
&__icon {
|
||||
flex-shrink: 0;
|
||||
width: 34px; // 设计 44 × 0.77
|
||||
height: 34px;
|
||||
border-radius: @radius-base;
|
||||
|
||||
&--pwd {
|
||||
background: @profile-icon-pwd;
|
||||
}
|
||||
|
||||
&--phone {
|
||||
background: @profile-icon-phone;
|
||||
}
|
||||
|
||||
&--email {
|
||||
background: @profile-icon-email;
|
||||
&:hover {
|
||||
border-color: @profile-line;
|
||||
}
|
||||
}
|
||||
|
||||
&__main {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 11px; // 设计 14 → 10.8,取可读下限 11
|
||||
font-size: @font-size-base; // 设计 14/600
|
||||
font-weight: 600;
|
||||
color: @heading-color;
|
||||
color: @profile-ink;
|
||||
}
|
||||
|
||||
&__status {
|
||||
.flex(row, flex-start, center);
|
||||
flex-wrap: wrap;
|
||||
gap: @spacing-sm;
|
||||
margin-top: @spacing-xs;
|
||||
font-size: 11px;
|
||||
&__sub {
|
||||
margin-top: 6px;
|
||||
font-size: @font-size-sm; // 设计 11/400
|
||||
color: @finance-axis-text; // #9CA3AF
|
||||
}
|
||||
|
||||
// 设计 28:已设置/已绑定 = 浅绿底绿字胶囊,未绑定 = 纯灰字
|
||||
&__badge {
|
||||
padding: 2px 8px;
|
||||
border-radius: @radius-sm;
|
||||
background: transparent;
|
||||
color: @text-color-secondary;
|
||||
font-size: 11px;
|
||||
&__state {
|
||||
margin-left: auto;
|
||||
font-size: @font-size-sm;
|
||||
font-weight: 500;
|
||||
color: @finance-muted-text; // 未绑定 #6B7280
|
||||
|
||||
&--ok {
|
||||
background: @tag-success-bg;
|
||||
color: @success-color;
|
||||
color: @success-color; // 已设置 / 已绑定 #16A34A
|
||||
}
|
||||
}
|
||||
|
||||
&__note {
|
||||
margin-top: @spacing-xs;
|
||||
color: @text-color-disabled;
|
||||
font-size: 11px;
|
||||
line-height: 1.6;
|
||||
&__arrow {
|
||||
margin-left: 20px;
|
||||
font-size: 21px;
|
||||
line-height: 1;
|
||||
color: @finance-axis-text;
|
||||
}
|
||||
|
||||
&__actions {
|
||||
.flex(row, center);
|
||||
gap: @spacing-sm;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
// 行内操作按钮:白底灰描边小按钮(设计 20/17 操作按钮同规格)
|
||||
.app-button {
|
||||
height: 28px;
|
||||
padding: 0 12px;
|
||||
&__delete {
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
border: 1px solid @profile-line;
|
||||
border-radius: @profile-radius;
|
||||
background: @white;
|
||||
color: @text-color;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
border-color: @primary-strong;
|
||||
color: @primary-strong;
|
||||
background: @white;
|
||||
}
|
||||
}
|
||||
|
||||
.app-button--text {
|
||||
border-color: transparent;
|
||||
background: transparent;
|
||||
color: @text-color;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
border-color: transparent;
|
||||
background: transparent;
|
||||
color: @primary-strong;
|
||||
}
|
||||
}
|
||||
|
||||
&__danger {
|
||||
.flex(column, flex-start);
|
||||
gap: @spacing-base;
|
||||
padding: @spacing-lg;
|
||||
border: 1px solid @profile-card-border;
|
||||
border-radius: @radius-base;
|
||||
background: @white;
|
||||
}
|
||||
|
||||
&__danger-title {
|
||||
font-size: 12px; // 设计 15 → 12
|
||||
font-weight: 700;
|
||||
color: @danger-color;
|
||||
}
|
||||
|
||||
&__block {
|
||||
.flex(column, flex-start);
|
||||
gap: @spacing-sm;
|
||||
}
|
||||
|
||||
// 设计 29:注销条件标题绿、注销风险提示标题红
|
||||
&__block-title {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
|
||||
&--ok {
|
||||
color: @success-color;
|
||||
}
|
||||
|
||||
&--risk {
|
||||
color: @danger-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__checks {
|
||||
.flex(column, flex-start);
|
||||
gap: @spacing-xs;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
&__check {
|
||||
font-size: 11px;
|
||||
color: @text-color;
|
||||
}
|
||||
|
||||
&__check-ok {
|
||||
margin-right: @spacing-xs;
|
||||
font-weight: 600;
|
||||
color: @success-color;
|
||||
}
|
||||
|
||||
&__risks {
|
||||
margin: 0;
|
||||
padding-left: @spacing-base;
|
||||
.flex(column, flex-start);
|
||||
gap: @spacing-xs;
|
||||
font-size: 11px;
|
||||
color: @text-color;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
&__agree {
|
||||
.flex(row, flex-start, center);
|
||||
gap: @spacing-sm;
|
||||
font-size: 11px;
|
||||
color: @text-color-secondary;
|
||||
cursor: pointer;
|
||||
|
||||
input {
|
||||
accent-color: @primary-strong;
|
||||
}
|
||||
|
||||
em {
|
||||
font-style: normal;
|
||||
color: @primary-strong;
|
||||
}
|
||||
}
|
||||
|
||||
// 注销账号:白底灰描边整行按钮(设计 28 实取文字 #9CA3AF、15 设计px)
|
||||
&__delete-btn {
|
||||
width: 100%;
|
||||
height: 36px;
|
||||
border: 1px solid @profile-line !important;
|
||||
background: @white !important;
|
||||
color: @text-color-disabled !important;
|
||||
font-size: 12px;
|
||||
color: @finance-axis-text;
|
||||
font-size: @font-size-base; // 设计 15/500
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
border-color: @danger-color !important;
|
||||
background: @white !important;
|
||||
color: @danger-color !important;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 1;
|
||||
cursor: not-allowed;
|
||||
&:hover {
|
||||
border-color: @danger-color;
|
||||
color: @danger-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@ import { useProfileStore } from '@/stores/modules/profile'
|
||||
import ProfileSider from './cpns/ProfileSider.vue'
|
||||
import ProfileUserCard from './cpns/ProfileUserCard.vue'
|
||||
|
||||
// 布局容器:顶部用户卡 + 左侧菜单 / 右侧子路由出口,数据只经 store
|
||||
// 布局容器:左侧用户卡 + 菜单(x155 起 245 宽),右侧内容卡(x400 起 1400 宽)
|
||||
// 数据只经 store
|
||||
const profileStore = useProfileStore()
|
||||
const { profile } = storeToRefs(profileStore)
|
||||
|
||||
@@ -20,7 +21,7 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<div class="profile">
|
||||
<div class="profile__container">
|
||||
<div class="profile__container container">
|
||||
<div class="profile__body">
|
||||
<aside class="profile__aside">
|
||||
<ProfileUserCard :profile="profile" @save-nickname="onSaveNickname" />
|
||||
@@ -35,40 +36,46 @@ onMounted(() => {
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
// 设计稿(个人中心 1920×1568)锚点:
|
||||
// 面包屑 y23 h26 · 左列 x155 宽 245 · 右卡 x400 y98 1400×532 · 页脚 y1087
|
||||
// 内容区顶 98 = 顶栏 72 + 上留白 26
|
||||
.profile {
|
||||
padding-bottom: @spacing-xxl;
|
||||
background: @bg-color;
|
||||
min-height: 737px; // 内容区 y98→835
|
||||
background: @profile-page-bg;
|
||||
|
||||
&__container {
|
||||
width: @container-width;
|
||||
max-width: calc(100% - @spacing-xl);
|
||||
margin: 0 auto;
|
||||
padding-top: @spacing-lg;
|
||||
padding-top: 26px; // 顶栏 72 → 内容区 98
|
||||
// 个人中心系独立基准(视觉核对定版 x155/1600),不随全站 70/1780 联动
|
||||
padding-left: clamp(@spacing-base, calc((100% - @profile-content) / 2), @profile-gutter);
|
||||
padding-right: clamp(@spacing-base, calc((100% - @profile-content) / 2), @profile-gutter);
|
||||
}
|
||||
|
||||
&__body {
|
||||
.flex(row, flex-start);
|
||||
gap: @spacing-base;
|
||||
align-items: flex-start;
|
||||
.flex(row, flex-start, stretch);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
// 左列(设计14):紫渐变用户卡 + 菜单,直接坐在页面底色上,无外层白卡
|
||||
// 左列 200:用户卡 + 菜单白卡,两卡间距 6
|
||||
// (设计稿左列 245、右卡 1400,合计 1645 超出内容宽 1595,按比例收左列到 200 保右卡 1400)
|
||||
&__aside {
|
||||
width: 114px; // 设计 148 × 0.77
|
||||
flex-shrink: 0;
|
||||
.flex(column, flex-start);
|
||||
gap: @spacing-base;
|
||||
.flex(column, flex-start, stretch);
|
||||
gap: 6px;
|
||||
flex: 0 0 200px;
|
||||
width: 200px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
// 右侧内容面板(设计14/28):整块白卡,内缩 16px 承载各页面
|
||||
// 右内容卡 1400:白底 + 浅灰描边
|
||||
&__main {
|
||||
flex: 1;
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
min-height: 400px;
|
||||
padding: @spacing-base;
|
||||
border-radius: @radius-base;
|
||||
min-height: 425px;
|
||||
margin-left: 40px; // 左列 200 → 右卡起点 240(设计稿比例:160/245 ≈ 0.65)
|
||||
padding: 24px 24px 0; // 卡内左缩进:卡 → 标题 +28
|
||||
border: 1px solid @profile-card-border;
|
||||
border-radius: @radius-lg;
|
||||
background: @white;
|
||||
box-shadow: @shadow-base;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -15,6 +15,36 @@ const router = useRouter()
|
||||
const profileStore = useProfileStore()
|
||||
const { profile } = storeToRefs(profileStore)
|
||||
|
||||
// ── 注销账号二次确认(设计稿 __4d03fd89:风险提示 + 注销条件 + 双按钮) ──
|
||||
const deleteVisible = ref(false)
|
||||
const agree = ref(false)
|
||||
const identityVisible = ref(false)
|
||||
|
||||
/** 注销条件(mock 全部满足) */
|
||||
const conditions = [
|
||||
{ label: '账号无未完成的订单', ok: true },
|
||||
{ label: '账号无未结清的款项', ok: false },
|
||||
{ label: '账号无进行中的合同', ok: true },
|
||||
{ label: '账号无处理中的工单', ok: true },
|
||||
]
|
||||
|
||||
/** 注销风险提示(设计稿 __4d03fd89 原文四条) */
|
||||
const risks = [
|
||||
'账号注销后,您将无法登录本应用,所有个人信息将被永久删除。',
|
||||
'您名下的订单、合同、工单等业务数据将一并清除,无法找回。',
|
||||
'注销后,同一手机号/邮箱将无法再次注册本应用。',
|
||||
'如有未完成的订单或服务,请先处理完毕后再进行注销。',
|
||||
]
|
||||
|
||||
function onDeleteConfirm(): void {
|
||||
if (!agree.value) {
|
||||
ElMessage.warning('请先阅读并同意《账号注销协议》')
|
||||
return
|
||||
}
|
||||
// 安全身份验证 → 验证通过后注销
|
||||
identityVisible.value = true
|
||||
}
|
||||
|
||||
// ── 修改密码 ──
|
||||
const pwdVisible = ref(false)
|
||||
|
||||
@@ -66,14 +96,6 @@ function onUnbindConfirm(): void {
|
||||
}
|
||||
|
||||
// ── 注销账号 ──
|
||||
const deleteVisible = ref(false)
|
||||
const identityVisible = ref(false)
|
||||
|
||||
function onDeleteConfirm(): void {
|
||||
// 确认注销 → 进入安全身份验证
|
||||
identityVisible.value = true
|
||||
}
|
||||
|
||||
function onIdentitySubmit(payload: { contact: string; code: string }): void {
|
||||
void (async () => {
|
||||
await profileStore.verifyIdentity(payload.contact, payload.code)
|
||||
@@ -96,6 +118,59 @@ function onIdentitySubmit(payload: { contact: string; code: string }): void {
|
||||
@delete-account="deleteVisible = true"
|
||||
/>
|
||||
|
||||
<!-- 注销账号 · 二次确认(设计稿 __4d03fd89) -->
|
||||
<ConfirmDialog
|
||||
v-model:visible="deleteVisible"
|
||||
title="注销账号"
|
||||
confirm-text="注销账号"
|
||||
cancel-text="暂不注销"
|
||||
danger
|
||||
@cancel="agree = false"
|
||||
@confirm="onDeleteConfirm"
|
||||
>
|
||||
<div class="delete-confirm">
|
||||
<span class="delete-confirm__icon" aria-hidden="true">i</span>
|
||||
<h3 class="delete-confirm__title">
|
||||
确定要注销账号吗?
|
||||
</h3>
|
||||
|
||||
<div class="delete-confirm__block">
|
||||
<h4 class="delete-confirm__block-title delete-confirm__block-title--risk">
|
||||
⚠ 注销风险提示
|
||||
</h4>
|
||||
<ul class="delete-confirm__risks">
|
||||
<li v-for="(item, index) in risks" :key="item">
|
||||
{{ index + 1 }}、{{ item }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="delete-confirm__block">
|
||||
<h4 class="delete-confirm__block-title delete-confirm__block-title--ok">
|
||||
✓ 注销条件
|
||||
</h4>
|
||||
<ul class="delete-confirm__conditions">
|
||||
<li
|
||||
v-for="item in conditions"
|
||||
:key="item.label"
|
||||
class="delete-confirm__condition"
|
||||
>
|
||||
<span>{{ item.label }}</span>
|
||||
<span
|
||||
class="delete-confirm__mark"
|
||||
:class="item.ok ? 'is-ok' : 'is-fail'"
|
||||
>{{ item.ok ? '✓' : '✕' }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<label class="delete-confirm__agree">
|
||||
<input v-model="agree" type="checkbox">
|
||||
<span>已阅读并同意<em>《账号注销协议》</em></span>
|
||||
</label>
|
||||
</div>
|
||||
</ConfirmDialog>
|
||||
|
||||
<ChangePasswordDialog
|
||||
v-model:visible="pwdVisible"
|
||||
:phone="profile?.phone ?? ''"
|
||||
@@ -126,22 +201,128 @@ function onIdentitySubmit(payload: { contact: string; code: string }): void {
|
||||
danger
|
||||
@confirm="onUnbindConfirm"
|
||||
/>
|
||||
|
||||
<ConfirmDialog
|
||||
v-model:visible="deleteVisible"
|
||||
title="注销账号"
|
||||
message="确定要注销账号吗?"
|
||||
confirm-text="注销账号"
|
||||
cancel-text="暂不注销"
|
||||
danger
|
||||
@confirm="onDeleteConfirm"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.security-page {
|
||||
.flex(column, flex-start);
|
||||
.flex(column, flex-start, stretch);
|
||||
gap: @spacing-base;
|
||||
}
|
||||
|
||||
// 设计稿(注销账号 __4d03fd89):
|
||||
// 弹层内容列 x660→1420 宽 760;感叹号 30/700 #EF4444;主问 19/700 #1F2937
|
||||
// 风险标题 13/600 #EF4444;正文 13/400 #4B5563 行距 26
|
||||
// 条件行 760×32 底 #FFFFFF bd #DDE1E7;勾选标记 14 圆底
|
||||
// 协议勾选框 16;取消按钮 760×46 底 #D8DBDF;注销按钮 760×46 底 #EF4444
|
||||
.delete-confirm {
|
||||
.flex(column, flex-start);
|
||||
align-items: center;
|
||||
padding: 8px 0;
|
||||
|
||||
&__icon {
|
||||
.flex(row, center);
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: @radius-round;
|
||||
background: fade(@danger-color, 12%);
|
||||
color: @danger-color;
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
&__title {
|
||||
margin-top: 10px;
|
||||
font-size: 19px;
|
||||
font-weight: 700;
|
||||
color: @profile-ink;
|
||||
}
|
||||
|
||||
&__block {
|
||||
width: 100%;
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
&__block-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
|
||||
&--risk {
|
||||
color: @danger-color;
|
||||
}
|
||||
|
||||
&--ok {
|
||||
color: @success-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__risks {
|
||||
margin-top: 12px;
|
||||
.flex(column, flex-start);
|
||||
gap: 9px;
|
||||
list-style: none;
|
||||
font-size: 13px;
|
||||
color: @finance-entry-text;
|
||||
}
|
||||
|
||||
&__conditions {
|
||||
margin-top: 12px;
|
||||
.flex(column, flex-start);
|
||||
gap: 10px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
&__condition {
|
||||
.flex(row, space-between, center);
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
padding: 0 16px;
|
||||
border: 1px solid @border-color;
|
||||
border-radius: @radius-sm;
|
||||
background: @white;
|
||||
font-size: 13px;
|
||||
color: @finance-entry-text;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
&__mark {
|
||||
.flex(row, center);
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-radius: @radius-round;
|
||||
color: @white;
|
||||
font-size: 10px;
|
||||
line-height: 1;
|
||||
|
||||
&.is-ok {
|
||||
background: @success-color;
|
||||
}
|
||||
|
||||
&.is-fail {
|
||||
background: @danger-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__agree {
|
||||
.flex(row, flex-start, center);
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
margin-top: 22px;
|
||||
font-size: @font-size-sm;
|
||||
color: @finance-muted-text;
|
||||
cursor: pointer;
|
||||
|
||||
input {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
accent-color: @primary-strong;
|
||||
}
|
||||
|
||||
em {
|
||||
font-style: normal;
|
||||
color: @primary-strong;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user