1463 lines
42 KiB
Vue
1463 lines
42 KiB
Vue
<template>
|
||
<div class="page-container">
|
||
<div class="order-layout">
|
||
<!-- 左侧生产令号 -->
|
||
<n-card class="order-tree-card" size="small">
|
||
<template #header>
|
||
<div class="order-tree-header">生产令号</div>
|
||
</template>
|
||
<div class="order-search">
|
||
<n-input v-model:value="projectTreeSearch" placeholder="搜索生产令号" clearable size="small">
|
||
<template #prefix>
|
||
<n-icon><SearchOutline /></n-icon>
|
||
</template>
|
||
</n-input>
|
||
</div>
|
||
<div class="order-tree-wrapper">
|
||
<n-tree
|
||
:data="projectTreeData"
|
||
:pattern="projectTreeSearch"
|
||
:selected-keys="selectedProjectKeys"
|
||
:node-props="projectNodeProps"
|
||
key-field="id"
|
||
label-field="label"
|
||
selectable
|
||
block-line
|
||
/>
|
||
</div>
|
||
</n-card>
|
||
|
||
<!-- 右侧生产订单列表 -->
|
||
<n-card class="order-list-card" size="small">
|
||
<template #header>
|
||
<div class="card-header">
|
||
<span>{{ selectedProjectLabel ? `【${selectedProjectLabel}】生产订单` : '全部生产订单' }}</span>
|
||
</div>
|
||
</template>
|
||
|
||
<!-- 搜索表单 -->
|
||
<div class="search-form">
|
||
<n-form inline :model="searchForm" label-placement="left">
|
||
<n-form-item label="物料编码">
|
||
<n-input v-model:value="searchForm.code" placeholder="请输入物料编码" clearable />
|
||
</n-form-item>
|
||
<n-form-item label="开始时间">
|
||
<n-date-picker v-model:value="searchForm.beginTime" type="datetime" clearable />
|
||
</n-form-item>
|
||
<n-form-item label="结束时间">
|
||
<n-date-picker v-model:value="searchForm.endTime" type="datetime" clearable />
|
||
</n-form-item>
|
||
<n-form-item>
|
||
<n-space>
|
||
<n-button type="primary" @click="handleSearch">
|
||
<template #icon><n-icon><SearchOutline /></n-icon></template>
|
||
搜索
|
||
</n-button>
|
||
<n-button @click="handleReset">
|
||
<template #icon><n-icon><RefreshOutline /></n-icon></template>
|
||
重置
|
||
</n-button>
|
||
</n-space>
|
||
</n-form-item>
|
||
</n-form>
|
||
</div>
|
||
|
||
<n-data-table
|
||
size="small"
|
||
remote
|
||
striped
|
||
:border="false"
|
||
:single-line="false"
|
||
:columns="columns"
|
||
:data="tableData"
|
||
:loading="loading"
|
||
/>
|
||
<div class="pagination-container" style="display: flex; justify-content: flex-end; margin-top: 12px">
|
||
<n-pagination
|
||
v-model:page="pagination.page"
|
||
v-model:page-size="pagination.pageSize"
|
||
:item-count="pagination.itemCount"
|
||
:page-sizes="[10, 20, 50, 100]"
|
||
show-size-picker
|
||
show-quick-jumper
|
||
@update:page="handlePageChange"
|
||
@update:page-size="handlePageSizeChange"
|
||
>
|
||
<template #prefix>
|
||
共 {{ pagination.itemCount }} 条
|
||
</template>
|
||
</n-pagination>
|
||
</div>
|
||
</n-card>
|
||
</div>
|
||
|
||
<!-- 工艺路线右侧抽屉 -->
|
||
<n-drawer v-model:show="routeDrawerVisible" :width="720" placement="right">
|
||
<n-drawer-content :title="routeDrawerTitle" closable>
|
||
<n-spin :show="routeDrawerLoading">
|
||
<template v-if="routeDetail">
|
||
<n-descriptions label-placement="left" :column="2" size="small" bordered class="route-desc">
|
||
<n-descriptions-item label="工艺路线编码">{{ routeDetail.routeCode || '-' }}</n-descriptions-item>
|
||
<n-descriptions-item label="工艺路线名称">{{ routeDetail.routeName || '-' }}</n-descriptions-item>
|
||
</n-descriptions>
|
||
<div class="route-steps-title">工序明细</div>
|
||
<n-data-table
|
||
size="small"
|
||
striped
|
||
:bordered="false"
|
||
:single-line="false"
|
||
:columns="routeStepColumns"
|
||
:data="routeDetail.stepList || []"
|
||
:max-height="520"
|
||
/>
|
||
</template>
|
||
<n-empty v-else-if="!routeDrawerLoading" description="未查询到工艺路线" />
|
||
</n-spin>
|
||
</n-drawer-content>
|
||
</n-drawer>
|
||
|
||
<!-- 新增/编辑弹窗 -->
|
||
<n-modal
|
||
v-model:show="modalVisible"
|
||
preset="card"
|
||
:title="modalTitle"
|
||
style="width: 900px"
|
||
:mask-closable="false"
|
||
>
|
||
<n-form
|
||
ref="formRef"
|
||
:model="formData"
|
||
:rules="formRules"
|
||
label-placement="left"
|
||
label-width="120px"
|
||
>
|
||
<n-grid :cols="2">
|
||
<!-- <n-gi>
|
||
<n-form-item label="生产令号" path="productionCode">
|
||
<n-input v-if="formData.id" v-model:value="formData.productionCode" placeholder="请输入生产令号" />
|
||
<n-input v-else v-model:value="formData.productionCode" @input="gongxu" placeholder="请输入生产令号" />
|
||
</n-form-item>
|
||
</n-gi> -->
|
||
<n-gi>
|
||
<n-form-item label="项目名称" path="project">
|
||
<n-input v-if="formData.id" v-model:value="formData.projectName" disabled placeholder="请选择项目" />
|
||
<n-select
|
||
v-else
|
||
v-model:value="formData.projectId"
|
||
filterable
|
||
placeholder="请选择项目"
|
||
:options="xmlist"
|
||
:loading="xmloading"
|
||
clearable
|
||
remote
|
||
:clear-filter-after-select="false"
|
||
@update:value="xmselupdate"
|
||
/>
|
||
</n-form-item>
|
||
</n-gi>
|
||
<n-gi>
|
||
<n-form-item label="物料编码" path="code">
|
||
<n-input v-if="formData.id" v-model:value="formData.code" disabled placeholder="请选择物料编码" />
|
||
<!-- <n-input v-else v-model:value="formData.code" placeholder="请选择物料编码" /> -->
|
||
<!-- @search="wlhand"-->
|
||
<n-select
|
||
v-else
|
||
v-model:value="formData.code"
|
||
filterable
|
||
placeholder="请选择物料编码"
|
||
:options="wllist"
|
||
:loading="wlloading"
|
||
clearable
|
||
remote
|
||
:clear-filter-after-select="false"
|
||
@update:value="gongxu"
|
||
|
||
/>
|
||
</n-form-item>
|
||
</n-gi>
|
||
<n-gi>
|
||
<n-form-item label="物料名称" path="name">
|
||
<n-input v-model:value="formData.name" placeholder="请输入物料名称" />
|
||
</n-form-item>
|
||
</n-gi>
|
||
<n-gi>
|
||
<n-form-item label="产品序列" path="sort">
|
||
<n-input v-if="formData.id" v-model:value="formData.sort" placeholder="请输入产品序列" />
|
||
<n-input v-else v-model:value="formData.sort" placeholder="请输入产品序列" />
|
||
</n-form-item>
|
||
</n-gi>
|
||
<n-gi>
|
||
<n-form-item label="生产数量" path="quantity">
|
||
<n-input v-if="formData.id" v-model:value="formData.quantity" disabled placeholder="请输入生产数量" />
|
||
<n-input v-else v-model:value="formData.quantity" placeholder="请输入生产数量" disabled />
|
||
</n-form-item>
|
||
</n-gi>
|
||
<n-gi>
|
||
<n-form-item label="订单编号" path="orderCode">
|
||
<n-input v-model:value="formData.orderCode" placeholder="订单编号" :disabled="!formData.id" />
|
||
</n-form-item>
|
||
</n-gi>
|
||
<n-gi>
|
||
<n-form-item label="工艺路线编码" path="routeCode">
|
||
<n-input v-model:value="formData.routeCode" placeholder="工艺路线编码" :disabled="!formData.id" />
|
||
</n-form-item>
|
||
</n-gi>
|
||
<n-gi>
|
||
<n-form-item label="生产车间" path="workshopId">
|
||
<n-input :value="resolveWorkshopLabel(formData.workshopId)" placeholder="生产车间" disabled />
|
||
</n-form-item>
|
||
</n-gi>
|
||
|
||
<n-gi>
|
||
<n-form-item label="是否半成品" path="sfProduct">
|
||
<n-radio-group v-model:value="formData.sfProduct" name="radiogroup">
|
||
<n-space>
|
||
<n-radio :value="1">是</n-radio>
|
||
<n-radio :value="0">否</n-radio>
|
||
</n-space>
|
||
</n-radio-group>
|
||
</n-form-item>
|
||
</n-gi>
|
||
<n-gi>
|
||
<n-form-item label="是否采购" path="procurement">
|
||
<!-- <n-input v-model:value="formData.procurement" placeholder="请输入是否采购, 1是 0不是" /> -->
|
||
<n-radio-group v-model:value="formData.procurement" name="radiogroup">
|
||
<n-space>
|
||
<n-radio :value="1">是</n-radio>
|
||
<n-radio :value="0">否</n-radio>
|
||
</n-space>
|
||
</n-radio-group>
|
||
</n-form-item>
|
||
</n-gi>
|
||
<n-gi>
|
||
<n-form-item label="预计开始时间" path="beginTime">
|
||
<n-date-picker v-model:value="formData.beginTime" type="datetime" clearable style="width: 100%" />
|
||
</n-form-item>
|
||
</n-gi>
|
||
<n-gi>
|
||
<n-form-item label="预计结束时间" path="endTime">
|
||
<n-date-picker v-model:value="formData.endTime" type="datetime" clearable style="width: 100%" />
|
||
</n-form-item>
|
||
</n-gi>
|
||
<n-gi>
|
||
<n-form-item label="派工接收人" path="assingWorkList">
|
||
<!-- <n-input v-model:value="formData.assingWorkId" placeholder="请选择派工接收人" /> -->
|
||
<n-select
|
||
multiple
|
||
filterable
|
||
v-model:value="formData.assingWorkList"
|
||
placeholder="请输入用户名称搜索"
|
||
:options="yglist"
|
||
:loading="loadingRef"
|
||
clearable
|
||
remote
|
||
:clear-filter-after-select="false"
|
||
@search="slehand"
|
||
/>
|
||
</n-form-item>
|
||
</n-gi>
|
||
</n-grid>
|
||
</n-form>
|
||
<template v-if="planList.length > 0">
|
||
<n-divider title-placement="left" size="small">可拖动工序排序</n-divider>
|
||
<VueDraggable
|
||
v-model="planList"
|
||
target=".sort-target"
|
||
:animation="150"
|
||
@end="tuozChange"
|
||
>
|
||
<table style="width: 100%;text-align: center;">
|
||
<thead>
|
||
<tr style="height: 30px;background: #e5e7eb;">
|
||
<th>订单名称</th>
|
||
<th>工序编码</th>
|
||
<th>工序名称</th>
|
||
<th>开始时间</th>
|
||
<th>结束时间</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody class="sort-target">
|
||
<!-- <gxitem
|
||
v-for="(n,i) in planList"
|
||
:obj="n"
|
||
:index="i"
|
||
@update="gxupdata"
|
||
/> -->
|
||
<tr
|
||
v-for="(n,i) in planList"
|
||
:key="i"
|
||
class="cursor-move"
|
||
:style="{
|
||
height: '40px',
|
||
background:isEven(i)?'#fff':'#f3f3f3'
|
||
}"
|
||
>
|
||
<td>{{ n.code }}{{n.sort}}</td>
|
||
<td>{{ n.name }}</td>
|
||
<td>{{ n.orderItemName }}</td>
|
||
<td>
|
||
<n-date-picker
|
||
v-model:value="n.beginTime"
|
||
type="datetime"
|
||
style="width: 100%;"
|
||
/>
|
||
</td>
|
||
<td>
|
||
<n-date-picker
|
||
v-model:value="n.endTime"
|
||
type="datetime"
|
||
style="width: 100%;"
|
||
/>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</VueDraggable>
|
||
</template>
|
||
|
||
<template #footer>
|
||
<n-space justify="end">
|
||
<n-button @click="modalVisible = false">取消</n-button>
|
||
<n-button type="primary" @click="handleSubmit">确定</n-button>
|
||
</n-space>
|
||
</template>
|
||
</n-modal>
|
||
|
||
<!--派工弹框-->
|
||
<n-modal
|
||
v-model:show="dispatchmodal"
|
||
title="派工"
|
||
preset="card"
|
||
style="width: 400px"
|
||
:mask-closable="false"
|
||
>
|
||
<n-form
|
||
ref="dispatchformRef"
|
||
:model="dispatchform"
|
||
:rules="dispatchrules"
|
||
label-placement="top"
|
||
label-width="80"
|
||
>
|
||
<n-form-item label="工单名称">
|
||
<n-input v-model:value="dispatchform.name" disabled />
|
||
</n-form-item>
|
||
<n-form-item label="指派员工" path="assingWorkList">
|
||
<!-- <n-select
|
||
v-model:value="dispatchform.userid"
|
||
:options="yglist"
|
||
clearable
|
||
placeholder="请选择员工"
|
||
/> -->
|
||
<!--v-model:value="dispatchform.assingWorkList"-->
|
||
<n-select
|
||
multiple
|
||
filterable
|
||
placeholder="请输入用户名称搜索"
|
||
:options="yglist"
|
||
:loading="loadingRef"
|
||
clearable
|
||
remote
|
||
:clear-filter-after-select="false"
|
||
@search="slehand"
|
||
@update:value="updatesle"
|
||
/>
|
||
|
||
<!-- <n-input v-model:value="dispatchform.userid" placeholder="请选择员工" /> -->
|
||
</n-form-item>
|
||
</n-form>
|
||
<template #footer>
|
||
<n-space justify="end">
|
||
<n-button size="small" @click="dispatchmodal = false">取消</n-button>
|
||
<n-button
|
||
size="small"
|
||
type="primary"
|
||
:loading="dispatchLoading"
|
||
@click="dispatchSubmit"
|
||
:disabled="dispatchddbtn"
|
||
>确定</n-button>
|
||
</n-space>
|
||
</template>
|
||
</n-modal>
|
||
<n-modal
|
||
v-model:show="kingdeeModalVisible"
|
||
preset="card"
|
||
:title="kingdeeModalTitle"
|
||
class="kingdee-modal"
|
||
:style="{ width: '96vw', maxWidth: '1920px' }"
|
||
:content-style="{ padding: '16px 24px', minHeight: '72vh' }"
|
||
:mask-closable="false"
|
||
:closable="true"
|
||
:close-on-esc="false"
|
||
>
|
||
<KingdeeVue
|
||
:kingdeeTableData="kingdeeTableData"
|
||
:selectedId="kingdeeOrderOtemId"
|
||
:loading="kingdeeLoading"
|
||
@close-modal="kingdeeModalVisible = false"
|
||
@holdTemporarilyCallback="holdTemporarilySave"
|
||
@synchronizationCallback="synchronizationSave"
|
||
@reCrawlCallback="reCrawlReorderForm"/>
|
||
</n-modal>
|
||
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, reactive, h, computed, onMounted, type HTMLAttributes } from 'vue'
|
||
import { NButton, NSpace, NIcon, NTag, useMessage, useDialog, type UploadCustomRequestOptions, type TreeOption, type DataTableColumns } from 'naive-ui'
|
||
import { SearchOutline, RefreshOutline, CreateOutline, PlayOutline, DocumentTextOutline } from '@vicons/ionicons5'
|
||
import { orderItemApi, type OrderItem } from '@/api/orderItem'
|
||
import { processRouteApi } from '@/api/processRoute'
|
||
import { useUserStore } from '@/stores/user'
|
||
import { VueDraggable } from 'vue-draggable-plus'
|
||
|
||
import KingdeeVue from '@/views/biz/kingdee/index.vue'
|
||
|
||
import { type KingdeePrdMo } from '@/api/orderProject'
|
||
import { mapKingdeeMoListToTableRows, type KingdeeMoTableRow } from '@/utils/kingdeeSchedule'
|
||
import { userApi } from '@/api/system'
|
||
import { deptApi } from '@/api/org'
|
||
|
||
const message = useMessage()
|
||
const dialog = useDialog()
|
||
|
||
const userStore = useUserStore()
|
||
|
||
|
||
function isEven(num:any) {
|
||
return num % 2 == 0
|
||
}
|
||
|
||
// 权限检查
|
||
const hasPermission = (permission: string) => userStore.hasPermission(permission)
|
||
|
||
// 搜索表单
|
||
const searchForm = reactive<any>({
|
||
code: '',
|
||
projectName: '',
|
||
orderCode: '',
|
||
routeCode: '',
|
||
workshopId: null as number | null,
|
||
beginTime: null as number | null,
|
||
endTime: null as number | null,
|
||
})
|
||
|
||
// 左侧生产令号树
|
||
type ProjectTreeNode = {
|
||
id: number
|
||
label: string
|
||
projectCode: string
|
||
projectName: string
|
||
}
|
||
const projectTreeSearch = ref('')
|
||
const projectTreeData = ref<ProjectTreeNode[]>([])
|
||
const selectedProjectKeys = ref<Array<string | number>>([])
|
||
const selectedProjectId = ref<number | undefined>(undefined)
|
||
const selectedProjectLabel = ref('')
|
||
|
||
const projectNodeProps = ({ option }: { option: TreeOption }): HTMLAttributes => {
|
||
return {
|
||
onClick() {
|
||
const id = option.id as number
|
||
if (selectedProjectId.value === id) {
|
||
selectedProjectId.value = undefined
|
||
selectedProjectKeys.value = []
|
||
selectedProjectLabel.value = ''
|
||
} else {
|
||
selectedProjectId.value = id
|
||
selectedProjectKeys.value = [id]
|
||
selectedProjectLabel.value = (option.projectCode as string) || (option.label as string) || ''
|
||
}
|
||
pagination.page = 1
|
||
loadData()
|
||
}
|
||
}
|
||
}
|
||
|
||
async function loadProjectTree() {
|
||
try {
|
||
const data = await orderItemApi.xmoptions({})
|
||
projectTreeData.value = (Array.isArray(data) ? data : []).map((item: any) => {
|
||
const projectCode = item?.additionParams?.projectCode || ''
|
||
const projectName = item?.label || ''
|
||
return {
|
||
id: Number(item.value),
|
||
label: projectCode || projectName,
|
||
projectCode,
|
||
projectName,
|
||
}
|
||
}).filter((n: ProjectTreeNode) => n.id && n.label)
|
||
} catch {
|
||
projectTreeData.value = []
|
||
}
|
||
}
|
||
|
||
|
||
|
||
// 表格数据
|
||
const tableData = ref<any>([])
|
||
const loading = ref(false)
|
||
const selectedIds = ref<any>([])
|
||
const pagination = reactive({
|
||
page: 1,
|
||
pageSize: 10,
|
||
itemCount: 0,
|
||
showSizePicker: true,
|
||
pageSizes: [10, 20, 50]
|
||
})
|
||
|
||
|
||
|
||
// 弹窗
|
||
const modalVisible = ref(false)
|
||
const modalTitle = ref('')
|
||
const importModalVisible = ref(false)
|
||
const formRef = ref()
|
||
const defaultFormData = {
|
||
id: '',
|
||
productionCode:'',
|
||
name: '',
|
||
code: '',
|
||
sort: '',
|
||
quantity: '',
|
||
projectId: '',
|
||
projectName:'',
|
||
parentId: '',
|
||
sfProduct: 0,
|
||
procurement: 0,
|
||
beginTime: null,
|
||
endTime: null,
|
||
actualStartTime: null,
|
||
actualEndTime: null,
|
||
assingWorkId: '',
|
||
assingWorkList:[],
|
||
assingWorkTime: null,
|
||
assingWorkOperationId: '',
|
||
assingWorkOperationTime: null,
|
||
starter: '',
|
||
orderCode: '',
|
||
routeCode: '',
|
||
workshopId: null as number | null,
|
||
}
|
||
const formData = reactive<any>({ ...defaultFormData })
|
||
|
||
// 字典选项(下拉框/单选框/复选框关联字典时使用)
|
||
const workshopList = ref<{ label: string; value: any; class: any }[]>([])
|
||
/** 部门全量(用于工段/车间名称解析) */
|
||
const deptNameMap = ref<Record<string, string>>({})
|
||
|
||
function resolveWorkshopLabel(val: any) {
|
||
if (val === null || val === undefined || val === '') return ''
|
||
const opt = workshopList.value.find(o =>
|
||
o.value === val ||
|
||
String(o.value) === String(val) ||
|
||
o.label === val ||
|
||
String(o.label) === String(val)
|
||
)
|
||
return opt?.label ?? String(val)
|
||
}
|
||
|
||
function resolveDeptName(val: any) {
|
||
if (val === null || val === undefined || val === '') return '-'
|
||
return deptNameMap.value[String(val)] || String(val)
|
||
}
|
||
|
||
// 工艺路线抽屉
|
||
const routeDrawerVisible = ref(false)
|
||
const routeDrawerLoading = ref(false)
|
||
const routeDrawerTitle = ref('工艺路线')
|
||
const routeDetail = ref<{
|
||
routeCode?: string
|
||
routeName?: string
|
||
stepList?: any[]
|
||
} | null>(null)
|
||
|
||
const routeStepColumns: DataTableColumns<any> = [
|
||
{ title: '工序号', key: 'operNumber', width: 72, align: 'center' },
|
||
{ title: '工序名称', key: 'processName', width: 110, align: 'center', ellipsis: { tooltip: true } },
|
||
{ title: '工序说明', key: 'operDescription', minWidth: 140, ellipsis: { tooltip: true } },
|
||
{
|
||
title: '工段',
|
||
key: 'sectionId',
|
||
width: 100,
|
||
align: 'center',
|
||
ellipsis: { tooltip: true },
|
||
render(row) { return resolveDeptName(row.sectionId) }
|
||
},
|
||
{
|
||
title: '生产车间',
|
||
key: 'workshopId',
|
||
width: 100,
|
||
align: 'center',
|
||
ellipsis: { tooltip: true },
|
||
render(row) { return resolveDeptName(row.workshopId) }
|
||
},
|
||
{ title: '活动量', key: 'activityQty', width: 80, align: 'center' },
|
||
{ title: '活动单位', key: 'activityUnit', width: 80, align: 'center' },
|
||
{ title: '控制码', key: 'optCtrlCodeName', width: 100, align: 'center', ellipsis: { tooltip: true } },
|
||
{
|
||
title: '委外',
|
||
key: 'isOutsource',
|
||
width: 64,
|
||
align: 'center',
|
||
render(row) {
|
||
return Number(row.isOutsource) === 1 ? '是' : '否'
|
||
}
|
||
},
|
||
]
|
||
|
||
async function openRouteDrawer(row: any) {
|
||
const code = row?.routeCode
|
||
if (!code) {
|
||
message.warning('该订单无工艺路线编码')
|
||
return
|
||
}
|
||
routeDrawerTitle.value = `工艺路线 · ${code}`
|
||
routeDrawerVisible.value = true
|
||
routeDrawerLoading.value = true
|
||
routeDetail.value = null
|
||
try {
|
||
const data: any = await orderItemApi.getRoute({
|
||
routeCode: code,
|
||
planId: row.id,
|
||
})
|
||
if (data) {
|
||
routeDetail.value = data
|
||
return
|
||
}
|
||
// 订单关联路线不存在时,回退查工艺路线主表
|
||
const master: any = await processRouteApi.getByCode(code)
|
||
if (master) {
|
||
routeDetail.value = {
|
||
routeCode: master.code,
|
||
routeName: master.name,
|
||
stepList: master.stepList || [],
|
||
}
|
||
} else {
|
||
message.warning('未查询到工艺路线')
|
||
}
|
||
} catch {
|
||
// 错误已在拦截器处理
|
||
} finally {
|
||
routeDrawerLoading.value = false
|
||
}
|
||
}
|
||
|
||
// 表单校验规则
|
||
const formRules = {
|
||
}
|
||
|
||
// 表格列(computed:字典异步加载后能触发表格重渲染)
|
||
const columns = computed(() => [
|
||
{
|
||
type: 'selection'
|
||
},
|
||
{
|
||
align:'center',
|
||
title: '生产令号',
|
||
key: 'mainCode',
|
||
width: '140'
|
||
},
|
||
{
|
||
align:'center',
|
||
title: '订单编号',
|
||
key: 'orderCode',
|
||
width:"120"
|
||
},
|
||
|
||
{
|
||
align:'center',
|
||
title: '物料名称',
|
||
key: 'name',
|
||
minWidth: 150,
|
||
},
|
||
{
|
||
align:'center',
|
||
title: '物料编码',
|
||
key: 'code',
|
||
width:"120"
|
||
},
|
||
|
||
{
|
||
align:'center',
|
||
title: '工艺路线编码',
|
||
key: 'routeCode',
|
||
width:"140",
|
||
render(row: any) {
|
||
const code = row.routeCode
|
||
if (!code) return '-'
|
||
return h(
|
||
'a',
|
||
{
|
||
class: 'route-code-link',
|
||
href: 'javascript:;',
|
||
style: {
|
||
color: '#2080f0',
|
||
textDecoration: 'underline',
|
||
cursor: 'pointer',
|
||
},
|
||
onClick: (e: MouseEvent) => {
|
||
e.preventDefault()
|
||
e.stopPropagation()
|
||
openRouteDrawer(row)
|
||
},
|
||
},
|
||
code
|
||
)
|
||
}
|
||
},
|
||
{
|
||
align:'center',
|
||
title: '生产车间',
|
||
key: 'workshopId',
|
||
width:"120",
|
||
render(row: any) {
|
||
const val = row.workshopId
|
||
// 兼容存部门 id 或车间名称(历史/金蝶草稿)
|
||
const opt = workshopList.value.find(o =>
|
||
o.value === val ||
|
||
String(o.value) === String(val) ||
|
||
o.label === val ||
|
||
String(o.label) === String(val)
|
||
)
|
||
if (!opt) return val ?? '-'
|
||
const tagType = opt.class && ['default', 'primary', 'info', 'success', 'warning', 'error'].includes(opt.class)
|
||
? opt.class
|
||
: 'info'
|
||
return h(NTag, { type: tagType, size: 'small' }, { default: () => opt.label })
|
||
}
|
||
},
|
||
// {
|
||
// align:'center',
|
||
// title: '产品序列',
|
||
// key: 'sort',
|
||
// width:"120"
|
||
// },
|
||
{
|
||
align:'center',
|
||
title: '生产数量',
|
||
key: 'quantity',
|
||
width:"120"
|
||
},
|
||
// {
|
||
// align:'center',
|
||
// title: '是否半成品',
|
||
// key: 'sfProduct',
|
||
// width:"120"
|
||
// },
|
||
// {
|
||
// align:'center',
|
||
// title: '是否采购',
|
||
// key: 'procurement',
|
||
// width:"120"
|
||
// },
|
||
{
|
||
align:'center',
|
||
title: '开始时间',
|
||
key: 'beginTime',
|
||
width:"160"
|
||
},
|
||
{
|
||
align:'center',
|
||
title: '结束时间',
|
||
key: 'endTime',
|
||
width:"160"
|
||
},
|
||
{
|
||
align:'center',
|
||
title: '实际开始时间',
|
||
key: 'actualStartTime',
|
||
width:"120"
|
||
},
|
||
{
|
||
align:'center',
|
||
title: '实际结束时间',
|
||
key: 'actualEndTime',
|
||
width:"120"
|
||
},
|
||
{
|
||
align:'center',
|
||
title: '派工操作人',
|
||
key: 'assingWorkOperationName',
|
||
width:"120"
|
||
},
|
||
{
|
||
align:'center',
|
||
title: '派工接收人',
|
||
key: 'assingWorkName',
|
||
width:"200"
|
||
},
|
||
{
|
||
align:'center',
|
||
title: '派工时间',
|
||
key: 'assingWorkTime',
|
||
width:"120"
|
||
},
|
||
{
|
||
align:'center',
|
||
title: '是否开工',
|
||
key: 'starter',
|
||
width:"120",
|
||
render(row: any) {
|
||
return row.starter === 1 ? '已开工' : '未开工'
|
||
}
|
||
},
|
||
{
|
||
align:'center',
|
||
title: '备注',
|
||
key: 'remark',
|
||
minWidth: 100,
|
||
},
|
||
{
|
||
align:'center',
|
||
title: '操作',
|
||
key: 'actions',
|
||
width: 260,
|
||
fixed:"right",
|
||
render(row:any) {
|
||
const buttons: ReturnType<typeof h>[] = []
|
||
|
||
if (hasPermission('biz:orderItem:edit')) {
|
||
buttons.push(h(NButton, {
|
||
size: 'small',
|
||
quaternary: true,
|
||
onClick: () => handleEdit(row),
|
||
}, {
|
||
default: () => [h(NIcon, null, { default: () => h(CreateOutline) }), ' 编辑'],
|
||
}))
|
||
}
|
||
// 未开工且有工艺路线的子订单可开工
|
||
if (hasPermission('biz:orderItem:startWork') && row.starter !== 1 && row.parentId && row.routeCode) {
|
||
buttons.push(h(NButton, {
|
||
size: 'small',
|
||
quaternary: true,
|
||
type: 'warning',
|
||
onClick: () => handleStartWork(row),
|
||
}, {
|
||
default: () => [h(NIcon, null, { default: () => h(PlayOutline) }), ' 开工'],
|
||
}))
|
||
}
|
||
if (hasPermission('biz:orderItem:reorderForm')) {
|
||
buttons.push(h(NButton, {
|
||
size: 'small',
|
||
quaternary: true,
|
||
type: 'info',
|
||
onClick: () => handleReorderForm(row, false),
|
||
}, {
|
||
default: () => [h(NIcon, null, { default: () => h(DocumentTextOutline) }), ' 补单'],
|
||
}))
|
||
}
|
||
|
||
return buttons.length > 0
|
||
? h('div', { style: { display: 'flex', alignItems: 'center', gap: '4px', flexWrap: 'nowrap', justifyContent: 'center' } }, buttons)
|
||
: '-'
|
||
}
|
||
}
|
||
])
|
||
|
||
//根据内容设置表格滚动条
|
||
let scrollX = ref(0)
|
||
|
||
function updateScrollX() {
|
||
const tableElement = document.querySelector('#my-table .n-data-table-table')
|
||
if (tableElement) {
|
||
// 使用 scrollWidth 可以获取表格内容的总宽度,确保滚动条出现
|
||
scrollX.value = tableElement.scrollWidth
|
||
} else {
|
||
scrollX.value = 2000;
|
||
}
|
||
};
|
||
|
||
// 加载数据
|
||
async function loadData() {
|
||
loading.value = true
|
||
try {
|
||
const res = await orderItemApi.page({
|
||
page: pagination.page,
|
||
pageSize: pagination.pageSize,
|
||
projectId: selectedProjectId.value,
|
||
code: searchForm.code || undefined,
|
||
projectName: searchForm.projectName || undefined,
|
||
beginTime: searchForm.beginTime,
|
||
endTime: searchForm.endTime
|
||
})
|
||
tableData.value = res.list
|
||
pagination.itemCount = res.total
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
// 搜索
|
||
function handleSearch() {
|
||
pagination.page = 1
|
||
loadData()
|
||
}
|
||
|
||
// 重置
|
||
function handleReset() {
|
||
searchForm.code = ''
|
||
searchForm.projectName = ''
|
||
searchForm.orderCode = ''
|
||
searchForm.routeCode = ''
|
||
searchForm.workshopId = null
|
||
searchForm.beginTime = null
|
||
searchForm.endTime = null
|
||
selectedProjectId.value = undefined
|
||
selectedProjectKeys.value = []
|
||
selectedProjectLabel.value = ''
|
||
projectTreeSearch.value = ''
|
||
handleSearch()
|
||
}
|
||
|
||
// 分页
|
||
function handlePageChange(page: number) {
|
||
pagination.page = page
|
||
loadData()
|
||
}
|
||
|
||
function handlePageSizeChange(pageSize: number) {
|
||
pagination.pageSize = pageSize
|
||
pagination.page = 1
|
||
loadData()
|
||
}
|
||
|
||
// 选择
|
||
function handleCheck(keys: Array<string | number>) {
|
||
selectedIds.value = keys as number[]
|
||
}
|
||
|
||
//工序
|
||
//根据生产令号查询工序
|
||
let planList = ref<any>([])
|
||
function gongxu(){
|
||
if(formData.code){
|
||
planList.value.splice(0)
|
||
orderItemApi.preCreation({
|
||
code:formData.code,
|
||
projectCode:formData.projectCode
|
||
}).then((rps:any) => {
|
||
planList.value = rps.planList ? rps.planList : []
|
||
formData.orderCode = rps.orderCode ?? ''
|
||
formData.routeCode = rps.routeCode ?? ''
|
||
formData.workshopId = rps.workshopId ?? null
|
||
if (rps.quantity != null) formData.quantity = rps.quantity
|
||
})
|
||
}else{
|
||
planList.value.splice(0)
|
||
formData.orderCode = ''
|
||
formData.routeCode = ''
|
||
formData.workshopId = null
|
||
}
|
||
}
|
||
|
||
function tuozChange() {
|
||
console.log(planList.value)
|
||
}
|
||
|
||
// function gxupdata(v:any) {
|
||
// console.log(planList.value,'planList')
|
||
// console.log(v,'gx')
|
||
// }
|
||
|
||
|
||
// 新增
|
||
function handleAdd() {
|
||
modalTitle.value = '新增生产订单'
|
||
|
||
Object.assign(formData, defaultFormData)
|
||
modalVisible.value = true
|
||
xmhand()
|
||
planList.value.splice(0)
|
||
}
|
||
|
||
//查询项目
|
||
let xmlist = ref<any>([])
|
||
let xmloading = ref(false)
|
||
|
||
|
||
async function xmhand() {
|
||
xmloading.value = true
|
||
xmlist.value = await orderItemApi.xmoptions({});
|
||
xmloading.value = false
|
||
}
|
||
|
||
let wllist = ref<any>([])
|
||
function xmselupdate(v:any,opt:any) {
|
||
planList.value.splice(0)
|
||
wllist.value.splice(0)
|
||
formData.code = ''
|
||
formData.orderCode = ''
|
||
formData.routeCode = ''
|
||
formData.workshopId = null
|
||
formData.projectName = opt.label
|
||
formData.projectCode = opt?.additionParams?.projectCode || ''
|
||
if(v){
|
||
wlhand(opt.value)
|
||
}
|
||
}
|
||
|
||
//根据项目查询物料
|
||
|
||
let wlloading = ref(false)
|
||
async function wlhand(v:any) {
|
||
wlloading.value = true
|
||
wllist.value = await orderItemApi.wloptions({projectId:v });
|
||
wlloading.value = false
|
||
}
|
||
|
||
const kingdeeOrderOtemId = ref<number | null>(null) // 记录当前正在查询的订单ID
|
||
const kingdeeModalVisible = ref(false)
|
||
const kingdeeModalTitle = ref('金蝶生产订单')
|
||
const kingdeeLoading = ref(false)
|
||
|
||
const kingdeeTableData = ref<KingdeeMoTableRow[]>([])
|
||
// const kingdeeExpandedKeys = ref<Array<string | number>>([])
|
||
|
||
async function reCrawlReorderForm(id:number,reCrawl:Boolean){
|
||
kingdeeLoading.value = true
|
||
try {
|
||
const data = await orderItemApi.preCreationInfo(id, {reCrawl:reCrawl})
|
||
kingdeeTableData.value = mapKingdeeMoListToTableRows(Array.isArray(data) ? data : [])
|
||
} finally {
|
||
kingdeeLoading.value = false
|
||
}
|
||
}
|
||
|
||
async function handleReorderForm(row:OrderItem, reCrawl:Boolean){
|
||
if (!row.id) {
|
||
message.warning('缺少物料订单ID,无法查询')
|
||
return
|
||
}
|
||
kingdeeOrderOtemId.value = row.id
|
||
kingdeeModalTitle.value = `金蝶生产订单${row.code ? ` - ${row.code}` : ''}`
|
||
kingdeeModalVisible.value = true
|
||
kingdeeTableData.value = []
|
||
await reCrawlReorderForm(row.id, reCrawl)
|
||
}
|
||
|
||
// 暂存金蝶生产订单数据(草稿)
|
||
async function holdTemporarilySave(id: number, data: KingdeePrdMo[]) {
|
||
try {
|
||
// 恢复数据结构,将 processRoutes 转换为 children
|
||
await orderItemApi.holdTemporarilySave(id, data)
|
||
} catch (error) {
|
||
// 错误拦截器已处理
|
||
}
|
||
}
|
||
|
||
// const synchronizationSave = async (id: number, data: KingdeePrdMo[], callback:Function) => {
|
||
// try {
|
||
// await orderItemApi.synchronizationSave(id, data) .then((rps:any) =>{
|
||
|
||
// }).catch((res) => {
|
||
// callback(res)
|
||
// })
|
||
// // 接口拿到数据,调用子的回调,回传结果
|
||
// } catch (err) {
|
||
// callback(err)
|
||
// }
|
||
// }
|
||
|
||
// 同步订单和计划表(通过 callback 回传结果,供子弹等待接口完成)
|
||
async function synchronizationSave(id: number, data: KingdeePrdMo[], callback: Function) {
|
||
try {
|
||
const rps = await orderItemApi.synchronizationSave(id, data)
|
||
callback(rps)
|
||
} catch (error) {
|
||
callback(null, error)
|
||
}
|
||
}
|
||
|
||
|
||
|
||
// 编辑
|
||
function handleEdit(row: OrderItem) {
|
||
modalTitle.value = '编辑生产订单'
|
||
modalVisible.value = true
|
||
planList.value.splice(0)
|
||
Object.assign(formData, row)
|
||
if(formData.sfProduct == null){
|
||
formData.sfProduct = 0
|
||
}
|
||
if(formData.procurement == null){
|
||
formData.procurement = 0
|
||
}
|
||
|
||
if(formData.assingWorkId){
|
||
formData.assingWorkList = formData.assingWorkId.split(',')
|
||
}
|
||
|
||
if (formData.beginTime && typeof formData.beginTime === 'string') {
|
||
formData.beginTime = new Date(formData.beginTime.replace(' ', 'T')).getTime()
|
||
}
|
||
if (formData.endTime && typeof formData.endTime === 'string') {
|
||
formData.endTime = new Date(formData.endTime.replace(' ', 'T')).getTime()
|
||
}
|
||
if (formData.actualStartTime && typeof formData.actualStartTime === 'string') {
|
||
formData.actualStartTime = new Date(formData.actualStartTime.replace(' ', 'T')).getTime()
|
||
}
|
||
if (formData.actualEndTime && typeof formData.actualEndTime === 'string') {
|
||
formData.actualEndTime = new Date(formData.actualEndTime.replace(' ', 'T')).getTime()
|
||
}
|
||
if (formData.createTime && typeof formData.createTime === 'string') {
|
||
formData.createTime = new Date(formData.createTime.replace(' ', 'T')).getTime()
|
||
}
|
||
if (formData.assingWorkTime && typeof formData.assingWorkTime === 'string') {
|
||
formData.assingWorkTime = new Date(formData.assingWorkTime.replace(' ', 'T')).getTime()
|
||
}
|
||
if (formData.assingWorkOperationTime && typeof formData.assingWorkOperationTime === 'string') {
|
||
formData.assingWorkOperationTime = new Date(formData.assingWorkOperationTime.replace(' ', 'T')).getTime()
|
||
}
|
||
|
||
slehand()
|
||
|
||
}
|
||
|
||
// 提交
|
||
async function handleSubmit() {
|
||
|
||
await formRef.value?.validate()
|
||
try {
|
||
const submitData = { ...formData } as OrderItem
|
||
if (typeof submitData.beginTime === 'number') {
|
||
submitData.beginTime = new Date(submitData.beginTime).toISOString().slice(0, 19).replace('T', ' ')
|
||
}
|
||
if (typeof submitData.endTime === 'number') {
|
||
submitData.endTime = new Date(submitData.endTime).toISOString().slice(0, 19).replace('T', ' ')
|
||
}
|
||
if (typeof submitData.actualStartTime === 'number') {
|
||
submitData.actualStartTime = new Date(submitData.actualStartTime).toISOString().slice(0, 19).replace('T', ' ')
|
||
}
|
||
if (typeof submitData.actualEndTime === 'number') {
|
||
submitData.actualEndTime = new Date(submitData.actualEndTime).toISOString().slice(0, 19).replace('T', ' ')
|
||
}
|
||
if (typeof submitData.createTime === 'number') {
|
||
submitData.createTime = new Date(submitData.createTime).toISOString().slice(0, 19).replace('T', ' ')
|
||
}
|
||
if (typeof submitData.assingWorkTime === 'number') {
|
||
submitData.assingWorkTime = new Date(submitData.assingWorkTime).toISOString().slice(0, 19).replace('T', ' ')
|
||
}
|
||
if (typeof submitData.assingWorkOperationTime === 'number') {
|
||
submitData.assingWorkOperationTime = new Date(submitData.assingWorkOperationTime).toISOString().slice(0, 19).replace('T', ' ')
|
||
}
|
||
|
||
|
||
|
||
if (submitData.id) {
|
||
await orderItemApi.update(submitData)
|
||
message.success('修改成功')
|
||
} else {
|
||
let savedata = Object.assign(
|
||
{},
|
||
submitData,
|
||
{
|
||
planList:planList.value
|
||
}
|
||
)
|
||
await orderItemApi.create(savedata)
|
||
message.success('新增成功')
|
||
}
|
||
modalVisible.value = false
|
||
loadData()
|
||
} catch (error) {
|
||
// 错误已在拦截器处理
|
||
}
|
||
}
|
||
|
||
//派工
|
||
let dispatchmodal = ref(false)
|
||
let dispatchform = reactive<any>({
|
||
id:'',
|
||
name:'',
|
||
//userid:'',
|
||
username:'',
|
||
assingWorkList:''
|
||
})
|
||
|
||
let yglist = ref<any>([])
|
||
|
||
const dispatchrules = {
|
||
assingWorkList:[{ required: true, message: '请选择员工', trigger: 'blur' }]
|
||
}
|
||
|
||
function updatesle(v:any) {
|
||
dispatchform.assingWorkList = v.join()
|
||
console.log(v)
|
||
}
|
||
|
||
let dispatchLoading = ref(false)
|
||
let dispatchddbtn = ref(false)
|
||
|
||
const dispatchformRef = ref()
|
||
|
||
let loadingRef = ref(false)
|
||
|
||
function slehand(v?:any) {
|
||
loadingRef.value = true
|
||
userApi.page({
|
||
page: 1,
|
||
pageSize: 200,
|
||
username: v,
|
||
}).then((rps:any) =>{
|
||
if(rps.list && rps.list.length > 0){
|
||
yglist.value = rps.list.map((n:any) => {
|
||
return {
|
||
label:n.username,
|
||
value:n.id+''
|
||
}
|
||
})
|
||
}
|
||
console.log(yglist.value,'12')
|
||
loadingRef.value = false
|
||
}).catch(() => {
|
||
loadingRef.value = false
|
||
})
|
||
}
|
||
|
||
function disphand(v:any){
|
||
dispatchmodal.value = true
|
||
dispatchformRef.value?.restoreValidation()
|
||
dispatchform.id = v.id
|
||
dispatchform.name = v.name
|
||
//dispatchform.userid = ''
|
||
dispatchform.assingWorkList = ''
|
||
slehand()
|
||
}
|
||
|
||
function dispatchSubmit() {
|
||
|
||
dispatchformRef.value?.validate((v:any) => {
|
||
if(!v){
|
||
// dispatchLoading.value = true
|
||
// dispatchddbtn.value = true
|
||
// message.success('操作成功!')
|
||
// setTimeout(()=> {
|
||
// dispatchmodal.value = false
|
||
// dispatchform.value = false
|
||
// dispatchLoading.value = false
|
||
// dispatchddbtn.value = false
|
||
// loadData()
|
||
// },1000)
|
||
orderItemApi.assignWork(Object.assign({},dispatchform,{assingWorkList:dispatchform.assingWorkList.split(',')}) ).then(() => {
|
||
message.success('操作成功!')
|
||
setTimeout(()=> {
|
||
dispatchmodal.value = false
|
||
dispatchLoading.value = false
|
||
dispatchddbtn.value = false
|
||
loadData()
|
||
},1000)
|
||
}).catch(() => {
|
||
dispatchddbtn.value = false
|
||
dispatchLoading.value = false
|
||
})
|
||
}
|
||
})
|
||
}
|
||
|
||
// 删除
|
||
function handleDelete(row: OrderItem) {
|
||
dialog.warning({
|
||
title: '提示',
|
||
content: '确定要删除该记录吗?',
|
||
positiveText: '确定',
|
||
negativeText: '取消',
|
||
onPositiveClick: async () => {
|
||
try {
|
||
await orderItemApi.delete([row.id!])
|
||
message.success('删除成功')
|
||
loadData()
|
||
} catch (error) {
|
||
// 错误已在拦截器处理
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
// 开工:生成工单
|
||
function handleStartWork(row: OrderItem) {
|
||
dialog.warning({
|
||
title: '提示',
|
||
content: `确定开工订单【${row.orderCode || row.name}】?开工后将生成执行订单与工单,派工请在工单侧操作。`,
|
||
positiveText: '确定',
|
||
negativeText: '取消',
|
||
onPositiveClick: async () => {
|
||
try {
|
||
await orderItemApi.startWork(row.id!)
|
||
message.success('开工成功')
|
||
loadData()
|
||
} catch (error) {
|
||
// 错误已在拦截器处理
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
// 批量删除
|
||
function handleBatchDelete() {
|
||
dialog.warning({
|
||
title: '提示',
|
||
content: `确定要删除选中的 ${selectedIds.value.length} 条记录吗?`,
|
||
positiveText: '确定',
|
||
negativeText: '取消',
|
||
onPositiveClick: async () => {
|
||
try {
|
||
await orderItemApi.delete(selectedIds.value)
|
||
message.success('删除成功')
|
||
selectedIds.value = []
|
||
loadData()
|
||
} catch (error) {
|
||
// 错误已在拦截器处理
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
// 导出
|
||
async function handleExport() {
|
||
try {
|
||
const params: Record<string, any> = {}
|
||
if (selectedIds.value.length > 0) params.ids = selectedIds.value
|
||
if (searchForm.productionCode) params.productionCode = searchForm.productionCode
|
||
if (searchForm.code) params.code = searchForm.code
|
||
if (searchForm.projectName) params.projectName = searchForm.projectName
|
||
if (searchForm.orderCode) params.orderCode = searchForm.orderCode
|
||
if (searchForm.routeCode) params.routeCode = searchForm.routeCode
|
||
if (searchForm.workshopId) params.workshopId = searchForm.workshopId
|
||
if (searchForm.beginTime != null) params.beginTime = searchForm.beginTime
|
||
if (searchForm.endTime != null) params.endTime = searchForm.endTime
|
||
const blob = await orderItemApi.export(params)
|
||
const url = window.URL.createObjectURL(blob)
|
||
const link = document.createElement('a')
|
||
link.href = url
|
||
link.download = '生产订单数据.xlsx'
|
||
link.click()
|
||
window.URL.revokeObjectURL(url)
|
||
} catch (error) {
|
||
// 错误已在拦截器处理
|
||
}
|
||
}
|
||
|
||
// 下载导入模板
|
||
async function handleDownloadTemplate() {
|
||
try {
|
||
const blob = await orderItemApi.downloadTemplate()
|
||
const url = window.URL.createObjectURL(blob)
|
||
const link = document.createElement('a')
|
||
link.href = url
|
||
link.download = '生产订单导入模板.xlsx'
|
||
link.click()
|
||
window.URL.revokeObjectURL(url)
|
||
} catch (error) {
|
||
// 错误已在拦截器处理
|
||
}
|
||
}
|
||
|
||
// 导入上传
|
||
async function handleImportUpload({ file }: UploadCustomRequestOptions) {
|
||
if (!file.file) return
|
||
try {
|
||
const result = await orderItemApi.importData(file.file)
|
||
if (result.fail > 0) {
|
||
dialog.warning({
|
||
title: '导入结果',
|
||
content: `成功: ${result.success} 条,失败: ${result.fail} 条\n错误信息: ${(result.errors || []).join('\n') || '无'}`,
|
||
positiveText: '确定'
|
||
})
|
||
} else {
|
||
message.success(`导入成功,共 ${result.success} 条数据`)
|
||
importModalVisible.value = false
|
||
}
|
||
loadData()
|
||
} catch (error) {
|
||
// 错误已在拦截器处理
|
||
}
|
||
}
|
||
|
||
// 加载车间选项(来自部门,不再使用字典)
|
||
async function loadWorkshopOptions() {
|
||
try {
|
||
const data = await deptApi.list()
|
||
const list = data || []
|
||
const map: Record<string, string> = {}
|
||
list.forEach((d: any) => {
|
||
if (d?.id != null) map[String(d.id)] = d.deptName || String(d.id)
|
||
})
|
||
deptNameMap.value = map
|
||
workshopList.value = list
|
||
.filter((d: any) => d.deptName && d.deptName.includes('车间'))
|
||
.map((d: any) => ({ label: d.deptName, value: d.id, class: 'info' }))
|
||
} catch {}
|
||
}
|
||
|
||
onMounted(() => {
|
||
loadProjectTree()
|
||
loadData()
|
||
loadWorkshopOptions()
|
||
|
||
updateScrollX()
|
||
window.addEventListener('resize', updateScrollX)
|
||
})
|
||
|
||
</script>
|
||
|
||
<style scoped>
|
||
.order-layout {
|
||
display: flex;
|
||
gap: 12px;
|
||
height: 100%;
|
||
}
|
||
|
||
.order-tree-card {
|
||
width: 280px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.order-tree-header {
|
||
font-weight: bold;
|
||
}
|
||
|
||
.order-search {
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.order-tree-wrapper {
|
||
height: calc(100vh - 280px);
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.order-list-card {
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
|
||
.card-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.search-form {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.table-toolbar {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
:deep(.route-code-link) {
|
||
color: #2080f0 !important;
|
||
cursor: pointer;
|
||
text-decoration: underline !important;
|
||
}
|
||
|
||
.route-desc {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.route-steps-title {
|
||
margin: 8px 0 12px;
|
||
font-weight: 600;
|
||
}
|
||
</style>
|