Merge branch 'master' of https://git.evo-techina.com/sgc/mes-vue
This commit is contained in:
commit
d0f1a35d70
@ -52,6 +52,48 @@ export interface OrderItem {
|
||||
proWorkshop?: string
|
||||
}
|
||||
|
||||
export interface KingdeePrdMo {
|
||||
productionOrderNo: string
|
||||
billNo: string
|
||||
workShopName: string
|
||||
materialCode: string
|
||||
quantity: number | null
|
||||
specModel: string | null
|
||||
unit: string | null
|
||||
materialName: string | null
|
||||
routingNo: string | null
|
||||
planStartTime: string | null
|
||||
planFinishTime: string | null
|
||||
pickMtrlStatus: string | null
|
||||
children: KingdeeProcessRoute[]
|
||||
}
|
||||
|
||||
|
||||
/** 金蝶工艺路线工序(树子节点) */
|
||||
export interface KingdeeProcessRoute {
|
||||
/** 工序号 FOperNumber */
|
||||
operNumber: number | null
|
||||
/** 工作中心 FWorkCenterId.FName */
|
||||
workCenterName: string | null
|
||||
/** 生产车间 FDepartmentId.FName */
|
||||
departmentName: string | null
|
||||
/** 工序名称 FProcessProperty */
|
||||
processName: string | null
|
||||
/** 工序说明 FOperDescription */
|
||||
operDescription: string | null
|
||||
/** 活动单位 FActivity1UnitID.FName */
|
||||
activityUnit: string | null
|
||||
/** 工序控制码 FOptCtrlCodeId.FName */
|
||||
optCtrlCodeName: string | null
|
||||
/** 活动量 FActivity1Qty */
|
||||
activityQty: number | null
|
||||
/** 计划开始时间 yyyy-MM-dd HH:mm:ss */
|
||||
planStartTime: string | null
|
||||
/** 计划结束时间 yyyy-MM-dd HH:mm:ss */
|
||||
planFinishTime: string | null
|
||||
}
|
||||
|
||||
|
||||
// 生产订单 API
|
||||
export const orderItemApi = {
|
||||
// 分页查询
|
||||
@ -86,6 +128,11 @@ export const orderItemApi = {
|
||||
preCreation(data: any) {
|
||||
return request({ url: '/biz/orderItem/preCreation', method: 'post', data })
|
||||
},
|
||||
//根据生产编号查询预生产订单
|
||||
preCreationInfo(id: number, params:any) {
|
||||
debugger;
|
||||
return request({ url: `/biz/orderItem/preCreation/${id}`, method: 'get', params})
|
||||
},
|
||||
|
||||
//查询项目名称
|
||||
xmoptions(params: any) {
|
||||
@ -96,6 +143,10 @@ export const orderItemApi = {
|
||||
wloptions(params: any) { //projectId
|
||||
return request({ url: '/biz/orderItem/options', method: 'get', params })
|
||||
},
|
||||
|
||||
holdTemporarilySave(id: number, data: KingdeePrdMo[]){
|
||||
return request({ url: `/biz/orderItem/kingdee/temporarily/save/${id}`, method: 'post', data })
|
||||
},
|
||||
|
||||
// 导出
|
||||
export(params?: {
|
||||
|
||||
@ -175,8 +175,8 @@ export const orderProjectApi = {
|
||||
},
|
||||
|
||||
// 查询金蝶生产订单 (支持优先读取本地暂存)
|
||||
getKingdeeOrder(id: number) {
|
||||
return request<KingdeePrdMo[]>({ url: `/biz/orderProject/kingdee/order/${id}`, method: 'get' })
|
||||
getKingdeeOrder(id: number, params:any) {
|
||||
return request<KingdeePrdMo[]>({ url: `/biz/orderProject/kingdee/order/${id}`, method: 'get', params })
|
||||
},
|
||||
|
||||
// 暂存金蝶生产订单数据(草稿)
|
||||
|
||||
458
src/views/biz/kingdee/index.vue
Normal file
458
src/views/biz/kingdee/index.vue
Normal file
@ -0,0 +1,458 @@
|
||||
<template>
|
||||
<div class="kingdee-toolbar">
|
||||
<n-space>
|
||||
<n-button
|
||||
size="small"
|
||||
:disabled="kingdeeLoading || !kingdeeTableData.length"
|
||||
@click="kingdeeToggleExpandAll"
|
||||
>
|
||||
{{ kingdeeAllExpanded ? '全部收起' : '全部展开' }}
|
||||
</n-button>
|
||||
<n-button
|
||||
size="small"
|
||||
type="primary"
|
||||
:disabled="kingdeeLoading || !kingdeeTableData.length"
|
||||
@click="handleGanttSchedule"
|
||||
>
|
||||
<template #icon><n-icon><CalendarOutline /></n-icon></template>
|
||||
甘特图排产
|
||||
</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
<n-data-table
|
||||
v-model:expanded-row-keys="kingdeeExpandedKeys"
|
||||
:columns="kingdeeMoColumns"
|
||||
:data="kingdeeTableData"
|
||||
:loading="kingdeeLoading"
|
||||
:row-key="kingdeeMoRowKey"
|
||||
:scroll-x="kingdeeMoScrollX"
|
||||
:max-height="kingdeeTableMaxHeight"
|
||||
:row-class-name="kingdeeMoRowClassName"
|
||||
size="small"
|
||||
style="margin-bottom:15px"
|
||||
/>
|
||||
<div style="margin-bottom: 1px;">
|
||||
<!-- <template #footer> -->
|
||||
<n-space justify="end">
|
||||
<n-button type="error" :disabled="kingdeeLoading" @click="reCrawlReorderForm">
|
||||
重新读取数据
|
||||
</n-button>
|
||||
<n-button type="primary" :disabled="kingdeeLoading" @click="handleSaveDraft">
|
||||
保存草稿
|
||||
</n-button>
|
||||
<n-button type="info" :disabled="kingdeeLoading" @click="handleSyncOrderAndPlan">
|
||||
同步订单计划
|
||||
</n-button>
|
||||
<n-button @click="$emit('close-modal')">关闭</n-button>
|
||||
</n-space>
|
||||
<!-- </template> -->
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, h, computed, defineProps, onMounted, watch, defineEmits} from 'vue'
|
||||
import { NButton, NSpace, NIcon, NTag, NDatePicker, NDataTable, useMessage, useDialog, type DataTableColumns } from 'naive-ui'
|
||||
import { type KingdeePrdMo, type KingdeeProcessRoute } from '@/api/orderProject'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { CalendarOutline } from '@vicons/ionicons5'
|
||||
|
||||
|
||||
const emit = defineEmits(['holdTemporarilyCallback', "synchronizationCallback","reCrawlCallback"])
|
||||
const dialog = useDialog()
|
||||
const message = useMessage()
|
||||
const router = useRouter()
|
||||
|
||||
const props = defineProps({
|
||||
kingdeeTableData: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
selectedId:{
|
||||
type: Number,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
kingdeeTableData.value = props.kingdeeTableData as KingdeeMoTableRow[]
|
||||
})
|
||||
|
||||
watch(()=>props.kingdeeTableData,()=>{
|
||||
kingdeeTableData.value = props.kingdeeTableData as KingdeeMoTableRow[]
|
||||
},{ deep: true } )
|
||||
|
||||
|
||||
const kingdeeModalVisible = ref(false)
|
||||
const kingdeeLoading = ref(false)
|
||||
/** 主表行:工序仅存 processRoutes,避免 children 触发树形重复行 */
|
||||
type KingdeeMoTableRow = Omit<KingdeePrdMo, 'children'> & { processRoutes: KingdeeProcessRoute[] }
|
||||
const kingdeeTableData = ref<KingdeeMoTableRow[]>([])
|
||||
const kingdeeExpandedKeys = ref<Array<string | number>>([])
|
||||
// const kingdeeCurrentProjectId = ref<number | null>(null) // 记录当前正在查询的订单ID
|
||||
const kingdeeTableMaxHeight = 'min(78vh, 720px)'
|
||||
const kingdeeMoScrollX = 1820
|
||||
const kingdeeProcessScrollX = 1360
|
||||
|
||||
const kingdeeMoColumns: DataTableColumns<KingdeeMoTableRow> = [
|
||||
{
|
||||
type: 'expand',
|
||||
expandable: () => true,
|
||||
renderExpand: (row) => renderKingdeeExpand(row),
|
||||
},
|
||||
{
|
||||
title: '类型', key: 'rowType', width: 96, align: 'center',
|
||||
render() {
|
||||
return h(NTag, { size: 'small', type: 'info', bordered: false }, { default: () => '生产订单' })
|
||||
}
|
||||
},
|
||||
{ title: '单据编号', key: 'billNo', width: 120, align: 'center', ellipsis: { tooltip: true } },
|
||||
{ title: '生产令号', key: 'productionOrderNo', width: 130, align: 'center', ellipsis: { tooltip: true } },
|
||||
{ title: '工艺路线', key: 'routingNo', width: 110, align: 'center', ellipsis: { tooltip: true } },
|
||||
{ title: '物料编码', key: 'materialCode', width: 180, ellipsis: { tooltip: true } },
|
||||
{ title: '物料名称', key: 'materialName', width: 160, ellipsis: { tooltip: true } },
|
||||
{
|
||||
title: '数量', key: 'quantity', width: 90, align: 'center',
|
||||
render(row) {
|
||||
return formatKingdeeQty(row.quantity)
|
||||
}
|
||||
},
|
||||
{ title: '生产车间', key: 'workShopName', width: 100, align: 'center', ellipsis: { tooltip: true } },
|
||||
{ title: '规格型号', key: 'specModel', width: 110, align: 'center', ellipsis: { tooltip: true } },
|
||||
{ title: '单位', key: 'unit', width: 60, align: 'center' },
|
||||
{
|
||||
title: '计划开工', key: 'planStartTime', width: 180, align: 'center',
|
||||
render(row) {
|
||||
return renderKingdeePlanPickerMo(row, 'planStartTime')
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '计划完工', key: 'planFinishTime', width: 180, align: 'center',
|
||||
render(row) {
|
||||
return renderKingdeePlanPickerMo(row, 'planFinishTime')
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '领料状态', key: 'pickMtrlStatus', width: 90, align: 'center',
|
||||
render(row) {
|
||||
const val = row.pickMtrlStatus
|
||||
return val != null ? (pickMtrlStatusMap[String(val)] ?? val) : '-'
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
const kingdeeProcessColumns: DataTableColumns<KingdeeProcessRoute> = [
|
||||
{
|
||||
title: '类型', key: 'rowType', width: 72, align: 'center',
|
||||
render() {
|
||||
return h(NTag, { size: 'small', type: 'warning', bordered: false }, { default: () => '工序' })
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '工序号', key: 'operNumber', width: 80, align: 'center',
|
||||
render(row) {
|
||||
return row.operNumber != null ? String(row.operNumber) : '-'
|
||||
}
|
||||
},
|
||||
{ title: '工序名称', key: 'processProperty', width: 100, align: 'center' },
|
||||
{ title: '工序说明', key: 'operDescription', width: 140, ellipsis: { tooltip: true } },
|
||||
{ title: '工作中心', key: 'workCenterName', width: 110, align: 'center', ellipsis: { tooltip: true } },
|
||||
{ title: '生产车间', key: 'departmentName', width: 110, align: 'center', ellipsis: { tooltip: true } },
|
||||
{
|
||||
title: '计划开始时间', key: 'planStartTime', width: 180, align: 'center',
|
||||
render(row) {
|
||||
return renderKingdeePlanPicker(row, 'planStartTime')
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '计划结束时间', key: 'planFinishTime', width: 180, align: 'center',
|
||||
render(row) {
|
||||
return renderKingdeePlanPicker(row, 'planFinishTime')
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '活动量', key: 'activityQty', width: 90, align: 'center',
|
||||
render(row) {
|
||||
return formatKingdeeQty(row.activityQty)
|
||||
}
|
||||
},
|
||||
{ title: '活动单位', key: 'activityUnit', width: 80, align: 'center' },
|
||||
{ title: '控制码', key: 'optCtrlCodeName', width: 120, align: 'center', ellipsis: { tooltip: true } },
|
||||
]
|
||||
|
||||
|
||||
|
||||
|
||||
const kingdeeAllExpanded = computed(() => {
|
||||
const total = kingdeeTableData.value.length
|
||||
if (!total) return false
|
||||
return kingdeeExpandedKeys.value.length >= total
|
||||
})
|
||||
|
||||
const pickMtrlStatusMap: Record<string, string> = {
|
||||
'1': '未领料',
|
||||
'2': '待定',
|
||||
'3': '已领料',
|
||||
}
|
||||
|
||||
function kingdeeMoRowClassName() {
|
||||
return 'kingdee-mo-row'
|
||||
}
|
||||
|
||||
|
||||
function formatDateTime(ts: number) {
|
||||
const d = new Date(ts)
|
||||
const pad = (n: number) => String(n).padStart(2, '0')
|
||||
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`
|
||||
}
|
||||
|
||||
function parseKingdeePlanTime(val: string | number | null | undefined): number | null {
|
||||
if (val == null || val === '') return null
|
||||
if (typeof val === 'number') return val
|
||||
const ts = new Date(val.replace(' ', 'T')).getTime()
|
||||
return Number.isNaN(ts) ? null : ts
|
||||
}
|
||||
|
||||
|
||||
function renderKingdeePlanPicker(row: KingdeeProcessRoute, field: 'planStartTime' | 'planFinishTime') {
|
||||
return h(NDatePicker, {
|
||||
value: parseKingdeePlanTime(row[field]),
|
||||
type: 'datetime',
|
||||
clearable: true,
|
||||
size: 'small',
|
||||
style: { width: '100%' },
|
||||
onUpdateValue: (val: number | null) => {
|
||||
row[field] = val != null ? formatDateTime(val) : null
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function renderKingdeePlanPickerMo(row: KingdeeMoTableRow, field: 'planStartTime' | 'planFinishTime') {
|
||||
return h(NDatePicker, {
|
||||
value: parseKingdeePlanTime(row[field]),
|
||||
type: 'datetime',
|
||||
clearable: true,
|
||||
size: 'small',
|
||||
style: { width: '100%' },
|
||||
onUpdateValue: (val: number | null) => {
|
||||
row[field] = val != null ? formatDateTime(val) : null
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
function formatKingdeeQty(val: number | null | undefined) {
|
||||
return val != null ? Number(val).toFixed(3) : '-'
|
||||
}
|
||||
|
||||
|
||||
function kingdeeMoRowKey(row: KingdeeMoTableRow) {
|
||||
return `mo-${row.productionOrderNo}-${row.billNo}`
|
||||
}
|
||||
|
||||
function kingdeeToggleExpandAll() {
|
||||
if (kingdeeAllExpanded.value) {
|
||||
kingdeeExpandedKeys.value = []
|
||||
} else {
|
||||
kingdeeExpandedKeys.value = kingdeeTableData.value.map(kingdeeMoRowKey)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function renderKingdeeExpand(row: KingdeeMoTableRow) {
|
||||
const routes = getKingdeeRoutes(row)
|
||||
if (!routes.length) {
|
||||
return h('div', { class: 'kingdee-expand-empty' }, '暂无工艺路线工序')
|
||||
}
|
||||
return h('div', { class: 'kingdee-expand-wrap' }, [
|
||||
h(NDataTable, {
|
||||
class: 'kingdee-process-table',
|
||||
columns: kingdeeProcessColumns,
|
||||
data: routes,
|
||||
rowKey: kingdeeProcessRowKey,
|
||||
size: 'small',
|
||||
bordered: true,
|
||||
striped: true,
|
||||
scrollX: kingdeeProcessScrollX,
|
||||
}),
|
||||
])
|
||||
}
|
||||
|
||||
function getKingdeeRoutes(mo: KingdeeMoTableRow) {
|
||||
return mo.processRoutes
|
||||
}
|
||||
function kingdeeProcessRowKey(row: KingdeeProcessRoute) {
|
||||
return `route-${row.operNumber}-${row.workCenterName}-${row.operDescription}`
|
||||
}
|
||||
|
||||
// 甘特图排产
|
||||
function handleGanttSchedule() {
|
||||
// 将待排产数据和当前项目ID存入 sessionStorage,供甘特图页面使用
|
||||
sessionStorage.setItem('gantt_schedule_data', JSON.stringify(kingdeeTableData.value))
|
||||
if (props.selectedId) {
|
||||
sessionStorage.setItem('gantt_project_id', String(props.selectedId))
|
||||
}
|
||||
// 跳转到甘特图排产独立页面
|
||||
router.push('/biz/orderProject/gantt')
|
||||
}
|
||||
|
||||
// 同步订单和计划表
|
||||
async function handleSyncOrderAndPlan() {
|
||||
if (!props.selectedId) return
|
||||
|
||||
kingdeeLoading.value = true
|
||||
try {
|
||||
// 恢复数据结构,将 processRoutes 转换为 children
|
||||
const draftData = kingdeeTableData.value.map(mo => {
|
||||
const { processRoutes, ...rest } = mo
|
||||
return { ...rest, children: processRoutes } as KingdeePrdMo
|
||||
})
|
||||
|
||||
emit('synchronizationCallback', props.selectedId, draftData)
|
||||
message.success('同步订单计划成功')
|
||||
kingdeeModalVisible.value = false
|
||||
} catch (error) {
|
||||
// 错误拦截器已处理
|
||||
} finally {
|
||||
kingdeeLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const reCrawlReorderForm = () => {
|
||||
// // 暂存金蝶生产订单数据(草稿)
|
||||
if (!props.selectedId) return
|
||||
|
||||
dialog.warning({
|
||||
title: '提示',
|
||||
content: '重启读取会导致当前页面数据全部重置, 确定需要重新读取吗?',
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
kingdeeLoading.value = true
|
||||
try {
|
||||
emit('reCrawlCallback', props.selectedId, true)
|
||||
message.success('重启读取成功')
|
||||
} catch (error) {
|
||||
// 错误拦截器已处理
|
||||
} finally {
|
||||
kingdeeLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
const handleSaveDraft = () => {
|
||||
// // 暂存金蝶生产订单数据(草稿)
|
||||
if (!props.selectedId) return
|
||||
|
||||
kingdeeLoading.value = true
|
||||
try {
|
||||
const draftData = kingdeeTableData.value.map(mo => {
|
||||
const { processRoutes, ...rest } = mo
|
||||
return { ...rest, children: processRoutes } as KingdeePrdMo
|
||||
})
|
||||
emit('holdTemporarilyCallback', props.selectedId, draftData)
|
||||
message.success('草稿保存成功')
|
||||
} catch (error) {
|
||||
// 错误拦截器已处理
|
||||
} finally {
|
||||
kingdeeLoading.value = false
|
||||
}
|
||||
|
||||
}
|
||||
// // 暂存金蝶生产订单数据(草稿)
|
||||
// async function handleSaveDraft() {
|
||||
// if (!kingdeeCurrentProjectId) return
|
||||
|
||||
// kingdeeLoading.value = true
|
||||
// try {
|
||||
// // 恢复数据结构,将 processRoutes 转换为 children
|
||||
// const draftData = kingdeeTableData.value.map(mo => {
|
||||
// const { processRoutes, ...rest } = mo
|
||||
// return { ...rest, children: processRoutes } as KingdeePrdMo
|
||||
// })
|
||||
|
||||
// emit('holdTemporarilyCallback', { id:kingdeeCurrentProjectId, data:draftData })
|
||||
// // await orderProjectApi.saveKingdeeOrderDraft(kingdeeCurrentProjectId.value, draftData)
|
||||
// // message.success('草稿保存成功')
|
||||
// } catch (error) {
|
||||
// // 错误拦截器已处理
|
||||
// } finally {
|
||||
// kingdeeLoading.value = false
|
||||
// }
|
||||
// }
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
.search-form {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.table-toolbar {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.kingdee-toolbar {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
:deep(.kingdee-modal .n-card) {
|
||||
max-height: 94vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
:deep(.kingdee-modal .n-card__content) {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
:deep(.kingdee-mo-row td) {
|
||||
background-color: rgba(32, 128, 240, 0.06) !important;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
:deep(.kingdee-mo-row:hover td) {
|
||||
background-color: rgba(32, 128, 240, 0.1) !important;
|
||||
}
|
||||
|
||||
.kingdee-expand-wrap {
|
||||
margin: 4px 8px 8px 36px;
|
||||
padding: 12px 14px 14px;
|
||||
border: 1px solid var(--n-border-color);
|
||||
border-left: 4px solid #18a058;
|
||||
border-radius: 6px;
|
||||
background: var(--n-action-color);
|
||||
}
|
||||
|
||||
:deep(.kingdee-process-table .n-data-table-th) {
|
||||
background: rgba(24, 160, 88, 0.12) !important;
|
||||
}
|
||||
|
||||
:deep(.kingdee-process-table .n-data-table-td) {
|
||||
background-color: var(--n-color) !important;
|
||||
}
|
||||
|
||||
:deep(.kingdee-process-table .n-data-table-tr--striped .n-data-table-td) {
|
||||
background-color: var(--n-action-color) !important;
|
||||
}
|
||||
|
||||
.kingdee-expand-empty {
|
||||
margin: 4px 8px 8px 36px;
|
||||
padding: 12px 14px;
|
||||
font-size: 13px;
|
||||
color: var(--n-text-color-3);
|
||||
border: 1px dashed var(--n-border-color);
|
||||
border-radius: 6px;
|
||||
background: var(--n-action-color);
|
||||
}
|
||||
</style>
|
||||
@ -34,7 +34,7 @@
|
||||
<!-- 工具栏 -->
|
||||
<div class="table-toolbar">
|
||||
<n-space>
|
||||
<n-button
|
||||
<!--<n-button
|
||||
size="small"
|
||||
type="primary"
|
||||
@click="handleAdd"
|
||||
@ -42,15 +42,15 @@
|
||||
<template #icon><n-icon><AddOutline /></n-icon></template>
|
||||
新增/补单
|
||||
</n-button>
|
||||
<!-- <n-button @click="importModalVisible = true">
|
||||
<n-button @click="importModalVisible = true">
|
||||
<template #icon><n-icon><CloudUploadOutline /></n-icon></template>
|
||||
导入
|
||||
</n-button>
|
||||
<n-button @click="handleExport">
|
||||
<template #icon><n-icon><DownloadOutline /></n-icon></template>
|
||||
导出{{ selectedIds.length > 0 ? `(${selectedIds.length})` : '' }}
|
||||
</n-button> -->
|
||||
<!-- <n-button type="error" :disabled="selectedIds.length === 0" @click="handleBatchDelete">
|
||||
</n-button>
|
||||
<n-button type="error" :disabled="selectedIds.length === 0" @click="handleBatchDelete">
|
||||
<template #icon><n-icon><TrashOutline /></n-icon></template>
|
||||
删除
|
||||
</n-button> -->
|
||||
@ -117,16 +117,11 @@
|
||||
</n-form-item>
|
||||
</n-gi> -->
|
||||
<n-gi>
|
||||
<n-form-item label="项目名称" path="projectCode">
|
||||
<!-- <n-input v-if="formData.id" v-model:value="formData.projectName" disabled placeholder="请选择项目名称" />
|
||||
-->
|
||||
|
||||
<n-form-item label="项目名称" path="project">
|
||||
<n-input v-if="formData.id" v-model:value="formData.projectName" disabled placeholder="请选择项目" />
|
||||
|
||||
<!--@search="xmhand"-->
|
||||
<n-select
|
||||
v-else
|
||||
v-model:value="formData.projectCode"
|
||||
v-model:value="formData.projectId"
|
||||
filterable
|
||||
placeholder="请选择项目"
|
||||
:options="xmlist"
|
||||
@ -350,77 +345,39 @@
|
||||
</n-space>
|
||||
</template>
|
||||
</n-modal>
|
||||
<!-- 导入弹窗 -->
|
||||
<!-- <n-modal v-model:show="importModalVisible" preset="card" title="导入生产订单" style="width: 500px">
|
||||
<n-space vertical>
|
||||
<n-alert type="info">
|
||||
<template #header>导入说明</template>
|
||||
<ul style="margin: 0; padding-left: 16px; line-height: 1.8">
|
||||
<li>请先下载导入模板,按模板格式填写数据</li>
|
||||
<li>支持 .xlsx 或 .xls 格式</li>
|
||||
</ul>
|
||||
</n-alert>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="handleDownloadTemplate">
|
||||
<template #icon><n-icon><DownloadOutline /></n-icon></template>
|
||||
下载模板
|
||||
</n-button>
|
||||
</n-space>
|
||||
<n-upload :max="1" accept=".xlsx,.xls" :show-file-list="true" :custom-request="handleImportUpload">
|
||||
<n-upload-dragger>
|
||||
<div style="margin-bottom: 12px">
|
||||
<n-icon size="48" :depth="3"><CloudUploadOutline /></n-icon>
|
||||
</div>
|
||||
<n-text style="font-size: 16px">点击或拖拽文件到此处上传</n-text>
|
||||
<n-p depth="3" style="margin: 8px 0 0 0">支持 .xlsx 或 .xls 格式</n-p>
|
||||
</n-upload-dragger>
|
||||
</n-upload>
|
||||
</n-space>
|
||||
<template #footer>
|
||||
<n-button @click="importModalVisible = false">关闭</n-button>
|
||||
</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"
|
||||
@close-modal="kingdeeModalVisible = false"
|
||||
@holdTemporarilyCallback="holdTemporarilySave"
|
||||
@synchronizationCallback="synchronizationSave"
|
||||
@reCrawlCallback="reCrawlReorderForm"/>
|
||||
</n-modal>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
ref,
|
||||
reactive,
|
||||
h,
|
||||
onMounted
|
||||
} from 'vue'
|
||||
import {
|
||||
NButton,
|
||||
NSpace,
|
||||
NIcon,
|
||||
//NUpload,
|
||||
useMessage,
|
||||
useDialog,
|
||||
//type DataTableColumns,
|
||||
type UploadCustomRequestOptions
|
||||
} from 'naive-ui'
|
||||
import {
|
||||
SearchOutline,
|
||||
RefreshOutline,
|
||||
AddOutline,
|
||||
//TrashOutline,
|
||||
//CreateOutline,
|
||||
// CloudUploadOutline,
|
||||
// DownloadOutline
|
||||
} from '@vicons/ionicons5'
|
||||
import {
|
||||
orderItemApi,
|
||||
type OrderItem
|
||||
} from '@/api/orderItem'
|
||||
|
||||
import { ref, reactive, h, onMounted } from 'vue'
|
||||
import { NButton, NSpace, NIcon, useMessage, useDialog, type UploadCustomRequestOptions} from 'naive-ui'
|
||||
import { orderItemApi, type OrderItem } from '@/api/orderItem'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
|
||||
import { VueDraggable } from 'vue-draggable-plus'
|
||||
|
||||
// import Gxitem from './gxitem.vue'
|
||||
|
||||
import KingdeeVue from '@/views/biz/kingdee/index.vue'
|
||||
|
||||
import { type KingdeePrdMo, type KingdeeProcessRoute } from '@/api/orderProject'
|
||||
import { userApi } from '@/api/system'
|
||||
|
||||
const message = useMessage()
|
||||
@ -632,19 +589,18 @@ const columns = [
|
||||
align:'center',
|
||||
title: '操作',
|
||||
key: 'actions',
|
||||
width: 140,
|
||||
width: 190,
|
||||
fixed: 'right',
|
||||
render(row:any) {
|
||||
|
||||
const buttons:any = []
|
||||
|
||||
|
||||
if(hasPermission('biz:orderItem:edit')){
|
||||
buttons.push(h(NButton, {
|
||||
size: 'small',
|
||||
type:'primary',
|
||||
ghost:true,
|
||||
onClick: () => { handleEdit(row) } },
|
||||
//{ default: () => [h(NIcon, null, { default: () => h(CreateOutline) }), ' 编辑' ]}
|
||||
{ default: () => '编辑'}
|
||||
))
|
||||
}
|
||||
@ -657,6 +613,15 @@ const columns = [
|
||||
{ default: () => '派工'}
|
||||
))
|
||||
}
|
||||
if(hasPermission('biz:orderItem:reorderForm')){
|
||||
buttons.push(h(NButton, {
|
||||
size: 'small',
|
||||
type:'info',
|
||||
ghost:true,
|
||||
onClick: () => handleReorderForm(row, false) }, //, disabled: row.starter !==1
|
||||
{ default: () => '补单'}
|
||||
))
|
||||
}
|
||||
|
||||
return buttons.length > 0 ? h(NSpace, {justify:'center'}, { default: () => buttons }) : '-'
|
||||
|
||||
@ -779,31 +744,14 @@ let xmlist = ref<any>([])
|
||||
let xmloading = ref(false)
|
||||
|
||||
|
||||
function xmhand() {
|
||||
async function xmhand() {
|
||||
xmloading.value = true
|
||||
orderItemApi.xmoptions({
|
||||
// page: 1,
|
||||
// pageSize: 100,
|
||||
// username: v,
|
||||
}).then((rps:any) =>{
|
||||
if(rps && rps.length > 0){
|
||||
xmlist.value = rps.map((n:any) => {
|
||||
return {
|
||||
label:n.label,
|
||||
value:n.value+''
|
||||
}
|
||||
})
|
||||
}
|
||||
xmloading.value = false
|
||||
}).catch(() => {
|
||||
xmloading.value = false
|
||||
})
|
||||
xmlist.value = await orderItemApi.xmoptions({});
|
||||
xmloading.value = false
|
||||
}
|
||||
|
||||
let wllist = ref<any>([])
|
||||
function xmselupdate(v:any,opt:any) {
|
||||
// console.log(v,'sle')
|
||||
// console.log(opt,'opt')
|
||||
planList.value.splice(0)
|
||||
wllist.value.splice(0)
|
||||
formData.code = ''
|
||||
@ -811,6 +759,7 @@ function xmselupdate(v:any,opt:any) {
|
||||
formData.routeCode = ''
|
||||
formData.proWorkshop = ''
|
||||
formData.projectName = opt.label
|
||||
formData.projectCode = opt?.additionParams?.projectCode || ''
|
||||
if(v){
|
||||
wlhand(opt.value)
|
||||
}
|
||||
@ -819,29 +768,73 @@ function xmselupdate(v:any,opt:any) {
|
||||
//根据项目查询物料
|
||||
|
||||
let wlloading = ref(false)
|
||||
function wlhand(v:any) {
|
||||
async function wlhand(v:any) {
|
||||
wlloading.value = true
|
||||
orderItemApi.wloptions({
|
||||
projectId:v
|
||||
// page: 1,
|
||||
// pageSize: 100,
|
||||
// username: v
|
||||
}).then((rps:any) =>{
|
||||
if(rps && rps.length > 0){
|
||||
wllist.value = rps.map((n:any) => {
|
||||
return {
|
||||
label:n.label,
|
||||
value:n.value+''
|
||||
}
|
||||
})
|
||||
}
|
||||
console.log(yglist.value,'12')
|
||||
wlloading.value = false
|
||||
}).catch(() => {
|
||||
wlloading.value = false
|
||||
})
|
||||
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)
|
||||
|
||||
type KingdeeMoTableRow = Omit<KingdeePrdMo, 'children'> & { processRoutes: KingdeeProcessRoute[] }
|
||||
const kingdeeTableData = ref<KingdeeMoTableRow[]>([])
|
||||
// const kingdeeExpandedKeys = ref<Array<string | number>>([])
|
||||
|
||||
async function reCrawlReorderForm(id:number,reCrawl:Boolean){
|
||||
try {
|
||||
const data = await orderItemApi.preCreationInfo(id, {reCrawl:reCrawl})
|
||||
kingdeeTableData.value = (Array.isArray(data) ? data : []).map((mo) => {
|
||||
const { children, ...rest } = mo
|
||||
const routes = [...(children ?? [])].sort((a, b) => (a.operNumber ?? 0) - (b.operNumber ?? 0)).map((r) => ({
|
||||
...r,
|
||||
planStartTime: r.planStartTime ?? null,
|
||||
planFinishTime: r.planFinishTime ?? null,
|
||||
}))
|
||||
return { ...rest, processRoutes: routes }
|
||||
})
|
||||
} 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
|
||||
kingdeeLoading.value = true
|
||||
reCrawlReorderForm(row.id, false)
|
||||
kingdeeLoading.value = false
|
||||
}
|
||||
|
||||
// 暂存金蝶生产订单数据(草稿)
|
||||
async function holdTemporarilySave(id: number, data: KingdeePrdMo[]) {
|
||||
try {
|
||||
// 恢复数据结构,将 processRoutes 转换为 children
|
||||
await orderItemApi.holdTemporarilySave(id, data)
|
||||
} catch (error) {
|
||||
// 错误拦截器已处理
|
||||
}
|
||||
}
|
||||
|
||||
// 同步订单和计划表
|
||||
async function synchronizationSave(id: number, data: KingdeePrdMo[]) {
|
||||
try {
|
||||
// 恢复数据结构,将 processRoutes 转换为 children
|
||||
await orderItemApi.synchronizationSave(id, data)
|
||||
} catch (error) {
|
||||
// 错误拦截器已处理
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 编辑
|
||||
function handleEdit(row: OrderItem) {
|
||||
modalTitle.value = '编辑生产订单'
|
||||
|
||||
@ -148,48 +148,13 @@
|
||||
:closable="false"
|
||||
:close-on-esc="false"
|
||||
>
|
||||
<div class="kingdee-toolbar">
|
||||
<n-space>
|
||||
<n-button
|
||||
size="small"
|
||||
:disabled="kingdeeLoading || !kingdeeTableData.length"
|
||||
@click="kingdeeToggleExpandAll"
|
||||
>
|
||||
{{ kingdeeAllExpanded ? '全部收起' : '全部展开' }}
|
||||
</n-button>
|
||||
<n-button
|
||||
size="small"
|
||||
type="primary"
|
||||
:disabled="kingdeeLoading || !kingdeeTableData.length"
|
||||
@click="handleGanttSchedule"
|
||||
>
|
||||
<template #icon><n-icon><CalendarOutline /></n-icon></template>
|
||||
甘特图排产
|
||||
</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
<n-data-table
|
||||
v-model:expanded-row-keys="kingdeeExpandedKeys"
|
||||
:columns="kingdeeMoColumns"
|
||||
:data="kingdeeTableData"
|
||||
:loading="kingdeeLoading"
|
||||
:row-key="kingdeeMoRowKey"
|
||||
:scroll-x="kingdeeMoScrollX"
|
||||
:max-height="kingdeeTableMaxHeight"
|
||||
:row-class-name="kingdeeMoRowClassName"
|
||||
size="small"
|
||||
/>
|
||||
<template #footer>
|
||||
<n-space justify="end">
|
||||
<n-button type="info" :disabled="kingdeeLoading" @click="handleSyncOrderAndPlan">
|
||||
同步订单计划
|
||||
</n-button>
|
||||
<n-button type="primary" :disabled="kingdeeLoading" @click="handleSaveDraft">
|
||||
保存草稿
|
||||
</n-button>
|
||||
<n-button @click="kingdeeModalVisible = false">关闭</n-button>
|
||||
</n-space>
|
||||
</template>
|
||||
<KingdeeVue
|
||||
:kingdeeTableData="kingdeeTableData"
|
||||
:selectedId="kingdeeCurrentProjectId"
|
||||
@close-modal="kingdeeModalVisible = false"
|
||||
@holdTemporarilyCallback="handleSaveDraft"
|
||||
@synchronizationCallback="handleSyncOrderAndPlan"
|
||||
@reCrawlCallback="reCrawlReorderForm"/>
|
||||
</n-modal>
|
||||
|
||||
<!-- 导入弹窗 -->
|
||||
@ -235,6 +200,9 @@ import { useUserStore } from '@/stores/user'
|
||||
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
|
||||
import KingdeeVue from '@/views/biz/kingdee/index.vue'
|
||||
|
||||
|
||||
const message = useMessage()
|
||||
const dialog = useDialog()
|
||||
const userStore = useUserStore()
|
||||
@ -451,7 +419,7 @@ const columns: DataTableColumns<OrderProject> = [
|
||||
const buttons = []
|
||||
if (hasPermission('biz:orderProject:getKingdeeOrder')) {
|
||||
buttons.push(
|
||||
h(NButton, { size: 'small', quaternary: true, type: 'info', onClick: () => handleKingdeeQuery(row) }, {
|
||||
h(NButton, { size: 'small', quaternary: true, type: 'info', onClick: () => handleKingdeeQuery(row, false) }, {
|
||||
default: () => [h(NIcon, null, { default: () => h(EyeOutline) }), ' 预生产查询']
|
||||
})
|
||||
)
|
||||
@ -691,8 +659,29 @@ function handleGanttSchedule() {
|
||||
router.push('/biz/orderProject/gantt')
|
||||
}
|
||||
|
||||
async function reCrawlReorderForm(id:number,reCrawl:Boolean){
|
||||
try {
|
||||
const data = await orderProjectApi.getKingdeeOrder(id,{reCrawl:reCrawl})
|
||||
kingdeeTableData.value = (Array.isArray(data) ? data : []).map((mo) => {
|
||||
const { children, ...rest } = mo
|
||||
const routes = [...(children ?? [])]
|
||||
.sort((a, b) => (a.operNumber ?? 0) - (b.operNumber ?? 0))
|
||||
.map((r) => normalizeKingdeeProcessRoute({
|
||||
...r,
|
||||
planStartTime: r.planStartTime ?? null,
|
||||
planFinishTime: r.planFinishTime ?? null,
|
||||
}))
|
||||
return { ...rest, processRoutes: routes }
|
||||
})
|
||||
if (kingdeeTableData.value.length === 0) {
|
||||
message.info('未查询到金蝶生产订单数据')
|
||||
}
|
||||
} finally {
|
||||
kingdeeLoading.value = false
|
||||
}
|
||||
}
|
||||
// 金蝶预生产查询
|
||||
async function handleKingdeeQuery(row: OrderProject) {
|
||||
async function handleKingdeeQuery(row: OrderProject,reCrawl:Boolean) {
|
||||
if (!row.id) {
|
||||
message.warning('缺少项目ID,无法查询')
|
||||
return
|
||||
@ -703,70 +692,98 @@ async function handleKingdeeQuery(row: OrderProject) {
|
||||
kingdeeLoading.value = true
|
||||
kingdeeTableData.value = []
|
||||
kingdeeExpandedKeys.value = []
|
||||
try {
|
||||
const data = await orderProjectApi.getKingdeeOrder(row.id)
|
||||
kingdeeTableData.value = (Array.isArray(data) ? data : []).map((mo) => {
|
||||
const { children, ...rest } = mo
|
||||
const routes = [...(children ?? [])]
|
||||
.sort((a, b) => (a.operNumber ?? 0) - (b.operNumber ?? 0))
|
||||
.map((r) => normalizeKingdeeProcessRoute({
|
||||
...r,
|
||||
planStartTime: r.planStartTime ?? null,
|
||||
planFinishTime: r.planFinishTime ?? null,
|
||||
}))
|
||||
return { ...rest, processRoutes: routes }
|
||||
})
|
||||
if (kingdeeTableData.value.length === 0) {
|
||||
message.info('未查询到金蝶生产订单数据')
|
||||
}
|
||||
} finally {
|
||||
kingdeeLoading.value = false
|
||||
}
|
||||
reCrawlReorderForm(row.id,reCrawl)
|
||||
// try {
|
||||
// const data = await orderProjectApi.getKingdeeOrder(row.id)
|
||||
// kingdeeTableData.value = (Array.isArray(data) ? data : []).map((mo) => {
|
||||
// const { children, ...rest } = mo
|
||||
// const routes = [...(children ?? [])]
|
||||
// .sort((a, b) => (a.operNumber ?? 0) - (b.operNumber ?? 0))
|
||||
// .map((r) => normalizeKingdeeProcessRoute({
|
||||
// ...r,
|
||||
// planStartTime: r.planStartTime ?? null,
|
||||
// planFinishTime: r.planFinishTime ?? null,
|
||||
// }))
|
||||
// return { ...rest, processRoutes: routes }
|
||||
// })
|
||||
// if (kingdeeTableData.value.length === 0) {
|
||||
// message.info('未查询到金蝶生产订单数据')
|
||||
// }
|
||||
// } finally {
|
||||
// kingdeeLoading.value = false
|
||||
// }
|
||||
}
|
||||
|
||||
// 暂存金蝶生产订单数据(草稿)
|
||||
async function handleSaveDraft() {
|
||||
if (!kingdeeCurrentProjectId.value) return
|
||||
|
||||
kingdeeLoading.value = true
|
||||
// 暂存金蝶生产订单数据(草稿)
|
||||
// async function holdTemporarilyCallback(id: number, data: KingdeePrdMo[]) {
|
||||
// await orderProjectApi.saveKingdeeOrderDraft(id, data)
|
||||
// }
|
||||
|
||||
// 暂存金蝶生产订单数据(草稿)
|
||||
async function handleSaveDraft(id: number, data: KingdeePrdMo[]) {
|
||||
try {
|
||||
// 恢复数据结构,将 processRoutes 转换为 children
|
||||
const draftData = kingdeeTableData.value.map(mo => {
|
||||
const { processRoutes, ...rest } = mo
|
||||
return { ...rest, children: processRoutes } as KingdeePrdMo
|
||||
})
|
||||
|
||||
await orderProjectApi.saveKingdeeOrderDraft(kingdeeCurrentProjectId.value, draftData)
|
||||
message.success('草稿保存成功')
|
||||
await orderProjectApi.saveKingdeeOrderDraft(id, data)
|
||||
} catch (error) {
|
||||
// 错误拦截器已处理
|
||||
} finally {
|
||||
kingdeeLoading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 同步订单和计划表
|
||||
async function handleSyncOrderAndPlan() {
|
||||
if (!kingdeeCurrentProjectId.value) return
|
||||
|
||||
kingdeeLoading.value = true
|
||||
async function handleSyncOrderAndPlan(id: number, data: KingdeePrdMo[]) {
|
||||
try {
|
||||
// 恢复数据结构,将 processRoutes 转换为 children
|
||||
const draftData = kingdeeTableData.value.map(mo => {
|
||||
const { processRoutes, ...rest } = mo
|
||||
return { ...rest, children: processRoutes } as KingdeePrdMo
|
||||
})
|
||||
|
||||
await orderProjectApi.saveKingdeeOrderAndPlan(kingdeeCurrentProjectId.value, draftData)
|
||||
message.success('同步订单计划成功')
|
||||
kingdeeModalVisible.value = false
|
||||
await orderProjectApi.saveKingdeeOrderAndPlan(id, data)
|
||||
} catch (error) {
|
||||
// 错误拦截器已处理
|
||||
} finally {
|
||||
kingdeeLoading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// // 暂存金蝶生产订单数据(草稿)
|
||||
// async function handleSaveDraft() {
|
||||
// if (!kingdeeCurrentProjectId.value) return
|
||||
|
||||
// kingdeeLoading.value = true
|
||||
// try {
|
||||
// // 恢复数据结构,将 processRoutes 转换为 children
|
||||
// const draftData = kingdeeTableData.value.map(mo => {
|
||||
// const { processRoutes, ...rest } = mo
|
||||
// return { ...rest, children: processRoutes } as KingdeePrdMo
|
||||
// })
|
||||
|
||||
// await orderProjectApi.saveKingdeeOrderDraft(kingdeeCurrentProjectId.value, draftData)
|
||||
// message.success('草稿保存成功')
|
||||
// } catch (error) {
|
||||
// // 错误拦截器已处理
|
||||
// } finally {
|
||||
// kingdeeLoading.value = false
|
||||
// }
|
||||
// }
|
||||
|
||||
// 同步订单和计划表
|
||||
// async function handleSyncOrderAndPlan() {
|
||||
// if (!kingdeeCurrentProjectId.value) return
|
||||
|
||||
// kingdeeLoading.value = true
|
||||
// try {
|
||||
// // 恢复数据结构,将 processRoutes 转换为 children
|
||||
// const draftData = kingdeeTableData.value.map(mo => {
|
||||
// const { processRoutes, ...rest } = mo
|
||||
// return { ...rest, children: processRoutes } as KingdeePrdMo
|
||||
// })
|
||||
|
||||
// await orderProjectApi.saveKingdeeOrderAndPlan(kingdeeCurrentProjectId.value, draftData)
|
||||
// message.success('同步订单计划成功')
|
||||
// kingdeeModalVisible.value = false
|
||||
// } catch (error) {
|
||||
// // 错误拦截器已处理
|
||||
// } finally {
|
||||
// kingdeeLoading.value = false
|
||||
// }
|
||||
// }
|
||||
|
||||
// 删除
|
||||
function handleDelete(row: OrderProject) {
|
||||
dialog.warning({
|
||||
|
||||
Loading…
Reference in New Issue
Block a user