feat: 应用管理和物模型映射2.1

This commit is contained in:
100011797 2023-06-13 09:40:36 +08:00
parent 299f624658
commit c8751bb8ad
16 changed files with 469 additions and 219 deletions

View File

@ -25,7 +25,7 @@
"event-source-polyfill": "^1.0.31",
"global": "^4.4.0",
"jetlinks-store": "^0.0.3",
"jetlinks-ui-components": "^1.0.22",
"jetlinks-ui-components": "^1.0.23",
"js-cookie": "^3.0.1",
"less": "^4.1.3",
"less-loader": "^11.1.0",

View File

@ -576,14 +576,16 @@ export const getDeviceNumber = (data?:any) => server.post<number>('/device-insta
/**
*
* @param productId
* @param data
* @param data/
*/
export const importDeviceByPlugin = (productId: string, data: any[]) => server.post(`/device/instance/plugin/${productId}/import`, data)
export const metadateMapById = (productId: string, data: ant[]) => server.patch(`/device/metadata/mapping/product/${productId}`, data)
export const metadateMapById = (type: 'device' | 'product', productId: string, data: any[]) => server.patch(`/device/metadata/mapping/${type}/${productId}`, data)
export const getMetadateMapById = (productId: string) => server.get(`/device/metadata/mapping/product/${productId}`)
export const getMetadateMapById = (type: 'device' | 'product', productId: string) => server.get(`/device/metadata/mapping/${type}/${productId}`)
export const getInkingDevices = (data: string[]) => server.post('/plugin/mapping/device/_all', data)
export const getProtocolMetadata = (id: string, transport: string) => server.get(`/protocol/${id}/${transport}/metadata`)

View File

@ -8,7 +8,7 @@ export const changeApplyStatus_api = (id: string, data: any) => server.put(`/app
// 删除应用
export const delApply_api = (id: string) => server.remove(`/application/${id}`)
export const queryType = () => server.get(`/application/providers`)
// 获取组织列表
export const getDepartmentList_api = (params: any) => server.get(`/organization/_all/tree`, params);

View File

@ -0,0 +1,3 @@
import Index from './index.vue'
export default Index

View File

@ -0,0 +1,240 @@
<template>
<div class='metadata-map'>
<div class='left'>
<j-input-search
style='width: 350px;margin-bottom:24px;'
placeholder='搜索平台属性名称'
allowClear
@search='search'
/>
<j-table
:columns="columns"
:data-source="dataSource"
:pagination='false'
:rowSelection='{
selectedRowKeys: selectedKeys,
hideSelectAll: true,
columnWidth: 0
}'
rowKey='id'
>
<template #bodyCell="{ column, text, record, index }">
<template v-if='column.dataIndex === "name"'>
<span class='metadata-title'>
<j-ellipsis>
{{ text }} ({{ record.id }})
</j-ellipsis>
</span>
</template>
<template v-if='column.dataIndex === "plugin"'>
<j-select
v-model:value='record.plugin'
style='width: 100%'
allowClear
@change='(id) => pluginChange(record, id)'
>
<j-select-option
v-for='(item, index) in pluginOptions'
:key='index + "_" + item.id'
:value='item.value'
:disabled='selectedPluginKeys.includes(item.id)'
>{{ item.label }} ({{ item.id }})</j-select-option>
</j-select>
</template>
</template>
</j-table>
</div>
<div class='right'>
<j-scrollbar>
<div class='title'>
功能说明
</div>
<p>
该功能用于将{{'协议包'}}中的
<b>物模型属性标识</b>
<b>平台物模型属性标识</b>进行映射,当两方属性标识不一致时可在当前页面直接修改映射管理系统将以映射后的物模型属性进行数据处理
</p>
<p>
未完成映射的属性标识目标属性列数据为空代表该属性值来源以在平台配置的来源为准
</p>
<p>
数据条背景亮起代表<b>标识一致</b><b>已完成映射</b>的属性
</p>
<div class='title'>
功能图示
</div>
<div>
<img :src='getImage("/device/matadataMap.png")' />
</div>
</j-scrollbar>
</div>
</div>
</template>
<script setup lang='ts' name='MetadataMap'>
import { storeToRefs } from 'pinia'
import { detail as queryPluginAccessDetail } from '@/api/link/accessConfig'
// import { getPluginData, getProductByPluginId } from '@/api/link/plugin'
import { getImage, onlyMessage } from '@/utils/comm'
import { getMetadateMapById, metadateMapById, getProtocolMetadata } from '@/api/device/instance'
import { useInstanceStore } from '@/store/instance';
const deviceStore = useInstanceStore()
const { current: deviceDetail } = storeToRefs(deviceStore)
const dataSourceCache = ref([])
const dataSource = ref([])
const pluginOptions = ref<any[]>([])
const columns = [
{
title: '序号',
dataIndex: 'index',
width: 100
},
{
title: '平台属性',
dataIndex: 'name',
},
{
title: '目标属性',
dataIndex: 'plugin',
width: 250,
sorter: {
compare: (a, b) => (a.plugin?.length || 0) - (b.plugin?.length || 0)
}
}
]
const selectedKeys = computed(() => {
return dataSource.value?.filter((item: any) => !!item?.plugin).map((i: any) => i.id) || []
})
const selectedPluginKeys = computed(() => {
return dataSource.value?.filter((item: any) => !!item?.plugin).map((i: any) => i.plugin) || []
})
const metadata = computed(() => {
return JSON.parse(deviceDetail.value?.metadata || '{}')
})
const _id = deviceDetail.value?.id
const getMetadataMapData = () => {
return new Promise(resolve => {
getMetadateMapById('device', _id).then((res: any) => {
if (res.success) {
resolve(res.result?.filter((i: any) => i.customMapping)?.map((item: any) => {
return {
id: item.metadataId,
pluginId: item.originalId
}
}) || [])
}
})
})
}
const search = (value: string) => {
if (value) {
dataSource.value = dataSourceCache.value.filter((item: any) => {
return !!item.name?.includes(value)
})
} else {
dataSource.value = dataSourceCache.value
}
}
const getDefaultMetadata = async () => {
const properties = metadata.value?.properties
const pluginMedata = await getPluginMetadata()
const pluginProperties = pluginMedata?.properties || []
const metadataMap = await getMetadataMapData()
pluginOptions.value = pluginProperties.map(item => ({...item, label: item.name, value: item.id}))
const concatProperties = [ ...pluginProperties.map(item => ({ id: item.id, pluginId: item.id})), ...metadataMap]
dataSource.value = properties?.map((item: any, index: number) => {
const _m = concatProperties.find(p => p.id === item.id)
return {
index: index + 1,
id: item.id, // id
name: item.name,
type: item.valueType?.type,
plugin: _m?.pluginId, // id
}
}) || []
dataSourceCache.value = dataSource.value
}
const getPluginMetadata = (): Promise<{ properties: any[]}> => {
return new Promise(resolve => {
const transport = deviceDetail.value?.transport
getProtocolMetadata(deviceDetail.value?.protocol || '', transport).then((res: any) => {
if(res.success){
resolve(JSON.parse(res?.result || '{}'))
}
resolve({ properties: [] })
})
})
}
const pluginChange = async (value: any, id: string) => {
const res = await metadateMapById('device', _id, [{
metadataType: 'property',
metadataId: value.id,
originalId: id || null
}])
if (res.success) {
onlyMessage('操作成功')
}
}
getDefaultMetadata()
</script>
<style scoped lang='less'>
.metadata-map {
// position: relative;
min-height: 100%;
display: flex;
gap: 24px;
.left {
// margin-right: 44px;
flex: 1;
}
.right {
// position: absolute;
border: 1px solid rgba(0, 0, 0, 0.08);
min-height: 100%;
min-width: 410px;
width: 33.33333%;
// top: 0;
// right: 0;
padding: 16px;
.title {
margin-bottom: 16px;
color: rgba(#000, .85);
font-weight: bold;
p {
initial-letter: 28px;
color: #666666;
}
}
}
.metadata-title {
color: #666666;
}
:deep(.ant-table-selection-column) {
padding: 0;
label {
display: none;
}
}
}
</style>

View File

@ -10,7 +10,7 @@
/>
<j-tabs
tab-position="left"
style="height: 600px"
style="height: 500px"
v-if="tabList.length"
v-model:activeKey="activeKey"
:tabBarStyle="{ width: '200px' }"
@ -120,7 +120,10 @@ const tabChange = (key: string) => {
min-height: 100%;
.property-box-left {
width: 200px;
min-height: 100%;
// :deep(.jet-tabs) {
// height: 100%;
// }
}
.property-box-right {
flex: 1;

View File

@ -114,6 +114,7 @@ import { useInstanceStore } from '@/store/instance';
import Info from './Info/index.vue';
import Running from './Running/index.vue';
import Metadata from '../../components/Metadata/index.vue';
import MetadataMap from './MetadataMap/index.vue';
import ChildDevice from './ChildDevice/index.vue';
import Diagnose from './Diagnose/index.vue';
import Function from './Function/index.vue';
@ -179,6 +180,7 @@ const tabs = {
EdgeMap,
Parsing,
Log,
MetadataMap
};
const getStatus = (id: string) => {
@ -254,6 +256,15 @@ const getDetail = () => {
tab: '边缘端映射',
});
}
if (
instanceStore.current?.features?.find(
(item: any) => item?.id === 'diffMetadataSameProduct',
) &&
!keys.includes('MetadataMap')
) {
list.value.push({ key: 'MetadataMap', tab: '物模型映射'});
}
};
const initPage = async (newId: any) => {

View File

@ -118,7 +118,7 @@ const selectedPluginKeys = computed(() => {
const getMetadataMapData = () => {
return new Promise(resolve => {
getMetadateMapById(productDetail.value?.id).then(res => {
getMetadateMapById('product', productDetail.value?.id).then(res => {
if (res.success) {
resolve(res.result?.filter(item => item.customMapping)?.map(item => {
return {
@ -168,7 +168,7 @@ const getPluginMetadata = (): Promise<{ properties: any[]}> => {
queryPluginAccessDetail(productDetail.value?.accessId!).then(async res => {
if (res.success) {
const _channelId = (res.result as any)!.channelId
const pluginRes = await getPluginData('product', productDetail.value?.accessId, productDetail.value?.id).catch(() => ({ success: false, result: {}}))
const pluginRes = await getPluginData('product', productDetail.value?.accessId || '', productDetail.value?.id).catch(() => ({ success: false, result: {}}))
const resp = await getProductByPluginId(_channelId).catch(() => ({ success: false, result: []}))
if (resp.success) {
const _item = (resp.result as any[])?.find((item: any) => item.id === (pluginRes?.result as any)?.externalId)
@ -182,7 +182,7 @@ const getPluginMetadata = (): Promise<{ properties: any[]}> => {
}
const pluginChange = async (value: any, id: string) => {
const res = await metadateMapById(productDetail.value?.id, [{
const res = await metadateMapById('product', productDetail.value?.id, [{
metadataType: 'property',
metadataId: value.id,
originalId: id

View File

@ -5,20 +5,21 @@
width="700px"
@ok="confirm"
@cancel="emits('update:visible', false)"
:filter-option="filterOption"
:maskClosable="false"
class="access-method-dialog-container"
>
<j-form :model="form" name="basic" autocomplete="off" layout="vertical">
<j-form :model="form" ref="formRef" layout="vertical">
<j-form-item
label="产品"
name="productId"
:rules="[{ required: true, message: '该字段是必填字段' }]"
:rules="[{ required: true, message: '请选择产品' }]"
>
<j-select
v-model:value="form.productId"
style="width: 100%"
show-search
:options="productList"
placeholder="请选择产品"
>
</j-select>
</j-form-item>
@ -35,13 +36,10 @@ const props = defineProps<{
visible: boolean;
}>();
const confirm = () => {
emits('confirm', form.value.productId);
emits('update:visible', false);
};
const formRef = ref<any>()
const form = ref({
productId: '',
const form = reactive({
productId: undefined,
});
const productList = ref<[productItem] | []>([]);
@ -56,10 +54,14 @@ const getOptions = () => {
});
};
const filterOption = (input: string, option: any) => {
return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
getOptions();
const confirm = () => {
formRef.value?.validate().then(() => {
emits('confirm', form.productId);
emits('update:visible', false);
})
};
</script>
<style lang="less" scoped>

View File

@ -41,7 +41,17 @@
<j-form-item name="basePath" v-bind="validateInfos.basePath">
<template #label>
<span>base-path</span>
<j-tooltip title="系统后台访问的url">
<j-tooltip>
<template #title>
<div style='word-break: break-all;'>
<div>
系统后台访问的url
</div>
<div>
格式{http/https}: //{IP}:{}/api
</div>
</div>
</template>
<img
class="img-style"
:src="getImage('/init-home/mark.png')"
@ -50,7 +60,7 @@
</template>
<j-input
v-model:value="form.basePath"
placeholder="请输入base-path"
placeholder="格式:{http/https}: //{前端所在服务器IP地址}:{前端暴露的服务端口}/api"
/>
</j-form-item>
<j-row :gutter="24" :span="24">
@ -253,13 +263,12 @@
</template>
<script setup lang="ts">
import { modalState, formState, logoState } from '../data/interface';
import { getImage } from '@/utils/comm.ts';
import { Form, message } from 'jetlinks-ui-components';
import { FILE_UPLOAD } from '@/api/comm';
import {
save,
} from '@/api/initHome';
import { LocalStore } from '@/utils/comm';
import { LocalStore, getImage } from '@/utils/comm';
import { TOKEN_KEY } from '@/utils/variable';
import { SystemConst } from '@/utils/consts';
const formRef = ref();

View File

@ -6,14 +6,14 @@
@change="onChange"
>
<j-radio-button
v-for="item in list"
v-for="item in options"
:value="item.value"
:key="item.value"
>
<div class="radio-container-item" @click.stop>
<div>
<MUpload
:defaultValue="item.imgUrl"
:defaultValue="defaultImg[item.value]"
:borderStyle="{
width: '90px',
height: '90px',
@ -25,7 +25,7 @@
@change="(_url) => onImgChange(_url, item.value)"
/>
</div>
<span>{{ item.text }}</span>
<span>{{ item.label }}</span>
</div>
</j-radio-button>
</j-radio-group>
@ -33,6 +33,7 @@
<script lang="ts" setup>
import { getImage } from '@/utils/comm';
import { PropType } from 'vue';
import MUpload from './MUpload.vue';
const props = defineProps({
@ -48,50 +49,24 @@ const props = defineProps({
type: String,
default: getImage('/apply/provider1.png'),
},
options: {
type: Array as PropType<any[]>,
default: () => []
}
});
const emit = defineEmits(['update:value', 'update:photoUrl']);
const list = [
{
value: 'internal-standalone',
text: '内部独立应用',
imgUrl: getImage('/apply/provider1.png'),
},
{
value: 'internal-integrated',
text: '内部集成应用',
imgUrl: getImage('/apply/provider2.png'),
},
{
value: 'wechat-webapp',
text: '微信网站应用',
imgUrl: getImage('/apply/provider4.png'),
},
{
value: 'dingtalk-ent-app',
text: '钉钉企业内部应用',
imgUrl: getImage('/apply/provider3.png'),
},
{
value: 'third-party',
text: '第三方应用',
imgUrl: getImage('/apply/provider5.png'),
},
{
value: 'wechat-miniapp',
text: '小程序应用',
imgUrl: getImage('/apply/provider1.png'),
},
];
const urlValue = ref({
const defaultImg = {
'internal-standalone': getImage('/apply/provider1.png'),
'internal-integrated': getImage('/apply/provider2.png'),
'wechat-webapp': getImage('/apply/provider4.png'),
'dingtalk-ent-app': getImage('/apply/provider3.png'),
'third-party': getImage('/apply/provider5.png'),
'wechat-miniapp': getImage('/apply/provider1.png'),
});
}
const urlValue = ref<any>({...defaultImg});
const _value = ref<string>('');
watchEffect(() => {

View File

@ -36,7 +36,7 @@
},
]"
>
<ApplyList v-model:photoUrl="form.data.logoUrl" v-model:value="form.data.provider" :disabled="!!routeQuery.id" />
<ApplyList :options="typeOptions" v-model:photoUrl="form.data.logoUrl" v-model:value="form.data.provider" :disabled="!!routeQuery.id" />
</j-form-item>
<j-form-item
label="接入方式"
@ -1380,17 +1380,15 @@
<MenuDialog
v-if="dialog.visible"
v-model:visible="dialog.visible"
:id="dialog.selectId"
:provider="dialog.selectProvider"
:data="dialog.current"
:mode="routeQuery.id ? 'edit' : 'add'"
@refresh="menuStory.jumpPage('system/Apply')"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { BASE_API_PATH, TOKEN_KEY } from '@/utils/variable';
import { LocalStore, filterSelectNode, onlyMessage } from '@/utils/comm'
import { testIP } from '@/utils/validate';
import {
@ -1398,6 +1396,7 @@ import {
addApp_api,
updateApp_api,
getAppInfo_api,
queryType,
} from '@/api/system/apply';
import FormLabel from './FormLabel.vue';
import RequestTable from './RequestTable.vue';
@ -1405,11 +1404,6 @@ import MenuDialog from '../../componenets/MenuDialog.vue';
import { getImage } from '@/utils/comm';
import type { formType, dictType, optionsType } from '../typing';
import { getRoleList_api } from '@/api/system/user';
import {
FormInstance,
UploadChangeParam,
UploadFile,
} from 'ant-design-vue';
import { message } from 'jetlinks-ui-components'
import { randomString } from '@/utils/utils';
import { cloneDeep, difference } from 'lodash';
@ -1424,6 +1418,8 @@ const menuStory = useMenuStore();
const deptPermission = 'system/Department';
const rolePermission = 'system/Role';
const typeOptions = ref<any[]>([])
//
const initForm: formType = {
name: '',
@ -1436,6 +1432,7 @@ const initForm: formType = {
baseUrl: '',
routeType: 'hash',
parameters: [],
configuration: {}
},
apiClient: {
// API
@ -1509,7 +1506,7 @@ const initForm: formType = {
defaultPasswd: '', //
},
};
const formRef = ref<FormInstance>();
const formRef = ref<any>();
const form = reactive({
data: { ...initForm },
// integrationModesISO: [] as string[], // 使
@ -1541,77 +1538,32 @@ const paramsValidator = () => {
});
};
onMounted(() => {
queryType().then((resp: any) => {
if(resp.status === 200){
const arr = resp.result.map((item: any) => ({
label: item.name,
value: item.provider,
integrationModes: item.integrationModes?.map((i: any) => {
return {
label: i.text,
value: i.value
}
})
}))
typeOptions.value = arr
}
});
})
//
const joinOptions = computed(() => {
if (form.data.provider === 'internal-standalone')
return [
{
label: '页面集成',
value: 'page',
},
{
label: 'API客户端',
value: 'apiClient',
},
{
label: 'API服务',
value: 'apiServer',
},
{
label: '单点登录',
value: 'ssoClient',
},
];
else if (form.data.provider === 'internal-integrated')
return [
{
label: '页面集成',
value: 'page',
},
{
label: 'API客户端',
value: 'apiClient',
},
];
else if (form.data.provider === 'wechat-webapp' || form.data.provider === 'wechat-miniapp')
return [
{
label: '单点登录',
value: 'ssoClient',
},
];
else if (form.data.provider === 'dingtalk-ent-app')
return [
{
label: '单点登录',
value: 'ssoClient',
},
];
else if (form.data.provider === 'third-party')
return [
{
label: '页面集成',
value: 'page',
},
{
label: 'API客户端',
value: 'apiClient',
},
{
label: 'API服务',
value: 'apiServer',
},
{
label: '单点登录',
value: 'ssoClient',
},
];
return typeOptions.value.find(item => form.data?.provider === item.value)?.integrationModes || []
});
const dialog = reactive({
visible: false,
selectId: '',
selectProvider: '' as any,
current: {}
});
init();
@ -1810,9 +1762,10 @@ function clickSave() {
if (resp.status === 200) {
const isPage = params.integrationModes.includes('page');
if (isPage) {
// form.data = params;
dialog.selectId = routeQuery.id || resp.result.id;
dialog.selectProvider = form.data.provider;
dialog.current = {
...params,
id: routeQuery.id || resp.result.id
}
dialog.visible = true;
} else {
message.success('保存成功');

View File

@ -28,7 +28,8 @@ export type formType = {
page: { // 页面集成
baseUrl: string,
routeType: 'hash' | 'history',
parameters: optionsType
parameters: optionsType,
configuration: any
},
apiClient: { // API客户端
baseUrl: string, // 接口地址

View File

@ -10,13 +10,14 @@
>
<j-select
v-model:value="form.checkedSystem"
@change="(value:string) => value && getTree(value)"
@change="(value) => value && getTree(value)"
style="width: 200px"
placeholder="请选择集成系统"
>
<j-select-option
v-for="item in form.systemList"
:value="item.value"
:key="item.value"
>{{ item.label }}</j-select-option
>
</j-select>
@ -29,8 +30,9 @@
v-model:expandedKeys="form.expandedKeys"
checkable
:tree-data="form.menuTree"
:fieldNames="{ key: 'id', title: 'name' }"
:fieldNames="{ key: 'code', title: 'name' }"
@check="treeCheck"
:height="300"
>
<template #title="{ name }">
<span>{{ name }}</span>
@ -41,13 +43,13 @@
<script setup lang="ts">
import { optionItemType } from '@/views/system/DataSource/typing';
import { applyType } from '../Save/typing';
import {
getOwner_api,
getOwnerStandalone_api,
getOwnerTree_api,
getOwnerTreeStandalone_api,
saveOwnerMenu_api,
updateApp_api,
} from '@/api/system/apply';
import { CheckInfo } from 'ant-design-vue/lib/vc-tree/props';
import { useMenuStore } from '@/store/menu';
@ -55,31 +57,40 @@ import { message } from 'jetlinks-ui-components';
import { getMenuTree_api } from '@/api/system/menu';
const menuStory = useMenuStore();
const emits = defineEmits(['update:visible']);
const emits = defineEmits(['update:visible', 'refresh']);
const props = defineProps<{
mode: 'add' | 'edit';
visible: boolean;
id: string;
provider: applyType;
data: any;
}>();
//
const loading = ref(false);
const handleOk = () => {
const handleOk = async () => {
const items = filterTree(form.menuTree, [
...form.checkedMenu,
...form.half,
]);
console.log(items)
if (form.checkedSystem) {
if (items && items.length !== 0) {
loading.value = true;
saveOwnerMenu_api('iot', form.id, items)
.then((resp) => {
if (resp.status === 200) {
message.success('操作成功');
emits('update:visible', false);
const resp = await saveOwnerMenu_api('iot', form.id, items).finally(() => (loading.value = false));
await updateApp_api(form.id as string, {
...props.data,
integrationModes: props.data?.integrationModes?.map((item: any) => item?.value || item),
page: {
...props.data?.page,
configuration: {
checkedSystem: form.checkedSystem
}
})
.finally(() => (loading.value = false));
}
})
if (resp.status === 200) {
//
message.success('操作成功');
emits('update:visible', false);
emits('refresh')
}
} else {
message.warning('请勾选配置菜单');
}
@ -94,21 +105,16 @@ const cancel = () => {
};
const form = reactive({
id: props.id,
id: props.data?.id,
checkedSystem: undefined as undefined | string,
checkedMenu: [] as string[],
expandedKeys: [] as string[],
half: [] as string[],
provider: props.provider,
provider: props.data?.provider,
systemList: [] as optionItemType[],
menuTree: [] as any[],
});
if (props.id) {
getSystemList();
getMenus();
}
/**
* 与集成系统关联的菜单
* @param params
@ -120,26 +126,26 @@ function getTree(params: string) {
: getOwnerTree_api(params);
api.then((resp: any) => {
form.menuTree = resp.result;
form.expandedKeys = resp.result.map((item: any) => item.id);
form.expandedKeys = resp.result.map((item: any) => item?.code);
});
}
/**
* 获取当前用户可访问菜单
*/
function getMenus() {
function getMenus(id: string) {
const params = {
terms: [
{
column: 'appId',
value: form.id,
value: id,
},
],
};
getMenuTree_api(params).then((resp: any) => {
if (resp.status === 200) {
form.menuTree = resp.result;
const keys = resp.result.map((item: any) => item.id) as string[];
form.expandedKeys = keys;
// form.menuTree = resp.result;
const keys = resp.result.map((item: any) => item?.code) as string[];
// form.expandedKeys = keys;
form.checkedMenu = keys;
}
});
@ -147,10 +153,10 @@ function getMenus() {
/**
* 获取集成系统选项
*/
function getSystemList() {
function getSystemList(id: string) {
const api =
form.provider === 'internal-standalone'
? getOwnerStandalone_api(form.id, ['iot'])
? getOwnerStandalone_api(id, ['iot'])
: getOwner_api(['iot']);
api.then((resp: any) => {
@ -162,9 +168,23 @@ function getSystemList() {
}
});
}
watch(() => props.data, (newVal: any) => {
form.checkedSystem = newVal?.page.configuration?.checkedSystem
if(form.checkedSystem){
getTree(form.checkedSystem)
}
if(newVal?.id) {
getSystemList(newVal?.id);
getMenus(newVal?.id);
}
}, {
deep: true,
immediate: true
})
//
function treeCheck(checkedKeys: any, e: CheckInfo) {
form.checkedMenu = checkedKeys;
form.checkedMenu = checkedKeys
form.half = e.halfCheckedKeys as string[];
}
//-
@ -174,7 +194,7 @@ function filterTree(nodes: any[], list: any[]) {
}
return nodes.filter((it) => {
//
if (list.indexOf(it.id) <= -1) {
if (list.indexOf(it.code) <= -1) {
return false;
}
//

View File

@ -102,15 +102,18 @@
) in item.children"
:key="i"
>
<j-button
type="link"
@click="o.onClick"
>
<AIcon :type="o.icon" />
<span>{{
o.text
}}</span>
</j-button>
<j-tooltip :title="o?.tooltip?.title">
<j-button
type="link"
@click="o.onClick"
:disabled="o.disabled"
>
<AIcon :type="o.icon" />
<span>{{
o.text
}}</span>
</j-button>
</j-tooltip>
</j-menu-item>
</j-menu>
</template>
@ -165,6 +168,7 @@
)"
:hasPermission="i.permission"
type="link"
:key="i.key"
:tooltip="i.tooltip"
:pop-confirm="i.popConfirm"
@click="i.onClick"
@ -181,9 +185,9 @@
<MenuDialog
v-if="dialogVisible"
v-model:visible="dialogVisible"
:id="selectId"
:provider="selectProvider"
mode="edit"
:data="current"
@refresh="table.refresh"
/>
</div>
</page-container>
@ -196,8 +200,8 @@ import {
getApplyList_api,
changeApplyStatus_api,
delApply_api,
queryType
} from '@/api/system/apply';
import { ActionsType } from '@/components/Table';
import { getImage } from '@/utils/comm';
import { useMenuStore } from '@/store/menu';
import { message } from 'jetlinks-ui-components';
@ -205,32 +209,46 @@ import BadgeStatus from '@/components/BadgeStatus/index.vue';
const menuStory = useMenuStore();
const permission = 'system/Apply';
const typeOptions = [
{
label: '内部独立应用',
value: 'internal-standalone',
},
{
label: '微信网站应用',
value: 'wechat-webapp',
},
{
label: '内部集成应用',
value: 'internal-integrated',
},
{
label: '钉钉企业内部应用',
value: 'dingtalk-ent-app',
},
{
label: '第三方应用',
value: 'third-party',
},
{
label: '小程序应用',
value: 'wechat-miniapp',
},
];
// const typeOptions = [
// {
// label: '',
// value: 'internal-standalone',
// },
// {
// label: '',
// value: 'wechat-webapp',
// },
// {
// label: '',
// value: 'internal-integrated',
// },
// {
// label: '',
// value: 'dingtalk-ent-app',
// },
// {
// label: '',
// value: 'third-party',
// },
// {
// label: '',
// value: 'wechat-miniapp',
// },
// ];
const typeOptions = ref<any[]>([])
onMounted(() => {
queryType().then((resp: any) => {
if(resp.status === 200){
const arr = resp.result.map((item: any) => ({
label: item.name,
value: item.provider,
}))
typeOptions.value = arr
}
});
})
const columns = [
{
title: '名称',
@ -247,10 +265,20 @@ const columns = [
dataIndex: 'provider',
key: 'provider',
ellipsis: true,
fixed: 'left',
search: {
type: 'select',
options: typeOptions,
// options: () =>
// new Promise((resolve) => {
// queryType().then((resp: any) => {
// resolve(
// resp.result.map((item: any) => ({
// label: item.name,
// value: item.provider,
// })),
// );
// });
// }),
},
scopedSlots: true,
},
@ -296,6 +324,7 @@ const columns = [
const queryParams = ref({});
const tableRef = ref();
const current = ref<any>({})
const table = {
refresh: () => {
tableRef.value.reload(queryParams.value);
@ -383,12 +412,14 @@ const table = {
key: 'page',
text: '集成菜单',
tooltip: {
title: '集成菜单',
title: !disabled ? '请先启用' : '集成菜单',
},
icon: 'MenuUnfoldOutlined',
disabled: !disabled,
onClick: () => {
selectId.value = data.id;
selectProvider.value = data.provider;
current.value = data
dialogVisible.value = true;
},
});
@ -441,7 +472,7 @@ const table = {
},
getTypeLabel: (val: string) => {
if (!val) return '';
return typeOptions.find((item) => item.value === val)?.label;
return typeOptions.value?.find((item) => item?.value === val)?.label;
},
};
const dialogVisible = ref(false);

View File

@ -3823,10 +3823,10 @@ jetlinks-store@^0.0.3:
resolved "https://registry.npmjs.org/jetlinks-store/-/jetlinks-store-0.0.3.tgz"
integrity sha512-AZf/soh1hmmwjBZ00fr1emuMEydeReaI6IBTGByQYhTmK1Zd5pQAxC7WLek2snRAn/HHDgJfVz2hjditKThl6Q==
jetlinks-ui-components@^1.0.22:
version "1.0.22"
resolved "https://registry.jetlinks.cn/jetlinks-ui-components/-/jetlinks-ui-components-1.0.22.tgz#1b7c3d632b5c1b55a4ce59fb010c48edb402c657"
integrity sha512-U19VTSmxCgz1ybNY3QhPRaTM9CVvq1nYJOMc+Y8rc2FnzQ9B7k1Xk/fmJZvdt7lqlcDL3xO0zXkIVdAdapG3GA==
jetlinks-ui-components@^1.0.23:
version "1.0.23"
resolved "https://registry.jetlinks.cn/jetlinks-ui-components/-/jetlinks-ui-components-1.0.23.tgz#029f45a61316e3bf3b4c75959d41d7d76068fcbe"
integrity sha512-6OGDn8/kAmjlHMoeIp5B4L6EeucbqKFxqnYys4MqmtEvco/d5Pr8rzmJEav6bZmGkN21YWNHpwkhX3yrQt2F+g==
dependencies:
"@vueuse/core" "^9.12.0"
"@vueuse/router" "^9.13.0"