Compare commits

...

7 Commits

Author SHA1 Message Date
tao
82210f6c26 进站/出站后刷新工序列表 2026-01-12 17:29:19 +08:00
tao
863fcf7b61 目录结构变更 2026-01-12 17:28:57 +08:00
tao
9a1fec8cbc 优化系统全局状态管理结构 2026-01-12 17:17:58 +08:00
tao
84797e76cd 修改工控机名称 2026-01-12 17:15:11 +08:00
tao
70021db98f 新建复制粘贴方法 2026-01-12 17:14:39 +08:00
tao
0361053f67 封装 Hold 按钮/模态框组件 2026-01-12 17:14:02 +08:00
tao
85828dd1a6 优化 Header 组件样式 2026-01-12 17:13:43 +08:00
38 changed files with 591 additions and 581 deletions

3
components.d.ts vendored
View File

@@ -40,8 +40,11 @@ declare module 'vue' {
ATypographyText: typeof import('ant-design-vue/es')['TypographyText'] ATypographyText: typeof import('ant-design-vue/es')['TypographyText']
DictTag: typeof import('./src/components/common/DictTag/index.vue')['default'] DictTag: typeof import('./src/components/common/DictTag/index.vue')['default']
Header: typeof import('./src/components/common/Header/index.vue')['default'] Header: typeof import('./src/components/common/Header/index.vue')['default']
HoldTraceOrder: typeof import('./src/components/traceOrderManage/holdTraceOrder.vue')['default']
ILucideBuilding: typeof import('~icons/lucide/building')['default'] ILucideBuilding: typeof import('~icons/lucide/building')['default']
ILucideChevronDown: typeof import('~icons/lucide/chevron-down')['default'] ILucideChevronDown: typeof import('~icons/lucide/chevron-down')['default']
ILucideChevronLeft: typeof import('~icons/lucide/chevron-left')['default']
ILucideChevronUp: typeof import('~icons/lucide/chevron-up')['default']
ILucideCopy: typeof import('~icons/lucide/copy')['default'] ILucideCopy: typeof import('~icons/lucide/copy')['default']
ILucideCpu: typeof import('~icons/lucide/cpu')['default'] ILucideCpu: typeof import('~icons/lucide/cpu')['default']
ILucideLoader: typeof import('~icons/lucide/loader')['default'] ILucideLoader: typeof import('~icons/lucide/loader')['default']

View File

@@ -49,7 +49,7 @@ defineProps({
}, },
height: { height: {
type: String, type: String,
default: '6vh', default: '',
}, },
zIndex: { zIndex: {
type: Number, type: Number,
@@ -100,7 +100,7 @@ const backToHome = () => {
<style scoped lang="scss"> <style scoped lang="scss">
.header-container { .header-container {
width: 100%; width: 100%;
padding: 0 1rem; padding: 6px 1rem;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 10px;

View File

@@ -0,0 +1,82 @@
<template>
<a-button class="action-btn" @click="handleHold">Hold</a-button>
<!-- Hold Modal -->
<a-modal v-model:open="openHoldModal" title="Hold 操作" @cancel="handleCloseHold" @ok="handleSubmitHold">
<a-form :colon="false" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
<a-form-item label="工单编码">
<a-input v-model:value="traceOrderStore.traceOrderInfo.code" readonly />
</a-form-item>
<a-form-item label="目标产品编码">
<a-input v-model:value="traceOrderStore.traceOrderInfo.tarMaterialCode" readonly />
</a-form-item>
<a-form-item label="目标产品名称">
<a-input v-model:value="traceOrderStore.traceOrderInfo.tarMaterialName" readonly />
</a-form-item>
<a-form-item label="发起工序名称">
<a-input v-model:value="traceOrderStore.stationInfo.operationTitle" readonly />
</a-form-item>
<a-form-item label="产品规格">
<a-input readonly />
</a-form-item>
<a-form-item label="计划完成日期">
<a-date-picker v-model:value="planFinishDate" placeholder="选择计划完成日期" valueFormat="YYYY-MM-DD HH:mm:ss" show-time
style="width: 100%" />
</a-form-item>
</a-form>
</a-modal>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useDialog } from '@/utils/useDialog';
import { useTraceOrderStore } from '@/store';
import { message } from 'ant-design-vue';
import { addQualityAbnormalContact } from '@/api/traceOrderManage';
const traceOrderStore = useTraceOrderStore();
// useDialog 管理弹窗状态
const { visible: openHoldModal, show, hide } = useDialog();
const planFinishDate = ref('');
const handleHold = () => {
if (!traceOrderStore.currentTraceOrderCode) {
message.error('请先选择工单!');
return;
}
show();
};
const handleCloseHold = () => {
planFinishDate.value = '';
hide();
};
const handleSubmitHold = async () => {
const tmpPlanFinishDate = planFinishDate.value;
// 修改随工单状态
try {
message.success('Hold 成功!')
planFinishDate.value = '';
openHoldModal.value = false;
} catch (error: any) {
message.error(error.message || 'Hold 失败');
return;
}
// 添加修改记录
try {
addQualityAbnormalContact({
materialCode: traceOrderStore.traceOrderInfo.tarMaterialCode,
abnormalOperation: traceOrderStore.stationInfo.operationCode,
planFinishDate: tmpPlanFinishDate,
status: "Hold",
})
} catch (error: any) {
message.error(error.message || '添加记录异常');
return;
}
};
</script>

View File

@@ -15,72 +15,72 @@ const routes = [
component: () => import("@/views/login.vue"), component: () => import("@/views/login.vue"),
}, },
{ {
path: "/pwoManage", path: "/traceOrderManage",
name: "PwoManage", name: "TraceOrderManage",
component: () => import("@/views/pwoManage/layout.vue"), component: () => import("@/views/traceOrderManage/layout.vue"),
redirect: { name: "PwoManageIndex" }, redirect: { name: "TraceOrderManageIndex" },
children: [ children: [
{ {
path: "", path: "",
name: "PwoManageIndex", name: "TraceOrderManageIndex",
component: () => import("@/views/pwoManage/index.vue"), component: () => import("@/views/traceOrderManage/index.vue"),
}, },
{ {
path: "infeed", path: "infeed",
name: "Infeed", name: "Infeed",
component: () => import("@/views/pwoManage/infeed/layout.vue"), component: () => import("@/views/traceOrderManage/infeed/layout.vue"),
redirect: { name: "PrimaryMaterial" }, redirect: { name: "PrimaryMaterial" },
children: [ children: [
{ {
path: "primaryMaterial", path: "primaryMaterial",
name: "PrimaryMaterial", name: "PrimaryMaterial",
component: () => component: () =>
import("@/views/pwoManage/infeed/primaryMaterial/index.vue"), import("@/views/traceOrderManage/infeed/primaryMaterial/index.vue"),
}, },
{ {
path: "rawMaterial", path: "rawMaterial",
name: "RawMaterial", name: "RawMaterial",
component: () => component: () =>
import("@/views/pwoManage/infeed/rawMaterial/index.vue"), import("@/views/traceOrderManage/infeed/rawMaterial/index.vue"),
}, },
{ {
path: "mask", path: "mask",
name: "Mask", name: "Mask",
component: () => import("@/views/pwoManage/infeed/mask/index.vue"), component: () => import("@/views/traceOrderManage/infeed/mask/index.vue"),
}, },
{ {
path: "equipment", path: "equipment",
name: "Equipment", name: "Equipment",
component: () => component: () =>
import("@/views/pwoManage/infeed/equipment/index.vue"), import("@/views/traceOrderManage/infeed/equipment/index.vue"),
}, },
], ],
}, },
{ {
path: "outfeed", path: "outfeed",
name: "Outfeed", name: "Outfeed",
component: () => import("@/views/pwoManage/outfeed/layout.vue"), component: () => import("@/views/traceOrderManage/outfeed/layout.vue"),
redirect: { name: "JobReport" }, redirect: { name: "JobReport" },
children: [ children: [
{ {
path: "jobReport", path: "jobReport",
name: "JobReport", name: "JobReport",
component: () => component: () =>
import("@/views/pwoManage/outfeed/jobReport/index.vue"), import("@/views/traceOrderManage/outfeed/jobReport/index.vue"),
}, },
{ {
path: "parameterConfiguration", path: "parameterConfiguration",
name: "ParameterConfiguration", name: "ParameterConfiguration",
component: () => component: () =>
import( import(
"@/views/pwoManage/outfeed/parameterConfiguration/index.vue" "@/views/traceOrderManage/outfeed/parameterConfiguration/index.vue"
), ),
}, },
{ {
path: "processGuidance", path: "processGuidance",
name: "ProcessGuidance", name: "ProcessGuidance",
component: () => component: () =>
import("@/views/pwoManage/outfeed/processGuidance/index.vue"), import("@/views/traceOrderManage/outfeed/processGuidance/index.vue"),
}, },
], ],
}, },

View File

@@ -1,5 +1,7 @@
export * from './auth'; // 系统管理
export * from './user'; export * from './system/auth';
export * from './pwo'; export * from './system/dict';
export * from './job'; export * from './system/user';
export * from './dict';
// 工单管理
export * from './traceOrderManage/traceOrder';

View File

@@ -1,36 +0,0 @@
import { defineStore } from "pinia";
import { ref, reactive } from "vue";
import { getStation } from "@/api/pwoManage/station";
export const useJobStore = defineStore("job", () => {
const jobInfo = reactive<any>({});
const loadingJobInfo = ref(false);
function setInfo(job: any) {
Object.assign(jobInfo, job);
}
function resetInfo() {
Object.assign(jobInfo, {});
}
async function refresh() {
loadingJobInfo.value = true;
try {
const { data } = await getStation(jobInfo.id);
Object.assign(jobInfo, data);
} catch (error: any) {
console.log(error.message);
} finally {
loadingJobInfo.value = false;
}
}
return {
jobInfo,
loadingJobInfo,
setInfo,
resetInfo,
refresh,
};
});

View File

@@ -1,31 +0,0 @@
import { defineStore } from "pinia";
import { reactive } from "vue";
export interface PwoInfo {
code: string;
id: string | number;
orderType: string;
[key: string]: any;
}
export const usePwoStore = defineStore("pwo", () => {
const pwoInfo = reactive<PwoInfo>({
code: "",
id: "",
orderType: "",
});
function setInfo(info: PwoInfo) {
Object.assign(pwoInfo, info);
}
function resetInfo() {
Object.assign(pwoInfo, {});
}
return {
pwoInfo,
setInfo,
resetInfo,
};
});

View File

@@ -0,0 +1,147 @@
import { defineStore } from "pinia";
import { ref } from "vue";
import { message } from "ant-design-vue";
import { debounce } from 'lodash';
import { listStation, getStation } from "@/api/traceOrderManage/station";
import {
listLotTraceOrder,
getLotTraceOrder,
} from "@/api/traceOrderManage";
export const useTraceOrderStore = defineStore("traceOrder", () => {
/* ========= 核心业务状态 ========= */
const currentTraceOrderId = ref<string | number>('');
const currentTraceOrderCode = ref<string>('');
const currentStationId = ref<string | number>('');
const currentStationCode = ref<string>('');
const traceOrderOptions = ref<any[]>([]);
const traceOrderInfo = ref<any>({});
const stationInfo = ref<any>({});
const stationList = ref<any[]>([]);
/* ========= actions ========= */
// 加载工单列表
const fetchTraceOrderOption = debounce(async (code: string) => {
if (!code) return;
try {
const { rows } = await listLotTraceOrder({
code,
pageSize: 10,
pageNum: 1,
});
traceOrderOptions.value = rows.map((item) => {
return {
id: item.id,
label: item.code,
value: item.code,
};
});
} catch (error: any) {
message.error(error.message || "获取工单列表失败");
}
}, 500);
// 选择工单
async function selectTraceOrder(value: string, option: any) {
currentTraceOrderId.value = option.id;
currentTraceOrderCode.value = value;
try {
loadingTraceOrderInfo.value = true;
if (!option.id) throw new Error();
const { data } = await getLotTraceOrder(option.id);
traceOrderInfo.value = data;
await fetchStationList();
} catch (error: any) {
message.error(error.message || "获取工单信息失败");
} finally {
loadingTraceOrderInfo.value = false;
}
}
// 获取工单信息
const loadingTraceOrderInfo = ref(false);
async function fetchTraceOrderInfo() {
if (!currentTraceOrderId.value) return;
try {
loadingTraceOrderInfo.value = true;
const { data } = await getLotTraceOrder(currentTraceOrderId.value);
traceOrderInfo.value = data;
fetchStationList();
} catch (error: any) {
message.error(error.message || '刷新工单信息失败');
} finally {
loadingTraceOrderInfo.value = false;
}
}
// 获取站点列表
const loadingStations = ref(false);
async function fetchStationList() {
if (!currentTraceOrderCode.value) return;
try {
loadingStations.value = true;
const res = await listStation({ traceOrderCode: currentTraceOrderCode.value });
stationList.value = (res.rows || []).map((item: any, idx: number) => {
return {
key: String(item.id ?? idx),
index: item.seqNo ?? idx + 1,
...item,
};
});
} catch (error: any) {
message.error(error?.msg || error?.message || "查询站点失败");
} finally {
loadingStations.value = false;
}
};
// 获取站点信息
const loadingStationInfo = ref(false);
async function fetchStationInfo() {
if (!currentTraceOrderId.value) return;
try {
loadingStationInfo.value = true;
const { data } = await getStation(currentStationId.value);
stationInfo.value = data;
} catch (error: any) {
console.log(error.message || '获取站点信息失败');
} finally {
loadingStationInfo.value = false;
}
}
// 选择站点
async function selectStation(stationId: string) {
currentStationId.value = stationId;
stationInfo.value = stationList.value.find((s: any) => s.id === stationId) ?? {};
}
async function refreshAll() {
await Promise.all([fetchTraceOrderInfo(), fetchStationList()]);
}
return {
currentTraceOrderId,
currentTraceOrderCode,
currentStationId,
currentStationCode,
traceOrderOptions,
traceOrderInfo,
stationInfo,
stationList,
loadingTraceOrderInfo,
loadingStations,
loadingStationInfo,
selectTraceOrder,
selectStation,
refreshAll,
fetchTraceOrderOption,
fetchTraceOrderInfo,
fetchStationList,
fetchStationInfo,
};
});

View File

@@ -0,0 +1,8 @@
import { message } from "ant-design-vue";
// 复制到剪贴板
export const handleCopy = async (text: string | number | undefined) => {
if (!text) return;
await navigator.clipboard.writeText(String(text));
message.success(`已复制: ${text}`);
};

View File

@@ -1,9 +1,9 @@
<template> <template>
<div class="ipc-dashboard"> <div class="ipc-dashboard">
<Header title="过站工控机" showLogout /> <Header title="MES 过站平台" showLogout />
<div class="menu-grid"> <div class="menu-grid">
<a-card class="menu-card" shadow="hover" @click="handleJumpTo('PwoManage')"> <a-card class="menu-card" shadow="hover" @click="handleJumpTo('TraceOrderManage')">
<div class="icon-wrap"> <div class="icon-wrap">
<i-lucide-building /> <i-lucide-building />
</div> </div>

View File

@@ -1,414 +0,0 @@
<script setup lang="ts">
import { ref, reactive, nextTick, onUnmounted, getCurrentInstance } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { message } from 'ant-design-vue';
import { debounce } from 'lodash';
import { usePwoStore, useJobStore } from '@/store';
import { listLotTraceOrder, getLotTraceOrder, addQualityAbnormalContact } from '@/api/pwoManage';
import type { LotTraceOrderData } from '@/api/pwoManage/model';
const { proxy } = getCurrentInstance() as any
const { mes_station_status, lot_trace_order_status } = proxy.useDict("mes_station_status", "lot_trace_order_status")
const route = useRoute();
const router = useRouter();
const pwoStore = usePwoStore();
const jobStore = useJobStore();
const workOrderInfo = reactive<LotTraceOrderData>({});
const processInfo = jobStore.jobInfo;
// 孙组件
const infeedRef = ref<any>(null);
const collapsed = ref(false);
const toggleCollapse = async () => {
collapsed.value = !collapsed.value;
await nextTick();
infeedRef.value?.renderTableHeight();
}
const redirectTo = (routeName: string) => {
router.push({ name: routeName });
if (routeName === 'PwoManage') {
handleRefresh();
}
}
const openHoldModal = ref(false);
const planFinishDate = ref('');
const handleHold = () => {
if (!workOrderInfo.code) {
message.error('请先选择工单!');
return;
}
openHoldModal.value = true;
};
const handleCloseHold = () => {
planFinishDate.value = '';
openHoldModal.value = false;
};
const handleSubmitHold = async () => {
const tmpPlanFinishDate = planFinishDate.value;
// 修改随工单状态
try {
message.success('Hold 成功!')
planFinishDate.value = '';
openHoldModal.value = false;
} catch (error: any) {
message.error(error.message || 'Hold 失败');
return;
}
// 添加修改记录
try {
addQualityAbnormalContact({
materialCode: workOrderInfo.tarMaterialCode,
abnormalOperation: processInfo.operationCode,
planFinishDate: tmpPlanFinishDate,
status: "Hold",
})
} catch (error: any) {
message.error(error.message || '添加记录异常');
return;
}
};
const handleCopy = async (text: string | number | undefined) => {
if (!text) return;
await navigator.clipboard.writeText(String(text));
message.success(`已复制: ${ text }`);
}
const pwoCodeOptions = ref<LotTraceOrderData[]>([])
const handleSearch = debounce(async (code: string) => {
if (!code) return;
try {
const { rows } = await listLotTraceOrder({
code,
pageSize: 10,
pageNum: 1,
});
pwoCodeOptions.value = rows.map(item => {
return {
id: item.id,
label: item.code,
value: item.code,
}
});
} catch (error: any) {
message.error(error.message || '获取工单信息失败');
}
}, 500)
const loadingPwoInfo = ref(false);
const handleChange = async (value: string, option: LotTraceOrderData) => {
workOrderInfo.code = value;
try {
loadingPwoInfo.value = true;
if (!option.id) throw new Error();
const { data } = await getLotTraceOrder(option.id)
Object.assign(workOrderInfo, data);
pwoStore.setInfo(data);
jobStore.resetInfo();
infeedRef.value?.fetchStations();
} catch (error: any) {
message.error(error.message || '获取工单信息失败');
} finally {
loadingPwoInfo.value = false;
}
}
// 刷新工单信息
const handleRefresh = async () => {
if (!workOrderInfo.id) return;
try {
loadingPwoInfo.value = true;
const { data } = await getLotTraceOrder(workOrderInfo.id)
Object.assign(workOrderInfo, data);
pwoStore.setInfo(data);
infeedRef.value?.fetchStations();
} catch (error: any) {
message.error(error.message || '刷新工单信息失败');
} finally {
loadingPwoInfo.value = false;
}
}
onUnmounted(() => {
pwoStore.resetInfo();
jobStore.resetInfo();
})
</script>
<template>
<div class="page-container">
<Header title="过站工控机" showHome 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)" size="small">
<template #icon><i-lucide-copy /></template>
</a-button>
</template>
</a-input>
</a-form-item>
<a-form-item label="工单状态">
<a-input readonly>
<template #prefix>
<DictTag :options="lot_trace_order_status" :value="workOrderInfo.status" size="medium" />
</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)" size="small">
<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)" size="small">
<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)" size="small">
<template #icon><i-lucide-copy /></template>
</a-button>
</template>
</a-input>
</a-form-item>
<!-- <a-form-item label="产品规格">
<a-input readonly>
<template #suffix>
<a-button @click="handleCopy('')" size="small">
<template #icon><i-lucide-copy /></template>
</a-button>
</template>
</a-input>
</a-form-item> -->
</a-col>
</a-row>
</a-form>
<template #extra>
<a-space>
工单编码
<a-select v-model:value="workOrderInfo.code" show-search placeholder="输入工单编码" style="width: 300px"
:show-arrow="false" :options="pwoCodeOptions" @search="handleSearch" :disabled="route.name !== 'PwoManageIndex'"
@change="(val, option) => handleChange(val as string, option as LotTraceOrderData)" />
<a-button @click="handleRefresh"><template #icon><i-lucide-rotate-cw /></template></a-button>
</a-space>
</template>
</a-card>
</a-spin>
</a-col>
<!-- Process Info -->
<a-col :span="8">
<a-spin :spinning="jobStore.loadingJobInfo">
<a-card title="工序信息" class="info-card" :bordered="false">
<a-form :model="processInfo" :colon="false" v-show="!collapsed">
<a-form-item label="工序名称">
<a-input v-model:value="processInfo.operationTitle" readonly>
<template #suffix>
<a-button @click="handleCopy(processInfo.operationTitle)" size="small">
<template #icon><i-lucide-copy /></template>
</a-button>
</template>
</a-input>
</a-form-item>
<a-form-item label="工序状态">
<a-input readonly>
<template #prefix>
<DictTag :options="mes_station_status" :value="processInfo.status" size="medium" />
</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)" size="small">
<template #icon><i-lucide-copy /></template>
</a-button>
</template>
</a-input>
</a-form-item>
</a-form>
<template #extra>
<a-button @click="jobStore.refresh"><template #icon><i-lucide-rotate-cw /></template></a-button>
</template>
</a-card>
</a-spin>
</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="redirectTo('PwoManage')">工单管理</a-button>
<a-button class="action-btn orange-btn" @click="redirectTo('PrimaryMaterial')">主材清单</a-button>
<a-button class="action-btn red-btn" @click="handleHold">Hold</a-button>
</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="redirectTo('PwoManage')">工单管理</a-menu-item>
<a-menu-item key="2" @click="redirectTo('PrimaryMaterial')">主材清单</a-menu-item>
<a-menu-item key="4" @click="handleHold">Hold</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 :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 readonly />
</a-form-item>
<a-form-item label="计划完成日期">
<a-date-picker v-model:value="planFinishDate" placeholder="选择计划完成日期"
valueFormat="YYYY-MM-DD HH:mm:ss" show-time style="width: 100%" />
</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: 12px 14px;
border-radius: 8px;
flex: 1;
min-height: 0;
overflow: auto;
}
</style>

View File

@@ -1,10 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, getCurrentInstance } from 'vue'; import { getCurrentInstance } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { message } from 'ant-design-vue';
import type { ColumnsType } from 'ant-design-vue/es/table/interface'; import type { ColumnsType } from 'ant-design-vue/es/table/interface';
import { listStation } from '@/api/pwoManage/station'; import { useTraceOrderStore } from '@/store';
import { usePwoStore, useJobStore } from '@/store';
const { proxy } = getCurrentInstance() as any const { proxy } = getCurrentInstance() as any
const { mes_station_status } = proxy.useDict("mes_station_status", "lot_trace_order_status") const { mes_station_status } = proxy.useDict("mes_station_status", "lot_trace_order_status")
@@ -21,9 +19,7 @@ interface TableItem {
} }
const router = useRouter(); const router = useRouter();
const pwoStore = usePwoStore(); const traceOrderStore = useTraceOrderStore();
const jobStore = useJobStore();
const tableData = ref<TableItem[]>([]);
const columns = [ const columns = [
{ title: '序号', dataIndex: 'index', key: 'index', align: 'center', width: 80 }, { title: '序号', dataIndex: 'index', key: 'index', align: 'center', width: 80 },
@@ -35,55 +31,30 @@ const columns = [
{ title: '操作', key: 'action', align: 'center' }, { title: '操作', key: 'action', align: 'center' },
]; ];
const loadingStations = ref(false);
const fetchStations = async () => {
try {
loadingStations.value = true;
const res = await listStation({ traceOrderCode: pwoStore.pwoInfo.code });
tableData.value = (res.rows || []).map((item: any, idx: number) => {
return {
key: String(item.id ?? idx),
index: item.seqNo ?? idx + 1,
...item,
} as TableItem;
});
} catch (error: any) {
message.error(error?.msg || error?.message || '查询站点失败');
} finally {
loadingStations.value = false;
}
};
const handleInfeed = (record: any) => { const handleInfeed = (record: any) => {
jobStore.setInfo(record);
router.push({ name: 'Infeed' }); router.push({ name: 'Infeed' });
}; };
const handleOutfeed = (record: any) => { const handleOutfeed = (record: any) => {
jobStore.setInfo(record);
router.push({ name: 'Outfeed' }); router.push({ name: 'Outfeed' });
}; };
function rowClick(record: TableItem) { function rowClick(record: TableItem) {
return { return {
onClick: () => { onClick: () => {
jobStore.setInfo(record); traceOrderStore.selectStation(record.id);
}, },
}; };
} }
defineExpose({
fetchStations
});
</script> </script>
<template> <template>
<div class="table-wrapper"> <div class="table-wrapper">
<a-table <a-table
:dataSource="tableData" :dataSource="traceOrderStore.stationList"
:columns="columns as ColumnsType<TableItem>" :columns="columns as ColumnsType<TableItem>"
:pagination="false" :pagination="false"
:loading="loadingStations" :loading="traceOrderStore.loadingStations"
bordered bordered
sticky sticky
rowKey="key" rowKey="key"
@@ -96,7 +67,7 @@ defineExpose({
</template> </template>
<template v-if="column.key === 'action'"> <template v-if="column.key === 'action'">
<a-space> <a-space>
<a-button size="large" type="primary" @click="handleInfeed(record)">进站</a-button> <a-button size="large" @click="handleInfeed(record)">进站</a-button>
<a-button size="large" type="primary" danger @click="handleOutfeed(record)">出站</a-button> <a-button size="large" type="primary" danger @click="handleOutfeed(record)">出站</a-button>
</a-space> </a-space>
</template> </template>
@@ -112,12 +83,13 @@ defineExpose({
.custom-table { .custom-table {
:deep(.ant-table-thead > tr > th) { :deep(.ant-table-thead > tr > th) {
background-color: #e6f7ff;
font-weight: bold; font-weight: bold;
font-size: clamp(14px, 1.2vw, 20px);
} }
:deep(.ant-table-tbody > tr > td) { :deep(.ant-table-tbody > tr > td) {
padding: 12px 8px; padding: 12px 8px;
font-size: clamp(14px, 1vw, 20px);
} }
} }
} }

View File

@@ -1,16 +1,16 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, reactive } from 'vue'; import { ref, onMounted, reactive } from 'vue';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
import { useJobStore } from '@/store'; import { useTraceOrderStore } from '@/store';
import type { ColumnsType } from 'ant-design-vue/es/table/interface'; import type { ColumnsType } from 'ant-design-vue/es/table/interface';
import { import {
getEquipmentByCode, getEquipmentByCode,
listEquipmentEntry, listEquipmentEntry,
addEquipmentEntry, addEquipmentEntry,
delEquipmentEntry, delEquipmentEntry,
} from '@/api/pwoManage/equipment'; } from '@/api/traceOrderManage/equipment';
const jobStore = useJobStore(); const traceOrderStore = useTraceOrderStore();
interface EquipmentTableItem { interface EquipmentTableItem {
key: string; key: string;
@@ -50,7 +50,7 @@ const handleBind = async () => {
try { try {
await addEquipmentEntry({ await addEquipmentEntry({
equipmentCode: equipmentInput.value, equipmentCode: equipmentInput.value,
stationCode: jobStore.jobInfo.code, stationCode: traceOrderStore.currentStationCode,
}); });
message.success('绑定成功'); message.success('绑定成功');
equipmentInput.value = ''; equipmentInput.value = '';
@@ -73,7 +73,7 @@ const handleUnbind = async (id: number) => {
// //
const loadingEquipmentTableData = ref(false); const loadingEquipmentTableData = ref(false);
const fetchBoundEquipmentList = async () => { const fetchBoundEquipmentList = async () => {
const stationId = jobStore.jobInfo.id; const stationId = traceOrderStore.currentStationCode;
if (!stationId) return; if (!stationId) return;
loadingEquipmentTableData.value = true; loadingEquipmentTableData.value = true;
try { try {

View File

@@ -1,14 +1,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed } from 'vue'; import { ref, computed, inject } from 'vue';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import { startStation } from '@/api/pwoManage/station'; import { startStation } from '@/api/traceOrderManage/station';
import { useJobStore } from '@/store/job'; import { useTraceOrderStore } from '@/store';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
const jobStore = useJobStore(); const traceOrderStore = useTraceOrderStore();
const menuItems = [ const menuItems = [
{ label: '主材', key: 'PrimaryMaterial', progress: 30 }, { label: '主材', key: 'PrimaryMaterial', progress: 30 },
@@ -27,8 +27,11 @@ const infeeding = ref(false);
const handleInfeed = async () => { const handleInfeed = async () => {
infeeding.value = true; infeeding.value = true;
try { try {
await startStation(jobStore.jobInfo.id); await startStation(traceOrderStore.currentStationId);
router.push({ name: 'PwoManage' }); message.success('进站成功');
traceOrderStore.fetchStationInfo();
traceOrderStore.fetchStationList();
router.push({ name: 'TraceOrderManage' });
} catch (error: any) { } catch (error: any) {
message.error(error.message || '进站失败'); message.error(error.message || '进站失败');
} finally { } finally {

View File

@@ -2,11 +2,11 @@
import { ref, onMounted, reactive } from 'vue'; import { ref, onMounted, reactive } from 'vue';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
import type { ColumnsType } from 'ant-design-vue/es/table/interface'; import type { ColumnsType } from 'ant-design-vue/es/table/interface';
import { listMaskCombination } from "@/api/pwoManage/maskCombination"; import { listMaskCombination } from "@/api/traceOrderManage/maskCombination";
import { listStationBindMask, bindMaskCombinationToStations, unbindStationMask } from "@/api/pwoManage/mask"; import { listStationBindMask, bindMaskCombinationToStations, unbindStationMask } from "@/api/traceOrderManage/mask";
import { usePwoStore } from '@/store'; import { useTraceOrderStore } from '@/store';
const pwoStore = usePwoStore(); const traceOrderStore = useTraceOrderStore();
interface MaskTableItem { interface MaskTableItem {
key: string; key: string;
@@ -61,7 +61,7 @@ const fetchCombinationList = async () => {
const handleBind = async (id: number) => { const handleBind = async (id: number) => {
try { try {
await bindMaskCombinationToStations({ await bindMaskCombinationToStations({
lotTraceOrderId: pwoStore.pwoInfo.id, lotTraceOrderId: traceOrderStore.currentTraceOrderId,
maskCombinationId: id maskCombinationId: id
}); });
message.success('绑定成功'); message.success('绑定成功');
@@ -86,7 +86,7 @@ const handleUnbind = async (id: number) => {
// //
const loadingMask = ref(false); const loadingMask = ref(false);
const fetchBoundMaskList = async () => { const fetchBoundMaskList = async () => {
const traceOrderId = pwoStore.pwoInfo.id; const traceOrderId = traceOrderStore.currentTraceOrderId;
if (!traceOrderId) return; if (!traceOrderId) return;
loadingMask.value = true; loadingMask.value = true;
try { try {

View File

@@ -1,12 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted } from 'vue'; import { ref, onMounted } from 'vue';
import { usePwoStore, useJobStore } from '@/store' import { useTraceOrderStore } from '@/store'
import type { ColumnsType } from 'ant-design-vue/es/table/interface'; import type { ColumnsType } from 'ant-design-vue/es/table/interface';
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'
import { listMainMaterialEntryLog, addWaferEntryLogByCarrier, addDieEntryLogByCarrier, addWaferEntryLog, addDieEntryLog, delMainMaterialEntryLog } from '@/api/pwoManage/primaryMaterial' import { listMainMaterialEntryLog, addWaferEntryLogByCarrier, addDieEntryLogByCarrier, addWaferEntryLog, addDieEntryLog, delMainMaterialEntryLog } from '@/api/traceOrderManage/primaryMaterial'
const pwoStore = usePwoStore(); const traceOrderStore = useTraceOrderStore();
const jobStore = useJobStore();
interface MaterialTableItem { interface MaterialTableItem {
key: string; key: string;
@@ -29,7 +28,7 @@ const materialColumns = [
// //
const loadingMaterialTableData = ref(false); const loadingMaterialTableData = ref(false);
const fetchPrimaryMaterialList = async () => { const fetchPrimaryMaterialList = async () => {
const stationId = jobStore.jobInfo.id; const stationId = traceOrderStore.currentStationId;
if (!stationId) return; if (!stationId) return;
loadingMaterialTableData.value = true; loadingMaterialTableData.value = true;
try { try {
@@ -48,7 +47,7 @@ const insertCarrier = async () => {
if (!carrierInput.value) return; if (!carrierInput.value) return;
const form = { const form = {
carrierCode: carrierInput.value, carrierCode: carrierInput.value,
stationCode: jobStore.jobInfo.code stationCode: traceOrderStore.currentStationCode,
}; };
try { try {
if (materialType.value === "Wafer") { if (materialType.value === "Wafer") {
@@ -73,7 +72,7 @@ const insertMaterial = async () => {
if (!materialInput.value) return; if (!materialInput.value) return;
const form = { const form = {
mainMaterialCodes: [materialInput.value], mainMaterialCodes: [materialInput.value],
stationCode: jobStore.jobInfo.code stationCode: traceOrderStore.currentStationCode,
}; };
try { try {
if (materialType.value === "Wafer") { if (materialType.value === "Wafer") {
@@ -126,8 +125,8 @@ defineExpose({
// //
const materialType = ref() const materialType = ref()
if (pwoStore.pwoInfo.orderType) { if (traceOrderStore.traceOrderInfo.orderType) {
const num = parseInt(pwoStore.pwoInfo.orderType) const num = parseInt(traceOrderStore.traceOrderInfo.orderType)
materialType.value = num % 4 === 0 ? 'Die' : 'Wafer' materialType.value = num % 4 === 0 ? 'Die' : 'Wafer'
} else { } else {
materialType.value = '主材类型异常' materialType.value = '主材类型异常'

View File

@@ -0,0 +1,272 @@
<script setup lang="ts">
import { ref, nextTick, getCurrentInstance } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { useTraceOrderStore } from '@/store';
import type { LotTraceOrderData } from '@/api/traceOrderManage/model';
import { handleCopy } from '@/utils/copyToClipboard';
const { proxy } = getCurrentInstance() as any
const { mes_station_status, lot_trace_order_status } = proxy.useDict("mes_station_status", "lot_trace_order_status")
const route = useRoute();
const router = useRouter();
const traceOrderStore = useTraceOrderStore();
const redirectTo = (routeName: string) => {
router.push({ name: routeName });
}
// 孙组件
const infeedRef = ref<any>(null);
const collapsed = ref(false);
// 折叠
const toggleCollapse = async () => {
collapsed.value = !collapsed.value;
await nextTick();
infeedRef.value?.renderTableHeight();
}
</script>
<template>
<div class="page-container">
<Header title="MES 过站平台" showHome showLogout>
<template #right-opts>
<a-button @click="toggleCollapse">
<template #icon>
<i-lucide-chevron-up v-if="!collapsed" />
<i-lucide-chevron-down v-else />
</template>
{{ collapsed ? '展开' : '折叠' }}
</a-button>
</template>
</Header>
<div class="content-wrapper">
<!-- Top Section -->
<div class="top-section">
<a-row :gutter="16" class="full-height-row">
<a-col :span="13">
<a-spin :spinning="traceOrderStore.loadingTraceOrderInfo">
<a-card title="工单信息" class="info-card" :bordered="false">
<a-form :model="traceOrderStore.traceOrderInfo" :colon="false" v-show="!collapsed">
<a-row :gutter="36">
<a-col :span="12">
<a-form-item label="工单批次">
<a-input v-model:value="traceOrderStore.traceOrderInfo.batchNo" readonly>
<template #suffix>
<a-button @click="handleCopy(traceOrderStore.traceOrderInfo.batchNo)" size="small">
<template #icon><i-lucide-copy /></template>
</a-button>
</template>
</a-input>
</a-form-item>
<a-form-item label="工单状态">
<a-input readonly>
<template #prefix>
<DictTag :options="lot_trace_order_status" :value="traceOrderStore.traceOrderInfo.status" size="medium" />
</template>
</a-input>
</a-form-item>
<a-form-item label="总计数量">
<a-input v-model:value="traceOrderStore.traceOrderInfo.planQty" readonly>
<template #suffix>
<a-button @click="handleCopy(traceOrderStore.traceOrderInfo.planQty)" size="small">
<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="traceOrderStore.traceOrderInfo.tarMaterialCode" readonly>
<template #suffix>
<a-button @click="handleCopy(traceOrderStore.traceOrderInfo.tarMaterialCode)" size="small">
<template #icon><i-lucide-copy /></template>
</a-button>
</template>
</a-input>
</a-form-item>
<a-form-item label="产品名称">
<a-input v-model:value="traceOrderStore.traceOrderInfo.tarMaterialName" readonly>
<template #suffix>
<a-button @click="handleCopy(traceOrderStore.traceOrderInfo.tarMaterialName)" size="small">
<template #icon><i-lucide-copy /></template>
</a-button>
</template>
</a-input>
</a-form-item>
<!-- <a-form-item label="产品规格">
<a-input readonly>
<template #suffix>
<a-button @click="handleCopy('')" size="small">
<template #icon><i-lucide-copy /></template>
</a-button>
</template>
</a-input>
</a-form-item> -->
</a-col>
</a-row>
</a-form>
<template #extra>
<a-space>
工单编码
<a-select v-model:value="traceOrderStore.currentTraceOrderCode" show-search placeholder="输入工单编码" style="width: 300px"
:show-arrow="false" :options="traceOrderStore.traceOrderOptions" @search="traceOrderStore.fetchTraceOrderOption" :disabled="route.name !== 'TraceOrderManageIndex'"
@change="(val, option) => traceOrderStore.selectTraceOrder(val as string, option as LotTraceOrderData)" />
<a-button @click="traceOrderStore.fetchTraceOrderInfo"><template #icon><i-lucide-rotate-cw /></template></a-button>
</a-space>
</template>
</a-card>
</a-spin>
</a-col>
<a-col :span="8">
<a-spin :spinning="traceOrderStore.loadingStationInfo">
<a-card title="工序信息" class="info-card" :bordered="false">
<a-form :model="traceOrderStore.stationInfo" :colon="false" v-show="!collapsed">
<a-form-item label="工序名称">
<a-input v-model:value="traceOrderStore.stationInfo.operationTitle" readonly>
<template #suffix>
<a-button @click="handleCopy(traceOrderStore.stationInfo.operationTitle)" size="small">
<template #icon><i-lucide-copy /></template>
</a-button>
</template>
</a-input>
</a-form-item>
<a-form-item label="工序状态">
<a-input readonly>
<template #prefix>
<DictTag :options="mes_station_status" :value="traceOrderStore.stationInfo.status" size="medium" />
</template>
</a-input>
</a-form-item>
<a-form-item label="作业编码">
<a-input v-model:value="traceOrderStore.stationInfo.code" readonly>
<template #suffix>
<a-button @click="handleCopy(traceOrderStore.stationInfo.code)" size="small">
<template #icon><i-lucide-copy /></template>
</a-button>
</template>
</a-input>
</a-form-item>
</a-form>
<template #extra>
<a-button @click="traceOrderStore.fetchStationInfo"><template #icon><i-lucide-rotate-cw /></template></a-button>
</template>
</a-card>
</a-spin>
</a-col>
<!-- Action Buttons -->
<a-col :span="3" class="action-buttons-col">
<div class="action-buttons" v-show="!collapsed">
<a-button class="action-btn" @click="redirectTo('TraceOrderManage')" :disabled="route.name == 'TraceOrderManageIndex'">工单管理</a-button>
<a-button class="action-btn" @click="redirectTo('PrimaryMaterial')" disabled>主材清单</a-button>
<HoldTraceOrder />
</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="redirectTo('TraceOrderManage')">工单管理</a-menu-item>
<a-menu-item key="2" @click="redirectTo('PrimaryMaterial')" disabled>主材清单</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>
</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;
}
// 传递给子组件的样式
:deep(.action-buttons) {
display: flex;
flex-direction: column;
gap: 6px;
height: 100%;
.action-btn {
height: 48px;
font-size: 20px;
font-weight: 500;
}
}
.bottom-section {
background: #fff;
padding: 12px 14px;
border-radius: 8px;
flex: 1;
min-height: 0;
overflow: auto;
}
</style>

View File

@@ -1,14 +1,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, onMounted, computed, getCurrentInstance } from 'vue'; import { ref, reactive, onMounted, computed, getCurrentInstance } from 'vue';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
import { useJobStore } from '@/store'; import { useTraceOrderStore } from '@/store';
import type { ColumnsType } from 'ant-design-vue/es/table/interface'; import type { ColumnsType } from 'ant-design-vue/es/table/interface';
import { listMainMaterialEntryLog, listMainMaterialOutboundLog, batchAddMainMaterialOutboundLog, getMainMaterialOutboundLog, updateMainMaterialOutboundLog, delMainMaterialOutboundLog } from "@/api/pwoManage/primaryMaterial"; import { listMainMaterialEntryLog, listMainMaterialOutboundLog, batchAddMainMaterialOutboundLog, getMainMaterialOutboundLog, updateMainMaterialOutboundLog, delMainMaterialOutboundLog } from "@/api/traceOrderManage/primaryMaterial";
const { proxy } = getCurrentInstance() as any const { proxy } = getCurrentInstance() as any
const { main_material_ok_level, main_material_ng_level } = proxy.useDict("main_material_ok_level", "main_material_ng_level") const { main_material_ok_level, main_material_ng_level } = proxy.useDict("main_material_ok_level", "main_material_ng_level")
const jobStore = useJobStore(); const traceOrderStore = useTraceOrderStore();
interface PrimaryMaterialTableItem { interface PrimaryMaterialTableItem {
key: string; key: string;
@@ -55,7 +55,7 @@ const primaryMaterialTableData = ref<PrimaryMaterialTableItem[]>([]);
const loadingPrimaryMaterialList = ref(false); const loadingPrimaryMaterialList = ref(false);
const fetchPrimaryMaterialList = async () => { const fetchPrimaryMaterialList = async () => {
const stationId = jobStore.jobInfo.id; const stationId = traceOrderStore.currentStationId;
if (!stationId) return; if (!stationId) return;
loadingPrimaryMaterialList.value = true; loadingPrimaryMaterialList.value = true;
try { try {
@@ -88,7 +88,7 @@ const infeedMaterialTableData = ref<InfeedMaterialTableItem[]>([]);
// //
const handlePickPrimaryMaterial = async () => { const handlePickPrimaryMaterial = async () => {
const stationId = jobStore.jobInfo.id; const stationId = traceOrderStore.currentStationId;
if (!stationId) return; if (!stationId) return;
try { try {
const { rows } = await listMainMaterialEntryLog({ stationId }); const { rows } = await listMainMaterialEntryLog({ stationId });
@@ -149,11 +149,11 @@ const handleChangeSelection = (selectedRowKeys: any, selectedRows: InfeedMateria
// //
const submitOutfeed = async () => { const submitOutfeed = async () => {
const stationCode = jobStore.jobInfo.code; const stationCode = traceOrderStore.currentStationCode;
try { try {
await batchAddMainMaterialOutboundLog({ stationCode, outbounds: rowSelection.value }); await batchAddMainMaterialOutboundLog({ stationCode, outbounds: rowSelection.value });
message.success("出站成功"); message.success("提交成功");
handleCancel(); handleCancel();
fetchPrimaryMaterialList(); fetchPrimaryMaterialList();
} catch (err: any) { } catch (err: any) {
@@ -187,6 +187,7 @@ onMounted(() => {
}) })
defineExpose({ defineExpose({
totals,
renderTableHeight renderTableHeight
}); });

View File

@@ -2,14 +2,14 @@
import { ref, computed, reactive } from 'vue'; import { ref, computed, reactive } from 'vue';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
import { listStorageLocation } from '@/api/pwoManage/location'; import { listStorageLocation } from '@/api/traceOrderManage/location';
import { completeStation } from '@/api/pwoManage/station'; import { completeStation } from '@/api/traceOrderManage/station';
import { useJobStore } from '@/store'; import { useTraceOrderStore } from '@/store';
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
const jobStore = useJobStore(); const traceOrderStore = useTraceOrderStore();
const menuItems = [ const menuItems = [
{ label: '主材报工', key: 'JobReport', progress: 30 }, { label: '主材报工', key: 'JobReport', progress: 30 },
@@ -49,10 +49,12 @@ const outfeeding = ref(false);
const handleOutfeed = async () => { const handleOutfeed = async () => {
outfeeding.value = true; outfeeding.value = true;
try { try {
await completeStation(jobStore.jobInfo.id, storage); await completeStation(traceOrderStore.currentStationId, storage);
openSelectLocation.value = false; openSelectLocation.value = false;
message.success('出站成功'); message.success('出站成功');
router.push({ name: 'PwoManage' }); traceOrderStore.fetchStationInfo();
traceOrderStore.fetchStationList();
router.push({ name: 'TraceOrderManage' });
} catch (error: any) { } catch (error: any) {
message.error(error.message || '出站失败'); message.error(error.message || '出站失败');
} finally { } finally {