Compare commits

..

69 Commits

Author SHA1 Message Date
Teo
fd56b48ebe 1 2025-09-12 23:32:56 +08:00
Teo
8530460757 1 2025-09-12 23:29:34 +08:00
ljx
0a58a655d2 提交 2025-09-12 23:27:10 +08:00
ljx
5f0368dad2 提交 2025-09-12 23:26:37 +08:00
Teo
beb576ceb8 Merge remote-tracking branch 'l-origin/ljx' 2025-09-12 22:39:12 +08:00
Teo
9fb1d7b043 1 2025-09-12 22:39:06 +08:00
ljx
010d3d8c3c 提交 2025-09-12 22:38:25 +08:00
ljx
5a2b17dea2 提交 2025-09-12 22:33:25 +08:00
ljx
5de6bd0918 提交 2025-09-12 22:22:00 +08:00
ljx
a71d861227 提交 2025-09-12 22:20:33 +08:00
Teo
149499ccc1 1 2025-09-12 22:10:11 +08:00
ljx
e1360a3f16 提交 2025-09-12 22:02:14 +08:00
ljx
8316636c68 提交 2025-09-12 22:01:26 +08:00
ljx
6bc9ed7054 Merge branch 'szq' of http://xny.yj-3d.com:3000/taoge/new_project into ljx 2025-09-12 22:01:17 +08:00
ljx
05157ff600 Merge branch 'fs' of http://xny.yj-3d.com:3000/taoge/new_project into ljx 2025-09-12 21:22:20 +08:00
Teo
d154147735 合并 2025-09-12 21:03:35 +08:00
tcy
bc59e4a893 style(progressCategory): 优化进度分类页面的样式和交互效果
- 调整摘要卡片的布局和间距
- 添加悬停动画效果和渐变边框
- 改进数值显示样式和默认值处理
- 增强图标视觉效果和交互反馈
2025-09-12 21:00:10 +08:00
Teo
4dc620b877 修复图片上传 2025-09-12 20:51:06 +08:00
Teo
17c9166ecd 合并 2025-09-12 20:46:19 +08:00
shi
198e42a26f 修改项目级大屏 2025-09-12 20:43:56 +08:00
Teo
9927ed4b00 h合并 2025-09-12 20:37:59 +08:00
4dc74dd4bf 倾斜模型 2025-09-12 20:28:12 +08:00
Teo
a1a9d13789 h合并 2025-09-12 20:16:25 +08:00
ljx
22440878b5 提交 2025-09-12 20:08:27 +08:00
Teo
6885712677 合并 2025-09-12 20:05:55 +08:00
ljx
0ed7ab95aa Merge branch 'main' of http://xny.yj-3d.com:3000/taoge/new_project into ljx 2025-09-12 20:01:15 +08:00
ljx
fd30294f69 提交 2025-09-12 20:00:26 +08:00
Teo
0c27426d80 合并 2025-09-12 19:38:17 +08:00
Teo
eb28d089cc 合并 2025-09-12 19:36:11 +08:00
Teo
cd75261a6d 合并 2025-09-12 19:35:45 +08:00
dhr
120a46d76c 0912 2025-09-12 19:34:45 +08:00
shi
aa1f2e8fdb 修改项目级大屏 2025-09-12 19:33:07 +08:00
ljx
ae21698e5f 修改 2025-09-12 19:28:43 +08:00
shi
9fbabd2b6a Merge branch 'main' of http://192.168.110.2:3000/taoge/mk_system into szq 2025-09-12 19:02:43 +08:00
shi
abb1817671 修改 2025-09-12 18:54:44 +08:00
Teo
02479cd4e5 合并 2025-09-12 11:16:09 +08:00
Teo
9deadf48bc 1 2025-09-12 11:14:51 +08:00
Teo
0db23ba44e 进度计划优化切换项目逻辑 2025-09-12 10:21:29 +08:00
Teo
9cc4e17c6a 进度计划 2025-09-11 21:01:16 +08:00
dhr
10d4314780 0911 2025-09-11 19:59:26 +08:00
ljx
6a07a25c2e 提交 2025-09-11 19:30:45 +08:00
ff33d02438 合并 2025-09-11 18:50:59 +08:00
094f64accd 合并 2025-09-11 18:49:36 +08:00
ljx
7993b7e6ac 修改 2025-09-11 18:47:55 +08:00
dhr
ed00cd6e0f 0911
git commit -m 0911
2025-09-11 18:45:28 +08:00
ljx
3f04ebcbda 修改 2025-09-11 18:23:30 +08:00
ljx
bfbf55eb19 修改 2025-09-11 17:45:10 +08:00
9caa6f215c 1 2025-09-11 17:05:15 +08:00
shi
2cd70eb415 修改 2025-09-11 17:01:06 +08:00
ljx
61a21a6250 提交 2025-09-11 16:49:24 +08:00
dhr
c26b87303c 0911 2025-09-11 15:59:47 +08:00
69cfffa0d4 合并 2025-09-11 09:10:25 +08:00
a658f0893f 合并 2025-09-11 09:09:50 +08:00
shi
122df7699f 增加项目公告滚动效果 2025-09-10 20:52:01 +08:00
ljx
b6eff020ce 提交代码 2025-09-10 20:03:15 +08:00
ljx
a3dd00645f 提交 2025-09-10 19:34:57 +08:00
c6f38a9593 打卡范围、项目级页面修改 2025-09-10 19:22:22 +08:00
ljx
a3d35a7410 提交 2025-09-10 15:26:29 +08:00
Teo
410c6beece Merge branch 'master' of http://192.168.110.2:3000/taoge_xiaodi/td_official 2025-09-10 11:51:09 +08:00
Teo
2a76bbb64c 取消进度日报分页 2025-09-10 11:51:03 +08:00
Teo
0755ab891d 1 2025-09-10 11:44:31 +08:00
38dcbe7f7a 优化 2025-09-10 11:42:24 +08:00
6ee83aae94 Merge branch 'main' of http://192.168.110.2:3000/taoge/mk_system into fs 2025-09-10 10:04:40 +08:00
644a222430 连接ws 2025-09-10 10:03:35 +08:00
ljx
f3b7417b4f 修改 2025-09-10 10:02:04 +08:00
71ba51772d 优化 2025-09-10 09:58:41 +08:00
Teo
11a3db5b61 修改 2025-09-10 09:23:51 +08:00
b62b12c0b4 优化 2025-09-10 09:11:50 +08:00
dhr
65ff68673c 0909 2025-09-09 22:34:40 +08:00
137 changed files with 7811 additions and 1423 deletions

View File

@ -5,14 +5,18 @@ VITE_APP_TITLE = 煤科建管平台
VITE_APP_ENV = 'development' VITE_APP_ENV = 'development'
# 开发环境 # 开发环境
VITE_APP_BASE_API = 'http://192.168.110.209:8899' # VITE_APP_BASE_API = 'http://192.168.110.209:8899'
# VITE_APP_BASE_API = 'http://58.17.134.85:8899' VITE_APP_BASE_API = 'http://58.17.134.85:8899'
# GO开发环境 # GO开发环境
VITE_APP_BASE_API_GO = 'http://xny.yj-3d.com:7464' VITE_APP_BASE_API_GO = 'http://xny.yj-3d.com:7464'
# VITE_APP_BASE_API_GO = 'http://192.168.110.188:8919' # VITE_APP_BASE_API_GO = 'http://192.168.110.188:8919'
# 无人机接口地址 # ws
VITE_APP_BASE_WS_API = 'ws://192.168.110.149:8899/resource/websocket'
# EARTH
VITE_APP_BASE_EARTH_API = "http://192.168.110.2:8895"
# 无人机接口地址
VITE_APP_BASE_DRONE_API = 'http://58.17.134.85:9512' VITE_APP_BASE_DRONE_API = 'http://58.17.134.85:9512'
# 应用访问路径 例如使用前缀 /admin/ # 应用访问路径 例如使用前缀 /admin/

View File

@ -17,6 +17,7 @@ VITE_APP_SNAILJOB_ADMIN = '/snail-job'
# GO生产环境 # GO生产环境
VITE_APP_BASE_API_GO = 'http://58.17.134.85:7464' VITE_APP_BASE_API_GO = 'http://58.17.134.85:7464'
VITE_APP_BASE_API = 'http://xny.yj-3d.com:8899' VITE_APP_BASE_API = 'http://xny.yj-3d.com:8899'
VITE_APP_BASE_EARTH_API = "http://192.168.110.2:8895"
# 是否在打包时开启压缩,支持 gzip 和 brotli # 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS = gzip VITE_BUILD_COMPRESS = gzip

0
npm Normal file
View File

View File

@ -34,7 +34,7 @@
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"diagram-js": "12.3.0", "diagram-js": "12.3.0",
"didi": "9.0.2", "didi": "9.0.2",
"echarts": "5.5.0", "echarts": "^5.5.0",
"echarts-gl": "^2.0.9", "echarts-gl": "^2.0.9",
"element-plus": "2.8.8", "element-plus": "2.8.8",
"esbuild": "^0.25.0", "esbuild": "^0.25.0",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
public/assets/demo/fog.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
public/assets/demo/haze.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -11,3 +11,34 @@ export const keyIndex = () => {
method: 'get' method: 'get'
}); });
}; };
/**
* 每个项目的出勤人数
*/
export const projectAttendanceCount = () => {
return request({
url: '/enterprise/big/screen/projectAttendanceCount',
method: 'get'
});
};
/**
* 人数统计
*/
export const peopleCount = () => {
return request({
url: '/enterprise/big/screen/peopleCount',
method: 'get'
});
};
/**
* 出勤人数统计
*/
export const allAttendanceCount = () => {
return request({
url: '/enterprise/big/screen/allAttendanceCount',
method: 'get'
});
};

View File

@ -106,6 +106,6 @@ export const getFootNote = (data) => {
return request({ return request({
url: 'gps/equipmentSon/getList', url: 'gps/equipmentSon/getList',
method: 'get', method: 'get',
data: data params: data
}); });
}; };

View File

