完成70%
This commit is contained in:
@@ -1,429 +1,11 @@
|
||||
<!-- 页面编号:M-01;用途:个人中心首页、提醒与服务导航。 -->
|
||||
<!-- 页面编号:M-01;用途:个人中心。资料 DTO 未声明时不展示 mock 用户。 -->
|
||||
<template>
|
||||
<view
|
||||
class="profile-page"
|
||||
:class="{
|
||||
'profile-state--ready': profileState === 'ready',
|
||||
'profile-state--error': profileState === 'error',
|
||||
}"
|
||||
>
|
||||
<ModulePageBackground module="profile" />
|
||||
<view class="profile-page__header">
|
||||
<PageHeader
|
||||
root
|
||||
title="我的"
|
||||
:action="profileState === 'ready' ? '资料' : ''"
|
||||
@action="toProfile"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="profile-content">
|
||||
<template v-if="profileState === 'ready'">
|
||||
<view class="profile-hero">
|
||||
<image
|
||||
class="profile-hero__hall"
|
||||
src="/static/assets/foundation/transparent/root-header-hall.png"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<image
|
||||
class="profile-hero__cloud"
|
||||
src="/static/assets/foundation/transparent/auth-title-cloud.png"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<view class="profile-hero__content">
|
||||
<view class="profile-hero__label"
|
||||
><text>个</text><text>人</text><text>谱</text><text>牒</text></view
|
||||
>
|
||||
<view class="profile-identity">
|
||||
<image
|
||||
class="profile-identity__seal"
|
||||
src="/static/assets/foundation/transparent/brand-seal.png"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<view class="profile-identity__copy">
|
||||
<text class="profile-identity__name">{{ currentUser.name }}</text>
|
||||
<text class="profile-identity__role">{{ currentUser.role }}</text>
|
||||
<text class="profile-identity__phone">{{ currentUser.phone }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="profile-scroll-notice"
|
||||
role="button"
|
||||
aria-label="查看待处理消息"
|
||||
@click="toNotifications"
|
||||
>
|
||||
<view class="profile-scroll-notice__copy">
|
||||
<text>待你处理</text>
|
||||
<text>{{ unreadCount }} 条家谱提醒与审核通知</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="profile-services">
|
||||
<view class="profile-section-heading">
|
||||
<image
|
||||
src="/static/assets/foundation/transparent/auth-divider-knot.png"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<text>服务与设置</text>
|
||||
<image
|
||||
src="/static/assets/foundation/transparent/auth-divider-knot.png"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
</view>
|
||||
<view class="profile-menu-list">
|
||||
<view
|
||||
v-for="item in menuItems"
|
||||
:key="item.label"
|
||||
class="profile-menu"
|
||||
role="button"
|
||||
:aria-label="`查看${item.label}`"
|
||||
@click="openItem(item)"
|
||||
>
|
||||
<image
|
||||
class="profile-menu__icon"
|
||||
:src="item.icon"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<view class="profile-menu__copy">
|
||||
<text class="profile-menu__label">{{ item.label }}</text>
|
||||
<text class="profile-menu__note">{{ item.note }}</text>
|
||||
</view>
|
||||
<image
|
||||
class="profile-menu__chevron"
|
||||
src="/static/assets/foundation/transparent/chevron-right.png"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<view v-else class="profile-error">
|
||||
<view class="profile-error__copy">
|
||||
<text class="profile-error__title">个人资料暂不可用</text>
|
||||
<text class="profile-error__description"
|
||||
>请稍后重新进入,账号和家谱资料不会受到影响。</text
|
||||
>
|
||||
</view>
|
||||
<AppButton
|
||||
block
|
||||
type="secondary"
|
||||
label="重新查看"
|
||||
@click="restoreProfile"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<AppTabbar active="profile" />
|
||||
</view>
|
||||
<view class="profile-page"><ModulePageBackground module="profile" /><view class="page-header"><PageHeader root title="我的" /></view><view class="page-content"><view class="state-card"><text>个人资料待后端字段合同</text><text>当前资料读取接口只返回通用对象,未声明昵称、角色、手机号或脱敏规则;页面已停止展示 mock 用户与 fixture 未读数。</text><view class="profile-menu"><AppButton block label="编辑资料" @click="open('M02')" /><AppButton block label="账号与安全" @click="open('M03')" /><AppButton block label="消息中心" @click="open('N01')" /><AppButton block label="帮助中心" @click="open('M06')" /><AppButton block label="意见反馈" @click="open('M07')" /><AppButton block label="应用推广" @click="open('M08')" /><AppButton block label="VIP 服务" @click="open('M09')" /><AppButton block label="关于与设置" @click="open('M10')" /></view></view></view><AppTabbar active="profile" /></view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref } from "vue";
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import AppButton from "@/components/AppButton.vue";
|
||||
import AppTabbar from "@/components/AppTabbar.vue";
|
||||
import ModulePageBackground from "@/components/ModulePageBackground.vue";
|
||||
import PageHeader from "@/components/PageHeader.vue";
|
||||
import {
|
||||
currentUser,
|
||||
listNotificationFixtures,
|
||||
} from "@/data/mock.js";
|
||||
import { openPage } from "@/utils/navigation.js";
|
||||
|
||||
const profileState = ref("ready");
|
||||
const unreadCount = computed(
|
||||
() => listNotificationFixtures().filter((notice) => notice.unread).length,
|
||||
);
|
||||
const menuItems = [
|
||||
{
|
||||
label: "账号与安全",
|
||||
note: "密码与手机号",
|
||||
icon: "/static/assets/modules/auth/transparent/a01-icon-lock-v1.png",
|
||||
routeKey: "M03",
|
||||
},
|
||||
{
|
||||
label: "帮助与反馈",
|
||||
note: "使用说明与问题反馈",
|
||||
icon: "/static/assets/foundation/transparent/notice.png",
|
||||
routeKey: "M06",
|
||||
},
|
||||
{
|
||||
label: "关于家谱",
|
||||
note: "协议、隐私与版本",
|
||||
icon: "/static/assets/foundation/transparent/brand-seal.png",
|
||||
routeKey: "M10",
|
||||
},
|
||||
{
|
||||
label: "邀请家人",
|
||||
note: "邀请规则与接入状态",
|
||||
icon: "/static/assets/foundation/transparent/brand-seal.png",
|
||||
routeKey: "M08",
|
||||
},
|
||||
{
|
||||
label: "服务与订单",
|
||||
note: "权益说明与订单记录",
|
||||
icon: "/static/assets/foundation/transparent/notice.png",
|
||||
routeKey: "M09",
|
||||
},
|
||||
];
|
||||
|
||||
onLoad((query) => {
|
||||
profileState.value = query.state === "error" ? "error" : "ready";
|
||||
});
|
||||
|
||||
const restoreProfile = () => {
|
||||
profileState.value = "ready";
|
||||
};
|
||||
const toProfile = () => openPage("M02", {}, "M01");
|
||||
const toNotifications = () => openPage("N01", {}, "M01");
|
||||
const openItem = (item) =>
|
||||
item.routeKey ? openPage(item.routeKey, {}, "M01") : Promise.resolve(false);
|
||||
import AppButton from "@/components/AppButton.vue"; import AppTabbar from "@/components/AppTabbar.vue"; import ModulePageBackground from "@/components/ModulePageBackground.vue"; import PageHeader from "@/components/PageHeader.vue"; import { openPage } from "@/utils/navigation.js"; const open=(route)=>openPage(route,{},"M01");
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "../../styles/adaptive-frame-profiles.scss" as adaptive;
|
||||
|
||||
.profile-page {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
flex-direction: column;
|
||||
background: $paper;
|
||||
}
|
||||
.profile-page__header,
|
||||
.profile-content {
|
||||
z-index: 1;
|
||||
}
|
||||
.profile-content {
|
||||
flex: 1;
|
||||
padding: 26rpx 30rpx 190rpx;
|
||||
}
|
||||
.profile-hero {
|
||||
@include adaptive.adaptive-profile-summary;
|
||||
display: grid;
|
||||
width: 100%;
|
||||
min-height: 252rpx;
|
||||
}
|
||||
.profile-hero__content {
|
||||
z-index: 1;
|
||||
display: grid;
|
||||
grid-area: 1 / 1;
|
||||
grid-template-columns: 42rpx minmax(0, 1fr);
|
||||
align-items: center;
|
||||
gap: 30rpx;
|
||||
padding: 34rpx 52rpx 32rpx 40rpx;
|
||||
}
|
||||
.profile-hero__hall {
|
||||
align-self: end;
|
||||
justify-self: end;
|
||||
grid-area: 1 / 1;
|
||||
width: 330rpx;
|
||||
height: 122rpx;
|
||||
margin-right: -18rpx;
|
||||
margin-bottom: -30rpx;
|
||||
opacity: 0.12;
|
||||
pointer-events: none;
|
||||
}
|
||||
.profile-hero__cloud {
|
||||
align-self: start;
|
||||
justify-self: end;
|
||||
grid-area: 1 / 1;
|
||||
width: 96rpx;
|
||||
height: 52rpx;
|
||||
margin-top: 22rpx;
|
||||
margin-right: 30rpx;
|
||||
opacity: 0.32;
|
||||
pointer-events: none;
|
||||
}
|
||||
.profile-hero__label {
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
width: 42rpx;
|
||||
min-height: 152rpx;
|
||||
box-sizing: border-box;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 2rpx solid #c9964c;
|
||||
border-radius: 4rpx;
|
||||
background: linear-gradient(180deg, #9f241f, #bd3427);
|
||||
box-shadow: inset 0 0 0 3rpx rgba(255, 222, 147, 0.24);
|
||||
color: #ffe6a9;
|
||||
font-family: STKaiti, KaiTi, serif;
|
||||
font-size: 21rpx;
|
||||
line-height: 1.12;
|
||||
}
|
||||
.profile-identity {
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
min-height: 252rpx;
|
||||
box-sizing: border-box;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
}
|
||||
.profile-identity__seal {
|
||||
width: 92rpx;
|
||||
height: 106rpx;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.profile-identity__name,
|
||||
.profile-identity__role,
|
||||
.profile-identity__phone {
|
||||
display: block;
|
||||
}
|
||||
.profile-identity__name {
|
||||
color: $ink;
|
||||
font-family: STKaiti, KaiTi, serif;
|
||||
font-size: 38rpx;
|
||||
font-weight: 700;
|
||||
letter-spacing: 3rpx;
|
||||
}
|
||||
.profile-identity__role {
|
||||
margin-top: 10rpx;
|
||||
color: #6f5942;
|
||||
font-size: 23rpx;
|
||||
}
|
||||
.profile-identity__phone {
|
||||
margin-top: 7rpx;
|
||||
color: $ink-muted;
|
||||
font-size: 21rpx;
|
||||
letter-spacing: 2rpx;
|
||||
}
|
||||
.profile-scroll-notice {
|
||||
@include adaptive.adaptive-scroll-button(primary);
|
||||
width: 88%;
|
||||
min-height: 112rpx;
|
||||
margin: 22rpx auto 0;
|
||||
}
|
||||
.profile-scroll-notice__copy {
|
||||
display: flex;
|
||||
min-height: 112rpx;
|
||||
box-sizing: border-box;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 13rpx 70rpx;
|
||||
color: #fff4d3;
|
||||
text-align: center;
|
||||
}
|
||||
.profile-scroll-notice__copy text:first-child {
|
||||
font-family: STKaiti, KaiTi, serif;
|
||||
font-size: 26rpx;
|
||||
font-weight: 700;
|
||||
letter-spacing: 3rpx;
|
||||
}
|
||||
.profile-scroll-notice__copy text:last-child {
|
||||
margin-top: 4rpx;
|
||||
color: #ffe4a8;
|
||||
font-size: 18rpx;
|
||||
}
|
||||
.profile-services {
|
||||
margin-top: 26rpx;
|
||||
padding: 0 12rpx;
|
||||
}
|
||||
.profile-section-heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 20rpx;
|
||||
padding-bottom: 12rpx;
|
||||
}
|
||||
.profile-section-heading image {
|
||||
width: 88rpx;
|
||||
height: 28rpx;
|
||||
opacity: 0.78;
|
||||
}
|
||||
.profile-section-heading image:last-child {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
.profile-section-heading text {
|
||||
color: $ink;
|
||||
font-family: STKaiti, KaiTi, serif;
|
||||
font-size: 31rpx;
|
||||
font-weight: 700;
|
||||
letter-spacing: 4rpx;
|
||||
}
|
||||
.profile-menu-list {
|
||||
border-top: 1px solid rgba(181, 137, 63, 0.55);
|
||||
}
|
||||
.profile-menu {
|
||||
display: flex;
|
||||
min-height: 116rpx;
|
||||
align-items: center;
|
||||
padding: 0 8rpx;
|
||||
border-bottom: 1px solid rgba(181, 137, 63, 0.4);
|
||||
}
|
||||
.profile-menu__icon {
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
margin-right: 22rpx;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.profile-menu__copy {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
.profile-menu__label,
|
||||
.profile-menu__note {
|
||||
display: block;
|
||||
}
|
||||
.profile-menu__label {
|
||||
color: $ink;
|
||||
font-size: 25rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.profile-menu__note {
|
||||
margin-top: 5rpx;
|
||||
color: $ink-muted;
|
||||
font-size: 21rpx;
|
||||
}
|
||||
.profile-menu__chevron {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
margin-left: 18rpx;
|
||||
opacity: 0.75;
|
||||
}
|
||||
.profile-error {
|
||||
margin-top: 38rpx;
|
||||
background: url("/static/assets/modules/profile/transparent/m01-profile-summary-card.png") top center / 100% 220rpx no-repeat;
|
||||
text-align: center;
|
||||
}
|
||||
.profile-error__copy {
|
||||
display: flex;
|
||||
min-height: 118px;
|
||||
box-sizing: border-box;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 54rpx;
|
||||
}
|
||||
.profile-error__title,
|
||||
.profile-error__description {
|
||||
display: block;
|
||||
}
|
||||
.profile-error__title {
|
||||
color: $ink;
|
||||
font-family: STKaiti, KaiTi, serif;
|
||||
font-size: 31rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.profile-error__description {
|
||||
margin-top: 13rpx;
|
||||
color: $ink-muted;
|
||||
font-size: 23rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.profile-error .app-button {
|
||||
margin: 20rpx auto 0;
|
||||
}
|
||||
@media (min-width: 400px) {
|
||||
.profile-content {
|
||||
padding-right: 38rpx;
|
||||
padding-left: 38rpx;
|
||||
}
|
||||
}
|
||||
/* M01 medium-ornate profile folio styles remain page-scoped and extensible. */
|
||||
.profile-page{display:flex;min-height:100vh;flex-direction:column;background:$paper}.page-header,.page-content{z-index:1}.page-content{flex:1;padding:18rpx 24rpx 190rpx}.state-card{box-sizing:border-box;min-height:340rpx;padding:52rpx 40rpx 50rpx;text-align:center;@include adaptive.adaptive-family-content}.state-card text{display:block}.state-card text:first-child{color:$ink;font-family:STKaiti,KaiTi,serif;font-size:35rpx;font-weight:700}.state-card text:nth-child(2){margin-top:18rpx;color:$ink-muted;font-size:24rpx;line-height:1.65}.profile-menu{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14rpx;margin-top:28rpx}.profile-menu .app-button{margin:0}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user