fix: 优化切换条件指标值错误问题;bug#23806、23826、23762、23672

* feat: 修改docker文件

* fix: bug#23086、23808、23669

* fix:删除+编辑

* fix: bug#23086

* fix: bug#23808

* fix: bug#23669

* fix: 优化切换条件指标值错误问题;bug#23806、23826、23762、23672

* fix: bug#23762、23672

* fix: bug#23826

* fix: 切换条件指标值错误问题

* fix: bug#23806
This commit is contained in:
qiaochuLei 2024-04-12 16:52:29 +08:00 committed by GitHub
parent a9a6a096e6
commit eb279582b1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 326 additions and 150 deletions

View File

@ -1,3 +1,3 @@
#!/usr/bin/env bash
docker build -t registry.cn-shenzhen.aliyuncs.com/jetlinks/jetlinks-ui-vue:2.2.0-SNAPSHOT .
docker push registry.cn-shenzhen.aliyuncs.com/jetlinks/jetlinks-ui-vue:2.2.0-SNAPSHOT
docker build -t registry.cn-shenzhen.aliyuncs.com/jetlinks/jetlinks-ui-vue:2.1.0-TEST .
docker push registry.cn-shenzhen.aliyuncs.com/jetlinks/jetlinks-ui-vue:2.1.0-TEST

51
package-lock.json generated
View File

@ -21,6 +21,7 @@
"event-source-polyfill": "^1.0.31",
"global": "^4.4.0",
"jetlinks-store": "^0.0.3",
"jetlinks-ui-components": "^1.0.37",
"js-cookie": "^3.0.1",
"jsencrypt": "^3.3.2",
"less": "^4.1.3",
@ -5216,6 +5217,30 @@
"resolved": "https://registry.npmjs.org/jetlinks-store/-/jetlinks-store-0.0.3.tgz",
"integrity": "sha512-AZf/soh1hmmwjBZ00fr1emuMEydeReaI6IBTGByQYhTmK1Zd5pQAxC7WLek2snRAn/HHDgJfVz2hjditKThl6Q=="
},
"node_modules/jetlinks-ui-components": {
"version": "1.0.37",
"resolved": "https://registry.npmjs.org/jetlinks-ui-components/-/jetlinks-ui-components-1.0.37.tgz",
"integrity": "sha512-Zhjz5/Zs02Jy40eLmh/zgF9zQlDKUpeHptTYzb9LQjszqAUAV3XjWPcNoyMqE4nP8Q3uagyw1yxJfWvzxDf62Q==",
"dependencies": {
"@vueuse/core": "^9.12.0",
"@vueuse/router": "^9.13.0",
"ant-design-vue": "^3.2.15",
"colorpicker-v3": "^2.10.2",
"lodash-es": "^4.17.21",
"monaco-editor": "^0.40.0",
"onigasm": "^2.2.5",
"sortablejs": "^1.15.0",
"vuedraggable": "^4.1.0"
},
"engines": {
"node": ">=18.14.0"
}
},
"node_modules/jetlinks-ui-components/node_modules/monaco-editor": {
"version": "0.40.0",
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.40.0.tgz",
"integrity": "sha512-1wymccLEuFSMBvCk/jT1YDW/GuxMLYwnFwF9CDyYCxoTw2Pt379J3FUhwy9c43j51JdcxVPjwk0jm0EVDsBS2g=="
},
"node_modules/js-cookie": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.1.tgz",
@ -8823,8 +8848,11 @@
"version": "2.0.5",
"resolved": "http://registry.jetlinks.cn/init-package-json/-/init-package-json-2.0.5.tgz",
"integrity": "sha512-u1uGAtEFu3VA6HNl/yUWw57jmKEMx8SKOxHhxjGnOFUiIlFnohKDFg4ZrPpv9wWqk44nDxGJAtqjdQFm+9XXQA==",
<<<<<<< HEAD
=======
"resolved": "http://registry.jetlinks.cn/init-package-json/-/init-package-json-2.0.5.tgz",
"integrity": "sha512-u1uGAtEFu3VA6HNl/yUWw57jmKEMx8SKOxHhxjGnOFUiIlFnohKDFg4ZrPpv9wWqk44nDxGJAtqjdQFm+9XXQA==",
>>>>>>> dev-bug
"inBundle": true,
"license": "ISC",
"dependencies": {
@ -17472,6 +17500,29 @@
"resolved": "https://registry.npmjs.org/jetlinks-store/-/jetlinks-store-0.0.3.tgz",
"integrity": "sha512-AZf/soh1hmmwjBZ00fr1emuMEydeReaI6IBTGByQYhTmK1Zd5pQAxC7WLek2snRAn/HHDgJfVz2hjditKThl6Q=="
},
"jetlinks-ui-components": {
"version": "1.0.37",
"resolved": "https://registry.npmjs.org/jetlinks-ui-components/-/jetlinks-ui-components-1.0.37.tgz",
"integrity": "sha512-Zhjz5/Zs02Jy40eLmh/zgF9zQlDKUpeHptTYzb9LQjszqAUAV3XjWPcNoyMqE4nP8Q3uagyw1yxJfWvzxDf62Q==",
"requires": {
"@vueuse/core": "^9.12.0",
"@vueuse/router": "^9.13.0",
"ant-design-vue": "^3.2.15",
"colorpicker-v3": "^2.10.2",
"lodash-es": "^4.17.21",
"monaco-editor": "^0.40.0",
"onigasm": "^2.2.5",
"sortablejs": "^1.15.0",
"vuedraggable": "^4.1.0"
},
"dependencies": {
"monaco-editor": {
"version": "0.40.0",
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.40.0.tgz",
"integrity": "sha512-1wymccLEuFSMBvCk/jT1YDW/GuxMLYwnFwF9CDyYCxoTw2Pt379J3FUhwy9c43j51JdcxVPjwk0jm0EVDsBS2g=="
}
}
},
"js-cookie": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.1.tgz",

