fix(post-p95): 编辑态按钉住版渲染,自填/代填主体展示改判 submitter
- 跨版本编辑必挂:编辑态此前吃 resolve 返回的当前发布版渲染,服务端却按答卷钉住 的旧版校验,升版后编辑永远 400。改为拉 /my/detail 取钉住版 groups,渲染与校验 同源(renderGroups)。 - 自填行 subject 归一为本人后,"本人自填"与"他人代填"的判据从"subject 是否为空" 改为"subject 是否等于 submitter",同步修正 My.vue / Data.vue / AnswerDetail.vue 三处展示与 tooltip。 验证:type-check + build 双绿。
This commit is contained in:
+27
-6
@@ -14,7 +14,7 @@ import { useRoute } from "vue-router";
|
||||
import { fieldWidget } from "@/components/fields";
|
||||
import type { DesignField } from "@/types/formSchema";
|
||||
import type { ResolvedForm, MyAnswerItem } from "@/types/answer";
|
||||
import { resolveForm, submitAnswer, listMyAnswers, deleteMyAnswer, editMyAnswer } from "@/api/module/fill";
|
||||
import { resolveForm, submitAnswer, listMyAnswers, deleteMyAnswer, editMyAnswer, getMyAnswerDetail } from "@/api/module/fill";
|
||||
import { startHeightReporting, reportSubmitResult, reportNeedLogin } from "@/utils/embed";
|
||||
import Utils from "@/utils";
|
||||
import { Message, Modal } from "view-ui-plus";
|
||||
@@ -107,9 +107,8 @@ function validateField(field: DesignField): string | null {
|
||||
|
||||
function validateAll(): boolean {
|
||||
const errors: Record<string, string> = {};
|
||||
if (!form.value?.groups) return true;
|
||||
const groups = form.value.groups as any[];
|
||||
for (const group of groups) {
|
||||
// 校验与渲染同源:编辑态吃钉住版 groups(renderGroups),否则按当前发布版(Bug#1)
|
||||
for (const group of renderGroups.value) {
|
||||
for (const field of group.fields || []) {
|
||||
const err = validateField(field);
|
||||
if (err) errors[field.key] = err;
|
||||
@@ -172,6 +171,14 @@ async function handleSubmit() {
|
||||
|
||||
const myAnswers = ref<MyAnswerItem[]>([]);
|
||||
const editingAnswer = ref<MyAnswerItem | null>(null);
|
||||
/** 编辑态渲染用的 groups = 答卷钉住的那一版(/my/detail);null/空=未进入编辑 */
|
||||
const editingGroups = ref<any[] | null>(null);
|
||||
|
||||
/** 渲染与校验同源的 groups:编辑态吃钉住版,否则吃当前发布版 */
|
||||
const renderGroups = computed<any[]>(() => {
|
||||
if (editingAnswer.value) return editingGroups.value || [];
|
||||
return (form.value?.groups as any[]) || [];
|
||||
});
|
||||
|
||||
async function loadMyAnswers() {
|
||||
try {
|
||||
@@ -181,9 +188,21 @@ async function loadMyAnswers() {
|
||||
}
|
||||
}
|
||||
|
||||
function handleEditAnswer(answer: MyAnswerItem) {
|
||||
async function handleEditAnswer(answer: MyAnswerItem) {
|
||||
if (submitting.value) return;
|
||||
try {
|
||||
// Bug#1:编辑必须按答卷**钉住的版本**渲染(/my/detail 返回该版本的 groups)。
|
||||
// 用当前发布版渲染,客户端会带上/漏掉升版后新增或删除的字段,而服务端按钉住旧版校验,
|
||||
// 结果必然是"含未知字段"或"缺必填"——表单升过一次版,编辑就永久 400。
|
||||
const detail = await getMyAnswerDetail(answer.answerId);
|
||||
editingGroups.value = (detail.groups as any[]) || [];
|
||||
} catch (e: any) {
|
||||
Message.error(e?.message || "加载答卷失败,无法编辑");
|
||||
return;
|
||||
}
|
||||
editingAnswer.value = answer;
|
||||
formValues.value = { ...answer.values };
|
||||
formErrors.value = {};
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
|
||||
@@ -198,6 +217,7 @@ async function handleUpdateAnswer() {
|
||||
await editMyAnswer(editingAnswer.value.answerId, formValues.value);
|
||||
Message.success("更新成功");
|
||||
editingAnswer.value = null;
|
||||
editingGroups.value = null;
|
||||
formValues.value = {};
|
||||
await loadMyAnswers();
|
||||
} catch (e: any) {
|
||||
@@ -225,6 +245,7 @@ function handleDeleteAnswer(answer: MyAnswerItem) {
|
||||
|
||||
function handleCancelEdit() {
|
||||
editingAnswer.value = null;
|
||||
editingGroups.value = null;
|
||||
formValues.value = {};
|
||||
formErrors.value = {};
|
||||
}
|
||||
@@ -327,7 +348,7 @@ const readonlyReason = computed(() => {
|
||||
|
||||
<!-- 表单字段 -->
|
||||
<div v-if="!submitted && !isReadonly || editingAnswer" class="form-groups">
|
||||
<div v-for="group in (form.groups as any[])" :key="group.key" class="form-group">
|
||||
<div v-for="group in renderGroups" :key="group.key" class="form-group">
|
||||
<h3 v-if="group.label" class="group-label">{{ group.label }}</h3>
|
||||
<div v-for="field in (group.fields || [])" :key="field.key" class="form-item">
|
||||
<label class="form-label">
|
||||
|
||||
+1
-1
@@ -208,7 +208,7 @@ const tableColumns = computed(() => {
|
||||
render: (h2: any, p: any) =>
|
||||
h2(
|
||||
"span",
|
||||
`提交人 ${p.row.submitterId}${p.row.subjectId ? `|主体 ${p.row.subjectId}` : "(本人自填)"}`
|
||||
`提交人 ${p.row.submitterId}${p.row.subjectId && p.row.subjectId !== p.row.submitterId ? `|主体 ${p.row.subjectId}` : "(本人自填)"}`
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
@@ -151,7 +151,7 @@ onMounted(async () => {
|
||||
<div class="meta-row"><span class="meta-key">报名号</span><span>{{ detail.answerNo || "—" }}</span></div>
|
||||
<div class="meta-row"><span class="meta-key">提交时间</span><span>{{ detail.submitTime }}</span></div>
|
||||
<div class="meta-row"><span class="meta-key">提交人 / 被代填人</span>
|
||||
<span>{{ detail.submitterId }} / {{ detail.subjectId ?? "—(本人自填)" }}</span>
|
||||
<span>{{ detail.submitterId }} / {{ detail.subjectId && detail.subjectId !== detail.submitterId ? detail.subjectId : "(本人自填)" }}</span>
|
||||
</div>
|
||||
<div class="meta-row"><span class="meta-key">表单 uuid</span><code>{{ detail.formUuid }}</code></div>
|
||||
</div>
|
||||
|
||||
@@ -271,10 +271,10 @@ const tableColumns = computed(() => {
|
||||
width: 170,
|
||||
render: (h2: any, p: any) =>
|
||||
h2(Tooltip, {
|
||||
content: `submitter_id=${p.row.submitterId}${p.row.subjectId ? `,subject_id=${p.row.subjectId}(他人代填)` : ",无代填主体"}`,
|
||||
content: `submitter_id=${p.row.submitterId}${p.row.subjectId && p.row.subjectId !== p.row.submitterId ? `,subject_id=${p.row.subjectId}(他人代填)` : ",无代填主体"}`,
|
||||
transfer: true
|
||||
}, {
|
||||
default: () => [h2("span", `提交人 ${p.row.submitterId}${p.row.subjectId ? `|主体 ${p.row.subjectId}` : ""}`)]
|
||||
default: () => [h2("span", `提交人 ${p.row.submitterId}${p.row.subjectId && p.row.subjectId !== p.row.submitterId ? `|主体 ${p.row.subjectId}` : ""}`)]
|
||||
})
|
||||
});
|
||||
cols.push(
|
||||
|
||||
Reference in New Issue
Block a user