Merge remote-tracking branch 'origin/feature/20260716/wms-module' into feature/20260716/wms-module
This commit is contained in:
@@ -92,5 +92,3 @@ export function operateTransportTask(data: {
|
||||
}) {
|
||||
return requestClient.post('/task/transport-task/operate', data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -14,5 +14,7 @@ export const ACTION_ICON = {
|
||||
BOOK: 'lucide:book',
|
||||
AUDIT: 'lucide:file-check',
|
||||
SEND: 'lucide:send',
|
||||
CIRCLE_CHECK: 'lucide:circle-check',
|
||||
CIRCLE_X: 'lucide:circle-x',
|
||||
CANCEL: 'lucide:ban',
|
||||
};
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type { VbenFormSchema } from '#/adapter/form';
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { BaseMaterialBaseApi } from '#/api/base/materialbase';
|
||||
import type {VbenFormSchema} from '#/adapter/form';
|
||||
import type {VxeTableGridOptions} from '#/adapter/vxe-table';
|
||||
import type {BaseMaterialBaseApi} from '#/api/base/materialbase';
|
||||
|
||||
import { handleTree } from '@vben/utils';
|
||||
import {handleTree} from '@vben/utils';
|
||||
|
||||
import { getClassStandardList, getClassStandardListByCode } from '#/api/base/classstandard';
|
||||
import { getSimpleMeasureUnitList } from '#/api/base/measureunit';
|
||||
import { getRangePickerDefaultProps } from '#/utils';
|
||||
import {getClassStandardList, getClassStandardListByCode} from '#/api/base/classstandard';
|
||||
import {getSimpleMeasureUnitList} from '#/api/base/measureunit';
|
||||
import {getRangePickerDefaultProps} from '#/utils';
|
||||
|
||||
// ========== 分类映射:classId → className ==========
|
||||
const classNameMap: Record<number, string> = {};
|
||||
@@ -46,102 +46,218 @@ async function loadMeasureUnitList() {
|
||||
// ========== 新增/修改的表单 ==========
|
||||
export function useFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
{ fieldName: 'materialId', component: 'Input', dependencies: { triggerFields: [''], show: () => false } },
|
||||
{ fieldName: 'materialCode', label: '物料编码', rules: 'required', component: 'Input', componentProps: { placeholder: '请输入物料编码' } },
|
||||
{ fieldName: 'materialName', label: '物料名称', rules: 'required', component: 'Input', componentProps: { placeholder: '请输入物料名称' } },
|
||||
{ fieldName: 'materialSpec', label: '规格', component: 'Input', componentProps: { placeholder: '请输入规格' } },
|
||||
{ fieldName: 'materialModel', label: '型号', component: 'Input', componentProps: { placeholder: '请输入型号' } },
|
||||
{ fieldName: 'englishName', label: '外文名称', component: 'Input', componentProps: { placeholder: '请输入外文名称' } },
|
||||
{
|
||||
fieldName: 'materialId',
|
||||
component: 'Input',
|
||||
dependencies: {triggerFields: [''], show: () => false}
|
||||
},
|
||||
{
|
||||
fieldName: 'materialCode',
|
||||
label: '物料编码',
|
||||
rules: 'required',
|
||||
component: 'Input',
|
||||
componentProps: {placeholder: '请输入物料编码'}
|
||||
},
|
||||
{
|
||||
fieldName: 'materialName',
|
||||
label: '物料名称',
|
||||
rules: 'required',
|
||||
component: 'Input',
|
||||
componentProps: {placeholder: '请输入物料名称'}
|
||||
},
|
||||
{
|
||||
fieldName: 'materialSpec',
|
||||
label: '规格',
|
||||
component: 'Input',
|
||||
componentProps: {placeholder: '请输入规格'}
|
||||
},
|
||||
{
|
||||
fieldName: 'materialModel',
|
||||
label: '型号',
|
||||
component: 'Input',
|
||||
componentProps: {placeholder: '请输入型号'}
|
||||
},
|
||||
{
|
||||
fieldName: 'englishName',
|
||||
label: '外文名称',
|
||||
component: 'Input',
|
||||
componentProps: {placeholder: '请输入外文名称'}
|
||||
},
|
||||
{
|
||||
fieldName: 'materialTypeId', label: '物料分类',
|
||||
component: 'ApiTreeSelect',
|
||||
componentProps: { api: loadMaterialTypeTree, labelField: 'className', valueField: 'classId', childrenField: 'children', placeholder: '请选择物料分类', allowClear: true, treeDefaultExpandAll: true },
|
||||
componentProps: {
|
||||
api: loadMaterialTypeTree,
|
||||
labelField: 'className',
|
||||
valueField: 'classId',
|
||||
childrenField: 'children',
|
||||
placeholder: '请选择物料分类',
|
||||
allowClear: true,
|
||||
treeDefaultExpandAll: true
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'baseUnitId', label: '基本计量单位', rules: 'required',
|
||||
component: 'ApiSelect',
|
||||
componentProps: { api: loadMeasureUnitList, labelField: 'unitCode', valueField: 'measureUnitId', placeholder: '请选择基本计量单位', allowClear: true },
|
||||
componentProps: {
|
||||
api: loadMeasureUnitList,
|
||||
labelField: 'unitCode',
|
||||
valueField: 'measureUnitId',
|
||||
placeholder: '请选择基本计量单位',
|
||||
allowClear: true
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'assUnitId', label: '辅助计量单位',
|
||||
component: 'ApiSelect',
|
||||
componentProps: { api: loadMeasureUnitList, labelField: 'unitCode', valueField: 'measureUnitId', placeholder: '请选择辅助计量单位', allowClear: true },
|
||||
componentProps: {
|
||||
api: loadMeasureUnitList,
|
||||
labelField: 'unitCode',
|
||||
valueField: 'measureUnitId',
|
||||
placeholder: '请选择辅助计量单位',
|
||||
allowClear: true
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'lenUnitId', label: '长度单位',
|
||||
component: 'ApiSelect',
|
||||
componentProps: { api: loadMeasureUnitList, labelField: 'unitCode', valueField: 'measureUnitId', placeholder: '请选择长度单位', allowClear: true },
|
||||
componentProps: {
|
||||
api: loadMeasureUnitList,
|
||||
labelField: 'unitCode',
|
||||
valueField: 'measureUnitId',
|
||||
placeholder: '请选择长度单位',
|
||||
allowClear: true
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'weightUnitId', label: '重量单位',
|
||||
component: 'ApiSelect',
|
||||
componentProps: { api: loadMeasureUnitList, labelField: 'unitCode', valueField: 'measureUnitId', placeholder: '请选择重量单位', allowClear: true },
|
||||
componentProps: {
|
||||
api: loadMeasureUnitList,
|
||||
labelField: 'unitCode',
|
||||
valueField: 'measureUnitId',
|
||||
placeholder: '请选择重量单位',
|
||||
allowClear: true
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'cubageUnitId', label: '体积单位',
|
||||
component: 'ApiSelect',
|
||||
componentProps: { api: loadMeasureUnitList, labelField: 'unitCode', valueField: 'measureUnitId', placeholder: '请选择体积单位', allowClear: true },
|
||||
componentProps: {
|
||||
api: loadMeasureUnitList,
|
||||
labelField: 'unitCode',
|
||||
valueField: 'measureUnitId',
|
||||
placeholder: '请选择体积单位',
|
||||
allowClear: true
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'isUsed', label: '是否启用', rules: 'required',
|
||||
component: 'RadioGroup',
|
||||
componentProps: { options: [{ label: '是', value: '1' }, { label: '否', value: '0' }], buttonStyle: 'solid', optionType: 'button' },
|
||||
componentProps: {
|
||||
options: [{label: '是', value: '1'}, {label: '否', value: '0'}],
|
||||
buttonStyle: 'solid',
|
||||
optionType: 'button'
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'extId',
|
||||
label: '外部标识',
|
||||
component: 'Input',
|
||||
componentProps: {placeholder: '请输入外部标识'}
|
||||
},
|
||||
{ fieldName: 'extId', label: '外部标识', component: 'Input', componentProps: { placeholder: '请输入外部标识' } },
|
||||
];
|
||||
}
|
||||
|
||||
// ========== 列表的搜索表单 ==========
|
||||
export function useGridFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
{ fieldName: 'materialCode', label: '物料编码', component: 'Input', componentProps: { allowClear: true, placeholder: '请输入物料编码' } },
|
||||
{ fieldName: 'materialName', label: '物料名称', component: 'Input', componentProps: { allowClear: true, placeholder: '请输入物料名称' } },
|
||||
{
|
||||
fieldName: 'materialCode',
|
||||
label: '物料编码',
|
||||
component: 'Input',
|
||||
componentProps: {allowClear: true, placeholder: '请输入物料编码'}
|
||||
},
|
||||
{
|
||||
fieldName: 'materialName',
|
||||
label: '物料名称',
|
||||
component: 'Input',
|
||||
componentProps: {allowClear: true, placeholder: '请输入物料名称'}
|
||||
},
|
||||
{
|
||||
fieldName: 'materialTypeId', label: '物料分类',
|
||||
component: 'ApiTreeSelect',
|
||||
componentProps: { api: loadMaterialTypeTree, labelField: 'className', valueField: 'classId', childrenField: 'children', placeholder: '请选择物料分类', allowClear: true },
|
||||
componentProps: {
|
||||
api: loadMaterialTypeTree,
|
||||
labelField: 'className',
|
||||
valueField: 'classId',
|
||||
childrenField: 'children',
|
||||
placeholder: '请选择物料分类',
|
||||
allowClear: true
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'createTime',
|
||||
label: '创建时间',
|
||||
component: 'RangePicker',
|
||||
componentProps: {...getRangePickerDefaultProps(), allowClear: true}
|
||||
},
|
||||
{
|
||||
fieldName: 'isUsed',
|
||||
label: '是否启用',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
placeholder: '请选择',
|
||||
options: [{label: '是', value: '1'}, {label: '否', value: '0'}]
|
||||
}
|
||||
},
|
||||
{ fieldName: 'createTime', label: '创建时间', component: 'RangePicker', componentProps: { ...getRangePickerDefaultProps(), allowClear: true } },
|
||||
{ fieldName: 'isUsed', label: '是否启用', component: 'Select', componentProps: { allowClear: true, placeholder: '请选择', options: [{ label: '是', value: '1' }, { label: '否', value: '0' }] } },
|
||||
];
|
||||
}
|
||||
|
||||
// ========== 列表的字段 ==========
|
||||
export function useGridColumns(): VxeTableGridOptions<BaseMaterialBaseApi.MaterialBase>['columns'] {
|
||||
return [
|
||||
{ type: 'checkbox', width: 40 },
|
||||
{ field: 'materialCode', title: '物料编码', minWidth: 120 },
|
||||
{ field: 'materialName', title: '物料名称', minWidth: 200 },
|
||||
{ field: 'materialSpec', title: '规格', minWidth: 120 },
|
||||
{ field: 'materialModel', title: '型号', minWidth: 120 },
|
||||
{ field: 'englishName', title: '外文名称', minWidth: 120 },
|
||||
{type: 'checkbox', width: 40},
|
||||
{field: 'materialCode', title: '物料编码', minWidth: 120},
|
||||
{field: 'materialName', title: '物料名称', minWidth: 200},
|
||||
{field: 'materialSpec', title: '规格', minWidth: 120},
|
||||
{field: 'materialModel', title: '型号', minWidth: 120},
|
||||
{field: 'englishName', title: '外文名称', minWidth: 120},
|
||||
{
|
||||
field: 'materialTypeId', title: '物料分类', minWidth: 150,
|
||||
formatter: ({ cellValue }: { cellValue: number }) => classNameMap[cellValue] || cellValue || '-',
|
||||
formatter: ({cellValue}: {
|
||||
cellValue: number
|
||||
}) => classNameMap[cellValue] || cellValue || '-',
|
||||
},
|
||||
{
|
||||
field: 'baseUnitId', title: '基本计量单位', minWidth: 120,
|
||||
formatter: ({ cellValue }: { cellValue: number }) => unitCodeMap[cellValue] || cellValue || '-',
|
||||
formatter: ({cellValue}: { cellValue: number }) => unitCodeMap[cellValue] || cellValue || '-',
|
||||
},
|
||||
{
|
||||
field: 'assUnitId', title: '辅助计量单位', minWidth: 120,
|
||||
formatter: ({ cellValue }: { cellValue: number }) => unitCodeMap[cellValue] || cellValue || '-',
|
||||
formatter: ({cellValue}: { cellValue: number }) => unitCodeMap[cellValue] || cellValue || '-',
|
||||
},
|
||||
{
|
||||
field: 'lenUnitId', title: '长度单位', minWidth: 120,
|
||||
formatter: ({ cellValue }: { cellValue: number }) => unitCodeMap[cellValue] || cellValue || '-',
|
||||
formatter: ({cellValue}: { cellValue: number }) => unitCodeMap[cellValue] || cellValue || '-',
|
||||
},
|
||||
{
|
||||
field: 'weightUnitId', title: '重量单位', minWidth: 120,
|
||||
formatter: ({ cellValue }: { cellValue: number }) => unitCodeMap[cellValue] || cellValue || '-',
|
||||
formatter: ({cellValue}: { cellValue: number }) => unitCodeMap[cellValue] || cellValue || '-',
|
||||
},
|
||||
{
|
||||
field: 'cubageUnitId', title: '体积单位', minWidth: 120,
|
||||
formatter: ({ cellValue }: { cellValue: number }) => unitCodeMap[cellValue] || cellValue || '-',
|
||||
formatter: ({cellValue}: { cellValue: number }) => unitCodeMap[cellValue] || cellValue || '-',
|
||||
},
|
||||
{ field: 'createTime', title: '创建时间', minWidth: 180, formatter: 'formatDateTime' },
|
||||
{ field: 'isUsed', title: '是否启用', minWidth: 100, formatter: ({ cellValue }: { cellValue: string }) => (cellValue === '1' ? '是' : '否') },
|
||||
{ field: 'extId', title: '外部标识', minWidth: 120 },
|
||||
{ title: '操作', width: 200, fixed: 'right', slots: { default: 'actions' } },
|
||||
{field: 'createTime', title: '创建时间', minWidth: 180, formatter: 'formatDateTime'},
|
||||
{
|
||||
field: 'isUsed',
|
||||
title: '是否启用',
|
||||
minWidth: 100,
|
||||
formatter: ({cellValue}: { cellValue: string }) => (cellValue === '1' ? '是' : '否')
|
||||
},
|
||||
{field: 'extId', title: '外部标识', minWidth: 120},
|
||||
{title: '操作', width: 200, fixed: 'right', slots: {default: 'actions'}},
|
||||
];
|
||||
}
|
||||
|
||||
@@ -4,12 +4,31 @@ import type { TaskTransportTaskApi } from '#/api/task/transporttask';
|
||||
|
||||
import { DICT_TYPE } from '@vben/constants';
|
||||
import { getDictOptions } from '@vben/hooks';
|
||||
import { handleTree } from '@vben/utils';
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import { getClassStandardListByCode } from '#/api/base/classstandard';
|
||||
import { getRangePickerDefaultProps } from '#/utils';
|
||||
|
||||
const taskTypeNameMap: Record<string, string> = {};
|
||||
|
||||
async function loadTaskTypeTree() {
|
||||
const data = await getClassStandardListByCode('0002');
|
||||
if (!data || data.length === 0) return [];
|
||||
return handleTree(data, 'classId', 'parentClassId');
|
||||
}
|
||||
|
||||
/** 新增/修改的表单 */
|
||||
export async function loadAllLookupData() {
|
||||
const taskTypeData = await getClassStandardListByCode('0002');
|
||||
taskTypeData?.forEach((item) => {
|
||||
if (item.classCode) {
|
||||
taskTypeNameMap[item.classCode] = item.className;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function useFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
@@ -369,11 +388,15 @@ export function useGridFormSchema(): VbenFormSchema[] {
|
||||
{
|
||||
fieldName: 'taskType',
|
||||
label: '任务类型',
|
||||
component: 'Select',
|
||||
component: 'ApiTreeSelect',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
options: [],
|
||||
api: loadTaskTypeTree,
|
||||
childrenField: 'children',
|
||||
labelField: 'className',
|
||||
placeholder: '请选择任务类型',
|
||||
treeDefaultExpandAll: true,
|
||||
valueField: 'classCode',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -588,6 +611,8 @@ export function useGridColumns(): VxeTableGridOptions<TaskTransportTaskApi.Trans
|
||||
field: 'taskType',
|
||||
title: '任务类型',
|
||||
minWidth: 120,
|
||||
formatter: ({ cellValue }: { cellValue: string }) =>
|
||||
taskTypeNameMap[cellValue] || cellValue || '-',
|
||||
},
|
||||
{
|
||||
field: 'acsTaskType',
|
||||
@@ -608,6 +633,10 @@ export function useGridColumns(): VxeTableGridOptions<TaskTransportTaskApi.Trans
|
||||
field: 'vehicleType',
|
||||
title: '载具类型',
|
||||
minWidth: 120,
|
||||
cellRender: {
|
||||
name: 'CellDict',
|
||||
props: { type: DICT_TYPE.WMS_VEHICLE_TYPE },
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'vehicleQty',
|
||||
@@ -632,6 +661,10 @@ export function useGridColumns(): VxeTableGridOptions<TaskTransportTaskApi.Trans
|
||||
field: 'isAutoIssue',
|
||||
title: '是否自动下发',
|
||||
minWidth: 120,
|
||||
cellRender: {
|
||||
name: 'CellDict',
|
||||
props: { type: DICT_TYPE.COMMON_IS_NO },
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'taskGroupId',
|
||||
@@ -671,6 +704,10 @@ export function useGridColumns(): VxeTableGridOptions<TaskTransportTaskApi.Trans
|
||||
field: 'createMode',
|
||||
title: '生成方式',
|
||||
minWidth: 120,
|
||||
cellRender: {
|
||||
name: 'CellDict',
|
||||
props: { type: DICT_TYPE.TASK_CREATE_MODE },
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'requestParam',
|
||||
@@ -706,10 +743,9 @@ export function useGridColumns(): VxeTableGridOptions<TaskTransportTaskApi.Trans
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
width: 300,
|
||||
width: 350,
|
||||
fixed: 'right',
|
||||
slots: { default: 'actions' },
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { TaskTransportTaskApi } from '#/api/task/transporttask';
|
||||
|
||||
import { ref } from 'vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
|
||||
import { confirm, Page, useVbenModal } from '@vben/common-ui';
|
||||
import { downloadFileFromBlobPart, isEmpty } from '@vben/utils';
|
||||
@@ -19,9 +19,15 @@ import {
|
||||
} from '#/api/task/transporttask';
|
||||
import { $t } from '#/locales';
|
||||
|
||||
import { useGridColumns, useGridFormSchema } from './data';
|
||||
import { loadAllLookupData, useGridColumns, useGridFormSchema } from './data';
|
||||
import Form from './modules/form.vue';
|
||||
|
||||
const ready = ref(false);
|
||||
onMounted(async () => {
|
||||
await loadAllLookupData();
|
||||
ready.value = true;
|
||||
});
|
||||
|
||||
const [FormModal, formModalApi] = useVbenModal({
|
||||
connectedComponent: Form,
|
||||
destroyOnClose: true,
|
||||
@@ -141,7 +147,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page auto-content-height>
|
||||
<Page v-if="ready" auto-content-height>
|
||||
<FormModal @success="handleRefresh" />
|
||||
<Grid table-title="搬运任务列表">
|
||||
<template #toolbar-tools>
|
||||
@@ -170,23 +176,31 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
label: '完成任务',
|
||||
label: '下发',
|
||||
type: 'link',
|
||||
icon: ACTION_ICON.SEND,
|
||||
auth: ['task:transport-task:issue'],
|
||||
disabled: row.taskStatus !== '40',
|
||||
onClick: handleOperate.bind(null, row, 'ISSUE', '下发任务'),
|
||||
},
|
||||
{
|
||||
label: '完成',
|
||||
type: 'link',
|
||||
icon: ACTION_ICON.CIRCLE_CHECK,
|
||||
auth: ['task:transport-task:finish'],
|
||||
disabled: ['79', '89', '99'].includes(row.taskStatus),
|
||||
disabled: ['79', '85', '89', '99'].includes(row.taskStatus),
|
||||
onClick: handleOperate.bind(null, row, 'FINISHED', '完成任务'),
|
||||
},
|
||||
{
|
||||
label: '取消任务',
|
||||
label: '取消',
|
||||
type: 'link',
|
||||
icon: ACTION_ICON.CANCEL,
|
||||
icon: ACTION_ICON.CIRCLE_X,
|
||||
auth: ['task:transport-task:cancel'],
|
||||
disabled: ['79', '89', '99'].includes(row.taskStatus),
|
||||
disabled: ['75', '79', '89', '99'].includes(row.taskStatus),
|
||||
onClick: handleOperate.bind(null, row, 'CANCELLED', '取消任务'),
|
||||
},
|
||||
{
|
||||
label: '强制完成任务',
|
||||
label: '强制完成',
|
||||
type: 'link',
|
||||
icon: ACTION_ICON.CANCEL,
|
||||
auth: ['task:transport-task:cancel'],
|
||||
|
||||
Reference in New Issue
Block a user