feat(mes): 优化 materialstock 的代码实现风格
parent
79af870afe
commit
e313de09c4
|
|
@ -1,11 +1,427 @@
|
||||||
import type { VbenFormSchema } from '#/adapter/form';
|
import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
|
||||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { MesProCardApi } from '#/api/mes/pro/card';
|
import type { MesProCardApi } from '#/api/mes/pro/card';
|
||||||
|
import type { MesProCardProcessApi } from '#/api/mes/pro/card/process';
|
||||||
|
|
||||||
import { markRaw } from 'vue';
|
import { h, markRaw } from 'vue';
|
||||||
|
|
||||||
|
import { DICT_TYPE } from '@vben/constants';
|
||||||
|
|
||||||
|
import { Button } from 'ant-design-vue';
|
||||||
|
|
||||||
|
import { generateAutoCode } from '#/api/mes/md/autocode/record';
|
||||||
import { MdItemSelect } from '#/views/mes/md/item/components';
|
import { MdItemSelect } from '#/views/mes/md/item/components';
|
||||||
|
import { MdWorkstationSelect } from '#/views/mes/md/workstation/components';
|
||||||
|
import { ProProcessSelect } from '#/views/mes/pro/process/components';
|
||||||
import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components';
|
import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components';
|
||||||
|
import {
|
||||||
|
MesAutoCodeRuleCode,
|
||||||
|
MesProWorkOrderStatusEnum,
|
||||||
|
} from '#/views/mes/utils/constants';
|
||||||
|
import { UserSelect } from '#/views/system/user/components';
|
||||||
|
|
||||||
|
/** 表单类型 */
|
||||||
|
export type FormType = 'create' | 'detail' | 'finish' | 'update';
|
||||||
|
|
||||||
|
/** 表头是否只读(完成、详情态) */
|
||||||
|
function isHeaderReadonly(formType: FormType): boolean {
|
||||||
|
return formType === 'detail' || formType === 'finish';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 新增/修改的表单 */
|
||||||
|
export function useFormSchema(
|
||||||
|
formType: FormType,
|
||||||
|
formApi?: VbenFormApi,
|
||||||
|
): VbenFormSchema[] {
|
||||||
|
const headerReadonly = isHeaderReadonly(formType);
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
fieldName: 'id',
|
||||||
|
component: 'Input',
|
||||||
|
dependencies: {
|
||||||
|
triggerFields: [''],
|
||||||
|
show: () => false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'status',
|
||||||
|
component: 'Input',
|
||||||
|
dependencies: {
|
||||||
|
triggerFields: [''],
|
||||||
|
show: () => false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'code',
|
||||||
|
label: '流转卡编码',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
disabled: headerReadonly,
|
||||||
|
placeholder: '请输入流转卡编码',
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
suffix:
|
||||||
|
formType === 'create' || formType === 'update'
|
||||||
|
? () =>
|
||||||
|
h(
|
||||||
|
Button,
|
||||||
|
{
|
||||||
|
type: 'default',
|
||||||
|
onClick: async () => {
|
||||||
|
const code = await generateAutoCode(
|
||||||
|
MesAutoCodeRuleCode.PRO_CARD_CODE,
|
||||||
|
);
|
||||||
|
await formApi?.setFieldValue('code', code);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ default: () => '生成' },
|
||||||
|
)
|
||||||
|
: undefined,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'workOrderId',
|
||||||
|
label: '生产工单',
|
||||||
|
component: markRaw(ProWorkOrderSelect),
|
||||||
|
componentProps: {
|
||||||
|
disabled: headerReadonly,
|
||||||
|
placeholder: '请选择生产工单',
|
||||||
|
status: MesProWorkOrderStatusEnum.CONFIRMED,
|
||||||
|
},
|
||||||
|
rules: 'selectRequired',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'itemId',
|
||||||
|
label: '产品',
|
||||||
|
component: markRaw(MdItemSelect),
|
||||||
|
componentProps: {
|
||||||
|
disabled: headerReadonly,
|
||||||
|
placeholder: '请选择产品',
|
||||||
|
},
|
||||||
|
rules: 'selectRequired',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'transferedQuantity',
|
||||||
|
label: '流转数量',
|
||||||
|
component: 'InputNumber',
|
||||||
|
componentProps: {
|
||||||
|
class: '!w-full',
|
||||||
|
disabled: headerReadonly,
|
||||||
|
min: 0,
|
||||||
|
placeholder: '请输入流转数量',
|
||||||
|
precision: 2,
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'batchCode',
|
||||||
|
label: '批次号',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
disabled: headerReadonly,
|
||||||
|
placeholder: '请输入批次号',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'remark',
|
||||||
|
label: '备注',
|
||||||
|
component: 'Textarea',
|
||||||
|
formItemClass: 'col-span-3',
|
||||||
|
componentProps: {
|
||||||
|
disabled: headerReadonly,
|
||||||
|
placeholder: '请输入备注',
|
||||||
|
rows: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 列表的搜索表单 */
|
||||||
|
export function useGridFormSchema(): VbenFormSchema[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
fieldName: 'code',
|
||||||
|
label: '流转卡编码',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
allowClear: true,
|
||||||
|
placeholder: '请输入流转卡编码',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'workOrderId',
|
||||||
|
label: '生产工单',
|
||||||
|
component: markRaw(ProWorkOrderSelect),
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请选择生产工单',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'itemId',
|
||||||
|
label: '产品',
|
||||||
|
component: markRaw(MdItemSelect),
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请选择产品',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'batchCode',
|
||||||
|
label: '批次号',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
allowClear: true,
|
||||||
|
placeholder: '请输入批次号',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 列表的字段 */
|
||||||
|
export function useGridColumns(): VxeTableGridOptions<MesProCardApi.Card>['columns'] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
field: 'code',
|
||||||
|
title: '流转卡编码',
|
||||||
|
width: 160,
|
||||||
|
slots: { default: 'code' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'workOrderCode',
|
||||||
|
title: '生产工单编号',
|
||||||
|
width: 160,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'workOrderName',
|
||||||
|
title: '工单名称',
|
||||||
|
minWidth: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'batchCode',
|
||||||
|
title: '批次号',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'itemCode',
|
||||||
|
title: '产品物料编码',
|
||||||
|
width: 140,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'itemName',
|
||||||
|
title: '产品物料名称',
|
||||||
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'specification',
|
||||||
|
title: '规格型号',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'unitMeasureName',
|
||||||
|
title: '单位',
|
||||||
|
width: 80,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'transferedQuantity',
|
||||||
|
title: '流转数量',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'status',
|
||||||
|
title: '单据状态',
|
||||||
|
minWidth: 100,
|
||||||
|
cellRender: {
|
||||||
|
name: 'CellDict',
|
||||||
|
props: { type: DICT_TYPE.MES_PRO_WORK_ORDER_STATUS },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
width: 240,
|
||||||
|
fixed: 'right',
|
||||||
|
slots: { default: 'actions' },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 工序记录子表的字段 */
|
||||||
|
export function useProcessGridColumns(
|
||||||
|
editable: boolean,
|
||||||
|
): VxeTableGridOptions<MesProCardProcessApi.CardProcess>['columns'] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
field: 'sort',
|
||||||
|
title: '序号',
|
||||||
|
width: 60,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'processName',
|
||||||
|
title: '工序名称',
|
||||||
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'processCode',
|
||||||
|
title: '工序编码',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'inputTime',
|
||||||
|
title: '进入工序时间',
|
||||||
|
width: 180,
|
||||||
|
formatter: 'formatDateTime',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'outputTime',
|
||||||
|
title: '出工序时间',
|
||||||
|
width: 180,
|
||||||
|
formatter: 'formatDateTime',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'inputQuantity',
|
||||||
|
title: '投入数量',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'outputQuantity',
|
||||||
|
title: '产出数量',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'unqualifiedQuantity',
|
||||||
|
title: '不良品数量',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'workstationCode',
|
||||||
|
title: '工位编码',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'workstationName',
|
||||||
|
title: '工位名称',
|
||||||
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'nickname',
|
||||||
|
title: '操作人',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
...(editable
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
width: 160,
|
||||||
|
fixed: 'right',
|
||||||
|
slots: { default: 'actions' },
|
||||||
|
} as const,
|
||||||
|
]
|
||||||
|
: []),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 工序记录新增/修改的表单 */
|
||||||
|
export function useProcessFormSchema(): VbenFormSchema[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
fieldName: 'sort',
|
||||||
|
label: '序号',
|
||||||
|
component: 'InputNumber',
|
||||||
|
componentProps: {
|
||||||
|
class: '!w-full',
|
||||||
|
min: 0,
|
||||||
|
placeholder: '请输入序号',
|
||||||
|
precision: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'processId',
|
||||||
|
label: '工序',
|
||||||
|
component: markRaw(ProProcessSelect),
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请选择工序',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'inputTime',
|
||||||
|
label: '进入工序时间',
|
||||||
|
component: 'DatePicker',
|
||||||
|
componentProps: {
|
||||||
|
class: '!w-full',
|
||||||
|
placeholder: '请选择进入工序时间',
|
||||||
|
showTime: true,
|
||||||
|
valueFormat: 'x',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'outputTime',
|
||||||
|
label: '出工序时间',
|
||||||
|
component: 'DatePicker',
|
||||||
|
componentProps: {
|
||||||
|
class: '!w-full',
|
||||||
|
placeholder: '请选择出工序时间',
|
||||||
|
showTime: true,
|
||||||
|
valueFormat: 'x',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'inputQuantity',
|
||||||
|
label: '投入数量',
|
||||||
|
component: 'InputNumber',
|
||||||
|
componentProps: {
|
||||||
|
class: '!w-full',
|
||||||
|
min: 0,
|
||||||
|
placeholder: '请输入投入数量',
|
||||||
|
precision: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'outputQuantity',
|
||||||
|
label: '产出数量',
|
||||||
|
component: 'InputNumber',
|
||||||
|
componentProps: {
|
||||||
|
class: '!w-full',
|
||||||
|
min: 0,
|
||||||
|
placeholder: '请输入产出数量',
|
||||||
|
precision: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'unqualifiedQuantity',
|
||||||
|
label: '不合格数量',
|
||||||
|
component: 'InputNumber',
|
||||||
|
componentProps: {
|
||||||
|
class: '!w-full',
|
||||||
|
min: 0,
|
||||||
|
placeholder: '请输入不合格数量',
|
||||||
|
precision: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'workstationId',
|
||||||
|
label: '工位',
|
||||||
|
component: markRaw(MdWorkstationSelect),
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请选择工位',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'userId',
|
||||||
|
label: '操作人',
|
||||||
|
component: markRaw(UserSelect),
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请选择操作人',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'remark',
|
||||||
|
label: '备注',
|
||||||
|
component: 'Textarea',
|
||||||
|
formItemClass: 'col-span-2',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入备注',
|
||||||
|
rows: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/** 流转卡选择弹窗的搜索表单 */
|
/** 流转卡选择弹窗的搜索表单 */
|
||||||
export function useCardSelectGridFormSchema(): VbenFormSchema[] {
|
export function useCardSelectGridFormSchema(): VbenFormSchema[] {
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,3 @@
|
||||||
|
export { default as GanttChart } from './gantt-chart.vue';
|
||||||
export { default as ProTaskSelectDialog } from './pro-task-select-dialog.vue';
|
export { default as ProTaskSelectDialog } from './pro-task-select-dialog.vue';
|
||||||
export { default as ProTaskSelect } from './pro-task-select.vue';
|
export { default as ProTaskSelect } from './pro-task-select.vue';
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,464 @@
|
||||||
import type { VbenFormSchema } from '#/adapter/form';
|
import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
|
||||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { MesProTaskApi } from '#/api/mes/pro/task';
|
import type { MesProTaskApi } from '#/api/mes/pro/task';
|
||||||
|
import type { MesProWorkOrderApi } from '#/api/mes/pro/workorder';
|
||||||
|
|
||||||
import { markRaw } from 'vue';
|
import { markRaw } from 'vue';
|
||||||
|
|
||||||
import { DICT_TYPE } from '@vben/constants';
|
import { DICT_TYPE } from '@vben/constants';
|
||||||
|
import { getDictOptions } from '@vben/hooks';
|
||||||
|
|
||||||
|
import { getRangePickerDefaultProps } from '#/utils';
|
||||||
|
import MdClientSelect from '#/views/mes/md/client/components/md-client-select.vue';
|
||||||
|
import { MdItemSelect } from '#/views/mes/md/item/components';
|
||||||
import { MdWorkstationSelect } from '#/views/mes/md/workstation/components';
|
import { MdWorkstationSelect } from '#/views/mes/md/workstation/components';
|
||||||
import { ProProcessSelect } from '#/views/mes/pro/process/components';
|
import { ProProcessSelect } from '#/views/mes/pro/process/components';
|
||||||
|
import { RouteColorPicker } from '#/views/mes/pro/route/components';
|
||||||
import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components';
|
import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components';
|
||||||
|
|
||||||
|
/** 待排产工单列表的搜索表单 */
|
||||||
|
export function useGridFormSchema(): VbenFormSchema[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
fieldName: 'code',
|
||||||
|
label: '工单编码',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
allowClear: true,
|
||||||
|
placeholder: '请输入工单编码',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'name',
|
||||||
|
label: '工单名称',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
allowClear: true,
|
||||||
|
placeholder: '请输入工单名称',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'orderSourceCode',
|
||||||
|
label: '来源单据',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
allowClear: true,
|
||||||
|
placeholder: '请输入来源单据编号',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'productId',
|
||||||
|
label: '产品',
|
||||||
|
component: markRaw(MdItemSelect),
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请选择产品',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'clientId',
|
||||||
|
label: '客户',
|
||||||
|
component: markRaw(MdClientSelect),
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请选择客户',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'requestDate',
|
||||||
|
label: '需求日期',
|
||||||
|
component: 'RangePicker',
|
||||||
|
componentProps: {
|
||||||
|
...getRangePickerDefaultProps(),
|
||||||
|
allowClear: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 待排产工单列表的字段 */
|
||||||
|
export function useGridColumns(): VxeTableGridOptions<MesProWorkOrderApi.WorkOrder>['columns'] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
field: 'code',
|
||||||
|
title: '工单编码',
|
||||||
|
fixed: 'left',
|
||||||
|
width: 200,
|
||||||
|
treeNode: true,
|
||||||
|
slots: { default: 'code' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'name',
|
||||||
|
title: '工单名称',
|
||||||
|
minWidth: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'orderSourceType',
|
||||||
|
title: '工单来源',
|
||||||
|
width: 100,
|
||||||
|
cellRender: {
|
||||||
|
name: 'CellDict',
|
||||||
|
props: { type: DICT_TYPE.MES_PRO_WORK_ORDER_SOURCE_TYPE },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'orderSourceCode',
|
||||||
|
title: '来源单据编号',
|
||||||
|
width: 140,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'productCode',
|
||||||
|
title: '产品编码',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'productName',
|
||||||
|
title: '产品名称',
|
||||||
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'productSpecification',
|
||||||
|
title: '规格型号',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'unitMeasureName',
|
||||||
|
title: '单位',
|
||||||
|
width: 80,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'quantity',
|
||||||
|
title: '工单数量',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'quantityChanged',
|
||||||
|
title: '调整数量',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'quantityProduced',
|
||||||
|
title: '已生产数量',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'clientCode',
|
||||||
|
title: '客户编码',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'clientName',
|
||||||
|
title: '客户名称',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'requestDate',
|
||||||
|
title: '需求日期',
|
||||||
|
width: 120,
|
||||||
|
formatter: 'formatDate',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'status',
|
||||||
|
title: '排产状态',
|
||||||
|
width: 100,
|
||||||
|
cellRender: {
|
||||||
|
name: 'CellDict',
|
||||||
|
props: { type: DICT_TYPE.MES_PRO_WORK_ORDER_STATUS },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
width: 100,
|
||||||
|
fixed: 'right',
|
||||||
|
slots: { default: 'actions' },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 排产对话框只读工单信息的表单 */
|
||||||
|
export function useScheduleFormSchema(): VbenFormSchema[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
fieldName: 'code',
|
||||||
|
label: '工单编码',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'name',
|
||||||
|
label: '工单名称',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'orderSourceType',
|
||||||
|
label: '工单来源',
|
||||||
|
component: 'Select',
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
options: getDictOptions(DICT_TYPE.MES_PRO_WORK_ORDER_SOURCE_TYPE, 'number'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'orderSourceCode',
|
||||||
|
label: '来源单据编号',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'type',
|
||||||
|
label: '工单类型',
|
||||||
|
component: 'Select',
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
options: getDictOptions(DICT_TYPE.MES_PRO_WORK_ORDER_TYPE, 'number'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'productId',
|
||||||
|
label: '产品',
|
||||||
|
component: markRaw(MdItemSelect),
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'productSpecification',
|
||||||
|
label: '规格型号',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'unitMeasureName',
|
||||||
|
label: '单位',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'quantity',
|
||||||
|
label: '工单数量',
|
||||||
|
component: 'InputNumber',
|
||||||
|
componentProps: {
|
||||||
|
class: '!w-full',
|
||||||
|
disabled: true,
|
||||||
|
precision: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'clientId',
|
||||||
|
label: '客户',
|
||||||
|
component: markRaw(MdClientSelect),
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'batchCode',
|
||||||
|
label: '批次号',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'requestDate',
|
||||||
|
label: '需求日期',
|
||||||
|
component: 'DatePicker',
|
||||||
|
componentProps: {
|
||||||
|
class: '!w-full',
|
||||||
|
disabled: true,
|
||||||
|
format: 'YYYY-MM-DD',
|
||||||
|
valueFormat: 'x',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'remark',
|
||||||
|
label: '备注',
|
||||||
|
component: 'Textarea',
|
||||||
|
formItemClass: 'col-span-3',
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
rows: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 生产任务子表的字段 */
|
||||||
|
export function useTaskGridColumns(
|
||||||
|
editable: boolean,
|
||||||
|
): VxeTableGridOptions<MesProTaskApi.Task>['columns'] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
field: 'code',
|
||||||
|
title: '任务编码',
|
||||||
|
width: 140,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'name',
|
||||||
|
title: '任务名称',
|
||||||
|
minWidth: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'workstationCode',
|
||||||
|
title: '工作站编号',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'workstationName',
|
||||||
|
title: '工作站名称',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'quantity',
|
||||||
|
title: '排产数量',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'producedQuantity',
|
||||||
|
title: '已生产数量',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'startTime',
|
||||||
|
title: '开始生产时间',
|
||||||
|
width: 170,
|
||||||
|
formatter: 'formatDateTime',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'duration',
|
||||||
|
title: '生产时长',
|
||||||
|
width: 80,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'endTime',
|
||||||
|
title: '预计完成时间',
|
||||||
|
width: 170,
|
||||||
|
formatter: 'formatDateTime',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'colorCode',
|
||||||
|
title: '显示颜色',
|
||||||
|
width: 100,
|
||||||
|
slots: { default: 'colorCode' },
|
||||||
|
},
|
||||||
|
...(editable
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
width: 160,
|
||||||
|
fixed: 'right',
|
||||||
|
slots: { default: 'actions' },
|
||||||
|
} as const,
|
||||||
|
]
|
||||||
|
: []),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 生产任务新增/修改的表单 */
|
||||||
|
export function useTaskFormSchema(formApi?: VbenFormApi): VbenFormSchema[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
fieldName: 'workstationId',
|
||||||
|
label: '工作站',
|
||||||
|
component: markRaw(MdWorkstationSelect),
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请选择工作站',
|
||||||
|
},
|
||||||
|
rules: 'selectRequired',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'quantity',
|
||||||
|
label: '排产数量',
|
||||||
|
component: 'InputNumber',
|
||||||
|
componentProps: {
|
||||||
|
class: '!w-full',
|
||||||
|
min: 0.01,
|
||||||
|
placeholder: '请输入排产数量',
|
||||||
|
precision: 2,
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'colorCode',
|
||||||
|
label: '甘特颜色',
|
||||||
|
component: markRaw(RouteColorPicker),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'startTime',
|
||||||
|
label: '开始时间',
|
||||||
|
component: 'DatePicker',
|
||||||
|
componentProps: {
|
||||||
|
class: '!w-full',
|
||||||
|
placeholder: '请选择开始时间',
|
||||||
|
showTime: true,
|
||||||
|
valueFormat: 'x',
|
||||||
|
// 开始时间变更:重新计算结束时间
|
||||||
|
onChange: () => recalcEndTime(formApi),
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'duration',
|
||||||
|
label: '生产时长',
|
||||||
|
component: 'InputNumber',
|
||||||
|
componentProps: {
|
||||||
|
class: '!w-full',
|
||||||
|
min: 1,
|
||||||
|
placeholder: '请输入生产时长',
|
||||||
|
precision: 0,
|
||||||
|
// 生产时长变更:重新计算结束时间
|
||||||
|
onChange: () => recalcEndTime(formApi),
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'endTime',
|
||||||
|
label: '结束时间',
|
||||||
|
component: 'DatePicker',
|
||||||
|
componentProps: {
|
||||||
|
class: '!w-full',
|
||||||
|
disabled: true,
|
||||||
|
showTime: true,
|
||||||
|
valueFormat: 'x',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'remark',
|
||||||
|
label: '备注',
|
||||||
|
component: 'Textarea',
|
||||||
|
formItemClass: 'col-span-3',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入备注',
|
||||||
|
rows: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 计算结束时间:开始时间 + 生产时长 × 8 小时 */
|
||||||
|
async function recalcEndTime(formApi?: VbenFormApi) {
|
||||||
|
if (!formApi) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const values = await formApi.getValues();
|
||||||
|
if (values.startTime && values.duration) {
|
||||||
|
const start = Number(values.startTime);
|
||||||
|
await formApi.setFieldValue(
|
||||||
|
'endTime',
|
||||||
|
start + values.duration * 8 * 3600 * 1000,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 任务选择弹窗的搜索表单 */
|
/** 任务选择弹窗的搜索表单 */
|
||||||
export function useTaskSelectGridFormSchema(): VbenFormSchema[] {
|
export function useTaskSelectGridFormSchema(): VbenFormSchema[] {
|
||||||
return [
|
return [
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
|
export { default as ProWorkOrderSelectDialog } from './pro-work-order-select-dialog.vue';
|
||||||
export { default as ProWorkOrderSelect } from './pro-work-order-select.vue';
|
export { default as ProWorkOrderSelect } from './pro-work-order-select.vue';
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,16 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { MesProWorkOrderApi } from '#/api/mes/pro/workorder';
|
import type { MesProWorkOrderApi } from '#/api/mes/pro/workorder';
|
||||||
|
|
||||||
import { computed, onMounted, ref, watch } from 'vue';
|
import { computed, ref, useAttrs, watch } from 'vue';
|
||||||
|
|
||||||
import { Select, Tag, Tooltip } from 'ant-design-vue';
|
import { IconifyIcon } from '@vben/icons';
|
||||||
|
|
||||||
import { getWorkOrder, getWorkOrderPage } from '#/api/mes/pro/workorder';
|
import { Input, Tooltip } from 'ant-design-vue';
|
||||||
|
|
||||||
|
import { getWorkOrder } from '#/api/mes/pro/workorder';
|
||||||
|
|
||||||
|
import ProWorkOrderSelectDialog from './pro-work-order-select-dialog.vue';
|
||||||
|
|
||||||
/**
|
|
||||||
* MES 生产工单选择器(轻量版)
|
|
||||||
*
|
|
||||||
* 当前用于安灯记录等只需要单选工单 ID 的业务页面:
|
|
||||||
* - 默认按 `status` 过滤拉取首页 100 条工单作为下拉
|
|
||||||
* - 编辑回显走 `getWorkOrder(id)`
|
|
||||||
* - 后续 `mes/pro/workorder` 完整迁移后,可替换为带弹窗的复杂选择器
|
|
||||||
*/
|
|
||||||
defineOptions({ name: 'ProWorkOrderSelect', inheritAttrs: false });
|
defineOptions({ name: 'ProWorkOrderSelect', inheritAttrs: false });
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
|
|
@ -22,7 +18,6 @@ const props = withDefaults(
|
||||||
allowClear?: boolean;
|
allowClear?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
modelValue?: number;
|
modelValue?: number;
|
||||||
pageSize?: number;
|
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
status?: number;
|
status?: number;
|
||||||
type?: number;
|
type?: number;
|
||||||
|
|
@ -31,7 +26,6 @@ const props = withDefaults(
|
||||||
allowClear: true,
|
allowClear: true,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
modelValue: undefined,
|
modelValue: undefined,
|
||||||
pageSize: 100,
|
|
||||||
placeholder: '请选择工单',
|
placeholder: '请选择工单',
|
||||||
status: undefined,
|
status: undefined,
|
||||||
type: undefined,
|
type: undefined,
|
||||||
|
|
@ -43,102 +37,104 @@ const emit = defineEmits<{
|
||||||
'update:modelValue': [value: number | undefined];
|
'update:modelValue': [value: number | undefined];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const allList = ref<MesProWorkOrderApi.WorkOrder[]>([]);
|
const attrs = useAttrs(); // 透传属性
|
||||||
const selectedItem = ref<MesProWorkOrderApi.WorkOrder>();
|
const dialogRef = ref<InstanceType<typeof ProWorkOrderSelectDialog>>(); // 工单选择弹窗
|
||||||
|
const hovering = ref(false); // 是否悬停
|
||||||
|
const selectedItem = ref<MesProWorkOrderApi.WorkOrder>(); // 当前选中工单
|
||||||
|
|
||||||
const selectValue = computed({
|
const displayLabel = computed(() => selectedItem.value?.code ?? ''); // 选择器展示编码
|
||||||
get: () => props.modelValue,
|
const showClear = computed(() => // 是否显示清空图标
|
||||||
set: (value: number | undefined) => {
|
props.allowClear &&
|
||||||
emit('update:modelValue', value);
|
!props.disabled &&
|
||||||
},
|
hovering.value &&
|
||||||
});
|
props.modelValue != null,
|
||||||
|
);
|
||||||
|
|
||||||
/** 前端过滤:按工单编码或名称模糊匹配 */
|
/** 根据编号单条查询工单信息(用于编辑回显) */
|
||||||
function handleFilter(input: string, option: any) {
|
async function resolveItemById(id: number | undefined) {
|
||||||
const keyword = input.toLowerCase();
|
if (id == null) {
|
||||||
const item = option?.item as MesProWorkOrderApi.WorkOrder | undefined;
|
|
||||||
return Boolean(
|
|
||||||
item?.code?.toLowerCase().includes(keyword) ||
|
|
||||||
item?.name?.toLowerCase().includes(keyword),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 同步选中工单详情,未在列表内时单独拉取 */
|
|
||||||
async function syncSelectedItem(value: number | undefined) {
|
|
||||||
if (value === undefined) {
|
|
||||||
selectedItem.value = undefined;
|
selectedItem.value = undefined;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const found = allList.value.find((item) => item.id === value);
|
if (selectedItem.value?.id === id) {
|
||||||
if (found) {
|
|
||||||
selectedItem.value = found;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
selectedItem.value = await getWorkOrder(id);
|
||||||
selectedItem.value = await getWorkOrder(value);
|
}
|
||||||
} catch (error) {
|
|
||||||
console.error('[ProWorkOrderSelect] resolveItemById failed:', error);
|
watch(() => props.modelValue, resolveItemById, { immediate: true });
|
||||||
|
|
||||||
|
/** 清空已选工单 */
|
||||||
|
function clearSelected() {
|
||||||
|
selectedItem.value = undefined;
|
||||||
|
emit('update:modelValue', undefined);
|
||||||
|
emit('change', undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 打开工单选择弹窗 */
|
||||||
|
function handleClick(event: MouseEvent) {
|
||||||
|
if (props.disabled) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
const target = event.target as HTMLElement;
|
||||||
|
if (showClear.value && target.closest('.ant-input-suffix')) {
|
||||||
|
event.stopPropagation();
|
||||||
|
clearSelected();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const selectedIds = props.modelValue == null ? [] : [props.modelValue];
|
||||||
|
dialogRef.value?.open(selectedIds, { multiple: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 除 v-model 外,额外抛出完整工单对象给业务表单使用 */
|
/** 弹窗选中回调 */
|
||||||
function handleChange(value: any) {
|
function handleSelected(rows: MesProWorkOrderApi.WorkOrder[]) {
|
||||||
const nextValue = value === undefined ? undefined : Number(value);
|
const item = rows[0];
|
||||||
syncSelectedItem(nextValue);
|
if (!item) {
|
||||||
emit('change', selectedItem.value);
|
return;
|
||||||
|
}
|
||||||
|
selectedItem.value = item;
|
||||||
|
emit('update:modelValue', item.id);
|
||||||
|
emit('change', item);
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.modelValue,
|
|
||||||
(value) => {
|
|
||||||
syncSelectedItem(value);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
const data = await getWorkOrderPage({
|
|
||||||
pageNo: 1,
|
|
||||||
pageSize: props.pageSize,
|
|
||||||
status: props.status,
|
|
||||||
type: props.type,
|
|
||||||
});
|
|
||||||
allList.value = data.list ?? [];
|
|
||||||
syncSelectedItem(props.modelValue);
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Tooltip :mouse-enter-delay="0.5" :open="selectedItem ? undefined : false">
|
<div
|
||||||
<template #title>
|
v-bind="attrs"
|
||||||
<div v-if="selectedItem" class="leading-6">
|
class="w-full"
|
||||||
<div>编码:{{ selectedItem.code || '-' }}</div>
|
:class="disabled ? 'cursor-not-allowed' : 'cursor-pointer'"
|
||||||
<div>名称:{{ selectedItem.name || '-' }}</div>
|
@click="handleClick"
|
||||||
<div>产品:{{ selectedItem.productName || '-' }}</div>
|
@mouseenter="hovering = true"
|
||||||
<div>数量:{{ selectedItem.quantity ?? '-' }}</div>
|
@mouseleave="hovering = false"
|
||||||
</div>
|
>
|
||||||
</template>
|
<Tooltip :mouse-enter-delay="0.5" :open="selectedItem ? undefined : false">
|
||||||
<Select
|
<template #title>
|
||||||
v-bind="$attrs"
|
<div v-if="selectedItem" class="leading-6">
|
||||||
v-model:value="selectValue"
|
<div>编码:{{ selectedItem.code || '-' }}</div>
|
||||||
:allow-clear="allowClear"
|
<div>名称:{{ selectedItem.name || '-' }}</div>
|
||||||
:disabled="disabled"
|
<div>产品:{{ selectedItem.productName || '-' }}</div>
|
||||||
:filter-option="handleFilter"
|
<div>数量:{{ selectedItem.quantity ?? '-' }}</div>
|
||||||
:placeholder="placeholder"
|
|
||||||
class="w-full"
|
|
||||||
show-search
|
|
||||||
@change="handleChange"
|
|
||||||
>
|
|
||||||
<Select.Option
|
|
||||||
v-for="item in allList"
|
|
||||||
:key="item.id"
|
|
||||||
:item="item"
|
|
||||||
:value="item.id"
|
|
||||||
>
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<span>{{ item.code }}</span>
|
|
||||||
<Tag v-if="item.name" color="default">{{ item.name }}</Tag>
|
|
||||||
</div>
|
</div>
|
||||||
</Select.Option>
|
</template>
|
||||||
</Select>
|
<Input
|
||||||
</Tooltip>
|
:disabled="disabled"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:value="displayLabel"
|
||||||
|
readonly
|
||||||
|
>
|
||||||
|
<template #suffix>
|
||||||
|
<IconifyIcon
|
||||||
|
class="size-4"
|
||||||
|
:icon="showClear ? 'lucide:circle-x' : 'lucide:search'"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</Input>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
<ProWorkOrderSelectDialog
|
||||||
|
ref="dialogRef"
|
||||||
|
:status="status"
|
||||||
|
:type="type"
|
||||||
|
@selected="handleSelected"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,3 @@
|
||||||
|
export { default as WmBatchDetail } from './wm-batch-detail.vue';
|
||||||
export { default as WmBatchSelectDialog } from './wm-batch-select-dialog.vue';
|
export { default as WmBatchSelectDialog } from './wm-batch-select-dialog.vue';
|
||||||
export { default as WmBatchSelect } from './wm-batch-select.vue';
|
export { default as WmBatchSelect } from './wm-batch-select.vue';
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,21 @@
|
||||||
import type { VbenFormSchema } from '#/adapter/form';
|
import type { VbenFormSchema } from '#/adapter/form';
|
||||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { MesWmBatchApi } from '#/api/mes/wm/batch';
|
import type { MesWmBatchApi } from '#/api/mes/wm/batch';
|
||||||
|
import type { DescriptionItemSchema } from '#/components/description';
|
||||||
|
|
||||||
import { markRaw } from 'vue';
|
import { h, markRaw } from 'vue';
|
||||||
|
|
||||||
import { DICT_TYPE } from '@vben/constants';
|
import { DICT_TYPE } from '@vben/constants';
|
||||||
import { getDictOptions } from '@vben/hooks';
|
import { getDictOptions } from '@vben/hooks';
|
||||||
|
import { formatDate } from '@vben/utils';
|
||||||
|
|
||||||
|
import { DictTag } from '#/components/dict-tag';
|
||||||
|
import { getRangePickerDefaultProps } from '#/utils';
|
||||||
import MdClientSelect from '#/views/mes/md/client/components/md-client-select.vue';
|
import MdClientSelect from '#/views/mes/md/client/components/md-client-select.vue';
|
||||||
import MdItemSelect from '#/views/mes/md/item/components/md-item-select.vue';
|
import MdItemSelect from '#/views/mes/md/item/components/md-item-select.vue';
|
||||||
import MdVendorSelect from '#/views/mes/md/vendor/components/md-vendor-select.vue';
|
import MdVendorSelect from '#/views/mes/md/vendor/components/md-vendor-select.vue';
|
||||||
import { MdWorkstationSelect } from '#/views/mes/md/workstation/components';
|
import { MdWorkstationSelect } from '#/views/mes/md/workstation/components';
|
||||||
|
import { ProTaskSelect } from '#/views/mes/pro/task/components';
|
||||||
import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components';
|
import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components';
|
||||||
import { TmToolSelect } from '#/views/mes/tm/tool/components';
|
import { TmToolSelect } from '#/views/mes/tm/tool/components';
|
||||||
|
|
||||||
|
|
@ -66,6 +71,14 @@ export function useBatchSelectGridFormSchema(): VbenFormSchema[] {
|
||||||
placeholder: '请选择工作站',
|
placeholder: '请选择工作站',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'taskId',
|
||||||
|
label: '生产任务',
|
||||||
|
component: markRaw(ProTaskSelect),
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请选择生产任务',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
fieldName: 'toolId',
|
fieldName: 'toolId',
|
||||||
label: '工具',
|
label: '工具',
|
||||||
|
|
@ -74,6 +87,15 @@ export function useBatchSelectGridFormSchema(): VbenFormSchema[] {
|
||||||
placeholder: '请选择工具',
|
placeholder: '请选择工具',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'moldId',
|
||||||
|
label: '模具编号',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
allowClear: true,
|
||||||
|
placeholder: '请输入模具编号',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
fieldName: 'salesOrderCode',
|
fieldName: 'salesOrderCode',
|
||||||
label: '销售订单编号',
|
label: '销售订单编号',
|
||||||
|
|
@ -111,6 +133,33 @@ export function useBatchSelectGridFormSchema(): VbenFormSchema[] {
|
||||||
placeholder: '请选择质量状态',
|
placeholder: '请选择质量状态',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'produceDate',
|
||||||
|
label: '生产日期',
|
||||||
|
component: 'RangePicker',
|
||||||
|
componentProps: {
|
||||||
|
...getRangePickerDefaultProps(),
|
||||||
|
allowClear: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'expireDate',
|
||||||
|
label: '有效期',
|
||||||
|
component: 'RangePicker',
|
||||||
|
componentProps: {
|
||||||
|
...getRangePickerDefaultProps(),
|
||||||
|
allowClear: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'receiptDate',
|
||||||
|
label: '入库日期',
|
||||||
|
component: 'RangePicker',
|
||||||
|
componentProps: {
|
||||||
|
...getRangePickerDefaultProps(),
|
||||||
|
allowClear: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -232,3 +281,92 @@ export function useBatchSelectGridColumns(
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 批次详情的描述字段 */
|
||||||
|
export function useDetailSchema(): DescriptionItemSchema[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
field: 'code',
|
||||||
|
label: '批次编号',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'itemCode',
|
||||||
|
label: '物料编码',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'itemName',
|
||||||
|
label: '物料名称',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'itemSpecification',
|
||||||
|
label: '规格型号',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'unitName',
|
||||||
|
label: '单位',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'lotNumber',
|
||||||
|
label: '生产批号',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'produceDate',
|
||||||
|
label: '生产日期',
|
||||||
|
render: (value) => (value ? formatDate(value, 'YYYY-MM-DD') : '-'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'expireDate',
|
||||||
|
label: '有效期',
|
||||||
|
render: (value) => (value ? formatDate(value, 'YYYY-MM-DD') : '-'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'receiptDate',
|
||||||
|
label: '入库日期',
|
||||||
|
render: (value) => (value ? formatDate(value, 'YYYY-MM-DD') : '-'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'vendorName',
|
||||||
|
label: '供应商',
|
||||||
|
render: (value) => value || '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'clientName',
|
||||||
|
label: '客户',
|
||||||
|
render: (value) => value || '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'workstationCode',
|
||||||
|
label: '工作站',
|
||||||
|
render: (value) => value || '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'purchaseOrderCode',
|
||||||
|
label: '采购订单编号',
|
||||||
|
render: (value) => value || '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'salesOrderCode',
|
||||||
|
label: '销售订单编号',
|
||||||
|
render: (value) => value || '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'workOrderCode',
|
||||||
|
label: '生产工单',
|
||||||
|
render: (value) => value || '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'qualityStatus',
|
||||||
|
label: '质量状态',
|
||||||
|
render: (value) =>
|
||||||
|
value == null
|
||||||
|
? '-'
|
||||||
|
: h(DictTag, { type: DICT_TYPE.MES_WM_QUALITY_STATUS, value }),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'remark',
|
||||||
|
label: '备注',
|
||||||
|
span: 3,
|
||||||
|
render: (value) => value || '-',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,7 @@ const emit = defineEmits<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const open = ref(false);
|
const open = ref(false);
|
||||||
const multiple = ref(true);
|
const multiple = ref(false); // 是否多选;默认按单选选择器使用
|
||||||
const syncingSingleSelection = ref(false);
|
|
||||||
const selectedRows = ref<MesWmMaterialStockApi.MaterialStock[]>([]);
|
const selectedRows = ref<MesWmMaterialStockApi.MaterialStock[]>([]);
|
||||||
const preSelectedIds = ref<number[]>([]);
|
const preSelectedIds = ref<number[]>([]);
|
||||||
const searchItemTypeId = ref<number>();
|
const searchItemTypeId = ref<number>();
|
||||||
|
|
@ -64,50 +63,37 @@ const alertTitle = computed(() => {
|
||||||
return `已按${parts.join('/')}预过滤`;
|
return `已按${parts.join('/')}预过滤`;
|
||||||
});
|
});
|
||||||
|
|
||||||
/** 单选模式同步 VXE 勾选状态 */
|
/** 获取多选记录,包含 VXE reserve 跨页记录 */
|
||||||
async function syncSingleSelection(row?: MesWmMaterialStockApi.MaterialStock) {
|
function getMultipleSelectedRows() {
|
||||||
syncingSingleSelection.value = true;
|
const selectedMap = new Map<number, MesWmMaterialStockApi.MaterialStock>();
|
||||||
await nextTick();
|
const records = [
|
||||||
await gridApi.grid.clearCheckboxRow();
|
...(gridApi.grid.getCheckboxReserveRecords?.() ?? []),
|
||||||
if (row) {
|
...(gridApi.grid.getCheckboxRecords?.() ?? []),
|
||||||
await gridApi.grid.setCheckboxRow(row, true);
|
] as MesWmMaterialStockApi.MaterialStock[];
|
||||||
}
|
records.forEach((row) => {
|
||||||
await nextTick();
|
const rowId = row.id;
|
||||||
syncingSingleSelection.value = false;
|
if (rowId !== undefined) {
|
||||||
|
selectedMap.set(rowId, row);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return [...selectedMap.values()];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 处理勾选变化 */
|
/** 处理多选勾选变化 */
|
||||||
async function handleCheckboxChange({
|
function handleCheckboxSelectChange() {
|
||||||
checked,
|
selectedRows.value = getMultipleSelectedRows();
|
||||||
records,
|
|
||||||
row,
|
|
||||||
}: {
|
|
||||||
checked: boolean;
|
|
||||||
records: MesWmMaterialStockApi.MaterialStock[];
|
|
||||||
row?: MesWmMaterialStockApi.MaterialStock;
|
|
||||||
}) {
|
|
||||||
if (syncingSingleSelection.value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!multiple.value) {
|
|
||||||
const selected = checked && row ? [row] : [];
|
|
||||||
selectedRows.value = selected;
|
|
||||||
await syncSingleSelection(selected[0]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
selectedRows.value = records;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 处理全选变化 */
|
/** 处理单选切换 */
|
||||||
function handleCheckboxAll({
|
function handleRadioChange(row: MesWmMaterialStockApi.MaterialStock) {
|
||||||
records,
|
selectedRows.value = [row];
|
||||||
}: {
|
}
|
||||||
records: MesWmMaterialStockApi.MaterialStock[];
|
|
||||||
}) {
|
/** 多选模式下切换行勾选 */
|
||||||
if (syncingSingleSelection.value) {
|
async function toggleMultipleRow(row: MesWmMaterialStockApi.MaterialStock) {
|
||||||
return;
|
const selected = gridApi.grid.isCheckedByCheckboxRow(row);
|
||||||
}
|
await gridApi.grid.setCheckboxRow(row, !selected);
|
||||||
selectedRows.value = records;
|
selectedRows.value = getMultipleSelectedRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 双击行:单选直接确认;多选切换勾选 */
|
/** 双击行:单选直接确认;多选切换勾选 */
|
||||||
|
|
@ -117,33 +103,34 @@ async function handleRowDblclick({
|
||||||
row: MesWmMaterialStockApi.MaterialStock;
|
row: MesWmMaterialStockApi.MaterialStock;
|
||||||
}) {
|
}) {
|
||||||
if (multiple.value) {
|
if (multiple.value) {
|
||||||
const checked = !gridApi.grid.isCheckedByCheckboxRow(row);
|
await toggleMultipleRow(row);
|
||||||
await gridApi.grid.setCheckboxRow(row, checked);
|
|
||||||
handleCheckboxChange({
|
|
||||||
checked,
|
|
||||||
records: gridApi.grid.getCheckboxRecords() as MesWmMaterialStockApi.MaterialStock[],
|
|
||||||
row,
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
selectedRows.value = [row];
|
selectedRows.value = [row];
|
||||||
await syncSingleSelection(row);
|
await gridApi.grid.setRadioRow(row);
|
||||||
handleConfirm();
|
handleConfirm();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 回显预选 */
|
/** 回显预选 */
|
||||||
function applyPreSelection() {
|
async function applyPreSelection() {
|
||||||
if (preSelectedIds.value.length === 0) {
|
if (preSelectedIds.value.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const rows = gridApi.grid.getData() as MesWmMaterialStockApi.MaterialStock[];
|
const rows = gridApi.grid.getData() as MesWmMaterialStockApi.MaterialStock[];
|
||||||
for (const row of rows) {
|
for (const row of rows) {
|
||||||
if (row.id && preSelectedIds.value.includes(row.id)) {
|
if (row.id === undefined || !preSelectedIds.value.includes(row.id)) {
|
||||||
gridApi.grid.setCheckboxRow(row, true);
|
continue;
|
||||||
if (!multiple.value) {
|
|
||||||
selectedRows.value = [row];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (multiple.value) {
|
||||||
|
await gridApi.grid.setCheckboxRow(row, true);
|
||||||
|
} else {
|
||||||
|
await gridApi.grid.setRadioRow(row);
|
||||||
|
selectedRows.value = [row];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (multiple.value) {
|
||||||
|
selectedRows.value = getMultipleSelectedRows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,10 +139,11 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
schema: useSelectGridFormSchema(),
|
schema: useSelectGridFormSchema(),
|
||||||
},
|
},
|
||||||
gridOptions: {
|
gridOptions: {
|
||||||
columns: useSelectGridColumns(),
|
columns: useSelectGridColumns(false),
|
||||||
height: 480,
|
height: 480,
|
||||||
keepSource: true,
|
keepSource: true,
|
||||||
checkboxConfig: { highlight: true, range: true, reserve: true },
|
checkboxConfig: { highlight: true, range: true, reserve: true },
|
||||||
|
radioConfig: { highlight: true, trigger: 'row' },
|
||||||
proxyConfig: {
|
proxyConfig: {
|
||||||
ajax: {
|
ajax: {
|
||||||
query: async ({ page }, formValues) => {
|
query: async ({ page }, formValues) => {
|
||||||
|
|
@ -186,8 +174,11 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
} as VxeTableGridOptions<MesWmMaterialStockApi.MaterialStock>,
|
} as VxeTableGridOptions<MesWmMaterialStockApi.MaterialStock>,
|
||||||
gridEvents: {
|
gridEvents: {
|
||||||
cellDblclick: handleRowDblclick,
|
cellDblclick: handleRowDblclick,
|
||||||
checkboxAll: handleCheckboxAll,
|
checkboxAll: handleCheckboxSelectChange,
|
||||||
checkboxChange: handleCheckboxChange,
|
checkboxChange: handleCheckboxSelectChange,
|
||||||
|
radioChange: ({ row }: { row: MesWmMaterialStockApi.MaterialStock }) => {
|
||||||
|
handleRadioChange(row);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -202,6 +193,8 @@ async function resetQueryState() {
|
||||||
selectedRows.value = [];
|
selectedRows.value = [];
|
||||||
searchItemTypeId.value = undefined;
|
searchItemTypeId.value = undefined;
|
||||||
await gridApi.grid.clearCheckboxRow();
|
await gridApi.grid.clearCheckboxRow();
|
||||||
|
await gridApi.grid.clearCheckboxReserve();
|
||||||
|
await gridApi.grid.clearRadioRow();
|
||||||
await gridApi.formApi.resetForm();
|
await gridApi.formApi.resetForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -211,13 +204,16 @@ async function openModal(
|
||||||
options?: { multiple?: boolean },
|
options?: { multiple?: boolean },
|
||||||
) {
|
) {
|
||||||
open.value = true;
|
open.value = true;
|
||||||
multiple.value = options?.multiple ?? true;
|
multiple.value = options?.multiple ?? false;
|
||||||
preSelectedIds.value = selectedIds || [];
|
preSelectedIds.value = selectedIds || [];
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
gridApi.setGridOptions({
|
||||||
|
columns: useSelectGridColumns(multiple.value),
|
||||||
|
});
|
||||||
await resetQueryState();
|
await resetQueryState();
|
||||||
await gridApi.query();
|
await gridApi.query();
|
||||||
await nextTick();
|
await nextTick();
|
||||||
applyPreSelection();
|
await applyPreSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 关闭弹窗 */
|
/** 关闭弹窗 */
|
||||||
|
|
@ -228,14 +224,12 @@ async function closeModal() {
|
||||||
|
|
||||||
/** 确认选择 */
|
/** 确认选择 */
|
||||||
function handleConfirm() {
|
function handleConfirm() {
|
||||||
if (selectedRows.value.length === 0) {
|
const rows = multiple.value ? getMultipleSelectedRows() : selectedRows.value;
|
||||||
|
if (rows.length === 0) {
|
||||||
message.warning(multiple.value ? '请至少选择一条数据' : '请选择一条数据');
|
message.warning(multiple.value ? '请至少选择一条数据' : '请选择一条数据');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emit(
|
emit('selected', multiple.value ? rows : [rows[0]!]);
|
||||||
'selected',
|
|
||||||
multiple.value ? selectedRows.value : [selectedRows.value[0]!],
|
|
||||||
);
|
|
||||||
open.value = false;
|
open.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,11 +71,7 @@ async function resolveItemById(id: number | undefined) {
|
||||||
if (selectedItem.value?.id === id) {
|
if (selectedItem.value?.id === id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
selectedItem.value = await getMaterialStock(id);
|
||||||
selectedItem.value = await getMaterialStock(id);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('[WmMaterialStockSelect] resolveItemById failed:', error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(() => props.modelValue, resolveItemById, { immediate: true });
|
watch(() => props.modelValue, resolveItemById, { immediate: true });
|
||||||
|
|
|
||||||
|
|
@ -72,8 +72,12 @@ export function useGridFormSchema(): VbenFormSchema[] {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 列表的字段 */
|
/** 列表的字段 */
|
||||||
|
// TODO @AI:看看别的模块,是不是会叫 onFrozenChange?还是一般叫什么梗合适???
|
||||||
export function useGridColumns(
|
export function useGridColumns(
|
||||||
onFrozenChange: (row: MesWmMaterialStockApi.MaterialStock) => void,
|
onFrozenChange: (
|
||||||
|
newFrozen: boolean,
|
||||||
|
row: MesWmMaterialStockApi.MaterialStock,
|
||||||
|
) => Promise<boolean | undefined>,
|
||||||
): VxeTableGridOptions<MesWmMaterialStockApi.MaterialStock>['columns'] {
|
): VxeTableGridOptions<MesWmMaterialStockApi.MaterialStock>['columns'] {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
|
@ -206,10 +210,12 @@ export function useSelectGridFormSchema(): VbenFormSchema[] {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 选择弹窗的字段 */
|
/** 选择弹窗的字段 */
|
||||||
export function useSelectGridColumns(): VxeTableGridOptions<MesWmMaterialStockApi.MaterialStock>['columns'] {
|
export function useSelectGridColumns(
|
||||||
|
multiple = false,
|
||||||
|
): VxeTableGridOptions<MesWmMaterialStockApi.MaterialStock>['columns'] {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
type: 'checkbox',
|
type: multiple ? 'checkbox' : 'radio',
|
||||||
width: 50,
|
width: 50,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import {
|
||||||
} from '#/api/mes/wm/materialstock';
|
} from '#/api/mes/wm/materialstock';
|
||||||
import { $t } from '#/locales';
|
import { $t } from '#/locales';
|
||||||
import MdItemTypeTree from '#/views/mes/md/item/type/components/md-item-type-tree.vue';
|
import MdItemTypeTree from '#/views/mes/md/item/type/components/md-item-type-tree.vue';
|
||||||
|
import { WmBatchDetail } from '#/views/mes/wm/batch/components';
|
||||||
import AreaForm from '#/views/mes/wm/warehouse/area/modules/form.vue';
|
import AreaForm from '#/views/mes/wm/warehouse/area/modules/form.vue';
|
||||||
|
|
||||||
import { useGridColumns, useGridFormSchema } from './data';
|
import { useGridColumns, useGridFormSchema } from './data';
|
||||||
|
|
@ -26,6 +27,8 @@ const [AreaModal, areaModalApi] = useVbenModal({
|
||||||
destroyOnClose: true,
|
destroyOnClose: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const batchDetailRef = ref<InstanceType<typeof WmBatchDetail>>();
|
||||||
|
|
||||||
/** 刷新表格 */
|
/** 刷新表格 */
|
||||||
function handleRefresh() {
|
function handleRefresh() {
|
||||||
gridApi.query();
|
gridApi.query();
|
||||||
|
|
@ -55,11 +58,20 @@ function handleOpenAreaDetail(row: MesWmMaterialStockApi.MaterialStock) {
|
||||||
areaModalApi.setData({ formType: 'detail', id: row.areaId }).open();
|
areaModalApi.setData({ formType: 'detail', id: row.areaId }).open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 打开批次详情弹窗 */
|
||||||
|
function handleOpenBatchDetail(row: MesWmMaterialStockApi.MaterialStock) {
|
||||||
|
if (!row.batchId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
batchDetailRef.value?.open(row.batchId);
|
||||||
|
}
|
||||||
|
|
||||||
/** 处理冻结状态切换 */
|
/** 处理冻结状态切换 */
|
||||||
async function handleFrozenChange(
|
async function handleFrozenChange(
|
||||||
|
newFrozen: boolean,
|
||||||
row: MesWmMaterialStockApi.MaterialStock,
|
row: MesWmMaterialStockApi.MaterialStock,
|
||||||
): Promise<boolean | undefined> {
|
): Promise<boolean | undefined> {
|
||||||
const text = row.frozen ? '冻结' : '解冻';
|
const text = newFrozen ? '冻结' : '解冻';
|
||||||
try {
|
try {
|
||||||
await confirm(`确认要"${text}"该库存记录吗?`);
|
await confirm(`确认要"${text}"该库存记录吗?`);
|
||||||
} catch {
|
} catch {
|
||||||
|
|
@ -68,7 +80,7 @@ async function handleFrozenChange(
|
||||||
// 更新冻结状态
|
// 更新冻结状态
|
||||||
await updateMaterialStockFrozen({
|
await updateMaterialStockFrozen({
|
||||||
id: row.id!,
|
id: row.id!,
|
||||||
frozen: row.frozen!,
|
frozen: newFrozen,
|
||||||
});
|
});
|
||||||
// 提示并返回成功
|
// 提示并返回成功
|
||||||
message.success(`${text}成功`);
|
message.success(`${text}成功`);
|
||||||
|
|
@ -117,6 +129,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<AreaModal />
|
<AreaModal />
|
||||||
|
<WmBatchDetail ref="batchDetailRef" />
|
||||||
|
|
||||||
<div class="flex h-full w-full">
|
<div class="flex h-full w-full">
|
||||||
<!-- 左侧物料分类树 -->
|
<!-- 左侧物料分类树 -->
|
||||||
|
|
@ -140,9 +153,15 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #batchCode="{ row }">
|
<template #batchCode="{ row }">
|
||||||
<span v-if="row.batchId" :title="row.batchCode">
|
<Button
|
||||||
|
v-if="row.batchId"
|
||||||
|
:title="row.batchCode"
|
||||||
|
size="small"
|
||||||
|
type="link"
|
||||||
|
@click="handleOpenBatchDetail(row)"
|
||||||
|
>
|
||||||
{{ row.batchCode }}
|
{{ row.batchCode }}
|
||||||
</span>
|
</Button>
|
||||||
<span v-else>-</span>
|
<span v-else>-</span>
|
||||||
</template>
|
</template>
|
||||||
<template #areaName="{ row }">
|
<template #areaName="{ row }">
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,15 @@ const routes: RouteRecordRaw[] = [
|
||||||
},
|
},
|
||||||
component: () => import('#/views/mes/wm/barcode/config/index.vue'),
|
component: () => import('#/views/mes/wm/barcode/config/index.vue'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'pro/task/edit',
|
||||||
|
name: 'MesProTaskGanttEdit',
|
||||||
|
meta: {
|
||||||
|
title: '甘特图编辑',
|
||||||
|
activePath: '/mes/pro/task',
|
||||||
|
},
|
||||||
|
component: () => import('#/views/mes/pro/task/edit/index.vue'),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,3 @@
|
||||||
|
export { default as GanttChart } from './gantt-chart.vue';
|
||||||
export { default as ProTaskSelectDialog } from './pro-task-select-dialog.vue';
|
export { default as ProTaskSelectDialog } from './pro-task-select-dialog.vue';
|
||||||
export { default as ProTaskSelect } from './pro-task-select.vue';
|
export { default as ProTaskSelect } from './pro-task-select.vue';
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,467 @@
|
||||||
import type { VbenFormSchema } from '#/adapter/form';
|
import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
|
||||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { MesProTaskApi } from '#/api/mes/pro/task';
|
import type { MesProTaskApi } from '#/api/mes/pro/task';
|
||||||
|
import type { MesProWorkOrderApi } from '#/api/mes/pro/workorder';
|
||||||
|
|
||||||
import { markRaw } from 'vue';
|
import { markRaw } from 'vue';
|
||||||
|
|
||||||
import { DICT_TYPE } from '@vben/constants';
|
import { DICT_TYPE } from '@vben/constants';
|
||||||
|
import { getDictOptions } from '@vben/hooks';
|
||||||
|
|
||||||
|
import { getRangePickerDefaultProps } from '#/utils';
|
||||||
|
import MdClientSelect from '#/views/mes/md/client/components/md-client-select.vue';
|
||||||
|
import { MdItemSelect } from '#/views/mes/md/item/components';
|
||||||
import { MdWorkstationSelect } from '#/views/mes/md/workstation/components';
|
import { MdWorkstationSelect } from '#/views/mes/md/workstation/components';
|
||||||
import { ProProcessSelect } from '#/views/mes/pro/process/components';
|
import { ProProcessSelect } from '#/views/mes/pro/process/components';
|
||||||
|
import { RouteColorPicker } from '#/views/mes/pro/route/components';
|
||||||
import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components';
|
import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components';
|
||||||
|
|
||||||
|
/** 待排产工单列表的搜索表单 */
|
||||||
|
export function useGridFormSchema(): VbenFormSchema[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
fieldName: 'code',
|
||||||
|
label: '工单编码',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
clearable: true,
|
||||||
|
placeholder: '请输入工单编码',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'name',
|
||||||
|
label: '工单名称',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
clearable: true,
|
||||||
|
placeholder: '请输入工单名称',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'orderSourceCode',
|
||||||
|
label: '来源单据',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
clearable: true,
|
||||||
|
placeholder: '请输入来源单据编号',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'productId',
|
||||||
|
label: '产品',
|
||||||
|
component: markRaw(MdItemSelect),
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请选择产品',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'clientId',
|
||||||
|
label: '客户',
|
||||||
|
component: markRaw(MdClientSelect),
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请选择客户',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'requestDate',
|
||||||
|
label: '需求日期',
|
||||||
|
component: 'RangePicker',
|
||||||
|
componentProps: {
|
||||||
|
...getRangePickerDefaultProps(),
|
||||||
|
clearable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 待排产工单列表的字段 */
|
||||||
|
export function useGridColumns(): VxeTableGridOptions<MesProWorkOrderApi.WorkOrder>['columns'] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
field: 'code',
|
||||||
|
title: '工单编码',
|
||||||
|
fixed: 'left',
|
||||||
|
width: 200,
|
||||||
|
treeNode: true,
|
||||||
|
slots: { default: 'code' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'name',
|
||||||
|
title: '工单名称',
|
||||||
|
minWidth: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'orderSourceType',
|
||||||
|
title: '工单来源',
|
||||||
|
width: 100,
|
||||||
|
cellRender: {
|
||||||
|
name: 'CellDict',
|
||||||
|
props: { type: DICT_TYPE.MES_PRO_WORK_ORDER_SOURCE_TYPE },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'orderSourceCode',
|
||||||
|
title: '来源单据编号',
|
||||||
|
width: 140,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'productCode',
|
||||||
|
title: '产品编码',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'productName',
|
||||||
|
title: '产品名称',
|
||||||
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'productSpecification',
|
||||||
|
title: '规格型号',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'unitMeasureName',
|
||||||
|
title: '单位',
|
||||||
|
width: 80,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'quantity',
|
||||||
|
title: '工单数量',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'quantityChanged',
|
||||||
|
title: '调整数量',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'quantityProduced',
|
||||||
|
title: '已生产数量',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'clientCode',
|
||||||
|
title: '客户编码',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'clientName',
|
||||||
|
title: '客户名称',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'requestDate',
|
||||||
|
title: '需求日期',
|
||||||
|
width: 120,
|
||||||
|
formatter: 'formatDate',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'status',
|
||||||
|
title: '排产状态',
|
||||||
|
width: 100,
|
||||||
|
cellRender: {
|
||||||
|
name: 'CellDict',
|
||||||
|
props: { type: DICT_TYPE.MES_PRO_WORK_ORDER_STATUS },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
width: 100,
|
||||||
|
fixed: 'right',
|
||||||
|
slots: { default: 'actions' },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 排产对话框只读工单信息的表单 */
|
||||||
|
export function useScheduleFormSchema(): VbenFormSchema[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
fieldName: 'code',
|
||||||
|
label: '工单编码',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'name',
|
||||||
|
label: '工单名称',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'orderSourceType',
|
||||||
|
label: '工单来源',
|
||||||
|
component: 'Select',
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
options: getDictOptions(DICT_TYPE.MES_PRO_WORK_ORDER_SOURCE_TYPE, 'number'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'orderSourceCode',
|
||||||
|
label: '来源单据编号',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'type',
|
||||||
|
label: '工单类型',
|
||||||
|
component: 'Select',
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
options: getDictOptions(DICT_TYPE.MES_PRO_WORK_ORDER_TYPE, 'number'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'productId',
|
||||||
|
label: '产品',
|
||||||
|
component: markRaw(MdItemSelect),
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'productSpecification',
|
||||||
|
label: '规格型号',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'unitMeasureName',
|
||||||
|
label: '单位',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'quantity',
|
||||||
|
label: '工单数量',
|
||||||
|
component: 'InputNumber',
|
||||||
|
componentProps: {
|
||||||
|
class: '!w-full',
|
||||||
|
controlsPosition: 'right',
|
||||||
|
disabled: true,
|
||||||
|
precision: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'clientId',
|
||||||
|
label: '客户',
|
||||||
|
component: markRaw(MdClientSelect),
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'batchCode',
|
||||||
|
label: '批次号',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'requestDate',
|
||||||
|
label: '需求日期',
|
||||||
|
component: 'DatePicker',
|
||||||
|
componentProps: {
|
||||||
|
class: '!w-full',
|
||||||
|
disabled: true,
|
||||||
|
type: 'date',
|
||||||
|
valueFormat: 'x',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'remark',
|
||||||
|
label: '备注',
|
||||||
|
component: 'Textarea',
|
||||||
|
formItemClass: 'col-span-3',
|
||||||
|
componentProps: {
|
||||||
|
disabled: true,
|
||||||
|
rows: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 生产任务子表的字段 */
|
||||||
|
export function useTaskGridColumns(
|
||||||
|
editable: boolean,
|
||||||
|
): VxeTableGridOptions<MesProTaskApi.Task>['columns'] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
field: 'code',
|
||||||
|
title: '任务编码',
|
||||||
|
width: 140,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'name',
|
||||||
|
title: '任务名称',
|
||||||
|
minWidth: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'workstationCode',
|
||||||
|
title: '工作站编号',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'workstationName',
|
||||||
|
title: '工作站名称',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'quantity',
|
||||||
|
title: '排产数量',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'producedQuantity',
|
||||||
|
title: '已生产数量',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'startTime',
|
||||||
|
title: '开始生产时间',
|
||||||
|
width: 170,
|
||||||
|
formatter: 'formatDateTime',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'duration',
|
||||||
|
title: '生产时长',
|
||||||
|
width: 80,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'endTime',
|
||||||
|
title: '预计完成时间',
|
||||||
|
width: 170,
|
||||||
|
formatter: 'formatDateTime',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'colorCode',
|
||||||
|
title: '显示颜色',
|
||||||
|
width: 100,
|
||||||
|
slots: { default: 'colorCode' },
|
||||||
|
},
|
||||||
|
...(editable
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
width: 160,
|
||||||
|
fixed: 'right',
|
||||||
|
slots: { default: 'actions' },
|
||||||
|
} as const,
|
||||||
|
]
|
||||||
|
: []),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 生产任务新增/修改的表单 */
|
||||||
|
export function useTaskFormSchema(formApi?: VbenFormApi): VbenFormSchema[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
fieldName: 'workstationId',
|
||||||
|
label: '工作站',
|
||||||
|
component: markRaw(MdWorkstationSelect),
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请选择工作站',
|
||||||
|
},
|
||||||
|
rules: 'selectRequired',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'quantity',
|
||||||
|
label: '排产数量',
|
||||||
|
component: 'InputNumber',
|
||||||
|
componentProps: {
|
||||||
|
class: '!w-full',
|
||||||
|
controlsPosition: 'right',
|
||||||
|
min: 0.01,
|
||||||
|
placeholder: '请输入排产数量',
|
||||||
|
precision: 2,
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'colorCode',
|
||||||
|
label: '甘特颜色',
|
||||||
|
component: markRaw(RouteColorPicker),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'startTime',
|
||||||
|
label: '开始时间',
|
||||||
|
component: 'DatePicker',
|
||||||
|
componentProps: {
|
||||||
|
class: '!w-full',
|
||||||
|
placeholder: '请选择开始时间',
|
||||||
|
type: 'datetime',
|
||||||
|
valueFormat: 'x',
|
||||||
|
// 开始时间变更:重新计算结束时间
|
||||||
|
onChange: () => recalcEndTime(formApi),
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'duration',
|
||||||
|
label: '生产时长',
|
||||||
|
component: 'InputNumber',
|
||||||
|
componentProps: {
|
||||||
|
class: '!w-full',
|
||||||
|
controlsPosition: 'right',
|
||||||
|
min: 1,
|
||||||
|
placeholder: '请输入生产时长',
|
||||||
|
precision: 0,
|
||||||
|
// 生产时长变更:重新计算结束时间
|
||||||
|
onChange: () => recalcEndTime(formApi),
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'endTime',
|
||||||
|
label: '结束时间',
|
||||||
|
component: 'DatePicker',
|
||||||
|
componentProps: {
|
||||||
|
class: '!w-full',
|
||||||
|
disabled: true,
|
||||||
|
type: 'datetime',
|
||||||
|
valueFormat: 'x',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'remark',
|
||||||
|
label: '备注',
|
||||||
|
component: 'Textarea',
|
||||||
|
formItemClass: 'col-span-3',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入备注',
|
||||||
|
rows: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 计算结束时间:开始时间 + 生产时长 × 8 小时 */
|
||||||
|
async function recalcEndTime(formApi?: VbenFormApi) {
|
||||||
|
if (!formApi) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const values = await formApi.getValues();
|
||||||
|
if (values.startTime && values.duration) {
|
||||||
|
const start = Number(values.startTime);
|
||||||
|
await formApi.setFieldValue(
|
||||||
|
'endTime',
|
||||||
|
start + values.duration * 8 * 3600 * 1000,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 任务选择弹窗的搜索表单 */
|
/** 任务选择弹窗的搜索表单 */
|
||||||
export function useTaskSelectGridFormSchema(): VbenFormSchema[] {
|
export function useTaskSelectGridFormSchema(): VbenFormSchema[] {
|
||||||
return [
|
return [
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,3 @@
|
||||||
|
export { default as WmBatchDetail } from './wm-batch-detail.vue';
|
||||||
export { default as WmBatchSelectDialog } from './wm-batch-select-dialog.vue';
|
export { default as WmBatchSelectDialog } from './wm-batch-select-dialog.vue';
|
||||||
export { default as WmBatchSelect } from './wm-batch-select.vue';
|
export { default as WmBatchSelect } from './wm-batch-select.vue';
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,7 @@ const emit = defineEmits<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const open = ref(false);
|
const open = ref(false);
|
||||||
const multiple = ref(true);
|
const multiple = ref(false); // 是否多选;默认按单选选择器使用
|
||||||
const syncingSingleSelection = ref(false);
|
|
||||||
const selectedRows = ref<MesWmMaterialStockApi.MaterialStock[]>([]);
|
const selectedRows = ref<MesWmMaterialStockApi.MaterialStock[]>([]);
|
||||||
const preSelectedIds = ref<number[]>([]);
|
const preSelectedIds = ref<number[]>([]);
|
||||||
const searchItemTypeId = ref<number>();
|
const searchItemTypeId = ref<number>();
|
||||||
|
|
@ -64,50 +63,37 @@ const alertTitle = computed(() => {
|
||||||
return `已按${parts.join('/')}预过滤`;
|
return `已按${parts.join('/')}预过滤`;
|
||||||
});
|
});
|
||||||
|
|
||||||
/** 单选模式同步 VXE 勾选状态 */
|
/** 获取多选记录,包含 VXE reserve 跨页记录 */
|
||||||
async function syncSingleSelection(row?: MesWmMaterialStockApi.MaterialStock) {
|
function getMultipleSelectedRows() {
|
||||||
syncingSingleSelection.value = true;
|
const selectedMap = new Map<number, MesWmMaterialStockApi.MaterialStock>();
|
||||||
await nextTick();
|
const records = [
|
||||||
await gridApi.grid.clearCheckboxRow();
|
...(gridApi.grid.getCheckboxReserveRecords?.() ?? []),
|
||||||
if (row) {
|
...(gridApi.grid.getCheckboxRecords?.() ?? []),
|
||||||
await gridApi.grid.setCheckboxRow(row, true);
|
] as MesWmMaterialStockApi.MaterialStock[];
|
||||||
}
|
records.forEach((row) => {
|
||||||
await nextTick();
|
const rowId = row.id;
|
||||||
syncingSingleSelection.value = false;
|
if (rowId !== undefined) {
|
||||||
|
selectedMap.set(rowId, row);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return [...selectedMap.values()];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 处理勾选变化 */
|
/** 处理多选勾选变化 */
|
||||||
async function handleCheckboxChange({
|
function handleCheckboxSelectChange() {
|
||||||
checked,
|
selectedRows.value = getMultipleSelectedRows();
|
||||||
records,
|
|
||||||
row,
|
|
||||||
}: {
|
|
||||||
checked: boolean;
|
|
||||||
records: MesWmMaterialStockApi.MaterialStock[];
|
|
||||||
row?: MesWmMaterialStockApi.MaterialStock;
|
|
||||||
}) {
|
|
||||||
if (syncingSingleSelection.value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!multiple.value) {
|
|
||||||
const selected = checked && row ? [row] : [];
|
|
||||||
selectedRows.value = selected;
|
|
||||||
await syncSingleSelection(selected[0]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
selectedRows.value = records;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 处理全选变化 */
|
/** 处理单选切换 */
|
||||||
function handleCheckboxAll({
|
function handleRadioChange(row: MesWmMaterialStockApi.MaterialStock) {
|
||||||
records,
|
selectedRows.value = [row];
|
||||||
}: {
|
}
|
||||||
records: MesWmMaterialStockApi.MaterialStock[];
|
|
||||||
}) {
|
/** 多选模式下切换行勾选 */
|
||||||
if (syncingSingleSelection.value) {
|
async function toggleMultipleRow(row: MesWmMaterialStockApi.MaterialStock) {
|
||||||
return;
|
const selected = gridApi.grid.isCheckedByCheckboxRow(row);
|
||||||
}
|
await gridApi.grid.setCheckboxRow(row, !selected);
|
||||||
selectedRows.value = records;
|
selectedRows.value = getMultipleSelectedRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 双击行:单选直接确认;多选切换勾选 */
|
/** 双击行:单选直接确认;多选切换勾选 */
|
||||||
|
|
@ -117,34 +103,34 @@ async function handleRowDblclick({
|
||||||
row: MesWmMaterialStockApi.MaterialStock;
|
row: MesWmMaterialStockApi.MaterialStock;
|
||||||
}) {
|
}) {
|
||||||
if (multiple.value) {
|
if (multiple.value) {
|
||||||
const checked = !gridApi.grid.isCheckedByCheckboxRow(row);
|
await toggleMultipleRow(row);
|
||||||
await gridApi.grid.setCheckboxRow(row, checked);
|
|
||||||
handleCheckboxChange({
|
|
||||||
checked,
|
|
||||||
records:
|
|
||||||
gridApi.grid.getCheckboxRecords() as MesWmMaterialStockApi.MaterialStock[],
|
|
||||||
row,
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
selectedRows.value = [row];
|
selectedRows.value = [row];
|
||||||
await syncSingleSelection(row);
|
await gridApi.grid.setRadioRow(row);
|
||||||
handleConfirm();
|
handleConfirm();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 回显预选 */
|
/** 回显预选 */
|
||||||
function applyPreSelection() {
|
async function applyPreSelection() {
|
||||||
if (preSelectedIds.value.length === 0) {
|
if (preSelectedIds.value.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const rows = gridApi.grid.getData() as MesWmMaterialStockApi.MaterialStock[];
|
const rows = gridApi.grid.getData() as MesWmMaterialStockApi.MaterialStock[];
|
||||||
for (const row of rows) {
|
for (const row of rows) {
|
||||||
if (row.id && preSelectedIds.value.includes(row.id)) {
|
if (row.id === undefined || !preSelectedIds.value.includes(row.id)) {
|
||||||
gridApi.grid.setCheckboxRow(row, true);
|
continue;
|
||||||
if (!multiple.value) {
|
|
||||||
selectedRows.value = [row];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (multiple.value) {
|
||||||
|
await gridApi.grid.setCheckboxRow(row, true);
|
||||||
|
} else {
|
||||||
|
await gridApi.grid.setRadioRow(row);
|
||||||
|
selectedRows.value = [row];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (multiple.value) {
|
||||||
|
selectedRows.value = getMultipleSelectedRows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,7 +139,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
schema: useSelectGridFormSchema(),
|
schema: useSelectGridFormSchema(),
|
||||||
},
|
},
|
||||||
gridOptions: {
|
gridOptions: {
|
||||||
columns: useSelectGridColumns(),
|
columns: useSelectGridColumns(false),
|
||||||
height: 480,
|
height: 480,
|
||||||
keepSource: true,
|
keepSource: true,
|
||||||
checkboxConfig: {
|
checkboxConfig: {
|
||||||
|
|
@ -161,6 +147,10 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
range: true,
|
range: true,
|
||||||
reserve: true,
|
reserve: true,
|
||||||
},
|
},
|
||||||
|
radioConfig: {
|
||||||
|
highlight: true,
|
||||||
|
trigger: 'row',
|
||||||
|
},
|
||||||
proxyConfig: {
|
proxyConfig: {
|
||||||
ajax: {
|
ajax: {
|
||||||
query: async ({ page }, formValues) => {
|
query: async ({ page }, formValues) => {
|
||||||
|
|
@ -191,8 +181,11 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
} as VxeTableGridOptions<MesWmMaterialStockApi.MaterialStock>,
|
} as VxeTableGridOptions<MesWmMaterialStockApi.MaterialStock>,
|
||||||
gridEvents: {
|
gridEvents: {
|
||||||
cellDblclick: handleRowDblclick,
|
cellDblclick: handleRowDblclick,
|
||||||
checkboxAll: handleCheckboxAll,
|
checkboxAll: handleCheckboxSelectChange,
|
||||||
checkboxChange: handleCheckboxChange,
|
checkboxChange: handleCheckboxSelectChange,
|
||||||
|
radioChange: ({ row }: { row: MesWmMaterialStockApi.MaterialStock }) => {
|
||||||
|
handleRadioChange(row);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -207,6 +200,8 @@ async function resetQueryState() {
|
||||||
selectedRows.value = [];
|
selectedRows.value = [];
|
||||||
searchItemTypeId.value = undefined;
|
searchItemTypeId.value = undefined;
|
||||||
await gridApi.grid.clearCheckboxRow();
|
await gridApi.grid.clearCheckboxRow();
|
||||||
|
await gridApi.grid.clearCheckboxReserve();
|
||||||
|
await gridApi.grid.clearRadioRow();
|
||||||
await gridApi.formApi.resetForm();
|
await gridApi.formApi.resetForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -216,13 +211,16 @@ async function openModal(
|
||||||
options?: { multiple?: boolean },
|
options?: { multiple?: boolean },
|
||||||
) {
|
) {
|
||||||
open.value = true;
|
open.value = true;
|
||||||
multiple.value = options?.multiple ?? true;
|
multiple.value = options?.multiple ?? false;
|
||||||
preSelectedIds.value = selectedIds || [];
|
preSelectedIds.value = selectedIds || [];
|
||||||
await nextTick();
|
await nextTick();
|
||||||
|
gridApi.setGridOptions({
|
||||||
|
columns: useSelectGridColumns(multiple.value),
|
||||||
|
});
|
||||||
await resetQueryState();
|
await resetQueryState();
|
||||||
await gridApi.query();
|
await gridApi.query();
|
||||||
await nextTick();
|
await nextTick();
|
||||||
applyPreSelection();
|
await applyPreSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 关闭弹窗 */
|
/** 关闭弹窗 */
|
||||||
|
|
@ -233,14 +231,12 @@ async function closeModal() {
|
||||||
|
|
||||||
/** 确认选择 */
|
/** 确认选择 */
|
||||||
function handleConfirm() {
|
function handleConfirm() {
|
||||||
if (selectedRows.value.length === 0) {
|
const rows = multiple.value ? getMultipleSelectedRows() : selectedRows.value;
|
||||||
|
if (rows.length === 0) {
|
||||||
ElMessage.warning(multiple.value ? '请至少选择一条数据' : '请选择一条数据');
|
ElMessage.warning(multiple.value ? '请至少选择一条数据' : '请选择一条数据');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emit(
|
emit('selected', multiple.value ? rows : [rows[0]!]);
|
||||||
'selected',
|
|
||||||
multiple.value ? selectedRows.value : [selectedRows.value[0]!],
|
|
||||||
);
|
|
||||||
open.value = false;
|
open.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,11 +71,7 @@ async function resolveItemById(id: number | undefined) {
|
||||||
if (selectedItem.value?.id === id) {
|
if (selectedItem.value?.id === id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
selectedItem.value = await getMaterialStock(id);
|
||||||
selectedItem.value = await getMaterialStock(id);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('[WmMaterialStockSelect] resolveItemById failed:', error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(() => props.modelValue, resolveItemById, { immediate: true });
|
watch(() => props.modelValue, resolveItemById, { immediate: true });
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,10 @@ export function useGridFormSchema(): VbenFormSchema[] {
|
||||||
|
|
||||||
/** 列表的字段 */
|
/** 列表的字段 */
|
||||||
export function useGridColumns(
|
export function useGridColumns(
|
||||||
onFrozenChange: (row: MesWmMaterialStockApi.MaterialStock) => void,
|
onFrozenChange: (
|
||||||
|
newFrozen: boolean,
|
||||||
|
row: MesWmMaterialStockApi.MaterialStock,
|
||||||
|
) => Promise<boolean | undefined>,
|
||||||
): VxeTableGridOptions<MesWmMaterialStockApi.MaterialStock>['columns'] {
|
): VxeTableGridOptions<MesWmMaterialStockApi.MaterialStock>['columns'] {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
|
@ -206,10 +209,12 @@ export function useSelectGridFormSchema(): VbenFormSchema[] {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 选择弹窗的字段 */
|
/** 选择弹窗的字段 */
|
||||||
export function useSelectGridColumns(): VxeTableGridOptions<MesWmMaterialStockApi.MaterialStock>['columns'] {
|
export function useSelectGridColumns(
|
||||||
|
multiple = false,
|
||||||
|
): VxeTableGridOptions<MesWmMaterialStockApi.MaterialStock>['columns'] {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
type: 'checkbox',
|
type: multiple ? 'checkbox' : 'radio',
|
||||||
width: 50,
|
width: 50,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import {
|
||||||
} from '#/api/mes/wm/materialstock';
|
} from '#/api/mes/wm/materialstock';
|
||||||
import { $t } from '#/locales';
|
import { $t } from '#/locales';
|
||||||
import MdItemTypeTree from '#/views/mes/md/item/type/components/md-item-type-tree.vue';
|
import MdItemTypeTree from '#/views/mes/md/item/type/components/md-item-type-tree.vue';
|
||||||
|
import { WmBatchDetail } from '#/views/mes/wm/batch/components';
|
||||||
import AreaForm from '#/views/mes/wm/warehouse/area/modules/form.vue';
|
import AreaForm from '#/views/mes/wm/warehouse/area/modules/form.vue';
|
||||||
|
|
||||||
import { useGridColumns, useGridFormSchema } from './data';
|
import { useGridColumns, useGridFormSchema } from './data';
|
||||||
|
|
@ -26,9 +27,14 @@ const [AreaModal, areaModalApi] = useVbenModal({
|
||||||
destroyOnClose: true,
|
destroyOnClose: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const batchDetailRef = ref<InstanceType<typeof WmBatchDetail>>();
|
||||||
|
|
||||||
/** 处理冻结状态切换 */
|
/** 处理冻结状态切换 */
|
||||||
async function handleFrozenChange(row: MesWmMaterialStockApi.MaterialStock) {
|
async function handleFrozenChange(
|
||||||
const text = row.frozen ? '冻结' : '解冻';
|
newFrozen: boolean,
|
||||||
|
row: MesWmMaterialStockApi.MaterialStock,
|
||||||
|
): Promise<boolean | undefined> {
|
||||||
|
const text = newFrozen ? '冻结' : '解冻';
|
||||||
try {
|
try {
|
||||||
await confirm(`确认要"${text}"该库存记录吗?`);
|
await confirm(`确认要"${text}"该库存记录吗?`);
|
||||||
} catch {
|
} catch {
|
||||||
|
|
@ -36,7 +42,7 @@ async function handleFrozenChange(row: MesWmMaterialStockApi.MaterialStock) {
|
||||||
}
|
}
|
||||||
await updateMaterialStockFrozen({
|
await updateMaterialStockFrozen({
|
||||||
id: row.id!,
|
id: row.id!,
|
||||||
frozen: row.frozen!,
|
frozen: newFrozen,
|
||||||
});
|
});
|
||||||
ElMessage.success(`${text}成功`);
|
ElMessage.success(`${text}成功`);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -90,6 +96,14 @@ function handleOpenAreaDetail(row: MesWmMaterialStockApi.MaterialStock) {
|
||||||
areaModalApi.setData({ formType: 'detail', id: row.areaId }).open();
|
areaModalApi.setData({ formType: 'detail', id: row.areaId }).open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 打开批次详情弹窗 */
|
||||||
|
function handleOpenBatchDetail(row: MesWmMaterialStockApi.MaterialStock) {
|
||||||
|
if (!row.batchId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
batchDetailRef.value?.open(row.batchId);
|
||||||
|
}
|
||||||
|
|
||||||
/** 导出表格 */
|
/** 导出表格 */
|
||||||
async function handleExport() {
|
async function handleExport() {
|
||||||
const data = await exportMaterialStock({
|
const data = await exportMaterialStock({
|
||||||
|
|
@ -110,6 +124,7 @@ async function handleExport() {
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<AreaModal />
|
<AreaModal />
|
||||||
|
<WmBatchDetail ref="batchDetailRef" />
|
||||||
|
|
||||||
<div class="flex h-full gap-3">
|
<div class="flex h-full gap-3">
|
||||||
<div class="bg-card w-1/6 rounded p-3">
|
<div class="bg-card w-1/6 rounded p-3">
|
||||||
|
|
@ -131,9 +146,16 @@ async function handleExport() {
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #batchCode="{ row }">
|
<template #batchCode="{ row }">
|
||||||
<span v-if="row.batchId" :title="row.batchCode">
|
<ElButton
|
||||||
|
v-if="row.batchId"
|
||||||
|
link
|
||||||
|
size="small"
|
||||||
|
:title="row.batchCode"
|
||||||
|
type="primary"
|
||||||
|
@click="handleOpenBatchDetail(row)"
|
||||||
|
>
|
||||||
{{ row.batchCode }}
|
{{ row.batchCode }}
|
||||||
</span>
|
</ElButton>
|
||||||
<span v-else>-</span>
|
<span v-else>-</span>
|
||||||
</template>
|
</template>
|
||||||
<template #areaName="{ row }">
|
<template #areaName="{ row }">
|
||||||
|
|
|
||||||
|
|
@ -285,6 +285,9 @@ catalogs:
|
||||||
defu:
|
defu:
|
||||||
specifier: ^6.1.7
|
specifier: ^6.1.7
|
||||||
version: 6.1.7
|
version: 6.1.7
|
||||||
|
dhtmlx-gantt:
|
||||||
|
specifier: ^9.1.1
|
||||||
|
version: 9.1.4
|
||||||
diagram-js:
|
diagram-js:
|
||||||
specifier: ^12.8.1
|
specifier: ^12.8.1
|
||||||
version: 12.8.1
|
version: 12.8.1
|
||||||
|
|
@ -525,6 +528,9 @@ catalogs:
|
||||||
tw-animate-css:
|
tw-animate-css:
|
||||||
specifier: ^1.4.0
|
specifier: ^1.4.0
|
||||||
version: 1.4.0
|
version: 1.4.0
|
||||||
|
tyme4ts:
|
||||||
|
specifier: ^1.5.0
|
||||||
|
version: 1.5.0
|
||||||
typescript:
|
typescript:
|
||||||
specifier: ^6.0.3
|
specifier: ^6.0.3
|
||||||
version: 6.0.3
|
version: 6.0.3
|
||||||
|
|
@ -819,6 +825,9 @@ importers:
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 1.11.20
|
version: 1.11.20
|
||||||
|
dhtmlx-gantt:
|
||||||
|
specifier: 'catalog:'
|
||||||
|
version: 9.1.4
|
||||||
diagram-js:
|
diagram-js:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 12.8.1
|
version: 12.8.1
|
||||||
|
|
@ -1071,6 +1080,9 @@ importers:
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 1.11.20
|
version: 1.11.20
|
||||||
|
dhtmlx-gantt:
|
||||||
|
specifier: 'catalog:'
|
||||||
|
version: 9.1.4
|
||||||
diagram-js:
|
diagram-js:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 12.8.1
|
version: 12.8.1
|
||||||
|
|
@ -1293,14 +1305,14 @@ importers:
|
||||||
version: 2.9.8(vue@3.5.34(typescript@6.0.3))
|
version: 2.9.8(vue@3.5.34(typescript@6.0.3))
|
||||||
vitepress-plugin-group-icons:
|
vitepress-plugin-group-icons:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 1.7.5(vite@8.0.10(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0))
|
version: 1.7.5(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0))
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@nolebase/vitepress-plugin-git-changelog':
|
'@nolebase/vitepress-plugin-git-changelog':
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 2.18.2(vitepress@2.0.0-alpha.17(@types/node@25.9.1)(async-validator@4.2.5)(axios@1.16.1)(change-case@5.4.4)(jiti@2.7.0)(less@4.6.4)(lightningcss@1.32.0)(nprogress@0.2.0)(postcss@8.5.15)(qrcode@1.5.4)(sass-embedded@1.100.0)(sass@1.100.0)(sortablejs@1.15.7)(terser@5.48.0)(typescript@6.0.3)(yaml@2.9.0))(vue@3.5.34(typescript@6.0.3))
|
version: 2.18.2(vitepress@2.0.0-alpha.17(@types/node@25.9.1)(async-validator@4.2.5)(axios@1.16.1)(change-case@5.4.4)(jiti@2.7.0)(less@4.6.4)(lightningcss@1.32.0)(nprogress@0.2.0)(postcss@8.5.15)(qrcode@1.5.4)(sass-embedded@1.100.0)(sass@1.100.0)(sortablejs@1.15.7)(terser@5.48.0)(typescript@6.0.3)(yaml@2.9.0))(vue@3.5.34(typescript@6.0.3))
|
||||||
'@tailwindcss/vite':
|
'@tailwindcss/vite':
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 4.3.0(vite@8.0.10(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0))
|
version: 4.3.0(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0))
|
||||||
'@vben/tailwind-config':
|
'@vben/tailwind-config':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../internal/tailwind-config
|
version: link:../internal/tailwind-config
|
||||||
|
|
@ -1309,7 +1321,7 @@ importers:
|
||||||
version: link:../internal/vite-config
|
version: link:../internal/vite-config
|
||||||
'@vite-pwa/vitepress':
|
'@vite-pwa/vitepress':
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 1.1.0(vite-plugin-pwa@1.3.0(vite@8.0.10(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0))(workbox-build@7.4.1)(workbox-window@7.4.1))
|
version: 1.1.0(vite-plugin-pwa@1.3.0(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0))(workbox-build@7.4.1)(workbox-window@7.4.1))
|
||||||
vitepress:
|
vitepress:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 2.0.0-alpha.17(@types/node@25.9.1)(async-validator@4.2.5)(axios@1.16.1)(change-case@5.4.4)(jiti@2.7.0)(less@4.6.4)(lightningcss@1.32.0)(nprogress@0.2.0)(postcss@8.5.15)(qrcode@1.5.4)(sass-embedded@1.100.0)(sass@1.100.0)(sortablejs@1.15.7)(terser@5.48.0)(typescript@6.0.3)(yaml@2.9.0)
|
version: 2.0.0-alpha.17(@types/node@25.9.1)(async-validator@4.2.5)(axios@1.16.1)(change-case@5.4.4)(jiti@2.7.0)(less@4.6.4)(lightningcss@1.32.0)(nprogress@0.2.0)(postcss@8.5.15)(qrcode@1.5.4)(sass-embedded@1.100.0)(sass@1.100.0)(sortablejs@1.15.7)(terser@5.48.0)(typescript@6.0.3)(yaml@2.9.0)
|
||||||
|
|
@ -7944,6 +7956,9 @@ packages:
|
||||||
devlop@1.1.0:
|
devlop@1.1.0:
|
||||||
resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
|
resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
|
||||||
|
|
||||||
|
dhtmlx-gantt@9.1.4:
|
||||||
|
resolution: {integrity: sha512-XCNA5QUiuV79Xq1ykNpH9LFNR2IVpDZMqnmBV6dsBeOkHyPMOpkyQ/gqAPCcK2GAvYHoN2nGAMYb2LldCWhMuQ==}
|
||||||
|
|
||||||
diagram-js-direct-editing@3.3.0:
|
diagram-js-direct-editing@3.3.0:
|
||||||
resolution: {integrity: sha512-EjXYb35J3qBU8lLz5U81hn7wNykVmF7U5DXZ7BvPok2IX7rmPz+ZyaI5AEMiqaC6lpSnHqPxFcPgKEiJcAiv5w==}
|
resolution: {integrity: sha512-EjXYb35J3qBU8lLz5U81hn7wNykVmF7U5DXZ7BvPok2IX7rmPz+ZyaI5AEMiqaC6lpSnHqPxFcPgKEiJcAiv5w==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|
@ -15694,6 +15709,13 @@ snapshots:
|
||||||
tailwindcss: 4.3.0
|
tailwindcss: 4.3.0
|
||||||
vite: 8.0.10(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0)
|
vite: 8.0.10(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0)
|
||||||
|
|
||||||
|
'@tailwindcss/vite@4.3.0(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0))':
|
||||||
|
dependencies:
|
||||||
|
'@tailwindcss/node': 4.3.0
|
||||||
|
'@tailwindcss/oxide': 4.3.0
|
||||||
|
tailwindcss: 4.3.0
|
||||||
|
vite: 8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0)
|
||||||
|
|
||||||
'@tanstack/store@0.11.0': {}
|
'@tanstack/store@0.11.0': {}
|
||||||
|
|
||||||
'@tanstack/virtual-core@3.15.0': {}
|
'@tanstack/virtual-core@3.15.0': {}
|
||||||
|
|
@ -16590,9 +16612,9 @@ snapshots:
|
||||||
global: 4.4.0
|
global: 4.4.0
|
||||||
is-function: 1.0.2
|
is-function: 1.0.2
|
||||||
|
|
||||||
'@vite-pwa/vitepress@1.1.0(vite-plugin-pwa@1.3.0(vite@8.0.10(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0))(workbox-build@7.4.1)(workbox-window@7.4.1))':
|
'@vite-pwa/vitepress@1.1.0(vite-plugin-pwa@1.3.0(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0))(workbox-build@7.4.1)(workbox-window@7.4.1))':
|
||||||
dependencies:
|
dependencies:
|
||||||
vite-plugin-pwa: 1.3.0(vite@8.0.10(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0))(workbox-build@7.4.1)(workbox-window@7.4.1)
|
vite-plugin-pwa: 1.3.0(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0))(workbox-build@7.4.1)(workbox-window@7.4.1)
|
||||||
|
|
||||||
'@vitejs/plugin-vue-jsx@5.1.5(vite@8.0.10(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0))(vue@3.5.34(typescript@6.0.3))':
|
'@vitejs/plugin-vue-jsx@5.1.5(vite@8.0.10(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0))(vue@3.5.34(typescript@6.0.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -18132,6 +18154,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
dequal: 2.0.3
|
dequal: 2.0.3
|
||||||
|
|
||||||
|
dhtmlx-gantt@9.1.4: {}
|
||||||
|
|
||||||
diagram-js-direct-editing@3.3.0(diagram-js@14.11.3):
|
diagram-js-direct-editing@3.3.0(diagram-js@14.11.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
diagram-js: 14.11.3
|
diagram-js: 14.11.3
|
||||||
|
|
@ -22536,6 +22560,17 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
vite-plugin-pwa@1.3.0(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0))(workbox-build@7.4.1)(workbox-window@7.4.1):
|
||||||
|
dependencies:
|
||||||
|
debug: 4.4.3
|
||||||
|
pretty-bytes: 6.1.1
|
||||||
|
tinyglobby: 0.2.16
|
||||||
|
vite: 8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0)
|
||||||
|
workbox-build: 7.4.1
|
||||||
|
workbox-window: 7.4.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
vite-plugin-vue-devtools@8.1.2(vite@8.0.10(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0))(vue@3.5.34(typescript@6.0.3)):
|
vite-plugin-vue-devtools@8.1.2(vite@8.0.10(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0))(vue@3.5.34(typescript@6.0.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/devtools-core': 8.1.2(vue@3.5.34(typescript@6.0.3))
|
'@vue/devtools-core': 8.1.2(vue@3.5.34(typescript@6.0.3))
|
||||||
|
|
@ -22620,13 +22655,13 @@ snapshots:
|
||||||
terser: 5.48.0
|
terser: 5.48.0
|
||||||
yaml: 2.9.0
|
yaml: 2.9.0
|
||||||
|
|
||||||
vitepress-plugin-group-icons@1.7.5(vite@8.0.10(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0)):
|
vitepress-plugin-group-icons@1.7.5(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@iconify-json/logos': 1.2.11
|
'@iconify-json/logos': 1.2.11
|
||||||
'@iconify-json/vscode-icons': 1.2.50
|
'@iconify-json/vscode-icons': 1.2.50
|
||||||
'@iconify/utils': 3.1.3
|
'@iconify/utils': 3.1.3
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 8.0.10(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0)
|
vite: 8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(less@4.6.4)(sass-embedded@1.100.0)(sass@1.100.0)(terser@5.48.0)(yaml@2.9.0)
|
||||||
|
|
||||||
vitepress@2.0.0-alpha.17(@types/node@25.9.1)(async-validator@4.2.5)(axios@1.16.1)(change-case@5.4.4)(jiti@2.7.0)(less@4.6.4)(lightningcss@1.32.0)(nprogress@0.2.0)(postcss@8.5.15)(qrcode@1.5.4)(sass-embedded@1.100.0)(sass@1.100.0)(sortablejs@1.15.7)(terser@5.48.0)(typescript@6.0.3)(yaml@2.9.0):
|
vitepress@2.0.0-alpha.17(@types/node@25.9.1)(async-validator@4.2.5)(axios@1.16.1)(change-case@5.4.4)(jiti@2.7.0)(less@4.6.4)(lightningcss@1.32.0)(nprogress@0.2.0)(postcss@8.5.15)(qrcode@1.5.4)(sass-embedded@1.100.0)(sass@1.100.0)(sortablejs@1.15.7)(terser@5.48.0)(typescript@6.0.3)(yaml@2.9.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue