新增工单管理界面

This commit is contained in:
tao
2025-12-23 13:37:48 +08:00
parent 7025a5304f
commit 9e45b78f31
3 changed files with 513 additions and 0 deletions

View File

@@ -0,0 +1,376 @@
<script setup lang="ts">
import { ref, reactive, nextTick } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import Header from '@/components/Header/index.vue';
import { message } from 'ant-design-vue';
import { useAuthStore, usePwoStore } from '@/store';
import type { WorkOrderInfo } from './model';
import { listLotTraceOrder } from '@/api/pwoManage';
import { storeToRefs } from 'pinia';
const route = useRoute();
const router = useRouter();
const authStore = useAuthStore();
const pwoStore = usePwoStore();
const workOrderInfo = reactive<WorkOrderInfo>({
code: '',
batchNo: '',
status: '',
tarMaterialName: '',
tarMaterialCode: '',
planQty: undefined,
});
const processInfo: any = storeToRefs(pwoStore).currentJob;
const loadingPwoInfo = ref(false);
const fetchLotTraceOrder = async () => {
if (!workOrderInfo.code) return;
try {
loadingPwoInfo.value = true;
const res = await listLotTraceOrder({
code: workOrderInfo.code,
});
if (res.total as number <= 0) {
throw new Error('未查询到工单信息,请检查工单编码')
};
workOrderInfo.status = res.rows[0].status;
workOrderInfo.batchNo = res.rows[0].batchNo;
workOrderInfo.tarMaterialName = res.rows[0].tarMaterialName;
workOrderInfo.tarMaterialCode = res.rows[0].tarMaterialCode;
workOrderInfo.planQty = res.rows[0].planQty;
router.replace({ query: { ...route.query, traceOrderCode: workOrderInfo.code, t: Date.now() } });
} catch (error: any) {
message.error(error.message || '获取工单信息失败');
} finally {
loadingPwoInfo.value = false;
}
};
// 孙组件
const infeedRef = ref<any>(null);
const collapsed = ref(false);
const toggleCollapse = async () => {
collapsed.value = !collapsed.value;
await nextTick();
infeedRef.value?.renderTableHeight();
}
const handlePwoManage = () => {
router.push({ name: 'PwoManage' })
}
const handleWaferAppearance = () => {
message.info('点击了 Wafer');
};
const handleDieAppearance = () => {
message.info('点击了 Die');
};
const openHoldModal = ref(false);
const holdForm = reactive({
planCompleteDate: '',
});
const handleHold = () => {
openHoldModal.value = true;
};
const handleCloseHold = () => {
holdForm.planCompleteDate = '';
openHoldModal.value = false;
};
const handleSubmitHold = () => {
message.success('Hold 住!')
holdForm.planCompleteDate = '';
openHoldModal.value = false;
};
const handleInfeed = () => {
router.push({ name: 'Infeed' });
};
const handleOutfeed = () => {
router.push({ name: 'Outfeed' });
};
const handleCopy = async (text: string | number | undefined) => {
if (!text) return;
await navigator.clipboard.writeText(String(text));
message.success(`已复制: ${ text }`);
}
</script>
<template>
<div class="page-container">
<Header title="过站工控机" showHome showBack showLogout>
<template #right-opts>
<a-button @click="toggleCollapse">{{ collapsed ? '展开' : '折叠' }}</a-button>
</template>
</Header>
<div class="content-wrapper">
<!-- Top Section -->
<div class="top-section">
<a-row :gutter="16" class="full-height-row">
<!-- Work Order Info -->
<a-col :span="13">
<a-spin :spinning="loadingPwoInfo">
<a-card title="工单信息" class="info-card" :bordered="false">
<a-form :model="workOrderInfo" :colon="false" v-show="!collapsed">
<a-row :gutter="36">
<a-col :span="12">
<a-form-item label="工单批次">
<a-input v-model:value="workOrderInfo.batchNo" readonly>
<template #suffix>
<a-button @click="handleCopy(workOrderInfo.batchNo)">
<template #icon><i-lucide-copy /></template>
</a-button>
</template>
</a-input>
</a-form-item>
<a-form-item label="工单状态">
<a-input v-model:value="workOrderInfo.status" readonly>
<template #suffix>
<a-button @click="handleCopy(workOrderInfo.status)">
<template #icon><i-lucide-copy /></template>
</a-button>
</template>
</a-input>
</a-form-item>
<a-form-item label="总计数量">
<a-input v-model:value="workOrderInfo.planQty" readonly>
<template #suffix>
<a-button @click="handleCopy(workOrderInfo.planQty)">
<template #icon><i-lucide-copy /></template>
</a-button>
</template>
</a-input>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="产品编码">
<a-input v-model:value="workOrderInfo.tarMaterialCode" readonly>
<template #suffix>
<a-button @click="handleCopy(workOrderInfo.tarMaterialCode)">
<template #icon><i-lucide-copy /></template>
</a-button>
</template>
</a-input>
</a-form-item>
<a-form-item label="产品名称">
<a-input v-model:value="workOrderInfo.tarMaterialName" readonly>
<template #suffix>
<a-button @click="handleCopy(workOrderInfo.tarMaterialName)">
<template #icon><i-lucide-copy /></template>
</a-button>
</template>
</a-input>
</a-form-item>
<a-form-item label="产品规格">
<a-input v-model:value="workOrderInfo.planQty" readonly>
<template #suffix>
<a-button @click="handleCopy(workOrderInfo.planQty)">
<template #icon><i-lucide-copy /></template>
</a-button>
</template>
</a-input>
</a-form-item>
</a-col>
</a-row>
</a-form>
<template #extra>
<a-input-search v-model:value="workOrderInfo.code" @search="fetchLotTraceOrder" placeholder="输入工单编码" enter-button />
</template>
</a-card>
</a-spin>
</a-col>
<!-- Process Info -->
<a-col :span="8">
<a-card title="工序信息" class="info-card" :bordered="false">
<a-form :model="processInfo" :colon="false" :label-col="{ span: 4 }" :wrapper-col="{ span: 20, offset: 2 }"
v-show="!collapsed">
<a-form-item label="工序名称">
<a-input v-model:value="processInfo.operationTitle" readonly>
<template #suffix>
<a-tag color="#f50" v-if="processInfo.status">{{ processInfo.status }}</a-tag>
<a-button @click="handleCopy(processInfo.operationTitle)">
<template #icon><i-lucide-copy /></template>
</a-button>
</template>
</a-input>
</a-form-item>
<a-form-item label="作业编码">
<a-input v-model:value="processInfo.code" readonly>
<template #suffix>
<a-button @click="handleCopy(processInfo.code)">
<template #icon><i-lucide-copy /></template>
</a-button>
</template>
</a-input>
</a-form-item>
<a-form-item label="设备名称">
<a-input v-model:value="processInfo.tarMaterialName" readonly>
<template #suffix>
<a-button @click="handleCopy(processInfo.tarMaterialName)">
<template #icon><i-lucide-copy /></template>
</a-button>
</template>
</a-input>
</a-form-item>
</a-form>
</a-card>
</a-col>
<!-- Action Buttons -->
<a-col :span="3" class="action-buttons-col">
<div class="action-buttons" v-show="!collapsed">
<a-button class="action-btn green-btn" @click="handlePwoManage">工单管理</a-button>
<a-button class="action-btn orange-btn" @click="handleWaferAppearance">Wafer 清单</a-button>
<a-button class="action-btn blue-btn" @click="handleDieAppearance">Die 清单</a-button>
<a-space>
<a-button class="action-btn red-btn" @click="handleHold">Hold</a-button>
<a-button class="action-btn orange-btn" @click="handleInfeed">进站</a-button>
<a-button class="action-btn blue-btn" @click="handleOutfeed">出站</a-button>
</a-space>
</div>
<a-card title="操作" class="info-card" :bordered="false" v-show="collapsed">
<template #extra>
<a-dropdown>
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="handlePwoManage">工单管理</a-menu-item>
<a-menu-item key="2" @click="handleWaferAppearance">Wafer 清单</a-menu-item>
<a-menu-item key="3" @click="handleDieAppearance">Die 清单</a-menu-item>
<a-menu-item key="4" @click="handleHold">Hold</a-menu-item>
<a-menu-item key="5" @click="handleInfeed">进站</a-menu-item>
<a-menu-item key="6" @click="handleOutfeed">出站</a-menu-item>
</a-menu>
</template>
<a-button>
更多
<i-lucide-chevron-down />
</a-button>
</a-dropdown>
</template>
</a-card>
</a-col>
</a-row>
</div>
<!-- Bottom Section -->
<main class="bottom-section">
<router-view v-slot="{ Component }">
<component :is="Component" ref="infeedRef" />
</router-view>
</main>
</div>
<!-- Hold Modal -->
<a-modal
v-model:open="openHoldModal"
title="Hold 操作"
@cancel="handleCloseHold"
@ok="handleSubmitHold"
>
<a-form :model="holdForm" :colon="false" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
<a-form-item label="工单编码">
<a-input v-model:value="workOrderInfo.code" readonly />
</a-form-item>
<a-form-item label="目标产品编码">
<a-input v-model:value="workOrderInfo.tarMaterialCode" readonly />
</a-form-item>
<a-form-item label="目标产品名称">
<a-input v-model:value="workOrderInfo.tarMaterialName" readonly />
</a-form-item>
<a-form-item label="工序名称">
<a-input v-model:value="processInfo.operationTitle" readonly />
</a-form-item>
<a-form-item label="产品规格">
<a-input v-model:value="processInfo.code" readonly />
</a-form-item>
<a-form-item label="计划完成日期">
<a-input v-model:value="holdForm.planCompleteDate" />
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<style scoped lang="scss">
.page-container {
height: 100vh;
background-color: #f0f2f5;
display: flex;
flex-direction: column;
overflow: hidden;
}
.content-wrapper {
padding: 16px;
flex: 1;
display: flex;
flex-direction: column;
gap: 16px;
min-height: 0;
}
.top-section {
background: transparent;
}
:deep(.ant-spin-nested-loading),
:deep(.ant-spin-container) {
height: 100%;
}
.info-card {
height: 100%;
border-radius: 8px;
:deep(.ant-card-head) {
min-height: 48px;
padding: 0 16px;
border-bottom: none;
font-size: 20px;
}
:deep(.ant-card-body) {
padding: 1px 16px;
}
:deep(.ant-form-item) {
margin-bottom: 12px;
}
}
.action-buttons-col {
display: flex;
flex-direction: column;
}
.action-buttons {
display: flex;
flex-direction: column;
gap: 6px;
height: 100%;
.action-btn {
height: 48px;
font-size: 16px;
color: #fff;
border: none;
border-radius: 4px;
}
}
.bottom-section {
background: #fff;
padding: 16px;
border-radius: 8px;
flex: 1;
min-height: 0;
overflow: auto;
}
</style>