超管后台 - 简化项目代码,移除掉接口返回错误时使用的虚假模拟数据

This commit is contained in:
柳清爽
2025-04-24 14:20:02 +08:00
parent 4a5b2eaa1e
commit 42d9cb6be5
3 changed files with 67 additions and 233 deletions

View File

@@ -21,46 +21,6 @@ import {
AlertDialogTitle, AlertDialogTitle,
} from "@/components/ui/alert-dialog" } from "@/components/ui/alert-dialog"
// 保留原始示例数据,作为加载失败时的备用数据
const adminsData = [
{
id: "1",
account: "admin_zhang",
username: "张管理",
role: "超级管理员",
permissions: ["项目管理", "客户池", "管理员权限"],
createdAt: "2023-05-01",
lastLogin: "2023-06-28 09:15",
},
{
id: "2",
account: "admin_li",
username: "李管理",
role: "项目管理员",
permissions: ["项目管理", "客户池"],
createdAt: "2023-05-10",
lastLogin: "2023-06-27 14:30",
},
{
id: "3",
account: "admin_wang",
username: "王管理",
role: "客户管理员",
permissions: ["客户池"],
createdAt: "2023-05-15",
lastLogin: "2023-06-28 11:45",
},
{
id: "4",
account: "admin_zhao",
username: "赵管理",
role: "项目管理员",
permissions: ["项目管理"],
createdAt: "2023-05-20",
lastLogin: "2023-06-26 16:20",
},
]
export default function AdminsPage() { export default function AdminsPage() {
const [searchTerm, setSearchTerm] = useState("") const [searchTerm, setSearchTerm] = useState("")
const [isLoading, setIsLoading] = useState(true) const [isLoading, setIsLoading] = useState(true)
@@ -95,14 +55,8 @@ export default function AdminsPage() {
description: response.msg || "请稍后重试", description: response.msg || "请稍后重试",
variant: "destructive", variant: "destructive",
}) })
// 加载失败时显示示例数据 setAdministrators([])
setAdministrators(adminsData.map(admin => ({ setTotalCount(0)
...admin,
id: Number(admin.id),
name: admin.username,
status: 1
})))
setTotalCount(adminsData.length)
} }
} catch (error) { } catch (error) {
console.error("获取管理员列表出错:", error) console.error("获取管理员列表出错:", error)
@@ -111,14 +65,8 @@ export default function AdminsPage() {
description: "请检查网络连接后重试", description: "请检查网络连接后重试",
variant: "destructive", variant: "destructive",
}) })
// 加载失败时显示示例数据 setAdministrators([])
setAdministrators(adminsData.map(admin => ({ setTotalCount(0)
...admin,
id: Number(admin.id),
name: admin.username,
status: 1
})))
setTotalCount(adminsData.length)
} finally { } finally {
setIsLoading(false) setIsLoading(false)
} }

View File

