278 lines
9.2 KiB
TypeScript
278 lines
9.2 KiB
TypeScript
import * as React from "react"
|
||
import { ShieldCheck, UserCog, Users } from "lucide-react"
|
||
|
||
import { Badge } from "@/components/ui/badge"
|
||
import { Button } from "@/components/ui/button"
|
||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||
import { Input } from "@/components/ui/input"
|
||
import {
|
||
Table,
|
||
TableBody,
|
||
TableCell,
|
||
TableHead,
|
||
TableHeader,
|
||
TableRow,
|
||
} from "@/components/ui/table"
|
||
|
||
type UserStatus = "enabled" | "disabled"
|
||
|
||
type UserRecord = {
|
||
id: string
|
||
name: string
|
||
account: string
|
||
role: "业务/市场负责人" | "内容运营专员" | "项目与运维负责人"
|
||
status: UserStatus
|
||
lastLogin: string
|
||
}
|
||
|
||
type PermissionKey =
|
||
| "source.sync"
|
||
| "content.edit"
|
||
| "content.approve"
|
||
| "content.publish"
|
||
| "settings.manage"
|
||
| "users.manage"
|
||
|
||
type RolePermission = {
|
||
roleName: "业务/市场负责人" | "内容运营专员" | "项目与运维负责人"
|
||
permissions: PermissionKey[]
|
||
}
|
||
|
||
const INITIAL_USERS: UserRecord[] = [
|
||
{
|
||
id: "u1",
|
||
name: "陈经理",
|
||
account: "market.chen",
|
||
role: "业务/市场负责人",
|
||
status: "enabled",
|
||
lastLogin: "2026-04-12 09:18",
|
||
},
|
||
{
|
||
id: "u2",
|
||
name: "刘运营",
|
||
account: "content.liu",
|
||
role: "内容运营专员",
|
||
status: "enabled",
|
||
lastLogin: "2026-04-12 08:42",
|
||
},
|
||
{
|
||
id: "u3",
|
||
name: "王运维",
|
||
account: "ops.wang",
|
||
role: "项目与运维负责人",
|
||
status: "enabled",
|
||
lastLogin: "2026-04-11 20:05",
|
||
},
|
||
{
|
||
id: "u4",
|
||
name: "赵测试",
|
||
account: "qa.zhao",
|
||
role: "内容运营专员",
|
||
status: "disabled",
|
||
lastLogin: "2026-04-01 11:20",
|
||
},
|
||
]
|
||
|
||
const PERMISSION_LABEL: Record<PermissionKey, string> = {
|
||
"source.sync": "官网车型库",
|
||
"content.edit": "内容编辑",
|
||
"content.approve": "内容审核",
|
||
"content.publish": "内容发布",
|
||
"settings.manage": "系统设置",
|
||
"users.manage": "用户与权限管理",
|
||
}
|
||
|
||
const INITIAL_ROLE_PERMISSIONS: RolePermission[] = [
|
||
{
|
||
roleName: "业务/市场负责人",
|
||
permissions: [
|
||
"content.approve",
|
||
"content.publish",
|
||
],
|
||
},
|
||
{
|
||
roleName: "内容运营专员",
|
||
permissions: [
|
||
"source.sync",
|
||
"content.edit",
|
||
"content.publish",
|
||
],
|
||
},
|
||
{
|
||
roleName: "项目与运维负责人",
|
||
permissions: [
|
||
"source.sync",
|
||
"settings.manage",
|
||
"users.manage",
|
||
],
|
||
},
|
||
]
|
||
|
||
const PERMISSION_COLUMNS: PermissionKey[] = [
|
||
"source.sync",
|
||
"content.edit",
|
||
"content.approve",
|
||
"content.publish",
|
||
"settings.manage",
|
||
"users.manage",
|
||
]
|
||
|
||
export function UserAccessManagement() {
|
||
const [query, setQuery] = React.useState("")
|
||
const [users, setUsers] = React.useState<UserRecord[]>(INITIAL_USERS)
|
||
const [rolePermissions, setRolePermissions] = React.useState<RolePermission[]>(INITIAL_ROLE_PERMISSIONS)
|
||
|
||
const filteredUsers = users.filter((user) => {
|
||
const key = `${user.name} ${user.account} ${user.role}`.toLowerCase()
|
||
return key.includes(query.toLowerCase())
|
||
})
|
||
|
||
const toggleUserStatus = (id: string) => {
|
||
setUsers((prev) =>
|
||
prev.map((user) =>
|
||
user.id === id
|
||
? { ...user, status: user.status === "enabled" ? "disabled" : "enabled" }
|
||
: user
|
||
)
|
||
)
|
||
}
|
||
|
||
const togglePermission = (roleName: RolePermission["roleName"], permission: PermissionKey) => {
|
||
setRolePermissions((prev) =>
|
||
prev.map((role) => {
|
||
if (role.roleName !== roleName) return role
|
||
const has = role.permissions.includes(permission)
|
||
return {
|
||
...role,
|
||
permissions: has
|
||
? role.permissions.filter((item) => item !== permission)
|
||
: [...role.permissions, permission],
|
||
}
|
||
})
|
||
)
|
||
}
|
||
|
||
return (
|
||
<div className="flex flex-col gap-6 p-8">
|
||
<div className="flex items-center justify-between">
|
||
<div className="flex flex-col gap-1">
|
||
<h1 className="text-3xl font-bold tracking-tight">用户与权限管理</h1>
|
||
<p className="text-muted-foreground">集中维护后台账号状态、角色定义与内容平台权限边界。</p>
|
||
</div>
|
||
<Button className="bg-audi-black hover:bg-audi-dark-gray text-white px-6">新增用户</Button>
|
||
</div>
|
||
|
||
<Card className="border-none shadow-sm bg-white">
|
||
<CardHeader>
|
||
<div className="flex items-center justify-between gap-3">
|
||
<div>
|
||
<CardTitle className="text-lg font-bold">用户管理</CardTitle>
|
||
<CardDescription>管理账号启用状态与角色归属。</CardDescription>
|
||
</div>
|
||
<div className="w-full max-w-xs">
|
||
<Input
|
||
value={query}
|
||
onChange={(e) => setQuery(e.target.value)}
|
||
placeholder="搜索姓名、账号或角色..."
|
||
/>
|
||
</div>
|
||
</div>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<Table>
|
||
<TableHeader>
|
||
<TableRow className="hover:bg-transparent border-b border-gray-100">
|
||
<TableHead className="font-bold text-audi-black">姓名</TableHead>
|
||
<TableHead className="font-bold text-audi-black">账号</TableHead>
|
||
<TableHead className="font-bold text-audi-black">角色</TableHead>
|
||
<TableHead className="font-bold text-audi-black">状态</TableHead>
|
||
<TableHead className="font-bold text-audi-black">最近登录</TableHead>
|
||
<TableHead className="text-right font-bold text-audi-black">操作</TableHead>
|
||
</TableRow>
|
||
</TableHeader>
|
||
<TableBody>
|
||
{filteredUsers.map((user) => (
|
||
<TableRow key={user.id} className="hover:bg-gray-50/50 border-b border-gray-50 transition-colors">
|
||
<TableCell className="font-medium">{user.name}</TableCell>
|
||
<TableCell className="text-muted-foreground">{user.account}</TableCell>
|
||
<TableCell>
|
||
<Badge variant="outline">{user.role}</Badge>
|
||
</TableCell>
|
||
<TableCell>
|
||
<Badge
|
||
variant="outline"
|
||
className={
|
||
user.status === "enabled"
|
||
? "bg-emerald-50 text-emerald-700 border-emerald-200"
|
||
: "bg-zinc-100 text-zinc-700 border-zinc-200"
|
||
}
|
||
>
|
||
{user.status === "enabled" ? "启用" : "停用"}
|
||
</Badge>
|
||
</TableCell>
|
||
<TableCell className="text-xs text-muted-foreground">{user.lastLogin}</TableCell>
|
||
<TableCell className="text-right">
|
||
<div className="inline-flex gap-2">
|
||
<Button size="sm" variant="outline">
|
||
编辑角色
|
||
</Button>
|
||
<Button size="sm" variant="outline" onClick={() => toggleUserStatus(user.id)}>
|
||
{user.status === "enabled" ? "停用" : "启用"}
|
||
</Button>
|
||
</div>
|
||
</TableCell>
|
||
</TableRow>
|
||
))}
|
||
</TableBody>
|
||
</Table>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
<Card className="border-none shadow-sm bg-white">
|
||
<CardHeader>
|
||
<CardTitle className="text-lg font-bold">角色与权限管理</CardTitle>
|
||
<CardDescription>按角色授予菜单、操作与审批权限(原型可直接勾选)。</CardDescription>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<div className="mb-3 flex items-center gap-2 text-sm text-muted-foreground">
|
||
<Users className="h-4 w-4" />角色
|
||
<UserCog className="h-4 w-4 ml-4" />权限
|
||
<ShieldCheck className="h-4 w-4 ml-4 text-audi-red" />权限边界
|
||
</div>
|
||
<Table>
|
||
<TableHeader>
|
||
<TableRow className="hover:bg-transparent border-b border-gray-100">
|
||
<TableHead className="font-bold text-audi-black">角色</TableHead>
|
||
{PERMISSION_COLUMNS.map((permission) => (
|
||
<TableHead key={permission} className="font-bold text-audi-black text-xs">
|
||
{PERMISSION_LABEL[permission]}
|
||
</TableHead>
|
||
))}
|
||
</TableRow>
|
||
</TableHeader>
|
||
<TableBody>
|
||
{rolePermissions.map((role) => (
|
||
<TableRow key={role.roleName} className="hover:bg-gray-50/50 border-b border-gray-50 transition-colors">
|
||
<TableCell className="font-medium">{role.roleName}</TableCell>
|
||
{PERMISSION_COLUMNS.map((permission) => {
|
||
const checked = role.permissions.includes(permission)
|
||
return (
|
||
<TableCell key={`${role.roleName}-${permission}`}>
|
||
<input
|
||
type="checkbox"
|
||
checked={checked}
|
||
onChange={() => togglePermission(role.roleName, permission)}
|
||
/>
|
||
</TableCell>
|
||
)
|
||
})}
|
||
</TableRow>
|
||
))}
|
||
</TableBody>
|
||
</Table>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
)
|
||
}
|