Merge branch 'dev' of github.com:jetlinks/jetlinks-ui-vue into dev

This commit is contained in:
leiqiaochu 2023-03-02 20:44:11 +08:00
commit 94cbb42173
81 changed files with 9280 additions and 886 deletions

6368
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,7 @@
"version": "0.0.0",
"scripts": {
"dev": "vite --mode develop",
"dev:force": "vite --force --mode develop",
"build": "node --max_old_space_size=1024000 ./node_modules/vite/bin/vite.js build",
"preview": "vite preview",
"eslint": "eslint --ext .js,.vue --ignore-path .gitignore --fix src",
@ -23,7 +24,7 @@
"event-source-polyfill": "^1.0.31",
"global": "^4.4.0",
"jetlinks-store": "^0.0.3",
"jetlinks-ui-components": "^1.0.0",
"jetlinks-ui-components": "^1.0.1",
"js-cookie": "^3.0.1",
"less": "^4.1.3",
"less-loader": "^11.1.0",
@ -35,12 +36,15 @@
"pinia": "^2.0.28",
"unplugin-auto-import": "^0.12.1",
"unplugin-vue-components": "^0.22.12",
"v-clipboard3": "^0.1.4",
"vite-plugin-monaco-editor": "^1.1.0",
"vue": "^3.2.45",
"vue-json-viewer": "^3.0.4",
"vue-router": "^4.1.6",
"vue3-json-viewer": "^2.2.2",
"vue3-markdown-it": "^1.0.10",
"vue3-ts-jsoneditor": "^2.7.1"
"vue3-ts-jsoneditor": "^2.7.1",
"vue3-video-play": "^1.3.1-beta.6"
},
"devDependencies": {
"@commitlint/cli": "^17.4.1",

View File

@ -0,0 +1,22 @@
import server from '@/utils/request'
// 获取记录列表
export const getList_api = (data:object): any =>server.get(`/notifications/_query`,encodeParams(data))
// 修改记录状态
export const changeStatus_api = (type:'_read'|'_unread',data:string[]): any =>server.post(`/notifications/${type}`,data)
const encodeParams = (params: Record<string, any>) => {
let result = {}
for (const key in params) {
if (Object.prototype.hasOwnProperty.call(params, key)) {
const value = params[key];
if(key === 'terms') {
result['terms[0].column:'] = 0
result['terms[0].value'] = JSON.stringify(value[0])
}else result[key] = value
}
}
return result
};

View File

@ -0,0 +1,22 @@
import server from '@/utils/request'
// 获取通知订阅列表
export const getNoticeList_api = () => server.post(`/notifications/subscriptions/_query/`);
// 保存通知订阅
export const save_api = (data:any) => server.patch(`/notifications/subscribe`, data);
// 保存通知订阅
export const remove_api = (id:string) => server.remove(`/notifications/subscription/${id}`);
/**
*
* @param id id
* @param status
*/
export const changeStatus_api = (id: string, status: '_disabled' | '_enabled') => server.put(`/notifications/subscription/${id}/${status}`);
// 获取订阅类型
export const getTypeList_api = () => server.get(`/notifications/providers`);
// 获取告警规则列表
export const getAlarmList_api = () => server.post(`/alarm/config/_query/no-paging`, {
sorts: [{ name: 'createTime', order: 'desc' }],
paging: false,
});

View File

@ -1,4 +1,6 @@
import server from '@/utils/request'
import server from '@/utils/request';
import { LocalStore } from '@/utils/comm';
import { BASE_API_PATH, TOKEN_KEY } from '@/utils/variable';
export default {
// 列表
@ -12,5 +14,54 @@ export default {
// 修改
update: (id: string, data: any) => server.put(`/media/channel/${id}`, data),
// 删除
del: (id: string) => server.remove(`media/channel/${id}`),
del: (id: string) => server.remove(`/media/channel/${id}`),
// ========== 视频播放 ==========
// 开始直播
ptzStart: (deviceId: string, channelId: string, type: string) =>
`${BASE_API_PATH}/media/device/${deviceId}/${channelId}/live.${type}?:X_Access_Token=${LocalStore.get(TOKEN_KEY)}`,
// 云台控制-停止
ptzStop: (deviceId: string, channelId: string) => server.post(`/media/device/${deviceId}/${channelId}/_ptz/STOP`),
// 云台控制-缩放、转向等
ptzTool: (deviceId: string, channelId: string, direct: string, speed: number = 90) =>
server.post(`/media/device/${deviceId}/${channelId}/_ptz/${direct}/${speed}`),
// 重置
mediaStop: (deviceId: string, channelId: string) => server.post(`/media/device/${deviceId}/${channelId}/_stop`),
// 查询是否正在录像
ptzIsRecord: (deviceId: string, channelId: string) => server.get(`/media/device/${deviceId}/${channelId}/live/recording`),
// 开始录像
recordStart: (deviceId: string, channelId: string, data: any) =>
server.post(`/media/device/${deviceId}/${channelId}/_record`, data),
// 停止录像
recordStop: (deviceId: string, channelId: string, data: any) =>
server.post(`/media/device/${deviceId}/${channelId}/_stop-record`, data),
// 查询本地回放记录
queryRecordLocal: (deviceId: string, channelId: string, data: any) =>
server.post(`/media/device/${deviceId}/${channelId}/records/in-local`, data),
// 播放本地回放
playbackLocal: (deviceId: string, channelId: string, suffix: string) =>
server.get(`/media/device/${deviceId}/${channelId}/playback.${suffix}`),
// 本地录像播放控制
playbackControl: (deviceId: string, channelId: string) =>
server.post(`/media/device/${deviceId}/${channelId}/stream-control`),
// 查询云端回放记录
recordsInServer: (deviceId: string, channelId: string) =>
server.post(`/media/device/${deviceId}/${channelId}/records/in-server`),
// 查询云端回放文件信息
recordsInServerFiles: (deviceId: string, channelId: string) =>
server.post(`/media/device/${deviceId}/${channelId}/records/in-server/files`),
// 播放云端回放
playbackStart: (recordId: string) => server.get(`/media/record/${recordId}.mp4`),
}

View File

@ -34,5 +34,9 @@ export default {
// 微信绑定用户
weChatBindUser: (data: any, id: string) => patch(`/user/third-party/weixin_corpMessage/${id}`, data),
// 解绑
unBindUser: (data: any, id: string) => post(`/user/third-party/${id}/_unbind`, data)
unBindUser: (data: any, id: string) => post(`/user/third-party/${id}/_unbind`, data),
//通知类型
queryMessageType: () => get(`/notifier/config/types`),
// 不分页-列表
queryListNoPaging: (data: any) => post(`/notifier/config/_query/no-paging?paging=false`, data)
}

View File

@ -23,5 +23,6 @@ export default {
// 语音/短信获取阿里云模板
getAliTemplate: (id: any) => get(`/notifier/sms/aliyun/${id}/templates`),
// 短信获取签名
getSigns: (id: any) => get(`/notifier/sms/aliyun/${id}/signs`)
getSigns: (id: any) => get(`/notifier/sms/aliyun/${id}/signs`),
getListByConfigId: (id: string, data: any): any => post(`/notifier/template/${id}/_query`, data),
}

View File

@ -64,6 +64,12 @@ const iconKeys = [
'ToolOutlined',
'FileOutlined',
'LikeOutlined',
'CaretUpOutlined',
'CaretRightOutlined',
'CaretLeftOutlined',
'CaretDownOutlined',
'MinusOutlined',
'AudioOutlined',
]
const Icon = (props: {type: string}) => {

View File

@ -1,8 +1,8 @@
<template>
<a-badge
<j-badge
:status="statusNames ? statusNames[status] : 'default'"
:text="text"
></a-badge>
></j-badge>
</template>
<script setup lang="ts">

View File

@ -21,7 +21,7 @@
<!-- 勾选 -->
<div v-if="active" class="checked-icon">
<div>
<CheckOutlined />
<AIcon type="CheckOutlined" />
</div>
</div>
@ -62,24 +62,6 @@
}"
>
<slot name="actions" v-bind="item"></slot>
<!-- <a-popconfirm v-if="item.popConfirm" v-bind="item.popConfirm">
<a-button :disabled="item.disabled">
<DeleteOutlined v-if="item.key === 'delete'" />
<template v-else>
<AIcon :type="item.icon" />
<span>{{ item.text }}</span>
</template>
</a-button>
</a-popconfirm>
<template v-else>
<a-button :disabled="item.disabled">
<DeleteOutlined v-if="item.key === 'delete'" />
<template v-else>
<AIcon :type="item.icon" />
<span>{{ item.text }}</span>
</template>
</a-button>
</template> -->
</div>
</div>
</slot>
@ -87,13 +69,7 @@
</template>
<script setup lang="ts">
import {
SearchOutlined,
CheckOutlined,
DeleteOutlined,
} from '@ant-design/icons-vue';
import BadgeStatus from '@/components/BadgeStatus/index.vue';
import { StatusColorEnum } from '@/utils/consts.ts';
import type { ActionsType } from '@/components/Table/index.vue';
import { PropType } from 'vue';

View File

@ -1,54 +1,54 @@
<template>
<template v-if="isPermission">
<template v-if="popConfirm">
<a-popconfirm v-bind="popConfirm" :disabled="!isPermission || props.disabled">
<a-tooltip v-if="tooltip" v-bind="tooltip">
<j-popconfirm v-bind="popConfirm" :disabled="!isPermission || props.disabled">
<j-tooltip v-if="tooltip" v-bind="tooltip">
<slot v-if="noButton"></slot>
<a-button v-else v-bind="props" :disabled="_isPermission" :style="props.style">
<j-button v-else v-bind="props" :disabled="_isPermission" :style="props.style">
<slot></slot>
<template #icon>
<slot name="icon"></slot>
</template>
</a-button>
</a-tooltip>
<a-button v-else v-bind="props" :disabled="_isPermission" >
</j-button>
</j-tooltip>
<j-button v-else v-bind="props" :disabled="_isPermission" >
<slot></slot>
<template #icon>
<slot name="icon"></slot>
</template>
</a-button>
</a-popconfirm>
</j-button>
</j-popconfirm>
</template>
<template v-else-if="tooltip">
<a-tooltip v-bind="tooltip">
<j-tooltip v-bind="tooltip">
<slot v-if="noButton"></slot>
<a-button v-else v-bind="props" :disabled="_isPermission" :style="props.style">
<j-button v-else v-bind="props" :disabled="_isPermission" :style="props.style">
<slot></slot>
<template #icon>
<slot name="icon"></slot>
</template>
</a-button>
</a-tooltip>
</j-button>
</j-tooltip>
</template>
<template v-else>
<slot v-if="noButton"></slot>
<a-button v-else v-bind="props" :disabled="_isPermission" :style="props.style">
<j-button v-else v-bind="props" :disabled="_isPermission" :style="props.style">
<slot></slot>
<template #icon>
<slot name="icon"></slot>
</template>
</a-button>
</j-button>
</template>
</template>
<a-tooltip v-else title="没有权限">
<j-tooltip v-else title="没有权限">
<slot v-if="noButton"></slot>
<a-button v-else v-bind="props" :disabled="_isPermission" :style="props.style">
<j-button v-else v-bind="props" :disabled="_isPermission" :style="props.style">
<slot></slot>
<template #icon>
<slot name="icon"></slot>
</template>
</a-button>
</a-tooltip>
</j-button>
</j-tooltip>
</template>
<script setup lang="ts" name="PermissionButton">
import { CSSProperties, PropType } from 'vue'

View File

@ -0,0 +1,50 @@
<!-- 视频播放 -->
<template>
<vue3videoPlay v-bind="options" />
</template>
<script setup lang="ts">
import 'vue3-video-play/dist/style.css';
import vue3videoPlay from 'vue3-video-play';
const props = defineProps({
src: { type: String, default: '' },
type: { type: String, default: 'mp4' },
});
watch(
() => props.src,
(val: string) => {
options.src = val;
},
);
const options = reactive({
...props,
width: '500px', //
height: '280px', //
color: '#409eff', //
title: '', //
// src: props.src,
// type: props.type,
muted: false, //
webFullScreen: false,
speedRate: ['0.75', '1.0', '1.25', '1.5', '2.0'], //
autoPlay: true, //
loop: false, //
mirror: false, //
ligthOff: false, //
volume: 0.3, //
control: true, //
controlBtns: [
'audioTrack',
'quality',
'speedRate',
'volume',
'setting',
'pip',
'pageFullScreen',
'fullScreen',
], //,
});
</script>

View File

@ -0,0 +1,128 @@
.live-player-tools {
display: flex;
flex-basis: 250px;
flex-direction: column;
justify-content: center;
margin-left: 24px;
padding: 0 12px;
.direction {
position: relative;
display: grid;
grid-gap: 2px;
grid-template-rows: 1fr 1fr;
grid-template-columns: 1fr 1fr;
margin-bottom: 30px;
overflow: hidden;
border-radius: 50%;
transform: rotateZ(45deg);
.direction-item {
position: relative;
display: flex;
align-items: center;
justify-content: center;
padding-bottom: 100%;
font-size: 36px;
background-color: rgba(#000, 0.1);
transition: background-color 0.3s;
.direction-icon {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotateZ(-45deg);
}
}
.direction-audio {
position: absolute;
top: 50%;
left: 50%;
display: flex;
align-items: center;
justify-content: center;
width: 45%;
height: 45%;
font-size: 30px;
background-color: #fff;
border-radius: 50%;
transform: translate(-50%, -50%) rotateZ(-45deg);
}
.zoom .zoom-item,
& .direction-item {
&:hover {
color: #fff;
background-color: @primary-color-hover;
}
&:active {
color: #fff;
background-color: @primary-color-active;
}
}
> div {
cursor: pointer;
&.disable {
color: @disabled-color;
}
}
}
.zoom {
display: grid;
grid-gap: 2px;
grid-template-columns: 1fr 1fr;
.zoom-item {
padding: 8px 0;
font-size: 24px;
text-align: center;
background-color: rgba(#000, 0.1);
cursor: pointer;
&:hover {
color: #fff;
background-color: @primary-color-hover;
}
&:active {
color: #fff;
background-color: @primary-color-active;
}
}
.zoom-in {
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.zoom-out {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
}
}
@media screen {
@media (min-width: 1300px) {
.live-player-tools {
flex-basis: 150px;
margin-left: 16px;
.direction {
.direction-item {
font-size: 24px;
}
}
.zoom {
.zoom-item {
font-size: 16px;
}
}
}
}
}

View File

@ -0,0 +1,66 @@
<!-- 视频播放工具栏 -->
<template>
<div class="live-player-tools">
<div class="direction">
<div
class="direction-item up"
@mousedown="emit('onMouseDown', 'UP')"
@mouseup="emit('onMouseUp', 'UP')"
>
<AIcon class="direction-icon" type="CaretUpOutlined" />
</div>
<div
class="direction-item right"
@mousedown="emit('onMouseDown', 'RIGHT')"
@mouseup="emit('onMouseUp', 'RIGHT')"
>
<AIcon class="direction-icon" type="CaretRightOutlined" />
</div>
<div
class="direction-item left"
@mousedown="emit('onMouseDown', 'LEFT')"
@mouseup="emit('onMouseUp', 'LEFT')"
>
<AIcon class="direction-icon" type="CaretLeftOutlined" />
</div>
<div
class="direction-item down"
@mousedown="emit('onMouseDown', 'DOWN')"
@mouseup="emit('onMouseUp', 'DOWN')"
>
<AIcon class="direction-icon" type="CaretDownOutlined" />
</div>
<div class="direction-audio">
<!-- <AIcon type="AudioOutlined" /> -->
</div>
</div>
<div class="zoom">
<div
class="zoom-item zoom-in"
@mousedown="emit('onMouseDown', 'ZOOM_IN')"
@mouseup="emit('onMouseUp', 'ZOOM_IN')"
>
<AIcon type="PlusOutlined" />
</div>
<div
class="zoom-item zoom-out"
@mousedown="emit('onMouseDown', 'ZOOM_OUT')"
@mouseup="emit('onMouseUp', 'ZOOM_OUT')"
>
<AIcon type="MinusOutlined" />
</div>
</div>
</div>
</template>
<script setup lang="ts">
type Emits = {
(e: 'onMouseDown', type: string): void;
(e: 'onMouseUp', type: string): void;
};
const emit = defineEmits<Emits>();
</script>
<style lang="less" scoped>
@import './mediaTool.less';
</style>

View File

@ -337,6 +337,14 @@ const JTable = defineComponent<JTableProps>({
rowSelection={props.rowSelection}
scroll={props.scroll}
v-slots={{
headerCell: (dt: Record<string, any>) => {
const { column, title } = dt;
if (column?.headerCell) {
return slots?.[column?.headerCell]!(column.title)
} else {
return title || ''
}
},
bodyCell: (dt: Record<string, any>) => {
const { column, record } = dt;
if ((column?.key || column?.dataIndex) && column?.scopedSlots && (slots?.[column?.dataIndex] || slots?.[column?.key])) {

View File

@ -31,7 +31,14 @@ export default [
path: '/account/center',
component: () => import('@/views/account/Center/index.vue')
},
{
path: '/account/NotificationSubscription',
component: () => import('@/views/account/NotificationSubscription/index.vue')
},
{
path: '/account/NotificationRecord',
component: () => import('@/views/account/NotificationRecord/index.vue')
},
// end: 测试用, 可删除
// 初始化

View File

@ -1,4 +1,14 @@
import { isObject } from 'lodash-es'
import { isObject, isArray } from 'lodash-es'
const encodeParams = (params: Record<string, any>) => {
const _params = new URLSearchParams()
for (const key in params) {
const _value = params[key]
const isArrOrObj = isObject(_value) || isArray(_value)
_params.set(key, isArrOrObj ? encodeParams(_value) : _value)
}
return _params.toString()
}
export default function encodeQuery(params: any) {
if (!params) return {};

View File

@ -6,11 +6,12 @@
width="770px"
@cancel="emits('update:visible', false)"
>
<a-form :model="form" layout="vertical">
<a-form :model="form" layout="vertical" ref="formRef">
<a-row :gutter="24">
<a-col :span="12">
<a-form-item
label="姓名"
name="name"
:rules="[{ required: true, message: '姓名必填' }]"
>
<a-input
@ -78,6 +79,7 @@
<script setup lang="ts">
import { updateMeInfo_api } from '@/api/account/center';
import { message } from 'ant-design-vue';
import { FormInstance } from 'ant-design-vue/es';
import { userInfoType } from '../typing';
const emits = defineEmits(['ok', 'update:visible']);
@ -86,14 +88,16 @@ const props = defineProps<{
data: userInfoType;
}>();
const form = ref(props.data);
const formRef = ref<FormInstance>();
const handleOk = () => {
updateMeInfo_api(form.value).then((resp) => {
if (resp.status === 200) {
message.success('保存成功');
emits('ok');
emits('update:visible', false);
}
formRef.value?.validate().then(() => {
updateMeInfo_api(form.value).then((resp) => {
if (resp.status === 200) {
message.success('保存成功');
emits('ok');
emits('update:visible', false);
}
});
});
};
</script>

View File

@ -118,13 +118,13 @@ const handleOk = () => {
oldPassword: form.value.oldPassword,
newPassword: form.value.newPassword,
};
// updateMepsd_api(params).then((resp) => {
// if (resp.status === 200) {
// message.success('');
// emits('ok');
// emits('update:visible', false);
// }
// });
updateMepsd_api(params).then((resp) => {
if (resp.status === 200) {
message.success('保存成功');
emits('ok');
emits('update:visible', false);
}
});
});
};
console.clear();

View File

@ -51,7 +51,7 @@
</div>
<div class="info-card">
<p>注册时间</p>
<p>{{ userInfo.createTime }}</p>
<p>{{ moment(userInfo.createTime).format('YYYY-MM-DD HH:mm:ss') }}</p>
</div>
<div class="info-card">
<p>电话</p>
@ -216,7 +216,7 @@
</page-container>
</template>
<script setup lang="ts">
<script setup lang="ts" name="Center">
import PermissionButton from '@/components/PermissionButton/index.vue';
import EditInfoDialog from './components/EditInfoDialog.vue';
import EditPasswordDialog from './components/EditPasswordDialog.vue';

View File

@ -0,0 +1,86 @@
<template>
<a-modal
visible
title="详情"
width="1000px"
@ok="emits('update:visible', false)"
@cancel="emits('update:visible', false)"
>
<a-row v-if="data?.targetType === 'device'">
<a-col :span="6" class="label">告警设备</a-col>
<a-col :span="6" class="value">
{{ data?.targetName || '' }}
</a-col>
<a-col :span="6" class="label">设备ID</a-col>
<a-col :span="6" class="value">
{{ data?.targetId || '' }}
</a-col>
</a-row>
<a-row>
<a-col :span="6" class="label">告警名称</a-col>
<a-col :span="6" class="value">
{{ data?.alarmName || data?.alarmConfigName || '' }}
</a-col>
<a-col :span="6" class="label">告警时间</a-col>
<a-col :span="6" class="value">
{{ moment(data?.alarmTime).format('YYYY-MM-DD HH:mm:ss') }}
</a-col>
<a-col :span="6" class="label">告警级别</a-col>
<a-col :span="6" class="value">
{{ (levelList.length > 0 && getLevelLabel(data.level)) || '' }}
</a-col>
<a-col :span="6" class="label">告警说明</a-col>
<a-col :span="6" class="value">{{ data?.description || '' }}</a-col>
<a-col :span="6" class="label">告警流水</a-col>
<a-col :span="18" class="value">
<!-- <MonacoEditor
style="width: 100%; height: 370px"
theme="vs"
v-model="jsonData"
/> -->
<JsonViewer :value="jsonData" copyable boxed sort />
</a-col>
</a-row>
</a-modal>
</template>
<script setup lang="ts">
import MonacoEditor from '@/components/MonacoEditor/index.vue';
import {JsonViewer} from 'vue3-json-viewer';
import { queryLevel as queryLevel_api } from '@/api/rule-engine/config';
import moment from 'moment';
const emits = defineEmits(['update:visible']);
const props = defineProps<{
visible: boolean;
data: any;
}>();
const levelList = ref<any[]>([]);
const data = computed(() => {
if (props.data.detailJson) return JSON.parse(props.data.detailJson);
else return props.data?.detail || props.data;
});
const getLevel = () => {
queryLevel_api().then((resp: any) => {
if (resp.status === 200) levelList.value = resp.result.levels;
});
};
getLevel();
const getLevelLabel = (id: string) => {
if (levelList.value.length < 1 || !id) return '';
const obj = levelList.value.find((item) => item.id === id);
return obj.title;
};
const jsonData = JSON.stringify({
name: 'qiu',
age: 18,
isMan: false,
arr: [1, 2, 5],
});
</script>
<style scoped></style>

View File

@ -0,0 +1,212 @@
<template>
<page-container>
<div class="notification-record-container">
<Search :columns="columns" @search="query.search" />
<JTable
ref="tableRef"
:columns="columns"
:request="getList_api"
model="TABLE"
:params="query.params.value"
:defaultParams="{
'sorts[0].name': 'notifyTime',
'sorts[0].order': 'desc',
}"
>
<template #topicProvider="slotProps">
{{ slotProps.topicName }}
</template>
<template #notifyTime="slotProps">
{{
moment(slotProps.notifyTime).format(
'YYYY-MM-DD HH:mm:ss',
)
}}
</template>
<template #state="slotProps">
<BadgeStatus
:status="slotProps.state.value"
:text="slotProps.state.text"
:statusNames="{
read: 'success',
unread: 'error',
}"
></BadgeStatus>
</template>
<template #action="slotProps">
<a-space :size="16">
<PermissionButton
type="link"
:popConfirm="{
title: `确认标为${
slotProps.state.value === 'read'
? '未读'
: '已读'
}`,
onConfirm: () => table.changeStatus(slotProps),
}"
:tooltip="{
title:
slotProps.state.value === 'read'
? '标为未读'
: '标为已读',
}"
>
<AIcon type="ReadIconOutlined" />
<!-- <svg
width="1em"
height="1em"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 18H6L2 22V2C2 2 2.9 2 4 2H20C21.1 2 22 2 22 2V11H20V4H4V16H12V18ZM23 14.34L21.59 12.93L17.35 17.17L15.23 15.05L13.82 16.46L17.34 20L23 14.34Z"
fill="currentColor"
/>
</svg> -->
</PermissionButton>
<PermissionButton
type="link"
:tooltip="{
title: '查看',
}"
@click="table.view(slotProps)"
>
<AIcon type="SearchOutlined" />
</PermissionButton>
</a-space>
</template>
</JTable>
<ViewDialog v-if="viewVisible" v-model:visible="viewVisible" :data="viewItem" />
</div>
</page-container>
</template>
<script setup lang="ts" name="NotificationRecord">
import ViewDialog from './components/ViewDialog.vue';
import PermissionButton from '@/components/PermissionButton/index.vue';
import {
getList_api,
changeStatus_api,
} from '@/api/account/notificationRecord';
import { getTypeList_api } from '@/api/account/notificationSubscription';
import { optionItem } from '@/views/rule-engine/Scene/typings';
import { dictItemType } from '@/views/system/DataSource/typing';
import moment from 'moment';
import { message } from 'ant-design-vue';
const columns = [
{
title: '类型',
dataIndex: 'topicProvider',
key: 'topicProvider',
search: {
type: 'select',
options: () =>
getTypeList_api().then((resp: any) =>
resp.result
.map((item: dictItemType) => ({
label: item.name,
value: item.id,
}))
.filter((item: optionItem) => item.value === 'alarm'),
),
},
scopedSlots: true,
ellipsis: true,
},
{
title: '消息',
dataIndex: 'message',
key: 'message',
search: {
type: 'string',
},
scopedSlots: true,
ellipsis: true,
},
{
title: '通知时间',
dataIndex: 'notifyTime',
key: 'notifyTime',
search: {
type: 'date',
},
scopedSlots: true,
ellipsis: true,
},
{
title: '状态',
dataIndex: 'state',
key: 'state',
search: {
type: 'select',
options: [
{
label: '未读',
value: 'unread',
},
{
label: '已读',
value: 'read',
},
],
},
scopedSlots: true,
ellipsis: true,
},
{
title: '操作',
dataIndex: 'action',
key: 'action',
ellipsis: true,
scopedSlots: true,
},
];
const query = {
params: ref({}),
search: (params: object) => {
query.params.value = { ...params };
},
};
const tableRef = ref();
const table = {
changeStatus: (row: any) => {
const type = row.state.value === 'read' ? '_unread' : '_read';
changeStatus_api(type, [row.id]).then((resp: any) => {
if (resp.status === 200) {
message.success('操作成功!');
table.refresh();
}
});
},
view: (row: any) => {
viewItem.value = row;
viewVisible.value = true;
},
refresh: () => {
tableRef.value && tableRef.value.reload();
},
};
const viewVisible = ref<boolean>(false);
const viewItem = ref<any>({});
</script>
<style lang="less" scoped>
.notification-record-container {
:deep(.ant-table-tbody) {
.ant-table-cell {
.ant-space-item {
.ant-btn-link {
padding: 0;
}
}
}
}
}
</style>

View File

@ -0,0 +1,150 @@
<template>
<a-modal
visible
:title="props.data.id ? '编辑' : '新增'"
width="865px"
@ok="confirm"
@cancel="emits('update:visible', false)"
>
<a-form :model="form" layout="vertical" ref="formRef">
<a-form-item
label="名称"
name="subscribeName"
:rules="[
{ required: true, message: '请输入名称' },
{
max: 64,
message: '最多可输入64个字符',
},
]"
>
<a-input
v-model:value="form.subscribeName"
placeholder="请输入名称"
/>
</a-form-item>
<a-row :gutter="24">
<a-col :span="12">
<a-form-item
label="类型"
name="topicProvider"
:rules="[{ required: true, message: '请选择类型' }]"
>
<a-select
v-model:value="form.topicProvider"
placeholder="请选择类型"
:options="typeList"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item
label="告警规则"
:name="['topicConfig', 'alarmConfigId']"
:rules="[{ required: true, message: '请选择告警规则' }]"
>
<a-select
:value="form.topicConfig.alarmConfigId?.split(',')"
:options="alarmList"
placeholder="请选择告警规则"
mode="multiple"
@change="onSelect"
></a-select>
</a-form-item>
</a-col>
</a-row>
<a-form-item
name="notice"
label="通知方式"
:rules="[{ required: true, message: '请选择通知方式' }]"
>
<a-checkbox-group
v-model:value="form.notice"
name="checkboxgroup"
:options="[
{
label: '站内通知',
value: 1,
},
]"
/>
</a-form-item>
</a-form>
</a-modal>
</template>
<script setup lang="ts">
import { rowType } from '../typing';
import {
getTypeList_api,
getAlarmList_api,
save_api,
} from '@/api/account/notificationSubscription';
import { optionsType } from '@/views/system/Department/typing';
import { dictItemType } from '@/views/system/DataSource/typing';
import { optionItem } from '@/views/rule-engine/Scene/typings';
import { FormInstance, message } from 'ant-design-vue';
const emits = defineEmits(['ok', 'update:visible']);
const props = defineProps<{
visible: boolean;
data: rowType;
}>();
const initForm = {
subscribeName: '',
topicConfig: {},
notice: [1],
};
const formRef = ref<FormInstance>();
const form = ref({
...initForm,
...props.data,
});
const confirm = () => {
formRef.value &&
formRef.value.validate().then(() => {
save_api(form.value).then((resp) => {
if (resp.status === 200) {
message.success('操作成功');
emits('ok')
emits('update:visible', false);
}
});
});
};
const typeList = ref<optionsType>([]);
const alarmList = ref<optionsType>([]);
init();
function init() {
getTypeList_api().then((resp: any) => {
if (resp.status === 200)
typeList.value = resp.result
.map((item: dictItemType) => ({
label: item.name,
value: item.id,
}))
.filter((item: optionItem) => item.value === 'alarm');
});
getAlarmList_api().then((resp: any) => {
if (resp.status === 200)
alarmList.value = resp.result.map((item: dictItemType) => ({
label: item.name,
value: item.id,
}));
});
}
function onSelect(keys: string[], items: optionsType) {
form.value.topicConfig = {
alarmConfigId: keys.join(','),
alarmConfigName: items.map((item) => item.label).join(','),
};
}
</script>
<style scoped></style>

View File

@ -0,0 +1,203 @@
<template>
<page-container>
<div class="notification-subscription-container">
<Search :columns="columns" @search="query.search" />
<JTable
ref="tableRef"
:columns="columns"
:request="getNoticeList_api"
model="TABLE"
:params="query.params.value"
:defaultParams="{
sorts: [{ name: 'notifyTime', order: 'desc' }],
}"
>
<template #headerTitle>
<PermissionButton type="primary" @click="table.edit()">
<AIcon type="PlusOutlined" />新增
</PermissionButton>
</template>
<template #alarmConfigName="slotProps">
{{ slotProps.topicConfig.alarmConfigName }}
</template>
<template #state="slotProps">
<BadgeStatus
:status="slotProps.state.value"
:text="slotProps.state.text"
:statusNames="{
enabled: 'success',
disabled: 'error',
}"
></BadgeStatus>
</template>
<template #action="slotProps">
<a-space :size="16">
<PermissionButton
type="link"
:tooltip="{
title: '编辑',
}"
@click="table.edit(slotProps)"
>
<AIcon type="EditOutlined" />
</PermissionButton>
<PermissionButton
type="link"
:popConfirm="{
title: `确定${
slotProps.state.value === 'enabled'
? '禁用'
: '启用'
}`,
onConfirm: () => table.changeStatus(slotProps),
}"
:tooltip="{
title:
slotProps.state.value === 'enabled'
? '禁用'
: '启用',
}"
>
<AIcon
:type="
slotProps.state.value === 'enabled'
? 'StopOutlined'
: 'PlayCircleOutlined'
"
/>
</PermissionButton>
<PermissionButton
type="link"
:tooltip="{
title:
slotProps.state.value === 'enabled'
? '请先禁用,再删除'
: '删除',
}"
:popConfirm="{
title: `确认删除?`,
onConfirm: () => table.delete(slotProps),
}"
:disabled="slotProps.state.value === 'enabled'"
>
<AIcon type="DeleteOutlined" />
</PermissionButton>
</a-space>
</template>
</JTable>
<EditDialog
v-if="dialogVisible"
v-model:visible="dialogVisible"
:data="table.seletctRow"
@ok="table.refresh"
/>
</div>
</page-container>
</template>
<script setup lang="ts" name="NotificationSubscription">
import PermissionButton from '@/components/PermissionButton/index.vue';
import EditDialog from './components/EditDialog.vue';
import {
getNoticeList_api,
changeStatus_api,
remove_api
} from '@/api/account/notificationSubscription';
import { rowType } from './typing';
import { message } from 'ant-design-vue';
const columns = [
{
title: '名称',
dataIndex: 'subscribeName',
key: 'subscribeName',
ellipsis: true,
search: {
type: 'string',
},
},
{
title: '类型',
dataIndex: 'topicName',
key: 'topicName',
scopedSlots: true,
ellipsis: true,
},
{
title: '告警规则',
dataIndex: 'alarmConfigName',
key: 'alarmConfigName',
scopedSlots: true,
ellipsis: true,
},
{
title: '状态',
dataIndex: 'state',
key: 'state',
scopedSlots: true,
ellipsis: true,
},
{
title: '操作',
dataIndex: 'action',
key: 'action',
ellipsis: true,
scopedSlots: true,
},
];
const query = {
params: ref({}),
search: (params: object) => {
query.params.value = {...params};
},
};
const dialogVisible = ref<boolean>(false);
const tableRef = ref();
const table = {
seletctRow: ref<rowType>(),
edit: (row?: rowType) => {
table.seletctRow = {
...(row || ({} as any)),
};
dialogVisible.value = true;
},
changeStatus: (row: rowType) => {
const status = row.state.value === 'enabled' ? '_disabled' : '_enabled';
changeStatus_api(row.id as string, status).then((resp) => {
if (resp.status === 200) {
message.success('操作成功!');
table.refresh();
} else message.warning('操作失败!');
});
},
delete: (row: rowType) => {
remove_api(row.id as string).then(resp=>{
if(resp.status === 200) {
message.success('操作成功!')
table.refresh()
}else message.warning('操作失败!')
})
},
refresh: () => {
tableRef.value && tableRef.value.reload();
},
};
</script>
<style lang="less" scoped>
.notification-subscription-container {
:deep(.ant-table-tbody) {
.ant-table-cell {
.ant-space-item {
.ant-btn-link {
padding: 0;
}
}
}
}
}
</style>

