
本文介绍如何在 Vue.js 表单中实现「显示所有亲属关系选项(含历史数据),但仅允许新录入时选择有效亲属关系」的需求,通过数据库字段扩展(如 IsBloodRelated)与前端逻辑结合,安全区分新/旧记录并禁用无效选项。
本文介绍如何在 vue.js 表单中实现「显示所有亲属关系选项(含历史数据),但仅允许新录入时选择有效亲属关系」的需求,通过数据库字段扩展(如 `isbloodrelated`)与前端逻辑结合,安全区分新/旧记录并禁用无效选项。
在患者管理类系统中,常需兼顾数据兼容性与业务规则演进。例如,早期数据库表 Relative(id, desc, status) 中的 status = 'I'(inactive)仅用于标记“已停用”,但无法准确表达语义——像 coworker、friend 并非“被停用”,而是从来就不属于合规的亲属关系范畴。因此,推荐将 status 字段重构为语义清晰的布尔型字段,如 IsBloodRelated: BOOLEAN 或 IsFamilyMember: BOOLEAN,从根本上提升可维护性与可读性。
✅ 数据库改造建议(关键一步)
-- 添加字段(PostgreSQL / MySQL 8.0+)
ALTER TABLE "Relative" ADD COLUMN "IsBloodRelated" BOOLEAN DEFAULT TRUE;
-- 更新历史数据(示例)
UPDATE "Relative" SET "IsBloodRelated" = FALSE
WHERE "RELATDESC" IN ('coworker', 'friend', 'neighbour', 'acquaintance');
-- 后续新增亲属关系时,务必显式指定该字段
INSERT INTO "Relative" ("RELATID", "RELATDESC", "IsBloodRelated")
VALUES (14, 'step-brother', TRUE);✅ Vue.js 前端实现逻辑
核心目标是:
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
- 对已有患者记录:下拉框仍显示其原始 RELATDESC(如 "friend"),且允许查看/编辑(不阻止提交);
- 对新建患者记录:下拉框中 IsBloodRelated = false 的选项应视觉可见但不可选(即 disabled),同时默认值应为首个有效亲属;
- 提交校验:服务端必须二次验证 IsBloodRelated = true,前端仅作友好提示。
示例代码(Vue 3 Composition API)
<template>
<select
id="PPRelOtherConType"
v-model="form.PPRelationOtherCon"
:disabled="isCreatingNew && !isBloodRelatedSelected"
>
<option
v-for="rel in filteredRelations"
:key="rel.RELATID"
:value="rel.RELATID"
:disabled="!rel.IsBloodRelated && isCreatingNew"
>
{{ rel.RELATDESC }}
<span v-if="!rel.IsBloodRelated && !isCreatingNew"> (legacy)</span>
<span v-if="!rel.IsBloodRelated && isCreatingNew"> — not allowed</span>
</option>
</select>
</template>
<script setup>
import { ref, computed } from 'vue'
const props = defineProps({
initialRelationId: { type: Number, default: null }, // 已有患者的 RELATID
isCreatingNew: { type: Boolean, default: true } // 是否为新建表单
})
const form = ref({
PPRelationOtherCon: props.initialRelationId || null
})
// 假设 PPrelations 来自 API 或 store
const PPrelations = ref([
{ RELATID: 1, RELATDESC: 'father', IsBloodRelated: true },
{ RELATID: 2, RELATDESC: 'mother', IsBloodRelated: true },
{ RELATID: 11, RELATDESC: 'coworker', IsBloodRelated: false },
{ RELATID: 12, RELATDESC: 'friend', IsBloodRelated: false }
])
// 动态过滤:新建时隐藏非亲属项(但保留原始值选项)
const filteredRelations = computed(() => {
if (!props.isCreatingNew) return PPrelations.value
// 新建时:保留所有项用于渲染,但标记 disabled 状态
return PPrelations.value
})
// 辅助判断当前选中项是否合规(用于禁用整个 select 的场景)
const isBloodRelatedSelected = computed(() => {
const selected = PPrelations.value.find(r => r.RELATID === form.value.PPRelationOtherCon)
return selected?.IsBloodRelated ?? false
})
</script>⚠️ 注意事项与最佳实践
- 永远不要依赖前端禁用做唯一校验:disabled 属性可被浏览器开发者工具轻易绕过。后端保存前必须查询 Relative 表并校验 IsBloodRelated = true,否则存在数据一致性风险。
- 用户体验优化:对 IsBloodRelated = false 的历史选项,建议添加视觉提示(如 (legacy)、灰色文字、tooltip 提示“该关系类型已不再支持新增”)。
- 避免使用 readonly 于 <select>:HTML 规范中 <select> 不支持 readonly 属性,应使用 disabled 或 CSS + JS 模拟只读效果(如 pointer-events: none; opacity: 0.7)。
- 初始化逻辑要健壮:当 initialRelationId 对应一个 IsBloodRelated = false 的旧值时,v-model 仍需能正确绑定,否则下拉框可能“空白”。确保 PPrelations 包含该 ID 的完整对象。
✅ 总结
通过将模糊的 status 字段升级为语义明确的 IsBloodRelated,再配合 Vue 的响应式计算属性与条件渲染,即可优雅实现「历史数据可读、新数据受控」的业务需求。关键在于:数据库设计先行,前后端校验并重,UI 层专注体验引导而非权限控制。此方案既保障了数据治理的严谨性,又维持了系统的平滑演进能力。

















