修改部分样式
This commit is contained in:
+485
-133
@@ -9,124 +9,279 @@
|
||||
}"
|
||||
>
|
||||
<ModulePageBackground module="tree" />
|
||||
<view class="edit-member-page__header"><PageHeader title="编辑成员" custom-back @back="requestBack" /></view>
|
||||
<view class="edit-member-page__header"
|
||||
><PageHeader title="编辑成员" custom-back @back="requestBack"
|
||||
/></view>
|
||||
<view class="edit-member-panel">
|
||||
<AppLoading v-if="editState === 'loading'" text="正在读取成员资料" description="请稍候,正在确认可编辑字段。" />
|
||||
<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>
|
||||
<text class="form-copy"
|
||||
>基础身份用于世系展示,生平说明会显示在有权限查看的成员档案中。</text
|
||||
>
|
||||
|
||||
<view class="member-context">
|
||||
<text>成员身份</text><text>第 {{ originalMember.generation }} 世 · {{ originalMember.branch }}</text>
|
||||
<text>成员身份</text
|
||||
><text
|
||||
>第 {{ originalMember.generation }} 世 ·
|
||||
{{ originalMember.branch }}</text
|
||||
>
|
||||
</view>
|
||||
<view class="form-field">
|
||||
<text>姓名</text>
|
||||
<input v-model="editForm.name" maxlength="20" placeholder="请输入姓名" placeholder-class="form-placeholder" @input="clearError('name')" />
|
||||
<input
|
||||
v-model="editForm.name"
|
||||
maxlength="20"
|
||||
placeholder="请输入姓名"
|
||||
placeholder-class="form-placeholder"
|
||||
@input="clearError('name')"
|
||||
/>
|
||||
</view>
|
||||
<text v-if="fieldErrors.name" class="field-error">{{ fieldErrors.name }}</text>
|
||||
<text v-if="fieldErrors.name" class="field-error">{{
|
||||
fieldErrors.name
|
||||
}}</text>
|
||||
|
||||
<view class="form-field">
|
||||
<text>人物编号</text>
|
||||
<input v-model="editForm.personNo" maxlength="40" placeholder="不填则由服务端生成" placeholder-class="form-placeholder" />
|
||||
<input
|
||||
v-model="editForm.personNo"
|
||||
maxlength="40"
|
||||
placeholder="不填则由服务端生成"
|
||||
placeholder-class="form-placeholder"
|
||||
/>
|
||||
</view>
|
||||
<picker :range="sexOptions.map((item) => item.label)" :value="optionIndex(sexOptions, editForm.sex)" @change="selectOption('sex', sexOptions, $event)">
|
||||
<picker
|
||||
:range="sexOptions.map((item) => item.label)"
|
||||
:value="optionIndex(sexOptions, editForm.sex)"
|
||||
@change="selectOption('sex', sexOptions, $event)"
|
||||
>
|
||||
<view class="form-field form-field--picker">
|
||||
<text>性别</text><text>{{ optionLabel(sexOptions, editForm.sex) || "请选择" }}</text>
|
||||
<text>性别</text
|
||||
><text>{{
|
||||
optionLabel(sexOptions, editForm.sex) || "请选择"
|
||||
}}</text>
|
||||
</view>
|
||||
</picker>
|
||||
<picker :range="bindingModeOptions.map((item) => item.label)" :value="optionIndex(bindingModeOptions, editForm.bindingMode)" @change="selectBindingMode">
|
||||
<picker
|
||||
:range="bindingModeOptions.map((item) => item.label)"
|
||||
:value="optionIndex(bindingModeOptions, editForm.bindingMode)"
|
||||
@change="selectBindingMode"
|
||||
>
|
||||
<view class="form-field form-field--picker">
|
||||
<text>身份认领</text><text>{{ optionLabel(bindingModeOptions, editForm.bindingMode) }}</text>
|
||||
<text>身份认领</text
|
||||
><text>{{
|
||||
optionLabel(bindingModeOptions, editForm.bindingMode)
|
||||
}}</text>
|
||||
</view>
|
||||
</picker>
|
||||
<view class="form-field">
|
||||
<text>业务用户</text>
|
||||
<text class="form-field__hint">{{ appUserBindingHint }}</text>
|
||||
</view>
|
||||
<text v-if="fieldErrors.bindingMode" class="field-error">{{ fieldErrors.bindingMode }}</text>
|
||||
<text v-if="fieldErrors.bindingMode" class="field-error">{{
|
||||
fieldErrors.bindingMode
|
||||
}}</text>
|
||||
<view class="form-field form-field--upload">
|
||||
<text>头像</text>
|
||||
<view>
|
||||
<button class="upload-button" :disabled="isAvatarUploading || isSubmitting" @click="uploadAvatar">{{ isAvatarUploading ? "上传中…" : "选择图片" }}</button>
|
||||
<text v-if="avatarFileName" class="upload-receipt">已上传:{{ avatarFileName }}</text>
|
||||
<button
|
||||
class="upload-button"
|
||||
:disabled="isAvatarUploading || isSubmitting"
|
||||
@click="uploadAvatar"
|
||||
>
|
||||
{{ isAvatarUploading ? "上传中…" : "选择图片" }}
|
||||
</button>
|
||||
<text v-if="avatarFileName" class="upload-receipt"
|
||||
>已上传:{{ avatarFileName }}</text
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
<text v-if="avatarUploadError" class="field-error">{{ avatarUploadError }}</text>
|
||||
<text v-if="avatarUploadError" class="field-error">{{
|
||||
avatarUploadError
|
||||
}}</text>
|
||||
|
||||
<view class="form-field">
|
||||
<text>别名</text>
|
||||
<input v-model="editForm.aliasName" placeholder="别名或曾用名" placeholder-class="form-placeholder" />
|
||||
<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" />
|
||||
<input
|
||||
v-model="editForm.generationName"
|
||||
maxlength="12"
|
||||
placeholder="例如:文字辈"
|
||||
placeholder-class="form-placeholder"
|
||||
/>
|
||||
</view>
|
||||
<view class="form-field">
|
||||
<text>世代</text>
|
||||
<input v-model="editForm.generation" type="number" placeholder="正整数" placeholder-class="form-placeholder" />
|
||||
<input
|
||||
v-model="editForm.generation"
|
||||
type="number"
|
||||
placeholder="正整数"
|
||||
placeholder-class="form-placeholder"
|
||||
/>
|
||||
</view>
|
||||
<picker :range="personOptionLabels" :value="personOptionIndex(editForm.fatherId)" @change="selectPerson('fatherId', $event)">
|
||||
<view class="form-field form-field--picker"><text>父亲</text><text>{{ personOptionLabel(editForm.fatherId) }}</text></view>
|
||||
<picker
|
||||
:range="personOptionLabels"
|
||||
:value="personOptionIndex(editForm.fatherId)"
|
||||
@change="selectPerson('fatherId', $event)"
|
||||
>
|
||||
<view class="form-field form-field--picker"
|
||||
><text>父亲</text
|
||||
><text>{{ personOptionLabel(editForm.fatherId) }}</text></view
|
||||
>
|
||||
</picker>
|
||||
<picker :range="personOptionLabels" :value="personOptionIndex(editForm.motherId)" @change="selectPerson('motherId', $event)">
|
||||
<view class="form-field form-field--picker"><text>母亲</text><text>{{ personOptionLabel(editForm.motherId) }}</text></view>
|
||||
<picker
|
||||
:range="personOptionLabels"
|
||||
:value="personOptionIndex(editForm.motherId)"
|
||||
@change="selectPerson('motherId', $event)"
|
||||
>
|
||||
<view class="form-field form-field--picker"
|
||||
><text>母亲</text
|
||||
><text>{{ personOptionLabel(editForm.motherId) }}</text></view
|
||||
>
|
||||
</picker>
|
||||
<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
|
||||
mode="date"
|
||||
:value="editForm.birthDate"
|
||||
@change="selectDate('birthDate', $event)"
|
||||
>
|
||||
<view class="form-field form-field--picker"
|
||||
><text>出生日期</text
|
||||
><text>{{ editForm.birthDate || "未填写" }}</text></view
|
||||
>
|
||||
</picker>
|
||||
<picker :range="lunarOptions.map((item) => item.label)" :value="optionIndex(lunarOptions, editForm.birthLunar)" @change="selectOption('birthLunar', lunarOptions, $event)">
|
||||
<picker
|
||||
:range="lunarOptions.map((item) => item.label)"
|
||||
:value="optionIndex(lunarOptions, editForm.birthLunar)"
|
||||
@change="selectOption('birthLunar', lunarOptions, $event)"
|
||||
>
|
||||
<view class="form-field form-field--picker">
|
||||
<text>出生农历</text><text>{{ optionLabel(lunarOptions, editForm.birthLunar) || "请选择" }}</text>
|
||||
<text>出生农历</text
|
||||
><text>{{
|
||||
optionLabel(lunarOptions, editForm.birthLunar) || "请选择"
|
||||
}}</text>
|
||||
</view>
|
||||
</picker>
|
||||
<view class="form-field">
|
||||
<text>出生地</text>
|
||||
<input v-model="editForm.birthPlace" placeholder="按家谱记载填写" placeholder-class="form-placeholder" />
|
||||
<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
|
||||
mode="date"
|
||||
:value="editForm.deathDate"
|
||||
@change="selectDate('deathDate', $event)"
|
||||
>
|
||||
<view class="form-field form-field--picker"
|
||||
><text>离世日期</text
|
||||
><text>{{ editForm.deathDate || "在世或未填写" }}</text></view
|
||||
>
|
||||
</picker>
|
||||
<picker :range="lunarOptions.map((item) => item.label)" :value="optionIndex(lunarOptions, editForm.deathLunar)" @change="selectOption('deathLunar', lunarOptions, $event)">
|
||||
<picker
|
||||
:range="lunarOptions.map((item) => item.label)"
|
||||
:value="optionIndex(lunarOptions, editForm.deathLunar)"
|
||||
@change="selectOption('deathLunar', lunarOptions, $event)"
|
||||
>
|
||||
<view class="form-field form-field--picker">
|
||||
<text>逝世农历</text><text>{{ optionLabel(lunarOptions, editForm.deathLunar) || "请选择" }}</text>
|
||||
<text>逝世农历</text
|
||||
><text>{{
|
||||
optionLabel(lunarOptions, editForm.deathLunar) || "请选择"
|
||||
}}</text>
|
||||
</view>
|
||||
</picker>
|
||||
<view class="form-field">
|
||||
<text>逝世地</text>
|
||||
<input v-model="editForm.deathPlace" placeholder="按家谱记载填写" placeholder-class="form-placeholder" />
|
||||
<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" />
|
||||
<input
|
||||
v-model="editForm.burialPlace"
|
||||
placeholder="按家谱记载填写"
|
||||
placeholder-class="form-placeholder"
|
||||
/>
|
||||
</view>
|
||||
<picker :range="personStatusOptions.map((item) => item.label)" :value="optionIndex(personStatusOptions, editForm.personStatus)" @change="selectOption('personStatus', personStatusOptions, $event)">
|
||||
<picker
|
||||
:range="personStatusOptions.map((item) => item.label)"
|
||||
:value="optionIndex(personStatusOptions, editForm.personStatus)"
|
||||
@change="selectOption('personStatus', personStatusOptions, $event)"
|
||||
>
|
||||
<view class="form-field form-field--picker">
|
||||
<text>人物状态</text><text>{{ optionLabel(personStatusOptions, editForm.personStatus) || "请选择" }}</text>
|
||||
<text>人物状态</text
|
||||
><text>{{
|
||||
optionLabel(personStatusOptions, editForm.personStatus) ||
|
||||
"请选择"
|
||||
}}</text>
|
||||
</view>
|
||||
</picker>
|
||||
<view class="form-field">
|
||||
<text>排序值</text>
|
||||
<input v-model="editForm.sortOrder" type="number" placeholder="可选整数,值越小越靠前" placeholder-class="form-placeholder" />
|
||||
<input
|
||||
v-model="editForm.sortOrder"
|
||||
type="number"
|
||||
placeholder="可选整数,值越小越靠前"
|
||||
placeholder-class="form-placeholder"
|
||||
/>
|
||||
</view>
|
||||
<view class="form-field">
|
||||
<text>关系名称</text>
|
||||
<input v-model="editForm.relationName" maxlength="30" placeholder="可选关系显示名称" placeholder-class="form-placeholder" />
|
||||
<input
|
||||
v-model="editForm.relationName"
|
||||
maxlength="30"
|
||||
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" />
|
||||
<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" />
|
||||
<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 v-if="fieldErrors.dates" class="field-error">{{
|
||||
fieldErrors.dates
|
||||
}}</text>
|
||||
|
||||
<text class="form-note">隐私字段只向本人和具备维护权限的家谱管理员展示。</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" />
|
||||
<image
|
||||
src="/static/assets/foundation/transparent/a01-scroll-primary-v3.png"
|
||||
mode="scaleToFill"
|
||||
/>
|
||||
<text>{{ isSubmitting ? "正在保存…" : "保存资料" }}</text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -136,7 +291,10 @@
|
||||
<text class="form-title">{{ resultCopy.title }}</text>
|
||||
<text class="form-copy">{{ resultCopy.copy }}</text>
|
||||
<view class="form-action" @click="handleResultAction">
|
||||
<image src="/static/assets/foundation/transparent/a01-scroll-primary-v3.png" mode="scaleToFill" />
|
||||
<image
|
||||
src="/static/assets/foundation/transparent/a01-scroll-primary-v3.png"
|
||||
mode="scaleToFill"
|
||||
/>
|
||||
<text>{{ resultCopy.action }}</text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -164,14 +322,17 @@ 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 { appApi, createRequestController, isRequestCancelled } from "@/utils/api.js";
|
||||
import { isImagePickCancelled, pickAndUploadImage } from "@/utils/resumable-image-upload.js";
|
||||
import { createDiscardConfirmation } from "@/utils/discard-confirmation.js";
|
||||
import {
|
||||
goBack,
|
||||
handleBackPress,
|
||||
runBackGuard,
|
||||
} from "@/utils/navigation.js";
|
||||
appApi,
|
||||
createRequestController,
|
||||
isRequestCancelled,
|
||||
} from "@/utils/api.js";
|
||||
import {
|
||||
isImagePickCancelled,
|
||||
pickAndUploadImage,
|
||||
} from "@/utils/resumable-image-upload.js";
|
||||
import { createDiscardConfirmation } from "@/utils/discard-confirmation.js";
|
||||
import { goBack, handleBackPress, runBackGuard } from "@/utils/navigation.js";
|
||||
|
||||
const editState = ref("loading");
|
||||
const genealogyId = ref("");
|
||||
@@ -235,11 +396,17 @@ const bindingModeOptions = Object.freeze([
|
||||
{ label: "绑定指定用户", value: "SPECIFIED" },
|
||||
]);
|
||||
const personOptions = ref([{ label: "不选择", value: "" }]);
|
||||
const personOptionLabels = computed(() => personOptions.value.map((item) => item.label));
|
||||
const personOptionLabels = computed(() =>
|
||||
personOptions.value.map((item) => item.label),
|
||||
);
|
||||
const appUserBindingHint = computed(() => {
|
||||
if (editForm.bindingMode === "NONE") return "不绑定账号,保存时不提交业务用户 ID";
|
||||
if (editForm.bindingMode === "SELF") return "由服务端从 Token 绑定当前登录账号,保存时不提交业务用户 ID";
|
||||
return editForm.appUserId ? "保留当前已认领的指定业务用户" : "需先选择指定业务用户;当前没有可用候选接口";
|
||||
if (editForm.bindingMode === "NONE")
|
||||
return "不绑定账号,保存时不提交业务用户 ID";
|
||||
if (editForm.bindingMode === "SELF")
|
||||
return "由服务端从 Token 绑定当前登录账号,保存时不提交业务用户 ID";
|
||||
return editForm.appUserId
|
||||
? "保留当前已认领的指定业务用户"
|
||||
: "需先选择指定业务用户;当前没有可用候选接口";
|
||||
});
|
||||
|
||||
const formSnapshot = computed(() => JSON.stringify(editForm));
|
||||
@@ -252,13 +419,33 @@ const isDirty = computed(
|
||||
Boolean(baseline.value) &&
|
||||
formSnapshot.value !== baseline.value,
|
||||
);
|
||||
const resultCopy = computed(() => ({
|
||||
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 resultCopy = computed(
|
||||
() =>
|
||||
({
|
||||
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;
|
||||
});
|
||||
@@ -278,15 +465,18 @@ const loadMember = async () => {
|
||||
originalMember.value = member;
|
||||
Object.assign(editForm, {
|
||||
appUserId: member.appUserId || "",
|
||||
bindingMode: member.bindingMode || (member.appUserId ? "SPECIFIED" : "NONE"),
|
||||
bindingMode:
|
||||
member.bindingMode || (member.appUserId ? "SPECIFIED" : "NONE"),
|
||||
personNo: member.personNo || "",
|
||||
name: member.name,
|
||||
aliasName: member.aliasName || "",
|
||||
sex: member.sex || "",
|
||||
generation: member.generation || "",
|
||||
generationName: member.generationName || "",
|
||||
fatherId: member.relatives.find((item) => item.relation === "父亲")?.id || "",
|
||||
motherId: member.relatives.find((item) => item.relation === "母亲")?.id || "",
|
||||
fatherId:
|
||||
member.relatives.find((item) => item.relation === "父亲")?.id || "",
|
||||
motherId:
|
||||
member.relatives.find((item) => item.relation === "母亲")?.id || "",
|
||||
avatarOssId: member.avatarOssId || "",
|
||||
birthDate: datePart(member.birthDate),
|
||||
birthLunar: member.birthLunar || "",
|
||||
@@ -315,18 +505,23 @@ const loadMember = async () => {
|
||||
};
|
||||
const loadPersonOptions = async () => {
|
||||
try {
|
||||
const rows = await appApi.getLineagePersonOptions(genealogyId.value, { requestController: personOptionsRequestController });
|
||||
const rows = await appApi.getLineagePersonOptions(genealogyId.value, {
|
||||
requestController: personOptionsRequestController,
|
||||
});
|
||||
const options = rows
|
||||
.map((item) => {
|
||||
const value = String(item?.personId ?? item?.id ?? "");
|
||||
if (!/^[1-9]\d*$/.test(value) || value === personId.value) return null;
|
||||
const name = String(item?.name || item?.personName || item?.personNo || "未命名人物");
|
||||
const name = String(
|
||||
item?.name || item?.personName || item?.personNo || "未命名人物",
|
||||
);
|
||||
return { value, label: `${name}(${value})` };
|
||||
})
|
||||
.filter(Boolean);
|
||||
personOptions.value = [{ label: "不选择", value: "" }, ...options];
|
||||
} catch (error) {
|
||||
if (!isRequestCancelled(error)) personOptions.value = [{ label: "暂无可选人物", value: "" }];
|
||||
if (!isRequestCancelled(error))
|
||||
personOptions.value = [{ label: "暂无可选人物", value: "" }];
|
||||
}
|
||||
};
|
||||
|
||||
@@ -360,31 +555,48 @@ const requestBack = () =>
|
||||
|
||||
onBackPress((event) => handleBackPress(event, requestBack));
|
||||
|
||||
const clearError = (field) => { fieldErrors[field] = ""; };
|
||||
const optionIndex = (options, value) => Math.max(0, options.findIndex((item) => item.value === value));
|
||||
const optionLabel = (options, value) => options.find((item) => item.value === value)?.label || "";
|
||||
const clearError = (field) => {
|
||||
fieldErrors[field] = "";
|
||||
};
|
||||
const optionIndex = (options, value) =>
|
||||
Math.max(
|
||||
0,
|
||||
options.findIndex((item) => item.value === value),
|
||||
);
|
||||
const optionLabel = (options, value) =>
|
||||
options.find((item) => item.value === value)?.label || "";
|
||||
const selectOption = (field, options, event) => {
|
||||
editForm[field] = options[Number(event.detail.value)]?.value || "";
|
||||
};
|
||||
const selectBindingMode = (event) => {
|
||||
editForm.bindingMode = bindingModeOptions[Number(event.detail.value)]?.value || "NONE";
|
||||
editForm.bindingMode =
|
||||
bindingModeOptions[Number(event.detail.value)]?.value || "NONE";
|
||||
fieldErrors.bindingMode = "";
|
||||
};
|
||||
const personOptionIndex = (value) => Math.max(0, personOptions.value.findIndex((item) => item.value === value));
|
||||
const personOptionLabel = (value) => personOptions.value.find((item) => item.value === value)?.label || "不选择";
|
||||
const personOptionIndex = (value) =>
|
||||
Math.max(
|
||||
0,
|
||||
personOptions.value.findIndex((item) => item.value === value),
|
||||
);
|
||||
const personOptionLabel = (value) =>
|
||||
personOptions.value.find((item) => item.value === value)?.label || "不选择";
|
||||
const selectPerson = (field, event) => {
|
||||
editForm[field] = personOptions.value[Number(event.detail.value)]?.value || "";
|
||||
editForm[field] =
|
||||
personOptions.value[Number(event.detail.value)]?.value || "";
|
||||
};
|
||||
const uploadAvatar = async () => {
|
||||
if (isAvatarUploading.value || isSubmitting.value) return;
|
||||
isAvatarUploading.value = true;
|
||||
avatarUploadError.value = "";
|
||||
try {
|
||||
const receipt = await pickAndUploadImage({ requestController: editRequestController });
|
||||
const receipt = await pickAndUploadImage({
|
||||
requestController: editRequestController,
|
||||
});
|
||||
editForm.avatarOssId = receipt.ossId;
|
||||
avatarFileName.value = receipt.fileName || "头像图片";
|
||||
} catch (error) {
|
||||
if (!isImagePickCancelled(error) && !isRequestCancelled(error)) avatarUploadError.value = error?.message || "头像上传失败,请稍后重试";
|
||||
if (!isImagePickCancelled(error) && !isRequestCancelled(error))
|
||||
avatarUploadError.value = error?.message || "头像上传失败,请稍后重试";
|
||||
} finally {
|
||||
isAvatarUploading.value = false;
|
||||
}
|
||||
@@ -395,41 +607,57 @@ const selectDate = (field, event) => {
|
||||
};
|
||||
const validateEditForm = () => {
|
||||
fieldErrors.name = editForm.name.trim() ? "" : "请填写成员姓名";
|
||||
fieldErrors.dates = editForm.birthDate && editForm.deathDate && editForm.deathDate < editForm.birthDate ? "离世日期不能早于出生日期" : "";
|
||||
fieldErrors.bindingMode = editForm.bindingMode === "SPECIFIED" && !editForm.appUserId
|
||||
? "当前未提供可选业务用户,不能指定认领"
|
||||
: "";
|
||||
fieldErrors.dates =
|
||||
editForm.birthDate &&
|
||||
editForm.deathDate &&
|
||||
editForm.deathDate < editForm.birthDate
|
||||
? "离世日期不能早于出生日期"
|
||||
: "";
|
||||
fieldErrors.bindingMode =
|
||||
editForm.bindingMode === "SPECIFIED" && !editForm.appUserId
|
||||
? "当前未提供可选业务用户,不能指定认领"
|
||||
: "";
|
||||
return !fieldErrors.name && !fieldErrors.dates && !fieldErrors.bindingMode;
|
||||
};
|
||||
const saveMember = async () => {
|
||||
if (isSubmitting.value || isAvatarUploading.value || !validateEditForm()) return;
|
||||
if (isSubmitting.value || isAvatarUploading.value || !validateEditForm())
|
||||
return;
|
||||
isSubmitting.value = true;
|
||||
try {
|
||||
await appApi.updatePerson(genealogyId.value, personId.value, {
|
||||
bindingMode: editForm.bindingMode,
|
||||
...(editForm.bindingMode === "SPECIFIED" ? { appUserId: editForm.appUserId } : {}),
|
||||
personNo: editForm.personNo,
|
||||
name: editForm.name,
|
||||
aliasName: editForm.aliasName,
|
||||
sex: editForm.sex,
|
||||
generation: editForm.generation ? Number(editForm.generation) : undefined,
|
||||
generationName: editForm.generationName,
|
||||
fatherId: editForm.fatherId,
|
||||
motherId: editForm.motherId,
|
||||
avatarOssId: editForm.avatarOssId,
|
||||
birthDate: editForm.birthDate,
|
||||
birthLunar: editForm.birthLunar,
|
||||
birthPlace: editForm.birthPlace,
|
||||
deathDate: editForm.deathDate,
|
||||
deathLunar: editForm.deathLunar,
|
||||
deathPlace: editForm.deathPlace,
|
||||
burialPlace: editForm.burialPlace,
|
||||
personStatus: editForm.personStatus,
|
||||
biography: editForm.summary,
|
||||
remark: editForm.remark,
|
||||
sortOrder: editForm.sortOrder,
|
||||
relationName: editForm.relationName,
|
||||
}, { requestController: editRequestController });
|
||||
await appApi.updatePerson(
|
||||
genealogyId.value,
|
||||
personId.value,
|
||||
{
|
||||
bindingMode: editForm.bindingMode,
|
||||
...(editForm.bindingMode === "SPECIFIED"
|
||||
? { appUserId: editForm.appUserId }
|
||||
: {}),
|
||||
personNo: editForm.personNo,
|
||||
name: editForm.name,
|
||||
aliasName: editForm.aliasName,
|
||||
sex: editForm.sex,
|
||||
generation: editForm.generation
|
||||
? Number(editForm.generation)
|
||||
: undefined,
|
||||
generationName: editForm.generationName,
|
||||
fatherId: editForm.fatherId,
|
||||
motherId: editForm.motherId,
|
||||
avatarOssId: editForm.avatarOssId,
|
||||
birthDate: editForm.birthDate,
|
||||
birthLunar: editForm.birthLunar,
|
||||
birthPlace: editForm.birthPlace,
|
||||
deathDate: editForm.deathDate,
|
||||
deathLunar: editForm.deathLunar,
|
||||
deathPlace: editForm.deathPlace,
|
||||
burialPlace: editForm.burialPlace,
|
||||
personStatus: editForm.personStatus,
|
||||
biography: editForm.summary,
|
||||
remark: editForm.remark,
|
||||
sortOrder: editForm.sortOrder,
|
||||
relationName: editForm.relationName,
|
||||
},
|
||||
{ requestController: editRequestController },
|
||||
);
|
||||
baseline.value = formSnapshot.value;
|
||||
await goBack();
|
||||
} catch (error) {
|
||||
@@ -442,9 +670,7 @@ const saveMember = async () => {
|
||||
}
|
||||
};
|
||||
const returnToMember = async () => {
|
||||
const confirmed = isDirty.value
|
||||
? await requestDiscardConfirmation()
|
||||
: true;
|
||||
const confirmed = isDirty.value ? await requestDiscardConfirmation() : true;
|
||||
if (!confirmed) return false;
|
||||
return goBack();
|
||||
};
|
||||
@@ -464,28 +690,154 @@ const handleResultAction = () => {
|
||||
<style scoped lang="scss">
|
||||
@use "../../styles/adaptive-frame-profiles.scss" as adaptive;
|
||||
|
||||
.edit-member-page { display: flex; min-height: 100vh; flex-direction: column; background: $paper; }
|
||||
.edit-member-page__header { z-index: 3; }
|
||||
.edit-member-panel { @include adaptive.adaptive-tree-panel; z-index: 2; width: calc(100% - 32rpx); margin: 18rpx auto 28rpx; padding: 7.5% 8%; }
|
||||
.form-eyebrow { display: block; color: $brand-red; font-size: 22rpx; letter-spacing: 3rpx; }
|
||||
.form-title { display: block; margin-top: 10rpx; color: $ink; font-family: "STKaiti", "KaiTi", serif; font-size: 34rpx; font-weight: 700; line-height: 1.35; }
|
||||
.form-copy, .form-note { display: block; margin-top: 10rpx; color: $ink-muted; font-size: 24rpx; line-height: 1.5; }
|
||||
.member-context, .form-field { @include adaptive.adaptive-tree-field; display: grid; grid-template-columns: auto minmax(0, 1fr); min-height: 78rpx; align-items: center; gap: 20rpx; margin-top: 14rpx; padding: 12rpx 22rpx; }
|
||||
.member-context text:first-child, .form-field > text:first-child { color: $ink; font-size: 24rpx; font-weight: 700; }
|
||||
.member-context text:last-child, .form-field > text:last-child, .form-field input, .form-field textarea { min-width: 0; color: $ink; font-size: 24rpx; line-height: 1.45; text-align: right; }
|
||||
.form-field textarea { width: auto; min-height: 54rpx; text-align: left; }
|
||||
.form-field__hint, .upload-receipt { color: $ink-muted; font-size: 21rpx; line-height: 1.4; text-align: right; }
|
||||
.form-field--upload > view { display: grid; justify-items: end; gap: 6rpx; }
|
||||
.upload-button { min-height: 54rpx; margin: 0; padding: 0 16rpx; border: 1rpx solid rgba(159, 23, 15, .42); border-radius: 8rpx; background: transparent; color: $brand-red; font-size: 22rpx; }
|
||||
.form-field--summary { align-items: start; }
|
||||
.form-placeholder { color: #a79884; }
|
||||
.field-error { display: block; margin: 5rpx 18rpx 0; color: $brand-red; font-size: 22rpx; line-height: 32rpx; }
|
||||
.form-note { text-align: center; }
|
||||
.form-action { display: grid; width: 100%; min-height: 76rpx; margin-top: 18rpx; }
|
||||
.form-action image, .form-action text { grid-area: 1 / 1; width: 100%; height: 100%; }
|
||||
.form-action text { z-index: 1; display: flex; align-items: center; justify-content: center; color: #fff9ed; font-size: 24rpx; font-weight: 700; }
|
||||
.edit-result { margin-top: 30%; text-align: center; }
|
||||
.edit-result .form-eyebrow, .edit-result .form-copy { text-align: center; }
|
||||
.edit-result .form-action { width: 420rpx; max-width: 100%; margin-right: auto; margin-left: auto; }
|
||||
@media (min-width: 400px) { .edit-member-panel { width: calc(100% - 48rpx); } }
|
||||
.edit-member-page {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
flex-direction: column;
|
||||
background: $paper;
|
||||
}
|
||||
.edit-member-page__header {
|
||||
z-index: 3;
|
||||
}
|
||||
.edit-member-panel {
|
||||
@include adaptive.adaptive-tree-panel;
|
||||
z-index: 2;
|
||||
width: calc(100% - 32rpx);
|
||||
margin: 18rpx auto 28rpx;
|
||||
padding: 7.5% 8%;
|
||||
}
|
||||
.form-eyebrow {
|
||||
display: block;
|
||||
color: $brand-red;
|
||||
font-size: 22rpx;
|
||||
letter-spacing: 3rpx;
|
||||
}
|
||||
.form-title {
|
||||
display: block;
|
||||
margin-top: 10rpx;
|
||||
color: $ink;
|
||||
font-family: "STKaiti", "KaiTi", serif;
|
||||
font-size: 34rpx;
|
||||
font-weight: 700;
|
||||
line-height: 1.35;
|
||||
}
|
||||
.form-copy,
|
||||
.form-note {
|
||||
display: block;
|
||||
margin-top: 10rpx;
|
||||
color: $ink-muted;
|
||||
font-size: 24rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.member-context,
|
||||
.form-field {
|
||||
@include adaptive.adaptive-tree-field;
|
||||
display: grid;
|
||||
grid-template-columns: auto minmax(0, 1fr);
|
||||
min-height: 78rpx;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
margin-top: 14rpx;
|
||||
padding: 12rpx 22rpx;
|
||||
}
|
||||
.member-context text:first-child,
|
||||
.form-field > text:first-child {
|
||||
color: $ink;
|
||||
font-size: 24rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.member-context text:last-child,
|
||||
.form-field > text:last-child,
|
||||
.form-field input,
|
||||
.form-field textarea {
|
||||
min-width: 0;
|
||||
color: $ink;
|
||||
font-size: 24rpx;
|
||||
line-height: 1.45;
|
||||
text-align: right;
|
||||
}
|
||||
.form-field textarea {
|
||||
width: auto;
|
||||
min-height: 54rpx;
|
||||
text-align: left;
|
||||
}
|
||||
.form-field__hint,
|
||||
.upload-receipt {
|
||||
color: $ink-muted;
|
||||
font-size: 21rpx;
|
||||
line-height: 1.4;
|
||||
text-align: right;
|
||||
}
|
||||
.form-field--upload > view {
|
||||
display: grid;
|
||||
justify-items: end;
|
||||
gap: 6rpx;
|
||||
}
|
||||
.upload-button {
|
||||
min-height: 54rpx;
|
||||
margin: 0;
|
||||
padding: 0 16rpx;
|
||||
border: 1rpx solid rgba(159, 23, 15, 0.42);
|
||||
border-radius: 8rpx;
|
||||
background: transparent;
|
||||
color: $brand-red;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
.form-field--summary {
|
||||
align-items: start;
|
||||
min-height: 200rpx;
|
||||
}
|
||||
.form-placeholder {
|
||||
color: #a79884;
|
||||
}
|
||||
.field-error {
|
||||
display: block;
|
||||
margin: 5rpx 18rpx 0;
|
||||
color: $brand-red;
|
||||
font-size: 22rpx;
|
||||
line-height: 32rpx;
|
||||
}
|
||||
.form-note {
|
||||
text-align: center;
|
||||
}
|
||||
.form-action {
|
||||
display: grid;
|
||||
width: 100%;
|
||||
min-height: 76rpx;
|
||||
margin-top: 18rpx;
|
||||
}
|
||||
.form-action image,
|
||||
.form-action text {
|
||||
grid-area: 1 / 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.form-action text {
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff9ed;
|
||||
font-size: 24rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.edit-result {
|
||||
margin-top: 30%;
|
||||
text-align: center;
|
||||
}
|
||||
.edit-result .form-eyebrow,
|
||||
.edit-result .form-copy {
|
||||
text-align: center;
|
||||
}
|
||||
.edit-result .form-action {
|
||||
width: 420rpx;
|
||||
max-width: 100%;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
@media (min-width: 400px) {
|
||||
.edit-member-panel {
|
||||
width: calc(100% - 48rpx);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user