View File

@ -0,0 +1,14 @@
export type rowType = {
id?: string;
locale: string;
state: { text: string, value: "enabled" | 'disabled' };
subscribeName: string;
subscriber: string;
subscriberType: string;
topicConfig: { alarmConfigId?: string, alarmConfigName?: string };
alarmConfigId: string;
alarmConfigName: stirng;
topicName: string;
topicProvider: string| undefined;
notice?:any[]
}

View File

@ -1,5 +1,5 @@
<template>
<a-drawer placement="right" :closable="false" :visible="true">
<j-drawer placement="right" :closable="false" :visible="true">
<template #title>
<div
style="
@ -15,21 +15,21 @@
@click="onClose"
/></span
>
<a-button type="primary" @click="saveBtn">保存</a-button>
<j-button type="primary" @click="saveBtn">保存</j-button>
</div>
</template>
<a-form layout="vertical" ref="formRef" :model="modelRef">
<j-form layout="vertical" ref="formRef" :model="modelRef">
<template v-for="(item, index) in props.config" :key="index">
<a-form-item
<j-form-item
:name="item.property"
v-for="i in item.properties"
:key="i.property"
>
<template #label>
<span style="margin-right: 5px">{{ i.name }}</span>
<a-tooltip v-if="i.description" :title="i.description"
<j-tooltip v-if="i.description" :title="i.description"
><AIcon type="QuestionCircleOutlined"
/></a-tooltip>
/></j-tooltip>
</template>
<ValueItem
v-model:modelValue="modelRef[i.property]"
@ -45,10 +45,10 @@
: undefined
"
/>
</a-form-item>
</j-form-item>
</template>
</a-form>
</a-drawer>
</j-form>
</j-drawer>
</template>
<script lang="ts" setup>

View File

