修改完成待测试

This commit is contained in:
2026-09-13 17:45:47 +08:00
parent 9ad572907b
commit bbc024f7f2
80 changed files with 3844 additions and 1672 deletions
+142 -42
View File
@@ -49,7 +49,7 @@
<picker
:range="sexOptions.map((item) => item.label)"
:value="optionIndex(sexOptions, editForm.sex)"
@change="selectOption('sex', sexOptions, $event)"
@change="selectSex"
>
<view class="form-field form-field--picker">
<text>性别</text
@@ -148,8 +148,28 @@
type="number"
placeholder="正整数"
placeholder-class="form-placeholder"
@blur="loadRankOptions"
/>
</view>
<picker
v-if="rankOptions.length"
:range="rankPickerLabels"
:value="rankOptionIndex"
:disabled="rankOptionsState !== 'ready'"
@change="selectRank"
>
<view class="form-field form-field--picker">
<text>排行称谓</text>
<text>{{ selectedRankName || "请选择" }}</text>
</view>
</picker>
<view v-else class="form-field form-field--disabled">
<text>排行称谓</text>
<text>{{ rankOptionStateLabel }}</text>
</view>
<text v-if="rankOptionsState === 'error'" class="field-error"
>排行配置暂未就绪请稍后重试</text
>
<picker
:range="personOptionLabels"
:value="personOptionIndex(editForm.fatherId)"
@@ -170,16 +190,15 @@
><text>{{ personOptionLabel(editForm.motherId) }}</text></view
>
</picker>
<picker
mode="date"
:value="editForm.birthDate"
@change="selectDate('birthDate', $event)"
<view
class="form-field form-field--picker"
role="button"
aria-label="选择出生日期"
@click="openDatePicker('birthDate', '选择出生日期')"
>
<view class="form-field form-field--picker"
><text>出生日期</text
><text>{{ editForm.birthDate || "未填写" }}</text></view
>
</picker>
<text>出生日期</text>
<text>{{ editForm.birthDate || "未填写" }}</text>
</view>
<picker
:range="lunarOptions.map((item) => item.label)"
:value="optionIndex(lunarOptions, editForm.birthLunar)"
@@ -257,17 +276,16 @@
placeholder-class="form-placeholder"
/>
</view>
<picker
<view
v-if="isDeceased"
mode="date"
:value="editForm.deathDate"
@change="selectDate('deathDate', $event)"
class="form-field form-field--picker"
role="button"
aria-label="选择离世日期"
@click="openDatePicker('deathDate', '选择离世日期')"
>
<view class="form-field form-field--picker"
><text>离世日期</text
><text>{{ editForm.deathDate || "在世或未填写" }}</text></view
>
</picker>
<text>离世日期</text>
<text>{{ editForm.deathDate || "在世或未填写" }}</text>
</view>
<picker
v-if="isDeceased"
:range="lunarOptions.map((item) => item.label)"
@@ -329,17 +347,16 @@
class="form-note"
>遗传病史属于敏感健康信息仅在已授权时读取和保存</text
>
<picker
<view
v-if="isDeceased"
mode="date"
:value="editForm.burialDate"
@change="selectDate('burialDate', $event)"
class="form-field form-field--picker"
role="button"
aria-label="选择安葬日期"
@click="openDatePicker('burialDate', '选择安葬日期')"
>
<view class="form-field form-field--picker"
><text>安葬日期</text
><text>{{ editForm.burialDate || "未填写" }}</text></view
>
</picker>
<text>安葬日期</text>
<text>{{ editForm.burialDate || "未填写" }}</text>
</view>
<view v-if="isDeceased" class="form-field">
<text>安葬地</text>
<input
@@ -361,15 +378,6 @@
}}</text>
</view>
</picker>
<view class="form-field">
<text>排序值</text>
<input
v-model="editForm.sortOrder"
type="number"
placeholder="可选整数,值越小越靠前"
placeholder-class="form-placeholder"
/>
</view>
<view class="form-field form-field--summary">
<text>人物简介</text>
<textarea
@@ -419,6 +427,14 @@
</view>
</view>
<MemberDatePickerSheet
:visible="datePickerVisible"
:title="datePickerTitle"
:value="datePickerValue"
@cancel="closeDatePicker"
@confirm="confirmDatePicker"
/>
<AppDialog
:visible="discardDialogVisible"
eyebrow="资料尚未保存"
@@ -439,6 +455,7 @@ 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 MemberDatePickerSheet from "@/components/tree/MemberDatePickerSheet.vue";
import ModulePageBackground from "@/components/ModulePageBackground.vue";
import PageHeader from "@/components/PageHeader.vue";
import {
@@ -476,11 +493,15 @@ const isAvatarUploading = ref(false);
const avatarFileName = ref("");
const avatarUploadError = ref("");
const discardDialogVisible = ref(false);
const datePickerVisible = ref(false);
const datePickerField = ref("");
const datePickerTitle = ref("选择日期");
const errorMessage = ref("");
const failedAction = ref("load");
const memberDetailRequestController = createRequestController();
const personOptionsRequestController = createRequestController();
const memberOptionsRequestController = createRequestController();
const rankOptionsRequestController = createRequestController();
const avatarUploadRequestController = createRequestController();
const memberUpdateRequestController = createRequestController();
const sensitiveProfileRequestController = createRequestController();
@@ -491,6 +512,8 @@ const dictionaryRequestControllers = {
};
let pageActive = true;
let loadSequence = 0;
let rankLoadSequence = 0;
let rankOptionsContext = "";
const originalMember = ref(null);
const baseline = ref("");
@@ -504,6 +527,7 @@ const editForm = reactive({
sex: "",
generation: "",
generationName: "",
rankId: "",
fatherId: "",
motherId: "",
avatarOssId: "",
@@ -541,6 +565,8 @@ const lunarOptions = memberFormOptions.lunar;
const personStatusOptions = memberFormOptions.personStatus;
const bindingModeOptions = memberFormOptions.bindingMode;
const personOptions = ref([{ label: "不选择", value: "" }]);
const rankOptionsState = ref("idle");
const rankOptions = ref([]);
const personOptionLabels = computed(() =>
personOptions.value.map((item) => item.label),
);
@@ -565,6 +591,26 @@ const memberOptionLabels = computed(() =>
memberBindingOptions.value.map((item) => item.label),
);
const isDeceased = computed(() => editForm.personStatus === "1");
const datePickerValue = computed(() => editForm[datePickerField.value] || "");
const rankOptionIndex = computed(() => {
const index = rankOptions.value.findIndex((item) => item.rankId === editForm.rankId);
return index < 0 ? 0 : index + 1;
});
const rankPickerLabels = computed(() => [
"请选择排行称谓",
...rankOptions.value.map((item) => item.rankName),
]);
const selectedRankName = computed(
() =>
rankOptions.value.find((item) => item.rankId === editForm.rankId)?.rankName ||
(editForm.rankId === originalMember.value?.rankId ? originalMember.value?.rankName : "") ||
"",
);
const rankOptionStateLabel = computed(() => {
if (rankOptionsState.value === "loading") return "正在读取";
if (rankOptionsState.value === "error") return "暂时无法读取";
return selectedRankName.value || "暂无可选排行";
});
const formSnapshot = computed(() => JSON.stringify(editForm));
const hasValidContext = computed(() =>
@@ -654,6 +700,7 @@ const loadMember = async () => {
sex: member.sex || "",
generation: member.generation || "",
generationName: member.generationName || "",
rankId: member.rankId || "",
fatherId:
member.relatives.find((item) => item.relation === "父亲")?.id || "",
motherId:
@@ -696,6 +743,8 @@ const loadMember = async () => {
errorMessage.value = "";
failedAction.value = "load";
editState.value = "form";
rankOptionsContext = `${Number(editForm.generation)}:${String(editForm.sex || "")}`;
void loadRankOptions();
} catch (error) {
if (!pageActive || activeLoad !== loadSequence || isRequestCancelled(error)) return;
originalMember.value = null;
@@ -720,7 +769,7 @@ const loadPersonOptions = async () => {
return null;
}
const name = item.name;
return { value: personOptionId, label: `${name}${personOptionId}` };
return { value: personOptionId, label: name };
})
.filter(Boolean);
personOptions.value = [{ label: "不选择", value: "" }, ...options];
@@ -779,6 +828,32 @@ const loadMemberOptions = async () => {
memberOptionsState.value = "error";
}
};
const loadRankOptions = async () => {
const generation = Number(editForm.generation);
const sex = String(editForm.sex || "");
const context = `${generation}:${sex}`;
const activeLoad = ++rankLoadSequence;
if (!Number.isSafeInteger(generation) || generation < 1 || !["0", "1", "2"].includes(sex)) {
rankOptions.value = [];
rankOptionsState.value = "idle";
return;
}
if (context !== rankOptionsContext) editForm.rankId = "";
rankOptionsContext = context;
rankOptionsState.value = "loading";
try {
const options = await lineageApi.getRankOptions(genealogyId.value, generation, sex, {
requestController: rankOptionsRequestController,
});
if (!pageActive || activeLoad !== rankLoadSequence) return;
rankOptions.value = options;
rankOptionsState.value = "ready";
} catch (error) {
if (!pageActive || activeLoad !== rankLoadSequence || isRequestCancelled(error)) return;
rankOptions.value = [];
rankOptionsState.value = "error";
}
};
onLoad((query) => {
genealogyId.value = String(query?.genealogyId || "");
@@ -802,6 +877,7 @@ onUnload(() => {
memberDetailRequestController.abort();
personOptionsRequestController.abort();
memberOptionsRequestController.abort();
rankOptionsRequestController.abort();
avatarUploadRequestController.abort();
memberUpdateRequestController.abort();
sensitiveProfileRequestController.abort();
@@ -811,10 +887,13 @@ onUnload(() => {
const requestBack = () =>
runBackGuard({
transientOpen: discardDialogVisible.value,
transientOpen: datePickerVisible.value || discardDialogVisible.value,
dirty: isDirty.value,
submitting: isSubmitting.value || isAvatarUploading.value,
"close-transient": cancelDiscard,
"close-transient": () => {
if (datePickerVisible.value) return closeDatePicker();
return cancelDiscard();
},
"block-submitting": () => true,
"confirm-discard": requestDiscardConfirmation,
});
@@ -829,6 +908,16 @@ const optionLabel = findMemberOptionLabel;
const selectOption = (field, options, event) => {
updateMemberFormOption(editForm, field, options, event);
};
const selectSex = (event) => {
const previousSex = editForm.sex;
selectOption("sex", sexOptions, event);
if (editForm.sex !== previousSex) editForm.rankId = "";
void loadRankOptions();
};
const selectRank = (event) => {
const selectedIndex = Number(event.detail.value) - 1;
editForm.rankId = rankOptions.value[selectedIndex]?.rankId || "";
};
const selectBindingMode = (event) => {
updateMemberBindingMode(editForm, event);
fieldErrors.bindingMode = "";
@@ -880,9 +969,19 @@ const uploadAvatar = async () => {
if (pageActive) isAvatarUploading.value = false;
}
};
const selectDate = (field, event) => {
editForm[field] = event.detail.value || "";
const openDatePicker = (field, title) => {
datePickerField.value = field;
datePickerTitle.value = title;
datePickerVisible.value = true;
};
const closeDatePicker = () => {
datePickerVisible.value = false;
};
const confirmDatePicker = (value) => {
if (!datePickerField.value) return closeDatePicker();
editForm[datePickerField.value] = value;
fieldErrors.dates = "";
closeDatePicker();
};
const validateEditForm = () => {
fieldErrors.name = editForm.name.trim() ? "" : "请填写成员姓名";
@@ -936,6 +1035,7 @@ const saveMember = async () => {
? Number(editForm.generation)
: undefined,
generationName: editForm.generationName,
rankId: editForm.rankId,
fatherId: editForm.fatherId,
motherId: editForm.motherId,
avatarOssId: editForm.avatarOssId,