Files
track/frontend/src/pages/admin/AdminPrintConfigPage.tsx
duxingchen 59c182a743 feat(frontend): 管理端页面 — 任务全景树/创建产品/标签打印/认证守卫
App.tsx:
- AntApp + AuthProvider + ToastProvider 三层包裹
- /admin/login 独立登录页
- /admin/* 路由认证守卫

AdminLayout:
- 未登录→跳转登录; 顶部栏显示用户名+登出
- 侧边栏: 全局概览/产品管理/任务全景

CreateProductDialog (Ant Design 重写):
- MOM物料手风琴选择器 (Collapse+Table)
- 分组懒加载 + useRef缓存 + 防抖搜索
- HEX ID只读展示 + 序列号/订单号选填

AdminProductsPage:
- 打印预览弹窗 (Base64标签预览 + 份数选择)
- 打印机设置入口 → AdminPrintConfigPage

扫码组件对齐:
- ProductCard: material_name/spec_model/current_location
- TaskListCard: 递归 task_tree + 状态配色 + 返工/裂变标签
- QueryResult: task_tree 优先
- ScanPage: 宏观状态栏
2026-08-05 14:01:36 +08:00

163 lines
5.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useEffect, useState } from "react";
import { Settings, Save, Loader2, Wifi, WifiOff } from "lucide-react";
import {
getPrinterConfig,
updatePrinterConfig,
type PrinterConfig,
} from "../../services/printApi";
import { useToast } from "../../components/ui/Toast";
export default function AdminPrintConfigPage() {
const { toast } = useToast();
const [config, setConfig] = useState<PrinterConfig | null>(null);
const [loading, setLoading] = useState(true);
const [saving, setSaving] = useState(false);
// 表单字段
const [ip, setIp] = useState("");
const [port, setPort] = useState(9100);
const [enabled, setEnabled] = useState(true);
useEffect(() => {
loadConfig();
}, []);
async function loadConfig() {
setLoading(true);
try {
const cfg = await getPrinterConfig();
setConfig(cfg);
const lp = cfg.label_printer;
setIp(lp.ip);
setPort(lp.port);
setEnabled(lp.enabled ?? true);
} catch (err: any) {
toast(err?.response?.data?.detail ?? "加载配置失败", "error");
} finally {
setLoading(false);
}
}
async function handleSave(e: React.FormEvent) {
e.preventDefault();
if (!ip.trim()) {
toast("请输入打印机 IP 地址", "error");
return;
}
setSaving(true);
try {
const result = await updatePrinterConfig(ip.trim(), port, enabled);
toast(result.message, "success");
} catch (err: any) {
toast(err?.response?.data?.detail ?? "保存失败", "error");
} finally {
setSaving(false);
}
}
if (loading) {
return (
<div className="flex items-center justify-center py-20">
<Loader2 className="h-8 w-8 animate-spin text-blue-500" />
</div>
);
}
return (
<div>
<div className="mb-6">
<h2 className="text-xl font-bold text-gray-800">打印机设置</h2>
<p className="mt-1 text-sm text-gray-500">
配置标签打印机(热敏打标机)的 IP 地址和端口,协议: TSPL
</p>
</div>
<div className="max-w-md rounded-xl bg-white p-6 shadow-sm">
<form onSubmit={handleSave} className="space-y-4">
{/* IP 地址 */}
<div>
<label className="mb-1 block text-sm font-medium text-gray-700">
打印机 IP 地址
</label>
<input
type="text"
value={ip}
onChange={(e) => setIp(e.target.value)}
placeholder="如 192.168.9.221"
className="w-full rounded-lg border border-gray-200 px-3 py-2.5 text-sm font-mono focus:border-blue-400 focus:outline-none focus:ring-2 focus:ring-blue-100"
/>
</div>
{/* 端口 */}
<div>
<label className="mb-1 block text-sm font-medium text-gray-700">
端口
</label>
<input
type="number"
value={port}
onChange={(e) => setPort(Number(e.target.value))}
min={1}
max={65535}
className="w-full rounded-lg border border-gray-200 px-3 py-2.5 text-sm font-mono focus:border-blue-400 focus:outline-none focus:ring-2 focus:ring-blue-100"
/>
<p className="mt-0.5 text-xs text-gray-400">
热敏打印机通常使用 9100 端口(Raw Socket)
</p>
</div>
{/* 启用状态 */}
<label className="flex items-center gap-3 cursor-pointer select-none">
<input
type="checkbox"
checked={enabled}
onChange={(e) => setEnabled(e.target.checked)}
className="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
/>
<div className="flex items-center gap-1.5">
{enabled ? (
<Wifi className="h-4 w-4 text-green-500" />
) : (
<WifiOff className="h-4 w-4 text-gray-400" />
)}
<span className="text-sm text-gray-700">
{enabled ? "已启用" : "已禁用"}
</span>
</div>
</label>
{/* 保存 */}
<button
type="submit"
disabled={saving}
className="flex w-full items-center justify-center gap-2 rounded-lg bg-blue-600 py-2.5 text-sm font-medium text-white transition-colors hover:bg-blue-700 disabled:opacity-50"
>
{saving ? (
<Loader2 className="h-4 w-4 animate-spin" />
) : (
<Save className="h-4 w-4" />
)}
保存设置
</button>
</form>
{/* 当前状态 */}
{config?.label_printer && (
<div className="mt-4 rounded-lg bg-gray-50 px-3 py-2.5 text-xs text-gray-500">
<p>
当前配置: {config.label_printer.ip}:{config.label_printer.port}
{" · "}
{config.label_printer.enabled ? (
<span className="text-green-600 font-medium">已启用</span>
) : (
<span className="text-gray-400">已禁用</span>
)}
</p>
</div>
)}
</div>
</div>
);
}