fix: 修改bug
This commit is contained in:
parent
6651e75930
commit
be0aeb9a0a
|
@ -35,10 +35,11 @@
|
||||||
<div class='info-body'>
|
<div class='info-body'>
|
||||||
<img
|
<img
|
||||||
:src="
|
:src="
|
||||||
iconMap.get(
|
bindUser?.avatar ||
|
||||||
bindUser?.applicationProvider,
|
iconMap.get(
|
||||||
) || getImage('/apply/internal-standalone.png')
|
bindUser?.applicationProvider,
|
||||||
"
|
) || getImage('/apply/internal-standalone.png')
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
<p>账号:{{ bindUser?.result?.userId || '-' }}</p>
|
<p>账号:{{ bindUser?.result?.userId || '-' }}</p>
|
||||||
<p>用户名:{{ bindUser?.result?.name || '-' }}</p>
|
<p>用户名:{{ bindUser?.result?.name || '-' }}</p>
|
||||||
|
@ -62,7 +63,7 @@
|
||||||
:src="getImage('/bind/Vector.png')"
|
:src="getImage('/bind/Vector.png')"
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
:src='iconMap.get(bindUser?.applicationProvider)'
|
:src='bindUser?.avatar || iconMap.get(bindUser?.applicationProvider)'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class='desc'>
|
<div class='desc'>
|
||||||
|
|
|
@ -128,10 +128,13 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-item-right {
|
.content-item-right {
|
||||||
button:hover {
|
:deep(button) {
|
||||||
background-color: @primary-color;
|
&:hover {
|
||||||
color: #fff;
|
background-color: @primary-color;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
<template>
|
||||||
|
<ResizeObserver @resize="onResize">
|
||||||
|
<div class="tag-box" ref="box">
|
||||||
|
<div v-for="(item, i) in value" :key="item.id" ref="tags">
|
||||||
|
<div v-if="i != _index" class="tag">
|
||||||
|
{{ item.name }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="tag-ellipsis"
|
||||||
|
:style="
|
||||||
|
i === _index
|
||||||
|
? {
|
||||||
|
width: `${offWidth}px`,
|
||||||
|
}
|
||||||
|
: {}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ item.name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ResizeObserver>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { default as ResizeObserver } from 'ant-design-vue/lib/vc-resize-observer';
|
||||||
|
const props = defineProps({
|
||||||
|
value: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const tags = ref<any>([]);
|
||||||
|
const box = ref<any>(null);
|
||||||
|
const _index = ref<number>(-1);
|
||||||
|
const offWidth = ref<number>(0);
|
||||||
|
|
||||||
|
const onResize = ({ width }: { width: number }) => {
|
||||||
|
let total = 0;
|
||||||
|
for (let i = 0; i < tags.value.length; i++) {
|
||||||
|
const item = tags.value[i];
|
||||||
|
total += item?.scrollWidth || 0;
|
||||||
|
const val = item?.offsetWidth - (total - width);
|
||||||
|
if (total >= width) {
|
||||||
|
_index.value = i;
|
||||||
|
offWidth.value = val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.tag-box {
|
||||||
|
margin-top: 15px;
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
background-color: #f7f8fa;
|
||||||
|
border-radius: 32px;
|
||||||
|
margin-right: 8px;
|
||||||
|
padding: 0 14px;
|
||||||
|
color: #333333;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.tag-ellipsis {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
background-color: #f7f8fa;
|
||||||
|
border-radius: 32px;
|
||||||
|
margin-right: 8px;
|
||||||
|
padding: 0 14px;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -16,25 +16,12 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="person-header-item-info-right">
|
<div class="person-header-item-info-right">
|
||||||
<div class="person-header-item-info-right-top">
|
<div class="person-header-item-info-right-top">
|
||||||
Hi, {{ user.userInfos?.name }}
|
<j-ellipsis>
|
||||||
|
Hi, {{ user.userInfos?.name }}
|
||||||
|
</j-ellipsis>
|
||||||
</div>
|
</div>
|
||||||
<div class="person-header-item-info-right-info">
|
<div class="person-header-item-info-right-info">
|
||||||
<!-- <div class="tag-box">
|
<RoleShow :value="user.userInfos?.roleList || []" />
|
||||||
<div
|
|
||||||
v-for="i in user.userInfos?.orgList || []"
|
|
||||||
:key="i?.id"
|
|
||||||
class="tag"
|
|
||||||
>{{ i?.name }}</div
|
|
||||||
>
|
|
||||||
</div> -->
|
|
||||||
<div class="tag-box">
|
|
||||||
<div
|
|
||||||
v-for="i in user.userInfos?.roleList || []"
|
|
||||||
:key="i?.id"
|
|
||||||
class="tag"
|
|
||||||
><j-ellipsis>{{ i?.name }}</j-ellipsis></div
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -105,6 +92,7 @@ import {
|
||||||
USER_CENTER_MENU_CODE,
|
USER_CENTER_MENU_CODE,
|
||||||
} from '@/utils/consts';
|
} from '@/utils/consts';
|
||||||
import { usePermissionStore } from '@/store/permission';
|
import { usePermissionStore } from '@/store/permission';
|
||||||
|
import RoleShow from './components/RoleShow/index.vue';
|
||||||
|
|
||||||
const imageTypes = reactive([
|
const imageTypes = reactive([
|
||||||
'image/jpeg',
|
'image/jpeg',
|
||||||
|
@ -204,6 +192,7 @@ onUnmounted(() => {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
.person-header-item-info {
|
.person-header-item-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
width: calc(100% - 380px);
|
||||||
.person-header-item-info-left {
|
.person-header-item-info-left {
|
||||||
margin-right: 30px;
|
margin-right: 30px;
|
||||||
}
|
}
|
||||||
|
@ -211,25 +200,16 @@ onUnmounted(() => {
|
||||||
.person-header-item-info-right {
|
.person-header-item-info-right {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
width: calc(100% - 126px);
|
||||||
.person-header-item-info-right-top {
|
.person-header-item-info-right-top {
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: 26px;
|
font-size: 26px;
|
||||||
color: #1d2129;
|
color: #1d2129;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
.person-header-item-info-right-info {
|
.person-header-item-info-right-info {
|
||||||
.tag-box {
|
width: 100%;
|
||||||
margin-top: 15px;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
.tag {
|
|
||||||
background-color: #F7F8FA;
|
|
||||||
border-radius: 32px;
|
|
||||||
margin-right: 8px;
|
|
||||||
padding: 0 14px;
|
|
||||||
color: #333333;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,94 +7,103 @@
|
||||||
allowClear
|
allowClear
|
||||||
@search="search"
|
@search="search"
|
||||||
/>
|
/>
|
||||||
<j-table
|
<div class="box">
|
||||||
:columns="columns"
|
<j-scrollbar height="100%">
|
||||||
:data-source="dataSource"
|
<j-table
|
||||||
:pagination="false"
|
:columns="columns"
|
||||||
:rowSelection="{
|
:data-source="dataSource"
|
||||||
selectedRowKeys: selectedKeys,
|
:pagination="false"
|
||||||
hideSelectAll: true,
|
:rowSelection="{
|
||||||
columnWidth: 0,
|
selectedRowKeys: selectedKeys,
|
||||||
}"
|
hideSelectAll: true,
|
||||||
rowKey="id"
|
columnWidth: 0,
|
||||||
>
|
}"
|
||||||
<template #headerCell="{ column }">
|
rowKey="id"
|
||||||
<template v-if="column.dataIndex === 'original'">
|
:customRow="customRow"
|
||||||
<div
|
>
|
||||||
style="
|
<template #headerCell="{ column }">
|
||||||
width: 100%;
|
<template v-if="column.dataIndex === 'original'">
|
||||||
display: flex;
|
<div
|
||||||
justify-content: space-between;
|
style="
|
||||||
align-items: center;
|
width: 100%;
|
||||||
"
|
display: flex;
|
||||||
>
|
justify-content: space-between;
|
||||||
<span>
|
align-items: center;
|
||||||
目标属性<j-tooltip
|
"
|
||||||
title="协议包中物模型下的属性"
|
|
||||||
>
|
>
|
||||||
<AIcon
|
<span>
|
||||||
style="margin-left: 10px"
|
目标属性<j-tooltip
|
||||||
type="QuestionCircleOutlined"
|
title="协议包中物模型下的属性"
|
||||||
/>
|
|
||||||
</j-tooltip>
|
|
||||||
</span>
|
|
||||||
<j-tag
|
|
||||||
v-if="filterValue !== undefined"
|
|
||||||
color="#87d068"
|
|
||||||
closable
|
|
||||||
@close="onClose"
|
|
||||||
><AIcon type="ArrowUpOutlined" /><span>{{
|
|
||||||
filterValue ? '已映射' : '未映射'
|
|
||||||
}}</span></j-tag
|
|
||||||
>
|
|
||||||
<j-dropdown v-else>
|
|
||||||
<AIcon type="FilterOutlined" />
|
|
||||||
<template #overlay>
|
|
||||||
<j-menu @click="onFilter">
|
|
||||||
<j-menu-item :key="true"
|
|
||||||
>置顶已映射数据</j-menu-item
|
|
||||||
>
|
>
|
||||||
<j-menu-item :key="false"
|
<AIcon
|
||||||
>置顶未映射数据</j-menu-item
|
style="margin-left: 10px"
|
||||||
>
|
type="QuestionCircleOutlined"
|
||||||
</j-menu>
|
/>
|
||||||
</template>
|
</j-tooltip>
|
||||||
</j-dropdown>
|
</span>
|
||||||
</div>
|
<j-tag
|
||||||
</template>
|
v-if="filterValue !== undefined"
|
||||||
</template>
|
color="#87d068"
|
||||||
<template #bodyCell="{ column, text, record }">
|
closable
|
||||||
<template v-if="column.dataIndex === 'name'">
|
@close="onClose"
|
||||||
<span class="metadata-title">
|
><AIcon
|
||||||
<j-ellipsis>
|
type="ArrowUpOutlined"
|
||||||
{{ text }} ({{ record.id }})
|
/><span>{{
|
||||||
</j-ellipsis>
|
filterValue ? '已映射' : '未映射'
|
||||||
</span>
|
}}</span></j-tag
|
||||||
</template>
|
>
|
||||||
<template v-if="column.dataIndex === 'original'">
|
<j-dropdown v-else>
|
||||||
<j-select
|
<AIcon type="FilterOutlined" />
|
||||||
v-model:value="record.original"
|
<template #overlay>
|
||||||
style="width: 100%"
|
<j-menu @click="onFilter">
|
||||||
allowClear
|
<j-menu-item :key="true"
|
||||||
@change="(id) => onChange(record, id)"
|
>置顶已映射数据</j-menu-item
|
||||||
placeholder="请选择"
|
>
|
||||||
>
|
<j-menu-item :key="false"
|
||||||
<j-select-option
|
>置顶未映射数据</j-menu-item
|
||||||
v-for="(item, index) in targetOptions"
|
>
|
||||||
:key="index + '_' + item.id"
|
</j-menu>
|
||||||
:value="item.value"
|
</template>
|
||||||
:disabled="
|
</j-dropdown>
|
||||||
selectedOriginalKeys.includes(item.id)
|
</div>
|
||||||
"
|
</template>
|
||||||
|
</template>
|
||||||
|
<template #bodyCell="{ column, text, record }">
|
||||||
|
<template v-if="column.dataIndex === 'name'">
|
||||||
|
<span class="metadata-title" ref="title">
|
||||||
|
<j-ellipsis>
|
||||||
|
{{ text }} ({{ record.id }})
|
||||||
|
</j-ellipsis>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.dataIndex === 'original'">
|
||||||
|
<j-select
|
||||||
|
v-model:value="record.original"
|
||||||
|
style="width: 100%"
|
||||||
|
allowClear
|
||||||
|
@change="(id) => onChange(record, id)"
|
||||||
|
placeholder="请选择"
|
||||||
>
|
>
|
||||||
{{ item.label }} ({{
|
<j-select-option
|
||||||
item.id
|
v-for="(item, index) in targetOptions"
|
||||||
}})</j-select-option
|
:key="index + '_' + item.id"
|
||||||
>
|
:value="item.value"
|
||||||
</j-select>
|
:disabled="
|
||||||
</template>
|
selectedOriginalKeys.includes(
|
||||||
</template>
|
item.id,
|
||||||
</j-table>
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ item.label }} ({{
|
||||||
|
item.id
|
||||||
|
}})</j-select-option
|
||||||
|
>
|
||||||
|
</j-select>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</j-table>
|
||||||
|
</j-scrollbar>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<j-scrollbar>
|
<j-scrollbar>
|
||||||
|
@ -140,6 +149,8 @@ const targetOptions = ref<any[]>([]);
|
||||||
const filterValue = ref<boolean | undefined>(undefined);
|
const filterValue = ref<boolean | undefined>(undefined);
|
||||||
const originalData = ref([]);
|
const originalData = ref([]);
|
||||||
|
|
||||||
|
const _value = ref<any>(undefined);
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: '序号',
|
title: '序号',
|
||||||
|
@ -198,13 +209,22 @@ const getMetadataMapData = () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const customRow = (record: any) => {
|
||||||
|
return {
|
||||||
|
id: record.id,
|
||||||
|
class: _value.value === record.name ? 'metadata-search-row' : '',
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const search = (value: string) => {
|
const search = (value: string) => {
|
||||||
if (value) {
|
if (value) {
|
||||||
dataSource.value = dataSourceCache.value.filter((item: any) => {
|
const _item: any = dataSourceCache.value.find((item: any) => {
|
||||||
return !!item.name?.includes(value);
|
return value === item.name;
|
||||||
});
|
});
|
||||||
|
_value.value = _item.name;
|
||||||
|
document.getElementById(_item?.id)?.scrollIntoView(); // 滚动到可视区域
|
||||||
} else {
|
} else {
|
||||||
dataSource.value = dataSourceCache.value;
|
_value.value = undefined;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -276,7 +296,7 @@ const onChange = async (value: any, id: string) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const onFilter = ({ key }: any) => {
|
const onFilter = ({ key }: any) => {
|
||||||
originalData.value = dataSource.value
|
originalData.value = dataSource.value;
|
||||||
const _dataSource = cloneDeep(dataSource.value).sort((a: any, b: any) => {
|
const _dataSource = cloneDeep(dataSource.value).sort((a: any, b: any) => {
|
||||||
if (!key) {
|
if (!key) {
|
||||||
return (a.original ? 1 : -1) - (b.original ? 1 : -1);
|
return (a.original ? 1 : -1) - (b.original ? 1 : -1);
|
||||||
|
@ -301,14 +321,24 @@ onMounted(() => {
|
||||||
|
|
||||||
<style scoped lang='less'>
|
<style scoped lang='less'>
|
||||||
.metadata-map {
|
.metadata-map {
|
||||||
// position: relative;
|
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 24px;
|
gap: 24px;
|
||||||
|
|
||||||
.left {
|
.left {
|
||||||
// margin-right: 44px;
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.box {
|
||||||
|
height: calc(100vh - 388px);
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
:deep(.metadata-search-row) {
|
||||||
|
td {
|
||||||
|
background: #ffff80 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.right {
|
.right {
|
||||||
|
|
|
@ -1,137 +1,152 @@
|
||||||
<template>
|
<template>
|
||||||
<div class='metadata-map'>
|
<div class="metadata-map">
|
||||||
<div class='left'>
|
<div class="left">
|
||||||
<j-input-search
|
<j-input-search
|
||||||
style='width: 350px;margin-bottom:24px;'
|
style="width: 350px; margin-bottom: 24px"
|
||||||
placeholder='搜索平台属性名称'
|
placeholder="搜索平台属性名称"
|
||||||
allowClear
|
allowClear
|
||||||
@search='search'
|
@search="search"
|
||||||
/>
|
/>
|
||||||
<j-table
|
<div class="box">
|
||||||
:columns="columns"
|
<j-scrollbar height="100%">
|
||||||
:data-source="dataSource"
|
<j-table
|
||||||
:pagination='false'
|
:columns="columns"
|
||||||
:rowSelection='{
|
:data-source="dataSource"
|
||||||
selectedRowKeys: selectedKeys,
|
:pagination="false"
|
||||||
hideSelectAll: true,
|
:rowSelection="{
|
||||||
columnWidth: 0
|
selectedRowKeys: selectedKeys,
|
||||||
}'
|
hideSelectAll: true,
|
||||||
rowKey='id'
|
columnWidth: 0,
|
||||||
>
|
}"
|
||||||
<template #headerCell="{ column }">
|
rowKey="id"
|
||||||
<template v-if="column.dataIndex === 'plugin'">
|
:customRow="customRow"
|
||||||
<div
|
>
|
||||||
style="
|
<template #headerCell="{ column }">
|
||||||
width: 100%;
|
<template v-if="column.dataIndex === 'plugin'">
|
||||||
display: flex;
|
<div
|
||||||
justify-content: space-between;
|
style="
|
||||||
align-items: center;
|
width: 100%;
|
||||||
"
|
display: flex;
|
||||||
>
|
justify-content: space-between;
|
||||||
<span>
|
align-items: center;
|
||||||
目标属性<j-tooltip title="插件中物模型下的属性">
|
"
|
||||||
<AIcon
|
>
|
||||||
style="margin-left: 10px"
|
<span>
|
||||||
type="QuestionCircleOutlined"
|
目标属性<j-tooltip
|
||||||
/>
|
title="插件中物模型下的属性"
|
||||||
</j-tooltip>
|
>
|
||||||
</span>
|
<AIcon
|
||||||
<j-tag
|
style="margin-left: 10px"
|
||||||
v-if="filterValue !== undefined"
|
type="QuestionCircleOutlined"
|
||||||
color="#87d068"
|
/>
|
||||||
closable
|
</j-tooltip>
|
||||||
@close="onClose"
|
</span>
|
||||||
><AIcon type="ArrowUpOutlined" /><span>{{
|
<j-tag
|
||||||
filterValue ? '已映射' : '未映射'
|
v-if="filterValue !== undefined"
|
||||||
}}</span></j-tag
|
color="#87d068"
|
||||||
>
|
closable
|
||||||
<j-dropdown v-else>
|
@close="onClose"
|
||||||
<AIcon type="FilterOutlined" />
|
><AIcon
|
||||||
<template #overlay>
|
type="ArrowUpOutlined"
|
||||||
<j-menu @click="onFilter">
|
/><span>{{
|
||||||
<j-menu-item :key="true"
|
filterValue ? '已映射' : '未映射'
|
||||||
>置顶已映射数据</j-menu-item
|
}}</span></j-tag
|
||||||
>
|
>
|
||||||
<j-menu-item :key="false"
|
<j-dropdown v-else>
|
||||||
>置顶未映射数据</j-menu-item
|
<AIcon type="FilterOutlined" />
|
||||||
>
|
<template #overlay>
|
||||||
</j-menu>
|
<j-menu @click="onFilter">
|
||||||
</template>
|
<j-menu-item :key="true"
|
||||||
</j-dropdown>
|
>置顶已映射数据</j-menu-item
|
||||||
</div>
|
>
|
||||||
</template>
|
<j-menu-item :key="false"
|
||||||
</template>
|
>置顶未映射数据</j-menu-item
|
||||||
<template #bodyCell="{ column, text, record }">
|
>
|
||||||
<template v-if='column.dataIndex === "name"'>
|
</j-menu>
|
||||||
<span class='metadata-title'>
|
</template>
|
||||||
<j-ellipsis>
|
</j-dropdown>
|
||||||
{{ text }} ({{ record.id }})
|
</div>
|
||||||
</j-ellipsis>
|
</template>
|
||||||
</span>
|
</template>
|
||||||
</template>
|
<template #bodyCell="{ column, text, record }">
|
||||||
<template v-if='column.dataIndex === "plugin"'>
|
<template v-if="column.dataIndex === 'name'">
|
||||||
<j-select
|
<span class="metadata-title">
|
||||||
v-model:value='record.plugin'
|
<j-ellipsis>
|
||||||
style='width: 100%'
|
{{ text }} ({{ record.id }})
|
||||||
allowClear
|
</j-ellipsis>
|
||||||
@change='(id) => pluginChange(record, id)'
|
</span>
|
||||||
>
|
</template>
|
||||||
<j-select-option
|
<template v-if="column.dataIndex === 'plugin'">
|
||||||
v-for='(item, index) in pluginOptions'
|
<j-select
|
||||||
:key='index + "_" + item.id'
|
v-model:value="record.plugin"
|
||||||
:value='item.value'
|
style="width: 100%"
|
||||||
:disabled='selectedPluginKeys.includes(item.id)'
|
allowClear
|
||||||
><j-tooltip :title="selectedPluginKeys.includes(item.id) ? '该属性已绑定平台属性' : ''">
|
@change="(id) => pluginChange(record, id)"
|
||||||
{{ item.label }} ({{
|
>
|
||||||
item.id
|
<j-select-option
|
||||||
}})
|
v-for="(item, index) in pluginOptions"
|
||||||
</j-tooltip></j-select-option>
|
:key="index + '_' + item.id"
|
||||||
</j-select>
|
:value="item.value"
|
||||||
</template>
|
:disabled="
|
||||||
</template>
|
selectedPluginKeys.includes(item.id)
|
||||||
</j-table>
|
"
|
||||||
|
><j-tooltip
|
||||||
|
:title="
|
||||||
|
selectedPluginKeys.includes(
|
||||||
|
item.id,
|
||||||
|
)
|
||||||
|
? '该属性已绑定平台属性'
|
||||||
|
: ''
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ item.label }} ({{ item.id }})
|
||||||
|
</j-tooltip></j-select-option
|
||||||
|
>
|
||||||
|
</j-select>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</j-table>
|
||||||
|
</j-scrollbar>
|
||||||
|
</div>
|
||||||
|
</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>
|
</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>
|
</template>
|
||||||
|
|
||||||
<script setup lang='ts' name='MetadataMap'>
|
<script setup lang='ts' name='MetadataMap'>
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia';
|
||||||
import { useProductStore } from '@/store/product';
|
import { useProductStore } from '@/store/product';
|
||||||
import { detail as queryPluginAccessDetail } from '@/api/link/accessConfig'
|
import { detail as queryPluginAccessDetail } from '@/api/link/accessConfig';
|
||||||
import { getPluginData, getProductByPluginId } from '@/api/link/plugin'
|
import { getPluginData, getProductByPluginId } from '@/api/link/plugin';
|
||||||
import { getImage, onlyMessage } from '@/utils/comm'
|
import { getImage, onlyMessage } from '@/utils/comm';
|
||||||
import { getMetadataMapById, metadataMapById } from '@/api/device/instance'
|
import { getMetadataMapById, metadataMapById } from '@/api/device/instance';
|
||||||
import { cloneDeep } from 'lodash-es';
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
|
||||||
const productStore = useProductStore();
|
const productStore = useProductStore();
|
||||||
const { current: productDetail } = storeToRefs(productStore)
|
const { current: productDetail } = storeToRefs(productStore);
|
||||||
const dataSourceCache = ref([])
|
const dataSourceCache = ref([]);
|
||||||
const dataSource = ref([])
|
const dataSource = ref([]);
|
||||||
const pluginOptions = ref<any[]>([])
|
const pluginOptions = ref<any[]>([]);
|
||||||
|
|
||||||
const filterValue = ref<boolean | undefined>(undefined);
|
const filterValue = ref<boolean | undefined>(undefined);
|
||||||
const originalData = ref([]);
|
const originalData = ref([]);
|
||||||
|
@ -141,66 +156,103 @@ const originalData = ref([]);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: '序号',
|
title: '序号',
|
||||||
dataIndex: 'index',
|
dataIndex: 'index',
|
||||||
width: 100
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '平台属性',
|
title: '平台属性',
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '目标属性',
|
title: '目标属性',
|
||||||
dataIndex: 'plugin',
|
dataIndex: 'plugin',
|
||||||
width: 250,
|
width: 250,
|
||||||
// sorter: tableFilter
|
// sorter: tableFilter
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
|
const _value = ref<any>(undefined);
|
||||||
|
|
||||||
const selectedKeys = computed(() => {
|
const selectedKeys = computed(() => {
|
||||||
return dataSource.value?.filter(item => !!item?.plugin).map(item => item.id) || []
|
return (
|
||||||
})
|
dataSource.value
|
||||||
|
?.filter((item) => !!item?.plugin)
|
||||||
|
.map((item) => item.id) || []
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
const selectedPluginKeys = computed(() => {
|
const selectedPluginKeys = computed(() => {
|
||||||
return dataSource.value?.filter(item => !!item?.plugin).map(item => item.plugin) || []
|
return (
|
||||||
})
|
dataSource.value
|
||||||
|
?.filter((item) => !!item?.plugin)
|
||||||
|
.map((item) => item.plugin) || []
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
const getMetadataMapData = () => {
|
const getMetadataMapData = () => {
|
||||||
return new Promise(resolve => {
|
return new Promise((resolve) => {
|
||||||
getMetadataMapById('product', productDetail.value?.id).then(res => {
|
getMetadataMapById('product', productDetail.value?.id).then((res) => {
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
resolve(res.result?.filter(item => item.customMapping)?.map(item => {
|
resolve(
|
||||||
return {
|
res.result
|
||||||
id: item.metadataId,
|
?.filter((item) => item.customMapping)
|
||||||
pluginId: item.originalId
|
?.map((item) => {
|
||||||
}
|
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 customRow = (record: any) => {
|
||||||
|
return {
|
||||||
|
id: record.id,
|
||||||
|
class: _value.value === record.name ? 'metadata-search-row' : '',
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const search = (value: string) => {
|
const search = (value: string) => {
|
||||||
if (value) {
|
if (value) {
|
||||||
dataSource.value = dataSourceCache.value.filter((item: any) => {
|
const _item: any = dataSourceCache.value.find((item: any) => {
|
||||||
return !!item.name?.includes(value)
|
return value === item.name;
|
||||||
})
|
});
|
||||||
} else {
|
_value.value = _item.name;
|
||||||
dataSource.value = dataSourceCache.value
|
document.getElementById(_item?.id)?.scrollIntoView(); // 滚动到可视区域
|
||||||
}
|
} else {
|
||||||
}
|
_value.value = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const getDefaultMetadata = async () => {
|
const getDefaultMetadata = async () => {
|
||||||
const metadata = JSON.parse(productDetail.value?.metadata || '{}')
|
const metadata = JSON.parse(productDetail.value?.metadata || '{}');
|
||||||
const properties = metadata.properties
|
const properties = metadata.properties;
|
||||||
const pluginMetadata = await getPluginMetadata()
|
const pluginMetadata = await getPluginMetadata();
|
||||||
const pluginProperties = pluginMetadata?.properties || []
|
const pluginProperties = pluginMetadata?.properties || [];
|
||||||
const metadataMap: any = await getMetadataMapData()
|
const metadataMap: any = await getMetadataMapData();
|
||||||
pluginOptions.value = pluginProperties.map(item => ({...item, label: item.name, value: item.id}))
|
pluginOptions.value = pluginProperties.map((item) => ({
|
||||||
|
...item,
|
||||||
|
label: item.name,
|
||||||
|
value: item.id,
|
||||||
|
}));
|
||||||
|
|
||||||
// const concatProperties = [ ...pluginProperties.map(item => ({ id: item.id, pluginId: item.id})), ...metadataMap]
|
// const concatProperties = [ ...pluginProperties.map(item => ({ id: item.id, pluginId: item.id})), ...metadataMap]
|
||||||
const concatProperties = [...metadataMap];
|
const concatProperties = [...metadataMap];
|
||||||
const arr = concatProperties.map((item) => item.id);
|
const arr = concatProperties.map((item) => item.id);
|
||||||
const _arr = concatProperties.map((item) => item.pluginId);
|
const _arr = concatProperties.map((item) => item.pluginId);
|
||||||
|
|
||||||
|
@ -211,50 +263,65 @@ const getDefaultMetadata = async () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
dataSource.value = properties?.map((item: any, index: number) => {
|
dataSource.value =
|
||||||
const _m = concatProperties.find(p => p.id === item.id)
|
properties?.map((item: any, index: number) => {
|
||||||
return {
|
const _m = concatProperties.find((p) => p.id === item.id);
|
||||||
index: index + 1,
|
return {
|
||||||
id: item.id, // 产品物模型id
|
index: index + 1,
|
||||||
name: item.name,
|
id: item.id, // 产品物模型id
|
||||||
type: item.valueType?.type,
|
name: item.name,
|
||||||
plugin: _m?.pluginId, // 插件物模型id
|
type: item.valueType?.type,
|
||||||
}
|
plugin: _m?.pluginId, // 插件物模型id
|
||||||
}) || []
|
};
|
||||||
dataSourceCache.value = dataSource.value
|
}) || [];
|
||||||
}
|
dataSourceCache.value = dataSource.value;
|
||||||
|
};
|
||||||
|
|
||||||
const getPluginMetadata = (): Promise<{ properties: any[]}> => {
|
const getPluginMetadata = (): Promise<{ properties: any[] }> => {
|
||||||
return new Promise(resolve => {
|
return new Promise((resolve) => {
|
||||||
queryPluginAccessDetail(productDetail.value?.accessId!).then(async res => {
|
queryPluginAccessDetail(productDetail.value?.accessId!).then(
|
||||||
if (res.success) {
|
async (res) => {
|
||||||
const _channelId = (res.result as any)!.channelId
|
if (res.success) {
|
||||||
const pluginRes = await getPluginData('product', productDetail.value?.accessId || '', productDetail.value?.id).catch(() => ({ success: false, result: {}}))
|
const _channelId = (res.result as any)!.channelId;
|
||||||
const resp = await getProductByPluginId(_channelId).catch(() => ({ success: false, result: []}))
|
const pluginRes = await getPluginData(
|
||||||
if (resp.success) {
|
'product',
|
||||||
const _item = (resp.result as any[])?.find((item: any) => item.id === (pluginRes?.result as any)?.externalId)
|
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,
|
||||||
|
);
|
||||||
|
|
||||||
resolve(_item ? _item.metadata : { properties: [] })
|
resolve(_item ? _item.metadata : { properties: [] });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resolve({ properties: [] })
|
resolve({ properties: [] });
|
||||||
})
|
},
|
||||||
})
|
);
|
||||||
}
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const pluginChange = async (value: any, id: string) => {
|
const pluginChange = async (value: any, id: string) => {
|
||||||
const res = await metadataMapById('product', productDetail.value?.id, [{
|
const res = await metadataMapById('product', productDetail.value?.id, [
|
||||||
metadataType: 'property',
|
{
|
||||||
metadataId: value.id,
|
metadataType: 'property',
|
||||||
originalId: id
|
metadataId: value.id,
|
||||||
}])
|
originalId: id,
|
||||||
if (res.success) {
|
},
|
||||||
onlyMessage('操作成功')
|
]);
|
||||||
}
|
if (res.success) {
|
||||||
}
|
onlyMessage('操作成功');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const onFilter = ({ key }: any) => {
|
const onFilter = ({ key }: any) => {
|
||||||
originalData.value = dataSource.value
|
originalData.value = dataSource.value;
|
||||||
const _dataSource = cloneDeep(dataSource.value).sort((a: any, b: any) => {
|
const _dataSource = cloneDeep(dataSource.value).sort((a: any, b: any) => {
|
||||||
if (!key) {
|
if (!key) {
|
||||||
return (a.plugin ? 1 : -1) - (b.plugin ? 1 : -1);
|
return (a.plugin ? 1 : -1) - (b.plugin ? 1 : -1);
|
||||||
|
@ -273,54 +340,64 @@ const onClose = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getDefaultMetadata()
|
getDefaultMetadata();
|
||||||
})
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang='less'>
|
<style scoped lang='less'>
|
||||||
.metadata-map {
|
.metadata-map {
|
||||||
// position: relative;
|
// 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-height: 100%;
|
||||||
min-width: 410px;
|
display: flex;
|
||||||
width: 33.33333%;
|
gap: 24px;
|
||||||
// top: 0;
|
|
||||||
// right: 0;
|
|
||||||
padding: 16px;
|
|
||||||
|
|
||||||
.title {
|
.left {
|
||||||
margin-bottom: 16px;
|
// margin-right: 44px;
|
||||||
color: rgba(#000, .85);
|
flex: 1;
|
||||||
font-weight: bold;
|
|
||||||
|
|
||||||
p {
|
.box {
|
||||||
initial-letter: 28px;
|
height: calc(100vh - 392px);
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
:deep(.metadata-search-row) {
|
||||||
|
td {
|
||||||
|
background: #ffff80 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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, 0.85);
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
p {
|
||||||
|
initial-letter: 28px;
|
||||||
|
color: #666666;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.metadata-title {
|
||||||
color: #666666;
|
color: #666666;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.metadata-title {
|
:deep(.ant-table-selection-column) {
|
||||||
color: #666666;
|
padding: 0;
|
||||||
}
|
label {
|
||||||
|
display: none;
|
||||||
:deep(.ant-table-selection-column) {
|
}
|
||||||
padding: 0;
|
|
||||||
label {
|
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
|
@ -429,7 +429,12 @@ const formRules = ref({
|
||||||
'configuration.host': [{ required: true, message: '请输入服务器地址', trigger: 'blur' }],
|
'configuration.host': [{ required: true, message: '请输入服务器地址', trigger: 'blur' }],
|
||||||
'configuration.sender': [
|
'configuration.sender': [
|
||||||
{ required: true, message: '请输入发件人', trigger: 'blur' },
|
{ required: true, message: '请输入发件人', trigger: 'blur' },
|
||||||
{ max: 64, message: '最多可输入64个字符' },
|
// { max: 64, message: '最多可输入64个字符' },
|
||||||
|
{
|
||||||
|
pattern:
|
||||||
|
/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/,
|
||||||
|
message: '请输入正确的邮箱',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
'configuration.username': [
|
'configuration.username': [
|
||||||
{ required: true, message: '请输入用户名', trigger: 'blur' },
|
{ required: true, message: '请输入用户名', trigger: 'blur' },
|
||||||
|
|
|
@ -71,7 +71,7 @@ const props = defineProps({
|
||||||
},
|
},
|
||||||
gridColumn: {
|
gridColumn: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 2
|
default: 3
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue