完成50%

This commit is contained in:
2026-07-23 08:23:59 +08:00
parent 9b0ad62df4
commit f1edc6b533
218 changed files with 24318 additions and 5514 deletions
+129 -53
View File
@@ -6,7 +6,7 @@
<PageHeader
:title="isAncestorStep ? '录入首代人物' : '创建家谱'"
custom-back
@back="goBack"
@back="requestBack"
/>
<view class="flow-content">
@@ -73,22 +73,15 @@
<text class="flow-rule__label">访问规则</text>
<view class="flow-rule__options">
<view
v-for="option in GENEALOGY_ACCESS_PRESET_OPTIONS"
:key="option.value"
class="flow-rule__option"
:class="{
'flow-rule__option--active':
createForm.visibility === 'MEMBER_ONLY',
createForm.accessPreset === option.value,
}"
@click="createForm.visibility = 'MEMBER_ONLY'"
>仅成员可见</view
>
<view
class="flow-rule__option"
:class="{
'flow-rule__option--active':
createForm.visibility === 'SEARCHABLE',
}"
@click="createForm.visibility = 'SEARCHABLE'"
>可搜索申请</view
@click="createForm.accessPreset = option.value"
>{{ option.label }}</view
>
</view>
</view>
@@ -223,7 +216,7 @@
<view class="flow-success-dialog__content">
<text class="flow-success-dialog__title">家谱创建完成</text>
<text class="flow-success-dialog__copy"
>首代人物已保存接下来进入家谱总览继续完善资料</text
>当前为本地流程预览资料尚未提交服务器可进入总览继续检查页面</text
>
<view class="flow-success-dialog__action" @click="enterOverview">
<text>进入家谱总览</text>
@@ -231,14 +224,40 @@
</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, onUnmounted, reactive, ref } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import { computed, reactive, ref } from "vue";
import { onBackPress, onUnload } from "@dcloudio/uni-app";
import AppDialog from "@/components/AppDialog.vue";
import GenealogyPageBackground from "@/components/GenealogyPageBackground.vue";
import PageHeader from "@/components/PageHeader.vue";
import {
createLocalGenealogyPreview,
removeLocalGenealogyPreview,
updateLocalGenealogyPreview,
updateLocalGenealogyPreviewAncestor,
} from "@/data/mock.js";
import { createDiscardConfirmation } from "@/utils/discard-confirmation.js";
import {
GENEALOGY_ACCESS_PRESET,
GENEALOGY_ACCESS_PRESET_OPTIONS,
} from "@/utils/genealogy-contracts.js";
import { handleBackPress, openPage, returnTo, runBackGuard } from "@/utils/navigation.js";
const currentStep = ref("create");
const genealogyId = ref("");
@@ -246,6 +265,7 @@ const isSubmitting = ref(false);
const createState = ref("form");
const ancestorState = ref("form");
const duplicateReminderVisible = ref(false);
const discardVisible = ref(false);
const fieldErrors = reactive({
surname: "",
name: "",
@@ -258,7 +278,7 @@ const createForm = reactive({
name: "",
hall: "",
location: "",
visibility: "MEMBER_ONLY",
accessPreset: GENEALOGY_ACCESS_PRESET.MEMBER_ONLY,
});
const ancestorForm = reactive({
personName: "",
@@ -286,31 +306,69 @@ const changeAncestorBirthDate = (event) => {
};
const isAncestorStep = computed(() => currentStep.value === "ancestor");
const isDirty = computed(() =>
isAncestorStep.value
? Boolean(
ancestorForm.personName ||
ancestorForm.birthDate ||
ancestorForm.introduction ||
ancestorForm.sex !== "0",
)
: Boolean(
createForm.surname ||
createForm.name ||
createForm.hall ||
createForm.location ||
createForm.accessPreset !== GENEALOGY_ACCESS_PRESET.MEMBER_ONLY,
),
);
const syncFlowFromRoute = (query = {}) => {
const isAncestorRoute = query?.step === "ancestor";
const routeGenealogyId = query?.genealogyId || "";
currentStep.value = isAncestorRoute ? "ancestor" : "create";
genealogyId.value =
routeGenealogyId || (isAncestorStep.value ? "local-created-genealogy" : "");
};
onLoad((query) => {
syncFlowFromRoute(query);
const discardConfirmation = createDiscardConfirmation((visible) => {
discardVisible.value = visible;
});
onUnmounted(() => {
if (submitTimer) clearTimeout(submitTimer);
});
const goBack = () => {
if (isAncestorStep.value) {
uni.redirectTo({ url: "/pages/genealogy/g03-create-genealogy" });
return;
const requestRawDiscardConfirmation = discardConfirmation.request;
const requestDiscardConfirmation = async () => {
const confirmed = await requestRawDiscardConfirmation();
if (confirmed && currentStep.value === "create" && genealogyId.value) {
removeLocalGenealogyPreview(genealogyId.value);
genealogyId.value = "";
}
uni.navigateBack();
return confirmed;
};
const confirmDiscard = discardConfirmation.confirm;
const cancelDiscard = discardConfirmation.cancel;
onUnload(() => {
const timer = submitTimer;
submitTimer = null;
if (timer) clearTimeout(timer);
discardConfirmation.dispose();
});
const closeActiveTransient = () => {
if (duplicateReminderVisible.value) closeDuplicateReminder();
else cancelDiscard();
};
const popInternalTrail = () => {
currentStep.value = "create";
ancestorState.value = "form";
return true;
};
const requestBack = () => {
if (ancestorState.value === "success") return enterOverview();
return runBackGuard({
transientOpen: duplicateReminderVisible.value || discardVisible.value,
internalTrail: isAncestorStep.value && !isSubmitting.value,
dirty: isDirty.value,
submitting: isSubmitting.value,
"close-transient": closeActiveTransient,
"pop-internal-trail": popInternalTrail,
"block-submitting": () => true,
"confirm-discard": requestDiscardConfirmation,
});
};
onBackPress((event) => handleBackPress(event, requestBack));
const clearFieldError = (field) => {
fieldErrors[field] = "";
@@ -333,23 +391,31 @@ const submitCreate = () => {
const closeDuplicateReminder = () => {
duplicateReminderVisible.value = false;
};
const searchExistingGenealogy = () =>
uni.navigateTo({ url: "/pages/genealogy/g06-search-genealogies" });
const confirmCreate = () => {
const searchExistingGenealogy = () => {
closeDuplicateReminder();
return openPage("G06", {}, "G03");
};
const confirmCreate = () => {
if (isSubmitting.value) return;
closeDuplicateReminder();
const createSnapshot = Object.freeze({ ...createForm });
isSubmitting.value = true;
createState.value = "submitting";
submitTimer = setTimeout(() => {
const timer = setTimeout(() => {
if (submitTimer !== timer) return;
submitTimer = null;
isSubmitting.value = false;
if (createForm.name.trim() === "失败") {
if (createSnapshot.name.trim() === "失败") {
createState.value = "error";
return;
}
const createdId = "local-created-genealogy";
uni.redirectTo({
url: `/pages/genealogy/g03-create-genealogy?step=ancestor&genealogyId=${createdId}`,
});
genealogyId.value =
updateLocalGenealogyPreview(genealogyId.value, createSnapshot) ||
createLocalGenealogyPreview(createSnapshot);
currentStep.value = "ancestor";
createState.value = "form";
}, 320);
submitTimer = timer;
};
const submitAncestor = () => {
@@ -363,19 +429,29 @@ const submitAncestor = () => {
return;
}
const ancestorSnapshot = Object.freeze({ ...ancestorForm });
isSubmitting.value = true;
ancestorState.value = "submitting";
submitTimer = setTimeout(() => {
const timer = setTimeout(() => {
if (submitTimer !== timer) return;
submitTimer = null;
isSubmitting.value = false;
ancestorState.value =
ancestorForm.personName.trim() === "失败" ? "error" : "success";
if (ancestorSnapshot.personName.trim() === "失败") {
ancestorState.value = "error";
return;
}
ancestorState.value = updateLocalGenealogyPreviewAncestor(
genealogyId.value,
ancestorSnapshot,
)
? "success"
: "error";
}, 320);
submitTimer = timer;
};
const enterOverview = () =>
uni.redirectTo({
url: `/pages/genealogy/g05-genealogy-overview?genealogyId=${genealogyId.value}`,
});
returnTo("G05", { genealogyId: genealogyId.value });
</script>
<style scoped lang="scss">