完成50%
This commit is contained in:
@@ -4,13 +4,13 @@
|
||||
class="relationship-page"
|
||||
:class="{
|
||||
'relationship-state--form': relationshipState === 'form',
|
||||
'relationship-state--success': relationshipState === 'success',
|
||||
'relationship-state--preview': relationshipState === 'preview',
|
||||
'relationship-state--conflict': relationshipState === 'conflict',
|
||||
'relationship-state--error': relationshipState === 'error',
|
||||
}"
|
||||
>
|
||||
<ModulePageBackground module="tree" />
|
||||
<view class="relationship-page__header"><PageHeader title="关系维护" /></view>
|
||||
<view class="relationship-page__header"><PageHeader title="关系维护" custom-back @back="requestBack" /></view>
|
||||
<view class="relationship-panel">
|
||||
<view v-if="relationshipState === 'form'" class="relationship-form">
|
||||
<text class="form-eyebrow">亲属关系校正</text>
|
||||
@@ -40,7 +40,7 @@
|
||||
<text class="form-note">父母子女关系会改变世系位置;配偶和兄弟姐妹关系不会自动改写现有父母。</text>
|
||||
<view class="form-action" @click="saveRelationship">
|
||||
<image src="/static/assets/foundation/transparent/a01-scroll-primary-v3.png" mode="scaleToFill" />
|
||||
<text>{{ isSubmitting ? "正在校验…" : "校验并保存关系" }}</text>
|
||||
<text>{{ isSubmitting ? "正在校验…" : "生成本地预览" }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
</view>
|
||||
<view v-else class="form-action" @click="handleResultAction">
|
||||
<image src="/static/assets/foundation/transparent/a01-scroll-primary-v3.png" mode="scaleToFill" />
|
||||
<text>{{ relationshipState === "success" ? "返回世系树" : "重新选择" }}</text>
|
||||
<text>{{ relationshipState === "preview" ? "返回世系树(不保存)" : hasValidContext ? "重新选择" : "返回上一页" }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -68,42 +68,60 @@
|
||||
eyebrow="关系校验规则"
|
||||
title="为什么不能保存这段关系"
|
||||
:message="conflictReason || '同一成员不能成为自己的亲属,也不能形成上下代循环或重复父母关系。'"
|
||||
:close-on-mask="false"
|
||||
@confirm="conflictDialogVisible = false"
|
||||
@close="conflictDialogVisible = false"
|
||||
/>
|
||||
<AppDialog
|
||||
:visible="discardDialogVisible"
|
||||
eyebrow="关系尚未保存"
|
||||
title="要放弃本次关系调整吗"
|
||||
message="当前关系只在本页预览,确认返回后不会修改世系。"
|
||||
cancel-text="继续核对"
|
||||
confirm-text="放弃并返回"
|
||||
show-cancel
|
||||
:close-on-mask="false"
|
||||
@cancel="cancelDiscard"
|
||||
@confirm="confirmDiscard"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, reactive, ref } from "vue";
|
||||
import { onLoad, onUnload } from "@dcloudio/uni-app";
|
||||
import { onBackPress, onLoad, onUnload } from "@dcloudio/uni-app";
|
||||
import AppDialog from "@/components/AppDialog.vue";
|
||||
import ModulePageBackground from "@/components/ModulePageBackground.vue";
|
||||
import PageHeader from "@/components/PageHeader.vue";
|
||||
import { genealogyContext } from "@/utils/genealogy-context.js";
|
||||
import { listTreeMemberFixtures } from "@/data/mock.js";
|
||||
import { createDiscardConfirmation } from "@/utils/discard-confirmation.js";
|
||||
import {
|
||||
goBack,
|
||||
handleBackPress,
|
||||
returnTo,
|
||||
runBackGuard,
|
||||
} from "@/utils/navigation.js";
|
||||
|
||||
const relationshipState = ref("form");
|
||||
const genealogyId = ref("");
|
||||
const personId = ref("");
|
||||
const isSubmitting = ref(false);
|
||||
const conflictDialogVisible = ref(false);
|
||||
const discardDialogVisible = ref(false);
|
||||
const conflictReason = ref("");
|
||||
let submitTimer = null;
|
||||
|
||||
const memberOptions = [
|
||||
{ id: "101", name: "汤文远", generation: 12, parentId: "" },
|
||||
{ id: "102", name: "汤正国", generation: 13, parentId: "101" },
|
||||
{ id: "103", name: "汤正华", generation: 13, parentId: "101" },
|
||||
{ id: "104", name: "汤凯", generation: 14, parentId: "102" },
|
||||
{ id: "105", name: "汤悦", generation: 14, parentId: "102" },
|
||||
];
|
||||
const memberOptions = computed(() => listTreeMemberFixtures(genealogyId.value));
|
||||
const relationshipOptions = ["父子(当前成员为父)", "父女(当前成员为父)", "母子(当前成员为母)", "母女(当前成员为母)", "配偶", "兄弟姐妹"];
|
||||
const relationshipForm = reactive({ sourceId: "", targetId: "", relationship: "" });
|
||||
const fieldErrors = reactive({ sourceId: "", targetId: "", relationship: "" });
|
||||
const memberLabels = computed(() => memberOptions.map((item) => `${item.name} · 第 ${item.generation} 世`));
|
||||
const memberById = computed(() => new Map(memberOptions.map((item) => [item.id, item])));
|
||||
const sourceIndex = computed(() => Math.max(0, memberOptions.findIndex((item) => item.id === relationshipForm.sourceId)));
|
||||
const targetIndex = computed(() => Math.max(0, memberOptions.findIndex((item) => item.id === relationshipForm.targetId)));
|
||||
const baseline = ref("");
|
||||
const memberLabels = computed(() => memberOptions.value.map((item) => `${item.name} · 第 ${item.generation} 世`));
|
||||
const memberById = computed(() => new Map(memberOptions.value.map((item) => [item.id, item])));
|
||||
const hasValidContext = computed(() =>
|
||||
Boolean(genealogyId.value && memberById.value.has(personId.value)),
|
||||
);
|
||||
const sourceIndex = computed(() => Math.max(0, memberOptions.value.findIndex((item) => item.id === relationshipForm.sourceId)));
|
||||
const targetIndex = computed(() => Math.max(0, memberOptions.value.findIndex((item) => item.id === relationshipForm.targetId)));
|
||||
const relationshipIndex = computed(() => Math.max(0, relationshipOptions.indexOf(relationshipForm.relationship)));
|
||||
const memberName = (id) => memberById.value.get(String(id))?.name || "";
|
||||
const relationshipPreview = computed(
|
||||
@@ -111,25 +129,67 @@ const relationshipPreview = computed(
|
||||
? `${memberName(relationshipForm.sourceId)}将以“${relationshipForm.relationship}”关联${memberName(relationshipForm.targetId)}。`
|
||||
: "完成三项选择后,这里会说明世系位置将如何变化。",
|
||||
);
|
||||
const formSnapshot = computed(() => JSON.stringify(relationshipForm));
|
||||
const isDirty = computed(() =>
|
||||
Boolean(baseline.value) && formSnapshot.value !== baseline.value,
|
||||
);
|
||||
const resultCopy = computed(() => ({
|
||||
success: { eyebrow: "关系已保存", title: "世系关系已经更新", copy: relationshipPreview.value },
|
||||
preview: { eyebrow: "本地流程预览", title: "关系校验已经通过", copy: `${relationshipPreview.value} 尚未提交服务器,返回后世系不会变化。` },
|
||||
conflict: { eyebrow: "发现关系冲突", title: "这段关系会造成世系矛盾", copy: conflictReason.value },
|
||||
error: { eyebrow: "关系未保存", title: "暂时无法完成关系调整", copy: "当前选择仍然保留,可返回后重新校验。" },
|
||||
error: hasValidContext.value
|
||||
? { eyebrow: "关系未保存", title: "暂时无法完成关系调整", copy: "当前选择仍然保留,可返回后重新校验。" }
|
||||
: { eyebrow: "成员入口无效", title: "没有找到要调整的成员", copy: "请从世系树重新进入,页面不会回退到其他成员。" },
|
||||
}[relationshipState.value] || {}));
|
||||
const discardConfirmation = createDiscardConfirmation((visible) => {
|
||||
discardDialogVisible.value = visible;
|
||||
});
|
||||
const requestDiscardConfirmation = discardConfirmation.request;
|
||||
const confirmDiscard = discardConfirmation.confirm;
|
||||
const cancelDiscard = discardConfirmation.cancel;
|
||||
|
||||
onLoad((query) => {
|
||||
genealogyId.value = query.genealogyId || genealogyContext.getCurrentGenealogyId() || "";
|
||||
personId.value = query.personId || "";
|
||||
relationshipForm.sourceId = personId.value && memberById.value.has(String(personId.value)) ? String(personId.value) : memberOptions[0].id;
|
||||
if (genealogyId.value) genealogyContext.setCurrentGenealogyId(genealogyId.value);
|
||||
relationshipState.value = query.state === "success" ? "success" : query.state === "conflict" ? "conflict" : query.state === "error" ? "error" : "form";
|
||||
genealogyId.value = String(query.genealogyId || "");
|
||||
personId.value = String(query.personId || "");
|
||||
relationshipForm.sourceId = hasValidContext.value ? personId.value : "";
|
||||
baseline.value = formSnapshot.value;
|
||||
relationshipState.value = !hasValidContext.value || query.state === "error"
|
||||
? "error"
|
||||
: query.state === "preview"
|
||||
? "preview"
|
||||
: query.state === "conflict"
|
||||
? "conflict"
|
||||
: "form";
|
||||
if (relationshipState.value === "conflict") conflictReason.value = "目标成员已经存在父级关系,请先核对原关系。";
|
||||
});
|
||||
onUnload(() => { if (submitTimer) clearTimeout(submitTimer); });
|
||||
onUnload(() => {
|
||||
const timer = submitTimer;
|
||||
submitTimer = null;
|
||||
if (timer) clearTimeout(timer);
|
||||
discardConfirmation.dispose();
|
||||
});
|
||||
|
||||
const closeTransient = () => {
|
||||
if (conflictDialogVisible.value) {
|
||||
conflictDialogVisible.value = false;
|
||||
return;
|
||||
}
|
||||
cancelDiscard();
|
||||
};
|
||||
const requestBack = () =>
|
||||
runBackGuard({
|
||||
transientOpen: conflictDialogVisible.value || discardDialogVisible.value,
|
||||
dirty: isDirty.value,
|
||||
submitting: isSubmitting.value,
|
||||
"close-transient": closeTransient,
|
||||
"block-submitting": () => true,
|
||||
"confirm-discard": requestDiscardConfirmation,
|
||||
});
|
||||
|
||||
onBackPress((event) => handleBackPress(event, requestBack));
|
||||
|
||||
const clearFieldError = (field) => { fieldErrors[field] = ""; };
|
||||
const selectMember = (field, event) => {
|
||||
relationshipForm[field] = memberOptions[Number(event.detail.value)]?.id || "";
|
||||
relationshipForm[field] = memberOptions.value[Number(event.detail.value)]?.id || "";
|
||||
clearFieldError(field);
|
||||
};
|
||||
const selectRelationship = (event) => {
|
||||
@@ -174,16 +234,30 @@ const saveRelationship = () => {
|
||||
if (conflictReason.value) relationshipState.value = "conflict";
|
||||
return;
|
||||
}
|
||||
const submitSnapshot = Object.freeze({ ...relationshipForm });
|
||||
isSubmitting.value = true;
|
||||
submitTimer = setTimeout(() => {
|
||||
relationshipState.value = relationshipForm.relationship === "失败" ? "error" : "success";
|
||||
const timer = setTimeout(() => {
|
||||
if (submitTimer !== timer) return;
|
||||
relationshipState.value = submitSnapshot.relationship === "失败" ? "error" : "preview";
|
||||
isSubmitting.value = false;
|
||||
submitTimer = null;
|
||||
}, 280);
|
||||
submitTimer = timer;
|
||||
};
|
||||
const returnToTree = async () => {
|
||||
const confirmed = isDirty.value
|
||||
? await requestDiscardConfirmation()
|
||||
: true;
|
||||
if (!confirmed) return false;
|
||||
return returnTo("T01", { genealogyId: genealogyId.value });
|
||||
};
|
||||
const handleResultAction = () => {
|
||||
if (relationshipState.value === "error") { relationshipState.value = "form"; return; }
|
||||
uni.navigateBack();
|
||||
if (relationshipState.value === "error") {
|
||||
if (!hasValidContext.value) return goBack();
|
||||
relationshipState.value = "form";
|
||||
return;
|
||||
}
|
||||
return returnToTree();
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user