修改完成待测试

This commit is contained in:
2026-09-13 17:45:47 +08:00
parent 9ad572907b
commit bbc024f7f2
80 changed files with 3844 additions and 1672 deletions
+60 -188
View File
@@ -79,36 +79,6 @@
</view>
</view>
<view class="profile-metadata" aria-label="个人资料摘要">
<view class="profile-metadata__item">
<image
class="profile-metadata__icon"
src="/static/assets/modules/profile/transparent/icon-person.png"
mode="aspectFit"
aria-hidden="true"
/>
<view><text>性别</text><text class="app-single-line">{{ sexText }}</text></view>
</view>
<view class="profile-metadata__item">
<image
class="profile-metadata__icon"
src="/static/assets/modules/profile/transparent/icon-calendar.png"
mode="aspectFit"
aria-hidden="true"
/>
<view><text>生日</text><text class="app-single-line">{{ birthdayText }}</text></view>
</view>
<view class="profile-metadata__item profile-metadata__item--email">
<image
class="profile-metadata__icon"
src="/static/assets/modules/profile/transparent/icon-envelope.png"
mode="aspectFit"
aria-hidden="true"
/>
<view><text>邮箱</text><text class="app-long-value">{{ profile.email || "未设置" }}</text></view>
</view>
</view>
<view class="profile-preference" aria-label="个性化推荐设置">
<view>
<text>个性化推荐</text>
@@ -165,9 +135,12 @@
</view>
</view>
</view>
<HomeAdvertisementPanel
class="profile-home-advertisements"
@open="openContentHome"
/>
</template>
<AppPromotionStrip v-if="!loading && !profileHomeError" placement="profile_bottom" title="为你推荐" />
<AppTabbar active="profile" />
</view>
</template>
@@ -177,18 +150,16 @@ import { computed, reactive, ref } from "vue";
import { onPageScroll, onShow, onUnload } from "@dcloudio/uni-app";
import AppAvatar from "@/components/AppAvatar.vue";
import AppButton from "@/components/AppButton.vue";
import AppPromotionStrip from "@/components/AppPromotionStrip.vue";
import AppTabbar from "@/components/AppTabbar.vue";
import {
PROFILE_SEX_OPTIONS
} from "@/services/api/profile-contract.js";
import HomeAdvertisementPanel from "@/components/genealogy/HomeAdvertisementPanel.vue";
import {
createRequestController,
isRequestCancelled
} from "@/services/api/request-controller.js";
import { profileApi } from "@/services/api/profile-service.js";
import { getRequestErrorMessage } from "@/services/api/request-error-message.js";
import { openPage } from "@/utils/navigation/gateway.js";
import { goRoot, openPage } from "@/utils/navigation/gateway.js";
import { genealogyContext } from "@/utils/genealogy/context.js";
const profile = reactive({
avatarFile: null,
@@ -211,84 +182,46 @@ const preferenceSaving = ref(false);
const preferenceError = ref("");
let isPageActive = true;
const serviceGroups = [
{
title: "账户与服务",
items: [
{
routeKey: "M03",
label: "账号与安全",
iconVariant: "security",
icon: "/static/assets/modules/profile/transparent/icon-security.png",
},
{
routeKey: "N01",
label: "消息中心",
iconVariant: "notifications",
icon: "/static/assets/modules/profile/transparent/icon-message.png",
},
{
routeKey: "M11",
label: "活动邀请",
iconVariant: "invitations",
icon: "/static/assets/modules/profile/transparent/icon-message.png",
},
{
routeKey: "M09",
label: "VIP 服务",
iconVariant: "vip",
icon: "/static/assets/modules/profile/transparent/icon-vip.png",
},
{
routeKey: "M12",
label: "收益与提现",
iconVariant: "earnings",
icon: "/static/assets/modules/profile/transparent/icon-vip.png",
},
],
},
const profileIcons = Object.freeze({
security: "/static/assets/modules/profile/transparent/icon-security.png",
notifications: "/static/assets/modules/profile/transparent/icon-message.png",
vip: "/static/assets/modules/profile/transparent/icon-vip.png",
help: "/static/assets/modules/profile/transparent/icon-help.png",
feedback: "/static/assets/modules/profile/transparent/icon-feedback.png",
settings: "/static/assets/modules/profile/transparent/icon-settings.png",
});
const serviceItem = (routeKey, label, iconVariant, params = null) => ({
routeKey,
label,
iconVariant,
icon: profileIcons[iconVariant],
...(params ? { params } : {}),
});
const serviceGroups = Object.freeze([
{
title: "支持与其他",
items: [
serviceItem("M06", "帮助中心", "help"),
serviceItem("M07", "意见反馈", "feedback"),
serviceItem("M03", "账号与安全", "security"),
serviceItem("M10", "关于与设置", "settings"),
serviceItem("F13", "网站公告", "notifications", {
title: "网站公告",
articleType: "notice",
}),
serviceItem("F13", "家谱新闻列表(图文)", "feedback", {
title: "家谱新闻",
articleType: "news",
}),
{
routeKey: "M06",
label: "帮助中心",
iconVariant: "help",
icon: "/static/assets/modules/profile/transparent/icon-help.png",
},
{
routeKey: "M07",
label: "意见反馈",
iconVariant: "feedback",
icon: "/static/assets/modules/profile/transparent/icon-feedback.png",
},
{
routeKey: "M08",
label: "应用推广",
iconVariant: "promotion",
icon: "/static/assets/modules/profile/transparent/icon-promotion.png",
},
{
routeKey: "M10",
label: "关于与设置",
iconVariant: "settings",
icon: "/static/assets/modules/profile/transparent/icon-settings.png",
...serviceItem("F04", "家谱系列文章(图文)", "feedback"),
requiresGenealogy: true,
},
],
},
];
const profileSexLabels = Object.freeze(
Object.fromEntries(PROFILE_SEX_OPTIONS.map(({ value, label }) => [value, label])),
);
const sexText = computed(
() => profileSexLabels[String(profile.sex)] || "未设置",
);
const birthdayText = computed(() =>
/^\d{4}-\d{2}-\d{2}/.test(profile.birthday)
? profile.birthday.slice(0, 10)
: "未设置",
);
]);
const loadProfile = async () => {
if (loading.value) return;
@@ -341,9 +274,21 @@ const changeRecommendationPreference = async (event) => {
}
};
const openService = (item) => openPage(item.routeKey, {}, "M01");
const openService = (item) => {
const params = { ...(item.params || {}) };
if (item.requiresGenealogy) {
const genealogyId = genealogyContext.getCurrentGenealogyId();
if (!genealogyId) {
uni.showToast({ title: "请先在家谱页选择家谱", icon: "none" });
return Promise.resolve(false);
}
params.genealogyId = genealogyId;
}
return openPage(item.routeKey, params, "M01");
};
const openEdit = () => openPage("M02", {}, "M01");
const openSettings = () => openPage("M10", {}, "M01");
const openContentHome = () => goRoot("F01");
onShow(() => {
void loadProfile();
@@ -352,13 +297,14 @@ onShow(() => {
onPageScroll(({ scrollTop = 0 }) => {
compactHeader.value = scrollTop > 44;
});
onUnload(() => {
const disposeProfilePortal = () => {
isPageActive = false;
compactHeader.value = false;
profileReadController.abort();
preferenceReadController.abort();
preferenceSaveController.abort();
});
};
onUnload(disposeProfilePortal);
</script>
<style scoped lang="scss">
@@ -611,68 +557,6 @@ onUnload(() => {
border: 0;
}
.profile-metadata {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
z-index: 1;
margin: -36rpx 34rpx 0;
padding: 10rpx 12rpx 12rpx;
border: 1rpx solid rgba(117, 83, 52, 0.09);
border-radius: 18rpx;
background: rgba(239, 234, 224, 0.92);
}
.profile-metadata__item {
display: flex;
min-width: 0;
align-items: flex-start;
gap: 12rpx;
padding: 14rpx 12rpx;
border-right: 0;
}
.profile-metadata__item:first-child {
border-right: 1rpx solid rgba(117, 83, 52, 0.16);
}
.profile-metadata__item--email {
grid-column: 1 / -1;
border-top: 1rpx solid rgba(117, 83, 52, 0.16);
}
.profile-metadata__icon {
width: 56rpx;
height: 56rpx;
flex: 0 0 auto;
filter: sepia(0.7) saturate(0.8) hue-rotate(330deg) brightness(0.82);
}
.profile-metadata__item view {
min-width: 0;
}
.profile-metadata__item text {
display: block;
}
.profile-metadata__item text:first-child {
color: #857263;
font-size: clamp(13px, 20rpx, 16px);
}
.profile-metadata__item text:last-child {
margin-top: 4rpx;
color: #382c25;
font-size: clamp(15px, 24rpx, 18px);
line-height: 1.25;
overflow-wrap: anywhere;
}
.profile-metadata__item--email text:last-child {
font-size: clamp(13px, 20rpx, 16px);
line-height: 1.35;
}
.profile-preference {
display: flex;
align-items: center;
@@ -717,6 +601,10 @@ onUnload(() => {
margin: 49rpx 58rpx 0 48rpx;
}
.profile-home-advertisements {
margin: 28rpx 24rpx 0;
}
.profile-service-group + .profile-service-group {
margin-top: 51rpx;
}
@@ -825,22 +713,6 @@ onUnload(() => {
height: 176rpx;
}
.profile-metadata {
grid-template-columns: minmax(0, 1fr);
}
.profile-metadata__item:first-child {
border-right: 0;
}
.profile-metadata__item + .profile-metadata__item {
border-top: 1rpx solid rgba(117, 83, 52, 0.16);
}
.profile-metadata__item--email {
grid-column: auto;
}
.profile-services {
margin-right: 38rpx;
margin-left: 38rpx;
+20 -3
View File
@@ -23,9 +23,15 @@
<AppButton compact type="secondary" label="重试" @click="loadReferralProfile" />
</view>
<view v-else-if="referralProfile.enabled" class="referral-card__content">
<text class="referral-card__code">{{ referralProfile.referralCode }}</text>
<text>已成功邀请 {{ referralProfile.referredUserCount }} </text>
<text>{{ referralProfile.shareDescription || "家人通过此链接注册后,系统会记录推荐关系。" }}</text>
<view class="referral-card__details">
<ReferralQrCode :value="referralProfile.shareUrl" />
<view class="referral-card__copy">
<text class="referral-card__code">{{ referralProfile.referralCode }}</text>
<text>已成功邀请 {{ referralProfile.referredUserCount }} </text>
<text>{{ referralProfile.shareDescription || "家人通过此链接注册后,系统会记录推荐关系。" }}</text>
<text class="referral-card__qr-hint">请家人扫码打开注册链接</text>
</view>
</view>
<view class="referral-card__actions">
<AppButton compact type="secondary" label="复制推荐码" @click="copyReferralCode" />
<AppButton compact type="secondary" label="复制推荐链接" @click="copyReferralLink" />
@@ -83,6 +89,7 @@ import AppButton from "@/components/AppButton.vue";
import AppLoading from "@/components/AppLoading.vue";
import ModulePageBackground from "@/components/ModulePageBackground.vue";
import PageHeader from "@/components/PageHeader.vue";
import ReferralQrCode from "@/components/ReferralQrCode.vue";
import {
createRequestController,
isRequestCancelled
@@ -318,7 +325,12 @@ onUnload(() => {
.referral-card__state > text { margin-top: 8rpx; color: $ink-muted; font-size: clamp(13px, 22rpx, 16px); line-height: 1.55; }
.referral-card__content,
.referral-card__state { margin-top: 22rpx; }
.referral-card__details { display: flex; align-items: center; gap: 24rpx; }
.referral-card__copy { min-width: 0; flex: 1; }
.referral-card__copy > text { display: block; }
.referral-card__copy > text:not(:first-child) { margin-top: 8rpx; }
.referral-card__code { color: #9e251b; font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: clamp(22px, 40rpx, 30px); font-weight: 700; letter-spacing: 3rpx; }
.referral-card__qr-hint { color: $brand-red; font-size: clamp(13px, 21rpx, 16px); }
.referral-card__actions { display: flex; flex-wrap: wrap; justify-content: flex-end; margin-top: 22rpx; gap: 12rpx; }
.referral-card__actions .app-button { width: auto; min-width: 150rpx; }
.promotion-state-card .app-button { margin-top: 28rpx; }
@@ -353,5 +365,10 @@ onUnload(() => {
min-width: 0;
flex: 1 1 220rpx;
}
.referral-card__details {
flex-direction: column;
align-items: flex-start;
}
}
</style>