feat: 全局概览/产品管理/人员看板跳转统一改为新标签页打开

This commit is contained in:
2026-09-03 16:27:18 +08:00
parent f65f6e12c6
commit 09984951fb
3 changed files with 10 additions and 21 deletions

View File

@ -4,7 +4,6 @@ import {
RefreshCw, Loader2, AlertCircle, ArrowRight, ArrowUp, ArrowDown, ArrowUpDown,
Clock, MessageCircle, CheckCircle2, Users,
} from "lucide-react";
import { useNavigate } from "react-router-dom";
import { Radio, DatePicker, Drawer, Input } from "antd";
import dayjs, { type Dayjs } from "dayjs";
import {
@ -79,10 +78,9 @@ function durationLabel(h: number) {
}
function WipRow({ t }: { t: WipTask }) {
const nav = useNavigate();
const handleClick = () => {
if (t.product_sn) {
nav(`/admin/tasks?sn=${t.product_sn}`);
window.open(`/admin/tasks?sn=${t.product_sn}`, "_blank");
}
};
return (
@ -162,11 +160,10 @@ function MsgRow({ m }: { m: ProductMessageItem }) {
// ─── 已完成明细项(卡片式) ─────────────────────────────
function CompletedRow({ t }: { t: CompletedTask }) {
const nav = useNavigate();
const completedTime = t.completed_at ? dayjs(t.completed_at).format("YYYY-MM-DD HH:mm") : "";
return (
<div
onClick={() => t.product_sn && nav(`/admin/tasks?sn=${t.product_sn}`)}
onClick={() => t.product_sn && window.open(`/admin/tasks?sn=${t.product_sn}`, "_blank")}
className="cursor-pointer rounded-lg border border-gray-100 bg-white px-4 py-3 transition-shadow hover:border-emerald-200 hover:shadow-md"
>
<div className="flex items-center gap-2">
@ -191,12 +188,11 @@ function CompletedRow({ t }: { t: CompletedTask }) {
// ─── 被驳回明细项(卡片式) ──────────────────────────────
function RejectedRow({ t }: { t: RejectedTask }) {
const nav = useNavigate();
const timeStr = t.rejected_at ? dayjs(t.rejected_at).format("YYYY-MM-DD HH:mm") : "";
const isRework = t.kind === "rework";
return (
<div
onClick={() => t.product_sn && nav(`/admin/tasks?sn=${t.product_sn}`)}
onClick={() => t.product_sn && window.open(`/admin/tasks?sn=${t.product_sn}`, "_blank")}
className="cursor-pointer rounded-lg border border-gray-100 bg-white px-4 py-3 transition-shadow hover:border-red-200 hover:shadow-md"
>
<div className="flex items-center gap-2">
@ -286,8 +282,6 @@ export default function AdminDashboard() {
const [opDetailLoading, setOpDetailLoading] = useState(false);
const [opDetailTitle, setOpDetailTitle] = useState("");
const navigate = useNavigate();
// ── 加载主数据 ──
const loadData = useCallback((key: DateRangeKey, range: [Dayjs, Dayjs] | null) => {
setLoading(true);
@ -536,7 +530,7 @@ export default function AdminDashboard() {
</button>
</div>
<div className="mt-3 flex items-center justify-between border-t border-gray-100 pt-3">
<button onClick={() => navigate("/notifications")}
<button onClick={() => window.open("/notifications", "_blank")}
className="flex items-center gap-1 text-xs text-gray-500 hover:text-blue-600">
<Bell className="h-3.5 w-3.5" />
{stats.unread_notifications > 0 ? `(${stats.unread_notifications})` : ""}
@ -596,15 +590,15 @@ export default function AdminDashboard() {
<div className="rounded-xl bg-white p-5 shadow-sm">
<h3 className="mb-4 text-sm font-semibold text-gray-700"> </h3>
<div className="space-y-2">
<button onClick={() => navigate("/admin/products")}
<button onClick={() => window.open("/admin/products", "_blank")}
className="flex w-full items-center justify-between rounded-lg bg-blue-50 px-4 py-3 text-left text-sm font-medium text-blue-700 hover:bg-blue-100 transition-colors">
<span>📦 </span><ArrowRight className="h-4 w-4" />
</button>
<button onClick={() => navigate("/admin/tasks")}
<button onClick={() => window.open("/admin/tasks", "_blank")}
className="flex w-full items-center justify-between rounded-lg bg-purple-50 px-4 py-3 text-left text-sm font-medium text-purple-700 hover:bg-purple-100 transition-colors">
<span>📋 </span><ArrowRight className="h-4 w-4" />
</button>
<button onClick={() => navigate("/notifications")}
<button onClick={() => window.open("/notifications", "_blank")}
className="flex w-full items-center justify-between rounded-lg bg-blue-50 px-4 py-3 text-left text-sm font-medium text-blue-700 hover:bg-blue-100 transition-colors">
<span>🔔 </span><ArrowRight className="h-4 w-4" />
</button>

View File

@ -1,9 +1,8 @@
/** 人员看板 — 实时在制品 + 历史工时台账 */
import { useEffect, useMemo, useState } from "react";
import {
Users, Package, ChevronDown, ChevronRight, Loader2, AlertCircle, RefreshCw, Clock, Download,
Users, Package, ChevronDown, ChevronRight, Loader2, AlertCircle, Clock, Download,
} from "lucide-react";
import { useNavigate } from "react-router-dom";
import { Radio, DatePicker, Table, Button, AutoComplete, Modal, Timeline, Image, Select } from "antd";
import type { ColumnsType } from "antd/es/table";
import dayjs, { type Dayjs } from "dayjs";
@ -83,8 +82,6 @@ export default function AdminPeoplePage() {
}
});
const navigate = useNavigate();
const load = () => {
setLoading(true);
fetchPeopleWorkload()
@ -338,7 +335,7 @@ export default function AdminPeoplePage() {
{w.devices.map((d) => (
<div
key={d.product_id}
onClick={() => navigate(`/admin/tasks?sn=${d.serial_number}`)}
onClick={() => window.open(`/admin/tasks?sn=${d.serial_number}`, "_blank")}
className="flex cursor-pointer items-center gap-3 rounded-lg border border-gray-100 bg-white px-4 py-2.5 transition-shadow hover:border-blue-200 hover:shadow-md"
>
<span className={`shrink-0 rounded-full px-2 py-0.5 text-[10px] font-bold ${d.task_status === "WIP" ? "bg-blue-100 text-blue-700" : "bg-amber-100 text-amber-700"}`}>

View File

@ -1,5 +1,4 @@
import { useEffect, useState, useMemo } from "react";
import { useNavigate } from "react-router-dom";
import {
Printer, RefreshCw, Loader2, QrCode, Plus, Settings, X,
Package, Hash, Tag, MapPin, Clock, Timer, CalendarDays,
@ -29,7 +28,6 @@ interface ProductGroup { groupKey: string; products: ProductResponse[]; allInWar
export default function AdminProductsPage() {
const { toast } = useToast();
const navigate = useNavigate();
const [products, setProducts] = useState<ProductResponse[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
@ -229,7 +227,7 @@ export default function AdminProductsPage() {
<div className="border-t border-gray-100 px-5 py-4">
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
{group.products.map(p => (
<div key={p.id} onClick={() => navigate(`/admin/tasks?sn=${p.serial_number}`)} className="group relative flex cursor-pointer flex-col rounded-xl bg-white shadow-sm ring-1 ring-gray-100 transition-shadow hover:shadow-md">
<div key={p.id} onClick={() => window.open(`/admin/tasks?sn=${p.serial_number}`, "_blank")} className="group relative flex cursor-pointer flex-col rounded-xl bg-white shadow-sm ring-1 ring-gray-100 transition-shadow hover:shadow-md">
<div className="absolute top-2 right-2 flex gap-1 opacity-0 transition-opacity group-hover:opacity-100 z-10">
<button onClick={(e) => { e.stopPropagation(); openEdit(p); }} className="rounded-lg bg-white p-1.5 text-gray-400 shadow-sm hover:bg-blue-50 hover:text-blue-600"><Pencil className="h-3.5 w-3.5" /></button>
<button onClick={(e) => { e.stopPropagation(); confirmDelete(p); }} className="rounded-lg bg-white p-1.5 text-gray-400 shadow-sm hover:bg-red-50 hover:text-red-500"><Trash2 className="h-3.5 w-3.5" /></button>