fix(exam): replace unfounded 4-char title rule with explicit validation messages
- 考试名称仅要求非空,移除无依据的至少 4 字限制;保留及格分 1-100、 至少一题、总分 100、题干/选项/答案完整、至少一名员工的发布校验 - 发布坞展示具体校验失败原因,不再静默禁用按钮 - CHANGELOG/README 同步 2026-07-25 组织姓名定向补齐与生产复核记录
This commit is contained in:
@@ -122,6 +122,7 @@
|
||||
</view>
|
||||
|
||||
<view class="publish-dock">
|
||||
<text v-if="publishValidationMessage" class="publish-validation-message" role="alert">{{ publishValidationMessage }}</text>
|
||||
<button class="dock-secondary" :disabled="saving || !valid" @click="save(false)">{{ saving ? '保存中' : '保存草稿' }}</button>
|
||||
<button class="dock-primary" :disabled="saving || !valid || !selectedMemberIds.length" @click="save(true)">{{ saving ? '发布中' : `发布给 ${selectedMemberIds.length} 人` }}</button>
|
||||
</view>
|
||||
@@ -161,14 +162,20 @@ const dateAfter = (days: number) => { const date = new Date(); date.setHours(12,
|
||||
const today = dateAfter(0);
|
||||
const requestId = () => `exam-publish:${examId.value || 'new'}:${Date.now()}:${Math.random().toString(36).slice(2, 8)}`;
|
||||
const totalScore = computed(() => questions.value.reduce((sum, item) => sum + Number(item.score || 0), 0));
|
||||
const valid = computed(() => title.value.trim().length >= 4
|
||||
&& passingScore.value > 0 && passingScore.value <= 100
|
||||
&& totalScore.value === 100
|
||||
&& questions.value.length > 0
|
||||
&& questions.value.every((item, index) => item.stem.trim()
|
||||
&& Number(item.score) > 0
|
||||
&& singleAnswerModels.value[index]?.trim()
|
||||
&& (item.format === 'short' || item.options.filter((option) => option.trim()).length >= 2)));
|
||||
const validationMessage = computed(() => {
|
||||
if (!title.value.trim()) return '请填写考试名称';
|
||||
if (passingScore.value < 1 || passingScore.value > 100) return '及格分必须在 1–100 分之间';
|
||||
if (!questions.value.length) return '请至少添加一道考试题';
|
||||
if (totalScore.value !== 100) return '试卷题目分值合计必须为 100 分';
|
||||
const incompleteIndex = questions.value.findIndex((item, index) => !item.stem.trim()
|
||||
|| Number(item.score) <= 0
|
||||
|| !singleAnswerModels.value[index]?.trim()
|
||||
|| (item.format !== 'short' && item.options.filter((option) => option.trim()).length < 2));
|
||||
return incompleteIndex < 0 ? '' : `请补全第 ${incompleteIndex + 1} 题的题干、分值、选项和答案`;
|
||||
});
|
||||
const valid = computed(() => !validationMessage.value);
|
||||
const publishValidationMessage = computed(() => validationMessage.value
|
||||
|| (!selectedMemberIds.value.length ? '发布前请至少选择 1 名员工' : ''));
|
||||
const goBack = () => uni.navigateBack({ delta: 1, fail: () => uni.redirectTo({ url: '/pages/supervisor/exams/index' }) });
|
||||
const selectPosition = (event: { detail: { value: string } }) => { positionIndex.value = Number(event.detail.value || 0); };
|
||||
const selectDueDate = (event: { detail: { value: string } }) => { dueDate.value = event.detail.value; };
|
||||
@@ -710,6 +717,15 @@ onLoad((options) => { examId.value = Number(options?.id || 0); void load(); });
|
||||
background: rgba(255, 255, 255, 0.97);
|
||||
}
|
||||
|
||||
.publish-validation-message {
|
||||
grid-column: 1 / -1;
|
||||
color: #a86100;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
line-height: 1.4;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.dock-primary,
|
||||
.dock-secondary {
|
||||
display: flex;
|
||||
|
||||
@@ -55,6 +55,9 @@ test('员工考试与主管组卷路由、题目播报、真实人员多选和
|
||||
assert.match(edit, /selectedMemberIds\.value\.length < 100/);
|
||||
assert.match(edit, /members\.value\.slice\(0, 100\)/);
|
||||
assert.match(edit, /requestId/);
|
||||
assert.doesNotMatch(edit, /title\.value\.trim\(\)\.length >= 4/);
|
||||
assert.match(edit, /请填写考试名称/);
|
||||
assert.match(edit, /publish-validation-message/);
|
||||
assert.match(service, /\/api\/aihr\/mobile\/exams\/supervisor/);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user