View File

@ -4,7 +4,7 @@
placeholder="请上传文件"
v-model:value="fileValue"
style="width: calc(100% - 110px)"
:disabled="true"
@change="fileValueChange"
/>
<j-upload
name="file"
@ -79,6 +79,10 @@ const handleChange = async (info: UploadChangeParam) => {
}
};
const fileValueChange = () =>{
emit('update:modelValue',fileValue.value)
}
watch(
() => props.modelValue,
(value) => {

View File

@ -9,9 +9,14 @@
>
<j-tab-pane v-for="func in newFunctions" :key="func.id">
<template #tab>
<div style="width: 100px; text-align: left">
<j-ellipsis>{{ func.name }}</j-ellipsis>
<j-tooltip>
<template #title>
{{ func.name }}
</template>
<div style="max-width: 100px" class="tabTitle">
{{ func.name }}
</div>
</j-tooltip>
</template>
</j-tab-pane>
</j-tabs>
@ -34,10 +39,7 @@
>
执行
</j-button>
<j-button
type="default"
@click="handleClear()"
>
<j-button type="default" @click="handleClear()">
清空
</j-button>
</j-space>
@ -122,8 +124,8 @@ watch(
},
{
immediate: true,
deep: true
}
deep: true,
},
);
const onTabChange = (_key: string) => {
@ -148,7 +150,8 @@ const handleExecute = async (func: any) => {
loading.value = false;
});
if (resp.success) {
executeResult.value = resp?.result instanceof Array ? resp?.result?.[0] : resp.result;
executeResult.value =
resp?.result instanceof Array ? resp?.result?.[0] : resp.result;
onlyMessage('操作成功');
}
};
@ -181,4 +184,9 @@ const handleClear = () => {
overflow: auto;
}
}
.tabTitle {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

View File

@ -6,12 +6,22 @@
<span>精简模式下参数只支持输入框的方式录入</span>
</j-space>
</div>
<j-tabs v-model="activeKey" tab-position="left" @change="onTabChange" :destroyInactiveTabPane="true">
<j-tabs
v-model="activeKey"
tab-position="left"
@change="onTabChange"
:destroyInactiveTabPane="true"
>
<j-tab-pane v-for="func in newFunctions" :key="func.id">
<template #tab>
<Ellipsis style="width: 100px; text-align: left">
<j-tooltip>
<template #title>
{{ func.name }}
</Ellipsis>
</template>
<div style="max-width: 150px" class="tabTitle">
{{ func.name }}
</div>
</j-tooltip>
</template>
<j-row :gutter="30">
<j-col :span="15">
@ -137,7 +147,7 @@ const columns = ref([
},
]);
const executeResult = ref('')
const executeResult = ref('');
//
const newFunctions = computed(() => {
@ -174,7 +184,7 @@ const newFunctions = computed(() => {
? tableItem['json']?.['properties'][0]
: undefined,
value: undefined,
required: tableItem.expands?.required
required: tableItem.expands?.required,
});
}
@ -203,17 +213,18 @@ const handleExecute = async (func: any) => {
obj[item.id] = item.value;
}
});
loading.value = true
loading.value = true;
const { success, result } = await execute(
route.params.id as string,
func.id,
obj,
).catch(() => {
loading.value = false
)
.catch(() => {
loading.value = false;
})
.finally(() => {
loading.value = false
})
loading.value = false;
});
if (!success) return;
onlyMessage('操作成功');
executeResult.value = result instanceof Array ? result[0] : result;
@ -227,13 +238,13 @@ const handleExecute = async (func: any) => {
* 清空
*/
const handleClear = (func: any) => {
executeResult.value = ''
executeResult.value = '';
proxy?.$refs[`${func.id}Ref`][0].resetFields();
};
const onTabChange = (_key: string) => {
executeResult.value = ''
}
executeResult.value = '';
};
</script>
<style lang="less" scoped>
@ -263,4 +274,9 @@ const onTabChange = (_key: string) => {
overflow: auto;
}
}
.tabTitle {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

View File

@ -160,8 +160,19 @@ watch(
);
modelRef.metrics = list || [];
} else {
modelRef.metrics =
props.data.expands?.metrics || [];
modelRef.metrics = (
props.data.expands?.metrics || []
).map((item: any) => {
const val = Array.isArray(item?.value)
? item?.value
: isNumber(item?.value)
? [item.value]
: item?.value?.split(',');
return {
...item,
value: val,
};
});
}
}
}

