fix: 新增 tree 组件的监听事件,优化 meta 全选的回调事件监听

This commit is contained in:
江志雄 2024-03-11 18:55:35 +08:00
parent 35b99a3270
commit 762f480f81
45 changed files with 462 additions and 1453 deletions

10
.vscode/launch.json vendored Normal file
View File

@ -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"
}
]
}

View File

@ -1,5 +1,39 @@
# @zhst/biz
## 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

View File

@ -1,8 +1,12 @@
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 { TreeData } 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 { WarningRecordCardProps, IRecord } from './WarningRecordCard';

View File

@ -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]);
});

View File

@ -1,2 +0,0 @@
declare const startChannel: (topic: any, req: any, callback: any) => () => void;
export default startChannel;

View File

@ -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;

View File

@ -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;

View File

@ -1,31 +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;
};
export declare const BOX_TYPE_LIST: {
value: string;
label: string;
}[];
export declare const ALL_LIST: {
value: string;
label: string;
}[];

View File

@ -1,8 +1,12 @@
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 { TreeData } 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 { WarningRecordCardProps, IRecord } from './WarningRecordCard';

View File

@ -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
});

View File

@ -1,2 +0,0 @@
declare const startChannel: (topic: any, req: any, callback: any) => () => void;
export default startChannel;

View File

@ -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;

View File

@ -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;

View File

@ -1,31 +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;
};
export declare const BOX_TYPE_LIST: {
value: string;
label: string;
}[];
export declare const ALL_LIST: {
value: string;
label: string;
}[];

View File

