视频接入接口
This commit is contained in:
217
build_log2.txt
Normal file
217
build_log2.txt
Normal file
@@ -0,0 +1,217 @@
|
||||
|
||||
> react-example@0.0.0 build
|
||||
> vite build
|
||||
|
||||
[36mvite v6.4.2 [32mbuilding for production...[36m[39m
|
||||
transforming...
|
||||
[32m鉁?[39m 9321 modules transformed.
|
||||
rendering chunks...
|
||||
npm : [33m[plugin vite:reporter]
|
||||
所在位置 行:1 字符: 25
|
||||
+ cd "D:\code\机器人智慧服务系统"; npm run build 2>&1 | Out-String -Width 300 | ...
|
||||
+ ~~~~~~~~~~~~~~~~~~
|
||||
+ CategoryInfo : NotSpecified: ([33m[plugin vite:reporter] :String) [], RemoteException
|
||||
+ FullyQualifiedErrorId : NativeCommandError
|
||||
|
||||
(!) D:/code/鏈哄櫒浜烘櫤鎱ф湇鍔$郴缁?src/store/userSlice.ts is dynamically imported by D:/code/鏈哄櫒浜烘櫤鎱ф湇鍔$郴缁?src/api/request.ts but also statically imported by D:/code/鏈哄櫒浜烘櫤鎱ф湇鍔$郴缁?src/components/Layout.tsx, D:/code/鏈哄櫒浜烘櫤鎱ф湇鍔$郴缁?src/pages/Login.tsx, D:/code/鏈哄櫒浜烘櫤鎱ф湇鍔$郴缁?src/pages/Profile.tsx, D:/code/鏈哄櫒浜烘櫤
|
||||
鎱ф湇鍔$郴缁?src/store/index.ts, dynamic import will not move module into another chunk.
|
||||
[39m
|
||||
[33m[plugin vite:reporter]
|
||||
(!) D:/code/鏈哄櫒浜烘櫤鎱ф湇鍔$郴缁?src/store/index.ts is dynamically imported by D:/code/鏈哄櫒浜烘櫤鎱ф湇鍔$郴缁?src/api/request.ts but also statically imported by D:/code/鏈哄櫒浜烘櫤鎱ф湇鍔$郴缁?src/components/Layout.tsx, D:/code/鏈哄櫒浜烘櫤鎱ф湇鍔$郴缁?src/main.tsx, D:/code/鏈哄櫒浜烘櫤鎱ф湇鍔$郴缁?src/pages/Login.tsx, D:/code/鏈哄櫒浜烘櫤鎱ф湇鍔$郴缁?src/p
|
||||
ages/Profile.tsx, dynamic import will not move module into another chunk.
|
||||
[39m
|
||||
computing gzip size...
|
||||
[2mdist/[22m[32mindex.html [39m[1m[2m 2.52 kB[22m[1m[22m[2m 鈹?gzip: 1.13 kB[22m
|
||||
[2mdist/[22m[32massets/gecaocar-DMp9NnzT.png [39m[1m[2m 16.23 kB[22m[1m[22m
|
||||
[2mdist/[22m[32massets/bgmain-DtapCCMy.jpg [39m[1m[2m 71.91 kB[22m[1m[22m
|
||||
[2mdist/[22m[32massets/xunjiancar-CAfmDzzl.png [39m[1m[2m 213.39 kB[22m[1m[22m
|
||||
[2mdist/[22m[32massets/carplane-f-ISorrw.png [39m[1m[2m 259.24 kB[22m[1m[22m
|
||||
[2mdist/[22m[32massets/logincard-B8hQtFRG.png [39m[1m[2m 355.36 kB[22m[1m[22m
|
||||
[2mdist/[22m[32massets/logo-BZW_A_MC.png [39m[1m[2m 1,814.58 kB[22m[1m[22m
|
||||
[2mdist/[22m[32massets/bgc2-CfINnBvq.png [39m[1m[2m 3,954.80 kB[22m[1m[22m
|
||||
[2mdist/[22m[32massets/inspectCar-C-BgLHu6.png [39m[1m[2m14,801.70 kB[22m[1m[22m
|
||||
[2mdist/[22m[35massets/Home-C67sUCdb.css [39m[1m[2m 1.21 kB[22m[1m[22m[2m 鈹?gzip: 0.55 kB[22m
|
||||
[2mdist/[22m[35massets/index-bPDl6cOh.css [39m[1m[2m 70.30 kB[22m[1m[22m[2m 鈹?gzip: 12.91 kB[22m
|
||||
[2mdist/[22m[36massets/useForceUpdate-CZFCNyeq.js [39m[1m[2m 0.11 kB[22m[1m[22m[2m 鈹?gzip: 0.13 kB[22m
|
||||
[2mdist/[22m[36massets/EyeOutlined-BFyfoix3.js [39m[1m[2m 0.20 kB[22m[1m[22m[2m 鈹?gzip: 0.18 kB[22m
|
||||
[2mdist/[22m[36massets/index-Bjna-cdU.js [39m[1m[2m 0.29 kB[22m[1m[22m[2m 鈹?gzip: 0.17 kB[22m
|
||||
[2mdist/[22m[36massets/constants-DwgWOJkA.js [39m[1m[2m 0.31 kB[22m[1m[22m[2m 鈹?gzip: 0.28 kB[22m
|
||||
[2mdist/[22m[36massets/chevron-right-vVBQ_U9m.js [39m[1m[2m 0.31 kB[22m[1m[22m[2m 鈹?gzip: 0.25 kB[22m
|
||||
[2mdist/[22m[36massets/SwapRightOutlined-CaVf5wQU.js [39m[1m[2m 0.32 kB[22m[1m[22m[2m 鈹?gzip: 0.26 kB[22m
|
||||
[2mdist/[22m[36massets/index-Be-tFikO.js [39m[1m[2m 0.35 kB[22m[1m[22m[2m 鈹?gzip: 0.19 kB[22m
|
||||
[2mdist/[22m[36massets/useBreakpoint-DAxx-Njc.js [39m[1m[2m 0.37 kB[22m[1m[22m[2m 鈹?gzip: 0.27 kB[22m
|
||||
[2mdist/[22m[36massets/Empty-xLCAL5dw.js [39m[1m[2m 0.40 kB[22m[1m[22m[2m 鈹?gzip: 0.32 kB[22m
|
||||
[2mdist/[22m[36massets/CloseOutlined-JMAuRABM.js [39m[1m[2m 0.41 kB[22m[1m[22m[2m 鈹?gzip: 0.31 kB[22m
|
||||
[2mdist/[22m[36massets/wind-1zUaWqEo.js [39m[1m[2m 0.43 kB[22m[1m[22m[2m 鈹?gzip: 0.31 kB[22m
|
||||
[2mdist/[22m[36massets/CheckOutlined-D2FgLXFS.js [39m[1m[2m 0.44 kB[22m[1m[22m[2m 鈹?gzip: 0.32 kB[22m
|
||||
[2mdist/[22m[36massets/PlusOutlined-D6I49DVX.js [39m[1m[2m 0.44 kB[22m[1m[22m[2m 鈹?gzip: 0.32 kB[22m
|
||||
[2mdist/[22m[36massets/EditOutlined-BR5vRp4u.js [39m[1m[2m 0.44 kB[22m[1m[22m[2m 鈹?gzip: 0.32 kB[22m
|
||||
[2mdist/[22m[36massets/SearchOutlined-DSqH5eOx.js [39m[1m[2m 0.44 kB[22m[1m[22m[2m 鈹?gzip: 0.32 kB[22m
|
||||
[2mdist/[22m[36massets/index-B8qYoa6A.js [39m[1m[2m 0.44 kB[22m[1m[22m[2m 鈹?gzip: 0.22 kB[22m
|
||||
[2mdist/[22m[36massets/zap-BbovkZw3.js [39m[1m[2m 0.45 kB[22m[1m[22m[2m 鈹?gzip: 0.32 kB[22m
|
||||
[2mdist/[22m[36massets/collapse-BbEVqHco.js [39m[1m[2m 0.45 kB[22m[1m[22m[2m 鈹?gzip: 0.20 kB[22m
|
||||
[2mdist/[22m[36massets/EyeOutlined-BRmjDxUJ.js [39m[1m[2m 0.45 kB[22m[1m[22m[2m 鈹?gzip: 0.32 kB[22m
|
||||
[2mdist/[22m[36massets/DeleteOutlined-DcPIqNbE.js [39m[1m[2m 0.45 kB[22m[1m[22m[2m 鈹?gzip: 0.32 kB[22m
|
||||
[2mdist/[22m[36massets/CalendarOutlined-DmuAJ4dw.js [39m[1m[2m 0.45 kB[22m[1m[22m[2m 鈹?gzip: 0.33 kB[22m
|
||||
[2mdist/[22m[36massets/DownloadOutlined-Dk0o-amg.js [39m[1m[2m 0.45 kB[22m[1m[22m[2m 鈹?gzip: 0.33 kB[22m
|
||||
[2mdist/[22m[36massets/ClockCircleOutlined-BdM1xofC.js [39m[1m[2m 0.46 kB[22m[1m[22m[2m 鈹?gzip: 0.33 kB[22m
|
||||
[2mdist/[22m[36massets/DownloadOutlined-DTidZHln.js [39m[1m[2m 0.46 kB[22m[1m[22m[2m 鈹?gzip: 0.30 kB[22m
|
||||
[2mdist/[22m[36massets/SwapOutlined-MHggqN5a.js [39m[1m[2m 0.47 kB[22m[1m[22m[2m 鈹?gzip: 0.34 kB[22m
|
||||
[2mdist/[22m[36massets/DeleteOutlined-DFutYCzo.js [39m[1m[2m 0.50 kB[22m[1m[22m[2m 鈹?gzip: 0.34 kB[22m
|
||||
[2mdist/[22m[36massets/shield-check-sfL9HgxB.js [39m[1m[2m 0.50 kB[22m[1m[22m[2m 鈹?gzip: 0.36 kB[22m
|
||||
[2mdist/[22m[36massets/CalendarOutlined-DKq2sctu.js [39m[1m[2m 0.51 kB[22m[1m[22m[2m 鈹?gzip: 0.31 kB[22m
|
||||
[2mdist/[22m[36massets/ClockCircleOutlined-CELcQ7Uv.js [39m[1m[2m 0.53 kB[22m[1m[22m[2m 鈹?gzip: 0.34 kB[22m
|
||||
[2mdist/[22m[36massets/EyeOutlined-Bmd706kk.js [39m[1m[2m 0.63 kB[22m[1m[22m[2m 鈹?gzip: 0.39 kB[22m
|
||||
[2mdist/[22m[36massets/PauseOutlined-BLt2csZU.js [39m[1m[2m 0.65 kB[22m[1m[22m[2m 鈹?gzip: 0.47 kB[22m
|
||||
[2mdist/[22m[36massets/play-1ljA3jPR.js [39m[1m[2m 0.66 kB[22m[1m[22m[2m 鈹?gzip: 0.36 kB[22m
|
||||
[2mdist/[22m[36massets/MoreOutlined-B1PG76QS.js [39m[1m[2m 0.67 kB[22m[1m[22m[2m 鈹?gzip: 0.43 kB[22m
|
||||
[2mdist/[22m[36massets/SystemSetting-tRZ3rI5Y.js [39m[1m[2m 0.67 kB[22m[1m[22m[2m 鈹?gzip: 0.42 kB[22m
|
||||
[2mdist/[22m[36massets/index-QGIuQAVc.js [39m[1m[2m 0.75 kB[22m[1m[22m[2m 鈹?gzip: 0.30 kB[22m
|
||||
[2mdist/[22m[36massets/ProtectedRoute-DBQ_RFvv.js [39m[1m[2m 0.77 kB[22m[1m[22m[2m 鈹?gzip: 0.47 kB[22m
|
||||
[2mdist/[22m[36massets/ThunderboltOutlined-CM9FK6lI.js [39m[1m[2m 0.81 kB[22m[1m[22m[2m 鈹?gzip: 0.57 kB[22m
|
||||
[2mdist/[22m[36massets/RiseOutlined-CG9xbajJ.js [39m[1m[2m 0.83 kB[22m[1m[22m[2m 鈹?gzip: 0.57 kB[22m
|
||||
[2mdist/[22m[36massets/cpu-COM_qCei.js [39m[1m[2m 0.83 kB[22m[1m[22m[2m 鈹?gzip: 0.41 kB[22m
|
||||
[2mdist/[22m[36massets/trending-up-C335pZ95.js [39m[1m[2m 0.83 kB[22m[1m[22m[2m 鈹?gzip: 0.39 kB[22m
|
||||
[2mdist/[22m[36massets/WarningOutlined-Btx5sX6A.js [39m[1m[2m 0.84 kB[22m[1m[22m[2m 鈹?gzip: 0.59 kB[22m
|
||||
[2mdist/[22m[36massets/DatabaseOutlined-C5nPN0EL.js [39m[1m[2m 0.84 kB[22m[1m[22m[2m 鈹?gzip: 0.53 kB[22m
|
||||
[2mdist/[22m[36massets/InfoCircleOutlined-BRsgui7Y.js [39m[1m[2m 0.88 kB[22m[1m[22m[2m 鈹?gzip: 0.56 kB[22m
|
||||
[2mdist/[22m[36massets/MailOutlined-CrBBI-jk.js [39m[1m[2m 0.88 kB[22m[1m[22m[2m 鈹?gzip: 0.59 kB[22m
|
||||
[2mdist/[22m[36massets/LockOutlined-CpZjW16Y.js [39m[1m[2m 0.88 kB[22m[1m[22m[2m 鈹?gzip: 0.60 kB[22m
|
||||
[2mdist/[22m[36massets/ExclamationCircleOutlined-BTwY9HjG.js [39m[1m[2m 0.88 kB[22m[1m[22m[2m 鈹?gzip: 0.57 kB[22m
|
||||
[2mdist/[22m[36massets/index-BZNW0Ac-.js [39m[1m[2m 0.89 kB[22m[1m[22m[2m 鈹?gzip: 0.28 kB[22m
|
||||
[2mdist/[22m[36massets/VideoCameraOutlined-BpSekwuQ.js [39m[1m[2m 0.89 kB[22m[1m[22m[2m 鈹?gzip: 0.62 kB[22m
|
||||
[2mdist/[22m[36massets/PlayCircleOutlined-C8_VtFd1.js [39m[1m[2m 0.90 kB[22m[1m[22m[2m 鈹?gzip: 0.58 kB[22m
|
||||
[2mdist/[22m[36massets/LeftOutlined-mtwdKv5a.js [39m[1m[2m 0.90 kB[22m[1m[22m[2m 鈹?gzip: 0.49 kB[22m
|
||||
[2mdist/[22m[36massets/index-B5BnD-LK.js [39m[1m[2m 0.93 kB[22m[1m[22m[2m 鈹?gzip: 0.56 kB[22m
|
||||
[2mdist/[22m[36massets/CheckCircleOutlined-CiWPVIDh.js [39m[1m[2m 0.94 kB[22m[1m[22m[2m 鈹?gzip: 0.61 kB[22m
|
||||
[2mdist/[22m[36massets/droplets-J52jZ87L.js [39m[1m[2m 0.94 kB[22m[1m[22m[2m 鈹?gzip: 0.50 kB[22m
|
||||
[2mdist/[22m[36massets/FileTextOutlined-8_Os79cm.js [39m[1m[2m 0.96 kB[22m[1m[22m[2m 鈹?gzip: 0.62 kB[22m
|
||||
[2mdist/[22m[36massets/RobotOutlined-D9B_FJ7c.js [39m[1m[2m 0.97 kB[22m[1m[22m[2m 鈹?gzip: 0.63 kB[22m
|
||||
[2mdist/[22m[36massets/BellOutlined-DEw0MDNM.js [39m[1m[2m 0.97 kB[22m[1m[22m[2m 鈹?gzip: 0.65 kB[22m
|
||||
[2mdist/[22m[36massets/FormOutlined-B5idtZPb.js [39m[1m[2m 1.00 kB[22m[1m[22m[2m 鈹?gzip: 0.66 kB[22m
|
||||
[2mdist/[22m[36massets/BarChartOutlined-D19D9dh2.js [39m[1m[2m 1.01 kB[22m[1m[22m[2m 鈹?gzip: 0.53 kB[22m
|
||||
[2mdist/[22m[36massets/BgColorsOutlined-D4zNRQ_S.js [39m[1m[2m 1.01 kB[22m[1m[22m[2m 鈹?gzip: 0.66 kB[22m
|
||||
[2mdist/[22m[36massets/AppstoreOutlined-vwQa2ti0.js [39m[1m[2m 1.06 kB[22m[1m[22m[2m 鈹?gzip: 0.52 kB[22m
|
||||
[2mdist/[22m[36massets/ExperimentOutlined-C4X5fx5X.js [39m[1m[2m 1.06 kB[22m[1m[22m[2m 鈹?gzip: 0.72 kB[22m
|
||||
[2mdist/[22m[36massets/BranchesOutlined-BsXN7E28.js [39m[1m[2m 1.07 kB[22m[1m[22m[2m 鈹?gzip: 0.65 kB[22m
|
||||
[2mdist/[22m[36massets/index-B7QMvlEx.js [39m[1m[2m 1.10 kB[22m[1m[22m[2m 鈹?gzip: 0.59 kB[22m
|
||||
[2mdist/[22m[36massets/ExpandOutlined-Wqi8y5jM.js [39m[1m[2m 1.12 kB[22m[1m[22m[2m 鈹?gzip: 0.59 kB[22m
|
||||
[2mdist/[22m[36massets/CloudOutlined-bffXYW10.js [39m[1m[2m 1.13 kB[22m[1m[22m[2m 鈹?gzip: 0.74 kB[22m
|
||||
[2mdist/[22m[36massets/UserOutlined-C7S2oBX2.js [39m[1m[2m 1.22 kB[22m[1m[22m[2m 鈹?gzip: 0.76 kB[22m
|
||||
[2mdist/[22m[36massets/ZoomOutOutlined-CdPjzMfa.js [39m[1m[2m 1.22 kB[22m[1m[22m[2m 鈹?gzip: 0.42 kB[22m
|
||||
[2mdist/[22m[36massets/ReloadOutlined-Xhzi5rUd.js [39m[1m[2m 1.23 kB[22m[1m[22m[2m 鈹?gzip: 0.77 kB[22m
|
||||
[2mdist/[22m[36massets/AlertOutlined-BSdXkZNw.js [39m[1m[2m 1.24 kB[22m[1m[22m[2m 鈹?gzip: 0.73 kB[22m
|
||||
[2mdist/[22m[36massets/AimOutlined-BQ_60xaP.js [39m[1m[2m 1.25 kB[22m[1m[22m[2m 鈹?gzip: 0.71 kB[22m
|
||||
[2mdist/[22m[36massets/alarmApi-D98kS4sF.js [39m[1m[2m 1.25 kB[22m[1m[22m[2m 鈹?gzip: 0.35 kB[22m
|
||||
[2mdist/[22m[36massets/SyncOutlined-D5St2s8G.js [39m[1m[2m 1.27 kB[22m[1m[22m[2m 鈹?gzip: 0.81 kB[22m
|
||||
[2mdist/[22m[36massets/MoneyCollectOutlined-BEnuS9NY.js [39m[1m[2m 1.30 kB[22m[1m[22m[2m 鈹?gzip: 0.79 kB[22m
|
||||
[2mdist/[22m[36massets/FullscreenOutlined-Bd0pqIlF.js [39m[1m[2m 1.34 kB[22m[1m[22m[2m 鈹?gzip: 0.77 kB[22m
|
||||
[2mdist/[22m[36massets/SafetyCertificateOutlined-DnZNNQOF.js [39m[1m[2m 1.41 kB[22m[1m[22m[2m 鈹?gzip: 0.76 kB[22m
|
||||
[2mdist/[22m[36massets/SwapOutlined-Dmzzor8a.js [39m[1m[2m 1.42 kB[22m[1m[22m[2m 鈹?gzip: 0.65 kB[22m
|
||||
[2mdist/[22m[36massets/ZoomOutOutlined-DAOfVl6t.js [39m[1m[2m 1.47 kB[22m[1m[22m[2m 鈹?gzip: 0.67 kB[22m
|
||||
[2mdist/[22m[36massets/satellite-D5SYgbBW.js [39m[1m[2m 1.47 kB[22m[1m[22m[2m 鈹?gzip: 0.54 kB[22m
|
||||
[2mdist/[22m[36massets/RocketOutlined-DvS5QcPf.js [39m[1m[2m 1.49 kB[22m[1m[22m[2m 鈹?gzip: 0.93 kB[22m
|
||||
[2mdist/[22m[36massets/EnvironmentOutlined-DmDILpSG.js [39m[1m[2m 1.49 kB[22m[1m[22m[2m 鈹?gzip: 0.91 kB[22m
|
||||
[2mdist/[22m[36massets/useBubbleLock-BcDDtpST.js [39m[1m[2m 1.54 kB[22m[1m[22m[2m 鈹?gzip: 0.75 kB[22m
|
||||
[2mdist/[22m[36massets/index-CALtcbsS.js [39m[1m[2m 1.61 kB[22m[1m[22m[2m 鈹?gzip: 0.85 kB[22m
|
||||
[2mdist/[22m[36massets/ApiOutlined-CzQyCItv.js [39m[1m[2m 1.61 kB[22m[1m[22m[2m 鈹?gzip: 0.87 kB[22m
|
||||
[2mdist/[22m[36massets/SunOutlined-4fVeMoLM.js [39m[1m[2m 1.75 kB[22m[1m[22m[2m 鈹?gzip: 0.90 kB[22m
|
||||
[2mdist/[22m[36massets/DashboardOutlined-By3UzQBB.js [39m[1m[2m 1.83 kB[22m[1m[22m[2m 鈹?gzip: 0.93 kB[22m
|
||||
[2mdist/[22m[36massets/createLucideIcon-I8N4V_Qv.js [39m[1m[2m 1.86 kB[22m[1m[22m[2m 鈹?gzip: 0.80 kB[22m
|
||||
[2mdist/[22m[36massets/CarOutlined-Dl55nQ-v.js [39m[1m[2m 2.00 kB[22m[1m[22m[2m 鈹?gzip: 0.98 kB[22m
|
||||
[2mdist/[22m[36massets/index-Bki12rLk.js [39m[1m[2m 2.04 kB[22m[1m[22m[2m 鈹?gzip: 1.00 kB[22m
|
||||
[2mdist/[22m[36massets/systemSetting-BrHh5w13.js [39m[1m[2m 2.11 kB[22m[1m[22m[2m 鈹?gzip: 0.45 kB[22m
|
||||
[2mdist/[22m[36massets/PlayCircleFilled-BBXiNPP8.js [39m[1m[2m 2.14 kB[22m[1m[22m[2m 鈹?gzip: 1.04 kB[22m
|
||||
[2mdist/[22m[36massets/LinkOutlined-DvFl02q6.js [39m[1m[2m 2.19 kB[22m[1m[22m[2m 鈹?gzip: 0.82 kB[22m
|
||||
[2mdist/[22m[36massets/index-CFB0_Wn2.js [39m[1m[2m 2.19 kB[22m[1m[22m[2m 鈹?gzip: 1.14 kB[22m
|
||||
[2mdist/[22m[36massets/SettingOutlined-DeJS8h5d.js [39m[1m[2m 2.35 kB[22m[1m[22m[2m 鈹?gzip: 1.21 kB[22m
|
||||
[2mdist/[22m[36massets/VideoPlayer-CBopx0N2.js [39m[1m[2m 2.39 kB[22m[1m[22m[2m 鈹?gzip: 1.33 kB[22m
|
||||
[2mdist/[22m[36massets/PictureTwoTone-BaO8R2Hf.js [39m[1m[2m 2.42 kB[22m[1m[22m[2m 鈹?gzip: 1.04 kB[22m
|
||||
[2mdist/[22m[36massets/index-Dzwhnzv1.js [39m[1m[2m 2.42 kB[22m[1m[22m[2m 鈹?gzip: 1.16 kB[22m
|
||||
[2mdist/[22m[36massets/SaveOutlined-CPLKsg-u.js [39m[1m[2m 3.28 kB[22m[1m[22m[2m 鈹?gzip: 1.40 kB[22m
|
||||
[2mdist/[22m[36massets/device-psUGD0yB.js [39m[1m[2m 3.38 kB[22m[1m[22m[2m 鈹?gzip: 0.76 kB[22m
|
||||
[2mdist/[22m[36massets/index-C8BzGSw1.js [39m[1m[2m 3.61 kB[22m[1m[22m[2m 鈹?gzip: 1.27 kB[22m
|
||||
[2mdist/[22m[36massets/row-CWgAqdVq.js [39m[1m[2m 3.74 kB[22m[1m[22m[2m 鈹?gzip: 1.64 kB[22m
|
||||
[2mdist/[22m[36massets/MonitorOutlined-BblwvURO.js [39m[1m[2m 3.85 kB[22m[1m[22m[2m 鈹?gzip: 1.28 kB[22m
|
||||
[2mdist/[22m[36massets/OnlineUser-DP0qCIhg.js [39m[1m[2m 3.87 kB[22m[1m[22m[2m 鈹?gzip: 1.82 kB[22m
|
||||
[2mdist/[22m[36massets/index-BU7NlCGd.js [39m[1m[2m 4.14 kB[22m[1m[22m[2m 鈹?gzip: 1.74 kB[22m
|
||||
[2mdist/[22m[36massets/MenuUnfoldOutlined-D7wIQeV0.js [39m[1m[2m 4.16 kB[22m[1m[22m[2m 鈹?gzip: 1.30 kB[22m
|
||||
[2mdist/[22m[36massets/ScanOutlined-BErT-8VV.js [39m[1m[2m 4.19 kB[22m[1m[22m[2m 鈹?gzip: 1.38 kB[22m
|
||||
[2mdist/[22m[36massets/index-D-WWTY9M.js [39m[1m[2m 4.21 kB[22m[1m[22m[2m 鈹?gzip: 1.58 kB[22m
|
||||
[2mdist/[22m[36massets/LoadingOutlined-CSGMXG1Q.js [39m[1m[2m 4.25 kB[22m[1m[22m[2m 鈹?gzip: 1.83 kB[22m
|
||||
[2mdist/[22m[36massets/index-CwWg_1c5.js [39m[1m[2m 4.38 kB[22m[1m[22m[2m 鈹?gzip: 1.76 kB[22m
|
||||
[2mdist/[22m[36massets/Organization-DaUilJNB.js [39m[1m[2m 4.43 kB[22m[1m[22m[2m 鈹?gzip: 1.95 kB[22m
|
||||
[2mdist/[22m[36massets/index-DLB_37uE.js [39m[1m[2m 4.58 kB[22m[1m[22m[2m 鈹?gzip: 1.91 kB[22m
|
||||
[2mdist/[22m[36massets/VideoCameraAddOutlined-DfZ_JO9-.js [39m[1m[2m 4.79 kB[22m[1m[22m[2m 鈹?gzip: 1.68 kB[22m
|
||||
[2mdist/[22m[36massets/WomanOutlined-DfQHI4i_.js [39m[1m[2m 4.82 kB[22m[1m[22m[2m 鈹?gzip: 1.76 kB[22m
|
||||
[2mdist/[22m[36massets/LineChartOutlined-DoICXm12.js [39m[1m[2m 5.07 kB[22m[1m[22m[2m 鈹?gzip: 1.82 kB[22m
|
||||
[2mdist/[22m[36massets/Roles-BcoDNXzy.js [39m[1m[2m 5.16 kB[22m[1m[22m[2m 鈹?gzip: 2.28 kB[22m
|
||||
[2mdist/[22m[36massets/index-DlknX2AJ.js [39m[1m[2m 5.44 kB[22m[1m[22m[2m 鈹?gzip: 2.24 kB[22m
|
||||
[2mdist/[22m[36massets/Users-Cc87fC1a.js [39m[1m[2m 5.46 kB[22m[1m[22m[2m 鈹?gzip: 2.17 kB[22m
|
||||
[2mdist/[22m[36massets/index-DBrV9klW.js [39m[1m[2m 5.57 kB[22m[1m[22m[2m 鈹?gzip: 2.20 kB[22m
|
||||
[2mdist/[22m[36massets/index-BIHkEVGV.js [39m[1m[2m 5.83 kB[22m[1m[22m[2m 鈹?gzip: 2.63 kB[22m
|
||||
[2mdist/[22m[36massets/Sider-S9XGzyBR.js [39m[1m[2m 6.64 kB[22m[1m[22m[2m 鈹?gzip: 2.85 kB[22m
|
||||
[2mdist/[22m[36massets/Input-C5V4O2--.js [39m[1m[2m 6.73 kB[22m[1m[22m[2m 鈹?gzip: 2.71 kB[22m
|
||||
[2mdist/[22m[36massets/LogManagement-DMoKnN3a.js [39m[1m[2m 6.80 kB[22m[1m[22m[2m 鈹?gzip: 3.23 kB[22m
|
||||
[2mdist/[22m[36massets/dayjs.min-BQmzeOJK.js [39m[1m[2m 7.15 kB[22m[1m[22m[2m 鈹?gzip: 3.11 kB[22m
|
||||
[2mdist/[22m[36massets/Timeline-DTl788NK.js [39m[1m[2m 7.47 kB[22m[1m[22m[2m 鈹?gzip: 2.32 kB[22m
|
||||
[2mdist/[22m[36massets/Profile-D6l6crbd.js [39m[1m[2m 7.59 kB[22m[1m[22m[2m 鈹?gzip: 2.67 kB[22m
|
||||
[2mdist/[22m[36massets/index-Bxnk55C6.js [39m[1m[2m 7.98 kB[22m[1m[22m[2m 鈹?gzip: 2.71 kB[22m
|
||||
[2mdist/[22m[36massets/GlobalOutlined-BBf_4gfp.js [39m[1m[2m 8.13 kB[22m[1m[22m[2m 鈹?gzip: 2.73 kB[22m
|
||||
[2mdist/[22m[36massets/StationManage-DqEWUwhR.js [39m[1m[2m 9.55 kB[22m[1m[22m[2m 鈹?gzip: 3.29 kB[22m
|
||||
[2mdist/[22m[36massets/CaretUpOutlined-CeF_o8iU.js [39m[1m[2m 9.72 kB[22m[1m[22m[2m 鈹?gzip: 3.73 kB[22m
|
||||
[2mdist/[22m[36massets/index-7OmqMvBS.js [39m[1m[2m 9.85 kB[22m[1m[22m[2m 鈹?gzip: 4.12 kB[22m
|
||||
[2mdist/[22m[36massets/index-CoZjM-Ur.js [39m[1m[2m 10.86 kB[22m[1m[22m[2m 鈹?gzip: 3.67 kB[22m
|
||||
[2mdist/[22m[36massets/index-BcHyRtCu.js [39m[1m[2m 13.09 kB[22m[1m[22m[2m 鈹?gzip: 4.32 kB[22m
|
||||
[2mdist/[22m[36massets/RealTimeMonitor-D3QaTkAC.js [39m[1m[2m 13.35 kB[22m[1m[22m[2m 鈹?gzip: 3.86 kB[22m
|
||||
[2mdist/[22m[36massets/Downloads-DcgcCi6l.js [39m[1m[2m 14.39 kB[22m[1m[22m[2m 鈹?gzip: 5.34 kB[22m
|
||||
[2mdist/[22m[36massets/Layout-Bd_POYYm.js [39m[1m[2m 14.43 kB[22m[1m[22m[2m 鈹?gzip: 5.93 kB[22m
|
||||
[2mdist/[22m[36massets/UserPage-32JpRX2A.js [39m[1m[2m 14.58 kB[22m[1m[22m[2m 鈹?gzip: 5.10 kB[22m
|
||||
[2mdist/[22m[36massets/mowerAllView-I1S0UCff.js [39m[1m[2m 15.31 kB[22m[1m[22m[2m 鈹?gzip: 5.14 kB[22m
|
||||
[2mdist/[22m[36massets/progress-BRDZKBDI.js [39m[1m[2m 16.32 kB[22m[1m[22m[2m 鈹?gzip: 5.97 kB[22m
|
||||
[2mdist/[22m[36massets/Video-DCzOHWv-.js [39m[1m[2m 17.54 kB[22m[1m[22m[2m 鈹?gzip: 6.37 kB[22m
|
||||
[2mdist/[22m[36massets/VideoMonitorPage-BhzNbDao.js [39m[1m[2m 19.23 kB[22m[1m[22m[2m 鈹?gzip: 5.70 kB[22m
|
||||
[2mdist/[22m[36massets/Home-Bn7xrUeS.js [39m[1m[2m 19.49 kB[22m[1m[22m[2m 鈹?gzip: 5.82 kB[22m
|
||||
[2mdist/[22m[36massets/ReportCenter-BBu6qFzX.js [39m[1m[2m 19.98 kB[22m[1m[22m[2m 鈹?gzip: 5.52 kB[22m
|
||||
[2mdist/[22m[36massets/AIAnalysis-6Etwoj3Z.js [39m[1m[2m 20.65 kB[22m[1m[22m[2m 鈹?gzip: 5.97 kB[22m
|
||||
[2mdist/[22m[36massets/SystemMaintain-Cd07s562.js [39m[1m[2m 21.22 kB[22m[1m[22m[2m 鈹?gzip: 6.42 kB[22m
|
||||
[2mdist/[22m[36massets/Agri-CAyj5gpp.js [39m[1m[2m 23.35 kB[22m[1m[22m[2m 鈹?gzip: 6.70 kB[22m
|
||||
[2mdist/[22m[36massets/CleanOptimization-m28ON6IA.js [39m[1m[2m 23.72 kB[22m[1m[22m[2m 鈹?gzip: 6.78 kB[22m
|
||||
[2mdist/[22m[36massets/BasicSettings-mBDMHnai.js [39m[1m[2m 24.03 kB[22m[1m[22m[2m 鈹?gzip: 6.94 kB[22m
|
||||
[2mdist/[22m[36massets/Pagination-E56Qk7uV.js [39m[1m[2m 24.07 kB[22m[1m[22m[2m 鈹?gzip: 7.27 kB[22m
|
||||
[2mdist/[22m[36massets/index-D2zgn0VX.js [39m[1m[2m 24.29 kB[22m[1m[22m[2m 鈹?gzip: 6.84 kB[22m
|
||||
[2mdist/[22m[36massets/index-CIQZPZYn.js [39m[1m[2m 24.61 kB[22m[1m[22m[2m 鈹?gzip: 8.41 kB[22m
|
||||
[2mdist/[22m[36massets/DeviceAccessPage-DkChs1SW.js [39m[1m[2m 27.31 kB[22m[1m[22m[2m 鈹?gzip: 7.77 kB[22m
|
||||
[2mdist/[22m[36massets/DeviceStatusPage-DeTc4zz3.js [39m[1m[2m 27.77 kB[22m[1m[22m[2m 鈹?gzip: 8.81 kB[22m
|
||||
[2mdist/[22m[36massets/AntdIcon-0lBFMey5.js [39m[1m[2m 28.67 kB[22m[1m[22m[2m 鈹?gzip: 10.61 kB[22m
|
||||
[2mdist/[22m[36massets/index-3QLgGeSa.js [39m[1m[2m 30.34 kB[22m[1m[22m[2m 鈹?gzip: 10.81 kB[22m
|
||||
[2mdist/[22m[36massets/index-4Tny0eKH.js [39m[1m[2m 31.74 kB[22m[1m[22m[2m 鈹?gzip: 11.04 kB[22m
|
||||
[2mdist/[22m[36massets/DeviceOverviewPage-OFF9ez_H.js [39m[1m[2m 34.95 kB[22m[1m[22m[2m 鈹?gzip: 9.58 kB[22m
|
||||
[2mdist/[22m[36massets/Map-B9M4yO_P.js [39m[1m[2m 35.52 kB[22m[1m[22m[2m 鈹?gzip: 16.50 kB[22m
|
||||
[2mdist/[22m[36massets/DeviceParamModal-aOMZwSFn.js [39m[1m[2m 36.02 kB[22m[1m[22m[2m 鈹?gzip: 12.66 kB[22m
|
||||
[2mdist/[22m[36massets/Alerts-DSpopPLD.js [39m[1m[2m 43.22 kB[22m[1m[22m[2m 鈹?gzip: 13.57 kB[22m
|
||||
[2mdist/[22m[36massets/WayLinePage-Cu3Rj_Of.js [39m[1m[2m 47.81 kB[22m[1m[22m[2m 鈹?gzip: 12.76 kB[22m
|
||||
[2mdist/[22m[36massets/RobotTaskPage-W5Q2YiXq.js [39m[1m[2m 50.58 kB[22m[1m[22m[2m 鈹?gzip: 15.72 kB[22m
|
||||
[2mdist/[22m[36massets/index-DtVs1TSu.js [39m[1m[2m 53.48 kB[22m[1m[22m[2m 鈹?gzip: 17.46 kB[22m
|
||||
[2mdist/[22m[36massets/index-DOfHuV9M.js [39m[1m[2m 55.58 kB[22m[1m[22m[2m 鈹?gzip: 16.79 kB[22m
|
||||
[2mdist/[22m[36massets/index-DdSZJIQg.js [39m[1m[2m 85.35 kB[22m[1m[22m[2m 鈹?gzip: 28.38 kB[22m
|
||||
[2mdist/[22m[36massets/index-8P5uuj0T.js [39m[1m[2m 104.37 kB[22m[1m[22m[2m 鈹?gzip: 33.62 kB[22m
|
||||
[2mdist/[22m[36massets/Table-DEFhGiKk.js [39m[1m[2m 105.22 kB[22m[1m[22m[2m 鈹?gzip: 35.08 kB[22m
|
||||
[2mdist/[22m[36massets/index-C4N9F59W.js [39m[1m[2m 119.58 kB[22m[1m[22m[2m 鈹?gzip: 40.54 kB[22m
|
||||
[2mdist/[22m[36massets/Login-B_ks4Hrx.js [39m[1m[2m 127.74 kB[22m[1m[22m[2m 鈹?gzip: 42.25 kB[22m
|
||||
[2mdist/[22m[36massets/VideoManagement-DTii0Wl_.js [39m[1m[2m 162.67 kB[22m[1m[22m[2m 鈹?gzip: 41.60 kB[22m
|
||||
[2mdist/[22m[36massets/useMqtt-CalKBDup.js [39m[1m[2m 372.77 kB[22m[1m[22m[2m 鈹?gzip: 112.37 kB[22m
|
||||
[2mdist/[22m[36massets/recharts-oahKx968.js [39m[1m[2m 376.93 kB[22m[1m[22m[2m 鈹?gzip: 108.14 kB[22m
|
||||
[2mdist/[22m[36massets/index-_6GufRdM.js [39m[1m[2m 651.35 kB[22m[1m[22m[2m 鈹?gzip: 215.64 kB[22m
|
||||
[2mdist/[22m[36massets/DeviceManagement-CdpxXm_d.js [39m[1m[2m 722.93 kB[22m[1m[22m[2m 鈹?gzip: 158.92 kB[22m
|
||||
[2mdist/[22m[36massets/MenuList-tLwkyiAS.js [39m[1m[2m 857.15 kB[22m[1m[22m[2m 鈹?gzip: 165.02 kB[22m
|
||||
[2mdist/[22m[36massets/WorkOrder-DfwdBKQc.js [39m[1m[33m 1,507.81 kB[39m[22m[2m 鈹?gzip: 445.47 kB[22m
|
||||
[2mdist/[22m[36massets/DroneVideoPlayer-BnJcr8Dl.js [39m[1m[33m 2,529.14 kB[39m[22m[2m 鈹?gzip: 708.00 kB[22m
|
||||
[33m
|
||||
(!) Some chunks are larger than 1000 kB after minification. Consider:
|
||||
- Using dynamic import() to code-split the application
|
||||
- Use build.rollupOptions.output.manualChunks to improve chunking: https://rollupjs.org/configuration-options/#output-manualchunks
|
||||
- Adjust chunk size limit for this warning via build.chunkSizeWarningLimit.[39m
|
||||
[36m[vite-plugin-static-copy][39m [32mCopied 1 items.[39m
|
||||
[32m鉁?built in 1m 39s[39m
|
||||
|
||||
23
package-lock.json
generated
23
package-lock.json
generated
@@ -24,6 +24,7 @@
|
||||
"dotenv": "^17.2.3",
|
||||
"echarts": "^6.0.0",
|
||||
"express": "^4.21.2",
|
||||
"flv.js": "^1.6.2",
|
||||
"js-cookie": "^3.0.5",
|
||||
"lodash": "^4.18.1",
|
||||
"lucide-react": "^0.546.0",
|
||||
@@ -4083,6 +4084,12 @@
|
||||
"benchmarks"
|
||||
]
|
||||
},
|
||||
"node_modules/es6-promise": {
|
||||
"version": "4.2.8",
|
||||
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
|
||||
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz",
|
||||
@@ -4372,6 +4379,16 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/flv.js": {
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmjs.org/flv.js/-/flv.js-1.6.2.tgz",
|
||||
"integrity": "sha512-xre4gUbX1MPtgQRKj2pxJENp/RnaHaxYvy3YToVVCrSmAWUu85b9mug6pTXF6zakUjNP2lFWZ1rkSX7gxhB/2A==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"es6-promise": "^4.2.8",
|
||||
"webworkify-webpack": "^2.1.5"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.16.0",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz",
|
||||
@@ -8165,6 +8182,12 @@
|
||||
"npm": ">=3.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/webworkify-webpack": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/webworkify-webpack/-/webworkify-webpack-2.1.5.tgz",
|
||||
"integrity": "sha512-2akF8FIyUvbiBBdD+RoHpoTbHMQF2HwjcxfDvgztAX5YwbZNyrtfUMgvfgFVsgDhDPVTlkbb5vyasqDHfIDPQw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/which-module": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"dotenv": "^17.2.3",
|
||||
"echarts": "^6.0.0",
|
||||
"express": "^4.21.2",
|
||||
"flv.js": "^1.6.2",
|
||||
"js-cookie": "^3.0.5",
|
||||
"lodash": "^4.18.1",
|
||||
"lucide-react": "^0.546.0",
|
||||
|
||||
@@ -1,104 +1,253 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
Card as AntdCard, Tag, Button, Space, Typography, Row, Col, message
|
||||
Card, Tag, Button, Space, Typography, Row, Col, Select, Table, Modal, message, Empty, Spin
|
||||
} from 'antd';
|
||||
import {
|
||||
VideoCameraOutlined, PlayCircleOutlined, HistoryOutlined, SettingOutlined,
|
||||
CameraOutlined, EyeOutlined
|
||||
VideoCameraOutlined, DownloadOutlined, PlayCircleOutlined,
|
||||
FolderOutlined, ReloadOutlined, EyeOutlined, DatabaseOutlined
|
||||
} from '@ant-design/icons';
|
||||
import axios from 'axios';
|
||||
import flvjs from 'flv.js';
|
||||
|
||||
const { Title, Text } = Typography;
|
||||
|
||||
// ======================
|
||||
// 视频管理(仅 admin 可见)
|
||||
// 说明:当前为前端展示页,数据使用本地 mock 视频通道。
|
||||
// 接入真实视频时,「实时预览」可跳转至监控页 /monitor(VideoMonitorPage),
|
||||
// 或对接 WebRTC / 流媒体服务获取实时画面与回放地址。
|
||||
// 真实数据对接 nodevideo(端口 9528,SRS 录制文件服务):
|
||||
// POST /list body: { deviceId?, year?, month?, day? }
|
||||
// 不传参 → 所有通道(deviceId);传 deviceId → 年份目录;逐级下钻 → 当天视频文件
|
||||
// 返回 { code, path, directories:[], files:[{ fileName, size, sizeFormatted }] }
|
||||
// GET /video/download?deviceId=&year=&month=&day=&fileName=
|
||||
// 流式返回录制视频(SRS 多为 .flv,用 flv.js 播放)
|
||||
// 说明:本机开发直连 http://localhost:9528;若部署到其它主机,请改为反向代理/相对路径。
|
||||
// ======================
|
||||
|
||||
const MOCK_CHANNELS = [
|
||||
{ id: 'CAM-01', name: '1区组件巡检摄像头', device: '巡检机器人-01', status: 'online', location: 'A排 1-12 组件', lastUpdate: '2026-08-10 12:58' },
|
||||
{ id: 'CAM-02', name: '升压站全景摄像头', device: '固定球机', status: 'online', location: '升压站', lastUpdate: '2026-08-10 12:59' },
|
||||
{ id: 'CAM-03', name: '无人机航拍通道', device: '无人机-01', status: 'offline', location: '全场', lastUpdate: '2026-08-09 18:20' },
|
||||
{ id: 'CAM-04', name: '汇流箱热成像', device: '巡检机器人-02', status: 'online', location: 'B排汇流箱', lastUpdate: '2026-08-10 13:01' },
|
||||
{ id: 'CAM-05', name: '逆变器舱监控', device: '固定枪机', status: 'online', location: '逆变器室', lastUpdate: '2026-08-10 13:00' },
|
||||
{ id: 'CAM-06', name: '组件热斑巡检通道', device: '无人机-02', status: 'offline', location: 'C排组件', lastUpdate: '2026-08-09 17:45' },
|
||||
];
|
||||
const NODEVIDEO_BASE = 'http://1.95.137.212:30003';
|
||||
|
||||
const fetchList = async (body: Record<string, string> = {}) => {
|
||||
const res = await axios.post(`${NODEVIDEO_BASE}/list`, body);
|
||||
return res.data as { code: number; path: string; directories: string[]; files: { fileName: string; size: number; sizeFormatted: string }[]; error?: string };
|
||||
};
|
||||
|
||||
const buildDownloadUrl = (p: { deviceId: string; year: string; month: string; day: string; fileName: string }) =>
|
||||
`${NODEVIDEO_BASE}/video/download?deviceId=${encodeURIComponent(p.deviceId)}&year=${p.year}&month=${p.month}&day=${p.day}&fileName=${encodeURIComponent(p.fileName)}`;
|
||||
|
||||
const isFlv = (name: string) => name.toLowerCase().endsWith('.flv');
|
||||
|
||||
const VideoManagement = () => {
|
||||
const navigate = useNavigate();
|
||||
const [channels] = useState(MOCK_CHANNELS);
|
||||
const [channels, setChannels] = useState<string[]>([]);
|
||||
const [channel, setChannel] = useState<string | undefined>();
|
||||
const [years, setYears] = useState<string[]>([]);
|
||||
const [year, setYear] = useState<string | undefined>();
|
||||
const [months, setMonths] = useState<string[]>([]);
|
||||
const [month, setMonth] = useState<string | undefined>();
|
||||
const [days, setDays] = useState<string[]>([]);
|
||||
const [day, setDay] = useState<string | undefined>();
|
||||
const [files, setFiles] = useState<{ fileName: string; size: number; sizeFormatted: string }[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [preview, setPreview] = useState<{ url: string; fileName: string } | null>(null);
|
||||
const videoRef = useRef<HTMLVideoElement>(null);
|
||||
const flvPlayerRef = useRef<any>(null);
|
||||
|
||||
const onlineCount = channels.filter((c) => c.status === 'online').length;
|
||||
|
||||
const handlePreview = (ch: any) => {
|
||||
if (ch.status !== 'online') {
|
||||
message.warning(`${ch.name} 当前离线,无法预览`);
|
||||
return;
|
||||
// 1. 加载通道列表(deviceId)
|
||||
const loadChannels = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const data = await fetchList({});
|
||||
if (data.code === 200) {
|
||||
setChannels(data.directories || []);
|
||||
} else {
|
||||
setChannels([]);
|
||||
message.warning(data.error || '读取通道失败');
|
||||
}
|
||||
} catch (e) {
|
||||
setChannels([]);
|
||||
message.error('无法连接 nodevideo 服务(9528)');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
// 跳转至实时监控页,可携带通道信息
|
||||
navigate('/monitor', { state: { channel: ch.id, name: ch.name } });
|
||||
};
|
||||
|
||||
useEffect(() => { loadChannels(); }, []);
|
||||
|
||||
// 2. 选通道 → 加载年份
|
||||
const onChannelChange = async (val: string) => {
|
||||
setChannel(val);
|
||||
setYear(undefined); setYears([]);
|
||||
setMonth(undefined); setMonths([]);
|
||||
setDay(undefined); setDays([]);
|
||||
setFiles([]);
|
||||
if (!val) return;
|
||||
setLoading(true);
|
||||
try {
|
||||
const data = await fetchList({ deviceId: val });
|
||||
setYears(data.code === 200 ? (data.directories || []) : []);
|
||||
} catch { setYears([]); }
|
||||
finally { setLoading(false); }
|
||||
};
|
||||
|
||||
// 3. 选年份 → 加载月份
|
||||
const onYearChange = async (val: string) => {
|
||||
setYear(val);
|
||||
setMonth(undefined); setMonths([]);
|
||||
setDay(undefined); setDays([]);
|
||||
setFiles([]);
|
||||
if (!val || !channel) return;
|
||||
setLoading(true);
|
||||
try {
|
||||
const data = await fetchList({ deviceId: channel, year: val });
|
||||
setMonths(data.code === 200 ? (data.directories || []) : []);
|
||||
} catch { setMonths([]); }
|
||||
finally { setLoading(false); }
|
||||
};
|
||||
|
||||
// 4. 选月份 → 加载日期
|
||||
const onMonthChange = async (val: string) => {
|
||||
setMonth(val);
|
||||
setDay(undefined); setDays([]);
|
||||
setFiles([]);
|
||||
if (!val || !channel || !year) return;
|
||||
setLoading(true);
|
||||
try {
|
||||
const data = await fetchList({ deviceId: channel, year, month: val });
|
||||
setDays(data.code === 200 ? (data.directories || []) : []);
|
||||
} catch { setDays([]); }
|
||||
finally { setLoading(false); }
|
||||
};
|
||||
|
||||
// 5. 选日期 → 加载当天视频文件
|
||||
const onDayChange = async (val: string) => {
|
||||
setDay(val);
|
||||
setFiles([]);
|
||||
if (!val || !channel || !year || !month) return;
|
||||
setLoading(true);
|
||||
try {
|
||||
const data = await fetchList({ deviceId: channel, year, month, day: val });
|
||||
setFiles(data.code === 200 ? (data.files || []) : []);
|
||||
if (data.code !== 200) message.warning(data.error || '读取文件失败');
|
||||
} catch { setFiles([]); message.error('读取文件失败'); }
|
||||
finally { setLoading(false); }
|
||||
};
|
||||
|
||||
// 预览:flv 用 flv.js,其余用原生 video
|
||||
useEffect(() => {
|
||||
if (!preview) return;
|
||||
const video = videoRef.current;
|
||||
if (!video) return;
|
||||
if (isFlv(preview.fileName) && flvjs.isSupported()) {
|
||||
const player = flvjs.createPlayer({ type: 'flv', url: preview.url, isLive: false });
|
||||
player.attachMediaElement(video);
|
||||
player.load();
|
||||
player.play().catch(() => { /* 自动播放策略可能拦截,用户手动点击 */ });
|
||||
flvPlayerRef.current = player;
|
||||
}
|
||||
return () => {
|
||||
flvPlayerRef.current?.destroy();
|
||||
flvPlayerRef.current = null;
|
||||
};
|
||||
}, [preview]);
|
||||
|
||||
const openPreview = (file: { fileName: string }) => {
|
||||
if (!channel || !year || !month || !day) return;
|
||||
setPreview({
|
||||
url: buildDownloadUrl({ deviceId: channel, year, month, day, fileName: file.fileName }),
|
||||
fileName: file.fileName,
|
||||
});
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{ title: '文件名', dataIndex: 'fileName', key: 'fileName', ellipsis: true },
|
||||
{ title: '大小', dataIndex: 'sizeFormatted', key: 'sizeFormatted', width: 120 },
|
||||
{
|
||||
title: '操作', key: 'action', width: 160,
|
||||
render: (_: any, rec: { fileName: string }) => (
|
||||
<Space>
|
||||
<Button size="small" type="link" icon={<PlayCircleOutlined />} onClick={() => openPreview(rec)}>预览</Button>
|
||||
<a href={buildDownloadUrl({ deviceId: channel!, year: year!, month: month!, day: day!, fileName: rec.fileName })} target="_blank" rel="noreferrer">
|
||||
<Button size="small" type="link" icon={<DownloadOutlined />}>下载</Button>
|
||||
</a>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div style={{ padding: '8px 0px', background: '#f5f7fa', minHeight: '100vh' }}>
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<Title level={4} style={{ margin: 0, fontSize: 'clamp(14px, 1.1vw, 18px)' }}>视频管理</Title>
|
||||
<Text type="secondary" style={{ fontSize: 12 }}>视频通道总览与预览管理,仅超级管理员可查看 · 在线 {onlineCount}/{channels.length}</Text>
|
||||
<Text type="secondary" style={{ fontSize: 12 }}>
|
||||
录像通道与回放管理(对接 nodevideo :9528) · 共 {channels.length} 个通道
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<Row gutter={[8, 8]}>
|
||||
{channels.map((ch) => {
|
||||
const online = ch.status === 'online';
|
||||
return (
|
||||
<Col xs={24} sm={12} lg={8} xl={6} key={ch.id}>
|
||||
<AntdCard
|
||||
bordered={false}
|
||||
style={{ borderRadius: 10, boxShadow: '0 2px 8px rgba(0,0,0,0.04)', overflow: 'hidden' }}
|
||||
bodyStyle={{ padding: 12 }}
|
||||
>
|
||||
{/* 视频快照占位 */}
|
||||
<div style={{
|
||||
position: 'relative', height: 120, borderRadius: 8, marginBottom: 10,
|
||||
background: online
|
||||
? 'linear-gradient(135deg, #0b2545 0%, #134074 100%)'
|
||||
: 'linear-gradient(135deg, #2b2b2b 0%, #4a4a4a 100%)',
|
||||
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||
}}>
|
||||
<CameraOutlined style={{ fontSize: 36, color: online ? 'rgba(255,255,255,0.85)' : 'rgba(255,255,255,0.35)' }} />
|
||||
<div style={{
|
||||
position: 'absolute', top: 8, left: 8,
|
||||
padding: '0 8px', borderRadius: 10, fontSize: 10,
|
||||
background: online ? 'rgba(82,196,26,0.9)' : 'rgba(0,0,0,0.45)',
|
||||
color: '#fff',
|
||||
}}>
|
||||
{online ? '● 在线' : '○ 离线'}
|
||||
</div>
|
||||
<div style={{
|
||||
position: 'absolute', bottom: 8, right: 8,
|
||||
padding: '0 8px', borderRadius: 10, fontSize: 10,
|
||||
background: 'rgba(0,0,0,0.45)', color: '#fff',
|
||||
}}>{ch.id}</div>
|
||||
</div>
|
||||
<Card bordered={false} style={{ borderRadius: 10, marginBottom: 8, boxShadow: '0 2px 8px rgba(0,0,0,0.04)' }} bodyStyle={{ padding: 12 }}>
|
||||
<Row gutter={[8, 8]} align="middle">
|
||||
<Col xs={24} sm={10} md={7}>
|
||||
<Text style={{ fontSize: 12, color: '#666' }}>通道</Text>
|
||||
<Select
|
||||
size="small" style={{ width: '100%' }} placeholder="选择设备通道"
|
||||
loading={loading && !channels.length}
|
||||
value={channel} onChange={onChannelChange}
|
||||
options={channels.map((c) => ({ value: c, label: c }))}
|
||||
showSearch optionFilterProp="label"
|
||||
/>
|
||||
</Col>
|
||||
<Col xs={8} sm={5} md={4}>
|
||||
<Text style={{ fontSize: 12, color: '#666' }}>年</Text>
|
||||
<Select size="small" style={{ width: '100%' }} placeholder="年" disabled={!channel}
|
||||
value={year} onChange={onYearChange}
|
||||
options={years.map((y) => ({ value: y, label: y }))} />
|
||||
</Col>
|
||||
<Col xs={8} sm={5} md={4}>
|
||||
<Text style={{ fontSize: 12, color: '#666' }}>月</Text>
|
||||
<Select size="small" style={{ width: '100%' }} placeholder="月" disabled={!year}
|
||||
value={month} onChange={onMonthChange}
|
||||
options={months.map((m) => ({ value: m, label: m }))} />
|
||||
</Col>
|
||||
<Col xs={8} sm={5} md={4}>
|
||||
<Text style={{ fontSize: 12, color: '#666' }}>日</Text>
|
||||
<Select size="small" style={{ width: '100%' }} placeholder="日" disabled={!month}
|
||||
value={day} onChange={onDayChange}
|
||||
options={days.map((d) => ({ value: d, label: d }))} />
|
||||
</Col>
|
||||
<Col xs={24} sm={4} md={5}>
|
||||
<Button size="small" icon={<ReloadOutlined />} onClick={loadChannels} style={{ width: '100%' }}>刷新通道</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
<div style={{ fontSize: 13, fontWeight: 600, color: '#262626', marginBottom: 4 }}>{ch.name}</div>
|
||||
<Space size={4} style={{ fontSize: 11, color: '#8c8c8c', marginBottom: 8 }} wrap>
|
||||
<VideoCameraOutlined />
|
||||
<span>{ch.device}</span>
|
||||
<Tag bordered={false} style={{ margin: 0, fontSize: 10 }} color={online ? 'green' : 'default'}>{ch.location}</Tag>
|
||||
</Space>
|
||||
<Card bordered={false} style={{ borderRadius: 10, boxShadow: '0 2px 8px rgba(0,0,0,0.04)' }} bodyStyle={{ padding: 4 }}>
|
||||
{loading ? (
|
||||
<div style={{ textAlign: 'center', padding: 40 }}><Spin /></div>
|
||||
) : !channel ? (
|
||||
<Empty description="请先选择视频通道" style={{ padding: 40 }} />
|
||||
) : !day ? (
|
||||
<Empty description="请选择 年 / 月 / 日 加载录像" image={Empty.PRESENTED_IMAGE_SIMPLE} style={{ padding: 40 }} />
|
||||
) : files.length === 0 ? (
|
||||
<Empty description="该日暂无录像文件" style={{ padding: 40 }} />
|
||||
) : (
|
||||
<Table
|
||||
size="small" rowKey="fileName" columns={columns} dataSource={files}
|
||||
pagination={{ size: 'small', pageSize: 10, showTotal: (t) => `共 ${t} 个文件` }}
|
||||
/>
|
||||
)}
|
||||
</Card>
|
||||
|
||||
<div style={{ display: 'flex', gap: 6, marginTop: 4 }}>
|
||||
<Button size="small" type="primary" icon={<PlayCircleOutlined />} style={{ flex: 1 }} onClick={() => handlePreview(ch)}>预览</Button>
|
||||
<Button size="small" icon={<HistoryOutlined />} disabled={!online} onClick={() => message.info(`${ch.name} 回放功能开发中`)}>回放</Button>
|
||||
<Button size="small" icon={<SettingOutlined />} onClick={() => message.info(`${ch.name} 参数设置`)} />
|
||||
</div>
|
||||
</AntdCard>
|
||||
</Col>
|
||||
);
|
||||
})}
|
||||
</Row>
|
||||
<Modal
|
||||
open={!!preview} title={`预览 ${preview?.fileName || ''}`} footer={null}
|
||||
onCancel={() => setPreview(null)} width={880} destroyOnClose
|
||||
>
|
||||
{preview && isFlv(preview.fileName) ? (
|
||||
<video ref={videoRef} controls style={{ width: '100%', background: '#000', borderRadius: 8 }} />
|
||||
) : preview && (
|
||||
<video src={preview.url} controls style={{ width: '100%', background: '#000', borderRadius: 8 }} />
|
||||
)}
|
||||
<div style={{ marginTop: 8, color: '#888', fontSize: 12 }}>
|
||||
若无法播放,请使用「下载」按钮获取文件后用本地播放器查看。
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user