View File

@ -16,7 +16,18 @@
:tabBarStyle="{ width: '200px' }"
@change="tabChange"
>
<j-tab-pane v-for="i in tabList" :key="i.key" :tab="i.tab" />
<j-tab-pane v-for="i in tabList" :key="i.key">
<template #tab>
<j-tooltip>
<template #title>
{{ i.tab }}
</template>
<div style="max-width: 150px" class="tabTitle">
{{ i.tab }}
</div>
</j-tooltip>
</template>
</j-tab-pane>
</j-tabs>
<JEmpty v-else style="margin: 180px 0" />
</div>
@ -129,4 +140,9 @@ const tabChange = (key: string) => {
flex: 1;
}
}
.tabTitle {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

View File

@ -161,7 +161,6 @@ const submitData = async (fileUrl: string) => {
errCount.value = et;
}
}
flag.value=false;
disabled.value = false;
};
source.onerror = (e: { status: number }) => {

View File

@ -720,7 +720,10 @@ const getActions = (
const resp = await _delete(data.id);
if (resp.status === 200) {
onlyMessage('操作成功!');
_selectedRowKeys.value=[];
const index = _selectedRowKeys.value.findIndex((id: any) => id === data.id);
if (index !== -1) {
_selectedRowKeys.value.splice(index, 1);
}
instanceRef.value?.reload();
} else {
onlyMessage('操作失败!', 'error');

View File

@ -210,7 +210,7 @@
key="add"
:disabled="hasOperate('add', type)"
:tooltip="{
placement: hasOperate('add', type) ? 'topRight' : 'top',
placement:'top',
title: hasOperate('add', type)
? '当前的存储方式不支持新增'
: '新增',

View File

@ -680,7 +680,10 @@ const getActions = (
const resp: any = await del(data.id);
if (resp.status === 200) {
onlyMessage('操作成功');
_selectedRowKeys.value=[];
const index = _selectedRowKeys.value.findIndex((id: any) => id === data.id);
if (index !== -1) {
_selectedRowKeys.value.splice(index, 1);
}
cardManageRef.value?.reload();
} else {
onlyMessage('操作失败!', 'error');

View File

@ -205,7 +205,6 @@ const tableRef = ref<Record<string, any>>({});
const params = ref<Record<string, any>>({});
let providersList = ref<Record<string, any>>([]);
const providersOptions = ref<Record<string, any>>([]);
const statusMap = new Map();
statusMap.set('enabled', 'success');
@ -227,7 +226,13 @@ const columns = [
key: 'provider',
search: {
type: 'select',
options: providersOptions,
options: async() =>{
const res: any = await getProviders();
const providersOptions = accessConfigTypeFilter(res.result || []);
return providersOptions.filter((i:any)=>{
return i.id !== 'modbus-tcp' && i.id !== 'opc-ua'
})
},
},
},
{
@ -331,10 +336,6 @@ const getActions = (data: Partial<Record<string, any>>): ActionsType[] => {
const getProvidersList = async () => {
const res: any = await getProviders();
providersList.value = res.result;
providersOptions.value = accessConfigTypeFilter(res.result || []);
providersOptions.value = providersOptions.value.filter((i:any)=>{
return i.id !== 'modbus-tcp' && i.id !== 'opc-ua'
})
};
getProvidersList();

View File

@ -303,7 +303,7 @@ watch(
const showDouble = computed(() => {
const isRange = paramsValue.termType
? doubleParamsKey.includes(paramsValue.termType)
? arrayParamsKey.includes(paramsValue.termType)
: false;
const isSourceMetric = paramsValue.value?.source === 'metric';
if (metricsCacheOption.value.length) {
@ -324,13 +324,7 @@ const showDouble = computed(() => {
});
const showArray = computed(()=>{
const isRange = paramsValue.termType ? [
'in',
'nin',
'contains_all',
'contains_any',
'not_contains',
].includes(paramsValue.termType) : false;
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) =>
@ -458,6 +452,8 @@ const termsTypeSelect = (e: { key: string; name: string }) => {
if (arrayParamsKey.includes(e.key) !== isArray) {
//
newValue.value = undefined;
}else{
newValue.value = paramsValue.value!.value
}
}
if (['isnull', 'notnull'].includes(e.key)) {

View File

@ -53,10 +53,16 @@
</slot>
</template>
<template #content>
<Ellipsis>
<h3 class="card-item-content-title">
<Ellipsis
style="
width: calc(100% - 100px);
font-size: 16px;
color: rgb(49, 94, 251);
font-weight: 700;
margin-bottom: 8px;
"
>
{{ slotProps.name }}
</h3>
</Ellipsis>
<j-row>
<j-col :span="12">

View File

@ -457,7 +457,7 @@ const uploader: uploaderType = {
uploader.imageTypes
.map((m: string) => m.split('.')[1])
.filter((typeStr) => file.type.includes(typeStr)).length > 0;
const sizeBool = file.size / 1024 / 1024 < 2;
const sizeBool = file.size / 1024 / 1024 < 4;
if (!typeBool) {
onlyMessage(`请上传.jpg.png.jfif.pjp.pjpeg.jpeg格式的图片`, 'error');
} else if (!sizeBool) {

View File

@ -1,6 +1,11 @@
<template>
<div class="left-contain">
<j-input placeholder="分组名称" v-model:value="searchValue" @pressEnter="search" @change="searchChange">
<j-input
placeholder="分组名称"
v-model:value="searchValue"
@pressEnter="search"
@change="searchChange"
>
<template #suffix>
<AIcon type="SearchOutlined" @click="search" />
</template>
@ -11,150 +16,207 @@
</j-button>
</div>
<div class="listBox">
<j-tree :tree-data="listData" v-if="listData.length" :fieldNames="{ title: 'name', key: 'id', children: 'children' }"
blockNode :selectedKeys="selectedKeys" :default-expanded-keys="['global_role']"
:showLine="{ showLeafIcon: false }">
<j-tree
:tree-data="listData"
v-if="listData.length"
:fieldNames="{ title: 'name', key: 'id', children: 'children' }"
blockNode
:selectedKeys="selectedKeys"
:default-expanded-keys="['global_role']"
:showLine="{ showLeafIcon: false }"
>
<template #title="item">
<div v-if="selectId === item.data.id">
<j-input v-model:value="addName" @blur="() => saveGroup(item.data)" ref="inputRef"
:maxlength="64"></j-input>
<j-input
v-model:value="addName"
@blur="() => saveGroup(item.data)"
ref="inputRef"
:maxlength="64"
></j-input>
</div>
<div class="treeItem" @click="() => selectGroup(item.data.id)" v-else>
<div
class="treeItem"
@click="() => selectGroup(item.data.id)"
v-else
>
<template v-if="!item?.children">
<div class="itemText">
<Ellipsis style="width: calc(100%-100px)">{{ item.name }}</Ellipsis>
<Ellipsis style="width: calc(100%-100px)">{{
item.name
}}</Ellipsis>
</div>
<div @click="(e) => e.stopPropagation()" v-if="item.id !== 'default_group'">
<PermissionButton type="text" hasPermission="system/Role:groupDelete" :popConfirm="{
<div
@click="(e) => e.stopPropagation()"
v-if="item.id !== 'default_group'"
>
<PermissionButton
type="text"
hasPermission="system/Role:groupDelete"
:popConfirm="{
title: `确定要删除?`,
onConfirm: () => deleteGroup(item.id),
}" :disabled="item.id === 'default_group'">
}"
:disabled="item.id === 'default_group'"
>
删除
</PermissionButton>
<PermissionButton type="text" hasPermission="system/Role:groupUpdate"
@click="editGroup(item.data)" :disabled="item.id === 'default_group'">
<PermissionButton
type="text"
hasPermission="system/Role:groupUpdate"
@click="editGroup(item.data)"
:disabled="item.id === 'default_group'"
>
编辑
</PermissionButton>
</div>
</template>
<template v-else>
<Ellipsis style="width: calc(100%-100px)">{{ item.name }}</Ellipsis>
<Ellipsis style="width: calc(100%-100px)">{{
item.name
}}</Ellipsis>
</template>
</div>
</template>
</j-tree>
<j-empty v-else style="margin-top: 100px;" />
<j-empty v-else style="margin-top: 100px" />
</div>
</div>
</template>
<script lang="ts" setup>
import { onlyMessage } from '@/utils/comm';
import { queryRoleGroup, saveRoleGroup, deleteRoleGroup } from '@/api/system/role';
import {
queryRoleGroup,
saveRoleGroup,
deleteRoleGroup,
} from '@/api/system/role';
import { randomString } from '@/utils/utils';
import { useUserInfo } from '@/store/userInfo';
import { storeToRefs } from 'pinia';
const emit = defineEmits(['selectData'])
const userInfoStore = useUserInfo()
const { userInfos } = storeToRefs(userInfoStore)
const emit = defineEmits(['selectData']);
const userInfoStore = useUserInfo();
const { userInfos } = storeToRefs(userInfoStore);
const admin = computed(() => {
return userInfos.value?.username === 'admin';
})
const listData: any = ref([{
});
const listData: any = ref([
{
name: '全局角色',
id: 'global_role',
children: []
}])
const selectedKeys = ref<string[]>(['global_role'])
const searchValue = ref()
const inputRef = ref()
const addName = ref()
const selectId = ref()
children: [],
},
]);
const selectedKeys = ref<string[]>(['global_role']);
const searchValue = ref();
const inputRef = ref();
const addName = ref();
const selectId = ref();
const queryGroup = async (select?: Boolean, searchName?: string) => {
const params = searchName ? { sorts: [{ name: 'createTime', order: 'desc' }], terms: [{ terms: [{ value: '%' + searchName + '%', termType: 'like', column: 'name' }] }] } : { sorts: [{ name: 'createTime', order: 'desc' }] }
const req: any = await queryRoleGroup(params)
const params = searchName
? {
sorts: [{ name: 'createTime', order: 'desc' }],
terms: [
{
terms: [
{
value: '%' + searchName + '%',
termType: 'like',
column: 'name',
},
],
},
],
}
: { sorts: [{ name: 'createTime', order: 'desc' }] };
const req: any = await queryRoleGroup(params);
if (req.status === 200) {
listData.value[0].children = req.result
listData.value[0].children = req.result;
if (req.result[req.result.length - 1].id === 'default_group') {
req.result.unshift(req.result[req.result.length - 1])
req.result.pop()
req.result.unshift(req.result[req.result.length - 1]);
req.result.pop();
}
// if(req.result.length && select){
// selectGroup(req.result[0].id)
// }
}
}
};
const addGroup = () => {
addName.value = ''
const newId = randomString()
listData.value[0].children.splice(1, 0, ({
addName.value = '';
const newId = randomString();
listData.value[0].children.splice(1, 0, {
name: '',
id: newId
}))
selectId.value = newId
id: newId,
});
selectId.value = newId;
nextTick(() => {
inputRef.value.focus()
})
}
inputRef.value.focus();
});
};
const saveGroup = async (data: any) => {
if (addName.value === '' ) {
listData.value[0].children.splice(1,1)
} else {
if(data.name===''){
listData.value[0].children.splice(1, 1);
}
}
else {
const saveData = {
name: addName.value,
id: data.id
}
const res = await saveRoleGroup(saveData)
id: data.id,
};
const res = await saveRoleGroup(saveData);
if (res.status === 200) {
onlyMessage('操作成功!')
queryGroup()
onlyMessage('操作成功!');
queryGroup();
} else {
onlyMessage('操作失败!')
onlyMessage('操作失败!');
}
}
setTimeout(() => {
selectId.value = ''
},300)
}
selectId.value = '';
}, 300);
};
const search = () => {
queryGroup(true, searchValue.value)
}
queryGroup(true, searchValue.value);
};
const searchChange = () => {
if (searchValue.value === '') {
queryGroup()
}
queryGroup();
}
};
const selectGroup = (id: string) => {
selectedKeys.value = [id]
id === 'global_role' ? emit('selectData', '') : emit('selectData', selectedKeys.value)
}
selectedKeys.value = [id];
id === 'global_role'
? emit('selectData', '')
: emit('selectData', selectedKeys.value);
};
const deleteGroup = async (id: string) => {
const res: any = await deleteRoleGroup(id)
const res: any = await deleteRoleGroup(id);
if (res.status === 200) {
onlyMessage('操作成功!')
queryGroup(true)
onlyMessage('操作成功!');
queryGroup(true);
} else {
onlyMessage('操作失败!')
}
onlyMessage('操作失败!');
}
};
const editGroup = (data: any) => {
if (!selectId.value) {
selectId.value = data.id
addName.value = data.name
selectId.value = data.id;
addName.value = data.name;
listData.value[0].children.forEach((item: any) => {
if (item.id === data.id) {
item.edit = true
item.edit = true;
}
})
});
nextTick(() => {
inputRef.value.focus()
})
inputRef.value.focus();
});
}
};
}
onMounted(() => {
queryGroup(true)
})
queryGroup(true);
});
</script>
<style lang="less" scoped>
.controls {
@ -167,7 +229,7 @@ onMounted(() => {
.itemText {
line-height: 32px;
max-width: 40%
max-width: 40%;
}
}

View File

@ -145,7 +145,7 @@
class="more-button-item"
v-for="(
item, index
) in bindings"
) in bindings.slice(4,bindings.length-1)"
:key="index"
@click="
handleClickOther(