feat:任务单排产-列表表头调整、排产弹框对接

pull/1/head
黄伟杰 1 month ago
parent 3a6a164960
commit e21b5e3246

@ -156,4 +156,8 @@ export const TaskApi = {
generatePlanByTaskDetail: async (params) => {
return await request.get({ url: `/mes/task/generate-plan/byTaskDetail`, params })
},
// 一键排产
oneClickSchedule: async (data: any) => {
return await request.post({ url: `/mes/task/one-click-schedule`, data })
},
}

@ -4,7 +4,7 @@
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
label-width="110px"
v-loading="formLoading"
>
<el-row :gutter="16">
@ -97,6 +97,30 @@
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="每日报工平均值" prop="dailyAverageValue">
<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 :span="12">
<el-form-item label="数据采集产能" prop="dataCollectionCapacity">
<el-input-number
v-model="formData.dataCollectionCapacity"
:min="0"
:precision="0"
controls-position="right"
class="!w-full"
placeholder="请输入数据采集产能"
/>
</el-form-item>
</el-col>
<!-- <el-col :span="12">
<el-form-item label="供应商" prop="supplier">
@ -435,7 +459,9 @@ const initFormData = () => ({
fileUrl: undefined,
qrcodeUrl: undefined,
sort: undefined,
dvId: undefined
dvId: undefined,
dailyAverageValue: undefined,
dataCollectionCapacity: undefined
})
const formData = ref({
@ -596,6 +622,8 @@ 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
@ -627,7 +655,9 @@ 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)
fileUrl: normalizeFileUrlAsJsonArrayString((formData.value as any).fileUrl),
dailyAverageValue: normalizeNumberish((formData.value as any).dailyAverageValue),
dataCollectionCapacity: normalizeNumberish((formData.value as any).dataCollectionCapacity)
} as unknown as DeviceLedgerVO
delete (data as any).deviceManagerIds
delete (data as any).componentIds

