Compare commits

...

13 Commits

3
.gitignore vendored

@ -7,4 +7,5 @@ pnpm-debug
auto-*.d.ts
.idea
.history
pnpm-lock.yaml
pnpm-lock.yaml
/.vscode

@ -121,6 +121,10 @@ export const DeviceApi = {
return await request.download({ url: `/iot/device/export-excel`, params })
},
exportLineDevice: async (params) => {
return await request.download({ url: `/iot/device/export-line-device`, params })
},
getLineDevicePage: async (params: LineDevicePageParams) => {
return await request.get({ url: `/iot/device/lineDevicePage`, params })
},

@ -37,6 +37,10 @@ export const TicketManagementApi = {
return await request.get({ url: `/mes/ticket-management/page`, params })
},
exportTicketManagement: async (params: any) => {
return await request.download({ url: `/mes/ticket-management/export-excel`, params })
},
batchUpdateTicketStatus: async (data: { ids: string; jobStatus: string | number }) => {
return await request.put({ url: `/mes/ticket-management/batchUpdateStatus`, data })
},

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 MiB

@ -456,10 +456,362 @@ export default {
},
basedata: {
product: {
category:{
name:'name',
category: {
name: 'name'
}
},
}
},
// Equipment Management
EquipmentManagement: {
// Equipment Classification
EquipmentClassification: {
code: 'Code',
name: 'Name',
createTime: 'Create Time',
id: 'ID',
remark: 'Remark',
sort: 'Sort',
operate: 'Operate',
add: 'Add',
edit: 'Edit',
delete: 'Delete',
detail: 'Detail',
placeholderCode: 'Please input code',
placeholderName: 'Please input name',
placeholderRemark: 'Please input remark',
placeholderSort: 'Please input sort'
},
// Equipment Ledger
EquipmentLedger: {
deviceCode: 'Code',
deviceName: 'Name',
deviceStatus: 'Status',
deviceType: 'Type',
deviceSpec: 'Spec',
deviceModel: 'Model',
productionDate: 'Production Date',
factoryEntryDate: 'Factory Entry Date',
deviceLocation: 'Location',
deviceManagerName: 'Manager',
remark: 'Remark',
creatorName: 'Creator',
createTime: 'Create Time',
updateTime: 'Update Time',
operate: 'Operate',
detail: 'Detail',
edit: 'Edit',
delete: 'Delete',
batchDelete: 'Batch Delete',
placeholderDeviceCode: 'Please input code',
placeholderDeviceName: 'Please input name',
placeholderDeviceStatus: 'Please select status',
placeholderDeviceType: 'Please select type',
placeholderDeviceModel: 'Please input model',
placeholderDeviceSpec: 'Please input spec',
placeholderProductionDate: 'Please select production date',
placeholderFactoryEntryDate: 'Please select factory entry date',
placeholderDeviceLocation: 'Please input location',
placeholderDeviceManagerIds: 'Please select manager',
placeholderRemark: 'Please input remark',
placeholderComponentIds: 'Please select critical component',
placeholderBeijianIds: 'Please select spare part',
deviceNo: 'Device No',
deviceBrand: 'Device Brand',
supplier: 'Supplier',
workshop: 'Workshop',
systemOrg: 'System Org',
checkHistory: 'Check History',
maintainHistory: 'Maintain History',
repairHistory: 'Repair History',
criticalComponent: 'Critical Component',
sparePart: 'Spare Part',
mold: 'Mold',
startTime: 'Start Time',
endTime: 'End Time',
query: 'Query',
reset: 'Reset',
export: 'Export',
operator: 'Operator',
checkMethod: 'Check Method',
criteria: 'Criteria',
checkTime: 'Check Time',
maintainMethod: 'Maintain Method',
maintainTime: 'Maintain Time',
projectName: 'Project Content',
repairResult: 'Repair Result',
finishDate: 'Finish Date',
componentCode: 'Code',
componentName: 'Name',
componentDesc: 'Description',
spareCode: 'Spare Code',
spareName: 'Spare Name',
category: 'Category',
unit: 'Unit',
moldCode: 'Code',
moldName: 'Name',
moldRemark: 'Remark',
fileUrl: 'File',
serialNumber: 'No.'
},
// Critical Component
EquipmentKeyItems: {
code: 'Code',
name: 'Name',
description: 'Description',
remark: 'Remark',
createTime: 'Create Time',
operate: 'Operate',
edit: 'Edit',
delete: 'Delete',
placeholderCode: 'Please input code',
placeholderName: 'Please input name',
placeholderDescription: 'Please input description',
placeholderRemark: 'Please input remark'
},
// Maintenance Project (Project Maintenance)
DvSubject: {
code: 'Code',
name: 'Name',
inspectionMethod: 'Inspection Method',
valueType: 'Value Type',
judgmentCriteria: 'Judgment Criteria',
creatorName: 'Creator',
createTime: 'Create Time',
operate: 'Operate',
projectCode: 'Project Code',
projectName: 'Project Name',
isEnable: 'Is Enable',
edit: 'Edit',
delete: 'Delete',
batchDelete: 'Batch Delete',
placeholderCode: 'Please input code',
placeholderName: 'Please input name',
placeholderJudgmentCriteria: 'Please input judgment criteria',
placeholderProjectCode: 'Please input project code',
placeholderProjectName: 'Please input project name',
placeholderInspectionMethod: 'Please select inspection method',
placeholderValueType: 'Please select value type'
},
// Plan Maintenance
PlanMaintenance: {
planName: 'Plan Name',
planType: 'Plan Type',
planTypeMaintain: 'Maintenance',
planTypeInspect: 'Inspection',
description: 'Description',
creatorName: 'Creator',
createTime: 'Create Time',
updateTime: 'Update Time',
operate: 'Operate',
index: 'No.',
subjectCode: 'Code',
subjectName: 'Name',
inspectionMethod: 'Inspection Method',
judgmentCriteria: 'Judgment Criteria',
batchDelete: 'Batch Delete',
placeholderPlanName: 'Please input plan name',
placeholderDescription: 'Please input description',
placeholderPlanType: 'Please select plan type',
placeholderSubjectName: 'Please input name',
placeholderSubjectDescription: 'Please input description',
placeholderSubjectSelect: 'Please select related project',
selectDeleteTip: 'Please select data to delete',
exportFilename: 'PlanMaintenance.xls'
},
// Task Management
TaskManagement: {
name: 'Name',
taskType: 'Type',
taskTypeInspect: 'Inspection',
taskTypeMaintain: 'Maintenance',
projectForm: 'Project Form',
startDate: 'Start Date',
endDate: 'End Date',
cronExpression: 'Cron Expression',
enabled: 'Enabled',
creatorName: 'Creator',
createTime: 'Create Time',
updateTime: 'Update Time',
operate: 'Operate',
index: 'No.',
deviceList: 'Device List',
dateRange: 'Date Range',
operableUsers: 'Operable Users',
createWorkOrder: 'Create Work Order',
placeholderName: 'Please input name',
placeholderTaskType: 'Please select type',
placeholderProjectForm: 'Please select project form',
placeholderDeviceList: 'Please select device list',
placeholderStartDate: 'Please select start date',
placeholderEndDate: 'Please select end date',
placeholderDateRange: 'Please select date range',
placeholderOperableUsers: 'Please select operable users',
placeholderCronExpression: 'Please input cron expression',
placeholderEnabled: 'Please select enabled status',
selectCronBeforeEnable: 'Please fill in cron expression before enabling task',
cronAlertTitle: 'Tip',
cronAlertConfirm: 'Got it',
createTicketSuccess: 'Create work order successfully',
createTicketFail: 'Create work order failed',
updateEnabledSuccess: 'Update enabled status successfully',
updateEnabledFail: 'Update enabled status failed',
exportFilename: 'TaskManagement.xls'
},
// Work Order Management
WorkOrderManagement: {
planNo: 'Order No',
planType: 'Type',
planTypeInspect: 'Inspection',
planTypeMaintain: 'Maintenance',
jobStatus: 'Job Status',
jobResult: 'Result',
deviceName: 'Device Name',
configName: 'Plan Config Name',
operatorName: 'Operator',
taskTime: 'Job Time',
taskEndTime: 'Planned End Time',
createTime: 'Create Time',
index: 'No.',
cancelTask: 'Cancel Task',
jobResultPending: 'Pending',
jobResultOk: 'Pass',
jobResultNg: 'Fail',
inspectionItemName: 'Inspection Item Name',
inspectionMethod: 'Inspection Method',
judgmentCriteria: 'Judgment Criteria',
inspectionResult: 'Inspection Result',
images: 'Images',
remark: 'Remark',
operate: 'Operate',
dialogTitleDefault: 'Inspection Result',
cancelConfirm: 'Confirm to cancel selected tasks?',
cancelSuccess: 'Cancel task successfully',
cancelFail: 'Cancel task failed',
selectAllDecisionError: 'Please select pass or fail for all pending records first',
selectDecisionError: 'Please select pass or fail for pending records first',
updateSuccess: 'Update successfully',
updateFail: 'Update failed',
placeholderPlanNo: 'Please input order no',
placeholderPlanType: 'Please select type',
placeholderJobStatus: 'Please select job status',
placeholderJobResult: 'Please select result',
ok: 'Pass',
ng: 'Fail',
dialogCancel: 'Cancel',
dialogSave: 'Save'
},
// Repair Order
DvRepair: {
repairCode: 'Repair Order No',
repairName: 'Repair Order',
machineryName: 'Device Name',
machineryCode: 'Device Code',
machinerySpec: 'Spec Model',
machineryTypeId: 'Device Type',
device: 'Device',
component: 'Key Component',
acceptedBy: 'Repairer',
confirmBy: 'Inspector',
requireDate: 'Request Date',
finishDate: 'Finish Date',
confirmDate: 'Accept Date',
repairResult: 'Repair Result',
repairStatus: 'Result',
status: 'Order Status',
deviceTypeDevice: 'Device',
deviceTypeComponent: 'Key Component',
repairLineTitle: 'Device Repair Line Items',
lineSubjectCode: 'Repair Code',
lineSubjectName: 'Repair Name',
lineSubjectContent: 'Repair Content',
lineRemark: 'Remark',
lineResult: 'Result',
lineResultOk: 'Pass',
lineResultNg: 'Fail',
repair: 'Repair',
index: 'No.',
machineryType: 'Device Type',
machineryTypeDevice: 'Device',
machineryTypeKeyItem: 'Key Component',
repairResultPending: 'Pending Repair',
repairResultOk: 'Pass',
repairResultNg: 'Fail',
statusPending: 'Pending',
statusFinished: 'Finished',
creatorName: 'Creator',
createTime: 'Create Time',
operate: 'Operate',
batchDelete: 'Batch Delete',
exportFilename: 'DeviceRepair.xlsx',
selectDeleteTip: 'Please select data to delete',
placeholderRepairCode: 'Please input repair order no',
placeholderRepairName: 'Please input repair order name',
placeholderMachineryName: 'Please input device name',
placeholderAcceptedBy: 'Please input repairer',
placeholderConfirmBy: 'Please input inspector',
placeholderStatus: 'Please select order status',
placeholderDevice: 'Please select device',
placeholderComponent: 'Please select key component',
placeholderRequireDate: 'Select request date',
placeholderFinishDate: 'Select finish date',
placeholderConfirmDate: 'Select accept date',
placeholderAutoFill: 'Auto fill',
placeholderLineSubjectCode: 'Please input repair code',
placeholderLineSubjectName: 'Please input repair name',
placeholderLineSubjectContent: 'Please input repair content',
placeholderLineRemark: 'Please input remark',
validatorRepairCodeRequired: 'Repair order no can not be empty',
validatorMachineryIdRequired: 'Device ID can not be empty',
validatorMachineryCodeRequired: 'Device code can not be empty',
validatorMachineryNameRequired: 'Device name can not be empty',
validatorMachineryTypeIdRequired: 'Device type can not be empty',
validatorRequireDateRequired: 'Request date can not be empty',
validatorFinishDateRequired: 'Finish date can not be empty',
validatorConfirmDateRequired: 'Accept date can not be empty',
validatorRepairResultRequired: 'Repair result can not be empty',
validatorLineRepairIdRequired: 'Repair order ID can not be empty',
validatorLineSubjectIdRequired: 'Item ID can not be empty',
validatorLineSubjectCodeRequired: 'Item code can not be empty',
validatorLineSubjectContentRequired: 'Item content can not be empty',
validatorLineRemarkRequired: 'Remark can not be empty',
validatorLineResultRequired: 'Result can not be empty'
},
// Repair Items
RepairItems: {
subjectCode: 'Repair Code',
subjectName: 'Repair Name',
deviceType: 'Device Type',
device: 'Device',
component: 'Key Component',
projectContent: 'Repair Content',
createTime: 'Create Time',
deviceName: 'Device Name',
componentName: 'Key Component Name',
isEnable: 'Enabled',
deviceTypeDevice: 'Device',
deviceTypeComponent: 'Key Component',
operate: 'Operate',
batchDelete: 'Batch Delete',
exportFilename: 'RepairItems.xlsx',
selectDeleteTip: 'Please select data to delete',
placeholderSubjectCode: 'Please input repair code',
placeholderSubjectName: 'Please input repair name',
placeholderDeviceType: 'Please select device type',
placeholderProjectContent: 'Please input repair content',
placeholderCreateTimeStart: 'Start Date',
placeholderCreateTimeEnd: 'End Date',
placeholderDevice: 'Please select device',
placeholderComponent: 'Please select key component',
validatorSubjectCodeRequired: 'Item code can not be empty',
validatorSubjectNameRequired: 'Item name can not be empty',
validatorDeviceTypeRequired: 'Device type can not be empty',
validatorDeviceRequired: 'Device can not be empty',
validatorComponentRequired: 'Key component can not be empty',
validatorIsEnableRequired: 'Enabled can not be empty'
}
}
}

@ -449,13 +449,366 @@ export default {
btn_zoom_out: '缩小',
preview: '预览'
},
'OAuth 2.0': 'OAuth 2.0',// 避免菜单名是 OAuth 2.0 时,一直 warn 报错
'OAuth 2.0': 'OAuth 2.0', // 避免菜单名是 OAuth 2.0 时,一直 warn 报错
basedata: {
product: {
category:{
name:'分类名称',
category: {
name: '分类名称'
}
}
},
// 设备管理
EquipmentManagement: {
// 设备分类
EquipmentClassification: {
code: '编码',
name: '名称',
createTime: '创建时间',
id: 'id',
remark: '备注',
sort: '排序',
operate: '操作',
add: '添加',
edit: '编辑',
delete: '删除',
detail: '详情',
placeholderCode: '请输入编码',
placeholderName: '请输入名称',
placeholderRemark: '请输入备注',
placeholderSort: '请输入排序'
},
// 设备台账
EquipmentLedger: {
deviceCode: '编码',
deviceName: '名称',
deviceStatus: '状态',
deviceType: '类型',
deviceSpec: '规格',
deviceModel: '型号',
productionDate: '生产日期',
factoryEntryDate: '入厂日期',
deviceLocation: '位置',
deviceManagerName: '责任人',
remark: '备注',
creatorName: '创建人',
createTime: '创建时间',
updateTime: '更新时间',
operate: '操作',
detail: '详情',
edit: '编辑',
delete: '删除',
batchDelete: '批量删除',
placeholderDeviceCode: '请输入编码',
placeholderDeviceName: '请输入名称',
placeholderDeviceStatus: '请选择状态',
placeholderDeviceType: '请选择类型',
placeholderDeviceModel: '请输入型号',
placeholderDeviceSpec: '请输入规格',
placeholderProductionDate: '请选择生产日期',
placeholderFactoryEntryDate: '请选择入厂日期',
placeholderDeviceLocation: '请输入位置',
placeholderDeviceManagerIds: '请选择责任人',
placeholderRemark: '请输入备注',
placeholderComponentIds: '请选择关键件',
placeholderBeijianIds: '请选择备件',
deviceNo: '设备编号',
deviceBrand: '设备品牌',
supplier: '供应商',
workshop: '所属车间',
systemOrg: '所属系统组织',
checkHistory: '点检履历',
maintainHistory: '保养履历',
repairHistory: '维修履历',
criticalComponent: '关键件',
sparePart: '备件',
mold: '模具',
startTime: '开始时间',
endTime: '结束时间',
query: '查询',
reset: '重置',
export: '导出',
operator: '操作人',
checkMethod: '点检方式',
criteria: '判定标准',
checkTime: '点检时间',
maintainMethod: '保养方式',
maintainTime: '保养时间',
projectName: '项目内容',
repairResult: '维修结果',
finishDate: '完成日期',
componentCode: '编码',
componentName: '名称',
componentDesc: '描述',
spareCode: '备件编码',
spareName: '备件名称',
category: '分类',
unit: '单位',
moldCode: '编码',
moldName: '名称',
moldRemark: '备注',
fileUrl: '资料',
serialNumber: '序号'
},
// 设备关键件
EquipmentKeyItems: {
code: '编码',
name: '名称',
description: '描述',
remark: '备注',
createTime: '创建时间',
operate: '操作',
edit: '编辑',
delete: '删除',
placeholderCode: '请输入编码',
placeholderName: '请输入名称',
placeholderDescription: '请输入描述',
placeholderRemark: '请输入备注'
},
// 项目维护
DvSubject: {
code: '编码',
name: '名称',
inspectionMethod: '检验方式',
valueType: '值类型',
judgmentCriteria: '判定基准',
creatorName: '创建人',
createTime: '创建时间',
operate: '操作',
projectCode: '项目编码',
projectName: '项目名称',
isEnable: '是否启用',
edit: '编辑',
delete: '删除',
batchDelete: '批量删除',
placeholderCode: '请输入编码',
placeholderName: '请输入名称',
placeholderJudgmentCriteria: '请输入判定基准',
placeholderProjectCode: '请输入项目编码',
placeholderProjectName: '请输入项目名称',
placeholderInspectionMethod: '请选择检验方式',
placeholderValueType: '请选择值类型'
},
},
// 方案维护
PlanMaintenance: {
planName: '方案名称',
planType: '方案类型',
planTypeMaintain: '保养',
planTypeInspect: '点检',
description: '描述',
creatorName: '创建人',
createTime: '创建时间',
updateTime: '更新时间',
operate: '操作',
index: '序号',
subjectCode: '编码',
subjectName: '名称',
inspectionMethod: '检验方式',
judgmentCriteria: '判定基准',
batchDelete: '批量删除',
placeholderPlanName: '请输入方案名称',
placeholderDescription: '请输入描述',
placeholderPlanType: '请选择方案类型',
placeholderSubjectName: '请输入名称',
placeholderSubjectDescription: '请输入描述',
placeholderSubjectSelect: '请选择关联项目',
selectDeleteTip: '请选择需要删除的数据',
exportFilename: '方案维护.xls'
},
// 任务管理
TaskManagement: {
name: '名称',
taskType: '类型',
taskTypeInspect: '点检',
taskTypeMaintain: '保养',
projectForm: '项目表单',
startDate: '开始日期',
endDate: '结束日期',
cronExpression: 'cron 表达式',
enabled: '启用',
creatorName: '创建人',
createTime: '创建时间',
updateTime: '更新时间',
operate: '操作',
index: '序号',
deviceList: '设备列表',
dateRange: '起止日期',
operableUsers: '可操作人',
createWorkOrder: '新增工单管理',
placeholderName: '请输入名称',
placeholderTaskType: '请选择类型',
placeholderProjectForm: '请选择项目表单',
placeholderDeviceList: '请选择设备列表',
placeholderStartDate: '请选择开始日期',
placeholderEndDate: '请选择结束日期',
placeholderDateRange: '请选择起止日期',
placeholderOperableUsers: '请选择可操作人',
placeholderCronExpression: '请输入 cron 表达式',
placeholderEnabled: '请选择是否启用',
selectCronBeforeEnable: '请先填写 cron 表达式,再启用任务',
cronAlertTitle: '提示',
cronAlertConfirm: '我知道了',
createTicketSuccess: '创建工单成功',
createTicketFail: '创建工单失败',
updateEnabledSuccess: '更新启用状态成功',
updateEnabledFail: '更新启用状态失败',
exportFilename: '任务管理.xls'
},
// 工单管理
WorkOrderManagement: {
planNo: '单号',
planType: '类型',
planTypeInspect: '点检',
planTypeMaintain: '保养',
jobStatus: '作业状态',
jobResult: '结果',
deviceName: '设备名称',
configName: '计划配置名称',
operatorName: '作业人',
taskTime: '作业时间',
taskEndTime: '计划结束作业时间',
createTime: '创建时间',
index: '序号',
cancelTask: '取消任务',
jobResultPending: '待检测',
jobResultOk: '通过',
jobResultNg: '不通过',
inspectionItemName: '检验项名称',
inspectionMethod: '检验方式',
judgmentCriteria: '判定基准',
inspectionResult: '检验结果',
images: '图片',
remark: '备注',
operate: '操作',
dialogTitleDefault: '检验结果',
cancelConfirm: '确认取消选中的任务吗?',
cancelSuccess: '取消任务成功',
cancelFail: '取消任务失败',
selectAllDecisionError: '请先为所有待检测记录选择通过或不通过',
selectDecisionError: '请先为待检测记录选择通过或不通过',
updateSuccess: '更新成功',
updateFail: '更新失败',
placeholderPlanNo: '请输入单号',
placeholderPlanType: '请选择类型',
placeholderJobStatus: '请选择作业状态',
placeholderJobResult: '请选择结果',
ok: '通过',
ng: '不通过',
dialogCancel: '取 消',
dialogSave: '保 存'
},
// 维修单
DvRepair: {
repairCode: '维修单号',
repairName: '维修单',
machineryName: '设备名称',
machineryCode: '设备编码',
machinerySpec: '规格型号',
machineryTypeId: '设备类型',
device: '设备',
component: '关键件',
acceptedBy: '维修人员',
confirmBy: '验收人员',
requireDate: '报修日期',
finishDate: '完成日期',
confirmDate: '验收日期',
repairResult: '维修结果',
repairStatus: '结果',
status: '单据状态',
deviceTypeDevice: '设备',
deviceTypeComponent: '关键件',
repairLineTitle: '设备维修项目行',
lineSubjectCode: '维修编码',
lineSubjectName: '维修名称',
lineSubjectContent: '维修内容',
lineRemark: '备注',
lineResult: '结果',
lineResultOk: '通过',
lineResultNg: '不通过',
repair: '维修',
index: '序号',
machineryType: '设备类型',
machineryTypeDevice: '设备',
machineryTypeKeyItem: '关键件',
repairResultPending: '待维修',
repairResultOk: '通过',
repairResultNg: '不通过',
statusPending: '待完成',
statusFinished: '已完成',
creatorName: '创建人',
createTime: '创建时间',
operate: '操作',
batchDelete: '批量删除',
exportFilename: '设备维修记录.xls',
selectDeleteTip: '请选择需要删除的数据',
placeholderRepairCode: '请输入维修单编号',
placeholderRepairName: '请输入维修单名称',
placeholderMachineryName: '请输入设备名称',
placeholderAcceptedBy: '请输入维修人员',
placeholderConfirmBy: '请输入验收人员',
placeholderStatus: '请选择单据状态',
placeholderDevice: '请选择设备',
placeholderComponent: '请选择关键件',
placeholderRequireDate: '选择报修日期',
placeholderFinishDate: '选择完成日期',
placeholderConfirmDate: '选择验收日期',
placeholderAutoFill: '自动带出',
placeholderLineSubjectCode: '请输入维修编码',
placeholderLineSubjectName: '请输入维修名称',
placeholderLineSubjectContent: '请输入维修内容',
placeholderLineRemark: '请输入备注',
validatorRepairCodeRequired: '维修单编号不能为空',
validatorMachineryIdRequired: '设备ID不能为空',
validatorMachineryCodeRequired: '设备编码不能为空',
validatorMachineryNameRequired: '设备名称不能为空',
validatorMachineryTypeIdRequired: '设备类型不能为空',
validatorRequireDateRequired: '报修日期不能为空',
validatorFinishDateRequired: '完成日期不能为空',
validatorConfirmDateRequired: '验收日期不能为空',
validatorRepairResultRequired: '维修结果不能为空',
validatorLineRepairIdRequired: '维修单ID不能为空',
validatorLineSubjectIdRequired: '项目ID不能为空',
validatorLineSubjectCodeRequired: '项目编码不能为空',
validatorLineSubjectContentRequired: '项目内容不能为空',
validatorLineRemarkRequired: '备注不能为空',
validatorLineResultRequired: '结果不能为空'
},
// 维修项目
RepairItems: {
subjectCode: '维修编码',
subjectName: '维修名称',
deviceType: '设备类型',
device: '设备',
component: '关键件',
projectContent: '维修内容',
createTime: '创建时间',
deviceName: '设备名称',
componentName: '关键件名称',
isEnable: '是否启用',
deviceTypeDevice: '设备',
deviceTypeComponent: '关键件',
operate: '操作',
batchDelete: '批量删除',
exportFilename: '维修项目.xls',
selectDeleteTip: '请选择需要删除的数据',
placeholderSubjectCode: '请输入维修编码',
placeholderSubjectName: '请输入维修名称',
placeholderDeviceType: '请选择设备类型',
placeholderProjectContent: '请输入维修内容',
placeholderCreateTimeStart: '开始日期',
placeholderCreateTimeEnd: '结束日期',
placeholderDevice: '请选择设备',
placeholderComponent: '请选择关键件',
validatorSubjectCodeRequired: '项目编码不能为空',
validatorSubjectNameRequired: '项目名称不能为空',
validatorDeviceTypeRequired: '设备类型不能为空',
validatorDeviceRequired: '设备不能为空',
validatorComponentRequired: '关键件不能为空',
validatorIsEnableRequired: '是否启用不能为空'
}
}
}

