「权限 × 状态 × 审计」联合约束机制
This commit is contained in:
@@ -29,6 +29,9 @@ import { computed, reactive, ref, watch } from "vue";
|
||||
import { ElMessage, type FormInstance, type FormRules } from "element-plus";
|
||||
import { createSite, updateSite } from "../../api/sites";
|
||||
import type { Site } from "../../types/api";
|
||||
import { useAuthStore } from "../../store/auth";
|
||||
import { evaluateAction } from "../../guards/actionGuard";
|
||||
import { logAudit } from "../../audit";
|
||||
|
||||
const props = defineProps<{
|
||||
visible: boolean;
|
||||
@@ -46,6 +49,7 @@ const visibleProxy = computed({
|
||||
set: (val: boolean) => emit("update:visible", val),
|
||||
});
|
||||
|
||||
const auth = useAuthStore();
|
||||
const formRef = ref<FormInstance>();
|
||||
const submitting = ref(false);
|
||||
const form = reactive({
|
||||
@@ -86,6 +90,21 @@ watch(
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (!formRef.value) return;
|
||||
const decision = evaluateAction({
|
||||
actorRole: auth.user?.role || null,
|
||||
requiredPermission: "site.manage",
|
||||
target: { siteId: props.site?.id, studyId: props.studyId },
|
||||
});
|
||||
if (!decision.allowed) {
|
||||
ElMessage.warning(decision.reason || "无权限执行该操作");
|
||||
logAudit(decision.auditType, {
|
||||
targetId: props.site?.id || props.studyId,
|
||||
targetName: props.site?.name,
|
||||
reason: decision.reason,
|
||||
severity: decision.severity,
|
||||
});
|
||||
return;
|
||||
}
|
||||
await formRef.value.validate();
|
||||
submitting.value = true;
|
||||
try {
|
||||
@@ -98,6 +117,12 @@ const onSubmit = async () => {
|
||||
is_active: form.is_active,
|
||||
});
|
||||
ElMessage.success("中心已更新");
|
||||
logAudit("SITE_STATUS_CHANGED", {
|
||||
targetId: props.site.id,
|
||||
targetName: props.site.name,
|
||||
after: { name: form.name, is_active: form.is_active },
|
||||
severity: "normal",
|
||||
});
|
||||
} else {
|
||||
await createSite(props.studyId, {
|
||||
name: form.name,
|
||||
@@ -106,11 +131,24 @@ const onSubmit = async () => {
|
||||
contact: form.contact,
|
||||
});
|
||||
ElMessage.success("中心已创建");
|
||||
logAudit("SITE_STATUS_CHANGED", {
|
||||
targetId: props.studyId,
|
||||
targetName: form.name,
|
||||
after: { name: form.name },
|
||||
severity: "normal",
|
||||
});
|
||||
}
|
||||
emit("saved");
|
||||
visibleProxy.value = false;
|
||||
} catch (e: any) {
|
||||
ElMessage.error(e?.response?.data?.message || "保存失败");
|
||||
logAudit("SITE_STATUS_CHANGED", {
|
||||
targetId: props.site?.id || props.studyId,
|
||||
targetName: props.site?.name || form.name,
|
||||
after: { name: form.name },
|
||||
severity: "warning",
|
||||
reason: e?.response?.data?.message,
|
||||
});
|
||||
} finally {
|
||||
submitting.value = false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user