326 lines
8.4 KiB
TypeScript
326 lines
8.4 KiB
TypeScript
import { prisma } from './prisma';
|
||
|
||
/**
|
||
* 判断是否是超级管理员(从数据库读取)
|
||
*/
|
||
export async function isSuperAdmin(userId: string | null | undefined): Promise<boolean> {
|
||
if (!userId) {
|
||
return false;
|
||
}
|
||
|
||
const user = await prisma.user.findUnique({
|
||
where: { id: userId },
|
||
select: { isSuperAdmin: true },
|
||
});
|
||
|
||
return user?.isSuperAdmin ?? false;
|
||
}
|
||
|
||
/**
|
||
* 同步版本的超级管理员判断(用于已经获取到用户信息的情况)
|
||
*/
|
||
export function isSuperAdminSync(isSuperAdmin: boolean): boolean {
|
||
return isSuperAdmin;
|
||
}
|
||
|
||
/**
|
||
* 获取当前超级管理员数量
|
||
*/
|
||
export async function getSuperAdminCount(): Promise<number> {
|
||
return await prisma.user.count({
|
||
where: { isSuperAdmin: true },
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 检查是否可以添加新的超级管理员(最多4个)
|
||
*/
|
||
export async function canAddSuperAdmin(): Promise<boolean> {
|
||
const count = await getSuperAdminCount();
|
||
return count < 4;
|
||
}
|
||
|
||
// 默认素材类型列表(作为后备,用于新部门创建默认权限配置时)
|
||
// 如果数据库中已有素材,会优先使用数据库中的素材类型
|
||
export const DEFAULT_MATERIAL_TYPES = [
|
||
'3D场景',
|
||
'详情页',
|
||
'材质',
|
||
'模特',
|
||
'实拍图片',
|
||
'买家秀图片',
|
||
'小红书种草',
|
||
'主图模版',
|
||
'SKU模版',
|
||
'主图视频',
|
||
'安装视频',
|
||
'种草视频',
|
||
'音乐',
|
||
'C4D模型',
|
||
'标准饰品',
|
||
'标准模型',
|
||
'品牌VI灵感',
|
||
'矢量文件',
|
||
'CAD',
|
||
] as const;
|
||
|
||
/**
|
||
* 从数据库中获取所有素材类型(去重)
|
||
*/
|
||
export async function getAllMaterialTypes(): Promise<string[]> {
|
||
try {
|
||
// 从materials表中查询所有不重复的materialType
|
||
const materials = await prisma.material.findMany({
|
||
select: {
|
||
materialType: true,
|
||
},
|
||
distinct: ['materialType'],
|
||
});
|
||
|
||
const dbTypes = materials.map((m) => m.materialType).filter(Boolean);
|
||
|
||
// 合并数据库中的类型和默认类型,去重并排序
|
||
const allTypes = Array.from(new Set([...dbTypes, ...DEFAULT_MATERIAL_TYPES])).sort();
|
||
|
||
return allTypes;
|
||
} catch (error) {
|
||
console.error('[getAllMaterialTypes] Error:', error);
|
||
// 如果查询失败,返回默认类型列表
|
||
return [...DEFAULT_MATERIAL_TYPES];
|
||
}
|
||
}
|
||
|
||
export interface DepartmentPermission {
|
||
department: string;
|
||
materialType: string;
|
||
canView: boolean;
|
||
canDownload: boolean;
|
||
canShare: boolean;
|
||
linkedToDepartment: string | null;
|
||
}
|
||
|
||
/**
|
||
* 获取部门的实际权限(考虑关联部门)
|
||
*/
|
||
export async function getDepartmentPermission(
|
||
department: string,
|
||
materialType: string
|
||
): Promise<DepartmentPermission | null> {
|
||
// 先查询当前部门的权限配置
|
||
const permission = await prisma.departmentMaterialPermission.findUnique({
|
||
where: {
|
||
department_materialType: {
|
||
department,
|
||
materialType,
|
||
},
|
||
},
|
||
});
|
||
|
||
// 如果有关联部门,从关联部门读取权限
|
||
if (permission?.linkedToDepartment) {
|
||
const linkedPermission = await prisma.departmentMaterialPermission.findUnique({
|
||
where: {
|
||
department_materialType: {
|
||
department: permission.linkedToDepartment,
|
||
materialType,
|
||
},
|
||
},
|
||
});
|
||
|
||
if (linkedPermission) {
|
||
return {
|
||
department,
|
||
materialType,
|
||
canView: linkedPermission.canView,
|
||
canDownload: linkedPermission.canDownload,
|
||
canShare: linkedPermission.canShare,
|
||
linkedToDepartment: permission.linkedToDepartment,
|
||
};
|
||
}
|
||
}
|
||
|
||
if (!permission) {
|
||
return null;
|
||
}
|
||
|
||
return {
|
||
department: permission.department,
|
||
materialType: permission.materialType,
|
||
canView: permission.canView,
|
||
canDownload: permission.canDownload,
|
||
canShare: permission.canShare,
|
||
linkedToDepartment: permission.linkedToDepartment,
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 获取部门所有素材类型的权限
|
||
*/
|
||
export async function getDepartmentPermissions(
|
||
department: string
|
||
): Promise<Record<string, DepartmentPermission>> {
|
||
const permissions = await prisma.departmentMaterialPermission.findMany({
|
||
where: { department },
|
||
});
|
||
|
||
const result: Record<string, DepartmentPermission> = {};
|
||
|
||
for (const perm of permissions) {
|
||
// 如果有关联部门,从关联部门读取
|
||
if (perm.linkedToDepartment) {
|
||
const linkedPerm = await prisma.departmentMaterialPermission.findUnique({
|
||
where: {
|
||
department_materialType: {
|
||
department: perm.linkedToDepartment,
|
||
materialType: perm.materialType,
|
||
},
|
||
},
|
||
});
|
||
|
||
if (linkedPerm) {
|
||
result[perm.materialType] = {
|
||
department,
|
||
materialType: perm.materialType,
|
||
canView: linkedPerm.canView,
|
||
canDownload: linkedPerm.canDownload,
|
||
canShare: linkedPerm.canShare,
|
||
linkedToDepartment: perm.linkedToDepartment,
|
||
};
|
||
}
|
||
} else {
|
||
result[perm.materialType] = {
|
||
department: perm.department,
|
||
materialType: perm.materialType,
|
||
canView: perm.canView,
|
||
canDownload: perm.canDownload,
|
||
canShare: perm.canShare,
|
||
linkedToDepartment: null,
|
||
};
|
||
}
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* 获取用户有查看权限的素材类型列表
|
||
*/
|
||
export async function getUserViewableMaterialTypes(
|
||
userDepartment: string | null | undefined,
|
||
userRole: string,
|
||
managedDepartment: string | null | undefined,
|
||
userId?: string | null | undefined
|
||
): Promise<string[]> {
|
||
// 超级管理员可以看到所有素材类型
|
||
if (userId && await isSuperAdmin(userId)) {
|
||
return await getAllMaterialTypes();
|
||
}
|
||
|
||
// 如果没有部门信息,返回空数组
|
||
const department = managedDepartment || userDepartment;
|
||
if (!department) {
|
||
return [];
|
||
}
|
||
|
||
// 获取该部门所有素材类型的权限
|
||
const permissions = await getDepartmentPermissions(department);
|
||
|
||
// 返回有查看权限的素材类型
|
||
return Object.values(permissions)
|
||
.filter((p) => p.canView)
|
||
.map((p) => p.materialType);
|
||
}
|
||
|
||
/**
|
||
* 检查用户是否有查看权限
|
||
*/
|
||
export async function canUserViewMaterial(
|
||
userDepartment: string | null | undefined,
|
||
userRole: string,
|
||
managedDepartment: string | null | undefined,
|
||
materialType: string,
|
||
userId?: string | null | undefined
|
||
): Promise<boolean> {
|
||
// 超级管理员可以查看所有素材
|
||
if (userId && await isSuperAdmin(userId)) {
|
||
return true;
|
||
}
|
||
|
||
// 如果没有部门信息,不允许查看
|
||
const department = managedDepartment || userDepartment;
|
||
if (!department) {
|
||
return false;
|
||
}
|
||
|
||
const permission = await getDepartmentPermission(department, materialType);
|
||
return permission?.canView ?? false;
|
||
}
|
||
|
||
/**
|
||
* 检查用户是否有下载权限
|
||
*/
|
||
export async function canUserDownloadMaterial(
|
||
userDepartment: string | null | undefined,
|
||
userRole: string,
|
||
managedDepartment: string | null | undefined,
|
||
materialType: string,
|
||
userId?: string | null | undefined
|
||
): Promise<boolean> {
|
||
// 超级管理员可以下载所有素材
|
||
if (userId && await isSuperAdmin(userId)) {
|
||
return true;
|
||
}
|
||
|
||
// 如果没有部门信息,不允许下载
|
||
const department = managedDepartment || userDepartment;
|
||
if (!department) {
|
||
return false;
|
||
}
|
||
|
||
const permission = await getDepartmentPermission(department, materialType);
|
||
return permission?.canDownload ?? false;
|
||
}
|
||
|
||
/**
|
||
* 检查是否是分享链接访问
|
||
*/
|
||
export function isShareLinkAccess(request: Request): boolean {
|
||
const url = new URL(request.url);
|
||
return url.searchParams.has('share') || url.searchParams.has('shareId');
|
||
}
|
||
|
||
/**
|
||
* 为部门创建默认权限配置
|
||
* 使用数据库中实际存在的所有素材类型
|
||
*/
|
||
export async function createDefaultPermissionsForDepartment(
|
||
department: string
|
||
): Promise<void> {
|
||
const existingPermissions = await prisma.departmentMaterialPermission.findMany({
|
||
where: { department },
|
||
});
|
||
|
||
const existingTypes = new Set(existingPermissions.map((p: any) => p.materialType));
|
||
|
||
// 获取数据库中所有素材类型
|
||
const allMaterialTypes = await getAllMaterialTypes();
|
||
|
||
const newPermissions = allMaterialTypes
|
||
.filter((type) => !existingTypes.has(type))
|
||
.map((materialType) => ({
|
||
department,
|
||
materialType,
|
||
canView: false, // 默认不允许查看
|
||
canDownload: false, // 默认不允许下载
|
||
canShare: true, // 默认允许分享
|
||
linkedToDepartment: null,
|
||
}));
|
||
|
||
if (newPermissions.length > 0) {
|
||
await prisma.departmentMaterialPermission.createMany({
|
||
data: newPermissions,
|
||
});
|
||
}
|
||
}
|
||
|