ow
This commit is contained in:
1 parent
b5d2a2ede0
commit
aff58692bb
17 files changed
+1851
-240
No files matched your search
@@ -113,9 +113,53 @@ async function onRetry(): Promise<void> {
|
||||
const data = ref<FamilyTreeData>(new FamilyTreeData());
|
||||
const tree = computed(() => data.value.FamilyTree);
|
||||
const currentPerson = computed(() => data.value.CurrentPerson?.FamilyPerson);
|
||||
/** 当前族员显示名(旧系统同款:姓+谱名连写) */
|
||||
const currentPersonName = computed(() => {
|
||||
const p = currentPerson.value;
|
||||
return p ? `${p.Surname ?? ""}${p.GenealogyName ?? ""}` : "";
|
||||
});
|
||||
const spouseMaps = computed(() => data.value.CurrentPerson?.FamilyTreeSpouseMaps ?? []);
|
||||
const childMaps = computed(() => data.value.CurrentPerson?.FamilyTreeChildrenMaps ?? []);
|
||||
|
||||
/** 关系行头像查表:Spouse/Children 视图字段不带头像,回查全族人员档案拿 AvatarUrl(谱系图 getAvatar 同款口径) */
|
||||
function personAvatar(personId?: string): string {
|
||||
if (!personId) {
|
||||
return "";
|
||||
}
|
||||
const persons = (data.value.CurrentPerson?.FamilyTreePersons ?? []) as any[];
|
||||
return persons.find(p => p?.PersonId === personId)?.AvatarUrl ?? "";
|
||||
}
|
||||
|
||||
/** 谱系图同款性别判定(family-tree-chart isMale 字面一致):空性别按男兜底 */
|
||||
function genderIsMale(gender?: string): boolean {
|
||||
if (!gender) {
|
||||
return true;
|
||||
}
|
||||
const label = getPolicyText("GenderPolicy", gender).toLowerCase();
|
||||
return label.includes("男") || label.includes("male") || gender === "M" || gender === "1";
|
||||
}
|
||||
|
||||
/** 关系对方性别回查:关系视图的 Gender 是记录拥有者(丈夫/父亲)的字段(谱系图配色踩过的坑),优先拿对方档案真值 */
|
||||
function personGender(personId?: string, fallback?: string): string {
|
||||
if (!personId) {
|
||||
return fallback ?? "";
|
||||
}
|
||||
const persons = (data.value.CurrentPerson?.FamilyTreePersons ?? []) as any[];
|
||||
return persons.find(p => p?.PersonId === personId)?.Gender || fallback || "";
|
||||
}
|
||||
|
||||
/** 谱系图同款性别配色:男蓝 / 女粉 */
|
||||
function genderTheme(gender?: string): string {
|
||||
return genderIsMale(gender) ? "#1890ff" : "#eb2f96";
|
||||
}
|
||||
|
||||
/** 无头像时的占位圆样式:白底 + 性别同色描边(谱系图同款);有头像返回空不覆盖 */
|
||||
function avatarFallbackStyle(hasAvatar: boolean, gender?: string): Record<string, string> {
|
||||
return hasAvatar
|
||||
? {}
|
||||
: { backgroundColor: "#ffffff", border: `3rpx solid ${genderTheme(gender)}` };
|
||||
}
|
||||
|
||||
const treeId = ref("");
|
||||
const loaded = ref(false);
|
||||
const isEdit = ref(false);
|
||||
@@ -704,10 +748,10 @@ defineExpose({
|
||||
</view>
|
||||
<view class="tree-page__scroll-wrap">
|
||||
<scroll-view scroll-y class="tree-page__scroll">
|
||||
<!-- 头卡(与媒体/共享页同套):白底 + 主题浅底图标 + 编号灰字独立行 -->
|
||||
<!-- 头卡(与媒体/共享页同套):白底 + 族谱树图标(与列表卡同款渐变底白树形) + 编号灰字独立行 -->
|
||||
<view class="detail-hero">
|
||||
<view class="detail-hero__avatar">
|
||||
<u-icon name="account-fill" size="64" :color="primary" />
|
||||
<image class="detail-hero__glyph" :src="treeGlyph" mode="aspectFit" />
|
||||
</view>
|
||||
<view class="detail-hero__main">
|
||||
<text class="detail-hero__name">{{ tree.TreeName || t("FamilyTreePage.unnamed") }}</text>
|
||||
@@ -768,11 +812,13 @@ defineExpose({
|
||||
<textarea v-model="tree.Brief" class="detail-field__textarea" :disabled="!isEdit" :maxlength="1000"
|
||||
:placeholder="t('FamilyTreePage.noBrief')" />
|
||||
</view>
|
||||
<!-- 封面文件暂时不用,先隐藏(保留代码便于日后恢复)
|
||||
<view class="detail-field">
|
||||
<text class="detail-field__label">{{ t("FamilyTreePage.treeCover") }}</text>
|
||||
<input v-model="tree.TreeCoverFilename" class="detail-field__input" :disabled="!isEdit"
|
||||
:maxlength="255">
|
||||
</view>
|
||||
-->
|
||||
<view class="detail-field detail-field--row">
|
||||
<text class="detail-field__label">{{ t("FamilyTreePage.publicIndc") }}</text>
|
||||
<u-switch :model-value="tree.PublicIndc === 'Y'" :disabled="!isEdit" :active-color="primary"
|
||||
@@ -795,17 +841,28 @@ defineExpose({
|
||||
<u-icon :name="folded.person ? 'arrow-right' : 'arrow-down'" size="26" color="#8f959e" />
|
||||
</view>
|
||||
<view v-show="!folded.person">
|
||||
<view class="detail-field detail-field--row">
|
||||
<text class="detail-field__label">{{ t("FamilyTreePage.gender") }}</text>
|
||||
<text class="detail-field__value">{{ genderText(currentPerson?.Gender) || "-" }}</text>
|
||||
</view>
|
||||
<view class="detail-field detail-field--row">
|
||||
<text class="detail-field__label">{{ t("FamilyTreePage.genealogyName") }}</text>
|
||||
<text class="detail-field__value">{{ currentPerson?.GenealogyName || "-" }}</text>
|
||||
</view>
|
||||
<view class="detail-field detail-field--row">
|
||||
<text class="detail-field__label">{{ t("FamilyTreePage.commonName") }}</text>
|
||||
<text class="detail-field__value">{{ currentPerson?.CommonName || "-" }}</text>
|
||||
<!-- 头像行(旧系统同款):圆头像 + 名字带性别 + 编号芯片与常用名,无头像时灰底人形占位 -->
|
||||
<view class="person-hero">
|
||||
<view class="person-hero__avatar"
|
||||
:style="avatarFallbackStyle(!!currentPerson?.AvatarUrl, currentPerson?.Gender)">
|
||||
<image v-if="currentPerson?.AvatarUrl" class="person-hero__img" :src="currentPerson.AvatarUrl"
|
||||
mode="aspectFill" />
|
||||
<u-icon v-else name="account" size="56" :color="genderTheme(currentPerson?.Gender)" />
|
||||
</view>
|
||||
<view class="person-hero__main">
|
||||
<view class="person-hero__line">
|
||||
<text class="person-hero__name">{{ currentPersonName || "-" }}</text>
|
||||
<text class="person-hero__gender">{{ genderText(currentPerson?.Gender) || "-" }}</text>
|
||||
</view>
|
||||
<view class="person-hero__chips">
|
||||
<text v-if="currentPerson?.PersonId" class="person-hero__chip">
|
||||
<text v-if="currentPerson?.CommonName" class="person-hero__chip-name">
|
||||
{{ currentPerson.CommonName }}
|
||||
</text>
|
||||
{{ `${t("FamilyPersonPage.personId")}: ${currentPerson.PersonId}` }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="op-btns">
|
||||
<view class="op-btn" @tap="pickCurrentPerson">
|
||||
@@ -853,9 +910,28 @@ defineExpose({
|
||||
</view>
|
||||
<view v-for="(record, index) in spouseMaps" :key="record.SpouseId" class="rel-item">
|
||||
<view class="rel-head" @tap="expandedSpouses[record.SpouseId] = !expandedSpouses[record.SpouseId]">
|
||||
<!-- 当前族员同款:圆头像 + 名字带性别 + 芯片(常用名值+成员编号) -->
|
||||
<view class="rel-avatar"
|
||||
:style="avatarFallbackStyle(!!personAvatar(record.SpouseId), personGender(record.SpouseId, record.Gender))">
|
||||
<image v-if="personAvatar(record.SpouseId)" class="rel-avatar__img"
|
||||
:src="personAvatar(record.SpouseId)" mode="aspectFill" />
|
||||
<u-icon v-else name="account" size="40"
|
||||
:color="genderTheme(personGender(record.SpouseId, record.Gender))" />
|
||||
</view>
|
||||
<view class="rel-text">
|
||||
<text class="rel-name">{{ record.SpouseSurname }}{{ record.SpouseGenealogyName }}</text>
|
||||
<text class="rel-sub">{{ genderText(record.Gender) }}</text>
|
||||
<view class="person-hero__line">
|
||||
<text class="rel-name">{{ record.SpouseSurname }}{{ record.SpouseGenealogyName }}</text>
|
||||
<text class="person-hero__gender">{{ genderText(personGender(record.SpouseId, record.Gender))
|
||||
}}</text>
|
||||
</view>
|
||||
<view class="person-hero__chips">
|
||||
<text class="person-hero__chip">
|
||||
<text v-if="record.SpouseCommonName" class="person-hero__chip-name">
|
||||
{{ record.SpouseCommonName }}
|
||||
</text>
|
||||
{{ `${t("FamilyPersonPage.personId")}: ${record.SpouseId}` }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="rel-ops">
|
||||
<template v-if="isEdit">
|
||||
@@ -971,9 +1047,28 @@ defineExpose({
|
||||
<view v-for="(record, index) in childMaps" :key="record.ChildrenId" class="rel-item">
|
||||
<view class="rel-head"
|
||||
@tap="expandedChildren[record.ChildrenId] = !expandedChildren[record.ChildrenId]">
|
||||
<!-- 当前族员同款:圆头像 + 名字带性别 + 芯片(常用名值+成员编号) -->
|
||||
<view class="rel-avatar"
|
||||
:style="avatarFallbackStyle(!!personAvatar(record.ChildrenId), personGender(record.ChildrenId, record.Gender))">
|
||||
<image v-if="personAvatar(record.ChildrenId)" class="rel-avatar__img"
|
||||
:src="personAvatar(record.ChildrenId)" mode="aspectFill" />
|
||||
<u-icon v-else name="account" size="40"
|
||||
:color="genderTheme(personGender(record.ChildrenId, record.Gender))" />
|
||||
</view>
|
||||
<view class="rel-text">
|
||||
<text class="rel-name">{{ record.ChildrenSurname }}{{ record.ChildrenGenealogyName }}</text>
|
||||
<text class="rel-sub">{{ genderText(record.Gender) }}</text>
|
||||
<view class="person-hero__line">
|
||||
<text class="rel-name">{{ record.ChildrenSurname }}{{ record.ChildrenGenealogyName }}</text>
|
||||
<text class="person-hero__gender">{{ genderText(personGender(record.ChildrenId, record.Gender))
|
||||
}}</text>
|
||||
</view>
|
||||
<view class="person-hero__chips">
|
||||
<text class="person-hero__chip">
|
||||
<text v-if="record.ChildrenCommonName" class="person-hero__chip-name">
|
||||
{{ record.ChildrenCommonName }}
|
||||
</text>
|
||||
{{ `${t("FamilyPersonPage.personId")}: ${record.ChildrenId}` }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="rel-ops">
|
||||
<template v-if="isEdit">
|
||||
@@ -1035,7 +1130,10 @@ defineExpose({
|
||||
<u-icon :name="folded.perms ? 'arrow-right' : 'arrow-down'" size="26" color="#8f959e" />
|
||||
</view>
|
||||
<view v-show="!folded.perms">
|
||||
<text class="perm-section-label">{{ t("FamilyTreePage.permPending") }}</text>
|
||||
<view class="perm-section-head">
|
||||
<text class="perm-section-label">{{ t("FamilyTreePage.permPending") }}</text>
|
||||
<text class="perm-section-count">{{ pendingPermissions.length }}</text>
|
||||
</view>
|
||||
<view v-if="!pendingPermissions.length" class="detail-empty">
|
||||
<text>{{ t("FamilyTreePage.permEmpty") }}</text>
|
||||
</view>
|
||||
@@ -1057,7 +1155,11 @@ defineExpose({
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<text class="perm-section-label">{{ t("FamilyTreePage.permManager") }}</text>
|
||||
<view class="perm-divider" />
|
||||
<view class="perm-section-head">
|
||||
<text class="perm-section-label">{{ t("FamilyTreePage.permManager") }}</text>
|
||||
<text class="perm-section-count">{{ managerPermissions.length }}</text>
|
||||
</view>
|
||||
<view v-if="!managerPermissions.length" class="detail-empty">
|
||||
<text>{{ t("FamilyTreePage.permEmpty") }}</text>
|
||||
</view>
|
||||
@@ -1358,10 +1460,95 @@ defineExpose({
|
||||
width: 140rpx;
|
||||
height: 140rpx;
|
||||
border-radius: 32rpx;
|
||||
background-color: var(--fg-soft, #eaf4ff);
|
||||
background: var(--fg-gradient, linear-gradient(135deg, #4a9dff, #2b8fff));
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 树形字形(与列表卡同款内联 SVG data-URI) */
|
||||
.detail-hero__glyph {
|
||||
width: 84rpx;
|
||||
height: 84rpx;
|
||||
}
|
||||
|
||||
/* 当前族员头像行(旧系统 hero 同款):圆头像 + 名字 + 编号芯片 */
|
||||
.person-hero {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
|
||||
/* 上距标题 24rpx;下距分隔线由 .op-btns 的 margin-top(24rpx) 提供,两侧视觉等距 */
|
||||
padding: 24rpx 0 0;
|
||||
}
|
||||
|
||||
.person-hero__avatar {
|
||||
display: flex;
|
||||
flex: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 112rpx;
|
||||
height: 112rpx;
|
||||
overflow: hidden;
|
||||
background-color: var(--fg-soft, #eaf4ff);
|
||||
border: 4rpx solid #ffffff;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 4rpx 14rpx rgba(31, 35, 41, 0.12);
|
||||
}
|
||||
|
||||
.person-hero__img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.person-hero__main {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
flex-direction: column;
|
||||
gap: 10rpx;
|
||||
}
|
||||
|
||||
.person-hero__line {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: baseline;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.person-hero__name {
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: #1f2329;
|
||||
}
|
||||
|
||||
.person-hero__gender {
|
||||
font-size: 26rpx;
|
||||
color: #8f959e;
|
||||
}
|
||||
|
||||
.person-hero__chips {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.person-hero__chip {
|
||||
padding: 4rpx 18rpx;
|
||||
font-size: 22rpx;
|
||||
color: var(--fg-primary, #2b8fff);
|
||||
background-color: var(--fg-soft, #eaf4ff);
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
/* 芯片内的常用名值:排在编号前,同芯片浅底、深色字(旧系统同款合并位) */
|
||||
.person-hero__chip-name {
|
||||
margin-right: 24rpx;
|
||||
font-size: 24rpx;
|
||||
color: #1f2329;
|
||||
}
|
||||
|
||||
.detail-hero__main {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
@@ -1594,12 +1781,33 @@ defineExpose({
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
/* 关系行圆头像(当前族员同款缩小一号):档案无头像时灰底人形占位 */
|
||||
.rel-avatar {
|
||||
display: flex;
|
||||
flex: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
overflow: hidden;
|
||||
background-color: var(--fg-soft, #eaf4ff);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.rel-avatar__img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.rel-text {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.rel-name {
|
||||
@@ -1680,11 +1888,39 @@ defineExpose({
|
||||
}
|
||||
|
||||
/* ===== 权限维护行 ===== */
|
||||
/* 子标题分组头:加深字色 + 加粗 + 计数徽章,让分区标题清晰可辨(对齐参照图) */
|
||||
.perm-section-head {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
padding: 28rpx 0 8rpx;
|
||||
}
|
||||
|
||||
/* 第二分区(管理名单)上方的通栏分隔带:负外边距 bleed 到卡片左右边,色带用主题软底把白卡横向"切开";
|
||||
加 border-radius 让色带两端收圆角,圆角处透出白卡底,两分区过渡更柔和 */
|
||||
.perm-divider {
|
||||
height: 16rpx;
|
||||
margin: 28rpx -28rpx 0;
|
||||
background-color: var(--fg-soft, #f6efe8);
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
|
||||
.perm-section-label {
|
||||
display: block;
|
||||
padding: 24rpx 0 4rpx;
|
||||
font-size: 24rpx;
|
||||
color: #8f959e;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #1f2329;
|
||||
}
|
||||
|
||||
.perm-section-count {
|
||||
min-width: 34rpx;
|
||||
padding: 0 10rpx;
|
||||
font-size: 22rpx;
|
||||
line-height: 34rpx;
|
||||
color: var(--fg-primary, #2b8fff);
|
||||
text-align: center;
|
||||
background-color: var(--fg-soft, #eaf4ff);
|
||||
border-radius: 17rpx;
|
||||
}
|
||||
|
||||
.perm-row {
|
||||
|
||||
Reference in new issue
Block a user