fix: bug#19588、19904、19950

* fix: 菜单详情按钮管理编码改变权限回流bug

* fix: 菜单bug

* fix: bug#19588

* fix: bug#19904

* fix: bug#19950
This commit is contained in:
XieYongHong 2023-11-09 17:48:28 +08:00 committed by GitHub
parent f473124ce8
commit 0ff347fded
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 286 additions and 66 deletions

View File

@ -15,4 +15,4 @@ export const dashboard = (data?:any) => server.post('/dashboard/_multi',data);
/** /**
* *
*/ */
export const getGo = (data?:any) => server.post('/geo/object/device/_search/geo.json') export const getGo = (data?:any) => server.post('/geo/object/device/_search/geo.json',data)

View File

@ -32,4 +32,9 @@ export const delOperations_api = (data:object) => server.remove(`/application/op
* @param data * @param data
* @returns * @returns
*/ */
export const updateOperations_api = (code:string,type:'_add'| '_delete', data: object) => server.post(`/application/${code}/grant/${type}`, data); // export const updateOperations_api = (code:string,type:'_add'| '_delete', data: object) => server.post(`/application/${code}/grant/${type}`, data);
/**
* -/api
*/
export const updateOperations_api = (id:string,data:object) => server.post(`/application/${id}/grant`,data)

View File

@ -179,13 +179,13 @@ const handleMeta = (item: MenuItem, isApp: boolean) => {
} }
} }
const findComponents = (code: string, level: number, isApp: boolean, components: any) => { const findComponents = (code: string, level: number, isApp: boolean, components: any, mate: any, hasChildren: boolean) => {
const myComponents = components[code] const myComponents = components[code]
if (level === 1) { // BasicLayoutPage if (level === 1) { // BasicLayoutPage
if (myComponents) { if (myComponents && !hasChildren) {
return h(BasicLayoutPage, {}, () => [h(defineAsyncComponent(() => myComponents()), {})]) return mate?.hasLayout === false ? () => myComponents() : h(BasicLayoutPage, {}, () => [h(defineAsyncComponent(() => myComponents()), {})])
} }
if (isApp) { if (isApp && !hasChildren) {
return h(BasicLayoutPage, {}, () => [h(Iframe, {})]) return h(BasicLayoutPage, {}, () => [h(Iframe, {})])
} }
return myComponents ? () => myComponents() : BasicLayoutPage return myComponents ? () => myComponents() : BasicLayoutPage
@ -266,7 +266,7 @@ export const handleMenus = (menuData: any[], components: any, level: number = 1)
children: item.children children: item.children
} }
route.component = findComponents(item.code, level, isApp, components) route.component = findComponents(item.code, level, isApp, components, item.meta, !!item.chidlren?.length)
const extraRoute = hasExtraChildren(item, extraRouteObj) const extraRoute = hasExtraChildren(item, extraRouteObj)
const detail_components = findDetailRouteItem(item, components) const detail_components = findDetailRouteItem(item, components)

View File

@ -37,7 +37,11 @@ import AmapComponent from '@/components/AMapComponent/index.vue';
import { getGo } from '@/api/device/dashboard'; import { getGo } from '@/api/device/dashboard';
let point = ref(); let point = ref();
const getMapData = async () => { const getMapData = async () => {
const res = await getGo({}); const res = await getGo({
    filter:{
        paging:false
    }
});
point.value = res.result?.features; point.value = res.result?.features;
}; };
getMapData(); getMapData();

View File

@ -158,14 +158,14 @@ watch(
if (props.type === 'device') { if (props.type === 'device') {
detail(id as string).then((resp) => { detail(id as string).then((resp) => {
loading.value = false loading.value = false
instanceStore.setCurrent(resp.result) // instanceStore.setCurrent(resp.result)
value.value = resp.result.metadata value.value = resp.result.metadata
hideVirtualRule(resp.result.metadata) hideVirtualRule(resp.result.metadata)
}); });
} else { } else {
productDetail(id as string).then((resp) => { productDetail(id as string).then((resp) => {
loading.value = false loading.value = false
productStore.setCurrent(resp.result) // productStore.setCurrent(resp.result)
value.value = resp.result.metadata value.value = resp.result.metadata
hideVirtualRule(resp.result.metadata) hideVirtualRule(resp.result.metadata)
}); });

View File

@ -197,6 +197,7 @@ import { getToken, onlyMessage } from '@/utils/comm';
import { useMetadataStore } from '@/store/metadata'; import { useMetadataStore } from '@/store/metadata';
import { omit } from 'lodash-es'; import { omit } from 'lodash-es';
import { Modal } from 'jetlinks-ui-components'; import { Modal } from 'jetlinks-ui-components';
import { testObject , testType , testAliType , testAliObject} from './valideta'
const route = useRoute(); const route = useRoute();
const instanceStore = useInstanceStore(); const instanceStore = useInstanceStore();
@ -298,18 +299,19 @@ const requiredCheck = (data:any) =>{
onlyMessage(`标签定义第${index + 1}个数组中缺失valueType.type属性`,'error'); onlyMessage(`标签定义第${index + 1}个数组中缺失valueType.type属性`,'error');
check = true check = true
return return
}else{
check = testType(item,index)
} }
if(!item?.expands?.source){ if(!item?.expands?.source){
onlyMessage(`属性定义第${index + 1}个数组中缺失expands.source属性`,'error'); onlyMessage(`属性定义第${index + 1}个数组中缺失expands.source属性`,'error');
check = true check = true
return return
} }
if((item?.expands?.source === 'device' || item?.expands?.source === 'rule') && !item?.expands?.type){ if((item?.expands?.source === 'device' || item?.expands?.source === 'rule') && !item?.expands?.type){
onlyMessage(`属性定义第${index + 1}个数组中缺失type属性`,'error'); onlyMessage(`属性定义第${index + 1}个数组中缺失type属性`,'error');
check = true check = true
return return
} }
}) })
} }
if(data?.functions && !check){ if(data?.functions && !check){
@ -329,6 +331,16 @@ const requiredCheck = (data:any) =>{
check = true check = true
return return
} }
if(item?.inputs){
testObject(item.inputs,index)
item.inputs.forEach((i:any)=>{
if(!i?.expands?.required && i?.expands?.required !== false){
onlyMessage(`方法定义inputs第${index+1}个数组中缺失expands.required属性`,'error')
check = true
return
}
})
}
}) })
} }
if(data?.events && !check){ if(data?.events && !check){
@ -401,6 +413,8 @@ const requiredCheck = (data:any) =>{
onlyMessage(`标签定义第${index + 1}个数组中缺失valueType.type属性`,'error'); onlyMessage(`标签定义第${index + 1}个数组中缺失valueType.type属性`,'error');
check = true check = true
return return
}else{
testType(item?.valueType?.type,index)
} }
if(!item?.expands?.type){ if(!item?.expands?.type){
onlyMessage(`标签定义第${index + 1}个数组中缺失expands.type属性`,'error'); onlyMessage(`标签定义第${index + 1}个数组中缺失expands.type属性`,'error');
@ -430,6 +444,8 @@ const aliCheck = (data:any) => {
onlyMessage(`属性定义第${index + 1}个数组中缺失dataType.type属性`,'error'); onlyMessage(`属性定义第${index + 1}个数组中缺失dataType.type属性`,'error');
check = true check = true
return return
}else{
testAliType(item,index)
} }
}) })
} }
@ -450,6 +466,9 @@ const aliCheck = (data:any) => {
check = true check = true
return return
} }
if(item?.inputData){
testAliObject(item.inputData,index)
}
}) })
} }
if(data?.events && !check){ if(data?.events && !check){

View File

@ -0,0 +1,141 @@
import { onlyMessage } from "@/utils/comm"
export const testProperties = (data:any) =>{
}
export const testType = (data:any,index:number,isArray?:boolean,isObject?:boolean)=>{
if(data.valueType.type === 'boolean'){
if(!data?.valueType?.trueText || !data?.valueType?.trueValue || !data?.valueType?.falseText || !data?.valueType?.falseValue){
onlyMessage(`方法定义inputs第${index+1}个数组ValueType中缺失必填属性`,'error')
return true
}
}
if(data.valueType.type === 'enum' && !isObject){
if(data.valueType?.elements?.length > 0){
data.valueType.elements.forEach((a:any,b:number)=>{
if(!a.value || !a.text){
onlyMessage(`方法定义inputs第${index+1}个数组ValueType中elements缺失必填属性`,'error')
return true
}
})
}else{
onlyMessage(`方法定义inputs第${index+1}个数组ValueType中缺失elements属性`,'error')
return true
}
}
if(data.valueType.type === 'array' && !isArray && !isObject){
if(data.valueType?.elementType){
testType(data.valueType.elementType,index,true)
}else{
onlyMessage(`方法定义inputs第${index+1}个数组ValueType中缺失elementType属性`,'error')
return true
}
}
if(data.valueType.type === 'file' && !isArray && !isObject){
if(!data.valueType?.fileType){
onlyMessage(`方法定义inputs第${index+1}个数组ValueType中缺失fileType属性`,'error')
return true
}
}
if(data.valueType.type === 'object' && !isArray && !isObject){
if(data?.valueType?.properties?.length > 0){
return testObject(data.valueType.properties,index)
}else{
onlyMessage(`方法定义inputs第${index+1}个数组ValueType中缺失properties属性`,'error')
return true
}
}
}
export const testObject = (data:any,index:number)=>{
let check = false
data.forEach((i:any)=>{
if(!i?.id){
onlyMessage(`方法定义inputs第${index+1}个数组中缺失id属性`,'error')
check = true
return
}
if(!i?.name){
onlyMessage(`方法定义inputs第${index+1}个数组中缺失name属性`,'error')
check = true
return
}
if(!i?.valueType?.type){
onlyMessage(`方法定义inputs第${index+1}个数组中缺失valueType.type属性`,'error')
check = true
return
}else{
check = testType(i,index,false,true)
return
}
})
return check
}
export const testAliType = (data:any,index:number,isArray?:boolean,isObject?:boolean)=>{
if(data.dataType.type === 'boolean'){
if(!data?.dataType?.trueText || !data?.dataType?.trueValue || !data?.dataType?.falseText || !data?.dataType?.falseValue){
onlyMessage(`方法定义inputs第${index+1}个数组dataType中缺失必填属性`,'error')
return true
}
}
if(data.dataType.type === 'enum' && !isObject){
if(data.dataType?.elements?.length > 0){
data.dataType.elements.forEach((a:any,b:number)=>{
if(!a.value || !a.text){
onlyMessage(`方法定义inputs第${index+1}个数组dataType中elements缺失必填属性`,'error')
return true
}
})
}else{
onlyMessage(`方法定义inputs第${index+1}个数组dataType中缺失elements属性`,'error')
return true
}
}
if(data.dataType.type === 'array' && !isArray && !isObject){
if(data.dataType?.elementType){
testType(data.dataType.elementType,index,true)
}else{
onlyMessage(`方法定义inputs第${index+1}个数组dataType中缺失elementType属性`,'error')
return true
}
}
if(data.dataType.type === 'file' && !isArray && !isObject){
if(!data.dataType?.fileType){
onlyMessage(`方法定义inputs第${index+1}个数组dataType中缺失fileType属性`,'error')
return true
}
}
if(data.dataType.type === 'object' && !isArray && !isObject){
if(data?.dataType?.properties?.length > 0){
return testAliObject(data.dataType.properties,index)
}else{
onlyMessage(`方法定义inputs第${index+1}个数组dataType中缺失properties属性`,'error')
return true
}
}
}
export const testAliObject = (data:any,index:number)=>{
let check = false
data.forEach((i:any)=>{
if(!i?.identifier){
onlyMessage(`方法定义inputs第${index+1}个数组中缺失id属性`,'error')
check = true
return
}
if(!i?.name){
onlyMessage(`方法定义inputs第${index+1}个数组中缺失name属性`,'error')
check = true
return
}
if(!i?.dataType?.type){
onlyMessage(`方法定义inputs第${index+1}个数组中缺失dataType.type属性`,'error')
check = true
return
}else{
check = testAliType(i,index,false,true)
return
}
})
return check
}

View File

@ -59,7 +59,7 @@
max-height="350px" max-height="350px"
v-model:value="form.data.permissions" v-model:value="form.data.permissions"
:disabled="props.mode === '查看'" :disabled="props.mode === '查看'"
:key="form.data.id || ''" :btnId="form.data.id "
/> />
</j-form-item> </j-form-item>
<j-form-item label="说明" name="describe"> <j-form-item label="说明" name="describe">

View File

@ -50,7 +50,7 @@ import { Form } from 'jetlinks-ui-components';
Form.useInjectFormItemContext(); Form.useInjectFormItemContext();
const props = defineProps<{ const props = defineProps<{
key: string; btnId: string;
value: any[]; value: any[];
firstWidth: number; firstWidth: number;
maxHeight: string; maxHeight: string;
@ -77,17 +77,17 @@ const permission = reactive({
init: () => { init: () => {
permission.getList(); permission.getList();
watch( // watch(
() => props.key, // () => props.btnId,
() => { // () => {
nextTick(() => { // nextTick(() => {
permission.list = permission.makeList( // permission.list = permission.makeList(
props.value, // props.value,
permission.sourceList, // permission.sourceList,
); // );
}); // });
}, // },
); // );
}, },
// //
getList: () => { getList: () => {

View File

@ -31,7 +31,7 @@
<j-ellipsis :lineClamp="2">{{ variables }}</j-ellipsis> <j-ellipsis :lineClamp="2">{{ variables }}</j-ellipsis>
</div> </div>
</div> </div>
<div class="item"> <div class="item" v-if="isNoCommunity" >
<div class="label">用户权限</div> <div class="label">用户权限</div>
<div class="value"> <div class="value">
<j-ellipsis :lineClamp="2">{{ obj.role }}</j-ellipsis> <j-ellipsis :lineClamp="2">{{ obj.role }}</j-ellipsis>
@ -49,6 +49,7 @@ import ConfigApi from '@/api/notice/config';
import TemplateApi from '@/api/notice/template'; import TemplateApi from '@/api/notice/template';
import { queryConfigVariables } from '@/api/system/noticeRule'; import { queryConfigVariables } from '@/api/system/noticeRule';
import { getRoleList_api } from '@/api/system/user'; import { getRoleList_api } from '@/api/system/user';
import { isNoCommunity } from "@/utils/utils";
const props = defineProps({ const props = defineProps({
data: { data: {

View File

@ -60,14 +60,14 @@
ref="variableRef" ref="variableRef"
/> />
</template> </template>
<template v-if="current === 4"> <template v-if="current === 4 && isNoCommunity ">
<div class="alert"> <div class="alert">
<AIcon type="InfoCircleOutlined" /> <AIcon type="InfoCircleOutlined" />
通过角色控制哪些用户可以订阅从{{ name }}接收到{{ showName }}通知 通过角色控制哪些用户可以订阅从{{ name }}接收到{{ showName }}通知
</div> </div>
<Role type="add" v-model="formModel.grant.role.idList" /> <Role type="add" v-model="formModel.grant.role.idList" />
</template> </template>
<template v-if="current === 5"> <template v-if="current === 5 || current === 4 && !isNoCommunity">
<div> <div>
<div class="alert"> <div class="alert">
<AIcon type="InfoCircleOutlined" /> <AIcon type="InfoCircleOutlined" />
@ -134,6 +134,7 @@ import { onlyMessage } from '@/utils/comm';
import Template from '@/api/notice/template'; import Template from '@/api/notice/template';
import { variableMap } from '../../data'; import { variableMap } from '../../data';
import { cloneDeep } from 'lodash-es'; import { cloneDeep } from 'lodash-es';
import { isNoCommunity } from "@/utils/utils";
type GrantType = { type GrantType = {
role: { role: {
@ -169,14 +170,20 @@ const props = defineProps({
}, },
}); });
const stepList = [ const stepList = isNoCommunity ? [
'选择通知方式', '选择通知方式',
'选择通知配置', '选择通知配置',
'选择通知模板', '选择通知模板',
'配置模板变量', '配置模板变量',
'配置用户权限', '配置用户权限',
'完成', '完成',
]; ] : [
'选择通知方式',
'选择通知配置',
'选择通知模板',
'配置模板变量',
'完成',
]
const current = ref<number>(0); const current = ref<number>(0);
const variable = ref([]); const variable = ref([]);
const formModel = reactive<{ const formModel = reactive<{

View File

@ -52,12 +52,6 @@
requestBody.pageSize, requestBody.pageSize,
'value', 'value',
]" ]"
:rules="[
{
required: true,
message: '该字段是必填字段',
},
]"
> >
<j-input <j-input
v-model:value="record.value" v-model:value="record.value"
@ -230,16 +224,22 @@ const _send = () => {
}; };
let url = props.selectApi?.url; let url = props.selectApi?.url;
const urlParams = {}; let params
requestBody.params.paramsTable.forEach((item) => { if (methodName === 'get'){
if (methodName === 'get') urlParams[item.name] = item.value; const urlParams = {};
requestBody.params.paramsTable.forEach((item) => {
urlParams[item.name] = item.value;
if (url.includes(`{${item.name}}`)) if (url.includes(`{${item.name}}`))
url = url.replace(`{${item.name}}`, item.value); url = url.replace(`{${item.name}}`, item.value);
}); });
const params = { params = {
...JSON.parse(requestBody.code || '{}'), ...JSON.parse(requestBody.code || '{}'),
...urlParams, ...urlParams,
}; };
}else{
params = JSON.parse(requestBody.code || '{}')
}
server[methodObj[methodName]](url, params).then((resp: any) => { server[methodObj[methodName]](url, params).then((resp: any) => {
// body // body
if (Object.keys(params).length === 0 && refStr.value) { if (Object.keys(params).length === 0 && refStr.value) {

View File

@ -93,6 +93,7 @@ const rowSelection = {
// } // }
// }, // },
onChange: (keys: string[], _data: any[]) => { onChange: (keys: string[], _data: any[]) => {
console.log(keys,'keys')
const _keys = _data.map(i => i.id) const _keys = _data.map(i => i.id)
// id // id
const currenTableKeys = _tableData.value.map((m: any) => m.id); const currenTableKeys = _tableData.value.map((m: any) => m.id);
@ -113,17 +114,18 @@ const rowSelection = {
emits('update:selectedRowKeys', [...otherSelectedKeys, ..._keys]); emits('update:selectedRowKeys', [...otherSelectedKeys, ..._keys]);
// / // /
const changed = {}; // const changed = {};
[...addKeys, ...removeKeys].forEach((key: string) => { // [...addKeys, ...removeKeys].forEach((key: string) => {
changed[key] = _tableData.value.find((f: any) => f.id === key); // changed[key] = _tableData.value.find((f: any) => f.id === key);
}); // });
if (props.mode === 'appManger') { // console.log(department.changedApis,'123')
// // if (props.mode === 'appManger') {
emits('update:changedApis', { // //
...department.changedApis, // emits('update:changedApis', {
...changed, // ...department.changedApis,
}); // ...changed,
} // });
// }
}, },
selectedRowKeys: ref<string[]>([]), selectedRowKeys: ref<string[]>([]),
}; };
@ -133,7 +135,6 @@ const save = async () => {
const removeKeys = props.sourceKeys.filter((key) => !keys.includes(key)); const removeKeys = props.sourceKeys.filter((key) => !keys.includes(key));
// key // key
const addKeys = keys.filter((key) => !props.sourceKeys.includes(key)); const addKeys = keys.filter((key) => !props.sourceKeys.includes(key));
if (props.mode === 'api') { if (props.mode === 'api') {
// api // api
// removeKeys.length && // removeKeys.length &&
@ -156,23 +157,33 @@ const save = async () => {
return return
} }
} else if (props.mode === 'appManger') { } else if (props.mode === 'appManger') {
const removeItems = removeKeys.map((key) => ({ const items = props.selectedRowKeys.map((key)=>({
id: key, id: key,
permissions: props.changedApis[key]?.security?props.changedApis[key]?.security:[], permissions: department.changedApis[key]?.security ? department.changedApis[key]?.security : []
})); }))
const addItems = addKeys.map((key) => ({ // const removeItems = removeKeys.map((key) => ({
id: key, // id: key,
permissions: props.changedApis[key]?.security?props.changedApis[key]?.security:[], // permissions: props.changedApis[key]?.security ? props.changedApis[key]?.security:[],
})); // }));
Promise.all([ // const addItems = addKeys.map((key) => ({
updateOperations_api(code, '_delete', { operations: removeItems }), // id: key,
updateOperations_api(code, '_add', { operations: addItems }), // permissions: props.changedApis[key]?.security ? props.changedApis[key]?.security:[],
]).then((resps) => { // }));
if (resps[0].status === 200 && resps[1].status === 200) { // Promise.all([
// updateOperations_api(code, '_delete', { operations: removeItems }),
// updateOperations_api(code, '_add', { operations: addItems }),
// ]).then((resps) => {
// if (resps[0].status === 200 && resps[1].status === 200) {
// onlyMessage('');
// emits('refresh');
// }
// });
updateOperations_api(code,{operations:items}).then((resp)=>{
if(resp.status === 200){
onlyMessage('操作成功'); onlyMessage('操作成功');
emits('refresh'); emits('refresh')
} }
}); })
} }
}; };

View File

@ -28,7 +28,9 @@ import {
getTreeTwo_api, getTreeTwo_api,
} from '@/api/system/apiPage'; } from '@/api/system/apiPage';
import type { modeType, treeNodeTpye } from '../typing'; import type { modeType, treeNodeTpye } from '../typing';
import { useDepartmentStore } from '@/store/department';
const department = useDepartmentStore();
const emits = defineEmits(['select']); const emits = defineEmits(['select']);
const props = defineProps<{ const props = defineProps<{
mode: modeType; mode: modeType;
@ -78,12 +80,41 @@ const getTreeData = () => {
} }
treeData.value = tree; treeData.value = tree;
const apis = {}
const table: any = dealTreeData(tree)
table.forEach((item:any)=>{
apis[item.id] = item
})
department.setChangedApis(apis);
}) })
.finally(() => { .finally(() => {
spinning.value = false; spinning.value = false;
}); });
}); });
}; };
const dealTreeData = (tree:Array<any>) =>{
let table:any = []
tree.forEach((item)=>{
if(item?.children){
item?.children.forEach(i=>{
i?.apiList?.forEach((apiItem:any)=>{
const { method, url } = apiItem as any;
for (const key in method) {
if (Object.prototype.hasOwnProperty.call(method, key)) {
table.push({
...method[key],
url,
method: key,
id: method[key].operationId,
});
}
}
})
})
}
})
return table
}
const clickSelectItem: TreeProps['onSelect'] = (key: any[], node: any) => { const clickSelectItem: TreeProps['onSelect'] = (key: any[], node: any) => {
if (key[0] === 'home') return emits('select', node.node.dataRef, {}); if (key[0] === 'home') return emits('select', node.node.dataRef, {});

View File

@ -97,6 +97,7 @@ export default defineConfig(({ mode}) => {
// target: 'http://192.168.32.163:8844', //张季本地 // target: 'http://192.168.32.163:8844', //张季本地
// target: 'http://120.77.179.54:8844', // 120测试 // target: 'http://120.77.179.54:8844', // 120测试
target: 'http://192.168.33.46:8844', // 本地开发环境 target: 'http://192.168.33.46:8844', // 本地开发环境
// target: 'http://192.168.33.1:8845', // 社区版开发环境
// target: 'http://192.168.32.5:8848', // 刘本地 // target: 'http://192.168.32.5:8848', // 刘本地
ws: 'ws://192.168.33.46:8844', ws: 'ws://192.168.33.46:8844',
changeOrigin: true, changeOrigin: true,