Merge remote-tracking branch 'origin/dev' into dev

# Conflicts:
#	yarn.lock
This commit is contained in:
XieYongHong 2023-07-10 20:08:09 +08:00
commit ce20383f7d
27 changed files with 402 additions and 131 deletions

View File

@ -2,7 +2,7 @@
<div class="card j-table-card-box">
<div
class="card-warp"
:class="{ active: active ? 'active' : '' }"
:class="{ active: active ? 'active' : '', 'disabled': disabled }"
@click="handleClick"
>
<div class="card-type" v-if="slots.type">
@ -140,6 +140,10 @@ const props = defineProps({
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
}
});
const getBackgroundColor = (code: string | number) => {
@ -160,6 +164,7 @@ const handleClick = () => {
.card {
width: 100%;
background-color: #fff;
.checked-icon {
position: absolute;
right: -22px;
@ -190,16 +195,20 @@ const handleClick = () => {
position: relative;
border: 1px solid #e6e6e6;
overflow: hidden;
cursor: pointer;
&:hover {
cursor: pointer;
box-shadow: 0 0 24px rgba(#000, 0.1);
.card-mask {
visibility: visible;
}
}
&.disabled {
filter: grayscale(100%);
cursor: not-allowed;
}
&.active {
position: relative;
border: 1px solid #2f54eb;

View File

@ -44,6 +44,7 @@
<j-form-item
label="地址"
:name="['pointKey']"
validateFirst
:rules="[
...ModBusRules.pointKey,
{

View File

@ -16,7 +16,6 @@
selectedRowKeys: _selectedRowKeys,
onChange: onSelectChange,
}"
@cancelSelect="cancelSelect"
>
<template #headerTitle>
<j-space>

View File

@ -3,7 +3,7 @@
<div style="padding: 0 10px">
<div class="alert">
<AIcon type="InfoCircleOutlined" />
你可以在该页面选择需要订阅的主题及接收通知的方式
注意接收人需要有告警配置页面的查询权限才能收到告警类通知
</div>
<div class="content-collapse">
<template v-if="dataSource.length">

View File

@ -65,7 +65,6 @@
selectedRowKeys: _selectedRowKeys,
onChange: onSelectChange,
}"
@cancelSelect="cancelSelect"
:params="params"
>
<template #registryTime="slotProps">

View File

@ -32,7 +32,6 @@
selectedRowKeys: _selectedRowKeys,
onChange: onSelectChange,
}"
@cancelSelect="cancelSelect"
:params="params"
:model="'TABLE'"
>

View File

@ -2,10 +2,24 @@
<div class="metadata-map">
<div class="left">
<j-space style="margin-bottom: 24px">
<j-select @change="onSearchChange" show-search allow-clear placeholder="请选择属性名称" style="width: 250px;">
<j-select-option :label="item.name" v-for="item in dataSourceCache" :value="item?.id" :key="item?.id">{{item?.name}}</j-select-option>
<j-select
@change="onSearchChange"
show-search
allow-clear
placeholder="请选择属性名称"
style="width: 250px"
>
<j-select-option
:label="item.name"
v-for="item in dataSourceCache"
:value="item?.id"
:key="item?.id"
>{{ item?.name }}</j-select-option
>
</j-select>
<j-button type="primary" @click="onSearch"><AIcon type="SearchOutlined" /></j-button>
<j-button type="primary" @click="onSearch"
><AIcon type="SearchOutlined"
/></j-button>
</j-space>
<div class="box">
<j-scrollbar height="100%">
@ -151,6 +165,7 @@ const originalData = ref([]);
const _value = ref<any>(undefined);
const searchValue = ref<any>(undefined);
const _delTag = ref<boolean>(false);
const columns = [
{
@ -202,6 +217,7 @@ const getMetadataMapData = () => {
return {
id: item.metadataId,
originalId: item.originalId,
customMapping: item.customMapping,
};
}) || [],
);
@ -218,18 +234,18 @@ const customRow = (record: any) => {
};
const onSearchChange = (_: any, options: any) => {
searchValue.value = options?.label
}
searchValue.value = options?.label;
};
const onSearch = () => {
if (searchValue.value) {
const _item: any = dataSourceCache.value.find((item: any) => {
return searchValue.value === item?.name;
});
if(_item) {
if (_item) {
_value.value = _item?.name;
document.getElementById(_item?.id)?.scrollIntoView(); //
}
}
} else {
_value.value = undefined;
}
@ -251,16 +267,23 @@ const getDefaultMetadata = async () => {
}));
const concatProperties = [...metadataMap];
const arr = concatProperties.map((item) => item.id);
const _arr = concatProperties.map((item) => item.originalId);
_properties.map((item) => {
//
if (!arr.includes(item.id) && !_arr.includes(item.id)) {
concatProperties.push({ id: item.id, originalId: item.id });
}
});
if (!concatProperties.length) {
_delTag.value = true;
const arr = concatProperties.map((item) => item.id);
const _arr = concatProperties.map((item) => item.originalId);
_properties.map((item) => {
//
if (!arr.includes(item.id) && !_arr.includes(item.id)) {
concatProperties.push({
id: item.id,
originalId: item.id,
customMapping: item?.customMapping,
});
}
});
}
dataSource.value =
properties?.map((item: any, index: number) => {
const _m = concatProperties.find((p) => p.id === item.id);
@ -269,6 +292,7 @@ const getDefaultMetadata = async () => {
id: item.id, // id
name: item?.name,
type: item.valueType?.type,
customMapping: _m?.customMapping,
original: _m?.originalId, // id
};
}) || [];
@ -289,19 +313,27 @@ const getMetadata = (): Promise<{ properties: any[] }> => {
});
};
const onChange = async (value: any, id: string) => {
const res = await metadataMapById('device', _id, [
{
metadataType: 'property',
metadataId: value.id,
originalId: id || null,
},
]);
if (res.success) {
const onMapData = async (arr: any[], flag?: boolean) => {
const res = await metadataMapById('device', _id, arr);
if (res.success && flag) {
onlyMessage('操作成功');
}
};
const onChange = async (value: any, id: string) => {
if ((!id && value?.customMapping) || id) {
// /
const arr = [
{
metadataType: 'property',
metadataId: value.id,
originalId: id,
},
];
onMapData(arr, true);
}
};
const onFilter = ({ key }: any) => {
originalData.value = dataSource.value;
const _dataSource = cloneDeep(dataSource.value).sort((a: any, b: any) => {
@ -324,6 +356,20 @@ const onClose = () => {
onMounted(() => {
getDefaultMetadata();
});
onUnmounted(() => {
if (_delTag.value) {
//
const arr = dataSourceCache.value.filter((i: any) => i?.original).map((item: any) => {
return {
metadataType: 'property',
metadataId: item.id,
originalId: item.original,
}
})
onMapData(arr)
}
});
</script>
<style scoped lang='less'>

View File

@ -28,7 +28,6 @@
] : [{ name: 'createTime', order: 'desc' }],
}"
:params="params"
@cancelSelect="cancelSelect"
:gridColumn="2"
:gridColumns="[2]"
>
@ -316,10 +315,10 @@ const handleClick = (data: any) => {
checkData.value = {...data}
}
const cancelSelect = () => {
selectedRowKeys.value = []
checkData.value = {}
}
// const cancelSelect = () => {
// selectedRowKeys.value = []
// checkData.value = {}
// }
/**
* 打开标签新增

View File

@ -151,6 +151,7 @@ const pluginOptions = ref<any[]>([]);
const filterValue = ref<boolean | undefined>(undefined);
const originalData = ref([]);
const searchValue = ref<any>(undefined);
const _delTag = ref<boolean>(false);
// const tableFilter = (value: string, record: any) => {
// return true
@ -203,6 +204,7 @@ const getMetadataMapData = () => {
return {
id: item.metadataId,
pluginId: item.originalId,
customMapping: item?.customMapping,
};
}) || [],
);
@ -250,16 +252,18 @@ const getDefaultMetadata = async () => {
// const concatProperties = [ ...pluginProperties.map(item => ({ id: item.id, pluginId: item.id})), ...metadataMap]
const concatProperties = [...metadataMap];
const arr = concatProperties.map((item) => item.id);
const _arr = concatProperties.map((item) => item.pluginId);
pluginProperties.map((item) => {
//
if (!arr.includes(item.id) && !_arr.includes(item.id)) {
concatProperties.push({ id: item.id, pluginId: item.id });
}
});
if(!concatProperties.length) {
_delTag.value = true
const arr = concatProperties.map((item) => item.id);
const _arr = concatProperties.map((item) => item.pluginId);
pluginProperties.map((item) => {
//
if (!arr.includes(item.id) && !_arr.includes(item.id)) {
concatProperties.push({ id: item.id, pluginId: item.id, customMapping: item?.customMapping, });
}
});
}
dataSource.value =
properties?.map((item: any, index: number) => {
const _m = concatProperties.find((p) => p.id === item.id);
@ -268,6 +272,7 @@ const getDefaultMetadata = async () => {
id: item.id, // id
name: item?.name,
type: item.valueType?.type,
customMapping: _m?.customMapping,
plugin: _m?.pluginId, // id
};
}) || [];
@ -304,19 +309,27 @@ const getPluginMetadata = (): Promise<{ properties: any[] }> => {
});
};
const pluginChange = async (value: any, id: string) => {
const res = await metadataMapById('product', productDetail.value?.id, [
{
metadataType: 'property',
metadataId: value.id,
originalId: id,
},
]);
if (res.success) {
const onMapData = async (arr: any[], flag?: boolean) => {
const res = await metadataMapById('product', productDetail.value?.id, arr);
if (res.success && flag) {
onlyMessage('操作成功');
}
};
const pluginChange = async (value: any, id: string) => {
if ((!id && value?.customMapping) || id) {
// /
const arr = [
{
metadataType: 'property',
metadataId: value.id,
originalId: id,
},
];
onMapData(arr, true)
}
};
const onFilter = ({ key }: any) => {
originalData.value = dataSource.value;
const _dataSource = cloneDeep(dataSource.value).sort((a: any, b: any) => {
@ -339,6 +352,20 @@ const onClose = () => {
onMounted(() => {
getDefaultMetadata();
});
onUnmounted(() => {
if (_delTag.value) {
//
const arr = dataSourceCache.value.filter((i: any) => i?.plugin).map((item: any) => {
return {
metadataType: 'property',
metadataId: item.id,
originalId: item.plugin,
}
})
onMapData(arr)
}
});
</script>
<style scoped lang='less'>

View File

@ -2006,7 +2006,7 @@ export default [
],
},
],
accessSupport: { text: "不支持", value: "unsupported" },
accessSupport: { text: "间接支持", value: "indirect" },
supportDataAccess: false
},
],
@ -2363,10 +2363,10 @@ export default [
permission: 'rule-scene',
actions: ['query', 'delete'],
},
{
permission: 'alarm-config',
actions: ['query'],
},
// {
// permission: 'alarm-config',
// actions: ['query'],
// },
],
},
{

View File

@ -23,7 +23,6 @@
selectedRowKeys: _selectedRowKeys,
onSelect: onSelectChange,
}"
@cancelSelect='cancelSelect'
:params='params'
>
<template #registryTime='slotProps'>

View File

@ -21,7 +21,6 @@
}
: false
"
@cancelSelect="cancelSelect"
:params="params"
:gridColumn="3"
>

View File

@ -40,7 +40,6 @@
selectedRowKeys: _selectedRowKeys,
onChange: onSelectChange,
}"
@cancelSelect="_selectedRowKeys = []"
:pagination="{
showSizeChanger: true,
pageSizeOptions: ['10', '20', '50', '100'],

View File

@ -17,7 +17,6 @@
selectedRowKeys: _selectedRowKeys,
onChange: onSelectChange,
}"
@cancelSelect="_selectedRowKeys = []"
:pagination="{
showSizeChanger: true,
pageSizeOptions: ['10', '20', '50', '100'],

View File

@ -143,7 +143,6 @@
import ChannelApi from '@/api/media/channel';
import type { ActionsType } from '@/views/device/Instance/typings';
import { useMenuStore } from 'store/menu';
import { message } from 'jetlinks-ui-components';
import Save from './Save.vue';
import Live from './Live/index.vue';
import Tree from './Tree/index.vue';

View File

@ -33,7 +33,6 @@
</template>
<script setup lang="ts">
import { message } from 'jetlinks-ui-components';
import type { recordsItemType } from './typings';
import type { Dayjs } from 'dayjs';
import dayjs from 'dayjs';

View File

@ -0,0 +1,213 @@
<template>
<j-modal
visible
title="新增"
okText="确定"
cancelText="取消"
:width="1000"
@cancel="closeModal"
@ok="saveCorrelation"
>
<pro-search :columns="columns" @search="handleSearch" />
<div style="height: 500px; overflow-y: auto">
<JProTable
model="CARD"
:request="query"
:rowSelection="{
selectedRowKeys: _selectedRowKeys,
onSelectNone: onSelectChange,
// onChange: onChange,
}"
:gridColumns="[1, 1, 1]"
:defaultParams="{
sorts: [
{
name: 'createTime',
order: 'desc',
},
],
terms,
}"
:params="params"
>
<template #card="slotProps">
<CardBox
:value="slotProps"
:status="slotProps.state?.value"
:statusText="slotProps.state?.text"
:active="_selectedRowKeys.includes(slotProps.id)"
@click="handleClick"
:statusNames="{
started: 'processing',
disable: 'error',
}"
:disabled="slotProps.state?.value === 'disable'"
>
<template #type>
<span
><img
:height="16"
:src="
typeMap.get(slotProps.triggerType)?.icon
"
style="margin-right: 5px"
/>{{
typeMap.get(slotProps.triggerType)?.text
}}</span
>
</template>
<template #img>
<img
:src="typeMap.get(slotProps.triggerType)?.img"
/>
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)">
<span style="font-size: 16px; font-weight: 600">
{{ slotProps.name }}
</span>
</Ellipsis>
<Ellipsis :lineClamp="2">
<div class="subTitle">
说明{{
slotProps?.description ||
typeMap.get(slotProps.triggerType)?.tip
}}
</div>
</Ellipsis>
</template>
</CardBox>
</template>
</JProTable>
</div>
</j-modal>
</template>
<script lang="ts" setup>
import { getImage, onlyMessage } from '@/utils/comm';
import { query } from '@/api/rule-engine/scene';
import { _execute } from '@/api/rule-engine/configuration';
const columns = [
{
title: '名称',
dataIndex: 'name',
key: 'name',
search: {
type: 'string',
},
},
{
title: '触发方式',
dataIndex: 'triggerType',
key: 'triggerType',
},
{
title: '状态',
dataIndex: 'state',
key: 'state',
search: {
type: 'select',
options: [
{
label: '正常',
value: 'started',
},
{
label: '禁用',
value: 'disable',
},
],
},
},
];
const props = defineProps({
data: {
type: Object,
default: () => {},
},
});
const terms = [
{
terms: [
{
column: 'id',
termType: 'alarm-bind-rule',
value: props.data?.id,
},
{
column: 'triggerType',
termType: 'eq',
value: props.data?.sceneTriggerType,
},
],
type: 'and',
},
];
const params = ref();
const typeMap = new Map();
typeMap.set('manual', {
text: '手动触发',
img: getImage('/scene/scene-hand.png'),
icon: getImage('/scene/trigger-type-icon/manual.png'),
tip: '适用于第三方平台向物联网平台下发指令控制设备',
});
const _selectedRowKeys = ref<string[]>([]);
const handleClick = (dt: any) => {
if(dt.state?.value === 'disable') {
return
}
if (_selectedRowKeys.value.includes(dt.id)) {
const _index = _selectedRowKeys.value.findIndex((i) => i === dt.id);
_selectedRowKeys.value.splice(_index, 1);
} else {
_selectedRowKeys.value = [..._selectedRowKeys.value, dt.id];
}
};
/**
* 取消选择事件
*/
const onSelectChange = () => {
_selectedRowKeys.value = [];
};
const handleSearch = (e: any) => {
params.value = e;
};
const emit = defineEmits(['close', 'save']);
/**
* 保存选中关联场景
*/
const saveCorrelation = async () => {
if (_selectedRowKeys.value.length > 0) {
const scene = _selectedRowKeys.value.map((i) => {
return { id: i };
});
_execute(scene).then((res) => {
if (res.status === 200) {
onlyMessage('操作成功');
emit('save');
} else {
onlyMessage('操作失败', 'error');
}
});
} else {
onlyMessage('请选择至少一条数据', 'error');
}
};
const closeModal = () => {
emit('close');
};
</script>
<style lang="less" scoped>
.subTitle {
color: rgba(0, 0, 0, 0.65);
font-size: 14px;
margin-top: 10px;
}
</style>

View File

@ -15,8 +15,8 @@
:request="query"
:rowSelection="{
selectedRowKeys: _selectedRowKeys,
onChange: onSelectChange
}"
@cancelSelect="cancelSelect"
:gridColumns="[1, 1, 1]"
:defaultParams="{
sorts: [
@ -189,13 +189,12 @@ const handleClick = (dt: any) => {
} else {
_selectedRowKeys.value = [..._selectedRowKeys.value, dt.id];
}
console.log(_selectedRowKeys.value);
};
/**
* 取消选择事件
*/
const cancelSelect = () => {
_selectedRowKeys.value = [];
const onSelectChange = (arr: any[]) => {
_selectedRowKeys.value = arr
};
const log = () => {};
log();

View File

@ -184,6 +184,7 @@
</FullPage>
</div>
</page-container>
<HandTrigger @save="onSave" @close="visible = false" v-if="visible" :data="current" />
</template>
<script lang="ts" setup>
@ -192,7 +193,6 @@ import {
_enable,
_disable,
remove,
_execute,
getScene,
} from '@/api/rule-engine/configuration';
import { queryLevel } from '@/api/rule-engine/config';
@ -201,6 +201,8 @@ import type { ActionsType } from '@/components/Table/index.vue';
import { getImage, onlyMessage } from '@/utils/comm';
import { useMenuStore } from '@/store/menu';
import encodeQuery from '@/utils/encodeQuery';
import HandTrigger from './HandTrigger/index.vue';
const params = ref<Record<string, any>>({});
let isAdd = ref<number>(0);
let title = ref<string>('');
@ -331,6 +333,9 @@ const columns = [
scopedSlots: true,
},
];
const visible = ref<boolean>(false);
const current = ref<any>({});
const map = {
product: '产品',
device: '设备',
@ -382,23 +387,9 @@ const getActions = (
? '未启用,不能手动触发'
: '手动触发',
},
popConfirm: {
title: '确定手动触发?',
onConfirm: async () => {
const scene = (data.scene || [])
.filter((item: any) => item?.triggerType === 'manual')
.map((i) => {
return { id: i?.id };
});
_execute(scene).then((res) => {
if (res.status === 200) {
onlyMessage('操作成功');
tableRef.value?.reload();
} else {
onlyMessage('操作失败', 'error');
}
});
},
onClick: () => {
visible.value = true;
current.value = data
},
icon: 'LikeOutlined',
},
@ -479,6 +470,10 @@ const getActions = (
(item) => item.key != 'tigger' || data.sceneTriggerType == 'manual',
);
};
const onSave = () => {
visible.value = false;
tableRef.value?.reload();
}
const add = () => {
menuStory.jumpPage('rule-engine/Alarm/Configuration/Save');
};

View File

@ -59,7 +59,6 @@ import { detail as configurationDetail } from '@/api/rule-engine/configuration';
import { useRoute } from 'vue-router';
import dayjs from 'dayjs';
import type { ActionsType } from '@/components/Table/index.vue';
import { message } from 'jetlinks-ui-components';
import { useAlarmStore } from '@/store/alarm';
import Info from './info.vue';
import { storeToRefs } from 'pinia';

View File

@ -42,7 +42,6 @@
selectedRowKeys: table._selectedRowKeys.value,
onChange: selectChange,
}"
@cancelSelect="table.cancelSelect"
:columns="columns"
>
<template #card="slotProps">

View File

@ -25,7 +25,6 @@
selectedRowKeys: table._selectedRowKeys,
onChange: table.onSelectChange,
}"
@cancelSelect="table.cancelSelect"
model="TABLE"
:defaultParams="{
pageSize: 10,

View File

@ -16,7 +16,6 @@
selectedRowKeys: table._selectedRowKeys,
onChange: table.onSelectChange,
}"
@cancelSelect="table.cancelSelect"
model="TABLE"
:defaultParams="{
pageSize: 10,

View File

@ -261,7 +261,6 @@
<script setup lang="ts">
import PermissionButton from '@/components/PermissionButton/index.vue';
import { FormInstance } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import ChooseIconDialog from '../components/ChooseIconDialog.vue';
import PermissChoose from '../components/PermissChoose.vue';
import {

View File

@ -24,8 +24,13 @@
v-for="item in dataSource"
:key="item.provider"
class="custom"
:header="item.name"
>
<template #header>
<div>
{{ item.name }}
<span style="margin-left: 10px;" class="alert" v-if="item.provider === 'alarm'">注意接收人需要有告警配置页面查询权限才能收到告警类通知</span>
</div>
</template>
<div class="child">
<template
v-for="(child, index) in item.children"

View File

@ -16,15 +16,7 @@
selectedRowKeys: selectedRowKeys,
onChange: (keys:string[])=>selectedRowKeys = keys,
}"
@cancelSelect="selectedRowKeys = []"
size="small"
:defaultParams="{
pageSize: 10,
}"
:pagination="{
showSizeChanger: true,
pageSizeOptions: ['10', '20', '50', '100'],
}"
>
<template #headerTitle>
<j-space>
@ -191,6 +183,7 @@ const table = {
//
const dialogVisible = ref(false);
</script>
<style lang="less" scoped>

View File

@ -1,42 +1,19 @@
<template>
<j-modal
visible
title="新增"
width="1000px"
@ok="confirm"
@cancel="emits('update:visible', false)"
>
<j-modal visible title="新增" width="1000px" @ok="confirm" @cancel="emits('update:visible', false)">
<!-- <j-advanced-search
:columns="columns"
type="simple"
@search="(params:any)=>queryParams = {...params}"
/> -->
<pro-search
:columns="columns"
target="simple"
@search="(params:any)=>queryParams = {...params}"
/>
<pro-search :columns="columns" target="simple" @search="(params: any) => queryParams = { ...params }" />
<j-pro-table
ref="tableRef"
:columns="columns"
:request="getUserList"
model="TABLE"
:params="queryParams"
<j-pro-table ref="tableRef" :columns="columns" :request="getUserList" model="TABLE" :params="queryParams"
:rowSelection="{
selectedRowKeys: selectedRowKeys,
onSelect: changeSelect,
}"
@cancelSelect="selectedRowKeys = []"
:defaultParams="{
pageSize: 10,
}"
:pagination="{
pageSizeOptions: ['10', '20', '50', '100'],
showSizeChanger: true,
hideOnSinglePage: false,
}"
>
onSelectAll: selectAll,
onSelectNone: ()=>selectedRowKeys = []
}">
</j-pro-table>
</j-modal>
</template>
@ -71,7 +48,7 @@ const columns = [
];
const queryParams = ref({});
const selectedRowKeys = ref<string[]>([]);
const selectedRowKeys = ref<any>([]);
const getUserList = (oParams: any) => {
const params = {
...oParams,
@ -117,4 +94,25 @@ const changeSelect = (item: any, state: boolean) => {
}
selectedRowKeys.value = [...arr.values()];
};
const selectAll = (selected: Boolean, selectedRows: any,changeRows:any) => {
if (selected) {
changeRows.map((i: any) => {
if (!selectedRowKeys.value.includes(i.id)) {
selectedRowKeys.value.push(i.id)
}
})
} else {
const arr = changeRows.map((item: any) => item.id)
const _ids: string[] = [];
selectedRowKeys.value.map((i: any) => {
if (!arr.includes(i)) {
_ids.push(i)
}
})
selectedRowKeys.value = _ids
}
}
</script>