feat(admin): Complete tenant management and module access control system
Major Features: - Tenant management CRUD (list, create, edit, delete, module configuration) - Dynamic module management system (modules table with 8 modules) - Multi-tenant module permission merging (ModuleService) - Module access control middleware (requireModule) - User module permission API (GET /api/v1/auth/me/modules) - Frontend module permission filtering (HomePage + TopNavigation) Module Integration: - RVW module integrated with PromptService (editorial + methodology) - All modules (RVW/PKB/ASL/DC) added authenticate + requireModule middleware - Fixed ReviewTask foreign key constraint (cross-schema issue) - Removed all MOCK_USER_ID, unified to request.user?.userId Prompt Management Enhancements: - Module names displayed in Chinese (RVW -> 智能审稿) - Enhanced version history with view content and rollback features - List page shows both activeVersion and draftVersion columns Database Changes: - Added platform_schema.modules table - Modified tenant_modules table (added index and UUID) - Removed ReviewTask foreign key to public.users (cross-schema fix) - Seeded 8 modules: RVW, PKB, ASL, DC, IIT, AIA, SSA, ST Documentation Updates: - Updated ADMIN module development status - Updated TODO checklist (89% progress) - Updated Prompt management plan (Phase 3.5.5 completed) - Added module authentication specification Files Changed: 80+ Status: All features tested and verified locally Next: User management module development
This commit is contained in:
206
backend/scripts/query-users.js
Normal file
206
backend/scripts/query-users.js
Normal file
@@ -0,0 +1,206 @@
|
||||
// 查询数据库用户信息
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
console.log('\n========== 平台用户 (platform_schema.users) ==========\n');
|
||||
|
||||
const users = await prisma.user.findMany({
|
||||
select: {
|
||||
id: true,
|
||||
phone: true,
|
||||
name: true,
|
||||
role: true,
|
||||
status: true,
|
||||
tenant_id: true,
|
||||
},
|
||||
orderBy: { role: 'asc' }
|
||||
});
|
||||
|
||||
console.log('用户列表:');
|
||||
console.table(users.map(u => ({
|
||||
ID: u.id.substring(0, 8) + '...',
|
||||
手机号: u.phone,
|
||||
姓名: u.name,
|
||||
角色: u.role,
|
||||
状态: u.status,
|
||||
})));
|
||||
|
||||
console.log('\n默认密码: 123456');
|
||||
|
||||
console.log('\n========== 角色权限 (platform_schema.role_permissions) ==========\n');
|
||||
|
||||
const rolePerms = await prisma.role_permissions.findMany({
|
||||
include: {
|
||||
permissions: true
|
||||
},
|
||||
orderBy: { role: 'asc' }
|
||||
});
|
||||
|
||||
const permsByRole = {};
|
||||
rolePerms.forEach(rp => {
|
||||
if (!permsByRole[rp.role]) {
|
||||
permsByRole[rp.role] = [];
|
||||
}
|
||||
permsByRole[rp.role].push(rp.permissions.code);
|
||||
});
|
||||
|
||||
console.log('角色权限:');
|
||||
Object.entries(permsByRole).forEach(([role, perms]) => {
|
||||
console.log(`\n${role}:`);
|
||||
perms.forEach(p => console.log(` - ${p}`));
|
||||
});
|
||||
|
||||
console.log('\n========== 租户模块配置 (platform_schema.tenant_modules) ==========\n');
|
||||
|
||||
const tenantModules = await prisma.tenant_modules.findMany({
|
||||
orderBy: [{ tenant_id: 'asc' }, { module_code: 'asc' }]
|
||||
});
|
||||
|
||||
if (tenantModules.length === 0) {
|
||||
console.log('⚠️ 尚未配置任何租户模块(所有用户可能默认访问所有模块)');
|
||||
} else {
|
||||
const modulesByTenant = {};
|
||||
tenantModules.forEach(tm => {
|
||||
if (!modulesByTenant[tm.tenant_id]) {
|
||||
modulesByTenant[tm.tenant_id] = [];
|
||||
}
|
||||
modulesByTenant[tm.tenant_id].push({
|
||||
module: tm.module_code,
|
||||
enabled: tm.is_enabled,
|
||||
expires: tm.expires_at
|
||||
});
|
||||
});
|
||||
|
||||
Object.entries(modulesByTenant).forEach(([tenantId, modules]) => {
|
||||
console.log(`\n租户 ${tenantId.substring(0, 8)}...:`);
|
||||
modules.forEach(m => {
|
||||
const status = m.enabled ? '✅' : '❌';
|
||||
const expiry = m.expires ? ` (到期: ${m.expires})` : '';
|
||||
console.log(` ${status} ${m.module}${expiry}`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
console.log('\n========== 租户列表 (platform_schema.tenants) ==========\n');
|
||||
|
||||
const tenants = await prisma.tenants.findMany({
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
code: true,
|
||||
type: true,
|
||||
status: true,
|
||||
}
|
||||
});
|
||||
|
||||
console.table(tenants.map(t => ({
|
||||
ID: t.id.substring(0, 8) + '...',
|
||||
名称: t.name,
|
||||
代码: t.code,
|
||||
类型: t.type,
|
||||
状态: t.status,
|
||||
})));
|
||||
|
||||
console.log('\n========== 用户-租户关系 ==========\n');
|
||||
|
||||
const usersWithTenant = await prisma.user.findMany({
|
||||
select: {
|
||||
phone: true,
|
||||
name: true,
|
||||
role: true,
|
||||
tenant_id: true,
|
||||
tenants: {
|
||||
select: {
|
||||
name: true,
|
||||
code: true
|
||||
}
|
||||
}
|
||||
},
|
||||
orderBy: { role: 'asc' }
|
||||
});
|
||||
|
||||
console.table(usersWithTenant.map(u => ({
|
||||
手机号: u.phone,
|
||||
姓名: u.name,
|
||||
角色: u.role,
|
||||
租户: u.tenants?.name || 'N/A',
|
||||
租户代码: u.tenants?.code || 'N/A',
|
||||
})));
|
||||
}
|
||||
|
||||
console.log('\n========== 示范医院详情 ==========\n');
|
||||
|
||||
const demoHospital = await prisma.tenants.findFirst({
|
||||
where: { code: 'demo-hospital' },
|
||||
include: {
|
||||
tenant_modules: true,
|
||||
users: {
|
||||
select: { id: true, phone: true, name: true, role: true }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (demoHospital) {
|
||||
console.log('租户ID:', demoHospital.id);
|
||||
console.log('名称:', demoHospital.name);
|
||||
console.log('联系人:', demoHospital.contact_name);
|
||||
console.log('联系电话:', demoHospital.contact_phone);
|
||||
console.log('\n已开通模块:');
|
||||
demoHospital.tenant_modules.forEach(m => {
|
||||
console.log(` ${m.is_enabled ? '✅' : '❌'} ${m.module_code}`);
|
||||
});
|
||||
console.log('\n租户下的用户:');
|
||||
demoHospital.users.forEach(u => {
|
||||
console.log(` - ${u.phone} ${u.name} (${u.role})`);
|
||||
});
|
||||
}
|
||||
|
||||
console.log('\n========== 张主任用户信息 ==========\n');
|
||||
|
||||
const zhangUser = await prisma.user.findFirst({
|
||||
where: { phone: '13800138001' },
|
||||
include: {
|
||||
tenants: {
|
||||
include: {
|
||||
tenant_modules: true
|
||||
}
|
||||
},
|
||||
tenant_members: {
|
||||
include: {
|
||||
tenants: {
|
||||
include: {
|
||||
tenant_modules: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (zhangUser) {
|
||||
console.log('用户ID:', zhangUser.id);
|
||||
console.log('手机号:', zhangUser.phone);
|
||||
console.log('姓名:', zhangUser.name);
|
||||
console.log('角色:', zhangUser.role);
|
||||
console.log('主租户ID:', zhangUser.tenant_id);
|
||||
console.log('主租户名称:', zhangUser.tenants?.name);
|
||||
console.log('\n主租户模块配置:');
|
||||
zhangUser.tenants?.tenant_modules?.forEach(m => {
|
||||
console.log(` ${m.is_enabled ? '✅' : '❌'} ${m.module_code}`);
|
||||
});
|
||||
console.log('\n额外加入的租户:');
|
||||
zhangUser.tenant_members?.forEach(tm => {
|
||||
console.log(` - ${tm.tenants.name}`);
|
||||
tm.tenants.tenant_modules?.forEach(m => {
|
||||
console.log(` ${m.is_enabled ? '✅' : '❌'} ${m.module_code}`);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
.catch(console.error)
|
||||
.finally(() => prisma.$disconnect());
|
||||
|
||||
Reference in New Issue
Block a user