@ -122,6 +122,11 @@ export interface EquipmentQuery extends PageQuery {
*/ */
type?: string | number; type?: string | number;
/**
* 展示用户/设备数据1=用户数据0=设备数据
*/
gpsType?: string | number;
/** /**
* 用户id * 用户id
*/ */

View File

@ -53,7 +53,6 @@ export interface MaterialReceiveVO {
* 备注 * 备注
*/ */
remark: string; remark: string;
} }
export interface MaterialReceiveForm extends BaseEntity { export interface MaterialReceiveForm extends BaseEntity {
@ -156,11 +155,13 @@ export interface MaterialReceiveForm extends BaseEntity {
* 备注 * 备注
*/ */
remark?: string; remark?: string;
/**
* 附件
*/
attachmentId?: string | number;
} }
export interface MaterialReceiveQuery extends PageQuery { export interface MaterialReceiveQuery extends PageQuery {
/** /**
* 项目id * 项目id
*/ */
@ -201,11 +202,8 @@ export interface MaterialReceiveQuery extends PageQuery {
*/ */
supplierUnit?: string; supplierUnit?: string;
/** /**
* 日期范围参数 * 日期范围参数
*/ */
params?: any; params?: any;
} }

View File

@ -0,0 +1,72 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { MechanicalrewritingVO, MechanicalrewritingForm, MechanicalrewritingQuery } from '@/api/mechanical/mechanicalrewriting/types';
/**
* 查询机械台账列表
* @param query
* @returns {*}
*/
export const listMechanicalrewriting = (query?: MechanicalrewritingQuery): AxiosPromise<MechanicalrewritingVO[]> => {
return request({
url: '/mechanical/mechanicalrewriting/list',
method: 'get',
params: query
});
};
/**
* 查询机械台账详细
* @param id
*/
export const getMechanicalrewriting = (id: string | number): AxiosPromise<MechanicalrewritingVO> => {
return request({
url: '/mechanical/mechanicalrewriting/' + id,
method: 'get'
});
};
/**
* 新增机械台账
* @param data
*/
export const addMechanicalrewriting = (data: MechanicalrewritingForm) => {
return request({
url: '/mechanical/mechanicalrewriting',
method: 'post',
data: data
});
};
/**
* 修改机械台账
* @param data
*/
export const updateMechanicalrewriting = (data: MechanicalrewritingForm) => {
return request({
url: '/mechanical/mechanicalrewriting',
method: 'put',
data: data
});
};
/**
* 删除机械台账
* @param id
*/
export const delMechanicalrewriting = (id: string | number | Array<string | number>) => {
return request({
url: '/mechanical/mechanicalrewriting/' + id,
method: 'delete'
});
};
//获取类型
export const getType = (query?: any) => {
return request({
url: '/mechanical/mechanicaltype/getTree',
method: 'get',
params: query
});
};

View File

@ -0,0 +1,306 @@
export interface MechanicalrewritingVO {
/**
* 自增ID
*/
id: string | number;
/**
* 项目ID
*/
projectId: string | number;
/**
* 班组名称
*/
teamName: string;
/**
* 设备名称
*/
devicename: string;
/**
* 设备类型
*/
deviceType: string;
/**
* 设备编号
*/
deviceNumber: string;
/**
* 入场日期
*/
entryTime: string;
/**
* 规格型号
*/
specification: string;
/**
* 生产能力
*/
production: string;
/**
* 车牌号码
*/
plateNumber: string;
/**
* 设备管理员
*/
deviceKeeper: string;
/**
* 车辆行驶证
*/
drivingLicence: string;
/**
* 新旧程度
*/
degree: string;
/**
* 车辆容量
*/
vehicleCapacity: string;
/**
* 车辆净重
*/
suttle: string;
/**
* 铭牌
*/
nameplate: string;
/**
* 合格证书
*/
qualification: string;
/**
* 设备照片
*/
equipmentPhoto: string;
/**
* 检验报告
*/
verificationReport: string;
/**
* 备注
*/
remark: string;
}
export interface MechanicalrewritingForm extends BaseEntity {
/**
* 自增ID
*/
id?: string | number;
/**
* 项目ID
*/
projectId?: string | number;
/**
* 班组名称
*/
teamName?: string;
/**
* 设备名称
*/
devicename?: string;
/**
* 设备类型
*/
deviceType?: string;
/**
* 设备编号
*/
deviceNumber?: string;
/**
* 入场日期
*/
entryTime?: string;
/**
* 规格型号
*/
specification?: string;
/**
* 生产能力
*/
production?: string;
/**
* 车牌号码
*/
plateNumber?: string;
/**
* 设备管理员
*/
deviceKeeper?: string;
/**
* 车辆行驶证
*/
drivingLicence?: string;
/**
* 新旧程度
*/
degree?: string;
/**
* 车辆容量
*/
vehicleCapacity?: string;
/**
* 车辆净重
*/
suttle?: string;
/**
* 铭牌
*/
nameplate?: string;
/**
* 合格证书
*/
qualification?: string;
/**
* 设备照片
*/
equipmentPhoto?: string;
/**
* 检验报告
*/
verificationReport?: string;
/**
* 备注
*/
remark?: string;
}
export interface MechanicalrewritingQuery extends PageQuery {
/**
* 项目ID
*/
projectId?: string | number;
/**
* 班组名称
*/
teamName?: string;
/**
* 设备名称
*/
devicename?: string;
/**
* 设备类型
*/
deviceType?: string;
/**
* 设备编号
*/
deviceNumber?: string;
/**
* 入场日期
*/
entryTime?: string;
/**
* 规格型号
*/
specification?: string;
/**
* 生产能力
*/
production?: string;
/**
* 车牌号码
*/
plateNumber?: string;
/**
* 设备管理员
*/
deviceKeeper?: string;
/**
* 车辆行驶证
*/
drivingLicence?: string;
/**
* 新旧程度
*/
degree?: string;
/**
* 车辆容量
*/
vehicleCapacity?: string;
/**
* 车辆净重
*/
suttle?: string;
/**
* 铭牌
*/
nameplate?: string;
/**
* 合格证书
*/
qualification?: string;
/**
* 设备照片
*/
equipmentPhoto?: string;
/**
* 检验报告
*/
verificationReport?: string;
/**
* 日期范围参数
*/
params?: any;
}

View File

@ -0,0 +1,63 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { MechanicaltypeVO, MechanicaltypeForm, MechanicaltypeQuery } from '@/api/mechanical/mechanicaltype/types';
/**
* 查询设备类型列表
* @param query
* @returns {*}
*/
export const listMechanicaltype = (query?: MechanicaltypeQuery): AxiosPromise<MechanicaltypeVO[]> => {
return request({
url: '/mechanical/mechanicaltype/list',
method: 'get',
params: query
});
};
/**
* 查询设备类型详细
* @param id
*/
export const getMechanicaltype = (id: string | number): AxiosPromise<MechanicaltypeVO> => {
return request({
url: '/mechanical/mechanicaltype/' + id,
method: 'get'
});
};
/**
* 新增设备类型
* @param data
*/
export const addMechanicaltype = (data: MechanicaltypeForm) => {
return request({
url: '/mechanical/mechanicaltype',
method: 'post',
data: data
});
};
/**
* 修改设备类型
* @param data
*/
export const updateMechanicaltype = (data: MechanicaltypeForm) => {
return request({
url: '/mechanical/mechanicaltype',
method: 'put',
data: data
});
};
/**
* 删除设备类型
* @param id
*/
export const delMechanicaltype = (id: string | number | Array<string | number>) => {
return request({
url: '/mechanical/mechanicaltype/' + id,
method: 'delete'
});
};

View File

@ -0,0 +1,129 @@
export interface MechanicaltypeVO {
/**
* 自增ID
*/
id: string | number;
/**
* 编码
*/
code: string;
/**
* 父编码
*/
pcode: string;
/**
* 大
*/
largeclass: string;
/**
* 中
*/
middleclass: string | number;
/**
* 子类
*/
subclass: string;
/**
* 备注
*/
remark: string;
/**
* 全名
*/
fullName: string;
/**
* 类型
*/
deviceType?: string;
}
export interface MechanicaltypeForm extends BaseEntity {
/**
* 自增ID
*/
id?: string | number;
/**
* 编码
*/
code?: string;
/**
* 父编码
*/
pcode?: string;
/**
* 大
*/
largeclass?: string;
/**
* 中
*/
middleclass?: string | number;
/**
* 子类
*/
subclass?: string;
/**
* 备注
*/
remark?: string;
/**
* 全名
*/
fullName?: string;
/**
* 类型
*/
deviceType?: string;
}
export interface MechanicaltypeQuery extends PageQuery {
/**
* 编码
*/
code?: string;
/**
* 父编码
*/
pcode?: string;
/**
* 大
*/
largeclass?: string;
/**
* 中
*/
middleclass?: string | number;
/**
* 子类
*/
subclass?: string;
/**
* 全名
*/
fullName?: string;
/**
* 日期范围参数
*/
params?: any;
}

View File

@ -23,7 +23,7 @@ export const projectProgress = (query?: any): any => {
export const outpuProgress = (query?: any): any => { export const outpuProgress = (query?: any): any => {
return request({ return request({
url: '/enterprise/big/screen/projectOutputValueComparison', url: '/enterprise/big/screen/projectProgressCapacity',
method: 'get', method: 'get',
params: query params: query
}); });

View File

@ -5,7 +5,7 @@ import { AxiosPromise } from 'axios';
export const getScreenWeather = (projectId: number | string) => { export const getScreenWeather = (projectId: number | string) => {
return request({ return request({
url: '/project/big/screen/weather/' + projectId, url: '/project/big/screen/weather/' + projectId,
method: 'get', method: 'get'
}); });
}; };
@ -13,7 +13,7 @@ export const getScreenWeather = (projectId: number | string) => {
export const getScreenSafetyDay = (projectId: number | string) => { export const getScreenSafetyDay = (projectId: number | string) => {
return request({ return request({
url: '/project/big/screen/safetyDay/' + projectId, url: '/project/big/screen/safetyDay/' + projectId,
method: 'get', method: 'get'
}); });
}; };
@ -21,7 +21,7 @@ export const getScreenSafetyDay = (projectId: number | string) => {
export const getScreenNews = (projectId: number | string) => { export const getScreenNews = (projectId: number | string) => {
return request({ return request({
url: '/project/big/screen/news/' + projectId, url: '/project/big/screen/news/' + projectId,
method: 'get', method: 'get'
}); });
}; };
@ -29,7 +29,7 @@ export const getScreenNews = (projectId: number | string) => {
export const getScreenLand = (projectId: number | string) => { export const getScreenLand = (projectId: number | string) => {
return request({ return request({
url: '/project/big/screen/' + projectId, url: '/project/big/screen/' + projectId,
method: 'get', method: 'get'
}); });
}; };
@ -37,7 +37,7 @@ export const getScreenLand = (projectId: number | string) => {
export const getScreenImgProcess = (projectId: number | string) => { export const getScreenImgProcess = (projectId: number | string) => {
return request({ return request({
url: '/project/big/screen/imageProgress/' + projectId, url: '/project/big/screen/imageProgress/' + projectId,
method: 'get', method: 'get'
}); });
}; };
@ -45,7 +45,7 @@ export const getScreenImgProcess = (projectId: number | string) => {
export const getScreenPeople = (projectId: number | string) => { export const getScreenPeople = (projectId: number | string) => {
return request({ return request({
url: '/project/big/screen/people/' + projectId, url: '/project/big/screen/people/' + projectId,
method: 'get', method: 'get'
}); });
}; };
@ -53,7 +53,10 @@ export const getScreenPeople = (projectId: number | string) => {
export const getScreenSafetyInspection = (projectId: number | string) => { export const getScreenSafetyInspection = (projectId: number | string) => {
return request({ return request({
url: '/project/big/screen/safetyInspection/' + projectId, url: '/project/big/screen/safetyInspection/' + projectId,
method: 'get', method: 'get'
// params: {
// projectId
// }
}); });
}; };
@ -61,7 +64,7 @@ export const getScreenSafetyInspection = (projectId: number | string) => {
export const getScreenGeneralize = (projectId: number | string) => { export const getScreenGeneralize = (projectId: number | string) => {
return request({ return request({
url: '/project/big/screen/generalize/' + projectId, url: '/project/big/screen/generalize/' + projectId,
method: 'get', method: 'get'
}); });
}; };
@ -88,3 +91,12 @@ export const setSelect = (data) => {
data data
}); });
}; };
// 获取模型列表
export const getModelList = (params) => {
return request({
url: '/yjearth4.0/api/v1/source/list',
method: 'get',
params
});
};

View File

@ -22,9 +22,12 @@ export const listSafetyWeeklyReport = (query?: SafetyWeeklyReportQuery): AxiosPr
* @param id * @param id
*/ */
export const getSafetyWeeklyReport = (id: string | number): AxiosPromise<SafetyWeeklyReportVO> => { export const getSafetyWeeklyReport = (id: string | number): AxiosPromise<SafetyWeeklyReportVO> => {
return request({ return requestGo({
url: '/safety/safetyWeeklyReport/' + id, url: '/zm/api/v1/system/busWeeklySecurityReport/get',
method: 'get' method: 'get',
params: {
id
}
}); });
}; };

View File

@ -31,6 +31,7 @@ export interface FlowTaskVO {
version?: string; version?: string;
applyNode?: boolean; applyNode?: boolean;
buttonList?: buttonList[]; buttonList?: buttonList[];
projectName?: string;
} }
export interface buttonList { export interface buttonList {

View File

@ -12,7 +12,8 @@ export default {
businessId: routerJumpVo.businessId, businessId: routerJumpVo.businessId,
type: routerJumpVo.type, type: routerJumpVo.type,
planMonth: routerJumpVo.planMonth, planMonth: routerJumpVo.planMonth,
taskId: routerJumpVo.taskId taskId: routerJumpVo.taskId,
projectName: routerJumpVo.projectName
} }
}); });
} }

View File

@ -4,6 +4,7 @@ export interface RouterJumpVo {
type: string; type: string;
formCustom: string; formCustom: string;
formPath: string; formPath: string;
projectName?: string;
} }
export interface StartProcessBo { export interface StartProcessBo {

BIN
src/assets/images/man.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
src/assets/images/map.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 KiB

View File

@ -107,7 +107,7 @@ const props = defineProps({
// 数量限制 // 数量限制
limit: propTypes.number.def(5), limit: propTypes.number.def(5),
// 大小限制(MB) // 大小限制(MB)
fileSize: propTypes.number.def(5), fileSize: propTypes.number.def(10),
// 文件类型, 例如['png', 'jpg', 'jpeg'] // 文件类型, 例如['png', 'jpg', 'jpeg']
// fileType: propTypes.array.def(['doc', 'xls', 'ppt', 'txt', 'pdf', 'png', 'jpg', 'jpeg', 'zip']), // fileType: propTypes.array.def(['doc', 'xls', 'ppt', 'txt', 'pdf', 'png', 'jpg', 'jpeg', 'zip']),
fileType: propTypes.array.def(['pdf']), fileType: propTypes.array.def(['pdf']),

View File

@ -46,6 +46,7 @@ import { OssVO } from '@/api/system/oss/types';
import { propTypes } from '@/utils/propTypes'; import { propTypes } from '@/utils/propTypes';
import { globalHeaders } from '@/utils/request'; import { globalHeaders } from '@/utils/request';
import { compressAccurately } from 'image-conversion'; import { compressAccurately } from 'image-conversion';
import { bool } from 'vue-types';
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
@ -55,7 +56,7 @@ const props = defineProps({
// 图片数量限制 // 图片数量限制
limit: propTypes.number.def(5), limit: propTypes.number.def(5),
// 大小限制(MB) // 大小限制(MB)
fileSize: propTypes.number.def(5), fileSize: propTypes.number.def(10),
// 文件类型, 例如['png', 'jpg', 'jpeg'] // 文件类型, 例如['png', 'jpg', 'jpeg']
fileType: propTypes.array.def(['png', 'jpg', 'jpeg']), fileType: propTypes.array.def(['png', 'jpg', 'jpeg']),
// 是否显示提示 // 是否显示提示
@ -81,7 +82,7 @@ const props = defineProps({
compressTargetSize: propTypes.number.def(300), compressTargetSize: propTypes.number.def(300),
idCardType: { idCardType: {
type: String, type: String,
default: false default: ''
} }
}); });
@ -93,7 +94,9 @@ const dialogImageUrl = ref('');
const dialogVisible = ref(false); const dialogVisible = ref(false);
const baseUrl = props.isGo ? import.meta.env.VITE_APP_BASE_API_GO : import.meta.env.VITE_APP_BASE_API; const baseUrl = props.isGo ? import.meta.env.VITE_APP_BASE_API_GO : import.meta.env.VITE_APP_BASE_API;
const uploadImgUrl = ref(baseUrl + props.action ? props.action : '/resource/oss/upload'); // 上传的图片服务器地址 const uploadImgUrl = ref(baseUrl + (props.action ? props.action : '/resource/oss/upload')); // 上传的图片服务器地址
console.log('🚀 ~ uploadImgUrl:', uploadImgUrl.value, baseUrl, props.action);
const headers = ref(globalHeaders()); const headers = ref(globalHeaders());
const fileList = ref<any[]>([]); const fileList = ref<any[]>([]);

View File

@ -1,15 +1,18 @@
<template> <template>
<div style="display: flex; justify-content: space-between"> <div>
<div> <div style="display: flex; justify-content: space-between">
<el-button v-if="submitButtonShow" :loading="props.buttonLoading" type="info" @click="submitForm('draft')">暂存</el-button> <div>
<el-button v-if="submitButtonShow" :loading="props.buttonLoading" type="primary" @click="submitForm('submit')"> </el-button> <el-button v-if="submitButtonShow" :loading="props.buttonLoading" type="info" @click="submitForm('draft')">暂存</el-button>
<el-button v-if="approvalButtonShow" :loading="props.buttonLoading" type="primary" @click="approvalVerifyOpen">审批</el-button> <el-button v-if="submitButtonShow" :loading="props.buttonLoading" type="primary" @click="submitForm('submit')"> </el-button>
<el-button v-if="props.id && props.status !== 'draft'" type="primary" @click="handleApprovalRecord">流程进度</el-button> <el-button v-if="approvalButtonShow" :loading="props.buttonLoading" type="primary" @click="approvalVerifyOpen">审批</el-button>
<slot /> <el-button v-if="props.id && props.status !== 'draft'" type="primary" @click="handleApprovalRecord">流程进度</el-button>
</div> <slot />
<div> </div>
<el-button style="float: right" @click="goBack()">返回</el-button> <div>
<el-button style="float: right" @click="goBack()">返回</el-button>
</div>
</div> </div>
<h3 v-if="props.projectName" class="text-lg font-semibold text-gray-800">项目名称{{ props.projectName }}</h3>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -22,7 +25,8 @@ const props = defineProps({
status: propTypes.string.def(''), status: propTypes.string.def(''),
pageType: propTypes.string.def(''), pageType: propTypes.string.def(''),
buttonLoading: propTypes.bool.def(false), buttonLoading: propTypes.bool.def(false),
id: propTypes.string.def('') || propTypes.number.def() id: propTypes.string.def('') || propTypes.number.def(),
projectName: propTypes.string.def('')
}); });
const emits = defineEmits(['submitForm', 'approvalVerifyOpen', 'handleApprovalRecord']); const emits = defineEmits(['submitForm', 'approvalVerifyOpen', 'handleApprovalRecord']);
//暂存,提交 //暂存,提交

View File

@ -167,7 +167,7 @@ const reset = () => {
form.value = { ...initFormData }; form.value = { ...initFormData };
leaveFormRef.value?.resetFields(); leaveFormRef.value?.resetFields();
}; };
const projectId = ref('');
/** 获取详情 */ /** 获取详情 */
const getInfo = () => { const getInfo = () => {
loading.value = true; loading.value = true;
@ -175,6 +175,7 @@ const getInfo = () => {
nextTick(async () => { nextTick(async () => {
const res = await getVersionDetail(routeParams.value.id); const res = await getVersionDetail(routeParams.value.id);
console.log(res); console.log(res);
projectId.value = res.data.projectId;
Object.assign(form.value, res.data); Object.assign(form.value, res.data);
loading.value = false; loading.value = false;
buttonLoading.value = false; buttonLoading.value = false;
@ -186,7 +187,7 @@ const sheets = ref([]);
const getSheetName = async () => { const getSheetName = async () => {
try { try {
const params = { const params = {
projectId: currentProject.value?.id, projectId: projectId.value,
versions: form.value.versions versions: form.value.versions
}; };
const res = await sheetList(params); const res = await sheetList(params);
@ -208,7 +209,7 @@ const tableData = ref([]);
//获取列表 //获取列表
const getListTable = async () => { const getListTable = async () => {
const res = await getTreeLimit({ const res = await getTreeLimit({
projectId: currentProject.value?.id, projectId: projectId.value,
versions: form.value.versions, versions: form.value.versions,
sheet: form.value.sheet, sheet: form.value.sheet,
type: '0' type: '0'

View File

@ -66,7 +66,7 @@
{{ scope.row.children.length > 0 ? '' : scope.row.quantity }} {{ scope.row.children.length > 0 ? '' : scope.row.quantity }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="remark" label="单价" align="center"> <el-table-column prop="remark" label="单价" align="center" width="200px">
<template #default="scope"> <template #default="scope">
<el-input-number <el-input-number
:disabled="versionObj.status != 'draft'" :disabled="versionObj.status != 'draft'"
@ -81,6 +81,7 @@
:precision="4" :precision="4"
:controls="false" :controls="false"
v-if="scope.row.quantity && scope.row.quantity != 0" v-if="scope.row.quantity && scope.row.quantity != 0"
width="200px"
/> />
</template> </template>
</el-table-column> </el-table-column>

View File

@ -11,6 +11,7 @@
:id="form.id" :id="form.id"
:status="form.status" :status="form.status"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>
<!-- 表单区域 --> <!-- 表单区域 -->

View File

@ -30,7 +30,7 @@
{{ proxy.formatPrice(scope.row.price) }} {{ proxy.formatPrice(scope.row.price) }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="plannedBiddingTime" align="center"> <el-table-column prop="plannedBiddingTime" align="center" width="250px">
<template #header> <span style="color: red">*</span>计划招标时间 </template> <template #header> <span style="color: red">*</span>计划招标时间 </template>
<template #default="scope"> <template #default="scope">
<el-date-picker <el-date-picker
@ -39,6 +39,7 @@
value-format="YYYY-MM-DD" value-format="YYYY-MM-DD"
placeholder="选择时间" placeholder="选择时间"
:disabled="scope.row.status == 0" :disabled="scope.row.status == 0"
style="width: 200px"
/> />
</template> </template>
</el-table-column> </el-table-column>
@ -126,7 +127,7 @@
<el-table-column prop="unit" label="单位" /> <el-table-column prop="unit" label="单位" />
<!-- <el-table-column prop="quantity" label="数量" /> --> <!-- <el-table-column prop="quantity" label="数量" /> -->
<el-table-column prop="quantity" label="计划量" align="center" /> <el-table-column prop="quantity" label="计划量" align="center" />
<el-table-column prop="selectNum" label="设计量" align="center"> <el-table-column prop="selectNum" label="设计量" align="center" width="200px">
<template #default="scope"> <template #default="scope">
<el-input-number <el-input-number
:model-value="scope.row.selectNum" :model-value="scope.row.selectNum"
@ -141,6 +142,7 @@
:controls="false" :controls="false"
:max="Math.floor(scope.row.quantity)" :max="Math.floor(scope.row.quantity)"
v-if="scope.row.quantity && scope.row.quantity != 0 && scope.row.unitPrice" v-if="scope.row.quantity && scope.row.quantity != 0 && scope.row.unitPrice"
width="150px"
/> />
</template> </template>
</el-table-column> </el-table-column>

View File

@ -5,7 +5,7 @@
<el-form :model="queryForm" :inline="true"> <el-form :model="queryForm" :inline="true">
<el-form-item label="版本号" prop="versions"> <el-form-item label="版本号" prop="versions">
<el-select v-model="queryForm.versions" placeholder="选择版本号" @change="changeVersions"> <el-select v-model="queryForm.versions" placeholder="选择版本号" @change="changeVersions">
<el-option v-for="item in options" :key="item.versions" :label="item.versions" :value="item.versions" /> <el-option v-for="item in options" :key="item.versions" :label="item.versionsName" :value="item.versions" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="表名" prop="sheet"> <el-form-item label="表名" prop="sheet">

View File

@ -11,6 +11,7 @@
:id="form.versions" :id="form.versions"
:status="form.status" :status="form.status"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>
<!-- 表单区域 --> <!-- 表单区域 -->
@ -162,7 +163,7 @@ const reset = () => {
form.value = { ...initFormData }; form.value = { ...initFormData };
leaveFormRef.value?.resetFields(); leaveFormRef.value?.resetFields();
}; };
const projectId = ref('');
/** 获取详情 */ /** 获取详情 */
const getInfo = () => { const getInfo = () => {
loading.value = true; loading.value = true;
@ -170,6 +171,7 @@ const getInfo = () => {
nextTick(async () => { nextTick(async () => {
const res = await getVersionDetails(routeParams.value.id); const res = await getVersionDetails(routeParams.value.id);
console.log(res); console.log(res);
projectId.value = res.data.projectId;
Object.assign(form.value, res.data); Object.assign(form.value, res.data);
loading.value = false; loading.value = false;
buttonLoading.value = false; buttonLoading.value = false;
@ -181,7 +183,7 @@ const sheets = ref([]);
const getSheetName = async () => { const getSheetName = async () => {
try { try {
const params = { const params = {
projectId: currentProject.value?.id, projectId: projectId.value,
versions: form.value.versions versions: form.value.versions
}; };
const res = await sheetList(params); const res = await sheetList(params);
@ -201,7 +203,7 @@ const changeSheet = () => {
//获取列表 //获取列表
const getListTable = async () => { const getListTable = async () => {
const res = await listBillofquantitiesLimitList({ const res = await listBillofquantitiesLimitList({
projectId: currentProject.value?.id, projectId: projectId.value,
versions: form.value.versions, versions: form.value.versions,
sheet: form.value.sheet sheet: form.value.sheet
}); });

View File

@ -11,6 +11,7 @@
:id="form.id" :id="form.id"
:status="form.status" :status="form.status"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>

View File

@ -11,6 +11,7 @@
:id="form.id" :id="form.id"
:status="form.status" :status="form.status"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>

View File

@ -1,30 +1,31 @@
<template> <template>
<el-row> <el-row>
<el-col> <el-col>
<div style="color: rgba(0, 30, 59, 1);;font-family: 'Alibaba-PuHuiTi-Bold';margin: 10px 0 0 0;" <div
:style="{ fontSize: fontLevelMap[props.fontLevel] }"> style="color: rgba(0, 30, 59, 1); font-family: 'Alibaba-PuHuiTi-Bold'; margin: 10px 0 0 0"
{{ props.title }} :style="{ fontSize: fontLevelMap[props.fontLevel] }"
</div> >
</el-col> {{ props.title }}
<el-col> </div>
<p style="color: rgba(154, 154, 154, 1);font-size: 14px;"> </el-col>
{{ props.subtitle }} <el-col>
</p> <p style="color: rgba(154, 154, 154, 1); font-size: 14px">
</el-col> {{ props.subtitle }}
</p>
</el-row> </el-col>
</el-row>
</template> </template>
<script setup> <script setup>
const props = defineProps({ const props = defineProps({
title: String, title: String,
subtitle: String, subtitle: String,
fontLevel: { fontLevel: {
type: Number, type: Number,
default: 1 default: 1
} }
}) });
const fontLevelMap = { const fontLevelMap = {
1: "24px", 1: '24px',
2: "18px" 2: '18px'
} };
</script> </script>

View File

@ -1,224 +1,218 @@
<template> <template>
<div class="cardItem"> <div class="cardItem">
<el-card> <el-card>
<div class="tianqi" <div
style="display: flex;flex-direction: column;align-items: center;background-color: #FAFAFA;border-radius: 10px;padding-bottom: 40px;"> class="tianqi"
<div> style="display: flex; flex-direction: column; align-items: center; background-color: #fafafa; border-radius: 10px; padding-bottom: 40px"
<img src="/assets/demo/Sunny.png" style="display: block; width: 100px;height: 100px;" alt=""> >
</div> <div>
<div style="font-family: 'Alibaba-PuHuiTi-Bold';font-size: 24px;"> <img src="/assets/demo/sunnyBig.png" style="display: block; width: 100px; height: 100px" alt="" />
31 </div>
</div> <div style="font-family: 'Alibaba-PuHuiTi-Bold'; font-size: 24px">31</div>
<div>晴朗</div> <div>晴朗</div>
<div style="color: rgba(154, 154, 154, 1);font-size: 14px;"> <div style="color: rgba(154, 154, 154, 1); font-size: 14px">紫外线强度<span></span></div>
紫外线强度<span></span> <div class="tianqi2">
</div> <div class="item">
<div class="tianqi2"> <div>
<div class="item"> <img src="/assets/demo/shidu.png" alt="" />
<div>
<img src="/assets/demo/shidu.png" alt="">
</div>
<div class="text">相对湿度 <span>45%</span></div>
</div>
<div class="item">
<div>
<img src="/assets/demo/qiangdu.png" alt="">
</div>
<div class="text">光照强度 <span>45%</span></div>
</div>
<div class="item">
<div>
<img src="/assets/demo/fengshu.png" alt="">
</div>
<div class="text">风速 <span>2.3m/s</span></div>
</div>
<div class="item">
<div>
<img src="/assets/demo/riluo.png" alt="">
</div>
<div class="text">日落时间 <span>19.45</span></div>
</div>
</div>
</div> </div>
<div class="weather-timeline"> <div class="text">相对湿度 <span>45%</span></div>
<div class="time-box"> </div>
<div class="time-item"> <div class="item">
<div class="time">16:00</div> <div>
<div class="temp">30°C</div> <img src="/assets/demo/qiangdu.png" alt="" />
<div class="img-box">
<img src="/assets/demo/sunny_s.png" alt="">
</div>
</div>
<div class="time-item">
<div class="time">17:00</div>
<div class="temp">29°C</div>
<div class="img-box">
<img src="/assets/demo/sunny_s.png" alt="">
</div>
</div>
<div class="time-item">
<div class="child">
<div class="time">18:00</div>
<div class="temp">25°C</div>
<div class="img-box">
<img src="/assets/demo/rain.png" alt="">
</div>
</div>
</div>
<div class="time-item show">
<div class="time">现在</div>
<div class="temp">25°C</div>
<div class="img-box">
<img src="/assets/demo/rain_show.png" alt="">
</div>
</div>
<div class="time-item">
<div class="time">20:00</div>
<div class="temp">25°C</div>
<div class="img-box">
<img src="/assets/demo/yin.png" alt="">
</div>
</div>
<div class="time-item">
<div class="time">21:00</div>
<div class="temp">20°C</div>
<div class="img-box">
<img src="/assets/demo/yin.png" alt="">
</div>
</div>
</div>
</div> </div>
</el-card> <div class="text">光照强度 <span>45%</span></div>
</div> </div>
<div class="item">
<div>
<img src="/assets/demo/fengshu.png" alt="" />
</div>
<div class="text">风速 <span>2.3m/s</span></div>
</div>
<div class="item">
<div>
<img src="/assets/demo/riluo.png" alt="" />
</div>
<div class="text">日落时间 <span>19.45</span></div>
</div>
</div>
</div>
<div class="weather-timeline">
<div class="time-box">
<div class="time-item">
<div class="time">16:00</div>
<div class="temp">30°C</div>
<div class="img-box">
<img src="/assets/demo/sunny_s.png" alt="" />
</div>
</div>
<div class="time-item">
<div class="time">17:00</div>
<div class="temp">29°C</div>
<div class="img-box">
<img src="/assets/demo/sunny_s.png" alt="" />
</div>
</div>
<div class="time-item">
<div class="child">
<div class="time">18:00</div>
<div class="temp">25°C</div>
<div class="img-box">
<img src="/assets/demo/rain.png" alt="" />
</div>
</div>
</div>
<div class="time-item show">
<div class="time">现在</div>
<div class="temp">25°C</div>
<div class="img-box">
<img src="/assets/demo/rain_show.png" alt="" />
</div>
</div>
<div class="time-item">
<div class="time">20:00</div>
<div class="temp">25°C</div>
<div class="img-box">
<img src="/assets/demo/yin.png" alt="" />
</div>
</div>
<div class="time-item">
<div class="time">21:00</div>
<div class="temp">20°C</div>
<div class="img-box">
<img src="/assets/demo/yin.png" alt="" />
</div>
</div>
</div>
</div>
</el-card>
</div>
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
.cardItem { .cardItem {
padding: -20px !important; padding: -20px !important;
} }
.tianqi2 { .tianqi2 {
width: 100%; width: 100%;
display: flex;
justify-content: space-around;
margin-top: 50px;
img {
width: 40px;
height: 40x;
display: block;
}
.item {
display: flex; display: flex;
justify-content: space-around; flex-direction: column;
margin-top: 50px; align-items: center;
font-size: 14px;
img { .text {
width: 40px; margin-top: 10px;
height: 40x;
display: block;
} }
}
.item {
display: flex;
flex-direction: column;
align-items: center;
font-size: 14px;
.text {
margin-top: 10px;
}
}
} }
.weather-timeline { .weather-timeline {
text-align: center; text-align: center;
color: #fff; color: #fff;
font-size: 14px; font-size: 14px;
margin: 15px 0; margin: 15px 0;
.time { .time {
margin: 10px 0; margin: 10px 0;
} }
.img-box { .img-box {
width: 40px; width: 40px;
height: 40px; height: 40px;
margin: 10px 0; margin: 10px 0;
} }
img { img {
width: 100%; width: 100%;
height: 100%; height: 100%;
display: block; display: block;
} }
// img[src*='Sunny'] { // img[src*='Sunny'] {
// width: 50px; // width: 50px;
// height: 50px; // height: 50px;
// } // }
// img[src*='rain'] { // img[src*='rain'] {
// width: 60px; // width: 60px;
// height: 60px; // height: 60px;
// } // }
padding: 15px;
background: linear-gradient(to right, #d6e2ff, #deebff);
border-radius: 15px;
padding: 15px; .time-box {
background: linear-gradient(to right, #D6E2FF, #DEEBFF); background: linear-gradient(to right, #447bff, #67a3fd);
border-radius: 15px; display: flex;
justify-content: space-between;
border-radius: 10px;
padding: 10px 20px;
align-items: center;
}
.time-box { .time-item.show {
background: linear-gradient(to right, #447BFF, #67A3FD); color: rgba(24, 109, 245, 1);
display: flex; position: relative;
justify-content: space-between; // z-index: 888;
border-radius: 10px; background-color: #fff;
padding: 10px 20px; padding: 0 5px;
align-items: center; }
}
.time-item.show { .show::after {
color: rgba(24, 109, 245, 1); // color: rgba(24, 109, 245, 1);
position: relative; // position: relative;
// z-index: 888; // z-index: 888;
background-color: #fff; // background-color: #fff;
padding: 0 5px; content: '';
position: absolute;
width: 100%;
height: 25px;
// background-color: red;
background-color: #fff;
left: 0;
border-radius: 0 0 25px 25px;
}
} .show::before {
// color: rgba(24, 109, 245, 1);
// position: relative;
// z-index: 888;
// background-color: #fff;
content: '';
position: absolute;
width: 100%;
height: 25px;
// background-color: red;
background-color: #fff;
left: 0;
top: -25px;
border-radius: 25px 25px 0 0;
}
.show::after { // .show::after {
// color: rgba(24, 109, 245, 1); // content: '';
// position: relative; // position: absolute;
// z-index: 888; // height: 155px;
// background-color: #fff; // background-color: #fff;
content: ''; // z-index: 999;
position: absolute; // width: 100%;
width: 100%; // top: -25px;
height: 25px; // left: 0;
// background-color: red; // border-radius: 20px;
background-color: #fff; // }
left: 0;
border-radius: 0 0 25px 25px;
}
.show::before {
// color: rgba(24, 109, 245, 1);
// position: relative;
// z-index: 888;
// background-color: #fff;
content: '';
position: absolute;
width: 100%;
height: 25px;
// background-color: red;
background-color: #fff;
left: 0;
top: -25px;
border-radius: 25px 25px 0 0;
}
// .show::after {
// content: '';
// position: absolute;
// height: 155px;
// background-color: #fff;
// z-index: 999;
// width: 100%;
// top: -25px;
// left: 0;
// border-radius: 20px;
// }
} }
</style> </style>
<script setup> <script setup></script>
</script>

View File

@ -11,6 +11,7 @@
:id="form.id" :id="form.id"
:status="form.status" :status="form.status"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>
<!-- 表单区域 --> <!-- 表单区域 -->

View File

@ -7,7 +7,7 @@
<el-form :model="state.queryForm" :inline="true"> <el-form :model="state.queryForm" :inline="true">
<el-form-item label="版本号" prop="versions"> <el-form-item label="版本号" prop="versions">
<el-select v-model="state.queryForm.versions" placeholder="选择版本号" @change="handleChangeVersion"> <el-select v-model="state.queryForm.versions" placeholder="选择版本号" @change="handleChangeVersion">
<el-option v-for="item in state.options" :key="item.versions" :label="item.versions" :value="item.versions" /> <el-option v-for="item in state.options" :key="item.versions" :label="item.versionsName" :value="item.versions" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="表名" prop="sheet"> <el-form-item label="表名" prop="sheet">
@ -48,7 +48,7 @@
<el-form :model="state.queryForm" :inline="true"> <el-form :model="state.queryForm" :inline="true">
<el-form-item label="版本号" prop="versions"> <el-form-item label="版本号" prop="versions">
<el-select v-model="state.queryForm.versions" placeholder="选择版本号" @change="handleChangeVersion"> <el-select v-model="state.queryForm.versions" placeholder="选择版本号" @change="handleChangeVersion">
<el-option v-for="item in state.options" :key="item.versions" :label="item.versions" :value="item.versions" /> <el-option v-for="item in state.options" :key="item.versions" :label="item.versionsName" :value="item.versions" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>

View File

@ -11,6 +11,7 @@
:id="form.versions" :id="form.versions"
:status="form.status" :status="form.status"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>
<!-- 表单区域 --> <!-- 表单区域 -->

View File

@ -11,6 +11,7 @@
:id="form.versions" :id="form.versions"
:status="form.status" :status="form.status"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>
<!-- 表单区域 --> <!-- 表单区域 -->

View File

@ -11,6 +11,7 @@
:id="form.versions" :id="form.versions"
:status="form.status" :status="form.status"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>
<!-- 表单区域 --> <!-- 表单区域 -->

View File

@ -11,6 +11,7 @@
:id="form.versions" :id="form.versions"
:status="form.status" :status="form.status"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>
<!-- 表单区域 --> <!-- 表单区域 -->

View File

@ -11,6 +11,7 @@
:id="form.id" :id="form.id"
:status="form.status" :status="form.status"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>
<!-- 表单区域 --> <!-- 表单区域 -->

View File

@ -11,6 +11,7 @@
:id="form.id" :id="form.id"
:status="form.status" :status="form.status"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>
<!-- 表单区域 --> <!-- 表单区域 -->

View File

@ -11,6 +11,7 @@
:id="form.id" :id="form.id"
:status="form.status" :status="form.status"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>
<!-- 表单区域 --> <!-- 表单区域 -->

View File

@ -11,6 +11,7 @@
:id="form.design" :id="form.design"
:status="form.auditStatus" :status="form.auditStatus"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>
<!-- 表单区域 --> <!-- 表单区域 -->

View File

@ -11,6 +11,7 @@
:id="form.id" :id="form.id"
:status="form.status" :status="form.status"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>

View File

@ -11,6 +11,7 @@
:id="form.id" :id="form.id"
:status="form.status" :status="form.status"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>
<!-- 表单区域 --> <!-- 表单区域 -->

View File

@ -11,6 +11,7 @@
:id="form.id" :id="form.id"
:status="form.status" :status="form.status"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>

View File

@ -11,6 +11,7 @@
:id="form.id" :id="form.id"
:status="form.status" :status="form.status"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>

View File

@ -11,6 +11,7 @@
:id="form.id" :id="form.id"
:status="form.status" :status="form.status"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>
<!-- 表单区域 --> <!-- 表单区域 -->

View File

@ -11,6 +11,7 @@
:id="form.id" :id="form.id"
:status="form.auditStatus" :status="form.auditStatus"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>
<!-- 表单区域 --> <!-- 表单区域 -->

View File

@ -11,6 +11,7 @@
:id="form.id" :id="form.id"
:status="form.auditStatus" :status="form.auditStatus"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>
<!-- 表单区域 --> <!-- 表单区域 -->

View File

@ -0,0 +1,756 @@
<template>
<div>
<div class="operation-inspection">
<div class="navigation-tabs">
<div class="nav-tab" @click="handleInspection1">待办事项</div>
<div class="nav-tab active" @click="handleInspection2">巡检管理</div>
<div class="nav-tab">试验管理</div>
<div class="nav-tab">报修管理</div>
<div class="nav-tab">抢修管理</div>
<div class="nav-tab">工单管理</div>
</div>
<TitleComponent title="运维巡检管理" subtitle="制定巡检计划,安排巡检任务,跟进巡检记录"></TitleComponent>
<!-- 选项卡和按钮组合 -->
<div class="tabs-wrapper">
<div style="display: flex; align-items: center; gap: 10px">
<el-button type="primary" @click="handleInspectionManagement1">巡检计划</el-button>
<el-button type="primary" @click="handleInspectionManagement2">巡检任务</el-button>
<el-button type="primary" @click="handleInspectionManagement3">巡检记录</el-button>
</div>
</div>
<!-- 筛选栏 -->
<div class="filter-bar">
<div class="filter-item">
<el-select v-model="planType" placeholder="计划类型" clearable>
<el-option label="全部类型" value="all"></el-option>
<el-option label="每日巡检" value="daily"></el-option>
<el-option label="每周巡检" value="weekly"></el-option>
<el-option label="每月巡检" value="monthly"></el-option>
<el-option label="每季度巡检" value="quarterly"></el-option>
</el-select>
</div>
<div class="filter-item">
<el-select v-model="status" placeholder="全部状态" clearable>
<el-option label="全部状态" value="all"></el-option>
<el-option label="启用中" value="enabled"></el-option>
<el-option label="已停用" value="disabled"></el-option>
</el-select>
</div>
<div class="filter-item">
<el-select v-model="inspectionObject" placeholder="巡检对象" clearable>
<el-option label="全部对象" value="all"></el-option>
<el-option label="服务器" value="server"></el-option>
<el-option label="网络设备" value="network"></el-option>
<el-option label="应用系统" value="application"></el-option>
<el-option label="基础设施" value="infrastructure"></el-option>
</el-select>
</div>
<div class="filter-actions">
<el-button type="primary" class="search-btn">搜索</el-button>
<el-button type="primary" icon="el-icon-plus" class="create-btn" @click="handleCreate">手动创建计划</el-button>
</div>
</div>
<!-- 表格 -->
<div class="table-wrapper">
<el-table :data="pagedTableData" stripe style="width: 100%" highlight-current-row class="custom-table">
<el-table-column align="center" prop="name" label="计划名称" style="width: 14.2%"></el-table-column>
<el-table-column align="center" prop="type" label="类型" style="width: 14.2%"></el-table-column>
<el-table-column align="center" prop="object" label="巡检对象" style="width: 14.2%"></el-table-column>
<el-table-column align="center" prop="frequency" label="频率" style="width: 14.2%"></el-table-column>
<el-table-column align="center" prop="status" label="状态" style="width: 14.2%">
<template #default="scope">
<el-tag :type="scope.row.status === 'enabled' ? 'success' : 'info'" class="status-tag">
{{ scope.row.status === 'enabled' ? '启用中' : '已停用' }}
</el-tag>
</template>
</el-table-column>
<el-table-column align="center" prop="responsible" label="负责人" style="width: 14.2%"></el-table-column>
<el-table-column align="center" label="操作" style="width: 14.2%" fixed="right">
<template #default="scope">
<el-button type="text" @click="handleEdit(scope.row)" size="small" class="action-btn">编辑</el-button>
<el-button type="text" @click="handleDetail(scope.row)" size="small" class="action-btn">详情</el-button>
<el-button
type="text"
:disabled="scope.row.status === 'disabled'"
@click="handleEnable(scope.row)"
size="small"
class="action-btn"
:class="{ 'text-success': scope.row.status === 'disabled' }"
>
{{ scope.row.status === 'enabled' ? '停用' : '启用' }}
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页区域 -->
<div class="pagination-section">
<div class="pagination-info">
显示第{{ (currentPage - 1) * pageSize + 1 }}{{ Math.min(currentPage * pageSize, total) }}共有{{ total }}条记录
</div>
<div class="pagination-controls">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[10, 20, 30, 40]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
background
>
</el-pagination>
</div>
</div>
</div>
<!-- 创建计划弹窗 -->
<el-dialog v-model="dialogVisible" title="新建巡检计划" width="700px" class="create-plan-dialog" center :show-close="true">
<el-form :model="createForm" :rules="createFormRules" ref="createFormRef" label-width="150px" class="custom-form">
<el-form-item label="计划名称*" prop="planName" class="form-item-large">
<el-input v-model="createForm.planName" placeholder="请输入计划名称" class="custom-input" />
</el-form-item>
<div class="form-row">
<el-form-item label="计划类型*" prop="planType" class="form-item-half">
<el-select v-model="createForm.planType" placeholder="请选择计划类型" class="custom-select">
<el-option label="每日巡检" value="daily" />
<el-option label="每周巡检" value="weekly" />
<el-option label="每月巡检" value="monthly" />
<el-option label="每季度巡检" value="quarterly" />
</el-select>
</el-form-item>
<el-form-item label="巡检对象类型*" prop="objectType" class="form-item-half">
<el-select v-model="createForm.objectType" placeholder="请选择对象类型" class="custom-select">
<el-option label="服务器" value="server" />
<el-option label="网络设备" value="network" />
<el-option label="应用系统" value="application" />
<el-option label="基础设施" value="infrastructure" />
</el-select>
</el-form-item>
</div>
<div class="form-row">
<el-form-item label="开始日期*" prop="startDate" class="form-item-half">
<el-date-picker
v-model="createForm.startDate"
type="date"
placeholder="选择日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
class="custom-date-picker"
/>
</el-form-item>
<el-form-item label="结束日期*" prop="endDate" class="form-item-half">
<el-date-picker
v-model="createForm.endDate"
type="date"
placeholder="选择日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
class="custom-date-picker"
/>
</el-form-item>
</div>
<el-form-item label="巡检频率*" class="form-item-large">
<div style="display: flex; align-items: center; gap: 20px">
<el-radio-group v-model="createForm.frequencyType" class="frequency-radio-group">
<el-radio label="daily">每天</el-radio>
<el-radio label="weekly">每周</el-radio>
<el-radio label="monthly">每月</el-radio>
</el-radio-group>
<!-- 每周选择框 - 变小并排在单选框后面 -->
<el-select
v-if="createForm.frequencyType === 'weekly'"
v-model="createForm.weekday"
placeholder="选择周几"
class="custom-select-small"
style="width: 100px"
>
<el-option label="周一" value="1" />
<el-option label="周二" value="2" />
<el-option label="周三" value="3" />
<el-option label="周四" value="4" />
<el-option label="周五" value="5" />
<el-option label="周六" value="6" />
<el-option label="周日" value="0" />
</el-select>
<!-- 每月选择框 - 变小并排在单选框后面 -->
<el-select
v-if="createForm.frequencyType === 'monthly'"
v-model="createForm.monthday"
placeholder="选择几号"
class="custom-select-small"
style="width: 100px"
>
<template v-for="day in 31" :key="day">
<el-option :label="day + '号'" :value="day" />
</template>
</el-select>
</div>
</el-form-item>
<div class="form-row" s>
<el-form-item label="计划开始时间*" prop="startTime" class="form-item-half">
<el-time-picker v-model="createForm.startTime" placeholder="选择时间" format="HH:mm" value-format="HH:mm" class="custom-time-picker" />
</el-form-item>
<el-form-item label="预计时长(分钟)" class="form-item-half">
<el-input v-model.number="createForm.estimatedDuration" class="custom-input" />
</el-form-item>
</div>
<el-form-item label="负责人*" prop="responsiblePerson" class="form-item-large">
<el-select v-model="createForm.responsiblePerson" placeholder="请选择负责人" class="custom-select">
<el-option label="张明" value="zhangming" />
<el-option label="李华" value="lihua" />
<el-option label="王强" value="wangqiang" />
</el-select>
</el-form-item>
<el-form-item label="巡检项*" class="form-item-large">
<el-checkbox-group v-model="createForm.inspectionItems" style="border: 0.1 solid black; padding: 5px">
<el-checkbox label="CPU使用率检查" />
<el-checkbox label="内存使用情况" />
<el-checkbox label="磁盘空间检查" />
<el-checkbox label="网络连接状态" />
<el-checkbox label="系统日志检查" />
</el-checkbox-group>
</el-form-item>
<el-form-item label="备注说明" prop="remarks" class="form-item-large">
<el-input v-model="createForm.remarks" type="textarea" placeholder="请输入备注" rows="3" class="custom-textarea" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="cancelCreatePlan">取消</el-button>
<el-button type="primary" @click="submitCreatePlan">新增任务</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup>
// 表单引用
const createFormRef = ref(null);
import { ref, computed, reactive } from 'vue';
import router from '@/router';
import TitleComponent from '@/views/demo/components/TitleComponent.vue';
// 激活的选项卡
const activeTab = ref('plan');
// 计划类型
const planType = ref('all');
// 状态
const status = ref('all');
// 巡检对象
const inspectionObject = ref('all');
// 原始表格数据
const rawTableData = ref([
{
name: '生产服务器每日巡检 2025-05-14',
type: '每日巡检',
object: '服务器',
frequency: '每天8:30',
status: 'enabled',
responsible: '张明'
},
{
name: '网络设备安全巡检 2025-04-15',
type: '每周巡检',
object: '网络设备',
frequency: '每天10:30',
status: 'enabled',
responsible: '张明'
},
{
name: '数据库性能巡检 2025-03-03',
type: '每月巡检',
object: '应用系统',
frequency: '每月1日14:00',
status: 'disabled',
responsible: '张明'
},
{
name: '机房环境季度检查',
type: '每季度巡检',
object: '基础设备',
frequency: '每季度第一个月5号',
status: 'enabled',
responsible: '张明'
},
{
name: '生产服务器每日巡检 2025-05-14',
type: '每日巡检',
object: '服务器',
frequency: '每天8:30',
status: 'enabled',
responsible: '张明'
},
{
name: '生产服务器每日巡检 2025-05-14',
type: '每日巡检',
object: '服务器',
frequency: '每天8:30',
status: 'enabled',
responsible: '张明'
},
{
name: '生产服务器每日巡检 2025-05-14',
type: '每日巡检',
object: '服务器',
frequency: '每天8:30',
status: 'enabled',
responsible: '张明'
},
{
name: '生产服务器每日巡检 2025-05-14',
type: '每日巡检',
object: '服务器',
frequency: '每天8:30',
status: 'enabled',
responsible: '张明'
},
{
name: '生产服务器每日巡检 2025-05-14',
type: '每日巡检',
object: '服务器',
frequency: '每天8:30',
status: 'enabled',
responsible: '张明'
},
{
name: '生产服务器每日巡检 2025-05-14',
type: '每日巡检',
object: '服务器',
frequency: '每天8:30',
status: 'enabled',
responsible: '张明'
},
{
name: '生产服务器每日巡检 2025-05-14',
type: '每日巡检',
object: '服务器',
frequency: '每天8:30',
status: 'enabled',
responsible: '张明'
},
// 增加更多数据用于测试分页
{
name: '应用系统安全检查',
type: '每周巡检',
object: '应用系统',
frequency: '每周五16:00',
status: 'enabled',
responsible: '李华'
},
{
name: '网络带宽监控',
type: '每日巡检',
object: '网络设备',
frequency: '每天12:00',
status: 'enabled',
responsible: '王强'
}
]);
// 当前页码
const currentPage = ref(1);
// 每页条数 - 与分页控件默认值保持一致
const pageSize = ref(10);
// 总条数 - 从原始数据计算得出
const total = ref(rawTableData.value.length);
// 计算属性:根据当前页码和每页条数获取分页后的数据
const pagedTableData = computed(() => {
const startIndex = (currentPage.value - 1) * pageSize.value;
const endIndex = startIndex + pageSize.value;
return rawTableData.value.slice(startIndex, endIndex);
});
// 每页条数改变
const handleSizeChange = (val) => {
pageSize.value = val;
currentPage.value = 1; // 重置到第一页
};
// 当前页码改变
const handleCurrentChange = (val) => {
currentPage.value = val;
};
// 编辑
const handleEdit = (row) => {
console.log('编辑', row);
};
// 详情
const handleDetail = (row) => {
console.log('详情', row);
};
// 启用/停用
const handleEnable = (row) => {
row.status = row.status === 'enabled' ? 'disabled' : 'enabled';
};
// 选项卡切换
const handleTabChange = (newTab, oldTab) => {
// 可以在这里添加选项卡切换时的逻辑
console.log('选项卡切换:', newTab, oldTab);
return true;
};
// 创建计划弹窗相关
const dialogVisible = ref(false);
const createForm = reactive({
planName: '',
planType: '',
objectType: '',
startDate: '',
endDate: '',
frequencyType: 'daily',
frequencyValue: '',
weekday: '', // 存储周几
monthday: '', // 存储几号
startTime: '',
estimatedDuration: 60,
responsiblePerson: '',
inspectionItems: [],
remarks: ''
});
// 创建计划表单验证规则
const createFormRules = computed(() => ({
planName: [{ required: true, message: '请输入计划名称', trigger: 'blur' }],
planType: [{ required: true, message: '请选择计划类型', trigger: 'change' }],
objectType: [{ required: true, message: '请选择对象类型', trigger: 'change' }],
startDate: [{ required: true, message: '请选择开始日期', trigger: 'change' }],
endDate: [{ required: true, message: '请选择结束日期', trigger: 'change' }],
startTime: [{ required: true, message: '请选择开始时间', trigger: 'change' }],
responsiblePerson: [{ required: true, message: '请选择负责人', trigger: 'change' }],
weekday: createForm.frequencyType === 'weekly' ? [{ required: true, message: '请选择周几', trigger: 'change' }] : [],
monthday: createForm.frequencyType === 'monthly' ? [{ required: true, message: '请选择几号', trigger: 'change' }] : []
}));
// 打开创建计划弹窗
const handleCreate = () => {
dialogVisible.value = true;
};
// 提交创建计划
const submitCreatePlan = () => {
console.log('提交创建计划:', createForm);
// 这里可以添加实际的创建计划逻辑
dialogVisible.value = false;
// 重置表单
Object.keys(createForm).forEach((key) => {
if (Array.isArray(createForm[key])) {
createForm[key] = [];
} else if (key === 'estimatedDuration') {
createForm[key] = 60;
} else if (key === 'frequencyType') {
createForm[key] = 'daily';
} else {
createForm[key] = '';
}
});
};
// 取消创建计划
const cancelCreatePlan = () => {
dialogVisible.value = false;
// 重置表单
Object.keys(createForm).forEach((key) => {
if (Array.isArray(createForm[key])) {
createForm[key] = [];
} else if (key === 'estimatedDuration') {
createForm[key] = 60;
} else if (key === 'frequencyType') {
createForm[key] = 'daily';
} else {
createForm[key] = '';
}
});
};
const handleInspection1 = () => {
router.push('/rili/rili');
};
const handleInspection2 = () => {
router.push('/rili/InspectionManagement');
};
const handleInspectionManagement1 = () => {
router.push('/rili/InspectionManagement');
};
const handleInspectionManagement2 = () => {
router.push('/rili/xunjianrenwu');
};
const handleInspectionManagement3 = () => {
router.push('/rili/xunjianjihua');
};
</script>
<style scoped>
/* 样式保持不变 */
.operation-inspection {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
/* 标题区域样式 */
.title-section {
background-color: #fff;
padding: 20px;
border-radius: 8px;
margin-bottom: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.page-title {
font-size: 24px;
font-weight: 600;
color: #303133;
margin: 0 0 8px 0;
}
.page-subtitle {
font-size: 14px;
color: #909399;
margin: 0;
}
/* 选项卡样式 */
.tabs-wrapper {
background-color: #fff;
padding: 20px;
border-radius: 8px;
margin-bottom: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.custom-tabs {
border-bottom: none;
padding-top: 20px;
}
.custom-tabs .el-tabs__header {
margin: 0 -20px 0 -20px;
padding: 0 20px;
border-bottom: 1px solid #e4e7ed;
}
.custom-tabs .el-tabs__nav-wrap::after {
height: 0;
}
.custom-tabs .el-tabs__item {
font-size: 14px;
color: #606266;
padding: 12px 20px;
margin-right: 20px;
border-bottom: 2px solid transparent;
}
.custom-tabs .el-tabs__item.is-active {
color: #409eff;
border-bottom-color: #409eff;
}
.custom-tabs .el-tabs__item:hover {
color: #409eff;
}
/* 筛选栏样式 */
.filter-bar {
background-color: #fff;
padding: 20px;
border-radius: 8px;
margin-bottom: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 16px;
}
.filter-item {
flex-shrink: 0;
}
.filter-bar .el-select {
width: 150px;
height: 36px;
}
.filter-actions {
margin-left: auto;
display: flex;
gap: 10px;
}
.search-btn,
.create-btn {
height: 36px;
border-radius: 4px;
}
/* 表格样式 */
.table-wrapper {
background-color: #fff;
padding: 20px;
border-radius: 8px;
margin-bottom: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.custom-table {
border: 1px solid #ebeef5;
border-radius: 4px;
overflow: hidden;
}
.custom-table th {
background-color: #fafafa;
font-weight: 500;
color: #606266;
text-align: left;
padding: 12px 16px;
border-bottom: 1px solid #ebeef5;
}
.custom-table td {
padding: 12px 16px;
border-bottom: 1px solid #ebeef5;
color: #303133;
}
.custom-table tr:hover {
background-color: #f5f7fa;
}
.custom-table tr.current-row {
background-color: #ecf5ff;
}
.status-tag {
padding: 4px 8px;
font-size: 12px;
border-radius: 4px;
}
.action-btn {
color: #409eff;
font-size: 12px;
padding: 4px 8px;
}
.action-btn:hover {
color: #66b1ff;
background-color: #ecf5ff;
}
/* 分页区域样式 */
.pagination-section {
background-color: #fff;
padding: 16px 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
display: flex;
justify-content: space-between;
align-items: center;
}
.pagination-info {
font-size: 14px;
color: #606266;
}
.pagination-controls .el-pagination {
margin: 0;
}
.pagination-controls .el-pagination__sizes {
margin-right: 20px;
}
.pagination-controls .el-pagination button {
min-width: 32px;
height: 32px;
line-height: 32px;
border-radius: 4px;
}
.pagination-controls .el-pagination .el-pager li {
min-width: 32px;
height: 32px;
line-height: 32px;
border-radius: 4px;
}
.pagination-controls .el-pagination .el-pager li.active {
background-color: #409eff;
color: #fff;
}
/* 导航栏样式 */
.navigation-tabs {
display: flex;
margin-bottom: 20px;
background-color: #fff;
border-radius: 4px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
padding: 2px;
}
.nav-tab {
padding: 12px 24px;
cursor: pointer;
transition: all 0.3s ease;
border-radius: 4px;
font-size: 14px;
color: #606266;
border-right: 1px solid #f0f0f0;
flex: 1;
text-align: center;
}
.nav-tab:last-child {
border-right: none;
}
.nav-tab:hover {
color: #409eff;
background-color: #ecf5ff;
}
.nav-tab.active {
background-color: #409eff;
color: #fff;
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
}
.nav-tab {
cursor: pointer;
user-select: none;
}
/* 响应式设计 */
@media (max-width: 1200px) {
.filter-bar {
flex-direction: column;
align-items: stretch;
}
.filter-actions {
margin-left: 0;
justify-content: flex-end;
}
}
</style>

View File

@ -0,0 +1,700 @@
<template>
<div class="container">
<!-- 导航栏 -->
<div class="navigation-tabs">
<div class="nav-tab active" @click="handleInspection1">待办事项</div>
<div class="nav-tab" @click="handleInspection2">巡检管理</div>
<div class="nav-tab">试验管理</div>
<div class="nav-tab">报修管理</div>
<div class="nav-tab">抢修管理</div>
<div class="nav-tab">工单管理</div>
</div>
<!-- 标题栏 -->
<div class="header">
<TitleComponent title="运维待办事项" subtitle="管理每日、每周等的运维工作任务"></TitleComponent>
</div>
<div class="main-content">
<!-- 左侧日历区域 -->
<div class="calendar-container">
<div class="calendar-header">
<div class="calendar-title">待办月视图</div>
<div class="calendar-controls">
<!-- 年份月份选择 -->
<el-select v-model="selectedYear" placeholder="选择年份" size="small" style="width: 80px; margin-right: 5px">
<el-option v-for="year in years" :key="year" :label="year.toString()" :value="year"></el-option>
</el-select>
<el-select v-model="selectedMonth" placeholder="选择月份" size="small" style="width: 80px; margin-right: 10px">
<el-option v-for="month in 12" :key="month" :label="month.toString()" :value="month"></el-option>
</el-select>
<!-- 月份切换按钮 -->
<el-button type="text" icon="el-icon-arrow-left" @click="decreaseMonth"></el-button>
<el-button type="text" icon="el-icon-arrow-right" @click="increaseMonth"></el-button>
<el-button type="primary" size="small">添加</el-button>
<el-button type="primary" size="small" @click="goToToday">今日</el-button>
<el-button type="text" icon="el-icon-plus"></el-button>
</div>
</div>
<!-- 使用 Element Plus 的日历组件 -->
<el-calendar v-model="currentDate">
<template #date-cell="{ date, data }">
<div class="custom-date-cell" :class="getCellClass(data.day)">
<div class="date-day">{{ data.day.split('-').slice(2).join('-') }}</div>
<div class="date-events">
<div v-for="event in getDayEvents(data.day)" :key="event.id" class="event-item" :class="'event-' + event.type">
<div class="event-title">{{ event.title }}</div>
<div class="event-description">{{ event.description }}</div>
</div>
</div>
</div>
</template>
</el-calendar>
</div>
<!-- 右侧表单区域 -->
<div class="form-container">
<div class="form-header">
<h2>今日待办</h2>
<el-button type="primary" size="small" icon="el-icon-plus" @click="openAddTaskDialog">添加</el-button>
</div>
<!-- 待办事项列表 -->
<div class="todo-list">
<!-- 待办项1 - 常规维护 -->
<div class="todo-item">
<div class="todo-color-indicator normal"></div>
<el-checkbox class="todo-checkbox"></el-checkbox>
<div class="todo-content">
<div class="todo-main">
<div class="todo-title">服务器例行检查</div>
<div class="todo-time">09:00-10:00 AM</div>
</div>
<div class="todo-description">检查所有生产服务器的CPU内存磁盘使用率确保正常运行</div>
</div>
</div>
<!-- 待办项2 - 重要 -->
<div class="todo-item important">
<div class="todo-color-indicator important"></div>
<el-checkbox class="todo-checkbox"></el-checkbox>
<div class="todo-content">
<div class="todo-main">
<div class="todo-title">数据库备份</div>
<div class="todo-time">14:00-15:00 PM</div>
</div>
<div class="todo-description">主要数据库全备份并验证备份文件完整性</div>
</div>
<div class="todo-actions">
<el-button type="text" icon="el-icon-edit"></el-button>
<el-button type="text" icon="el-icon-delete"></el-button>
</div>
</div>
<!-- 待办项3 - 紧急 -->
<div class="todo-item">
<div class="todo-color-indicator urgent"></div>
<el-checkbox class="todo-checkbox"></el-checkbox>
<div class="todo-content">
<div class="todo-main">
<div class="todo-title">网络设备固件更新</div>
<div class="todo-time">18:00-20:00 PM</div>
</div>
<div class="todo-description">更新核心交换机和防火墙固件需安排在业务低峰期</div>
</div>
</div>
<!-- 待办项4 - 常规维护 -->
<div class="todo-item">
<div class="todo-color-indicator normal"></div>
<el-checkbox class="todo-checkbox"></el-checkbox>
<div class="todo-content">
<div class="todo-main">
<div class="todo-title">服务器例行检查</div>
<div class="todo-time">08:00-09:00 AM</div>
</div>
<div class="todo-description">检查所有生产服务器的CPU内存磁盘使用率确保正常运行</div>
</div>
</div>
<!-- 待办项5 - 常规维护 -->
<div class="todo-item">
<div class="todo-color-indicator normal"></div>
<el-checkbox class="todo-checkbox"></el-checkbox>
<div class="todo-content">
<div class="todo-main">
<div class="todo-title">服务器例行检查</div>
<div class="todo-time">06:00-07:00 AM</div>
</div>
<div class="todo-description">检查所有生产服务器的CPU内存磁盘使用率确保正常运行</div>
</div>
</div>
</div>
<!-- 状态图例 - 标签形式 -->
<div class="status-legend">
<span class="status-tag normal">常规维护</span>
<span class="status-tag important">重要</span>
<span class="status-tag urgent">紧急</span>
</div>
</div>
</div>
<el-dialog v-model="dialogVisible" title="新增任务" width="480px" class="custom-dialog" :before-close="closeDialog">
<el-form :model="taskForm" label-width="80px" class="task-form">
<el-form-item label="任务名称" prop="name">
<el-input v-model="taskForm.name" placeholder="输入任务名称" class="form-input"></el-input>
</el-form-item>
<el-form-item label="任务描述" prop="description">
<el-input v-model="taskForm.description" placeholder="输入任务描述" class="form-input"></el-input>
</el-form-item>
<el-form-item label="时间" prop="timeRange">
<el-date-picker
v-model="taskForm.timeRange"
type="datetimerange"
start-placeholder="开始时间"
end-placeholder="结束时间"
class="form-input"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="优先级" prop="priority">
<el-select v-model="taskForm.priority" placeholder="选择优先级" class="form-input">
<el-option label="常规项" value="常规项"></el-option>
<el-option label="重要" value="重要"></el-option>
<el-option label="紧急" value="紧急"></el-option>
</el-select>
</el-form-item>
<el-form-item label="任务类型" prop="taskType">
<el-select v-model="taskForm.taskType" placeholder="选择任务类型" class="form-input">
<el-option label="常规维护" value="常规维护"></el-option>
<el-option label="安全巡检" value="安全巡检"></el-option>
<el-option label="系统升级" value="系统升级"></el-option>
<el-option label="数据备份" value="数据备份"></el-option>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="closeDialog">取消</el-button>
<el-button type="primary" @click="saveTask">保存任务</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, computed, watch } from 'vue';
import router from '@/router';
import TitleComponent from '../demo/components/TitleComponent.vue';
// 生成年份选项生成2020-2029年的年份范围
const targetYear = 2025;
const years = ref(Array.from({ length: 10 }, (_, index) => 2020 + index));
const selectedYear = ref(targetYear);
const selectedMonth = ref(9);
// 默认显示2025年9月
const currentDate = ref(new Date(targetYear, 8, 1));
// 减少月份
const decreaseMonth = () => {
const date = new Date(currentDate.value);
date.setMonth(date.getMonth() - 1);
currentDate.value = date;
updateYearAndMonth();
};
// 增加月份
const increaseMonth = () => {
const date = new Date(currentDate.value);
date.setMonth(date.getMonth() + 1);
currentDate.value = date;
updateYearAndMonth();
};
// 回到今天
const goToToday = () => {
currentDate.value = new Date();
updateYearAndMonth();
};
// 日历事件数据 - 2025年9月的随机事件
const calendarEvents = ref([
// 服务维护事件
{ id: 1, date: '2025-09-11', title: '服务维护', description: '维护公司内部服务器', type: 'service' },
{ id: 2, date: '2025-09-28', title: '服务维护', description: '先所有旧服务器部署新内存', type: 'service' },
// 数据库管理事件
{ id: 3, date: '2025-09-21', title: '数据库管理', description: '定期执行数据库优化', type: 'database' },
{ id: 4, date: '2025-09-30', title: '数据库管理', description: '大型数据库备份策略', type: 'database' },
// 网络维护事件
{ id: 5, date: '2025-09-05', title: '网络维护', description: '网络设备例行检查', type: 'network' },
{ id: 6, date: '2025-09-15', title: '网络维护', description: '更新网络安全策略', type: 'network' },
// 系统升级事件
{ id: 7, date: '2025-09-18', title: '系统升级', description: '核心系统版本升级', type: 'upgrade' },
{ id: 8, date: '2025-09-25', title: '系统升级', description: '应用服务升级部署', type: 'upgrade' }
]);
// 获取指定日期的事件
const getDayEvents = (dateStr) => {
return calendarEvents.value.filter((event) => event.date === dateStr);
};
// 根据事件类型获取单元格样式
const getCellClass = (date) => {
const events = getDayEvents(date);
if (events.length > 0) {
const eventType = events[0].type;
return `date-cell-${eventType}`;
}
return '';
};
// 更新年份和月份选择器的值
const updateYearAndMonth = () => {
selectedYear.value = currentDate.value.getFullYear();
selectedMonth.value = currentDate.value.getMonth() + 1;
};
// 监听年份和月份变化,更新日历显示
watch([selectedYear, selectedMonth], ([newYear, newMonth]) => {
const date = new Date(currentDate.value);
date.setFullYear(newYear);
date.setMonth(newMonth - 1);
currentDate.value = date;
});
// 初始化年份和月份选择器
updateYearAndMonth();
// 弹窗相关状态管理
const dialogVisible = ref(false);
const taskForm = ref({
name: '',
description: '',
timeRange: '',
priority: '常规项',
taskType: '常规维护'
});
// 打开添加任务弹窗
const openAddTaskDialog = () => {
dialogVisible.value = true;
};
// 关闭弹窗
const closeDialog = () => {
dialogVisible.value = false;
};
// 保存任务
const saveTask = () => {
// 这里可以添加表单验证和保存逻辑
console.log('保存任务:', taskForm.value);
// 重置表单
taskForm.value = {
name: '',
description: '',
timeRange: '',
priority: '常规项',
taskType: '常规维护'
};
// 关闭弹窗
closeDialog();
};
const handleInspection1 = () => {
router.push('/rili/rili');
};
const handleInspection2 = () => {
router.push('/rili/InspectionManagement');
};
</script>
<style scoped>
.container {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
/* 导航栏样式 */
.navigation-tabs {
display: flex;
margin-bottom: 20px;
background-color: #fff;
border-radius: 4px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
padding: 2px;
}
.nav-tab {
padding: 12px 24px;
cursor: pointer;
transition: all 0.3s ease;
border-radius: 4px;
font-size: 14px;
color: #606266;
border-right: 1px solid #f0f0f0;
flex: 1;
text-align: center;
}
.nav-tab:last-child {
border-right: none;
}
.nav-tab:hover {
color: #409eff;
background-color: #ecf5ff;
}
.nav-tab.active {
background-color: #409eff;
color: #fff;
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
}
.nav-tab {
cursor: pointer;
user-select: none;
}
.header {
margin-bottom: 20px;
}
.header h1 {
font-size: 24px;
font-weight: 600;
color: #303133;
margin: 0;
}
.header p {
font-size: 14px;
color: #606266;
margin: 5px 0 0 0;
}
.main-content {
display: flex;
gap: 20px;
}
/* 日历区域样式 */
.calendar-container {
flex: 1;
background-color: #fff;
border-radius: 4px;
padding: 20px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
/* 自定义弹窗样式 */
.custom-dialog {
border-radius: 8px;
overflow: hidden;
}
.custom-dialog .el-dialog__header {
background-color: #f5f7fa;
border-bottom: 1px solid #e4e7ed;
padding: 15px 20px;
}
.custom-dialog .el-dialog__title {
font-size: 16px;
color: #303133;
}
.custom-dialog .el-dialog__body {
padding: 20px;
}
/* 确保所有输入框长度相等 */
.task-form .form-input {
height: 30px;
width: 100%;
}
/* 时间选择器样式调整 */
.task-form .el-date-editor {
width: 100%;
height: 30px;
}
.calendar-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.calendar-title {
font-size: 16px;
font-weight: 600;
color: #303133;
}
.calendar-controls {
display: flex;
align-items: center;
gap: 10px;
}
.el-select {
margin-right: 5px;
}
/* 表单区域样式 */
.form-container {
width: 400px;
background-color: #fff;
border-radius: 4px;
padding: 20px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.form-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 1px solid #f0f0f0;
}
.form-header h2 {
font-size: 16px;
font-weight: 600;
color: #303133;
margin: 0;
}
.todo-list {
display: flex;
flex-direction: column;
gap: 10px;
margin-bottom: 20px;
max-height: 400px;
overflow-y: auto;
}
.todo-item {
display: flex;
align-items: flex-start;
gap: 10px;
padding: 12px 12px 12px 20px;
background-color: #fafafa;
border-radius: 4px;
position: relative;
transition: all 0.3s ease;
}
/* 重要任务的背景色 */
.todo-item.important {
background-color: #e6f7ff;
}
.todo-checkbox {
margin-top: 2px;
flex-shrink: 0;
}
.todo-content {
flex: 1;
}
.todo-main {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 4px;
}
.todo-title {
font-size: 14px;
font-weight: 500;
color: #303133;
}
.todo-time {
font-size: 12px;
color: #909399;
}
.todo-description {
font-size: 12px;
color: #606266;
line-height: 1.4;
}
.todo-actions {
position: absolute;
right: 10px;
bottom: 10px;
display: flex;
gap: 5px;
}
.todo-actions .el-button {
padding: 4px 8px;
min-width: auto;
}
/* 状态图例 - 标签形式 */
.status-legend {
display: flex;
gap: 10px;
padding-top: 15px;
border-top: 1px solid #ebeef5;
}
.status-tag {
display: inline-block;
padding: 4px 12px;
border-radius: 16px;
font-size: 12px;
color: #fff;
}
.status-tag.normal {
background-color: #52c41a;
}
.status-tag.important {
background-color: #faad14;
}
.status-tag.urgent {
background-color: #ff4d4f;
}
.todo-color-indicator {
width: 8px;
height: 100%;
border-radius: 0 4px 4px 0;
position: absolute;
left: 0;
top: 0;
flex-shrink: 0;
}
.todo-color-indicator.normal {
background-color: #52c41a;
}
.todo-color-indicator.important {
background-color: #faad14;
}
.todo-color-indicator.urgent {
background-color: #ff4d4f;
}
/* 自定义日历单元格样式 */
.custom-date-cell {
padding: 5px;
text-align: center;
}
/* 系统升级事件样式 */
.event-upgrade {
background-color: #fff1f0;
color: #f5222d;
}
/* 日期单元格背景色 - 按事件类型 */
.date-cell-service {
background-color: #e6f7ff;
}
.date-cell-database {
background-color: #f0f9ff;
}
.date-cell-network {
background-color: #fffbe6;
}
.date-cell-upgrade {
background-color: #fff1f0;
}
/* 日历样式优化 */
.el-calendar {
width: 100%;
}
.el-calendar-table {
width: 100%;
}
.el-calendar-table td {
padding: 2px;
vertical-align: top;
}
.el-calendar-day {
height: 120px;
border-radius: 4px;
overflow: hidden;
}
.date-day {
font-weight: bold;
margin-bottom: 5px;
}
.date-events {
flex: 1;
overflow: hidden;
}
.event-item {
padding: 3px;
margin-bottom: 2px;
border-radius: 3px;
font-size: 12px;
}
.event-title {
font-weight: bold;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.event-description {
font-size: 11px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* 服务维护事件样式 */
.event-service {
background-color: #e6f7ff;
color: #1890ff;
}
/* 数据库管理事件样式 */
.event-database {
background-color: #f0f9ff;
color: #36cfc9;
}
/* 网络维护事件样式 */
.event-network {
background-color: #fffbe6;
color: #faad14;
}
/* 系统升级事件样式 */
.event-upgrade {
background-color: #fff1f0;
color: #f5222d;
}
</style>

View File

@ -0,0 +1,672 @@
<template>
<div class="operation-inspection">
<div class="navigation-tabs">
<div class="nav-tab" @click="handleInspection1">待办事项</div>
<div class="nav-tab active" @click="handleInspection2">巡检管理</div>
<div class="nav-tab">试验管理</div>
<div class="nav-tab">报修管理</div>
<div class="nav-tab">抢修管理</div>
<div class="nav-tab">工单管理</div>
</div>
<div style="display: flex; align-items: center; gap: 1200px">
<TitleComponent title="运维巡检管理" subtitle="制定巡检计划,安排巡检任务,跟进巡检记录"></TitleComponent>
<div style="display: flex; align-items: center; gap: 10px">
<el-button type="primary" class="export-btn">筛选</el-button>
<el-button type="primary" class="create-btn">导入数据</el-button>
</div>
</div>
<!-- 选项卡和按钮组合 -->
<div class="tabs-wrapper">
<div style="display: flex; align-items: center; gap: 10px">
<el-button type="primary" @click="handleInspectionManagement1">巡检计划</el-button>
<el-button type="primary" @click="handleInspectionManagement2">巡检任务</el-button>
<el-button type="primary" @click="handleInspectionManagement3">巡检记录</el-button>
</div>
</div>
<!-- 筛选栏 -->
<div class="filter-bar">
<div class="filter-item">
<el-select v-model="filterStatus" placeholder="状态" clearable>
<el-option label="全部状态" value="all"></el-option>
<el-option label="正常" value="normal"></el-option>
<el-option label="需关注" value="attention"></el-option>
<el-option label="有问题" value="problem"></el-option>
</el-select>
</div>
<div class="filter-item">
<el-select v-model="filterType" placeholder="巡检类型" clearable>
<el-option label="全部类型" value="all"></el-option>
<el-option label="数据库" value="database"></el-option>
<el-option label="服务器" value="server"></el-option>
<el-option label="网络设备" value="network"></el-option>
</el-select>
</div>
<div class="filter-item">
<el-date-picker
v-model="dateRange"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
></el-date-picker>
</div>
<div class="filter-actions">
<el-button type="primary" class="search-btn">搜索</el-button>
</div>
</div>
<!-- 主内容区 -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6" style="grid-auto-rows: 1fr">
<!-- 左侧和中间内容区 -->
<div class="lg:col-span-2 space-y-6">
<!-- 巡检记录与报告卡片 -->
<div class="content-card">
<div class="card-header">
<h2 class="card-title">巡检记录与报告</h2>
<div class="flex space-x-2">
<button
class="px-3 py-1 text-sm rounded-md hover:bg-gray-200 transition"
:class="{ 'bg-gray-100 text-gray-700': timeRange === 'month', 'bg-white text-gray-500': timeRange !== 'month' }"
@click="handleTimeRangeChange('month')"
>
</button>
<button
class="px-3 py-1 text-sm rounded-md hover:bg-gray-100 transition"
:class="{ 'bg-gray-100 text-gray-700': timeRange === 'week', 'bg-white text-gray-500': timeRange !== 'week' }"
@click="handleTimeRangeChange('week')"
>
</button>
<button
class="px-3 py-1 text-sm rounded-md hover:bg-gray-100 transition"
:class="{ 'bg-gray-100 text-gray-700': timeRange === 'day', 'bg-white text-gray-500': timeRange !== 'day' }"
@click="handleTimeRangeChange('day')"
>
</button>
</div>
</div>
<!-- 数据卡片 -->
<div class="card-body">
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div class="stat-card">
<p class="stat-label">本月完成巡检</p>
<p class="stat-value">42</p>
</div>
<div class="stat-card">
<p class="stat-label">发现问题数</p>
<p class="stat-value">7</p>
</div>
<div class="stat-card">
<p class="stat-label">已解决问题</p>
<p class="stat-value">5</p>
</div>
<div class="stat-card">
<p class="stat-label">平均完成时间</p>
<p class="stat-value">45分钟</p>
</div>
</div>
<div class="divider"></div>
<!-- 图表区域 -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 py-4">
<!-- 饼图 - 本月巡检完成情况 -->
<div class="md:col-span-1">
<p class="chart-title">本月完成巡检</p>
<div class="relative w-32 h-32 mx-auto">
<!-- 饼图使用SVG绘制 - 显示本月巡检完成情况 -->
<svg class="w-full h-full" viewBox="0 0 100 100">
<!-- 背景圆环 -->
<circle cx="50" cy="50" r="45" fill="none" stroke="#f3f4f6" stroke-width="10" />
<!-- 已完成部分 (72%) -->
<circle
cx="50"
cy="50"
r="45"
fill="none"
stroke="#10b981"
stroke-width="10"
stroke-dasharray="282.74"
stroke-dashoffset="113.1"
transform="rotate(-90 50 50)"
/>
<!-- 未完成部分 (28%) -->
<circle
cx="50"
cy="50"
r="45"
fill="none"
stroke="#f97316"
stroke-width="10"
stroke-dasharray="113.1"
stroke-dashoffset="0"
transform="rotate(-90 50 50)"
/>
</svg>
<!-- 饼图中心显示 -->
<div class="absolute inset-0 flex flex-col items-center justify-center">
<p class="text-sm text-gray-500">已解决问题</p>
<p class="text-lg font-bold text-gray-800">72%</p>
</div>
</div>
<!-- 饼图图例 -->
<div class="mt-3 flex justify-center space-x-4">
<div class="flex items-center">
<div class="w-3 h-3 rounded-full bg-green-500 mr-1"></div>
<span class="text-xs text-gray-600">已解决</span>
</div>
<div class="flex items-center">
<div class="w-3 h-3 rounded-full bg-orange-500 mr-1"></div>
<span class="text-xs text-gray-600">未解决</span>
</div>
</div>
</div>
<!-- 进度条 -->
<div class="md:col-span-2 flex flex-col justify-center">
<div class="space-y-4">
<div>
<div class="flex justify-between text-sm mb-1">
<span class="text-gray-600">完成率</span>
<span class="font-medium text-gray-800">68%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2">
<div class="bg-red-500 h-2 rounded-full" style="width: 68%"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1">
<span class="text-gray-600">解决率</span>
<span class="font-medium text-gray-800">72%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2">
<div class="bg-green-500 h-2 rounded-full" style="width: 72%"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1">
<span class="text-gray-600">及时率</span>
<span class="font-medium text-gray-800">60%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2">
<div class="bg-gray-500 h-2 rounded-full" style="width: 60%"></div>
</div>
</div>
</div>
</div>
</div>
<div class="divider"></div>
<!-- 发现问题种类 -->
<div class="py-4">
<h3 class="section-title">发现问题种类</h3>
<div class="space-y-4">
<div>
<div class="flex justify-between text-sm mb-1">
<span class="text-gray-600">温度异常率</span>
<span class="text-gray-500">85%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2">
<div class="bg-blue-500 h-2 rounded-full" style="width: 85%"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1">
<span class="text-gray-600">内存使用率</span>
<span class="text-gray-500">62%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2">
<div class="bg-blue-500 h-2 rounded-full" style="width: 62%"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1">
<span class="text-gray-600">CPU负载</span>
<span class="text-gray-500">45%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2">
<div class="bg-blue-500 h-2 rounded-full" style="width: 45%"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1">
<span class="text-gray-600">响应时间</span>
<span class="text-gray-500">30%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2">
<div class="bg-blue-500 h-2 rounded-full" style="width: 30%"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1">
<span class="text-gray-600">磁盘空间状态</span>
<span class="text-gray-500">15%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2">
<div class="bg-blue-500 h-2 rounded-full" style="width: 15%"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 右侧最近巡检结果 -->
<div class="lg:col-span-1" style="display: flex; flex-direction: column; height: 100%">
<div class="content-card" style="flex: 1; display: flex; flex-direction: column">
<div class="card-header">
<h2 class="card-title">最近巡检结果</h2>
</div>
<!-- 巡检结果列表 -->
<div class="card-body" style="flex: 1; overflow-y: auto">
<div class="inspection-results space-y-4">
<!-- 结果1正常 -->
<div class="inspection-card bg-white border border-gray-200 rounded-lg p-4 shadow-sm">
<div class="flex justify-between items-start mb-4">
<h3 class="text-lg font-medium text-gray-800">数据库性能巡检</h3>
<span class="status-tag status-normal px-3 py-1 text-xs">正常</span>
</div>
<p class="text-sm text-gray-500 mb-3">2025-06-15 14:00-16:45 张明</p>
<div class="flex justify-between items-center mb-4">
<div class="flex flex-col items-center">
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">系统连接量</span>
<span class="text-sm font-medium">128<500</span>
</div>
<div class="flex flex-col items-center">
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">查询响应时间</span>
<span class="text-sm font-medium">平均0.3S</span>
</div>
<div class="flex flex-col items-center">
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">表空间使用率</span>
<span class="text-sm font-medium">75%</span>
</div>
<div class="flex flex-col items-center">
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">日志文件</span>
<span class="text-sm font-medium">正常轮转</span>
</div>
</div>
<div class="flex justify-end gap-2">
<el-button size="small" class="text-sm border-gray-300 text-gray-600">查看详情</el-button>
<el-button type="primary" size="small" class="text-sm">生成报告</el-button>
</div>
</div>
<!-- 结果2需关注 -->
<div class="inspection-card bg-white border border-gray-200 rounded-lg p-4 shadow-sm">
<div class="flex justify-between items-start mb-4">
<h3 class="text-lg font-medium text-gray-800">生产服务器日常巡检</h3>
<span class="status-tag status-attention px-3 py-1 text-xs">需关注</span>
</div>
<p class="text-sm text-gray-500 mb-3">2025-06-15 14:00-16:45 张明</p>
<div class="flex justify-between items-center mb-4">
<div class="flex flex-col items-center">
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">CPU使用率</span>
<span class="text-sm font-medium">平均35%峰值59%</span>
</div>
<div class="flex flex-col items-center">
<i class="fas fa-exclamation-circle text-yellow-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">内存使用率</span>
<span class="text-sm font-medium">85%</span>
</div>
<div class="flex flex-col items-center">
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">磁盘空间</span>
<span class="text-sm font-medium">62%</span>
</div>
<div class="flex flex-col items-center">
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">服务状态</span>
<span class="text-sm font-medium">正常运行</span>
</div>
</div>
<div class="bg-yellow-50 border border-yellow-200 rounded-md p-3 mb-4">
<div class="flex items-start">
<i class="fas fa-info-circle text-yellow-500 mt-0.5 mr-2"></i>
<p class="text-xs text-yellow-800">已创建问题单 #PRB-2023061501计划于今晚进行内存扩容</p>
</div>
</div>
<div class="flex justify-end gap-2">
<el-button size="small" class="text-sm border-gray-300 text-gray-600">查看详情</el-button>
<el-button type="primary" size="small" class="text-sm">生成报告</el-button>
</div>
</div>
<!-- 结果3有问题 -->
<div class="inspection-card bg-white border border-gray-200 rounded-lg p-4 shadow-sm">
<div class="flex justify-between items-start mb-4">
<h3 class="text-lg font-medium text-gray-800">网络设备安全巡检</h3>
<span class="status-tag status-problem px-3 py-1 text-xs">有问题</span>
</div>
<p class="text-sm text-gray-500 mb-3">2025-06-14 10:00-11:30 李华</p>
<div class="grid grid-cols-2 gap-2 mb-4">
<div class="flex flex-col items-center">
<i class="fas fa-times-circle text-red-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">防火墙规则</span>
<span class="text-sm font-medium">部分规则异常</span>
</div>
<div class="flex flex-col items-center">
<i class="fas fa-exclamation-circle text-yellow-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">安全补丁</span>
<span class="text-sm font-medium">需更新</span>
</div>
<div class="flex flex-col items-center">
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">访问控制</span>
<span class="text-sm font-medium">正常</span>
</div>
<div class="flex flex-col items-center">
<i class="fas fa-check-circle text-green-500 text-lg mb-1"></i>
<span class="text-xs text-gray-600 mb-1">流量监控</span>
<span class="text-sm font-medium">正常</span>
</div>
</div>
<div class="flex justify-end gap-2">
<el-button size="small" class="text-sm border-gray-300 text-gray-600">查看详情</el-button>
<el-button type="primary" size="small" class="text-sm">生成报告</el-button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
import router from '@/router';
import TitleComponent from '@/views/demo/components/TitleComponent.vue';
// 筛选条件
const filterStatus = ref('all');
const filterType = ref('all');
const dateRange = ref([]);
// 时间范围选择
const timeRange = ref('month'); // 默认选中"月"
// 时间范围切换函数
const handleTimeRangeChange = (range) => {
timeRange.value = range;
// 在实际应用中,这里应该根据选择的时间范围重新获取数据
console.log(`切换到${range}视图`);
};
// 导航方法
const handleInspection1 = () => {
router.push('/rili/rili');
};
const handleInspection2 = () => {
router.push('/rili/InspectionManagement');
};
const handleInspectionManagement1 = () => {
router.push('/rili/InspectionManagement');
};
const handleInspectionManagement2 = () => {
router.push('/rili/xunjianrenwu');
};
const handleInspectionManagement3 = () => {
router.push('/rili/xunjianjihua');
};
</script>
<style scoped>
/* 主容器样式 */
.operation-inspection {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
/* 导航栏样式 */
.navigation-tabs {
display: flex;
margin-bottom: 20px;
background-color: #fff;
border-radius: 4px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
padding: 2px;
}
.nav-tab {
padding: 12px 24px;
cursor: pointer;
transition: all 0.3s ease;
border-radius: 4px;
font-size: 14px;
color: #606266;
border-right: 1px solid #f0f0f0;
flex: 1;
text-align: center;
}
.nav-tab:last-child {
border-right: none;
}
.nav-tab:hover {
color: #409eff;
background-color: #ecf5ff;
}
.nav-tab.active {
background-color: #409eff;
color: #fff;
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
}
.nav-tab {
cursor: pointer;
user-select: none;
}
/* 选项卡样式 */
.tabs-wrapper {
background-color: #fff;
padding: 20px;
border-radius: 8px;
margin-bottom: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
/* 筛选栏样式 */
.filter-bar {
background-color: #fff;
padding: 20px;
border-radius: 8px;
margin-bottom: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 16px;
}
.filter-item {
flex-shrink: 0;
}
.filter-bar .el-select,
.filter-bar .el-date-picker {
width: 150px;
height: 36px;
}
.filter-actions {
margin-left: auto;
display: flex;
gap: 10px;
}
.search-btn,
.export-btn,
.create-btn {
height: 36px;
border-radius: 4px;
}
/* 内容卡片样式 */
.content-card {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
overflow: hidden;
}
.card-header {
padding: 20px;
border-bottom: 1px solid #e4e7ed;
display: flex;
justify-content: space-between;
align-items: center;
}
.card-title {
font-size: 16px;
font-weight: 500;
color: #303133;
margin: 0;
}
.card-body {
padding: 0 20px;
}
/* 统计卡片样式 */
.stat-card {
background-color: #f5f7fa;
border-radius: 6px;
padding: 16px;
}
.stat-label {
font-size: 14px;
color: #606266;
margin: 0 0 8px 0;
}
.stat-value {
font-size: 24px;
font-weight: 600;
color: #303133;
margin: 0;
}
/* 分隔线 */
.divider {
height: 1px;
background-color: #e4e7ed;
margin: 16px 0;
}
/* 图表标题 */
.chart-title {
font-size: 14px;
color: #606266;
margin: 0 0 8px 0;
}
/* 区域标题 */
.section-title {
font-size: 14px;
font-weight: 500;
color: #303133;
margin: 0 0 12px 0;
}
/* 记录列表样式 */
.record-list {
margin: 0;
padding: 0;
}
.record-item {
padding: 16px 0;
}
.record-title {
font-size: 14px;
font-weight: 500;
color: #303133;
margin: 0;
}
.record-time,
.record-type {
font-size: 12px;
color: #909399;
margin: 4px 0 0 0;
}
/* 状态标签 */
.status-tag {
font-size: 12px;
padding: 2px 8px;
border-radius: 4px;
}
.status-normal {
background-color: #f0f9eb;
color: #52c41a;
border: 1px solid #e1f3d8;
}
.status-attention {
background-color: #fffbe6;
color: #faad14;
border: 1px solid #fff1b8;
}
.status-problem {
background-color: #fff2f0;
color: #f5222d;
border: 1px solid #ffe3e0;
}
/* 操作按钮 */
.action-btn {
color: #409eff;
font-size: 12px;
padding: 4px 8px;
}
.action-btn:hover {
color: #66b1ff;
background-color: #ecf5ff;
}
/* 响应式设计 */
@media (max-width: 1200px) {
.filter-bar {
flex-direction: column;
align-items: stretch;
}
.filter-actions {
margin-left: 0;
justify-content: flex-end;
}
}
</style>

View File

@ -0,0 +1,892 @@
<template>
<div>
<div class="inspection-tasks">
<div class="navigation-tabs">
<div class="nav-tab" @click="handleInspection1">待办事项</div>
<div class="nav-tab active" @click="handleInspection2">巡检管理</div>
<div class="nav-tab">试验管理</div>
<div class="nav-tab">报修管理</div>
<div class="nav-tab">抢修管理</div>
<div class="nav-tab">工单管理</div>
</div>
<!-- 页面标题 -->
<TitleComponent title="运维巡检管理" subtitle="制定巡检计划,安排巡检任务,跟进巡检记录"></TitleComponent>
<!-- 选项卡 -->
<div class="tabs-wrapper">
<div style="display: flex; align-items: center; gap: 10px">
<el-button type="primary" @click="handleInspectionManagement1">巡检计划</el-button>
<el-button type="primary" @click="handleInspectionManagement2">巡检任务</el-button>
<el-button type="primary" @click="handleInspectionManagement3">巡检记录</el-button>
</div>
</div>
<!-- 筛选栏 -->
<div class="filter-bar">
<div class="filter-container">
<div class="filter-item">
<el-select v-model="taskStatus" placeholder="任务状态">
<el-option label="待执行" value="pending"></el-option>
<el-option label="执行中" value="executing"></el-option>
<el-option label="已延期" value="delayed"></el-option>
<el-option label="已完成" value="completed"></el-option>
</el-select>
</div>
<div class="filter-item">
<el-select v-model="planType" placeholder="全部计划">
<el-option label="每日巡检计划" value="daily"></el-option>
<el-option label="每周巡检计划" value="weekly"></el-option>
<el-option label="每月巡检计划" value="monthly"></el-option>
<el-option label="每季度巡检计划" value="quarterly"></el-option>
</el-select>
</div>
<div class="filter-item">
<el-select v-model="executor" placeholder="执行人">
<el-option label="全部人员" value="all"></el-option>
<el-option label="张明" value="zhangming"></el-option>
<el-option label="李华" value="lihua"></el-option>
<el-option label="王强" value="wangqiang"></el-option>
</el-select>
</div>
<div class="filter-actions">
<el-button type="primary" class="search-btn" @click="handleSearch"> <i class="el-icon-search mr-1"></i>搜索 </el-button>
<el-button type="primary" icon="el-icon-plus" class="create-btn" @click="handleCreateTask"> 手动创建任务 </el-button>
</div>
</div>
</div>
<!-- 任务卡片列表 -->
<div class="task-cards">
<div class="task-card" v-for="(task, index) in pagedTasks" :key="index">
<div class="task-header">
<div class="task-title">
{{ task.title }}
</div>
<div class="task-status" :class="task.statusClass">
{{ task.statusText }}
</div>
</div>
<div class="task-details">
<div class="detail-item">
<span class="detail-label">计划时间</span>
<span class="detail-value">{{ task.planTime }}</span>
</div>
<div class="detail-item">
<span class="detail-label">巡检对象</span>
<span class="detail-value">{{ task.target }}</span>
</div>
<div class="detail-item">
<span class="detail-label">执行人</span>
<span class="detail-value">{{ task.executor }}</span>
</div>
<div class="detail-item">
<span class="detail-label">关联计划</span>
<span class="detail-value">{{ task.relatedPlan }}</span>
</div>
<!-- 特定状态的额外信息 -->
<div v-if="task.status === 'delayed'" class="delay-reason">
<span class="detail-label">延期原因</span>
<span class="detail-value">{{ task.delayReason }}</span>
</div>
<div v-if="task.status === 'executing'" class="progress-container">
<span class="detail-label">完成进度</span>
<div class="progress-bar">
<el-progress :percentage="task.progress" stroke-width="6" :stroke-color="task.progressColor"></el-progress>
</div>
</div>
<div v-if="task.status === 'completed'" class="task-result">
<span class="detail-label">结果</span>
<span class="detail-value" :class="task.resultClass">{{ task.result }}</span>
</div>
</div>
<div class="task-actions">
<el-button type="text" size="small" class="action-btn view-btn" @click="handleView(task)"> 详情 </el-button>
<el-button type="primary" size="small" :class="task.actionClass" @click="handleAction(task)">
{{ task.actionText }}
</el-button>
</div>
</div>
</div>
<!-- 分页区域 -->
<div class="pagination-section">
<div class="pagination-controls">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[8, 12, 16, 20]"
:page-size="pageSize"
layout="prev, pager, next, jumper"
:total="total"
background
>
</el-pagination>
</div>
</div>
<!-- 添加新任务弹窗 -->
<el-dialog v-model="createTaskDialogVisible" title="添加新任务" width="500px" :before-close="handleCancelCreateTask">
<el-form ref="createTaskFormRef" :model="createTaskForm" :rules="createTaskRules" label-width="80px">
<el-form-item label="任务名称" prop="taskName">
<el-input v-model="createTaskForm.taskName" placeholder="输入任务名称" />
</el-form-item>
<el-form-item label="巡检对象" prop="inspectionTarget">
<el-input v-model="createTaskForm.inspectionTarget" placeholder="输入巡检内容" />
</el-form-item>
<el-form-item label="时间" prop="timeRange">
<el-date-picker
v-model="createTaskForm.timeRange"
type="datetimerange"
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD HH:mm"
value-format="YYYY-MM-DD HH:mm"
placeholder="选择时间范围"
/>
</el-form-item>
<el-form-item label="关联计划">
<el-select v-model="createTaskForm.relatedPlan" placeholder="选择关联计划">
<el-option label="全部计划" value="all" />
<el-option label="每日巡检计划" value="daily" />
<el-option label="每周巡检计划" value="weekly" />
<el-option label="每月巡检计划" value="monthly" />
<el-option label="每季度巡检计划" value="quarterly" />
</el-select>
</el-form-item>
<el-form-item label="执行人">
<el-select v-model="createTaskForm.executor" placeholder="选择执行人">
<el-option label="全部人员" value="all" />
<el-option label="张明" value="zhangming" />
<el-option label="李华" value="lihua" />
<el-option label="王强" value="wangqiang" />
<el-option label="赵伟" value="zhaowei" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCancelCreateTask">取消</el-button>
<el-button type="primary" @click="handleSaveTask">保存任务</el-button>
</span>
</template>
</el-dialog>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
import router from '@/router';
import TitleComponent from '@/views/demo/components/TitleComponent.vue';
// 激活的选项卡
const activeTab = ref('task');
// 筛选条件
const taskStatus = ref('');
const planType = ref('');
const executor = ref('');
// 任务数据
const tasks = ref([
{
title: '生产服务器日常巡检',
status: 'pending',
statusText: '待执行',
statusClass: 'status-pending',
planTime: '2025-06-16 08:30',
target: '生产服务器集群(12台)',
executor: '张明',
relatedPlan: '每日巡检计划',
actionText: '开始执行',
actionClass: 'start-btn'
},
{
title: '机房环境检查',
status: 'delayed',
statusText: '已延期',
statusClass: 'status-delayed',
planTime: '2025-06-16 08:30',
target: '机房温度、湿度、电源',
executor: '李华',
relatedPlan: '每周巡检计划',
delayReason: '设备维修处理中',
actionText: '重新安排',
actionClass: 'reschedule-btn'
},
{
title: '网络设备安全巡检',
status: 'executing',
statusText: '执行中',
statusClass: 'status-executing',
planTime: '2025-06-16 09:30',
target: '核心交换机、防火墙',
executor: '王强',
relatedPlan: '每周巡检计划',
progress: 60,
progressColor: '#FF7D00',
actionText: '完成',
actionClass: 'complete-btn'
},
{
title: '数据库性能巡检',
status: 'completed',
statusText: '已完成',
statusClass: 'status-completed',
planTime: '2025-06-16 10:30',
target: '生产数据库集群(2组)',
executor: '赵伟',
relatedPlan: '每月巡检计划',
result: '正常',
resultClass: 'result-normal',
actionText: '查看报告',
actionClass: 'report-btn'
},
{
title: '生产服务器日常巡检',
status: 'pending',
statusText: '待执行',
statusClass: 'status-pending',
planTime: '2025-06-16 13:30',
target: '生产服务器集群(12台)',
executor: '张明',
relatedPlan: '每日巡检计划',
actionText: '开始执行',
actionClass: 'start-btn'
},
{
title: '机房环境检查',
status: 'delayed',
statusText: '已延期',
statusClass: 'status-delayed',
planTime: '2025-06-16 14:00',
target: '机房温度、湿度、电源',
executor: '李华',
relatedPlan: '每周巡检计划',
delayReason: '设备维修处理中',
actionText: '重新安排',
actionClass: 'reschedule-btn'
},
{
title: '网络设备安全巡检',
status: 'executing',
statusText: '执行中',
statusClass: 'status-executing',
planTime: '2025-06-16 15:00',
target: '核心交换机、防火墙',
executor: '王强',
relatedPlan: '每周巡检计划',
progress: 35,
progressColor: '#FF7D00',
actionText: '完成',
actionClass: 'complete-btn'
},
{
title: '数据库性能巡检',
status: 'completed',
statusText: '已完成',
statusClass: 'status-completed',
planTime: '2025-06-16 16:00',
target: '生产数据库集群(2组)',
executor: '赵伟',
relatedPlan: '每月巡检计划',
result: '正常',
resultClass: 'result-normal',
actionText: '查看报告',
actionClass: 'report-btn'
}
]);
// 分页相关
const currentPage = ref(1);
const pageSize = ref(8);
const total = ref(tasks.value.length);
// 状态排序映射
const statusOrder = {
pending: 0, // 待完成
delayed: 1, // 已延期
executing: 2, // 执行中
completed: 3 // 已完成
};
// 分页处理后的数据(含排序)
const pagedTasks = computed(() => {
// 先按状态排序
const sortedTasks = [...tasks.value].sort((a, b) => {
return statusOrder[a.status] - statusOrder[b.status];
});
// 再进行分页
const startIndex = (currentPage.value - 1) * pageSize.value;
const endIndex = startIndex + pageSize.value;
return sortedTasks.slice(startIndex, endIndex);
});
// 搜索处理
const handleSearch = () => {
currentPage.value = 1; // 重置到第一页
// 实际应用中这里会根据筛选条件过滤数据
};
// 创建任务弹窗相关
const createTaskDialogVisible = ref(false);
const createTaskForm = ref({
taskName: '',
inspectionTarget: '',
timeRange: [],
relatedPlan: 'all',
executor: 'all'
});
const createTaskRules = {
taskName: [{ required: true, message: '请输入任务名称', trigger: 'blur' }],
inspectionTarget: [{ required: true, message: '请输入巡检对象', trigger: 'blur' }],
timeRange: [{ required: true, message: '请选择时间范围', trigger: 'change' }]
};
// 创建任务
const handleCreateTask = () => {
createTaskDialogVisible.value = true;
};
// 保存任务
const handleSaveTask = () => {
// 模拟保存任务逻辑
console.log('保存任务:', createTaskForm.value);
// 关闭弹窗
createTaskDialogVisible.value = false;
// 重置表单
createTaskForm.value = {
taskName: '',
inspectionTarget: '',
timeRange: [],
relatedPlan: 'all',
executor: 'all'
};
// 这里可以添加成功提示和刷新任务列表的逻辑
};
// 取消创建任务
const handleCancelCreateTask = () => {
createTaskDialogVisible.value = false;
// 重置表单
createTaskForm.value = {
taskName: '',
inspectionTarget: '',
timeRange: [],
relatedPlan: 'all',
executor: 'all'
};
};
// 分页事件
const handleSizeChange = (val) => {
pageSize.value = val;
currentPage.value = 1;
};
const handleCurrentChange = (val) => {
currentPage.value = val;
};
// 查看任务详情
const handleView = (task) => {
console.log('查看任务详情:', task);
};
const handleInspectionManagement1 = () => {
router.push('/rili/InspectionManagement');
};
const handleInspectionManagement2 = () => {
router.push('/rili/xunjianrenwu');
};
const handleInspectionManagement3 = () => {
router.push('/rili/xunjianjihua');
};
const handleInspection1 = () => {
router.push('/rili/rili');
};
const handleInspection2 = () => {
router.push('/rili/InspectionManagement');
};
</script>
<style scoped>
.inspection-tasks {
padding: 20px;
background-color: #f5f7fa;
min-height: 100vh;
}
/* 选项卡样式 */
.tabs-wrapper {
background-color: #fff;
padding: 20px;
border-radius: 8px;
margin-bottom: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.custom-tabs {
border-bottom: none;
padding-top: 20px;
}
.custom-tabs .el-tabs__header {
margin: 0 -20px 0 -20px;
padding: 0 20px;
border-bottom: 1px solid #e4e7ed;
}
.custom-tabs .el-tabs__nav-wrap::after {
height: 0;
}
.custom-tabs .el-tabs__item {
font-size: 14px;
color: #606266;
padding: 12px 20px;
margin-right: 20px;
border-bottom: 2px solid transparent;
}
.custom-tabs .el-tabs__item.is-active {
color: #409eff;
border-bottom-color: #409eff;
}
.custom-tabs .el-tabs__item:hover {
color: #409eff;
}
/* 筛选栏样式 */
.filter-bar {
background-color: #fff;
border-radius: 8px;
margin-bottom: 24px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
padding: 16px 24px;
}
.filter-container {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 16px;
width: 100%;
}
.filter-item {
flex-shrink: 0;
}
.filter-bar .el-select {
width: 180px;
height: 36px;
}
.filter-bar .el-select .el-input__inner {
border-radius: 4px;
border-color: #dcdfe6;
transition: all 0.2s ease;
}
.filter-bar .el-select .el-input__inner:focus {
border-color: #165dff;
box-shadow: 0 0 0 2px rgba(22, 93, 255, 0.1);
}
.filter-actions {
margin-left: auto;
display: flex;
gap: 12px;
flex-shrink: 0;
}
.search-btn {
background-color: #f2f3f5;
color: #303133;
border-color: #f2f3f5;
transition: all 0.2s ease;
}
.search-btn:hover {
background-color: #e5e6eb;
color: #303133;
border-color: #e5e6eb;
}
.create-btn {
background-color: #165dff;
border-color: #165dff;
transition: all 0.2s ease;
}
.create-btn:hover {
background-color: #0e42d2;
border-color: #0e42d2;
}
/* 任务卡片样式 */
.task-cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.task-card {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
padding: 16px 16px 60px 16px; /* 底部留出更多空间给按钮 */
transition: box-shadow 0.2s ease;
position: relative;
overflow: hidden;
min-height: 280px; /* 确保有足够高度显示所有内容 */
}
.task-actions {
display: flex;
justify-content: flex-end;
align-items: center;
padding-top: 12px;
border-top: 1px solid #f0f2f5;
position: absolute;
bottom: 16px;
right: 16px;
left: 16px;
background-color: #fff;
padding: 12px 0 0 0;
z-index: 10;
}
.task-card::before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 4px;
}
.task-card.status-pending::before {
background-color: #1677ff;
}
.task-card.status-delayed::before {
background-color: #ff4d4f;
}
.task-card.status-executing::before {
background-color: #fa8c16;
}
.task-card.status-completed::before {
background-color: #52c41a;
}
.task-card:hover {
transform: translateY(-3px);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
}
.task-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 16px;
padding-bottom: 12px;
border-bottom: 1px solid #f0f2f5;
}
.task-title {
font-size: 16px;
font-weight: 500;
color: #1d2129;
line-height: 1.4;
}
.task-status {
padding: 4px 10px;
border-radius: 6px;
font-size: 12px;
font-weight: 500;
border: 1px solid transparent;
}
/* 待执行状态 - 蓝色 */
.status-pending {
background-color: #e6f7ff;
color: #1677ff;
border-color: #91d5ff;
}
/* 已延期状态 - 红色 */
.status-delayed {
background-color: #fff2f0;
color: #ff4d4f;
border-color: #ffccc7;
}
/* 执行中状态 - 黄色 */
.status-executing {
background-color: #fffbe6;
color: #fa8c16;
border-color: #ffe58f;
}
/* 已完成状态 - 绿色 */
.status-completed {
background-color: #f6ffed;
color: #52c41a;
border-color: #b7eb8f;
}
.task-details {
margin-bottom: 16px;
}
.detail-item {
display: flex;
margin-bottom: 10px;
font-size: 13px;
}
.detail-label {
flex: 0 0 80px;
color: #86909c;
}
.detail-value {
flex: 1;
color: #4e5969;
word-break: break-all;
}
.delay-reason {
display: flex;
margin: 10px 0;
font-size: 13px;
padding-top: 8px;
border-top: 1px dashed #f0f2f5;
}
.progress-container {
display: flex;
flex-direction: column;
margin: 10px 0;
padding-top: 8px;
border-top: 1px dashed #f0f2f5;
z-index: 1;
}
.progress-bar {
flex: 1;
padding-left: 80px;
margin-top: 4px;
position: relative;
z-index: 1;
}
.progress-text {
position: absolute;
right: 0;
top: 0;
font-size: 12px;
color: #86909c;
}
.task-result {
display: flex;
margin: 10px 0;
font-size: 13px;
padding-top: 8px;
border-top: 1px dashed #f0f2f5;
}
.result-normal {
color: #00b42a;
}
.result-abnormal {
color: #f53f3f;
}
.task-actions {
display: flex;
justify-content: flex-end;
align-items: center;
padding-top: 12px;
border-top: 1px solid #f0f2f5;
position: absolute;
bottom: 16px;
right: 16px;
left: 16px;
background-color: #fff;
padding: 12px 0 0 0;
z-index: 10;
}
.action-btn {
font-size: 13px;
padding: 4px 10px;
}
.view-btn {
color: #165dff;
}
.view-btn:hover {
color: #0e42d2;
background-color: #e8f3ff;
}
.start-btn {
background-color: #165dff;
border-color: #165dff;
}
.start-btn:hover {
background-color: #0e42d2;
border-color: #0e42d2;
}
.reschedule-btn {
background-color: #ff7d00;
border-color: #ff7d00;
}
.reschedule-btn:hover {
background-color: #e86a00;
border-color: #e86a00;
}
.complete-btn {
background-color: #00b42a;
border-color: #00b42a;
}
.complete-btn:hover {
background-color: #008718;
border-color: #008718;
}
.report-btn {
background-color: #86909c;
border-color: #86909c;
}
.report-btn:hover {
background-color: #6b7785;
border-color: #6b7785;
}
/* 分页区域样式 */
.pagination-section {
display: flex;
justify-content: center;
margin-top: 20px;
}
.pagination-controls .el-pagination {
margin: 0;
}
.pagination-controls .el-pagination button,
.pagination-controls .el-pagination .el-pager li {
min-width: 36px;
height: 36px;
line-height: 36px;
border-radius: 4px;
}
.pagination-controls .el-pagination .el-pager li.active {
background-color: #165dff;
color: #fff;
}
/* 响应式设计 */
@media (max-width: 1200px) {
.task-cards {
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}
}
@media (max-width: 768px) {
.inspection-tasks {
padding: 16px;
}
.filter-container {
flex-direction: column;
align-items: stretch;
}
.filter-actions {
margin-left: 0;
justify-content: flex-end;
}
.filter-bar .el-select {
width: 100%;
}
.task-cards {
grid-template-columns: 1fr;
}
}
/* 导航栏样式 */
.navigation-tabs {
display: flex;
margin-bottom: 20px;
background-color: #fff;
border-radius: 4px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
padding: 2px;
}
.nav-tab {
padding: 12px 24px;
cursor: pointer;
transition: all 0.3s ease;
border-radius: 4px;
font-size: 14px;
color: #606266;
border-right: 1px solid #f0f0f0;
flex: 1;
text-align: center;
}
.nav-tab:last-child {
border-right: none;
}
.nav-tab:hover {
color: #409eff;
background-color: #ecf5ff;
}
.nav-tab.active {
background-color: #409eff;
color: #fff;
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
}
.nav-tab {
cursor: pointer;
user-select: none;
}
</style>

View File

@ -4,7 +4,7 @@
<div ref="mapRef" class="map-container" style="width: 100%; height: 100%" /> <div ref="mapRef" class="map-container" style="width: 100%; height: 100%" />
</div> </div>
<div class="centerPage_bottom"> <div class="centerPage_bottom">
<Title title="风险预警"> <Title title="风险预警" style="font-size: 22px">
<img src="@/assets/projectLarge/robot.svg" alt="" height="20px" width="20px" /> <img src="@/assets/projectLarge/robot.svg" alt="" height="20px" width="20px" />
</Title> </Title>
<div class="centerPage_bottom_table"> <div class="centerPage_bottom_table">
@ -48,10 +48,13 @@ const loading = ref(false);
const tableData = ref([]); const tableData = ref([]);
const risk_level_type = ref(); const risk_level_type = ref();
const safety_inspection_type = ref(); const safety_inspection_type = ref();
const router = useRouter();
// 新增:获取项目地理信息数据 // 新增:获取项目地理信息数据
const getProjectGisData = async () => { const getProjectGisData = async () => {
try { try {
const response = await projectGis(); const response = await projectGis();
console.log(response, 111111111111);
if (response.code === 200) { if (response.code === 200) {
// 过滤掉没有经纬度的项目 // 过滤掉没有经纬度的项目
projectData.value = response.data.filter((item: any) => item.lng !== null && item.lat !== null && item.lng !== '' && item.lat !== ''); projectData.value = response.data.filter((item: any) => item.lng !== null && item.lat !== null && item.lng !== '' && item.lat !== '');
@ -107,6 +110,7 @@ const initEcharts = () => {
// 从接口数据生成散点数据 // 从接口数据生成散点数据
const scatterData = projectData.value.map((item) => ({ const scatterData = projectData.value.map((item) => ({
name: item.projectName, name: item.projectName,
id: item.id,
value: [parseFloat(item.lng), parseFloat(item.lat)], // 转换为数值类型 value: [parseFloat(item.lng), parseFloat(item.lat)], // 转换为数值类型
shortName: item.shortName, shortName: item.shortName,
projectSite: item.projectSite, projectSite: item.projectSite,
@ -159,6 +163,7 @@ const initEcharts = () => {
<div style="font-weight: bold;">${data.name}</div> <div style="font-weight: bold;">${data.name}</div>
<div>地点:${data.projectSite}</div> <div>地点:${data.projectSite}</div>
<div>经纬度:${data.value[0].toFixed(6)}, ${data.value[1].toFixed(6)}</div> <div>经纬度:${data.value[0].toFixed(6)}, ${data.value[1].toFixed(6)}</div>
`; `;
} }
if (params.seriesType === 'map') { if (params.seriesType === 'map') {
@ -196,6 +201,20 @@ const initEcharts = () => {
}; };
myChart.setOption(option); myChart.setOption(option);
// 添加点击事件监听 - 这是关键修改部分
myChart.on('click', function (params: any) {
console.log(params, 111111);
// 检查点击的是散点图系列
if (params.componentType === 'series' && params.seriesType === 'scatter') {
// 跳转到项目详情页
navigateToProjectDetail(params.data);
}
});
};
const navigateToProjectDetail = (data) => {
window.open('http://xny.yj-3d.com:7788/ProjectScreen?projectId=' + data.id + '&projectName=' + data.name, '_blank');
//xny.yj-3d.com
}; };
const risk_level_type1 = ref([]); const risk_level_type1 = ref([]);
const safety_inspection_type1 = ref([]); const safety_inspection_type1 = ref([]);

View File

@ -11,8 +11,8 @@
</div> </div>
</div> </div>
<div class="title"> <div class="title">
<div>煤科建管-新能源项目数智化管理平台</div> <div>新能源项目数智化管理平台</div>
<div>Coal Science Construction Management - New Energy Project Digital Intelligent Management Platform</div> <div>New Energy Project Digital Intelligent Management Platform</div>
</div> </div>
<div class="header_right"> <div class="header_right">
<div class="top-bar"> <div class="top-bar">
@ -25,7 +25,7 @@
class="weather-item" class="weather-item"
:style="{ transform: `translateY(-${offsetY}px)`, transition: transition }" :style="{ transform: `translateY(-${offsetY}px)`, transition: transition }"
> >
<img :src="`../../../src/assets/images/${item.icon}.png`" alt="" /> <img :src="`/assets/demo/${item.icon}.png`" alt="" />
<div>{{ item.weather }}{{ item.tempMin }}°/{{ item.tempMax }}°</div> <div>{{ item.weather }}{{ item.tempMin }}°/{{ item.tempMax }}°</div>
<div>{{ item.week }}({{ item.date }})</div> <div>{{ item.week }}({{ item.date }})</div>
</div> </div>
@ -47,14 +47,14 @@
<div class="bottom-block"></div> <div class="bottom-block"></div>
</div> </div>
<!-- --> <!-- -->
<div class="change" @click="emit('changePage')"> <!-- <div class="change" @click="emit('changePage')">
<el-icon size="20" v-if="!isFull"> <el-icon size="20" v-if="!isFull">
<Expand /> <Expand />
</el-icon> </el-icon>
<el-icon size="20" v-else> <el-icon size="20" v-else>
<Fold /> <Fold />
</el-icon> </el-icon>
</div> </div> -->
</div> </div>
</div> </div>
</div> </div>
@ -214,6 +214,7 @@ onUnmounted(() => {
.header_left_text { .header_left_text {
font-weight: 500; font-weight: 500;
text-shadow: 0px 1.24px 6.21px rgba(25, 179, 250, 1); text-shadow: 0px 1.24px 6.21px rgba(25, 179, 250, 1);
font-size: 26px;
} }
} }

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="leftPage"> <div class="leftPage">
<div class="topPage"> <div class="topPage">
<Title style="font-size: 22px" title="企业关键指标" /> <Title title="企业关键指标" />
<div class="indicators"> <div class="indicators">
<div class="indicator-card" v-for="indicator in indicators" :key="indicator.id"> <div class="indicator-card" v-for="indicator in indicators" :key="indicator.id">
<div style="display: flex; align-items: baseline; gap: 4px; margin-bottom: 5px"> <div style="display: flex; align-items: baseline; gap: 4px; margin-bottom: 5px">
@ -17,44 +17,74 @@
</div> </div>
<div class="endPage"> <div class="endPage">
<Title style="font-size: 22px" title="人员情况" /> <Title title="人员情况" />
<div class="map"> <!-- 人员总览区域 -->
<div class="project_attendance_chart"> <div class="people_overview">
<Title style="font-size: 22px" title="各项目人员出勤率" /> <div class="people_overview_content">
<div class="chart_content" ref="attendanceChartRef"></div> <div class="people_image">
</div> <!-- 本地图片占位后续可替换为实际图片路径 -->
<div class="attendance_tag"> <img src="@/assets/images/man.png" alt="人员总览" class="placeholder_image" />
<div class="tag_item">
<img src="@/assets/projectLarge/people.svg" alt="" />
<div class="tag_title">出勤人</div>
<div class="tag_info">
{{ attendanceCount }}
<span style="font-size: 14px"></span>
</div>
</div> </div>
<div class="tag_item"> <div class="people_stats">
<img src="@/assets/projectLarge/people.svg" alt="" /> <div class="stat_item">
<div class="tag_title">在岗人</div> <div class="stat_label">出勤人数</div>
<div class="tag_info"> <div class="stat_value">{{ attendanceCount }}</div>
{{ peopleCount }}
<span style="font-size: 14px"></span>
</div> </div>
</div> <div class="stat_item">
<div class="tag_item"> <div class="stat_label">出勤率</div>
<img src="@/assets/projectLarge/people.svg" alt="" /> <div class="stat_rate">{{ attendanceRate }}%</div>
<div class="tag_title">出勤率</div>
<div class="tag_info">
{{ attendanceRate }}
<span style="font-size: 14px">%</span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!-- 点阵地图 -->
<div class="people_map">
<div class="map_container">
<img src="@/assets/images/map.png" />
</div>
</div>
<div class="attendance_tag"></div> <!-- 人员分类统计 -->
<div class="people_categories">
<div class="category_item">
<div class="category_icon">
<!-- 本地图片占位后续可替换为实际图片路径 -->
<img src="@/assets/images/constructor.png" alt="施工人员" class="category_image" />
</div>
<div class="category_info">
<div class="category_label">施工人员</div>
<div class="category_count">{{ constructionPersonnelCount }}</div>
</div>
</div>
<div class="category_item">
<div class="category_icon">
<!-- 本地图片占位后续可替换为实际图片路径 -->
<img src="@/assets/images/subcontractor.png" alt="分包人员" class="category_image" />
</div>
<div class="category_info">
<div class="category_label">分包人员</div>
<div class="category_count">{{ subcontractorsCount }}</div>
</div>
</div>
<div class="category_item">
<div class="category_icon">
<!-- 本地图片占位后续可替换为实际图片路径 -->
<img src="@/assets/images/manager.png" alt="管理人员" class="category_image" />
</div>
<div class="category_info">
<div class="category_label">管理人员</div>
<div class="category_count">{{ managersCount }}</div>
</div>
</div>
</div>
<!-- 项目出勤率柱状图 -->
<div class="project_attendance_chart">
<Title title="项目出勤率统计" />
<div class="chart_content" ref="attendanceChartRef"></div>
</div>
</div> </div>
<!-- 项目出勤率柱状图 -->
</div> </div>
</template> </template>
@ -62,7 +92,7 @@
import { ref } from 'vue'; import { ref } from 'vue';
import Title from './title.vue'; import Title from './title.vue';
import { getScreenNews, getScreenPeople } from '@/api/projectScreen'; import { getScreenNews, getScreenPeople } from '@/api/projectScreen';
import { keyIndex } from '@/api/enterpriseLarge/index'; import { keyIndex, projectAttendanceCount, peopleCount, allAttendanceCount } from '@/api/enterpriseLarge/index';
import { mapOption } from './optionList'; import { mapOption } from './optionList';
import * as echarts from 'echarts'; import * as echarts from 'echarts';
@ -78,31 +108,31 @@ const mapChartRef = ref<HTMLDivElement | null>(null);
const indicators = ref([ const indicators = ref([
{ {
id: '1', id: '1',
name: '在建项目', name: '光伏项目',
value: '28', value: '28',
unit: '个', unit: '个',
iconPath: '/src/assets/images/beUnder.png' iconPath: '/assets/demo/beUnder.png'
}, },
{ {
id: '2', id: '2',
name: '合同总额', name: '风电项目',
value: '288.88', value: '288.88',
unit: '亿元', unit: '',
iconPath: '/src/assets/images/contract.png' iconPath: '/assets/demo/contract.png'
}, },
{ {
id: '3', id: '3',
name: '总容量', name: '光伏项目总容量',
value: '158.88', value: '158.88',
unit: '', unit: 'MW',
iconPath: '/src/assets/images/totalCapacity.png' iconPath: '/assets/demo/totalCapacity.png'
}, },
{ {
id: '4', id: '4',
name: '今日施工', name: '风电项目总容量',
value: '18', value: '18',
unit: '', unit: 'MW',
iconPath: '/src/assets/images/todayConstruction.png' iconPath: '/assets/demo/todayConstruction.png'
} }
]); ]);
@ -114,9 +144,14 @@ const newDetail = ref({
const newId = ref(''); const newId = ref('');
const attendanceCount = ref(0); const attendanceCount = ref(0);
const attendanceRate = ref(0); const attendanceRate = ref(0);
const peopleCount = ref(0); const totalPeopleCount = ref(0);
const teamAttendanceList = ref([{ id: '', teamName: '', attendanceNumber: 0, allNumber: 0, attendanceRate: 0, attendanceTime: '' }]); const teamAttendanceList = ref([{ id: '', teamName: '', attendanceNumber: 0, allNumber: 0, attendanceRate: 0, attendanceTime: '' }]);
// 人员分类统计数据
const constructionPersonnelCount = ref(0);
const managersCount = ref(0);
const subcontractorsCount = ref(0);
// 项目出勤率数据 // 项目出勤率数据
const projectAttendanceData = ref([ const projectAttendanceData = ref([
{ name: 'A项目', value: 62 }, { name: 'A项目', value: 62 },
@ -129,6 +164,11 @@ const projectAttendanceData = ref([
let attendanceChart = null; let attendanceChart = null;
const attendanceChartRef = ref<HTMLDivElement | null>(null); const attendanceChartRef = ref<HTMLDivElement | null>(null);
// 滚动相关状态
const scrollInterval = ref<number | null>(null);
const currentScrollIndex = ref(0);
const scrollSpeed = 1000; // 滚动间隔时间(ms)
/** /**
* 获取项目人员出勤数据 * 获取项目人员出勤数据
*/ */
@ -136,13 +176,169 @@ const getPeopleData = async () => {
const res = await getScreenPeople(props.projectId); const res = await getScreenPeople(props.projectId);
const { data, code } = res; const { data, code } = res;
if (code === 200) { if (code === 200) {
attendanceCount.value = data.attendanceCount; totalPeopleCount.value = data.peopleCount;
attendanceRate.value = data.attendanceRate;
peopleCount.value = data.peopleCount;
teamAttendanceList.value = data.teamAttendanceList; teamAttendanceList.value = data.teamAttendanceList;
} }
}; };
/**
* 获取人员分类统计数据
*/
const getPeopleCategoryData = async () => {
try {
const res = await peopleCount();
const { data, code } = res;
if (code === 200 && data) {
constructionPersonnelCount.value = data.constructionPersonnelCount || 0;
managersCount.value = data.managersCount || 0;
subcontractorsCount.value = data.subcontractorsCount || 0;
}
} catch (error) {
console.error('获取人员分类统计数据失败:', error);
}
};
/**
* 获取人员总览数据 - 通过allAttendanceCount接口
*/
const getProjectAttendanceCount = async () => {
try {
const res = await allAttendanceCount();
const { data, code } = res;
if (code === 200) {
console.log(data, 222222222);
// 直接使用接口返回的数据
attendanceCount.value = data.attendanceCount || 0;
attendanceRate.value = data.attendanceRate || 0;
}
} catch (error) {
console.error('获取人员总览数据失败:', error);
}
};
/**
* 滚动到指定项目
*/
const scrollToProject = (index: number) => {
if (!attendanceChart || projectAttendanceData.value.length === 0) return;
// 计算实际索引
const realIndex = index % projectAttendanceData.value.length;
currentScrollIndex.value = realIndex;
// 获取项目名称
const projectName = projectAttendanceData.value[realIndex].name;
// 触发tooltip显示
attendanceChart.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: realIndex
});
// 高亮当前项目的柱子
attendanceChart.dispatchAction({
type: 'highlight',
seriesIndex: 0,
dataIndex: realIndex
});
// 取消高亮其他项目的柱子
attendanceChart.dispatchAction({
type: 'downplay',
seriesIndex: 0,
dataIndex: Array.from({ length: projectAttendanceData.value.length }, (_, i) => i).filter((i) => i !== realIndex)
});
// 更新滚动条位置,确保滚动时滚动条同步移动
// 无论项目数量多少,都应该同步滚动条
if (projectAttendanceData.value.length > 0) {
// 计算滚动条应该移动到的位置
// 确保当前项目居中显示
const totalProjects = projectAttendanceData.value.length;
const visiblePercentage = 20; // 与dataZoom的end值保持一致
const itemPercentage = 100 / totalProjects; // 每个项目所占总宽度的百分比
// 计算新的start值使当前项目尽量居中显示
let newStart = realIndex * itemPercentage - visiblePercentage / 2 + itemPercentage / 2;
// 确保start值在有效范围内
newStart = Math.max(0, Math.min(100 - visiblePercentage, newStart));
// 更新dataZoom组件的位置
attendanceChart.dispatchAction({
type: 'dataZoom',
start: newStart,
end: newStart + visiblePercentage
});
}
};
/**
* 获取项目出勤率统计数据 - 保持项目出勤率图表功能
*/
const getProjectAttendanceStats = async () => {
try {
const res = await projectAttendanceCount();
const { data, code } = res;
// 添加日志信息以便调试
console.log('projectAttendanceCount接口返回数据:', res);
if (code === 200 && data && data.length > 0) {
console.log('有效数据:', data);
// 更新项目出勤率图表数据
projectAttendanceData.value = data.map((project) => ({
name: project.projectName,
value: project.attendanceRate
}));
console.log('处理后的数据:', projectAttendanceData.value);
// 如果图表已初始化,重新设置数据
if (attendanceChart) {
console.log('更新图表数据');
attendanceChart.setOption({
xAxis: {
data: projectAttendanceData.value.map((item) => item.name)
},
series: [
{
data: projectAttendanceData.value.map((item) => item.value)
}
]
});
}
} else {
console.warn('数据不符合预期:', { code, data });
// 使用默认数据确保图表有内容显示
if (!projectAttendanceData.value.length) {
projectAttendanceData.value = [
{ name: 'A项目', value: 62 },
{ name: 'B项目', value: 56 },
{ name: 'C项目', value: 95 },
{ name: 'D项目', value: 64 },
{ name: 'E项目', value: 97.5 }
];
}
}
} catch (error) {
console.error('获取项目出勤率数据失败:', error);
// 发生错误时使用默认数据
if (!projectAttendanceData.value.length) {
projectAttendanceData.value = [
{ name: 'A项目', value: 62 },
{ name: 'B项目', value: 56 },
{ name: 'C项目', value: 95 },
{ name: 'D项目', value: 64 },
{ name: 'E项目', value: 97.5 }
];
}
}
};
/** /**
* 获取企业关键指标数据 * 获取企业关键指标数据
*/ */
@ -151,10 +347,10 @@ const getKeyIndexData = async () => {
const { data, code } = res; const { data, code } = res;
if (code === 200) { if (code === 200) {
// 更新指标数据,使用接口返回的指定字段 // 更新指标数据,使用接口返回的指定字段
indicators.value[0].value = data.ongoingProject || 0; indicators.value[0].value = data.photovoltaicCount || 0;
indicators.value[1].value = data.totalContractAmount || 0; indicators.value[1].value = data.windElectricityCount || 0;
indicators.value[2].value = data.totalCapacity || 0; indicators.value[2].value = data.photovoltaicTotalCapacity || 0;
indicators.value[3].value = data.todayProject || 0; indicators.value[3].value = data.windElectricityTotalCapacity || 0;
} }
}; };
@ -163,8 +359,23 @@ const getKeyIndexData = async () => {
*/ */
const initAttendanceChart = () => { const initAttendanceChart = () => {
if (!attendanceChartRef.value) { if (!attendanceChartRef.value) {
console.warn('attendanceChartRef不存在');
return; return;
} }
// 确保有数据可显示
if (!projectAttendanceData.value || !projectAttendanceData.value.length) {
console.log('使用默认数据初始化图表');
projectAttendanceData.value = [
{ name: 'A项目', value: 62 },
{ name: 'B项目', value: 56 },
{ name: 'C项目', value: 95 },
{ name: 'D项目', value: 64 },
{ name: 'E项目', value: 97.5 }
];
}
console.log('开始初始化图表,当前数据:', projectAttendanceData.value);
attendanceChart = echarts.init(attendanceChartRef.value); attendanceChart = echarts.init(attendanceChartRef.value);
const option = { const option = {
@ -191,13 +402,45 @@ const initAttendanceChart = () => {
grid: { grid: {
top: 40, top: 40,
right: 30, right: 30,
bottom: 40, bottom: 60, // 增加底部空间以确保标签完全显示
left: 30, left: 30,
containLabel: true, containLabel: true,
backgroundColor: 'rgba(10, 24, 45, 0.1)', backgroundColor: 'rgba(10, 24, 45, 0.1)',
borderColor: 'rgba(29, 214, 255, 0.1)', borderColor: 'rgba(29, 214, 255, 0.1)',
borderWidth: 1 borderWidth: 1
}, },
// 添加dataZoom组件实现水平滚动
dataZoom: [
{
type: 'slider',
show: true,
xAxisIndex: [0],
start: 0,
end: 20, // 固定为20%与visiblePercentage保持一致
height: 20,
bottom: 10,
backgroundColor: 'rgba(10, 24, 45, 0.2)',
fillerColor: 'rgba(29, 214, 255, 0.2)',
borderColor: 'rgba(29, 214, 255, 0.3)',
textStyle: {
color: '#e6f7ff'
},
handleStyle: {
color: 'rgba(29, 214, 255, 0.6)',
borderColor: 'rgba(255, 255, 255, 0.3)'
},
moveHandleStyle: {
color: 'rgba(29, 214, 255, 0.8)'
}
},
// 支持鼠标滚轮缩放
{
type: 'inside',
xAxisIndex: [0],
start: 0,
end: 20 // 固定为20%与visiblePercentage保持一致
}
],
xAxis: { xAxis: {
type: 'category', type: 'category',
data: projectAttendanceData.value.map((item) => item.name), data: projectAttendanceData.value.map((item) => item.name),
@ -209,9 +452,18 @@ const initAttendanceChart = () => {
axisLabel: { axisLabel: {
color: '#e6f7ff', color: '#e6f7ff',
fontSize: 14, fontSize: 14,
interval: 0, interval: 0, // 强制显示所有标签
fontWeight: 'bold', fontWeight: 'bold',
padding: [10, 0, 0, 0] padding: [10, 0, 0, 0],
// 防止标签重叠,旋转角度调整
rotate: 0,
// 添加formatter函数当名称超过6个汉字时显示省略号
formatter: function (value) {
if (value.length > 6) {
return value.substring(0, 6) + '...';
}
return value;
}
}, },
axisTick: { axisTick: {
show: true, show: true,
@ -321,6 +573,11 @@ const initAttendanceChart = () => {
attendanceChart.setOption(option); attendanceChart.setOption(option);
// 移除自动滚动功能,保留其他事件监听
if (attendanceChartRef.value) {
// 保留其他可能需要的事件监听器
}
// 添加窗口大小变化时的图表更新 // 添加窗口大小变化时的图表更新
const handleResize = () => { const handleResize = () => {
if (attendanceChart) { if (attendanceChart) {
@ -333,6 +590,8 @@ const initAttendanceChart = () => {
// 清理函数 // 清理函数
onUnmounted(() => { onUnmounted(() => {
window.removeEventListener('resize', handleResize); window.removeEventListener('resize', handleResize);
// 移除鼠标事件监听(已在上面移除添加的事件监听)
}); });
}; };
@ -347,17 +606,20 @@ const initMapChart = () => {
mapChart.setOption(mapOption); mapChart.setOption(mapOption);
}; };
onMounted(() => { onMounted(async () => {
// nextTick(() => { // nextTick(() => {
// initMapChart(); // initMapChart();
// }); // });
getPeopleData(); getPeopleData();
getKeyIndexData(); getKeyIndexData();
getProjectAttendanceCount(); // 获取人员总览数据
getPeopleCategoryData();
// 初始化项目出勤率柱状图 // 先等待获取项目出勤率数据
setTimeout(() => { await getProjectAttendanceStats(); // 获取项目出勤率图表数据
initAttendanceChart();
}, 100); // 再初始化图表
initAttendanceChart();
}); });
onUnmounted(() => { onUnmounted(() => {
@ -383,37 +645,59 @@ onUnmounted(() => {
.endPage { .endPage {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center;
width: 100%; width: 100%;
padding: 15px 0; height: 250;
border: 1px solid rgba(29, 214, 255, 0.1); border: 1px solid rgba(29, 214, 255, 0.1);
box-sizing: border-box; box-sizing: border-box;
} }
.endPage { .endPage {
height: auto;
flex: 1; flex: 1;
margin-top: 23px; min-height: 550px;
} }
.project_attendance_chart { .project_attendance_chart {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center;
width: 100%; width: 100%;
padding: 15px 0; margin-top: 15px;
border: 1px solid rgba(29, 214, 255, 0.1); padding-bottom: 10px;
box-sizing: border-box;
.chart_title { .chart_title {
font-size: 16px; font-size: 16px;
color: #e6f7ff; color: #e6f7ff;
margin-bottom: 15px; margin-bottom: 5px;
text-align: left; text-align: left;
} }
.scroll_controls {
display: flex;
justify-content: flex-end;
gap: 10px;
margin-bottom: 10px;
padding-right: 10px;
}
.control_btn {
padding: 5px 15px;
background: rgba(10, 24, 45, 0.8);
border: 1px solid rgba(29, 214, 255, 0.3);
color: #e6f7ff;
font-size: 12px;
cursor: pointer;
border-radius: 4px;
transition: all 0.3s ease;
}
.control_btn:hover {
background: rgba(29, 214, 255, 0.2);
border-color: rgba(29, 214, 255, 0.6);
}
.chart_content { .chart_content {
width: 100%; width: 100%;
height: 200px; height: 320px; /* 增加高度以容纳滚动条 */
position: relative; position: relative;
overflow: hidden;
} }
} }
} }
@ -422,20 +706,20 @@ onUnmounted(() => {
width: 100%; width: 100%;
display: grid; display: grid;
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
gap: 15px; gap: 10px;
margin-top: 15px; margin-bottom: 8px;
padding: 0 15px; padding: 0 10px;
box-sizing: border-box; box-sizing: border-box;
} }
.indicator-card { .indicator-card {
position: relative; position: relative;
width: 100%; width: 100%;
height: 100px; height: 80px;
background: rgba(10, 24, 45, 0.7); background: rgba(10, 24, 45, 0.7);
border: 1px solid rgba(29, 214, 255, 0.2); border: 1px solid rgba(29, 214, 255, 0.2);
border-radius: 4px; border-radius: 4px;
padding: 15px; padding: 10px;
box-sizing: border-box; box-sizing: border-box;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -488,53 +772,149 @@ onUnmounted(() => {
object-fit: contain; object-fit: contain;
} }
.map { /* 人员总览样式 */
margin-top: 15px; .people_overview {
}
.attendance_tag {
width: 100%; width: 100%;
margin-top: 5px;
box-sizing: border-box;
border: 1px solid rgba(29, 214, 255, 0.1);
background: rgba(10, 24, 45, 0.3);
}
.people_overview_title {
font-size: 16px;
color: #e6f7ff;
margin-bottom: 5px;
border-bottom: 1px solid rgba(29, 214, 255, 0.1);
}
.people_overview_content {
display: flex; display: flex;
justify-content: space-between; align-items: center;
padding: 0 30px;
margin-top: 15px;
.tag_item {
width: 28%;
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
border: 1px dashed rgba(29, 214, 255, 0.3);
padding: 10px;
.tag_info {
font-size: 20px;
font-weight: 700;
color: rgba(230, 247, 255, 1);
text-shadow: 0px 1.24px 6.21px rgba(0, 190, 247, 1);
}
.tag_title {
font-size: 14px;
font-weight: 400;
color: rgba(230, 247, 255, 1);
}
}
} }
.attendance_list { .people_image {
padding: 0px 30px; width: 60px;
height: 60px;
background: linear-gradient(135deg, rgba(29, 214, 255, 0.1) 0%, rgba(29, 214, 255, 0.05) 100%);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.placeholder_image {
width: 100%;
height: 100%;
object-fit: contain;
}
.people_stats {
flex: 1;
display: flex;
justify-content: space-around;
}
.stat_item {
display: flex;
flex-direction: column;
align-items: center;
}
.stat_label {
font-size: 14px; font-size: 14px;
color: #8ab2ff;
.attendance_item { margin-bottom: 5px;
display: grid;
grid-template-columns: 3fr 2fr 2fr 3fr;
margin-top: 20px;
}
} }
.subfont { .stat_value {
color: rgba(138, 149, 165, 1); font-size: 28px;
font-weight: bold;
color: #e6f7ff;
text-shadow: 0px 1.24px 6.21px rgba(0, 190, 247, 0.5);
}
.stat_rate {
font-size: 28px;
font-weight: bold;
color: #00c853;
text-shadow: 0px 1.24px 6.21px rgba(0, 200, 83, 0.5);
}
.people_map {
width: 100%;
margin-top: 8px;
background: rgba(10, 24, 45, 0.5);
border: 1px solid rgba(29, 214, 255, 0.1);
border-radius: 4px;
overflow: hidden;
position: relative;
}
.map_background {
width: 100%;
height: 100%;
background-image: radial-gradient(circle, rgba(29, 214, 255, 0.3) 1px, transparent 1px),
radial-gradient(circle, rgba(29, 214, 255, 0.3) 1px, transparent 1px);
background-size: 40px 40px;
background-position:
0,
0,
20px 20px;
position: relative;
}
/* 人员分类统计样式 */
.people_categories {
display: flex;
justify-content: space-around;
margin-top: 5px;
}
.category_item {
display: flex;
flex: 1;
margin: 10px, 30px;
}
.category_icon {
margin-left: 15px;
margin-top: 10px;
width: 30px;
height: 30px;
background: linear-gradient(135deg, rgba(29, 214, 255, 0.1) 0%, rgba(10, 120, 200, 0.1) 100%);
border: 1px solid rgba(29, 214, 255, 0.2);
border-radius: 5px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.category_image {
width: 45px;
height: 45px;
object-fit: contain;
}
.category_info {
display: flex;
flex-direction: column;
margin-left: 8px;
margin-top: 8px;
flex: 1;
}
.category_label {
font-size: 12px;
color: #8ab2ff;
margin-bottom: 1px;
}
.category_count {
font-size: 16px;
font-weight: bold;
color: #e6f7ff;
text-shadow: 0px 1.24px 6.21px rgba(0, 190, 247, 0.3);
} }
</style> </style>

View File

@ -47,7 +47,7 @@ export let pieOption = {
alignTo: 'edge', alignTo: 'edge',
formatter: function (params) { formatter: function (params) {
// 只显示前三个数据项 // 只显示前三个数据项
return `{name|${params.data.name}}\n{percent|${params.data.completionRate}MW}`; return `{name|${params.data.name}}\n{percent|${(params.data.completionRate / 100).toFixed(2)}%}`;
}, },
minMargin: 10, minMargin: 10,
edgeDistance: 20, edgeDistance: 20,
@ -75,7 +75,7 @@ export let barOption = {
itemWidth: 12, itemWidth: 12,
itemHeight: 12, itemHeight: 12,
// 调整文字与图标间距 // 调整文字与图标间距
data: ['计划产值', '实际产值'], data: ['实际进度', '计划进度'],
top: 0, top: 0,
right: 10, right: 10,
bottom: 10, bottom: 10,
@ -90,11 +90,17 @@ export let barOption = {
trigger: 'axis', trigger: 'axis',
// formatter: '{b0}{c0}万元', // formatter: '{b0}{c0}万元',
formatter: (params: any) => { formatter: (params: any) => {
// console.log(params);
const projectName = params[0].name;
// params 是数组,对应每条柱子 // params 是数组,对应每条柱子
return params // return params.map((p: any) => `${p.name} <br/> ${p.seriesName}${Number(p.value).toFixed(2)} MW`).join('<br/>');
.map((p: any) => `${p.seriesName}${Number(p.value).toFixed(2)} 亿元`) return (
`${projectName}<br/>` +
.join('<br/>'); params
.slice(0, 2)
.map((p) => `${p.seriesName}${Number(p.value).toFixed(2)} MW`)
.join('<br/>')
);
}, },
textStyle: { textStyle: {
color: '#fff' color: '#fff'
@ -119,7 +125,7 @@ export let barOption = {
} }
}, },
yAxis: { yAxis: {
name: '单位:亿元', name: 'MW',
type: 'value', type: 'value',
axisLabel: { axisLabel: {
formatter: '{value}' formatter: '{value}'
@ -136,7 +142,7 @@ export let barOption = {
}, },
series: [ series: [
{ {
name: '计划产值', name: '实际进度',
type: 'bar', type: 'bar',
data: [], data: [],
barWidth: '10', barWidth: '10',
@ -161,7 +167,7 @@ export let barOption = {
} }
}, },
{ {
name: '实际产值', name: '计划进度',
type: 'bar', type: 'bar',
data: [], data: [],
barWidth: '10', barWidth: '10',

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="leftPage"> <div class="leftPage">
<div class="topPage"> <div class="topPage">
<Title title="项目进度分析" /> <Title title="项目进度分析" style="font-size: 22px" />
<div class="progress"> <div class="progress">
<div class="progress_item"> <div class="progress_item">
<div class="progress_imgBox"> <div class="progress_imgBox">
@ -53,7 +53,7 @@
</div> </div>
</div> </div>
<div class="output"> <div class="output">
<Title title="实际产值与预期产值对比" /> <Title title="实际进度与计划进度对比" style="font-size: 22px" />
<div class="chart_container"> <div class="chart_container">
<div ref="lineChartRef" class="echart" /> <div ref="lineChartRef" class="echart" />
</div> </div>
@ -107,26 +107,27 @@ const processedDataList = ref([]);
//获取数据 //获取数据
const getData = async () => { const getData = async () => {
const res = await projectProgress(); const res = await projectProgress();
console.log('🚀 ~ getData ~ res:', res);
if (res.code == 200) { if (res.code == 200) {
capacityData.value = res.data; capacityData.value = res.data;
// processedDataList.value = res.data.projectProgressDetailList; // processedDataList.value = res.data.projectProgressDetailList;
let totalCapacity = 0; // let totalCapacity = 0;
const processedData = res.data.projectProgressDetailList.map((item) => { // const processedData = res.data.projectProgressDetailList.map((item) => {
const capacity = parseInt(item.projectCapacity) || 0; // const capacity = parseInt(item.projectCapacity) || 0;
totalCapacity += capacity; // totalCapacity += capacity;
return { // return {
name: item.projectName, // name: item.projectName,
value: capacity, // value: capacity,
completionRate: item.completionRate // completionRate: item.completionRate
}; // };
}); // });
// 计算每个项目的百分比 // // 计算每个项目的百分比
processedData.forEach((item) => { // processedData.forEach((item) => {
item.percentage = totalCapacity > 0 ? ((item.value / totalCapacity) * 100).toFixed(2) : '0%'; // item.percentage = totalCapacity > 0 ? ((item.value / totalCapacity) * 100).toFixed(2) : '0%';
}); // });
processedDataList.value = processedData; // processedDataList.value = processedData;
initPieChart(); // initPieChart();
} }
}; };
// 初始化饼图 // 初始化饼图
@ -143,7 +144,7 @@ const initPieChart = () => {
}; };
}); });
pieOption.series.data = data; pieOption.series.data = data;
console.log(data);
// pieOption.graphic[0].style.text = totalPercent.value + '%'; // pieOption.graphic[0].style.text = totalPercent.value + '%';
pieChart = echarts.init(pieChartRef.value, null, { pieChart = echarts.init(pieChartRef.value, null, {
renderer: 'canvas', renderer: 'canvas',
@ -155,9 +156,27 @@ const initPieChart = () => {
const getOutputData = async () => { const getOutputData = async () => {
const res = await outpuProgress(); const res = await outpuProgress();
if (res.code == 200) { if (res.code == 200) {
designAreaData.value = res.data.map((item: any) => Number(item.planValue)); designAreaData.value = res.data.map((item: any) => Number((item.plannedCapacity * item.progressPercentage) / 100));
transferAreaData.value = res.data.map((item: any) => Number(item.actualValue)); transferAreaData.value = res.data.map((item: any) => Number(item.plannedCapacity));
barNames.value = res.data.map((item: any) => item.projectName); barNames.value = res.data.map((item: any) => item.projectName);
let totalCapacity = 0;
const processedData = res.data.map((item) => {
const capacity = item.plannedCapacity * item.progressPercentage || 0;
totalCapacity += capacity;
return {
name: item.projectName,
value: capacity,
completionRate: item.progressPercentage
};
});
// 计算每个项目的百分比
processedData.forEach((item) => {
item.percentage = totalCapacity > 0 ? ((item.value / totalCapacity) * 100).toFixed(2) : '0%';
});
processedDataList.value = processedData;
initPieChart();
initLineChart(); initLineChart();
} }
}; };
@ -328,13 +347,14 @@ onUnmounted(() => {
padding: 15px 5px 5px 5px; padding: 15px 5px 5px 5px;
.progress_text_title { .progress_text_title {
width: 100%; width: 100%;
// height: 100%; height: 100%;
display: flex; display: flex;
justify-content: space-between; justify-content: center;
align-items: center; align-items: center;
& > div:first-child { & > div:first-child {
// 第一个子元素的样式 // 第一个子元素的样式
width: 50%; // width: 50%;
height: 100%;
font-size: 24px; font-size: 24px;
// font-weight: bold; // font-weight: bold;
font-family: 'AlimamaShuHeiTi', sans-serif; font-family: 'AlimamaShuHeiTi', sans-serif;
@ -343,10 +363,14 @@ onUnmounted(() => {
& > div:last-child { & > div:last-child {
// 最后一个子元素的样式 // 最后一个子元素的样式
width: 50%; // width: 50%;
height: 100%;
font-size: 12px; font-size: 12px;
color: #999; color: #999;
text-align: center; display: flex;
justify-content: center;
align-items: center;
padding-left: 5px;
} }
} }
.content_text { .content_text {

View File

@ -31,15 +31,15 @@ const isHideOther = ref(false);
* 切换中心页面全屏 * 切换中心页面全屏
*/ */
const handleChangePage = () => { const handleChangePage = () => {
if (isFull.value) { // if (isFull.value) {
isFull.value = false; // isFull.value = false;
setTimeout(() => { // setTimeout(() => {
isHideOther.value = false; // isHideOther.value = false;
}, 500); // }, 500);
} else { // } else {
isFull.value = true; // isFull.value = true;
isHideOther.value = true; // isHideOther.value = true;
} // }
}; };
</script> </script>

View File

@ -71,15 +71,17 @@ let data = [
const getTrajectoryData = async () => { const getTrajectoryData = async () => {
try { try {
// 从URL参数中获取clientId、projectId和userId // 从URL参数中获取clientId、projectId和userId
const { clientId, projectId, userId } = route.query; const { clientId, projectId, userId, gpsType } = route.query;
if (!clientId || !projectId || !userId) { if (!projectId || !userId || !gpsType) {
ElMessage.warning('缺少必要参数,请检查传入的参数'); ElMessage.warning('缺少必要参数,请检查传入的参数');
return; return;
} }
loading.value = true; loading.value = true;
const res = await getFootNote({ clientId, projectId, userId }); // 确保gpsType转换为数字类型以便正确传递给后端
const gpsTypeNum = parseInt(gpsType, 10);
const res = await getFootNote({ clientId, projectId, userId, gpsType: gpsTypeNum });
if (res && res.code === 200 && res.data && res.data.length > 0) { if (res && res.code === 200 && res.data && res.data.length > 0) {
data = res.data; data = res.data;

View File

@ -22,7 +22,7 @@
<el-card shadow="never"> <el-card shadow="never">
<template #header> <template #header>
<el-row :gutter="10" class="mb8"> <el-row :gutter="20" class="mb8">
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['gps:equipment:edit']" <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['gps:equipment:edit']"
>修改</el-button >修改</el-button
@ -39,7 +39,12 @@
> >
</el-col> </el-col>
<el-col :span="2"> <el-col :span="2">
<el-button type="primary" plain @click="handleViewAll">{{ viewAllButtonText }}</el-button> <el-button type="primary" plain @click="toggleGpsType">
{{ currentGpsType === 0 ? '显示用户数据' : '显示设备数据' }}
</el-button>
</el-col>
<el-col :span="2">
<el-button type="primary" v-if="queryParams.gpsType !== 1" plain @click="handleViewAll">{{ viewAllButtonText }}</el-button>
</el-col> </el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
@ -102,7 +107,7 @@
type="primary" type="primary"
icon="Location" icon="Location"
v-hasPermi="['gps:equipmentSon:getList']" v-hasPermi="['gps:equipmentSon:getList']"
@click="handleGoToEmptyPage(scope.row.userId, scope.row.projectId, scope.row.clientId)" @click="handleGoToEmptyPage(scope.row.userId, scope.row.projectId, scope.row.clientId, scope.row.gpsType)"
:disabled="!scope.row.userId || !scope.row.projectId" :disabled="!scope.row.userId || !scope.row.projectId"
></el-button> ></el-button>
</el-tooltip> </el-tooltip>
@ -189,7 +194,7 @@
type="primary" type="primary"
icon="Location" icon="Location"
v-hasPermi="['gps:equipmentSon:getList']" v-hasPermi="['gps:equipmentSon:getList']"
@click="handleGoToEmptyPage(scope.row.userId, scope.row.projectId, currentHistoryClientId)" @click="handleGoToEmptyPage(scope.row.userId, scope.row.projectId, currentHistoryClientId, currentGpsType)"
></el-button> ></el-button>
</el-tooltip> </el-tooltip>
</template> </template>
@ -301,6 +306,9 @@ const initFormData: EquipmentForm = {
remark: undefined remark: undefined
}; };
// 当前GPS类型 (0:设备数据, 1:用户数据)
const currentGpsType = ref(0);
// 页面数据 // 页面数据
const data = reactive<PageData<EquipmentForm, EquipmentQuery>>({ const data = reactive<PageData<EquipmentForm, EquipmentQuery>>({
form: { ...initFormData }, form: { ...initFormData },
@ -317,6 +325,7 @@ const data = reactive<PageData<EquipmentForm, EquipmentQuery>>({
creationTime: undefined, creationTime: undefined,
lastAccessedTime: undefined, lastAccessedTime: undefined,
registered: undefined, registered: undefined,
gpsType: 0, // 默认显示设备数据
params: {} params: {}
}, },
rules: { rules: {
@ -385,6 +394,15 @@ const formatDateTime = (timestamp: any): string => {
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}; };
/** 切换GPS数据类型 */
const toggleGpsType = () => {
currentGpsType.value = currentGpsType.value === 0 ? 1 : 0;
queryParams.value.gpsType = currentGpsType.value;
queryParams.value.pageNum = 1;
getList();
proxy?.$modal.msgSuccess(`已切换到${currentGpsType.value === 0 ? '设备数据' : '用户数据'}模式`);
};
/** 获取设备列表 */ /** 获取设备列表 */
const getList = async () => { const getList = async () => {
loading.value = true; loading.value = true;
@ -397,6 +415,9 @@ const getList = async () => {
queryParams.value.projectId = undefined; queryParams.value.projectId = undefined;
} }
// 确保gpsType参数正确设置
queryParams.value.gpsType = currentGpsType.value;
const res = await listEquipment(queryParams.value); const res = await listEquipment(queryParams.value);
equipmentList.value = res.rows as ExtendedEquipmentVO[]; equipmentList.value = res.rows as ExtendedEquipmentVO[];
total.value = res.total; total.value = res.total;
@ -490,16 +511,24 @@ const handleViewAll = () => {
getList(); getList();
}; };
const handleGoToEmptyPage = (userId: any, projectId: any, clientId: any) => { const handleGoToEmptyPage = (userId: any, projectId: any, clientId: any, gpsType: number) => {
console.log('userId:', userId, 'projectId:', projectId, 'clientId:', clientId); console.log('userId:', userId, 'projectId:', projectId, 'clientId:', clientId, 'gpsType:', gpsType);
const queryParams: any = {
userId: userId,
projectId: projectId,
gpsType: gpsType,
clientId: clientId
};
// 当gpsType为0时传入clientId为1时不传入
if (gpsType === 1 && clientId) {
queryParams.clientId = '';
}
router.push({ router.push({
path: './equipmentGPS', path: './equipmentGPS',
query: { query: queryParams
userId: userId,
projectId: projectId,
clientId: clientId
}
}); });
}; };

View File

@ -82,18 +82,11 @@
</el-row> </el-row>
</template> </template>
<el-table <el-table v-loading="loading" :data="formalitiesAreConsolidatedList" @selection-change="handleSelectionChange" row-key="id" default-expand-all>
v-loading="loading"
:table-layout="'auto'"
:data="formalitiesAreConsolidatedList"
@selection-change="handleSelectionChange"
row-key="id"
default-expand-all
>
<el-table-column type="selection" width="55" align="center" /> <el-table-column type="selection" width="55" align="center" />
<el-table-column label="手续办理清单" align="left" prop="formalitiesName"> <el-table-column label="手续办理清单" align="left" prop="formalitiesName">
<template #default="scope"> <template #default="scope">
{{ scope.row.formalitiesName }} <div>{{ scope.row.formalitiesName }}</div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="计划开始时间" align="center" prop="planTheStartTime" width="180"> <el-table-column label="计划开始时间" align="center" prop="planTheStartTime" width="180">

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="ol-map" id="olMap"></div> <div class="ol-map" id="olMap"></div>
<div class="left_title_button"> <div class="left_title_button">
<div class="title">{{ projectName }}</div> <div class="title">{{ currentProject.name }}</div>
<div class="btn" @click="updateZhiJiaZhuanDian('zhuangdian')"> <div class="btn" @click="updateZhiJiaZhuanDian('zhuangdian')">
<SvgIcon :name="bottomSvg" :isStyle="true" :className="'width:250px;height:50px;'" /> <SvgIcon :name="bottomSvg" :isStyle="true" :className="'width:250px;height:50px;'" />
<span>桩点-更新高程</span> <span>桩点-更新高程</span>
@ -29,6 +29,11 @@
import { workScheduleDel } from '@/api/progress/plan'; import { workScheduleDel } from '@/api/progress/plan';
import { renderFacilitiesToCesium } from '@/views/gisHome/js/renderFacilities'; import { renderFacilitiesToCesium } from '@/views/gisHome/js/renderFacilities';
import { CenterHeight } from '@/views/gis2D/js/center'; import { CenterHeight } from '@/views/gis2D/js/center';
import { useUserStoreHook } from '@/store/modules/user';
const userStore = useUserStoreHook();
const currentProject = computed(() => userStore.selectedProject);
console.log('projectName', currentProject);
import md5 from 'js-md5'; import md5 from 'js-md5';
const arr = ref(); const arr = ref();
const initFacilities = async () => { const initFacilities = async () => {
@ -129,8 +134,10 @@ onMounted(async () => {
username: 'admin', username: 'admin',
password: md5('admin_admin123'), password: md5('admin_admin123'),
host: 'http://192.168.110.2:8895/' host: 'http://192.168.110.2:8895/'
}).then((res) => {
createEarth();
console.log(res);
}); });
createEarth();
await handletilList(); await handletilList();
await initFacilities(); await initFacilities();
console.log(YJ); console.log(YJ);

View File

@ -9,7 +9,7 @@
<!-- 合同利润保持万元显示 --> <!-- 合同利润保持万元显示 -->
<RevenueContractCard title="合同利润" :value="formatToTenThousand(data.profitAmount, 'tenThousand')" /> <RevenueContractCard title="合同利润" :value="formatToTenThousand(data.profitAmount, 'tenThousand')" />
<!-- 工程变更改为百分比显示 --> <!-- 工程变更改为百分比显示 -->
<RevenueContractCard title="工程变更" :value="formatToTenThousand(data.changeAmount, 'percentage')" unit="" /> <!-- <RevenueContractCard title="工程变更" :value="formatToTenThousand(data.changeAmount, 'percentage')" unit="" /> -->
</div> </div>
</div> </div>
<div class="centerPage_map"> <div class="centerPage_map">

View File

@ -25,7 +25,7 @@
class="weather-item" class="weather-item"
:style="{ transform: `translateY(-${offsetY}px)`, transition: transition }" :style="{ transform: `translateY(-${offsetY}px)`, transition: transition }"
> >
<img :src="`../../../src/assets/images/${item.icon}.png`" alt="" /> <img :src="`/assets/demo/${item.icon}.png`" alt="" />
<div>{{ item.weather }}{{ item.tempMin }}°/{{ item.tempMax }}°</div> <div>{{ item.weather }}{{ item.tempMin }}°/{{ item.tempMax }}°</div>
<div>{{ item.week }}({{ item.date }})</div> <div>{{ item.week }}({{ item.date }})</div>
</div> </div>

View File

@ -1,4 +1,4 @@
ID<template> <template>
<div class="large-screen"> <div class="large-screen">
<Header /> <Header />
<div class="nav"> <div class="nav">
@ -21,7 +21,6 @@ import leftPage from './components/leftPage.vue';
import centerPage from './components/centerPage.vue'; import centerPage from './components/centerPage.vue';
import rightPage from './components/rightPage.vue'; import rightPage from './components/rightPage.vue';
// import '@/assets/styles/element.scss'; // import '@/assets/styles/element.scss';
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@ -3,13 +3,19 @@
<div class="max-w-4xl mx-auto"> <div class="max-w-4xl mx-auto">
<!-- 顶部按钮区域 --> <!-- 顶部按钮区域 -->
<el-card class="mb-4 rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md"> <el-card class="mb-4 rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md">
<approvalButton @submitForm="submitForm" @approvalVerifyOpen="approvalVerifyOpen" <approvalButton
@handleApprovalRecord="handleApprovalRecord" :buttonLoading="buttonLoading" :id="form.mrpBaseBo.id" @submitForm="submitForm"
:status="form.mrpBaseBo.status" :pageType="routeParams.type" /> @approvalVerifyOpen="approvalVerifyOpen"
@handleApprovalRecord="handleApprovalRecord"
:buttonLoading="buttonLoading"
:id="form.mrpBaseBo.id"
:status="form.mrpBaseBo.status"
:pageType="routeParams.type"
:projectName="routeParams.projectName"
/>
</el-card> </el-card>
<!-- 表单区域 --> <!-- 表单区域 -->
<el-card <el-card class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
class="rounded-lg shadow-sm bg-white border border-gray-100 transition-all hover:shadow-md overflow-hidden">
<div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100"> <div class="p-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-gray-100">
<h3 class="text-lg font-semibold text-gray-800">物资设备批次需求计划</h3> <h3 class="text-lg font-semibold text-gray-800">物资设备批次需求计划</h3>
<el-row :gutter="20"> <el-row :gutter="20">
@ -20,8 +26,7 @@
</el-col> </el-col>
<el-col :span="8" :offset="0"> <el-col :span="8" :offset="0">
<el-form-item label="编制日期" prop="mrpBaseBo.preparedDate"> <el-form-item label="编制日期" prop="mrpBaseBo.preparedDate">
<el-date-picker v-model="form.mrpBaseBo.preparedDate" type="date" value-format="YYYY-MM-DD" disabled <el-date-picker v-model="form.mrpBaseBo.preparedDate" type="date" value-format="YYYY-MM-DD" disabled placeholder="请选择编制日期" />
placeholder="请选择编制日期" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8" :offset="0"> <el-col :span="8" :offset="0">
@ -50,8 +55,14 @@
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" /> <submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
<approvalRecord ref="approvalRecordRef"></approvalRecord> <approvalRecord ref="approvalRecordRef"></approvalRecord>
<!-- 流程选择对话框 --> <!-- 流程选择对话框 -->
<el-dialog draggable v-model="dialogVisible.visible" :title="dialogVisible.title" :before-close="handleClose" <el-dialog
width="500" class="rounded-lg shadow-lg"> draggable
v-model="dialogVisible.visible"
:title="dialogVisible.title"
:before-close="handleClose"
width="500"
class="rounded-lg shadow-lg"
>
<div class="p-4"> <div class="p-4">
<p class="text-gray-600 mb-4">请选择要启动的流程</p> <p class="text-gray-600 mb-4">请选择要启动的流程</p>
<el-select v-model="flowCode" placeholder="请选择流程" style="width: 100%"> <el-select v-model="flowCode" placeholder="请选择流程" style="width: 100%">
@ -60,10 +71,12 @@
</div> </div>
<template #footer> <template #footer>
<div class="dialog-footer p-4 border-t border-gray-100 flex justify-end space-x-3"> <div class="dialog-footer p-4 border-t border-gray-100 flex justify-end space-x-3">
<el-button @click="handleClose" <el-button @click="handleClose" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors"
class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors">取消</el-button> >取消</el-button
<el-button type="primary" @click="submitFlow()" >
class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors">确认</el-button> <el-button type="primary" @click="submitFlow()" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors"
>确认</el-button
>
</div> </div>
</template> </template>
</el-dialog> </el-dialog>

View File

@ -11,6 +11,7 @@
:id="form.id" :id="form.id"
:status="form.approvalDesign" :status="form.approvalDesign"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>
<!-- 表单区域 --> <!-- 表单区域 -->

View File

@ -8,27 +8,35 @@
<span>{{ scope.row.residue }}</span> <span>{{ scope.row.residue }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="出库数量" align="center" prop="number"> <el-table-column label="出库数量" align="center" prop="number" width="150px">
<template #default="scope"> <template #default="scope">
<el-input-number v-if="scope.row.type" v-model="scope.row.number" :controls="false" :min="0" :max="scope.row.residue" :precision="0" /> <el-input-number
v-if="scope.row.type"
v-model="scope.row.number"
:controls="false"
:min="0"
:max="scope.row.residue"
:precision="0"
style="width: 100px"
/>
<span v-else>{{ scope.row.number }}</span> <span v-else>{{ scope.row.number }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="交接单位" align="center" prop="recipient"> <el-table-column label="交接单位" align="center" prop="recipient" width="150px">
<template #default="scope"> <template #default="scope">
<el-input v-if="scope.row.type" style="width: 150px" v-model="scope.row.recipient" /> <el-input v-if="scope.row.type" v-model="scope.row.recipient" width="100px" />
<span v-else>{{ scope.row.recipient }}</span> <span v-else>{{ scope.row.recipient }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="领用人" align="center" prop=" shipper"> <el-table-column label="领用人" align="center" prop=" shipper" width="150px">
<template #default="scope"> <template #default="scope">
<el-input v-if="scope.row.type" style="width: 150px" v-model="scope.row.shipper" /> <el-input v-if="scope.row.type" v-model="scope.row.shipper" width="100px" />
<span v-else>{{ scope.row.shipper }}</span> <span v-else>{{ scope.row.shipper }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作人" align="center" prop="operator"> <el-table-column label="操作人" align="center" prop="operator" width="150px">
<template #default="scope"> <template #default="scope">
<el-input v-if="scope.row.type" style="width: 150px" v-model="scope.row.operator" /> <el-input v-if="scope.row.type" v-model="scope.row.operator" width="100px" />
<span v-else>{{ scope.row.operator }}</span> <span v-else>{{ scope.row.operator }}</span>
</template> </template>
</el-table-column> </el-table-column>

View File

@ -70,6 +70,13 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="备注" align="center" prop="remark" /> <el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="附件" align="center" prop="attachmentName">
<template #default="scope">
<el-button :href="scope.row.attachmentName" link type="primary" @click="downloadAttachment(scope.row)">{{
scope.row.attachmentName
}}</el-button>
</template>
</el-table-column>
<el-table-column label="操作" align="center" min-width="120" fixed="right"> <el-table-column label="操作" align="center" min-width="120" fixed="right">
<template #default="scope"> <template #default="scope">
<!-- <el-button link type="primary" icon="edit" @click="handleUpdate(scope.row)" v-hasPermi="['materials:materialReceive:edit']" <!-- <el-button link type="primary" icon="edit" @click="handleUpdate(scope.row)" v-hasPermi="['materials:materialReceive:edit']"
@ -254,6 +261,11 @@
<file-upload :isShowTip="false" :fileType="['pdf', 'png', 'jpg', 'jpeg']" v-model="form.licenseCountFileId" /> <file-upload :isShowTip="false" :fileType="['pdf', 'png', 'jpg', 'jpeg']" v-model="form.licenseCountFileId" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12">
<el-form-item label="附件" prop="attachmentId">
<file-upload :isShowTip="false" :fileType="['pdf', 'png', 'jpg', 'jpeg', 'zip']" v-model="form.attachmentId" />
</el-form-item>
</el-col>
<el-col :span="24"> <el-col :span="24">
<span style="color: #ff0000ab; margin-bottom: 10px; display: block">注意pdf/png/jpg/jpeg格式文件</span> <span style="color: #ff0000ab; margin-bottom: 10px; display: block">注意pdf/png/jpg/jpeg格式文件</span>
</el-col> </el-col>
@ -351,6 +363,7 @@ const getInitFormData = (): MaterialReceiveForm => {
techDocCountFileId: undefined, techDocCountFileId: undefined,
licenseCount: undefined, licenseCount: undefined,
licenseCountFileId: undefined, licenseCountFileId: undefined,
attachmentId: undefined,
storageType: '1', storageType: '1',
remark: undefined, remark: undefined,
docId: undefined, docId: undefined,
@ -538,6 +551,17 @@ const handleUpdate = async (row?: MaterialReceiveVO) => {
proxy?.$modal.msgError('获取详情失败'); proxy?.$modal.msgError('获取详情失败');
} }
}; };
//下载附件
const downloadAttachment = (row: any) => {
if (row.attachmentUrl) {
const link = document.createElement('a');
link.href = row.attachmentUrl;
link.download = row.fileName || 'download';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
};
/** 提交按钮 */ /** 提交按钮 */
const submitForm = () => { const submitForm = () => {

View File

@ -3,7 +3,25 @@
<el-row :gutter="10" class="mb8"> <el-row :gutter="10" class="mb8">
<el-col :span="5"> <el-col :span="5">
<el-card shadow="never"> <el-card shadow="never">
<el-tree style="max-width: 600px" :data="TreeData" :props="defaultProps" @node-click="handleNodeClick" /> <!-- <el-tree style="max-width: 600px" :data="TreeData" :props="defaultProps" @node-click="handleNodeClick" /> -->
<el-tree
:data="TreeData"
:props="defaultProps"
@node-click="handleNodeClick"
node-key="id"
default-expand-all
:expand-on-click-node="false"
>
<template #default="{ node, data }">
<span class="custom-tree-node">
<span class="tree-title">
<div>
<div>{{ node.label }}</div>
</div>
</span>
</span>
</template>
</el-tree>
</el-card> </el-card>
</el-col> </el-col>
@ -473,3 +491,53 @@ onMounted(() => {
getMaterialsListData(); getMaterialsListData();
}); });
</script> </script>
<style lang="scss" scoped>
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding-right: 8px;
height: 40px; /* 固定高度 */
}
.tree-title {
display: flex;
align-items: center;
}
:deep(.el-tree) {
font-weight: normal;
}
:deep(.el-tree-node) {
margin: 2px 0;
}
:deep(.el-tree-node__content) {
height: auto !important;
margin: 2px 0;
border-radius: 4px;
transition: all 0.3s;
}
:deep(.el-tree-node__content:hover) {
background-color: #ecf5ff !important;
}
/* 为不同层级添加不同的边框颜色 */
:deep(.el-tree-node:focus > .el-tree-node__content) {
background-color: #d9ecff !important;
}
:deep(.el-tree-node > .el-tree-node__content) {
border-left: 3px solid #409eff;
}
:deep(.el-tree-node .el-tree-node__children .el-tree-node__content) {
border-left: 3px solid #67c23a;
}
:deep(.el-tree-node .el-tree-node__children .el-tree-node__children .el-tree-node__content) {
border-left: 3px solid #e6a23c;
}
</style>

View File

@ -11,6 +11,7 @@
:id="form.id" :id="form.id"
:status="form.approvalOrder" :status="form.approvalOrder"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>
<!-- 表单区域 --> <!-- 表单区域 -->

View File

@ -11,6 +11,7 @@
:id="form.id" :id="form.id"
:status="form.status" :status="form.status"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>
<!-- 表单区域 --> <!-- 表单区域 -->
@ -319,7 +320,9 @@ onMounted(() => {
.el-input__inner, .el-input__inner,
.el-select .el-input__inner { .el-select .el-input__inner {
border-radius: 4px; border-radius: 4px;
transition: border-color 0.2s, box-shadow 0.2s; transition:
border-color 0.2s,
box-shadow 0.2s;
&:focus { &:focus {
border-color: var(--primary-light); border-color: var(--primary-light);
@ -329,7 +332,9 @@ onMounted(() => {
.el-textarea__inner { .el-textarea__inner {
border-radius: 4px; border-radius: 4px;
transition: border-color 0.2s, box-shadow 0.2s; transition:
border-color 0.2s,
box-shadow 0.2s;
&:focus { &:focus {
border-color: var(--primary-light); border-color: var(--primary-light);

View File

@ -11,6 +11,7 @@
:id="form.id" :id="form.id"
:status="form.status" :status="form.status"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>

View File

@ -11,6 +11,7 @@
:id="form.id" :id="form.id"
:status="form.approvalPlan" :status="form.approvalPlan"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>
<!-- 表单区域 --> <!-- 表单区域 -->

View File

@ -0,0 +1,311 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="编码" prop="code">
<el-input v-model="queryParams.code" placeholder="请输入编码" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['mechanical:mechanicaltype:add']">新增</el-button>
</el-col>
<!-- <el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['mechanical:mechanicaltype:edit']"
>修改</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete()"
v-hasPermi="['mechanical:mechanicaltype:remove']"
>删除</el-button
>
</el-col> -->
<!-- <el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['mechanical:mechanicaltype:export']">导出</el-button>
</el-col> -->
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="mechanicaltypeList">
<!-- <el-table-column type="selection" width="55" align="center" /> -->
<!-- <el-table-column label="id" align="center" prop="id" v-if="true" /> -->
<el-table-column label="编码" align="center" prop="code" />
<el-table-column label="父编码" align="center" prop="pcode" />
<el-table-column label="大" align="center" prop="largeclass" />
<el-table-column label="中" align="center" prop="middleclass" />
<el-table-column label="子类" align="center" prop="subclass" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="全名" align="center" prop="fullName" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['mechanical:mechanicaltype:edit']"
>修改</el-button
>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['mechanical:mechanicaltype:remove']"
>删除</el-button
>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改设备类型对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="mechanicaltypeFormRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="编码" prop="code">
<el-input v-model="form.code" placeholder="请输入编码" :disabled="form.id ? true : false" />
</el-form-item>
<el-form-item label="父编码" prop="pcode">
<el-input v-model="form.pcode" placeholder="请输入父编码" :disabled="form.id ? true : false" />
</el-form-item>
<el-form-item label="类型" prop="deviceType">
<el-select v-model="form.deviceType" placeholder="选择类型" @change="changeDeviceType" :disabled="form.id ? true : false">
<el-option v-for="item in devicelist" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="大类" prop="largeclass" v-if="form.deviceType == '1'">
<el-input v-model="form.largeclass" placeholder="请输入大类" />
</el-form-item>
<el-form-item label="中" prop="middleclass" v-if="form.deviceType == '2'">
<el-input v-model="form.middleclass" placeholder="请输入中" />
</el-form-item>
<el-form-item label="子类" prop="subclass" v-if="form.deviceType == '3'">
<el-input v-model="form.subclass" placeholder="请输入子类" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
<el-form-item label="全名" prop="fullName" v-if="form.deviceType == '3'">
<el-input v-model="form.fullName" placeholder="请输入全名" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="Mechanicaltype" lang="ts">
import { listMechanicaltype, getMechanicaltype, delMechanicaltype, addMechanicaltype, updateMechanicaltype } from '@/api/mechanical/mechanicaltype';
import { MechanicaltypeVO, MechanicaltypeQuery, MechanicaltypeForm } from '@/api/mechanical/mechanicaltype/types';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const mechanicaltypeList = ref<MechanicaltypeVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const queryFormRef = ref<ElFormInstance>();
const mechanicaltypeFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const devicelist = ref([
{
label: '大',
value: '1'
},
{
label: '中',
value: '2'
},
{
label: '子类',
value: '3'
}
]);
const initFormData: MechanicaltypeForm = {
id: undefined,
code: undefined,
pcode: undefined,
largeclass: undefined,
middleclass: undefined,
subclass: undefined,
remark: undefined,
fullName: undefined,
deviceType: undefined
};
const data = reactive<PageData<MechanicaltypeForm, MechanicaltypeQuery>>({
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
code: undefined,
pcode: undefined,
largeclass: undefined,
middleclass: undefined,
subclass: undefined,
fullName: undefined,
params: {}
},
rules: {
code: [{ required: true, message: '编码不能为空', trigger: 'blur' }],
pcode: [{ required: true, message: '父编码不能为空', trigger: 'blur' }],
deviceType: [{ required: true, message: '类型不能为空', trigger: 'blur' }],
largeclass: [{ required: true, message: '大不能为空', trigger: 'blur' }],
middleclass: [{ required: true, message: '中不能为空', trigger: 'blur' }],
subclass: [{ required: true, message: '子类不能为空', trigger: 'blur' }],
// remark: [{ required: true, message: '备注不能为空', trigger: 'blur' }],
fullName: [{ required: true, message: '全名不能为空', trigger: 'blur' }]
}
});
const { queryParams, form, rules } = toRefs(data);
const changeDeviceType = () => {
if (form.value.deviceType == '1') {
form.value.middleclass = undefined;
form.value.subclass = undefined;
form.value.fullName = undefined;
} else if (form.value.deviceType == '2') {
form.value.largeclass = undefined;
form.value.subclass = undefined;
form.value.fullName = undefined;
} else if (form.value.deviceType == '3') {
form.value.largeclass = undefined;
form.value.middleclass = undefined;
}
};
/** 查询设备类型列表 */
const getList = async () => {
loading.value = true;
const res = await listMechanicaltype(queryParams.value);
mechanicaltypeList.value = res.rows;
total.value = res.total;
loading.value = false;
};
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
};
/** 表单重置 */
const reset = () => {
form.value = { ...initFormData };
mechanicaltypeFormRef.value?.resetFields();
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
};
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
handleQuery();
};
/** 多选框选中数据 */
const handleSelectionChange = (selection: MechanicaltypeVO[]) => {
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
};
/** 新增按钮操作 */
const handleAdd = () => {
reset();
dialog.visible = true;
dialog.title = '添加设备类型';
};
/** 修改按钮操作 */
const handleUpdate = async (row?: MechanicaltypeVO) => {
reset();
const _id = row?.id || ids.value[0];
const res = await getMechanicaltype(_id);
console.log(res);
if (res.data.subclass) {
res.data.deviceType = '3';
}
if (res.data.middleclass) {
res.data.deviceType = '2';
}
if (res.data.largeclass) {
res.data.deviceType = '1';
}
Object.assign(form.value, res.data);
dialog.visible = true;
dialog.title = '修改设备类型';
};
/** 提交按钮 */
const submitForm = () => {
mechanicaltypeFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.id) {
await updateMechanicaltype(form.value).finally(() => (buttonLoading.value = false));
} else {
await addMechanicaltype(form.value).finally(() => (buttonLoading.value = false));
}
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
}
});
};
/** 删除按钮操作 */
const handleDelete = async (row?: MechanicaltypeVO) => {
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除设备类型编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
await delMechanicaltype(_ids);
proxy?.$modal.msgSuccess('删除成功');
await getList();
};
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download(
'mechanical/mechanicaltype/export',
{
...queryParams.value
},
`mechanicaltype_${new Date().getTime()}.xlsx`
);
};
onMounted(() => {
getList();
});
</script>

View File

@ -0,0 +1,300 @@
<template>
<!-- 添加或修改机械台账对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="50%" append-to-body>
<el-form ref="mechanicalrewritingFormRef" :model="form" :rules="rules" label-width="120px">
<el-row>
<el-col :span="12">
<el-form-item label="设备名称" prop="devicename">
<el-input v-model="form.devicename" placeholder="请输入设备名称" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="设备类型" prop="equipmentType">
<!-- <el-cascader v-model="form.deviceType" :options="options" @change="handleChange" /> -->
<el-cascader
placeholder="请选择设备类型"
:emitPath="false"
filterable
v-model="form.equipmentType"
:options="options"
:props="propsConfig"
@change="handleChange"
style="width: 300px"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="设备编号" prop="deviceNumber">
<el-input v-model="form.deviceNumber" placeholder="请输入设备编号" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="班组名称" prop="teamName">
<el-input v-model="form.teamName" placeholder="请输入班组名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="入场日期" prop="entryTime">
<el-date-picker clearable v-model="form.entryTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择入场日期"> </el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="规格型号" prop="specification">
<el-input v-model="form.specification" placeholder="请输入规格型号" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="生产能力" prop="production">
<el-input v-model="form.production" placeholder="请输入生产能力" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="车牌号码" prop="plateNumber">
<el-input v-model="form.plateNumber" placeholder="请输入车牌号码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="设备管理员" prop="deviceKeeper">
<el-input v-model="form.deviceKeeper" placeholder="请输入设备管理员" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="车辆行驶证" prop="drivingLicence">
<el-input v-model="form.drivingLicence" placeholder="请输入车辆行驶证" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="新旧程度" prop="degree">
<el-input v-model="form.degree" placeholder="请输入新旧程度" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="车辆容量" prop="vehicleCapacity">
<el-input v-model="form.vehicleCapacity" placeholder="请输入车辆容量" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="车辆净重" prop="suttle">
<el-input v-model="form.suttle" placeholder="请输入车辆净重" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="铭牌" prop="nameplateId">
<image-upload v-model="form.nameplateId" :limit="1" :is-show-tip="false" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="合格证书" prop="qualificationId">
<image-upload v-model="form.qualificationId" :limit="1" :is-show-tip="false" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="设备照片" prop="equipmentPhotoId">
<image-upload v-model="form.equipmentPhotoId" :limit="1" :is-show-tip="false" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="检验报告" prop="verificationReportId">
<image-upload v-model="form.verificationReportId" :limit="1" :is-show-tip="false" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { getType, addMechanicalrewriting, getMechanicalrewriting, updateMechanicalrewriting } from '@/api/mechanical/mechanicalrewriting';
import { useUserStoreHook } from '@/store/modules/user';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const dialog = reactive<DialogOption>({
visible: false,
title: '添加机械台账'
});
const form: any = ref({
id: undefined,
projectId: undefined,
teamName: undefined,
devicename: undefined,
deviceType: undefined,
equipmentType: undefined,
deviceNumber: undefined,
entryTime: undefined,
specification: undefined,
production: undefined,
plateNumber: undefined,
deviceKeeper: undefined,
drivingLicence: undefined,
degree: undefined,
vehicleCapacity: undefined,
suttle: undefined,
nameplateId: undefined,
qualificationId: undefined,
equipmentPhotoId: undefined,
verificationReportId: undefined,
remark: undefined
});
const rules = ref({
devicename: [{ required: true, message: '设备名称不能为空', trigger: 'blur' }],
equipmentType: [{ required: true, message: '设备类型不能为空', trigger: 'blur' }],
deviceNumber: [{ required: true, message: '设备编号不能为空', trigger: 'blur' }],
entryTime: [{ required: true, message: '入场时间不能为空', trigger: 'blur' }],
specification: [{ required: true, message: '规格不能为空', trigger: 'blur' }],
production: [{ required: true, message: '生产能力不能为空', trigger: 'blur' }],
teamName: [{ required: true, message: '班组名称不能为空', trigger: 'blur' }],
degree: [{ required: true, message: '新旧程度不能为空', trigger: 'blur' }],
nameplateId: [{ required: true, message: '铭牌不能为空', trigger: 'blur' }],
qualificationId: [{ required: true, message: '合格证书不能为空', trigger: 'blur' }],
equipmentPhotoId: [{ required: true, message: '设备照片不能为空', trigger: 'blur' }]
});
const buttonLoading = ref(false);
const mechanicalrewritingFormRef = ref();
const propsConfig = {
expandTrigger: 'hover' as const,
value: 'code',
label: 'name',
children: 'children'
};
const userStore = useUserStoreHook();
const currentProject = computed(() => userStore.selectedProject);
const emit = defineEmits(['success']);
const submitForm = () => {
mechanicalrewritingFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
// buttonLoading.value = true;
console.log(form.value);
const parmas = {
...form.value,
projectId: currentProject.value.id
};
if (form.value.id) {
const res = await updateMechanicalrewriting(parmas);
if (res.code === 200) {
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
emit('success');
}
} else {
const res = await addMechanicalrewriting(parmas);
if (res.code === 200) {
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
emit('success');
}
}
}
});
};
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
};
/** 表单重置 */
const reset = () => {
form.value = {
id: undefined,
projectId: undefined,
teamName: undefined,
devicename: undefined,
deviceType: undefined,
deviceNumber: undefined,
entryTime: undefined,
specification: undefined,
production: undefined,
plateNumber: undefined,
deviceKeeper: undefined,
drivingLicence: undefined,
degree: undefined,
vehicleCapacity: undefined,
suttle: undefined,
nameplateId: undefined,
qualificationId: undefined,
equipmentPhotoId: undefined,
verificationReportId: undefined,
equipmentType: undefined,
remark: undefined
};
mechanicalrewritingFormRef.value?.resetFields();
};
const options: any = ref([]);
const open = async (id?: number) => {
const title = id ? '修改机械台账' : '添加机械台账';
dialog.title = title;
dialog.visible = true;
getTypeList();
if (id) {
const res = await getMechanicalrewriting(id);
console.log(res);
form.value = res.data;
form.value.equipmentType = res.data.deviceNumber + '_' + res.data.deviceType;
// Object.assign(form.value, res.data);
}
};
//获取类型
const getTypeList = async () => {
const res = await getType();
if (res.code === 200) {
res.data.forEach((element) => {
element.name = element.largeclass;
element.code = element.code + '_' + element.largeclass;
if (element.children && element.children.length) {
element.children.forEach((elements) => {
elements.name = elements.middleclass;
elements.code = elements.code + '_' + elements.middleclass;
if (elements.children && elements.children.length) {
elements.children.forEach((elementss) => {
elementss.code = elementss.code + '_' + elementss.subclass;
elementss.name = elementss.subclass;
});
}
});
}
});
options.value = res.data;
console.log(options.value);
}
};
//选择了类型
const handleChange = (val: any) => {
form.value.deviceNumber = val[val.length - 1].split('_')[0];
form.value.deviceType = val[val.length - 1].split('_')[1];
};
defineExpose({
open
});
</script>
<style scoped></style>

View File

@ -0,0 +1,119 @@
<template>
<!-- 机械台账详情抽屉 -->
<el-drawer v-model="isShowDialog" size="40%" direction="ltr">
<template #header>
<span>机械台账详情</span>
</template>
<el-form ref="formRef" :model="formData" label-width="100px">
<el-row>
<el-col :span="12">
<el-form-item label="设备名称">{{ formData.devicename }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="设备类型">{{ formData.deviceType }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="设备编号">{{ formData.deviceNumber }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="班组名称">{{ formData.teamName }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="入场日期">{{ parseTime(formData.entryTime, '{y}-{m}-{d}') }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="规格型号">{{ formData.specification }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="生产能力">{{ formData.production }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="车牌号码">{{ formData.plateNumber }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="设备管理员">{{ formData.deviceKeeper }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="车辆行驶证">{{ formData.drivingLicence }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="新旧程度">{{ formData.degree }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="车辆容量">{{ formData.vehicleCapacity }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="车辆净重">{{ formData.suttle }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="铭牌">
<el-image :src="formData.nameplate" fit="contain" style="width: 150px; height: 150px" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="合格证书">
<el-image :src="formData.equipmentPhoto" fit="contain" style="width: 150px; height: 150px" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="设备照片">
<el-image :src="formData.qualification" fit="contain" style="width: 150px; height: 150px" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="检验报告">
<el-image :src="formData.verificationReport" fit="contain" style="width: 150px; height: 150px" />
</el-form-item>
</el-col>
<!-- <el-col :span="12">
<el-form-item label="上传时间">{{ formData.createdAt }}</el-form-item>
</el-col> -->
<el-col :span="12">
<el-form-item label="备注">{{ formData.remark }}</el-form-item>
</el-col>
</el-row>
</el-form>
</el-drawer>
</template>
<script setup lang="ts">
import { getMechanicalrewriting } from '@/api/mechanical/mechanicalrewriting';
const formData: any = ref({
devicename: '',
deviceType: '',
deviceNumber: '',
teamName: '',
entryTime: '',
specification: '',
production: '',
plateNumber: '',
deviceKeeper: '',
drivingLicence: '',
degree: '',
vehicleCapacity: '',
suttle: '',
nameplate: '',
qualification: '',
equipmentPhoto: '',
verificationReport: '',
createdAt: '',
remark: ''
});
const isShowDialog = ref(false);
const open = async (id?: any) => {
console.log(id);
isShowDialog.value = true;
if (id) {
const res = await getMechanicalrewriting(id);
console.log(res);
formData.value = res.data;
// form.value.equipmentType = res.data.deviceNumber + '_' + res.data.deviceType;
// Object.assign(form.value, res.data);
}
};
defineExpose({
open
});
</script>

View File

@ -0,0 +1,269 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="设备名称" prop="devicename">
<el-input v-model="queryParams.devicename" placeholder="请输入设备名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['mechanical:mechanicalrewriting:add']">新增</el-button>
</el-col>
<!-- <el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['mechanical:mechanicalrewriting:export']"
>导出</el-button
>
</el-col> -->
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="mechanicalrewritingList">
<!-- <el-table-column type="selection" width="55" align="center" /> -->
<!-- <el-table-column label="自增ID" align="center" prop="id" v-if="true" />
<el-table-column label="项目ID" align="center" prop="projectId" /> -->
<el-table-column label="班组名称" align="center" prop="teamName" />
<el-table-column label="设备名称" align="center" prop="devicename" />
<el-table-column label="设备类型" align="center" prop="deviceType" />
<el-table-column label="设备编号" align="center" prop="deviceNumber" />
<el-table-column label="入场日期" align="center" prop="entryTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.entryTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="规格型号" align="center" prop="specification" />
<el-table-column label="生产能力" align="center" prop="production" />
<el-table-column label="车牌号码" align="center" prop="plateNumber" />
<el-table-column label="设备管理员" align="center" prop="deviceKeeper" />
<el-table-column label="车辆行驶证" align="center" prop="drivingLicence" />
<el-table-column label="新旧程度" align="center" prop="degree" />
<el-table-column label="车辆容量" align="center" prop="vehicleCapacity" />
<el-table-column label="车辆净重" align="center" prop="suttle" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" fixed="right" min-width="200" fixed-width>
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="View" @click="handleDetails(scope.row)" v-hasPermi="['mechanical:mechanicalrewriting:edit']"
>详情</el-button
>
</el-tooltip>
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['mechanical:mechanicalrewriting:edit']"
>修改</el-button
>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['mechanical:mechanicalrewriting:remove']"
>删除</el-button
>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<addComponent ref="addComponentRef" @success="getList" />
<detailsComponent ref="detailsComponentRef" />
</div>
</template>
<script setup name="Mechanicalrewriting" lang="ts">
import {
listMechanicalrewriting,
getMechanicalrewriting,
delMechanicalrewriting,
addMechanicalrewriting,
updateMechanicalrewriting
} from '@/api/mechanical/mechanicalrewriting';
import { MechanicalrewritingVO, MechanicalrewritingQuery, MechanicalrewritingForm } from '@/api/mechanical/mechanicalrewriting/types';
import addComponent from './components/add.vue';
import detailsComponent from './components/details.vue';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const mechanicalrewritingList = ref<MechanicalrewritingVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const queryFormRef = ref<ElFormInstance>();
const mechanicalrewritingFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const initFormData: MechanicalrewritingForm = {
id: undefined,
projectId: undefined,
teamName: undefined,
devicename: undefined,
deviceType: undefined,
deviceNumber: undefined,
entryTime: undefined,
specification: undefined,
production: undefined,
plateNumber: undefined,
deviceKeeper: undefined,
drivingLicence: undefined,
degree: undefined,
vehicleCapacity: undefined,
suttle: undefined,
nameplate: undefined,
qualification: undefined,
equipmentPhoto: undefined,
verificationReport: undefined,
remark: undefined
};
const data = reactive<PageData<MechanicalrewritingForm, MechanicalrewritingQuery>>({
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
projectId: undefined,
teamName: undefined,
devicename: undefined,
deviceType: undefined,
deviceNumber: undefined,
entryTime: undefined,
specification: undefined,
production: undefined,
plateNumber: undefined,
deviceKeeper: undefined,
drivingLicence: undefined,
degree: undefined,
vehicleCapacity: undefined,
suttle: undefined,
nameplate: undefined,
qualification: undefined,
equipmentPhoto: undefined,
verificationReport: undefined,
params: {}
},
rules: {
id: [{ required: true, message: '自增ID不能为空', trigger: 'blur' }]
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询机械台账列表 */
const getList = async () => {
loading.value = true;
const res = await listMechanicalrewriting(queryParams.value);
mechanicalrewritingList.value = res.rows;
total.value = res.total;
loading.value = false;
};
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
};
/** 表单重置 */
const reset = () => {
form.value = { ...initFormData };
mechanicalrewritingFormRef.value?.resetFields();
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
};
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
handleQuery();
};
/** 多选框选中数据 */
const handleSelectionChange = (selection: MechanicalrewritingVO[]) => {
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
};
const addComponentRef = ref();
/** 新增按钮操作 */
const handleAdd = () => {
addComponentRef.value?.open();
};
/** 修改按钮操作 */
const handleUpdate = async (row?: MechanicalrewritingVO) => {
// reset();
const _id = row?.id || ids.value[0];
addComponentRef.value?.open(_id);
};
const detailsComponentRef = ref();
//详情
const handleDetails = (row) => {
const _id = row?.id || ids.value[0];
detailsComponentRef.value?.open(_id);
};
/** 提交按钮 */
const submitForm = () => {
mechanicalrewritingFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.id) {
await updateMechanicalrewriting(form.value).finally(() => (buttonLoading.value = false));
} else {
await addMechanicalrewriting(form.value).finally(() => (buttonLoading.value = false));
}
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
}
});
};
/** 删除按钮操作 */
const handleDelete = async (row?: MechanicalrewritingVO) => {
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除机械台账编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
await delMechanicalrewriting(_ids);
proxy?.$modal.msgSuccess('删除成功');
await getList();
};
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download(
'mechanical/mechanicalrewriting/export',
{
...queryParams.value
},
`mechanicalrewriting_${new Date().getTime()}.xlsx`
);
};
onMounted(() => {
getList();
});
</script>

View File

@ -11,6 +11,7 @@
:id="form.id" :id="form.id"
:status="form.auditStatus" :status="form.auditStatus"
:pageType="routeParams.type" :pageType="routeParams.type"
:projectName="routeParams.projectName"
/> />
</el-card> </el-card>
<!-- 表单区域 --> <!-- 表单区域 -->

Some files were not shown because too many files have changed in this diff Show More