Commit 1cf5afe5 authored by David Yang's avatar David Yang

feat: enforce table view field permissions

parent f91ad267
......@@ -12,6 +12,7 @@ import { useSubjectRecord } from './hooks/useSubjectRecord';
import SubjectViewContent from './components/SubjectViewContent';
import {
checkViewCondition,
isFieldDisabledByView,
isViewAccessible,
} from '@/utils/subjectView';
......@@ -49,6 +50,7 @@ const RecordDetailDrawer = (props, ref) => {
filterView = [],
preferredViewName,
disabledFields = EMPTY_ARRAY,
authorizationView = null,
} = props;
const [refreshKey, setRefreshKey] = useState(() => Date.now());
......@@ -135,7 +137,9 @@ const RecordDetailDrawer = (props, ref) => {
[disabledFields],
);
const isDrawerFieldDisabled = (fieldPath, currentView) =>
disabledFieldSet.has(fieldPath) || isFieldDisabled(fieldPath, currentView);
disabledFieldSet.has(fieldPath) ||
isFieldDisabled(fieldPath, currentView) ||
isFieldDisabledByView(fieldPath, authorizationView);
const closeDrawer = () => {
onClose?.();
......
......@@ -1638,6 +1638,7 @@ export default function ProblemRectificationListPage() {
onDataChange={onDataChange}
disabledFields={[DELAY_REQUEST_FIELD, DELAY_REQUEST_ITEMS_FIELD]}
preferredViewName={activeGridView?.title || activeGridView?.name}
authorizationView={activeGridView}
/>
),
}}
......
......@@ -65,7 +65,9 @@
- `settings.restrictions` 与 `settings.filters.conditions` 共同决定该视图下可见的数据范围
- `settings.viewAuth` 决定当前用户是否能看到该视图
- `type = "detail"` 的视图用于详情抽屉字段编排,按 `columns` 顺序渲染字段
- `settings.auth` 与 `disableColumns` 用于控制详情抽屉内字段是否允许编辑
- 表格 Tab 的 `settings.auth` 按字段路径控制详情抽屉内对应字段是否允许编辑,规则结构与多维表格一致:`field` 使用 `title` 或 `metadata.<fieldName>`,`type` 支持 `group`、`role`、`permission`,授权值分别从 `groups`、`roles`、`permissions` 读取
- 表格 Tab 的 `settings.disableColumns` 与 `settings.auth`、当前详情视图自身的同名配置叠加生效;任一层禁止编辑时字段保留展示但进入只读状态,并显示“当前视图无编辑权限”,不隐藏列或字段
- 管理员、系统账号拥有字段编辑权限旁路;普通用户按当前登录用户的用户组、应用用户组、角色或权限集合匹配,未命中配置时不得编辑。切换表格 Tab 后,详情抽屉必须立即改用新 Tab 的权限配置
因此前端新增字段展示、部门视图调整、列顺序变化时,应优先改 Subject View 配置,而不是直接修改页面常量。
......
......@@ -35,10 +35,12 @@ export function getCurrentUserFromStorage() {
}
function collectUserGroups(user) {
return toArray(user?.groups)
const directGroups = toArray(user?.groups)
.flatMap((group) => [group?._id, group?.name, group?.display_name, group])
.map(normalizeText)
.filter(Boolean);
const appGroups = toArray(user?.applications).flatMap((app) => app?.groups || []);
return [...directGroups, ...appGroups].map(normalizeText).filter(Boolean);
}
function collectUserRoles(user) {
......@@ -67,7 +69,7 @@ export function hasAuthAccess(authRule, user = getCurrentUserFromStorage()) {
return false;
}
if (user.type === 'admin') {
if (user.type === 'admin' || user.type === 'system') {
return true;
}
......@@ -87,7 +89,7 @@ export function hasAuthAccess(authRule, user = getCurrentUserFromStorage()) {
return intersects([user.username, user.display_name, user._id], authRule.usernames);
}
return true;
return intersects(collectUserRoles(user), ['管理']);
}
export function getFieldValue(record, fieldPath) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment