Files
jiapuapp/pages/genealogy/g09-my-applications.vue
T
2026-07-20 06:52:33 +08:00

383 lines
9.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- 页面编号G-09用途我的家谱申请列表与空/失败状态 -->
<template>
<view class="application-page">
<GenealogyPageBackground />
<view class="application-page__header"
><PageHeader title="我的申请"
/></view>
<view
class="application-content"
:class="{
'application-state--list': applicationState === 'list',
'application-state--empty': applicationState === 'empty',
'application-state--error': applicationState === 'error',
}"
>
<template v-if="applicationState === 'list'">
<view class="application-intro">
<text>入谱申请进度</text><text>审核结果会同步到消息中心</text>
</view>
<view
v-for="item in applications"
:key="item.id"
class="application-card"
>
<image
class="application-card__skin"
src="/static/assets/modules/genealogy/transparent/list-slip-frame.png"
mode="scaleToFill"
/>
<view class="application-card__body">
<text class="application-card__name">{{ item.genealogyName }}</text>
<text class="application-card__time">{{ item.appliedAt }}</text>
<text class="application-card__relation">{{ item.relation }}</text>
<text
class="application-card__status"
:class="`application-card__status--${item.status.toLowerCase()}`"
>{{ statusLabel(item.status) }}</text
>
<text class="application-card__hint">{{
statusHint(item.status)
}}</text>
<view
v-if="actionFor(item)"
class="application-card__action"
@click="handleApplicationAction(item)"
>{{ actionFor(item) }}</view
>
</view>
</view>
</template>
<AppLoading
v-else-if="applicationState === 'loading'"
text="正在整理申请记录"
description="请稍候,正在同步审核状态。"
/>
<view v-else class="application-state-card">
<image
src="/static/assets/modules/genealogy/transparent/list-slip-frame.png"
mode="scaleToFill"
/>
<view class="application-state-card__copy">
<text>{{ stateTitle }}</text>
<text>{{ stateCopy }}</text>
</view>
</view>
<view
v-if="applicationState !== 'list' && applicationState !== 'loading'"
class="application-page__action"
@click="
applicationState === 'error' ? loadApplications({}) : toSearch()
"
>
<image
src="/static/assets/foundation/transparent/a01-scroll-primary-v3.png"
mode="aspectFit"
/>
<text>{{
applicationState === "error" ? "重新查看" : "查找公开家谱"
}}</text>
</view>
</view>
<AppDialog
:visible="!!withdrawTarget"
title="撤回加入申请"
:message="
withdrawTarget
? `确认撤回对“${withdrawTarget.genealogyName}”的申请?撤回后如需加入,可重新提交。`
: ''
"
confirm-text="确认撤回"
cancel-text="暂不撤回"
show-cancel
@confirm="confirmWithdraw"
@cancel="cancelWithdraw"
@close="cancelWithdraw"
/>
</view>
</template>
<script setup>
import { computed, ref } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import AppDialog from "@/components/AppDialog.vue";
import AppLoading from "@/components/AppLoading.vue";
import GenealogyPageBackground from "@/components/GenealogyPageBackground.vue";
import PageHeader from "@/components/PageHeader.vue";
const applications = ref([]);
const applicationState = ref("loading");
const errorMessage = ref("");
const withdrawTarget = ref(null);
const applicationSamples = [
{
id: 1,
genealogyId: 1001,
genealogyName: "汤氏家谱",
relation: "自述为汤正华堂侄",
appliedAt: "今天 10:24",
status: "PENDING",
},
{
id: 2,
genealogyId: 1002,
genealogyName: "汝南汤氏家谱",
relation: "祖居河南汝南",
appliedAt: "昨天 18:02",
status: "APPROVED",
},
{
id: 3,
genealogyId: 1003,
genealogyName: "清河汤氏家谱",
relation: "补充材料不足",
appliedAt: "7月12日 09:18",
status: "REJECTED",
},
];
const statusLabel = (status) =>
({
PENDING: "审核中",
APPROVED: "已通过",
REJECTED: "未通过",
WITHDRAWN: "已撤回",
})[status] || "状态未知";
const statusHint = (status) =>
({
PENDING: "管理员尚未处理,可在审核前撤回",
APPROVED: "申请已通过,可进入这部家谱",
REJECTED: "请修改关系说明后重新提交",
WITHDRAWN: "申请已撤回,不再进入管理员审核",
})[status] || "";
const actionFor = (item) =>
({ PENDING: "撤回申请", APPROVED: "进入家谱", REJECTED: "修改后重新提交" })[
item.status
] || "";
const stateTitle = computed(() =>
applicationState.value === "empty"
? "还没有入谱申请"
: applicationState.value === "loading"
? "正在整理申请记录"
: "申请记录暂时无法读取",
);
const stateCopy = computed(() =>
applicationState.value === "empty"
? "从家谱搜索提交的申请会显示在这里;邀请码直接加入不进入本页。"
: applicationState.value === "loading"
? "请稍候,正在同步审核状态。"
: errorMessage.value || "请检查网络后重新查看。",
);
const loadApplications = (query = {}) => {
applicationState.value = "loading";
errorMessage.value = "";
if (query.state === "empty") {
applicationState.value = "empty";
return;
}
if (query.state === "error") {
applicationState.value = "error";
return;
}
if (query.state === "loading") {
applicationState.value = "loading";
return;
}
applications.value = applicationSamples.map((item) => ({ ...item }));
applicationState.value = "list";
};
onLoad(loadApplications);
const handleApplicationAction = (item) => {
if (item.status === "APPROVED")
return uni.navigateTo({
url: `/pages/genealogy/g05-genealogy-overview?genealogyId=${item.genealogyId}`,
});
if (item.status === "REJECTED")
return uni.navigateTo({
url: `/pages/genealogy/g08-join-application?source=search&previous=rejected&genealogyId=${item.genealogyId}`,
});
if (item.status === "PENDING") withdrawTarget.value = item;
};
const cancelWithdraw = () => {
withdrawTarget.value = null;
};
const confirmWithdraw = () => {
const target = applications.value.find(
(item) => item.id === withdrawTarget.value?.id,
);
if (target) target.status = "WITHDRAWN";
cancelWithdraw();
};
const toSearch = () =>
uni.navigateTo({ url: "/pages/genealogy/g06-search-genealogies" });
</script>
<style scoped lang="scss">
.application-page {
position: relative;
min-height: 100vh;
overflow-x: hidden;
background: $paper;
}
.application-page__header {
position: relative;
z-index: 3;
}
.application-content {
position: relative;
z-index: 2;
padding: 28rpx 24rpx 60rpx;
}
.application-intro {
display: flex;
align-items: baseline;
justify-content: space-between;
margin: 0 8rpx 20rpx;
}
.application-intro text:first-child {
color: $ink;
font-family: "STKaiti", "KaiTi", serif;
font-size: 31rpx;
font-weight: 700;
}
.application-intro text:last-child {
color: $ink-muted;
font-size: 24rpx;
}
.application-card {
position: relative;
width: 100%;
height: calc((100vw - 24px) * 0.34286);
min-height: 228rpx;
max-height: 282rpx;
margin-bottom: 18rpx;
}
.application-card__skin {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
.application-card__body {
position: absolute;
inset: 18% 7% 14% 8.5%;
}
.application-card__name {
color: $ink;
font-family: "STKaiti", "KaiTi", serif;
font-size: 30rpx;
font-weight: 700;
}
.application-card__time {
position: absolute;
top: 3rpx;
right: 0;
color: #998873;
font-size: 23rpx;
}
.application-card__relation {
display: block;
max-width: 70%;
margin-top: 14rpx;
color: $ink-muted;
font-size: 24rpx;
}
.application-card__status {
position: absolute;
right: 3%;
bottom: 38%;
color: $brand-red;
font-size: 25rpx;
font-weight: 700;
}
.application-card__status--approved {
color: #537368;
}
.application-card__status--rejected {
color: #7e6f62;
}
.application-card__hint {
position: absolute;
bottom: 5%;
left: 0;
max-width: 62%;
color: #766653;
font-size: 23rpx;
}
.application-card__action {
position: absolute;
right: 2%;
bottom: 2%;
z-index: 2;
display: flex;
min-height: 54rpx;
align-items: center;
color: $brand-red;
font-size: 23rpx;
font-weight: 700;
}
.application-state-card {
position: relative;
width: 100%;
height: calc((100vw - 24px) * 0.34286);
min-height: 228rpx;
margin-top: 80rpx;
}
.application-state-card > image {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
.application-state-card__copy {
position: absolute;
inset: 22% 12%;
display: flex;
flex-direction: column;
justify-content: center;
text-align: center;
}
.application-state-card__copy text:first-child {
color: $ink;
font-family: "STKaiti", "KaiTi", serif;
font-size: 31rpx;
font-weight: 700;
}
.application-state-card__copy text:last-child {
margin-top: 16rpx;
color: $ink-muted;
font-size: 24rpx;
line-height: 1.6;
}
.application-page__action {
position: relative;
width: 420rpx;
height: 82rpx;
margin: 34rpx auto 0;
}
.application-page__action image {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
.application-page__action text {
position: relative;
z-index: 1;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
color: #fff9ed;
font-size: 26rpx;
font-weight: 700;
}
</style>