perf(物联网产品,设备,物模型模块): 优化物联网管理整个模块代码及其它模块bug

This commit is contained in:
Kven 2025-01-09 15:28:27 +08:00
parent 47f226e019
commit 803ce3dfa6
22 changed files with 293 additions and 177 deletions

View File

@ -1,4 +1,5 @@
import axios from 'axios'; import axios from 'axios';
import dashboard from '@/router/routes/modules/dashboard';
export interface DeviceRecord { export interface DeviceRecord {
size: number; size: number;
@ -17,7 +18,7 @@ export interface DeviceCreateRecord {
name?: string; name?: string;
hardwareVersion: string; hardwareVersion: string;
firmwareVersion: string; firmwareVersion: string;
extendParams: string; extendParams: string[];
properties: string; properties: string;
productId: number; productId: number;
} }
@ -46,6 +47,14 @@ export function queryDeviceList(data: DeviceRecord) {
export function queryDeviceDetail(id: number) { export function queryDeviceDetail(id: number) {
return axios.get(`/api/rest/device/${id}`); return axios.get(`/api/rest/device/${id}`);
} }
// 名称模糊查询
export function queryDeviceByName(data: any) {
return axios({
url: `/api/rest/product/fuzzy`,
method: 'get',
params: data,
});
}
// 新增 // 新增
export function createDevice(data: DeviceCreateRecord) { export function createDevice(data: DeviceCreateRecord) {
@ -54,7 +63,7 @@ export function createDevice(data: DeviceCreateRecord) {
// 修改 // 修改
export function updateDevice(data:DeviceUpdateRecord) { export function updateDevice(data:DeviceUpdateRecord) {
return axios.put(`/api/rest/device/${data.id}`, data); return axios.patch(`/api/rest/device/${data.id}`, data);
} }
// 删除 // 删除
export function deleteDevice(id: number) { export function deleteDevice(id: number) {

View File

@ -26,25 +26,25 @@ export interface MessageCreateRecord {
// 查看详情 // 查看详情
export function queryMessage(userId: number, messageId: number) { export function queryMessage(userId: number, messageId: number) {
return axios.get(`/api/rest/message/${userId}/${messageId}`); return axios.get(`/api/rest/notice/${userId}/${messageId}`);
} }
// 分页查询 // 分页查询
export function queryMessageList(data: MessageRecord) { export function queryMessageList(data: MessageRecord) {
return axios({ return axios({
url: '/api/rest/message', url: '/api/rest/notice',
method: 'get', method: 'get',
params: data, params: data,
}); });
} }
// 创建消息 // 创建消息
export function createMessage(data: MessageCreateRecord) { export function createMessage(data: MessageCreateRecord) {
return axios.post('/api/rest/message', data); return axios.post('/api/rest/notice', data);
} }
// 获取消息推送方式 // 获取消息推送方式
export function getMessageTypes() { export function getMessageTypes() {
return axios.get('/api/rest/message/setting'); return axios.get('/api/rest/notice/setting');
} }
// 设置消息推送方式 // 设置消息推送方式
export function setMessageTypes(data: string[]) { export function setMessageTypes(data: string[]) {
return axios.patch('/api/rest/message/setting', data); return axios.patch('/api/rest/notice/setting', data);
} }

View File

@ -49,7 +49,7 @@ export interface MessagesRecord {
} }
export interface MessageStatus { export interface MessageStatus {
ids: string[]; ids: number[];
} }
export type MessageListType = MessagesList[]; export type MessageListType = MessagesList[];

View File

@ -6,7 +6,7 @@
<span> {{ item.title }}{{ formatUnreadLength(item.key) }} </span> <span> {{ item.title }}{{ formatUnreadLength(item.key) }} </span>
</template> </template>
<a-result v-if="!renderList.length" status="404"> <a-result v-if="!renderList.length" status="404">
<template #subtitle> {{ $t('messageBox.noContent') }} </template> <template #subtitle> 暂无内容 </template>
</a-result> </a-result>
<List <List
:render-list="renderList" :render-list="renderList"

View File

@ -150,9 +150,9 @@
</a-tooltip> </a-tooltip>
</li> </li>
<li> <!-- <li>-->
<a-button status="normal">{{ userStore.permissions }}</a-button> <!-- <a-button status="normal">{{ userStore.permissions }}</a-button>-->
</li> <!-- </li>-->
<li> <li>
<a-dropdown trigger="click"> <a-dropdown trigger="click">
<a-avatar <a-avatar

View File

@ -12,6 +12,6 @@
"globalSettings": false, "globalSettings": false,
"device": "desktop", "device": "desktop",
"tabBar": false, "tabBar": false,
"menuFromServer": true, "menuFromServer": false,
"serverMenu": [] "serverMenu": []
} }

View File

@ -5,11 +5,11 @@ import { intersection } from 'lodash';
function checkPermission(el: HTMLElement, binding: DirectiveBinding) { function checkPermission(el: HTMLElement, binding: DirectiveBinding) {
const { value } = binding; const { value } = binding;
const userStore = useUserStore(); const userStore = useUserStore();
const { authorities } = userStore; const { permissions } = userStore;
if (Array.isArray(value)) { if (Array.isArray(value)) {
if (value.length > 0) { if (value.length > 0) {
const hasPermission = intersection(value, authorities).length > 0; const hasPermission = intersection(value, permissions).length > 0;
if (!hasPermission && el.parentNode) { if (!hasPermission && el.parentNode) {
el.parentNode.removeChild(el); el.parentNode.removeChild(el);

View File

@ -7,6 +7,7 @@ const DASHBOARD: AppRouteRecordRaw = {
component: DEFAULT_LAYOUT, component: DEFAULT_LAYOUT,
meta: { meta: {
locale: 'menu.dashboard', locale: 'menu.dashboard',
title: '首页',
requiresAuth: true, requiresAuth: true,
icon: 'icon-dashboard', // 设置图标 icon: 'icon-dashboard', // 设置图标
order: 0, // 排序路由菜单项。如果设置该值,值越高,越靠前 order: 0, // 排序路由菜单项。如果设置该值,值越高,越靠前
@ -17,7 +18,8 @@ const DASHBOARD: AppRouteRecordRaw = {
name: 'Workplace', name: 'Workplace',
component: () => import('@/views/dashboard/workplace/index.vue'), component: () => import('@/views/dashboard/workplace/index.vue'),
meta: { meta: {
locale: 'menu.dashboard.workplace', locale:'menu.dashboard.workplace',
title: '工作台',
requiresAuth: true, requiresAuth: true,
permissions: ['*'], permissions: ['*'],
}, },

View File

@ -18,7 +18,7 @@ const IOT: AppRouteRecordRaw = {
name: 'Product', name: 'Product',
component: () => import('@/views/iot/product/index.vue'), component: () => import('@/views/iot/product/index.vue'),
meta: { meta: {
// locale: 'menu.system.dept', locale: 'menu.system.product',
title: '产品管理', title: '产品管理',
requiresAuth: true, requiresAuth: true,
permissions: ['*'], permissions: ['*'],
@ -29,7 +29,7 @@ const IOT: AppRouteRecordRaw = {
name: 'Device', name: 'Device',
component: () => import('@/views/iot/device/index.vue'), component: () => import('@/views/iot/device/index.vue'),
meta: { meta: {
// locale: 'menu.system.role', locale: 'menu.system.device',
title: '设备管理', title: '设备管理',
requiresAuth: true, requiresAuth: true,
permissions: ['*'], permissions: ['*'],
@ -40,6 +40,7 @@ const IOT: AppRouteRecordRaw = {
name: 'productDetail', name: 'productDetail',
component: () => import('@/views/iot/product/components/product-detail.vue'), component: () => import('@/views/iot/product/components/product-detail.vue'),
meta: { meta: {
locale:'menu.system.product',
title: '产品详情', title: '产品详情',
requiresAuth: true, requiresAuth: true,
showInMenu: false, showInMenu: false,
@ -51,6 +52,7 @@ const IOT: AppRouteRecordRaw = {
name: 'deviceDetail', name: 'deviceDetail',
component: () => import('@/views/iot/device/components/device-detail.vue'), component: () => import('@/views/iot/device/components/device-detail.vue'),
meta: { meta: {
locale: 'menu.system.deviceDetail',
title: '设备详情', title: '设备详情',
requiresAuth: true, requiresAuth: true,
showInMenu: false, showInMenu: false,
@ -62,6 +64,7 @@ const IOT: AppRouteRecordRaw = {
name: 'productTsl', name: 'productTsl',
component: () => import('@/views/iot/product/components/product-tsl.vue'), component: () => import('@/views/iot/product/components/product-tsl.vue'),
meta: { meta: {
locale: 'menu.system.productTsl',
title: '物模型', title: '物模型',
requiresAuth: true, requiresAuth: true,
showInMenu: false, showInMenu: false,

View File

@ -7,6 +7,7 @@ const NOTIFICATION: AppRouteRecordRaw = {
component: DEFAULT_LAYOUT, component: DEFAULT_LAYOUT,
meta: { meta: {
locale: '通知管理', locale: '通知管理',
title: '通知管理',
requiresAuth: true, requiresAuth: true,
icon: 'icon-message', // 设置图标 icon: 'icon-message', // 设置图标
order: 0, // 排序路由菜单项。如果设置该值,值越高,越靠前 order: 0, // 排序路由菜单项。如果设置该值,值越高,越靠前
@ -18,6 +19,7 @@ const NOTIFICATION: AppRouteRecordRaw = {
component: () => import('@/views/notification/notice/index.vue'), component: () => import('@/views/notification/notice/index.vue'),
meta: { meta: {
locale: '公告通知', locale: '公告通知',
title: '公告通知',
requiresAuth: true, requiresAuth: true,
permissions: ['*'], permissions: ['*'],
}, },
@ -28,6 +30,7 @@ const NOTIFICATION: AppRouteRecordRaw = {
component: () => import('@/views/notification/noticeSet/index.vue'), component: () => import('@/views/notification/noticeSet/index.vue'),
meta: { meta: {
locale: '公告管理', locale: '公告管理',
title: '公告管理',
requiresAuth: true, requiresAuth: true,
permissions: ['*'], permissions: ['*'],
}, },

View File

@ -27,6 +27,7 @@ const SYSTEM: AppRouteRecordRaw = {
name: 'Role', name: 'Role',
component: () => import('@/views/system/role/index.vue'), component: () => import('@/views/system/role/index.vue'),
meta: { meta: {
title: '角色管理',
requiresAuth: true, requiresAuth: true,
permissions: ['*'], permissions: ['*'],
}, },
@ -36,6 +37,7 @@ const SYSTEM: AppRouteRecordRaw = {
name: 'Dept', name: 'Dept',
component: () => import('@/views/system/dept/index.vue'), component: () => import('@/views/system/dept/index.vue'),
meta: { meta: {
title: '部门管理',
requiresAuth: true, requiresAuth: true,
permissions: ['*'], permissions: ['*'],
}, },
@ -45,14 +47,17 @@ const SYSTEM: AppRouteRecordRaw = {
name: 'User', name: 'User',
component: () => import('@/views/system/user/index.vue'), component: () => import('@/views/system/user/index.vue'),
meta: { meta: {
title: '用户管理',
requiresAuth: true, requiresAuth: true,
permissions: ['*'], permissions: ['*'],
}, },
}, },
{ {
path: 'authority', path: 'authority',
name: 'Authority',
component: () => import('@/views/system/authority/index.vue'), component: () => import('@/views/system/authority/index.vue'),
meta: { meta: {
title: '权限管理',
requiresAuth: true, requiresAuth: true,
permissions: ['*'], permissions: ['*'],
}, },

View File

@ -6,6 +6,11 @@ import useTabBarStore from './modules/tab-bar';
import useRoleStore from './modules/role'; import useRoleStore from './modules/role';
import useDeptStore from './modules/dept'; import useDeptStore from './modules/dept';
import useAuthStore from './modules/auth'; import useAuthStore from './modules/auth';
import useMessagesStore from './modules/messages';
import useBulletinsStore from './modules/bulletins';
import useMessageStore from './modules/message-mgmt';
import useBulletinStore from './modules/bulle-mgmt';
const pinia = createPinia(); const pinia = createPinia();
pinia.use(piniaPluginPersistedstate); pinia.use(piniaPluginPersistedstate);
@ -17,5 +22,9 @@ export {
useDeptStore, useDeptStore,
useRoleStore, useRoleStore,
useAuthStore, useAuthStore,
useMessagesStore,
useBulletinsStore,
useMessageStore,
useBulletinStore
}; };
export default pinia; export default pinia;

View File

@ -6,7 +6,7 @@ import {
queryDeptList, queryDeptList,
enabled, enabled,
remove, remove,
update, update, getAllDeptTree
} from '@/api/dept'; } from '@/api/dept';
import { deptStore } from './type'; import { deptStore } from './type';
@ -25,6 +25,11 @@ const useDeptStore = defineStore('dept', {
}, },
}, },
actions: { actions: {
// 获取所有部门树
async getAllDeptTree(id: number | string) {
return getAllDeptTree(id);
},
// 获取所有的角色列表 // 获取所有的角色列表
async getDeptList(data: DeptRecord) { async getDeptList(data: DeptRecord) {
return queryDeptList(data); return queryDeptList(data);

View File

@ -49,7 +49,6 @@ const useUserStore = defineStore('user', {
setInfo(partial: Partial<UserState>) { setInfo(partial: Partial<UserState>) {
this.$patch(partial); this.$patch(partial);
}, },
// Reset user's information // Reset user's information
resetInfo() { resetInfo() {
this.$reset(); this.$reset();

View File

@ -1,68 +1,68 @@
// // 新建 @/utils/excel.ts // 新建 @/utils/excel.ts
//
// import saveAs from 'file-saver'; // https://www.npmjs.com/package/file-saver import saveAs from 'file-saver'; // https://www.npmjs.com/package/file-saver
// import ExcelJS from 'exceljs'; // https://github.com/exceljs/exceljs/blob/master/README_zh.md import ExcelJS from 'exceljs'; // https://github.com/exceljs/exceljs/blob/master/README_zh.md
// import * as XLSX from 'xlsx'; // https://www.npmjs.com/package/xlsx import * as XLSX from 'xlsx'; // https://www.npmjs.com/package/xlsx
// import { Message } from '@arco-design/web-vue'; // https://arco.design/vue/component/message import { Message } from '@arco-design/web-vue'; // https://arco.design/vue/component/message
// import { FileItem } from '@arco-design/web-vue/es/upload/interfaces'; // arco类型 import { FileItem } from '@arco-design/web-vue/es/upload/interfaces'; // arco类型
//
// export interface DownloadExcelPrams { export interface DownloadExcelPrams {
// columns: { title: string; key: string }[]; columns: { title: string; key: string }[];
// rows: object[]; rows: object[];
// name: string; name: string;
// } }
//
// // 导出下载文件 // 导出下载文件
// export function downloadExcel({ export function downloadExcel({
// columns, columns,
// rows, rows,
// name = '未命名文件', name = '未命名文件',
// }: DownloadExcelPrams) { }: DownloadExcelPrams) {
// const workbook = new ExcelJS.Workbook(); const workbook = new ExcelJS.Workbook();
// workbook.creator = 'Start-front'; workbook.creator = 'Start-front';
// workbook.lastModifiedBy = 'Start-front'; workbook.lastModifiedBy = 'Start-front';
// workbook.created = new Date(1985, 8, 30); workbook.created = new Date(1985, 8, 30);
// workbook.modified = new Date(); workbook.modified = new Date();
// workbook.lastPrinted = new Date(2016, 9, 27); workbook.lastPrinted = new Date(2016, 9, 27);
//
// // 将工作簿添加一个sheet页sheet1 // 将工作簿添加一个sheet页sheet1
// const sheet1 = workbook.addWorksheet(name); const sheet1 = workbook.addWorksheet(name);
// // 表头数据添加 // 表头数据添加
// sheet1.columns = columns.map((item) => ({ sheet1.columns = columns.map((item) => ({
// header: item.title, header: item.title,
// key: item.key, key: item.key,
// width: 20, width: 20,
// })); }));
// // 表格内容添加 // 表格内容添加
// rows.map((item) => sheet1.addRow(item)); rows.map((item) => sheet1.addRow(item));
// workbook.xlsx.writeBuffer().then((buffer) => { workbook.xlsx.writeBuffer().then((buffer) => {
// saveAs( saveAs(
// new Blob([buffer], { type: 'application/octet-stream' }), new Blob([buffer], { type: 'application/octet-stream' }),
// `${name}.xlsx` `${name}.xlsx`
// ); );
// }); });
// } }
//
// // 读取文件为json格式 // 读取文件为json格式
// export function readExcle(fileItem: FileItem) { export function readExcle(fileItem: FileItem) {
// return new Promise((resove, reject) => { return new Promise((resove, reject) => {
// try { try {
// let workbook: XLSX.Sheet; let workbook: XLSX.Sheet;
// const reader = new FileReader(); const reader = new FileReader();
// reader.readAsBinaryString(fileItem.file as File); // 发起异步请求 reader.readAsBinaryString(fileItem.file as File); // 发起异步请求
// reader.onload = function (ev) { reader.onload = function (ev) {
// const data = ev.target?.result; const data = ev.target?.result;
// workbook = XLSX.read(data, { type: 'binary' }); workbook = XLSX.read(data, { type: 'binary' });
// const sheetNames = workbook.SheetNames; // 工作表名称集合 const sheetNames = workbook.SheetNames; // 工作表名称集合
// sheetNames.forEach((name: string) => { sheetNames.forEach((name: string) => {
// const worksheet = workbook.Sheets[name]; // 只能通过工作表名称来获取指定工作表 const worksheet = workbook.Sheets[name]; // 只能通过工作表名称来获取指定工作表
// const jsonres = XLSX.utils.sheet_to_json(worksheet); const jsonres = XLSX.utils.sheet_to_json(worksheet);
// resove(jsonres); resove(jsonres);
// }); });
// }; // onload }; // onload
// } catch (error) { } catch (error) {
// Message.error('读取失败,请选择正确文件'); Message.error('读取失败,请选择正确文件');
// reject(error); reject(error);
// } }
// }); });
// } }

View File

@ -16,6 +16,7 @@
<a-modal <a-modal
width="900px" width="900px"
height="500px"
:visible="visible" :visible="visible"
@cancel="handleCancel" @cancel="handleCancel"
> >
@ -23,23 +24,26 @@
<a-form <a-form
ref="CreateRef" ref="CreateRef"
:model="formData" :model="formData"
:style="{ width: '650px' }" :style="{ width: '800px', height: '420px' }"
> >
<!-- 产品id --> <!-- 产品id -->
<a-form-item <a-form-item
field="productId" field="productName"
label="产品名称" label="产品名称"
:rules="[{ required: true, message: '产品名称不能为空' }]" :rules="[{ required: true, message: '产品名称不能为空' }]"
:validate-trigger="['change']" :validate-trigger="['change']"
> >
<a-select <a-select
v-model="formData.productId" v-model="formData.productName"
placeholder="请选择产品名称" placeholder="请选择产品名称"
:loading="loading" :loading="loading"
:filter-option="false" :filter-option="false"
allow-search
@search="handleSearch" @search="handleSearch"
> >
<a-option v-for="item of options" :key="item.id" :value="item">{{item}}</a-option> <a-option v-for="item of options" :key="item.id" :value="item.name">{{
item.name
}}</a-option>
</a-select> </a-select>
</a-form-item> </a-form-item>
<!-- 设备名称 --> <!-- 设备名称 -->
@ -49,10 +53,7 @@
:rules="[{ required: true, message: '设备名称不能为空' }]" :rules="[{ required: true, message: '设备名称不能为空' }]"
:validate-trigger="['change']" :validate-trigger="['change']"
> >
<a-input <a-input v-model="formData.name" placeholder="请输入设备名称" />
v-model="formData.name"
placeholder='请输入设备名称'
/>
</a-form-item> </a-form-item>
<!-- 硬件版本 --> <!-- 硬件版本 -->
<a-form-item <a-form-item
@ -63,7 +64,7 @@
> >
<a-input <a-input
v-model="formData.hardwareVersion" v-model="formData.hardwareVersion"
placeholder='请输入硬件版本' placeholder="请输入硬件版本"
/> />
</a-form-item> </a-form-item>
<!-- 固件版本 --> <!-- 固件版本 -->
@ -75,29 +76,57 @@
> >
<a-input <a-input
v-model="formData.firmwareVersion" v-model="formData.firmwareVersion"
placeholder='请输入固件版本' placeholder="请输入固件版本"
/>
</a-form-item>
<a-form-item
field="remark"
label="备注"
>
<a-textarea
v-model="formData.remark"
placeholder="请输入描述"
/> />
</a-form-item> </a-form-item>
<!-- 扩展属性 --> <!-- 扩展属性 -->
<a-form-item <a-form-item field="extendParams" label="扩展属性">
field="extendParams" <!-- <a-input-->
label="扩展属性" <!-- v-model="formData.extendParams"-->
> <!-- placeholder='请输入扩展属性'-->
<!-- <a-input--> <!-- />-->
<!-- v-model="formData.extendParams"-->
<!-- placeholder='请输入扩展属性'-->
<!-- />-->
<div style="width: 100%"> <div style="width: 100%">
<div style="width: 100%;margin-bottom: 5px; "> <div style="width: 100%; margin-bottom: 5px">
<a-space v-for="(param,index) in paramsData" :key="index" style="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.name" placeholder="名称" allow-clear />
<a-input v-model="param.identifier" placeholder="标识" allow-clear /> <a-input
<a-select v-model="param.dataType" :options="dataTypeOptions" allow-search /> v-model="param.identifier"
<a-select v-model="param.type" :options="typeOptions" allow-search /> placeholder="标识"
<a-button type="text" @click="handleDeleteParams(index)"><icon-minus-circle /></a-button> allow-clear
/>
<a-select
v-model="param.dataType"
:options="dataTypeOptions"
allow-search
placeholder="数据类型"
style="width: 140px"
/>
<a-select
v-model="param.type"
:options="typeOptions"
allow-search
placeholder="类型"
style="width: 140px"
/>
<a-button type="text" @click="handleDeleteParams(index)"
><icon-minus-circle
/></a-button>
</a-space> </a-space>
</div> </div>
<a-button @click="handleAddParams" style="width: 100%" > <a-button type="outline" @click="handleAddParams" style="width: 100%">
<icon-plus /> <icon-plus />
</a-button> </a-button>
</div> </div>
@ -106,21 +135,30 @@
<template #footer> <template #footer>
<a-button class="editor-button" @click="handleCancel">取消</a-button> <a-button class="editor-button" @click="handleCancel">取消</a-button>
<a-button class="editor-button" type="primary" @click="handleSubmit">确定</a-button> <a-button class="editor-button" type="primary" @click="handleSubmit"
>确定</a-button
>
</template> </template>
</a-modal> </a-modal>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import useVisible from '@/hooks/visible'; import useVisible from '@/hooks/visible';
import { computed, defineEmits, PropType, ref, shallowRef, onBeforeUnmount, reactive } from 'vue'; import {
computed,
defineEmits,
PropType,
ref,
shallowRef,
onBeforeUnmount,
} from 'vue';
import { CreateRecord } from '@/api/user'; import { CreateRecord } from '@/api/user';
import { FormInstance } from '@arco-design/web-vue/es/form'; import { FormInstance } from '@arco-design/web-vue/es/form';
import { Message } from '@arco-design/web-vue'; import { Message } from '@arco-design/web-vue';
import { useMessageStore } from '@/store'; import '@wangeditor/editor/dist/css/style.css';
import '@wangeditor/editor/dist/css/style.css' import { createDevice, queryDeviceByName, queryDeviceDetail, updateDevice } from '@/api/device';
import { createDevice, updateDevice } from '@/api/device';
import type { SelectOptionData } from '@arco-design/web-vue/es/select/interface'; import type { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
import { queryProductDetail } from '@/api/product';
const props = defineProps({ const props = defineProps({
prem: { prem: {
@ -168,11 +206,11 @@
]); ]);
const typeOptions = computed<SelectOptionData[]>(() => [ const typeOptions = computed<SelectOptionData[]>(() => [
{ {
label: '物模型输入', label: '输入',
value: 'INPUT', value: 'INPUT',
}, },
{ {
label: '物模型输出', label: '输出',
value: 'OUTPUT', value: 'OUTPUT',
}, },
{ {
@ -191,22 +229,34 @@
const formData = ref<any>({ const formData = ref<any>({
...props.prem, ...props.prem,
}); });
const editorRef = shallowRef() const editorRef = shallowRef();
const options = ref(['Option1', 'Option2', 'Option3']); const options = ref();
const loading = ref(false); const loading = ref(false);
// //
const handleSearch = (value: any) => { const handleSearch = (value: any) => {
if (value) { if (value) {
loading.value = true; loading.value = true;
window.setTimeout(() => { options.value = [];
options.value = [`${value}-Option1`, `${value}-Option2`, `${value}-Option3`] window.setTimeout(async () => {
const res = await queryDeviceByName({
name: value,
page:1,
size: 10,
});
options.value = res.data.records.map((item: any) => {
return {
id: item.id,
name: item.name,
};
});
loading.value = false; loading.value = false;
}, 2000) }, 2000);
} else { } else {
options.value = [] options.value = [];
} }
}; };
// //
const handleAddParams = () => { const handleAddParams = () => {
// paramsVisible.value = true; // paramsVisible.value = true;
@ -218,7 +268,7 @@
}); });
}; };
// //
const handleDeleteParams = (record: any) => { const handleDeleteParams = (record: number) => {
if (record !== -1) { if (record !== -1) {
paramsData.value.splice(record, 1); paramsData.value.splice(record, 1);
} }
@ -226,14 +276,27 @@
// //
const handleClick = () => { const handleClick = () => {
setVisible(true); setVisible(true);
if(!props.isCreate) {
const ID = formData.value.productId;
queryProductDetail(ID).then((res) => {
formData.value.productName = res.data.name;
});
queryDeviceDetail(formData.value.id).then((res) => {
paramsData.value = res.data.extendParams;
})
}
}; };
// //
const handleSubmit = async () => { const handleSubmit = async () => {
const valid = await CreateRef.value?.validate(); const valid = await CreateRef.value?.validate();
// formData.value.productId = formData.value.productId.id;
if (!valid) { if (!valid) {
// //
formData.value.extendParams = paramsData.value; formData.value.extendParams = paramsData.value;
const productId = await queryDeviceByName(formData.value.productName);
formData.value.productId = productId.data.records[0].id;
if (props.isCreate) { if (props.isCreate) {
// formData.value.username = formData.value.email; // formData.value.username = formData.value.email;
const res = await createDevice(formData.value); const res = await createDevice(formData.value);
@ -263,21 +326,20 @@
// //
onBeforeUnmount(() => { onBeforeUnmount(() => {
const editor = editorRef.value const editor = editorRef.value;
if (editor == null) return if (editor == null) return;
editor.destroy() editor.destroy();
}) });
// //
const handleCancel = async () => { const handleCancel = async () => {
checkKeys.value = []; checkKeys.value = [];
setVisible(false); setVisible(false);
}; };
</script> </script>
<style scoped> <style scoped>
.editor-button{ .editor-button {
position: static position: static;
} }
</style> </style>

View File

@ -215,7 +215,6 @@
import usePagination from '@/hooks/pagination'; import usePagination from '@/hooks/pagination';
import type { SelectOptionData } from '@arco-design/web-vue/es/select/interface'; import type { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
import type { TableColumnData } from '@arco-design/web-vue/es/table/interface'; import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
import { useBulletinStore } from '@/store';
import useTableOption from '@/hooks/table-option'; import useTableOption from '@/hooks/table-option';
import { Message } from '@arco-design/web-vue'; import { Message } from '@arco-design/web-vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
@ -248,7 +247,6 @@
deepClone, deepClone,
} = useTableOption(); } = useTableOption();
const bulletinStore = useBulletinStore();
const columns = computed<TableColumnData[]>(() => [ const columns = computed<TableColumnData[]>(() => [
{ {

View File

@ -81,7 +81,7 @@
field="remark" field="remark"
label="备注" label="备注"
> >
<a-input <a-textarea
v-model="formData.remark" v-model="formData.remark"
placeholder='请输入备注' placeholder='请输入备注'
/> />
@ -143,8 +143,8 @@
<a-space v-for="(param,index) in paramsData" :key="index" style="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.name" placeholder="名称" allow-clear />
<a-input v-model="param.identifier" 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.dataType" :options="dataTypeOptions" allow-search placeholder="数据类型" style="width: 140px"/>
<a-select v-model="param.type" :options="typeOptions" allow-search /> <a-select v-model="param.type" :options="typeOptions" allow-search placeholder="类型" style="width: 140px"/>
<a-button type="text" @click="handleDeleteParams(index)"><icon-minus-circle /></a-button> <a-button type="text" @click="handleDeleteParams(index)"><icon-minus-circle /></a-button>
</a-space> </a-space>
</div> </div>
@ -348,11 +348,11 @@
]); ]);
const typeOptions = computed<SelectOptionData[]>(() => [ const typeOptions = computed<SelectOptionData[]>(() => [
{ {
label: '物模型输入', label: '输入',
value: 'INPUT', value: 'INPUT',
}, },
{ {
label: '物模型输出', label: '输出',
value: 'OUTPUT', value: 'OUTPUT',
}, },
{ {
@ -365,6 +365,7 @@
const fetchData = async (Id: number | undefined) => { const fetchData = async (Id: number | undefined) => {
const res = await queryProductDetail(Id); const res = await queryProductDetail(Id);
formData.value = res.data; formData.value = res.data;
paramsData.value = res.data.params;
}; };
// //
const handleClick = () => { const handleClick = () => {

View File

@ -80,7 +80,7 @@
<a-form <a-form
ref="propertyCreateRef" ref="propertyCreateRef"
:model="propertyAddData" :model="propertyAddData"
:style="{ width: '650px' }" :style="{ width: '800px', height: '420px' }"
> >
<!-- 设备名称 --> <!-- 设备名称 -->
<a-form-item <a-form-item
@ -152,7 +152,7 @@
<a-form <a-form
ref="serveCreateRef" ref="serveCreateRef"
:model="serveAddData" :model="serveAddData"
:style="{ width: '650px' }" :style="{ width: '800px', height: '420px' }"
> >
<!-- 服务名称 --> <!-- 服务名称 -->
<a-form-item <a-form-item
@ -188,8 +188,8 @@
<a-space v-for="(param,index) in serveInputData" :key="index" style="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.name" placeholder="名称" allow-clear />
<a-input v-model="param.identifier" 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.dataType" :options="dataTypeOptions" allow-search placeholder="数据类型" style="width: 140px"/>
<a-select v-model="param.type" :options="typeOptions" allow-search placeholder="类型"/> <a-select v-model="param.type" :options="typeOptions" allow-search placeholder="类型" style="width: 140px"/>
<a-button type="text" @click="handleDeleteParams(index,'serveInputData')"><icon-minus-circle /></a-button> <a-button type="text" @click="handleDeleteParams(index,'serveInputData')"><icon-minus-circle /></a-button>
</a-space> </a-space>
</div> </div>
@ -208,8 +208,8 @@
<a-space v-for="(param,index) in serveOutputData" :key="index" style="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.name" placeholder="名称" allow-clear />
<a-input v-model="param.identifier" 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.dataType" :options="dataTypeOptions" allow-search placeholder="数据类型" style="width: 140px"/>
<a-select v-model="param.type" :options="typeOptions" allow-search placeholder="类型"/> <a-select v-model="param.type" :options="typeOptions" allow-search placeholder="类型" style="width: 140px"/>
<a-button type="text" @click="handleDeleteParams(index,'serveOutputData')"><icon-minus-circle /></a-button> <a-button type="text" @click="handleDeleteParams(index,'serveOutputData')"><icon-minus-circle /></a-button>
</a-space> </a-space>
</div> </div>
@ -245,7 +245,7 @@
<a-form <a-form
ref="eventCreateRef" ref="eventCreateRef"
:model="eventAddData" :model="eventAddData"
:style="{ width: '650px' }" :style="{ width: '800px', height: '420px' }"
> >
<!-- 事件名称 --> <!-- 事件名称 -->
<a-form-item <a-form-item
@ -278,10 +278,7 @@
:rules="[{ required: true, message: '类型不能为空' }]" :rules="[{ required: true, message: '类型不能为空' }]"
:validate-trigger="['change']" :validate-trigger="['change']"
> >
<a-input <a-select v-model="eventAddData.type" :options="eventTypeOptions" allow-search placeholder="请选择类型"/>
v-model="eventAddData.type"
placeholder='请输入类型'
/>
</a-form-item> </a-form-item>
<!-- 输出参数 --> <!-- 输出参数 -->
<a-form-item <a-form-item
@ -293,8 +290,8 @@
<a-space v-for="(param,index) in eventOutputData" :key="index" style="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.name" placeholder="名称" allow-clear />
<a-input v-model="param.identifier" 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.dataType" :options="dataTypeOptions" allow-search placeholder="数据类型" style="width: 140px"/>
<a-select v-model="param.type" :options="typeOptions" allow-search placeholder="类型"/> <a-select v-model="param.type" :options="typeOptions" allow-search placeholder="类型" style="width: 140px"/>
<a-button type="text" @click="handleDeleteParams(index,'eventOutputData')"><icon-minus-circle /></a-button> <a-button type="text" @click="handleDeleteParams(index,'eventOutputData')"><icon-minus-circle /></a-button>
</a-space> </a-space>
</div> </div>
@ -404,11 +401,11 @@
]); ]);
const typeOptions = computed<SelectOptionData[]>(() => [ const typeOptions = computed<SelectOptionData[]>(() => [
{ {
label: '物模型输入', label: '输入',
value: 'INPUT', value: 'INPUT',
}, },
{ {
label: '物模型输出', label: '输出',
value: 'OUTPUT', value: 'OUTPUT',
}, },
{ {
@ -416,6 +413,16 @@
value: 'RW', value: 'RW',
}, },
]); ]);
const eventTypeOptions = computed<SelectOptionData[]>(() => [
{
label: '主动',
value: 'ACTIVE',
},
{
label: '被动',
value: 'PASSIVE',
},
]);
const propertyAddData = ref({ const propertyAddData = ref({
productId:id, productId:id,
}); });

View File

@ -113,6 +113,7 @@
<a-table <a-table
row-key="id" row-key="id"
:default-expand-all-rows="true" :default-expand-all-rows="true"
:default-expanded-keys="[1]"
:loading="loading" :loading="loading"
:columns="(cloneColumns as TableColumnData[])" :columns="(cloneColumns as TableColumnData[])"
:data="renderData" :data="renderData"
@ -183,7 +184,7 @@ import { Pagination } from '@/types/global';
import type { TableColumnData } from '@arco-design/web-vue/es/table/interface'; import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { Message } from '@arco-design/web-vue'; import { Message } from '@arco-design/web-vue';
import { DeptRecord } from '@/api/dept'; import { DeptRecord, getAllDeptTree } from '@/api/dept';
import { useDeptStore } from '@/store'; import { useDeptStore } from '@/store';
import DeptEdit from './components/dept-edit.vue'; import DeptEdit from './components/dept-edit.vue';
@ -266,12 +267,12 @@ const columns = computed<TableColumnData[]>(() => [
const fetchData = async (params?: Partial<DeptRecord>) => { const fetchData = async (params?: Partial<DeptRecord>) => {
setLoading(true); setLoading(true);
try { try {
const res = await deptStore.getDeptList(params); const res = await deptStore.getAllDeptTree(1);
renderData.value = res.data.records; renderData.value = res.data;
pagination.page = res.data.page; // pagination.page = res.data.page;
pagination.current = res.data.current; // pagination.current = res.data.current;
pagination.total = res.data.total; // pagination.total = res.data.total;
} catch (err) { } catch (err) {
// you can report use errorHandler or other // you can report use errorHandler or other
} finally { } finally {

View File

@ -30,7 +30,7 @@
{ message: '请输入用戶' }, { message: '请输入用戶' },
]" ]"
> >
<a-input <a-input-tag
v-model="formData.userIds" v-model="formData.userIds"
placeholder='请选择用戶' placeholder='请选择用戶'
:value=formData.userIds :value=formData.userIds
@ -142,13 +142,13 @@
</a-tree> </a-tree>
</a-card> </a-card>
<a-card style="flex: 1"> <a-card style="flex: 1">
<a-button type="primary" >全选</a-button> <a-button type="primary" style="margin-bottom: 10px" @click="handleCheckAllUsers">全选</a-button>
<a-table <a-table
:data="selectedDepartmentMembers" :data="selectedDepartmentMembers"
:columns="columns" :columns="columns"
style="height: 520px"> style="height: 520px">
<template #id="{ record }"> <template #id="{ record }">
<a-checkbox v-model="selectedIds" :value="record.id"> </a-checkbox> <a-checkbox v-model="selectedIds" :value="record.userId"> </a-checkbox>
</template> </template>
<template #username="{ record }"> <template #username="{ record }">
{{ record.username }} {{ record.username }}
@ -176,6 +176,7 @@
import { IEditorConfig } from '@wangeditor/editor' import { IEditorConfig } from '@wangeditor/editor'
import '@wangeditor/editor/dist/css/style.css' import '@wangeditor/editor/dist/css/style.css'
import { getAllDeptTree } from '@/api/dept'; import { getAllDeptTree } from '@/api/dept';
import configArcoStyleImportPlugin from '../../../../../config/plugin/arcoStyleImport';
const props = defineProps({ const props = defineProps({
prem: { prem: {
@ -202,7 +203,7 @@
const messageStore = useMessageStore(); const messageStore = useMessageStore();
const isFullScreen = ref(false); const isFullScreen = ref(false);
const mode = 'default'; const mode = 'default';
const selectedIds= ref<string[]>([]); const selectedIds= ref<number[]>([]);
const toolbarConfig = { excludeKeys: ['uploadVideo', 'insertImage','insertVideo']} const toolbarConfig = { excludeKeys: ['uploadVideo', 'insertImage','insertVideo']}
const columns = computed<any[]>(()=>[ const columns = computed<any[]>(()=>[
{ {
@ -302,7 +303,7 @@
} }
// 广 // 广
const getSelectedMembers = (treeData: any[], selectedKeys: string[]) => { const getSelectedMembers = (treeData: any[], selectedKeys: number[]) => {
const queue:any = [...treeData]; const queue:any = [...treeData];
const selectedMembers: any[] = []; const selectedMembers: any[] = [];
while (queue.length > 0) { while (queue.length > 0) {
@ -322,9 +323,9 @@
// //
const handleClickTree = (id: string[]) => { const handleClickTree = (id: number[]) => {
// '1' // '1'
if (id[0] === '1' || id.length === 0) { if (id[0] === 1 && id.length === 1) {
// 广 // 广
const allMembers: any[] = []; const allMembers: any[] = [];
const queue:any = [...deptTreeData.value]; const queue:any = [...deptTreeData.value];
@ -346,13 +347,13 @@
selectedDepartmentMembers.value = Members; selectedDepartmentMembers.value = Members;
} }
// //
const handleCheckTree = (id: string[]) => { const handleCheckTree = (id: number[]) => {
if (id[0] === '1' ) { // '1' if (id[0] === 1 ) { // '1'
const allKeys: string[] = []; const allKeys: number[] = [];
const traverseTree = (node: any) => { const traverseTree = (node: any) => {
if (node.members) { if (node.members) {
node.members.forEach((member: any) => { node.members.forEach((member: any) => {
allKeys.push(member.id); allKeys.push(member.userId);
}); });
} }
if (node.children) { if (node.children) {
@ -368,7 +369,7 @@
} else { } else {
const selectedKeys = getSelectedMembers(deptTreeData.value, id); const selectedKeys = getSelectedMembers(deptTreeData.value, id);
selectedIds.value = selectedKeys.map(item => item.id); selectedIds.value = selectedKeys.map(item => item.userId);
} }
}; };
@ -428,6 +429,17 @@
formData.value.userIds = selectedIds.value; formData.value.userIds = selectedIds.value;
}; };
//
const handleCheckAllUsers = () => {
if(selectedIds.value.length ===0 ) {
handleCheckTree([1]);
} else {
selectedIds.value = [];
}
};
// //
const deptTreeCancel = () => { const deptTreeCancel = () => {
deptVisible.value = false; deptVisible.value = false;