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

This commit is contained in:
jackhoo_98 2023-03-28 18:52:47 +08:00
commit c98d22977a
43 changed files with 599 additions and 278 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

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

View File

@ -43,7 +43,7 @@ export const detail = (id: string) => server.get<ProductItem>(`/device-product/$
*
* @param data
*/
export const category = (data: any) => server.post('/device/category/_tree', data)
export const category = (data: any) => server.get('/device/category/_tree?paging=false', data)
/**
*

View File

@ -5,10 +5,13 @@
:trigger="['click']"
@visible-change="visibleChange"
>
<div class="icon-content">
<!-- <div class="icon-content">
<AIcon type="BellOutlined" style="font-size: 16px" />
<span class="unread" v-show="total > 0">{{ total }}</span>
</div>
</div> -->
<j-badge :count="total" :offset="[3, -3]">
<AIcon type="BellOutlined" style="font-size: 16px" />
</j-badge>
<template #overlay>
<div>
<NoticeInfo :data="list" @on-action="handleRead" />
@ -26,6 +29,9 @@ import { notification, Button } from 'ant-design-vue';
import { changeStatus_api } from '@/api/account/notificationRecord';
import { useUserInfo } from '@/store/userInfo';
import { useMenuStore } from '@/store/menu';
const { jumpPage } = useMenuStore();
const updateCount = computed(() => useUserInfo().$state.alarmUpdateCount);
const total = ref(0);
@ -44,29 +50,37 @@ const subscribeNotice = () => {
class="ellipsis"
style={{ cursor: 'pointer' }}
onClick={() => {
changeStatus_api('_read', [resp.id]);
{
/* changeStatus_api('_read', [resp.id]); */
}
read('', resp);
}}
>
{resp?.payload?.message}
</div>
),
onClick: () => {
changeStatus_api('_read', [resp.id]);
// changeStatus_api('_read', [resp.id])
read('', resp);
},
key: resp.payload.id,
btn: (
<Button
type="primary"
size="small"
onClick={() => {
changeStatus_api('_read', [resp.id]).then(
onClick={(e) => {
{
/* changeStatus_api('_read', [resp.id]).then(
(resp: any) => {
if (resp.status === 200) {
notification.close(resp.payload.id);
getList();
}
},
);
); */
}
e.stopPropagation();
read('_read', resp);
}}
>
标记已读
@ -75,6 +89,21 @@ const subscribeNotice = () => {
});
});
};
const read = (type: string, data: any) => {
changeStatus_api('_read', [data.payload.id]).then((resp: any) => {
if (resp.status !== 200) return;
notification.close(data.payload.id);
getList();
if (type !== '_read') {
jumpPage('account/NotificationRecord', {
row: data.payload.detail,
});
}
});
};
const getList = () => {
loading.value = true;
const params = {

View File

@ -7,10 +7,10 @@
:headers="{
'X-Access-Token': LocalStore.get(TOKEN_KEY),
}"
accept=".xlsx,.csv"
:maxCount="1"
:showUploadList="false"
@change="uploadChange"
:accept="props?.file?.fileType ? `.${props?.file?.fileType}` : '.xlsx'"
>
<j-button>
<template #icon><AIcon type="UploadOutlined" /></template>

View File

@ -90,8 +90,8 @@ const props: JUploadProps = defineProps({
default: '',
},
accept:{
type:Array,
default:()=>[],
type: String,
default: undefined
}
});

View File

@ -1,5 +1,5 @@
<template>
<page-container :tabList="list" @tabChange="onTabChange">
<page-container :tabList="list" :tabActiveKey="activeKey" @tabChange="onTabChange">
<AccessLog v-if="activeKey === '1'" />
<SystemLog v-else />
</page-container>
@ -8,7 +8,9 @@
import { defineComponent, ref } from 'vue';
import AccessLog from './Access/index.vue';
import SystemLog from './System/index.vue';
import {useRouterParams} from "@/utils/hooks/useParams";
const routerParams = useRouterParams()
const activeKey = ref('1');
const list = [
@ -25,4 +27,10 @@ const list = [
const onTabChange = (e: string) => {
activeKey.value = e;
};
onMounted(() => {
if (routerParams.params.value.tab === 'system') {
activeKey.value = '2';
}
});
</script>

View File

@ -166,6 +166,7 @@ const columns = [
dataIndex: 'registerTime',
search: {
type: 'date',
rename: 'registryTime'
},
width: 200,
scopedSlots: true,
@ -290,7 +291,19 @@ watch(
* @param params
*/
const handleSearch = (e: any) => {
params.value = e;
const newParams = (e?.terms as any[])?.map(item1 => {
item1.terms = item1.terms.map((item2: any) => {
if (item2.column === 'version') {
return {
column: 'id$dev-firmware',
value: [item2]
}
}
return item2
})
return item1
})
params.value = { terms: newParams || []}
};
</script>

View File

@ -13,7 +13,7 @@
<j-row type="flex">
<j-col flex="180px">
<j-form-item name="photoUrl">
<JProUpload accept="image/*" v-model="modelRef.photoUrl" />
<JProUpload accept="image/jpg,image/png,image/jfif,image/pjp,image/pjpeg,image/jpeg" v-model="modelRef.photoUrl" />
</j-form-item>
</j-col>
<j-col flex="auto">

View File

@ -565,6 +565,9 @@ onMounted(() => {
if (routerParams.params.value.type === 'add') {
handleAdd();
}
if (routerParams.params.value.type === 'import') {
importVisible.value = true;
}
});
const handleParams = (config: Record<string, any>) => {

View File

@ -1019,6 +1019,9 @@ watchEffect(() => {
nextTick(() => {
getData();
});
watch(()=>productStore.current,()=>{
getData()
})
</script>
<style lang="less" scoped>
:deep(

View File

@ -77,7 +77,7 @@
type="primary"
:popConfirm="{
title: `确定应用配置?`,
onConfirm: handleConfig,
onConfirm: handleDeploy,
}"
:disabled="productStore.current?.state === 0"
:tooltip="

View File

@ -68,7 +68,11 @@
:tree-data="treeList"
@change="valueChange"
allow-clear
:fieldNames="{ label: 'name', value: 'id' }"
:fieldNames="{
label: 'name',
value: 'id',
children: 'children',
}"
:filterTreeNode="
(v, option) => filterSelectNode(v, option)
"
@ -120,11 +124,7 @@ import { FILE_UPLOAD } from '@/api/comm';
import { isInput } from '@/utils/regular';
import type { Rule } from 'ant-design-vue/es/form';
import { queryProductId, addProduct, editProduct } from '@/api/device/product';
import {
SearchOutlined,
CheckOutlined,
DeleteOutlined,
} from '@ant-design/icons-vue';
import encodeQuery from '@/utils/encodeQuery';
const productStore = useProductStore();
const emit = defineEmits(['success']);
const props = defineProps({
@ -246,14 +246,25 @@ const valueChange = (value: string, label: string) => {
* 查询产品分类
*/
const queryProductTree = async () => {
category({
paging: false,
}).then((resp) => {
category(encodeQuery({ sorts: { sortIndex: 'asc' } })).then((resp) => {
if (resp.status === 200) {
treeList.value = resp.result;
treeList.value = dealProductTree(treeList.value);
}
});
};
/**
* 处理产品分类key
*/
const dealProductTree = (arr: any) => {
return arr.map((element: any) => {
element.key = element.id;
if (element.children) {
element.children = dealProductTree(element.children);
}
return element
});
};
watch(
() => props.isAdd,
() => {
@ -326,7 +337,7 @@ const submitData = () => {
//
form.classifiedId
? form.classifiedId
: (form.classifiedId = ''); //
: (form.classifiedId = ''); //
form.classifiedName
? form.classifiedName
: (form.classifiedName = '');

View File

@ -13,7 +13,7 @@
<j-row type="flex">
<j-col flex="180px">
<j-form-item name="photoUrl">
<JProUpload accept="image/*" v-model="modelRef.photoUrl" />
<JProUpload accept="image/jpg,image/png,image/jfif,image/pjp,image/pjpeg,image/jpeg" v-model="modelRef.photoUrl" />
</j-form-item>
</j-col>
<j-col flex="auto">

View File

@ -6,7 +6,7 @@
@ok="onSave"
@cancel="onCancel"
>
<div class="alert">
<div class="resource-issue-alert">
<AIcon
type="InfoCircleOutlined"
style="margin-right: 10px"
@ -17,7 +17,7 @@
target="edge-resource-issue"
@search="handleSearch"
type="simple"
class="search"
class="resource-issue-search"
/>
<JProTable
ref="edgeResourceIssueRef"
@ -31,6 +31,10 @@
selectedRowKeys: _selectedRowKeys,
onChange: onSelectChange,
}"
:pagination="{
showSizeChanger: true,
pageSizeOptions: ['10', '20', '50', '100'],
}"
>
<template #state="slotProps">
<j-badge
@ -47,7 +51,12 @@
}}</span>
</template>
</JProTable>
<Result v-if="visible" :data="props.data" :list="_data" @close="onCancel" />
<Result
v-if="visible"
:data="props.data"
:list="_data"
@close="onCancel"
/>
</j-modal>
</template>
@ -56,9 +65,11 @@ import { onlyMessage } from '@/utils/comm';
import { queryDeviceList } from '@/api/edge/resource';
import dayjs from 'dayjs';
import Result from './Result.vue';
import { queryNoPagingPost } from '@/api/device/product';
const defaultParams = {
sorts: [{ name: 'createTime', order: 'desc' }],
pageSize: 10,
sorts: [{ name: 'registerTime', order: 'desc' }],
terms: [
{
terms: [
@ -111,6 +122,18 @@ const columns = [
ellipsis: true,
search: {
type: 'select',
rename: 'productId',
options: () =>
new Promise((resolve) => {
queryNoPagingPost({ paging: false }).then((resp: any) => {
resolve(
resp.result.map((item: any) => ({
label: item.name,
value: item.id,
})),
);
});
}),
},
},
{
@ -155,10 +178,10 @@ const handleSearch = (v: any) => {
};
const onSave = () => {
if(_data.value.length){
visible.value = true
if (_data.value.length) {
visible.value = true;
} else {
onlyMessage('请选择设备', 'error')
onlyMessage('请选择设备', 'error');
}
};
@ -167,12 +190,12 @@ const onCancel = () => {
};
</script>
<style lang="less" scoped>
.search {
padding: 0px;
<style lang="less">
.resource-issue-search {
padding: 18px 0 0 0;
margin: 0px;
}
.alert {
.resource-issue-alert {
height: 40px;
padding-left: 10px;
color: rgba(0, 0, 0, 0.55);

View File

@ -15,6 +15,7 @@
<template #card="slotProps">
<CardBox
:value="slotProps"
@click="handleView(slotProps)"
:actions="getActions(slotProps, 'card')"
:status="slotProps.state?.value"
:statusText="slotProps.state?.text"
@ -30,10 +31,7 @@
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)">
<span
style="font-size: 16px; font-weight: 600"
@click.stop="handleView(slotProps.id)"
>
<span style="font-size: 16px; font-weight: 600">
{{ slotProps.name }}
</span>
</Ellipsis>
@ -120,7 +118,11 @@
type="link"
style="padding: 0 5px"
:danger="i.key === 'delete'"
:hasPermission="i.key === 'view' ? true : 'edge/Resource:' + i.key"
:hasPermission="
i.key === 'view'
? true
: 'edge/Resource:' + i.key
"
>
<template #icon><AIcon :type="i.icon" /></template>
</PermissionButton>
@ -213,17 +215,6 @@ const columns = [
new Promise((resolve) => {
queryNoPagingPost({
paging: false,
terms: [
{
terms: [
{
column: 'productId$product-info',
value: 'accessProvider is official-edge-gateway',
},
],
type: 'and',
},
],
sorts: [
{
name: 'createTime',
@ -278,6 +269,17 @@ const getActions = (
): ActionsType[] => {
if (!data) return [];
const actions = [
{
key: 'view',
text: '查看',
tooltip: {
title: '查看',
},
icon: 'EyeOutlined',
onClick: () => {
handleView(data);
},
},
{
key: 'update',
text: '编辑',
@ -370,8 +372,8 @@ const handleSearch = (_params: any) => {
params.value = _params;
};
const handleView = (id: string) => {
menuStory.jumpPage('device/Instance/Detail', { id });
const handleView = (dt: any) => {
menuStory.jumpPage('device/Instance/Detail', { id: dt?.sourceId });
};
const saveBtn = () => {
@ -384,6 +386,7 @@ const onRefresh = () => {
edgeResourceRef.value?.reload();
};
</script>
<style lang="less" scoped>
</style>
<style lang="less" scoped>
</style>

View File

@ -193,31 +193,31 @@ const opsStepDetails: recommendList[] = [
title: '协议管理',
details:
'根据业务需求自定义开发对应的产品(设备模型)接入协议,并上传到平台。',
iconUrl: '/images/home/bottom-1.png',
iconUrl: '/images/home/Frame 4528.png',
linkUrl: 'link/Protocol',
},
{
title: '证书管理',
details: '统一维护平台内的证书,用于数据通信加密。',
iconUrl: '/images/home/bottom-6.png',
iconUrl: '/images/home/Frame 4528.png',
linkUrl: 'link/Certificate',
},
{
title: '网络组件',
details: '根据不同的传输类型配置平台底层网络组件相关参数。',
iconUrl: '/images/home/bottom-3.png',
iconUrl: '/images/home/Frame 4529.png',
linkUrl: 'link/Type',
},
{
title: '设备接入网关',
details: '根据不同的传输类型,关联消息协议,配置设备接入网关相关参数。',
iconUrl: '/images/home/bottom-4.png',
iconUrl: '/images/home/Frame 4528(1).png',
linkUrl: 'link/AccessConfig',
},
{
title: '日志管理',
details: '监控系统日志,及时处理系统异常。',
iconUrl: '/images/home/bottom-5.png',
iconUrl: '/images/home/Frame 4528.png',
linkUrl: 'Log',
params: {
tab: 'system',

View File

@ -53,31 +53,31 @@ const opsStepDetails: recommendList[] = [
title: '协议管理',
details:
'根据业务需求自定义开发对应的产品(设备模型)接入协议,并上传到平台。',
iconUrl: '/images/home/bottom-1.png',
iconUrl: '/images/home/Frame 4528.png',
linkUrl: 'link/Protocol',
},
{
title: '证书管理',
details: '统一维护平台内的证书,用于数据通信加密。',
iconUrl: '/images/home/bottom-6.png',
iconUrl: '/images/home/Frame 4528.png',
linkUrl: 'link/Certificate',
},
{
title: '网络组件',
details: '根据不同的传输类型配置平台底层网络组件相关参数。',
iconUrl: '/images/home/bottom-3.png',
iconUrl: '/images/home/Frame 4529.png',
linkUrl: 'link/Type',
},
{
title: '设备接入网关',
details: '根据不同的传输类型,关联消息协议,配置设备接入网关相关参数。',
iconUrl: '/images/home/bottom-4.png',
iconUrl: '/images/home/Frame 4528(1).png',
linkUrl: 'link/AccessConfig',
},
{
title: '日志管理',
details: '监控系统日志,及时处理系统异常。',
iconUrl: '/images/home/bottom-5.png',
iconUrl: '/images/home/Frame 4528.png',
linkUrl: 'Log',
params: {
tab: 'system',

View File

@ -139,7 +139,7 @@ const deviceStepDetails: recommendList[] = [
linkUrl: 'device/Instance',
auth: devicePermission('import'),
params: {
import: true,
type: 'import',
},
},
];

View File

@ -35,14 +35,14 @@ export default {
createTime: 1679906031144,
granted: true,
icon: "icon-keshihua",
id:"68a02c9efa9fb4885c89b007f97d074d",
level:3,
name:"仪表盘",
id: "68a02c9efa9fb4885c89b007f97d074d",
level: 3,
name: "仪表盘",
owner: "iot",
parentId :"b6327c3ff01b49c9a7a96101606dc27a",
path:"WXaI-KCgA-gBU0",
sortIndex:1,
url:"/iot/device/DashBoard",
parentId: "b6327c3ff01b49c9a7a96101606dc27a",
path: "WXaI-KCgA-gBU0",
sortIndex: 1,
url: "/iot/device/DashBoard",
},
{
id: '1-3-2',
@ -201,6 +201,21 @@ export default {
},
],
[ROLEKEYS.link]: [
{
assetAccesses: [],
code: "link/DashBoard",
createTime: 1679994088091,
granted: true,
icon: "icon-keshihua",
id: "47bedff9df89ecc0f0ce896e53805f02",
level: 3,
name: "仪表盘",
owner: "iot",
parentId: "bd55cdc9d0c1700afe628f572f91c22e",
path: "rmJT-eI2B-2yTR",
sortIndex: 1,
url: "/iot/link/dashboard",
},
{
id: '1-4-2',
parentId: '1-4',
@ -258,6 +273,20 @@ export default {
options: {},
createTime: 1659344075524,
granted: true,
}, {
assetAccesses: [],
code: "Log",
createTime: 1679994088091,
granted: true,
icon: "icon-rizhifuwu",
id: "c340f8977e0d221da893715cab58ae8c",
level: 3,
name: "日志管理",
owner: "iot",
parentId: "bd55cdc9d0c1700afe628f572f91c22e",
path: "rmJT-eI2B-xH5Y",
sortIndex: 1,
url: "/iot/link/Log",
},
{
id: '1-4-5',
@ -446,6 +475,21 @@ export default {
},
],
[ROLEKEYS.complex]: [
{
assetAccesses: [],
code: "device/DashBoard",
createTime: 1679906031144,
granted: true,
icon: "icon-keshihua",
id: "68a02c9efa9fb4885c89b007f97d074d",
level: 3,
name: "仪表盘",
owner: "iot",
parentId: "b6327c3ff01b49c9a7a96101606dc27a",
path: "WXaI-KCgA-gBU0",
sortIndex: 1,
url: "/iot/device/DashBoard",
},
{
id: '1-3-2',
parentId: '1-3',
@ -601,6 +645,21 @@ export default {
createTime: 1659344075524,
granted: true,
},
{
assetAccesses: [],
code: "link/DashBoard",
createTime: 1679994088091,
granted: true,
icon: "icon-keshihua",
id: "47bedff9df89ecc0f0ce896e53805f02",
level: 3,
name: "仪表盘",
owner: "iot",
parentId: "bd55cdc9d0c1700afe628f572f91c22e",
path: "rmJT-eI2B-2yTR",
sortIndex: 1,
url: "/iot/link/dashboard",
},
{
id: '1-4-2',
parentId: '1-4',
@ -659,6 +718,21 @@ export default {
createTime: 1659344075524,
granted: true,
},
{
assetAccesses: [],
code: "Log",
createTime: 1679994088091,
granted: true,
icon: "icon-rizhifuwu",
id: "c340f8977e0d221da893715cab58ae8c",
level: 3,
name: "日志管理",
owner: "iot",
parentId: "bd55cdc9d0c1700afe628f572f91c22e",
path: "rmJT-eI2B-xH5Y",
sortIndex: 1,
url: "/iot/link/Log",
},
{
id: '1-4-5',
parentId: '1-4',

View File

@ -185,7 +185,8 @@ export default [
},
],
accessSupport: { text: "支持", value: "support" },
supportDataAccess: true
supportDataAccess: true,
assetType: 'notifyConfig'
},
{
code: 'notice/Template',
@ -306,6 +307,7 @@ export default [
},
],
accessSupport: { text: "支持", value: "support" },
assetType: 'notifyTemplate',
supportDataAccess: true
},
],
@ -969,8 +971,9 @@ export default [
],
},
],
accessSupport: { text: "不支持", value: "unsupported" },
supportDataAccess: false
accessSupport: { text: "支持", value: "support" },
supportDataAccess: true,
assetType: 'deviceGateway'
},
{
code: 'link/Protocol',
@ -1041,8 +1044,9 @@ export default [
],
},
],
accessSupport: { text: "不支持", value: "unsupported" },
supportDataAccess: false
accessSupport: { text: "支持", value: "support" },
supportDataAccess: true,
assetType: 'protocol'
},
{
code: 'Log',
@ -1143,8 +1147,9 @@ export default [
],
},
],
accessSupport: { text: "不支持", value: "unsupported" },
supportDataAccess: false
accessSupport: { text: "支持", value: "support" },
supportDataAccess: true,
assetType: 'network'
},
{
code: 'link/Certificate',
@ -1200,7 +1205,8 @@ export default [
},
],
accessSupport: { text: "支持", value: "support" },
supportDataAccess: true
supportDataAccess: true,
assetType: 'certificate'
},
{
code: 'media/Stream',
@ -1546,7 +1552,8 @@ export default [
},
],
accessSupport: { text: "支持", value: "support" },
supportDataAccess: true
supportDataAccess: true,
assetType: 'dataCollectChannel'
},
{
code: 'DataCollect/Collector',
@ -1679,7 +1686,8 @@ export default [
},
],
accessSupport: { text: "支持", value: "support" },
supportDataAccess: true
supportDataAccess: true,
assetType: 'ataCollectCollector'
},
],
},
@ -1850,7 +1858,8 @@ export default [
},
],
accessSupport: { text: "支持", value: "support" },
supportDataAccess: true
supportDataAccess: true,
assetType: 'alarmConfig'
},
{
code: 'rule-engine/Alarm/Log',
@ -1994,8 +2003,9 @@ export default [
],
},
],
accessSupport: { text: "不支持", value: "unsupported" },
supportDataAccess: false
accessSupport: { text: "支持", value: "support" },
supportDataAccess: true,
assetType: 'dueros'
},
{
code: 'Northbound/AliCloud',
@ -2233,7 +2243,8 @@ export default [
},
],
accessSupport: { text: "支持", value: "support" },
supportDataAccess: true
supportDataAccess: true,
assetType: 'ruleInstance'
},
{
code: 'rule-engine/Scene',
@ -2385,7 +2396,8 @@ export default [
},
],
accessSupport: { text: "支持", value: "support" },
supportDataAccess: true
supportDataAccess: true,
assetType: 'scene'
},
],
},
@ -2906,7 +2918,8 @@ export default [
},
],
accessSupport: { text: "支持", value: "support" },
supportDataAccess: true
supportDataAccess: true,
assetType: 'gbCascade'
},
],
},
@ -3051,7 +3064,8 @@ export default [
},
],
accessSupport: { text: "支持", value: "support" },
supportDataAccess: true
supportDataAccess: true,
assetType: 'user'
},
{
code: 'system/Department',
@ -3249,7 +3263,8 @@ export default [
},
],
accessSupport: { text: "支持", value: "support" },
supportDataAccess: true
supportDataAccess: true,
assetType: 'organization'
},
{
code: 'system/Role',
@ -3326,7 +3341,8 @@ export default [
},
],
accessSupport: { text: "支持", value: "support" },
supportDataAccess: true
supportDataAccess: true,
assetType: 'role'
},
{
code: 'system/Menu',
@ -3640,7 +3656,8 @@ export default [
},
],
accessSupport: { text: "支持", value: "support" },
supportDataAccess: true
supportDataAccess: true,
assetType: 'datasource'
},
{
code: 'system/Platforms/Setting',
@ -4042,8 +4059,9 @@ export default [
],
},
],
accessSupport: { text: "不支持", value: "unsupported" },
supportDataAccess: false
accessSupport: { text: "支持", value: "support" },
supportDataAccess: true,
assetType: 'networkCard'
},
{
path: '5Hpl-ZjAG',
@ -4160,8 +4178,9 @@ export default [
],
},
],
accessSupport: { text: "不支持", value: "unsupported" },
supportDataAccess: false
accessSupport: { text: "支持", value: "support" },
supportDataAccess: true,
assetType: 'networkCardPlatform'
},
{
path: '5Hpl-cL34',

View File

@ -1,132 +1,146 @@
<!-- 绑定设备 -->
<template>
<j-modal :maskClosable="false" width="1100px" :visible="true" title="选择设备" okText="确定" cancelText="取消" @ok="handleOk"
@cancel="handleCancel" :confirmLoading="btnLoading">
<div style="margin-top: 10px">
<pro-search :columns="columns" target="iot-card-bind-device" @search="handleSearch" type="simple" />
<j-pro-table ref="bindDeviceRef" :columns="columns" :request="queryUnbounded" model="TABLE" :defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }],
}" :rowSelection="{
type: 'radio',
selectedRowKeys: _selectedRowKeys,
onSelect: onSelectChange,
}" @cancelSelect="cancelSelect" :params="params">
<template #registryTime="slotProps">
{{
slotProps.registryTime
? moment(slotProps.registryTime).format(
'YYYY-MM-DD HH:mm:ss',
)
: ''
}}
</template>
<template #state="slotProps">
<j-badge :text="slotProps.state.text" :status="statusMap.get(slotProps.state.value)" />
</template>
</j-pro-table>
</div>
</j-modal>
<j-modal :maskClosable='false' width='1100px' :visible='true' title='选择设备' okText='确定' cancelText='取消' @ok='handleOk'
@cancel='handleCancel' :confirmLoading='btnLoading'>
<div style='margin-top: 10px'>
<pro-search :columns='columns' target='iot-card-bind-device' @search='handleSearch' type='simple' />
<j-pro-table
ref='bindDeviceRef'
:columns='columns'
:request='queryUnbounded'
model='TABLE'
:defaultParams="{
pageSize: 10,
sorts: [{ name: 'createTime', order: 'desc' }],
}"
:pagination="{
showSizeChanger: true,
pageSizeOptions: ['10', '20', '50', '100'],
}"
:rowSelection="{
type: 'radio',
selectedRowKeys: _selectedRowKeys,
onSelect: onSelectChange,
}"
@cancelSelect='cancelSelect'
:params='params'
>
<template #registryTime='slotProps'>
{{
slotProps.registryTime
? moment(slotProps.registryTime).format(
'YYYY-MM-DD HH:mm:ss'
)
: ''
}}
</template>
<template #state='slotProps'>
<j-badge :text='slotProps.state.text' :status='statusMap.get(slotProps.state.value)' />
</template>
</j-pro-table>
</div>
</j-modal>
</template>
<script setup lang="ts">
import { queryUnbounded, bind } from '@/api/iot-card/cardManagement';
import moment from 'moment';
import { message } from 'jetlinks-ui-components';
<script setup lang='ts'>
import { queryUnbounded, bind } from '@/api/iot-card/cardManagement'
import moment from 'moment'
import { message } from 'jetlinks-ui-components'
const emit = defineEmits(['change']);
const emit = defineEmits(['change'])
const props = defineProps({
cardId: {
type: String,
},
});
cardId: {
type: String
}
})
const bindDeviceRef = ref<Record<string, any>>({});
const params = ref<Record<string, any>>({});
const _selectedRowKeys = ref<string[]>([]);
const btnLoading = ref<boolean>(false);
const bindDeviceRef = ref<Record<string, any>>({})
const params = ref<Record<string, any>>({})
const _selectedRowKeys = ref<string[]>([])
const btnLoading = ref<boolean>(false)
const statusMap = new Map();
statusMap.set('online', 'processing');
statusMap.set('offline', 'error');
statusMap.set('notActive', 'warning');
const statusMap = new Map()
statusMap.set('online', 'processing')
statusMap.set('offline', 'error')
statusMap.set('notActive', 'warning')
const columns = [
{
title: 'ID',
dataIndex: 'id',
key: 'id',
ellipsis: true,
fixed: 'left',
search: {
type: 'string',
},
},
{
title: '设备名称',
dataIndex: 'name',
key: 'name',
ellipsis: true,
search: {
type: 'string',
},
},
{
title: '注册时间',
dataIndex: 'registryTime',
key: 'registryTime',
scopedSlots: true,
search: {
type: 'date',
},
// sorter: true,
},
{
title: '状态',
dataIndex: 'state',
key: 'state',
scopedSlots: true,
search: {
type: 'select',
options: [
{ label: '禁用', value: 'notActive' },
{ label: '离线', value: 'offline' },
{ label: '在线', value: 'online' },
],
},
// filterMultiple: false,
},
];
{
title: 'ID',
dataIndex: 'id',
key: 'id',
ellipsis: true,
fixed: 'left',
search: {
type: 'string'
}
},
{
title: '设备名称',
dataIndex: 'name',
key: 'name',
ellipsis: true,
search: {
type: 'string'
}
},
{
title: '注册时间',
dataIndex: 'registryTime',
key: 'registryTime',
scopedSlots: true,
search: {
type: 'date'
}
// sorter: true,
},
{
title: '状态',
dataIndex: 'state',
key: 'state',
scopedSlots: true,
search: {
type: 'select',
options: [
{ label: '禁用', value: 'notActive' },
{ label: '离线', value: 'offline' },
{ label: '在线', value: 'online' }
]
}
// filterMultiple: false,
}
]
const handleSearch = (e: any) => {
params.value = e;
};
params.value = e
}
const onSelectChange = (record: any) => {
_selectedRowKeys.value = [record.id];
};
_selectedRowKeys.value = [record.id]
}
const cancelSelect = () => {
_selectedRowKeys.value = [];
};
_selectedRowKeys.value = []
}
const handleOk = () => {
btnLoading.value = true;
bind(props.cardId, _selectedRowKeys.value[0])
.then((resp: any) => {
if (resp.status === 200) {
message.success('操作成功')
emit('change', true);
}
})
.finally(() => {
btnLoading.value = false;
});
};
btnLoading.value = true
bind(props.cardId, _selectedRowKeys.value[0])
.then((resp: any) => {
if (resp.status === 200) {
message.success('操作成功')
emit('change', true)
}
})
.finally(() => {
btnLoading.value = false
})
}
const handleCancel = () => {
emit('change', false);
};
emit('change', false)
}
</script>
<style scoped lang="less"></style>
<style scoped lang='less'></style>

View File

@ -57,7 +57,7 @@ const createChart = () => {
nextTick(() => {
const myChart = echarts.init(chartRef.value as HTMLElement);
const sData: number[] = props.chartData.map(
(m: any) => m.value && m.value.toFixed(2),
(m: any) => m.value && m.value.toFixed(0),
);
const maxY = Math.max.apply(null, sData.length ? sData : [0]);
const options = {
@ -80,25 +80,53 @@ const createChart = () => {
// minInterval: 1,
},
series: [
// {
// name: '()',
// data: sData,
// type: 'bar',
// barWidth: 16,
// itemStyle: {
// color: '#2f54eb',
// },
// },
// {
// name: '()',
// type: 'line',
// symbol: 'circle',
// showSymbol: false,
// smooth: true,
// lineStyle: {
// color: '#a5fff9',
// },
// data: sData,
// },
{
name: '播放数量(人次)',
data: sData,
type: 'bar',
barWidth: 16,
itemStyle: {
color: '#2f54eb',
},
},
{
name: '播放数量(人次)',
type: 'line',
symbol: 'circle',
showSymbol: false,
smooth: true,
lineStyle: {
color: '#a5fff9',
symbolSize: 0, //
color: '#ADC6FF',
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: '#ADC6FF', // 100%
},
{
offset: 1,
color: '#FFFFFF', // 0%
},
],
global: false, // false
},
},
data: sData,
},
],
};

View File

@ -135,7 +135,7 @@ const aggPlayingFooter = ref<Footer[]>([]);
const aggPlayingTotal = ref(0);
const getAggPlayingData = () => {
dashboardApi.aggPlaying().then((res) => {
aggTotal.value = res.result.playingTotal;
aggPlayingTotal.value = res.result.playingTotal;
aggPlayingFooter.value = [
{
title: '播放人数',

View File

@ -28,7 +28,7 @@
<div class="tool-item">
<j-popconfirm
title="重置将断开直播, 可能会影响其他播放者"
@confirm="() => handleReset"
@confirm="handleReset"
>
重置
</j-popconfirm>

View File

@ -22,7 +22,7 @@
<PermissionButton
type="primary"
@click="add"
hasPermission="device/Instance:add"
hasPermission="rule-engine/Alarm/Configuration:add"
>
<template #icon
><AIcon type="PlusOutlined"
@ -82,7 +82,7 @@
<PermissionButton
:disabled="item.disabled"
:popConfirm="item.popConfirm"
:tooltip="{ ...item.tootip }"
:tooltip="{ ...item.tooltip }"
@click="item.onClick"
:hasPermission="
'rule-engine/Alarm/Configuration:' +

View File

@ -287,7 +287,7 @@ const orgCol = [
},
];
let params:any = ref({
let params: any = ref({
sorts: [{ name: 'alarmTime', order: 'desc' }],
terms: [],
});
@ -369,7 +369,10 @@ const getActions = (
key: 'solve',
text: '告警处理',
tooltip: {
title: '告警处理',
title:
currentData.state?.value === 'normal'
? '无告警'
: '告警处理',
},
icon: 'ToolOutlined',
onClick: () => {
@ -432,14 +435,14 @@ const closeLog = () => {
};
</script>
<style lang="less" scoped>
.content-left{
border-right: .2px solid rgba(0,0,0,0.2);
.content-left {
border-right: 0.2px solid rgba(0, 0, 0, 0.2);
}
.content-right-title{
.content-right-title {
color: #666;
font-size: 12px
font-size: 12px;
}
.content-left-title{
font-size: 18px
.content-left-title {
font-size: 18px;
}
</style>

View File

@ -42,7 +42,6 @@
<TimeSelect
key="flow-static"
:type="'week'"
@change="initQueryTime"
/>
</template>
@ -483,7 +482,11 @@ const selectChange = () => {
],
};
state.ranking = res.result
?.filter((item: any) => item.group === 'alarmRank')
?.filter(
(item: any) =>
item.group === 'alarmRank' &&
item.data?.value?.count !== 0,
)
.map((d: { data: { value: any } }) => d.data?.value)
.sort(
(a: { count: number }, b: { count: number }) =>

View File

@ -242,10 +242,30 @@ const handleOptionsColumnsValue = (termsColumns: any[], _options: any) => {
}
const columnSelect = (e: any) => {
paramsValue.termType = 'eq'
paramsValue.value = {
source: tabsOptions.value[0].key,
value: undefined
const dataType = e.type
const hasTypeChange = dataType !== tabsOptions.value[0].component
let termTypeChange = false
//
const termTypes = e.termTypes
if (!termTypes.some((item: {id: string}) => paramsValue.termType === item.id)) { //
termTypeChange = true
paramsValue.termType = termTypes?.length ? termTypes[0].id : 'eq'
}
if (hasTypeChange) {
paramsValue.termType = termTypes?.length ? termTypes[0].id : 'eq'
paramsValue.value = {
source: tabsOptions.value[0].key,
value: undefined
}
} else if (termTypeChange) {
const oldValue = isArray(paramsValue.value!.value) ? paramsValue.value!.value[0] : paramsValue.value!.value
const value = arrayParamsKey.includes(e.key) ? [ oldValue, undefined ] : oldValue
paramsValue.value = {
source: paramsValue.value?.source || tabsOptions.value[0].key,
value: value
}
}
const columns = e.metadata === true ? [e.column] : []
@ -266,7 +286,7 @@ const termsTypeSelect = (e: { key: string, name: string }) => {
const oldValue = isArray(paramsValue.value!.value) ? paramsValue.value!.value[0] : paramsValue.value!.value
const value = arrayParamsKey.includes(e.key) ? [ oldValue, undefined ] : oldValue
paramsValue.value = {
source: tabsOptions.value[0].key,
source: paramsValue.value?.source || tabsOptions.value[0].key,
value: value
}
emit('update:value', { ...paramsValue })

View File

@ -84,7 +84,7 @@ const props = defineProps({
},
});
const emit = defineEmits(['update:value', 'change']);
const emit = defineEmits(['update:value', 'change', 'update:detail']);
const getLogo = (type: string, provider: string) => {
return MSG_TYPE[type].find((f: any) => f.value === provider)?.logo;
@ -133,10 +133,12 @@ const handleClick = (dt: any) => {
_selectedRowKeys.value = [];
emit('update:value', undefined);
emit('change', { templateName: undefined });
emit('update:detail', undefined);
} else {
_selectedRowKeys.value = [dt.id];
emit('update:value', dt.id);
emit('change', { templateName: dt?.name });
emit('update:detail', dt);
}
};

View File

@ -75,6 +75,10 @@ const props = defineProps({
type: Object,
default: () => {},
},
template: {
type: Object,
default: () => {},
},
});
const emit = defineEmits(['update:value', 'change']);
@ -87,6 +91,12 @@ watchEffect(() => {
Object.assign(modelRef, props?.value);
});
watchEffect(() => {
if(props?.template?.template?.sendTo && props?.template?.template?.sendTo?.length){
emit('change', { sendTo: props?.template?.template?.sendTo.join(' ') });
}
});
const getType = (item: any) => {
return item.expands?.businessType || item.type;
};
@ -180,16 +190,16 @@ const onChange = (val: any, type: any) => {
emit('change', { tagName: val });
} else if (type === 'user') {
emit('change', { sendTo: val });
} else if (type === 'build-in') {
// emit('change', { sendTo: val });
}
};
const onSave = () =>
new Promise((resolve) => {
formRef.value?.validate().then(async (_data: any) => {
new Promise((resolve, reject) => {
formRef.value?.validate().then((_data: any) => {
resolve(_data);
});
}).catch(() => {
reject(false)
})
});
defineExpose({ onSave });

View File

@ -47,6 +47,7 @@
<j-form-item name="templateId">
<NotifyTemplate
v-model:value="formModel.templateId"
v-model:detail="template"
:notifierId="formModel.notifierId"
@change="(val) => onValChange(val, 'templateId')"
/>
@ -58,6 +59,7 @@
:variableDefinitions="variable"
:value="formModel.variables"
:notify="formModel"
:template="template"
@change="(val) => onValChange(val, 'variables')"
ref="variableRef"
/>
@ -119,11 +121,19 @@ const formModel = reactive({
const variable = ref([]);
const variableRef = ref();
const template = ref();
watch(
() => props.value,
(newVal) => {
Object.assign(formModel, newVal);
if(newVal?.templateId){
Template.detail(newVal?.templateId).then((resp: any) => {
if(resp.status === 200){
template.value = resp.result
}
})
}
},
{ deep: true, immediate: true },
);
@ -193,8 +203,11 @@ const onCancel = () => {
emit('cancel');
};
const onOk = async () => {
const _data = await variableRef.value.onSave();
formModel.variables = _data;
let _data = undefined
if(variable.value.length){
_data = await variableRef.value.onSave()
}
formModel.variables = _data || [];
const { options, ...extra } = formModel;
emit('save', { ...extra }, { ...options });
};

View File

@ -48,7 +48,7 @@ const label: Record<number, any> = {
const emit = defineEmits<Emit>()
const myValue = ref<ValueType>(props.value)
const myValue = ref<ValueType>(props.value || [undefined, undefined] as any)
const mySource = ref<string>(props.source)
const onSelect = (v: any, _label: string, index: number) => {

View File

@ -100,7 +100,7 @@ type Emit = {
}
const props = defineProps({
...defaultSetting
...defaultSetting,
})
const emit = defineEmits<Emit>()

View File

@ -14,7 +14,7 @@ export type TabsOption = {
key: string;
component: string
}
type ValueArrayType = [string, number]
type ValueArrayType = [string, number, undefined]
export type ValueType = string | number | undefined | ValueArrayType
export const defaultSetting = {

View File

@ -133,7 +133,7 @@ const props = defineProps({
type: '',
termType: 'eq',
value: {
source: 'fixed',
source: 'manual',
value: undefined
}
})
@ -216,12 +216,20 @@ watch(() => [columnOptions.value, paramsValue.column], () => {
const showDouble = computed(() => {
const isRange = paramsValue.termType ? arrayParamsKey.includes(paramsValue.termType) : false
const isSourceMetric = paramsValue.value?.source === 'metric'
if (metricsCacheOption.value.length) {
metricOption.value = metricsCacheOption.value.filter(item => isRange ? item.range : !item.range)
} else {
metricOption.value = []
}
return isRange && !isMetric.value
if (isRange) {
if (isMetric.value) {
return !isSourceMetric
}
return true
}
return false
})
const mouseover = () => {
@ -237,11 +245,29 @@ const mouseout = () => {
}
const columnSelect = (option: any) => {
const dataType = option.dataType
const hasTypeChange = dataType !== tabsOptions.value[0].component
let termTypeChange = false
//
const termTypes = option.termTypes
paramsValue.termType = termTypes?.length ? termTypes[0].id : 'eq'
paramsValue.value = {
source: tabsOptions.value[0].key,
value: undefined
if (!termTypes.some((item: {id: string}) => paramsValue.termType === item.id)) { //
termTypeChange = true
paramsValue.termType = termTypes?.length ? termTypes[0].id : 'eq'
}
if (hasTypeChange) { //
paramsValue.termType = termTypes?.length ? termTypes[0].id : 'eq'
paramsValue.value = {
source: tabsOptions.value[0].key,
value: undefined
}
} else if (termTypeChange) {
const oldValue = isArray(paramsValue.value!.value) ? paramsValue.value!.value[0] : paramsValue.value!.value
const value = arrayParamsKey.includes(paramsValue.termType as string) ? [ oldValue, undefined ] : oldValue
paramsValue.value = {
source: paramsValue.value?.source || tabsOptions.value[0].key,
value: value
}
}
handOptionByColumn(option)
emit('update:value', { ...paramsValue })
@ -254,7 +280,7 @@ const termsTypeSelect = (e: { key: string, name: string }) => {
const oldValue = isArray(paramsValue.value!.value) ? paramsValue.value!.value[0] : paramsValue.value!.value
const value = arrayParamsKey.includes(e.key) ? [ oldValue, undefined ] : oldValue
paramsValue.value = {
source: tabsOptions.value[0].key,
source: paramsValue.value?.source || tabsOptions.value[0].key,
value: value
}
emit('update:value', { ...paramsValue })
@ -263,7 +289,7 @@ const termsTypeSelect = (e: { key: string, name: string }) => {
}
const valueSelect = (_: any, label: string, labelObj: Record<number, any>) => {
const valueSelect = (v: any, label: string, labelObj: Record<number, any>) => {
emit('update:value', { ...paramsValue })
formItemContext.onFieldChange()
formModel.value.options!.when[props.branchName].terms[props.whenName].terms[props.name][2] = labelObj
@ -278,7 +304,7 @@ const termAdd = () => {
const terms = {
column: undefined,
value: {
source: 'fixed',
source: 'manual',
value: undefined
},
termType: undefined,

View File

@ -97,7 +97,7 @@ const addWhen = () => {
{
column: undefined,
value: {
source: 'fixed',
source: 'manual',
value: undefined
},
termType: undefined,

View File

@ -65,7 +65,7 @@
<div>
<j-image
:preview="false"
:src="getImage('/apply/provider3.png')"
:src="getImage('/apply/provider4.png')"
/>
<p>微信网站应用</p>
</div>
@ -74,7 +74,7 @@
<div>
<j-image
:preview="false"
:src="getImage('/apply/provider4.png')"
:src="getImage('/apply/provider3.png')"
/>
<p>钉钉企业内部应用</p>
</div>

View File

@ -5,7 +5,7 @@
<LeftTree @change="(id) => (departmentId = id)" />
</div>
<div class="right">
<j-tabs v-model:activeKey="activeKey">
<j-tabs v-model:activeKey="activeKey" destroyInactiveTabPane>
<j-tab-pane key="product" tab="产品">
<Product
:parentId="departmentId"

View File

@ -27,9 +27,19 @@
}"
>
<template #headerTitle>
<j-button type="primary" @click="dialogVisible = true">
<AIcon type="PlusOutlined" />新增
</j-button>
<j-space>
<j-button type="primary" @click="dialogVisible = true">
<AIcon type="PlusOutlined" />新增
</j-button>
<PermissionButton
:popConfirm="{
title: `是否批量解除绑定`,
onConfirm: () => table.unbind(),
}"
>
<AIcon type="DisconnectOutlined" />批量解绑
</PermissionButton>
</j-space>
</template>
<template #status="slotProps">
@ -159,8 +169,13 @@ const table = {
return getUserByRole_api(params);
},
//
unbind: (ids: string[] = []) => {
unbindUser_api(roleId, ids).then((resp) => {
unbind: (ids?: string[]) => {
const data = ids ? ids : selectedRowKeys.value;
if (!data.length) {
message.warning('请勾选数据');
return;
}
unbindUser_api(roleId, data).then((resp) => {
if (resp.status === 200) {
message.success('操作成功');
table.refresh();
@ -170,6 +185,7 @@ const table = {
//
refresh: () => {
tableRef.value.reload();
selectedRowKeys.value = [];
},
};

View File

@ -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#531a7cd5cc4069dc299f0efcc92411a4eee369e7"
integrity sha512-7VHsz5lVG9PlFkHoJvEown4QARuVuasR+jDa9NNQ+pJSHAtHAeiIO1bpVTQKfE5WCyhCKPnN8yIerJLLzmQ1fA==
resolved "http://47.108.170.157:9013/jetlinks-ui-components/-/jetlinks-ui-components-1.0.5.tgz#031a300df4df31a353d738cacee8b4ff630ae2d0"
integrity sha512-SfucQ7LzlE13VdyZsDhrhzwF9Le/NOke5F6UY3bNN1OJiRD/bZMJecGQxWBQGv567lKcV60SOPCMT8ExiZxUgw==
dependencies:
"@vueuse/core" "^9.12.0"
ant-design-vue "^3.2.15"