Merge branch 'master' of http://47.109.37.87:3000/by2025/admin-vben5
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run
# Conflicts: # apps/web-antd/vite.config.mts
@@ -0,0 +1,61 @@
|
||||
import type { InspectionItemVO, InspectionItemForm, InspectionItemQuery } from './model';
|
||||
|
||||
import type { ID, IDS } from '#/api/common';
|
||||
import type { PageResult } from '#/api/common';
|
||||
|
||||
import { commonExport } from '#/api/helper';
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
/**
|
||||
* 查询巡检项目列表
|
||||
* @param params
|
||||
* @returns 巡检项目列表
|
||||
*/
|
||||
export function inspectionItemList(params?: InspectionItemQuery) {
|
||||
return requestClient.get<PageResult<InspectionItemVO>>('/property/inspectionItem/list', { params });
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出巡检项目列表
|
||||
* @param params
|
||||
* @returns 巡检项目列表
|
||||
*/
|
||||
export function inspectionItemExport(params?: InspectionItemQuery) {
|
||||
return commonExport('/property/inspectionItem/export', params ?? {});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询巡检项目详情
|
||||
* @param id id
|
||||
* @returns 巡检项目详情
|
||||
*/
|
||||
export function inspectionItemInfo(id: ID) {
|
||||
return requestClient.get<InspectionItemVO>(`/property/inspectionItem/${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增巡检项目
|
||||
* @param data
|
||||
* @returns void
|
||||
*/
|
||||
export function inspectionItemAdd(data: InspectionItemForm) {
|
||||
return requestClient.postWithMsg<void>('/property/inspectionItem', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新巡检项目
|
||||
* @param data
|
||||
* @returns void
|
||||
*/
|
||||
export function inspectionItemUpdate(data: InspectionItemForm) {
|
||||
return requestClient.putWithMsg<void>('/property/inspectionItem', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除巡检项目
|
||||
* @param id id
|
||||
* @returns void
|
||||
*/
|
||||
export function inspectionItemRemove(id: ID | IDS) {
|
||||
return requestClient.deleteWithMsg<void>(`/property/inspectionItem/${id}`);
|
||||
}
|
49
apps/web-antd/src/api/property/inspectionManagement/inspectionItem/model.d.ts
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
import type { PageQuery, BaseEntity } from '#/api/common';
|
||||
|
||||
export interface InspectionItemVO {
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 项目名称
|
||||
*/
|
||||
itemName: string;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
remark: string;
|
||||
|
||||
}
|
||||
|
||||
export interface InspectionItemForm extends BaseEntity {
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 项目名称
|
||||
*/
|
||||
itemName?: string;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
remark?: string;
|
||||
|
||||
}
|
||||
|
||||
export interface InspectionItemQuery extends PageQuery {
|
||||
/**
|
||||
* 项目名称
|
||||
*/
|
||||
itemName?: string;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: any;
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
import type { InspectionPlanVO, InspectionPlanForm, InspectionPlanQuery } from './model';
|
||||
|
||||
import type { ID, IDS } from '#/api/common';
|
||||
import type { PageResult } from '#/api/common';
|
||||
|
||||
import { commonExport } from '#/api/helper';
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
/**
|
||||
* 查询巡检计划列表
|
||||
* @param params
|
||||
* @returns 巡检计划列表
|
||||
*/
|
||||
export function inspectionPlanList(params?: InspectionPlanQuery) {
|
||||
return requestClient.get<PageResult<InspectionPlanVO>>('/property/inspectionPlan/list', { params });
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出巡检计划列表
|
||||
* @param params
|
||||
* @returns 巡检计划列表
|
||||
*/
|
||||
export function inspectionPlanExport(params?: InspectionPlanQuery) {
|
||||
return commonExport('/property/inspectionPlan/export', params ?? {});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询巡检计划详情
|
||||
* @param id id
|
||||
* @returns 巡检计划详情
|
||||
*/
|
||||
export function inspectionPlanInfo(id: ID) {
|
||||
return requestClient.get<InspectionPlanVO>(`/property/inspectionPlan/${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增巡检计划
|
||||
* @param data
|
||||
* @returns void
|
||||
*/
|
||||
export function inspectionPlanAdd(data: InspectionPlanForm) {
|
||||
return requestClient.postWithMsg<void>('/property/inspectionPlan', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新巡检计划
|
||||
* @param data
|
||||
* @returns void
|
||||
*/
|
||||
export function inspectionPlanUpdate(data: InspectionPlanForm) {
|
||||
return requestClient.putWithMsg<void>('/property/inspectionPlan', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除巡检计划
|
||||
* @param id id
|
||||
* @returns void
|
||||
*/
|
||||
export function inspectionPlanRemove(id: ID | IDS) {
|
||||
return requestClient.deleteWithMsg<void>(`/property/inspectionPlan/${id}`);
|
||||
}
|
199
apps/web-antd/src/api/property/inspectionManagement/inspectionPlan/model.d.ts
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
import type { PageQuery, BaseEntity } from '#/api/common';
|
||||
|
||||
export interface InspectionPlanVO {
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 巡检计划名称
|
||||
*/
|
||||
planName: string;
|
||||
|
||||
/**
|
||||
* 巡检路线id
|
||||
*/
|
||||
inspectionRouteId: string | number;
|
||||
|
||||
/**
|
||||
* 巡检周期
|
||||
*/
|
||||
inspectionPlanPeriod: number;
|
||||
|
||||
/**
|
||||
* 任务提前分组
|
||||
*/
|
||||
beforeTime: number;
|
||||
|
||||
/**
|
||||
* 开始日期
|
||||
*/
|
||||
startDate: string;
|
||||
|
||||
/**
|
||||
* 结束日期
|
||||
*/
|
||||
endDate: string;
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
startTime: string;
|
||||
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
endTime: string;
|
||||
|
||||
/**
|
||||
* 签到方式(0现场定位,1现场定位)
|
||||
*/
|
||||
signType: number;
|
||||
|
||||
/**
|
||||
* 允许补检(0允许1不允许)
|
||||
*/
|
||||
canReexamine: number;
|
||||
|
||||
/**
|
||||
* 选择员工
|
||||
*/
|
||||
userId: string | number;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
remark: string;
|
||||
|
||||
}
|
||||
|
||||
export interface InspectionPlanForm extends BaseEntity {
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 巡检计划名称
|
||||
*/
|
||||
planName?: string;
|
||||
|
||||
/**
|
||||
* 巡检路线id
|
||||
*/
|
||||
inspectionRouteId?: string | number;
|
||||
|
||||
/**
|
||||
* 巡检周期
|
||||
*/
|
||||
inspectionPlanPeriod?: number;
|
||||
|
||||
/**
|
||||
* 任务提前分组
|
||||
*/
|
||||
beforeTime?: number;
|
||||
|
||||
/**
|
||||
* 开始日期
|
||||
*/
|
||||
startDate?: string;
|
||||
|
||||
/**
|
||||
* 结束日期
|
||||
*/
|
||||
endDate?: string;
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
startTime?: string;
|
||||
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
endTime?: string;
|
||||
|
||||
/**
|
||||
* 签到方式(0现场定位,1现场定位)
|
||||
*/
|
||||
signType?: number;
|
||||
|
||||
/**
|
||||
* 允许补检(0允许1不允许)
|
||||
*/
|
||||
canReexamine?: number;
|
||||
|
||||
/**
|
||||
* 选择员工
|
||||
*/
|
||||
userId?: string | number;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
remark?: string;
|
||||
|
||||
}
|
||||
|
||||
export interface InspectionPlanQuery extends PageQuery {
|
||||
/**
|
||||
* 巡检计划名称
|
||||
*/
|
||||
planName?: string;
|
||||
|
||||
/**
|
||||
* 巡检路线id
|
||||
*/
|
||||
inspectionRouteId?: string | number;
|
||||
|
||||
/**
|
||||
* 巡检周期
|
||||
*/
|
||||
inspectionPlanPeriod?: number;
|
||||
|
||||
/**
|
||||
* 任务提前分组
|
||||
*/
|
||||
beforeTime?: number;
|
||||
|
||||
/**
|
||||
* 开始日期
|
||||
*/
|
||||
startDate?: string;
|
||||
|
||||
/**
|
||||
* 结束日期
|
||||
*/
|
||||
endDate?: string;
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
startTime?: string;
|
||||
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
endTime?: string;
|
||||
|
||||
/**
|
||||
* 签到方式(0现场定位,1现场定位)
|
||||
*/
|
||||
signType?: number;
|
||||
|
||||
/**
|
||||
* 允许补检(0允许1不允许)
|
||||
*/
|
||||
canReexamine?: number;
|
||||
|
||||
/**
|
||||
* 选择员工
|
||||
*/
|
||||
userId?: string | number;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: any;
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
import type { InspectionPointVO, InspectionPointForm, InspectionPointQuery } from './model';
|
||||
|
||||
import type { ID, IDS } from '#/api/common';
|
||||
import type { PageResult } from '#/api/common';
|
||||
|
||||
import { commonExport } from '#/api/helper';
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
/**
|
||||
* 查询巡检点列表
|
||||
* @param params
|
||||
* @returns 巡检点列表
|
||||
*/
|
||||
export function inspectionPointList(params?: InspectionPointQuery) {
|
||||
return requestClient.get<PageResult<InspectionPointVO>>('/property/inspectionPoint/list', { params });
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出巡检点列表
|
||||
* @param params
|
||||
* @returns 巡检点列表
|
||||
*/
|
||||
export function inspectionPointExport(params?: InspectionPointQuery) {
|
||||
return commonExport('/property/inspectionPoint/export', params ?? {});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询巡检点详情
|
||||
* @param id id
|
||||
* @returns 巡检点详情
|
||||
*/
|
||||
export function inspectionPointInfo(id: ID) {
|
||||
return requestClient.get<InspectionPointVO>(`/property/inspectionPoint/${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增巡检点
|
||||
* @param data
|
||||
* @returns void
|
||||
*/
|
||||
export function inspectionPointAdd(data: InspectionPointForm) {
|
||||
return requestClient.postWithMsg<void>('/property/inspectionPoint', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新巡检点
|
||||
* @param data
|
||||
* @returns void
|
||||
*/
|
||||
export function inspectionPointUpdate(data: InspectionPointForm) {
|
||||
return requestClient.putWithMsg<void>('/property/inspectionPoint', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除巡检点
|
||||
* @param id id
|
||||
* @returns void
|
||||
*/
|
||||
export function inspectionPointRemove(id: ID | IDS) {
|
||||
return requestClient.deleteWithMsg<void>(`/property/inspectionPoint/${id}`);
|
||||
}
|
139
apps/web-antd/src/api/property/inspectionManagement/inspectionPoint/model.d.ts
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
import type { PageQuery, BaseEntity } from '#/api/common';
|
||||
|
||||
export interface InspectionPointVO {
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 巡检项目id
|
||||
*/
|
||||
itemId: string | number;
|
||||
|
||||
/**
|
||||
* 巡检点名称
|
||||
*/
|
||||
pointName: string;
|
||||
|
||||
/**
|
||||
* 巡检点类型
|
||||
*/
|
||||
pointType: number;
|
||||
|
||||
/**
|
||||
* nfc编码
|
||||
*/
|
||||
nfcCode: string;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
remark: string;
|
||||
|
||||
/**
|
||||
* 创建人id
|
||||
*/
|
||||
createById: string | number;
|
||||
|
||||
/**
|
||||
* 更新人id
|
||||
*/
|
||||
updateById: string | number;
|
||||
|
||||
/**
|
||||
* 搜索值
|
||||
*/
|
||||
searchValue: string;
|
||||
|
||||
}
|
||||
|
||||
export interface InspectionPointForm extends BaseEntity {
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 巡检项目id
|
||||
*/
|
||||
itemId?: string | number;
|
||||
|
||||
/**
|
||||
* 巡检点名称
|
||||
*/
|
||||
pointName?: string;
|
||||
|
||||
/**
|
||||
* 巡检点类型
|
||||
*/
|
||||
pointType?: number;
|
||||
|
||||
/**
|
||||
* nfc编码
|
||||
*/
|
||||
nfcCode?: string;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
remark?: string;
|
||||
|
||||
/**
|
||||
* 创建人id
|
||||
*/
|
||||
createById?: string | number;
|
||||
|
||||
/**
|
||||
* 更新人id
|
||||
*/
|
||||
updateById?: string | number;
|
||||
|
||||
/**
|
||||
* 搜索值
|
||||
*/
|
||||
searchValue?: string;
|
||||
|
||||
}
|
||||
|
||||
export interface InspectionPointQuery extends PageQuery {
|
||||
/**
|
||||
* 巡检项目id
|
||||
*/
|
||||
itemId?: string | number;
|
||||
|
||||
/**
|
||||
* 巡检点名称
|
||||
*/
|
||||
pointName?: string;
|
||||
|
||||
/**
|
||||
* 巡检点类型
|
||||
*/
|
||||
pointType?: number;
|
||||
|
||||
/**
|
||||
* nfc编码
|
||||
*/
|
||||
nfcCode?: string;
|
||||
|
||||
/**
|
||||
* 创建人id
|
||||
*/
|
||||
createById?: string | number;
|
||||
|
||||
/**
|
||||
* 更新人id
|
||||
*/
|
||||
updateById?: string | number;
|
||||
|
||||
/**
|
||||
* 搜索值
|
||||
*/
|
||||
searchValue?: string;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: any;
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
import type { InspectionRouteVO, InspectionRouteForm, InspectionRouteQuery } from './model';
|
||||
|
||||
import type { ID, IDS } from '#/api/common';
|
||||
import type { PageResult } from '#/api/common';
|
||||
|
||||
import { commonExport } from '#/api/helper';
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
/**
|
||||
* 查询巡检路线列表
|
||||
* @param params
|
||||
* @returns 巡检路线列表
|
||||
*/
|
||||
export function inspectionRouteList(params?: InspectionRouteQuery) {
|
||||
return requestClient.get<PageResult<InspectionRouteVO>>('/property/inspectionRoute/list', { params });
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出巡检路线列表
|
||||
* @param params
|
||||
* @returns 巡检路线列表
|
||||
*/
|
||||
export function inspectionRouteExport(params?: InspectionRouteQuery) {
|
||||
return commonExport('/property/inspectionRoute/export', params ?? {});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询巡检路线详情
|
||||
* @param id id
|
||||
* @returns 巡检路线详情
|
||||
*/
|
||||
export function inspectionRouteInfo(id: ID) {
|
||||
return requestClient.get<InspectionRouteVO>(`/property/inspectionRoute/${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增巡检路线
|
||||
* @param data
|
||||
* @returns void
|
||||
*/
|
||||
export function inspectionRouteAdd(data: InspectionRouteForm) {
|
||||
return requestClient.postWithMsg<void>('/property/inspectionRoute', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新巡检路线
|
||||
* @param data
|
||||
* @returns void
|
||||
*/
|
||||
export function inspectionRouteUpdate(data: InspectionRouteForm) {
|
||||
return requestClient.putWithMsg<void>('/property/inspectionRoute', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除巡检路线
|
||||
* @param id id
|
||||
* @returns void
|
||||
*/
|
||||
export function inspectionRouteRemove(id: ID | IDS) {
|
||||
return requestClient.deleteWithMsg<void>(`/property/inspectionRoute/${id}`);
|
||||
}
|
49
apps/web-antd/src/api/property/inspectionManagement/inspectionRoute/model.d.ts
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
import type { PageQuery, BaseEntity } from '#/api/common';
|
||||
|
||||
export interface InspectionRouteVO {
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 路线名称
|
||||
*/
|
||||
routeName: string;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
remark: string;
|
||||
|
||||
}
|
||||
|
||||
export interface InspectionRouteForm extends BaseEntity {
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 路线名称
|
||||
*/
|
||||
routeName?: string;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
remark?: string;
|
||||
|
||||
}
|
||||
|
||||
export interface InspectionRouteQuery extends PageQuery {
|
||||
/**
|
||||
* 路线名称
|
||||
*/
|
||||
routeName?: string;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: any;
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
import type { InspectionTaskVO, InspectionTaskForm, InspectionTaskQuery } from './model';
|
||||
|
||||
import type { ID, IDS } from '#/api/common';
|
||||
import type { PageResult } from '#/api/common';
|
||||
|
||||
import { commonExport } from '#/api/helper';
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
/**
|
||||
* 查询巡检任务列表
|
||||
* @param params
|
||||
* @returns 巡检任务列表
|
||||
*/
|
||||
export function inspectionTaskList(params?: InspectionTaskQuery) {
|
||||
return requestClient.get<PageResult<InspectionTaskVO>>('/property/inspectionTask/list', { params });
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出巡检任务列表
|
||||
* @param params
|
||||
* @returns 巡检任务列表
|
||||
*/
|
||||
export function inspectionTaskExport(params?: InspectionTaskQuery) {
|
||||
return commonExport('/property/inspectionTask/export', params ?? {});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询巡检任务详情
|
||||
* @param id id
|
||||
* @returns 巡检任务详情
|
||||
*/
|
||||
export function inspectionTaskInfo(id: ID) {
|
||||
return requestClient.get<InspectionTaskVO>(`/property/inspectionTask/${id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增巡检任务
|
||||
* @param data
|
||||
* @returns void
|
||||
*/
|
||||
export function inspectionTaskAdd(data: InspectionTaskForm) {
|
||||
return requestClient.postWithMsg<void>('/property/inspectionTask', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新巡检任务
|
||||
* @param data
|
||||
* @returns void
|
||||
*/
|
||||
export function inspectionTaskUpdate(data: InspectionTaskForm) {
|
||||
return requestClient.putWithMsg<void>('/property/inspectionTask', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除巡检任务
|
||||
* @param id id
|
||||
* @returns void
|
||||
*/
|
||||
export function inspectionTaskRemove(id: ID | IDS) {
|
||||
return requestClient.deleteWithMsg<void>(`/property/inspectionTask/${id}`);
|
||||
}
|
169
apps/web-antd/src/api/property/inspectionManagement/inspectionTask/model.d.ts
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
import type { PageQuery, BaseEntity } from '#/api/common';
|
||||
|
||||
export interface InspectionTaskVO {
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 巡检计划id
|
||||
*/
|
||||
inspectionPlanId: string | number;
|
||||
|
||||
/**
|
||||
* 实际巡检时间
|
||||
*/
|
||||
actInsTime: string;
|
||||
|
||||
/**
|
||||
* 当前巡检人
|
||||
*/
|
||||
actUserId: string | number;
|
||||
|
||||
/**
|
||||
* 巡检方式
|
||||
*/
|
||||
taskType: string;
|
||||
|
||||
/**
|
||||
* 转移描述
|
||||
*/
|
||||
transferDesc: string;
|
||||
|
||||
/**
|
||||
* 巡检状态
|
||||
*/
|
||||
status: string;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
remark: string;
|
||||
|
||||
/**
|
||||
* 创建人id
|
||||
*/
|
||||
createById: string | number;
|
||||
|
||||
/**
|
||||
* 更新人id
|
||||
*/
|
||||
updateById: string | number;
|
||||
|
||||
/**
|
||||
* 搜索值
|
||||
*/
|
||||
searchValue: string;
|
||||
|
||||
}
|
||||
|
||||
export interface InspectionTaskForm extends BaseEntity {
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 巡检计划id
|
||||
*/
|
||||
inspectionPlanId?: string | number;
|
||||
|
||||
/**
|
||||
* 实际巡检时间
|
||||
*/
|
||||
actInsTime?: string;
|
||||
|
||||
/**
|
||||
* 当前巡检人
|
||||
*/
|
||||
actUserId?: string | number;
|
||||
|
||||
/**
|
||||
* 巡检方式
|
||||
*/
|
||||
taskType?: string;
|
||||
|
||||
/**
|
||||
* 转移描述
|
||||
*/
|
||||
transferDesc?: string;
|
||||
|
||||
/**
|
||||
* 巡检状态
|
||||
*/
|
||||
status?: string;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
remark?: string;
|
||||
|
||||
/**
|
||||
* 创建人id
|
||||
*/
|
||||
createById?: string | number;
|
||||
|
||||
/**
|
||||
* 更新人id
|
||||
*/
|
||||
updateById?: string | number;
|
||||
|
||||
/**
|
||||
* 搜索值
|
||||
*/
|
||||
searchValue?: string;
|
||||
|
||||
}
|
||||
|
||||
export interface InspectionTaskQuery extends PageQuery {
|
||||
/**
|
||||
* 巡检计划id
|
||||
*/
|
||||
inspectionPlanId?: string | number;
|
||||
|
||||
/**
|
||||
* 实际巡检时间
|
||||
*/
|
||||
actInsTime?: string;
|
||||
|
||||
/**
|
||||
* 当前巡检人
|
||||
*/
|
||||
actUserId?: string | number;
|
||||
|
||||
/**
|
||||
* 巡检方式
|
||||
*/
|
||||
taskType?: string;
|
||||
|
||||
/**
|
||||
* 转移描述
|
||||
*/
|
||||
transferDesc?: string;
|
||||
|
||||
/**
|
||||
* 巡检状态
|
||||
*/
|
||||
status?: string;
|
||||
|
||||
/**
|
||||
* 创建人id
|
||||
*/
|
||||
createById?: string | number;
|
||||
|
||||
/**
|
||||
* 更新人id
|
||||
*/
|
||||
updateById?: string | number;
|
||||
|
||||
/**
|
||||
* 搜索值
|
||||
*/
|
||||
searchValue?: string;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: any;
|
||||
}
|
BIN
apps/web-antd/src/assets/digitalIntelligence/bg.png
Normal file
After Width: | Height: | Size: 556 KiB |
BIN
apps/web-antd/src/assets/digitalIntelligence/center-bg.png
Normal file
After Width: | Height: | Size: 360 KiB |
BIN
apps/web-antd/src/assets/digitalIntelligence/circle1.png
Normal file
After Width: | Height: | Size: 8.6 KiB |
BIN
apps/web-antd/src/assets/digitalIntelligence/circle2.png
Normal file
After Width: | Height: | Size: 8.1 KiB |
BIN
apps/web-antd/src/assets/digitalIntelligence/circle3.png
Normal file
After Width: | Height: | Size: 8.1 KiB |
BIN
apps/web-antd/src/assets/digitalIntelligence/circle4.png
Normal file
After Width: | Height: | Size: 8.3 KiB |
BIN
apps/web-antd/src/assets/energyConsumptionAnalysis/bg.png
Normal file
After Width: | Height: | Size: 549 KiB |
BIN
apps/web-antd/src/assets/energyConsumptionAnalysis/center-bg.png
Normal file
After Width: | Height: | Size: 570 KiB |
After Width: | Height: | Size: 803 B |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 3.1 KiB |
BIN
apps/web-antd/src/assets/monitor/bg.png
Normal file
After Width: | Height: | Size: 394 KiB |
BIN
apps/web-antd/src/assets/monitor/device-alerts-bg1.png
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
apps/web-antd/src/assets/monitor/device-alerts-bg2.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
apps/web-antd/src/assets/monitor/device-alerts-bg3.png
Normal file
After Width: | Height: | Size: 50 KiB |
BIN
apps/web-antd/src/assets/monitor/device-alerts-button1.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
apps/web-antd/src/assets/monitor/monitor1.png
Normal file
After Width: | Height: | Size: 167 KiB |
BIN
apps/web-antd/src/assets/monitor/monitor2.png
Normal file
After Width: | Height: | Size: 175 KiB |
BIN
apps/web-antd/src/assets/monitor/monitor3.png
Normal file
After Width: | Height: | Size: 171 KiB |
BIN
apps/web-antd/src/assets/monitor/monitor4.png
Normal file
After Width: | Height: | Size: 175 KiB |
BIN
apps/web-antd/src/assets/monitor/monitor5.png
Normal file
After Width: | Height: | Size: 184 KiB |
BIN
apps/web-antd/src/assets/monitor/monitor6.png
Normal file
After Width: | Height: | Size: 160 KiB |
BIN
apps/web-antd/src/assets/navigation/科技数据粒子上升蓝色.gif
Normal file
After Width: | Height: | Size: 38 MiB |
BIN
apps/web-antd/src/assets/property/bg.png
Normal file
After Width: | Height: | Size: 438 KiB |
BIN
apps/web-antd/src/assets/property/center-bg.png
Normal file
After Width: | Height: | Size: 360 KiB |
BIN
apps/web-antd/src/assets/property/customer-circle.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
BIN
apps/web-antd/src/assets/property/personnel-duty-circle1.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
apps/web-antd/src/assets/property/personnel-duty-circle2.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
apps/web-antd/src/assets/property/personnel-duty-circle3.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
BIN
apps/web-antd/src/assets/property/personnel-duty-circle4.png
Normal file
After Width: | Height: | Size: 6.0 KiB |
BIN
apps/web-antd/src/assets/security/bg.png
Normal file
After Width: | Height: | Size: 450 KiB |
BIN
apps/web-antd/src/assets/security/button1.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
apps/web-antd/src/assets/security/button2.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
apps/web-antd/src/assets/security/button3.png
Normal file
After Width: | Height: | Size: 773 B |
BIN
apps/web-antd/src/assets/security/center-bg.png
Normal file
After Width: | Height: | Size: 327 KiB |
BIN
apps/web-antd/src/assets/security/monitor1.png
Normal file
After Width: | Height: | Size: 104 KiB |
BIN
apps/web-antd/src/assets/security/monitor2.png
Normal file
After Width: | Height: | Size: 71 KiB |
BIN
apps/web-antd/src/assets/security/stop-icon.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
@@ -11,6 +11,7 @@ import {
|
||||
GiteeIcon,
|
||||
GitHubOutlined,
|
||||
UserOutlined,
|
||||
|
||||
} from '@vben/icons';
|
||||
import {
|
||||
BasicLayout,
|
||||
@@ -30,6 +31,7 @@ import { resetRoutes } from '#/router';
|
||||
import { useAuthStore, useNotifyStore } from '#/store';
|
||||
import { useTenantStore } from '#/store/tenant';
|
||||
import LoginForm from '#/views/_core/authentication/login.vue';
|
||||
// import { TagOutlined } from '@ant-design/icons-vue';
|
||||
|
||||
const userStore = useUserStore();
|
||||
const authStore = useAuthStore();
|
||||
@@ -83,6 +85,13 @@ const menus = computed(() => {
|
||||
icon: CircleHelp,
|
||||
text: $t('ui.widgets.qa'),
|
||||
},
|
||||
{
|
||||
handler: () => {
|
||||
router.push('/navigation');
|
||||
},
|
||||
// icon: TagOutlined,
|
||||
text: '返回导航',
|
||||
},
|
||||
];
|
||||
/**
|
||||
* 租户选中状态 不显示个人中心
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { initPreferences } from '@vben/preferences';
|
||||
import { unmountGlobalLoading } from '@vben/utils';
|
||||
import { overridesPreferences } from './preferences';
|
||||
|
||||
import './utils/flexible'
|
||||
/**
|
||||
* 应用初始化完成之后再进行页面加载渲染
|
||||
*/
|
||||
|
@@ -100,6 +100,67 @@ const coreRoutes: RouteRecordRaw[] = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
component: () => import('#/views/screen/navigation/Navigation.vue'),
|
||||
name: 'navigation',
|
||||
path: '/navigation',
|
||||
meta: {
|
||||
title: '导航页面', // 或者用 $t('page.navigation.title')
|
||||
requiresAuth: true, // 如果需要登录验证
|
||||
},
|
||||
},
|
||||
{
|
||||
component: () => import('#/views/screen/energyConsumptionAnalysis/index.vue'),
|
||||
name: 'energyAnalysis',
|
||||
path: '/energyAnalysis',
|
||||
meta: {
|
||||
title: '能耗大屏',
|
||||
requiresAuth: true, // 如果需要登录验证
|
||||
},
|
||||
}, {
|
||||
component: () => import('#/views/screen/property/index.vue'),
|
||||
name: 'property',
|
||||
path: '/property',
|
||||
meta: {
|
||||
title: '物业大屏',
|
||||
requiresAuth: true, // 如果需要登录验证
|
||||
},
|
||||
}, {
|
||||
component: () => import('#/views/screen/security/index.vue'),
|
||||
name: 'security',
|
||||
path: '/security',
|
||||
meta: {
|
||||
title: '安防大屏',
|
||||
requiresAuth: true, // 如果需要登录验证
|
||||
},
|
||||
},
|
||||
{
|
||||
component: () => import('#/views/screen/monitor/index.vue'),
|
||||
name: 'monitor',
|
||||
path: '/monitor',
|
||||
meta: {
|
||||
title: '监控大屏',
|
||||
requiresAuth: true, // 如果需要登录验证
|
||||
},
|
||||
},
|
||||
{
|
||||
component: () => import('#/views/screen/security/index.vue'),
|
||||
name: 'security',
|
||||
path: '/security',
|
||||
meta: {
|
||||
title: '安防大屏',
|
||||
requiresAuth: true, // 如果需要登录验证
|
||||
},
|
||||
},
|
||||
{
|
||||
component: () => import('#/views/screen/digitalIntelligence/index.vue'),
|
||||
name: 'digitalIntelligence',
|
||||
path: '/digitalIntelligence',
|
||||
meta: {
|
||||
title: '商务中心数智管理平台',
|
||||
requiresAuth: true, // 如果需要登录验证
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export { coreRoutes, fallbackNotFoundRoute };
|
||||
|
@@ -58,7 +58,7 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
} else {
|
||||
onSuccess
|
||||
? await onSuccess?.()
|
||||
: await router.push(preferences.app.defaultHomePath);
|
||||
: await router.push('/navigation');
|
||||
}
|
||||
|
||||
if (userInfo?.realName) {
|
||||
|
119
apps/web-antd/src/utils/echartsResize.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import type { ECharts } from 'echarts'
|
||||
|
||||
/**
|
||||
* ECharts 图表自适应管理器
|
||||
* 用于监听图表容器大小变化并自动调整图表大小
|
||||
*/
|
||||
export class EChartsResizeManager {
|
||||
private charts: Map<ECharts, ResizeObserver> = new Map()
|
||||
private resizeHandler: (() => void) | null = null
|
||||
|
||||
constructor() {
|
||||
this.initResizeListener()
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加图表到管理器
|
||||
* @param chart ECharts 实例
|
||||
*/
|
||||
addChart(chart: ECharts): void {
|
||||
if (chart && !this.charts.has(chart)) {
|
||||
// 获取图表容器元素
|
||||
const container = chart.getDom()
|
||||
if (container) {
|
||||
// 为每个图表创建独立的 ResizeObserver
|
||||
const observer = new ResizeObserver(() => {
|
||||
if (chart && !chart.isDisposed()) {
|
||||
chart.resize()
|
||||
}
|
||||
})
|
||||
|
||||
// 监听图表容器的大小变化
|
||||
observer.observe(container)
|
||||
this.charts.set(chart, observer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除图表
|
||||
* @param chart ECharts 实例
|
||||
*/
|
||||
removeChart(chart: ECharts): void {
|
||||
const observer = this.charts.get(chart)
|
||||
if (observer) {
|
||||
observer.disconnect()
|
||||
this.charts.delete(chart)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有图表
|
||||
*/
|
||||
clearCharts(): void {
|
||||
this.charts.forEach(observer => {
|
||||
observer.disconnect()
|
||||
})
|
||||
this.charts.clear()
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新调整所有图表大小
|
||||
*/
|
||||
resizeAllCharts(): void {
|
||||
this.charts.forEach((observer, chart) => {
|
||||
if (chart && !chart.isDisposed()) {
|
||||
chart.resize()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化窗口大小变化监听器
|
||||
*/
|
||||
private initResizeListener(): void {
|
||||
// 监听窗口大小变化
|
||||
this.resizeHandler = () => {
|
||||
this.resizeAllCharts()
|
||||
}
|
||||
window.addEventListener('resize', this.resizeHandler)
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁监听器
|
||||
*/
|
||||
destroy(): void {
|
||||
if (this.resizeHandler) {
|
||||
window.removeEventListener('resize', this.resizeHandler)
|
||||
this.resizeHandler = null
|
||||
}
|
||||
|
||||
this.clearCharts()
|
||||
}
|
||||
}
|
||||
|
||||
// 创建全局实例
|
||||
export const echartsResizeManager = new EChartsResizeManager()
|
||||
|
||||
/**
|
||||
* 便捷函数:添加图表到管理器
|
||||
* @param chart ECharts 实例
|
||||
*/
|
||||
export function addChartToResizeManager(chart: ECharts): void {
|
||||
echartsResizeManager.addChart(chart)
|
||||
}
|
||||
|
||||
/**
|
||||
* 便捷函数:移除图表
|
||||
* @param chart ECharts 实例
|
||||
*/
|
||||
export function removeChartFromResizeManager(chart: ECharts): void {
|
||||
echartsResizeManager.removeChart(chart)
|
||||
}
|
||||
|
||||
/**
|
||||
* 便捷函数:手动触发所有图表重新调整大小
|
||||
*/
|
||||
export function resizeAllCharts(): void {
|
||||
echartsResizeManager.resizeAllCharts()
|
||||
}
|
12
apps/web-antd/src/utils/flexible.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
function setRootFontSize(): void {
|
||||
const baseWidth = 1920 // 设计稿宽度
|
||||
const baseFontSize = 16 // 设计稿根字体
|
||||
const screenWidth = window.innerWidth
|
||||
const fontSize = (screenWidth / baseWidth) * baseFontSize
|
||||
document.documentElement.style.fontSize = fontSize + 'px'
|
||||
}
|
||||
|
||||
setRootFontSize()
|
||||
window.addEventListener('resize', setRootFontSize)
|
||||
|
||||
export default setRootFontSize
|
264
apps/web-antd/src/utils/pie3d.ts
Normal file
@@ -0,0 +1,264 @@
|
||||
import * as echarts from 'echarts'
|
||||
import 'echarts-gl'
|
||||
|
||||
interface Pie3DData {
|
||||
name: string
|
||||
value: number
|
||||
itemStyle?: {
|
||||
color?: string
|
||||
opacity?: number
|
||||
}
|
||||
startRatio?: number
|
||||
endRatio?: number
|
||||
}
|
||||
|
||||
interface Pie3DOptions {
|
||||
data: Pie3DData[]
|
||||
height?: number
|
||||
hoverHeightScale?: number
|
||||
selectOffset?: number
|
||||
distance?: number
|
||||
boxHeight?: number
|
||||
radius?: number
|
||||
}
|
||||
|
||||
interface ParametricEquation {
|
||||
u: { min: number; max: number; step: number }
|
||||
v: { min: number; max: number; step: number }
|
||||
x: (u: number, v: number) => number
|
||||
y: (u: number, v: number) => number
|
||||
z: (u: number, v: number) => number
|
||||
}
|
||||
|
||||
interface SeriesItem {
|
||||
name: string
|
||||
type: string
|
||||
parametric: boolean
|
||||
wireframe: { show: boolean }
|
||||
pieData?: Pie3DData
|
||||
pieStatus?: { selected: boolean; hovered: boolean; k: number }
|
||||
itemStyle?: any
|
||||
parametricEquation?: ParametricEquation
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染3D饼图,支持点击选中(外移)、鼠标悬停高亮(升高)、高亮修正,无label/legend。
|
||||
* @param dom - 容器DOM
|
||||
* @param options - 配置项
|
||||
* options.data: [{name, value, itemStyle}]
|
||||
* options.height: 饼图厚度
|
||||
* options.hoverHeightScale: 高亮时高度放大倍数
|
||||
* options.selectOffset: 选中时外移距离(默认0.1)
|
||||
* options.distance: 视角距离
|
||||
* options.boxHeight: grid3D.boxHeight
|
||||
* options.radius: 半径缩放
|
||||
* @returns echartsInstance
|
||||
*/
|
||||
export function renderPie3DChart(dom: HTMLElement, options: Pie3DOptions): echarts.ECharts | undefined {
|
||||
if (!dom) return
|
||||
const myChart = echarts.init(dom)
|
||||
const hoverHeightScale = options.hoverHeightScale || 1.2
|
||||
const selectOffset = options.selectOffset || 0.1
|
||||
const distance = options.distance || 120
|
||||
const gridBoxHeight = options.boxHeight || 10
|
||||
const R = options.radius || 0.8
|
||||
const fixedH = 100
|
||||
|
||||
// 生成扇形的曲面参数方程
|
||||
function getParametricEquation(startRatio: number, endRatio: number, isSelected: boolean, isHovered: boolean, k: number, h: number): ParametricEquation {
|
||||
const midRatio = (startRatio + endRatio) / 2
|
||||
const startRadian = startRatio * Math.PI * 2
|
||||
const endRadian = endRatio * Math.PI * 2
|
||||
const midRadian = midRatio * Math.PI * 2
|
||||
if (startRatio === 0 && endRatio === 1) isSelected = false
|
||||
k = typeof k !== 'undefined' ? k : 1
|
||||
const offsetX = isSelected ? Math.cos(midRadian) * selectOffset : 0
|
||||
const offsetY = isSelected ? Math.sin(midRadian) * selectOffset : 0
|
||||
const hoverRate = isHovered ? 1.05 : 1
|
||||
return {
|
||||
u: { min: -Math.PI, max: Math.PI * 3, step: Math.PI / 32 },
|
||||
v: { min: 0, max: Math.PI * 2, step: Math.PI / 20 },
|
||||
x: function(u: number, v: number) {
|
||||
if (u < startRadian) return offsetX + R * Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate
|
||||
if (u > endRadian) return offsetX + R * Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate
|
||||
return offsetX + R * Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate
|
||||
},
|
||||
y: function(u: number, v: number) {
|
||||
if (u < startRadian) return offsetY + R * Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate
|
||||
if (u > endRadian) return offsetY + R * Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate
|
||||
return offsetY + R * Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate
|
||||
},
|
||||
z: function(u: number, v: number) {
|
||||
if (u < -Math.PI * 0.5) return Math.sin(u)
|
||||
if (u > Math.PI * 2.5) return Math.sin(u) * h * .1
|
||||
return Math.sin(v) > 0 ? 1 * h * .1 : -1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 生成series
|
||||
function getPie3D(pieData: Pie3DData[]): SeriesItem[] {
|
||||
const series: SeriesItem[] = []
|
||||
let sumValue = 0
|
||||
let startValue = 0
|
||||
let endValue = 0
|
||||
const k = 1 // 实心饼图
|
||||
for (let i = 0; i < pieData.length; i++) {
|
||||
sumValue += pieData[i].value
|
||||
const seriesItem: SeriesItem = {
|
||||
name: typeof pieData[i].name === 'undefined' ? `series${i}` : pieData[i].name,
|
||||
type: 'surface',
|
||||
parametric: true,
|
||||
wireframe: { show: false },
|
||||
pieData: pieData[i],
|
||||
pieStatus: { selected: false, hovered: false, k: k }
|
||||
}
|
||||
if (pieData[i].itemStyle) {
|
||||
const itemStyle: any = {}
|
||||
const itemStyleObj: any = pieData[i].itemStyle
|
||||
if (itemStyleObj.color) itemStyle.color = itemStyleObj.color
|
||||
if (itemStyleObj.opacity !== undefined) itemStyle.opacity = itemStyleObj.opacity
|
||||
seriesItem.itemStyle = itemStyle
|
||||
}
|
||||
series.push(seriesItem)
|
||||
}
|
||||
for (let i = 0; i < series.length; i++) {
|
||||
endValue = startValue + series[i].pieData!.value
|
||||
series[i].pieData!.startRatio = startValue / sumValue
|
||||
series[i].pieData!.endRatio = endValue / sumValue
|
||||
series[i].parametricEquation = getParametricEquation(
|
||||
series[i].pieData!.startRatio!,
|
||||
series[i].pieData!.endRatio!,
|
||||
false,
|
||||
false,
|
||||
k,
|
||||
fixedH // 所有块厚度一样
|
||||
)
|
||||
startValue = endValue
|
||||
}
|
||||
// 透明圆环用于高亮修正
|
||||
series.push({
|
||||
name: 'mouseoutSeries',
|
||||
type: 'surface',
|
||||
parametric: true,
|
||||
wireframe: { show: false },
|
||||
itemStyle: { opacity: 0 },
|
||||
parametricEquation: {
|
||||
u: { min: 0, max: Math.PI * 2, step: Math.PI / 20 },
|
||||
v: { min: 0, max: Math.PI, step: Math.PI / 20 },
|
||||
x: function(u: number, v: number) { return Math.sin(v) * Math.sin(u) + Math.sin(u) },
|
||||
y: function(u: number, v: number) { return Math.sin(v) * Math.cos(u) + Math.cos(u) },
|
||||
z: function(u: number, v: number) { return Math.cos(v) > 0 ? 0.1 : -0.1 }
|
||||
}
|
||||
})
|
||||
return series
|
||||
}
|
||||
|
||||
const series = getPie3D(options.data)
|
||||
// 不加pie2d,不加legend,不加label
|
||||
const option = {
|
||||
backgroundColor: 'rgba(0,0,0,0)',
|
||||
legend: undefined,
|
||||
tooltip: undefined,
|
||||
xAxis3D: { min: -1, max: 1 },
|
||||
yAxis3D: { min: -1, max: 1 },
|
||||
zAxis3D: { min: -1, max: 1 },
|
||||
grid3D: {
|
||||
show: false,
|
||||
boxHeight: gridBoxHeight,
|
||||
viewControl: {
|
||||
alpha: 35,
|
||||
distance: distance,
|
||||
rotateSensitivity: 0,
|
||||
zoomSensitivity: 0,
|
||||
panSensitivity: 0,
|
||||
autoRotate: false
|
||||
}
|
||||
},
|
||||
series: series
|
||||
}
|
||||
myChart.setOption(option, true)
|
||||
|
||||
// 选中/高亮交互
|
||||
let hoveredIndex = ''
|
||||
|
||||
// // 点击选中(外移)
|
||||
// myChart.on('click', function(params) {
|
||||
// if (!series[params.seriesIndex] || series[params.seriesIndex].type !== 'surface') return;
|
||||
// let isSelected = !series[params.seriesIndex].pieStatus.selected;
|
||||
// let isHovered = series[params.seriesIndex].pieStatus.hovered;
|
||||
// let k = series[params.seriesIndex].pieStatus.k;
|
||||
// let startRatio = series[params.seriesIndex].pieData.startRatio;
|
||||
// let endRatio = series[params.seriesIndex].pieData.endRatio;
|
||||
// // 取消之前选中
|
||||
// if (selectedIndex !== '' && selectedIndex !== params.seriesIndex) {
|
||||
// let prev = series[selectedIndex];
|
||||
// prev.parametricEquation = getParametricEquation(
|
||||
// prev.pieData.startRatio, prev.pieData.endRatio, false, prev.pieStatus.hovered, k, prev.pieData.value
|
||||
// );
|
||||
// prev.pieStatus.selected = false;
|
||||
// }
|
||||
// // 当前选中/取消
|
||||
// series[params.seriesIndex].parametricEquation = getParametricEquation(
|
||||
// startRatio, endRatio, isSelected, isHovered, k, series[params.seriesIndex].pieData.value
|
||||
// );
|
||||
// series[params.seriesIndex].pieStatus.selected = isSelected;
|
||||
// isSelected ? selectedIndex = params.seriesIndex : selectedIndex = '';
|
||||
// myChart.setOption({ series });
|
||||
// });
|
||||
|
||||
// 悬停高亮(升高)
|
||||
myChart.on('mouseover', function(params: any) {
|
||||
if (!series[params.seriesIndex] || !series[params.seriesIndex].pieData) return
|
||||
if (hoveredIndex === params.seriesIndex) return
|
||||
// 取消之前高亮
|
||||
if (hoveredIndex !== '') {
|
||||
const prev = series[parseInt(hoveredIndex)]
|
||||
if (!prev || !prev.pieData) return
|
||||
prev.parametricEquation = getParametricEquation(
|
||||
prev.pieData.startRatio!,
|
||||
prev.pieData.endRatio!,
|
||||
prev.pieStatus!.selected,
|
||||
false,
|
||||
prev.pieStatus!.k,
|
||||
fixedH
|
||||
)
|
||||
prev.pieStatus!.hovered = false
|
||||
hoveredIndex = ''
|
||||
}
|
||||
// 当前高亮
|
||||
const cur = series[params.seriesIndex]
|
||||
cur.parametricEquation = getParametricEquation(
|
||||
cur.pieData!.startRatio!,
|
||||
cur.pieData!.endRatio!,
|
||||
cur.pieStatus!.selected,
|
||||
true,
|
||||
cur.pieStatus!.k,
|
||||
fixedH * hoverHeightScale
|
||||
)
|
||||
cur.pieStatus!.hovered = true
|
||||
hoveredIndex = params.seriesIndex.toString()
|
||||
myChart.setOption({ series })
|
||||
})
|
||||
|
||||
// 全局移出,修正高亮残留
|
||||
myChart.on('globalout', function() {
|
||||
if (hoveredIndex !== '') {
|
||||
const prev = series[parseInt(hoveredIndex)]
|
||||
if (!prev || !prev.pieData) return
|
||||
prev.parametricEquation = getParametricEquation(
|
||||
prev.pieData.startRatio!,
|
||||
prev.pieData.endRatio!,
|
||||
prev.pieStatus!.selected,
|
||||
false,
|
||||
prev.pieStatus!.k,
|
||||
fixedH
|
||||
)
|
||||
prev.pieStatus!.hovered = false
|
||||
hoveredIndex = ''
|
||||
myChart.setOption({ series })
|
||||
}
|
||||
})
|
||||
|
||||
return myChart
|
||||
}
|
129
apps/web-antd/src/utils/threeDBarOption.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
import * as echarts from 'echarts'
|
||||
|
||||
interface ThreeDBarOptionConfig {
|
||||
xData: string[]
|
||||
yData: number[]
|
||||
barWidth?: number
|
||||
colorConfig?: {
|
||||
left0?: string
|
||||
left08?: string
|
||||
top03?: string
|
||||
top1?: string
|
||||
}
|
||||
}
|
||||
|
||||
export function getThreeDBarOption({ xData, yData, barWidth = 30, colorConfig = {} }: ThreeDBarOptionConfig) {
|
||||
// 注册 shape 只需一次,防止多次注册报错
|
||||
if (!(echarts.graphic as any).registered3DBar) {
|
||||
const leftShape = echarts.graphic.extendShape({
|
||||
buildPath(ctx: any, shape: any) {
|
||||
const { topBasicsYAxis, bottomYAxis, basicsXAxis } = shape
|
||||
const WIDTH = 15
|
||||
const OBLIQUE_ANGLE_HEIGHT = 8
|
||||
const p1 = [basicsXAxis - WIDTH, topBasicsYAxis - OBLIQUE_ANGLE_HEIGHT]
|
||||
const p2 = [basicsXAxis - WIDTH, bottomYAxis]
|
||||
const p3 = [basicsXAxis, bottomYAxis]
|
||||
const p4 = [basicsXAxis, topBasicsYAxis]
|
||||
ctx.moveTo(p1[0], p1[1])
|
||||
ctx.lineTo(p2[0], p2[1])
|
||||
ctx.lineTo(p3[0], p3[1])
|
||||
ctx.lineTo(p4[0], p4[1])
|
||||
}
|
||||
})
|
||||
const rightShape = echarts.graphic.extendShape({
|
||||
buildPath(ctx: any, shape: any) {
|
||||
const { topBasicsYAxis, bottomYAxis, basicsXAxis } = shape
|
||||
const WIDTH = 15
|
||||
const OBLIQUE_ANGLE_HEIGHT = 2
|
||||
const p1 = [basicsXAxis, topBasicsYAxis]
|
||||
const p2 = [basicsXAxis, bottomYAxis]
|
||||
const p3 = [basicsXAxis + WIDTH, bottomYAxis]
|
||||
const p4 = [basicsXAxis + WIDTH, topBasicsYAxis - OBLIQUE_ANGLE_HEIGHT]
|
||||
ctx.moveTo(p1[0], p1[1])
|
||||
ctx.lineTo(p2[0], p2[1])
|
||||
ctx.lineTo(p3[0], p3[1])
|
||||
ctx.lineTo(p4[0], p4[1])
|
||||
}
|
||||
})
|
||||
const topShape = echarts.graphic.extendShape({
|
||||
buildPath(ctx: any, shape: any) {
|
||||
const { topBasicsYAxis, basicsXAxis } = shape
|
||||
const WIDTH = 15
|
||||
const OBLIQUE_ANGLE_HEIGHT = 8
|
||||
const p1 = [basicsXAxis, topBasicsYAxis]
|
||||
const p2 = [basicsXAxis + WIDTH, topBasicsYAxis - OBLIQUE_ANGLE_HEIGHT]
|
||||
const p3 = [basicsXAxis, topBasicsYAxis - OBLIQUE_ANGLE_HEIGHT * 2]
|
||||
const p4 = [basicsXAxis - WIDTH, topBasicsYAxis - OBLIQUE_ANGLE_HEIGHT]
|
||||
ctx.moveTo(p1[0], p1[1])
|
||||
ctx.lineTo(p2[0], p2[1])
|
||||
ctx.lineTo(p3[0], p3[1])
|
||||
ctx.lineTo(p4[0], p4[1])
|
||||
}
|
||||
})
|
||||
echarts.graphic.registerShape('leftShape', leftShape)
|
||||
echarts.graphic.registerShape('rightShape', rightShape)
|
||||
echarts.graphic.registerShape('topShape', topShape)
|
||||
;(echarts.graphic as any).registered3DBar = true
|
||||
}
|
||||
|
||||
return {
|
||||
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
|
||||
grid: { left: '3%', right: '4%', bottom: '3%', top: "12%", containLabel: true },
|
||||
xAxis: [{
|
||||
type: 'category',
|
||||
data: xData,
|
||||
axisTick: { alignWithLabel: true },
|
||||
axisLine: { lineStyle: { color: '#3ec6ff' } },
|
||||
axisLabel: { color: '#fff' }
|
||||
}],
|
||||
yAxis: [{
|
||||
type: 'value',
|
||||
axisLine: { show: false },
|
||||
splitLine: { lineStyle: { color: '#1b4a7a' } },
|
||||
axisLabel: { color: '#fff' }
|
||||
}],
|
||||
series: [{
|
||||
type: 'custom',
|
||||
data: yData,
|
||||
barWidth,
|
||||
renderItem(params: any, api: any) {
|
||||
const basicsCoord = api.coord([api.value(0), api.value(1)])
|
||||
const topBasicsYAxis = basicsCoord[1]
|
||||
const basicsXAxis = basicsCoord[0]
|
||||
const bottomYAxis = api.coord([api.value(0), 0])[1]
|
||||
return {
|
||||
type: 'group',
|
||||
children: [
|
||||
{
|
||||
type: 'leftShape',
|
||||
shape: { topBasicsYAxis, basicsXAxis, bottomYAxis },
|
||||
style: {
|
||||
fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: colorConfig.left0 || '#2ADBEF' },
|
||||
{ offset: 1, color: colorConfig.left08 || '#2677F9 ' },
|
||||
])
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'rightShape',
|
||||
shape: { topBasicsYAxis, basicsXAxis, bottomYAxis },
|
||||
style: {
|
||||
fill: '#114EAD '
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'topShape',
|
||||
shape: { topBasicsYAxis, basicsXAxis, bottomYAxis },
|
||||
style: {
|
||||
fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0.3, color: colorConfig.top03 || '#6DF0FF' },
|
||||
{ offset: 1, color: colorConfig.top1 || '#6DF0FF' }
|
||||
])
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
@@ -4,6 +4,8 @@ import {renderDict} from "#/utils/render";
|
||||
import {getDictOptions} from "#/utils/dict";
|
||||
import {h} from "vue";
|
||||
import {Rate} from "ant-design-vue";
|
||||
import type {Dayjs} from "dayjs";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
|
||||
export const querySchema: FormSchemaGetter = () => [
|
||||
@@ -39,6 +41,11 @@ export const columns: VxeGridProps['columns'] = [
|
||||
field: 'orderName',
|
||||
minWidth: 180,
|
||||
},
|
||||
{
|
||||
title: '工单类型',
|
||||
field: 'typeName',
|
||||
minWidth: 150,
|
||||
},
|
||||
{
|
||||
title: '派单时间',
|
||||
field: 'dispatchTime',
|
||||
@@ -73,8 +80,8 @@ export const columns: VxeGridProps['columns'] = [
|
||||
title: '评价',
|
||||
field: 'serviceEvalua',
|
||||
width: 180,
|
||||
slots:{
|
||||
default: ({ row }) => {
|
||||
slots: {
|
||||
default: ({row}) => {
|
||||
return h(Rate, {
|
||||
value: row.serviceEvalua || 0,
|
||||
disabled: true,
|
||||
@@ -143,6 +150,7 @@ export const modalSchema: FormSchemaGetter = () => [
|
||||
showTime: true,
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
disabledDate: disabledDate
|
||||
},
|
||||
rules: 'selectRequired',
|
||||
},
|
||||
@@ -208,3 +216,6 @@ export const modalSchema: FormSchemaGetter = () => [
|
||||
rules: 'selectRequired',
|
||||
},
|
||||
];
|
||||
const disabledDate = (current: Dayjs) => {
|
||||
return current && current < dayjs().endOf('day');
|
||||
};
|
||||
|
@@ -35,6 +35,14 @@ const formOptions: VbenFormProps = {
|
||||
},
|
||||
schema: querySchema(),
|
||||
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
|
||||
handleReset: async () => {
|
||||
ordersType.value = '0';
|
||||
const { formApi, reload } = tableApi;
|
||||
await formApi.resetForm();
|
||||
const formValues = formApi.form.values;
|
||||
formApi.setLatestSubmissionValues(formValues);
|
||||
await reload(formValues);
|
||||
},
|
||||
};
|
||||
|
||||
const gridOptions: VxeGridProps = {
|
||||
@@ -53,6 +61,7 @@ const gridOptions: VxeGridProps = {
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({page}, formValues = {}) => {
|
||||
formValues.type = ordersType.value=='0'?undefined:ordersType.value;
|
||||
return await workOrdersList({
|
||||
pageNum: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
@@ -85,7 +94,7 @@ function handleAdd() {
|
||||
modalApi.setData({});
|
||||
modalApi.open();
|
||||
}
|
||||
function handleInfo(row) {
|
||||
function handleInfo(row:any) {
|
||||
detailApi.setData({id:row.id});
|
||||
detailApi.open();
|
||||
}
|
||||
@@ -139,21 +148,14 @@ async function queryOrderType() {
|
||||
onMounted(async () => {
|
||||
await queryOrderType()
|
||||
});
|
||||
|
||||
async function changeOrdersType(val: string) {
|
||||
await tableApi.formApi.setValues({
|
||||
type: val === '0' ? undefined : val, // '0' 表示全部工单,传 undefined 或清除该字段
|
||||
});
|
||||
console.log(tableApi.formApi.getValues(),'==================')
|
||||
await tableApi.query()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page :auto-content-height="true">
|
||||
<BasicTable table-title="工单处理列表">
|
||||
<BasicTable table-title="工单处理列表" class="order-work-left-radio">
|
||||
<template #table-title>
|
||||
<RadioGroup v-model:value="ordersType" button-style="solid" @change="changeOrdersType">
|
||||
<RadioGroup v-model:value="ordersType" button-style="solid"
|
||||
@change="() => tableApi.reload()">
|
||||
<RadioButton v-for="item in ordersTypeList"
|
||||
:value="item.value">{{ item.label }}
|
||||
</RadioButton>
|
||||
@@ -219,3 +221,18 @@ async function changeOrdersType(val: string) {
|
||||
<WorkOrdersDetail/>
|
||||
</Page>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
:where(.css-dev-only-do-not-override-aza1th).ant-radio-group {
|
||||
white-space: nowrap;
|
||||
overflow-y: hidden;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
</style>
|
||||
<style lang="scss">
|
||||
.order-work-left-radio{
|
||||
.vxe-toolbar .vxe-buttons--wrapper, .vxe-toolbar .vxe-tools--wrapper {
|
||||
max-width: 70% !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -24,7 +24,7 @@ const [BasicModal, modalApi] = useVbenModal({
|
||||
});
|
||||
|
||||
const orderDetail = shallowRef<null | WorkOrdersVO>(null);
|
||||
|
||||
const handleRecords=ref<any[]>([])
|
||||
async function handleOpenChange(open: boolean) {
|
||||
if (!open) {
|
||||
return null;
|
||||
@@ -34,6 +34,13 @@ async function handleOpenChange(open: boolean) {
|
||||
const {id} = modalApi.getData() as { id: number | string };
|
||||
// 赋值
|
||||
orderDetail.value = await workOrdersInfo(id);
|
||||
if(orderDetail.value){
|
||||
handleRecords.value=[
|
||||
{type:orderDetail.value.typeName,time:orderDetail.value.compleTime,personName:orderDetail.value.handlerText},
|
||||
{type:'跟进',time:orderDetail.value.dispatchTime,personName:orderDetail.value.initiatorNameText},
|
||||
{type:'创建工单',time:orderDetail.value.createTime,personName:orderDetail.value.initiatorNameText},
|
||||
]
|
||||
}
|
||||
|
||||
modalApi.modalLoading(false);
|
||||
}
|
||||
@@ -52,18 +59,16 @@ async function handleOpenChange(open: boolean) {
|
||||
{{ orderDetail.orderName }}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="工单类型">
|
||||
<component
|
||||
:is="renderDict(orderDetail.customerType,'wy_khlx')"
|
||||
/>
|
||||
{{orderDetail.typeName}}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="发起人">
|
||||
{{ orderDetail.rentalPeriod }}
|
||||
{{ orderDetail.initiatorNameText+'-'+orderDetail.initiatorPhone}}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="派单时间">
|
||||
{{ orderDetail.dispatchTime }}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="处理人">
|
||||
{{ orderDetail.totalAmount + "元" }}
|
||||
{{ orderDetail.handlerText }}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="具体位置" :span="2">
|
||||
{{ orderDetail.location }}
|
||||
@@ -74,7 +79,7 @@ async function handleOpenChange(open: boolean) {
|
||||
<DescriptionsItem label="完成时间">
|
||||
{{ orderDetail.compleTime }}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="评价">
|
||||
<DescriptionsItem label="服务评价">
|
||||
<Rate :value="orderDetail.serviceEvalua" disabled/>
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="是否超时">
|
||||
@@ -86,11 +91,11 @@ async function handleOpenChange(open: boolean) {
|
||||
<Divider orientation="left" orientation-margin="0px">
|
||||
处理记录
|
||||
</Divider>
|
||||
<Timeline>
|
||||
<TimelineItem>
|
||||
<p>类型:</p>
|
||||
<p>时间:</p>
|
||||
<p>处理人:</p>
|
||||
<Timeline v-if="handleRecords.length">
|
||||
<TimelineItem v-for="item in handleRecords">
|
||||
<p>类型:{{item.type}}</p>
|
||||
<p>时间:{{item.time}}</p>
|
||||
<p>处理人:{{item.personName}}</p>
|
||||
</TimelineItem>
|
||||
</Timeline>
|
||||
</div>
|
||||
|
@@ -98,7 +98,7 @@ export const modalSchema: FormSchemaGetter = () => [
|
||||
},
|
||||
{
|
||||
label: '完成时效(小时)',
|
||||
fieldName: 'isTransfers',
|
||||
fieldName: 'completionNumber',
|
||||
component: 'Input',
|
||||
rules: 'required',
|
||||
},
|
||||
|
@@ -41,11 +41,6 @@ async function handleOpenChange(open: boolean) {
|
||||
:is="renderDict(workOrdersTypeInfoDetail.operationMode,'pro_operation_pattern')"
|
||||
/>
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="运作模式" v-if="workOrdersTypeInfoDetail.operationMode!=null">
|
||||
<component
|
||||
:is="renderDict(workOrdersTypeInfoDetail.operationMode,'pro_operation_pattern')"
|
||||
/>
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="排序值">
|
||||
{{ workOrdersTypeInfoDetail.sort }}
|
||||
</DescriptionsItem>
|
||||
|
@@ -189,6 +189,6 @@ export const modalSchema: FormSchemaGetter = () => [
|
||||
{
|
||||
label: '备注',
|
||||
fieldName: 'remark',
|
||||
component: 'Input',
|
||||
component: 'Textarea',
|
||||
},
|
||||
];
|
||||
|
@@ -120,6 +120,7 @@ export const modalSchema: FormSchemaGetter = () => [
|
||||
label: '价格体系',
|
||||
fieldName: 'price',
|
||||
component: 'Input',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '状态',
|
||||
@@ -134,6 +135,6 @@ export const modalSchema: FormSchemaGetter = () => [
|
||||
{
|
||||
label: '备注',
|
||||
fieldName: 'remarks',
|
||||
component: 'Input',
|
||||
component: 'Textarea',
|
||||
},
|
||||
];
|
||||
|
@@ -12,6 +12,7 @@ import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
|
||||
import { modalSchema } from './data';
|
||||
import productDetailModal from './rentalPlan-detial-modal.vue';
|
||||
import { getDictOptions } from '#/utils/dict';
|
||||
import { Item } from 'ant-design-vue/es/menu';
|
||||
|
||||
const emit = defineEmits<{ reload: [] }>();
|
||||
|
||||
@@ -69,7 +70,10 @@ const [BasicModal, modalApi] = useVbenModal({
|
||||
if ((isUpdate.value || isReadonly.value) && id) {
|
||||
const record = await rentalPlanInfo(id);
|
||||
// 后端返回绿植产品包列表结构处理
|
||||
detailTable.value = record.productList.map((item:any) => item.product);
|
||||
detailTable.value = record.productList.map((item:any) => {...item.product,Item.productNum});
|
||||
|
||||
console.log(detailTable.value);
|
||||
|
||||
await formApi.setValues(record);
|
||||
}
|
||||
await markInitialized();
|
||||
|
@@ -87,10 +87,14 @@ onMounted(async () => {
|
||||
data: xAxisData.value,
|
||||
boundaryGap: false,
|
||||
},
|
||||
yAxis: { type: 'value' },
|
||||
yAxis: { type: 'value',
|
||||
axisLabel: {
|
||||
formatter: (value) => `${value * 100}%`
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '订单数',
|
||||
name: '订单趋势',
|
||||
type: 'line',
|
||||
data: seriesData.value ||[],
|
||||
smooth: true,
|
||||
@@ -123,17 +127,22 @@ onMounted(async () => {
|
||||
],
|
||||
});
|
||||
renderCustomerTypesBar({
|
||||
title: { text: '客户类型分配' },
|
||||
title: { text: '客户类型分布' },
|
||||
tooltip: { trigger: 'axis' },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: countByCusTypeData.type || [],
|
||||
data: ['企业客户','个人客户','政府机构','商业地产','其他'],
|
||||
boundaryGap: true,
|
||||
},
|
||||
yAxis: { type: 'value' },
|
||||
yAxis: { type: 'value',
|
||||
axisLabel: {
|
||||
// formatter: (value: number) => `${parseInt(value.toString())}`
|
||||
},
|
||||
// interval: 0,
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '订单数',
|
||||
name: '客户数',
|
||||
type: 'bar',
|
||||
data: countByCusTypeData.counts || [],
|
||||
},
|
||||
@@ -141,16 +150,28 @@ onMounted(async () => {
|
||||
});
|
||||
renderCustomerRenewalLine({
|
||||
title: { text: '客户续租率趋势' },
|
||||
tooltip: { trigger: 'axis' },
|
||||
tooltip: { trigger: 'axis',
|
||||
formatter: function(params:any) {
|
||||
let result = params[0].axisValue + '<br/>';
|
||||
params.forEach((item:any) => {
|
||||
result += item.marker + item.seriesName + ':' + item.data + '%<br/>';
|
||||
});
|
||||
return result;
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: countRenewRateData.month || [],
|
||||
boundaryGap: false,
|
||||
},
|
||||
yAxis: { type: 'value' },
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
formatter: '{value}%',
|
||||
}, },
|
||||
series: [
|
||||
{
|
||||
name: '订单数',
|
||||
name: '续租率',
|
||||
type: 'line',
|
||||
data: countRenewRateData.rate || [],
|
||||
smooth: true,
|
||||
@@ -162,6 +183,19 @@ onMounted(async () => {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: { type: 'shadow' },
|
||||
formatter: function(params:any) {
|
||||
// params 是一个数组,包含每个系列的当前项
|
||||
let result = params[0].axisValue + '<br/>';
|
||||
params.forEach((item:any) => {
|
||||
if (item.seriesName === '完成率') {
|
||||
// 假设原始数据是 80,显示为 80%
|
||||
result += item.marker + item.seriesName + ':' + item.data + '%<br/>';
|
||||
} else {
|
||||
result += item.marker + item.seriesName + ':' + item.data + '<br/>';
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: ['计划任务数', '已完成数', '完成率'],
|
||||
@@ -169,7 +203,7 @@ onMounted(async () => {
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: countAchievedData.type || [],
|
||||
data: ['修剪整形','肥水管理','中耕除草','病虫害防治','越冬防寒'],
|
||||
},
|
||||
],
|
||||
yAxis: [
|
||||
@@ -195,7 +229,7 @@ onMounted(async () => {
|
||||
{
|
||||
name: '计划任务数',
|
||||
type: 'bar',
|
||||
data: countAchievedData.toral || [],
|
||||
data: countAchievedData.total || [],
|
||||
},
|
||||
{
|
||||
name: '已完成数',
|
||||
@@ -220,7 +254,7 @@ onMounted(async () => {
|
||||
orient: 'horizontal',
|
||||
left: 'center',
|
||||
bottom: 10,
|
||||
data: ['一星', '两星', '三星', '四星', '五星'],
|
||||
data: ['一星', '二星', '三星', '四星', '五星'],
|
||||
},
|
||||
series: [
|
||||
{
|
||||
@@ -283,7 +317,7 @@ function formatNumber(num: number | string) {
|
||||
<div class="title">
|
||||
<div class="title-text">绿植租赁业务统计报表:</div>
|
||||
<div class="title-operate">
|
||||
<div class="export">
|
||||
<div class="export" style="display: none;">
|
||||
<Button size="large" style="color: #fff; background-color: #22c55e">
|
||||
导出数据
|
||||
</Button>
|
||||
|
@@ -0,0 +1,68 @@
|
||||
import type { FormSchemaGetter } from '#/adapter/form';
|
||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
|
||||
|
||||
export const querySchema: FormSchemaGetter = () => [
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'id',
|
||||
label: '编号',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'itemName',
|
||||
label: '巡检项目',
|
||||
},
|
||||
];
|
||||
|
||||
// 需要使用i18n注意这里要改成getter形式 否则切换语言不会刷新
|
||||
// export const columns: () => VxeGridProps['columns'] = () => [
|
||||
export const columns: VxeGridProps['columns'] = [
|
||||
{ type: 'checkbox', width: 60 },
|
||||
{
|
||||
title: '编号',
|
||||
field: 'id',
|
||||
},
|
||||
{
|
||||
title: '巡检项目',
|
||||
field: 'itemName',
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
field: 'createTime',
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
field: 'remark',
|
||||
},
|
||||
{
|
||||
field: 'action',
|
||||
fixed: 'right',
|
||||
slots: { default: 'action' },
|
||||
title: '操作',
|
||||
width: 180,
|
||||
},
|
||||
];
|
||||
|
||||
export const modalSchema: FormSchemaGetter = () => [
|
||||
{
|
||||
label: '主键id',
|
||||
fieldName: 'id',
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
show: () => false,
|
||||
triggerFields: [''],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '巡检项目',
|
||||
fieldName: 'itemName',
|
||||
component: 'Input',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '备注',
|
||||
fieldName: 'remark',
|
||||
component: 'Textarea',
|
||||
},
|
||||
];
|
@@ -0,0 +1,182 @@
|
||||
<script setup lang="ts">
|
||||
import type { Recordable } from '@vben/types';
|
||||
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { Page, useVbenModal, type VbenFormProps } from '@vben/common-ui';
|
||||
import { getVxePopupContainer } from '@vben/utils';
|
||||
|
||||
import { Modal, Popconfirm, Space } from 'ant-design-vue';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import {
|
||||
useVbenVxeGrid,
|
||||
vxeCheckboxChecked,
|
||||
type VxeGridProps
|
||||
} from '#/adapter/vxe-table';
|
||||
|
||||
import {
|
||||
inspectionItemExport,
|
||||
inspectionItemList,
|
||||
inspectionItemRemove,
|
||||
} from '#/api/property/inspectionManagement/inspectionItem';
|
||||
import type { InspectionItemForm } from '#/api/property/inspectionManagement/inspectionItem/model';
|
||||
import { commonDownloadExcel } from '#/utils/file/download';
|
||||
|
||||
import inspectionItemModal from './inspectionItem-modal.vue';
|
||||
import { columns, querySchema } from './data';
|
||||
|
||||
const formOptions: VbenFormProps = {
|
||||
commonConfig: {
|
||||
labelWidth: 80,
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
schema: querySchema(),
|
||||
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
|
||||
// 处理区间选择器RangePicker时间格式 将一个字段映射为两个字段 搜索/导出会用到
|
||||
// 不需要直接删除
|
||||
// fieldMappingTime: [
|
||||
// [
|
||||
// 'createTime',
|
||||
// ['params[beginTime]', 'params[endTime]'],
|
||||
// ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59'],
|
||||
// ],
|
||||
// ],
|
||||
};
|
||||
|
||||
const gridOptions: VxeGridProps = {
|
||||
checkboxConfig: {
|
||||
// 高亮
|
||||
highlight: true,
|
||||
// 翻页时保留选中状态
|
||||
reserve: true,
|
||||
// 点击行选中
|
||||
// trigger: 'row',
|
||||
},
|
||||
// 需要使用i18n注意这里要改成getter形式 否则切换语言不会刷新
|
||||
// columns: columns(),
|
||||
columns,
|
||||
height: 'auto',
|
||||
keepSource: true,
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }, formValues = {}) => {
|
||||
return await inspectionItemList({
|
||||
pageNum: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
...formValues,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
rowConfig: {
|
||||
keyField: 'id',
|
||||
},
|
||||
// 表格全局唯一表示 保存列配置需要用到
|
||||
id: 'property-inspectionItem-index'
|
||||
};
|
||||
|
||||
const [BasicTable, tableApi] = useVbenVxeGrid({
|
||||
formOptions,
|
||||
gridOptions,
|
||||
});
|
||||
|
||||
const [InspectionItemModal, modalApi] = useVbenModal({
|
||||
connectedComponent: inspectionItemModal,
|
||||
});
|
||||
|
||||
function handleAdd() {
|
||||
modalApi.setData({});
|
||||
modalApi.open();
|
||||
}
|
||||
|
||||
async function handleEdit(row: Required<InspectionItemForm>) {
|
||||
modalApi.setData({ id: row.id });
|
||||
modalApi.open();
|
||||
}
|
||||
|
||||
async function handleDelete(row: Required<InspectionItemForm>) {
|
||||
await inspectionItemRemove(row.id);
|
||||
await tableApi.query();
|
||||
}
|
||||
|
||||
function handleMultiDelete() {
|
||||
const rows = tableApi.grid.getCheckboxRecords();
|
||||
const ids = rows.map((row: Required<InspectionItemForm>) => row.id);
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
okType: 'danger',
|
||||
content: `确认删除选中的${ids.length}条记录吗?`,
|
||||
onOk: async () => {
|
||||
await inspectionItemRemove(ids);
|
||||
await tableApi.query();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleDownloadExcel() {
|
||||
commonDownloadExcel(inspectionItemExport, '巡检项目数据', tableApi.formApi.form.values, {
|
||||
fieldMappingTime: formOptions.fieldMappingTime,
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page :auto-content-height="true">
|
||||
<BasicTable table-title="巡检项目列表">
|
||||
<template #toolbar-tools>
|
||||
<Space>
|
||||
<a-button
|
||||
v-access:code="['property:inspectionItem:export']"
|
||||
@click="handleDownloadExcel"
|
||||
>
|
||||
{{ $t('pages.common.export') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
:disabled="!vxeCheckboxChecked(tableApi)"
|
||||
danger
|
||||
type="primary"
|
||||
v-access:code="['property:inspectionItem:remove']"
|
||||
@click="handleMultiDelete">
|
||||
{{ $t('pages.common.delete') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
type="primary"
|
||||
v-access:code="['property:inspectionItem:add']"
|
||||
@click="handleAdd"
|
||||
>
|
||||
{{ $t('pages.common.add') }}
|
||||
</a-button>
|
||||
</Space>
|
||||
</template>
|
||||
<template #action="{ row }">
|
||||
<Space>
|
||||
<ghost-button
|
||||
v-access:code="['property:inspectionItem:edit']"
|
||||
@click.stop="handleEdit(row)"
|
||||
>
|
||||
{{ $t('pages.common.edit') }}
|
||||
</ghost-button>
|
||||
<Popconfirm
|
||||
:get-popup-container="getVxePopupContainer"
|
||||
placement="left"
|
||||
title="确认删除?"
|
||||
@confirm="handleDelete(row)"
|
||||
>
|
||||
<ghost-button
|
||||
danger
|
||||
v-access:code="['property:inspectionItem:remove']"
|
||||
@click.stop=""
|
||||
>
|
||||
{{ $t('pages.common.delete') }}
|
||||
</ghost-button>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
</template>
|
||||
</BasicTable>
|
||||
<InspectionItemModal @reload="tableApi.query()" />
|
||||
</Page>
|
||||
</template>
|
@@ -0,0 +1,101 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
import { $t } from '@vben/locales';
|
||||
import { cloneDeep } from '@vben/utils';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import { inspectionItemAdd, inspectionItemInfo, inspectionItemUpdate } from '#/api/property/inspectionManagement/inspectionItem';
|
||||
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
|
||||
|
||||
import { modalSchema } from './data';
|
||||
|
||||
const emit = defineEmits<{ reload: [] }>();
|
||||
|
||||
const isUpdate = ref(false);
|
||||
const title = computed(() => {
|
||||
return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
|
||||
});
|
||||
|
||||
const [BasicForm, formApi] = useVbenForm({
|
||||
commonConfig: {
|
||||
// 默认占满两列
|
||||
formItemClass: 'col-span-2',
|
||||
// 默认label宽度 px
|
||||
labelWidth: 80,
|
||||
// 通用配置项 会影响到所有表单项
|
||||
componentProps: {
|
||||
class: 'w-full',
|
||||
}
|
||||
},
|
||||
schema: modalSchema(),
|
||||
showDefaultActions: false,
|
||||
wrapperClass: 'grid-cols-2',
|
||||
});
|
||||
|
||||
const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
|
||||
{
|
||||
initializedGetter: defaultFormValueGetter(formApi),
|
||||
currentGetter: defaultFormValueGetter(formApi),
|
||||
},
|
||||
);
|
||||
|
||||
const [BasicModal, modalApi] = useVbenModal({
|
||||
// 在这里更改宽度
|
||||
class: 'w-[550px]',
|
||||
fullscreenButton: false,
|
||||
onBeforeClose,
|
||||
onClosed: handleClosed,
|
||||
onConfirm: handleConfirm,
|
||||
onOpenChange: async (isOpen) => {
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
}
|
||||
modalApi.modalLoading(true);
|
||||
|
||||
const { id } = modalApi.getData() as { id?: number | string };
|
||||
isUpdate.value = !!id;
|
||||
|
||||
if (isUpdate.value && id) {
|
||||
const record = await inspectionItemInfo(id);
|
||||
await formApi.setValues(record);
|
||||
}
|
||||
await markInitialized();
|
||||
|
||||
modalApi.modalLoading(false);
|
||||
},
|
||||
});
|
||||
|
||||
async function handleConfirm() {
|
||||
try {
|
||||
modalApi.lock(true);
|
||||
const { valid } = await formApi.validate();
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
// getValues获取为一个readonly的对象 需要修改必须先深拷贝一次
|
||||
const data = cloneDeep(await formApi.getValues());
|
||||
await (isUpdate.value ? inspectionItemUpdate(data) : inspectionItemAdd(data));
|
||||
resetInitialized();
|
||||
emit('reload');
|
||||
modalApi.close();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
modalApi.lock(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleClosed() {
|
||||
await formApi.resetForm();
|
||||
resetInitialized();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicModal :title="title">
|
||||
<BasicForm />
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
@@ -0,0 +1,220 @@
|
||||
import type {FormSchemaGetter} from '#/adapter/form';
|
||||
import type {VxeGridProps} from '#/adapter/vxe-table';
|
||||
import {getDictOptions} from "#/utils/dict";
|
||||
import {renderDict} from "#/utils/render";
|
||||
|
||||
|
||||
export const querySchema: FormSchemaGetter = () => [
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'planName',
|
||||
label: '计划名称',
|
||||
},
|
||||
|
||||
{
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: getDictOptions('wy_xjzq'),
|
||||
},
|
||||
fieldName: 'inspectionPlanPeriod',
|
||||
label: '巡检周期',
|
||||
},
|
||||
{
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: getDictOptions('wy_xjqdfs'),
|
||||
},
|
||||
fieldName: 'signType',
|
||||
label: '签到方式',
|
||||
},
|
||||
];
|
||||
|
||||
export const columns: VxeGridProps['columns'] = [
|
||||
{type: 'checkbox', width: 60},
|
||||
{
|
||||
title: '主键id',
|
||||
field: 'id',
|
||||
},
|
||||
{
|
||||
title: '巡检计划名称',
|
||||
field: 'planName',
|
||||
},
|
||||
{
|
||||
title: '巡检路线',
|
||||
field: 'inspectionRouteId',
|
||||
},
|
||||
{
|
||||
title: '巡检周期',
|
||||
field: 'inspectionPlanPeriod',
|
||||
slots: {
|
||||
default: ({ row }) => {
|
||||
return renderDict(row.inspectionPlanPeriod, 'wy_xjzq');
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '任务提前分组',
|
||||
field: 'beforeTime',
|
||||
},
|
||||
{
|
||||
title: '开始日期',
|
||||
field: 'startDate',
|
||||
},
|
||||
{
|
||||
title: '结束日期',
|
||||
field: 'endDate',
|
||||
},
|
||||
{
|
||||
title: '开始时间',
|
||||
field: 'startTime',
|
||||
},
|
||||
{
|
||||
title: '结束时间',
|
||||
field: 'endTime',
|
||||
},
|
||||
{
|
||||
title: '签到方式',
|
||||
field: 'signType',
|
||||
slots: {
|
||||
default: ({ row }) => {
|
||||
return renderDict(row.signType, 'wy_xjqdfs');
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '是否允许补检',
|
||||
field: 'canReexamine',
|
||||
slots: {
|
||||
default: ({ row }) => {
|
||||
return renderDict(row.canReexamine, 'wy_sf');
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '选择员工',
|
||||
field: 'userId',
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
field: 'remark',
|
||||
},
|
||||
{
|
||||
field: 'action',
|
||||
fixed: 'right',
|
||||
slots: {default: 'action'},
|
||||
title: '操作',
|
||||
width: 180,
|
||||
},
|
||||
];
|
||||
|
||||
export const modalSchema: FormSchemaGetter = () => [
|
||||
{
|
||||
label: '主键id',
|
||||
fieldName: 'id',
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
show: () => false,
|
||||
triggerFields: [''],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '巡检计划名称',
|
||||
fieldName: 'planName',
|
||||
component: 'Input',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '巡检路线',
|
||||
fieldName: 'inspectionRouteId',
|
||||
component: 'Input',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '巡检周期',
|
||||
fieldName: 'inspectionPlanPeriod',
|
||||
component: 'Input',
|
||||
rules: 'required',
|
||||
componentProps: {
|
||||
options: getDictOptions('wy_xjzq'),
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '任务提前分组',
|
||||
fieldName: 'beforeTime',
|
||||
component: 'Input',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '开始日期',
|
||||
fieldName: 'startDate',
|
||||
component: 'DatePicker',
|
||||
componentProps: {
|
||||
showTime: true,
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
},
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '结束日期',
|
||||
fieldName: 'endDate',
|
||||
component: 'DatePicker',
|
||||
componentProps: {
|
||||
showTime: true,
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
},
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '开始时间',
|
||||
fieldName: 'startTime',
|
||||
component: 'DatePicker',
|
||||
componentProps: {
|
||||
showTime: true,
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
},
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '结束时间',
|
||||
fieldName: 'endTime',
|
||||
component: 'DatePicker',
|
||||
componentProps: {
|
||||
showTime: true,
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
},
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '签到方式',
|
||||
fieldName: 'signType',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: getDictOptions('wy_xjqdfs'),
|
||||
},
|
||||
rules: 'selectRequired',
|
||||
},
|
||||
{
|
||||
label: '允许补检',
|
||||
fieldName: 'canReexamine',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: getDictOptions('wy_sf'),
|
||||
},
|
||||
rules: 'selectRequired',
|
||||
},
|
||||
{
|
||||
label: '选择员工',
|
||||
fieldName: 'userId',
|
||||
component: 'Input',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '备注',
|
||||
fieldName: 'remark',
|
||||
component: 'Input',
|
||||
},
|
||||
];
|
@@ -0,0 +1,182 @@
|
||||
<script setup lang="ts">
|
||||
import type { Recordable } from '@vben/types';
|
||||
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { Page, useVbenModal, type VbenFormProps } from '@vben/common-ui';
|
||||
import { getVxePopupContainer } from '@vben/utils';
|
||||
|
||||
import { Modal, Popconfirm, Space } from 'ant-design-vue';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import {
|
||||
useVbenVxeGrid,
|
||||
vxeCheckboxChecked,
|
||||
type VxeGridProps
|
||||
} from '#/adapter/vxe-table';
|
||||
|
||||
import {
|
||||
inspectionPlanExport,
|
||||
inspectionPlanList,
|
||||
inspectionPlanRemove,
|
||||
} from '#/api/property/inspectionManagement/inspectionPlan';
|
||||
import type { InspectionPlanForm } from '#/api/property/inspectionManagement/inspectionPlan/model';
|
||||
import { commonDownloadExcel } from '#/utils/file/download';
|
||||
|
||||
import inspectionPlanModal from './inspectionPlan-modal.vue';
|
||||
import { columns, querySchema } from './data';
|
||||
|
||||
const formOptions: VbenFormProps = {
|
||||
commonConfig: {
|
||||
labelWidth: 80,
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
schema: querySchema(),
|
||||
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
|
||||
// 处理区间选择器RangePicker时间格式 将一个字段映射为两个字段 搜索/导出会用到
|
||||
// 不需要直接删除
|
||||
// fieldMappingTime: [
|
||||
// [
|
||||
// 'createTime',
|
||||
// ['params[beginTime]', 'params[endTime]'],
|
||||
// ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59'],
|
||||
// ],
|
||||
// ],
|
||||
};
|
||||
|
||||
const gridOptions: VxeGridProps = {
|
||||
checkboxConfig: {
|
||||
// 高亮
|
||||
highlight: true,
|
||||
// 翻页时保留选中状态
|
||||
reserve: true,
|
||||
// 点击行选中
|
||||
// trigger: 'row',
|
||||
},
|
||||
// 需要使用i18n注意这里要改成getter形式 否则切换语言不会刷新
|
||||
// columns: columns(),
|
||||
columns,
|
||||
height: 'auto',
|
||||
keepSource: true,
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }, formValues = {}) => {
|
||||
return await inspectionPlanList({
|
||||
pageNum: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
...formValues,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
rowConfig: {
|
||||
keyField: 'id',
|
||||
},
|
||||
// 表格全局唯一表示 保存列配置需要用到
|
||||
id: 'property-inspectionPlan-index'
|
||||
};
|
||||
|
||||
const [BasicTable, tableApi] = useVbenVxeGrid({
|
||||
formOptions,
|
||||
gridOptions,
|
||||
});
|
||||
|
||||
const [InspectionPlanModal, modalApi] = useVbenModal({
|
||||
connectedComponent: inspectionPlanModal,
|
||||
});
|
||||
|
||||
function handleAdd() {
|
||||
modalApi.setData({});
|
||||
modalApi.open();
|
||||
}
|
||||
|
||||
async function handleEdit(row: Required<InspectionPlanForm>) {
|
||||
modalApi.setData({ id: row.id });
|
||||
modalApi.open();
|
||||
}
|
||||
|
||||
async function handleDelete(row: Required<InspectionPlanForm>) {
|
||||
await inspectionPlanRemove(row.id);
|
||||
await tableApi.query();
|
||||
}
|
||||
|
||||
function handleMultiDelete() {
|
||||
const rows = tableApi.grid.getCheckboxRecords();
|
||||
const ids = rows.map((row: Required<InspectionPlanForm>) => row.id);
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
okType: 'danger',
|
||||
content: `确认删除选中的${ids.length}条记录吗?`,
|
||||
onOk: async () => {
|
||||
await inspectionPlanRemove(ids);
|
||||
await tableApi.query();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleDownloadExcel() {
|
||||
commonDownloadExcel(inspectionPlanExport, '巡检计划数据', tableApi.formApi.form.values, {
|
||||
fieldMappingTime: formOptions.fieldMappingTime,
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page :auto-content-height="true">
|
||||
<BasicTable table-title="巡检计划列表">
|
||||
<template #toolbar-tools>
|
||||
<Space>
|
||||
<a-button
|
||||
v-access:code="['property:inspectionPlan:export']"
|
||||
@click="handleDownloadExcel"
|
||||
>
|
||||
{{ $t('pages.common.export') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
:disabled="!vxeCheckboxChecked(tableApi)"
|
||||
danger
|
||||
type="primary"
|
||||
v-access:code="['property:inspectionPlan:remove']"
|
||||
@click="handleMultiDelete">
|
||||
{{ $t('pages.common.delete') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
type="primary"
|
||||
v-access:code="['property:inspectionPlan:add']"
|
||||
@click="handleAdd"
|
||||
>
|
||||
{{ $t('pages.common.add') }}
|
||||
</a-button>
|
||||
</Space>
|
||||
</template>
|
||||
<template #action="{ row }">
|
||||
<Space>
|
||||
<ghost-button
|
||||
v-access:code="['property:inspectionPlan:edit']"
|
||||
@click.stop="handleEdit(row)"
|
||||
>
|
||||
{{ $t('pages.common.edit') }}
|
||||
</ghost-button>
|
||||
<Popconfirm
|
||||
:get-popup-container="getVxePopupContainer"
|
||||
placement="left"
|
||||
title="确认删除?"
|
||||
@confirm="handleDelete(row)"
|
||||
>
|
||||
<ghost-button
|
||||
danger
|
||||
v-access:code="['property:inspectionPlan:remove']"
|
||||
@click.stop=""
|
||||
>
|
||||
{{ $t('pages.common.delete') }}
|
||||
</ghost-button>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
</template>
|
||||
</BasicTable>
|
||||
<InspectionPlanModal @reload="tableApi.query()" />
|
||||
</Page>
|
||||
</template>
|
@@ -0,0 +1,101 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
import { $t } from '@vben/locales';
|
||||
import { cloneDeep } from '@vben/utils';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import { inspectionPlanAdd, inspectionPlanInfo, inspectionPlanUpdate } from '#/api/property/inspectionManagement/inspectionPlan';
|
||||
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
|
||||
|
||||
import { modalSchema } from './data';
|
||||
|
||||
const emit = defineEmits<{ reload: [] }>();
|
||||
|
||||
const isUpdate = ref(false);
|
||||
const title = computed(() => {
|
||||
return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
|
||||
});
|
||||
|
||||
const [BasicForm, formApi] = useVbenForm({
|
||||
commonConfig: {
|
||||
// 默认占满两列
|
||||
formItemClass: 'col-span-2',
|
||||
// 默认label宽度 px
|
||||
labelWidth: 80,
|
||||
// 通用配置项 会影响到所有表单项
|
||||
componentProps: {
|
||||
class: 'w-full',
|
||||
}
|
||||
},
|
||||
schema: modalSchema(),
|
||||
showDefaultActions: false,
|
||||
wrapperClass: 'grid-cols-2',
|
||||
});
|
||||
|
||||
const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
|
||||
{
|
||||
initializedGetter: defaultFormValueGetter(formApi),
|
||||
currentGetter: defaultFormValueGetter(formApi),
|
||||
},
|
||||
);
|
||||
|
||||
const [BasicModal, modalApi] = useVbenModal({
|
||||
// 在这里更改宽度
|
||||
class: 'w-[550px]',
|
||||
fullscreenButton: false,
|
||||
onBeforeClose,
|
||||
onClosed: handleClosed,
|
||||
onConfirm: handleConfirm,
|
||||
onOpenChange: async (isOpen) => {
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
}
|
||||
modalApi.modalLoading(true);
|
||||
|
||||
const { id } = modalApi.getData() as { id?: number | string };
|
||||
isUpdate.value = !!id;
|
||||
|
||||
if (isUpdate.value && id) {
|
||||
const record = await inspectionPlanInfo(id);
|
||||
await formApi.setValues(record);
|
||||
}
|
||||
await markInitialized();
|
||||
|
||||
modalApi.modalLoading(false);
|
||||
},
|
||||
});
|
||||
|
||||
async function handleConfirm() {
|
||||
try {
|
||||
modalApi.lock(true);
|
||||
const { valid } = await formApi.validate();
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
// getValues获取为一个readonly的对象 需要修改必须先深拷贝一次
|
||||
const data = cloneDeep(await formApi.getValues());
|
||||
await (isUpdate.value ? inspectionPlanUpdate(data) : inspectionPlanAdd(data));
|
||||
resetInitialized();
|
||||
emit('reload');
|
||||
modalApi.close();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
modalApi.lock(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleClosed() {
|
||||
await formApi.resetForm();
|
||||
resetInitialized();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicModal :title="title">
|
||||
<BasicForm />
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
@@ -0,0 +1,149 @@
|
||||
import type { FormSchemaGetter } from '#/adapter/form';
|
||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
|
||||
|
||||
export const querySchema: FormSchemaGetter = () => [
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'itemId',
|
||||
label: '巡检项目id',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'pointName',
|
||||
label: '巡检点名称',
|
||||
},
|
||||
{
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
},
|
||||
fieldName: 'pointType',
|
||||
label: '巡检点类型',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'nfcCode',
|
||||
label: 'nfc编码',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'createById',
|
||||
label: '创建人id',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'updateById',
|
||||
label: '更新人id',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'searchValue',
|
||||
label: '搜索值',
|
||||
},
|
||||
];
|
||||
|
||||
// 需要使用i18n注意这里要改成getter形式 否则切换语言不会刷新
|
||||
// export const columns: () => VxeGridProps['columns'] = () => [
|
||||
export const columns: VxeGridProps['columns'] = [
|
||||
{ type: 'checkbox', width: 60 },
|
||||
{
|
||||
title: '主键id',
|
||||
field: 'id',
|
||||
},
|
||||
{
|
||||
title: '巡检项目id',
|
||||
field: 'itemId',
|
||||
},
|
||||
{
|
||||
title: '巡检点名称',
|
||||
field: 'pointName',
|
||||
},
|
||||
{
|
||||
title: '巡检点类型',
|
||||
field: 'pointType',
|
||||
},
|
||||
{
|
||||
title: 'nfc编码',
|
||||
field: 'nfcCode',
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
field: 'remark',
|
||||
},
|
||||
{
|
||||
title: '创建人id',
|
||||
field: 'createById',
|
||||
},
|
||||
{
|
||||
title: '更新人id',
|
||||
field: 'updateById',
|
||||
},
|
||||
{
|
||||
title: '搜索值',
|
||||
field: 'searchValue',
|
||||
},
|
||||
{
|
||||
field: 'action',
|
||||
fixed: 'right',
|
||||
slots: { default: 'action' },
|
||||
title: '操作',
|
||||
width: 180,
|
||||
},
|
||||
];
|
||||
|
||||
export const modalSchema: FormSchemaGetter = () => [
|
||||
{
|
||||
label: '主键id',
|
||||
fieldName: 'id',
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
show: () => false,
|
||||
triggerFields: [''],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '巡检项目id',
|
||||
fieldName: 'itemId',
|
||||
component: 'Input',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '巡检点名称',
|
||||
fieldName: 'pointName',
|
||||
component: 'Input',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '巡检点类型',
|
||||
fieldName: 'pointType',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
},
|
||||
rules: 'selectRequired',
|
||||
},
|
||||
{
|
||||
label: 'nfc编码',
|
||||
fieldName: 'nfcCode',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '备注',
|
||||
fieldName: 'remark',
|
||||
component: 'Textarea',
|
||||
},
|
||||
{
|
||||
label: '创建人id',
|
||||
fieldName: 'createById',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '更新人id',
|
||||
fieldName: 'updateById',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '搜索值',
|
||||
fieldName: 'searchValue',
|
||||
component: 'Input',
|
||||
},
|
||||
];
|
@@ -0,0 +1,182 @@
|
||||
<script setup lang="ts">
|
||||
import type { Recordable } from '@vben/types';
|
||||
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { Page, useVbenModal, type VbenFormProps } from '@vben/common-ui';
|
||||
import { getVxePopupContainer } from '@vben/utils';
|
||||
|
||||
import { Modal, Popconfirm, Space } from 'ant-design-vue';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import {
|
||||
useVbenVxeGrid,
|
||||
vxeCheckboxChecked,
|
||||
type VxeGridProps
|
||||
} from '#/adapter/vxe-table';
|
||||
|
||||
import {
|
||||
inspectionPointExport,
|
||||
inspectionPointList,
|
||||
inspectionPointRemove,
|
||||
} from '#/api/property/inspectionManagement/inspectionPoint';
|
||||
import type { InspectionPointForm } from '#/api/property/inspectionManagement/inspectionPoint/model';
|
||||
import { commonDownloadExcel } from '#/utils/file/download';
|
||||
|
||||
import inspectionPointModal from './inspectionPoint-modal.vue';
|
||||
import { columns, querySchema } from './data';
|
||||
|
||||
const formOptions: VbenFormProps = {
|
||||
commonConfig: {
|
||||
labelWidth: 80,
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
schema: querySchema(),
|
||||
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
|
||||
// 处理区间选择器RangePicker时间格式 将一个字段映射为两个字段 搜索/导出会用到
|
||||
// 不需要直接删除
|
||||
// fieldMappingTime: [
|
||||
// [
|
||||
// 'createTime',
|
||||
// ['params[beginTime]', 'params[endTime]'],
|
||||
// ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59'],
|
||||
// ],
|
||||
// ],
|
||||
};
|
||||
|
||||
const gridOptions: VxeGridProps = {
|
||||
checkboxConfig: {
|
||||
// 高亮
|
||||
highlight: true,
|
||||
// 翻页时保留选中状态
|
||||
reserve: true,
|
||||
// 点击行选中
|
||||
// trigger: 'row',
|
||||
},
|
||||
// 需要使用i18n注意这里要改成getter形式 否则切换语言不会刷新
|
||||
// columns: columns(),
|
||||
columns,
|
||||
height: 'auto',
|
||||
keepSource: true,
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }, formValues = {}) => {
|
||||
return await inspectionPointList({
|
||||
pageNum: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
...formValues,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
rowConfig: {
|
||||
keyField: 'id',
|
||||
},
|
||||
// 表格全局唯一表示 保存列配置需要用到
|
||||
id: 'property-inspectionPoint-index'
|
||||
};
|
||||
|
||||
const [BasicTable, tableApi] = useVbenVxeGrid({
|
||||
formOptions,
|
||||
gridOptions,
|
||||
});
|
||||
|
||||
const [InspectionPointModal, modalApi] = useVbenModal({
|
||||
connectedComponent: inspectionPointModal,
|
||||
});
|
||||
|
||||
function handleAdd() {
|
||||
modalApi.setData({});
|
||||
modalApi.open();
|
||||
}
|
||||
|
||||
async function handleEdit(row: Required<InspectionPointForm>) {
|
||||
modalApi.setData({ id: row.id });
|
||||
modalApi.open();
|
||||
}
|
||||
|
||||
async function handleDelete(row: Required<InspectionPointForm>) {
|
||||
await inspectionPointRemove(row.id);
|
||||
await tableApi.query();
|
||||
}
|
||||
|
||||
function handleMultiDelete() {
|
||||
const rows = tableApi.grid.getCheckboxRecords();
|
||||
const ids = rows.map((row: Required<InspectionPointForm>) => row.id);
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
okType: 'danger',
|
||||
content: `确认删除选中的${ids.length}条记录吗?`,
|
||||
onOk: async () => {
|
||||
await inspectionPointRemove(ids);
|
||||
await tableApi.query();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleDownloadExcel() {
|
||||
commonDownloadExcel(inspectionPointExport, '巡检点数据', tableApi.formApi.form.values, {
|
||||
fieldMappingTime: formOptions.fieldMappingTime,
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page :auto-content-height="true">
|
||||
<BasicTable table-title="巡检点列表">
|
||||
<template #toolbar-tools>
|
||||
<Space>
|
||||
<a-button
|
||||
v-access:code="['property:inspectionPoint:export']"
|
||||
@click="handleDownloadExcel"
|
||||
>
|
||||
{{ $t('pages.common.export') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
:disabled="!vxeCheckboxChecked(tableApi)"
|
||||
danger
|
||||
type="primary"
|
||||
v-access:code="['property:inspectionPoint:remove']"
|
||||
@click="handleMultiDelete">
|
||||
{{ $t('pages.common.delete') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
type="primary"
|
||||
v-access:code="['property:inspectionPoint:add']"
|
||||
@click="handleAdd"
|
||||
>
|
||||
{{ $t('pages.common.add') }}
|
||||
</a-button>
|
||||
</Space>
|
||||
</template>
|
||||
<template #action="{ row }">
|
||||
<Space>
|
||||
<ghost-button
|
||||
v-access:code="['property:inspectionPoint:edit']"
|
||||
@click.stop="handleEdit(row)"
|
||||
>
|
||||
{{ $t('pages.common.edit') }}
|
||||
</ghost-button>
|
||||
<Popconfirm
|
||||
:get-popup-container="getVxePopupContainer"
|
||||
placement="left"
|
||||
title="确认删除?"
|
||||
@confirm="handleDelete(row)"
|
||||
>
|
||||
<ghost-button
|
||||
danger
|
||||
v-access:code="['property:inspectionPoint:remove']"
|
||||
@click.stop=""
|
||||
>
|
||||
{{ $t('pages.common.delete') }}
|
||||
</ghost-button>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
</template>
|
||||
</BasicTable>
|
||||
<InspectionPointModal @reload="tableApi.query()" />
|
||||
</Page>
|
||||
</template>
|
@@ -0,0 +1,101 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
import { $t } from '@vben/locales';
|
||||
import { cloneDeep } from '@vben/utils';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import { inspectionPointAdd, inspectionPointInfo, inspectionPointUpdate } from '#/api/property/inspectionManagement/inspectionPoint';
|
||||
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
|
||||
|
||||
import { modalSchema } from './data';
|
||||
|
||||
const emit = defineEmits<{ reload: [] }>();
|
||||
|
||||
const isUpdate = ref(false);
|
||||
const title = computed(() => {
|
||||
return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
|
||||
});
|
||||
|
||||
const [BasicForm, formApi] = useVbenForm({
|
||||
commonConfig: {
|
||||
// 默认占满两列
|
||||
formItemClass: 'col-span-2',
|
||||
// 默认label宽度 px
|
||||
labelWidth: 80,
|
||||
// 通用配置项 会影响到所有表单项
|
||||
componentProps: {
|
||||
class: 'w-full',
|
||||
}
|
||||
},
|
||||
schema: modalSchema(),
|
||||
showDefaultActions: false,
|
||||
wrapperClass: 'grid-cols-2',
|
||||
});
|
||||
|
||||
const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
|
||||
{
|
||||
initializedGetter: defaultFormValueGetter(formApi),
|
||||
currentGetter: defaultFormValueGetter(formApi),
|
||||
},
|
||||
);
|
||||
|
||||
const [BasicModal, modalApi] = useVbenModal({
|
||||
// 在这里更改宽度
|
||||
class: 'w-[550px]',
|
||||
fullscreenButton: false,
|
||||
onBeforeClose,
|
||||
onClosed: handleClosed,
|
||||
onConfirm: handleConfirm,
|
||||
onOpenChange: async (isOpen) => {
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
}
|
||||
modalApi.modalLoading(true);
|
||||
|
||||
const { id } = modalApi.getData() as { id?: number | string };
|
||||
isUpdate.value = !!id;
|
||||
|
||||
if (isUpdate.value && id) {
|
||||
const record = await inspectionPointInfo(id);
|
||||
await formApi.setValues(record);
|
||||
}
|
||||
await markInitialized();
|
||||
|
||||
modalApi.modalLoading(false);
|
||||
},
|
||||
});
|
||||
|
||||
async function handleConfirm() {
|
||||
try {
|
||||
modalApi.lock(true);
|
||||
const { valid } = await formApi.validate();
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
// getValues获取为一个readonly的对象 需要修改必须先深拷贝一次
|
||||
const data = cloneDeep(await formApi.getValues());
|
||||
await (isUpdate.value ? inspectionPointUpdate(data) : inspectionPointAdd(data));
|
||||
resetInitialized();
|
||||
emit('reload');
|
||||
modalApi.close();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
modalApi.lock(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleClosed() {
|
||||
await formApi.resetForm();
|
||||
resetInitialized();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicModal :title="title">
|
||||
<BasicForm />
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
@@ -0,0 +1,59 @@
|
||||
import type { FormSchemaGetter } from '#/adapter/form';
|
||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
|
||||
|
||||
export const querySchema: FormSchemaGetter = () => [
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'routeName',
|
||||
label: '路线名称',
|
||||
},
|
||||
];
|
||||
|
||||
// 需要使用i18n注意这里要改成getter形式 否则切换语言不会刷新
|
||||
// export const columns: () => VxeGridProps['columns'] = () => [
|
||||
export const columns: VxeGridProps['columns'] = [
|
||||
{ type: 'checkbox', width: 60 },
|
||||
{
|
||||
title: '主键id',
|
||||
field: 'id',
|
||||
},
|
||||
{
|
||||
title: '路线名称',
|
||||
field: 'routeName',
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
field: 'remark',
|
||||
},
|
||||
{
|
||||
field: 'action',
|
||||
fixed: 'right',
|
||||
slots: { default: 'action' },
|
||||
title: '操作',
|
||||
width: 180,
|
||||
},
|
||||
];
|
||||
|
||||
export const modalSchema: FormSchemaGetter = () => [
|
||||
{
|
||||
label: '主键id',
|
||||
fieldName: 'id',
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
show: () => false,
|
||||
triggerFields: [''],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '路线名称',
|
||||
fieldName: 'routeName',
|
||||
component: 'Input',
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
label: '备注',
|
||||
fieldName: 'remark',
|
||||
component: 'Input',
|
||||
},
|
||||
];
|
@@ -0,0 +1,182 @@
|
||||
<script setup lang="ts">
|
||||
import type { Recordable } from '@vben/types';
|
||||
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { Page, useVbenModal, type VbenFormProps } from '@vben/common-ui';
|
||||
import { getVxePopupContainer } from '@vben/utils';
|
||||
|
||||
import { Modal, Popconfirm, Space } from 'ant-design-vue';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import {
|
||||
useVbenVxeGrid,
|
||||
vxeCheckboxChecked,
|
||||
type VxeGridProps
|
||||
} from '#/adapter/vxe-table';
|
||||
|
||||
import {
|
||||
inspectionRouteExport,
|
||||
inspectionRouteList,
|
||||
inspectionRouteRemove,
|
||||
} from '#/api/property/inspectionManagement/inspectionRoute';
|
||||
import type { InspectionRouteForm } from '#/api/property/inspectionManagement/inspectionRoute/model';
|
||||
import { commonDownloadExcel } from '#/utils/file/download';
|
||||
|
||||
import inspectionRouteModal from './inspectionRoute-modal.vue';
|
||||
import { columns, querySchema } from './data';
|
||||
|
||||
const formOptions: VbenFormProps = {
|
||||
commonConfig: {
|
||||
labelWidth: 80,
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
schema: querySchema(),
|
||||
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
|
||||
// 处理区间选择器RangePicker时间格式 将一个字段映射为两个字段 搜索/导出会用到
|
||||
// 不需要直接删除
|
||||
// fieldMappingTime: [
|
||||
// [
|
||||
// 'createTime',
|
||||
// ['params[beginTime]', 'params[endTime]'],
|
||||
// ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59'],
|
||||
// ],
|
||||
// ],
|
||||
};
|
||||
|
||||
const gridOptions: VxeGridProps = {
|
||||
checkboxConfig: {
|
||||
// 高亮
|
||||
highlight: true,
|
||||
// 翻页时保留选中状态
|
||||
reserve: true,
|
||||
// 点击行选中
|
||||
// trigger: 'row',
|
||||
},
|
||||
// 需要使用i18n注意这里要改成getter形式 否则切换语言不会刷新
|
||||
// columns: columns(),
|
||||
columns,
|
||||
height: 'auto',
|
||||
keepSource: true,
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }, formValues = {}) => {
|
||||
return await inspectionRouteList({
|
||||
pageNum: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
...formValues,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
rowConfig: {
|
||||
keyField: 'id',
|
||||
},
|
||||
// 表格全局唯一表示 保存列配置需要用到
|
||||
id: 'property-inspectionRoute-index'
|
||||
};
|
||||
|
||||
const [BasicTable, tableApi] = useVbenVxeGrid({
|
||||
formOptions,
|
||||
gridOptions,
|
||||
});
|
||||
|
||||
const [InspectionRouteModal, modalApi] = useVbenModal({
|
||||
connectedComponent: inspectionRouteModal,
|
||||
});
|
||||
|
||||
function handleAdd() {
|
||||
modalApi.setData({});
|
||||
modalApi.open();
|
||||
}
|
||||
|
||||
async function handleEdit(row: Required<InspectionRouteForm>) {
|
||||
modalApi.setData({ id: row.id });
|
||||
modalApi.open();
|
||||
}
|
||||
|
||||
async function handleDelete(row: Required<InspectionRouteForm>) {
|
||||
await inspectionRouteRemove(row.id);
|
||||
await tableApi.query();
|
||||
}
|
||||
|
||||
function handleMultiDelete() {
|
||||
const rows = tableApi.grid.getCheckboxRecords();
|
||||
const ids = rows.map((row: Required<InspectionRouteForm>) => row.id);
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
okType: 'danger',
|
||||
content: `确认删除选中的${ids.length}条记录吗?`,
|
||||
onOk: async () => {
|
||||
await inspectionRouteRemove(ids);
|
||||
await tableApi.query();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleDownloadExcel() {
|
||||
commonDownloadExcel(inspectionRouteExport, '巡检路线数据', tableApi.formApi.form.values, {
|
||||
fieldMappingTime: formOptions.fieldMappingTime,
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page :auto-content-height="true">
|
||||
<BasicTable table-title="巡检路线列表">
|
||||
<template #toolbar-tools>
|
||||
<Space>
|
||||
<a-button
|
||||
v-access:code="['property:inspectionRoute:export']"
|
||||
@click="handleDownloadExcel"
|
||||
>
|
||||
{{ $t('pages.common.export') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
:disabled="!vxeCheckboxChecked(tableApi)"
|
||||
danger
|
||||
type="primary"
|
||||
v-access:code="['property:inspectionRoute:remove']"
|
||||
@click="handleMultiDelete">
|
||||
{{ $t('pages.common.delete') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
type="primary"
|
||||
v-access:code="['property:inspectionRoute:add']"
|
||||
@click="handleAdd"
|
||||
>
|
||||
{{ $t('pages.common.add') }}
|
||||
</a-button>
|
||||
</Space>
|
||||
</template>
|
||||
<template #action="{ row }">
|
||||
<Space>
|
||||
<ghost-button
|
||||
v-access:code="['property:inspectionRoute:edit']"
|
||||
@click.stop="handleEdit(row)"
|
||||
>
|
||||
{{ $t('pages.common.edit') }}
|
||||
</ghost-button>
|
||||
<Popconfirm
|
||||
:get-popup-container="getVxePopupContainer"
|
||||
placement="left"
|
||||
title="确认删除?"
|
||||
@confirm="handleDelete(row)"
|
||||
>
|
||||
<ghost-button
|
||||
danger
|
||||
v-access:code="['property:inspectionRoute:remove']"
|
||||
@click.stop=""
|
||||
>
|
||||
{{ $t('pages.common.delete') }}
|
||||
</ghost-button>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
</template>
|
||||
</BasicTable>
|
||||
<InspectionRouteModal @reload="tableApi.query()" />
|
||||
</Page>
|
||||
</template>
|
@@ -0,0 +1,101 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
import { $t } from '@vben/locales';
|
||||
import { cloneDeep } from '@vben/utils';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import { inspectionRouteAdd, inspectionRouteInfo, inspectionRouteUpdate } from '#/api/property/inspectionManagement/inspectionRoute';
|
||||
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
|
||||
|
||||
import { modalSchema } from './data';
|
||||
|
||||
const emit = defineEmits<{ reload: [] }>();
|
||||
|
||||
const isUpdate = ref(false);
|
||||
const title = computed(() => {
|
||||
return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
|
||||
});
|
||||
|
||||
const [BasicForm, formApi] = useVbenForm({
|
||||
commonConfig: {
|
||||
// 默认占满两列
|
||||
formItemClass: 'col-span-2',
|
||||
// 默认label宽度 px
|
||||
labelWidth: 80,
|
||||
// 通用配置项 会影响到所有表单项
|
||||
componentProps: {
|
||||
class: 'w-full',
|
||||
}
|
||||
},
|
||||
schema: modalSchema(),
|
||||
showDefaultActions: false,
|
||||
wrapperClass: 'grid-cols-2',
|
||||
});
|
||||
|
||||
const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
|
||||
{
|
||||
initializedGetter: defaultFormValueGetter(formApi),
|
||||
currentGetter: defaultFormValueGetter(formApi),
|
||||
},
|
||||
);
|
||||
|
||||
const [BasicModal, modalApi] = useVbenModal({
|
||||
// 在这里更改宽度
|
||||
class: 'w-[550px]',
|
||||
fullscreenButton: false,
|
||||
onBeforeClose,
|
||||
onClosed: handleClosed,
|
||||
onConfirm: handleConfirm,
|
||||
onOpenChange: async (isOpen) => {
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
}
|
||||
modalApi.modalLoading(true);
|
||||
|
||||
const { id } = modalApi.getData() as { id?: number | string };
|
||||
isUpdate.value = !!id;
|
||||
|
||||
if (isUpdate.value && id) {
|
||||
const record = await inspectionRouteInfo(id);
|
||||
await formApi.setValues(record);
|
||||
}
|
||||
await markInitialized();
|
||||
|
||||
modalApi.modalLoading(false);
|
||||
},
|
||||
});
|
||||
|
||||
async function handleConfirm() {
|
||||
try {
|
||||
modalApi.lock(true);
|
||||
const { valid } = await formApi.validate();
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
// getValues获取为一个readonly的对象 需要修改必须先深拷贝一次
|
||||
const data = cloneDeep(await formApi.getValues());
|
||||
await (isUpdate.value ? inspectionRouteUpdate(data) : inspectionRouteAdd(data));
|
||||
resetInitialized();
|
||||
emit('reload');
|
||||
modalApi.close();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
modalApi.lock(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleClosed() {
|
||||
await formApi.resetForm();
|
||||
resetInitialized();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicModal :title="title">
|
||||
<BasicForm />
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
@@ -0,0 +1,192 @@
|
||||
import type { FormSchemaGetter } from '#/adapter/form';
|
||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||
|
||||
|
||||
export const querySchema: FormSchemaGetter = () => [
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'inspectionPlanId',
|
||||
label: '巡检计划id',
|
||||
},
|
||||
{
|
||||
component: 'DatePicker',
|
||||
componentProps: {
|
||||
showTime: true,
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
},
|
||||
fieldName: 'actInsTime',
|
||||
label: '实际巡检时间',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'actUserId',
|
||||
label: '当前巡检人',
|
||||
},
|
||||
{
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
},
|
||||
fieldName: 'taskType',
|
||||
label: '巡检方式',
|
||||
},
|
||||
{
|
||||
component: 'Textarea',
|
||||
fieldName: 'transferDesc',
|
||||
label: '转移描述',
|
||||
},
|
||||
{
|
||||
component: 'RadioGroup',
|
||||
componentProps: {
|
||||
buttonStyle: 'solid',
|
||||
optionType: 'button',
|
||||
},
|
||||
fieldName: 'status',
|
||||
label: '巡检状态',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'createById',
|
||||
label: '创建人id',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'updateById',
|
||||
label: '更新人id',
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'searchValue',
|
||||
label: '搜索值',
|
||||
},
|
||||
];
|
||||
|
||||
// 需要使用i18n注意这里要改成getter形式 否则切换语言不会刷新
|
||||
// export const columns: () => VxeGridProps['columns'] = () => [
|
||||
export const columns: VxeGridProps['columns'] = [
|
||||
{ type: 'checkbox', width: 60 },
|
||||
{
|
||||
title: '主键id',
|
||||
field: 'id',
|
||||
},
|
||||
{
|
||||
title: '巡检计划id',
|
||||
field: 'inspectionPlanId',
|
||||
},
|
||||
{
|
||||
title: '实际巡检时间',
|
||||
field: 'actInsTime',
|
||||
},
|
||||
{
|
||||
title: '当前巡检人',
|
||||
field: 'actUserId',
|
||||
},
|
||||
{
|
||||
title: '巡检方式',
|
||||
field: 'taskType',
|
||||
},
|
||||
{
|
||||
title: '转移描述',
|
||||
field: 'transferDesc',
|
||||
},
|
||||
{
|
||||
title: '巡检状态',
|
||||
field: 'status',
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
field: 'remark',
|
||||
},
|
||||
{
|
||||
title: '创建人id',
|
||||
field: 'createById',
|
||||
},
|
||||
{
|
||||
title: '更新人id',
|
||||
field: 'updateById',
|
||||
},
|
||||
{
|
||||
title: '搜索值',
|
||||
field: 'searchValue',
|
||||
},
|
||||
{
|
||||
field: 'action',
|
||||
fixed: 'right',
|
||||
slots: { default: 'action' },
|
||||
title: '操作',
|
||||
width: 180,
|
||||
},
|
||||
];
|
||||
|
||||
export const modalSchema: FormSchemaGetter = () => [
|
||||
{
|
||||
label: '主键id',
|
||||
fieldName: 'id',
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
show: () => false,
|
||||
triggerFields: [''],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '巡检计划id',
|
||||
fieldName: 'inspectionPlanId',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '实际巡检时间',
|
||||
fieldName: 'actInsTime',
|
||||
component: 'DatePicker',
|
||||
componentProps: {
|
||||
showTime: true,
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '当前巡检人',
|
||||
fieldName: 'actUserId',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '巡检方式',
|
||||
fieldName: 'taskType',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '转移描述',
|
||||
fieldName: 'transferDesc',
|
||||
component: 'Textarea',
|
||||
},
|
||||
{
|
||||
label: '巡检状态',
|
||||
fieldName: 'status',
|
||||
component: 'RadioGroup',
|
||||
componentProps: {
|
||||
buttonStyle: 'solid',
|
||||
optionType: 'button',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '备注',
|
||||
fieldName: 'remark',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '创建人id',
|
||||
fieldName: 'createById',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '更新人id',
|
||||
fieldName: 'updateById',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '搜索值',
|
||||
fieldName: 'searchValue',
|
||||
component: 'Input',
|
||||
},
|
||||
];
|
@@ -0,0 +1,182 @@
|
||||
<script setup lang="ts">
|
||||
import type { Recordable } from '@vben/types';
|
||||
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { Page, useVbenModal, type VbenFormProps } from '@vben/common-ui';
|
||||
import { getVxePopupContainer } from '@vben/utils';
|
||||
|
||||
import { Modal, Popconfirm, Space } from 'ant-design-vue';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import {
|
||||
useVbenVxeGrid,
|
||||
vxeCheckboxChecked,
|
||||
type VxeGridProps
|
||||
} from '#/adapter/vxe-table';
|
||||
|
||||
import {
|
||||
inspectionTaskExport,
|
||||
inspectionTaskList,
|
||||
inspectionTaskRemove,
|
||||
} from '#/api/property/inspectionManagement/inspectionTask';
|
||||
import type { InspectionTaskForm } from '#/api/property/inspectionManagement/inspectionTask/model';
|
||||
import { commonDownloadExcel } from '#/utils/file/download';
|
||||
|
||||
import inspectionTaskModal from './inspectionTask-modal.vue';
|
||||
import { columns, querySchema } from './data';
|
||||
|
||||
const formOptions: VbenFormProps = {
|
||||
commonConfig: {
|
||||
labelWidth: 80,
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
schema: querySchema(),
|
||||
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
|
||||
// 处理区间选择器RangePicker时间格式 将一个字段映射为两个字段 搜索/导出会用到
|
||||
// 不需要直接删除
|
||||
// fieldMappingTime: [
|
||||
// [
|
||||
// 'createTime',
|
||||
// ['params[beginTime]', 'params[endTime]'],
|
||||
// ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59'],
|
||||
// ],
|
||||
// ],
|
||||
};
|
||||
|
||||
const gridOptions: VxeGridProps = {
|
||||
checkboxConfig: {
|
||||
// 高亮
|
||||
highlight: true,
|
||||
// 翻页时保留选中状态
|
||||
reserve: true,
|
||||
// 点击行选中
|
||||
// trigger: 'row',
|
||||
},
|
||||
// 需要使用i18n注意这里要改成getter形式 否则切换语言不会刷新
|
||||
// columns: columns(),
|
||||
columns,
|
||||
height: 'auto',
|
||||
keepSource: true,
|
||||
pagerConfig: {},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }, formValues = {}) => {
|
||||
return await inspectionTaskList({
|
||||
pageNum: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
...formValues,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
rowConfig: {
|
||||
keyField: 'id',
|
||||
},
|
||||
// 表格全局唯一表示 保存列配置需要用到
|
||||
id: 'property-inspectionTask-index'
|
||||
};
|
||||
|
||||
const [BasicTable, tableApi] = useVbenVxeGrid({
|
||||
formOptions,
|
||||
gridOptions,
|
||||
});
|
||||
|
||||
const [InspectionTaskModal, modalApi] = useVbenModal({
|
||||
connectedComponent: inspectionTaskModal,
|
||||
});
|
||||
|
||||
function handleAdd() {
|
||||
modalApi.setData({});
|
||||
modalApi.open();
|
||||
}
|
||||
|
||||
async function handleEdit(row: Required<InspectionTaskForm>) {
|
||||
modalApi.setData({ id: row.id });
|
||||
modalApi.open();
|
||||
}
|
||||
|
||||
async function handleDelete(row: Required<InspectionTaskForm>) {
|
||||
await inspectionTaskRemove(row.id);
|
||||
await tableApi.query();
|
||||
}
|
||||
|
||||
function handleMultiDelete() {
|
||||
const rows = tableApi.grid.getCheckboxRecords();
|
||||
const ids = rows.map((row: Required<InspectionTaskForm>) => row.id);
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
okType: 'danger',
|
||||
content: `确认删除选中的${ids.length}条记录吗?`,
|
||||
onOk: async () => {
|
||||
await inspectionTaskRemove(ids);
|
||||
await tableApi.query();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleDownloadExcel() {
|
||||
commonDownloadExcel(inspectionTaskExport, '巡检任务数据', tableApi.formApi.form.values, {
|
||||
fieldMappingTime: formOptions.fieldMappingTime,
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page :auto-content-height="true">
|
||||
<BasicTable table-title="巡检任务列表">
|
||||
<template #toolbar-tools>
|
||||
<Space>
|
||||
<a-button
|
||||
v-access:code="['property:inspectionTask:export']"
|
||||
@click="handleDownloadExcel"
|
||||
>
|
||||
{{ $t('pages.common.export') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
:disabled="!vxeCheckboxChecked(tableApi)"
|
||||
danger
|
||||
type="primary"
|
||||
v-access:code="['property:inspectionTask:remove']"
|
||||
@click="handleMultiDelete">
|
||||
{{ $t('pages.common.delete') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
type="primary"
|
||||
v-access:code="['property:inspectionTask:add']"
|
||||
@click="handleAdd"
|
||||
>
|
||||
{{ $t('pages.common.add') }}
|
||||
</a-button>
|
||||
</Space>
|
||||
</template>
|
||||
<template #action="{ row }">
|
||||
<Space>
|
||||
<ghost-button
|
||||
v-access:code="['property:inspectionTask:edit']"
|
||||
@click.stop="handleEdit(row)"
|
||||
>
|
||||
{{ $t('pages.common.edit') }}
|
||||
</ghost-button>
|
||||
<Popconfirm
|
||||
:get-popup-container="getVxePopupContainer"
|
||||
placement="left"
|
||||
title="确认删除?"
|
||||
@confirm="handleDelete(row)"
|
||||
>
|
||||
<ghost-button
|
||||
danger
|
||||
v-access:code="['property:inspectionTask:remove']"
|
||||
@click.stop=""
|
||||
>
|
||||
{{ $t('pages.common.delete') }}
|
||||
</ghost-button>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
</template>
|
||||
</BasicTable>
|
||||
<InspectionTaskModal @reload="tableApi.query()" />
|
||||
</Page>
|
||||
</template>
|
@@ -0,0 +1,101 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
import { $t } from '@vben/locales';
|
||||
import { cloneDeep } from '@vben/utils';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import { inspectionTaskAdd, inspectionTaskInfo, inspectionTaskUpdate } from '#/api/property/inspectionManagement/inspectionTask';
|
||||
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
|
||||
|
||||
import { modalSchema } from './data';
|
||||
|
||||
const emit = defineEmits<{ reload: [] }>();
|
||||
|
||||
const isUpdate = ref(false);
|
||||
const title = computed(() => {
|
||||
return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
|
||||
});
|
||||
|
||||
const [BasicForm, formApi] = useVbenForm({
|
||||
commonConfig: {
|
||||
// 默认占满两列
|
||||
formItemClass: 'col-span-2',
|
||||
// 默认label宽度 px
|
||||
labelWidth: 80,
|
||||
// 通用配置项 会影响到所有表单项
|
||||
componentProps: {
|
||||
class: 'w-full',
|
||||
}
|
||||
},
|
||||
schema: modalSchema(),
|
||||
showDefaultActions: false,
|
||||
wrapperClass: 'grid-cols-2',
|
||||
});
|
||||
|
||||
const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
|
||||
{
|
||||
initializedGetter: defaultFormValueGetter(formApi),
|
||||
currentGetter: defaultFormValueGetter(formApi),
|
||||
},
|
||||
);
|
||||
|
||||
const [BasicModal, modalApi] = useVbenModal({
|
||||
// 在这里更改宽度
|
||||
class: 'w-[550px]',
|
||||
fullscreenButton: false,
|
||||
onBeforeClose,
|
||||
onClosed: handleClosed,
|
||||
onConfirm: handleConfirm,
|
||||
onOpenChange: async (isOpen) => {
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
}
|
||||
modalApi.modalLoading(true);
|
||||
|
||||
const { id } = modalApi.getData() as { id?: number | string };
|
||||
isUpdate.value = !!id;
|
||||
|
||||
if (isUpdate.value && id) {
|
||||
const record = await inspectionTaskInfo(id);
|
||||
await formApi.setValues(record);
|
||||
}
|
||||
await markInitialized();
|
||||
|
||||
modalApi.modalLoading(false);
|
||||
},
|
||||
});
|
||||
|
||||
async function handleConfirm() {
|
||||
try {
|
||||
modalApi.lock(true);
|
||||
const { valid } = await formApi.validate();
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
// getValues获取为一个readonly的对象 需要修改必须先深拷贝一次
|
||||
const data = cloneDeep(await formApi.getValues());
|
||||
await (isUpdate.value ? inspectionTaskUpdate(data) : inspectionTaskAdd(data));
|
||||
resetInitialized();
|
||||
emit('reload');
|
||||
modalApi.close();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
modalApi.lock(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleClosed() {
|
||||
await formApi.resetForm();
|
||||
resetInitialized();
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicModal :title="title">
|
||||
<BasicForm />
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
@@ -118,6 +118,7 @@ async function queryAddServices() {
|
||||
unit: item.unit,
|
||||
quantity: 0
|
||||
}))
|
||||
console.log(res,addServiceList.value);
|
||||
}
|
||||
|
||||
async function queryPersonData() {
|
||||
|
@@ -4,8 +4,6 @@
|
||||
<a-form
|
||||
:model="formState"
|
||||
layout="inline"
|
||||
@finish="onFinish"
|
||||
@finishFailed="onFinishFailed"
|
||||
class="form-box"
|
||||
>
|
||||
<a-form-item label="会议日期">
|
||||
@@ -80,6 +78,7 @@ const formState = reactive<FormState>({
|
||||
});
|
||||
const simpleImage = Empty.PRESENTED_IMAGE_SIMPLE;
|
||||
|
||||
const meetingList = ref<MeetVO[]>([])
|
||||
async function handleSearch() {
|
||||
let hours = '';
|
||||
if (formState.openHours && formState.openHours.length) {
|
||||
@@ -107,15 +106,6 @@ function handleAdd(id:string) {
|
||||
modalApi.setData({id});
|
||||
modalApi.open();
|
||||
}
|
||||
|
||||
const onFinish = (values: any) => {
|
||||
console.log('Success:', values);
|
||||
};
|
||||
const onFinishFailed = (errorInfo: any) => {
|
||||
console.log('Failed:', errorInfo);
|
||||
};
|
||||
|
||||
const meetingList = ref<MeetVO[]>([])
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
@@ -60,7 +60,8 @@ function generateWeekDates(): void {
|
||||
return startOfWeek.add(i, 'day').format('YYYY-MM-DD');
|
||||
});
|
||||
weekDates.value = dates;
|
||||
selectedDate.value = dates[0] ?? '';
|
||||
// 默认选中今天
|
||||
selectedDate.value = today.format('YYYY-MM-DD');
|
||||
}
|
||||
|
||||
// 获取预约数据
|
||||
@@ -137,7 +138,6 @@ async function fetchBookings(): Promise<void> {
|
||||
});
|
||||
bookingTable.value = table;
|
||||
}
|
||||
console.log(bookingTable.value,'bookingTable.value');
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取预约数据失败:', error);
|
||||
@@ -150,7 +150,8 @@ async function fetchBookings(): Promise<void> {
|
||||
function handleViewModeChange(e: RadioChangeEvent): void {
|
||||
viewMode.value = e.target.value;
|
||||
if (viewMode.value === 'date') {
|
||||
selectedDate.value = weekDates.value[0] ?? '';
|
||||
// 默认选中今天
|
||||
selectedDate.value = dayjs().format('YYYY-MM-DD');
|
||||
} else {
|
||||
selectedRoom.value = roomList.value[0]?.id ?? '';
|
||||
}
|
||||
|
1274
apps/web-antd/src/views/screen/digitalIntelligence/index.vue
Normal file
@@ -0,0 +1,890 @@
|
||||
<template>
|
||||
<div class="mian">
|
||||
<div class="title">
|
||||
<div class="left">
|
||||
<div class="left-first" id="time">--:--:--</div>
|
||||
<div class="left-second" id="date">----</div>
|
||||
</div>
|
||||
<div class="center">南川区综合服务中心数智管理平台能耗大屏</div>
|
||||
<div class="right">
|
||||
<div>{{ weekDay }}</div>
|
||||
<div>晴</div>
|
||||
<div>40℃</div>
|
||||
<div class="logout" @click="logout">
|
||||
<img src="../../../assets/return.png" style="width: 1.5rem; height: 1.5rem;">
|
||||
<div>
|
||||
退出
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header">
|
||||
<div class="header-item">
|
||||
<span class="header-label">今年用电量</span>
|
||||
<span class="header-value orange">180</span>
|
||||
<span class="header-unit">亿kwh</span>
|
||||
</div>
|
||||
<div class="header-item">
|
||||
<span class="header-label">本月用电总量</span>
|
||||
<span class="header-value green">1.8</span>
|
||||
<span class="header-unit">亿kwh</span>
|
||||
</div>
|
||||
<div class="header-item">
|
||||
<span class="header-label">今年用水总量</span>
|
||||
<span class="header-value blue">2600</span>
|
||||
<span class="header-unit">万吨</span>
|
||||
</div>
|
||||
<div class="header-item">
|
||||
<span class="header-label">本月用水总量</span>
|
||||
<span class="header-value purple">30</span>
|
||||
<span class="header-unit">万吨</span>
|
||||
</div>
|
||||
<div class="header-item">
|
||||
<span class="header-label">设备总数</span>
|
||||
<span class="header-value green">500</span>
|
||||
<span class="header-unit">台</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="contents">
|
||||
<div class="content">
|
||||
<div class="content-left">
|
||||
<div class="first">
|
||||
<div class="first-total">
|
||||
<div class="first-total-title">今日用电量</div>
|
||||
<div class="first-total-value">
|
||||
<div class="first-total-value-number">1</div>
|
||||
<div class="first-total-value-number">2</div>
|
||||
<div class="first-total-value-number">3</div>
|
||||
</div>
|
||||
<div class="first-total-unit">kwh</div>
|
||||
</div>
|
||||
<div ref="barChart" class="bar-chart" style="width:100%;height:80%;"></div>
|
||||
</div>
|
||||
<div class="second">
|
||||
<div ref="powerChart" class="power-chart"></div>
|
||||
</div>
|
||||
<div class="third">
|
||||
<div class="env-cards">
|
||||
<div class="env-card">
|
||||
<div class="env-card-content">
|
||||
<div class="env-title">PM2.5(μg/m³)</div>
|
||||
<div class="env-value">5</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="env-card">
|
||||
<div class="env-card-content">
|
||||
<div class="env-title">PM10(μg/m³)</div>
|
||||
<div class="env-value">120</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="env-card">
|
||||
<div class="env-card-content">
|
||||
<div class="env-title">噪声(dB(A))</div>
|
||||
<div class="env-value">50</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="env-card">
|
||||
<div class="env-card-content">
|
||||
<div class="env-title">一氧化碳(ppm)</div>
|
||||
<div class="env-value">10</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ref="envChart" class="env-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-center">
|
||||
<div class="content-center-first">
|
||||
<div class="first-item">
|
||||
<div class="item"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-center-second">
|
||||
<div class="second-item">
|
||||
<div class="second-item-text">645</div>
|
||||
<div class="second-item-text">729</div>
|
||||
<div class="second-item-text">648</div>
|
||||
<div class="second-item-text">786</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-right">
|
||||
<div class="first">
|
||||
<div class="first-total">
|
||||
<div class="first-total-title">今日用水量</div>
|
||||
<div class="first-total-value">
|
||||
<div class="first-total-value-number">1</div>
|
||||
<div class="first-total-value-number">2</div>
|
||||
<div class="first-total-value-number">3</div>
|
||||
</div>
|
||||
<div class="first-total-unit">吨</div>
|
||||
</div>
|
||||
<div ref="pie3dChart" class="pie3d-chart"></div>
|
||||
</div>
|
||||
<div class="second">
|
||||
<div ref="waterChart" class="water-chart"></div>
|
||||
</div>
|
||||
<div class="third">
|
||||
<div class="device-cards">
|
||||
<div class="device-card1">
|
||||
<div>
|
||||
<img src="../../../assets/energyConsumptionAnalysis/devices-number-icon.png" style="width: 1.75rem;height: 1.75rem;" alt="">
|
||||
</div>
|
||||
<div class="device-card-text-box">
|
||||
<div class="device-card-text">设备总数</div>
|
||||
<div class="device-card1-value">650</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="device-card2">
|
||||
<div>
|
||||
<img src="../../../assets/energyConsumptionAnalysis/devices-online-icon.png" style="width: 1.75rem;height: 1.75rem;" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<div class="device-card-text">设备在线数</div>
|
||||
<div class="device-card2-value">632</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="device-card3">
|
||||
<div>
|
||||
<img src="../../../assets/energyConsumptionAnalysis/devices-offline-icon.png" style="width: 1.75rem;height: 1.75rem;" alt="">
|
||||
</div>
|
||||
<div>
|
||||
<div class="device-card-text">设备离线数</div>
|
||||
<div class="device-card3-value">18</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ref="deviceChart" class="device-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import * as echarts from 'echarts'
|
||||
import 'echarts-gl'
|
||||
import { getThreeDBarOption } from '#/utils/threeDBarOption'
|
||||
import { renderPie3DChart } from '#/utils/pie3d'
|
||||
import { addChartToResizeManager, removeChartFromResizeManager } from '#/utils/echartsResize'
|
||||
|
||||
// 路由
|
||||
const router = useRouter()
|
||||
|
||||
// 图表实例
|
||||
const barChart = ref<HTMLElement>()
|
||||
const powerChart = ref<HTMLElement>()
|
||||
const envChart = ref<HTMLElement>()
|
||||
const waterChart = ref<HTMLElement>()
|
||||
const deviceChart = ref<HTMLElement>()
|
||||
const pie3dChart = ref<HTMLElement>()
|
||||
|
||||
// 定时器
|
||||
let timer: number | null = null
|
||||
|
||||
// 星期几
|
||||
const weekDay = ref('')
|
||||
|
||||
// 图表实例
|
||||
let barChartInstance: echarts.ECharts | null = null
|
||||
let powerChartInstance: echarts.ECharts | null = null
|
||||
let envChartInstance: echarts.ECharts | null = null
|
||||
let waterChartInstance: echarts.ECharts | null = null
|
||||
let deviceChartInstance: echarts.ECharts | null = null
|
||||
let pie3dChartInstance: any = null
|
||||
|
||||
// 退出方法
|
||||
const logout = () => {
|
||||
router.push('/navigation')
|
||||
}
|
||||
|
||||
// 更新时间
|
||||
const updateTime = () => {
|
||||
const now = new Date()
|
||||
const time = now.toLocaleTimeString('zh-CN', { hour12: false })
|
||||
const date = now.getFullYear() + '.' +
|
||||
String(now.getMonth() + 1).padStart(2, '0') + '.' +
|
||||
String(now.getDate()).padStart(2, '0')
|
||||
|
||||
// 获取星期几
|
||||
const weekDays = ['日', '一', '二', '三', '四', '五', '六']
|
||||
weekDay.value = '星期' + weekDays[now.getDay()]
|
||||
|
||||
const timeElement = document.getElementById('time')
|
||||
const dateElement = document.getElementById('date')
|
||||
|
||||
if (timeElement) timeElement.innerText = time
|
||||
if (dateElement) dateElement.innerText = date
|
||||
}
|
||||
|
||||
// 初始化柱状图
|
||||
const initBarChart = () => {
|
||||
if (!barChart.value) return
|
||||
|
||||
const chart = echarts.init(barChart.value)
|
||||
const option = getThreeDBarOption({
|
||||
xData: ['A区', 'B区', 'C区', 'D区'],
|
||||
yData: [320, 452, 688, 400]
|
||||
})
|
||||
chart.setOption(option)
|
||||
barChartInstance = chart
|
||||
addChartToResizeManager(chart)
|
||||
}
|
||||
|
||||
// 初始化电力图表
|
||||
const initPowerChart = () => {
|
||||
if (!powerChart.value) return
|
||||
|
||||
const chart = echarts.init(powerChart.value)
|
||||
const option = {
|
||||
tooltip: { trigger: 'axis' },
|
||||
grid: { left: 40, right: 20, top: 40, bottom: 30 },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: Array.from({length: 19}, (_, i) => i + 6),
|
||||
axisLine: { lineStyle: { color: '#3ec6ff' } },
|
||||
axisLabel: { color: '#fff' }
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: '',
|
||||
axisLine: { lineStyle: { color: '#3ec6ff' } },
|
||||
axisLabel: { color: '#fff' },
|
||||
splitLine: { lineStyle: { color: '#1e90ff22' } }
|
||||
},
|
||||
series: [{
|
||||
data: [80, 120, 100, 130, 150, 180, 200, 220, 250, 285, 230, 200, 180, 150, 120, 100, 80, 60, 40],
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
symbol: 'circle',
|
||||
symbolSize: 0,
|
||||
itemStyle: { color: '#3ec6ff' },
|
||||
lineStyle: { width: 1 },
|
||||
areaStyle: { color: new echarts.graphic.LinearGradient(
|
||||
0, 0, 0, 1, // 上→下
|
||||
[
|
||||
{ offset: 0, color: '#32B7E9' },
|
||||
{ offset: 1, color: 'rgba(50,183,233,0)' }
|
||||
]
|
||||
), }
|
||||
}]
|
||||
}
|
||||
chart.setOption(option)
|
||||
powerChartInstance = chart
|
||||
addChartToResizeManager(chart)
|
||||
}
|
||||
|
||||
// 初始化环境图表
|
||||
const initEnvChart = () => {
|
||||
if (!envChart.value) return
|
||||
|
||||
const chart = echarts.init(envChart.value)
|
||||
const option = {
|
||||
tooltip: { trigger: 'axis' },
|
||||
grid: { left: 40, right: 20, top: 10, bottom: 20 },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: Array.from({length: 8}, (_, i) => (i+1)*3),
|
||||
axisLine: { lineStyle: { color: '#3ec6ff' } },
|
||||
axisLabel: { color: '#fff' }
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLine: { lineStyle: { color: '#3ec6ff' } },
|
||||
axisLabel: { color: '#fff' },
|
||||
splitLine: { lineStyle: { color: '#1e90ff22' } }
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '今年',
|
||||
data: [100, 200, 150, 300, 250, 200, 100, 80],
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
itemStyle: { color: '#b388ff' },
|
||||
lineStyle: { width: 3 },
|
||||
areaStyle: { color: 'rgba(179,136,255,0.2)' },
|
||||
symbol: 'circle',
|
||||
symbolSize: 0,
|
||||
},
|
||||
{
|
||||
name: '去年',
|
||||
data: [80, 120, 100, 180, 150, 120, 60, 40],
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
itemStyle: { color: '#ffb300' },
|
||||
lineStyle: { width: 3 },
|
||||
areaStyle: { color: 'rgba(255,179,0,0.15)' },
|
||||
symbol: 'circle',
|
||||
symbolSize: 0,
|
||||
}
|
||||
]
|
||||
}
|
||||
chart.setOption(option)
|
||||
envChartInstance = chart
|
||||
addChartToResizeManager(chart)
|
||||
}
|
||||
|
||||
// 初始化水表图表
|
||||
const initWaterChart = () => {
|
||||
if (!waterChart.value) return
|
||||
|
||||
const chart = echarts.init(waterChart.value)
|
||||
const option = {
|
||||
tooltip: { trigger: 'axis' },
|
||||
legend: {
|
||||
data: ['今日', '平均'],
|
||||
textStyle: { color: '#fff' },
|
||||
right: 20,
|
||||
top: 10,
|
||||
bottom: 10
|
||||
},
|
||||
grid: { left: 40, right: 20, top: 40, bottom: 30 },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: Array.from({length: 19}, (_, i) => i + 6),
|
||||
axisLine: { lineStyle: { color: '#3ec6ff' } },
|
||||
axisLabel: { color: '#fff' }
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLine: { lineStyle: { color: '#3ec6ff' } },
|
||||
axisLabel: { color: '#fff' },
|
||||
splitLine: { lineStyle: { color: '#1e90ff22' } }
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '今日',
|
||||
data: [1.2, 2.1, 1.8, 2.5, 3.0, 3.8, 4.2, 4.5, 4.8, 4.8, 4.0, 3.2, 2.5, 2.0, 1.5, 1.0, 0.8, 0.5, 0.2],
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
symbol: 'circle',
|
||||
symbolSize: 0,
|
||||
itemStyle: { color: '#3ec6ff' },
|
||||
lineStyle: { width: 1 },
|
||||
areaStyle: { color: new echarts.graphic.LinearGradient(
|
||||
0, 0, 0, 1, // 上→下
|
||||
[
|
||||
{ offset: 0, color: '#32B7E9' },
|
||||
{ offset: 1, color: 'rgba(50,183,233,0)' }
|
||||
]
|
||||
), }
|
||||
},
|
||||
{
|
||||
name: '平均',
|
||||
data: Array(19).fill(2.5),
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
symbol: 'none',
|
||||
itemStyle: { color: '#ff6b00' },
|
||||
lineStyle: { width: 1, type: 'solid', color: '#ff6b00' }
|
||||
}
|
||||
]
|
||||
}
|
||||
chart.setOption(option)
|
||||
waterChartInstance = chart
|
||||
addChartToResizeManager(chart)
|
||||
}
|
||||
|
||||
// 初始化设备图表
|
||||
const initDeviceChart = () => {
|
||||
if (!deviceChart.value) return
|
||||
|
||||
const chart = echarts.init(deviceChart.value)
|
||||
const option = {
|
||||
grid: { left: 60, right: 40, top: 10, bottom: 30 },
|
||||
xAxis: {
|
||||
type: 'value',
|
||||
axisLine: { lineStyle: { color: '#8697BA' } },
|
||||
axisLabel: { color: '#fff' },
|
||||
splitLine: { show: false }
|
||||
},
|
||||
yAxis: {
|
||||
type: 'category',
|
||||
data: ['门禁', '监控', '水表'],
|
||||
axisLine: { lineStyle: { color: '#8697BA' } },
|
||||
axisLabel: { color: '#A1B2C2' }
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '设备数',
|
||||
type: 'bar',
|
||||
data: [650, 120, 40],
|
||||
barWidth: 12,
|
||||
itemStyle: {
|
||||
color: function(params: any) {
|
||||
const colors = [
|
||||
new echarts.graphic.LinearGradient(
|
||||
0, 0, 0, 1, // 上→下
|
||||
[
|
||||
{ offset: 0, color: '#2986B1' },
|
||||
{ offset: 1, color: '#6941FF' }
|
||||
]
|
||||
),
|
||||
new echarts.graphic.LinearGradient(
|
||||
0, 0, 0, 1, // 上→下
|
||||
[
|
||||
{ offset: 0, color: '#33FF99' },
|
||||
{ offset: 1, color: '#00908E' }
|
||||
]
|
||||
),
|
||||
new echarts.graphic.LinearGradient(
|
||||
0, 0, 0, 1, // 上→下
|
||||
[
|
||||
{ offset: 0, color: '#01B4FF' },
|
||||
{ offset: 1, color: '#0336FF' }
|
||||
]
|
||||
),
|
||||
];
|
||||
return colors[params.dataIndex]
|
||||
}
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'right',
|
||||
color: '#fff'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
chart.setOption(option)
|
||||
deviceChartInstance = chart
|
||||
addChartToResizeManager(chart)
|
||||
}
|
||||
|
||||
// 初始化3D饼图
|
||||
const initPie3DChart = () => {
|
||||
if (!pie3dChart.value) return
|
||||
|
||||
pie3dChartInstance = renderPie3DChart(pie3dChart.value, {
|
||||
data: [
|
||||
{ name: 'A区域', value: 20, itemStyle: { color: '#3ffbff' } },
|
||||
{ name: 'D区域', value: 20, itemStyle: { color: '#b388ff' } },
|
||||
{ name: 'C区域', value: 45, itemStyle: { color: '#ff9900' } },
|
||||
{ name: 'B区域', value: 15, itemStyle: { color: '#3f6bff' } },
|
||||
],
|
||||
hoverHeightScale: 2,
|
||||
selectOffset: 0.1,
|
||||
distance: 220,
|
||||
boxHeight: 5
|
||||
})
|
||||
if (pie3dChartInstance) {
|
||||
addChartToResizeManager(pie3dChartInstance)
|
||||
}
|
||||
}
|
||||
|
||||
// 组件挂载时初始化
|
||||
onMounted(() => {
|
||||
updateTime()
|
||||
timer = setInterval(updateTime, 1000)
|
||||
initBarChart()
|
||||
initPowerChart()
|
||||
initEnvChart()
|
||||
initWaterChart()
|
||||
initDeviceChart()
|
||||
initPie3DChart()
|
||||
})
|
||||
|
||||
// 组件卸载时清理
|
||||
onBeforeUnmount(() => {
|
||||
if (timer) {
|
||||
clearInterval(timer)
|
||||
}
|
||||
|
||||
// 从管理器中移除图表
|
||||
if (barChartInstance) {
|
||||
removeChartFromResizeManager(barChartInstance)
|
||||
barChartInstance.dispose()
|
||||
}
|
||||
if (powerChartInstance) {
|
||||
removeChartFromResizeManager(powerChartInstance)
|
||||
powerChartInstance.dispose()
|
||||
}
|
||||
if (envChartInstance) {
|
||||
removeChartFromResizeManager(envChartInstance)
|
||||
envChartInstance.dispose()
|
||||
}
|
||||
if (waterChartInstance) {
|
||||
removeChartFromResizeManager(waterChartInstance)
|
||||
waterChartInstance.dispose()
|
||||
}
|
||||
if (deviceChartInstance) {
|
||||
removeChartFromResizeManager(deviceChartInstance)
|
||||
deviceChartInstance.dispose()
|
||||
}
|
||||
if (pie3dChartInstance) {
|
||||
removeChartFromResizeManager(pie3dChartInstance)
|
||||
pie3dChartInstance.dispose()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.mian{
|
||||
height: 100vh;
|
||||
background: url("../../../assets/energyConsumptionAnalysis/bg.png");
|
||||
background-size: 100% 100%;
|
||||
background-color: #081b3a;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.title {
|
||||
height: 5.375rem;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.left{
|
||||
display: flex;
|
||||
width: 14.3125rem;
|
||||
.left-first{
|
||||
padding-left: 2.3125rem;
|
||||
padding-right: 3.5rem;
|
||||
font-size: 1.875rem;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
.left-second{
|
||||
width: 6.5rem;
|
||||
font-family: ShiShangZhongHeiJianTi;
|
||||
font-weight: 400;
|
||||
font-size: 1.25rem;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
.center{
|
||||
font-size: 1.9rem;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
letter-spacing: 0.1em;
|
||||
text-shadow: 0 0 10px #1e90ff, 0 0 20px #1e90ff;
|
||||
}
|
||||
.right{
|
||||
width: 17.3125rem;
|
||||
display: flex;
|
||||
font-family: ShiShangZhongHeiJianTi;
|
||||
font-weight: 400;
|
||||
font-size: 1.25rem;
|
||||
color: #FFFFFF;
|
||||
gap: .75rem;
|
||||
.logout{
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
gap: .2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
.header{
|
||||
/* margin-top: 1.125rem; */
|
||||
margin-left: 4.625rem;
|
||||
margin-right: 4.25rem;
|
||||
height: 4.4rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.header-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 1.5rem;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 0 10px #0ff2, 0 0 20px #0ff2 inset;
|
||||
}
|
||||
.header-label {
|
||||
color: #fff;
|
||||
font-size: 1rem;
|
||||
margin-right: 0.5rem;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.header-value {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
margin: 0 0.2rem;
|
||||
}
|
||||
|
||||
.header-value.orange { color: #ffb300; }
|
||||
.header-value.green { color: #00ffb0; }
|
||||
.header-value.blue { color: #3ec6ff; }
|
||||
.header-value.purple { color: #b388ff; }
|
||||
|
||||
.header-unit {
|
||||
color: #fff;
|
||||
font-size: 1rem;
|
||||
margin-left: 0.2rem;
|
||||
}
|
||||
}
|
||||
.header div{
|
||||
width: 20.125rem;
|
||||
}
|
||||
.content{
|
||||
flex:1;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 0 2.25rem 2.25rem 2.25rem;
|
||||
.content-left{
|
||||
width: 32.6875rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
.first{
|
||||
height: 13.9rem;
|
||||
.first-total{
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
padding: 1rem 1rem 0 0;
|
||||
font-size: 1.12rem;
|
||||
color: #89EAFF;
|
||||
.first-total-title{
|
||||
font-family: Microsoft YaHei;
|
||||
font-weight: 400;
|
||||
font-size: 1.12rem;
|
||||
line-height: 1rem;
|
||||
}
|
||||
.first-total-value{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.first-total-value-number{
|
||||
font-family: Microsoft YaHei;
|
||||
font-weight: bold;
|
||||
font-size: 1.3rem;
|
||||
color: #89EAFF;
|
||||
line-height: 1rem;
|
||||
padding: .3rem;
|
||||
margin: 0 .1rem;
|
||||
border: .02rem solid rgba(99,145,180,0.59);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.second{
|
||||
height: 12.5rem;
|
||||
/* margin-top:2.25rem;
|
||||
margin-bottom: 2rem; */
|
||||
.power-chart {
|
||||
height: 100%;
|
||||
margin-top: 0.2rem;
|
||||
}
|
||||
}
|
||||
.third{
|
||||
height: 16rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* justify-content: space-around; */
|
||||
.env-cards {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 5rem;
|
||||
margin-left: 1rem;
|
||||
margin-right: 1.1rem;
|
||||
.env-card {
|
||||
width: 6.9rem;
|
||||
height: 3.2rem;
|
||||
border-radius: 0.5rem;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
.env-card-content{
|
||||
.env-title {
|
||||
font-size: .9rem;
|
||||
font-weight: 400;
|
||||
color: #4CE2D1;
|
||||
}
|
||||
.env-value {
|
||||
font-size: .8rem;
|
||||
font-weight: bold;
|
||||
font-family: ShiShangZhongHeiJianTi;
|
||||
font-weight: 400;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.env-chart {
|
||||
height: 8rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
.content-center{
|
||||
width: 47.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
.content-center-first{
|
||||
height: 31.9rem;
|
||||
.first-item{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: url("../../../assets/energyConsumptionAnalysis/center-bg.png");
|
||||
background-size: 95% 95%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
}
|
||||
.content-center-second{
|
||||
height: 12.5rem;
|
||||
.second-item{
|
||||
margin-top: 6rem;
|
||||
margin-left: 3.68rem;
|
||||
margin-bottom: 6.5rem;
|
||||
margin-right: 4.9rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.second-item-text{
|
||||
width: 5.37rem;
|
||||
font-family: ShiShangZhongHeiJianTi;
|
||||
font-weight: 400;
|
||||
font-size: 1.37rem;
|
||||
color: #FFFFFF;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.content-right{
|
||||
width: 32.68rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
.first{
|
||||
height: 14.9rem;
|
||||
.first-total{
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
padding: 1rem 1rem 0 0;
|
||||
font-size: 1.12rem;
|
||||
color: #89EAFF;
|
||||
.first-total-title{
|
||||
font-family: Microsoft YaHei;
|
||||
font-weight: 400;
|
||||
font-size: 1.12rem;
|
||||
line-height: 1rem;
|
||||
}
|
||||
.first-total-value{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.first-total-value-number{
|
||||
font-family: Microsoft YaHei;
|
||||
font-weight: bold;
|
||||
font-size: 1.3rem;
|
||||
color: #89EAFF;
|
||||
line-height: 1rem;
|
||||
padding: .3rem;
|
||||
margin: 0 .1rem;
|
||||
border: .02rem solid rgba(99,145,180,0.59);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.second{
|
||||
height: 12.5rem;
|
||||
/* margin-top:2.25rem;
|
||||
margin-bottom: 2rem; */
|
||||
.water-chart {
|
||||
height: 100%;
|
||||
margin-top: 0.2rem;
|
||||
}
|
||||
}
|
||||
.third{
|
||||
height: 14rem;
|
||||
.device-cards {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 2rem;
|
||||
margin-right: 1.06rem;
|
||||
/* margin-bottom: 0.5rem; */
|
||||
margin-left: 1.31rem;
|
||||
.device-card1{
|
||||
height: 3.2rem;
|
||||
width: 7.21rem;
|
||||
background: url("../../../assets/energyConsumptionAnalysis/devices-number.png");
|
||||
background-size: 100% 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.device-card1-value{
|
||||
font-family: Arial;
|
||||
font-weight: bold;
|
||||
font-size: 1.25rem;
|
||||
color: #02B3F4;
|
||||
}
|
||||
}
|
||||
.device-card2{
|
||||
height: 3.2rem;
|
||||
width: 7.21rem;
|
||||
background: url("../../../assets/energyConsumptionAnalysis/devices-online.png");
|
||||
background-size: 100% 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.device-card2-value{
|
||||
font-family: Arial;
|
||||
font-weight: bold;
|
||||
font-size: 1.25rem;
|
||||
color: #1DE39D;
|
||||
}
|
||||
}
|
||||
.device-card3{
|
||||
height: 3.2rem;
|
||||
width: 7.21rem;
|
||||
background: url("../../../assets/energyConsumptionAnalysis/devices-offline.png");
|
||||
background-size: 100% 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.device-card3-value{
|
||||
font-family: Arial;
|
||||
font-weight: bold;
|
||||
font-size: 1.25rem;
|
||||
color: #F19315;
|
||||
}
|
||||
}
|
||||
.device-card-text{
|
||||
font-family: Microsoft YaHei UI;
|
||||
font-weight: 400;
|
||||
font-size: 0.75rem;
|
||||
color: #A1B2C2;
|
||||
line-height: 0.75rem;
|
||||
}
|
||||
}
|
||||
.device-chart {
|
||||
height: 8rem;
|
||||
/* margin-top: 0.2rem; */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.pie3d-title {
|
||||
color: #fff;
|
||||
font-size: 1.1rem;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
.pie3d-water {
|
||||
color: #fff;
|
||||
font-size: 0.95rem;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
.pie3d-water-num {
|
||||
font-size: 1.3rem;
|
||||
color: #3ec6ff;
|
||||
background: #0a1e3a;
|
||||
border-radius: 0.2rem;
|
||||
padding: 0 0.2rem;
|
||||
margin: 0 0.2rem;
|
||||
letter-spacing: 0.1em;
|
||||
}
|
||||
.pie3d-chart {
|
||||
width: 100%;
|
||||
height: 176px;
|
||||
min-height: unset;
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
1283
apps/web-antd/src/views/screen/monitor/index.vue
Normal file
307
apps/web-antd/src/views/screen/navigation/Navigation.vue
Normal file
@@ -0,0 +1,307 @@
|
||||
<template>
|
||||
<div class="navigation-bg">
|
||||
<div class="navigation-head">
|
||||
<div class="navigation-head-left">超级管理员 欢迎你</div>
|
||||
<div class="navigation-head-center">南川区综合服务中心数智平台</div>
|
||||
<div class="navigation-head-right" @click="logout">
|
||||
<span>
|
||||
<!-- <img src="../../../assets/return.png" alt="退出"> -->
|
||||
退出
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navigation-body">
|
||||
<div class="navigation-body-left">
|
||||
<div @click="goToProperty()">基础物业</div>
|
||||
<div @click="goToEnergyAnalysis()">能耗分析</div>
|
||||
<div @click="goToSecurity()">安防大屏</div>
|
||||
<div @click="goToMonitor()">监控大屏</div>
|
||||
</div>
|
||||
<div class="navigation-body-center">
|
||||
<div class="top-content">
|
||||
<div class="top-content-text1"><div class="text1">数据管理</div></div>
|
||||
<div class="top-content-text2"><div class="text1">运行监控</div></div>
|
||||
<div class="top-content-text3"><div class="text1">信息管理</div></div>
|
||||
<div class="top-content-text4"><div class="text1">配置管理</div></div>
|
||||
<div class="top-content-text5"><div class="text1">登录管理</div></div>
|
||||
<div class="top-content-text6"><div class="text1">驾驶舱</div></div>
|
||||
</div>
|
||||
<div class="bottom-content">
|
||||
<div class="bottom-content-text1"><div class="text">数字建模</div></div>
|
||||
<div class="bottom-content-text2"><div class="text">指挥中心</div></div>
|
||||
<div class="bottom-content-text3"><div class="text">软件支撑</div></div>
|
||||
<div class="bottom-content-text4"><div class="text">应用管理</div></div>
|
||||
<div class="bottom-content-text5"><div class="text">数据管理</div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navigation-body-right">
|
||||
<div @click="goToDigitalIntelligence()">商务中心</div>
|
||||
<div @click="goToHome()">后台管理</div>
|
||||
<div>能源管理</div>
|
||||
<div>能耗分析</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from 'vue-router'
|
||||
import { preferences } from '@vben/preferences';
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
// 退出方法
|
||||
const logout = () => {
|
||||
// 这里可以添加清除 token、重定向登录页等逻辑
|
||||
console.log('用户退出')
|
||||
router.push('/login') // 假设登录页面路径为 /login
|
||||
}
|
||||
//物业
|
||||
const goToProperty = () => {
|
||||
router.push('/property')
|
||||
}
|
||||
//能耗分析
|
||||
const goToEnergyAnalysis = () => {
|
||||
router.push('/energyAnalysis')
|
||||
}
|
||||
// 监控大屏
|
||||
const goToSecurity = () => {
|
||||
router.push('/security')
|
||||
}
|
||||
// 监控大屏
|
||||
const goToMonitor = () => {
|
||||
router.push('/monitor')
|
||||
}
|
||||
// 商务中心数智管理平台
|
||||
const goToDigitalIntelligence = () => {
|
||||
router.push('/digitalIntelligence')
|
||||
}
|
||||
//
|
||||
const goToHome = () => {
|
||||
router.push(preferences.app.defaultHomePath);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.navigation-bg {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
text-align: center;
|
||||
background: url("../../../assets/navigation.png");
|
||||
background-size: 100% 100%;
|
||||
color: #fff;
|
||||
text-shadow: 0 0.125rem 0.5rem #000;
|
||||
font-family: Arial, sans-serif;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.navigation-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
height: 3.5rem;
|
||||
}
|
||||
|
||||
.navigation-head-center{
|
||||
font-size: 1.9rem;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
letter-spacing: 0.1em;
|
||||
}
|
||||
.navigation-head-left,
|
||||
.navigation-head-right {
|
||||
flex: 1 1 100%;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
padding-left: 1.3rem;
|
||||
padding-right: 1.3rem;
|
||||
}
|
||||
|
||||
@media (min-width: 48em) {
|
||||
.navigation-head-left {
|
||||
flex: 1;
|
||||
text-align: left;
|
||||
font-size: 0.875rem;
|
||||
padding-left: 1.3rem;
|
||||
}
|
||||
.navigation-head-center {
|
||||
flex: 3;
|
||||
font-size: 1.5rem;
|
||||
text-align: center;
|
||||
}
|
||||
.navigation-head-right {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
font-size: 0.875rem;
|
||||
padding-right: 1.3rem;
|
||||
}
|
||||
}
|
||||
|
||||
.navigation-body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.navigation-body-left {
|
||||
width: 12%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
padding: 2.25rem 1.25rem;
|
||||
height: 35rem;
|
||||
}
|
||||
|
||||
.navigation-body-left div {
|
||||
background: url("../../../assets/shine.png") no-repeat center;
|
||||
background-size: contain;
|
||||
font-size: 1rem;
|
||||
padding: 0.625rem 1.25rem;
|
||||
min-width: 7.5rem;
|
||||
max-width: 100%;
|
||||
transition: transform 0.2s ease;
|
||||
cursor: pointer;
|
||||
color: #77DAFF;
|
||||
}
|
||||
.navigation-body-left div:hover {
|
||||
color: #ffffff;
|
||||
background-image: url("../../../assets/shine-lines.png");
|
||||
}
|
||||
|
||||
.navigation-body-center{
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.top-content{
|
||||
height: 70%;
|
||||
padding-top: 26rem;
|
||||
padding-left: 19.5rem;
|
||||
padding-right: 20rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.top-content-text1{
|
||||
font-size: 1.0625rem;
|
||||
width: 4.6875rem;
|
||||
height: 7.5rem;
|
||||
padding-top: 0.5rem;
|
||||
color: #86B6E6;
|
||||
cursor: pointer;
|
||||
}
|
||||
.top-content-text2{
|
||||
font-size: 1.0625rem;
|
||||
font-weight: 600;
|
||||
width: 4.6875rem;
|
||||
height: 7.5rem;
|
||||
padding-top: 1.25rem;
|
||||
color: #86ECDE;
|
||||
cursor: pointer;
|
||||
}
|
||||
.top-content-text3{
|
||||
font-size: 1.0625rem;
|
||||
font-weight: 600;
|
||||
width: 4.6875rem;
|
||||
height: 7.5rem;
|
||||
padding-top: 2.5rem;
|
||||
color: #FECFB4;
|
||||
cursor: pointer;
|
||||
}
|
||||
.top-content-text4{
|
||||
font-size: 1.0625rem;
|
||||
font-weight: 600;
|
||||
width: 4.6875rem;
|
||||
height: 7.5rem;
|
||||
padding-top: 2.625rem;
|
||||
color: #CDADF4;
|
||||
cursor: pointer;
|
||||
}
|
||||
.top-content-text5{
|
||||
font-size: 1.0625rem;
|
||||
font-weight: 600;
|
||||
width: 4.6875rem;
|
||||
height: 7.5rem;
|
||||
padding-top: 1.5625rem;
|
||||
color: #86ECDE;
|
||||
cursor: pointer;
|
||||
}
|
||||
.top-content-text6{
|
||||
font-size: 1.0625rem;
|
||||
font-weight: 600;
|
||||
width: 4.6875rem;
|
||||
height: 7.5rem;
|
||||
padding-top: 1.25rem;
|
||||
color: #86B6E6;
|
||||
cursor: pointer;
|
||||
}
|
||||
.text1{
|
||||
padding: 0.3125rem 1.875rem;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-content{
|
||||
height: 50%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding-top: 12.5rem;
|
||||
padding-left: 23.625rem;
|
||||
padding-right: 24.25rem;
|
||||
font-size: 1rem;
|
||||
color: #00EEFD;
|
||||
.bottom-content-text1{
|
||||
width: 6.875rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
.bottom-content-text2{
|
||||
padding-top: 0.75rem;
|
||||
width: 6.875rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
.bottom-content-text3{
|
||||
padding-top: 1.125rem;
|
||||
width: 6.875rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
.bottom-content-text4{
|
||||
padding-top: 0.8125rem;
|
||||
width: 6.875rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
.bottom-content-text5{
|
||||
width: 6.875rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
.text{
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
.navigation-body-right{
|
||||
width: 12%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
padding: 2.25rem 1.25rem;
|
||||
height: 35rem;
|
||||
}
|
||||
.navigation-body-right div {
|
||||
background: url("../../../assets/shine.png") no-repeat center;
|
||||
background-size: contain;
|
||||
font-size: 1rem;
|
||||
padding: 0.625rem 1.25rem;
|
||||
min-width: 7.5rem;
|
||||
max-width: 100%;
|
||||
transition: transform 0.2s ease;
|
||||
cursor: pointer;
|
||||
color: #77DAFF;
|
||||
}
|
||||
.navigation-body-right div:hover {
|
||||
background-image: url("../../../assets/shine-lines.png");
|
||||
color: #ffffff;
|
||||
}
|
||||
</style>
|
804
apps/web-antd/src/views/screen/property/index.vue
Normal file
@@ -0,0 +1,804 @@
|
||||
<template>
|
||||
<div class="mian">
|
||||
<div class="title">
|
||||
<div class="left">
|
||||
<div class="left-first" id="time">--:--:--</div>
|
||||
<div class="left-second" id="date">----</div>
|
||||
</div>
|
||||
<div class="center">南川区综合服务中心数智管理平台物业大屏</div>
|
||||
<div class="right">
|
||||
<div>{{ weekDay }}</div>
|
||||
<div>晴</div>
|
||||
<div>40℃</div>
|
||||
<div class="logout" @click="logout">
|
||||
<img src="../../../assets/return.png" style="width: 1.5rem; height: 1.5rem;">
|
||||
<div>
|
||||
退出
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header">
|
||||
<div class="header-item">
|
||||
<span class="header-label">今年用电量</span>
|
||||
<span class="header-value orange">180</span>
|
||||
<span class="header-unit">亿kwh</span>
|
||||
</div>
|
||||
<div class="header-item">
|
||||
<span class="header-label">本月用电总量</span>
|
||||
<span class="header-value green">1.8</span>
|
||||
<span class="header-unit">亿kwh</span>
|
||||
</div>
|
||||
<div class="header-item">
|
||||
<span class="header-label">今年用水总量</span>
|
||||
<span class="header-value blue">2600</span>
|
||||
<span class="header-unit">万吨</span>
|
||||
</div>
|
||||
<div class="header-item">
|
||||
<span class="header-label">本月用水总量</span>
|
||||
<span class="header-value purple">30</span>
|
||||
<span class="header-unit">万吨</span>
|
||||
</div>
|
||||
<div class="header-item">
|
||||
<span class="header-label">设备总数</span>
|
||||
<span class="header-value green">500</span>
|
||||
<span class="header-unit">台</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="contents">
|
||||
<div class="content">
|
||||
<div class="content-left">
|
||||
<div class="first">
|
||||
<div ref="barChart" class="bar-chart" style="width:100%;height:100%;"></div>
|
||||
</div>
|
||||
<div class="second">
|
||||
<div ref="powerChart" class="power-chart"></div>
|
||||
</div>
|
||||
<div class="third">
|
||||
<div ref="envChart" class="env-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-center">
|
||||
<div class="content-center-first">
|
||||
<div class="first-item">
|
||||
<div class="item"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-center-second">
|
||||
<div class="second-item">
|
||||
<div class="second-item-box1">645</div>
|
||||
<div class="second-item-box2">729</div>
|
||||
<div class="second-item-box3">648</div>
|
||||
<div class="second-item-box4">786</div>
|
||||
<div class="second-item-box5">645</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-right">
|
||||
<div class="first">
|
||||
<div ref="waterChart" class="water-chart"></div>
|
||||
<!-- <div ref="pie3dChart" class="pie3d-chart"></div> -->
|
||||
</div>
|
||||
<div class="second">
|
||||
<div class="second-box">
|
||||
<div class="box-content">
|
||||
<div class="box-content-label">服务数量</div>
|
||||
<div class="box-content-num">132</div>
|
||||
</div>
|
||||
<div class="box-content">
|
||||
<div class="box-content-label">服务数量</div>
|
||||
<div class="box-content-num">862</div>
|
||||
</div>
|
||||
<div class="box-content">
|
||||
<div class="box-content-label">服务数量</div>
|
||||
<div class="box-content-num">272</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div ref="waterChart" class="water-chart"></div> -->
|
||||
</div>
|
||||
<div class="third">
|
||||
<div ref="deviceChart" class="device-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import * as echarts from 'echarts'
|
||||
import 'echarts-gl'
|
||||
import { getThreeDBarOption } from '#/utils/threeDBarOption'
|
||||
import { renderPie3DChart } from '#/utils/pie3d'
|
||||
import { addChartToResizeManager, removeChartFromResizeManager } from '#/utils/echartsResize'
|
||||
|
||||
// 路由
|
||||
const router = useRouter()
|
||||
|
||||
// 图表实例
|
||||
const barChart = ref<HTMLElement>()
|
||||
const powerChart = ref<HTMLElement>()
|
||||
const envChart = ref<HTMLElement>()
|
||||
const waterChart = ref<HTMLElement>()
|
||||
const deviceChart = ref<HTMLElement>()
|
||||
const pie3dChart = ref<HTMLElement>()
|
||||
|
||||
// 定时器
|
||||
let timer: number | null = null
|
||||
|
||||
// 星期几
|
||||
const weekDay = ref('')
|
||||
|
||||
// 图表实例
|
||||
let barChartInstance: echarts.ECharts | null = null
|
||||
let powerChartInstance: echarts.ECharts | null = null
|
||||
let envChartInstance: echarts.ECharts | null = null
|
||||
let waterChartInstance: echarts.ECharts | null = null
|
||||
let deviceChartInstance: echarts.ECharts | null = null
|
||||
let pie3dChartInstance: any = null
|
||||
|
||||
// 退出方法
|
||||
const logout = () => {
|
||||
router.push('/navigation')
|
||||
}
|
||||
|
||||
// 更新时间
|
||||
const updateTime = () => {
|
||||
const now = new Date()
|
||||
const time = now.toLocaleTimeString('zh-CN', { hour12: false })
|
||||
const date = now.getFullYear() + '.' +
|
||||
String(now.getMonth() + 1).padStart(2, '0') + '.' +
|
||||
String(now.getDate()).padStart(2, '0')
|
||||
|
||||
// 获取星期几
|
||||
const weekDays = ['日', '一', '二', '三', '四', '五', '六']
|
||||
weekDay.value = '星期' + weekDays[now.getDay()]
|
||||
|
||||
const timeElement = document.getElementById('time')
|
||||
const dateElement = document.getElementById('date')
|
||||
|
||||
if (timeElement) timeElement.innerText = time
|
||||
if (dateElement) dateElement.innerText = date
|
||||
}
|
||||
|
||||
// 初始化柱状图
|
||||
const initBarChart = () => {
|
||||
if (!barChart.value) return
|
||||
|
||||
const chart = echarts.init(barChart.value)
|
||||
const option = getThreeDBarOption({
|
||||
xData: ['A区', 'B区', 'C区', 'D区'],
|
||||
yData: [320, 452, 688, 400]
|
||||
})
|
||||
chart.setOption(option)
|
||||
barChartInstance = chart
|
||||
addChartToResizeManager(chart)
|
||||
}
|
||||
|
||||
// 初始化电力图表
|
||||
const initPowerChart = () => {
|
||||
if (!powerChart.value) return
|
||||
|
||||
const chart = echarts.init(powerChart.value)
|
||||
const option = {
|
||||
tooltip: { trigger: 'axis' },
|
||||
grid: { left: 40, right: 20, top: 32, bottom: 20 },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: Array.from({length: 19}, (_, i) => i + 6),
|
||||
axisLine: { lineStyle: { color: '#3ec6ff' } },
|
||||
axisLabel: { color: '#fff' }
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: '',
|
||||
axisLine: { lineStyle: { color: '#3ec6ff' } },
|
||||
axisLabel: { color: '#fff' },
|
||||
splitLine: { lineStyle: { color: '#1e90ff22' } }
|
||||
},
|
||||
series: [{
|
||||
data: [80, 120, 100, 130, 150, 180, 200, 220, 250, 285, 230, 200, 180, 150, 120, 100, 80, 60, 40],
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
symbol: 'circle',
|
||||
symbolSize: 0,
|
||||
itemStyle: { color: '#3ec6ff' },
|
||||
lineStyle: { width: 1 },
|
||||
areaStyle: { color: new echarts.graphic.LinearGradient(
|
||||
0, 0, 0, 1, // 上→下
|
||||
[
|
||||
{ offset: 0, color: '#32B7E9' },
|
||||
{ offset: 1, color: 'rgba(50,183,233,0)' }
|
||||
]
|
||||
), }
|
||||
}]
|
||||
}
|
||||
chart.setOption(option)
|
||||
powerChartInstance = chart
|
||||
addChartToResizeManager(chart)
|
||||
}
|
||||
|
||||
// 初始化环境图表
|
||||
const initEnvChart = () => {
|
||||
if (!envChart.value) return
|
||||
|
||||
const chart = echarts.init(envChart.value)
|
||||
const option = {
|
||||
tooltip: { trigger: 'axis' },
|
||||
grid: { left: 40, right: 20, top: 40, bottom: 30 },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: Array.from({length: 8}, (_, i) => (i+1)*3),
|
||||
axisLine: { lineStyle: { color: '#3ec6ff' } },
|
||||
axisLabel: { color: '#fff' }
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLine: { lineStyle: { color: '#3ec6ff' } },
|
||||
axisLabel: { color: '#fff' },
|
||||
splitLine: { lineStyle: { color: '#1e90ff22' } }
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '今年',
|
||||
data: [100, 200, 150, 300, 250, 200, 100, 80],
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
itemStyle: { color: '#b388ff' },
|
||||
lineStyle: { width: 3 },
|
||||
areaStyle: { color: 'rgba(179,136,255,0.2)' },
|
||||
symbol: 'circle',
|
||||
symbolSize: 0,
|
||||
},
|
||||
{
|
||||
name: '去年',
|
||||
data: [80, 120, 100, 180, 150, 120, 60, 40],
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
itemStyle: { color: '#ffb300' },
|
||||
lineStyle: { width: 3 },
|
||||
areaStyle: { color: 'rgba(255,179,0,0.15)' },
|
||||
symbol: 'circle',
|
||||
symbolSize: 0,
|
||||
}
|
||||
]
|
||||
}
|
||||
chart.setOption(option)
|
||||
envChartInstance = chart
|
||||
addChartToResizeManager(chart)
|
||||
}
|
||||
|
||||
// 初始化水表图表
|
||||
const initWaterChart = () => {
|
||||
if (!waterChart.value) return
|
||||
|
||||
const chart = echarts.init(waterChart.value)
|
||||
const option = {
|
||||
tooltip: { trigger: 'axis' },
|
||||
legend: {
|
||||
data: ['今日', '平均'],
|
||||
textStyle: { color: '#fff' },
|
||||
right: 20,
|
||||
top: 10
|
||||
},
|
||||
grid: { left: 40, right: 20, top: 40, bottom: 30 },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: Array.from({length: 19}, (_, i) => i + 6),
|
||||
axisLine: { lineStyle: { color: '#3ec6ff' } },
|
||||
axisLabel: { color: '#fff' }
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLine: { lineStyle: { color: '#3ec6ff' } },
|
||||
axisLabel: { color: '#fff' },
|
||||
splitLine: { lineStyle: { color: '#1e90ff22' } }
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '今日',
|
||||
data: [1.2, 2.1, 1.8, 2.5, 3.0, 3.8, 4.2, 4.5, 4.8, 4.8, 4.0, 3.2, 2.5, 2.0, 1.5, 1.0, 0.8, 0.5, 0.2],
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
symbol: 'circle',
|
||||
symbolSize: 0,
|
||||
itemStyle: { color: '#3ec6ff' },
|
||||
lineStyle: { width: 1 },
|
||||
areaStyle: { color: new echarts.graphic.LinearGradient(
|
||||
0, 0, 0, 1, // 上→下
|
||||
[
|
||||
{ offset: 0, color: '#32B7E9' },
|
||||
{ offset: 1, color: 'rgba(50,183,233,0)' }
|
||||
]
|
||||
), }
|
||||
},
|
||||
{
|
||||
name: '平均',
|
||||
data: Array(19).fill(2.5),
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
symbol: 'none',
|
||||
itemStyle: { color: '#ff6b00' },
|
||||
lineStyle: { width: 1, type: 'solid', color: '#ff6b00' }
|
||||
}
|
||||
]
|
||||
}
|
||||
chart.setOption(option)
|
||||
waterChartInstance = chart
|
||||
addChartToResizeManager(chart)
|
||||
}
|
||||
|
||||
// 初始化设备图表
|
||||
const initDeviceChart = () => {
|
||||
if (!deviceChart.value) return
|
||||
|
||||
const chart = echarts.init(deviceChart.value)
|
||||
const option = {
|
||||
grid: { left: 60, right: 40, top: 10, bottom: 30 },
|
||||
xAxis: {
|
||||
type: 'value',
|
||||
axisLine: { lineStyle: { color: '#8697BA' } },
|
||||
axisLabel: { color: '#fff' },
|
||||
splitLine: { show: false }
|
||||
},
|
||||
yAxis: {
|
||||
type: 'category',
|
||||
data: ['门禁', '监控', '水表'],
|
||||
axisLine: { lineStyle: { color: '#8697BA' } },
|
||||
axisLabel: { color: '#A1B2C2' }
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '设备数',
|
||||
type: 'bar',
|
||||
data: [650, 120, 40],
|
||||
barWidth: 12,
|
||||
itemStyle: {
|
||||
color: function(params: any) {
|
||||
const colors = [
|
||||
new echarts.graphic.LinearGradient(
|
||||
0, 0, 0, 1, // 上→下
|
||||
[
|
||||
{ offset: 0, color: '#2986B1' },
|
||||
{ offset: 1, color: '#6941FF' }
|
||||
]
|
||||
),
|
||||
new echarts.graphic.LinearGradient(
|
||||
0, 0, 0, 1, // 上→下
|
||||
[
|
||||
{ offset: 0, color: '#33FF99' },
|
||||
{ offset: 1, color: '#00908E' }
|
||||
]
|
||||
),
|
||||
new echarts.graphic.LinearGradient(
|
||||
0, 0, 0, 1, // 上→下
|
||||
[
|
||||
{ offset: 0, color: '#01B4FF' },
|
||||
{ offset: 1, color: '#0336FF' }
|
||||
]
|
||||
),
|
||||
];
|
||||
return colors[params.dataIndex]
|
||||
}
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'right',
|
||||
color: '#fff'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
chart.setOption(option)
|
||||
deviceChartInstance = chart
|
||||
addChartToResizeManager(chart)
|
||||
}
|
||||
|
||||
// 初始化3D饼图
|
||||
const initPie3DChart = () => {
|
||||
if (!pie3dChart.value) return
|
||||
|
||||
pie3dChartInstance = renderPie3DChart(pie3dChart.value, {
|
||||
data: [
|
||||
{ name: 'A区域', value: 20, itemStyle: { color: '#3ffbff' } },
|
||||
{ name: 'D区域', value: 20, itemStyle: { color: '#b388ff' } },
|
||||
{ name: 'C区域', value: 45, itemStyle: { color: '#ff9900' } },
|
||||
{ name: 'B区域', value: 15, itemStyle: { color: '#3f6bff' } },
|
||||
],
|
||||
hoverHeightScale: 2,
|
||||
selectOffset: 0.1,
|
||||
distance: 220,
|
||||
boxHeight: 5
|
||||
})
|
||||
if (pie3dChartInstance) {
|
||||
addChartToResizeManager(pie3dChartInstance)
|
||||
}
|
||||
}
|
||||
|
||||
// 组件挂载时初始化
|
||||
onMounted(() => {
|
||||
updateTime()
|
||||
timer = setInterval(updateTime, 1000)
|
||||
initBarChart()
|
||||
initPowerChart()
|
||||
initEnvChart()
|
||||
initWaterChart()
|
||||
initDeviceChart()
|
||||
initPie3DChart()
|
||||
})
|
||||
|
||||
// 组件卸载时清理
|
||||
onBeforeUnmount(() => {
|
||||
if (timer) {
|
||||
clearInterval(timer)
|
||||
}
|
||||
|
||||
// 从管理器中移除图表
|
||||
if (barChartInstance) {
|
||||
removeChartFromResizeManager(barChartInstance)
|
||||
barChartInstance.dispose()
|
||||
}
|
||||
if (powerChartInstance) {
|
||||
removeChartFromResizeManager(powerChartInstance)
|
||||
powerChartInstance.dispose()
|
||||
}
|
||||
if (envChartInstance) {
|
||||
removeChartFromResizeManager(envChartInstance)
|
||||
envChartInstance.dispose()
|
||||
}
|
||||
if (waterChartInstance) {
|
||||
removeChartFromResizeManager(waterChartInstance)
|
||||
waterChartInstance.dispose()
|
||||
}
|
||||
if (deviceChartInstance) {
|
||||
removeChartFromResizeManager(deviceChartInstance)
|
||||
deviceChartInstance.dispose()
|
||||
}
|
||||
if (pie3dChartInstance) {
|
||||
removeChartFromResizeManager(pie3dChartInstance)
|
||||
pie3dChartInstance.dispose()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.mian{
|
||||
height: 100vh;
|
||||
background: url("../../../assets/property/bg.png");
|
||||
background-size: 100% 100%;
|
||||
background-color: #081b3a;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.title {
|
||||
height: 5.375rem;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.left{
|
||||
display: flex;
|
||||
width: 14.3125rem;
|
||||
.left-first{
|
||||
padding-left: 2.3125rem;
|
||||
padding-right: 3.5rem;
|
||||
font-size: 1.875rem;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
.left-second{
|
||||
width: 6.5rem;
|
||||
font-family: ShiShangZhongHeiJianTi;
|
||||
font-weight: 400;
|
||||
font-size: 1.25rem;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
.center{
|
||||
font-size: 1.9rem;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
letter-spacing: 0.1em;
|
||||
text-shadow: 0 0 10px #1e90ff, 0 0 20px #1e90ff;
|
||||
}
|
||||
.right{
|
||||
width: 17.3125rem;
|
||||
display: flex;
|
||||
font-family: ShiShangZhongHeiJianTi;
|
||||
font-weight: 400;
|
||||
font-size: 1.25rem;
|
||||
color: #FFFFFF;
|
||||
gap: .75rem;
|
||||
.logout{
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
gap: .2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
.header{
|
||||
margin-top: 1.125rem;
|
||||
margin-left: 4.625rem;
|
||||
margin-right: 4.25rem;
|
||||
height: 6rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.header-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 1.5rem;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 0 10px #0ff2, 0 0 20px #0ff2 inset;
|
||||
}
|
||||
.header-label {
|
||||
color: #fff;
|
||||
font-size: 1rem;
|
||||
margin-right: 0.5rem;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.header-value {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
margin: 0 0.2rem;
|
||||
}
|
||||
|
||||
.header-value.orange { color: #ffb300; }
|
||||
.header-value.green { color: #00ffb0; }
|
||||
.header-value.blue { color: #3ec6ff; }
|
||||
.header-value.purple { color: #b388ff; }
|
||||
|
||||
.header-unit {
|
||||
color: #fff;
|
||||
font-size: 1rem;
|
||||
margin-left: 0.2rem;
|
||||
}
|
||||
}
|
||||
.header div{
|
||||
width: 20.125rem;
|
||||
}
|
||||
.contents{
|
||||
flex: 1;
|
||||
.content{
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 0 2.25rem 2.25rem 2.25rem;
|
||||
.content-left{
|
||||
width: 32.6875rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
.first{
|
||||
height: 16.81rem;
|
||||
.pie3d-title {
|
||||
color: #fff;
|
||||
font-size: 1.1rem;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
.pie3d-water {
|
||||
color: #fff;
|
||||
font-size: 0.95rem;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
.pie3d-water-num {
|
||||
font-size: 1.3rem;
|
||||
color: #3ec6ff;
|
||||
background: #0a1e3a;
|
||||
border-radius: 0.2rem;
|
||||
padding: 0 0.2rem;
|
||||
margin: 0 0.2rem;
|
||||
letter-spacing: 0.1em;
|
||||
}
|
||||
.pie3d-chart {
|
||||
width: 100%;
|
||||
height: 176px;
|
||||
min-height: unset;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
.second{
|
||||
height: 12rem;
|
||||
/* margin-top:2.25rem; */
|
||||
/* margin-bottom: 2rem; */
|
||||
.power-chart {
|
||||
height: 100%;
|
||||
/* margin-top: 0.2rem; */
|
||||
}
|
||||
}
|
||||
.third{
|
||||
height: 12.12rem;
|
||||
.env-chart {
|
||||
height: 12rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
.content-center{
|
||||
width: 47.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
.content-center-first{
|
||||
height: 30.9rem;
|
||||
.first-item{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: url("../../../assets/property/center-bg.png");
|
||||
background-size: 95% 95%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
}
|
||||
.content-center-second{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 12.5rem;
|
||||
.second-item{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
.second-item-box1{
|
||||
width: 7rem;
|
||||
height: 7rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: ShiShangZhongHeiJianTi;
|
||||
font-weight: 400;
|
||||
font-size: 1.37rem;
|
||||
color: #FFFFFF;
|
||||
background: url("../../../assets/property/personnel-duty-circle1.png");
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.second-item-box2{
|
||||
width: 7rem;
|
||||
height: 7rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: ShiShangZhongHeiJianTi;
|
||||
font-weight: 400;
|
||||
font-size: 1.37rem;
|
||||
color: #FFFFFF;
|
||||
background: url("../../../assets/property/personnel-duty-circle2.png");
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.second-item-box3{
|
||||
width: 7rem;
|
||||
height: 7rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: ShiShangZhongHeiJianTi;
|
||||
font-weight: 400;
|
||||
font-size: 1.37rem;
|
||||
color: #FFFFFF;
|
||||
background: url("../../../assets/property/personnel-duty-circle3.png");
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.second-item-box4{
|
||||
width: 7rem;
|
||||
height: 7rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: ShiShangZhongHeiJianTi;
|
||||
font-weight: 400;
|
||||
font-size: 1.37rem;
|
||||
color: #FFFFFF;
|
||||
background: url("../../../assets/property/personnel-duty-circle1.png");
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.second-item-box5{
|
||||
width: 7rem;
|
||||
height: 7rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: ShiShangZhongHeiJianTi;
|
||||
font-weight: 400;
|
||||
font-size: 1.37rem;
|
||||
color: #FFFFFF;
|
||||
background: url("../../../assets/property/personnel-duty-circle4.png");
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
.content-right{
|
||||
width: 32.68rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
.first{
|
||||
height: 16.81rem;
|
||||
.water-chart {
|
||||
height: 100%;
|
||||
/* margin-top: 0.2rem; */
|
||||
}
|
||||
}
|
||||
.second{
|
||||
height: 11rem;
|
||||
margin-top:2rem;
|
||||
margin-bottom: 2rem;
|
||||
.second-box{
|
||||
margin-top: 2rem;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
.box-content{
|
||||
height: 8rem;
|
||||
width: 8rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.box-content-label{
|
||||
font-family: Microsoft YaHei;
|
||||
font-weight: 400;
|
||||
font-size: .8rem;
|
||||
color: #C4D6FF;
|
||||
line-height: 2rem;
|
||||
}
|
||||
.box-content-num{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 6rem;
|
||||
height: 6rem;
|
||||
background: url("../../../assets/property/customer-circle.png");
|
||||
background-size: 100% 100%;
|
||||
font-family: Microsoft YaHei;
|
||||
font-weight: 400;
|
||||
font-size: 1.2rem;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
.third{
|
||||
height: 13.12rem;
|
||||
.device-chart {
|
||||
height: 10rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.pie3d-title {
|
||||
color: #fff;
|
||||
font-size: 1.1rem;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
.pie3d-water {
|
||||
color: #fff;
|
||||
font-size: 0.95rem;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
.pie3d-water-num {
|
||||
font-size: 1.3rem;
|
||||
color: #3ec6ff;
|
||||
background: #0a1e3a;
|
||||
border-radius: 0.2rem;
|
||||
padding: 0 0.2rem;
|
||||
margin: 0 0.2rem;
|
||||
letter-spacing: 0.1em;
|
||||
}
|
||||
.pie3d-chart {
|
||||
width: 100%;
|
||||
height: 176px;
|
||||
min-height: unset;
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|