@ -611,6 +611,18 @@ const remainingRouter: AppRouteRecordRaw[] = [
}
},
{
path: '/iot/report/dashboardPage/Dashboard1',
component: () => import('@/views/report/dashboardPage/dashboard1/Dashboard8.vue'),
name: 'IotReportDashboard1',
meta: {
title: '智能制造产线任务总览',
hidden: true,
noTagsView: true,
canTo: true
}
},
{
path: '/:pathMatch(.*)*',
component: () => import('@/views/Error/404.vue'),

@ -45,16 +45,47 @@ export const useDictStore = defineStore('dict', {
this.dictMap = dictMap
this.isSetDict = true
} else {
try {
const res = await getSimpleDictDataList()
const dictDataMap = new Map<string, any>()
res.forEach((dictData: DictDataVO) => {
const enumValueObj = dictDataMap[dictData.dictType]
if (!enumValueObj) {
dictDataMap[dictData.dictType] = []
}
dictDataMap[dictData.dictType].push({
value: dictData.value,
label: dictData.label,
colorType: dictData.colorType,
cssClass: dictData.cssClass
})
})
this.dictMap = dictDataMap
wsCache.set(CACHE_KEY.DICT_CACHE, dictDataMap, { exp: 60 })
} catch (error) {
console.error('加载数据字典失败', error)
this.dictMap = new Map<string, any>()
} finally {
this.isSetDict = true
}
}
},
getDictByType(type: string) {
if (!this.isSetDict) {
this.setDictMap()
}
return this.dictMap[type]
},
async resetDict() {
wsCache.delete(CACHE_KEY.DICT_CACHE)
try {
const res = await getSimpleDictDataList()
// 设置数据
const dictDataMap = new Map<string, any>()
res.forEach((dictData: DictDataVO) => {
// 获得 dictType 层级
const enumValueObj = dictDataMap[dictData.dictType]
if (!enumValueObj) {
dictDataMap[dictData.dictType] = []
}
// 处理 dictValue 层级
dictDataMap[dictData.dictType].push({
value: dictData.value,
label: dictData.label,
@ -63,38 +94,13 @@ export const useDictStore = defineStore('dict', {
})
})
this.dictMap = dictDataMap
wsCache.set(CACHE_KEY.DICT_CACHE, dictDataMap, { exp: 60 })
} catch (error) {
console.error('重置数据字典失败', error)
this.dictMap = new Map<string, any>()
} finally {
this.isSetDict = true
wsCache.set(CACHE_KEY.DICT_CACHE, dictDataMap, { exp: 60 }) // 60 秒 过期
}
},
getDictByType(type: string) {
if (!this.isSetDict) {
this.setDictMap()
}
return this.dictMap[type]
},
async resetDict() {
wsCache.delete(CACHE_KEY.DICT_CACHE)
const res = await getSimpleDictDataList()
// 设置数据
const dictDataMap = new Map<string, any>()
res.forEach((dictData: DictDataVO) => {
// 获得 dictType 层级
const enumValueObj = dictDataMap[dictData.dictType]
if (!enumValueObj) {
dictDataMap[dictData.dictType] = []
}
// 处理 dictValue 层级
dictDataMap[dictData.dictType].push({
value: dictData.value,
label: dictData.label,
colorType: dictData.colorType,
cssClass: dictData.cssClass
})
})
this.dictMap = dictDataMap
this.isSetDict = true
wsCache.set(CACHE_KEY.DICT_CACHE, dictDataMap, { exp: 60 }) // 60 秒 过期
}
}
})

