完成40%

This commit is contained in:
rain
2026-07-23 17:21:27 +08:00
parent f1edc6b533
commit bb6431b319
114 changed files with 10931 additions and 877 deletions
+71 -57
View File
@@ -121,7 +121,7 @@
>
<view class="genealogy-lower">
<view v-if="createdGenealogies.length" class="list-section">
<view class="section-heading"><text>创建</text></view>
<view class="section-heading"><text>管理</text></view>
<GenealogyCard
v-for="item in createdGenealogies"
:key="item.id"
@@ -144,7 +144,10 @@
/>
</view>
<view class="list-section application-section">
<view
v-if="applicationRecords.length"
class="list-section application-section"
>
<view class="section-heading"><text>加入申请</text></view>
<view
v-for="item in applicationRecords"
@@ -350,7 +353,7 @@
<script setup>
import { computed, nextTick, ref } from "vue";
import { onBackPress, onLoad } from "@dcloudio/uni-app";
import { onBackPress, onLoad, onShow, onUnload } from "@dcloudio/uni-app";
import AppLoading from "@/components/AppLoading.vue";
import AppTabbar from "@/components/AppTabbar.vue";
import AppButton from "@/components/AppButton.vue";
@@ -358,17 +361,16 @@ import GenealogyCard from "@/components/GenealogyCard.vue";
import GenealogyPageBackground from "@/components/GenealogyPageBackground.vue";
import PageHeader from "@/components/PageHeader.vue";
import {
findGenealogyFixture,
genealogies,
getGenealogyFixtureAccess,
listNotificationFixtures,
} from "@/data/mock.js";
appApi,
createRequestController,
isRequestCancelled,
} from "@/utils/api.js";
import { genealogyContext } from "@/utils/genealogy-context.js";
import { handleBackPress, openPage, runBackGuard } from "@/utils/navigation.js";
const isLoading = ref(false);
const hasError = ref(false);
const list = ref(genealogies);
const list = ref([]);
const forceEmptyState = ref(false);
const contextInvalidated = ref(false);
const contextReconcileFailed = ref(false);
@@ -378,9 +380,14 @@ const switcherVisible = ref(false);
const selectedGenealogyId = ref(null);
const listScrollCommand = ref(0);
const currentListScrollTop = ref(0);
const listRequestController = createRequestController();
let loadGeneration = 0;
let pageActive = true;
let presentationState = "default";
let skipNextShowRefresh = true;
const syncEmptyStateFromRoute = (query = {}) => {
const presentationState = ["empty", "loading", "error"].includes(
presentationState = ["empty", "loading", "error"].includes(
query?.state,
)
? query.state
@@ -419,15 +426,59 @@ const reconcilePageGenealogyContext = () => {
}
};
const loadGenealogies = async () => {
const generation = ++loadGeneration;
listRequestController.abort();
isLoading.value = true;
hasError.value = false;
try {
const result = await appApi.getMyGenealogies({
requestController: listRequestController,
});
if (!pageActive || generation !== loadGeneration) return;
list.value = result;
reconcilePageGenealogyContext();
} catch (error) {
if (
!pageActive ||
generation !== loadGeneration ||
isRequestCancelled(error)
) {
return;
}
hasError.value = true;
} finally {
if (pageActive && generation === loadGeneration) {
isLoading.value = false;
}
}
};
onLoad((query) => {
syncEmptyStateFromRoute(query);
requestedGenealogyId.value = String(query?.genealogyId || "");
reconcilePageGenealogyContext();
if (presentationState === "default") {
loadGenealogies();
} else {
reconcilePageGenealogyContext();
}
});
const unreadCount = computed(
() => listNotificationFixtures().filter((item) => item.unread).length,
);
onShow(() => {
if (skipNextShowRefresh) {
skipNextShowRefresh = false;
return;
}
if (presentationState === "default") loadGenealogies();
});
onUnload(() => {
pageActive = false;
loadGeneration += 1;
listRequestController.abort();
});
const unreadCount = computed(() => 0);
const hasGenealogies = computed(
() => !forceEmptyState.value && list.value.length > 0,
);
@@ -439,14 +490,10 @@ const isListLayout = computed(
hasGenealogies.value,
);
const createdGenealogies = computed(() =>
list.value.filter(
(item) => getGenealogyFixtureAccess(item.id).accessRole === "owner",
),
list.value.filter((item) => item.accessRole === "owner"),
);
const joinedGenealogies = computed(() =>
list.value.filter(
(item) => getGenealogyFixtureAccess(item.id).accessRole === "member",
),
list.value.filter((item) => item.accessRole === "member"),
);
const availableGenealogies = computed(() => list.value);
const currentGenealogy = computed(
@@ -456,41 +503,14 @@ const currentGenealogy = computed(
) || null,
);
const isCurrentGenealogyOwner = computed(
() =>
getGenealogyFixtureAccess(currentGenealogy.value?.id).accessRole ===
"owner",
() => currentGenealogy.value?.accessRole === "owner",
);
const currentRoleLabel = computed(() =>
isCurrentGenealogyOwner.value ? "管理员" : "成员",
);
// 仅用于页面样式阶段覆盖加入申请的关键状态,不作为接口数据
const applicationRecords = [
{
id: "pending",
genealogyId: "2003",
statusLabel: "审核中",
tone: "pending",
description: "申请已提交,等待管理员审核",
},
{
id: "rejected",
genealogyId: "2004",
statusLabel: "被拒绝",
tone: "rejected",
description: "可修改关系说明后重新申请",
},
{
id: "removed",
genealogyId: "2005",
statusLabel: "已退出",
tone: "muted",
description: "如需恢复成员身份,可重新申请加入",
},
].map((record) => ({
...record,
name: findGenealogyFixture(record.genealogyId)?.name || "未知家谱",
}));
// 普通加入申请批次接通前不展示本地伪记录
const applicationRecords = ref([]);
const shortcuts = [
{
@@ -603,13 +623,7 @@ const openApplication = (record) => {
);
};
const retryLoad = () => {
if (contextReconcileFailed.value) {
hasError.value = false;
reconcilePageGenealogyContext();
return;
}
hasError.value = false;
isLoading.value = false;
loadGenealogies();
};
const openShortcut = (key) => {