diff --git a/.dumirc.ts b/.dumirc.ts index 36d1e9e..445c479 100644 --- a/.dumirc.ts +++ b/.dumirc.ts @@ -1,8 +1,6 @@ import { defineConfig } from 'dumi'; import path from 'path'; -console.log(path.join(__dirname, 'packages/hooks/src')); - export default defineConfig({ logo: '/logo.jpg', favicons: ['/logo.jpg'], @@ -11,6 +9,15 @@ export default defineConfig({ socialLinks: { gitlab: 'http://10.0.0.88/web-project/zhst-Lambo', }, + nav: { + mode: 'append', + value: [ + { + title: '智能柜物料库→', + link: 'http://10.0.0.222:30098', + }, + ], + }, }, alias: { '@zhst/hooks': path.join(__dirname, 'packages/hooks/src'), @@ -35,14 +42,4 @@ export default defineConfig({ srcDir: ['packages', 'src'], peerDeps: true, }, - extraBabelPlugins: [ - [ - 'import', - { - libraryName: 'antd', - libraryDirectory: 'es', - style: true, - }, - ], - ], }); diff --git a/.fatherrc.ts b/.fatherrc.ts index 0e503e9..db700bd 100644 --- a/.fatherrc.ts +++ b/.fatherrc.ts @@ -2,14 +2,4 @@ import { defineConfig } from 'father'; export default defineConfig({ // more father config: https://github.com/umijs/father/blob/master/docs/config.md - extraBabelPlugins: [ - [ - 'import', - { - libraryName: 'antd', - libraryDirectory: 'es', - style: true, - }, - ], - ], }); diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..d6aacd6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,10 @@ +{ + "configurations": [ + { + "type": "chrome", + "name": "http://localhost:8000/metas/big-image-preview", + "request": "launch", + "url": "http://localhost:8000/metas/big-image-preview" + } + ] +} diff --git a/package.json b/package.json index d055230..046c2be 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,6 @@ "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "@umijs/lint": "^4.0.0", - "babel-plugin-import": "^1.13.8", "dumi": "^2.2.13", "eslint": "^8.23.0", "father": "^4.1.0", diff --git a/packages/biz/CHANGELOG.md b/packages/biz/CHANGELOG.md index 5fa366f..b14b8d6 100644 --- a/packages/biz/CHANGELOG.md +++ b/packages/biz/CHANGELOG.md @@ -1,5 +1,115 @@ # @zhst/biz +## 0.10.1 + +### Patch Changes + +- Updated dependencies + - @zhst/meta@0.9.1 + +## 0.10.0 + +### Minor Changes + +- 修改 metad 大图组建 + +### Patch Changes + +- Updated dependencies + - @zhst/meta@0.9.0 + +## 0.9.8 + +### Patch Changes + +- @zhst/func@0.7.5 +- @zhst/hooks@0.8.4 +- @zhst/meta@0.8.5 + +## 0.9.7 + +### Patch Changes + +- 新增 RealTimeMonitor,VideoPlayerCard,ViewLargerImageModal,WarningRecordCard 组件,优化盒子树创建弹框规则校验 +- Updated dependencies + - @zhst/meta@0.8.5 + +## 0.9.6 + +### Patch Changes + +- 新增 tree 组件的监听事件,优化 meta 全选的回调事件监听 +- Updated dependencies + - @zhst/hooks@0.8.3 + - @zhst/func@0.7.4 + - @zhst/meta@0.8.4 + +## 0.9.5 + +### Patch Changes + +- 删除预览图组件,新增摄像头状态判断,修复 ts 生成失败问题 + +## 0.9.4 + +### Patch Changes + +- 添加 biz 模块修改树形盒子组件监听事件 + +## 0.9.3 + +### Patch Changes + +- 新增监听点击事件自定义 + +## 0.9.2 + +### Patch Changes + +- 新增 BoxSelectTree 监听时钟点击事件,导入盒子事件 + +## 0.9.1 + +### Patch Changes + +- 修改 boxSelectTree 类型提示 +- Updated dependencies + - @zhst/hooks@0.8.2 + - @zhst/func@0.7.3 + - @zhst/meta@0.8.3 + +## 0.9.0 + +### Minor Changes + +- 优化 boxSelectTree 组件,添加可以自定义配置按钮功能 + +### Patch Changes + +- Updated dependencies + - @zhst/hooks@0.8.1 + - @zhst/func@0.7.2 + - @zhst/meta@0.8.2 + +## 0.8.0 + +### Minor Changes + +- @zhst/biz 优化数组件 + +### Patch Changes + +- Updated dependencies + - @zhst/hooks@0.8.0 + - @zhst/func@0.7.1 + - @zhst/meta@0.8.1 + +## 0.7.0 + +### Minor Changes + +- 新增预警记录卡片组件 + ## 0.6.0 ### Minor Changes diff --git a/packages/biz/es/index.d.ts b/packages/biz/es/index.d.ts index ba509c5..743bed4 100644 --- a/packages/biz/es/index.d.ts +++ b/packages/biz/es/index.d.ts @@ -1,5 +1,17 @@ export { default as BigImageModal } from './BigImageModal'; +export type { BigImageModalProps } from './BigImageModal'; export { default as BoxSelectTree } from './boxSelectTree'; +export type { BoxSelectTreeProps } from './boxSelectTree'; export { default as Tree } from './tree'; +export type { BoxTreeProps, TreeData } from './tree'; export { default as TreeTransfer } from './treeTransfer'; +export type { TreeTransferProps } from './treeTransfer'; export { default as TreeTransferModal } from './treeTransferModal'; +export type { TreeTransferModalProps } from './treeTransferModal'; +export { default as WarningRecordCard } from './WarningRecordCard'; +export type { IRecord, WarningRecordCardProps } from './WarningRecordCard'; +export type { ViewLargerImageModalRef, ViewLargerImageModalProps } from './ViewLargerImageModal'; +export { default as ViewLargerImageModal, useViewLargerImageModal } from './ViewLargerImageModal'; +export type { VideoPlayerCardProps } from './VideoPlayerCard'; +export { default as VideoPlayerCard } from './VideoPlayerCard'; +export { default as RealTimeMonitor } from './RealTimeMonitor'; diff --git a/packages/biz/es/index.js b/packages/biz/es/index.js index beffc49..d340720 100644 --- a/packages/biz/es/index.js +++ b/packages/biz/es/index.js @@ -2,4 +2,8 @@ export { default as BigImageModal } from "./BigImageModal"; export { default as BoxSelectTree } from "./boxSelectTree"; export { default as Tree } from "./tree"; export { default as TreeTransfer } from "./treeTransfer"; -export { default as TreeTransferModal } from "./treeTransferModal"; \ No newline at end of file +export { default as TreeTransferModal } from "./treeTransferModal"; +export { default as WarningRecordCard } from "./WarningRecordCard"; +export { default as ViewLargerImageModal, useViewLargerImageModal } from "./ViewLargerImageModal"; +export { default as VideoPlayerCard } from "./VideoPlayerCard"; +export { default as RealTimeMonitor } from "./RealTimeMonitor"; \ No newline at end of file diff --git a/packages/biz/es/useSocket/index.js b/packages/biz/es/useSocket/index.js deleted file mode 100644 index 305ec57..0000000 --- a/packages/biz/es/useSocket/index.js +++ /dev/null @@ -1,95 +0,0 @@ -function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } -function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } -function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } -function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } -function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); } -function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } -import { useMemo } from 'react'; -import { throttle as loadshThrottle, noop } from '@zhst/func'; -import { useDeepEffect, useLatest } from '@zhst/hooks'; -import ws from "./ws"; -var getSelf = function getSelf(v) { - return v; -}; -export var SocketApi = { - CameraTaskStatue: 'singer.DeviceService/SubScribeCameraTaskStatus', - DeviceStatus: 'singer.TaskManagerService/SubscribeTaskStatus', - SubscribeSolutionDeploy: 'singer.SolutionManagerService/SubscribeSolutionDeploy', - SubscribeTasksSummary: 'singer.TaskManagerService/SubscribeTasksSummary', - MonitorSubscribeResult: 'singer.MonitorService/MonitorSubscribeResult', - MonitorSubscribeStatus: 'singer.MonitorService/MonitorSubscribeStatus', - SubscribeArchiveGroupUpload: 'singer.ArchiveGroupService/CreateArchiveByImport', - SubscribeJointTask: 'singer.JointTaskService/SubscribeJointTask', - SubscribeGroupFragment: 'singer.VideoService/SubscribeVideoFragmentStatus', - // 监听视频分片状态变化,包括新建、删除、变化 - SubscribeGroup: 'singer.VideoService/SubscribeGroup', - // 监听视频分组状态变化,列表变化也通知 - SubscribeStreamEvent: 'singer.MediaManagerService/SubscribeStreamEvent' // 监听视频分组状态变化,列表变化也通知 -}; -export default (function (topic) { - var iterator = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : noop; - var opt = arguments.length > 2 ? arguments[2] : undefined; - var _ref = opt || {}, - _ref$req = _ref.req, - req = _ref$req === void 0 ? {} : _ref$req, - _ref$throttle = _ref.throttle, - throttle = _ref$throttle === void 0 ? 0 : _ref$throttle, - _ref$beforeLoopTmp = _ref.beforeLoopTmp, - beforeLoopTmp = _ref$beforeLoopTmp === void 0 ? getSelf : _ref$beforeLoopTmp, - _ref$shouldBreak = _ref.shouldBreak, - shouldBreak = _ref$shouldBreak === void 0 ? false : _ref$shouldBreak, - forceRefresh = _ref.forceRefresh, - close = _ref.close; - - // 带上token - var reqstring = useMemo(function () { - var newReq = _objectSpread(_objectSpread({}, req), {}, { - extraHeaders: { - authorization: localStorage.getItem('USER-TOKEN') - } - }); - return JSON.stringify(newReq); - }, [req]); - var latestIterator = useLatest(iterator); - useDeepEffect(function () { - if (close) { - return; - } - //控制socket 请求发送 - if (shouldBreak) { - return; - } - //去抖动 - - var tmpData = []; - var throttleUpdate = loadshThrottle(function () { - if (tmpData.length == 0) { - return; - } - var _tmpData = beforeLoopTmp(tmpData); - latestIterator.current(_tmpData); //加了throttle 数据就变成数组 - tmpData = []; - }, throttle); - var unSubscribe = ws.subscribe(SocketApi[topic], reqstring, function (socketData) { - try { - if (!throttle) { - latestIterator.current(socketData); - } else { - tmpData.push(socketData); - throttleUpdate(); - } - } catch (error) { - console.error('useSocke:', error); - } - }); - return function () { - try { - unSubscribe(); - throttleUpdate.cancel(); - } catch (error) { - console.error(error); - throw error; - } - }; - }, [topic, reqstring, shouldBreak, forceRefresh, close]); -}); \ No newline at end of file diff --git a/packages/biz/es/useSocket/onceChannel.d.ts b/packages/biz/es/useSocket/onceChannel.d.ts deleted file mode 100644 index 400ffa7..0000000 --- a/packages/biz/es/useSocket/onceChannel.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare const startChannel: (topic: any, req: any, callback: any) => () => void; -export default startChannel; diff --git a/packages/biz/es/useSocket/onceChannel.js b/packages/biz/es/useSocket/onceChannel.js deleted file mode 100644 index b7f273e..0000000 --- a/packages/biz/es/useSocket/onceChannel.js +++ /dev/null @@ -1,24 +0,0 @@ -function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } -function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } -function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } -function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } -function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); } -function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } -//@ts-nocheck -import channel from "./ws"; -var startChannel = function startChannel(topic, req, callback) { - // 带上token - var reqstring = JSON.stringify(_objectSpread(_objectSpread({}, req), {}, { - extraHeaders: { - authorization: localStorage.getItem('USER-TOKEN') - } - })); - var unSubscribe = channel.subscribe(topic, reqstring, function (socketData) { - var shouldStop = callback(socketData); - if (shouldStop) { - unSubscribe === null || unSubscribe === void 0 || unSubscribe(); - } - }); - return unSubscribe; -}; -export default startChannel; \ No newline at end of file diff --git a/packages/biz/es/useSocket/ws.d.ts b/packages/biz/es/useSocket/ws.d.ts deleted file mode 100644 index 0dc9550..0000000 --- a/packages/biz/es/useSocket/ws.d.ts +++ /dev/null @@ -1,26 +0,0 @@ -declare class Channel { - /** - * io 实例化对象 - */ - ioIns: any; - /** - * 已存在的订阅列表 - */ - listeners: never[]; - /** - * 调试信息 记录订阅/反订阅次数 - */ - subscribeListenerId: never[]; - unSubscribeListenerId: never[]; - init: () => void; - retry: (listener: { - [x: string]: any; - lastRetryInterval: number | undefined; - intervalId: NodeJS.Timeout; - } | undefined) => void; - doEmit: (topic: any, req: any, listenerId: any) => void; - subscribe(topic: any, req: any, handle: any): () => void; - unSubscribe(topic: any, req: any, handleId: any, listenerId: any): void; -} -declare const channelIns: Channel; -export default channelIns; diff --git a/packages/biz/es/useSocket/ws.js b/packages/biz/es/useSocket/ws.js deleted file mode 100644 index a3918cb..0000000 --- a/packages/biz/es/useSocket/ws.js +++ /dev/null @@ -1,244 +0,0 @@ -function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } -function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } } -function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } -function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } -function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); } -function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } -// @ts-nocheck -import { v4 as uuidv4 } from 'uuid'; -import { has } from '@zhst/func'; -import io from 'socket.io-client'; -import { SOCKET_HOST } from '@common/constants'; -var EMITSTATE = { - NOT_CONNECT: 0, - WAITING: 1, - CONNECT: 2 -}; -var initRetryTime = 0; -var intervalTime = 5 * 1000; //下次重试增加时间 -var maxIntervalTime = 1 * 60 * 60 * 1000; //最大重试时间1小时 -var Channel = /*#__PURE__*/function () { - function Channel() { - var _this = this; - _classCallCheck(this, Channel); - /** - * io 实例化对象 - */ - _defineProperty(this, "ioIns", void 0); - /** - * 已存在的订阅列表 - */ - _defineProperty(this, "listeners", [ - // { - // topic: "", - // req: "", - // suInfo: {}, - // hasEmit: false,//是否已经订阅 - // lastRetryInterval: 0, - // handles: { - // } - // } - ]); - /** - * 调试信息 记录订阅/反订阅次数 - */ - _defineProperty(this, "subscribeListenerId", []); - _defineProperty(this, "unSubscribeListenerId", []); - _defineProperty(this, "init", function () { - var ioIns = _this.ioIns = io(SOCKET_HOST, { - reconnection: true, - transports: ['websocket'], - forceNew: true - }); - ioIns.on('connect', function () { - for (var _len = arguments.length, arg = new Array(_len), _key = 0; _key < _len; _key++) { - arg[_key] = arguments[_key]; - } - console.debug('connect', arg); - _this.ioIns = ioIns; - _this.listeners.forEach(function (v) { - _this.doEmit(v['topic'], v['req'], v['id']); - }); - }); - ioIns.on('event', function () { - for (var _len2 = arguments.length, arg = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { - arg[_key2] = arguments[_key2]; - } - console.debug('event', arg); - }); - ioIns.on('disconnect', function () { - for (var _len3 = arguments.length, arg = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { - arg[_key3] = arguments[_key3]; - } - console.debug('disconnect', arg); - _this.subscribeListenerId = []; - _this.unSubscribeListenerId = []; - }); - ioIns.on('reconnect', function () { - for (var _len4 = arguments.length, arg = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { - arg[_key4] = arguments[_key4]; - } - console.debug('reconnect', arg); - _this.listeners.forEach(function (v) { - v['hasEmit'] = EMITSTATE.NOT_CONNECT; - _this.doEmit(v['topic'], v['req'], v['id']); - }); - }); - }); - _defineProperty(this, "retry", function (listener) { - //重试逻辑 - var intervalId = setTimeout(function () { - var hasExit = _this.listeners.find(function (v) { - return v['topic'] === (listener === null || listener === void 0 ? void 0 : listener['topic']) && v['req'] === listener['req']; - }); - if (!hasExit) return; - listener['hasEmit'] = EMITSTATE.NOT_CONNECT; - _this.doEmit(listener['topic'], listener['req'], listener['id']); - }, listener.lastRetryInterval); - listener.intervalId = intervalId; - listener.lastRetryInterval = intervalTime + listener.lastRetryInterval > maxIntervalTime ? maxIntervalTime : intervalTime + listener.lastRetryInterval; - }); - _defineProperty(this, "doEmit", function (topic, req, listenerId) { - var _this$ioIns, _this$ioIns$emit; - if (!_this.ioIns) { - _this.init(); - } - //订阅过就不订阅了 - var hasEmit = _this.listeners.find(function (v) { - return v['topic'] === topic && v['req'] === req && v['hasEmit'] !== EMITSTATE.NOT_CONNECT; - }); - if (hasEmit) { - return; - } - var listener = _this.listeners.find(function (v) { - return v['topic'] === topic && v['req'] === req; - }); - listener['hasEmit'] = EMITSTATE.WAITING; - (_this$ioIns = _this.ioIns) === null || _this$ioIns === void 0 || (_this$ioIns$emit = _this$ioIns.emit) === null || _this$ioIns$emit === void 0 || _this$ioIns$emit.call(_this$ioIns, topic, req, function (data) { - var _this$ioIns2, _this$ioIns2$on; - console.info('emit', topic, req, data); - var suInfo = JSON.parse(data); - if (has(suInfo, 'Error.code')) { - if (suInfo.Error.code === 500) { - //后端出错 - _this.retry(listener); - } - return; - } - // console.debug('SUBSCRIBE', listenerId, topic, req, suInfo); - _this.subscribeListenerId.push(listenerId); - // debugger - //重新找一遍topic - var currentTopicIndex = _this.listeners.findIndex(function (v) { - return v['topic'] === topic && v['req'] === req && v['id'] === listenerId; - }); - if (currentTopicIndex == -1) { - // 不存在说明listener取消了 直接反订阅 - _this.ioIns.emit('UnSubscribe', JSON.stringify(suInfo), function (data) { - _this.unSubscribeListenerId.push(listenerId); - console.debug('UNSUBSCRIBE', listenerId, topic, req, data); - }); - return; - } - if (!suInfo['SubscribeID']) { - _this.listeners.splice(currentTopicIndex, 0); - } else { - _this.listeners[currentTopicIndex]['suInfo'] = suInfo; - _this.listeners[currentTopicIndex]['hasEmit'] = EMITSTATE.CONNECT; - } - (_this$ioIns2 = _this.ioIns) === null || _this$ioIns2 === void 0 || (_this$ioIns2$on = _this$ioIns2.on) === null || _this$ioIns2$on === void 0 || _this$ioIns2$on.call(_this$ioIns2, suInfo['SubscribeID'], function (data) { - console.info('on', suInfo['SubscribeID'], data); - try { - var socketData = JSON.parse(data); - if (has(socketData, 'Error.code')) { - if (socketData.Error.code === 500) { - //后端出错 - _this.retry(listener); - } - return; - } - var _ref = _this.listeners.find(function (v) { - return v['topic'] === topic && v['req'] === req; - }) || {}, - _ref$handles = _ref.handles, - handles = _ref$handles === void 0 ? {} : _ref$handles; - Object.keys(handles).forEach(function (key) { - try { - //后面观察 为什么delete后在foreach - var func = handles[key]; - if (!func) return; - func(socketData); - } catch (error) { - console.error(error); - } - }); - } catch (error) { - console.debug('error', error); - } - }); - }); - }); - } - _createClass(Channel, [{ - key: "subscribe", - value: function subscribe(topic, req, handle) { - var handleId = uuidv4(); - var listenerId = uuidv4(); - var listener = this.listeners.find(function (v) { - return v['topic'] === topic && v['req'] === req; - }); - if (listener) { - listener['handles'][handleId] = handle; - } else { - this.listeners.push({ - topic: topic, - req: req, - suInfo: {}, - id: listenerId, - hasEmit: EMITSTATE.NOT_CONNECT, - lastRetryInterval: initRetryTime, - handles: _defineProperty({}, "".concat(handleId), handle) - }); - //未注册过 则去订阅 - this.doEmit(topic, req, listenerId); - } - return this.unSubscribe.bind(this, topic, req, handleId, listenerId); - } - }, { - key: "unSubscribe", - value: function unSubscribe(topic, req, handleId, listenerId) { - var _this2 = this; - var listener = this.listeners.find(function (v) { - return v['topic'] === topic && v['req'] === req && v['id'] === listenerId; - }); - var _ref2 = listener || {}, - _ref2$handles = _ref2.handles, - handles = _ref2$handles === void 0 ? {} : _ref2$handles, - suInfo = _ref2.suInfo; - if (handles[handleId]) { - delete handles[handleId]; - //如果没有其他订阅就删除 - if (Object.keys(handles).length === 0) { - if (this.intervalId) { - clearTimeout(this.intervalId); - } - if (listener['hasEmit'] === EMITSTATE['CONNECT']) { - this.ioIns.emit('UnSubscribe', JSON.stringify(suInfo), function (data) { - _this2.unSubscribeListenerId.push(listenerId); - console.debug('UNSUBSCRIBE', listener['id'], topic, req, data); - }); - } - this.listeners = this.listeners.filter(function (v) { - return !(v['topic'] === topic && v['req'] === req); - }); - } - } - } - }]); - return Channel; -}(); //单例 -var channelIns = new Channel(); -//暴露实例 调试用 -window.__channel__ = channelIns; -export default channelIns; \ No newline at end of file diff --git a/packages/biz/es/utils/constants.d.ts b/packages/biz/es/utils/constants.d.ts deleted file mode 100644 index 45a9a99..0000000 --- a/packages/biz/es/utils/constants.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -export declare const OBJECT_GRNER_THRESHOLD = 0.8; -export declare const OBJECT_AGE_TYPE_THRESHOLD = 0.5; -export declare const MODE_KEY = "test_mode"; -export declare const SEARCH_IMG_COUNT = 10; -export declare const GLOBAL_IS_ITEM_NUMBER_SHOW = false; -export declare const publicPath = "hummingbird"; -export declare const ENTER_CIRCLE = "MONITORTYPE_ENTER_CIRCLE"; -export declare const OUT_CIRCLE = "MONITORTYPE_OUT_CIRCLE"; -export declare const TEMP = "MONITORTYPE_TEMP"; -export declare const GLOBAL_IS_BOX_VMS_SHOW = true; -export declare const BODY_SEARCH_THRESHOID = 0.45; -export declare const RECORD_VERSION = "3.0.0"; -export declare const DeviceTab: { - EMPTY: number; - REAL_CAMERA: number; - PREPROCESS_CAMERA: number; - TAG_CAMERA: number; - HISTORY_VIDEO_GROUP: number; - VIRTUAL_CAMERA: number; - REAL_CAMERA_NOFACE: number; - REAL_CAMERA_ONLYFACE: number; - REAL_CAMERA_NOFACE_NOBOX_NODIRECONNECT: number; -}; diff --git a/packages/biz/es/utils/constants.js b/packages/biz/es/utils/constants.js index 1ad86ba..925bab4 100644 --- a/packages/biz/es/utils/constants.js +++ b/packages/biz/es/utils/constants.js @@ -27,4 +27,17 @@ export var DeviceTab = { REAL_CAMERA_NOFACE: 6, REAL_CAMERA_ONLYFACE: 7, REAL_CAMERA_NOFACE_NOBOX_NODIRECONNECT: 8 // 只有普通摄像头,没有人脸、没有盒子、直连 -}; \ No newline at end of file +}; + +// 盒子 Tab 切换 +export var BOX_TYPE_LIST = [{ + value: '1', + label: '盒子' +}, { + value: '2', + label: '盒子组' +}]; +export var ALL_LIST = [{ + value: '', + label: '全部' +}]; \ No newline at end of file diff --git a/packages/biz/lib/index.d.ts b/packages/biz/lib/index.d.ts index ba509c5..743bed4 100644 --- a/packages/biz/lib/index.d.ts +++ b/packages/biz/lib/index.d.ts @@ -1,5 +1,17 @@ export { default as BigImageModal } from './BigImageModal'; +export type { BigImageModalProps } from './BigImageModal'; export { default as BoxSelectTree } from './boxSelectTree'; +export type { BoxSelectTreeProps } from './boxSelectTree'; export { default as Tree } from './tree'; +export type { BoxTreeProps, TreeData } from './tree'; export { default as TreeTransfer } from './treeTransfer'; +export type { TreeTransferProps } from './treeTransfer'; export { default as TreeTransferModal } from './treeTransferModal'; +export type { TreeTransferModalProps } from './treeTransferModal'; +export { default as WarningRecordCard } from './WarningRecordCard'; +export type { IRecord, WarningRecordCardProps } from './WarningRecordCard'; +export type { ViewLargerImageModalRef, ViewLargerImageModalProps } from './ViewLargerImageModal'; +export { default as ViewLargerImageModal, useViewLargerImageModal } from './ViewLargerImageModal'; +export type { VideoPlayerCardProps } from './VideoPlayerCard'; +export { default as VideoPlayerCard } from './VideoPlayerCard'; +export { default as RealTimeMonitor } from './RealTimeMonitor'; diff --git a/packages/biz/lib/index.js b/packages/biz/lib/index.js index e86160c..435cd59 100644 --- a/packages/biz/lib/index.js +++ b/packages/biz/lib/index.js @@ -31,9 +31,14 @@ var src_exports = {}; __export(src_exports, { BigImageModal: () => import_BigImageModal.default, BoxSelectTree: () => import_boxSelectTree.default, + RealTimeMonitor: () => import_RealTimeMonitor.default, Tree: () => import_tree.default, TreeTransfer: () => import_treeTransfer.default, - TreeTransferModal: () => import_treeTransferModal.default + TreeTransferModal: () => import_treeTransferModal.default, + VideoPlayerCard: () => import_VideoPlayerCard.default, + ViewLargerImageModal: () => import_ViewLargerImageModal.default, + WarningRecordCard: () => import_WarningRecordCard.default, + useViewLargerImageModal: () => import_ViewLargerImageModal.useViewLargerImageModal }); module.exports = __toCommonJS(src_exports); var import_BigImageModal = __toESM(require("./BigImageModal")); @@ -41,11 +46,20 @@ var import_boxSelectTree = __toESM(require("./boxSelectTree")); var import_tree = __toESM(require("./tree")); var import_treeTransfer = __toESM(require("./treeTransfer")); var import_treeTransferModal = __toESM(require("./treeTransferModal")); +var import_WarningRecordCard = __toESM(require("./WarningRecordCard")); +var import_ViewLargerImageModal = __toESM(require("./ViewLargerImageModal")); +var import_VideoPlayerCard = __toESM(require("./VideoPlayerCard")); +var import_RealTimeMonitor = __toESM(require("./RealTimeMonitor")); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { BigImageModal, BoxSelectTree, + RealTimeMonitor, Tree, TreeTransfer, - TreeTransferModal + TreeTransferModal, + VideoPlayerCard, + ViewLargerImageModal, + WarningRecordCard, + useViewLargerImageModal }); diff --git a/packages/biz/lib/useSocket/index.js b/packages/biz/lib/useSocket/index.js deleted file mode 100644 index b4d6861..0000000 --- a/packages/biz/lib/useSocket/index.js +++ /dev/null @@ -1,118 +0,0 @@ -var __create = Object.create; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __getProtoOf = Object.getPrototypeOf; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( - // If the importer is in node compatibility mode or this is not an ESM - // file that has been converted to a CommonJS file using a Babel- - // compatible transform (i.e. "__esModule" has not been set), then set - // "default" to the CommonJS "module.exports" for node compatibility. - isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, - mod -)); -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); - -// src/useSocket/index.ts -var useSocket_exports = {}; -__export(useSocket_exports, { - SocketApi: () => SocketApi, - default: () => useSocket_default -}); -module.exports = __toCommonJS(useSocket_exports); -var import_react = require("react"); -var import_func = require("@zhst/func"); -var import_hooks = require("@zhst/hooks"); -var import_ws = __toESM(require("./ws")); -var getSelf = (v) => v; -var SocketApi = { - CameraTaskStatue: "singer.DeviceService/SubScribeCameraTaskStatus", - DeviceStatus: "singer.TaskManagerService/SubscribeTaskStatus", - SubscribeSolutionDeploy: "singer.SolutionManagerService/SubscribeSolutionDeploy", - SubscribeTasksSummary: "singer.TaskManagerService/SubscribeTasksSummary", - MonitorSubscribeResult: "singer.MonitorService/MonitorSubscribeResult", - MonitorSubscribeStatus: "singer.MonitorService/MonitorSubscribeStatus", - SubscribeArchiveGroupUpload: "singer.ArchiveGroupService/CreateArchiveByImport", - SubscribeJointTask: "singer.JointTaskService/SubscribeJointTask", - SubscribeGroupFragment: "singer.VideoService/SubscribeVideoFragmentStatus", - // 监听视频分片状态变化,包括新建、删除、变化 - SubscribeGroup: "singer.VideoService/SubscribeGroup", - // 监听视频分组状态变化,列表变化也通知 - SubscribeStreamEvent: "singer.MediaManagerService/SubscribeStreamEvent" - // 监听视频分组状态变化,列表变化也通知 -}; -var useSocket_default = (topic, iterator = import_func.noop, opt) => { - const { - req = {}, - throttle = 0, - beforeLoopTmp = getSelf, - shouldBreak = false, - forceRefresh, - close - } = opt || {}; - const reqstring = (0, import_react.useMemo)(() => { - const newReq = { - ...req, - extraHeaders: { - authorization: localStorage.getItem("USER-TOKEN") - } - }; - return JSON.stringify(newReq); - }, [req]); - const latestIterator = (0, import_hooks.useLatest)(iterator); - (0, import_hooks.useDeepEffect)(() => { - if (close) { - return; - } - if (shouldBreak) { - return; - } - let tmpData = []; - const throttleUpdate = (0, import_func.throttle)(() => { - if (tmpData.length == 0) { - return; - } - const _tmpData = beforeLoopTmp(tmpData); - latestIterator.current(_tmpData); - tmpData = []; - }, throttle); - const unSubscribe = import_ws.default.subscribe(SocketApi[topic], reqstring, (socketData) => { - try { - if (!throttle) { - latestIterator.current(socketData); - } else { - tmpData.push(socketData); - throttleUpdate(); - } - } catch (error) { - console.error("useSocke:", error); - } - }); - return () => { - try { - unSubscribe(); - throttleUpdate.cancel(); - } catch (error) { - console.error(error); - throw error; - } - }; - }, [topic, reqstring, shouldBreak, forceRefresh, close]); -}; -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - SocketApi -}); diff --git a/packages/biz/lib/useSocket/onceChannel.d.ts b/packages/biz/lib/useSocket/onceChannel.d.ts deleted file mode 100644 index 400ffa7..0000000 --- a/packages/biz/lib/useSocket/onceChannel.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare const startChannel: (topic: any, req: any, callback: any) => () => void; -export default startChannel; diff --git a/packages/biz/lib/useSocket/onceChannel.js b/packages/biz/lib/useSocket/onceChannel.js deleted file mode 100644 index 2dc648e..0000000 --- a/packages/biz/lib/useSocket/onceChannel.js +++ /dev/null @@ -1,51 +0,0 @@ -var __create = Object.create; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __getProtoOf = Object.getPrototypeOf; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( - // If the importer is in node compatibility mode or this is not an ESM - // file that has been converted to a CommonJS file using a Babel- - // compatible transform (i.e. "__esModule" has not been set), then set - // "default" to the CommonJS "module.exports" for node compatibility. - isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, - mod -)); -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); - -// src/useSocket/onceChannel.tsx -var onceChannel_exports = {}; -__export(onceChannel_exports, { - default: () => onceChannel_default -}); -module.exports = __toCommonJS(onceChannel_exports); -var import_ws = __toESM(require("./ws")); -var startChannel = (topic, req, callback) => { - let reqstring = JSON.stringify({ - ...req, - extraHeaders: { - authorization: localStorage.getItem("USER-TOKEN") - } - }); - let unSubscribe = import_ws.default.subscribe(topic, reqstring, (socketData) => { - let shouldStop = callback(socketData); - if (shouldStop) { - unSubscribe == null ? void 0 : unSubscribe(); - } - }); - return unSubscribe; -}; -var onceChannel_default = startChannel; diff --git a/packages/biz/lib/useSocket/ws.d.ts b/packages/biz/lib/useSocket/ws.d.ts deleted file mode 100644 index 0dc9550..0000000 --- a/packages/biz/lib/useSocket/ws.d.ts +++ /dev/null @@ -1,26 +0,0 @@ -declare class Channel { - /** - * io 实例化对象 - */ - ioIns: any; - /** - * 已存在的订阅列表 - */ - listeners: never[]; - /** - * 调试信息 记录订阅/反订阅次数 - */ - subscribeListenerId: never[]; - unSubscribeListenerId: never[]; - init: () => void; - retry: (listener: { - [x: string]: any; - lastRetryInterval: number | undefined; - intervalId: NodeJS.Timeout; - } | undefined) => void; - doEmit: (topic: any, req: any, listenerId: any) => void; - subscribe(topic: any, req: any, handle: any): () => void; - unSubscribe(topic: any, req: any, handleId: any, listenerId: any): void; -} -declare const channelIns: Channel; -export default channelIns; diff --git a/packages/biz/lib/useSocket/ws.js b/packages/biz/lib/useSocket/ws.js deleted file mode 100644 index 8dab6f2..0000000 --- a/packages/biz/lib/useSocket/ws.js +++ /dev/null @@ -1,224 +0,0 @@ -var __create = Object.create; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __getProtoOf = Object.getPrototypeOf; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( - // If the importer is in node compatibility mode or this is not an ESM - // file that has been converted to a CommonJS file using a Babel- - // compatible transform (i.e. "__esModule" has not been set), then set - // "default" to the CommonJS "module.exports" for node compatibility. - isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, - mod -)); -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); - -// src/useSocket/ws.ts -var ws_exports = {}; -__export(ws_exports, { - default: () => ws_default -}); -module.exports = __toCommonJS(ws_exports); -var import_uuid = require("uuid"); -var import_func = require("@zhst/func"); -var import_socket = __toESM(require("socket.io-client")); -var import_constants = require("@common/constants"); -var EMITSTATE = { - NOT_CONNECT: 0, - WAITING: 1, - CONNECT: 2 -}; -var initRetryTime = 0; -var intervalTime = 5 * 1e3; -var maxIntervalTime = 1 * 60 * 60 * 1e3; -var Channel = class { - constructor() { - /** - * 已存在的订阅列表 - */ - this.listeners = [ - // { - // topic: "", - // req: "", - // suInfo: {}, - // hasEmit: false,//是否已经订阅 - // lastRetryInterval: 0, - // handles: { - // } - // } - ]; - /** - * 调试信息 记录订阅/反订阅次数 - */ - this.subscribeListenerId = []; - this.unSubscribeListenerId = []; - this.init = () => { - const ioIns = this.ioIns = (0, import_socket.default)(import_constants.SOCKET_HOST, { - reconnection: true, - transports: ["websocket"], - forceNew: true - }); - ioIns.on("connect", (...arg) => { - console.debug("connect", arg); - this.ioIns = ioIns; - this.listeners.forEach((v) => { - this.doEmit(v["topic"], v["req"], v["id"]); - }); - }); - ioIns.on("event", (...arg) => { - console.debug("event", arg); - }); - ioIns.on("disconnect", (...arg) => { - console.debug("disconnect", arg); - this.subscribeListenerId = []; - this.unSubscribeListenerId = []; - }); - ioIns.on("reconnect", (...arg) => { - console.debug("reconnect", arg); - this.listeners.forEach((v) => { - v["hasEmit"] = EMITSTATE.NOT_CONNECT; - this.doEmit(v["topic"], v["req"], v["id"]); - }); - }); - }; - this.retry = (listener) => { - const intervalId = setTimeout(() => { - const hasExit = this.listeners.find( - (v) => v["topic"] === (listener == null ? void 0 : listener["topic"]) && v["req"] === listener["req"] - ); - if (!hasExit) - return; - listener["hasEmit"] = EMITSTATE.NOT_CONNECT; - this.doEmit(listener["topic"], listener["req"], listener["id"]); - }, listener.lastRetryInterval); - listener.intervalId = intervalId; - listener.lastRetryInterval = intervalTime + listener.lastRetryInterval > maxIntervalTime ? maxIntervalTime : intervalTime + listener.lastRetryInterval; - }; - this.doEmit = (topic, req, listenerId) => { - var _a, _b; - if (!this.ioIns) { - this.init(); - } - const hasEmit = this.listeners.find( - (v) => v["topic"] === topic && v["req"] === req && v["hasEmit"] !== EMITSTATE.NOT_CONNECT - ); - if (hasEmit) { - return; - } - const listener = this.listeners.find((v) => v["topic"] === topic && v["req"] === req); - listener["hasEmit"] = EMITSTATE.WAITING; - (_b = (_a = this.ioIns) == null ? void 0 : _a.emit) == null ? void 0 : _b.call(_a, topic, req, (data) => { - var _a2, _b2; - console.info("emit", topic, req, data); - const suInfo = JSON.parse(data); - if ((0, import_func.has)(suInfo, "Error.code")) { - if (suInfo.Error.code === 500) { - this.retry(listener); - } - return; - } - this.subscribeListenerId.push(listenerId); - const currentTopicIndex = this.listeners.findIndex( - (v) => v["topic"] === topic && v["req"] === req && v["id"] === listenerId - ); - if (currentTopicIndex == -1) { - this.ioIns.emit("UnSubscribe", JSON.stringify(suInfo), (data2) => { - this.unSubscribeListenerId.push(listenerId); - console.debug("UNSUBSCRIBE", listenerId, topic, req, data2); - }); - return; - } - if (!suInfo["SubscribeID"]) { - this.listeners.splice(currentTopicIndex, 0); - } else { - this.listeners[currentTopicIndex]["suInfo"] = suInfo; - this.listeners[currentTopicIndex]["hasEmit"] = EMITSTATE.CONNECT; - } - (_b2 = (_a2 = this.ioIns) == null ? void 0 : _a2.on) == null ? void 0 : _b2.call(_a2, suInfo["SubscribeID"], (data2) => { - console.info("on", suInfo["SubscribeID"], data2); - try { - const socketData = JSON.parse(data2); - if ((0, import_func.has)(socketData, "Error.code")) { - if (socketData.Error.code === 500) { - this.retry(listener); - } - return; - } - const { handles = {} } = this.listeners.find((v) => v["topic"] === topic && v["req"] === req) || {}; - Object.keys(handles).forEach((key) => { - try { - const func = handles[key]; - if (!func) - return; - func(socketData); - } catch (error) { - console.error(error); - } - }); - } catch (error) { - console.debug("error", error); - } - }); - }); - }; - } - subscribe(topic, req, handle) { - const handleId = (0, import_uuid.v4)(); - const listenerId = (0, import_uuid.v4)(); - const listener = this.listeners.find((v) => v["topic"] === topic && v["req"] === req); - if (listener) { - listener["handles"][handleId] = handle; - } else { - this.listeners.push({ - topic, - req, - suInfo: {}, - id: listenerId, - hasEmit: EMITSTATE.NOT_CONNECT, - lastRetryInterval: initRetryTime, - handles: { - [`${handleId}`]: handle - } - }); - this.doEmit(topic, req, listenerId); - } - return this.unSubscribe.bind(this, topic, req, handleId, listenerId); - } - unSubscribe(topic, req, handleId, listenerId) { - const listener = this.listeners.find( - (v) => v["topic"] === topic && v["req"] === req && v["id"] === listenerId - ); - const { handles = {}, suInfo } = listener || {}; - if (handles[handleId]) { - delete handles[handleId]; - if (Object.keys(handles).length === 0) { - if (this.intervalId) { - clearTimeout(this.intervalId); - } - if (listener["hasEmit"] === EMITSTATE["CONNECT"]) { - this.ioIns.emit("UnSubscribe", JSON.stringify(suInfo), (data) => { - this.unSubscribeListenerId.push(listenerId); - console.debug("UNSUBSCRIBE", listener["id"], topic, req, data); - }); - } - this.listeners = this.listeners.filter((v) => !(v["topic"] === topic && v["req"] === req)); - } - } - } -}; -var channelIns = new Channel(); -window.__channel__ = channelIns; -var ws_default = channelIns; diff --git a/packages/biz/lib/utils/constants.d.ts b/packages/biz/lib/utils/constants.d.ts deleted file mode 100644 index 45a9a99..0000000 --- a/packages/biz/lib/utils/constants.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -export declare const OBJECT_GRNER_THRESHOLD = 0.8; -export declare const OBJECT_AGE_TYPE_THRESHOLD = 0.5; -export declare const MODE_KEY = "test_mode"; -export declare const SEARCH_IMG_COUNT = 10; -export declare const GLOBAL_IS_ITEM_NUMBER_SHOW = false; -export declare const publicPath = "hummingbird"; -export declare const ENTER_CIRCLE = "MONITORTYPE_ENTER_CIRCLE"; -export declare const OUT_CIRCLE = "MONITORTYPE_OUT_CIRCLE"; -export declare const TEMP = "MONITORTYPE_TEMP"; -export declare const GLOBAL_IS_BOX_VMS_SHOW = true; -export declare const BODY_SEARCH_THRESHOID = 0.45; -export declare const RECORD_VERSION = "3.0.0"; -export declare const DeviceTab: { - EMPTY: number; - REAL_CAMERA: number; - PREPROCESS_CAMERA: number; - TAG_CAMERA: number; - HISTORY_VIDEO_GROUP: number; - VIRTUAL_CAMERA: number; - REAL_CAMERA_NOFACE: number; - REAL_CAMERA_ONLYFACE: number; - REAL_CAMERA_NOFACE_NOBOX_NODIRECONNECT: number; -}; diff --git a/packages/biz/lib/utils/constants.js b/packages/biz/lib/utils/constants.js index 6c57f12..733d65a 100644 --- a/packages/biz/lib/utils/constants.js +++ b/packages/biz/lib/utils/constants.js @@ -19,7 +19,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru // src/utils/constants.ts var constants_exports = {}; __export(constants_exports, { + ALL_LIST: () => ALL_LIST, BODY_SEARCH_THRESHOID: () => BODY_SEARCH_THRESHOID, + BOX_TYPE_LIST: () => BOX_TYPE_LIST, DeviceTab: () => DeviceTab, ENTER_CIRCLE: () => ENTER_CIRCLE, GLOBAL_IS_BOX_VMS_SHOW: () => GLOBAL_IS_BOX_VMS_SHOW, @@ -62,9 +64,18 @@ var DeviceTab = { REAL_CAMERA_NOFACE_NOBOX_NODIRECONNECT: 8 // 只有普通摄像头,没有人脸、没有盒子、直连 }; +var BOX_TYPE_LIST = [ + { value: "1", label: "盒子" }, + { value: "2", label: "盒子组" } +]; +var ALL_LIST = [ + { value: "", label: "全部" } +]; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { + ALL_LIST, BODY_SEARCH_THRESHOID, + BOX_TYPE_LIST, DeviceTab, ENTER_CIRCLE, GLOBAL_IS_BOX_VMS_SHOW, diff --git a/packages/biz/package.json b/packages/biz/package.json index d696711..87a6497 100644 --- a/packages/biz/package.json +++ b/packages/biz/package.json @@ -1,6 +1,6 @@ { "name": "@zhst/biz", - "version": "0.6.0", + "version": "0.10.1", "description": "业务库", "keywords": [ "business", @@ -35,7 +35,7 @@ "registry": "http://10.0.0.77:4874" }, "devDependencies": { - "@types/zhst": "workspace:^" + "@zhst/types": "workspace:^" }, "dependencies": { "@ant-design/icons": "^5.2.6", @@ -45,6 +45,7 @@ "@zhst/meta": "workspace:^", "antd": "^5.12.5", "classnames": "^2.5.1", - "rc-util": "^5.38.1" + "rc-util": "^5.38.1", + "dayjs": "^1.11.10" } } diff --git a/packages/biz/src/RealTimeMonitor/RealTimeMonitor.tsx b/packages/biz/src/RealTimeMonitor/RealTimeMonitor.tsx new file mode 100644 index 0000000..73d7dd4 --- /dev/null +++ b/packages/biz/src/RealTimeMonitor/RealTimeMonitor.tsx @@ -0,0 +1,69 @@ +import React from 'react'; +import { IRecord, VideoPlayerCardProps, ViewLargerImageModalRef } from '@zhst/biz'; +import WindowToggle from './components/WindowToggle'; +import WarningRecordList from './components/WarningRecordList'; + +interface RealTimeMonitorProps { + videoDataSource?: VideoPlayerCardProps[]; + handleWindowClick?: (key?: string) => void; + handleCloseButtonClick?: (key?: string) => void; + selectedWindowKey?: string; + warningDataSource?: IRecord[]; + viewLargerImageModalRef?: React.RefObject; + /* + 处理 图片下载按钮点击事件 + */ + handleDownloadImg?: (imgSrc?: string) => void; + /* + 处理 预警记录卡片点击事件 + */ + onRecordClick?: (record?: IRecord) => void; + /* + 获取选中的 记录 id 用于 判断是否显示 选中样式 + */ + selectedRecordId?: string; + isRecordListLoading?: boolean; + recordListTitle?: string; + style?: React.CSSProperties; + cardStyle?: React.CSSProperties; + imgStyle?: React.CSSProperties; + largeImageTitle?: string; +} + +export const RealTimeMonitor: React.FC = (props) => { + + const { videoDataSource, + handleWindowClick, + handleCloseButtonClick, + selectedWindowKey, + warningDataSource, + viewLargerImageModalRef, + handleDownloadImg, + onRecordClick, + selectedRecordId, + isRecordListLoading, + } = props + + return ( +
+ + +
+ + ); +}; + +export default RealTimeMonitor; \ No newline at end of file diff --git a/packages/biz/src/RealTimeMonitor/components/WarningRecordList/WarningRecordList.tsx b/packages/biz/src/RealTimeMonitor/components/WarningRecordList/WarningRecordList.tsx new file mode 100644 index 0000000..9aba8b9 --- /dev/null +++ b/packages/biz/src/RealTimeMonitor/components/WarningRecordList/WarningRecordList.tsx @@ -0,0 +1,82 @@ +import React from 'react'; +import { ViewLargerImageModal, WarningRecordCard, IRecord, ViewLargerImageModalRef } from '@zhst/biz'; +import { Empty, Space, Spin } from 'antd'; +import "./index.less" +import { LoadingOutlined } from '@ant-design/icons'; + +interface WarningRecordListProps { + dataSource?: IRecord[]; + viewLargerImageModalRef?: React.RefObject; + /* + 处理 图片下载按钮点击事件 + */ + handleDownloadImg?: (imgSrc?: string) => void; + /* + 处理 预警记录卡片点击事件 + */ + onRecordClick?: (record?: IRecord) => void; + /* + 获取选中的 记录 id 用于 判断是否显示 选中样式 + */ + selectedRecordId?: string; + isRecordListLoading?: boolean; + recordListTitle?: string; + style?: React.CSSProperties; + cardStyle?: React.CSSProperties; + imgStyle?: React.CSSProperties; + largeImageTitle?: string; +} + +const WarningRecordList: React.FC = (props) => { + + const { + dataSource = [], + viewLargerImageModalRef, + selectedRecordId, + handleDownloadImg, + onRecordClick, + isRecordListLoading, + recordListTitle, + style, + cardStyle, + imgStyle, + largeImageTitle + } = props + + return ( +
+
{recordListTitle}
+
+ { + isRecordListLoading ? +
+ } /> +
+ : (dataSource?.length) > 0 ? + + {dataSource?.map((record, index) => { + if (index > 2) return + return ( { onRecordClick?.(record) }} + selectedRecordId={selectedRecordId} + cardStyle={{ width: 300, height: 264, ...cardStyle }} + imgStyle={{ width: 280, height: 169, ...imgStyle }} + />) + } + )} + + : +
+ +
+ } +
+ {/* 弹窗 绑定ref 后可以调用 handleCancel方法关闭弹窗 show方法打开弹窗 */} + +
+ ) +}; + +export default WarningRecordList; \ No newline at end of file diff --git a/packages/biz/src/RealTimeMonitor/components/WarningRecordList/index.less b/packages/biz/src/RealTimeMonitor/components/WarningRecordList/index.less new file mode 100644 index 0000000..e348f82 --- /dev/null +++ b/packages/biz/src/RealTimeMonitor/components/WarningRecordList/index.less @@ -0,0 +1,20 @@ +.zhst-biz-warning-record-list { + display: flex; + flex-direction: column; + border-left: solid 1px #00000026; + width: 320px; + + .header { + width: 100%; + height: 48px; + background-color: #EFF2F4; + padding: 10px 20px; + box-sizing: border-box; + } + + .body { + padding: 10px; + overflow: hidden; + flex: 1; + } +} \ No newline at end of file diff --git a/packages/biz/src/RealTimeMonitor/components/WarningRecordList/index.tsx b/packages/biz/src/RealTimeMonitor/components/WarningRecordList/index.tsx new file mode 100644 index 0000000..3e4aa09 --- /dev/null +++ b/packages/biz/src/RealTimeMonitor/components/WarningRecordList/index.tsx @@ -0,0 +1,2 @@ +import WarningRecordList from './WarningRecordList' +export default WarningRecordList \ No newline at end of file diff --git a/packages/biz/src/RealTimeMonitor/components/WindowToggle/WindowToggle.tsx b/packages/biz/src/RealTimeMonitor/components/WindowToggle/WindowToggle.tsx new file mode 100644 index 0000000..0211f0f --- /dev/null +++ b/packages/biz/src/RealTimeMonitor/components/WindowToggle/WindowToggle.tsx @@ -0,0 +1,71 @@ +import React, { useState } from 'react'; +import { Segmented } from 'antd'; +import { AppstoreOutlined, BarsOutlined } from '@ant-design/icons'; +import { VideoPlayerCard, VideoPlayerCardProps } from '@zhst/biz'; +import './index.less' +import { theme } from 'antd/lib'; + +type Size = 'large' | 'small' + +interface WindowToggleProps { + dataSource?: VideoPlayerCardProps[]; + handleWindowClick?: (key?: string) => void; + handleCloseButtonClick?: (key?: string) => void; + selectedWindowKey?: string; +} + +export const WindowToggle: React.FC = (props) => { + + const { dataSource = [], handleWindowClick, handleCloseButtonClick, selectedWindowKey } = props + const [size, setSize] = useState("large"); + const { useToken } = theme + const { token } = useToken() + + const getLabelStyle = (isSelected: boolean) => ({ + padding: "0 11px", background: "#fff", + ...(isSelected ? { background: token.colorPrimary, color: '#fff' } : {}), + }); + + + return ( +
+ {/* 切换按钮 */} +
+
}, + { value: 'small', label:
}, + ]} + onChange={(value) => { + // 当一个窗口时 默认 selectedkey 第一条数据的 windowkey + if (value === 'large' && dataSource.length > 0) { + const { windowKey } = dataSource[0] + handleWindowClick?.(windowKey) + } + setSize(value as Size) + }} + /> +
+ +
+ { + dataSource?.map((item, index) => { + if (size === "large" && index > 0) return + return ( + ) + }) + } +
+ + ); +}; + +export default WindowToggle; + diff --git a/packages/biz/src/RealTimeMonitor/components/WindowToggle/index.less b/packages/biz/src/RealTimeMonitor/components/WindowToggle/index.less new file mode 100644 index 0000000..61c77bd --- /dev/null +++ b/packages/biz/src/RealTimeMonitor/components/WindowToggle/index.less @@ -0,0 +1,45 @@ +.zhst-biz-window-toggle { + display: flex; + flex-direction: column; + flex: 1; + + .header { + width: 100%; + height: 48px; + background-color: #EFF2F4; + padding: 10px 20px; + box-sizing: border-box; + + .ant-segmented { + padding: 0; + + .ant-segmented-group { + border-radius: 4px; + overflow: hidden; + + .ant-segmented-item { + border-radius: 0; + + .ant-segmented-item-label { + padding: 0; + } + } + } + } + } + + .body { + flex: 1; + width: 100%; + background-color: #E5EAEC; + padding: 10px; + box-sizing: border-box; + display: flex; + flex-wrap: wrap; + justify-content: space-between; + + >div { + margin: 10px; + } + } +} \ No newline at end of file diff --git a/packages/biz/src/RealTimeMonitor/components/WindowToggle/index.tsx b/packages/biz/src/RealTimeMonitor/components/WindowToggle/index.tsx new file mode 100644 index 0000000..0fa9c9a --- /dev/null +++ b/packages/biz/src/RealTimeMonitor/components/WindowToggle/index.tsx @@ -0,0 +1,2 @@ +import WindowToggle from './WindowToggle' +export default WindowToggle \ No newline at end of file diff --git a/packages/biz/src/RealTimeMonitor/demo/base.tsx b/packages/biz/src/RealTimeMonitor/demo/base.tsx new file mode 100644 index 0000000..90338fd --- /dev/null +++ b/packages/biz/src/RealTimeMonitor/demo/base.tsx @@ -0,0 +1,161 @@ + +import React, { useState } from 'react'; +import { IRecord, RealTimeMonitor, VideoPlayerCardProps, useViewLargerImageModal } from '@zhst/biz'; +import { videoData, warningData } from './mock'; +import { Space } from 'antd'; +import dayjs from 'dayjs' +import './index.less' + +export default () => { + + // 必须设置初始数据 用于渲染 4个窗口 + const initialVideoDataSource: VideoPlayerCardProps[] = [ + { + windowKey: 'first-window', + }, + { + windowKey: 'second-window', + }, + { + windowKey: 'third-window', + }, + { + windowKey: 'forth-window', + } + ] + const [videoDataSource, setVideoDataSource] = useState(initialVideoDataSource); + const [warningDataSource, setWarningDataSource] = useState(); + const [selectedWindowKey, setSelectedWindowKey] = useState('first-window'); + const [selectedRecordId, setSelectedRecordId] = React.useState() + const [isRecordListLoading, setIsRecordListLoading] = React.useState(false) + // 把弹窗的ref 拿出来 + const viewLargerImageModalRef = useViewLargerImageModal() + + const handleWindowClick = (key?: string) => { + setSelectedWindowKey(key) + } + + const clearWindowData = (key?: string) => { + // 当关闭窗口时 也要刷新 右侧 预警记录接口 不要忘记 + setVideoDataSource((pre) => { + const newVideoDataSource = pre.map((item) => { + if (item.windowKey === key) { + return { windowKey: key }; + } + return item; // 保持不变 + }); + return newVideoDataSource + }) + } + + const handleDownloadImg = (imgSrc?: string) => { + console.log(imgSrc) + // 可以调用 下面 方法关闭弹窗 + // viewLargerImageModalRef.current?.handleCancel() + } + + const onRecordClick = (record?: IRecord) => { + // 点击的时候把数据 拿过来处理一下传给大图弹框 + const { imgSrc, warningType, boxId, position, cabietId, warningTime, warningTimestamp, warningTimeFormat = 'YYYY-MM-DD HH:mm:ss' } = record || {} + const formattedDate = warningTimestamp ? dayjs(warningTimestamp).format(warningTimeFormat) : ''; + const warningTimeShow = warningTime ? warningTime : formattedDate + //用于渲染右侧的 信息 + const warningData = [ + { label: '预警类型', value: warningType }, + { label: '预警时间', value: warningTimeShow }, + { label: '盒子', value: boxId }, + { label: '点位', value: position }, + { label: '柜子ID', value: cabietId }, + ] + // 调用这个方法打开弹框 + viewLargerImageModalRef?.current?.show({ imgSrc: imgSrc, warningData: warningData }) + + setSelectedRecordId(record?.id) + } + + const mockData = () => { + // 请求时需要对应窗口为loading 状态 + setVideoDataSource((pre) => { + const newVideoDataSource: VideoPlayerCardProps[] = pre.map((item) => { + // 开启loading + if (item.windowKey === selectedWindowKey) { + return { ...item, isWindowLoading: true, title: '' } + } + return item + }); + return newVideoDataSource + }) + + // 模拟 视频数据请求 + setTimeout(() => { + // 对后端返回数据进行处理 组装一套符合属性的 数据 + const newVideoData: VideoPlayerCardProps = { imgSrc: videoData.imgSrc, title: videoData.title, } + setVideoDataSource((pre) => { + const newVideoDataSource: VideoPlayerCardProps[] = pre.map((item) => { + // 传给 选中的视频窗口 + if (item.windowKey === selectedWindowKey) { + return { ...item, ...newVideoData } + } + return item + }); + return newVideoDataSource + }) + + setVideoDataSource((pre) => { + const newVideoDataSource: VideoPlayerCardProps[] = pre.map((item) => { + // 关闭loading + if (item.windowKey === selectedWindowKey) { + return { ...item, isWindowLoading: false } + } + return item + }); + return newVideoDataSource + }) + + }, 3000); + + // 模拟 预警记录数据请求 + + setIsRecordListLoading(true) + + setTimeout(() => { + const newWarningDataSource: IRecord[] = warningData.map(o => { + return { + imgSrc: o.imgSrc, + id: o.id, + warningType: o.warningType, + boxId: o.boxId, + position: o.position, + cabietId: o.cabietId, + //,`柜子ID: ${o.cabietId}` + warningInfo: [`盒子${o.boxId}`, `位置${o.position}`, `柜子ID${o.cabietId}`], + // cabietText: `柜子ID: ${o.cabietId}`, + warningTimestamp: o.warningTimestamp, + } + }) + setWarningDataSource(newWarningDataSource) + setIsRecordListLoading(false) + }, 1000) + + } + + return ( + + + + + + + ) +} diff --git a/packages/biz/src/RealTimeMonitor/demo/index.less b/packages/biz/src/RealTimeMonitor/demo/index.less new file mode 100644 index 0000000..71ea110 --- /dev/null +++ b/packages/biz/src/RealTimeMonitor/demo/index.less @@ -0,0 +1,5 @@ +#realtimemonitor-demo-base { + .dumi-default-previewer-demo>div { + width: 100%; + } +} \ No newline at end of file diff --git a/packages/biz/src/RealTimeMonitor/demo/mock.tsx b/packages/biz/src/RealTimeMonitor/demo/mock.tsx new file mode 100644 index 0000000..4497d61 --- /dev/null +++ b/packages/biz/src/RealTimeMonitor/demo/mock.tsx @@ -0,0 +1,65 @@ +export const videoData = { + imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png', + // videoSrc: 'ws://10.0.0.7:9033/flv/File/test/test_h264_1.mp4.flv?ip=127.0.0.1', + title: `盒子1 点位1` +} + +export const warningData = [ + { + imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png', + id: '156156ewr1', + warningType: '火焰识别', + boxId: '2', + position: '2', + cabietId: '002', + // warningTime: "2023-03-01 ", + warningTimestamp: Date.now(), + // warningTimeFormat:"YYYY-MM-DD" + }, + { + imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png', + id: '156156ewr155', + warningType: '火焰识别', + boxId: '1', + position: '1', + cabietId: '001', + // warningTime: "2023-03-01 ", + warningTimestamp: Date.now(), + // warningTimeFormat:"YYYY-MM-DD" + }, + { + imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png', + id: '156156rew155', + warningType: '火焰识别', + boxId: '3', + position: '3', + cabietId: '004', + // warningTime: "2023-03-01 ", + warningTimestamp: Date.now(), + // warningTimeFormat:"YYYY-MM-DD" + }, + { + imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png', + id: '15615615ew5', + warningType: '火焰识别', + boxId: '4', + position: '4', + cabietId: '004', + // warningTime: "2023-03-01 ", + warningTimestamp: Date.now(), + // warningTimeFormat:"YYYY-MM-DD" + }, + { + imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png', + id: '15615615sdf5', + warningType: '火焰识别', + boxId: '5', + position: '5', + cabietId: '005', + // warningTime: "2023-03-01 ", + warningTimestamp: Date.now(), + // warningTimeFormat:"YYYY-MM-DD" + } +] + + diff --git a/packages/biz/src/RealTimeMonitor/index.md b/packages/biz/src/RealTimeMonitor/index.md new file mode 100644 index 0000000..e18579f --- /dev/null +++ b/packages/biz/src/RealTimeMonitor/index.md @@ -0,0 +1,36 @@ +--- +group: 数据展示 +category: Components +subtitle: 实时监控页面 +title: RealTimeMonitor 实时监控页面 +--- + +# RealTimeMonitor 实时监控页面 + + + + + + +## API + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| videoDataSource | 用于渲染 每个窗口的数据 | VideoPlayerCardProps[] | 需要传一组默认值用于窗口的渲染| - | +| warningDataSource | 用于渲染 预警记录的数据 | WindowProps[] | 需要传一组默认值用于窗口的渲染| - | +| handleWindowClick | 用于获取窗口的 windowKey 方便更新对应窗口数据 | (key?: string) => void; | - | - | +| handleCloseButtonClick | 用于点击窗口关闭按钮的事件 | (key?: string) => void; | - | - | +| selectedWindowKey | 选中的窗口的 key 用于控制 选中边框样式 |string| - | - | +| handleDownloadImg | 用于处理查看大图下载图片的事件 | (key?: string) => void; | - | - | +| onRecordClick | 用于处理预警记录卡片点击事件事件 | (key?: string) => void; | - | - | +| selectedRecordId| 用于判断是否显示选中样式 |string| - | - | +| isRecordListLoading | 判断预警记录列表loading状态 |boolean| - | - | +| recordListTitle | 预警记录列表的标题 | string | - | - | +| viewLargerImageModalRef | 查看大图弹窗的ref | viewLargerImageModalRef={viewLargerImageModalRef}| | - | +| viewLargerImageModalRef | 查看大图弹窗的ref |React.RefObject\| - | - | + + + + + + diff --git a/packages/biz/src/RealTimeMonitor/index.tsx b/packages/biz/src/RealTimeMonitor/index.tsx new file mode 100644 index 0000000..00985f9 --- /dev/null +++ b/packages/biz/src/RealTimeMonitor/index.tsx @@ -0,0 +1,2 @@ +import RealTimeMonitor from './RealTimeMonitor' +export default RealTimeMonitor \ No newline at end of file diff --git a/packages/biz/src/VideoPlayerCard/VideoPlayerCard.tsx b/packages/biz/src/VideoPlayerCard/VideoPlayerCard.tsx new file mode 100644 index 0000000..7499d22 --- /dev/null +++ b/packages/biz/src/VideoPlayerCard/VideoPlayerCard.tsx @@ -0,0 +1,101 @@ +import { Card, Space, CardProps, Spin, Button } from 'antd'; +import { theme } from 'antd/lib'; +import { VideoPlayer, type VideoViewRef } from '@zhst/meta'; +import React, { useState, useEffect, ReactNode, useRef } from 'react'; +import { CloseOutlined, LoadingOutlined } from '@ant-design/icons'; +import './index.less' +export interface VideoPlayerCardProps { + windowKey?: string; + selectedWindowKey?: string; + showType?: 'video' | "image"; + imgSrc?: string; + videoSrc?: string; + cardProps?: CardProps; + errorReasonText?: string; + isWindowLoading?: boolean; + size?: 'large' | 'small'; + title?: string | ReactNode + handleCloseButtonClick?: (key?: string) => void; + handleWindowClick?: (key?: string) => void; +} + +export const VideoPlayerCard: React.FC = (props) => { + + const componentName = `zhst-biz-video-player-card`; + const { showType, imgSrc, videoSrc, cardProps, isWindowLoading, errorReasonText, size, title, handleCloseButtonClick, handleWindowClick, windowKey, selectedWindowKey = '' } = props; + const [cardContent, setCardContent] = useState(null); + const { useToken } = theme + const { token } = useToken() + const videoRef = useRef(null) + const selectedBorderStyle = { + border: `2px solid ${token.colorPrimary}`, boxShadow: " 0px 2px 9px 0px rgba(0,0,0,0.16)" + } + const cardStyle: React.CSSProperties = { + ...(size === 'large' ? { height: 931 } : { height: 456, cursor: 'pointer' }), + ...(size === 'small' && selectedWindowKey === windowKey ? selectedBorderStyle : {}) + }; + const videoPlayerCardStyle = size === 'small' ? { width: "calc(50% - 20px)" } : { flex: 1 } + + useEffect(() => { + if (!isWindowLoading && (videoSrc || imgSrc)) { + let contentElement: JSX.Element | null = null; + if (videoSrc) { + contentElement = ( + + ); + videoRef.current?.setShowCrop(true) + + } else if (imgSrc) { + contentElement = ( + 首帧图 + ); + } + setCardContent(contentElement); + } else { + setCardContent(null) + } + }, [showType, imgSrc, videoSrc, isWindowLoading]); + + return ( +
{ handleWindowClick?.(windowKey) }} style={videoPlayerCardStyle}> + +
{title}
+
+ +
+ } + style={{ display: "flex", flexDirection: "column", borderRadius: 4, overflow: "hidden", ...cardStyle }} + bodyStyle={{ flex: 1 }} + {...cardProps} + > + {cardContent ? ( + <> + {cardContent} + + ) : ( +
+ { + isWindowLoading ? +
+ } /> +
+ : !!errorReasonText && {errorReasonText} + } +
+ )} + {/* 其他内容 */} +
+
+ ); +}; + +export default VideoPlayerCard; + diff --git a/packages/biz/src/VideoPlayerCard/demo/base.tsx b/packages/biz/src/VideoPlayerCard/demo/base.tsx new file mode 100644 index 0000000..7063d94 --- /dev/null +++ b/packages/biz/src/VideoPlayerCard/demo/base.tsx @@ -0,0 +1,19 @@ + +import React from 'react'; +import { VideoPlayerCard, type VideoPlayerCardProps } from '@zhst/biz'; +import { Space } from 'antd'; + +const mockVideoPlayerCardProps: VideoPlayerCardProps = { + showType: 'image', + // videoSrc: 'https://example.com/video.mp4', + imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png', // 如果需要在没有视频时显示图片封面 + size: 'small', +}; + +export default () => { + return ( + + + + ) +} diff --git a/packages/biz/src/VideoPlayerCard/index.less b/packages/biz/src/VideoPlayerCard/index.less new file mode 100644 index 0000000..0f87e3e --- /dev/null +++ b/packages/biz/src/VideoPlayerCard/index.less @@ -0,0 +1,30 @@ +.zhst-biz-video-player-card { + .ant-card-head { + padding: 0 20px; + } + + .ant-card-body { + padding: 0; + overflow: hidden; + border-radius: 0; + + .zhst-image__video-view { + height: 100%; + } + } + + .card-close-button { + .ant-btn { + padding: 0 3px; + height: 22px; + color: #00000073; + } + + .ant-btn:hover { + padding: 0 3px; + height: 22px; + color: #000000e0; + } + } + +} \ No newline at end of file diff --git a/packages/biz/src/VideoPlayerCard/index.md b/packages/biz/src/VideoPlayerCard/index.md new file mode 100644 index 0000000..a888603 --- /dev/null +++ b/packages/biz/src/VideoPlayerCard/index.md @@ -0,0 +1,34 @@ +--- +group: 数据展示 +category: Components +subtitle: 视频播放卡片 +title: VideoPlayerCard 视频播放卡片 +--- + +# VideoPlayerCard 视频播放卡片 + + + + + + +## API + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| windowKey | 每个卡片的唯一标识 | string | - | - | +| selectedWindowKey | 选中的窗口key | string | - | - | +| imgSrc | 图片地址 | string | - | - | +| videoSrc | 视频地址 | string | - | - | +| errorReasonText | 加载失败的错误提示 | string | - | - | +| isWindowLoading | 判断是否显示loading | boolean | - | - | +| size | 设置窗口大小 | 'large' \| 'small' | - | - | +| title | 设置窗口标题 | string \| ReactNode | - | - | +| handleCloseButtonClick | 处理关闭按钮事件 | (key?: string) => void| - | - | +| handleWindowClick | 处理窗口点击事件 | (key?: string) => void| - | - | + + + + + + diff --git a/packages/biz/src/VideoPlayerCard/index.tsx b/packages/biz/src/VideoPlayerCard/index.tsx new file mode 100644 index 0000000..20710eb --- /dev/null +++ b/packages/biz/src/VideoPlayerCard/index.tsx @@ -0,0 +1,3 @@ +import VideoPlayerCard from './VideoPlayerCard' +export type { VideoPlayerCardProps } from './VideoPlayerCard' +export default VideoPlayerCard \ No newline at end of file diff --git a/packages/biz/src/ViewLargerImageModal/ViewLargerImageModal.tsx b/packages/biz/src/ViewLargerImageModal/ViewLargerImageModal.tsx new file mode 100644 index 0000000..f4475bd --- /dev/null +++ b/packages/biz/src/ViewLargerImageModal/ViewLargerImageModal.tsx @@ -0,0 +1,86 @@ +import React, { useImperativeHandle, useRef, useState, forwardRef } from 'react'; +import { Modal, ModalProps, Space, SpaceProps } from 'antd'; +import theme from 'antd/lib/theme'; +import { DownloadOutlined } from '@ant-design/icons'; +import './index.less' + +type ViewLargerImageModalParams = { + imgSrc?: string; + warningData?: { + label?: string; + value?: string; + }[]; +}; + +export interface ViewLargerImageModalRef { + show: (params?: ViewLargerImageModalParams) => void; + handleCancel: () => void; +} + +export interface ViewLargerImageModalProps { + imgStyle?: React.CSSProperties; + downloadImg?: (imgSrc?: string) => void; + title?: string; + downloadText?: string; + modalProps?: ModalProps + spaceProps?: SpaceProps; +} + +export const ViewLargerImageModal = forwardRef( + (props, ref) => { + + const { modalProps, downloadImg, imgStyle, title = '预警大图', downloadText = '下载大图', spaceProps } = props + const { useToken } = theme + const { token } = useToken() + const [open, setOpen] = useState(false); + const [imgSrc, setImgSrc] = useState(); + const [warningData, setWarningData] = useState(); + + const handleCancel = () => { + setOpen(false); + } + + useImperativeHandle(ref, () => { + return { + show: (_params) => { + setOpen(true); + setImgSrc(_params?.imgSrc) + setWarningData(_params?.warningData) + }, + handleCancel + }; + }); + + return ( + + + {title} +
+ {warningData?.map(({ label, value }) => ( +
+ {`${label}: `} + {value} +
+ ))} + {imgSrc && downloadImg &&
downloadImg?.(imgSrc)} >{downloadText}
} +
+
+
+ ); + } +) + +export default ViewLargerImageModal; + +export const useViewLargerImageModal = () => { + return useRef(null); +}; \ No newline at end of file diff --git a/packages/biz/src/ViewLargerImageModal/demo/base.tsx b/packages/biz/src/ViewLargerImageModal/demo/base.tsx new file mode 100644 index 0000000..0668f55 --- /dev/null +++ b/packages/biz/src/ViewLargerImageModal/demo/base.tsx @@ -0,0 +1,94 @@ + +import React from 'react'; +import { ViewLargerImageModal, WarningRecordCard, IRecord, useViewLargerImageModal } from '@zhst/biz'; +import { Space } from 'antd'; +import dayjs from 'dayjs'; + +// 结合预警图列表 演示查看预警大图的使用 例如 后端返回这样的数据结构 +const backEndData = [ + { + imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png', + id: '1561561', + warningType: '火焰识别', + boxId: '2', + position: '2', + cabietId: '002', + // warningTime: "2023-03-01 ", + warningTimestamp: Date.now(), + // warningTimeFormat:"YYYY-MM-DD" + }, + { + imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png', + id: '156156155', + warningType: '火焰识别', + boxId: '1', + position: '1', + cabietId: '001', + // warningTime: "2023-03-01 ", + warningTimestamp: Date.now(), + // warningTimeFormat:"YYYY-MM-DD" + } +] + +// 前端处理数据结构 +const dataSource = backEndData.map(o => { + return { + imgSrc: o.imgSrc, + id: o.id, + warningType: o.warningType, + boxId: o.boxId, + position: o.position, + cabietId: o.cabietId, + //,`柜子ID ${o.cabietId}` + warningInfo: [`盒子${o.boxId}`, `位置${o.position}`], + cabietText: `柜子ID: ${o.cabietId}`, + warningTimestamp: o.warningTimestamp, + } +}) + + + +export default () => { + + const [selectedRecordId, setSelectedRecordId] = React.useState() + + // 把弹窗的ref 拿出来 + const viewLargerImageModalRef = useViewLargerImageModal() + + const handleDownloadImg = () => { + console.log('download') + // 可以调用 下面 方法关闭弹窗 + // viewLargerImageModalRef.current?.handleCancel() + } + + const handleClick = (record?: IRecord) => { + // 点击的时候把数据 拿过来处理一下传给大图弹框 + const { imgSrc, warningType, boxId, position, cabietId, warningTime, warningTimestamp, warningTimeFormat = 'YYYY-MM-DD HH:mm:ss' } = record || {} + const formattedDate = warningTimestamp ? dayjs(warningTimestamp).format(warningTimeFormat) : ''; + const warningTimeShow = warningTime ? warningTime : formattedDate + //用于渲染右侧的 信息 + const warningData = [ + { label: '预警类型', value: warningType }, + { label: '预警时间', value: warningTimeShow }, + { label: '盒子', value: boxId }, + { label: '点位', value: position }, + { label: '柜子ID', value: cabietId }, + ] + // 调用这个方法打开弹框 + viewLargerImageModalRef?.current?.show({ imgSrc: imgSrc, warningData: warningData }) + + setSelectedRecordId(record?.id) + } + + return ( + <> + + { + dataSource?.map((record) => { handleClick(record) }} selectedRecordId={selectedRecordId} />) + } + + {/* 弹窗 绑定ref 后可以调用 handleCancel方法关闭弹窗 show方法打开弹窗 */} + + + ) +} diff --git a/packages/biz/src/ViewLargerImageModal/index.less b/packages/biz/src/ViewLargerImageModal/index.less new file mode 100644 index 0000000..32363d0 --- /dev/null +++ b/packages/biz/src/ViewLargerImageModal/index.less @@ -0,0 +1,62 @@ +.zhst-biz-view-warning-larger-image-modal { + font-family: MicrosoftYaHei; + + .ant-modal-content { + padding: 0; + height: 492px; + border-radius: 6px; + overflow: hidden; + + .ant-modal-close { + top: 14px; + right: 16px; + } + + .ant-modal-header { + height: 48px; + line-height: 48px; + margin-bottom: 0; + + .ant-modal-title { + height: 100%; + line-height: 48px; + font-weight: bold; + padding-left: 20px; + } + } + + .ant-modal-body { + height: 444px; + + >div { + width: 100%; + height: 100%; + align-items: flex-start; + + >div:nth-child(2) { + position: relative; + flex: 1; + box-sizing: border-box; + height: 100%; + padding: 30px 16px; + + .right-context>div { + margin-bottom: 20px; + } + + .right-context .context-key { + font-weight: bold; + } + + .img-download { + position: absolute; + bottom: 0; + cursor: pointer; + } + + } + + } + } + } +} \ No newline at end of file diff --git a/packages/biz/src/ViewLargerImageModal/index.md b/packages/biz/src/ViewLargerImageModal/index.md new file mode 100644 index 0000000..d4ae110 --- /dev/null +++ b/packages/biz/src/ViewLargerImageModal/index.md @@ -0,0 +1,28 @@ +--- +group: 数据展示 +category: Components +subtitle: 查看大图弹窗 +title: ViewLargerImageModal 查看大图弹窗 +--- + +# ViewLargerImageModal 查看大图弹窗 + + + + + + +## API + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| show() |通过 ref 用于开启弹窗 可以将点击的 记录传给弹窗| | | | +| handleCancel() | 通过 ref 用于关闭弹窗 | | | | +| imgSrc | 图片地址 |string | | | +| contextData | 大图显示的数据 | | | | +| imgStyle | 用于修改图片样式 | | | | +| downloadImg | 传入下载图片的方法 | | | | +| title | 弹窗标题 | string | | | +| downloadText | 下载按钮文本 | string | | | +| modalProps | 弹窗属性 | | | | + diff --git a/packages/biz/src/ViewLargerImageModal/index.tsx b/packages/biz/src/ViewLargerImageModal/index.tsx new file mode 100644 index 0000000..2780f86 --- /dev/null +++ b/packages/biz/src/ViewLargerImageModal/index.tsx @@ -0,0 +1,4 @@ +import ViewLargerImageModal, { useViewLargerImageModal } from './ViewLargerImageModal' +export type { ViewLargerImageModalRef, ViewLargerImageModalProps } from './ViewLargerImageModal' +export default ViewLargerImageModal; +export { useViewLargerImageModal }; \ No newline at end of file diff --git a/packages/biz/src/WarningRecordCard/WarningRecordCard.tsx b/packages/biz/src/WarningRecordCard/WarningRecordCard.tsx new file mode 100644 index 0000000..4833868 --- /dev/null +++ b/packages/biz/src/WarningRecordCard/WarningRecordCard.tsx @@ -0,0 +1,109 @@ +import { Card, Space, Divider, CardProps } from 'antd'; +import { theme } from 'antd/lib'; +import React from 'react'; +import dayjs from 'dayjs'; +import './index.less' +export interface IRecord { + + imgSrc?: string; + + id?: string; + /** + * 预警类型 + */ + warningType?: string; + /* + 用于显示 盒子 点位 柜子 等信息 + */ + warningInfo?: string[] + /* + 右侧 柜子id 显示 + /* + 盒子 ID + */ + boxId: string; + /* + 位置信息 + */ + position: string; + /* + 柜子id + */ + cabietId?: string; + /* + 直接传格式化好的时间 + /* + 右侧 柜子id 显示 + */ + cabietText?: string; + /* + 直接传格式化好的时间 + */ + warningTime?: string; + /* + 传格时间戳 + */ + warningTimestamp?: string | number + /* + 传格时间格式 + @default YYYY-MM-DD HH:mm:ss + */ + warningTimeFormat?: string; + +}; + +export interface WarningRecordCardProps { + record?: IRecord; + onRecordClick?: (record?: IRecord) => void; + style?: React.CSSProperties; + cardProps?: CardProps; + selectedRecordId?: string; + cardStyle?: React.CSSProperties; + imgStyle?: React.CSSProperties; +}; + +export const WarningRecordCard: React.FC = (props) => { + + const componentName = `zhst-biz-warning-record-card`; + const { record, onRecordClick, style, cardProps, selectedRecordId, cardStyle, imgStyle } = props; + const { imgSrc, id, warningType, warningInfo = [], cabietText, warningTime, warningTimestamp, warningTimeFormat = 'YYYY-MM-DD HH:mm:ss' } = record || {} + const formattedDate = warningTimestamp ? dayjs(warningTimestamp).format(warningTimeFormat) : ''; + const warningTimeShow = warningTime ? warningTime : formattedDate + const { useToken } = theme + const { token } = useToken() + const selectedBorderStyle = { + border: `2px solid ${token.colorPrimary}`, boxShadow: " 0px 2px 9px 0px rgba(0,0,0,0.16)" + } + const selectedCardStyle: React.CSSProperties = { + ...(selectedRecordId === record?.id ? selectedBorderStyle : {}) + }; + + const handleClick = () => { + onRecordClick?.(record); + }; + + return ( +
+ } + style={{ width: 356, height: 302, padding: 10, borderRadius: 4, ...selectedCardStyle, ...cardStyle }} + {...cardProps} + > +
+
{warningType}
+ }> + {warningInfo?.map((item, index) => ( +
+ {item} +
+ ))} +
+
{warningTimeShow}
+
+
{cabietText}
+
+
+ ); +}; + +export default WarningRecordCard; diff --git a/packages/biz/src/WarningRecordCard/demo/base.tsx b/packages/biz/src/WarningRecordCard/demo/base.tsx new file mode 100644 index 0000000..51a8039 --- /dev/null +++ b/packages/biz/src/WarningRecordCard/demo/base.tsx @@ -0,0 +1,56 @@ + +import React from 'react'; +import { WarningRecordCard } from '@zhst/biz'; +import { Space } from 'antd'; + +// 例如 后端返回这样的数据结构 +const backEndData = [ + { + imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png', + id: '1561561', + warningType: '火焰识别', + boxId: '2', + position: '2', + cabietId: '002', + // warningTime: "2023-03-01 ", + warningTimestamp: Date.now(), + // warningTimeFormat:"YYYY-MM-DD" + }, + { + imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png', + id: '156156155', + warningType: '火焰识别', + boxId: '1', + position: '1', + cabietId: '001', + // warningTime: "2023-03-01 ", + warningTimestamp: Date.now(), + // warningTimeFormat:"YYYY-MM-DD" + } +] + +// 前端处理数据结构 +const dataSource = backEndData.map(o => { + return { + imgSrc: o.imgSrc, + id: o.id, + warningType: o.warningType, + boxId: o.boxId, + position: o.position, + cabietId: o.cabietId, + warningInfo: [`盒子${o.boxId}`, `位置${o.position}`, `柜子ID${o.cabietId}`], + // cabietText: `柜子ID: ${o.cabietId}`, + warningTimestamp: o.warningTimestamp, + } +}) + +export default () => { + + return ( + + { + dataSource?.map((record) => ) + } + + ) +} diff --git a/packages/biz/src/WarningRecordCard/index.less b/packages/biz/src/WarningRecordCard/index.less new file mode 100644 index 0000000..7cfba38 --- /dev/null +++ b/packages/biz/src/WarningRecordCard/index.less @@ -0,0 +1,27 @@ +.zhst-biz-warning-record-card { + cursor: pointer; + + .ant-card-body { + padding: 0; + font-family: MicrosoftYaHei; + line-height: 19px; + display: flex; + margin-top: 10px; + + .left-context { + flex: 1; + + >div { + margin-top: 6px; + } + + >div:nth-child(1) { + margin-top: 0; + } + } + + .warning-type { + font-weight: bold; + } + } +} \ No newline at end of file diff --git a/packages/biz/src/WarningRecordCard/index.md b/packages/biz/src/WarningRecordCard/index.md new file mode 100644 index 0000000..bb9e648 --- /dev/null +++ b/packages/biz/src/WarningRecordCard/index.md @@ -0,0 +1,30 @@ +--- +group: 数据展示 +category: Components +subtitle: 预警记录卡片 +title: WarningRecordCard 预警记录卡片 +--- + +# WarningRecordCard 预警记录卡片 + + + + + + +## API + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| imgSrc | 图片src | string | - | - | +| id | 数据的唯一id 用于key 传值| string | - | - | +| warningType | 预警类型 | string | - | - | +| warningInfo | 盒子 点位 柜子 等信息 | string[] | - | - | +| cabietText | 右侧 柜子信息 | string | - | - | +| warningTime | 预警时间 格式化后的时间字符串 | string | - | - | +| warningTimestamp | 预警时间戳 | string \| number | - | - | +| warningTimeFormat | 预警时间格式 | string | YYYY-MM-DD HH:mm:ss | - | + + + + diff --git a/packages/biz/src/WarningRecordCard/index.tsx b/packages/biz/src/WarningRecordCard/index.tsx new file mode 100644 index 0000000..b60bf27 --- /dev/null +++ b/packages/biz/src/WarningRecordCard/index.tsx @@ -0,0 +1,3 @@ +import WarningRecordCard from './WarningRecordCard' +export type { IRecord, WarningRecordCardProps} from './WarningRecordCard' +export default WarningRecordCard \ No newline at end of file diff --git a/packages/biz/src/boxSelectTree/boxSelectTree.tsx b/packages/biz/src/boxSelectTree/boxSelectTree.tsx index fe3914e..aea65ad 100644 --- a/packages/biz/src/boxSelectTree/boxSelectTree.tsx +++ b/packages/biz/src/boxSelectTree/boxSelectTree.tsx @@ -1,21 +1,11 @@ import React, { FC } from 'react'; -import { InputProps, Tabs, TabsProps, TreeDataNode, TreeProps } from 'antd' +import { Tabs, TabsProps } from 'antd' import BoxPanel from './components/boxPanel'; -import { ModalFormProps } from '@ant-design/pro-components'; +import type { BoxPanelProps } from './components/boxPanel'; -export interface BoxSelectTreeProps { - boxDataSource: TreeDataNode[] - data: TreeDataNode[] - onSearch?: (e: any) => void // 搜索 - onItemSelect?: TreeProps['onSelect'] - onItemCheck?: TreeProps['onCheck'] +export interface BoxSelectTreeProps extends BoxPanelProps { onTabChange?: (e: any) => void - onBoxBatchDelete?: (data?: any) => void - onBoxDelete?: (data?: any) => void - onCreateSubmit?: ModalFormProps['onFinish'] tabsProps?: TabsProps - searchInputProps?: InputProps - treeProps?: TreeProps } const BoxSelectTree: FC = (props) => { @@ -29,15 +19,17 @@ const BoxSelectTree: FC = (props) => { onBoxBatchDelete, onBoxDelete, onCreateSubmit, + onClockClick, + onImport, + onCreate, tabsProps, searchInputProps, - treeProps + treeProps, + customImport, + showOptions, + extraBtns, } = props - const onChange = (key: string) => { - onTabChange?.(key) - }; - const items: TabsProps['items'] = [ { key: '1', @@ -48,12 +40,18 @@ const BoxSelectTree: FC = (props) => { boxDataSource={boxDataSource} treeProps={treeProps} data={data} + onCreate={onCreate} onCreateSubmit={onCreateSubmit} onBoxBatchDelete={onBoxBatchDelete} onBoxDelete={onBoxDelete} onSearch={onSearch} onItemCheck={onItemCheck} onItemSelect={onItemSelect} + showOptions={showOptions} + customImport={customImport} + extraBtns={extraBtns} + onClockClick={onClockClick} + onImport={onImport} /> ) }, @@ -66,12 +64,18 @@ const BoxSelectTree: FC = (props) => { searchInputProps={searchInputProps} treeProps={treeProps} data={data} + onCreate={onCreate} onBoxBatchDelete={onBoxBatchDelete} onCreateSubmit={onCreateSubmit} onBoxDelete={onBoxDelete} onSearch={onSearch} onItemCheck={onItemCheck} onItemSelect={onItemSelect} + showOptions={showOptions} + customImport={customImport} + extraBtns={extraBtns} + onClockClick={onClockClick} + onImport={onImport} /> ) }, @@ -82,7 +86,7 @@ const BoxSelectTree: FC = (props) => { defaultActiveKey="1" centered items={items} - onChange={onChange} + onChange={onTabChange} tabBarGutter={0} indicator={{ size: (origin) => origin, align: 'center' }} {...tabsProps} diff --git a/packages/biz/src/boxSelectTree/components/boxPanel/index.tsx b/packages/biz/src/boxSelectTree/components/boxPanel/index.tsx index 0cad4a0..396e375 100644 --- a/packages/biz/src/boxSelectTree/components/boxPanel/index.tsx +++ b/packages/biz/src/boxSelectTree/components/boxPanel/index.tsx @@ -1,14 +1,16 @@ import React, { FC, useState, useRef } from 'react'; import{ Button, Divider, Input, Space, TreeDataNode } from 'antd' import { ModalForm, ModalFormProps, ProFormInstance, ProFormText } from '@ant-design/pro-components' -import { DiffOutlined, SwitcherOutlined } from '@ant-design/icons' +import { ClockCircleOutlined, CloseCircleOutlined, DiffOutlined, FolderAddOutlined, ImportOutlined, SwitcherOutlined } from '@ant-design/icons' import type { TreeProps, InputProps } from 'antd'; +import type { BoxTreeProps } from '../../../tree'; import TreeTransferModal from '../../../treeTransferModal' import BoxTree from '../../../tree'; -export interface BoxGroupPanelProps { +export interface BoxPanelProps { searchInputProps?: InputProps - treeProps?: TreeProps + showOptions?: boolean + treeProps?: Partial data: TreeDataNode[] boxDataSource: TreeDataNode[] handleImport?: () => void @@ -18,11 +20,19 @@ export interface BoxGroupPanelProps { onBoxBatchDelete?: (data?: any) => void onBoxDelete?: (data?: any) => void onCreateSubmit?: ModalFormProps['onFinish'] + onClockClick?: () => void + onImport?: () => void + onBatch?: () => void + onCreate?: () => void + customImport?: any + extraBtns?: any } -const BoxGroupPanel: FC = (props) => { +const BoxPanel: FC = (props) => { const { searchInputProps, + showOptions = true, + extraBtns, data = [], onSearch, treeProps, @@ -31,7 +41,12 @@ const BoxGroupPanel: FC = (props) => { onCreateSubmit, onBoxBatchDelete, onBoxDelete, - boxDataSource + onClockClick, + onImport, + onBatch, + onCreate, + boxDataSource, + customImport } = props const [isTreeCheckable, setIsTreeCheckable] = useState(false) const [targetItems, setTargetItems] = useState([]); @@ -40,8 +55,7 @@ const BoxGroupPanel: FC = (props) => { const createFormRef = useRef< ProFormInstance<{ name: string; - company?: string; - useMode?: string; + boxList?: any[]; }> >() @@ -75,89 +89,122 @@ const BoxGroupPanel: FC = (props) => { setTargetItems(pre => pre.filter(o => o.key !== key)) } - const onOk = (data: any) => { - console.log('data', data) + // 盒子点击确定 + const onBoxChoiceOk = async (data: any) => { + createFormRef.current?.setFieldValue('boxList', data) + createFormRef.current?.setFieldValue('boxName', 123) + console.log(createFormRef.current?.getFieldValue('boxList')) + setBoxChoiceOpen(false) } - const onReset = () => { + // 盒子选择重置 + const onBoxChoiceReset = () => { setCheckedKeys([]) setTargetItems([]) } return (
+ {/* 盒子选择弹框 */} setBoxChoiceOpen(false)} - onRadioChange={(val) => console.log('radio', val)} // 顶部 radio 事件 + onRadioChange={(e) => console.log('radio', e.target.value)} // 顶部 radio 事件 dataSource={boxDataSource} // 数据源 targetItems={targetItems} // 右侧选中项 checkedKeys={checkedKeys} // 左侧选中 - onReset={onReset} // 重置按钮事件 - onOk={onOk} // 确定按钮事件 + onReset={onBoxChoiceReset} // 重置按钮事件 + onOk={onBoxChoiceOk} // 确定按钮事件 onTreeCheck={onTreeCheck} // 树check选中事件 onItemDelete={onItemDelete} // 右侧点击删除事件 /> - - + + onSearch?.(e)} placeholder='请输入盒子名称' {...searchInputProps} /> - + {customImport || ( + <> + } - submitter={{ - searchConfig: { - submitText: '确定', - resetText: '取消', - }, - }} - onFinish={onCreateSubmit} - > - - - { - createFormRef.current?.setFieldValue('boxList', null) - }} >恢复默认 - setBoxChoiceOpen(true)}>范围选择 - + {/* 是否显示操作按钮 */} + {showOptions && ( + <> + + + + {onCreate ? + ( + + ) : ( + + width={'600px'} + open={onCreate ? false : undefined} + formRef={createFormRef} + title="新建组" + modalProps={{ destroyOnClose: true }} + layout='horizontal' + labelCol={{ span: 6 }} + wrapperCol={{ span: 18 }} + trigger={} + submitter={{ + searchConfig: { + submitText: '确定', + resetText: '取消', + }, + }} + onFinish={onCreateSubmit} + > + + + { + createFormRef.current?.setFieldValue('boxList', null) + onBoxChoiceReset() + }} >恢复默认 + setBoxChoiceOpen(true)}>范围选择 + + ) + }} + /> + ) - }} - /> - - - {/* @ts-ignore */} - - - + + + + )} + {extraBtns} = (props) => { ) } -export default BoxGroupPanel +export default BoxPanel diff --git a/packages/biz/src/boxSelectTree/demo/async.tsx b/packages/biz/src/boxSelectTree/demo/async.tsx new file mode 100644 index 0000000..ac573e8 --- /dev/null +++ b/packages/biz/src/boxSelectTree/demo/async.tsx @@ -0,0 +1,82 @@ +import React, { useState } from 'react'; +import { BoxSelectTree } from '@zhst/biz'; +import { boxDataSource } from './mock' + +interface DataNode { + title: string; + key: string; + isLeaf?: boolean; + children?: DataNode[]; +} + +const initTreeData: DataNode[] = [ + { title: '盒子组1', key: '0' }, + { title: '盒子组2', key: '1' }, + { title: '盒子组3', key: '2', isLeaf: true }, +]; + +/** + * 递归更新树结构 + * @param list 原数组列表 + * @param key 当前选中的项 + * @param children 需要插入更新的数据 + * @returns newList + */ +const updateTreeData = (list: DataNode[], key: React.Key, children: DataNode[]): DataNode[] => + list.map((node) => { + if (node.key === key) { + return { + ...node, + children, + }; + } + if (node.children) { + return { + ...node, + children: updateTreeData(node.children, key, children), + }; + } + return node; + }); + +const demo = () => { + const [treeData, setTreeData] = useState(initTreeData); + const [activeKey, setActiveKey] = useState('1') + const [checkedKeys, setCheckedKeys] = useState([]); + + const onLoadData = ({ key, children }: any) => + new Promise((resolve) => { + if (children) { + resolve(); + return; + } + setTimeout(() => { + setTreeData((origin) => + updateTreeData(origin, key, [ + { title: '盒子', key: `${key}-0` }, + { title: '盒子', key: `${key}-1` }, + ]), + ); + resolve(); + }, 1000); + }); + + return ( +
+ onLoadData(_params), + checkedKeys + }} + /> +
+ ); +}; + +export default demo; diff --git a/packages/biz/src/boxSelectTree/demo/basic.tsx b/packages/biz/src/boxSelectTree/demo/basic.tsx index dd2b0dc..8bb399a 100644 --- a/packages/biz/src/boxSelectTree/demo/basic.tsx +++ b/packages/biz/src/boxSelectTree/demo/basic.tsx @@ -2,10 +2,12 @@ import React, { useState } from 'react'; import { BoxSelectTree } from '@zhst/biz'; import { treeData, boxDataSource } from './mock' import { Select, TreeProps, Modal, Checkbox } from 'antd'; +import { BOX_TYPE_LIST } from '../../utils/constants'; const { Option } = Select const demo = () => { + const [activeKey, setActiveKey] = useState('1') const [searchType, setSearchType] = useState('1') const [searchVal, setSearchVal] = useState('') const [checkedKeys, setCheckedKeys] = useState([]); @@ -32,18 +34,25 @@ const demo = () => { } return ( -
+
{contextHolder} console.log('搜索', e)} - onCreateSubmit={async () => { return true }} + onCreateSubmit={async (_data) => { + console.log('新建盒子', _data) + return true + }} onItemCheck={onTreeCheck} onItemSelect={e => console.log('onItemSelect', e)} - onTabChange={e => console.log('tabChange', e)} - onBoxDelete={data => console.log('盒子删除', data)} + onTabChange={val => setActiveKey(val)} onBoxBatchDelete={onBoxBatchDelete} + onClockClick={() => console.log('时钟点击事件')} + onImport={() => console.log('导入盒子')} + tabsProps={{ + activeKey, + }} searchInputProps={{ addonBefore: ( ), onChange: e => setSearchVal(e.target.value), value: searchVal }} treeProps={{ - checkedKeys + onItemDelete: data => console.log('删除', data), + onItemSetting: data => console.log('配置事件', data), + onItemRename: (data) =>console.log('重命名', data), + onItemRenameFinish: async (val, data) => console.log('盒子重命名提交(返回boolean,控制弹框显示\隐藏)', val, data), + checkedKeys, }} />
diff --git a/packages/biz/src/boxSelectTree/demo/extraBtns.tsx b/packages/biz/src/boxSelectTree/demo/extraBtns.tsx new file mode 100644 index 0000000..d889b8b --- /dev/null +++ b/packages/biz/src/boxSelectTree/demo/extraBtns.tsx @@ -0,0 +1,28 @@ +import React, { useState } from 'react'; +import { BoxSelectTree } from '@zhst/biz'; +import { treeData, boxDataSource } from './mock' +import { Button } from 'antd'; + +const demo = () => { + const [activeKey, setActiveKey] = useState('1') + const [checkedKeys, setCheckedKeys] = useState([]); + + return ( +
+ 自定义按钮} + tabsProps={{ + activeKey, + }} + treeProps={{ + checkedKeys + }} + /> +
+ ); +}; + +export default demo; diff --git a/packages/biz/src/boxSelectTree/demo/mock.tsx b/packages/biz/src/boxSelectTree/demo/mock.tsx index f60888b..d6bbc91 100644 --- a/packages/biz/src/boxSelectTree/demo/mock.tsx +++ b/packages/biz/src/boxSelectTree/demo/mock.tsx @@ -1,6 +1,6 @@ -import { TreeDataNode } from "antd"; +import { TreeData } from "@zhst/biz"; -export const treeData: TreeDataNode[] = [ +export const boxDataSource: TreeData[] = [ { title: '全部盒子', key: '0-0', @@ -12,10 +12,12 @@ export const treeData: TreeDataNode[] = [ { title: '摄像头1', key: '0-0-0-0', + isCamera: true }, { title: '摄像头2', key: '0-0-0-1', + isCamera: true }, ], }, @@ -25,7 +27,8 @@ export const treeData: TreeDataNode[] = [ children: [ { title: '摄像头4', - key: '0-0-1-0' + key: '0-0-1-0', + isCamera: true } ], }, @@ -34,36 +37,18 @@ export const treeData: TreeDataNode[] = [ ]; -export const boxDataSource: TreeDataNode[] = [ +export const treeData: TreeData[] = [ + { key: '0-1-0', title: '分组0-1-0', isLeaf: true, checkable: false }, + { key: '0-1-1', title: '分组0-1-1', isLeaf: true, checkable: false }, + { key: '0-1-2', title: '分组0-1-2', isLeaf: true, checkable: false }, { - key: '0-0', - title: '分组0-0', - isLeaf: false, - checkable: false, - }, - { - key: '0-1', - title: '分组0-1', + key: '0-1-3', + title: '分组0-1-3', isLeaf: false, children: [ - { key: '0-1-0', title: '分组0-1-0', isLeaf: true, checkable: false }, - { key: '0-1-1', title: '分组0-1-1', isLeaf: true, checkable: false }, - { key: '0-1-2', title: '分组0-1-2', isLeaf: true, checkable: false }, - { - key: '0-1-3', - title: '分组0-1-3', - isLeaf: false, - children: [ - { key: '0-1-3-1', title: '分组0-1-3-1', isLeaf: true }, - { key: '0-1-3-2', title: '分组0-1-3-2', isLeaf: true }, - { key: '0-1-3-3', title: '分组0-1-3-3', isLeaf: true }, - ], - }, + { key: '0-1-3-1', title: '分组0-1-3-1', isLeaf: true, isCamera: true }, + { key: '0-1-3-2', title: '分组0-1-3-2', isLeaf: true, isCamera: true }, + { key: '0-1-3-3', title: '分组0-1-3-3', isLeaf: true, isCamera: true }, ], }, - { key: '0-2', title: '分组0-2', isLeaf: false, checkable: false, }, - { key: '0-3', title: '分组0-3', isLeaf: false, checkable: false, }, - { key: '0-4', title: '分组0-4', isLeaf: false, checkable: false, }, - { key: '0-5', title: '分组0-4', isLeaf: false, checkable: false, }, - { key: '0-6', title: '分组0-4', isLeaf: false, checkable: false, }, ]; diff --git a/packages/biz/src/boxSelectTree/demo/noOptions.tsx b/packages/biz/src/boxSelectTree/demo/noOptions.tsx new file mode 100644 index 0000000..a2e34e7 --- /dev/null +++ b/packages/biz/src/boxSelectTree/demo/noOptions.tsx @@ -0,0 +1,61 @@ +import React, { useState } from 'react'; +import { BoxSelectTree } from '@zhst/biz'; +import { Button, Select, TreeProps } from 'antd'; +import { FilterOutlined } from '@ant-design/icons'; +import { BOX_TYPE_LIST } from '../../utils/constants'; +import { treeData, boxDataSource } from './mock' + +const { Option } = Select + +const demo = () => { + const [activeKey, setActiveKey] = useState('1') + const [searchType, setSearchType] = useState('1') + const [searchVal, setSearchVal] = useState('') + const [checkedKeys, setCheckedKeys] = useState([]); + + const onTreeCheck: TreeProps['onCheck'] = (keys: any) => { + setCheckedKeys(keys) + } + + return ( +
+ console.log('搜索', e)} + onItemCheck={onTreeCheck} + onItemSelect={e => console.log('onItemSelect', e)} + onTabChange={val => setActiveKey(val)} + onBoxDelete={data => console.log('盒子删除', data)} + showOptions={false} + tabsProps={{ + activeKey, + }} + customImport={
+ ); +}; + +export default demo; diff --git a/packages/biz/src/boxSelectTree/index.md b/packages/biz/src/boxSelectTree/index.md index aa8ec86..a377225 100644 --- a/packages/biz/src/boxSelectTree/index.md +++ b/packages/biz/src/boxSelectTree/index.md @@ -13,7 +13,11 @@ group: ## 代码演示 基本用法 +自定义其它按钮 +不显示其它按钮 +异步加载数据 +## API | 参数 | 说明 | 类型 | 默认值 | 版本 | | --- | --- | --- | --- | --- | @@ -24,3 +28,11 @@ group: | tabsProps | Tabs组件的Props | antd的Tabs组件 | - | - | | searchInputProps | 搜索框的Props | antd的Input组件 | - | - | | onTabChange | tab切换监听 | function: (e) => void | - | - | +| onBoxDelete | 盒子删除事件 | function: (e) => void | - | - | +| onBoxBatchDelete | 盒子批量删除事件 | function: (e) => void | - | - | +| onCreateSubmit | 新建提交事件 | function: (e) => void | - | - | +| onImport | 监听导入盒子点击事件 | function: () => void | - | - | +| onClockClick | 监听时钟点击事件 | function: () => void | - | - | +| onCreate | 监听创建点击事件 | function: () => void | 如果不传默认用自带的创建事件 | - | +| showOptions | 展示其它功能按钮 | boolean | true | - | + diff --git a/packages/biz/src/boxSelectTree/index.tsx b/packages/biz/src/boxSelectTree/index.tsx index c3e4bd4..8adaf1d 100644 --- a/packages/biz/src/boxSelectTree/index.tsx +++ b/packages/biz/src/boxSelectTree/index.tsx @@ -1,3 +1,5 @@ import BoxSelectTree from './boxSelectTree'; +export type { BoxSelectTreeProps } from './boxSelectTree' + export default BoxSelectTree; diff --git a/packages/biz/src/index.tsx b/packages/biz/src/index.tsx index 092c165..2685d54 100644 --- a/packages/biz/src/index.tsx +++ b/packages/biz/src/index.tsx @@ -1,5 +1,18 @@ export { default as BigImageModal } from './BigImageModal' +export type { BigImageModalProps } from './BigImageModal' export { default as BoxSelectTree } from './boxSelectTree' +export type { BoxSelectTreeProps } from './boxSelectTree' export { default as Tree } from './tree' +export type { BoxTreeProps, TreeData } from './tree' export { default as TreeTransfer } from './treeTransfer' +export type { TreeTransferProps } from './treeTransfer' export { default as TreeTransferModal } from './treeTransferModal' +export type { TreeTransferModalProps } from './treeTransferModal' +export { default as WarningRecordCard } from './WarningRecordCard' +export type { IRecord, WarningRecordCardProps } from './WarningRecordCard' +export type { ViewLargerImageModalRef, ViewLargerImageModalProps } from './ViewLargerImageModal' +export { default as ViewLargerImageModal, useViewLargerImageModal } from './ViewLargerImageModal' +export type { VideoPlayerCardProps } from './VideoPlayerCard' +export { default as VideoPlayerCard } from './VideoPlayerCard' +export { default as RealTimeMonitor } from './RealTimeMonitor' + diff --git a/packages/biz/src/tree/boxTree.tsx b/packages/biz/src/tree/boxTree.tsx index 425596f..f769199 100644 --- a/packages/biz/src/tree/boxTree.tsx +++ b/packages/biz/src/tree/boxTree.tsx @@ -1,70 +1,122 @@ -import React, { FC } from 'react'; +import React, { FC, useState } from 'react'; import { Tree, Badge, TreeDataNode, Space, TreeProps } from 'antd'; +import theme from 'antd/es/theme' import { CloseOutlined, EditOutlined, SettingOutlined } from '@ant-design/icons' import { ModalForm, ProFormText } from '@ant-design/pro-components'; import './index.less' const componentName = 'zhst-biz-tree' +const { useToken } = theme export interface BoxTreeProps extends TreeProps { data: TreeDataNode[] treeCheckable?: boolean showItemOption?: boolean - treeProps?: TreeProps + customOptions?: any; onItemCheck?: TreeProps['onCheck'] onItemSelect?: TreeProps['onSelect'] onItemSetting?: (_data: any) => void onItemDelete?: (_data: any) => void - onRenameFinish?: (_data: any, _nodeData: any) => Promise + onItemRename?: (_nodeData: any) => void + onItemRenameFinish?: (_data: any, _nodeData: any) => Promise } const boxTree: FC = (props) => { - const { onItemSelect, onItemCheck, onItemSetting, onItemDelete, data = [], showItemOption = true, treeCheckable = false, onRenameFinish } = props + const { + onItemSelect, + onItemCheck, + onItemSetting, + onItemDelete, + data = [], + showItemOption = true, + treeCheckable = false, + onItemRename, + onItemRenameFinish, + customOptions + } = props + const { token } = useToken() + const [checkedItem, setCheckedItem] = useState('') + + const cameraStatus = new Map([ + ['0', 'error'], + ['1', 'success'], + ['3', 'processing'], + ['4', 'default'], + ]) return ( { + setCheckedItem(selectedKeys[0]) + onItemSelect?.(selectedKeys, info) + }} onCheck={onItemCheck} treeData={data} titleRender={(_nodeData) => { return (
- {!_nodeData.children && } - {_nodeData.title as any} - {showItemOption && - } - submitter={{ - searchConfig: { - submitText: '确定', - resetText: '取消', - }, - }} - onFinish={async (value) => onRenameFinish?.(value, _nodeData)} - > - - - onItemSetting?.(_nodeData)} /> - onItemDelete?.(_nodeData)} /> - } + {/* @ts-ignore */} + {!_nodeData.children && _nodeData.isCamera && } + + {_nodeData.title as any} + + {showItemOption && ( + + {customOptions || ( + <> + { + e.preventDefault(); + e.stopPropagation(); + onItemRename?.(_nodeData) + }} />} + submitter={{ + searchConfig: { + submitText: '确定', + resetText: '取消', + }, + }} + onFinish={async (value) => onItemRenameFinish?.(value, _nodeData)} + > + + + { + e.preventDefault(); + e.stopPropagation(); + onItemSetting?.(_nodeData)} + } /> + { + e.preventDefault(); + e.stopPropagation(); + onItemDelete?.(_nodeData) + }} /> + + )} + + )}
) }} diff --git a/packages/biz/src/tree/demo/customOptions.tsx b/packages/biz/src/tree/demo/customOptions.tsx new file mode 100644 index 0000000..bcb14fb --- /dev/null +++ b/packages/biz/src/tree/demo/customOptions.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Tree } from '@zhst/biz'; +import { LoadingOutlined, PlayCircleOutlined, SettingOutlined } from '@ant-design/icons'; +import { treeData } from './mock' + +const demo = () => { + return ( +
+ + + + + + )} + /> +
+ ); +}; + +export default demo; diff --git a/packages/biz/src/tree/demo/customTitleRender.tsx b/packages/biz/src/tree/demo/customTitleRender.tsx index 61971a2..95f3cd2 100644 --- a/packages/biz/src/tree/demo/customTitleRender.tsx +++ b/packages/biz/src/tree/demo/customTitleRender.tsx @@ -14,8 +14,11 @@ const demo = () => { diff --git a/packages/biz/src/tree/index.md b/packages/biz/src/tree/index.md index 7a84601..b54b366 100644 --- a/packages/biz/src/tree/index.md +++ b/packages/biz/src/tree/index.md @@ -14,8 +14,15 @@ group: 基本用法 自定义渲染界面 不展示配置项 +自定义配置项 +## API + +**额外参数可以参考 antd - Tree 组件** | 参数 | 说明 | 类型 | 默认值 | 版本 | | --- | --- | --- | --- | --- | | data | 数据源 | Array[] | [] | - | +| titleRender | 子项自定义 | ReactNode、 undefined | - | - | +| showItemOption | 是否显示额外配置功能 | boolean | true | - | +| customOptions | 自定义配置项 | any | - | - | diff --git a/packages/biz/src/tree/index.tsx b/packages/biz/src/tree/index.tsx index fb90026..7f1277a 100644 --- a/packages/biz/src/tree/index.tsx +++ b/packages/biz/src/tree/index.tsx @@ -1,3 +1,16 @@ +import { TreeDataNode } from 'antd'; import BoxTree from './boxTree'; +export interface TreeData extends TreeDataNode { + children?: TreeDataNode['children'] & { + isCamera?: boolean + /** + * 0-失败 1-成功 2-进行中 3-未知 + */ + status?: '0' | '1' | '2' | '3' + }[] +} + +export type { BoxTreeProps } from './boxTree' + export default BoxTree; diff --git a/packages/biz/src/treeTransfer/index.md b/packages/biz/src/treeTransfer/index.md index ba09b9d..678b494 100644 --- a/packages/biz/src/treeTransfer/index.md +++ b/packages/biz/src/treeTransfer/index.md @@ -13,6 +13,8 @@ group: 基本用法 和Modal组合使用 +## API + | 参数 | 说明 | 类型 | 默认值 | 版本 | | --- | --- | --- | --- | --- | | data | 数据源 | Array[] | [] | - | diff --git a/packages/biz/src/treeTransfer/index.tsx b/packages/biz/src/treeTransfer/index.tsx index e912a8e..f4390fb 100644 --- a/packages/biz/src/treeTransfer/index.tsx +++ b/packages/biz/src/treeTransfer/index.tsx @@ -1,3 +1,7 @@ import TreeTransfer from "./TreeTransfer"; +export type { TreeTransferProps } from './TreeTransfer' + +export * from './treeTransferHelper' + export default TreeTransfer diff --git a/packages/biz/src/treeTransferModal/TreeTransferModal.tsx b/packages/biz/src/treeTransferModal/TreeTransferModal.tsx index 565357e..303cd40 100644 --- a/packages/biz/src/treeTransferModal/TreeTransferModal.tsx +++ b/packages/biz/src/treeTransferModal/TreeTransferModal.tsx @@ -1,7 +1,7 @@ import React, { FC, useState } from 'react'; +import { Modal, ModalProps, Radio, RadioGroupProps, Select, SelectProps, TransferProps, TreeDataNode, TreeProps } from 'antd'; import TreeTransfer from '../treeTransfer'; -import { Modal, ModalProps, Radio, RadioGroupProps, TransferProps, TreeDataNode } from 'antd'; -import { TreeProps } from 'antd/lib'; +import { ALL_LIST, BOX_TYPE_LIST } from '../utils/constants'; export interface TreeTransferModalProps { dataSource: TreeDataNode[] @@ -17,7 +17,10 @@ export interface TreeTransferModalProps { open?: boolean onCancel?: ModalProps['onCancel'] onRadioChange?: RadioGroupProps['onChange'] + onSelect?: SelectProps['onSelect'] modalProps?: ModalProps + radioProps?: RadioGroupProps + selectProps?: SelectProps } const TreeTransferModal: FC = (props) => { @@ -31,11 +34,14 @@ const TreeTransferModal: FC = (props) => { onReset, onRadioChange, onTreeCheck, + onSelect, targetItems, modalProps, + radioProps, + selectProps, } = props - const [type, setType] = useState('box') + const [type, setType] = useState('1') return ( = (props) => { {...modalProps} >
- { - setType(e.target.value) - onRadioChange?.(e) - }} - style={{ marginLeft: '24px', padding: '20px 0' }} - value={type} - > - 盒子 - 盒子组 - +
+ { + setType(e.target.value) + onRadioChange?.(e) + }} + style={{ marginLeft: '24px', padding: '20px 0' }} + value={type} + options={BOX_TYPE_LIST} + {...radioProps} + /> +