@ -228,11 +228,13 @@ const handleBatchDelete = async () => {
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await DeviceAttributeTypeApi.exportDeviceAttributeType(queryParams)
const params: any = {
...queryParams,
ids: selectedIds.value.length ? selectedIds.value.join(',') : undefined,
}
const data = await DeviceAttributeTypeApi.exportDeviceAttributeType(params)
download.excel(data, '采集点分类.xls')
} catch {
} finally {

@ -103,6 +103,23 @@ const recordGroups = ref<RecordGroup[]>([])
const collectionTimeRange = ref<string[]>([])
const formatDateTime = (date: Date) => {
const pad = (value: number) => String(value).padStart(2, '0')
const y = date.getFullYear()
const m = pad(date.getMonth() + 1)
const d = pad(date.getDate())
const h = pad(date.getHours())
const mi = pad(date.getMinutes())
const s = pad(date.getSeconds())
return `${y}-${m}-${d} ${h}:${mi}:${s}`
}
const buildLastHoursRange = (hours: number) => {
const end = new Date()
const start = new Date(end.getTime() - hours * 60 * 60 * 1000)
return [formatDateTime(start), formatDateTime(end)]
}
const toGroupMap = (value: any): Record<string, any[]> => {
if (!value || typeof value !== 'object' || Array.isArray(value)) {
return {}
@ -206,6 +223,7 @@ watch(
if (!visible) {
return
}
collectionTimeRange.value = buildLastHoursRange(4)
fetchHistory()
}
)

@ -50,6 +50,9 @@
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
</el-button>
<el-button type="success" plain @click="handleExport" :loading="exportLoading">
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
@ -61,7 +64,9 @@
:stripe="true"
:show-overflow-tooltip="true"
row-key="id"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" reserve-selection />
<el-table-column label="产线编码" align="left" prop="lineNode" min-width="140px" />
<el-table-column label="产线名称" align="left" prop="lineName" min-width="160px" />
<el-table-column label="设备编码" align="left" prop="deviceCode" min-width="140px" />
@ -98,14 +103,18 @@
<script setup lang="ts">
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { DeviceApi, LineDeviceVO, LineDevicePageParams } from '@/api/iot/device'
import HistorySingleDeviceDialog from './HistorySingleDeviceDialog.vue'
defineOptions({ name: 'HistoryData' })
const message = useMessage()
const loading = ref(true)
const list = ref<LineDeviceVO[]>([])
const total = ref(0)
const exportLoading = ref(false)
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
@ -119,6 +128,14 @@ const queryParams = reactive({
const queryFormRef = ref()
const selectedIds = ref<(string | number)[]>([])
const handleSelectionChange = (rows: LineDeviceVO[]) => {
selectedIds.value =
rows?.map((row) => ((row as any)?.id ?? (row as any)?.deviceId) as string | number).filter(
(id) => id !== undefined && id !== null && id !== ''
) ?? []
}
const singleDialogVisible = ref(false)
const singleDeviceId = ref<string | number>()
const singleDeviceName = ref<string>('')
@ -188,4 +205,20 @@ onActivated(() => {
}
getList()
})
const handleExport = async () => {
try {
await message.exportConfirm()
exportLoading.value = true
const params: any = {
...buildQueryParams(),
ids: selectedIds.value.length ? selectedIds.value.join(',') : undefined
}
const data = await DeviceApi.exportLineDevice(params)
download.excel(data, '历史数据设备.xls')
} catch {
} finally {
exportLoading.value = false
}
}
</script>

@ -28,12 +28,23 @@ v-model="queryParams.deviceName" placeholder="请输入设备名称" clearable @
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
</el-button>
<el-button type="success" plain @click="handleExport" :loading="exportLoading">
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" row-key="id">
<el-table
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
row-key="id"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" reserve-selection />
<el-table-column label="产线编码" align="left" prop="lineNode" min-width="140px" />
<el-table-column label="产线名称" align="left" prop="lineName" min-width="160px" />
<el-table-column label="设备编码" align="left" prop="deviceCode" min-width="140px" />
@ -66,6 +77,7 @@ v-model="queryParams.deviceName" placeholder="请输入设备名称" clearable @
<script setup lang="ts">
import { DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { DeviceApi, LineDeviceVO } from '@/api/iot/device'
import SingleDeviceMonitorDialog from './SingleDeviceMonitorDialog.vue'
@ -76,6 +88,7 @@ const message = useMessage()
const loading = ref(true)
const list = ref<LineDeviceVO[]>([])
const total = ref(0)
const exportLoading = ref(false)
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
@ -87,7 +100,15 @@ const queryParams = reactive({
status: undefined,
collectionTime: undefined
})
const queryFormRef = ref() //
const queryFormRef = ref()
const selectedIds = ref<(string | number)[]>([])
const handleSelectionChange = (rows: LineDeviceVO[]) => {
selectedIds.value =
rows?.map((row) => ((row as any)?.id ?? (row as any)?.deviceId) as string | number).filter(
(id) => id !== undefined && id !== null && id !== ''
) ?? []
}
const monitorDialogVisible = ref(false)
const monitorDeviceId = ref<string | number>()
@ -143,6 +164,22 @@ const handleSingleMonitor = (row: LineDeviceVO) => {
monitorDialogVisible.value = true
}
const handleExport = async () => {
try {
await message.exportConfirm()
exportLoading.value = true
const params: any = {
...buildQueryParams(),
ids: selectedIds.value.length ? selectedIds.value.join(',') : undefined
}
const data = await DeviceApi.exportLineDevice(params)
download.excel(data, '实时监控设备.xls')
} catch {
} finally {
exportLoading.value = false
}
}
onMounted(() => {
getList()
})

@ -1,22 +1,41 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible" width="720px">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="90px" v-loading="formLoading">
<el-form-item label="编码" prop="code">
<el-input v-model="formData.code" placeholder="请输入编码" clearable :disabled = "formType === 'update'"/>
<el-form-item :label="t('EquipmentManagement.EquipmentKeyItems.code')" prop="code">
<el-input
v-model="formData.code"
:placeholder="t('EquipmentManagement.EquipmentKeyItems.placeholderCode')"
clearable
:disabled="formType === 'update'"
/>
</el-form-item>
<el-form-item label="名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入名称" clearable />
<el-form-item :label="t('EquipmentManagement.EquipmentKeyItems.name')" prop="name">
<el-input
v-model="formData.name"
:placeholder="t('EquipmentManagement.EquipmentKeyItems.placeholderName')"
clearable
/>
</el-form-item>
<el-form-item label="描述" prop="description">
<el-input v-model="formData.description" placeholder="请输入描述" clearable type="textarea" />
<el-form-item :label="t('EquipmentManagement.EquipmentKeyItems.description')" prop="description">
<el-input
v-model="formData.description"
:placeholder="t('EquipmentManagement.EquipmentKeyItems.placeholderDescription')"
clearable
type="textarea"
/>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" placeholder="请输入备注" clearable type="textarea" />
<el-form-item :label="t('EquipmentManagement.EquipmentKeyItems.remark')" prop="remark">
<el-input
v-model="formData.remark"
:placeholder="t('EquipmentManagement.EquipmentKeyItems.placeholderRemark')"
clearable
type="textarea"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="submitForm" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
<el-button type="primary" @click="submitForm" :disabled="formLoading">{{ t('common.ok') }}</el-button>
</template>
</Dialog>
</template>

@ -1,40 +1,65 @@
<template>
<ContentWrap>
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="编码" prop="code">
<el-input v-model="queryParams.code" placeholder="请输入编码" clearable @keyup.enter="handleQuery" class="!w-240px" />
<el-form-item :label="t('EquipmentManagement.EquipmentKeyItems.code')" prop="code">
<el-input
v-model="queryParams.code"
:placeholder="t('EquipmentManagement.EquipmentKeyItems.placeholderCode')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="名称" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入名称" clearable @keyup.enter="handleQuery" class="!w-240px" />
<el-form-item :label="t('EquipmentManagement.EquipmentKeyItems.name')" prop="name">
<el-input
v-model="queryParams.name"
:placeholder="t('EquipmentManagement.EquipmentKeyItems.placeholderName')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="描述" prop="description">
<el-form-item :label="t('EquipmentManagement.EquipmentKeyItems.description')" prop="description">
<el-input
v-model="queryParams.description"
placeholder="请输入描述"
:placeholder="t('EquipmentManagement.EquipmentKeyItems.placeholderDescription')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="queryParams.remark" placeholder="请输入备注" clearable @keyup.enter="handleQuery" class="!w-240px" />
<el-form-item :label="t('EquipmentManagement.EquipmentKeyItems.remark')" prop="remark">
<el-input
v-model="queryParams.remark"
:placeholder="t('EquipmentManagement.EquipmentKeyItems.placeholderRemark')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-form-item :label="t('EquipmentManagement.EquipmentKeyItems.createTime')" prop="createTime">
<el-date-picker
v-model="queryParams.createTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:start-placeholder="t('common.startTimeText')"
:end-placeholder="t('common.endTimeText')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-220px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" />
{{ t('common.query') }}
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" />
{{ t('common.reset') }}
</el-button>
<el-button type="primary" plain @click="openForm('create')" v-hasPermi="['mes:critical-component:create']">
<Icon icon="ep:plus" class="mr-5px" /> 新增
<Icon icon="ep:plus" class="mr-5px" />
{{ t('action.add') }}
</el-button>
<el-button
type="danger"
@ -43,7 +68,8 @@
:disabled="!selectedIds.length"
v-hasPermi="['mes:critical-component:delete']"
>
<Icon icon="ep:delete" class="mr-5px" /> 删除
<Icon icon="ep:delete" class="mr-5px" />
{{ t('EquipmentManagement.EquipmentKeyItems.delete') }}
</el-button>
<el-button
type="success"
@ -52,7 +78,8 @@
:loading="exportLoading"
v-hasPermi="['mes:critical-component:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
<Icon icon="ep:download" class="mr-5px" />
{{ t('action.export') }}
</el-button>
</el-form-item>
</el-form>
@ -61,18 +88,18 @@
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" />
<el-table-column label="编码" align="center" prop="code" min-width="140" />
<el-table-column label="名称" align="center" prop="name" min-width="140" />
<el-table-column label="描述" align="center" prop="description" min-width="180" />
<el-table-column label="备注" align="center" prop="remark" min-width="180" />
<el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180" />
<el-table-column label="操作" align="center" width="140" fixed="right">
<el-table-column :label="t('EquipmentManagement.EquipmentKeyItems.code')" align="center" prop="code" min-width="140" />
<el-table-column :label="t('EquipmentManagement.EquipmentKeyItems.name')" align="center" prop="name" min-width="140" />
<el-table-column :label="t('EquipmentManagement.EquipmentKeyItems.description')" align="center" prop="description" min-width="180" />
<el-table-column :label="t('EquipmentManagement.EquipmentKeyItems.remark')" align="center" prop="remark" min-width="180" />
<el-table-column :label="t('EquipmentManagement.EquipmentKeyItems.createTime')" align="center" prop="createTime" :formatter="dateFormatter" width="180" />
<el-table-column :label="t('EquipmentManagement.EquipmentKeyItems.operate')" align="center" width="140" fixed="right">
<template #default="scope">
<el-button link type="primary" @click="openForm('update', scope.row)" v-hasPermi="['mes:critical-component:update']">
编辑
{{ t('EquipmentManagement.EquipmentKeyItems.edit') }}
</el-button>
<el-button link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['mes:critical-component:delete']">
删除
{{ t('EquipmentManagement.EquipmentKeyItems.delete') }}
</el-button>
</template>
</el-table-column>
@ -186,4 +213,3 @@ onMounted(() => {
getList()
})
</script>

@ -15,18 +15,18 @@
</el-col> -->
<el-col :span="12">
<el-form-item label="编码" prop="deviceCode" required>
<el-input :disabled = "formType == 'update'" v-model="formData.deviceCode" placeholder="请输入编码" />
<el-form-item :label="t('EquipmentManagement.EquipmentLedger.deviceCode')" prop="deviceCode" required>
<el-input :disabled = "formType == 'update'" v-model="formData.deviceCode" :placeholder="t('EquipmentManagement.EquipmentLedger.placeholderDeviceCode')" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="名称" prop="deviceName" required>
<el-input v-model="formData.deviceName" placeholder="请输入名称" />
<el-form-item :label="t('EquipmentManagement.EquipmentLedger.deviceName')" prop="deviceName" required>
<el-input v-model="formData.deviceName" :placeholder="t('EquipmentManagement.EquipmentLedger.placeholderDeviceName')" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="类型" prop="deviceType" required>
<el-form-item :label="t('EquipmentManagement.EquipmentLedger.deviceType')" prop="deviceType" required>
<el-tree-select
v-model="formData.deviceType"
:data="deviceTypeTree"
@ -34,26 +34,26 @@
check-strictly
default-expand-all
value-key="id"
placeholder="请选择类型"
:placeholder="t('EquipmentManagement.EquipmentLedger.placeholderDeviceType')"
class="!w-full"
/>
</el-form-item>
</el-col>
<!-- <el-col :span="12">
<el-form-item label="品牌" prop="deviceBrand">
<el-form-item :label="t('EquipmentManagement.EquipmentLedger.deviceBrand')" prop="deviceBrand">
<el-input v-model="formData.deviceBrand" placeholder="请输入品牌" />
</el-form-item>
</el-col> -->
<el-col :span="24">
<el-form-item label="型号" prop="deviceModel">
<el-input v-model="formData.deviceModel" placeholder="请输入型号" />
<el-form-item :label="t('EquipmentManagement.EquipmentLedger.deviceModel')" prop="deviceModel">
<el-input v-model="formData.deviceModel" :placeholder="t('EquipmentManagement.EquipmentLedger.placeholderDeviceModel')" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="规格" prop="deviceSpec">
<el-input v-model="formData.deviceSpec" placeholder="请输入规格" />
<el-form-item :label="t('EquipmentManagement.EquipmentLedger.deviceSpec')" prop="deviceSpec">
<el-input v-model="formData.deviceSpec" :placeholder="t('EquipmentManagement.EquipmentLedger.placeholderDeviceSpec')" />
</el-form-item>
</el-col>
@ -86,20 +86,20 @@
</el-col> -->
<el-col :span="24">
<el-form-item label="生产日期" prop="productionDate" required>
<el-date-picker v-model="formData.productionDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择生产日期" class="!w-full" />
<el-form-item :label="t('EquipmentManagement.EquipmentLedger.productionDate')" prop="productionDate" required>
<el-date-picker v-model="formData.productionDate" type="date" value-format="YYYY-MM-DD" :placeholder="t('EquipmentManagement.EquipmentLedger.placeholderProductionDate')" class="!w-full" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="入厂日期" prop="factoryEntryDate" required>
<el-date-picker v-model="formData.factoryEntryDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择入厂日期" class="!w-full" />
<el-form-item :label="t('EquipmentManagement.EquipmentLedger.factoryEntryDate')" prop="factoryEntryDate" required>
<el-date-picker v-model="formData.factoryEntryDate" type="date" value-format="YYYY-MM-DD" :placeholder="t('EquipmentManagement.EquipmentLedger.placeholderFactoryEntryDate')" class="!w-full" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="位置" prop="deviceLocation">
<el-input v-model="formData.deviceLocation" placeholder="请输入位置" />
<el-form-item :label="t('EquipmentManagement.EquipmentLedger.deviceLocation')" prop="deviceLocation">
<el-input v-model="formData.deviceLocation" :placeholder="t('EquipmentManagement.EquipmentLedger.placeholderDeviceLocation')" />
</el-form-item>
</el-col>
@ -122,13 +122,13 @@
</el-col> -->
<el-col :span="24">
<el-form-item label="责任人" prop="deviceManagerIds">
<el-form-item :label="t('EquipmentManagement.EquipmentLedger.deviceManagerName')" prop="deviceManagerIds">
<el-select
v-model="formData.deviceManagerIds"
multiple
filterable
clearable
placeholder="请选择责任人"
:placeholder="t('EquipmentManagement.EquipmentLedger.placeholderDeviceManagerIds')"
class="!w-full"
>
<el-option v-for="item in users" :key="item.id" :label="item.nickname" :value="item.id" />
@ -137,19 +137,19 @@
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" placeholder="请输入备注" type="textarea" />
<el-form-item :label="t('EquipmentManagement.EquipmentLedger.remark')" prop="remark">
<el-input v-model="formData.remark" :placeholder="t('EquipmentManagement.EquipmentLedger.placeholderRemark')" type="textarea" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="关键件" prop="componentIds">
<el-form-item :label="t('EquipmentManagement.EquipmentLedger.criticalComponent')" prop="componentIds">
<el-select
v-model="formData.componentIds"
multiple
filterable
clearable
placeholder="请选择关键件"
:placeholder="t('EquipmentManagement.EquipmentLedger.placeholderComponentIds')"
class="!w-full"
>
<el-option
@ -163,13 +163,13 @@
</el-col>
<el-col :span="24">
<el-form-item label="备件" prop="beijianIds">
<el-form-item :label="t('EquipmentManagement.EquipmentLedger.sparePart')" prop="beijianIds">
<el-select
v-model="formData.beijianIds"
multiple
filterable
clearable
placeholder="请选择备件"
:placeholder="t('EquipmentManagement.EquipmentLedger.placeholderBeijianIds')"
class="!w-full"
>
<el-option
@ -183,15 +183,15 @@
</el-col>
<el-col :span="24">
<el-form-item label="资料" prop="fileUrl">
<el-form-item :label="t('EquipmentManagement.EquipmentLedger.fileUrl')" prop="fileUrl">
<UploadFile :is-show-tip="false" v-model="formData.fileUrl" :limit="1" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
<el-button @click="submitForm" type="primary" :disabled="formLoading">{{ t('common.ok') }}</el-button>
<el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
@ -267,11 +267,11 @@ const formData = ref({
...initFormData()
})
const formRules = reactive<FormRules>({
deviceCode: [{ required: true, message: '编码不能为空', trigger: 'blur' }],
deviceName: [{ required: true, message: '名称不能为空', trigger: 'blur' }],
deviceType: [{ required: true, message: '类型不能为空', trigger: 'change' }],
productionDate: [{ required: true, message: '生产日期不能为空', trigger: 'change' }],
factoryEntryDate: [{ required: true, message: '入厂日期不能为空', trigger: 'change' }]
deviceCode: [{ required: true, message: t('EquipmentManagement.EquipmentLedger.placeholderDeviceCode'), trigger: 'blur' }],
deviceName: [{ required: true, message: t('EquipmentManagement.EquipmentLedger.placeholderDeviceName'), trigger: 'blur' }],
deviceType: [{ required: true, message: t('EquipmentManagement.EquipmentLedger.placeholderDeviceType'), trigger: 'change' }],
productionDate: [{ required: true, message: t('EquipmentManagement.EquipmentLedger.placeholderProductionDate'), trigger: 'change' }],
factoryEntryDate: [{ required: true, message: t('EquipmentManagement.EquipmentLedger.placeholderFactoryEntryDate'), trigger: 'change' }]
})
const formRef = ref() // Ref

@ -9,38 +9,38 @@ v-loading="typeTreeLoading" :data="typeTreeData" node-key="id" highlight-current
<div class="device-ledger-right">
<ContentWrap>
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="60px">
<el-form-item label="编码" prop="deviceCode">
<el-form-item :label="t('EquipmentManagement.EquipmentLedger.deviceCode')" prop="deviceCode">
<el-input
v-model="queryParams.deviceCode" placeholder="请输入编码" clearable @keyup.enter="handleQuery"
v-model="queryParams.deviceCode" :placeholder="t('EquipmentManagement.EquipmentLedger.placeholderDeviceCode')" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="名称" prop="deviceName">
<el-form-item :label="t('EquipmentManagement.EquipmentLedger.deviceName')" prop="deviceName">
<el-input
v-model="queryParams.deviceName" placeholder="请输入名称" clearable @keyup.enter="handleQuery"
v-model="queryParams.deviceName" :placeholder="t('EquipmentManagement.EquipmentLedger.placeholderDeviceName')" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="状态" prop="deviceStatus">
<el-select v-model="queryParams.deviceStatus" placeholder="请选择状态" clearable class="!w-240px">
<el-form-item :label="t('EquipmentManagement.EquipmentLedger.deviceStatus')" prop="deviceStatus">
<el-select v-model="queryParams.deviceStatus" :placeholder="t('EquipmentManagement.EquipmentLedger.placeholderDeviceStatus')" clearable class="!w-240px">
<el-option v-for="dict in tzStatusOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> 搜索
<Icon icon="ep:search" class="mr-5px" /> {{ t('common.query') }}
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
<Icon icon="ep:refresh" class="mr-5px" /> {{ t('common.reset') }}
</el-button>
<el-button type="primary" plain @click="openForm('create')" v-hasPermi="['mes:device-ledger:create']">
<Icon icon="ep:plus" class="mr-5px" /> 新增
<Icon icon="ep:plus" class="mr-5px" /> {{ t('action.add') }}
</el-button>
<el-button type="danger" plain @click="handleBatchDelete" v-hasPermi="['mes:device-ledger:delete']">
<Icon icon="ep:delete" class="mr-5px" /> 批量删除
<Icon icon="ep:delete" class="mr-5px" /> {{ t('EquipmentManagement.EquipmentLedger.batchDelete') }}
</el-button>
<el-button
type="success" plain @click="handleExport" :loading="exportLoading"
v-hasPermi="['mes:device-ledger:export']">
<Icon icon="ep:download" class="mr-5px" /> 导出
<Icon icon="ep:download" class="mr-5px" /> {{ t('action.export') }}
</el-button>
</el-form-item>
</el-form>
@ -51,21 +51,21 @@ type="success" plain @click="handleExport" :loading="exportLoading"
ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"
row-key="id" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" fixed="left" reserve-selection />
<el-table-column label="序号" align="center" width="80" fixed="left">
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.serialNumber')" align="center" width="80" fixed="left">
<template #default="scope">
{{ (queryParams.pageNo - 1) * queryParams.pageSize + scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column label="编码" align="center" prop="deviceCode" min-width="110px" />
<el-table-column label="名称" align="center" prop="deviceName" min-width="120px" />
<el-table-column label="类型" align="center" prop="deviceType" min-width="110px">
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.deviceCode')" align="center" prop="deviceCode" min-width="110px" />
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.deviceName')" align="center" prop="deviceName" min-width="120px" />
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.deviceType')" align="center" prop="deviceType" min-width="110px">
<template #default="scope">
<el-tag effect="light">
{{ getDeviceTypeName(scope.row.deviceTypeName ?? scope.row.deviceType) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="deviceStatus">
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.deviceStatus')" align="center" prop="deviceStatus">
<template #default="scope">
<el-tag
:type="getTzStatusTagType(scope.row.deviceStatus)"
@ -75,36 +75,36 @@ ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-to
</el-tag>
</template>
</el-table-column>
<el-table-column label="规格" align="center" prop="deviceSpec" />
<el-table-column label="型号" align="center" prop="deviceModel" />
<!-- <el-table-column label="品牌" align="center" prop="deviceBrand" /> -->
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.deviceSpec')" align="center" prop="deviceSpec" />
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.deviceModel')" align="center" prop="deviceModel" />
<!-- <el-table-column :label="t('EquipmentManagement.EquipmentLedger.deviceBrand')" align="center" prop="deviceBrand" /> -->
<el-table-column
label="生产日期" align="center" prop="productionDate" :formatter="dateFormatter2"
:label="t('EquipmentManagement.EquipmentLedger.productionDate')" align="center" prop="productionDate" :formatter="dateFormatter2"
width="140px" />
<el-table-column
label="入厂日期" align="center" prop="factoryEntryDate" :formatter="dateFormatter2"
:label="t('EquipmentManagement.EquipmentLedger.factoryEntryDate')" align="center" prop="factoryEntryDate" :formatter="dateFormatter2"
width="140px" />
<!-- <el-table-column label="供应商" align="center" prop="supplier" width="110px" /> -->
<!-- <el-table-column label="所属车间" align="center" prop="workshop" width="110px" /> -->
<el-table-column label="位置" align="center" prop="deviceLocation" min-width="150px" />
<!-- <el-table-column label="使用部门" align="center" prop="systemOrg" width="110px" /> -->
<el-table-column label="责任人" align="center" prop="deviceManagerName" width="150px" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="创建人" align="center" prop="creatorName" width="150px" />
<el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180px" />
<el-table-column label="更新时间" align="center" prop="updateTime" :formatter="dateFormatter" width="180px" />
<el-table-column label="操作" align="center" min-width="160px" fixed="right">
<!-- <el-table-column :label="t('EquipmentManagement.EquipmentLedger.supplier')" align="center" prop="supplier" width="110px" /> -->
<!-- <el-table-column :label="t('EquipmentManagement.EquipmentLedger.workshop')" align="center" prop="workshop" width="110px" /> -->
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.deviceLocation')" align="center" prop="deviceLocation" min-width="150px" />
<!-- <el-table-column :label="t('EquipmentManagement.EquipmentLedger.systemOrg')" align="center" prop="systemOrg" width="110px" /> -->
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.deviceManagerName')" align="center" prop="deviceManagerName" width="150px" />
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.remark')" align="center" prop="remark" />
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.creatorName')" align="center" prop="creatorName" width="150px" />
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.createTime')" align="center" prop="createTime" :formatter="dateFormatter" width="180px" />
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.updateTime')" align="center" prop="updateTime" :formatter="dateFormatter" width="180px" />
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.operate')" align="center" min-width="160px" fixed="right">
<template #default="scope">
<el-button link @click="handleDetail(scope.row.id)"></el-button>
<el-button link @click="handleDetail(scope.row.id)">{{ t('EquipmentManagement.EquipmentLedger.detail') }}</el-button>
<el-button
link type="primary" @click="openForm('update', scope.row.id)"
v-hasPermi="['mes:device-ledger:update']">
编辑
{{ t('EquipmentManagement.EquipmentLedger.edit') }}
</el-button>
<el-button
link type="danger" @click="handleDelete(scope.row.id)"
v-hasPermi="['mes:device-ledger:delete']">
删除
{{ t('EquipmentManagement.EquipmentLedger.delete') }}
</el-button>
</template>
</el-table-column>
@ -116,49 +116,49 @@ link type="danger" @click="handleDelete(scope.row.id)"
<ContentWrap v-if="detailVisible" v-loading="detailLoading">
<div class="device-ledger-detail-header">
<div class="device-ledger-detail-title">详情</div>
<div class="device-ledger-detail-title">{{ t('EquipmentManagement.EquipmentLedger.detail') }}</div>
<el-button link @click="closeDetail">
<Icon icon="ep:close" />
</el-button>
</div>
<el-descriptions :column="3" class="device-ledger-detail-desc">
<el-descriptions-item label="设备编号">{{ detailData?.deviceCode ?? '' }}</el-descriptions-item>
<el-descriptions-item label="设备名称">{{ detailData?.deviceName ?? '' }}</el-descriptions-item>
<el-descriptions-item label="设备状态">
<el-descriptions-item :label="t('EquipmentManagement.EquipmentLedger.deviceNo')">{{ detailData?.deviceCode ?? '' }}</el-descriptions-item>
<el-descriptions-item :label="t('EquipmentManagement.EquipmentLedger.deviceName')">{{ detailData?.deviceName ?? '' }}</el-descriptions-item>
<el-descriptions-item :label="t('EquipmentManagement.EquipmentLedger.deviceStatus')">
<dict-tag type="mes_tz_status" :value="detailData?.deviceStatus" />
</el-descriptions-item>
<!-- <el-descriptions-item label="设备品牌">{{ detailData?.deviceBrand ?? '' }}</el-descriptions-item> -->
<el-descriptions-item label="设备型号">{{ detailData?.deviceModel ?? '' }}</el-descriptions-item>
<el-descriptions-item label="设备规格">{{ detailData?.deviceSpec ?? '' }}</el-descriptions-item>
<el-descriptions-item label="设备类型">
<!-- <el-descriptions-item :label="t('EquipmentManagement.EquipmentLedger.deviceBrand')">{{ detailData?.deviceBrand ?? '' }}</el-descriptions-item> -->
<el-descriptions-item :label="t('EquipmentManagement.EquipmentLedger.deviceModel')">{{ detailData?.deviceModel ?? '' }}</el-descriptions-item>
<el-descriptions-item :label="t('EquipmentManagement.EquipmentLedger.deviceSpec')">{{ detailData?.deviceSpec ?? '' }}</el-descriptions-item>
<el-descriptions-item :label="t('EquipmentManagement.EquipmentLedger.deviceType')">
<el-tag effect="light">{{ getDeviceTypeName(detailData?.deviceTypeName ?? detailData?.deviceType)
}}</el-tag>
</el-descriptions-item>
<!-- <el-descriptions-item label="供应商">{{ detailData?.supplier ?? '' }}</el-descriptions-item> -->
<el-descriptions-item label="所属车间">{{ detailData?.workshop ?? '' }}</el-descriptions-item>
<!-- <el-descriptions-item label="所属系统组织">{{ detailData?.systemOrg ?? '' }}</el-descriptions-item> -->
<el-descriptions-item label="设备位置">{{ detailData?.deviceLocation ?? '' }}</el-descriptions-item>
<el-descriptions-item label="设备负责人">{{ detailData?.deviceManagerName ?? '' }}</el-descriptions-item>
<el-descriptions-item label="设备生产日期">{{ formatDetailDate(detailData?.productionDate) }}</el-descriptions-item>
<el-descriptions-item label="设备入厂日期">{{ formatDetailDate(detailData?.factoryEntryDate)
<!-- <el-descriptions-item :label="t('EquipmentManagement.EquipmentLedger.supplier')">{{ detailData?.supplier ?? '' }}</el-descriptions-item> -->
<el-descriptions-item :label="t('EquipmentManagement.EquipmentLedger.workshop')">{{ detailData?.workshop ?? '' }}</el-descriptions-item>
<!-- <el-descriptions-item :label="t('EquipmentManagement.EquipmentLedger.systemOrg')">{{ detailData?.systemOrg ?? '' }}</el-descriptions-item> -->
<el-descriptions-item :label="t('EquipmentManagement.EquipmentLedger.deviceLocation')">{{ detailData?.deviceLocation ?? '' }}</el-descriptions-item>
<el-descriptions-item :label="t('EquipmentManagement.EquipmentLedger.deviceManagerName')">{{ detailData?.deviceManagerName ?? '' }}</el-descriptions-item>
<el-descriptions-item :label="t('EquipmentManagement.EquipmentLedger.productionDate')">{{ formatDetailDate(detailData?.productionDate) }}</el-descriptions-item>
<el-descriptions-item :label="t('EquipmentManagement.EquipmentLedger.factoryEntryDate')">{{ formatDetailDate(detailData?.factoryEntryDate)
}}</el-descriptions-item>
<el-descriptions-item label="备注">{{ detailData?.remark ?? detailData?.deviceRemark ?? ''
<el-descriptions-item :label="t('EquipmentManagement.EquipmentLedger.remark')">{{ detailData?.remark ?? detailData?.deviceRemark ?? ''
}}</el-descriptions-item>
</el-descriptions>
<el-tabs v-model="detailActiveTab" class="mt-12px">
<el-tab-pane label="点检履历" name="check">
<el-tab-pane :label="t('EquipmentManagement.EquipmentLedger.checkHistory')" name="check">
<div style="margin-bottom: 16px;">
<el-date-picker
v-model="inspectionDateRange" type="daterange" value-format="YYYY-MM-DD HH:mm:ss"
start-placeholder="开始时间" end-placeholder="结束时间" range-separator="至" :unlink-panels="true"
:start-placeholder="t('common.startTimeText')" :end-placeholder="t('common.endTimeText')" range-separator="-" :unlink-panels="true"
class="mr-10px" />
<el-button type="primary" plain @click="handleQueryInspection"></el-button>
<el-button @click="handleResetInspection"></el-button>
<el-button type="primary" plain @click="handleQueryInspection">{{ t('common.query') }}</el-button>
<el-button @click="handleResetInspection">{{ t('common.reset') }}</el-button>
<el-button
type="success" plain :loading="inspectionExportLoading" @click="handleExportInspection"
v-hasPermi="['mes:device-ledger:export']">
<Icon icon="ep:download" class="mr-5px" /> 导出
<Icon icon="ep:download" class="mr-5px" /> {{ t('action.export') }}
</el-button>
</div>
<el-empty v-if="!inspectionStepGroups.length" />
@ -169,7 +169,7 @@ v-else direction="vertical" :active="inspectionStepGroups.length"
<template #title>
<div class="device-ledger-history-title">
<span class="device-ledger-history-time">[{{ group.time }}]</span>
<span class="device-ledger-history-operator">操作人: {{ group.operator }}</span>
<span class="device-ledger-history-operator">{{ t('EquipmentManagement.EquipmentLedger.operator') }}: {{ group.operator }}</span>
</div>
</template>
<template #description>
@ -181,26 +181,26 @@ v-else direction="vertical" :active="inspectionStepGroups.length"
</div>
<div class="device-ledger-history-item-body">
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">点检方式</span>
<span class="device-ledger-history-item-label">{{ t('EquipmentManagement.EquipmentLedger.checkMethod') }}</span>
<span class="device-ledger-history-item-value">
<dict-tag type="Inspection_method" :value="item.method" />
</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">判定标准</span>
<span class="device-ledger-history-item-label">{{ t('EquipmentManagement.EquipmentLedger.criteria') }}</span>
<span class="device-ledger-history-item-value">{{ item.criteria ?? '-' }}</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">点检时间</span>
<span class="device-ledger-history-item-label">{{ t('EquipmentManagement.EquipmentLedger.checkTime') }}</span>
<span class="device-ledger-history-item-value">{{ formatHistoryTime(item.taskTime)
}}</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">创建时间</span>
<span class="device-ledger-history-item-label">{{ t('EquipmentManagement.EquipmentLedger.createTime') }}</span>
<span class="device-ledger-history-item-value">{{ formatHistoryTime(item.createTime) }}</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">备注</span>
<span class="device-ledger-history-item-label">{{ t('EquipmentManagement.EquipmentLedger.remark') }}</span>
<span class="device-ledger-history-item-value">{{ item.remark ?? '-' }}</span>
</div>
<div v-if="item.images?.length" class="device-ledger-history-item-images">
@ -219,18 +219,18 @@ v-for="img in item.images" :key="img" :src="img" :preview-src-list="item.images"
</el-step>
</el-steps>
</el-tab-pane>
<el-tab-pane label="保养履历" name="maintain">
<el-tab-pane :label="t('EquipmentManagement.EquipmentLedger.maintainHistory')" name="maintain">
<div style="margin-bottom: 16px;">
<el-date-picker
v-model="maintainDateRange" type="daterange" value-format="YYYY-MM-DD HH:mm:ss"
start-placeholder="开始时间" end-placeholder="结束时间" range-separator="至" :unlink-panels="true"
:start-placeholder="t('common.startTimeText')" :end-placeholder="t('common.endTimeText')" range-separator="-" :unlink-panels="true"
class="mr-10px" />
<el-button type="primary" plain @click="handleQueryMaintain"></el-button>
<el-button @click="handleResetMaintain"></el-button>
<el-button type="primary" plain @click="handleQueryMaintain">{{ t('common.query') }}</el-button>
<el-button @click="handleResetMaintain">{{ t('common.reset') }}</el-button>
<el-button
type="success" plain :loading="maintainExportLoading" @click="handleExportMaintain"
v-hasPermi="['mes:device-ledger:export']">
<Icon icon="ep:download" class="mr-5px" /> 导出
<Icon icon="ep:download" class="mr-5px" /> {{ t('action.export') }}
</el-button>
</div>
<el-empty v-if="!maintainStepGroups.length" />
@ -241,7 +241,7 @@ v-else direction="vertical" class="device-ledger-history-steps"
<template #title>
<div class="device-ledger-history-title">
<span class="device-ledger-history-time">[{{ group.time }}]</span>
<span class="device-ledger-history-operator">操作人: {{ group.operator }}</span>
<span class="device-ledger-history-operator">{{ t('EquipmentManagement.EquipmentLedger.operator') }}: {{ group.operator }}</span>
</div>
</template>
<template #description>
@ -253,27 +253,27 @@ v-else direction="vertical" class="device-ledger-history-steps"
</div>
<div class="device-ledger-history-item-body">
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">保养方式</span>
<span class="device-ledger-history-item-label">{{ t('EquipmentManagement.EquipmentLedger.maintainMethod') }}</span>
<span class="device-ledger-history-item-value">
<dict-tag type="Inspection_method" :value="item.method" />
</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">判定标准</span>
<span class="device-ledger-history-item-label">{{ t('EquipmentManagement.EquipmentLedger.criteria') }}</span>
<span class="device-ledger-history-item-value">{{ item.criteria ?? '-' }}</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">保养时间</span>
<span class="device-ledger-history-item-label">{{ t('EquipmentManagement.EquipmentLedger.maintainTime') }}</span>
<span class="device-ledger-history-item-value">
{{ String(formatHistoryTime(item.taskTime))}}
</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">创建时间</span>
<span class="device-ledger-history-item-label">{{ t('EquipmentManagement.EquipmentLedger.createTime') }}</span>
<span class="device-ledger-history-item-value">{{ formatHistoryTime(item.createTime) }}</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">备注</span>
<span class="device-ledger-history-item-label">{{ t('EquipmentManagement.EquipmentLedger.remark') }}</span>
<span class="device-ledger-history-item-value">{{ item.remark ?? '-' }}</span>
</div>
<div v-if="item.images?.length" class="device-ledger-history-item-images">
@ -292,18 +292,18 @@ v-for="img in item.images" :key="img" :src="img" :preview-src-list="item.images"
</el-step>
</el-steps>
</el-tab-pane>
<el-tab-pane label="维修履历" name="repair">
<el-tab-pane :label="t('EquipmentManagement.EquipmentLedger.repairHistory')" name="repair">
<div style="margin-bottom: 16px;">
<el-date-picker
v-model="repairDateRange" type="daterange" value-format="YYYY-MM-DD HH:mm:ss"
start-placeholder="开始时间" end-placeholder="结束时间" range-separator="至" :unlink-panels="true"
:start-placeholder="t('common.startTimeText')" :end-placeholder="t('common.endTimeText')" range-separator="-" :unlink-panels="true"
class="mr-10px" />
<el-button type="primary" plain @click="handleQueryRepair"></el-button>
<el-button @click="handleResetRepair"></el-button>
<el-button type="primary" plain @click="handleQueryRepair">{{ t('common.query') }}</el-button>
<el-button @click="handleResetRepair">{{ t('common.reset') }}</el-button>
<el-button
type="success" plain :loading="repairExportLoading" @click="handleExportRepair"
v-hasPermi="['mes:device-ledger:export']">
<Icon icon="ep:download" class="mr-5px" /> 导出
<Icon icon="ep:download" class="mr-5px" /> {{ t('action.export') }}
</el-button>
</div>
<el-empty v-if="!repairGroups.length" />
@ -325,11 +325,11 @@ v-for="row in group.items" :key="String(row.id ?? row.subjectId ?? row.subjectCo
</div>
<div class="device-ledger-history-item-body">
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">项目内容</span>
<span class="device-ledger-history-item-label">{{ t('EquipmentManagement.EquipmentLedger.projectName') }}</span>
<span class="device-ledger-history-item-value">{{ row.subjectContent ?? '-' }}</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">维修结果</span>
<span class="device-ledger-history-item-label">{{ t('EquipmentManagement.EquipmentLedger.repairResult') }}</span>
<span class="device-ledger-history-item-value">
<el-tag :type="getResultTagType(row.result ?? row.repairResult)">
{{ getResultLabel(row.repairResult ?? row.result) }}
@ -337,11 +337,11 @@ v-for="row in group.items" :key="String(row.id ?? row.subjectId ?? row.subjectCo
</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">备注</span>
<span class="device-ledger-history-item-label">{{ t('EquipmentManagement.EquipmentLedger.remark') }}</span>
<span class="device-ledger-history-item-value">{{ row.remark ?? '-' }}</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">完成日期</span>
<span class="device-ledger-history-item-label">{{ t('EquipmentManagement.EquipmentLedger.finishDate') }}</span>
<span class="device-ledger-history-item-value">{{
String(formatHistoryTime(row.finishDate)).split(' ')[0] }}</span>
</div>
@ -361,53 +361,46 @@ v-for="img in row.malfunctionImages" :key="img" :src="img"
</el-collapse-item>
</el-collapse>
</el-tab-pane>
<el-tab-pane label="关键件" name="criticalComponent">
<el-tab-pane :label="t('EquipmentManagement.EquipmentLedger.criticalComponent')" name="criticalComponent">
<div class="device-ledger-tab-toolbar">
<el-button
type="success" plain :loading="criticalExportLoading" @click="handleExportCriticalComponent"
v-hasPermi="['mes:device-ledger:export']">
<Icon icon="ep:download" class="mr-5px" /> 导出
<Icon icon="ep:download" class="mr-5px" /> {{ t('action.export') }}
</el-button>
</div>
<el-table
v-loading="loading" :data="detailData?.componentList" :stripe="true"
:show-overflow-tooltip="true">
<el-table-column label="编码" align="center" prop="code" min-width="140" />
<el-table-column label="名称" align="center" prop="name" min-width="140" />
<el-table-column label="描述" align="center" prop="description" min-width="180" />
<el-table-column label="备注" align="center" prop="remark" min-width="180" />
<el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180" />
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.componentCode')" align="center" prop="code" min-width="140" />
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.componentName')" align="center" prop="name" min-width="140" />
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.componentDesc')" align="center" prop="description" min-width="180" />
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.remark')" align="center" prop="remark" min-width="180" />
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.createTime')" align="center" prop="createTime" :formatter="dateFormatter" width="180" />
</el-table>
</el-tab-pane>
<el-tab-pane label="备件" name="component">
<el-tab-pane :label="t('EquipmentManagement.EquipmentLedger.sparePart')" name="component">
<div class="device-ledger-tab-toolbar">
<el-button
type="success" plain :loading="spareExportLoading" @click="handleExportSpareBased"
v-hasPermi="['mes:device-ledger:export']">
<Icon icon="ep:download" class="mr-5px" /> 导出
<Icon icon="ep:download" class="mr-5px" /> {{ t('action.export') }}
</el-button>
</div>
<el-table v-loading="loading" :data="detailData?.beijianList" :stripe="true" :show-overflow-tooltip="true">
<el-table-column label="备件编码" align="center" prop="barCode" />
<el-table-column label="备件名称" align="left" prop="name" width="220px" />
<el-table-column label="分类" align="center" prop="categoryName" />
<el-table-column label="单位" align="center" prop="unitName" />
<el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180px" />
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.spareCode')" align="center" prop="barCode" />
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.spareName')" align="left" prop="name" width="220px" />
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.category')" align="center" prop="categoryName" />
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.unit')" align="center" prop="unitName" />
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.createTime')" align="center" prop="createTime" :formatter="dateFormatter" width="180px" />
</el-table>
</el-tab-pane>
<el-tab-pane label="模具" name="mold">
<div class="device-ledger-tab-toolbar">
<el-button
type="success" plain :loading="moldExportLoading" @click="handleExportMold"
v-hasPermi="['mes:device-ledger:export']">
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
</div>
<el-table v-loading="loading" :data="detailData?.moldList" :stripe="true" :show-overflow-tooltip="true">
<el-table-column label="编码" align="center" prop="code" min-width="140" />
<el-table-column label="名称" align="center" prop="name" min-width="140" />
<el-table-column label="备注" align="center" prop="remark" min-width="180" />
<el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180" />
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.moldCode')" align="center" prop="code" min-width="140" />
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.moldName')" align="center" prop="name" min-width="140" />
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.moldRemark')" align="center" prop="remark" min-width="180" />
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.createTime')" align="center" prop="createTime" :formatter="dateFormatter" width="180" />
</el-table>
<Pagination
:total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
@ -456,7 +449,6 @@ const queryFormRef = ref() // 搜索的表单
const exportLoading = ref(false) //
const criticalExportLoading = ref(false)
const spareExportLoading = ref(false)
const moldExportLoading = ref(false)
const inspectionExportLoading = ref(false)
const inspectionDateRange = ref<string[] | undefined>(undefined)
const maintainExportLoading = ref(false)
@ -954,7 +946,6 @@ const handleExportCriticalComponent = async () => {
}
}
//
const handleExportSpareBased = async () => {
if (!selectedDetailId.value) {
message.error('请先选择设备')
@ -971,23 +962,6 @@ const handleExportSpareBased = async () => {
}
}
//
const handleExportMold = async () => {
if (!selectedDetailId.value) {
message.error('请先选择设备')
return
}
try {
await message.exportConfirm()
moldExportLoading.value = true
const data = await DeviceLedgerApi.exportMold({ id: selectedDetailId.value })
download.excel(data, '模具.xls')
} catch {
} finally {
moldExportLoading.value = false
}
}
const handleExportInspection = async () => {
if (!selectedDetailId.value) {
message.error('请先选择设备')
@ -1109,7 +1083,7 @@ onMounted(async () => {
.device-ledger-tab-toolbar {
margin-bottom: 8px;
text-align: left;
text-align: right;
}
.device-ledger-history-items {

@ -7,22 +7,22 @@
label-width="100px"
v-loading="formLoading"
>
<el-form-item label="编码" prop="code">
<el-input v-model="formData.code" placeholder="请输入编码" />
<el-form-item :label="t('EquipmentManagement.EquipmentClassification.code')" prop="code">
<el-input v-model="formData.code" :placeholder="t('EquipmentManagement.EquipmentClassification.placeholderCode')" />
</el-form-item>
<el-form-item label="名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入名称" />
<el-form-item :label="t('EquipmentManagement.EquipmentClassification.name')" prop="name">
<el-input v-model="formData.name" :placeholder="t('EquipmentManagement.EquipmentClassification.placeholderName')" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" placeholder="请输入备注" />
<el-form-item :label="t('EquipmentManagement.EquipmentClassification.remark')" prop="remark">
<el-input v-model="formData.remark" :placeholder="t('EquipmentManagement.EquipmentClassification.placeholderRemark')" />
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input v-model="formData.sort" placeholder="请输入排序" />
<el-form-item :label="t('EquipmentManagement.EquipmentClassification.sort')" prop="sort">
<el-input v-model="formData.sort" :placeholder="t('EquipmentManagement.EquipmentClassification.placeholderSort')" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
<el-button @click="submitForm" type="primary" :disabled="formLoading">{{ t('common.ok') }}</el-button>
<el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
</template>

@ -8,44 +8,44 @@
:inline="true"
label-width="68px"
>
<el-form-item label="编码" prop="code">
<el-form-item :label="t('EquipmentManagement.EquipmentClassification.code')" prop="code">
<el-input
v-model="queryParams.code"
placeholder="请输入编码"
:placeholder="t('EquipmentManagement.EquipmentClassification.placeholderCode')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="名称" prop="name">
<el-form-item :label="t('EquipmentManagement.EquipmentClassification.name')" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入名称"
:placeholder="t('EquipmentManagement.EquipmentClassification.placeholderName')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-form-item :label="t('EquipmentManagement.EquipmentClassification.createTime')" prop="createTime">
<el-date-picker
v-model="queryParams.createTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:start-placeholder="t('common.startTimeText')"
:end-placeholder="t('common.endTimeText')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-220px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> {{ t('common.query') }}</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> {{ t('common.reset') }}</el-button>
<el-button
type="primary"
plain
@click="openForm('create')"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
<Icon icon="ep:plus" class="mr-5px" /> {{ t('action.add') }}
</el-button>
<el-button
type="success"
@ -54,7 +54,7 @@
:loading="exportLoading"
v-hasPermi="['mes:device-type:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
<Icon icon="ep:download" class="mr-5px" /> {{ t('action.export') }}
</el-button>
</el-form-item>
</el-form>
@ -71,40 +71,40 @@
default-expand-all
:tree-props="{ children: 'children' }"
>
<el-table-column label="id" align="center" prop="id" />
<el-table-column label="编码" align="center" prop="code" />
<el-table-column label="名称" align="center" prop="name" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="排序" align="center" prop="sort" />
<!-- <el-table-column :label="t('EquipmentManagement.EquipmentClassification.id')" align="center" prop="id" /> -->
<el-table-column :label="t('EquipmentManagement.EquipmentClassification.code')" align="center" prop="code" />
<el-table-column :label="t('EquipmentManagement.EquipmentClassification.name')" align="center" prop="name" />
<el-table-column :label="t('EquipmentManagement.EquipmentClassification.remark')" align="center" prop="remark" />
<el-table-column :label="t('EquipmentManagement.EquipmentClassification.sort')" align="center" prop="sort" />
<el-table-column
label="创建时间"
:label="t('EquipmentManagement.EquipmentClassification.createTime')"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="操作" align="center" min-width="120px">
<el-table-column :label="t('EquipmentManagement.EquipmentClassification.operate')" align="center" min-width="120px">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('create', undefined, scope.row)"
>
添加
{{ t('EquipmentManagement.EquipmentClassification.add') }}
</el-button>
<el-button
link
type="primary"
@click="openForm('update', scope.row.id, scope.row)"
>
编辑
{{ t('EquipmentManagement.EquipmentClassification.edit') }}
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
>
删除
{{ t('EquipmentManagement.EquipmentClassification.delete') }}
</el-button>
</template>
</el-table-column>

@ -3,37 +3,44 @@
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px" v-loading="formLoading">
<el-row>
<el-col :span="8">
<el-form-item label="维修单编号" prop="repairCode">
<el-input v-model="formData.repairCode" placeholder="请输入维修单编号" :disabled="isRepairMode" />
<el-form-item :label="t('EquipmentManagement.DvRepair.repairCode')" prop="repairCode">
<el-input
v-model="formData.repairCode"
:placeholder="t('EquipmentManagement.DvRepair.placeholderRepairCode')"
:disabled="isRepairMode" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="维修单" prop="repairName">
<el-input v-model="formData.repairName" placeholder="请输入维修单名称" :disabled="isRepairMode" />
<el-form-item :label="t('EquipmentManagement.DvRepair.repairName')" prop="repairName">
<el-input
v-model="formData.repairName"
:placeholder="t('EquipmentManagement.DvRepair.placeholderRepairName')"
:disabled="isRepairMode" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="设备类型" prop="machineryTypeId">
<el-form-item :label="t('EquipmentManagement.DvRepair.machineryTypeId')" prop="machineryTypeId">
<el-radio-group v-model="formData.machineryTypeId" :disabled="isRepairMode">
<el-radio :label="1">设备</el-radio>
<el-radio :label="2">关键件</el-radio>
<el-radio :label="1">{{ t('EquipmentManagement.DvRepair.machineryTypeDevice') }}</el-radio>
<el-radio :label="2">{{ t('EquipmentManagement.DvRepair.machineryTypeKeyItem') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-row>
<el-col :span="8">
<el-form-item label="设备" prop="deviceId">
<el-form-item :label="t('EquipmentManagement.DvRepair.device')" prop="deviceId">
<el-select
v-model="formData.deviceId" filterable clearable :loading="deviceLoading"
:disabled="isRepairMode" placeholder="请选择设备" class="!w-full">
v-model="formData.deviceId" filterable clearable :loading="deviceLoading"
:disabled="isRepairMode"
:placeholder="t('EquipmentManagement.DvRepair.placeholderDevice')" class="!w-full">
<el-option v-for="opt in deviceOptions" :key="String(opt.value)" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
<el-form-item v-if="showComponentSelect" label="关键件" prop="componentId">
<el-form-item v-if="showComponentSelect" :label="t('EquipmentManagement.DvRepair.component')" prop="componentId">
<el-select
v-model="formData.componentId" clearable :loading="componentLoading" :disabled="isRepairMode"
placeholder="请选择关键件" class="!w-full">
v-model="formData.componentId" clearable :loading="componentLoading" :disabled="isRepairMode"
:placeholder="t('EquipmentManagement.DvRepair.placeholderComponent')" class="!w-full">
<el-option
v-for="opt in componentOptions" :key="String(opt.value)" :label="opt.label"
v-for="opt in componentOptions" :key="String(opt.value)" :label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
@ -41,33 +48,45 @@ v-for="opt in componentOptions" :key="String(opt.value)" :label="opt.label"
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="设备名称" prop="machineryName" :required="false">
<el-input v-model="formData.machineryName" placeholder="自动带出" disabled />
<el-form-item :label="t('EquipmentManagement.DvRepair.machineryName')" prop="machineryName" :required="false">
<el-input
v-model="formData.machineryName"
:placeholder="t('EquipmentManagement.DvRepair.placeholderAutoFill')"
disabled />
</el-form-item>
</el-col>
<el-col :span="8"> <el-form-item label="设备编码" prop="machineryCode" :required="false">
<el-input v-model="formData.machineryCode" placeholder="自动带出" disabled />
<el-col :span="8">
<el-form-item :label="t('EquipmentManagement.DvRepair.machineryCode')" prop="machineryCode" :required="false">
<el-input
v-model="formData.machineryCode"
:placeholder="t('EquipmentManagement.DvRepair.placeholderAutoFill')"
disabled />
</el-form-item></el-col>
<el-col :span="8">
<el-form-item label="规格型号" prop="machinerySpec" :required="false">
<el-input v-model="formData.machinerySpec" placeholder="自动带出" disabled />
<el-form-item :label="t('EquipmentManagement.DvRepair.machinerySpec')" prop="machinerySpec" :required="false">
<el-input
v-model="formData.machinerySpec"
:placeholder="t('EquipmentManagement.DvRepair.placeholderAutoFill')"
disabled />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="维修人员" prop="acceptedBy">
<el-form-item :label="t('EquipmentManagement.DvRepair.acceptedBy')" prop="acceptedBy">
<el-select
v-model="formData.acceptedBy" filterable clearable placeholder="请选择维修人员" class="!w-full"
v-model="formData.acceptedBy" filterable clearable
:placeholder="t('EquipmentManagement.DvRepair.placeholderAcceptedBy')" class="!w-full"
:disabled="isRepairMode">
<el-option v-for="item in users" :key="String(item.id)" :label="item.nickname" :value="String(item.id)" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="验收人员" prop="confirmBy">
<el-form-item :label="t('EquipmentManagement.DvRepair.confirmBy')" prop="confirmBy">
<el-select
v-model="formData.confirmBy" filterable clearable placeholder="请选择验收人员" class="!w-full"
v-model="formData.confirmBy" filterable clearable
:placeholder="t('EquipmentManagement.DvRepair.placeholderConfirmBy')" class="!w-full"
:disabled="isRepairMode">
<el-option v-for="item in users" :key="String(item.id)" :label="item.nickname" :value="String(item.id)" />
</el-select>
@ -78,41 +97,44 @@ v-model="formData.confirmBy" filterable clearable placeholder="请选择验收
<template v-if="showRepairFields">
<el-row>
<el-col :span="8">
<el-form-item label="报修日期" prop="requireDate">
<el-form-item :label="t('EquipmentManagement.DvRepair.requireDate')" prop="requireDate">
<el-date-picker
v-model="formData.requireDate" type="date" value-format="x" placeholder="选择报修日期"
v-model="formData.requireDate" type="date" value-format="x"
:placeholder="t('EquipmentManagement.DvRepair.placeholderRequireDate')"
class="!w-full" :disabled="repairFieldsDisabled" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="完成日期" prop="finishDate">
<el-form-item :label="t('EquipmentManagement.DvRepair.finishDate')" prop="finishDate">
<el-date-picker
v-model="formData.finishDate" type="date" value-format="x" placeholder="选择完成日期"
v-model="formData.finishDate" type="date" value-format="x"
:placeholder="t('EquipmentManagement.DvRepair.placeholderFinishDate')"
class="!w-full" :disabled="repairFieldsDisabled" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="验收日期" prop="confirmDate">
<el-form-item :label="t('EquipmentManagement.DvRepair.confirmDate')" prop="confirmDate">
<el-date-picker
v-model="formData.confirmDate" type="date" value-format="x" placeholder="选择验收日期"
v-model="formData.confirmDate" type="date" value-format="x"
:placeholder="t('EquipmentManagement.DvRepair.placeholderConfirmDate')"
class="!w-full" :disabled="repairFieldsDisabled" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="维修结果" prop="repairResult">
<el-form-item :label="t('EquipmentManagement.DvRepair.repairResult')" prop="repairResult">
<Editor v-model="formData.repairResult" height="150px" :readonly="repairFieldsDisabled" />
</el-form-item>
</template>
</el-form>
<!-- 子表的表单 -->
<el-tabs v-model="subTabsName">
<el-tab-pane label="设备维修项目行" name="dvRepairLine">
<el-tab-pane :label="t('EquipmentManagement.DvRepair.repairLineTitle')" name="dvRepairLine">
<DvRepairLineForm ref="dvRepairLineFormRef" :repair-id="formData.id" :line-mode="lineMode" />
</el-tab-pane>
</el-tabs>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
<el-button @click="submitForm" type="primary" :disabled="formLoading">{{ t('common.ok') }}</el-button>
<el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
</template>
@ -296,16 +318,16 @@ watch(
}
)
const formRules = reactive({
repairCode: [{ required: true, message: '维修单编号不能为空', trigger: 'blur' }],
machineryId: [{ required: true, message: '设备ID不能为空', trigger: 'blur' }],
machineryCode: [{ required: true, message: '设备编码不能为空', trigger: 'blur' }],
machineryName: [{ required: true, message: '设备名称不能为空', trigger: 'blur' }],
machineryTypeId: [{ required: true, message: '设备类型不能为空', trigger: 'blur' }],
repairCode: [{ required: true, message: t('EquipmentManagement.DvRepair.validatorRepairCodeRequired'), trigger: 'blur' }],
machineryId: [{ required: true, message: t('EquipmentManagement.DvRepair.validatorMachineryIdRequired'), trigger: 'blur' }],
machineryCode: [{ required: true, message: t('EquipmentManagement.DvRepair.validatorMachineryCodeRequired'), trigger: 'blur' }],
machineryName: [{ required: true, message: t('EquipmentManagement.DvRepair.validatorMachineryNameRequired'), trigger: 'blur' }],
machineryTypeId: [{ required: true, message: t('EquipmentManagement.DvRepair.validatorMachineryTypeIdRequired'), trigger: 'blur' }],
requireDate: [
{
validator: (_: any, value: any, callback: any) => {
if (formType.value === 'repair' && !value) {
callback(new Error('报修日期不能为空'))
callback(new Error(t('EquipmentManagement.DvRepair.validatorRequireDateRequired')))
return
}
callback()
@ -317,7 +339,7 @@ const formRules = reactive({
{
validator: (_: any, value: any, callback: any) => {
if (formType.value === 'repair' && !value) {
callback(new Error('完成日期不能为空'))
callback(new Error(t('EquipmentManagement.DvRepair.validatorFinishDateRequired')))
return
}
callback()
@ -329,7 +351,7 @@ const formRules = reactive({
{
validator: (_: any, value: any, callback: any) => {
if (formType.value === 'repair' && !value) {
callback(new Error('验收日期不能为空'))
callback(new Error(t('EquipmentManagement.DvRepair.validatorConfirmDateRequired')))
return
}
callback()
@ -341,7 +363,7 @@ const formRules = reactive({
{
validator: (_: any, value: any, callback: any) => {
if (formType.value === 'repair' && !value) {
callback(new Error('维修结果不能为空'))
callback(new Error(t('EquipmentManagement.DvRepair.validatorRepairResultRequired')))
return
}
callback()

@ -8,7 +8,7 @@
:inline-message="true"
>
<el-table :data="formData" class="-mt-10px">
<el-table-column label="序号" type="index" width="100" />
<el-table-column :label="t('EquipmentManagement.DvRepair.index')" type="index" width="100" />
<!-- <el-table-column label="项目ID" min-width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.subjectId`" :rules="formRules.subjectId" class="mb-0px!">
@ -16,23 +16,23 @@
</el-form-item>
</template>
</el-table-column> -->
<el-table-column label="维修编码" min-width="150">
<el-table-column :label="t('EquipmentManagement.DvRepair.lineSubjectCode')" min-width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.subjectCode`" :rules="formRules.subjectCode" class="mb-0px!">
<el-input
v-model="row.subjectCode"
placeholder="请输入维修编码"
:placeholder="t('EquipmentManagement.DvRepair.placeholderLineSubjectCode')"
:disabled="props.lineMode !== 'edit'"
/>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="维修名称" min-width="150">
<el-table-column :label="t('EquipmentManagement.DvRepair.lineSubjectName')" min-width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.subjectName`" :rules="formRules.subjectName" class="mb-0px!">
<el-input
v-model="row.subjectName"
placeholder="请输入维修名称"
:placeholder="t('EquipmentManagement.DvRepair.placeholderLineSubjectName')"
:disabled="props.lineMode !== 'edit'"
/>
</el-form-item>
@ -45,13 +45,13 @@
</el-form-item>
</template>
</el-table-column> -->
<el-table-column label="维修内容" min-width="300">
<el-table-column :label="t('EquipmentManagement.DvRepair.lineSubjectContent')" min-width="300">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.subjectContent`" :rules="formRules.subjectContent" class="mb-0px!">
<el-input
type="textarea"
v-model="row.subjectContent"
placeholder="请输入维修内容"
:placeholder="t('EquipmentManagement.DvRepair.placeholderLineSubjectContent')"
:disabled="props.lineMode !== 'edit'"
/>
</el-form-item>
@ -59,14 +59,14 @@
</el-table-column>
<el-table-column
v-if="props.lineMode === 'repair' || props.lineMode === 'readonlyWithResult'"
label="备注"
:label="t('EquipmentManagement.DvRepair.lineRemark')"
min-width="180"
>
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.remark`" :rules="formRules.remark" class="mb-0px!">
<el-input
v-model="row.remark"
placeholder="请输入备注"
:placeholder="t('EquipmentManagement.DvRepair.placeholderLineRemark')"
:disabled="props.lineMode !== 'repair'"
/>
</el-form-item>
@ -74,14 +74,14 @@
</el-table-column>
<el-table-column
v-if="props.lineMode === 'repair' || props.lineMode === 'readonlyWithResult'"
label="结果"
:label="t('EquipmentManagement.DvRepair.lineResult')"
min-width="160"
>
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.result`" :rules="formRules.result" class="mb-0px!">
<el-radio-group v-model="row.result" :disabled="props.lineMode !== 'repair'">
<el-radio :value="1">通过</el-radio>
<el-radio :value="2">不通过</el-radio>
<el-radio :value="1">{{ t('EquipmentManagement.DvRepair.lineResultOk') }}</el-radio>
<el-radio :value="2">{{ t('EquipmentManagement.DvRepair.lineResultNg') }}</el-radio>
</el-radio-group>
</el-form-item>
</template>
@ -139,18 +139,19 @@ const props = defineProps<{
repairId: undefined
lineMode?: 'edit' | 'repair' | 'readonlyWithResult'
}>()
const { t } = useI18n()
const formLoading = ref(false) //
const formData = ref([])
const formRules = reactive({
repairId: [{ required: true, message: '维修单ID不能为空', trigger: 'blur' }],
subjectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }],
subjectCode: [{ required: true, message: '项目编码不能为空', trigger: 'blur' }],
subjectContent: [{ required: true, message: '项目内容不能为空', trigger: 'blur' }],
repairId: [{ required: true, message: t('EquipmentManagement.DvRepair.validatorLineRepairIdRequired'), trigger: 'blur' }],
subjectId: [{ required: true, message: t('EquipmentManagement.DvRepair.validatorLineSubjectIdRequired'), trigger: 'blur' }],
subjectCode: [{ required: true, message: t('EquipmentManagement.DvRepair.validatorLineSubjectCodeRequired'), trigger: 'blur' }],
subjectContent: [{ required: true, message: t('EquipmentManagement.DvRepair.validatorLineSubjectContentRequired'), trigger: 'blur' }],
remark: [
{
validator: (_: any, value: any, callback: any) => {
if (props.lineMode === 'repair' && !value) {
callback(new Error('备注不能为空'))
callback(new Error(t('EquipmentManagement.DvRepair.validatorLineRemarkRequired')))
return
}
callback()
@ -162,7 +163,7 @@ const formRules = reactive({
{
validator: (_: any, value: any, callback: any) => {
if (props.lineMode === 'repair' && (value === undefined || value === null || value === '')) {
callback(new Error('结果不能为空'))
callback(new Error(t('EquipmentManagement.DvRepair.validatorLineResultRequired')))
return
}
callback()

@ -2,69 +2,100 @@
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="维修单号" prop="repairCode">
<el-form-item :label="t('EquipmentManagement.DvRepair.repairCode')" prop="repairCode">
<el-input
v-model="queryParams.repairCode" placeholder="请输入维修单编号" clearable @keyup.enter="handleQuery"
v-model="queryParams.repairCode"
:placeholder="t('EquipmentManagement.DvRepair.placeholderRepairCode')"
clearable
@keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="维修单" prop="repairName">
<el-form-item :label="t('EquipmentManagement.DvRepair.repairName')" prop="repairName">
<el-input
v-model="queryParams.repairName" placeholder="请输入维修单名称" clearable @keyup.enter="handleQuery"
v-model="queryParams.repairName"
:placeholder="t('EquipmentManagement.DvRepair.placeholderRepairName')"
clearable
@keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="设备名称" prop="machineryName">
<el-form-item :label="t('EquipmentManagement.DvRepair.machineryName')" prop="machineryName">
<el-input
v-model="queryParams.machineryName" placeholder="请输入设备名称" clearable @keyup.enter="handleQuery"
v-model="queryParams.machineryName"
:placeholder="t('EquipmentManagement.DvRepair.placeholderMachineryName')"
clearable
@keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="报修日期" prop="requireDate">
<el-form-item :label="t('EquipmentManagement.DvRepair.requireDate')" prop="requireDate">
<el-date-picker
v-model="queryParams.requireDate" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
start-placeholder="开始日期" end-placeholder="结束日期"
v-model="queryParams.requireDate"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
:start-placeholder="t('common.startTime')"
:end-placeholder="t('common.endTime')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-240px" />
</el-form-item>
<el-form-item label="完成日期" prop="finishDate">
<el-form-item :label="t('EquipmentManagement.DvRepair.finishDate')" prop="finishDate">
<el-date-picker
v-model="queryParams.finishDate" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
start-placeholder="开始日期" end-placeholder="结束日期"
v-model="queryParams.finishDate"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
:start-placeholder="t('common.startTime')"
:end-placeholder="t('common.endTime')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-240px" />
</el-form-item>
<el-form-item label="验收日期" prop="confirmDate">
<el-form-item :label="t('EquipmentManagement.DvRepair.confirmDate')" prop="confirmDate">
<el-date-picker
v-model="queryParams.confirmDate" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
start-placeholder="开始日期" end-placeholder="结束日期"
v-model="queryParams.confirmDate"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
:start-placeholder="t('common.startTime')"
:end-placeholder="t('common.endTime')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-240px" />
</el-form-item>
<el-form-item label="维修人员" prop="acceptedBy">
<el-form-item :label="t('EquipmentManagement.DvRepair.acceptedBy')" prop="acceptedBy">
<el-input
v-model="queryParams.acceptedBy" placeholder="请输入维修人员" clearable @keyup.enter="handleQuery"
v-model="queryParams.acceptedBy"
:placeholder="t('EquipmentManagement.DvRepair.placeholderAcceptedBy')"
clearable
@keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="单据状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择单据状态" clearable class="!w-240px">
<el-form-item :label="t('EquipmentManagement.DvRepair.status')" prop="status">
<el-select
v-model="queryParams.status"
:placeholder="t('EquipmentManagement.DvRepair.placeholderStatus')"
clearable
class="!w-240px"
>
<el-option v-for="opt in statusOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> 搜索
<Icon icon="ep:search" class="mr-5px" />
{{ t('common.query') }}
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
<Icon icon="ep:refresh" class="mr-5px" />
{{ t('common.reset') }}
</el-button>
<el-button type="primary" plain @click="openForm('create')" v-hasPermi="['mes:dv-repair:create']">
<Icon icon="ep:plus" class="mr-5px" /> 新增
<Icon icon="ep:plus" class="mr-5px" />
{{ t('action.add') }}
</el-button>
<el-button type="danger" plain @click="handleBatchDelete" v-hasPermi="['mes:dv-repair:delete']">
<Icon icon="ep:delete" class="mr-5px" /> 批量删除
<Icon icon="ep:delete" class="mr-5px" />
{{ t('EquipmentManagement.DvRepair.batchDelete') }}
</el-button>
<el-button
type="success" plain @click="handleExport" :loading="exportLoading"
type="success" plain @click="handleExport" :loading="exportLoading"
v-hasPermi="['mes:dv-repair:export']">
<Icon icon="ep:download" class="mr-5px" /> 导出
<Icon icon="ep:download" class="mr-5px" />
{{ t('action.export') }}
</el-button>
</el-form-item>
</el-form>
@ -73,34 +104,54 @@ type="success" plain @click="handleExport" :loading="exportLoading"
<!-- 列表 -->
<ContentWrap>
<el-table
ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" row-key="id"
ref="tableRef"
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
row-key="id"
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" fixed="left" reserve-selection />
<el-table-column label="维修单号" align="center" prop="repairCode" />
<el-table-column label="维修单" align="center" prop="repairName" />
<el-table-column label="设备" align="center" prop="machineryName" />
<el-table-column label="设备编码" align="center" prop="machineryCode" />
<el-table-column :label="t('EquipmentManagement.DvRepair.repairCode')" align="center" prop="repairCode" />
<el-table-column :label="t('EquipmentManagement.DvRepair.repairName')" align="center" prop="repairName" />
<el-table-column :label="t('EquipmentManagement.DvRepair.machineryName')" align="center" prop="machineryName" />
<el-table-column :label="t('EquipmentManagement.DvRepair.machineryCode')" align="center" prop="machineryCode" />
<!-- <el-table-column label="品牌" align="center" prop="machineryBrand" /> -->
<el-table-column label="规格型号" align="center" prop="machinerySpec" />
<el-table-column label="设备类型" align="center" prop="machineryTypeId" width="100px">
<el-table-column :label="t('EquipmentManagement.DvRepair.machinerySpec')" align="center" prop="machinerySpec" />
<el-table-column :label="t('EquipmentManagement.DvRepair.machineryType')" align="center" prop="machineryTypeId" width="100px">
<template #default="scope">
<dict-tag :type="DICT_TYPE.MES_MACHINE_TYPE" :value="scope.row.machineryTypeId" />
</template>
</el-table-column>
<el-table-column label="报修日期" align="center" prop="requireDate" :formatter="dateFormatter2" width="110px" />
<el-table-column label="完成日期" align="center" prop="finishDate" :formatter="dateFormatter2" width="110px" />
<el-table-column label="验收日期" align="center" prop="confirmDate" :formatter="dateFormatter2" width="110px" />
<el-table-column label="维修结果" align="center" prop="repairResult" />
<el-table-column label="维修人员" align="center" prop="acceptedBy" />
<el-table-column label="验收人员" align="center" prop="confirmBy" />
<el-table-column label="单据状态" align="center" prop="status" width="110px">
<el-table-column
:label="t('EquipmentManagement.DvRepair.requireDate')"
align="center"
prop="requireDate"
:formatter="dateFormatter2"
width="110px" />
<el-table-column
:label="t('EquipmentManagement.DvRepair.finishDate')"
align="center"
prop="finishDate"
:formatter="dateFormatter2"
width="110px" />
<el-table-column
:label="t('EquipmentManagement.DvRepair.confirmDate')"
align="center"
prop="confirmDate"
:formatter="dateFormatter2"
width="110px" />
<el-table-column :label="t('EquipmentManagement.DvRepair.repairResult')" align="center" prop="repairResult" />
<el-table-column :label="t('EquipmentManagement.DvRepair.acceptedBy')" align="center" prop="acceptedBy" />
<el-table-column :label="t('EquipmentManagement.DvRepair.confirmBy')" align="center" prop="confirmBy" />
<el-table-column :label="t('EquipmentManagement.DvRepair.status')" align="center" prop="status" width="110px">
<template #default="scope">
<el-tag :type="getStatusTagType(scope.row.status)" effect="light">
{{ getStatusLabel(scope.row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="结果" align="center" prop="repairStatus" min-width="120">
<el-table-column :label="t('EquipmentManagement.DvRepair.repairStatus')" align="center" prop="repairStatus" min-width="120">
<template #default="scope">
<el-tag :type="getResultTagType(scope.row.repairStatus)" effect="light">
{{ getResultLabel(scope.row.repairStatus) }}
@ -109,27 +160,29 @@ ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-to
</el-table-column>
<!-- <el-table-column label="备注" align="center" prop="remark" /> -->
<el-table-column
label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="170px"
:label="t('EquipmentManagement.DvRepair.createTime')" align="center" prop="createTime" :formatter="dateFormatter" width="170px"
fixed="right" />
<el-table-column label="操作" align="center" fixed="right" width="200px">
<el-table-column :label="t('EquipmentManagement.DvRepair.operate')" align="center" fixed="right" width="200px">
<template #default="scope">
<el-button
link type="primary" @click="openForm('repair', scope.row.id)"
v-if="String(scope.row.status) !== '1'" v-hasPermi="['mes:dv-repair:update']">维修</el-button>
link type="primary" @click="openForm('repair', scope.row.id)"
v-if="String(scope.row.status) !== '1'" v-hasPermi="['mes:dv-repair:update']">
{{ t('EquipmentManagement.DvRepair.repair') }}
</el-button>
<el-button
link type="primary" @click="openForm('update', scope.row.id)"
link type="primary" @click="openForm('update', scope.row.id)"
v-hasPermi="['mes:dv-repair:update']">
编辑
{{ t('action.update') }}
</el-button>
<el-button link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['mes:dv-repair:delete']">
删除
{{ t('action.delete') }}
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
:total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
@pagination="getList" />
</ContentWrap>
@ -178,14 +231,14 @@ const queryFormRef = ref() // 搜索的表单
const exportLoading = ref(false) //
const statusOptions = [
{ label: '待完成', value: '0' },
{ label: '已完成', value: '1' }
{ label: t('EquipmentManagement.DvRepair.statusPending'), value: '0' },
{ label: t('EquipmentManagement.DvRepair.statusFinished'), value: '1' }
]
const getStatusLabel = (value: any) => {
const v = value === '' || value === null || value === undefined ? undefined : String(value)
if (v === '0') return '待完成'
if (v === '1') return '已完成'
if (v === '0') return t('EquipmentManagement.DvRepair.statusPending')
if (v === '1') return t('EquipmentManagement.DvRepair.statusFinished')
return '-'
}
@ -198,9 +251,9 @@ const getStatusTagType = (value: any) => {
const getResultLabel = (value: any) => {
const v = value === '' || value === null || value === undefined ? undefined : String(value)
if (v == '0') return '待维修'
if (v == '1') return '通过'
if (v == '2') return '不通过'
if (v == '0') return t('EquipmentManagement.DvRepair.repairResultPending')
if (v == '1') return t('EquipmentManagement.DvRepair.repairResultOk')
if (v == '2') return t('EquipmentManagement.DvRepair.repairResultNg')
return '-'
}
@ -274,7 +327,7 @@ const handleDelete = async (ids: number | number[]) => {
const handleBatchDelete = async () => {
if (!selectedIds.value.length) {
message.error('请选择需要删除的数据')
message.error(t('EquipmentManagement.DvRepair.selectDeleteTip'))
return
}
await handleDelete(selectedIds.value)
@ -294,7 +347,7 @@ const handleExport = async () => {
}
: queryParams
)
download.excel(data, '设备维修记录.xls')
download.excel(data, t('EquipmentManagement.DvRepair.exportFilename'))
} catch {
} finally {
exportLoading.value = false

@ -7,26 +7,49 @@
label-width="100px"
v-loading="formLoading"
>
<el-form-item label="项目编码" prop="subjectCode">
<el-input v-model="formData.subjectCode" placeholder="请输入项目编码" :disabled = "formType === 'update'"/>
<el-form-item :label="t('EquipmentManagement.DvSubject.projectCode')" prop="subjectCode">
<el-input
v-model="formData.subjectCode"
:placeholder="t('EquipmentManagement.DvSubject.placeholderProjectCode')"
:disabled="formType === 'update'"
/>
</el-form-item>
<el-form-item label="项目名称" prop="subjectName">
<el-input v-model="formData.subjectName" placeholder="请输入项目名称" />
<el-form-item :label="t('EquipmentManagement.DvSubject.projectName')" prop="subjectName">
<el-input
v-model="formData.subjectName"
:placeholder="t('EquipmentManagement.DvSubject.placeholderProjectName')"
/>
</el-form-item>
<el-form-item label="检验方式" prop="inspectionMethod">
<el-select v-model="formData.inspectionMethod" placeholder="请选择检验方式" clearable filterable class="!w-full">
<el-form-item :label="t('EquipmentManagement.DvSubject.inspectionMethod')" prop="inspectionMethod">
<el-select
v-model="formData.inspectionMethod"
:placeholder="t('EquipmentManagement.DvSubject.placeholderInspectionMethod')"
clearable
filterable
class="!w-full"
>
<el-option v-for="dict in inspectionMethodOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="值类型" prop="valueType">
<el-select v-model="formData.valueType" placeholder="请选择值类型" clearable filterable class="!w-full">
<el-form-item :label="t('EquipmentManagement.DvSubject.valueType')" prop="valueType">
<el-select
v-model="formData.valueType"
:placeholder="t('EquipmentManagement.DvSubject.placeholderValueType')"
clearable
filterable
class="!w-full"
>
<el-option v-for="dict in valueTypeOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="判定基准" prop="judgmentCriteria">
<el-input v-model="formData.judgmentCriteria" placeholder="请输入判定基准" type="textarea" />
<el-form-item :label="t('EquipmentManagement.DvSubject.judgmentCriteria')" prop="judgmentCriteria">
<el-input
v-model="formData.judgmentCriteria"
:placeholder="t('EquipmentManagement.DvSubject.placeholderJudgmentCriteria')"
type="textarea"
/>
</el-form-item>
<el-form-item label="是否启用" prop="isEnable">
<el-form-item :label="t('EquipmentManagement.DvSubject.isEnable')" prop="isEnable">
<el-radio-group v-model="formData.isEnable">
<el-radio v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" :key="dict.value" :label="dict.value">
{{ dict.label }}
@ -35,8 +58,8 @@
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
<el-button @click="submitForm" type="primary" :disabled="formLoading">{{ t('common.ok') }}</el-button>
<el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
</template>

@ -1,39 +1,59 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="编码" prop="subjectCode">
<el-form-item :label="t('EquipmentManagement.DvSubject.code')" prop="subjectCode">
<el-input
v-model="queryParams.subjectCode" placeholder="请输入编码" clearable @keyup.enter="handleQuery"
class="!w-240px" />
v-model="queryParams.subjectCode"
:placeholder="t('EquipmentManagement.DvSubject.placeholderCode')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="名称" prop="subjectName">
<el-form-item :label="t('EquipmentManagement.DvSubject.name')" prop="subjectName">
<el-input
v-model="queryParams.subjectName" placeholder="请输入名称" clearable @keyup.enter="handleQuery"
class="!w-240px" />
v-model="queryParams.subjectName"
:placeholder="t('EquipmentManagement.DvSubject.placeholderName')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="判定基准" prop="judgmentCriteria">
<el-form-item :label="t('EquipmentManagement.DvSubject.judgmentCriteria')" prop="judgmentCriteria">
<el-input
v-model="queryParams.judgmentCriteria" placeholder="请输入判定基准" clearable @keyup.enter="handleQuery"
class="!w-240px" />
v-model="queryParams.judgmentCriteria"
:placeholder="t('EquipmentManagement.DvSubject.placeholderJudgmentCriteria')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> 搜索
<Icon icon="ep:search" class="mr-5px" />
{{ t('common.query') }}
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
<Icon icon="ep:refresh" class="mr-5px" />
{{ t('common.reset') }}
</el-button>
<el-button type="primary" plain @click="openForm('create')" v-hasPermi="['mes:dv-subject:create']">
<Icon icon="ep:plus" class="mr-5px" /> 新增
<Icon icon="ep:plus" class="mr-5px" />
{{ t('action.add') }}
</el-button>
<el-button type="danger" plain @click="handleBatchDelete" v-hasPermi="['mes:dv-subject:delete']">
<Icon icon="ep:delete" class="mr-5px" /> 批量删除
<Icon icon="ep:delete" class="mr-5px" />
{{ t('EquipmentManagement.DvSubject.batchDelete') }}
</el-button>
<el-button
type="success" plain @click="handleExport" :loading="exportLoading"
v-hasPermi="['mes:dv-subject:export']">
<Icon icon="ep:download" class="mr-5px" /> 导出
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['mes:dv-subject:export']"
>
<Icon icon="ep:download" class="mr-5px" />
{{ t('action.export') }}
</el-button>
</el-form-item>
</el-form>
@ -45,14 +65,14 @@ type="success" plain @click="handleExport" :loading="exportLoading"
ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" row-key="id"
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" fixed="left" reserve-selection />
<el-table-column label="序号" align="center" width="80" fixed="left">
<el-table-column :label="t('common.index')" align="center" width="80" fixed="left">
<template #default="scope">
{{ (queryParams.pageNo - 1) * queryParams.pageSize + scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column label="编码" align="center" prop="subjectCode" />
<el-table-column label="名称" align="center" prop="subjectName" />
<el-table-column label="检验方式" align="center" prop="inspectionMethod" width="120px">
<el-table-column :label="t('EquipmentManagement.DvSubject.code')" align="center" prop="subjectCode" />
<el-table-column :label="t('EquipmentManagement.DvSubject.name')" align="center" prop="subjectName" />
<el-table-column :label="t('EquipmentManagement.DvSubject.inspectionMethod')" align="center" prop="inspectionMethod" width="120px">
<template #default="scope">
<el-tag
effect="light" :type="getTagType('Inspection_method', scope.row.inspectionMethod)"
@ -62,7 +82,7 @@ effect="light" :type="getTagType('Inspection_method', scope.row.inspectionMethod
</el-tag>
</template>
</el-table-column>
<el-table-column label="值类型" align="center" prop="valueType" width="120px">
<el-table-column :label="t('EquipmentManagement.DvSubject.valueType')" align="center" prop="valueType" width="120px">
<template #default="scope">
<el-tag
effect="light" :type="getTagType('value_types', scope.row.valueType)"
@ -72,18 +92,20 @@ effect="light" :type="getTagType('value_types', scope.row.valueType)"
</el-tag>
</template>
</el-table-column>
<el-table-column label="判定基准" align="center" prop="judgmentCriteria" />
<el-table-column label="创建人" align="center" prop="creatorName" />
<el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180px" />
<el-table-column label="操作" align="center" fixed="right" width="160px">
<el-table-column :label="t('EquipmentManagement.DvSubject.judgmentCriteria')" align="center" prop="judgmentCriteria" />
<el-table-column :label="t('EquipmentManagement.DvSubject.creatorName')" align="center" prop="creatorName" />
<el-table-column :label="t('EquipmentManagement.DvSubject.createTime')" align="center" prop="createTime" :formatter="dateFormatter" width="180px" />
<el-table-column :label="t('EquipmentManagement.DvSubject.operate')" align="center" fixed="right" width="160px">
<template #default="scope">
<el-button
link type="primary" @click="openForm('update', scope.row.id)"
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['mes:dv-subject:update']">
编辑
{{ t('EquipmentManagement.DvSubject.edit') }}
</el-button>
<el-button link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['mes:dv-subject:delete']">
删除
{{ t('EquipmentManagement.DvSubject.delete') }}
</el-button>
</template>
</el-table-column>

@ -54,11 +54,11 @@ v-if="getPointDetailsRows(scope.row).length" :data="getPointDetailsRows(scope.ro
</el-table>
</template>
</el-table-column>
<el-table-column label="序号" align="center" width="70">
<!-- <el-table-column label="序号" align="center" width="70">
<template #default="scope">
{{ (queryParams.pageNo - 1) * queryParams.pageSize + scope.$index + 1 }}
</template>
</el-table-column>
</el-table-column> -->
<el-table-column label="表名称" align="center" prop="name" min-width="120" />
<el-table-column label="能源类型" align="center" prop="deviceTypeName" min-width="100" />
<el-table-column label="所属区域" align="center" prop="orgName" min-width="100" />

@ -72,8 +72,16 @@
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
row-key="id"
@selection-change="handleSelectionChange"
>
<!-- <el-table-column label="ID" align="center" prop="id" /> -->
<el-table-column type="selection" width="55" reserve-selection />
<el-table-column label="能耗类型编码" align="center" prop="code" />
<el-table-column label="能耗类型名称" align="center" prop="name" />
<el-table-column label="单位" align="center" prop="unit" />
@ -153,6 +161,11 @@ const queryParams = reactive({
const queryFormRef = ref() //
const exportLoading = ref(false) //
const selectedIds = ref<number[]>([])
const handleSelectionChange = (rows: EnergyTypeVO[]) => {
selectedIds.value = rows?.map((row) => row.id).filter((id) => id !== undefined && id !== null) ?? []
}
/** 查询列表 */
const getList = async () => {
loading.value = true
@ -203,7 +216,11 @@ const handleExport = async () => {
await message.exportConfirm()
//
exportLoading.value = true
const data = await EnergyTypeApi.exportEnergyType(queryParams)
const params: any = {
...queryParams,
ids: selectedIds.value.length ? selectedIds.value.join(',') : undefined
}
const data = await EnergyTypeApi.exportEnergyType(params)
download.excel(data, '能耗类型.xls')
} catch {
} finally {
@ -215,4 +232,4 @@ const handleExport = async () => {
onMounted(() => {
getList()
})
</script>
</script>

@ -1,28 +1,39 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible" width="720px">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px" v-loading="formLoading">
<el-form-item label="方案名称" prop="planName" required>
<el-input v-model="formData.planName" placeholder="请输入方案名称" />
<el-form-item :label="t('EquipmentManagement.PlanMaintenance.planName')" prop="planName" required>
<el-input
v-model="formData.planName"
:placeholder="t('EquipmentManagement.PlanMaintenance.placeholderPlanName')"
/>
</el-form-item>
<el-form-item label="方案类型" prop="planType" required>
<el-select v-model="formData.planType" placeholder="请选择方案类型" class="!w-full">
<el-option :value="1" label="保养" />
<el-option :value="2" label="点检" />
<el-form-item :label="t('EquipmentManagement.PlanMaintenance.planType')" prop="planType" required>
<el-select
v-model="formData.planType"
:placeholder="t('EquipmentManagement.PlanMaintenance.placeholderPlanType')"
class="!w-full"
>
<el-option :value="1" :label="t('EquipmentManagement.PlanMaintenance.planTypeMaintain')" />
<el-option :value="2" :label="t('EquipmentManagement.PlanMaintenance.planTypeInspect')" />
</el-select>
</el-form-item>
<el-form-item label="描述" prop="description">
<el-input v-model="formData.description" placeholder="请输入描述" type="textarea" />
<el-form-item :label="t('EquipmentManagement.PlanMaintenance.description')" prop="description">
<el-input
v-model="formData.description"
:placeholder="t('EquipmentManagement.PlanMaintenance.placeholderDescription')"
type="textarea"
/>
</el-form-item>
<el-form-item label="关联项目" prop="subjectIds">
<el-form-item :label="t('EquipmentManagement.PlanMaintenance.subjectName')" prop="subjectIds">
<el-select
v-model="formData.subjectIds"
multiple
filterable
clearable
placeholder="请选择关联项目"
:placeholder="t('EquipmentManagement.PlanMaintenance.placeholderSubjectSelect')"
class="!w-full"
>
<el-option v-for="item in subjectOptions" :key="item.id" :label="item.subjectName" :value="item.id" />
@ -31,8 +42,8 @@
</el-form>
<template #footer>
<el-button type="primary" @click="submitForm" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="submitForm" :disabled="formLoading">{{ t('common.ok') }}</el-button>
<el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
</template>
@ -91,8 +102,12 @@ const initFormData = () => ({
const formData = ref(initFormData())
const formRules = reactive<FormRules>({
planName: [{ required: true, message: '方案名称不能为空', trigger: 'blur' }],
planType: [{ required: true, message: '方案类型不能为空', trigger: 'change' }]
planName: [
{ required: true, message: t('EquipmentManagement.PlanMaintenance.placeholderPlanName'), trigger: 'blur' }
],
planType: [
{ required: true, message: t('EquipmentManagement.PlanMaintenance.placeholderPlanType'), trigger: 'change' }
]
})
const formRef = ref()

@ -1,38 +1,51 @@
<template>
<ContentWrap>
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="60px">
<el-form-item label="名称" prop="planName">
<el-form-item :label="t('EquipmentManagement.PlanMaintenance.planName')" prop="planName">
<el-input
v-model="queryParams.planName"
placeholder="请输入名称"
:placeholder="t('EquipmentManagement.PlanMaintenance.placeholderPlanName')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="类型" prop="planType">
<el-select v-model="queryParams.planType" placeholder="请选择类型" clearable class="!w-240px">
<el-option :value="1" label="保养" />
<el-option :value="2" label="点检" />
<el-form-item :label="t('EquipmentManagement.PlanMaintenance.planType')" prop="planType">
<el-select
v-model="queryParams.planType"
:placeholder="t('EquipmentManagement.PlanMaintenance.placeholderPlanType')"
clearable
class="!w-240px"
>
<el-option :value="1" :label="t('EquipmentManagement.PlanMaintenance.planTypeMaintain')" />
<el-option :value="2" :label="t('EquipmentManagement.PlanMaintenance.planTypeInspect')" />
</el-select>
</el-form-item>
<el-form-item label="描述" prop="description">
<el-form-item :label="t('EquipmentManagement.PlanMaintenance.description')" prop="description">
<el-input
v-model="queryParams.description"
placeholder="请输入描述"
:placeholder="t('EquipmentManagement.PlanMaintenance.placeholderDescription')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" />
{{ t('common.query') }}
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" />
{{ t('common.reset') }}
</el-button>
<el-button type="primary" plain @click="openForm('create')" v-hasPermi="['mes:plan-maintenance:create']">
<Icon icon="ep:plus" class="mr-5px" /> 新增
<Icon icon="ep:plus" class="mr-5px" />
{{ t('action.add') }}
</el-button>
<el-button type="danger" plain @click="handleBatchDelete" v-hasPermi="['mes:plan-maintenance:delete']">
<Icon icon="ep:delete" class="mr-5px" /> 批量删除
<Icon icon="ep:delete" class="mr-5px" />
{{ t('EquipmentManagement.PlanMaintenance.batchDelete') }}
</el-button>
<el-button
type="success"
@ -41,7 +54,8 @@
:loading="exportLoading"
v-hasPermi="['mes:plan-maintenance:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
<Icon icon="ep:download" class="mr-5px" />
{{ t('action.export') }}
</el-button>
</el-form-item>
</el-form>
@ -67,14 +81,14 @@
:show-overflow-tooltip="true"
size="small"
>
<el-table-column label="序号" align="center" width="80">
<el-table-column :label="t('EquipmentManagement.PlanMaintenance.index')" align="center" width="80">
<template #default="s2">
{{ s2.$index + 1 }}
</template>
</el-table-column>
<el-table-column label="编码" align="center" prop="subjectCode" />
<el-table-column label="名称" align="center" prop="subjectName" />
<el-table-column label="检验方式" align="center" prop="inspectionMethod" width="120">
<el-table-column :label="t('EquipmentManagement.PlanMaintenance.subjectCode')" align="center" prop="subjectCode" />
<el-table-column :label="t('EquipmentManagement.PlanMaintenance.subjectName')" align="center" prop="subjectName" />
<el-table-column :label="t('EquipmentManagement.PlanMaintenance.inspectionMethod')" align="center" prop="inspectionMethod" width="120">
<template #default="s2">
<span v-if="s2.row.inspectionMethod === undefined || s2.row.inspectionMethod === null || s2.row.inspectionMethod === ''">-</span>
<el-tag
@ -89,36 +103,36 @@
</el-tag>
</template>
</el-table-column>
<el-table-column label="判定基准" align="center" prop="judgmentCriteria" />
<el-table-column :label="t('EquipmentManagement.PlanMaintenance.judgmentCriteria')" align="center" prop="judgmentCriteria" />
</el-table>
</div>
</template>
</el-table-column>
<el-table-column label="序号" align="center" width="80">
<el-table-column :label="t('EquipmentManagement.PlanMaintenance.index')" align="center" width="80">
<template #default="scope">
{{ (queryParams.pageNo - 1) * queryParams.pageSize + scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column label="名称" align="center" prop="planName" min-width="160" />
<el-table-column label="类型" align="center" prop="planType" width="110">
<el-table-column :label="t('EquipmentManagement.PlanMaintenance.planName')" align="center" prop="planName" min-width="160" />
<el-table-column :label="t('EquipmentManagement.PlanMaintenance.planType')" align="center" prop="planType" width="110">
<template #default="scope">
<el-tag effect="light" :type="getPlanTypeTagType(scope.row.planType)">
{{ getPlanTypeLabel(scope.row.planType) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="描述" align="center" prop="description" min-width="220" />
<el-table-column label="创建人" align="center" prop="creatorName" width="140" />
<el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180" />
<el-table-column label="更新时间" align="center" prop="updateTime" :formatter="dateFormatter" width="180" />
<el-table-column label="操作" align="center" fixed="right" width="160">
<el-table-column :label="t('EquipmentManagement.PlanMaintenance.description')" align="center" prop="description" min-width="220" />
<el-table-column :label="t('EquipmentManagement.PlanMaintenance.creatorName')" align="center" prop="creatorName" width="140" />
<el-table-column :label="t('EquipmentManagement.PlanMaintenance.createTime')" align="center" prop="createTime" :formatter="dateFormatter" width="180" />
<!-- <el-table-column :label="t('EquipmentManagement.PlanMaintenance.updateTime')" align="center" prop="updateTime" :formatter="dateFormatter" width="180" /> -->
<el-table-column :label="t('EquipmentManagement.PlanMaintenance.operate')" align="center" fixed="right" width="160">
<template #default="scope">
<el-button link type="primary" @click="openForm('update', scope.row)" v-hasPermi="['mes:plan-maintenance:update']">
编辑
{{ t('action.update') }}
</el-button>
<el-button link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['mes:plan-maintenance:delete']">
删除
{{ t('action.delete') }}
</el-button>
</template>
</el-table-column>
@ -263,8 +277,8 @@ const handleExpandChange = async (row: PlanMaintenanceVO, expandedRows: PlanMain
const getPlanTypeLabel = (value: any) => {
const v = value === '' || value === null || value === undefined ? undefined : Number(value)
if (v === 1) return '保养'
if (v === 2) return '点检'
if (v === 1) return t('EquipmentManagement.PlanMaintenance.planTypeMaintain')
if (v === 2) return t('EquipmentManagement.PlanMaintenance.planTypeInspect')
return value ?? ''
}
@ -297,7 +311,7 @@ const handleDelete = async (ids: number | string | Array<number | string>) => {
const handleBatchDelete = async () => {
if (!selectedIds.value.length) {
message.error('请选择需要删除的数据')
message.error(t('EquipmentManagement.PlanMaintenance.selectDeleteTip'))
return
}
await handleDelete(selectedIds.value)
@ -312,7 +326,7 @@ const handleExport = async () => {
ids: selectedIds.value.length ? selectedIds.value.join(',') : undefined
}
const data = await PlanMaintenanceApi.exportPlanMaintenance(params)
download.excel(data, '方案维护.xls')
download.excel(data, t('EquipmentManagement.PlanMaintenance.exportFilename'))
} catch {
} finally {
exportLoading.value = false

@ -1,19 +1,25 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible" width="900px">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px" v-loading="formLoading">
<el-form-item label="维修编码" prop="subjectCode">
<el-input v-model="formData.subjectCode" placeholder="请输入维修编码" />
<el-form-item :label="t('EquipmentManagement.RepairItems.subjectCode')" prop="subjectCode">
<el-input
v-model="formData.subjectCode"
:placeholder="t('EquipmentManagement.RepairItems.placeholderSubjectCode')"
/>
</el-form-item>
<el-form-item label="维修名称" prop="subjectName">
<el-input v-model="formData.subjectName" placeholder="请输入维修名称" />
<el-form-item :label="t('EquipmentManagement.RepairItems.subjectName')" prop="subjectName">
<el-input
v-model="formData.subjectName"
:placeholder="t('EquipmentManagement.RepairItems.placeholderSubjectName')"
/>
</el-form-item>
<el-form-item label="设备类型" prop="deviceType">
<el-form-item :label="t('EquipmentManagement.RepairItems.deviceType')" prop="deviceType">
<el-radio-group v-model="formData.deviceType">
<el-radio :label="1">设备</el-radio>
<el-radio :label="2">关键件</el-radio>
<el-radio :label="1">{{ t('EquipmentManagement.RepairItems.deviceTypeDevice') }}</el-radio>
<el-radio :label="2">{{ t('EquipmentManagement.RepairItems.deviceTypeComponent') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="showDeviceSelect" label="设备" prop="deviceId">
<el-form-item v-if="showDeviceSelect" :label="t('EquipmentManagement.RepairItems.device')" prop="deviceId">
<el-select
v-model="formData.deviceId"
filterable
@ -22,18 +28,18 @@
clearable
:remote-method="handleDeviceSearch"
:loading="deviceLoading"
placeholder="请选择设备"
:placeholder="t('EquipmentManagement.RepairItems.placeholderDevice')"
class="!w-full"
>
<el-option v-for="opt in deviceOptions" :key="String(opt.value)" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
<el-form-item v-if="showComponentSelect" label="关键件" prop="componentId">
<el-form-item v-if="showComponentSelect" :label="t('EquipmentManagement.RepairItems.component')" prop="componentId">
<el-select
v-model="formData.componentId"
clearable
:loading="componentLoading"
placeholder="请选择关键件"
:placeholder="t('EquipmentManagement.RepairItems.placeholderComponent')"
class="!w-full"
>
<el-option v-for="opt in componentOptions" :key="String(opt.value)" :label="opt.label" :value="opt.value" />
@ -54,10 +60,14 @@
<el-input v-model="formData.judgmentCriteria" placeholder="请输入判定基准" type="textarea" />
</el-form-item>
-->
<el-form-item label="维修内容" prop="projectContent">
<el-input v-model="formData.projectContent" placeholder="请输入维修内容" type="textarea" />
<el-form-item :label="t('EquipmentManagement.RepairItems.projectContent')" prop="projectContent">
<el-input
v-model="formData.projectContent"
:placeholder="t('EquipmentManagement.RepairItems.placeholderProjectContent')"
type="textarea"
/>
</el-form-item>
<el-form-item label="是否启用" prop="isEnable">
<el-form-item :label="t('EquipmentManagement.RepairItems.isEnable')" prop="isEnable">
<el-radio-group v-model="formData.isEnable">
<el-radio v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" :key="dict.value" :label="dict.value">
{{ dict.label }}
@ -66,8 +76,8 @@
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
<el-button @click="submitForm" type="primary" :disabled="formLoading">{{ t('common.ok') }}</el-button>
<el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
</template>
@ -197,7 +207,7 @@ const validateDeviceId = (_: any, value: any, callback: any) => {
}
const dt = formData.value.deviceType
if ((dt === 1 || dt === 2) && (value === undefined || value === null || value === '')) {
callback(new Error('设备不能为空'))
callback(new Error(t('EquipmentManagement.RepairItems.validatorDeviceRequired')))
return
}
callback()
@ -210,19 +220,19 @@ const validateComponentId = (_: any, value: any, callback: any) => {
}
const dt = formData.value.deviceType
if (dt === 2 && (value === undefined || value === null || value === '')) {
callback(new Error('关键件不能为空'))
callback(new Error(t('EquipmentManagement.RepairItems.validatorComponentRequired')))
return
}
callback()
}
const formRules = reactive({
subjectCode: [{ required: true, message: '项目编码不能为空' }],
subjectName: [{ required: true, message: '项目名称不能为空' }],
deviceType: [{ required: true, message: '设备类型不能为空' }],
subjectCode: [{ required: true, message: t('EquipmentManagement.RepairItems.validatorSubjectCodeRequired') }],
subjectName: [{ required: true, message: t('EquipmentManagement.RepairItems.validatorSubjectNameRequired') }],
deviceType: [{ required: true, message: t('EquipmentManagement.RepairItems.validatorDeviceTypeRequired') }],
deviceId: [{ validator: validateDeviceId }],
componentId: [{ validator: validateComponentId }],
isEnable: [{ required: true, message: '是否启用不能为空' }]
isEnable: [{ required: true, message: t('EquipmentManagement.RepairItems.validatorIsEnableRequired') }]
})
const open = async (type: string, row?: any) => {

@ -1,14 +1,32 @@
<template>
<ContentWrap>
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="维修编码" prop="subjectCode">
<el-input v-model="queryParams.subjectCode" placeholder="请输入维修编码" clearable @keyup.enter="handleQuery" class="!w-240px" />
<el-form-item :label="t('EquipmentManagement.RepairItems.subjectCode')" prop="subjectCode">
<el-input
v-model="queryParams.subjectCode"
:placeholder="t('EquipmentManagement.RepairItems.placeholderSubjectCode')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="维修名称" prop="subjectName">
<el-input v-model="queryParams.subjectName" placeholder="请输入维修名称" clearable @keyup.enter="handleQuery" class="!w-240px" />
<el-form-item :label="t('EquipmentManagement.RepairItems.subjectName')" prop="subjectName">
<el-input
v-model="queryParams.subjectName"
:placeholder="t('EquipmentManagement.RepairItems.placeholderSubjectName')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="设备类型" prop="deviceType">
<el-select v-model="queryParams.deviceType" placeholder="请选择设备类型" clearable filterable class="!w-240px">
<el-form-item :label="t('EquipmentManagement.RepairItems.deviceType')" prop="deviceType">
<el-select
v-model="queryParams.deviceType"
:placeholder="t('EquipmentManagement.RepairItems.placeholderDeviceType')"
clearable
filterable
class="!w-240px"
>
<el-option v-for="opt in deviceTypeOptions" :key="String(opt.value)" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
@ -33,37 +51,37 @@
/>
</el-form-item>
-->
<el-form-item label="维修内容" prop="projectContent">
<el-form-item :label="t('EquipmentManagement.RepairItems.projectContent')" prop="projectContent">
<el-input
v-model="queryParams.projectContent"
placeholder="请输入维修内容"
:placeholder="t('EquipmentManagement.RepairItems.placeholderProjectContent')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-form-item :label="t('EquipmentManagement.RepairItems.createTime')" prop="createTime">
<el-date-picker
v-model="queryParams.createTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:start-placeholder="t('EquipmentManagement.RepairItems.placeholderCreateTimeStart')"
:end-placeholder="t('EquipmentManagement.RepairItems.placeholderCreateTimeEnd')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-220px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> {{ t('common.query') }}</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> {{ t('common.reset') }}</el-button>
<el-button type="primary" plain @click="openForm('create')" v-hasPermi="['mes:repair-tems:create']">
<Icon icon="ep:plus" class="mr-5px" /> 新增
<Icon icon="ep:plus" class="mr-5px" /> {{ t('action.add') }}
</el-button>
<el-button type="danger" plain @click="handleBatchDelete" :disabled="!selectedIds.length" v-hasPermi="['mes:repair-tems:delete']">
<Icon icon="ep:delete" class="mr-5px" /> 批量删除
<Icon icon="ep:delete" class="mr-5px" /> {{ t('EquipmentManagement.RepairItems.batchDelete') }}
</el-button>
<el-button type="success" plain @click="handleExport" :loading="exportLoading" v-hasPermi="['mes:repair-tems:export']">
<Icon icon="ep:download" class="mr-5px" /> 导出
<Icon icon="ep:download" class="mr-5px" /> {{ t('action.export') }}
</el-button>
</el-form-item>
</el-form>
@ -72,15 +90,15 @@
<ContentWrap>
<el-table ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" row-key="id" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" fixed="left" reserve-selection />
<el-table-column label="维修编码" align="center" prop="subjectCode" min-width="130" :formatter="cellOrDash" />
<el-table-column label="维修名称" align="center" prop="subjectName" min-width="160" :formatter="cellOrDash" />
<el-table-column label="设备类型" align="center" prop="deviceType" min-width="140">
<el-table-column :label="t('EquipmentManagement.RepairItems.subjectCode')" align="center" prop="subjectCode" min-width="130" :formatter="cellOrDash" />
<el-table-column :label="t('EquipmentManagement.RepairItems.subjectName')" align="center" prop="subjectName" min-width="160" :formatter="cellOrDash" />
<el-table-column :label="t('EquipmentManagement.RepairItems.deviceType')" align="center" prop="deviceType" min-width="140">
<template #default="scope">
<el-tag effect="light">{{ getDeviceTypeName(scope.row.deviceType) }}</el-tag>
</template>
</el-table-column>
<el-table-column label="设备名称" align="center" prop="deviceName" min-width="160" :formatter="cellOrDash" />
<el-table-column label="关键件名称" align="center" prop="componentName" min-width="160" :formatter="cellOrDash" />
<el-table-column :label="t('EquipmentManagement.RepairItems.deviceName')" align="center" prop="deviceName" min-width="160" :formatter="cellOrDash" />
<el-table-column :label="t('EquipmentManagement.RepairItems.componentName')" align="center" prop="componentName" min-width="160" :formatter="cellOrDash" />
<!--
<el-table-column label="检验方式" align="center" prop="inspectionMethod" width="120">
<template #default="scope">
@ -94,12 +112,26 @@
</el-table-column>
<el-table-column label="判定基准" align="center" prop="judgmentCriteria" min-width="180" />
-->
<el-table-column label="维修内容" align="center" prop="projectContent" min-width="200" :formatter="cellOrDash" />
<el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateOrDash" width="180" />
<el-table-column label="操作" align="center" width="140" fixed="right">
<el-table-column :label="t('EquipmentManagement.RepairItems.projectContent')" align="center" prop="projectContent" min-width="200" :formatter="cellOrDash" />
<el-table-column :label="t('EquipmentManagement.RepairItems.createTime')" align="center" prop="createTime" :formatter="dateOrDash" width="180" />
<el-table-column :label="t('EquipmentManagement.RepairItems.operate')" align="center" width="140" fixed="right">
<template #default="scope">
<el-button link type="primary" @click="openForm('update', scope.row)" v-hasPermi="['mes:repair-tems:update']"></el-button>
<el-button link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['mes:repair-tems:delete']"></el-button>
<el-button
link
type="primary"
@click="openForm('update', scope.row)"
v-hasPermi="['mes:repair-tems:update']"
>
{{ t('action.update') }}
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['mes:repair-tems:delete']"
>
{{ t('action.delete') }}
</el-button>
</template>
</el-table-column>
</el-table>
@ -153,15 +185,15 @@ const selectedIds = ref<number[]>([])
const formRef = ref()
const deviceTypeOptions = ref<{ label: string; value: number }[]>([
{ label: '设备', value: 1 },
{ label: '关键件', value: 2 }
{ label: t('EquipmentManagement.RepairItems.deviceTypeDevice'), value: 1 },
{ label: t('EquipmentManagement.RepairItems.deviceTypeComponent'), value: 2 }
])
const getDeviceTypeName = (value: any) => {
if (value === undefined || value === null || value === '') return '-'
const v = typeof value === 'number' ? value : Number(value)
if (v === 1) return '设备'
if (v === 2) return '关键件'
if (v === 1) return t('EquipmentManagement.RepairItems.deviceTypeDevice')
if (v === 2) return t('EquipmentManagement.RepairItems.deviceTypeComponent')
return String(value)
}
@ -223,7 +255,7 @@ const handleDelete = async (ids: number | number[]) => {
const handleBatchDelete = async () => {
if (!selectedIds.value.length) {
message.error('请选择需要删除的数据')
message.error(t('EquipmentManagement.RepairItems.selectDeleteTip'))
return
}
await handleDelete(selectedIds.value)
@ -238,7 +270,7 @@ const handleExport = async () => {
ids: selectedIds.value.length ? selectedIds.value.join(',') : undefined
}
const data = await RepairItemsApi.exportRepairItems(params)
download.excel(data, '维修项目.xls')
download.excel(data, t('EquipmentManagement.RepairItems.exportFilename'))
} catch {
} finally {
exportLoading.value = false

@ -7,58 +7,61 @@
label-width="110px"
v-loading="formLoading"
>
<el-form-item label="名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入名称" />
<el-form-item :label="t('EquipmentManagement.TaskManagement.name')" prop="name">
<el-input
v-model="formData.name"
:placeholder="t('EquipmentManagement.TaskManagement.placeholderName')"
/>
</el-form-item>
<el-form-item label="类型" prop="taskType">
<el-form-item :label="t('EquipmentManagement.TaskManagement.taskType')" prop="taskType">
<el-radio-group v-model="formData.taskType">
<el-radio :label="1">点检</el-radio>
<el-radio :label="2">保养</el-radio>
<el-radio :label="1">{{ t('EquipmentManagement.TaskManagement.taskTypeInspect') }}</el-radio>
<el-radio :label="2">{{ t('EquipmentManagement.TaskManagement.taskTypeMaintain') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="设备列表" prop="deviceList">
<el-form-item :label="t('EquipmentManagement.TaskManagement.deviceList')" prop="deviceList">
<el-select
v-model="formData.deviceList"
multiple
filterable
clearable
placeholder="请选择设备列表"
:placeholder="t('EquipmentManagement.TaskManagement.placeholderDeviceList')"
class="!w-full"
>
<el-option v-for="item in deviceOptions" :key="String(item.id)" :label="item.deviceName" :value="String(item.id)" />
</el-select>
</el-form-item>
<el-form-item label="项目表单" prop="projectForm">
<el-form-item :label="t('EquipmentManagement.TaskManagement.projectForm')" prop="projectForm">
<el-select
v-model="formData.projectForm"
filterable
clearable
placeholder="请选择项目表单"
:placeholder="t('EquipmentManagement.TaskManagement.placeholderProjectForm')"
class="!w-full"
>
<el-option v-for="item in planOptions" :key="String(item.id)" :label="item.planName" :value="Number(item.id)" />
</el-select>
</el-form-item>
<el-form-item label="起止日期" prop="dateRange">
<el-form-item :label="t('EquipmentManagement.TaskManagement.dateRange')" prop="dateRange">
<el-date-picker
v-model="formData.dateRange"
value-format="YYYY-MM-DD"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:start-placeholder="t('EquipmentManagement.TaskManagement.placeholderStartDate')"
:end-placeholder="t('EquipmentManagement.TaskManagement.placeholderEndDate')"
class="!w-320px"
/>
</el-form-item>
<el-form-item label="cron 表达式" prop="cronExpression">
<el-form-item :label="t('EquipmentManagement.TaskManagement.cronExpression')" prop="cronExpression">
<crontab v-model="formData.cronExpression" />
</el-form-item>
<el-form-item label="可操作人" prop="operableUsers">
<el-form-item :label="t('EquipmentManagement.TaskManagement.operableUsers')" prop="operableUsers">
<el-select
v-model="formData.operableUsers"
multiple
filterable
clearable
placeholder="请选择可操作人"
:placeholder="t('EquipmentManagement.TaskManagement.placeholderOperableUsers')"
class="!w-full"
>
<el-option v-for="item in users" :key="String(item.id)" :label="item.nickname" :value="String(item.id)" />
@ -66,8 +69,8 @@
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
<el-button @click="submitForm" type="primary" :disabled="formLoading">{{ t('common.ok') }}</el-button>
<el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
</template>
@ -142,12 +145,24 @@ const formData = ref({
})
const formRules = reactive({
name: [{ required: true, message: '名称不能为空', trigger: 'blur' }],
taskType: [{ required: true, message: '类型不能为空', trigger: 'change' }],
enabled: [{ required: true, message: '是否启用不能为空', trigger: 'change' }],
deviceList: [{ required: true, message: '设备列表不能为空', trigger: 'change' }],
projectForm: [{ required: true, message: '项目表单不能为空', trigger: 'change' }],
dateRange: [{required: true, message: '起止日期不能为空', trigger: 'change' }]
name: [
{ required: true, message: t('EquipmentManagement.TaskManagement.placeholderName'), trigger: 'blur' }
],
taskType: [
{ required: true, message: t('EquipmentManagement.TaskManagement.placeholderTaskType'), trigger: 'change' }
],
enabled: [
{ required: true, message: t('EquipmentManagement.TaskManagement.placeholderEnabled'), trigger: 'change' }
],
deviceList: [
{ required: true, message: t('EquipmentManagement.TaskManagement.placeholderDeviceList'), trigger: 'change' }
],
projectForm: [
{ required: true, message: t('EquipmentManagement.TaskManagement.placeholderProjectForm'), trigger: 'change' }
],
dateRange: [
{ required: true, message: t('EquipmentManagement.TaskManagement.placeholderDateRange'), trigger: 'change' }
]
})
const resetForm = () => {

@ -7,27 +7,32 @@
:inline="true"
label-width="68px"
>
<el-form-item label="名称" prop="name">
<el-form-item :label="t('EquipmentManagement.TaskManagement.name')" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入名称"
:placeholder="t('EquipmentManagement.TaskManagement.placeholderName')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="类型" prop="taskType">
<el-select v-model="queryParams.taskType" placeholder="请选择类型" clearable class="!w-240px">
<el-form-item :label="t('EquipmentManagement.TaskManagement.taskType')" prop="taskType">
<el-select
v-model="queryParams.taskType"
:placeholder="t('EquipmentManagement.TaskManagement.placeholderTaskType')"
clearable
class="!w-240px"
>
<el-option v-for="opt in taskTypeOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
<el-form-item label="项目表单" prop="projectForm">
<el-form-item :label="t('EquipmentManagement.TaskManagement.projectForm')" prop="projectForm">
<el-select
v-model="queryParams.projectForm"
multiple
filterable
clearable
placeholder="请选择项目表单"
:placeholder="t('EquipmentManagement.TaskManagement.placeholderProjectForm')"
class="!w-240px"
>
<el-option v-for="item in planOptions" :key="String(item.id)" :label="item.planName" :value="String(item.id)" />
@ -35,13 +40,16 @@
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> 搜索
<Icon icon="ep:search" class="mr-5px" />
{{ t('common.query') }}
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
<Icon icon="ep:refresh" class="mr-5px" />
{{ t('common.reset') }}
</el-button>
<el-button type="primary" plain @click="openForm('create')" v-hasPermi="['mes:task-management:create']">
<Icon icon="ep:plus" class="mr-5px" /> 新增
<Icon icon="ep:plus" class="mr-5px" />
{{ t('action.add') }}
</el-button>
<el-button
type="success"
@ -50,7 +58,8 @@
:loading="exportLoading"
v-hasPermi="['mes:task-management:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
<Icon icon="ep:download" class="mr-5px" />
{{ t('action.export') }}
</el-button>
</el-form-item>
</el-form>
@ -65,20 +74,66 @@
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" />
<el-table-column type="index" label="序号" align="center" width="70" />
<el-table-column label="名称" align="center" prop="name" min-width="140" />
<el-table-column label="类型" align="center" prop="taskType" width="90">
<el-table-column
type="index"
:label="t('EquipmentManagement.TaskManagement.index')"
align="center"
width="70"
/>
<el-table-column
:label="t('EquipmentManagement.TaskManagement.name')"
align="center"
prop="name"
min-width="140"
/>
<el-table-column
:label="t('EquipmentManagement.TaskManagement.taskType')"
align="center"
prop="taskType"
width="90"
>
<template #default="scope">
<el-tag v-if="scope.row.taskType === 1" type="primary"></el-tag>
<el-tag v-else-if="scope.row.taskType === 2" type="success">保养</el-tag>
<el-tag v-if="scope.row.taskType === 1" type="primary">
{{ t('EquipmentManagement.TaskManagement.taskTypeInspect') }}
</el-tag>
<el-tag v-else-if="scope.row.taskType === 2" type="success">
{{ t('EquipmentManagement.TaskManagement.taskTypeMaintain') }}
</el-tag>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="项目表单" align="center" prop="projectFormName" min-width="140" />
<el-table-column label="开始日期" align="center" prop="startDate" :formatter="dateFormatter2" width="120" />
<el-table-column label="结束日期" align="center" prop="endDate" :formatter="dateFormatter2" width="120" />
<el-table-column label="cron 表达式" align="center" prop="cronExpression" min-width="180" />
<el-table-column label="启用" align="center" prop="enabled" width="110">
<el-table-column
:label="t('EquipmentManagement.TaskManagement.projectForm')"
align="center"
prop="projectFormName"
min-width="140"
/>
<el-table-column
:label="t('EquipmentManagement.TaskManagement.startDate')"
align="center"
prop="startDate"
:formatter="dateFormatter2"
width="120"
/>
<el-table-column
:label="t('EquipmentManagement.TaskManagement.endDate')"
align="center"
prop="endDate"
:formatter="dateFormatter2"
width="120"
/>
<el-table-column
:label="t('EquipmentManagement.TaskManagement.cronExpression')"
align="center"
prop="cronExpression"
min-width="180"
/>
<el-table-column
:label="t('EquipmentManagement.TaskManagement.enabled')"
align="center"
prop="enabled"
width="110"
>
<template #default="scope">
<el-switch
:model-value="scope.row.enabled === true || scope.row.enabled === 'true'"
@ -87,10 +142,32 @@
/>
</template>
</el-table-column>
<el-table-column label="创建人" align="center" prop="creator" width="120" />
<el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180" />
<el-table-column label="更新时间" align="center" prop="updateTime" :formatter="dateFormatter" width="180" />
<el-table-column label="操作" fixed="right" align="center" width="230">
<el-table-column
:label="t('EquipmentManagement.TaskManagement.creatorName')"
align="center"
prop="creatorName"
width="120"
/>
<el-table-column
:label="t('EquipmentManagement.TaskManagement.createTime')"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180"
/>
<el-table-column
:label="t('EquipmentManagement.TaskManagement.updateTime')"
align="center"
prop="updateTime"
:formatter="dateFormatter"
width="180"
/>
<el-table-column
:label="t('EquipmentManagement.TaskManagement.operate')"
fixed="right"
align="center"
width="230"
>
<template #default="scope">
<el-button
link
@ -98,7 +175,7 @@
@click="handleCreateTicket(scope.row.id)"
:loading="ticketLoadingId === scope.row.id"
>
新增工单管理
{{ t('EquipmentManagement.TaskManagement.createWorkOrder') }}
</el-button>
<el-button
link
@ -106,10 +183,10 @@
@click="openForm('update', scope.row)"
v-hasPermi="['mes:task-management:update']"
>
编辑
{{ t('action.update') }}
</el-button>
<el-button link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['mes:task-management:delete']">
删除
{{ t('action.delete') }}
</el-button>
</template>
</el-table-column>
@ -141,8 +218,8 @@ const message = useMessage()
const { t } = useI18n()
const taskTypeOptions = [
{ label: '点检', value: 1 },
{ label: '保养', value: 2 }
{ label: t('EquipmentManagement.TaskManagement.taskTypeInspect'), value: 1 },
{ label: t('EquipmentManagement.TaskManagement.taskTypeMaintain'), value: 2 }
]
const loading = ref(true)
@ -241,9 +318,9 @@ const handleCreateTicket = async (id?: number) => {
ticketLoadingId.value = id
try {
await TaskManagementApi.createTaskManagementTicket(id)
message.success('创建工单成功')
message.success(t('EquipmentManagement.TaskManagement.createTicketSuccess'))
} catch {
message.error('创建工单失败')
message.error(t('EquipmentManagement.TaskManagement.createTicketFail'))
} finally {
ticketLoadingId.value = undefined
}
@ -254,9 +331,9 @@ const handleBeforeEnabledChange = async (row: TaskManagementVO) => {
if (isEnabled) return true
const cronExpression = (row as any)?.cronExpression
if (typeof cronExpression === 'string' && cronExpression.trim()) return true
await ElMessageBox.alert('请先填写 cron 表达式,再启用任务', '提示', {
await ElMessageBox.alert(t('EquipmentManagement.TaskManagement.selectCronBeforeEnable'), t('EquipmentManagement.TaskManagement.cronAlertTitle'), {
type: 'warning',
confirmButtonText: '我知道了',
confirmButtonText: t('EquipmentManagement.TaskManagement.cronAlertConfirm'),
closeOnClickModal: false,
closeOnPressEscape: false
})
@ -269,10 +346,10 @@ const handleEnabledChange = async (row: TaskManagementVO, value: boolean) => {
row.enabled = value
try {
await TaskManagementApi.updateTaskManagementEnabled(String(row.id), value ? 'true' : 'false')
message.success('更新启用状态成功')
message.success(t('EquipmentManagement.TaskManagement.updateEnabledSuccess'))
} catch {
row.enabled = oldEnabled
message.error('更新启用状态失败')
message.error(t('EquipmentManagement.TaskManagement.updateEnabledFail'))
}
}
@ -285,7 +362,7 @@ const handleExport = async () => {
params.ids = selectedIds.value.join(',')
}
const data = await TaskManagementApi.exportTaskManagement(params)
download.excel(data, '任务管理.xls')
download.excel(data, t('EquipmentManagement.TaskManagement.exportFilename'))
} catch {
} finally {
exportLoading.value = false

@ -1,40 +1,88 @@
<template>
<Dialog v-model="dialogVisible" :title="dialogTitle" width="1100px">
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" :row-key="getRowKey">
<el-table-column type="index" label="序号" align="center" width="70" />
<el-table-column label="检验项名称" align="center" prop="inspectionItemName" min-width="180" />
<el-table-column label="检验方式" align="center" prop="inspectionMethod" min-width="140">
<el-table-column
type="index"
:label="t('EquipmentManagement.WorkOrderManagement.index')"
align="center"
width="70"
/>
<el-table-column
:label="t('EquipmentManagement.WorkOrderManagement.inspectionItemName')"
align="center"
prop="inspectionItemName"
min-width="180"
/>
<el-table-column
:label="t('EquipmentManagement.WorkOrderManagement.inspectionMethod')"
align="center"
prop="inspectionMethod"
min-width="140"
>
<template #default="scope">
<dict-tag type="Inspection_method" :value="scope.row.inspectionMethod" />
</template>
</el-table-column>
<el-table-column label="判定基准" align="center" prop="judgmentCriteria" min-width="160" />
<el-table-column label="检验结果" align="center" prop="inspectionResult" width="120">
<el-table-column
:label="t('EquipmentManagement.WorkOrderManagement.judgmentCriteria')"
align="center"
prop="judgmentCriteria"
min-width="160"
/>
<el-table-column
:label="t('EquipmentManagement.WorkOrderManagement.inspectionResult')"
align="center"
prop="inspectionResult"
width="120"
>
<template #default="scope">
<el-tag v-if="String(scope.row.inspectionResult) === '0'" type="info"></el-tag>
<el-tag v-else-if="String(scope.row.inspectionResult) === '1'" type="success">通过</el-tag>
<el-tag v-else-if="String(scope.row.inspectionResult) === '2'" type="danger">不通过</el-tag>
<el-tag v-if="String(scope.row.inspectionResult) === '0'" type="info">
{{ t('EquipmentManagement.WorkOrderManagement.jobResultPending') }}
</el-tag>
<el-tag v-else-if="String(scope.row.inspectionResult) === '1'" type="success">
{{ t('EquipmentManagement.WorkOrderManagement.jobResultOk') }}
</el-tag>
<el-tag v-else-if="String(scope.row.inspectionResult) === '2'" type="danger">
{{ t('EquipmentManagement.WorkOrderManagement.jobResultNg') }}
</el-tag>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="图片" align="center" prop="images" width="160">
<el-table-column
:label="t('EquipmentManagement.WorkOrderManagement.images')"
align="center"
prop="images"
width="160"
>
<template #default="scope">
<UploadImg
v-if="String(scope.row.inspectionResult) === '0'" v-model="imageMap[String(scope.row.id)]"
v-if="String(scope.row.inspectionResult) === '0'"
v-model="imageMap[String(scope.row.id)]"
:drag="false" :show-btn-text="false" width="64px" height="64px" />
<el-image
v-else-if="scope.row.images" :src="parseFirstImage(scope.row.images)"
v-else-if="scope.row.images"
:src="parseFirstImage(scope.row.images)"
:preview-src-list="parseImages(scope.row.images)" preview-teleported fit="cover"
style="width: 64px; height: 64px" />
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" min-width="160" />
<el-table-column label="操作" align="center" width="200" fixed="right">
<el-table-column
:label="t('EquipmentManagement.WorkOrderManagement.remark')"
align="center"
prop="remark"
min-width="160"
/>
<el-table-column
:label="t('EquipmentManagement.WorkOrderManagement.operate')"
align="center"
width="200"
fixed="right"
>
<template #default="scope">
<el-radio-group v-if="String(scope.row.inspectionResult) === '0'" v-model="decisionMap[String(scope.row.id)]">
<el-radio :label="'1'">通过</el-radio>
<el-radio :label="'2'">不通过</el-radio>
<el-radio :label="'1'">{{ t('EquipmentManagement.WorkOrderManagement.ok') }}</el-radio>
<el-radio :label="'2'">{{ t('EquipmentManagement.WorkOrderManagement.ng') }}</el-radio>
</el-radio-group>
<span v-else>-</span>
</template>
@ -42,20 +90,27 @@ v-else-if="scope.row.images" :src="parseFirstImage(scope.row.images)"
</el-table>
<el-pagination
v-show="total > 0" v-model:current-page="queryParams.pageNo" v-model:page-size="queryParams.pageSize"
:background="true" :page-sizes="[10, 20, 30, 50, 100]" :pager-count="7" :total="total"
class="mt-15px mb-15px flex justify-end" layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange" @current-change="handleCurrentChange" />
v-show="total > 0"
v-model:current-page="queryParams.pageNo"
v-model:page-size="queryParams.pageSize"
:background="true"
:page-sizes="[10, 20, 30, 50, 100]"
:pager-count="7"
:total="total"
class="mt-15px mb-15px flex justify-end"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange" />
<template #footer>
<el-button @click="dialogVisible = false"> </el-button>
<el-button @click="dialogVisible = false">{{ t('EquipmentManagement.WorkOrderManagement.dialogCancel') }}</el-button>
<el-button
type="primary"
@click="handleSave"
:loading="submitLoading"
:disabled="submitLoading || !isAllPendingSelected()"
>
{{ t('EquipmentManagement.WorkOrderManagement.dialogSave') }}
</el-button>
</template>
</Dialog>
@ -68,9 +123,10 @@ defineOptions({ name: 'TicketResultDialog' })
const emit = defineEmits(['success'])
const message = useMessage()
const { t } = useI18n()
const dialogVisible = ref(false)
const dialogTitle = ref('检验结果')
const dialogTitle = ref(t('EquipmentManagement.WorkOrderManagement.dialogTitleDefault'))
const loading = ref(false)
const submitLoading = ref(false)
@ -87,7 +143,7 @@ const queryParams = reactive({
const open = async (options: { managementId: number; title?: string }) => {
dialogVisible.value = true
dialogTitle.value = options.title || '检验结果'
dialogTitle.value = options.title || t('EquipmentManagement.WorkOrderManagement.dialogTitleDefault')
managementId.value = options.managementId
for (const key of Object.keys(decisionMap)) delete decisionMap[key]
for (const key of Object.keys(imageMap)) delete imageMap[key]
@ -138,7 +194,7 @@ const handleSave = async () => {
return !decision
})
if (hasUnselected) {
message.error('请先为所有待检测记录选择通过或不通过')
message.error(t('EquipmentManagement.WorkOrderManagement.selectAllDecisionError'))
return
}
const payload: TicketResultVO[] = []
@ -151,17 +207,17 @@ const handleSave = async () => {
payload.push({ ...(row as any), inspectionResult: decision, images: img || row.images })
}
if (!payload.length) {
message.error('请先为待检测记录选择通过或不通过')
message.error(t('EquipmentManagement.WorkOrderManagement.selectDecisionError'))
return
}
submitLoading.value = true
try {
await TicketManagementApi.batchUpdateTicketResults(payload)
message.success('更新成功')
message.success(t('EquipmentManagement.WorkOrderManagement.updateSuccess'))
emit('success')
dialogVisible.value = false
} catch {
message.error('更新失败')
message.error(t('EquipmentManagement.WorkOrderManagement.updateFail'))
} finally {
submitLoading.value = false
}

@ -1,34 +1,60 @@
<template>
<ContentWrap>
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="单号" prop="planNo">
<el-form-item :label="t('EquipmentManagement.WorkOrderManagement.planNo')" prop="planNo">
<el-input
v-model="queryParams.planNo" placeholder="请输入单号" clearable @keyup.enter="handleQuery"
v-model="queryParams.planNo"
:placeholder="t('EquipmentManagement.WorkOrderManagement.placeholderPlanNo')"
clearable
@keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="类型" prop="planType">
<el-select v-model="queryParams.planType" placeholder="请选择类型" clearable class="!w-240px">
<el-form-item :label="t('EquipmentManagement.WorkOrderManagement.planType')" prop="planType">
<el-select
v-model="queryParams.planType"
:placeholder="t('EquipmentManagement.WorkOrderManagement.placeholderPlanType')"
clearable
class="!w-240px"
>
<el-option v-for="opt in planTypeOptions" :key="String(opt.value)" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
<el-form-item label="作业状态" prop="jobStatus">
<el-select v-model="queryParams.jobStatus" placeholder="请选择作业状态" clearable class="!w-240px">
<el-form-item :label="t('EquipmentManagement.WorkOrderManagement.jobStatus')" prop="jobStatus">
<el-select
v-model="queryParams.jobStatus"
:placeholder="t('EquipmentManagement.WorkOrderManagement.placeholderJobStatus')"
clearable
class="!w-240px"
>
<el-option
v-for="opt in getStrDictOptions('job_status')" :key="String(opt.value)" :label="opt.label"
v-for="opt in getStrDictOptions('job_status')"
:key="String(opt.value)"
:label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
<el-form-item label="结果" prop="jobResult">
<el-select v-model="queryParams.jobResult" placeholder="请选择结果" clearable class="!w-240px">
<el-form-item :label="t('EquipmentManagement.WorkOrderManagement.jobResult')" prop="jobResult">
<el-select
v-model="queryParams.jobResult"
:placeholder="t('EquipmentManagement.WorkOrderManagement.placeholderJobResult')"
clearable
class="!w-240px"
>
<el-option v-for="opt in jobResultOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
<Icon icon="ep:refresh" class="mr-5px" />
{{ t('common.reset') }}
</el-button>
<el-button type="primary" @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> 查询
<Icon icon="ep:search" class="mr-5px" />
{{ t('common.query') }}
</el-button>
<el-button type="success" plain @click="handleExport" :loading="exportLoading">
<Icon icon="ep:download" class="mr-5px" />
导出
</el-button>
</el-form-item>
</el-form>
@ -37,49 +63,128 @@ v-for="opt in getStrDictOptions('job_status')" :key="String(opt.value)" :label="
<ContentWrap>
<div class="mb-10px">
<el-button
type="warning" plain @click="handleBatchCancel" :disabled="!selectedIds.length"
:loading="cancelLoading">
取消任务
type="warning"
plain
@click="handleBatchCancel"
:disabled="!selectedIds.length"
:loading="cancelLoading"
>
{{ t('EquipmentManagement.WorkOrderManagement.cancelTask') }}
</el-button>
</div>
<el-table
v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"
@selection-change="handleSelectionChange" @row-click="handleRowClick">
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
row-key="id"
@selection-change="handleSelectionChange"
@row-click="handleRowClick"
>
<el-table-column type="selection" width="55" />
<el-table-column type="index" label="序号" align="center" width="70" />
<el-table-column label="单号" align="center" prop="planNo" min-width="160" />
<el-table-column label="设备名称" align="center" prop="deviceName" min-width="160" />
<el-table-column label="类型" align="center" prop="planType" width="90">
<!-- <el-table-column
type="index"
:label="t('EquipmentManagement.WorkOrderManagement.index')"
align="center"
width="70"
/> -->
<el-table-column
:label="t('EquipmentManagement.WorkOrderManagement.planNo')"
align="center"
prop="planNo"
min-width="160"
/>
<el-table-column
:label="t('EquipmentManagement.WorkOrderManagement.deviceName')"
align="center"
prop="deviceName"
min-width="160"
/>
<el-table-column
:label="t('EquipmentManagement.WorkOrderManagement.planType')"
align="center"
prop="planType"
width="90"
>
<template #default="scope">
<el-tag v-if="String(scope.row.planType) === '1'" type="primary"></el-tag>
<el-tag v-else-if="String(scope.row.planType) === '2'" type="success">保养</el-tag>
<el-tag v-if="String(scope.row.planType) === '1'" type="primary">
{{ t('EquipmentManagement.WorkOrderManagement.planTypeInspect') }}
</el-tag>
<el-tag v-else-if="String(scope.row.planType) === '2'" type="success">
{{ t('EquipmentManagement.WorkOrderManagement.planTypeMaintain') }}
</el-tag>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="计划配置名称" align="center" prop="configName" min-width="160" />
<el-table-column label="作业状态" align="center" prop="jobStatus" width="120">
<el-table-column
:label="t('EquipmentManagement.WorkOrderManagement.configName')"
align="center"
prop="configName"
min-width="160"
/>
<el-table-column
:label="t('EquipmentManagement.WorkOrderManagement.jobStatus')"
align="center"
prop="jobStatus"
width="120"
>
<template #default="scope">
<dict-tag :type="'job_status'" :value="scope.row.jobStatus" />
</template>
</el-table-column>
<el-table-column label="作业人" align="center" prop="operatorName" width="140" />
<el-table-column label="作业时间" align="center" prop="taskTime" :formatter="dateFormatter" width="180" />
<el-table-column label="计划结束作业时间" align="center" prop="taskEndTime" :formatter="dateFormatter" width="180" />
<el-table-column label="结果" align="center" prop="jobResult" width="90">
<el-table-column
:label="t('EquipmentManagement.WorkOrderManagement.operatorName')"
align="center"
prop="operatorName"
width="140"
/>
<el-table-column
:label="t('EquipmentManagement.WorkOrderManagement.taskTime')"
align="center"
prop="taskTime"
:formatter="dateFormatter"
width="180"
/>
<el-table-column
:label="t('EquipmentManagement.WorkOrderManagement.taskEndTime')"
align="center"
prop="taskEndTime"
:formatter="dateFormatter"
width="180"
/>
<el-table-column
:label="t('EquipmentManagement.WorkOrderManagement.jobResult')"
align="center"
prop="jobResult"
width="90"
>
<template #default="scope">
<el-tag v-if="scope.row.jobResult == '1'" type="success"></el-tag>
<el-tag v-else-if="scope.row.jobResult == '2'" type="danger">不通过</el-tag>
<el-tag v-if="scope.row.jobResult == '1'" type="success">
{{ t('EquipmentManagement.WorkOrderManagement.jobResultOk') }}
</el-tag>
<el-tag v-else-if="scope.row.jobResult == '2'" type="danger">
{{ t('EquipmentManagement.WorkOrderManagement.jobResultNg') }}
</el-tag>
<span v-else>-</span>
</template>
</el-table-column>
<!-- <el-table-column label="备注" align="center" prop="remark" min-width="160" /> -->
<el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180" />
<el-table-column
:label="t('EquipmentManagement.WorkOrderManagement.createTime')"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180"
/>
</el-table>
<Pagination
:total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
@pagination="getList" />
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<TicketResultDialog ref="resultDialogRef" @success="getList" />
@ -99,12 +204,12 @@ const message = useMessage()
const dictStore = useDictStoreWithOut()
const planTypeOptions = [
{ label: '点检', value: '1' },
{ label: '保养', value: '2' }
{ label: t('EquipmentManagement.WorkOrderManagement.planTypeInspect'), value: '1' },
{ label: t('EquipmentManagement.WorkOrderManagement.planTypeMaintain'), value: '2' }
]
const jobResultOptions = [
{ label: '通过', value: 'OK' },
{ label: '不通过', value: 'NG' }
{ label: t('EquipmentManagement.WorkOrderManagement.jobResultOk'), value: 'OK' },
{ label: t('EquipmentManagement.WorkOrderManagement.jobResultNg'), value: 'NG' }
]
const loading = ref(true)
@ -112,6 +217,7 @@ const list = ref<TicketManagementVO[]>([])
const total = ref(0)
const selectedIds = ref<number[]>([])
const cancelLoading = ref(false)
const exportLoading = ref(false)
const queryParams = reactive({
pageNo: 1,
@ -154,10 +260,10 @@ const handleSelectionChange = (rows: TicketManagementVO[]) => {
const handleBatchCancel = async () => {
if (!selectedIds.value.length) return
try {
await message.confirm('确认取消选中的任务吗?')
await message.confirm(t('EquipmentManagement.WorkOrderManagement.cancelConfirm'))
cancelLoading.value = true
await TicketManagementApi.batchUpdateTicketStatus({ ids: selectedIds.value.join(','), jobStatus: '2' })
message.success('取消任务成功')
message.success(t('EquipmentManagement.WorkOrderManagement.cancelSuccess'))
selectedIds.value = []
await getList()
} catch {
@ -166,6 +272,24 @@ const handleBatchCancel = async () => {
}
}
const handleExport = async () => {
try {
await message.exportConfirm()
exportLoading.value = true
const params: any = {
...queryParams,
ids: selectedIds.value.length ? selectedIds.value.join(',') : undefined
}
const data = await TicketManagementApi.exportTicketManagement(params)
//
const download = (await import('@/utils/download')).default
download.excel(data, '工单管理.xls')
} catch {
} finally {
exportLoading.value = false
}
}
const resultDialogRef = ref<InstanceType<typeof TicketResultDialog>>()
const handleRowClick = async (row: TicketManagementVO, column: any) => {
@ -173,7 +297,9 @@ const handleRowClick = async (row: TicketManagementVO, column: any) => {
if (!row?.id) return
await resultDialogRef.value?.open({
managementId: row.id,
title: row.planNo ? `检验结果-${row.planNo}` : '检验结果'
title: row.planNo
? `${t('EquipmentManagement.WorkOrderManagement.dialogTitleDefault')}-${row.planNo}`
: t('EquipmentManagement.WorkOrderManagement.dialogTitleDefault')
})
}

@ -61,7 +61,15 @@ type="success" plain @click="handleExport" :loading="exportLoading"
</ContentWrap>
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
row-key="id"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" fixed="left" reserve-selection />
<el-table-column label="序号" type="index" width="80" />
<el-table-column label="单号" align="center" prop="code" />
<el-table-column label="质检分类" align="center">
@ -168,6 +176,8 @@ const exportLoading = ref(false)
const orgTypeOptions = getStrDictOptions(DICT_TYPE.MES_ORG_TYPE)
const selectedIds = ref<number[]>([])
const getList = async () => {
loading.value = true
try {
@ -210,11 +220,19 @@ const handleDelete = async (id: number) => {
} catch { }
}
const handleSelectionChange = (rows: ZjTaskVO[]) => {
selectedIds.value = (rows.map((row) => row.id).filter((id) => id !== undefined && id !== null) as number[])
}
const handleExport = async () => {
try {
await message.exportConfirm()
exportLoading.value = true
const data = await ZjTaskApi.exportZjTask(queryParams)
const params = {
...queryParams,
ids: selectedIds.value.length ? selectedIds.value.join(',') : undefined,
}
const data = await ZjTaskApi.exportZjTask(params)
download.excel(data, '检验任务.xls')
} catch {
} finally {

@ -44,7 +44,15 @@ type="success" plain @click="handleExport" :loading="exportLoading"
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
row-key="id"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" fixed="left" reserve-selection />
<!-- <el-table-column label="ID" align="center" prop="id" /> -->
<el-table-column label="名称" align="center" prop="name" />
<el-table-column label="作业方式" align="center" prop="tool" />
@ -113,6 +121,7 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const selectedIds = ref<number[]>([])
/** 查询列表 */
const getList = async () => {
@ -157,6 +166,10 @@ const handleDelete = async (id: number) => {
} catch { }
}
const handleSelectionChange = (rows: any[]) => {
selectedIds.value = rows?.map((row) => row.id).filter((id) => id !== undefined) ?? []
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
@ -164,7 +177,11 @@ const handleExport = async () => {
await message.exportConfirm()
//
exportLoading.value = true
const data = await ZjItemApi.exportZjItem(queryParams)
const params = {
...queryParams,
ids: selectedIds.value.length ? selectedIds.value.join(',') : undefined,
}
const data = await ZjItemApi.exportZjItem(params)
download.excel(data, '质量管理-检验项目.xls')
} catch {
} finally {

@ -61,7 +61,15 @@ type="success" plain @click="handleExport" :loading="exportLoading"
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" @expand-change="handleExpandChange">
<el-table
v-loading="loading"
:data="list"
:show-overflow-tooltip="true"
row-key="id"
@expand-change="handleExpandChange"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" fixed="left" reserve-selection />
<el-table-column type="expand">
<template #default="scope">
<el-table
@ -148,6 +156,7 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const selectedIds = ref<number[]>([])
const formatValDisplay = (val: any) => {
if (val === undefined || val === null || val === '') return ''
@ -205,6 +214,10 @@ const handleDelete = async (id: number) => {
} catch { }
}
const handleSelectionChange = (rows: any[]) => {
selectedIds.value = rows?.map((row) => row.id).filter((id) => id !== undefined) ?? []
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
@ -212,7 +225,11 @@ const handleExport = async () => {
await message.exportConfirm()
//
exportLoading.value = true
const data = await ZjSchemaApi.exportZjSchema(queryParams)
const params = {
...queryParams,
ids: selectedIds.value.length ? selectedIds.value.join(',') : undefined,
}
const data = await ZjSchemaApi.exportZjSchema(params)
download.excel(data, '检验方案.xls')
} catch {
} finally {

@ -72,7 +72,15 @@
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
row-key="id"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" fixed="left" reserve-selection />
<!-- <el-table-column label="ID" align="center" prop="id" /> -->
<el-table-column label="编码" align="center" prop="code" />
<el-table-column label="名称" align="center" prop="name" />
@ -143,6 +151,7 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const selectedIds = ref<number[]>([])
/** 查询列表 */
const getList = async () => {
@ -187,6 +196,10 @@ const handleDelete = async (id: number) => {
} catch {}
}
const handleSelectionChange = (rows: any[]) => {
selectedIds.value = rows?.map((row) => row.id).filter((id) => id !== undefined) ?? []
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
@ -194,7 +207,11 @@ const handleExport = async () => {
await message.exportConfirm()
//
exportLoading.value = true
const data = await ZjTypeApi.exportZjType(queryParams)
const params = {
...queryParams,
ids: selectedIds.value.length ? selectedIds.value.join(',') : undefined,
}
const data = await ZjTypeApi.exportZjType(params)
download.excel(data, '质量管理-检验类型.xls')
} catch {
} finally {
@ -206,4 +223,4 @@ const handleExport = async () => {
onMounted(() => {
getList()
})
</script>
</script>

@ -83,7 +83,7 @@
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.enabled" />
</template>
</el-table-column>
<el-table-column label="创建人" align="center" prop="creator" width="120" />
<el-table-column label="创建人" align="center" prop="creatorName" width="120" />
<el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180" />
<el-table-column label="更新时间" align="center" prop="updateTime" :formatter="dateFormatter" width="180" />
<el-table-column label="操作" fixed="right" align="center" width="230">

@ -69,7 +69,7 @@
class="mb-16px"
>
<el-card shadow="hover" class="dashboard-card" :body-style="{ padding: '0' }">
<div class="dashboard-card-image-wrapper">
<div class="dashboard-card-image-wrapper" @click="handlePreview(item)">
<img
class="dashboard-card-image"
:src="item.indexImage || defaultImage"
@ -89,9 +89,21 @@
</div>
</div>
<div class="dashboard-card-actions">
<el-button type="primary" text @click="handlePreview(item)">
<Icon icon="ep:arrow-right" class="mr-5px" /> 预览
</el-button>
<el-popover placement="bottom-end" trigger="click" width="140">
<div class="dashboard-card-menu">
<el-button type="primary" text @click="openEditDialog(item)">
编辑
</el-button>
<el-button type="danger" text @click="handleDelete(item)">
删除
</el-button>
</div>
<template #reference>
<el-button text circle>
<Icon icon="ep:more" />
</el-button>
</template>
</el-popover>
</div>
</div>
</el-card>
@ -107,7 +119,11 @@
</div>
</ContentWrap>
<el-dialog v-model="createDialogVisible" title="新增数据大屏" width="600px">
<el-dialog
v-model="createDialogVisible"
:title="dialogMode === 'create' ? '新增数据大屏' : '编辑数据大屏'"
width="600px"
>
<el-form :model="createForm" ref="createFormRef" label-width="80px">
<el-form-item label="名称">
<el-input v-model="createForm.name" placeholder="请输入名称" />
@ -142,7 +158,7 @@
</el-form>
<template #footer>
<el-button @click="createDialogVisible = false"> </el-button>
<el-button type="primary" :loading="createLoading" @click="submitCreate">
<el-button type="primary" :loading="createLoading" @click="submitDialog">
</el-button>
</template>
@ -157,6 +173,7 @@ import defaultImage from '@/assets/imgs/logo.png'
defineOptions({ name: 'DashboardList' })
const { push } = useRouter()
const message = useMessage()
interface DashboardItem {
id: number
@ -165,6 +182,7 @@ interface DashboardItem {
state: string
indexImage?: string
route?: string
content?: string
}
const loading = ref(false)
@ -184,6 +202,8 @@ const queryFormRef = ref()
const createDialogVisible = ref(false)
const createLoading = ref(false)
const createFormRef = ref()
const dialogMode = ref<'create' | 'edit'>('create')
const editingId = ref<number | null>(null)
const createForm = reactive({
name: '',
remark: '',
@ -219,7 +239,7 @@ const resetQuery = () => {
const handlePreview = (item: DashboardItem) => {
if (!item.route) {
useMessage().error('未配置预览路由')
message.error('未配置预览路由')
return
}
const path = item.route.startsWith('/') ? item.route : `/${item.route}`
@ -236,22 +256,51 @@ const resetCreateForm = () => {
}
const openCreateDialog = () => {
dialogMode.value = 'create'
editingId.value = null
resetCreateForm()
createDialogVisible.value = true
}
const submitCreate = async () => {
const openEditDialog = (item: DashboardItem) => {
dialogMode.value = 'edit'
editingId.value = item.id
createForm.name = item.name || ''
createForm.remark = item.remark || ''
createForm.state = item.state || ''
createForm.indexImage = item.indexImage || ''
createForm.route = item.route || ''
createForm.content = item.content || ''
createDialogVisible.value = true
}
const submitDialog = async () => {
if (!createForm.name) {
useMessage().error('名称不能为空')
message.error('名称不能为空')
return
}
if (dialogMode.value === 'edit' && !editingId.value) {
message.error('缺少数据编号,无法编辑')
return
}
createLoading.value = true
try {
await request.post({
url: '/mes/goview/create',
data: createForm
})
useMessage().success('新增成功')
if (dialogMode.value === 'create') {
await request.post({
url: '/mes/goview/create',
data: createForm
})
message.success('新增成功')
} else {
await request.put({
url: '/mes/goview/update',
data: {
id: editingId.value,
...createForm
}
})
message.success('编辑成功')
}
createDialogVisible.value = false
handleQuery()
} finally {
@ -259,6 +308,18 @@ const submitCreate = async () => {
}
}
const handleDelete = async (item: DashboardItem) => {
if (!item.id) return
try {
await message.delConfirm()
await request.delete({
url: `/mes/goview/delete?id=${item.id}`
})
message.success('删除成功')
await getList()
} catch {}
}
onMounted(() => {
getList()
})
@ -279,6 +340,7 @@ onMounted(() => {
width: 100%;
padding-top: 56.25%;
overflow: hidden;
cursor: pointer;
}
.dashboard-card-image {

@ -0,0 +1,197 @@
<template>
<div class="dashboard-container">
<div class="bg-grid"></div>
<div class="bg-scan"><div class="scan-line"></div></div>
<DashboardHeader />
<main>
<div class="layout">
<el-row :gutter="10" class="main-row">
<el-col :span="5" class="col">
<div class="col-item col-item-overview">
<!-- 设备概况 -->
<DeviceOverview />
</div>
<div class="col-item col-item-payment">
<!-- Payment method -->
<PaymentMethod />
</div>
<div class="col-item col-item-extra">
<!-- 产量趋势 -->
<ProductionTrend />
</div>
</el-col>
<el-col :span="14" class="col">
<div class="center-shell">
<img class="dashboard-center-image" src="@/assets/imgs/dashboard_img.png" alt="dashboard" />
</div>
</el-col>
<el-col :span="5" class="col">
<div class="col-item col-item-event">
<!-- 事件提醒 -->
<EventReminder />
</div>
<div class="col-item col-item-task">
<!-- 任务列表 -->
<TaskList />
</div>
<div class="col-item col-item-energy">
<!-- 能耗监测 -->
<EnergyMonitor />
</div>
</el-col>
</el-row>
</div>
</main>
</div>
</template>
<script setup lang="ts">
import DashboardHeader from './components/DashboardHeader.vue'
import DeviceOverview from './components/DeviceOverview.vue'
import PaymentMethod from './components/PaymentMethod.vue'
import EventReminder from './components/EventReminder.vue'
import TaskList from './components/TaskList.vue'
import EnergyMonitor from './components/EnergyMonitor.vue'
import ProductionTrend from './components/ProductionTrend.vue'
</script>
<style scoped>
/* Define CSS Variables locally for this dashboard */
.dashboard-container {
--bg: #050816;
--bg-deep: #020617;
--card-bg: rgba(15, 23, 42, 0.86);
--border: rgba(56, 189, 248, 0.35);
--text: #e5f0ff;
--muted: #94a3b8;
--primary: #38bdf8;
--accent: #22d3ee;
--blue: #1e90ff;
--green: #22c55e;
--purple: #8b5cf6;
--warn: #f59e0b;
--danger: #ef4444;
--gap: 10px;
--header-h: 86px;
position: relative;
width: 100%;
min-height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Microsoft Yahei", Arial, sans-serif;
color: var(--text);
background-color: var(--bg-deep);
background-image:
radial-gradient(circle at 20% 0, rgba(56, 189, 248, 0.26) 0, transparent 48%),
radial-gradient(circle at 80% 110%, rgba(129, 140, 248, 0.22) 0, transparent 52%),
linear-gradient(135deg, #020617 0%, #020617 45%, #020617 100%);
}
.bg-grid {
position: absolute;
inset: 0;
pointer-events: none;
background-image: linear-gradient(rgba(15,23,42,0.8) 1px, transparent 1px),
linear-gradient(90deg, rgba(15,23,42,0.8) 1px, transparent 1px);
background-size: 70px 70px;
opacity: 0.55;
z-index: 0;
}
.bg-scan {
position: absolute;
inset: 0;
overflow: hidden;
pointer-events: none;
z-index: 0;
}
.scan-line {
position: absolute;
top: -40%;
left: 0;
width: 100%;
height: 40%;
background: radial-gradient(circle at 50% 0, rgba(56, 189, 248, 0.38), transparent 70%);
opacity: 0.5;
filter: blur(32px);
animation: scanDown 16s linear infinite;
}
@keyframes scanDown {
0% { transform: translateY(-100%); }
100% { transform: translateY(260%); }
}
main {
height: calc(100vh - var(--header-h));
padding: var(--gap);
box-sizing: border-box;
position: relative;
z-index: 1;
display: flex;
flex-direction: column;
gap: var(--gap);
min-height: 0;
}
.layout {
flex: 1;
height: 100%;
display: flex;
flex-direction: column;
gap: var(--gap);
width: 100%;
min-height: 0;
}
.main-row {
flex: 1;
height: 100%;
min-height: 0;
}
.col {
height: 100%;
min-height: 0;
display: flex;
flex-direction: column;
gap: var(--gap);
}
.col-item {
flex: 1;
min-height: 0;
display: flex;
}
.col-item :deep(> *) {
width: 100%;
height: 100%;
}
.center-shell {
flex: 1;
min-height: 0;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
border: 1px solid rgba(30,64,175,0.55);
background: rgba(2,6,23,0.18);
padding: 10px;
}
.dashboard-center-image {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
</style>

@ -0,0 +1,269 @@
<template>
<header>
<div class="header-inner">
<div class="header-left">
<div class="time">{{ timeStr }}</div>
<div class="date">{{ dateStr }}</div>
</div>
<div class="header-center">
<div class="title-wrap">
<svg class="title-frame" viewBox="0 0 1200 120" preserveAspectRatio="none" aria-hidden="true">
<defs>
<linearGradient id="frameStroke" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" stop-color="rgba(34,211,238,0.0)" />
<stop offset="0.18" stop-color="rgba(34,211,238,0.85)" />
<stop offset="0.5" stop-color="rgba(96,165,250,0.95)" />
<stop offset="0.82" stop-color="rgba(34,211,238,0.85)" />
<stop offset="1" stop-color="rgba(34,211,238,0.0)" />
</linearGradient>
<linearGradient id="frameFill" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="rgba(30,144,255,0.20)" />
<stop offset="1" stop-color="rgba(2,6,23,0.0)" />
</linearGradient>
<filter id="frameGlow" x="-30%" y="-60%" width="160%" height="220%">
<feGaussianBlur stdDeviation="3.2" result="blur" />
<feColorMatrix
in="blur"
type="matrix"
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0"
result="colored"
/>
<feMerge>
<feMergeNode in="colored" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</defs>
<path d="M10 5 L150 115 L1050 115 L1190 5 Z" fill="url(#frameFill)" />
<path
d="M10 5 L150 115 L1050 115 L1190 5"
stroke="url(#frameStroke)"
stroke-width="4"
fill="none"
filter="url(#frameGlow)"
/>
</svg>
<div class="title">产线运行看板</div>
</div>
</div>
<div class="header-right">
<div class="back-btn" @click="goBack">
<Icon icon="ep:back" />
<span>返回</span>
</div>
<div class="weather">
<Icon icon="fa-solid:cloud-sun" class="weather-icon" />
<div class="weather-meta">
<div class="temp">{{ weather.temp }}</div>
<div class="desc">{{ weather.desc }}</div>
</div>
</div>
</div>
</div>
</header>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter()
const timeStr = ref('')
const dateStr = ref('')
const weather = ref({ temp: '27°C', desc: 'Cloudy to clear' })
let timer: number | undefined
const goBack = () => {
router.back()
}
const updateTime = () => {
const d = new Date()
const h = String(d.getHours()).padStart(2, '0')
const mi = String(d.getMinutes()).padStart(2, '0')
const s = String(d.getSeconds()).padStart(2, '0')
timeStr.value = `${h}:${mi}:${s}`
const y = d.getFullYear()
const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
const weekMap = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
dateStr.value = `${weekMap[d.getDay()]}, ${y}-${m}-${day}`
}
onMounted(() => {
updateTime()
timer = window.setInterval(updateTime, 1000)
})
onUnmounted(() => {
if (timer) clearInterval(timer)
})
</script>
<style scoped>
header {
height: var(--header-h);
position: relative;
z-index: 2;
display: flex;
align-items: center;
padding: 0 18px;
background:
linear-gradient(to bottom, rgba(15, 23, 42, 0.95), rgba(15, 23, 42, 0.85)),
radial-gradient(circle at 50% 0, rgba(56, 189, 248, 0.22), transparent 60%);
border-bottom: 1px solid rgba(148, 163, 184, 0.35);
box-shadow: 0 10px 35px rgba(15, 23, 42, 0.9);
}
.header-inner {
width: 100%;
display: grid;
grid-template-columns: 320px 1fr 320px;
align-items: center;
gap: 12px;
}
.header-left {
justify-self: start;
display: flex;
flex-direction: column;
gap: 2px;
}
.time {
font-size: 22px;
font-weight: 800;
color: #e0f2fe;
letter-spacing: 1px;
}
.date {
font-size: 12px;
color: var(--muted);
}
.header-center {
justify-self: center;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
}
.title-wrap {
position: relative;
width: min(980px, 100%);
height: 64px;
display: flex;
align-items: center;
justify-content: center;
}
.title-frame {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
pointer-events: none;
opacity: 0.95;
}
.title {
position: relative;
z-index: 1;
font-size: 28px;
font-weight: 900;
letter-spacing: 3px;
background: linear-gradient(to bottom, #e0f2fe, #60a5fa);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
text-shadow: 0 0 20px rgba(56, 189, 248, 0.65);
}
.header-right {
justify-self: end;
display: flex;
align-items: center;
justify-content: flex-end;
gap: 20px;
}
.back-btn {
display: flex;
align-items: center;
gap: 6px;
padding: 6px 16px;
border-radius: 4px;
background: rgba(30, 64, 175, 0.3);
border: 1px solid rgba(56, 189, 248, 0.3);
color: #e0f2fe;
font-size: 14px;
cursor: pointer;
transition: all 0.3s;
}
.back-btn:hover {
background: rgba(30, 64, 175, 0.6);
border-color: rgba(56, 189, 248, 0.8);
box-shadow: 0 0 10px rgba(56, 189, 248, 0.4);
}
.weather {
display: flex;
align-items: center;
gap: 12px;
color: var(--muted);
}
.weather-icon {
font-size: 28px;
color: var(--accent);
}
.weather-meta {
display: flex;
flex-direction: column;
line-height: 1.2;
}
.temp {
font-size: 16px;
font-weight: 700;
color: #e0f2fe;
}
.desc {
font-size: 12px;
color: var(--muted);
}
@media (max-width: 1600px) {
.title {
font-size: 24px;
}
.title-wrap {
height: 58px;
}
.header-inner {
grid-template-columns: 280px 1fr 280px;
}
}
@media (max-width: 1366px) {
.title {
font-size: 20px;
letter-spacing: 3px;
}
.title-wrap {
height: 54px;
}
.time {
font-size: 18px;
}
}
</style>

@ -0,0 +1,157 @@
<template>
<div class="card">
<div class="panel-title">
<span class="title-dot"></span>
<span>设备概况</span>
</div>
<div class="panel-body overview-body">
<div v-for="item in overviewItems" :key="item.key" class="gauge-item">
<div class="gauge" :style="getGaugeStyle(item.percent, item.color)">
<div class="gauge-inner">
<div class="gauge-value">{{ item.value }}</div>
<div class="gauge-label">{{ item.label }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { colors } from '../utils'
const overviewItems = [
{ key: 'device', label: '设备数量', value: '987,965', percent: 78, color: colors.cyan },
{ key: 'running', label: '运行数量', value: '30', percent: 66, color: colors.blue },
{ key: 'idle', label: '待机数量', value: '2', percent: 42, color: colors.warn },
{ key: 'alarm', label: '报警数量', value: '10', percent: 58, color: colors.danger }
]
const getGaugeStyle = (percent: number, color: string) => {
const p = Math.max(0, Math.min(100, percent))
return {
background: `conic-gradient(${color} ${p * 3.6}deg, rgba(148,163,184,0.18) 0deg)`
}
}
</script>
<style scoped>
.card {
height: 100%;
background: linear-gradient(135deg, rgba(15,23,42,0.96), rgba(15,23,42,0.88));
border-radius: 8px;
border: 1px solid rgba(30,64,175,0.85);
box-shadow:
0 18px 45px rgba(15,23,42,0.95),
0 0 0 1px rgba(15,23,42,1),
inset 0 0 0 1px rgba(56,189,248,0.05);
position: relative;
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 0;
}
.card::before,
.card::after {
content: "";
position: absolute;
width: 12px;
height: 12px;
border-radius: 2px;
border: 1px solid rgba(56,189,248,0.75);
opacity: 0.6;
pointer-events: none;
}
.card::before {
top: -1px;
left: -1px;
border-right: none;
border-bottom: none;
}
.card::after {
right: -1px;
bottom: -1px;
border-left: none;
border-top: none;
}
.panel-title {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 12px;
border-bottom: 1px solid rgba(41, 54, 95, 0.9);
font-size: 16px;
font-weight: 900;
color: #e5f0ff;
}
.title-dot {
width: 10px;
height: 10px;
border-radius: 50%;
border: 1px solid rgba(56,189,248,0.95);
box-shadow: 0 0 12px rgba(56,189,248,0.45);
}
.panel-body {
flex: 1;
min-height: 0;
padding: 10px 12px;
}
.overview-body {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
}
.gauge-item {
display: flex;
align-items: center;
justify-content: center;
}
.gauge {
width: 110px;
height: 110px;
border-radius: 50%;
padding: 8px;
box-sizing: border-box;
}
.gauge-inner {
width: 100%;
height: 100%;
border-radius: 50%;
background: rgba(2,6,23,0.92);
border: 1px solid rgba(148,163,184,0.25);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 2px;
text-align: center;
}
.gauge-value {
font-size: 18px;
font-weight: 900;
color: #e5f0ff;
}
.gauge-label {
font-size: 11px;
color: rgba(148,163,184,0.95);
}
@media (max-width: 1366px) {
.gauge {
width: 96px;
height: 96px;
}
}
</style>

@ -0,0 +1,187 @@
<template>
<div class="card">
<div class="panel-title panel-title-between">
<div class="panel-title-left">
<span class="title-dot"></span>
<span>能耗监测</span>
</div>
<div class="tabs">
<span class="tab" :class="{ active: energyTab === 'first' }" @click="energyTab = 'first'">First aid</span>
<span class="tab" :class="{ active: energyTab === 'after' }" @click="energyTab = 'after'">Aftermarket</span>
</div>
</div>
<div class="panel-body">
<div ref="chartRef" class="chart"></div>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, ref, watch } from 'vue'
import * as echarts from 'echarts'
import { colors, style } from '../utils'
const energyTab = ref<'first' | 'after'>('first')
const chartRef = ref<HTMLElement | null>(null)
let chart: echarts.ECharts | null = null
const render = () => {
if (!chart) return
const x = ['9:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00']
const y =
energyTab.value === 'first'
? [820, 1650, 980, 1240, 1560, 1320, 1680]
: [680, 1420, 880, 1100, 1320, 1180, 1480]
chart.setOption({
backgroundColor: 'transparent',
tooltip: { trigger: 'axis' },
grid: { top: '18%', left: '6%', right: '4%', bottom: '12%', containLabel: true },
xAxis: { type: 'category', data: x, axisLine: style.axisLine, axisLabel: { ...style.axisLabel, fontSize: 10 } },
yAxis: { type: 'value', axisLine: { show: false }, axisLabel: { ...style.axisLabel, fontSize: 10 }, splitLine: style.splitLine },
series: [
{
type: 'bar',
barWidth: 12,
itemStyle: {
borderRadius: [6, 6, 0, 0],
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: colors.blue },
{ offset: 1, color: 'rgba(30,144,255,0.10)' }
])
},
data: y
}
]
})
}
const resize = () => {
chart?.resize()
}
onMounted(() => {
if (!chartRef.value) return
chart = echarts.init(chartRef.value, 'dark', { renderer: 'canvas' })
render()
window.addEventListener('resize', resize)
})
onUnmounted(() => {
window.removeEventListener('resize', resize)
chart?.dispose()
})
watch(energyTab, () => {
render()
})
</script>
<style scoped>
.card {
height: 100%;
background: linear-gradient(135deg, rgba(15,23,42,0.96), rgba(15,23,42,0.88));
border-radius: 8px;
border: 1px solid rgba(30,64,175,0.85);
box-shadow:
0 18px 45px rgba(15,23,42,0.95),
0 0 0 1px rgba(15,23,42,1),
inset 0 0 0 1px rgba(56,189,248,0.05);
position: relative;
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 0;
}
.card::before,
.card::after {
content: "";
position: absolute;
width: 12px;
height: 12px;
border-radius: 2px;
border: 1px solid rgba(56,189,248,0.75);
opacity: 0.6;
pointer-events: none;
}
.card::before {
top: -1px;
left: -1px;
border-right: none;
border-bottom: none;
}
.card::after {
right: -1px;
bottom: -1px;
border-left: none;
border-top: none;
}
.panel-title {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 12px;
border-bottom: 1px solid rgba(41, 54, 95, 0.9);
font-size: 16px;
font-weight: 900;
color: #e5f0ff;
}
.panel-title-between {
justify-content: space-between;
}
.panel-title-left {
display: inline-flex;
align-items: center;
gap: 10px;
}
.title-dot {
width: 10px;
height: 10px;
border-radius: 50%;
border: 1px solid rgba(56,189,248,0.95);
box-shadow: 0 0 12px rgba(56,189,248,0.45);
}
.tabs {
display: inline-flex;
align-items: center;
gap: 10px;
font-size: 11px;
font-weight: 600;
color: rgba(148,163,184,0.95);
}
.tab {
cursor: pointer;
user-select: none;
padding: 2px 8px;
border-radius: 999px;
border: 1px solid rgba(148,163,184,0.4);
background: rgba(2,6,23,0.2);
}
.tab.active {
border-color: rgba(56,189,248,0.85);
color: #e0f2fe;
box-shadow: 0 0 14px rgba(56,189,248,0.35);
}
.panel-body {
flex: 1;
min-height: 0;
padding: 10px 12px;
}
.chart {
width: 100%;
height: 100%;
min-height: 160px;
}
</style>

@ -0,0 +1,239 @@
<template>
<div class="card">
<div class="panel-title">
<span class="title-dot"></span>
<span>事件提醒</span>
</div>
<div class="panel-body body">
<div class="event-list">
<div v-for="item in eventItems" :key="item.key" class="event-row">
<div class="event-name">
<span class="event-bullet" :style="{ borderColor: item.color }"></span>
<span>{{ item.name }}</span>
</div>
<div class="event-count" :style="{ color: item.color }">{{ item.count }}</div>
</div>
</div>
<div class="event-chart">
<div class="chart-container">
<div ref="chartRef" class="chart"></div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue'
import * as echarts from 'echarts'
import { colors } from '../utils'
const chartRef = ref<HTMLElement | null>(null)
let chart: echarts.ECharts | null = null
const eventItems = [
{ key: 'check', name: '点检', count: 1, percent: 30, color: colors.cyan },
{ key: 'maintain', name: '保养', count: 1, percent: 42, color: colors.warn },
{ key: 'repair', name: '维修', count: 1, percent: 20, color: colors.danger }
]
const render = () => {
if (!chart) return
const percentMap = Object.fromEntries(eventItems.map((i) => [i.name, i.percent])) as Record<string, number>
chart.setOption({
backgroundColor: 'transparent',
tooltip: { trigger: 'item' },
legend: {
orient: 'vertical',
right: 10,
top: 'center',
icon: 'circle',
itemWidth: 10,
itemHeight: 10,
itemGap: 14,
selectedMode: false,
textStyle: {
rich: {
percent: { fontSize: 18, fontWeight: 900, color: '#e5f0ff', lineHeight: 20 },
name: { fontSize: 12, fontWeight: 700, color: 'rgba(148,163,184,0.95)', lineHeight: 16 }
}
},
formatter: (name: string) => `{percent|${percentMap[name] ?? 0}%}\n{name|${name}}`
},
series: [
{
type: 'pie',
radius: ['48%', '70%'],
center: ['35%', '50%'],
avoidLabelOverlap: true,
label: { show: false },
labelLine: { show: false },
padAngle: 2,
itemStyle: { borderRadius: 8, borderWidth: 6, borderColor: 'rgba(2,6,23,0.9)' },
emphasis: { scale: false },
data: [
{ value: 30, name: '点检', itemStyle: { color: colors.cyan } },
{ value: 42, name: '保养', itemStyle: { color: colors.warn } },
{ value: 20, name: '维修', itemStyle: { color: colors.danger } }
]
}
]
})
}
const resize = () => {
chart?.resize()
}
onMounted(() => {
if (!chartRef.value) return
chart = echarts.init(chartRef.value, 'dark', { renderer: 'canvas' })
render()
window.addEventListener('resize', resize)
})
onUnmounted(() => {
window.removeEventListener('resize', resize)
chart?.dispose()
})
</script>
<style scoped>
.card {
height: 100%;
background: linear-gradient(135deg, rgba(15,23,42,0.96), rgba(15,23,42,0.88));
border-radius: 8px;
border: 1px solid rgba(30,64,175,0.85);
box-shadow:
0 18px 45px rgba(15,23,42,0.95),
0 0 0 1px rgba(15,23,42,1),
inset 0 0 0 1px rgba(56,189,248,0.05);
position: relative;
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 0;
}
.card::before,
.card::after {
content: "";
position: absolute;
width: 12px;
height: 12px;
border-radius: 2px;
border: 1px solid rgba(56,189,248,0.75);
opacity: 0.6;
pointer-events: none;
}
.card::before {
top: -1px;
left: -1px;
border-right: none;
border-bottom: none;
}
.card::after {
right: -1px;
bottom: -1px;
border-left: none;
border-top: none;
}
.panel-title {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 12px;
border-bottom: 1px solid rgba(41, 54, 95, 0.9);
font-size: 16px;
font-weight: 900;
color: #e5f0ff;
}
.title-dot {
width: 10px;
height: 10px;
border-radius: 50%;
border: 1px solid rgba(56,189,248,0.95);
box-shadow: 0 0 12px rgba(56,189,248,0.45);
}
.panel-body {
flex: 1;
min-height: 0;
padding: 10px 12px;
}
.body {
display: grid;
grid-template-columns: 0.7fr 1.3fr;
gap: 10px;
align-items: center;
}
.event-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.event-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 10px;
border-radius: 6px;
border: 1px solid rgba(30,64,175,0.7);
background: rgba(15,23,42,0.7);
}
.event-name {
display: inline-flex;
align-items: center;
gap: 8px;
font-size: 12px;
color: #e5f0ff;
}
.event-bullet {
width: 12px;
height: 12px;
border-radius: 50%;
border: 3px solid;
box-sizing: border-box;
}
.event-count {
font-size: 14px;
font-weight: 900;
}
.event-chart {
height: 100%;
min-height: 170px;
display: flex;
min-height: 0;
}
.chart-container {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
min-height: 0;
}
.chart {
width: 100%;
height: 100%;
}
@media (max-width: 1366px) {
.body {
grid-template-columns: 0.8fr 1.2fr;
}
}
</style>

@ -0,0 +1,170 @@
<template>
<div class="card">
<div class="panel-title">
<span class="title-dot"></span>
<span>Payment method</span>
<div class="date-filter">
<el-date-picker
v-model="pickedDate"
type="date"
format="YYYY MM/DD"
value-format="YYYY-MM-DD"
:clearable="false"
size="small"
/>
</div>
</div>
<div class="panel-body">
<div ref="chartRef" class="chart"></div>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue'
import * as echarts from 'echarts'
import { colors, style } from '../utils'
const chartRef = ref<HTMLElement | null>(null)
let chart: echarts.ECharts | null = null
const pickedDate = ref('2023-08-31')
const render = () => {
if (!chart) return
const x = ['9:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00']
const y = [60, 120, 165, 140, 185, 150, 190]
chart.setOption({
backgroundColor: 'transparent',
grid: { top: '14%', left: '6%', right: '4%', bottom: '12%', containLabel: true },
tooltip: { trigger: 'axis' },
xAxis: { type: 'category', data: x, axisLine: style.axisLine, axisLabel: { ...style.axisLabel, fontSize: 10 } },
yAxis: { type: 'value', axisLine: { show: false }, axisLabel: { ...style.axisLabel, fontSize: 10 }, splitLine: style.splitLine },
series: [
{
type: 'line',
smooth: true,
showSymbol: true,
symbolSize: 6,
lineStyle: { width: 2, color: colors.cyan },
itemStyle: { color: colors.cyan },
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(34,211,238,0.38)' },
{ offset: 1, color: 'rgba(34,211,238,0.06)' }
])
},
data: y
}
]
})
}
const resize = () => {
chart?.resize()
}
onMounted(() => {
if (!chartRef.value) return
chart = echarts.init(chartRef.value, 'dark', { renderer: 'canvas' })
render()
window.addEventListener('resize', resize)
})
onUnmounted(() => {
window.removeEventListener('resize', resize)
chart?.dispose()
})
</script>
<style scoped>
.card {
height: 100%;
background: linear-gradient(135deg, rgba(15,23,42,0.96), rgba(15,23,42,0.88));
border-radius: 8px;
border: 1px solid rgba(30,64,175,0.85);
box-shadow:
0 18px 45px rgba(15,23,42,0.95),
0 0 0 1px rgba(15,23,42,1),
inset 0 0 0 1px rgba(56,189,248,0.05);
position: relative;
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 0;
}
.card::before,
.card::after {
content: "";
position: absolute;
width: 12px;
height: 12px;
border-radius: 2px;
border: 1px solid rgba(56,189,248,0.75);
opacity: 0.6;
pointer-events: none;
}
.card::before {
top: -1px;
left: -1px;
border-right: none;
border-bottom: none;
}
.card::after {
right: -1px;
bottom: -1px;
border-left: none;
border-top: none;
}
.panel-title {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 12px;
border-bottom: 1px solid rgba(41, 54, 95, 0.9);
font-size: 16px;
font-weight: 900;
color: #e5f0ff;
}
.title-dot {
width: 10px;
height: 10px;
border-radius: 50%;
border: 1px solid rgba(56,189,248,0.95);
box-shadow: 0 0 12px rgba(56,189,248,0.45);
}
.date-filter {
margin-left: auto;
display: inline-flex;
align-items: center;
}
.date-filter :deep(.el-input__wrapper) {
background: rgba(2,6,23,0.35);
box-shadow: none;
border: 1px solid rgba(148,163,184,0.35);
}
.date-filter :deep(.el-input__inner) {
color: rgba(224,242,254,0.95);
font-size: 12px;
font-weight: 700;
}
.panel-body {
flex: 1;
min-height: 0;
padding: 10px 12px;
}
.chart {
width: 100%;
height: 100%;
min-height: 160px;
}
</style>

@ -0,0 +1,165 @@
<template>
<div class="card">
<div class="panel-title">
<span class="title-dot"></span>
<span>产量趋势</span>
<span class="tag">今日</span>
</div>
<div class="panel-body">
<div ref="chartRef" class="chart"></div>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue'
import * as echarts from 'echarts'
import { colors, style } from '../utils'
const chartRef = ref<HTMLElement | null>(null)
let chart: echarts.ECharts | null = null
const render = () => {
if (!chart) return
const x = ['9:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00']
const output = [320, 460, 520, 610, 720, 690, 780]
const passRate = [98.5, 99.2, 98.1, 98.9, 99.0, 98.6, 99.3]
chart.setOption({
backgroundColor: 'transparent',
tooltip: { trigger: 'axis' },
grid: { top: '18%', left: '6%', right: '6%', bottom: '12%', containLabel: true },
xAxis: { type: 'category', data: x, axisLine: style.axisLine, axisLabel: { ...style.axisLabel, fontSize: 10 } },
yAxis: [
{ type: 'value', axisLine: { show: false }, axisLabel: { ...style.axisLabel, fontSize: 10 }, splitLine: style.splitLine },
{ type: 'value', min: 96, max: 100, axisLine: { show: false }, axisLabel: { ...style.axisLabel, fontSize: 10 }, splitLine: { show: false } }
],
series: [
{
name: '产量',
type: 'bar',
barWidth: 12,
itemStyle: {
borderRadius: [6, 6, 0, 0],
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: colors.purple },
{ offset: 1, color: 'rgba(139,92,246,0.10)' }
])
},
data: output
},
{
name: '良率',
type: 'line',
yAxisIndex: 1,
smooth: true,
showSymbol: false,
lineStyle: { width: 2, color: colors.cyan },
data: passRate
}
]
})
}
const resize = () => {
chart?.resize()
}
onMounted(() => {
if (!chartRef.value) return
chart = echarts.init(chartRef.value, 'dark', { renderer: 'canvas' })
render()
window.addEventListener('resize', resize)
})
onUnmounted(() => {
window.removeEventListener('resize', resize)
chart?.dispose()
})
</script>
<style scoped>
.card {
height: 100%;
background: linear-gradient(135deg, rgba(15,23,42,0.96), rgba(15,23,42,0.88));
border-radius: 8px;
border: 1px solid rgba(30,64,175,0.85);
box-shadow:
0 18px 45px rgba(15,23,42,0.95),
0 0 0 1px rgba(15,23,42,1),
inset 0 0 0 1px rgba(56,189,248,0.05);
position: relative;
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 0;
}
.card::before,
.card::after {
content: "";
position: absolute;
width: 12px;
height: 12px;
border-radius: 2px;
border: 1px solid rgba(56,189,248,0.75);
opacity: 0.6;
pointer-events: none;
}
.card::before {
top: -1px;
left: -1px;
border-right: none;
border-bottom: none;
}
.card::after {
right: -1px;
bottom: -1px;
border-left: none;
border-top: none;
}
.panel-title {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 12px;
border-bottom: 1px solid rgba(41, 54, 95, 0.9);
font-size: 16px;
font-weight: 900;
color: #e5f0ff;
}
.title-dot {
width: 10px;
height: 10px;
border-radius: 50%;
border: 1px solid rgba(56,189,248,0.95);
box-shadow: 0 0 12px rgba(56,189,248,0.45);
}
.tag {
margin-left: auto;
border-radius: 999px;
padding: 2px 8px;
font-size: 11px;
font-weight: 700;
border: 1px solid rgba(148,163,184,0.4);
color: rgba(148,163,184,0.95);
background: rgba(2,6,23,0.2);
}
.panel-body {
flex: 1;
min-height: 0;
padding: 10px 12px;
}
.chart {
width: 100%;
height: 100%;
min-height: 160px;
}
</style>

@ -0,0 +1,152 @@
<template>
<div class="card">
<div class="panel-title">
<span class="title-dot"></span>
<span>任务列表</span>
</div>
<div class="panel-body table-body">
<table class="task-table">
<thead>
<tr>
<th>时间</th>
<th>类型</th>
<th>设备</th>
<th>责任人</th>
<th>状态</th>
</tr>
</thead>
<tbody>
<tr v-for="row in taskRows" :key="row.id" :class="row.status">
<td>{{ row.time }}</td>
<td>{{ row.type }}</td>
<td>{{ row.device }}</td>
<td>{{ row.owner }}</td>
<td class="status-cell" :style="{ color: row.color }">{{ row.statusLabel }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script setup lang="ts">
import { colors } from '../utils'
const taskRows = [
{ id: 1, time: '10:20', type: '点检', device: '1号装配机', owner: 'XXX', status: 'ok', statusLabel: '正常', color: colors.cyan },
{ id: 2, time: '10:25', type: '点检', device: '1号装配机', owner: 'XXX', status: 'ok', statusLabel: '正常', color: colors.cyan },
{ id: 3, time: '10:30', type: '维修', device: '1号装配机', owner: 'XXX', status: 'danger', statusLabel: '维修', color: colors.danger },
{ id: 4, time: '10:35', type: '保养', device: '1号装配机', owner: 'XXX', status: 'ok', statusLabel: '保养', color: colors.warn },
{ id: 5, time: '10:40', type: '点检', device: '1号装配机', owner: 'XXX', status: 'ok', statusLabel: '正常', color: colors.cyan },
{ id: 6, time: '10:45', type: '点检', device: '1号装配机', owner: 'XXX', status: 'ok', statusLabel: '正常', color: colors.cyan }
]
</script>
<style scoped>
.card {
height: 100%;
background: linear-gradient(135deg, rgba(15,23,42,0.96), rgba(15,23,42,0.88));
border-radius: 8px;
border: 1px solid rgba(30,64,175,0.85);
box-shadow:
0 18px 45px rgba(15,23,42,0.95),
0 0 0 1px rgba(15,23,42,1),
inset 0 0 0 1px rgba(56,189,248,0.05);
position: relative;
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 0;
}
.card::before,
.card::after {
content: "";
position: absolute;
width: 12px;
height: 12px;
border-radius: 2px;
border: 1px solid rgba(56,189,248,0.75);
opacity: 0.6;
pointer-events: none;
}
.card::before {
top: -1px;
left: -1px;
border-right: none;
border-bottom: none;
}
.card::after {
right: -1px;
bottom: -1px;
border-left: none;
border-top: none;
}
.panel-title {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 12px;
border-bottom: 1px solid rgba(41, 54, 95, 0.9);
font-size: 16px;
font-weight: 900;
color: #e5f0ff;
}
.title-dot {
width: 10px;
height: 10px;
border-radius: 50%;
border: 1px solid rgba(56,189,248,0.95);
box-shadow: 0 0 12px rgba(56,189,248,0.45);
}
.panel-body {
flex: 1;
min-height: 0;
padding: 10px 12px;
}
.table-body {
padding: 0;
}
.task-table {
width: 100%;
border-collapse: collapse;
table-layout: fixed;
font-size: 12px;
}
.task-table thead {
background: radial-gradient(circle at 0 0, rgba(56,189,248,0.18), transparent 70%);
}
.task-table th {
padding: 10px 8px;
color: var(--accent);
font-weight: 700;
text-align: left;
border-bottom: 1px solid rgba(51,65,85,0.9);
}
.task-table td {
padding: 10px 8px;
border-bottom: 1px solid rgba(30,64,175,0.3);
color: #e5f0ff;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.task-table tbody tr:hover td {
background: rgba(56,189,248,0.08);
}
.status-cell {
font-weight: 800;
}
</style>

@ -0,0 +1,62 @@
import { onMounted, onUnmounted } from 'vue'
import * as echarts from 'echarts'
export const colors = {
blue: '#1e90ff',
cyan: '#22d3ee',
green: '#22c55e',
purple: '#8b5cf6',
warn: '#f59e0b',
danger: '#ef4444'
}
export const style = {
axisLine: { lineStyle: { color: 'rgba(148,163,184,0.45)' } },
axisLabel: { color: '#a8b7d8', fontSize: 12 },
splitLine: { lineStyle: { color: 'rgba(30,64,175,0.55)', type: 'dashed' } },
legendText: { color: '#e5f0ff', fontSize: 12 }
}
export function animateCount(el: HTMLElement | null, target: number, suffix: string, duration: number) {
if (!el) return
const start = 0
const t0 = performance.now()
const step = (t: number) => {
const p = Math.min(1, (t - t0) / duration)
const v = start + (target - start) * p
const out = Number.isInteger(target) ? Math.round(v) : Math.round(v * 10) / 10
el.textContent = suffix ? `${out}${suffix}` : `${out}`
if (p < 1) requestAnimationFrame(step)
}
requestAnimationFrame(step)
}
export function useChart(domId: string) {
let chart: echarts.ECharts | null = null
const init = () => {
const el = document.getElementById(domId)
if (!el) return null
chart = echarts.init(el, 'dark', { renderer: 'canvas' })
return chart
}
const resize = () => {
chart?.resize()
}
onMounted(() => {
window.addEventListener('resize', resize)
})
onUnmounted(() => {
window.removeEventListener('resize', resize)
chart?.dispose()
})
return {
init,
resize,
instance: () => chart
}
}

@ -11,6 +11,10 @@
</div>
</div>
<div class="header-right">
<el-button class="back-btn" type="primary" size="small" plain @click="goBack">
<Icon icon="fa-solid:arrow-left" class="back-icon" />
<span>返回</span>
</el-button>
<span class="chip">
<Icon icon="fa-regular:clock" class="chip-icon" />
<span>{{ timeStr }}</span>
@ -26,6 +30,9 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter()
const timeStr = ref('')
let timer: number | undefined
@ -41,6 +48,10 @@ const updateTime = () => {
timeStr.value = `${y}-${m}-${day} ${h}:${mi}:${s}`
}
const goBack = () => {
router.back()
}
onMounted(() => {
updateTime()
timer = window.setInterval(updateTime, 1000)
@ -123,6 +134,28 @@ header {
color: var(--muted);
}
.back-btn {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 4px 12px;
border-radius: 999px;
border-color: rgba(56, 189, 248, 0.85);
background: radial-gradient(circle at 0 0, rgba(56, 189, 248, 0.22), transparent 70%);
color: #e0f2fe;
box-shadow: 0 0 18px rgba(56, 189, 248, 0.45);
}
.back-btn:hover {
border-color: rgba(96, 165, 250, 0.95);
background: radial-gradient(circle at 0 0, rgba(59, 130, 246, 0.35), transparent 70%);
}
.back-icon {
font-size: 14px;
color: var(--accent);
}
.chip {
border-radius: 999px;
border: 1px solid rgba(148, 163, 184, 0.5);

@ -1,4 +1,4 @@
import { onUnmounted } from 'vue'
import { onMounted, onUnmounted } from 'vue'
import * as echarts from 'echarts'
export const colors = {
@ -45,7 +45,12 @@ export function useChart(domId: string) {
chart?.resize()
}
onMounted(() => {
window.addEventListener('resize', resize)
})
onUnmounted(() => {
window.removeEventListener('resize', resize)
chart?.dispose()
})

Loading…
Cancel
Save