Merge branch 'develop' into 'master'
Develop See merge request web-project/zhst-lambo!6
This commit is contained in:
commit
b42be0d8b1
21
.dumirc.ts
21
.dumirc.ts
@ -1,8 +1,6 @@
|
|||||||
import { defineConfig } from 'dumi';
|
import { defineConfig } from 'dumi';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
console.log(path.join(__dirname, 'packages/hooks/src'));
|
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
logo: '/logo.jpg',
|
logo: '/logo.jpg',
|
||||||
favicons: ['/logo.jpg'],
|
favicons: ['/logo.jpg'],
|
||||||
@ -11,6 +9,15 @@ export default defineConfig({
|
|||||||
socialLinks: {
|
socialLinks: {
|
||||||
gitlab: 'http://10.0.0.88/web-project/zhst-Lambo',
|
gitlab: 'http://10.0.0.88/web-project/zhst-Lambo',
|
||||||
},
|
},
|
||||||
|
nav: {
|
||||||
|
mode: 'append',
|
||||||
|
value: [
|
||||||
|
{
|
||||||
|
title: '智能柜物料库→',
|
||||||
|
link: 'http://10.0.0.222:30098',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
alias: {
|
alias: {
|
||||||
'@zhst/hooks': path.join(__dirname, 'packages/hooks/src'),
|
'@zhst/hooks': path.join(__dirname, 'packages/hooks/src'),
|
||||||
@ -35,14 +42,4 @@ export default defineConfig({
|
|||||||
srcDir: ['packages', 'src'],
|
srcDir: ['packages', 'src'],
|
||||||
peerDeps: true,
|
peerDeps: true,
|
||||||
},
|
},
|
||||||
extraBabelPlugins: [
|
|
||||||
[
|
|
||||||
'import',
|
|
||||||
{
|
|
||||||
libraryName: 'antd',
|
|
||||||
libraryDirectory: 'es',
|
|
||||||
style: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
10
.fatherrc.ts
10
.fatherrc.ts
@ -2,14 +2,4 @@ import { defineConfig } from 'father';
|
|||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// more father config: https://github.com/umijs/father/blob/master/docs/config.md
|
// more father config: https://github.com/umijs/father/blob/master/docs/config.md
|
||||||
extraBabelPlugins: [
|
|
||||||
[
|
|
||||||
'import',
|
|
||||||
{
|
|
||||||
libraryName: 'antd',
|
|
||||||
libraryDirectory: 'es',
|
|
||||||
style: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
10
.vscode/launch.json
vendored
Normal file
10
.vscode/launch.json
vendored
Normal 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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -58,7 +58,6 @@
|
|||||||
"@types/react": "^18.0.0",
|
"@types/react": "^18.0.0",
|
||||||
"@types/react-dom": "^18.0.0",
|
"@types/react-dom": "^18.0.0",
|
||||||
"@umijs/lint": "^4.0.0",
|
"@umijs/lint": "^4.0.0",
|
||||||
"babel-plugin-import": "^1.13.8",
|
|
||||||
"dumi": "^2.2.13",
|
"dumi": "^2.2.13",
|
||||||
"eslint": "^8.23.0",
|
"eslint": "^8.23.0",
|
||||||
"father": "^4.1.0",
|
"father": "^4.1.0",
|
||||||
|
@ -1,5 +1,115 @@
|
|||||||
# @zhst/biz
|
# @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
|
## 0.6.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
12
packages/biz/es/index.d.ts
vendored
12
packages/biz/es/index.d.ts
vendored
@ -1,5 +1,17 @@
|
|||||||
export { default as BigImageModal } from './BigImageModal';
|
export { default as BigImageModal } from './BigImageModal';
|
||||||
|
export type { BigImageModalProps } from './BigImageModal';
|
||||||
export { default as BoxSelectTree } from './boxSelectTree';
|
export { default as BoxSelectTree } from './boxSelectTree';
|
||||||
|
export type { BoxSelectTreeProps } from './boxSelectTree';
|
||||||
export { default as Tree } from './tree';
|
export { default as Tree } from './tree';
|
||||||
|
export type { BoxTreeProps, TreeData } from './tree';
|
||||||
export { default as TreeTransfer } from './treeTransfer';
|
export { default as TreeTransfer } from './treeTransfer';
|
||||||
|
export type { TreeTransferProps } from './treeTransfer';
|
||||||
export { default as TreeTransferModal } from './treeTransferModal';
|
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';
|
||||||
|
@ -3,3 +3,7 @@ export { default as BoxSelectTree } from "./boxSelectTree";
|
|||||||
export { default as Tree } from "./tree";
|
export { default as Tree } from "./tree";
|
||||||
export { default as TreeTransfer } from "./treeTransfer";
|
export { default as TreeTransfer } from "./treeTransfer";
|
||||||
export { default as TreeTransferModal } from "./treeTransferModal";
|
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";
|
@ -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]);
|
|
||||||
});
|
|
2
packages/biz/es/useSocket/onceChannel.d.ts
vendored
2
packages/biz/es/useSocket/onceChannel.d.ts
vendored
@ -1,2 +0,0 @@
|
|||||||
declare const startChannel: (topic: any, req: any, callback: any) => () => void;
|
|
||||||
export default startChannel;
|
|
@ -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;
|
|
26
packages/biz/es/useSocket/ws.d.ts
vendored
26
packages/biz/es/useSocket/ws.d.ts
vendored
@ -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;
|
|
@ -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;
|
|
23
packages/biz/es/utils/constants.d.ts
vendored
23
packages/biz/es/utils/constants.d.ts
vendored
@ -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;
|
|
||||||
};
|
|
@ -28,3 +28,16 @@ export var DeviceTab = {
|
|||||||
REAL_CAMERA_ONLYFACE: 7,
|
REAL_CAMERA_ONLYFACE: 7,
|
||||||
REAL_CAMERA_NOFACE_NOBOX_NODIRECONNECT: 8 // 只有普通摄像头,没有人脸、没有盒子、直连
|
REAL_CAMERA_NOFACE_NOBOX_NODIRECONNECT: 8 // 只有普通摄像头,没有人脸、没有盒子、直连
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 盒子 Tab 切换
|
||||||
|
export var BOX_TYPE_LIST = [{
|
||||||
|
value: '1',
|
||||||
|
label: '盒子'
|
||||||
|
}, {
|
||||||
|
value: '2',
|
||||||
|
label: '盒子组'
|
||||||
|
}];
|
||||||
|
export var ALL_LIST = [{
|
||||||
|
value: '',
|
||||||
|
label: '全部'
|
||||||
|
}];
|
12
packages/biz/lib/index.d.ts
vendored
12
packages/biz/lib/index.d.ts
vendored
@ -1,5 +1,17 @@
|
|||||||
export { default as BigImageModal } from './BigImageModal';
|
export { default as BigImageModal } from './BigImageModal';
|
||||||
|
export type { BigImageModalProps } from './BigImageModal';
|
||||||
export { default as BoxSelectTree } from './boxSelectTree';
|
export { default as BoxSelectTree } from './boxSelectTree';
|
||||||
|
export type { BoxSelectTreeProps } from './boxSelectTree';
|
||||||
export { default as Tree } from './tree';
|
export { default as Tree } from './tree';
|
||||||
|
export type { BoxTreeProps, TreeData } from './tree';
|
||||||
export { default as TreeTransfer } from './treeTransfer';
|
export { default as TreeTransfer } from './treeTransfer';
|
||||||
|
export type { TreeTransferProps } from './treeTransfer';
|
||||||
export { default as TreeTransferModal } from './treeTransferModal';
|
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';
|
||||||
|
@ -31,9 +31,14 @@ var src_exports = {};
|
|||||||
__export(src_exports, {
|
__export(src_exports, {
|
||||||
BigImageModal: () => import_BigImageModal.default,
|
BigImageModal: () => import_BigImageModal.default,
|
||||||
BoxSelectTree: () => import_boxSelectTree.default,
|
BoxSelectTree: () => import_boxSelectTree.default,
|
||||||
|
RealTimeMonitor: () => import_RealTimeMonitor.default,
|
||||||
Tree: () => import_tree.default,
|
Tree: () => import_tree.default,
|
||||||
TreeTransfer: () => import_treeTransfer.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);
|
module.exports = __toCommonJS(src_exports);
|
||||||
var import_BigImageModal = __toESM(require("./BigImageModal"));
|
var import_BigImageModal = __toESM(require("./BigImageModal"));
|
||||||
@ -41,11 +46,20 @@ var import_boxSelectTree = __toESM(require("./boxSelectTree"));
|
|||||||
var import_tree = __toESM(require("./tree"));
|
var import_tree = __toESM(require("./tree"));
|
||||||
var import_treeTransfer = __toESM(require("./treeTransfer"));
|
var import_treeTransfer = __toESM(require("./treeTransfer"));
|
||||||
var import_treeTransferModal = __toESM(require("./treeTransferModal"));
|
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:
|
// Annotate the CommonJS export names for ESM import in node:
|
||||||
0 && (module.exports = {
|
0 && (module.exports = {
|
||||||
BigImageModal,
|
BigImageModal,
|
||||||
BoxSelectTree,
|
BoxSelectTree,
|
||||||
|
RealTimeMonitor,
|
||||||
Tree,
|
Tree,
|
||||||
TreeTransfer,
|
TreeTransfer,
|
||||||
TreeTransferModal
|
TreeTransferModal,
|
||||||
|
VideoPlayerCard,
|
||||||
|
ViewLargerImageModal,
|
||||||
|
WarningRecordCard,
|
||||||
|
useViewLargerImageModal
|
||||||
});
|
});
|
||||||
|
@ -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
|
|
||||||
});
|
|
2
packages/biz/lib/useSocket/onceChannel.d.ts
vendored
2
packages/biz/lib/useSocket/onceChannel.d.ts
vendored
@ -1,2 +0,0 @@
|
|||||||
declare const startChannel: (topic: any, req: any, callback: any) => () => void;
|
|
||||||
export default startChannel;
|
|
@ -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;
|
|
26
packages/biz/lib/useSocket/ws.d.ts
vendored
26
packages/biz/lib/useSocket/ws.d.ts
vendored
@ -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;
|
|
@ -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;
|
|
23
packages/biz/lib/utils/constants.d.ts
vendored
23
packages/biz/lib/utils/constants.d.ts
vendored
@ -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;
|
|
||||||
};
|
|
@ -19,7 +19,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|||||||
// src/utils/constants.ts
|
// src/utils/constants.ts
|
||||||
var constants_exports = {};
|
var constants_exports = {};
|
||||||
__export(constants_exports, {
|
__export(constants_exports, {
|
||||||
|
ALL_LIST: () => ALL_LIST,
|
||||||
BODY_SEARCH_THRESHOID: () => BODY_SEARCH_THRESHOID,
|
BODY_SEARCH_THRESHOID: () => BODY_SEARCH_THRESHOID,
|
||||||
|
BOX_TYPE_LIST: () => BOX_TYPE_LIST,
|
||||||
DeviceTab: () => DeviceTab,
|
DeviceTab: () => DeviceTab,
|
||||||
ENTER_CIRCLE: () => ENTER_CIRCLE,
|
ENTER_CIRCLE: () => ENTER_CIRCLE,
|
||||||
GLOBAL_IS_BOX_VMS_SHOW: () => GLOBAL_IS_BOX_VMS_SHOW,
|
GLOBAL_IS_BOX_VMS_SHOW: () => GLOBAL_IS_BOX_VMS_SHOW,
|
||||||
@ -62,9 +64,18 @@ var DeviceTab = {
|
|||||||
REAL_CAMERA_NOFACE_NOBOX_NODIRECONNECT: 8
|
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:
|
// Annotate the CommonJS export names for ESM import in node:
|
||||||
0 && (module.exports = {
|
0 && (module.exports = {
|
||||||
|
ALL_LIST,
|
||||||
BODY_SEARCH_THRESHOID,
|
BODY_SEARCH_THRESHOID,
|
||||||
|
BOX_TYPE_LIST,
|
||||||
DeviceTab,
|
DeviceTab,
|
||||||
ENTER_CIRCLE,
|
ENTER_CIRCLE,
|
||||||
GLOBAL_IS_BOX_VMS_SHOW,
|
GLOBAL_IS_BOX_VMS_SHOW,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@zhst/biz",
|
"name": "@zhst/biz",
|
||||||
"version": "0.6.0",
|
"version": "0.10.1",
|
||||||
"description": "业务库",
|
"description": "业务库",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"business",
|
"business",
|
||||||
@ -35,7 +35,7 @@
|
|||||||
"registry": "http://10.0.0.77:4874"
|
"registry": "http://10.0.0.77:4874"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/zhst": "workspace:^"
|
"@zhst/types": "workspace:^"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/icons": "^5.2.6",
|
"@ant-design/icons": "^5.2.6",
|
||||||
@ -45,6 +45,7 @@
|
|||||||
"@zhst/meta": "workspace:^",
|
"@zhst/meta": "workspace:^",
|
||||||
"antd": "^5.12.5",
|
"antd": "^5.12.5",
|
||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
"rc-util": "^5.38.1"
|
"rc-util": "^5.38.1",
|
||||||
|
"dayjs": "^1.11.10"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
69
packages/biz/src/RealTimeMonitor/RealTimeMonitor.tsx
Normal file
69
packages/biz/src/RealTimeMonitor/RealTimeMonitor.tsx
Normal file
@ -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<ViewLargerImageModalRef>;
|
||||||
|
/*
|
||||||
|
处理 图片下载按钮点击事件
|
||||||
|
*/
|
||||||
|
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<RealTimeMonitorProps> = (props) => {
|
||||||
|
|
||||||
|
const { videoDataSource,
|
||||||
|
handleWindowClick,
|
||||||
|
handleCloseButtonClick,
|
||||||
|
selectedWindowKey,
|
||||||
|
warningDataSource,
|
||||||
|
viewLargerImageModalRef,
|
||||||
|
handleDownloadImg,
|
||||||
|
onRecordClick,
|
||||||
|
selectedRecordId,
|
||||||
|
isRecordListLoading,
|
||||||
|
} = props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='zhst-biz-real-time-monitor' style={{ display: 'flex' }} >
|
||||||
|
<WindowToggle
|
||||||
|
selectedWindowKey={selectedWindowKey}
|
||||||
|
dataSource={videoDataSource}
|
||||||
|
handleWindowClick={handleWindowClick}
|
||||||
|
handleCloseButtonClick={handleCloseButtonClick}
|
||||||
|
/>
|
||||||
|
<WarningRecordList
|
||||||
|
dataSource={warningDataSource}
|
||||||
|
handleDownloadImg={handleDownloadImg}
|
||||||
|
onRecordClick={onRecordClick}
|
||||||
|
selectedRecordId={selectedRecordId}
|
||||||
|
viewLargerImageModalRef={viewLargerImageModalRef}
|
||||||
|
isRecordListLoading={isRecordListLoading}
|
||||||
|
recordListTitle="监控预警记录"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RealTimeMonitor;
|
@ -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<ViewLargerImageModalRef>;
|
||||||
|
/*
|
||||||
|
处理 图片下载按钮点击事件
|
||||||
|
*/
|
||||||
|
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<WarningRecordListProps> = (props) => {
|
||||||
|
|
||||||
|
const {
|
||||||
|
dataSource = [],
|
||||||
|
viewLargerImageModalRef,
|
||||||
|
selectedRecordId,
|
||||||
|
handleDownloadImg,
|
||||||
|
onRecordClick,
|
||||||
|
isRecordListLoading,
|
||||||
|
recordListTitle,
|
||||||
|
style,
|
||||||
|
cardStyle,
|
||||||
|
imgStyle,
|
||||||
|
largeImageTitle
|
||||||
|
} = props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='zhst-biz-warning-record-list' style={style}>
|
||||||
|
<div className='header'>{recordListTitle}</div>
|
||||||
|
<div className='body'>
|
||||||
|
{
|
||||||
|
isRecordListLoading ?
|
||||||
|
<div style={{ height: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
||||||
|
<Spin indicator={<LoadingOutlined style={{ fontSize: 24 }} />} />
|
||||||
|
</div>
|
||||||
|
: (dataSource?.length) > 0 ?
|
||||||
|
<Space direction='vertical' size={10} >
|
||||||
|
{dataSource?.map((record, index) => {
|
||||||
|
if (index > 2) return
|
||||||
|
return (<WarningRecordCard
|
||||||
|
key={record?.id}
|
||||||
|
record={record}
|
||||||
|
onRecordClick={(record) => { onRecordClick?.(record) }}
|
||||||
|
selectedRecordId={selectedRecordId}
|
||||||
|
cardStyle={{ width: 300, height: 264, ...cardStyle }}
|
||||||
|
imgStyle={{ width: 280, height: 169, ...imgStyle }}
|
||||||
|
/>)
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
|
:
|
||||||
|
<div style={{ height: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
||||||
|
<Empty description="暂无数据" />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
{/* 弹窗 绑定ref 后可以调用 handleCancel方法关闭弹窗 show方法打开弹窗 */}
|
||||||
|
<ViewLargerImageModal ref={viewLargerImageModalRef} downloadImg={handleDownloadImg} title={largeImageTitle} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WarningRecordList;
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
import WarningRecordList from './WarningRecordList'
|
||||||
|
export default WarningRecordList
|
@ -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<WindowToggleProps> = (props) => {
|
||||||
|
|
||||||
|
const { dataSource = [], handleWindowClick, handleCloseButtonClick, selectedWindowKey } = props
|
||||||
|
const [size, setSize] = useState<Size>("large");
|
||||||
|
const { useToken } = theme
|
||||||
|
const { token } = useToken()
|
||||||
|
|
||||||
|
const getLabelStyle = (isSelected: boolean) => ({
|
||||||
|
padding: "0 11px", background: "#fff",
|
||||||
|
...(isSelected ? { background: token.colorPrimary, color: '#fff' } : {}),
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='zhst-biz-window-toggle'>
|
||||||
|
{/* 切换按钮 */}
|
||||||
|
<div className='header'>
|
||||||
|
<Segmented
|
||||||
|
defaultValue='large'
|
||||||
|
options={[
|
||||||
|
{ value: 'large', label: <div style={getLabelStyle(size === 'large')}><BarsOutlined /></div> },
|
||||||
|
{ value: 'small', label: <div style={getLabelStyle(size === 'small')}><AppstoreOutlined /></div> },
|
||||||
|
]}
|
||||||
|
onChange={(value) => {
|
||||||
|
// 当一个窗口时 默认 selectedkey 第一条数据的 windowkey
|
||||||
|
if (value === 'large' && dataSource.length > 0) {
|
||||||
|
const { windowKey } = dataSource[0]
|
||||||
|
handleWindowClick?.(windowKey)
|
||||||
|
}
|
||||||
|
setSize(value as Size)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='body'>
|
||||||
|
{
|
||||||
|
dataSource?.map((item, index) => {
|
||||||
|
if (size === "large" && index > 0) return
|
||||||
|
return (
|
||||||
|
<VideoPlayerCard
|
||||||
|
key={item.windowKey}
|
||||||
|
selectedWindowKey={selectedWindowKey}
|
||||||
|
size={size} {...item}
|
||||||
|
handleWindowClick={handleWindowClick}
|
||||||
|
handleCloseButtonClick={handleCloseButtonClick}
|
||||||
|
/>)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WindowToggle;
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
import WindowToggle from './WindowToggle'
|
||||||
|
export default WindowToggle
|
161
packages/biz/src/RealTimeMonitor/demo/base.tsx
Normal file
161
packages/biz/src/RealTimeMonitor/demo/base.tsx
Normal file
@ -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<VideoPlayerCardProps[]>(initialVideoDataSource);
|
||||||
|
const [warningDataSource, setWarningDataSource] = useState<IRecord[]>();
|
||||||
|
const [selectedWindowKey, setSelectedWindowKey] = useState<string | undefined>('first-window');
|
||||||
|
const [selectedRecordId, setSelectedRecordId] = React.useState<string | undefined>()
|
||||||
|
const [isRecordListLoading, setIsRecordListLoading] = React.useState<boolean>(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 (
|
||||||
|
|
||||||
|
|
||||||
|
<Space size={[8, 16]} direction="vertical">
|
||||||
|
<RealTimeMonitor
|
||||||
|
selectedWindowKey={selectedWindowKey}
|
||||||
|
videoDataSource={videoDataSource}
|
||||||
|
handleWindowClick={handleWindowClick}
|
||||||
|
handleCloseButtonClick={clearWindowData}
|
||||||
|
warningDataSource={warningDataSource}
|
||||||
|
handleDownloadImg={handleDownloadImg}
|
||||||
|
onRecordClick={onRecordClick}
|
||||||
|
selectedRecordId={selectedRecordId}
|
||||||
|
viewLargerImageModalRef={viewLargerImageModalRef}
|
||||||
|
isRecordListLoading={isRecordListLoading}
|
||||||
|
recordListTitle="监控预警记录" />
|
||||||
|
<button onClick={() => { mockData() }}>模拟数据</button>
|
||||||
|
</Space>
|
||||||
|
)
|
||||||
|
}
|
5
packages/biz/src/RealTimeMonitor/demo/index.less
Normal file
5
packages/biz/src/RealTimeMonitor/demo/index.less
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#realtimemonitor-demo-base {
|
||||||
|
.dumi-default-previewer-demo>div {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
65
packages/biz/src/RealTimeMonitor/demo/mock.tsx
Normal file
65
packages/biz/src/RealTimeMonitor/demo/mock.tsx
Normal file
@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
36
packages/biz/src/RealTimeMonitor/index.md
Normal file
36
packages/biz/src/RealTimeMonitor/index.md
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
---
|
||||||
|
group: 数据展示
|
||||||
|
category: Components
|
||||||
|
subtitle: 实时监控页面
|
||||||
|
title: RealTimeMonitor 实时监控页面
|
||||||
|
---
|
||||||
|
|
||||||
|
# RealTimeMonitor 实时监控页面
|
||||||
|
|
||||||
|
|
||||||
|
<code src="./demo/base.tsx"></code>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 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\<ViewLargerImageModalRef\>| - | - |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
2
packages/biz/src/RealTimeMonitor/index.tsx
Normal file
2
packages/biz/src/RealTimeMonitor/index.tsx
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
import RealTimeMonitor from './RealTimeMonitor'
|
||||||
|
export default RealTimeMonitor
|
101
packages/biz/src/VideoPlayerCard/VideoPlayerCard.tsx
Normal file
101
packages/biz/src/VideoPlayerCard/VideoPlayerCard.tsx
Normal file
@ -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<VideoPlayerCardProps> = (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<JSX.Element | null>(null);
|
||||||
|
const { useToken } = theme
|
||||||
|
const { token } = useToken()
|
||||||
|
const videoRef = useRef<VideoViewRef>(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 = (
|
||||||
|
<VideoPlayer ref={videoRef} url={videoSrc} />
|
||||||
|
);
|
||||||
|
videoRef.current?.setShowCrop(true)
|
||||||
|
|
||||||
|
} else if (imgSrc) {
|
||||||
|
contentElement = (
|
||||||
|
<img
|
||||||
|
alt="首帧图"
|
||||||
|
src={imgSrc}
|
||||||
|
style={{ width: "100%", height: "100%", display: 'block' }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
setCardContent(contentElement);
|
||||||
|
} else {
|
||||||
|
setCardContent(null)
|
||||||
|
}
|
||||||
|
}, [showType, imgSrc, videoSrc, isWindowLoading]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={componentName} onClick={() => { handleWindowClick?.(windowKey) }} style={videoPlayerCardStyle}>
|
||||||
|
<Card
|
||||||
|
title={
|
||||||
|
<Space style={{ width: "100%", justifyContent: "space-between" }}>
|
||||||
|
<div>{title}</div>
|
||||||
|
<div className="card-close-button">
|
||||||
|
<Button type="text" onClick={() => { handleCloseButtonClick?.(windowKey) }} >
|
||||||
|
<CloseOutlined />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Space>}
|
||||||
|
style={{ display: "flex", flexDirection: "column", borderRadius: 4, overflow: "hidden", ...cardStyle }}
|
||||||
|
bodyStyle={{ flex: 1 }}
|
||||||
|
{...cardProps}
|
||||||
|
>
|
||||||
|
{cardContent ? (
|
||||||
|
<>
|
||||||
|
{cardContent}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div style={{ backgroundColor: '#000', height: '100%', display: 'flex', padding: '20px', boxSizing: 'border-box' }}>
|
||||||
|
{
|
||||||
|
isWindowLoading ?
|
||||||
|
<div style={{ flex: 1, display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
||||||
|
<Spin indicator={<LoadingOutlined style={{ fontSize: 24 }} />} />
|
||||||
|
</div>
|
||||||
|
: !!errorReasonText && <span style={{ color: token.colorError }}>{errorReasonText}</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{/* 其他内容 */}
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default VideoPlayerCard;
|
||||||
|
|
19
packages/biz/src/VideoPlayerCard/demo/base.tsx
Normal file
19
packages/biz/src/VideoPlayerCard/demo/base.tsx
Normal file
@ -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 (
|
||||||
|
<Space size={[8, 16]} direction="vertical">
|
||||||
|
<VideoPlayerCard {...mockVideoPlayerCardProps} />
|
||||||
|
</Space>
|
||||||
|
)
|
||||||
|
}
|
30
packages/biz/src/VideoPlayerCard/index.less
Normal file
30
packages/biz/src/VideoPlayerCard/index.less
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
34
packages/biz/src/VideoPlayerCard/index.md
Normal file
34
packages/biz/src/VideoPlayerCard/index.md
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
---
|
||||||
|
group: 数据展示
|
||||||
|
category: Components
|
||||||
|
subtitle: 视频播放卡片
|
||||||
|
title: VideoPlayerCard 视频播放卡片
|
||||||
|
---
|
||||||
|
|
||||||
|
# VideoPlayerCard 视频播放卡片
|
||||||
|
|
||||||
|
|
||||||
|
<code src="./demo/base.tsx"></code>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 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| - | - |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
3
packages/biz/src/VideoPlayerCard/index.tsx
Normal file
3
packages/biz/src/VideoPlayerCard/index.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import VideoPlayerCard from './VideoPlayerCard'
|
||||||
|
export type { VideoPlayerCardProps } from './VideoPlayerCard'
|
||||||
|
export default VideoPlayerCard
|
@ -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<ViewLargerImageModalRef, ViewLargerImageModalProps>(
|
||||||
|
(props, ref) => {
|
||||||
|
|
||||||
|
const { modalProps, downloadImg, imgStyle, title = '预警大图', downloadText = '下载大图', spaceProps } = props
|
||||||
|
const { useToken } = theme
|
||||||
|
const { token } = useToken()
|
||||||
|
const [open, setOpen] = useState<boolean>(false);
|
||||||
|
const [imgSrc, setImgSrc] = useState<string>();
|
||||||
|
const [warningData, setWarningData] = useState<ViewLargerImageModalParams['warningData']>();
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
setOpen(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => {
|
||||||
|
return {
|
||||||
|
show: (_params) => {
|
||||||
|
setOpen(true);
|
||||||
|
setImgSrc(_params?.imgSrc)
|
||||||
|
setWarningData(_params?.warningData)
|
||||||
|
},
|
||||||
|
handleCancel
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
className='zhst-biz-view-warning-larger-image-modal'
|
||||||
|
open={open}
|
||||||
|
destroyOnClose
|
||||||
|
title={title}
|
||||||
|
width="1029px"
|
||||||
|
footer={null}
|
||||||
|
onCancel={handleCancel}
|
||||||
|
{...modalProps}
|
||||||
|
>
|
||||||
|
<Space size={0} styles={{ item: { backgroundColor: '#F6F9FAFF' } }} {...spaceProps}>
|
||||||
|
<img alt={title} src={imgSrc} style={{ width: 789, height: 444, display: 'block', ...imgStyle }} />
|
||||||
|
<div className='right-context'>
|
||||||
|
{warningData?.map(({ label, value }) => (
|
||||||
|
<div key={label} >
|
||||||
|
<span className='context-key'>{`${label}: `}</span>
|
||||||
|
{value}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{imgSrc && downloadImg && <div className='img-download' style={{ color: token.colorPrimary }} onClick={() => downloadImg?.(imgSrc)} ><DownloadOutlined /><span style={{ paddingLeft: 3 }}>{downloadText}</span></div>}
|
||||||
|
</div>
|
||||||
|
</Space>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export default ViewLargerImageModal;
|
||||||
|
|
||||||
|
export const useViewLargerImageModal = () => {
|
||||||
|
return useRef<ViewLargerImageModalRef>(null);
|
||||||
|
};
|
94
packages/biz/src/ViewLargerImageModal/demo/base.tsx
Normal file
94
packages/biz/src/ViewLargerImageModal/demo/base.tsx
Normal file
@ -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<string | undefined>()
|
||||||
|
|
||||||
|
// 把弹窗的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 (
|
||||||
|
<>
|
||||||
|
<Space size={[8, 16]} >
|
||||||
|
{
|
||||||
|
dataSource?.map((record) => <WarningRecordCard key={record?.id} record={record} onRecordClick={(record) => { handleClick(record) }} selectedRecordId={selectedRecordId} />)
|
||||||
|
}
|
||||||
|
</Space>
|
||||||
|
{/* 弹窗 绑定ref 后可以调用 handleCancel方法关闭弹窗 show方法打开弹窗 */}
|
||||||
|
<ViewLargerImageModal ref={viewLargerImageModalRef} downloadImg={handleDownloadImg} title="预警大图" />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
62
packages/biz/src/ViewLargerImageModal/index.less
Normal file
62
packages/biz/src/ViewLargerImageModal/index.less
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
packages/biz/src/ViewLargerImageModal/index.md
Normal file
28
packages/biz/src/ViewLargerImageModal/index.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
group: 数据展示
|
||||||
|
category: Components
|
||||||
|
subtitle: 查看大图弹窗
|
||||||
|
title: ViewLargerImageModal 查看大图弹窗
|
||||||
|
---
|
||||||
|
|
||||||
|
# ViewLargerImageModal 查看大图弹窗
|
||||||
|
|
||||||
|
|
||||||
|
<code src="./demo/base.tsx"></code>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| show() |通过 ref 用于开启弹窗 可以将点击的 记录传给弹窗| | | |
|
||||||
|
| handleCancel() | 通过 ref 用于关闭弹窗 | | | |
|
||||||
|
| imgSrc | 图片地址 |string | | |
|
||||||
|
| contextData | 大图显示的数据 | | | |
|
||||||
|
| imgStyle | 用于修改图片样式 | | | |
|
||||||
|
| downloadImg | 传入下载图片的方法 | | | |
|
||||||
|
| title | 弹窗标题 | string | | |
|
||||||
|
| downloadText | 下载按钮文本 | string | | |
|
||||||
|
| modalProps | 弹窗属性 | | | |
|
||||||
|
|
4
packages/biz/src/ViewLargerImageModal/index.tsx
Normal file
4
packages/biz/src/ViewLargerImageModal/index.tsx
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import ViewLargerImageModal, { useViewLargerImageModal } from './ViewLargerImageModal'
|
||||||
|
export type { ViewLargerImageModalRef, ViewLargerImageModalProps } from './ViewLargerImageModal'
|
||||||
|
export default ViewLargerImageModal;
|
||||||
|
export { useViewLargerImageModal };
|
109
packages/biz/src/WarningRecordCard/WarningRecordCard.tsx
Normal file
109
packages/biz/src/WarningRecordCard/WarningRecordCard.tsx
Normal file
@ -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<WarningRecordCardProps> = (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 (
|
||||||
|
<div className={componentName} key={id} onClick={handleClick} style={style}>
|
||||||
|
<Card
|
||||||
|
cover={<img alt="预警图" src={imgSrc} style={{ width: 336, height: 203, borderRadius: 0, ...imgStyle }} />}
|
||||||
|
style={{ width: 356, height: 302, padding: 10, borderRadius: 4, ...selectedCardStyle, ...cardStyle }}
|
||||||
|
{...cardProps}
|
||||||
|
>
|
||||||
|
<div className='left-context'>
|
||||||
|
<div className="warning-type">{warningType}</div>
|
||||||
|
<Space size={0} split={<Divider type="vertical" />}>
|
||||||
|
{warningInfo?.map((item, index) => (
|
||||||
|
<div key={index} className="info-item">
|
||||||
|
{item}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</Space>
|
||||||
|
<div className='warning-time'>{warningTimeShow}</div>
|
||||||
|
</div>
|
||||||
|
<div className='cabietInfo' >{cabietText}</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WarningRecordCard;
|
56
packages/biz/src/WarningRecordCard/demo/base.tsx
Normal file
56
packages/biz/src/WarningRecordCard/demo/base.tsx
Normal file
@ -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 (
|
||||||
|
<Space size={[8, 16]} direction="vertical">
|
||||||
|
{
|
||||||
|
dataSource?.map((record) => <WarningRecordCard key={record?.id} record={record} />)
|
||||||
|
}
|
||||||
|
</Space>
|
||||||
|
)
|
||||||
|
}
|
27
packages/biz/src/WarningRecordCard/index.less
Normal file
27
packages/biz/src/WarningRecordCard/index.less
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
packages/biz/src/WarningRecordCard/index.md
Normal file
30
packages/biz/src/WarningRecordCard/index.md
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
group: 数据展示
|
||||||
|
category: Components
|
||||||
|
subtitle: 预警记录卡片
|
||||||
|
title: WarningRecordCard 预警记录卡片
|
||||||
|
---
|
||||||
|
|
||||||
|
# WarningRecordCard 预警记录卡片
|
||||||
|
|
||||||
|
|
||||||
|
<code src="./demo/base.tsx"></code>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 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 | - |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
3
packages/biz/src/WarningRecordCard/index.tsx
Normal file
3
packages/biz/src/WarningRecordCard/index.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import WarningRecordCard from './WarningRecordCard'
|
||||||
|
export type { IRecord, WarningRecordCardProps} from './WarningRecordCard'
|
||||||
|
export default WarningRecordCard
|
@ -1,21 +1,11 @@
|
|||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import { InputProps, Tabs, TabsProps, TreeDataNode, TreeProps } from 'antd'
|
import { Tabs, TabsProps } from 'antd'
|
||||||
import BoxPanel from './components/boxPanel';
|
import BoxPanel from './components/boxPanel';
|
||||||
import { ModalFormProps } from '@ant-design/pro-components';
|
import type { BoxPanelProps } from './components/boxPanel';
|
||||||
|
|
||||||
export interface BoxSelectTreeProps {
|
export interface BoxSelectTreeProps extends BoxPanelProps {
|
||||||
boxDataSource: TreeDataNode[]
|
|
||||||
data: TreeDataNode[]
|
|
||||||
onSearch?: (e: any) => void // 搜索
|
|
||||||
onItemSelect?: TreeProps['onSelect']
|
|
||||||
onItemCheck?: TreeProps['onCheck']
|
|
||||||
onTabChange?: (e: any) => void
|
onTabChange?: (e: any) => void
|
||||||
onBoxBatchDelete?: (data?: any) => void
|
|
||||||
onBoxDelete?: (data?: any) => void
|
|
||||||
onCreateSubmit?: ModalFormProps['onFinish']
|
|
||||||
tabsProps?: TabsProps
|
tabsProps?: TabsProps
|
||||||
searchInputProps?: InputProps
|
|
||||||
treeProps?: TreeProps
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const BoxSelectTree: FC<BoxSelectTreeProps> = (props) => {
|
const BoxSelectTree: FC<BoxSelectTreeProps> = (props) => {
|
||||||
@ -29,15 +19,17 @@ const BoxSelectTree: FC<BoxSelectTreeProps> = (props) => {
|
|||||||
onBoxBatchDelete,
|
onBoxBatchDelete,
|
||||||
onBoxDelete,
|
onBoxDelete,
|
||||||
onCreateSubmit,
|
onCreateSubmit,
|
||||||
|
onClockClick,
|
||||||
|
onImport,
|
||||||
|
onCreate,
|
||||||
tabsProps,
|
tabsProps,
|
||||||
searchInputProps,
|
searchInputProps,
|
||||||
treeProps
|
treeProps,
|
||||||
|
customImport,
|
||||||
|
showOptions,
|
||||||
|
extraBtns,
|
||||||
} = props
|
} = props
|
||||||
|
|
||||||
const onChange = (key: string) => {
|
|
||||||
onTabChange?.(key)
|
|
||||||
};
|
|
||||||
|
|
||||||
const items: TabsProps['items'] = [
|
const items: TabsProps['items'] = [
|
||||||
{
|
{
|
||||||
key: '1',
|
key: '1',
|
||||||
@ -48,12 +40,18 @@ const BoxSelectTree: FC<BoxSelectTreeProps> = (props) => {
|
|||||||
boxDataSource={boxDataSource}
|
boxDataSource={boxDataSource}
|
||||||
treeProps={treeProps}
|
treeProps={treeProps}
|
||||||
data={data}
|
data={data}
|
||||||
|
onCreate={onCreate}
|
||||||
onCreateSubmit={onCreateSubmit}
|
onCreateSubmit={onCreateSubmit}
|
||||||
onBoxBatchDelete={onBoxBatchDelete}
|
onBoxBatchDelete={onBoxBatchDelete}
|
||||||
onBoxDelete={onBoxDelete}
|
onBoxDelete={onBoxDelete}
|
||||||
onSearch={onSearch}
|
onSearch={onSearch}
|
||||||
onItemCheck={onItemCheck}
|
onItemCheck={onItemCheck}
|
||||||
onItemSelect={onItemSelect}
|
onItemSelect={onItemSelect}
|
||||||
|
showOptions={showOptions}
|
||||||
|
customImport={customImport}
|
||||||
|
extraBtns={extraBtns}
|
||||||
|
onClockClick={onClockClick}
|
||||||
|
onImport={onImport}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -66,12 +64,18 @@ const BoxSelectTree: FC<BoxSelectTreeProps> = (props) => {
|
|||||||
searchInputProps={searchInputProps}
|
searchInputProps={searchInputProps}
|
||||||
treeProps={treeProps}
|
treeProps={treeProps}
|
||||||
data={data}
|
data={data}
|
||||||
|
onCreate={onCreate}
|
||||||
onBoxBatchDelete={onBoxBatchDelete}
|
onBoxBatchDelete={onBoxBatchDelete}
|
||||||
onCreateSubmit={onCreateSubmit}
|
onCreateSubmit={onCreateSubmit}
|
||||||
onBoxDelete={onBoxDelete}
|
onBoxDelete={onBoxDelete}
|
||||||
onSearch={onSearch}
|
onSearch={onSearch}
|
||||||
onItemCheck={onItemCheck}
|
onItemCheck={onItemCheck}
|
||||||
onItemSelect={onItemSelect}
|
onItemSelect={onItemSelect}
|
||||||
|
showOptions={showOptions}
|
||||||
|
customImport={customImport}
|
||||||
|
extraBtns={extraBtns}
|
||||||
|
onClockClick={onClockClick}
|
||||||
|
onImport={onImport}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -82,7 +86,7 @@ const BoxSelectTree: FC<BoxSelectTreeProps> = (props) => {
|
|||||||
defaultActiveKey="1"
|
defaultActiveKey="1"
|
||||||
centered
|
centered
|
||||||
items={items}
|
items={items}
|
||||||
onChange={onChange}
|
onChange={onTabChange}
|
||||||
tabBarGutter={0}
|
tabBarGutter={0}
|
||||||
indicator={{ size: (origin) => origin, align: 'center' }}
|
indicator={{ size: (origin) => origin, align: 'center' }}
|
||||||
{...tabsProps}
|
{...tabsProps}
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
import React, { FC, useState, useRef } from 'react';
|
import React, { FC, useState, useRef } from 'react';
|
||||||
import{ Button, Divider, Input, Space, TreeDataNode } from 'antd'
|
import{ Button, Divider, Input, Space, TreeDataNode } from 'antd'
|
||||||
import { ModalForm, ModalFormProps, ProFormInstance, ProFormText } from '@ant-design/pro-components'
|
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 { TreeProps, InputProps } from 'antd';
|
||||||
|
import type { BoxTreeProps } from '../../../tree';
|
||||||
import TreeTransferModal from '../../../treeTransferModal'
|
import TreeTransferModal from '../../../treeTransferModal'
|
||||||
import BoxTree from '../../../tree';
|
import BoxTree from '../../../tree';
|
||||||
import './index.less'
|
// import './index.less'
|
||||||
|
|
||||||
export interface BoxGroupPanelProps {
|
export interface BoxPanelProps {
|
||||||
searchInputProps?: InputProps
|
searchInputProps?: InputProps
|
||||||
treeProps?: TreeProps
|
showOptions?: boolean
|
||||||
|
treeProps?: Partial<BoxTreeProps>
|
||||||
data: TreeDataNode[]
|
data: TreeDataNode[]
|
||||||
boxDataSource: TreeDataNode[]
|
boxDataSource: TreeDataNode[]
|
||||||
handleImport?: () => void
|
handleImport?: () => void
|
||||||
@ -19,11 +21,19 @@ export interface BoxGroupPanelProps {
|
|||||||
onBoxBatchDelete?: (data?: any) => void
|
onBoxBatchDelete?: (data?: any) => void
|
||||||
onBoxDelete?: (data?: any) => void
|
onBoxDelete?: (data?: any) => void
|
||||||
onCreateSubmit?: ModalFormProps['onFinish']
|
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 {
|
const {
|
||||||
searchInputProps,
|
searchInputProps,
|
||||||
|
showOptions = true,
|
||||||
|
extraBtns,
|
||||||
data = [],
|
data = [],
|
||||||
onSearch,
|
onSearch,
|
||||||
treeProps,
|
treeProps,
|
||||||
@ -32,7 +42,12 @@ const BoxGroupPanel: FC<BoxGroupPanelProps> = (props) => {
|
|||||||
onCreateSubmit,
|
onCreateSubmit,
|
||||||
onBoxBatchDelete,
|
onBoxBatchDelete,
|
||||||
onBoxDelete,
|
onBoxDelete,
|
||||||
boxDataSource
|
onClockClick,
|
||||||
|
onImport,
|
||||||
|
onBatch,
|
||||||
|
onCreate,
|
||||||
|
boxDataSource,
|
||||||
|
customImport
|
||||||
} = props
|
} = props
|
||||||
const [isTreeCheckable, setIsTreeCheckable] = useState(false)
|
const [isTreeCheckable, setIsTreeCheckable] = useState(false)
|
||||||
const [targetItems, setTargetItems] = useState<TreeDataNode[]>([]);
|
const [targetItems, setTargetItems] = useState<TreeDataNode[]>([]);
|
||||||
@ -41,8 +56,7 @@ const BoxGroupPanel: FC<BoxGroupPanelProps> = (props) => {
|
|||||||
const createFormRef = useRef<
|
const createFormRef = useRef<
|
||||||
ProFormInstance<{
|
ProFormInstance<{
|
||||||
name: string;
|
name: string;
|
||||||
company?: string;
|
boxList?: any[];
|
||||||
useMode?: string;
|
|
||||||
}>
|
}>
|
||||||
>()
|
>()
|
||||||
|
|
||||||
@ -76,89 +90,122 @@ const BoxGroupPanel: FC<BoxGroupPanelProps> = (props) => {
|
|||||||
setTargetItems(pre => pre.filter(o => o.key !== key))
|
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([])
|
setCheckedKeys([])
|
||||||
setTargetItems([])
|
setTargetItems([])
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ padding: '0 16px' }}>
|
<div style={{ padding: '0 16px' }}>
|
||||||
|
{/* 盒子选择弹框 */}
|
||||||
<TreeTransferModal
|
<TreeTransferModal
|
||||||
open={boxChoiceOpen}
|
open={boxChoiceOpen}
|
||||||
onCancel={() => setBoxChoiceOpen(false)}
|
onCancel={() => setBoxChoiceOpen(false)}
|
||||||
onRadioChange={(val) => console.log('radio', val)} // 顶部 radio 事件
|
onRadioChange={(e) => console.log('radio', e.target.value)} // 顶部 radio 事件
|
||||||
dataSource={boxDataSource} // 数据源
|
dataSource={boxDataSource} // 数据源
|
||||||
targetItems={targetItems} // 右侧选中项
|
targetItems={targetItems} // 右侧选中项
|
||||||
checkedKeys={checkedKeys} // 左侧选中
|
checkedKeys={checkedKeys} // 左侧选中
|
||||||
onReset={onReset} // 重置按钮事件
|
onReset={onBoxChoiceReset} // 重置按钮事件
|
||||||
onOk={onOk} // 确定按钮事件
|
onOk={onBoxChoiceOk} // 确定按钮事件
|
||||||
onTreeCheck={onTreeCheck} // 树check选中事件
|
onTreeCheck={onTreeCheck} // 树check选中事件
|
||||||
onItemDelete={onItemDelete} // 右侧点击删除事件
|
onItemDelete={onItemDelete} // 右侧点击删除事件
|
||||||
/>
|
/>
|
||||||
<Space size={12} direction='vertical'>
|
<Space size={12} direction='vertical' style={{ width: '100%' }}>
|
||||||
<Space>
|
<Space size={4} style={{ width: '100%', justifyContent: 'space-between' }} >
|
||||||
<Input size='middle' onChange={(e) => onSearch?.(e)} placeholder='请输入盒子名称' {...searchInputProps} />
|
<Input size='middle' onChange={(e) => onSearch?.(e)} placeholder='请输入盒子名称' {...searchInputProps} />
|
||||||
<Button style={{ width: '80px' }} type='primary' >导入盒子</Button>
|
{customImport || (
|
||||||
|
<>
|
||||||
|
<Button type="text" onClick={() => onBatch?.() || handleCheckable()} icon={isTreeCheckable ? <SwitcherOutlined /> : <DiffOutlined />} />
|
||||||
|
<Button type="text" onClick={() => onClockClick?.()} icon={<ClockCircleOutlined />} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Space>
|
</Space>
|
||||||
<Space align='center'>
|
{/* 是否显示操作按钮 */}
|
||||||
<ModalForm
|
{showOptions && (
|
||||||
width={'600px'}
|
<>
|
||||||
formRef={createFormRef}
|
<Space align='center'>
|
||||||
title="新建组"
|
<Button type='text' style={{ padding: '4px 8px' }} onClick={() => onImport?.()} icon={<ImportOutlined />} >导入盒子</Button>
|
||||||
modalProps={{ destroyOnClose: true }}
|
<Divider type="vertical" style={{ margin: '8px 0' }} />
|
||||||
layout='horizontal'
|
{onCreate ?
|
||||||
labelCol={{ span: 6 }}
|
(
|
||||||
wrapperCol={{ span: 18 }}
|
<Button onClick={onCreate} type='text' style={{ padding: '4px 8px' }} icon={<FolderAddOutlined />} >新建组</Button>
|
||||||
trigger={<Button type='link' >新建组</Button>}
|
) : (
|
||||||
submitter={{
|
<ModalForm<{
|
||||||
searchConfig: {
|
name: string
|
||||||
submitText: '确定',
|
boxList?: any[]
|
||||||
resetText: '取消',
|
}>
|
||||||
},
|
width={'600px'}
|
||||||
}}
|
open={onCreate ? false : undefined}
|
||||||
onFinish={onCreateSubmit}
|
formRef={createFormRef}
|
||||||
>
|
title="新建组"
|
||||||
<ProFormText
|
modalProps={{ destroyOnClose: true }}
|
||||||
rules={[
|
layout='horizontal'
|
||||||
{
|
labelCol={{ span: 6 }}
|
||||||
required: true,
|
wrapperCol={{ span: 18 }}
|
||||||
},
|
trigger={<Button type='text' style={{ padding: '4px 8px' }} icon={<FolderAddOutlined />} >新建组</Button>}
|
||||||
]}
|
submitter={{
|
||||||
width="md"
|
searchConfig: {
|
||||||
name="name"
|
submitText: '确定',
|
||||||
label="盒子组名称"
|
resetText: '取消',
|
||||||
placeholder="请输入盒子名称"
|
},
|
||||||
/>
|
}}
|
||||||
<ProFormText
|
onFinish={onCreateSubmit}
|
||||||
width="md"
|
>
|
||||||
name="boxList"
|
<ProFormText
|
||||||
label="盒子选择"
|
rules={[
|
||||||
placeholder="已选择0个盒子"
|
{
|
||||||
fieldProps={{
|
required: true,
|
||||||
readOnly: true,
|
max: 20,
|
||||||
suffix: (
|
},
|
||||||
<Space>
|
{
|
||||||
<a onClick={() => {
|
pattern: /^[^\s]*$/g,
|
||||||
createFormRef.current?.setFieldValue('boxList', null)
|
message: '禁止输入空格'
|
||||||
}} >恢复默认</a>
|
}
|
||||||
<a onClick={() => setBoxChoiceOpen(true)}>范围选择</a>
|
]}
|
||||||
</Space>
|
fieldProps={{ showCount: 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' }} />
|
||||||
</ModalForm>
|
{/* @ts-ignore */}
|
||||||
<Divider type="vertical" />
|
<Button danger type='text' style={{ padding: '4px 8px' }} icon={<CloseCircleOutlined />} disabled={treeProps?.checkedKeys?.length <= 0} onClick={onBoxBatchDelete} >删除</Button>
|
||||||
{/* @ts-ignore */}
|
</Space>
|
||||||
<Button danger type='link' disabled={treeProps?.checkedKeys?.length <= 0} onClick={onBoxBatchDelete} >删除</Button>
|
<Divider style={{ margin: 0 }} />
|
||||||
<Divider type="vertical" />
|
</>
|
||||||
<Button type="link" onClick={() => handleCheckable()} icon={isTreeCheckable ? <DiffOutlined /> : <SwitcherOutlined />} />
|
)}
|
||||||
<Button type="link" onClick={() => handleCheckable()} icon={isTreeCheckable ? <DiffOutlined /> : <SwitcherOutlined />} />
|
{extraBtns}
|
||||||
</Space>
|
|
||||||
<Divider style={{ margin: 0 }} />
|
|
||||||
<BoxTree
|
<BoxTree
|
||||||
treeCheckable={isTreeCheckable}
|
treeCheckable={isTreeCheckable}
|
||||||
data={data}
|
data={data}
|
||||||
@ -172,4 +219,4 @@ const BoxGroupPanel: FC<BoxGroupPanelProps> = (props) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default BoxGroupPanel
|
export default BoxPanel
|
||||||
|
82
packages/biz/src/boxSelectTree/demo/async.tsx
Normal file
82
packages/biz/src/boxSelectTree/demo/async.tsx
Normal 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;
|
@ -2,10 +2,12 @@ import React, { useState } from 'react';
|
|||||||
import { BoxSelectTree } from '@zhst/biz';
|
import { BoxSelectTree } from '@zhst/biz';
|
||||||
import { treeData, boxDataSource } from './mock'
|
import { treeData, boxDataSource } from './mock'
|
||||||
import { Select, TreeProps, Modal, Checkbox } from 'antd';
|
import { Select, TreeProps, Modal, Checkbox } from 'antd';
|
||||||
|
import { BOX_TYPE_LIST } from '../../utils/constants';
|
||||||
|
|
||||||
const { Option } = Select
|
const { Option } = Select
|
||||||
|
|
||||||
const demo = () => {
|
const demo = () => {
|
||||||
|
const [activeKey, setActiveKey] = useState('1')
|
||||||
const [searchType, setSearchType] = useState('1')
|
const [searchType, setSearchType] = useState('1')
|
||||||
const [searchVal, setSearchVal] = useState('')
|
const [searchVal, setSearchVal] = useState('')
|
||||||
const [checkedKeys, setCheckedKeys] = useState<string[]>([]);
|
const [checkedKeys, setCheckedKeys] = useState<string[]>([]);
|
||||||
@ -32,18 +34,25 @@ const demo = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ border: '1px solid #ccc', width: '320px' }}>
|
<div style={{ border: '1px solid #ccc', width: '320px', minHeight: '900px' }}>
|
||||||
{contextHolder}
|
{contextHolder}
|
||||||
<BoxSelectTree
|
<BoxSelectTree
|
||||||
data={treeData}
|
data={activeKey === '1' ? treeData : boxDataSource}
|
||||||
boxDataSource={boxDataSource}
|
boxDataSource={boxDataSource}
|
||||||
onSearch={e => console.log('搜索', e)}
|
onSearch={e => console.log('搜索', e)}
|
||||||
onCreateSubmit={async () => { return true }}
|
onCreateSubmit={async (_data) => {
|
||||||
|
console.log('新建盒子', _data)
|
||||||
|
return true
|
||||||
|
}}
|
||||||
onItemCheck={onTreeCheck}
|
onItemCheck={onTreeCheck}
|
||||||
onItemSelect={e => console.log('onItemSelect', e)}
|
onItemSelect={e => console.log('onItemSelect', e)}
|
||||||
onTabChange={e => console.log('tabChange', e)}
|
onTabChange={val => setActiveKey(val)}
|
||||||
onBoxDelete={data => console.log('盒子删除', data)}
|
|
||||||
onBoxBatchDelete={onBoxBatchDelete}
|
onBoxBatchDelete={onBoxBatchDelete}
|
||||||
|
onClockClick={() => console.log('时钟点击事件')}
|
||||||
|
onImport={() => console.log('导入盒子')}
|
||||||
|
tabsProps={{
|
||||||
|
activeKey,
|
||||||
|
}}
|
||||||
searchInputProps={{
|
searchInputProps={{
|
||||||
addonBefore: (
|
addonBefore: (
|
||||||
<Select
|
<Select
|
||||||
@ -54,15 +63,20 @@ const demo = () => {
|
|||||||
}}
|
}}
|
||||||
style={{ width: '72px' }}
|
style={{ width: '72px' }}
|
||||||
>
|
>
|
||||||
<Option value="1">盒子</Option>
|
{BOX_TYPE_LIST.map(item => (
|
||||||
<Option value="2">盒子组</Option>
|
<Option value={item.value}>{item.label}</Option>
|
||||||
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
),
|
),
|
||||||
onChange: e => setSearchVal(e.target.value),
|
onChange: e => setSearchVal(e.target.value),
|
||||||
value: searchVal
|
value: searchVal
|
||||||
}}
|
}}
|
||||||
treeProps={{
|
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>
|
</div>
|
||||||
|
28
packages/biz/src/boxSelectTree/demo/extraBtns.tsx
Normal file
28
packages/biz/src/boxSelectTree/demo/extraBtns.tsx
Normal file
@ -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<string[]>([]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ border: '1px solid #ccc', width: '340px', minHeight: '900px' }}>
|
||||||
|
<BoxSelectTree
|
||||||
|
data={activeKey === '1' ? treeData : boxDataSource}
|
||||||
|
boxDataSource={boxDataSource}
|
||||||
|
showOptions={false}
|
||||||
|
extraBtns={<Button type="dashed" style={{ color: 'green' }}>自定义按钮</Button>}
|
||||||
|
tabsProps={{
|
||||||
|
activeKey,
|
||||||
|
}}
|
||||||
|
treeProps={{
|
||||||
|
checkedKeys
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default demo;
|
@ -1,6 +1,6 @@
|
|||||||
import { TreeDataNode } from "antd";
|
import { TreeData } from "@zhst/biz";
|
||||||
|
|
||||||
export const treeData: TreeDataNode[] = [
|
export const boxDataSource: TreeData[] = [
|
||||||
{
|
{
|
||||||
title: '全部盒子',
|
title: '全部盒子',
|
||||||
key: '0-0',
|
key: '0-0',
|
||||||
@ -12,10 +12,12 @@ export const treeData: TreeDataNode[] = [
|
|||||||
{
|
{
|
||||||
title: '摄像头1',
|
title: '摄像头1',
|
||||||
key: '0-0-0-0',
|
key: '0-0-0-0',
|
||||||
|
isCamera: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '摄像头2',
|
title: '摄像头2',
|
||||||
key: '0-0-0-1',
|
key: '0-0-0-1',
|
||||||
|
isCamera: true
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -25,7 +27,8 @@ export const treeData: TreeDataNode[] = [
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
title: '摄像头4',
|
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',
|
key: '0-1-3',
|
||||||
title: '分组0-0',
|
title: '分组0-1-3',
|
||||||
isLeaf: false,
|
|
||||||
checkable: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '0-1',
|
|
||||||
title: '分组0-1',
|
|
||||||
isLeaf: false,
|
isLeaf: false,
|
||||||
children: [
|
children: [
|
||||||
{ key: '0-1-0', title: '分组0-1-0', isLeaf: true, checkable: false },
|
{ key: '0-1-3-1', title: '分组0-1-3-1', isLeaf: true, isCamera: true },
|
||||||
{ key: '0-1-1', title: '分组0-1-1', isLeaf: true, checkable: false },
|
{ key: '0-1-3-2', title: '分组0-1-3-2', isLeaf: true, isCamera: true },
|
||||||
{ key: '0-1-2', title: '分组0-1-2', isLeaf: true, checkable: false },
|
{ key: '0-1-3-3', title: '分组0-1-3-3', isLeaf: true, isCamera: true },
|
||||||
{
|
|
||||||
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-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, },
|
|
||||||
];
|
];
|
||||||
|
61
packages/biz/src/boxSelectTree/demo/noOptions.tsx
Normal file
61
packages/biz/src/boxSelectTree/demo/noOptions.tsx
Normal file
@ -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<string[]>([]);
|
||||||
|
|
||||||
|
const onTreeCheck: TreeProps['onCheck'] = (keys: any) => {
|
||||||
|
setCheckedKeys(keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ border: '1px solid #ccc', width: '340px', minHeight: '900px' }}>
|
||||||
|
<BoxSelectTree
|
||||||
|
data={activeKey === '1' ? treeData : boxDataSource}
|
||||||
|
boxDataSource={boxDataSource}
|
||||||
|
onSearch={e => 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={<Button type="text" icon={<FilterOutlined />} />}
|
||||||
|
searchInputProps={{
|
||||||
|
addonBefore: (
|
||||||
|
<Select
|
||||||
|
value={searchType}
|
||||||
|
onChange={_type => {
|
||||||
|
setSearchType(_type)
|
||||||
|
setSearchVal('')
|
||||||
|
}}
|
||||||
|
style={{ width: '72px' }}
|
||||||
|
>
|
||||||
|
{BOX_TYPE_LIST.map(item => (
|
||||||
|
<Option value={item.value}>{item.label}</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
),
|
||||||
|
onChange: e => setSearchVal(e.target.value),
|
||||||
|
value: searchVal
|
||||||
|
}}
|
||||||
|
treeProps={{
|
||||||
|
checkedKeys
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default demo;
|
@ -13,7 +13,11 @@ group:
|
|||||||
## 代码演示
|
## 代码演示
|
||||||
|
|
||||||
<code src="./demo/basic.tsx">基本用法</code>
|
<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
|
||||||
|
|
||||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
@ -24,3 +28,11 @@ group:
|
|||||||
| tabsProps | Tabs组件的Props | antd的Tabs组件 | - | - |
|
| tabsProps | Tabs组件的Props | antd的Tabs组件 | - | - |
|
||||||
| searchInputProps | 搜索框的Props | antd的Input组件 | - | - |
|
| searchInputProps | 搜索框的Props | antd的Input组件 | - | - |
|
||||||
| onTabChange | tab切换监听 | function: (e) => void | - | - |
|
| 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 | - |
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
import BoxSelectTree from './boxSelectTree';
|
import BoxSelectTree from './boxSelectTree';
|
||||||
|
|
||||||
|
export type { BoxSelectTreeProps } from './boxSelectTree'
|
||||||
|
|
||||||
export default BoxSelectTree;
|
export default BoxSelectTree;
|
||||||
|
@ -1,5 +1,18 @@
|
|||||||
export { default as BigImageModal } from './BigImageModal'
|
export { default as BigImageModal } from './BigImageModal'
|
||||||
|
export type { BigImageModalProps } from './BigImageModal'
|
||||||
export { default as BoxSelectTree } from './boxSelectTree'
|
export { default as BoxSelectTree } from './boxSelectTree'
|
||||||
|
export type { BoxSelectTreeProps } from './boxSelectTree'
|
||||||
export { default as Tree } from './tree'
|
export { default as Tree } from './tree'
|
||||||
|
export type { BoxTreeProps, TreeData } from './tree'
|
||||||
export { default as TreeTransfer } from './treeTransfer'
|
export { default as TreeTransfer } from './treeTransfer'
|
||||||
|
export type { TreeTransferProps } from './treeTransfer'
|
||||||
export { default as TreeTransferModal } from './treeTransferModal'
|
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'
|
||||||
|
|
||||||
|
@ -1,70 +1,122 @@
|
|||||||
import React, { FC } from 'react';
|
import React, { FC, useState } from 'react';
|
||||||
import { Tree, Badge, TreeDataNode, Space, TreeProps } from 'antd';
|
import { Tree, Badge, TreeDataNode, Space, TreeProps } from 'antd';
|
||||||
|
import theme from 'antd/es/theme'
|
||||||
import { CloseOutlined, EditOutlined, SettingOutlined } from '@ant-design/icons'
|
import { CloseOutlined, EditOutlined, SettingOutlined } from '@ant-design/icons'
|
||||||
import { ModalForm, ProFormText } from '@ant-design/pro-components';
|
import { ModalForm, ProFormText } from '@ant-design/pro-components';
|
||||||
import './index.less'
|
import './index.less'
|
||||||
|
|
||||||
const componentName = 'zhst-biz-tree'
|
const componentName = 'zhst-biz-tree'
|
||||||
|
const { useToken } = theme
|
||||||
|
|
||||||
export interface BoxTreeProps extends TreeProps {
|
export interface BoxTreeProps extends TreeProps {
|
||||||
data: TreeDataNode[]
|
data: TreeDataNode[]
|
||||||
treeCheckable?: boolean
|
treeCheckable?: boolean
|
||||||
showItemOption?: boolean
|
showItemOption?: boolean
|
||||||
treeProps?: TreeProps
|
customOptions?: any;
|
||||||
onItemCheck?: TreeProps['onCheck']
|
onItemCheck?: TreeProps['onCheck']
|
||||||
onItemSelect?: TreeProps['onSelect']
|
onItemSelect?: TreeProps['onSelect']
|
||||||
onItemSetting?: (_data: any) => void
|
onItemSetting?: (_data: any) => void
|
||||||
onItemDelete?: (_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) => {
|
const boxTree: FC<BoxTreeProps> = (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<React.Key>('')
|
||||||
|
|
||||||
|
const cameraStatus = new Map([
|
||||||
|
['0', 'error'],
|
||||||
|
['1', 'success'],
|
||||||
|
['3', 'processing'],
|
||||||
|
['4', 'default'],
|
||||||
|
])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tree
|
<Tree
|
||||||
checkable={treeCheckable}
|
checkable={treeCheckable}
|
||||||
blockNode
|
blockNode
|
||||||
onSelect={onItemSelect}
|
onSelect={(selectedKeys, info) => {
|
||||||
|
setCheckedItem(selectedKeys[0])
|
||||||
|
onItemSelect?.(selectedKeys, info)
|
||||||
|
}}
|
||||||
onCheck={onItemCheck}
|
onCheck={onItemCheck}
|
||||||
treeData={data}
|
treeData={data}
|
||||||
titleRender={(_nodeData) => {
|
titleRender={(_nodeData) => {
|
||||||
return (
|
return (
|
||||||
<div className={`${componentName}-item-render`}>
|
<div className={`${componentName}-item-render`}>
|
||||||
{!_nodeData.children && <Badge style={{ marginRight: '6px' }} status="success" />}
|
{/* @ts-ignore */}
|
||||||
{_nodeData.title as any}
|
{!_nodeData.children && _nodeData.isCamera && <Badge style={{ marginRight: '6px' }} status={cameraStatus.get(_nodeData.status || '4')} />}
|
||||||
{showItemOption && <Space className={`${componentName}-item-render_right`} style={{ float:'right' }} >
|
<span
|
||||||
<ModalForm
|
// @ts-ignore
|
||||||
title="重命名"
|
style={(checkedItem === _nodeData.key) && _nodeData.isCamera ? {
|
||||||
width={600}
|
color: token.colorPrimary
|
||||||
modalProps={{ destroyOnClose: true }}
|
} : {}}
|
||||||
layout='horizontal'
|
>
|
||||||
labelCol={{ span: 6 }}
|
{_nodeData.title as any}
|
||||||
wrapperCol={{ span: 18 }}
|
</span>
|
||||||
trigger={<EditOutlined />}
|
{showItemOption && (
|
||||||
submitter={{
|
<Space className={`${componentName}-item-render_right`} style={{ float:'right' }} >
|
||||||
searchConfig: {
|
{customOptions || (
|
||||||
submitText: '确定',
|
<>
|
||||||
resetText: '取消',
|
<ModalForm
|
||||||
},
|
title="重命名"
|
||||||
}}
|
width={600}
|
||||||
onFinish={async (value) => onRenameFinish?.(value, _nodeData)}
|
modalProps={{ destroyOnClose: true }}
|
||||||
>
|
layout='horizontal'
|
||||||
<ProFormText
|
labelCol={{ span: 6 }}
|
||||||
rules={[
|
wrapperCol={{ span: 18 }}
|
||||||
{
|
trigger={<EditOutlined onClick={(e) => {
|
||||||
required: true,
|
e.preventDefault();
|
||||||
},
|
e.stopPropagation();
|
||||||
]}
|
onItemRename?.(_nodeData)
|
||||||
width="md"
|
}} />}
|
||||||
name="name"
|
submitter={{
|
||||||
label="盒子名称"
|
searchConfig: {
|
||||||
placeholder="请输入盒子名称"
|
submitText: '确定',
|
||||||
/>
|
resetText: '取消',
|
||||||
</ModalForm>
|
},
|
||||||
<SettingOutlined onClick={() => onItemSetting?.(_nodeData)} />
|
}}
|
||||||
<CloseOutlined onClick={() => onItemDelete?.(_nodeData)} />
|
onFinish={async (value) => onItemRenameFinish?.(value, _nodeData)}
|
||||||
</Space>}
|
>
|
||||||
|
<ProFormText
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
width="md"
|
||||||
|
name="name"
|
||||||
|
label="盒子名称"
|
||||||
|
placeholder="请输入盒子名称"
|
||||||
|
/>
|
||||||
|
</ModalForm>
|
||||||
|
<SettingOutlined onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
onItemSetting?.(_nodeData)}
|
||||||
|
} />
|
||||||
|
<CloseOutlined onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
onItemDelete?.(_nodeData)
|
||||||
|
}} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
23
packages/biz/src/tree/demo/customOptions.tsx
Normal file
23
packages/biz/src/tree/demo/customOptions.tsx
Normal file
@ -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 (
|
||||||
|
<div style={{ width: '320px' }}>
|
||||||
|
<Tree
|
||||||
|
data={treeData}
|
||||||
|
customOptions={(
|
||||||
|
<>
|
||||||
|
<PlayCircleOutlined />
|
||||||
|
<SettingOutlined />
|
||||||
|
<LoadingOutlined />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default demo;
|
@ -14,8 +14,11 @@ const demo = () => {
|
|||||||
<div>
|
<div>
|
||||||
{title}
|
{title}
|
||||||
<div style={{ float: 'right' }} >
|
<div style={{ float: 'right' }} >
|
||||||
<Tooltip placement="right" title={'存在0个'}>
|
<Tooltip
|
||||||
<a >包含0个</a>
|
placement="right"
|
||||||
|
title={'存在0个'}
|
||||||
|
>
|
||||||
|
<a>在0个组中包含</a>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,8 +14,15 @@ group:
|
|||||||
<code src="./demo/basic.tsx">基本用法</code>
|
<code src="./demo/basic.tsx">基本用法</code>
|
||||||
<code src="./demo/customTitleRender.tsx">自定义渲染界面</code>
|
<code src="./demo/customTitleRender.tsx">自定义渲染界面</code>
|
||||||
<code src="./demo/noOption.tsx">不展示配置项</code>
|
<code src="./demo/noOption.tsx">不展示配置项</code>
|
||||||
|
<code src="./demo/customOptions.tsx">自定义配置项</code>
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
**额外参数可以参考 antd - Tree 组件**
|
||||||
|
|
||||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| data | 数据源 | Array[] | [] | - |
|
| data | 数据源 | Array[] | [] | - |
|
||||||
|
| titleRender | 子项自定义 | ReactNode、 undefined | - | - |
|
||||||
|
| showItemOption | 是否显示额外配置功能 | boolean | true | - |
|
||||||
|
| customOptions | 自定义配置项 | any | - | - |
|
||||||
|
@ -1,3 +1,16 @@
|
|||||||
|
import { TreeDataNode } from 'antd';
|
||||||
import BoxTree from './boxTree';
|
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;
|
export default BoxTree;
|
||||||
|
@ -13,6 +13,8 @@ group:
|
|||||||
<code src="./demo/basic.tsx">基本用法</code>
|
<code src="./demo/basic.tsx">基本用法</code>
|
||||||
<code src="./demo/withModal.tsx">和Modal组合使用</code>
|
<code src="./demo/withModal.tsx">和Modal组合使用</code>
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| data | 数据源 | Array[] | [] | - |
|
| data | 数据源 | Array[] | [] | - |
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
import TreeTransfer from "./TreeTransfer";
|
import TreeTransfer from "./TreeTransfer";
|
||||||
|
|
||||||
|
export type { TreeTransferProps } from './TreeTransfer'
|
||||||
|
|
||||||
|
export * from './treeTransferHelper'
|
||||||
|
|
||||||
export default TreeTransfer
|
export default TreeTransfer
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { FC, useState } from 'react';
|
import React, { FC, useState } from 'react';
|
||||||
|
import { Modal, ModalProps, Radio, RadioGroupProps, Select, SelectProps, TransferProps, TreeDataNode, TreeProps } from 'antd';
|
||||||
import TreeTransfer from '../treeTransfer';
|
import TreeTransfer from '../treeTransfer';
|
||||||
import { Modal, ModalProps, Radio, RadioGroupProps, TransferProps, TreeDataNode } from 'antd';
|
import { ALL_LIST, BOX_TYPE_LIST } from '../utils/constants';
|
||||||
import { TreeProps } from 'antd/lib';
|
|
||||||
|
|
||||||
export interface TreeTransferModalProps {
|
export interface TreeTransferModalProps {
|
||||||
dataSource: TreeDataNode[]
|
dataSource: TreeDataNode[]
|
||||||
@ -17,7 +17,10 @@ export interface TreeTransferModalProps {
|
|||||||
open?: boolean
|
open?: boolean
|
||||||
onCancel?: ModalProps['onCancel']
|
onCancel?: ModalProps['onCancel']
|
||||||
onRadioChange?: RadioGroupProps['onChange']
|
onRadioChange?: RadioGroupProps['onChange']
|
||||||
|
onSelect?: SelectProps['onSelect']
|
||||||
modalProps?: ModalProps
|
modalProps?: ModalProps
|
||||||
|
radioProps?: RadioGroupProps
|
||||||
|
selectProps?: SelectProps
|
||||||
}
|
}
|
||||||
|
|
||||||
const TreeTransferModal: FC<TreeTransferModalProps> = (props) => {
|
const TreeTransferModal: FC<TreeTransferModalProps> = (props) => {
|
||||||
@ -31,11 +34,14 @@ const TreeTransferModal: FC<TreeTransferModalProps> = (props) => {
|
|||||||
onReset,
|
onReset,
|
||||||
onRadioChange,
|
onRadioChange,
|
||||||
onTreeCheck,
|
onTreeCheck,
|
||||||
|
onSelect,
|
||||||
targetItems,
|
targetItems,
|
||||||
modalProps,
|
modalProps,
|
||||||
|
radioProps,
|
||||||
|
selectProps,
|
||||||
} = props
|
} = props
|
||||||
|
|
||||||
const [type, setType] = useState('box')
|
const [type, setType] = useState('1')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
@ -48,17 +54,25 @@ const TreeTransferModal: FC<TreeTransferModalProps> = (props) => {
|
|||||||
{...modalProps}
|
{...modalProps}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<Radio.Group
|
<div>
|
||||||
onChange={e => {
|
<Radio.Group
|
||||||
setType(e.target.value)
|
onChange={e => {
|
||||||
onRadioChange?.(e)
|
setType(e.target.value)
|
||||||
}}
|
onRadioChange?.(e)
|
||||||
style={{ marginLeft: '24px', padding: '20px 0' }}
|
}}
|
||||||
value={type}
|
style={{ marginLeft: '24px', padding: '20px 0' }}
|
||||||
>
|
value={type}
|
||||||
<Radio value={'box'}>盒子</Radio>
|
options={BOX_TYPE_LIST}
|
||||||
<Radio value={'boxGroup'}>盒子组</Radio>
|
{...radioProps}
|
||||||
</Radio.Group>
|
/>
|
||||||
|
<Select
|
||||||
|
defaultValue={''}
|
||||||
|
style={{ marginLeft: 200, width: 150 }}
|
||||||
|
options={ALL_LIST}
|
||||||
|
onSelect={onSelect}
|
||||||
|
{...selectProps}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
{type === 'box' ?
|
{type === 'box' ?
|
||||||
(
|
(
|
||||||
<TreeTransfer
|
<TreeTransfer
|
||||||
|
@ -7,7 +7,7 @@ import { boxDataSource } from './mock'
|
|||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
const [targetItems, setTargetItems] = useState<TreeDataNode[]>([]);
|
const [targetItems, setTargetItems] = useState<TreeDataNode[]>([]);
|
||||||
const [checkedKeys, setCheckedKeys] = useState<string[]>([]);
|
const [checkedKeys, setCheckedKeys] = useState<string[]>([]);
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(true)
|
||||||
|
|
||||||
const onTreeCheck: TreeProps['onCheck'] = (keys: any, info) => {
|
const onTreeCheck: TreeProps['onCheck'] = (keys: any, info) => {
|
||||||
let _targetItems: TreeDataNode[] = []
|
let _targetItems: TreeDataNode[] = []
|
||||||
@ -47,7 +47,7 @@ const App: React.FC = () => {
|
|||||||
<TreeTransferModal
|
<TreeTransferModal
|
||||||
open={open}
|
open={open}
|
||||||
onCancel={() => setOpen(false)}
|
onCancel={() => setOpen(false)}
|
||||||
onRadioChange={() => setOpen(false)} // 顶部 radio 事件
|
onRadioChange={(e) => console.log('radioChange', e)} // 顶部 radio 事件
|
||||||
dataSource={boxDataSource} // 数据源
|
dataSource={boxDataSource} // 数据源
|
||||||
targetItems={targetItems} // 右侧选中项
|
targetItems={targetItems} // 右侧选中项
|
||||||
checkedKeys={checkedKeys} // 左侧选中
|
checkedKeys={checkedKeys} // 左侧选中
|
||||||
|
@ -12,6 +12,8 @@ group:
|
|||||||
|
|
||||||
<code src="./demo/basic.tsx">基本用法</code>
|
<code src="./demo/basic.tsx">基本用法</code>
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| data | 数据源 | Array[] | [] | - |
|
| data | 数据源 | Array[] | [] | - |
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
import TreeTransferModal from './TreeTransferModal'
|
import TreeTransferModal from './TreeTransferModal'
|
||||||
|
|
||||||
|
export type { TreeTransferModalProps } from './TreeTransferModal'
|
||||||
|
|
||||||
export default TreeTransferModal
|
export default TreeTransferModal
|
||||||
|
@ -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]);
|
|
||||||
};
|
|
@ -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;
|
|
@ -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;
|
|
@ -25,3 +25,13 @@ export const DeviceTab = {
|
|||||||
REAL_CAMERA_ONLYFACE: 7,
|
REAL_CAMERA_ONLYFACE: 7,
|
||||||
REAL_CAMERA_NOFACE_NOBOX_NODIRECONNECT: 8, // 只有普通摄像头,没有人脸、没有盒子、直连
|
REAL_CAMERA_NOFACE_NOBOX_NODIRECONNECT: 8, // 只有普通摄像头,没有人脸、没有盒子、直连
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 盒子 Tab 切换
|
||||||
|
export const BOX_TYPE_LIST = [
|
||||||
|
{ value: '1', label: '盒子' },
|
||||||
|
{ value: '2', label: '盒子组' }
|
||||||
|
]
|
||||||
|
|
||||||
|
export const ALL_LIST = [
|
||||||
|
{ value: '', label: '全部' }
|
||||||
|
]
|
||||||
|
@ -1,5 +1,43 @@
|
|||||||
# @zhst/utils
|
# @zhst/utils
|
||||||
|
|
||||||
|
## 0.7.5
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/request@0.8.4
|
||||||
|
|
||||||
|
## 0.7.4
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 新增 tree 组件的监听事件,优化 meta 全选的回调事件监听
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/request@0.8.3
|
||||||
|
|
||||||
|
## 0.7.3
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 修改 boxSelectTree 类型提示
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/request@0.8.2
|
||||||
|
|
||||||
|
## 0.7.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 优化 boxSelectTree 组件,添加可以自定义配置按钮功能
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/request@0.8.1
|
||||||
|
|
||||||
|
## 0.7.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/request@0.8.0
|
||||||
|
|
||||||
## 0.7.0
|
## 0.7.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
@ -1,358 +1 @@
|
|||||||
var _ALGORITHM_VERSION;
|
export default {};
|
||||||
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 _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
|
|
||||||
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
||||||
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
||||||
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
|
|
||||||
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
|
|
||||||
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
||||||
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(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
|
|
||||||
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
|
|
||||||
import { cloneDeep, get, isNull } from 'lodash-es';
|
|
||||||
import { dataURLToBlob } from "../file";
|
|
||||||
var proto = {
|
|
||||||
Common: {
|
|
||||||
AlgorithmVersion: {
|
|
||||||
VERSION_REID_HEAD_ATTR: '形体',
|
|
||||||
VERSION_FACE: '人脸',
|
|
||||||
VERSION_NON_MOTOR_VEHICLE: '非机动车'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
export var ALGORITHM_VERSION = (_ALGORITHM_VERSION = {}, _defineProperty(_ALGORITHM_VERSION, '7', '形体'), _defineProperty(_ALGORITHM_VERSION, '4', '人脸'), _defineProperty(_ALGORITHM_VERSION, '6', '非机动车'), _ALGORITHM_VERSION);
|
|
||||||
export var algorithmVersions = _toConsumableArray(Object.keys(ALGORITHM_VERSION));
|
|
||||||
export var getBikeExtendRect = function getBikeExtendRect(rect, maxW) {
|
|
||||||
var newRect = _objectSpread({}, rect);
|
|
||||||
//向上扩大一倍
|
|
||||||
var oldY = cloneDeep(rect.y);
|
|
||||||
newRect.y = newRect.y - newRect.h < 0 ? 0 : newRect.y - newRect.h;
|
|
||||||
newRect.h += oldY - newRect.y;
|
|
||||||
var newX = Math.round(newRect.x - newRect.w * 0.15);
|
|
||||||
if (newX < 0) {
|
|
||||||
newX = 0;
|
|
||||||
}
|
|
||||||
var newW = newRect.x - newX + newRect.w + Math.round(newRect.w * 0.15);
|
|
||||||
if (newX + newW > maxW) {
|
|
||||||
newW = maxW - newX;
|
|
||||||
}
|
|
||||||
newRect.x = newX;
|
|
||||||
newRect.w = newW;
|
|
||||||
return newRect;
|
|
||||||
};
|
|
||||||
export var getOtherExtendRect = function getOtherExtendRect(srcRect, maxW, maxH, type) {
|
|
||||||
var wExtendRadio = 0.25;
|
|
||||||
var upExtendRadio = 0.25;
|
|
||||||
var downExtendRadio = 0.25;
|
|
||||||
var fixPersonExtend = true;
|
|
||||||
var nx = 0;
|
|
||||||
var nw = 0;
|
|
||||||
nx = srcRect.x - Math.round(srcRect.w * wExtendRadio);
|
|
||||||
if (nx < 0) {
|
|
||||||
nx = 0;
|
|
||||||
}
|
|
||||||
nw = srcRect.x - nx + srcRect.w + Math.round(srcRect.w * wExtendRadio);
|
|
||||||
if (nx + nw > maxW) {
|
|
||||||
nw = maxW - nx;
|
|
||||||
}
|
|
||||||
var ny = 0;
|
|
||||||
var nh = 0;
|
|
||||||
ny = srcRect.y - Math.round(upExtendRadio * srcRect.h);
|
|
||||||
if (ny < 0) {
|
|
||||||
ny = 0;
|
|
||||||
}
|
|
||||||
nh = srcRect.y - ny + srcRect.h + Math.round(srcRect.h * downExtendRadio);
|
|
||||||
if (ny + nh > maxH) {
|
|
||||||
nh = maxH - ny;
|
|
||||||
}
|
|
||||||
var newRect = {
|
|
||||||
x: nx,
|
|
||||||
y: ny,
|
|
||||||
w: nw,
|
|
||||||
h: nh
|
|
||||||
};
|
|
||||||
if ((type === proto.Common.AlgorithmVersion.VERSION_REID_HEAD_ATTR || type === proto.Common.AlgorithmVersion.VERSION_FACE) && fixPersonExtend) {
|
|
||||||
var fixW = Math.round(nh * 0.75);
|
|
||||||
if (nw < fixW) {
|
|
||||||
// 应该扩展宽度
|
|
||||||
var newX = nx + Math.round(nw / 2.0 - 0.5 * fixW);
|
|
||||||
if (newX < 0) {
|
|
||||||
newX = 0;
|
|
||||||
}
|
|
||||||
var newW = fixW;
|
|
||||||
if (newW + newX > maxW) {
|
|
||||||
newW = maxW - newX;
|
|
||||||
}
|
|
||||||
newRect = {
|
|
||||||
x: newX,
|
|
||||||
y: ny,
|
|
||||||
w: newW,
|
|
||||||
h: nh
|
|
||||||
};
|
|
||||||
} else if (nw > fixW) {
|
|
||||||
// 应该扩展高度
|
|
||||||
var fixH = Math.round(nw * 1.333);
|
|
||||||
var newY = ny + Math.round(nh / 2.0 - 0.5 * fixH);
|
|
||||||
if (newY < 0) {
|
|
||||||
newY = 0;
|
|
||||||
}
|
|
||||||
var newH = fixH;
|
|
||||||
if (newY + newH > maxH) {
|
|
||||||
newH = maxH - newY;
|
|
||||||
}
|
|
||||||
newRect = {
|
|
||||||
x: nx,
|
|
||||||
y: newY,
|
|
||||||
w: nw,
|
|
||||||
h: newH
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return newRect;
|
|
||||||
};
|
|
||||||
export var getNormalization = function getNormalization(srcRect, maxW, maxH) {
|
|
||||||
var newRect = _objectSpread({}, srcRect);
|
|
||||||
newRect.x = srcRect.x / maxW;
|
|
||||||
newRect.y = srcRect.y / maxH;
|
|
||||||
newRect.w = srcRect.w / maxW;
|
|
||||||
newRect.h = srcRect.h / maxH;
|
|
||||||
if (newRect.x + newRect.w > 1) {
|
|
||||||
newRect.w = 1 - newRect.x;
|
|
||||||
}
|
|
||||||
if (newRect.y + newRect.h > 1) {
|
|
||||||
newRect.h = 1 - newRect.y;
|
|
||||||
}
|
|
||||||
return newRect;
|
|
||||||
};
|
|
||||||
//传入od框 穿出 od扩展框
|
|
||||||
export var getExtendRect = function getExtendRect(normalizationRect, imgW, imgH, type) {
|
|
||||||
var rect = {
|
|
||||||
x: normalizationRect.x * imgW,
|
|
||||||
y: normalizationRect.y * imgH,
|
|
||||||
w: normalizationRect.w * imgW,
|
|
||||||
h: normalizationRect.h * imgH
|
|
||||||
};
|
|
||||||
var newRect;
|
|
||||||
if (type === proto.Common.AlgorithmVersion.VERSION_NON_MOTOR_VEHICLE) {
|
|
||||||
newRect = getBikeExtendRect(rect, imgW);
|
|
||||||
} else {
|
|
||||||
newRect = getOtherExtendRect(rect, imgW, imgH, type);
|
|
||||||
}
|
|
||||||
newRect = getNormalization(newRect, imgW, imgH);
|
|
||||||
return newRect;
|
|
||||||
};
|
|
||||||
export var getTransformRect = function getTransformRect(image, transform, rect) {
|
|
||||||
var canvasRect = {
|
|
||||||
x: rect.x,
|
|
||||||
y: rect.y,
|
|
||||||
x2: rect.x + rect.w,
|
|
||||||
y2: rect.h + rect.y
|
|
||||||
};
|
|
||||||
//1.转成缩放前的坐标
|
|
||||||
var translateX = transform.translateX,
|
|
||||||
translateY = transform.translateY,
|
|
||||||
scale = transform.scale,
|
|
||||||
rotate = transform.rotate;
|
|
||||||
var originAxisRect = {
|
|
||||||
x: (canvasRect.x - translateX) / scale,
|
|
||||||
y: (canvasRect.y - translateY) / scale,
|
|
||||||
x2: (canvasRect.x2 - translateX) / scale,
|
|
||||||
y2: (canvasRect.y2 - translateY) / scale
|
|
||||||
};
|
|
||||||
//2.转成图片坐标
|
|
||||||
//不考虑旋转 图片原点就是坐标原点
|
|
||||||
var imgAxisRect = originAxisRect;
|
|
||||||
//但是旋转90度后图片不在坐标原点 加上这部分diff
|
|
||||||
if (rotate % 180 !== 0) {
|
|
||||||
//90度调整偏移量
|
|
||||||
var offsetX = -(image.height - image.width) / 2;
|
|
||||||
var offsetY = -(image.width - image.height) / 2;
|
|
||||||
imgAxisRect = {
|
|
||||||
x: originAxisRect.x - offsetX,
|
|
||||||
y: originAxisRect.y - offsetY,
|
|
||||||
x2: originAxisRect.x2 - offsetX,
|
|
||||||
y2: originAxisRect.y2 - offsetY
|
|
||||||
};
|
|
||||||
}
|
|
||||||
//3.限制框不要超出图片
|
|
||||||
var imgW = image.width;
|
|
||||||
var imgH = image.height;
|
|
||||||
if (rotate % 180 !== 0) {
|
|
||||||
var _ref = [imgH, imgW];
|
|
||||||
imgW = _ref[0];
|
|
||||||
imgH = _ref[1];
|
|
||||||
}
|
|
||||||
imgAxisRect.x = Math.min(imgW, Math.max(imgAxisRect.x, 0));
|
|
||||||
imgAxisRect.y = Math.min(imgH, Math.max(imgAxisRect.y, 0));
|
|
||||||
imgAxisRect.x2 = Math.min(imgW, Math.max(imgAxisRect.x2, 0));
|
|
||||||
imgAxisRect.y2 = Math.min(imgH, Math.max(imgAxisRect.y2, 0));
|
|
||||||
//获取归一化坐标
|
|
||||||
var endRect = {
|
|
||||||
x: imgAxisRect.x2 > imgAxisRect.x ? imgAxisRect.x : imgAxisRect.x2,
|
|
||||||
y: imgAxisRect.y2 > imgAxisRect.y ? imgAxisRect.y : imgAxisRect.y2,
|
|
||||||
w: Math.abs(imgAxisRect.x2 - imgAxisRect.x),
|
|
||||||
h: Math.abs(imgAxisRect.y2 - imgAxisRect.y)
|
|
||||||
};
|
|
||||||
return getNormalization(endRect, imgW, imgH);
|
|
||||||
};
|
|
||||||
|
|
||||||
//旋转图片后转成file 对象
|
|
||||||
export var getRotateImg = function getRotateImg(image, rotate) {
|
|
||||||
var _commonCanvas$parentN;
|
|
||||||
var imgW = image.width;
|
|
||||||
var imgH = image.height;
|
|
||||||
if (rotate % 180 !== 0) {
|
|
||||||
var _ref2 = [imgH, imgW];
|
|
||||||
imgW = _ref2[0];
|
|
||||||
imgH = _ref2[1];
|
|
||||||
}
|
|
||||||
var commonCanvas = document.createElement('canvas');
|
|
||||||
commonCanvas.width = imgW;
|
|
||||||
commonCanvas.height = imgH;
|
|
||||||
commonCanvas.style.display = 'none';
|
|
||||||
document.body.appendChild(commonCanvas);
|
|
||||||
var commonCtx = commonCanvas.getContext('2d');
|
|
||||||
//移动到图片中心 旋转
|
|
||||||
|
|
||||||
commonCtx === null || commonCtx === void 0 || commonCtx.save();
|
|
||||||
if (rotate % 180 !== 0) {
|
|
||||||
//90度调整偏移量
|
|
||||||
commonCtx === null || commonCtx === void 0 || commonCtx.translate((image.height - image.width) / 2, (image.width - image.height) / 2);
|
|
||||||
}
|
|
||||||
commonCtx === null || commonCtx === void 0 || commonCtx.translate(image.width / 2, image.height / 2);
|
|
||||||
commonCtx === null || commonCtx === void 0 || commonCtx.rotate(rotate / 180 * Math.PI);
|
|
||||||
commonCtx === null || commonCtx === void 0 || commonCtx.translate(-image.width / 2, -image.height / 2);
|
|
||||||
commonCtx === null || commonCtx === void 0 || commonCtx.drawImage(image, 0, 0);
|
|
||||||
commonCtx === null || commonCtx === void 0 || commonCtx.restore();
|
|
||||||
var dataUrl = commonCanvas.toDataURL('image/jpeg');
|
|
||||||
var blobData = dataURLToBlob(dataUrl);
|
|
||||||
var file = new window.File([blobData], "".concat(new Date().getTime()), {
|
|
||||||
type: 'image/jpeg'
|
|
||||||
});
|
|
||||||
(_commonCanvas$parentN = commonCanvas.parentNode) === null || _commonCanvas$parentN === void 0 || _commonCanvas$parentN.removeChild(commonCanvas);
|
|
||||||
return file;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 格式化工具
|
|
||||||
* @param originData
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export var getOdRect = function getOdRect(originData) {
|
|
||||||
var data = get(originData, 'objects', []).filter(function (v) {
|
|
||||||
return !isNull(get(v, 'infoOnSource.bboxInFrame.bboxRatio'));
|
|
||||||
}).map(function (v, index) {
|
|
||||||
// objectId==0 特征没有提取到过滤1掉
|
|
||||||
var rect = get(v, 'infoOnSource.bboxInFrame.bboxRatio');
|
|
||||||
var extendBox = get(v, 'infoOnSource.bboxInFrame.extendBoxRatio');
|
|
||||||
var frameTimestamp = get(v, 'timestamp'); //时间戳创建档案的时候需要
|
|
||||||
var qualityScore = get(v, 'qualityScore');
|
|
||||||
var algorithmVersion = get(v, 'objectType') === 'OBJECT_TYPE_PEDESTRAIN' ? 'VERSION_REID_HEAD_ATTR' : get(v, 'objectType') === 'OBJECT_TYPE_FACE' ? 'VERSION_FACE' : 'VERSION_REID_HEAD_ATTR';
|
|
||||||
var featureData = get(v, 'feature', []).filter(function (v) {
|
|
||||||
return v.type === 'FEATURE_TYPE_BYTE';
|
|
||||||
});
|
|
||||||
var objectRectIndex = algorithmVersion === 'VERSION_FACE' ? 0 : 1;
|
|
||||||
var objectType = get(v, 'objectType');
|
|
||||||
var objectId = get(v, 'objectIndex.objectId');
|
|
||||||
var 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(function (v) {
|
|
||||||
return v.objectId !== '0';
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
throw new Error('empty');
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
//档案库od
|
|
||||||
export var getOdRectV2 = function getOdRectV2(originData) {
|
|
||||||
var resp = originData.odv2Result[0];
|
|
||||||
var subObjects = []; //形体
|
|
||||||
var data = get(resp, 'objects', []).filter(function (v) {
|
|
||||||
return !isNull(get(v, 'subObjects[0].infoOnSource.bboxInFrame.bboxRatio'));
|
|
||||||
}).map(function (v, index) {
|
|
||||||
var rect = get(v, 'infoOnSource.bboxInFrame.bboxRatio');
|
|
||||||
var qualityScore = get(v, 'qualityScore');
|
|
||||||
var algorithmVersion = get(v, 'objectType');
|
|
||||||
var featrueData = get(v, 'feature', []).filter(function (v) {
|
|
||||||
return v.name === 'feature-body' || v.name === 'feature-face';
|
|
||||||
});
|
|
||||||
var objectRectIndex = algorithmVersion === 'OBJECT_TYPE_FACE' ? 0 : 1;
|
|
||||||
var objectType = get(v, 'objectType');
|
|
||||||
var objectId = get(v, 'objectIndex.objectId');
|
|
||||||
//如果存在subObjects的数组不为null表示形体里面带人脸,人脸的od框也要显示出来
|
|
||||||
if (get(v, 'subObjects', []).length) {
|
|
||||||
get(v, 'subObjects', []).forEach(function (e) {
|
|
||||||
var rect = get(e, 'infoOnSource.bboxInFrame.bboxRatio');
|
|
||||||
var qualityScore = get(e, 'qualityScore');
|
|
||||||
var algorithmVersion = get(e, 'objectType');
|
|
||||||
var featrueData = get(e, 'feature', []).filter(function (v) {
|
|
||||||
return v.name === 'feature-body' || v.name === 'feature-face';
|
|
||||||
});
|
|
||||||
var objectRectIndex = algorithmVersion === 'OBJECT_TYPE_FACE' ? 0 : 1;
|
|
||||||
var objectType = get(e, 'objectType');
|
|
||||||
var 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: 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
|
|
||||||
};
|
|
||||||
});
|
|
||||||
var brr = data.concat(subObjects).map(function (v, vs) {
|
|
||||||
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;
|
|
||||||
};
|
|
@ -26,15 +26,12 @@ export var formateDuration = function formateDuration(diff) {
|
|||||||
if (minutes > 0) {
|
if (minutes > 0) {
|
||||||
returnStr = minutes + '分'; //+ returnStr;
|
returnStr = minutes + '分'; //+ returnStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hours > 0) {
|
if (hours > 0) {
|
||||||
returnStr = hours + '小时'; // + returnStr;
|
returnStr = hours + '小时'; // + returnStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (days > 0) {
|
if (days > 0) {
|
||||||
returnStr = days + '天'; //+ returnStr;
|
returnStr = days + '天'; //+ returnStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnStr;
|
return returnStr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@zhst/func",
|
"name": "@zhst/func",
|
||||||
"version": "0.7.0",
|
"version": "0.7.5",
|
||||||
"description": "函数合集",
|
"description": "函数合集",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"hooks"
|
"hooks"
|
||||||
|
@ -1,367 +1 @@
|
|||||||
import { cloneDeep, get, isNull } from 'lodash-es';
|
export default {}
|
||||||
import { dataURLToBlob } from '../file';
|
|
||||||
import { IOdRectOrigin, Rect } from '@zhst/types';
|
|
||||||
|
|
||||||
const proto = {
|
|
||||||
Common: {
|
|
||||||
AlgorithmVersion: {
|
|
||||||
VERSION_REID_HEAD_ATTR: '形体',
|
|
||||||
VERSION_FACE: '人脸',
|
|
||||||
VERSION_NON_MOTOR_VEHICLE: '非机动车',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
export const ALGORITHM_VERSION = {
|
|
||||||
['7']: '形体',
|
|
||||||
['4']: '人脸',
|
|
||||||
['6']: '非机动车',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const algorithmVersions = [...Object.keys(ALGORITHM_VERSION)]
|
|
||||||
|
|
||||||
export const getBikeExtendRect = (rect: Rect, maxW: number) => {
|
|
||||||
const newRect = { ...rect };
|
|
||||||
//向上扩大一倍
|
|
||||||
const oldY = cloneDeep(rect.y);
|
|
||||||
newRect.y = newRect.y - newRect.h < 0 ? 0 : newRect.y - newRect.h;
|
|
||||||
newRect.h += oldY - newRect.y;
|
|
||||||
|
|
||||||
let newX = Math.round(newRect.x - newRect.w * 0.15);
|
|
||||||
if (newX < 0) {
|
|
||||||
newX = 0;
|
|
||||||
}
|
|
||||||
let newW = newRect.x - newX + newRect.w + Math.round(newRect.w * 0.15);
|
|
||||||
if (newX + newW > maxW) {
|
|
||||||
newW = maxW - newX;
|
|
||||||
}
|
|
||||||
newRect.x = newX;
|
|
||||||
newRect.w = newW;
|
|
||||||
|
|
||||||
return newRect;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getOtherExtendRect = (srcRect: Rect, maxW: number, maxH: number, type: string) => {
|
|
||||||
const wExtendRadio = 0.25;
|
|
||||||
const upExtendRadio = 0.25;
|
|
||||||
const downExtendRadio = 0.25;
|
|
||||||
const fixPersonExtend = true;
|
|
||||||
|
|
||||||
let nx = 0;
|
|
||||||
let nw = 0;
|
|
||||||
|
|
||||||
nx = srcRect.x - Math.round(srcRect.w * wExtendRadio);
|
|
||||||
if (nx < 0) {
|
|
||||||
nx = 0;
|
|
||||||
}
|
|
||||||
nw = srcRect.x - nx + srcRect.w + Math.round(srcRect.w * wExtendRadio);
|
|
||||||
if (nx + nw > maxW) {
|
|
||||||
nw = maxW - nx;
|
|
||||||
}
|
|
||||||
|
|
||||||
let ny = 0;
|
|
||||||
let nh = 0;
|
|
||||||
ny = srcRect.y - Math.round(upExtendRadio * srcRect.h);
|
|
||||||
if (ny < 0) {
|
|
||||||
ny = 0;
|
|
||||||
}
|
|
||||||
nh = srcRect.y - ny + srcRect.h + Math.round(srcRect.h * downExtendRadio);
|
|
||||||
if (ny + nh > maxH) {
|
|
||||||
nh = maxH - ny;
|
|
||||||
}
|
|
||||||
|
|
||||||
let newRect = {
|
|
||||||
x: nx,
|
|
||||||
y: ny,
|
|
||||||
w: nw,
|
|
||||||
h: nh,
|
|
||||||
};
|
|
||||||
if (
|
|
||||||
(type === proto.Common.AlgorithmVersion.VERSION_REID_HEAD_ATTR ||
|
|
||||||
type === proto.Common.AlgorithmVersion.VERSION_FACE) &&
|
|
||||||
fixPersonExtend
|
|
||||||
) {
|
|
||||||
const fixW = Math.round(nh * 0.75);
|
|
||||||
if (nw < fixW) {
|
|
||||||
// 应该扩展宽度
|
|
||||||
let newX = nx + Math.round(nw / 2.0 - 0.5 * fixW);
|
|
||||||
if (newX < 0) {
|
|
||||||
newX = 0;
|
|
||||||
}
|
|
||||||
let newW = fixW;
|
|
||||||
if (newW + newX > maxW) {
|
|
||||||
newW = maxW - newX;
|
|
||||||
}
|
|
||||||
|
|
||||||
newRect = {
|
|
||||||
x: newX,
|
|
||||||
y: ny,
|
|
||||||
w: newW,
|
|
||||||
h: nh,
|
|
||||||
};
|
|
||||||
} else if (nw > fixW) {
|
|
||||||
// 应该扩展高度
|
|
||||||
const fixH = Math.round(nw * 1.333);
|
|
||||||
let newY = ny + Math.round(nh / 2.0 - 0.5 * fixH);
|
|
||||||
if (newY < 0) {
|
|
||||||
newY = 0;
|
|
||||||
}
|
|
||||||
let newH = fixH;
|
|
||||||
if (newY + newH > maxH) {
|
|
||||||
newH = maxH - newY;
|
|
||||||
}
|
|
||||||
newRect = {
|
|
||||||
x: nx,
|
|
||||||
y: newY,
|
|
||||||
w: nw,
|
|
||||||
h: newH,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return newRect;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getNormalization = (srcRect: Rect, maxW: number, maxH: number) => {
|
|
||||||
const newRect = {
|
|
||||||
...srcRect,
|
|
||||||
};
|
|
||||||
newRect.x = srcRect.x / maxW;
|
|
||||||
newRect.y = srcRect.y / maxH;
|
|
||||||
newRect.w = srcRect.w / maxW;
|
|
||||||
newRect.h = srcRect.h / maxH;
|
|
||||||
if (newRect.x + newRect.w > 1) {
|
|
||||||
newRect.w = 1 - newRect.x;
|
|
||||||
}
|
|
||||||
if (newRect.y + newRect.h > 1) {
|
|
||||||
newRect.h = 1 - newRect.y;
|
|
||||||
}
|
|
||||||
return newRect;
|
|
||||||
};
|
|
||||||
//传入od框 穿出 od扩展框
|
|
||||||
export const getExtendRect = (normalizationRect: Rect, imgW: number, imgH: number, type: string) => {
|
|
||||||
const rect = {
|
|
||||||
x: normalizationRect.x * imgW,
|
|
||||||
y: normalizationRect.y * imgH,
|
|
||||||
w: normalizationRect.w * imgW,
|
|
||||||
h: normalizationRect.h * imgH,
|
|
||||||
};
|
|
||||||
|
|
||||||
let newRect;
|
|
||||||
if (type === proto.Common.AlgorithmVersion.VERSION_NON_MOTOR_VEHICLE) {
|
|
||||||
newRect = getBikeExtendRect(rect, imgW);
|
|
||||||
} else {
|
|
||||||
newRect = getOtherExtendRect(rect, imgW, imgH, type);
|
|
||||||
}
|
|
||||||
newRect = getNormalization(newRect, imgW, imgH);
|
|
||||||
return newRect;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getTransformRect = (image: { height: number; width: number; }, transform: { translateX: any; translateY: any; scale: any; rotate: any; }, rect: Rect) => {
|
|
||||||
const canvasRect = {
|
|
||||||
x: rect.x,
|
|
||||||
y: rect.y,
|
|
||||||
x2: rect.x + rect.w,
|
|
||||||
y2: rect.h + rect.y,
|
|
||||||
};
|
|
||||||
//1.转成缩放前的坐标
|
|
||||||
const { translateX, translateY, scale, rotate } = transform;
|
|
||||||
const originAxisRect = {
|
|
||||||
x: (canvasRect.x - translateX) / scale,
|
|
||||||
y: (canvasRect.y - translateY) / scale,
|
|
||||||
x2: (canvasRect.x2 - translateX) / scale,
|
|
||||||
y2: (canvasRect.y2 - translateY) / scale,
|
|
||||||
};
|
|
||||||
//2.转成图片坐标
|
|
||||||
//不考虑旋转 图片原点就是坐标原点
|
|
||||||
let imgAxisRect = originAxisRect;
|
|
||||||
//但是旋转90度后图片不在坐标原点 加上这部分diff
|
|
||||||
if (rotate % 180 !== 0) {
|
|
||||||
//90度调整偏移量
|
|
||||||
const offsetX = -(image.height - image.width) / 2;
|
|
||||||
const offsetY = -(image.width - image.height) / 2;
|
|
||||||
imgAxisRect = {
|
|
||||||
x: originAxisRect.x - offsetX,
|
|
||||||
y: originAxisRect.y - offsetY,
|
|
||||||
x2: originAxisRect.x2 - offsetX,
|
|
||||||
y2: originAxisRect.y2 - offsetY,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
//3.限制框不要超出图片
|
|
||||||
let imgW = image.width;
|
|
||||||
let imgH = image.height;
|
|
||||||
if (rotate % 180 !== 0) {
|
|
||||||
[imgW, imgH] = [imgH, imgW];
|
|
||||||
}
|
|
||||||
imgAxisRect.x = Math.min(imgW, Math.max(imgAxisRect.x, 0));
|
|
||||||
imgAxisRect.y = Math.min(imgH, Math.max(imgAxisRect.y, 0));
|
|
||||||
imgAxisRect.x2 = Math.min(imgW, Math.max(imgAxisRect.x2, 0));
|
|
||||||
imgAxisRect.y2 = Math.min(imgH, Math.max(imgAxisRect.y2, 0));
|
|
||||||
//获取归一化坐标
|
|
||||||
const endRect = {
|
|
||||||
x: imgAxisRect.x2 > imgAxisRect.x ? imgAxisRect.x : imgAxisRect.x2,
|
|
||||||
y: imgAxisRect.y2 > imgAxisRect.y ? imgAxisRect.y : imgAxisRect.y2,
|
|
||||||
w: Math.abs(imgAxisRect.x2 - imgAxisRect.x),
|
|
||||||
h: Math.abs(imgAxisRect.y2 - imgAxisRect.y),
|
|
||||||
};
|
|
||||||
|
|
||||||
return getNormalization(endRect, imgW, imgH);
|
|
||||||
};
|
|
||||||
|
|
||||||
//旋转图片后转成file 对象
|
|
||||||
export const getRotateImg = (image: HTMLImageElement, rotate: number) => {
|
|
||||||
let imgW = image.width;
|
|
||||||
let imgH = image.height;
|
|
||||||
if (rotate % 180 !== 0) {
|
|
||||||
[imgW, imgH] = [imgH, imgW];
|
|
||||||
}
|
|
||||||
const commonCanvas = document.createElement('canvas');
|
|
||||||
commonCanvas.width = imgW;
|
|
||||||
commonCanvas.height = imgH;
|
|
||||||
commonCanvas.style.display = 'none';
|
|
||||||
document.body.appendChild(commonCanvas);
|
|
||||||
const commonCtx = commonCanvas.getContext('2d');
|
|
||||||
//移动到图片中心 旋转
|
|
||||||
|
|
||||||
commonCtx?.save();
|
|
||||||
if (rotate % 180 !== 0) {
|
|
||||||
//90度调整偏移量
|
|
||||||
commonCtx?.translate((image.height - image.width) / 2, (image.width - image.height) / 2);
|
|
||||||
}
|
|
||||||
commonCtx?.translate(image.width / 2, image.height / 2);
|
|
||||||
commonCtx?.rotate((rotate / 180) * Math.PI);
|
|
||||||
commonCtx?.translate(-image.width / 2, -image.height / 2);
|
|
||||||
commonCtx?.drawImage(image, 0, 0);
|
|
||||||
commonCtx?.restore();
|
|
||||||
|
|
||||||
const dataUrl = commonCanvas.toDataURL('image/jpeg');
|
|
||||||
const blobData = dataURLToBlob(dataUrl);
|
|
||||||
const file = new window.File([blobData], `${new Date().getTime()}`, {
|
|
||||||
type: 'image/jpeg',
|
|
||||||
});
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
@ -1,5 +1,45 @@
|
|||||||
# @zhst/hooks
|
# @zhst/hooks
|
||||||
|
|
||||||
|
## 0.8.4
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- @zhst/func@0.7.5
|
||||||
|
|
||||||
|
## 0.8.3
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 新增 tree 组件的监听事件,优化 meta 全选的回调事件监听
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/func@0.7.4
|
||||||
|
|
||||||
|
## 0.8.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 修改 boxSelectTree 类型提示
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/func@0.7.3
|
||||||
|
|
||||||
|
## 0.8.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 优化 boxSelectTree 组件,添加可以自定义配置按钮功能
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/func@0.7.2
|
||||||
|
|
||||||
|
## 0.8.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- @zhst/biz 优化数组件
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- @zhst/func@0.7.1
|
||||||
|
|
||||||
## 0.7.0
|
## 0.7.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
@ -2,8 +2,8 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" ==
|
|||||||
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 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 _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 _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(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
|
||||||
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
|
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 { useLatest } from 'ahooks';
|
import { useLatest } from 'ahooks';
|
||||||
import events from 'events';
|
import events from 'events';
|
||||||
import { get, isArray } from '@zhst/func';
|
import { get, isArray } from '@zhst/func';
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@zhst/hooks",
|
"name": "@zhst/hooks",
|
||||||
"version": "0.7.0",
|
"version": "0.8.4",
|
||||||
"description": "hooks合集",
|
"description": "hooks合集",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"hooks"
|
"hooks"
|
||||||
|
@ -1,5 +1,74 @@
|
|||||||
# @zhst/utils
|
# @zhst/utils
|
||||||
|
|
||||||
|
## 0.9.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 添加数据为空时自定义
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/meta@0.9.1
|
||||||
|
|
||||||
|
## 0.9.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- 修改 metad 大图组建
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/meta@0.9.0
|
||||||
|
|
||||||
|
## 0.8.5
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- @zhst/func@0.7.5
|
||||||
|
- @zhst/hooks@0.8.4
|
||||||
|
- @zhst/meta@0.8.5
|
||||||
|
- 修改大图组组建的手动绘制截图逻辑
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/meta@0.8.5
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
|
- 修改 boxSelectTree 类型提示
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/hooks@0.8.2
|
||||||
|
- @zhst/func@0.7.3
|
||||||
|
- @zhst/meta@0.8.3
|
||||||
|
|
||||||
|
## 0.8.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 优化 boxSelectTree 组件,添加可以自定义配置按钮功能
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/hooks@0.8.1
|
||||||
|
- @zhst/func@0.7.2
|
||||||
|
- @zhst/meta@0.8.2
|
||||||
|
|
||||||
|
## 0.8.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/hooks@0.8.0
|
||||||
|
- @zhst/func@0.7.1
|
||||||
|
- @zhst/meta@0.8.1
|
||||||
|
|
||||||
## 0.8.0
|
## 0.8.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
@ -13,10 +13,9 @@ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o =
|
|||||||
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
||||||
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
||||||
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
||||||
import React, { useEffect, useState, useCallback, useRef, useImperativeHandle } from 'react';
|
import React, { useEffect, useState, useRef, useImperativeHandle } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { useLatest } from '@zhst/hooks';
|
import { get, pick, isNull, generateImg, dataURLToBlob, getTransforms, addEventListenerWrapper, getFileByRect } from '@zhst/func';
|
||||||
import { get, pick, isNull, generateImg, dataURLToBlob, getOdRect, getExtendRect, getTransformRect, getRotateImg, getTransforms, addEventListenerWrapper, getFileByRect } from '@zhst/func';
|
|
||||||
import Align from 'rc-align';
|
import Align from 'rc-align';
|
||||||
import { Button, Empty } from '..';
|
import { Button, Empty } from '..';
|
||||||
import Icon from "../iconfont";
|
import Icon from "../iconfont";
|
||||||
@ -24,6 +23,7 @@ import { Cropper, Viewer, EVENT_VIEWER_TRANSFORM_CHANGE, EVENT_VIEWER_READY, EVE
|
|||||||
import BtnGroup from "./components/BtnGroup";
|
import BtnGroup from "./components/BtnGroup";
|
||||||
import "./index.less";
|
import "./index.less";
|
||||||
import { defaultAlignOption, CROP_TYPE } from "../utils/constants";
|
import { defaultAlignOption, CROP_TYPE } from "../utils/constants";
|
||||||
|
import { getOdRect, getExtendRect, getTransformRect, getRotateImg } from "./bigImagePreviewHelper";
|
||||||
var componentName = "zhst-image__img-view";
|
var componentName = "zhst-image__img-view";
|
||||||
var cropBtnDataSource = [{
|
var cropBtnDataSource = [{
|
||||||
key: 'close',
|
key: 'close',
|
||||||
@ -55,7 +55,7 @@ export var BigImagePreview = /*#__PURE__*/React.forwardRef(function (props, ref)
|
|||||||
var width = props.width,
|
var width = props.width,
|
||||||
height = props.height,
|
height = props.height,
|
||||||
_props$showScore = props.showScore,
|
_props$showScore = props.showScore,
|
||||||
showScore = _props$showScore === void 0 ? true : _props$showScore,
|
showScore = _props$showScore === void 0 ? false : _props$showScore,
|
||||||
data = props.data,
|
data = props.data,
|
||||||
_props$showOpt = props.showOpt,
|
_props$showOpt = props.showOpt,
|
||||||
showOpt = _props$showOpt === void 0 ? false : _props$showOpt,
|
showOpt = _props$showOpt === void 0 ? false : _props$showOpt,
|
||||||
@ -67,14 +67,21 @@ export var BigImagePreview = /*#__PURE__*/React.forwardRef(function (props, ref)
|
|||||||
screenshotButtonRender = _props$screenshotButt2 === void 0 ? function () {
|
screenshotButtonRender = _props$screenshotButt2 === void 0 ? function () {
|
||||||
return /*#__PURE__*/React.createElement("div", {
|
return /*#__PURE__*/React.createElement("div", {
|
||||||
style: {
|
style: {
|
||||||
color: '#fff'
|
color: '#fff',
|
||||||
|
width: '80px',
|
||||||
|
top: 0,
|
||||||
|
fontSize: 12
|
||||||
}
|
}
|
||||||
}, "\u56DE\u8C03DOM");
|
}, "\u56DE\u8C03DOM");
|
||||||
} : _props$screenshotButt2,
|
} : _props$screenshotButt2,
|
||||||
_props$hideLeftTopBtn = props.hideLeftTopBtn,
|
_props$hideLeftTopBtn = props.hideLeftTopBtn,
|
||||||
hideLeftTopBtn = _props$hideLeftTopBtn === void 0 ? true : _props$hideLeftTopBtn,
|
hideLeftTopBtn = _props$hideLeftTopBtn === void 0 ? true : _props$hideLeftTopBtn,
|
||||||
|
onDraw = props.onDraw,
|
||||||
_props$viewOption = props.viewOption,
|
_props$viewOption = props.viewOption,
|
||||||
viewOption = _props$viewOption === void 0 ? {} : _props$viewOption;
|
viewOption = _props$viewOption === void 0 ? {} : _props$viewOption,
|
||||||
|
type = props.type,
|
||||||
|
hideTypeBtns = props.hideTypeBtns,
|
||||||
|
customEmpty = props.customEmpty;
|
||||||
var imageKey = data.imageKey,
|
var imageKey = data.imageKey,
|
||||||
attachImg = data.attachImg,
|
attachImg = data.attachImg,
|
||||||
odRect = data.odRect,
|
odRect = data.odRect,
|
||||||
@ -82,22 +89,15 @@ export var BigImagePreview = /*#__PURE__*/React.forwardRef(function (props, ref)
|
|||||||
_data$objects = data.objects,
|
_data$objects = data.objects,
|
||||||
objects = _data$objects === void 0 ? [] : _data$objects;
|
objects = _data$objects === void 0 ? [] : _data$objects;
|
||||||
var imgContainerRef = React.useRef(null);
|
var imgContainerRef = React.useRef(null);
|
||||||
var _useState = useState(false),
|
|
||||||
_useState2 = _slicedToArray(_useState, 2),
|
|
||||||
isReady = _useState2[0],
|
|
||||||
setIsReady = _useState2[1];
|
|
||||||
var init = useCallback(function ($container) {
|
|
||||||
imgContainerRef.current = $container;
|
|
||||||
setIsReady(true);
|
|
||||||
}, []);
|
|
||||||
// ============================= viewer =========================
|
// ============================= viewer =========================
|
||||||
var imgInsRef = useRef(null);
|
var imgInsRef = useRef(null);
|
||||||
var _useState3 = useState(false),
|
var _useState = useState(false),
|
||||||
_useState4 = _slicedToArray(_useState3, 2),
|
_useState2 = _slicedToArray(_useState, 2),
|
||||||
isImgReady = _useState4[0],
|
isImgReady = _useState2[0],
|
||||||
setIsImgReady = _useState4[1];
|
setIsImgReady = _useState2[1];
|
||||||
useEffect(function () {
|
useEffect(function () {
|
||||||
if (!isReady || !(imgContainerRef !== null && imgContainerRef !== void 0 && imgContainerRef.current)) return;
|
if (!(imgContainerRef !== null && imgContainerRef !== void 0 && imgContainerRef.current)) return;
|
||||||
var handleReady = addEventListenerWrapper(imgContainerRef.current, EVENT_VIEWER_READY, function () {
|
var handleReady = addEventListenerWrapper(imgContainerRef.current, EVENT_VIEWER_READY, function () {
|
||||||
setIsImgReady(true);
|
setIsImgReady(true);
|
||||||
});
|
});
|
||||||
@ -113,7 +113,7 @@ export var BigImagePreview = /*#__PURE__*/React.forwardRef(function (props, ref)
|
|||||||
imgInsRef === null || imgInsRef === void 0 || (_imgInsRef$current = imgInsRef.current) === null || _imgInsRef$current === void 0 || (_imgInsRef$current$de = _imgInsRef$current.destroy) === null || _imgInsRef$current$de === void 0 || _imgInsRef$current$de.call(_imgInsRef$current);
|
imgInsRef === null || imgInsRef === void 0 || (_imgInsRef$current = imgInsRef.current) === null || _imgInsRef$current === void 0 || (_imgInsRef$current$de = _imgInsRef$current.destroy) === null || _imgInsRef$current$de === void 0 || _imgInsRef$current$de.call(_imgInsRef$current);
|
||||||
imgInsRef.current = null;
|
imgInsRef.current = null;
|
||||||
};
|
};
|
||||||
}, [isReady, imageKey]);
|
}, [imageKey]);
|
||||||
|
|
||||||
// ============================= viewer操作按钮 =========================
|
// ============================= viewer操作按钮 =========================
|
||||||
var handleOptClick = function handleOptClick(v) {
|
var handleOptClick = function handleOptClick(v) {
|
||||||
@ -134,42 +134,42 @@ export var BigImagePreview = /*#__PURE__*/React.forwardRef(function (props, ref)
|
|||||||
// ============================= cropper =========================
|
// ============================= cropper =========================
|
||||||
// 手动截图相关参数
|
// 手动截图相关参数
|
||||||
var cropInsRef = useRef(null);
|
var cropInsRef = useRef(null);
|
||||||
var _useState5 = useState(showOpt),
|
var _useState3 = useState(showOpt),
|
||||||
|
_useState4 = _slicedToArray(_useState3, 2),
|
||||||
|
showCrop = _useState4[0],
|
||||||
|
setShowCrop = _useState4[1];
|
||||||
|
var _useState5 = useState(type || CROP_TYPE['AUTO']),
|
||||||
_useState6 = _slicedToArray(_useState5, 2),
|
_useState6 = _slicedToArray(_useState5, 2),
|
||||||
showCrop = _useState6[0],
|
cropType = _useState6[0],
|
||||||
setShowCrop = _useState6[1];
|
setCropType = _useState6[1];
|
||||||
var _useState7 = useState(CROP_TYPE['AUTO']),
|
|
||||||
_useState8 = _slicedToArray(_useState7, 2),
|
|
||||||
cropType = _useState8[0],
|
|
||||||
setCropType = _useState8[1];
|
|
||||||
|
|
||||||
// 自动截图相关参数
|
// 自动截图相关参数
|
||||||
|
var _useState7 = useState([]),
|
||||||
|
_useState8 = _slicedToArray(_useState7, 2),
|
||||||
|
odList = _useState8[0],
|
||||||
|
setOdList = _useState8[1];
|
||||||
var _useState9 = useState([]),
|
var _useState9 = useState([]),
|
||||||
_useState10 = _slicedToArray(_useState9, 2),
|
_useState10 = _slicedToArray(_useState9, 2),
|
||||||
odList = _useState10[0],
|
extendOdList = _useState10[0],
|
||||||
setOdList = _useState10[1];
|
setExtendOdList = _useState10[1];
|
||||||
var _useState11 = useState([]),
|
var _useState11 = useState(null),
|
||||||
_useState12 = _slicedToArray(_useState11, 2),
|
_useState12 = _slicedToArray(_useState11, 2),
|
||||||
extendOdList = _useState12[0],
|
selectRectId = _useState12[0],
|
||||||
setExtendOdList = _useState12[1];
|
setSelectRectId = _useState12[1];
|
||||||
var _useState13 = useState(null),
|
|
||||||
_useState14 = _slicedToArray(_useState13, 2),
|
|
||||||
selectRectId = _useState14[0],
|
|
||||||
setSelectRectId = _useState14[1];
|
|
||||||
|
|
||||||
// 定位按钮相关参数
|
// 定位按钮相关参数
|
||||||
var alginContainerRef = useRef(null);
|
var alginContainerRef = useRef(null);
|
||||||
var alignRef = useRef(null);
|
var alignRef = useRef(null);
|
||||||
var _useState15 = useState(null),
|
var _useState13 = useState(null),
|
||||||
_useState16 = _slicedToArray(_useState15, 2),
|
_useState14 = _slicedToArray(_useState13, 2),
|
||||||
cropRect = _useState16[0],
|
cropRect = _useState14[0],
|
||||||
setCropRect = _useState16[1];
|
setCropRect = _useState14[1];
|
||||||
|
|
||||||
// 选中的版本号
|
// 选中的版本号
|
||||||
var _useState17 = useState(null),
|
var _useState15 = useState(null),
|
||||||
_useState18 = _slicedToArray(_useState17, 2),
|
_useState16 = _slicedToArray(_useState15, 2),
|
||||||
selectAlgorithmVersion = _useState18[0],
|
selectAlgorithmVersion = _useState16[0],
|
||||||
setSelectAlgorithmVersion = _useState18[1];
|
setSelectAlgorithmVersion = _useState16[1];
|
||||||
var handlerCropStartRef = useRef(null);
|
var handlerCropStartRef = useRef(null);
|
||||||
var handlerCropEndRef = useRef(null);
|
var handlerCropEndRef = useRef(null);
|
||||||
var handleShapeSelectRef = useRef(null);
|
var handleShapeSelectRef = useRef(null);
|
||||||
@ -185,6 +185,8 @@ export var BigImagePreview = /*#__PURE__*/React.forwardRef(function (props, ref)
|
|||||||
cropInsRef.current = null;
|
cropInsRef.current = null;
|
||||||
};
|
};
|
||||||
}, [isImgReady, showCrop, cropType, imageKey]);
|
}, [isImgReady, showCrop, cropType, imageKey]);
|
||||||
|
|
||||||
|
// 初始化页面的绘制矩形
|
||||||
var initData = function initData(_objects) {
|
var initData = function initData(_objects) {
|
||||||
var imgIns = imgInsRef.current;
|
var imgIns = imgInsRef.current;
|
||||||
var _odRect = odRect;
|
var _odRect = odRect;
|
||||||
@ -210,7 +212,7 @@ export var BigImagePreview = /*#__PURE__*/React.forwardRef(function (props, ref)
|
|||||||
var shapeList = odList.map(function (rect) {
|
var shapeList = odList.map(function (rect) {
|
||||||
return _objectSpread(_objectSpread({}, rect), {}, {
|
return _objectSpread(_objectSpread({}, rect), {}, {
|
||||||
selectAble: true,
|
selectAble: true,
|
||||||
id: rect['id'],
|
id: ['id'],
|
||||||
algorithmVersion: rect.algorithmVersion
|
algorithmVersion: rect.algorithmVersion
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -223,28 +225,49 @@ export var BigImagePreview = /*#__PURE__*/React.forwardRef(function (props, ref)
|
|||||||
});
|
});
|
||||||
setExtendOdList(extendRect);
|
setExtendOdList(extendRect);
|
||||||
imgIns.replaceShape(shapeList);
|
imgIns.replaceShape(shapeList);
|
||||||
handleShapeSelectRef.current = addEventListenerWrapper(imgContainerRef.current, 'shape-select', function (e) {
|
// 框选监听事件
|
||||||
var id = e.detail;
|
handleShapeSelectRef.current = addEventListenerWrapper(imgContainerRef.current, 'shape-select', /*#__PURE__*/function () {
|
||||||
setSelectRectId(id);
|
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(e) {
|
||||||
var selectShape = shapeList.find(function (v) {
|
var id, selectShape, axisRect, _rect2;
|
||||||
return v['id'] === id;
|
return _regeneratorRuntime().wrap(function _callee$(_context) {
|
||||||
});
|
while (1) switch (_context.prev = _context.next) {
|
||||||
if (selectShape) {
|
case 0:
|
||||||
setSelectAlgorithmVersion(selectShape['algorithmVersion']);
|
id = e.detail;
|
||||||
//换算成屏幕坐标
|
setSelectRectId(id);
|
||||||
var axisRect = imgIns.imgRectAxisToCanvasAxisRect(selectShape);
|
selectShape = shapeList.find(function (v) {
|
||||||
var _rect = {
|
return v['id'] === id;
|
||||||
x: axisRect.x2 > axisRect.x ? axisRect.x : axisRect.x2,
|
});
|
||||||
y: axisRect.y2 > axisRect.y ? axisRect.y : axisRect.y2,
|
if (selectShape) {
|
||||||
w: Math.abs(axisRect.x2 - axisRect.x),
|
setSelectAlgorithmVersion(selectShape['algorithmVersion']);
|
||||||
h: Math.abs(axisRect.y2 - axisRect.y)
|
//换算成屏幕坐标
|
||||||
};
|
axisRect = imgIns.imgRectAxisToCanvasAxisRect(selectShape);
|
||||||
setCropRect(_rect);
|
_rect2 = {
|
||||||
} else {
|
x: axisRect.x2 > axisRect.x ? axisRect.x : axisRect.x2,
|
||||||
// @ts-ignore
|
y: axisRect.y2 > axisRect.y ? axisRect.y : axisRect.y2,
|
||||||
setCropRect(null);
|
w: Math.abs(axisRect.x2 - axisRect.x),
|
||||||
}
|
h: Math.abs(axisRect.y2 - axisRect.y)
|
||||||
});
|
};
|
||||||
|
setCropRect(_rect2);
|
||||||
|
onDraw === null || onDraw === void 0 || onDraw({
|
||||||
|
rectList: [_rect2],
|
||||||
|
extendRectList: [_rect2],
|
||||||
|
imgKey: imageKey,
|
||||||
|
selectIndex: id
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// @ts-ignore
|
||||||
|
setCropRect(null);
|
||||||
|
}
|
||||||
|
case 4:
|
||||||
|
case "end":
|
||||||
|
return _context.stop();
|
||||||
|
}
|
||||||
|
}, _callee);
|
||||||
|
}));
|
||||||
|
return function (_x) {
|
||||||
|
return _ref.apply(this, arguments);
|
||||||
|
};
|
||||||
|
}());
|
||||||
};
|
};
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
var rect = getOdRect({
|
var rect = getOdRect({
|
||||||
@ -263,18 +286,41 @@ export var BigImagePreview = /*#__PURE__*/React.forwardRef(function (props, ref)
|
|||||||
setSelectAlgorithmVersion(null);
|
setSelectAlgorithmVersion(null);
|
||||||
setCropRect(null);
|
setCropRect(null);
|
||||||
});
|
});
|
||||||
handlerCropEndRef.current = addEventListenerWrapper(imgContainerRef.current, EVENT_CROP_END, function (event) {
|
handlerCropEndRef.current = addEventListenerWrapper(imgContainerRef.current, EVENT_CROP_END, /*#__PURE__*/function () {
|
||||||
var _alignRef$current, _alignRef$current$for;
|
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(event) {
|
||||||
var data = event.detail;
|
var _alignRef$current, _alignRef$current$for;
|
||||||
setSelectAlgorithmVersion(null);
|
var data, _rect, _cropData;
|
||||||
setCropRect({
|
return _regeneratorRuntime().wrap(function _callee2$(_context2) {
|
||||||
x: data.left,
|
while (1) switch (_context2.prev = _context2.next) {
|
||||||
y: data.top,
|
case 0:
|
||||||
w: data.width,
|
data = event.detail;
|
||||||
h: data.height
|
setSelectAlgorithmVersion(null);
|
||||||
});
|
_rect = {
|
||||||
alignRef === null || alignRef === void 0 || (_alignRef$current = alignRef.current) === null || _alignRef$current === void 0 || (_alignRef$current$for = _alignRef$current.forceAlign) === null || _alignRef$current$for === void 0 || _alignRef$current$for.call(_alignRef$current);
|
x: data.left,
|
||||||
});
|
y: data.top,
|
||||||
|
w: data.width,
|
||||||
|
h: data.height
|
||||||
|
};
|
||||||
|
setCropRect(_rect);
|
||||||
|
_context2.next = 6;
|
||||||
|
return getCropInfo({
|
||||||
|
type: cropType,
|
||||||
|
rect: _rect
|
||||||
|
});
|
||||||
|
case 6:
|
||||||
|
_cropData = _context2.sent;
|
||||||
|
onDraw === null || onDraw === void 0 || onDraw(_cropData);
|
||||||
|
alignRef === null || alignRef === void 0 || (_alignRef$current = alignRef.current) === null || _alignRef$current === void 0 || (_alignRef$current$for = _alignRef$current.forceAlign) === null || _alignRef$current$for === void 0 || _alignRef$current$for.call(_alignRef$current);
|
||||||
|
case 9:
|
||||||
|
case "end":
|
||||||
|
return _context2.stop();
|
||||||
|
}
|
||||||
|
}, _callee2);
|
||||||
|
}));
|
||||||
|
return function (_x2) {
|
||||||
|
return _ref2.apply(this, arguments);
|
||||||
|
};
|
||||||
|
}());
|
||||||
cropInsRef.current = new Cropper(imgContainerRef.current, {
|
cropInsRef.current = new Cropper(imgContainerRef.current, {
|
||||||
showMask: true,
|
showMask: true,
|
||||||
viewer: imgIns
|
viewer: imgIns
|
||||||
@ -283,26 +329,25 @@ export var BigImagePreview = /*#__PURE__*/React.forwardRef(function (props, ref)
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 获取框选的截图框信息
|
// 获取框选的截图框信息
|
||||||
var latestCropType = useLatest(cropType);
|
|
||||||
var latestCropRect = useLatest(cropRect);
|
|
||||||
var getCropInfo = /*#__PURE__*/function () {
|
var getCropInfo = /*#__PURE__*/function () {
|
||||||
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(cb) {
|
var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(opt) {
|
||||||
var cropType, cropRect, imgIns, transform, newImgKey, rectList, extendRectList, selectIndex, shapes, shapeIds, newRect, _data;
|
var type, rect, cropType, cropRect, imgIns, transform, newImgKey, rectList, extendRectList, selectIndex, shapes, shapeIds, newRect, _data, data;
|
||||||
return _regeneratorRuntime().wrap(function _callee3$(_context3) {
|
return _regeneratorRuntime().wrap(function _callee5$(_context5) {
|
||||||
while (1) switch (_context3.prev = _context3.next) {
|
while (1) switch (_context5.prev = _context5.next) {
|
||||||
case 0:
|
case 0:
|
||||||
cropType = latestCropType.current;
|
type = opt.type, rect = opt.rect;
|
||||||
cropRect = latestCropRect.current;
|
cropType = type;
|
||||||
|
cropRect = rect;
|
||||||
imgIns = imgInsRef.current;
|
imgIns = imgInsRef.current;
|
||||||
transform = imgIns.targetTransform;
|
transform = imgIns.targetTransform;
|
||||||
newImgKey = imageKey;
|
newImgKey = imageKey;
|
||||||
rectList = [];
|
rectList = [];
|
||||||
extendRectList = [];
|
extendRectList = [];
|
||||||
selectIndex = 0;
|
selectIndex = 0;
|
||||||
_context3.t0 = cropType;
|
_context5.t0 = cropType;
|
||||||
_context3.next = _context3.t0 === CROP_TYPE['AUTO'] ? 11 : 17;
|
_context5.next = _context5.t0 === CROP_TYPE['AUTO'] ? 12 : 18;
|
||||||
break;
|
break;
|
||||||
case 11:
|
case 12:
|
||||||
shapes = imgIns.getSelectShape();
|
shapes = imgIns.getSelectShape();
|
||||||
shapeIds = shapes.map(function (v) {
|
shapeIds = shapes.map(function (v) {
|
||||||
return v['id'];
|
return v['id'];
|
||||||
@ -331,8 +376,8 @@ export var BigImagePreview = /*#__PURE__*/React.forwardRef(function (props, ref)
|
|||||||
selectIndex = rectList.findIndex(function (v) {
|
selectIndex = rectList.findIndex(function (v) {
|
||||||
return v['id'] === selectRectId;
|
return v['id'] === selectRectId;
|
||||||
});
|
});
|
||||||
return _context3.abrupt("break", 22);
|
return _context5.abrupt("break", 23);
|
||||||
case 17:
|
case 18:
|
||||||
//获取旋转过的坐标
|
//获取旋转过的坐标
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
newRect = getTransformRect(imgIns.image, transform, cropRect); //判断是不是旋转过
|
newRect = getTransformRect(imgIns.image, transform, cropRect); //判断是不是旋转过
|
||||||
@ -342,40 +387,40 @@ export var BigImagePreview = /*#__PURE__*/React.forwardRef(function (props, ref)
|
|||||||
}
|
}
|
||||||
rectList.push(newRect);
|
rectList.push(newRect);
|
||||||
extendRectList.push(newRect);
|
extendRectList.push(newRect);
|
||||||
return _context3.abrupt("break", 22);
|
return _context5.abrupt("break", 23);
|
||||||
case 22:
|
case 23:
|
||||||
_context3.next = 24;
|
_context5.next = 25;
|
||||||
return Promise.all(extendRectList.map( /*#__PURE__*/function () {
|
return Promise.all(extendRectList.map( /*#__PURE__*/function () {
|
||||||
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(rect, index) {
|
var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(rect, index) {
|
||||||
var file, imgKey;
|
var file, imgKey;
|
||||||
return _regeneratorRuntime().wrap(function _callee$(_context) {
|
return _regeneratorRuntime().wrap(function _callee3$(_context3) {
|
||||||
while (1) switch (_context.prev = _context.next) {
|
while (1) switch (_context3.prev = _context3.next) {
|
||||||
case 0:
|
case 0:
|
||||||
_context.next = 2;
|
_context3.next = 2;
|
||||||
return getFileByRect(imgIns.image, rect);
|
return getFileByRect(imgIns.image, rect);
|
||||||
case 2:
|
case 2:
|
||||||
file = _context.sent;
|
file = _context3.sent;
|
||||||
imgKey = file;
|
imgKey = file;
|
||||||
extendRectList[index] = _objectSpread(_objectSpread({}, rect), {}, {
|
extendRectList[index] = _objectSpread(_objectSpread({}, rect), {}, {
|
||||||
imgKey: imgKey
|
imgKey: imgKey
|
||||||
});
|
});
|
||||||
case 5:
|
case 5:
|
||||||
case "end":
|
case "end":
|
||||||
return _context.stop();
|
return _context3.stop();
|
||||||
}
|
}
|
||||||
}, _callee);
|
}, _callee3);
|
||||||
}));
|
}));
|
||||||
return function (_x2, _x3) {
|
return function (_x4, _x5) {
|
||||||
return _ref2.apply(this, arguments);
|
return _ref4.apply(this, arguments);
|
||||||
};
|
};
|
||||||
}()));
|
}()));
|
||||||
case 24:
|
case 25:
|
||||||
_context3.next = 26;
|
_context5.next = 27;
|
||||||
return Promise.all(rectList.map( /*#__PURE__*/function () {
|
return Promise.all(rectList.map( /*#__PURE__*/function () {
|
||||||
var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(rect, index) {
|
var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4(rect, index) {
|
||||||
var faceCorrectImage, faceCorrectImageKey, base64, blobData, file, newRect;
|
var faceCorrectImage, faceCorrectImageKey, base64, blobData, file, newRect;
|
||||||
return _regeneratorRuntime().wrap(function _callee2$(_context2) {
|
return _regeneratorRuntime().wrap(function _callee4$(_context4) {
|
||||||
while (1) switch (_context2.prev = _context2.next) {
|
while (1) switch (_context4.prev = _context4.next) {
|
||||||
case 0:
|
case 0:
|
||||||
faceCorrectImage = rect['faceCorrectImage'];
|
faceCorrectImage = rect['faceCorrectImage'];
|
||||||
if (faceCorrectImage) {
|
if (faceCorrectImage) {
|
||||||
@ -391,35 +436,30 @@ export var BigImagePreview = /*#__PURE__*/React.forwardRef(function (props, ref)
|
|||||||
rectList[index] = newRect;
|
rectList[index] = newRect;
|
||||||
case 5:
|
case 5:
|
||||||
case "end":
|
case "end":
|
||||||
return _context2.stop();
|
return _context4.stop();
|
||||||
}
|
}
|
||||||
}, _callee2);
|
}, _callee4);
|
||||||
}));
|
}));
|
||||||
return function (_x4, _x5) {
|
return function (_x6, _x7) {
|
||||||
return _ref3.apply(this, arguments);
|
return _ref5.apply(this, arguments);
|
||||||
};
|
};
|
||||||
}()));
|
}()));
|
||||||
case 26:
|
case 27:
|
||||||
cb === null || cb === void 0 || cb({
|
data = {
|
||||||
rectList: rectList,
|
rectList: rectList,
|
||||||
extendRectList: extendRectList,
|
extendRectList: extendRectList,
|
||||||
selectIndex: selectIndex,
|
selectIndex: selectIndex,
|
||||||
imgKey: newImgKey
|
imgKey: newImgKey
|
||||||
});
|
};
|
||||||
return _context3.abrupt("return", {
|
return _context5.abrupt("return", data);
|
||||||
rectList: rectList,
|
case 29:
|
||||||
extendRectList: extendRectList,
|
|
||||||
selectIndex: selectIndex,
|
|
||||||
imgKey: newImgKey
|
|
||||||
});
|
|
||||||
case 28:
|
|
||||||
case "end":
|
case "end":
|
||||||
return _context3.stop();
|
return _context5.stop();
|
||||||
}
|
}
|
||||||
}, _callee3);
|
}, _callee5);
|
||||||
}));
|
}));
|
||||||
return function getCropInfo(_x) {
|
return function getCropInfo(_x3) {
|
||||||
return _ref.apply(this, arguments);
|
return _ref3.apply(this, arguments);
|
||||||
};
|
};
|
||||||
}();
|
}();
|
||||||
|
|
||||||
@ -439,23 +479,14 @@ export var BigImagePreview = /*#__PURE__*/React.forwardRef(function (props, ref)
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ============================= attact img =========================
|
// ============================= attact img =========================
|
||||||
var _useState19 = useState(0),
|
var _useState17 = useState(0),
|
||||||
|
_useState18 = _slicedToArray(_useState17, 2),
|
||||||
|
selectAttachImgIndex = _useState18[0],
|
||||||
|
setSelectAttachImgIndex = _useState18[1];
|
||||||
|
var _useState19 = useState(false),
|
||||||
_useState20 = _slicedToArray(_useState19, 2),
|
_useState20 = _slicedToArray(_useState19, 2),
|
||||||
selectAttachImgIndex = _useState20[0],
|
isZoomin = _useState20[0],
|
||||||
setSelectAttachImgIndex = _useState20[1];
|
setIsZoomin = _useState20[1];
|
||||||
var _useState21 = useState(false),
|
|
||||||
_useState22 = _slicedToArray(_useState21, 2),
|
|
||||||
isZoomin = _useState22[0],
|
|
||||||
setIsZoomin = _useState22[1];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改当前图片预览下标
|
|
||||||
* @param diff 跳转强度 正向后翻、负值向前翻
|
|
||||||
*/
|
|
||||||
var handleChangeIndex = function handleChangeIndex(cb) {
|
|
||||||
if (!imageKey) return;
|
|
||||||
cb === null || cb === void 0 || cb();
|
|
||||||
};
|
|
||||||
|
|
||||||
// ============================== Ref ===============================
|
// ============================== Ref ===============================
|
||||||
useImperativeHandle(ref, function () {
|
useImperativeHandle(ref, function () {
|
||||||
@ -463,8 +494,7 @@ export var BigImagePreview = /*#__PURE__*/React.forwardRef(function (props, ref)
|
|||||||
imgInsRef: imgInsRef,
|
imgInsRef: imgInsRef,
|
||||||
setShowCrop: setShowCrop,
|
setShowCrop: setShowCrop,
|
||||||
initData: initData,
|
initData: initData,
|
||||||
getCropInfo: getCropInfo,
|
getCropInfo: getCropInfo
|
||||||
handleChangeIndex: handleChangeIndex
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
return /*#__PURE__*/React.createElement("div", {
|
return /*#__PURE__*/React.createElement("div", {
|
||||||
@ -475,13 +505,14 @@ export var BigImagePreview = /*#__PURE__*/React.forwardRef(function (props, ref)
|
|||||||
}
|
}
|
||||||
}, imageKey ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
|
}, imageKey ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
|
||||||
className: classNames("".concat(componentName, "-main"), cropType === CROP_TYPE['AUTO'] && "".concat(componentName, "-main--cursor")),
|
className: classNames("".concat(componentName, "-main"), cropType === CROP_TYPE['AUTO'] && "".concat(componentName, "-main--cursor")),
|
||||||
ref: init
|
ref: imgContainerRef
|
||||||
|
// style={{ width: width, height: height }}
|
||||||
}), !hideLeftTopBtn && /*#__PURE__*/React.createElement(BtnGroup, {
|
}), !hideLeftTopBtn && /*#__PURE__*/React.createElement(BtnGroup, {
|
||||||
className: classNames("".concat(componentName, "-opt")),
|
className: classNames("".concat(componentName, "-opt")),
|
||||||
dataSource: operateBtnDataSource,
|
dataSource: operateBtnDataSource,
|
||||||
onClick: handleOptClick,
|
onClick: handleOptClick,
|
||||||
placement: "left"
|
placement: "left"
|
||||||
}), showCrop && /*#__PURE__*/React.createElement(BtnGroup, {
|
}), !hideTypeBtns && showCrop && /*#__PURE__*/React.createElement(BtnGroup, {
|
||||||
circle: true,
|
circle: true,
|
||||||
className: classNames("".concat(componentName, "-crop-opt")),
|
className: classNames("".concat(componentName, "-crop-opt")),
|
||||||
dataSource: cropBtnDataSource,
|
dataSource: cropBtnDataSource,
|
||||||
@ -515,8 +546,8 @@ export var BigImagePreview = /*#__PURE__*/React.forwardRef(function (props, ref)
|
|||||||
className: classNames("".concat(componentName, "-attach"), isZoomin && "".concat(componentName, "-attach--zoomin"), "".concat(componentName, "-attach--fixed"), isZoomin && "".concat(componentName, "-attach--zoomin--fixed"))
|
className: classNames("".concat(componentName, "-attach"), isZoomin && "".concat(componentName, "-attach--zoomin"), "".concat(componentName, "-attach--fixed"), isZoomin && "".concat(componentName, "-attach--zoomin--fixed"))
|
||||||
}, /*#__PURE__*/React.createElement("div", {
|
}, /*#__PURE__*/React.createElement("div", {
|
||||||
className: classNames("".concat(componentName, "-attach__tab"))
|
className: classNames("".concat(componentName, "-attach__tab"))
|
||||||
}, showAttachImgLabel ? attachImg === null || attachImg === void 0 ? void 0 : attachImg.map(function (_ref4, index) {
|
}, showAttachImgLabel ? attachImg === null || attachImg === void 0 ? void 0 : attachImg.map(function (_ref6, index) {
|
||||||
var label = _ref4.label;
|
var label = _ref6.label;
|
||||||
return /*#__PURE__*/React.createElement("div", {
|
return /*#__PURE__*/React.createElement("div", {
|
||||||
key: index,
|
key: index,
|
||||||
className: classNames("".concat(componentName, "-attach__tab-item"), selectAttachImgIndex === index && "".concat(componentName, "-attach__tab-item--select")),
|
className: classNames("".concat(componentName, "-attach__tab-item"), selectAttachImgIndex === index && "".concat(componentName, "-attach__tab-item--select")),
|
||||||
@ -550,15 +581,25 @@ export var BigImagePreview = /*#__PURE__*/React.forwardRef(function (props, ref)
|
|||||||
draggable: "false",
|
draggable: "false",
|
||||||
className: classNames("".concat(componentName, "-attach__img"), "".concat(componentName, "-attach__img--fixed")),
|
className: classNames("".concat(componentName, "-attach__img"), "".concat(componentName, "-attach__img--fixed")),
|
||||||
src: get(attachImg, "".concat(selectAttachImgIndex, ".url"), '')
|
src: get(attachImg, "".concat(selectAttachImgIndex, ".url"), '')
|
||||||
})), showScore && /*#__PURE__*/React.createElement("div", {
|
})), (showScore || score) && /*#__PURE__*/React.createElement("div", {
|
||||||
style: {
|
style: {
|
||||||
bottom: 20
|
bottom: 20
|
||||||
},
|
},
|
||||||
className: classNames("".concat(componentName, "__face-score"))
|
className: classNames("".concat(componentName, "__face-score"))
|
||||||
}, "\u4EBA\u8138\u8D28\u91CF\u5206\uFF1A".concat(Number(score).toFixed(2)))) : /*#__PURE__*/React.createElement(Empty, {
|
}, "\u4EBA\u8138\u8D28\u91CF\u5206\uFF1A".concat(Number(score).toFixed(2)))) : /*#__PURE__*/React.createElement("div", {
|
||||||
|
style: {
|
||||||
|
height: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center'
|
||||||
|
}
|
||||||
|
}, customEmpty || /*#__PURE__*/React.createElement(Empty, {
|
||||||
|
style: {
|
||||||
|
margin: 0
|
||||||
|
},
|
||||||
image: Empty.PRESENTED_IMAGE_SIMPLE,
|
image: Empty.PRESENTED_IMAGE_SIMPLE,
|
||||||
description: "\u6682\u65E0\u6570\u636E"
|
description: "\u6682\u65E0\u6570\u636E"
|
||||||
}));
|
})));
|
||||||
});
|
});
|
||||||
BigImagePreview.displayName = 'BigImagePreview';
|
BigImagePreview.displayName = 'BigImagePreview';
|
||||||
export default BigImagePreview;
|
export default BigImagePreview;
|
@ -0,0 +1,270 @@
|
|||||||
|
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 _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
|
||||||
|
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
||||||
|
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
||||||
|
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
|
||||||
|
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
|
||||||
|
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
||||||
|
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 { cloneDeep, dataURLToBlob, get, isNull } from "@zhst/func";
|
||||||
|
var proto = {
|
||||||
|
Common: {
|
||||||
|
AlgorithmVersion: {
|
||||||
|
VERSION_REID_HEAD_ATTR: '形体',
|
||||||
|
VERSION_FACE: '人脸',
|
||||||
|
VERSION_NON_MOTOR_VEHICLE: '非机动车'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
export var ALGORITHM_VERSION = _defineProperty(_defineProperty(_defineProperty({}, '7', '形体'), '4', '人脸'), '6', '非机动车');
|
||||||
|
export var algorithmVersions = _toConsumableArray(Object.keys(ALGORITHM_VERSION));
|
||||||
|
/**
|
||||||
|
* 格式化工具
|
||||||
|
* @param originData
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export var getOdRect = function getOdRect(originData) {
|
||||||
|
var data = get(originData, 'objects', []).filter(function (v) {
|
||||||
|
return !isNull(get(v, 'bboxRatio')) || get(v, 'objectIndex.objectId') !== '0';
|
||||||
|
}).map(function (v, index) {
|
||||||
|
var rect = get(v, 'bboxRatio');
|
||||||
|
var extendBox = get(v, 'extendBoxRatio');
|
||||||
|
var frameTimestamp = get(v, 'timestamp'); //时间戳创建档案的时候需要
|
||||||
|
var qualityScore = get(v, 'qualityScore');
|
||||||
|
var algorithmVersion = get(v, 'objectType') === 'OBJECT_TYPE_PEDESTRAIN' ? 'VERSION_REID_HEAD_ATTR' : get(v, 'objectType') === 'OBJECT_TYPE_FACE' ? 'VERSION_FACE' : 'VERSION_REID_HEAD_ATTR';
|
||||||
|
var objectRectIndex = algorithmVersion === 'VERSION_FACE' ? 0 : 1;
|
||||||
|
var objectType = get(v, 'objectType');
|
||||||
|
var objectId = get(v, 'objectIndex.objectId');
|
||||||
|
var sourceObjectId = get(v, 'sourceObjectId');
|
||||||
|
return {
|
||||||
|
x: rect.x,
|
||||||
|
y: rect.y,
|
||||||
|
w: rect.w,
|
||||||
|
h: rect.h,
|
||||||
|
id: index,
|
||||||
|
qualityScore: qualityScore,
|
||||||
|
algorithmVersion: algorithmVersion,
|
||||||
|
objectRectIndex: objectRectIndex,
|
||||||
|
objectType: objectType,
|
||||||
|
objectId: objectId,
|
||||||
|
frameTimestamp: frameTimestamp,
|
||||||
|
sourceObjectId: sourceObjectId,
|
||||||
|
extendBox: extendBox
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
export var getNormalization = function getNormalization(srcRect, maxW, maxH) {
|
||||||
|
var newRect = _objectSpread({}, srcRect);
|
||||||
|
newRect.x = srcRect.x / maxW;
|
||||||
|
newRect.y = srcRect.y / maxH;
|
||||||
|
newRect.w = srcRect.w / maxW;
|
||||||
|
newRect.h = srcRect.h / maxH;
|
||||||
|
if (newRect.x + newRect.w > 1) {
|
||||||
|
newRect.w = 1 - newRect.x;
|
||||||
|
}
|
||||||
|
if (newRect.y + newRect.h > 1) {
|
||||||
|
newRect.h = 1 - newRect.y;
|
||||||
|
}
|
||||||
|
return newRect;
|
||||||
|
};
|
||||||
|
//传入od框 穿出 od扩展框
|
||||||
|
export var getExtendRect = function getExtendRect(normalizationRect, imgW, imgH, type) {
|
||||||
|
var rect = {
|
||||||
|
x: normalizationRect.x * imgW,
|
||||||
|
y: normalizationRect.y * imgH,
|
||||||
|
w: normalizationRect.w * imgW,
|
||||||
|
h: normalizationRect.h * imgH
|
||||||
|
};
|
||||||
|
var newRect;
|
||||||
|
if (type === proto.Common.AlgorithmVersion.VERSION_NON_MOTOR_VEHICLE) {
|
||||||
|
newRect = getBikeExtendRect(rect, imgW);
|
||||||
|
} else {
|
||||||
|
newRect = getOtherExtendRect(rect, imgW, imgH, type);
|
||||||
|
}
|
||||||
|
newRect = getNormalization(newRect, imgW, imgH);
|
||||||
|
return newRect;
|
||||||
|
};
|
||||||
|
export var getBikeExtendRect = function getBikeExtendRect(rect, maxW) {
|
||||||
|
var newRect = _objectSpread({}, rect);
|
||||||
|
//向上扩大一倍
|
||||||
|
var oldY = cloneDeep(rect.y);
|
||||||
|
newRect.y = newRect.y - newRect.h < 0 ? 0 : newRect.y - newRect.h;
|
||||||
|
newRect.h += oldY - newRect.y;
|
||||||
|
var newX = Math.round(newRect.x - newRect.w * 0.15);
|
||||||
|
if (newX < 0) {
|
||||||
|
newX = 0;
|
||||||
|
}
|
||||||
|
var newW = newRect.x - newX + newRect.w + Math.round(newRect.w * 0.15);
|
||||||
|
if (newX + newW > maxW) {
|
||||||
|
newW = maxW - newX;
|
||||||
|
}
|
||||||
|
newRect.x = newX;
|
||||||
|
newRect.w = newW;
|
||||||
|
return newRect;
|
||||||
|
};
|
||||||
|
export var getOtherExtendRect = function getOtherExtendRect(srcRect, maxW, maxH, type) {
|
||||||
|
var wExtendRadio = 0.25;
|
||||||
|
var upExtendRadio = 0.25;
|
||||||
|
var downExtendRadio = 0.25;
|
||||||
|
var fixPersonExtend = true;
|
||||||
|
var nx = 0;
|
||||||
|
var nw = 0;
|
||||||
|
nx = srcRect.x - Math.round(srcRect.w * wExtendRadio);
|
||||||
|
if (nx < 0) {
|
||||||
|
nx = 0;
|
||||||
|
}
|
||||||
|
nw = srcRect.x - nx + srcRect.w + Math.round(srcRect.w * wExtendRadio);
|
||||||
|
if (nx + nw > maxW) {
|
||||||
|
nw = maxW - nx;
|
||||||
|
}
|
||||||
|
var ny = 0;
|
||||||
|
var nh = 0;
|
||||||
|
ny = srcRect.y - Math.round(upExtendRadio * srcRect.h);
|
||||||
|
if (ny < 0) {
|
||||||
|
ny = 0;
|
||||||
|
}
|
||||||
|
nh = srcRect.y - ny + srcRect.h + Math.round(srcRect.h * downExtendRadio);
|
||||||
|
if (ny + nh > maxH) {
|
||||||
|
nh = maxH - ny;
|
||||||
|
}
|
||||||
|
var newRect = {
|
||||||
|
x: nx,
|
||||||
|
y: ny,
|
||||||
|
w: nw,
|
||||||
|
h: nh
|
||||||
|
};
|
||||||
|
if ((type === proto.Common.AlgorithmVersion.VERSION_REID_HEAD_ATTR || type === proto.Common.AlgorithmVersion.VERSION_FACE) && fixPersonExtend) {
|
||||||
|
var fixW = Math.round(nh * 0.75);
|
||||||
|
if (nw < fixW) {
|
||||||
|
// 应该扩展宽度
|
||||||
|
var newX = nx + Math.round(nw / 2.0 - 0.5 * fixW);
|
||||||
|
if (newX < 0) {
|
||||||
|
newX = 0;
|
||||||
|
}
|
||||||
|
var newW = fixW;
|
||||||
|
if (newW + newX > maxW) {
|
||||||
|
newW = maxW - newX;
|
||||||
|
}
|
||||||
|
newRect = {
|
||||||
|
x: newX,
|
||||||
|
y: ny,
|
||||||
|
w: newW,
|
||||||
|
h: nh
|
||||||
|
};
|
||||||
|
} else if (nw > fixW) {
|
||||||
|
// 应该扩展高度
|
||||||
|
var fixH = Math.round(nw * 1.333);
|
||||||
|
var newY = ny + Math.round(nh / 2.0 - 0.5 * fixH);
|
||||||
|
if (newY < 0) {
|
||||||
|
newY = 0;
|
||||||
|
}
|
||||||
|
var newH = fixH;
|
||||||
|
if (newY + newH > maxH) {
|
||||||
|
newH = maxH - newY;
|
||||||
|
}
|
||||||
|
newRect = {
|
||||||
|
x: nx,
|
||||||
|
y: newY,
|
||||||
|
w: nw,
|
||||||
|
h: newH
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newRect;
|
||||||
|
};
|
||||||
|
export var getTransformRect = function getTransformRect(image, transform, rect) {
|
||||||
|
var canvasRect = {
|
||||||
|
x: rect.x,
|
||||||
|
y: rect.y,
|
||||||
|
x2: rect.x + rect.w,
|
||||||
|
y2: rect.h + rect.y
|
||||||
|
};
|
||||||
|
//1.转成缩放前的坐标
|
||||||
|
var translateX = transform.translateX,
|
||||||
|
translateY = transform.translateY,
|
||||||
|
scale = transform.scale,
|
||||||
|
rotate = transform.rotate;
|
||||||
|
var originAxisRect = {
|
||||||
|
x: (canvasRect.x - translateX) / scale,
|
||||||
|
y: (canvasRect.y - translateY) / scale,
|
||||||
|
x2: (canvasRect.x2 - translateX) / scale,
|
||||||
|
y2: (canvasRect.y2 - translateY) / scale
|
||||||
|
};
|
||||||
|
//2.转成图片坐标
|
||||||
|
//不考虑旋转 图片原点就是坐标原点
|
||||||
|
var imgAxisRect = originAxisRect;
|
||||||
|
//但是旋转90度后图片不在坐标原点 加上这部分diff
|
||||||
|
if (rotate % 180 !== 0) {
|
||||||
|
//90度调整偏移量
|
||||||
|
var offsetX = -(image.height - image.width) / 2;
|
||||||
|
var offsetY = -(image.width - image.height) / 2;
|
||||||
|
imgAxisRect = {
|
||||||
|
x: originAxisRect.x - offsetX,
|
||||||
|
y: originAxisRect.y - offsetY,
|
||||||
|
x2: originAxisRect.x2 - offsetX,
|
||||||
|
y2: originAxisRect.y2 - offsetY
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//3.限制框不要超出图片
|
||||||
|
var imgW = image.width;
|
||||||
|
var imgH = image.height;
|
||||||
|
if (rotate % 180 !== 0) {
|
||||||
|
var _ref = [imgH, imgW];
|
||||||
|
imgW = _ref[0];
|
||||||
|
imgH = _ref[1];
|
||||||
|
}
|
||||||
|
imgAxisRect.x = Math.min(imgW, Math.max(imgAxisRect.x, 0));
|
||||||
|
imgAxisRect.y = Math.min(imgH, Math.max(imgAxisRect.y, 0));
|
||||||
|
imgAxisRect.x2 = Math.min(imgW, Math.max(imgAxisRect.x2, 0));
|
||||||
|
imgAxisRect.y2 = Math.min(imgH, Math.max(imgAxisRect.y2, 0));
|
||||||
|
//获取归一化坐标
|
||||||
|
var endRect = {
|
||||||
|
x: imgAxisRect.x2 > imgAxisRect.x ? imgAxisRect.x : imgAxisRect.x2,
|
||||||
|
y: imgAxisRect.y2 > imgAxisRect.y ? imgAxisRect.y : imgAxisRect.y2,
|
||||||
|
w: Math.abs(imgAxisRect.x2 - imgAxisRect.x),
|
||||||
|
h: Math.abs(imgAxisRect.y2 - imgAxisRect.y)
|
||||||
|
};
|
||||||
|
return getNormalization(endRect, imgW, imgH);
|
||||||
|
};
|
||||||
|
|
||||||
|
//旋转图片后转成file 对象
|
||||||
|
export var getRotateImg = function getRotateImg(image, rotate) {
|
||||||
|
var _commonCanvas$parentN;
|
||||||
|
var imgW = image.width;
|
||||||
|
var imgH = image.height;
|
||||||
|
if (rotate % 180 !== 0) {
|
||||||
|
var _ref2 = [imgH, imgW];
|
||||||
|
imgW = _ref2[0];
|
||||||
|
imgH = _ref2[1];
|
||||||
|
}
|
||||||
|
var commonCanvas = document.createElement('canvas');
|
||||||
|
commonCanvas.width = imgW;
|
||||||
|
commonCanvas.height = imgH;
|
||||||
|
commonCanvas.style.display = 'none';
|
||||||
|
document.body.appendChild(commonCanvas);
|
||||||
|
var commonCtx = commonCanvas.getContext('2d');
|
||||||
|
//移动到图片中心 旋转
|
||||||
|
|
||||||
|
commonCtx === null || commonCtx === void 0 || commonCtx.save();
|
||||||
|
if (rotate % 180 !== 0) {
|
||||||
|
//90度调整偏移量
|
||||||
|
commonCtx === null || commonCtx === void 0 || commonCtx.translate((image.height - image.width) / 2, (image.width - image.height) / 2);
|
||||||
|
}
|
||||||
|
commonCtx === null || commonCtx === void 0 || commonCtx.translate(image.width / 2, image.height / 2);
|
||||||
|
commonCtx === null || commonCtx === void 0 || commonCtx.rotate(rotate / 180 * Math.PI);
|
||||||
|
commonCtx === null || commonCtx === void 0 || commonCtx.translate(-image.width / 2, -image.height / 2);
|
||||||
|
commonCtx === null || commonCtx === void 0 || commonCtx.drawImage(image, 0, 0);
|
||||||
|
commonCtx === null || commonCtx === void 0 || commonCtx.restore();
|
||||||
|
var dataUrl = commonCanvas.toDataURL('image/jpeg');
|
||||||
|
var blobData = dataURLToBlob(dataUrl);
|
||||||
|
var file = new window.File([blobData], "".concat(new Date().getTime()), {
|
||||||
|
type: 'image/jpeg'
|
||||||
|
});
|
||||||
|
(_commonCanvas$parentN = commonCanvas.parentNode) === null || _commonCanvas$parentN === void 0 || _commonCanvas$parentN.removeChild(commonCanvas);
|
||||||
|
return file;
|
||||||
|
};
|
@ -2,6 +2,7 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
width: calc(100%);
|
width: calc(100%);
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
font-size: 0;
|
||||||
|
|
||||||
&__face-score {
|
&__face-score {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -62,14 +63,9 @@
|
|||||||
height: 202px;
|
height: 202px;
|
||||||
transition: all 200ms;
|
transition: all 200ms;
|
||||||
|
|
||||||
&--fixed {
|
|
||||||
}
|
|
||||||
|
|
||||||
&--zoomin {
|
&--zoomin {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
&--fixed {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__tab {
|
&__tab {
|
||||||
|
@ -34,7 +34,7 @@ export default {
|
|||||||
try {
|
try {
|
||||||
handler.remove();
|
handler.remove();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
warn('CROP:REMOVE_EVENT_FAIL,', error);
|
warn('CROP:REMOVE_EVENT_FAIL: ', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -46,7 +46,9 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
|||||||
screenshotButtonRender = _props$screenshotButt2 === void 0 ? function () {
|
screenshotButtonRender = _props$screenshotButt2 === void 0 ? function () {
|
||||||
return /*#__PURE__*/React.createElement("div", {
|
return /*#__PURE__*/React.createElement("div", {
|
||||||
style: {
|
style: {
|
||||||
color: '#fff'
|
color: '#fff',
|
||||||
|
width: '80px',
|
||||||
|
top: 0
|
||||||
}
|
}
|
||||||
}, "\u56DE\u8C03DOM");
|
}, "\u56DE\u8C03DOM");
|
||||||
} : _props$screenshotButt2,
|
} : _props$screenshotButt2,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export var CROP_TYPE = {
|
export var CROP_TYPE = {
|
||||||
CUSTOM: 'CSUTOM',
|
CUSTOM: 'CUSTOM',
|
||||||
AUTO: 'AUTO'
|
AUTO: 'AUTO'
|
||||||
};
|
};
|
||||||
export var defaultAlignOption = {
|
export var defaultAlignOption = {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@zhst/meta",
|
"name": "@zhst/meta",
|
||||||
"version": "0.8.0",
|
"version": "0.9.1",
|
||||||
"description": "原子组件",
|
"description": "原子组件",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"meta",
|
"meta",
|
||||||
|
@ -1,23 +1,18 @@
|
|||||||
import React, { useEffect, ReactElement, useState, useCallback, useRef, useImperativeHandle } from 'react';
|
import React, { useEffect, ReactElement, useState, useRef, useImperativeHandle } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { useLatest } from '@zhst/hooks';
|
|
||||||
import {
|
import {
|
||||||
get,
|
get,
|
||||||
pick,
|
pick,
|
||||||
isNull,
|
isNull,
|
||||||
generateImg,
|
generateImg,
|
||||||
dataURLToBlob,
|
dataURLToBlob,
|
||||||
getOdRect,
|
|
||||||
getExtendRect,
|
|
||||||
getTransformRect,
|
|
||||||
getRotateImg,
|
|
||||||
getTransforms,
|
getTransforms,
|
||||||
addEventListenerWrapper,
|
addEventListenerWrapper,
|
||||||
getFileByRect
|
getFileByRect
|
||||||
} from '@zhst/func';
|
} from '@zhst/func';
|
||||||
import Align from 'rc-align';
|
import Align from 'rc-align';
|
||||||
import { Button, Empty } from '..';
|
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 Icon from '../iconfont';
|
||||||
import {
|
import {
|
||||||
Cropper,
|
Cropper,
|
||||||
@ -30,10 +25,15 @@ import {
|
|||||||
import BtnGroup from './components/BtnGroup';
|
import BtnGroup from './components/BtnGroup';
|
||||||
import './index.less'
|
import './index.less'
|
||||||
import { defaultAlignOption, CROP_TYPE } from '../utils/constants'
|
import { defaultAlignOption, CROP_TYPE } from '../utils/constants'
|
||||||
|
import {
|
||||||
|
getOdRect,
|
||||||
|
IOdObject,
|
||||||
|
getExtendRect,
|
||||||
|
getTransformRect,
|
||||||
|
getRotateImg, } from './bigImagePreviewHelper'
|
||||||
|
|
||||||
const componentName = `zhst-image__img-view`;
|
const componentName = `zhst-image__img-view`;
|
||||||
|
|
||||||
|
|
||||||
export interface ViewOption {
|
export interface ViewOption {
|
||||||
/* 图片url */
|
/* 图片url */
|
||||||
image?: string | HTMLImageElement;
|
image?: string | HTMLImageElement;
|
||||||
@ -67,7 +67,7 @@ export interface ImgViewProps extends React.HTMLAttributes<HTMLElement> {
|
|||||||
attachImg?: Array<{ label: string; url: string }>; // 缩略图列表
|
attachImg?: Array<{ label: string; url: string }>; // 缩略图列表
|
||||||
odRect?: Rect
|
odRect?: Rect
|
||||||
score?: number
|
score?: number
|
||||||
objects?: IOdRectOrigin[] // 图片人物框选
|
objects?: IOdObject
|
||||||
}
|
}
|
||||||
showAttachImgLabel?: boolean; // 是否显示缩略图
|
showAttachImgLabel?: boolean; // 是否显示缩略图
|
||||||
showOpt?: boolean; // 是否显示操作面板
|
showOpt?: boolean; // 是否显示操作面板
|
||||||
@ -77,8 +77,28 @@ export interface ImgViewProps extends React.HTMLAttributes<HTMLElement> {
|
|||||||
screenshotButtonAlign?: AlignType;
|
screenshotButtonAlign?: AlignType;
|
||||||
screenshotButtonRender?: (screenshotButtonProp: IScreenshotButtonProp) => ReactElement;
|
screenshotButtonRender?: (screenshotButtonProp: IScreenshotButtonProp) => ReactElement;
|
||||||
hideLeftTopBtn?: boolean;
|
hideLeftTopBtn?: boolean;
|
||||||
|
onDraw?: (obj: {
|
||||||
|
rectList: any;
|
||||||
|
extendRectList: {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
w: number;
|
||||||
|
h: number;
|
||||||
|
}[];
|
||||||
|
selectIndex: number;
|
||||||
|
imgKey: string;
|
||||||
|
}) => void
|
||||||
showScore?: boolean // 是否显示相似度
|
showScore?: boolean // 是否显示相似度
|
||||||
viewOption?: ViewOption;
|
viewOption?: ViewOption;
|
||||||
|
onRectSelect?: (data: {
|
||||||
|
rectList: any[];
|
||||||
|
extendRectList: any[];
|
||||||
|
selectIndex: number;
|
||||||
|
imgKey: string;
|
||||||
|
}) => void
|
||||||
|
type?: 'CUSTOM' | 'AUTO'
|
||||||
|
hideTypeBtns?: boolean
|
||||||
|
customEmpty?: any
|
||||||
}
|
}
|
||||||
export interface ImgViewRef {
|
export interface ImgViewRef {
|
||||||
/* 图片实例 */
|
/* 图片实例 */
|
||||||
@ -127,14 +147,18 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
|
|||||||
const {
|
const {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
showScore = true,
|
showScore = false,
|
||||||
data,
|
data,
|
||||||
showOpt = false,
|
showOpt = false,
|
||||||
showAttachImgLabel = true,
|
showAttachImgLabel = true,
|
||||||
screenshotButtonAlign = defaultAlignOption,
|
screenshotButtonAlign = defaultAlignOption,
|
||||||
screenshotButtonRender = () => <div style={{ color: '#fff' }}>回调DOM</div>,
|
screenshotButtonRender = () => <div style={{ color: '#fff', width: '80px', top: 0, fontSize: 12 }}>回调DOM</div>,
|
||||||
hideLeftTopBtn = true,
|
hideLeftTopBtn = true,
|
||||||
viewOption = {}
|
onDraw,
|
||||||
|
viewOption = {},
|
||||||
|
type,
|
||||||
|
hideTypeBtns,
|
||||||
|
customEmpty,
|
||||||
} = props;
|
} = props;
|
||||||
const {
|
const {
|
||||||
imageKey,
|
imageKey,
|
||||||
@ -144,18 +168,13 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
|
|||||||
objects = [],
|
objects = [],
|
||||||
} = data
|
} = data
|
||||||
const imgContainerRef = React.useRef(null);
|
const imgContainerRef = React.useRef(null);
|
||||||
const [isReady, setIsReady] = useState(false);
|
|
||||||
|
|
||||||
const init = useCallback(($container: null) => {
|
|
||||||
imgContainerRef.current = $container;
|
|
||||||
setIsReady(true);
|
|
||||||
}, []);
|
|
||||||
// ============================= viewer =========================
|
// ============================= viewer =========================
|
||||||
const imgInsRef = useRef<any>(null);
|
const imgInsRef = useRef<any>(null);
|
||||||
const [isImgReady, setIsImgReady] = useState(false);
|
const [isImgReady, setIsImgReady] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isReady || !imgContainerRef?.current) return;
|
if (!imgContainerRef?.current) return;
|
||||||
const handleReady = addEventListenerWrapper(imgContainerRef.current, EVENT_VIEWER_READY, () => {
|
const handleReady = addEventListenerWrapper(imgContainerRef.current, EVENT_VIEWER_READY, () => {
|
||||||
setIsImgReady(true);
|
setIsImgReady(true);
|
||||||
});
|
});
|
||||||
@ -176,7 +195,7 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
|
|||||||
imgInsRef?.current?.destroy?.();
|
imgInsRef?.current?.destroy?.();
|
||||||
imgInsRef.current = null;
|
imgInsRef.current = null;
|
||||||
};
|
};
|
||||||
}, [isReady, imageKey]);
|
}, [imageKey]);
|
||||||
|
|
||||||
// ============================= viewer操作按钮 =========================
|
// ============================= viewer操作按钮 =========================
|
||||||
const handleOptClick = (v: string) => {
|
const handleOptClick = (v: string) => {
|
||||||
@ -197,7 +216,7 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
|
|||||||
// 手动截图相关参数
|
// 手动截图相关参数
|
||||||
const cropInsRef: any = useRef(null);
|
const cropInsRef: any = useRef(null);
|
||||||
const [showCrop, setShowCrop] = useState(showOpt);
|
const [showCrop, setShowCrop] = useState(showOpt);
|
||||||
const [cropType, setCropType] = useState(CROP_TYPE['AUTO']);
|
const [cropType, setCropType] = useState(type || CROP_TYPE['AUTO']);
|
||||||
|
|
||||||
// 自动截图相关参数
|
// 自动截图相关参数
|
||||||
const [odList, setOdList] = useState<any>([]);
|
const [odList, setOdList] = useState<any>([]);
|
||||||
@ -227,7 +246,8 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
|
|||||||
};
|
};
|
||||||
}, [isImgReady, showCrop, cropType, imageKey]);
|
}, [isImgReady, showCrop, cropType, imageKey]);
|
||||||
|
|
||||||
const initData = (_objects: IOdRectOrigin[]) => {
|
// 初始化页面的绘制矩形
|
||||||
|
const initData = (_objects: IOdObject | never[]) => {
|
||||||
const imgIns = imgInsRef.current;
|
const imgIns = imgInsRef.current;
|
||||||
const _odRect = odRect
|
const _odRect = odRect
|
||||||
//清理crop
|
//清理crop
|
||||||
@ -251,7 +271,8 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
|
|||||||
const shapeList = odList.map((rect: { [x: string]: any; algorithmVersion: any; }) => ({
|
const shapeList = odList.map((rect: { [x: string]: any; algorithmVersion: any; }) => ({
|
||||||
...rect,
|
...rect,
|
||||||
selectAble: true,
|
selectAble: true,
|
||||||
id: rect['id'],
|
id:
|
||||||
|
['id'],
|
||||||
algorithmVersion: rect.algorithmVersion,
|
algorithmVersion: rect.algorithmVersion,
|
||||||
}));
|
}));
|
||||||
imgIns.replaceShape(shapeList);
|
imgIns.replaceShape(shapeList);
|
||||||
@ -263,7 +284,8 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
|
|||||||
});
|
});
|
||||||
setExtendOdList(extendRect);
|
setExtendOdList(extendRect);
|
||||||
imgIns.replaceShape(shapeList);
|
imgIns.replaceShape(shapeList);
|
||||||
handleShapeSelectRef.current = addEventListenerWrapper(imgContainerRef.current, 'shape-select', (e: { detail: any; }) => {
|
// 框选监听事件
|
||||||
|
handleShapeSelectRef.current = addEventListenerWrapper(imgContainerRef.current, 'shape-select', async (e: { detail: any; }) => {
|
||||||
const id = e.detail;
|
const id = e.detail;
|
||||||
setSelectRectId(id);
|
setSelectRectId(id);
|
||||||
const selectShape = shapeList.find((v: { [x: string]: any; }) => v['id'] === id);
|
const selectShape = shapeList.find((v: { [x: string]: any; }) => v['id'] === id);
|
||||||
@ -278,6 +300,7 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
|
|||||||
h: Math.abs(axisRect.y2 - axisRect.y),
|
h: Math.abs(axisRect.y2 - axisRect.y),
|
||||||
};
|
};
|
||||||
setCropRect(rect);
|
setCropRect(rect);
|
||||||
|
onDraw?.({ rectList: [rect], extendRectList: [rect], imgKey: imageKey, selectIndex: id })
|
||||||
} else {
|
} else {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
setCropRect(null);
|
setCropRect(null);
|
||||||
@ -298,15 +321,18 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
|
|||||||
setSelectAlgorithmVersion(null);
|
setSelectAlgorithmVersion(null);
|
||||||
setCropRect(null);
|
setCropRect(null);
|
||||||
});
|
});
|
||||||
handlerCropEndRef.current = addEventListenerWrapper(imgContainerRef.current, EVENT_CROP_END, (event: { detail: any; }) => {
|
handlerCropEndRef.current = addEventListenerWrapper(imgContainerRef.current, EVENT_CROP_END, async (event: { detail: any; }) => {
|
||||||
const data = event.detail;
|
const data = event.detail;
|
||||||
setSelectAlgorithmVersion(null);
|
setSelectAlgorithmVersion(null);
|
||||||
setCropRect({
|
const _rect = {
|
||||||
x: data.left,
|
x: data.left,
|
||||||
y: data.top,
|
y: data.top,
|
||||||
w: data.width,
|
w: data.width,
|
||||||
h: data.height,
|
h: data.height,
|
||||||
});
|
}
|
||||||
|
setCropRect(_rect);
|
||||||
|
const _cropData = await getCropInfo({ type: cropType, rect: _rect })
|
||||||
|
onDraw?.(_cropData)
|
||||||
alignRef?.current?.forceAlign?.();
|
alignRef?.current?.forceAlign?.();
|
||||||
});
|
});
|
||||||
cropInsRef.current = new Cropper(imgContainerRef.current, {
|
cropInsRef.current = new Cropper(imgContainerRef.current, {
|
||||||
@ -317,11 +343,10 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取框选的截图框信息
|
// 获取框选的截图框信息
|
||||||
const latestCropType = useLatest(cropType);
|
const getCropInfo = async (opt: { type: string; rect: Rect }) => {
|
||||||
const latestCropRect = useLatest(cropRect);
|
const { type, rect } = opt
|
||||||
const getCropInfo = async (cb: (data: any) => void) => {
|
const cropType = type;
|
||||||
const cropType = latestCropType.current;
|
const cropRect = rect;
|
||||||
const cropRect = latestCropRect.current;
|
|
||||||
const imgIns = imgInsRef.current;
|
const imgIns = imgInsRef.current;
|
||||||
const transform = imgIns.targetTransform;
|
const transform = imgIns.targetTransform;
|
||||||
let newImgKey = imageKey;
|
let newImgKey = imageKey;
|
||||||
@ -398,8 +423,15 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
|
|||||||
rectList[index] = newRect;
|
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 +453,12 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
|
|||||||
const [selectAttachImgIndex, setSelectAttachImgIndex] = useState(0);
|
const [selectAttachImgIndex, setSelectAttachImgIndex] = useState(0);
|
||||||
const [isZoomin, setIsZoomin] = useState(false);
|
const [isZoomin, setIsZoomin] = useState(false);
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改当前图片预览下标
|
|
||||||
* @param diff 跳转强度 正向后翻、负值向前翻
|
|
||||||
*/
|
|
||||||
const handleChangeIndex = (cb?: () => void) => {
|
|
||||||
if (!imageKey) return
|
|
||||||
cb?.()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================== Ref ===============================
|
// ============================== Ref ===============================
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
imgInsRef,
|
imgInsRef,
|
||||||
setShowCrop,
|
setShowCrop,
|
||||||
initData,
|
initData,
|
||||||
getCropInfo,
|
getCropInfo,
|
||||||
handleChangeIndex
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -449,7 +471,8 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
|
|||||||
`${componentName}-main`,
|
`${componentName}-main`,
|
||||||
cropType === CROP_TYPE['AUTO'] && `${componentName}-main--cursor`
|
cropType === CROP_TYPE['AUTO'] && `${componentName}-main--cursor`
|
||||||
)}
|
)}
|
||||||
ref={init}
|
ref={imgContainerRef}
|
||||||
|
// style={{ width: width, height: height }}
|
||||||
/>
|
/>
|
||||||
{/* 图片操作 */}
|
{/* 图片操作 */}
|
||||||
{!hideLeftTopBtn && (
|
{!hideLeftTopBtn && (
|
||||||
@ -460,7 +483,7 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
|
|||||||
placement="left"
|
placement="left"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showCrop && (
|
{!hideTypeBtns && showCrop && (
|
||||||
<BtnGroup
|
<BtnGroup
|
||||||
circle
|
circle
|
||||||
className={classNames(`${componentName}-crop-opt`)}
|
className={classNames(`${componentName}-crop-opt`)}
|
||||||
@ -562,7 +585,7 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{showScore && <div
|
{(showScore || score) && <div
|
||||||
style={{ bottom: 20 }}
|
style={{ bottom: 20 }}
|
||||||
className={classNames(`${componentName}__face-score`)}
|
className={classNames(`${componentName}__face-score`)}
|
||||||
>
|
>
|
||||||
@ -570,7 +593,9 @@ export const BigImagePreview = React.forwardRef<ImgViewRef, ImgViewProps>((props
|
|||||||
</div>}
|
</div>}
|
||||||
</>
|
</>
|
||||||
:
|
:
|
||||||
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="暂无数据" />
|
<div style={{ height: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
||||||
|
{customEmpty || <Empty style={{ margin: 0 }} image={Empty.PRESENTED_IMAGE_SIMPLE} description="暂无数据" />}
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,300 @@
|
|||||||
|
import { cloneDeep, dataURLToBlob, get, isNull } from "@zhst/func";
|
||||||
|
import { ObjectType, Rect } from "@zhst/types";
|
||||||
|
|
||||||
|
const proto = {
|
||||||
|
Common: {
|
||||||
|
AlgorithmVersion: {
|
||||||
|
VERSION_REID_HEAD_ATTR: '形体',
|
||||||
|
VERSION_FACE: '人脸',
|
||||||
|
VERSION_NON_MOTOR_VEHICLE: '非机动车',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
export const ALGORITHM_VERSION = {
|
||||||
|
['7']: '形体',
|
||||||
|
['4']: '人脸',
|
||||||
|
['6']: '非机动车',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const algorithmVersions = [...Object.keys(ALGORITHM_VERSION)]
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getNormalization = (srcRect: Rect, maxW: number, maxH: number) => {
|
||||||
|
const newRect = {
|
||||||
|
...srcRect,
|
||||||
|
};
|
||||||
|
newRect.x = srcRect.x / maxW;
|
||||||
|
newRect.y = srcRect.y / maxH;
|
||||||
|
newRect.w = srcRect.w / maxW;
|
||||||
|
newRect.h = srcRect.h / maxH;
|
||||||
|
if (newRect.x + newRect.w > 1) {
|
||||||
|
newRect.w = 1 - newRect.x;
|
||||||
|
}
|
||||||
|
if (newRect.y + newRect.h > 1) {
|
||||||
|
newRect.h = 1 - newRect.y;
|
||||||
|
}
|
||||||
|
return newRect;
|
||||||
|
};
|
||||||
|
//传入od框 穿出 od扩展框
|
||||||
|
export const getExtendRect = (normalizationRect: Rect, imgW: number, imgH: number, type: string) => {
|
||||||
|
const rect = {
|
||||||
|
x: normalizationRect.x * imgW,
|
||||||
|
y: normalizationRect.y * imgH,
|
||||||
|
w: normalizationRect.w * imgW,
|
||||||
|
h: normalizationRect.h * imgH,
|
||||||
|
};
|
||||||
|
|
||||||
|
let newRect;
|
||||||
|
if (type === proto.Common.AlgorithmVersion.VERSION_NON_MOTOR_VEHICLE) {
|
||||||
|
newRect = getBikeExtendRect(rect, imgW);
|
||||||
|
} else {
|
||||||
|
newRect = getOtherExtendRect(rect, imgW, imgH, type);
|
||||||
|
}
|
||||||
|
newRect = getNormalization(newRect, imgW, imgH);
|
||||||
|
return newRect;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const getBikeExtendRect = (rect: Rect, maxW: number) => {
|
||||||
|
const newRect = { ...rect };
|
||||||
|
//向上扩大一倍
|
||||||
|
const oldY = cloneDeep(rect.y);
|
||||||
|
newRect.y = newRect.y - newRect.h < 0 ? 0 : newRect.y - newRect.h;
|
||||||
|
newRect.h += oldY - newRect.y;
|
||||||
|
|
||||||
|
let newX = Math.round(newRect.x - newRect.w * 0.15);
|
||||||
|
if (newX < 0) {
|
||||||
|
newX = 0;
|
||||||
|
}
|
||||||
|
let newW = newRect.x - newX + newRect.w + Math.round(newRect.w * 0.15);
|
||||||
|
if (newX + newW > maxW) {
|
||||||
|
newW = maxW - newX;
|
||||||
|
}
|
||||||
|
newRect.x = newX;
|
||||||
|
newRect.w = newW;
|
||||||
|
|
||||||
|
return newRect;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getOtherExtendRect = (srcRect: Rect, maxW: number, maxH: number, type: string) => {
|
||||||
|
const wExtendRadio = 0.25;
|
||||||
|
const upExtendRadio = 0.25;
|
||||||
|
const downExtendRadio = 0.25;
|
||||||
|
const fixPersonExtend = true;
|
||||||
|
|
||||||
|
let nx = 0;
|
||||||
|
let nw = 0;
|
||||||
|
|
||||||
|
nx = srcRect.x - Math.round(srcRect.w * wExtendRadio);
|
||||||
|
if (nx < 0) {
|
||||||
|
nx = 0;
|
||||||
|
}
|
||||||
|
nw = srcRect.x - nx + srcRect.w + Math.round(srcRect.w * wExtendRadio);
|
||||||
|
if (nx + nw > maxW) {
|
||||||
|
nw = maxW - nx;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ny = 0;
|
||||||
|
let nh = 0;
|
||||||
|
ny = srcRect.y - Math.round(upExtendRadio * srcRect.h);
|
||||||
|
if (ny < 0) {
|
||||||
|
ny = 0;
|
||||||
|
}
|
||||||
|
nh = srcRect.y - ny + srcRect.h + Math.round(srcRect.h * downExtendRadio);
|
||||||
|
if (ny + nh > maxH) {
|
||||||
|
nh = maxH - ny;
|
||||||
|
}
|
||||||
|
|
||||||
|
let newRect = {
|
||||||
|
x: nx,
|
||||||
|
y: ny,
|
||||||
|
w: nw,
|
||||||
|
h: nh,
|
||||||
|
};
|
||||||
|
if (
|
||||||
|
(type === proto.Common.AlgorithmVersion.VERSION_REID_HEAD_ATTR ||
|
||||||
|
type === proto.Common.AlgorithmVersion.VERSION_FACE) &&
|
||||||
|
fixPersonExtend
|
||||||
|
) {
|
||||||
|
const fixW = Math.round(nh * 0.75);
|
||||||
|
if (nw < fixW) {
|
||||||
|
// 应该扩展宽度
|
||||||
|
let newX = nx + Math.round(nw / 2.0 - 0.5 * fixW);
|
||||||
|
if (newX < 0) {
|
||||||
|
newX = 0;
|
||||||
|
}
|
||||||
|
let newW = fixW;
|
||||||
|
if (newW + newX > maxW) {
|
||||||
|
newW = maxW - newX;
|
||||||
|
}
|
||||||
|
|
||||||
|
newRect = {
|
||||||
|
x: newX,
|
||||||
|
y: ny,
|
||||||
|
w: newW,
|
||||||
|
h: nh,
|
||||||
|
};
|
||||||
|
} else if (nw > fixW) {
|
||||||
|
// 应该扩展高度
|
||||||
|
const fixH = Math.round(nw * 1.333);
|
||||||
|
let newY = ny + Math.round(nh / 2.0 - 0.5 * fixH);
|
||||||
|
if (newY < 0) {
|
||||||
|
newY = 0;
|
||||||
|
}
|
||||||
|
let newH = fixH;
|
||||||
|
if (newY + newH > maxH) {
|
||||||
|
newH = maxH - newY;
|
||||||
|
}
|
||||||
|
newRect = {
|
||||||
|
x: nx,
|
||||||
|
y: newY,
|
||||||
|
w: nw,
|
||||||
|
h: newH,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newRect;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const getTransformRect = (image: { height: number; width: number; }, transform: { translateX: any; translateY: any; scale: any; rotate: any; }, rect: Rect) => {
|
||||||
|
const canvasRect = {
|
||||||
|
x: rect.x,
|
||||||
|
y: rect.y,
|
||||||
|
x2: rect.x + rect.w,
|
||||||
|
y2: rect.h + rect.y,
|
||||||
|
};
|
||||||
|
//1.转成缩放前的坐标
|
||||||
|
const { translateX, translateY, scale, rotate } = transform;
|
||||||
|
const originAxisRect = {
|
||||||
|
x: (canvasRect.x - translateX) / scale,
|
||||||
|
y: (canvasRect.y - translateY) / scale,
|
||||||
|
x2: (canvasRect.x2 - translateX) / scale,
|
||||||
|
y2: (canvasRect.y2 - translateY) / scale,
|
||||||
|
};
|
||||||
|
//2.转成图片坐标
|
||||||
|
//不考虑旋转 图片原点就是坐标原点
|
||||||
|
let imgAxisRect = originAxisRect;
|
||||||
|
//但是旋转90度后图片不在坐标原点 加上这部分diff
|
||||||
|
if (rotate % 180 !== 0) {
|
||||||
|
//90度调整偏移量
|
||||||
|
const offsetX = -(image.height - image.width) / 2;
|
||||||
|
const offsetY = -(image.width - image.height) / 2;
|
||||||
|
imgAxisRect = {
|
||||||
|
x: originAxisRect.x - offsetX,
|
||||||
|
y: originAxisRect.y - offsetY,
|
||||||
|
x2: originAxisRect.x2 - offsetX,
|
||||||
|
y2: originAxisRect.y2 - offsetY,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//3.限制框不要超出图片
|
||||||
|
let imgW = image.width;
|
||||||
|
let imgH = image.height;
|
||||||
|
if (rotate % 180 !== 0) {
|
||||||
|
[imgW, imgH] = [imgH, imgW];
|
||||||
|
}
|
||||||
|
imgAxisRect.x = Math.min(imgW, Math.max(imgAxisRect.x, 0));
|
||||||
|
imgAxisRect.y = Math.min(imgH, Math.max(imgAxisRect.y, 0));
|
||||||
|
imgAxisRect.x2 = Math.min(imgW, Math.max(imgAxisRect.x2, 0));
|
||||||
|
imgAxisRect.y2 = Math.min(imgH, Math.max(imgAxisRect.y2, 0));
|
||||||
|
//获取归一化坐标
|
||||||
|
const endRect = {
|
||||||
|
x: imgAxisRect.x2 > imgAxisRect.x ? imgAxisRect.x : imgAxisRect.x2,
|
||||||
|
y: imgAxisRect.y2 > imgAxisRect.y ? imgAxisRect.y : imgAxisRect.y2,
|
||||||
|
w: Math.abs(imgAxisRect.x2 - imgAxisRect.x),
|
||||||
|
h: Math.abs(imgAxisRect.y2 - imgAxisRect.y),
|
||||||
|
};
|
||||||
|
|
||||||
|
return getNormalization(endRect, imgW, imgH);
|
||||||
|
};
|
||||||
|
|
||||||
|
//旋转图片后转成file 对象
|
||||||
|
export const getRotateImg = (image: HTMLImageElement, rotate: number) => {
|
||||||
|
let imgW = image.width;
|
||||||
|
let imgH = image.height;
|
||||||
|
if (rotate % 180 !== 0) {
|
||||||
|
[imgW, imgH] = [imgH, imgW];
|
||||||
|
}
|
||||||
|
const commonCanvas = document.createElement('canvas');
|
||||||
|
commonCanvas.width = imgW;
|
||||||
|
commonCanvas.height = imgH;
|
||||||
|
commonCanvas.style.display = 'none';
|
||||||
|
document.body.appendChild(commonCanvas);
|
||||||
|
const commonCtx = commonCanvas.getContext('2d');
|
||||||
|
//移动到图片中心 旋转
|
||||||
|
|
||||||
|
commonCtx?.save();
|
||||||
|
if (rotate % 180 !== 0) {
|
||||||
|
//90度调整偏移量
|
||||||
|
commonCtx?.translate((image.height - image.width) / 2, (image.width - image.height) / 2);
|
||||||
|
}
|
||||||
|
commonCtx?.translate(image.width / 2, image.height / 2);
|
||||||
|
commonCtx?.rotate((rotate / 180) * Math.PI);
|
||||||
|
commonCtx?.translate(-image.width / 2, -image.height / 2);
|
||||||
|
commonCtx?.drawImage(image, 0, 0);
|
||||||
|
commonCtx?.restore();
|
||||||
|
|
||||||
|
const dataUrl = commonCanvas.toDataURL('image/jpeg');
|
||||||
|
const blobData = dataURLToBlob(dataUrl);
|
||||||
|
const file = new window.File([blobData], `${new Date().getTime()}`, {
|
||||||
|
type: 'image/jpeg',
|
||||||
|
});
|
||||||
|
commonCanvas.parentNode?.removeChild(commonCanvas);
|
||||||
|
return file;
|
||||||
|
};
|
@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
import React, { useRef } from 'react';
|
import React, { useRef } from 'react';
|
||||||
import { Button, Space } from '@zhst/meta'
|
import { Button, ImgViewRef, Space } from '@zhst/meta'
|
||||||
import { BigImagePreview } from '@zhst/meta'
|
import { BigImagePreview } from '@zhst/meta'
|
||||||
|
|
||||||
|
|
||||||
@ -25,42 +25,33 @@ const props = {
|
|||||||
time: '2022-01-01', // 摄像头拍摄时间
|
time: '2022-01-01', // 摄像头拍摄时间
|
||||||
objects: [
|
objects: [
|
||||||
{
|
{
|
||||||
"infoOnSource": {
|
"bboxRatio": {
|
||||||
"bboxInFrame": {
|
"x": 0.5519352,
|
||||||
"bboxRatio": {
|
"y": 0.2965385,
|
||||||
"x": 0.5519352,
|
"w": 0.05185461,
|
||||||
"y": 0.2965385,
|
"h": 0.24698898
|
||||||
"w": 0.05185461,
|
},
|
||||||
"h": 0.24698898
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"infoOnSource": {
|
"bboxRatio": {
|
||||||
"bboxInFrame": {
|
"x": 0.58543766,
|
||||||
"bboxRatio": {
|
"y": 0.3203356,
|
||||||
"x": 0.58543766,
|
"w": 0.052037954,
|
||||||
"y": 0.3203356,
|
"h": 0.2664015
|
||||||
"w": 0.052037954,
|
},
|
||||||
"h": 0.2664015
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const imgRef = useRef(null)
|
const imgRef = useRef<ImgViewRef>(null)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Space size={[8, 16]} direction="vertical">
|
<Space size={[8, 16]} direction="vertical">
|
||||||
<BigImagePreview {...props} ref={imgRef} />
|
<BigImagePreview {...props} ref={imgRef} />
|
||||||
<Space>
|
<Space>
|
||||||
<Button type="primary" onClick={() => imgRef.current?.setShowCrop(true)}>编辑</Button>
|
<Button type="primary" onClick={() => imgRef.current?.setShowCrop(true)}>编辑</Button>
|
||||||
<Button onClick={() => imgRef.current?.handleChangeIndex(1)}>下一张</Button>
|
|
||||||
<Button onClick={() => imgRef.current?.setShowCrop(false)}>取消</Button>
|
<Button onClick={() => imgRef.current?.setShowCrop(false)}>取消</Button>
|
||||||
</Space>
|
</Space>
|
||||||
</Space>
|
</Space>
|
||||||
|
28
packages/meta/src/BigImagePreview/demo/empty.tsx
Normal file
28
packages/meta/src/BigImagePreview/demo/empty.tsx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
import React, { useRef } from 'react';
|
||||||
|
import { Button, ImgViewRef, Space } from '@zhst/meta'
|
||||||
|
import { BigImagePreview } from '@zhst/meta'
|
||||||
|
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
height: '320px',
|
||||||
|
width: '640px',
|
||||||
|
data: {
|
||||||
|
imageKey: '',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME:需要优化 props
|
||||||
|
export default () => {
|
||||||
|
const imgRef = useRef<ImgViewRef>(null)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Space size={[8, 16]} direction="vertical" style={{ border: '1px solid #ccc' }}>
|
||||||
|
<BigImagePreview {...props} type="CUSTOM" hideTypeBtns ref={imgRef} />
|
||||||
|
<Space>
|
||||||
|
<Button type="primary" onClick={() => imgRef.current?.setShowCrop(true)}>编辑</Button>
|
||||||
|
<Button onClick={() => imgRef.current?.setShowCrop(false)}>取消</Button>
|
||||||
|
</Space>
|
||||||
|
</Space>
|
||||||
|
)
|
||||||
|
}
|
35
packages/meta/src/BigImagePreview/demo/noAttach.tsx
Normal file
35
packages/meta/src/BigImagePreview/demo/noAttach.tsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
import React, { useRef } from 'react';
|
||||||
|
import { Button, Space } from '@zhst/meta'
|
||||||
|
import { BigImagePreview } from '@zhst/meta'
|
||||||
|
import type { ImgViewRef } from '@zhst/meta'
|
||||||
|
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
height: '320px',
|
||||||
|
width: '640px',
|
||||||
|
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', // 摄像头拍摄时间
|
||||||
|
},
|
||||||
|
onDraw: (data: any) => console.log('data', data),
|
||||||
|
hideTypeBtns: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const imgRef = useRef<ImgViewRef>(null)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Space size={[8, 16]} direction="vertical">
|
||||||
|
<BigImagePreview {...props} type="CUSTOM" ref={imgRef} />
|
||||||
|
<Space>
|
||||||
|
<Button type="primary" onClick={() => imgRef.current?.setShowCrop(true)}>编辑</Button>
|
||||||
|
<Button onClick={() => imgRef.current?.setShowCrop(false)}>取消</Button>
|
||||||
|
</Space>
|
||||||
|
</Space>
|
||||||
|
)
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
width: calc(100%);
|
width: calc(100%);
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
font-size: 0;
|
||||||
|
|
||||||
&__face-score {
|
&__face-score {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -62,14 +63,9 @@
|
|||||||
height: 202px;
|
height: 202px;
|
||||||
transition: all 200ms;
|
transition: all 200ms;
|
||||||
|
|
||||||
&--fixed {
|
|
||||||
}
|
|
||||||
|
|
||||||
&--zoomin {
|
&--zoomin {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
&--fixed {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__tab {
|
&__tab {
|
||||||
|
@ -8,15 +8,60 @@ title: BigImagePreview 大图预览组件
|
|||||||
# BigImagePreview 大图预览组件
|
# BigImagePreview 大图预览组件
|
||||||
|
|
||||||
<code src="./demo/base.tsx">基本</code>
|
<code src="./demo/base.tsx">基本</code>
|
||||||
|
<code src="./demo/noAttach.tsx">不展示小图</code>
|
||||||
|
<code src="./demo/empty.tsx">空数据</code>
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
|
| data | 当前组件数据对象 | IData(必填) | - | |
|
||||||
| imageKey | 当前大图链接 | string(必填) | - | |
|
| imageKey | 当前大图链接 | string(必填) | - | |
|
||||||
| odRect | 圈选矩形参数 | { x: number; y: number; w: number; h: number } | - | |
|
|
||||||
| height | 高度 | number(选填) | - | |
|
| height | 高度 | number(选填) | - | |
|
||||||
| width | 宽度 | number(选填) | - | |
|
| width | 宽度 | number(选填) | - | |
|
||||||
|
|
||||||
|
### IData
|
||||||
|
|
||||||
|
可以通过组件的 props 获取ts 定义:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import type { ImgViewProps } from '@zhst/meta'
|
||||||
|
|
||||||
|
const data: ImgViewProps['data'] = {
|
||||||
|
imageKey: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
||||||
|
odRect:{
|
||||||
|
"x":0.553125,"y":0.29722223,"w":0.048958335,"h":0.2462963
|
||||||
|
},
|
||||||
|
attachImg: [
|
||||||
|
{
|
||||||
|
"url": "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png","label": "形体"
|
||||||
|
},{
|
||||||
|
"url": "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png",
|
||||||
|
"label": "人脸"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
score: 0.815207, // 人脸质量分
|
||||||
|
showScore: true, // 人脸质量分
|
||||||
|
cameraPosition: 'string', // 摄像头位置
|
||||||
|
time: '2022-01-01', // 摄像头拍摄时间
|
||||||
|
objects: [
|
||||||
|
{
|
||||||
|
"bboxRatio": {
|
||||||
|
"x": 0.5519352,
|
||||||
|
"y": 0.2965385,
|
||||||
|
"w": 0.05185461,
|
||||||
|
"h": 0.24698898
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| imageKey | 当前大图链接 | string | - | |
|
||||||
|
| odRect | 初始化OD | { x: number; y: number; w: number; h: number } | - | |
|
||||||
|
| attachImg | 缩略图对象 | { url: string; label: string; }[](选填) | - | |
|
||||||
|
| objects | 多OD状态列表 | IOdRectOrigin[](选填) | - | |
|
||||||
|
| objects | 多OD状态列表 | IOdRectOrigin[](选填) | - | |
|
||||||
| score | 相似度 | number(选填) | - | |
|
| score | 相似度 | number(选填) | - | |
|
||||||
| attachImg | 缩略图 | { url: string; label: string; }[](选填) | - | |
|
|
||||||
| objects | 编辑状态参数 | IOdRectOrigin[](选填) | - | |
|
|
||||||
|
@ -66,7 +66,7 @@ export default {
|
|||||||
try {
|
try {
|
||||||
handler.remove();
|
handler.remove();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
warn('CROP:REMOVE_EVENT_FAIL,', error);
|
warn('CROP:REMOVE_EVENT_FAIL: ', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user