@ -2,7 +2,7 @@
<div style="margin-top: 20px" v-if="config.length">
<div style="display: flex; margin-bottom: 20px; align-items: center">
<div style="font-size: 16px; font-weight: 700">配置</div>
<a-space>
<j-space>
<PermissionButton
type="link"
@click="visible = true"
@ -20,10 +20,10 @@
}"
hasPermission="device/Instance:update"
>
<AIcon type="CheckOutlined" />应用配置<a-tooltip
<AIcon type="CheckOutlined" />应用配置<j-tooltip
title="修改配置后需重新应用后才能生效。"
><AIcon type="QuestionCircleOutlined"
/></a-tooltip>
/></j-tooltip>
</PermissionButton>
<PermissionButton
type="link"
@ -34,26 +34,26 @@
}"
hasPermission="device/Instance:update"
>
<AIcon type="SyncOutlined" />恢复默认<a-tooltip
<AIcon type="SyncOutlined" />恢复默认<j-tooltip
title="该设备单独编辑过配置信息,点击此将恢复成默认的配置信息,请谨慎操作。"
><AIcon type="QuestionCircleOutlined"
/></a-tooltip>
/></j-tooltip>
</PermissionButton>
</a-space>
</j-space>
</div>
<a-descriptions bordered size="small" v-for="i in config" :key="i.name">
<j-descriptions bordered size="small" v-for="i in config" :key="i.name">
<template #title
><h4 style="font-size: 15px">{{ i.name }}</h4></template
>
<a-descriptions-item
<j-descriptions-item
v-for="item in i.properties"
:key="item.property"
>
<template #label>
<span style="margin-right: 5px">{{ item.name }}</span>
<a-tooltip v-if="item.description" :title="item.description"
<j-tooltip v-if="item.description" :title="item.description"
><AIcon type="QuestionCircleOutlined"
/></a-tooltip>
/></j-tooltip>
</template>
<span
v-if="
@ -68,7 +68,7 @@
instanceStore.current?.configuration?.[item.property] ||
''
}}</span>
<a-tooltip
<j-tooltip
v-if="isExit(item.property)"
:title="`有效值:${
instanceStore.current?.configuration?.[
@ -76,10 +76,10 @@
]
}`"
><AIcon type="QuestionCircleOutlined"
/></a-tooltip>
/></j-tooltip>
</span>
</a-descriptions-item>
</a-descriptions>
</j-descriptions-item>
</j-descriptions>
<Save
v-if="visible"
@save="saveBtn"

View File

@ -1,5 +1,5 @@
<template>
<a-drawer placement="right" :closable="false" :visible="true">
<j-drawer placement="right" :closable="false" :visible="true">
<template #title>
<div
style="
@ -15,32 +15,32 @@
@click="onClose"
/></span
>
<a-button type="primary" @click="saveBtn">保存</a-button>
<j-button type="primary" @click="saveBtn">保存</j-button>
</div>
</template>
<a-form layout="vertical" ref="formRef" :model="modelRef">
<a-form-item
<j-form layout="vertical" ref="formRef" :model="modelRef">
<j-form-item
:name="item.relation"
:label="item.relationName"
v-for="(item, index) in dataSource"
:key="index"
>
<a-select
<j-select
showSearch
mode="multiple"
v-model:value="modelRef[item.relation]"
:placeholder="`请选择${item.relationName}`"
>
<a-select-option
<j-select-option
:value="item.value"
v-for="item in userList"
:key="item.id"
>{{ item.name }}</a-select-option
>{{ item.name }}</j-select-option
>
</a-select>
</a-form-item>
</a-form>
</a-drawer>
</j-select>
</j-form-item>
</j-form>
</j-drawer>
</template>
<script lang="ts" setup>

View File

@ -1,6 +1,6 @@
<template>
<div style="margin-top: 20px">
<a-descriptions bordered>
<j-descriptions bordered>
<template #title>
关系信息
<PermissionButton
@ -8,13 +8,13 @@
@click="visible = true"
hasPermission="device/Instance:update"
>
<AIcon type="EditOutlined" />编辑<a-tooltip
<AIcon type="EditOutlined" />编辑<j-tooltip
title="管理设备与其他业务的关联关系,关系来源于关系配置"
><AIcon type="QuestionCircleOutlined"
/></a-tooltip>
/></j-tooltip>
</PermissionButton>
</template>
<a-descriptions-item
<j-descriptions-item
:span="1"
v-for="item in dataSource"
:key="item.objectId"
@ -23,9 +23,9 @@
item?.related
? (item?.related || []).map((i) => i.name).join(',')
: ''
}}</a-descriptions-item
}}</j-descriptions-item
>
</a-descriptions>
</j-descriptions>
<Save v-if="visible" @save="saveBtn" @close="visible = false" />
</div>
</template>

View File

@ -1,15 +1,15 @@
<template>
<a-modal
<j-modal
:width="1000"
:visible="true"
title="编辑标签"
@ok="handleOk"
@cancel="handleCancel"
>
<a-table
<j-table
rowKey="id"
:columns="columns"
:data-source="dataSource"
:datj-source="dataSource"
bordered
:pagination="false"
>
@ -43,8 +43,8 @@
</template>
</div>
</template>
</a-table>
</a-modal>
</j-table>
</j-modal>
</template>
<script lang="ts" setup>

View File

@ -1,6 +1,6 @@
<template>
<div style="margin-top: 20px">
<a-descriptions bordered>
<j-descriptions bordered>
<template #title>
标签
<PermissionButton
@ -11,14 +11,14 @@
<AIcon type="EditOutlined" />编辑
</PermissionButton>
</template>
<a-descriptions-item
<j-descriptions-item
:span="1"
v-for="item in dataSource"
:key="item.key"
:label="`${item.name}${item.key})`"
>{{ item?.value }}</a-descriptions-item
>{{ item?.value }}</j-descriptions-item
>
</a-descriptions>
</j-descriptions>
<Save v-if="visible" @close="visible = false" @save="saveBtn" />
</div>
</template>

View File

@ -1,6 +1,6 @@
<template>
<a-card>
<a-descriptions bordered>
<j-card>
<j-descriptions bordered>
<template #title>
设备信息
<PermissionButton
@ -12,59 +12,59 @@
编辑
</PermissionButton>
</template>
<a-descriptions-item label="设备ID">{{
<j-descriptions-item label="设备ID">{{
instanceStore.current.id
}}</a-descriptions-item>
<a-descriptions-item label="产品名称">{{
}}</j-descriptions-item>
<j-descriptions-item label="产品名称">{{
instanceStore.current.productName
}}</a-descriptions-item>
<a-descriptions-item label="产品分类">{{
}}</j-descriptions-item>
<j-descriptions-item label="产品分类">{{
instanceStore.current.classifiedName
}}</a-descriptions-item>
<a-descriptions-item label="设备类型">{{
}}</j-descriptions-item>
<j-descriptions-item label="设备类型">{{
instanceStore.current.deviceType?.text
}}</a-descriptions-item>
<a-descriptions-item label="固件版本">{{
}}</j-descriptions-item>
<j-descriptions-item label="固件版本">{{
instanceStore.current.firmwareInfo?.version
}}</a-descriptions-item>
<a-descriptions-item label="连接协议">{{
}}</j-descriptions-item>
<j-descriptions-item label="连接协议">{{
instanceStore.current?.protocolName
}}</a-descriptions-item>
<a-descriptions-item label="消息协议">{{
}}</j-descriptions-item>
<j-descriptions-item label="消息协议">{{
instanceStore.current.transport
}}</a-descriptions-item>
<a-descriptions-item label="创建时间">{{
}}</j-descriptions-item>
<j-descriptions-item label="创建时间">{{
instanceStore.current.createTime
? moment(instanceStore.current.createTime).format(
'YYYY-MM-DD HH:mm:ss',
)
: ''
}}</a-descriptions-item>
<a-descriptions-item label="注册时间">{{
}}</j-descriptions-item>
<j-descriptions-item label="注册时间">{{
instanceStore.current.registerTime
? moment(instanceStore.current.registerTime).format(
'YYYY-MM-DD HH:mm:ss',
)
: ''
}}</a-descriptions-item>
<a-descriptions-item label="最后上线时间">{{
}}</j-descriptions-item>
<j-descriptions-item label="最后上线时间">{{
instanceStore.current.onlineTime
? moment(instanceStore.current.onlineTime).format(
'YYYY-MM-DD HH:mm:ss',
)
: ''
}}</a-descriptions-item>
<a-descriptions-item
}}</j-descriptions-item>
<j-descriptions-item
label="父设备"
v-if="
instanceStore.current.deviceType?.value === 'childrenDevice'
"
>{{ instanceStore.current.parentId }}</a-descriptions-item
>{{ instanceStore.current.parentId }}</j-descriptions-item
>
<a-descriptions-item label="说明">{{
<j-descriptions-item label="说明">{{
instanceStore.current.description
}}</a-descriptions-item>
</a-descriptions>
}}</j-descriptions-item>
</j-descriptions>
<Config />
<Tags
v-if="
@ -84,7 +84,7 @@
@close="visible = false"
@save="saveBtn"
/>
</a-card>
</j-card>
</template>
<script lang="ts" setup>

View File

@ -1,11 +1,11 @@
<template>
<a-card>
<j-card>
<Search
:columns="columns"
target="device-instance-log"
@search="handleSearch"
/>
<JTable
<JProTable
ref="instanceRefLog"
:columns="columns"
:request="(e: Record<string, any>) => queryLog(instanceStore.current.id, e)"
@ -26,23 +26,23 @@
}}
</template>
<template #action="slotProps">
<a-space>
<j-space>
<template
v-for="i in getActions(slotProps, 'table')"
:key="i.key"
>
<a-button
<j-button
@click="i.onClick"
type="link"
style="padding: 0px"
>
<template #icon><AIcon :type="i.icon" /></template>
</a-button>
</j-button>
</template>
</a-space>
</j-space>
</template>
</JTable>
</a-card>
</JProTable>
</j-card>
</template>
<script lang="ts" setup>

View File

@ -1,12 +1,12 @@
<template>
<a-spin :spinning="loading">
<JTable
<j-spin :spinning="loading">
<JProTable
:columns="columns"
:dataSource="dataSource"
:bodyStyle="{ padding: '0 0 0 20px' }"
>
<template #headerTitle>
<a-input-search
<j-input-search
placeholder="请输入名称"
style="width: 300px; margin-bottom: 10px"
@search="onSearch"
@ -31,18 +31,18 @@
{{ propertyValue[slotProps?.id]?.timeString || '--' }}
</template>
<template #action="slotProps">
<a-space :size="16">
<j-space :size="16">
<template v-for="i in getActions(slotProps)" :key="i.key">
<a-tooltip v-bind="i.tooltip" v-if="i.key !== 'edit'">
<a-button
<j-tooltip v-bind="i.tooltip" v-if="i.key !== 'edit'">
<j-button
style="padding: 0"
type="link"
:disabled="i.disabled"
@click="i.onClick && i.onClick(slotProps)"
>
<AIcon :type="i.icon" />
</a-button>
</a-tooltip>
</j-button>
</j-tooltip>
<PermissionButton
:disabled="i.disabled"
v-else
@ -56,10 +56,10 @@
<template #icon><AIcon :type="i.icon" /></template>
</PermissionButton>
</template>
</a-space>
</j-space>
</template>
<template #paginationRender>
<a-pagination
<j-pagination
size="small"
:total="total"
:showQuickJumper="false"
@ -78,8 +78,8 @@
@change="pageChange"
/>
</template>
</JTable>
</a-spin>
</JProTable>
</j-spin>
<Save v-if="editVisible" @close="editVisible = false" :data="currentInfo" />
<Indicators
v-if="indicatorVisible"

View File

@ -1,15 +1,15 @@
<template>
<a-card>
<j-card>
<div class="property-box">
<div class="property-box-left">
<a-input-search
<j-input-search
v-model:value="value"
placeholder="请输入事件名称"
style="width: 200px; margin-bottom: 10px"
@search="onSearch"
:allowClear="true"
/>
<a-tabs
<j-tabs
tab-position="left"
style="height: 600px"
v-if="tabList.length"
@ -17,12 +17,12 @@
:tabBarStyle="{ width: '200px' }"
@change="tabChange"
>
<a-tab-pane
<j-tab-pane
v-for="i in tabList"
:key="i.key"
:tab="i.tab"
/>
</a-tabs>
</j-tabs>
<JEmpty v-else style="margin: 250px 0" />
</div>
<div class="property-box-right">
@ -30,7 +30,7 @@
<Property v-else :data="properties" />
</div>
</div>
</a-card>
</j-card>
</template>
<script lang="ts" setup>

View File

@ -1,88 +1,88 @@
<template>
<a-modal
<j-modal
:maskClosable="false"
width="650px"
:visible="true"
:title="!!props.data.id ? '编辑' : '新增'"
:title="!!data?.id ? '编辑' : '新增'"
@ok="handleSave"
@cancel="handleCancel"
:confirmLoading="loading"
>
<div style="margin-top: 10px">
<a-form
<j-form
:layout="'vertical'"
ref="formRef"
:rules="rules"
:model="modelRef"
>
<a-row type="flex">
<a-col flex="180px">
<a-form-item name="photoUrl">
<j-row type="flex">
<j-col flex="180px">
<j-form-item name="photoUrl">
<JUpload v-model="modelRef.photoUrl" />
</a-form-item>
</a-col>
<a-col flex="auto">
<a-form-item name="id">
</j-form-item>
</j-col>
<j-col flex="auto">
<j-form-item name="id">
<template #label>
<span>
ID
<a-tooltip title="若不填写系统将自动生成唯一ID">
<j-tooltip title="若不填写系统将自动生成唯一ID">
<AIcon
type="QuestionCircleOutlined"
style="margin-left: 2px;" />
</a-tooltip>
</j-tooltip>
</span>
</template>
<a-input
<j-input
v-model:value="modelRef.id"
placeholder="请输入ID"
:disabled="!!props.data.id"
:disabled="!!data?.id"
/>
</a-form-item>
<a-form-item label="名称" name="name">
<a-input
</j-form-item>
<j-form-item label="名称" name="name">
<j-input
v-model:value="modelRef.name"
placeholder="请输入名称"
/>
</a-form-item>
</a-col>
</a-row>
<a-form-item name="productId">
</j-form-item>
</j-col>
</j-row>
<j-form-item name="productId">
<template #label>
<span>所属产品
<a-tooltip title="只能选择“正常”状态的产品">
<j-tooltip title="只能选择“正常”状态的产品">
<AIcon
type="QuestionCircleOutlined"
style="margin-left: 2px" />
</a-tooltip>
</j-tooltip>
</span>
</template>
<a-select
<j-select
showSearch
v-model:value="modelRef.productId"
placeholder="请选择所属产品"
:filter-option="filterOption"
>
<a-select-option
<j-select-option
:value="item.id"
v-for="item in productList"
:key="item.id"
:label="item.name"
:disabled="!!props.data.id"
>{{item.name}}</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="说明" name="describe">
<a-textarea
:disabled="!!data?.id"
>{{item.name}}</j-select-option>
</j-select>
</j-form-item>
<j-form-item label="说明" name="describe">
<j-textarea
v-model:value="modelRef.describe"
placeholder="请输入说明"
showCount
:maxlength="200"
/>
</a-form-item>
</a-form>
</j-form-item>
</j-form>
</div>
</a-modal>
</j-modal>
</template>
<script lang="ts" setup>
@ -157,7 +157,7 @@ const rules = {
message: '最多输入64个字符',
},
{
pattern: /^[a-zA-Z0-9_\-]+$/,
pattern: /^[j-zA-Z0-9_\-]+$/,
message: '请输入英文或者数字或者-或者_',
},
{

View File

@ -1,11 +1,11 @@
<template>
<page-container>
<Search
<JSearch
:columns="columns"
target="device-instance"
@search="handleSearch"
/>
<JTable
<JProTable
ref="instanceRef"
:columns="columns"
:request="query"
@ -18,7 +18,7 @@
:params="params"
>
<template #headerTitle>
<a-space>
<j-space>
<PermissionButton
type="primary"
@click="handleAdd"
@ -27,13 +27,13 @@
<template #icon><AIcon type="PlusOutlined" /></template>
新增
</PermissionButton>
<a-dropdown>
<a-button
<j-dropdown>
<j-button
>批量操作 <AIcon type="DownOutlined"
/></a-button>
/></j-button>
<template #overlay>
<a-menu>
<a-menu-item>
<j-menu>
<j-menu-item>
<PermissionButton
@click="exportVisible = true"
hasPermission="device/Instance:export"
@ -43,8 +43,8 @@
/></template>
批量导出设备
</PermissionButton>
</a-menu-item>
<a-menu-item>
</j-menu-item>
<j-menu-item>
<PermissionButton
@click="importVisible = true"
hasPermission="device/Instance:import"
@ -54,8 +54,8 @@
/></template>
批量导入设备
</PermissionButton>
</a-menu-item>
<a-menu-item>
</j-menu-item>
<j-menu-item>
<PermissionButton
ghost
type="primary"
@ -70,8 +70,8 @@
/></template>
激活全部设备
</PermissionButton>
</a-menu-item>
<a-menu-item>
</j-menu-item>
<j-menu-item>
<PermissionButton
type="primary"
@click="syncDeviceStatus"
@ -82,8 +82,8 @@
/></template>
同步设备状态
</PermissionButton>
</a-menu-item>
<a-menu-item v-if="_selectedRowKeys.length">
</j-menu-item>
<j-menu-item v-if="_selectedRowKeys.length">
<PermissionButton
type="primary"
danger
@ -98,8 +98,8 @@
/></template>
删除选中设备
</PermissionButton>
</a-menu-item>
<a-menu-item v-if="_selectedRowKeys.length">
</j-menu-item>
<j-menu-item v-if="_selectedRowKeys.length">
<PermissionButton
type="primary"
:popConfirm="{
@ -113,8 +113,8 @@
/></template>
激活选中设备
</PermissionButton>
</a-menu-item>
<a-menu-item v-if="_selectedRowKeys.length">
</j-menu-item>
<j-menu-item v-if="_selectedRowKeys.length">
<PermissionButton
type="primary"
danger
@ -129,11 +129,11 @@
/></template>
禁用选中设备
</PermissionButton>
</a-menu-item>
</a-menu>
</j-menu-item>
</j-menu>
</template>
</a-dropdown>
</a-space>
</j-dropdown>
</j-space>
</template>
<template #card="slotProps">
<CardBox
@ -160,22 +160,22 @@
{{ slotProps.name }}
</span>
</Ellipsis>
<a-row style="margin-top: 20px">
<a-col :span="12">
<j-row style="margin-top: 20px">
<j-col :span="12">
<div class="card-item-content-text">
设备类型
</div>
<div>{{ slotProps.deviceType?.text }}</div>
</a-col>
<a-col :span="12">
</j-col>
<j-col :span="12">
<div class="card-item-content-text">
产品名称
</div>
<Ellipsis style="width: 100%">
{{ slotProps.productName }}
</Ellipsis>
</a-col>
</a-row>
</j-col>
</j-row>
</template>
<template #actions="item">
<PermissionButton
@ -200,13 +200,13 @@
</CardBox>
</template>
<template #state="slotProps">
<a-badge
<j-badge
:text="slotProps.state?.text"
:status="statusMap.get(slotProps.state?.value)"
/>
</template>
<template #action="slotProps">
<a-space>
<j-space>
<template
v-for="i in getActions(slotProps, 'table')"
:key="i.key"
@ -225,9 +225,9 @@
<template #icon><AIcon :type="i.icon" /></template>
</PermissionButton>
</template>
</a-space>
</j-space>
</template>
</JTable>
</JProTable>
</page-container>
<Import v-if="importVisible" @close="importVisible = false" />
<Export

View File

@ -1,5 +1,5 @@
<template>
<JTable :loading="loading" :data-source="data" size="small" :columns="columns" row-key="id" model="TABLE">
<j-pro-table :loading="loading" :data-source="data" size="small" :columns="columns" row-key="id" model="TABLE">
<template #headerTitle>
<a-input-search v-model:value="searchValue" placeholder="请输入名称" @search="handleSearch"></a-input-search>
</template>
@ -28,12 +28,12 @@
{{ sourceMap[slotProps.expands?.source] }}
</template>
<template #type="slotProps">
<a-tag v-for="item in (slotProps.expands?.type || [])" :key="item">
<j-tag v-for="item in (slotProps.expands?.type || [])" :key="item">
{{ expandsType[item] }}
</a-tag>
</j-tag>
</template>
<template #action="slotProps">
<a-space>
<j-space>
<PermissionButton :uhas-permission="`${permission}:update`" type="link" key="edit" style="padding: 0"
:udisabled="operateLimits('updata', type)" @click="handleEditClick(slotProps)" :tooltip="{
title: operateLimits('updata', type) ? '当前的存储方式不支持编辑' : '编辑',
@ -50,14 +50,13 @@
}">
<Aicon type="DeleteOutlined" />
</PermissionButton>
</a-space>
</j-space>
</template>
</JTable>
</j-pro-table>
</template>
<script setup lang="ts" name="BaseMetadata">
import type { MetadataItem, MetadataType } from '@/views/device/Product/typings'
import MetadataMapping from './columns'
import JTable from '@/components/Table'
import { useInstanceStore } from '@/store/instance'
import { useProductStore } from '@/store/product'
import { useMetadataStore } from '@/store/metadata'

View File

@ -15,7 +15,7 @@
组装上报设备的数据您可以导出完整物模型用于云端应用开发
</p>
</div>
<a-tabs @change="handleConvertMetadata">
<a-tabs @change="handleConvertMetadata" destroy-inactive-tab-pane>
<a-tab-pane v-for="item in codecs" :key="item.id" :tab="item.name">
<div class="cat-panel">
<MonacoEditor v-model="value" theme="vs" style="height: 100%"></MonacoEditor>

View File

@ -1,8 +1,8 @@
<template>
<a-card>
<j-card>
<div class='device-detail-metadata' style="position: relative;">
<div class="tips">
<a-tooltip :title="instanceStore.detail?.independentMetadata && type === 'device'
<j-tooltip :title="instanceStore.detail?.independentMetadata && type === 'device'
? '该设备已脱离产品物模型,修改产品物模型对该设备无影响'
: '设备会默认继承产品的物模型,修改设备物模型后将脱离产品物模型'">
<div class="ellipsis">
@ -13,11 +13,11 @@
: '设备会默认继承产品的物模型,修改设备物模型后将脱离产品物模型'
}}
</div>
</a-tooltip>
</j-tooltip>
</div>
<a-tabs class="metadataNav" destroyInactiveTabPane type="card">
<j-tabs class="metadataNav" destroyInactiveTabPane type="card">
<template #rightExtra>
<a-space>
<j-space>
<PermissionButton v-if="type === 'device' && instanceStore.detail?.independentMetadata"
:hasPermission="`${permission}:update`" :popConfirm="{ title: '确认重置?', onConfirm: resetMetadata, }"
:tooltip="{ title: '重置后将使用产品的物模型配置' }" key="reload">
@ -25,32 +25,31 @@
</PermissionButton>
<PermissionButton :hasPermission="`${permission}:update`" @click="visible = true">快速导入</PermissionButton>
<PermissionButton :hasPermission="`${permission}:update`" @click="cat = true">物模型TSL</PermissionButton>
</a-space>
</j-space>
</template>
<a-tab-pane tab="属性定义" key="properties">
<j-tab-pane tab="属性定义" key="properties">
<BaseMetadata :target="type" type="properties" :permission="permission" />
</a-tab-pane>
<a-tab-pane tab="功能定义" key="functions">
</j-tab-pane>
<j-tab-pane tab="功能定义" key="functions">
<BaseMetadata :target="type" type="functions" :permission="permission" />
</a-tab-pane>
<a-tab-pane tab="事件定义" key="events">
</j-tab-pane>
<j-tab-pane tab="事件定义" key="events">
<BaseMetadata :target="type" type="events" :permission="permission" />
</a-tab-pane>
<a-tab-pane tab="标签定义" key="tags">
</j-tab-pane>
<j-tab-pane tab="标签定义" key="tags">
<BaseMetadata :target="type" type="tags" :permission="permission" />
</a-tab-pane>
</a-tabs>
</j-tab-pane>
</j-tabs>
<Import v-model:visible="visible" :type="type" @close="visible = false" />
<Cat v-model:visible="cat" @close="cat = false" :type="type" />
</div>
</a-card>
</j-card>
</template>
<script setup lang="ts" name="Metadata">
import PermissionButton from '@/components/PermissionButton/index.vue'
import { deleteMetadata } from '@/api/device/instance.js'
import { message } from 'ant-design-vue'
import { SystemConst } from '@/utils/consts'
import { useInstanceStore } from '@/store/instance'
import Import from './Import/index.vue'
import Cat from './Cat/index.vue'

View File

@ -17,7 +17,7 @@
@search="handleSearch"
/>
<JTable
<JProTable
ref="listRef"
model="table"
:columns="columns"
@ -62,7 +62,7 @@
></a-badge>
</a-space>
</template>
</JTable>
</JProTable>
</a-modal>
</template>

View File

@ -8,7 +8,7 @@
@search="handleSearch"
/>
<JTable
<JProTable
ref="listRef"
model="table"
:columns="columns"
@ -40,6 +40,16 @@
</a-popconfirm>
</a-space>
</template>
<template #gbChannelIdHeader="title">
<a-tooltip
title="国标级联有16位、20位两种格式。在当前页面修改不会修改视频设备-通道页面中的国标ID"
>
<a-space>
<span>{{ title }}</span>
<AIcon type="InfoCircleOutlined" />
</a-space>
</a-tooltip>
</template>
<template #gbChannelId="slotProps">
<a-space>
<Ellipsis>
@ -134,7 +144,7 @@
</a-tooltip>
</a-space>
</template>
</JTable>
</JProTable>
<BindChannel v-model:visible="bindVis" @submit="listRef.reload()" />
</page-container>
@ -172,6 +182,7 @@ const columns = [
dataIndex: 'gbChannelId',
key: 'gbChannelId',
scopedSlots: true,
headerCell: 'gbChannelIdHeader', //
search: {
type: 'string',
},

View File

@ -6,7 +6,7 @@
@search="handleSearch"
/>
<JTable
<JProTable
ref="listRef"
:columns="columns"
:request="(e:any) => lastValueFrom(e)"
@ -192,7 +192,7 @@
</template> -->
</a-space>
</template>
</JTable>
</JProTable>
<Publish v-model:visible="publishVis" :data="currentData" />
</page-container>

View File

@ -0,0 +1,58 @@
.media-live {
display: flex;
.live-player-tools {
flex-basis: 230px;
.direction-item {
font-size: 30px !important;
}
.zoom-item {
font-size: 20px !important;
}
}
.media-live-video {
position: relative;
flex-grow: 1;
width: 0;
.media-tool {
position: absolute;
top: 4px;
right: 0;
z-index: 2;
display: flex;
opacity: 0;
transition: opacity 0.3s;
&:hover {
opacity: 1;
}
.tool-item {
margin-right: 6px;
padding: 4px;
color: #fff;
font-size: 14px;
background-color: hsla(0, 0%, 50.2%, 0.8);
border-radius: 2px;
cursor: pointer;
&:hover {
background-color: hsla(0, 0%, 50.2%, 0.85);
}
&:active {
background-color: hsla(0, 0%, 50.2%, 0.9);
}
}
}
}
}
.media-live-tool {
display: flex;
margin-top: 24px;
}

View File

@ -0,0 +1,159 @@
<!-- 视频设备 - 播放 -->
<template>
<a-modal
v-model:visible="_vis"
title="播放"
cancelText="取消"
okText="确定"
width="800px"
:maskClosable="false"
@ok="_vis = false"
@cancel="_vis = false"
>
<div class="media-live">
<div class="media-live-video">
<div class="media-tool">
<div class="tool-item" @click.stop="handleRecord">
{{
isRecord === 0
? '开始录像'
: isRecord === 1
? '请求录像中'
: '停止录像'
}}
</div>
<div class="tool-item">刷新</div>
<div class="tool-item" @click.stop="handleReset">重置</div>
</div>
<LivePlayer :src="src" :type="mediaType" />
</div>
<MediaTool
@onMouseDown="handleMouseDown"
@onMouseUp="handleMouseUp"
/>
</div>
<div class="media-live-tool">
<a-radio-group
v-model:value="mediaType"
button-style="solid"
@change="mediaStart"
>
<a-radio-button value="mp4">MP4</a-radio-button>
<a-radio-button value="flv">FLV</a-radio-button>
<a-radio-button value="m3u8">HLS</a-radio-button>
</a-radio-group>
</div>
</a-modal>
</template>
<script setup lang="ts">
import { PropType } from 'vue';
import LivePlayer from '@/components/Player/index.vue';
import MediaTool from '@/components/Player/mediaTool.vue';
import channelApi from '@/api/media/channel';
type Emits = {
(e: 'update:visible', data: boolean): void;
};
const emit = defineEmits<Emits>();
const props = defineProps({
visible: { type: Boolean, default: false },
data: {
type: Object as PropType<Partial<Record<string, any>>>,
default: () => ({}),
},
});
const _vis = computed({
get: () => props.visible,
set: (val) => emit('update:visible', val),
});
//
const src = ref('');
//
const mediaType = ref('mp4');
/**
* 媒体开始播放
*/
const mediaStart = () => {
src.value = channelApi.ptzStart(
props.data.deviceId,
props.data.channelId,
mediaType.value,
);
};
//
const isRecord = ref(0); // 0 1 2
/**
* 查询录像状态
*/
const getIsRecord = async () => {
const { result } = await channelApi.ptzIsRecord(
props.data.deviceId,
props.data.channelId,
);
isRecord.value = result ? 2 : 0;
};
/**
* 点击录像/停止录像
*/
const handleRecord = async () => {
if (isRecord.value === 0) {
isRecord.value = 1;
const res = await channelApi.recordStart(
props.data.deviceId,
props.data.channelId,
{ local: false },
);
if (res.success) {
isRecord.value = 2;
} else {
isRecord.value = 0;
}
} else if (isRecord.value === 2) {
const res = await channelApi.recordStop(
props.data.deviceId,
props.data.channelId,
{ local: false },
);
if (res.success) {
isRecord.value = 0;
}
}
};
/**
* 重置
*/
const handleReset = async () => {
channelApi.mediaStop(props.data.deviceId, props.data.channelId);
};
/**
* 点击控制按钮
* @param type 控制类型
*/
const handleMouseDown = (type: string) => {
channelApi.ptzTool(props.data.deviceId, props.data.channelId, type);
};
const handleMouseUp = () => {
channelApi.ptzStop(props.data.deviceId, props.data.channelId);
};
watch(
() => _vis.value,
(val: boolean) => {
if (val) {
mediaStart();
getIsRecord();
}
},
);
</script>
<style lang="less" scoped>
@import './index.less';
</style>

View File

@ -8,7 +8,7 @@
@search="handleSearch"
/>
<JTable
<JProTable
ref="listRef"
:columns="columns"
:request="(e:any) => ChannelApi.list(e, route?.query.id as string)"
@ -76,13 +76,14 @@
</a-tooltip>
</a-space>
</template>
</JTable>
</JProTable>
<Save
v-model:visible="saveVis"
:channelData="channelData"
@submit="listRef.reload()"
/>
<Live v-model:visible="playerVis" :data="channelData" />
</page-container>
</template>
@ -92,6 +93,7 @@ import type { ActionsType } from '@/components/Table/index.vue';
import { useMenuStore } from 'store/menu';
import { message } from 'ant-design-vue';
import Save from './Save.vue';
import Live from './Live/index.vue';
import { cloneDeep } from 'lodash-es';
const menuStory = useMenuStore();
@ -169,7 +171,7 @@ const handleAdd = () => {
};
const listRef = ref();
const playVis = ref(false);
const playerVis = ref(false);
const channelData = ref();
/**
@ -203,7 +205,8 @@ const getActions = (
},
icon: 'VideoCameraOutlined',
onClick: () => {
playVis.value = true;
channelData.value = cloneDeep(data);
playerVis.value = true;
},
},
{

View File

@ -5,7 +5,7 @@
target="notice-config"
@search="handleSearch"
/>
<JTable
<JProTable
ref="listRef"
:columns="columns"
:request="DeviceApi.list"
@ -125,7 +125,7 @@
</a-tooltip>
</a-space>
</template>
</JTable>
</JProTable>
</page-container>
</template>

View File

@ -7,7 +7,7 @@
@search="handleSearch"
/>
<JTable
<JProTable
ref="instanceRef"
:columns="columns"
:request="(e:any) => configApi.getHistory(e, data.id)"
@ -42,7 +42,7 @@
@click="handleDetail(slotProps.context)"
/>
</template>
</JTable>
</JProTable>
</a-modal>
</template>

View File

@ -34,7 +34,7 @@
<a-empty v-if="!deptTreeData.length" />
</a-col>
<a-col :span="20">
<JTable
<JProTable
ref="tableRef"
:columns="columns"
:dataSource="dataSource"
@ -92,7 +92,7 @@
</a-tooltip>
</a-space>
</template>
</JTable>
</JProTable>
</a-col>
</a-row>
</a-modal>

View File

@ -5,7 +5,7 @@
target="notice-config"
@search="handleSearch"
/>
<JTable
<JProTable
ref="configRef"
:columns="columns"
:request="ConfigApi.list"
@ -163,7 +163,7 @@
</a-tooltip>
</a-space>
</template>
</JTable>
</JProTable>
<Debug v-model:visible="debugVis" :data="currentConfig" />
<Log v-model:visible="logVis" :data="currentConfig" />

View File

@ -7,7 +7,7 @@
@search="handleSearch"
/>
<JTable
<JProTable
ref="instanceRef"
:columns="columns"
:request="(e:any) => templateApi.getHistory(e, data.id)"
@ -42,7 +42,7 @@
@click="handleDetail(slotProps.context)"
/>
</template>
</JTable>
</JProTable>
</a-modal>
</template>

View File

@ -5,7 +5,7 @@
target="notice-config"
@search="handleSearch"
/>
<JTable
<JProTable
ref="configRef"
:columns="columns"
:request="TemplateApi.list"
@ -159,7 +159,7 @@
</a-tooltip>
</a-space>
</template>
</JTable>
</JProTable>
<Debug v-model:visible="debugVis" :data="currentConfig" />
<Log v-model:visible="logVis" :data="currentConfig" />

View File

@ -29,6 +29,7 @@
v-model:selectorValues='addModel.selectorValues'
/>
<Type
ref='typeRef'
v-else-if='addModel.stepNumber === 2'
:metadata='addModel.metadata'
/>
@ -46,7 +47,7 @@
<script setup lang='ts' name='AddModel'>
import type { PropType } from 'vue'
import type { metadataType, TriggerDevice } from '@/views/rule-engine/Scene/typings'
import type { metadataType, TriggerDevice, TriggerDeviceOptions } from '@/views/rule-engine/Scene/typings'
import { onlyMessage } from '@/utils/comm'
import { detail as deviceDetail } from '@/api/device/instance'
import Product from './Product.vue'
@ -69,6 +70,7 @@ interface AddModelType extends Omit<TriggerDevice, 'selectorValues'> {
}
const emit = defineEmits<Emit>()
const typeRef = ref()
const props = defineProps({
value: {
@ -81,9 +83,7 @@ const props = defineProps({
},
options: {
type: Object as PropType<any>,
default: () => ({
})
default: () => ({})
}
})
@ -100,7 +100,7 @@ const addModel = reactive<AddModelType>({
Object.assign(addModel, props.value)
const handleOptions = () => {
const handleOptions = (data: TriggerDeviceOptions) => {
}
@ -138,10 +138,12 @@ const save = async (step?: number) => {
}
addModel.stepNumber = 2
} else {
const typeData = await typeRef.value.vail()
console.log(typeData)
if (typeData) {
const _options = handleOptions(typeData);
}
}
// handleOptions()
// emit('update:value', {})
}
const saveClick = () => save()

View File

@ -1,52 +1,57 @@
<template>
<a-row :gutter='24'>
<a-col :span='10'>
<a-form-item
name='functionId'
:rules="[{ required: true, message: '请选择功能' }]"
>
<a-select
showSearch
allowClear
v-model='functionId'
style='width: 100%'
placeholder='请选择功能'
:filterOption='filterSelectNode'
@select='onSelect'
/>
</a-form-item>
</a-col>
<a-col :span='14'>
<a-form-item>定时调用所选功能</a-form-item>
</a-col>
<a-col :span='24'>
<a-form-item
style='margin-top: 24px'
name='functionParameters'
>
<a-form ref='invokeForm' :model='formModel' layout='vertical' :colon='false'>
<a-row :gutter='24'>
<a-col :span='10'>
<a-form-item
name='functionId'
:rules="[{ required: true, message: '请选择功能' }]"
>
<a-select
showSearch
allowClear
v-model:value='formModel.functionId'
style='width: 100%'
placeholder='请选择功能'
:options='functions'
:filterOption='filterSelectNode'
@select='onSelect'
/>
</a-form-item>
</a-col>
<a-col :span='14'>
<a-form-item>定时调用所选功能</a-form-item>
</a-col>
<a-col :span='24'>
<FunctionCall
v-model:value='_value'
:data='callDataOptions'
:value='_value'
:data='functionData'
@change='callDataChange'
/>
</a-form-item>
</a-col>
</a-row>
</a-col>
</a-row>
</a-form>
</template>
<script setup lang='ts' name='InvokeFunction'>
import { filterSelectNode } from '@/utils/comm'
import { FunctionCall } from '../components'
import type { PropType } from 'vue'
import { defineExpose } from 'vue'
type Emit = {
(e: 'update:value', data: Record<string, any>): void
(e: 'update:functionParameters', data: Array<Record<string, any>>): void
(e: 'update:functionId', data: string): void
(e: 'update:action', data: string): void
}
const props = defineProps({
value: {
type: Object,
default: () => ({})
functionId: {
type: String,
default: undefined
},
functionParameters: {
type: Array as PropType<Record<string, any>[]>,
default: () => []
},
action: {
type: String,
@ -59,46 +64,53 @@ const props = defineProps({
})
const emit = defineEmits<Emit>()
const invokeForm = ref()
const formModel = reactive({
functionId: props.functionId
})
const _value = ref<any[]>(props.functionParameters)
const functionId = ref()
const _value = ref([])
/**
* 获取当前选择功能属性
*/
const functionData = computed(() => {
const functionItem: any = props.functions.find((f: any) => f.id === formModel.functionId)
const arrCache = []
const callDataOptions = computed(() => {
const _valueKeys = Object.keys(props.value)
if (_valueKeys.length) {
return _valueKeys.map(key => {
const item: any = props.functions.find((p: any) => p.id === key)
if (item) {
return {
id: item.id,
name: item.name,
type: item.valueType ? item.valueType.type : '-',
format: item.valueType ? item.valueType.format : undefined,
options: item.valueType ? item.valueType.element : undefined,
value: props.value[key]
}
}
return {
id: key,
name: key,
type: '',
format: undefined,
options: undefined,
value: props.value[key]
}
})
if (functionItem) {
const properties = functionItem.valueType ? functionItem.valueType.properties : functionItem.inputs;
for (const datum of properties) {
arrCache.push({
id: datum.id,
name: datum.name,
type: datum.valueType ? datum.valueType.type : '-',
format: datum.valueType ? datum.valueType.format : undefined,
options: datum.valueType ? datum.valueType.elements : undefined,
value: undefined,
});
}
}
return []
return arrCache
})
const onSelect = (v: string, item: any) => {
emit('update:action', `执行${item.name}`)
emit('update:functionId', v)
}
const callDataChange = () => {
const callDataChange = (v: any[]) => {
_value.value = v
emit('update:functionParameters', v)
}
defineExpose({
validateFields: () => new Promise(async (resolve) => {
const data = await invokeForm.value?.validateFields()
resolve(data)
})
})
</script>
<style scoped>

View File

@ -14,6 +14,7 @@
:params='params'
:request='productQuery'
:gridColumn='2'
:gridColumns='[2,2,2]'
:bodyStyle='{
paddingRight: 0,
paddingLeft: 0

View File

@ -11,15 +11,22 @@
v-model:value='formModel.operator'
/>
</a-form-item>
<Timer v-if='showTimer' v-model:value='formModel.timer' />
<ReadProperties v-if='showReadProperty' v-model:value='formModel.readProperties' v-model:action='optionCache.action' :properties='readProperties' />
<a-form-item
<template v-if='showTimer'>
<Timer ref='timerRef' v-model:value='formModel.timer' />
</template>
<ReadProperties
v-if='showReadProperty'
v-model:value='formModel.readProperties'
v-model:action='optionCache.action'
:properties='readProperties'
/>
<WriteProperty
ref='writeRef'
v-if='showWriteProperty'
name='writeProperties'
:rules="[{ required: true, message: '请输入修改值' }]"
>
<WriteProperty v-model:value='formModel.writeProperties' v-model:action='optionCache.action' :properties='writeProperties' />
</a-form-item>
v-model:value='formModel.writeProperties'
v-model:action='optionCache.action'
:properties='writeProperties'
/>
<a-form-item
v-if='showReportEvent'
name='eventId'
@ -34,6 +41,14 @@
@select='eventSelect'
/>
</a-form-item>
<template v-if='showInvokeFunction'>
<InvokeFunction
ref='invokeRef'
v-model:type='formModel.functionId'
v-model:functionParameters='formModel.functionParameters'
:functions='functionOptions'
/>
</template>
</a-form>
</div>
</template>
@ -47,6 +62,9 @@ import type { PropType } from 'vue'
import { TypeEnum } from '@/views/rule-engine/Scene/Save/Device/util'
import ReadProperties from './ReadProperties.vue'
import WriteProperty from './WriteProperty.vue'
import InvokeFunction from './InvokeFunction.vue'
import { defineExpose } from 'vue'
import { cloneDeep, omit } from 'lodash-es'
const props = defineProps({
metadata: {
@ -72,19 +90,25 @@ const optionCache = reactive({
const readProperties = ref<any[]>([])
const writeProperties = ref<any[]>([])
const eventOptions = ref<any[]>([])
const functionOptions = ref<any[]>([])
const typeForm = ref()
const timerRef = ref()
const writeRef = ref()
const invokeRef = ref()
const topOptions = computed(() => {
const baseOptions = [
{
label: '设备上线',
value: 'online',
img: getImage('/scene/online.png'),
img: getImage('/scene/online.png')
},
{
label: '设备离线',
value: 'offline',
img: getImage('/scene/offline.png'),
},
img: getImage('/scene/offline.png')
}
]
if (props.metadata.events?.length) {
@ -94,9 +118,21 @@ const topOptions = computed(() => {
if (props.metadata.properties?.length) {
const _properties = props.metadata.properties
readProperties.value = _properties.filter((item: any) => item.expands.type?.includes('read')).map(item => ({...item, label: item.name, value: item.id }))
writeProperties.value = _properties.filter((item: any) => item.expands.type?.includes('write')).map(item => ({...item, label: item.name, value: item.id }))
const reportProperties = _properties.filter((item: any) => item.expands.type?.includes('report')).map(item => ({...item, label: item.name, value: item.id }))
readProperties.value = _properties.filter((item: any) => item.expands.type?.includes('read')).map(item => ({
...item,
label: item.name,
value: item.id
}))
writeProperties.value = _properties.filter((item: any) => item.expands.type?.includes('write')).map(item => ({
...item,
label: item.name,
value: item.id
}))
const reportProperties = _properties.filter((item: any) => item.expands.type?.includes('report')).map(item => ({
...item,
label: item.name,
value: item.id
}))
if (readProperties.value.length) {
baseOptions.push(TypeEnum.readProperty)
@ -109,11 +145,11 @@ const topOptions = computed(() => {
if (reportProperties.length) {
baseOptions.push(TypeEnum.reportProperty)
}
}
if (props.metadata.functions?.length) {
baseOptions.push(TypeEnum.invokeFunction)
functionOptions.value = props.metadata.functions.map(item => ({ ...item, label: item.name, value: item.id }))
}
return baseOptions
@ -147,6 +183,50 @@ const eventSelect = (_: string, eventItem: any) => {
optionCache.action = `${eventItem.name}上报`
}
defineExpose({
vail: () => {
return new Promise(async (resolve, reject) => {
const cloneModel = cloneDeep(formModel)
const filterKey: string[] = []
const typeData = await typeForm.value?.validateFields()
if (!typeData) return resolve(false)
if (!showReadProperty.value) {
filterKey.push('readProperties')
}
if (showInvokeFunction.value) {
const invokeData = await invokeRef.value?.validateFields()
if (!invokeData) return resolve(false)
} else {
filterKey.push('functionId')
filterKey.push('functionParameters')
}
if (showTimer.value) {
const timerData = await timerRef.value?.validateFields()
if (!timerData) return resolve(false)
} else {
filterKey.push('timer')
}
if (!showReportEvent.value) {
filterKey.push('eventId')
}
if (showWriteProperty.value) {
const writeData = await writeRef.value?.validateFields()
if (!writeData) return resolve(false)
} else {
filterKey.push('writeProperties')
}
resolve(omit(cloneModel, filterKey))
})
}
})
</script>
<style scoped lang='less'>

View File

@ -1,37 +1,43 @@
<template>
<a-row :futter='[24, 24]'>
<a-col :span='10'>
<a-select
showSearch
style='width: 100%'
placeholder='请选择属性'
v-model:value='reportKey'
:options='properties'
:filter-option='filterSelectNode'
@change='change'
/>
</a-col>
<a-col :span='14'>
<span style='line-height: 32px;padding-left: 24px'>
定时调用所选属性
</span>
</a-col>
<a-col :span='24' v-if='showTable'>
<div style='margin-top: 24px'>
<a-form ref='writeForm' :model='formModel' layout='vertical' :colon='false'>
<a-row :futter='[24, 24]'>
<a-col :span='10'>
<a-form-item
name='reportKey'
:rules="[{ required: true, message: '请输入修改值' }]"
>
<a-select
showSearch
style='width: 100%'
placeholder='请选择属性'
v-model:value='formModel.reportKey'
:options='properties'
:filter-option='filterSelectNode'
@change='change'
/>
</a-form-item>
</a-col>
<a-col :span='14'>
<span style='line-height: 32px;padding-left: 24px'>
定时调用所选属性
</span>
</a-col>
<a-col :span='24' v-if='showTable'>
<FunctionCall
:value='_value'
:data='callDataOptions'
@change='callDataChange'
/>
</div>
</a-col>
</a-row>
</a-col>
</a-row>
</a-form>
</template>
<script setup lang='ts' name='WriteProperties'>
import { filterSelectNode } from '@/utils/comm'
import { FunctionCall } from '../components'
import type { PropType } from 'vue'
import { defineExpose } from 'vue'
type Emit = {
(e: 'update:value', data: Record<string, any>): void
@ -55,8 +61,12 @@ const props = defineProps({
const emit = defineEmits<Emit>()
const reportKey = ref<string>()
const formModel = reactive<{ reportKey: string | undefined }>({
reportKey: undefined
})
const callData = ref<Array<{ id: string, value: string | undefined }>>()
const writeForm = ref()
const _value = ref([])
const callDataOptions = computed(() => {
@ -88,11 +98,10 @@ const callDataOptions = computed(() => {
})
const showTable = computed(() => {
return !!reportKey.value
return !!formModel.reportKey
})
const change = (v: string, option: any) => {
console.log(v, option)
const _data = {
[v]: undefined
}
@ -103,17 +112,24 @@ const change = (v: string, option: any) => {
const callDataChange = (v: any[]) => {
emit('update:value', {
[reportKey.value!]: v[0]?.value
[formModel.reportKey!]: v[0]?.value
})
}
const initRowKey = () => {
if (props.value.length) {
const keys = Object.keys(props.value)
reportKey.value = keys[0]
formModel.reportKey = keys[0]
}
}
defineExpose({
validateFields: () => new Promise(async (resolve) => {
const data = await writeForm.value?.validateFields()
resolve(data)
})
})
</script>
<style scoped>

View File

@ -14,6 +14,7 @@
<Title :options='data.options.trigger' />
</AddButton>
</a-form-item>
<Action />
<AddModel v-if='visible' @cancel='visible = false' v-model='data.device' v-model:options='data.options.trigger' />
</div>
</template>
@ -24,6 +25,7 @@ import { useSceneStore } from '@/store/scene'
import AddModel from './AddModal.vue'
import AddButton from '../components/AddButton.vue'
import Title from '../components/Title.vue'
import Action from '../action/index.vue'
const sceneStore = useSceneStore()
const { data } = storeToRefs<any>(sceneStore)

View File

@ -0,0 +1,63 @@
<template>
<j-modal
title="延迟执行"
visible
:width="400"
@cancel="onCancel"
@ok="onOk"
:maskClosable="false"
>
<a-input-number
style="max-width: 220px"
placeholder="请输入时间"
v-model:value="value"
:precision="3"
:min="0"
:max="6535"
>
<template #addonAfter>
<a-select
:options="[
{ label: '秒', value: 'seconds' },
{ label: '分', value: 'minutes' },
{ label: '小时', value: 'hours' },
]"
v-model:value="unit"
/>
</template>
</a-input-number>
</j-modal>
</template>
<script lang="ts" setup>
import { onlyMessage } from '@/utils/comm';
const timeUnitEnum = {
seconds: '秒',
minutes: '分',
hours: '小时',
};
const emit = defineEmits(['cancel', 'save']);
const value = ref<number>(0);
const unit = ref<'seconds' | 'minutes' | 'hours'>('seconds');
const onCancel = () => {
emit('cancel');
};
const onOk = () => {
if (unref(value) || unref(value) === 0) {
} else {
onlyMessage('请输入时间', 'error');
}
emit(
'save',
{
time: value.value,
unit: unit.value,
},
{ name: `${value.value} ${timeUnitEnum[unit.value]}后,执行后续动作` },
);
};
</script>

View File

@ -0,0 +1,22 @@
<template>
<j-modal
title="执行动作"
visible
:width="860"
@cancel="onCancel"
@ok="onOk"
:maskClosable="false"
>
device
</j-modal>
</template>
<script lang="ts" setup>
const emit = defineEmits(['cancel', 'save']);
const onCancel = () => {
emit('cancel');
};
const onOk = () => {
emit('save');
};
</script>

View File

@ -0,0 +1,3 @@
<template>
<div>ITEM</div>
</template>

View File

@ -0,0 +1,74 @@
<template>
<div class="action-list-content">
<div class="actions-add-list" :class="{'border': props.actions.length}">
<j-button type="primary" ghost style="width: 100%" @click="onAdd">
<template #icon><AIcon type="PlusOutlined" /></template>
添加执行动作
</j-button>
</div>
<Modal v-if="visible" @cancel="visible = false" />
</div>
</template>
<script lang="ts" setup>
import { PropType } from 'vue';
import { ActionsType, ParallelType } from '../../../typings';
import Modal from '../Modal/index.vue'
interface ListProps {
branchesName: number;
type: ParallelType;
actions: ActionsType[];
parallel: boolean;
}
const props = defineProps({
branchesName: Number,
type: {
type: String as PropType<ListProps['type']>,
default: 'serial',
},
actions: {
type: Array as PropType<ListProps['actions']>,
default: () => [],
},
parallel: Boolean,
});
const visible = ref<boolean>(false)
const onAdd = () => {
visible.value = true
}
</script>
<style lang="less" scoped>
.action-list-content {
padding: 8px;
.actions-list_form {
.action-list-add {
display: flex;
justify-content: flex-end;
margin-top: 16px;
padding-top: 16px;
border-top: 1px solid @primary-color;
}
}
.filter-add-button {
width: 100%;
color: rgba(0, 0, 0, 0.3);
text-align: center;
cursor: pointer;
}
.actions-add-list {
&.border {
padding-top: 16px;
border-top: 1px solid @primary-color;
}
}
}
</style>

View File

@ -0,0 +1,2 @@
export { default as List } from './List.vue';
export { default as Item } from './Item.vue';

View File

@ -0,0 +1,105 @@
<template>
<j-modal
title="类型"
visible
:width="860"
@cancel="onCancel"
@ok="onOk"
:maskClosable="false"
>
<a-form ref="actionForm" :model="formModel" layout="vertical">
<a-form-item
label="类型"
name="type"
:rules="[
{
required: true,
message: '请选择类型',
},
]"
>
<j-card-select
v-model:value="formModel.type"
:options="options"
type="horizontal"
float="right"
/>
</a-form-item>
<template v-if="actionType === 'device'">
<Device @cancel="onCancel" @save="onPropsOk" />
</template>
<template v-else-if="actionType === 'notify'">
<Notify @cancel="onCancel" @save="onPropsOk" />
</template>
<template v-else-if="actionType === 'delay'">
<Delay @cancel="onCancel" @save="onPropsOk" />
</template>
</a-form>
</j-modal>
</template>
<script lang="ts" setup>
import { getImage } from '@/utils/comm';
import Delay from '../Delay/index.vue'
import Notify from '../Notify/index.vue'
import Device from '../Device/index.vue'
const emit = defineEmits(['cancel', 'save']);
const options = [
{
label: '设备输出',
value: 'device',
iconUrl: getImage('/scene/device-type.png'),
subLabel: '配置设备调用功能、读取属性、设置属性规则',
},
{
label: '消息通知',
value: 'notify',
iconUrl: getImage('/scene/message-type.png'),
subLabel: '配置向指定用户发邮件、钉钉、微信、短信等通知',
},
{
label: '延迟执行',
value: 'delay',
iconUrl: getImage('/scene/delay-type.png'),
subLabel: '等待一段时间后,再执行后续动作',
},
{
label: '触发告警',
value: 'trigger',
iconUrl: getImage('/scene/trigger-type.png'),
subLabel: '配置触发告警规则,需配合“告警配置”使用',
},
{
label: '解除告警',
value: 'relieve',
iconUrl: getImage('/scene/cancel-type.png'),
subLabel: '配置解除告警规则,需配合“告警配置”使用',
},
];
const actionForm = ref();
const formModel = reactive({
type: '',
});
const actionType = ref<string>('')
const onCancel = () => {
emit('cancel');
};
const onOk = () => {
actionForm.value.validate().then((values: any) => {
actionType.value = values?.type
if (values?.type === 'relieve' || values?.type === 'trigger') {
// emit('save');
// props.save({ ...props.data, executor: 'alarm', alarm: { mode: values.type } }, {});
}
});
};
const onPropsOk = (data: any, option: any) => {
console.log(data, option)
}
</script>

View File

@ -0,0 +1,178 @@
<template>
<Search
:columns="columns"
type="simple"
target="action-notice-config"
@search="handleSearch"
class="search"
/>
<div style="height: 400px; overflow-y: auto">
<JTable
:columns="columns"
:request="ConfigApi.list"
model="CARD"
:bodyStyle="{
paddingRight: 0,
paddingLeft: 0,
}"
:defaultParams="{
terms: [
{
terms: [
{
termType: 'eq',
column: 'type',
value: props.notifyType,
},
],
},
],
sorts: [{ name: 'createTime', order: 'desc' }],
}"
:params="params"
:gridColumn="2"
:gridColumns="[2, 2, 2]"
:rowSelection="{
selectedRowKeys: _selectedRowKeys,
}"
@cancelSelect="cancelSelect"
>
<template #card="slotProps">
<CardBox
:showStatus="false"
:value="slotProps"
:showTool="false"
:actions="[]"
v-bind="slotProps"
@click="handleClick"
:active="_selectedRowKeys.includes(slotProps.id)"
>
<template #img>
<slot name="img">
<img
:src="
getLogo(slotProps.type, slotProps.provider)
"
class="logo"
/>
</slot>
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)">
<span style="font-size: 16px; font-weight: 600">
{{ slotProps.name }}
</span>
</Ellipsis>
<a-row>
<a-col :span="12">
<div class="card-item-content-text">
通知方式
</div>
<div>
{{ getMethodTxt(slotProps.type) }}
</div>
</a-col>
<a-col :span="12">
<div class="card-item-content-text">说明</div>
<Ellipsis>
{{ slotProps.description }}
</Ellipsis>
</a-col>
</a-row>
</template>
</CardBox>
</template>
</JTable>
</div>
</template>
<script lang="ts" setup>
import ConfigApi from '@/api/notice/config';
import { MSG_TYPE, NOTICE_METHOD } from '@/views/notice/const';
const props = defineProps({
notifyType: {
type: String,
default: '',
},
value: {
type: String,
default: '',
},
});
const emit = defineEmits(['update:value']);
const getLogo = (type: string, provider: string) => {
return MSG_TYPE[type].find((f: any) => f.value === provider)?.logo;
};
const getMethodTxt = (type: string) => {
return NOTICE_METHOD.find((f) => f.value === type)?.label;
};
const params = ref<Record<string, any>>({});
const _selectedRowKeys = ref<string[]>([]);
const columns = [
{
title: '名称',
dataIndex: 'name',
key: 'name',
search: {
type: 'string',
},
},
{
title: 'ID',
dataIndex: 'id',
key: 'id',
search: {
type: 'string',
},
},
{
title: '说明',
dataIndex: 'description',
key: 'description',
search: {
type: 'string',
},
},
];
const handleSearch = (_params: any) => {
params.value = _params;
};
const cancelSelect = () => {
_selectedRowKeys.value = [];
};
const handleClick = (dt: any) => {
_selectedRowKeys.value = [dt.id];
emit('update:value', dt.id);
};
watch(
() => props.value,
(newValue) => {
if (newValue) {
_selectedRowKeys.value = [newValue];
} else {
_selectedRowKeys.value = [];
}
},
{
deep: true,
immediate: true,
},
);
</script>
<style lang="less" scoped>
.search {
margin-bottom: 0;
padding-right: 0px;
padding-left: 0px;
}
</style>

View File

@ -0,0 +1,167 @@
<template>
<Search
:columns="columns"
type="simple"
target="action-notice-template"
@search="handleSearch"
class="search"
/>
<div style="height: 400px; overflow-y: auto">
<JTable
:columns="columns"
:request="(e) => TemplateApi.getListByConfigId(props.notifierId, e)"
model="CARD"
:bodyStyle="{
paddingRight: 0,
paddingLeft: 0,
}"
:defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }],
}"
:params="params"
:gridColumn="2"
:gridColumns="[2, 2, 2]"
:rowSelection="{
selectedRowKeys: _selectedRowKeys,
}"
@cancelSelect="cancelSelect"
>
<template #card="slotProps">
<CardBox
:showStatus="false"
:value="slotProps"
:showTool="false"
:actions="[]"
v-bind="slotProps"
@click="handleClick"
:active="_selectedRowKeys.includes(slotProps.id)"
>
<template #img>
<slot name="img">
<img
:src="
getLogo(slotProps.type, slotProps.provider)
"
class="logo"
/>
</slot>
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)">
<span style="font-size: 16px; font-weight: 600">
{{ slotProps.name }}
</span>
</Ellipsis>
<a-row>
<a-col :span="12">
<div class="card-item-content-text">
通知方式
</div>
<div>
{{ getMethodTxt(slotProps.type) }}
</div>
</a-col>
<a-col :span="12">
<div class="card-item-content-text">说明</div>
<Ellipsis>
{{ slotProps.description }}
</Ellipsis>
</a-col>
</a-row>
</template>
</CardBox>
</template>
</JTable>
</div>
</template>
<script lang="ts" setup>
import TemplateApi from '@/api/notice/template';
import { MSG_TYPE, NOTICE_METHOD } from '@/views/notice/const';
const props = defineProps({
notifierId: {
type: String,
default: '',
},
value: {
type: String,
default: '',
},
});
const emit = defineEmits(['update:value']);
const getLogo = (type: string, provider: string) => {
return MSG_TYPE[type].find((f: any) => f.value === provider)?.logo;
};
const getMethodTxt = (type: string) => {
return NOTICE_METHOD.find((f) => f.value === type)?.label;
};
const params = ref<Record<string, any>>({});
const _selectedRowKeys = ref<string[]>([]);
const columns = [
{
title: '名称',
dataIndex: 'name',
key: 'name',
search: {
type: 'string',
},
},
{
title: 'ID',
dataIndex: 'id',
key: 'id',
search: {
type: 'string',
},
},
{
title: '说明',
dataIndex: 'description',
key: 'description',
search: {
type: 'string',
},
},
];
const handleSearch = (_params: any) => {
params.value = _params;
};
const cancelSelect = () => {
_selectedRowKeys.value = [];
};
const handleClick = (dt: any) => {
_selectedRowKeys.value = [dt.id];
emit('update:value', dt.id);
};
watch(
() => props.value,
(newValue) => {
if (newValue) {
_selectedRowKeys.value = [newValue];
} else {
_selectedRowKeys.value = [];
}
},
{
deep: true,
immediate: true,
},
);
</script>
<style lang="less" scoped>
.search {
margin-bottom: 0;
padding-right: 0px;
padding-left: 0px;
}
</style>

View File

@ -0,0 +1,61 @@
<template>
<a-spin :spinning="loading">
<j-card-select
v-model:value="notifyType"
:options="options"
:icon-size="106"
/>
</a-spin>
</template>
<script lang="ts" setup>
import { getImage } from '@/utils/comm';
import notice from '@/api/notice/config';
const iconMap = new Map();
iconMap.set('dingTalk', getImage('/notice/dingtalk.png'));
iconMap.set('weixin', getImage('/notice/wechat.png'));
iconMap.set('email', getImage('/notice/email.png'));
iconMap.set('voice', getImage('/notice/voice.png'));
iconMap.set('sms', getImage('/notice/sms.png'));
iconMap.set('webhook', getImage('/notice/webhook.png'));
const props = defineProps({
value: {
type: String,
default: '',
},
});
const emit = defineEmits(['update:value'])
const loading = ref<boolean>(false);
const notifyType = ref('');
const options = ref<any[]>([]);
watch(
() => notifyType,
(newVal) => {
emit('update:value', newVal)
},
{ deep: true, immediate: true },
);
onMounted(() => {
notice.queryMessageType().then((resp) => {
if (resp.status === 200) {
options.value = (resp.result as any[]).map((item) => {
return {
label: item.name,
value: item.id,
iconUrl: iconMap.get(item.id),
};
});
}
});
notifyType.value = props.value
});
</script>
<style lang="less" scoped>
</style>

View File

@ -0,0 +1,70 @@
<template>
<a-form
v-if="variableDefinitions.length"
:layout="'vertical'"
ref="formRef"
:model="modelRef"
>
<template v-for="item in variableDefinitions" :key="item.id">
<a-form-item
:name="item.id"
:label="item.name"
:rules="[{ required: true, message: `请输入${item.name}` }]"
>
<User
v-if="getType(item) === 'user'"
v-model="modelRef[`${item.id}`]"
/>
<Org
v-else-if="getType(item) === 'org'"
v-model="modelRef[`${item.id}`]"
/>
<Tag
v-else-if="getType(item) === 'tag'"
v-model="modelRef[`${item.id}`]"
/>
<InputFile
v-else-if="getType(item) === 'file'"
v-model="modelRef[`${item.id}`]"
/>
<a-input
v-else-if="getType(item) === 'link'"
v-model="modelRef[`${item.id}`]"
/>
<BuildIn
v-else
v-model="modelRef[`${item.id}`]"
/>
</a-form-item>
</template>
</a-form>
</template>
<script lang="ts" setup>
import BuildIn from './variableItem/BuildIn.vue';
import Org from './variableItem/Org.vue';
import Tag from './variableItem/Tag.vue';
import InputFile from './variableItem/InputFile.vue';
import User from './variableItem/User.vue';
const props = defineProps({
variableDefinitions: {
type: Array,
default: () => [],
},
value: {
type: Object,
default: () => {},
},
});
const formRef = ref();
const modelRef = reactive({});
Object.assign(formRef, props.value);
const getType = (item: any) => {
return item.expands?.businessType || item.type;
};
</script>

View File

@ -0,0 +1,146 @@
<template>
<j-modal
title="执行动作"
visible
:width="860"
@cancel="onCancel"
@ok="onOk"
:maskClosable="false"
>
<div class="steps-steps">
<a-steps :current="current" size="small" @change="onChange">
<a-step title="通知方式" key="way" />
<a-step title="通知配置" key="config" />
<a-step title="通知模板" key="template" />
<a-step title="模板变量" key="variable" />
</a-steps>
</div>
<div class="steps-content">
<a-form ref="actionForm" :model="formModel" layout="vertical">
<template v-if="current === 0">
<a-form-item
label="应用"
name="notifyType"
:rules="[
{
required: true,
message: '请选择通知方式',
},
]"
>
<NotifyWay v-model:value="formModel.notifyType" />
</a-form-item>
</template>
<template v-if="current === 1">
<a-form-item name="notifierId">
<NotifyConfig v-model:value="formModel.notifierId" :notifyType="formModel.notifyType" />
</a-form-item>
</template>
<template v-if="current === 2">
<a-form-item name="templateId">
<NotifyTemplate v-model:value="formModel.templateId" :notifierId="formModel.notifierId" />
</a-form-item>
</template>
<template v-if="current === 3">
<a-form-item name="variables">
<VariableDefinitions
:variableDefinitions="variable"
v-model:value="formModel.variables"
/>
</a-form-item>
</template>
</a-form>
</div>
<template #footer>
<a-space>
<j-button v-if="current === 0" @click="onCancel">取消</j-button>
<j-button v-if="current > 0" @click="prev">上一步</j-button>
<j-button v-if="current < 3" type="primary" @click="next">下一步</j-button>
<j-button v-if="current === 3" type="primary" @click="onOk">确定</j-button>
</a-space>
</template>
</j-modal>
</template>
<script lang="ts" setup>
import NotifyWay from './NotifyWay.vue';
import NotifyConfig from './NotifyConfig.vue';
import NotifyTemplate from './NotifyTemplate.vue';
import VariableDefinitions from './VariableDefinitions.vue';
import { onlyMessage } from '@/utils/comm';
import Template from '@/api/notice/template';
const emit = defineEmits(['cancel', 'save']);
const current = ref(0);
const formModel = reactive({
notifyType: '',
notifierId: '',
templateId: '',
variables: [],
});
const variable = ref([]);
const jumpStep = async (val: number) => {
if (val === 0) {
current.value = val;
} else if (val === 1) {
if (formModel.notifyType) {
current.value = val
} else {
onlyMessage('请选择通知方式', 'error');
}
} else if (val === 2) {
if (formModel.notifierId) {
current.value = val
} else {
onlyMessage('请选择通知配置', 'error');
}
} else if (val === 3) {
formModel.templateId = '1628943618904956928'
if (formModel.templateId) {
const resp = await Template.getTemplateDetail(formModel.templateId);
if (resp.status === 200) {
variable.value = resp.result?.variableDefinitions || [];
current.value = val
}
} else {
onlyMessage('请选择通知模板', 'error');
}
}
};
const onChange = (cur: number) => {
jumpStep(cur)
};
const prev = () => {
current.value -= 1;
};
const next = async () => {
jumpStep(current.value + 1)
};
const onCancel = () => {
emit('cancel');
};
const onOk = () => {
emit('save');
};
</script>
<style lang="less" scoped>
.steps-steps {
width: 100%;
margin-bottom: 17px;
padding-bottom: 17px;
border-bottom: 1px solid #f0f0f0;
}
.steps-content {
width: 100%;
}
</style>

View File

@ -0,0 +1,3 @@
<template>
build-in
</template>

View File

@ -0,0 +1,3 @@
<template>
input-file
</template>

View File

@ -0,0 +1,3 @@
<template>
org
</template>

View File

@ -0,0 +1,3 @@
<template>
tag
</template>

View File

@ -0,0 +1,3 @@
<template>
user
</template>

View File

@ -0,0 +1,133 @@
<template>
<div class="actions">
<div class="actions-title">
<span>执行</span>
<ShakeLimit
v-if="props.openShakeLimit"
v-model:value="shakeLimit"
/>
</div>
<div class="actions-warp">
<a-collapse v-model:activeKey="activeKeys">
<a-collapse-panel key="1">
<template #header>
<span>
串行
<span class="panel-tip">
按顺序依次执行动作适用于基于动作输出参数判断是否执行后续动作的场景
</span>
</span>
</template>
<div class="actions-list">
<List
type="serial"
:branchesName="props.name"
:parallel="false"
:actions="serialArray.length ? serialArray[0].actions : []"
/>
</div>
</a-collapse-panel>
<a-collapse-panel key="2">
<template #header>
<span>
并行
<span class="panel-tip">
同时执行所有动作适用于不需要关注执行动作先后顺序和结果的场景
</span>
</span>
</template>
<div class="actions-list">
<List
type="parallel"
:branchesName="props.name"
:parallel="true"
:actions="parallelArray.length ? parallelArray[0].actions : []"
/>
</div>
</a-collapse-panel>
</a-collapse>
</div>
</div>
</template>
<script lang="ts" setup>
import ShakeLimit from '../components/ShakeLimit/index.vue';
import { List } from './ListItem';
import { storeToRefs } from 'pinia';
import { useSceneStore } from '@/store/scene';
import { BranchesThen } from '../../typings';
import { PropType } from 'vue';
interface ActionsProps {
name: number;
openShakeLimit?: boolean;
thenOptions: BranchesThen[];
}
const props = defineProps({
name: Number,
thenOptions: {
type: Array as PropType<ActionsProps['thenOptions']>,
default: () => [],
},
openShakeLimit: Boolean,
});
const shakeLimit = ref({});
const activeKeys = ref<string[]>(['1']);
const parallelArray = ref<BranchesThen[]>([]);
const serialArray = ref<BranchesThen[]>([]);
const lock = ref<boolean>(false)
watch(
() => props.thenOptions,
(newVal) => {
parallelArray.value = newVal.filter((item) => item.parallel);
serialArray.value = newVal.filter((item) => !item.parallel);
const isSerialActions = serialArray.value.some((item) => {
return !!item.actions.length;
});
if (
!lock.value &&
parallelArray.value.length &&
(!serialArray.value.length || !isSerialActions)
) {
activeKeys.value = ['2']
lock.value = true
}
//TODO
},
{
deep: true,
immediate: true,
},
);
</script>
<style lang="less" scoped>
.actions {
.actions-title {
display: flex;
gap: 16px;
align-items: center;
margin-bottom: 16px;
font-weight: 800;
font-size: 14px;
line-height: 32px;
}
.actions-warp {
.actions-list {
width: 100%;
}
}
.panel-tip {
padding-left: 8px;
color: rgba(#000, 0.45);
}
}
</style>

View File

@ -1,7 +1,10 @@
<template>
<a-table
<j-table
model='TABLE'
:noPagination='true'
:data-source='dataSource.value'
:columns='columns'
:bodyStyle='{ padding: 0}'
>
<template #bodyCell="{ column, record, index }">
<template v-if='column.dataIndex === "name"'>
@ -33,7 +36,7 @@
/>
</template>
</template>
</a-table>
</j-table>
</template>
<script setup lang='ts' name='FunctionCall'>
@ -61,13 +64,6 @@ const dataSource = reactive<{value: any[]}>({
value: []
})
watch(() => props.data, () => {
dataSource.value = props.data.map((item: any) => {
const oldValue = props.value.find((oldItem: any) => oldItem.name === item.id)
return oldValue ? { ...item, value: oldValue.value } : item
})
}, { immediate: true })
const columns = [
{
title: '参数名称',
@ -99,6 +95,13 @@ const handleOptions = (record: any) => {
}
}
watch(() => props.data, () => {
dataSource.value = props.data.map((item: any) => {
const oldValue = props.value.find((oldItem: any) => oldItem.name === item.id)
return oldValue ? { ...item, value: oldValue.value } : item
})
}, { immediate: true })
watch(() => dataSource.value, () => {
const _value = dataSource.value.map(item => ({
name: item.id, value: item.value

View File

@ -0,0 +1,85 @@
<template>
<div class="shakeLimit">
<a-switch
checkedChildren="开启防抖"
unCheckedChildren="关闭防抖"
v-model:checked="shakeLimit.enabled"
style="margin-right: 12px"
/>
<template v-if="shakeLimit.enabled">
<a-input-number :min="1" :max="100" :precision="0" size="small" v-model:value="shakeLimit.time" style="width: 32px" />
<span>秒内发送</span>
<a-input-number :min="1" :max="100" :precision="0" size="small" v-model:value="shakeLimit.threshold" style="width: 32px" />
<span>次及以上时处理</span>
<a-radio-group :options="alarmFirstOptions" optionType="button" v-model:value="shakeLimit.alarmFirst" size="small" />
</template>
</div>
</template>
<script lang="ts" setup>
import { cloneDeep } from "lodash-es";
import { PropType } from "vue";
type ShakeLimitType = {
enabled: boolean | undefined,
time?: number | undefined | null,
threshold?: number | undefined | null,
alarmFirst?: boolean | undefined
}
type Emit = {
(e: 'update:value', data: ShakeLimitType): void
}
const alarmFirstOptions = [
{ label: '第一次', value: true },
{ label: '最后一次', value: false },
];
const props = defineProps({
value: {
type: Object as PropType<ShakeLimitType>,
default: () => ({})
}
})
const emit = defineEmits<Emit>()
const shakeLimit = reactive<ShakeLimitType>({
enabled: undefined,
time: 1,
threshold: 1,
alarmFirst: undefined
})
Object.assign(shakeLimit, props.value)
watch(() => shakeLimit, () => {
const cloneValue = cloneDeep(shakeLimit)
emit('update:value', cloneValue)
}, {
deep: true
})
</script>
<style lang="less" scoped>
.shakeLimit {
display: flex;
gap: 4px;
align-items: center;
font-weight: 400;
font-size: 14px;
:deep(.ant-input-number-handler-wrap) {
display: none;
}
:deep(.ant-radio-button-wrapper) {
padding: 0 16px;
}
input {
padding: 0 4px;
}
}
</style>

View File

@ -108,6 +108,7 @@ import WhenOption from './WhenOption.vue'
import { cloneDeep } from 'lodash-es'
import type { OperationTimer } from '../../../typings'
import { isCron } from '@/utils/regular'
import { defineExpose } from 'vue'
type NameType = string[] | string
@ -143,6 +144,7 @@ const formModel = reactive<OperationTimer>({
unit: 'seconds'
}
})
const timerForm = ref()
Object.assign(formModel, props.value)
@ -174,6 +176,13 @@ watch(() => formModel, () => {
emit('update:value', cloneValue)
}, { deep: true })
defineExpose({
validateFields: () => new Promise(async (resolve) => {
const data = await timerForm.value?.validateFields()
resolve(data)
})
})
</script>
<style scoped lang='less'>

View File

@ -1,7 +1,7 @@
<template>
<page-container>
<Search :columns="columns" target="scene" @search="handleSearch" />
<JTable
<JProTable
ref="sceneRef"
:columns="columns"
:request="query"
@ -9,7 +9,7 @@
:params="params"
>
<template #headerTitle>
<a-space>
<j-space>
<PermissionButton
type="primary"
@click="handleAdd"
@ -18,7 +18,7 @@
<template #icon><AIcon type="PlusOutlined" /></template>
新增
</PermissionButton>
</a-space>
</j-space>
</template>
<template #card="slotProps">
<SceneCard
@ -90,13 +90,13 @@
{{ typeMap.get(slotProps.triggerType)?.text }}
</template>
<template #state="slotProps">
<a-badge
<j-badge
:text="slotProps.state?.text"
:status="statusMap.get(slotProps.state?.value)"
/>
</template>
<template #action="slotProps">
<a-space>
<j-space>
<template
v-for="i in getActions(slotProps, 'table')"
:key="i.key"
@ -115,9 +115,9 @@
<template #icon><AIcon :type="i.icon" /></template>
</PermissionButton>
</template>
</a-space>
</j-space>
</template>
</JTable>
</JProTable>
<SaveModal v-if="visible" @close="visible = false" :data="current" />
</page-container>
</template>

View File

@ -92,7 +92,7 @@
:type="
slotProps.status
? 'StopOutlined'
: 'PlayCircleOutlined '
: 'PlayCircleOutlined'
"
/>
</PermissionButton>

458
yarn.lock
View File

@ -36,19 +36,19 @@
"@ant-design/colors@^6.0.0":
version "6.0.0"
resolved "https://registry.jetlinks.cn/@ant-design%2fcolors/-/colors-6.0.0.tgz#9b9366257cffcc47db42b9d0203bb592c13c0298"
resolved "https://registry.npmjs.org/@ant-design/colors/-/colors-6.0.0.tgz"
integrity sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==
dependencies:
"@ctrl/tinycolor" "^3.4.0"
"@ant-design/icons-svg@^4.2.1":
version "4.2.1"
resolved "https://registry.jetlinks.cn/@ant-design%2ficons-svg/-/icons-svg-4.2.1.tgz#8630da8eb4471a4aabdaed7d1ff6a97dcb2cf05a"
resolved "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.2.1.tgz"
integrity sha512-EB0iwlKDGpG93hW8f85CTJTs4SvMX7tt5ceupvhALp1IF44SeUFOMhKUOYqpsoYWQKAOuTRDMqn75rEaKDp0Xw==
"@ant-design/icons-vue@^6.1.0":
version "6.1.0"
resolved "https://registry.jetlinks.cn/@ant-design%2ficons-vue/-/icons-vue-6.1.0.tgz#f9324fdc0eb4cea943cf626d2bf3db9a4ff4c074"
resolved "https://registry.npmjs.org/@ant-design/icons-vue/-/icons-vue-6.1.0.tgz"
integrity sha512-EX6bYm56V+ZrKN7+3MT/ubDkvJ5rK/O2t380WFRflDcVFgsvl3NLH7Wxeau6R8DbrO5jWR6DSTC3B6gYFp77AA==
dependencies:
"@ant-design/colors" "^6.0.0"
@ -288,9 +288,9 @@
"@babel/plugin-syntax-typescript" "^7.20.0"
"@babel/runtime@^7.10.5":
version "7.21.0"
resolved "https://registry.jetlinks.cn/@babel%2fruntime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673"
integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==
version "7.20.7"
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.7.tgz"
integrity sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==
dependencies:
regenerator-runtime "^0.13.11"
@ -502,9 +502,9 @@
"@jridgewell/trace-mapping" "0.3.9"
"@ctrl/tinycolor@^3.4.0":
version "3.6.0"
resolved "https://registry.jetlinks.cn/@ctrl%2ftinycolor/-/tinycolor-3.6.0.tgz#53fa5fe9c34faee89469e48f91d51a3766108bc8"
integrity sha512-/Z3l6pXthq0JvMYdUFyX9j0MaCltlIn6mfh9jLyQwg5aPKxkyNa0PTHtU1AlFXLNk55ZuAeJRcpvq+tmLfKmaQ==
version "3.5.0"
resolved "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.5.0.tgz"
integrity sha512-tlJpwF40DEQcfR/QF+wNMVyGMaO9FQp6Z1Wahj4Gk3CJQYHwA2xVG7iKDFdW6zuxZY9XWOpGcfNCTsX4McOsOg==
"@esbuild/android-arm64@0.16.12":
version "0.16.12"
@ -855,107 +855,6 @@
node-gyp "^7.1.0"
read-package-json-fast "^2.0.1"
"@octokit/auth-token@^2.4.4":
version "2.5.0"
resolved "https://registry.npmmirror.com/@octokit/auth-token/-/auth-token-2.5.0.tgz#27c37ea26c205f28443402477ffd261311f21e36"
integrity sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==
dependencies:
"@octokit/types" "^6.0.3"
"@octokit/core@^3.5.1":
version "3.6.0"
resolved "https://registry.npmmirror.com/@octokit/core/-/core-3.6.0.tgz#3376cb9f3008d9b3d110370d90e0a1fcd5fe6085"
integrity sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==
dependencies:
"@octokit/auth-token" "^2.4.4"
"@octokit/graphql" "^4.5.8"
"@octokit/request" "^5.6.3"
"@octokit/request-error" "^2.0.5"
"@octokit/types" "^6.0.3"
before-after-hook "^2.2.0"
universal-user-agent "^6.0.0"
"@octokit/endpoint@^6.0.1":
version "6.0.12"
resolved "https://registry.npmmirror.com/@octokit/endpoint/-/endpoint-6.0.12.tgz#3b4d47a4b0e79b1027fb8d75d4221928b2d05658"
integrity sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==
dependencies:
"@octokit/types" "^6.0.3"
is-plain-object "^5.0.0"
universal-user-agent "^6.0.0"
"@octokit/graphql@^4.5.8":
version "4.8.0"
resolved "https://registry.npmmirror.com/@octokit/graphql/-/graphql-4.8.0.tgz#664d9b11c0e12112cbf78e10f49a05959aa22cc3"
integrity sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==
dependencies:
"@octokit/request" "^5.6.0"
"@octokit/types" "^6.0.3"
universal-user-agent "^6.0.0"
"@octokit/openapi-types@^12.11.0":
version "12.11.0"
resolved "https://registry.npmmirror.com/@octokit/openapi-types/-/openapi-types-12.11.0.tgz#da5638d64f2b919bca89ce6602d059f1b52d3ef0"
integrity sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==
"@octokit/plugin-paginate-rest@^2.16.8":
version "2.21.3"
resolved "https://registry.npmmirror.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz#7f12532797775640dbb8224da577da7dc210c87e"
integrity sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==
dependencies:
"@octokit/types" "^6.40.0"
"@octokit/plugin-request-log@^1.0.4":
version "1.0.4"
resolved "https://registry.npmmirror.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz#5e50ed7083a613816b1e4a28aeec5fb7f1462e85"
integrity sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==
"@octokit/plugin-rest-endpoint-methods@^5.12.0":
version "5.16.2"
resolved "https://registry.npmmirror.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz#7ee8bf586df97dd6868cf68f641354e908c25342"
integrity sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==
dependencies:
"@octokit/types" "^6.39.0"
deprecation "^2.3.1"
"@octokit/request-error@^2.0.5", "@octokit/request-error@^2.1.0":
version "2.1.0"
resolved "https://registry.npmmirror.com/@octokit/request-error/-/request-error-2.1.0.tgz#9e150357831bfc788d13a4fd4b1913d60c74d677"
integrity sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==
dependencies:
"@octokit/types" "^6.0.3"
deprecation "^2.0.0"
once "^1.4.0"
"@octokit/request@^5.6.0", "@octokit/request@^5.6.3":
version "5.6.3"
resolved "https://registry.npmmirror.com/@octokit/request/-/request-5.6.3.tgz#19a022515a5bba965ac06c9d1334514eb50c48b0"
integrity sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==
dependencies:
"@octokit/endpoint" "^6.0.1"
"@octokit/request-error" "^2.1.0"
"@octokit/types" "^6.16.1"
is-plain-object "^5.0.0"
node-fetch "^2.6.7"
universal-user-agent "^6.0.0"
"@octokit/rest@^18":
version "18.12.0"
resolved "https://registry.npmmirror.com/@octokit/rest/-/rest-18.12.0.tgz#f06bc4952fc87130308d810ca9d00e79f6988881"
integrity sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==
dependencies:
"@octokit/core" "^3.5.1"
"@octokit/plugin-paginate-rest" "^2.16.8"
"@octokit/plugin-request-log" "^1.0.4"
"@octokit/plugin-rest-endpoint-methods" "^5.12.0"
"@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.39.0", "@octokit/types@^6.40.0":
version "6.41.0"
resolved "https://registry.npmmirror.com/@octokit/types/-/types-6.41.0.tgz#e58ef78d78596d2fb7df9c6259802464b5f84a04"
integrity sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==
dependencies:
"@octokit/openapi-types" "^12.11.0"
"@rollup/pluginutils@^4.1.2", "@rollup/pluginutils@^4.2.0":
version "4.2.1"
resolved "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz"
@ -975,7 +874,7 @@
"@simonwep/pickr@~1.8.0":
version "1.8.2"
resolved "https://registry.jetlinks.cn/@simonwep%2fpickr/-/pickr-1.8.2.tgz#96dc86675940d7cad63d69c22083dd1cbb9797cb"
resolved "https://registry.npmjs.org/@simonwep/pickr/-/pickr-1.8.2.tgz"
integrity sha512-/l5w8BIkrpP6n1xsetx9MWPWlU6OblN5YgZZphxan0Tq4BByTCETL6lyIeY8lagalS2Nbt4F2W034KHLIiunKA==
dependencies:
core-js "^3.15.1"
@ -1028,14 +927,6 @@
resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz"
integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==
"@types/glob@*":
version "8.1.0"
resolved "https://registry.npmmirror.com/@types/glob/-/glob-8.1.0.tgz#b63e70155391b0584dce44e7ea25190bbc38f2fc"
integrity sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==
dependencies:
"@types/minimatch" "^5.1.2"
"@types/node" "*"
"@types/lodash-es@^4.17.6":
version "4.17.6"
resolved "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.6.tgz"
@ -1053,11 +944,6 @@
resolved "https://registry.npmjs.org/@types/marked/-/marked-4.0.8.tgz"
integrity sha512-HVNzMT5QlWCOdeuBsgXP8EZzKUf0+AXzN+sLmjvaB3ZlLqO+e4u0uXrdw9ub69wBKFs+c6/pA4r9sy6cCDvImw==
"@types/minimatch@^5.1.2":
version "5.1.2"
resolved "https://registry.npmmirror.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca"
integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==
"@types/minimist@^1.2.0":
version "1.2.2"
resolved "https://registry.npmmirror.com/@types/minimist/-/minimist-1.2.2.tgz"
@ -1080,14 +966,6 @@
resolved "https://registry.npmmirror.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz"
integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==
"@types/shelljs@^0.8.11":
version "0.8.11"
resolved "https://registry.npmmirror.com/@types/shelljs/-/shelljs-0.8.11.tgz#17a5696c825974e96828e96e89585d685646fcb8"
integrity sha512-x9yaMvEh5BEaZKeVQC4vp3l+QoFj3BXcd4aYfuKSzIIyihjdVARAadYy3SMNIz0WCCdS2vB9JL/U6GQk5PaxQw==
dependencies:
"@types/glob" "*"
"@types/node" "*"
"@types/three@0.143.0":
version "0.143.0"
resolved "https://registry.npmjs.org/@types/three/-/three-0.143.0.tgz"
@ -1194,16 +1072,6 @@
estree-walker "^2.0.2"
source-map "^0.6.1"
"@vue/compiler-core@3.2.47":
version "3.2.47"
resolved "https://registry.jetlinks.cn/@vue%2fcompiler-core/-/compiler-core-3.2.47.tgz#3e07c684d74897ac9aa5922c520741f3029267f8"
integrity sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==
dependencies:
"@babel/parser" "^7.16.4"
"@vue/shared" "3.2.47"
estree-walker "^2.0.2"
source-map "^0.6.1"
"@vue/compiler-dom@3.2.45", "@vue/compiler-dom@^3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.45.tgz"
@ -1212,14 +1080,6 @@
"@vue/compiler-core" "3.2.45"
"@vue/shared" "3.2.45"
"@vue/compiler-dom@3.2.47":
version "3.2.47"
resolved "https://registry.jetlinks.cn/@vue%2fcompiler-dom/-/compiler-dom-3.2.47.tgz#a0b06caf7ef7056939e563dcaa9cbde30794f305"
integrity sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==
dependencies:
"@vue/compiler-core" "3.2.47"
"@vue/shared" "3.2.47"
"@vue/compiler-sfc@3.2.45", "@vue/compiler-sfc@^3.2.29", "@vue/compiler-sfc@^3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.45.tgz"
@ -1236,22 +1096,6 @@
postcss "^8.1.10"
source-map "^0.6.1"
"@vue/compiler-sfc@3.2.47":
version "3.2.47"
resolved "https://registry.jetlinks.cn/@vue%2fcompiler-sfc/-/compiler-sfc-3.2.47.tgz#1bdc36f6cdc1643f72e2c397eb1a398f5004ad3d"
integrity sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==
dependencies:
"@babel/parser" "^7.16.4"
"@vue/compiler-core" "3.2.47"
"@vue/compiler-dom" "3.2.47"
"@vue/compiler-ssr" "3.2.47"
"@vue/reactivity-transform" "3.2.47"
"@vue/shared" "3.2.47"
estree-walker "^2.0.2"
magic-string "^0.25.7"
postcss "^8.1.10"
source-map "^0.6.1"
"@vue/compiler-ssr@3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.45.tgz"
@ -1260,14 +1104,6 @@
"@vue/compiler-dom" "3.2.45"
"@vue/shared" "3.2.45"
"@vue/compiler-ssr@3.2.47":
version "3.2.47"
resolved "https://registry.jetlinks.cn/@vue%2fcompiler-ssr/-/compiler-ssr-3.2.47.tgz#35872c01a273aac4d6070ab9d8da918ab13057ee"
integrity sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==
dependencies:
"@vue/compiler-dom" "3.2.47"
"@vue/shared" "3.2.47"
"@vue/devtools-api@^6.4.5":
version "6.4.5"
resolved "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.4.5.tgz"
@ -1284,17 +1120,6 @@
estree-walker "^2.0.2"
magic-string "^0.25.7"
"@vue/reactivity-transform@3.2.47":
version "3.2.47"
resolved "https://registry.jetlinks.cn/@vue%2freactivity-transform/-/reactivity-transform-3.2.47.tgz#e45df4d06370f8abf29081a16afd25cffba6d84e"
integrity sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==
dependencies:
"@babel/parser" "^7.16.4"
"@vue/compiler-core" "3.2.47"
"@vue/shared" "3.2.47"
estree-walker "^2.0.2"
magic-string "^0.25.7"
"@vue/reactivity@3.2.45", "@vue/reactivity@^3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.45.tgz"
@ -1302,13 +1127,6 @@
dependencies:
"@vue/shared" "3.2.45"
"@vue/reactivity@3.2.47":
version "3.2.47"
resolved "https://registry.jetlinks.cn/@vue%2freactivity/-/reactivity-3.2.47.tgz#1d6399074eadfc3ed35c727e2fd707d6881140b6"
integrity sha512-7khqQ/75oyyg+N/e+iwV6lpy1f5wq759NdlS1fpAhFXa8VeAIKGgk2E/C4VF59lx5b+Ezs5fpp/5WsRYXQiKxQ==
dependencies:
"@vue/shared" "3.2.47"
"@vue/runtime-core@3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.45.tgz"
@ -1317,14 +1135,6 @@
"@vue/reactivity" "3.2.45"
"@vue/shared" "3.2.45"
"@vue/runtime-core@3.2.47":
version "3.2.47"
resolved "https://registry.jetlinks.cn/@vue%2fruntime-core/-/runtime-core-3.2.47.tgz#406ebade3d5551c00fc6409bbc1eeb10f32e121d"
integrity sha512-RZxbLQIRB/K0ev0K9FXhNbBzT32H9iRtYbaXb0ZIz2usLms/D55dJR2t6cIEUn6vyhS3ALNvNthI+Q95C+NOpA==
dependencies:
"@vue/reactivity" "3.2.47"
"@vue/shared" "3.2.47"
"@vue/runtime-dom@3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.45.tgz"
@ -1334,15 +1144,6 @@
"@vue/shared" "3.2.45"
csstype "^2.6.8"
"@vue/runtime-dom@3.2.47":
version "3.2.47"
resolved "https://registry.jetlinks.cn/@vue%2fruntime-dom/-/runtime-dom-3.2.47.tgz#93e760eeaeab84dedfb7c3eaf3ed58d776299382"
integrity sha512-ArXrFTjS6TsDei4qwNvgrdmHtD930KgSKGhS5M+j8QxXrDJYLqYw4RRcDy1bz1m1wMmb6j+zGLifdVHtkXA7gA==
dependencies:
"@vue/runtime-core" "3.2.47"
"@vue/shared" "3.2.47"
csstype "^2.6.8"
"@vue/server-renderer@3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.45.tgz"
@ -1351,24 +1152,11 @@
"@vue/compiler-ssr" "3.2.45"
"@vue/shared" "3.2.45"
"@vue/server-renderer@3.2.47":
version "3.2.47"
resolved "https://registry.jetlinks.cn/@vue%2fserver-renderer/-/server-renderer-3.2.47.tgz#8aa1d1871fc4eb5a7851aa7f741f8f700e6de3c0"
integrity sha512-dN9gc1i8EvmP9RCzvneONXsKfBRgqFeFZLurmHOveL7oH6HiFXJw5OGu294n1nHc/HMgTy6LulU/tv5/A7f/LA==
dependencies:
"@vue/compiler-ssr" "3.2.47"
"@vue/shared" "3.2.47"
"@vue/shared@3.2.45", "@vue/shared@^3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.2.45.tgz"
integrity sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg==
"@vue/shared@3.2.47":
version "3.2.47"
resolved "https://registry.jetlinks.cn/@vue%2fshared/-/shared-3.2.47.tgz#e597ef75086c6e896ff5478a6bfc0a7aa4bbd14c"
integrity sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==
"@vuemap/layer-3dtiles@^0.0.3":
version "0.0.3"
resolved "https://registry.npmjs.org/@vuemap/layer-3dtiles/-/layer-3dtiles-0.0.3.tgz"
@ -1399,13 +1187,13 @@
"@vueuse/core@^7.5.5":
version "7.7.1"
resolved "https://registry.jetlinks.cn/@vueuse%2fcore/-/core-7.7.1.tgz#fc284f4103de73c7fb79bc06579d8066790db511"
resolved "https://registry.jetlinks.cn/@vueuse%2fcore/-/core-7.7.1.tgz"
integrity sha512-PRRgbATMpoeUmkCEBtUeJgOwtew8s+4UsEd+Pm7MhkjL2ihCNrSqxNVtM6NFE4uP2sWnkGcZpCjPuNSxowJ1Ow==
dependencies:
"@vueuse/shared" "7.7.1"
vue-demi "*"
"@vueuse/core@^9.10.0":
"@vueuse/core@^9.10.0", "@vueuse/core@^9.12.0":
version "9.12.0"
resolved "https://registry.npmmirror.com/@vueuse/core/-/core-9.12.0.tgz"
integrity sha512-h/Di8Bvf6xRcvS/PvUVheiMYYz3U0tH3X25YxONSaAUBa841ayMwxkuzx/DGUMCW/wHWzD8tRy2zYmOC36r4sg==
@ -1415,29 +1203,14 @@
"@vueuse/shared" "9.12.0"
vue-demi "*"
"@vueuse/core@^9.12.0":
version "9.13.0"
resolved "https://registry.jetlinks.cn/@vueuse%2fcore/-/core-9.13.0.tgz#2f69e66d1905c1e4eebc249a01759cf88ea00cf4"
integrity sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==
dependencies:
"@types/web-bluetooth" "^0.0.16"
"@vueuse/metadata" "9.13.0"
"@vueuse/shared" "9.13.0"
vue-demi "*"
"@vueuse/metadata@9.12.0":
version "9.12.0"
resolved "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.12.0.tgz"
integrity sha512-9oJ9MM9lFLlmvxXUqsR1wLt1uF7EVbP5iYaHJYqk+G2PbMjY6EXvZeTjbdO89HgoF5cI6z49o2zT/jD9SVoNpQ==
"@vueuse/metadata@9.13.0":
version "9.13.0"
resolved "https://registry.jetlinks.cn/@vueuse%2fmetadata/-/metadata-9.13.0.tgz#bc25a6cdad1b1a93c36ce30191124da6520539ff"
integrity sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==
"@vueuse/shared@7.7.1":
version "7.7.1"
resolved "https://registry.jetlinks.cn/@vueuse%2fshared/-/shared-7.7.1.tgz#77e312de7275380efce86b0079bd7938791a076b"
resolved "https://registry.jetlinks.cn/@vueuse%2fshared/-/shared-7.7.1.tgz"
integrity sha512-rN2qd22AUl7VdBxihagWyhUNHCyVk9IpvBTTfHoLH9G7rGE552X1f+zeCfehuno0zXif13jPw+icW/wn2a0rnQ==
dependencies:
vue-demi "*"
@ -1449,13 +1222,6 @@
dependencies:
vue-demi "*"
"@vueuse/shared@9.13.0":
version "9.13.0"
resolved "https://registry.jetlinks.cn/@vueuse%2fshared/-/shared-9.13.0.tgz#089ff4cc4e2e7a4015e57a8f32e4b39d096353b9"
integrity sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==
dependencies:
vue-demi "*"
JSONStream@^1.0.4:
version "1.3.5"
resolved "https://registry.npmmirror.com/JSONStream/-/JSONStream-1.3.5.tgz"
@ -1605,7 +1371,7 @@ ansistyles@~0.1.3:
ant-design-vue@^3.2.15:
version "3.2.15"
resolved "https://registry.jetlinks.cn/ant-design-vue/-/ant-design-vue-3.2.15.tgz#eab52877fa08a9e4c8cb311ea479a90203dcb302"
resolved "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-3.2.15.tgz"
integrity sha512-sJfE7LWimSdAPe4dzNyQBrmVMnOTNQTkG9oOyr+7W8qIYrX8sYWyC68Nn1uum4KBJUSZUa/BU6dohvTG0urBhA==
dependencies:
"@ant-design/colors" "^6.0.0"
@ -1682,7 +1448,7 @@ array-ify@^1.0.0:
array-tree-filter@^2.1.0:
version "2.1.0"
resolved "https://registry.jetlinks.cn/array-tree-filter/-/array-tree-filter-2.1.0.tgz#873ac00fec83749f255ac8dd083814b4f6329190"
resolved "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-2.1.0.tgz"
integrity sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==
arrify@^1.0.1:
@ -1714,7 +1480,7 @@ astral-regex@^2.0.0:
async-validator@^4.0.0:
version "4.2.5"
resolved "https://registry.jetlinks.cn/async-validator/-/async-validator-4.2.5.tgz#c96ea3332a521699d0afaaceed510a54656c6339"
resolved "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz"
integrity sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==
async@^1.5.2:
@ -1784,11 +1550,6 @@ bcrypt-pbkdf@^1.0.0:
dependencies:
tweetnacl "^0.14.3"
before-after-hook@^2.2.0:
version "2.2.3"
resolved "https://registry.npmmirror.com/before-after-hook/-/before-after-hook-2.2.3.tgz#c51e809c81a4e354084422b9b26bad88249c517c"
integrity sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==
bin-links@^2.2.1:
version "2.3.0"
resolved "https://registry.jetlinks.cn/bin-links/-/bin-links-2.3.0.tgz#1ff241c86d2c29b24ae52f49544db5d78a4eb967"
@ -2013,7 +1774,7 @@ chalk@^3.0.0:
chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.2:
version "4.1.2"
resolved "https://registry.jetlinks.cn/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
resolved "https://registry.jetlinks.cn/chalk/-/chalk-4.1.2.tgz"
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
dependencies:
ansi-styles "^4.1.0"
@ -2146,7 +1907,7 @@ cli-width@^3.0.0:
resolved "https://registry.npmmirror.com/cli-width/-/cli-width-3.0.0.tgz"
integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
clipboard@^2.0.4:
clipboard@^2.0.10, clipboard@^2.0.4:
version "2.0.11"
resolved "https://registry.jetlinks.cn/clipboard/-/clipboard-2.0.11.tgz"
integrity sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==
@ -2249,7 +2010,7 @@ colorette@^2.0.16, colorette@^2.0.19:
colorpicker-v3@^2.10.2:
version "2.10.2"
resolved "https://registry.jetlinks.cn/colorpicker-v3/-/colorpicker-v3-2.10.2.tgz#f5e2f9ea603eee4d227ba10fa436d86963aa2bd0"
resolved "https://registry.jetlinks.cn/colorpicker-v3/-/colorpicker-v3-2.10.2.tgz"
integrity sha512-ZWPq5wcugS3NcL7DwYqVSP5mE/x45FK31olGpig+Tko5jUXk0danfEYi1Aei3lgYs+Z0zAfhbhqVuDgOdUs5Mw==
dependencies:
"@vueuse/core" "^7.5.5"
@ -2272,7 +2033,7 @@ combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
commander@^2.19.0, commander@^2.20.0, commander@^2.9.0:
version "2.20.3"
resolved "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz"
resolved "https://registry.jetlinks.cn/commander/-/commander-2.20.3.tgz"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
commander@^8.3.0:
@ -2280,7 +2041,7 @@ commander@^8.3.0:
resolved "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz"
integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==
commander@^9, commander@^9.4.1:
commander@^9.4.1:
version "9.5.0"
resolved "https://registry.npmmirror.com/commander/-/commander-9.5.0.tgz"
integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==
@ -2318,7 +2079,7 @@ compare-func@^2.0.0:
compute-scroll-into-view@^1.0.20:
version "1.0.20"
resolved "https://registry.jetlinks.cn/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz#1768b5522d1172754f5d0c9b02de3af6be506a43"
resolved "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz"
integrity sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==
concat-map@0.0.1:
@ -2421,9 +2182,9 @@ copy-anything@^2.0.1:
is-what "^3.14.1"
core-js@^3.15.1:
version "3.29.0"
resolved "https://registry.jetlinks.cn/core-js/-/core-js-3.29.0.tgz#0273e142b67761058bcde5615c503c7406b572d6"
integrity sha512-VG23vuEisJNkGl6XQmFJd3rEG/so/CNatqeE+7uZAwTSwFeB/qaO0be8xZYUNWprJ/GIwL8aMt9cj1kvbpTZhg==
version "3.27.0"
resolved "https://registry.npmjs.org/core-js/-/core-js-3.27.0.tgz"
integrity sha512-wY6cKosevs430KRkHUIsvepDXHGjlXOZO3hYXNyqpD6JvB0X28aXyv0t1Y1vZMwE7SoKmtfa6IASHCPN52FwBQ==
core-util-is@1.0.2:
version "1.0.2"
@ -2525,7 +2286,7 @@ dashdash@^1.12.0:
dayjs@^1.10.5:
version "1.11.7"
resolved "https://registry.jetlinks.cn/dayjs/-/dayjs-1.11.7.tgz#4b296922642f70999544d1144a2c25730fce63e2"
resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz"
integrity sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==
de-indent@^1.0.2:
@ -2614,11 +2375,6 @@ depd@^1.1.2:
resolved "https://registry.jetlinks.cn/depd/-/depd-1.1.2.tgz"
integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==
deprecation@^2.0.0, deprecation@^2.3.1:
version "2.3.1"
resolved "https://registry.npmmirror.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919"
integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==
detect-indent@^6.0.0:
version "6.1.0"
resolved "https://registry.npmmirror.com/detect-indent/-/detect-indent-6.1.0.tgz"
@ -2644,12 +2400,12 @@ diff@^5.0.0:
dom-align@^1.12.1:
version "1.12.4"
resolved "https://registry.jetlinks.cn/dom-align/-/dom-align-1.12.4.tgz#3503992eb2a7cfcb2ed3b2a6d21e0b9c00d54511"
resolved "https://registry.npmjs.org/dom-align/-/dom-align-1.12.4.tgz"
integrity sha512-R8LUSEay/68zE5c8/3BDxiTEvgb4xZTF0RKmAHfiEVN3klfIpXfi2/QCoiWPccVQ0J/ZGdz9OjzL4uJEP/MRAw==
dom-scroll-into-view@^2.0.0:
version "2.0.1"
resolved "https://registry.jetlinks.cn/dom-scroll-into-view/-/dom-scroll-into-view-2.0.1.tgz#0decc8522801fd8d3f1c6ba355a74d382c5f989b"
resolved "https://registry.npmjs.org/dom-scroll-into-view/-/dom-scroll-into-view-2.0.1.tgz"
integrity sha512-bvVTQe1lfaUr1oFzZX80ce9KLDlZ3iU+XGNE/bz9HnGdklTieqsbmsLHe+rT2XWqopvL0PckkYqN7ksmm5pe3w==
dom-serializer@^1.0.1:
@ -2888,11 +2644,6 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
resolved "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
escape-string-regexp@^4.0.0:
version "4.0.0"
resolved "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
escape-string-regexp@^5.0.0:
version "5.0.0"
resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz"
@ -3256,7 +3007,7 @@ glob-parent@^5.1.2, glob-parent@~5.1.2:
dependencies:
is-glob "^4.0.1"
glob@^7.0.0, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.0:
glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.0:
version "7.2.3"
resolved "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz"
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
@ -3416,6 +3167,11 @@ highlight.js@^11.3.1:
resolved "https://registry.npmmirror.com/highlight.js/-/highlight.js-11.7.0.tgz"
integrity sha512-1rRqesRFhMO/PRF+G86evnyJkCgaZFOI+Z6kdj15TA18funfoqJXvgPCLSf0SWq3SRfg1j3HlDs8o4s3EGq1oQ==
hls.js@^1.0.10:
version "1.3.4"
resolved "https://registry.jetlinks.cn/hls.js/-/hls.js-1.3.4.tgz#8212a3f95c3321f64a586f20e67876f3a9d09488"
integrity sha512-iFEwVqtEDk6sKotcTwtJ5OMo/nuDTk9PrpB8FI2J2WYf8EriTVfR4FaK0aNyYtwbYeRSWCXJKlz23xeREdlNYg==
homedir-polyfill@^1.0.0:
version "1.0.3"
resolved "https://registry.npmmirror.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz"
@ -3630,11 +3386,6 @@ inquirer@^7.0.4:
strip-ansi "^6.0.0"
through "^2.3.6"
interpret@^1.0.0:
version "1.4.0"
resolved "https://registry.npmmirror.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
ip-regex@^4.1.0:
version "4.3.0"
resolved "https://registry.jetlinks.cn/ip-regex/-/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5"
@ -3804,14 +3555,9 @@ is-plain-obj@^1.1.0:
is-plain-object@3.0.1:
version "3.0.1"
resolved "https://registry.jetlinks.cn/is-plain-object/-/is-plain-object-3.0.1.tgz#662d92d24c0aa4302407b0d45d21f2251c85f85b"
resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz"
integrity sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==
is-plain-object@^5.0.0:
version "5.0.0"
resolved "https://registry.npmmirror.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==
is-redirect@^1.0.0:
version "1.0.0"
resolved "https://registry.npmmirror.com/is-redirect/-/is-redirect-1.0.0.tgz"
@ -3896,10 +3642,10 @@ jetlinks-store@^0.0.3:
resolved "https://registry.npmjs.org/jetlinks-store/-/jetlinks-store-0.0.3.tgz"
integrity sha512-AZf/soh1hmmwjBZ00fr1emuMEydeReaI6IBTGByQYhTmK1Zd5pQAxC7WLek2snRAn/HHDgJfVz2hjditKThl6Q==
jetlinks-ui-components@^1.0.0:
version "1.0.0"
resolved "https://registry.jetlinks.cn/jetlinks-ui-components/-/jetlinks-ui-components-1.0.0.tgz#dca7bb82e53f464990b0851635e8f82be6c69db6"
integrity sha512-pgJ0Uiw4Dxc0AU2GqaOaVhNYun1VEmv78OtJcir2sq9rVSIuXCtTl1eHYMPiiPb6z1fG677KKs1gqvrpUwhguQ==
jetlinks-ui-components@^1.0.1:
version "1.0.1"
resolved "https://registry.jetlinks.cn/jetlinks-ui-components/-/jetlinks-ui-components-1.0.1.tgz#12fe9a193af14b859e1baf02fbd706a2be5b31cf"
integrity sha512-4hdEJUaKNMSIcmbn4qKcG8oK7h6VSYP3X3fCNndBm6WhHh+9ONf8f+3OSrUy1PvxdenmqO0VN2QdWV0KupByKQ==
dependencies:
"@vueuse/core" "^9.12.0"
ant-design-vue "^3.2.15"
@ -4373,7 +4119,7 @@ longest@^2.0.1:
loose-envify@^1.0.0:
version "1.4.0"
resolved "https://registry.jetlinks.cn/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
@ -4569,13 +4315,6 @@ marked@^4.2.12:
resolved "https://registry.npmjs.org/marked/-/marked-4.2.12.tgz"
integrity sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==
matcher@^4.0.0:
version "4.0.0"
resolved "https://registry.npmmirror.com/matcher/-/matcher-4.0.0.tgz#a42a05a09aaed92e2d241eb91fddac689461ea51"
integrity sha512-S6x5wmcDmsDRRU/c2dkccDwQPXoFczc5+HpQ2lON8pnvHlnvHAHj5WlLVvw6n6vNyHuVugYrFohYxbS+pvFpKQ==
dependencies:
escape-string-regexp "^4.0.0"
mdurl@^1.0.1:
version "1.0.1"
resolved "https://registry.npmmirror.com/mdurl/-/mdurl-1.0.1.tgz"
@ -4793,17 +4532,13 @@ moment@*, moment@^2.29.4:
monaco-editor@^0.35.0:
version "0.35.0"
resolved "https://registry.jetlinks.cn/monaco-editor/-/monaco-editor-0.35.0.tgz#49c4220c815262a900dacf0ae8a59bef66efab8b"
resolved "https://registry.jetlinks.cn/monaco-editor/-/monaco-editor-0.35.0.tgz"
integrity sha512-BJfkAZ0EJ7JgrgWzqjfBNP9hPSS8NlfECEDMEIIiozV2UaPq22yeuOjgbd3TwMh3anH0krWZirXZfn8KUSxiOA==
monaco-editor@^0.36.0:
version "0.36.0"
resolved "https://registry.npmmirror.com/monaco-editor/-/monaco-editor-0.36.0.tgz#8e7dba92f8110b369fdbc2312366184216419fc7"
integrity sha512-1Pn3AatfK88flUigyBozA4mt8+SB5xlgloQDu1RqivARw9yKaml/jceIvndae7Z2Nq8T7xZccFlmH+n6rkFg6g==
dependencies:
"@types/shelljs" "^0.8.11"
pin-github-action "^1.8.0"
shelljs "^0.8.5"
version "0.36.1"
resolved "https://registry.jetlinks.cn/monaco-editor/-/monaco-editor-0.36.1.tgz"
integrity sha512-/CaclMHKQ3A6rnzBzOADfwdSJ25BFoFT0Emxsc4zYVyav5SkK9iA6lEtIeuN/oRYbwPgviJT+t3l+sjFa28jYg==
mrm-core@^7.1.13:
version "7.1.13"
@ -4881,7 +4616,7 @@ nanoid@^3.3.4:
nanopop@^2.1.0:
version "2.2.0"
resolved "https://registry.jetlinks.cn/nanopop/-/nanopop-2.2.0.tgz#bd1c25588a7beaf68865bc2df19db4c58c77dcc9"
resolved "https://registry.npmjs.org/nanopop/-/nanopop-2.2.0.tgz"
integrity sha512-E9JaHcxh3ere8/BEZHAcnuD10RluTSPyTToBvoFWS9/7DcCx6gyKjbn7M7Bx7E1veCxCuY1iO6h4+gdAf1j73Q==
needle@^3.1.0:
@ -4906,13 +4641,6 @@ no-case@^3.0.4:
lower-case "^2.0.2"
tslib "^2.0.3"
node-fetch@^2.6.7:
version "2.6.9"
resolved "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6"
integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==
dependencies:
whatwg-url "^5.0.0"
node-gyp@^7.1.0, node-gyp@^7.1.2:
version "7.1.2"
resolved "https://registry.jetlinks.cn/node-gyp/-/node-gyp-7.1.2.tgz"
@ -5552,17 +5280,6 @@ pify@^4.0.1:
resolved "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz"
integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
pin-github-action@^1.8.0:
version "1.8.0"
resolved "https://registry.npmmirror.com/pin-github-action/-/pin-github-action-1.8.0.tgz#50f0833e6af5bbba2bbfc978ca5e498b5670b9d8"
integrity sha512-8QMKGbDUmMLFSyeV7hDIVmlI8B3ThJed1uFYuhcCBLi/w8xHPbrPhnCvJndYdugNc8aj1FrijrOMDLQ93ATc7A==
dependencies:
"@octokit/rest" "^18"
commander "^9"
debug "^4.3.4"
matcher "^4.0.0"
yaml "^2.1.3"
pinia@^2.0.28:
version "2.0.28"
resolved "https://registry.npmjs.org/pinia/-/pinia-2.0.28.tgz"
@ -5831,13 +5548,6 @@ readme-badger@^0.3.0:
dependencies:
balanced-match "^1.0.0"
rechoir@^0.6.2:
version "0.6.2"
resolved "https://registry.npmmirror.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==
dependencies:
resolve "^1.1.6"
redent@^3.0.0:
version "3.0.0"
resolved "https://registry.npmmirror.com/redent/-/redent-3.0.0.tgz"
@ -5848,7 +5558,7 @@ redent@^3.0.0:
regenerator-runtime@^0.13.11:
version "0.13.11"
resolved "https://registry.jetlinks.cn/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz"
integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
registry-auth-token@^3.0.1:
@ -5940,7 +5650,7 @@ require-main-filename@^2.0.0:
resize-observer-polyfill@^1.5.1:
version "1.5.1"
resolved "https://registry.jetlinks.cn/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
resolved "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz"
integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
resolve-from@5.0.0, resolve-from@^5.0.0:
@ -5960,7 +5670,7 @@ resolve-global@1.0.0, resolve-global@^1.0.0:
dependencies:
global-dirs "^0.1.1"
resolve@^1.1.6, resolve@^1.10.0, resolve@^1.22.1:
resolve@^1.10.0, resolve@^1.22.1:
version "1.22.1"
resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz"
integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
@ -6068,7 +5778,7 @@ sax@^1.2.4:
scroll-into-view-if-needed@^2.2.25:
version "2.2.31"
resolved "https://registry.jetlinks.cn/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz#d3c482959dc483e37962d1521254e3295d0d1587"
resolved "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz"
integrity sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==
dependencies:
compute-scroll-into-view "^1.0.20"
@ -6135,7 +5845,7 @@ set-blocking@^2.0.0, set-blocking@~2.0.0:
shallow-equal@^1.0.0:
version "1.2.1"
resolved "https://registry.jetlinks.cn/shallow-equal/-/shallow-equal-1.2.1.tgz#4c16abfa56043aa20d050324efa68940b0da79da"
resolved "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz"
integrity sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==
shebang-command@^1.2.0:
@ -6162,15 +5872,6 @@ shebang-regex@^3.0.0:
resolved "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
shelljs@^0.8.5:
version "0.8.5"
resolved "https://registry.npmmirror.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c"
integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==
dependencies:
glob "^7.0.0"
interpret "^1.0.0"
rechoir "^0.6.2"
sigmund@^1.0.1:
version "1.0.1"
resolved "https://registry.npmmirror.com/sigmund/-/sigmund-1.0.1.tgz"
@ -6554,6 +6255,11 @@ three@0.143.0:
resolved "https://registry.npmjs.org/three/-/three-0.143.0.tgz"
integrity sha512-oKcAGYHhJ46TGEuHjodo2n6TY2R6lbvrkp+feKZxqsUL/WkH7GKKaeu6RHeyb2Xjfk2dPLRKLsOP0KM2VgT8Zg==
throttle-debounce@^3.0.1:
version "3.0.1"
resolved "https://registry.jetlinks.cn/throttle-debounce/-/throttle-debounce-3.0.1.tgz#32f94d84dfa894f786c9a1f290e7a645b6a19abb"
integrity sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg==
through2@^4.0.0:
version "4.0.2"
resolved "https://registry.npmmirror.com/through2/-/through2-4.0.2.tgz"
@ -6613,11 +6319,6 @@ tough-cookie@~2.5.0:
psl "^1.1.28"
punycode "^2.1.1"
tr46@~0.0.3:
version "0.0.3"
resolved "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
treeverse@^1.0.4:
version "1.0.4"
resolved "https://registry.jetlinks.cn/treeverse/-/treeverse-1.0.4.tgz#a6b0ebf98a1bca6846ddc7ecbc900df08cb9cd5f"
@ -6773,11 +6474,6 @@ unique-string@^2.0.0:
dependencies:
crypto-random-string "^2.0.0"
universal-user-agent@^6.0.0:
version "6.0.0"
resolved "https://registry.npmmirror.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee"
integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==
universalify@^0.1.0:
version "0.1.2"
resolved "https://registry.npmmirror.com/universalify/-/universalify-0.1.2.tgz"
@ -6932,7 +6628,7 @@ user-meta@^1.0.0:
util-deprecate@^1.0.1, util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.jetlinks.cn/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
resolved "https://registry.jetlinks.cn/util-deprecate/-/util-deprecate-1.0.2.tgz"
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
uuid@^3.3.2:
@ -6940,6 +6636,11 @@ uuid@^3.3.2:
resolved "https://registry.jetlinks.cn/uuid/-/uuid-3.4.0.tgz"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
v-clipboard3@^0.1.4:
version "0.1.4"
resolved "https://registry.jetlinks.cn/v-clipboard3/-/v-clipboard3-0.1.4.tgz#13bdd12ce9728190d70f6ebf8b71de59d88b550e"
integrity sha512-iGIXgluf2WLbT+/Z1de9kKzoK9c9aPpy+zcPlY8/fneO+NHK95QEmFx2Q9LoxeUPRemD+nOfEv1J20Ki7W0v7Q==
v8-compile-cache-lib@^3.0.1:
version "3.0.1"
resolved "https://registry.npmmirror.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz"
@ -6994,7 +6695,7 @@ vite-plugin-html@^3.2.0:
vite-plugin-monaco-editor@^1.1.0:
version "1.1.0"
resolved "https://registry.jetlinks.cn/vite-plugin-monaco-editor/-/vite-plugin-monaco-editor-1.1.0.tgz#a6238c2e13d5e98dd54a1bc51f6f189325219de3"
resolved "https://registry.jetlinks.cn/vite-plugin-monaco-editor/-/vite-plugin-monaco-editor-1.1.0.tgz"
integrity sha512-IvtUqZotrRoVqwT0PBBDIZPNraya3BxN/bfcNfnxZ5rkJiGcNtO5eAOWWSgT7zullIAEqQwxMU83yL9J5k7gww==
vite-plugin-style-import@^2.0.0:
@ -7067,11 +6768,18 @@ vue-tsc@^1.0.11:
vue-types@^3.0.0:
version "3.0.2"
resolved "https://registry.jetlinks.cn/vue-types/-/vue-types-3.0.2.tgz#ec16e05d412c038262fc1efa4ceb9647e7fb601d"
resolved "https://registry.npmjs.org/vue-types/-/vue-types-3.0.2.tgz"
integrity sha512-IwUC0Aq2zwaXqy74h4WCvFCUtoV0iSWr0snWnE9TnU18S66GAQyqQbRf2qfJtUuiFsBf6qp0MEwdonlwznlcrw==
dependencies:
is-plain-object "3.0.1"
vue3-json-viewer@^2.2.2:
version "2.2.2"
resolved "https://registry.jetlinks.cn/vue3-json-viewer/-/vue3-json-viewer-2.2.2.tgz#43a512f378c602bb6b7f2a72adeaf7d15b443885"
integrity sha512-56l3XDGggnpwEqZieXsSMhNT4NhtO6d7zuSAxHo4i0UVxymyY2jRb7UMQOU1ztChKALZCAzX7DlgrsnEhxu77A==
dependencies:
clipboard "^2.0.10"
vue3-markdown-it@^1.0.10:
version "1.0.10"
resolved "https://registry.npmmirror.com/vue3-markdown-it/-/vue3-markdown-it-1.0.10.tgz"
@ -7099,7 +6807,16 @@ vue3-ts-jsoneditor@^2.7.1:
vanilla-jsoneditor "^0.7.9"
vue "^3.2.37"
vue@^3.2.25:
vue3-video-play@^1.3.1-beta.6:
version "1.3.1-beta.6"
resolved "https://registry.jetlinks.cn/vue3-video-play/-/vue3-video-play-1.3.1-beta.6.tgz#bca3f55a11053eaa37053835e4610c04d9cc509e"
integrity sha512-Olrx2/LNAds7fuor/yX9ZKT9sOcwcfTt2g2YbbCrEaAmZ5Tb0hwBr5z+/CoLwELzzRzXCHPmWWoT0Wm5W/Nwpw==
dependencies:
hls.js "^1.0.10"
throttle-debounce "^3.0.1"
vue "^3.2.2"
vue@^3.2.2, vue@^3.2.25:
version "3.2.47"
resolved "https://registry.jetlinks.cn/vue/-/vue-3.2.47.tgz#3eb736cbc606fc87038dbba6a154707c8a34cff0"
integrity sha512-60188y/9Dc9WVrAZeUVSDxRQOZ+z+y5nO2ts9jWXSTkMvayiWxCWOWtBQoYjLeccfXkiiPZWAHcV+WTPhkqJHQ==
@ -7128,7 +6845,7 @@ walk-up-path@^1.0.0:
warning@^4.0.0:
version "4.0.3"
resolved "https://registry.jetlinks.cn/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
resolved "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz"
integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==
dependencies:
loose-envify "^1.0.0"
@ -7140,11 +6857,6 @@ wcwidth@^1.0.0:
dependencies:
defaults "^1.0.3"
webidl-conversions@^3.0.0:
version "3.0.1"
resolved "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
webpack-merge@^4.2.2:
version "4.2.2"
resolved "https://registry.npmmirror.com/webpack-merge/-/webpack-merge-4.2.2.tgz"
@ -7162,14 +6874,6 @@ webpack-virtual-modules@^0.5.0:
resolved "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.5.0.tgz"
integrity sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==
whatwg-url@^5.0.0:
version "5.0.0"
resolved "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
dependencies:
tr46 "~0.0.3"
webidl-conversions "^3.0.0"
which-module@^2.0.0:
version "2.0.0"
resolved "https://registry.npmmirror.com/which-module/-/which-module-2.0.0.tgz"