forked from wangziqi/gongxue-base
fix: harden permission-gated UI — minimum-org endpoint, modal/Popconfirm fail-closed on revocation
67 lines
2.0 KiB
TypeScript
67 lines
2.0 KiB
TypeScript
import { useCallback, useEffect, useRef } from 'react';
|
|
import { Modal } from 'antd';
|
|
import api from '../api';
|
|
import { message } from '../ui/app-message';
|
|
|
|
/**
|
|
* Shared hook for viewing sensitive student info (phone / ID number).
|
|
* Logs an audit entry before revealing the unmasked value.
|
|
*
|
|
* @param studentId - The student whose data is being viewed
|
|
* @param module - Audit module label (e.g. '学生管理', '学生档案')
|
|
* @param canLog - Whether the current user has log:create; when false any
|
|
* already-open confirm modal is destroyed.
|
|
*/
|
|
export function useViewSensitive(studentId: number, module: string, canLog: boolean) {
|
|
const canLogRef = useRef(canLog);
|
|
const modalRef = useRef<ReturnType<typeof Modal.confirm> | null>(null);
|
|
canLogRef.current = canLog;
|
|
|
|
useEffect(() => {
|
|
if (!canLogRef.current && modalRef.current) {
|
|
modalRef.current.destroy();
|
|
modalRef.current = null;
|
|
}
|
|
return () => {
|
|
modalRef.current?.destroy();
|
|
modalRef.current = null;
|
|
};
|
|
}, []);
|
|
|
|
return useCallback(
|
|
(field: string, value: string) => {
|
|
if (!canLogRef.current) return;
|
|
modalRef.current = Modal.confirm({
|
|
title: '查看敏感信息',
|
|
content: `您即将查看 "${field}" 的完整信息。此操作将被记录。`,
|
|
okText: '确认查看',
|
|
cancelText: '取消',
|
|
onOk: async () => {
|
|
if (!canLogRef.current) return;
|
|
try {
|
|
await api.post('/operation-logs/audit', {
|
|
module,
|
|
action: '查看敏感信息',
|
|
targetId: studentId,
|
|
targetType: 'student',
|
|
detail: `查看${field}`,
|
|
});
|
|
} catch {
|
|
message.error('操作日志记录失败,请稍后重试');
|
|
return;
|
|
}
|
|
Modal.info({
|
|
title: field,
|
|
content: value,
|
|
okText: '关闭',
|
|
});
|
|
},
|
|
afterClose: () => {
|
|
modalRef.current = null;
|
|
},
|
|
});
|
|
},
|
|
[studentId, module],
|
|
);
|
|
}
|