Compare commits

...

49 Commits
ck ... main

Author SHA1 Message Date
黄伟杰 13133c28be feat:添加打印模板页面-二维码样例 2 days ago
黄伟杰 2d20ec5344 feat:备件信息-二维码模板回显 2 days ago
黄伟杰 ae6ef128ee feat:模具管理-二维码模板回显 2 days ago
黄伟杰 4f6ee86798 feat:设备关键件-二维码模板回显 2 days ago
黄伟杰 5ff4d7e41a feat:设备台账-二维码模板回显 2 days ago
黄伟杰 288d10f3c7 feat:产品物料信息-二维码模板回显 2 days ago
黄伟杰 f3be54dd9f feat:添加打印模板管理模块 2 days ago
黄伟杰 ad79342616 style:甘特图-条块拖拽超出时间轴提示 3 days ago
黄伟杰 e472d4cb86 Merge branch 'main' of https://git.ngsk.tech/linweidong/besure_web 4 days ago
黄伟杰 4648bdca93 feat:报表管理-添加“展开/收起”按钮 4 days ago
liutao 1418015844 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	src/api/iot/deviceOperationOverview/index.ts
4 days ago
liutao a28acd5991 补充文件 4 days ago
黄伟杰 68c960317d feat:质量管理-添加“展开/收起”按钮 4 days ago
黄伟杰 88797b7760 style:产能报表-添加时间筛选入参 4 days ago
黄伟杰 0d7ae49a10 feat:模具管理-添加“展开/收起”按钮 4 days ago
黄伟杰 e6a3e05220 feat:备件模块-添加“展开/收起”按钮 4 days ago
黄伟杰 a12ed938c1 style:设备管理-添加“展开/折叠”按钮 4 days ago
黄伟杰 63d7ab3c8d style:产能报表-字段调整 4 days ago
黄伟杰 e99351440d feat:能耗类型-添加“展开/折叠”按钮 4 days ago
黄伟杰 1461cb2b25 feat:仓储管理-添加“展开/折叠”按钮 4 days ago
黄伟杰 985e92ee2b feat:产能报表-添加报工产能弹框 4 days ago
黄伟杰 aa3111131d feat:IOT模块添加展开/收起按钮 4 days ago
黄伟杰 a6d2265622 style:修改展开/收起按钮样式 4 days ago
黄伟杰 9f7a3c81b6 style:任务单排产-产能来源字段逻辑调整 4 days ago
黄伟杰 2a6b73e566 fix:修复runoverview api文件缺失问题 5 days ago
黄伟杰 1bdd5c276f style:产能报表-删除状态字段 5 days ago
黄伟杰 e68b934593 feat:生产管理模块-筛选条件添加“更多”按钮 6 days ago
黄伟杰 cb0ade38e0 Merge branch 'main' of https://git.ngsk.tech/linweidong/besure_web 6 days ago
黄伟杰 152a906c16 feat:添加产能报表页面 6 days ago
黄伟杰 e13fdef1f6 feat:工厂建模模块-筛选条件添加“更多”按钮 6 days ago
liutao 2295788977 Merge remote-tracking branch 'origin/main' 6 days ago
liutao d9b062419d 设备管理调整 6 days ago
liutao d0db5f5a90 设备管理调整 6 days ago
黄伟杰 80e2cda424 style:搜索菜单按钮,点击后自动获取焦点 6 days ago
黄伟杰 176a3dc607 Merge branch 'main' of https://git.ngsk.tech/linweidong/besure_web 6 days ago
黄伟杰 182e9e9712 feat:排产-甘特图添加双击弹框-调整任务 7 days ago
liutao 84101b7866 设备运行概览 7 days ago
liutao 2872f52d57 设备运行概览调整 7 days ago
黄伟杰 8c3f7a5aec feat:排产-甘特图添加锁定、撤回操作按钮 7 days ago
黄伟杰 fc6f348ad6 style:排产甘特图i18适配 7 days ago
黄伟杰 0ff6eaef69 style:甘特图-计划明细字段调整 7 days ago
liutao f88765448b Merge remote-tracking branch 'origin/main' 1 week ago
liutao bedd8d9bca 切换时真加点击事件 1 week ago
liutao 4abb93deab 样式优化 1 week ago
黄伟杰 21fdceb26f Merge branch 'main' of https://git.ngsk.tech/linweidong/besure_web 1 week ago
黄伟杰 d8a88b6fd7 feat:甘特图修改-多个计划展示在一行显示 1 week ago
黄伟杰 0dbdf57204 style:任务制单-查询条件样式优化 1 week ago
黄伟杰 da56f8d359 style:设备台账-移除每日报工平均值、数据采集产能 1 week ago
黄伟杰 85b759406d style:任务单排产-排产-产能来源改成从字典获取 1 week ago