@ -10,9 +10,11 @@
<div class="device-ledger-right">
<ContentWrap>
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true"
<el-form
class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true"
label-width="60px">
<el-form-item :label="t('EquipmentManagement.EquipmentLedger.deviceCode')"
<el-form-item
:label="t('EquipmentManagement.EquipmentLedger.deviceCode')"
prop="deviceCode">
<el-input
v-model="queryParams.deviceCode"
@ -20,7 +22,8 @@
clearable @keyup.enter="handleQuery"
class="!w-240px"/>
</el-form-item>
<el-form-item :label="t('EquipmentManagement.EquipmentLedger.deviceName')"
<el-form-item
:label="t('EquipmentManagement.EquipmentLedger.deviceName')"
prop="deviceName">
<el-input
v-model="queryParams.deviceName"
@ -28,12 +31,15 @@
clearable @keyup.enter="handleQuery"
class="!w-240px"/>
</el-form-item>
<el-form-item :label="t('EquipmentManagement.EquipmentLedger.deviceStatus')"
<el-form-item
:label="t('EquipmentManagement.EquipmentLedger.deviceStatus')"
prop="deviceStatus">
<el-select v-model="queryParams.deviceStatus"
<el-select
v-model="queryParams.deviceStatus"
:placeholder="t('EquipmentManagement.EquipmentLedger.placeholderDeviceStatus')"
clearable class="!w-240px">
<el-option v-for="dict in tzStatusOptions" :key="dict.value" :label="dict.label"
<el-option
v-for="dict in tzStatusOptions" :key="dict.value" :label="dict.label"
:value="dict.value"/>
</el-select>
</el-form-item>
@ -46,12 +52,14 @@
<Icon icon="ep:refresh" class="mr-5px"/>
{{ t('common.reset') }}
</el-button>
<el-button type="primary" plain @click="openForm('create')"
<el-button
type="primary" plain @click="openForm('create')"
v-hasPermi="['mes:device-ledger:create']">
<Icon icon="ep:plus" class="mr-5px"/>
{{ t('action.add') }}
</el-button>
<el-button type="danger" plain @click="handleBatchDelete"
<el-button
type="danger" plain @click="handleBatchDelete"
v-hasPermi="['mes:device-ledger:delete']">
<Icon icon="ep:delete" class="mr-5px"/>
{{ t('EquipmentManagement.EquipmentLedger.batchDelete') }}
@ -82,17 +90,21 @@
: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('EquipmentManagement.EquipmentLedger.serialNumber')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.serialNumber')"
align="center" width="50" fixed="left">
<template #default="scope">
{{ (queryParams.pageNo - 1) * queryParams.pageSize + scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.deviceCode')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.deviceCode')"
align="center" prop="deviceCode" min-width="160px" sortable/>
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.deviceName')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.deviceName')"
align="center" prop="deviceName" min-width="140px" sortable/>
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.deviceType')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.deviceType')"
align="center" prop="deviceType" min-width="110px" sortable>
<template #default="scope">
<el-tag effect="light">
@ -100,7 +112,8 @@
</el-tag>
</template>
</el-table-column>
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.deviceStatus')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.deviceStatus')"
align="center" prop="deviceStatus" sortable>
<template #default="scope">
<el-switch
@ -111,7 +124,8 @@
/>
</template>
</el-table-column>
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.isSchedueld')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.isSchedueld')"
align="center" prop="isSchedueld" min-width="100px">
<template #default="scope">
<el-tag :type="Number(scope.row.isSchedueld ?? scope.row.isScheduled) === 1 ? 'success' : 'info'" effect="light">
@ -119,11 +133,14 @@
</el-tag>
</template>
</el-table-column>
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.ratedCapacity')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.ratedCapacity')"
align="center" prop="ratedCapacity" min-width="120px"/>
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.deviceSpec')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.deviceSpec')"
align="center" prop="deviceSpec"/>
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.deviceModel')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.deviceModel')"
align="center" prop="deviceModel"/>
<!-- <el-table-column :label="t('EquipmentManagement.EquipmentLedger.deviceBrand')" align="center" prop="deviceBrand" /> -->
<el-table-column
@ -136,19 +153,24 @@
width="120px" sortable/>
<!-- <el-table-column :label="t('EquipmentManagement.EquipmentLedger.supplier')" align="center" prop="supplier" width="110px" /> -->
<!-- <el-table-column :label="t('EquipmentManagement.EquipmentLedger.workshop')" align="center" prop="workshop" width="110px" /> -->
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.workshop')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.workshop')"
align="center" prop="workshopName" min-width="150px" sortable/>
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.deviceLocation')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.deviceLocation')"
align="center" prop="deviceLocation" min-width="150px"/>
<!-- <el-table-column :label="t('EquipmentManagement.EquipmentLedger.systemOrg')" align="center" prop="systemOrg" width="110px" /> -->
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.deviceManagerName')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.deviceManagerName')"
align="center" prop="deviceManagerName" width="150px" sortable/>
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.remark')" align="center"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.remark')" align="center"
prop="remark"/>
<!-- <el-table-column :label="t('EquipmentManagement.EquipmentLedger.creatorName')" align="center" prop="creatorName" width="150px" sortable />
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.createTime')" align="center" prop="createTime" :formatter="dateFormatter" width="180px" sortable /> -->
<!-- <el-table-column :label="t('EquipmentManagement.EquipmentLedger.updateTime')" align="center" prop="updateTime" :formatter="dateFormatter" width="180px" sortable /> -->
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.operate')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.operate')"
align="center" min-width="160px" fixed="right">
<template #default="scope">
<el-button link @click="handleDetail(scope.row.id)">
@ -355,7 +377,8 @@
<el-steps
v-else direction="vertical" :active="inspectionStepGroups.length"
class="device-ledger-history-steps">
<el-step v-for="group in inspectionStepGroups" :key="group.key"
<el-step
v-for="group in inspectionStepGroups" :key="group.key"
style="margin-top:8px">
<template #title>
<div class="device-ledger-history-title">
@ -367,7 +390,8 @@
</template>
<template #description>
<div class="device-ledger-history-items">
<div v-for="item in group.items" :key="item.key"
<div
v-for="item in group.items" :key="item.key"
class="device-ledger-history-item">
<div class="device-ledger-history-item-head">
<el-tag :type="getResultTagType(item.result)">{{
@ -434,7 +458,8 @@
</el-step>
</el-steps>
</el-tab-pane>
<el-tab-pane :label="t('EquipmentManagement.EquipmentLedger.maintainHistory')"
<el-tab-pane
:label="t('EquipmentManagement.EquipmentLedger.maintainHistory')"
name="maintain">
<div style="margin-bottom: 16px;">
<el-date-picker
@ -469,7 +494,8 @@
</template>
<template #description>
<div class="device-ledger-history-items">
<div v-for="item in group.items" :key="item.key"
<div
v-for="item in group.items" :key="item.key"
class="device-ledger-history-item">
<div class="device-ledger-history-item-head">
<el-tag :type="getResultTagType(item.result)">{{
@ -536,7 +562,8 @@
</el-step>
</el-steps>
</el-tab-pane>
<el-tab-pane :label="t('EquipmentManagement.EquipmentLedger.repairHistory')"
<el-tab-pane
:label="t('EquipmentManagement.EquipmentLedger.repairHistory')"
name="repair">
<div style="margin-bottom: 16px;">
<el-date-picker
@ -611,7 +638,8 @@
String(formatHistoryTime(row.finishDate)).split(' ')[0]
}}</span>
</div>
<div v-if="row.malfunctionImages?.length"
<div
v-if="row.malfunctionImages?.length"
class="device-ledger-history-item-images">
<el-image
v-for="img in row.malfunctionImages" :key="img" :src="img"
@ -628,7 +656,8 @@
</el-collapse-item>
</el-collapse>
</el-tab-pane>
<el-tab-pane :label="t('EquipmentManagement.EquipmentLedger.criticalComponent')"
<el-tab-pane
:label="t('EquipmentManagement.EquipmentLedger.criticalComponent')"
name="criticalComponent">
<div class="device-ledger-tab-toolbar">
<el-button
@ -642,15 +671,20 @@
<el-table
v-loading="loading" :data="detailData?.componentList" :stripe="true"
:show-overflow-tooltip="true">
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.componentCode')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.componentCode')"
align="center" prop="code" min-width="140" sortable/>
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.componentName')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.componentName')"
align="center" prop="name" min-width="140" sortable/>
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.componentDesc')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.componentDesc')"
align="center" prop="description" min-width="180"/>
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.remark')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.remark')"
align="center" prop="remark" min-width="180"/>
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.createTime')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.createTime')"
align="center" prop="createTime" :formatter="dateFormatter"
width="180" sortable/>
</el-table>
@ -664,31 +698,42 @@
{{ t('action.export') }}
</el-button>
</div>
<el-table v-loading="loading" :data="detailData?.beijianList" :stripe="true"
<el-table
v-loading="loading" :data="detailData?.beijianList" :stripe="true"
:show-overflow-tooltip="true">
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.spareCode')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.spareCode')"
align="center" prop="barCode" sortable/>
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.spareName')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.spareName')"
align="left" prop="name" width="220px" sortable/>
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.category')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.category')"
align="center" prop="categoryName" sortable/>
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.unit')" align="center"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.unit')" align="center"
prop="unitName" sortable/>
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.createTime')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.createTime')"
align="center" prop="createTime" :formatter="dateFormatter"
width="180px" sortable/>
</el-table>
</el-tab-pane>
<el-tab-pane label="模具" name="mold">
<el-table v-loading="loading" :data="detailData?.moldList" :stripe="true"
<el-table
v-loading="loading" :data="detailData?.moldList" :stripe="true"
:show-overflow-tooltip="true">
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.moldCode')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.moldCode')"
align="center" prop="code" min-width="140" sortable/>
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.moldName')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.moldName')"
align="center" prop="name" min-width="140" sortable/>
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.moldRemark')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.moldRemark')"
align="center" prop="remark" min-width="180"/>
<el-table-column :label="t('EquipmentManagement.EquipmentLedger.createTime')"
<el-table-column
:label="t('EquipmentManagement.EquipmentLedger.createTime')"
align="center" prop="createTime" :formatter="dateFormatter"
width="180" sortable/>
</el-table>

