完成70%
This commit is contained in:
+125
-52
@@ -4,15 +4,16 @@
|
||||
class="edit-member-page"
|
||||
:class="{
|
||||
'edit-state--form': editState === 'form',
|
||||
'edit-state--preview': editState === 'preview',
|
||||
'edit-state--loading': editState === 'loading',
|
||||
'edit-state--error': editState === 'error',
|
||||
'edit-state--no-permission': editState === 'no-permission',
|
||||
}"
|
||||
>
|
||||
<ModulePageBackground module="tree" />
|
||||
<view class="edit-member-page__header"><PageHeader title="编辑成员" custom-back @back="requestBack" /></view>
|
||||
<view class="edit-member-panel">
|
||||
<view v-if="editState === 'form'" class="edit-member-form">
|
||||
<AppLoading v-if="editState === 'loading'" text="正在读取成员资料" description="请稍候,正在确认可编辑字段。" />
|
||||
|
||||
<view v-else-if="editState === 'form'" class="edit-member-form">
|
||||
<text class="form-eyebrow">成员档案维护</text>
|
||||
<text class="form-title">完善{{ originalMember.name }}的生命记录</text>
|
||||
<text class="form-copy">基础身份用于世系展示,生平说明会显示在有权限查看的成员档案中。</text>
|
||||
@@ -26,6 +27,10 @@
|
||||
</view>
|
||||
<text v-if="fieldErrors.name" class="field-error">{{ fieldErrors.name }}</text>
|
||||
|
||||
<view class="form-field">
|
||||
<text>别名</text>
|
||||
<input v-model="editForm.aliasName" placeholder="别名或曾用名" placeholder-class="form-placeholder" />
|
||||
</view>
|
||||
<view class="form-field">
|
||||
<text>字辈</text>
|
||||
<input v-model="editForm.generationName" maxlength="12" placeholder="例如:文字辈" placeholder-class="form-placeholder" />
|
||||
@@ -33,19 +38,43 @@
|
||||
<picker mode="date" :value="editForm.birthDate" @change="selectDate('birthDate', $event)">
|
||||
<view class="form-field form-field--picker"><text>出生日期</text><text>{{ editForm.birthDate || "未填写" }}</text></view>
|
||||
</picker>
|
||||
<view class="form-field">
|
||||
<text>出生农历</text>
|
||||
<input v-model="editForm.birthLunar" placeholder="按家谱记载填写" placeholder-class="form-placeholder" />
|
||||
</view>
|
||||
<view class="form-field">
|
||||
<text>出生地</text>
|
||||
<input v-model="editForm.birthPlace" placeholder="按家谱记载填写" placeholder-class="form-placeholder" />
|
||||
</view>
|
||||
<picker mode="date" :value="editForm.deathDate" @change="selectDate('deathDate', $event)">
|
||||
<view class="form-field form-field--picker"><text>离世日期</text><text>{{ editForm.deathDate || "在世或未填写" }}</text></view>
|
||||
</picker>
|
||||
<view class="form-field">
|
||||
<text>逝世农历</text>
|
||||
<input v-model="editForm.deathLunar" placeholder="按家谱记载填写" placeholder-class="form-placeholder" />
|
||||
</view>
|
||||
<view class="form-field">
|
||||
<text>逝世地</text>
|
||||
<input v-model="editForm.deathPlace" placeholder="按家谱记载填写" placeholder-class="form-placeholder" />
|
||||
</view>
|
||||
<view class="form-field">
|
||||
<text>安葬地</text>
|
||||
<input v-model="editForm.burialPlace" placeholder="按家谱记载填写" placeholder-class="form-placeholder" />
|
||||
</view>
|
||||
<view class="form-field form-field--summary">
|
||||
<text>人物简介</text>
|
||||
<textarea v-model="editForm.summary" auto-height maxlength="500" placeholder="记录生平、迁徙或重要经历" placeholder-class="form-placeholder" />
|
||||
</view>
|
||||
<view class="form-field form-field--summary">
|
||||
<text>备注</text>
|
||||
<textarea v-model="editForm.remark" auto-height placeholder="记录其他需要保留的信息" placeholder-class="form-placeholder" />
|
||||
</view>
|
||||
<text v-if="fieldErrors.dates" class="field-error">{{ fieldErrors.dates }}</text>
|
||||
|
||||
<text class="form-note">隐私字段只向本人和具备维护权限的家谱管理员展示。</text>
|
||||
<view class="form-action" @click="saveMember">
|
||||
<image src="/static/assets/foundation/transparent/a01-scroll-primary-v3.png" mode="scaleToFill" />
|
||||
<text>{{ isSubmitting ? "正在校验…" : "生成本地预览" }}</text>
|
||||
<text>{{ isSubmitting ? "正在保存…" : "保存资料" }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -78,10 +107,11 @@
|
||||
<script setup>
|
||||
import { computed, reactive, ref } from "vue";
|
||||
import { onBackPress, onLoad, onUnload } from "@dcloudio/uni-app";
|
||||
import AppLoading from "@/components/AppLoading.vue";
|
||||
import AppDialog from "@/components/AppDialog.vue";
|
||||
import ModulePageBackground from "@/components/ModulePageBackground.vue";
|
||||
import PageHeader from "@/components/PageHeader.vue";
|
||||
import { findTreeMemberPresentationFixture } from "@/data/mock.js";
|
||||
import { appApi, createRequestController, isRequestCancelled } from "@/utils/api.js";
|
||||
import { createDiscardConfirmation } from "@/utils/discard-confirmation.js";
|
||||
import {
|
||||
goBack,
|
||||
@@ -89,16 +119,32 @@ import {
|
||||
runBackGuard,
|
||||
} from "@/utils/navigation.js";
|
||||
|
||||
const editState = ref("form");
|
||||
const editState = ref("loading");
|
||||
const genealogyId = ref("");
|
||||
const personId = ref("");
|
||||
const isSubmitting = ref(false);
|
||||
const discardDialogVisible = ref(false);
|
||||
let submitTimer = null;
|
||||
const errorMessage = ref("");
|
||||
const failedAction = ref("load");
|
||||
const editRequestController = createRequestController();
|
||||
let loadSequence = 0;
|
||||
|
||||
const originalMember = ref(null);
|
||||
const baseline = ref("");
|
||||
const editForm = reactive({ name: "", generationName: "", birthDate: "", deathDate: "", summary: "" });
|
||||
const editForm = reactive({
|
||||
name: "",
|
||||
aliasName: "",
|
||||
generationName: "",
|
||||
birthDate: "",
|
||||
birthLunar: "",
|
||||
birthPlace: "",
|
||||
deathDate: "",
|
||||
deathLunar: "",
|
||||
deathPlace: "",
|
||||
burialPlace: "",
|
||||
summary: "",
|
||||
remark: "",
|
||||
});
|
||||
const fieldErrors = reactive({ name: "", dates: "" });
|
||||
|
||||
const formSnapshot = computed(() => JSON.stringify(editForm));
|
||||
@@ -107,16 +153,16 @@ const hasValidContext = computed(() =>
|
||||
);
|
||||
const isDirty = computed(
|
||||
() =>
|
||||
(editState.value === "form" || editState.value === "preview") &&
|
||||
editState.value === "form" &&
|
||||
Boolean(baseline.value) &&
|
||||
formSnapshot.value !== baseline.value,
|
||||
);
|
||||
const resultCopy = computed(() => ({
|
||||
preview: { eyebrow: "本地流程预览", title: `${editForm.name}的资料已通过本地校验`, copy: "尚未提交服务器,返回成员档案后不会显示本次修改。", action: "返回成员档案(不保存)" },
|
||||
error: hasValidContext.value
|
||||
? { eyebrow: "资料未保存", title: "暂时无法保存成员档案", copy: "当前修改仍保留,可返回表单后重试。", action: "返回修改" }
|
||||
: { eyebrow: "成员入口无效", title: "没有找到要编辑的成员", copy: "请从成员档案重新进入,页面不会创建临时成员身份。", action: "返回上一页" },
|
||||
"no-permission": { eyebrow: "权限不足", title: "当前账号不能编辑这位成员", copy: "本人或具备成员维护权限的家谱管理员才能修改档案。", action: "返回成员档案" },
|
||||
error: failedAction.value === "save"
|
||||
? { eyebrow: "保存失败", title: "成员档案尚未保存", copy: errorMessage.value || "服务未确认本次修改,请检查填写后重试。", action: "返回修改" }
|
||||
: hasValidContext.value
|
||||
? { eyebrow: "资料读取失败", title: "暂时无法读取成员档案", copy: errorMessage.value || "请返回后重试。", action: "重新读取" }
|
||||
: { eyebrow: "成员入口无效", title: "没有找到要编辑的成员", copy: errorMessage.value || "请从成员档案重新进入。", action: "返回上一页" },
|
||||
}[editState.value] || {}));
|
||||
const discardConfirmation = createDiscardConfirmation((visible) => {
|
||||
discardDialogVisible.value = visible;
|
||||
@@ -125,49 +171,55 @@ const requestDiscardConfirmation = discardConfirmation.request;
|
||||
const confirmDiscard = discardConfirmation.confirm;
|
||||
const cancelDiscard = discardConfirmation.cancel;
|
||||
|
||||
const loadMember = (id) => {
|
||||
const member = findTreeMemberPresentationFixture(genealogyId.value, id);
|
||||
if (!member) return false;
|
||||
originalMember.value = { ...member };
|
||||
if (["privacy", "forbidden"].includes(member.status)) {
|
||||
Object.assign(editForm, {
|
||||
name: member.name,
|
||||
generationName: "",
|
||||
birthDate: "",
|
||||
deathDate: "",
|
||||
summary: "",
|
||||
const loadMember = async () => {
|
||||
const activeLoad = ++loadSequence;
|
||||
editState.value = "loading";
|
||||
try {
|
||||
const member = await appApi.getPerson(genealogyId.value, personId.value, {
|
||||
requestController: editRequestController,
|
||||
});
|
||||
} else {
|
||||
if (activeLoad !== loadSequence) return;
|
||||
originalMember.value = member;
|
||||
Object.assign(editForm, {
|
||||
name: member.name,
|
||||
aliasName: member.aliasName || "",
|
||||
generationName: member.generationName || "",
|
||||
birthDate: member.birthDate || "",
|
||||
birthLunar: member.birthLunar || "",
|
||||
birthPlace: member.birthplace || "",
|
||||
deathDate: member.deathDate || "",
|
||||
summary: member.summary || "",
|
||||
deathLunar: member.deathLunar || "",
|
||||
deathPlace: member.deathPlace || "",
|
||||
burialPlace: member.burialPlace || "",
|
||||
summary: member.biography || "",
|
||||
remark: member.remark || "",
|
||||
});
|
||||
baseline.value = formSnapshot.value;
|
||||
errorMessage.value = "";
|
||||
failedAction.value = "load";
|
||||
editState.value = "form";
|
||||
} catch (error) {
|
||||
if (activeLoad !== loadSequence || isRequestCancelled(error)) return;
|
||||
originalMember.value = null;
|
||||
failedAction.value = "load";
|
||||
errorMessage.value = error?.message || "成员资料暂不可用。";
|
||||
editState.value = "error";
|
||||
}
|
||||
baseline.value = formSnapshot.value;
|
||||
return true;
|
||||
};
|
||||
|
||||
onLoad((query) => {
|
||||
genealogyId.value = String(query.genealogyId || "");
|
||||
personId.value = String(query.personId || "");
|
||||
const loaded = Boolean(genealogyId.value && personId.value) && loadMember(personId.value);
|
||||
editState.value = !loaded
|
||||
? "error"
|
||||
: ["privacy", "forbidden"].includes(originalMember.value.status)
|
||||
? "no-permission"
|
||||
: query.state === "preview"
|
||||
? "preview"
|
||||
: query.state === "error"
|
||||
? "error"
|
||||
: "form";
|
||||
if (!genealogyId.value || !personId.value || query.state === "error") {
|
||||
editState.value = "error";
|
||||
errorMessage.value = "当前家谱或成员上下文无效。";
|
||||
return;
|
||||
}
|
||||
void loadMember();
|
||||
});
|
||||
onUnload(() => {
|
||||
const timer = submitTimer;
|
||||
submitTimer = null;
|
||||
if (timer) clearTimeout(timer);
|
||||
loadSequence += 1;
|
||||
editRequestController.abort();
|
||||
discardConfirmation.dispose();
|
||||
});
|
||||
|
||||
@@ -193,17 +245,34 @@ const validateEditForm = () => {
|
||||
fieldErrors.dates = editForm.birthDate && editForm.deathDate && editForm.deathDate < editForm.birthDate ? "离世日期不能早于出生日期" : "";
|
||||
return !fieldErrors.name && !fieldErrors.dates;
|
||||
};
|
||||
const saveMember = () => {
|
||||
const saveMember = async () => {
|
||||
if (isSubmitting.value || !validateEditForm()) return;
|
||||
const submitSnapshot = Object.freeze({ ...editForm });
|
||||
isSubmitting.value = true;
|
||||
const timer = setTimeout(() => {
|
||||
if (submitTimer !== timer) return;
|
||||
editState.value = submitSnapshot.name.trim() === "失败" ? "error" : "preview";
|
||||
try {
|
||||
await appApi.updatePerson(genealogyId.value, personId.value, {
|
||||
name: editForm.name,
|
||||
aliasName: editForm.aliasName,
|
||||
generationName: editForm.generationName,
|
||||
birthDate: editForm.birthDate,
|
||||
birthLunar: editForm.birthLunar,
|
||||
birthPlace: editForm.birthPlace,
|
||||
deathDate: editForm.deathDate,
|
||||
deathLunar: editForm.deathLunar,
|
||||
deathPlace: editForm.deathPlace,
|
||||
burialPlace: editForm.burialPlace,
|
||||
biography: editForm.summary,
|
||||
remark: editForm.remark,
|
||||
}, { requestController: editRequestController });
|
||||
baseline.value = formSnapshot.value;
|
||||
await goBack();
|
||||
} catch (error) {
|
||||
if (isRequestCancelled(error)) return;
|
||||
failedAction.value = "save";
|
||||
errorMessage.value = error?.message || "服务未确认本次修改。";
|
||||
editState.value = "error";
|
||||
} finally {
|
||||
isSubmitting.value = false;
|
||||
submitTimer = null;
|
||||
}, 280);
|
||||
submitTimer = timer;
|
||||
}
|
||||
};
|
||||
const returnToMember = async () => {
|
||||
const confirmed = isDirty.value
|
||||
@@ -213,11 +282,15 @@ const returnToMember = async () => {
|
||||
return goBack();
|
||||
};
|
||||
const handleResultAction = () => {
|
||||
if (editState.value === "error" && hasValidContext.value) {
|
||||
if (failedAction.value === "save") {
|
||||
editState.value = "form";
|
||||
return;
|
||||
}
|
||||
return returnToMember();
|
||||
if (editState.value === "error") {
|
||||
if (!genealogyId.value || !personId.value) return returnToMember();
|
||||
return loadMember();
|
||||
}
|
||||
editState.value = "form";
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user