<template>
|
<div>
|
<!-- 手动创建任务弹窗 -->
|
<vol-box v-model="showManualCreate" :lazy="true" width="500px" :padding="15" title="手动创建任务">
|
<el-form :model="manualFormData" ref="form" label-width="100px">
|
<el-form-item label="任务类型" prop="taskType" required>
|
<el-select v-model="manualFormData.taskType" placeholder="请选择任务类型">
|
<el-option label="入库" value="入库"></el-option>
|
<el-option label="出库" value="出库"></el-option>
|
<el-option label="移库" value="移库"></el-option>
|
</el-select>
|
</el-form-item>
|
<el-form-item label="起点地址" prop="sourceAddress" required>
|
<el-input v-model="manualFormData.sourceAddress" placeholder="请输入起点地址"></el-input>
|
</el-form-item>
|
<el-form-item label="终点地址" prop="targetAddress" required>
|
<el-input v-model="manualFormData.targetAddress" placeholder="请输入终点地址"></el-input>
|
</el-form-item>
|
<el-form-item label="条码" prop="barcode" required>
|
<el-input v-model="manualFormData.barcode" placeholder="请输入条码"></el-input>
|
</el-form-item>
|
<el-form-item label="仓库ID" prop="warehouseId" required>
|
<el-input v-model="manualFormData.warehouseId" placeholder="请输入仓库ID"></el-input>
|
</el-form-item>
|
<el-form-item label="优先级">
|
<el-input v-model="manualFormData.grade" readonly></el-input>
|
</el-form-item>
|
</el-form>
|
<template #footer>
|
<el-button type="primary" size="small" @click="submitManualCreate">确定</el-button>
|
<el-button type="danger" size="small" @click="showManualCreate = false">关闭</el-button>
|
</template>
|
</vol-box>
|
|
<!-- 手动下发任务弹窗 -->
|
<vol-box v-model="showDispatch" :lazy="true" width="900px" :padding="15" title="手动下发任务到 WCS">
|
<div v-if="dispatchRows.length > 0" class="dispatch-info">
|
已选任务数: <span class="count">{{ dispatchRows.length }}</span> 个
|
</div>
|
|
<el-table :data="dispatchTableData" border style="width: 100%; margin-top: 10px" max-height="400">
|
<el-table-column prop="taskNum" label="任务号" width="120"></el-table-column>
|
<el-table-column prop="palletCode" label="托盘号" width="140">
|
<template v-slot="{ row }">
|
<el-input v-if="row && row.editable" v-model="row.palletCode" size="small" placeholder="请输入"></el-input>
|
<span v-else>{{ row ? row.palletCode : '' }}</span>
|
</template>
|
</el-table-column>
|
<el-table-column prop="sourceAddress" label="起点地址" width="160">
|
<template v-slot="{ row }">
|
<el-input v-if="row && row.editable" v-model="row.sourceAddress" size="small" placeholder="请输入"></el-input>
|
<span v-else>{{ row ? row.sourceAddress : '' }}</span>
|
</template>
|
</el-table-column>
|
<el-table-column prop="targetAddress" label="终点地址" width="160">
|
<template v-slot="{ row }">
|
<el-input v-if="row && row.editable" v-model="row.targetAddress" size="small" placeholder="请输入"></el-input>
|
<span v-else>{{ row ? row.targetAddress : '' }}</span>
|
</template>
|
</el-table-column>
|
<el-table-column prop="grade" label="优先级" width="100">
|
<template v-slot="{ row }">
|
<el-input-number v-if="row && row.editable" v-model="row.grade" :min="1" :max="99" size="small" style="width: 80px"></el-input-number>
|
<span v-else>{{ row ? row.grade : '' }}</span>
|
</template>
|
</el-table-column>
|
<el-table-column prop="statusName" label="状态" width="120">
|
<template v-slot="{ row }">
|
<span :class="{ 'status-error': row && !row.editable }">{{ row ? row.statusName : '' }}</span>
|
</template>
|
</el-table-column>
|
</el-table>
|
|
<div v-if="dispatchFailResults && dispatchFailResults.length > 0" class="fail-results">
|
<div class="fail-title">下发失败任务:</div>
|
<el-table :data="dispatchFailResults" border style="width: 100%; margin-top: 10px" max-height="200">
|
<el-table-column prop="taskNum" label="任务号" width="120"></el-table-column>
|
<el-table-column prop="errorMessage" label="失败原因"></el-table-column>
|
</el-table>
|
</div>
|
|
<template #footer>
|
<el-button type="primary" size="small" @click="submitDispatch" :loading="dispatchLoading">确认下发</el-button>
|
<el-button type="danger" size="small" @click="showDispatch = false">取消</el-button>
|
</template>
|
</vol-box>
|
</div>
|
</template>
|
|
<script>
|
import VolBox from "@/components/basic/VolBox.vue";
|
|
export default {
|
components: { VolBox },
|
emits: ["parentCall"],
|
data() {
|
return {
|
// 手动创建任务
|
showManualCreate: false,
|
manualFormData: {
|
taskType: "",
|
sourceAddress: "",
|
targetAddress: "",
|
barcode: "",
|
warehouseId: "",
|
grade: 1,
|
},
|
// 手动下发任务
|
showDispatch: false,
|
dispatchLoading: false,
|
dispatchRows: [],
|
dispatchTableData: [],
|
dispatchFailResults: [],
|
dispatchOriginalData: [],
|
};
|
},
|
methods: {
|
// 手动创建任务 - 打开
|
open() {
|
this.showManualCreate = true;
|
this.resetManualForm();
|
},
|
resetManualForm() {
|
this.manualFormData = {
|
taskType: "",
|
sourceAddress: "",
|
targetAddress: "",
|
barcode: "",
|
warehouseId: "",
|
grade: 1,
|
};
|
},
|
submitManualCreate() {
|
if (!this.manualFormData.taskType) return this.$message.error("请选择任务类型");
|
if (!this.manualFormData.sourceAddress) return this.$message.error("请输入起点地址");
|
if (!this.manualFormData.targetAddress) return this.$message.error("请输入终点地址");
|
if (!this.manualFormData.barcode) return this.$message.error("请输入条码");
|
if (!this.manualFormData.warehouseId) return this.$message.error("请输入仓库ID");
|
|
this.http
|
.post("/api/Task/CreateManualTask", this.manualFormData, "数据处理中...")
|
.then((res) => {
|
if (!res.status) return this.$message.error(res.message);
|
this.$message.success("任务创建成功");
|
this.showManualCreate = false;
|
this.$emit("parentCall", ($vue) => { $vue.refresh(); });
|
});
|
},
|
// 手动下发任务 - 打开
|
openDispatch(rows) {
|
console.log('openDispatch called with rows:', rows);
|
console.log('rows type:', typeof rows, Array.isArray(rows));
|
// 确保是数组
|
if (!rows) {
|
this.dispatchRows = [];
|
} else if (Array.isArray(rows)) {
|
this.dispatchRows = rows;
|
} else {
|
// 如果是单个对象,包装成数组
|
this.dispatchRows = [rows];
|
}
|
console.log('dispatchRows length:', this.dispatchRows.length);
|
this.dispatchFailResults = [];
|
// 先初始化数据,再显示弹窗
|
this.initDispatchTableData();
|
this.showDispatch = true;
|
},
|
initDispatchTableData() {
|
console.log('initDispatchTableData dispatchRows:', this.dispatchRows);
|
console.log('dispatchRows isArray:', Array.isArray(this.dispatchRows), 'length:', this.dispatchRows?.length);
|
|
// 确保 dispatchRows 是数组
|
if (!this.dispatchRows || !Array.isArray(this.dispatchRows)) {
|
console.warn('dispatchRows 不是有效数组,重置为空数组');
|
this.dispatchTableData = [];
|
return;
|
}
|
|
const statusNames = {
|
'inbound_200': '入库新单',
|
'outbound_100': '出库新单',
|
'relocation_300': '移库新单',
|
'outbound_110': '堆垛机出库执行中',
|
'outbound_115': '堆垛机出库完成',
|
'inbound_220': '输送线入库执行中',
|
'inbound_230': '堆垛机入库执行中',
|
'inbound_290': '入库任务完成',
|
'outbound_120': '输送线出库执行中',
|
'outbound_125': '输送线出库完成',
|
'outbound_200': '出库任务完成',
|
'relocation_310': '堆垛机移库执行中'
|
};
|
|
const result = [];
|
const original = [];
|
let filteredCount = 0; // 记录被过滤的任务数量
|
for (const row of this.dispatchRows) {
|
console.log('Processing row:', row);
|
// Handle possible field name differences (camelCase vs PascalCase)
|
const taskId = row.taskId ?? row.Id ?? row.id ?? 0;
|
const taskType = row.taskType ?? row.TaskType ?? row.task_type ?? 0;
|
const taskStatus = row.taskStatus ?? row.TaskStatus ?? row.task_status ?? 0;
|
console.log('taskId:', taskId, 'taskType:', taskType, 'taskStatus:', taskStatus);
|
const statusKey = this.getStatusKey(taskType, taskStatus);
|
console.log('statusKey:', statusKey);
|
const statusName = statusNames[statusKey] || `状态${taskStatus}`;
|
const editable = this.isEditable(taskType, taskStatus);
|
console.log('editable:', editable, '根据 taskType:', taskType, 'taskStatus:', taskStatus);
|
|
// 非新建状态的任务不显示在弹窗中
|
if (!editable) {
|
console.log(`任务${taskId}状态[${statusName}]不是新建,已过滤`);
|
filteredCount++;
|
continue;
|
}
|
|
const item = {
|
taskId: taskId,
|
taskNum: row.taskNum ?? row.TaskNum ?? 0,
|
sourceAddress: row.sourceAddress || row.SourceAddress || '',
|
targetAddress: row.targetAddress || row.TargetAddress || '',
|
grade: row.grade ?? row.Grade ?? 1,
|
statusName: statusName,
|
palletCode: row.palletCode || row.PalletCode || '',
|
editable: editable,
|
taskType: taskType,
|
taskStatus: taskStatus
|
};
|
result.push(item);
|
// 保存原始数据的副本
|
original.push({ ...item });
|
}
|
this.dispatchTableData = result;
|
this.dispatchOriginalData = original;
|
console.log('dispatchTableData result:', this.dispatchTableData);
|
console.log('dispatchOriginalData:', this.dispatchOriginalData);
|
|
// 如果有被过滤的任务,显示提示
|
if (filteredCount > 0) {
|
this.$message.warning(`选中的${this.dispatchRows.length}个任务中有${filteredCount}个非新建状态任务已过滤`);
|
}
|
},
|
getStatusKey(taskType, taskStatus) {
|
if (taskType === 200) return `inbound_${taskStatus}`;
|
if (taskType === 100) return `outbound_${taskStatus}`;
|
if (taskType === 300) return `relocation_${taskStatus}`;
|
return `other_${taskStatus}`;
|
},
|
isEditable(taskType, taskStatus) {
|
if (taskType === 200 && taskStatus === 200) return true;
|
if (taskType === 100 && taskStatus === 100) return true;
|
if (taskType === 300 && taskStatus === 300) return true;
|
return false;
|
},
|
submitDispatch() {
|
if (this.dispatchTableData.length === 0) return this.$message.error("请先选择任务");
|
|
const dispatchData = this.dispatchTableData.map(row => ({
|
taskId: row.taskId,
|
palletCode: row.palletCode,
|
sourceAddress: row.sourceAddress,
|
targetAddress: row.targetAddress,
|
grade: row.grade
|
}));
|
console.log('Dispatching data:', dispatchData);
|
|
this.dispatchLoading = true;
|
this.http
|
.post("/api/Task/DispatchTasksToWCS", dispatchData, "数据处理中...")
|
.then((res) => {
|
this.dispatchLoading = false;
|
if (!res.status) {
|
this.$message.error(res.message);
|
if (res.data && res.data.failResults) {
|
this.dispatchFailResults = res.data.failResults;
|
}
|
return;
|
}
|
|
if (res.data && res.data.failCount === 0) {
|
this.$message.success(res.message);
|
this.showDispatch = false;
|
this.$emit("parentCall", ($vue) => { $vue.refresh(); });
|
return;
|
}
|
|
if (res.data && res.data.failResults) {
|
this.dispatchFailResults = res.data.failResults;
|
}
|
|
if (res.data && res.data.failCount > 0 && res.data.successCount > 0) {
|
this.$message.warning(res.message);
|
} else {
|
this.$message.error(res.message);
|
}
|
})
|
.catch(() => {
|
this.dispatchLoading = false;
|
});
|
}
|
}
|
};
|
</script>
|
|
<style scoped>
|
.dispatch-info {
|
font-size: 14px;
|
color: #606266;
|
margin-bottom: 10px;
|
}
|
.dispatch-info .count {
|
color: #409eff;
|
font-weight: bold;
|
}
|
.status-error {
|
color: #f56c6c;
|
}
|
.fail-results {
|
margin-top: 15px;
|
padding: 10px;
|
background: #fef0f0;
|
border-radius: 4px;
|
}
|
.fail-title {
|
font-size: 14px;
|
color: #f56c6c;
|
margin-bottom: 5px;
|
}
|
</style>
|