From e834e99a6b39a17d17f623977a0095fcd4f7f556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=B3=E6=B8=85=E7=88=BD?= Date: Wed, 2 Apr 2025 16:50:32 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=AE=BE=E5=A4=87=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E9=A1=B5IMEI=E8=BF=87=E9=95=BF=E6=8D=A2=E8=A1=8C?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cunkebao/app/components/DeviceSelector.tsx | 6 +- Cunkebao/app/components/device-grid.tsx | 22 +++- .../components/device-selection-dialog.tsx | 6 +- Cunkebao/app/devices/[id]/page.tsx | 6 +- Cunkebao/app/devices/page.tsx | 6 +- .../components/device-selection-dialog.tsx | 8 +- .../moments-sync/new/steps/DeviceSelector.tsx | 71 +++++++--- Cunkebao/components/ImeiDisplay.tsx | 121 ++++++++++++++++++ Cunkebao/components/device-grid.tsx | 12 +- 9 files changed, 223 insertions(+), 35 deletions(-) create mode 100644 Cunkebao/components/ImeiDisplay.tsx diff --git a/Cunkebao/app/components/DeviceSelector.tsx b/Cunkebao/app/components/DeviceSelector.tsx index cc876b07..ebd1ba62 100755 --- a/Cunkebao/app/components/DeviceSelector.tsx +++ b/Cunkebao/app/components/DeviceSelector.tsx @@ -18,6 +18,7 @@ import { PaginationNext, PaginationPrevious, } from "@/components/ui/pagination" +import { ImeiDisplay } from "@/components/ImeiDisplay" interface WechatAccount { wechatId: string @@ -169,7 +170,10 @@ export function DeviceSelector({ {device.status === "online" ? "在线" : "离线"} -
IMEI: {device.imei}
+
+ IMEI: + +
{device.wechatAccounts.map((account) => (
diff --git a/Cunkebao/app/components/device-grid.tsx b/Cunkebao/app/components/device-grid.tsx index 9b5a5fe8..028119a7 100755 --- a/Cunkebao/app/components/device-grid.tsx +++ b/Cunkebao/app/components/device-grid.tsx @@ -6,6 +6,7 @@ import { Badge } from "@/components/ui/badge" import { Checkbox } from "@/components/ui/checkbox" import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog" import { Battery, Smartphone, MessageCircle, Users, Clock } from "lucide-react" +import { ImeiDisplay } from "@/components/ImeiDisplay" export interface Device { id: string @@ -88,11 +89,15 @@ export function DeviceGrid({ /> )}
-
-
{device.name}
- - {device.status === "online" ? "在线" : "离线"} - +
+
+
{device.name}
+
+ + {device.status === "online" ? "在线" : "离线"} + +
+
@@ -142,10 +147,13 @@ export function DeviceGrid({

{selectedDevice.name}

-

IMEI: {selectedDevice.imei}

+

+ IMEI: + +

- + {selectedDevice.status === "online" ? "在线" : "离线"}
diff --git a/Cunkebao/app/components/device-selection-dialog.tsx b/Cunkebao/app/components/device-selection-dialog.tsx index 9e434c81..e467984f 100755 --- a/Cunkebao/app/components/device-selection-dialog.tsx +++ b/Cunkebao/app/components/device-selection-dialog.tsx @@ -11,6 +11,7 @@ import { Card } from "@/components/ui/card" import { Badge } from "@/components/ui/badge" import { ScrollArea } from "@/components/ui/scroll-area" import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs" +import { ImeiDisplay } from "@/components/ImeiDisplay" interface WechatAccount { wechatId: string @@ -278,7 +279,10 @@ export function DeviceSelectionDialog({ {device.status === "online" ? "在线" : "离线"}
-
IMEI: {device.imei}
+
+ IMEI: + +
{/* 微信账号信息 */}
diff --git a/Cunkebao/app/devices/[id]/page.tsx b/Cunkebao/app/devices/[id]/page.tsx index 521741eb..9a2596d1 100755 --- a/Cunkebao/app/devices/[id]/page.tsx +++ b/Cunkebao/app/devices/[id]/page.tsx @@ -12,6 +12,7 @@ import { Label } from "@/components/ui/label" import { ScrollArea } from "@/components/ui/scroll-area" import { fetchDeviceDetail, fetchDeviceRelatedAccounts, updateDeviceTaskConfig, fetchDeviceHandleLogs } from "@/api/devices" import { toast } from "sonner" +import { ImeiDisplay } from "@/components/ImeiDisplay" interface WechatAccount { id: string @@ -439,7 +440,10 @@ export default function DeviceDetailPage() { {device.status === "online" ? "在线" : "离线"}
-
IMEI: {device.imei}
+
+ IMEI: + +
{device.historicalIds && device.historicalIds.length > 0 && (
历史ID: {device.historicalIds.join(", ")}
)} diff --git a/Cunkebao/app/devices/page.tsx b/Cunkebao/app/devices/page.tsx index 037b4dba..3fae1f18 100755 --- a/Cunkebao/app/devices/page.tsx +++ b/Cunkebao/app/devices/page.tsx @@ -15,6 +15,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" import { fetchDeviceList, deleteDevice } from "@/api/devices" import { ServerDevice } from "@/types/device" import { api } from "@/lib/api" +import { ImeiDisplay } from "@/components/ImeiDisplay" // 设备接口更新为与服务端接口对应的类型 interface Device extends ServerDevice { @@ -594,7 +595,10 @@ export default function DevicesPage() { {device.status === "online" ? "在线" : "离线"} -
IMEI: {device.imei}
+
+ IMEI: + +
微信号: {device.wechatId || "未绑定"}
好友数: {device.totalFriend} diff --git a/Cunkebao/app/workspace/moments-sync/components/device-selection-dialog.tsx b/Cunkebao/app/workspace/moments-sync/components/device-selection-dialog.tsx index d87bb3d5..f4b9cfe3 100755 --- a/Cunkebao/app/workspace/moments-sync/components/device-selection-dialog.tsx +++ b/Cunkebao/app/workspace/moments-sync/components/device-selection-dialog.tsx @@ -9,6 +9,7 @@ import { Search, RefreshCw } from "lucide-react" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { ScrollArea } from "@/components/ui/scroll-area" import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group" +import { ImeiDisplay } from "@/components/ImeiDisplay" interface Device { id: string @@ -123,12 +124,15 @@ export function DeviceSelectionDialog({ open, onOpenChange, selectedDevices, onS
{device.name} - + {device.status === "online" ? "在线" : "离线"}
-
IMEI: {device.imei}
+
+ IMEI: + +
微信号: {device.wxid}
{device.usedInPlans > 0 && ( diff --git a/Cunkebao/app/workspace/moments-sync/new/steps/DeviceSelector.tsx b/Cunkebao/app/workspace/moments-sync/new/steps/DeviceSelector.tsx index 2a0c9ce6..f5e2e0b5 100755 --- a/Cunkebao/app/workspace/moments-sync/new/steps/DeviceSelector.tsx +++ b/Cunkebao/app/workspace/moments-sync/new/steps/DeviceSelector.tsx @@ -4,7 +4,7 @@ import { useState, useEffect } from "react" import { Card } from "@/components/ui/card" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" -import { Search, RefreshCw, X } from "lucide-react" +import { Search, RefreshCw, X, ChevronLeft, ChevronRight } from "lucide-react" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { Checkbox } from "@/components/ui/checkbox" import { toast } from "@/components/ui/use-toast" @@ -17,6 +17,7 @@ import { PaginationNext, PaginationPrevious, } from "@/components/ui/pagination" +import { ImeiDisplay } from "@/components/ImeiDisplay" // 定义类型,避免导入错误 interface Device { @@ -148,6 +149,16 @@ export function DeviceSelector({ formData, onChange, onNext, onPrev }: DeviceSel } } + const handlePrevPage = () => { + setCurrentPage((prev) => Math.max(1, prev - 1)) + } + + const handleNextPage = () => { + setCurrentPage((prev) => Math.min(Math.ceil(filteredDevices.length / itemsPerPage), prev + 1)) + } + + const isLastPage = currentPage === Math.ceil(filteredDevices.length / itemsPerPage) + return (
@@ -193,15 +204,14 @@ export function DeviceSelector({ formData, onChange, onNext, onPrev }: DeviceSel
{device.name}
-
+ {device.status === "online" ? "在线" : "离线"} -
+ +
+
+ IMEI: +
-
IMEI: {device.imei}
微信号: {device.wechatId}
{device.usedInPlans > 0 && (
已用于 {device.usedInPlans} 个计划
@@ -211,24 +221,25 @@ export function DeviceSelector({ formData, onChange, onNext, onPrev }: DeviceSel ))}
- + setCurrentPage((prev) => Math.max(1, prev - 1))} + onClick={handlePrevPage} disabled={currentPage === 1} /> - {Array.from({ length: Math.ceil(filteredDevices.length / itemsPerPage) }, (_, i) => i + 1).map((page) => ( - - setCurrentPage(page)} isActive={currentPage === page}> - {page} + {Array.from({ length: Math.ceil(filteredDevices.length / itemsPerPage) }).map((_, index) => ( + + setCurrentPage(index + 1)} + isActive={currentPage === index + 1} + > + {index + 1} ))} - setCurrentPage((prev) => Math.min(Math.ceil(filteredDevices.length / itemsPerPage), prev + 1)) - } - disabled={currentPage === Math.ceil(filteredDevices.length / itemsPerPage)} + onClick={handleNextPage} + disabled={isLastPage} /> @@ -268,6 +279,30 @@ export function DeviceSelector({ formData, onChange, onNext, onPrev }: DeviceSel 下一步
+ +
+ + +
+ {currentPage} / {Math.ceil(filteredDevices.length / itemsPerPage)} +
+ + +
) diff --git a/Cunkebao/components/ImeiDisplay.tsx b/Cunkebao/components/ImeiDisplay.tsx new file mode 100644 index 00000000..ef95a33e --- /dev/null +++ b/Cunkebao/components/ImeiDisplay.tsx @@ -0,0 +1,121 @@ +"use client" + +import { useState, useEffect } from "react" +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription +} from "@/components/ui/dialog" +import { Button } from "@/components/ui/button" +import { Copy } from "lucide-react" +import { toast } from "@/components/ui/use-toast" + +interface ImeiDisplayProps { + imei: string + className?: string + containerWidth?: string | number // 可以接受字符串或数字类型的容器宽度配置 +} + +export function ImeiDisplay({ imei, className = "", containerWidth = "max-w-[calc(100%-40px)]" }: ImeiDisplayProps) { + // 初始状态设为false,确保服务端渲染和客户端水合时状态一致 + const [open, setOpen] = useState(false) + const [mounted, setMounted] = useState(false) + + // 确保只在客户端执行的初始化逻辑 + useEffect(() => { + setMounted(true) + }, []) + + const handleCopy = () => { + // 只在客户端执行 + if (typeof navigator === 'undefined') return + + try { + if (navigator.clipboard) { + navigator.clipboard.writeText(imei) + toast({ + title: "已复制", + description: "IMEI已复制到剪贴板", + }) + } else { + // 备用复制方法 + const textArea = document.createElement("textarea") + textArea.value = imei + document.body.appendChild(textArea) + textArea.focus() + textArea.select() + + try { + document.execCommand('copy') + toast({ + title: "已复制", + description: "IMEI已复制到剪贴板", + }) + } catch (err) { + toast({ + title: "复制失败", + description: "您的浏览器不支持自动复制", + variant: "destructive" + }) + } + + document.body.removeChild(textArea) + } + } catch (err) { + toast({ + title: "复制失败", + description: "您的浏览器不支持自动复制", + variant: "destructive" + }) + } + } + + // 处理containerWidth为数字的情况 + const widthStyle = typeof containerWidth === 'number' + ? `max-w-[${containerWidth}px]` + : containerWidth + + // 服务端渲染时,仅返回静态内容 + if (!mounted) { + return {imei} + } + + return ( + <> + { + e.stopPropagation() + setOpen(true) + }} + title={imei} + > + {imei} + + + + + + 设备IMEI + + 完整的设备唯一标识符 + + +
+ {imei} + +
+
+
+ + ) +} \ No newline at end of file diff --git a/Cunkebao/components/device-grid.tsx b/Cunkebao/components/device-grid.tsx index 8688f88f..6b93ac49 100755 --- a/Cunkebao/components/device-grid.tsx +++ b/Cunkebao/components/device-grid.tsx @@ -2,8 +2,9 @@ import { Card } from "@/components/ui/card" import { Badge } from "@/components/ui/badge" -import { Smartphone, Battery, Users, MessageCircle } from "lucide-react" +import { Smartphone, Battery, Users, MessageCircle, Clock } from "lucide-react" import { Checkbox } from "@/components/ui/checkbox" +import { ImeiDisplay } from "@/components/ImeiDisplay" export interface Device { id: string @@ -54,7 +55,7 @@ export function DeviceGrid({ devices, selectable, selectedDevices, onSelect, dev )}
- + {currentStatus.status === "online" ? "在线" : "离线"}
@@ -68,7 +69,10 @@ export function DeviceGrid({ devices, selectable, selectedDevices, onSelect, dev
{device.name}
-
IMEI-{device.imei}
+
+ IMEI: + +
{device.remark &&
备注: {device.remark}
} @@ -90,7 +94,7 @@ export function DeviceGrid({ devices, selectable, selectedDevices, onSelect, dev
今日添加:{device.todayAdded}
加友状态: - + {device.addFriendStatus === "normal" ? "正常" : "异常"}