@@ -20,94 +20,6 @@ import { getTrafficPoolList } from "@/lib/traffic-pool-api"
import { Customer } from "@/lib/traffic-pool-api" import { Customer } from "@/lib/traffic-pool-api"
import { PaginationControls } from "@/components/ui/pagination-controls" import { PaginationControls } from "@/components/ui/pagination-controls"
// Sample customer data
const customersData = [
{
id: "1",
name: "张三",
avatar: "/placeholder.svg?height=40&width=40",
wechatId: "zhangsan123",
gender: "男",
region: "北京",
source: "微信搜索",
tags: ["潜在客户", "高消费"],
projectName: "电商平台项目",
addedDate: "2023-06-10",
},
{
id: "2",
name: "李四",
avatar: "/placeholder.svg?height=40&width=40",
wechatId: "lisi456",
gender: "男",
region: "上海",
source: "朋友推荐",
tags: ["活跃用户"],
projectName: "社交媒体营销",
addedDate: "2023-06-12",
},
{
id: "3",
name: "王五",
avatar: "/placeholder.svg?height=40&width=40",
wechatId: "wangwu789",
gender: "男",
region: "广州",
source: "广告点击",
tags: ["新用户"],
projectName: "企业官网推广",
addedDate: "2023-06-15",
},
{
id: "4",
name: "赵六",
avatar: "/placeholder.svg?height=40&width=40",
wechatId: "zhaoliu321",
gender: "男",
region: "深圳",
source: "线下活动",
tags: ["高消费", "忠诚客户"],
projectName: "教育平台项目",
addedDate: "2023-06-18",
},
{
id: "5",
name: "钱七",
avatar: "/placeholder.svg?height=40&width=40",
wechatId: "qianqi654",
gender: "女",
region: "成都",
source: "微信群",
tags: ["潜在客户"],
projectName: "金融服务推广",
addedDate: "2023-06-20",
},
{
id: "6",
name: "孙八",
avatar: "/placeholder.svg?height=40&width=40",
wechatId: "sunba987",
gender: "女",
region: "武汉",
source: "微信搜索",
tags: ["活跃用户", "高消费"],
projectName: "电商平台项目",
addedDate: "2023-06-22",
},
{
id: "7",
name: "周九",
avatar: "/placeholder.svg?height=40&width=40",
wechatId: "zhoujiu135",
gender: "女",
region: "杭州",
source: "朋友推荐",
tags: ["新用户"],
projectName: "社交媒体营销",
addedDate: "2023-06-25",
},
]
export default function CustomersPage() { export default function CustomersPage() {
const [searchTerm, setSearchTerm] = useState("") const [searchTerm, setSearchTerm] = useState("")
const [selectedRegion, setSelectedRegion] = useState("") const [selectedRegion, setSelectedRegion] = useState("")
@@ -162,25 +74,6 @@ export default function CustomersPage() {
setCurrentPage(1); // Reset to first page when page size changes setCurrentPage(1); // Reset to first page when page size changes
}; };
// Filter customers based on search and filters (兼容示例数据)
const filteredCustomers = customersData.filter((customer) => {
const matchesSearch =
customer.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
customer.wechatId.toLowerCase().includes(searchTerm.toLowerCase())
const matchesRegion = selectedRegion ? customer.region === selectedRegion : true
const matchesGender = selectedGender ? customer.gender === selectedGender : true
const matchesSource = selectedSource ? customer.source === selectedSource : true
const matchesProject = selectedProject ? customer.projectName === selectedProject : true
return matchesSearch && matchesRegion && matchesGender && matchesSource && matchesProject
})
// Get unique values for filters
const regions = [...new Set(customersData.map((c) => c.region))]
const sources = [...new Set(customersData.map((c) => c.source))]
const projects = [...new Set(customersData.map((c) => c.projectName))]
return ( return (
<div className="space-y-6"> <div className="space-y-6">
<div className="flex justify-between"> <div className="flex justify-between">
@@ -217,11 +110,7 @@ export default function CustomersPage() {
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem value="all"></SelectItem> <SelectItem value="all"></SelectItem>
{regions.map((region) => ( {/* 从API获取到的regions数据应在此处映射 */}
<SelectItem key={region} value={region}>
{region}
</SelectItem>
))}
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
@@ -248,28 +137,20 @@ export default function CustomersPage() {
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem value="all"></SelectItem> <SelectItem value="all"></SelectItem>
{sources.map((source) => ( {/* 从API获取到的sources数据应在此处映射 */}
<SelectItem key={source} value={source}>
{source}
</SelectItem>
))}
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
<DropdownMenuSeparator /> <DropdownMenuSeparator />
<div className="p-2"> <div className="p-2">
<p className="mb-2 text-sm font-medium"></p> <p className="mb-2 text-sm font-medium"></p>
<Select value={selectedProject} onValueChange={setSelectedProject}> <Select value={selectedProject} onValueChange={setSelectedProject}>
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="所有项目" /> <SelectValue placeholder="所有项目" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectItem value="all"></SelectItem> <SelectItem value="all"></SelectItem>
{projects.map((project) => ( {/* 从API获取到的projects数据应在此处映射 */}
<SelectItem key={project} value={project}>
{project}
</SelectItem>
))}
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
@@ -277,16 +158,16 @@ export default function CustomersPage() {
</DropdownMenu> </DropdownMenu>
</div> </div>
<div className="rounded-md border"> <div className="border rounded-md">
<Table> <Table>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead></TableHead> <TableHead></TableHead>
<TableHead>ID</TableHead>
<TableHead></TableHead> <TableHead></TableHead>
<TableHead></TableHead> <TableHead></TableHead>
<TableHead></TableHead> <TableHead></TableHead>
<TableHead></TableHead> <TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead> <TableHead></TableHead>
<TableHead className="text-right"></TableHead> <TableHead className="text-right"></TableHead>
</TableRow> </TableRow>
@@ -294,45 +175,45 @@ export default function CustomersPage() {
<TableBody> <TableBody>
{isLoading ? ( {isLoading ? (
<TableRow> <TableRow>
<TableCell colSpan={8} className="h-24 text-center"> <TableCell colSpan={8} className="text-center py-4">...</TableCell>
...
</TableCell>
</TableRow> </TableRow>
) : error ? ( ) : error ? (
<TableRow> <TableRow>
<TableCell colSpan={8} className="h-24 text-center text-red-600"> <TableCell colSpan={8} className="text-center py-4 text-red-500">{error}</TableCell>
{error}
</TableCell>
</TableRow> </TableRow>
) : customers.length > 0 ? ( ) : customers.length === 0 ? (
<TableRow>
<TableCell colSpan={8} className="text-center py-4"></TableCell>
</TableRow>
) : (
customers.map((customer) => ( customers.map((customer) => (
<TableRow key={customer.id}> <TableRow key={customer.id}>
<TableCell> <TableCell>
<div className="flex items-center gap-3"> <div className="flex items-center gap-2">
<Avatar> <Avatar className="h-8 w-8">
<AvatarImage <AvatarImage src={customer.avatar || "/placeholder.svg?height=40&width=40"} alt={customer.nickname} />
src={customer.avatar || "/placeholder.svg?height=40&width=40"} <AvatarFallback>{customer.nickname ? customer.nickname.substring(0, 1) : "?"}</AvatarFallback>
alt={customer.nickname || "未知"}
onError={(e) => {
// 图片加载失败时使用默认图片
const target = e.target as HTMLImageElement;
target.src = "/placeholder.svg?height=40&width=40";
}}
/>
<AvatarFallback>{(customer.nickname || "未知").slice(0, 2)}</AvatarFallback>
</Avatar> </Avatar>
<div> <div>
<div className="font-medium">{customer.nickname || "未知"}</div> <div className="font-medium">{customer.nickname}</div>
<div className="text-xs text-muted-foreground">{customer.gender}</div> <div className="text-sm text-muted-foreground">{customer.wechatId}</div>
</div> </div>
</div> </div>
</TableCell> </TableCell>
<TableCell>{customer.wechatId}</TableCell>
<TableCell>{customer.gender}</TableCell> <TableCell>{customer.gender}</TableCell>
<TableCell>{customer.region}</TableCell> <TableCell>{customer.region}</TableCell>
<TableCell>{customer.source}</TableCell> <TableCell>{customer.source}</TableCell>
<TableCell>{customer.projectName}</TableCell> <TableCell>
<TableCell>{customer.addTime}</TableCell> <div className="flex flex-wrap gap-1">
{customer.tags && customer.tags.map((tag) => (
<Badge key={tag} variant="secondary">
{tag}
</Badge>
))}
</div>
</TableCell>
<TableCell>{customer.companyName}</TableCell>
<TableCell>{customer.createTime}</TableCell>
<TableCell className="text-right"> <TableCell className="text-right">
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild>
@@ -342,41 +223,43 @@ export default function CustomersPage() {
</Button> </Button>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent align="end"> <DropdownMenuContent align="end">
<DropdownMenuItem asChild> <DropdownMenuItem>
<Link href={`/dashboard/customers/${customer.id}`}> <Link href={`/dashboard/customers/${customer.id}`} className="flex items-center w-full">
<Eye className="mr-2 h-4 w-4" /> <Eye className="mr-2 h-4 w-4" />
</Link> </Link>
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem> <DropdownMenuSeparator />
<UserPlus className="mr-2 h-4 w-4" /> <DropdownMenuItem></DropdownMenuItem>
</DropdownMenuItem> <DropdownMenuItem></DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
</TableCell> </TableCell>
</TableRow> </TableRow>
)) ))
) : (
<TableRow>
<TableCell colSpan={8} className="h-24 text-center">
</TableCell>
</TableRow>
)} )}
</TableBody> </TableBody>
</Table> </Table>
</div> </div>
{/* 使用新的分页组件 */} {/* 分页控制 */}
<div className="flex items-center justify-between">
<div className="text-sm text-muted-foreground">
{totalItems} {currentPage} {totalPages}
</div>
<div className="flex items-center space-x-2">
<PaginationControls <PaginationControls
currentPage={currentPage} currentPage={currentPage}
totalPages={totalPages} totalPages={totalPages}
onPageChange={setCurrentPage}
onPageSizeChange={handlePageSizeChange}
pageSize={pageSize} pageSize={pageSize}
totalItems={totalItems} totalItems={totalItems}
onPageChange={setCurrentPage} // 直接传递setCurrentPage
onPageSizeChange={handlePageSizeChange}
/> />
</div> </div>
</div> </div>
</div>
</div>
) )
} }

View File

@@ -28,6 +28,9 @@ interface Project {
deviceCount: number deviceCount: number
friendCount: number friendCount: number
userCount: number userCount: number
username: string
status: number
devices?: Device[]
} }
export default function EditProjectPage({ params }: { params: { id: string } }) { export default function EditProjectPage({ params }: { params: { id: string } }) {
@@ -37,7 +40,7 @@ export default function EditProjectPage({ params }: { params: { id: string } })
const [project, setProject] = useState<Project | null>(null) const [project, setProject] = useState<Project | null>(null)
const [password, setPassword] = useState("") const [password, setPassword] = useState("")
const [confirmPassword, setConfirmPassword] = useState("") const [confirmPassword, setConfirmPassword] = useState("")
const { id } = use(params) const id = params.id
useEffect(() => { useEffect(() => {
const fetchProject = async () => { const fetchProject = async () => {
@@ -82,8 +85,8 @@ export default function EditProjectPage({ params }: { params: { id: string } })
account: project?.account, account: project?.account,
memo: project?.memo, memo: project?.memo,
phone: project?.phone, phone: project?.phone,
username: nickname, username: project?.username,
status: parseInt(status), status: project?.status,
...(password && { password }) ...(password && { password })
}), }),
}) })
@@ -215,7 +218,7 @@ export default function EditProjectPage({ params }: { params: { id: string } })
<div className="space-y-2"> <div className="space-y-2">
<Label></Label> <Label></Label>
<div className="space-y-3"> <div className="space-y-3">
{project?.devices.length > 0 && project.devices.map((device) => ( {project && project.devices && project.devices.length > 0 && project.devices.map((device) => (
<div key={device.id} className="flex items-center gap-2"> <div key={device.id} className="flex items-center gap-2">
<Input <Input
value={device.memo} value={device.memo}