完成70%
This commit is contained in:
@@ -1,462 +1,4 @@
|
||||
<!-- 页面编号:G-08;用途:申请加入家谱与提交成功/失败状态。 -->
|
||||
<template>
|
||||
<view class="join-page">
|
||||
<GenealogyPageBackground />
|
||||
<view class="join-page__header">
|
||||
<PageHeader :title="sourceContract.headerTitle" custom-back @back="requestBack" />
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="join-panel"
|
||||
:class="{
|
||||
'join-state--form': joinState === 'form',
|
||||
'join-state--success': joinState === 'success',
|
||||
'join-state--error': joinState === 'error',
|
||||
'join-state--ineligible': joinState === 'ineligible',
|
||||
}"
|
||||
>
|
||||
<view v-if="joinState === 'form'" class="join-form">
|
||||
<text class="join-form__eyebrow">{{ sourceContract.eyebrow }}</text>
|
||||
<text class="join-form__title"
|
||||
>{{ sourceContract.formTitle }} {{ genealogyName }}</text
|
||||
>
|
||||
<text class="join-form__copy">{{ sourceContract.formCopy }}</text>
|
||||
<view class="join-field">
|
||||
<text>真实姓名</text
|
||||
><input
|
||||
v-model="form.realName"
|
||||
placeholder="请输入真实姓名"
|
||||
placeholder-class="join-placeholder"
|
||||
@input="clearFieldError('realName')"
|
||||
/>
|
||||
</view>
|
||||
<text v-if="fieldErrors.realName" class="join-field-error">{{
|
||||
fieldErrors.realName
|
||||
}}</text>
|
||||
<view class="join-field">
|
||||
<text>与家谱关系</text
|
||||
><input
|
||||
v-model="form.relation"
|
||||
placeholder="例如:某某某堂侄"
|
||||
placeholder-class="join-placeholder"
|
||||
@input="clearFieldError('relation')"
|
||||
/>
|
||||
</view>
|
||||
<text v-if="fieldErrors.relation" class="join-field-error">{{
|
||||
fieldErrors.relation
|
||||
}}</text>
|
||||
<text class="relation-help"
|
||||
>请以家谱中一位已知长辈为参照,例如:某某某堂侄</text
|
||||
>
|
||||
<view class="join-field join-field--message">
|
||||
<text>{{ sourceContract.thirdFieldLabel }}</text
|
||||
><textarea
|
||||
v-model="form.message"
|
||||
auto-height
|
||||
maxlength="80"
|
||||
:placeholder="sourceContract.thirdFieldPlaceholder"
|
||||
placeholder-class="join-placeholder"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<text class="join-form__note">{{ sourceContract.note }}</text>
|
||||
<view class="join-action" @click="submitJoin">
|
||||
<text>{{
|
||||
isSubmitting
|
||||
? sourceContract.submittingLabel
|
||||
: sourceContract.submitLabel
|
||||
}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else class="join-result">
|
||||
<text class="join-result__eyebrow">{{
|
||||
joinState === "success"
|
||||
? sourceContract.successEyebrow
|
||||
: joinState === "ineligible"
|
||||
? "当前不可申请"
|
||||
: sourceContract.errorEyebrow
|
||||
}}</text>
|
||||
<text class="join-result__title">{{
|
||||
joinState === "success"
|
||||
? sourceContract.successTitle
|
||||
: joinState === "ineligible"
|
||||
? ineligibleTitle
|
||||
: sourceContract.errorTitle
|
||||
}}</text>
|
||||
<text class="join-result__copy">{{ resultCopy }}</text>
|
||||
<view
|
||||
class="join-action"
|
||||
@click="
|
||||
joinState === 'success'
|
||||
? completeFlow()
|
||||
: joinState === 'ineligible'
|
||||
? handleIneligibleAction()
|
||||
: retryForm()
|
||||
"
|
||||
>
|
||||
<text>{{
|
||||
joinState === "success"
|
||||
? sourceContract.nextLabel
|
||||
: joinState === "ineligible"
|
||||
? ineligibleActionLabel
|
||||
: "重新填写"
|
||||
}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<AppDialog
|
||||
:visible="discardVisible"
|
||||
title="放弃填写?"
|
||||
message="当前身份关系尚未保存,确认返回后将清空。"
|
||||
confirm-text="放弃并返回"
|
||||
cancel-text="继续填写"
|
||||
show-cancel
|
||||
compact-actions
|
||||
:close-on-mask="false"
|
||||
@confirm="confirmDiscard"
|
||||
@cancel="cancelDiscard"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, reactive, ref } from "vue";
|
||||
import { onBackPress, onLoad, onUnload } from "@dcloudio/uni-app";
|
||||
import AppDialog from "@/components/AppDialog.vue";
|
||||
import GenealogyPageBackground from "@/components/GenealogyPageBackground.vue";
|
||||
import PageHeader from "@/components/PageHeader.vue";
|
||||
import {
|
||||
findGenealogyFixture,
|
||||
getGenealogyFixtureAccess,
|
||||
} from "@/data/mock.js";
|
||||
import { createDiscardConfirmation } from "@/utils/discard-confirmation.js";
|
||||
import {
|
||||
goBack,
|
||||
goRoot,
|
||||
handleBackPress,
|
||||
openPage,
|
||||
returnTo,
|
||||
runBackGuard,
|
||||
} from "@/utils/navigation.js";
|
||||
|
||||
const genealogyId = ref("");
|
||||
const source = ref("search");
|
||||
const genealogyName = ref("这部家谱");
|
||||
const joinState = ref("form");
|
||||
const isSubmitting = ref(false);
|
||||
const errorMessage = ref("");
|
||||
const ineligibleRelation = ref("unknown");
|
||||
const discardVisible = ref(false);
|
||||
const form = reactive({ realName: "", relation: "", message: "" });
|
||||
const fieldErrors = reactive({ realName: "", relation: "" });
|
||||
let submitTimer = null;
|
||||
const isDirty = computed(() =>
|
||||
Boolean(form.realName || form.relation || form.message),
|
||||
);
|
||||
const discardConfirmation = createDiscardConfirmation((visible) => {
|
||||
discardVisible.value = visible;
|
||||
});
|
||||
const requestDiscardConfirmation = discardConfirmation.request;
|
||||
const confirmDiscard = discardConfirmation.confirm;
|
||||
const cancelDiscard = discardConfirmation.cancel;
|
||||
const sourceContract = computed(() =>
|
||||
source.value === "invite"
|
||||
? {
|
||||
headerTitle: "确认身份关系",
|
||||
eyebrow: "邀请码定位预览",
|
||||
formTitle: "核对家谱",
|
||||
formCopy:
|
||||
"请填写真实身份和亲属关系;当前仅验证页面流程,不会变更成员身份。",
|
||||
thirdFieldLabel: "补充信息",
|
||||
thirdFieldPlaceholder: "选填:补充祖居地、长辈姓名等信息",
|
||||
note: "后端尚未提供邀请码验证与直接入谱接口。",
|
||||
submitLabel: "完成本地校验",
|
||||
submittingLabel: "正在校验…",
|
||||
successEyebrow: "本地校验完成",
|
||||
successTitle: "信息尚未提交服务器",
|
||||
errorEyebrow: "校验未完成",
|
||||
errorTitle: "暂时无法完成校验",
|
||||
nextLabel: "返回我的家谱",
|
||||
successCopy: `本地流程预览已完成“${genealogyName.value}”的身份填写;返回后不会选中或加入这部家谱。`,
|
||||
}
|
||||
: {
|
||||
headerTitle: "申请加入家谱",
|
||||
eyebrow: "公开家谱入谱申请",
|
||||
formTitle: "申请加入",
|
||||
formCopy: "请填写真实身份和亲属关系,管理员审核后会通过消息告知结果。",
|
||||
thirdFieldLabel: "申请说明",
|
||||
thirdFieldPlaceholder: "补充祖居地、长辈姓名等核验信息",
|
||||
note: "当前仅验证页面流程,后端申请接口接入后才能正式提交。",
|
||||
submitLabel: "完成本地校验",
|
||||
submittingLabel: "正在校验…",
|
||||
successEyebrow: "本地校验完成",
|
||||
successTitle: "申请尚未提交服务器",
|
||||
errorEyebrow: "申请未提交",
|
||||
errorTitle: "暂时无法完成校验",
|
||||
nextLabel: "查看我的申请",
|
||||
successCopy: `本地流程预览已完成“${genealogyName.value}”的申请填写,当前不会新增审核记录。`,
|
||||
},
|
||||
);
|
||||
const resultCopy = computed(() =>
|
||||
joinState.value === "success"
|
||||
? sourceContract.value.successCopy
|
||||
: joinState.value === "ineligible"
|
||||
? ({
|
||||
owned: "这是你创建的家谱,无需重复提交加入申请。",
|
||||
joined: "你已经是这部家谱的成员,无需重复申请。",
|
||||
pending: "这部家谱已有待审核申请,请先查看申请进度。",
|
||||
})[ineligibleRelation.value] ||
|
||||
"当前家谱不存在、未公开或不可申请,请返回后重新选择。"
|
||||
: errorMessage.value ||
|
||||
"请检查网络后重新填写;未成功提交的内容不会进入审核列表。",
|
||||
);
|
||||
const ineligibleTitle = computed(
|
||||
() =>
|
||||
({
|
||||
owned: "你已拥有这部家谱",
|
||||
joined: "你已加入这部家谱",
|
||||
pending: "申请正在审核中",
|
||||
})[ineligibleRelation.value] || "无法打开申请表",
|
||||
);
|
||||
const ineligibleActionLabel = computed(
|
||||
() =>
|
||||
ineligibleRelation.value === "pending"
|
||||
? "查看申请进度"
|
||||
: ["owned", "joined"].includes(ineligibleRelation.value)
|
||||
? "返回我的家谱"
|
||||
: "返回上一页",
|
||||
);
|
||||
|
||||
onLoad((query) => {
|
||||
genealogyId.value = String(query.genealogyId || "");
|
||||
source.value = query.source === "invite" ? "invite" : "search";
|
||||
if (!genealogyId.value) {
|
||||
ineligibleRelation.value = "unknown";
|
||||
joinState.value = "ineligible";
|
||||
return;
|
||||
}
|
||||
const fixture = findGenealogyFixture(genealogyId.value);
|
||||
genealogyName.value = fixture?.name || "这部家谱";
|
||||
const access = getGenealogyFixtureAccess(genealogyId.value);
|
||||
if (!fixture || !access.canApply) {
|
||||
ineligibleRelation.value = access.relation;
|
||||
joinState.value = "ineligible";
|
||||
return;
|
||||
}
|
||||
if (query.state === "success") joinState.value = "success";
|
||||
});
|
||||
|
||||
const requestBack = () => {
|
||||
if (joinState.value === "success") return completeFlow();
|
||||
return runBackGuard({
|
||||
transientOpen: discardVisible.value,
|
||||
dirty: isDirty.value,
|
||||
submitting: isSubmitting.value,
|
||||
"close-transient": cancelDiscard,
|
||||
"block-submitting": () => true,
|
||||
"confirm-discard": requestDiscardConfirmation,
|
||||
});
|
||||
};
|
||||
|
||||
onBackPress((event) => handleBackPress(event, requestBack));
|
||||
onUnload(() => {
|
||||
const timer = submitTimer;
|
||||
submitTimer = null;
|
||||
if (timer) clearTimeout(timer);
|
||||
discardConfirmation.dispose();
|
||||
});
|
||||
|
||||
const submitJoin = () => {
|
||||
if (isSubmitting.value) return;
|
||||
fieldErrors.realName = form.realName.trim() ? "" : "请填写真实姓名";
|
||||
fieldErrors.relation = form.relation.trim() ? "" : "请填写与家谱的关系";
|
||||
if (fieldErrors.realName || fieldErrors.relation) return;
|
||||
const submitSnapshot = Object.freeze({ ...form });
|
||||
isSubmitting.value = true;
|
||||
const timer = setTimeout(() => {
|
||||
if (submitTimer !== timer) return;
|
||||
submitTimer = null;
|
||||
joinState.value =
|
||||
submitSnapshot.realName.trim() === "失败" ? "error" : "success";
|
||||
if (joinState.value === "error")
|
||||
errorMessage.value =
|
||||
source.value === "invite"
|
||||
? "邀请码加入暂未完成,请稍后重试。"
|
||||
: "申请暂未提交,请稍后重试。";
|
||||
isSubmitting.value = false;
|
||||
}, 280);
|
||||
submitTimer = timer;
|
||||
};
|
||||
const clearFieldError = (field) => {
|
||||
fieldErrors[field] = "";
|
||||
};
|
||||
const retryForm = () => {
|
||||
joinState.value = "form";
|
||||
errorMessage.value = "";
|
||||
};
|
||||
const handleIneligibleAction = () => {
|
||||
if (ineligibleRelation.value === "pending")
|
||||
return openPage("G09", { status: "pending" }, "G08");
|
||||
if (["owned", "joined"].includes(ineligibleRelation.value))
|
||||
return goRoot("G01", { genealogyId: genealogyId.value });
|
||||
return goBack();
|
||||
};
|
||||
const completeFlow = () =>
|
||||
source.value === "invite" ? returnTo("G01", {}) : returnTo("G09", {});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "../../styles/adaptive-frame-profiles.scss" as adaptive;
|
||||
.join-page {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
flex-direction: column;
|
||||
background: $paper;
|
||||
}
|
||||
.join-page__header {
|
||||
z-index: 3;
|
||||
}
|
||||
.join-panel {
|
||||
@include adaptive.adaptive-genealogy-state-panel;
|
||||
z-index: 2;
|
||||
width: calc(100% - 32rpx);
|
||||
min-height: min(590px, calc((100vw - 16px) * 1.337));
|
||||
margin: 22rpx auto 0;
|
||||
padding: 70rpx 8%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.join-form {
|
||||
min-width: 0;
|
||||
}
|
||||
.join-form__eyebrow,
|
||||
.join-result__eyebrow {
|
||||
display: block;
|
||||
color: $brand-red;
|
||||
font-size: 23rpx;
|
||||
letter-spacing: 3rpx;
|
||||
}
|
||||
.join-form__title,
|
||||
.join-result__title {
|
||||
display: block;
|
||||
margin-top: 12rpx;
|
||||
color: $ink;
|
||||
font-family: "STKaiti", "KaiTi", serif;
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.join-form__copy,
|
||||
.join-result__copy {
|
||||
display: block;
|
||||
margin-top: 12rpx;
|
||||
color: $ink-muted;
|
||||
font-size: 22rpx;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.join-field {
|
||||
@include adaptive.adaptive-genealogy-form-field;
|
||||
display: grid;
|
||||
min-height: 92rpx;
|
||||
margin-top: 18rpx;
|
||||
}
|
||||
.join-form__previous {
|
||||
display: block;
|
||||
margin-top: 14rpx;
|
||||
color: $brand-red;
|
||||
font-size: 22rpx;
|
||||
line-height: 1.55;
|
||||
}
|
||||
.join-field > text {
|
||||
z-index: 1;
|
||||
grid-area: 1 / 1;
|
||||
align-self: center;
|
||||
margin-left: 24rpx;
|
||||
color: $ink;
|
||||
font-size: 23rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.join-field input,
|
||||
.join-field textarea {
|
||||
z-index: 1;
|
||||
grid-area: 1 / 1;
|
||||
width: auto;
|
||||
min-width: 0;
|
||||
min-height: 92rpx;
|
||||
margin-right: 20rpx;
|
||||
margin-left: 170rpx;
|
||||
color: $ink;
|
||||
font-size: 23rpx;
|
||||
line-height: 92rpx;
|
||||
}
|
||||
.join-field textarea {
|
||||
box-sizing: border-box;
|
||||
padding-top: 26rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.join-placeholder {
|
||||
color: #a79884;
|
||||
}
|
||||
.join-field-error {
|
||||
display: block;
|
||||
margin-top: 3rpx;
|
||||
color: $brand-red;
|
||||
font-size: 24rpx;
|
||||
line-height: 34rpx;
|
||||
text-align: right;
|
||||
}
|
||||
.relation-help {
|
||||
display: block;
|
||||
margin-top: 5rpx;
|
||||
color: #8e7b67;
|
||||
font-size: 19rpx;
|
||||
line-height: 29rpx;
|
||||
}
|
||||
.join-form__note {
|
||||
display: block;
|
||||
margin-top: 18rpx;
|
||||
color: $ink-muted;
|
||||
font-size: 21rpx;
|
||||
text-align: center;
|
||||
}
|
||||
.join-action {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 82rpx;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 20rpx;
|
||||
background: url("/static/assets/foundation/transparent/a01-scroll-primary-v3.png")
|
||||
center / contain no-repeat;
|
||||
}
|
||||
.join-action text {
|
||||
z-index: 1;
|
||||
color: #fff9ed;
|
||||
font-size: 27rpx;
|
||||
font-weight: 700;
|
||||
letter-spacing: 3rpx;
|
||||
}
|
||||
.join-result {
|
||||
text-align: center;
|
||||
}
|
||||
.join-state--success,
|
||||
.join-state--error {
|
||||
padding: 170rpx 12% 70rpx;
|
||||
}
|
||||
.join-result__eyebrow {
|
||||
text-align: center;
|
||||
}
|
||||
.join-result__copy {
|
||||
margin-top: 22rpx;
|
||||
}
|
||||
.join-result .join-action {
|
||||
width: 420rpx;
|
||||
max-width: 100%;
|
||||
margin: 34rpx auto 0;
|
||||
}
|
||||
@media (min-width: 400px) {
|
||||
.join-panel {
|
||||
width: calc(100% - 48rpx);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- 页面编号:G-08;用途:加入申请。公开家谱详情/权限投影不完整时保持关闭。 -->
|
||||
<template><view class="join-page"><GenealogyPageBackground /><view class="page-header"><PageHeader title="申请加入家谱" custom-back @back="backToSearch" /></view><view class="page-content"><view class="state-card"><text>加入申请待后端字段合同</text><text>申请提交 operation 不等于可安全发起申请:当前没有公开家谱详情、可申请权限或稳定家谱条目 ID 的消费投影。页面不再使用 fixture 家谱或本地申请成功提示。</text><AppButton block label="返回搜索家谱" @click="backToSearch" /></view></view></view></template>
|
||||
<script setup>import AppButton from "@/components/AppButton.vue";import GenealogyPageBackground from "@/components/GenealogyPageBackground.vue";import PageHeader from "@/components/PageHeader.vue";import {returnTo} from "@/utils/navigation.js";const backToSearch=()=>returnTo("G06");</script>
|
||||
<style scoped lang="scss">@use "../../styles/adaptive-frame-profiles.scss" as adaptive;.join-page{display:flex;min-height:100vh;flex-direction:column;background:$paper}.page-header,.page-content{z-index:1}.page-content{padding:18rpx 24rpx 72rpx}.state-card{box-sizing:border-box;min-height:340rpx;padding:78rpx 52rpx 50rpx;text-align:center;@include adaptive.adaptive-genealogy-state-panel}.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}.state-card .app-button{margin-top:28rpx}</style>
|
||||
|
||||
Reference in New Issue
Block a user