@ -54,7 +54,8 @@
<el-form-item :label="t('EnergyManagement.EnergyDevice.dialogRulesLabel')" prop="operationRulesVOList">
<div class="w-full flex flex-col gap-8px">
<div v-for="(rule, index) in formData.operationRulesVOList" :key="index"
<div
v-for="(rule, index) in formData.operationRulesVOList" :key="index"
class="w-full flex items-center gap-8px">
<el-tree-select
v-model="rule.pointValue"

@ -6,12 +6,12 @@
<el-table-column :label="t('ProductionPlan.TaskSummary.detailTableTaskCodeColumn')" align="center" prop="taskCode" sortable />
<el-table-column :label="t('ProductionPlan.TaskSummary.detailTableProductCodeColumn')" align="center" prop="barCode" sortable />
<el-table-column :label="t('ProductionPlan.TaskSummary.detailTableProductNameColumn')" align="center" prop="productName" sortable/>
<el-table-column :label="t('ProductionPlan.TaskSummary.detailTableTotalNumberColumn')" align="center" prop="totalNumber" />
<el-table-column :label="t('ProductionPlan.TaskSummary.detailTableTotalNumberColumn')" align="center" prop="number" />
<el-table-column :label="t('ProductionPlan.TaskSummary.detailTablePlanNumberColumn')" align="center" prop="planNumber" />
<el-table-column :label="t('ProductionPlan.TaskSummary.detailTableUnplanNumberColumn')" align="center">
<template #default="scope">
<span class="el-alert--warning" style="color: #e66126">
{{scope.row.totalNumber-scope.row.planNumber>0 ? scope.row.totalNumber-scope.row.planNumber : 0}}
{{scope.row.number-scope.row.planNumber>0 ? scope.row.number-scope.row.planNumber : 0}}
</span>
</template>
</el-table-column>
@ -21,7 +21,7 @@
link
type="info"
@click="openItemNeed(scope.row.productName, scope.row.productId,
scope.row.totalNumber-scope.row.planNumber)"
scope.row.number-scope.row.planNumber)"
v-hasPermi="['mes:task:query']"
>
{{ t('ProductionPlan.TaskSummary.detailActionMaterialLabel') }}
@ -38,7 +38,7 @@
link
type="success"
@click="addPlanForm(scope.row.taskId, scope.row.productId,
scope.row.totalNumber - scope.row.planNumber,scope.row.taskDetailIds)"
scope.row.number - scope.row.planNumber,scope.row.taskDetailIds)"
v-hasPermi="['mes:task:plan']"
>
{{ t('ProductionPlan.TaskSummary.detailActionCreatePlanLabel') }}
@ -91,7 +91,8 @@ watch(
const getList = async () => {
loading.value = true
try {
list.value = await TaskApi.getTaskDetailSummaryListByTaskId(queryParams.taskId)
const data = await TaskApi.getTaskDetailPage(queryParams)
list.value = data.list
} finally {
loading.value = false
}

@ -0,0 +1,493 @@
<template>
<Dialog v-model="dialogVisible" title="排产" width="80%" destroy-on-close>
<div class="flex items-center gap-20px mb-16px">
<div class="flex items-center gap-8px">
<span class="text-red-500">*</span>
<span>排产规则</span>
<el-select v-model="searchForm.sortRule" class="!w-220px" clearable>
<el-option v-for="item in scheduleRuleOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
<div class="flex items-center gap-8px">
<span class="text-red-500">*</span>
<span>产能来源</span>
<el-select v-model="searchForm.capacityType" class="!w-220px">
<el-option v-for="item in capacityTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
</div>
<div class="border border-solid border-gray-200 rounded p-16px mt-16px">
<el-form :inline="true" :model="searchForm" label-width="90px" class="-mb-8px">
<el-form-item label="任务单编码">
<el-input v-model="searchForm.code" placeholder="请输入" clearable class="!w-200px" />
</el-form-item>
<el-form-item label="下达日期">
<el-date-picker
v-model="searchForm.orderDate"
type="daterange"
value-format="YYYY-MM-DD HH:mm:ss"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-260px"
/>
</el-form-item>
<el-form-item label="交货日期">
<el-date-picker
v-model="searchForm.deliveryDate"
type="daterange"
value-format="YYYY-MM-DD HH:mm:ss"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-260px"
/>
</el-form-item>
<el-form-item label="备注">
<el-input v-model="searchForm.remark" placeholder="请输入" clearable class="!w-220px" />
</el-form-item>
<el-form-item label="任务类型">
<el-checkbox v-model="searchForm.inventoryTaskSchedule"></el-checkbox>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">
<Icon icon="ep:search" class="mr-5px" /> 查询
</el-button>
<el-button @click="handleReset">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
</el-button>
</el-form-item>
</el-form>
<el-table
ref="taskTableRef"
v-loading="taskLoading"
:data="taskList"
border
:stripe="true"
:show-overflow-tooltip="true"
highlight-current-row
class="mt-12px"
row-key="id"
@current-change="handleCurrentTaskChange"
@select="handleTaskSelect"
@select-all="handleTaskSelectAll"
>
<el-table-column type="selection" width="55" :reserve-selection="true" align="center" />
<el-table-column :label="t('ProductionPlan.TaskSummary.tableTaskCodeColumn')" align="center" prop="code" width="200px" sortable />
<el-table-column :label="t('ProductionPlan.TaskSummary.tableOrderDateColumn')" align="center" prop="orderDate" :formatter="dateFormatter2" sortable />
<el-table-column :label="t('ProductionPlan.TaskSummary.tableDeliveryDateColumn')" align="center" prop="deliveryDate" :formatter="dateFormatter2" sortable />
<el-table-column :label="t('ProductionPlan.Task.tableTaskTypeColumn')" align="center" prop="taskType" sortable>
<template #default="scope">
<dict-tag :type="DICT_TYPE.MES_TASK_TYPE" :value="scope.row.taskType" />
</template>
</el-table-column>
<el-table-column :label="t('ProductionPlan.TaskSummary.tableStatusColumn')" align="center" prop="status" sortable>
<template #default="scope">
<dict-tag :type="DICT_TYPE.MES_TASK_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column :label="t('ProductionPlan.TaskSummary.tableScheduleCompletedColumn')" align="center">
<template #default="scope">
<el-tag :type="scope.row.isScheduled ? 'success' : 'info'">{{ scope.row.isScheduled ? '是' : '否' }}</el-tag>
</template>
</el-table-column>
<el-table-column :label="t('ProductionPlan.TaskSummary.tableRemarkColumn')" align="center" prop="remark" />
<el-table-column :label="t('ProductionPlan.TaskSummary.tableOperateColumn')" align="center" min-width="100px">
<template #default="scope">
<el-button link type="info" @click="openTaskItemNeed(scope.row)">
{{ t('ProductionPlan.TaskSummary.actionMaterialLabel') }}
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="loadTaskList"
/>
<div class="text-20px font-bold mt-20px mb-12px">{{ t('ProductionPlan.TaskSummary.detailTabSummaryLabel') }}</div>
<el-table
ref="detailTableRef"
v-loading="detailLoading"
:data="detailList"
border
:stripe="true"
:show-overflow-tooltip="true"
row-key="id"
@select="handleDetailSelect"
@select-all="handleDetailSelectAll"
>
<el-table-column type="selection" width="55" :reserve-selection="true" align="center" />
<el-table-column :label="t('ProductionPlan.TaskSummary.detailTableTaskCodeColumn')" align="center" prop="taskCode" sortable />
<el-table-column :label="t('ProductionPlan.TaskSummary.detailTableProductCodeColumn')" align="center" prop="barCode" sortable />
<el-table-column :label="t('ProductionPlan.TaskSummary.detailTableProductNameColumn')" align="center" prop="productName" sortable />
<el-table-column :label="t('ProductionPlan.TaskSummary.detailTableTotalNumberColumn')" align="center" prop="number" />
<el-table-column :label="t('ProductionPlan.TaskSummary.detailTablePlanNumberColumn')" align="center" prop="planNumber" />
<el-table-column :label="t('ProductionPlan.TaskSummary.detailTableUnplanNumberColumn')" align="center">
<template #default="scope">
<span class="el-alert--warning" style="color: #e66126">
{{ scope.row.number - scope.row.planNumber > 0 ? scope.row.number - scope.row.planNumber : 0 }}
</span>
</template>
</el-table-column>
<el-table-column :label="t('ProductionPlan.TaskSummary.detailTableOperateColumn')" align="center" width="100px">
<template #default="scope">
<el-button link type="info" @click="openProductItemNeed(scope.row)">
{{ t('ProductionPlan.TaskSummary.detailActionMaterialLabel') }}
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<template #footer>
<el-button type="primary" :loading="submitLoading" @click="handleSubmit"></el-button>
<el-button @click="dialogVisible = false">取消</el-button>
</template>
</Dialog>
<ItemNeedIndex ref="itemNeedRef" />
</template>
<script setup lang="ts">
import { DICT_TYPE } from '@/utils/dict'
import { TaskApi } from '@/api/mes/task'
import ItemNeedIndex from '@/views/mes/bom/ItemNeedIndex.vue'
import { dateFormatter2 } from '@/utils/formatTime'
defineOptions({ name: 'TaskScheduleDialog' })
const message = useMessage()
const { t } = useI18n() //
const emit = defineEmits(['success'])
const dialogVisible = ref(false)
const taskLoading = ref(false)
const detailLoading = ref(false)
const submitLoading = ref(false)
const itemNeedRef = ref()
const taskTableRef = ref()
const detailTableRef = ref()
const scheduleRuleOptions = [
{ label: '订单优先级', value: 2 },
{ label: '订单交期优先', value: 4 }
]
const capacityTypeOptions = [
{ label: '额定产能', value: 1 },
{ label: '每日报工平均值', value: 2 },
{ label: '数据采集产能', value: 3 }
]
const searchForm = reactive({
inventoryTaskSchedule: false,
sortRule: 2 as number | undefined,
capacityType: 1 as number | undefined,
code: '',
orderDate: [] as string[],
deliveryDate: [] as string[],
remark: ''
})
const total = ref(0)
const queryParams = reactive({
pageNo: 1,
pageSize: 10
})
const taskList = ref<any[]>([])
const detailList = ref<any[]>([])
const currentTask = ref<any>()
const allDetailsMap = ref<Record<number, any[]>>({}) // store details per taskId
const loadTaskList = async () => {
taskLoading.value = true
try {
const params: any = {
isScheduled: 0,
pageNo: queryParams.pageNo,
pageSize: queryParams.pageSize,
code: searchForm.code || undefined,
orderDate: searchForm.orderDate,
deliveryDate: searchForm.deliveryDate,
remark: searchForm.remark || undefined,
taskType: searchForm.inventoryTaskSchedule ? '库存任务' : undefined
}
const data = await TaskApi.getPlanTaskPage(params)
taskList.value = data?.list ?? []
total.value = data?.total ?? 0
if (taskList.value.length) {
await handleCurrentTaskChange(taskList.value[0])
} else {
currentTask.value = undefined
detailList.value = []
}
} finally {
taskLoading.value = false
}
}
const loadDetailList = async (taskId?: number) => {
if (!taskId) {
detailList.value = []
return
}
// Use cached list if exists
if (allDetailsMap.value[taskId]) {
detailList.value = allDetailsMap.value[taskId]
return
}
detailLoading.value = true
try {
const data = await TaskApi.getTaskDetailPage({
pageNo: 1,
pageSize: 10,
taskId
})
const list = (data?.list ?? []).map((item: any) => ({
...item,
_parentTaskOrderPriority: currentTask.value?.orderPriority,
_parentTaskDeliveryDate: currentTask.value?.deliveryDate
}))
// Cache the loaded list
allDetailsMap.value[taskId] = list
detailList.value = list
} finally {
detailLoading.value = false
}
}
const handleCurrentTaskChange = async (row: any) => {
if (!row) return
currentTask.value = row
await loadDetailList(row?.id)
// Re-apply selection state for children when view changes
nextTick(() => {
const parentIsSelected = taskTableRef.value?.getSelectionRows()?.some((t: any) => t.id === row.id)
if (parentIsSelected) {
detailList.value.forEach(child => {
detailTableRef.value?.toggleRowSelection(child, true)
})
}
})
}
const handleTaskSelect = async (selection: any[], row: any) => {
const isSelected = selection.some((item) => item.id === row.id)
// load detail list to cache if not exists
if (!allDetailsMap.value[row.id]) {
currentTask.value = row
await loadDetailList(row.id)
}
const childList = allDetailsMap.value[row.id] || []
if (isSelected && childList.length === 0) {
message.warning(`任务单 ${row.code} 无任务明细数据,无法勾选`)
taskTableRef.value?.toggleRowSelection(row, false)
return
}
if (childList.length) {
childList.forEach((child) => {
// Find the row in detailList if currently displayed, or just use the child object
// `toggleRowSelection` needs the exact object reference that is in `data`
const rowInView = detailList.value.find(d => d.id === child.id)
if (rowInView) {
detailTableRef.value?.toggleRowSelection(rowInView, isSelected)
} else {
// If not in view but we want to select it, we can push it to selection or wait until viewed
// In Element Plus, toggleRowSelection works best with displayed data.
// We'll rely on handleCurrentTaskChange to re-apply selection if needed when viewed.
}
})
}
}
const handleTaskSelectAll = async (selection: any[]) => {
const isAllSelected = selection.length > 0
if (isAllSelected) {
const validRows = []
let hasEmptyChild = false
for (const row of selection) {
if (!allDetailsMap.value[row.id]) {
currentTask.value = row
await loadDetailList(row.id)
}
const childList = allDetailsMap.value[row.id] || []
if (childList.length === 0) {
hasEmptyChild = true
taskTableRef.value?.toggleRowSelection(row, false)
} else {
validRows.push(row)
childList.forEach((child) => {
const rowInView = detailList.value.find(d => d.id === child.id)
if (rowInView) {
detailTableRef.value?.toggleRowSelection(rowInView, true)
}
})
}
}
if (hasEmptyChild) {
message.warning('部分任务单无明细数据,已自动取消勾选')
}
} else {
detailTableRef.value?.clearSelection()
}
}
const handleDetailSelect = (selection: any[], row: any) => {
const taskId = row.taskId
const childList = allDetailsMap.value[taskId] || []
// check if all children for this task are selected
const allChildrenSelected = childList.every(child => selection.some(sel => sel.id === child.id))
const noChildrenSelected = childList.every(child => !selection.some(sel => sel.id === child.id))
const parentTask = taskList.value.find(task => task.id === taskId)
if (parentTask) {
if (allChildrenSelected) {
taskTableRef.value?.toggleRowSelection(parentTask, true)
} else if (noChildrenSelected) {
taskTableRef.value?.toggleRowSelection(parentTask, false)
}
}
}
const handleDetailSelectAll = (selection: any[]) => {
if (!currentTask.value?.id) return
const taskId = currentTask.value.id
const childList = allDetailsMap.value[taskId] || []
const parentTask = taskList.value.find(task => task.id === taskId)
if (parentTask) {
// if any child in current view is selected, consider it an intent to select parent (if not all were selected)
// selection will contain all selected items across pages, so we need to filter for current view's task
const currentViewSelection = selection.filter(sel => sel.taskId === taskId)
if (currentViewSelection.length === childList.length && childList.length > 0) {
taskTableRef.value?.toggleRowSelection(parentTask, true)
} else if (currentViewSelection.length === 0) {
taskTableRef.value?.toggleRowSelection(parentTask, false)
}
}
}
const handleSearch = async () => {
queryParams.pageNo = 1
await loadTaskList()
}
const handleReset = async () => {
searchForm.inventoryTaskSchedule = false
searchForm.sortRule = undefined
searchForm.capacityType = 1
searchForm.code = ''
searchForm.orderDate = []
searchForm.deliveryDate = []
searchForm.remark = ''
queryParams.pageNo = 1
await loadTaskList()
}
const openTaskItemNeed = (row: any) => {
if (!row?.id) return
itemNeedRef.value.open('task', '任务单-' + (row?.code ?? ''), row.id)
}
const openTaskPlan = (row: any) => {
if (!row?.id) return
window.open(`/mes/plan?taskId=${row.id}`, '_self')
}
const openProductItemNeed = (row: any) => {
if (!row?.productId) return
const number = row.number - row.planNumber > 0 ? row.number - row.planNumber : 0
itemNeedRef.value.open('product', row.productName, row.productId, number)
}
const openDetailPlan = (row: any) => {
if (!row?.taskId || !row?.productId) return
window.open(`/mes/plan?taskId=${row.taskId}&productId=${row.productId}`, '_self')
}
const openDetailCreatePlan = (_row: any) => {
message.info('请在任务单汇总明细列表中使用“新增计划”功能')
}
const handleSubmit = async () => {
if (searchForm.sortRule === undefined) {
message.warning('请选择排产规则')
return
}
if (searchForm.capacityType === undefined) {
message.warning('请选择产能来源')
return
}
const selectedRows = detailTableRef.value?.getSelectionRows() || []
if (selectedRows.length === 0) {
message.warning('至少选一个任务单汇总明细的数据')
return
}
submitLoading.value = true
try {
const createReqVO = selectedRows.map((row: any) => {
const planNumber = row.number - row.planNumber > 0 ? row.number - row.planNumber : 0
return {
// PlanForm fields
productId: row.productId,
taskId: row.taskId,
taskDetailId: row.id,
planNumber: planNumber,
finishNumber: 0,
isPreProduction: 0,
isCode: true,
planStartTime: new Date().getTime(),
planEndTime: new Date().getTime(),
reyaNumber: planNumber,
// Image fields
orderPriority: row.orderPriority || row._parentTaskOrderPriority || 0,
workOrderCode: row.taskCode,
deliveryDate: row._parentTaskDeliveryDate || new Date().getTime(), // Fallback
orderDetailDeliveryDate: row.deliveryDate || row.finishDate || row._parentTaskDeliveryDate || new Date().getTime(), // Fallback
orderDetailId: row.id
}
})
await TaskApi.oneClickSchedule({
createReqVO,
sortRule: searchForm.sortRule,
capacityType: searchForm.capacityType
})
message.success('排产已提交')
dialogVisible.value = false
emit('success')
} finally {
submitLoading.value = false
}
}
const open = async () => {
dialogVisible.value = true
await loadTaskList()
}
defineExpose({ open })
</script>

@ -1,30 +1,36 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="auto"
<el-form
class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="auto"
label-position="left">
<el-form-item :label="t('ProductionPlan.TaskSummary.searchCodeLabel')" prop="code">
<el-input v-model="queryParams.code" :placeholder="t('ProductionPlan.TaskSummary.searchCodePlaceholder')"
<el-input
v-model="queryParams.code" :placeholder="t('ProductionPlan.TaskSummary.searchCodePlaceholder')"
clearable @keyup.enter="handleQuery" class="!w-240px" />
</el-form-item>
<el-form-item :label="t('ProductionPlan.TaskSummary.searchOrderLabel')" prop="orderDate">
<el-date-picker v-model="queryParams.orderDate" @change="handleQuery" value-format="YYYY-MM-DD HH:mm:ss"
<el-date-picker
v-model="queryParams.orderDate" @change="handleQuery" value-format="YYYY-MM-DD HH:mm:ss"
type="daterange" :start-placeholder="t('ProductionPlan.TaskSummary.searchOrderStartPlaceholder')"
:end-placeholder="t('ProductionPlan.TaskSummary.searchOrderEndPlaceholder')"
: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.searchDeliveryLabel')" prop="deliveryDate">
<el-date-picker v-model="queryParams.deliveryDate" value-format="YYYY-MM-DD HH:mm:ss" @change="handleQuery"
<el-date-picker
v-model="queryParams.deliveryDate" value-format="YYYY-MM-DD HH:mm:ss" @change="handleQuery"
type="daterange" :start-placeholder="t('ProductionPlan.TaskSummary.searchDeliveryStartPlaceholder')"
: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-input v-model="queryParams.remark" :placeholder="t('ProductionPlan.TaskSummary.searchRemarkPlaceholder')"
<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-date-picker v-model="queryParams.createTime" @change="handleQuery" value-format="YYYY-MM-DD HH:mm:ss"
<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" />
@ -40,6 +46,9 @@
<el-button type="success" plain @click="handleExport" :loading="exportLoading" v-hasPermi="['mes:task:export']">
<Icon icon="ep:download" class="mr-5px" /> {{ t('ProductionPlan.TaskSummary.buttonExportText') }}
</el-button>
<el-button type="primary" @click="openScheduleDialog">
<Icon icon="ep:plus" class="mr-5px" /> 排产
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
@ -54,13 +63,17 @@
<el-tab-pane :label="t('ProductionPlan.TaskSummary.tabFinishedLabel')" name="5" />
<el-tab-pane :label="t('ProductionPlan.TaskSummary.tabStoredLabel')" name="6" />
</el-tabs>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" highlight-current-row
<el-table
v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" highlight-current-row
@current-change="handleCurrentChange">
<el-table-column :label="t('ProductionPlan.TaskSummary.tableTaskCodeColumn')" align="center" prop="code"
<el-table-column
:label="t('ProductionPlan.TaskSummary.tableTaskCodeColumn')" align="center" prop="code"
width="200px" sortable />
<el-table-column :label="t('ProductionPlan.TaskSummary.tableOrderDateColumn')" align="center" prop="orderDate"
<el-table-column
:label="t('ProductionPlan.TaskSummary.tableOrderDateColumn')" align="center" prop="orderDate"
:formatter="dateFormatter2" sortable />
<el-table-column :label="t('ProductionPlan.TaskSummary.tableDeliveryDateColumn')" align="center"
<el-table-column
:label="t('ProductionPlan.TaskSummary.tableDeliveryDateColumn')" align="center"
prop="deliveryDate" :formatter="dateFormatter2" sortable />
<el-table-column :label="t('ProductionPlan.TaskSummary.tableStatusColumn')" align="center" prop="status" sortable>
<template #default="scope">
@ -76,7 +89,8 @@
<el-table-column :label="t('ProductionPlan.TaskSummary.tableOperateColumn')" align="center" min-width="200px">
<template #default="scope">
<el-button link type="info" @click="openItemNeed(scope.row.code, scope.row.id)"
<el-button
link type="info" @click="openItemNeed(scope.row.code, scope.row.id)"
v-hasPermi="['mes:task:query']">
{{ t('ProductionPlan.TaskSummary.actionMaterialLabel') }}
</el-button>
@ -90,7 +104,8 @@
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
<Pagination
:total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
@pagination="getList" />
</ContentWrap>
@ -106,6 +121,7 @@
<ItemNeedIndex ref="formRef" @success="getList" />
<!-- 排程弹窗 -->
<TaskPlanForm ref="taskPlanFormRef" @success="getList" />
<TaskScheduleDialog ref="taskScheduleDialogRef" @success="getList" />
</template>
<script setup lang="ts">
@ -114,9 +130,9 @@ import { dateFormatter, dateFormatter2 } from '@/utils/formatTime'
import download from '@/utils/download'
import { TaskApi, TaskVO } from '@/api/mes/task'
import TaskDetailList from './components/TaskDetailList.vue'
import PlanForm from "@/views/mes/plan/PlanForm.vue";
import ItemNeedIndex from "@/views/mes/bom/ItemNeedIndex.vue";
import TaskPlanForm from "@/views/mes/tasksummary/components/TaskPlan.vue";
import TaskScheduleDialog from '@/views/mes/tasksummary/components/TaskScheduleDialog.vue'
/** 生产任务单 列表 */
defineOptions({ name: 'TaskSummary' })
@ -141,6 +157,7 @@ const queryParams = reactive({
const queryFormRef = ref() //
const exportLoading = ref(false) //
const { push } = useRouter()
const taskScheduleDialogRef = ref()
/** 查询列表 */
const getList = async () => {
loading.value = true
@ -180,6 +197,10 @@ const handleExport = async () => {
}
}
const openScheduleDialog = () => {
taskScheduleDialogRef.value?.open()
}
/** 选中行操作 */
const currentRow = ref({}) //
const handleCurrentChange = (row) => {

Loading…
Cancel
Save