From 70da1652e00de66b54e9651639c1bf6dda88b357 Mon Sep 17 00:00:00 2001
From: Your Name <123456>
Date: Fri, 17 Feb 2023 16:26:40 +0800
Subject: [PATCH] 页面
---
src/views/basic/material/index.vue | 322 ++
src/views/experiment/developing/index.vue | 347 ++
src/views/basic/room/components/roomDialog.vue | 139
src/types/layout.d.ts | 59
src/views/experiment/project/components/applyDialog.vue | 98
src/views/system/home/index.ts | 3
src/router/route.ts | 32
src/views/basic/unit/index.ts | 45
src/views/basic/room/index.vue | 302 ++
src/views/basic/person/index.ts | 52
src/views/basic/material/components/materialDialog.vue | 169 +
src/api/basic/room/index.ts | 45
src/views/basic/equipment/components/equipmentDialog.vue | 167 +
src/views/experiment/project/components/selectEquipment.vue | 208 +
src/views/system/home/index.vue | 144 +
src/utils/request.ts | 12
src/api/basic/unit/index.ts | 38
src/views/home/dialog.vue | 272 +
src/views/basic/unit/index.vue | 313 ++
src/views/experiment/developing/components/projectDialog.vue | 533 +++
src/views/basic/room/index.ts | 41
src/views/experiment/developing/components/applyDialog.vue | 98
src/views/basic/equipment/index.ts | 46
src/views/experiment/developing/components/selectMaterial.vue | 210 +
.env.development | 6
src/views/basic/person/index.vue | 315 ++
src/assets/style/index.scss | 3
src/views/experiment/developing/components/applyStart.vue | 101
src/views/home/index.vue | 149
src/views/home/index.ts | 3
src/api/experiment/project/index.ts | 54
src/views/experiment/project/components/projectDialog.vue | 533 +++
src/views/experiment/developing/components/selectPerson.vue | 218 +
src/api/basic/equipement/index.ts | 44
src/api/systemManage/role/index.ts | 4
src/views/experiment/project/index.ts | 150 +
src/types/global.d.ts | 111
src/views/experiment/developing/components/selectEquipment.vue | 208 +
src/views/basic/equipment/index.vue | 319 ++
src/views/experiment/project/components/selectMaterial.vue | 210 +
src/types/mitt.d.ts | 38
src/types/views.d.ts | 330 ++
src/views/experiment/developing/index.ts | 150 +
src/views/experiment/developing/components/selectDanger.vue | 184 +
src/types/pinia.d.ts | 91
src/views/loginPage/component/accountLogin.vue | 2
src/views/experiment/project/components/selectDanger.vue | 184 +
src/views/experiment/project/index.vue | 324 ++
src/views/basic/person/components/personDialog.vue | 197 +
src/views/experiment/project/components/applyStart.vue | 101
src/views/basic/unit/components/unitDialog.vue | 167 +
src/api/basic/person/index.ts | 44
src/views/system/home/dialog.vue | 272 +
src/router/backEnd.ts | 1
src/api/systemManage/menu/index.ts | 11
src/types/axios.d.ts | 13
src/views/basic/material/index.ts | 48
src/api/basic/material/index.ts | 44
src/views/experiment/project/components/selectPerson.vue | 218 +
59 files changed, 8,481 insertions(+), 61 deletions(-)
diff --git a/.env.development b/.env.development
index bb3516f..5285007 100644
--- a/.env.development
+++ b/.env.development
@@ -4,16 +4,16 @@
#VITE_API_URL = 'http://192.168.0.35:8008'
#李宇飞接口地址
-#VITE_API_URL = 'http://192.168.0.50:8008'
+VITE_API_URL = 'http://192.168.0.22:8084'
#张凤接口地址
#VITE_API_URL = 'http://192.168.0.29:8008'
#黄振接口地址
-VITE_API_URL = 'http://192.168.0.5:8084'
+#VITE_API_URL = 'http://192.168.0.5:8084'
#施正红接口地址
-#VITE_API_URL = 'http://192.168.0.8:8084'
+#VITE_API_URL = 'http://192.168.0.18:8084'
#戚会山接口地址
#VITE_API_URL = 'http://121.239.169.27:16006/safeplatform'
diff --git a/src/api/basic/equipement/index.ts b/src/api/basic/equipement/index.ts
new file mode 100644
index 0000000..b8a18de
--- /dev/null
+++ b/src/api/basic/equipement/index.ts
@@ -0,0 +1,44 @@
+import request from '/@/utils/request';
+
+export function equipmentApi() {
+ return {
+ getEquipmentByList: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/select/getDevicePage',
+ method: 'post',
+ data: params
+ });
+ },
+
+ addEquipment: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/insert/insertDevice',
+ method: 'post',
+ data: params
+ });
+ },
+
+ modEquipment: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/update/updateDevice',
+ method: 'post',
+ data: params
+ });
+ },
+
+ deleteEquipmentById: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/delete/deleteDevice',
+ method: 'post',
+ data: params
+ });
+ },
+
+ getAllEquipment: () => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/select/listDevice',
+ method: 'get',
+ });
+ },
+ };
+}
diff --git a/src/api/basic/material/index.ts b/src/api/basic/material/index.ts
new file mode 100644
index 0000000..c0ff740
--- /dev/null
+++ b/src/api/basic/material/index.ts
@@ -0,0 +1,44 @@
+import request from '/@/utils/request';
+
+export function materialApi() {
+ return {
+ getMaterialByList: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/select/selectStuffPage',
+ method: 'post',
+ data: params
+ });
+ },
+
+ addMaterial: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/insert/insertStuff',
+ method: 'post',
+ data: params
+ });
+ },
+
+ modMaterial: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/update/updateStuff',
+ method: 'post',
+ data: params
+ });
+ },
+
+ deleteMaterialById: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/delete/deleteStuff',
+ method: 'post',
+ data: params
+ });
+ },
+
+ getAllMaterial: () => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/select/listStuff',
+ method: 'get',
+ });
+ },
+ };
+}
diff --git a/src/api/basic/person/index.ts b/src/api/basic/person/index.ts
new file mode 100644
index 0000000..a49ed1d
--- /dev/null
+++ b/src/api/basic/person/index.ts
@@ -0,0 +1,44 @@
+import request from '/@/utils/request';
+
+export function personApi() {
+ return {
+ getPersonByList: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/select/selectPersonPage',
+ method: 'post',
+ data: params
+ });
+ },
+
+ addPerson: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/insert/insertPerson',
+ method: 'post',
+ data: params
+ });
+ },
+
+ modPerson: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/update/updatePerson',
+ method: 'post',
+ data: params
+ });
+ },
+
+ deletePersonById: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/delete/deletePerson',
+ method: 'post',
+ data: params
+ });
+ },
+
+ getAllPerson: () => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/select/listPerson',
+ method: 'get',
+ });
+ },
+ };
+}
diff --git a/src/api/basic/room/index.ts b/src/api/basic/room/index.ts
new file mode 100644
index 0000000..0e6f055
--- /dev/null
+++ b/src/api/basic/room/index.ts
@@ -0,0 +1,45 @@
+import request from '/@/utils/request';
+
+export function roomApi() {
+ return {
+ getRoomByList: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/select/selectSitePage',
+ method: 'post',
+ data: params
+ });
+ },
+
+ addRoom: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/insert/insertSite',
+ method: 'post',
+ data: params
+ });
+ },
+
+ modRoom: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/update/updateSite',
+ method: 'post',
+ data: params
+ });
+ },
+
+ deleteRoomById: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/delete/deleteSite',
+ method: 'post',
+ data: params
+ });
+ },
+
+ getAllRoom: () => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/select/listSite',
+ method: 'get',
+ });
+ },
+
+ };
+}
diff --git a/src/api/basic/unit/index.ts b/src/api/basic/unit/index.ts
new file mode 100644
index 0000000..5953dd2
--- /dev/null
+++ b/src/api/basic/unit/index.ts
@@ -0,0 +1,38 @@
+import request from '/@/utils/request';
+
+export function unitApi() {
+ return {
+ getUnitByList: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/select/selectRiskUnitPage',
+ method: 'post',
+ data: params
+ });
+ },
+
+ addUnit: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/insert/insertRiskUnit',
+ method: 'post',
+ data: params
+ });
+ },
+
+ modUnit: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/update/updateRiskUnit',
+ method: 'post',
+ data: params
+ });
+ },
+
+ deleteUnitById: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/basic/delete/deleteRiskUnit',
+ method: 'post',
+ data: params
+ });
+ },
+
+ };
+}
diff --git a/src/api/experiment/project/index.ts b/src/api/experiment/project/index.ts
new file mode 100644
index 0000000..b512600
--- /dev/null
+++ b/src/api/experiment/project/index.ts
@@ -0,0 +1,54 @@
+import request from '/@/utils/request';
+
+export function projectApi() {
+ return {
+ getProjectByList: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/experimentInfo/list/page/project',
+ method: 'post',
+ data: params
+ });
+ },
+
+ addProject: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/experimentInfo/save',
+ method: 'post',
+ data: params
+ });
+ },
+
+ modProject: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/experimentInfo/mod',
+ method: 'post',
+ data: params
+ });
+ },
+
+ applyProject: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/experimentInfo/update/develop',
+ method: 'post',
+ data: params
+ });
+ },
+
+ accessProject: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/experimentInfo/update/apply/evaluation',
+ method: 'post',
+ data: params
+ });
+ },
+
+ deleteProjectById: (params: object) => {
+ return request({
+ url: import.meta.env.VITE_API_URL + '/experimentInfo/delete',
+ method: 'post',
+ data: params
+ });
+ },
+
+ };
+}
diff --git a/src/api/systemManage/menu/index.ts b/src/api/systemManage/menu/index.ts
index bbb0469..84e24af 100644
--- a/src/api/systemManage/menu/index.ts
+++ b/src/api/systemManage/menu/index.ts
@@ -24,7 +24,7 @@
// v1
addMenu: (value?: object) => {
return request({
- url: import.meta.env.VITE_API_URL + `/menu/add`,
+ url: import.meta.env.VITE_API_URL + `/sys/console/menu/add`,
method: 'post',
data: value
});
@@ -32,17 +32,16 @@
// v1
modMenu: (value?: object) => {
return request({
- url: import.meta.env.VITE_API_URL + `/menu/mod`,
+ url: import.meta.env.VITE_API_URL + `/sys/console/menu/mod`,
method: 'post',
data: value
});
},
// v1
- deleteMenu: (value?: object) => {
+ deleteMenu: (value: number) => {
return request({
- url: import.meta.env.VITE_API_URL + `/menu/del`,
- method: 'post',
- data: value
+ url: import.meta.env.VITE_API_URL + `/sys/console/menu/del?menuItemId=${value}`,
+ method: 'get',
});
},
// v1
diff --git a/src/api/systemManage/role/index.ts b/src/api/systemManage/role/index.ts
index 85b00cf..f099cac 100644
--- a/src/api/systemManage/role/index.ts
+++ b/src/api/systemManage/role/index.ts
@@ -5,8 +5,8 @@
// v2
getRoleList: () => {
return request({
- url: import.meta.env.VITE_API_URL + `/role/list`,
- method: 'post'
+ url: import.meta.env.VITE_API_URL + `/account/role/find/all/active`,
+ method: 'get'
});
},
// v2
diff --git a/src/assets/style/index.scss b/src/assets/style/index.scss
index 1503233..a55e6ad 100644
--- a/src/assets/style/index.scss
+++ b/src/assets/style/index.scss
@@ -17,3 +17,6 @@
.page-position{
float: right;
}
+.input-length {
+ width: 90% !important;
+}
diff --git a/src/router/backEnd.ts b/src/router/backEnd.ts
index b7750e8..12240fc 100644
--- a/src/router/backEnd.ts
+++ b/src/router/backEnd.ts
@@ -28,7 +28,6 @@
if (window.nextLoading === undefined) NextLoading.start();
if (!Cookies.get('token')) return false;
const res = await getBackEndControlRoutes();
- debugger
await useRequestOldRoutes().setRequestOldRoutes(JSON.parse(JSON.stringify(res.data.data)));
dynamicRoutes[0].children = await backEndComponent(res.data.data);
await setAddRoute();
diff --git a/src/router/route.ts b/src/router/route.ts
index a29e775..827dd4d 100644
--- a/src/router/route.ts
+++ b/src/router/route.ts
@@ -95,36 +95,4 @@
isKeepAlive: false
}
},
- {
- path: '/warningScreen',
- name: 'warningScreen',
- component: () => import('/@/views/riskWarningSys/warningBigScreen/index.vue'),
- meta: {
- title: '预警预报'
- }
- },
- {
- path: '/msgDetail',
- name: 'msgDetail',
- component: () => import('/@/views/riskWarningSys/warningBigScreen/indexs/msgDetail.vue'),
- meta: {
- title: 'spi报告详情'
- }
- },
- {
- path: '/screenPage',
- name: 'screenPage',
- component: () => import('/@/views/riskWarningSys/warningBigScreen/indexs/index.vue'),
- meta: {
- title: '预警预报'
- }
- },
- {
- path: '/securities',
- name: 'securities',
- component: () => import('/@/views/facilityManagement/securities/index.vue'),
- meta: {
- title: '安全物资与设备'
- }
- }
];
diff --git a/src/types/axios.d.ts b/src/types/axios.d.ts
new file mode 100644
index 0000000..bcd0a21
--- /dev/null
+++ b/src/types/axios.d.ts
@@ -0,0 +1,13 @@
+/* eslint-disable */
+import * as axios from 'axios';
+
+// 扩展 axios 数据返回类型,可自行扩展
+declare module 'axios' {
+ export interface AxiosResponse<T = any> {
+ code: number;
+ data: T;
+ message: string;
+ type?: string;
+ [key: string]: T;
+ }
+}
diff --git a/src/types/global.d.ts b/src/types/global.d.ts
new file mode 100644
index 0000000..a46b866
--- /dev/null
+++ b/src/types/global.d.ts
@@ -0,0 +1,111 @@
+// 申明外部 npm 插件模块
+declare module 'vue-grid-layout';
+declare module 'qrcodejs2-fixes';
+declare module 'splitpanes';
+declare module 'js-cookie';
+declare module '@wangeditor/editor-for-vue';
+declare module 'js-table2excel';
+declare module 'qs';
+
+// 声明一个模块,防止引入文件时报错
+declare module '*.json';
+declare module '*.png';
+declare module '*.jpg';
+declare module '*.scss';
+declare module '*.ts';
+declare module '*.js';
+
+// 声明文件,*.vue 后缀的文件交给 vue 模块来处理
+declare module '*.vue' {
+ import type { DefineComponent } from 'vue';
+ const component: DefineComponent<{}, {}, any>;
+ export default component;
+}
+
+// 声明文件,定义全局变量
+/* eslint-disable */
+declare interface Window {
+ nextLoading: boolean;
+}
+
+// 声明路由当前项类型
+declare type RouteItem<T = any> = {
+ path: string;
+ name?: string | symbol | undefined | null;
+ redirect?: string;
+ k?: T;
+ meta?: {
+ title?: string;
+ isLink?: string;
+ isHide?: boolean;
+ isKeepAlive?: boolean;
+ isAffix?: boolean;
+ isIframe?: boolean;
+ roles?: string[];
+ icon?: string;
+ isDynamic?: boolean;
+ isDynamicPath?: string;
+ isIframeOpen?: string;
+ loading?: boolean;
+ };
+ children: T[];
+ query?: { [key: string]: T };
+ params?: { [key: string]: T };
+ contextMenuClickId?: string | number;
+ commonUrl?: string;
+ isFnClick?: boolean;
+ url?: string;
+ transUrl?: string;
+ title?: string;
+ id?: string | number;
+};
+
+// 声明路由 to from
+declare interface RouteToFrom<T = any> extends RouteItem {
+ path?: string;
+ children?: T[];
+}
+
+// 声明路由当前项类型集合
+declare type RouteItems<T extends RouteItem = any> = T[];
+
+// 声明 ref
+declare type RefType<T = any> = T | null;
+
+// 声明 HTMLElement
+declare type HtmlType = HTMLElement | string | undefined | null;
+
+// 申明 children 可选
+declare type ChilType<T = any> = {
+ children?: T[];
+};
+
+// 申明 数组
+declare type EmptyArrayType<T = any> = T[];
+
+// 申明 对象
+declare type EmptyObjectType<T = any> = {
+ [key: string]: T;
+};
+
+// 申明 select option
+declare type SelectOptionType = {
+ value: string | number;
+ label: string | number;
+};
+
+// 鼠标滚轮滚动类型
+declare interface WheelEventType extends WheelEvent {
+ wheelDelta: number;
+}
+
+// table 数据格式公共类型
+declare interface TableType<T = any> {
+ total: number;
+ loading: boolean;
+ param: {
+ pageNum: number;
+ pageSize: number;
+ [key: string]: T;
+ };
+}
diff --git a/src/types/layout.d.ts b/src/types/layout.d.ts
new file mode 100644
index 0000000..82904ef
--- /dev/null
+++ b/src/types/layout.d.ts
@@ -0,0 +1,59 @@
+// aside
+declare type AsideState = {
+ menuList: RouteRecordRaw[];
+ clientWidth: number;
+};
+
+// columnsAside
+declare type ColumnsAsideState<T = any> = {
+ columnsAsideList: T[];
+ liIndex: number;
+ liOldIndex: null | number;
+ liHoverIndex: null | number;
+ liOldPath: null | string;
+ difference: number;
+ routeSplit: string[];
+};
+
+// navBars breadcrumb
+declare type BreadcrumbState<T = any> = {
+ breadcrumbList: T[];
+ routeSplit: string[];
+ routeSplitFirst: string;
+ routeSplitIndex: number;
+};
+
+// navBars search
+declare type SearchState<T = any> = {
+ isShowSearch: boolean;
+ menuQuery: string;
+ tagsViewList: T[];
+};
+
+// navBars tagsView
+declare type TagsViewState<T = any> = {
+ routeActive: string | T;
+ routePath: string | unknown;
+ dropdown: {
+ x: string | number;
+ y: string | number;
+ };
+ sortable: T;
+ tagsRefsIndex: number;
+ tagsViewList: T[];
+ tagsViewRoutesList: T[];
+};
+
+// navBars parent
+declare type ParentViewState<T = any> = {
+ refreshRouterViewKey: string;
+ iframeRefreshKey: string;
+ keepAliveNameList: string[];
+ iframeList: T[];
+};
+
+// navBars link
+declare type LinkViewState = {
+ title: string;
+ isLink: string;
+};
diff --git a/src/types/mitt.d.ts b/src/types/mitt.d.ts
new file mode 100644
index 0000000..b68b80d
--- /dev/null
+++ b/src/types/mitt.d.ts
@@ -0,0 +1,38 @@
+/**
+ * mitt 事件类型定义
+ *
+ * @method openSetingsDrawer 打开布局设置弹窗
+ * @method restoreDefault 分栏布局,鼠标移入、移出数据显示
+ * @method setSendColumnsChildren 分栏布局,鼠标移入、移出菜单数据传入到 navMenu 下的菜单中
+ * @method setSendClassicChildren 经典布局,开启切割菜单时,菜单数据传入到 navMenu 下的菜单中
+ * @method getBreadcrumbIndexSetFilterRoutes 布局设置弹窗,开启切割菜单时,菜单数据传入到 navMenu 下的菜单中
+ * @method layoutMobileResize 浏览器窗口改变时,用于适配移动端界面显示
+ * @method openOrCloseSortable 布局设置弹窗,开启 TagsView 拖拽
+ * @method openShareTagsView 布局设置弹窗,开启 TagsView 共用
+ * @method onTagsViewRefreshRouterView tagsview 刷新界面
+ * @method onCurrentContextmenuClick tagsview 右键菜单每项点击时
+ */
+declare type MittType<T = any> = {
+ openSetingsDrawer?: string;
+ restoreDefault?: string;
+ setSendColumnsChildren: T;
+ setSendClassicChildren: T;
+ getBreadcrumbIndexSetFilterRoutes?: string;
+ layoutMobileResize: T;
+ openOrCloseSortable?: string;
+ openShareTagsView?: string;
+ onTagsViewRefreshRouterView?: T;
+ onCurrentContextmenuClick?: T;
+};
+
+// mitt 参数类型定义
+declare type LayoutMobileResize = {
+ layout: string;
+ clientWidth: number;
+};
+
+// mitt 参数菜单类型
+declare type MittMenu = {
+ children: RouteRecordRaw[];
+ item?: RouteItem;
+};
diff --git a/src/types/pinia.d.ts b/src/types/pinia.d.ts
new file mode 100644
index 0000000..09c6e47
--- /dev/null
+++ b/src/types/pinia.d.ts
@@ -0,0 +1,91 @@
+/**
+ * pinia 类型定义
+ */
+
+// 用户信息
+declare interface UserInfosState<T = any> {
+ userInfos: {
+ authBtnList: string[];
+ photo: string;
+ roles: string[];
+ time: number;
+ userName: string;
+ [key: string]: T;
+ };
+}
+
+// 路由缓存列表
+declare interface KeepAliveNamesState {
+ keepAliveNames: string[];
+ cachedViews: string[];
+}
+
+// 后端返回原始路由(未处理时)
+declare interface RequestOldRoutesState {
+ requestOldRoutes: string[];
+}
+
+// TagsView 路由列表
+declare interface TagsViewRoutesState<T = any> {
+ tagsViewRoutes: T[];
+ isTagsViewCurrenFull: Boolean;
+}
+
+// 路由列表
+declare interface RoutesListState<T = any> {
+ routesList: T[];
+ isColumnsMenuHover: Boolean;
+ isColumnsNavHover: Boolean;
+}
+
+// 布局配置
+declare interface ThemeConfigState {
+ themeConfig: {
+ isDrawer: boolean;
+ primary: string;
+ topBar: string;
+ topBarColor: string;
+ isTopBarColorGradual: boolean;
+ menuBar: string;
+ menuBarColor: string;
+ menuBarActiveColor: string;
+ isMenuBarColorGradual: boolean;
+ columnsMenuBar: string;
+ columnsMenuBarColor: string;
+ isColumnsMenuBarColorGradual: boolean;
+ isColumnsMenuHoverPreload: boolean;
+ isCollapse: boolean;
+ isUniqueOpened: boolean;
+ isFixedHeader: boolean;
+ isFixedHeaderChange: boolean;
+ isClassicSplitMenu: boolean;
+ isLockScreen: boolean;
+ lockScreenTime: number;
+ isShowLogo: boolean;
+ isShowLogoChange: boolean;
+ isBreadcrumb: boolean;
+ isTagsview: boolean;
+ isBreadcrumbIcon: boolean;
+ isTagsviewIcon: boolean;
+ isCacheTagsView: boolean;
+ isSortableTagsView: boolean;
+ isShareTagsView: boolean;
+ isFooter: boolean;
+ isGrayscale: boolean;
+ isInvert: boolean;
+ isIsDark: boolean;
+ isWartermark: boolean;
+ wartermarkText: string;
+ tagsStyle: string;
+ animation: string;
+ columnsAsideStyle: string;
+ columnsAsideLayout: string;
+ layout: string;
+ isRequestRoutes: boolean;
+ globalTitle: string;
+ globalViceTitle: string;
+ globalViceTitleMsg: string;
+ globalI18n: string;
+ globalComponentSize: string;
+ };
+}
diff --git a/src/types/views.d.ts b/src/types/views.d.ts
new file mode 100644
index 0000000..2cd6faf
--- /dev/null
+++ b/src/types/views.d.ts
@@ -0,0 +1,330 @@
+/**
+ * views personal
+ */
+type NewInfo = {
+ title: string;
+ date: string;
+ link: string;
+};
+type Recommend = {
+ title: string;
+ msg: string;
+ icon: string;
+ bg: string;
+ iconColor: string;
+};
+
+declare type PersonalState = {
+ newsInfoList: NewInfo[];
+ recommendList: Recommend[];
+ personalForm: {
+ name: string;
+ email: string;
+ autograph: string;
+ occupation: string;
+ phone: string;
+ sex: string;
+ };
+};
+
+/**
+ * views visualizing
+ */
+declare type Demo2State<T = any> = {
+ time: {
+ txt: string;
+ fun: number;
+ };
+ dropdownList: T[];
+ dropdownActive: string;
+ skyList: T[];
+ dBtnList: T[];
+ chartData4Index: number;
+ dBtnActive: number;
+ earth3DBtnList: T[];
+ chartData4List: T[];
+ myCharts: T[];
+};
+
+/**
+ * views params
+ */
+declare type ParamsState = {
+ value: string;
+ tagsViewName: string;
+ tagsViewNameIsI18n: boolean;
+};
+
+/**
+ * views system
+ */
+// role
+declare interface RowRoleType {
+ roleName: string;
+ roleSign: string;
+ describe: string;
+ sort: number;
+ status: boolean;
+ createTime: string;
+}
+
+interface SysRoleTableType extends TableType {
+ data: RowRoleType[];
+}
+
+declare interface SysRoleState {
+ tableData: SysRoleTableType;
+}
+
+declare type TreeType = {
+ id: number;
+ label: string;
+ children?: TreeType[];
+};
+
+// user
+declare type RowUserType<T = any> = {
+ userName: string;
+ userNickname: string;
+ roleSign: string;
+ department: string[];
+ phone: string;
+ email: string;
+ sex: string;
+ password: string;
+ overdueTime: T;
+ status: boolean;
+ describe: string;
+ createTime: T;
+};
+
+interface SysUserTableType extends TableType {
+ data: RowUserType[];
+}
+
+declare interface SysUserState {
+ tableData: SysUserTableType;
+}
+
+declare type DeptTreeType = {
+ deptName: string;
+ createTime: string;
+ status: boolean;
+ sort: number;
+ describe: string;
+ id: number | string;
+ children?: DeptTreeType[];
+};
+
+// dept
+declare interface RowDeptType extends DeptTreeType {
+ deptLevel: string[];
+ person: string;
+ phone: string;
+ email: string;
+}
+
+interface SysDeptTableType extends TableType {
+ data: DeptTreeType[];
+}
+
+declare interface SysDeptState {
+ tableData: SysDeptTableType;
+}
+
+// dic
+type ListType = {
+ id: number;
+ label: string;
+ value: string;
+};
+
+declare interface RowDicType {
+ dicName: string;
+ fieldName: string;
+ describe: string;
+ status: boolean;
+ createTime: string;
+ list: ListType[];
+}
+
+interface SysDicTableType extends TableType {
+ data: RowDicType[];
+}
+
+declare interface SysDicState {
+ tableData: SysDicTableType;
+}
+
+/**
+ * views pages
+ */
+// filtering
+declare type FilteringChilType = {
+ id: number | string;
+ label: string;
+ active: boolean;
+};
+
+declare type FilterListType = {
+ img: string;
+ title: string;
+ evaluate: string;
+ collection: string;
+ price: string;
+ monSales: string;
+ id: number | string;
+ loading?: boolean;
+};
+
+declare type FilteringRowType = {
+ title: string;
+ isMore: boolean;
+ isShowMore: boolean;
+ id: number | string;
+ children: FilteringChilType[];
+};
+
+// tableRules
+declare type TableRulesHeaderType = {
+ prop: string;
+ width: string | number;
+ label: string;
+ isRequired?: boolean;
+ isTooltip?: boolean;
+ type: string;
+};
+
+declare type TableRulesState = {
+ tableData: {
+ data: EmptyObjectType[];
+ header: TableRulesHeaderType[];
+ option: SelectOptionType[];
+ };
+};
+
+declare type TableRulesOneProps = {
+ name: string;
+ email: string;
+ autograph: string;
+ occupation: string;
+};
+
+// tree
+declare type RowTreeType = {
+ id: number;
+ label: string;
+ label1: string;
+ label2: string;
+ isShow: boolean;
+ children?: RowTreeType[];
+};
+
+// workflow index
+declare type NodeListState = {
+ id: string | number;
+ nodeId: string | undefined;
+ class: HTMLElement | string;
+ left: number | string;
+ top: number | string;
+ icon: string;
+ name: string;
+};
+
+declare type LineListState = {
+ sourceId: string;
+ targetId: string;
+ label: string;
+};
+
+declare type XyState = {
+ x: string | number;
+ y: string | number;
+};
+
+declare type WorkflowState<T = any> = {
+ leftNavList: T[];
+ dropdownNode: XyState;
+ dropdownLine: XyState;
+ isShow: boolean;
+ jsPlumb: T;
+ jsPlumbNodeIndex: null | number;
+ jsplumbDefaults: T;
+ jsplumbMakeSource: T;
+ jsplumbMakeTarget: T;
+ jsplumbConnect: T;
+ jsplumbData: {
+ nodeList: NodeListState[];
+ lineList: LineListState[];
+ };
+};
+
+// workflow drawer
+declare type WorkflowDrawerNodeState<T = any> = {
+ node: { [key: string]: T };
+ nodeRules: T;
+ form: T;
+ tabsActive: string;
+ loading: {
+ extend: boolean;
+ };
+};
+
+declare type WorkflowDrawerLabelType = {
+ type: string;
+ label: string;
+};
+
+declare type WorkflowDrawerState<T = any> = {
+ isOpen: boolean;
+ nodeData: {
+ type: string;
+ };
+ jsplumbConn: T;
+};
+
+/**
+ * views make
+ */
+// tableDemo
+declare type TableDemoPageType = {
+ pageNum: number;
+ pageSize: number;
+};
+
+declare type TableHeaderType = {
+ key: string;
+ width: string;
+ title: string;
+ type: string | number;
+ colWidth: string;
+ width?: string | number;
+ height?: string | number;
+ isCheck: boolean;
+};
+
+declare type TableSearchType = {
+ label: string;
+ prop: string;
+ placeholder: string;
+ required: boolean;
+ type: string;
+ options?: SelectOptionType[];
+};
+
+declare type TableDemoState = {
+ tableData: {
+ data: EmptyObjectType[];
+ header: TableHeaderType[];
+ config: {
+ total: number;
+ loading: boolean;
+ isBorder: boolean;
+ isSelection: boolean;
+ isSerialNo: boolean;
+ isOperate: boolean;
+ };
+ search: TableSearchType[];
+ param: EmptyObjectType;
+ };
+};
diff --git a/src/utils/request.ts b/src/utils/request.ts
index 21107e5..10500ec 100644
--- a/src/utils/request.ts
+++ b/src/utils/request.ts
@@ -15,11 +15,11 @@
service.interceptors.request.use(
(config) => {
- for (let key in config.data) {
- if (config.data[key] == '' && config.data[key] !== 0) {
- config.data[key] = null;
- }
- }
+ // for (let key in config.data) {
+ // if (config.data[key] == '' && config.data[key] !== 0) {
+ // config.data[key] = null;
+ // }
+ // }
if (Cookies.get('token')) {
(<any>config.headers).common['tk'] = `${Cookies.get('token')}`;
(<any>config.headers).common['uid'] = `${Cookies.get('uid')}`;
@@ -63,7 +63,7 @@
Session.clear();
window.location.href = '/';
});
- } else if (response.data.code && response.data.code === 'A0215') {
+ } else if (response.data.code && response.data.code === 405) {
ElMessage.error('token失效');
// logOut;
useLoginApi()
diff --git a/src/views/basic/equipment/components/equipmentDialog.vue b/src/views/basic/equipment/components/equipmentDialog.vue
new file mode 100644
index 0000000..d52c0ef
--- /dev/null
+++ b/src/views/basic/equipment/components/equipmentDialog.vue
@@ -0,0 +1,167 @@
+<template>
+ <div class="system-menu-dialog-container">
+ <el-dialog :title="equipmentDialogState.title" v-model="equipmentDialogState.equipmentDialogVisible" width="600px">
+ <el-form ref="EquipmentFormRef" :rules="equipmentDialogState.equipmentFormRules" :model="equipmentDialogState.equipmentForm" size="default" label-width="120px">
+ <el-row :gutter="35">
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="设备编号" prop="deviceCode">
+ <el-input v-model="equipmentDialogState.equipmentForm.deviceCode" placeholder="设备编号" clearable class="input-length"></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="设备名称" prop="deviceName">
+ <el-input v-model="equipmentDialogState.equipmentForm.deviceName" placeholder="设备名称" clearable class="input-length"></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="设备功率" prop="devicePower">
+ <el-input v-model="equipmentDialogState.equipmentForm.devicePower" placeholder="设备功率" clearable class="input-length"></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="计量单位" prop="deviceUnit">
+ <el-select v-model="equipmentDialogState.equipmentForm.deviceUnit" placeholder="计量单位" clearable class="input-length">
+ <el-option v-for="item in equipmentDialogState.deviceUnitList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="是否特种设备">
+ <el-select v-model="equipmentDialogState.equipmentForm.specialDevice" placeholder="是否特种设备" clearable class="input-length">
+ <el-option v-for="item in equipmentDialogState.specialDeviceList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="安全防护">
+ <el-input type="textarea" :rows="3" v-model="equipmentDialogState.equipmentForm.safeProtect" placeholder="安全防护" clearable class="input-length"></el-input>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <template #footer>
+ <span class="dialog-footer">
+ <el-button @click="equipmentDialogState.equipmentDialogVisible = !equipmentDialogState.equipmentDialogVisible" size="default">取 消</el-button>
+ <el-button type="primary" @click="onSubmitEquipment" size="default">确定</el-button>
+ </span>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup lang="ts">
+import { reactive, ref } from "vue";
+import {useMenuApi} from "/@/api/systemManage/menu";
+import {ElMessage} from "element-plus";
+import {equipmentApi} from "/@/api/basic/equipement";
+
+const EquipmentFormRef = ref()
+
+const equipmentDialogState = reactive<EquipmentDialogType>({
+ title: '',
+ equipmentDialogVisible: false,
+ equipmentForm: {
+ id: null,
+ deviceCode: '',
+ deviceName: '',
+ devicePower: '',
+ deviceUnit: null,
+ safeProtect: '',
+ },
+ equipmentFormRules: {
+ deviceCode: [{ required: true, message: '请填写设备编号', trigger: 'blur' }],
+ deviceName: [{ required: true, message: '请填写设备名称', trigger: 'blur' }],
+ devicePower: [{ required: true, message: '请填写设备功率', trigger: 'blur' }],
+ deviceUnit: [{ required: true, message: '请选择计量单位', trigger: 'change' }]
+ },
+ specialDeviceList: [],
+ deviceUnitList: [
+ {id:1, name: '台'},
+ {id:2, name: '个'},
+ {id:3, name: '件'}
+ ]
+})
+
+const showEquipmentDialog = (title: string, value: EquipmentType, specialDeviceList: Type []) => {
+
+ equipmentDialogState.equipmentDialogVisible = true;
+ equipmentDialogState.specialDeviceList = specialDeviceList;
+ setTimeout(() => {
+ EquipmentFormRef.value.clearValidate();
+ });
+ if(title === '新增'){
+ equipmentDialogState.title = '新增';
+ equipmentDialogState.equipmentForm = {
+ id: null,
+ deviceCode: '',
+ deviceName: '',
+ devicePower: '',
+ deviceUnit: null,
+ safeProtect: '',
+ };
+ }else{
+ equipmentDialogState.title = '编辑'
+ equipmentDialogState.equipmentForm = {
+ id: value.id,
+ deviceCode: value.deviceCode,
+ deviceName: value.deviceName,
+ devicePower: value.devicePower,
+ deviceUnit: value.deviceUnit,
+ safeProtect: value.safeProtect,
+ };
+ }
+};
+
+const onSubmitEquipment = () => {
+ EquipmentFormRef.value.validate(async(valid: boolean) => {
+ if(valid){
+ if(equipmentDialogState.title === '新增'){
+ let res = await equipmentApi().addEquipment(equipmentDialogState.equipmentForm);
+ if(res.data.code === 100){
+ emit('refresh')
+ equipmentDialogState.equipmentDialogVisible = false;
+ ElMessage({
+ type: 'success',
+ message: '新增成功'
+ })
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg,
+ });
+ }
+ }else{
+ let res = await equipmentApi().modEquipment(equipmentDialogState.equipmentForm)
+ if(res.data.code === 100){
+ emit('refresh')
+ equipmentDialogState.equipmentDialogVisible = false;
+ ElMessage({
+ type: 'success',
+ message: '编辑成功'
+ })
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg,
+ });
+ }
+ }
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: '请完善基本信息',
+ });
+ }
+ })
+}
+
+const emit = defineEmits(['refresh'])
+
+defineExpose({
+ showEquipmentDialog
+})
+</script>
+
+<style scoped>
+
+</style>
diff --git a/src/views/basic/equipment/index.ts b/src/views/basic/equipment/index.ts
new file mode 100644
index 0000000..27483e9
--- /dev/null
+++ b/src/views/basic/equipment/index.ts
@@ -0,0 +1,46 @@
+declare interface EquipmentStateType {
+ equipmentData: Array<EquipmentType>
+ searchQuery: {
+ pageIndex: number,
+ pageSize: number,
+ deviceCode: string,
+ deviceName: string,
+ devicePower: string,
+ specialDevice: number | null,
+ }
+ total: number
+ specialDeviceList: Array<Type>,
+ deviceUnitList: Array<Type>
+}
+
+declare interface EquipmentType {
+ id: number | null,
+ deviceCode: string,
+ deviceName: string,
+ devicePower: string,
+ deviceUnit: number | null,
+ safeProtect: string,
+}
+
+declare interface Type {
+ id: number,
+ name: string,
+}
+
+declare interface EquipmentDialogType {
+ title: string,
+ equipmentDialogVisible: boolean,
+ equipmentForm: {
+ id: number | null,
+ deviceCode: string,
+ deviceName: string,
+ devicePower: string,
+ deviceUnit: number | null,
+ safeProtect: string,
+ },
+ equipmentFormRules: {
+
+ },
+ specialDeviceList: Array<Type>,
+ deviceUnitList: Array<Type>
+}
diff --git a/src/views/basic/equipment/index.vue b/src/views/basic/equipment/index.vue
new file mode 100644
index 0000000..0eb0e7a
--- /dev/null
+++ b/src/views/basic/equipment/index.vue
@@ -0,0 +1,319 @@
+<template>
+ <div class="home-container">
+ <div style="height: 100%">
+ <el-row class="homeCard">
+ <div class="basic-line">
+ <span>设备编码:</span>
+ <el-input v-model="equipmentState.searchQuery.deviceCode" clearable filterable class="input-box" placeholder="设备编码">
+ </el-input>
+ </div>
+ <div class="basic-line">
+ <span>设备名称:</span>
+ <el-input v-model="equipmentState.searchQuery.deviceName" clearable filterable class="input-box" placeholder="设备名称">
+ </el-input>
+ </div>
+ <div class="basic-line">
+ <span>设备功率:</span>
+ <el-input v-model="equipmentState.searchQuery.devicePower" clearable filterable class="input-box" placeholder="设备功率">
+ </el-input>
+ </div>
+ <div class="basic-line">
+ <span>是否特种设备:</span>
+ <el-select v-model="equipmentState.searchQuery.specialDevice" clearable filterable class="input-box" placeholder="是否特种设备">
+ <el-option v-for="item in equipmentState.specialDeviceList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+ </el-select>
+ </div>
+ <div style="padding-bottom: 10px">
+ <el-button type="primary" @click="getEquipmentData">查询</el-button>
+ <el-button plain @click="reset">重置</el-button>
+ </div>
+ </el-row>
+ <div class="homeCard">
+ <div class="main-card">
+ <el-row class="cardTop">
+ <el-col :span="12" class="mainCardBtn">
+ <el-button type="primary" :icon="Plus" size="default" @click="openEquipmentDialog('新增', {})">新增</el-button>
+ <!-- <el-button type="danger" :icon="Delete" size="default" plain>删除</el-button>-->
+ </el-col>
+<!-- <el-button type="primary" :icon="Refresh" size="default" />-->
+ </el-row>
+ <el-table ref="multipleTableRef" :data="equipmentState.equipmentData" style="width: 100%" height="calc(100% - 100px)" :header-cell-style="{ background: '#fafafa' }">
+ <el-table-column prop="deviceCode" label="设备编号"/>
+ <el-table-column prop="deviceName" label="设备名称" />
+ <el-table-column prop="devicePower" label="设备功率">
+ <template #default="scope">
+ <span>{{`${scope.row.devicePower}${equipmentState.deviceUnitList.find(item =>item.id === scope.row.deviceUnit)?.name || ''}`}}</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="specialDevice" label="是否特殊装备" show-overflow-tooltip>
+ <template #default="scope">
+ <span>{{`${equipmentState.specialDeviceList.find(item =>item.id === scope.row.specialDevice)?.name}`}}</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="createTime" label="创建时间" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="createByUserName" label="创建人" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="updateTime" label="最后修改时间" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="updateByUserName" label="最后修改人" show-overflow-tooltip></el-table-column>
+ <el-table-column label="操作" width="150">
+ <template #default="scope">
+ <el-button size="small" text type="primary" :icon="Edit" @click="openEquipmentDialog('修改', scope.row)">修改</el-button>
+ <el-button size="small" text type="danger" :icon="Delete" @click="onDelEquipment(scope.row)">删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ <div class="pageBtn">
+ <el-pagination @size-change="onHandleSizeChange" @current-change="onHandleCurrentChange" :pager-count="5" :page-sizes="[10, 20, 30]" v-model:current-page="equipmentState.searchQuery.pageIndex" background v-model:page-size="equipmentState.searchQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="equipmentState.total" class="page-position"> </el-pagination>
+ </div>
+ </div>
+ </div>
+ </div>
+ <equipment-dialog ref="equipmentDialogRef" @refresh="getEquipmentData"></equipment-dialog>
+ </div>
+</template>
+
+<script setup lang="ts">
+import {defineAsyncComponent, onMounted, reactive, ref} from "vue";
+import {equipmentApi} from "/@/api/basic/equipement";
+import {ElMessage, ElMessageBox} from "element-plus";
+import { Edit, View, Plus, Delete } from '@element-plus/icons-vue';
+
+const EquipmentDialog = defineAsyncComponent(() => import('./components/equipmentDialog.vue'));
+
+const equipmentDialogRef = ref();
+
+const equipmentState = reactive<EquipmentStateType>({
+ equipmentData: [],
+ searchQuery: {
+ pageIndex: 1,
+ pageSize: 10,
+ deviceCode: '',
+ deviceName: '',
+ devicePower: '',
+ specialDevice: null,
+ },
+ total: 0,
+ specialDeviceList: [
+ {id: 1, name: '是'},
+ {id:2, name: '否'}
+ ],
+ deviceUnitList: [
+ {id:1, name: '台'},
+ {id:2, name: '个'},
+ {id:3, name: '件'}
+ ]
+})
+
+const getEquipmentData = async () => {
+ let res = await equipmentApi().getEquipmentByList(equipmentState.searchQuery);
+ if(res.data.code === 100){
+ equipmentState.equipmentData = res.data.data;
+ equipmentState.total = res.data.total;
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ });
+ }
+};
+
+const openEquipmentDialog = (title: string, value: EquipmentType) => {
+ equipmentDialogRef.value.showEquipmentDialog(title, value, equipmentState.specialDeviceList);
+};
+
+const onDelEquipment = (val: EquipmentType) => {
+ ElMessageBox.confirm(`此操作将永久删除该设备:“${val.deviceName}”,是否继续?`, '提示', {
+ confirmButtonText: '确认',
+ cancelButtonText: '取消',
+ type: 'warning'
+ })
+ .then(async () => {
+ let res = await equipmentApi().deleteEquipmentById({ id: val.id });
+ if (res.data.code === 100) {
+ ElMessage({
+ type: 'success',
+ duration: 2000,
+ message: '删除成功'
+ });
+ await getEquipmentData();
+ } else {
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ });
+ }
+ })
+ .catch((error) => {
+ });
+}
+
+const onHandleSizeChange = (val: number) => {
+ equipmentState.searchQuery.pageSize = val;
+ getEquipmentData();
+};
+
+const onHandleCurrentChange = (val: number) => {
+ equipmentState.searchQuery.pageIndex = val;
+ getEquipmentData();
+};
+
+const reset = () => {
+ equipmentState.searchQuery = {
+ pageIndex: 1,
+ pageSize: 10,
+ deviceCode: '',
+ deviceName: '',
+ devicePower: '',
+ specialDevice: null,
+ }
+};
+
+onMounted(() => {
+ getEquipmentData()
+})
+
+</script>
+
+<style scoped lang="scss">
+$homeNavLengh: 8;
+.home-container {
+ height: calc(100vh - 144px);
+ box-sizing: border-box;
+ overflow: hidden;
+ .homeCard {
+ width: 100%;
+ padding: 20px;
+ box-sizing: border-box;
+ background: #fff;
+ border-radius: 4px;
+
+ .main-card {
+ width: 100%;
+ height: 100%;
+ .cardTop {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 20px;
+ .mainCardBtn {
+ margin: 0;
+ }
+ }
+ .pageBtn {
+ height: 60px;
+ display: flex;
+ align-items: center;
+ justify-content: right;
+
+ .demo-pagination-block + .demo-pagination-block {
+ margin-top: 10px;
+ }
+ .demo-pagination-block .demonstration {
+ margin-bottom: 16px;
+ }
+ }
+ }
+ &:last-of-type {
+ height: calc(100% - 100px);
+ }
+ }
+ .el-row {
+ display: flex;
+ align-items: center;
+ margin-bottom: 20px;
+ &:last-child {
+ margin-bottom: 0;
+ }
+ .grid-content {
+ align-items: center;
+ min-height: 36px;
+ }
+
+ .topInfo {
+ display: flex;
+ align-items: center;
+ font-size: 16px;
+ font-weight: bold;
+
+ & > div {
+ white-space: nowrap;
+ margin-right: 20px;
+ }
+ }
+ }
+}
+.stepItem {
+ width: 100%;
+ display: flex;
+ align-items: flex-start;
+ margin-bottom: 30px;
+ margin-left: 30px;
+ padding-bottom: 30px;
+ border-left: 2px solid #ccc;
+ &:first-of-type {
+ margin-top: 30px;
+ }
+ &:last-of-type {
+ margin-bottom: 0;
+ border-left: none;
+ }
+ .stepNum {
+ width: 30px;
+ height: 30px;
+ border-radius: 15px;
+ box-sizing: border-box;
+ color: #333;
+ border: 1px solid #999;
+ line-height: 28px;
+ text-align: center;
+ margin-right: 10px;
+ margin-left: -16px;
+ margin-top: -30px;
+ }
+ .stepCard {
+ width: 100%;
+ margin-top: -30px;
+
+ .box-card {
+ width: 100%;
+ &:deep(.el-card__header) {
+ padding: 10px 15px;
+ }
+ .card-header {
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ & > div:first-of-type {
+ margin-right: 80px;
+ font-size: 18px;
+ font-weight: bold;
+ }
+ }
+ }
+ }
+ &:hover .card-header {
+ color: #0098f5;
+ }
+ &:hover .stepNum {
+ border: 2px solid #0098f5;
+ color: #0098f5;
+ }
+}
+
+:deep(.el-date-editor) {
+ width: 100%;
+}
+.el-select {
+ width: 100%;
+}
+:deep(.el-textarea.is-disabled .el-textarea__inner) {
+ background-color: var(--el-card-bg-color);
+ color: var(--el-input-text-color, var(--el-text-color-regular));
+}
+:deep(.el-input.is-disabled .el-input__inner) {
+ color: var(--el-input-text-color, var(--el-text-color-regular));
+}
+:deep(.el-input.is-disabled .el-input__wrapper) {
+ background-color: var(--el-card-bg-color);
+}
+</style>
diff --git a/src/views/basic/material/components/materialDialog.vue b/src/views/basic/material/components/materialDialog.vue
new file mode 100644
index 0000000..559b711
--- /dev/null
+++ b/src/views/basic/material/components/materialDialog.vue
@@ -0,0 +1,169 @@
+<template>
+ <div class="system-menu-dialog-container">
+ <el-dialog :title="materialDialogState.title" v-model="materialDialogState.materialDialogVisible" width="600px">
+ <el-form ref="MaterialFormRef" :rules="materialDialogState.materialFormRules" :model="materialDialogState.materialForm" size="default" label-width="120px">
+ <el-row :gutter="35">
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="实验材料" prop="stuffName">
+ <el-input v-model="materialDialogState.materialForm.stuffName" placeholder="实验材料" clearable class="input-length"></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="编号" prop="stuffCode">
+ <el-input v-model="materialDialogState.materialForm.stuffCode" placeholder="编号" clearable class="input-length"></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="材料类型" prop="stuffType">
+ <el-select v-model="materialDialogState.materialForm.stuffType" placeholder="材料类型" clearable class="input-length">
+ <el-option v-for="item in materialDialogState.stuffTypeList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="材料储存" prop="stuffStorage">
+ <el-select v-model="materialDialogState.materialForm.stuffStorage" placeholder="材料储存" clearable class="input-length">
+ <el-option v-for="item in materialDialogState.stuffStorageList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="计量单位" prop="stuffUnit">
+ <el-select v-model="materialDialogState.materialForm.stuffUnit" placeholder="计量单位" clearable class="input-length">
+ <el-option v-for="item in materialDialogState.stuffUnitList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <template #footer>
+ <span class="dialog-footer">
+ <el-button @click="materialDialogState.materialDialogVisible = !materialDialogState.materialDialogVisible" size="default">取 消</el-button>
+ <el-button type="primary" @click="onSubmitMaterial" size="default">确定</el-button>
+ </span>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup lang="ts">
+import { reactive, ref } from "vue";
+import {useMenuApi} from "/@/api/systemManage/menu";
+import {ElMessage} from "element-plus";
+import {materialApi} from "/@/api/basic/material";
+
+const MaterialFormRef = ref()
+
+const materialDialogState = reactive<MaterialDialogType>({
+ title: '',
+ materialDialogVisible: false,
+ materialForm: {
+ stuffCode: '',
+ stuffName: '',
+ stuffStorage: null,
+ stuffType: null,
+ stuffUnit: null,
+ },
+ materialFormRules: {
+ stuffCode: [{ required: true, message: '请填写实验材料', trigger: 'blur' }],
+ stuffName: [{ required: true, message: '请填写编号', trigger: 'blur' }],
+ stuffStorage: [{ required: true, message: '请选择材料类型', trigger: 'change' }],
+ stuffType: [{ required: true, message: '请选择材料储存', trigger: 'change' }],
+ stuffUnit: [{ required: true, message: '请选择计量单位', trigger: 'change' }]
+ },
+ stuffTypeList: [
+ {id: 1, name: '化学试剂'},
+ {id:2, name: '基础材料'}
+ ],
+ stuffStorageList: [
+ {id:1, name: '智能试剂柜'},
+ {id:2, name: '普通储存柜'},
+ ],
+ stuffUnitList: [
+ {id:1, name: 'g'},
+ {id:2, name: 'kg'},
+ {id:3, name: 'ml'},
+ {id:4, name: 'l'},
+ ]
+})
+
+const showMaterialDialog = (title: string, value: MaterialType) => {
+ materialDialogState.materialDialogVisible = true;
+ setTimeout(() => {
+ MaterialFormRef.value.clearValidate();
+ });
+ if(title === '新增'){
+ materialDialogState.title = '新增';
+ materialDialogState.materialForm = {
+ stuffName: '',
+ stuffCode: '',
+ stuffType: null,
+ stuffStorage: null,
+ stuffUnit: null,
+ };
+ }else{
+ materialDialogState.title = '编辑'
+ materialDialogState.materialForm = {
+ id: value.id,
+ stuffName: value.stuffName,
+ stuffCode: value.stuffCode,
+ stuffType: value.stuffType,
+ stuffStorage: value.stuffStorage,
+ stuffUnit: value.stuffUnit,
+ };
+ }
+};
+
+const onSubmitMaterial = () => {
+ MaterialFormRef.value.validate(async(valid: boolean) => {
+ if(valid){
+ if(materialDialogState.title === '新增'){
+ let res = await materialApi().addMaterial(materialDialogState.materialForm);
+ if(res.data.code === 100){
+ emit('refresh')
+ materialDialogState.materialDialogVisible = false;
+ ElMessage({
+ type: 'success',
+ message: '新增成功'
+ })
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg,
+ });
+ }
+ }else{
+ let res = await materialApi().modMaterial(materialDialogState.materialForm)
+ if(res.data.code === 100){
+ emit('refresh')
+ materialDialogState.materialDialogVisible = false;
+ ElMessage({
+ type: 'success',
+ message: '编辑成功'
+ })
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg,
+ });
+ }
+ }
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: '请完善基本信息',
+ });
+ }
+ })
+}
+
+const emit = defineEmits(['refresh'])
+
+defineExpose({
+ showMaterialDialog
+})
+</script>
+
+<style scoped>
+
+</style>
diff --git a/src/views/basic/material/index.ts b/src/views/basic/material/index.ts
new file mode 100644
index 0000000..8be5c9a
--- /dev/null
+++ b/src/views/basic/material/index.ts
@@ -0,0 +1,48 @@
+declare interface MaterialStateType{
+ materialData: Array<MaterialType>
+ searchQuery: {
+ pageIndex: number,
+ pageSize: number,
+ stuffName: string,
+ stuffCode: string,
+ stuffType: number | null,
+ }
+ total: number,
+ stuffTypeList: Array<Type>,
+ stuffStorageList: Array<Type>,
+ stuffUnitList: Array<Type>
+}
+
+
+declare interface MaterialType {
+ id?: number | null,
+ stuffName: string,
+ stuffCode: string,
+ stuffType: number | null,
+ stuffStorage: number | null,
+ stuffUnit: number | null,
+}
+
+declare interface Type {
+ id: number,
+ name: string,
+}
+
+declare interface MaterialDialogType {
+ title: string,
+ materialDialogVisible: boolean,
+ materialForm: {
+ id?: number | null,
+ stuffName: string,
+ stuffCode: string,
+ stuffType: number | null,
+ stuffStorage: number | null,
+ stuffUnit: number | null,
+ },
+ materialFormRules: {
+
+ },
+ stuffTypeList: Array<Type>,
+ stuffStorageList: Array<Type>,
+ stuffUnitList: Array<Type>
+}
diff --git a/src/views/basic/material/index.vue b/src/views/basic/material/index.vue
new file mode 100644
index 0000000..1ac05d1
--- /dev/null
+++ b/src/views/basic/material/index.vue
@@ -0,0 +1,322 @@
+<template>
+ <div class="home-container">
+ <div style="height: 100%">
+ <el-row class="homeCard">
+ <div class="basic-line">
+ <span>实验材料:</span>
+ <el-input v-model="materialState.searchQuery.stuffName" clearable filterable class="input-box" placeholder="实验材料">
+ </el-input>
+ </div>
+ <div class="basic-line">
+ <span>耗材编号:</span>
+ <el-input v-model="materialState.searchQuery.stuffCode" clearable filterable class="input-box" placeholder="耗材编号">
+ </el-input>
+ </div>
+ <div class="basic-line">
+ <span>材料类型:</span>
+ <el-select v-model="materialState.searchQuery.stuffType" clearable filterable class="input-box" placeholder="材料类型">
+ <el-option v-for="item in materialState.stuffTypeList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+ </el-select>
+ </div>
+ <div style="padding-bottom: 10px">
+ <el-button type="primary" @click="getMaterialData">查询</el-button>
+ <el-button plain @click="reset">重置</el-button>
+ </div>
+ </el-row>
+ <div class="homeCard">
+ <div class="main-card">
+ <el-row class="cardTop">
+ <el-col :span="12" class="mainCardBtn">
+ <el-button type="primary" :icon="Plus" size="default" @click="openMaterialDialog('新增', {})">新增</el-button>
+ <!-- <el-button type="danger" :icon="Delete" size="default" plain>删除</el-button>-->
+ </el-col>
+<!-- <el-button type="primary" :icon="Refresh" size="default" />-->
+ </el-row>
+ <el-table ref="multipleTableRef" :data="materialState.materialData" style="width: 100%" height="calc(100% - 100px)" :header-cell-style="{ background: '#fafafa' }">
+ <el-table-column prop="stuffName" label="实验材料"/>
+ <el-table-column prop="stuffCode" label="编号" />
+ <el-table-column prop="stuffType" label="材料类型">
+ <template #default="scope">
+ <span>{{`${materialState.stuffTypeList.find(item =>item.id === scope.row.stuffType)?.name || ''}`}}</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="stuffStorage" label="材料储存" show-overflow-tooltip>
+ <template #default="scope">
+ <span>{{`${materialState.stuffStorageList.find(item =>item.id === scope.row.stuffStorage)?.name || ''}`}}</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="stuffUnit" label="计量单位" show-overflow-tooltip>
+ <template #default="scope">
+ <span>{{`${materialState.stuffUnitList.find(item =>item.id === scope.row.stuffUnit)?.name || ''}`}}</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="createTime" label="创建时间" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="createByUserName" label="创建人" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="updateTime" label="最后修改时间" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="updateByUserName" label="最后修改人" show-overflow-tooltip></el-table-column>
+ <el-table-column label="操作" width="150">
+ <template #default="scope">
+ <el-button size="small" text type="primary" :icon="Edit" @click="openMaterialDialog('修改', scope.row)">修改</el-button>
+ <el-button size="small" text type="danger" :icon="Delete" @click="onDelMaterial(scope.row)">删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ <div class="pageBtn">
+ <el-pagination @size-change="onHandleSizeChange" @current-change="onHandleCurrentChange" :pager-count="5" :page-sizes="[10, 20, 30]" v-model:current-page="materialState.searchQuery.pageIndex" background v-model:page-size="materialState.searchQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="materialState.total" class="page-position"> </el-pagination>
+ </div>
+ </div>
+ </div>
+ </div>
+ <material-dialog ref="materialDialogRef" @refresh="getMaterialData"></material-dialog>
+ </div>
+</template>
+
+<script setup lang="ts">
+import {defineAsyncComponent, onMounted, reactive, ref} from "vue";
+import { materialApi } from "/@/api/basic/material";
+import {ElMessage, ElMessageBox} from "element-plus";
+import { Edit, View, Plus, Delete } from '@element-plus/icons-vue';
+
+const MaterialDialog = defineAsyncComponent(() => import('./components/materialDialog.vue'));
+
+const materialDialogRef = ref();
+
+const materialState = reactive<MaterialStateType>({
+ materialData: [],
+ searchQuery: {
+ pageIndex: 1,
+ pageSize: 10,
+ stuffName: '',
+ stuffCode: '',
+ stuffType: null,
+ },
+ total: 0,
+ stuffTypeList: [
+ {id: 1, name: '化学试剂'},
+ {id:2, name: '基础材料'}
+ ],
+ stuffStorageList: [
+ {id:1, name: '智能试剂柜'},
+ {id:2, name: '普通储存柜'},
+ ],
+ stuffUnitList: [
+ {id:1, name: 'g'},
+ {id:2, name: 'kg'},
+ {id:3, name: 'ml'},
+ {id:4, name: 'l'},
+ ]
+})
+
+const getMaterialData = async () => {
+ let res = await materialApi().getMaterialByList(materialState.searchQuery);
+ if(res.data.code === 100){
+ materialState.materialData = res.data.data;
+ materialState.total = res.data.total;
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ });
+ }
+};
+
+const openMaterialDialog = (title: string, value: MaterialType) => {
+ materialDialogRef.value.showMaterialDialog(title, value);
+};
+
+const onDelMaterial = (val: MaterialType) => {
+ ElMessageBox.confirm(`此操作将永久删除该设备:“${val.stuffName}”,是否继续?`, '提示', {
+ confirmButtonText: '确认',
+ cancelButtonText: '取消',
+ type: 'warning'
+ })
+ .then(async () => {
+ let res = await materialApi().deleteMaterialById({ id: val.id });
+ if (res.data.code === 100) {
+ ElMessage({
+ type: 'success',
+ duration: 2000,
+ message: '删除成功'
+ });
+ await getMaterialData();
+ } else {
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ });
+ }
+ })
+ .catch((error) => {
+ });
+}
+
+const onHandleSizeChange = (val: number) => {
+ materialState.searchQuery.pageSize = val;
+ getMaterialData();
+};
+
+const onHandleCurrentChange = (val: number) => {
+ materialState.searchQuery.pageIndex = val;
+ getMaterialData();
+};
+
+const reset = () => {
+ materialState.searchQuery = {
+ pageIndex: 1,
+ pageSize: 10,
+ stuffName: '',
+ stuffCode: '',
+ stuffType: null,
+ }
+};
+
+onMounted(() => {
+ getMaterialData()
+})
+
+</script>
+
+<style scoped lang="scss">
+$homeNavLengh: 8;
+.home-container {
+ height: calc(100vh - 144px);
+ box-sizing: border-box;
+ overflow: hidden;
+ .homeCard {
+ width: 100%;
+ padding: 20px;
+ box-sizing: border-box;
+ background: #fff;
+ border-radius: 4px;
+
+ .main-card {
+ width: 100%;
+ height: 100%;
+ .cardTop {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 20px;
+ .mainCardBtn {
+ margin: 0;
+ }
+ }
+ .pageBtn {
+ height: 60px;
+ display: flex;
+ align-items: center;
+ justify-content: right;
+
+ .demo-pagination-block + .demo-pagination-block {
+ margin-top: 10px;
+ }
+ .demo-pagination-block .demonstration {
+ margin-bottom: 16px;
+ }
+ }
+ }
+ &:last-of-type {
+ height: calc(100% - 100px);
+ }
+ }
+ .el-row {
+ display: flex;
+ align-items: center;
+ margin-bottom: 20px;
+ &:last-child {
+ margin-bottom: 0;
+ }
+ .grid-content {
+ align-items: center;
+ min-height: 36px;
+ }
+
+ .topInfo {
+ display: flex;
+ align-items: center;
+ font-size: 16px;
+ font-weight: bold;
+
+ & > div {
+ white-space: nowrap;
+ margin-right: 20px;
+ }
+ }
+ }
+}
+.stepItem {
+ width: 100%;
+ display: flex;
+ align-items: flex-start;
+ margin-bottom: 30px;
+ margin-left: 30px;
+ padding-bottom: 30px;
+ border-left: 2px solid #ccc;
+ &:first-of-type {
+ margin-top: 30px;
+ }
+ &:last-of-type {
+ margin-bottom: 0;
+ border-left: none;
+ }
+ .stepNum {
+ width: 30px;
+ height: 30px;
+ border-radius: 15px;
+ box-sizing: border-box;
+ color: #333;
+ border: 1px solid #999;
+ line-height: 28px;
+ text-align: center;
+ margin-right: 10px;
+ margin-left: -16px;
+ margin-top: -30px;
+ }
+ .stepCard {
+ width: 100%;
+ margin-top: -30px;
+
+ .box-card {
+ width: 100%;
+ &:deep(.el-card__header) {
+ padding: 10px 15px;
+ }
+ .card-header {
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ & > div:first-of-type {
+ margin-right: 80px;
+ font-size: 18px;
+ font-weight: bold;
+ }
+ }
+ }
+ }
+ &:hover .card-header {
+ color: #0098f5;
+ }
+ &:hover .stepNum {
+ border: 2px solid #0098f5;
+ color: #0098f5;
+ }
+}
+
+:deep(.el-date-editor) {
+ width: 100%;
+}
+.el-select {
+ width: 100%;
+}
+:deep(.el-textarea.is-disabled .el-textarea__inner) {
+ background-color: var(--el-card-bg-color);
+ color: var(--el-input-text-color, var(--el-text-color-regular));
+}
+:deep(.el-input.is-disabled .el-input__inner) {
+ color: var(--el-input-text-color, var(--el-text-color-regular));
+}
+:deep(.el-input.is-disabled .el-input__wrapper) {
+ background-color: var(--el-card-bg-color);
+}
+</style>
diff --git a/src/views/basic/person/components/personDialog.vue b/src/views/basic/person/components/personDialog.vue
new file mode 100644
index 0000000..65e7a44
--- /dev/null
+++ b/src/views/basic/person/components/personDialog.vue
@@ -0,0 +1,197 @@
+<template>
+ <div class="system-menu-dialog-container">
+ <el-dialog :title="personDialogState.title" v-model="personDialogState.personDialogVisible" width="600px">
+ <el-form ref="PersonFormRef" :rules="personDialogState.personFormRules" :model="personDialogState.personForm" size="default" label-width="120px">
+ <el-row :gutter="35">
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="人员名称" prop="personName">
+ <el-input v-model="personDialogState.personForm.personName" placeholder="人员名称" clearable class="input-length"></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="人员年龄" prop="personAge">
+ <el-input @input="onVerifiyNumberInteger($event, 'age')" v-model="personDialogState.personForm.personAge" placeholder="人员年龄" clearable class="input-length"></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="人员性别" prop="personGender">
+ <el-select v-model="personDialogState.personForm.personGender" placeholder="人员性别" clearable class="input-length">
+ <el-option v-for="item in personDialogState.personGenderList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="专业" prop="personMajor">
+ <el-input v-model="personDialogState.personForm.personMajor" placeholder="专业" clearable class="input-length"></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="部门名称" prop="depName">
+ <el-input v-model="personDialogState.personForm.depName" placeholder="部门名称" clearable class="input-length"></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="手机号" prop="phone">
+ <el-input @input="onVerifiyNumberInteger($event, 'phone')" v-model="personDialogState.personForm.phone" placeholder="手机号" clearable class="input-length"></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="相关资质" prop="aptitude">
+ <el-input v-model="personDialogState.personForm.aptitude" placeholder="相关资质" clearable class="input-length"></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="培训情况" prop="training">
+ <el-select v-model="personDialogState.personForm.training" placeholder="培训情况" clearable class="input-length">
+ <el-option v-for="item in personDialogState.trainingList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <template #footer>
+ <span class="dialog-footer">
+ <el-button @click="personDialogState.personDialogVisible = !personDialogState.personDialogVisible" size="default">取 消</el-button>
+ <el-button type="primary" @click="onSubmitPerson" size="default">确定</el-button>
+ </span>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup lang="ts">
+import { reactive, ref } from "vue";
+import {useMenuApi} from "/@/api/systemManage/menu";
+import {ElMessage} from "element-plus";
+import {personApi} from "/@/api/basic/person";
+import { verifiyNumberInteger } from '../../../../utils/toolsValidate'
+
+const PersonFormRef = ref()
+
+const personDialogState = reactive<PersonDialogType>({
+ title: '',
+ personDialogVisible: false,
+ personForm: {
+ personName: '',
+ personAge: null,
+ personGender: null,
+ personMajor: '',
+ depName: '',
+ phone: null,
+ aptitude: '',
+ training: null,
+ },
+ personFormRules: {
+ personName: [{ required: true, message: '请填写人员名称', trigger: 'blur' }],
+ personMajor: [{ required: true, message: '请填写专业', trigger: 'blur' }],
+ aptitude: [{ required: true, message: '请填写相关资质', trigger: 'blur' }],
+ personAge: [{ required: true, message: '请填写人员年龄', trigger: 'blur' }],
+ personGender: [{ required: true, message: '请选择人员性别', trigger: 'change' }],
+ phone: [{ required: true, message: '请填写手机号', trigger: 'blur' }],
+ training: [{ required: true, message: '请选择培训情况', trigger: 'change' }]
+ },
+ personGenderList: [
+ {id:1, name: '男'},
+ {id:2, name: '女'},
+ ],
+ trainingList: [
+ {id:1, name: '已完成当期安全培训'},
+ {id:2, name: '未完成当期安全培训'},
+ ]
+})
+
+const showPersonDialog = (title: string, value: PersonType,) => {
+
+ personDialogState.personDialogVisible = true;
+ setTimeout(() => {
+ PersonFormRef.value.clearValidate();
+ });
+ if(title === '新增'){
+ personDialogState.title = '新增';
+ personDialogState.personForm = {
+ personName: '',
+ personAge: null,
+ personGender: null,
+ personMajor: '',
+ depName: '',
+ phone: null,
+ aptitude: '',
+ training: null,
+ };
+ }else{
+ personDialogState.title = '编辑'
+ personDialogState.personForm = {
+ id: value.id,
+ personName: value.personName,
+ personAge: value.personAge,
+ personGender: value.personGender,
+ personMajor: value.personMajor,
+ depName: value.depName,
+ phone: value.phone,
+ aptitude: value.aptitude,
+ training: value.training,
+ };
+ }
+};
+
+const onSubmitPerson = () => {
+ PersonFormRef.value.validate(async(valid: boolean) => {
+ if(valid){
+ if(personDialogState.title === '新增'){
+ let res = await personApi().addPerson(personDialogState.personForm);
+ if(res.data.code === 100){
+ emit('refresh')
+ personDialogState.personDialogVisible = false;
+ ElMessage({
+ type: 'success',
+ message: '新增成功'
+ })
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg,
+ });
+ }
+ }else{
+ let res = await personApi().modPerson(personDialogState.personForm)
+ if(res.data.code === 100){
+ emit('refresh')
+ personDialogState.personDialogVisible = false;
+ ElMessage({
+ type: 'success',
+ message: '编辑成功'
+ })
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg,
+ });
+ }
+ }
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: '请完善基本信息',
+ });
+ }
+ })
+};
+
+const onVerifiyNumberInteger = (val: number, title: string) => {
+ if (title === 'age') {
+ personDialogState.personForm.personAge = Number(verifiyNumberInteger(val.toString())) === 0 ? null : Number(verifiyNumberInteger(val.toString()));
+ } else if (title === 'phone') {
+ personDialogState.personForm.phone = Number(verifiyNumberInteger(val.toString())) === 0 ? null : Number(verifiyNumberInteger(val.toString()));
+ }
+};
+
+const emit = defineEmits(['refresh']);
+
+defineExpose({
+ showPersonDialog
+});
+</script>
+
+<style scoped>
+
+</style>
diff --git a/src/views/basic/person/index.ts b/src/views/basic/person/index.ts
new file mode 100644
index 0000000..c1de227
--- /dev/null
+++ b/src/views/basic/person/index.ts
@@ -0,0 +1,52 @@
+declare interface PersonStateType extends PublicType{
+ personData: Array<PersonType>
+ searchQuery: {
+ pageIndex: number,
+ pageSize: number,
+ personName: string,
+ training: number | null,
+ depName: string,
+ }
+ total: number
+}
+
+declare interface PersonType {
+ id?: number | null,
+ personName: string,
+ personAge: number | null,
+ personGender: number | null,
+ personMajor: string,
+ depName: string,
+ phone: number | null,
+ aptitude: string,
+ training: number | null,
+}
+
+declare interface PublicType {
+ personGenderList: Array<Type>,
+ trainingList: Array<Type>
+}
+
+declare interface Type {
+ id: number,
+ name: string,
+}
+
+declare interface PersonDialogType extends PublicType{
+ title: string,
+ personDialogVisible: boolean,
+ personForm: {
+ id?: number | null,
+ personName: string,
+ personAge: number | null,
+ personGender: number | null,
+ personMajor: string,
+ depName: string,
+ phone: number | null,
+ aptitude: string,
+ training: number | null,
+ },
+ personFormRules: {
+
+ },
+}
diff --git a/src/views/basic/person/index.vue b/src/views/basic/person/index.vue
new file mode 100644
index 0000000..0492573
--- /dev/null
+++ b/src/views/basic/person/index.vue
@@ -0,0 +1,315 @@
+<template>
+ <div class="home-container">
+ <div style="height: 100%">
+ <el-row class="homeCard">
+ <div class="basic-line">
+ <span>人员名称:</span>
+ <el-input v-model="personState.searchQuery.personName" clearable filterable class="input-box" placeholder="人员名称">
+ </el-input>
+ </div>
+ <div class="basic-line">
+ <span>部门名称:</span>
+ <el-input v-model="personState.searchQuery.depName" clearable filterable class="input-box" placeholder="部门名称">
+ </el-input>
+ </div>
+ <div class="basic-line">
+ <span>培训情况:</span>
+ <el-select v-model="personState.searchQuery.training" clearable filterable class="input-box" placeholder="培训情况">
+ <el-option v-for="item in personState.trainingList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+ </el-select>
+ </div>
+ <div style="padding-bottom: 10px">
+ <el-button type="primary" @click="getPersonData">查询</el-button>
+ <el-button plain @click="reset">重置</el-button>
+ </div>
+ </el-row>
+ <div class="homeCard">
+ <div class="main-card">
+ <el-row class="cardTop">
+ <el-col :span="12" class="mainCardBtn">
+ <el-button type="primary" :icon="Plus" size="default" @click="openPersonDialog('新增', {})">新增</el-button>
+ <!-- <el-button type="danger" :icon="Delete" size="default" plain>删除</el-button>-->
+ </el-col>
+<!-- <el-button type="primary" :icon="Refresh" size="default" />-->
+ </el-row>
+ <el-table ref="multipleTableRef" :data="personState.personData" style="width: 100%" height="calc(100% - 100px)" :header-cell-style="{ background: '#fafafa' }">
+ <el-table-column prop="personName" label="人员名称"/>
+ <el-table-column prop="personAge" label="年龄" />
+ <el-table-column prop="personGender" label="性别">
+ <template #default="scope">
+ <span>{{`${personState.personGenderList.find(item =>item.id === scope.row.personGender)?.name || ''}`}}</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="personMajor" label="专业" show-overflow-tooltip/>
+ <el-table-column prop="depName" label="部门名称" show-overflow-tooltip/>
+ <el-table-column prop="phone" label="手机号" show-overflow-tooltip/>
+ <el-table-column prop="aptitude" label="相关资质" show-overflow-tooltip/>
+ <el-table-column prop="training" label="培训情况" show-overflow-tooltip>
+ <template #default="scope">
+ <span>{{`${personState.trainingList.find(item =>item.id === scope.row.training)?.name || ''}`}}</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="createTime" label="创建时间" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="createByUserName" label="创建人" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="updateTime" label="最后修改时间" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="updateByUserName" label="最后修改人" show-overflow-tooltip></el-table-column>
+ <el-table-column label="操作" width="150">
+ <template #default="scope">
+ <el-button size="small" text type="primary" :icon="Edit" @click="openPersonDialog('修改', scope.row)">修改</el-button>
+ <el-button size="small" text type="danger" :icon="Delete" @click="onDelPerson(scope.row)">删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ <div class="pageBtn">
+ <el-pagination @size-change="onHandleSizeChange" @current-change="onHandleCurrentChange" :pager-count="5" :page-sizes="[10, 20, 30]" v-model:current-page="personState.searchQuery.pageIndex" background v-model:page-size="personState.searchQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="personState.total" class="page-position"> </el-pagination>
+ </div>
+ </div>
+ </div>
+ </div>
+ <person-dialog ref="personDialogRef" @refresh="getPersonData"></person-dialog>
+ </div>
+</template>
+
+<script setup lang="ts">
+import {defineAsyncComponent, onMounted, reactive, ref} from "vue";
+import {personApi} from "/@/api/basic/person";
+import {ElMessage, ElMessageBox} from "element-plus";
+import { Edit, View, Plus, Delete } from '@element-plus/icons-vue';
+
+const PersonDialog = defineAsyncComponent(() => import('./components/personDialog.vue'));
+
+const personDialogRef = ref();
+
+const personState = reactive<PersonStateType>({
+ personData: [],
+ searchQuery: {
+ pageIndex: 1,
+ pageSize: 10,
+ personName: '',
+ training: null,
+ depName: '',
+ },
+ total: 0,
+ personGenderList: [
+ {id:1, name: '男'},
+ {id:2, name: '女'},
+ ],
+ trainingList: [
+ {id: 1, name: '已完成当期安全培训'},
+ {id:2, name: '未完成当期安全培训'}
+ ],
+})
+
+const getPersonData = async () => {
+ let res = await personApi().getPersonByList(personState.searchQuery);
+ if(res.data.code === 100){
+ personState.personData = res.data.data;
+ personState.total = res.data.total;
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ });
+ }
+};
+
+const openPersonDialog = (title: string, value: PersonType) => {
+ personDialogRef.value.showPersonDialog(title, value);
+};
+
+const onDelPerson = (val: PersonType) => {
+ ElMessageBox.confirm(`此操作将永久删除该设备:“${val.personName}”,是否继续?`, '提示', {
+ confirmButtonText: '确认',
+ cancelButtonText: '取消',
+ type: 'warning'
+ })
+ .then(async () => {
+ let res = await personApi().deletePersonById({ id: val.id });
+ if (res.data.code === 100) {
+ ElMessage({
+ type: 'success',
+ duration: 2000,
+ message: '删除成功'
+ });
+ await getPersonData();
+ } else {
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ });
+ }
+ })
+ .catch((error) => {
+ });
+}
+
+const onHandleSizeChange = (val: number) => {
+ personState.searchQuery.pageSize = val;
+ getPersonData();
+};
+
+const onHandleCurrentChange = (val: number) => {
+ personState.searchQuery.pageIndex = val;
+ getPersonData();
+};
+
+const reset = () => {
+ personState.searchQuery = {
+ pageIndex: 1,
+ pageSize: 10,
+ personName: '',
+ training: null,
+ depName: '',
+ }
+};
+
+onMounted(() => {
+ getPersonData()
+})
+
+</script>
+
+<style scoped lang="scss">
+$homeNavLengh: 8;
+.home-container {
+ height: calc(100vh - 144px);
+ box-sizing: border-box;
+ overflow: hidden;
+ .homeCard {
+ width: 100%;
+ padding: 20px;
+ box-sizing: border-box;
+ background: #fff;
+ border-radius: 4px;
+
+ .main-card {
+ width: 100%;
+ height: 100%;
+ .cardTop {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 20px;
+ .mainCardBtn {
+ margin: 0;
+ }
+ }
+ .pageBtn {
+ height: 60px;
+ display: flex;
+ align-items: center;
+ justify-content: right;
+
+ .demo-pagination-block + .demo-pagination-block {
+ margin-top: 10px;
+ }
+ .demo-pagination-block .demonstration {
+ margin-bottom: 16px;
+ }
+ }
+ }
+ &:last-of-type {
+ height: calc(100% - 100px);
+ }
+ }
+ .el-row {
+ display: flex;
+ align-items: center;
+ margin-bottom: 20px;
+ &:last-child {
+ margin-bottom: 0;
+ }
+ .grid-content {
+ align-items: center;
+ min-height: 36px;
+ }
+
+ .topInfo {
+ display: flex;
+ align-items: center;
+ font-size: 16px;
+ font-weight: bold;
+
+ & > div {
+ white-space: nowrap;
+ margin-right: 20px;
+ }
+ }
+ }
+}
+.stepItem {
+ width: 100%;
+ display: flex;
+ align-items: flex-start;
+ margin-bottom: 30px;
+ margin-left: 30px;
+ padding-bottom: 30px;
+ border-left: 2px solid #ccc;
+ &:first-of-type {
+ margin-top: 30px;
+ }
+ &:last-of-type {
+ margin-bottom: 0;
+ border-left: none;
+ }
+ .stepNum {
+ width: 30px;
+ height: 30px;
+ border-radius: 15px;
+ box-sizing: border-box;
+ color: #333;
+ border: 1px solid #999;
+ line-height: 28px;
+ text-align: center;
+ margin-right: 10px;
+ margin-left: -16px;
+ margin-top: -30px;
+ }
+ .stepCard {
+ width: 100%;
+ margin-top: -30px;
+
+ .box-card {
+ width: 100%;
+ &:deep(.el-card__header) {
+ padding: 10px 15px;
+ }
+ .card-header {
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ & > div:first-of-type {
+ margin-right: 80px;
+ font-size: 18px;
+ font-weight: bold;
+ }
+ }
+ }
+ }
+ &:hover .card-header {
+ color: #0098f5;
+ }
+ &:hover .stepNum {
+ border: 2px solid #0098f5;
+ color: #0098f5;
+ }
+}
+
+:deep(.el-date-editor) {
+ width: 100%;
+}
+.el-select {
+ width: 100%;
+}
+:deep(.el-textarea.is-disabled .el-textarea__inner) {
+ background-color: var(--el-card-bg-color);
+ color: var(--el-input-text-color, var(--el-text-color-regular));
+}
+:deep(.el-input.is-disabled .el-input__inner) {
+ color: var(--el-input-text-color, var(--el-text-color-regular));
+}
+:deep(.el-input.is-disabled .el-input__wrapper) {
+ background-color: var(--el-card-bg-color);
+}
+</style>
diff --git a/src/views/basic/room/components/roomDialog.vue b/src/views/basic/room/components/roomDialog.vue
new file mode 100644
index 0000000..51ccec4
--- /dev/null
+++ b/src/views/basic/room/components/roomDialog.vue
@@ -0,0 +1,139 @@
+<template>
+ <div class="system-menu-dialog-container">
+ <el-dialog :title="roomDialogState.title" v-model="roomDialogState.roomDialogVisible" width="600px">
+ <el-form ref="roomFormRef" :rules="roomDialogState.roomFormRules" :model="roomDialogState.roomForm" size="default" label-width="120px">
+ <el-row :gutter="35">
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="场所名称" prop="siteName">
+ <el-input v-model="roomDialogState.roomForm.siteName" placeholder="场所名称" clearable class="input-length"></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="实验室所在楼" prop="floor">
+ <el-input v-model="roomDialogState.roomForm.floor" placeholder="实验室所在楼" clearable class="input-length"></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="实验室所在房间" prop="room">
+ <el-input v-model="roomDialogState.roomForm.room" placeholder="实验室所在房间" clearable class="input-length"></el-input>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <template #footer>
+ <span class="dialog-footer">
+ <el-button @click="roomDialogState.roomDialogVisible = !roomDialogState.roomDialogVisible" size="default">取 消</el-button>
+ <el-button type="primary" @click="onSubmitRoom" size="default">确定</el-button>
+ </span>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup lang="ts">
+import { reactive, ref } from "vue";
+import {ElMessage} from "element-plus";
+import {roomApi} from "/@/api/basic/room";
+
+const roomFormRef = ref()
+
+const roomDialogState = reactive<RoomDialogType>({
+ title: '',
+ roomDialogVisible: false,
+ roomForm: {
+ siteName: '',
+ floor: '',
+ room: '',
+ },
+ roomFormRules: {
+ deviceCode: [{ required: true, message: '请填写设备编号', trigger: 'blur' }],
+ deviceName: [{ required: true, message: '请填写设备名称', trigger: 'blur' }],
+ devicePower: [{ required: true, message: '请填写设备功率', trigger: 'blur' }],
+ deviceUnit: [{ required: true, message: '请选择计量单位', trigger: 'change' }]
+ },
+ specialDeviceList: [],
+ deviceUnitList: [
+ {id:1, name: '台'},
+ {id:2, name: '个'},
+ {id:3, name: '件'}
+ ]
+})
+
+const showroomDialog = (title: string, value: RoomType, specialDeviceList: Type []) => {
+
+ roomDialogState.roomDialogVisible = true;
+ roomDialogState.specialDeviceList = specialDeviceList;
+ setTimeout(() => {
+ roomFormRef.value.clearValidate();
+ });
+ if(title === '新增'){
+ roomDialogState.title = '新增';
+ roomDialogState.roomForm = {
+ siteName: '',
+ floor: '',
+ room: '',
+ };
+ }else{
+ roomDialogState.title = '编辑'
+ roomDialogState.roomForm = {
+ id: value.id,
+ siteName: value.siteName,
+ floor: value.floor,
+ room: value.room,
+ };
+ }
+};
+
+const onSubmitRoom = () => {
+ roomFormRef.value.validate(async(valid: boolean) => {
+ if(valid){
+ if(roomDialogState.title === '新增'){
+ let res = await roomApi().addRoom(roomDialogState.roomForm);
+ if(res.data.code === 100){
+ emit('refresh')
+ roomDialogState.roomDialogVisible = false;
+ ElMessage({
+ type: 'success',
+ message: '新增成功'
+ })
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg,
+ });
+ }
+ }else{
+ let res = await roomApi().modRoom(roomDialogState.roomForm)
+ if(res.data.code === 100){
+ emit('refresh')
+ roomDialogState.roomDialogVisible = false;
+ ElMessage({
+ type: 'success',
+ message: '编辑成功'
+ })
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg,
+ });
+ }
+ }
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: '请完善基本信息',
+ });
+ }
+ })
+}
+
+const emit = defineEmits(['refresh'])
+
+defineExpose({
+ showroomDialog
+})
+</script>
+
+<style scoped>
+
+</style>
diff --git a/src/views/basic/room/index.ts b/src/views/basic/room/index.ts
new file mode 100644
index 0000000..677de72
--- /dev/null
+++ b/src/views/basic/room/index.ts
@@ -0,0 +1,41 @@
+declare interface RoomStateType {
+ roomData: Array<RoomType>
+ searchQuery: {
+ pageIndex: number,
+ pageSize: number,
+ siteName: string,
+ floor: string,
+ room: string,
+ }
+ total: number
+ specialDeviceList: Array<Type>,
+ deviceUnitList: Array<Type>
+}
+
+declare interface RoomType {
+ id?: number | null,
+ siteName: string,
+ floor: string,
+ room: string,
+}
+
+declare interface Type {
+ id: number,
+ name: string,
+}
+
+declare interface RoomDialogType {
+ title: string,
+ roomDialogVisible: boolean,
+ roomForm: {
+ id?: number | null,
+ siteName: string,
+ floor: string,
+ room: string,
+ },
+ roomFormRules: {
+
+ },
+ specialDeviceList: Array<Type>,
+ deviceUnitList: Array<Type>
+}
diff --git a/src/views/basic/room/index.vue b/src/views/basic/room/index.vue
new file mode 100644
index 0000000..0af9501
--- /dev/null
+++ b/src/views/basic/room/index.vue
@@ -0,0 +1,302 @@
+<template>
+ <div class="home-container">
+ <div style="height: 100%">
+ <el-row class="homeCard">
+ <div class="basic-line">
+ <span>场所名称:</span>
+ <el-input v-model="roomState.searchQuery.siteName" clearable filterable class="input-box" placeholder="场所名称">
+ </el-input>
+ </div>
+ <div class="basic-line">
+ <span>楼:</span>
+ <el-input v-model="roomState.searchQuery.floor" clearable filterable class="input-box" placeholder="楼">
+ </el-input>
+ </div>
+ <div class="basic-line">
+ <span>房间号:</span>
+ <el-input v-model="roomState.searchQuery.room" clearable filterable class="input-box" placeholder="房间号">
+ </el-input>
+ </div>
+ <div style="padding-bottom: 10px">
+ <el-button type="primary" @click="getRoomData">查询</el-button>
+ <el-button plain @click="reset">重置</el-button>
+ </div>
+ </el-row>
+ <div class="homeCard">
+ <div class="main-card">
+ <el-row class="cardTop">
+ <el-col :span="12" class="mainCardBtn">
+ <el-button type="primary" :icon="Plus" size="default" @click="openRoomDialog('新增', {})">新增</el-button>
+ <!-- <el-button type="danger" :icon="Delete" size="default" plain>删除</el-button>-->
+ </el-col>
+<!-- <el-button type="primary" :icon="Refresh" size="default" />-->
+ </el-row>
+ <el-table ref="multipleTableRef" :data="roomState.roomData" style="width: 100%" height="calc(100% - 100px)" :header-cell-style="{ background: '#fafafa' }">
+ <el-table-column prop="siteName" label="场所名称"/>
+ <el-table-column prop="floor" label="实验室所在楼" />
+ <el-table-column prop="room" label="实验室所在房间"/>
+ <el-table-column prop="createTime" label="创建时间" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="createByUserName" label="创建人" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="updateTime" label="最后修改时间" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="updateByUserName" label="最后修改人" show-overflow-tooltip></el-table-column>
+ <el-table-column label="操作" width="150">
+ <template #default="scope">
+ <el-button size="small" text type="primary" :icon="Edit" @click="openRoomDialog('修改', scope.row)">修改</el-button>
+ <el-button size="small" text type="danger" :icon="Delete" @click="onDelRoom(scope.row)">删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ <div class="pageBtn">
+ <el-pagination @size-change="onHandleSizeChange" @current-change="onHandleCurrentChange" :pager-count="5" :page-sizes="[10, 20, 30]" v-model:current-page="roomState.searchQuery.pageIndex" background v-model:page-size="roomState.searchQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="roomState.total" class="page-position"> </el-pagination>
+ </div>
+ </div>
+ </div>
+ </div>
+ <room-dialog ref="roomDialogRef" @refresh="getRoomData"></room-dialog>
+ </div>
+</template>
+
+<script setup lang="ts">
+import {defineAsyncComponent, onMounted, reactive, ref} from "vue";
+import {roomApi} from "/@/api/basic/room";
+import {ElMessage, ElMessageBox} from "element-plus";
+import { Edit, View, Plus, Delete } from '@element-plus/icons-vue';
+
+const RoomDialog = defineAsyncComponent(() => import('./components/roomDialog.vue'));
+
+const roomDialogRef = ref();
+
+const roomState = reactive<RoomStateType>({
+ roomData: [],
+ searchQuery: {
+ pageIndex: 1,
+ pageSize: 10,
+ siteName: '',
+ floor: '',
+ room: '',
+ },
+ total: 0,
+ specialDeviceList: [
+ {id: 1, name: '是'},
+ {id:2, name: '否'}
+ ],
+ deviceUnitList: [
+ {id:1, name: '台'},
+ {id:2, name: '个'},
+ {id:3, name: '件'}
+ ]
+})
+
+const getRoomData = async () => {
+ let res = await roomApi().getRoomByList(roomState.searchQuery);
+ if(res.data.code === 100){
+ roomState.roomData = res.data.data;
+ roomState.total = res.data.total;
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ });
+ }
+};
+
+const openRoomDialog = (title: string, value: RoomType) => {
+ roomDialogRef.value.showroomDialog(title, value, roomState.specialDeviceList);
+};
+
+const onDelRoom = (val: RoomType) => {
+ ElMessageBox.confirm(`此操作将永久删除该设备:“${val.siteName}”,是否继续?`, '提示', {
+ confirmButtonText: '确认',
+ cancelButtonText: '取消',
+ type: 'warning'
+ })
+ .then(async () => {
+ let res = await roomApi().deleteRoomById({ id: val.id });
+ if (res.data.code === 100) {
+ ElMessage({
+ type: 'success',
+ duration: 2000,
+ message: '删除成功'
+ });
+ await getRoomData();
+ } else {
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ });
+ }
+ })
+ .catch((error) => {
+ });
+}
+
+const onHandleSizeChange = (val: number) => {
+ roomState.searchQuery.pageSize = val;
+ getRoomData();
+};
+
+const onHandleCurrentChange = (val: number) => {
+ roomState.searchQuery.pageIndex = val;
+ getRoomData();
+};
+
+const reset = () => {
+ roomState.searchQuery = {
+ pageIndex: 1,
+ pageSize: 10,
+ siteName: '',
+ floor: '',
+ room: '',
+ }
+};
+
+onMounted(() => {
+ getRoomData()
+})
+
+</script>
+
+<style scoped lang="scss">
+$homeNavLengh: 8;
+.home-container {
+ height: calc(100vh - 144px);
+ box-sizing: border-box;
+ overflow: hidden;
+ .homeCard {
+ width: 100%;
+ padding: 20px;
+ box-sizing: border-box;
+ background: #fff;
+ border-radius: 4px;
+
+ .main-card {
+ width: 100%;
+ height: 100%;
+ .cardTop {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 20px;
+ .mainCardBtn {
+ margin: 0;
+ }
+ }
+ .pageBtn {
+ height: 60px;
+ display: flex;
+ align-items: center;
+ justify-content: right;
+
+ .demo-pagination-block + .demo-pagination-block {
+ margin-top: 10px;
+ }
+ .demo-pagination-block .demonstration {
+ margin-bottom: 16px;
+ }
+ }
+ }
+ &:last-of-type {
+ height: calc(100% - 100px);
+ }
+ }
+ .el-row {
+ display: flex;
+ align-items: center;
+ margin-bottom: 20px;
+ &:last-child {
+ margin-bottom: 0;
+ }
+ .grid-content {
+ align-items: center;
+ min-height: 36px;
+ }
+
+ .topInfo {
+ display: flex;
+ align-items: center;
+ font-size: 16px;
+ font-weight: bold;
+
+ & > div {
+ white-space: nowrap;
+ margin-right: 20px;
+ }
+ }
+ }
+}
+.stepItem {
+ width: 100%;
+ display: flex;
+ align-items: flex-start;
+ margin-bottom: 30px;
+ margin-left: 30px;
+ padding-bottom: 30px;
+ border-left: 2px solid #ccc;
+ &:first-of-type {
+ margin-top: 30px;
+ }
+ &:last-of-type {
+ margin-bottom: 0;
+ border-left: none;
+ }
+ .stepNum {
+ width: 30px;
+ height: 30px;
+ border-radius: 15px;
+ box-sizing: border-box;
+ color: #333;
+ border: 1px solid #999;
+ line-height: 28px;
+ text-align: center;
+ margin-right: 10px;
+ margin-left: -16px;
+ margin-top: -30px;
+ }
+ .stepCard {
+ width: 100%;
+ margin-top: -30px;
+
+ .box-card {
+ width: 100%;
+ &:deep(.el-card__header) {
+ padding: 10px 15px;
+ }
+ .card-header {
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ & > div:first-of-type {
+ margin-right: 80px;
+ font-size: 18px;
+ font-weight: bold;
+ }
+ }
+ }
+ }
+ &:hover .card-header {
+ color: #0098f5;
+ }
+ &:hover .stepNum {
+ border: 2px solid #0098f5;
+ color: #0098f5;
+ }
+}
+
+:deep(.el-date-editor) {
+ width: 100%;
+}
+.el-select {
+ width: 100%;
+}
+:deep(.el-textarea.is-disabled .el-textarea__inner) {
+ background-color: var(--el-card-bg-color);
+ color: var(--el-input-text-color, var(--el-text-color-regular));
+}
+:deep(.el-input.is-disabled .el-input__inner) {
+ color: var(--el-input-text-color, var(--el-text-color-regular));
+}
+:deep(.el-input.is-disabled .el-input__wrapper) {
+ background-color: var(--el-card-bg-color);
+}
+</style>
diff --git a/src/views/basic/unit/components/unitDialog.vue b/src/views/basic/unit/components/unitDialog.vue
new file mode 100644
index 0000000..00341fe
--- /dev/null
+++ b/src/views/basic/unit/components/unitDialog.vue
@@ -0,0 +1,167 @@
+<template>
+ <div class="system-menu-dialog-container">
+ <el-dialog :title="unitDialogState.title" v-model="unitDialogState.unitDialogVisible" width="600px">
+ <el-form ref="UnitFormRef" :rules="unitDialogState.unitFormRules" :model="unitDialogState.unitForm" size="default" label-width="120px">
+ <el-row :gutter="35">
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="设备编号" prop="deviceCode">
+ <el-input v-model="unitDialogState.unitForm.deviceCode" placeholder="设备编号" clearable class="input-length"></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="设备名称" prop="deviceName">
+ <el-input v-model="unitDialogState.unitForm.deviceName" placeholder="设备名称" clearable class="input-length"></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="设备功率" prop="devicePower">
+ <el-input v-model="unitDialogState.unitForm.devicePower" placeholder="设备功率" clearable class="input-length"></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="计量单位" prop="deviceUnit">
+ <el-select v-model="unitDialogState.unitForm.deviceUnit" placeholder="计量单位" clearable class="input-length">
+ <el-option v-for="item in unitDialogState.deviceUnitList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="是否特种设备">
+ <el-select v-model="unitDialogState.unitForm.specialDevice" placeholder="是否特种设备" clearable class="input-length">
+ <el-option v-for="item in unitDialogState.specialDeviceList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="安全防护">
+ <el-input type="textarea" :rows="3" v-model="unitDialogState.unitForm.safeProtect" placeholder="安全防护" clearable class="input-length"></el-input>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <template #footer>
+ <span class="dialog-footer">
+ <el-button @click="unitDialogState.unitDialogVisible = !unitDialogState.unitDialogVisible" size="default">取 消</el-button>
+ <el-button type="primary" @click="onSubmitUnit" size="default">确定</el-button>
+ </span>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup lang="ts">
+import { reactive, ref } from "vue";
+import {ElMessage} from "element-plus";
+import {unitApi} from "/@/api/basic/unit";
+
+const UnitFormRef = ref()
+
+const unitDialogState = reactive<UnitDialogType>({
+ title: '',
+ unitDialogVisible: false,
+ unitForm: {
+ id: null,
+ deviceCode: '',
+ deviceName: '',
+ devicePower: '',
+ deviceUnit: null,
+ safeProtect: '',
+ },
+ unitFormRules: {
+ deviceCode: [{ required: true, message: '请填写设备编号', trigger: 'blur' }],
+ deviceName: [{ required: true, message: '请填写设备名称', trigger: 'blur' }],
+ devicePower: [{ required: true, message: '请填写设备功率', trigger: 'blur' }],
+ deviceUnit: [{ required: true, message: '请选择计量单位', trigger: 'change' }]
+ },
+ riskSourceTypeList: [
+ {id: 1, name: '区域、实验场所'},
+ {id:2, name: '设施设备'},
+ {id:3, name: '固定工艺节点'},
+ ],
+ evaluateStatusList: [
+ {id: 1, name: '未评价'},
+ {id:2, name: '已评价'},
+ ]
+})
+
+const showUnitDialog = (title: string, value: UnitType) => {
+ unitDialogState.unitDialogVisible = true;
+ setTimeout(() => {
+ UnitFormRef.value.clearValidate();
+ });
+ if(title === '新增'){
+ unitDialogState.title = '新增';
+ unitDialogState.unitForm = {
+ id: null,
+ deviceCode: '',
+ deviceName: '',
+ devicePower: '',
+ deviceUnit: null,
+ safeProtect: '',
+ };
+ }else{
+ unitDialogState.title = '编辑'
+ unitDialogState.unitForm = {
+ id: value.id,
+ deviceCode: value.deviceCode,
+ deviceName: value.deviceName,
+ devicePower: value.devicePower,
+ deviceUnit: value.deviceUnit,
+ safeProtect: value.safeProtect,
+ };
+ }
+};
+
+const onSubmitUnit = () => {
+ UnitFormRef.value.validate(async(valid: boolean) => {
+ if(valid){
+ if(unitDialogState.title === '新增'){
+ let res = await unitApi().addUnit(unitDialogState.unitForm);
+ if(res.data.code === 100){
+ emit('refresh')
+ unitDialogState.unitDialogVisible = false;
+ ElMessage({
+ type: 'success',
+ message: '新增成功'
+ })
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg,
+ });
+ }
+ }else{
+ let res = await unitApi().modUnit(unitDialogState.unitForm)
+ if(res.data.code === 100){
+ emit('refresh')
+ unitDialogState.unitDialogVisible = false;
+ ElMessage({
+ type: 'success',
+ message: '编辑成功'
+ })
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg,
+ });
+ }
+ }
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: '请完善基本信息',
+ });
+ }
+ })
+}
+
+const emit = defineEmits(['refresh'])
+
+defineExpose({
+ showUnitDialog
+})
+</script>
+
+<style scoped>
+
+</style>
diff --git a/src/views/basic/unit/index.ts b/src/views/basic/unit/index.ts
new file mode 100644
index 0000000..ae9436d
--- /dev/null
+++ b/src/views/basic/unit/index.ts
@@ -0,0 +1,45 @@
+declare interface UnitStateType {
+ unitData: Array<UnitType>
+ searchQuery: {
+ pageIndex: number,
+ pageSize: number,
+ riskCode: string,
+ riskName: string,
+ riskSourceType: number | null,
+ }
+ total: number
+ riskSourceTypeList: Array<Type>,
+ evaluateStatusList: Array<Type>,
+}
+
+declare interface UnitType {
+ id: number | null,
+ deviceCode: string,
+ deviceName: string,
+ devicePower: string,
+ deviceUnit: number | null,
+ safeProtect: string,
+}
+
+declare interface Type {
+ id: number,
+ name: string,
+}
+
+declare interface UnitDialogType {
+ title: string,
+ unitDialogVisible: boolean,
+ unitForm: {
+ id: number | null,
+ deviceCode: string,
+ deviceName: string,
+ devicePower: string,
+ deviceUnit: number | null,
+ safeProtect: string,
+ },
+ unitFormRules: {
+
+ },
+ riskSourceTypeList: Array<Type>,
+ evaluateStatusList: Array<Type>,
+}
diff --git a/src/views/basic/unit/index.vue b/src/views/basic/unit/index.vue
new file mode 100644
index 0000000..c7788af
--- /dev/null
+++ b/src/views/basic/unit/index.vue
@@ -0,0 +1,313 @@
+<template>
+ <div class="home-container">
+ <div style="height: 100%">
+ <el-row class="homeCard">
+ <div class="basic-line">
+ <span>风险单元编号:</span>
+ <el-input v-model="unitState.searchQuery.riskCode" clearable filterable class="input-box" placeholder="风险单元编号">
+ </el-input>
+ </div>
+ <div class="basic-line">
+ <span>风险单元名称:</span>
+ <el-input v-model="unitState.searchQuery.riskName" clearable filterable class="input-box" placeholder="风险单元名称">
+ </el-input>
+ </div>
+ <div class="basic-line">
+ <span>风险源风险类型:</span>
+ <el-select v-model="unitState.searchQuery.riskSourceType" clearable filterable class="input-box" placeholder="风险源风险类型">
+ <el-option v-for="item in unitState.riskSourceTypeList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+ </el-select>
+ </div>
+ <div style="padding-bottom: 10px">
+ <el-button type="primary" @click="getUnitData">查询</el-button>
+ <el-button plain @click="reset">重置</el-button>
+ </div>
+ </el-row>
+ <div class="homeCard">
+ <div class="main-card">
+ <el-row class="cardTop">
+ <el-col :span="12" class="mainCardBtn">
+ <el-button type="primary" :icon="Plus" size="default" @click="openunitDialog('新增', {})">新增</el-button>
+ <!-- <el-button type="danger" :icon="Delete" size="default" plain>删除</el-button>-->
+ </el-col>
+<!-- <el-button type="primary" :icon="Refresh" size="default" />-->
+ </el-row>
+ <el-table ref="multipleTableRef" :data="unitState.unitData" style="width: 100%" height="calc(100% - 100px)" :header-cell-style="{ background: '#fafafa' }">
+ <el-table-column prop="riskCode" label="风险单元编号" show-overflow-tooltip/>
+ <el-table-column prop="riskName" label="风险单元名称" show-overflow-tooltip/>
+ <el-table-column prop="riskSourceType" label="风险源风险类型" show-overflow-tooltip>
+ <template #default="scope">
+ <span>{{`${unitState.riskSourceTypeList.find(item =>item.id === scope.row.riskSourceType)?.name || ''}`}}</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="evaluateStatus" label="评价状态" show-overflow-tooltip>
+ <template #default="scope">
+ <span>{{`${unitState.evaluateStatusList.find(item =>item.id === scope.row.evaluateStatus)?.name || ''}`}}</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="liabilityUserName" label="责任人" show-overflow-tooltip/>
+ <el-table-column prop="liabilityDep" label="责任部门" show-overflow-tooltip/>
+ <el-table-column prop="createTime" label="创建时间" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="createByUserName" label="创建人" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="updateTime" label="最后修改时间" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="updateByUserName" label="最后修改人" show-overflow-tooltip></el-table-column>
+ <el-table-column label="操作" width="150">
+ <template #default="scope">
+ <el-button size="small" text type="primary" :icon="Edit" @click="openUnitDialog('修改', scope.row)">修改</el-button>
+ <el-button size="small" text type="danger" :icon="Delete" @click="onDelUnit(scope.row)">删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ <div class="pageBtn">
+ <el-pagination @size-change="onHandleSizeChange" @current-change="onHandleCurrentChange" :pager-count="5" :page-sizes="[10, 20, 30]" v-model:current-page="unitState.searchQuery.pageIndex" background v-model:page-size="unitState.searchQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="unitState.total" class="page-position"> </el-pagination>
+ </div>
+ </div>
+ </div>
+ </div>
+ <unit-dialog ref="unitDialogRef" @refresh="getUnitData"></unit-dialog>
+ </div>
+</template>
+
+<script setup lang="ts">
+import {defineAsyncComponent, onMounted, reactive, ref} from "vue";
+import {unitApi} from "/@/api/basic/unit";
+import {ElMessage, ElMessageBox} from "element-plus";
+import { Edit, View, Plus, Delete } from '@element-plus/icons-vue';
+
+const UnitDialog = defineAsyncComponent(() => import('./components/unitDialog.vue'));
+
+const unitDialogRef = ref();
+
+const unitState = reactive<UnitStateType>({
+ unitData: [],
+ searchQuery: {
+ pageIndex: 1,
+ pageSize: 10,
+ riskCode: '',
+ riskName: '',
+ riskSourceType: null,
+ },
+ total: 0,
+ riskSourceTypeList: [
+ {id: 1, name: '区域、实验场所'},
+ {id:2, name: '设施设备'},
+ {id:3, name: '固定工艺节点'},
+ ],
+ evaluateStatusList: [
+ {id: 1, name: '未评价'},
+ {id:2, name: '已评价'},
+ ]
+})
+
+const getUnitData = async () => {
+ let res = await unitApi().getUnitByList(unitState.searchQuery);
+ if(res.data.code === 100){
+ unitState.unitData = res.data.data;
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ });
+ }
+};
+
+const openUnitDialog = (title: string, value: UnitType) => {
+ unitDialogRef.value.showUnitDialog(title, value);
+};
+
+const onDelUnit = (val: UnitType) => {
+ ElMessageBox.confirm(`此操作将永久删除该设备:“${val.deviceName}”,是否继续?`, '提示', {
+ confirmButtonText: '确认',
+ cancelButtonText: '取消',
+ type: 'warning'
+ })
+ .then(async () => {
+ let res = await unitApi().deleteUnitById({ id: val.id });
+ if (res.data.code === 100) {
+ ElMessage({
+ type: 'success',
+ duration: 2000,
+ message: '删除成功'
+ });
+ await getUnitData();
+ } else {
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ });
+ }
+ })
+ .catch((error) => {
+ });
+}
+
+const onHandleSizeChange = (val: number) => {
+ unitState.searchQuery.pageSize = val;
+ getUnitData();
+};
+
+const onHandleCurrentChange = (val: number) => {
+ unitState.searchQuery.pageIndex = val;
+ getUnitData();
+};
+
+const reset = () => {
+ unitState.searchQuery = {
+ pageIndex: 1,
+ pageSize: 10,
+ riskCode: '',
+ riskName: '',
+ riskSourceType: null,
+ }
+};
+
+onMounted(() => {
+ getUnitData()
+})
+
+</script>
+
+<style scoped lang="scss">
+$homeNavLengh: 8;
+.home-container {
+ height: calc(100vh - 144px);
+ box-sizing: border-box;
+ overflow: hidden;
+ .homeCard {
+ width: 100%;
+ padding: 20px;
+ box-sizing: border-box;
+ background: #fff;
+ border-radius: 4px;
+
+ .main-card {
+ width: 100%;
+ height: 100%;
+ .cardTop {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 20px;
+ .mainCardBtn {
+ margin: 0;
+ }
+ }
+ .pageBtn {
+ height: 60px;
+ display: flex;
+ align-items: center;
+ justify-content: right;
+
+ .demo-pagination-block + .demo-pagination-block {
+ margin-top: 10px;
+ }
+ .demo-pagination-block .demonstration {
+ margin-bottom: 16px;
+ }
+ }
+ }
+ &:last-of-type {
+ height: calc(100% - 100px);
+ }
+ }
+ .el-row {
+ display: flex;
+ align-items: center;
+ margin-bottom: 20px;
+ &:last-child {
+ margin-bottom: 0;
+ }
+ .grid-content {
+ align-items: center;
+ min-height: 36px;
+ }
+
+ .topInfo {
+ display: flex;
+ align-items: center;
+ font-size: 16px;
+ font-weight: bold;
+
+ & > div {
+ white-space: nowrap;
+ margin-right: 20px;
+ }
+ }
+ }
+}
+.stepItem {
+ width: 100%;
+ display: flex;
+ align-items: flex-start;
+ margin-bottom: 30px;
+ margin-left: 30px;
+ padding-bottom: 30px;
+ border-left: 2px solid #ccc;
+ &:first-of-type {
+ margin-top: 30px;
+ }
+ &:last-of-type {
+ margin-bottom: 0;
+ border-left: none;
+ }
+ .stepNum {
+ width: 30px;
+ height: 30px;
+ border-radius: 15px;
+ box-sizing: border-box;
+ color: #333;
+ border: 1px solid #999;
+ line-height: 28px;
+ text-align: center;
+ margin-right: 10px;
+ margin-left: -16px;
+ margin-top: -30px;
+ }
+ .stepCard {
+ width: 100%;
+ margin-top: -30px;
+
+ .box-card {
+ width: 100%;
+ &:deep(.el-card__header) {
+ padding: 10px 15px;
+ }
+ .card-header {
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ & > div:first-of-type {
+ margin-right: 80px;
+ font-size: 18px;
+ font-weight: bold;
+ }
+ }
+ }
+ }
+ &:hover .card-header {
+ color: #0098f5;
+ }
+ &:hover .stepNum {
+ border: 2px solid #0098f5;
+ color: #0098f5;
+ }
+}
+
+:deep(.el-date-editor) {
+ width: 100%;
+}
+.el-select {
+ width: 100%;
+}
+:deep(.el-textarea.is-disabled .el-textarea__inner) {
+ background-color: var(--el-card-bg-color);
+ color: var(--el-input-text-color, var(--el-text-color-regular));
+}
+:deep(.el-input.is-disabled .el-input__inner) {
+ color: var(--el-input-text-color, var(--el-text-color-regular));
+}
+:deep(.el-input.is-disabled .el-input__wrapper) {
+ background-color: var(--el-card-bg-color);
+}
+</style>
diff --git a/src/views/experiment/developing/components/applyDialog.vue b/src/views/experiment/developing/components/applyDialog.vue
new file mode 100644
index 0000000..b65f862
--- /dev/null
+++ b/src/views/experiment/developing/components/applyDialog.vue
@@ -0,0 +1,98 @@
+<template>
+ <div class="system-menu-dialog-container">
+ <el-dialog :title="applyStartDialogState.title" v-model="applyStartDialogState.applyStartDialogVisible" width="600px">
+ <el-form ref="applyStartFormRef" :rules="applyStartDialogState.applyStartFormRules" :model="applyStartDialogState.applyStartForm" size="default" label-width="160px">
+ <el-row :gutter="35">
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="实验开始时间" prop="startTime">
+ <el-date-picker type="datetime" format="YYYY/MM/DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" v-model="applyStartDialogState.applyStartForm.startTime" class="input-length"/>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="是否是安全信息化系统 " prop="sisStatus">
+ <el-radio-group v-model="applyStartDialogState.applyStartForm.sisStatus">
+ <el-radio :label="1">是</el-radio>
+ <el-radio :label="2">否</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="安全信息化系统" prop="safeInformationSystem">
+ <el-input v-model="applyStartDialogState.applyStartForm.safeInformationSystem" placeholder="材料类型" class="input-length">
+ </el-input>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <template #footer>
+ <span class="dialog-footer">
+ <el-button @click="applyStartDialogState.applyStartDialogVisible = !applyStartDialogState.applyStartDialogVisible" size="default">取 消</el-button>
+ <el-button type="primary" @click="onSubmitApplyStart" size="default">确定</el-button>
+ </span>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup lang="ts">
+import { reactive, ref } from "vue";
+import {ElMessage} from "element-plus";
+import {projectApi} from "/@/api/experiment/project";
+
+const applyStartFormRef = ref()
+
+const applyStartDialogState = reactive<ApplyStartDialogType>({
+ title: '',
+ applyStartDialogVisible: false,
+ applyStartForm: {
+ id: null,
+ sisStatus: null,
+ safeInformationSystem: '',
+ startTime: '',
+ },
+ applyStartFormRules: {
+
+ },
+})
+
+const showApplyStartDialog = (value: ProjectType) => {
+ applyStartDialogState.applyStartDialogVisible = true;
+ applyStartDialogState.applyStartForm.id = <number>value.id
+};
+
+const onSubmitApplyStart = () => {
+ applyStartFormRef.value.validate(async(valid: boolean) => {
+ if(valid){
+ let res = await projectApi().applyProject([applyStartDialogState.applyStartForm]);
+ if(res.data.code === 100){
+ emit('refresh')
+ applyStartDialogState.applyStartDialogVisible = false;
+ ElMessage({
+ type: 'success',
+ message: '申请开展成功'
+ })
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg,
+ });
+ }
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: '请完善基本信息',
+ });
+ }
+ })
+};
+
+const emit = defineEmits(['refresh'])
+
+defineExpose({
+ showApplyStartDialog
+})
+</script>
+
+<style scoped>
+
+</style>
diff --git a/src/views/experiment/developing/components/applyStart.vue b/src/views/experiment/developing/components/applyStart.vue
new file mode 100644
index 0000000..8906f6e
--- /dev/null
+++ b/src/views/experiment/developing/components/applyStart.vue
@@ -0,0 +1,101 @@
+<template>
+ <div class="system-menu-dialog-container">
+ <el-dialog :title="applyStartDialogState.title" v-model="applyStartDialogState.applyStartDialogVisible" width="600px">
+ <el-form ref="applyStartFormRef" :rules="applyStartDialogState.applyStartFormRules" :model="applyStartDialogState.applyStartForm" size="default" label-width="120px">
+ <el-row :gutter="35">
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="实验材料" prop="stuffName">
+ <el-date-picker type="datetime" format="YYYY/MM/DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" v-model="applyStartDialogState.applyStartForm.startTime" class="input-length"/>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="编号" prop="sisStatus">
+ <el-radio-group v-model="applyStartDialogState.applyStartForm.sisStatus">
+ <el-radio :label="1">是</el-radio>
+ <el-radio :label="2">否</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="材料类型" prop="stuffType">
+ <el-select v-model="applyStartDialogState.applyStartForm.safeInformationSystem" placeholder="材料类型" class="input-length">
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <template #footer>
+ <span class="dialog-footer">
+ <el-button @click="applyStartDialogState.applyStartDialogVisible = !applyStartDialogState.applyStartDialogVisible" size="default">取 消</el-button>
+ <el-button type="primary" @click="onSubmitApplyStart" size="default">确定</el-button>
+ </span>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup lang="ts">
+import { reactive, ref } from "vue";
+import {ElMessage} from "element-plus";
+import {projectApi} from "/@/api/experiment/project";
+
+const applyStartFormRef = ref()
+
+const applyStartDialogState = reactive<ApplyStartDialogType>({
+ title: '',
+ applyStartDialogVisible: false,
+ applyStartForm: {
+ id: null,
+ sisStatus: null,
+ safeInformationSystem: '',
+ startTime: '',
+ },
+ applyStartFormRules: {
+ stuffCode: [{ required: true, message: '请填写实验材料', trigger: 'blur' }],
+ stuffName: [{ required: true, message: '请填写编号', trigger: 'blur' }],
+ stuffStorage: [{ required: true, message: '请选择材料类型', trigger: 'change' }],
+ stuffType: [{ required: true, message: '请选择材料储存', trigger: 'change' }],
+ stuffUnit: [{ required: true, message: '请选择计量单位', trigger: 'change' }]
+ },
+})
+
+const showApplyStartDialog = (value: ProjectType) => {
+ applyStartDialogState.applyStartDialogVisible = true;
+};
+
+const onSubmitApplyStart = () => {
+ applyStartFormRef.value.validate(async(valid: boolean) => {
+ if(valid){
+ let res = await projectApi().applyProject(applyStartDialogState.applyStartForm);
+ if(res.data.code === 100){
+ emit('refresh')
+ applyStartDialogState.applyStartDialogVisible = false;
+ ElMessage({
+ type: 'success',
+ message: '申请开展成功'
+ })
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg,
+ });
+ }
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: '请完善基本信息',
+ });
+ }
+ })
+};
+
+const emit = defineEmits(['refresh'])
+
+defineExpose({
+ showApplyStartDialog
+})
+</script>
+
+<style scoped>
+
+</style>
diff --git a/src/views/experiment/developing/components/projectDialog.vue b/src/views/experiment/developing/components/projectDialog.vue
new file mode 100644
index 0000000..b621833
--- /dev/null
+++ b/src/views/experiment/developing/components/projectDialog.vue
@@ -0,0 +1,533 @@
+<template>
+ <div class="system-menu-dialog-container">
+ <el-dialog :title="projectDialogState.title" v-model="projectDialogState.projectDialogVisible" width="70%">
+ <el-form ref="ProjectFormRef" :rules="projectDialogState.projectFormRules" :model="projectDialogState.projectForm" size="default" label-width="0">
+ <table class="report-table">
+ <th class="m-color b-font" style="text-align: center">***研究所/***大学<br />科学研究实验项目安全风险基础信息录入表(已开展B)</th>
+ <tr>
+ <td class="w-25 m-color">实验名称</td>
+ <td class="w-75 m-color">
+ <el-form-item prop="experimentName">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.experimentName" placeholder="请输入实验名称" />
+ </el-form-item>
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">实验类型</td>
+ <td class="w-75 m-color">
+
+ <el-radio-group style="text-align: center" :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.experimentType">
+ <el-radio :label="1">化学类</el-radio>
+ <el-radio :label="2">生物类</el-radio>
+ <el-radio :label="3">辐射类</el-radio>
+ <el-radio :label="4">机电类</el-radio>
+ <el-radio :label="5">特种设备类</el-radio>
+ <el-radio :label="6">其他类</el-radio>
+ </el-radio-group>
+
+
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">部门</td>
+ <td class="w-25 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.dep" />
+ </td>
+ <td class="w-25 m-color">负责人</td>
+ <td class="w-16 m-color">
+ <el-select :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.liabilityUserId" clearable filterable>
+ <el-option
+ v-for="item in projectDialogState.allPersonList"
+ :key="item.id"
+ :value="item.id"
+ :label="item.personName"
+ ></el-option>
+ </el-select>
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">立项时间</td>
+ <td class="w-25 m-color">
+ <el-date-picker :disabled="projectDialogState.disabled" type="datetime" format="YYYY/MM/DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" v-model="projectDialogState.projectForm.expectStartTime" />
+ </td>
+<!-- <td class="w-16 m-color">开展时间</td>-->
+<!-- <td class="w-16 m-color">-->
+<!-- <el-date-picker v-model="projectDialogState.projectForm.startTime" />-->
+<!-- </td>-->
+ <td class="w-25 m-color">安全负责人</td>
+ <td class="w-16 m-color">
+ <el-select :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.safeLiabilityUserId" clearable filterable>
+ <el-option
+ v-for="item in projectDialogState.allPersonList"
+ :key="item.id"
+ :value="item.id"
+ :label="item.personName"
+ ></el-option>
+ </el-select>
+ </td>
+ </tr>
+ <tr class="m-color b-font" style="text-align: center">实验场所</tr>
+<!-- <tr>-->
+<!-- <td class="w-25 m-color">楼宇</td>-->
+<!-- <td class="w-75 m-color">-->
+<!-- <el-input v-model="projectDialogState.projectForm.building" placeholder="请输入楼栋名称" />-->
+<!-- </td>-->
+<!-- </tr>-->
+ <tr>
+ <td class="w-25 m-color">房间号</td>
+<!-- <td class="w-75 m-color">-->
+ <td class="w-16 m-color">
+ <el-select :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.siteId" placeholder="请输入房间号" >
+ <el-option
+ v-for="item in projectDialogState.allRoomList"
+ :key="item.id"
+ :value="item.id"
+ :label="item.room"
+ ></el-option>
+ </el-select>
+ </td>
+ </tr>
+ <select-material ref="selectMaterialRef" v-model:disabled="projectDialogState.disabled" v-model:data="projectDialogState.projectForm.stuffList"></select-material>
+ <select-equipment ref="selectEquipmentRef" v-model:disabled="projectDialogState.disabled" v-model:data="projectDialogState.projectForm.deviceList"></select-equipment>
+ <tr>
+ <td class="w-25 m-color">实验步骤</td>
+ <td class="w-75 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.experimentStep" placeholder="请输入实验步骤" />
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">操作方法</td>
+ <td class="w-75 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.experimentMethod" placeholder="请输入操作方法" />
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">工艺过程</td>
+ <td class="w-75 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.process" placeholder="请输入工艺过程" />
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">特殊/关键过程</td>
+ <td class="w-75 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.keyProcess" placeholder="请输入特殊/关键过程" />
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">是否存在过夜、老化实验</td>
+ <td class="w-25 m-color">
+ <el-radio-group :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.timeout">
+ <el-radio :label="1">存在</el-radio>
+ <el-radio :label="2">不存在</el-radio>
+ </el-radio-group>
+ </td>
+ <td class="w-25 m-color">过夜、老化保障措施</td>
+ <td class="w-25 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.timeoutManager" />
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">是否在封闭条件下</td>
+ <td class="w-25 m-color">
+ <el-radio-group :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.closed">
+ <el-radio :label="1">存在</el-radio>
+ <el-radio :label="2">不存在</el-radio>
+ </el-radio-group>
+ </td>
+ <td class="w-25 m-color">封闭条件保障措施</td>
+ <td class="w-25 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.unclosedManager" />
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">实验场所防爆措施条件和设施情况</td>
+ <td class="w-75 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.explosionProof" placeholder="请输入" />
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">实验场所防火措施条件和设施情况</td>
+ <td class="w-75 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.fireProof" placeholder="请输入" />
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">实验场所防中毒措施条件和设施情况</td>
+ <td class="w-75 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.poisonProof" placeholder="请输入" />
+ </td>
+ </tr>
+
+
+ <select-danger ref="selectDangerRef" v-model:data="projectDialogState.projectForm.hazardousWasteList" v-model:disabled="projectDialogState.disabled"></select-danger>
+ <select-person ref="selectPersonRef" v-model:data="projectDialogState.projectForm.persons" v-model:disabled="projectDialogState.disabled"></select-person>
+
+
+<!-- <tr>-->
+<!-- <td class="w-25 m-color">安全信息化系统使用情况</td>-->
+<!-- <td class="w-25 m-color">-->
+<!-- <el-radio-group v-model="projectDialogState.projectForm.useIT">-->
+<!-- <el-radio value="1">是</el-radio>-->
+<!-- <el-radio value="2">否</el-radio>-->
+<!-- </el-radio-group>-->
+<!-- </td>-->
+<!-- <td class="w-25 m-color">系统名称</td>-->
+<!-- <td class="w-25 m-color">-->
+<!-- <el-input v-model="projectDialogState.projectForm.systemName" placeholder="请输入" />-->
+<!-- </td>-->
+<!-- </tr>-->
+ <tr>
+ <td class="w-25 m-color">安全管理制度</td>
+ <td class="w-75 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.safeManagerMethod" placeholder="请输入" />
+ </td>
+ </tr>
+ <tr class="m-color b-font" style="text-align: center">应急预案/应急演练</tr>
+ <tr>
+ <td class="w-25 m-color">有无预案</td>
+ <td class="w-25 m-color">
+ 预案名称
+ </td>
+ <td class="w-25 m-color">是否演练</td>
+ <td class="w-25 m-color">
+ 演练情况
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.emergencyPlan" />
+ </td>
+ <td class="w-25 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.emergencyPlanName" />
+ </td>
+ <td class="w-25 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.emergencyDrillStatus" />
+ </td>
+ <td class="w-25 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.emergencyDrill" />
+ </td>
+ </tr>
+ <tr class="m-color b-font" style=" text-align: center">实验人员</tr>
+ <tr>
+ <td class="w-25 m-color">实验场所是否需要分区隔断</td>
+ <td class="w-75 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.partitionCondition" placeholder="请输入" />
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">其它基础信息(详细描述)</td>
+ <td class="w-75 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.note" placeholder="请输入" />
+ </td>
+ </tr>
+ </table>
+ </el-form>
+ <template #footer>
+ <span class="dialog-footer" style="padding-top:10px;text-align: center !important;">
+ <el-button @click="projectDialogState.projectDialogVisible = !projectDialogState.projectDialogVisible" size="default">取 消</el-button>
+ <el-button type="primary" v-if="!projectDialogState.disabled" @click="onSubmitProject" size="default">确定</el-button>
+ </span>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup lang="ts">
+import {defineAsyncComponent, nextTick, onMounted, reactive, ref} from "vue";
+import {ElMessage} from "element-plus";
+import {projectApi} from "/@/api/experiment/project";
+import {personApi} from "/@/api/basic/person";
+
+const SelectEquipment = defineAsyncComponent(() => import('./selectEquipment.vue'))
+const SelectMaterial = defineAsyncComponent(() => import('./selectMaterial.vue'))
+const SelectDanger = defineAsyncComponent(() => import('./selectDanger.vue'))
+const SelectPerson = defineAsyncComponent(() => import('./selectPerson.vue'))
+const ProjectFormRef = ref()
+const selectPersonRef = ref()
+const selectEquipmentRef = ref()
+const selectMaterialRef = ref()
+const selectDangerRef = ref()
+
+const projectDialogState = reactive<ProjectDialogType>({
+ title: '',
+ disabled: false,
+ projectDialogVisible: false,
+ projectForm: {
+ id: null,
+ experimentName: "",
+ experimentType: null,
+ liabilityUserId: null,
+ safeLiabilityUserId: null,
+ dep: "",
+ siteId: null,
+ experimentStep: "",
+ experimentMethod: "",
+ process: "",
+ keyProcess: "",
+ timeout: null,
+ timeoutManager: "",
+ closed: null,
+ unclosedManager: "",
+ explosionProof: "",
+ fireProof: "",
+ poisonProof: "",
+ hazardousWaste: null,
+ safeManagerMethod: "",
+ emergencyPlan: "",
+ emergencyDrill: "",
+ emergencyPlanName: "",
+ emergencyDrillStatus: "",
+ partitionCondition: "",
+ note: "",
+ expectStartTime: null,
+ persons: [
+ ],
+ deviceList: [
+ ],
+ stuffList: [
+ ],
+ hazardousWasteList: [
+ ]
+ },
+ projectFormRules: {
+ experimentName: [{ required: true, message: '请填写设备编号', trigger: 'blur' }],
+ deviceName: [{ required: true, message: '请填写设备名称', trigger: 'blur' }],
+ devicePower: [{ required: true, message: '请填写设备功率', trigger: 'blur' }],
+ deviceUnit: [{ required: true, message: '请选择计量单位', trigger: 'change' }]
+ },
+ allPersonList: [],
+ allRoomList: [],
+})
+
+const showProjectDialog = (title: string, value: ProjectType, allRoomList: RoomType []) => {
+ projectDialogState.projectDialogVisible = true;
+ projectDialogState.allRoomList = allRoomList
+ setTimeout(() => {
+ ProjectFormRef.value.clearValidate();
+ });
+ if(title === '新增'){
+ projectDialogState.disabled = false
+ projectDialogState.title = '新增';
+ projectDialogState.projectForm = {
+ id: null,
+ experimentName: "",
+ experimentType: null,
+ liabilityUserId: null,
+ safeLiabilityUserId: null,
+ dep: "",
+ siteId: null,
+ experimentStep: "",
+ experimentMethod: "",
+ process: "",
+ keyProcess: "",
+ timeout: null,
+ timeoutManager: "",
+ closed: null,
+ unclosedManager: "",
+ explosionProof: "",
+ fireProof: "",
+ poisonProof: "",
+ hazardousWaste: 1,
+ safeManagerMethod: "",
+ emergencyPlan: "",
+ emergencyDrill: "",
+ emergencyPlanName: "",
+ emergencyDrillStatus: "",
+ partitionCondition: "",
+ note: "",
+ expectStartTime: null,
+ persons: [
+ ],
+ deviceList: [
+ ],
+ stuffList: [
+ ],
+ hazardousWasteList: [
+ ]
+ };
+ }else{
+ projectDialogState.title = '查看';
+ projectDialogState.disabled = true
+ for(let i in projectDialogState.projectForm) {
+ if(isValidKey(i, projectDialogState.projectForm)) {
+ projectDialogState.projectForm[i] = value[i];
+ }
+ }
+ }
+};
+
+const isValidKey = (key: string | number | symbol, object:object): key is keyof typeof object =>{
+ return key in object;
+};
+
+const onSubmitProject = () => {
+ ProjectFormRef.value.validate(async(valid: boolean) => {
+ if(valid){
+ if(projectDialogState.title === '新增'){
+ projectDialogState.projectForm.persons = selectPersonRef.value.dataList
+ projectDialogState.projectForm.hazardousWasteList = selectDangerRef.value.dataList
+ projectDialogState.projectForm.stuffList = selectMaterialRef.value.dataList
+ projectDialogState.projectForm.deviceList = selectEquipmentRef.value.dataList
+ let res = await projectApi().addProject(projectDialogState.projectForm);
+ if(res.data.code === 100){
+ emit('refresh')
+ projectDialogState.projectDialogVisible = false;
+ ElMessage({
+ type: 'success',
+ message: '新增成功'
+ })
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg,
+ });
+ }
+ }else{
+ let res = await projectApi().modProject(projectDialogState.projectForm)
+ if(res.data.code === 100){
+ emit('refresh')
+ projectDialogState.projectDialogVisible = false;
+ ElMessage({
+ type: 'success',
+ message: '编辑成功'
+ })
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg,
+ });
+ }
+ }
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: '请完善基本信息',
+ });
+ }
+ })
+};
+
+const getAllPersonList = async () => {
+ let res = await personApi().getAllPerson();
+ if(res.data.code === 100){
+ projectDialogState.allPersonList = JSON.parse(JSON.stringify(res.data.data));
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ })
+ }
+};
+
+const emit = defineEmits(['refresh']);
+
+defineExpose({
+ showProjectDialog,
+});
+
+onMounted(() => {
+ getAllPersonList();
+});
+</script>
+
+<style scoped lang="scss">
+.site-layout-background {
+ background: #fff;
+}
+
+.report-table {
+ width: 100%;
+ border-collapse: collapse;
+ border: 1px solid #337ecc;
+ margin: 20px 0;
+
+th {
+ padding: 10px 0;
+ border: 1px solid #337ecc;
+ border-left: none;
+}
+
+tr {
+ width: 100%;
+ height: 44px;
+ line-height: 42px;
+ border-bottom: 1px solid #ccc;
+
+&:last-of-type {
+ border-bottom: none;
+ }
+
+td {
+ border-right: 1px solid #ccc;
+ display: inline-block;
+ height: 44px;
+ vertical-align: middle;
+ text-align: center;
+ line-height: 42px;
+
+&:last-of-type {
+ border-right: none;
+ }
+
+&.w-14 {
+ width: calc((100/7)/100 * 100%);
+ }
+
+&.w-16 {
+ width: calc((100/6)/100 * 100%);
+ }
+
+&.w-18 {
+ width: 16.59%;
+ }
+
+&.w-20 {
+ width: 20%;
+ }
+
+&.w-25 {
+ width: 25%;
+ }
+
+&.w-50 {
+ width: 50%;
+ }
+
+&.w-75 {
+ width: 75%;
+ }
+
+.ant-input {
+ height: 100%;
+ border: none;
+ background: #f5f7fa;
+}
+
+.ant-picker {
+ width: 100%;
+ height: 100%;
+}
+}
+}
+
+.b-font {
+ font-size: 16px;
+ font-weight: bolder;
+}
+}
+
+.m-color {
+ color: #0c4995;
+}
+:deep(.el-input__wrapper ){
+ box-shadow: none;
+ margin-top: 6px;
+}
+:deep(.el-dialog__footer){
+ padding-top: 20px;
+ display: flex;
+ justify-content: center;
+}
+
+
+</style>
diff --git a/src/views/experiment/developing/components/selectDanger.vue b/src/views/experiment/developing/components/selectDanger.vue
new file mode 100644
index 0000000..8ef010c
--- /dev/null
+++ b/src/views/experiment/developing/components/selectDanger.vue
@@ -0,0 +1,184 @@
+<template>
+ <tr class="m-color b-font" style="text-align: center">危废情况</tr>
+ <tr>
+ <td class="w-20 m-color">序号</td>
+ <td class="w-20 m-color">废弃物分类</td>
+ <td class="w-20 m-color">存储方式</td>
+ <td class="w-20 m-color">预估处理量</td>
+ <td class="w-20 m-color">操作</td>
+ </tr>
+ <tr v-for="(item,index) in selectDangerState.wasteList" :key="index">
+ <td class="w-20">
+ {{ index + 1 }}
+ </td>
+ <td class="w-20">
+ <el-select :disabled="selectDangerState.disabled" v-model="item.classify" clearable filterable>
+ <el-option v-for="item in selectDangerState.classifyList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+ </el-select>
+ </td>
+ <td class="w-20">
+ <el-select :disabled="selectDangerState.disabled" v-model="item.wasteStorage" clearable filterable>
+ <el-option v-for="item in selectDangerState.wasteStorageList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+ </el-select>
+ </td>
+ <td class="w-20">
+ <el-input type="number" v-model="item.handAmount"></el-input>
+ </td>
+ <td class="w-20">
+ <el-button :disabled="selectDangerState.disabled" type="danger" @click="deleteDangerItem(index)">删除</el-button>
+ </td>
+ </tr>
+ <tr style="text-align: center">
+ <el-button :disabled="selectDangerState.disabled" type="primary" shape="round" @click="addDangerItem()">
+ 添加行
+ </el-button>
+ </tr>
+</template>
+
+<script setup lang="ts">
+import {reactive, watchEffect} from "vue";
+
+let props = defineProps({
+ disabled: Boolean,
+ data: Array<WasteType>
+});
+
+const selectDangerState = reactive<SelectDangerType>({
+ disabled: false,
+ wasteList: [
+ ],
+ classifyList:[
+ {id:1, name: '有机'},
+ {id:2, name: '酸'},
+ {id:3, name: '碱性'},
+ {id:4, name: '固体废弃物'},
+ {id:5, name: '医疗废弃物'},
+ {id:6, name: '过期化学品'},
+ {id:7, name: '其他'}
+ ],
+ wasteStorageList: [
+ {id:1, name: '吨袋'},
+ {id:2, name: '吨桶'},
+ {id:3, name: '小桶'},
+ {id:4, name: '托盘'},
+ {id:5, name: '其他'},
+ ]
+})
+
+watchEffect(() => {
+ selectDangerState.wasteList = props.data as Array<WasteType>
+ selectDangerState.disabled = props.disabled
+});
+
+const addDangerItem = () => {
+ selectDangerState.wasteList.push({classify: null, wasteStorage: null, handAmount: null,});
+};
+
+const deleteDangerItem = (index: number) => {
+ selectDangerState.wasteList.splice(index,1);
+};
+
+const formatList = (formatList: Array<WasteType>) => {
+ selectDangerState.wasteList = formatList
+}
+
+defineExpose({
+ formatList,
+ dataList: selectDangerState.wasteList,
+});
+
+</script>
+
+<style scoped lang="scss">
+.site-layout-background {
+ background: #fff;
+}
+
+.report-table {
+ width: 100%;
+ border-collapse: collapse;
+ border: 1px solid #337ecc;
+ margin: 20px 0;
+
+ th {
+ padding: 10px 0;
+ border: 1px solid #337ecc;
+ border-left: none;
+ }
+
+ tr {
+ width: 100%;
+ height: 44px;
+ line-height: 42px;
+ border-bottom: 1px solid #ccc;
+
+ &:last-of-type {
+ border-bottom: none;
+ }
+
+ td {
+ border-right: 1px solid #ccc;
+ display: inline-block;
+ height: 44px;
+ vertical-align: middle;
+ text-align: center;
+ line-height: 42px;
+
+ &:last-of-type {
+ border-right: none;
+ }
+
+ &.w-14 {
+ width: calc((100/7)/100 * 100%);
+ }
+
+ &.w-16 {
+ width: calc((100/6)/100 * 100%);
+ }
+
+ &.w-18 {
+ width: 16.59%;
+ }
+
+ &.w-20 {
+ width: 20%;
+ }
+
+ &.w-25 {
+ width: 25%;
+ }
+
+ &.w-50 {
+ width: 50%;
+ }
+
+ &.w-75 {
+ width: 75%;
+ }
+
+ .ant-input {
+ height: 100%;
+ border: none;
+ background: #f5f7fa;
+ }
+
+ .ant-picker {
+ width: 100%;
+ height: 100%;
+ }
+ }
+ }
+
+ .b-font {
+ font-size: 16px;
+ font-weight: bolder;
+ }
+}
+
+.m-color {
+ color: #0c4995;
+}
+:deep(.el-input__wrapper ){
+ box-shadow: none;
+}
+</style>
diff --git a/src/views/experiment/developing/components/selectEquipment.vue b/src/views/experiment/developing/components/selectEquipment.vue
new file mode 100644
index 0000000..c86e11f
--- /dev/null
+++ b/src/views/experiment/developing/components/selectEquipment.vue
@@ -0,0 +1,208 @@
+<template>
+ <tr class="m-color b-font" style="text-align: center">实验所用的仪器/设备</tr>
+ <tr>
+ <td class="w-16 m-color">设备名称</td>
+ <td class="w-16 m-color">编号</td>
+ <td class="w-16 m-color">设备功率</td>
+ <td class="w-16 m-color">是否特种</td>
+ <td class="w-16 m-color">设备数量</td>
+ <td class="w-16 m-color">操作</td>
+ </tr>
+ <tr v-for="(item,index) in selectEquipmentState.equipmentList" :key="index">
+ <td class="w-16">
+ <el-select :disabled="selectEquipmentState.disabled" filterable v-model="item.deviceId" @change="giveOtherEquipmentValue($event, index)">
+ <el-option
+ v-for="item in selectEquipmentState.allEquipmentList"
+ :key="item.id"
+ :value="item.id"
+ :label="item.deviceName"
+ >
+ </el-option>
+ </el-select>
+ </td>
+ <td class="w-16">
+ <el-input :disabled="selectEquipmentState.disabled" v-model="item.deviceCode" placeholder="请输入数量" />
+ </td>
+ <td class="w-16">
+ <el-input :disabled="selectEquipmentState.disabled" v-model="item.devicePower" />
+ </td>
+ <td class="w-16">
+ <el-radio-group :disabled="selectEquipmentState.disabled" v-model="item.specialDevice">
+ <el-radio :label="1">是</el-radio>
+ <el-radio :label="2">否</el-radio>
+ </el-radio-group>
+ </td>
+ <td class="w-16">
+ <el-input type="number" v-model="item.deviceUseCount" />
+ </td>
+ <td class="w-16">
+ <el-button :disabled="selectEquipmentState.disabled" type="danger" @click="deleteEquipmentItem(index)">删除</el-button>
+ </td>
+ </tr>
+ <tr style="text-align: center">
+ <el-button :disabled="selectEquipmentState.disabled" type="primary" shape="round" @click="addEquipmentItem()">
+ 选择实验仪器
+ </el-button>
+ </tr>
+</template>
+
+<script setup lang="ts">
+import {onMounted, reactive, watchEffect} from "vue";
+import {ElMessage} from "element-plus";
+import { equipmentApi } from "/@/api/basic/equipement";
+
+let props = defineProps({
+ disabled: Boolean,
+ data: Array<AllEquipmentListType>
+});
+
+const selectEquipmentState = reactive<SelectEquipmentType>({
+ disabled: false,
+ equipmentList: [],
+ allEquipmentList: [],
+});
+
+watchEffect(() => {
+ selectEquipmentState.equipmentList = props.data as Array<AllEquipmentListType>
+ selectEquipmentState.disabled = props.disabled
+});
+
+const addEquipmentItem = () => {
+ selectEquipmentState.equipmentList.push({deviceId: null, deviceUseCount: null, deviceCode: '', deviceName: '', devicePower: '', specialDevice: '',});
+};
+
+const deleteEquipmentItem = (index: number) => {
+ selectEquipmentState.equipmentList.splice(index,1);
+};
+
+const getAllEquipmentList = async () => {
+ let res = await equipmentApi().getAllEquipment();
+ if(res.data.code === 100){
+ selectEquipmentState.allEquipmentList = JSON.parse(JSON.stringify(res.data.data));
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ })
+ }
+};
+
+const giveOtherEquipmentValue = (value: number, index:number) => {
+ const data = selectEquipmentState.allEquipmentList.find(item => item.id === value) as AllEquipmentListType
+ selectEquipmentState.equipmentList[index] = {
+ deviceId: data.id,
+ deviceUseCount: null,
+ deviceCode: data.deviceCode,
+ deviceName: data.deviceName,
+ devicePower: data.devicePower,
+ specialDevice: data.specialDevice
+ }
+};
+
+const formatList = (formatList: Array<AllEquipmentListType>) => {
+ selectEquipmentState.equipmentList = formatList
+}
+
+defineExpose({
+ dataList: selectEquipmentState.equipmentList,
+ formatList
+});
+
+onMounted(() => {
+ getAllEquipmentList();
+});
+</script>
+
+<style scoped lang="scss">
+.site-layout-background {
+ background: #fff;
+}
+
+.report-table {
+ width: 100%;
+ border-collapse: collapse;
+ border: 1px solid #337ecc;
+ margin: 20px 0;
+
+ th {
+ padding: 10px 0;
+ border: 1px solid #337ecc;
+ border-left: none;
+ }
+
+ tr {
+ width: 100%;
+ height: 44px;
+ line-height: 42px;
+ border-bottom: 1px solid #ccc;
+
+ &:last-of-type {
+ border-bottom: none;
+ }
+
+ td {
+ border-right: 1px solid #ccc;
+ display: inline-block;
+ height: 44px;
+ vertical-align: middle;
+ text-align: center;
+ line-height: 42px;
+
+ &:last-of-type {
+ border-right: none;
+ }
+
+ &.w-14 {
+ width: calc((100/7)/100 * 100%);
+ }
+
+ &.w-16 {
+ width: calc((100/6)/100 * 100%);
+ }
+
+ &.w-18 {
+ width: 16.59%;
+ }
+
+ &.w-20 {
+ width: 20%;
+ }
+
+ &.w-25 {
+ width: 25%;
+ }
+
+ &.w-50 {
+ width: 50%;
+ }
+
+ &.w-75 {
+ width: 75%;
+ }
+
+ .ant-input {
+ height: 100%;
+ border: none;
+ background: #f5f7fa;
+ }
+
+ .ant-picker {
+ width: 100%;
+ height: 100%;
+ }
+ }
+ }
+
+ .b-font {
+ font-size: 16px;
+ font-weight: bolder;
+ }
+}
+
+.m-color {
+ color: #0c4995;
+}
+:deep(.el-input__wrapper ){
+ box-shadow: none;
+}
+</style>
diff --git a/src/views/experiment/developing/components/selectMaterial.vue b/src/views/experiment/developing/components/selectMaterial.vue
new file mode 100644
index 0000000..bb29d5f
--- /dev/null
+++ b/src/views/experiment/developing/components/selectMaterial.vue
@@ -0,0 +1,210 @@
+<template>
+ <tr class="m-color b-font" style="text-align: center">实验所用的试剂或材料</tr>
+ <tr>
+ <td class="w-14 m-color">实验材料</td>
+ <td class="w-14 m-color">耗材ID</td>
+ <td class="w-14 m-color">材料类型</td>
+ <td class="w-14 m-color">材料储存</td>
+ <td class="w-14 m-color">计量单位</td>
+ <td class="w-14 m-color">使用数量</td>
+ <td class="w-14 m-color">操作</td>
+ </tr>
+ <tr v-for="(item,index) in selectMaterialState.materialList" :key="index">
+ <td class="w-14">
+ <el-select :disabled="selectMaterialState.disabled" filterable v-model="item.stuffId" @change="giveOtherMaterialValue($event, index)">
+ <el-option
+ v-for="item in selectMaterialState.allMaterialList"
+ :key="item.id"
+ :value="item.id"
+ :label="item.stuffName"
+ >
+ </el-option>
+ </el-select>
+ </td>
+ <td class="w-14">
+ <el-input :disabled="selectMaterialState.disabled" v-model="item.stuffCode" />
+ </td>
+ <td class="w-14">
+ <el-input :disabled="selectMaterialState.disabled" v-model="item.stuffType" />
+ </td>
+ <td class="w-14">
+ <el-input :disabled="selectMaterialState.disabled" v-model="item.stuffStorage" />
+ </td>
+ <td class="w-14">
+ <el-input :disabled="selectMaterialState.disabled" v-model="item.stuffUnit" />
+ </td>
+ <td class="w-14">
+ <el-input type="number" v-model="item.stuffUseCount" />
+ </td>
+ <td class="w-14">
+ <el-button type="danger" :disabled="selectMaterialState.disabled" @click="deleteMaterialItem(index)">删除</el-button>
+ </td>
+ </tr>
+ <tr style="text-align: center">
+ <el-button :disabled="selectMaterialState.disabled" type="primary" shape="round" @click="addMaterialItem()">
+ 选择实验材料
+ </el-button>
+ </tr>
+</template>
+
+<script setup lang="ts">
+import {onMounted, reactive, watchEffect} from "vue";
+import { materialApi } from "/@/api/basic/material";
+import {ElMessage} from "element-plus";
+let props = defineProps({
+ disabled: Boolean,
+ data: Array<AllMaterialListType>
+});
+
+const selectMaterialState = reactive<SelectMaterialType>({
+ disabled: false,
+ materialList: [],
+ allMaterialList: [],
+})
+
+const addMaterialItem = () => {
+ selectMaterialState.materialList.push({stuffId: null, stuffUseCount: null, stuffName: '',stuffCode:'',stuffType: '', stuffStorage: '', stuffUnit: ''});
+};
+
+watchEffect(() => {
+ selectMaterialState.materialList = props.data as Array<AllMaterialListType>
+ selectMaterialState.disabled = props.disabled
+});
+
+const deleteMaterialItem = (index: number) => {
+ selectMaterialState.materialList.splice(index,1);
+};
+
+const getAllPersonList = async () => {
+ let res = await materialApi().getAllMaterial();
+ if(res.data.code === 100){
+ selectMaterialState.allMaterialList = JSON.parse(JSON.stringify(res.data.data));
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ })
+ }
+};
+
+const giveOtherMaterialValue = (value: number, index:number) => {
+ const data = selectMaterialState.allMaterialList.find(item => item.id === value) as AllMaterialListType
+ selectMaterialState.materialList[index] = {
+ stuffId: data.id,
+ stuffUseCount: data.stuffUseCount,
+ stuffName: data.stuffName,
+ stuffCode: data.stuffCode,
+ stuffType: data.stuffType,
+ stuffStorage: data.stuffStorage,
+ stuffUnit: data.stuffUnit
+ };
+};
+
+const formatList = (formatList: Array<AllMaterialListType>) => {
+ selectMaterialState.materialList = formatList
+};
+
+defineExpose({
+ dataList: selectMaterialState.materialList,
+ formatList
+});
+
+
+onMounted(() => {
+ getAllPersonList();
+});
+</script>
+
+<style scoped lang="scss">
+.site-layout-background {
+ background: #fff;
+}
+
+.report-table {
+ width: 100%;
+ border-collapse: collapse;
+ border: 1px solid #337ecc;
+ margin: 20px 0;
+
+ th {
+ padding: 10px 0;
+ border: 1px solid #337ecc;
+ border-left: none;
+ }
+
+ tr {
+ width: 100%;
+ height: 44px;
+ line-height: 42px;
+ border-bottom: 1px solid #ccc;
+
+ &:last-of-type {
+ border-bottom: none;
+ }
+
+ td {
+ border-right: 1px solid #ccc;
+ display: inline-block;
+ height: 44px;
+ vertical-align: middle;
+ text-align: center;
+ line-height: 42px;
+
+ &:last-of-type {
+ border-right: none;
+ }
+
+ &.w-14 {
+ width: calc((100/7)/100 * 100%);
+ }
+
+ &.w-16 {
+ width: calc((100/6)/100 * 100%);
+ }
+
+ &.w-18 {
+ width: 16.59%;
+ }
+
+ &.w-20 {
+ width: 20%;
+ }
+
+ &.w-25 {
+ width: 25%;
+ }
+
+ &.w-50 {
+ width: 50%;
+ }
+
+ &.w-75 {
+ width: 75%;
+ }
+
+ .ant-input {
+ height: 100%;
+ border: none;
+ background: #f5f7fa;
+ }
+
+ .ant-picker {
+ width: 100%;
+ height: 100%;
+ }
+ }
+ }
+
+ .b-font {
+ font-size: 16px;
+ font-weight: bolder;
+ }
+}
+
+.m-color {
+ color: #0c4995;
+}
+:deep(.el-input__wrapper ){
+ box-shadow: none;
+}
+</style>
diff --git a/src/views/experiment/developing/components/selectPerson.vue b/src/views/experiment/developing/components/selectPerson.vue
new file mode 100644
index 0000000..e0359b8
--- /dev/null
+++ b/src/views/experiment/developing/components/selectPerson.vue
@@ -0,0 +1,218 @@
+<template>
+ <tr class="m-color b-font" style="text-align: center">实验人员</tr>
+ <tr>
+ <td class="w-14 m-color">姓名</td>
+ <td class="w-14 m-color">年龄</td>
+ <td class="w-14 m-color">性别</td>
+ <td class="w-14 m-color">专业</td>
+ <td class="w-14 m-color">部门</td>
+ <td class="w-14 m-color">相关资质</td>
+ <td class="w-14 m-color">操作</td>
+ </tr>
+ <tr v-for="(item,index) in selectPersonState.personList" :key="index">
+ <td class="w-14">
+ <el-select filterable :disabled="selectPersonState.disabled" v-model="item.personId" @change="giveOtherPersonValue($event, index)">
+ <el-option
+ v-for="item in selectPersonState.allPersonList"
+ :key="item.id"
+ :value="item.id"
+ :label="item.personName"
+ >
+ </el-option>
+ </el-select>
+ </td>
+ <td class="w-14">
+ <el-input :disabled="selectPersonState.disabled" v-model="item.personAge" />
+ </td>
+ <td class="w-14">
+ <el-input :disabled="selectPersonState.disabled" v-model="item.personGender" />
+ </td>
+ <td class="w-14">
+ <el-input :disabled="selectPersonState.disabled" v-model="item.personMajor" />
+ </td>
+ <td class="w-14">
+ <el-input :disabled="selectPersonState.disabled" v-model="item.depName" />
+ </td>
+ <td class="w-14">
+ <el-input :disabled="selectPersonState.disabled" v-model="item.aptitude" />
+ </td>
+ <td class="w-14">
+ <el-button type="danger" :disabled="selectPersonState.disabled" @click="deletePersonItem(index)">删除</el-button>
+ </td>
+ </tr>
+ <tr style="text-align: center">
+ <el-button :disabled="selectPersonState.disabled" type="primary" shape="round" @click="addPersonItem()">
+ 选择实验人员
+ </el-button>
+ </tr>
+</template>
+
+<script setup lang="ts">
+import {nextTick, onMounted, reactive, watchEffect} from "vue";
+import { personApi } from "/@/api/basic/person";
+import {ElMessage} from "element-plus";
+
+let props = defineProps({
+ disabled: Boolean,
+ data: Array<AllPersonListType>
+
+});
+
+const selectPersonState = reactive<SelectPersonType>({
+ disabled: false,
+ personList: [],
+ allPersonList: [
+ ],
+});
+
+watchEffect(() => {
+ selectPersonState.personList = props.data as Array<AllPersonListType>
+ selectPersonState.disabled = props.disabled
+});
+
+const addPersonItem = () => {
+ selectPersonState.personList.push({personId: null, personName: null, personAge: null, personGender:'',personMajor:'',depName:'',phone:'',aptitude:'',training:''});
+};
+
+const deletePersonItem = (index: number) => {
+ selectPersonState.personList.splice(index,1);
+};
+
+const getAllPersonList = async () => {
+ let res = await personApi().getAllPerson();
+ if(res.data.code === 100){
+ selectPersonState.allPersonList = JSON.parse(JSON.stringify(res.data.data));
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ })
+ }
+};
+
+const giveOtherPersonValue = (value: number, index:number) => {
+ // selectPersonState.personList[index] = selectPersonState.allPersonList.find(item => item.id === value) as AllPersonListType
+ const data = selectPersonState.allPersonList.find(item => item.id === value) as AllPersonListType
+ selectPersonState.personList[index] = {
+ personId: data.id,
+ personName: data.personName,
+ personAge: data.personAge,
+ personGender: data.personGender,
+ personMajor: data.personMajor,
+ depName: data.depName,
+ phone: data.phone,
+ aptitude: data.aptitude,
+ training: data.training,
+ };
+};
+
+const formatList = (formatList: Array<AllPersonListType>) => {
+ nextTick(() => {
+ selectPersonState.personList = formatList
+ })
+
+};
+
+defineExpose({
+ formatList,
+ dataList: selectPersonState.personList,
+});
+
+onMounted(() => {
+ getAllPersonList();
+});
+</script>
+
+<style scoped lang="scss">
+.site-layout-background {
+ background: #fff;
+}
+
+.report-table {
+ width: 100%;
+ border-collapse: collapse;
+ border: 1px solid #337ecc;
+ margin: 20px 0;
+
+ th {
+ padding: 10px 0;
+ border: 1px solid #337ecc;
+ border-left: none;
+ }
+
+ tr {
+ width: 100%;
+ height: 44px;
+ line-height: 42px;
+ border-bottom: 1px solid #ccc;
+
+ &:last-of-type {
+ border-bottom: none;
+ }
+
+ td {
+ border-right: 1px solid #ccc;
+ display: inline-block;
+ height: 44px;
+ vertical-align: middle;
+ text-align: center;
+ line-height: 42px;
+
+ &:last-of-type {
+ border-right: none;
+ }
+
+ &.w-14 {
+ width: calc((100/7)/100 * 100%);
+ }
+
+ &.w-16 {
+ width: calc((100/6)/100 * 100%);
+ }
+
+ &.w-18 {
+ width: 16.59%;
+ }
+
+ &.w-20 {
+ width: 20%;
+ }
+
+ &.w-25 {
+ width: 25%;
+ }
+
+ &.w-50 {
+ width: 50%;
+ }
+
+ &.w-75 {
+ width: 75%;
+ }
+
+ .ant-input {
+ height: 100%;
+ border: none;
+ background: #f5f7fa;
+ }
+
+ .ant-picker {
+ width: 100%;
+ height: 100%;
+ }
+ }
+ }
+
+ .b-font {
+ font-size: 16px;
+ font-weight: bolder;
+ }
+}
+
+.m-color {
+ color: #0c4995;
+}
+:deep(.el-input__wrapper ){
+ box-shadow: none;
+}
+</style>
diff --git a/src/views/experiment/developing/index.ts b/src/views/experiment/developing/index.ts
new file mode 100644
index 0000000..c06feb7
--- /dev/null
+++ b/src/views/experiment/developing/index.ts
@@ -0,0 +1,150 @@
+declare interface ProjectStateType {
+ projectData: Array<ProjectType>
+ searchQuery: {
+ pageIndex: number,
+ pageSize: number,
+ searchParams: {
+ experimentName: string,
+ experimentType: null | number,
+ }
+ },
+ total: 0,
+ experimentTypeList: Type []
+ allRoomList: RoomType []
+}
+
+declare interface ProjectType {
+ id?: number | null,
+ experimentCode: string,
+}
+
+declare interface Type {
+ id: number,
+ name: string,
+}
+
+declare interface ProjectDialogType {
+ title: string,
+ disabled: boolean,
+ projectDialogVisible: boolean,
+ projectForm: {
+ id: null | number,
+ experimentName: string,
+ experimentType: null | number,
+ liabilityUserId: null | number,
+ safeLiabilityUserId: null | number,
+ dep: string,
+ siteId: null | number,
+ experimentStep: string,
+ experimentMethod: string,
+ process: string,
+ keyProcess: string,
+ timeout: null | number,
+ timeoutManager: string,
+ closed: null | number,
+ unclosedManager: string,
+ explosionProof: string,
+ fireProof: string,
+ poisonProof: string,
+ hazardousWaste: null | number,
+ safeManagerMethod: string,
+ emergencyPlan: string,
+ emergencyDrill: string,
+ emergencyPlanName: string,
+ emergencyDrillStatus: string,
+ partitionCondition: string,
+ note: string,
+ expectStartTime: null | number,
+ persons: SelectPersonType [],
+ deviceList: SelectEquipmentType [],
+ stuffList: SelectMaterialType [],
+ hazardousWasteList: SelectDangerType []
+ },
+ projectFormRules: {
+
+ },
+ allPersonList: Array<AllPersonListType>
+ allRoomList: Array<RoomType>
+}
+
+declare interface SelectDangerType {
+ disabled: boolean
+ wasteList: Array<WasteType>
+ classifyList: Array<Type>
+ wasteStorageList: Array<Type>
+}
+
+declare interface WasteType {
+ classify: null | number,
+ wasteStorage: null | number,
+ handAmount: null | number,
+}
+
+
+declare interface SelectPersonType {
+ disabled: boolean
+ personList: Array<AllPersonListType>
+ allPersonList: Array<AllPersonListType>
+}
+
+declare interface AllPersonListType {
+ id: null | number,
+ personId?: null | number,
+ personName: null,
+ personAge: null,
+ personGender:'',
+ personMajor:'',
+ depName:'',
+ phone:'',
+ aptitude:'',
+ training:''
+}
+
+declare interface SelectEquipmentType {
+ disabled: boolean
+ equipmentList: Array<AllEquipmentListType>,
+ allEquipmentList: Array<AllEquipmentListType>,
+}
+
+declare interface AllEquipmentListType {
+ id?: null | number,
+ deviceId?: null | number,
+ deviceUseCount: null | number,
+ deviceCode: string,
+ deviceName: string,
+ devicePower: string,
+ specialDevice: string,
+}
+
+
+declare interface SelectMaterialType {
+ disabled: boolean
+ materialList: Array<AllMaterialListType>,
+ allMaterialList: Array<AllMaterialListType>,
+}
+
+declare interface AllMaterialListType {
+ id?: null | number,
+ stuffId?: null | number,
+ stuffUseCount: null | number,
+ stuffName: string,
+ stuffCode:string,
+ stuffType: string,
+ stuffStorage: string,
+ stuffUnit: string
+}
+
+
+declare interface ApplyStartDialogType {
+ title: string,
+ applyStartDialogVisible: boolean,
+ applyStartForm: {
+ id: number | null,
+ sisStatus: number | null,
+ safeInformationSystem: string,
+ startTime: string,
+ },
+ applyStartFormRules: {
+
+ },
+}
diff --git a/src/views/experiment/developing/index.vue b/src/views/experiment/developing/index.vue
new file mode 100644
index 0000000..ba7ab0b
--- /dev/null
+++ b/src/views/experiment/developing/index.vue
@@ -0,0 +1,347 @@
+<template>
+ <div class="home-container">
+ <div style="height: 100%">
+ <el-row class="homeCard">
+ <div class="basic-line">
+ <span>实验名称:</span>
+ <el-input v-model="projectState.searchQuery.searchParams.experimentName" clearable filterable class="input-box" placeholder="实验名称">
+ </el-input>
+ </div>
+ <div class="basic-line">
+ <span>实验类型:</span>
+ <el-select v-model="projectState.searchQuery.searchParams.experimentType" clearable filterable class="input-box" placeholder="实验类型">
+ <el-option v-for="item in projectState.experimentTypeList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+ </el-select>
+ </div>
+ <div style="padding-bottom: 10px">
+ <el-button type="primary" @click="getProjectData">查询</el-button>
+ <el-button plain @click="reset">重置</el-button>
+ </div>
+ </el-row>
+ <div class="homeCard">
+ <div class="main-card">
+ <el-row class="cardTop">
+ <el-col :span="12" class="mainCardBtn">
+ <el-button type="primary" :icon="Plus" size="default" @click="openProjectDialog('新增', {})">新增</el-button>
+ <!-- <el-button type="danger" :icon="Delete" size="default" plain>删除</el-button>-->
+ </el-col>
+<!-- <el-button type="primary" :icon="Refresh" size="default" />-->
+ </el-row>
+ <el-table ref="multipleTableRef" :data="projectState.projectData" style="width: 100%" height="calc(100% - 100px)" :header-cell-style="{ background: '#fafafa' }">
+ <el-table-column prop="experimentCode" label="实验编号"/>
+ <el-table-column prop="expectStartTime" label="立项时间" />
+ <el-table-column prop="liabilityUser" label="负责人"/>
+ <el-table-column prop="createTime" label="创建时间" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="createByUserName" label="创建人" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="updateTime" label="最后修改时间" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="updateByUserName" label="最后修改人" show-overflow-tooltip></el-table-column>
+ <el-table-column label="操作" width="250">
+ <template #default="scope">
+ <el-button size="small" text type="primary" :icon="View" @click="openProjectDialog('查看', scope.row)">查看</el-button>
+ <el-button size="small" text type="primary" :icon="Edit" @click="applyAccess( scope.row)">申请评估</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ <div class="pageBtn">
+ <el-pagination @size-change="onHandleSizeChange" @current-change="onHandleCurrentChange" :pager-count="5" :page-sizes="[10, 20, 30]" v-model:current-page="projectState.searchQuery.pageIndex" background v-model:page-size="projectState.searchQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="projectState.total" class="page-position"> </el-pagination>
+ </div>
+ </div>
+ </div>
+ </div>
+ <project-dialog ref="ProjectDialogRef" @refresh="getProjectData"></project-dialog>
+<!-- <apply-start ref="ApplyStartRef"></apply-start>-->
+ <test ref="ApplyStartRef" @refresh="getProjectData"></test>
+ </div>
+</template>
+
+<script setup lang="ts">
+import {defineAsyncComponent, onMounted, reactive, ref} from "vue";
+import {projectApi} from "/@/api/experiment/project";
+import {ElMessage, ElMessageBox} from "element-plus";
+import { View,Edit, Plus, Delete } from '@element-plus/icons-vue';
+import {roomApi} from "/@/api/basic/room";
+
+const ProjectDialog = defineAsyncComponent(() => import('./components/projectDialog.vue'));
+const Test = defineAsyncComponent(() => import('./components/applyDialog.vue'))
+
+const ProjectDialogRef = ref();
+const ApplyStartRef = ref();
+
+const projectState = reactive<ProjectStateType>({
+ projectData: [],
+ searchQuery: {
+ pageIndex: 1,
+ pageSize: 10,
+ searchParams: {
+ experimentName: '',
+ experimentType: null,
+ }
+ },
+ total: 0,
+ experimentTypeList: [
+ {id: 1, name: '化学类'},
+ {id: 2, name: '生物类'},
+ {id: 3, name: '辐射类'},
+ {id: 4, name: '机电类'},
+ {id: 5, name: '特种设备类'},
+ {id: 6, name: '其它类'},
+ ],
+ allRoomList: []
+})
+
+const getProjectData = async () => {
+ let res = await projectApi().getProjectByList(projectState.searchQuery);
+ if(res.data.code === 100){
+ projectState.projectData = res.data.data;
+ projectState.total = res.data.total;
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ });
+ }
+};
+
+const openProjectDialog = (title: string, value: ProjectType) => {
+ ProjectDialogRef.value.showProjectDialog(title, value, projectState.allRoomList);
+};
+
+const applyAccess = (val: ProjectType) => {
+ debugger
+ ElMessageBox.confirm(`此操作将申请评估该实验:“${val.experimentCode}”,是否继续?`, '提示', {
+ confirmButtonText: '确认',
+ cancelButtonText: '取消',
+ type: 'warning'
+ })
+ .then(async () => {
+ let res = await projectApi().accessProject([val.id]);
+ if (res.data.code === 100) {
+ ElMessage({
+ type: 'success',
+ duration: 2000,
+ message: '申请成功'
+ });
+ await getProjectData();
+ } else {
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ });
+ }
+ })
+ .catch((error) => {
+ });
+}
+
+const onDelProject = (val: ProjectType) => {
+ ElMessageBox.confirm(`此操作将永久删除该实验:“${val.experimentCode}”,是否继续?`, '提示', {
+ confirmButtonText: '确认',
+ cancelButtonText: '取消',
+ type: 'warning'
+ })
+ .then(async () => {
+ debugger
+ let res = await projectApi().deleteProjectById({ id: val.id });
+ if (res.data.code === 100) {
+ ElMessage({
+ type: 'success',
+ duration: 2000,
+ message: '删除成功'
+ });
+ await getProjectData();
+ } else {
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ });
+ }
+ })
+ .catch((error) => {
+ });
+}
+
+const onHandleSizeChange = (val: number) => {
+ projectState.searchQuery.pageSize = val;
+ getProjectData();
+};
+
+const onHandleCurrentChange = (val: number) => {
+ projectState.searchQuery.pageIndex = val;
+ getProjectData();
+};
+
+const reset = () => {
+ projectState.searchQuery = {
+ pageIndex: 1,
+ pageSize: 10,
+ searchParams: {
+ experimentName: '',
+ experimentType: null,
+ }
+ }
+};
+
+const getRoomData = async () => {
+ let res = await roomApi().getAllRoom();
+ if(res.data.code === 100){
+ projectState.allRoomList = JSON.parse(JSON.stringify(res.data.data));
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ });
+ }
+};
+
+onMounted(() => {
+ getProjectData();
+ getRoomData();
+})
+
+</script>
+
+<style scoped lang="scss">
+$homeNavLengh: 8;
+.home-container {
+ height: calc(100vh - 144px);
+ box-sizing: border-box;
+ overflow: hidden;
+ .homeCard {
+ width: 100%;
+ padding: 20px;
+ box-sizing: border-box;
+ background: #fff;
+ border-radius: 4px;
+
+ .main-card {
+ width: 100%;
+ height: 100%;
+ .cardTop {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 20px;
+ .mainCardBtn {
+ margin: 0;
+ }
+ }
+ .pageBtn {
+ height: 60px;
+ display: flex;
+ align-items: center;
+ justify-content: right;
+
+ .demo-pagination-block + .demo-pagination-block {
+ margin-top: 10px;
+ }
+ .demo-pagination-block .demonstration {
+ margin-bottom: 16px;
+ }
+ }
+ }
+ &:last-of-type {
+ height: calc(100% - 100px);
+ }
+ }
+ .el-row {
+ display: flex;
+ align-items: center;
+ margin-bottom: 20px;
+ &:last-child {
+ margin-bottom: 0;
+ }
+ .grid-content {
+ align-items: center;
+ min-height: 36px;
+ }
+
+ .topInfo {
+ display: flex;
+ align-items: center;
+ font-size: 16px;
+ font-weight: bold;
+
+ & > div {
+ white-space: nowrap;
+ margin-right: 20px;
+ }
+ }
+ }
+}
+.stepItem {
+ width: 100%;
+ display: flex;
+ align-items: flex-start;
+ margin-bottom: 30px;
+ margin-left: 30px;
+ padding-bottom: 30px;
+ border-left: 2px solid #ccc;
+ &:first-of-type {
+ margin-top: 30px;
+ }
+ &:last-of-type {
+ margin-bottom: 0;
+ border-left: none;
+ }
+ .stepNum {
+ width: 30px;
+ height: 30px;
+ border-radius: 15px;
+ box-sizing: border-box;
+ color: #333;
+ border: 1px solid #999;
+ line-height: 28px;
+ text-align: center;
+ margin-right: 10px;
+ margin-left: -16px;
+ margin-top: -30px;
+ }
+ .stepCard {
+ width: 100%;
+ margin-top: -30px;
+
+ .box-card {
+ width: 100%;
+ &:deep(.el-card__header) {
+ padding: 10px 15px;
+ }
+ .card-header {
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ & > div:first-of-type {
+ margin-right: 80px;
+ font-size: 18px;
+ font-weight: bold;
+ }
+ }
+ }
+ }
+ &:hover .card-header {
+ color: #0098f5;
+ }
+ &:hover .stepNum {
+ border: 2px solid #0098f5;
+ color: #0098f5;
+ }
+}
+
+:deep(.el-date-editor) {
+ width: 100%;
+}
+.el-select {
+ width: 100%;
+}
+:deep(.el-textarea.is-disabled .el-textarea__inner) {
+ background-color: var(--el-card-bg-color);
+ color: var(--el-input-text-color, var(--el-text-color-regular));
+}
+:deep(.el-input.is-disabled .el-input__inner) {
+ color: var(--el-input-text-color, var(--el-text-color-regular));
+}
+:deep(.el-input.is-disabled .el-input__wrapper) {
+ background-color: var(--el-card-bg-color);
+ box-shadow: none;
+}
+</style>
diff --git a/src/views/experiment/project/components/applyDialog.vue b/src/views/experiment/project/components/applyDialog.vue
new file mode 100644
index 0000000..b65f862
--- /dev/null
+++ b/src/views/experiment/project/components/applyDialog.vue
@@ -0,0 +1,98 @@
+<template>
+ <div class="system-menu-dialog-container">
+ <el-dialog :title="applyStartDialogState.title" v-model="applyStartDialogState.applyStartDialogVisible" width="600px">
+ <el-form ref="applyStartFormRef" :rules="applyStartDialogState.applyStartFormRules" :model="applyStartDialogState.applyStartForm" size="default" label-width="160px">
+ <el-row :gutter="35">
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="实验开始时间" prop="startTime">
+ <el-date-picker type="datetime" format="YYYY/MM/DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" v-model="applyStartDialogState.applyStartForm.startTime" class="input-length"/>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="是否是安全信息化系统 " prop="sisStatus">
+ <el-radio-group v-model="applyStartDialogState.applyStartForm.sisStatus">
+ <el-radio :label="1">是</el-radio>
+ <el-radio :label="2">否</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="安全信息化系统" prop="safeInformationSystem">
+ <el-input v-model="applyStartDialogState.applyStartForm.safeInformationSystem" placeholder="材料类型" class="input-length">
+ </el-input>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <template #footer>
+ <span class="dialog-footer">
+ <el-button @click="applyStartDialogState.applyStartDialogVisible = !applyStartDialogState.applyStartDialogVisible" size="default">取 消</el-button>
+ <el-button type="primary" @click="onSubmitApplyStart" size="default">确定</el-button>
+ </span>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup lang="ts">
+import { reactive, ref } from "vue";
+import {ElMessage} from "element-plus";
+import {projectApi} from "/@/api/experiment/project";
+
+const applyStartFormRef = ref()
+
+const applyStartDialogState = reactive<ApplyStartDialogType>({
+ title: '',
+ applyStartDialogVisible: false,
+ applyStartForm: {
+ id: null,
+ sisStatus: null,
+ safeInformationSystem: '',
+ startTime: '',
+ },
+ applyStartFormRules: {
+
+ },
+})
+
+const showApplyStartDialog = (value: ProjectType) => {
+ applyStartDialogState.applyStartDialogVisible = true;
+ applyStartDialogState.applyStartForm.id = <number>value.id
+};
+
+const onSubmitApplyStart = () => {
+ applyStartFormRef.value.validate(async(valid: boolean) => {
+ if(valid){
+ let res = await projectApi().applyProject([applyStartDialogState.applyStartForm]);
+ if(res.data.code === 100){
+ emit('refresh')
+ applyStartDialogState.applyStartDialogVisible = false;
+ ElMessage({
+ type: 'success',
+ message: '申请开展成功'
+ })
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg,
+ });
+ }
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: '请完善基本信息',
+ });
+ }
+ })
+};
+
+const emit = defineEmits(['refresh'])
+
+defineExpose({
+ showApplyStartDialog
+})
+</script>
+
+<style scoped>
+
+</style>
diff --git a/src/views/experiment/project/components/applyStart.vue b/src/views/experiment/project/components/applyStart.vue
new file mode 100644
index 0000000..8906f6e
--- /dev/null
+++ b/src/views/experiment/project/components/applyStart.vue
@@ -0,0 +1,101 @@
+<template>
+ <div class="system-menu-dialog-container">
+ <el-dialog :title="applyStartDialogState.title" v-model="applyStartDialogState.applyStartDialogVisible" width="600px">
+ <el-form ref="applyStartFormRef" :rules="applyStartDialogState.applyStartFormRules" :model="applyStartDialogState.applyStartForm" size="default" label-width="120px">
+ <el-row :gutter="35">
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="实验材料" prop="stuffName">
+ <el-date-picker type="datetime" format="YYYY/MM/DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" v-model="applyStartDialogState.applyStartForm.startTime" class="input-length"/>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="编号" prop="sisStatus">
+ <el-radio-group v-model="applyStartDialogState.applyStartForm.sisStatus">
+ <el-radio :label="1">是</el-radio>
+ <el-radio :label="2">否</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="材料类型" prop="stuffType">
+ <el-select v-model="applyStartDialogState.applyStartForm.safeInformationSystem" placeholder="材料类型" class="input-length">
+ </el-select>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <template #footer>
+ <span class="dialog-footer">
+ <el-button @click="applyStartDialogState.applyStartDialogVisible = !applyStartDialogState.applyStartDialogVisible" size="default">取 消</el-button>
+ <el-button type="primary" @click="onSubmitApplyStart" size="default">确定</el-button>
+ </span>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup lang="ts">
+import { reactive, ref } from "vue";
+import {ElMessage} from "element-plus";
+import {projectApi} from "/@/api/experiment/project";
+
+const applyStartFormRef = ref()
+
+const applyStartDialogState = reactive<ApplyStartDialogType>({
+ title: '',
+ applyStartDialogVisible: false,
+ applyStartForm: {
+ id: null,
+ sisStatus: null,
+ safeInformationSystem: '',
+ startTime: '',
+ },
+ applyStartFormRules: {
+ stuffCode: [{ required: true, message: '请填写实验材料', trigger: 'blur' }],
+ stuffName: [{ required: true, message: '请填写编号', trigger: 'blur' }],
+ stuffStorage: [{ required: true, message: '请选择材料类型', trigger: 'change' }],
+ stuffType: [{ required: true, message: '请选择材料储存', trigger: 'change' }],
+ stuffUnit: [{ required: true, message: '请选择计量单位', trigger: 'change' }]
+ },
+})
+
+const showApplyStartDialog = (value: ProjectType) => {
+ applyStartDialogState.applyStartDialogVisible = true;
+};
+
+const onSubmitApplyStart = () => {
+ applyStartFormRef.value.validate(async(valid: boolean) => {
+ if(valid){
+ let res = await projectApi().applyProject(applyStartDialogState.applyStartForm);
+ if(res.data.code === 100){
+ emit('refresh')
+ applyStartDialogState.applyStartDialogVisible = false;
+ ElMessage({
+ type: 'success',
+ message: '申请开展成功'
+ })
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg,
+ });
+ }
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: '请完善基本信息',
+ });
+ }
+ })
+};
+
+const emit = defineEmits(['refresh'])
+
+defineExpose({
+ showApplyStartDialog
+})
+</script>
+
+<style scoped>
+
+</style>
diff --git a/src/views/experiment/project/components/projectDialog.vue b/src/views/experiment/project/components/projectDialog.vue
new file mode 100644
index 0000000..b621833
--- /dev/null
+++ b/src/views/experiment/project/components/projectDialog.vue
@@ -0,0 +1,533 @@
+<template>
+ <div class="system-menu-dialog-container">
+ <el-dialog :title="projectDialogState.title" v-model="projectDialogState.projectDialogVisible" width="70%">
+ <el-form ref="ProjectFormRef" :rules="projectDialogState.projectFormRules" :model="projectDialogState.projectForm" size="default" label-width="0">
+ <table class="report-table">
+ <th class="m-color b-font" style="text-align: center">***研究所/***大学<br />科学研究实验项目安全风险基础信息录入表(已开展B)</th>
+ <tr>
+ <td class="w-25 m-color">实验名称</td>
+ <td class="w-75 m-color">
+ <el-form-item prop="experimentName">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.experimentName" placeholder="请输入实验名称" />
+ </el-form-item>
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">实验类型</td>
+ <td class="w-75 m-color">
+
+ <el-radio-group style="text-align: center" :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.experimentType">
+ <el-radio :label="1">化学类</el-radio>
+ <el-radio :label="2">生物类</el-radio>
+ <el-radio :label="3">辐射类</el-radio>
+ <el-radio :label="4">机电类</el-radio>
+ <el-radio :label="5">特种设备类</el-radio>
+ <el-radio :label="6">其他类</el-radio>
+ </el-radio-group>
+
+
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">部门</td>
+ <td class="w-25 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.dep" />
+ </td>
+ <td class="w-25 m-color">负责人</td>
+ <td class="w-16 m-color">
+ <el-select :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.liabilityUserId" clearable filterable>
+ <el-option
+ v-for="item in projectDialogState.allPersonList"
+ :key="item.id"
+ :value="item.id"
+ :label="item.personName"
+ ></el-option>
+ </el-select>
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">立项时间</td>
+ <td class="w-25 m-color">
+ <el-date-picker :disabled="projectDialogState.disabled" type="datetime" format="YYYY/MM/DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" v-model="projectDialogState.projectForm.expectStartTime" />
+ </td>
+<!-- <td class="w-16 m-color">开展时间</td>-->
+<!-- <td class="w-16 m-color">-->
+<!-- <el-date-picker v-model="projectDialogState.projectForm.startTime" />-->
+<!-- </td>-->
+ <td class="w-25 m-color">安全负责人</td>
+ <td class="w-16 m-color">
+ <el-select :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.safeLiabilityUserId" clearable filterable>
+ <el-option
+ v-for="item in projectDialogState.allPersonList"
+ :key="item.id"
+ :value="item.id"
+ :label="item.personName"
+ ></el-option>
+ </el-select>
+ </td>
+ </tr>
+ <tr class="m-color b-font" style="text-align: center">实验场所</tr>
+<!-- <tr>-->
+<!-- <td class="w-25 m-color">楼宇</td>-->
+<!-- <td class="w-75 m-color">-->
+<!-- <el-input v-model="projectDialogState.projectForm.building" placeholder="请输入楼栋名称" />-->
+<!-- </td>-->
+<!-- </tr>-->
+ <tr>
+ <td class="w-25 m-color">房间号</td>
+<!-- <td class="w-75 m-color">-->
+ <td class="w-16 m-color">
+ <el-select :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.siteId" placeholder="请输入房间号" >
+ <el-option
+ v-for="item in projectDialogState.allRoomList"
+ :key="item.id"
+ :value="item.id"
+ :label="item.room"
+ ></el-option>
+ </el-select>
+ </td>
+ </tr>
+ <select-material ref="selectMaterialRef" v-model:disabled="projectDialogState.disabled" v-model:data="projectDialogState.projectForm.stuffList"></select-material>
+ <select-equipment ref="selectEquipmentRef" v-model:disabled="projectDialogState.disabled" v-model:data="projectDialogState.projectForm.deviceList"></select-equipment>
+ <tr>
+ <td class="w-25 m-color">实验步骤</td>
+ <td class="w-75 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.experimentStep" placeholder="请输入实验步骤" />
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">操作方法</td>
+ <td class="w-75 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.experimentMethod" placeholder="请输入操作方法" />
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">工艺过程</td>
+ <td class="w-75 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.process" placeholder="请输入工艺过程" />
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">特殊/关键过程</td>
+ <td class="w-75 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.keyProcess" placeholder="请输入特殊/关键过程" />
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">是否存在过夜、老化实验</td>
+ <td class="w-25 m-color">
+ <el-radio-group :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.timeout">
+ <el-radio :label="1">存在</el-radio>
+ <el-radio :label="2">不存在</el-radio>
+ </el-radio-group>
+ </td>
+ <td class="w-25 m-color">过夜、老化保障措施</td>
+ <td class="w-25 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.timeoutManager" />
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">是否在封闭条件下</td>
+ <td class="w-25 m-color">
+ <el-radio-group :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.closed">
+ <el-radio :label="1">存在</el-radio>
+ <el-radio :label="2">不存在</el-radio>
+ </el-radio-group>
+ </td>
+ <td class="w-25 m-color">封闭条件保障措施</td>
+ <td class="w-25 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.unclosedManager" />
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">实验场所防爆措施条件和设施情况</td>
+ <td class="w-75 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.explosionProof" placeholder="请输入" />
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">实验场所防火措施条件和设施情况</td>
+ <td class="w-75 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.fireProof" placeholder="请输入" />
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">实验场所防中毒措施条件和设施情况</td>
+ <td class="w-75 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.poisonProof" placeholder="请输入" />
+ </td>
+ </tr>
+
+
+ <select-danger ref="selectDangerRef" v-model:data="projectDialogState.projectForm.hazardousWasteList" v-model:disabled="projectDialogState.disabled"></select-danger>
+ <select-person ref="selectPersonRef" v-model:data="projectDialogState.projectForm.persons" v-model:disabled="projectDialogState.disabled"></select-person>
+
+
+<!-- <tr>-->
+<!-- <td class="w-25 m-color">安全信息化系统使用情况</td>-->
+<!-- <td class="w-25 m-color">-->
+<!-- <el-radio-group v-model="projectDialogState.projectForm.useIT">-->
+<!-- <el-radio value="1">是</el-radio>-->
+<!-- <el-radio value="2">否</el-radio>-->
+<!-- </el-radio-group>-->
+<!-- </td>-->
+<!-- <td class="w-25 m-color">系统名称</td>-->
+<!-- <td class="w-25 m-color">-->
+<!-- <el-input v-model="projectDialogState.projectForm.systemName" placeholder="请输入" />-->
+<!-- </td>-->
+<!-- </tr>-->
+ <tr>
+ <td class="w-25 m-color">安全管理制度</td>
+ <td class="w-75 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.safeManagerMethod" placeholder="请输入" />
+ </td>
+ </tr>
+ <tr class="m-color b-font" style="text-align: center">应急预案/应急演练</tr>
+ <tr>
+ <td class="w-25 m-color">有无预案</td>
+ <td class="w-25 m-color">
+ 预案名称
+ </td>
+ <td class="w-25 m-color">是否演练</td>
+ <td class="w-25 m-color">
+ 演练情况
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.emergencyPlan" />
+ </td>
+ <td class="w-25 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.emergencyPlanName" />
+ </td>
+ <td class="w-25 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.emergencyDrillStatus" />
+ </td>
+ <td class="w-25 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.emergencyDrill" />
+ </td>
+ </tr>
+ <tr class="m-color b-font" style=" text-align: center">实验人员</tr>
+ <tr>
+ <td class="w-25 m-color">实验场所是否需要分区隔断</td>
+ <td class="w-75 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.partitionCondition" placeholder="请输入" />
+ </td>
+ </tr>
+ <tr>
+ <td class="w-25 m-color">其它基础信息(详细描述)</td>
+ <td class="w-75 m-color">
+ <el-input :disabled="projectDialogState.disabled" v-model="projectDialogState.projectForm.note" placeholder="请输入" />
+ </td>
+ </tr>
+ </table>
+ </el-form>
+ <template #footer>
+ <span class="dialog-footer" style="padding-top:10px;text-align: center !important;">
+ <el-button @click="projectDialogState.projectDialogVisible = !projectDialogState.projectDialogVisible" size="default">取 消</el-button>
+ <el-button type="primary" v-if="!projectDialogState.disabled" @click="onSubmitProject" size="default">确定</el-button>
+ </span>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup lang="ts">
+import {defineAsyncComponent, nextTick, onMounted, reactive, ref} from "vue";
+import {ElMessage} from "element-plus";
+import {projectApi} from "/@/api/experiment/project";
+import {personApi} from "/@/api/basic/person";
+
+const SelectEquipment = defineAsyncComponent(() => import('./selectEquipment.vue'))
+const SelectMaterial = defineAsyncComponent(() => import('./selectMaterial.vue'))
+const SelectDanger = defineAsyncComponent(() => import('./selectDanger.vue'))
+const SelectPerson = defineAsyncComponent(() => import('./selectPerson.vue'))
+const ProjectFormRef = ref()
+const selectPersonRef = ref()
+const selectEquipmentRef = ref()
+const selectMaterialRef = ref()
+const selectDangerRef = ref()
+
+const projectDialogState = reactive<ProjectDialogType>({
+ title: '',
+ disabled: false,
+ projectDialogVisible: false,
+ projectForm: {
+ id: null,
+ experimentName: "",
+ experimentType: null,
+ liabilityUserId: null,
+ safeLiabilityUserId: null,
+ dep: "",
+ siteId: null,
+ experimentStep: "",
+ experimentMethod: "",
+ process: "",
+ keyProcess: "",
+ timeout: null,
+ timeoutManager: "",
+ closed: null,
+ unclosedManager: "",
+ explosionProof: "",
+ fireProof: "",
+ poisonProof: "",
+ hazardousWaste: null,
+ safeManagerMethod: "",
+ emergencyPlan: "",
+ emergencyDrill: "",
+ emergencyPlanName: "",
+ emergencyDrillStatus: "",
+ partitionCondition: "",
+ note: "",
+ expectStartTime: null,
+ persons: [
+ ],
+ deviceList: [
+ ],
+ stuffList: [
+ ],
+ hazardousWasteList: [
+ ]
+ },
+ projectFormRules: {
+ experimentName: [{ required: true, message: '请填写设备编号', trigger: 'blur' }],
+ deviceName: [{ required: true, message: '请填写设备名称', trigger: 'blur' }],
+ devicePower: [{ required: true, message: '请填写设备功率', trigger: 'blur' }],
+ deviceUnit: [{ required: true, message: '请选择计量单位', trigger: 'change' }]
+ },
+ allPersonList: [],
+ allRoomList: [],
+})
+
+const showProjectDialog = (title: string, value: ProjectType, allRoomList: RoomType []) => {
+ projectDialogState.projectDialogVisible = true;
+ projectDialogState.allRoomList = allRoomList
+ setTimeout(() => {
+ ProjectFormRef.value.clearValidate();
+ });
+ if(title === '新增'){
+ projectDialogState.disabled = false
+ projectDialogState.title = '新增';
+ projectDialogState.projectForm = {
+ id: null,
+ experimentName: "",
+ experimentType: null,
+ liabilityUserId: null,
+ safeLiabilityUserId: null,
+ dep: "",
+ siteId: null,
+ experimentStep: "",
+ experimentMethod: "",
+ process: "",
+ keyProcess: "",
+ timeout: null,
+ timeoutManager: "",
+ closed: null,
+ unclosedManager: "",
+ explosionProof: "",
+ fireProof: "",
+ poisonProof: "",
+ hazardousWaste: 1,
+ safeManagerMethod: "",
+ emergencyPlan: "",
+ emergencyDrill: "",
+ emergencyPlanName: "",
+ emergencyDrillStatus: "",
+ partitionCondition: "",
+ note: "",
+ expectStartTime: null,
+ persons: [
+ ],
+ deviceList: [
+ ],
+ stuffList: [
+ ],
+ hazardousWasteList: [
+ ]
+ };
+ }else{
+ projectDialogState.title = '查看';
+ projectDialogState.disabled = true
+ for(let i in projectDialogState.projectForm) {
+ if(isValidKey(i, projectDialogState.projectForm)) {
+ projectDialogState.projectForm[i] = value[i];
+ }
+ }
+ }
+};
+
+const isValidKey = (key: string | number | symbol, object:object): key is keyof typeof object =>{
+ return key in object;
+};
+
+const onSubmitProject = () => {
+ ProjectFormRef.value.validate(async(valid: boolean) => {
+ if(valid){
+ if(projectDialogState.title === '新增'){
+ projectDialogState.projectForm.persons = selectPersonRef.value.dataList
+ projectDialogState.projectForm.hazardousWasteList = selectDangerRef.value.dataList
+ projectDialogState.projectForm.stuffList = selectMaterialRef.value.dataList
+ projectDialogState.projectForm.deviceList = selectEquipmentRef.value.dataList
+ let res = await projectApi().addProject(projectDialogState.projectForm);
+ if(res.data.code === 100){
+ emit('refresh')
+ projectDialogState.projectDialogVisible = false;
+ ElMessage({
+ type: 'success',
+ message: '新增成功'
+ })
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg,
+ });
+ }
+ }else{
+ let res = await projectApi().modProject(projectDialogState.projectForm)
+ if(res.data.code === 100){
+ emit('refresh')
+ projectDialogState.projectDialogVisible = false;
+ ElMessage({
+ type: 'success',
+ message: '编辑成功'
+ })
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg,
+ });
+ }
+ }
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: '请完善基本信息',
+ });
+ }
+ })
+};
+
+const getAllPersonList = async () => {
+ let res = await personApi().getAllPerson();
+ if(res.data.code === 100){
+ projectDialogState.allPersonList = JSON.parse(JSON.stringify(res.data.data));
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ })
+ }
+};
+
+const emit = defineEmits(['refresh']);
+
+defineExpose({
+ showProjectDialog,
+});
+
+onMounted(() => {
+ getAllPersonList();
+});
+</script>
+
+<style scoped lang="scss">
+.site-layout-background {
+ background: #fff;
+}
+
+.report-table {
+ width: 100%;
+ border-collapse: collapse;
+ border: 1px solid #337ecc;
+ margin: 20px 0;
+
+th {
+ padding: 10px 0;
+ border: 1px solid #337ecc;
+ border-left: none;
+}
+
+tr {
+ width: 100%;
+ height: 44px;
+ line-height: 42px;
+ border-bottom: 1px solid #ccc;
+
+&:last-of-type {
+ border-bottom: none;
+ }
+
+td {
+ border-right: 1px solid #ccc;
+ display: inline-block;
+ height: 44px;
+ vertical-align: middle;
+ text-align: center;
+ line-height: 42px;
+
+&:last-of-type {
+ border-right: none;
+ }
+
+&.w-14 {
+ width: calc((100/7)/100 * 100%);
+ }
+
+&.w-16 {
+ width: calc((100/6)/100 * 100%);
+ }
+
+&.w-18 {
+ width: 16.59%;
+ }
+
+&.w-20 {
+ width: 20%;
+ }
+
+&.w-25 {
+ width: 25%;
+ }
+
+&.w-50 {
+ width: 50%;
+ }
+
+&.w-75 {
+ width: 75%;
+ }
+
+.ant-input {
+ height: 100%;
+ border: none;
+ background: #f5f7fa;
+}
+
+.ant-picker {
+ width: 100%;
+ height: 100%;
+}
+}
+}
+
+.b-font {
+ font-size: 16px;
+ font-weight: bolder;
+}
+}
+
+.m-color {
+ color: #0c4995;
+}
+:deep(.el-input__wrapper ){
+ box-shadow: none;
+ margin-top: 6px;
+}
+:deep(.el-dialog__footer){
+ padding-top: 20px;
+ display: flex;
+ justify-content: center;
+}
+
+
+</style>
diff --git a/src/views/experiment/project/components/selectDanger.vue b/src/views/experiment/project/components/selectDanger.vue
new file mode 100644
index 0000000..8ef010c
--- /dev/null
+++ b/src/views/experiment/project/components/selectDanger.vue
@@ -0,0 +1,184 @@
+<template>
+ <tr class="m-color b-font" style="text-align: center">危废情况</tr>
+ <tr>
+ <td class="w-20 m-color">序号</td>
+ <td class="w-20 m-color">废弃物分类</td>
+ <td class="w-20 m-color">存储方式</td>
+ <td class="w-20 m-color">预估处理量</td>
+ <td class="w-20 m-color">操作</td>
+ </tr>
+ <tr v-for="(item,index) in selectDangerState.wasteList" :key="index">
+ <td class="w-20">
+ {{ index + 1 }}
+ </td>
+ <td class="w-20">
+ <el-select :disabled="selectDangerState.disabled" v-model="item.classify" clearable filterable>
+ <el-option v-for="item in selectDangerState.classifyList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+ </el-select>
+ </td>
+ <td class="w-20">
+ <el-select :disabled="selectDangerState.disabled" v-model="item.wasteStorage" clearable filterable>
+ <el-option v-for="item in selectDangerState.wasteStorageList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+ </el-select>
+ </td>
+ <td class="w-20">
+ <el-input type="number" v-model="item.handAmount"></el-input>
+ </td>
+ <td class="w-20">
+ <el-button :disabled="selectDangerState.disabled" type="danger" @click="deleteDangerItem(index)">删除</el-button>
+ </td>
+ </tr>
+ <tr style="text-align: center">
+ <el-button :disabled="selectDangerState.disabled" type="primary" shape="round" @click="addDangerItem()">
+ 添加行
+ </el-button>
+ </tr>
+</template>
+
+<script setup lang="ts">
+import {reactive, watchEffect} from "vue";
+
+let props = defineProps({
+ disabled: Boolean,
+ data: Array<WasteType>
+});
+
+const selectDangerState = reactive<SelectDangerType>({
+ disabled: false,
+ wasteList: [
+ ],
+ classifyList:[
+ {id:1, name: '有机'},
+ {id:2, name: '酸'},
+ {id:3, name: '碱性'},
+ {id:4, name: '固体废弃物'},
+ {id:5, name: '医疗废弃物'},
+ {id:6, name: '过期化学品'},
+ {id:7, name: '其他'}
+ ],
+ wasteStorageList: [
+ {id:1, name: '吨袋'},
+ {id:2, name: '吨桶'},
+ {id:3, name: '小桶'},
+ {id:4, name: '托盘'},
+ {id:5, name: '其他'},
+ ]
+})
+
+watchEffect(() => {
+ selectDangerState.wasteList = props.data as Array<WasteType>
+ selectDangerState.disabled = props.disabled
+});
+
+const addDangerItem = () => {
+ selectDangerState.wasteList.push({classify: null, wasteStorage: null, handAmount: null,});
+};
+
+const deleteDangerItem = (index: number) => {
+ selectDangerState.wasteList.splice(index,1);
+};
+
+const formatList = (formatList: Array<WasteType>) => {
+ selectDangerState.wasteList = formatList
+}
+
+defineExpose({
+ formatList,
+ dataList: selectDangerState.wasteList,
+});
+
+</script>
+
+<style scoped lang="scss">
+.site-layout-background {
+ background: #fff;
+}
+
+.report-table {
+ width: 100%;
+ border-collapse: collapse;
+ border: 1px solid #337ecc;
+ margin: 20px 0;
+
+ th {
+ padding: 10px 0;
+ border: 1px solid #337ecc;
+ border-left: none;
+ }
+
+ tr {
+ width: 100%;
+ height: 44px;
+ line-height: 42px;
+ border-bottom: 1px solid #ccc;
+
+ &:last-of-type {
+ border-bottom: none;
+ }
+
+ td {
+ border-right: 1px solid #ccc;
+ display: inline-block;
+ height: 44px;
+ vertical-align: middle;
+ text-align: center;
+ line-height: 42px;
+
+ &:last-of-type {
+ border-right: none;
+ }
+
+ &.w-14 {
+ width: calc((100/7)/100 * 100%);
+ }
+
+ &.w-16 {
+ width: calc((100/6)/100 * 100%);
+ }
+
+ &.w-18 {
+ width: 16.59%;
+ }
+
+ &.w-20 {
+ width: 20%;
+ }
+
+ &.w-25 {
+ width: 25%;
+ }
+
+ &.w-50 {
+ width: 50%;
+ }
+
+ &.w-75 {
+ width: 75%;
+ }
+
+ .ant-input {
+ height: 100%;
+ border: none;
+ background: #f5f7fa;
+ }
+
+ .ant-picker {
+ width: 100%;
+ height: 100%;
+ }
+ }
+ }
+
+ .b-font {
+ font-size: 16px;
+ font-weight: bolder;
+ }
+}
+
+.m-color {
+ color: #0c4995;
+}
+:deep(.el-input__wrapper ){
+ box-shadow: none;
+}
+</style>
diff --git a/src/views/experiment/project/components/selectEquipment.vue b/src/views/experiment/project/components/selectEquipment.vue
new file mode 100644
index 0000000..c86e11f
--- /dev/null
+++ b/src/views/experiment/project/components/selectEquipment.vue
@@ -0,0 +1,208 @@
+<template>
+ <tr class="m-color b-font" style="text-align: center">实验所用的仪器/设备</tr>
+ <tr>
+ <td class="w-16 m-color">设备名称</td>
+ <td class="w-16 m-color">编号</td>
+ <td class="w-16 m-color">设备功率</td>
+ <td class="w-16 m-color">是否特种</td>
+ <td class="w-16 m-color">设备数量</td>
+ <td class="w-16 m-color">操作</td>
+ </tr>
+ <tr v-for="(item,index) in selectEquipmentState.equipmentList" :key="index">
+ <td class="w-16">
+ <el-select :disabled="selectEquipmentState.disabled" filterable v-model="item.deviceId" @change="giveOtherEquipmentValue($event, index)">
+ <el-option
+ v-for="item in selectEquipmentState.allEquipmentList"
+ :key="item.id"
+ :value="item.id"
+ :label="item.deviceName"
+ >
+ </el-option>
+ </el-select>
+ </td>
+ <td class="w-16">
+ <el-input :disabled="selectEquipmentState.disabled" v-model="item.deviceCode" placeholder="请输入数量" />
+ </td>
+ <td class="w-16">
+ <el-input :disabled="selectEquipmentState.disabled" v-model="item.devicePower" />
+ </td>
+ <td class="w-16">
+ <el-radio-group :disabled="selectEquipmentState.disabled" v-model="item.specialDevice">
+ <el-radio :label="1">是</el-radio>
+ <el-radio :label="2">否</el-radio>
+ </el-radio-group>
+ </td>
+ <td class="w-16">
+ <el-input type="number" v-model="item.deviceUseCount" />
+ </td>
+ <td class="w-16">
+ <el-button :disabled="selectEquipmentState.disabled" type="danger" @click="deleteEquipmentItem(index)">删除</el-button>
+ </td>
+ </tr>
+ <tr style="text-align: center">
+ <el-button :disabled="selectEquipmentState.disabled" type="primary" shape="round" @click="addEquipmentItem()">
+ 选择实验仪器
+ </el-button>
+ </tr>
+</template>
+
+<script setup lang="ts">
+import {onMounted, reactive, watchEffect} from "vue";
+import {ElMessage} from "element-plus";
+import { equipmentApi } from "/@/api/basic/equipement";
+
+let props = defineProps({
+ disabled: Boolean,
+ data: Array<AllEquipmentListType>
+});
+
+const selectEquipmentState = reactive<SelectEquipmentType>({
+ disabled: false,
+ equipmentList: [],
+ allEquipmentList: [],
+});
+
+watchEffect(() => {
+ selectEquipmentState.equipmentList = props.data as Array<AllEquipmentListType>
+ selectEquipmentState.disabled = props.disabled
+});
+
+const addEquipmentItem = () => {
+ selectEquipmentState.equipmentList.push({deviceId: null, deviceUseCount: null, deviceCode: '', deviceName: '', devicePower: '', specialDevice: '',});
+};
+
+const deleteEquipmentItem = (index: number) => {
+ selectEquipmentState.equipmentList.splice(index,1);
+};
+
+const getAllEquipmentList = async () => {
+ let res = await equipmentApi().getAllEquipment();
+ if(res.data.code === 100){
+ selectEquipmentState.allEquipmentList = JSON.parse(JSON.stringify(res.data.data));
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ })
+ }
+};
+
+const giveOtherEquipmentValue = (value: number, index:number) => {
+ const data = selectEquipmentState.allEquipmentList.find(item => item.id === value) as AllEquipmentListType
+ selectEquipmentState.equipmentList[index] = {
+ deviceId: data.id,
+ deviceUseCount: null,
+ deviceCode: data.deviceCode,
+ deviceName: data.deviceName,
+ devicePower: data.devicePower,
+ specialDevice: data.specialDevice
+ }
+};
+
+const formatList = (formatList: Array<AllEquipmentListType>) => {
+ selectEquipmentState.equipmentList = formatList
+}
+
+defineExpose({
+ dataList: selectEquipmentState.equipmentList,
+ formatList
+});
+
+onMounted(() => {
+ getAllEquipmentList();
+});
+</script>
+
+<style scoped lang="scss">
+.site-layout-background {
+ background: #fff;
+}
+
+.report-table {
+ width: 100%;
+ border-collapse: collapse;
+ border: 1px solid #337ecc;
+ margin: 20px 0;
+
+ th {
+ padding: 10px 0;
+ border: 1px solid #337ecc;
+ border-left: none;
+ }
+
+ tr {
+ width: 100%;
+ height: 44px;
+ line-height: 42px;
+ border-bottom: 1px solid #ccc;
+
+ &:last-of-type {
+ border-bottom: none;
+ }
+
+ td {
+ border-right: 1px solid #ccc;
+ display: inline-block;
+ height: 44px;
+ vertical-align: middle;
+ text-align: center;
+ line-height: 42px;
+
+ &:last-of-type {
+ border-right: none;
+ }
+
+ &.w-14 {
+ width: calc((100/7)/100 * 100%);
+ }
+
+ &.w-16 {
+ width: calc((100/6)/100 * 100%);
+ }
+
+ &.w-18 {
+ width: 16.59%;
+ }
+
+ &.w-20 {
+ width: 20%;
+ }
+
+ &.w-25 {
+ width: 25%;
+ }
+
+ &.w-50 {
+ width: 50%;
+ }
+
+ &.w-75 {
+ width: 75%;
+ }
+
+ .ant-input {
+ height: 100%;
+ border: none;
+ background: #f5f7fa;
+ }
+
+ .ant-picker {
+ width: 100%;
+ height: 100%;
+ }
+ }
+ }
+
+ .b-font {
+ font-size: 16px;
+ font-weight: bolder;
+ }
+}
+
+.m-color {
+ color: #0c4995;
+}
+:deep(.el-input__wrapper ){
+ box-shadow: none;
+}
+</style>
diff --git a/src/views/experiment/project/components/selectMaterial.vue b/src/views/experiment/project/components/selectMaterial.vue
new file mode 100644
index 0000000..bb29d5f
--- /dev/null
+++ b/src/views/experiment/project/components/selectMaterial.vue
@@ -0,0 +1,210 @@
+<template>
+ <tr class="m-color b-font" style="text-align: center">实验所用的试剂或材料</tr>
+ <tr>
+ <td class="w-14 m-color">实验材料</td>
+ <td class="w-14 m-color">耗材ID</td>
+ <td class="w-14 m-color">材料类型</td>
+ <td class="w-14 m-color">材料储存</td>
+ <td class="w-14 m-color">计量单位</td>
+ <td class="w-14 m-color">使用数量</td>
+ <td class="w-14 m-color">操作</td>
+ </tr>
+ <tr v-for="(item,index) in selectMaterialState.materialList" :key="index">
+ <td class="w-14">
+ <el-select :disabled="selectMaterialState.disabled" filterable v-model="item.stuffId" @change="giveOtherMaterialValue($event, index)">
+ <el-option
+ v-for="item in selectMaterialState.allMaterialList"
+ :key="item.id"
+ :value="item.id"
+ :label="item.stuffName"
+ >
+ </el-option>
+ </el-select>
+ </td>
+ <td class="w-14">
+ <el-input :disabled="selectMaterialState.disabled" v-model="item.stuffCode" />
+ </td>
+ <td class="w-14">
+ <el-input :disabled="selectMaterialState.disabled" v-model="item.stuffType" />
+ </td>
+ <td class="w-14">
+ <el-input :disabled="selectMaterialState.disabled" v-model="item.stuffStorage" />
+ </td>
+ <td class="w-14">
+ <el-input :disabled="selectMaterialState.disabled" v-model="item.stuffUnit" />
+ </td>
+ <td class="w-14">
+ <el-input type="number" v-model="item.stuffUseCount" />
+ </td>
+ <td class="w-14">
+ <el-button type="danger" :disabled="selectMaterialState.disabled" @click="deleteMaterialItem(index)">删除</el-button>
+ </td>
+ </tr>
+ <tr style="text-align: center">
+ <el-button :disabled="selectMaterialState.disabled" type="primary" shape="round" @click="addMaterialItem()">
+ 选择实验材料
+ </el-button>
+ </tr>
+</template>
+
+<script setup lang="ts">
+import {onMounted, reactive, watchEffect} from "vue";
+import { materialApi } from "/@/api/basic/material";
+import {ElMessage} from "element-plus";
+let props = defineProps({
+ disabled: Boolean,
+ data: Array<AllMaterialListType>
+});
+
+const selectMaterialState = reactive<SelectMaterialType>({
+ disabled: false,
+ materialList: [],
+ allMaterialList: [],
+})
+
+const addMaterialItem = () => {
+ selectMaterialState.materialList.push({stuffId: null, stuffUseCount: null, stuffName: '',stuffCode:'',stuffType: '', stuffStorage: '', stuffUnit: ''});
+};
+
+watchEffect(() => {
+ selectMaterialState.materialList = props.data as Array<AllMaterialListType>
+ selectMaterialState.disabled = props.disabled
+});
+
+const deleteMaterialItem = (index: number) => {
+ selectMaterialState.materialList.splice(index,1);
+};
+
+const getAllPersonList = async () => {
+ let res = await materialApi().getAllMaterial();
+ if(res.data.code === 100){
+ selectMaterialState.allMaterialList = JSON.parse(JSON.stringify(res.data.data));
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ })
+ }
+};
+
+const giveOtherMaterialValue = (value: number, index:number) => {
+ const data = selectMaterialState.allMaterialList.find(item => item.id === value) as AllMaterialListType
+ selectMaterialState.materialList[index] = {
+ stuffId: data.id,
+ stuffUseCount: data.stuffUseCount,
+ stuffName: data.stuffName,
+ stuffCode: data.stuffCode,
+ stuffType: data.stuffType,
+ stuffStorage: data.stuffStorage,
+ stuffUnit: data.stuffUnit
+ };
+};
+
+const formatList = (formatList: Array<AllMaterialListType>) => {
+ selectMaterialState.materialList = formatList
+};
+
+defineExpose({
+ dataList: selectMaterialState.materialList,
+ formatList
+});
+
+
+onMounted(() => {
+ getAllPersonList();
+});
+</script>
+
+<style scoped lang="scss">
+.site-layout-background {
+ background: #fff;
+}
+
+.report-table {
+ width: 100%;
+ border-collapse: collapse;
+ border: 1px solid #337ecc;
+ margin: 20px 0;
+
+ th {
+ padding: 10px 0;
+ border: 1px solid #337ecc;
+ border-left: none;
+ }
+
+ tr {
+ width: 100%;
+ height: 44px;
+ line-height: 42px;
+ border-bottom: 1px solid #ccc;
+
+ &:last-of-type {
+ border-bottom: none;
+ }
+
+ td {
+ border-right: 1px solid #ccc;
+ display: inline-block;
+ height: 44px;
+ vertical-align: middle;
+ text-align: center;
+ line-height: 42px;
+
+ &:last-of-type {
+ border-right: none;
+ }
+
+ &.w-14 {
+ width: calc((100/7)/100 * 100%);
+ }
+
+ &.w-16 {
+ width: calc((100/6)/100 * 100%);
+ }
+
+ &.w-18 {
+ width: 16.59%;
+ }
+
+ &.w-20 {
+ width: 20%;
+ }
+
+ &.w-25 {
+ width: 25%;
+ }
+
+ &.w-50 {
+ width: 50%;
+ }
+
+ &.w-75 {
+ width: 75%;
+ }
+
+ .ant-input {
+ height: 100%;
+ border: none;
+ background: #f5f7fa;
+ }
+
+ .ant-picker {
+ width: 100%;
+ height: 100%;
+ }
+ }
+ }
+
+ .b-font {
+ font-size: 16px;
+ font-weight: bolder;
+ }
+}
+
+.m-color {
+ color: #0c4995;
+}
+:deep(.el-input__wrapper ){
+ box-shadow: none;
+}
+</style>
diff --git a/src/views/experiment/project/components/selectPerson.vue b/src/views/experiment/project/components/selectPerson.vue
new file mode 100644
index 0000000..e0359b8
--- /dev/null
+++ b/src/views/experiment/project/components/selectPerson.vue
@@ -0,0 +1,218 @@
+<template>
+ <tr class="m-color b-font" style="text-align: center">实验人员</tr>
+ <tr>
+ <td class="w-14 m-color">姓名</td>
+ <td class="w-14 m-color">年龄</td>
+ <td class="w-14 m-color">性别</td>
+ <td class="w-14 m-color">专业</td>
+ <td class="w-14 m-color">部门</td>
+ <td class="w-14 m-color">相关资质</td>
+ <td class="w-14 m-color">操作</td>
+ </tr>
+ <tr v-for="(item,index) in selectPersonState.personList" :key="index">
+ <td class="w-14">
+ <el-select filterable :disabled="selectPersonState.disabled" v-model="item.personId" @change="giveOtherPersonValue($event, index)">
+ <el-option
+ v-for="item in selectPersonState.allPersonList"
+ :key="item.id"
+ :value="item.id"
+ :label="item.personName"
+ >
+ </el-option>
+ </el-select>
+ </td>
+ <td class="w-14">
+ <el-input :disabled="selectPersonState.disabled" v-model="item.personAge" />
+ </td>
+ <td class="w-14">
+ <el-input :disabled="selectPersonState.disabled" v-model="item.personGender" />
+ </td>
+ <td class="w-14">
+ <el-input :disabled="selectPersonState.disabled" v-model="item.personMajor" />
+ </td>
+ <td class="w-14">
+ <el-input :disabled="selectPersonState.disabled" v-model="item.depName" />
+ </td>
+ <td class="w-14">
+ <el-input :disabled="selectPersonState.disabled" v-model="item.aptitude" />
+ </td>
+ <td class="w-14">
+ <el-button type="danger" :disabled="selectPersonState.disabled" @click="deletePersonItem(index)">删除</el-button>
+ </td>
+ </tr>
+ <tr style="text-align: center">
+ <el-button :disabled="selectPersonState.disabled" type="primary" shape="round" @click="addPersonItem()">
+ 选择实验人员
+ </el-button>
+ </tr>
+</template>
+
+<script setup lang="ts">
+import {nextTick, onMounted, reactive, watchEffect} from "vue";
+import { personApi } from "/@/api/basic/person";
+import {ElMessage} from "element-plus";
+
+let props = defineProps({
+ disabled: Boolean,
+ data: Array<AllPersonListType>
+
+});
+
+const selectPersonState = reactive<SelectPersonType>({
+ disabled: false,
+ personList: [],
+ allPersonList: [
+ ],
+});
+
+watchEffect(() => {
+ selectPersonState.personList = props.data as Array<AllPersonListType>
+ selectPersonState.disabled = props.disabled
+});
+
+const addPersonItem = () => {
+ selectPersonState.personList.push({personId: null, personName: null, personAge: null, personGender:'',personMajor:'',depName:'',phone:'',aptitude:'',training:''});
+};
+
+const deletePersonItem = (index: number) => {
+ selectPersonState.personList.splice(index,1);
+};
+
+const getAllPersonList = async () => {
+ let res = await personApi().getAllPerson();
+ if(res.data.code === 100){
+ selectPersonState.allPersonList = JSON.parse(JSON.stringify(res.data.data));
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ })
+ }
+};
+
+const giveOtherPersonValue = (value: number, index:number) => {
+ // selectPersonState.personList[index] = selectPersonState.allPersonList.find(item => item.id === value) as AllPersonListType
+ const data = selectPersonState.allPersonList.find(item => item.id === value) as AllPersonListType
+ selectPersonState.personList[index] = {
+ personId: data.id,
+ personName: data.personName,
+ personAge: data.personAge,
+ personGender: data.personGender,
+ personMajor: data.personMajor,
+ depName: data.depName,
+ phone: data.phone,
+ aptitude: data.aptitude,
+ training: data.training,
+ };
+};
+
+const formatList = (formatList: Array<AllPersonListType>) => {
+ nextTick(() => {
+ selectPersonState.personList = formatList
+ })
+
+};
+
+defineExpose({
+ formatList,
+ dataList: selectPersonState.personList,
+});
+
+onMounted(() => {
+ getAllPersonList();
+});
+</script>
+
+<style scoped lang="scss">
+.site-layout-background {
+ background: #fff;
+}
+
+.report-table {
+ width: 100%;
+ border-collapse: collapse;
+ border: 1px solid #337ecc;
+ margin: 20px 0;
+
+ th {
+ padding: 10px 0;
+ border: 1px solid #337ecc;
+ border-left: none;
+ }
+
+ tr {
+ width: 100%;
+ height: 44px;
+ line-height: 42px;
+ border-bottom: 1px solid #ccc;
+
+ &:last-of-type {
+ border-bottom: none;
+ }
+
+ td {
+ border-right: 1px solid #ccc;
+ display: inline-block;
+ height: 44px;
+ vertical-align: middle;
+ text-align: center;
+ line-height: 42px;
+
+ &:last-of-type {
+ border-right: none;
+ }
+
+ &.w-14 {
+ width: calc((100/7)/100 * 100%);
+ }
+
+ &.w-16 {
+ width: calc((100/6)/100 * 100%);
+ }
+
+ &.w-18 {
+ width: 16.59%;
+ }
+
+ &.w-20 {
+ width: 20%;
+ }
+
+ &.w-25 {
+ width: 25%;
+ }
+
+ &.w-50 {
+ width: 50%;
+ }
+
+ &.w-75 {
+ width: 75%;
+ }
+
+ .ant-input {
+ height: 100%;
+ border: none;
+ background: #f5f7fa;
+ }
+
+ .ant-picker {
+ width: 100%;
+ height: 100%;
+ }
+ }
+ }
+
+ .b-font {
+ font-size: 16px;
+ font-weight: bolder;
+ }
+}
+
+.m-color {
+ color: #0c4995;
+}
+:deep(.el-input__wrapper ){
+ box-shadow: none;
+}
+</style>
diff --git a/src/views/experiment/project/index.ts b/src/views/experiment/project/index.ts
new file mode 100644
index 0000000..c06feb7
--- /dev/null
+++ b/src/views/experiment/project/index.ts
@@ -0,0 +1,150 @@
+declare interface ProjectStateType {
+ projectData: Array<ProjectType>
+ searchQuery: {
+ pageIndex: number,
+ pageSize: number,
+ searchParams: {
+ experimentName: string,
+ experimentType: null | number,
+ }
+ },
+ total: 0,
+ experimentTypeList: Type []
+ allRoomList: RoomType []
+}
+
+declare interface ProjectType {
+ id?: number | null,
+ experimentCode: string,
+}
+
+declare interface Type {
+ id: number,
+ name: string,
+}
+
+declare interface ProjectDialogType {
+ title: string,
+ disabled: boolean,
+ projectDialogVisible: boolean,
+ projectForm: {
+ id: null | number,
+ experimentName: string,
+ experimentType: null | number,
+ liabilityUserId: null | number,
+ safeLiabilityUserId: null | number,
+ dep: string,
+ siteId: null | number,
+ experimentStep: string,
+ experimentMethod: string,
+ process: string,
+ keyProcess: string,
+ timeout: null | number,
+ timeoutManager: string,
+ closed: null | number,
+ unclosedManager: string,
+ explosionProof: string,
+ fireProof: string,
+ poisonProof: string,
+ hazardousWaste: null | number,
+ safeManagerMethod: string,
+ emergencyPlan: string,
+ emergencyDrill: string,
+ emergencyPlanName: string,
+ emergencyDrillStatus: string,
+ partitionCondition: string,
+ note: string,
+ expectStartTime: null | number,
+ persons: SelectPersonType [],
+ deviceList: SelectEquipmentType [],
+ stuffList: SelectMaterialType [],
+ hazardousWasteList: SelectDangerType []
+ },
+ projectFormRules: {
+
+ },
+ allPersonList: Array<AllPersonListType>
+ allRoomList: Array<RoomType>
+}
+
+declare interface SelectDangerType {
+ disabled: boolean
+ wasteList: Array<WasteType>
+ classifyList: Array<Type>
+ wasteStorageList: Array<Type>
+}
+
+declare interface WasteType {
+ classify: null | number,
+ wasteStorage: null | number,
+ handAmount: null | number,
+}
+
+
+declare interface SelectPersonType {
+ disabled: boolean
+ personList: Array<AllPersonListType>
+ allPersonList: Array<AllPersonListType>
+}
+
+declare interface AllPersonListType {
+ id: null | number,
+ personId?: null | number,
+ personName: null,
+ personAge: null,
+ personGender:'',
+ personMajor:'',
+ depName:'',
+ phone:'',
+ aptitude:'',
+ training:''
+}
+
+declare interface SelectEquipmentType {
+ disabled: boolean
+ equipmentList: Array<AllEquipmentListType>,
+ allEquipmentList: Array<AllEquipmentListType>,
+}
+
+declare interface AllEquipmentListType {
+ id?: null | number,
+ deviceId?: null | number,
+ deviceUseCount: null | number,
+ deviceCode: string,
+ deviceName: string,
+ devicePower: string,
+ specialDevice: string,
+}
+
+
+declare interface SelectMaterialType {
+ disabled: boolean
+ materialList: Array<AllMaterialListType>,
+ allMaterialList: Array<AllMaterialListType>,
+}
+
+declare interface AllMaterialListType {
+ id?: null | number,
+ stuffId?: null | number,
+ stuffUseCount: null | number,
+ stuffName: string,
+ stuffCode:string,
+ stuffType: string,
+ stuffStorage: string,
+ stuffUnit: string
+}
+
+
+declare interface ApplyStartDialogType {
+ title: string,
+ applyStartDialogVisible: boolean,
+ applyStartForm: {
+ id: number | null,
+ sisStatus: number | null,
+ safeInformationSystem: string,
+ startTime: string,
+ },
+ applyStartFormRules: {
+
+ },
+}
diff --git a/src/views/experiment/project/index.vue b/src/views/experiment/project/index.vue
new file mode 100644
index 0000000..9c6c50c
--- /dev/null
+++ b/src/views/experiment/project/index.vue
@@ -0,0 +1,324 @@
+<template>
+ <div class="home-container">
+ <div style="height: 100%">
+ <el-row class="homeCard">
+ <div class="basic-line">
+ <span>实验名称:</span>
+ <el-input v-model="projectState.searchQuery.searchParams.experimentName" clearable filterable class="input-box" placeholder="实验名称">
+ </el-input>
+ </div>
+ <div class="basic-line">
+ <span>实验类型:</span>
+ <el-select v-model="projectState.searchQuery.searchParams.experimentType" clearable filterable class="input-box" placeholder="实验类型">
+ <el-option v-for="item in projectState.experimentTypeList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+ </el-select>
+ </div>
+ <div style="padding-bottom: 10px">
+ <el-button type="primary" @click="getProjectData">查询</el-button>
+ <el-button plain @click="reset">重置</el-button>
+ </div>
+ </el-row>
+ <div class="homeCard">
+ <div class="main-card">
+ <el-row class="cardTop">
+ <el-col :span="12" class="mainCardBtn">
+ <el-button type="primary" :icon="Plus" size="default" @click="openProjectDialog('新增', {})">新增</el-button>
+ <!-- <el-button type="danger" :icon="Delete" size="default" plain>删除</el-button>-->
+ </el-col>
+<!-- <el-button type="primary" :icon="Refresh" size="default" />-->
+ </el-row>
+ <el-table ref="multipleTableRef" :data="projectState.projectData" style="width: 100%" height="calc(100% - 100px)" :header-cell-style="{ background: '#fafafa' }">
+ <el-table-column prop="experimentCode" label="实验编号"/>
+ <el-table-column prop="expectStartTime" label="立项时间" />
+ <el-table-column prop="liabilityUser" label="负责人"/>
+ <el-table-column prop="createTime" label="创建时间" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="createByUserName" label="创建人" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="updateTime" label="最后修改时间" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="updateByUserName" label="最后修改人" show-overflow-tooltip></el-table-column>
+ <el-table-column label="操作" width="250">
+ <template #default="scope">
+ <el-button size="small" text type="primary" :icon="View" @click="openProjectDialog('查看', scope.row)">查看</el-button>
+ <el-button size="small" text type="primary" :icon="Edit" @click="applyStart('申请开展', scope.row)">申请开展</el-button>
+ <el-button size="small" text type="danger" :icon="Delete" @click="onDelProject(scope.row)">删除</el-button> </template>
+ </el-table-column>
+ </el-table>
+ <div class="pageBtn">
+ <el-pagination @size-change="onHandleSizeChange" @current-change="onHandleCurrentChange" :pager-count="5" :page-sizes="[10, 20, 30]" v-model:current-page="projectState.searchQuery.pageIndex" background v-model:page-size="projectState.searchQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="projectState.total" class="page-position"> </el-pagination>
+ </div>
+ </div>
+ </div>
+ </div>
+ <project-dialog ref="ProjectDialogRef" @refresh="getProjectData"></project-dialog>
+<!-- <apply-start ref="ApplyStartRef"></apply-start>-->
+ <test ref="ApplyStartRef" @refresh="getProjectData"></test>
+ </div>
+</template>
+
+<script setup lang="ts">
+import {defineAsyncComponent, onMounted, reactive, ref} from "vue";
+import {projectApi} from "/@/api/experiment/project";
+import {ElMessage, ElMessageBox} from "element-plus";
+import { View,Edit, Plus, Delete } from '@element-plus/icons-vue';
+import {roomApi} from "/@/api/basic/room";
+
+const ProjectDialog = defineAsyncComponent(() => import('./components/projectDialog.vue'));
+const Test = defineAsyncComponent(() => import('./components/applyDialog.vue'))
+
+const ProjectDialogRef = ref();
+const ApplyStartRef = ref();
+
+const projectState = reactive<ProjectStateType>({
+ projectData: [],
+ searchQuery: {
+ pageIndex: 1,
+ pageSize: 10,
+ searchParams: {
+ experimentName: '',
+ experimentType: null,
+ }
+ },
+ total: 0,
+ experimentTypeList: [
+ {id: 1, name: '化学类'},
+ {id: 2, name: '生物类'},
+ {id: 3, name: '辐射类'},
+ {id: 4, name: '机电类'},
+ {id: 5, name: '特种设备类'},
+ {id: 6, name: '其它类'},
+ ],
+ allRoomList: []
+})
+
+const getProjectData = async () => {
+ let res = await projectApi().getProjectByList(projectState.searchQuery);
+ if(res.data.code === 100){
+ projectState.projectData = res.data.data;
+ projectState.total = res.data.total;
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ });
+ }
+};
+
+const openProjectDialog = (title: string, value: ProjectType) => {
+ ProjectDialogRef.value.showProjectDialog(title, value, projectState.allRoomList);
+};
+
+const applyStart = (title: string, value: ProjectType) => {
+ ApplyStartRef.value.showApplyStartDialog(value);
+};
+
+const onDelProject = (val: ProjectType) => {
+ ElMessageBox.confirm(`此操作将永久删除该实验:“${val.experimentCode}”,是否继续?`, '提示', {
+ confirmButtonText: '确认',
+ cancelButtonText: '取消',
+ type: 'warning'
+ })
+ .then(async () => {
+ debugger
+ let res = await projectApi().deleteProjectById({ id: val.id });
+ if (res.data.code === 100) {
+ ElMessage({
+ type: 'success',
+ duration: 2000,
+ message: '删除成功'
+ });
+ await getProjectData();
+ } else {
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ });
+ }
+ })
+ .catch((error) => {
+ });
+}
+
+const onHandleSizeChange = (val: number) => {
+ projectState.searchQuery.pageSize = val;
+ getProjectData();
+};
+
+const onHandleCurrentChange = (val: number) => {
+ projectState.searchQuery.pageIndex = val;
+ getProjectData();
+};
+
+const reset = () => {
+ projectState.searchQuery = {
+ pageIndex: 1,
+ pageSize: 10,
+ searchParams: {
+ experimentName: '',
+ experimentType: null,
+ }
+ }
+};
+
+const getRoomData = async () => {
+ let res = await roomApi().getAllRoom();
+ if(res.data.code === 100){
+ projectState.allRoomList = JSON.parse(JSON.stringify(res.data.data));
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ });
+ }
+};
+
+onMounted(() => {
+ getProjectData();
+ getRoomData();
+})
+
+</script>
+
+<style scoped lang="scss">
+$homeNavLengh: 8;
+.home-container {
+ height: calc(100vh - 144px);
+ box-sizing: border-box;
+ overflow: hidden;
+ .homeCard {
+ width: 100%;
+ padding: 20px;
+ box-sizing: border-box;
+ background: #fff;
+ border-radius: 4px;
+
+ .main-card {
+ width: 100%;
+ height: 100%;
+ .cardTop {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 20px;
+ .mainCardBtn {
+ margin: 0;
+ }
+ }
+ .pageBtn {
+ height: 60px;
+ display: flex;
+ align-items: center;
+ justify-content: right;
+
+ .demo-pagination-block + .demo-pagination-block {
+ margin-top: 10px;
+ }
+ .demo-pagination-block .demonstration {
+ margin-bottom: 16px;
+ }
+ }
+ }
+ &:last-of-type {
+ height: calc(100% - 100px);
+ }
+ }
+ .el-row {
+ display: flex;
+ align-items: center;
+ margin-bottom: 20px;
+ &:last-child {
+ margin-bottom: 0;
+ }
+ .grid-content {
+ align-items: center;
+ min-height: 36px;
+ }
+
+ .topInfo {
+ display: flex;
+ align-items: center;
+ font-size: 16px;
+ font-weight: bold;
+
+ & > div {
+ white-space: nowrap;
+ margin-right: 20px;
+ }
+ }
+ }
+}
+.stepItem {
+ width: 100%;
+ display: flex;
+ align-items: flex-start;
+ margin-bottom: 30px;
+ margin-left: 30px;
+ padding-bottom: 30px;
+ border-left: 2px solid #ccc;
+ &:first-of-type {
+ margin-top: 30px;
+ }
+ &:last-of-type {
+ margin-bottom: 0;
+ border-left: none;
+ }
+ .stepNum {
+ width: 30px;
+ height: 30px;
+ border-radius: 15px;
+ box-sizing: border-box;
+ color: #333;
+ border: 1px solid #999;
+ line-height: 28px;
+ text-align: center;
+ margin-right: 10px;
+ margin-left: -16px;
+ margin-top: -30px;
+ }
+ .stepCard {
+ width: 100%;
+ margin-top: -30px;
+
+ .box-card {
+ width: 100%;
+ &:deep(.el-card__header) {
+ padding: 10px 15px;
+ }
+ .card-header {
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ & > div:first-of-type {
+ margin-right: 80px;
+ font-size: 18px;
+ font-weight: bold;
+ }
+ }
+ }
+ }
+ &:hover .card-header {
+ color: #0098f5;
+ }
+ &:hover .stepNum {
+ border: 2px solid #0098f5;
+ color: #0098f5;
+ }
+}
+
+:deep(.el-date-editor) {
+ width: 100%;
+}
+.el-select {
+ width: 100%;
+}
+:deep(.el-textarea.is-disabled .el-textarea__inner) {
+ background-color: var(--el-card-bg-color);
+ color: var(--el-input-text-color, var(--el-text-color-regular));
+}
+:deep(.el-input.is-disabled .el-input__inner) {
+ color: var(--el-input-text-color, var(--el-text-color-regular));
+}
+:deep(.el-input.is-disabled .el-input__wrapper) {
+ background-color: var(--el-card-bg-color);
+ box-shadow: none;
+}
+</style>
diff --git a/src/views/home/dialog.vue b/src/views/home/dialog.vue
new file mode 100644
index 0000000..b1da6ca
--- /dev/null
+++ b/src/views/home/dialog.vue
@@ -0,0 +1,272 @@
+<template>
+ <div class="system-menu-dialog-container">
+ <el-dialog :title="state.dialog.title" v-model="state.dialog.isShowDialog" width="769px">
+ <el-form ref="menuDialogFormRef" :model="state.ruleForm" size="default" label-width="80px">
+ <el-row :gutter="35">
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="上级菜单">
+ <el-cascader
+ :options="state.menuData"
+ :props="{ emitPath: false, checkStrictly: true, value: 'id', label: 'title' }"
+ placeholder="请选择上级菜单"
+ clearable
+ class="w100"
+ @change="test"
+ v-model="state.ruleForm.parentId">
+ </el-cascader>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+ <el-form-item label="菜单名称">
+ <el-input v-model="state.ruleForm.meta.title" placeholder="格式:message.router.xxx" clearable></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+ <el-form-item label="路由名称">
+ <el-input v-model="state.ruleForm.name" placeholder="路由中的 name 值" clearable></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+ <el-form-item label="路由路径">
+ <el-input v-model="state.ruleForm.path" placeholder="路由中的 path 值" clearable></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+ <el-form-item label="重定向">
+ <el-input v-model="state.ruleForm.redirect" placeholder="请输入路由重定向" clearable></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+ <el-form-item label="菜单图标">
+ <IconSelector placeholder="请输入菜单图标" v-model="state.ruleForm.meta.icon" />
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+ <el-form-item label="组件路径">
+ <el-input v-model="state.ruleForm.component" placeholder="组件路径" clearable></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+ <el-form-item label="链接地址">
+ <el-input
+ v-model="state.ruleForm.meta.isLink"
+ placeholder="外链/内嵌时链接地址(http:xxx.com)"
+ clearable
+ >
+ </el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+ <el-form-item label="权限标识">
+ <el-select v-model="state.ruleForm.meta.roles" multiple placeholder="取角色管理" clearable class="w100">
+ <el-option v-for="item in state.roleList" :key="item.id" :value="item.id" :label="item.name"></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+ <el-form-item label="菜单排序">
+ <el-input-number v-model="state.ruleForm.priority" controls-position="right" placeholder="请输入排序" class="w100" />
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+ <el-form-item label="是否隐藏">
+ <el-radio-group v-model="state.ruleForm.meta.isHide">
+ <el-radio :label="true">隐藏</el-radio>
+ <el-radio :label="false">不隐藏</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <template #footer>
+ <span class="dialog-footer">
+ <el-button @click="onCancel" size="default">取 消</el-button>
+ <el-button type="primary" @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
+ </span>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup lang="ts" name="systemMenuDialog">
+import { defineAsyncComponent, reactive, onMounted, ref } from 'vue';
+import { storeToRefs } from 'pinia';
+import { useRoutesList } from '/@/stores/routesList';
+import { i18n } from '/@/i18n/index';
+import {ElMessage} from "element-plus";
+import { useMenuApi } from "/@/api/systemManage/menu";
+import {useRoleApi} from "/@/api/systemManage/role";
+// import { setBackEndControlRefreshRoutes } from "/@/router/backEnd";
+
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['refresh']);
+
+// 引入组件
+const IconSelector = defineAsyncComponent(() => import('/@/components/iconSelector/index.vue'));
+
+// 定义变量内容
+const menuDialogFormRef = ref();
+const stores = useRoutesList();
+const { routesList } = storeToRefs(stores);
+const state = reactive({
+ roleList:[],
+ // 参数请参考 `/src/router/route.ts` 中的 `dynamicRoutes` 路由菜单格式
+ ruleForm: {
+ id: null,
+ parentId: null,
+ description: '',
+ name: '',
+ component: '',
+ priority: 0,
+ path: '',
+ redirect: '',
+ publicable: null,
+ meta: {
+ title: '',
+ icon: '',
+ isHide: false,
+ isKeepAlive: true,
+ isAffix: false,
+ isLink: '',
+ isIframe: false,
+ roles: '',
+ },
+ },
+ menuData: [] as RouteItems [], // 上级菜单数据
+ dialog: {
+ isShowDialog: false,
+ type: '',
+ title: '',
+ submitTxt: '',
+ },
+});
+
+const test = () => {
+ console.log(state.menuData)
+}
+
+// 获取 pinia 中的路由
+const getMenuData = (routes: RouteItems) => {
+ const arr: RouteItems = [];
+ routes.map((val: RouteItem) => {
+ val['title'] = i18n.global.t(val.meta?.title as string);
+ arr.push({ ...val });
+ if (val.children) getMenuData(val.children);
+ });
+ return arr;
+};
+// 打开弹窗
+const openDialog = (type: string, row?: any) => {
+ if (type === 'edit') {
+ for(let i in state.ruleForm){
+ state.ruleForm[i] = row[i]
+ }
+ state.dialog.title = '修改菜单';
+ state.dialog.submitTxt = '修 改';
+ } else {
+ state.dialog.title = '新增菜单';
+ state.dialog.submitTxt = '新 增';
+ state.ruleForm = {
+ id: null,
+ parentId: null,
+ description: '',
+ name: '',
+ component: '',
+ priority: 0,
+ path: '',
+ redirect: '',
+ publicable: null,
+ meta: {
+ title: '',
+ icon: '',
+ isHide: false,
+ isKeepAlive: true,
+ isAffix: false,
+ isLink: '',
+ isIframe: false,
+ roles: '',
+ },
+ }
+ // 清空表单,此项需加表单验证才能使用
+ // nextTick(() => {
+ // menuDialogFormRef.value.resetFields();
+ // });
+ }
+ state.dialog.type = type;
+ state.dialog.isShowDialog = true;
+};
+// 关闭弹窗
+const closeDialog = () => {
+ state.dialog.isShowDialog = false;
+};
+
+// 取消
+const onCancel = () => {
+ closeDialog();
+};
+// 提交
+const onSubmit = () => {
+ menuDialogFormRef.value.validate(async (valid: boolean) => {
+ if(valid){
+ if(state.dialog.title === '新增菜单'){
+ let res = await useMenuApi().addMenu(state.ruleForm)
+ if(res.data.code === 100){
+ emit('refresh')
+ state.dialog.isShowDialog = false;
+ ElMessage({
+ type: 'success',
+ message: '新增成功'
+ })
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg,
+ });
+ }
+ }else{
+ let res = await useMenuApi().modMenu(state.ruleForm)
+ if(res.data.code === 100){
+ emit('refresh')
+ state.dialog.isShowDialog = false;
+ ElMessage({
+ type: 'success',
+ message: '编辑成功'
+ })
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg,
+ });
+ }
+ }
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: '请完善基本信息',
+ });
+ }
+ })
+};
+
+const getRoles = async () => {
+ let res = await useRoleApi().getRoleList()
+ if(res.data.code === 100){
+ state.roleList = res.data.data
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.message
+ })
+ }
+}
+// 页面加载时
+onMounted(() => {
+ state.menuData = getMenuData(routesList.value);
+ getRoles()
+});
+
+// 暴露变量
+defineExpose({
+ openDialog,
+});
+</script>
diff --git a/src/views/home/index.ts b/src/views/home/index.ts
new file mode 100644
index 0000000..9742bbb
--- /dev/null
+++ b/src/views/home/index.ts
@@ -0,0 +1,3 @@
+interface EquipmentStateType {
+
+}
diff --git a/src/views/home/index.vue b/src/views/home/index.vue
index 0771f90..91d40aa 100644
--- a/src/views/home/index.vue
+++ b/src/views/home/index.vue
@@ -1,15 +1,144 @@
<template>
-<div>
- 123
-</div>
+ <div class="system-menu-container layout-pd">
+ <el-card shadow="hover">
+ <div class="system-menu-search mb15">
+ <el-input size="default" placeholder="请输入菜单名称" style="max-width: 180px"> </el-input>
+ <el-button size="default" type="primary" class="ml10">
+ <el-icon>
+ <ele-Search />
+ </el-icon>
+ 查询
+ </el-button>
+ <el-button size="default" type="success" class="ml10" @click="onOpenAddMenu">
+ <el-icon>
+ <ele-FolderAdd />
+ </el-icon>
+ 新增菜单
+ </el-button>
+ </div>
+ <el-table
+ :data="state.tableData.data"
+ v-loading="state.tableData.loading"
+ style="width: 100%"
+ row-key="path"
+ :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
+ >
+ <el-table-column label="菜单名称" show-overflow-tooltip>
+ <template #default="scope">
+ <SvgIcon :name="scope.row.meta.icon" />
+ <span class="ml10">{{ $t(scope.row.meta.title) }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="path" label="路由路径" show-overflow-tooltip></el-table-column>
+ <el-table-column label="组件路径" show-overflow-tooltip>
+ <template #default="scope">
+ <span>{{ scope.row.component }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="权限标识" show-overflow-tooltip>
+ <template #default="scope">
+ <span>{{ scope.row.meta.roles }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="排序" show-overflow-tooltip width="80">
+ <template #default="scope">
+ {{ scope.$index }}
+ </template>
+ </el-table-column>
+ <el-table-column label="类型" show-overflow-tooltip width="80">
+ <template #default="scope">
+ <el-tag type="success" size="small">{{ scope.row.xx }}菜单</el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column label="操作" show-overflow-tooltip width="140">
+ <template #default="scope">
+ <el-button size="small" text type="primary" @click="onOpenAddMenu('add')">新增</el-button>
+ <el-button size="small" text type="primary" @click="onOpenEditMenu('edit', scope.row)">修改</el-button>
+ <el-button size="small" text type="primary" @click="onTabelRowDel(scope.row)">删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ </el-card>
+ <MenuDialog ref="menuDialogRef" @refresh="getTableData()" />
+ </div>
</template>
-<script>
-export default {
- name: "index"
+<script setup lang="ts" name="systemMenu">
+import { defineAsyncComponent, ref, onMounted, reactive } from 'vue';
+import { RouteRecordRaw } from 'vue-router';
+import { ElMessageBox, ElMessage } from 'element-plus';
+import { storeToRefs } from 'pinia';
+import { useRoutesList } from '/@/stores/routesList';
+import { useMenuApi } from "/@/api/systemManage/menu";
+import { initBackEndControlRoutes } from "/@/router/backEnd";
+import {roomApi} from "/@/api/basic/room";
+// import { setBackEndControlRefreshRoutes } from "/@/router/backEnd";
+
+// 引入组件
+const MenuDialog = defineAsyncComponent(() => import('/@/views/home/dialog.vue'));
+
+// 定义变量内容
+const stores = useRoutesList();
+const { routesList } = storeToRefs(stores);
+const menuDialogRef = ref();
+const state = reactive({
+ tableData: {
+ data: [] as RouteRecordRaw[],
+ loading: false,
+ },
+});
+
+// 获取路由数据,真实请从接口获取
+const getTableData = async () => {
+ let res = await useMenuApi().getMenuAdmin();
+ if (res.data.code === 100) {
+ state.tableData.data = res.data.data;
+ await initBackEndControlRoutes()
+ } else {
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ });
+ }
+};
+// 打开新增菜单弹窗
+const onOpenAddMenu = (type: string) => {
+ menuDialogRef.value.openDialog(type);
+};
+// 打开编辑菜单弹窗
+const onOpenEditMenu = (type: string, row: RouteRecordRaw) => {
+ menuDialogRef.value.openDialog(type, row);
+};
+// 删除当前行
+const onTabelRowDel = (row: RouteRecordRaw) => {
+ ElMessageBox.confirm(`此操作将永久删除该菜单,是否继续?`, '提示', {
+ confirmButtonText: '确认',
+ cancelButtonText: '取消',
+ type: 'warning'
+ })
+ .then(async () => {
+ let res = await useMenuApi().deleteMenu(row.id );
+ if (res.data.code === 100) {
+ ElMessage({
+ type: 'success',
+ duration: 2000,
+ message: '删除成功'
+ });
+ await getTableData();
+ } else {
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ });
+ }
+ })
+ .catch((error) => {
+
+ });
}
+
+// 页面加载时
+onMounted(() => {
+ getTableData();
+});
</script>
-
-<style scoped>
-
-</style>
diff --git a/src/views/loginPage/component/accountLogin.vue b/src/views/loginPage/component/accountLogin.vue
index 96d52e9..7726cac 100644
--- a/src/views/loginPage/component/accountLogin.vue
+++ b/src/views/loginPage/component/accountLogin.vue
@@ -233,7 +233,7 @@
// 登录成功,跳到转首页
// 如果是复制粘贴的路径,非首页/登录页,那么登录成功后重定向到对应的路径中
// if (route.json.query?.redirect) {
- router.push('/newHome');
+ router.push('/home');
// router.push({
// path: <string>route.json.query?.redirect,
// query: Object.keys(<string>route.json.query?.params).length > 0 ? JSON.parse(<string>route.json.query?.params) : '',
diff --git a/src/views/system/home/dialog.vue b/src/views/system/home/dialog.vue
new file mode 100644
index 0000000..b1da6ca
--- /dev/null
+++ b/src/views/system/home/dialog.vue
@@ -0,0 +1,272 @@
+<template>
+ <div class="system-menu-dialog-container">
+ <el-dialog :title="state.dialog.title" v-model="state.dialog.isShowDialog" width="769px">
+ <el-form ref="menuDialogFormRef" :model="state.ruleForm" size="default" label-width="80px">
+ <el-row :gutter="35">
+ <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+ <el-form-item label="上级菜单">
+ <el-cascader
+ :options="state.menuData"
+ :props="{ emitPath: false, checkStrictly: true, value: 'id', label: 'title' }"
+ placeholder="请选择上级菜单"
+ clearable
+ class="w100"
+ @change="test"
+ v-model="state.ruleForm.parentId">
+ </el-cascader>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+ <el-form-item label="菜单名称">
+ <el-input v-model="state.ruleForm.meta.title" placeholder="格式:message.router.xxx" clearable></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+ <el-form-item label="路由名称">
+ <el-input v-model="state.ruleForm.name" placeholder="路由中的 name 值" clearable></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+ <el-form-item label="路由路径">
+ <el-input v-model="state.ruleForm.path" placeholder="路由中的 path 值" clearable></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+ <el-form-item label="重定向">
+ <el-input v-model="state.ruleForm.redirect" placeholder="请输入路由重定向" clearable></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+ <el-form-item label="菜单图标">
+ <IconSelector placeholder="请输入菜单图标" v-model="state.ruleForm.meta.icon" />
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+ <el-form-item label="组件路径">
+ <el-input v-model="state.ruleForm.component" placeholder="组件路径" clearable></el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+ <el-form-item label="链接地址">
+ <el-input
+ v-model="state.ruleForm.meta.isLink"
+ placeholder="外链/内嵌时链接地址(http:xxx.com)"
+ clearable
+ >
+ </el-input>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+ <el-form-item label="权限标识">
+ <el-select v-model="state.ruleForm.meta.roles" multiple placeholder="取角色管理" clearable class="w100">
+ <el-option v-for="item in state.roleList" :key="item.id" :value="item.id" :label="item.name"></el-option>
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+ <el-form-item label="菜单排序">
+ <el-input-number v-model="state.ruleForm.priority" controls-position="right" placeholder="请输入排序" class="w100" />
+ </el-form-item>
+ </el-col>
+ <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+ <el-form-item label="是否隐藏">
+ <el-radio-group v-model="state.ruleForm.meta.isHide">
+ <el-radio :label="true">隐藏</el-radio>
+ <el-radio :label="false">不隐藏</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <template #footer>
+ <span class="dialog-footer">
+ <el-button @click="onCancel" size="default">取 消</el-button>
+ <el-button type="primary" @click="onSubmit" size="default">{{ state.dialog.submitTxt }}</el-button>
+ </span>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup lang="ts" name="systemMenuDialog">
+import { defineAsyncComponent, reactive, onMounted, ref } from 'vue';
+import { storeToRefs } from 'pinia';
+import { useRoutesList } from '/@/stores/routesList';
+import { i18n } from '/@/i18n/index';
+import {ElMessage} from "element-plus";
+import { useMenuApi } from "/@/api/systemManage/menu";
+import {useRoleApi} from "/@/api/systemManage/role";
+// import { setBackEndControlRefreshRoutes } from "/@/router/backEnd";
+
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['refresh']);
+
+// 引入组件
+const IconSelector = defineAsyncComponent(() => import('/@/components/iconSelector/index.vue'));
+
+// 定义变量内容
+const menuDialogFormRef = ref();
+const stores = useRoutesList();
+const { routesList } = storeToRefs(stores);
+const state = reactive({
+ roleList:[],
+ // 参数请参考 `/src/router/route.ts` 中的 `dynamicRoutes` 路由菜单格式
+ ruleForm: {
+ id: null,
+ parentId: null,
+ description: '',
+ name: '',
+ component: '',
+ priority: 0,
+ path: '',
+ redirect: '',
+ publicable: null,
+ meta: {
+ title: '',
+ icon: '',
+ isHide: false,
+ isKeepAlive: true,
+ isAffix: false,
+ isLink: '',
+ isIframe: false,
+ roles: '',
+ },
+ },
+ menuData: [] as RouteItems [], // 上级菜单数据
+ dialog: {
+ isShowDialog: false,
+ type: '',
+ title: '',
+ submitTxt: '',
+ },
+});
+
+const test = () => {
+ console.log(state.menuData)
+}
+
+// 获取 pinia 中的路由
+const getMenuData = (routes: RouteItems) => {
+ const arr: RouteItems = [];
+ routes.map((val: RouteItem) => {
+ val['title'] = i18n.global.t(val.meta?.title as string);
+ arr.push({ ...val });
+ if (val.children) getMenuData(val.children);
+ });
+ return arr;
+};
+// 打开弹窗
+const openDialog = (type: string, row?: any) => {
+ if (type === 'edit') {
+ for(let i in state.ruleForm){
+ state.ruleForm[i] = row[i]
+ }
+ state.dialog.title = '修改菜单';
+ state.dialog.submitTxt = '修 改';
+ } else {
+ state.dialog.title = '新增菜单';
+ state.dialog.submitTxt = '新 增';
+ state.ruleForm = {
+ id: null,
+ parentId: null,
+ description: '',
+ name: '',
+ component: '',
+ priority: 0,
+ path: '',
+ redirect: '',
+ publicable: null,
+ meta: {
+ title: '',
+ icon: '',
+ isHide: false,
+ isKeepAlive: true,
+ isAffix: false,
+ isLink: '',
+ isIframe: false,
+ roles: '',
+ },
+ }
+ // 清空表单,此项需加表单验证才能使用
+ // nextTick(() => {
+ // menuDialogFormRef.value.resetFields();
+ // });
+ }
+ state.dialog.type = type;
+ state.dialog.isShowDialog = true;
+};
+// 关闭弹窗
+const closeDialog = () => {
+ state.dialog.isShowDialog = false;
+};
+
+// 取消
+const onCancel = () => {
+ closeDialog();
+};
+// 提交
+const onSubmit = () => {
+ menuDialogFormRef.value.validate(async (valid: boolean) => {
+ if(valid){
+ if(state.dialog.title === '新增菜单'){
+ let res = await useMenuApi().addMenu(state.ruleForm)
+ if(res.data.code === 100){
+ emit('refresh')
+ state.dialog.isShowDialog = false;
+ ElMessage({
+ type: 'success',
+ message: '新增成功'
+ })
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg,
+ });
+ }
+ }else{
+ let res = await useMenuApi().modMenu(state.ruleForm)
+ if(res.data.code === 100){
+ emit('refresh')
+ state.dialog.isShowDialog = false;
+ ElMessage({
+ type: 'success',
+ message: '编辑成功'
+ })
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg,
+ });
+ }
+ }
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: '请完善基本信息',
+ });
+ }
+ })
+};
+
+const getRoles = async () => {
+ let res = await useRoleApi().getRoleList()
+ if(res.data.code === 100){
+ state.roleList = res.data.data
+ }else{
+ ElMessage({
+ type: 'warning',
+ message: res.data.message
+ })
+ }
+}
+// 页面加载时
+onMounted(() => {
+ state.menuData = getMenuData(routesList.value);
+ getRoles()
+});
+
+// 暴露变量
+defineExpose({
+ openDialog,
+});
+</script>
diff --git a/src/views/system/home/index.ts b/src/views/system/home/index.ts
new file mode 100644
index 0000000..9742bbb
--- /dev/null
+++ b/src/views/system/home/index.ts
@@ -0,0 +1,3 @@
+interface EquipmentStateType {
+
+}
diff --git a/src/views/system/home/index.vue b/src/views/system/home/index.vue
new file mode 100644
index 0000000..91d40aa
--- /dev/null
+++ b/src/views/system/home/index.vue
@@ -0,0 +1,144 @@
+<template>
+ <div class="system-menu-container layout-pd">
+ <el-card shadow="hover">
+ <div class="system-menu-search mb15">
+ <el-input size="default" placeholder="请输入菜单名称" style="max-width: 180px"> </el-input>
+ <el-button size="default" type="primary" class="ml10">
+ <el-icon>
+ <ele-Search />
+ </el-icon>
+ 查询
+ </el-button>
+ <el-button size="default" type="success" class="ml10" @click="onOpenAddMenu">
+ <el-icon>
+ <ele-FolderAdd />
+ </el-icon>
+ 新增菜单
+ </el-button>
+ </div>
+ <el-table
+ :data="state.tableData.data"
+ v-loading="state.tableData.loading"
+ style="width: 100%"
+ row-key="path"
+ :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
+ >
+ <el-table-column label="菜单名称" show-overflow-tooltip>
+ <template #default="scope">
+ <SvgIcon :name="scope.row.meta.icon" />
+ <span class="ml10">{{ $t(scope.row.meta.title) }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="path" label="路由路径" show-overflow-tooltip></el-table-column>
+ <el-table-column label="组件路径" show-overflow-tooltip>
+ <template #default="scope">
+ <span>{{ scope.row.component }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="权限标识" show-overflow-tooltip>
+ <template #default="scope">
+ <span>{{ scope.row.meta.roles }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="排序" show-overflow-tooltip width="80">
+ <template #default="scope">
+ {{ scope.$index }}
+ </template>
+ </el-table-column>
+ <el-table-column label="类型" show-overflow-tooltip width="80">
+ <template #default="scope">
+ <el-tag type="success" size="small">{{ scope.row.xx }}菜单</el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column label="操作" show-overflow-tooltip width="140">
+ <template #default="scope">
+ <el-button size="small" text type="primary" @click="onOpenAddMenu('add')">新增</el-button>
+ <el-button size="small" text type="primary" @click="onOpenEditMenu('edit', scope.row)">修改</el-button>
+ <el-button size="small" text type="primary" @click="onTabelRowDel(scope.row)">删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ </el-card>
+ <MenuDialog ref="menuDialogRef" @refresh="getTableData()" />
+ </div>
+</template>
+
+<script setup lang="ts" name="systemMenu">
+import { defineAsyncComponent, ref, onMounted, reactive } from 'vue';
+import { RouteRecordRaw } from 'vue-router';
+import { ElMessageBox, ElMessage } from 'element-plus';
+import { storeToRefs } from 'pinia';
+import { useRoutesList } from '/@/stores/routesList';
+import { useMenuApi } from "/@/api/systemManage/menu";
+import { initBackEndControlRoutes } from "/@/router/backEnd";
+import {roomApi} from "/@/api/basic/room";
+// import { setBackEndControlRefreshRoutes } from "/@/router/backEnd";
+
+// 引入组件
+const MenuDialog = defineAsyncComponent(() => import('/@/views/home/dialog.vue'));
+
+// 定义变量内容
+const stores = useRoutesList();
+const { routesList } = storeToRefs(stores);
+const menuDialogRef = ref();
+const state = reactive({
+ tableData: {
+ data: [] as RouteRecordRaw[],
+ loading: false,
+ },
+});
+
+// 获取路由数据,真实请从接口获取
+const getTableData = async () => {
+ let res = await useMenuApi().getMenuAdmin();
+ if (res.data.code === 100) {
+ state.tableData.data = res.data.data;
+ await initBackEndControlRoutes()
+ } else {
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ });
+ }
+};
+// 打开新增菜单弹窗
+const onOpenAddMenu = (type: string) => {
+ menuDialogRef.value.openDialog(type);
+};
+// 打开编辑菜单弹窗
+const onOpenEditMenu = (type: string, row: RouteRecordRaw) => {
+ menuDialogRef.value.openDialog(type, row);
+};
+// 删除当前行
+const onTabelRowDel = (row: RouteRecordRaw) => {
+ ElMessageBox.confirm(`此操作将永久删除该菜单,是否继续?`, '提示', {
+ confirmButtonText: '确认',
+ cancelButtonText: '取消',
+ type: 'warning'
+ })
+ .then(async () => {
+ let res = await useMenuApi().deleteMenu(row.id );
+ if (res.data.code === 100) {
+ ElMessage({
+ type: 'success',
+ duration: 2000,
+ message: '删除成功'
+ });
+ await getTableData();
+ } else {
+ ElMessage({
+ type: 'warning',
+ message: res.data.msg
+ });
+ }
+ })
+ .catch((error) => {
+
+ });
+}
+
+// 页面加载时
+onMounted(() => {
+ getTableData();
+});
+</script>
--
Gitblit v1.9.2