Initial commit

This commit is contained in:
2026-04-13 20:28:09 +08:00
commit e2a2eb4666
62 changed files with 17589 additions and 0 deletions

View File

@@ -0,0 +1,288 @@
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 =
| "dashboard.view"
| "source.sync"
| "content.edit"
| "content.approve"
| "content.publish"
| "leads.manage"
| "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> = {
"dashboard.view": "查看仪表盘",
"source.sync": "车型同步",
"content.edit": "内容编辑",
"content.approve": "内容审核",
"content.publish": "内容发布",
"leads.manage": "潜客管理",
"settings.manage": "系统设置",
"users.manage": "用户与权限管理",
}
const INITIAL_ROLE_PERMISSIONS: RolePermission[] = [
{
roleName: "业务/市场负责人",
permissions: [
"dashboard.view",
"content.approve",
"content.publish",
"leads.manage",
],
},
{
roleName: "内容运营专员",
permissions: [
"dashboard.view",
"source.sync",
"content.edit",
"content.publish",
"leads.manage",
],
},
{
roleName: "项目与运维负责人",
permissions: [
"dashboard.view",
"source.sync",
"settings.manage",
"users.manage",
],
},
]
const PERMISSION_COLUMNS: PermissionKey[] = [
"dashboard.view",
"source.sync",
"content.edit",
"content.approve",
"content.publish",
"leads.manage",
"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>
)
}