feat: 初始化项目(待优化ts)
This commit is contained in:
parent
8d8aa13483
commit
c4390a34d7
@ -13,6 +13,7 @@ export default defineConfig({
|
|||||||
'@zhst/func': path.join(__dirname, 'packages/func/src'),
|
'@zhst/func': path.join(__dirname, 'packages/func/src'),
|
||||||
'@zhst/biz': path.join(__dirname, 'packages/biz/src'),
|
'@zhst/biz': path.join(__dirname, 'packages/biz/src'),
|
||||||
'@zhst/meta': path.join(__dirname, 'packages/meta/src'),
|
'@zhst/meta': path.join(__dirname, 'packages/meta/src'),
|
||||||
|
'@zhst/request': path.join(__dirname, 'packages/request/src'),
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
docDirs: ['docs'],
|
docDirs: ['docs'],
|
||||||
@ -21,6 +22,9 @@ export default defineConfig({
|
|||||||
{ type: 'utils', dir: 'packages/func/src' },
|
{ type: 'utils', dir: 'packages/func/src' },
|
||||||
{ type: 'biz', dir: 'packages/biz/src' },
|
{ type: 'biz', dir: 'packages/biz/src' },
|
||||||
{ type: 'meta', dir: 'packages/meta/src' },
|
{ type: 'meta', dir: 'packages/meta/src' },
|
||||||
|
{ type: 'request', dir: 'packages/request/src' },
|
||||||
|
{ type: 'constants', dir: 'packages/constants/src' },
|
||||||
|
{ type: 'types', dir: 'packages/types/src' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
monorepoRedirect: {
|
monorepoRedirect: {
|
||||||
|
@ -20,6 +20,79 @@ features:
|
|||||||
description: 原子组件库
|
description: 原子组件库
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
<Tree>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
docs
|
||||||
|
<small>全局文档</small>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
index.md
|
||||||
|
<small>这是首页文档</small>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
packages
|
||||||
|
<small>组件包目录</small>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
biz
|
||||||
|
<small>业务组件</small>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
func
|
||||||
|
<small>函数库</small>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
hooks
|
||||||
|
<small>hooks</small>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
constants
|
||||||
|
<small>静态枚举值定义</small>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
meta
|
||||||
|
<small>元组件</small>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
request
|
||||||
|
<small>请求库</small>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
types
|
||||||
|
<small>类型定义库</small>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
material
|
||||||
|
<small>物料库</small>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
src
|
||||||
|
<small>这是 src 文件夹</small>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
index.md
|
||||||
|
<small>这是 index.md</small>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
.dumirc.ts
|
||||||
|
<small>文档配置</small>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
package.json
|
||||||
|
<small>这是 package.json</small>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</Tree>
|
||||||
|
|
||||||
## 本文档食用说明
|
## 本文档食用说明
|
||||||
|
|
||||||
目前在开发中的项目为:@zhst/bizs、@zhst/hooks、@zhst/meta、@zhst/func。
|
目前在开发中的项目为:@zhst/bizs、@zhst/hooks、@zhst/meta、@zhst/func。
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
"lib/**/style/*",
|
"lib/**/style/*",
|
||||||
"*.less"
|
"*.less"
|
||||||
],
|
],
|
||||||
"main": "lib/index.tsx",
|
"main": "lib/index.js",
|
||||||
"module": "es/index.js",
|
"module": "es/index.js",
|
||||||
"typings": "es/index.d.ts",
|
"typings": "es/index.d.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
@ -32,6 +32,9 @@
|
|||||||
"access": "public",
|
"access": "public",
|
||||||
"registry": "http://10.0.0.77:4874"
|
"registry": "http://10.0.0.77:4874"
|
||||||
},
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@zhst/types": "workspace:^"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@zhst/func": "workspace:^",
|
"@zhst/func": "workspace:^",
|
||||||
"@zhst/hooks": "workspace:^",
|
"@zhst/hooks": "workspace:^",
|
||||||
|
@ -67,256 +67,7 @@
|
|||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.zhst-image__img-view {
|
|
||||||
position: relative;
|
|
||||||
width: calc(100% - 46px - 46px - 20px - 20px);
|
|
||||||
height: 100%;
|
|
||||||
margin: 0 66px;
|
|
||||||
|
|
||||||
&-opt {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 99;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-crop-opt {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 99;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-align {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-main {
|
|
||||||
// height: 532px;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
&--cursor {
|
|
||||||
& canvas {
|
|
||||||
cursor: pointer !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-screenshot {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-attach {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 11;
|
|
||||||
bottom: 0;
|
|
||||||
|
|
||||||
// left: 78px;
|
|
||||||
left: 0;
|
|
||||||
min-width: 120px;
|
|
||||||
height: 202px;
|
|
||||||
transition: all 200ms;
|
|
||||||
|
|
||||||
&--fixed {
|
|
||||||
width: 152px !important;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--zoomin {
|
|
||||||
height: 532px;
|
|
||||||
|
|
||||||
&--fixed {
|
|
||||||
width: 398px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__tab {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
&-item {
|
|
||||||
display: flex;
|
|
||||||
width: 30px;
|
|
||||||
height: 24px;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
background: #000;
|
|
||||||
color: #fff;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 12px;
|
|
||||||
opacity: 0.5;
|
|
||||||
transition: all 200ms;
|
|
||||||
|
|
||||||
&--select {
|
|
||||||
width: 48px;
|
|
||||||
height: 34px;
|
|
||||||
background: #09f;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__scale {
|
|
||||||
position: absolute;
|
|
||||||
top: 4px;
|
|
||||||
right: 4px;
|
|
||||||
display: flex;
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
background: rgb(0 0 0 / 60%);
|
|
||||||
border-radius: 100%;
|
|
||||||
cursor: pointer;
|
|
||||||
line-height: 30px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__img {
|
|
||||||
height: 100%;
|
|
||||||
object-fit: contain;
|
|
||||||
|
|
||||||
&--fixed {
|
|
||||||
width: 100%;
|
|
||||||
object-fit: contain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.zhst-image__video-view {
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
width: 100%;
|
|
||||||
height: 532px;
|
|
||||||
background-color: #333;
|
|
||||||
|
|
||||||
// &-flv {
|
|
||||||
// width: 85%;
|
|
||||||
// }
|
|
||||||
&-screenshot {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-crop-container {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-align {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-opt {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 99;
|
|
||||||
bottom: 0;
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
height: 32px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
align-items: center;
|
|
||||||
padding: 0 12px;
|
|
||||||
background-color: rgb(0 0 0 / 80%);
|
|
||||||
line-height: 32px;
|
|
||||||
|
|
||||||
&>div:first-child {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-right: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&>div:last-child {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-left: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-range {
|
|
||||||
display: flex;
|
|
||||||
height: 32px;
|
|
||||||
flex: 1;
|
|
||||||
align-items: center;
|
|
||||||
line-height: 32px;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
&>div:first-child {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&>div:last-child {
|
|
||||||
width: 100px;
|
|
||||||
margin-left: 8px;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__player-mask {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 99;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
background-color: rgb(4 4 4 / 70%);
|
|
||||||
|
|
||||||
&--bg {
|
|
||||||
z-index: 999;
|
|
||||||
background-color: rgb(4 4 4 / 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
i {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-title {
|
|
||||||
margin-top: 12px;
|
|
||||||
color: #fff;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
& a {
|
|
||||||
color: #09f;
|
|
||||||
cursor: pointer;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__icon-wraper {
|
|
||||||
display: flex;
|
|
||||||
width: 80px;
|
|
||||||
height: 80px;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
background-color: rgb(255 255 255 / 10%);
|
|
||||||
border-radius: 50%;
|
|
||||||
cursor: pointer;
|
|
||||||
line-height: 80px;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
// &:hover {
|
|
||||||
// background: #0099ff;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.zhst-image__tool {
|
.zhst-image__tool {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -553,57 +304,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.zhst-image__btn-group {
|
|
||||||
// display: flex;
|
|
||||||
width: 30px;
|
|
||||||
box-shadow: 0 2px 6px 0 rgb(0 0 0 / 40%);
|
|
||||||
|
|
||||||
&__item {
|
|
||||||
display: flex;
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
background: #000;
|
|
||||||
|
|
||||||
&>button {
|
|
||||||
padding: 0;
|
|
||||||
color: #fff;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: #09f;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
color: #09f;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
&>span {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--active {
|
|
||||||
&>button {
|
|
||||||
color: #09f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--circle {
|
|
||||||
background-color: none;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--circle &__item {
|
|
||||||
margin-bottom: 4px;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.zhst-image__compater-view {
|
.zhst-image__compater-view {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -962,78 +662,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.zhst-image__score {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
&-box {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
box-sizing: border-box;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
border-radius: 50%;
|
|
||||||
|
|
||||||
&-bg {
|
|
||||||
display: flex;
|
|
||||||
overflow: hidden;
|
|
||||||
box-sizing: border-box;
|
|
||||||
align-items: flex-end;
|
|
||||||
justify-content: center;
|
|
||||||
border: 2px solid #fff;
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 50%;
|
|
||||||
|
|
||||||
&-inner {
|
|
||||||
width: 100% !important;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-score {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
color: rgb(0 0 0 / 88%);
|
|
||||||
font-size: 28px;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&-text {
|
|
||||||
width: 54px;
|
|
||||||
height: 24px;
|
|
||||||
color: rgb(0 0 0 / 88%);
|
|
||||||
font-size: 18px;
|
|
||||||
line-height: 24px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.zhst-image__CornerScore {
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 56px;
|
|
||||||
height: 22px;
|
|
||||||
line-height: 22px;
|
|
||||||
text-align: right;
|
|
||||||
vertical-align: bottom;
|
|
||||||
padding-right: 1px;
|
|
||||||
background-size: 100%;
|
|
||||||
background-image: url('./images/percent_background.png');
|
|
||||||
z-index: 99;
|
|
||||||
|
|
||||||
&>span {
|
|
||||||
padding-right: 6px;
|
|
||||||
line-height: 22px;
|
|
||||||
font-size: 12px;
|
|
||||||
vertical-align: middle;
|
|
||||||
color: rgba(255, 255, 255, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.zhst-image__attributePanel {
|
.zhst-image__attributePanel {
|
||||||
margin: 0 66px;
|
margin: 0 66px;
|
||||||
background: #f6f6f6;
|
background: #f6f6f6;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* 适配老的大屏组件数据格式传入
|
* 适配老的大屏组件数据格式传入
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { AlgorithmVersionStr, HumanProperty, ObjectType, Rect, ViewOption, AlignType, IScreenshotButtonProp, ODRECT } from './interface'
|
import { AlgorithmVersionStr, HumanProperty, ObjectType, Rect, ViewOption, AlignType, IScreenshotButtonProp, ODRECT } from '@zhst/types'
|
||||||
|
|
||||||
export type TAB_TYPE = 'COMPATER' | 'NORMAL' | 'TRACK';
|
export type TAB_TYPE = 'COMPATER' | 'NORMAL' | 'TRACK';
|
||||||
export type MODEL_TYPE = 'VIDEO' | 'IMAGE';
|
export type MODEL_TYPE = 'VIDEO' | 'IMAGE';
|
||||||
|
@ -1,217 +0,0 @@
|
|||||||
export type CamerasStatusList = [string[], string[], string[]];
|
|
||||||
|
|
||||||
export type Rect = { x: number; y: number; w: number; h: number };
|
|
||||||
|
|
||||||
export type StatusList = {
|
|
||||||
taskOverview: any;
|
|
||||||
taskIndex: {
|
|
||||||
deviceId: string;
|
|
||||||
solutionId: string;
|
|
||||||
};
|
|
||||||
}[];
|
|
||||||
|
|
||||||
export enum OperationType {
|
|
||||||
OPERATION_TYPE_UNKNOW, // 未知状态,传该值会报错
|
|
||||||
OPERATION_TYPE_START,
|
|
||||||
OPERATION_TYPE_STOP
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export enum AlgorithmVersion {
|
|
||||||
VERSION_MGN_BNN, // MGN+BNN算法
|
|
||||||
VERSION_BNN_PRO, // BNNPRO算法
|
|
||||||
VERSION_BNN_PRO_ATTR, // BNNPROATTR算法
|
|
||||||
VERSION_BNN_PRO_ATTR_SCORE, // BNNPROATTR算法
|
|
||||||
VERSION_FACE, // 人脸算法
|
|
||||||
VERSION_HEAD, // 头肩算法
|
|
||||||
VERSION_NON_MOTOR_VEHICLE, // 非机动车的算法
|
|
||||||
VERSION_REID_HEAD_ATTR, // 形体头肩属性三种特征融合的算法
|
|
||||||
VERSION_MOTOR_VEHICLE, // 机动车的算法
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum AlgorithmVersionStr {
|
|
||||||
VERSION_MGN_BNN = 'VERSION_MGN_BNN', // MGN+BNN算法
|
|
||||||
VERSION_BNN_PRO = 'VERSION_BNN_PRO', // BNNPRO算法
|
|
||||||
VERSION_BNN_PRO_ATTR = 'VERSION_BNN_PRO_ATTR', // BNNPROATTR算法
|
|
||||||
VERSION_BNN_PRO_ATTR_SCORE = 'VERSION_BNN_PRO_ATTR_SCORE', // BNNPROATTR算法
|
|
||||||
VERSION_FACE = 'VERSION_FACE', // 人脸算法
|
|
||||||
VERSION_HEAD = 'VERSION_HEAD', // 头肩算法
|
|
||||||
VERSION_NON_MOTOR_VEHICLE = 'VERSION_NON_MOTOR_VEHICLE', // 非机动车的算法
|
|
||||||
VERSION_REID_HEAD_ATTR = 'VERSION_REID_HEAD_ATTR', // 形体头肩属性三种特征融合的算法
|
|
||||||
VERSION_MOTOR_VEHICLE = 'VERSION_MOTOR_VEHICLE', // 机动车的算法
|
|
||||||
}
|
|
||||||
|
|
||||||
类型枚举
|
|
||||||
export enum ObjectType {
|
|
||||||
OBJECT_TYPE_NULL,
|
|
||||||
OBJECT_TYPE_PEDESTRAIN,
|
|
||||||
OBJECT_TYPE_BICYCLE,
|
|
||||||
OBJECT_TYPE_CAR,
|
|
||||||
OBJECT_TYPE_MOTORBIKE,
|
|
||||||
OBJECT_TYPE_AEROPLANE,
|
|
||||||
OBJECT_TYPE_BUS,
|
|
||||||
OBJECT_TYPE_TRAIN,
|
|
||||||
OBJECT_TYPE_TRUCK,
|
|
||||||
OBJECT_TYPE_MOTOR_RIDER,
|
|
||||||
OBJECT_TYPE_BIKE_RIDER,
|
|
||||||
OBJECT_TYPE_MAX,
|
|
||||||
OBJECT_TYPE_FACE = 101,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 性别
|
|
||||||
export enum Gender {
|
|
||||||
GENDER_NONE = 'GENDER_NONE',
|
|
||||||
GENDER_MAN = 'GENDER_MAN',
|
|
||||||
GENDER_WOMAN = 'GENDER_WOMAN',
|
|
||||||
}
|
|
||||||
|
|
||||||
// 年龄
|
|
||||||
export enum Age {
|
|
||||||
AGE_ALL = 'AGE_ALL',
|
|
||||||
AGE_ZERO = 'AGE_ZERO',
|
|
||||||
AGE_OVERENGHTEEN = 'AGE_OVERENGHTEEN',
|
|
||||||
AGE_OVERSIXTY = 'AGE_OVERSIXTY',
|
|
||||||
}
|
|
||||||
|
|
||||||
// 戴帽子状态
|
|
||||||
export enum Hat {
|
|
||||||
HAT_ALL = 'HAT_ALL',
|
|
||||||
HAT_NONE = 'HAT_NONE',
|
|
||||||
HAT_OWNED = 'HAT_OWNED',
|
|
||||||
}
|
|
||||||
|
|
||||||
// 颜色
|
|
||||||
export enum Color {
|
|
||||||
COLOR_ALL = 'COLOR_ALL',
|
|
||||||
COLOR_BLACK = 'COLOR_BLACK',
|
|
||||||
COLOR_WHITE = 'COLOR_WHITE',
|
|
||||||
COLOR_GRAY = 'COLOR_GRAY',
|
|
||||||
COLOR_BROWN = 'COLOR_BROWN',
|
|
||||||
COLOR_PINK = 'COLOR_PINK',
|
|
||||||
COLOR_REDANDORANGE = 'COLOR_REDANDORANGE',
|
|
||||||
COLOR_YELLOW = 'COLOR_YELLOW',
|
|
||||||
COLOR_GREEN = 'COLOR_GREEN',
|
|
||||||
COLOR_BLUE = 'COLOR_BLUE',
|
|
||||||
COLOR_PURPLE = 'COLOR_PURPLE',
|
|
||||||
}
|
|
||||||
|
|
||||||
// 背包
|
|
||||||
export enum Package {
|
|
||||||
PACKAGE_ALL = 'PACKAGE_ALL',
|
|
||||||
PACKAGE_HANDBAG = 'PACKAGE_HANDBAG',
|
|
||||||
PACKAGE_BACKPACK = 'PACKAGE_BACKPACK',
|
|
||||||
PACKAGE_SHOULDERBAG = 'PACKAGE_SHOULDERBAG',
|
|
||||||
PACKAGE_OTHER = 'PACKAGE_OTHER',
|
|
||||||
PACKAGE_NONE = 'PACKAGE_NONE',
|
|
||||||
}
|
|
||||||
|
|
||||||
// 行走模式
|
|
||||||
export enum WalkPattern {
|
|
||||||
WALKPATTERN_ALL = 'WALKPATTERN_ALL',
|
|
||||||
WALKPATTERN_WALK = 'WALKPATTERN_WALK',
|
|
||||||
WALKPATTERN_RIDING = 'WALKPATTERN_RIDING',
|
|
||||||
}
|
|
||||||
|
|
||||||
// 人类属性
|
|
||||||
export interface HumanProperty {
|
|
||||||
age: Age;
|
|
||||||
downColor: Color;
|
|
||||||
gender: Gender;
|
|
||||||
hat: Hat;
|
|
||||||
package: Package;
|
|
||||||
upColor: Color;
|
|
||||||
walkPattern: WalkPattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 人类属性枚举
|
|
||||||
export interface EnumHumanProperty {
|
|
||||||
Gender: typeof Gender;
|
|
||||||
Age: typeof Age;
|
|
||||||
Hat: typeof Hat;
|
|
||||||
Color: typeof Color;
|
|
||||||
Package: typeof Package;
|
|
||||||
WalkPattern: typeof WalkPattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IScreenshotButtonProp {
|
|
||||||
model: 'VIDEO' | 'IMAGE';
|
|
||||||
getCropInfo: () => Promise<RESP>;
|
|
||||||
setShowCrop: React.Dispatch<React.SetStateAction<boolean>>;
|
|
||||||
cropType: typeof cropType[number];
|
|
||||||
selectAlgorithmVersion: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AlignType {
|
|
||||||
/**
|
|
||||||
* move point of source node to align with point of target node.
|
|
||||||
* Such as ['tr','cc'], align top right point of source node with center point of target node.
|
|
||||||
* Point can be 't'(top), 'b'(bottom), 'c'(center), 'l'(left), 'r'(right) */
|
|
||||||
points?: AlignPoint[];
|
|
||||||
/**
|
|
||||||
* offset source node by offset[0] in x and offset[1] in y.
|
|
||||||
* If offset contains percentage string value, it is relative to sourceNode region.
|
|
||||||
*/
|
|
||||||
offset?: number[];
|
|
||||||
/**
|
|
||||||
* offset target node by offset[0] in x and offset[1] in y.
|
|
||||||
* If targetOffset contains percentage string value, it is relative to targetNode region.
|
|
||||||
*/
|
|
||||||
targetOffset?: number[];
|
|
||||||
/**
|
|
||||||
* If adjustX field is true, will adjust source node in x direction if source node is invisible.
|
|
||||||
* If adjustY field is true, will adjust source node in y direction if source node is invisible.
|
|
||||||
*/
|
|
||||||
overflow?: {
|
|
||||||
adjustX?: boolean | number;
|
|
||||||
adjustY?: boolean | number;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Whether use css right instead of left to position
|
|
||||||
*/
|
|
||||||
useCssRight?: boolean;
|
|
||||||
/**
|
|
||||||
* Whether use css bottom instead of top to position
|
|
||||||
*/
|
|
||||||
useCssBottom?: boolean;
|
|
||||||
/**
|
|
||||||
* Whether use css transform instead of left/top/right/bottom to position if browser supports.
|
|
||||||
* Defaults to false.
|
|
||||||
*/
|
|
||||||
useCssTransform?: boolean;
|
|
||||||
ignoreShake?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ODRECT = {
|
|
||||||
topleft: {
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
};
|
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface ViewOption {
|
|
||||||
/* 图片url */
|
|
||||||
image?: string | HTMLImageElement;
|
|
||||||
|
|
||||||
/* 缩放灵敏度(0,1],default: 0.1 */
|
|
||||||
wheelZoomRatio?: number;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 是否允许缩放
|
|
||||||
* @default: true
|
|
||||||
*/
|
|
||||||
scaleAble?: boolean;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 是否允许拖拽
|
|
||||||
* @default: true
|
|
||||||
*/
|
|
||||||
dragAble?: boolean;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* fit scale 作为 最小缩放
|
|
||||||
* @default: false
|
|
||||||
*/
|
|
||||||
fitScaleAsMinScale?: boolean;
|
|
||||||
}
|
|
0
packages/constants/lib/user/index.d.ts
vendored
Normal file
0
packages/constants/lib/user/index.d.ts
vendored
Normal file
0
packages/constants/lib/user/index.js
Normal file
0
packages/constants/lib/user/index.js
Normal file
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
nav:
|
nav:
|
||||||
title: 业务组件
|
title: 其它
|
||||||
order: 1
|
order: 1
|
||||||
title: 快速上手
|
title: 快速上手
|
||||||
---
|
---
|
||||||
|
0
packages/constants/src/user/index.ts
Normal file
0
packages/constants/src/user/index.ts
Normal file
41
packages/func/es/camera/constants.d.ts
vendored
41
packages/func/es/camera/constants.d.ts
vendored
@ -1,41 +0,0 @@
|
|||||||
/**
|
|
||||||
* 设备类型枚举
|
|
||||||
*/
|
|
||||||
export declare const DeviceType: {
|
|
||||||
VMS: string;
|
|
||||||
DIR: string;
|
|
||||||
CAMERA: string;
|
|
||||||
};
|
|
||||||
export declare const LOCAL_KEY = "local";
|
|
||||||
export declare const DIRE_CONNECT_KEY = "direconnect";
|
|
||||||
export declare const BOX_LIST_KEY = "boxlist";
|
|
||||||
export declare enum VmsplatformOpt {
|
|
||||||
VMSPLATFORMOPT_ID = 0,
|
|
||||||
VMSPLATFORMOPT_PLATFORMNAME = 1,
|
|
||||||
VMSPLATFORMOPT_PLUGINNAME = 2,
|
|
||||||
VMSPLATFORMOPT_IP = 3,
|
|
||||||
VMSPLATFORMOPT_PORT = 4,
|
|
||||||
VMSPLATFORMOPT_USERNAME = 5,
|
|
||||||
VMSPLATFORMOPT_PASSWORD = 6
|
|
||||||
}
|
|
||||||
export declare enum OPT {
|
|
||||||
OR = 0,
|
|
||||||
AND = 1,
|
|
||||||
ORNOT = 2,
|
|
||||||
ANDNOT = 3
|
|
||||||
}
|
|
||||||
export declare enum DevicemanagerCameraType {
|
|
||||||
DEVICEMANAGER_CAMERA_TYPE_DEFAULT = 0,
|
|
||||||
DEVICEMANAGER_CAMERA_TYPE_NORMAL = 1,
|
|
||||||
DEVICEMANAGER_CAMERA_TYPE_1400 = 97,
|
|
||||||
DEVICEMANAGER_CAMERA_TYPE_DHGRABBER = 98,
|
|
||||||
DEVICEMANAGER_CAMERA_TYPE_HKGRABBER = 99,
|
|
||||||
DEVICEMANAGER_CAMERA_TYPE_LOCAL = 100
|
|
||||||
}
|
|
||||||
export declare const BOX_DIRECONNECT_PLATFORM_FILTER: {
|
|
||||||
filtervmsplatformList: {
|
|
||||||
opt: OPT;
|
|
||||||
vmsplatformOpt: VmsplatformOpt;
|
|
||||||
value: string;
|
|
||||||
}[];
|
|
||||||
};
|
|
40
packages/func/es/camera/index.d.ts
vendored
40
packages/func/es/camera/index.d.ts
vendored
@ -1,40 +0,0 @@
|
|||||||
import { DevicemanagerCameraType } from './constants';
|
|
||||||
export declare const isFaceCamera: (type: DevicemanagerCameraType) => boolean;
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param value 传入的数据 可以是 item(camera/vms/dirs)/ deviceID
|
|
||||||
* @param isId
|
|
||||||
*/
|
|
||||||
export declare function getDeviceType(value: {
|
|
||||||
[x: string]: any;
|
|
||||||
id: any;
|
|
||||||
} | string): any;
|
|
||||||
/**
|
|
||||||
* 后端设备id/vmsid/dirid是三张表 合并在一起不保证唯一 前端生成唯一key
|
|
||||||
* @param id 设备id
|
|
||||||
* @param type 设备类型
|
|
||||||
*/
|
|
||||||
export declare function deviceIDToDeviceKey(id: any, type: string, vmsId?: any): string;
|
|
||||||
/**
|
|
||||||
* 后端设备id/vmsid/dirid是三张表 合并在一起不保证唯一 前端生成唯一key
|
|
||||||
* @param item camera/vms/dirs
|
|
||||||
*/
|
|
||||||
export declare function deviceToDeviceKey(item: {
|
|
||||||
[x: string]: any;
|
|
||||||
id: any;
|
|
||||||
}): string;
|
|
||||||
/**
|
|
||||||
* 设备树key 转 后端设备原始id dirid是string/vms&camera 是number 和后端保持一致
|
|
||||||
* @param deviceKey 设备树的id
|
|
||||||
*/
|
|
||||||
export declare function deviceKeyToDeviceId(deviceKey: {
|
|
||||||
split: (arg0: string) => [any, any];
|
|
||||||
}): any;
|
|
||||||
export declare const getVmsIdByDeviceId: (key: string) => string;
|
|
||||||
/**
|
|
||||||
* 通过设备id或设备key在树里面找摄像头
|
|
||||||
* @param ids cameraId
|
|
||||||
* @param deviceTree 树
|
|
||||||
* @param type "id" | "key"
|
|
||||||
*/
|
|
||||||
export declare const findCamerasByInDeviceTree: (ids: never[] | undefined, deviceTree: any, type?: string) => any[];
|
|
61
packages/func/es/file/index.d.ts
vendored
61
packages/func/es/file/index.d.ts
vendored
@ -1,61 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* @param url 需要转为图片的链接
|
|
||||||
* @returns 图片的 dom
|
|
||||||
*/
|
|
||||||
export declare const urlToImg: (url: string) => Promise<HTMLImageElement>;
|
|
||||||
export declare const base64DecodeImageKey: (base64ImgKey: string) => string;
|
|
||||||
/**
|
|
||||||
* 通过url获取图片的base64字符串
|
|
||||||
* @param src 图片链接
|
|
||||||
* @param outputFormat 图片格式
|
|
||||||
* @returns base64 @string
|
|
||||||
*/
|
|
||||||
export declare const getBase64ByUrl: (src: string | URL, outputFormat?: string) => Promise<unknown>;
|
|
||||||
/**
|
|
||||||
* 把文件转base64
|
|
||||||
* @param file @file 文件
|
|
||||||
* @returns @string
|
|
||||||
*/
|
|
||||||
export declare const fileToBase64: (file: any) => Promise<string>;
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param image @file 图片文件
|
|
||||||
* @param width @number 宽度
|
|
||||||
* @param height @number 高度
|
|
||||||
* @returns @string base64
|
|
||||||
*/
|
|
||||||
export declare const getBase64Image: (image: any, width?: any, height?: any) => string;
|
|
||||||
/**
|
|
||||||
* 通过图片获取base64
|
|
||||||
* @param src 图片地址
|
|
||||||
* @returns @string
|
|
||||||
*/
|
|
||||||
export declare const getBase64ByImage: (src: string) => Promise<unknown>;
|
|
||||||
/**
|
|
||||||
* url转base64
|
|
||||||
* @param {String} url - url地址
|
|
||||||
*/
|
|
||||||
export declare const urlToBase64V2: (url: string) => Promise<unknown>;
|
|
||||||
/**
|
|
||||||
* base64转Blob
|
|
||||||
* @param {String} base64 - base64
|
|
||||||
*/
|
|
||||||
export declare function base64toBlob(base64: string): Blob | undefined;
|
|
||||||
/**
|
|
||||||
* 图片集打包压缩下载
|
|
||||||
* 1. url -> base64 -> blob
|
|
||||||
* 2. 将blob加入jsZip文件夹内,用file-saver保存
|
|
||||||
* @param {Array<{url:string,name:string}>} imgDataList
|
|
||||||
* @param {string} zipName
|
|
||||||
*/
|
|
||||||
export declare const downloadPackageImages: (imgDataList: string | any[], zipName: string) => Promise<void>;
|
|
||||||
export declare function getFileSize(size: number): string;
|
|
||||||
export declare const dataURLToBlob: (dataurl: string) => Blob;
|
|
||||||
/**
|
|
||||||
* key 转 http 链接
|
|
||||||
* @param originImgkey 图片的值 ,可以是 base64 也可以是 http链接
|
|
||||||
* @param host 图片的域值
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
export declare const generateImg: (imgKey: string, host?: string) => string;
|
|
@ -343,4 +343,18 @@ export var generateImg = function generateImg(_imgKey) {
|
|||||||
imgUrl = '';
|
imgUrl = '';
|
||||||
}
|
}
|
||||||
return imgUrl;
|
return imgUrl;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定字符串后面的部分
|
||||||
|
* @param imageKey v1_开头的字符串
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export var getImageKey = function getImageKey(imageKey, preFix) {
|
||||||
|
var splitIndex = preFix || 'v1_';
|
||||||
|
if (imageKey.startsWith(splitIndex)) {
|
||||||
|
return window.atob(imageKey.split(splitIndex)[1]).replace('_', '/');
|
||||||
|
} else {
|
||||||
|
return imageKey;
|
||||||
|
}
|
||||||
};
|
};
|
9
packages/func/es/index.d.ts
vendored
9
packages/func/es/index.d.ts
vendored
@ -1,9 +0,0 @@
|
|||||||
export * from 'lodash-es';
|
|
||||||
export * from './file';
|
|
||||||
export * from './map';
|
|
||||||
export * from './performance';
|
|
||||||
export * from './string';
|
|
||||||
export * from './number';
|
|
||||||
export * from './time';
|
|
||||||
export * from './utils';
|
|
||||||
export * from './camera';
|
|
@ -6,4 +6,5 @@ export * from "./string";
|
|||||||
export * from "./number";
|
export * from "./number";
|
||||||
export * from "./time";
|
export * from "./time";
|
||||||
export * from "./utils";
|
export * from "./utils";
|
||||||
export * from "./camera";
|
export * from "./camera";
|
||||||
|
export * from "./math";
|
10
packages/func/es/map/index.d.ts
vendored
10
packages/func/es/map/index.d.ts
vendored
@ -1,10 +0,0 @@
|
|||||||
/**
|
|
||||||
* 获取经纬信息
|
|
||||||
* @param lngLat 位置信息
|
|
||||||
* @returns @object { long, lat }
|
|
||||||
*/
|
|
||||||
export declare const fixedLngLat: (lngLat?: string) => string;
|
|
||||||
export declare const transformLngLat: (lngLat?: string) => {
|
|
||||||
longitude: number;
|
|
||||||
latitude: number;
|
|
||||||
} | null;
|
|
413
packages/func/es/math/index.js
Normal file
413
packages/func/es/math/index.js
Normal file
File diff suppressed because one or more lines are too long
8
packages/func/es/number/index.d.ts
vendored
8
packages/func/es/number/index.d.ts
vendored
@ -1,8 +0,0 @@
|
|||||||
/**
|
|
||||||
* 设置数据的精度
|
|
||||||
* @param originNumber
|
|
||||||
* @param accuracy 精度 以原点为中心向左为正,向右为负,
|
|
||||||
* @param isCeil 是否为向上取整
|
|
||||||
* @returns number
|
|
||||||
*/
|
|
||||||
export declare const setNumberAccuracy: (originNumber: number, accuracy?: number, isCeil?: boolean) => number;
|
|
1
packages/func/es/performance/index.d.ts
vendored
1
packages/func/es/performance/index.d.ts
vendored
@ -1 +0,0 @@
|
|||||||
export declare const speedConvert: (bps: number, contertUnit?: number) => string;
|
|
7
packages/func/es/string/index.d.ts
vendored
7
packages/func/es/string/index.d.ts
vendored
@ -1,7 +0,0 @@
|
|||||||
export declare const getStrLength: (str: string) => number;
|
|
||||||
/**
|
|
||||||
* js截取字符串,中英文都能用
|
|
||||||
* @param str:需要截取的字符串
|
|
||||||
* @param len: 需要截取的长度
|
|
||||||
*/
|
|
||||||
export declare const cutStr: (str: string, len: number) => string | String | undefined;
|
|
5
packages/func/es/time/index.d.ts
vendored
5
packages/func/es/time/index.d.ts
vendored
@ -1,5 +0,0 @@
|
|||||||
export declare const formateDuration: (diff: number) => string;
|
|
||||||
export declare function generateTime(): {
|
|
||||||
startDateTime: number;
|
|
||||||
endDateTime: number;
|
|
||||||
};
|
|
117
packages/func/es/upload/index.js
Normal file
117
packages/func/es/upload/index.js
Normal file
File diff suppressed because one or more lines are too long
20
packages/func/es/utils/index.d.ts
vendored
20
packages/func/es/utils/index.d.ts
vendored
@ -1,20 +0,0 @@
|
|||||||
export { default as isChrome } from './isChrome';
|
|
||||||
export declare const matchS3Prefix: (str: string) => boolean;
|
|
||||||
/**
|
|
||||||
* 通过文件名获取文件类型
|
|
||||||
* @param fileName 文件名称
|
|
||||||
* @returns 文件类型
|
|
||||||
*/
|
|
||||||
export declare const getFileSuffix: (fileName: string) => string;
|
|
||||||
/**
|
|
||||||
* 通过类型获取文件名
|
|
||||||
* @param type 类型
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export declare const getImageSuffixByFileType: (type: string) => string;
|
|
||||||
export declare function getChromeVersion(): number | false;
|
|
||||||
export declare const nextTick: (func: (value: void) => void | PromiseLike<void>) => void;
|
|
||||||
export declare const loop: (items: string | any[], callback: (arg0: any) => any) => void;
|
|
||||||
export declare const addEventListener: (target: any, eventType: string, cb: any, option?: any) => {
|
|
||||||
remove: () => void;
|
|
||||||
};
|
|
@ -1,3 +1,4 @@
|
|||||||
|
import { isNumber } from 'lodash-es';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
export { default as isChrome } from "./isChrome";
|
export { default as isChrome } from "./isChrome";
|
||||||
export var matchS3Prefix = function matchS3Prefix(str) {
|
export var matchS3Prefix = function matchS3Prefix(str) {
|
||||||
@ -103,4 +104,41 @@ export var addEventListener = function addEventListener(target, eventType, cb, o
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get transforms base on the given object.
|
||||||
|
* @param {Object} obj - The target object.
|
||||||
|
* @returns {string} A string contains transform values.
|
||||||
|
*/
|
||||||
|
export function getTransforms(_ref) {
|
||||||
|
var rotate = _ref.rotate,
|
||||||
|
scaleX = _ref.scaleX,
|
||||||
|
scaleY = _ref.scaleY,
|
||||||
|
translateX = _ref.translateX,
|
||||||
|
translateY = _ref.translateY;
|
||||||
|
var values = [];
|
||||||
|
if (isNumber(translateX) && translateX !== 0) {
|
||||||
|
values.push("translateX(".concat(translateX, "px)"));
|
||||||
|
}
|
||||||
|
if (isNumber(translateY) && translateY !== 0) {
|
||||||
|
values.push("translateY(".concat(translateY, "px)"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate should come first before scale to match orientation transform
|
||||||
|
if (isNumber(rotate) && rotate !== 0) {
|
||||||
|
values.push("rotate(".concat(rotate, "deg)"));
|
||||||
|
}
|
||||||
|
if (isNumber(scaleX) && scaleX !== 1) {
|
||||||
|
values.push("scaleX(".concat(scaleX, ")"));
|
||||||
|
}
|
||||||
|
if (isNumber(scaleY) && scaleY !== 1) {
|
||||||
|
values.push("scaleY(".concat(scaleY, ")"));
|
||||||
|
}
|
||||||
|
var transform = values.length ? values.join(' ') : 'none';
|
||||||
|
return {
|
||||||
|
WebkitTransform: transform,
|
||||||
|
msTransform: transform,
|
||||||
|
transform: transform
|
||||||
|
};
|
||||||
|
}
|
3
packages/func/es/utils/isChrome.d.ts
vendored
3
packages/func/es/utils/isChrome.d.ts
vendored
@ -1,3 +0,0 @@
|
|||||||
export declare const isBrowser: boolean;
|
|
||||||
declare const isChrome: () => boolean;
|
|
||||||
export default isChrome;
|
|
41
packages/func/lib/camera/constants.d.ts
vendored
41
packages/func/lib/camera/constants.d.ts
vendored
@ -1,41 +0,0 @@
|
|||||||
/**
|
|
||||||
* 设备类型枚举
|
|
||||||
*/
|
|
||||||
export declare const DeviceType: {
|
|
||||||
VMS: string;
|
|
||||||
DIR: string;
|
|
||||||
CAMERA: string;
|
|
||||||
};
|
|
||||||
export declare const LOCAL_KEY = "local";
|
|
||||||
export declare const DIRE_CONNECT_KEY = "direconnect";
|
|
||||||
export declare const BOX_LIST_KEY = "boxlist";
|
|
||||||
export declare enum VmsplatformOpt {
|
|
||||||
VMSPLATFORMOPT_ID = 0,
|
|
||||||
VMSPLATFORMOPT_PLATFORMNAME = 1,
|
|
||||||
VMSPLATFORMOPT_PLUGINNAME = 2,
|
|
||||||
VMSPLATFORMOPT_IP = 3,
|
|
||||||
VMSPLATFORMOPT_PORT = 4,
|
|
||||||
VMSPLATFORMOPT_USERNAME = 5,
|
|
||||||
VMSPLATFORMOPT_PASSWORD = 6
|
|
||||||
}
|
|
||||||
export declare enum OPT {
|
|
||||||
OR = 0,
|
|
||||||
AND = 1,
|
|
||||||
ORNOT = 2,
|
|
||||||
ANDNOT = 3
|
|
||||||
}
|
|
||||||
export declare enum DevicemanagerCameraType {
|
|
||||||
DEVICEMANAGER_CAMERA_TYPE_DEFAULT = 0,
|
|
||||||
DEVICEMANAGER_CAMERA_TYPE_NORMAL = 1,
|
|
||||||
DEVICEMANAGER_CAMERA_TYPE_1400 = 97,
|
|
||||||
DEVICEMANAGER_CAMERA_TYPE_DHGRABBER = 98,
|
|
||||||
DEVICEMANAGER_CAMERA_TYPE_HKGRABBER = 99,
|
|
||||||
DEVICEMANAGER_CAMERA_TYPE_LOCAL = 100
|
|
||||||
}
|
|
||||||
export declare const BOX_DIRECONNECT_PLATFORM_FILTER: {
|
|
||||||
filtervmsplatformList: {
|
|
||||||
opt: OPT;
|
|
||||||
vmsplatformOpt: VmsplatformOpt;
|
|
||||||
value: string;
|
|
||||||
}[];
|
|
||||||
};
|
|
@ -1,90 +0,0 @@
|
|||||||
var __defProp = Object.defineProperty;
|
|
||||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
||||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
||||||
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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
||||||
|
|
||||||
// src/camera/constants.ts
|
|
||||||
var constants_exports = {};
|
|
||||||
__export(constants_exports, {
|
|
||||||
BOX_DIRECONNECT_PLATFORM_FILTER: () => BOX_DIRECONNECT_PLATFORM_FILTER,
|
|
||||||
BOX_LIST_KEY: () => BOX_LIST_KEY,
|
|
||||||
DIRE_CONNECT_KEY: () => DIRE_CONNECT_KEY,
|
|
||||||
DeviceType: () => DeviceType,
|
|
||||||
DevicemanagerCameraType: () => DevicemanagerCameraType,
|
|
||||||
LOCAL_KEY: () => LOCAL_KEY,
|
|
||||||
OPT: () => OPT,
|
|
||||||
VmsplatformOpt: () => VmsplatformOpt
|
|
||||||
});
|
|
||||||
module.exports = __toCommonJS(constants_exports);
|
|
||||||
var DeviceType = {
|
|
||||||
VMS: "vms",
|
|
||||||
DIR: "dir",
|
|
||||||
CAMERA: "camera"
|
|
||||||
};
|
|
||||||
var LOCAL_KEY = "local";
|
|
||||||
var DIRE_CONNECT_KEY = "direconnect";
|
|
||||||
var BOX_LIST_KEY = "boxlist";
|
|
||||||
var VmsplatformOpt = /* @__PURE__ */ ((VmsplatformOpt2) => {
|
|
||||||
VmsplatformOpt2[VmsplatformOpt2["VMSPLATFORMOPT_ID"] = 0] = "VMSPLATFORMOPT_ID";
|
|
||||||
VmsplatformOpt2[VmsplatformOpt2["VMSPLATFORMOPT_PLATFORMNAME"] = 1] = "VMSPLATFORMOPT_PLATFORMNAME";
|
|
||||||
VmsplatformOpt2[VmsplatformOpt2["VMSPLATFORMOPT_PLUGINNAME"] = 2] = "VMSPLATFORMOPT_PLUGINNAME";
|
|
||||||
VmsplatformOpt2[VmsplatformOpt2["VMSPLATFORMOPT_IP"] = 3] = "VMSPLATFORMOPT_IP";
|
|
||||||
VmsplatformOpt2[VmsplatformOpt2["VMSPLATFORMOPT_PORT"] = 4] = "VMSPLATFORMOPT_PORT";
|
|
||||||
VmsplatformOpt2[VmsplatformOpt2["VMSPLATFORMOPT_USERNAME"] = 5] = "VMSPLATFORMOPT_USERNAME";
|
|
||||||
VmsplatformOpt2[VmsplatformOpt2["VMSPLATFORMOPT_PASSWORD"] = 6] = "VMSPLATFORMOPT_PASSWORD";
|
|
||||||
return VmsplatformOpt2;
|
|
||||||
})(VmsplatformOpt || {});
|
|
||||||
var OPT = /* @__PURE__ */ ((OPT2) => {
|
|
||||||
OPT2[OPT2["OR"] = 0] = "OR";
|
|
||||||
OPT2[OPT2["AND"] = 1] = "AND";
|
|
||||||
OPT2[OPT2["ORNOT"] = 2] = "ORNOT";
|
|
||||||
OPT2[OPT2["ANDNOT"] = 3] = "ANDNOT";
|
|
||||||
return OPT2;
|
|
||||||
})(OPT || {});
|
|
||||||
var DevicemanagerCameraType = /* @__PURE__ */ ((DevicemanagerCameraType2) => {
|
|
||||||
DevicemanagerCameraType2[DevicemanagerCameraType2["DEVICEMANAGER_CAMERA_TYPE_DEFAULT"] = 0] = "DEVICEMANAGER_CAMERA_TYPE_DEFAULT";
|
|
||||||
DevicemanagerCameraType2[DevicemanagerCameraType2["DEVICEMANAGER_CAMERA_TYPE_NORMAL"] = 1] = "DEVICEMANAGER_CAMERA_TYPE_NORMAL";
|
|
||||||
DevicemanagerCameraType2[DevicemanagerCameraType2["DEVICEMANAGER_CAMERA_TYPE_1400"] = 97] = "DEVICEMANAGER_CAMERA_TYPE_1400";
|
|
||||||
DevicemanagerCameraType2[DevicemanagerCameraType2["DEVICEMANAGER_CAMERA_TYPE_DHGRABBER"] = 98] = "DEVICEMANAGER_CAMERA_TYPE_DHGRABBER";
|
|
||||||
DevicemanagerCameraType2[DevicemanagerCameraType2["DEVICEMANAGER_CAMERA_TYPE_HKGRABBER"] = 99] = "DEVICEMANAGER_CAMERA_TYPE_HKGRABBER";
|
|
||||||
DevicemanagerCameraType2[DevicemanagerCameraType2["DEVICEMANAGER_CAMERA_TYPE_LOCAL"] = 100] = "DEVICEMANAGER_CAMERA_TYPE_LOCAL";
|
|
||||||
return DevicemanagerCameraType2;
|
|
||||||
})(DevicemanagerCameraType || {});
|
|
||||||
var BOX_DIRECONNECT_PLATFORM_FILTER = {
|
|
||||||
filtervmsplatformList: [
|
|
||||||
{
|
|
||||||
opt: 0 /* OR */,
|
|
||||||
vmsplatformOpt: 1 /* VMSPLATFORMOPT_PLATFORMNAME */,
|
|
||||||
value: "direconnect"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
opt: 0 /* OR */,
|
|
||||||
vmsplatformOpt: 1 /* VMSPLATFORMOPT_PLATFORMNAME */,
|
|
||||||
value: "boxlist"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
// Annotate the CommonJS export names for ESM import in node:
|
|
||||||
0 && (module.exports = {
|
|
||||||
BOX_DIRECONNECT_PLATFORM_FILTER,
|
|
||||||
BOX_LIST_KEY,
|
|
||||||
DIRE_CONNECT_KEY,
|
|
||||||
DeviceType,
|
|
||||||
DevicemanagerCameraType,
|
|
||||||
LOCAL_KEY,
|
|
||||||
OPT,
|
|
||||||
VmsplatformOpt
|
|
||||||
});
|
|
40
packages/func/lib/camera/index.d.ts
vendored
40
packages/func/lib/camera/index.d.ts
vendored
@ -1,40 +0,0 @@
|
|||||||
import { DevicemanagerCameraType } from './constants';
|
|
||||||
export declare const isFaceCamera: (type: DevicemanagerCameraType) => boolean;
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param value 传入的数据 可以是 item(camera/vms/dirs)/ deviceID
|
|
||||||
* @param isId
|
|
||||||
*/
|
|
||||||
export declare function getDeviceType(value: {
|
|
||||||
[x: string]: any;
|
|
||||||
id: any;
|
|
||||||
} | string): any;
|
|
||||||
/**
|
|
||||||
* 后端设备id/vmsid/dirid是三张表 合并在一起不保证唯一 前端生成唯一key
|
|
||||||
* @param id 设备id
|
|
||||||
* @param type 设备类型
|
|
||||||
*/
|
|
||||||
export declare function deviceIDToDeviceKey(id: any, type: string, vmsId?: any): string;
|
|
||||||
/**
|
|
||||||
* 后端设备id/vmsid/dirid是三张表 合并在一起不保证唯一 前端生成唯一key
|
|
||||||
* @param item camera/vms/dirs
|
|
||||||
*/
|
|
||||||
export declare function deviceToDeviceKey(item: {
|
|
||||||
[x: string]: any;
|
|
||||||
id: any;
|
|
||||||
}): string;
|
|
||||||
/**
|
|
||||||
* 设备树key 转 后端设备原始id dirid是string/vms&camera 是number 和后端保持一致
|
|
||||||
* @param deviceKey 设备树的id
|
|
||||||
*/
|
|
||||||
export declare function deviceKeyToDeviceId(deviceKey: {
|
|
||||||
split: (arg0: string) => [any, any];
|
|
||||||
}): any;
|
|
||||||
export declare const getVmsIdByDeviceId: (key: string) => string;
|
|
||||||
/**
|
|
||||||
* 通过设备id或设备key在树里面找摄像头
|
|
||||||
* @param ids cameraId
|
|
||||||
* @param deviceTree 树
|
|
||||||
* @param type "id" | "key"
|
|
||||||
*/
|
|
||||||
export declare const findCamerasByInDeviceTree: (ids: never[] | undefined, deviceTree: any, type?: string) => any[];
|
|
@ -1,143 +0,0 @@
|
|||||||
var __defProp = Object.defineProperty;
|
|
||||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
||||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
||||||
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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
||||||
|
|
||||||
// src/camera/index.ts
|
|
||||||
var camera_exports = {};
|
|
||||||
__export(camera_exports, {
|
|
||||||
deviceIDToDeviceKey: () => deviceIDToDeviceKey,
|
|
||||||
deviceKeyToDeviceId: () => deviceKeyToDeviceId,
|
|
||||||
deviceToDeviceKey: () => deviceToDeviceKey,
|
|
||||||
findCamerasByInDeviceTree: () => findCamerasByInDeviceTree,
|
|
||||||
getDeviceType: () => getDeviceType,
|
|
||||||
getVmsIdByDeviceId: () => getVmsIdByDeviceId,
|
|
||||||
isFaceCamera: () => isFaceCamera
|
|
||||||
});
|
|
||||||
module.exports = __toCommonJS(camera_exports);
|
|
||||||
var import_lodash_es = require("lodash-es");
|
|
||||||
var import_utils = require("../utils");
|
|
||||||
var import_constants = require("./constants");
|
|
||||||
var isFaceCamera = (type) => {
|
|
||||||
return [
|
|
||||||
import_constants.DevicemanagerCameraType.DEVICEMANAGER_CAMERA_TYPE_1400,
|
|
||||||
import_constants.DevicemanagerCameraType.DEVICEMANAGER_CAMERA_TYPE_HKGRABBER,
|
|
||||||
import_constants.DevicemanagerCameraType.DEVICEMANAGER_CAMERA_TYPE_DHGRABBER
|
|
||||||
].includes(type);
|
|
||||||
};
|
|
||||||
function getDeviceType(value) {
|
|
||||||
let type;
|
|
||||||
let isDeviceKey = (0, import_lodash_es.isString)(value);
|
|
||||||
if (isDeviceKey) {
|
|
||||||
type = value.split("_")[0];
|
|
||||||
} else {
|
|
||||||
if ((0, import_lodash_es.has)(value, "longitude")) {
|
|
||||||
type = import_constants.DeviceType["CAMERA"];
|
|
||||||
}
|
|
||||||
if ((0, import_lodash_es.has)(value, "ip")) {
|
|
||||||
type = import_constants.DeviceType["VMS"];
|
|
||||||
}
|
|
||||||
if (!type) {
|
|
||||||
type = import_constants.DeviceType["DIR"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
function deviceIDToDeviceKey(id, type, vmsId) {
|
|
||||||
if (type == import_constants.DeviceType["DIR"]) {
|
|
||||||
return `${type}_${id}_${vmsId}`;
|
|
||||||
} else {
|
|
||||||
return `${type}_${id}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function deviceToDeviceKey(item) {
|
|
||||||
let deviceKey = "";
|
|
||||||
let type = getDeviceType(item);
|
|
||||||
if (!type) {
|
|
||||||
console.error("device type is null!");
|
|
||||||
}
|
|
||||||
switch (type) {
|
|
||||||
case import_constants.DeviceType["DIR"]:
|
|
||||||
{
|
|
||||||
let dirId = item["dirid"] || item["dirId"];
|
|
||||||
if (!dirId && dirId !== 0) {
|
|
||||||
console.error("dirId type is null!");
|
|
||||||
}
|
|
||||||
let vmsId = (0, import_lodash_es.get)(item, "extendInfo.vmsPlatformId");
|
|
||||||
if (!vmsId && vmsId !== 0) {
|
|
||||||
console.error("vmsId type is null!");
|
|
||||||
}
|
|
||||||
deviceKey = `${type}_${dirId}_${vmsId}`;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case import_constants.DeviceType["VMS"]:
|
|
||||||
deviceKey = `${type}_${item["id"]}`;
|
|
||||||
break;
|
|
||||||
case import_constants.DeviceType["CAMERA"]:
|
|
||||||
{
|
|
||||||
let vmsId = (0, import_lodash_es.get)(item, "extendInfo.vmsPlatformId");
|
|
||||||
if (!vmsId && vmsId !== 0) {
|
|
||||||
console.error("vmsId type is null!");
|
|
||||||
}
|
|
||||||
deviceKey = `${type}_${item.id}`;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return deviceKey;
|
|
||||||
}
|
|
||||||
function deviceKeyToDeviceId(deviceKey) {
|
|
||||||
let [type, id] = deviceKey.split("_");
|
|
||||||
return type === import_constants.DeviceType["DIR"] ? id : Number(id);
|
|
||||||
}
|
|
||||||
var getVmsIdByDeviceId = (key) => {
|
|
||||||
const type = getDeviceType(key);
|
|
||||||
let vmsId = "";
|
|
||||||
switch (type) {
|
|
||||||
case import_constants.DeviceType["CAMERA"]:
|
|
||||||
case import_constants.DeviceType["DIR"]:
|
|
||||||
vmsId = key.split("_")[2];
|
|
||||||
break;
|
|
||||||
case import_constants.DeviceType["VMS"]:
|
|
||||||
vmsId = key.split("_")[1];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!vmsId) {
|
|
||||||
console.error("vmsid is null!");
|
|
||||||
}
|
|
||||||
return vmsId;
|
|
||||||
};
|
|
||||||
var findCamerasByInDeviceTree = (ids = [], deviceTree, type = "id") => {
|
|
||||||
let cameraInfoList = [];
|
|
||||||
let _ids = ids.map((v) => String(v));
|
|
||||||
(0, import_utils.loop)(deviceTree, (item) => {
|
|
||||||
let isCamera = getDeviceType((0, import_lodash_es.get)(item, "key", "")) === import_constants.DeviceType["CAMERA"];
|
|
||||||
let isMatch = type === "key" ? _ids.includes((0, import_lodash_es.get)(item, "key")) : _ids.includes(`${(0, import_lodash_es.get)(item, "origin.id")}`);
|
|
||||||
if (isCamera && isMatch) {
|
|
||||||
cameraInfoList.push(item);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return cameraInfoList;
|
|
||||||
};
|
|
||||||
// Annotate the CommonJS export names for ESM import in node:
|
|
||||||
0 && (module.exports = {
|
|
||||||
deviceIDToDeviceKey,
|
|
||||||
deviceKeyToDeviceId,
|
|
||||||
deviceToDeviceKey,
|
|
||||||
findCamerasByInDeviceTree,
|
|
||||||
getDeviceType,
|
|
||||||
getVmsIdByDeviceId,
|
|
||||||
isFaceCamera
|
|
||||||
});
|
|
61
packages/func/lib/file/index.d.ts
vendored
61
packages/func/lib/file/index.d.ts
vendored
@ -1,61 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* @param url 需要转为图片的链接
|
|
||||||
* @returns 图片的 dom
|
|
||||||
*/
|
|
||||||
export declare const urlToImg: (url: string) => Promise<HTMLImageElement>;
|
|
||||||
export declare const base64DecodeImageKey: (base64ImgKey: string) => string;
|
|
||||||
/**
|
|
||||||
* 通过url获取图片的base64字符串
|
|
||||||
* @param src 图片链接
|
|
||||||
* @param outputFormat 图片格式
|
|
||||||
* @returns base64 @string
|
|
||||||
*/
|
|
||||||
export declare const getBase64ByUrl: (src: string | URL, outputFormat?: string) => Promise<unknown>;
|
|
||||||
/**
|
|
||||||
* 把文件转base64
|
|
||||||
* @param file @file 文件
|
|
||||||
* @returns @string
|
|
||||||
*/
|
|
||||||
export declare const fileToBase64: (file: any) => Promise<string>;
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param image @file 图片文件
|
|
||||||
* @param width @number 宽度
|
|
||||||
* @param height @number 高度
|
|
||||||
* @returns @string base64
|
|
||||||
*/
|
|
||||||
export declare const getBase64Image: (image: any, width?: any, height?: any) => string;
|
|
||||||
/**
|
|
||||||
* 通过图片获取base64
|
|
||||||
* @param src 图片地址
|
|
||||||
* @returns @string
|
|
||||||
*/
|
|
||||||
export declare const getBase64ByImage: (src: string) => Promise<unknown>;
|
|
||||||
/**
|
|
||||||
* url转base64
|
|
||||||
* @param {String} url - url地址
|
|
||||||
*/
|
|
||||||
export declare const urlToBase64V2: (url: string) => Promise<unknown>;
|
|
||||||
/**
|
|
||||||
* base64转Blob
|
|
||||||
* @param {String} base64 - base64
|
|
||||||
*/
|
|
||||||
export declare function base64toBlob(base64: string): Blob | undefined;
|
|
||||||
/**
|
|
||||||
* 图片集打包压缩下载
|
|
||||||
* 1. url -> base64 -> blob
|
|
||||||
* 2. 将blob加入jsZip文件夹内,用file-saver保存
|
|
||||||
* @param {Array<{url:string,name:string}>} imgDataList
|
|
||||||
* @param {string} zipName
|
|
||||||
*/
|
|
||||||
export declare const downloadPackageImages: (imgDataList: string | any[], zipName: string) => Promise<void>;
|
|
||||||
export declare function getFileSize(size: number): string;
|
|
||||||
export declare const dataURLToBlob: (dataurl: string) => Blob;
|
|
||||||
/**
|
|
||||||
* key 转 http 链接
|
|
||||||
* @param originImgkey 图片的值 ,可以是 base64 也可以是 http链接
|
|
||||||
* @param host 图片的域值
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
export declare const generateImg: (imgKey: string, host?: string) => string;
|
|
@ -1,280 +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/file/index.ts
|
|
||||||
var file_exports = {};
|
|
||||||
__export(file_exports, {
|
|
||||||
base64DecodeImageKey: () => base64DecodeImageKey,
|
|
||||||
base64toBlob: () => base64toBlob,
|
|
||||||
dataURLToBlob: () => dataURLToBlob,
|
|
||||||
downloadPackageImages: () => downloadPackageImages,
|
|
||||||
fileToBase64: () => fileToBase64,
|
|
||||||
generateImg: () => generateImg,
|
|
||||||
getBase64ByImage: () => getBase64ByImage,
|
|
||||||
getBase64ByUrl: () => getBase64ByUrl,
|
|
||||||
getBase64Image: () => getBase64Image,
|
|
||||||
getFileSize: () => getFileSize,
|
|
||||||
urlToBase64V2: () => urlToBase64V2,
|
|
||||||
urlToImg: () => urlToImg
|
|
||||||
});
|
|
||||||
module.exports = __toCommonJS(file_exports);
|
|
||||||
var import_base_64 = __toESM(require("base-64"));
|
|
||||||
var import_jszip = __toESM(require("jszip"));
|
|
||||||
var import_file_saver = __toESM(require("file-saver"));
|
|
||||||
var import_utils = require("../utils");
|
|
||||||
var import_lodash_es = require("lodash-es");
|
|
||||||
var urlToImg = (url) => {
|
|
||||||
const resImage = new Promise((resolve) => {
|
|
||||||
const image = new Image();
|
|
||||||
image.crossOrigin = "";
|
|
||||||
image.src = url;
|
|
||||||
image.onload = () => {
|
|
||||||
resolve(image);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return resImage;
|
|
||||||
};
|
|
||||||
var base64DecodeImageKey = (base64ImgKey) => {
|
|
||||||
let tempStr = base64ImgKey;
|
|
||||||
if ((0, import_utils.matchS3Prefix)(tempStr)) {
|
|
||||||
tempStr = tempStr.replace(/^v[0-9]_/, "");
|
|
||||||
tempStr = import_base_64.default.decode(tempStr);
|
|
||||||
}
|
|
||||||
const [bucket, ...pathArr] = tempStr.split("_");
|
|
||||||
return tempStr = `${bucket}/${pathArr.join("_")}`;
|
|
||||||
};
|
|
||||||
var getBase64ByUrl = function(src, outputFormat = "image/png") {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
xhr.open("GET", src, true);
|
|
||||||
xhr.responseType = "arraybuffer";
|
|
||||||
xhr.onload = function(e) {
|
|
||||||
if (Number(xhr.status) === 200) {
|
|
||||||
const uInt8Array = new Uint8Array(xhr.response);
|
|
||||||
let i = uInt8Array.length;
|
|
||||||
const binaryString = new Array(i);
|
|
||||||
while (i--) {
|
|
||||||
binaryString[i] = String.fromCharCode(uInt8Array[i]);
|
|
||||||
}
|
|
||||||
const data = binaryString.join("");
|
|
||||||
const base64 = window.btoa(data);
|
|
||||||
const dataUrl = "data:" + (outputFormat || "image/png") + ";base64," + base64;
|
|
||||||
resolve(dataUrl);
|
|
||||||
} else {
|
|
||||||
reject(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
xhr.onerror = (e) => {
|
|
||||||
reject(e);
|
|
||||||
};
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
var fileToBase64 = (file) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.readAsDataURL(file);
|
|
||||||
reader.onload = function(e) {
|
|
||||||
resolve(e == null ? void 0 : e.target.result);
|
|
||||||
};
|
|
||||||
reader.onerror = function(e) {
|
|
||||||
reject(e);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
var getBase64Image = (image, width, height) => {
|
|
||||||
const canvas = document.createElement("canvas");
|
|
||||||
canvas.width = width !== void 0 ? width : image.width;
|
|
||||||
canvas.height = height !== void 0 ? height : image.height;
|
|
||||||
const ctx = canvas.getContext("2d");
|
|
||||||
ctx == null ? void 0 : ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
|
|
||||||
const ext = image.src.substring(image.src.lastIndexOf(".") + 1).toLowerCase();
|
|
||||||
const dataURL = canvas.toDataURL("image/" + ext);
|
|
||||||
return dataURL;
|
|
||||||
};
|
|
||||||
var getBase64ByImage = function(src) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const image = new Image();
|
|
||||||
const timestamp = (/* @__PURE__ */ new Date()).getTime();
|
|
||||||
const imgUrl = src + "?" + timestamp;
|
|
||||||
image.src = imgUrl;
|
|
||||||
image.onload = function() {
|
|
||||||
function getBase64Image2(img) {
|
|
||||||
const canvas = document.createElement("canvas");
|
|
||||||
canvas.width = img.width;
|
|
||||||
canvas.height = img.height;
|
|
||||||
const ctx = canvas.getContext("2d");
|
|
||||||
ctx == null ? void 0 : ctx.drawImage(img, 0, 0, img.width, img.height);
|
|
||||||
const ext = img.src.substring(img.src.lastIndexOf(".") + 1).toLowerCase();
|
|
||||||
const dataURL = canvas.toDataURL("image/" + ext);
|
|
||||||
return dataURL;
|
|
||||||
}
|
|
||||||
const base64 = getBase64Image2(image);
|
|
||||||
resolve(base64);
|
|
||||||
};
|
|
||||||
image.onerror = (e) => {
|
|
||||||
reject(e);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
var urlToBase64V2 = (url) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let image = new Image();
|
|
||||||
image.onload = function() {
|
|
||||||
var _a;
|
|
||||||
let canvas = document.createElement("canvas");
|
|
||||||
canvas.width = image.naturalWidth;
|
|
||||||
canvas.height = image.naturalHeight;
|
|
||||||
(_a = canvas == null ? void 0 : canvas.getContext("2d")) == null ? void 0 : _a.drawImage(image, 0, 0);
|
|
||||||
let result = canvas.toDataURL("image/png");
|
|
||||||
resolve(result);
|
|
||||||
};
|
|
||||||
const imgUrl = url;
|
|
||||||
image.setAttribute("crossOrigin", "Anonymous");
|
|
||||||
image.src = imgUrl;
|
|
||||||
image.onerror = () => {
|
|
||||||
reject(new Error("Images fail to load"));
|
|
||||||
};
|
|
||||||
}).catch((error) => {
|
|
||||||
throw new Error(error);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
function base64toBlob(base64) {
|
|
||||||
if (!base64)
|
|
||||||
return;
|
|
||||||
var arr = base64.split(","), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
|
|
||||||
while (n--) {
|
|
||||||
u8arr[n] = bstr.charCodeAt(n);
|
|
||||||
}
|
|
||||||
return new Blob([u8arr], { type: mime });
|
|
||||||
}
|
|
||||||
var downloadPackageImages = async (imgDataList, zipName) => {
|
|
||||||
let imgDataDownLoadList = [];
|
|
||||||
let imgBlobList = [];
|
|
||||||
let imageSuffix = [];
|
|
||||||
let zip = new import_jszip.default();
|
|
||||||
let img = zip.folder(zipName);
|
|
||||||
try {
|
|
||||||
for (let i2 = 0; i2 < imgDataList.length; i2++) {
|
|
||||||
let src = imgDataList[i2].url;
|
|
||||||
let suffix = src.substring(src.lastIndexOf("."));
|
|
||||||
let base64ByUrl = await urlToBase64V2(imgDataList[i2].url);
|
|
||||||
if (!base64ByUrl)
|
|
||||||
continue;
|
|
||||||
let blob = base64toBlob(base64ByUrl);
|
|
||||||
imgDataDownLoadList.push(imgDataList[i2]);
|
|
||||||
imgBlobList.push(blob);
|
|
||||||
imageSuffix.push(suffix);
|
|
||||||
}
|
|
||||||
if (imgBlobList.length === 0)
|
|
||||||
throw new Error("The number of pictures is zero !");
|
|
||||||
if (imgBlobList.length > 0) {
|
|
||||||
for (var i = 0; i < imgBlobList.length; i++) {
|
|
||||||
img == null ? void 0 : img.file(
|
|
||||||
imgDataDownLoadList[i].name + (0, import_lodash_es.get)(imageSuffix, `.${i}`, imageSuffix[0]),
|
|
||||||
// @ts-ignore
|
|
||||||
imgBlobList[i],
|
|
||||||
{
|
|
||||||
base64: true
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
zip.generateAsync({ type: "blob" }).then(function(content) {
|
|
||||||
import_file_saver.default.saveAs(content, zipName + ".zip");
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
throw new Error(error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
function getFileSize(size) {
|
|
||||||
if (!size)
|
|
||||||
return "";
|
|
||||||
var num = 1024;
|
|
||||||
if (size < num)
|
|
||||||
return size + "B";
|
|
||||||
if (size < Math.pow(num, 2))
|
|
||||||
return (size / num).toFixed(2) + "K";
|
|
||||||
if (size < Math.pow(num, 3))
|
|
||||||
return (size / Math.pow(num, 2)).toFixed(2) + "M";
|
|
||||||
if (size < Math.pow(num, 4))
|
|
||||||
return (size / Math.pow(num, 3)).toFixed(2) + "G";
|
|
||||||
return (size / Math.pow(num, 4)).toFixed(2) + "T";
|
|
||||||
}
|
|
||||||
var dataURLToBlob = (dataurl) => {
|
|
||||||
const arr = dataurl.split(",");
|
|
||||||
const mime = arr[0].match(/:(.*?);/)[1];
|
|
||||||
const bstr = atob(arr[1]);
|
|
||||||
let n = bstr.length;
|
|
||||||
const u8arr = new Uint8Array(n);
|
|
||||||
while (n--) {
|
|
||||||
u8arr[n] = bstr.charCodeAt(n);
|
|
||||||
}
|
|
||||||
return new Blob([u8arr], { type: mime });
|
|
||||||
};
|
|
||||||
var generateImg = (_imgKey, host = "http://10.0.0.120") => {
|
|
||||||
let imgKey = _imgKey;
|
|
||||||
let imgUrl = "";
|
|
||||||
if (!imgKey)
|
|
||||||
return "";
|
|
||||||
if (/^(http:|https:)/.test(imgKey)) {
|
|
||||||
return imgKey;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if ((0, import_utils.matchS3Prefix)(imgKey)) {
|
|
||||||
imgKey = base64DecodeImageKey(imgKey);
|
|
||||||
if (imgKey.endsWith("/")) {
|
|
||||||
const i = imgKey.substring(0, imgKey.length - 1);
|
|
||||||
imgKey = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
imgUrl = `${host}/file/${imgKey}`;
|
|
||||||
if (_imgKey.includes("v3")) {
|
|
||||||
imgUrl = `${host}/minio/${imgKey}`;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
imgUrl = "";
|
|
||||||
}
|
|
||||||
return imgUrl;
|
|
||||||
};
|
|
||||||
// Annotate the CommonJS export names for ESM import in node:
|
|
||||||
0 && (module.exports = {
|
|
||||||
base64DecodeImageKey,
|
|
||||||
base64toBlob,
|
|
||||||
dataURLToBlob,
|
|
||||||
downloadPackageImages,
|
|
||||||
fileToBase64,
|
|
||||||
generateImg,
|
|
||||||
getBase64ByImage,
|
|
||||||
getBase64ByUrl,
|
|
||||||
getBase64Image,
|
|
||||||
getFileSize,
|
|
||||||
urlToBase64V2,
|
|
||||||
urlToImg
|
|
||||||
});
|
|
9
packages/func/lib/index.d.ts
vendored
9
packages/func/lib/index.d.ts
vendored
@ -1,9 +0,0 @@
|
|||||||
export * from 'lodash-es';
|
|
||||||
export * from './file';
|
|
||||||
export * from './map';
|
|
||||||
export * from './performance';
|
|
||||||
export * from './string';
|
|
||||||
export * from './number';
|
|
||||||
export * from './time';
|
|
||||||
export * from './utils';
|
|
||||||
export * from './camera';
|
|
@ -1,39 +0,0 @@
|
|||||||
var __defProp = Object.defineProperty;
|
|
||||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
||||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
||||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
||||||
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 __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
||||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
||||||
|
|
||||||
// src/index.ts
|
|
||||||
var src_exports = {};
|
|
||||||
module.exports = __toCommonJS(src_exports);
|
|
||||||
__reExport(src_exports, require("lodash-es"), module.exports);
|
|
||||||
__reExport(src_exports, require("./file"), module.exports);
|
|
||||||
__reExport(src_exports, require("./map"), module.exports);
|
|
||||||
__reExport(src_exports, require("./performance"), module.exports);
|
|
||||||
__reExport(src_exports, require("./string"), module.exports);
|
|
||||||
__reExport(src_exports, require("./number"), module.exports);
|
|
||||||
__reExport(src_exports, require("./time"), module.exports);
|
|
||||||
__reExport(src_exports, require("./utils"), module.exports);
|
|
||||||
__reExport(src_exports, require("./camera"), module.exports);
|
|
||||||
// Annotate the CommonJS export names for ESM import in node:
|
|
||||||
0 && (module.exports = {
|
|
||||||
...require("lodash-es"),
|
|
||||||
...require("./file"),
|
|
||||||
...require("./map"),
|
|
||||||
...require("./performance"),
|
|
||||||
...require("./string"),
|
|
||||||
...require("./number"),
|
|
||||||
...require("./time"),
|
|
||||||
...require("./utils"),
|
|
||||||
...require("./camera")
|
|
||||||
});
|
|
10
packages/func/lib/map/index.d.ts
vendored
10
packages/func/lib/map/index.d.ts
vendored
@ -1,10 +0,0 @@
|
|||||||
/**
|
|
||||||
* 获取经纬信息
|
|
||||||
* @param lngLat 位置信息
|
|
||||||
* @returns @object { long, lat }
|
|
||||||
*/
|
|
||||||
export declare const fixedLngLat: (lngLat?: string) => string;
|
|
||||||
export declare const transformLngLat: (lngLat?: string) => {
|
|
||||||
longitude: number;
|
|
||||||
latitude: number;
|
|
||||||
} | null;
|
|
@ -1,54 +0,0 @@
|
|||||||
var __defProp = Object.defineProperty;
|
|
||||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
||||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
||||||
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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
||||||
|
|
||||||
// src/map/index.ts
|
|
||||||
var map_exports = {};
|
|
||||||
__export(map_exports, {
|
|
||||||
fixedLngLat: () => fixedLngLat,
|
|
||||||
transformLngLat: () => transformLngLat
|
|
||||||
});
|
|
||||||
module.exports = __toCommonJS(map_exports);
|
|
||||||
var fixedLngLat = (lngLat) => {
|
|
||||||
if (!lngLat) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
const lngLatArr = lngLat.split(",");
|
|
||||||
const longitude = Number(lngLatArr[0]).toFixed(6);
|
|
||||||
const latitude = Number(lngLatArr[1]).toFixed(6);
|
|
||||||
if (lngLatArr.length < 2) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return `${longitude},${latitude}`;
|
|
||||||
};
|
|
||||||
var transformLngLat = (lngLat) => {
|
|
||||||
if (lngLat) {
|
|
||||||
const lngLatArr = lngLat ? lngLat.split(",") : [];
|
|
||||||
const longitude = Number(lngLatArr[0]);
|
|
||||||
const latitude = Number(lngLatArr[1]);
|
|
||||||
if (lngLatArr.length < 2) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return { longitude, latitude };
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
// Annotate the CommonJS export names for ESM import in node:
|
|
||||||
0 && (module.exports = {
|
|
||||||
fixedLngLat,
|
|
||||||
transformLngLat
|
|
||||||
});
|
|
8
packages/func/lib/number/index.d.ts
vendored
8
packages/func/lib/number/index.d.ts
vendored
@ -1,8 +0,0 @@
|
|||||||
/**
|
|
||||||
* 设置数据的精度
|
|
||||||
* @param originNumber
|
|
||||||
* @param accuracy 精度 以原点为中心向左为正,向右为负,
|
|
||||||
* @param isCeil 是否为向上取整
|
|
||||||
* @returns number
|
|
||||||
*/
|
|
||||||
export declare const setNumberAccuracy: (originNumber: number, accuracy?: number, isCeil?: boolean) => number;
|
|
@ -1,45 +0,0 @@
|
|||||||
var __defProp = Object.defineProperty;
|
|
||||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
||||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
||||||
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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
||||||
|
|
||||||
// src/number/index.ts
|
|
||||||
var number_exports = {};
|
|
||||||
__export(number_exports, {
|
|
||||||
setNumberAccuracy: () => setNumberAccuracy
|
|
||||||
});
|
|
||||||
module.exports = __toCommonJS(number_exports);
|
|
||||||
var setNumberAccuracy = (originNumber, accuracy = 0, isCeil = true) => {
|
|
||||||
if (originNumber === 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
let returnData = 0;
|
|
||||||
if (isCeil) {
|
|
||||||
returnData = Math.ceil(originNumber / Math.pow(10, accuracy)) * Math.pow(10, accuracy);
|
|
||||||
} else {
|
|
||||||
returnData = Math.floor(originNumber / Math.pow(10, accuracy)) * Math.pow(10, accuracy);
|
|
||||||
}
|
|
||||||
if (accuracy < 0) {
|
|
||||||
returnData = Number(returnData.toFixed(-accuracy));
|
|
||||||
} else {
|
|
||||||
returnData = Number(returnData.toFixed(0));
|
|
||||||
}
|
|
||||||
return returnData;
|
|
||||||
};
|
|
||||||
// Annotate the CommonJS export names for ESM import in node:
|
|
||||||
0 && (module.exports = {
|
|
||||||
setNumberAccuracy
|
|
||||||
});
|
|
1
packages/func/lib/performance/index.d.ts
vendored
1
packages/func/lib/performance/index.d.ts
vendored
@ -1 +0,0 @@
|
|||||||
export declare const speedConvert: (bps: number, contertUnit?: number) => string;
|
|
@ -1,41 +0,0 @@
|
|||||||
var __defProp = Object.defineProperty;
|
|
||||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
||||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
||||||
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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
||||||
|
|
||||||
// src/performance/index.ts
|
|
||||||
var performance_exports = {};
|
|
||||||
__export(performance_exports, {
|
|
||||||
speedConvert: () => speedConvert
|
|
||||||
});
|
|
||||||
module.exports = __toCommonJS(performance_exports);
|
|
||||||
var speedConvert = (bps, contertUnit = 8) => {
|
|
||||||
if (bps === void 0)
|
|
||||||
return `0KB/s`;
|
|
||||||
const byte = bps / contertUnit;
|
|
||||||
if (bps > 1024 * 1024 * 1024) {
|
|
||||||
return `${(byte / 1024 / 1024 / 1024).toFixed(2)}GB/s`;
|
|
||||||
} else if (byte > 1024 * 1024) {
|
|
||||||
return `${(byte / 1024 / 1024).toFixed(2)}MB/s`;
|
|
||||||
} else if (byte > 1024) {
|
|
||||||
return `${(byte / 1024).toFixed(2)}KB/s`;
|
|
||||||
}
|
|
||||||
return `${byte}KB/s`;
|
|
||||||
};
|
|
||||||
// Annotate the CommonJS export names for ESM import in node:
|
|
||||||
0 && (module.exports = {
|
|
||||||
speedConvert
|
|
||||||
});
|
|
7
packages/func/lib/string/index.d.ts
vendored
7
packages/func/lib/string/index.d.ts
vendored
@ -1,7 +0,0 @@
|
|||||||
export declare const getStrLength: (str: string) => number;
|
|
||||||
/**
|
|
||||||
* js截取字符串,中英文都能用
|
|
||||||
* @param str:需要截取的字符串
|
|
||||||
* @param len: 需要截取的长度
|
|
||||||
*/
|
|
||||||
export declare const cutStr: (str: string, len: number) => string | String | undefined;
|
|
@ -1,62 +0,0 @@
|
|||||||
var __defProp = Object.defineProperty;
|
|
||||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
||||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
||||||
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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
||||||
|
|
||||||
// src/string/index.ts
|
|
||||||
var string_exports = {};
|
|
||||||
__export(string_exports, {
|
|
||||||
cutStr: () => cutStr,
|
|
||||||
getStrLength: () => getStrLength
|
|
||||||
});
|
|
||||||
module.exports = __toCommonJS(string_exports);
|
|
||||||
var getStrLength = function(str) {
|
|
||||||
var realLength = 0, len = str.length, charCode = -1;
|
|
||||||
for (var i = 0; i < len; i++) {
|
|
||||||
charCode = str.charCodeAt(i);
|
|
||||||
if (charCode >= 0 && charCode <= 128)
|
|
||||||
realLength += 1;
|
|
||||||
else
|
|
||||||
realLength += 2;
|
|
||||||
}
|
|
||||||
return realLength;
|
|
||||||
};
|
|
||||||
var cutStr = function cutstr(str, len) {
|
|
||||||
var str_length = 0;
|
|
||||||
var str_len = 0;
|
|
||||||
let str_cut = new String();
|
|
||||||
str_len = str.length;
|
|
||||||
for (var i = 0; i < str_len; i++) {
|
|
||||||
let a = str.charAt(i);
|
|
||||||
str_length++;
|
|
||||||
if (escape(a).length > 4) {
|
|
||||||
str_length++;
|
|
||||||
}
|
|
||||||
str_cut = str_cut.concat(a);
|
|
||||||
if (str_length >= len) {
|
|
||||||
str_cut = str_cut.concat("...");
|
|
||||||
return str_cut;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (str_length < len) {
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Annotate the CommonJS export names for ESM import in node:
|
|
||||||
0 && (module.exports = {
|
|
||||||
cutStr,
|
|
||||||
getStrLength
|
|
||||||
});
|
|
5
packages/func/lib/time/index.d.ts
vendored
5
packages/func/lib/time/index.d.ts
vendored
@ -1,5 +0,0 @@
|
|||||||
export declare const formateDuration: (diff: number) => string;
|
|
||||||
export declare function generateTime(): {
|
|
||||||
startDateTime: number;
|
|
||||||
endDateTime: number;
|
|
||||||
};
|
|
@ -1,66 +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/time/index.ts
|
|
||||||
var time_exports = {};
|
|
||||||
__export(time_exports, {
|
|
||||||
formateDuration: () => formateDuration,
|
|
||||||
generateTime: () => generateTime
|
|
||||||
});
|
|
||||||
module.exports = __toCommonJS(time_exports);
|
|
||||||
var import_dayjs = __toESM(require("dayjs"));
|
|
||||||
var formateDuration = (diff) => {
|
|
||||||
var days = Math.floor(diff / (24 * 3600 * 1e3));
|
|
||||||
var leave1 = diff % (24 * 3600 * 1e3);
|
|
||||||
var hours = Math.floor(leave1 / (3600 * 1e3));
|
|
||||||
var leave2 = leave1 % (3600 * 1e3);
|
|
||||||
var minutes = Math.floor(leave2 / (60 * 1e3));
|
|
||||||
var leave3 = leave2 % (60 * 1e3);
|
|
||||||
var seconds = Math.round(leave3 / 1e3);
|
|
||||||
var returnStr = seconds + "秒";
|
|
||||||
if (minutes > 0) {
|
|
||||||
returnStr = minutes + "分";
|
|
||||||
}
|
|
||||||
if (hours > 0) {
|
|
||||||
returnStr = hours + "小时";
|
|
||||||
}
|
|
||||||
if (days > 0) {
|
|
||||||
returnStr = days + "天";
|
|
||||||
}
|
|
||||||
return returnStr;
|
|
||||||
};
|
|
||||||
function generateTime() {
|
|
||||||
let endDateTime = (0, import_dayjs.default)().endOf("day").unix();
|
|
||||||
let startDateTime = (0, import_dayjs.default)().startOf("day").unix();
|
|
||||||
return { startDateTime, endDateTime };
|
|
||||||
}
|
|
||||||
// Annotate the CommonJS export names for ESM import in node:
|
|
||||||
0 && (module.exports = {
|
|
||||||
formateDuration,
|
|
||||||
generateTime
|
|
||||||
});
|
|
20
packages/func/lib/utils/index.d.ts
vendored
20
packages/func/lib/utils/index.d.ts
vendored
@ -1,20 +0,0 @@
|
|||||||
export { default as isChrome } from './isChrome';
|
|
||||||
export declare const matchS3Prefix: (str: string) => boolean;
|
|
||||||
/**
|
|
||||||
* 通过文件名获取文件类型
|
|
||||||
* @param fileName 文件名称
|
|
||||||
* @returns 文件类型
|
|
||||||
*/
|
|
||||||
export declare const getFileSuffix: (fileName: string) => string;
|
|
||||||
/**
|
|
||||||
* 通过类型获取文件名
|
|
||||||
* @param type 类型
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export declare const getImageSuffixByFileType: (type: string) => string;
|
|
||||||
export declare function getChromeVersion(): number | false;
|
|
||||||
export declare const nextTick: (func: (value: void) => void | PromiseLike<void>) => void;
|
|
||||||
export declare const loop: (items: string | any[], callback: (arg0: any) => any) => void;
|
|
||||||
export declare const addEventListener: (target: any, eventType: string, cb: any, option?: any) => {
|
|
||||||
remove: () => void;
|
|
||||||
};
|
|
@ -1,138 +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/utils/index.ts
|
|
||||||
var utils_exports = {};
|
|
||||||
__export(utils_exports, {
|
|
||||||
addEventListener: () => addEventListener,
|
|
||||||
getChromeVersion: () => getChromeVersion,
|
|
||||||
getFileSuffix: () => getFileSuffix,
|
|
||||||
getImageSuffixByFileType: () => getImageSuffixByFileType,
|
|
||||||
isChrome: () => import_isChrome.default,
|
|
||||||
loop: () => loop,
|
|
||||||
matchS3Prefix: () => matchS3Prefix,
|
|
||||||
nextTick: () => nextTick
|
|
||||||
});
|
|
||||||
module.exports = __toCommonJS(utils_exports);
|
|
||||||
var import_react_dom = __toESM(require("react-dom"));
|
|
||||||
var import_isChrome = __toESM(require("./isChrome"));
|
|
||||||
var matchS3Prefix = (str) => {
|
|
||||||
return /^v[0-9]_/.test(str);
|
|
||||||
};
|
|
||||||
var getFileSuffix = (fileName) => {
|
|
||||||
const splitArr = fileName.split(".");
|
|
||||||
return splitArr.length < 2 ? "" : splitArr[splitArr.length - 1];
|
|
||||||
};
|
|
||||||
var getImageSuffixByFileType = (type) => {
|
|
||||||
let imageSuffix = "";
|
|
||||||
switch (type) {
|
|
||||||
case "jpeg": {
|
|
||||||
imageSuffix = ".jpg";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "gif": {
|
|
||||||
imageSuffix = ".gif";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "png": {
|
|
||||||
imageSuffix = ".png";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "vnd.wap.wbmp": {
|
|
||||||
imageSuffix = ".wbmp";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "x-up-wpng": {
|
|
||||||
imageSuffix = ".wpng";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "nbmp": {
|
|
||||||
imageSuffix = ".nbmp";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return imageSuffix;
|
|
||||||
};
|
|
||||||
function getChromeVersion() {
|
|
||||||
const arr = navigator.userAgent.split(" ");
|
|
||||||
let chromeVersion = "";
|
|
||||||
for (let i = 0; i < arr.length; i++) {
|
|
||||||
if (/chrome/i.test(arr[i]))
|
|
||||||
chromeVersion = arr[i];
|
|
||||||
}
|
|
||||||
if (chromeVersion) {
|
|
||||||
return Number(chromeVersion.split("/")[1].split(".")[0]);
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var nextTick = (func) => {
|
|
||||||
if (queueMicrotask) {
|
|
||||||
queueMicrotask(func);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Promise.resolve().then(func);
|
|
||||||
};
|
|
||||||
var loop = (items, callback) => {
|
|
||||||
for (let i = 0; i < items.length; i++) {
|
|
||||||
const element = items[i];
|
|
||||||
let isBreak = callback(element);
|
|
||||||
if (isBreak) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (element["children"]) {
|
|
||||||
loop(element["children"], callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var addEventListener = (target, eventType, cb, option) => {
|
|
||||||
const callback = import_react_dom.default.unstable_batchedUpdates ? function run(e) {
|
|
||||||
import_react_dom.default.unstable_batchedUpdates(cb, e);
|
|
||||||
} : cb;
|
|
||||||
if (target.addEventListener) {
|
|
||||||
target.addEventListener(eventType, callback, option);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
remove: () => {
|
|
||||||
if (target.removeEventListener) {
|
|
||||||
target.removeEventListener(eventType, callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
// Annotate the CommonJS export names for ESM import in node:
|
|
||||||
0 && (module.exports = {
|
|
||||||
addEventListener,
|
|
||||||
getChromeVersion,
|
|
||||||
getFileSuffix,
|
|
||||||
getImageSuffixByFileType,
|
|
||||||
isChrome,
|
|
||||||
loop,
|
|
||||||
matchS3Prefix,
|
|
||||||
nextTick
|
|
||||||
});
|
|
3
packages/func/lib/utils/isChrome.d.ts
vendored
3
packages/func/lib/utils/isChrome.d.ts
vendored
@ -1,3 +0,0 @@
|
|||||||
export declare const isBrowser: boolean;
|
|
||||||
declare const isChrome: () => boolean;
|
|
||||||
export default isChrome;
|
|
@ -1,42 +0,0 @@
|
|||||||
var __defProp = Object.defineProperty;
|
|
||||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
||||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
||||||
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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
||||||
|
|
||||||
// src/utils/isChrome.ts
|
|
||||||
var isChrome_exports = {};
|
|
||||||
__export(isChrome_exports, {
|
|
||||||
default: () => isChrome_default,
|
|
||||||
isBrowser: () => isBrowser
|
|
||||||
});
|
|
||||||
module.exports = __toCommonJS(isChrome_exports);
|
|
||||||
var isBrowser = !!(typeof window !== "undefined" && window);
|
|
||||||
var isChrome = () => {
|
|
||||||
const winNav = isBrowser && window.navigator;
|
|
||||||
const vendorName = winNav && winNav.vendor;
|
|
||||||
const userAgent = winNav && winNav.userAgent;
|
|
||||||
const isChromium = isBrowser && typeof chrome !== "undefined";
|
|
||||||
const isOpera = isBrowser && typeof opr !== "undefined";
|
|
||||||
const isIEedge = userAgent && userAgent.indexOf("Edge") > -1;
|
|
||||||
const isIOSChrome = !!(userAgent && userAgent.match("CriOS"));
|
|
||||||
const isDesktopChrome = isChromium && vendorName === "Google Inc." && !isOpera && !isIEedge;
|
|
||||||
return isIOSChrome || isDesktopChrome;
|
|
||||||
};
|
|
||||||
var isChrome_default = isChrome;
|
|
||||||
// Annotate the CommonJS export names for ESM import in node:
|
|
||||||
0 && (module.exports = {
|
|
||||||
isBrowser
|
|
||||||
});
|
|
@ -13,10 +13,11 @@
|
|||||||
"lib/**/style/*",
|
"lib/**/style/*",
|
||||||
"*.less"
|
"*.less"
|
||||||
],
|
],
|
||||||
"main": "lib/index.tsx",
|
"main": "lib/index.js",
|
||||||
"module": "es/index.js",
|
"module": "es/index.js",
|
||||||
"typings": "es/index.d.ts",
|
"typings": "es/index.d.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
"./*": "./*",
|
||||||
"./package.json": "./package.json"
|
"./package.json": "./package.json"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
@ -32,15 +33,19 @@
|
|||||||
"registry": "http://10.0.0.77:4874"
|
"registry": "http://10.0.0.77:4874"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@zhst/request": "workspace:^",
|
||||||
"base-64": "^1.0.0",
|
"base-64": "^1.0.0",
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.10",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"lodash-es": "^4.17.21"
|
"lodash-es": "^4.17.21",
|
||||||
|
"uuid": "^9.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/base-64": "^1.0.2",
|
"@types/base-64": "^1.0.2",
|
||||||
"@types/file-saver": "^2.0.7",
|
"@types/file-saver": "^2.0.7",
|
||||||
"@types/lodash-es": "^4.17.12"
|
"@types/lodash-es": "^4.17.12",
|
||||||
|
"@types/uuid": "^9.0.7",
|
||||||
|
"@zhst/types": "workspace:^"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,8 @@ import Base64 from 'base-64'
|
|||||||
import JSZip from 'jszip';
|
import JSZip from 'jszip';
|
||||||
import FileSaver from 'file-saver';
|
import FileSaver from 'file-saver';
|
||||||
import { matchS3Prefix } from '../utils'
|
import { matchS3Prefix } from '../utils'
|
||||||
import { get } from 'lodash-es';
|
import { get, isString } from 'lodash-es';
|
||||||
|
import { Rect } from '@zhst/types'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -296,3 +297,49 @@ export const generateImg: (imgKey: string, host?: string) => string = (_imgKey,
|
|||||||
}
|
}
|
||||||
return imgUrl;
|
return imgUrl;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定字符串后面的部分
|
||||||
|
* @param imageKey v1_开头的字符串
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getImageKey = (imageKey: string, preFix?: string) => {
|
||||||
|
const splitIndex = preFix || 'v1_';
|
||||||
|
if (imageKey.startsWith(splitIndex)) {
|
||||||
|
return window.atob(imageKey.split(splitIndex)[1]).replace('_', '/');
|
||||||
|
} else {
|
||||||
|
return imageKey;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取图片
|
||||||
|
* @param img 图片的url链接
|
||||||
|
* @param odRect
|
||||||
|
* @returns file
|
||||||
|
*/
|
||||||
|
export const getFileByRect = async (img: string, odRect: Rect) => {
|
||||||
|
let image;
|
||||||
|
|
||||||
|
if (isString(img)) {
|
||||||
|
const url = generateImg(img);
|
||||||
|
image = await urlToImg(url);
|
||||||
|
} else {
|
||||||
|
image = img;
|
||||||
|
}
|
||||||
|
const commonCanvas = document.createElement('canvas');
|
||||||
|
commonCanvas.width = odRect.w * image.width;
|
||||||
|
commonCanvas.height = odRect.h * image.height;
|
||||||
|
commonCanvas.style.display = 'none';
|
||||||
|
document.body.appendChild(commonCanvas);
|
||||||
|
const commonCtx = commonCanvas.getContext('2d');
|
||||||
|
commonCtx?.translate(-odRect.x * image.width, -odRect.y * image.height);
|
||||||
|
commonCtx?.drawImage(image, 0, 0);
|
||||||
|
const base64 = commonCanvas.toDataURL('image/jpeg');
|
||||||
|
const blobData = dataURLToBlob(base64);
|
||||||
|
commonCanvas.parentNode?.removeChild(commonCanvas);
|
||||||
|
const file = new window.File([blobData], `${new Date().getTime()}`, {
|
||||||
|
type: 'image/jpeg',
|
||||||
|
});
|
||||||
|
return file;
|
||||||
|
};
|
||||||
|
@ -7,3 +7,5 @@ export * from './number'
|
|||||||
export * from './time'
|
export * from './time'
|
||||||
export * from './utils'
|
export * from './utils'
|
||||||
export * from './camera'
|
export * from './camera'
|
||||||
|
export * from './math'
|
||||||
|
export * from './upload'
|
||||||
|
448
packages/func/src/math/index.ts
Normal file
448
packages/func/src/math/index.ts
Normal file
@ -0,0 +1,448 @@
|
|||||||
|
import { cloneDeep, get, isNull, isNumber, isString } from 'lodash-es';
|
||||||
|
import { dataURLToBlob, generateImg, urlToImg } 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, maxW, maxH, type) => {
|
||||||
|
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 fileKey = 'v1_' + window.btoa('public_' + imgKey.split('public/')[1]);
|
||||||
|
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) => !isNull(get(v, 'subObjects[0].infoOnSource.bboxInFrame.bboxRatio')))
|
||||||
|
.map((v, index) => {
|
||||||
|
const rect = get(v, 'infoOnSource.bboxInFrame.bboxRatio');
|
||||||
|
const qualityScore = get(v, 'qualityScore');
|
||||||
|
const algorithmVersion = get(v, 'objectType');
|
||||||
|
const featrueData = get(v, 'feature', []).filter(
|
||||||
|
(v) => 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) => {
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
//获取图片
|
||||||
|
|
||||||
|
export const getFileByRect = async (img: any, odRect: Rect) => {
|
||||||
|
let image;
|
||||||
|
if (isString(img)) {
|
||||||
|
const url = generateImg(img);
|
||||||
|
console.log(url, '获取图片');
|
||||||
|
image = await urlToImg(url);
|
||||||
|
console.log(image, '获取的图片');
|
||||||
|
} else {
|
||||||
|
image = img;
|
||||||
|
}
|
||||||
|
const commonCanvas = document.createElement('canvas');
|
||||||
|
commonCanvas.width = odRect.w * image.width;
|
||||||
|
commonCanvas.height = odRect.h * image.height;
|
||||||
|
commonCanvas.style.display = 'none';
|
||||||
|
document.body.appendChild(commonCanvas);
|
||||||
|
const commonCtx = commonCanvas.getContext('2d');
|
||||||
|
commonCtx?.translate(-odRect.x * image.width, -odRect.y * image.height);
|
||||||
|
commonCtx?.drawImage(image, 0, 0);
|
||||||
|
const base64 = commonCanvas.toDataURL('image/jpeg');
|
||||||
|
const blobData = dataURLToBlob(base64);
|
||||||
|
commonCanvas?.parentNode?.removeChild(commonCanvas);
|
||||||
|
const file = new window.File([blobData], `${new Date().getTime()}`, {
|
||||||
|
type: 'image/jpeg',
|
||||||
|
});
|
||||||
|
return file;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get transforms base on the given object.
|
||||||
|
* @param {Object} obj - The target object.
|
||||||
|
* @returns {string} A string contains transform values.
|
||||||
|
*/
|
||||||
|
export function getTransforms({
|
||||||
|
rotate,
|
||||||
|
scaleX,
|
||||||
|
scaleY,
|
||||||
|
translateX,
|
||||||
|
translateY,
|
||||||
|
}: {
|
||||||
|
rotate?: number;
|
||||||
|
scaleX?: number;
|
||||||
|
scaleY?: number;
|
||||||
|
translateX?: number;
|
||||||
|
translateY?: number;
|
||||||
|
}) {
|
||||||
|
const values = [];
|
||||||
|
|
||||||
|
if (isNumber(translateX) && translateX !== 0) {
|
||||||
|
values.push(`translateX(${translateX}px)`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNumber(translateY) && translateY !== 0) {
|
||||||
|
values.push(`translateY(${translateY}px)`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate should come first before scale to match orientation transform
|
||||||
|
if (isNumber(rotate) && rotate !== 0) {
|
||||||
|
values.push(`rotate(${rotate}deg)`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNumber(scaleX) && scaleX !== 1) {
|
||||||
|
values.push(`scaleX(${scaleX})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNumber(scaleY) && scaleY !== 1) {
|
||||||
|
values.push(`scaleY(${scaleY})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const transform = values.length ? values.join(' ') : 'none';
|
||||||
|
|
||||||
|
return {
|
||||||
|
WebkitTransform: transform,
|
||||||
|
msTransform: transform,
|
||||||
|
transform,
|
||||||
|
};
|
||||||
|
}
|
@ -25,3 +25,14 @@ export const setNumberAccuracy = (originNumber: number, accuracy = 0, isCeil = t
|
|||||||
}
|
}
|
||||||
return returnData;
|
return returnData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取数字
|
||||||
|
* @param number 需要校验的数值
|
||||||
|
* @returns @number
|
||||||
|
*/
|
||||||
|
export const toRealNumber = (number: any) => {
|
||||||
|
if (isNaN(number) || number === Infinity) {
|
||||||
|
return 0;
|
||||||
|
} else return number;
|
||||||
|
};
|
||||||
|
@ -47,3 +47,14 @@ export function generateTime() {
|
|||||||
let startDateTime = dayjs().startOf('day').unix();
|
let startDateTime = dayjs().startOf('day').unix();
|
||||||
return { startDateTime, endDateTime };
|
return { startDateTime, endDateTime };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化时间为 00:00
|
||||||
|
* @param seconds 时间,单位秒
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function formatDurationTime(seconds: number) {
|
||||||
|
var minutes = Math.floor(seconds / 60) || 0;
|
||||||
|
var remainingSeconds = Math.floor(seconds % 60);
|
||||||
|
return (minutes < 10 ? `0${minutes}` : minutes) + ":" + (remainingSeconds < 10 ? "0" : "") + remainingSeconds;
|
||||||
|
}
|
||||||
|
58
packages/func/src/upload/index.ts
Normal file
58
packages/func/src/upload/index.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import dayjs from "dayjs";
|
||||||
|
import { getFileSuffix, getImageSuffixByFileType } from "../utils";
|
||||||
|
import base64 from "base-64";
|
||||||
|
import { v4 as uuidV4 } from 'uuid'
|
||||||
|
import { get } from "lodash-es";
|
||||||
|
import request from '@zhst/request'
|
||||||
|
|
||||||
|
//小文件上传走s3
|
||||||
|
const defaultBucket = 'public';
|
||||||
|
type uploadOption = {
|
||||||
|
bucket?: string;
|
||||||
|
dir?: string;
|
||||||
|
withSuFuffix?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const commonUpload = async (file: File, option: uploadOption = {}, type: string) => {
|
||||||
|
const { bucket = defaultBucket, dir = 'file', withSuFuffix = false } = option;
|
||||||
|
const prefix = `${dayjs().format('YYYYMMDD')}`;
|
||||||
|
const fileSuffix = withSuFuffix ? getFileSuffix(get(file, 'name')) : '';
|
||||||
|
const fileType = file['type'].split('/', 2);
|
||||||
|
let imageSuffix = '';
|
||||||
|
if (fileType['0'] === 'image') {
|
||||||
|
imageSuffix = getImageSuffixByFileType(fileType['1']);
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = `${prefix}/${dir ? `${dir}/` : ''}${uuidV4()}${!fileSuffix ? '' : `.${fileSuffix}`}`;
|
||||||
|
let imgKey = `${bucket}_${bucket}_${key}${imageSuffix}`; //后端约定 见https://docs.qq.com/doc/DUklodHNxUGl2U3NM》
|
||||||
|
if (type === 'upload') {
|
||||||
|
imgKey = `v1_${base64.encode(imgKey)}`;
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
reader.onload = async () => {
|
||||||
|
if (reader.result) {
|
||||||
|
await request({
|
||||||
|
method: 'PUT',
|
||||||
|
url: '/singer.FileServerService/PutObject',
|
||||||
|
data: {
|
||||||
|
version: 1,
|
||||||
|
bucket: defaultBucket,
|
||||||
|
objectName: `${bucket}_${key}${imageSuffix}`,
|
||||||
|
// fileData: reader.result,
|
||||||
|
putObjectOption: {
|
||||||
|
contentType: file.type,
|
||||||
|
},
|
||||||
|
fileDataBase64: reader.result?.split(';base64,')[1],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
resolve(imgKey);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const upload = async (file: File, option: uploadOption = {}) => {
|
||||||
|
return await commonUpload(file, option, 'upload');
|
||||||
|
};
|
@ -1,3 +1,4 @@
|
|||||||
|
import { isNumber } from 'lodash-es';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
|
|
||||||
export { default as isChrome } from './isChrome';
|
export { default as isChrome } from './isChrome';
|
||||||
@ -90,7 +91,7 @@ export const loop = (items: string | any[], callback: (arg0: any) => any) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addEventListener = (target: any, eventType: string, cb: any, option?: any) => {
|
export const addEventListenerWrapper = (target: any, eventType: string, cb: any, option?: any) => {
|
||||||
/* eslint camelcase: 2 */
|
/* eslint camelcase: 2 */
|
||||||
const callback = ReactDOM.unstable_batchedUpdates
|
const callback = ReactDOM.unstable_batchedUpdates
|
||||||
? function run(e: any) {
|
? function run(e: any) {
|
||||||
@ -109,3 +110,54 @@ export const addEventListener = (target: any, eventType: string, cb: any, option
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get transforms base on the given object.
|
||||||
|
* @param {Object} obj - The target object.
|
||||||
|
* @returns {string} A string contains transform values.
|
||||||
|
*/
|
||||||
|
export function getTransforms({
|
||||||
|
rotate,
|
||||||
|
scaleX,
|
||||||
|
scaleY,
|
||||||
|
translateX,
|
||||||
|
translateY,
|
||||||
|
}: {
|
||||||
|
rotate?: number;
|
||||||
|
scaleX?: number;
|
||||||
|
scaleY?: number;
|
||||||
|
translateX?: number;
|
||||||
|
translateY?: number;
|
||||||
|
}) {
|
||||||
|
const values = [];
|
||||||
|
|
||||||
|
if (isNumber(translateX) && translateX !== 0) {
|
||||||
|
values.push(`translateX(${translateX}px)`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNumber(translateY) && translateY !== 0) {
|
||||||
|
values.push(`translateY(${translateY}px)`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate should come first before scale to match orientation transform
|
||||||
|
if (isNumber(rotate) && rotate !== 0) {
|
||||||
|
values.push(`rotate(${rotate}deg)`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNumber(scaleX) && scaleX !== 1) {
|
||||||
|
values.push(`scaleX(${scaleX})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNumber(scaleY) && scaleY !== 1) {
|
||||||
|
values.push(`scaleY(${scaleY})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const transform = values.length ? values.join(' ') : 'none';
|
||||||
|
|
||||||
|
return {
|
||||||
|
WebkitTransform: transform,
|
||||||
|
msTransform: transform,
|
||||||
|
transform,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
"lib/**/style/*",
|
"lib/**/style/*",
|
||||||
"*.less"
|
"*.less"
|
||||||
],
|
],
|
||||||
"main": "lib/index.tsx",
|
"main": "lib/index.js",
|
||||||
"module": "es/index.js",
|
"module": "es/index.js",
|
||||||
"typings": "es/index.d.ts",
|
"typings": "es/index.d.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
@ -31,6 +31,9 @@
|
|||||||
"access": "public",
|
"access": "public",
|
||||||
"registry": "http://10.0.0.77:4874"
|
"registry": "http://10.0.0.77:4874"
|
||||||
},
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@zhst/types": "workspace:^"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@zhst/func": "workspace:^",
|
"@zhst/func": "workspace:^",
|
||||||
"ahooks": "^3.7.8",
|
"ahooks": "^3.7.8",
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
"lib/**/style/*",
|
"lib/**/style/*",
|
||||||
"*.less"
|
"*.less"
|
||||||
],
|
],
|
||||||
"main": "lib/index.tsx",
|
"main": "lib/index.js",
|
||||||
"module": "es/index.js",
|
"module": "es/index.js",
|
||||||
"typings": "es/index.d.ts",
|
"typings": "es/index.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
"lib/**/style/*",
|
"lib/**/style/*",
|
||||||
"*.less"
|
"*.less"
|
||||||
],
|
],
|
||||||
"main": "lib/index.tsx",
|
"main": "lib/index.js",
|
||||||
"module": "es/index.js",
|
"module": "es/index.js",
|
||||||
"typings": "es/index.d.ts",
|
"typings": "es/index.d.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
@ -32,13 +32,20 @@
|
|||||||
"access": "public",
|
"access": "public",
|
||||||
"registry": "http://10.0.0.77:4874"
|
"registry": "http://10.0.0.77:4874"
|
||||||
},
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@zhst/types": "workspace:^"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@turf/boolean-point-in-polygon": "^6.5.0",
|
"@turf/boolean-point-in-polygon": "^6.5.0",
|
||||||
"@turf/turf": "^6.5.0",
|
"@turf/turf": "^6.5.0",
|
||||||
|
"@types/downloadjs": "^1.4.6",
|
||||||
"@zhst/func": "workspace:^",
|
"@zhst/func": "workspace:^",
|
||||||
"@zhst/hooks": "workspace:^",
|
"@zhst/hooks": "workspace:^",
|
||||||
"antd": "^5.12.5",
|
"antd": "^5.12.5",
|
||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
|
"downloadjs": "^1.4.7",
|
||||||
|
"flv.js": "^1.6.2",
|
||||||
|
"rc-align": "^4.0.15",
|
||||||
"rc-util": "^5.38.1",
|
"rc-util": "^5.38.1",
|
||||||
"react": "^18.0.0",
|
"react": "^18.0.0",
|
||||||
"react-dom": "^18.0.0"
|
"react-dom": "^18.0.0"
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
.zhst-image__btn-group {
|
||||||
|
// display: flex;
|
||||||
|
width: 30px;
|
||||||
|
box-shadow: 0 2px 6px 0 rgb(0 0 0 / 40%);
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
display: flex;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: #000;
|
||||||
|
|
||||||
|
&>button {
|
||||||
|
padding: 0;
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #09f;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
color: #09f;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&>span {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--active {
|
||||||
|
&>button {
|
||||||
|
color: #09f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--circle {
|
||||||
|
background-color: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--circle &__item {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
import React, { MouseEvent } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { Button, Tooltip, TooltipProps } from 'antd';
|
||||||
|
import Icon from '../../../iconfont';
|
||||||
|
import './index.less';
|
||||||
|
|
||||||
|
const componentName = `zhst-image__btn-group`;
|
||||||
|
|
||||||
|
export interface BtnGroupProps {
|
||||||
|
className: string;
|
||||||
|
dataSource: Array<{ key: string; icon: string; title: string }>;
|
||||||
|
onClick: (v: string, e: MouseEvent<HTMLElement>) => void;
|
||||||
|
selectKey?: string;
|
||||||
|
circle?: boolean;
|
||||||
|
placement?: TooltipProps['placement'];
|
||||||
|
}
|
||||||
|
export const BtnGroup: React.FC<BtnGroupProps> = (props) => {
|
||||||
|
const { dataSource, onClick, className, circle, selectKey = '', placement = 'right' } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
componentName,
|
||||||
|
circle && `${componentName}--circle`,
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{dataSource.map(({ key, icon, title }) => {
|
||||||
|
const isSelect = key === selectKey;
|
||||||
|
return (
|
||||||
|
<Tooltip key={key} placement={placement} title={title}>
|
||||||
|
<div
|
||||||
|
key={key}
|
||||||
|
className={classNames(
|
||||||
|
`${componentName}__item`,
|
||||||
|
isSelect && `${componentName}__item--active`
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
onClick={(e) => {
|
||||||
|
onClick(key, e);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon size={18} icon={icon} />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
BtnGroup.displayName = 'BtnGroup';
|
||||||
|
|
||||||
|
export default BtnGroup;
|
@ -0,0 +1,21 @@
|
|||||||
|
.bigImageWrapper--v2__screenshot {
|
||||||
|
min-width: 90px;
|
||||||
|
background: rgb(0 0 0 / 50%);
|
||||||
|
border-radius: 0;
|
||||||
|
|
||||||
|
&>button {
|
||||||
|
width: 100%;
|
||||||
|
color: #fff !important;
|
||||||
|
font-family: 'Microsoft YaHei';
|
||||||
|
font-size: 12px !important;
|
||||||
|
border-radius: 0;
|
||||||
|
|
||||||
|
&>span {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #09f !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,106 @@
|
|||||||
|
import React from'react'
|
||||||
|
import { Button } from 'antd';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import type { AlgorithmVersion } from '@zhst/types'
|
||||||
|
import { IBigImageOpt } from '@zhst/types/BigImageModal'
|
||||||
|
import './index.less';
|
||||||
|
|
||||||
|
const componentName = 'bigImageWrapper--v2';
|
||||||
|
|
||||||
|
interface IScreenShotButton {
|
||||||
|
getCropInfo: () => void
|
||||||
|
setShowCrop: any
|
||||||
|
cropType: string
|
||||||
|
selectAlgorithmVersion: AlgorithmVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
const getScreenshotButtonRender = (arg: {
|
||||||
|
disableBtn: number[];
|
||||||
|
onBigImageActionClick: (type: number, item: any) => void;
|
||||||
|
}) => {
|
||||||
|
const { disableBtn = [], onBigImageActionClick } = arg;
|
||||||
|
return (param: IScreenShotButton) => {
|
||||||
|
const { getCropInfo, setShowCrop, cropType, selectAlgorithmVersion } = param;
|
||||||
|
let isAuto = cropType === 'AUTO';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames(`${componentName}__screenshot`)}
|
||||||
|
style={{
|
||||||
|
zIndex: 100,
|
||||||
|
position: 'absolute',
|
||||||
|
width: '86px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{!disableBtn.includes(IBigImageOpt['ADD_HISTORY_WITH_CROP']) && isAuto && (
|
||||||
|
<Button
|
||||||
|
type={'text'}
|
||||||
|
onClick={async (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
const image = await getCropInfo();
|
||||||
|
setShowCrop(false);
|
||||||
|
onBigImageActionClick(IBigImageOpt['ADD_HISTORY_WITH_CROP'], image);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
目标检索
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{!disableBtn.includes(IBigImageOpt['ADD_HISTORY_WITH_CROP_BODY']) && !isAuto && (
|
||||||
|
<Button
|
||||||
|
type={'text'}
|
||||||
|
onClick={async (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
const image = await getCropInfo();
|
||||||
|
setShowCrop(false);
|
||||||
|
onBigImageActionClick(IBigImageOpt['ADD_HISTORY_WITH_CROP_BODY'], image);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
搜形体
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{!disableBtn.includes(IBigImageOpt['ADD_HISTORY_WITH_CROP_VEHICLE']) && !isAuto && (
|
||||||
|
<Button
|
||||||
|
type={'text'}
|
||||||
|
onClick={async (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
const image = await getCropInfo();
|
||||||
|
setShowCrop(false);
|
||||||
|
onBigImageActionClick(IBigImageOpt['ADD_HISTORY_WITH_CROP_VEHICLE'], image);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
搜非机动车
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{!disableBtn.includes(IBigImageOpt['ADD_HISTORY_WITH_CROP_ARCHIVE']) &&
|
||||||
|
selectAlgorithmVersion !== 0 && (
|
||||||
|
<Button
|
||||||
|
type={'text'}
|
||||||
|
onClick={async (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
let image = await getCropInfo();
|
||||||
|
setShowCrop(false);
|
||||||
|
if (!image.rectList[0].algorithmVersion) {
|
||||||
|
image.rectList[0].algorithmVersion = 0;
|
||||||
|
image.extendRectList[0].algorithmVersion = 0;
|
||||||
|
}
|
||||||
|
onBigImageActionClick(IBigImageOpt['ADD_HISTORY_WITH_CROP_ARCHIVE'], image);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
档案检索
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
type={'text'}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
setShowCrop(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
退出框选
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getScreenshotButtonRender;
|
129
packages/meta/src/BigImagePreview/index.less
Normal file
129
packages/meta/src/BigImagePreview/index.less
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
.zhst-image__img-view {
|
||||||
|
position: relative;
|
||||||
|
width: calc(100%);
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
&__face-score {
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
bottom: 80px;
|
||||||
|
color: red;
|
||||||
|
font-family: 'Microsoft YaHei';
|
||||||
|
font-size: 19px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-opt {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 99;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-crop-opt {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 99;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-align {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-main {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 0;
|
||||||
|
|
||||||
|
&--cursor {
|
||||||
|
& canvas {
|
||||||
|
min-height: 320px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-screenshot {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-attach {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 11;
|
||||||
|
bottom: 0;
|
||||||
|
|
||||||
|
// left: 78px;
|
||||||
|
left: 0;
|
||||||
|
min-width: 120px;
|
||||||
|
height: 202px;
|
||||||
|
transition: all 200ms;
|
||||||
|
|
||||||
|
&--fixed {
|
||||||
|
}
|
||||||
|
|
||||||
|
&--zoomin {
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
&--fixed {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__tab {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
&-item {
|
||||||
|
display: flex;
|
||||||
|
width: 30px;
|
||||||
|
height: 24px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: #000;
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 12px;
|
||||||
|
opacity: 0.5;
|
||||||
|
transition: all 200ms;
|
||||||
|
|
||||||
|
&--select {
|
||||||
|
width: 48px;
|
||||||
|
height: 34px;
|
||||||
|
background: #09f;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__scale {
|
||||||
|
position: absolute;
|
||||||
|
top: 4px;
|
||||||
|
right: 4px;
|
||||||
|
display: flex;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: rgb(0 0 0 / 60%);
|
||||||
|
border-radius: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
line-height: 30px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__img {
|
||||||
|
height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
|
||||||
|
&--fixed {
|
||||||
|
width: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
62
packages/meta/src/BigImagePreview/index.md
Normal file
62
packages/meta/src/BigImagePreview/index.md
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
---
|
||||||
|
nav:
|
||||||
|
title: 元组件
|
||||||
|
order: 1
|
||||||
|
group:
|
||||||
|
title: 通用
|
||||||
|
order: 3
|
||||||
|
---
|
||||||
|
|
||||||
|
# BigImagePreview 大图预览组件
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import React, { useState, useRef } from 'react';
|
||||||
|
import { Button, Space } from 'antd'
|
||||||
|
import { BigImagePreview } from '@zhst/meta'
|
||||||
|
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
imageKey:"http://10.0.0.120:30003/file/singer-20240110/1/5/1744894622934503424.jpg",
|
||||||
|
odRect:{
|
||||||
|
"x":0.5445312,
|
||||||
|
"y":0.19166666,
|
||||||
|
"w":0.08671875,
|
||||||
|
"h":0.40138888
|
||||||
|
},
|
||||||
|
heigth: '500px',
|
||||||
|
attachImg: [
|
||||||
|
{
|
||||||
|
"url": "http://10.0.0.120:30003/file/singer-20240110/1/5/1744894622695428096.jpg","label": "形体"
|
||||||
|
},{
|
||||||
|
"url": "http://10.0.0.120:30003/file/singer-20240110/1/5/1744894588427964418.jpg",
|
||||||
|
"label": "人脸"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
score: 0.891417,
|
||||||
|
objects: [{"objectIndex":{"objectId":"1745329264976201728","solutionId":"0","deviceId":"0","fragmentId":"0"},"objectType":"OBJECT_TYPE_PEDESTRAIN","sourceObjectId":"0","level":0,"confidence":0.8910453,"pathInfo":null,"frameInfo":{"frameId":"0","frameTimestamp":"1704953898021","width":0,"height":0,"originWidth":0,"originHeight":0,"offsetTime":"0","skipNumber":"0"},"deviceInfo":null,"infoOnSource":{"bboxInSource":null,"bboxInFrame":{"bbox":null,"bboxRatio":{"x":0.69192713,"y":0.53585213,"w":0.031508446,"h":0.12733544},"extendBbox":null,"extendBoxRatio":null},"countInSource":0,"indexInSource":0},"qualityScore":0,"frameImage":null,"objectImage":null,"objectExtImage":null,"feature":[{"name":"feature-body","type":"FEATURE_TYPE_BYTE","featureId":"0","featureByte":"","featureBool":[],"featureUint8":[],"featureUint16":[],"featureUint32":[],"featureUint64":[],"featureInt8":[],"featureInt16":[],"featureInt32":[],"featureInt64":[],"featureFloat32":[],"featureString":[]},{"name":"property-body","type":"FEATURE_TYPE_FLOAT32","featureId":"0","featureByte":"","featureBool":[],"featureUint8":[],"featureUint16":[],"featureUint32":[],"featureUint64":[],"featureInt8":[],"featureInt16":[],"featureInt32":[],"featureInt64":[],"featureFloat32":[0.8251953,0.40527344,0.4567871,0.20178223,0.26220703,0.5083008,0.36499023,0.045196533,0.92822266,0.08300781,0.9663086,0.71533203,0.112976074,0.3935547,0.25048828,0.11694336,0.5317383,0.26293945,0.13134766,0.11657715,0.4868164,0.3647461,0.06903076,0.234375,0.84472656,0.07684326,0.08227539,0.035827637,0.11315918,0.0637207,0.1850586,0.057495117,0.9013672,0.15673828,0.14099121,0.040618896,0.08270264,0.076538086,0.828125,0.055419922,0.038391113,0.03137207,0.07574463,0.08105469,0.05340576,0.023330688,0.25561523,0.05090332,0.17480469,0.73779297,0.49169922,0.63500977,0.033691406],"featureString":[]}],"subObjects":[]},{"objectIndex":{"objectId":"1745329264976201729","solutionId":"0","deviceId":"0","fragmentId":"0"},"objectType":"OBJECT_TYPE_PEDESTRAIN","sourceObjectId":"0","level":0,"confidence":0.74931294,"pathInfo":null,"frameInfo":{"frameId":"0","frameTimestamp":"1704953898021","width":0,"height":0,"originWidth":0,"originHeight":0,"offsetTime":"0","skipNumber":"0"},"deviceInfo":null,"infoOnSource":{"bboxInSource":null,"bboxInFrame":{"bbox":null,"bboxRatio":{"x":0.73869747,"y":0.5493781,"w":0.025924563,"h":0.11845186},"extendBbox":null,"extendBoxRatio":null},"countInSource":0,"indexInSource":0},"qualityScore":0,"frameImage":null,"objectImage":null,"objectExtImage":null,"feature":[{"name":"feature-body","type":"FEATURE_TYPE_BYTE","featureId":"0","featureByte":"","featureBool":[],"featureUint8":[],"featureUint16":[],"featureUint32":[],"featureUint64":[],"featureInt8":[],"featureInt16":[],"featureInt32":[],"featureInt64":[],"featureFloat32":[],"featureString":[]},{"name":"property-body","type":"FEATURE_TYPE_FLOAT32","featureId":"0","featureByte":"","featureBool":[],"featureUint8":[],"featureUint16":[],"featureUint32":[],"featureUint64":[],"featureInt8":[],"featureInt16":[],"featureInt32":[],"featureInt64":[],"featureFloat32":[0.41308594,0.33789062,0.5917969,0.17590332,0.7392578,0.3046875,0.5053711,0.017181396,0.94677734,0.19189453,0.8696289,0.21728516,0.14611816,0.27514648,0.5161133,0.49414062,0.77978516,0.25952148,0.26586914,0.07751465,0.15344238,0.2680664,0.82958984,0.13134766,0.41992188,0.118774414,0.04046631,0.13342285,0.16113281,0.16186523,0.07922363,0.044525146,0.9760742,0.19250488,0.22131348,0.044921875,0.046539307,0.040161133,0.9453125,0.04751587,0.1361084,0.013069153,0.049316406,0.0385437,0.06903076,0.056762695,0.047790527,0.09057617,0.58691406,0.2607422,0.6953125,0.4946289,0.1303711],"featureString":[]}],"subObjects":[]}]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const imgRef = useRef(null)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Space size={[8, 16]} direction="vertical">
|
||||||
|
<BigImagePreview {...props} ref={imgRef} />
|
||||||
|
<Space>
|
||||||
|
<Button type="primary" onClick={() => imgRef.current?.setShowCrop(true)}>编辑</Button>
|
||||||
|
<Button onClick={() => imgRef.current?.setShowCrop(false)}>取消</Button>
|
||||||
|
</Space>
|
||||||
|
</Space>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| 参数名 | 参数类型 | 参数说明 |
|
||||||
|
| ------ | -------- | ---- |
|
||||||
|
| imageKey | string(必填) | 当前大图链接 |
|
||||||
|
| odRect | { x: number; y: number; w: number; h: number } | 圈选矩形 |
|
||||||
|
|height|string(选填)|高度|
|
||||||
|
|width|string(选填)|宽度|
|
||||||
|
|score|string(选填)|相似度|
|
||||||
|
|attachImg|{ url: string; label: string; }[](选填)|缩略图|
|
||||||
|
|objects | IOdRectOrigin[] | 编辑状态参数 |
|
540
packages/meta/src/BigImagePreview/index.tsx
Normal file
540
packages/meta/src/BigImagePreview/index.tsx
Normal file
@ -0,0 +1,540 @@
|
|||||||
|
import React, { useEffect, ReactElement, useState, useCallback, useRef, useImperativeHandle } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { useLatest } from '@zhst/hooks';
|
||||||
|
import {
|
||||||
|
get,
|
||||||
|
pick,
|
||||||
|
isNull,
|
||||||
|
generateImg,
|
||||||
|
dataURLToBlob,
|
||||||
|
getOdRect,
|
||||||
|
getExtendRect,
|
||||||
|
getTransformRect,
|
||||||
|
getRotateImg,
|
||||||
|
getTransforms,
|
||||||
|
addEventListenerWrapper,
|
||||||
|
upload,
|
||||||
|
getFileByRect
|
||||||
|
} from '@zhst/func';
|
||||||
|
import Align from 'rc-align';
|
||||||
|
import { Button } from 'antd';
|
||||||
|
import type { Rect, IScreenshotButtonProp, ODRECT, AlignType, ViewOption, IOdRectOrigin } from '@zhst/types'
|
||||||
|
import Icon from '../iconfont';
|
||||||
|
import {
|
||||||
|
Cropper,
|
||||||
|
Viewer,
|
||||||
|
EVENT_VIEWER_TRANSFORM_CHANGE,
|
||||||
|
EVENT_VIEWER_READY,
|
||||||
|
EVENT_CROP_START,
|
||||||
|
EVENT_CROP_END,
|
||||||
|
} from '../ImageEditor';
|
||||||
|
import BtnGroup from './components/BtnGroup';
|
||||||
|
import './index.less'
|
||||||
|
import getScreenshotButtonRender from './components/ScreenhotButtons';
|
||||||
|
|
||||||
|
const componentName = `zhst-image__img-view`;
|
||||||
|
|
||||||
|
export const CROP_TYPE = {
|
||||||
|
CUSTOM: 'CSUTOM',
|
||||||
|
AUTO: 'AUTO',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const defaultAlignOption = {
|
||||||
|
points: ['bl', 'br'],
|
||||||
|
offset: [6, 0],
|
||||||
|
overflow: {
|
||||||
|
adjustX: true,
|
||||||
|
adjustY: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface ImgViewProps extends React.HTMLAttributes<HTMLElement> {
|
||||||
|
imageKey: string; //不在监听url变化 更新走销毁
|
||||||
|
odRect: ODRECT;
|
||||||
|
attachImg?: Array<{ label: string; url: string }>; // 缩略图列表
|
||||||
|
showAttachImgLabel: boolean; // 是否显示缩略图
|
||||||
|
showOpt: boolean; // 是否显示操作面板
|
||||||
|
width?: string | number;
|
||||||
|
height?: string | number;
|
||||||
|
/* 截图渲染 */
|
||||||
|
screenshotButtonAlign: AlignType;
|
||||||
|
screenshotButtonRender: (screenshotButtonProp: IScreenshotButtonProp) => ReactElement;
|
||||||
|
hideLeftTopBtn?: boolean;
|
||||||
|
score?: number;
|
||||||
|
viewOption?: ViewOption;
|
||||||
|
objects: IOdRectOrigin[]
|
||||||
|
}
|
||||||
|
export interface ImgViewRef {
|
||||||
|
/* 图片实例 */
|
||||||
|
imgInsRef: React.MutableRefObject<any>;
|
||||||
|
/* 切换编辑模式 */
|
||||||
|
setShowCrop: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cropBtnDataSource = [
|
||||||
|
{
|
||||||
|
key: 'close',
|
||||||
|
icon: 'icon-danchuangguanbi',
|
||||||
|
title: '退出',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'autoCrop',
|
||||||
|
icon: 'icon-zidong',
|
||||||
|
title: '智能框选',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'customCrop',
|
||||||
|
icon: 'icon-shoudong',
|
||||||
|
title: '手动框选',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const operateBtnDataSource = [
|
||||||
|
{
|
||||||
|
key: 'zoomOut',
|
||||||
|
icon: 'icon-fangda',
|
||||||
|
title: '放大',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'zoomIn',
|
||||||
|
icon: 'icon-suoxiao',
|
||||||
|
title: '缩小',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'reset',
|
||||||
|
icon: 'icon-zhongzhi3',
|
||||||
|
title: '重置图片',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const ImgView = React.forwardRef<ImgViewRef, ImgViewProps>((props, ref) => {
|
||||||
|
const {
|
||||||
|
imageKey,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
odRect,
|
||||||
|
score = 0,
|
||||||
|
attachImg = [],
|
||||||
|
objects = [],
|
||||||
|
showOpt = false,
|
||||||
|
showAttachImgLabel = true,
|
||||||
|
screenshotButtonAlign = defaultAlignOption,
|
||||||
|
screenshotButtonRender = getScreenshotButtonRender({
|
||||||
|
onBigImageActionClick: () => {},
|
||||||
|
disableBtn: [],
|
||||||
|
}),
|
||||||
|
hideLeftTopBtn = true,
|
||||||
|
viewOption = {}
|
||||||
|
} = props;
|
||||||
|
const imgContainerRef = React.useRef(null);
|
||||||
|
const [isReady, setIsReady] = useState(false);
|
||||||
|
|
||||||
|
console.log('props', props)
|
||||||
|
|
||||||
|
const init = useCallback(($container: null) => {
|
||||||
|
imgContainerRef.current = $container;
|
||||||
|
setIsReady(true);
|
||||||
|
}, []);
|
||||||
|
// ============================= viewer =========================
|
||||||
|
const imgInsRef = useRef<any>(null);
|
||||||
|
const [isImgReady, setIsImgReady] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isReady) return;
|
||||||
|
const handleReady = addEventListenerWrapper(imgContainerRef.current, EVENT_VIEWER_READY, () => {
|
||||||
|
setIsImgReady(true);
|
||||||
|
});
|
||||||
|
const handleTransformChange = addEventListenerWrapper(
|
||||||
|
imgContainerRef.current,
|
||||||
|
EVENT_VIEWER_TRANSFORM_CHANGE,
|
||||||
|
() => {
|
||||||
|
}
|
||||||
|
);
|
||||||
|
imgInsRef.current = new Viewer(imgContainerRef.current, {
|
||||||
|
...viewOption,
|
||||||
|
fitScaleAsMinScale: true,
|
||||||
|
image: generateImg(imageKey),
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
handleReady?.remove();
|
||||||
|
handleTransformChange?.remove();
|
||||||
|
imgInsRef?.current?.destroy?.();
|
||||||
|
imgInsRef.current = null;
|
||||||
|
};
|
||||||
|
}, [isReady, imageKey]);
|
||||||
|
|
||||||
|
// ============================= viewer操作按钮 =========================
|
||||||
|
const handleOptClick = (v: string) => {
|
||||||
|
switch (v) {
|
||||||
|
case 'zoomOut':
|
||||||
|
imgInsRef?.current?.scaleTo?.(0.1);
|
||||||
|
break;
|
||||||
|
case 'zoomIn':
|
||||||
|
imgInsRef?.current?.scaleTo?.(-0.1);
|
||||||
|
break;
|
||||||
|
case 'reset':
|
||||||
|
imgInsRef?.current?.reset?.(-0.1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================= cropper =========================
|
||||||
|
// 手动截图相关参数
|
||||||
|
const cropInsRef = useRef(null);
|
||||||
|
const [showCrop, setShowCrop] = useState(showOpt);
|
||||||
|
const [cropType, setCropType] = useState(CROP_TYPE['AUTO']);
|
||||||
|
|
||||||
|
// 自动截图相关参数
|
||||||
|
const [odList, setOdList] = useState([]);
|
||||||
|
const [extendOdList, setExtendOdList] = useState([]);
|
||||||
|
const [selectRectId, setSelectRectId] = useState(null);
|
||||||
|
|
||||||
|
// 定位按钮相关参数
|
||||||
|
const aliginContainerRef = useRef(null);
|
||||||
|
const alignRef = useRef(null);
|
||||||
|
const [cropRect, setCropRect] = useState<Rect | null>(null);
|
||||||
|
|
||||||
|
// 选中的版本号
|
||||||
|
const [selectAlgorithmVersion, setSelectAlgorithmVersion] = useState(null);
|
||||||
|
const handlerCropStartRef = useRef(null);
|
||||||
|
const handlerCropEndRef = useRef(null);
|
||||||
|
const handleShapeSelectRef = useRef(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
initData(objects)
|
||||||
|
return () => {
|
||||||
|
imgInsRef.current?.clearShape?.();
|
||||||
|
handlerCropStartRef.current?.remove();
|
||||||
|
handlerCropEndRef.current?.remove();
|
||||||
|
handleShapeSelectRef.current?.remove();
|
||||||
|
cropInsRef?.current?.destroy?.();
|
||||||
|
cropInsRef.current = null;
|
||||||
|
};
|
||||||
|
}, [isImgReady, showCrop, cropType]);
|
||||||
|
|
||||||
|
const initData = (_objects: IOdRectOrigin[]) => {
|
||||||
|
const imgIns = imgInsRef.current;
|
||||||
|
//清理crop
|
||||||
|
setCropRect(null);
|
||||||
|
if (!isImgReady) return;
|
||||||
|
if (!showCrop) {
|
||||||
|
imgIns?.addShape?.({
|
||||||
|
x: get(odRect, 'x', 0),
|
||||||
|
y: get(odRect, 'y', 0),
|
||||||
|
w: get(odRect, 'w', 0),
|
||||||
|
h: get(odRect, 'h', 0),
|
||||||
|
selectAble: false,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cropType === CROP_TYPE['AUTO']) {
|
||||||
|
const handleGetOD = (odList: any) => {
|
||||||
|
const imgSize = imgIns.getImgSize();
|
||||||
|
const shapeList = odList.map((rect: { [x: string]: any; algorithmVersion: any; }) => ({
|
||||||
|
...rect,
|
||||||
|
selectAble: true,
|
||||||
|
id: rect['id'],
|
||||||
|
algorithmVersion: rect.algorithmVersion,
|
||||||
|
}));
|
||||||
|
imgIns.replaceShape(shapeList);
|
||||||
|
//顺便吧扩展框拿到
|
||||||
|
const extendRect = shapeList.map((rect: { algorithmVersion: string; }) => {
|
||||||
|
const extendRect = getExtendRect(rect, imgSize.w, imgSize.h, rect.algorithmVersion);
|
||||||
|
return { ...rect, ...extendRect };
|
||||||
|
});
|
||||||
|
setExtendOdList(extendRect);
|
||||||
|
imgIns.replaceShape(shapeList);
|
||||||
|
handleShapeSelectRef.current = addEventListenerWrapper(imgContainerRef.current, 'shape-select', (e) => {
|
||||||
|
const id = e.detail;
|
||||||
|
setSelectRectId(id);
|
||||||
|
const selectShape = shapeList.find((v) => v['id'] === id);
|
||||||
|
if (selectShape) {
|
||||||
|
setSelectAlgorithmVersion(selectShape['algorithmVersion']);
|
||||||
|
//换算成屏幕坐标
|
||||||
|
const axisRect = imgIns.imgRectAxisToCanvasAxisRect(selectShape);
|
||||||
|
const rect = {
|
||||||
|
x: axisRect.x2 > axisRect.x ? axisRect.x : axisRect.x2,
|
||||||
|
y: axisRect.y2 > axisRect.y ? axisRect.y : axisRect.y2,
|
||||||
|
w: Math.abs(axisRect.x2 - axisRect.x),
|
||||||
|
h: Math.abs(axisRect.y2 - axisRect.y),
|
||||||
|
};
|
||||||
|
setCropRect(rect);
|
||||||
|
} else {
|
||||||
|
// @ts-ignore
|
||||||
|
setCropRect(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const rect = getOdRect({ objects })
|
||||||
|
setOdList(rect);
|
||||||
|
handleGetOD(rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cropType === CROP_TYPE['CUSTOM']) {
|
||||||
|
// 手动框选状态预先清除imgIns
|
||||||
|
imgIns?.clearShape?.();
|
||||||
|
handlerCropStartRef.current = addEventListenerWrapper(imgContainerRef.current, EVENT_CROP_START, (event) => {
|
||||||
|
setSelectAlgorithmVersion(null);
|
||||||
|
setCropRect(null);
|
||||||
|
});
|
||||||
|
handlerCropEndRef.current = addEventListenerWrapper(imgContainerRef.current, EVENT_CROP_END, (event) => {
|
||||||
|
const data = event.detail;
|
||||||
|
setSelectAlgorithmVersion(null);
|
||||||
|
setCropRect({
|
||||||
|
x: data.left,
|
||||||
|
y: data.top,
|
||||||
|
w: data.width,
|
||||||
|
h: data.height,
|
||||||
|
});
|
||||||
|
alignRef?.current?.forceAlign?.();
|
||||||
|
});
|
||||||
|
cropInsRef.current = new Cropper(imgContainerRef.current, {
|
||||||
|
showMask: true,
|
||||||
|
viewer: imgIns,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取框选的截图框信息
|
||||||
|
const latestCropType = useLatest(cropType);
|
||||||
|
const latestImgKey = useLatest(imageKey);
|
||||||
|
const latestCropRect = useLatest(cropRect);
|
||||||
|
const getCropInfo = async () => {
|
||||||
|
const cropType = latestCropType.current;
|
||||||
|
const cropRect = latestCropRect.current;
|
||||||
|
const imgIns = imgInsRef.current;
|
||||||
|
const transform = imgIns.targetTransform;
|
||||||
|
let newImgKey = latestImgKey.current;
|
||||||
|
let rectList = [];
|
||||||
|
let extendRectList = [];
|
||||||
|
let selectIndex = 0;
|
||||||
|
switch (cropType) {
|
||||||
|
case CROP_TYPE['AUTO']:
|
||||||
|
const shapes = imgIns.getSelectShape();
|
||||||
|
const shapeIds = shapes.map((v) => v['id']);
|
||||||
|
rectList = odList
|
||||||
|
.filter((v) => shapeIds.includes(v['id']))
|
||||||
|
.map((item: any) => {
|
||||||
|
if (
|
||||||
|
item.algorithmVersion === 'OBJECT_TYPE_FACE' ||
|
||||||
|
item.objectType === 'OBJECT_TYPE_FACE'
|
||||||
|
) {
|
||||||
|
if (!isNull(item.extendBox)) {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
w: get(item, 'extendBox.w'),
|
||||||
|
h: get(item, 'extendBox.h'),
|
||||||
|
x: get(item, 'extendBox.x'),
|
||||||
|
y: get(item, 'extendBox.y'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
extendRectList = extendOdList
|
||||||
|
.filter((v) => shapeIds.includes(v['id']))
|
||||||
|
.map((v) => pick(v, ['x', 'y', 'w', 'h', 'algorithmVersion', 'id']));
|
||||||
|
selectIndex = rectList.findIndex((v) => v['id'] === selectRectId);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//获取旋转过的坐标
|
||||||
|
const newRect = getTransformRect(imgIns.image, transform, cropRect);
|
||||||
|
//判断是不是旋转过
|
||||||
|
if (get(transform, 'rotate', 0) % 360 != 0) {
|
||||||
|
const data = getRotateImg(imgIns.image, get(transform, 'rotate', 0));
|
||||||
|
//在画布上画旋转后的图片
|
||||||
|
newImgKey = await upload(data);
|
||||||
|
}
|
||||||
|
rectList.push(newRect);
|
||||||
|
extendRectList.push(newRect);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//扩展框获取imgkey
|
||||||
|
await Promise.all(
|
||||||
|
extendRectList.map(async (rect, index) => {
|
||||||
|
const file = await getFileByRect(imgIns.image, rect);
|
||||||
|
const imgKey = await upload(file);
|
||||||
|
extendRectList[index] = { ...rect, imgKey };
|
||||||
|
})
|
||||||
|
);
|
||||||
|
//人脸图获取矫正图
|
||||||
|
await Promise.all(
|
||||||
|
rectList.map(async (rect, index) => {
|
||||||
|
const faceCorrectImage = rect['faceCorrectImage'];
|
||||||
|
let faceCorrectImageKey;
|
||||||
|
if (faceCorrectImage) {
|
||||||
|
const base64 = `data:image/jpg;base64,${faceCorrectImage}`;
|
||||||
|
const blobData = dataURLToBlob(base64);
|
||||||
|
const file = new window.File([blobData], `${new Date().getTime()}`);
|
||||||
|
faceCorrectImageKey = await upload(file);
|
||||||
|
}
|
||||||
|
const newRect = {
|
||||||
|
...rect,
|
||||||
|
...(faceCorrectImageKey ? { faceCorrectImageKey } : {}),
|
||||||
|
};
|
||||||
|
delete newRect['faceCorrectImage'];
|
||||||
|
rectList[index] = newRect;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return { rectList, extendRectList, selectIndex, imgKey: newImgKey };
|
||||||
|
};
|
||||||
|
|
||||||
|
// 操作界面判断
|
||||||
|
const handleCropBtnClick = (v: string) => {
|
||||||
|
switch (v) {
|
||||||
|
case 'close':
|
||||||
|
setShowCrop(false);
|
||||||
|
break;
|
||||||
|
case 'autoCrop':
|
||||||
|
setCropType(CROP_TYPE['AUTO']);
|
||||||
|
break;
|
||||||
|
case 'customCrop':
|
||||||
|
setCropType(CROP_TYPE['CUSTOM']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================= attact img =========================
|
||||||
|
const showAttachImg = attachImg.length !== 0;
|
||||||
|
const [selectAttachImgIndex, setSelectAttachImgIndex] = useState(0);
|
||||||
|
const [isZoomin, setIsZoomin] = useState(false);
|
||||||
|
|
||||||
|
// ============================== Ref ===============================
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
imgInsRef,
|
||||||
|
setShowCrop,
|
||||||
|
initData,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classNames(`${componentName}`)} style={{ height, width }}>
|
||||||
|
{/*场景图大图 */}
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
`${componentName}-main`,
|
||||||
|
cropType === CROP_TYPE['AUTO'] && `${componentName}-main--cursor`
|
||||||
|
)}
|
||||||
|
ref={init}
|
||||||
|
/>
|
||||||
|
{/* 图片操作 */}
|
||||||
|
{!hideLeftTopBtn && (
|
||||||
|
<BtnGroup
|
||||||
|
className={classNames(`${componentName}-opt`)}
|
||||||
|
dataSource={operateBtnDataSource}
|
||||||
|
onClick={handleOptClick}
|
||||||
|
placement="left"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{showCrop && (
|
||||||
|
<BtnGroup
|
||||||
|
circle
|
||||||
|
className={classNames(`${componentName}-crop-opt`)}
|
||||||
|
dataSource={cropBtnDataSource}
|
||||||
|
onClick={handleCropBtnClick}
|
||||||
|
selectKey={cropType === CROP_TYPE['AUTO'] ? 'autoCrop' : 'customCrop'}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{showCrop && cropRect && screenshotButtonRender && (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
ref={aliginContainerRef}
|
||||||
|
className={classNames(`${componentName}-align`)}
|
||||||
|
style={Object.assign(
|
||||||
|
{
|
||||||
|
width: cropRect.w,
|
||||||
|
height: cropRect.h,
|
||||||
|
},
|
||||||
|
getTransforms({
|
||||||
|
translateX: cropRect.x,
|
||||||
|
translateY: cropRect.y,
|
||||||
|
})
|
||||||
|
)}
|
||||||
|
></div>
|
||||||
|
<Align
|
||||||
|
ref={alignRef}
|
||||||
|
monitorWindowResize
|
||||||
|
align={screenshotButtonAlign}
|
||||||
|
target={function () {
|
||||||
|
return aliginContainerRef.current;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{screenshotButtonRender({
|
||||||
|
model: 'IMAGE',
|
||||||
|
getCropInfo,
|
||||||
|
setShowCrop,
|
||||||
|
cropType,
|
||||||
|
selectAlgorithmVersion,
|
||||||
|
})}
|
||||||
|
</Align>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{/* 场景图小图 */}
|
||||||
|
{showAttachImg && !showCrop && (
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
`${componentName}-attach`,
|
||||||
|
isZoomin && `${componentName}-attach--zoomin`,
|
||||||
|
`${componentName}-attach--fixed`,
|
||||||
|
isZoomin && `${componentName}-attach--zoomin--fixed`
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className={classNames(`${componentName}-attach__tab`)}>
|
||||||
|
{showAttachImgLabel
|
||||||
|
? attachImg.map(({ label, url }, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className={classNames(
|
||||||
|
`${componentName}-attach__tab-item`,
|
||||||
|
selectAttachImgIndex === index && `${componentName}-attach__tab-item--select`
|
||||||
|
)}
|
||||||
|
onMouseEnter={() => {
|
||||||
|
setSelectAttachImgIndex(index);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
: null}
|
||||||
|
</div>
|
||||||
|
<div className={classNames(`${componentName}-attach__scale`)}>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
//绝对定位下onClick事件失效采用onMouseDown
|
||||||
|
onMouseDown={(e) => {
|
||||||
|
//如果是左键执行
|
||||||
|
if (e.button == 0) {
|
||||||
|
setIsZoomin((pre) => !pre);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
color: '#fff',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
styles={{ display: 'flex' }}
|
||||||
|
icon={isZoomin ? 'icon-cancle_fullscreen' : 'icon-fullscreen'}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<img
|
||||||
|
draggable="false"
|
||||||
|
className={classNames(
|
||||||
|
`${componentName}-attach__img`,
|
||||||
|
`${componentName}-attach__img--fixed`
|
||||||
|
)}
|
||||||
|
src={get(attachImg, `${selectAttachImgIndex}.url`, '')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div
|
||||||
|
style={{ bottom: 20 }}
|
||||||
|
className={classNames(`${componentName}__face-score`)}
|
||||||
|
>{`人脸质量分:${(score as number).toFixed(2)}`}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
ImgView.displayName = 'ImgView';
|
||||||
|
|
||||||
|
export default ImgView;
|
@ -1,6 +1,6 @@
|
|||||||
//@ts-nocheck
|
//@ts-nocheck
|
||||||
import { addClass, removeClass } from 'rc-util/lib/Dom/class';
|
import { addClass, removeClass } from 'rc-util/lib/Dom/class';
|
||||||
import { addEventlistener, isNumber, get } from '@zhst/func';
|
import { addEventListenerWrapper, isNumber, get } from '@zhst/func';
|
||||||
import warn from 'rc-util/lib/warn';
|
import warn from 'rc-util/lib/warn';
|
||||||
import { getData, getPointer, getOffset, dispatchEvent } from '../utils';
|
import { getData, getPointer, getOffset, dispatchEvent } from '../utils';
|
||||||
import {
|
import {
|
||||||
@ -36,13 +36,13 @@ export default {
|
|||||||
bind() {
|
bind() {
|
||||||
const { container, element, eventHandleList = [], option } = this;
|
const { container, element, eventHandleList = [], option } = this;
|
||||||
|
|
||||||
const handleCropStart = addEventlistener(
|
const handleCropStart = addEventListenerWrapper(
|
||||||
container,
|
container,
|
||||||
EVENT_POINTER_DOWN,
|
EVENT_POINTER_DOWN,
|
||||||
this.onCropStart.bind(this)
|
this.onCropStart.bind(this)
|
||||||
);
|
);
|
||||||
eventHandleList.push(handleCropStart);
|
eventHandleList.push(handleCropStart);
|
||||||
const handleCropMove = addEventlistener(
|
const handleCropMove = addEventListenerWrapper(
|
||||||
element.ownerDocument,
|
element.ownerDocument,
|
||||||
EVENT_POINTER_MOVE,
|
EVENT_POINTER_MOVE,
|
||||||
this.onCropMove.bind(this)
|
this.onCropMove.bind(this)
|
||||||
@ -51,7 +51,7 @@ export default {
|
|||||||
EVENT_POINTER_UP.trim()
|
EVENT_POINTER_UP.trim()
|
||||||
.split(REGEXP_SPACES)
|
.split(REGEXP_SPACES)
|
||||||
.forEach((eventName) => {
|
.forEach((eventName) => {
|
||||||
const handleCropEnd = addEventlistener(
|
const handleCropEnd = addEventListenerWrapper(
|
||||||
element.ownerDocument,
|
element.ownerDocument,
|
||||||
eventName,
|
eventName,
|
||||||
this.onCropEnd.bind(this)
|
this.onCropEnd.bind(this)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//@ts-nocheck
|
//@ts-nocheck
|
||||||
import {addEventlistener} from '@zhst/func';
|
import {addEventListenerWrapper} from '@zhst/func';
|
||||||
import { EVENT_WHEEL } from './constants';
|
import { EVENT_WHEEL } from './constants';
|
||||||
import { EVENT_VIEWER_TRANSFORM_CHANGE } from '../viewer/constants';
|
import { EVENT_VIEWER_TRANSFORM_CHANGE } from '../viewer/constants';
|
||||||
|
|
||||||
@ -10,12 +10,12 @@ export default {
|
|||||||
if (this.options.viewer) {
|
if (this.options.viewer) {
|
||||||
const viewer = this.options.viewer;
|
const viewer = this.options.viewer;
|
||||||
//添加缩放事件
|
//添加缩放事件
|
||||||
const handleWhele = addEventlistener(container, EVENT_WHEEL, this.onWheel.bind(this));
|
const handleWhele = addEventListenerWrapper(container, EVENT_WHEEL, this.onWheel.bind(this));
|
||||||
eventHandleList.push(handleWhele);
|
eventHandleList.push(handleWhele);
|
||||||
//添加事件监听 获取limit crop box & 渲染canvas
|
//添加事件监听 获取limit crop box & 渲染canvas
|
||||||
this.onTransformChange(viewer);
|
this.onTransformChange(viewer);
|
||||||
this.limited = true;
|
this.limited = true;
|
||||||
const handleTransformChange = addEventlistener(
|
const handleTransformChange = addEventListenerWrapper(
|
||||||
viewer.element,
|
viewer.element,
|
||||||
EVENT_VIEWER_TRANSFORM_CHANGE,
|
EVENT_VIEWER_TRANSFORM_CHANGE,
|
||||||
(event) => {
|
(event) => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//@ts-nocheck
|
//@ts-nocheck
|
||||||
import { isNumber, get, addEventListener } from '@zhst/func';
|
import { isNumber, get, addEventListenerWrapper } from '@zhst/func';
|
||||||
import { addClass, removeClass } from 'rc-util/lib/Dom/class.js';
|
import { addClass, removeClass } from 'rc-util/lib/Dom/class.js';
|
||||||
import guid from 'rc-util/lib/guid';
|
import guid from 'rc-util/lib/guid';
|
||||||
import warn from 'rc-util/lib/warn';
|
import warn from 'rc-util/lib/warn';
|
||||||
@ -33,19 +33,19 @@ export default {
|
|||||||
//图片事件
|
//图片事件
|
||||||
const scaleAble = get(options, 'scaleAble', true);
|
const scaleAble = get(options, 'scaleAble', true);
|
||||||
if (scaleAble) {
|
if (scaleAble) {
|
||||||
const handleWhele = addEventListener(canvas, EVENT_WHEEL, this.onWheel.bind(this));
|
const handleWhele = addEventListenerWrapper(canvas, EVENT_WHEEL, this.onWheel.bind(this));
|
||||||
eventHandleList.push(handleWhele);
|
eventHandleList.push(handleWhele);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dragAble = get(options, 'dragAble', true);
|
const dragAble = get(options, 'dragAble', true);
|
||||||
if (dragAble) {
|
if (dragAble) {
|
||||||
const handleDragStart = addEventListener(
|
const handleDragStart = addEventListenerWrapper(
|
||||||
canvas,
|
canvas,
|
||||||
EVENT_POINTER_DOWN,
|
EVENT_POINTER_DOWN,
|
||||||
this.onDragStart.bind(this)
|
this.onDragStart.bind(this)
|
||||||
);
|
);
|
||||||
eventHandleList.push(addEventListener);
|
eventHandleList.push(addEventListenerWrapper);
|
||||||
const handleDragMove = addEventListener(
|
const handleDragMove = addEventListenerWrapper(
|
||||||
element.ownerDocument,
|
element.ownerDocument,
|
||||||
EVENT_POINTER_MOVE,
|
EVENT_POINTER_MOVE,
|
||||||
this.onDragMove.bind(this)
|
this.onDragMove.bind(this)
|
||||||
@ -54,7 +54,7 @@ export default {
|
|||||||
EVENT_POINTER_UP.trim()
|
EVENT_POINTER_UP.trim()
|
||||||
.split(REGEXP_SPACES)
|
.split(REGEXP_SPACES)
|
||||||
.forEach((eventName) => {
|
.forEach((eventName) => {
|
||||||
const handleDragEnd = addEventListener(
|
const handleDragEnd = addEventListenerWrapper(
|
||||||
element.ownerDocument,
|
element.ownerDocument,
|
||||||
eventName,
|
eventName,
|
||||||
this.onDragEnd.bind(this)
|
this.onDragEnd.bind(this)
|
||||||
@ -64,11 +64,11 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//rect事件
|
//rect事件
|
||||||
const handleClick = addEventListener(canvas, EVENT_CLICK, this.onClick.bind(this));
|
const handleClick = addEventListenerWrapper(canvas, EVENT_CLICK, this.onClick.bind(this));
|
||||||
eventHandleList.push(handleClick);
|
eventHandleList.push(handleClick);
|
||||||
// const handleLeveal = addEventListener(canvas, EVENT_LEAVEL, this.onLeavel.bind(this));
|
// const handleLeveal = addEventListenerWrapper(canvas, EVENT_LEAVEL, this.onLeavel.bind(this));
|
||||||
// eventHandleList.push(handleLeveal);
|
// eventHandleList.push(handleLeveal);
|
||||||
// const handleEnter = addEventListener(canvas, EVENT_ENTER, this.onEnter.bind(this));
|
// const handleEnter = addEventListenerWrapper(canvas, EVENT_ENTER, this.onEnter.bind(this));
|
||||||
// eventHandleList.push(handleEnter);
|
// eventHandleList.push(handleEnter);
|
||||||
},
|
},
|
||||||
unbind() {
|
unbind() {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useRef, useState, FC, useEffect, useCallback } from 'react'
|
import React, { useRef, useState, FC, useEffect, useCallback } from 'react'
|
||||||
import { generateImg, get, addEventListener } from '@zhst/func';
|
import { generateImg, get, addEventListenerWrapper } from '@zhst/func';
|
||||||
import { useUpdateEffect } from '@zhst/hooks';
|
import { useUpdateEffect } from '@zhst/hooks';
|
||||||
import { Button } from 'antd';
|
import { Button } from 'antd';
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
@ -43,7 +43,7 @@ const CompaterImage: FC<CompaterImageProps> = (props) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setShowUrl(url);
|
setShowUrl(url);
|
||||||
const handleTransformChange = addEventListener(
|
const handleTransformChange = addEventListenerWrapper(
|
||||||
imgContainerRef.current,
|
imgContainerRef.current,
|
||||||
'viewer-transform-change',
|
'viewer-transform-change',
|
||||||
(event: any) => {
|
(event: any) => {
|
||||||
|
116
packages/meta/src/VideoPlayer/components/FlvPlayer/index.tsx
Normal file
116
packages/meta/src/VideoPlayer/components/FlvPlayer/index.tsx
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
import React, { Component, CSSProperties } from 'react';
|
||||||
|
import flvjs from 'flv.js';
|
||||||
|
import { isEqual } from '@zhst/func';
|
||||||
|
|
||||||
|
export const FLV_EVENT = flvjs.Events;
|
||||||
|
|
||||||
|
export interface VideoPlayerProps {
|
||||||
|
className: string;
|
||||||
|
style?: CSSProperties;
|
||||||
|
type: string;
|
||||||
|
isLive?: boolean;
|
||||||
|
cors?: boolean;
|
||||||
|
withCredentials?: boolean;
|
||||||
|
playId?: number;
|
||||||
|
|
||||||
|
hasAudio?: boolean;
|
||||||
|
hasVideo?: boolean;
|
||||||
|
|
||||||
|
duration?: number;
|
||||||
|
filesize?: number;
|
||||||
|
url?: string;
|
||||||
|
autoPlay?: boolean;
|
||||||
|
onCreat?: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see https://github.com/Bilibili/flv.js/blob/master/docs/api.md#config
|
||||||
|
*/
|
||||||
|
config: object;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class VideoPlayer extends Component<VideoPlayerProps, any> {
|
||||||
|
state = {
|
||||||
|
curPlayUrl: '',
|
||||||
|
shouldReinit: false,
|
||||||
|
};
|
||||||
|
flvPlayer = null;
|
||||||
|
videoElement = null;
|
||||||
|
|
||||||
|
static getDerivedStateFromProps = (nextProps: { url?: any; playId?: any; }, prevState: { curPlayUrl?: any; playId?: any; }) => {
|
||||||
|
const { playId = 0 } = nextProps;
|
||||||
|
const { playId: prePlayId = 0 } = prevState;
|
||||||
|
|
||||||
|
if (nextProps.url !== undefined) {
|
||||||
|
if (!isEqual(nextProps.url, prevState.curPlayUrl) || !isEqual(playId, prePlayId)) {
|
||||||
|
return {
|
||||||
|
playId: playId,
|
||||||
|
curPlayUrl: nextProps.url,
|
||||||
|
shouldReinit: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 否则,对于state不进行任何操作
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
initFlv = ($video: null) => {
|
||||||
|
this.videoElement = $video;
|
||||||
|
const { className, autoPlay = true, config = {}, onCreat, playId, ...others } = this.props;
|
||||||
|
|
||||||
|
if ($video) {
|
||||||
|
|
||||||
|
if (flvjs.isSupported() && this.props.url && this.props.url !== '') {
|
||||||
|
const reload = () => {
|
||||||
|
|
||||||
|
if (this.flvPlayer && this.flvPlayer.destroy) {
|
||||||
|
try {
|
||||||
|
this.flvPlayer?.destroy();
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let flvPlayer = flvjs.createPlayer({ ...others }, config);
|
||||||
|
flvPlayer.attachMediaElement($video);
|
||||||
|
flvPlayer.load();
|
||||||
|
this.flvPlayer = flvPlayer;
|
||||||
|
this.flvPlayer.reload = reload;
|
||||||
|
onCreat && onCreat(this.flvPlayer, $video);
|
||||||
|
};
|
||||||
|
reload();
|
||||||
|
onCreat && onCreat(this.flvPlayer, $video);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
if (this.flvPlayer) {
|
||||||
|
this.flvPlayer?.unload();
|
||||||
|
this.flvPlayer?.detachMediaElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
componentDidUpdate() {
|
||||||
|
if (this.state.shouldReinit) {
|
||||||
|
this.setState({ shouldReinit: false });
|
||||||
|
this.initFlv(this.videoElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const { className, style } = this.props;
|
||||||
|
return (
|
||||||
|
<video
|
||||||
|
muted
|
||||||
|
preload="metadata"
|
||||||
|
className={className}
|
||||||
|
// controls={true}
|
||||||
|
style={Object.assign(
|
||||||
|
{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
},
|
||||||
|
style ? style : {}
|
||||||
|
)}
|
||||||
|
ref={this.initFlv}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
53
packages/meta/src/VideoPlayer/components/Loading/index.less
Normal file
53
packages/meta/src/VideoPlayer/components/Loading/index.less
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
.zhst-image__video-view__player-mask {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 99;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: rgb(4 4 4 / 70%);
|
||||||
|
|
||||||
|
&--bg {
|
||||||
|
z-index: 999;
|
||||||
|
background-color: rgb(4 4 4 / 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-title {
|
||||||
|
margin-top: 12px;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
& a {
|
||||||
|
color: #09f;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.zhst-image__video-view__icon-wraper {
|
||||||
|
display: flex;
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: rgb(255 255 255 / 10%);
|
||||||
|
border-radius: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
line-height: 80px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
// &:hover {
|
||||||
|
// background: #0099ff;
|
||||||
|
// }
|
||||||
|
}
|
72
packages/meta/src/VideoPlayer/components/Loading/index.tsx
Normal file
72
packages/meta/src/VideoPlayer/components/Loading/index.tsx
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import React, { FC } from 'react'
|
||||||
|
import { Spin } from 'antd'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
import Icon from '../../../iconfont'
|
||||||
|
import './index.less'
|
||||||
|
|
||||||
|
const componentName = `zhst-image__video-view`;
|
||||||
|
|
||||||
|
export interface ILoading {
|
||||||
|
status: 'LOADING' | 'COMPLETED' | 'END' | 'ERROR'
|
||||||
|
reload: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const Loading: FC<ILoading> = (props) => {
|
||||||
|
const { status, reload } = props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames(`${componentName}__player-mask`)}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* todo:图标颜色 */}
|
||||||
|
{status === 'LOADING' && (
|
||||||
|
<Spin tip="加载中..." spinning={status === 'LOADING'} />
|
||||||
|
)}
|
||||||
|
{status === 'END' && (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
onClick={() => {
|
||||||
|
reload();
|
||||||
|
}}
|
||||||
|
className={classNames(`${componentName}__icon-wraper`)}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
styles={{
|
||||||
|
fill: '#ffffff',
|
||||||
|
color: '#ffffff',
|
||||||
|
}}
|
||||||
|
size={54}
|
||||||
|
icon={'icon-shuaxin'}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={classNames(`${componentName}__player-mask-title`)}>
|
||||||
|
{'点击刷新后,将重新播放'}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{status === 'ERROR' && (
|
||||||
|
<>
|
||||||
|
<div className={classNames(`${componentName}__icon-wraper`)}>
|
||||||
|
<Icon
|
||||||
|
styles={{
|
||||||
|
color: '#ffffff',
|
||||||
|
}}
|
||||||
|
size={54}
|
||||||
|
icon={'icon-jiazaishibai'}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={classNames(`${componentName}__player-mask-title`)}>
|
||||||
|
{'视频加载失败,'}
|
||||||
|
<a onClick={reload}> {'刷新'}</a>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Loading
|
49
packages/meta/src/VideoPlayer/components/Progress/index.less
Normal file
49
packages/meta/src/VideoPlayer/components/Progress/index.less
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
.zhst-image__range {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&--no-slider {
|
||||||
|
.next-range-slider {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .next-range .next-range-track {
|
||||||
|
height: 8px;
|
||||||
|
margin-top: -4px;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .next-range .next-range-selected {
|
||||||
|
height: 8px;
|
||||||
|
margin-top: -4px;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .next-range .next-range-slider-inner {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
border-color: #fff;
|
||||||
|
margin-top: -7px;
|
||||||
|
margin-left: -7px;
|
||||||
|
background-color: #0098ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .next-range .next-range-slider {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
margin-top: -7px;
|
||||||
|
margin-left: -7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .next-range.simulation-click>.next-range-slider-inner {
|
||||||
|
border: 2px solid #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .next-range .next-range-frag.next-range-active .next-range-slider .next-range-slider-inner {
|
||||||
|
border: 2px solid #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .next-range .next-range-slider.next-range-slider-moving .next-range-slider-inner {
|
||||||
|
border: 2px solid #fff !important;
|
||||||
|
}
|
||||||
|
}
|
29
packages/meta/src/VideoPlayer/components/Progress/index.tsx
Normal file
29
packages/meta/src/VideoPlayer/components/Progress/index.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { Slider } from 'antd';
|
||||||
|
import './index.less';
|
||||||
|
|
||||||
|
const componentName = `zhst-image__range`;
|
||||||
|
|
||||||
|
export interface RangeWrapperProps extends React.HTMLAttributes<HTMLElement> {
|
||||||
|
showSlider: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Range: React.FC<RangeWrapperProps> = (props) => {
|
||||||
|
const { className, style, showSlider = true, ...others } = props;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={style}
|
||||||
|
className={classNames(
|
||||||
|
`${componentName}`,
|
||||||
|
!showSlider && `${componentName}--no-slider`,
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{/* @ts-ignore */}
|
||||||
|
<Slider {...others}></Slider>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Range;
|
75
packages/meta/src/VideoPlayer/index.less
Normal file
75
packages/meta/src/VideoPlayer/index.less
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
.zhst-image__video-view {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
|
height: 532px;
|
||||||
|
background-color: #333;
|
||||||
|
|
||||||
|
// &-flv {
|
||||||
|
// width: 85%;
|
||||||
|
// }
|
||||||
|
&-screenshot {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-crop-container {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-align {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-opt {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 99;
|
||||||
|
bottom: 0;
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
height: 32px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 12px;
|
||||||
|
background-color: rgb(0 0 0 / 80%);
|
||||||
|
line-height: 32px;
|
||||||
|
|
||||||
|
&>div:first-child {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&>div:last-child {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-left: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-range {
|
||||||
|
display: flex;
|
||||||
|
height: 32px;
|
||||||
|
flex: 1;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 32px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&>div:first-child {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&>div:last-child {
|
||||||
|
width: 100px;
|
||||||
|
margin-left: 8px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
packages/meta/src/VideoPlayer/index.md
Normal file
27
packages/meta/src/VideoPlayer/index.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
nav:
|
||||||
|
title: 元组件
|
||||||
|
order: 1
|
||||||
|
group:
|
||||||
|
title: 通用
|
||||||
|
order: 3
|
||||||
|
---
|
||||||
|
|
||||||
|
# VideoPlayer 视频播放
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import React from 'react';
|
||||||
|
import { VideoPlayer } from '@zhst/meta'
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
"flvUrl":"ws://10.0.0.120:9033/flv/HaikangNvr/45.flv?ip=10.0.2.103&stime=1705051970&etime=1705051990",
|
||||||
|
"maxDuration":20,
|
||||||
|
"showCrop$":false
|
||||||
|
}
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
return (
|
||||||
|
<VideoPlayer {...props} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
696
packages/meta/src/VideoPlayer/index.tsx
Normal file
696
packages/meta/src/VideoPlayer/index.tsx
Normal file
@ -0,0 +1,696 @@
|
|||||||
|
import React, { Dispatch, ReactElement, SetStateAction, forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
||||||
|
import {
|
||||||
|
noop,
|
||||||
|
get,
|
||||||
|
addEventListenerWrapper,
|
||||||
|
dataURLToBlob,
|
||||||
|
nextTick,
|
||||||
|
toRealNumber,
|
||||||
|
getTransforms,
|
||||||
|
formatDurationTime
|
||||||
|
} from '@zhst/func';
|
||||||
|
import Align from 'rc-align';
|
||||||
|
import { Rect, IScreenshotButtonProp, AlignType } from '@zhst/types'
|
||||||
|
import { useLatest, useUpdateEffect, useFullscreen, useUnmount } from '@zhst/hooks';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import download from 'downloadjs';
|
||||||
|
import { Button, message } from 'antd';
|
||||||
|
import Icon from '../iconfont';
|
||||||
|
import {
|
||||||
|
Cropper,
|
||||||
|
EVENT_CROP_START,
|
||||||
|
EVENT_CROP_END,
|
||||||
|
} from '../ImageEditor';
|
||||||
|
import FlvPlayer, { FLV_EVENT } from './components/FlvPlayer';
|
||||||
|
import Range from './components/Progress';
|
||||||
|
import Loading, { ILoading } from './components/Loading';
|
||||||
|
import getScreenshotButtonRender from '../BigImagePreview/components/ScreenhotButtons';
|
||||||
|
import './index.less'
|
||||||
|
|
||||||
|
const componentName = `zhst-image__video-view`;
|
||||||
|
|
||||||
|
export const CROP_TYPE = {
|
||||||
|
CUSTOM: 'CSUTOM',
|
||||||
|
AUTO: 'AUTO',
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getShowStatus(isLoadingVideo: boolean, isEnd: boolean, isError: boolean): ILoading['status'] {
|
||||||
|
let status = null;
|
||||||
|
if (isLoadingVideo) {
|
||||||
|
status = 'LOADING';
|
||||||
|
}
|
||||||
|
if (isError) {
|
||||||
|
status = 'ERROR';
|
||||||
|
}
|
||||||
|
if (isEnd) {
|
||||||
|
status = 'END';
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface VideoViewProps {
|
||||||
|
/* 播放地址 */
|
||||||
|
flvUrl: string;
|
||||||
|
/* 播放总时间 */
|
||||||
|
maxDuration?: number;
|
||||||
|
/* 截图渲染 */
|
||||||
|
screenshotButtonAlign?: AlignType;
|
||||||
|
screenshotButtonRender?: (screenshotButtonProp: IScreenshotButtonProp) => ReactElement;
|
||||||
|
/* 默认截图框 */
|
||||||
|
defautlNormalizationRect?: Rect;
|
||||||
|
/* 截图回调 */
|
||||||
|
onCropChange?: (showCrop: boolean, normalizationRect: null | Rect) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VideoViewRef {
|
||||||
|
/* 当前图片模式 */
|
||||||
|
cropAble: boolean;
|
||||||
|
setShowCrop: Dispatch<SetStateAction<boolean>>;
|
||||||
|
downloadVideoframe: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VideoPlayer = forwardRef<VideoViewRef, VideoViewProps>((props, ref) => {
|
||||||
|
const {
|
||||||
|
flvUrl,
|
||||||
|
maxDuration,
|
||||||
|
screenshotButtonAlign = {
|
||||||
|
points: ['bl', 'br'],
|
||||||
|
offset: [6, 0],
|
||||||
|
overflow: {
|
||||||
|
adjustX: true,
|
||||||
|
adjustY: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
screenshotButtonRender = getScreenshotButtonRender({
|
||||||
|
onBigImageActionClick: () => {},
|
||||||
|
disableBtn: [],
|
||||||
|
}),
|
||||||
|
onCropChange,
|
||||||
|
defautlNormalizationRect: defaultNormalizationRect,
|
||||||
|
} = props;
|
||||||
|
const videoType = useMemo(() => (flvUrl && flvUrl.startsWith('http') ? 'mp4' : 'flv'), [flvUrl]);
|
||||||
|
// ========================== 播放 =========================
|
||||||
|
//实例参数
|
||||||
|
const containerRef = useRef(null); //容器ref
|
||||||
|
const videoRef = useRef(null); //video 标签dom
|
||||||
|
const videoInsRef: any = useRef(null); //flv 实例
|
||||||
|
const [playSeq, setPlaySeq] = useState(0); // 通过重置playid使FLV组件重新渲染
|
||||||
|
const videoRemoveListener = useRef(noop); //移除dom监听的中间函数
|
||||||
|
const loadingTimeRef = useRef<number | null>(0); //最后一次加载时间
|
||||||
|
const delayLoadingTimer = useRef(null); //算loading的定时器
|
||||||
|
//状态参数
|
||||||
|
const [isReady, setIsReady] = useState(false); //
|
||||||
|
const [isPlay, setIsPlay] = useState(false); //当前是否播放
|
||||||
|
|
||||||
|
const [isEnd, setIsEnd] = useState(false); //是否播放结束
|
||||||
|
const [isError, setIsError] = useState(false); //播放出错
|
||||||
|
const [isVideoLoadFinished, setIsVideoLoadFinish] = useState(false); //是否缓存加载完成
|
||||||
|
const [playTime, setPlayTime] = useState(0); //当前播放时间
|
||||||
|
const [isLoadingVideo, setIsLoadingVideo] = useState(true); //是否加载中
|
||||||
|
const [isDelayLoading, setIsDelayLoading] = useState(false); //显示的转圈loading 延迟0.2s显示
|
||||||
|
//设置延迟转圈圈
|
||||||
|
const latestIsLoadingVideo = useLatest(isLoadingVideo);
|
||||||
|
const setIsLoadingVideoWrapper = (isLoading: boolean) => {
|
||||||
|
setIsLoadingVideo((preLoading) => {
|
||||||
|
if (!preLoading && isLoading) {
|
||||||
|
loadingTimeRef.current = new Date().getTime();
|
||||||
|
}
|
||||||
|
if (!isLoading) {
|
||||||
|
loadingTimeRef.current = null;
|
||||||
|
}
|
||||||
|
//延迟0。2s相关
|
||||||
|
if (!isLoading) {
|
||||||
|
setIsDelayLoading(false);
|
||||||
|
}
|
||||||
|
if (!delayLoadingTimer.current && preLoading) {
|
||||||
|
delayLoadingTimer.current = setTimeout(() => {
|
||||||
|
if (latestIsLoadingVideo.current) {
|
||||||
|
//0.2s后才显示
|
||||||
|
setIsDelayLoading(true);
|
||||||
|
}
|
||||||
|
delayLoadingTimer.current = null;
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
return isLoading;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// 初始化loading 30s 直接显示错误
|
||||||
|
// TODO :逻辑忘记了 不应该是每次init player吗?
|
||||||
|
useEffect(() => {
|
||||||
|
let timer = setInterval(() => {
|
||||||
|
if (loadingTimeRef.current) {
|
||||||
|
if (new Date().getTime() - loadingTimeRef.current > 1000 * 30) {
|
||||||
|
checkIsErr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
return () => {
|
||||||
|
clearInterval(timer);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
//结束的时候暂停 保证不播了
|
||||||
|
useUpdateEffect(() => {
|
||||||
|
if (isEnd) {
|
||||||
|
videoInsRef?.current?.pause?.();
|
||||||
|
}
|
||||||
|
}, [isEnd]);
|
||||||
|
|
||||||
|
// 捕捉视频播放报错
|
||||||
|
const checkIsErr = () => {
|
||||||
|
setIsError(true)
|
||||||
|
try {
|
||||||
|
videoInsRef?.current?.destroy?.();
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
const latestMaxDuration = useLatest(maxDuration);
|
||||||
|
const initPlayer = useCallback((ins: any, dom: any) => {
|
||||||
|
videoRef.current = dom;
|
||||||
|
videoInsRef.current = ins;
|
||||||
|
const maxDuration = latestMaxDuration.current || 0;
|
||||||
|
//监听播放事件
|
||||||
|
let video = dom;
|
||||||
|
let errorLister = (e: any) => {
|
||||||
|
checkIsErr();
|
||||||
|
console.error('视频出错了', e, video.currentTime);
|
||||||
|
};
|
||||||
|
let waitingListener = (e: any) => {
|
||||||
|
setIsLoadingVideoWrapper(true);
|
||||||
|
console.debug('视频加载等待', e, video.currentTime);
|
||||||
|
};
|
||||||
|
let playingListener = (e: any) => {
|
||||||
|
setIsLoadingVideoWrapper(false);
|
||||||
|
setIsError(false)
|
||||||
|
console.debug('视频从等待中播放', e, video.currentTime);
|
||||||
|
};
|
||||||
|
let playLister = (e: any) => {
|
||||||
|
setIsPlay(true);
|
||||||
|
setIsError(false)
|
||||||
|
console.debug('提示该视频正在播放中', e, video.currentTime);
|
||||||
|
};
|
||||||
|
let pauseListener = (e: any) => {
|
||||||
|
setIsPlay(false);
|
||||||
|
console.debug('暂停播放', e, video.currentTime);
|
||||||
|
};
|
||||||
|
let endedListner = (e: any) => {
|
||||||
|
setIsEnd(true);
|
||||||
|
setIsVideoLoadFinish(true);
|
||||||
|
console.debug('视频播放完了', e, video.currentTime);
|
||||||
|
};
|
||||||
|
let timeupdateListner = (e: any) => {
|
||||||
|
console.debug(
|
||||||
|
'视频播放时间更新',
|
||||||
|
e,
|
||||||
|
video.currentTime,
|
||||||
|
videoRef.current?.duration,
|
||||||
|
maxDuration
|
||||||
|
);
|
||||||
|
let nowTime = video.currentTime;
|
||||||
|
if (nowTime >= maxDuration) {
|
||||||
|
setIsEnd(true);
|
||||||
|
setIsVideoLoadFinish(true);
|
||||||
|
}
|
||||||
|
setPlayTime(nowTime);
|
||||||
|
};
|
||||||
|
// see https://github.com/bilibili/flv.js/issues/337
|
||||||
|
let windowErrorHandle = (errorEvent: { [x: string]: string; }) => {
|
||||||
|
try {
|
||||||
|
if (
|
||||||
|
errorEvent['message'] ==
|
||||||
|
"Uncaught TypeError: Cannot read property 'flushStashedSamples' of null"
|
||||||
|
) {
|
||||||
|
checkIsErr();
|
||||||
|
console.error('视频出错了 window监听', errorEvent);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
video.addEventListener('error', errorLister);
|
||||||
|
video.addEventListener('waiting', waitingListener);
|
||||||
|
video.addEventListener('playing', playingListener);
|
||||||
|
video.addEventListener('play', playLister);
|
||||||
|
video.addEventListener('pause', pauseListener);
|
||||||
|
video.addEventListener('ended', endedListner);
|
||||||
|
video.addEventListener('timeupdate', timeupdateListner);
|
||||||
|
window.addEventListener('error', windowErrorHandle);
|
||||||
|
|
||||||
|
videoRemoveListener.current = () => {
|
||||||
|
video.removeEventListener('error', errorLister);
|
||||||
|
video.removeEventListener('waiting', waitingListener);
|
||||||
|
video.removeEventListener('playing', playingListener);
|
||||||
|
video.removeEventListener('play', playLister);
|
||||||
|
video.removeEventListener('pause', pauseListener);
|
||||||
|
video.removeEventListener('ended', endedListner);
|
||||||
|
video.removeEventListener('timeupdate', timeupdateListner);
|
||||||
|
window.removeEventListener('error', windowErrorHandle);
|
||||||
|
};
|
||||||
|
|
||||||
|
videoInsRef?.current.on(FLV_EVENT.ERROR, (type: any, errDetail: any, info: any) => {
|
||||||
|
checkIsErr();
|
||||||
|
console.error('videoInsRef 错误', type, errDetail, info, video.currentTime);
|
||||||
|
});
|
||||||
|
let playPromise = videoInsRef?.current.play();
|
||||||
|
//先ready 遮挡会导致播放失败
|
||||||
|
setIsReady(true);
|
||||||
|
playPromise
|
||||||
|
.then(() => {
|
||||||
|
setIsReady(true);
|
||||||
|
})
|
||||||
|
.catch((...arg: any) => {
|
||||||
|
try {
|
||||||
|
} catch (error) {}
|
||||||
|
// setIsError(true);
|
||||||
|
console.error('playPromise视频出错了', arg);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useUnmount(() => {
|
||||||
|
try {
|
||||||
|
videoRemoveListener.current();
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const reload = async () => {
|
||||||
|
if (videoInsRef.current) {
|
||||||
|
let oldTime = videoInsRef.current.currentTime;
|
||||||
|
videoInsRef.current.currentTime = 0;
|
||||||
|
|
||||||
|
//如果修改时间不成功,则走重新加载的逻辑
|
||||||
|
if (oldTime === videoInsRef.current.currentTime) {
|
||||||
|
//重置状态
|
||||||
|
setIsReady(false);
|
||||||
|
setIsPlay(false);
|
||||||
|
setIsLoadingVideoWrapper(false);
|
||||||
|
setIsReady(false);
|
||||||
|
setIsEnd(false);
|
||||||
|
setIsVideoLoadFinish(false);
|
||||||
|
setPlayTime(0);
|
||||||
|
|
||||||
|
//清楚dom事件监听
|
||||||
|
try {
|
||||||
|
videoRemoveListener.current();
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
setPlaySeq((pre) => pre + 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
videoInsRef.current.play();
|
||||||
|
}
|
||||||
|
|
||||||
|
setPlayTime(0);
|
||||||
|
setIsEnd(false);
|
||||||
|
};
|
||||||
|
const seek = (v: string) => {
|
||||||
|
if (videoInsRef.current && isVideoLoadFinished) {
|
||||||
|
setPlayTime(parseFloat(v));
|
||||||
|
videoInsRef.current.currentTime = parseFloat(v);
|
||||||
|
} else {
|
||||||
|
message.warning('待视频加载完,才可操作进度条')
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// ========================== 视频opt bar =========================
|
||||||
|
const [isFullscreen, { toggleFullscreen }] = useFullscreen(containerRef, {
|
||||||
|
pageFullscreen: true,
|
||||||
|
});
|
||||||
|
const showMaxDuration = !!maxDuration
|
||||||
|
? maxDuration
|
||||||
|
: toRealNumber(get(videoRef, 'current.duration', 0));
|
||||||
|
const showSlider = videoInsRef.current && isVideoLoadFinished;
|
||||||
|
const showStatus = getShowStatus(isDelayLoading, isEnd, isError);
|
||||||
|
|
||||||
|
// ========================== 截图 =========================
|
||||||
|
const corpContainerRef = useRef();
|
||||||
|
const cropInsRef = useRef(null);
|
||||||
|
const [showCrop, setShowCrop] = useState<boolean>(false);
|
||||||
|
|
||||||
|
//回显默认框选
|
||||||
|
const isFirstFlagRef = useRef<boolean>(true);
|
||||||
|
useEffect(() => {
|
||||||
|
const isFirst = isFirstFlagRef.current;
|
||||||
|
if (!isLoadingVideo && isReady && isFirst && defaultNormalizationRect && !showStatus) {
|
||||||
|
nextTick(() => {
|
||||||
|
setShowCrop(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [isLoadingVideo, showStatus]);
|
||||||
|
|
||||||
|
//定位按钮相关参数
|
||||||
|
const alginContainerRef = useRef(null);
|
||||||
|
const alignRef = useRef(null);
|
||||||
|
const [cropRect, setCropRect] = useState<Rect| null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
showCrop ? videoInsRef?.current?.pause() : videoInsRef?.current?.play();
|
||||||
|
}, [showCrop]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let handlerCropStart: { remove: () => void; };
|
||||||
|
let handlerCropEnd: { remove: () => void; };
|
||||||
|
setCropRect(null);
|
||||||
|
if (!isReady) return;
|
||||||
|
if (showCrop) {
|
||||||
|
handlerCropStart = addEventListenerWrapper(corpContainerRef.current, EVENT_CROP_START, (event) => {
|
||||||
|
setCropRect(null);
|
||||||
|
});
|
||||||
|
handlerCropEnd = addEventListenerWrapper(corpContainerRef.current, EVENT_CROP_END, (event) => {
|
||||||
|
const data = event.detail;
|
||||||
|
setCropRect({
|
||||||
|
x: data.left,
|
||||||
|
y: data.top,
|
||||||
|
w: data.width,
|
||||||
|
h: data.height,
|
||||||
|
});
|
||||||
|
alignRef?.current?.forceAlign?.();
|
||||||
|
});
|
||||||
|
let video: any = videoRef.current;
|
||||||
|
//计算limitcroppbox
|
||||||
|
let scale = Math.min(
|
||||||
|
video.offsetWidth / video.videoWidth,
|
||||||
|
video.offsetHeight / video.videoHeight
|
||||||
|
);
|
||||||
|
let finalVideoWidth = video.videoWidth * scale;
|
||||||
|
let finalVideoHeight = video.videoHeight * scale;
|
||||||
|
let cropBoxLimited = {
|
||||||
|
width: finalVideoWidth,
|
||||||
|
height: finalVideoHeight,
|
||||||
|
top: (video.offsetHeight - finalVideoHeight) / 2,
|
||||||
|
left: (video.offsetWidth - finalVideoWidth) / 2,
|
||||||
|
};
|
||||||
|
//获取视频图片
|
||||||
|
let canvas = document.createElement('canvas');
|
||||||
|
canvas.width = video.offsetWidth;
|
||||||
|
canvas.height = video.offsetHeight;
|
||||||
|
canvas.style.display = 'none';
|
||||||
|
document.body.appendChild(canvas);
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
ctx.drawImage(
|
||||||
|
video,
|
||||||
|
(video.offsetWidth - finalVideoWidth) / 2,
|
||||||
|
(video.offsetHeight - finalVideoHeight) / 2,
|
||||||
|
finalVideoWidth,
|
||||||
|
finalVideoHeight
|
||||||
|
);
|
||||||
|
let imageData = canvas.toDataURL('image/png');
|
||||||
|
canvas.parentNode?.removeChild(canvas);
|
||||||
|
//回显编辑框
|
||||||
|
const isFirst = isFirstFlagRef.current;
|
||||||
|
let initialCropBoxData = null;
|
||||||
|
if (isFirst && defaultNormalizationRect) {
|
||||||
|
initialCropBoxData = {
|
||||||
|
left: defaultNormalizationRect.x * finalVideoWidth + cropBoxLimited.left,
|
||||||
|
top: defaultNormalizationRect.y * finalVideoHeight + cropBoxLimited.top,
|
||||||
|
width: defaultNormalizationRect.w * finalVideoWidth,
|
||||||
|
height: defaultNormalizationRect.h * finalVideoHeight,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
isFirstFlagRef.current = false;
|
||||||
|
|
||||||
|
cropInsRef.current = new Cropper(corpContainerRef.current, {
|
||||||
|
showMask: true,
|
||||||
|
cropBoxLimited,
|
||||||
|
img: imageData,
|
||||||
|
initialCropBoxData,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return () => {
|
||||||
|
handlerCropStart?.remove();
|
||||||
|
handlerCropEnd?.remove();
|
||||||
|
cropInsRef?.current?.destroy?.();
|
||||||
|
cropInsRef.current = null;
|
||||||
|
};
|
||||||
|
}, [showCrop, isReady]);
|
||||||
|
|
||||||
|
const latestCropRect = useLatest(cropRect);
|
||||||
|
|
||||||
|
const getCropInfo = async () => {
|
||||||
|
const cropRect = latestCropRect.current as any;
|
||||||
|
let video: any = videoRef.current;
|
||||||
|
if (!video) return
|
||||||
|
let rectList = [];
|
||||||
|
let extendRectList = [];
|
||||||
|
let selectIndex = 0;
|
||||||
|
//获取视频图片的url
|
||||||
|
let scale = Math.min(
|
||||||
|
video.offsetWidth / video.videoWidth,
|
||||||
|
video.offsetHeight / video.videoHeight
|
||||||
|
);
|
||||||
|
let finalVideoWidth = video.videoWidth * scale;
|
||||||
|
let finalVideoHeight = video.videoHeight * scale;
|
||||||
|
let canvas = document.createElement('canvas');
|
||||||
|
canvas.width = finalVideoWidth;
|
||||||
|
canvas.height = finalVideoHeight;
|
||||||
|
canvas.style.display = 'none';
|
||||||
|
document.body.appendChild(canvas);
|
||||||
|
let ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
|
||||||
|
ctx.drawImage(
|
||||||
|
video,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
finalVideoWidth,
|
||||||
|
finalVideoHeight
|
||||||
|
);
|
||||||
|
let base64 = canvas.toDataURL('image/jpeg');
|
||||||
|
const blobData = dataURLToBlob(base64);
|
||||||
|
canvas.parentNode?.removeChild(canvas);
|
||||||
|
const file = new window.File([blobData], `${new Date().getTime()}`);
|
||||||
|
let newRect = {
|
||||||
|
w: cropRect.w / finalVideoWidth,
|
||||||
|
h: cropRect.h / finalVideoHeight,
|
||||||
|
x: (cropRect.x - (video.offsetWidth - finalVideoWidth) / 2) / finalVideoWidth,
|
||||||
|
y: (cropRect.y - (video.offsetHeight - finalVideoHeight) / 2) / finalVideoHeight
|
||||||
|
};
|
||||||
|
rectList.push(newRect);
|
||||||
|
extendRectList.push(newRect);
|
||||||
|
//扩展框获取imgkey
|
||||||
|
extendRectList.forEach(async (rect, index) => {
|
||||||
|
extendRectList[index] = {
|
||||||
|
...rect,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
rectList,
|
||||||
|
extendRectList,
|
||||||
|
selectIndex,
|
||||||
|
file
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
//回调
|
||||||
|
useEffect(() => {
|
||||||
|
//计算归一化crop rect
|
||||||
|
let normalizationRect = null;
|
||||||
|
if (showCrop && cropRect) {
|
||||||
|
let video: any = videoRef.current;
|
||||||
|
let scale = Math.min(
|
||||||
|
video.offsetWidth / video.videoWidth,
|
||||||
|
video.offsetHeight / video.videoHeight
|
||||||
|
);
|
||||||
|
let finalVideoWidth = video.videoWidth * scale;
|
||||||
|
let finalVideoHeight = video.videoHeight * scale;
|
||||||
|
let cropBoxLimited = {
|
||||||
|
width: finalVideoWidth,
|
||||||
|
height: finalVideoHeight,
|
||||||
|
top: (video.offsetHeight - finalVideoHeight) / 2,
|
||||||
|
left: (video.offsetWidth - finalVideoWidth) / 2,
|
||||||
|
};
|
||||||
|
normalizationRect = {
|
||||||
|
x: (cropRect.x - cropBoxLimited.left) / cropBoxLimited.width,
|
||||||
|
y: (cropRect.y - cropBoxLimited.top) / cropBoxLimited.height,
|
||||||
|
w: cropRect.w / cropBoxLimited.width,
|
||||||
|
h: cropRect.h / cropBoxLimited.height,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onCropChange?.(showCrop, normalizationRect);
|
||||||
|
}, [showCrop, cropRect]);
|
||||||
|
|
||||||
|
// ========================== 截帧 =========================
|
||||||
|
const downloadVideoframe = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
videoInsRef?.current?.pause?.();
|
||||||
|
let video: any = videoRef.current;
|
||||||
|
var canvas = document.createElement('canvas');
|
||||||
|
const ctx = canvas.getContext('2d')
|
||||||
|
let base64;
|
||||||
|
//当视频处于还未加载出来时,截屏为黑色图片
|
||||||
|
if (video.readyState === 0) {
|
||||||
|
ctx?.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
canvas.width = video.offsetWidth;
|
||||||
|
canvas.height = video.offsetHeight;
|
||||||
|
// @ts-ignore
|
||||||
|
ctx.fillStyle = 'black';
|
||||||
|
ctx?.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
base64 = canvas.toDataURL();
|
||||||
|
} else {
|
||||||
|
canvas.width = video.videoWidth;
|
||||||
|
canvas.height = video.videoHeight;
|
||||||
|
ctx?.drawImage(video, 0, 0, canvas.width, canvas.height);
|
||||||
|
base64 = canvas.toDataURL('image/png');
|
||||||
|
}
|
||||||
|
download(base64);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// ============================== 暴露出去的方法 ===============================
|
||||||
|
const latestIsReady = useLatest(isReady);
|
||||||
|
const cropAble = !showStatus && isReady;
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
cropAble,
|
||||||
|
setShowCrop: (dispatch) => {
|
||||||
|
const isReady = latestIsReady.current;
|
||||||
|
if (!isReady) return;
|
||||||
|
setShowCrop(dispatch);
|
||||||
|
},
|
||||||
|
downloadVideoframe,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classNames(`${componentName}`)} ref={containerRef}>
|
||||||
|
{flvUrl && (
|
||||||
|
<>
|
||||||
|
<FlvPlayer
|
||||||
|
playId={playSeq}
|
||||||
|
autoPlay={true}
|
||||||
|
className={classNames(`${componentName}-flv`)}
|
||||||
|
type={videoType}
|
||||||
|
url={flvUrl}
|
||||||
|
config={{
|
||||||
|
enableStashBuffer: true,
|
||||||
|
stashInitialSize: 1024 * 700,
|
||||||
|
isLive: true,
|
||||||
|
hasAudio: false,
|
||||||
|
hasVideo: true,
|
||||||
|
}}
|
||||||
|
onCreat={initPlayer}
|
||||||
|
/>
|
||||||
|
{/* //截图 */}
|
||||||
|
<div
|
||||||
|
className={classNames(`${componentName}-crop-container`)}
|
||||||
|
ref={corpContainerRef}
|
||||||
|
style={{
|
||||||
|
display: isFullscreen ? 'none' : 'block',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* <div ref={corpRef}></div> */}
|
||||||
|
</div>
|
||||||
|
{showCrop && cropRect && screenshotButtonRender && (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
ref={alginContainerRef}
|
||||||
|
className={classNames(`${componentName}-align`)}
|
||||||
|
style={Object.assign(
|
||||||
|
{
|
||||||
|
width: cropRect.w,
|
||||||
|
height: cropRect.h,
|
||||||
|
},
|
||||||
|
getTransforms({
|
||||||
|
translateX: cropRect.x,
|
||||||
|
translateY: cropRect.y,
|
||||||
|
})
|
||||||
|
)}
|
||||||
|
></div>
|
||||||
|
<Align
|
||||||
|
ref={alignRef}
|
||||||
|
monitorWindowResize
|
||||||
|
align={screenshotButtonAlign}
|
||||||
|
target={function () {
|
||||||
|
return alginContainerRef.current;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{screenshotButtonRender({
|
||||||
|
model: 'IMAGE',
|
||||||
|
getCropInfo,
|
||||||
|
setShowCrop,
|
||||||
|
cropType: CROP_TYPE['CUSTOM'],
|
||||||
|
})}
|
||||||
|
</Align>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{/* 视频进度条 */}
|
||||||
|
{!showCrop && (
|
||||||
|
<div className={`${componentName}-opt`}>
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
onClick={(e) => {
|
||||||
|
if (!isPlay) {
|
||||||
|
//播放中暂停
|
||||||
|
videoInsRef?.current?.play();
|
||||||
|
setShowCrop(false);
|
||||||
|
} else {
|
||||||
|
videoInsRef?.current?.pause();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
styles={{
|
||||||
|
color: '#fff',
|
||||||
|
display: 'flex',
|
||||||
|
}}
|
||||||
|
color="#1890ff"
|
||||||
|
size={18}
|
||||||
|
icon={!isPlay ? 'icon-shipinbofang' : 'icon-shipinzanting'}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`${componentName}-opt-range`}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Range
|
||||||
|
value={playTime}
|
||||||
|
min={0}
|
||||||
|
max={showMaxDuration}
|
||||||
|
hasTip={false}
|
||||||
|
showSlider={showSlider}
|
||||||
|
onChange={seek}
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
{/* TODO: 删除扩展方法format */}
|
||||||
|
{formatDurationTime(playTime)}/{formatDurationTime(showMaxDuration)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
toggleFullscreen();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
styles={{
|
||||||
|
color: '#fff',
|
||||||
|
display: 'flex',
|
||||||
|
}}
|
||||||
|
size={18}
|
||||||
|
icon={isFullscreen ? 'icon-cancle_fullscreen' : 'icon-fullscreen'}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{/* mask */}
|
||||||
|
{!!showStatus && (
|
||||||
|
<Loading status={showStatus} reload={() => reload()} />
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default VideoPlayer;
|
1679
packages/meta/src/iconfont/iconfont.css
Normal file
1679
packages/meta/src/iconfont/iconfont.css
Normal file
File diff suppressed because it is too large
Load Diff
1
packages/meta/src/iconfont/iconfont.js
Normal file
1
packages/meta/src/iconfont/iconfont.js
Normal file
File diff suppressed because one or more lines are too long
BIN
packages/meta/src/iconfont/iconfont.ttf
Normal file
BIN
packages/meta/src/iconfont/iconfont.ttf
Normal file
Binary file not shown.
BIN
packages/meta/src/iconfont/iconfont.woff
Normal file
BIN
packages/meta/src/iconfont/iconfont.woff
Normal file
Binary file not shown.
BIN
packages/meta/src/iconfont/iconfont.woff2
Normal file
BIN
packages/meta/src/iconfont/iconfont.woff2
Normal file
Binary file not shown.
@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import './iconfont.css'
|
||||||
|
|
||||||
interface IconFontProps {
|
interface IconFontProps {
|
||||||
styles?: React.CSSProperties;
|
styles?: React.CSSProperties;
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
export { default as doubleClick } from './doubleClick';
|
export { default as doubleClick } from './doubleClick';
|
||||||
export { default as Icon } from './iconfont';
|
export { default as Icon } from './iconfont';
|
||||||
export { default as ImagePreview } from './ImagePreview'
|
export { default as ImagePreview } from './ImagePreview'
|
||||||
|
export { default as BigImagePreview } from './BigImagePreview'
|
||||||
|
export { default as VideoPlayer } from './VideoPlayer'
|
||||||
|
7
packages/request/.fatherrc.ts
Normal file
7
packages/request/.fatherrc.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { defineConfig } from 'father';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
// more father config: https://github.com/umijs/father/blob/master/docs/config.md
|
||||||
|
esm: { output: 'es' },
|
||||||
|
cjs: { output: 'lib' },
|
||||||
|
});
|
19
packages/request/CHANGELOG.md
Normal file
19
packages/request/CHANGELOG.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# @zhst/request
|
||||||
|
|
||||||
|
## 0.2.4
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- feat: 新增 meta 包
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/func@0.2.4
|
||||||
|
- @zhst/hooks@0.2.4
|
||||||
|
- @zhst/meta@0.2.4
|
||||||
|
|
||||||
|
## 0.2.3
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- fix: 调试包 link
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/hooks@0.2.3
|
14
packages/request/README.md
Normal file
14
packages/request/README.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
## 介绍
|
||||||
|
|
||||||
|
zhst 请求库
|
||||||
|
|
||||||
|
## 安装
|
||||||
|
|
||||||
|
> pnpm install @zhst/request
|
||||||
|
|
||||||
|
## 使用
|
||||||
|
|
||||||
|
```js
|
||||||
|
import React from 'react';
|
||||||
|
import request from '@zhst/request'
|
||||||
|
```
|
185
packages/request/es/index.js
Normal file
185
packages/request/es/index.js
Normal file
File diff suppressed because one or more lines are too long
45
packages/request/package.json
Normal file
45
packages/request/package.json
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"name": "@zhst/request",
|
||||||
|
"version": "0.2.4",
|
||||||
|
"description": "请求库",
|
||||||
|
"keywords": [
|
||||||
|
"request",
|
||||||
|
"umi-request"
|
||||||
|
],
|
||||||
|
"license": "ISC",
|
||||||
|
"author": "dev",
|
||||||
|
"sideEffects": [
|
||||||
|
"dist/*",
|
||||||
|
"es/**/style/*",
|
||||||
|
"lib/**/style/*",
|
||||||
|
"*.less"
|
||||||
|
],
|
||||||
|
"main": "lib/index.ts",
|
||||||
|
"module": "es/index.js",
|
||||||
|
"typings": "es/index.d.ts",
|
||||||
|
"exports": {
|
||||||
|
"./package.json": "./package.json"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"es",
|
||||||
|
"lib"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "father build"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public",
|
||||||
|
"registry": "http://10.0.0.77:4874"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"antd": "^5.12.5",
|
||||||
|
"base-64": "^1.0.0",
|
||||||
|
"lodash-es": "^4.17.21",
|
||||||
|
"umi-request": "^1.4.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/base-64": "^1.0.2",
|
||||||
|
"@types/lodash-es": "^4.17.12",
|
||||||
|
"@zhst/types": "workspace:^"
|
||||||
|
}
|
||||||
|
}
|
8
packages/request/src/index.md
Normal file
8
packages/request/src/index.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
nav:
|
||||||
|
title: 请求库
|
||||||
|
order: 1
|
||||||
|
title: 快速上手
|
||||||
|
---
|
||||||
|
|
||||||
|
<embed src="../README.md" ></embed>
|
149
packages/request/src/index.ts
Normal file
149
packages/request/src/index.ts
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
import { extend } from 'umi-request';
|
||||||
|
import type { RequestOptionsInit } from 'umi-request';
|
||||||
|
import { omit, get } from 'lodash-es';
|
||||||
|
import { message } from 'antd';
|
||||||
|
import { User } from '@zhst/types/user';
|
||||||
|
import base64 from 'base-64';
|
||||||
|
|
||||||
|
export class ResponseError<D> extends Error {
|
||||||
|
name;
|
||||||
|
data;
|
||||||
|
response;
|
||||||
|
request;
|
||||||
|
type;
|
||||||
|
constructor(
|
||||||
|
response: Response,
|
||||||
|
text: string,
|
||||||
|
data: D,
|
||||||
|
request: {
|
||||||
|
url: string;
|
||||||
|
options: RequestOptionsInit;
|
||||||
|
},
|
||||||
|
type = 'ResponseError'
|
||||||
|
) {
|
||||||
|
super(text || response.statusText);
|
||||||
|
this.name = 'ResponseError';
|
||||||
|
this.data = data;
|
||||||
|
this.response = response;
|
||||||
|
this.request = request;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const req = extend({
|
||||||
|
getResponse: true,
|
||||||
|
// timeout: 1000,
|
||||||
|
parseResponse: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
//错误处理中间件
|
||||||
|
req.use(async (ctx, next) => {
|
||||||
|
const { req } = ctx;
|
||||||
|
const { toast = true } = req?.options || {};
|
||||||
|
try {
|
||||||
|
await next();
|
||||||
|
const { res } = ctx;
|
||||||
|
const d = await res.text();
|
||||||
|
if (res.status === 401) {
|
||||||
|
localStorage.removeItem(User.TOKEN_KEY);
|
||||||
|
localStorage.removeItem(User.USER_KEY);
|
||||||
|
message.warning('登录过期,请重新登录!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const isEmptyRes = d === ''; //有些后端接口成功会返回空 做下兼容
|
||||||
|
if (!res) return
|
||||||
|
const body = !isEmptyRes ? JSON.parse(d) : d;
|
||||||
|
if (res.status >= 200 && res.status < 300) {
|
||||||
|
ctx.res = body;
|
||||||
|
} else {
|
||||||
|
// 先判断Grpc-Metadata-Errorx-Message
|
||||||
|
let errMsg = res.headers.get('Grpc-Metadata-Errorx-Message');
|
||||||
|
if (errMsg) {
|
||||||
|
errMsg = window?.utf8?.decode(base64.decode(errMsg));
|
||||||
|
// 后判断 body中的message
|
||||||
|
} else if (!errMsg && get(body, 'message')) {
|
||||||
|
errMsg = `${get(body, 'message')}`;
|
||||||
|
} else {
|
||||||
|
// 最后看状态码
|
||||||
|
errMsg = '您的网络发生异常,无法连接服务器';
|
||||||
|
}
|
||||||
|
toast && message.error(errMsg);
|
||||||
|
throw new ResponseError(res, errMsg, d, req, 'CustomError');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (get(error, 'type') !== 'CustomError') {
|
||||||
|
toast && message.error('您的网络发生异常,无法连接服务器');
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export interface OPTION extends RequestOptionsInit {
|
||||||
|
toast?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CGI {
|
||||||
|
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
||||||
|
url: string;
|
||||||
|
baseUrl?: string;
|
||||||
|
data?: { [key: string]: any };
|
||||||
|
useBaseUrl?: boolean;
|
||||||
|
originUrl?: boolean;
|
||||||
|
refererSuffix?: string;
|
||||||
|
}
|
||||||
|
export const doRequest = <T>(cgi: CGI, option?: OPTION): Promise<T> => {
|
||||||
|
const {
|
||||||
|
method,
|
||||||
|
url,
|
||||||
|
baseUrl,
|
||||||
|
data = {},
|
||||||
|
useBaseUrl = true,
|
||||||
|
originUrl = false,
|
||||||
|
refererSuffix = '',
|
||||||
|
} = cgi;
|
||||||
|
const token = localStorage.getItem(User.TOKEN_KEY);
|
||||||
|
const userInfo = localStorage.getItem(User.USER_KEY)
|
||||||
|
? JSON.parse(localStorage.getItem(User.USER_KEY)!)
|
||||||
|
: null;
|
||||||
|
let newUrl = '';
|
||||||
|
if (useBaseUrl) {
|
||||||
|
newUrl = `${baseUrl}${url}`;
|
||||||
|
} else {
|
||||||
|
// 本地Mock -- http://127.0.0.1:4523/m1/2822485-0-default
|
||||||
|
// 7环境gateway -- http://10.0.0.7:32223
|
||||||
|
newUrl = `http://10.0.0.7:32223${url}`; // 7环境进行调试
|
||||||
|
}
|
||||||
|
if (originUrl) {
|
||||||
|
newUrl = url;
|
||||||
|
}
|
||||||
|
// 对于 /:id 类的 url 进行参数填充
|
||||||
|
const regex = /\/:(\w+)/g; // 替换 url 参数
|
||||||
|
const params = [];
|
||||||
|
let matches;
|
||||||
|
while ((matches = regex.exec(newUrl)) != null) {
|
||||||
|
if (matches[1]) {
|
||||||
|
params.push(matches[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
params.forEach(function (name) {
|
||||||
|
let d = data?.[name];
|
||||||
|
if (d == null) {
|
||||||
|
d = '';
|
||||||
|
}
|
||||||
|
newUrl = newUrl.replace(`:${name}`, d);
|
||||||
|
});
|
||||||
|
//通过method 判断解析成data / params
|
||||||
|
const newData = omit(data, params);
|
||||||
|
const paramObj = method.toLowerCase() === 'get' ? { params: newData } : { data: newData };
|
||||||
|
return req(newUrl, {
|
||||||
|
method: method,
|
||||||
|
...paramObj,
|
||||||
|
...option,
|
||||||
|
headers: {
|
||||||
|
authorization: token!,
|
||||||
|
...(refererSuffix ? { zhst_referer: `${baseUrl}${refererSuffix}` } : {}),
|
||||||
|
},
|
||||||
|
}) as Promise<T>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default doRequest;
|
28
packages/types/BigImageModal.d.ts
vendored
Normal file
28
packages/types/BigImageModal.d.ts
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
export enum IBigImageOpt {
|
||||||
|
ADD_CONDITION, //添加目标
|
||||||
|
ADD_TRACK_POINT, //添加到轨迹
|
||||||
|
ADD_HISTORY, //全息检索
|
||||||
|
PLAY_VIDEO, //视频播放按钮
|
||||||
|
ADD_CONDITION_WITH_CROP,
|
||||||
|
ADD_HISTORY_WITH_CROP,
|
||||||
|
SWITCH_DIALOG_MODE,
|
||||||
|
NO_IMAGE_DOWNLOAD_BTN,
|
||||||
|
NO_VIDEO_DOWNLOAD_BTN,
|
||||||
|
ADD_HISTORY_WITH_CROP_BODY, //以人搜人,搜形体
|
||||||
|
ADD_HISTORY_WITH_CROP_VEHICLE, //搜非机动车
|
||||||
|
ADD_STORAGE_RACK, //加入暂存架
|
||||||
|
ADD_HISTORY_WITH_CROP_ARCHIVE, //添加到档案检索
|
||||||
|
ADD_HISTORY_ARCHIVE, //添加到档案检索
|
||||||
|
ADD_ARCHIVE, //添加到档案库
|
||||||
|
CREATE_MONITOR, //创建布控
|
||||||
|
ADD_HISTORY_WITH_CROP_FACE,
|
||||||
|
ADD_HISTORY_WITH_CROP_CAR,
|
||||||
|
BOX_SELECTION,
|
||||||
|
DELETE_TRACK, //删除轨迹
|
||||||
|
ADD_SMART_TRACK_IMAGE, //跳去智能追踪
|
||||||
|
TECHNICAL_WARFARE_APPLICATION, //技战应用
|
||||||
|
PEER_ANALYSIS, //同行人分析
|
||||||
|
FLAG_BY_BACK_SEARCH, //背影搜脸
|
||||||
|
ADD_ARCHIVE_WITH_HK, //添加到档案库
|
||||||
|
ADD_CURRENT_SRARCH, //添加到当前检索(目标检索)
|
||||||
|
}
|
@ -4,12 +4,12 @@
|
|||||||
|
|
||||||
## 安装
|
## 安装
|
||||||
|
|
||||||
> pnpm install @zhst/constants
|
> pnpm install @zhst/types
|
||||||
|
|
||||||
## 使用
|
## 使用
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { TYPE } from '@zhst/constants'
|
import type { User } from '@zhst/types'
|
||||||
|
|
||||||
```
|
```
|
||||||
|
278
packages/types/index.d.ts
vendored
278
packages/types/index.d.ts
vendored
@ -0,0 +1,278 @@
|
|||||||
|
/// <reference path="BigImageModal.d.ts" />
|
||||||
|
export * from './BigImageModal'
|
||||||
|
|
||||||
|
export type CamerasStatusList = [string[], string[], string[]];
|
||||||
|
|
||||||
|
export type Rect = { x: number; y: number; w: number; h: number };
|
||||||
|
|
||||||
|
export type StatusList = {
|
||||||
|
taskOverview: any;
|
||||||
|
taskIndex: {
|
||||||
|
deviceId: string;
|
||||||
|
solutionId: string;
|
||||||
|
};
|
||||||
|
}[];
|
||||||
|
|
||||||
|
export enum OperationType {
|
||||||
|
OPERATION_TYPE_UNKNOW, // 未知状态,传该值会报错
|
||||||
|
OPERATION_TYPE_START,
|
||||||
|
OPERATION_TYPE_STOP
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export enum AlgorithmVersion {
|
||||||
|
VERSION_MGN_BNN, // MGN+BNN算法
|
||||||
|
VERSION_BNN_PRO, // BNNPRO算法
|
||||||
|
VERSION_BNN_PRO_ATTR, // BNNPROATTR算法
|
||||||
|
VERSION_BNN_PRO_ATTR_SCORE, // BNNPROATTR算法
|
||||||
|
VERSION_FACE, // 人脸算法
|
||||||
|
VERSION_HEAD, // 头肩算法
|
||||||
|
VERSION_NON_MOTOR_VEHICLE, // 非机动车的算法
|
||||||
|
VERSION_REID_HEAD_ATTR, // 形体头肩属性三种特征融合的算法
|
||||||
|
VERSION_MOTOR_VEHICLE, // 机动车的算法
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum AlgorithmVersionStr {
|
||||||
|
VERSION_MGN_BNN = 'VERSION_MGN_BNN', // MGN+BNN算法
|
||||||
|
VERSION_BNN_PRO = 'VERSION_BNN_PRO', // BNNPRO算法
|
||||||
|
VERSION_BNN_PRO_ATTR = 'VERSION_BNN_PRO_ATTR', // BNNPROATTR算法
|
||||||
|
VERSION_BNN_PRO_ATTR_SCORE = 'VERSION_BNN_PRO_ATTR_SCORE', // BNNPROATTR算法
|
||||||
|
VERSION_FACE = 'VERSION_FACE', // 人脸算法
|
||||||
|
VERSION_HEAD = 'VERSION_HEAD', // 头肩算法
|
||||||
|
VERSION_NON_MOTOR_VEHICLE = 'VERSION_NON_MOTOR_VEHICLE', // 非机动车的算法
|
||||||
|
VERSION_REID_HEAD_ATTR = 'VERSION_REID_HEAD_ATTR', // 形体头肩属性三种特征融合的算法
|
||||||
|
VERSION_MOTOR_VEHICLE = 'VERSION_MOTOR_VEHICLE', // 机动车的算法
|
||||||
|
}
|
||||||
|
|
||||||
|
类型枚举
|
||||||
|
export enum ObjectType {
|
||||||
|
OBJECT_TYPE_NULL,
|
||||||
|
OBJECT_TYPE_PEDESTRAIN,
|
||||||
|
OBJECT_TYPE_BICYCLE,
|
||||||
|
OBJECT_TYPE_CAR,
|
||||||
|
OBJECT_TYPE_MOTORBIKE,
|
||||||
|
OBJECT_TYPE_AEROPLANE,
|
||||||
|
OBJECT_TYPE_BUS,
|
||||||
|
OBJECT_TYPE_TRAIN,
|
||||||
|
OBJECT_TYPE_TRUCK,
|
||||||
|
OBJECT_TYPE_MOTOR_RIDER,
|
||||||
|
OBJECT_TYPE_BIKE_RIDER,
|
||||||
|
OBJECT_TYPE_MAX,
|
||||||
|
OBJECT_TYPE_FACE = 101,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 性别
|
||||||
|
export enum Gender {
|
||||||
|
GENDER_NONE = 'GENDER_NONE',
|
||||||
|
GENDER_MAN = 'GENDER_MAN',
|
||||||
|
GENDER_WOMAN = 'GENDER_WOMAN',
|
||||||
|
}
|
||||||
|
|
||||||
|
// 年龄
|
||||||
|
export enum Age {
|
||||||
|
AGE_ALL = 'AGE_ALL',
|
||||||
|
AGE_ZERO = 'AGE_ZERO',
|
||||||
|
AGE_OVERENGHTEEN = 'AGE_OVERENGHTEEN',
|
||||||
|
AGE_OVERSIXTY = 'AGE_OVERSIXTY',
|
||||||
|
}
|
||||||
|
|
||||||
|
// 戴帽子状态
|
||||||
|
export enum Hat {
|
||||||
|
HAT_ALL = 'HAT_ALL',
|
||||||
|
HAT_NONE = 'HAT_NONE',
|
||||||
|
HAT_OWNED = 'HAT_OWNED',
|
||||||
|
}
|
||||||
|
|
||||||
|
// 颜色
|
||||||
|
export enum Color {
|
||||||
|
COLOR_ALL = 'COLOR_ALL',
|
||||||
|
COLOR_BLACK = 'COLOR_BLACK',
|
||||||
|
COLOR_WHITE = 'COLOR_WHITE',
|
||||||
|
COLOR_GRAY = 'COLOR_GRAY',
|
||||||
|
COLOR_BROWN = 'COLOR_BROWN',
|
||||||
|
COLOR_PINK = 'COLOR_PINK',
|
||||||
|
COLOR_REDANDORANGE = 'COLOR_REDANDORANGE',
|
||||||
|
COLOR_YELLOW = 'COLOR_YELLOW',
|
||||||
|
COLOR_GREEN = 'COLOR_GREEN',
|
||||||
|
COLOR_BLUE = 'COLOR_BLUE',
|
||||||
|
COLOR_PURPLE = 'COLOR_PURPLE',
|
||||||
|
}
|
||||||
|
|
||||||
|
// 背包
|
||||||
|
export enum Package {
|
||||||
|
PACKAGE_ALL = 'PACKAGE_ALL',
|
||||||
|
PACKAGE_HANDBAG = 'PACKAGE_HANDBAG',
|
||||||
|
PACKAGE_BACKPACK = 'PACKAGE_BACKPACK',
|
||||||
|
PACKAGE_SHOULDERBAG = 'PACKAGE_SHOULDERBAG',
|
||||||
|
PACKAGE_OTHER = 'PACKAGE_OTHER',
|
||||||
|
PACKAGE_NONE = 'PACKAGE_NONE',
|
||||||
|
}
|
||||||
|
|
||||||
|
// 行走模式
|
||||||
|
export enum WalkPattern {
|
||||||
|
WALKPATTERN_ALL = 'WALKPATTERN_ALL',
|
||||||
|
WALKPATTERN_WALK = 'WALKPATTERN_WALK',
|
||||||
|
WALKPATTERN_RIDING = 'WALKPATTERN_RIDING',
|
||||||
|
}
|
||||||
|
|
||||||
|
// 人类属性
|
||||||
|
export interface HumanProperty {
|
||||||
|
age: Age;
|
||||||
|
downColor: Color;
|
||||||
|
gender: Gender;
|
||||||
|
hat: Hat;
|
||||||
|
package: Package;
|
||||||
|
upColor: Color;
|
||||||
|
walkPattern: WalkPattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 人类属性枚举
|
||||||
|
export interface EnumHumanProperty {
|
||||||
|
Gender: typeof Gender;
|
||||||
|
Age: typeof Age;
|
||||||
|
Hat: typeof Hat;
|
||||||
|
Color: typeof Color;
|
||||||
|
Package: typeof Package;
|
||||||
|
WalkPattern: typeof WalkPattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IScreenshotButtonProp {
|
||||||
|
model: 'VIDEO' | 'IMAGE';
|
||||||
|
getCropInfo: () => Promise<RESP>;
|
||||||
|
setShowCrop: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
|
cropType: typeof cropType[number];
|
||||||
|
selectAlgorithmVersion: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AlignType {
|
||||||
|
/**
|
||||||
|
* move point of source node to align with point of target node.
|
||||||
|
* Such as ['tr','cc'], align top right point of source node with center point of target node.
|
||||||
|
* Point can be 't'(top), 'b'(bottom), 'c'(center), 'l'(left), 'r'(right) */
|
||||||
|
points?: AlignPoint[];
|
||||||
|
/**
|
||||||
|
* offset source node by offset[0] in x and offset[1] in y.
|
||||||
|
* If offset contains percentage string value, it is relative to sourceNode region.
|
||||||
|
*/
|
||||||
|
offset?: number[];
|
||||||
|
/**
|
||||||
|
* offset target node by offset[0] in x and offset[1] in y.
|
||||||
|
* If targetOffset contains percentage string value, it is relative to targetNode region.
|
||||||
|
*/
|
||||||
|
targetOffset?: number[];
|
||||||
|
/**
|
||||||
|
* If adjustX field is true, will adjust source node in x direction if source node is invisible.
|
||||||
|
* If adjustY field is true, will adjust source node in y direction if source node is invisible.
|
||||||
|
*/
|
||||||
|
overflow?: {
|
||||||
|
adjustX?: boolean | number;
|
||||||
|
adjustY?: boolean | number;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Whether use css right instead of left to position
|
||||||
|
*/
|
||||||
|
useCssRight?: boolean;
|
||||||
|
/**
|
||||||
|
* Whether use css bottom instead of top to position
|
||||||
|
*/
|
||||||
|
useCssBottom?: boolean;
|
||||||
|
/**
|
||||||
|
* Whether use css transform instead of left/top/right/bottom to position if browser supports.
|
||||||
|
* Defaults to false.
|
||||||
|
*/
|
||||||
|
useCssTransform?: boolean;
|
||||||
|
ignoreShake?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ODRECT = {
|
||||||
|
topleft: {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
};
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface ViewOption {
|
||||||
|
/* 图片url */
|
||||||
|
image?: string | HTMLImageElement;
|
||||||
|
|
||||||
|
/* 缩放灵敏度(0,1],default: 0.1 */
|
||||||
|
wheelZoomRatio?: number;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 是否允许缩放
|
||||||
|
* @default: true
|
||||||
|
*/
|
||||||
|
scaleAble?: boolean;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 是否允许拖拽
|
||||||
|
* @default: true
|
||||||
|
*/
|
||||||
|
dragAble?: boolean;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fit scale 作为 最小缩放
|
||||||
|
* @default: false
|
||||||
|
*/
|
||||||
|
fitScaleAsMinScale?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type IOdRectOrigin {
|
||||||
|
objectIndex: {
|
||||||
|
objectId: string
|
||||||
|
solutionId: string
|
||||||
|
deviceId: string
|
||||||
|
fragmentId: string
|
||||||
|
}
|
||||||
|
objectType: ObjectType,
|
||||||
|
sourceObjectId: string,
|
||||||
|
level: string
|
||||||
|
confidence: string | number,
|
||||||
|
pathInfo: any,
|
||||||
|
frameInfo: {
|
||||||
|
frameId: string
|
||||||
|
frameTimestamp: string | number
|
||||||
|
width: number
|
||||||
|
height: number
|
||||||
|
originWidth: number
|
||||||
|
originHeight: number
|
||||||
|
offsetTime: number
|
||||||
|
skipNumber: number
|
||||||
|
},
|
||||||
|
deviceInfo: any
|
||||||
|
infoOnSource:{
|
||||||
|
bboxInSource:any
|
||||||
|
bboxInFrame: {
|
||||||
|
bbox: any,
|
||||||
|
bboxRatio: Rect
|
||||||
|
extendBbox: any
|
||||||
|
extendBoxRatio: number
|
||||||
|
},
|
||||||
|
countInSource: any
|
||||||
|
indexInSource: any
|
||||||
|
},
|
||||||
|
qualityScore: number
|
||||||
|
frameImage: any
|
||||||
|
objectImage: any
|
||||||
|
objectExtImage: any
|
||||||
|
feature: {
|
||||||
|
name: string
|
||||||
|
type: ObjectType,
|
||||||
|
featureId: number
|
||||||
|
featureByte: string
|
||||||
|
featureBool:any[]
|
||||||
|
featureUint8: any[]
|
||||||
|
featureUint16: any[]
|
||||||
|
featureUint32: any[]
|
||||||
|
featureUint64: any[]
|
||||||
|
featureInt8: any[]
|
||||||
|
featureInt16: any[]
|
||||||
|
featureInt32: any[]
|
||||||
|
featureInt64: any[]
|
||||||
|
featureFloat32: any[]
|
||||||
|
featureString: any[]
|
||||||
|
}
|
||||||
|
subObjects: any[]
|
||||||
|
}
|
@ -11,13 +11,15 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"author": "dev",
|
"author": "dev",
|
||||||
"main": "",
|
"main": "",
|
||||||
"typings": "es/index.d.ts",
|
"typings": "index.d.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"types": {
|
"types": {
|
||||||
"default": "./index.d.ts"
|
"default": "./index.d.ts"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"./user": "./user.d.ts",
|
||||||
|
"./BigImageModal": "./BigImageModal.d.ts",
|
||||||
"./package.json": "./package.json"
|
"./package.json": "./package.json"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
nav:
|
nav:
|
||||||
title: types
|
title: 类型定义
|
||||||
order: 1
|
order: 99
|
||||||
title: 快速上手
|
title: 快速上手
|
||||||
---
|
---
|
||||||
|
|
||||||
|
4
packages/types/user.d.ts
vendored
Normal file
4
packages/types/user.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export enum User {
|
||||||
|
TOKEN_KEY = 'USER-TOKEN',
|
||||||
|
USER_KEY = 'USER'
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user