feat(新增物模型模块及优化部门树): 新增物模型模块及优化其它模块代码

This commit is contained in:
Kven 2025-01-08 11:13:44 +08:00
parent daf3f540a4
commit 1cbd436f73
18 changed files with 1699 additions and 182 deletions

View File

@ -14,7 +14,7 @@ export default mergeConfig(
proxy: {
'/api': {
// target: 'http://8.134.75.234:8081',
target: 'http://127.0.0.1:8081',
target: 'http://192.168.3.238:8081',
changeOrigin: true,
},
},

View File

@ -11,6 +11,17 @@ export interface DeptRecord extends DeptCreateRecord {
id: string;
}
// 获取部门树
export function getAllDeptTree(id: number | string) {
return axios({
method: 'get',
url: '/api/rest/dept/tree',
params: {
id,
}
});
}
// 添加区域
export function create(data: DeptCreateRecord) {
return axios.post(`/api/rest/dept`, data);

View File

@ -24,8 +24,6 @@ export interface MessageCreateRecord {
attachmentIds?: string[];
}
// 查看详情
export function queryMessage(userId: number, messageId: number) {
return axios.get(`/api/rest/message/${userId}/${messageId}`);

75
src/api/tsl.ts Normal file
View File

@ -0,0 +1,75 @@
import axios from 'axios';
export interface Record {
current: number;
size: number;
}
export interface ServeRecord extends Record {
name?: string;
identifier?: string;
productId: number;
}
export interface PropertyRecord extends Record {
name?: string;
identifier?: string;
productId: number;
dataType?: string;
ioType?: string;
}
export interface eventRecord extends Record {
name?: string;
level?: string;
identifier?: string;
productId?: number;
}
export function queryServeList(data: ServeRecord) {
return axios({
url: '/api/rest/tsl/serve',
method: 'get',
params: data,
});
}
export function queryPropertyList(data: PropertyRecord) {
return axios({
url: '/api/rest/tsl/property',
method: 'get',
params: data,
});
}
export function queryEventList(data: eventRecord) {
return axios({
url: '/api/rest/tsl/event',
method: 'get',
params: data,
});
}
export function createServe(data: any) {
return axios.post(`/api/rest/tsl/serve`, data);
}
export function createProperty(data: any) {
return axios.post(`/api/rest/tsl/property`, data);
}
export function createEvent(data: any) {
return axios.post(`/api/rest/tsl/event`, data);
}
export function deleteServe(data: any) {
return axios.delete(`/api/rest/tsl/serve/${data}`, );
}
export function deleteProperty(data: any) {
return axios.delete(`/api/rest/tsl/property/${data}`);
}
export function deleteEvent(data: any) {
return axios.delete(`/api/rest/tsl/event/${data}`);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

34
src/mock/deptTree.ts Normal file
View File

@ -0,0 +1,34 @@
import Mock from 'mockjs';
import setupMock, { successResponseWrap } from '@/utils/setup-mock';
// 生成部门树数据
const deptTree = Mock.mock({
'totalDept': {
'dept': '总部门',
'children': [
{
'dept': '部门1',
'members': [
{'name': '@cname'},
{'name': '@cname'}
]
},
{
'dept': '部门2',
'members': [
{'name': '@cname'},
{'name': '@cname'}
]
}
]
}
});
setupMock({
setup: () => {
Mock.mock(new RegExp('/api/deptTree'), () => {
return successResponseWrap(deptTree);
})
}
})
// 假设你需要将这个数据作为一个 API 的响应

View File

@ -46,6 +46,29 @@ const IOT: AppRouteRecordRaw = {
permissions: ['*'],
},
},
{
path: 'device/:id',
name: 'deviceDetail',
component: () => import('@/views/iot/device/components/device-detail.vue'),
meta: {
title: '设备详情',
requiresAuth: true,
showInMenu: false,
permissions: ['*'],
},
},
{
path: 'product/tsl/:id',
name: 'productTsl',
component: () => import('@/views/iot/product/components/product-tsl.vue'),
meta: {
title: '物模型',
requiresAuth: true,
showInMenu: false,
permissions: ['*'],
},
}
],
};

View File

@ -0,0 +1,94 @@
<template>
<a-card
class="general-card"
title='公告'
:header-style="{ paddingBottom: '0' }"
:body-style="{ padding: '15px 20px 13px 20px' }"
>
<template #extra>
<a-link @click="$router.push({ name: 'Bulletins' })">查看更多</a-link>
</template>
<div>
<div v-for="(item, idx) in renderData" :key="idx" class="item">
<a-tag color=blue size="small">通知</a-tag>
<span class="item-content" @click="$router.push({name:'Details',params:{id:item.id}})">
{{ item.title }}
</span>
</div>
</div>
</a-card>
</template>
<script lang="ts" setup>
//
import { BulletinsRecord } from '@/api/bulletins';
import { useBulletinsStore } from '@/store';
import { ref } from 'vue';
const bulletinsStore = useBulletinsStore();
const renderData = ref<BulletinsRecord[]>([]);
//
const fetchData = async (
params: BulletinsRecord = { current: 1 ,size: 5}
) => {
try {
const res = await bulletinsStore.getBulletinsList(params);
renderData.value = res.data.records;
} catch (err) {
// you can report use errorHandler or other
}
};
fetchData();
const list = [
{
type: 'orangered',
label: '活动',
content: '内容最新优惠活动',
},
{
type: 'cyan',
label: '消息',
content: '新增内容尚未通过审核,详情请点击查看。',
},
{
type: 'blue',
label: '通知',
content: '当前产品试用期即将结束,如需续费请点击查看。',
},
{
type: 'blue',
label: '通知',
content: '1月新系统升级计划通知',
},
{
type: 'cyan',
label: '消息',
content: '新增内容已经通过审核,详情请点击查看。',
},
];
</script>
<style scoped lang="less">
.item {
display: flex;
align-items: center;
width: 100%;
height: 24px;
margin-bottom: 4px;
.item-content {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-left: 4px;
color: var(--color-text-2);
text-decoration: none;
font-size: 13px;
cursor: pointer;
}
}
</style>

View File

@ -0,0 +1,35 @@
<template>
<a-card
class="general-card"
:title="$t('workplace.quick.operation')"
:header-style="{ paddingBottom: '0' }"
:body-style="{ padding: '24px 20px 0 20px' }"
>
<template #extra>
<a-link>{{ $t('workplace.quickOperation.setup') }}</a-link>
</template>
<a-row :gutter="8">
<a-col v-for="link in links" :key="link.text" :span="8" class="wrapper">
<div class="icon">
<component :is="link.icon" />
</div>
<a-typography-paragraph class="text">
{{ $t(link.text) }}
</a-typography-paragraph>
</a-col>
</a-row>
<a-divider class="split-line" style="margin: 0" />
</a-card>
</template>
<script lang="ts" setup>
const links = [
{ text: 'workplace.contentManagement', icon: 'icon-file' },
{ text: 'workplace.contentStatistical', icon: 'icon-storage' },
{ text: 'workplace.advanced', icon: 'icon-settings' },
{ text: 'workplace.onlinePromotion', icon: 'icon-mobile' },
{ text: 'workplace.contentPutIn', icon: 'icon-fire' },
];
</script>
<style scoped lang="less"></style>

View File

@ -0,0 +1,44 @@
<template>
<a-card
class="general-card"
:title="$t('workplace.recently.visited')"
:header-style="{ paddingBottom: '0' }"
:body-style="{ paddingTop: '26px' }"
>
<div style="margin-bottom: -1rem">
<a-row :gutter="8">
<a-col v-for="link in links" :key="link.text" :span="8" class="wrapper">
<div class="icon">
<component :is="link.icon" />
</div>
<a-typography-paragraph class="text">
{{ $t(link.text) }}
</a-typography-paragraph>
</a-col>
</a-row>
</div>
</a-card>
</template>
<script lang="ts" setup>
const links = [
{
text: 'workplace.contentManagement',
icon: 'icon-storage',
},
{
text: 'workplace.contentStatistical',
icon: 'icon-file',
},
{
text: 'workplace.advanced',
icon: 'icon-settings',
},
];
</script>
<style lang="less" scoped>
:deep(.arco-card-header-title) {
line-height: inherit;
}
</style>

View File

@ -1,70 +1,102 @@
<template>
<a-button
type="outline"
size="small"
status="success"
style="padding: 7px; margin-right: 10px"
@click="handleClick"
>
<template #icon><icon-list /></template>
详情
</a-button>
<a-modal
width="600px"
:visible="visible"
@cancel="handleCancel"
>
<template #title>设备详情</template>
<a-descriptions style="margin-top: 20px" :data="formData" size="large" :title=formData.name :column="1">
<a-descriptions-item label="产品名称">{{formData.productId}}</a-descriptions-item>
<a-descriptions-item label="硬件版本">{{formData.hardwareVersion}}</a-descriptions-item>
<a-descriptions-item label="固件版本">{{formData.firmwareVersion}}</a-descriptions-item>
<a-descriptions-item label="扩展属性">{{formData.extendParams}}</a-descriptions-item>
<div class="container">
<Breadcrumb :items="['物联网管理', '设备管理', '设备详情']" />
<a-card class="general-card" title=" ">
<a-descriptions v-model="renderData" size="large">
<template #title><h3 style="margin-top: -15px">设备详情</h3></template>
<a-descriptions-item label="设备名称">{{renderData.name }}</a-descriptions-item>
<a-descriptions-item label="硬件版本">{{renderData.hardwareVersion }}</a-descriptions-item>
<a-descriptions-item label="固件版本">{{renderData.firmwareVersion }}</a-descriptions-item>
<a-descriptions-item label="所属产品">{{renderData.productId }}</a-descriptions-item>
<!-- <a-descriptions-item label="备注">{{renderData.remark }}</a-descriptions-item>-->
<a-descriptions-item label="创建时间">{{dayjs(renderData.createTime).format('YYYY-MM-DD HH:mm:ss') }}</a-descriptions-item>
</a-descriptions>
<template #footer>
<!-- <a-button class="editor-button" @click="handleCancel">取消</a-button>-->
<a-button class="editor-button" type="primary" @click="handleCancel">确定</a-button>
</template>
</a-modal>
</a-card>
<a-card class="general-card" style="margin-top: 10px">
<a-tabs :active-key="activeKey" @tab-click="handleMenuClick" style="padding-top: 20px">
<a-tab-pane key="1" tab="参数" title="扩展属性">
<a-table :columns="columns" :data="renderData.extendParams" />
</a-tab-pane>
<a-tab-pane key="2" tab="基本信息" title="基本信息">
基本信息
</a-tab-pane>
<a-tab-pane key="3" tab="执行服务" title="执行服务"> 执行服务内容 </a-tab-pane>
</a-tabs>
</a-card>
</div>
</template>
<script lang="ts" setup>
import useVisible from '@/hooks/visible';
import { defineEmits, PropType, ref } from 'vue';
import { DeviceCreateRecord } from '@/api/device';
import '@wangeditor/editor/dist/css/style.css'
import dayjs from 'dayjs';
import { useRoute } from 'vue-router';
import { onMounted, ref } from 'vue';
import { queryDeviceDetail } from '@/api/device';
const props = defineProps({
prem: {
type: Object as PropType<DeviceCreateRecord>,
const route = useRoute();
const id = Number(route.params.id);
const columns = [
{
title: '参数名称',
dataIndex: 'name',
slotName: 'name',
},
isCreate: Boolean,
});
const emit = defineEmits(['refresh']);
const { visible, setVisible } = useVisible(false);
const formData = ref<any>({
...props.prem,
});
//
const handleClick = () => {
setVisible(true);
{
title: '参数标识',
dataIndex: 'identifier',
slotName: 'identifier',
},
{
title: '数据类型',
dataIndex: 'dataType',
slotName: 'dataType',
},
{
title: '参数类型',
dataIndex: 'type',
slotName: 'type',
},
];
const activeKey = ref('1');
const renderData = ref([]);
const fetchData = async (Id: number) => {
const res = await queryDeviceDetail(Id);
renderData.value = res.data;
};
//
const handleCancel = async () => {
setVisible(false);
const handleMenuClick = (e: any) => {
activeKey.value = e;
};
onMounted(() => {
fetchData(id);
});
</script>
<style scoped>
.editor-button{
position: static
.container {
padding: 0 20px 20px 20px;
}
h1 {
font-size: 24px;
margin-bottom: 10px;
}
.meta span {
margin-right: 20px;
}
.attachments li {
margin-bottom: 10px;
}
.attachments a {
display: flex;
align-items: center;
font-size: 14px;
color: #1890ff;
text-decoration: none;
}
.attachments a:hover {
text-decoration: underline;
}
</style>

View File

@ -82,13 +82,25 @@
<a-form-item
field="extendParams"
label="扩展属性"
:rules="[{ required: true, message: '扩展属性不能为空' }]"
:validate-trigger="['change']"
>
<a-input
v-model="formData.extendParams"
placeholder='请输入扩展属性'
/>
<!-- <a-input-->
<!-- v-model="formData.extendParams"-->
<!-- placeholder='请输入扩展属性'-->
<!-- />-->
<div style="width: 100%">
<div style="width: 100%;margin-bottom: 5px; ">
<a-space v-for="(param,index) in paramsData" :key="index" style="margin-bottom: 5px">
<a-input v-model="param.name" placeholder="名称" allow-clear />
<a-input v-model="param.identifier" placeholder="标识" allow-clear />
<a-select v-model="param.dataType" :options="dataTypeOptions" allow-search />
<a-select v-model="param.type" :options="typeOptions" allow-search />
<a-button type="text" @click="handleDeleteParams(index)"><icon-minus-circle /></a-button>
</a-space>
</div>
<a-button @click="handleAddParams" style="width: 100%" >
<icon-plus />
</a-button>
</div>
</a-form-item>
</a-form>
@ -108,6 +120,7 @@
import { useMessageStore } from '@/store';
import '@wangeditor/editor/dist/css/style.css'
import { createDevice, updateDevice } from '@/api/device';
import type { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
const props = defineProps({
prem: {
@ -115,6 +128,58 @@
},
isCreate: Boolean,
});
const paramsData = ref([
{
name: '',
identifier: '',
dataType: '',
type: '',
},
]);
const dataTypeOptions = computed<SelectOptionData[]>(() => [
{
label: '整型',
value: 'INT',
},
{
label: '单精度浮点型',
value: 'FLOAT',
},
{
label: '双精度浮点型',
value: 'DOUBLE',
},
{
label: '布尔型',
value: 'BOOLEAN',
},
{
label: '字符串',
value: 'STRING',
},
{
label: '日期型',
value: 'DATE',
},
{
label: '透传',
value: 'RAW',
},
]);
const typeOptions = computed<SelectOptionData[]>(() => [
{
label: '物模型输入',
value: 'INPUT',
},
{
label: '物模型输出',
value: 'OUTPUT',
},
{
label: '读写属性',
value: 'RW',
},
]);
const emit = defineEmits(['refresh']);
const modalTitle = computed(() => {
return props.isCreate ? '创建设备' : '编辑设备';
@ -142,7 +207,22 @@
options.value = []
}
};
//
const handleAddParams = () => {
// paramsVisible.value = true;
paramsData.value.push({
name: '',
identifier: '',
dataType: '',
type: '',
});
};
//
const handleDeleteParams = (record: any) => {
if (record !== -1) {
paramsData.value.splice(record, 1);
}
};
//
const handleClick = () => {
setVisible(true);
@ -153,6 +233,7 @@
const valid = await CreateRef.value?.validate();
if (!valid) {
//
formData.value.extendParams = paramsData.value;
if (props.isCreate) {
// formData.value.username = formData.value.email;
const res = await createDevice(formData.value);

View File

@ -162,17 +162,16 @@
{{ record.online == true? '是' : '否' }}
</template>
<template #operations="{ record }">
<!-- <a-button-->
<!-- type="outline"-->
<!-- size="small"-->
<!-- status="success"-->
<!-- style="padding: 7px; margin-right: 10px"-->
<!-- @click="openDetail(record.id)"-->
<!-- >-->
<!-- <template #icon><icon-list /></template>-->
<!-- 详情-->
<!-- </a-button>-->
<DeviceDetail :prem="record" />
<a-button
type="outline"
size="small"
status="success"
style="padding: 7px; margin-right: 10px"
@click="openDetail(record.id)"
>
<template #icon><icon-list /></template>
详情
</a-button>
<DeviceEdit
ref="editUserRef"
:prem="record"
@ -338,7 +337,7 @@
//
function openDetail(id:number): void{
const url = router.resolve({
name: 'Detail',
name: 'deviceDetail',
params: {id}
}).href;
router.push(url);

View File

@ -1,20 +1,27 @@
<template>
<div class="container">
<Breadcrumb :items="['物联网管理', '产品管理','产品详情']" />
<Breadcrumb :items="['物联网管理', '产品管理', '产品详情']" />
<a-card class="general-card" title=" ">
<div class="announcement-detail">
<a-descriptions :data="renderData" size="large" title="产品详情" bordered >
<a-descriptions-item label="产品名称">{{renderData.name}}</a-descriptions-item>
<a-descriptions-item label="产品类型">{{renderData.productType}}</a-descriptions-item>
<a-descriptions-item label="产品型号">{{renderData.model}}</a-descriptions-item>
<a-descriptions-item label="通讯协议">{{renderData.link}}</a-descriptions-item>
<a-descriptions-item label="备注">{{renderData.remark}}</a-descriptions-item>
<a-descriptions-item label="创建时间">{{dayjs(renderData.createTime).format('YYYY-MM-DD HH:mm:ss')}}</a-descriptions-item>
<a-descriptions-item label="扩展属性">
<a-table :columns="columns" :data="renderData.params" row-key="id" :pagination="false"/>
</a-descriptions-item>
<a-descriptions v-model="renderData" size="large">
<template #title><h3 style="margin-top: -15px">产品详情</h3></template>
<a-descriptions-item label="产品名称">{{renderData.name }}</a-descriptions-item>
<a-descriptions-item label="产品类型">{{renderData.productType }}</a-descriptions-item>
<a-descriptions-item label="产品型号">{{renderData.model }}</a-descriptions-item>
<a-descriptions-item label="通讯协议">{{renderData.link }}</a-descriptions-item>
<a-descriptions-item label="备注">{{renderData.remark }}</a-descriptions-item>
<a-descriptions-item label="创建时间">{{dayjs(renderData.createTime).format('YYYY-MM-DD HH:mm:ss') }}</a-descriptions-item>
</a-descriptions>
</div>
</a-card>
<a-card class="general-card" style="margin-top: 10px">
<a-tabs :active-key="activeKey" @tab-click="handleMenuClick" style="padding-top: 20px">
<a-tab-pane key="1" tab="参数" title="参数">
<a-table :columns="columns" :data="renderData.params" />
</a-tab-pane>
<a-tab-pane key="2" tab="基本信息" title="基本信息">
基本信息
</a-tab-pane>
<a-tab-pane key="3" tab="执行服务" title="执行服务"> 执行服务内容 </a-tab-pane>
</a-tabs>
</a-card>
</div>
</template>
@ -27,7 +34,7 @@
const route = useRoute();
const id = Number(route.params.id);
const columns=[
const columns = [
{
title: '参数名称',
dataIndex: 'name',
@ -49,72 +56,34 @@
slotName: 'type',
},
];
const renderData = ref<any>(
{
name: '产品名称',
productType: '设备',
model: '123456',
link: 'TCP',
remark: '123456',
createTime: '2023-08-08 10:10:10',
params:[
{
name:'设备名称',
identifier:'1.0.0',
dataType:'1.0.0',
type:'123456',
},
{
name:'设备名称',
identifier:'1.0.0',
dataType:'1.0.0',
type:'123456',
},
{
name:'设备名称',
identifier:'1.0.0',
dataType:'1.0.0',
type:'123456',
},
]
},
);
// const fetchData = async (Id: number) => {
// const res = await queryProductDetail(Id);
// renderData.value = res.data;
// };
// onMounted(() => {
// fetchData(id);
// });
const activeKey = ref('1');
const renderData = ref([]);
const fetchData = async (Id: number) => {
const res = await queryProductDetail(Id);
renderData.value = res.data;
};
const handleMenuClick = (e: any) => {
activeKey.value = e;
};
onMounted(() => {
fetchData(id);
});
</script>
<style scoped>
.container {
padding: 0 20px 20px 20px;
}
.announcement-detail {
min-width: 800px;
max-width: 800px;
margin: auto;
padding: 20px;
border: 1px solid #ddd;
background-color: #fff; /* 白色背景,与淡蓝色背景区分开来 */
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
h1 {
font-size: 24px;
margin-bottom: 10px;
}
.meta span {
margin-right: 20px;
}
.attachments li {
margin-bottom: 10px;
}
@ -131,5 +100,3 @@
text-decoration: underline;
}
</style>

View File

@ -0,0 +1,445 @@
<template>
<a-button v-if="props.isCreate" type="primary" @click="handleClick">
<template #icon><icon-plus /></template>
新建
</a-button>
<a-button
v-if="!props.isCreate"
type="outline"
size="small"
:style="{ marginRight: '10px', padding: '7px' }"
@click="handleClick"
>
<template #icon><icon-edit /></template>
修改
</a-button>
<a-modal
width="900px"
height="500px"
:visible="visible"
@cancel="handleCancel"
>
<template #title>{{ modalTitle }}</template>
<a-form
ref="CreateRef"
:model="formData"
:style="{ width: '800px',height: '420px' }"
>
<!-- 产品名称 -->
<a-form-item
field="name"
label='产品名称'
:rules="[{ required: true, message: '产品名称不能为空' }]"
:validate-trigger="['change']"
>
<a-input
v-model="formData.name"
placeholder='请输入产品名称'
/>
</a-form-item>
<!-- 产品分类-->
<a-form-item
field="productType"
label="产品分类"
:rules="[{ required: true, message: '产品分类不能为空' }]"
:validate-trigger="['change']"
>
<a-input
v-model="formData.productType"
placeholder='请选择产品分类'
/>
</a-form-item>
<!-- 产品类型 -->
<a-form-item
field="model"
label="类型"
:rules="[{ required: true, message: '产品类型不能为空' }]"
:validate-trigger="['change']"
>
<a-input
v-model="formData.model"
placeholder='请输入产品类型'
/>
</a-form-item>
<!-- 接入方式 -->
<a-form-item
field="link"
label="接入"
:rules="[{ required: true, message: '接入方式不能为空' }]"
:validate-trigger="['change']"
>
<a-select
v-model="formData.link"
placeholder='请输入接入方式'
:options="linkOptions"
allow-search
/>
</a-form-item>
<!-- 备注 -->
<a-form-item
field="remark"
label="备注"
>
<a-input
v-model="formData.remark"
placeholder='请输入备注'
/>
</a-form-item>
<!-- 参数 -->
<a-form-item
field="params"
label="参数"
>
<!-- <a-table-->
<!-- :columns="columns"-->
<!-- :data="paramsData"-->
<!-- :bordered="false"-->
<!-- :pagination="false"-->
<!-- :table-layout-fixed="true"-->
<!-- :show-header="false"-->
<!-- :hoverable="false"-->
<!-- :column-resizable="true"-->
<!-- :filter-icon-align-left="true"-->
<!-- :body-cell-class="{ padding: '0px',marginLeft: '-10px' }"-->
<!-- >-->
<!-- <template #name="{ record }">-->
<!-- <a-input-->
<!-- v-model="record.name"-->
<!-- placeholder="名称"-->
<!-- />-->
<!-- </template>-->
<!-- <template #identifier="{ record }">-->
<!-- <a-input-->
<!-- v-model="record.identifier"-->
<!-- placeholder="标识"-->
<!-- />-->
<!-- </template>-->
<!-- <template #dataType="{ record }">-->
<!-- <a-select-->
<!-- v-model="record.dataType"-->
<!-- :options="dataTypeOptions"-->
<!-- allow-search-->
<!-- />-->
<!-- </template>-->
<!-- <template #type="{ record }">-->
<!-- <a-select-->
<!-- v-model="record.type"-->
<!-- :options="typeOptions"-->
<!-- allow-search-->
<!-- />-->
<!-- </template>-->
<!-- <template #operation="{ record }">-->
<!-- <a-button type="text" @click="handleDeleteParams(record)"><icon-minus-circle /></a-button>-->
<!-- </template>-->
<!-- <template #footer>-->
<!-- <a-button @click="handleAddParams" style="width: 100%" >-->
<!-- <icon-plus />-->
<!-- </a-button>-->
<!-- </template>-->
<!-- </a-table>-->
<div style="width: 100%">
<div style="width: 100%;margin-bottom: 5px; ">
<a-space v-for="(param,index) in paramsData" :key="index" style="margin-bottom: 5px">
<a-input v-model="param.name" placeholder="名称" allow-clear />
<a-input v-model="param.identifier" placeholder="标识" allow-clear />
<a-select v-model="param.dataType" :options="dataTypeOptions" allow-search />
<a-select v-model="param.type" :options="typeOptions" allow-search />
<a-button type="text" @click="handleDeleteParams(index)"><icon-minus-circle /></a-button>
</a-space>
</div>
<a-button @click="handleAddParams" style="width: 100%" type="outline">
<icon-plus />
</a-button>
</div>
</a-form-item>
</a-form>
<template #footer>
<a-button class="editor-button" @click="handleCancel">取消</a-button>
<a-button class="editor-button" type="primary" @click="handleSubmit">确定</a-button>
</template>
</a-modal>
<a-modal
width="900px"
:visible="paramsVisible"
@cancel="paramsCancel"
>
<template #title>添加参数</template>
<a-form
ref="CreateRef"
:model="paramsData"
:style="{ width: '650px' }"
>
<!-- 添加参数 -->
<a-form-item
field="name"
label="参数名称"
:rules="[{ required: true, message: '参数名称不能为空' }]"
:validate-trigger="['change']"
>
<a-input
v-model="paramsData.name"
placeholder='请选择参数名称'
/>
</a-form-item>
<!-- 参数标识 -->
<a-form-item
field="identifier"
label="参数标识"
:rules="[{ required: true, message: '参数标识不能为空' }]"
:validate-trigger="['change']"
>
<a-input
v-model="paramsData.identifier"
placeholder='请选择参数标识'
/>
</a-form-item>
<a-form-item
field="dataType"
label="数据类型"
:rules="[{ required: true, message: '数据类型不能为空' }]"
:validate-trigger="['change']"
>
<a-select
v-model="paramsData.dataType"
placeholder='请输入数据类型'
:options="dataTypeOptions"
allow-search
/>
</a-form-item>
<a-form-item
field="type"
label="参数类型"
:rules="[{ required: true, message: '参数类型不能为空' }]"
:validate-trigger="['change']"
>
<a-select
v-model="paramsData.type"
placeholder='请输入参数类型'
:options="typeOptions"
allow-search
/>
</a-form-item>
</a-form>
<template #footer>
<a-button class="editor-button" @click="paramsCancel">取消</a-button>
<a-button class="editor-button" type="primary" @click="paramsSubmit">确定</a-button>
</template>
</a-modal>
</template>
<script lang="ts" setup>
import useVisible from '@/hooks/visible';
import { computed, defineEmits, onMounted, PropType, ref } from 'vue';
import { FormInstance } from '@arco-design/web-vue/es/form';
import { Message } from '@arco-design/web-vue';
import '@wangeditor/editor/dist/css/style.css'
import type { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
import { createProduct, ProductCreateRecord, queryProductDetail, updateProduct } from '@/api/product';
const props = defineProps({
prem: {
type: Object as PropType<ProductCreateRecord>,
},
isCreate: Boolean,
id: Number,
});
const emit = defineEmits(['refresh']);
const modalTitle = computed(() => {
return props.isCreate ? '创建产品' : '编辑产品';
});
const { visible, setVisible } = useVisible(false);
const CreateRef = ref<FormInstance>();
const formData = ref<any>({
// params: [],
// ...props.prem,
});
const columns=[
{
title: '参数名称',
dataIndex: 'name',
slotName: 'name',
width: '120',
},
{
title: '参数标识',
dataIndex: 'identifier',
slotName: 'identifier',
width: '120',
align: 'left'
},
{
title: '数据类型',
dataIndex: 'dataType',
slotName: 'dataType',
width: '150',
align: 'left'
},
{
title: '参数类型',
dataIndex: 'type',
slotName: 'type',
width: '180',
align: 'left'
},
{
title: '操作',
dataIndex: 'operation',
slotName: 'operation',
align: 'left'
}
];
const paramsData = ref([
{
name: '',
identifier: '',
dataType: '',
type: '',
},
]);
const linkOptions = computed<SelectOptionData[]>(() => [
{
label: 'TCP',
value: 'TCP',
},
{
label: 'HTTP',
value: 'HTTP',
},
{
label: 'MQTT',
value: 'MQTT',
},
]);
const dataTypeOptions = computed<SelectOptionData[]>(() => [
{
label: '整型',
value: 'INT',
},
{
label: '单精度浮点型',
value: 'FLOAT',
},
{
label: '双精度浮点型',
value: 'DOUBLE',
},
{
label: '布尔型',
value: 'BOOLEAN',
},
{
label: '字符串',
value: 'STRING',
},
{
label: '日期型',
value: 'DATE',
},
{
label: '透传',
value: 'RAW',
},
]);
const typeOptions = computed<SelectOptionData[]>(() => [
{
label: '物模型输入',
value: 'INPUT',
},
{
label: '物模型输出',
value: 'OUTPUT',
},
{
label: '读写属性',
value: 'RW',
},
]);
const paramsVisible = ref(false);
const paramsName = ref([]);
const fetchData = async (Id: number | undefined) => {
const res = await queryProductDetail(Id);
formData.value = res.data;
};
//
const handleClick = () => {
setVisible(true);
if (!props.isCreate) {
fetchData(props.id);
}
};
//
const handleSubmit = async () => {
const valid = await CreateRef.value?.validate();
if (!valid) {
//
if (props.isCreate) {
formData.value.params = paramsData.value;
// formData.value.username = formData.value.email;
const res = await createProduct(formData.value);
if (res.status === 200) {
Message.success({
content: '新建成功',
duration: 5 * 1000,
});
emit('refresh');
setVisible(false);
}
CreateRef.value?.resetFields();
} else {
//
const res = await updateProduct(formData.value);
if (res.status === 200) {
Message.success({
content: '修改成功',
duration: 5 * 1000,
});
emit('refresh');
setVisible(false);
}
}
}
};
//
const handleAddParams = () => {
// paramsVisible.value = true;
paramsData.value.push({
name: '',
identifier: '',
dataType: '',
type: '',
});
};
//
const handleDeleteParams = (record: any) => {
if (record !== -1) {
paramsData.value.splice(record, 1);
}
};
//
const paramsCancel = () => {
paramsVisible.value = false;
};
//
const paramsSubmit = () => {
paramsVisible.value = false;
formData.value.params.push(paramsData.value);
paramsName.value.push(paramsData.value.name);
}
//
const handleCancel = async () => {
setVisible(false);
};
</script>
<style scoped>
.editor-button{
position: static
}
</style>

View File

@ -0,0 +1,648 @@
<template>
<div class="container">
<Breadcrumb :items="['物联网管理', '产品管理', '物模型']" />
<a-card class="general-card" title=" " style="height: 50px">
<h3 style="margin-top: -24px">物模型</h3>
</a-card>
<a-card class="general-card" style="margin-top: 10px;padding-top: 20px">
<a-tabs type="rounded" position="left" size="large" @change="changeKey" animation style="">
<a-tab-pane key="1" title="属性">
<a-button type="primary" style="margin-bottom: 10px" @click="handleClick">
<template #icon><icon-plus /></template>
新建
</a-button>
<a-table :columns="columns" :data="propertyData" >
<template #operation="{ record }">
<a-button
type="outline"
status="danger"
size="small"
style="padding: 7px;margin-right: 10px"
@click="handleDeleteProperty(record)"
>
<template #icon><icon-delete /></template>
删除
</a-button>
</template>
</a-table>
</a-tab-pane>
<a-tab-pane key="2" title="服务">
<a-button type="primary" style="margin-bottom: 10px" @click="handleClick">
<template #icon><icon-plus /></template>
新建
</a-button>
<a-table :columns="columns" :data="serveData" >
<template #operation="{ record }">
<a-button
type="outline"
status="danger"
size="small"
style="padding: 7px;margin-right: 10px"
@click="handleDeleteServe(record)"
>
<template #icon><icon-delete /></template>
删除
</a-button>
</template>
</a-table>
</a-tab-pane>
<a-tab-pane key="3" title="事件">
<a-button type="primary" style="margin-bottom: 10px" @click="handleClick">
<template #icon><icon-plus /></template>
新建
</a-button>
<a-table :columns="columns" :data="eventData" >
<template #operation="{ record }">
<a-button
type="outline"
status="danger"
size="small"
style="padding: 7px;margin-right: 10px"
@click="handleDeleteEvent(record)"
>
<template #icon><icon-delete /></template>
删除
</a-button>
</template>
</a-table>
</a-tab-pane>
</a-tabs>
</a-card>
</div>
<a-modal
width="900px"
height="500px"
:visible="visible && keyValue==='1'"
@cancel="handleCancel"
>
<template #title>新建属性</template>
<a-form
ref="propertyCreateRef"
:model="propertyAddData"
:style="{ width: '650px' }"
>
<!-- 设备名称 -->
<a-form-item
field="name"
label="属性名称"
:rules="[{ required: true, message: '设备名称不能为空' }]"
:validate-trigger="['change']"
>
<a-input
v-model="propertyAddData.name"
placeholder='请输入设备名称'
/>
</a-form-item>
<!-- 标识 -->
<a-form-item
field="identifier"
label="标识"
:rules="[{ required: true, message: '标识不能为空' }]"
:validate-trigger="['change']"
>
<a-input
v-model="propertyAddData.identifier"
placeholder='请输入标识'
/>
</a-form-item>
<!-- 数据类型 -->
<a-form-item
field="dataType"
label="数据类型"
:rules="[{ required: true, message: '数据类型不能为空' }]"
:validate-trigger="['change']"
>
<a-select v-model="propertyAddData.dataType" :options="dataTypeOptions" allow-search placeholder="请选择数据类型"/>
</a-form-item>
<!-- 读写类型 -->
<a-form-item
field="ioType"
label="读写类型"
>
<a-radio-group v-model="propertyAddData.ioType">
<a-radio value="1">读写</a-radio>
<a-radio value="2">只读</a-radio>
</a-radio-group>
</a-form-item>
<!-- 备注 -->
<a-form-item
field="remark"
label="备注"
>
<a-textarea
v-model="propertyAddData.remark"
placeholder='请输入备注'
/>
</a-form-item>
</a-form>
<template #footer>
<a-button class="editor-button" @click="handleCancel">取消</a-button>
<a-button class="editor-button" type="primary" @click="handleSubmit">确定</a-button>
</template>
</a-modal>
<a-modal
width="900px"
height="500px"
:visible="visible && keyValue==='2'"
@cancel="handleCancel"
>
<template #title>新建服务</template>
<a-form
ref="serveCreateRef"
:model="serveAddData"
:style="{ width: '650px' }"
>
<!-- 服务名称 -->
<a-form-item
field="name"
label="服务名称"
:rules="[{ required: true, message: '服务名称不能为空' }]"
:validate-trigger="['change']"
>
<a-input
v-model="serveAddData.name"
placeholder='请输入服务名称'
/>
</a-form-item>
<!-- 标识 -->
<a-form-item
field="identifier"
label="标识"
:rules="[{ required: true, message: '标识不能为空' }]"
:validate-trigger="['change']"
>
<a-input
v-model="serveAddData.identifier"
placeholder='请输入标识'
/>
</a-form-item>
<!-- 输入参数 -->
<a-form-item
field="inputs"
label="输入参数"
>
<div style="width: 100%">
<div style="width: 100%;margin-bottom: 5px; ">
<a-space v-for="(param,index) in serveInputData" :key="index" style="margin-bottom: 5px">
<a-input v-model="param.name" placeholder="名称" allow-clear />
<a-input v-model="param.identifier" placeholder="标识" allow-clear />
<a-select v-model="param.dataType" :options="dataTypeOptions" allow-search placeholder="数据类型" />
<a-select v-model="param.type" :options="typeOptions" allow-search placeholder="类型"/>
<a-button type="text" @click="handleDeleteParams(index,'serveInputData')"><icon-minus-circle /></a-button>
</a-space>
</div>
<a-button @click="handleAddParams('serveInputData')" style="width: 100%" type="outline">
<icon-plus />
</a-button>
</div>
</a-form-item>
<!-- 输出参数 -->
<a-form-item
field="outputs"
label="输出参数"
>
<div style="width: 100%">
<div style="width: 100%;margin-bottom: 5px; ">
<a-space v-for="(param,index) in serveOutputData" :key="index" style="margin-bottom: 5px">
<a-input v-model="param.name" placeholder="名称" allow-clear />
<a-input v-model="param.identifier" placeholder="标识" allow-clear />
<a-select v-model="param.dataType" :options="dataTypeOptions" allow-search placeholder="数据类型"/>
<a-select v-model="param.type" :options="typeOptions" allow-search placeholder="类型"/>
<a-button type="text" @click="handleDeleteParams(index,'serveOutputData')"><icon-minus-circle /></a-button>
</a-space>
</div>
<a-button @click="handleAddParams('serveOutputData')" style="width: 100%" type="outline">
<icon-plus />
</a-button>
</div>
</a-form-item>
<!-- 备注 -->
<a-form-item
field="remark"
label="备注"
>
<a-textarea
v-model="serveInputData.remark"
placeholder='请输入备注'
/>
</a-form-item>
</a-form>
<template #footer>
<a-button class="editor-button" @click="handleCancel">取消</a-button>
<a-button class="editor-button" type="primary" @click="handleSubmit">确定</a-button>
</template>
</a-modal>
<a-modal
width="900px"
height="500px"
:visible="visible && keyValue==='3'"
@cancel="handleCancel"
>
<template #title>新建事件</template>
<a-form
ref="eventCreateRef"
:model="eventAddData"
:style="{ width: '650px' }"
>
<!-- 事件名称 -->
<a-form-item
field="name"
label="服务名称"
:rules="[{ required: true, message: '服务名称不能为空' }]"
:validate-trigger="['change']"
>
<a-input
v-model="eventAddData.name"
placeholder='请输入服务名称'
/>
</a-form-item>
<!-- 标识 -->
<a-form-item
field="identifier"
label="标识"
:rules="[{ required: true, message: '标识不能为空' }]"
:validate-trigger="['change']"
>
<a-input
v-model="eventAddData.identifier"
placeholder='请输入标识'
/>
</a-form-item>
<!-- 类型 -->
<a-form-item
field="type"
label="类型"
:rules="[{ required: true, message: '类型不能为空' }]"
:validate-trigger="['change']"
>
<a-input
v-model="eventAddData.type"
placeholder='请输入类型'
/>
</a-form-item>
<!-- 输出参数 -->
<a-form-item
field="outputs"
label="输出参数"
>
<div style="width: 100%">
<div style="width: 100%;margin-bottom: 5px; ">
<a-space v-for="(param,index) in eventOutputData" :key="index" style="margin-bottom: 5px">
<a-input v-model="param.name" placeholder="名称" allow-clear />
<a-input v-model="param.identifier" placeholder="标识" allow-clear />
<a-select v-model="param.dataType" :options="dataTypeOptions" allow-search placeholder="数据类型"/>
<a-select v-model="param.type" :options="typeOptions" allow-search placeholder="类型"/>
<a-button type="text" @click="handleDeleteParams(index,'eventOutputData')"><icon-minus-circle /></a-button>
</a-space>
</div>
<a-button @click="handleAddParams('eventOutputData')" style="width: 100%" type="outline">
<icon-plus />
</a-button>
</div>
</a-form-item>
<!-- 备注 -->
<a-form-item
field="remark"
label="备注"
>
<a-textarea
v-model="eventAddData.remark"
placeholder='请输入备注'
/>
</a-form-item>
</a-form>
<template #footer>
<a-button class="editor-button" @click="handleCancel">取消</a-button>
<a-button class="editor-button" type="primary" @click="handleSubmit">确定</a-button>
</template>
</a-modal>
</template>
<script lang="ts" setup>
import { useRoute } from 'vue-router';
import { computed, onMounted, ref } from 'vue';
import useVisible from '@/hooks/visible';
import {
createEvent,
createProperty,
createServe,
deleteEvent,
deleteProperty,
deleteServe,
queryEventList,
queryPropertyList,
queryServeList
} from '@/api/tsl';
import type { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
import { FormInstance } from '@arco-design/web-vue/es/form';
import { Message } from '@arco-design/web-vue';
const { visible, setVisible } = useVisible();
const route = useRoute();
const id = Number(route.params.id);
const columns = [
{
title: '名称',
dataIndex: 'name',
slotName: 'name',
},
{
title: '标识',
dataIndex: 'identifier',
slotName: 'identifier',
},
{
title: '备注',
dataIndex: 'remark',
slotName: 'remark',
},
{
title: '操作',
dataIndex: 'operation',
slotName: 'operation',
},
];
const serveData = ref([]);
const propertyData = ref([]);
const eventData = ref([]);
const keyValue = ref('1');
const paramsData = ref([]);
const dataTypeOptions = computed<SelectOptionData[]>(() => [
{
label: '整型',
value: 'INT',
},
{
label: '单精度浮点型',
value: 'FLOAT',
},
{
label: '双精度浮点型',
value: 'DOUBLE',
},
{
label: '布尔型',
value: 'BOOLEAN',
},
{
label: '字符串',
value: 'STRING',
},
{
label: '日期型',
value: 'DATE',
},
{
label: '透传',
value: 'RAW',
},
]);
const typeOptions = computed<SelectOptionData[]>(() => [
{
label: '物模型输入',
value: 'INPUT',
},
{
label: '物模型输出',
value: 'OUTPUT',
},
{
label: '读写属性',
value: 'RW',
},
]);
const propertyAddData = ref({
productId:id,
});
const eventAddData = ref({
productId:id,
outputs: [{
name: '',
identifier: '',
dataType: '',
type: '',
}],
});
const serveAddData = ref({
productId:id,
inputs: [{
name: '',
identifier: '',
dataType: '',
type: '',
}],
outputs: [{
name: '',
identifier: '',
dataType: '',
type: '',
}],
});
const serveInputData = ref([{
name: '',
identifier: '',
dataType: '',
type: '',
}]);
const serveOutputData = ref([{
name: '',
identifier: '',
dataType: '',
type: '',
}]);
const eventOutputData = ref([{
name: '',
identifier: '',
dataType: '',
type: '',
}]);
const propertyCreateRef = ref<FormInstance>();
const eventCreateRef = ref<FormInstance>();
const serveCreateRef = ref<FormInstance>();
const fetchData = async (Id: number) => {
const params={
size:10,
current:1,
productId:Id,
}
const res1 = await queryServeList(params);
serveData.value = res1.data.records;
const res2 = await queryPropertyList(params);
propertyData.value = res2.data.records;
const res3 = await queryEventList(params);
eventData.value = res3.data.records;
};
const changeKey= (e:any) =>{
keyValue.value = e;
}
//
const handleClick = () => {
setVisible(true);
};
//
const handleCancel = async () => {
setVisible(false);
};
//
const handleSubmit = async () => {
if(keyValue.value==='1'){
const valid = await propertyCreateRef.value?.validate();
if (!valid) {
const res = await createProperty(propertyAddData.value);
if (res.status === 200) {
Message.success({
content: '新建成功',
duration: 5 * 1000,
});
await fetchData(id);
setVisible(false);
}
}
} else if(keyValue.value==='2') {
const valid = await serveCreateRef.value?.validate();
if (!valid) {
serveAddData.value.inputs = serveInputData.value;
serveAddData.value.outputs = serveOutputData.value;
const res = await createServe(serveAddData.value);
if (res.status === 200) {
Message.success({
content: '新建成功',
duration: 5 * 1000,
});
await fetchData(id);
setVisible(false);
}
}
} else if(keyValue.value==='3') {
const valid = await eventCreateRef.value?.validate();
if (!valid) {
eventAddData.value.outputs = eventOutputData.value;
const res = await createEvent(eventAddData.value);
if (res.status === 200) {
Message.success({
content: '新建成功',
duration: 5 * 1000,
});
await fetchData(id);
setVisible(false);
}
}
}
};
//
const handleDeleteParams = (record: any,data: string) => {
console.log(record);
if (record !== -1 && data==='serveInputData') {
serveInputData.value.splice(record, 1);
} else if (record!== -1 && data==='serveOutputData') {
serveOutputData.value.splice(record, 1);
} else if (record!== -1 && data==='eventOutputData') {
eventOutputData.value.splice(record, 1);
}
};
//
const handleAddParams = (data:string) => {
console.log(data);
if(data==='serveInputData'){
serveInputData.value.push({
name: '',
identifier: '',
dataType: '',
type: '',
});
}else if(data==='serveOutputData') {
serveOutputData.value.push({
name: '',
identifier: '',
dataType: '',
type: '',
});
} else if(data==='eventOutputData') {
eventOutputData.value.push({
name: '',
identifier: '',
dataType: '',
type: '',
});
}
};
//
const handleDeleteProperty = async (record: any) => {
const res = await deleteProperty(record.id);
console.log(res);
if (res.status === 200) {
Message.success({
content: '删除成功',
duration: 5 * 1000,
});
await fetchData(id);
}
};
//
const handleDeleteServe = async (record: any) => {
console.log(record);
const res = await deleteServe(record.id);
if (res.status === 200) {
Message.success({
content: '删除成功',
duration: 5 * 1000,
});
await fetchData(id);
}
};
//
const handleDeleteEvent = async (record: any) => {
const res = await deleteEvent(record.id);
if (res.status === 200) {
Message.success({
content: '删除成功',
duration: 5 * 1000,
});
await fetchData(id);
}
};
onMounted(() => {
fetchData(id);
});
</script>
<style scoped>
.container {
padding: 0 20px 20px 20px;
}
h1 {
font-size: 24px;
margin-bottom: 10px;
}
.meta span {
margin-right: 20px;
}
.attachments li {
margin-bottom: 10px;
}
.attachments a {
display: flex;
align-items: center;
font-size: 14px;
color: #1890ff;
text-decoration: none;
}
.attachments a:hover {
text-decoration: underline;
}
</style>

View File

@ -172,6 +172,16 @@
<template #icon><icon-list /></template>
详情
</a-button>
<a-button
type="outline"
size="small"
status="warning"
style="padding: 7px; margin-right: 10px"
@click="openTsl(record.id)"
>
<template #icon><icon-list /></template>
物模型
</a-button>
<ProductEdit
:id="record.id"
ref="editUserRef"
@ -339,6 +349,15 @@
router.push(url);
};
//
function openTsl(id:number): void{
const url = router.resolve({
name: 'productTsl',
params: {id}
}).href;
router.push(url);
};
//
const handleDelete = async (id: number) => {
const res = await deleteProduct(id);

View File

@ -134,11 +134,12 @@
<a-card style="margin-right: 10px;width: 30%">
<a-tree
:data="deptTreeData"
checkable="true"
:field-names="{ title: 'name', key: 'id', children: 'children' }"
style="margin-bottom: 8px; max-width: 240px"
@select="handleClickTree"
@check="handleCheckTree"
/>
>
</a-tree>
</a-card>
<a-card style="flex: 1">
<a-button type="primary" >全选</a-button>
@ -146,11 +147,11 @@
:data="selectedDepartmentMembers"
:columns="columns"
style="height: 520px">
<template #key="{ record }">
<a-checkbox v-model="selectedIds" :value="record.key"> </a-checkbox>
<template #id="{ record }">
<a-checkbox v-model="selectedIds" :value="record.id"> </a-checkbox>
</template>
<template #title="{ record }">
{{ record.title }}
<template #username="{ record }">
{{ record.username }}
</template>
</a-table>
</a-card>
@ -165,7 +166,7 @@
<script lang="ts" setup>
import useVisible from '@/hooks/visible';
import { computed, defineEmits, PropType, ref, shallowRef, onBeforeUnmount, reactive } from 'vue';
import { computed, defineEmits, PropType, ref, shallowRef, onBeforeUnmount, reactive, onMounted } from 'vue';
import { CreateRecord } from '@/api/user';
import { FormInstance } from '@arco-design/web-vue/es/form';
import { Message } from '@arco-design/web-vue';
@ -174,6 +175,7 @@
import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
import { IEditorConfig } from '@wangeditor/editor'
import '@wangeditor/editor/dist/css/style.css'
import { getAllDeptTree } from '@/api/dept';
const props = defineProps({
prem: {
@ -205,12 +207,12 @@
const columns = computed<any[]>(()=>[
{
title: '操作',
dataIndex: 'key',
slotName: 'key',
dataIndex: 'id',
slotName: 'id',
},
{
title: '用户',
dataIndex: 'title',
dataIndex: 'username',
},
])
@ -253,33 +255,33 @@
// },
// },
// );
const deptTreeData = reactive([
const deptTreeData = ref([
{
key: '1',
title: '总部门',
id: '1',
name: '总部门',
children: [
{
key: '2',
title: '部门1',
id: '2',
name: '部门1',
members: [
{ key: '101', title: '成员1' },
{ key: '102', title: '成员2' }
{ id: '101', username: '成员1' },
{ id: '102', username: '成员2' }
]
},
{
key: '3',
title: '部门2',
id: '3',
name: '部门2',
members: [
{ key: '201', title: '成员3' },
{ key: '202', title: '成员4' }
{ id: '201', username: '成员3' },
{ id: '202', username: '成员4' }
]
},
{
key: '4',
title: '部门3',
id: '4',
name: '部门3',
members: [
{ key: '203', title: '成员5' },
{ key: '204', title: '成员6' }
{ id: '203', username: '成员5' },
{ id: '204', username: '成员6' }
]
}
]
@ -287,6 +289,13 @@
]);
const selectedDepartmentMembers: any = ref([]);
const renderData = ref<any[]>([]);
//
const getDeptTree = async () => {
const res = await getAllDeptTree(1);
if (res.status === 200) {
deptTreeData.value = res.data;
}
}
//
const queryDeptTree= async ()=>{
deptVisible.value = true;
@ -299,7 +308,7 @@
while (queue.length > 0) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const node = queue.shift()!;
if (selectedKeys.includes(node.key)) {
if (selectedKeys.includes(node.id)) {
if (node.members) {
selectedMembers.push(...node.members);
}
@ -313,12 +322,12 @@
//
const handleClickTree = (key: string[]) => {
const handleClickTree = (id: string[]) => {
// '1'
if (key[0] === '1' || key.length === 0) {
if (id[0] === '1' || id.length === 0) {
// 广
const allMembers: any[] = [];
const queue:any = [...deptTreeData];
const queue:any = [...deptTreeData.value];
while (queue.length > 0) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const node = queue.shift()!;
@ -333,17 +342,17 @@
renderData.value = selectedDepartmentMembers.value;
return;
}
const Members = getSelectedMembers(deptTreeData, key);
const Members = getSelectedMembers(deptTreeData.value, id);
selectedDepartmentMembers.value = Members;
}
//
const handleCheckTree = (key: string[]) => {
if (key[0] === '1' ) { // '1'
const handleCheckTree = (id: string[]) => {
if (id[0] === '1' ) { // '1'
const allKeys: string[] = [];
const traverseTree = (node: any) => {
if (node.members) {
node.members.forEach((member: any) => {
allKeys.push(member.key);
allKeys.push(member.id);
});
}
if (node.children) {
@ -352,14 +361,14 @@
});
}
};
deptTreeData.forEach((node: any) => {
deptTreeData.value.forEach((node: any) => {
traverseTree(node);
});
selectedIds.value = allKeys;
} else {
const selectedKeys = getSelectedMembers(deptTreeData, key);
selectedIds.value = selectedKeys.map(item => item.key);
const selectedKeys = getSelectedMembers(deptTreeData.value, id);
selectedIds.value = selectedKeys.map(item => item.id);
}
};
@ -423,6 +432,9 @@
const deptTreeCancel = () => {
deptVisible.value = false;
};
onMounted(async () => {
await getDeptTree();
});
</script>
<style scoped>