Merge branch 'dev' into dev-hub
This commit is contained in:
commit
ef9cfc902c
|
@ -1,5 +1,10 @@
|
|||
<template>
|
||||
<ConfigProvider :locale='zhCN'>
|
||||
<!-- <router-view v-slot="{ Component }">-->
|
||||
<!-- <keep-alive>-->
|
||||
<!-- <component :is="Component" />-->
|
||||
<!-- </keep-alive>-->
|
||||
<!-- </router-view>-->
|
||||
<router-view />
|
||||
</ConfigProvider>
|
||||
</template>
|
||||
|
|
|
@ -194,4 +194,4 @@ export const getMetadataConfig = (params: {
|
|||
id: string;
|
||||
dataType: string;
|
||||
};
|
||||
}) => server.get<Record<any, any>[]>(`/device/product/${params.deviceId}/config-metadata/${params.metadata.type}/${params.metadata.id}/${params.metadata.dataType}`)
|
||||
}) => server.get<Record<any, any>[]>(`/device/product/${params.deviceId}/config-metadata/${params.metadata.type}/${params.metadata.id}/${params.metadata.dataType}`)
|
||||
|
|
|
@ -75,11 +75,9 @@ const handleMenuClick = (e: any) => {
|
|||
if(!(val?.popConfirm || val?.onClick)){
|
||||
emits('update:isCheck', true);
|
||||
emits('change', true);
|
||||
}
|
||||
if (val?.popConfirm) {
|
||||
visible.value = false;
|
||||
} else {
|
||||
visible.value = true;
|
||||
} else {
|
||||
visible.value = false;
|
||||
}
|
||||
_item.value = (val || {}) as any;
|
||||
};
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
v-model:selectedKeys="state.selectedKeys"
|
||||
:pure="state.pure"
|
||||
:breadcrumb="{ routes: breadcrumb }"
|
||||
@backClick='routerBack'
|
||||
>
|
||||
<template #breadcrumbRender="slotProps">
|
||||
<a
|
||||
|
@ -14,7 +15,7 @@
|
|||
>
|
||||
{{ slotProps.route.breadcrumbName }}
|
||||
</a>
|
||||
<span v-else style='cursor: pointer' >{{ slotProps.route.breadcrumbName }}</span>
|
||||
<span v-else style='cursor: default' >{{ slotProps.route.breadcrumbName }}</span>
|
||||
</template>
|
||||
<template #rightContentRender>
|
||||
<div class="right-content">
|
||||
|
@ -70,6 +71,10 @@ const state = reactive<StateType>({
|
|||
selectedKeys: [],
|
||||
});
|
||||
|
||||
const routerBack = () => {
|
||||
router.go(-1)
|
||||
}
|
||||
|
||||
const findRouteMeta = (code: string) => {
|
||||
let meta = []
|
||||
let menuItem: any = menu.menus[code]
|
||||
|
|
|
@ -194,7 +194,7 @@ const timeChange = (e: any) => {
|
|||
}
|
||||
|
||||
const inputChange = (e: any) => {
|
||||
emit('change', e.target ? e.target.value : e)
|
||||
emit('change', e && e.target ? e.target.value : e)
|
||||
}
|
||||
|
||||
const dateChange = (e: any) => {
|
||||
|
|
|
@ -51,7 +51,7 @@ export const AccountMenu = {
|
|||
export default [
|
||||
{ path: '/*', redirect: '/'},
|
||||
{
|
||||
path: '/login',
|
||||
path: LoginPath,
|
||||
component: () => import('@/views/user/Login/index.vue')
|
||||
},
|
||||
{
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
type DepartmentStateType = {
|
||||
productId: string;
|
||||
optType: string | undefined;
|
||||
}
|
||||
|
||||
export const useDepartmentStore = defineStore({
|
||||
id: 'department',
|
||||
state: (): DepartmentStateType => ({
|
||||
productId: '',
|
||||
// 设备资产分配弹窗操作类型:
|
||||
// 1. optType === 'handle': 手动点击资产分配按钮;
|
||||
// 2. optType === ': 产品资产分配后, 自动弹出设备资产分配
|
||||
optType: ''
|
||||
}),
|
||||
actions: {
|
||||
setProductId(value: string) {
|
||||
this.productId = value
|
||||
},
|
||||
setType(value: string | undefined) {
|
||||
this.optType = value
|
||||
}
|
||||
}
|
||||
})
|
|
@ -109,7 +109,7 @@ export const useSceneStore = defineStore('scene', () => {
|
|||
...result,
|
||||
trigger: result.trigger || {},
|
||||
branches: cloneDeep(assignmentKey(branches)),
|
||||
options: result.options ? {...defaultOptions, ...result.options } : defaultOptions,
|
||||
options: result.options ? {...cloneDeep(defaultOptions), ...result.options } : cloneDeep(defaultOptions),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,6 +148,9 @@ const extraRouteObj = {
|
|||
'edge/Device': {
|
||||
children: [{ code: 'Remote', name: '远程控制' }],
|
||||
},
|
||||
'rule-engine/Alarm/Log': {
|
||||
children: [{ code: 'Record', name: '处理记录' }]
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -206,7 +209,7 @@ const findDetailRoutes = (routes: any[]): any[] => {
|
|||
export const findCodeRoute = (asyncRouterMap: any[]) => {
|
||||
const routeMeta = {}
|
||||
|
||||
function getDetail( code: string, url: string) {
|
||||
function getDetail(code: string, url: string) {
|
||||
const detail = findDetailRouteItem(code, url)
|
||||
if (!detail) return
|
||||
routeMeta[(detail as MenuItem).code] = {
|
||||
|
@ -217,7 +220,7 @@ export const findCodeRoute = (asyncRouterMap: any[]) => {
|
|||
}
|
||||
}
|
||||
|
||||
function findChildren (data: any[], code: string = '') {
|
||||
function findChildren(data: any[], code: string = '') {
|
||||
data.forEach(route => {
|
||||
routeMeta[route.code] = {
|
||||
path: route.url || route.path,
|
||||
|
@ -254,7 +257,7 @@ export const findCodeRoute = (asyncRouterMap: any[]) => {
|
|||
return routeMeta
|
||||
}
|
||||
|
||||
export function filterAsyncRouter(asyncRouterMap: any, parentCode = '', level = 1): { menusData: any, silderMenus: any} {
|
||||
export function filterAsyncRouter(asyncRouterMap: any, parentCode = '', level = 1): { menusData: any, silderMenus: any } {
|
||||
const _asyncRouterMap = cloneDeep(asyncRouterMap)
|
||||
const menusData: any[] = []
|
||||
const silderMenus: any[] = []
|
||||
|
@ -270,7 +273,7 @@ export function filterAsyncRouter(asyncRouterMap: any, parentCode = '', level =
|
|||
},
|
||||
}
|
||||
|
||||
const silder = {..._route}
|
||||
const silder = { ..._route }
|
||||
|
||||
// 查看是否有隐藏子路由
|
||||
route.children = findChildrenRoute(route.code, route.url, route.children)
|
||||
|
|
|
@ -155,12 +155,10 @@ const errorHandler = (error: any) => {
|
|||
Notification.error({
|
||||
key: '401',
|
||||
message: 'Unauthorized',
|
||||
description: 'Authorization verification failed'
|
||||
description: '用户未登录'
|
||||
})
|
||||
setTimeout(() => {
|
||||
router.replace({
|
||||
path: LoginPath
|
||||
})
|
||||
location.href = `/#${LoginPath}`
|
||||
}, 0)
|
||||
}
|
||||
} else if (error.response === undefined) {
|
||||
|
@ -179,10 +177,13 @@ request.interceptors.request.use(config => {
|
|||
const token = LocalStore.get(TOKEN_KEY)
|
||||
// const token = store.$state.tokenAlias
|
||||
if (!token) {
|
||||
// setTimeout(() => {
|
||||
// router.replace({
|
||||
// path: LoginPath
|
||||
// })
|
||||
// }, 0)
|
||||
setTimeout(() => {
|
||||
router.replace({
|
||||
path: LoginPath
|
||||
})
|
||||
location.href = `/#${LoginPath}`
|
||||
}, 0)
|
||||
return config
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
format="YYYY-MM-DD HH:mm:ss"
|
||||
valueFormat="YYYY-MM-DD HH:mm:ss"
|
||||
style="margin-left: 12px"
|
||||
:show-time="{ format: 'HH:mm:ss' }"
|
||||
@change="rangeChange"
|
||||
v-model:value="rangeVal"
|
||||
:allowClear="false"
|
||||
|
@ -110,5 +111,5 @@ const handleBtnChange = (val: string) => {
|
|||
});
|
||||
};
|
||||
handleBtnChange(radioValue.value);
|
||||
watch(() => radioValue.value, { deep: true, immediate: true });
|
||||
// watch(() => radioValue.value, { deep: true, immediate: true });
|
||||
</script>
|
||||
|
|
|
@ -364,7 +364,7 @@ const setDevMesChartOption = (
|
|||
grid: {
|
||||
top: '2%',
|
||||
bottom: '5%',
|
||||
left: maxY > 100000 ? '90px' : '60px',
|
||||
left: maxY > 100000 ? '50px' : '70px',
|
||||
right: '50px',
|
||||
},
|
||||
series: [
|
||||
|
|
|
@ -147,6 +147,10 @@ const columns = [
|
|||
dataIndex: 'id',
|
||||
key: 'id',
|
||||
ellipsis: true,
|
||||
search:{
|
||||
type:'string',
|
||||
defaultTermType: 'eq'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '设备名称',
|
||||
|
|
|
@ -162,7 +162,7 @@ import {
|
|||
} from '@/api/device/instance';
|
||||
import MSelect from './MSelect.vue';
|
||||
import PatchMapping from './PatchMapping.vue';
|
||||
import { message } from 'ant-design-vue/es';
|
||||
import { onlyMessage } from '@/utils/comm';
|
||||
|
||||
const columns = [
|
||||
{
|
||||
|
@ -280,7 +280,7 @@ const unbind = async (id: string) => {
|
|||
},
|
||||
);
|
||||
if (resp.status === 200) {
|
||||
message.success('操作成功!');
|
||||
onlyMessage('操作成功!', 'success');
|
||||
handleSearch();
|
||||
}
|
||||
}
|
||||
|
@ -313,7 +313,7 @@ const onSave = () => {
|
|||
submitData,
|
||||
);
|
||||
if (resp.status === 200) {
|
||||
message.success('操作成功!');
|
||||
onlyMessage('操作成功!', 'success');
|
||||
handleSearch();
|
||||
}
|
||||
}
|
||||
|
@ -342,7 +342,7 @@ const onAction = async (record: any) => {
|
|||
submitData,
|
||||
);
|
||||
if (resp.status === 200) {
|
||||
message.success('操作成功!');
|
||||
onlyMessage('操作成功!', 'success');
|
||||
handleSearch();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
<j-image :src="value?.formatValue" />
|
||||
</template>
|
||||
<template v-else-if="['.flv', '.m3u8', '.mp4'].includes(type)">
|
||||
<LivePlayer :url="value?.formatValue" autoplay />
|
||||
</template>
|
||||
<template v-else>
|
||||
<JsonViewer
|
||||
|
@ -25,6 +26,7 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import JsonViewer from 'vue-json-viewer';
|
||||
import LivePlayer from '@/components/Player/index.vue';
|
||||
|
||||
const _data = defineProps({
|
||||
type: {
|
||||
|
|
|
@ -1,101 +1,91 @@
|
|||
<template>
|
||||
<page-container
|
||||
:tabList="list"
|
||||
:showBack="true"
|
||||
:tabActiveKey="instanceStore.tabActiveKey"
|
||||
@tabChange="onTabChange"
|
||||
>
|
||||
<template #title>
|
||||
<div>
|
||||
<div style="display: flex; align-items: center">
|
||||
<!-- <j-button @click="onBack" size="small">返回</j-button> -->
|
||||
<div style="font-size: 24px">
|
||||
{{ instanceStore.current?.name }}
|
||||
</div>
|
||||
<j-divider type="vertical" />
|
||||
<j-space>
|
||||
<span
|
||||
style="font-size: 14px; color: rgba(0, 0, 0, 0.85)"
|
||||
>
|
||||
状态:
|
||||
<j-badge
|
||||
:status="
|
||||
statusMap.get(
|
||||
instanceStore.current?.state?.value,
|
||||
)
|
||||
"
|
||||
/>
|
||||
{{ instanceStore.current?.state?.text }}
|
||||
</span>
|
||||
<PermissionButton
|
||||
v-if="
|
||||
instanceStore.current?.state?.value ===
|
||||
'notActive'
|
||||
"
|
||||
type="link"
|
||||
style="margin-top: -5px; padding: 0 20px"
|
||||
:popConfirm="{
|
||||
title: '确认启用设备',
|
||||
onConfirm: handleAction,
|
||||
}"
|
||||
hasPermission="device/Instance:action"
|
||||
>
|
||||
启用设备
|
||||
</PermissionButton>
|
||||
<PermissionButton
|
||||
v-if="
|
||||
instanceStore.current?.state?.value === 'online'
|
||||
"
|
||||
type="link"
|
||||
style="margin-top: -5px; padding: 0 20px"
|
||||
:popConfirm="{
|
||||
title: '确认断开连接?',
|
||||
onConfirm: handleDisconnect,
|
||||
}"
|
||||
hasPermission="device/Instance:action"
|
||||
>
|
||||
断开连接
|
||||
</PermissionButton>
|
||||
<j-tooltip
|
||||
v-if="
|
||||
instanceStore.current?.accessProvider ===
|
||||
'child-device' &&
|
||||
instanceStore.current?.state?.value ===
|
||||
'offline'
|
||||
"
|
||||
:title="
|
||||
instanceStore.current?.features?.find(
|
||||
(item) => item?.id === 'selfManageState',
|
||||
<div style="display: flex; align-items: center">
|
||||
{{ instanceStore.current?.name }}
|
||||
<j-divider type="vertical" />
|
||||
<j-space>
|
||||
<span style="font-size: 14px; color: rgba(0, 0, 0, 0.85)">
|
||||
状态:
|
||||
<j-badge
|
||||
:status="
|
||||
statusMap.get(
|
||||
instanceStore.current?.state?.value,
|
||||
)
|
||||
? '该设备的在线状态与父设备(网关设备)保持一致'
|
||||
: '该设备在线状态由设备自身运行状态决定,不继承父设备(网关设备)的在线状态'
|
||||
"
|
||||
>
|
||||
<AIcon
|
||||
type="QuestionCircleOutlined"
|
||||
style="font-size: 14px"
|
||||
/>
|
||||
</j-tooltip>
|
||||
</j-space>
|
||||
</div>
|
||||
<div style="padding-top: 24px">
|
||||
<j-descriptions size="small" :column="4">
|
||||
<j-descriptions-item label="ID">{{
|
||||
instanceStore.current?.id
|
||||
}}</j-descriptions-item>
|
||||
<j-descriptions-item label="所属产品">
|
||||
<PermissionButton
|
||||
type="link"
|
||||
style="margin-top: -5px; padding: 0"
|
||||
@click="jumpProduct"
|
||||
hasPermission="device/Product:view"
|
||||
>
|
||||
{{ instanceStore.current?.productName }}
|
||||
</PermissionButton>
|
||||
</j-descriptions-item>
|
||||
</j-descriptions>
|
||||
</div>
|
||||
/>
|
||||
{{ instanceStore.current?.state?.text }}
|
||||
</span>
|
||||
<PermissionButton
|
||||
v-if="
|
||||
instanceStore.current?.state?.value === 'notActive'
|
||||
"
|
||||
type="link"
|
||||
style="margin-top: -5px; padding: 0 20px"
|
||||
:popConfirm="{
|
||||
title: '确认启用设备',
|
||||
onConfirm: handleAction,
|
||||
}"
|
||||
hasPermission="device/Instance:action"
|
||||
>
|
||||
启用设备
|
||||
</PermissionButton>
|
||||
<PermissionButton
|
||||
v-if="instanceStore.current?.state?.value === 'online'"
|
||||
type="link"
|
||||
style="margin-top: -5px; padding: 0 20px"
|
||||
:popConfirm="{
|
||||
title: '确认断开连接?',
|
||||
onConfirm: handleDisconnect,
|
||||
}"
|
||||
hasPermission="device/Instance:action"
|
||||
>
|
||||
断开连接
|
||||
</PermissionButton>
|
||||
<j-tooltip
|
||||
v-if="
|
||||
instanceStore.current?.accessProvider ===
|
||||
'child-device' &&
|
||||
instanceStore.current?.state?.value === 'offline'
|
||||
"
|
||||
:title="
|
||||
instanceStore.current?.features?.find(
|
||||
(item) => item?.id === 'selfManageState',
|
||||
)
|
||||
? '该设备的在线状态与父设备(网关设备)保持一致'
|
||||
: '该设备在线状态由设备自身运行状态决定,不继承父设备(网关设备)的在线状态'
|
||||
"
|
||||
>
|
||||
<AIcon
|
||||
type="QuestionCircleOutlined"
|
||||
style="font-size: 14px"
|
||||
/>
|
||||
</j-tooltip>
|
||||
</j-space>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<j-descriptions size="small" :column="4">
|
||||
<j-descriptions-item label="ID">{{
|
||||
instanceStore.current?.id
|
||||
}}</j-descriptions-item>
|
||||
<j-descriptions-item label="所属产品">
|
||||
<PermissionButton
|
||||
type="link"
|
||||
style="margin-top: -5px; padding: 0"
|
||||
@click="jumpProduct"
|
||||
hasPermission="device/Product:view"
|
||||
>
|
||||
{{ instanceStore.current?.productName }}
|
||||
</PermissionButton>
|
||||
</j-descriptions-item>
|
||||
</j-descriptions>
|
||||
</template>
|
||||
<template #extra>
|
||||
<img
|
||||
@click="handleRefresh"
|
||||
|
@ -142,7 +132,7 @@ statusMap.set('notActive', 'warning');
|
|||
|
||||
const statusRef = ref();
|
||||
|
||||
const list = ref([
|
||||
const initList = [
|
||||
{
|
||||
key: 'Info',
|
||||
tab: '实例信息',
|
||||
|
@ -163,7 +153,9 @@ const list = ref([
|
|||
key: 'Log',
|
||||
tab: '日志管理',
|
||||
},
|
||||
]);
|
||||
];
|
||||
|
||||
const list = ref([...initList]);
|
||||
|
||||
const tabs = {
|
||||
Info,
|
||||
|
@ -191,64 +183,7 @@ const getStatus = (id: string) => {
|
|||
});
|
||||
};
|
||||
|
||||
watch(
|
||||
() => route.params?.id,
|
||||
(newId) => {
|
||||
if (newId) {
|
||||
instanceStore.refresh(String(newId));
|
||||
getStatus(String(newId));
|
||||
instanceStore.tabActiveKey = 'Info'
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
instanceStore.tabActiveKey = history.state?.params?.tab || 'Info';
|
||||
});
|
||||
|
||||
// const onBack = () => {
|
||||
// menuStory.jumpPage('device/Instance');
|
||||
// };
|
||||
|
||||
const onTabChange = (e: string) => {
|
||||
instanceStore.tabActiveKey = e;
|
||||
};
|
||||
|
||||
const handleAction = async () => {
|
||||
if (instanceStore.current?.id) {
|
||||
const resp = await _deploy(instanceStore.current?.id);
|
||||
if (resp.status === 200) {
|
||||
message.success('操作成功!');
|
||||
instanceStore.refresh(instanceStore.current?.id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleDisconnect = async () => {
|
||||
if (instanceStore.current?.id) {
|
||||
const resp = await _disconnect(instanceStore.current?.id);
|
||||
if (resp.status === 200) {
|
||||
message.success('操作成功!');
|
||||
instanceStore.refresh(instanceStore.current?.id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleRefresh = async () => {
|
||||
if (instanceStore.current?.id) {
|
||||
await instanceStore.refresh(instanceStore.current?.id);
|
||||
message.success('操作成功');
|
||||
}
|
||||
};
|
||||
|
||||
const jumpProduct = () => {
|
||||
menuStory.jumpPage('device/Product/Detail', {
|
||||
id: instanceStore.current?.productId,
|
||||
});
|
||||
};
|
||||
|
||||
watchEffect(() => {
|
||||
const getDetail = () => {
|
||||
const keys = list.value.map((i) => i.key);
|
||||
if (
|
||||
instanceStore.current?.protocol &&
|
||||
|
@ -309,8 +244,67 @@ watchEffect(() => {
|
|||
tab: '边缘端映射',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
() => route.params?.id,
|
||||
async (newId) => {
|
||||
if (newId) {
|
||||
await instanceStore.refresh(String(newId));
|
||||
getStatus(String(newId));
|
||||
list.value = [...initList];
|
||||
getDetail();
|
||||
instanceStore.tabActiveKey = 'Info';
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
instanceStore.tabActiveKey = history.state?.params?.tab || 'Info';
|
||||
});
|
||||
|
||||
const onBack = () => {
|
||||
menuStory.jumpPage('device/Instance');
|
||||
};
|
||||
|
||||
const onTabChange = (e: string) => {
|
||||
instanceStore.tabActiveKey = e;
|
||||
};
|
||||
|
||||
const handleAction = async () => {
|
||||
if (instanceStore.current?.id) {
|
||||
const resp = await _deploy(instanceStore.current?.id);
|
||||
if (resp.status === 200) {
|
||||
message.success('操作成功!');
|
||||
instanceStore.refresh(instanceStore.current?.id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleDisconnect = async () => {
|
||||
if (instanceStore.current?.id) {
|
||||
const resp = await _disconnect(instanceStore.current?.id);
|
||||
if (resp.status === 200) {
|
||||
message.success('操作成功!');
|
||||
instanceStore.refresh(instanceStore.current?.id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleRefresh = async () => {
|
||||
if (instanceStore.current?.id) {
|
||||
await instanceStore.refresh(instanceStore.current?.id);
|
||||
message.success('操作成功');
|
||||
}
|
||||
};
|
||||
|
||||
const jumpProduct = () => {
|
||||
menuStory.jumpPage('device/Product/Detail', {
|
||||
id: instanceStore.current?.productId,
|
||||
});
|
||||
};
|
||||
|
||||
onUnmounted(() => {
|
||||
statusRef.value && statusRef.value.unsubscribe();
|
||||
});
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
</div>
|
||||
<div v-else>
|
||||
<p>{{ type === 'active' ? '启用' : '同步' }}成功:{{ count }}条</p>
|
||||
<p v-if="type === 'active'">启用失败:{{ errCount }}条<j-tooltip title="实例信息页面中的配置项未完善"><AIcon type="QuestionCircleOutlined" /></j-tooltip></p>
|
||||
<p v-if="type === 'active'">启用失败:{{ errCount }}条<j-tooltip title="实例信息页面中的配置项未完善"><AIcon style="margin-left: 5px" type="QuestionCircleOutlined" /></j-tooltip></p>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
|
@ -56,13 +56,13 @@ const getData = (api: string) => {
|
|||
source.value = _source;
|
||||
_source.onmessage = (e: any) => {
|
||||
const res = JSON.parse(e.data);
|
||||
// console.log(res)
|
||||
switch (props.type) {
|
||||
case 'active':
|
||||
if (res.success) {
|
||||
_source.close();
|
||||
dt += res.total;
|
||||
count.value = dt;
|
||||
flag.value = false;
|
||||
} else {
|
||||
if (res.source) {
|
||||
errCount.value = 1
|
||||
|
@ -76,6 +76,7 @@ const getData = (api: string) => {
|
|||
case 'sync':
|
||||
dt += res;
|
||||
count.value = dt;
|
||||
flag.value = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -328,6 +328,7 @@ const columns = [
|
|||
title: 'ID',
|
||||
dataIndex: 'id',
|
||||
key: 'id',
|
||||
ellipsis: true,
|
||||
search: {
|
||||
type: 'string',
|
||||
defaultTermType: 'eq',
|
||||
|
@ -337,6 +338,7 @@ const columns = [
|
|||
title: '设备名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
ellipsis: true,
|
||||
search: {
|
||||
type: 'string',
|
||||
first: true,
|
||||
|
@ -346,6 +348,7 @@ const columns = [
|
|||
title: '产品名称',
|
||||
dataIndex: 'productName',
|
||||
key: 'productName',
|
||||
ellipsis: true,
|
||||
search: {
|
||||
type: 'select',
|
||||
rename: 'productId',
|
||||
|
@ -367,6 +370,7 @@ const columns = [
|
|||
dataIndex: 'createTime',
|
||||
key: 'createTime',
|
||||
scopedSlots: true,
|
||||
width: 200,
|
||||
search: {
|
||||
type: 'date',
|
||||
},
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
"
|
||||
>
|
||||
<j-button
|
||||
style="margin: 0 0 0 20px"
|
||||
class="changeBtn"
|
||||
size="small"
|
||||
:disabled="
|
||||
productStore.current?.count &&
|
||||
|
@ -568,7 +568,17 @@ const query = reactive({
|
|||
});
|
||||
const param = ref<Record<string, any>>({
|
||||
pageSize: 4,
|
||||
terms: [],
|
||||
terms: [
|
||||
{
|
||||
terms: [
|
||||
{
|
||||
column: 'channel',
|
||||
termType: 'nin',
|
||||
value: 'plugin',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
const queryParams = ref<Record<string, any>>({});
|
||||
/**
|
||||
|
@ -669,49 +679,6 @@ const driver1 = new Driver({
|
|||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* 表格列表
|
||||
*/
|
||||
// const columnsMQTT: any[] = [
|
||||
// {
|
||||
// title: '分组',
|
||||
// dataIndex: 'group',
|
||||
// key: 'group',
|
||||
// ellipsis: true,
|
||||
// width: 100,
|
||||
// // customCell: (record: any, index: number) => {
|
||||
// // const list =
|
||||
// // (config?.routes || []).sort((a: any, b: any) => a - b) || [];
|
||||
// // const arr = list.filter((res: any) => {
|
||||
// // // 这里gpsNumber是我需要判断的字段名(相同就合并)
|
||||
// // return res?.group == record?.group;
|
||||
// // });
|
||||
// // if (index == 0 || list[index - 1]?.group != record?.group) {
|
||||
// // return { rowSpan: arr.length };
|
||||
// // } else {
|
||||
// // return { rowSpan: 0 };
|
||||
// // }
|
||||
// // },
|
||||
// },
|
||||
// {
|
||||
// title: 'topic',
|
||||
// dataIndex: 'topic',
|
||||
// key: 'topic',
|
||||
// },
|
||||
// {
|
||||
// title: '上下行',
|
||||
// dataIndex: 'stream',
|
||||
// key: 'stream',
|
||||
// ellipsis: true,
|
||||
// align: 'center',
|
||||
// width: 100,
|
||||
// },
|
||||
// {
|
||||
// title: '说明',
|
||||
// dataIndex: 'description',
|
||||
// key: 'description',
|
||||
// },
|
||||
// ];
|
||||
let columnsMQTT = ref(<TableColumnType>[]);
|
||||
const ColumnsMQTT = [
|
||||
{
|
||||
|
@ -760,38 +727,6 @@ const ColumnsHTTP = [
|
|||
// scopedSlots: { customRender: 'description' },
|
||||
},
|
||||
];
|
||||
// const columnsHTTP: any[] = [
|
||||
// {
|
||||
// title: '分组',
|
||||
// dataIndex: 'group',
|
||||
// key: 'group',
|
||||
// ellipsis: true,
|
||||
// width: 100,
|
||||
// // customCell: (record: any, index: number) => {
|
||||
// // const list =
|
||||
// // (config?.routes || []).sort((a: any, b: any) => a - b) || [];
|
||||
// // const arr = list.filter((res: any) => {
|
||||
// // // 这里gpsNumber是我需要判断的字段名(相同就合并)
|
||||
// // return res?.group == record?.group;
|
||||
// // });
|
||||
// // if (index == 0 || list[index - 1]?.group != record?.group) {
|
||||
// // return { rowSpan: arr.length };
|
||||
// // } else {
|
||||
// // return { rowSpan: 0 };
|
||||
// // }
|
||||
// // },
|
||||
// },
|
||||
// {
|
||||
// title: '示例',
|
||||
// dataIndex: 'example',
|
||||
// key: 'example',
|
||||
// },
|
||||
// {
|
||||
// title: '说明',
|
||||
// dataIndex: 'description',
|
||||
// key: 'description',
|
||||
// },
|
||||
// ];
|
||||
/**
|
||||
* 获取上下行数据
|
||||
*/
|
||||
|
@ -892,6 +827,28 @@ const submitData = async () => {
|
|||
accessProvider: current.value?.provider,
|
||||
messageProtocol: current.value?.protocol,
|
||||
};
|
||||
// getConfigView(current.value?.protocol, current.value?.transport).then(
|
||||
// (resp: any) => {
|
||||
// metadata.value = (resp?.result[0] as ConfigMetadata) || {
|
||||
// properties: [],
|
||||
// };
|
||||
// // 流传输模式 初始为udp模式
|
||||
// if (metadata.value?.properties) {
|
||||
// metadata.value?.properties.forEach((item) => {
|
||||
// if (
|
||||
// item.name === '流传输模式' &&
|
||||
// (!productStore.current?.configuration ||
|
||||
// !productStore.current?.configuration.hasOwnProperty(
|
||||
// item.name,
|
||||
// ))
|
||||
// ) {
|
||||
// formData.data[item.name] =
|
||||
// item.type.expands?.defaultValue;
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// },
|
||||
// );
|
||||
const metatdata = JSON.parse(productStore.current?.metadata || '{}');
|
||||
if (!productStore.current?.metadata) {
|
||||
const response = await getConfigView(
|
||||
|
@ -1128,4 +1085,10 @@ nextTick(() => {
|
|||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
}
|
||||
.changeBtn{
|
||||
margin: 0 0 0 20px;
|
||||
color: #315EFB;
|
||||
background: #ffffff;
|
||||
border: 1px solid #315EFB
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<template>
|
||||
<page-container
|
||||
:tabList="list"
|
||||
@back="onBack"
|
||||
:tabActiveKey="productStore.tabActiveKey"
|
||||
@tabChange="onTabChange"
|
||||
showBack="true"
|
||||
|
@ -49,9 +48,21 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<div style="padding-top: 10px">
|
||||
<j-descriptions size="small" :column="4">
|
||||
<j-descriptions-item label="设备数量"
|
||||
<j-descriptions-item
|
||||
label="设备数量"
|
||||
:labelStyle="{
|
||||
fontSize: '14px',
|
||||
opacity: 0.55,
|
||||
}"
|
||||
:contentStyle="{
|
||||
fontSize: '14px',
|
||||
color: '#092EE7',
|
||||
cursor: 'pointer',
|
||||
}"
|
||||
><span @click="jumpDevice">{{
|
||||
productStore.current?.count
|
||||
? productStore.current?.count
|
||||
|
@ -62,18 +73,6 @@
|
|||
</div>
|
||||
</template>
|
||||
<template #extra>
|
||||
<!-- <j-popconfirm
|
||||
title="确认应用配置"
|
||||
@confirm="handleCofig"
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<j-button
|
||||
:disabled="productStore.current.state === 0"
|
||||
type="primary"
|
||||
>应用配置</j-button
|
||||
>
|
||||
</j-popconfirm> -->
|
||||
<PermissionButton
|
||||
type="primary"
|
||||
:popConfirm="{
|
||||
|
@ -172,7 +171,9 @@ watch(
|
|||
getProtocol();
|
||||
},
|
||||
);
|
||||
const onBack = () => {};
|
||||
const onBack = () => {
|
||||
history.back();
|
||||
};
|
||||
|
||||
const onTabChange = (e: string) => {
|
||||
productStore.tabActiveKey = e;
|
||||
|
@ -250,7 +251,7 @@ const getProtocol = async () => {
|
|||
tab: '数据解析',
|
||||
},
|
||||
];
|
||||
}else{
|
||||
} else {
|
||||
list.value = [
|
||||
{
|
||||
key: 'Info',
|
||||
|
@ -264,7 +265,8 @@ const getProtocol = async () => {
|
|||
{
|
||||
key: 'Device',
|
||||
tab: '设备接入',
|
||||
},]
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@
|
|||
>
|
||||
<template #title="item">
|
||||
<span>{{ item.title }}</span>
|
||||
<a-tooltip :title="item"
|
||||
<a-tooltip :title="item.option.tooltip"
|
||||
><AIcon
|
||||
type="QuestionCircleOutlined"
|
||||
style="margin-left: 2px"
|
||||
|
|
|
@ -563,7 +563,7 @@ const query = reactive({
|
|||
},
|
||||
},
|
||||
{
|
||||
title: '所属部门',
|
||||
title: '所属组织',
|
||||
key: 'id$dim-assets',
|
||||
dataIndex: 'id$dim-assets',
|
||||
search: {
|
||||
|
|
|
@ -196,11 +196,12 @@ const resetMetadata = async () => {
|
|||
// }
|
||||
const { id } = route.params
|
||||
if (target === 'device') {
|
||||
instanceStore.refresh(id as string)
|
||||
await instanceStore.refresh(id as string)
|
||||
} else {
|
||||
productStore.refresh(id as string)
|
||||
await productStore.getDetail(id as string)
|
||||
}
|
||||
metadataStore.set('importMetadata', true)
|
||||
|
||||
};
|
||||
|
||||
const removeItem = async (record: MetadataItem) => {
|
||||
|
|
|
@ -61,12 +61,15 @@ const close = () => {
|
|||
|
||||
const instanceStore = useInstanceStore()
|
||||
const productStore = useProductStore()
|
||||
const metadataMap = {
|
||||
product: productStore.current?.metadata as string,
|
||||
device: instanceStore.current?.metadata as string,
|
||||
};
|
||||
const metadata = metadataMap[props.type];
|
||||
const value = ref(metadata)
|
||||
const metadata = computed(() => {
|
||||
const metadataMap = {
|
||||
product: productStore.current?.metadata as string,
|
||||
device: instanceStore.current?.metadata as string,
|
||||
};
|
||||
return metadataMap[props.type];
|
||||
})
|
||||
// const metadata = metadataMap[props.type];
|
||||
const value = ref(metadata.value)
|
||||
const handleExport = async () => {
|
||||
try {
|
||||
downloadObject(
|
||||
|
@ -86,14 +89,14 @@ const handleConvertMetadata = (key: Key) => {
|
|||
if (key === 'alink') {
|
||||
value.value = '';
|
||||
if (metadata) {
|
||||
convertMetadata('to', 'alink', JSON.parse(metadata)).then(res => {
|
||||
convertMetadata('to', 'alink', JSON.parse(metadata.value)).then(res => {
|
||||
if (res.status === 200) {
|
||||
value.value = JSON.stringify(res.result)
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
value.value = metadata;
|
||||
value.value = metadata.value;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -267,26 +267,26 @@ const columns = [
|
|||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'productId$product-info',
|
||||
dataIndex: 'productId$product-info',
|
||||
title: '接入方式',
|
||||
hideInTable: true,
|
||||
search: {
|
||||
type: 'select',
|
||||
options: () =>
|
||||
new Promise((resolve) => {
|
||||
queryGatewayList({}).then((resp: any) => {
|
||||
resolve(
|
||||
resp.result.map((item: any) => ({
|
||||
label: item.name,
|
||||
value: `accessId is ${item.id}`,
|
||||
})),
|
||||
);
|
||||
});
|
||||
}),
|
||||
},
|
||||
},
|
||||
// {
|
||||
// key: 'productId$product-info',
|
||||
// dataIndex: 'productId$product-info',
|
||||
// title: '接入方式',
|
||||
// hideInTable: true,
|
||||
// search: {
|
||||
// type: 'select',
|
||||
// options: () =>
|
||||
// new Promise((resolve) => {
|
||||
// queryGatewayList({}).then((resp: any) => {
|
||||
// resolve(
|
||||
// resp.result.map((item: any) => ({
|
||||
// label: item.name,
|
||||
// value: `accessId is ${item.id}`,
|
||||
// })),
|
||||
// );
|
||||
// });
|
||||
// }),
|
||||
// },
|
||||
// },
|
||||
{
|
||||
dataIndex: 'deviceType',
|
||||
title: '设备类型',
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
<j-col :span="8">已下发数量:{{ countErr + count }}</j-col>
|
||||
</j-row>
|
||||
<div v-if="!flag">
|
||||
<j-textarea :rows="20" :value="JSON.stringify(errMessage)" />
|
||||
<j-textarea :rows="10" :value="JSON.stringify(errMessage)" />
|
||||
</div>
|
||||
</j-modal>
|
||||
</template>
|
||||
|
@ -86,7 +86,7 @@ const getData = () => {
|
|||
et += 1;
|
||||
countErr.value = et;
|
||||
flag.value = false;
|
||||
if (errMessages.length <= 5) {
|
||||
if (errMessages.length < 5) {
|
||||
errMessages.push({ ...res });
|
||||
errMessage.value = [...errMessages];
|
||||
}
|
||||
|
|
|
@ -169,7 +169,8 @@ const onCancel = () => {
|
|||
|
||||
<style lang="less" scoped>
|
||||
.search {
|
||||
padding: 0 0 0 24px;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
}
|
||||
.alert {
|
||||
height: 40px;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<template>
|
||||
<j-form layout="vertical" :model="form" ref="formBasicRef">
|
||||
<j-row :span="24" :gutter="24">
|
||||
<j-col :span="10">
|
||||
<j-col :span="12">
|
||||
<j-form-item
|
||||
label="系统名称"
|
||||
name="title"
|
||||
|
@ -193,7 +193,7 @@
|
|||
</j-col>
|
||||
</j-row>
|
||||
</j-col>
|
||||
<j-col :span="14">
|
||||
<j-col :span="12">
|
||||
<j-form-item label="登录背景图">
|
||||
<div class="upload-image-warp-back">
|
||||
<div class="upload-image-border-back">
|
||||
|
|
|
@ -183,6 +183,7 @@ defineExpose({
|
|||
flex: 1 1 auto;
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
.role-item-content {
|
||||
|
|
|
@ -237,6 +237,11 @@ const getData = (
|
|||
return new Promise((resolve) => {
|
||||
queryFlow(start, end, {
|
||||
orderBy: 'date',
|
||||
terms: [{
|
||||
column : "cardId",
|
||||
termType: "eq",
|
||||
value: route.params.id
|
||||
}]
|
||||
}).then((resp: any) => {
|
||||
if (resp.status === 200) {
|
||||
const sortArray = resp.result.sort(
|
||||
|
|
|
@ -232,8 +232,8 @@ const handleOk = () => {
|
|||
btnLoading.value = true;
|
||||
const resp =
|
||||
props.type === 'add'
|
||||
? await add(toRaw(modelRef))
|
||||
: await edit(toRaw(modelRef));
|
||||
? await add(toRaw(modelRef)).catch(err => err)
|
||||
: await edit(toRaw(modelRef)).catch(err => err);
|
||||
btnLoading.value = false;
|
||||
if (resp.status === 200) {
|
||||
message.success('操作成功')
|
||||
|
|
|
@ -457,6 +457,7 @@ const columns = [
|
|||
width: 200,
|
||||
search: {
|
||||
type: 'string',
|
||||
defaultTermType: 'eq'
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -466,6 +467,9 @@ const columns = [
|
|||
ellipsis: true,
|
||||
scopedSlots: true,
|
||||
width: 200,
|
||||
search: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '平台对接',
|
||||
|
@ -568,10 +572,11 @@ const columns = [
|
|||
search: {
|
||||
type: 'select',
|
||||
options: [
|
||||
{ label: '正常', value: 'using' },
|
||||
{ label: '激活', value: 'using' },
|
||||
{ label: '未激活', value: 'toBeActivated' },
|
||||
{ label: '停机', value: 'deactivate' },
|
||||
],
|
||||
{ label: '其它', value: 'using,toBeActivated,deactivate' },
|
||||
]
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -737,7 +742,16 @@ const getActions = (
|
|||
};
|
||||
|
||||
const handleSearch = (e: any) => {
|
||||
params.value = e;
|
||||
const newParams = (e?.terms as any[])?.map(item1 => {
|
||||
item1.terms = item1.terms.map((item2: any) => {
|
||||
if (['cardStateType'].includes(item2.column)) {
|
||||
item2.termType = 'nin'
|
||||
}
|
||||
return item2
|
||||
})
|
||||
return item1
|
||||
})
|
||||
params.value = { terms: newParams || [] };
|
||||
};
|
||||
|
||||
const onSelectChange = (keys: string[], rows: []) => {
|
||||
|
|
|
@ -87,7 +87,7 @@
|
|||
</page-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
<script setup lang="ts" name='IotCardHome'>
|
||||
import { getImage } from '@/utils/comm';
|
||||
import Guide from '../components/Guide.vue';
|
||||
import moment from 'moment';
|
||||
|
@ -113,14 +113,14 @@ const menuHasPermission = useMenuStore().hasPermission;
|
|||
const btnHasPermission = usePermissionStore().hasPermission;
|
||||
|
||||
// 菜单权限
|
||||
const dashBoardUrl = menuHasPermission('/iot-card/Dashboard');
|
||||
const platformUrl = menuHasPermission('/iot-card/Platform/Detail');
|
||||
const recordUrl = menuHasPermission('/iot-card/Record');
|
||||
const cardUrl = menuHasPermission('/iot-card/CardManagement');
|
||||
const dashBoardUrl = menuHasPermission('iot-card/Dashboard');
|
||||
const platformUrl = menuHasPermission('iot-card/Platform/Detail');
|
||||
const recordUrl = menuHasPermission('iot-card/Record');
|
||||
const cardUrl = menuHasPermission('iot-card/CardManagement');
|
||||
|
||||
// 按钮权限
|
||||
const paltformPermission = btnHasPermission(`/iot-card/Platform:add`);
|
||||
const cardPermission = btnHasPermission(`/iot-card/CardManagement:add`);
|
||||
const paltformPermission = btnHasPermission(`iot-card/Platform:add`);
|
||||
const cardPermission = btnHasPermission(`iot-card/CardManagement:add`);
|
||||
|
||||
const Image = {
|
||||
1: getImage('/home/1.png'),
|
||||
|
@ -179,23 +179,19 @@ const pieChartData = ref<any[]>([
|
|||
]);
|
||||
|
||||
const jumpPage = (data: GuideItemProps) => {
|
||||
console.log(data.auth)
|
||||
if (!data.auth){
|
||||
message.warning('暂无权限,请联系管理员');
|
||||
return
|
||||
}
|
||||
if (data.key === 'EQUIPMENT') {
|
||||
menuStory.jumpPage(data.url, { id: 'add' });
|
||||
menuStory.jumpPage(data.url, { id: ':id'});
|
||||
} else {
|
||||
menuStory.jumpPage(data.url);
|
||||
}
|
||||
};
|
||||
|
||||
const jumpDashboard = () => {
|
||||
// if (dashBoardUrl) {
|
||||
// router.push(`${dashBoardUrl}`);
|
||||
// } else {
|
||||
// message.warning('暂无权限,请联系管理员');
|
||||
// }
|
||||
menuStory.jumpPage('iot-card/Dashboard');
|
||||
};
|
||||
|
||||
|
|
|
@ -204,6 +204,7 @@ const rules = {
|
|||
};
|
||||
|
||||
const getDetail = async () => {
|
||||
console.log(route.params)
|
||||
if (route.params.id === ':id') return;
|
||||
const resp: any = await queryById(route.params.id);
|
||||
if (resp.status === 200) {
|
||||
|
|
|
@ -238,7 +238,7 @@ const handleSearch = (e: any) => {
|
|||
* 新增
|
||||
*/
|
||||
const handleAdd = () => {
|
||||
menuStory.jumpPage('iot-card/Platform/Detail', { id: 'add' })
|
||||
menuStory.jumpPage('iot-card/Platform/Detail', { id: ':id' })
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
@ -16,8 +16,9 @@
|
|||
</j-radio-button>
|
||||
</j-radio-group>
|
||||
<j-range-picker
|
||||
format="YYYY-MM-DD"
|
||||
valueFormat="YYYY-MM-DD"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
valueFormat="YYYY-MM-DD HH:mm:ss"
|
||||
:show-time="{ format: 'HH:mm:ss' }"
|
||||
style="margin-left: 12px"
|
||||
@change="rangeChange"
|
||||
v-model:value="rangeVal"
|
||||
|
@ -28,7 +29,7 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import moment from 'moment';
|
||||
import dayjs from 'dayjs';
|
||||
import { PropType } from 'vue';
|
||||
|
||||
interface BtnOptions {
|
||||
|
@ -70,38 +71,37 @@ const rangeVal = ref<[string, string]>();
|
|||
const rangeChange = (val: any) => {
|
||||
radioValue.value = undefined;
|
||||
emit('change', {
|
||||
start: moment(val[0]).valueOf(),
|
||||
end: moment(val[1]).valueOf(),
|
||||
start: dayjs(val[0]).valueOf(),
|
||||
end: dayjs(val[1]).valueOf(),
|
||||
type: undefined,
|
||||
});
|
||||
};
|
||||
|
||||
const getTimeByType = (type: string) => {
|
||||
const getTimeByType = (type?: string) => {
|
||||
switch (type) {
|
||||
case 'hour':
|
||||
return moment().subtract(1, 'hours').valueOf();
|
||||
return dayjs().subtract(1, 'hours').valueOf();
|
||||
case 'week':
|
||||
return moment().subtract(6, 'days').valueOf();
|
||||
return dayjs().subtract(6, 'days').valueOf();
|
||||
case 'month':
|
||||
return moment().subtract(29, 'days').valueOf();
|
||||
return dayjs().subtract(29, 'days').valueOf();
|
||||
case 'year':
|
||||
return moment().subtract(365, 'days').valueOf();
|
||||
return dayjs().subtract(365, 'days').valueOf();
|
||||
default:
|
||||
return moment().startOf('day').valueOf();
|
||||
return dayjs().startOf('day').valueOf();
|
||||
}
|
||||
};
|
||||
|
||||
const handleBtnChange = (val: string) => {
|
||||
radioValue.value = val;
|
||||
let endTime = moment(new Date()).valueOf();
|
||||
const handleBtnChange = (val?: string) => {
|
||||
let endTime = dayjs(new Date()).valueOf();
|
||||
let startTime = getTimeByType(val);
|
||||
if (val === 'yesterday') {
|
||||
startTime = moment().subtract(1, 'days').startOf('day').valueOf();
|
||||
endTime = moment().subtract(1, 'days').endOf('day').valueOf();
|
||||
startTime = dayjs().subtract(1, 'days').startOf('day').valueOf();
|
||||
endTime = dayjs().subtract(1, 'days').endOf('day').valueOf();
|
||||
}
|
||||
rangeVal.value = [
|
||||
moment(startTime).format('YYYY-MM-DD'),
|
||||
moment(endTime).format('YYYY-MM-DD'),
|
||||
dayjs(startTime).format('YYYY-MM-DD HH:mm:ss'),
|
||||
dayjs(endTime).format('YYYY-MM-DD HH:mm:ss'),
|
||||
];
|
||||
emit('change', {
|
||||
start: startTime,
|
||||
|
@ -110,11 +110,8 @@ const handleBtnChange = (val: string) => {
|
|||
});
|
||||
};
|
||||
|
||||
watch(
|
||||
() => radioValue.value,
|
||||
(val) => {
|
||||
handleBtnChange(val);
|
||||
},
|
||||
{ deep: true, immediate: true },
|
||||
);
|
||||
nextTick(() => {
|
||||
handleBtnChange(radioValue.value)
|
||||
})
|
||||
|
||||
</script>
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
</j-col>
|
||||
</j-row>
|
||||
<j-form-item label="级别" name="level">
|
||||
<j-radio-group v-model:value="form.level">
|
||||
<j-radio-group v-model:value="form.level" class="levelSelect">
|
||||
<j-radio-button
|
||||
v-for="(item, index) in levelOption"
|
||||
:key="index"
|
||||
|
@ -199,7 +199,11 @@ queryData();
|
|||
<style lang="less" scoped>
|
||||
.ant-radio-button-wrapper {
|
||||
margin: 10px 15px 0 0;
|
||||
width: 125px;
|
||||
width: 20%;
|
||||
height: 100%;
|
||||
}
|
||||
.levelSelect{
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
|
@ -1,13 +1,5 @@
|
|||
<template>
|
||||
<j-modal
|
||||
visible
|
||||
title="处理记录"
|
||||
:width="1200"
|
||||
cancelText="取消"
|
||||
okText="确定"
|
||||
@ok="clsoeModal"
|
||||
@cancel="clsoeModal"
|
||||
>
|
||||
<page-container>
|
||||
<pro-search
|
||||
:columns="columns"
|
||||
target="bind-channel"
|
||||
|
@ -30,7 +22,7 @@
|
|||
<span>
|
||||
{{
|
||||
dayjs(slotsProps.handleTime).format(
|
||||
'YYYY-MM-DD HH:mm:ss'
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
)
|
||||
}}
|
||||
</span>
|
||||
|
@ -41,29 +33,25 @@
|
|||
<template #alarmTime="slotProps">
|
||||
<span>
|
||||
{{
|
||||
dayjs(slotProps.alarmTime).format(
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
)
|
||||
dayjs(slotProps.alarmTime).format('YYYY-MM-DD HH:mm:ss')
|
||||
}}
|
||||
</span>
|
||||
</template>
|
||||
</JProTable>
|
||||
</j-modal>
|
||||
</page-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { queryHandleHistory } from '@/api/rule-engine/log';
|
||||
import dayjs from 'dayjs';
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
},
|
||||
});
|
||||
import { useRoute } from 'vue-router';
|
||||
const route = useRoute();
|
||||
const id = route.query?.id;
|
||||
const terms = [
|
||||
{
|
||||
column: 'alarmRecordId',
|
||||
termType: 'eq',
|
||||
value: props.data.id,
|
||||
value: id,
|
||||
type: 'and',
|
||||
},
|
||||
];
|
||||
|
@ -119,9 +107,6 @@ const emit = defineEmits(['closeLog']);
|
|||
/**
|
||||
* 关闭弹窗
|
||||
*/
|
||||
const clsoeModal = () => {
|
||||
emit('closeLog');
|
||||
};
|
||||
|
||||
const handleSearch = (e: any) => {
|
||||
params.value = e;
|
|
@ -62,8 +62,8 @@
|
|||
</span>
|
||||
</Ellipsis>
|
||||
<j-row :gutter="24">
|
||||
<j-col :span="8">
|
||||
<div class="content-des-title">
|
||||
<j-col :span="8" class="content-left">
|
||||
<div class="content-left-title">
|
||||
{{ titleMap.get(slotProps.targetType) }}
|
||||
</div>
|
||||
<Ellipsis
|
||||
|
@ -73,7 +73,7 @@
|
|||
>
|
||||
</j-col>
|
||||
<j-col :span="8">
|
||||
<div class="content-des-title">
|
||||
<div class="content-right-title">
|
||||
最近告警时间
|
||||
</div>
|
||||
<Ellipsis
|
||||
|
@ -87,7 +87,7 @@
|
|||
>
|
||||
</j-col>
|
||||
<j-col :span="8">
|
||||
<div class="content-des-title">状态</div>
|
||||
<div class="content-right-title">状态</div>
|
||||
<BadgeStatus
|
||||
:status="slotProps.state.value"
|
||||
:statusName="{
|
||||
|
@ -136,11 +136,6 @@
|
|||
v-if="data.solveVisible"
|
||||
@closeSolve="closeSolve"
|
||||
/>
|
||||
<SolveLog
|
||||
:data="data.current"
|
||||
v-if="data.logVisible"
|
||||
@closeLog="closeLog"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -292,7 +287,7 @@ const orgCol = [
|
|||
},
|
||||
];
|
||||
|
||||
let params = ref({
|
||||
let params:any = ref({
|
||||
sorts: [{ name: 'alarmTime', order: 'desc' }],
|
||||
terms: [],
|
||||
});
|
||||
|
@ -412,8 +407,11 @@ const getActions = (
|
|||
},
|
||||
icon: 'FileTextOutlined',
|
||||
onClick: () => {
|
||||
data.value.current = currentData;
|
||||
data.value.logVisible = true;
|
||||
menuStory.jumpPage(
|
||||
'rule-engine/Alarm/Log/Record',
|
||||
{},
|
||||
{ id: currentData.id },
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
@ -434,4 +432,14 @@ const closeLog = () => {
|
|||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.content-left{
|
||||
border-right: .2px solid rgba(0,0,0,0.2);
|
||||
}
|
||||
.content-right-title{
|
||||
color: #666;
|
||||
font-size: 12px
|
||||
}
|
||||
.content-left-title{
|
||||
font-size: 18px
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
:statusText="slotProps.state?.text"
|
||||
@click="openRuleEditor"
|
||||
:statusNames="{
|
||||
started: 'success',
|
||||
started: 'processing',
|
||||
disable: 'error',
|
||||
}"
|
||||
>
|
||||
|
@ -88,17 +88,17 @@
|
|||
</CardBox>
|
||||
</template>
|
||||
<template #state="slotProps">
|
||||
<j-badge
|
||||
<BadgeStatus
|
||||
:text="
|
||||
slotProps.state?.value === 'started'
|
||||
? '正常'
|
||||
: '禁用'
|
||||
"
|
||||
:status="
|
||||
slotProps.state?.value === 'started'
|
||||
? 'success'
|
||||
: 'error'
|
||||
"
|
||||
:status="slotProps.state?.value"
|
||||
:statusNames="{
|
||||
started: 'processing',
|
||||
disable: 'error',
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
title='触发规则'
|
||||
visible
|
||||
:width='820'
|
||||
@click='save'
|
||||
@ok='save'
|
||||
@cancel='cancel'
|
||||
:maskClosable="false"
|
||||
>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
:columns="columns"
|
||||
type='simple'
|
||||
@search="handleSearch"
|
||||
class='search'
|
||||
class="scene-search"
|
||||
target="scene-triggrt-device-device"
|
||||
/>
|
||||
<j-divider style='margin: 0' />
|
||||
|
|
|
@ -22,11 +22,16 @@
|
|||
<j-form-item>定时调用所选功能</j-form-item>
|
||||
</j-col>
|
||||
<j-col :span='24'>
|
||||
<j-form-item
|
||||
name='functionData'
|
||||
:rules="rules"
|
||||
>
|
||||
<FunctionCall
|
||||
:value='_value'
|
||||
v-model:value='formModel.functionData'
|
||||
:data='functionData'
|
||||
@change='callDataChange'
|
||||
/>
|
||||
</j-form-item>
|
||||
</j-col>
|
||||
</j-row>
|
||||
</j-form>
|
||||
|
@ -66,9 +71,9 @@ const props = defineProps({
|
|||
const emit = defineEmits<Emit>()
|
||||
const invokeForm = ref()
|
||||
const formModel = reactive({
|
||||
functionId: props.functionId
|
||||
functionId: props.functionId,
|
||||
functionData: props.functionParameters
|
||||
})
|
||||
const _value = ref<any[]>(props.functionParameters)
|
||||
|
||||
/**
|
||||
* 获取当前选择功能属性
|
||||
|
@ -94,13 +99,29 @@ const functionData = computed(() => {
|
|||
return arrCache
|
||||
})
|
||||
|
||||
const rules = [{
|
||||
validator(_: string, value: any) {
|
||||
if (!value?.length && functionData.value.length) {
|
||||
return Promise.reject('请输入功能值')
|
||||
} else {
|
||||
let hasValue = value.find((item: { name: string, value: any}) => !item.value)
|
||||
if (hasValue) {
|
||||
const functionItem = functionData.value.find((item: any) => item.id === hasValue.name)
|
||||
return Promise.reject(functionItem?.name ? `请输入${functionItem?.name}值` : '请输入功能值')
|
||||
}
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
}]
|
||||
|
||||
const onSelect = (v: string, item: any) => {
|
||||
formModel.functionData = []
|
||||
emit('update:action', `执行${item.name}`)
|
||||
emit('update:functionId', v)
|
||||
emit('update:functionParameters', [])
|
||||
}
|
||||
|
||||
const callDataChange = (v: any[]) => {
|
||||
_value.value = v
|
||||
emit('update:functionParameters', v)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
:columns="columns"
|
||||
type='simple'
|
||||
@search="handleSearch"
|
||||
class='search'
|
||||
class="scene-search"
|
||||
target="scene-triggrt-device-device"
|
||||
/>
|
||||
<j-divider style='margin: 0' />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class='actions-branches-item'>
|
||||
<div class='manual actions-branches-item'>
|
||||
<j-form-item
|
||||
:rules="actionRules"
|
||||
:name="['branches', 0, 'then']"
|
||||
|
@ -32,6 +32,21 @@ const actionRules = [{
|
|||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style scoped lang='less'>
|
||||
@minWidth: 75%;
|
||||
|
||||
.manual {
|
||||
&.actions-branches-item {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (min-width: 1600px) {
|
||||
.manual {
|
||||
&.actions-branches-item {
|
||||
width: @minWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -3,7 +3,7 @@
|
|||
title='触发规则'
|
||||
visible
|
||||
:width='820'
|
||||
@click='save'
|
||||
@ok='save'
|
||||
@cancel='cancel'
|
||||
>
|
||||
<Timer
|
||||
|
@ -15,17 +15,16 @@
|
|||
<script setup lang="ts" name="timerAddModel">
|
||||
import Timer from '../components/Timer'
|
||||
import type { OperationTimer } from '@/views/rule-engine/Scene/typings'
|
||||
import {nextTick, PropType} from "vue";
|
||||
import {TriggerDevice} from "@/views/rule-engine/Scene/typings";
|
||||
import { PropType} from "vue";
|
||||
import {handleTimerOptions} from "@/views/rule-engine/Scene/Save/components/Timer/util";
|
||||
|
||||
type Emit = {
|
||||
(e: 'cancel'): void
|
||||
(e: 'save', data: TriggerDevice, options: Record<string, any>): void
|
||||
(e: 'save', data: OperationTimer, options: Record<string, any>): void
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
timer: {
|
||||
value: {
|
||||
type: Object as PropType<OperationTimer>,
|
||||
default: () => ({})
|
||||
}
|
||||
|
@ -39,14 +38,14 @@ interface AddModelType {
|
|||
}
|
||||
|
||||
const addModel = reactive<AddModelType>({
|
||||
timer: props.timer
|
||||
timer: props.value
|
||||
})
|
||||
|
||||
const save = async () => {
|
||||
const timerData = await timerRef.value?.validateFields()
|
||||
if (timerData) {
|
||||
const options = handleTimerOptions(timerData)
|
||||
emit("save", timerData, options)
|
||||
const options = handleTimerOptions(addModel.timer)
|
||||
emit("save", addModel.timer, options)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,9 +53,9 @@ const cancel = () => {
|
|||
emit("cancel")
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
Object.assign(addModel, props.timer)
|
||||
})
|
||||
// watchEffect(() => {
|
||||
// addModel.timer = props.value
|
||||
// })
|
||||
|
||||
</script>
|
||||
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
<template>
|
||||
<div :class='["trigger-options-content", isAdd ? "is-add" : ""]'>
|
||||
<span v-if='!isAdd'> 点击配置定时触发 </span>
|
||||
<template v-else>
|
||||
<div class='center-item'>
|
||||
<AIcon v-if='options.selectorIcon' :type='options.selectorIcon' class='icon-padding-right' />
|
||||
<span class='trigger-options-name'>
|
||||
<Ellipsis style='max-width: 310px'>
|
||||
{{ options.name }}
|
||||
</Ellipsis>
|
||||
</span>
|
||||
<span v-if='options.extraName'>{{ options.extraName }}</span>
|
||||
</div>
|
||||
<div v-if='options.when'>
|
||||
<span className='trigger-options-when'>{{ options.when }}</span>
|
||||
</div>
|
||||
<div v-if='options.time'>
|
||||
<span className='trigger-options-time'>{{ options.time }}</span>
|
||||
</div>
|
||||
<div v-if='options.extraTime'>
|
||||
<span className='trigger-options-extraTime'>{{ options.extraTime }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts' name='TimerTitle'>
|
||||
|
||||
const props = defineProps({
|
||||
options: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
|
||||
const isAdd = computed(() => {
|
||||
console.log(props.options, Object.keys(props.options).length)
|
||||
return !!Object.keys(props.options).length
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang='less'>
|
||||
.trigger-options-content {
|
||||
display: inline-flex;
|
||||
gap: 16px;
|
||||
|
||||
.center-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.icon-padding-right {
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
|
@ -2,7 +2,7 @@
|
|||
<div class='timer'>
|
||||
<j-form-item
|
||||
:rules="rules"
|
||||
name="timer"
|
||||
:name="['trigger', 'timer']"
|
||||
>
|
||||
<template #label>
|
||||
<TitleComponent data='触发规则' style='font-size: 14px;' />
|
||||
|
@ -29,8 +29,7 @@
|
|||
v-if="visible"
|
||||
@cancel='visible = false'
|
||||
@save="save"
|
||||
:value="data.trigger.device"
|
||||
:options="data.options.trigger"
|
||||
:value="data.trigger.timer"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -41,6 +40,7 @@ import { storeToRefs } from 'pinia';
|
|||
import Action from '../action/index.vue';
|
||||
import AddModel from './AddModal.vue'
|
||||
import AddButton from '../components/AddButton.vue'
|
||||
import Title from './Title.vue'
|
||||
import type { OperationTimer, BranchesThen } from '@/views/rule-engine/Scene/typings'
|
||||
|
||||
const sceneStore = useSceneStore();
|
||||
|
@ -49,6 +49,7 @@ const visible = ref(false)
|
|||
|
||||
const rules = [{
|
||||
validator(_: any, v: any) {
|
||||
console.log(v)
|
||||
if (!v) {
|
||||
return Promise.reject(new Error('请配置定时触发规则'));
|
||||
}
|
||||
|
@ -85,5 +86,21 @@ const save = (_data: OperationTimer, options: Record<string, any>) => {
|
|||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style scoped lang='less'>
|
||||
@minWidth: 75%;
|
||||
|
||||
.timer {
|
||||
.actions-branches-item {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (min-width: 1600px) {
|
||||
.timer {
|
||||
.actions-branches-item {
|
||||
width: @minWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -3,7 +3,7 @@
|
|||
:columns="columns"
|
||||
type="simple"
|
||||
@search="handleSearch"
|
||||
class="search"
|
||||
class="scene-search"
|
||||
target="scene-trigger-device-product"
|
||||
/>
|
||||
<j-divider style="margin: 0" />
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
showSearch
|
||||
placeholder="请选择功能"
|
||||
v-model:value="modelRef.message.functionId"
|
||||
@select='functionSelect'
|
||||
>
|
||||
<j-select-option
|
||||
v-for="item in metadata?.functions || []"
|
||||
|
@ -34,7 +35,7 @@
|
|||
<j-form-item
|
||||
v-if="modelRef.message.functionId"
|
||||
:name="['message', 'inputs']"
|
||||
:rules="[{ required: true, message: '请输入功能值' }]"
|
||||
:rules="functionRules"
|
||||
>
|
||||
<EditTable
|
||||
:functions="functions"
|
||||
|
@ -138,6 +139,25 @@ const modelRef = reactive({
|
|||
},
|
||||
});
|
||||
|
||||
const functionSelect = () => {
|
||||
modelRef.message.inputs = []
|
||||
}
|
||||
|
||||
const functionRules = [{
|
||||
validator(_: string, value: any) {
|
||||
if (!value?.length && functions.value.length) {
|
||||
return Promise.reject('请输入功能值')
|
||||
} else {
|
||||
const hasValue = value.find((item: { name: string, value: any}) => !item.value)
|
||||
if (hasValue) {
|
||||
const functionItem = functions.value.find((item: any) => item.id === hasValue.name)
|
||||
return Promise.reject(functionItem?.name ? `请输入${functionItem.name}值` : '请输入功能值')
|
||||
}
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
}]
|
||||
|
||||
const metadata = ref<{
|
||||
functions: any[];
|
||||
properties: any[];
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
:columns="columns"
|
||||
type="simple"
|
||||
@search="handleSearch"
|
||||
class="search"
|
||||
class="scene-search"
|
||||
target="scene-trigger-device-device"
|
||||
/>
|
||||
<j-divider style="margin: 0" />
|
||||
|
|
|
@ -101,6 +101,7 @@ const valueChange = debounce(() => {
|
|||
const _value = dataSource.value.map(item => ({
|
||||
name: item.id, value: item.value
|
||||
}))
|
||||
console.log(_value)
|
||||
emit('change', _value)
|
||||
emit('update:value', _value)
|
||||
}, 500)
|
||||
|
|
|
@ -17,6 +17,7 @@ import { numberToString } from './util'
|
|||
|
||||
type Emit = {
|
||||
(e: 'update:value', data: Array<number>):void
|
||||
(e: 'change', data: Array<number>):void
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
|
@ -48,6 +49,7 @@ const change = (number: number) => {
|
|||
}
|
||||
rowKeys.value = [..._keys.values()]
|
||||
emit('update:value', rowKeys.value)
|
||||
emit('change', rowKeys.value)
|
||||
}
|
||||
|
||||
const allActive = computed(() => {
|
||||
|
@ -57,7 +59,9 @@ const allActive = computed(() => {
|
|||
watch(() => props.type, () => {
|
||||
const isMonth = props.type === 'month'
|
||||
const day = isMonth ? 31 : 7
|
||||
change(0)
|
||||
if (!props.value.length) {
|
||||
change(0)
|
||||
}
|
||||
timeOptions.value = new Array(day)
|
||||
.fill(1)
|
||||
.map((_, index) => {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
]'
|
||||
option-type='button'
|
||||
button-style='solid'
|
||||
@change='updateValue'
|
||||
/>
|
||||
</j-form-item>
|
||||
<j-form-item v-if='showCron' name='cron' :rules="[
|
||||
|
@ -32,11 +33,11 @@
|
|||
}
|
||||
}
|
||||
]">
|
||||
<j-input placeholder='corn表达式' v-model:value='formModel.cron' />
|
||||
<j-input placeholder='corn表达式' v-model:value='formModel.cron' @change='updateValue' />
|
||||
</j-form-item>
|
||||
<template v-else>
|
||||
<j-form-item name='when'>
|
||||
<WhenOption v-model:value='formModel.when' :type='formModel.trigger' />
|
||||
<WhenOption v-model:value='formModel.when' :type='formModel.trigger' @change='updateValue' />
|
||||
</j-form-item>
|
||||
<j-form-item name='mod'>
|
||||
<j-radio-group
|
||||
|
@ -47,13 +48,19 @@
|
|||
]'
|
||||
option-type='button'
|
||||
button-style='solid'
|
||||
@change='updateValue'
|
||||
/>
|
||||
</j-form-item>
|
||||
</template>
|
||||
<j-space v-if='showOnce' style='display: flex;gap: 24px'>
|
||||
<j-form-item :name="['once', 'time']">
|
||||
<j-time-picker valueFormat='HH:mm:ss' v-model:value='formModel.once.time' style='width: 100%'
|
||||
format='HH:mm:ss' />
|
||||
<j-time-picker
|
||||
valueFormat='HH:mm:ss'
|
||||
v-model:value='formModel.once.time'
|
||||
style='width: 100%'
|
||||
format='HH:mm:ss'
|
||||
@change='updateValue'
|
||||
/>
|
||||
</j-form-item>
|
||||
<j-form-item> 执行一次</j-form-item>
|
||||
</j-space>
|
||||
|
@ -68,6 +75,7 @@
|
|||
@change='(v) => {
|
||||
formModel.period.from = v[0]
|
||||
formModel.period.to = v[1]
|
||||
updateValue()
|
||||
}'
|
||||
/>
|
||||
</j-form-item>
|
||||
|
@ -83,6 +91,7 @@
|
|||
:min='1'
|
||||
:max='59'
|
||||
v-model:value='formModel.period.every'
|
||||
@change='updateValue'
|
||||
>
|
||||
<template #addonAfter>
|
||||
<j-select
|
||||
|
@ -92,6 +101,7 @@
|
|||
{ label: "分", value: "minutes" },
|
||||
{ label: "小时", value: "hours" },
|
||||
]'
|
||||
@select='updateValue'
|
||||
/>
|
||||
</template>
|
||||
</j-input-number>
|
||||
|
@ -103,7 +113,7 @@
|
|||
|
||||
<script setup lang='ts' name='Timer'>
|
||||
import type { PropType } from 'vue'
|
||||
import moment from 'moment'
|
||||
import dayjs from 'dayjs'
|
||||
import WhenOption from './WhenOption.vue'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import type { OperationTimer } from '../../../typings'
|
||||
|
@ -131,23 +141,21 @@ const emit = defineEmits<Emit>()
|
|||
|
||||
const formModel = reactive<OperationTimer>({
|
||||
trigger: 'week',
|
||||
when: [],
|
||||
when: props.value.when || [],
|
||||
mod: 'period',
|
||||
cron: undefined,
|
||||
once: {
|
||||
time: moment(new Date()).format('HH:mm:ss')
|
||||
time: dayjs(new Date()).format('HH:mm:ss')
|
||||
},
|
||||
period: {
|
||||
from: moment(new Date()).startOf('day').format('HH:mm:ss'),
|
||||
to: moment(new Date()).endOf('day').format('HH:mm:ss'),
|
||||
from: dayjs(new Date()).startOf('day').format('HH:mm:ss'),
|
||||
to: dayjs(new Date()).endOf('day').format('HH:mm:ss'),
|
||||
every: 1,
|
||||
unit: 'seconds'
|
||||
}
|
||||
})
|
||||
const timerForm = ref()
|
||||
|
||||
Object.assign(formModel, props.value)
|
||||
|
||||
const showCron = computed(() => {
|
||||
return formModel.trigger === 'cron'
|
||||
})
|
||||
|
@ -160,7 +168,7 @@ const showPeriod = computed(() => {
|
|||
return formModel.trigger !== 'cron' && formModel.mod === 'period'
|
||||
})
|
||||
|
||||
watch(() => formModel, () => {
|
||||
const updateValue = () => {
|
||||
const cloneValue = cloneDeep(formModel)
|
||||
if (cloneValue.trigger === 'cron') {
|
||||
delete cloneValue.when
|
||||
|
@ -174,7 +182,7 @@ watch(() => formModel, () => {
|
|||
delete cloneValue.period
|
||||
}
|
||||
emit('update:value', cloneValue)
|
||||
}, { deep: true })
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
validateFields: () => new Promise(async (resolve) => {
|
||||
|
@ -182,6 +190,8 @@ defineExpose({
|
|||
resolve(data)
|
||||
})
|
||||
})
|
||||
Object.assign(formModel, props.value)
|
||||
formModel.when = props.value.when || []
|
||||
|
||||
</script>
|
||||
|
||||
|
|
|
@ -57,15 +57,17 @@ const classNames = computed(() => {
|
|||
})
|
||||
|
||||
const handleClick = (type: string) => {
|
||||
emit('update:modelValue', type)
|
||||
if (!props.disabled) {
|
||||
emit('update:modelValue', type)
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang='less'>
|
||||
// @import 'ant-design-vue/es/style/themes/default.less';
|
||||
|
||||
.scene-trigger-way-warp {display: flex;
|
||||
.scene-trigger-way-warp {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px 24px;
|
||||
width: 100%;
|
||||
|
@ -115,5 +117,16 @@ const handleClick = (type: string) => {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
color: rgba(#000, .8);
|
||||
.way-item-image {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.trigger-way-item {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -114,4 +114,7 @@ onUnmounted(() => {
|
|||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang='less'>
|
||||
@import "./style.less";
|
||||
</style>
|
|
@ -0,0 +1,3 @@
|
|||
.scene-search {
|
||||
padding: 24px 0 0 0;
|
||||
}
|
|
@ -300,7 +300,7 @@ const getActions = (
|
|||
];
|
||||
if (data.triggerType === 'manual') {
|
||||
const _item: ActionsType = {
|
||||
key: 'trigger',
|
||||
key: 'tigger',
|
||||
text: '手动触发',
|
||||
disabled: data.state?.value === 'disable',
|
||||
tooltip: {
|
||||
|
|
|
@ -143,6 +143,9 @@ import {
|
|||
} from '@/api/system/department';
|
||||
import { message } from 'jetlinks-ui-components';
|
||||
import { dictType } from '../typing';
|
||||
import { useDepartmentStore } from '@/store/department';
|
||||
|
||||
const departmentStore = useDepartmentStore();
|
||||
|
||||
const emits = defineEmits(['confirm', 'update:visible']);
|
||||
const props = defineProps<{
|
||||
|
@ -154,6 +157,9 @@ const props = defineProps<{
|
|||
}>();
|
||||
// 弹窗相关
|
||||
const loading = ref(false);
|
||||
// 资产咨询次数, 产品分配后自动进入的设备资产, 第一次需要带上产品id查询
|
||||
const queryCount = ref(0);
|
||||
|
||||
const confirm = () => {
|
||||
if (table.selectedRows.length < 1) {
|
||||
return message.warning('请先勾选数据');
|
||||
|
@ -167,6 +173,11 @@ const confirm = () => {
|
|||
permission: item.selectPermissions,
|
||||
}));
|
||||
|
||||
if (params.length === 1) {
|
||||
// 只选择一个产品资产分配时, 分配之后, 进入设备资产分配需查出对应产品下的设备
|
||||
departmentStore.setProductId(params[0].assetIdList[0]);
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
bindDeviceOrProductList_api(props.assetType, params)
|
||||
.then(() => {
|
||||
|
@ -259,8 +270,10 @@ const table: any = {
|
|||
// 选中
|
||||
onSelectChange: (row: any) => {
|
||||
// 若该项的可选权限中没有分享权限,则不支持任何操作
|
||||
if (!row.permissionList.find((item: any) => item.value === 'share'))
|
||||
if (!row.permissionList.find((item: any) => item.value === 'share')) {
|
||||
message.warning('该资产不支持共享');
|
||||
return;
|
||||
}
|
||||
const selectedRowKeys = table._selectedRowKeys.value;
|
||||
const index = selectedRowKeys.indexOf(row.id);
|
||||
|
||||
|
@ -330,7 +343,9 @@ const table: any = {
|
|||
resolve({
|
||||
code: 200,
|
||||
result: {
|
||||
data: data.sort((a, b) => a.createTime - b.createTime),
|
||||
data: data.sort(
|
||||
(a, b) => a.createTime - b.createTime,
|
||||
),
|
||||
pageIndex,
|
||||
pageSize,
|
||||
total,
|
||||
|
@ -394,6 +409,7 @@ const table: any = {
|
|||
}),
|
||||
// 整理参数并获取数据
|
||||
requestFun: async (oParams: any) => {
|
||||
queryCount.value += 1;
|
||||
if (props.parentId) {
|
||||
const terms = [
|
||||
{
|
||||
|
@ -411,9 +427,24 @@ const table: any = {
|
|||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
column: 'productId$product-info',
|
||||
type: 'and',
|
||||
value: `id is ${departmentStore.productId}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
if (
|
||||
props.assetType !== 'device' ||
|
||||
!departmentStore.productId ||
|
||||
queryCount.value > 1 ||
|
||||
departmentStore.optType === 'handle'
|
||||
) {
|
||||
// 非设备|产品id不存在|有其他查询操作(queryCount+1)|设备页面手动点击资产分配, 均删除产品带入的id
|
||||
terms[0].terms.pop();
|
||||
}
|
||||
if (oParams.terms && oParams.terms.length > 0)
|
||||
terms.unshift({ terms: oParams.terms });
|
||||
const params = {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
placeholder="请选择上级组织"
|
||||
:tree-data="treeData"
|
||||
:field-names="{ value: 'id' }"
|
||||
@change="handleTreeSelectChange"
|
||||
>
|
||||
<template #title="{ name }"> {{ name }} </template>
|
||||
</j-tree-select>
|
||||
|
@ -60,6 +61,21 @@ import {
|
|||
updateDepartment_api,
|
||||
} from '@/api/system/department';
|
||||
|
||||
type treeType = {
|
||||
id: string;
|
||||
parentId?: string;
|
||||
name: string;
|
||||
sortIndex: string | number;
|
||||
children?: treeType[];
|
||||
disabled?: boolean;
|
||||
};
|
||||
type formType = {
|
||||
id?: string;
|
||||
parentId?: string;
|
||||
name: string;
|
||||
sortIndex: string | number;
|
||||
};
|
||||
|
||||
const emits = defineEmits(['refresh', 'update:visible']);
|
||||
const props = defineProps<{
|
||||
treeData: any[];
|
||||
|
@ -91,8 +107,8 @@ const treeData = computed(() => {
|
|||
});
|
||||
/**
|
||||
* 在给定的树中通过id匹配
|
||||
* @param node
|
||||
* @param id
|
||||
* @param node
|
||||
* @param id
|
||||
*/
|
||||
const findItemById = (node: treeType[], id: string): treeType | null => {
|
||||
let result = null;
|
||||
|
@ -107,7 +123,7 @@ const findItemById = (node: treeType[], id: string): treeType | null => {
|
|||
};
|
||||
/**
|
||||
* 将此树下的所有节点禁用
|
||||
* @param treeNode
|
||||
* @param treeNode
|
||||
*/
|
||||
const filterTree = (treeNode: treeType[]) => {
|
||||
if (treeNode.length < 1) return;
|
||||
|
@ -160,18 +176,15 @@ const form = reactive({
|
|||
});
|
||||
form.init();
|
||||
|
||||
type treeType = {
|
||||
id: string;
|
||||
parentId?: string;
|
||||
name: string;
|
||||
sortIndex: string | number;
|
||||
children?: treeType[];
|
||||
disabled?: boolean;
|
||||
};
|
||||
type formType = {
|
||||
id?: string;
|
||||
parentId?: string;
|
||||
name: string;
|
||||
sortIndex: string | number;
|
||||
/**
|
||||
* 上级组织选择改变
|
||||
*/
|
||||
const handleTreeSelectChange = () => {
|
||||
// 上级组织
|
||||
const parent = treeData.value.find((f: any) => f.id === form.data.parentId);
|
||||
// 当前编辑的组织排序, 为选择上级组织的最大排序+1, 如上级组织没有自组织, 则默认为1
|
||||
form.data.sortIndex = parent?.children
|
||||
? parent.children[parent.children.length - 1].sortIndex + 1
|
||||
: 1;
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<PermissionButton
|
||||
:hasPermission="`${permission}:assert`"
|
||||
type="primary"
|
||||
@click="table.clickAdd"
|
||||
@click="table.clickAdd('handle')"
|
||||
>
|
||||
<AIcon type="PlusOutlined" />资产分配
|
||||
</PermissionButton>
|
||||
|
@ -70,7 +70,7 @@
|
|||
:status="slotProps.state?.value"
|
||||
:statusText="slotProps.state?.text"
|
||||
:statusNames="{
|
||||
online: 'success',
|
||||
online: 'processing',
|
||||
offline: 'error',
|
||||
notActive: 'warning',
|
||||
}"
|
||||
|
@ -147,7 +147,7 @@
|
|||
:status="slotProps.state.value"
|
||||
:text="slotProps.state.text"
|
||||
:statusNames="{
|
||||
online: 'success',
|
||||
online: 'processing',
|
||||
offline: 'error',
|
||||
notActive: 'warning',
|
||||
}"
|
||||
|
@ -211,6 +211,9 @@ import { intersection } from 'lodash-es';
|
|||
|
||||
import type { dictType, optionsType } from '../typing';
|
||||
import { message } from 'jetlinks-ui-components';
|
||||
import { useDepartmentStore } from '@/store/department';
|
||||
|
||||
const departmentStore = useDepartmentStore();
|
||||
|
||||
const permission = 'system/Department';
|
||||
|
||||
|
@ -247,6 +250,9 @@ const columns = [
|
|||
search: {
|
||||
rename: 'productId$product-info',
|
||||
type: 'select',
|
||||
handleValue(value: string) {
|
||||
return `id is ${value}`;
|
||||
},
|
||||
options: () =>
|
||||
new Promise((resolve) => {
|
||||
const params = {
|
||||
|
@ -288,14 +294,9 @@ const columns = [
|
|||
search: {
|
||||
type: 'select',
|
||||
options: [
|
||||
{
|
||||
label: '正常',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: '禁用',
|
||||
value: 0,
|
||||
},
|
||||
{ label: '禁用', value: 'notActive' },
|
||||
{ label: '离线', value: 'offline' },
|
||||
{ label: '在线', value: 'online' },
|
||||
],
|
||||
},
|
||||
scopedSlots: true,
|
||||
|
@ -467,7 +468,9 @@ const table = {
|
|||
};
|
||||
}
|
||||
},
|
||||
clickAdd: () => {
|
||||
clickAdd: (type?: string) => {
|
||||
// 设备资产分配弹窗操作类型: type = 'handle': 手动点击资产分配按钮, !type产品资产分配后, 自动弹出设备资产分配
|
||||
departmentStore.setType(type)
|
||||
dialogs.addShow = true;
|
||||
},
|
||||
clickEdit: (row?: any) => {
|
||||
|
@ -520,7 +523,7 @@ const dialogs = reactive({
|
|||
});
|
||||
|
||||
table.init();
|
||||
nextTick(() => {
|
||||
watchEffect(() => {
|
||||
props.bindBool && table.clickAdd();
|
||||
emits('update:bindBool', false);
|
||||
});
|
||||
|
|
|
@ -68,9 +68,8 @@
|
|||
:status="slotProps.state?.value"
|
||||
:statusText="slotProps.state?.text"
|
||||
:statusNames="{
|
||||
online: 'success',
|
||||
offline: 'error',
|
||||
notActive: 'warning',
|
||||
1: 'processing',
|
||||
0: 'error',
|
||||
}"
|
||||
>
|
||||
<template #img>
|
||||
|
@ -172,9 +171,8 @@
|
|||
:status="slotProps.state.value"
|
||||
:text="slotProps.state.text"
|
||||
:statusNames="{
|
||||
online: 'success',
|
||||
offline: 'error',
|
||||
notActive: 'warning',
|
||||
1: 'processing',
|
||||
0: 'error',
|
||||
}"
|
||||
></BadgeStatus>
|
||||
</template>
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
:dataSource="paramsTable"
|
||||
:pagination="false"
|
||||
size="small"
|
||||
bordered
|
||||
>
|
||||
<template #bodyCell="{ column, record, index }">
|
||||
<template v-if="column.key === 'name'">
|
||||
|
@ -65,8 +66,7 @@
|
|||
</template>
|
||||
<template v-else-if="column.key === 'action'">
|
||||
<PermissionButton
|
||||
type="link"
|
||||
:hasPermission="`{permission}:delete`"
|
||||
type="text"
|
||||
:popConfirm="{
|
||||
title: `确定删除`,
|
||||
onConfirm: () =>
|
||||
|
@ -88,8 +88,9 @@
|
|||
style="text-align: center"
|
||||
/>
|
||||
<j-button
|
||||
type="dashed"
|
||||
@click="requestBody.addRow"
|
||||
style="width: 100%; text-align: center"
|
||||
style="width: 100%; text-align: center; margin-top: 5px;"
|
||||
>
|
||||
<AIcon type="PlusOutlined" />新增
|
||||
</j-button>
|
||||
|
@ -305,11 +306,15 @@ type requestObj = {
|
|||
}
|
||||
}
|
||||
.table {
|
||||
margin-bottom: 22px;
|
||||
:deep(.ant-table-cell) {
|
||||
padding: 0 8px;
|
||||
height: 56px;
|
||||
}
|
||||
}
|
||||
:deep(.ant-form-item) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ const rowSelection = {
|
|||
},
|
||||
selectedRowKeys: ref<string[]>([]),
|
||||
};
|
||||
const save = () => {
|
||||
const save = async () => {
|
||||
const keys = props.selectedRowKeys;
|
||||
|
||||
const removeKeys = props.sourceKeys.filter((key) => !keys.includes(key));
|
||||
|
@ -87,13 +87,20 @@ const save = () => {
|
|||
|
||||
if (props.mode === 'api') {
|
||||
// 此时是api配置
|
||||
removeKeys.length &&
|
||||
delOperations_api(removeKeys)
|
||||
.finally(() => addOperations_api(addKeys))
|
||||
.then(() => {
|
||||
message.success('操作成功');
|
||||
emits('refresh')
|
||||
});
|
||||
// removeKeys.length &&
|
||||
// delOperations_api(removeKeys)
|
||||
// .finally(() => addOperations_api(addKeys))
|
||||
// .then(() => {
|
||||
// message.success('操作成功');
|
||||
// emits('refresh');
|
||||
// });
|
||||
// fix: bug#10829
|
||||
removeKeys.length && (await delOperations_api(removeKeys));
|
||||
const res = await addOperations_api(addKeys);
|
||||
if (res.success) {
|
||||
message.success('操作成功');
|
||||
emits('refresh');
|
||||
}
|
||||
} else if (props.mode === 'appManger') {
|
||||
const removeItems = removeKeys.map((key) => ({
|
||||
id: key,
|
||||
|
|
|
@ -78,12 +78,16 @@ const form = reactive({
|
|||
});
|
||||
},
|
||||
clickSave: () => {
|
||||
const updateRole = updateRole_api(form.data);
|
||||
const updateTree = updatePrimissTree_api(roleId, { menus: form.menus });
|
||||
formRef.value?.validate().then(() => {
|
||||
const updateRole = updateRole_api(form.data);
|
||||
const updateTree = updatePrimissTree_api(roleId, {
|
||||
menus: form.menus,
|
||||
});
|
||||
|
||||
Promise.all([updateRole, updateTree]).then((resp) => {
|
||||
message.success('操作成功');
|
||||
router.push('/system/Role');
|
||||
Promise.all([updateRole, updateTree]).then((resp) => {
|
||||
message.success('操作成功');
|
||||
router.push('/system/Role');
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
@ -123,7 +127,7 @@ form.getForm();
|
|||
:deep(.ant-form-item-required) {
|
||||
padding-right: 12px;
|
||||
|
||||
&::before{
|
||||
&::before {
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<pro-search
|
||||
:columns="columns"
|
||||
target="category"
|
||||
@search="(params:any)=>queryParams = {...params}"
|
||||
@search="handleParams"
|
||||
/>
|
||||
|
||||
<j-pro-table
|
||||
|
@ -262,6 +262,23 @@ type dictType = {
|
|||
name: string;
|
||||
};
|
||||
type modalType = '' | 'add' | 'edit' | 'reset';
|
||||
|
||||
const handleParams = (params: any)=> {
|
||||
|
||||
const newParams = (params?.terms as any[])?.map(item1 => {
|
||||
item1.terms = item1.terms.map((item2: any) => {
|
||||
if (['telephone', 'email'].includes(item2.column)) {
|
||||
return {
|
||||
column: 'id$user-detail',
|
||||
value: [item2]
|
||||
}
|
||||
}
|
||||
return item2
|
||||
})
|
||||
return item1
|
||||
})
|
||||
queryParams.value = { terms: newParams || [] }
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
|
@ -92,8 +92,8 @@ export default defineConfig(({ mode}) => {
|
|||
[env.VITE_APP_BASE_API]: {
|
||||
// target: 'http://192.168.33.22:8800',
|
||||
// target: 'http://192.168.32.244:8881',
|
||||
// target: 'http://120.77.179.54:8844', // 120测试
|
||||
target: 'http://192.168.33.46:8844', // 本地开发环境
|
||||
target: 'http://120.77.179.54:8844', // 120测试
|
||||
// target: 'http://192.168.33.46:8844', // 本地开发环境
|
||||
ws: 'ws://192.168.33.46:8844',
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/api/, '')
|
||||
|
|
|
@ -3700,8 +3700,8 @@ jetlinks-store@^0.0.3:
|
|||
|
||||
jetlinks-ui-components@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "http://47.108.170.157:9013/jetlinks-ui-components/-/jetlinks-ui-components-1.0.5.tgz#682711e0f69c141fff2c256db61a060c82539611"
|
||||
integrity sha512-rQxD/YlE+XSAG7BWIcFTtKrCQJXk5o+TUgejyuUT/baBThJB6xYt1k2dQEdXyiwpukYen5FzaoLpelSD9SUegw==
|
||||
resolved "http://47.108.170.157:9013/jetlinks-ui-components/-/jetlinks-ui-components-1.0.5.tgz#f2e62df4054e513df39e3355592d95e356438328"
|
||||
integrity sha512-vfQ8g8nEJueDkHCVcg9WeWDDjnPklyigbobB1CQArfHLd5O4x6vLFWvF69k0yqytCvIOXB13CzhLtMnv68pC5w==
|
||||
dependencies:
|
||||
"@vueuse/core" "^9.12.0"
|
||||
ant-design-vue "^3.2.15"
|
||||
|
|
Loading…
Reference in New Issue