|
|
@@ -0,0 +1,251 @@
|
|
|
+<template>
|
|
|
+ <AidopDemoShell :title="pageTitle" subtitle="工单物料齐套上线看板">
|
|
|
+ <el-form :inline="true" :model="query" class="mb12" @submit.prevent>
|
|
|
+ <el-form-item label="订单号">
|
|
|
+ <el-input v-model="query.seOrder" clearable placeholder="模糊查询" style="width: 170px" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="工单号">
|
|
|
+ <el-input v-model="query.workord" clearable placeholder="模糊查询" style="width: 170px" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="产品编码">
|
|
|
+ <el-input v-model="query.bomNumber" clearable placeholder="精确查询" style="width: 160px" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="物料编码">
|
|
|
+ <el-input v-model="query.itemNum" clearable placeholder="精确查询" style="width: 160px" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="供应商名称">
|
|
|
+ <el-input v-model="query.supplierName" clearable placeholder="模糊查询" style="width: 170px" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" @click="doSearch">查询</el-button>
|
|
|
+ <el-button @click="resetQuery">重置</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <div class="toolbar">
|
|
|
+ <el-button type="primary" plain :loading="refreshing" @click="onRefresh">刷新</el-button>
|
|
|
+ <el-popover placement="bottom" width="240" trigger="click">
|
|
|
+ <template #reference><el-button text>列设置</el-button></template>
|
|
|
+ <el-checkbox
|
|
|
+ v-for="item in toggleItems"
|
|
|
+ :key="item.key"
|
|
|
+ :model-value="col[item.key]"
|
|
|
+ @change="(v) => setColumnVisible(item.key, Boolean(v))"
|
|
|
+ >
|
|
|
+ {{ item.label }}
|
|
|
+ </el-checkbox>
|
|
|
+ </el-popover>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-table :data="rows" v-loading="loading" border stripe style="width: 100%" @sort-change="onSortChange">
|
|
|
+ <el-table-column
|
|
|
+ v-for="item in visibleColumns"
|
|
|
+ :key="item.key"
|
|
|
+ :prop="item.key"
|
|
|
+ :label="item.label"
|
|
|
+ :min-width="item.minWidth || 120"
|
|
|
+ :width="item.width"
|
|
|
+ :align="item.align || 'left'"
|
|
|
+ :fixed="item.fixed"
|
|
|
+ :sortable="item.sortable ? 'custom' : false"
|
|
|
+ :show-overflow-tooltip="item.overflow ?? true"
|
|
|
+ :resizable="true"
|
|
|
+ >
|
|
|
+ <template v-if="item.format === 'date'" #default="{ row }">{{ fmtDate(row[item.key]) }}</template>
|
|
|
+ <template v-else-if="item.format === 'num'" #default="{ row }">{{ fmtNumber(row[item.key]) }}</template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <div class="pager">
|
|
|
+ <el-pagination
|
|
|
+ v-model:current-page="query.page"
|
|
|
+ v-model:page-size="query.pageSize"
|
|
|
+ :total="total"
|
|
|
+ :page-sizes="[10, 20, 50]"
|
|
|
+ layout="total, sizes, prev, pager, next"
|
|
|
+ @current-change="loadList"
|
|
|
+ @size-change="loadList"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </AidopDemoShell>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts" name="aidopS3WorkOrderMaterialReadiness">
|
|
|
+import { computed, onMounted, reactive, ref } from 'vue';
|
|
|
+import { useRoute } from 'vue-router';
|
|
|
+import { ElMessage } from 'element-plus';
|
|
|
+import AidopDemoShell from '/@/views/aidop/components/AidopDemoShell.vue';
|
|
|
+import {
|
|
|
+ fetchWorkOrderMaterialReadinessList,
|
|
|
+ refreshWorkOrderMaterialReadiness,
|
|
|
+ type WorkOrderMaterialReadinessRow,
|
|
|
+} from '../api/workOrderMaterialReadiness';
|
|
|
+
|
|
|
+const route = useRoute();
|
|
|
+const pageTitle = computed(() => (route.meta?.title as string) || '工单物料齐套上线看板');
|
|
|
+
|
|
|
+const query = reactive({
|
|
|
+ seOrder: '',
|
|
|
+ workord: '',
|
|
|
+ bomNumber: '',
|
|
|
+ itemNum: '',
|
|
|
+ supplierName: '',
|
|
|
+ page: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ sortField: '',
|
|
|
+ sortOrder: '',
|
|
|
+});
|
|
|
+
|
|
|
+const loading = ref(false);
|
|
|
+const refreshing = ref(false);
|
|
|
+const rows = ref<WorkOrderMaterialReadinessRow[]>([]);
|
|
|
+const total = ref(0);
|
|
|
+
|
|
|
+const columns = [
|
|
|
+ { key: 'rowNum', label: '序号', width: 90, fixed: undefined, sortable: true },
|
|
|
+ { key: 'seOrder', label: '订单号', width: 160, fixed: 'left', sortable: true },
|
|
|
+ { key: 'sePriority', label: '订单优先级', width: 120, sortable: true, align: 'right', format: 'num' },
|
|
|
+ { key: 'workord', label: '工单号', width: 170, sortable: true },
|
|
|
+ { key: 'priority', label: '工单优先级', width: 120, sortable: true, align: 'right', format: 'num' },
|
|
|
+ { key: 'morderType', label: '工单类型', width: 120, sortable: true },
|
|
|
+ { key: 'lotSerial', label: '生产批号', width: 130, sortable: true },
|
|
|
+ { key: 'op', label: '工序', width: 90, sortable: true, align: 'right' },
|
|
|
+ { key: 'opOrdDate', label: '工序开工日期', width: 140, sortable: true, format: 'date' },
|
|
|
+ { key: 'bomNumber', label: '产品编码', width: 150, sortable: true },
|
|
|
+ { key: 'descr', label: '产品描述', minWidth: 160, sortable: true },
|
|
|
+ { key: 'descr1', label: '规格型号', minWidth: 140, sortable: true },
|
|
|
+ { key: 'productionNumber', label: '生产数量', width: 110, sortable: true, align: 'right', format: 'num' },
|
|
|
+ { key: 'checktime', label: 'MRP日期', width: 140, sortable: true, format: 'date' },
|
|
|
+ { key: 'pmbom', label: 'BOM版本', width: 110, sortable: true },
|
|
|
+ { key: 'itemType', label: '物料类型', width: 110, sortable: true },
|
|
|
+ { key: 'ownerApplication', label: '物料属性', width: 110, sortable: true },
|
|
|
+ { key: 'itemNum', label: '物料编码', width: 140, sortable: true },
|
|
|
+ { key: 'componentItemDescr', label: '物料描述', minWidth: 160, sortable: true },
|
|
|
+ { key: 'componentItemDrawing', label: '物料图号', width: 130, sortable: true },
|
|
|
+ { key: 'qtyRequired', label: '需求数量', width: 110, sortable: true, align: 'right', format: 'num' },
|
|
|
+ { key: 'componentItemUM', label: '单位', width: 90, sortable: true },
|
|
|
+ { key: 'componentItemKittingTime', label: '需求日期', width: 130, sortable: true, format: 'date' },
|
|
|
+ { key: 'qtyRec', label: '发料数量', width: 110, sortable: true, align: 'right', format: 'num' },
|
|
|
+ { key: 'recDate', label: '发料日期', width: 130, sortable: true, format: 'date' },
|
|
|
+ { key: 'shortage', label: '欠料数量', width: 110, sortable: true, align: 'right', format: 'num' },
|
|
|
+ { key: 'qtyFrom', label: '备料数量', width: 110, sortable: true, align: 'right', format: 'num' },
|
|
|
+ { key: 'fromDate', label: '备料日期', width: 130, sortable: true, format: 'date' },
|
|
|
+ { key: 'zjsl', label: '在检数量', width: 110, sortable: true, align: 'right', format: 'num' },
|
|
|
+ { key: 'jykssj', label: '检验申请日期', width: 140, sortable: true, format: 'date' },
|
|
|
+ { key: 'ztsl', label: '在途数量', width: 110, sortable: true, align: 'right', format: 'num' },
|
|
|
+ { key: 'jhshrq', label: '发货日期', width: 130, sortable: true, format: 'date' },
|
|
|
+ { key: 'jqsl', label: '承诺数量', width: 110, sortable: true, align: 'right', format: 'num' },
|
|
|
+ { key: 'hfjq', label: '承诺交期', width: 130, sortable: true, format: 'date' },
|
|
|
+ { key: 'purOrdQty', label: '采购数量', width: 110, sortable: true, align: 'right', format: 'num' },
|
|
|
+ { key: 'purOrdorddate', label: '采购日期', width: 130, sortable: true, format: 'date' },
|
|
|
+ { key: 'purOrds', label: '采购单号', width: 150, sortable: true },
|
|
|
+ { key: 'contractDate', label: '合同日期', width: 130, sortable: true, format: 'date' },
|
|
|
+ { key: 'contractNO', label: '合同编号', width: 150, sortable: true },
|
|
|
+ { key: 'supplierNumber', label: '供应商编码', width: 130, sortable: true },
|
|
|
+ { key: 'supplierName', label: '供应商名称', minWidth: 150, sortable: true },
|
|
|
+ { key: 'buyer', label: '采购组', width: 100, sortable: true },
|
|
|
+ { key: 'buyerUser', label: '采购员', width: 100, sortable: true },
|
|
|
+] as const;
|
|
|
+
|
|
|
+type ColumnDef = (typeof columns)[number];
|
|
|
+type ColumnKey = ColumnDef['key'];
|
|
|
+
|
|
|
+const col = reactive(
|
|
|
+ Object.fromEntries(columns.map((item) => [item.key, true])) as Record<ColumnKey, boolean>
|
|
|
+);
|
|
|
+
|
|
|
+const toggleItems = columns.map((item) => ({ key: item.key, label: item.label }));
|
|
|
+const visibleColumns = computed(() => columns.filter((item) => col[item.key]));
|
|
|
+
|
|
|
+function fmtDate(v?: string | number | null) {
|
|
|
+ if (!v) return '';
|
|
|
+ return String(v).slice(0, 10);
|
|
|
+}
|
|
|
+function fmtNumber(v?: string | number | null) {
|
|
|
+ if (v === null || v === undefined || v === '') return '';
|
|
|
+ const n = Number(v);
|
|
|
+ return Number.isNaN(n) ? String(v) : n.toLocaleString('zh-CN');
|
|
|
+}
|
|
|
+
|
|
|
+async function loadList() {
|
|
|
+ loading.value = true;
|
|
|
+ try {
|
|
|
+ const data = await fetchWorkOrderMaterialReadinessList({
|
|
|
+ page: query.page,
|
|
|
+ pageSize: query.pageSize,
|
|
|
+ seOrder: query.seOrder || undefined,
|
|
|
+ workord: query.workord || undefined,
|
|
|
+ bomNumber: query.bomNumber || undefined,
|
|
|
+ itemNum: query.itemNum || undefined,
|
|
|
+ supplierName: query.supplierName || undefined,
|
|
|
+ sortField: query.sortField || undefined,
|
|
|
+ sortOrder: query.sortOrder || undefined,
|
|
|
+ });
|
|
|
+ rows.value = data.list || [];
|
|
|
+ total.value = data.total || 0;
|
|
|
+ } finally {
|
|
|
+ loading.value = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function doSearch() {
|
|
|
+ query.page = 1;
|
|
|
+ loadList();
|
|
|
+}
|
|
|
+
|
|
|
+function resetQuery() {
|
|
|
+ query.seOrder = '';
|
|
|
+ query.workord = '';
|
|
|
+ query.bomNumber = '';
|
|
|
+ query.itemNum = '';
|
|
|
+ query.supplierName = '';
|
|
|
+ query.page = 1;
|
|
|
+ query.sortField = '';
|
|
|
+ query.sortOrder = '';
|
|
|
+ loadList();
|
|
|
+}
|
|
|
+
|
|
|
+async function onRefresh() {
|
|
|
+ refreshing.value = true;
|
|
|
+ try {
|
|
|
+ await refreshWorkOrderMaterialReadiness();
|
|
|
+ ElMessage.success('刷新成功');
|
|
|
+ await loadList();
|
|
|
+ } finally {
|
|
|
+ refreshing.value = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function setColumnVisible(key: ColumnKey, visible: boolean) {
|
|
|
+ col[key] = visible;
|
|
|
+}
|
|
|
+
|
|
|
+function onSortChange({ prop, order }: { prop: string; order: string | null }) {
|
|
|
+ query.sortField = prop || '';
|
|
|
+ query.sortOrder = order === 'ascending' ? 'asc' : order === 'descending' ? 'desc' : '';
|
|
|
+ loadList();
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(loadList);
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+@import '/@/views/aidop/styles/aidop-demo.scss';
|
|
|
+
|
|
|
+.mb12 {
|
|
|
+ margin-bottom: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.toolbar {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ margin-bottom: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.pager {
|
|
|
+ margin-top: 12px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+}
|
|
|
+</style>
|