@ -1,6 +1,6 @@
{
"name": "@zhst/biz",
"version": "0.9.1",
"version": "0.9.6",
"description": "业务库",
"keywords": [
"business",

View File

@ -1,24 +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
showOptions?: boolean
customImport?: any
extraBtns?: any
}
const BoxSelectTree: FC<BoxSelectTreeProps> = (props) => {
@ -32,18 +19,17 @@ const BoxSelectTree: FC<BoxSelectTreeProps> = (props) => {
onBoxBatchDelete,
onBoxDelete,
onCreateSubmit,
onClockClick,
onImport,
onCreate,
tabsProps,
searchInputProps,
treeProps,
customImport,
showOptions,
extraBtns,
showOptions = true
} = props
const onChange = (key: string) => {
onTabChange?.(key)
};
const items: TabsProps['items'] = [
{
key: '1',
@ -54,6 +40,7 @@ const BoxSelectTree: FC<BoxSelectTreeProps> = (props) => {
boxDataSource={boxDataSource}
treeProps={treeProps}
data={data}
onCreate={onCreate}
onCreateSubmit={onCreateSubmit}
onBoxBatchDelete={onBoxBatchDelete}
onBoxDelete={onBoxDelete}
@ -63,6 +50,8 @@ const BoxSelectTree: FC<BoxSelectTreeProps> = (props) => {
showOptions={showOptions}
customImport={customImport}
extraBtns={extraBtns}
onClockClick={onClockClick}
onImport={onImport}
/>
)
},
@ -75,6 +64,7 @@ const BoxSelectTree: FC<BoxSelectTreeProps> = (props) => {
searchInputProps={searchInputProps}
treeProps={treeProps}
data={data}
onCreate={onCreate}
onBoxBatchDelete={onBoxBatchDelete}
onCreateSubmit={onCreateSubmit}
onBoxDelete={onBoxDelete}
@ -84,6 +74,8 @@ const BoxSelectTree: FC<BoxSelectTreeProps> = (props) => {
showOptions={showOptions}
customImport={customImport}
extraBtns={extraBtns}
onClockClick={onClockClick}
onImport={onImport}
/>
)
},
@ -94,7 +86,7 @@ const BoxSelectTree: FC<BoxSelectTreeProps> = (props) => {
defaultActiveKey="1"
centered
items={items}
onChange={onChange}
onChange={onTabChange}
tabBarGutter={0}
indicator={{ size: (origin) => origin, align: 'center' }}
{...tabsProps}

View File

@ -3,13 +3,14 @@ import{ Button, Divider, Input, Space, TreeDataNode } from 'antd'
import { ModalForm, ModalFormProps, ProFormInstance, ProFormText } from '@ant-design/pro-components'
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
showOptions?: boolean
treeProps?: TreeProps
treeProps?: Partial<BoxTreeProps>
data: TreeDataNode[]
boxDataSource: TreeDataNode[]
handleImport?: () => void
@ -20,11 +21,14 @@ export interface BoxGroupPanelProps {
onBoxDelete?: (data?: any) => void
onCreateSubmit?: ModalFormProps['onFinish']
onClockClick?: () => void
onImport?: () => void
onBatch?: () => void
onCreate?: () => void
customImport?: any
extraBtns?: any
}
const BoxGroupPanel: FC<BoxGroupPanelProps> = (props) => {
const BoxPanel: FC<BoxPanelProps> = (props) => {
const {
searchInputProps,
showOptions = true,
@ -38,6 +42,9 @@ const BoxGroupPanel: FC<BoxGroupPanelProps> = (props) => {
onBoxBatchDelete,
onBoxDelete,
onClockClick,
onImport,
onBatch,
onCreate,
boxDataSource,
customImport
} = props
@ -116,7 +123,7 @@ const BoxGroupPanel: FC<BoxGroupPanelProps> = (props) => {
<Input size='middle' onChange={(e) => onSearch?.(e)} placeholder='请输入盒子名称' {...searchInputProps} />
{customImport || (
<>
<Button type="text" onClick={() => handleCheckable()} icon={!isTreeCheckable ? <DiffOutlined /> : <SwitcherOutlined />} />
<Button type="text" onClick={() => onBatch?.() || handleCheckable()} icon={isTreeCheckable ? <SwitcherOutlined /> : <DiffOutlined />} />
<Button type="text" onClick={() => onClockClick?.()} icon={<ClockCircleOutlined />} />
</>
)}
@ -125,58 +132,65 @@ const BoxGroupPanel: FC<BoxGroupPanelProps> = (props) => {
{showOptions && (
<>
<Space align='center'>
<Button type='text' style={{ padding: '4px 8px' }} icon={<ImportOutlined />} ></Button>
<Button type='text' style={{ padding: '4px 8px' }} onClick={() => onImport?.()} icon={<ImportOutlined />} ></Button>
<Divider type="vertical" style={{ margin: '8px 0' }} />
<ModalForm<{
name: string
boxList?: any[]
}>
width={'600px'}
formRef={createFormRef}
title="新建组"
modalProps={{ destroyOnClose: true }}
layout='horizontal'
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
trigger={<Button type='text' style={{ padding: '4px 8px' }} icon={<FolderAddOutlined />} ></Button>}
submitter={{
searchConfig: {
submitText: '确定',
resetText: '取消',
},
}}
onFinish={onCreateSubmit}
>
<ProFormText
rules={[
{
required: true,
},
]}
width="md"
name="name"
label="盒子组名称"
placeholder="请输入盒子名称"
/>
<ProFormText
width="md"
name="boxList"
label="盒子选择"
fieldProps={{
readOnly: true,
value: `已选择${createFormRef.current?.getFieldValue('boxList')?.length || 0}个盒子`,
suffix: (
<Space>
<a onClick={() => {
createFormRef.current?.setFieldValue('boxList', null)
onBoxChoiceReset()
}} ></a>
<a onClick={() => setBoxChoiceOpen(true)}></a>
</Space>
)
}}
/>
</ModalForm>
{onCreate ?
(
<Button onClick={onCreate} type='text' style={{ padding: '4px 8px' }} icon={<FolderAddOutlined />} ></Button>
) : (
<ModalForm<{
name: string
boxList?: any[]
}>
width={'600px'}
open={onCreate ? false : undefined}
formRef={createFormRef}
title="新建组"
modalProps={{ destroyOnClose: true }}
layout='horizontal'
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
trigger={<Button type='text' style={{ padding: '4px 8px' }} icon={<FolderAddOutlined />} ></Button>}
submitter={{
searchConfig: {
submitText: '确定',
resetText: '取消',
},
}}
onFinish={onCreateSubmit}
>
<ProFormText
rules={[
{
required: true,
},
]}
width="md"
name="name"
label="盒子组名称"
placeholder="请输入盒子名称"
/>
<ProFormText
width="md"
name="boxList"
label="盒子选择"
fieldProps={{
readOnly: true,
value: `已选择${createFormRef.current?.getFieldValue('boxList')?.length || 0}个盒子`,
suffix: (
<Space>
<a onClick={() => {
createFormRef.current?.setFieldValue('boxList', null)
onBoxChoiceReset()
}} ></a>
<a onClick={() => setBoxChoiceOpen(true)}></a>
</Space>
)
}}
/>
</ModalForm>
)
}
<Divider type="vertical" style={{ margin: '8px 0' }} />
{/* @ts-ignore */}
<Button danger type='text' style={{ padding: '4px 8px' }} icon={<CloseCircleOutlined />} disabled={treeProps?.checkedKeys?.length <= 0} onClick={onBoxBatchDelete} ></Button>
@ -198,4 +212,4 @@ const BoxGroupPanel: FC<BoxGroupPanelProps> = (props) => {
)
}
export default BoxGroupPanel
export default BoxPanel

View File

@ -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<string[]>([]);
const onLoadData = ({ key, children }: any) =>
new Promise<void>((resolve) => {
if (children) {
resolve();
return;
}
setTimeout(() => {
setTreeData((origin) =>
updateTreeData(origin, key, [
{ title: '盒子', key: `${key}-0` },
{ title: '盒子', key: `${key}-1` },
]),
);
resolve();
}, 1000);
});
return (
<div style={{ border: '1px solid #ccc', width: '340px', minHeight: '900px' }}>
<BoxSelectTree
data={treeData}
boxDataSource={boxDataSource}
showOptions={false}
tabsProps={{
activeKey,
}}
treeProps={{
loadData: (_params) => onLoadData(_params),
checkedKeys
}}
/>
</div>
);
};
export default demo;

View File

@ -47,8 +47,9 @@ const demo = () => {
onItemCheck={onTreeCheck}
onItemSelect={e => console.log('onItemSelect', e)}
onTabChange={val => setActiveKey(val)}
onBoxDelete={data => console.log('盒子删除', data)}
onBoxBatchDelete={onBoxBatchDelete}
onClockClick={() => console.log('时钟点击事件')}
onImport={() => console.log('导入盒子')}
tabsProps={{
activeKey,
}}
@ -71,7 +72,11 @@ const demo = () => {
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,
}}
/>
</div>

View File

@ -2,7 +2,7 @@
category: Components
title: BoxSelectTree 盒子树
demo:
cols: 4
cols: 2
group:
title: 进阶组件
order: 2
@ -15,6 +15,7 @@ group:
<code src="./demo/basic.tsx">基本用法</code>
<code src="./demo/extraBtns.tsx">自定义其它按钮</code>
<code src="./demo/noOptions.tsx">不显示其它按钮</code>
<code src="./demo/async.tsx">异步加载数据</code>
## API
@ -30,5 +31,8 @@ group:
| onBoxDelete | 盒子删除事件 | function: (e) => void | - | - |
| onBoxBatchDelete | 盒子批量删除事件 | function: (e) => void | - | - |
| onCreateSubmit | 新建提交事件 | function: (e) => void | - | - |
| onImport | 监听导入盒子点击事件 | function: () => void | - | - |
| onClockClick | 监听时钟点击事件 | function: () => void | - | - |
| onCreate | 监听创建点击事件 | function: () => void | 如果不传默认用自带的创建事件 | - |
| showOptions | 展示其它功能按钮 | boolean | true | - |

View File

@ -1,3 +1,5 @@
import BoxSelectTree from './boxSelectTree';
export type { BoxSelectTreeProps } from './boxSelectTree'
export default BoxSelectTree;

View File

@ -1,8 +1,12 @@
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 { TreeData } 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 { WarningRecordCardProps, IRecord } from './WarningRecordCard'

View File

@ -17,7 +17,8 @@ export interface BoxTreeProps extends TreeProps {
onItemSelect?: TreeProps['onSelect']
onItemSetting?: (_data: any) => void
onItemDelete?: (_data: any) => void
onRenameFinish?: (_data: any, _nodeData: any) => Promise<any>
onItemRename?: (_nodeData: any) => void
onItemRenameFinish?: (_data: any, _nodeData: any) => Promise<any>
}
const boxTree: FC<BoxTreeProps> = (props) => {
@ -29,15 +30,18 @@ const boxTree: FC<BoxTreeProps> = (props) => {
data = [],
showItemOption = true,
treeCheckable = false,
onRenameFinish,
onItemRename,
onItemRenameFinish,
customOptions
} = props
const { token } = useToken()
const [checkedItem, setCheckedItem] = useState<React.Key>('')
const cameraStatus = new Map([
['0', 'success'],
['1', 'error']
['0', 'error'],
['1', 'success'],
['3', 'processing'],
['4', 'default'],
])
return (
@ -54,7 +58,7 @@ const boxTree: FC<BoxTreeProps> = (props) => {
return (
<div className={`${componentName}-item-render`}>
{/* @ts-ignore */}
{!_nodeData.children && _nodeData.isCamera && <Badge style={{ marginRight: '6px' }} status={cameraStatus.get('0')} />}
{!_nodeData.children && _nodeData.isCamera && <Badge style={{ marginRight: '6px' }} status={cameraStatus.get(_nodeData.status || '4')} />}
<span
// @ts-ignore
style={(checkedItem === _nodeData.key) && _nodeData.isCamera ? {
@ -74,14 +78,18 @@ const boxTree: FC<BoxTreeProps> = (props) => {
layout='horizontal'
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
trigger={<EditOutlined />}
trigger={<EditOutlined onClick={(e) => {
e.preventDefault();
e.stopPropagation();
onItemRename?.(_nodeData)
}} />}
submitter={{
searchConfig: {
submitText: '确定',
resetText: '取消',
},
}}
onFinish={async (value) => onRenameFinish?.(value, _nodeData)}
onFinish={async (value) => onItemRenameFinish?.(value, _nodeData)}
>
<ProFormText
rules={[
@ -95,8 +103,16 @@ const boxTree: FC<BoxTreeProps> = (props) => {
placeholder="请输入盒子名称"
/>
</ModalForm>
<SettingOutlined onClick={() => onItemSetting?.(_nodeData)} />
<CloseOutlined onClick={() => onItemDelete?.(_nodeData)} />
<SettingOutlined onClick={(e) => {
e.preventDefault();
e.stopPropagation();
onItemSetting?.(_nodeData)}
} />
<CloseOutlined onClick={(e) => {
e.preventDefault();
e.stopPropagation();
onItemDelete?.(_nodeData)
}} />
</>
)}
</Space>

View File

@ -4,7 +4,13 @@ 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;

View File

@ -1,3 +1,7 @@
import TreeTransfer from "./TreeTransfer";
export type { TreeTransferProps } from './TreeTransfer'
export * from './treeTransferHelper'
export default TreeTransfer

View File

@ -1,3 +1,5 @@
import TreeTransferModal from './TreeTransferModal'
export type { TreeTransferModalProps } from './TreeTransferModal'
export default TreeTransferModal

View File

@ -1,99 +0,0 @@
import { useMemo } from 'react';
import { throttle as loadshThrottle, noop } from '@zhst/func';
import { useDeepEffect, useLatest } from '@zhst/hooks';
import ws from './ws';
const getSelf = (v: any) => v;
export const 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', // 监听视频分组状态变化,列表变化也通知
};
type ApiKeys = keyof typeof SocketApi;
export default (
topic: ApiKeys,
iterator: any = noop,
opt?: {
req?: { [key: string]: any };
throttle?: number;
parseData?: boolean;
beforeLoopTmp?: Function;
shouldBreak: boolean;
forceRefresh: any;
close?: boolean;
}
) => {
const {
req = {},
throttle = 0,
beforeLoopTmp = getSelf,
shouldBreak = false,
forceRefresh,
close,
} = opt || {};
// 带上token
const reqstring = useMemo(() => {
const newReq = {
...req,
extraHeaders: {
authorization: localStorage.getItem('USER-TOKEN'),
},
};
return JSON.stringify(newReq);
}, [req]);
const latestIterator = useLatest(iterator);
useDeepEffect(() => {
if (close) {
return;
}
//控制socket 请求发送
if (shouldBreak) {
return;
}
//去抖动
let tmpData: any = [];
const throttleUpdate = loadshThrottle(() => {
if (tmpData.length == 0) {
return;
}
const _tmpData = beforeLoopTmp(tmpData);
latestIterator.current(_tmpData); //加了throttle 数据就变成数组
tmpData = [];
}, throttle);
const unSubscribe = ws.subscribe(SocketApi[topic], reqstring, (socketData: any) => {
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]);
};

View File

@ -1,23 +0,0 @@
//@ts-nocheck
import channel from './ws';
const startChannel = (topic, req, callback) => {
// 带上token
let reqstring = JSON.stringify({
...req,
extraHeaders: {
authorization: localStorage.getItem('USER-TOKEN'),
},
});
let unSubscribe = channel.subscribe(topic, reqstring, (socketData) => {
let shouldStop = callback(socketData);
if (shouldStop) {
unSubscribe?.();
}
});
return unSubscribe;
};
export default startChannel;

View File

@ -1,222 +0,0 @@
// @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';
const EMITSTATE = {
NOT_CONNECT: 0,
WAITING: 1,
CONNECT: 2,
};
const initRetryTime = 0;
const intervalTime = 5 * 1000; //下次重试增加时间
const maxIntervalTime = 1 * 60 * 60 * 1000; //最大重试时间1小时
class Channel {
/**
* io
*/
ioIns;
/**
*
*/
listeners = [
// {
// topic: "",
// req: "",
// suInfo: {},
// hasEmit: false,//是否已经订阅
// lastRetryInterval: 0,
// handles: {
// }
// }
];
/**
* /
*/
subscribeListenerId = [];
unSubscribeListenerId = [];
init = () => {
const ioIns = (this.ioIns = io(SOCKET_HOST, {
reconnection: true,
transports: ['websocket'],
forceNew: true,
}));
ioIns.on('connect', (...arg: any) => {
console.debug('connect', arg);
this.ioIns = ioIns;
this.listeners.forEach((v) => {
this.doEmit(v['topic'], v['req'], v['id']);
});
});
ioIns.on('event', (...arg: any) => {
console.debug('event', arg);
});
ioIns.on('disconnect', (...arg: any) => {
console.debug('disconnect', arg);
this.subscribeListenerId = [];
this.unSubscribeListenerId = [];
});
ioIns.on('reconnect', (...arg: any) => {
console.debug('reconnect', arg);
this.listeners.forEach((v) => {
v['hasEmit'] = EMITSTATE.NOT_CONNECT;
this.doEmit(v['topic'], v['req'], v['id']);
});
});
};
retry = (listener: { [x: string]: any; lastRetryInterval: number | undefined; intervalId: NodeJS.Timeout; } | undefined) => {
//重试逻辑
const intervalId = setTimeout(() => {
const hasExit = this.listeners.find(
(v) => v['topic'] === 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;
};
doEmit = (topic, req, listenerId) => {
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;
this.ioIns?.emit?.(topic, req, (data) => {
console.info('emit', topic, req, data);
const 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
const currentTopicIndex = this.listeners.findIndex(
(v) => v['topic'] === topic && v['req'] === req && v['id'] === listenerId
);
if (currentTopicIndex == -1) {
// 不存在说明listener取消了 直接反订阅
this.ioIns.emit('UnSubscribe', JSON.stringify(suInfo), (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.ioIns?.on?.(suInfo['SubscribeID'], (data) => {
console.info('on', suInfo['SubscribeID'], data);
try {
const socketData = JSON.parse(data);
if (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 {
//后面观察 为什么delete后在foreach
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 = uuidv4();
const listenerId = uuidv4();
const listener = this.listeners.find((v) => 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: {
[`${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));
}
}
}
}
//单例
const channelIns = new Channel();
//暴露实例 调试用
window.__channel__ = channelIns;
export default channelIns;

View File

@ -1,5 +1,13 @@
# @zhst/utils
## 0.7.4
### Patch Changes
- 新增 tree 组件的监听事件,优化 meta 全选的回调事件监听
- Updated dependencies
- @zhst/request@0.8.3
## 0.7.3
### Patch Changes

View File

@ -1,6 +1,6 @@
{
"name": "@zhst/func",
"version": "0.7.3",
"version": "0.7.4",
"description": "函数合集",
"keywords": [
"hooks"

View File

@ -240,128 +240,3 @@ export const getRotateImg = (image: HTMLImageElement, rotate: number) => {
commonCanvas.parentNode?.removeChild(commonCanvas);
return file;
};
/**
*
* @param originData
* @returns
*/
export const getOdRect = (originData: IOdRectOrigin) => {
let data = get(originData, 'objects', [])
.filter((v: any) => !isNull(get(v, 'infoOnSource.bboxInFrame.bboxRatio')))
.map((v: any, index: any) => {
// objectId==0 特征没有提取到过滤1掉
const rect = get(v, 'infoOnSource.bboxInFrame.bboxRatio');
const extendBox = get(v, 'infoOnSource.bboxInFrame.extendBoxRatio');
const frameTimestamp = get(v, 'timestamp'); //时间戳创建档案的时候需要
const qualityScore = get(v, 'qualityScore');
const algorithmVersion =
get(v, 'objectType') === 'OBJECT_TYPE_PEDESTRAIN'
? 'VERSION_REID_HEAD_ATTR'
: get(v, 'objectType') === 'OBJECT_TYPE_FACE'
? 'VERSION_FACE'
: 'VERSION_REID_HEAD_ATTR';
const featureData = get(v, 'feature', []).filter(
(v: any) => v.type === 'FEATURE_TYPE_BYTE'
);
const objectRectIndex = algorithmVersion === 'VERSION_FACE' ? 0 : 1;
const objectType = get(v, 'objectType');
const objectId = get(v, 'objectIndex.objectId');
const sourceObjectId = get(v, 'sourceObjectId');
return {
x: rect.x,
y: rect.y,
w: rect.w,
h: rect.h,
// faceCorrectImage: faceCorrectImage,
id: index,
qualityScore: qualityScore,
algorithmVersion: algorithmVersion,
featureData: get(featureData, '0.featureByte'),
objectRectIndex: objectRectIndex,
objectType: objectType,
objectId: objectId,
frameTimestamp: frameTimestamp,
sourceObjectId: sourceObjectId,
extendBox: extendBox,
};
});
if (data.length > 0) {
data = data.filter((v: { objectId: string; }) => v.objectId !== '0');
} else {
throw new Error('empty');
}
return data;
};
//档案库od
export const getOdRectV2 = (originData: { odv2Result: any[]; }) => {
const resp = originData.odv2Result[0];
const subObjects: { x: any; y: any; w: any; h: any; id: any; qualityScore: any; algorithmVersion: any; featrueData: any; objectRectIndex: number; objectType: any; objectId: any; }[] = []; //形体
const data = get(resp, 'objects', [])
.filter((v: any) => !isNull(get(v, 'subObjects[0].infoOnSource.bboxInFrame.bboxRatio')))
.map((v: any, index: any) => {
const rect = get(v, 'infoOnSource.bboxInFrame.bboxRatio');
const qualityScore = get(v, 'qualityScore');
const algorithmVersion = get(v, 'objectType');
const featrueData = get(v, 'feature', []).filter(
(v: { name: string; }) => v.name === 'feature-body' || v.name === 'feature-face'
);
const objectRectIndex = algorithmVersion === 'OBJECT_TYPE_FACE' ? 0 : 1;
const objectType = get(v, 'objectType');
const objectId = get(v, 'objectIndex.objectId');
//如果存在subObjects的数组不为null表示形体里面带人脸人脸的od框也要显示出来
if (get(v, 'subObjects', []).length) {
get(v, 'subObjects', []).forEach((e: any) => {
const rect = get(e, 'infoOnSource.bboxInFrame.bboxRatio');
const qualityScore = get(e, 'qualityScore');
const algorithmVersion = get(e, 'objectType');
const featrueData = get(e, 'feature', []).filter(
(v: { name: string; }) => v.name === 'feature-body' || v.name === 'feature-face'
);
const objectRectIndex = algorithmVersion === 'OBJECT_TYPE_FACE' ? 0 : 1;
const objectType = get(e, 'objectType');
const objectId = get(e, 'objectIndex.objectId');
subObjects.push({
x: rect.x,
y: rect.y,
w: rect.w,
h: rect.h,
id: index,
qualityScore: qualityScore,
algorithmVersion: algorithmVersion,
featrueData: featrueData.length ? featrueData[0].featureByte : '',
objectRectIndex: objectRectIndex,
objectType: objectType,
objectId,
});
});
}
return {
x: rect.x,
y: rect.y,
w: rect.w,
h: rect.h,
id: index,
qualityScore: qualityScore,
algorithmVersion: algorithmVersion,
featrueData: featrueData[0].featureByte,
objectRectIndex: objectRectIndex,
objectType: objectType,
objectId: objectId,
};
});
const brr = data.concat(subObjects).map((v: { id: any; }, vs: any) => {
if (String(v.id)) {
v.id = vs;
}
return v;
});
if (brr.length > 0) {
console.log(brr, 'data111');
} else {
throw new Error('empty');
}
console.log(brr);
return brr;
};

View File

@ -1,5 +1,13 @@
# @zhst/hooks
## 0.8.3
### Patch Changes
- 新增 tree 组件的监听事件,优化 meta 全选的回调事件监听
- Updated dependencies
- @zhst/func@0.7.4
## 0.8.2
### Patch Changes

View File

@ -1,6 +1,6 @@
{
"name": "@zhst/hooks",
"version": "0.8.2",
"version": "0.8.3",
"description": "hooks合集",
"keywords": [
"hooks"

View File

@ -1,5 +1,15 @@
# @zhst/utils
## 0.8.4
### Patch Changes
- 新增 tree 组件的监听事件,优化 meta 全选的回调事件监听
- Updated dependencies
- @zhst/hooks@0.8.3
- @zhst/func@0.7.4
- @zhst/meta@0.8.4
## 0.8.3
### Patch Changes

View File

@ -1,6 +1,6 @@
{
"name": "@zhst/meta",
"version": "0.8.3",
"version": "0.8.4",
"description": "原子组件",
"keywords": [
"meta",

View File

@ -7,7 +7,6 @@ import {
isNull,
generateImg,
dataURLToBlob,
getOdRect,
getExtendRect,
getTransformRect,
getRotateImg,
@ -17,7 +16,7 @@ import {
} from '@zhst/func';
import Align from 'rc-align';
import { Button, Empty } from '..';
import { type Rect, type IScreenshotButtonProp, type AlignType, type IOdRectOrigin } from '@zhst/types'
import { type Rect, type IScreenshotButtonProp, type AlignType } from '@zhst/types'
import Icon from '../iconfont';
import {
Cropper,
@ -30,10 +29,10 @@ import {
import BtnGroup from './components/BtnGroup';
import './index.less'
import { defaultAlignOption, CROP_TYPE } from '../utils/constants'
import { getOdRect, IOdObject } from './bigImagePreviewHelper'
const componentName = `zhst-image__img-view`;
export interface ViewOption {
/* 图片url */
image?: string | HTMLImageElement;
@ -67,7 +66,7 @@ export interface ImgViewProps extends React.HTMLAttributes<HTMLElement> {
attachImg?: Array<{ label: string; url: string }>; // 缩略图列表
odRect?: Rect
score?: number
objects?: IOdRectOrigin[] // 图片人物框选
objects?: IOdObject
}
showAttachImgLabel?: boolean; // 是否显示缩略图
showOpt?: boolean; // 是否显示操作面板
@ -77,6 +76,7 @@ export interface ImgViewProps extends React.HTMLAttributes<HTMLElement> {
screenshotButtonAlign?: AlignType;
screenshotButtonRender?: (screenshotButtonProp: IScreenshotButtonProp) => ReactElement;
hideLeftTopBtn?: boolean;
onRectSelect?: (obj: IOdObject) => void
showScore?: boolean // 是否显示相似度
viewOption?: ViewOption;
}
@ -127,12 +127,12 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
const {
width,
height,
showScore = true,
showScore = false,
data,
showOpt = false,
showAttachImgLabel = true,
screenshotButtonAlign = defaultAlignOption,
screenshotButtonRender = () => <div style={{ color: '#fff' }}>DOM</div>,
screenshotButtonRender = () => <div style={{ color: '#fff', width: '80px', top: 0 }}>DOM</div>,
hideLeftTopBtn = true,
viewOption = {}
} = props;
@ -144,18 +144,13 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
objects = [],
} = data
const imgContainerRef = React.useRef(null);
const [isReady, setIsReady] = useState(false);
const init = useCallback(($container: null) => {
imgContainerRef.current = $container;
setIsReady(true);
}, []);
// ============================= viewer =========================
const imgInsRef = useRef<any>(null);
const [isImgReady, setIsImgReady] = useState(false);
useEffect(() => {
if (!isReady || !imgContainerRef?.current) return;
if (!imgContainerRef?.current) return;
const handleReady = addEventListenerWrapper(imgContainerRef.current, EVENT_VIEWER_READY, () => {
setIsImgReady(true);
});
@ -176,7 +171,7 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
imgInsRef?.current?.destroy?.();
imgInsRef.current = null;
};
}, [isReady, imageKey]);
}, [imageKey]);
// ============================= viewer操作按钮 =========================
const handleOptClick = (v: string) => {
@ -227,7 +222,8 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
};
}, [isImgReady, showCrop, cropType, imageKey]);
const initData = (_objects: IOdRectOrigin[]) => {
// 初始化页面的绘制矩形
const initData = (_objects: IOdObject | never[]) => {
const imgIns = imgInsRef.current;
const _odRect = odRect
//清理crop
@ -301,12 +297,15 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
handlerCropEndRef.current = addEventListenerWrapper(imgContainerRef.current, EVENT_CROP_END, (event: { detail: any; }) => {
const data = event.detail;
setSelectAlgorithmVersion(null);
setCropRect({
const _rect = {
x: data.left,
y: data.top,
w: data.width,
h: data.height,
});
}
setCropRect(_rect);
const p = getCropInfo({ type: cropType, rect: _rect })
console.log('p', p)
alignRef?.current?.forceAlign?.();
});
cropInsRef.current = new Cropper(imgContainerRef.current, {
@ -317,11 +316,10 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
}
// 获取框选的截图框信息
const latestCropType = useLatest(cropType);
const latestCropRect = useLatest(cropRect);
const getCropInfo = async (cb: (data: any) => void) => {
const cropType = latestCropType.current;
const cropRect = latestCropRect.current;
const getCropInfo = async (opt: { type: string; rect: Rect }) => {
const { type, rect } = opt
const cropType = type;
const cropRect = rect;
const imgIns = imgInsRef.current;
const transform = imgIns.targetTransform;
let newImgKey = imageKey;
@ -398,8 +396,15 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
rectList[index] = newRect;
})
);
cb?.({ rectList, extendRectList, selectIndex, imgKey: newImgKey })
return { rectList, extendRectList, selectIndex, imgKey: newImgKey };
let data = {
rectList,
extendRectList,
selectIndex,
imgKey: newImgKey
}
return data;
};
// 操作界面判断
@ -421,22 +426,12 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
const [selectAttachImgIndex, setSelectAttachImgIndex] = useState(0);
const [isZoomin, setIsZoomin] = useState(false);
/**
*
* @param diff
*/
const handleChangeIndex = (cb?: () => void) => {
if (!imageKey) return
cb?.()
}
// ============================== Ref ===============================
useImperativeHandle(ref, () => ({
imgInsRef,
setShowCrop,
initData,
getCropInfo,
handleChangeIndex
}));
return (
@ -449,7 +444,7 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
`${componentName}-main`,
cropType === CROP_TYPE['AUTO'] && `${componentName}-main--cursor`
)}
ref={init}
ref={imgContainerRef}
/>
{/* 图片操作 */}
{!hideLeftTopBtn && (
@ -562,7 +557,7 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
/>
</div>
)}
{showScore && <div
{(showScore || score) && <div
style={{ bottom: 20 }}
className={classNames(`${componentName}__face-score`)}
>

View File

@ -0,0 +1,58 @@
import { get, isNull } from "@zhst/func";
import { ObjectType, Rect } from "@zhst/types";
export interface IOdObject {
objects: {
bboxRatio: Rect
timestamp?: string
qualityScore?: string
extendBoxRatio?: any
objectType?: ObjectType
objectIndex?: {
objectId: string
}
sourceObjectId?: string
}[]
}
/**
*
* @param originData
* @returns
*/
export const getOdRect = (originData: IOdObject) => {
let data = get(originData, 'objects', [])
.filter((v: any) => !isNull(get(v, 'bboxRatio')) || get(v, 'objectIndex.objectId') !== '0' )
.map((v: any, index: any) => {
const rect = get(v, 'bboxRatio');
const extendBox = get(v, 'extendBoxRatio');
const frameTimestamp = get(v, 'timestamp'); //时间戳创建档案的时候需要
const qualityScore = get(v, 'qualityScore');
const algorithmVersion =
get(v, 'objectType') === 'OBJECT_TYPE_PEDESTRAIN'
? 'VERSION_REID_HEAD_ATTR'
: get(v, 'objectType') === 'OBJECT_TYPE_FACE'
? 'VERSION_FACE'
: 'VERSION_REID_HEAD_ATTR';
const objectRectIndex = algorithmVersion === 'VERSION_FACE' ? 0 : 1;
const objectType = get(v, 'objectType');
const objectId = get(v, 'objectIndex.objectId');
const sourceObjectId = get(v, 'sourceObjectId');
return {
x: rect.x,
y: rect.y,
w: rect.w,
h: rect.h,
id: index,
qualityScore,
algorithmVersion,
objectRectIndex,
objectType,
objectId,
frameTimestamp,
sourceObjectId,
extendBox,
};
});
return data;
};

View File

@ -25,28 +25,20 @@ const props = {
time: '2022-01-01', // 摄像头拍摄时间
objects: [
{
"infoOnSource": {
"bboxInFrame": {
"bboxRatio": {
"x": 0.5519352,
"y": 0.2965385,
"w": 0.05185461,
"h": 0.24698898
},
},
},
"bboxRatio": {
"x": 0.5519352,
"y": 0.2965385,
"w": 0.05185461,
"h": 0.24698898
},
},
{
"infoOnSource": {
"bboxInFrame": {
"bboxRatio": {
"x": 0.58543766,
"y": 0.3203356,
"w": 0.052037954,
"h": 0.2664015
},
},
},
"bboxRatio": {
"x": 0.58543766,
"y": 0.3203356,
"w": 0.052037954,
"h": 0.2664015
},
},
]
}

View File

@ -0,0 +1,43 @@
import React, { useRef } from 'react';
import { Button, Space } from '@zhst/meta'
import { BigImagePreview } from '@zhst/meta'
const props = {
heigth: '500px',
data: {
imageKey: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
odRect:{
"x":0.553125,"y":0.29722223,"w":0.048958335,"h":0.2462963
},
cameraPosition: 'string', // 摄像头位置
time: '2022-01-01', // 摄像头拍摄时间
objects: [
{
"bboxRatio": {
"x": 0.5519352,
"y": 0.2965385,
"w": 0.05185461,
"h": 0.24698898
},
},
]
},
onRectSelect: data => console.log('data', data)
}
export default () => {
const imgRef = useRef(null)
return (
<Space size={[8, 16]} direction="vertical">
<BigImagePreview {...props} ref={imgRef} />
<Space>
<Button type="primary" onClick={() => imgRef.current?.setShowCrop(true)}></Button>
<Button onClick={() => imgRef.current?.handleChangeIndex(1)}></Button>
<Button onClick={() => imgRef.current?.setShowCrop(false)}></Button>
</Space>
</Space>
)
}

View File

@ -2,6 +2,7 @@
position: relative;
width: calc(100%);
height: 100%;
font-size: 0;
&__face-score {
position: absolute;
@ -62,14 +63,9 @@
height: 202px;
transition: all 200ms;
&--fixed {
}
&--zoomin {
height: 100%;
&--fixed {
}
}
&__tab {

View File

@ -8,6 +8,7 @@ title: BigImagePreview 大图预览组件
# BigImagePreview 大图预览组件
<code src="./demo/base.tsx">基本</code>
<code src="./demo/noAttach.tsx">不展示小图</code>
## API

View File

@ -63,7 +63,7 @@ const VideoPlayer = forwardRef<VideoViewRef, VideoViewProps>((props, ref) => {
adjustY: true,
},
},
screenshotButtonRender = () => <div style={{ color: '#fff' }}>DOM</div>,
screenshotButtonRender = () => <div style={{ color: '#fff', width: '80px', top: 0 }}>DOM</div>,
onCropChange,
defautlNormalizationRect: defaultNormalizationRect,
} = props;

View File

@ -1,5 +1,11 @@
# @zhst/request
## 0.8.3
### Patch Changes
- 新增 tree 组件的监听事件,优化 meta 全选的回调事件监听
## 0.8.2
### Patch Changes

View File

@ -1,6 +1,6 @@
{
"name": "@zhst/request",
"version": "0.8.2",
"version": "0.8.3",
"description": "请求库",
"keywords": [
"request",