@ -35,6 +35,7 @@ export interface MoldVO {
status: number // 状态
images: string // 模具图片
qrcodeUrl?: string
templateJson?: string | any
fileUrl?: string
remark: string // 备注
isEnable: boolean // 是否启用

@ -7,6 +7,7 @@ export interface ProductVO {
barCode: string // 产品条码
isCode?: boolean
qrcodeUrl?: string
templateJson?: string | any
categoryId: number // 产品类型编号
subCategoryId: number // 产品类型子类编号
subCategoryName: string // 产品类型子类名称

@ -0,0 +1,62 @@
import request from '@/config/axios'
export interface DeviceOperationOverviewParams {
ids?: string
startTime?: string
endTime?: string
timelinePageNo?: number
timelinePageSize?: number
}
export interface DeviceOperationOverviewMetricVO {
key: string
icon: string
value: number
unit: string
change: number
}
export interface DeviceOperationOverviewHourlyStatusVO {
hour: string
running: number
standby: number
fault: number
offline: number
}
export interface DeviceOperationOverviewSummaryVO {
status: 'running' | 'standby' | 'fault' | 'offline'
percent: number
hours: number
}
export interface DeviceOperationOverviewTimelineSegmentVO {
status: 'running' | 'standby' | 'fault' | 'offline'
startHour: number
endHour: number
}
export interface DeviceOperationOverviewTimelineRowVO {
id: string
name: string
utilizationRate: number
segments: DeviceOperationOverviewTimelineSegmentVO[]
}
export interface DeviceOperationOverviewRespVO {
metrics: DeviceOperationOverviewMetricVO[]
hourlyStatus: DeviceOperationOverviewHourlyStatusVO[]
summary: DeviceOperationOverviewSummaryVO[]
summaryTotalHours: number
timelineRows: DeviceOperationOverviewTimelineRowVO[]
totalDevices: number
}
export const DeviceOperationOverviewApi = {
getRunOverview: async (params: DeviceOperationOverviewParams) => {
return await request.get<DeviceOperationOverviewRespVO>({
url: `/iot/device-operation-record/runOverview`,
params
})
}
}

@ -9,6 +9,7 @@ export interface CriticalComponentVO {
count?: number
remark?: string
qrcodeUrl?: string
templateJson?: string | any
createTime?: string
images?: string
}

@ -0,0 +1,47 @@
import request from '@/config/axios'
export interface CapacityReportVO {
id: number
deviceCode: string
deviceName: string
typeName: string
deviceStatus: number
ratedCapacity: number
reportCapacity: number
actualCapacity: number
workshopName: string
}
export interface CapacityReportQuery {
pageNo: number
pageSize: number
deviceCode?: string
deviceName?: string
deviceType?: string
deviceStatus?: string
workshop?: string
ids?: string
}
export const DeviceLedgerApi = {
/**
*
*/
getCapacityReportPage: async (params: CapacityReportQuery) => {
return await request.get({ url: '/mes/device-ledger/capacity-report/page', params })
},
/**
*
*/
exportCapacityReport: async (params: { ids?: string }) => {
return await request.download({ url: '/mes/device-ledger/capacity-report/export-excel', params })
},
/**
*
*/
updateDeviceLedger: async (data: { id: number; deviceStatus: number }) => {
return await request.put({ url: '/mes/device-ledger/update', data })
}
}

@ -26,6 +26,7 @@ export interface DeviceLedgerVO {
remark: string // 备注
fileUrl?: string // 附件下载
qrcodeUrl?: string
templateJson?: string | any
isSchedueld?: number
isScheduled?: number
ratedCapacity?: number

@ -177,5 +177,9 @@ export const PlanApi = {
getPlanPageByTask: async (params: any) => {
return await request.get({ url: `/mes/plan/page-by-task`, params })
},
getProductCapacityPage: async (params: any) => {
return await request.get({ url: `/mes/plan/product-capacity-page`, params })
}
}

@ -0,0 +1,33 @@
import request from '@/config/axios'
export interface PrintTemplateVO {
id: number
templateCode: string
templateName: string
templateType: number
templateJson: string
remark: string
isEnable: boolean
createTime: string
}
export const PrintTemplateApi = {
getPrintTemplatePage: async (params: any) => {
return await request.get({ url: `/mes/print-template/page`, params })
},
getPrintTemplate: async (id: number) => {
return await request.get({ url: `/mes/print-template/get?id=` + id })
},
createPrintTemplate: async (data: PrintTemplateVO) => {
return await request.post({ url: `/mes/print-template/create`, data })
},
updatePrintTemplate: async (data: PrintTemplateVO) => {
return await request.put({ url: `/mes/print-template/update`, data })
},
deletePrintTemplate: async (id: number) => {
return await request.delete({ url: `/mes/print-template/delete?id=` + id })
},
exportPrintTemplate: async (params) => {
return await request.download({ url: `/mes/print-template/export-excel`, params })
},
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 B

@ -63,6 +63,9 @@ const props = withDefaults(
printPaperHeight?: number
printMaxWidth?: number
printMaxHeight?: number
templateJsonUrl?: string
templateJson?: any
printData?: Record<string, any>
}>(),
{
imageUrl: '',
@ -82,7 +85,10 @@ const props = withDefaults(
printPaperWidth: 80,
printPaperHeight: 80,
printMaxWidth: 180,
printMaxHeight: 120
printMaxHeight: 120,
templateJsonUrl: '',
templateJson: undefined,
printData: () => ({})
}
)
@ -202,26 +208,88 @@ const handlePreview = () => {
})
}
const replaceTemplateValues = (templateJson: any, printData: Record<string, any>) => {
if (!templateJson?.panels) return templateJson
return {
...templateJson,
panels: templateJson.panels.map((panel: any) => ({
...panel,
printElements: panel.printElements?.map((element: any) => {
if (!element?.options?.qid) return element
const qid = element.options.qid
const value = printData[qid]
if (value === undefined || value === null) return element
const newOptions = { ...element.options }
if (qid === 'qrcodeUrl') {
newOptions.src = value
newOptions.testData = value
} else {
newOptions.field = qid
if (newOptions.testData === undefined || newOptions.testData === '') {
newOptions.testData = String(value)
}
}
return {
...element,
options: newOptions
}
}) || []
}))
}
}
const handlePrint = async () => {
if (!props.imageUrl || !props.showPrint) return
let templateJson: any
let printData: Record<string, any>
printData = {
qrcodeUrl: props.imageUrl,
printId: props.printId === undefined || props.printId === null ? '' : String(props.printId),
...props.printData
}
if (props.templateJson) {
templateJson = replaceTemplateValues(props.templateJson, printData)
} else if (props.templateJsonUrl) {
try {
const response = await request.get({ url: props.templateJsonUrl })
templateJson = typeof response.data === 'string' ? JSON.parse(response.data) : response.data
templateJson = replaceTemplateValues(templateJson, printData)
} catch (error) {
console.error('获取打印模板失败', error)
message.error('获取打印模板失败')
return
}
} else {
const printSize = await resolvePrintSize(props.imageUrl)
const imageWidth = printSize.width
const imageHeight = printSize.height
const printId = props.printId === undefined || props.printId === null ? '' : String(props.printId)
const idAreaHeight = printId ? 14 : 0
const paperHeight = imageHeight + idAreaHeight
templateJson = buildQrcodeTemplateJson(props.imageUrl, printId, imageWidth, imageHeight, paperHeight)
}
const paperSize = templateJson?.panels?.[0] ? {
width: templateJson.panels[0].width,
height: templateJson.panels[0].height
} : { width: 80, height: 80 }
hiprintPreviewDialogRef.value?.open({
title: props.printTitle,
printData: {
qrcodeUrl: props.imageUrl,
printId
},
templateJson: buildQrcodeTemplateJson(props.imageUrl, printId, imageWidth, imageHeight, paperHeight),
printData,
templateJson,
withDefaultQrcodeLayout: false,
paperSize: {
width: imageWidth,
height: paperHeight
}
paperSize
})
}

@ -17,9 +17,10 @@
/>
</el-select>
</ElDialog>
<div v-else class="custom-hover" @click.stop="showTopSearch = !showTopSearch">
<div v-else class="custom-hover" @click.stop="toggleTopSearch">
<Icon icon="ep:search" />
<el-select
ref="topSelectRef"
@click.stop
filterable
:reserve-keyword="false"
@ -51,7 +52,8 @@ defineProps({
const router = useRouter() //
const showSearch = ref(false) //
const showTopSearch = ref(false) //
const value: Ref = ref('') //
const value: Ref = ref('')
const topSelectRef = ref<InstanceType<typeof ElSelect>>()
const routers = router.getRoutes() //
const options = computed(() => {
@ -86,6 +88,15 @@ function hiddenTopSearch() {
showTopSearch.value = false
}
function toggleTopSearch() {
showTopSearch.value = !showTopSearch.value
if (showTopSearch.value) {
setTimeout(() => {
topSelectRef.value?.focus()
}, 600)
}
}
onMounted(() => {
window.addEventListener('keydown', listenKey)
window.addEventListener('click', hiddenTopSearch)

@ -1335,10 +1335,57 @@ export default {
validatorDeviceCodeRequired: 'Code can not be empty',
gjTitle: 'Select key components',
bjTitle: 'Select spare parts',
normal: 'Normal',
stop: 'Stopped',
maintenance: 'Maintenance',
scrap: 'Scrap',
placeholderWorkshop: 'Please input workshop',
reportCapacity: 'Report Capacity',
actualCapacity: 'Actual Capacity',
Detail: {
invalidId: 'Invalid device ID'
}
},
// Capacity Report
CapacityReport: {
deviceCode: 'Device Code',
deviceName: 'Device Name',
deviceType: 'Device Type',
deviceStatus: 'Device Status',
workshop: 'Workshop',
ratedCapacity: 'Rated Capacity (Planned Capacity)',
reportCapacity: 'Report Capacity',
reportCapacityTooltip: 'Default query for average of data from the last half year (excluding today)',
reportCapacityViewDetail: 'View Detail',
actualCapacity: 'Actual Capacity',
actualCapacityTooltip: 'Default query for average of data from the last half year (excluding today)',
placeholderDeviceCode: 'Please input device code',
placeholderDeviceName: 'Please input device name',
placeholderDeviceType: 'Please input device type',
placeholderDeviceStatus: 'Please select device status',
placeholderWorkshop: 'Please input workshop',
baogongTime: 'Capacity Statistics Time',
placeholderBaogongTimeStart: 'Start Time',
placeholderBaogongTimeEnd: 'End Time',
shortcutLastWeek: 'Last Week',
shortcutLastHalfYear: 'Last Half Year',
shortcutLastYear: 'Last Year',
dialogTitlePrefix: 'Report Capacity Detail - ',
dialogProductCode: 'Product Code',
dialogProductCodePlaceholder: 'Please input product code',
dialogProductName: 'Product Name',
dialogProductNamePlaceholder: 'Please input product name',
dialogBaogongTime: 'Report Time',
dialogBaogongTimeStart: 'Report Start Time',
dialogBaogongTimeEnd: 'Report End Time',
dialogTaskCode: 'Task Code',
dialogTaskCodePlaceholder: 'Please input task code',
dialogBaogongTotal: 'Report Total',
dialogAvgCapacity: 'Avg Report Capacity',
dialogSearchButtonText: 'Search',
dialogResetButtonText: 'Reset',
exportFilename: 'Capacity Report.xls'
},
// Critical Component
EquipmentKeyItems: {
code: 'Code',
@ -1803,6 +1850,8 @@ export default {
addButtonText: 'Add',
exportButtonText: 'Export',
expandButtonText: 'Expand/Collapse',
collapseText: 'Collapse',
expandText: 'Expand',
tableCodeColumn: 'Organization Code',
tableNameColumn: 'Organization Name',
tableSortColumn: 'Display Order',
@ -2749,6 +2798,36 @@ export default {
updateFail: 'Update failed'
}
},
TemplateManagement: {
PrintTemplate: {
moduleName: 'Print Template',
templateCode: 'Template Code',
templateName: 'Template Name',
templateType: 'Template Type',
templateJson: 'Template JSON',
remark: 'Remark',
isEnable: 'Enabled',
enabled: 'Enabled',
disabled: 'Disabled',
createTime: 'Create Time',
operate: 'Operate',
exportFilename: 'PrintTemplate.xls',
typeLabel: 'Label',
typeBarcode: 'Barcode',
typeReport: 'Report',
placeholderTemplateCode: 'Please input template code',
templateCodeTooltip: 'Turn on the switch to auto-generate code, no manual input required',
placeholderTemplateName: 'Please input template name',
placeholderTemplateType: 'Please select template type',
placeholderTemplateJson: 'Please input template JSON content',
placeholderRemark: 'Please input remark',
validatorCodeRequired: 'Template code can not be empty',
validatorNameRequired: 'Template name can not be empty',
validatorTypeRequired: 'Template type can not be empty',
design: 'Design',
designTitle: 'Template Design'
}
},
QualityManagement: {
ZjType: {
moduleName: 'Inspection Type',
@ -4301,6 +4380,8 @@ export default {
searchButtonText: 'Search',
resetButtonText: 'Reset',
exportButtonText: 'Export',
collapseText: 'Collapse',
expandText: 'Expand',
tableLineCodeColumn: 'Line Code',
tableLineNameColumn: 'Line Name',
@ -4338,6 +4419,8 @@ export default {
searchButtonText: 'Search',
resetButtonText: 'Reset',
exportButtonText: 'Export',
collapseText: 'Collapse',
expandText: 'Expand',
tableLineCodeColumn: 'Line Code',
tableLineNameColumn: 'Line Name',
@ -4575,6 +4658,7 @@ export default {
planCountLabel: 'Plan Count',
planDetailTitle: 'Plan Details',
planCodeColon: 'Plan Code: ',
taskCodeColon: 'Task Code: ',
planNumberColon: 'Plan Qty: ',
deliveryDateColon: 'Delivery Date: ',
startColon: 'Start: ',
@ -4582,19 +4666,28 @@ export default {
latestStartColon: 'Latest Start: ',
emptyDescription: 'No Schedule Info',
adjustTaskTitle: 'Adjust Task',
taskLabel: 'Task',
taskPlaceholder: 'Please select task',
deviceLabel: 'Device',
devicePlaceholder: 'Please select device',
startDateLabel: 'Start Date',
startDatePlaceholder: 'Please select start date',
startDatePlaceholder: 'Please select plan start date',
endDateLabel: 'End Date',
endDatePlaceholder: 'Please select plan end date',
durationLabel: 'Days',
buttonCancel: 'Cancel',
buttonConfirm: 'Confirm',
editStartDateTitle: 'Edit Start Time',
startTimeLabel: 'Start Time',
startTimePlaceholder: 'Please select start time',
warningCompleteDeviceDate: 'Please complete device and start date',
capacityTypeLabel: 'Capacity Source',
warningCompleteDeviceDate: 'Please complete device, start date and end date',
warningValidTime: 'Please select a valid time',
warningEndBeforeStart: 'End time cannot be earlier than start time',
warningDragOutOfRange: 'Drag out of date range, reverted to original position',
columnTaskName: 'Task Name',
columnDeviceName: 'Device Name',
columnPlanInfo: 'Plan Info',
columnStartTime: 'Start Time',
columnDays: 'Days',
scaleMonthFormat: 'MMM YYYY',
@ -4616,7 +4709,18 @@ export default {
statusStarted: 'Started',
statusPaused: 'Paused',
statusPendingStorage: 'Pending Storage',
statusStored: 'Stored'
statusStored: 'Stored',
dialogTitle: 'Schedule Gantt Preview',
workerLabel: 'Worker',
workerPlaceholder: 'Please select worker',
calcLossLabel: 'Calculate Loss',
lockBtn: 'Lock',
unlockBtn: 'Unlock',
undoBtn: 'Undo',
buttonSave: 'Save',
buttonClose: 'Close',
warningNoPlanData: 'No plan data to save',
saveSuccess: 'Schedule saved successfully'
}
}
}

@ -1325,10 +1325,57 @@ export default {
validatorDeviceCodeRequired: '编码不能为空',
gjTitle: '选择关键件',
bjTitle: '选择备件',
normal: '正常',
stop: '停用',
maintenance: '维修',
scrap: '报废',
placeholderWorkshop: '请输入所属车间',
reportCapacity: '报工产能',
actualCapacity: '实际产能',
Detail: {
invalidId: '无效的设备ID'
}
},
// 产能报表
CapacityReport: {
deviceCode: '设备编码',
deviceName: '设备名称',
deviceType: '设备类型',
deviceStatus: '设备状态',
workshop: '所属车间',
ratedCapacity: '额定产能(计划产能)',
reportCapacity: '报工产能',
reportCapacityTooltip: '默认查询近半年的数据均值(不包含今日)',
reportCapacityViewDetail: '查看明细',
actualCapacity: '实际产能',
actualCapacityTooltip: '默认查询近半年的数据均值(不包含今日)',
placeholderDeviceCode: '请输入设备编码',
placeholderDeviceName: '请输入设备名称',
placeholderDeviceType: '请输入设备类型',
placeholderDeviceStatus: '请选择设备状态',
placeholderWorkshop: '请输入所属车间',
baogongTime: '产能统计时间',
placeholderBaogongTimeStart: '开始时间',
placeholderBaogongTimeEnd: '结束时间',
shortcutLastWeek: '近一周',
shortcutLastHalfYear: '近半年',
shortcutLastYear: '近一年',
dialogTitlePrefix: '报工产能明细 - ',
dialogProductCode: '产品编码',
dialogProductCodePlaceholder: '请输入产品编码',
dialogProductName: '产品名称',
dialogProductNamePlaceholder: '请输入产品名称',
dialogBaogongTime: '报工时间',
dialogBaogongTimeStart: '报工开始时间',
dialogBaogongTimeEnd: '报工结束时间',
dialogTaskCode: '任务编码',
dialogTaskCodePlaceholder: '请输入任务编码',
dialogBaogongTotal: '报工总数',
dialogAvgCapacity: '报工均值产能',
dialogSearchButtonText: '搜索',
dialogResetButtonText: '重置',
exportFilename: '产能报表.xls'
},
// 设备关键件
EquipmentKeyItems: {
count: '数量',
@ -2253,6 +2300,36 @@ export default {
updateFail: '更新失败'
}
},
TemplateManagement: {
PrintTemplate: {
moduleName: '打印模板',
templateCode: '模板编码',
templateName: '模板名称',
templateType: '模板类型',
templateJson: '模板JSON',
remark: '备注',
isEnable: '是否启用',
enabled: '启用',
disabled: '禁用',
createTime: '创建时间',
operate: '操作',
exportFilename: '打印模板.xls',
typeLabel: '标签',
typeBarcode: '条码',
typeReport: '报表',
placeholderTemplateCode: '请输入模板编码',
templateCodeTooltip: '开启开关则自动生成编码,无需手动输入',
placeholderTemplateName: '请输入模板名称',
placeholderTemplateType: '请选择模板类型',
placeholderTemplateJson: '请输入模板JSON内容',
placeholderRemark: '请输入备注',
validatorCodeRequired: '模板编码不能为空',
validatorNameRequired: '模板名称不能为空',
validatorTypeRequired: '模板类型不能为空',
design: '配置',
designTitle: '模板配置'
}
},
QualityManagement: {
ZjType: {
moduleName: '检验类型',
@ -2632,6 +2709,8 @@ export default {
addButtonText: '新增',
exportButtonText: '导出',
expandButtonText: '展开/折叠',
collapseText: '收起',
expandText: '展开',
tableCodeColumn: '组织编码',
tableNameColumn: '组织名称',
tableSortColumn: '显示顺序',
@ -4137,6 +4216,8 @@ export default {
searchButtonText: '搜索',
resetButtonText: '重置',
exportButtonText: '导出',
collapseText: '收起',
expandText: '展开',
tableLineCodeColumn: '产线编码',
tableLineNameColumn: '产线名称',
@ -4174,6 +4255,8 @@ export default {
searchButtonText: '搜索',
resetButtonText: '重置',
exportButtonText: '导出',
collapseText: '收起',
expandText: '展开',
tableLineCodeColumn: '产线编码',
tableLineNameColumn: '产线名称',
@ -4786,6 +4869,7 @@ export default {
planCountLabel: '计划条数',
planDetailTitle: '计划明细',
planCodeColon: '计划编码:',
taskCodeColon: '任务编码:',
planNumberColon: '计划数量:',
deliveryDateColon: '交货日期:',
startColon: '开始:',
@ -4793,19 +4877,28 @@ export default {
latestStartColon: '最晚开工:',
emptyDescription: '暂无计划信息',
adjustTaskTitle: '调整任务',
taskLabel: '任务',
taskPlaceholder: '请选择任务',
deviceLabel: '设备',
devicePlaceholder: '请选择设备',
startDateLabel: '开始日期',
startDatePlaceholder: '请选择开始日期',
startDatePlaceholder: '请选择计划开始日期',
endDateLabel: '结束日期',
endDatePlaceholder: '请选择计划结束日期',
durationLabel: '天数',
buttonCancel: '取消',
buttonConfirm: '确定',
editStartDateTitle: '修改开始时间',
startTimeLabel: '开始时间',
startTimePlaceholder: '请选择开始时间',
warningCompleteDeviceDate: '请完善设备和开始日期',
capacityTypeLabel: '产能来源',
warningCompleteDeviceDate: '请完善设备、计划开始日期和计划结束日期',
warningValidTime: '请选择有效的时间',
warningEndBeforeStart: '结束时间不能早于开始时间',
warningDragOutOfRange: '拖拽超出日期范围,已恢复原位',
columnTaskName: '任务名称',
columnDeviceName: '设备名称',
columnPlanInfo: '计划信息',
columnStartTime: '开始时间',
columnDays: '天数',
scaleMonthFormat: 'YYYY年M月',
@ -4827,7 +4920,18 @@ export default {
statusStarted: '已开工',
statusPaused: '暂停',
statusPendingStorage: '待入库',
statusStored: '已入库'
statusStored: '已入库',
dialogTitle: '排产甘特图预览',
workerLabel: '领料人',
workerPlaceholder: '请选择领料人',
calcLossLabel: '是否计算损耗',
lockBtn: '锁定',
unlockBtn: '解锁',
undoBtn: '撤回',
buttonSave: '保存',
buttonClose: '关闭',
warningNoPlanData: '暂无可保存的计划数据',
saveSuccess: '排产计划保存成功'
}
}
}

@ -1,83 +1,56 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
min-label-width="68px"
>
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" min-label-width="68px">
<el-form-item :label="t('FactoryModeling.AutocodeRule.searchRuleCodeLabel')" prop="ruleCode">
<el-input
v-model="queryParams.ruleCode"
:placeholder="t('FactoryModeling.AutocodeRule.searchRuleCodePlaceholder')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
<el-input v-model="queryParams.ruleCode"
:placeholder="t('FactoryModeling.AutocodeRule.searchRuleCodePlaceholder')" clearable
@keyup.enter="handleQuery" class="!w-240px" />
</el-form-item>
<el-form-item :label="t('FactoryModeling.AutocodeRule.searchRuleNameLabel')" prop="ruleName">
<el-input
v-model="queryParams.ruleName"
:placeholder="t('FactoryModeling.AutocodeRule.searchRuleNamePlaceholder')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
<el-input v-model="queryParams.ruleName"
:placeholder="t('FactoryModeling.AutocodeRule.searchRuleNamePlaceholder')" clearable
@keyup.enter="handleQuery" class="!w-240px" />
</el-form-item>
<el-form-item :label="t('FactoryModeling.AutocodeRule.searchRuleDescLabel')" prop="ruleDesc">
<el-input
v-model="queryParams.ruleDesc"
:placeholder="t('FactoryModeling.AutocodeRule.searchRuleDescPlaceholder')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
<el-input v-model="queryParams.ruleDesc"
:placeholder="t('FactoryModeling.AutocodeRule.searchRuleDescPlaceholder')" clearable
@keyup.enter="handleQuery" class="!w-240px" />
</el-form-item>
<el-form-item :label="t('FactoryModeling.AutocodeRule.searchRemarkLabel')" prop="remark">
<el-input
v-model="queryParams.remark"
:placeholder="t('FactoryModeling.AutocodeRule.searchRemarkPlaceholder')"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
<el-form-item :label="t('FactoryModeling.AutocodeRule.searchRemarkLabel')" prop="remark" v-show="showAllFilters">
<el-input v-model="queryParams.remark" :placeholder="t('FactoryModeling.AutocodeRule.searchRemarkPlaceholder')"
clearable @keyup.enter="handleQuery" class="!w-240px" />
</el-form-item>
<el-form-item :label="t('FactoryModeling.AutocodeRule.searchIsEnableLabel')" prop="isEnable">
<el-select
v-model="queryParams.isEnable"
:placeholder="t('FactoryModeling.AutocodeRule.searchIsEnablePlaceholder')"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
<el-form-item :label="t('FactoryModeling.AutocodeRule.searchIsEnableLabel')" prop="isEnable"
v-show="showAllFilters">
<el-select v-model="queryParams.isEnable"
:placeholder="t('FactoryModeling.AutocodeRule.searchIsEnablePlaceholder')" clearable class="!w-240px">
<el-option v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" :key="dict.value"
:label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') :
t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> {{ t('FactoryModeling.AutocodeRule.searchButtonText') }}</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> {{ t('FactoryModeling.AutocodeRule.resetButtonText') }}</el-button>
<el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['erp:autocode-rule:create']"
>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> {{ t('FactoryModeling.AutocodeRule.searchButtonText') }}
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> {{ t('FactoryModeling.AutocodeRule.resetButtonText') }}
</el-button>
<el-button type="primary" plain @click="openForm('create')" v-hasPermi="['erp:autocode-rule:create']">
<Icon icon="ep:plus" class="mr-5px" /> {{ t('FactoryModeling.AutocodeRule.addButtonText') }}
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['erp:autocode-rule:export']"
>
<el-button type="success" plain @click="handleExport" :loading="exportLoading"
v-hasPermi="['erp:autocode-rule:export']">
<Icon icon="ep:download" class="mr-5px" /> {{ t('FactoryModeling.AutocodeRule.exportButtonText') }}
</el-button>
</el-form-item>
@ -98,22 +71,27 @@
</template>
</el-table-column>
<!-- <el-table-column label="ID" align="center" prop="id" /> -->
<el-table-column :label="t('FactoryModeling.AutocodeRule.tableRuleCodeColumn')" align="center" prop="ruleCode" width="260px" sortable/>
<el-table-column :label="t('FactoryModeling.AutocodeRule.tableRuleNameColumn')" align="center" prop="ruleName" width="200px" sortable/>
<el-table-column :label="t('FactoryModeling.AutocodeRule.tableRuleCodeColumn')" align="center" prop="ruleCode"
width="260px" sortable />
<el-table-column :label="t('FactoryModeling.AutocodeRule.tableRuleNameColumn')" align="center" prop="ruleName"
width="200px" sortable />
<el-table-column :label="t('FactoryModeling.AutocodeRule.tableBarcodeTypeColumn')" align="center">
<template #default="scope">
<el-tag type="primary">{{ getBarcodeTypeLabel(scope.row.barcodeType) }}</el-tag>
</template>
</el-table-column>
<el-table-column :label="t('FactoryModeling.AutocodeRule.tableRuleDescColumn')" align="center" prop="ruleDesc" />
<el-table-column :label="t('FactoryModeling.AutocodeRule.tableMaxLengthColumn')" align="center" prop="maxLength" />
<el-table-column :label="t('FactoryModeling.AutocodeRule.tableMaxLengthColumn')" align="center"
prop="maxLength" />
<el-table-column :label="t('FactoryModeling.AutocodeRule.tableIsPaddedColumn')" align="center" prop="isPadded">
<template #default="scope">
<dict-tag :type="DICT_TYPE.ERP_AUTOCODE_IS_PADDING" :value="scope.row.isPadded" />
</template>
</el-table-column>
<el-table-column :label="t('FactoryModeling.AutocodeRule.tablePaddedCharColumn')" align="center" prop="paddedChar" />
<el-table-column :label="t('FactoryModeling.AutocodeRule.tablePaddedMethodColumn')" align="center" prop="paddedMethod">
<el-table-column :label="t('FactoryModeling.AutocodeRule.tablePaddedCharColumn')" align="center"
prop="paddedChar" />
<el-table-column :label="t('FactoryModeling.AutocodeRule.tablePaddedMethodColumn')" align="center"
prop="paddedMethod">
<template #default="scope">
<dict-tag :type="DICT_TYPE.ERP_AUTOCODE_PADDING_TYPE" :value="scope.row.paddedMethod" />
</template>
@ -125,42 +103,26 @@
</template>
</el-table-column>
<el-table-column :label="t('FactoryModeling.AutocodeRule.tableOperateColumn')" align="center" fixed="right" width="200">
<el-table-column :label="t('FactoryModeling.AutocodeRule.tableOperateColumn')" align="center" fixed="right"
width="200">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['erp:autocode-rule:update']"
>
<el-button link type="primary" @click="openForm('update', scope.row.id)"
v-hasPermi="['erp:autocode-rule:update']">
{{ t('FactoryModeling.AutocodeRule.tableEditAction') }}
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['erp:autocode-rule:delete']"
>
<el-button link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['erp:autocode-rule:delete']">
{{ t('FactoryModeling.AutocodeRule.tableDeleteAction') }}
</el-button>
<el-button
link
type="primary"
@click="handleTestCode(scope.row.ruleCode)"
v-hasPermi="['erp:autocode-rule:update']"
>
<el-button link type="primary" @click="handleTestCode(scope.row.ruleCode)"
v-hasPermi="['erp:autocode-rule:update']">
{{ t('FactoryModeling.AutocodeRule.tableTestCodeAction') }}
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
@pagination="getList" />
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
@ -200,6 +162,13 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const showAllFilters = ref(false) //
const filterCount = 5 // ruleCoderuleNameruleDescremarkisEnable
/** 切换筛选框展开/折叠 */
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const getBarcodeTypeLabel = (value: any) => {
const str = value === undefined || value === null ? '' : String(value)

@ -52,7 +52,7 @@
/>
</el-select>
</el-form-item>
<el-form-item :label="t('SparePartsManagement.SpareIn.warehouse')" prop="warehouseId">
<el-form-item :label="t('SparePartsManagement.SpareIn.warehouse')" prop="warehouseId" v-show="showAllFilters">
<el-select
v-model="queryParams.warehouseId"
clearable
@ -68,7 +68,7 @@
/>
</el-select>
</el-form-item>
<el-form-item :label="t('SparePartsManagement.SpareIn.remark')" prop="remark">
<el-form-item :label="t('SparePartsManagement.SpareIn.remark')" prop="remark" v-show="showAllFilters">
<el-input
v-model="queryParams.remark"
:placeholder="t('SparePartsManagement.SpareIn.placeholderRemark')"
@ -77,6 +77,12 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<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>
@ -253,6 +259,11 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const showAllFilters = ref(false)
const filterCount = 5
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const productList = ref<ProductVO[]>([]) //
const warehouseList = ref<WarehouseVO[]>([]) //
const supplierList = ref<SupplierVO[]>([]) //

@ -45,7 +45,7 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item :label="t('SparePartsManagement.SpareOut.warehouse')" prop="warehouseId">
<el-form-item :label="t('SparePartsManagement.SpareOut.warehouse')" prop="warehouseId" v-show="showAllFilters">
<el-select
v-model="queryParams.warehouseId"
clearable
@ -61,7 +61,7 @@
/>
</el-select>
</el-form-item>
<el-form-item :label="t('SparePartsManagement.SpareOut.remark')" prop="remark">
<el-form-item :label="t('SparePartsManagement.SpareOut.remark')" prop="remark" v-show="showAllFilters">
<el-input
v-model="queryParams.remark"
:placeholder="t('SparePartsManagement.SpareOut.placeholderRemark')"
@ -70,6 +70,12 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<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>
@ -248,6 +254,11 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const showAllFilters = ref(false)
const filterCount = 5
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const productList = ref<ProductVO[]>([]) //
const warehouseList = ref<WarehouseVO[]>([]) //

@ -118,6 +118,8 @@
:refresh-url="getQrcodeRefreshUrl()"
:refresh-disabled="!formData.id || !formData.barCode"
refresh-confirm-text="确认刷新该备件二维码吗?"
:template-json="formData.templateJson"
:print-data="buildPrintData()"
@refresh-success="handleQrcodeRefreshSuccess"
/>
</el-form-item>
@ -158,6 +160,7 @@ const formData = ref({
barCode: undefined,
isCode: undefined,
qrcodeUrl: undefined,
templateJson: undefined,
categoryId: undefined,
unitId: undefined,
status: undefined,
@ -201,7 +204,15 @@ const open = async (type: string, id?: number) => {
if (id) {
formLoading.value = true
try {
formData.value = await ProductApi.getProduct(id)
const productData = await ProductApi.getProduct(id)
const templateJson = productData?.templateJson
const parsedTemplateJson = typeof templateJson === 'string'
? JSON.parse(templateJson)
: templateJson
formData.value = {
...productData,
templateJson: parsedTemplateJson
}
} finally {
formLoading.value = false
}
@ -223,6 +234,20 @@ const getQrcodeRefreshUrl = () => {
return `/erp/product/regenerate-code?id=${formData.value.id}&code=${encodeURIComponent(String(formData.value.barCode))}`
}
const buildPrintData = () => {
return {
id: formData.value.id,
barCode: formData.value.barCode,
name: formData.value.name,
standard: formData.value.standard,
unitId: formData.value.unitId,
safetyNumber: formData.value.safetyNumber,
status: formData.value.status,
remark: formData.value.remark,
qrcodeUrl: formData.value.qrcodeUrl
}
}
const handleQrcodeRefreshSuccess = async (data: any) => {
if (!formData.value.id) return
if (data?.qrcodeUrl) {
@ -267,6 +292,7 @@ const resetForm = () => {
barCode: undefined,
isCode: true,
qrcodeUrl: undefined,
templateJson: undefined,
categoryId: undefined,
unitId: undefined,
status: CommonStatusEnum.ENABLE,

@ -52,7 +52,7 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item :label="t('SparePartsManagement.SpareRecord.createTime')" prop="createTime">
<el-form-item :label="t('SparePartsManagement.SpareRecord.createTime')" prop="createTime" v-show="showAllFilters">
<el-date-picker
v-model="queryParams.createTime"
value-format="YYYY-MM-DD HH:mm:ss"
@ -63,6 +63,12 @@
class="!w-220px"
/>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<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>
@ -173,6 +179,11 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const showAllFilters = ref(false)
const filterCount = 4
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const productList = ref<ProductVO[]>([]) //
const warehouseList = ref<WarehouseVO[]>([]) //

@ -43,6 +43,12 @@
/>
</el-select>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<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>
@ -118,6 +124,11 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const showAllFilters = ref(false)
const filterCount = 2
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const productList = ref<ProductVO[]>([]) //
const warehouseList = ref<WarehouseVO[]>([]) //

@ -97,6 +97,8 @@
:refresh-url="getQrcodeRefreshUrl()"
:refresh-disabled="!formData.id || !formData.code"
refresh-confirm-text="确认刷新该模具二维码吗?"
:template-json="formData.templateJson"
:print-data="buildPrintData()"
@refresh-success="handleQrcodeRefreshSuccess"
/>
</el-form-item>
@ -159,6 +161,7 @@ const formData = ref({
status: undefined,
images: undefined,
qrcodeUrl: undefined,
templateJson: undefined,
remark: undefined,
isEnable: undefined,
fileUrl: '',
@ -208,7 +211,15 @@ const open = async (type: string, id?: number, brandId: number) => {
if (id) {
formLoading.value = true
try {
formData.value = await MoldBrandApi.getMold(id)
const moldData = await MoldBrandApi.getMold(id)
const templateJson = moldData?.templateJson
const parsedTemplateJson = typeof templateJson === 'string'
? JSON.parse(templateJson)
: templateJson
formData.value = {
...moldData,
templateJson: parsedTemplateJson
}
} finally {
formLoading.value = false
}
@ -231,6 +242,21 @@ const getQrcodeRefreshUrl = () => {
return `/erp/mold-brand/regenerate-code?id=${formData.value.id}&code=${encodeURIComponent(String(formData.value.code))}`
}
const buildPrintData = () => {
return {
id: formData.value.id,
code: formData.value.code,
name: formData.value.name,
unitId: formData.value.unitId,
machineId: formData.value.machineId,
useTime: formData.value.useTime,
inTime: formData.value.inTime,
status: formData.value.status,
remark: formData.value.remark,
qrcodeUrl: formData.value.qrcodeUrl
}
}
const handleQrcodeRefreshSuccess = async (data: any) => {
if (!formData.value.id) return
if (data?.qrcodeUrl) {
@ -280,6 +306,7 @@ const resetForm = () => {
status: 3,
images: undefined,
qrcodeUrl: undefined,
templateJson: undefined,
remark: undefined,
isEnable: true,
fileUrl: '',

@ -163,6 +163,8 @@
:refresh-url="getQrcodeRefreshUrl()"
:refresh-disabled="!formData.id || !formData.barCode"
refresh-confirm-text="确认刷新该产品二维码吗?"
:template-json="formData.templateJson"
:print-data="buildPrintData()"
@refresh-success="handleQrcodeRefreshSuccess"
/>
</el-form-item>
@ -296,6 +298,7 @@ const formData = ref({
barCode: undefined,
isCode: undefined,
qrcodeUrl: undefined,
templateJson: undefined,
categoryId: undefined,
unitId: undefined,
status: undefined,
@ -511,9 +514,14 @@ const open = async (type: string, id?: number) => {
['name', 'code'],
'模具'
)
const templateJson = productData?.templateJson
const parsedTemplateJson = typeof templateJson === 'string'
? JSON.parse(templateJson)
: templateJson
formData.value = {
...formData.value,
...productData,
templateJson: parsedTemplateJson,
devices,
molds
}
@ -538,6 +546,17 @@ const getQrcodeRefreshUrl = () => {
return `/erp/product/regenerate-code?id=${formData.value.id}&code=${encodeURIComponent(String(formData.value.barCode))}`
}
const buildPrintData = () => {
return {
id: formData.value.id,
name: formData.value.name,
barCode: formData.value.barCode,
standard: formData.value.standard,
remark: formData.value.remark,
qrcodeUrl: formData.value.qrcodeUrl
}
}
const handleQrcodeRefreshSuccess = async (data: any) => {
if (!formData.value.id) return
if (data?.qrcodeUrl) {

@ -60,7 +60,7 @@
/>
</el-select>
</el-form-item> -->
<el-form-item :label="t('ErpStock.In.warehouse')" prop="warehouseId">
<el-form-item :label="t('ErpStock.In.warehouse')" prop="warehouseId" v-show="showAllFilters">
<el-select
v-model="queryParams.warehouseId"
clearable
@ -76,7 +76,7 @@
/>
</el-select>
</el-form-item>
<el-form-item :label="t('ErpStock.In.creator')" prop="creator">
<el-form-item :label="t('ErpStock.In.creator')" prop="creator" v-show="showAllFilters">
<el-select
v-model="queryParams.creator"
clearable
@ -92,7 +92,7 @@
/>
</el-select>
</el-form-item>
<el-form-item :label="t('ErpStock.In.status')" prop="status">
<el-form-item :label="t('ErpStock.In.status')" prop="status" v-show="showAllFilters">
<el-select
v-model="queryParams.status"
:placeholder="t('ErpStock.In.placeholderStatus')"
@ -107,7 +107,7 @@
/>
</el-select>
</el-form-item>
<el-form-item :label="t('ErpStock.In.remark')" prop="remark">
<el-form-item :label="t('ErpStock.In.remark')" prop="remark" v-show="showAllFilters">
<el-input
v-model="queryParams.remark"
:placeholder="t('ErpStock.In.placeholderRemark')"
@ -116,6 +116,13 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') :
t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<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>
@ -308,6 +315,11 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const showAllFilters = ref(false)
const filterCount = 7
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const productList = ref<ProductVO[]>([]) //
const warehouseList = ref<WarehouseVO[]>([]) //
const supplierList = ref<SupplierVO[]>([]) //

@ -60,7 +60,7 @@
/>
</el-select>
</el-form-item> -->
<el-form-item :label="t('ErpStock.Out.warehouse')" prop="warehouseId">
<el-form-item :label="t('ErpStock.Out.warehouse')" prop="warehouseId" v-show="showAllFilters">
<el-select
v-model="queryParams.warehouseId"
clearable
@ -76,7 +76,7 @@
/>
</el-select>
</el-form-item>
<el-form-item :label="t('ErpStock.In.creator')" prop="creator">
<el-form-item :label="t('ErpStock.In.creator')" prop="creator" v-show="showAllFilters">
<el-select
v-model="queryParams.creator"
clearable
@ -92,7 +92,7 @@
/>
</el-select>
</el-form-item>
<el-form-item :label="t('ErpStock.In.status')" prop="status">
<el-form-item :label="t('ErpStock.In.status')" prop="status" v-show="showAllFilters">
<el-select
v-model="queryParams.status"
:placeholder="t('ErpStock.In.placeholderStatus')"
@ -107,7 +107,7 @@
/>
</el-select>
</el-form-item>
<el-form-item :label="t('ErpStock.Out.remark')" prop="remark">
<el-form-item :label="t('ErpStock.Out.remark')" prop="remark" v-show="showAllFilters">
<el-input
v-model="queryParams.remark"
:placeholder="t('ErpStock.Out.placeholderRemark')"
@ -116,6 +116,13 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') :
t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<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>
@ -317,6 +324,11 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const showAllFilters = ref(false)
const filterCount = 7
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const productList = ref<ProductVO[]>([]) //
const warehouseList = ref<WarehouseVO[]>([]) //
const customerList = ref<CustomerVO[]>([]) //

@ -57,7 +57,7 @@
/>
</el-select>
</el-form-item>
<el-form-item :label="t('ErpStock.Record.bizNo')" prop="bizNo">
<el-form-item :label="t('ErpStock.Record.bizNo')" prop="bizNo" v-show="showAllFilters">
<el-input
v-model="queryParams.bizNo"
:placeholder="t('ErpStock.Record.placeholderBizNo')"
@ -66,7 +66,7 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item :label="t('common.createTime')" prop="createTime">
<el-form-item :label="t('common.createTime')" prop="createTime" v-show="showAllFilters">
<el-date-picker
v-model="queryParams.createTime"
value-format="YYYY-MM-DD HH:mm:ss"
@ -77,6 +77,13 @@
class="!w-220px"
/>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') :
t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<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>
@ -200,6 +207,11 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const showAllFilters = ref(false)
const filterCount = 5
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const productList = ref<ProductVO[]>([]) //
const warehouseList = ref<WarehouseVO[]>([]) //
const categoryTabs = ref<ProductCategoryVO[]>([])

@ -33,6 +33,13 @@
/>
</el-select>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') :
t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<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>
@ -245,6 +252,11 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const showAllFilters = ref(false)
const filterCount = 2
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const detailDialogVisible = ref(false) //
const detailData = ref<WarehouseVO | null>(null) //
const activeTab = ref('area') // tab

@ -40,7 +40,7 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item :label="t('ErpStock.WarehouseArea.status')" prop="status">
<el-form-item :label="t('ErpStock.WarehouseArea.status')" prop="status" v-show="showAllFilters">
<el-select
v-model="queryParams.status"
:placeholder="t('ErpStock.WarehouseArea.placeholderStatus')"
@ -55,6 +55,13 @@
/>
</el-select>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') :
t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<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>
@ -149,6 +156,11 @@ const queryParams = reactive({
status: undefined
})
const queryFormRef = ref()
const showAllFilters = ref(false)
const filterCount = 4
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const warehouseList = ref<any[]>([])
const getWarehouseName = (warehouseId: number) => {

@ -47,7 +47,7 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item :label="t('ErpStock.WarehouseLocation.name')" prop="name">
<el-form-item :label="t('ErpStock.WarehouseLocation.name')" prop="name" v-show="showAllFilters">
<el-input
v-model="queryParams.name"
:placeholder="t('ErpStock.WarehouseLocation.placeholderName')"
@ -56,7 +56,7 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item :label="t('ErpStock.WarehouseLocation.status')" prop="status">
<el-form-item :label="t('ErpStock.WarehouseLocation.status')" prop="status" v-show="showAllFilters">
<el-select
v-model="queryParams.status"
:placeholder="t('ErpStock.WarehouseLocation.placeholderStatus')"
@ -71,6 +71,13 @@
/>
</el-select>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') :
t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<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>
@ -191,6 +198,11 @@ const queryParams = reactive({
status: undefined
})
const queryFormRef = ref()
const showAllFilters = ref(false)
const filterCount = 5
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const warehouseList = ref<any[]>([])
const areaList = ref<any[]>([])

@ -11,7 +11,7 @@
</el-button>
</div>
</div>
<el-tabs v-model="deviceTabActive">
<el-tabs v-model="deviceTabActive" :onclick="changeClick">
<el-tab-pane :label="deviceAttributeTabLabel" name="deviceAttribute">
<DeviceAttributeList :device-id="attributeDeviceId" />
</el-tab-pane>
@ -599,6 +599,9 @@ const resetDeviceAlarmQuery = () => {
deviceAlarmQueryParams.pageNo = 1
getDeviceAlarmList()
}
const changeClick = () => {
deviceTabActive.value==='deviceRule' ? getRuleList() : getDeviceAlarmList()
}
const openCreateRuleForm = () => {
if (!attributeDeviceId.value) {

@ -34,7 +34,7 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item :label="t('DataCollection.HistoryData.searchLineNameLabel')" prop="lineName">
<el-form-item :label="t('DataCollection.HistoryData.searchLineNameLabel')" prop="lineName" v-show="showAllFilters">
<el-input
v-model="queryParams.lineName"
:placeholder="t('DataCollection.HistoryData.searchLineNamePlaceholder')"
@ -43,6 +43,12 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('DataCollection.HistoryData.collapseText') : t('DataCollection.HistoryData.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" />
@ -151,6 +157,11 @@ const loading = ref(true)
const list = ref<LineDeviceVO[]>([])
const total = ref(0)
const exportLoading = ref(false)
const showAllFilters = ref(false)
const filterCount = 4
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const queryParams = reactive({
pageNo: 1,
pageSize: 10,

@ -34,7 +34,7 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item :label="t('DataCollection.RealTimeMonitoring.searchLineNameLabel')" prop="lineName">
<el-form-item :label="t('DataCollection.RealTimeMonitoring.searchLineNameLabel')" prop="lineName" v-show="showAllFilters">
<el-input
v-model="queryParams.lineName"
:placeholder="t('DataCollection.RealTimeMonitoring.searchLineNamePlaceholder')"
@ -43,6 +43,12 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('DataCollection.RealTimeMonitoring.collapseText') : t('DataCollection.RealTimeMonitoring.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" />
@ -156,6 +162,11 @@ const loading = ref(true)
const list = ref<LineDeviceVO[]>([])
const total = ref(0)
const exportLoading = ref(false)
const showAllFilters = ref(false)
const filterCount = 4
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const queryParams = reactive({
pageNo: 1,
pageSize: 10,

@ -38,7 +38,7 @@
</div>
</div>
<div v-for="row in pagedRows" :key="row.id" class="timeline-table__row">
<div v-for="row in timelineRows" :key="row.id" class="timeline-table__row">
<div class="timeline-table__meta">
<div class="timeline-table__device">{{ row.name }}</div>
<div class="timeline-table__rate">{{ row.utilizationRate.toFixed(2) }}%</div>
@ -116,12 +116,20 @@ const legendItems = computed(() => [
{ status: 'offline' as const, color: statusColors.offline, label: t('DataCollection.RunOverview.legend.offline') }
])
const hourTicks = Array.from({ length: 13 }, (_, index) => `${String(index * 2).padStart(2, '0')}:00`)
const pagedRows = computed(() => {
const start = (props.pageNo - 1) * props.pageSize
return props.rows.slice(start, start + props.pageSize)
})
const hourTicks = Array.from({ length: 24 }, (_, index) => `${String(index).padStart(2, '0')}:00`)
const timelineRows = computed(() =>
props.rows.map((row) => ({
...row,
segments: (row.segments || []).filter(
(segment) =>
!!statusColors[segment.status] &&
Number.isFinite(segment.startHour) &&
Number.isFinite(segment.endHour) &&
segment.endHour > segment.startHour
)
}))
)
</script>
<style scoped lang="scss">
@ -239,7 +247,6 @@ const pagedRows = computed(() => {
.timeline-track {
height: 20px;
background: #f5f7fb;
border-radius: 999px;
overflow: hidden;
}

@ -2,22 +2,28 @@
<ContentWrap class="run-overview-filter">
<el-form :model="modelValue" inline label-width="auto">
<el-form-item :label="t('DataCollection.RunOverview.groupLabel')">
<el-select
<el-tree-select
:model-value="modelValue.groupId"
:placeholder="t('DataCollection.RunOverview.groupPlaceholder')"
:data="groupOptions"
:props="treeProps"
check-strictly
clearable
default-expand-all
class="!w-220px"
@update:model-value="updateField('groupId', $event)"
>
<el-option v-for="item in groupOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
:placeholder="t('DataCollection.RunOverview.groupPlaceholder')"
@update:model-value="handleGroupChange"
/>
</el-form-item>
<el-form-item :label="t('DataCollection.RunOverview.deviceLabel')">
<el-select
:model-value="modelValue.deviceId"
multiple
collapse-tags
collapse-tags-tooltip
clearable
:placeholder="t('DataCollection.RunOverview.devicePlaceholder')"
class="!w-240px"
@update:model-value="updateField('deviceId', $event || '')"
@update:model-value="updateField('deviceId', $event || [])"
>
<el-option v-for="item in deviceOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
@ -52,21 +58,26 @@
<Icon icon="ep:refresh" class="mr-5px" />
{{ t('DataCollection.RunOverview.resetButtonText') }}
</el-button>
<el-button type="success" plain @click="emit('export')">
<!-- <el-button type="success" plain @click="emit('export')">
<Icon icon="ep:download" class="mr-5px" />
{{ t('DataCollection.RunOverview.exportButtonText') }}
</el-button>
</el-button>-->
</el-form-item>
</el-form>
</ContentWrap>
</template>
<script setup lang="ts">
import type { OverviewOption, QuickRangeKey, RunOverviewQueryParams } from './types'
import type {
OrganizationTreeOption,
OverviewOption,
QuickRangeKey,
RunOverviewQueryParams
} from './types'
const props = defineProps<{
modelValue: RunOverviewQueryParams
groupOptions: OverviewOption[]
groupOptions: OrganizationTreeOption[]
deviceOptions: OverviewOption[]
quickRanges: Array<{ label: string; value: QuickRangeKey }>
}>()
@ -80,6 +91,11 @@ const emit = defineEmits<{
}>()
const { t } = useI18n()
const treeProps = {
value: 'id',
label: 'name',
children: 'children'
}
const updateField = <K extends keyof RunOverviewQueryParams>(key: K, value: RunOverviewQueryParams[K]) => {
emit('update:modelValue', {
@ -87,6 +103,15 @@ const updateField = <K extends keyof RunOverviewQueryParams>(key: K, value: RunO
[key]: value
})
}
const handleGroupChange = (value: string | number | undefined) => {
const nextGroupId = value == null ? '' : String(value)
emit('update:modelValue', {
...props.modelValue,
groupId: nextGroupId,
deviceId: props.modelValue.deviceId
})
}
</script>
<style scoped lang="scss">

@ -23,7 +23,11 @@
</div>
<div class="chart-panel__side">
<div class="chart-panel__side-title">{{ t('DataCollection.RunOverview.summaryTitle') }}</div>
<Echart :options="pieOption" height="320px" />
<div class="chart-panel__summary-layout">
<!-- <div class="chart-panel__pie">
<Echart :options="pieOption" height="280px" />
</div>&ndash;&gt;-->
<Echart :options="pieOption" height="280px" />
<div class="chart-panel__legend">
<div v-for="item in summary" :key="item.status" class="chart-panel__legend-item">
<span class="dot" :style="{ background: statusColors[item.status] }"></span>
@ -33,6 +37,7 @@
</div>
</div>
</div>
</div>
</ContentWrap>
</template>
@ -47,6 +52,7 @@ const Echart = EchartChart
const props = defineProps<{
hourlyStatus: HourlyStatusItem[]
summary: StatusSummaryItem[]
summaryTotalHours?: number
}>()
const { t } = useI18n()
@ -136,7 +142,7 @@ const pieOption = computed<EChartsOption>(() => ({
left: 'center',
top: '42%',
style: {
text: `${t('DataCollection.RunOverview.totalTimeLabel')}\n24.00 h`,
text: `${t('DataCollection.RunOverview.totalTimeLabel')}\n${(props.summaryTotalHours ?? 0).toFixed(2)} h`,
textAlign: 'center',
fill: '#101828',
fontSize: 14,
@ -198,20 +204,34 @@ const pieOption = computed<EChartsOption>(() => ({
}
.chart-panel__side {
padding: 8px 8px 0;
padding: 8px 12px 0;
}
.chart-panel__summary-layout {
display: grid;
grid-template-columns: minmax(180px, 220px) minmax(180px, 1fr);
align-items: center;
gap: 8px 16px;
min-height: 280px;
}
.chart-panel__pie {
display: flex;
align-items: center;
justify-content: center;
}
.chart-panel__legend {
display: flex;
flex-direction: column;
gap: 10px;
margin-top: -8px;
gap: 14px;
justify-content: center;
}
.chart-panel__legend-item {
display: grid;
grid-template-columns: 12px 1fr auto;
gap: 8px;
grid-template-columns: 12px 52px 1fr;
gap: 10px;
align-items: center;
color: #344054;
font-size: 13px;
@ -230,11 +250,22 @@ const pieOption = computed<EChartsOption>(() => ({
.value {
color: #101828;
font-weight: 600;
text-align: left;
}
@media (max-width: 1100px) {
.chart-panel__body {
grid-template-columns: 1fr;
}
.chart-panel__summary-layout {
grid-template-columns: 1fr;
justify-items: center;
}
.chart-panel__legend {
width: 100%;
max-width: 320px;
}
}
</style>

@ -1,15 +1,31 @@
export type RunStatus = 'running' | 'standby' | 'fault' | 'offline'
export type QuickRangeKey = 'today' | 'yesterday' | 'last7Days' | 'last30Days' | 'custom'
export type QuickRangeKey = 'today' | 'yesterday' | 'last7Days' | 'last30Days'
export interface OverviewOption {
label: string
value: string
}
export interface OrganizationFilterItem {
id: number | string
name: string
parentId?: number | string | null
dvId?: number | string | null
machineName?: string
}
export interface OrganizationTreeOption {
id: number | string
name: string
parentId?: number | string | null
dvId?: number | string | null
children?: OrganizationTreeOption[]
}
export interface RunOverviewQueryParams {
groupId: string
deviceId: string
deviceId: string[]
quickRange: QuickRangeKey
timeRange: [string, string]
}
@ -53,6 +69,7 @@ export interface RunOverviewData {
metrics: RunOverviewMetric[]
hourlyStatus: HourlyStatusItem[]
summary: StatusSummaryItem[]
summaryTotalHours: number
timelineRows: DeviceTimelineRow[]
totalDevices: number
}

@ -22,12 +22,15 @@
@quick-range-change="handleQuickRangeChange"
@query="handleQuery"
@reset="resetQuery"
@export="handleExport"
/>
<OverviewMetricCards :metrics="overviewData.metrics" />
<StatusDistributionChart :hourly-status="overviewData.hourlyStatus" :summary="overviewData.summary" />
<StatusDistributionChart
:hourly-status="overviewData.hourlyStatus"
:summary="overviewData.summary"
:summary-total-hours="overviewData.summaryTotalHours"
/>
<OperationTimelineChart
:rows="overviewData.timelineRows"
@ -45,12 +48,22 @@
<script setup lang="ts">
import dayjs from 'dayjs'
import { useFullscreen } from '@vueuse/core'
import { DeviceOperationOverviewApi } from '@/api/iot/deviceOperationOverview'
import { OrganizationApi } from '@/api/mes/organization'
import { handleTree } from '@/utils/tree'
import OverviewFilterBar from './components/OverviewFilterBar.vue'
import OverviewMetricCards from './components/OverviewMetricCards.vue'
import OperationTimelineChart from './components/OperationTimelineChart.vue'
import StatusDistributionChart from './components/StatusDistributionChart.vue'
import { buildDefaultQueryParams, buildRunOverviewData, DEVICE_OPTIONS, GROUP_OPTIONS } from './mock'
import type { QuickRangeKey, RunOverviewData, RunOverviewQueryParams } from './components/types'
import { buildDefaultQueryParams } from './mock'
import type {
OrganizationFilterItem,
OrganizationTreeOption,
OverviewOption,
QuickRangeKey,
RunOverviewData,
RunOverviewQueryParams
} from './components/types'
defineOptions({ name: 'IotRunOverview' })
@ -58,9 +71,8 @@ const { t } = useI18n()
const message = useMessage()
const fullscreenTargetRef = ref()
const { isFullscreen, toggle: toggleFullscreen } = useFullscreen(fullscreenTargetRef)
const groupOptions = GROUP_OPTIONS
const deviceOptions = DEVICE_OPTIONS
const organizationList = ref<OrganizationFilterItem[]>([])
const groupOptions = ref<OrganizationTreeOption[]>([])
const createDateRangeByQuickKey = (key: QuickRangeKey): [string, string] => {
const format = 'YYYY-MM-DD HH:mm:ss'
@ -83,40 +95,119 @@ const quickRanges = computed(() => [
{ label: t('DataCollection.RunOverview.quickRange.yesterday'), value: 'yesterday' as const },
{ label: t('DataCollection.RunOverview.quickRange.last7Days'), value: 'last7Days' as const },
{ label: t('DataCollection.RunOverview.quickRange.last30Days'), value: 'last30Days' as const },
{ label: t('DataCollection.RunOverview.quickRange.custom'), value: 'custom' as const }
/* { label: t('DataCollection.RunOverview.quickRange.custom'), value: 'custom' as const }*/
])
const queryParams = ref<RunOverviewQueryParams>(buildDefaultQueryParams())
const overviewData = ref<RunOverviewData>(buildRunOverviewData(queryParams.value))
const pageNo = ref(1)
const pageSize = ref(10)
const refreshData = () => {
overviewData.value = buildRunOverviewData(queryParams.value)
const organizationMap = computed(() => {
return organizationList.value.reduce<Record<string, OrganizationFilterItem>>((acc, item) => {
acc[String(item.id)] = item
return acc
}, {})
})
const childrenByParentId = computed(() => {
return organizationList.value.reduce<Record<string, OrganizationFilterItem[]>>((acc, item) => {
const parentKey = String(item.parentId ?? 0)
if (!acc[parentKey]) acc[parentKey] = []
acc[parentKey].push(item)
return acc
}, {})
})
const collectDeviceOptionsByGroup = (groupId?: string) => {
const deviceMap = new Map<string, OverviewOption>()
const pushDevice = (node?: OrganizationFilterItem) => {
if (!node?.dvId || !node.machineName?.trim()) return
const deviceId = String(node.dvId)
if (!deviceMap.has(deviceId)) {
deviceMap.set(deviceId, {
label: node.machineName.trim(),
value: deviceId
})
}
}
if (!groupId) {
organizationList.value.forEach(pushDevice)
return Array.from(deviceMap.values())
}
const queue = [groupId]
while (queue.length > 0) {
const currentId = queue.shift() as string
pushDevice(organizationMap.value[currentId])
const children = childrenByParentId.value[currentId] || []
children.forEach((child) => queue.push(String(child.id)))
}
return Array.from(deviceMap.values())
}
const deviceOptions = computed(() => collectDeviceOptionsByGroup(queryParams.value.groupId))
const overviewData = ref<RunOverviewData>({
metrics: [],
hourlyStatus: [],
summary: [],
summaryTotalHours: 0,
timelineRows: [],
totalDevices: 0
})
const currentDeviceIds = computed(() =>
queryParams.value.deviceId.length > 0 ? queryParams.value.deviceId : deviceOptions.value.map((item) => item.value)
)
const buildOverviewRequestParams = () => ({
ids: currentDeviceIds.value.join(','),
startTime: queryParams.value.timeRange[0],
endTime: queryParams.value.timeRange[1],
timelinePageNo: pageNo.value,
timelinePageSize: pageSize.value
})
const refreshData = async () => {
const response = await DeviceOperationOverviewApi.getRunOverview(buildOverviewRequestParams())
overviewData.value = {
metrics: response?.metrics || [],
hourlyStatus: response?.hourlyStatus || [],
summary: response?.summary || [],
summaryTotalHours: response?.summaryTotalHours || 0,
timelineRows: response?.timelineRows || [],
totalDevices: response?.totalDevices || 0
}
const maxPage = Math.max(1, Math.ceil(overviewData.value.totalDevices / pageSize.value))
if (pageNo.value > maxPage) pageNo.value = maxPage
}
const resetToFirstPageAndRefresh = () => {
if (pageNo.value !== 1) {
pageNo.value = 1
return
}
void refreshData()
}
const handleQuickRangeChange = (key: QuickRangeKey) => {
queryParams.value = {
...queryParams.value,
quickRange: key,
timeRange: key === 'custom' ? queryParams.value.timeRange : createDateRangeByQuickKey(key)
timeRange: createDateRangeByQuickKey(key)
}
pageNo.value = 1
refreshData()
}
const handleQuery = () => {
pageNo.value = 1
refreshData()
resetToFirstPageAndRefresh()
}
const resetQuery = () => {
queryParams.value = buildDefaultQueryParams()
pageNo.value = 1
pageSize.value = 10
refreshData()
resetToFirstPageAndRefresh()
}
const handleExport = () => {
@ -126,7 +217,52 @@ const handleExport = () => {
const handlePageSizeChange = (size: number) => {
pageSize.value = size
pageNo.value = 1
void refreshData()
}
watch(pageNo, () => {
void refreshData()
})
const getOrganizationOptions = async () => {
const data = await OrganizationApi.getOrganizationList()
organizationList.value = Array.isArray(data)
? data.map((item) => ({
id: String(item.id),
name: item.name,
parentId: item.parentId != null ? String(item.parentId) : item.parentId,
dvId: item.dvId,
machineName: item.machineName
}))
: []
groupOptions.value = handleTree(
organizationList.value.map((item) => ({ ...item })),
'id',
'parentId'
) as OrganizationTreeOption[]
}
watch(
deviceOptions,
(options) => {
if (queryParams.value.deviceId.length === 0) return
const validDeviceIds = queryParams.value.deviceId.filter((deviceId) =>
options.some((item) => item.value === deviceId)
)
if (validDeviceIds.length !== queryParams.value.deviceId.length) {
queryParams.value = {
...queryParams.value,
deviceId: validDeviceIds
}
}
},
{ immediate: true }
)
onMounted(async () => {
await getOrganizationOptions()
await refreshData()
})
</script>
<style scoped lang="scss">

@ -1,178 +1,15 @@
import dayjs from 'dayjs'
import type {
DeviceTimelineRow,
HourlyStatusItem,
OverviewOption,
RunOverviewData,
RunOverviewQueryParams,
RunOverviewMetric,
RunStatus
} from './components/types'
import type { RunOverviewQueryParams } from './components/types'
const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss'
export const GROUP_OPTIONS: OverviewOption[] = [
{ label: 'SMT一组', value: 'group-1' },
{ label: '成型二组', value: 'group-2' },
{ label: '总装三组', value: 'group-3' }
]
export const DEVICE_OPTIONS: OverviewOption[] = [
{ label: '模拟干燥设备04', value: 'device-01' },
{ label: '模拟干燥设备03', value: 'device-02' },
{ label: '模拟干燥设备02', value: 'device-03' },
{ label: '成型模拟设备05', value: 'device-04' },
{ label: '成型模拟设备04', value: 'device-05' },
{ label: '模拟干燥设备', value: 'device-06' },
{ label: '成型模拟设备02', value: 'device-07' },
{ label: '成型模拟设备01', value: 'device-08' },
{ label: '物流输送设备01', value: 'device-09' },
{ label: '包装工作站02', value: 'device-10' },
{ label: '包装工作站03', value: 'device-11' },
{ label: '拧紧设备01', value: 'device-12' },
{ label: '视觉检测设备01', value: 'device-13' }
]
const shiftTimeline = (segments: Array<{ status: RunStatus; startHour: number; endHour: number }>, offset: number) =>
segments.map((segment, index) => {
let nextStart = segment.startHour + offset
let nextEnd = segment.endHour + offset
if (index === 0 && nextStart < 0) nextStart = 0
if (index === segments.length - 1 && nextEnd > 24) nextEnd = 24
return {
...segment,
startHour: Math.max(0, Math.min(24, Number(nextStart.toFixed(2)))),
endHour: Math.max(0, Math.min(24, Number(nextEnd.toFixed(2))))
}
})
const BASE_SEGMENTS = [
{ status: 'running' as const, startHour: 0, endHour: 2.7 },
{ status: 'standby' as const, startHour: 2.7, endHour: 3.1 },
{ status: 'running' as const, startHour: 3.1, endHour: 6.6 },
{ status: 'standby' as const, startHour: 6.6, endHour: 7.15 },
{ status: 'running' as const, startHour: 7.15, endHour: 13.9 },
{ status: 'standby' as const, startHour: 13.9, endHour: 14.25 },
{ status: 'offline' as const, startHour: 14.25, endHour: 14.95 },
{ status: 'running' as const, startHour: 14.95, endHour: 17.45 },
{ status: 'fault' as const, startHour: 17.45, endHour: 18.15 },
{ status: 'standby' as const, startHour: 18.15, endHour: 18.8 },
{ status: 'running' as const, startHour: 18.8, endHour: 20.55 },
{ status: 'standby' as const, startHour: 20.55, endHour: 20.95 },
{ status: 'running' as const, startHour: 20.95, endHour: 22.25 },
{ status: 'offline' as const, startHour: 22.25, endHour: 23.05 },
{ status: 'running' as const, startHour: 23.05, endHour: 23.7 },
{ status: 'offline' as const, startHour: 23.7, endHour: 24 }
]
const TIMELINE_OFFSETS = [0, -0.3, 0.8, -0.5, 0.45, 1.05, -1.1, 0.25, -0.75, 0.6, -0.2, 1.2, -0.45]
export const buildDefaultQueryParams = (): RunOverviewQueryParams => {
const start = dayjs().startOf('day')
const end = dayjs().endOf('day')
return {
groupId: GROUP_OPTIONS[0].value,
deviceId: '',
groupId: '',
deviceId: [],
quickRange: 'today',
timeRange: [start.format(DATE_TIME_FORMAT), end.format(DATE_TIME_FORMAT)]
}
}
const toTimelineRows = (): DeviceTimelineRow[] =>
DEVICE_OPTIONS.map((device, index) => ({
id: device.value,
name: device.label,
utilizationRate: [82.35, 76.12, 68.54, 75.63, 72.18, 91.24, 65.32, 78.44, 71.05, 83.67, 69.18, 87.42, 74.56][index],
segments: shiftTimeline(BASE_SEGMENTS, TIMELINE_OFFSETS[index] || 0)
}))
const toHourlyStatus = (summaryFactor: number): HourlyStatusItem[] => {
return Array.from({ length: 24 }, (_, hour) => {
const runningBase = 74 + Math.sin((hour / 24) * Math.PI * 3) * 14 + summaryFactor * 2
const standbyBase = 10 + Math.cos((hour / 24) * Math.PI * 4) * 7
const faultBase = 2 + Math.max(0, Math.sin((hour - 5) / 2.2)) * 5
const offlineBase = 100 - runningBase - standbyBase - faultBase
const running = Math.max(48, Math.min(88, Number(runningBase.toFixed(2))))
const standby = Math.max(4, Math.min(26, Number(standbyBase.toFixed(2))))
const fault = Math.max(1, Math.min(8, Number(faultBase.toFixed(2))))
const offline = Number(Math.max(4, 100 - running - standby - fault).toFixed(2))
return {
hour: `${String(hour).padStart(2, '0')}:00`,
running,
standby,
fault,
offline
}
})
}
const createMetrics = (summaryFactor: number): RunOverviewMetric[] => [
{
key: 'utilizationRate',
icon: 'ep:pie-chart',
value: Number((75.42 + summaryFactor * 1.2).toFixed(2)),
unit: '%',
change: 4.32
},
{
key: 'powerOnRate',
icon: 'ep:video-play',
value: Number((90.12 + summaryFactor * 0.7).toFixed(2)),
unit: '%',
change: 2.15
},
{
key: 'faultRate',
icon: 'ep:warning',
value: Number(Math.max(1.5, 3.21 - summaryFactor * 0.35).toFixed(2)),
unit: '%',
change: -1.03
},
{
key: 'standbyRate',
icon: 'ep:timer',
value: Number(Math.max(4, 6.67 - summaryFactor * 0.25).toFixed(2)),
unit: '%',
change: -1.14
}
]
const createSummary = (summaryFactor: number) => {
const running = Number((75.42 + summaryFactor * 1.2).toFixed(2))
const standby = Number(Math.max(4, 6.67 - summaryFactor * 0.25).toFixed(2))
const fault = Number(Math.max(1.5, 3.21 - summaryFactor * 0.35).toFixed(2))
const offline = Number((100 - running - standby - fault).toFixed(2))
return [
{ status: 'running' as const, percent: running, hours: Number(((24 * running) / 100).toFixed(2)) },
{ status: 'standby' as const, percent: standby, hours: Number(((24 * standby) / 100).toFixed(2)) },
{ status: 'fault' as const, percent: fault, hours: Number(((24 * fault) / 100).toFixed(2)) },
{ status: 'offline' as const, percent: offline, hours: Number(((24 * offline) / 100).toFixed(2)) }
]
}
export const buildRunOverviewData = (query: RunOverviewQueryParams): RunOverviewData => {
const summaryFactor =
query.quickRange === 'today'
? 0
: query.quickRange === 'yesterday'
? -0.8
: query.quickRange === 'last7Days'
? 1.1
: query.quickRange === 'last30Days'
? 0.45
: 0.15
const rows = toTimelineRows()
const filteredRows = query.deviceId ? rows.filter((row) => row.id === query.deviceId) : rows
return {
metrics: createMetrics(summaryFactor),
hourlyStatus: toHourlyStatus(summaryFactor),
summary: createSummary(summaryFactor),
timelineRows: filteredRows,
totalDevices: filteredRows.length
}
}

@ -37,7 +37,7 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item :label="t('FactoryModeling.ProductBOM.searchEnableLabel')" prop="isEnable">
<el-form-item :label="t('FactoryModeling.ProductBOM.searchEnableLabel')" prop="isEnable" v-show="showAllFilters">
<el-select
v-model="queryParams.isEnable"
:placeholder="t('FactoryModeling.ProductBOM.searchEnablePlaceholder')"
@ -54,6 +54,13 @@
</el-select>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> {{ t('FactoryModeling.ProductBOM.searchButtonText') }}</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> {{ t('FactoryModeling.ProductBOM.resetButtonText') }}</el-button>
@ -178,6 +185,13 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const showAllFilters = ref(false) //
const filterCount = 4 // codeproductIdremarkisEnable
/** 切换筛选框展开/折叠 */
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
/** 查询列表 */
const getList = async () => {

@ -0,0 +1,174 @@
<template>
<Dialog v-model="dialogVisible" :title="dialogTitle" width="1300" :scroll="true" max-height="70vh" align-center>
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="auto">
<el-form-item :label="t('EquipmentManagement.CapacityReport.dialogProductCode')" prop="productCode">
<el-input
v-model="queryParams.productCode"
:placeholder="t('EquipmentManagement.CapacityReport.dialogProductCodePlaceholder')"
clearable
@keyup.enter="handleQuery"
class="!w-200px"
/>
</el-form-item>
<el-form-item :label="t('EquipmentManagement.CapacityReport.dialogProductName')" prop="productName">
<el-input
v-model="queryParams.productName"
:placeholder="t('EquipmentManagement.CapacityReport.dialogProductNamePlaceholder')"
clearable
@keyup.enter="handleQuery"
class="!w-200px"
/>
</el-form-item>
<el-form-item :label="t('EquipmentManagement.CapacityReport.dialogBaogongTime')" prop="baogongTime">
<el-date-picker v-model="baogongTime" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
:start-placeholder="t('EquipmentManagement.CapacityReport.dialogBaogongTimeStart')"
:end-placeholder="t('EquipmentManagement.CapacityReport.dialogBaogongTimeEnd')"
:shortcuts="baogongTimeShortcuts"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-240px" />
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" />
{{ t('EquipmentManagement.CapacityReport.dialogSearchButtonText') }}
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" />
{{ t('EquipmentManagement.CapacityReport.dialogResetButtonText') }}
</el-button>
</el-form-item>
</el-form>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" style="margin-top: 16px">
<el-table-column :label="t('EquipmentManagement.CapacityReport.dialogProductCode')" align="center" prop="productCode" />
<el-table-column :label="t('EquipmentManagement.CapacityReport.dialogProductName')" align="center" prop="productName" />
<el-table-column :label="t('EquipmentManagement.CapacityReport.dialogBaogongTotal')" align="center" prop="baogongTotal" />
<el-table-column :label="t('EquipmentManagement.CapacityReport.dialogAvgCapacity')" align="center" prop="avgCapacity" />
</el-table>
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</Dialog>
</template>
<script setup lang="ts">
import { PlanApi } from '@/api/mes/plan'
const { t } = useI18n()
const props = defineProps<{
modelValue: boolean
deviceId?: number
deviceName?: string
}>()
const emit = defineEmits<{
(e: 'update:modelValue', value: boolean): void
}>()
const dialogVisible = computed({
get() {
return props.modelValue
},
set(value: boolean) {
emit('update:modelValue', value)
}
})
const dialogTitle = computed(() => {
const name = props.deviceName || '-'
return `${t('EquipmentManagement.CapacityReport.dialogTitlePrefix')}${name}`
})
const loading = ref(false)
const list = ref<any[]>([])
const total = ref(0)
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
deviceId: undefined as number | undefined,
productCode: undefined as string | undefined,
productName: undefined as string | undefined,
beginBaogongTime: undefined as string | undefined,
endBaogongTime: undefined as string | undefined
})
const baogongTime = ref<[string, string]>(['', ''])
const baogongTimeShortcuts = [
{
text: t('EquipmentManagement.CapacityReport.shortcutLastWeek'),
value: () => {
const end = new Date()
const start = new Date()
start.setDate(start.getDate() - 7)
return [start, end]
}
},
{
text: t('EquipmentManagement.CapacityReport.shortcutLastHalfYear'),
value: () => {
const end = new Date()
const start = new Date()
start.setMonth(start.getMonth() - 6)
return [start, end]
}
},
{
text: t('EquipmentManagement.CapacityReport.shortcutLastYear'),
value: () => {
const end = new Date()
const start = new Date()
start.setFullYear(start.getFullYear() - 1)
return [start, end]
}
}
]
const queryFormRef = ref()
const getList = async () => {
if (!props.deviceId) {
list.value = []
total.value = 0
return
}
loading.value = true
try {
const params = {
...queryParams,
beginBaogongTime: baogongTime.value?.[0] || undefined,
endBaogongTime: baogongTime.value?.[1] || undefined
}
const data = await PlanApi.getProductCapacityPage(params)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
const resetQuery = () => {
queryFormRef.value?.resetFields()
baogongTime.value = ['', '']
queryParams.deviceId = props.deviceId
handleQuery()
}
watch(
() => [props.modelValue, props.deviceId],
([visible, deviceId]) => {
if (!visible) return
queryParams.deviceId = deviceId as number
queryParams.pageNo = 1
queryParams.productCode = undefined
queryParams.productName = undefined
queryParams.taskCode = undefined
getList()
}
)
</script>

@ -0,0 +1,234 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" min-label-width="80px">
<el-form-item :label="t('EquipmentManagement.CapacityReport.deviceCode')" prop="deviceCode">
<el-input v-model="queryParams.deviceCode"
:placeholder="t('EquipmentManagement.CapacityReport.placeholderDeviceCode')" clearable
@keyup.enter="handleQuery" class="!w-240px" />
</el-form-item>
<el-form-item :label="t('EquipmentManagement.CapacityReport.deviceName')" prop="deviceName">
<el-input v-model="queryParams.deviceName"
:placeholder="t('EquipmentManagement.CapacityReport.placeholderDeviceName')" clearable
@keyup.enter="handleQuery" class="!w-240px" />
</el-form-item>
<el-form-item :label="t('EquipmentManagement.CapacityReport.baogongTime')" prop="baogongTime">
<el-date-picker v-model="baogongTime" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
:start-placeholder="t('EquipmentManagement.CapacityReport.placeholderBaogongTimeStart')"
:end-placeholder="t('EquipmentManagement.CapacityReport.placeholderBaogongTimeEnd')"
:shortcuts="baogongTimeShortcuts"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-240px" />
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') :
t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<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="success" plain @click="handleExport" :loading="exportLoading">
<Icon icon="ep:download" class="mr-5px" /> {{ t('EquipmentManagement.EquipmentLedger.export') }}
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" :row-key="(row) => row.id"
@select-all="handleSelectAll" @select="handleSelect">
<el-table-column type="selection" width="55" align="center" />
<el-table-column :label="t('EquipmentManagement.CapacityReport.deviceCode')" align="center" prop="deviceCode"
sortable />
<el-table-column :label="t('EquipmentManagement.CapacityReport.deviceName')" align="center" prop="deviceName"
sortable />
<el-table-column :label="t('EquipmentManagement.CapacityReport.deviceType')" align="center" prop="typeName"
sortable />
<el-table-column :label="t('EquipmentManagement.CapacityReport.ratedCapacity')" align="center"
prop="ratedCapacity" sortable />
<el-table-column align="center" prop="reportCapacity">
<template #header>
<span>{{ t('EquipmentManagement.CapacityReport.reportCapacity') }}</span>
<el-tooltip :content="t('EquipmentManagement.CapacityReport.reportCapacityTooltip')" placement="top">
<Icon icon="ep:question-filled" class="ml-4px"
style="vertical-align: middle; color: var(--el-text-color-secondary)" />
</el-tooltip>
</template>
<template #default="scope">
<el-button link type="primary" @click="openProductCapacity(scope.row)">
{{ t('EquipmentManagement.CapacityReport.reportCapacityViewDetail') }}
</el-button>
</template>
</el-table-column>
<el-table-column align="center" prop="actualCapacity" sortable>
<template #header>
<span>{{ t('EquipmentManagement.CapacityReport.actualCapacity') }}</span>
<el-tooltip :content="t('EquipmentManagement.CapacityReport.actualCapacityTooltip')" placement="top">
<Icon icon="ep:question-filled" class="ml-4px"
style="vertical-align: middle; color: var(--el-text-color-secondary)" />
</el-tooltip>
</template>
</el-table-column>
<el-table-column :label="t('EquipmentManagement.CapacityReport.workshop')" align="center" prop="workshopName"
sortable />
</el-table>
<Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
@pagination="getList" />
</ContentWrap>
<ProductCapacityDialog v-model="productCapacityVisible" :device-id="productCapacityDeviceId"
:device-name="productCapacityDeviceName" />
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import download from '@/utils/download'
import { DeviceLedgerApi, CapacityReportVO } from '@/api/mes/device-ledger'
import ProductCapacityDialog from './ProductCapacityDialog.vue'
defineOptions({ name: 'CapacityReport' })
const message = useMessage()
const { t } = useI18n()
const loading = ref(true)
const list = ref<CapacityReportVO[]>([])
const total = ref(0)
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
deviceCode: undefined,
deviceName: undefined,
deviceType: undefined,
workshop: undefined,
beginTime: undefined,
endTime: undefined
})
const baogongTime = ref<[string, string]>(['', ''])
const queryFormRef = ref()
const exportLoading = ref(false)
const showAllFilters = ref(false)
const filterCount = 3
const selectedIds = ref<number[]>([])
const productCapacityVisible = ref(false)
const productCapacityDeviceId = ref<number>()
const productCapacityDeviceName = ref<string>()
const baogongTimeShortcuts = [
{
text: t('EquipmentManagement.CapacityReport.shortcutLastWeek'),
value: () => {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
return [start, end]
}
},
{
text: t('EquipmentManagement.CapacityReport.shortcutLastHalfYear'),
value: () => {
const end = new Date()
const start = new Date()
start.setMonth(start.getMonth() - 6)
return [start, end]
}
},
{
text: t('EquipmentManagement.CapacityReport.shortcutLastYear'),
value: () => {
const end = new Date()
const start = new Date()
start.setFullYear(start.getFullYear() - 1)
return [start, end]
}
}
]
const openProductCapacity = (row: CapacityReportVO) => {
productCapacityDeviceId.value = row.id
productCapacityDeviceName.value = row.deviceName
productCapacityVisible.value = true
}
/** 切换筛选框展开/折叠 */
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const getList = async () => {
loading.value = true
try {
const params = {
...queryParams,
beginTime: baogongTime.value?.[0] || undefined,
endTime: baogongTime.value?.[1] || undefined
}
const data = await DeviceLedgerApi.getCapacityReportPage(params)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
const handleQuery = () => {
queryParams.pageNo = 1
selectedIds.value = []
getList()
}
const resetQuery = () => {
queryFormRef.value?.resetFields()
baogongTime.value = ['', '']
selectedIds.value = []
handleQuery()
}
const handleSelectAll = (val: boolean) => {
if (val) {
selectedIds.value = list.value.map(item => item.id)
} else {
selectedIds.value = []
}
}
const handleSelect = (val: boolean, row: CapacityReportVO) => {
if (val) {
selectedIds.value.push(row.id)
} else {
const index = selectedIds.value.indexOf(row.id)
if (index > -1) {
selectedIds.value.splice(index, 1)
}
}
}
const handleExport = async () => {
try {
await message.exportConfirm()
exportLoading.value = true
const params: { ids?: string } = {}
if (selectedIds.value.length > 0) {
params.ids = selectedIds.value.join(',')
}
const data = await DeviceLedgerApi.exportCapacityReport(params)
download.excel(data, t('EquipmentManagement.CapacityReport.exportFilename'))
} catch {
} finally {
exportLoading.value = false
}
}
onMounted(() => {
getList()
})
</script>

File diff suppressed because it is too large Load Diff

@ -72,6 +72,8 @@
:refresh-url="getQrcodeRefreshUrl()"
:refresh-disabled="!formData.id || !formData.code"
refresh-confirm-text="确认刷新该关键件二维码吗?"
:template-json="formData.templateJson"
:print-data="buildPrintData()"
@refresh-success="handleQrcodeRefreshSuccess"
/>
</el-form-item>
@ -123,6 +125,7 @@ const formData = ref<Partial<CriticalComponentVO>>({
count: undefined,
remark: undefined,
qrcodeUrl: undefined,
templateJson: undefined,
images: undefined
})
@ -152,7 +155,9 @@ const resetForm = () => {
description: undefined,
count: undefined,
remark: undefined,
qrcodeUrl: undefined
qrcodeUrl: undefined,
templateJson: undefined,
images: undefined
}
formRef.value?.resetFields?.()
}
@ -169,6 +174,18 @@ const getQrcodeRefreshUrl = () => {
return `/mes/critical-component/regenerate-code?id=${formData.value.id}&code=${encodeURIComponent(String(formData.value.code))}`
}
const buildPrintData = () => {
return {
id: formData.value.id,
code: formData.value.code,
name: formData.value.name,
description: formData.value.description,
count: formData.value.count,
remark: formData.value.remark,
qrcodeUrl: formData.value.qrcodeUrl
}
}
const handleQrcodeRefreshSuccess = async (data: any) => {
if (!formData.value.id) return
if (data?.qrcodeUrl) {
@ -189,6 +206,10 @@ const open = async (type: 'create' | 'update', id?: number) => {
formLoading.value = true
try {
const detail = await CriticalComponentApi.getCriticalComponent(id)
const templateJson = detail?.templateJson
const parsedTemplateJson = typeof templateJson === 'string'
? JSON.parse(templateJson)
: templateJson
formData.value = {
id: detail?.id,
code: detail?.code,
@ -199,6 +220,7 @@ const open = async (type: 'create' | 'update', id?: number) => {
count: detail?.count,
remark: detail?.remark,
qrcodeUrl: detail?.qrcodeUrl,
templateJson: parsedTemplateJson,
images: detail?.images
}
} finally {

@ -11,24 +11,30 @@ v-model="queryParams.code" :placeholder="t('EquipmentManagement.EquipmentKeyItem
v-model="queryParams.name" :placeholder="t('EquipmentManagement.EquipmentKeyItems.placeholderName')"
clearable @keyup.enter="handleQuery" class="!w-240px" />
</el-form-item>
<el-form-item :label="t('EquipmentManagement.EquipmentKeyItems.description')" prop="description">
<el-form-item :label="t('EquipmentManagement.EquipmentKeyItems.description')" prop="description" v-show="showAllFilters">
<el-input
v-model="queryParams.description"
:placeholder="t('EquipmentManagement.EquipmentKeyItems.placeholderDescription')" clearable
@keyup.enter="handleQuery" class="!w-240px" />
</el-form-item>
<el-form-item :label="t('EquipmentManagement.EquipmentKeyItems.remark')" prop="remark">
<el-form-item :label="t('EquipmentManagement.EquipmentKeyItems.remark')" prop="remark" v-show="showAllFilters">
<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="t('EquipmentManagement.EquipmentKeyItems.createTime')" prop="createTime">
<el-form-item :label="t('EquipmentManagement.EquipmentKeyItems.createTime')" prop="createTime" v-show="showAllFilters">
<el-date-picker
v-model="queryParams.createTime" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
: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 v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" />
@ -175,6 +181,11 @@ const queryParams = reactive({
const queryFormRef = ref()
const selectedIds = ref<number[]>([])
const showAllFilters = ref(false)
const filterCount = 5
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const importDialogVisible = ref(false)
const importLoading = ref(false)

@ -63,18 +63,7 @@
class="!w-full" :placeholder="t('EquipmentManagement.EquipmentLedger.placeholderRatedCapacity')" />
</el-form-item>
</el-col>
<el-col v-if="isScheduledEnabled" :span="12">
<el-form-item label="每日报工平均值" prop="dailyAverageValue" :required="isScheduledEnabled">
<el-input-number v-model="formData.dailyAverageValue" :min="0" :precision="0" controls-position="right"
class="!w-full" placeholder="请输入每日报工平均值" />
</el-form-item>
</el-col>
<el-col v-if="isScheduledEnabled" :span="12">
<el-form-item label="数据采集产能" prop="dataCollectionCapacity" :required="isScheduledEnabled">
<el-input-number v-model="formData.dataCollectionCapacity" :min="0" :precision="0"
controls-position="right" class="!w-full" placeholder="请输入数据采集产能" />
</el-form-item>
</el-col>
</el-row>
@ -214,7 +203,10 @@
:print-max-width="220" :empty-text="t('EquipmentManagement.EquipmentLedger.qrcodeEmpty')"
:error-text="t('EquipmentManagement.EquipmentLedger.qrcodeLoadError')"
:refresh-url="getQrcodeRefreshUrl()" :refresh-disabled="!formData.id || !formData.deviceCode"
refresh-confirm-text="确认刷新该设备二维码吗?" @refresh-success="handleQrcodeRefreshSuccess" />
refresh-confirm-text="确认刷新该设备二维码吗?"
:template-json="formData.templateJson"
:print-data="buildPrintData()"
@refresh-success="handleQrcodeRefreshSuccess" />
</el-form-item>
</el-col>
@ -509,10 +501,9 @@ const initFormData = () => ({
beijianIds: [] as number[],
fileUrl: undefined,
qrcodeUrl: undefined,
templateJson: undefined,
sort: undefined,
dvId: undefined,
dailyAverageValue: undefined,
dataCollectionCapacity: undefined
dvId: undefined
})
const formData = ref({
@ -547,8 +538,6 @@ const formRules = reactive<FormRules>({
deviceName: [{ required: true, message: t('EquipmentManagement.EquipmentLedger.placeholderDeviceName'), trigger: 'blur' }],
deviceType: [{ required: true, message: t('EquipmentManagement.EquipmentLedger.placeholderDeviceType'), trigger: 'change' }],
ratedCapacity: [{ validator: validateScheduledRequired('额定产能'), trigger: ['blur', 'change'] }],
dailyAverageValue: [{ validator: validateScheduledRequired('每日报工平均值'), trigger: ['blur', 'change'] }],
dataCollectionCapacity: [{ validator: validateScheduledRequired('数据采集产能'), trigger: ['blur', 'change'] }],
productionDate: [{ required: true, message: t('EquipmentManagement.EquipmentLedger.placeholderProductionDate'), trigger: 'change' }],
factoryEntryDate: [{ required: true, message: t('EquipmentManagement.EquipmentLedger.placeholderFactoryEntryDate'), trigger: 'change' }]
})
@ -557,7 +546,7 @@ const formRef = ref() // 表单 Ref
watch(
() => formData.value.isScheduled,
() => {
formRef.value?.clearValidate?.(['ratedCapacity', 'dailyAverageValue', 'dataCollectionCapacity'])
formRef.value?.clearValidate?.(['ratedCapacity'])
}
)
@ -643,6 +632,20 @@ const getQrcodeRefreshUrl = () => {
return `/mes/device-ledger/regenerate-code?id=${formData.value.id}&code=${encodeURIComponent(String(formData.value.deviceCode))}`
}
const buildPrintData = () => {
return {
id: formData.value.id,
deviceCode: formData.value.deviceCode,
deviceName: formData.value.deviceName,
deviceSpec: formData.value.deviceSpec,
deviceBrand: formData.value.deviceBrand,
deviceModel: formData.value.deviceModel,
deviceLocation: formData.value.deviceLocation,
remark: formData.value.remark,
qrcodeUrl: formData.value.qrcodeUrl
}
}
const handleQrcodeRefreshSuccess = async (data: any) => {
if (!formData.value.id) return
if (data?.qrcodeUrl) {
@ -692,9 +695,14 @@ const open = async (type: string, id?: number, defaultDeviceTypeId?: number) =>
formLoading.value = true
try {
const detail = await DeviceLedgerApi.getDeviceLedger(id)
const templateJson = (detail as any)?.templateJson
const parsedTemplateJson = typeof templateJson === 'string'
? JSON.parse(templateJson)
: templateJson
formData.value = {
...initFormData(),
...(detail as any),
templateJson: parsedTemplateJson,
isCode: (detail as any)?.isCode ?? false,
isScheduled: normalizeNumberish((detail as any)?.isScheduled ?? (detail as any)?.isScheduled) ?? 0,
ratedCapacity: normalizeNumberish((detail as any)?.ratedCapacity),
@ -705,8 +713,6 @@ const open = async (type: string, id?: number, defaultDeviceTypeId?: number) =>
componentIds: parseIdsValue((detail as any)?.componentId),
beijianIds: parseIdsValue((detail as any)?.beijianId),
qrcodeUrl: (detail as any)?.qrcodeUrl,
dailyAverageValue: normalizeNumberish((detail as any)?.dailyAverageValue),
dataCollectionCapacity: normalizeNumberish((detail as any)?.dataCollectionCapacity),
}
} finally {
formLoading.value = false
@ -934,9 +940,7 @@ const submitForm = async () => {
deviceManager: formData.value.deviceManagerIds?.length ? formData.value.deviceManagerIds.join(',') : undefined,
componentId: formData.value.componentIds?.length ? formData.value.componentIds.join(',') : undefined,
beijianId: formData.value.beijianIds?.length ? formData.value.beijianIds.join(',') : undefined,
fileUrl: normalizeFileUrlAsJsonArrayString((formData.value as any).fileUrl),
dailyAverageValue: normalizeNumberish((formData.value as any).dailyAverageValue),
dataCollectionCapacity: normalizeNumberish((formData.value as any).dataCollectionCapacity)
fileUrl: normalizeFileUrlAsJsonArrayString((formData.value as any).fileUrl)
} as unknown as DeviceLedgerVO
delete (data as any).deviceManagerIds
delete (data as any).componentIds

@ -28,7 +28,7 @@
class="!w-240px" />
</el-form-item>
<el-form-item :label="t('EquipmentManagement.DvRepair.requireDate')" prop="requireDate">
<el-form-item :label="t('EquipmentManagement.DvRepair.requireDate')" prop="requireDate" v-show="showAllFilters">
<el-date-picker
v-model="queryParams.requireDate"
value-format="YYYY-MM-DD HH:mm:ss"
@ -37,7 +37,7 @@
:end-placeholder="t('common.endTimeText')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-240px" />
</el-form-item>
<el-form-item :label="t('EquipmentManagement.DvRepair.finishDate')" prop="finishDate">
<el-form-item :label="t('EquipmentManagement.DvRepair.finishDate')" prop="finishDate" v-show="showAllFilters">
<el-date-picker
v-model="queryParams.finishDate"
value-format="YYYY-MM-DD HH:mm:ss"
@ -46,7 +46,7 @@
:end-placeholder="t('common.endTimeText')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-240px" />
</el-form-item>
<el-form-item :label="t('EquipmentManagement.DvRepair.confirmDate')" prop="confirmDate">
<el-form-item :label="t('EquipmentManagement.DvRepair.confirmDate')" prop="confirmDate" v-show="showAllFilters">
<el-date-picker
v-model="queryParams.confirmDate"
value-format="YYYY-MM-DD HH:mm:ss"
@ -55,7 +55,7 @@
:end-placeholder="t('common.endTimeText')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-240px" />
</el-form-item>
<el-form-item :label="t('EquipmentManagement.DvRepair.acceptedBy')" prop="acceptedBy">
<el-form-item :label="t('EquipmentManagement.DvRepair.acceptedBy')" prop="acceptedBy" v-show="showAllFilters">
<el-input
v-model="queryParams.acceptedBy"
:placeholder="t('EquipmentManagement.DvRepair.placeholderAcceptedBy')"
@ -64,7 +64,7 @@
class="!w-240px" />
</el-form-item>
<el-form-item :label="t('EquipmentManagement.DvRepair.status')" prop="status">
<el-form-item :label="t('EquipmentManagement.DvRepair.status')" prop="status" v-show="showAllFilters">
<el-select
v-model="queryParams.status"
:placeholder="t('EquipmentManagement.DvRepair.placeholderStatus')"
@ -74,6 +74,12 @@
<el-option v-for="opt in statusOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" />
@ -229,6 +235,11 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const showAllFilters = ref(false)
const filterCount = 8
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const statusOptions = [
{ label: t('EquipmentManagement.DvRepair.statusPending'), value: '0' },

@ -35,7 +35,7 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item :label="t('EnergyManagement.EnergyType.searchCreateTimeLabel')" prop="createTime">
<el-form-item :label="t('EnergyManagement.EnergyType.searchCreateTimeLabel')" prop="createTime" v-show="showAllFilters">
<el-date-picker
v-model="queryParams.createTime"
value-format="YYYY-MM-DD HH:mm:ss"
@ -46,6 +46,13 @@
class="!w-220px"
/>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') :
t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" />
@ -192,6 +199,11 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const showAllFilters = ref(false)
const filterCount = 4
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const selectedIds = ref<number[]>([])
const handleSelectionChange = (rows: EnergyTypeVO[]) => {

@ -40,7 +40,7 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item :label="t('ProductionPlan.FeedingRecord.searchUserLabel')" prop="userId">
<el-form-item :label="t('ProductionPlan.FeedingRecord.searchUserLabel')" prop="userId" v-show="showAllFilters">
<el-input
v-model="queryParams.userId"
:placeholder="t('ProductionPlan.FeedingRecord.searchUserPlaceholder')"
@ -49,7 +49,7 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item :label="t('ProductionPlan.FeedingRecord.searchRemarkLabel')" prop="remark">
<el-form-item :label="t('ProductionPlan.FeedingRecord.searchRemarkLabel')" prop="remark" v-show="showAllFilters">
<el-input
v-model="queryParams.remark"
:placeholder="t('ProductionPlan.FeedingRecord.searchRemarkPlaceholder')"
@ -58,6 +58,15 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') :
t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> {{ t('ProductionPlan.FeedingRecord.buttonSearchText') }}</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> {{ t('ProductionPlan.FeedingRecord.buttonResetText') }}</el-button>
@ -214,6 +223,13 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const showAllFilters = ref(false) //
const filterCount = 4 //
/** 切换筛选框展开/折叠 */
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
/** 查询列表 */
const getList = async () => {

@ -61,7 +61,7 @@
/>
</el-select>
</el-form-item> -->
<el-form-item :label="t('MoldManagement.MoldGet.warehouse')" prop="warehouseId">
<el-form-item :label="t('MoldManagement.MoldGet.warehouse')" prop="warehouseId" v-show="showAllFilters">
<el-select
v-model="queryParams.warehouseId"
clearable
@ -77,7 +77,7 @@
/>
</el-select>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldGet.creator')" prop="creator">
<el-form-item :label="t('MoldManagement.MoldGet.creator')" prop="creator" v-show="showAllFilters">
<el-select
v-model="queryParams.creator"
clearable
@ -93,7 +93,7 @@
/>
</el-select>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldGet.status')" prop="status">
<el-form-item :label="t('MoldManagement.MoldGet.status')" prop="status" v-show="showAllFilters">
<el-select
v-model="queryParams.status"
:placeholder="t('MoldManagement.MoldGet.placeholderStatus')"
@ -108,7 +108,7 @@
/>
</el-select>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldGet.remark')" prop="remark">
<el-form-item :label="t('MoldManagement.MoldGet.remark')" prop="remark" v-show="showAllFilters">
<el-input
v-model="queryParams.remark"
:placeholder="t('MoldManagement.MoldGet.placeholderRemark')"
@ -117,6 +117,12 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<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>
@ -297,6 +303,11 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const showAllFilters = ref(false)
const filterCount = 7
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const productList = ref<ProductVO[]>([]) //
const warehouseList = ref<WarehouseVO[]>([]) //
const customerList = ref<CustomerVO[]>([]) //

@ -60,7 +60,7 @@
/>
</el-select>
</el-form-item> -->
<el-form-item :label="t('MoldManagement.MoldReturn.warehouse')" prop="warehouseId">
<el-form-item :label="t('MoldManagement.MoldReturn.warehouse')" prop="warehouseId" v-show="showAllFilters">
<el-select
v-model="queryParams.warehouseId"
clearable
@ -76,7 +76,7 @@
/>
</el-select>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldReturn.creator')" prop="creator">
<el-form-item :label="t('MoldManagement.MoldReturn.creator')" prop="creator" v-show="showAllFilters">
<el-select
v-model="queryParams.creator"
clearable
@ -92,7 +92,7 @@
/>
</el-select>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldReturn.status')" prop="status">
<el-form-item :label="t('MoldManagement.MoldReturn.status')" prop="status" v-show="showAllFilters">
<el-select
v-model="queryParams.status"
:placeholder="t('MoldManagement.MoldReturn.placeholderStatus')"
@ -107,7 +107,7 @@
/>
</el-select>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldReturn.remark')" prop="remark">
<el-form-item :label="t('MoldManagement.MoldReturn.remark')" prop="remark" v-show="showAllFilters">
<el-input
v-model="queryParams.remark"
:placeholder="t('MoldManagement.MoldReturn.placeholderRemark')"
@ -116,6 +116,12 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<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>
@ -292,6 +298,11 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const showAllFilters = ref(false)
const filterCount = 7
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const productList = ref<ProductVO[]>([]) //
const warehouseList = ref<WarehouseVO[]>([]) //
const customerList = ref<CustomerVO[]>([]) //

@ -54,7 +54,7 @@
/>
</el-select>
</el-form-item> -->
<el-form-item :label="t('FactoryModeling.FactoryStructure.searchOrgClassLabel')" prop="orgClass">
<el-form-item :label="t('FactoryModeling.FactoryStructure.searchOrgClassLabel')" prop="orgClass" v-show="showAllFilters">
<el-select
v-model="queryParams.orgClass"
:placeholder="t('FactoryModeling.FactoryStructure.searchOrgClassPlaceholder')"
@ -70,6 +70,13 @@
</el-select>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> {{ t('FactoryModeling.FactoryStructure.searchButtonText') }}</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> {{ t('FactoryModeling.FactoryStructure.resetButtonText') }}</el-button>
@ -219,6 +226,13 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const showAllFilters = ref(false) //
const filterCount = 4 // codeparentIdnameorgClass
/** 切换筛选框展开/折叠 */
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
/** 查询列表 */
const getList = async () => {

@ -18,22 +18,31 @@
<el-option v-for="item in productList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item :label="t('ProductionPlan.Plan.searchRemarkLabel')" prop="remark">
<el-form-item :label="t('ProductionPlan.Plan.searchRemarkLabel')" prop="remark" v-show="showAllFilters">
<el-input v-model="queryParams.remark" :placeholder="t('ProductionPlan.Plan.searchRemarkPlaceholder')" clearable
@keyup.enter="handleQuery" class="!w-180px" />
</el-form-item>
<el-form-item :label="t('ProductionPlan.Plan.searchPlanStartLabel')" prop="planStartTime">
<el-form-item :label="t('ProductionPlan.Plan.searchPlanStartLabel')" prop="planStartTime" v-show="showAllFilters">
<el-date-picker v-model="queryParams.planStartTime" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
@change="handleQuery" :start-placeholder="t('ProductionPlan.Plan.searchPlanStartStartPlaceholder')"
:end-placeholder="t('ProductionPlan.Plan.searchPlanStartEndPlaceholder')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-240px" />
</el-form-item>
<el-form-item :label="t('ProductionPlan.Plan.searchPlanEndLabel')" prop="planEndTime">
<el-form-item :label="t('ProductionPlan.Plan.searchPlanEndLabel')" prop="planEndTime" v-show="showAllFilters">
<el-date-picker v-model="queryParams.planEndTime" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
@change="handleQuery" :start-placeholder="t('ProductionPlan.Plan.searchPlanEndStartPlaceholder')"
:end-placeholder="t('ProductionPlan.Plan.searchPlanEndEndPlaceholder')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-240px" />
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') :
t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> {{ t('ProductionPlan.Plan.buttonSearchText') }}
@ -321,6 +330,14 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const showAllFilters = ref(false) //
const filterCount = 4 //
/** 切换筛选框展开/折叠 */
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const warehouseList = ref<WarehouseVO[]>([]) //
const storeDialogVisible = ref(false) //
const storeWarehouseId = ref<number>() // ID

@ -0,0 +1,441 @@
<template>
<Dialog v-model="dialogVisible" :title="dialogTitle" width="92%" :fullscreen="false" top="4vh">
<div class="hiprint-preview">
<div class="hiprint-toolbar">
<div class="hiprint-paper">
<el-button
v-for="(value, type) in paperTypes"
:key="type"
size="small"
:type="curPaperType === type ? 'primary' : 'default'"
@click="setPaper(type, value)"
>
{{ type }}
</el-button>
<el-popover placement="bottom-start" :width="260" trigger="click" v-model:visible="paperPopVisible">
<template #reference>
<el-button size="small" :type="curPaperType === 'other' ? 'primary' : 'default'">自定义纸张</el-button>
</template>
<div class="paper-pop">
<div class="paper-pop-title">设置纸张宽高(mm)</div>
<div class="paper-pop-form">
<el-input-number v-model="paperWidth" :precision="1" :min="1" controls-position="right" />
<span>x</span>
<el-input-number v-model="paperHeight" :precision="1" :min="1" controls-position="right" />
</div>
<el-button class="mt-8px" size="small" type="primary" @click="setPaperOther"></el-button>
</div>
</el-popover>
</div>
<div class="hiprint-zoom">
<el-button size="small" @click="changeScale(false)">
<Icon icon="ep:zoom-out" />
</el-button>
<div class="zoom-value">{{ (scaleValue * 100).toFixed(0) }}%</div>
<el-button size="small" @click="changeScale(true)">
<Icon icon="ep:zoom-in" />
</el-button>
</div>
<el-button type="primary" size="small" :loading="saveLoading" @click="handleSave">
<Icon icon="ep:check" class="mr-4px" />
{{ t('common.save') }}
</el-button>
</div>
<div class="hiprint-body">
<div class="hiprint-left">
<div class="hiprint-title">基础元素</div>
<div :id="dragContainerId" class="hiprint-drag-wrap">
<div v-for="item in baseElements" :key="item.tid" class="ep-draggable-item hiprint-item" :tid="item.tid">
<span>{{ item.label }}</span>
</div>
</div>
<div v-if="barcodeElements.length" class="hiprint-title" style="margin-top: 8px"></div>
<div v-if="barcodeElements.length" :id="barcodeDragContainerId" class="hiprint-drag-wrap">
<div v-for="item in barcodeElements" :key="item.tid" class="ep-draggable-item hiprint-item" :tid="item.tid">
<span style="display: block; text-align: center;" v-html="item.label"></span>
</div>
</div>
</div>
<div class="hiprint-center">
<div :id="designerContainerId"></div>
</div>
<div class="hiprint-right">
<div :id="settingContainerId"></div>
</div>
</div>
</div>
</Dialog>
</template>
<script setup lang="ts">
import { defaultElementTypeProvider, hiprint } from 'vue-plugin-hiprint'
import { PrintTemplateApi } from '@/api/mes/printtemplate'
import { getSimpleDictDataList } from '@/api/system/dict/dict.data'
import qrCodeImg from '@/assets/imgs/qrCode.png'
const { t } = useI18n()
const message = useMessage()
const baseElements = [
{ tid: 'defaultModule.text', label: '文本' },
{ tid: 'defaultModule.image', label: '图片' },
{ tid: 'qrcodeModule.qrcode', label: '二维码' },
{ tid: 'defaultModule.longText', label: '长文' },
{ tid: 'defaultModule.table', label: '表格' },
{ tid: 'defaultModule.hline', label: '横线' },
{ tid: 'defaultModule.vline', label: '竖线' },
{ tid: 'defaultModule.rect', label: '矩形' },
{ tid: 'defaultModule.oval', label: '圆形' }
]
const barcodeElements = ref<{ tid: string; label: string }[]>([])
const barcodeDictData = ref<any[]>([])
const loadBarcodeDictData = async () => {
try {
const res = await getSimpleDictDataList()
const filtered = (res || []).filter((item: any) => item.dictType === 'print_template_type')
barcodeDictData.value = filtered
const elements: { tid: string; label: string }[] = []
filtered.forEach((item: any) => {
elements.push({ tid: `barcodeModule.${item.value}_qrcode`, label: `${item.label}<br/>二维码` })
elements.push({ tid: `barcodeModule.${item.value}_text`, label: `${item.label}<br/>文本` })
})
barcodeElements.value = elements
} catch (e) {
console.error('加载条码字典数据失败', e)
}
}
const barcodeProvider = function () {
const addElementTypes = function (context: any) {
context.removePrintElementTypes('barcodeModule')
if (!barcodeDictData.value.length) return
const groups: any[] = []
barcodeDictData.value.forEach((item: any) => {
const remark = item.remark || ''
const parts = remark.split(',').map((s: string) => s.trim())
const qrcodeField = parts[0] || ''
const textField = parts[1] || ''
groups.push(
new hiprint.PrintElementTypeGroup(item.label, [
{
tid: `barcodeModule.${item.value}_qrcode`,
title: `${item.label}`,
type: 'image',
options: {
field: qrcodeField,
src: qrCodeImg,
testData: qrCodeImg,
width: 80,
height: 80,
title: `${item.label}<br/>二维码`
}
},
{
tid: `barcodeModule.${item.value}_text`,
title: `${item.label}`,
type: 'text',
options: {
field: textField,
testData: '',
title: `${item.label}<br/>文本`,
fontSize: 10,
textAlign: 'center',
width: 80,
height: 16
}
}
])
)
})
context.addPrintElementTypes('barcodeModule', groups)
}
return { addElementTypes }
}
const qrcodeProvider = function () {
const addElementTypes = function (context: any) {
context.removePrintElementTypes('qrcodeModule')
context.addPrintElementTypes('qrcodeModule', [
new hiprint.PrintElementTypeGroup('二维码', [
{
tid: 'qrcodeModule.qrcode',
title: '二维码',
type: 'image',
options: {
field: '',
src: qrCodeImg,
testData: qrCodeImg,
width: 80,
height: 80,
title: '二维码'
}
}
])
])
}
return { addElementTypes }
}
const dialogVisible = ref(false)
const dialogTitle = ref('模板配置')
const saveLoading = ref(false)
const currentRow = ref<any>(null)
const currentTemplateJson = ref<Record<string, any> | undefined>(undefined)
const instanceId = `hiprint-designer-${Math.random().toString(36).slice(2)}`
const dragContainerId = `${instanceId}-drag`
const barcodeDragContainerId = `${instanceId}-barcode-drag`
const designerContainerId = `${instanceId}-designer`
const settingContainerId = `${instanceId}-setting`
const paperTypes = {
A3: { width: 420, height: 296.6 },
A4: { width: 210, height: 296.6 },
A5: { width: 210, height: 147.6 },
B3: { width: 500, height: 352.6 },
B4: { width: 250, height: 352.6 },
B5: { width: 250, height: 175.6 }
}
const curPaper = ref({
type: 'A4',
width: 210,
height: 296.6
})
const paperPopVisible = ref(false)
const paperWidth = ref(220)
const paperHeight = ref(80)
const curPaperType = computed(() => {
let type = 'other'
for (const [key, value] of Object.entries(paperTypes)) {
if (value.width === curPaper.value.width && value.height === curPaper.value.height) {
type = key
break
}
}
return type
})
const scaleValue = ref(1)
const scaleMax = 5
const scaleMin = 0.5
let hiprintInited = false
let hiprintTemplate: any
const ensureInit = () => {
if (hiprintInited) {
return
}
hiprint.init({
providers: [new defaultElementTypeProvider(), qrcodeProvider(), barcodeProvider()]
})
hiprintInited = true
}
const buildLeftElement = () => {
const jquery = (window as any).$
if (!jquery) {
message.warning('未检测到 jQuery无法加载拖拽元素')
return
}
hiprint.PrintElementTypeManager.buildByHtml(jquery(`#${dragContainerId} .ep-draggable-item`))
if (barcodeElements.value.length) {
hiprint.PrintElementTypeManager.buildByHtml(jquery(`#${barcodeDragContainerId} .ep-draggable-item`))
}
}
const buildDesigner = () => {
const jquery = (window as any).$
if (!jquery) {
message.warning('未检测到 jQuery无法初始化打印设计器')
return
}
jquery(`#${designerContainerId}`).empty()
const template = currentTemplateJson.value || undefined
hiprintTemplate = new hiprint.PrintTemplate({
template,
settingContainer: `#${settingContainerId}`
})
hiprintTemplate.design(`#${designerContainerId}`)
setPaper(curPaperType.value, { width: curPaper.value.width, height: curPaper.value.height })
hiprintTemplate.zoom(scaleValue.value)
}
const setPaper = (type: string, value: { width: number; height: number }) => {
if (!hiprintTemplate) {
return
}
const width = Number(value.width)
const height = Number(value.height)
curPaper.value = { type, width, height }
hiprintTemplate.setPaper(width, height)
}
const setPaperOther = () => {
paperPopVisible.value = false
setPaper('other', { width: Number(paperWidth.value), height: Number(paperHeight.value) })
}
const changeScale = (isZoomIn: boolean) => {
if (!hiprintTemplate) {
return
}
let nextScale = scaleValue.value
if (isZoomIn) {
nextScale += 0.1
if (nextScale > scaleMax) nextScale = scaleMax
} else {
nextScale -= 0.1
if (nextScale < scaleMin) nextScale = scaleMin
}
scaleValue.value = nextScale
hiprintTemplate.zoom(nextScale)
}
const handleSave = async () => {
if (!hiprintTemplate) {
return
}
const templateJson = hiprintTemplate.getJson()
saveLoading.value = true
try {
await PrintTemplateApi.updatePrintTemplate({
id: currentRow.value.id,
templateCode: currentRow.value.templateCode,
templateName: currentRow.value.templateName,
templateType: currentRow.value.templateType,
templateJson: JSON.stringify(templateJson),
} as any)
message.success(t('common.updateSuccess'))
dialogVisible.value = false
emit('success')
} finally {
saveLoading.value = false
}
}
const resetState = () => {
scaleValue.value = 1
curPaper.value = {
type: 'A4',
width: 210,
height: 296.6
}
paperWidth.value = 220
paperHeight.value = 80
paperPopVisible.value = false
}
const open = async (row: any) => {
currentRow.value = row
dialogTitle.value = `${t('TemplateManagement.PrintTemplate.designTitle')}${row.templateName ? ' - ' + row.templateName : ''}`
currentTemplateJson.value = row.templateJson ? (typeof row.templateJson === 'string' ? JSON.parse(row.templateJson) : row.templateJson) : undefined
resetState()
await loadBarcodeDictData()
dialogVisible.value = true
await nextTick()
ensureInit()
buildLeftElement()
buildDesigner()
}
const emit = defineEmits(['success'])
defineExpose({ open })
</script>
<style scoped lang="scss">
.hiprint-preview {
width: 100%;
}
.hiprint-toolbar {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 12px;
}
.hiprint-paper {
display: flex;
align-items: center;
gap: 6px;
flex-wrap: wrap;
}
.hiprint-zoom {
display: flex;
align-items: center;
gap: 4px;
}
.zoom-value {
width: 56px;
text-align: center;
font-size: 13px;
color: var(--el-text-color-regular);
}
.paper-pop-title {
font-size: 14px;
font-weight: 600;
}
.paper-pop-form {
margin-top: 8px;
display: flex;
align-items: center;
gap: 8px;
}
.hiprint-body {
height: 75vh;
display: grid;
grid-template-columns: 220px 1fr 300px;
gap: 12px;
}
.hiprint-left,
.hiprint-center,
.hiprint-right {
background: var(--el-bg-color);
border: 1px solid var(--el-border-color-light);
border-radius: 8px;
overflow: auto;
}
.hiprint-center {
padding: 16px;
}
.hiprint-right {
padding: 12px;
}
.hiprint-title {
padding: 10px 10px 0;
font-weight: 600;
}
.hiprint-drag-wrap {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
padding: 10px;
}
.hiprint-item {
min-height: 56px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 6px;
border: 1px solid var(--el-border-color);
background: var(--el-fill-color-light);
color: var(--el-text-color-primary);
cursor: grab;
}
</style>

@ -0,0 +1,125 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="120px" v-loading="formLoading">
<el-form-item prop="templateCode">
<template #label>
<span>
{{ t('TemplateManagement.PrintTemplate.templateCode') }}
<el-tooltip :content="t('TemplateManagement.PrintTemplate.templateCodeTooltip')" placement="top">
<Icon icon="ep:question-filled" />
</el-tooltip>
</span>
</template>
<el-row :gutter="10" style="width: 100%;">
<el-col :xs="24" :sm="18" :md="16" :lg="14" :xl="12">
<el-input v-model="formData.templateCode" :placeholder="t('TemplateManagement.PrintTemplate.placeholderTemplateCode')" :disabled="formData.isAutoCode || formType === 'update'" />
</el-col>
<el-col :xs="24" :sm="6" :md="4" :lg="3" :xl="2">
<el-switch v-model="formData.isAutoCode" :disabled="formType === 'update'" />
</el-col>
</el-row>
</el-form-item>
<el-form-item :label="t('TemplateManagement.PrintTemplate.templateName')" prop="templateName">
<el-input v-model="formData.templateName" :placeholder="t('TemplateManagement.PrintTemplate.placeholderTemplateName')" />
</el-form-item>
<el-form-item :label="t('TemplateManagement.PrintTemplate.templateType')" prop="templateType">
<el-select v-model="formData.templateType" :placeholder="t('TemplateManagement.PrintTemplate.placeholderTemplateType')" class="!w-full">
<el-option v-for="dict in getIntDictOptions('print_template_type')" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item :label="t('TemplateManagement.PrintTemplate.isEnable')" prop="isEnable">
<el-switch v-model="formData.isEnable" />
</el-form-item>
<el-form-item :label="t('TemplateManagement.PrintTemplate.remark')" prop="remark">
<el-input v-model="formData.remark" :placeholder="t('TemplateManagement.PrintTemplate.placeholderRemark')" />
</el-form-item>
</el-form>
<template #footer>
<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>
<script setup lang="ts">
import { PrintTemplateApi, PrintTemplateVO } from '@/api/mes/printtemplate'
import { getIntDictOptions } from '@/utils/dict'
defineOptions({ name: 'PrintTemplateForm' })
const { t } = useI18n()
const message = useMessage()
const dialogVisible = ref(false)
const dialogTitle = ref('')
const formLoading = ref(false)
const formType = ref('')
const formData = ref({
id: undefined,
templateCode: undefined,
isAutoCode: true,
templateName: undefined,
templateType: undefined,
remark: undefined,
isEnable: true,
})
const formRules = computed(() => ({
templateCode: formData.value.isAutoCode ? [] : [{ required: true, message: t('TemplateManagement.PrintTemplate.validatorCodeRequired'), trigger: 'blur' }],
templateName: [{ required: true, message: t('TemplateManagement.PrintTemplate.validatorNameRequired'), trigger: 'blur' }],
templateType: [{ required: true, message: t('TemplateManagement.PrintTemplate.validatorTypeRequired'), trigger: 'change' }],
}))
const formRef = ref()
const open = async (type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
if (id) {
formLoading.value = true
try {
formData.value = await PrintTemplateApi.getPrintTemplate(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ open })
const emit = defineEmits(['success'])
const submitForm = async () => {
await formRef.value.validate()
formLoading.value = true
try {
const data = formData.value as unknown as PrintTemplateVO
const { isAutoCode, ...submitData } = data as any
if (isAutoCode) {
delete submitData.templateCode
}
if (formType.value === 'create') {
await PrintTemplateApi.createPrintTemplate(submitData)
message.success(t('common.createSuccess'))
} else {
await PrintTemplateApi.updatePrintTemplate(submitData)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
emit('success')
} finally {
formLoading.value = false
}
}
const resetForm = () => {
formData.value = {
id: undefined,
templateCode: undefined,
isAutoCode: true,
templateName: undefined,
templateType: undefined,
remark: undefined,
isEnable: true,
}
formRef.value?.resetFields()
}
</script>

@ -0,0 +1,169 @@
<template>
<ContentWrap>
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" min-label-width="68px">
<el-form-item :label="t('TemplateManagement.PrintTemplate.templateCode')" prop="templateCode">
<el-input v-model="queryParams.templateCode"
:placeholder="t('TemplateManagement.PrintTemplate.placeholderTemplateCode')" clearable
@keyup.enter="handleQuery" class="!w-240px" />
</el-form-item>
<el-form-item :label="t('TemplateManagement.PrintTemplate.templateName')" prop="templateName">
<el-input v-model="queryParams.templateName"
:placeholder="t('TemplateManagement.PrintTemplate.placeholderTemplateName')" clearable
@keyup.enter="handleQuery" class="!w-240px" />
</el-form-item>
<el-form-item>
<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" /> {{ t('action.add') }}
</el-button>
<el-button type="success" plain @click="handleExport" :loading="exportLoading">
<Icon icon="ep:download" class="mr-5px" /> {{ t('action.export') }}
</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"
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" fixed="left" reserve-selection />
<el-table-column :label="t('TemplateManagement.PrintTemplate.templateCode')" align="center" prop="templateCode"
sortable />
<el-table-column :label="t('TemplateManagement.PrintTemplate.templateName')" align="center" prop="templateName"
sortable />
<el-table-column :label="t('TemplateManagement.PrintTemplate.templateType')" align="center" prop="templateType"
sortable>
<template #default="scope">
<dict-tag type="print_template_type" :value="scope.row.templateType" />
</template>
</el-table-column>
<el-table-column :label="t('TemplateManagement.PrintTemplate.isEnable')" align="center" prop="isEnable" sortable>
<template #default="scope">
<el-tag :type="scope.row.isEnable ? 'success' : 'danger'">
{{ scope.row.isEnable ? t('TemplateManagement.PrintTemplate.enabled') :
t('TemplateManagement.PrintTemplate.disabled') }}
</el-tag>
</template>
</el-table-column>
<el-table-column :label="t('TemplateManagement.PrintTemplate.templateJson')" align="center" prop="templateJson"
min-width="200px" :show-overflow-tooltip="true" />
<el-table-column :label="t('TemplateManagement.PrintTemplate.remark')" align="center" prop="remark" />
<el-table-column :label="t('TemplateManagement.PrintTemplate.createTime')" align="center" prop="createTime"
:formatter="dateFormatter" width="180px" sortable />
<el-table-column :label="t('TemplateManagement.PrintTemplate.operate')" align="center" min-width="160px">
<template #default="scope">
<el-button link type="primary" @click="openForm('update', scope.row.id)">
{{ t('action.edit') }}
</el-button>
<el-button link type="warning" @click="openDesigner(scope.row)">
{{ t('TemplateManagement.PrintTemplate.design') }}
</el-button>
<el-button link type="danger" @click="handleDelete(scope.row.id)">
{{ t('action.del') }}
</el-button>
</template>
</el-table-column>
</el-table>
<Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
@pagination="getList" />
</ContentWrap>
<PrintTemplateForm ref="formRef" @success="getList" />
<PrintTemplateDesigner ref="designerRef" @success="getList" />
</template>
<script setup lang="ts">
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { PrintTemplateApi, PrintTemplateVO } from '@/api/mes/printtemplate'
import { DictTag } from '@/components/DictTag'
import PrintTemplateForm from './PrintTemplateForm.vue'
import PrintTemplateDesigner from './PrintTemplateDesigner.vue'
defineOptions({ name: 'PrintTemplate' })
const message = useMessage()
const { t } = useI18n()
const loading = ref(true)
const list = ref<PrintTemplateVO[]>([])
const total = ref(0)
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
templateCode: undefined,
templateName: undefined,
})
const queryFormRef = ref()
const exportLoading = ref(false)
const selectedIds = ref<number[]>([])
const getList = async () => {
loading.value = true
try {
const data = await PrintTemplateApi.getPrintTemplatePage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
const designerRef = ref()
const openDesigner = (row: any) => {
designerRef.value.open(row)
}
const handleDelete = async (id: number) => {
try {
await message.delConfirm()
await PrintTemplateApi.deletePrintTemplate(id)
message.success(t('common.delSuccess'))
await getList()
} catch { }
}
const handleExport = async () => {
try {
await message.exportConfirm()
exportLoading.value = true
const params = {
...queryParams,
ids: selectedIds.value.length ? selectedIds.value.join(',') : undefined,
}
const data = await PrintTemplateApi.exportPrintTemplate(params)
download.excel(data, t('TemplateManagement.PrintTemplate.exportFilename'))
} catch {
} finally {
exportLoading.value = false
}
}
const handleSelectionChange = (rows: any[]) => {
selectedIds.value = rows?.map((row) => row.id).filter((id) => id !== undefined) ?? []
}
onMounted(() => {
getList()
})
</script>

@ -41,7 +41,7 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item :label="t('ProductionReport.Index.searchRemarkLabel')" prop="remark">
<el-form-item :label="t('ProductionReport.Index.searchRemarkLabel')" prop="remark" v-show="showAllFilters">
<el-input
v-model="queryParams.remark"
:placeholder="t('ProductionReport.Index.searchRemarkPlaceholder')"
@ -50,7 +50,7 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item :label="t('ProductionReport.Index.searchCreateTimeLabel')" prop="createTime">
<el-form-item :label="t('ProductionReport.Index.searchCreateTimeLabel')" prop="createTime" v-show="showAllFilters">
<el-date-picker
v-model="queryParams.createTime"
@change="handleQuery"
@ -62,6 +62,15 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') :
t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> {{ t('ProductionReport.Index.buttonSearch') }}
@ -170,6 +179,13 @@ const queryParams = reactive({
})
const queryFormRef = ref()
const exportLoading = ref(false)
const showAllFilters = ref(false) //
const filterCount = 4 //
/** 切换筛选框展开/折叠 */
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const activeStatusTab = ref('')

@ -51,7 +51,7 @@
/>
</el-form-item>
-->
<el-form-item :label="t('EquipmentManagement.RepairItems.projectContent')" prop="projectContent">
<el-form-item :label="t('EquipmentManagement.RepairItems.projectContent')" prop="projectContent" v-show="showAllFilters">
<el-input
v-model="queryParams.projectContent"
:placeholder="t('EquipmentManagement.RepairItems.placeholderProjectContent')"
@ -60,7 +60,7 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item :label="t('EquipmentManagement.RepairItems.createTime')" prop="createTime">
<el-form-item :label="t('EquipmentManagement.RepairItems.createTime')" prop="createTime" v-show="showAllFilters">
<el-date-picker
v-model="queryParams.createTime"
value-format="YYYY-MM-DD HH:mm:ss"
@ -71,6 +71,12 @@
class="!w-220px"
/>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<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>
@ -183,6 +189,11 @@ const queryFormRef = ref()
const tableRef = ref()
const selectedIds = ref<number[]>([])
const formRef = ref()
const showAllFilters = ref(false)
const filterCount = 5
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const deviceTypeOptions = ref<{ label: string; value: number }[]>([
{ label: t('EquipmentManagement.RepairItems.deviceTypeDevice'), value: 1 },

@ -46,7 +46,7 @@
/>
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-form-item label="创建时间" prop="createTime" v-show="showAllFilters">
<el-date-picker
v-model="queryParams.createTime"
value-format="YYYY-MM-DD HH:mm:ss"
@ -57,6 +57,12 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</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>
@ -144,6 +150,12 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const showAllFilters = ref(false)
const filterCount = 4
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
/** 查询列表 */
const getList = async () => {

@ -26,7 +26,7 @@
:start-placeholder="t('ProductionPlan.Task.searchOrderStartPlaceholder')"
:end-placeholder="t('ProductionPlan.Task.searchOrderEndPlaceholder')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-180px"
class="!w-280px"
/>
</el-form-item>
<el-form-item :label="t('ProductionPlan.Task.searchDeliveryLabel')" prop="deliveryDate">
@ -38,11 +38,11 @@
:start-placeholder="t('ProductionPlan.Task.searchDeliveryStartPlaceholder')"
:end-placeholder="t('ProductionPlan.Task.searchDeliveryEndPlaceholder')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-180px"
class="!w-280px"
/>
</el-form-item>
<el-form-item :label="t('ProductionPlan.Task.searchRemarkLabel')" prop="remark">
<el-form-item :label="t('ProductionPlan.Task.searchRemarkLabel')" prop="remark" v-show="showAllFilters">
<el-input
v-model="queryParams.remark"
:placeholder="t('ProductionPlan.Task.searchRemarkPlaceholder')"
@ -51,7 +51,7 @@
class="!w-180px"
/>
</el-form-item>
<el-form-item :label="t('ProductionPlan.Task.searchCreateTimeLabel')" prop="createTime">
<el-form-item :label="t('ProductionPlan.Task.searchCreateTimeLabel')" prop="createTime" v-show="showAllFilters">
<el-date-picker
v-model="queryParams.createTime"
@change="handleQuery"
@ -60,9 +60,18 @@
:start-placeholder="t('ProductionPlan.Task.searchCreateTimeStartPlaceholder')"
:end-placeholder="t('ProductionPlan.Task.searchCreateTimeEndPlaceholder')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-240px"
class="!w-280px"
/>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') :
t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> {{ t('ProductionPlan.Task.buttonSearchText') }}</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> {{ t('ProductionPlan.Task.buttonResetText') }}</el-button>
@ -221,6 +230,13 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const showAllFilters = ref(false) //
const filterCount = 4 //
/** 切换筛选框展开/折叠 */
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
/** 查询列表 */
const getList = async () => {
@ -326,3 +342,13 @@ const changeStatus = async (type:string, status: number, id: number) => {
let activeListName = 'taskDetail'
</script>
<style scoped>
.task-search-form {
display: flex;
flex-wrap: wrap;
}
.task-search-form :deep(.el-form-item) {
margin-right: 16px;
}
</style>

@ -216,7 +216,8 @@
</template>
<script setup lang="ts">
import { DICT_TYPE } from '@/utils/dict'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { useDictStoreWithOut } from '@/store/modules/dict'
import { TaskApi } from '@/api/mes/task'
import { ProductApi } from '@/api/erp/product/product'
import { DeviceLedgerApi } from '@/api/mes/deviceledger'
@ -228,8 +229,10 @@ import TaskSchedulePreviewDialog from './TaskSchedulePreviewDialog.vue'
defineOptions({ name: 'TaskScheduleDialog' })
const message = useMessage()
const { t } = useI18n() //
const { t } = useI18n()
const emit = defineEmits(['success'])
const dictStore = useDictStoreWithOut()
const dictReady = ref(false)
const dialogVisible = ref(false)
const taskLoading = ref(false)
@ -270,11 +273,10 @@ const scheduleRuleOptions = computed(() => [
{ label: t('ProductionPlan.TaskSummary.scheduleRuleCategory'), value: 3 },
{ label: t('ProductionPlan.TaskSummary.scheduleRuleDelivery'), value: 4 }
])
const capacityTypeOptions = computed(() => [
{ label: t('ProductionPlan.TaskSummary.capacityTypeRated'), value: 1 },
{ label: t('ProductionPlan.TaskSummary.capacityTypeDailyAvg'), value: 2 },
{ label: t('ProductionPlan.TaskSummary.capacityTypeDataCollection'), value: 3 }
])
const capacityTypeOptions = computed(() => {
if (!dictReady.value) return []
return getIntDictOptions('capacity_sources')
})
const searchForm = reactive({
inventoryTaskSchedule: false,
@ -774,6 +776,8 @@ const handleSubmit = async () => {
}
const open = async () => {
await dictStore.setDictMap()
dictReady.value = true
dialogVisible.value = true
await loadTaskList()
}

@ -1,21 +1,33 @@
<template>
<Dialog v-model="previewVisible" title="排产甘特图预览" width="100%" align-center>
<Dialog v-model="previewVisible" :title="t('GanttChart.GanttPanel.dialogTitle')" width="100%" align-center>
<div class="preview-options">
<el-form :inline="true">
<el-form-item label="领料人">
<el-select v-model="scheduleOptions.workerId" clearable filterable placeholder="请选择领料人" style="width: 200px">
<el-form-item :label="t('GanttChart.GanttPanel.workerLabel')">
<el-select v-model="scheduleOptions.workerId" clearable filterable :placeholder="t('GanttChart.GanttPanel.workerPlaceholder')" style="width: 200px">
<el-option v-for="item in workerList" :key="item.id" :label="item.nickname" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="是否计算损耗">
<el-form-item :label="t('GanttChart.GanttPanel.calcLossLabel')">
<el-switch v-model="scheduleOptions.isCalculateLoss" />
</el-form-item>
<el-form-item>
<el-button :type="ganttEditable ? 'primary' : 'default'" @click="toggleGanttEditable">
<Icon :icon="ganttEditable ? 'ep:unlock' : 'ep:lock'" class="mr-4px" />
{{ ganttEditable ? t('GanttChart.GanttPanel.unlockBtn') : t('GanttChart.GanttPanel.lockBtn') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button :disabled="!ganttEditable" @click="handleUndo">
<Icon icon="ep:refresh-left" class="mr-4px" />
{{ t('GanttChart.GanttPanel.undoBtn') }}
</el-button>
</el-form-item>
</el-form>
</div>
<ScheduleGanttPanelEditable :schedule-list="previewScheduleList" height="800px" />
<ScheduleGanttPanelEditable ref="ganttPanelRef" :schedule-list="previewScheduleList" :editable="ganttEditable" height="800px" />
<template #footer>
<el-button type="primary" :loading="previewSaveLoading" @click="handlePreviewSave"></el-button>
<el-button @click="previewVisible = false">关闭</el-button>
<el-button type="primary" :loading="previewSaveLoading" @click="handlePreviewSave">{{ t('GanttChart.GanttPanel.buttonSave') }}</el-button>
<el-button @click="previewVisible = false">{{ t('GanttChart.GanttPanel.buttonClose') }}</el-button>
</template>
</Dialog>
</template>
@ -25,9 +37,12 @@ import { PlanApi } from '@/api/mes/plan'
import * as UserApi from '@/api/system/user'
import ScheduleGanttPanelEditable from './ScheduleGanttPanelEditable.vue'
import dayjs from 'dayjs'
import { useI18n } from '@/hooks/web/useI18n'
defineOptions({ name: 'TaskSchedulePreviewDialog' })
const { t } = useI18n()
const props = defineProps<{
modelValue: boolean
scheduleList: any[]
@ -40,6 +55,16 @@ const emit = defineEmits<{
const message = useMessage()
const previewSaveLoading = ref(false)
const ganttEditable = ref(false)
const ganttPanelRef = ref<InstanceType<typeof ScheduleGanttPanelEditable>>()
const toggleGanttEditable = () => {
ganttEditable.value = !ganttEditable.value
}
const handleUndo = () => {
ganttPanelRef.value?.undo()
}
const workerList = ref<UserApi.UserVO[]>([])
const scheduleOptions = reactive({
@ -61,9 +86,12 @@ const previewVisible = computed({
})
watch(previewVisible, (visible) => {
if (visible && workerList.value.length === 0) {
if (visible) {
if (workerList.value.length === 0) {
loadWorkerList()
}
ganttEditable.value = false
}
})
const previewScheduleList = computed(() => (Array.isArray(props.scheduleList) ? props.scheduleList : []))
@ -100,14 +128,14 @@ const handlePreviewSave = async () => {
})
if (!createReqVOList.length) {
message.warning('暂无可保存的计划数据')
message.warning(t('GanttChart.GanttPanel.warningNoPlanData'))
return
}
previewSaveLoading.value = true
try {
await PlanApi.createBatch({ createReqVOList })
message.success('排产计划保存成功')
message.success(t('GanttChart.GanttPanel.saveSuccess'))
previewVisible.value = false
emit('saved')
} finally {

@ -23,18 +23,27 @@ v-model="queryParams.deliveryDate" value-format="YYYY-MM-DD HH:mm:ss" @change="h
:end-placeholder="t('ProductionPlan.TaskSummary.searchDeliveryEndPlaceholder')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-240px" />
</el-form-item>
<el-form-item :label="t('ProductionPlan.TaskSummary.searchRemarkLabel')" prop="remark">
<el-form-item :label="t('ProductionPlan.TaskSummary.searchRemarkLabel')" prop="remark" v-show="showAllFilters">
<el-input
v-model="queryParams.remark" :placeholder="t('ProductionPlan.TaskSummary.searchRemarkPlaceholder')"
clearable @keyup.enter="handleQuery" class="!w-240px" />
</el-form-item>
<el-form-item :label="t('ProductionPlan.TaskSummary.searchCreateTimeLabel')" prop="createTime">
<el-form-item :label="t('ProductionPlan.TaskSummary.searchCreateTimeLabel')" prop="createTime" v-show="showAllFilters">
<el-date-picker
v-model="queryParams.createTime" @change="handleQuery" value-format="YYYY-MM-DD HH:mm:ss"
type="daterange" :start-placeholder="t('ProductionPlan.TaskSummary.searchCreateTimeStartPlaceholder')"
:end-placeholder="t('ProductionPlan.TaskSummary.searchCreateTimeEndPlaceholder')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-240px" />
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') :
t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> {{ t('ProductionPlan.TaskSummary.buttonSearchText') }}
@ -171,6 +180,14 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const showAllFilters = ref(false) //
const filterCount = 4 //
/** 切换筛选框展开/折叠 */
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const { push } = useRouter()
const taskScheduleDialogRef = ref()
const deliveryDateFormatter = (_row: any, _column: any, value: any) => {

@ -33,7 +33,7 @@
:value="opt.value" />
</el-select>
</el-form-item>
<el-form-item :label="t('EquipmentManagement.WorkOrderManagement.jobResult')" prop="jobResult">
<el-form-item :label="t('EquipmentManagement.WorkOrderManagement.jobResult')" prop="jobResult" v-show="showAllFilters">
<el-select
v-model="queryParams.jobResult"
:placeholder="t('EquipmentManagement.WorkOrderManagement.placeholderJobResult')"
@ -43,6 +43,12 @@
<el-option v-for="opt in jobResultOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" />
@ -229,6 +235,11 @@ const queryParams = reactive({
})
const queryFormRef = ref()
const showAllFilters = ref(false)
const filterCount = 4
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const getList = async () => {
loading.value = true

@ -38,7 +38,7 @@ v-model="queryParams.ticket" placeholder="请输入工单" clearable @keyup.ente
<el-option v-for="item in orgTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item :label="t('QualityManagement.ZjTask.status')" prop="status">
<el-form-item :label="t('QualityManagement.ZjTask.status')" prop="status" v-show="showAllFilters">
<el-select
v-model="queryParams.status"
clearable
@ -50,7 +50,7 @@ v-for="opt in getStrDictOptions('job_status')" :key="String(opt.value)" :label="
:value="opt.value" />
</el-select>
</el-form-item>
<el-form-item :label="t('QualityManagement.ZjTask.result')" prop="result">
<el-form-item :label="t('QualityManagement.ZjTask.result')" prop="result" v-show="showAllFilters">
<el-input
v-model="queryParams.result"
:placeholder="t('QualityManagement.ZjTask.placeholderResult')"
@ -59,7 +59,7 @@ v-for="opt in getStrDictOptions('job_status')" :key="String(opt.value)" :label="
class="!w-240px"
/>
</el-form-item>
<el-form-item :label="t('QualityManagement.ZjTask.createTime')" prop="createTime">
<el-form-item :label="t('QualityManagement.ZjTask.createTime')" prop="createTime" v-show="showAllFilters">
<el-date-picker
v-model="queryParams.createTime"
value-format="YYYY-MM-DD HH:mm:ss"
@ -70,6 +70,12 @@ v-for="opt in getStrDictOptions('job_status')" :key="String(opt.value)" :label="
class="!w-260px"
/>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> {{ t('common.query') }}
@ -229,6 +235,12 @@ const orgTypeOptions = getStrDictOptions(DICT_TYPE.MES_ORG_TYPE)
const selectedIds = ref<number[]>([])
const cancelLoading = ref(false)
const showAllFilters = ref(false)
const filterCount = 6
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const getList = async () => {
loading.value = true

@ -29,7 +29,7 @@
@keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item :label="t('QualityManagement.ZjItem.createTime')" prop="createTime">
<el-form-item :label="t('QualityManagement.ZjItem.createTime')" prop="createTime" v-show="showAllFilters">
<el-date-picker
v-model="queryParams.createTime"
value-format="YYYY-MM-DD HH:mm:ss"
@ -38,6 +38,12 @@
:end-placeholder="t('QualityManagement.ZjItem.placeholderCreateTimeEnd')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-220px" />
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> {{ t('common.query') }}
@ -143,6 +149,12 @@ const queryParams = reactive({
const queryFormRef = ref() //
const exportLoading = ref(false) //
const selectedIds = ref<number[]>([])
const showAllFilters = ref(false)
const filterCount = 4
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
/** 查询列表 */
const getList = async () => {

@ -44,7 +44,7 @@ v-for="dict in getDictOptions('mes_zj_schema_sample_method')" :key="dict.value"
class="!w-240px"
/>
</el-form-item> -->
<el-form-item :label="t('QualityManagement.ZjSchema.remark')" prop="remark">
<el-form-item :label="t('QualityManagement.ZjSchema.remark')" prop="remark" v-show="showAllFilters">
<el-input
v-model="queryParams.remark"
:placeholder="t('QualityManagement.ZjSchema.placeholderRemark')"
@ -53,7 +53,7 @@ v-for="dict in getDictOptions('mes_zj_schema_sample_method')" :key="dict.value"
class="!w-240px"
/>
</el-form-item>
<el-form-item :label="t('QualityManagement.ZjSchema.item')" prop="item">
<el-form-item :label="t('QualityManagement.ZjSchema.item')" prop="item" v-show="showAllFilters">
<el-input
v-model="queryParams.item"
:placeholder="t('QualityManagement.ZjSchema.placeholderItem')"
@ -62,7 +62,7 @@ v-for="dict in getDictOptions('mes_zj_schema_sample_method')" :key="dict.value"
class="!w-240px"
/>
</el-form-item>
<el-form-item :label="t('QualityManagement.ZjSchema.createTime')" prop="createTime">
<el-form-item :label="t('QualityManagement.ZjSchema.createTime')" prop="createTime" v-show="showAllFilters">
<el-date-picker
v-model="queryParams.createTime"
value-format="YYYY-MM-DD HH:mm:ss"
@ -73,6 +73,12 @@ v-for="dict in getDictOptions('mes_zj_schema_sample_method')" :key="dict.value"
class="!w-220px"
/>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> {{ t('common.query') }}
@ -199,6 +205,12 @@ const queryParams = reactive({
const queryFormRef = ref() //
const exportLoading = ref(false) //
const selectedIds = ref<number[]>([])
const showAllFilters = ref(false)
const filterCount = 6
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const formatValDisplay = (val: any) => {
if (val === undefined || val === null || val === '') return ''

@ -35,7 +35,7 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item :label="t('QualityManagement.ZjType.createTime')" prop="createTime">
<el-form-item :label="t('QualityManagement.ZjType.createTime')" prop="createTime" v-show="showAllFilters">
<el-date-picker
v-model="queryParams.createTime"
value-format="YYYY-MM-DD HH:mm:ss"
@ -46,6 +46,12 @@
class="!w-220px"
/>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<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>
@ -152,6 +158,12 @@ const queryParams = reactive({
const queryFormRef = ref() //
const exportLoading = ref(false) //
const selectedIds = ref<number[]>([])
const showAllFilters = ref(false)
const filterCount = 4
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
/** 查询列表 */
const getList = async () => {

@ -17,6 +17,12 @@ v-model="queryParams.subjectName" :placeholder="t('MoldManagement.MoldInspection
v-model="queryParams.judgmentCriteria" :placeholder="t('MoldManagement.MoldInspectionItems.placeholderJudgmentCriteria')" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> {{ t('common.query') }}
@ -138,6 +144,11 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const showAllFilters = ref(false)
const filterCount = 3
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const getTagDict = (dictType: string, value: any) => {
if (!dictReady.value) return undefined

@ -30,6 +30,12 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<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>
@ -213,6 +219,12 @@ const list = ref<PlanMaintenanceVO[]>([])
const total = ref(0)
const exportLoading = ref(false)
const showAllFilters = ref(false)
const filterCount = 3
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const queryParams = reactive({
pageNo: 1,
pageSize: 10,

@ -28,7 +28,7 @@
/>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldRepair.moldName')" prop="moldName">
<el-form-item :label="t('MoldManagement.MoldRepair.moldName')" prop="moldName" v-show="showAllFilters">
<el-input
v-model="queryParams.moldName"
:placeholder="t('MoldManagement.MoldRepair.placeholderMoldName')"
@ -38,28 +38,28 @@
/>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldRepair.requireDate')" prop="requireDate">
<el-form-item :label="t('MoldManagement.MoldRepair.requireDate')" prop="requireDate" v-show="showAllFilters">
<el-date-picker
v-model="queryParams.requireDate" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
:start-placeholder="t('MoldManagement.MoldRepair.placeholderRequireDateStart')"
:end-placeholder="t('MoldManagement.MoldRepair.placeholderRequireDateEnd')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-240px" />
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldRepair.finishDate')" prop="finishDate">
<el-form-item :label="t('MoldManagement.MoldRepair.finishDate')" prop="finishDate" v-show="showAllFilters">
<el-date-picker
v-model="queryParams.finishDate" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
:start-placeholder="t('MoldManagement.MoldRepair.placeholderFinishDateStart')"
:end-placeholder="t('MoldManagement.MoldRepair.placeholderFinishDateEnd')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-240px" />
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldRepair.confirmDate')" prop="confirmDate">
<el-form-item :label="t('MoldManagement.MoldRepair.confirmDate')" prop="confirmDate" v-show="showAllFilters">
<el-date-picker
v-model="queryParams.confirmDate" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
:start-placeholder="t('MoldManagement.MoldRepair.placeholderConfirmDateStart')"
:end-placeholder="t('MoldManagement.MoldRepair.placeholderConfirmDateEnd')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-240px" />
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldRepair.repairUser')" prop="acceptedBy">
<el-form-item :label="t('MoldManagement.MoldRepair.repairUser')" prop="acceptedBy" v-show="showAllFilters">
<el-input
v-model="queryParams.acceptedBy"
:placeholder="t('MoldManagement.MoldRepair.placeholderRepairUser')"
@ -68,7 +68,7 @@
class="!w-240px" />
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldRepair.status')" prop="status">
<el-form-item :label="t('MoldManagement.MoldRepair.status')" prop="status" v-show="showAllFilters">
<el-select
v-model="queryParams.status"
:placeholder="t('MoldManagement.MoldRepair.placeholderStatus')"
@ -78,6 +78,12 @@
<el-option v-for="opt in statusOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> {{ t('MoldManagement.MoldRepair.search') }}
@ -196,6 +202,11 @@ const { t } = useI18n()
const loading = ref(true)
const list = ref<MoldRepairVO[]>([])
const total = ref(0)
const showAllFilters = ref(false)
const filterCount = 9
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const queryParams = reactive({
pageNo: 1,
pageSize: 10,

@ -28,7 +28,7 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldRepairItems.createTime')" prop="createTime">
<el-form-item :label="t('MoldManagement.MoldRepairItems.createTime')" prop="createTime" v-show="showAllFilters">
<el-date-picker
v-model="queryParams.createTime"
value-format="YYYY-MM-DD HH:mm:ss"
@ -39,6 +39,12 @@
class="!w-220px"
/>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> {{ t('MoldManagement.MoldRepairItems.search') }}</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> {{ t('MoldManagement.MoldRepairItems.reset') }}</el-button>
@ -130,6 +136,11 @@ const queryParams = reactive({
})
const queryFormRef = ref()
const showAllFilters = ref(false)
const filterCount = 4
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const tableRef = ref()
const selectedIds = ref<number[]>([])
const formRef = ref()

@ -38,6 +38,12 @@
<el-option v-for="item in planOptions" :key="String(item.id)" :label="item.planName" :value="String(item.id)" />
</el-select>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<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>
@ -167,6 +173,11 @@ const queryParams = reactive({
projectForm: [] as string[]
})
const queryFormRef = ref()
const showAllFilters = ref(false)
const filterCount = 3
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const parseIdsValue = (value: any): string[] => {
if (!value) return []

@ -30,7 +30,7 @@
<el-option 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="t('MoldManagement.MoldWorkOrderInquiry.jobResult')" prop="jobResult">
<el-form-item :label="t('MoldManagement.MoldWorkOrderInquiry.jobResult')" prop="jobResult" v-show="showAllFilters">
<el-select
v-model="queryParams.jobResult"
:placeholder="t('MoldManagement.MoldWorkOrderInquiry.placeholderJobResult')"
@ -40,6 +40,12 @@
<el-option v-for="opt in jobResultOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
{{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
</el-button>
</el-form-item>
<el-form-item>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> {{ t('MoldManagement.MoldWorkOrderInquiry.reset') }}
@ -142,6 +148,11 @@ const queryParams = reactive({
})
const queryFormRef = ref()
const showAllFilters = ref(false)
const filterCount = 4
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
}
const getList = async () => {
loading.value = true

Loading…
Cancel
Save