feat(mes): 完善条码管理迁移并补齐业务选择器
parent
7ee42b9888
commit
6b6d45132f
|
|
@ -21,6 +21,8 @@ export namespace MesProWorkOrderApi {
|
|||
routeName?: string;
|
||||
clientId?: number;
|
||||
clientName?: string;
|
||||
vendorId?: number; // 供应商编号
|
||||
vendorName?: string; // 供应商名称
|
||||
planStartTime?: number | string;
|
||||
planEndTime?: number | string;
|
||||
actualStartTime?: number | string;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import type { PageParam, PageResult } from '@vben/request';
|
||||
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace MesWmItemReceiptApi {
|
||||
|
|
@ -19,16 +21,66 @@ export namespace MesWmItemReceiptApi {
|
|||
locationName?: string; // 库区名称
|
||||
areaId?: number; // 库位编号
|
||||
areaName?: string; // 库位名称
|
||||
receiptDate?: Date | number | string; // 入库日期
|
||||
receiptDate?: number; // 入库日期
|
||||
status?: number; // 状态
|
||||
remark?: string; // 备注
|
||||
createTime?: Date; // 创建时间
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询采购入库单分页 */
|
||||
export function getItemReceiptPage(params: PageParam) {
|
||||
return requestClient.get<PageResult<MesWmItemReceiptApi.ItemReceipt>>(
|
||||
'/mes/wm/item-receipt/page',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询采购入库单详情 */
|
||||
export function getItemReceipt(id: number) {
|
||||
return requestClient.get<MesWmItemReceiptApi.ItemReceipt>(
|
||||
`/mes/wm/item-receipt/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增采购入库单 */
|
||||
export function createItemReceipt(data: MesWmItemReceiptApi.ItemReceipt) {
|
||||
return requestClient.post<number>('/mes/wm/item-receipt/create', data);
|
||||
}
|
||||
|
||||
/** 修改采购入库单 */
|
||||
export function updateItemReceipt(data: MesWmItemReceiptApi.ItemReceipt) {
|
||||
return requestClient.put('/mes/wm/item-receipt/update', data);
|
||||
}
|
||||
|
||||
/** 删除采购入库单 */
|
||||
export function deleteItemReceipt(id: number) {
|
||||
return requestClient.delete(`/mes/wm/item-receipt/delete?id=${id}`);
|
||||
}
|
||||
|
||||
/** 提交采购入库单 */
|
||||
export function submitItemReceipt(id: number) {
|
||||
return requestClient.put(`/mes/wm/item-receipt/submit?id=${id}`);
|
||||
}
|
||||
|
||||
/** 执行上架 */
|
||||
export function stockItemReceipt(id: number) {
|
||||
return requestClient.put(`/mes/wm/item-receipt/stock?id=${id}`);
|
||||
}
|
||||
|
||||
/** 执行入库 */
|
||||
export function finishItemReceipt(id: number) {
|
||||
return requestClient.put(`/mes/wm/item-receipt/finish?id=${id}`);
|
||||
}
|
||||
|
||||
/** 取消采购入库单 */
|
||||
export function cancelItemReceipt(id: number) {
|
||||
return requestClient.put(`/mes/wm/item-receipt/cancel?id=${id}`);
|
||||
}
|
||||
|
||||
/** 导出采购入库单 */
|
||||
export function exportItemReceipt(params: any) {
|
||||
return requestClient.download('/mes/wm/item-receipt/export-excel', {
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@ import type { PageParam, PageResult } from '@vben/request';
|
|||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace MesWmItemReceiptLineApi {
|
||||
/** MES 物料接收单行 */
|
||||
/** MES 采购入库单行 */
|
||||
export interface ItemReceiptLine {
|
||||
id?: number; // 行编号
|
||||
receiptId?: number; // 入库单编号
|
||||
receiptCode?: string; // 入库单编码
|
||||
arrivalNoticeLineId?: number; // 到货通知单行编号
|
||||
purchaseOrderCode?: string; // 采购订单号
|
||||
itemId?: number; // 物料编号
|
||||
itemCode?: string; // 物料编码
|
||||
|
|
@ -15,14 +16,48 @@ export namespace MesWmItemReceiptLineApi {
|
|||
specification?: string; // 规格型号
|
||||
unitMeasureName?: string; // 单位
|
||||
receivedQuantity?: number; // 入库数量
|
||||
batchId?: number; // 批次编号
|
||||
batchCode?: string; // 批次号
|
||||
productionDate?: number; // 生产日期
|
||||
expireDate?: number; // 有效期
|
||||
lotNumber?: string; // 生产批号
|
||||
iqcCheckFlag?: boolean; // 是否检验
|
||||
iqcId?: number; // 来料检验单编号
|
||||
iqcCode?: string; // 来料检验单编码
|
||||
remark?: string; // 备注
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询物料接收单行分页 */
|
||||
/** 查询采购入库单行分页 */
|
||||
export function getItemReceiptLinePage(params: PageParam) {
|
||||
return requestClient.get<PageResult<MesWmItemReceiptLineApi.ItemReceiptLine>>(
|
||||
'/mes/wm/item-receipt-line/page',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询采购入库单行详情 */
|
||||
export function getItemReceiptLine(id: number) {
|
||||
return requestClient.get<MesWmItemReceiptLineApi.ItemReceiptLine>(
|
||||
`/mes/wm/item-receipt-line/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增采购入库单行 */
|
||||
export function createItemReceiptLine(
|
||||
data: MesWmItemReceiptLineApi.ItemReceiptLine,
|
||||
) {
|
||||
return requestClient.post<number>('/mes/wm/item-receipt-line/create', data);
|
||||
}
|
||||
|
||||
/** 修改采购入库单行 */
|
||||
export function updateItemReceiptLine(
|
||||
data: MesWmItemReceiptLineApi.ItemReceiptLine,
|
||||
) {
|
||||
return requestClient.put('/mes/wm/item-receipt-line/update', data);
|
||||
}
|
||||
|
||||
/** 删除采购入库单行 */
|
||||
export function deleteItemReceiptLine(id: number) {
|
||||
return requestClient.delete(`/mes/wm/item-receipt-line/delete?id=${id}`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace MesWmOutsourceIssueDetailApi {
|
||||
/** MES 外协发料单明细 */
|
||||
export interface OutsourceIssueDetail {
|
||||
id?: number; // 明细编号
|
||||
lineId?: number; // 行编号
|
||||
issueId?: number; // 发料单编号
|
||||
itemId?: number; // 物料编号
|
||||
itemCode?: string; // 物料编码
|
||||
itemName?: string; // 物料名称
|
||||
specification?: string; // 规格型号
|
||||
unitMeasureName?: string; // 计量单位名称
|
||||
quantity?: number; // 数量
|
||||
materialStockId?: number; // 库存编号
|
||||
batchId?: number; // 批次编号
|
||||
batchCode?: string; // 批次编码
|
||||
warehouseId?: number; // 仓库编号
|
||||
warehouseName?: string; // 仓库名称
|
||||
locationId?: number; // 库区编号
|
||||
locationName?: string; // 库区名称
|
||||
areaId?: number; // 库位编号
|
||||
areaName?: string; // 库位名称
|
||||
remark?: string; // 备注
|
||||
createTime?: Date; // 创建时间
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询外协发料单明细列表 */
|
||||
export function getOutsourceIssueDetailListByLineId(lineId: number) {
|
||||
return requestClient.get<
|
||||
MesWmOutsourceIssueDetailApi.OutsourceIssueDetail[]
|
||||
>('/mes/wm/outsource-issue-detail/list-by-line', { params: { lineId } });
|
||||
}
|
||||
|
||||
/** 查询外协发料单明细详情 */
|
||||
export function getOutsourceIssueDetail(id: number) {
|
||||
return requestClient.get<MesWmOutsourceIssueDetailApi.OutsourceIssueDetail>(
|
||||
`/mes/wm/outsource-issue-detail/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增外协发料单明细 */
|
||||
export function createOutsourceIssueDetail(
|
||||
data: MesWmOutsourceIssueDetailApi.OutsourceIssueDetail,
|
||||
) {
|
||||
return requestClient.post('/mes/wm/outsource-issue-detail/create', data);
|
||||
}
|
||||
|
||||
/** 修改外协发料单明细 */
|
||||
export function updateOutsourceIssueDetail(
|
||||
data: MesWmOutsourceIssueDetailApi.OutsourceIssueDetail,
|
||||
) {
|
||||
return requestClient.put('/mes/wm/outsource-issue-detail/update', data);
|
||||
}
|
||||
|
||||
/** 删除外协发料单明细 */
|
||||
export function deleteOutsourceIssueDetail(id: number) {
|
||||
return requestClient.delete(`/mes/wm/outsource-issue-detail/delete?id=${id}`);
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
import type { PageParam, PageResult } from '@vben/request';
|
||||
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace MesWmOutsourceIssueApi {
|
||||
/** MES 外协发料单 */
|
||||
export interface OutsourceIssue {
|
||||
id?: number; // 发料单编号
|
||||
code?: string; // 发料单编号
|
||||
name?: string; // 发料单名称
|
||||
vendorId?: number; // 供应商编号
|
||||
vendorCode?: string; // 供应商编码
|
||||
vendorName?: string; // 供应商名称
|
||||
workOrderId?: number; // 生产工单编号
|
||||
workOrderCode?: string; // 生产工单编码
|
||||
workOrderName?: string; // 生产工单名称
|
||||
issueDate?: number; // 发料日期
|
||||
status?: number; // 单据状态
|
||||
remark?: string; // 备注
|
||||
createTime?: Date; // 创建时间
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询外协发料单分页 */
|
||||
export function getOutsourceIssuePage(params: PageParam) {
|
||||
return requestClient.get<PageResult<MesWmOutsourceIssueApi.OutsourceIssue>>(
|
||||
'/mes/wm/outsource-issue/page',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询外协发料单详情 */
|
||||
export function getOutsourceIssue(id: number) {
|
||||
return requestClient.get<MesWmOutsourceIssueApi.OutsourceIssue>(
|
||||
`/mes/wm/outsource-issue/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增外协发料单 */
|
||||
export function createOutsourceIssue(
|
||||
data: MesWmOutsourceIssueApi.OutsourceIssue,
|
||||
) {
|
||||
return requestClient.post<number>('/mes/wm/outsource-issue/create', data);
|
||||
}
|
||||
|
||||
/** 修改外协发料单 */
|
||||
export function updateOutsourceIssue(
|
||||
data: MesWmOutsourceIssueApi.OutsourceIssue,
|
||||
) {
|
||||
return requestClient.put('/mes/wm/outsource-issue/update', data);
|
||||
}
|
||||
|
||||
/** 删除外协发料单 */
|
||||
export function deleteOutsourceIssue(id: number) {
|
||||
return requestClient.delete(`/mes/wm/outsource-issue/delete?id=${id}`);
|
||||
}
|
||||
|
||||
/** 提交外协发料单 */
|
||||
export function submitOutsourceIssue(id: number) {
|
||||
return requestClient.put(`/mes/wm/outsource-issue/submit?id=${id}`);
|
||||
}
|
||||
|
||||
/** 执行拣货 */
|
||||
export function stockOutsourceIssue(id: number) {
|
||||
return requestClient.put(`/mes/wm/outsource-issue/stock?id=${id}`);
|
||||
}
|
||||
|
||||
/** 执行领出 */
|
||||
export function finishOutsourceIssue(id: number) {
|
||||
return requestClient.put(`/mes/wm/outsource-issue/finish?id=${id}`);
|
||||
}
|
||||
|
||||
/** 取消外协发料单 */
|
||||
export function cancelOutsourceIssue(id: number) {
|
||||
return requestClient.put(`/mes/wm/outsource-issue/cancel?id=${id}`);
|
||||
}
|
||||
|
||||
/** 校验外协发料单拣货数量是否与发料数量一致 */
|
||||
export function checkOutsourceIssueQuantity(id: number) {
|
||||
return requestClient.get<boolean>(
|
||||
`/mes/wm/outsource-issue/check-quantity?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 导出外协发料单 */
|
||||
export function exportOutsourceIssue(params: any) {
|
||||
return requestClient.download('/mes/wm/outsource-issue/export-excel', {
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
import type { PageParam, PageResult } from '@vben/request';
|
||||
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace MesWmOutsourceIssueLineApi {
|
||||
/** MES 外协发料单行 */
|
||||
export interface OutsourceIssueLine {
|
||||
id?: number; // 行编号
|
||||
issueId?: number; // 发料单编号
|
||||
itemId?: number; // 物料编号
|
||||
itemCode?: string; // 物料编码
|
||||
itemName?: string; // 物料名称
|
||||
specification?: string; // 规格型号
|
||||
unitMeasureName?: string; // 计量单位名称
|
||||
quantity?: number; // 发料数量
|
||||
materialStockId?: number; // 库存编号
|
||||
batchId?: number; // 批次编号
|
||||
batchCode?: string; // 批次编码
|
||||
remark?: string; // 备注
|
||||
createTime?: Date; // 创建时间
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询外协发料单行分页 */
|
||||
export function getOutsourceIssueLinePage(params: PageParam) {
|
||||
return requestClient.get<
|
||||
PageResult<MesWmOutsourceIssueLineApi.OutsourceIssueLine>
|
||||
>('/mes/wm/outsource-issue-line/page', { params });
|
||||
}
|
||||
|
||||
/** 查询外协发料单行详情 */
|
||||
export function getOutsourceIssueLine(id: number) {
|
||||
return requestClient.get<MesWmOutsourceIssueLineApi.OutsourceIssueLine>(
|
||||
`/mes/wm/outsource-issue-line/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增外协发料单行 */
|
||||
export function createOutsourceIssueLine(
|
||||
data: MesWmOutsourceIssueLineApi.OutsourceIssueLine,
|
||||
) {
|
||||
return requestClient.post('/mes/wm/outsource-issue-line/create', data);
|
||||
}
|
||||
|
||||
/** 修改外协发料单行 */
|
||||
export function updateOutsourceIssueLine(
|
||||
data: MesWmOutsourceIssueLineApi.OutsourceIssueLine,
|
||||
) {
|
||||
return requestClient.put('/mes/wm/outsource-issue-line/update', data);
|
||||
}
|
||||
|
||||
/** 删除外协发料单行 */
|
||||
export function deleteOutsourceIssueLine(id: number) {
|
||||
return requestClient.delete(`/mes/wm/outsource-issue-line/delete?id=${id}`);
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace MesWmOutsourceReceiptDetailApi {
|
||||
/** MES 外协入库单明细 */
|
||||
export interface OutsourceReceiptDetail {
|
||||
id?: number; // 明细编号
|
||||
lineId?: number; // 行编号
|
||||
receiptId?: number; // 入库单编号
|
||||
itemId?: number; // 物料编号
|
||||
itemCode?: string; // 物料编码
|
||||
itemName?: string; // 物料名称
|
||||
specification?: string; // 规格型号
|
||||
unitMeasureName?: string; // 计量单位名称
|
||||
quantity?: number; // 上架数量
|
||||
batchId?: number; // 批次编号
|
||||
batchCode?: string; // 批次编码
|
||||
warehouseId?: number; // 仓库编号
|
||||
warehouseName?: string; // 仓库名称
|
||||
locationId?: number; // 库区编号
|
||||
locationName?: string; // 库区名称
|
||||
areaId?: number; // 库位编号
|
||||
areaName?: string; // 库位名称
|
||||
remark?: string; // 备注
|
||||
createTime?: Date; // 创建时间
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询外协入库单明细列表 */
|
||||
export function getOutsourceReceiptDetailListByLineId(lineId: number) {
|
||||
return requestClient.get<
|
||||
MesWmOutsourceReceiptDetailApi.OutsourceReceiptDetail[]
|
||||
>('/mes/wm/outsource-receipt-detail/list-by-line', { params: { lineId } });
|
||||
}
|
||||
|
||||
/** 查询外协入库单明细详情 */
|
||||
export function getOutsourceReceiptDetail(id: number) {
|
||||
return requestClient.get<MesWmOutsourceReceiptDetailApi.OutsourceReceiptDetail>(
|
||||
`/mes/wm/outsource-receipt-detail/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增外协入库单明细 */
|
||||
export function createOutsourceReceiptDetail(
|
||||
data: MesWmOutsourceReceiptDetailApi.OutsourceReceiptDetail,
|
||||
) {
|
||||
return requestClient.post('/mes/wm/outsource-receipt-detail/create', data);
|
||||
}
|
||||
|
||||
/** 修改外协入库单明细 */
|
||||
export function updateOutsourceReceiptDetail(
|
||||
data: MesWmOutsourceReceiptDetailApi.OutsourceReceiptDetail,
|
||||
) {
|
||||
return requestClient.put('/mes/wm/outsource-receipt-detail/update', data);
|
||||
}
|
||||
|
||||
/** 删除外协入库单明细 */
|
||||
export function deleteOutsourceReceiptDetail(id: number) {
|
||||
return requestClient.delete(
|
||||
`/mes/wm/outsource-receipt-detail/delete?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
import type { PageParam, PageResult } from '@vben/request';
|
||||
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace MesWmOutsourceReceiptApi {
|
||||
/** MES 外协入库单 */
|
||||
export interface OutsourceReceipt {
|
||||
id?: number; // 入库单编号
|
||||
code?: string; // 入库单编码
|
||||
name?: string; // 入库单名称
|
||||
workOrderId?: number; // 外协工单编号
|
||||
workOrderCode?: string; // 外协工单编码
|
||||
vendorId?: number; // 供应商编号
|
||||
vendorName?: string; // 供应商名称
|
||||
receiptDate?: number; // 入库日期
|
||||
status?: number; // 单据状态
|
||||
remark?: string; // 备注
|
||||
createTime?: Date; // 创建时间
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询外协入库单分页 */
|
||||
export function getOutsourceReceiptPage(params: PageParam) {
|
||||
return requestClient.get<PageResult<MesWmOutsourceReceiptApi.OutsourceReceipt>>(
|
||||
'/mes/wm/outsource-receipt/page',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询外协入库单详情 */
|
||||
export function getOutsourceReceipt(id: number) {
|
||||
return requestClient.get<MesWmOutsourceReceiptApi.OutsourceReceipt>(
|
||||
`/mes/wm/outsource-receipt/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增外协入库单 */
|
||||
export function createOutsourceReceipt(
|
||||
data: MesWmOutsourceReceiptApi.OutsourceReceipt,
|
||||
) {
|
||||
return requestClient.post<number>('/mes/wm/outsource-receipt/create', data);
|
||||
}
|
||||
|
||||
/** 修改外协入库单 */
|
||||
export function updateOutsourceReceipt(
|
||||
data: MesWmOutsourceReceiptApi.OutsourceReceipt,
|
||||
) {
|
||||
return requestClient.put('/mes/wm/outsource-receipt/update', data);
|
||||
}
|
||||
|
||||
/** 删除外协入库单 */
|
||||
export function deleteOutsourceReceipt(id: number) {
|
||||
return requestClient.delete(`/mes/wm/outsource-receipt/delete?id=${id}`);
|
||||
}
|
||||
|
||||
/** 提交外协入库单 */
|
||||
export function submitOutsourceReceipt(id: number) {
|
||||
return requestClient.put(`/mes/wm/outsource-receipt/submit?id=${id}`);
|
||||
}
|
||||
|
||||
/** 执行上架 */
|
||||
export function stockOutsourceReceipt(id: number) {
|
||||
return requestClient.put(`/mes/wm/outsource-receipt/stock?id=${id}`);
|
||||
}
|
||||
|
||||
/** 完成入库 */
|
||||
export function finishOutsourceReceipt(id: number) {
|
||||
return requestClient.put(`/mes/wm/outsource-receipt/finish?id=${id}`);
|
||||
}
|
||||
|
||||
/** 取消外协入库单 */
|
||||
export function cancelOutsourceReceipt(id: number) {
|
||||
return requestClient.put(`/mes/wm/outsource-receipt/cancel?id=${id}`);
|
||||
}
|
||||
|
||||
/** 导出外协入库单 */
|
||||
export function exportOutsourceReceipt(params: any) {
|
||||
return requestClient.download('/mes/wm/outsource-receipt/export-excel', {
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
import type { PageParam, PageResult } from '@vben/request';
|
||||
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace MesWmOutsourceReceiptLineApi {
|
||||
/** MES 外协入库单行 */
|
||||
export interface OutsourceReceiptLine {
|
||||
id?: number; // 行编号
|
||||
receiptId?: number; // 入库单编号
|
||||
itemId?: number; // 物料编号
|
||||
itemCode?: string; // 物料编码
|
||||
itemName?: string; // 物料名称
|
||||
specification?: string; // 规格型号
|
||||
unitMeasureName?: string; // 计量单位名称
|
||||
quantity?: number; // 入库数量
|
||||
batchId?: number; // 批次编号
|
||||
batchCode?: string; // 批次编码
|
||||
productionDate?: number; // 生产日期
|
||||
expireDate?: number; // 有效期
|
||||
lotNumber?: string; // 生产批号
|
||||
iqcCheckFlag?: boolean; // 是否需要质检
|
||||
remark?: string; // 备注
|
||||
createTime?: Date; // 创建时间
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询外协入库单行分页 */
|
||||
export function getOutsourceReceiptLinePage(params: PageParam) {
|
||||
return requestClient.get<
|
||||
PageResult<MesWmOutsourceReceiptLineApi.OutsourceReceiptLine>
|
||||
>('/mes/wm/outsource-receipt-line/page', { params });
|
||||
}
|
||||
|
||||
/** 查询外协入库单行详情 */
|
||||
export function getOutsourceReceiptLine(id: number) {
|
||||
return requestClient.get<MesWmOutsourceReceiptLineApi.OutsourceReceiptLine>(
|
||||
`/mes/wm/outsource-receipt-line/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增外协入库单行 */
|
||||
export function createOutsourceReceiptLine(
|
||||
data: MesWmOutsourceReceiptLineApi.OutsourceReceiptLine,
|
||||
) {
|
||||
return requestClient.post('/mes/wm/outsource-receipt-line/create', data);
|
||||
}
|
||||
|
||||
/** 修改外协入库单行 */
|
||||
export function updateOutsourceReceiptLine(
|
||||
data: MesWmOutsourceReceiptLineApi.OutsourceReceiptLine,
|
||||
) {
|
||||
return requestClient.put('/mes/wm/outsource-receipt-line/update', data);
|
||||
}
|
||||
|
||||
/** 删除外协入库单行 */
|
||||
export function deleteOutsourceReceiptLine(id: number) {
|
||||
return requestClient.delete(`/mes/wm/outsource-receipt-line/delete?id=${id}`);
|
||||
}
|
||||
|
|
@ -5,12 +5,24 @@ import { requestClient } from '#/api/request';
|
|||
export namespace MesWmProductSalesApi {
|
||||
/** MES 销售出库单 */
|
||||
export interface ProductSales {
|
||||
id?: number; // 销售出库单编号
|
||||
id?: number; // 出库单编号
|
||||
code?: string; // 出库单编号
|
||||
name?: string; // 出库单名称
|
||||
noticeId?: number; // 发货通知单编号
|
||||
noticeCode?: string; // 发货通知单编码
|
||||
clientId?: number; // 客户编号
|
||||
clientCode?: string; // 客户编码
|
||||
clientName?: string; // 客户名称
|
||||
salesOrderCode?: string; // 销售订单编号
|
||||
salesDate?: Date; // 出库日期
|
||||
salesDate?: number; // 出库日期
|
||||
contactName?: string; // 收货人
|
||||
contactTelephone?: string; // 联系方式
|
||||
contactAddress?: string; // 收货地址
|
||||
carrier?: string; // 承运商
|
||||
shippingNumber?: string; // 运输单号
|
||||
status?: number; // 单据状态
|
||||
remark?: string; // 备注
|
||||
createTime?: Date; // 创建时间
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -21,3 +33,64 @@ export function getProductSalesPage(params: PageParam) {
|
|||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询销售出库单详情 */
|
||||
export function getProductSales(id: number) {
|
||||
return requestClient.get<MesWmProductSalesApi.ProductSales>(
|
||||
`/mes/wm/product-sales/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增销售出库单 */
|
||||
export function createProductSales(data: MesWmProductSalesApi.ProductSales) {
|
||||
return requestClient.post<number>('/mes/wm/product-sales/create', data);
|
||||
}
|
||||
|
||||
/** 修改销售出库单 */
|
||||
export function updateProductSales(data: MesWmProductSalesApi.ProductSales) {
|
||||
return requestClient.put('/mes/wm/product-sales/update', data);
|
||||
}
|
||||
|
||||
/** 删除销售出库单 */
|
||||
export function deleteProductSales(id: number) {
|
||||
return requestClient.delete(`/mes/wm/product-sales/delete?id=${id}`);
|
||||
}
|
||||
|
||||
/** 提交销售出库单 */
|
||||
export function submitProductSales(id: number) {
|
||||
return requestClient.put(`/mes/wm/product-sales/submit?id=${id}`);
|
||||
}
|
||||
|
||||
/** 执行拣货 */
|
||||
export function stockProductSales(id: number) {
|
||||
return requestClient.put(`/mes/wm/product-sales/stock?id=${id}`);
|
||||
}
|
||||
|
||||
/** 填写运单 */
|
||||
export function shippingProductSales(data: MesWmProductSalesApi.ProductSales) {
|
||||
return requestClient.put('/mes/wm/product-sales/shipping', data);
|
||||
}
|
||||
|
||||
/** 执行出库 */
|
||||
export function finishProductSales(id: number) {
|
||||
return requestClient.put(`/mes/wm/product-sales/finish?id=${id}`);
|
||||
}
|
||||
|
||||
/** 取消销售出库单 */
|
||||
export function cancelProductSales(id: number) {
|
||||
return requestClient.put(`/mes/wm/product-sales/cancel?id=${id}`);
|
||||
}
|
||||
|
||||
/** 校验销售出库单拣货数量是否与出库数量一致 */
|
||||
export function checkProductSalesQuantity(id: number) {
|
||||
return requestClient.get<boolean>(
|
||||
`/mes/wm/product-sales/check-quantity?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 导出销售出库单 */
|
||||
export function exportProductSales(params: any) {
|
||||
return requestClient.download('/mes/wm/product-sales/export-excel', {
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,13 +6,19 @@ export namespace MesWmProductSalesLineApi {
|
|||
/** MES 销售出库单行 */
|
||||
export interface ProductSalesLine {
|
||||
id?: number; // 行编号
|
||||
salesId?: number; // 出库单编号
|
||||
noticeLineId?: number; // 发货通知单行编号
|
||||
itemId?: number; // 物料编号
|
||||
itemCode?: string; // 物料编码
|
||||
itemName?: string; // 物料名称
|
||||
specification?: string; // 规格型号
|
||||
unitMeasureName?: string; // 单位
|
||||
quantity?: number; // 出库数量
|
||||
pickedQuantity?: number; // 已拣货数量
|
||||
batchId?: number; // 批次编号
|
||||
batchCode?: string; // 批次号
|
||||
oqcCheckFlag?: boolean; // 是否检验
|
||||
remark?: string; // 备注
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -22,3 +28,29 @@ export function getProductSalesLinePage(params: PageParam) {
|
|||
PageResult<MesWmProductSalesLineApi.ProductSalesLine>
|
||||
>('/mes/wm/product-sales-line/page', { params });
|
||||
}
|
||||
|
||||
/** 查询销售出库单行详情 */
|
||||
export function getProductSalesLine(id: number) {
|
||||
return requestClient.get<MesWmProductSalesLineApi.ProductSalesLine>(
|
||||
`/mes/wm/product-sales-line/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增销售出库单行 */
|
||||
export function createProductSalesLine(
|
||||
data: MesWmProductSalesLineApi.ProductSalesLine,
|
||||
) {
|
||||
return requestClient.post<number>('/mes/wm/product-sales-line/create', data);
|
||||
}
|
||||
|
||||
/** 修改销售出库单行 */
|
||||
export function updateProductSalesLine(
|
||||
data: MesWmProductSalesLineApi.ProductSalesLine,
|
||||
) {
|
||||
return requestClient.put('/mes/wm/product-sales-line/update', data);
|
||||
}
|
||||
|
||||
/** 删除销售出库单行 */
|
||||
export function deleteProductSalesLine(id: number) {
|
||||
return requestClient.delete(`/mes/wm/product-sales-line/delete?id=${id}`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
export { default as ProCardSelectDialog } from './pro-card-select-dialog.vue';
|
||||
export { default as ProCardSelect } from './pro-card-select.vue';
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
<script lang="ts" setup>
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { MesProCardApi } from '#/api/mes/pro/card';
|
||||
|
||||
import { nextTick, ref } from 'vue';
|
||||
|
||||
import { Button, message, Modal } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { getCardPage } from '#/api/mes/pro/card';
|
||||
|
||||
import { useCardSelectGridColumns, useCardSelectGridFormSchema } from '../data';
|
||||
|
||||
const emit = defineEmits<{
|
||||
selected: [rows: MesProCardApi.Card[]];
|
||||
}>();
|
||||
|
||||
const open = ref(false); // 弹窗是否打开
|
||||
const multiple = ref(false); // 是否多选;默认按单选选择器使用
|
||||
const selectedRows = ref<MesProCardApi.Card[]>([]); // 已选流转卡列表
|
||||
const preSelectedIds = ref<number[]>([]); // 预选流转卡编号列表
|
||||
|
||||
/** 获取多选记录,包含 VXE reserve 跨页记录 */
|
||||
function getMultipleSelectedRows() {
|
||||
const selectedMap = new Map<number, MesProCardApi.Card>();
|
||||
const records = [
|
||||
...(gridApi.grid.getCheckboxReserveRecords?.() ?? []),
|
||||
...(gridApi.grid.getCheckboxRecords?.() ?? []),
|
||||
] as MesProCardApi.Card[];
|
||||
records.forEach((row) => {
|
||||
const rowId = row.id;
|
||||
if (rowId !== undefined) {
|
||||
selectedMap.set(rowId, row);
|
||||
}
|
||||
});
|
||||
return [...selectedMap.values()];
|
||||
}
|
||||
|
||||
/** 处理多选勾选变化 */
|
||||
function handleCheckboxSelectChange() {
|
||||
selectedRows.value = getMultipleSelectedRows();
|
||||
}
|
||||
|
||||
/** 处理单选切换 */
|
||||
function handleRadioChange(row: MesProCardApi.Card) {
|
||||
selectedRows.value = [row];
|
||||
}
|
||||
|
||||
/** 多选模式下切换行勾选 */
|
||||
async function toggleMultipleRow(row: MesProCardApi.Card) {
|
||||
const selected = gridApi.grid.isCheckedByCheckboxRow(row);
|
||||
await gridApi.grid.setCheckboxRow(row, !selected);
|
||||
selectedRows.value = getMultipleSelectedRows();
|
||||
}
|
||||
|
||||
/** 处理行双击:单选直接确认,多选切换勾选 */
|
||||
async function handleCellDblclick({ row }: { row: MesProCardApi.Card }) {
|
||||
if (multiple.value) {
|
||||
await toggleMultipleRow(row);
|
||||
return;
|
||||
}
|
||||
selectedRows.value = [row];
|
||||
await gridApi.grid.setRadioRow(row);
|
||||
handleConfirm();
|
||||
}
|
||||
|
||||
/** 回显预选流转卡 */
|
||||
async function applyPreSelection() {
|
||||
if (preSelectedIds.value.length === 0) {
|
||||
return;
|
||||
}
|
||||
const rows = gridApi.grid.getData() as MesProCardApi.Card[];
|
||||
for (const row of rows) {
|
||||
if (row.id === undefined || !preSelectedIds.value.includes(row.id)) {
|
||||
continue;
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
formOptions: {
|
||||
schema: useCardSelectGridFormSchema(),
|
||||
},
|
||||
gridOptions: {
|
||||
columns: useCardSelectGridColumns(false),
|
||||
height: 520,
|
||||
keepSource: true,
|
||||
checkboxConfig: {
|
||||
highlight: true,
|
||||
range: true,
|
||||
reserve: true,
|
||||
},
|
||||
radioConfig: {
|
||||
highlight: true,
|
||||
trigger: 'row',
|
||||
},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }, formValues) => {
|
||||
return await getCardPage({
|
||||
pageNo: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
...formValues,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
rowConfig: {
|
||||
keyField: 'id',
|
||||
isHover: true,
|
||||
},
|
||||
toolbarConfig: {
|
||||
refresh: true,
|
||||
search: true,
|
||||
},
|
||||
} as VxeTableGridOptions<MesProCardApi.Card>,
|
||||
gridEvents: {
|
||||
cellDblclick: handleCellDblclick,
|
||||
checkboxAll: handleCheckboxSelectChange,
|
||||
checkboxChange: handleCheckboxSelectChange,
|
||||
radioChange: ({ row }: { row: MesProCardApi.Card }) => {
|
||||
handleRadioChange(row);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/** 重置查询和选择状态 */
|
||||
async function resetQueryState() {
|
||||
selectedRows.value = [];
|
||||
await gridApi.grid.clearCheckboxRow();
|
||||
await gridApi.grid.clearCheckboxReserve();
|
||||
await gridApi.grid.clearRadioRow();
|
||||
await gridApi.formApi.resetForm();
|
||||
}
|
||||
|
||||
/** 打开流转卡选择弹窗 */
|
||||
async function openModal(
|
||||
selectedIds?: number[],
|
||||
options?: { multiple?: boolean },
|
||||
) {
|
||||
open.value = true;
|
||||
multiple.value = options?.multiple ?? false;
|
||||
preSelectedIds.value = selectedIds || [];
|
||||
await nextTick();
|
||||
gridApi.setGridOptions({
|
||||
columns: useCardSelectGridColumns(multiple.value),
|
||||
});
|
||||
await resetQueryState();
|
||||
await gridApi.query();
|
||||
await nextTick();
|
||||
await applyPreSelection();
|
||||
}
|
||||
|
||||
/** 关闭流转卡选择弹窗 */
|
||||
function closeModal() {
|
||||
open.value = false;
|
||||
}
|
||||
|
||||
/** 确认选择流转卡 */
|
||||
function handleConfirm() {
|
||||
const rows = multiple.value ? getMultipleSelectedRows() : selectedRows.value;
|
||||
if (rows.length === 0) {
|
||||
message.warning(multiple.value ? '请至少选择一条数据' : '请选择一条数据');
|
||||
return;
|
||||
}
|
||||
emit('selected', multiple.value ? rows : [rows[0]!]);
|
||||
open.value = false;
|
||||
}
|
||||
|
||||
defineExpose({ open: openModal });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal
|
||||
v-model:open="open"
|
||||
title="流转卡选择"
|
||||
width="70%"
|
||||
:destroy-on-close="true"
|
||||
@ok="handleConfirm"
|
||||
@cancel="closeModal"
|
||||
>
|
||||
<Grid table-title="流转卡列表" />
|
||||
<template #footer>
|
||||
<Button @click="closeModal">取消</Button>
|
||||
<Button type="primary" @click="handleConfirm">确定</Button>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
<script lang="ts" setup>
|
||||
import type { MesProCardApi } from '#/api/mes/pro/card';
|
||||
|
||||
import { computed, ref, useAttrs, watch } from 'vue';
|
||||
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
|
||||
import { Input, Tooltip } from 'ant-design-vue';
|
||||
|
||||
import { getCard } from '#/api/mes/pro/card';
|
||||
|
||||
import ProCardSelectDialog from './pro-card-select-dialog.vue';
|
||||
|
||||
defineOptions({ name: 'ProCardSelect', inheritAttrs: false });
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
allowClear?: boolean;
|
||||
disabled?: boolean;
|
||||
modelValue?: number;
|
||||
placeholder?: string;
|
||||
}>(),
|
||||
{
|
||||
allowClear: true,
|
||||
disabled: false,
|
||||
modelValue: undefined,
|
||||
placeholder: '请选择流转卡',
|
||||
},
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
change: [item: MesProCardApi.Card | undefined];
|
||||
'update:modelValue': [value: number | undefined];
|
||||
}>();
|
||||
|
||||
const attrs = useAttrs();
|
||||
const dialogRef = ref<InstanceType<typeof ProCardSelectDialog>>();
|
||||
const hovering = ref(false);
|
||||
const selectedItem = ref<MesProCardApi.Card>();
|
||||
|
||||
const displayLabel = computed(() => selectedItem.value?.code ?? '');
|
||||
|
||||
const showClear = computed(
|
||||
() =>
|
||||
props.allowClear &&
|
||||
!props.disabled &&
|
||||
hovering.value &&
|
||||
props.modelValue != null,
|
||||
);
|
||||
|
||||
/** 根据编号单条查询流转卡信息(用于编辑回显) */
|
||||
async function resolveItemById(id: number | undefined) {
|
||||
if (id == null) {
|
||||
selectedItem.value = undefined;
|
||||
return;
|
||||
}
|
||||
if (selectedItem.value?.id === id) {
|
||||
return;
|
||||
}
|
||||
selectedItem.value = await getCard(id);
|
||||
}
|
||||
|
||||
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 });
|
||||
}
|
||||
|
||||
/** 弹窗选中回调 */
|
||||
function handleSelected(rows: MesProCardApi.Card[]) {
|
||||
const item = rows[0];
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
selectedItem.value = item;
|
||||
emit('update:modelValue', item.id);
|
||||
emit('change', item);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-bind="attrs"
|
||||
class="w-full"
|
||||
:class="disabled ? 'cursor-not-allowed' : 'cursor-pointer'"
|
||||
@click="handleClick"
|
||||
@mouseenter="hovering = true"
|
||||
@mouseleave="hovering = false"
|
||||
>
|
||||
<Tooltip :mouse-enter-delay="0.5" :open="selectedItem ? undefined : false">
|
||||
<template #title>
|
||||
<div v-if="selectedItem" class="leading-6">
|
||||
<div>编号:{{ selectedItem.code || '-' }}</div>
|
||||
<div>工单:{{ selectedItem.workOrderCode || '-' }}</div>
|
||||
<div>批次:{{ selectedItem.batchCode || '-' }}</div>
|
||||
<div>产品:{{ selectedItem.itemName || '-' }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<Input
|
||||
:disabled="disabled"
|
||||
:placeholder="placeholder"
|
||||
:value="displayLabel"
|
||||
readonly
|
||||
>
|
||||
<template #suffix>
|
||||
<IconifyIcon
|
||||
class="size-4"
|
||||
:icon="showClear ? 'lucide:circle-x' : 'lucide:search'"
|
||||
/>
|
||||
</template>
|
||||
</Input>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<ProCardSelectDialog ref="dialogRef" @selected="handleSelected" />
|
||||
</template>
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
import type { VbenFormSchema } from '#/adapter/form';
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { MesProCardApi } from '#/api/mes/pro/card';
|
||||
|
||||
import { markRaw } from 'vue';
|
||||
|
||||
import { MdItemSelect } from '#/views/mes/md/item/components';
|
||||
import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components';
|
||||
|
||||
/** 流转卡选择弹窗的搜索表单 */
|
||||
export function useCardSelectGridFormSchema(): 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 useCardSelectGridColumns(
|
||||
multiple = false,
|
||||
): VxeTableGridOptions<MesProCardApi.Card>['columns'] {
|
||||
return [
|
||||
{
|
||||
type: multiple ? 'checkbox' : 'radio',
|
||||
width: 50,
|
||||
},
|
||||
{
|
||||
field: 'code',
|
||||
title: '流转卡编号',
|
||||
width: 160,
|
||||
},
|
||||
{
|
||||
field: 'workOrderCode',
|
||||
title: '生产工单编号',
|
||||
width: 160,
|
||||
},
|
||||
{
|
||||
field: 'itemCode',
|
||||
title: '产品物料编码',
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
field: 'batchCode',
|
||||
title: '批次号',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: 'itemName',
|
||||
title: '产品物料名称',
|
||||
minWidth: 150,
|
||||
},
|
||||
{
|
||||
field: 'specification',
|
||||
title: '规格型号',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: 'unitMeasureName',
|
||||
title: '单位',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
field: 'transferedQuantity',
|
||||
title: '流转数量',
|
||||
width: 100,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
@ -151,11 +151,22 @@ export const MesAutoCodeRuleCode = {
|
|||
TM_TOOL_CODE: 'TM_TOOL_CODE',
|
||||
WM_AREA_CODE: 'WM_AREA_CODE',
|
||||
WM_LOCATION_CODE: 'WM_LOCATION_CODE',
|
||||
WM_ARRIVAL_NOTICE_CODE: 'WM_ARRIVAL_NOTICE_CODE',
|
||||
WM_ITEM_RECEIPT_CODE: 'WM_ITEM_RECEIPT_CODE',
|
||||
WM_RETURN_VENDOR_CODE: 'WM_RETURN_VENDOR_CODE',
|
||||
WM_SALES_NOTICE_CODE: 'WM_SALES_NOTICE_CODE',
|
||||
WM_RETURN_SALES_CODE: 'WM_RETURN_SALES_CODE',
|
||||
WM_RETURN_ISSUE_CODE: 'WM_RETURN_ISSUE_CODE',
|
||||
WM_PRODUCT_ISSUE_CODE: 'WM_PRODUCT_ISSUE_CODE',
|
||||
WM_PRODUCT_SALES_CODE: 'WM_PRODUCT_SALES_CODE',
|
||||
PRODUCTRECPT_CODE: 'PRODUCTRECPT_CODE',
|
||||
WM_MISC_ISSUE_CODE: 'WM_MISC_ISSUE_CODE',
|
||||
WM_MISC_RECEIPT_CODE: 'WM_MISC_RECEIPT_CODE',
|
||||
WM_OUTSOURCE_ISSUE_CODE: 'WM_OUTSOURCE_ISSUE_CODE',
|
||||
WM_OUTSOURCE_RECEIPT_CODE: 'WM_OUTSOURCE_RECEIPT_CODE',
|
||||
WM_PACKAGE_CODE: 'WM_PACKAGE_CODE',
|
||||
WM_STOCK_TAKING_CODE: 'WM_STOCK_TAKING_CODE',
|
||||
WM_STOCK_TAKING_PLAN_CODE: 'WM_STOCK_TAKING_PLAN_CODE',
|
||||
WM_WAREHOUSE_CODE: 'WM_WAREHOUSE_CODE',
|
||||
} as const;
|
||||
|
||||
|
|
@ -165,6 +176,38 @@ export const MesWmPackageStatusEnum = {
|
|||
FINISHED: MesOrderStatusConstants.FINISHED,
|
||||
} as const;
|
||||
|
||||
/** MES 盘点类型枚举 */
|
||||
export const MesWmStockTakingTypeEnum = {
|
||||
STATIC: 1,
|
||||
DYNAMIC: 2,
|
||||
} as const;
|
||||
|
||||
/** MES 盘点任务状态枚举 */
|
||||
export const MesWmStockTakingTaskStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
APPROVING: MesOrderStatusConstants.APPROVING,
|
||||
FINISHED: MesOrderStatusConstants.FINISHED,
|
||||
CANCELED: MesOrderStatusConstants.CANCELLED,
|
||||
} as const;
|
||||
|
||||
/** MES 盘点任务行状态枚举 */
|
||||
export const MesWmStockTakingTaskLineStatusEnum = {
|
||||
UNCOUNTED: 0,
|
||||
NORMAL: 1,
|
||||
GAIN: 2,
|
||||
LOSS: 3,
|
||||
} as const;
|
||||
|
||||
/** MES 盘点方案参数类型枚举 */
|
||||
export const MesWmStockTakingParamTypeEnum = {
|
||||
WAREHOUSE: 102,
|
||||
LOCATION: 103,
|
||||
AREA: 104,
|
||||
BATCH: 107,
|
||||
ITEM: 600,
|
||||
QUALITY_STATUS: 900,
|
||||
} as const;
|
||||
|
||||
/** MES 生产工单状态枚举 */
|
||||
export const MesProWorkOrderStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
|
|
@ -263,6 +306,87 @@ export const MesWmOutsourceReceiptStatusEnum = {
|
|||
CANCELED: MesOrderStatusConstants.CANCELLED,
|
||||
} as const;
|
||||
|
||||
/** MES 到货通知单状态枚举 */
|
||||
export const MesWmArrivalNoticeStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
PENDING_QC: MesOrderStatusConstants.APPROVING,
|
||||
PENDING_RECEIPT: MesOrderStatusConstants.APPROVED,
|
||||
FINISHED: MesOrderStatusConstants.FINISHED,
|
||||
} as const;
|
||||
|
||||
/** MES 采购入库单状态枚举 */
|
||||
export const MesWmItemReceiptStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
APPROVING: MesOrderStatusConstants.APPROVING,
|
||||
APPROVED: MesOrderStatusConstants.APPROVED,
|
||||
FINISHED: MesOrderStatusConstants.FINISHED,
|
||||
CANCELED: MesOrderStatusConstants.CANCELLED,
|
||||
} as const;
|
||||
|
||||
/** MES 供应商退货单状态枚举 */
|
||||
export const MesWmReturnVendorStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
APPROVING: MesOrderStatusConstants.APPROVING,
|
||||
APPROVED: MesOrderStatusConstants.APPROVED,
|
||||
FINISHED: MesOrderStatusConstants.FINISHED,
|
||||
CANCELED: MesOrderStatusConstants.CANCELLED,
|
||||
} as const;
|
||||
|
||||
/** MES 发货通知单状态枚举 */
|
||||
export const MesWmSalesNoticeStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
APPROVED: MesOrderStatusConstants.APPROVED,
|
||||
} as const;
|
||||
|
||||
/** MES 销售退货单状态枚举 */
|
||||
export const MesWmReturnSalesStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
CONFIRMED: MesOrderStatusConstants.CONFIRMED,
|
||||
APPROVING: MesOrderStatusConstants.APPROVING,
|
||||
APPROVED: MesOrderStatusConstants.APPROVED,
|
||||
FINISHED: MesOrderStatusConstants.FINISHED,
|
||||
CANCELED: MesOrderStatusConstants.CANCELLED,
|
||||
} as const;
|
||||
|
||||
/** MES 生产退料单状态枚举 */
|
||||
export const MesWmReturnIssueStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
CONFIRMED: MesOrderStatusConstants.CONFIRMED,
|
||||
APPROVING: MesOrderStatusConstants.APPROVING,
|
||||
APPROVED: MesOrderStatusConstants.APPROVED,
|
||||
FINISHED: MesOrderStatusConstants.FINISHED,
|
||||
CANCELED: MesOrderStatusConstants.CANCELLED,
|
||||
} as const;
|
||||
|
||||
/** MES 领料出库单状态枚举 */
|
||||
export const MesWmProductIssueStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
APPROVING: MesOrderStatusConstants.APPROVING,
|
||||
APPROVED: MesOrderStatusConstants.APPROVED,
|
||||
FINISHED: MesOrderStatusConstants.FINISHED,
|
||||
CANCELED: MesOrderStatusConstants.CANCELLED,
|
||||
} as const;
|
||||
|
||||
/** MES 产品入库单状态枚举 */
|
||||
export const MesWmProductReceiptStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
APPROVING: MesOrderStatusConstants.APPROVING,
|
||||
APPROVED: MesOrderStatusConstants.APPROVED,
|
||||
FINISHED: MesOrderStatusConstants.FINISHED,
|
||||
CANCELED: MesOrderStatusConstants.CANCELLED,
|
||||
} as const;
|
||||
|
||||
/** MES 销售出库单状态枚举 */
|
||||
export const MesWmProductSalesStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
CONFIRMED: MesOrderStatusConstants.CONFIRMED,
|
||||
APPROVING: MesOrderStatusConstants.APPROVING,
|
||||
SHIPPING: 10, // 待填写运单
|
||||
APPROVED: MesOrderStatusConstants.APPROVED,
|
||||
FINISHED: MesOrderStatusConstants.FINISHED,
|
||||
CANCELED: MesOrderStatusConstants.CANCELLED,
|
||||
} as const;
|
||||
|
||||
/** MES 质检结果值类型枚举 */
|
||||
export const MesQcResultValueType = {
|
||||
FLOAT: 1,
|
||||
|
|
|
|||
|
|
@ -19,9 +19,12 @@ 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 MdWorkshopSelect from '#/views/mes/md/workstation/components/md-workshop-select.vue';
|
||||
import MdWorkstationSelect from '#/views/mes/md/workstation/components/md-workstation-select.vue';
|
||||
import { ProCardSelect } from '#/views/mes/pro/card/components';
|
||||
import ProWorkOrderSelect from '#/views/mes/pro/workorder/components/pro-work-order-select.vue';
|
||||
import TmToolSelect from '#/views/mes/tm/tool/components/tm-tool-select.vue';
|
||||
import { BarcodeBizTypeEnum } from '#/views/mes/utils/constants';
|
||||
import { WmBatchSelect } from '#/views/mes/wm/batch/components';
|
||||
import { UserSelect } from '#/views/system/user/components';
|
||||
|
||||
import WmMaterialStockSelect from './../materialstock/components/wm-material-stock-select.vue';
|
||||
import { WmPackageSelect } from './../packages/components';
|
||||
|
|
@ -51,15 +54,31 @@ async function syncBizDetail(
|
|||
}
|
||||
let bizCode: string | undefined;
|
||||
let bizName: string | undefined;
|
||||
if (bizType === BarcodeBizTypeEnum.STOCK) {
|
||||
bizCode = item.itemCode;
|
||||
bizName = item.itemName;
|
||||
} else if (bizType === BarcodeBizTypeEnum.PACKAGE) {
|
||||
bizCode = item.code;
|
||||
bizName = item.clientName || item.code;
|
||||
} else {
|
||||
bizCode = item.code || item.username;
|
||||
bizName = item.name || item.nickname;
|
||||
switch (bizType) {
|
||||
case BarcodeBizTypeEnum.BATCH: {
|
||||
bizCode = item.code;
|
||||
bizName = item.itemName || item.code;
|
||||
break;
|
||||
}
|
||||
case BarcodeBizTypeEnum.PACKAGE: {
|
||||
bizCode = item.code;
|
||||
bizName = item.clientName || item.code;
|
||||
break;
|
||||
}
|
||||
case BarcodeBizTypeEnum.PROCARD: {
|
||||
bizCode = item.code;
|
||||
bizName = item.workOrderName || item.code;
|
||||
break;
|
||||
}
|
||||
case BarcodeBizTypeEnum.STOCK: {
|
||||
bizCode = item.itemCode;
|
||||
bizName = item.itemName;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
bizCode = item.code || item.username;
|
||||
bizName = item.name || item.nickname;
|
||||
}
|
||||
}
|
||||
// 先回填业务编码、名称并清空旧条码内容
|
||||
await formApi.setValues({ bizCode, bizName, content: undefined });
|
||||
|
|
@ -328,6 +347,45 @@ export function useFormSchema(formApi?: VbenFormApi): VbenFormSchema[] {
|
|||
},
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
fieldName: 'bizId',
|
||||
label: '批次',
|
||||
component: markRaw(WmBatchSelect),
|
||||
componentProps: {
|
||||
onChange: (item: any) => syncBizDetail(formApi, item),
|
||||
},
|
||||
dependencies: {
|
||||
triggerFields: ['bizType'],
|
||||
show: (values) => values.bizType === BarcodeBizTypeEnum.BATCH,
|
||||
},
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
fieldName: 'bizId',
|
||||
label: '流转卡',
|
||||
component: markRaw(ProCardSelect),
|
||||
componentProps: {
|
||||
onChange: (item: any) => syncBizDetail(formApi, item),
|
||||
},
|
||||
dependencies: {
|
||||
triggerFields: ['bizType'],
|
||||
show: (values) => values.bizType === BarcodeBizTypeEnum.PROCARD,
|
||||
},
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
fieldName: 'bizId',
|
||||
label: '人员',
|
||||
component: markRaw(UserSelect),
|
||||
componentProps: {
|
||||
onChange: (item: any) => syncBizDetail(formApi, item),
|
||||
},
|
||||
dependencies: {
|
||||
triggerFields: ['bizType'],
|
||||
show: (values) => values.bizType === BarcodeBizTypeEnum.USER,
|
||||
},
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
fieldName: 'bizId',
|
||||
label: '业务编号',
|
||||
|
|
@ -343,13 +401,16 @@ export function useFormSchema(formApi?: VbenFormApi): VbenFormSchema[] {
|
|||
values.bizType !== undefined &&
|
||||
![
|
||||
BarcodeBizTypeEnum.AREA,
|
||||
BarcodeBizTypeEnum.BATCH,
|
||||
BarcodeBizTypeEnum.CLIENT,
|
||||
BarcodeBizTypeEnum.ITEM,
|
||||
BarcodeBizTypeEnum.LOCATION,
|
||||
BarcodeBizTypeEnum.MACHINERY,
|
||||
BarcodeBizTypeEnum.PACKAGE,
|
||||
BarcodeBizTypeEnum.PROCARD,
|
||||
BarcodeBizTypeEnum.STOCK,
|
||||
BarcodeBizTypeEnum.TOOL,
|
||||
BarcodeBizTypeEnum.USER,
|
||||
BarcodeBizTypeEnum.VENDOR,
|
||||
BarcodeBizTypeEnum.WAREHOUSE,
|
||||
BarcodeBizTypeEnum.WORKORDER,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
export { default as WmBatchSelectDialog } from './wm-batch-select-dialog.vue';
|
||||
export { default as WmBatchSelect } from './wm-batch-select.vue';
|
||||
|
|
@ -0,0 +1,248 @@
|
|||
<script lang="ts" setup>
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { MesWmBatchApi } from '#/api/mes/wm/batch';
|
||||
|
||||
import { computed, nextTick, ref } from 'vue';
|
||||
|
||||
import { Alert, Button, message, Modal } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { getBatchPage } from '#/api/mes/wm/batch';
|
||||
|
||||
import { useBatchSelectGridColumns, useBatchSelectGridFormSchema } from '../data';
|
||||
|
||||
const emit = defineEmits<{
|
||||
selected: [rows: MesWmBatchApi.Batch[]];
|
||||
}>();
|
||||
|
||||
const open = ref(false); // 弹窗是否打开
|
||||
const multiple = ref(false); // 是否多选;默认按单选选择器使用
|
||||
const selectedRows = ref<MesWmBatchApi.Batch[]>([]); // 已选批次列表
|
||||
const preSelectedIds = ref<number[]>([]); // 预选批次编号列表
|
||||
const externalItemId = ref<number>(); // 外部传入的默认物料过滤
|
||||
const externalClientId = ref<number>(); // 外部传入的默认客户过滤
|
||||
const externalVendorId = ref<number>(); // 外部传入的默认供应商过滤
|
||||
const externalSalesOrderCode = ref<string>(); // 外部传入的默认销售订单过滤
|
||||
|
||||
const filterTip = computed(() => {
|
||||
const parts: string[] = [];
|
||||
if (externalClientId.value != null) {
|
||||
parts.push('客户');
|
||||
}
|
||||
if (externalVendorId.value != null) {
|
||||
parts.push('供应商');
|
||||
}
|
||||
if (externalSalesOrderCode.value != null) {
|
||||
parts.push('销售订单');
|
||||
}
|
||||
return parts.length > 0 ? `已按${parts.join('/')}预过滤` : '';
|
||||
});
|
||||
|
||||
/** 获取多选记录,包含 VXE reserve 跨页记录 */
|
||||
function getMultipleSelectedRows() {
|
||||
const selectedMap = new Map<number, MesWmBatchApi.Batch>();
|
||||
const records = [
|
||||
...(gridApi.grid.getCheckboxReserveRecords?.() ?? []),
|
||||
...(gridApi.grid.getCheckboxRecords?.() ?? []),
|
||||
] as MesWmBatchApi.Batch[];
|
||||
records.forEach((row) => {
|
||||
const rowId = row.id;
|
||||
if (rowId !== undefined) {
|
||||
selectedMap.set(rowId, row);
|
||||
}
|
||||
});
|
||||
return [...selectedMap.values()];
|
||||
}
|
||||
|
||||
/** 处理多选勾选变化 */
|
||||
function handleCheckboxSelectChange() {
|
||||
selectedRows.value = getMultipleSelectedRows();
|
||||
}
|
||||
|
||||
/** 处理单选切换 */
|
||||
function handleRadioChange(row: MesWmBatchApi.Batch) {
|
||||
selectedRows.value = [row];
|
||||
}
|
||||
|
||||
/** 多选模式下切换行勾选 */
|
||||
async function toggleMultipleRow(row: MesWmBatchApi.Batch) {
|
||||
const selected = gridApi.grid.isCheckedByCheckboxRow(row);
|
||||
await gridApi.grid.setCheckboxRow(row, !selected);
|
||||
selectedRows.value = getMultipleSelectedRows();
|
||||
}
|
||||
|
||||
/** 处理行双击:单选直接确认,多选切换勾选 */
|
||||
async function handleCellDblclick({ row }: { row: MesWmBatchApi.Batch }) {
|
||||
if (multiple.value) {
|
||||
await toggleMultipleRow(row);
|
||||
return;
|
||||
}
|
||||
selectedRows.value = [row];
|
||||
await gridApi.grid.setRadioRow(row);
|
||||
handleConfirm();
|
||||
}
|
||||
|
||||
/** 回显预选批次 */
|
||||
async function applyPreSelection() {
|
||||
if (preSelectedIds.value.length === 0) {
|
||||
return;
|
||||
}
|
||||
const rows = gridApi.grid.getData() as MesWmBatchApi.Batch[];
|
||||
for (const row of rows) {
|
||||
if (row.id === undefined || !preSelectedIds.value.includes(row.id)) {
|
||||
continue;
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
formOptions: {
|
||||
schema: useBatchSelectGridFormSchema(),
|
||||
},
|
||||
gridOptions: {
|
||||
columns: useBatchSelectGridColumns(false),
|
||||
height: 520,
|
||||
keepSource: true,
|
||||
checkboxConfig: {
|
||||
highlight: true,
|
||||
range: true,
|
||||
reserve: true,
|
||||
},
|
||||
radioConfig: {
|
||||
highlight: true,
|
||||
trigger: 'row',
|
||||
},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }, formValues) => {
|
||||
return await getBatchPage({
|
||||
pageNo: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
...formValues,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
rowConfig: {
|
||||
keyField: 'id',
|
||||
isHover: true,
|
||||
},
|
||||
toolbarConfig: {
|
||||
refresh: true,
|
||||
search: true,
|
||||
},
|
||||
} as VxeTableGridOptions<MesWmBatchApi.Batch>,
|
||||
gridEvents: {
|
||||
cellDblclick: handleCellDblclick,
|
||||
checkboxAll: handleCheckboxSelectChange,
|
||||
checkboxChange: handleCheckboxSelectChange,
|
||||
radioChange: ({ row }: { row: MesWmBatchApi.Batch }) => {
|
||||
handleRadioChange(row);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/** 重置查询和选择状态,保留外部传入的默认过滤 */
|
||||
async function resetQueryState() {
|
||||
selectedRows.value = [];
|
||||
await gridApi.grid.clearCheckboxRow();
|
||||
await gridApi.grid.clearCheckboxReserve();
|
||||
await gridApi.grid.clearRadioRow();
|
||||
await gridApi.formApi.resetForm();
|
||||
if (externalItemId.value) {
|
||||
await gridApi.formApi.setFieldValue('itemId', externalItemId.value);
|
||||
}
|
||||
if (externalClientId.value) {
|
||||
await gridApi.formApi.setFieldValue('clientId', externalClientId.value);
|
||||
}
|
||||
if (externalVendorId.value) {
|
||||
await gridApi.formApi.setFieldValue('vendorId', externalVendorId.value);
|
||||
}
|
||||
if (externalSalesOrderCode.value) {
|
||||
await gridApi.formApi.setFieldValue(
|
||||
'salesOrderCode',
|
||||
externalSalesOrderCode.value,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/** 打开批次选择弹窗 */
|
||||
async function openModal(
|
||||
selectedIds?: number[],
|
||||
options?: {
|
||||
clientId?: number;
|
||||
itemId?: number;
|
||||
multiple?: boolean;
|
||||
salesOrderCode?: string;
|
||||
vendorId?: number;
|
||||
},
|
||||
) {
|
||||
open.value = true;
|
||||
multiple.value = options?.multiple ?? false;
|
||||
preSelectedIds.value = selectedIds || [];
|
||||
externalItemId.value = options?.itemId;
|
||||
externalClientId.value = options?.clientId;
|
||||
externalVendorId.value = options?.vendorId;
|
||||
externalSalesOrderCode.value = options?.salesOrderCode;
|
||||
await nextTick();
|
||||
gridApi.setGridOptions({
|
||||
columns: useBatchSelectGridColumns(multiple.value),
|
||||
});
|
||||
await resetQueryState();
|
||||
await gridApi.query();
|
||||
await nextTick();
|
||||
await applyPreSelection();
|
||||
}
|
||||
|
||||
/** 关闭批次选择弹窗 */
|
||||
function closeModal() {
|
||||
open.value = false;
|
||||
}
|
||||
|
||||
/** 确认选择批次 */
|
||||
function handleConfirm() {
|
||||
const rows = multiple.value ? getMultipleSelectedRows() : selectedRows.value;
|
||||
if (rows.length === 0) {
|
||||
message.warning(multiple.value ? '请至少选择一条数据' : '请选择一条数据');
|
||||
return;
|
||||
}
|
||||
emit('selected', multiple.value ? rows : [rows[0]!]);
|
||||
open.value = false;
|
||||
}
|
||||
|
||||
defineExpose({ open: openModal });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal
|
||||
v-model:open="open"
|
||||
title="批次选择"
|
||||
width="80%"
|
||||
:destroy-on-close="true"
|
||||
@ok="handleConfirm"
|
||||
@cancel="closeModal"
|
||||
>
|
||||
<Alert
|
||||
v-if="filterTip"
|
||||
:message="filterTip"
|
||||
type="info"
|
||||
show-icon
|
||||
class="!mb-3"
|
||||
/>
|
||||
<Grid table-title="批次列表" />
|
||||
<template #footer>
|
||||
<Button @click="closeModal">取消</Button>
|
||||
<Button type="primary" @click="handleConfirm">确定</Button>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
<script lang="ts" setup>
|
||||
import type { MesWmBatchApi } from '#/api/mes/wm/batch';
|
||||
|
||||
import { computed, ref, useAttrs, watch } from 'vue';
|
||||
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
|
||||
import { Input, Tooltip } from 'ant-design-vue';
|
||||
|
||||
import { getBatch } from '#/api/mes/wm/batch';
|
||||
|
||||
import WmBatchSelectDialog from './wm-batch-select-dialog.vue';
|
||||
|
||||
defineOptions({ name: 'WmBatchSelect', inheritAttrs: false });
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
allowClear?: boolean;
|
||||
clientId?: number; // 默认过滤的客户 ID
|
||||
disabled?: boolean;
|
||||
itemId?: number; // 默认过滤的物料 ID
|
||||
modelValue?: number;
|
||||
placeholder?: string;
|
||||
salesOrderCode?: string; // 默认过滤的销售订单编号
|
||||
vendorId?: number; // 默认过滤的供应商 ID
|
||||
}>(),
|
||||
{
|
||||
allowClear: true,
|
||||
clientId: undefined,
|
||||
disabled: false,
|
||||
itemId: undefined,
|
||||
modelValue: undefined,
|
||||
placeholder: '请选择批次',
|
||||
salesOrderCode: undefined,
|
||||
vendorId: undefined,
|
||||
},
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
change: [item: MesWmBatchApi.Batch | undefined];
|
||||
'update:modelValue': [value: number | undefined];
|
||||
}>();
|
||||
|
||||
const attrs = useAttrs();
|
||||
const dialogRef = ref<InstanceType<typeof WmBatchSelectDialog>>();
|
||||
const hovering = ref(false);
|
||||
const selectedItem = ref<MesWmBatchApi.Batch>();
|
||||
|
||||
const displayLabel = computed(() => selectedItem.value?.code ?? '');
|
||||
|
||||
const showClear = computed(
|
||||
() =>
|
||||
props.allowClear &&
|
||||
!props.disabled &&
|
||||
hovering.value &&
|
||||
props.modelValue != null,
|
||||
);
|
||||
|
||||
/** 根据编号单条查询批次信息(用于编辑回显) */
|
||||
async function resolveItemById(id: number | undefined) {
|
||||
if (id == null) {
|
||||
selectedItem.value = undefined;
|
||||
return;
|
||||
}
|
||||
if (selectedItem.value?.id === id) {
|
||||
return;
|
||||
}
|
||||
selectedItem.value = await getBatch(id);
|
||||
}
|
||||
|
||||
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, {
|
||||
clientId: props.clientId,
|
||||
itemId: props.itemId,
|
||||
multiple: false,
|
||||
salesOrderCode: props.salesOrderCode,
|
||||
vendorId: props.vendorId,
|
||||
});
|
||||
}
|
||||
|
||||
/** 弹窗选中回调 */
|
||||
function handleSelected(rows: MesWmBatchApi.Batch[]) {
|
||||
const item = rows[0];
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
selectedItem.value = item;
|
||||
emit('update:modelValue', item.id);
|
||||
emit('change', item);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-bind="attrs"
|
||||
class="w-full"
|
||||
:class="disabled ? 'cursor-not-allowed' : 'cursor-pointer'"
|
||||
@click="handleClick"
|
||||
@mouseenter="hovering = true"
|
||||
@mouseleave="hovering = false"
|
||||
>
|
||||
<Tooltip :mouse-enter-delay="0.5" :open="selectedItem ? undefined : false">
|
||||
<template #title>
|
||||
<div v-if="selectedItem" class="leading-6">
|
||||
<div>批次编号:{{ selectedItem.code || '-' }}</div>
|
||||
<div>物料编码:{{ selectedItem.itemCode || '-' }}</div>
|
||||
<div>物料名称:{{ selectedItem.itemName || '-' }}</div>
|
||||
<div>生产批号:{{ selectedItem.lotNumber || '-' }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<Input
|
||||
:disabled="disabled"
|
||||
:placeholder="placeholder"
|
||||
:value="displayLabel"
|
||||
readonly
|
||||
>
|
||||
<template #suffix>
|
||||
<IconifyIcon
|
||||
class="size-4"
|
||||
:icon="showClear ? 'lucide:circle-x' : 'lucide:search'"
|
||||
/>
|
||||
</template>
|
||||
</Input>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<WmBatchSelectDialog ref="dialogRef" @selected="handleSelected" />
|
||||
</template>
|
||||
|
|
@ -0,0 +1,234 @@
|
|||
import type { VbenFormSchema } from '#/adapter/form';
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { MesWmBatchApi } from '#/api/mes/wm/batch';
|
||||
|
||||
import { markRaw } from 'vue';
|
||||
|
||||
import { DICT_TYPE } from '@vben/constants';
|
||||
import { getDictOptions } from '@vben/hooks';
|
||||
|
||||
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 MdVendorSelect from '#/views/mes/md/vendor/components/md-vendor-select.vue';
|
||||
import { MdWorkstationSelect } from '#/views/mes/md/workstation/components';
|
||||
import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components';
|
||||
import { TmToolSelect } from '#/views/mes/tm/tool/components';
|
||||
|
||||
/** 批次选择弹窗的搜索表单 */
|
||||
export function useBatchSelectGridFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
fieldName: 'code',
|
||||
label: '批次编号',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
placeholder: '请输入批次编号',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'itemId',
|
||||
label: '产品物料',
|
||||
component: markRaw(MdItemSelect),
|
||||
componentProps: {
|
||||
placeholder: '请选择产品物料',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'vendorId',
|
||||
label: '供应商',
|
||||
component: markRaw(MdVendorSelect),
|
||||
componentProps: {
|
||||
placeholder: '请选择供应商',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'clientId',
|
||||
label: '客户',
|
||||
component: markRaw(MdClientSelect),
|
||||
componentProps: {
|
||||
placeholder: '请选择客户',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'workOrderId',
|
||||
label: '生产工单',
|
||||
component: markRaw(ProWorkOrderSelect),
|
||||
componentProps: {
|
||||
placeholder: '请选择生产工单',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'workstationId',
|
||||
label: '工作站',
|
||||
component: markRaw(MdWorkstationSelect),
|
||||
componentProps: {
|
||||
placeholder: '请选择工作站',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'toolId',
|
||||
label: '工具',
|
||||
component: markRaw(TmToolSelect),
|
||||
componentProps: {
|
||||
placeholder: '请选择工具',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'salesOrderCode',
|
||||
label: '销售订单编号',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
placeholder: '请输入销售订单编号',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'purchaseOrderCode',
|
||||
label: '采购订单编号',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
placeholder: '请输入采购订单编号',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'lotNumber',
|
||||
label: '生产批号',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
placeholder: '请输入生产批号',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'qualityStatus',
|
||||
label: '质量状态',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
options: getDictOptions(DICT_TYPE.MES_WM_QUALITY_STATUS, 'number'),
|
||||
placeholder: '请选择质量状态',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 批次选择弹窗的字段 */
|
||||
export function useBatchSelectGridColumns(
|
||||
multiple = false,
|
||||
): VxeTableGridOptions<MesWmBatchApi.Batch>['columns'] {
|
||||
return [
|
||||
{
|
||||
type: multiple ? 'checkbox' : 'radio',
|
||||
width: 50,
|
||||
},
|
||||
{
|
||||
field: 'code',
|
||||
title: '批次编号',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
field: 'itemCode',
|
||||
title: '物料编码',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
field: 'itemName',
|
||||
title: '物料名称',
|
||||
minWidth: 140,
|
||||
},
|
||||
{
|
||||
field: 'itemSpecification',
|
||||
title: '规格型号',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: 'unitName',
|
||||
title: '单位',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
field: 'vendorCode',
|
||||
title: '供应商编码',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: 'vendorName',
|
||||
title: '供应商名称',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: 'clientCode',
|
||||
title: '客户编码',
|
||||
width: 110,
|
||||
},
|
||||
{
|
||||
field: 'clientName',
|
||||
title: '客户名称',
|
||||
width: 110,
|
||||
},
|
||||
{
|
||||
field: 'salesOrderCode',
|
||||
title: '销售订单编号',
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
field: 'purchaseOrderCode',
|
||||
title: '采购订单编号',
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
field: 'workOrderCode',
|
||||
title: '工单编码',
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
field: 'workstationCode',
|
||||
title: '工作站编码',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: 'taskCode',
|
||||
title: '生产任务编号',
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
field: 'toolCode',
|
||||
title: '工具编号',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: 'lotNumber',
|
||||
title: '生产批号',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: 'qualityStatus',
|
||||
title: '质量状态',
|
||||
width: 100,
|
||||
cellRender: {
|
||||
name: 'CellDict',
|
||||
props: { type: DICT_TYPE.MES_WM_QUALITY_STATUS },
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'produceDate',
|
||||
title: '生产日期',
|
||||
width: 120,
|
||||
formatter: 'formatDate',
|
||||
},
|
||||
{
|
||||
field: 'expireDate',
|
||||
title: '有效期',
|
||||
width: 120,
|
||||
formatter: 'formatDate',
|
||||
},
|
||||
{
|
||||
field: 'receiptDate',
|
||||
title: '入库日期',
|
||||
width: 120,
|
||||
formatter: 'formatDate',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,488 @@
|
|||
import type { VbenFormApi, VbenFormSchema } from '#/adapter/form';
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { MesProWorkOrderApi } from '#/api/mes/pro/workorder';
|
||||
import type { MesWmMaterialStockApi } from '#/api/mes/wm/materialstock';
|
||||
import type { MesWmOutsourceIssueApi } from '#/api/mes/wm/outsourceissue';
|
||||
import type { MesWmOutsourceIssueDetailApi } from '#/api/mes/wm/outsourceissue/detail';
|
||||
import type { MesWmOutsourceIssueLineApi } from '#/api/mes/wm/outsourceissue/line';
|
||||
|
||||
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 { getRangePickerDefaultProps } from '#/utils';
|
||||
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 ProWorkOrderSelect from '#/views/mes/pro/workorder/components/pro-work-order-select.vue';
|
||||
import {
|
||||
MesAutoCodeRuleCode,
|
||||
MesProWorkOrderStatusEnum,
|
||||
MesProWorkOrderTypeEnum,
|
||||
} from '#/views/mes/utils/constants';
|
||||
import { WmMaterialStockSelect } from '#/views/mes/wm/materialstock/components';
|
||||
import {
|
||||
WmWarehouseAreaSelect,
|
||||
WmWarehouseLocationSelect,
|
||||
WmWarehouseSelect,
|
||||
} from '#/views/mes/wm/warehouse/components';
|
||||
|
||||
/** 表单类型 */
|
||||
export type FormType = 'create' | 'detail' | 'finish' | 'stock' | 'update';
|
||||
|
||||
/** 表单头部是否只读(拣货、详情、领出态) */
|
||||
function isHeaderReadonly(formType: FormType): boolean {
|
||||
return (
|
||||
formType === 'detail' || formType === 'finish' || formType === 'stock'
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增/修改的表单 */
|
||||
export function useFormSchema(
|
||||
formType: FormType,
|
||||
formApi?: VbenFormApi,
|
||||
): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
fieldName: 'id',
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
triggerFields: [''],
|
||||
show: () => false,
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'status',
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
triggerFields: [''],
|
||||
show: () => false,
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'code',
|
||||
label: '发料单编号',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入发料单编号',
|
||||
},
|
||||
rules: 'required',
|
||||
suffix: isHeaderReadonly(formType)
|
||||
? undefined
|
||||
: () =>
|
||||
h(
|
||||
Button,
|
||||
{
|
||||
type: 'default',
|
||||
onClick: async () => {
|
||||
const code = await generateAutoCode(
|
||||
MesAutoCodeRuleCode.WM_OUTSOURCE_ISSUE_CODE,
|
||||
);
|
||||
await formApi?.setFieldValue('code', code);
|
||||
},
|
||||
},
|
||||
{ default: () => '生成' },
|
||||
),
|
||||
},
|
||||
{
|
||||
fieldName: 'name',
|
||||
label: '发料单名称',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入发料单名称',
|
||||
},
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
fieldName: 'issueDate',
|
||||
label: '发料日期',
|
||||
component: 'DatePicker',
|
||||
componentProps: {
|
||||
format: 'YYYY-MM-DD',
|
||||
placeholder: '请选择发料日期',
|
||||
valueFormat: 'x',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'workOrderId',
|
||||
label: '外协工单',
|
||||
component: markRaw(ProWorkOrderSelect),
|
||||
componentProps: {
|
||||
// 选择外协工单后,自动回填供应商
|
||||
onChange: async (workOrder?: MesProWorkOrderApi.WorkOrder) => {
|
||||
await formApi?.setFieldValue('vendorId', workOrder?.vendorId);
|
||||
},
|
||||
status: MesProWorkOrderStatusEnum.CONFIRMED,
|
||||
type: MesProWorkOrderTypeEnum.OUTSOURCE,
|
||||
},
|
||||
rules: 'selectRequired',
|
||||
},
|
||||
{
|
||||
fieldName: 'vendorId',
|
||||
label: '供应商',
|
||||
component: markRaw(MdVendorSelect),
|
||||
componentProps: {
|
||||
placeholder: '请选择供应商',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'remark',
|
||||
label: '备注',
|
||||
component: 'Textarea',
|
||||
formItemClass: 'col-span-3',
|
||||
componentProps: {
|
||||
placeholder: '请输入备注',
|
||||
rows: 3,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 列表的搜索表单 */
|
||||
export function useGridFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
fieldName: 'code',
|
||||
label: '发料单编号',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
placeholder: '请输入发料单编号',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'name',
|
||||
label: '发料单名称',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
placeholder: '请输入发料单名称',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'vendorId',
|
||||
label: '供应商',
|
||||
component: markRaw(MdVendorSelect),
|
||||
componentProps: {
|
||||
placeholder: '请选择供应商',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'issueDate',
|
||||
label: '发料日期',
|
||||
component: 'RangePicker',
|
||||
componentProps: {
|
||||
...getRangePickerDefaultProps(),
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 列表的字段 */
|
||||
export function useGridColumns(): VxeTableGridOptions<MesWmOutsourceIssueApi.OutsourceIssue>['columns'] {
|
||||
return [
|
||||
{
|
||||
field: 'code',
|
||||
title: '发料单编号',
|
||||
minWidth: 160,
|
||||
slots: { default: 'code' },
|
||||
},
|
||||
{
|
||||
field: 'name',
|
||||
title: '发料单名称',
|
||||
minWidth: 150,
|
||||
},
|
||||
{
|
||||
field: 'workOrderCode',
|
||||
title: '生产工单号',
|
||||
minWidth: 140,
|
||||
},
|
||||
{
|
||||
field: 'vendorName',
|
||||
title: '供应商名称',
|
||||
minWidth: 120,
|
||||
},
|
||||
{
|
||||
field: 'issueDate',
|
||||
title: '发料日期',
|
||||
width: 180,
|
||||
formatter: 'formatDate',
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
title: '单据状态',
|
||||
minWidth: 100,
|
||||
cellRender: {
|
||||
name: 'CellDict',
|
||||
props: { type: DICT_TYPE.MES_WM_OUTSOURCE_ISSUE_STATUS },
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
width: 240,
|
||||
fixed: 'right',
|
||||
slots: { default: 'actions' },
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 发料单行子表的字段 */
|
||||
export function useLineGridColumns(
|
||||
editable: boolean,
|
||||
stockable: boolean,
|
||||
): VxeTableGridOptions<MesWmOutsourceIssueLineApi.OutsourceIssueLine>['columns'] {
|
||||
return [
|
||||
{
|
||||
type: 'expand',
|
||||
width: 48,
|
||||
slots: { content: 'detail' },
|
||||
},
|
||||
{
|
||||
field: 'itemCode',
|
||||
title: '物料编码',
|
||||
minWidth: 120,
|
||||
},
|
||||
{
|
||||
field: 'itemName',
|
||||
title: '物料名称',
|
||||
minWidth: 140,
|
||||
},
|
||||
{
|
||||
field: 'specification',
|
||||
title: '规格型号',
|
||||
minWidth: 120,
|
||||
},
|
||||
{
|
||||
field: 'unitMeasureName',
|
||||
title: '单位',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
field: 'quantity',
|
||||
title: '领料数量',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
field: 'batchCode',
|
||||
title: '批次号',
|
||||
minWidth: 120,
|
||||
},
|
||||
{
|
||||
field: 'remark',
|
||||
title: '备注',
|
||||
minWidth: 150,
|
||||
},
|
||||
...(editable || stockable
|
||||
? [
|
||||
{
|
||||
title: '操作',
|
||||
width: 160,
|
||||
fixed: 'right',
|
||||
slots: { default: 'actions' },
|
||||
} as const,
|
||||
]
|
||||
: []),
|
||||
];
|
||||
}
|
||||
|
||||
/** 发料单行新增/修改的表单 */
|
||||
export function useLineFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
fieldName: 'itemId',
|
||||
label: '物料',
|
||||
component: markRaw(MdItemSelect),
|
||||
componentProps: {
|
||||
placeholder: '请选择物料',
|
||||
},
|
||||
rules: 'selectRequired',
|
||||
},
|
||||
{
|
||||
fieldName: 'quantity',
|
||||
label: '发料数量',
|
||||
component: 'InputNumber',
|
||||
componentProps: {
|
||||
class: '!w-full',
|
||||
min: 0,
|
||||
placeholder: '请输入发料数量',
|
||||
precision: 2,
|
||||
},
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
fieldName: 'batchCode',
|
||||
label: '批次号',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入批次号',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'remark',
|
||||
label: '备注',
|
||||
component: 'Textarea',
|
||||
formItemClass: 'col-span-3',
|
||||
componentProps: {
|
||||
placeholder: '请输入备注',
|
||||
rows: 3,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 发料明细子表的字段 */
|
||||
export function useDetailGridColumns(
|
||||
stockable: boolean,
|
||||
): VxeTableGridOptions<MesWmOutsourceIssueDetailApi.OutsourceIssueDetail>['columns'] {
|
||||
return [
|
||||
{
|
||||
field: 'warehouseName',
|
||||
title: '仓库名称',
|
||||
minWidth: 100,
|
||||
},
|
||||
{
|
||||
field: 'locationName',
|
||||
title: '库区名称',
|
||||
minWidth: 100,
|
||||
},
|
||||
{
|
||||
field: 'areaName',
|
||||
title: '库位名称',
|
||||
minWidth: 100,
|
||||
},
|
||||
{
|
||||
field: 'quantity',
|
||||
title: '数量',
|
||||
width: 100,
|
||||
},
|
||||
...(stockable
|
||||
? [
|
||||
{
|
||||
title: '操作',
|
||||
width: 120,
|
||||
fixed: 'right',
|
||||
slots: { default: 'actions' },
|
||||
} as const,
|
||||
]
|
||||
: []),
|
||||
];
|
||||
}
|
||||
|
||||
/** 发料明细新增/修改的表单 */
|
||||
export function useDetailFormSchema(formApi?: VbenFormApi): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
fieldName: 'quantityMax',
|
||||
component: 'Input',
|
||||
dependencies: {
|
||||
triggerFields: [''],
|
||||
show: () => false,
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'materialStockId',
|
||||
label: '库存记录',
|
||||
component: markRaw(WmMaterialStockSelect),
|
||||
componentProps: {
|
||||
// 选择库存记录后,自动回填仓库/库区/库位/批次/数量
|
||||
onChange: async (stock?: MesWmMaterialStockApi.MaterialStock) => {
|
||||
await formApi?.setValues({
|
||||
areaId: stock?.areaId,
|
||||
batchCode: stock?.batchCode,
|
||||
batchId: stock?.batchId,
|
||||
locationId: stock?.locationId,
|
||||
quantity: stock?.quantity,
|
||||
quantityMax: stock?.quantity,
|
||||
warehouseId: stock?.warehouseId,
|
||||
});
|
||||
},
|
||||
},
|
||||
rules: 'selectRequired',
|
||||
dependencies: {
|
||||
triggerFields: ['itemId'],
|
||||
componentProps: (values) => ({
|
||||
itemId: values.itemId,
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'itemId',
|
||||
label: '物料',
|
||||
component: markRaw(MdItemSelect),
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'quantity',
|
||||
label: '数量',
|
||||
component: 'InputNumber',
|
||||
componentProps: {
|
||||
class: '!w-full',
|
||||
min: 0,
|
||||
placeholder: '请输入数量',
|
||||
precision: 2,
|
||||
},
|
||||
rules: 'required',
|
||||
dependencies: {
|
||||
triggerFields: ['quantityMax'],
|
||||
componentProps: (values) => ({
|
||||
class: '!w-full',
|
||||
max: values.quantityMax,
|
||||
min: 0,
|
||||
placeholder: '请输入数量',
|
||||
precision: 2,
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'warehouseId',
|
||||
label: '发料仓库',
|
||||
component: markRaw(WmWarehouseSelect),
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'locationId',
|
||||
label: '库区',
|
||||
component: markRaw(WmWarehouseLocationSelect),
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
dependencies: {
|
||||
triggerFields: ['warehouseId'],
|
||||
componentProps: (values) => ({
|
||||
disabled: true,
|
||||
warehouseId: values.warehouseId,
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'areaId',
|
||||
label: '库位',
|
||||
component: markRaw(WmWarehouseAreaSelect),
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
dependencies: {
|
||||
triggerFields: ['locationId'],
|
||||
componentProps: (values) => ({
|
||||
disabled: true,
|
||||
locationId: values.locationId,
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'batchCode',
|
||||
label: '批次号',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
@ -1 +1,2 @@
|
|||
export { default as DeptSelectModal } from './select-modal.vue';
|
||||
export { default as DeptTreeSelect } from './tree-select.vue';
|
||||
|
|
|
|||
|
|
@ -10,10 +10,16 @@ import { Input, Spin, Tree } from 'ant-design-vue';
|
|||
|
||||
import { getSimpleDeptList } from '#/api/system/dept';
|
||||
|
||||
const emit = defineEmits(['select']);
|
||||
defineOptions({ name: 'DeptTreeSelect' });
|
||||
|
||||
const emit = defineEmits<{
|
||||
select: [dept?: SystemDeptApi.Dept];
|
||||
}>();
|
||||
|
||||
const deptList = ref<SystemDeptApi.Dept[]>([]); // 部门列表
|
||||
const deptTree = ref<any[]>([]); // 部门树
|
||||
const expandedKeys = ref<number[]>([]); // 展开的节点
|
||||
const selectedKeys = ref<number[]>([]); // 选中的节点
|
||||
const loading = ref(false); // 加载状态
|
||||
const searchValue = ref(''); // 搜索值
|
||||
|
||||
|
|
@ -31,11 +37,21 @@ function handleSearch(e: any) {
|
|||
expandedKeys.value = deptTree.value.map((node) => node.id!);
|
||||
}
|
||||
|
||||
/** 选中部门 */
|
||||
/** 选中部门:点击已选中的节点时取消选中 */
|
||||
function handleSelect(_selectedKeys: any[], info: any) {
|
||||
emit('select', info.node.dataRef);
|
||||
emit('select', info.selected ? info.node.dataRef : undefined);
|
||||
}
|
||||
|
||||
/** 重置选中状态(供外部重置按钮调用) */
|
||||
function reset() {
|
||||
searchValue.value = '';
|
||||
selectedKeys.value = [];
|
||||
deptTree.value = handleTree(deptList.value);
|
||||
emit('select', undefined);
|
||||
}
|
||||
|
||||
defineExpose({ reset });
|
||||
|
||||
/** 初始化 */
|
||||
onMounted(async () => {
|
||||
try {
|
||||
|
|
@ -43,8 +59,6 @@ onMounted(async () => {
|
|||
const data = await getSimpleDeptList();
|
||||
deptList.value = data;
|
||||
deptTree.value = handleTree(data);
|
||||
} catch (error) {
|
||||
console.error('获取部门数据失败', error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
|
|
@ -54,24 +68,25 @@ onMounted(async () => {
|
|||
<template>
|
||||
<div>
|
||||
<Input
|
||||
placeholder="搜索部门"
|
||||
allow-clear
|
||||
v-model:value="searchValue"
|
||||
@change="handleSearch"
|
||||
allow-clear
|
||||
class="w-full"
|
||||
placeholder="搜索部门"
|
||||
@change="handleSearch"
|
||||
>
|
||||
<template #prefix>
|
||||
<IconifyIcon icon="lucide:search" class="size-4" />
|
||||
<IconifyIcon class="size-4" icon="lucide:search" />
|
||||
</template>
|
||||
</Input>
|
||||
<Spin :spinning="loading" wrapper-class-name="w-full">
|
||||
<Tree
|
||||
@select="handleSelect"
|
||||
v-if="deptTree.length > 0"
|
||||
v-model:selected-keys="selectedKeys"
|
||||
class="pt-2"
|
||||
:tree-data="deptTree"
|
||||
:default-expand-all="true"
|
||||
:field-names="{ title: 'name', key: 'id', children: 'children' }"
|
||||
:tree-data="deptTree"
|
||||
@select="handleSelect"
|
||||
/>
|
||||
<div v-else-if="!loading" class="py-4 text-center text-gray-500">
|
||||
暂无数据
|
||||
|
|
@ -1 +1,3 @@
|
|||
export { default as UserSelectDialog } from './select-dialog.vue';
|
||||
export { default as UserSelectModal } from './select-modal.vue';
|
||||
export { default as UserSelect } from './select.vue';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,305 @@
|
|||
<script lang="ts" setup>
|
||||
import type { VbenFormSchema } from '#/adapter/form';
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { SystemDeptApi } from '#/api/system/dept';
|
||||
import type { SystemUserApi } from '#/api/system/user';
|
||||
|
||||
import { nextTick, ref } from 'vue';
|
||||
|
||||
import { CommonStatusEnum, DICT_TYPE } from '@vben/constants';
|
||||
import { getDictOptions } from '@vben/hooks';
|
||||
|
||||
import { Button, Col, message, Modal, Row } from 'ant-design-vue';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { getUserPage } from '#/api/system/user';
|
||||
import { DeptTreeSelect } from '#/views/system/dept/components';
|
||||
|
||||
const emit = defineEmits<{
|
||||
selected: [rows: SystemUserApi.User[]];
|
||||
}>();
|
||||
|
||||
const open = ref(false); // 弹窗是否打开
|
||||
const multiple = ref(false); // 是否多选;默认按单选选择器使用
|
||||
const selectedRows = ref<SystemUserApi.User[]>([]); // 已选用户列表
|
||||
const preSelectedIds = ref<number[]>([]); // 预选用户编号列表
|
||||
const deptId = ref<number>(); // 当前部门过滤
|
||||
const deptTreeRef = ref<InstanceType<typeof DeptTreeSelect>>(); // 部门树
|
||||
|
||||
/** 用户选择弹窗的搜索表单 */
|
||||
function useUserSelectGridFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
fieldName: 'username',
|
||||
label: '用户名称',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
placeholder: '请输入用户名称',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'nickname',
|
||||
label: '用户昵称',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
placeholder: '请输入用户昵称',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'mobile',
|
||||
label: '手机号码',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
placeholder: '请输入手机号码',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'status',
|
||||
label: '状态',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'),
|
||||
placeholder: '请选择状态',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 用户选择弹窗的字段 */
|
||||
function useUserSelectGridColumns(
|
||||
isMultiple = false,
|
||||
): VxeTableGridOptions<SystemUserApi.User>['columns'] {
|
||||
return [
|
||||
{
|
||||
type: isMultiple ? 'checkbox' : 'radio',
|
||||
width: 50,
|
||||
},
|
||||
{
|
||||
field: 'id',
|
||||
title: '用户编号',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: 'username',
|
||||
title: '用户名称',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
field: 'nickname',
|
||||
title: '用户昵称',
|
||||
minWidth: 150,
|
||||
},
|
||||
{
|
||||
field: 'mobile',
|
||||
title: '手机号码',
|
||||
width: 130,
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
title: '状态',
|
||||
width: 90,
|
||||
cellRender: {
|
||||
name: 'CellDict',
|
||||
props: { type: DICT_TYPE.COMMON_STATUS },
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 获取多选记录,包含 VXE reserve 跨页记录 */
|
||||
function getMultipleSelectedRows() {
|
||||
const selectedMap = new Map<number, SystemUserApi.User>();
|
||||
const records = [
|
||||
...(gridApi.grid.getCheckboxReserveRecords?.() ?? []),
|
||||
...(gridApi.grid.getCheckboxRecords?.() ?? []),
|
||||
] as SystemUserApi.User[];
|
||||
records.forEach((row) => {
|
||||
const rowId = row.id;
|
||||
if (rowId !== undefined) {
|
||||
selectedMap.set(rowId, row);
|
||||
}
|
||||
});
|
||||
return [...selectedMap.values()];
|
||||
}
|
||||
|
||||
/** 处理多选勾选变化 */
|
||||
function handleCheckboxSelectChange() {
|
||||
selectedRows.value = getMultipleSelectedRows();
|
||||
}
|
||||
|
||||
/** 处理单选切换 */
|
||||
function handleRadioChange(row: SystemUserApi.User) {
|
||||
selectedRows.value = [row];
|
||||
}
|
||||
|
||||
/** 多选模式下切换行勾选 */
|
||||
async function toggleMultipleRow(row: SystemUserApi.User) {
|
||||
const selected = gridApi.grid.isCheckedByCheckboxRow(row);
|
||||
await gridApi.grid.setCheckboxRow(row, !selected);
|
||||
selectedRows.value = getMultipleSelectedRows();
|
||||
}
|
||||
|
||||
/** 处理行双击:单选直接确认,多选切换勾选 */
|
||||
async function handleCellDblclick({ row }: { row: SystemUserApi.User }) {
|
||||
if (multiple.value) {
|
||||
await toggleMultipleRow(row);
|
||||
return;
|
||||
}
|
||||
selectedRows.value = [row];
|
||||
await gridApi.grid.setRadioRow(row);
|
||||
handleConfirm();
|
||||
}
|
||||
|
||||
/** 回显预选用户 */
|
||||
async function applyPreSelection() {
|
||||
if (preSelectedIds.value.length === 0) {
|
||||
return;
|
||||
}
|
||||
const rows = gridApi.grid.getData() as SystemUserApi.User[];
|
||||
for (const row of rows) {
|
||||
if (row.id === undefined || !preSelectedIds.value.includes(row.id)) {
|
||||
continue;
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
formOptions: {
|
||||
schema: useUserSelectGridFormSchema(),
|
||||
},
|
||||
gridOptions: {
|
||||
columns: useUserSelectGridColumns(false),
|
||||
height: 520,
|
||||
keepSource: true,
|
||||
checkboxConfig: {
|
||||
highlight: true,
|
||||
range: true,
|
||||
reserve: true,
|
||||
},
|
||||
radioConfig: {
|
||||
highlight: true,
|
||||
trigger: 'row',
|
||||
},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }, formValues) => {
|
||||
return await getUserPage({
|
||||
pageNo: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
deptId: deptId.value,
|
||||
...formValues,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
rowConfig: {
|
||||
keyField: 'id',
|
||||
isHover: true,
|
||||
},
|
||||
toolbarConfig: {
|
||||
refresh: true,
|
||||
search: true,
|
||||
},
|
||||
} as VxeTableGridOptions<SystemUserApi.User>,
|
||||
gridEvents: {
|
||||
cellDblclick: handleCellDblclick,
|
||||
checkboxAll: handleCheckboxSelectChange,
|
||||
checkboxChange: handleCheckboxSelectChange,
|
||||
radioChange: ({ row }: { row: SystemUserApi.User }) => {
|
||||
handleRadioChange(row);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/** 部门树节点点击 */
|
||||
function handleDeptNodeClick(dept?: SystemDeptApi.Dept) {
|
||||
deptId.value = dept?.id;
|
||||
gridApi.query();
|
||||
}
|
||||
|
||||
/** 重置查询和选择状态 */
|
||||
async function resetQueryState() {
|
||||
selectedRows.value = [];
|
||||
deptId.value = undefined;
|
||||
await gridApi.grid.clearCheckboxRow();
|
||||
await gridApi.grid.clearCheckboxReserve();
|
||||
await gridApi.grid.clearRadioRow();
|
||||
await gridApi.formApi.resetForm();
|
||||
deptTreeRef.value?.reset();
|
||||
}
|
||||
|
||||
/** 打开用户选择弹窗 */
|
||||
async function openModal(
|
||||
selectedIds?: number[],
|
||||
options?: { multiple?: boolean },
|
||||
) {
|
||||
open.value = true;
|
||||
multiple.value = options?.multiple ?? false;
|
||||
preSelectedIds.value = selectedIds || [];
|
||||
await nextTick();
|
||||
gridApi.setGridOptions({
|
||||
columns: useUserSelectGridColumns(multiple.value),
|
||||
});
|
||||
await resetQueryState();
|
||||
await gridApi.formApi.setFieldValue('status', CommonStatusEnum.ENABLE);
|
||||
await gridApi.query();
|
||||
await nextTick();
|
||||
await applyPreSelection();
|
||||
}
|
||||
|
||||
/** 关闭用户选择弹窗 */
|
||||
function closeModal() {
|
||||
open.value = false;
|
||||
}
|
||||
|
||||
/** 确认选择用户 */
|
||||
function handleConfirm() {
|
||||
const rows = multiple.value ? getMultipleSelectedRows() : selectedRows.value;
|
||||
if (rows.length === 0) {
|
||||
message.warning(multiple.value ? '请至少选择一条数据' : '请选择一条数据');
|
||||
return;
|
||||
}
|
||||
emit('selected', multiple.value ? rows : [rows[0]!]);
|
||||
open.value = false;
|
||||
}
|
||||
|
||||
defineExpose({ open: openModal });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal
|
||||
v-model:open="open"
|
||||
title="人员选择"
|
||||
width="80%"
|
||||
:destroy-on-close="true"
|
||||
@ok="handleConfirm"
|
||||
@cancel="closeModal"
|
||||
>
|
||||
<Row :gutter="12">
|
||||
<Col :span="5">
|
||||
<DeptTreeSelect ref="deptTreeRef" @select="handleDeptNodeClick" />
|
||||
</Col>
|
||||
<Col :span="19">
|
||||
<Grid table-title="用户列表" />
|
||||
</Col>
|
||||
</Row>
|
||||
<template #footer>
|
||||
<Button @click="closeModal">取消</Button>
|
||||
<Button type="primary" @click="handleConfirm">确定</Button>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
<script lang="ts" setup>
|
||||
import type { SystemUserApi } from '#/api/system/user';
|
||||
|
||||
import { computed, ref, useAttrs, watch } from 'vue';
|
||||
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
|
||||
import { Input, Tooltip } from 'ant-design-vue';
|
||||
|
||||
import { getUser } from '#/api/system/user';
|
||||
|
||||
import UserSelectDialog from './select-dialog.vue';
|
||||
|
||||
defineOptions({ name: 'UserSelect', inheritAttrs: false });
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
allowClear?: boolean;
|
||||
disabled?: boolean;
|
||||
modelValue?: number;
|
||||
placeholder?: string;
|
||||
}>(),
|
||||
{
|
||||
allowClear: true,
|
||||
disabled: false,
|
||||
modelValue: undefined,
|
||||
placeholder: '请选择用户',
|
||||
},
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
change: [item: SystemUserApi.User | undefined];
|
||||
'update:modelValue': [value: number | undefined];
|
||||
}>();
|
||||
|
||||
const attrs = useAttrs();
|
||||
const dialogRef = ref<InstanceType<typeof UserSelectDialog>>();
|
||||
const hovering = ref(false);
|
||||
const selectedItem = ref<SystemUserApi.User>();
|
||||
|
||||
const displayLabel = computed(
|
||||
() => selectedItem.value?.nickname ?? selectedItem.value?.username ?? '',
|
||||
);
|
||||
|
||||
const showClear = computed(
|
||||
() =>
|
||||
props.allowClear &&
|
||||
!props.disabled &&
|
||||
hovering.value &&
|
||||
props.modelValue != null,
|
||||
);
|
||||
|
||||
/** 根据编号单条查询用户信息(用于编辑回显) */
|
||||
async function resolveItemById(id: number | undefined) {
|
||||
if (id == null) {
|
||||
selectedItem.value = undefined;
|
||||
return;
|
||||
}
|
||||
if (selectedItem.value?.id === id) {
|
||||
return;
|
||||
}
|
||||
selectedItem.value = await getUser(id);
|
||||
}
|
||||
|
||||
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 });
|
||||
}
|
||||
|
||||
/** 弹窗选中回调 */
|
||||
function handleSelected(rows: SystemUserApi.User[]) {
|
||||
const item = rows[0];
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
selectedItem.value = item;
|
||||
emit('update:modelValue', item.id);
|
||||
emit('change', item);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-bind="attrs"
|
||||
class="w-full"
|
||||
:class="disabled ? 'cursor-not-allowed' : 'cursor-pointer'"
|
||||
@click="handleClick"
|
||||
@mouseenter="hovering = true"
|
||||
@mouseleave="hovering = false"
|
||||
>
|
||||
<Tooltip :mouse-enter-delay="0.5" :open="selectedItem ? undefined : false">
|
||||
<template #title>
|
||||
<div v-if="selectedItem" class="leading-6">
|
||||
<div>用户名称:{{ selectedItem.username || '-' }}</div>
|
||||
<div>用户昵称:{{ selectedItem.nickname || '-' }}</div>
|
||||
<div>手机号码:{{ selectedItem.mobile || '-' }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<Input
|
||||
:disabled="disabled"
|
||||
:placeholder="placeholder"
|
||||
:value="displayLabel"
|
||||
readonly
|
||||
>
|
||||
<template #suffix>
|
||||
<IconifyIcon
|
||||
class="size-4"
|
||||
:icon="showClear ? 'lucide:circle-x' : 'lucide:search'"
|
||||
/>
|
||||
</template>
|
||||
</Input>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<UserSelectDialog ref="dialogRef" @selected="handleSelected" />
|
||||
</template>
|
||||
|
|
@ -21,10 +21,10 @@ import {
|
|||
updateUserStatus,
|
||||
} from '#/api/system/user';
|
||||
import { $t } from '#/locales';
|
||||
import { DeptTreeSelect } from '#/views/system/dept/components';
|
||||
|
||||
import { useGridColumns, useGridFormSchema } from './data';
|
||||
import AssignRoleForm from './modules/assign-role-form.vue';
|
||||
import DeptTree from './modules/dept-tree.vue';
|
||||
import Form from './modules/form.vue';
|
||||
import ImportForm from './modules/import-form.vue';
|
||||
import ResetPasswordForm from './modules/reset-password-form.vue';
|
||||
|
|
@ -62,8 +62,8 @@ async function handleExport() {
|
|||
|
||||
/** 选择部门 */
|
||||
const searchDeptId = ref<number | undefined>(undefined);
|
||||
async function handleDeptSelect(dept: SystemDeptApi.Dept) {
|
||||
searchDeptId.value = dept.id;
|
||||
async function handleDeptSelect(dept?: SystemDeptApi.Dept) {
|
||||
searchDeptId.value = dept?.id;
|
||||
handleRefresh();
|
||||
}
|
||||
|
||||
|
|
@ -205,7 +205,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||
<div class="flex h-full w-full">
|
||||
<!-- 左侧部门树 -->
|
||||
<Card class="mr-4 h-full w-1/6">
|
||||
<DeptTree @select="handleDeptSelect" />
|
||||
<DeptTreeSelect @select="handleDeptSelect" />
|
||||
</Card>
|
||||
<!-- 右侧用户列表 -->
|
||||
<div class="w-5/6">
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ export namespace MesProWorkOrderApi {
|
|||
routeName?: string;
|
||||
clientId?: number;
|
||||
clientName?: string;
|
||||
vendorId?: number; // 供应商编号
|
||||
vendorName?: string; // 供应商名称
|
||||
planStartTime?: number | string;
|
||||
planEndTime?: number | string;
|
||||
actualStartTime?: number | string;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace MesWmOutsourceIssueDetailApi {
|
||||
/** MES 外协发料单明细 */
|
||||
export interface OutsourceIssueDetail {
|
||||
id?: number; // 明细编号
|
||||
lineId?: number; // 行编号
|
||||
issueId?: number; // 发料单编号
|
||||
itemId?: number; // 物料编号
|
||||
itemCode?: string; // 物料编码
|
||||
itemName?: string; // 物料名称
|
||||
specification?: string; // 规格型号
|
||||
unitMeasureName?: string; // 计量单位名称
|
||||
quantity?: number; // 数量
|
||||
materialStockId?: number; // 库存编号
|
||||
batchId?: number; // 批次编号
|
||||
batchCode?: string; // 批次编码
|
||||
warehouseId?: number; // 仓库编号
|
||||
warehouseName?: string; // 仓库名称
|
||||
locationId?: number; // 库区编号
|
||||
locationName?: string; // 库区名称
|
||||
areaId?: number; // 库位编号
|
||||
areaName?: string; // 库位名称
|
||||
remark?: string; // 备注
|
||||
createTime?: Date; // 创建时间
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询外协发料单明细列表 */
|
||||
export function getOutsourceIssueDetailListByLineId(lineId: number) {
|
||||
return requestClient.get<
|
||||
MesWmOutsourceIssueDetailApi.OutsourceIssueDetail[]
|
||||
>('/mes/wm/outsource-issue-detail/list-by-line', { params: { lineId } });
|
||||
}
|
||||
|
||||
/** 查询外协发料单明细详情 */
|
||||
export function getOutsourceIssueDetail(id: number) {
|
||||
return requestClient.get<MesWmOutsourceIssueDetailApi.OutsourceIssueDetail>(
|
||||
`/mes/wm/outsource-issue-detail/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增外协发料单明细 */
|
||||
export function createOutsourceIssueDetail(
|
||||
data: MesWmOutsourceIssueDetailApi.OutsourceIssueDetail,
|
||||
) {
|
||||
return requestClient.post('/mes/wm/outsource-issue-detail/create', data);
|
||||
}
|
||||
|
||||
/** 修改外协发料单明细 */
|
||||
export function updateOutsourceIssueDetail(
|
||||
data: MesWmOutsourceIssueDetailApi.OutsourceIssueDetail,
|
||||
) {
|
||||
return requestClient.put('/mes/wm/outsource-issue-detail/update', data);
|
||||
}
|
||||
|
||||
/** 删除外协发料单明细 */
|
||||
export function deleteOutsourceIssueDetail(id: number) {
|
||||
return requestClient.delete(`/mes/wm/outsource-issue-detail/delete?id=${id}`);
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
import type { PageParam, PageResult } from '@vben/request';
|
||||
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace MesWmOutsourceIssueApi {
|
||||
/** MES 外协发料单 */
|
||||
export interface OutsourceIssue {
|
||||
id?: number; // 发料单编号
|
||||
code?: string; // 发料单编号
|
||||
name?: string; // 发料单名称
|
||||
vendorId?: number; // 供应商编号
|
||||
vendorCode?: string; // 供应商编码
|
||||
vendorName?: string; // 供应商名称
|
||||
workOrderId?: number; // 生产工单编号
|
||||
workOrderCode?: string; // 生产工单编码
|
||||
workOrderName?: string; // 生产工单名称
|
||||
issueDate?: number; // 发料日期
|
||||
status?: number; // 单据状态
|
||||
remark?: string; // 备注
|
||||
createTime?: Date; // 创建时间
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询外协发料单分页 */
|
||||
export function getOutsourceIssuePage(params: PageParam) {
|
||||
return requestClient.get<PageResult<MesWmOutsourceIssueApi.OutsourceIssue>>(
|
||||
'/mes/wm/outsource-issue/page',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询外协发料单详情 */
|
||||
export function getOutsourceIssue(id: number) {
|
||||
return requestClient.get<MesWmOutsourceIssueApi.OutsourceIssue>(
|
||||
`/mes/wm/outsource-issue/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增外协发料单 */
|
||||
export function createOutsourceIssue(
|
||||
data: MesWmOutsourceIssueApi.OutsourceIssue,
|
||||
) {
|
||||
return requestClient.post<number>('/mes/wm/outsource-issue/create', data);
|
||||
}
|
||||
|
||||
/** 修改外协发料单 */
|
||||
export function updateOutsourceIssue(
|
||||
data: MesWmOutsourceIssueApi.OutsourceIssue,
|
||||
) {
|
||||
return requestClient.put('/mes/wm/outsource-issue/update', data);
|
||||
}
|
||||
|
||||
/** 删除外协发料单 */
|
||||
export function deleteOutsourceIssue(id: number) {
|
||||
return requestClient.delete(`/mes/wm/outsource-issue/delete?id=${id}`);
|
||||
}
|
||||
|
||||
/** 提交外协发料单 */
|
||||
export function submitOutsourceIssue(id: number) {
|
||||
return requestClient.put(`/mes/wm/outsource-issue/submit?id=${id}`);
|
||||
}
|
||||
|
||||
/** 执行拣货 */
|
||||
export function stockOutsourceIssue(id: number) {
|
||||
return requestClient.put(`/mes/wm/outsource-issue/stock?id=${id}`);
|
||||
}
|
||||
|
||||
/** 执行领出 */
|
||||
export function finishOutsourceIssue(id: number) {
|
||||
return requestClient.put(`/mes/wm/outsource-issue/finish?id=${id}`);
|
||||
}
|
||||
|
||||
/** 取消外协发料单 */
|
||||
export function cancelOutsourceIssue(id: number) {
|
||||
return requestClient.put(`/mes/wm/outsource-issue/cancel?id=${id}`);
|
||||
}
|
||||
|
||||
/** 校验外协发料单拣货数量是否与发料数量一致 */
|
||||
export function checkOutsourceIssueQuantity(id: number) {
|
||||
return requestClient.get<boolean>(
|
||||
`/mes/wm/outsource-issue/check-quantity?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 导出外协发料单 */
|
||||
export function exportOutsourceIssue(params: any) {
|
||||
return requestClient.download('/mes/wm/outsource-issue/export-excel', {
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
import type { PageParam, PageResult } from '@vben/request';
|
||||
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace MesWmOutsourceIssueLineApi {
|
||||
/** MES 外协发料单行 */
|
||||
export interface OutsourceIssueLine {
|
||||
id?: number; // 行编号
|
||||
issueId?: number; // 发料单编号
|
||||
itemId?: number; // 物料编号
|
||||
itemCode?: string; // 物料编码
|
||||
itemName?: string; // 物料名称
|
||||
specification?: string; // 规格型号
|
||||
unitMeasureName?: string; // 计量单位名称
|
||||
quantity?: number; // 发料数量
|
||||
materialStockId?: number; // 库存编号
|
||||
batchId?: number; // 批次编号
|
||||
batchCode?: string; // 批次编码
|
||||
remark?: string; // 备注
|
||||
createTime?: Date; // 创建时间
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询外协发料单行分页 */
|
||||
export function getOutsourceIssueLinePage(params: PageParam) {
|
||||
return requestClient.get<
|
||||
PageResult<MesWmOutsourceIssueLineApi.OutsourceIssueLine>
|
||||
>('/mes/wm/outsource-issue-line/page', { params });
|
||||
}
|
||||
|
||||
/** 查询外协发料单行详情 */
|
||||
export function getOutsourceIssueLine(id: number) {
|
||||
return requestClient.get<MesWmOutsourceIssueLineApi.OutsourceIssueLine>(
|
||||
`/mes/wm/outsource-issue-line/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增外协发料单行 */
|
||||
export function createOutsourceIssueLine(
|
||||
data: MesWmOutsourceIssueLineApi.OutsourceIssueLine,
|
||||
) {
|
||||
return requestClient.post('/mes/wm/outsource-issue-line/create', data);
|
||||
}
|
||||
|
||||
/** 修改外协发料单行 */
|
||||
export function updateOutsourceIssueLine(
|
||||
data: MesWmOutsourceIssueLineApi.OutsourceIssueLine,
|
||||
) {
|
||||
return requestClient.put('/mes/wm/outsource-issue-line/update', data);
|
||||
}
|
||||
|
||||
/** 删除外协发料单行 */
|
||||
export function deleteOutsourceIssueLine(id: number) {
|
||||
return requestClient.delete(`/mes/wm/outsource-issue-line/delete?id=${id}`);
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace MesWmOutsourceReceiptDetailApi {
|
||||
/** MES 外协入库单明细 */
|
||||
export interface OutsourceReceiptDetail {
|
||||
id?: number; // 明细编号
|
||||
lineId?: number; // 行编号
|
||||
receiptId?: number; // 入库单编号
|
||||
itemId?: number; // 物料编号
|
||||
itemCode?: string; // 物料编码
|
||||
itemName?: string; // 物料名称
|
||||
specification?: string; // 规格型号
|
||||
unitMeasureName?: string; // 计量单位名称
|
||||
quantity?: number; // 上架数量
|
||||
batchId?: number; // 批次编号
|
||||
batchCode?: string; // 批次编码
|
||||
warehouseId?: number; // 仓库编号
|
||||
warehouseName?: string; // 仓库名称
|
||||
locationId?: number; // 库区编号
|
||||
locationName?: string; // 库区名称
|
||||
areaId?: number; // 库位编号
|
||||
areaName?: string; // 库位名称
|
||||
remark?: string; // 备注
|
||||
createTime?: Date; // 创建时间
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询外协入库单明细列表 */
|
||||
export function getOutsourceReceiptDetailListByLineId(lineId: number) {
|
||||
return requestClient.get<
|
||||
MesWmOutsourceReceiptDetailApi.OutsourceReceiptDetail[]
|
||||
>('/mes/wm/outsource-receipt-detail/list-by-line', { params: { lineId } });
|
||||
}
|
||||
|
||||
/** 查询外协入库单明细详情 */
|
||||
export function getOutsourceReceiptDetail(id: number) {
|
||||
return requestClient.get<MesWmOutsourceReceiptDetailApi.OutsourceReceiptDetail>(
|
||||
`/mes/wm/outsource-receipt-detail/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增外协入库单明细 */
|
||||
export function createOutsourceReceiptDetail(
|
||||
data: MesWmOutsourceReceiptDetailApi.OutsourceReceiptDetail,
|
||||
) {
|
||||
return requestClient.post('/mes/wm/outsource-receipt-detail/create', data);
|
||||
}
|
||||
|
||||
/** 修改外协入库单明细 */
|
||||
export function updateOutsourceReceiptDetail(
|
||||
data: MesWmOutsourceReceiptDetailApi.OutsourceReceiptDetail,
|
||||
) {
|
||||
return requestClient.put('/mes/wm/outsource-receipt-detail/update', data);
|
||||
}
|
||||
|
||||
/** 删除外协入库单明细 */
|
||||
export function deleteOutsourceReceiptDetail(id: number) {
|
||||
return requestClient.delete(
|
||||
`/mes/wm/outsource-receipt-detail/delete?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
import type { PageParam, PageResult } from '@vben/request';
|
||||
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace MesWmOutsourceReceiptApi {
|
||||
/** MES 外协入库单 */
|
||||
export interface OutsourceReceipt {
|
||||
id?: number; // 入库单编号
|
||||
code?: string; // 入库单编码
|
||||
name?: string; // 入库单名称
|
||||
workOrderId?: number; // 外协工单编号
|
||||
workOrderCode?: string; // 外协工单编码
|
||||
vendorId?: number; // 供应商编号
|
||||
vendorName?: string; // 供应商名称
|
||||
receiptDate?: number; // 入库日期
|
||||
status?: number; // 单据状态
|
||||
remark?: string; // 备注
|
||||
createTime?: Date; // 创建时间
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询外协入库单分页 */
|
||||
export function getOutsourceReceiptPage(params: PageParam) {
|
||||
return requestClient.get<PageResult<MesWmOutsourceReceiptApi.OutsourceReceipt>>(
|
||||
'/mes/wm/outsource-receipt/page',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
/** 查询外协入库单详情 */
|
||||
export function getOutsourceReceipt(id: number) {
|
||||
return requestClient.get<MesWmOutsourceReceiptApi.OutsourceReceipt>(
|
||||
`/mes/wm/outsource-receipt/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增外协入库单 */
|
||||
export function createOutsourceReceipt(
|
||||
data: MesWmOutsourceReceiptApi.OutsourceReceipt,
|
||||
) {
|
||||
return requestClient.post<number>('/mes/wm/outsource-receipt/create', data);
|
||||
}
|
||||
|
||||
/** 修改外协入库单 */
|
||||
export function updateOutsourceReceipt(
|
||||
data: MesWmOutsourceReceiptApi.OutsourceReceipt,
|
||||
) {
|
||||
return requestClient.put('/mes/wm/outsource-receipt/update', data);
|
||||
}
|
||||
|
||||
/** 删除外协入库单 */
|
||||
export function deleteOutsourceReceipt(id: number) {
|
||||
return requestClient.delete(`/mes/wm/outsource-receipt/delete?id=${id}`);
|
||||
}
|
||||
|
||||
/** 提交外协入库单 */
|
||||
export function submitOutsourceReceipt(id: number) {
|
||||
return requestClient.put(`/mes/wm/outsource-receipt/submit?id=${id}`);
|
||||
}
|
||||
|
||||
/** 执行上架 */
|
||||
export function stockOutsourceReceipt(id: number) {
|
||||
return requestClient.put(`/mes/wm/outsource-receipt/stock?id=${id}`);
|
||||
}
|
||||
|
||||
/** 完成入库 */
|
||||
export function finishOutsourceReceipt(id: number) {
|
||||
return requestClient.put(`/mes/wm/outsource-receipt/finish?id=${id}`);
|
||||
}
|
||||
|
||||
/** 取消外协入库单 */
|
||||
export function cancelOutsourceReceipt(id: number) {
|
||||
return requestClient.put(`/mes/wm/outsource-receipt/cancel?id=${id}`);
|
||||
}
|
||||
|
||||
/** 导出外协入库单 */
|
||||
export function exportOutsourceReceipt(params: any) {
|
||||
return requestClient.download('/mes/wm/outsource-receipt/export-excel', {
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
import type { PageParam, PageResult } from '@vben/request';
|
||||
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace MesWmOutsourceReceiptLineApi {
|
||||
/** MES 外协入库单行 */
|
||||
export interface OutsourceReceiptLine {
|
||||
id?: number; // 行编号
|
||||
receiptId?: number; // 入库单编号
|
||||
itemId?: number; // 物料编号
|
||||
itemCode?: string; // 物料编码
|
||||
itemName?: string; // 物料名称
|
||||
specification?: string; // 规格型号
|
||||
unitMeasureName?: string; // 计量单位名称
|
||||
quantity?: number; // 入库数量
|
||||
batchId?: number; // 批次编号
|
||||
batchCode?: string; // 批次编码
|
||||
productionDate?: number; // 生产日期
|
||||
expireDate?: number; // 有效期
|
||||
lotNumber?: string; // 生产批号
|
||||
iqcCheckFlag?: boolean; // 是否需要质检
|
||||
remark?: string; // 备注
|
||||
createTime?: Date; // 创建时间
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询外协入库单行分页 */
|
||||
export function getOutsourceReceiptLinePage(params: PageParam) {
|
||||
return requestClient.get<
|
||||
PageResult<MesWmOutsourceReceiptLineApi.OutsourceReceiptLine>
|
||||
>('/mes/wm/outsource-receipt-line/page', { params });
|
||||
}
|
||||
|
||||
/** 查询外协入库单行详情 */
|
||||
export function getOutsourceReceiptLine(id: number) {
|
||||
return requestClient.get<MesWmOutsourceReceiptLineApi.OutsourceReceiptLine>(
|
||||
`/mes/wm/outsource-receipt-line/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 新增外协入库单行 */
|
||||
export function createOutsourceReceiptLine(
|
||||
data: MesWmOutsourceReceiptLineApi.OutsourceReceiptLine,
|
||||
) {
|
||||
return requestClient.post('/mes/wm/outsource-receipt-line/create', data);
|
||||
}
|
||||
|
||||
/** 修改外协入库单行 */
|
||||
export function updateOutsourceReceiptLine(
|
||||
data: MesWmOutsourceReceiptLineApi.OutsourceReceiptLine,
|
||||
) {
|
||||
return requestClient.put('/mes/wm/outsource-receipt-line/update', data);
|
||||
}
|
||||
|
||||
/** 删除外协入库单行 */
|
||||
export function deleteOutsourceReceiptLine(id: number) {
|
||||
return requestClient.delete(`/mes/wm/outsource-receipt-line/delete?id=${id}`);
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
export { default as ProCardSelectDialog } from './pro-card-select-dialog.vue';
|
||||
export { default as ProCardSelect } from './pro-card-select.vue';
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
<script lang="ts" setup>
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { MesProCardApi } from '#/api/mes/pro/card';
|
||||
|
||||
import { nextTick, ref } from 'vue';
|
||||
|
||||
import { ElButton, ElDialog, ElMessage } from 'element-plus';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { getCardPage } from '#/api/mes/pro/card';
|
||||
|
||||
import { useCardSelectGridColumns, useCardSelectGridFormSchema } from '../data';
|
||||
|
||||
const emit = defineEmits<{
|
||||
selected: [rows: MesProCardApi.Card[]];
|
||||
}>();
|
||||
|
||||
const open = ref(false); // 弹窗是否打开
|
||||
const multiple = ref(false); // 是否多选;默认按单选选择器使用
|
||||
const selectedRows = ref<MesProCardApi.Card[]>([]); // 已选流转卡列表
|
||||
const preSelectedIds = ref<number[]>([]); // 预选流转卡编号列表
|
||||
|
||||
/** 获取多选记录,包含 VXE reserve 跨页记录 */
|
||||
function getMultipleSelectedRows() {
|
||||
const selectedMap = new Map<number, MesProCardApi.Card>();
|
||||
const records = [
|
||||
...(gridApi.grid.getCheckboxReserveRecords?.() ?? []),
|
||||
...(gridApi.grid.getCheckboxRecords?.() ?? []),
|
||||
] as MesProCardApi.Card[];
|
||||
records.forEach((row) => {
|
||||
const rowId = row.id;
|
||||
if (rowId !== undefined) {
|
||||
selectedMap.set(rowId, row);
|
||||
}
|
||||
});
|
||||
return [...selectedMap.values()];
|
||||
}
|
||||
|
||||
/** 处理多选勾选变化 */
|
||||
function handleCheckboxSelectChange() {
|
||||
selectedRows.value = getMultipleSelectedRows();
|
||||
}
|
||||
|
||||
/** 处理单选切换 */
|
||||
function handleRadioChange(row: MesProCardApi.Card) {
|
||||
selectedRows.value = [row];
|
||||
}
|
||||
|
||||
/** 多选模式下切换行勾选 */
|
||||
async function toggleMultipleRow(row: MesProCardApi.Card) {
|
||||
const selected = gridApi.grid.isCheckedByCheckboxRow(row);
|
||||
await gridApi.grid.setCheckboxRow(row, !selected);
|
||||
selectedRows.value = getMultipleSelectedRows();
|
||||
}
|
||||
|
||||
/** 处理行双击:单选直接确认,多选切换勾选 */
|
||||
async function handleCellDblclick({ row }: { row: MesProCardApi.Card }) {
|
||||
if (multiple.value) {
|
||||
await toggleMultipleRow(row);
|
||||
return;
|
||||
}
|
||||
selectedRows.value = [row];
|
||||
await gridApi.grid.setRadioRow(row);
|
||||
handleConfirm();
|
||||
}
|
||||
|
||||
/** 回显预选流转卡 */
|
||||
async function applyPreSelection() {
|
||||
if (preSelectedIds.value.length === 0) {
|
||||
return;
|
||||
}
|
||||
const rows = gridApi.grid.getData() as MesProCardApi.Card[];
|
||||
for (const row of rows) {
|
||||
if (row.id === undefined || !preSelectedIds.value.includes(row.id)) {
|
||||
continue;
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
formOptions: {
|
||||
schema: useCardSelectGridFormSchema(),
|
||||
},
|
||||
gridOptions: {
|
||||
columns: useCardSelectGridColumns(false),
|
||||
height: 520,
|
||||
keepSource: true,
|
||||
checkboxConfig: {
|
||||
highlight: true,
|
||||
range: true,
|
||||
reserve: true,
|
||||
},
|
||||
radioConfig: {
|
||||
highlight: true,
|
||||
trigger: 'row',
|
||||
},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }, formValues) => {
|
||||
return await getCardPage({
|
||||
pageNo: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
...formValues,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
rowConfig: {
|
||||
keyField: 'id',
|
||||
isHover: true,
|
||||
},
|
||||
toolbarConfig: {
|
||||
refresh: true,
|
||||
search: true,
|
||||
},
|
||||
} as VxeTableGridOptions<MesProCardApi.Card>,
|
||||
gridEvents: {
|
||||
cellDblclick: handleCellDblclick,
|
||||
checkboxAll: handleCheckboxSelectChange,
|
||||
checkboxChange: handleCheckboxSelectChange,
|
||||
radioChange: ({ row }: { row: MesProCardApi.Card }) => {
|
||||
handleRadioChange(row);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/** 重置查询和选择状态 */
|
||||
async function resetQueryState() {
|
||||
selectedRows.value = [];
|
||||
await gridApi.grid.clearCheckboxRow();
|
||||
await gridApi.grid.clearCheckboxReserve();
|
||||
await gridApi.grid.clearRadioRow();
|
||||
await gridApi.formApi.resetForm();
|
||||
}
|
||||
|
||||
/** 打开流转卡选择弹窗 */
|
||||
async function openModal(
|
||||
selectedIds?: number[],
|
||||
options?: { multiple?: boolean },
|
||||
) {
|
||||
open.value = true;
|
||||
multiple.value = options?.multiple ?? false;
|
||||
preSelectedIds.value = selectedIds || [];
|
||||
await nextTick();
|
||||
gridApi.setGridOptions({
|
||||
columns: useCardSelectGridColumns(multiple.value),
|
||||
});
|
||||
await resetQueryState();
|
||||
await gridApi.query();
|
||||
await nextTick();
|
||||
await applyPreSelection();
|
||||
}
|
||||
|
||||
/** 关闭流转卡选择弹窗 */
|
||||
function closeModal() {
|
||||
open.value = false;
|
||||
}
|
||||
|
||||
/** 确认选择流转卡 */
|
||||
function handleConfirm() {
|
||||
const rows = multiple.value ? getMultipleSelectedRows() : selectedRows.value;
|
||||
if (rows.length === 0) {
|
||||
ElMessage.warning(multiple.value ? '请至少选择一条数据' : '请选择一条数据');
|
||||
return;
|
||||
}
|
||||
emit('selected', multiple.value ? rows : [rows[0]!]);
|
||||
open.value = false;
|
||||
}
|
||||
|
||||
defineExpose({ open: openModal });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ElDialog v-model="open" title="流转卡选择" width="70%">
|
||||
<Grid table-title="流转卡列表" />
|
||||
<template #footer>
|
||||
<ElButton @click="closeModal">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleConfirm">确定</ElButton>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
<script lang="ts" setup>
|
||||
import type { MesProCardApi } from '#/api/mes/pro/card';
|
||||
|
||||
import { computed, ref, useAttrs, watch } from 'vue';
|
||||
|
||||
import { CircleX, Search } from '@vben/icons';
|
||||
|
||||
import { ElInput, ElTooltip } from 'element-plus';
|
||||
|
||||
import { getCard } from '#/api/mes/pro/card';
|
||||
|
||||
import ProCardSelectDialog from './pro-card-select-dialog.vue';
|
||||
|
||||
defineOptions({ name: 'ProCardSelect', inheritAttrs: false });
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
clearable?: boolean;
|
||||
disabled?: boolean;
|
||||
modelValue?: number;
|
||||
placeholder?: string;
|
||||
}>(),
|
||||
{
|
||||
clearable: true,
|
||||
disabled: false,
|
||||
modelValue: undefined,
|
||||
placeholder: '请选择流转卡',
|
||||
},
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
change: [item: MesProCardApi.Card | undefined];
|
||||
'update:modelValue': [value: number | undefined];
|
||||
}>();
|
||||
|
||||
const attrs = useAttrs();
|
||||
const dialogRef = ref<InstanceType<typeof ProCardSelectDialog>>();
|
||||
const hovering = ref(false);
|
||||
const selectedItem = ref<MesProCardApi.Card>();
|
||||
|
||||
const displayLabel = computed(() => selectedItem.value?.code ?? '');
|
||||
|
||||
const showClear = computed(
|
||||
() =>
|
||||
props.clearable &&
|
||||
!props.disabled &&
|
||||
hovering.value &&
|
||||
props.modelValue != null,
|
||||
);
|
||||
|
||||
/** 根据编号单条查询流转卡信息(用于编辑回显) */
|
||||
async function resolveItemById(id: number | undefined) {
|
||||
if (id == null) {
|
||||
selectedItem.value = undefined;
|
||||
return;
|
||||
}
|
||||
if (selectedItem.value?.id === id) {
|
||||
return;
|
||||
}
|
||||
selectedItem.value = await getCard(id);
|
||||
}
|
||||
|
||||
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('.el-input__suffix')) {
|
||||
event.stopPropagation();
|
||||
clearSelected();
|
||||
return;
|
||||
}
|
||||
const selectedIds = props.modelValue == null ? [] : [props.modelValue];
|
||||
dialogRef.value?.open(selectedIds, { multiple: false });
|
||||
}
|
||||
|
||||
/** 弹窗选中回调 */
|
||||
function handleSelected(rows: MesProCardApi.Card[]) {
|
||||
const item = rows[0];
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
selectedItem.value = item;
|
||||
emit('update:modelValue', item.id);
|
||||
emit('change', item);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-bind="attrs"
|
||||
class="w-full"
|
||||
:class="disabled ? 'cursor-not-allowed' : 'cursor-pointer'"
|
||||
@click="handleClick"
|
||||
@mouseenter="hovering = true"
|
||||
@mouseleave="hovering = false"
|
||||
>
|
||||
<ElTooltip :disabled="!selectedItem" placement="top" :show-after="500">
|
||||
<template #content>
|
||||
<div v-if="selectedItem" class="leading-6">
|
||||
<div>编号:{{ selectedItem.code || '-' }}</div>
|
||||
<div>工单:{{ selectedItem.workOrderCode || '-' }}</div>
|
||||
<div>批次:{{ selectedItem.batchCode || '-' }}</div>
|
||||
<div>产品:{{ selectedItem.itemName || '-' }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<ElInput
|
||||
:disabled="disabled"
|
||||
:model-value="displayLabel"
|
||||
:placeholder="placeholder"
|
||||
readonly
|
||||
>
|
||||
<template #suffix>
|
||||
<CircleX v-if="showClear" class="size-4" />
|
||||
<Search v-else class="size-4" />
|
||||
</template>
|
||||
</ElInput>
|
||||
</ElTooltip>
|
||||
</div>
|
||||
<ProCardSelectDialog ref="dialogRef" @selected="handleSelected" />
|
||||
</template>
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
import type { VbenFormSchema } from '#/adapter/form';
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { MesProCardApi } from '#/api/mes/pro/card';
|
||||
|
||||
import { markRaw } from 'vue';
|
||||
|
||||
import { MdItemSelect } from '#/views/mes/md/item/components';
|
||||
import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components';
|
||||
|
||||
/** 流转卡选择弹窗的搜索表单 */
|
||||
export function useCardSelectGridFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
fieldName: 'code',
|
||||
label: '流转卡编号',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
clearable: true,
|
||||
placeholder: '请输入流转卡编号',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'workOrderId',
|
||||
label: '生产工单',
|
||||
component: markRaw(ProWorkOrderSelect),
|
||||
componentProps: {
|
||||
placeholder: '请选择生产工单',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'itemId',
|
||||
label: '产品物料',
|
||||
component: markRaw(MdItemSelect),
|
||||
componentProps: {
|
||||
placeholder: '请选择产品物料',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'batchCode',
|
||||
label: '批次号',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
clearable: true,
|
||||
placeholder: '请输入批次号',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 流转卡选择弹窗的字段 */
|
||||
export function useCardSelectGridColumns(
|
||||
multiple = false,
|
||||
): VxeTableGridOptions<MesProCardApi.Card>['columns'] {
|
||||
return [
|
||||
{
|
||||
type: multiple ? 'checkbox' : 'radio',
|
||||
width: 50,
|
||||
},
|
||||
{
|
||||
field: 'code',
|
||||
title: '流转卡编号',
|
||||
width: 160,
|
||||
},
|
||||
{
|
||||
field: 'workOrderCode',
|
||||
title: '生产工单编号',
|
||||
width: 160,
|
||||
},
|
||||
{
|
||||
field: 'itemCode',
|
||||
title: '产品物料编码',
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
field: 'batchCode',
|
||||
title: '批次号',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: 'itemName',
|
||||
title: '产品物料名称',
|
||||
minWidth: 150,
|
||||
},
|
||||
{
|
||||
field: 'specification',
|
||||
title: '规格型号',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: 'unitMeasureName',
|
||||
title: '单位',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
field: 'transferedQuantity',
|
||||
title: '流转数量',
|
||||
width: 100,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
@ -151,9 +151,22 @@ export const MesAutoCodeRuleCode = {
|
|||
TM_TOOL_CODE: 'TM_TOOL_CODE',
|
||||
WM_AREA_CODE: 'WM_AREA_CODE',
|
||||
WM_LOCATION_CODE: 'WM_LOCATION_CODE',
|
||||
WM_ARRIVAL_NOTICE_CODE: 'WM_ARRIVAL_NOTICE_CODE',
|
||||
WM_ITEM_RECEIPT_CODE: 'WM_ITEM_RECEIPT_CODE',
|
||||
WM_RETURN_VENDOR_CODE: 'WM_RETURN_VENDOR_CODE',
|
||||
WM_SALES_NOTICE_CODE: 'WM_SALES_NOTICE_CODE',
|
||||
WM_RETURN_SALES_CODE: 'WM_RETURN_SALES_CODE',
|
||||
WM_RETURN_ISSUE_CODE: 'WM_RETURN_ISSUE_CODE',
|
||||
WM_PRODUCT_ISSUE_CODE: 'WM_PRODUCT_ISSUE_CODE',
|
||||
WM_PRODUCT_SALES_CODE: 'WM_PRODUCT_SALES_CODE',
|
||||
PRODUCTRECPT_CODE: 'PRODUCTRECPT_CODE',
|
||||
WM_MISC_ISSUE_CODE: 'WM_MISC_ISSUE_CODE',
|
||||
WM_MISC_RECEIPT_CODE: 'WM_MISC_RECEIPT_CODE',
|
||||
WM_OUTSOURCE_ISSUE_CODE: 'WM_OUTSOURCE_ISSUE_CODE',
|
||||
WM_OUTSOURCE_RECEIPT_CODE: 'WM_OUTSOURCE_RECEIPT_CODE',
|
||||
WM_PACKAGE_CODE: 'WM_PACKAGE_CODE',
|
||||
WM_STOCK_TAKING_CODE: 'WM_STOCK_TAKING_CODE',
|
||||
WM_STOCK_TAKING_PLAN_CODE: 'WM_STOCK_TAKING_PLAN_CODE',
|
||||
WM_WAREHOUSE_CODE: 'WM_WAREHOUSE_CODE',
|
||||
} as const;
|
||||
|
||||
|
|
@ -163,6 +176,38 @@ export const MesWmPackageStatusEnum = {
|
|||
FINISHED: MesOrderStatusConstants.FINISHED,
|
||||
} as const;
|
||||
|
||||
/** MES 盘点类型枚举 */
|
||||
export const MesWmStockTakingTypeEnum = {
|
||||
STATIC: 1,
|
||||
DYNAMIC: 2,
|
||||
} as const;
|
||||
|
||||
/** MES 盘点任务状态枚举 */
|
||||
export const MesWmStockTakingTaskStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
APPROVING: MesOrderStatusConstants.APPROVING,
|
||||
FINISHED: MesOrderStatusConstants.FINISHED,
|
||||
CANCELED: MesOrderStatusConstants.CANCELLED,
|
||||
} as const;
|
||||
|
||||
/** MES 盘点任务行状态枚举 */
|
||||
export const MesWmStockTakingTaskLineStatusEnum = {
|
||||
UNCOUNTED: 0,
|
||||
NORMAL: 1,
|
||||
GAIN: 2,
|
||||
LOSS: 3,
|
||||
} as const;
|
||||
|
||||
/** MES 盘点方案参数类型枚举 */
|
||||
export const MesWmStockTakingParamTypeEnum = {
|
||||
WAREHOUSE: 102,
|
||||
LOCATION: 103,
|
||||
AREA: 104,
|
||||
BATCH: 107,
|
||||
ITEM: 600,
|
||||
QUALITY_STATUS: 900,
|
||||
} as const;
|
||||
|
||||
/** MES 生产工单状态枚举 */
|
||||
export const MesProWorkOrderStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
|
|
@ -173,6 +218,13 @@ export const MesProWorkOrderStatusEnum = {
|
|||
CANCELLED: MesOrderStatusConstants.CANCELLED,
|
||||
} as const;
|
||||
|
||||
/** MES 工单类型枚举 */
|
||||
export const MesProWorkOrderTypeEnum = {
|
||||
SELF: 1, // 自行生产
|
||||
OUTSOURCE: 2, // 代工
|
||||
PURCHASE: 3, // 采购
|
||||
} as const;
|
||||
|
||||
/** MES 生产任务状态枚举 */
|
||||
export const MesProTaskStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
|
|
@ -236,6 +288,105 @@ export const MesWmMiscReceiptStatusEnum = {
|
|||
CANCELED: MesOrderStatusConstants.CANCELLED,
|
||||
} as const;
|
||||
|
||||
/** MES 外协发料单状态枚举 */
|
||||
export const MesWmOutsourceIssueStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
APPROVING: MesOrderStatusConstants.APPROVING,
|
||||
APPROVED: MesOrderStatusConstants.APPROVED,
|
||||
FINISHED: MesOrderStatusConstants.FINISHED,
|
||||
CANCELLED: MesOrderStatusConstants.CANCELLED,
|
||||
} as const;
|
||||
|
||||
/** MES 外协入库单状态枚举 */
|
||||
export const MesWmOutsourceReceiptStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
APPROVING: MesOrderStatusConstants.APPROVING,
|
||||
APPROVED: MesOrderStatusConstants.APPROVED,
|
||||
FINISHED: MesOrderStatusConstants.FINISHED,
|
||||
CANCELED: MesOrderStatusConstants.CANCELLED,
|
||||
} as const;
|
||||
|
||||
/** MES 到货通知单状态枚举 */
|
||||
export const MesWmArrivalNoticeStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
PENDING_QC: MesOrderStatusConstants.APPROVING,
|
||||
PENDING_RECEIPT: MesOrderStatusConstants.APPROVED,
|
||||
FINISHED: MesOrderStatusConstants.FINISHED,
|
||||
} as const;
|
||||
|
||||
/** MES 采购入库单状态枚举 */
|
||||
export const MesWmItemReceiptStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
APPROVING: MesOrderStatusConstants.APPROVING,
|
||||
APPROVED: MesOrderStatusConstants.APPROVED,
|
||||
FINISHED: MesOrderStatusConstants.FINISHED,
|
||||
CANCELED: MesOrderStatusConstants.CANCELLED,
|
||||
} as const;
|
||||
|
||||
/** MES 供应商退货单状态枚举 */
|
||||
export const MesWmReturnVendorStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
APPROVING: MesOrderStatusConstants.APPROVING,
|
||||
APPROVED: MesOrderStatusConstants.APPROVED,
|
||||
FINISHED: MesOrderStatusConstants.FINISHED,
|
||||
CANCELED: MesOrderStatusConstants.CANCELLED,
|
||||
} as const;
|
||||
|
||||
/** MES 发货通知单状态枚举 */
|
||||
export const MesWmSalesNoticeStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
APPROVED: MesOrderStatusConstants.APPROVED,
|
||||
} as const;
|
||||
|
||||
/** MES 销售退货单状态枚举 */
|
||||
export const MesWmReturnSalesStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
CONFIRMED: MesOrderStatusConstants.CONFIRMED,
|
||||
APPROVING: MesOrderStatusConstants.APPROVING,
|
||||
APPROVED: MesOrderStatusConstants.APPROVED,
|
||||
FINISHED: MesOrderStatusConstants.FINISHED,
|
||||
CANCELED: MesOrderStatusConstants.CANCELLED,
|
||||
} as const;
|
||||
|
||||
/** MES 生产退料单状态枚举 */
|
||||
export const MesWmReturnIssueStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
CONFIRMED: MesOrderStatusConstants.CONFIRMED,
|
||||
APPROVING: MesOrderStatusConstants.APPROVING,
|
||||
APPROVED: MesOrderStatusConstants.APPROVED,
|
||||
FINISHED: MesOrderStatusConstants.FINISHED,
|
||||
CANCELED: MesOrderStatusConstants.CANCELLED,
|
||||
} as const;
|
||||
|
||||
/** MES 领料出库单状态枚举 */
|
||||
export const MesWmProductIssueStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
APPROVING: MesOrderStatusConstants.APPROVING,
|
||||
APPROVED: MesOrderStatusConstants.APPROVED,
|
||||
FINISHED: MesOrderStatusConstants.FINISHED,
|
||||
CANCELED: MesOrderStatusConstants.CANCELLED,
|
||||
} as const;
|
||||
|
||||
/** MES 产品入库单状态枚举 */
|
||||
export const MesWmProductReceiptStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
APPROVING: MesOrderStatusConstants.APPROVING,
|
||||
APPROVED: MesOrderStatusConstants.APPROVED,
|
||||
FINISHED: MesOrderStatusConstants.FINISHED,
|
||||
CANCELED: MesOrderStatusConstants.CANCELLED,
|
||||
} as const;
|
||||
|
||||
/** MES 销售出库单状态枚举 */
|
||||
export const MesWmProductSalesStatusEnum = {
|
||||
PREPARE: MesOrderStatusConstants.DRAFT,
|
||||
CONFIRMED: MesOrderStatusConstants.CONFIRMED,
|
||||
APPROVING: MesOrderStatusConstants.APPROVING,
|
||||
SHIPPING: 10, // 待填写运单
|
||||
APPROVED: MesOrderStatusConstants.APPROVED,
|
||||
FINISHED: MesOrderStatusConstants.FINISHED,
|
||||
CANCELED: MesOrderStatusConstants.CANCELLED,
|
||||
} as const;
|
||||
|
||||
/** MES 质检结果值类型枚举 */
|
||||
export const MesQcResultValueType = {
|
||||
FLOAT: 1,
|
||||
|
|
|
|||
|
|
@ -19,9 +19,12 @@ 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 MdWorkshopSelect from '#/views/mes/md/workstation/components/md-workshop-select.vue';
|
||||
import MdWorkstationSelect from '#/views/mes/md/workstation/components/md-workstation-select.vue';
|
||||
import { ProCardSelect } from '#/views/mes/pro/card/components';
|
||||
import ProWorkOrderSelect from '#/views/mes/pro/workorder/components/pro-work-order-select.vue';
|
||||
import TmToolSelect from '#/views/mes/tm/tool/components/tm-tool-select.vue';
|
||||
import { BarcodeBizTypeEnum } from '#/views/mes/utils/constants';
|
||||
import { WmBatchSelect } from '#/views/mes/wm/batch/components';
|
||||
import { UserSelect } from '#/views/system/user/components';
|
||||
|
||||
import WmMaterialStockSelect from './../materialstock/components/wm-material-stock-select.vue';
|
||||
import { WmPackageSelect } from './../packages/components';
|
||||
|
|
@ -51,15 +54,31 @@ async function syncBizDetail(
|
|||
}
|
||||
let bizCode: string | undefined;
|
||||
let bizName: string | undefined;
|
||||
if (bizType === BarcodeBizTypeEnum.STOCK) {
|
||||
bizCode = item.itemCode;
|
||||
bizName = item.itemName;
|
||||
} else if (bizType === BarcodeBizTypeEnum.PACKAGE) {
|
||||
bizCode = item.code;
|
||||
bizName = item.clientName || item.code;
|
||||
} else {
|
||||
bizCode = item.code || item.username;
|
||||
bizName = item.name || item.nickname;
|
||||
switch (bizType) {
|
||||
case BarcodeBizTypeEnum.BATCH: {
|
||||
bizCode = item.code;
|
||||
bizName = item.itemName || item.code;
|
||||
break;
|
||||
}
|
||||
case BarcodeBizTypeEnum.PACKAGE: {
|
||||
bizCode = item.code;
|
||||
bizName = item.clientName || item.code;
|
||||
break;
|
||||
}
|
||||
case BarcodeBizTypeEnum.PROCARD: {
|
||||
bizCode = item.code;
|
||||
bizName = item.workOrderName || item.code;
|
||||
break;
|
||||
}
|
||||
case BarcodeBizTypeEnum.STOCK: {
|
||||
bizCode = item.itemCode;
|
||||
bizName = item.itemName;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
bizCode = item.code || item.username;
|
||||
bizName = item.name || item.nickname;
|
||||
}
|
||||
}
|
||||
// 先回填业务编码、名称并清空旧条码内容
|
||||
await formApi.setValues({ bizCode, bizName, content: undefined });
|
||||
|
|
@ -328,6 +347,45 @@ export function useFormSchema(formApi?: VbenFormApi): VbenFormSchema[] {
|
|||
},
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
fieldName: 'bizId',
|
||||
label: '批次',
|
||||
component: markRaw(WmBatchSelect),
|
||||
componentProps: {
|
||||
onChange: (item: any) => syncBizDetail(formApi, item),
|
||||
},
|
||||
dependencies: {
|
||||
triggerFields: ['bizType'],
|
||||
show: (values) => values.bizType === BarcodeBizTypeEnum.BATCH,
|
||||
},
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
fieldName: 'bizId',
|
||||
label: '流转卡',
|
||||
component: markRaw(ProCardSelect),
|
||||
componentProps: {
|
||||
onChange: (item: any) => syncBizDetail(formApi, item),
|
||||
},
|
||||
dependencies: {
|
||||
triggerFields: ['bizType'],
|
||||
show: (values) => values.bizType === BarcodeBizTypeEnum.PROCARD,
|
||||
},
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
fieldName: 'bizId',
|
||||
label: '人员',
|
||||
component: markRaw(UserSelect),
|
||||
componentProps: {
|
||||
onChange: (item: any) => syncBizDetail(formApi, item),
|
||||
},
|
||||
dependencies: {
|
||||
triggerFields: ['bizType'],
|
||||
show: (values) => values.bizType === BarcodeBizTypeEnum.USER,
|
||||
},
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
fieldName: 'bizId',
|
||||
label: '业务编号',
|
||||
|
|
@ -344,13 +402,16 @@ export function useFormSchema(formApi?: VbenFormApi): VbenFormSchema[] {
|
|||
values.bizType !== undefined &&
|
||||
![
|
||||
BarcodeBizTypeEnum.AREA,
|
||||
BarcodeBizTypeEnum.BATCH,
|
||||
BarcodeBizTypeEnum.CLIENT,
|
||||
BarcodeBizTypeEnum.ITEM,
|
||||
BarcodeBizTypeEnum.LOCATION,
|
||||
BarcodeBizTypeEnum.MACHINERY,
|
||||
BarcodeBizTypeEnum.PACKAGE,
|
||||
BarcodeBizTypeEnum.PROCARD,
|
||||
BarcodeBizTypeEnum.STOCK,
|
||||
BarcodeBizTypeEnum.TOOL,
|
||||
BarcodeBizTypeEnum.USER,
|
||||
BarcodeBizTypeEnum.VENDOR,
|
||||
BarcodeBizTypeEnum.WAREHOUSE,
|
||||
BarcodeBizTypeEnum.WORKORDER,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
export { default as WmBatchSelectDialog } from './wm-batch-select-dialog.vue';
|
||||
export { default as WmBatchSelect } from './wm-batch-select.vue';
|
||||
|
|
@ -0,0 +1,241 @@
|
|||
<script lang="ts" setup>
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { MesWmBatchApi } from '#/api/mes/wm/batch';
|
||||
|
||||
import { computed, nextTick, ref } from 'vue';
|
||||
|
||||
import { ElAlert, ElButton, ElDialog, ElMessage } from 'element-plus';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { getBatchPage } from '#/api/mes/wm/batch';
|
||||
|
||||
import { useBatchSelectGridColumns, useBatchSelectGridFormSchema } from '../data';
|
||||
|
||||
const emit = defineEmits<{
|
||||
selected: [rows: MesWmBatchApi.Batch[]];
|
||||
}>();
|
||||
|
||||
const open = ref(false); // 弹窗是否打开
|
||||
const multiple = ref(false); // 是否多选;默认按单选选择器使用
|
||||
const selectedRows = ref<MesWmBatchApi.Batch[]>([]); // 已选批次列表
|
||||
const preSelectedIds = ref<number[]>([]); // 预选批次编号列表
|
||||
const externalItemId = ref<number>(); // 外部传入的默认物料过滤
|
||||
const externalClientId = ref<number>(); // 外部传入的默认客户过滤
|
||||
const externalVendorId = ref<number>(); // 外部传入的默认供应商过滤
|
||||
const externalSalesOrderCode = ref<string>(); // 外部传入的默认销售订单过滤
|
||||
|
||||
const filterTip = computed(() => {
|
||||
const parts: string[] = [];
|
||||
if (externalClientId.value != null) {
|
||||
parts.push('客户');
|
||||
}
|
||||
if (externalVendorId.value != null) {
|
||||
parts.push('供应商');
|
||||
}
|
||||
if (externalSalesOrderCode.value != null) {
|
||||
parts.push('销售订单');
|
||||
}
|
||||
return parts.length > 0 ? `已按${parts.join('/')}预过滤` : '';
|
||||
});
|
||||
|
||||
/** 获取多选记录,包含 VXE reserve 跨页记录 */
|
||||
function getMultipleSelectedRows() {
|
||||
const selectedMap = new Map<number, MesWmBatchApi.Batch>();
|
||||
const records = [
|
||||
...(gridApi.grid.getCheckboxReserveRecords?.() ?? []),
|
||||
...(gridApi.grid.getCheckboxRecords?.() ?? []),
|
||||
] as MesWmBatchApi.Batch[];
|
||||
records.forEach((row) => {
|
||||
const rowId = row.id;
|
||||
if (rowId !== undefined) {
|
||||
selectedMap.set(rowId, row);
|
||||
}
|
||||
});
|
||||
return [...selectedMap.values()];
|
||||
}
|
||||
|
||||
/** 处理多选勾选变化 */
|
||||
function handleCheckboxSelectChange() {
|
||||
selectedRows.value = getMultipleSelectedRows();
|
||||
}
|
||||
|
||||
/** 处理单选切换 */
|
||||
function handleRadioChange(row: MesWmBatchApi.Batch) {
|
||||
selectedRows.value = [row];
|
||||
}
|
||||
|
||||
/** 多选模式下切换行勾选 */
|
||||
async function toggleMultipleRow(row: MesWmBatchApi.Batch) {
|
||||
const selected = gridApi.grid.isCheckedByCheckboxRow(row);
|
||||
await gridApi.grid.setCheckboxRow(row, !selected);
|
||||
selectedRows.value = getMultipleSelectedRows();
|
||||
}
|
||||
|
||||
/** 处理行双击:单选直接确认,多选切换勾选 */
|
||||
async function handleCellDblclick({ row }: { row: MesWmBatchApi.Batch }) {
|
||||
if (multiple.value) {
|
||||
await toggleMultipleRow(row);
|
||||
return;
|
||||
}
|
||||
selectedRows.value = [row];
|
||||
await gridApi.grid.setRadioRow(row);
|
||||
handleConfirm();
|
||||
}
|
||||
|
||||
/** 回显预选批次 */
|
||||
async function applyPreSelection() {
|
||||
if (preSelectedIds.value.length === 0) {
|
||||
return;
|
||||
}
|
||||
const rows = gridApi.grid.getData() as MesWmBatchApi.Batch[];
|
||||
for (const row of rows) {
|
||||
if (row.id === undefined || !preSelectedIds.value.includes(row.id)) {
|
||||
continue;
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
formOptions: {
|
||||
schema: useBatchSelectGridFormSchema(),
|
||||
},
|
||||
gridOptions: {
|
||||
columns: useBatchSelectGridColumns(false),
|
||||
height: 520,
|
||||
keepSource: true,
|
||||
checkboxConfig: {
|
||||
highlight: true,
|
||||
range: true,
|
||||
reserve: true,
|
||||
},
|
||||
radioConfig: {
|
||||
highlight: true,
|
||||
trigger: 'row',
|
||||
},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }, formValues) => {
|
||||
return await getBatchPage({
|
||||
pageNo: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
...formValues,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
rowConfig: {
|
||||
keyField: 'id',
|
||||
isHover: true,
|
||||
},
|
||||
toolbarConfig: {
|
||||
refresh: true,
|
||||
search: true,
|
||||
},
|
||||
} as VxeTableGridOptions<MesWmBatchApi.Batch>,
|
||||
gridEvents: {
|
||||
cellDblclick: handleCellDblclick,
|
||||
checkboxAll: handleCheckboxSelectChange,
|
||||
checkboxChange: handleCheckboxSelectChange,
|
||||
radioChange: ({ row }: { row: MesWmBatchApi.Batch }) => {
|
||||
handleRadioChange(row);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/** 重置查询和选择状态,保留外部传入的默认过滤 */
|
||||
async function resetQueryState() {
|
||||
selectedRows.value = [];
|
||||
await gridApi.grid.clearCheckboxRow();
|
||||
await gridApi.grid.clearCheckboxReserve();
|
||||
await gridApi.grid.clearRadioRow();
|
||||
await gridApi.formApi.resetForm();
|
||||
if (externalItemId.value) {
|
||||
await gridApi.formApi.setFieldValue('itemId', externalItemId.value);
|
||||
}
|
||||
if (externalClientId.value) {
|
||||
await gridApi.formApi.setFieldValue('clientId', externalClientId.value);
|
||||
}
|
||||
if (externalVendorId.value) {
|
||||
await gridApi.formApi.setFieldValue('vendorId', externalVendorId.value);
|
||||
}
|
||||
if (externalSalesOrderCode.value) {
|
||||
await gridApi.formApi.setFieldValue(
|
||||
'salesOrderCode',
|
||||
externalSalesOrderCode.value,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/** 打开批次选择弹窗 */
|
||||
async function openModal(
|
||||
selectedIds?: number[],
|
||||
options?: {
|
||||
clientId?: number;
|
||||
itemId?: number;
|
||||
multiple?: boolean;
|
||||
salesOrderCode?: string;
|
||||
vendorId?: number;
|
||||
},
|
||||
) {
|
||||
open.value = true;
|
||||
multiple.value = options?.multiple ?? false;
|
||||
preSelectedIds.value = selectedIds || [];
|
||||
externalItemId.value = options?.itemId;
|
||||
externalClientId.value = options?.clientId;
|
||||
externalVendorId.value = options?.vendorId;
|
||||
externalSalesOrderCode.value = options?.salesOrderCode;
|
||||
await nextTick();
|
||||
gridApi.setGridOptions({
|
||||
columns: useBatchSelectGridColumns(multiple.value),
|
||||
});
|
||||
await resetQueryState();
|
||||
await gridApi.query();
|
||||
await nextTick();
|
||||
await applyPreSelection();
|
||||
}
|
||||
|
||||
/** 关闭批次选择弹窗 */
|
||||
function closeModal() {
|
||||
open.value = false;
|
||||
}
|
||||
|
||||
/** 确认选择批次 */
|
||||
function handleConfirm() {
|
||||
const rows = multiple.value ? getMultipleSelectedRows() : selectedRows.value;
|
||||
if (rows.length === 0) {
|
||||
ElMessage.warning(multiple.value ? '请至少选择一条数据' : '请选择一条数据');
|
||||
return;
|
||||
}
|
||||
emit('selected', multiple.value ? rows : [rows[0]!]);
|
||||
open.value = false;
|
||||
}
|
||||
|
||||
defineExpose({ open: openModal });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ElDialog v-model="open" title="批次选择" width="80%">
|
||||
<ElAlert
|
||||
v-if="filterTip"
|
||||
:closable="false"
|
||||
class="!mb-3"
|
||||
:title="filterTip"
|
||||
type="info"
|
||||
/>
|
||||
<Grid table-title="批次列表" />
|
||||
<template #footer>
|
||||
<ElButton @click="closeModal">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleConfirm">确定</ElButton>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
<script lang="ts" setup>
|
||||
import type { MesWmBatchApi } from '#/api/mes/wm/batch';
|
||||
|
||||
import { computed, ref, useAttrs, watch } from 'vue';
|
||||
|
||||
import { CircleX, Search } from '@vben/icons';
|
||||
|
||||
import { ElInput, ElTooltip } from 'element-plus';
|
||||
|
||||
import { getBatch } from '#/api/mes/wm/batch';
|
||||
|
||||
import WmBatchSelectDialog from './wm-batch-select-dialog.vue';
|
||||
|
||||
defineOptions({ name: 'WmBatchSelect', inheritAttrs: false });
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
clearable?: boolean;
|
||||
clientId?: number; // 默认过滤的客户 ID
|
||||
disabled?: boolean;
|
||||
itemId?: number; // 默认过滤的物料 ID
|
||||
modelValue?: number;
|
||||
placeholder?: string;
|
||||
salesOrderCode?: string; // 默认过滤的销售订单编号
|
||||
vendorId?: number; // 默认过滤的供应商 ID
|
||||
}>(),
|
||||
{
|
||||
clearable: true,
|
||||
clientId: undefined,
|
||||
disabled: false,
|
||||
itemId: undefined,
|
||||
modelValue: undefined,
|
||||
placeholder: '请选择批次',
|
||||
salesOrderCode: undefined,
|
||||
vendorId: undefined,
|
||||
},
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
change: [item: MesWmBatchApi.Batch | undefined];
|
||||
'update:modelValue': [value: number | undefined];
|
||||
}>();
|
||||
|
||||
const attrs = useAttrs();
|
||||
const dialogRef = ref<InstanceType<typeof WmBatchSelectDialog>>();
|
||||
const hovering = ref(false);
|
||||
const selectedItem = ref<MesWmBatchApi.Batch>();
|
||||
|
||||
const displayLabel = computed(() => selectedItem.value?.code ?? '');
|
||||
|
||||
const showClear = computed(
|
||||
() =>
|
||||
props.clearable &&
|
||||
!props.disabled &&
|
||||
hovering.value &&
|
||||
props.modelValue != null,
|
||||
);
|
||||
|
||||
/** 根据编号单条查询批次信息(用于编辑回显) */
|
||||
async function resolveItemById(id: number | undefined) {
|
||||
if (id == null) {
|
||||
selectedItem.value = undefined;
|
||||
return;
|
||||
}
|
||||
if (selectedItem.value?.id === id) {
|
||||
return;
|
||||
}
|
||||
selectedItem.value = await getBatch(id);
|
||||
}
|
||||
|
||||
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('.el-input__suffix')) {
|
||||
event.stopPropagation();
|
||||
clearSelected();
|
||||
return;
|
||||
}
|
||||
const selectedIds = props.modelValue == null ? [] : [props.modelValue];
|
||||
dialogRef.value?.open(selectedIds, {
|
||||
clientId: props.clientId,
|
||||
itemId: props.itemId,
|
||||
multiple: false,
|
||||
salesOrderCode: props.salesOrderCode,
|
||||
vendorId: props.vendorId,
|
||||
});
|
||||
}
|
||||
|
||||
/** 弹窗选中回调 */
|
||||
function handleSelected(rows: MesWmBatchApi.Batch[]) {
|
||||
const item = rows[0];
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
selectedItem.value = item;
|
||||
emit('update:modelValue', item.id);
|
||||
emit('change', item);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-bind="attrs"
|
||||
class="w-full"
|
||||
:class="disabled ? 'cursor-not-allowed' : 'cursor-pointer'"
|
||||
@click="handleClick"
|
||||
@mouseenter="hovering = true"
|
||||
@mouseleave="hovering = false"
|
||||
>
|
||||
<ElTooltip :disabled="!selectedItem" placement="top" :show-after="500">
|
||||
<template #content>
|
||||
<div v-if="selectedItem" class="leading-6">
|
||||
<div>批次编号:{{ selectedItem.code || '-' }}</div>
|
||||
<div>物料编码:{{ selectedItem.itemCode || '-' }}</div>
|
||||
<div>物料名称:{{ selectedItem.itemName || '-' }}</div>
|
||||
<div>生产批号:{{ selectedItem.lotNumber || '-' }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<ElInput
|
||||
:disabled="disabled"
|
||||
:model-value="displayLabel"
|
||||
:placeholder="placeholder"
|
||||
readonly
|
||||
>
|
||||
<template #suffix>
|
||||
<CircleX v-if="showClear" class="size-4" />
|
||||
<Search v-else class="size-4" />
|
||||
</template>
|
||||
</ElInput>
|
||||
</ElTooltip>
|
||||
</div>
|
||||
<WmBatchSelectDialog ref="dialogRef" @selected="handleSelected" />
|
||||
</template>
|
||||
|
|
@ -1 +1,2 @@
|
|||
export { default as DeptSelectModal } from './select-modal.vue';
|
||||
export { default as DeptTreeSelect } from './tree-select.vue';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script lang="ts" setup>
|
||||
// TODO @jason:看看这个有没办法,整体代码的文件顺序,注释风格等,和 /Users/yunai/Java/yudao-ui-admin-vben-v5/apps/web-antd/src/views/system/dept/components/select-modal.vue 一致。原因是:好维护~
|
||||
import type { SystemDeptApi } from '#/api/system/dept';
|
||||
|
||||
import { nextTick, ref } from 'vue';
|
||||
|
|
@ -15,16 +14,11 @@ defineOptions({ name: 'DeptSelectModal' });
|
|||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
// 取消按钮文本
|
||||
cancelText?: string;
|
||||
// checkable 状态下节点选择完全受控
|
||||
checkStrictly?: boolean;
|
||||
// 确认按钮文本
|
||||
confirmText?: string;
|
||||
// 是否支持多选
|
||||
multiple?: boolean;
|
||||
// 标题
|
||||
title?: string;
|
||||
cancelText?: string; // 取消按钮文本
|
||||
checkStrictly?: boolean; // checkable 状态下节点选择完全受控
|
||||
confirmText?: string; // 确认按钮文本
|
||||
multiple?: boolean; // 是否支持多选
|
||||
title?: string; // 标题
|
||||
}>(),
|
||||
{
|
||||
cancelText: '取消',
|
||||
|
|
@ -39,16 +33,11 @@ const emit = defineEmits<{
|
|||
confirm: [deptList: SystemDeptApi.Dept[]];
|
||||
}>();
|
||||
|
||||
// 部门树形结构
|
||||
const deptTree = ref<any[]>([]);
|
||||
// 选中的部门 ID 列表
|
||||
const selectedDeptIds = ref<number[]>([]);
|
||||
// 部门数据
|
||||
const deptData = ref<SystemDeptApi.Dept[]>([]);
|
||||
// Tree 组件引用
|
||||
const treeRef = ref();
|
||||
const deptTree = ref<any[]>([]); // 部门树形结构
|
||||
const selectedDeptIds = ref<number[]>([]); // 选中的部门 ID 列表
|
||||
const deptData = ref<SystemDeptApi.Dept[]>([]); // 部门数据
|
||||
const treeRef = ref(); // Tree 组件引用
|
||||
|
||||
// 对话框配置
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
async onConfirm() {
|
||||
// 获取选中的部门ID
|
||||
|
|
|
|||
|
|
@ -10,12 +10,18 @@ import { ElInput, ElTree } from 'element-plus';
|
|||
|
||||
import { getSimpleDeptList } from '#/api/system/dept';
|
||||
|
||||
const emit = defineEmits(['select']);
|
||||
defineOptions({ name: 'DeptTreeSelect' });
|
||||
|
||||
const emit = defineEmits<{
|
||||
select: [dept?: SystemDeptApi.Dept];
|
||||
}>();
|
||||
|
||||
const deptList = ref<SystemDeptApi.Dept[]>([]); // 部门列表
|
||||
const deptTree = ref<any[]>([]); // 部门树
|
||||
const expandedKeys = ref<number[]>([]); // 展开的节点
|
||||
const loading = ref(false); // 加载状态
|
||||
const searchValue = ref(''); // 搜索值
|
||||
const treeRef = ref<InstanceType<typeof ElTree>>(); // 树 Ref
|
||||
let currentNodeId: number | undefined; // 当前选中的节点 ID
|
||||
|
||||
/** 处理搜索逻辑 */
|
||||
function handleSearch(value: string) {
|
||||
|
|
@ -26,15 +32,31 @@ function handleSearch(value: string) {
|
|||
)
|
||||
: deptList.value;
|
||||
deptTree.value = handleTree(filteredList);
|
||||
// 展开所有节点
|
||||
expandedKeys.value = deptTree.value.map((node) => node.id!);
|
||||
}
|
||||
|
||||
/** 选中部门 */
|
||||
function handleSelect(data: any) {
|
||||
/** 选中部门:点击已选中的节点时取消选中 */
|
||||
function handleSelect(data: SystemDeptApi.Dept) {
|
||||
if (currentNodeId === data.id) {
|
||||
currentNodeId = undefined;
|
||||
treeRef.value?.setCurrentKey(undefined);
|
||||
emit('select', undefined);
|
||||
return;
|
||||
}
|
||||
currentNodeId = data.id;
|
||||
emit('select', data);
|
||||
}
|
||||
|
||||
/** 重置选中状态(供外部重置按钮调用) */
|
||||
function reset() {
|
||||
searchValue.value = '';
|
||||
currentNodeId = undefined;
|
||||
treeRef.value?.setCurrentKey(undefined);
|
||||
deptTree.value = handleTree(deptList.value);
|
||||
emit('select', undefined);
|
||||
}
|
||||
|
||||
defineExpose({ reset });
|
||||
|
||||
/** 初始化 */
|
||||
onMounted(async () => {
|
||||
try {
|
||||
|
|
@ -42,8 +64,6 @@ onMounted(async () => {
|
|||
const data = await getSimpleDeptList();
|
||||
deptList.value = data;
|
||||
deptTree.value = handleTree(data);
|
||||
} catch (error) {
|
||||
console.error('获取部门数据失败', error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
|
|
@ -53,11 +73,11 @@ onMounted(async () => {
|
|||
<template>
|
||||
<div>
|
||||
<ElInput
|
||||
placeholder="搜索部门"
|
||||
clearable
|
||||
v-model="searchValue"
|
||||
@input="handleSearch"
|
||||
class="w-full"
|
||||
clearable
|
||||
placeholder="搜索部门"
|
||||
@input="handleSearch"
|
||||
>
|
||||
<template #prefix>
|
||||
<Search class="size-4" />
|
||||
|
|
@ -65,13 +85,15 @@ onMounted(async () => {
|
|||
</ElInput>
|
||||
<div v-loading="loading">
|
||||
<ElTree
|
||||
class="pt-2"
|
||||
v-if="deptTree.length > 0"
|
||||
ref="treeRef"
|
||||
class="pt-2"
|
||||
:data="deptTree"
|
||||
default-expand-all
|
||||
highlight-current
|
||||
node-key="id"
|
||||
:props="{ label: 'name', children: 'children' }"
|
||||
@node-click="handleSelect"
|
||||
default-expand-all
|
||||
node-key="id"
|
||||
/>
|
||||
<div v-else-if="!loading" class="py-4 text-center text-gray-500">
|
||||
暂无数据
|
||||
|
|
@ -1 +1,3 @@
|
|||
export { default as UserSelectDialog } from './select-dialog.vue';
|
||||
export { default as UserSelectModal } from './select-modal.vue';
|
||||
export { default as UserSelect } from './select.vue';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,298 @@
|
|||
<script lang="ts" setup>
|
||||
import type { VbenFormSchema } from '#/adapter/form';
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { SystemDeptApi } from '#/api/system/dept';
|
||||
import type { SystemUserApi } from '#/api/system/user';
|
||||
|
||||
import { nextTick, ref } from 'vue';
|
||||
|
||||
import { CommonStatusEnum, DICT_TYPE } from '@vben/constants';
|
||||
import { getDictOptions } from '@vben/hooks';
|
||||
|
||||
import { ElButton, ElCol, ElDialog, ElMessage, ElRow } from 'element-plus';
|
||||
|
||||
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { getUserPage } from '#/api/system/user';
|
||||
import { DeptTreeSelect } from '#/views/system/dept/components';
|
||||
|
||||
const emit = defineEmits<{
|
||||
selected: [rows: SystemUserApi.User[]];
|
||||
}>();
|
||||
|
||||
const open = ref(false); // 弹窗是否打开
|
||||
const multiple = ref(false); // 是否多选;默认按单选选择器使用
|
||||
const selectedRows = ref<SystemUserApi.User[]>([]); // 已选用户列表
|
||||
const preSelectedIds = ref<number[]>([]); // 预选用户编号列表
|
||||
const deptId = ref<number>(); // 当前部门过滤
|
||||
const deptTreeRef = ref<InstanceType<typeof DeptTreeSelect>>(); // 部门树
|
||||
|
||||
/** 用户选择弹窗的搜索表单 */
|
||||
function useUserSelectGridFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
{
|
||||
fieldName: 'username',
|
||||
label: '用户名称',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
clearable: true,
|
||||
placeholder: '请输入用户名称',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'nickname',
|
||||
label: '用户昵称',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
clearable: true,
|
||||
placeholder: '请输入用户昵称',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'mobile',
|
||||
label: '手机号码',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
clearable: true,
|
||||
placeholder: '请输入手机号码',
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'status',
|
||||
label: '状态',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
clearable: true,
|
||||
options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'),
|
||||
placeholder: '请选择状态',
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 用户选择弹窗的字段 */
|
||||
function useUserSelectGridColumns(
|
||||
isMultiple = false,
|
||||
): VxeTableGridOptions<SystemUserApi.User>['columns'] {
|
||||
return [
|
||||
{
|
||||
type: isMultiple ? 'checkbox' : 'radio',
|
||||
width: 50,
|
||||
},
|
||||
{
|
||||
field: 'id',
|
||||
title: '用户编号',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
field: 'username',
|
||||
title: '用户名称',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
field: 'nickname',
|
||||
title: '用户昵称',
|
||||
minWidth: 150,
|
||||
},
|
||||
{
|
||||
field: 'mobile',
|
||||
title: '手机号码',
|
||||
width: 130,
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
title: '状态',
|
||||
width: 90,
|
||||
cellRender: {
|
||||
name: 'CellDict',
|
||||
props: { type: DICT_TYPE.COMMON_STATUS },
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 获取多选记录,包含 VXE reserve 跨页记录 */
|
||||
function getMultipleSelectedRows() {
|
||||
const selectedMap = new Map<number, SystemUserApi.User>();
|
||||
const records = [
|
||||
...(gridApi.grid.getCheckboxReserveRecords?.() ?? []),
|
||||
...(gridApi.grid.getCheckboxRecords?.() ?? []),
|
||||
] as SystemUserApi.User[];
|
||||
records.forEach((row) => {
|
||||
const rowId = row.id;
|
||||
if (rowId !== undefined) {
|
||||
selectedMap.set(rowId, row);
|
||||
}
|
||||
});
|
||||
return [...selectedMap.values()];
|
||||
}
|
||||
|
||||
/** 处理多选勾选变化 */
|
||||
function handleCheckboxSelectChange() {
|
||||
selectedRows.value = getMultipleSelectedRows();
|
||||
}
|
||||
|
||||
/** 处理单选切换 */
|
||||
function handleRadioChange(row: SystemUserApi.User) {
|
||||
selectedRows.value = [row];
|
||||
}
|
||||
|
||||
/** 多选模式下切换行勾选 */
|
||||
async function toggleMultipleRow(row: SystemUserApi.User) {
|
||||
const selected = gridApi.grid.isCheckedByCheckboxRow(row);
|
||||
await gridApi.grid.setCheckboxRow(row, !selected);
|
||||
selectedRows.value = getMultipleSelectedRows();
|
||||
}
|
||||
|
||||
/** 处理行双击:单选直接确认,多选切换勾选 */
|
||||
async function handleCellDblclick({ row }: { row: SystemUserApi.User }) {
|
||||
if (multiple.value) {
|
||||
await toggleMultipleRow(row);
|
||||
return;
|
||||
}
|
||||
selectedRows.value = [row];
|
||||
await gridApi.grid.setRadioRow(row);
|
||||
handleConfirm();
|
||||
}
|
||||
|
||||
/** 回显预选用户 */
|
||||
async function applyPreSelection() {
|
||||
if (preSelectedIds.value.length === 0) {
|
||||
return;
|
||||
}
|
||||
const rows = gridApi.grid.getData() as SystemUserApi.User[];
|
||||
for (const row of rows) {
|
||||
if (row.id === undefined || !preSelectedIds.value.includes(row.id)) {
|
||||
continue;
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
formOptions: {
|
||||
schema: useUserSelectGridFormSchema(),
|
||||
},
|
||||
gridOptions: {
|
||||
columns: useUserSelectGridColumns(false),
|
||||
height: 520,
|
||||
keepSource: true,
|
||||
checkboxConfig: {
|
||||
highlight: true,
|
||||
range: true,
|
||||
reserve: true,
|
||||
},
|
||||
radioConfig: {
|
||||
highlight: true,
|
||||
trigger: 'row',
|
||||
},
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
query: async ({ page }, formValues) => {
|
||||
return await getUserPage({
|
||||
pageNo: page.currentPage,
|
||||
pageSize: page.pageSize,
|
||||
deptId: deptId.value,
|
||||
...formValues,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
rowConfig: {
|
||||
keyField: 'id',
|
||||
isHover: true,
|
||||
},
|
||||
toolbarConfig: {
|
||||
refresh: true,
|
||||
search: true,
|
||||
},
|
||||
} as VxeTableGridOptions<SystemUserApi.User>,
|
||||
gridEvents: {
|
||||
cellDblclick: handleCellDblclick,
|
||||
checkboxAll: handleCheckboxSelectChange,
|
||||
checkboxChange: handleCheckboxSelectChange,
|
||||
radioChange: ({ row }: { row: SystemUserApi.User }) => {
|
||||
handleRadioChange(row);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/** 部门树节点点击 */
|
||||
function handleDeptNodeClick(dept?: SystemDeptApi.Dept) {
|
||||
deptId.value = dept?.id;
|
||||
gridApi.query();
|
||||
}
|
||||
|
||||
/** 重置查询和选择状态 */
|
||||
async function resetQueryState() {
|
||||
selectedRows.value = [];
|
||||
deptId.value = undefined;
|
||||
await gridApi.grid.clearCheckboxRow();
|
||||
await gridApi.grid.clearCheckboxReserve();
|
||||
await gridApi.grid.clearRadioRow();
|
||||
await gridApi.formApi.resetForm();
|
||||
deptTreeRef.value?.reset();
|
||||
}
|
||||
|
||||
/** 打开用户选择弹窗 */
|
||||
async function openModal(
|
||||
selectedIds?: number[],
|
||||
options?: { multiple?: boolean },
|
||||
) {
|
||||
open.value = true;
|
||||
multiple.value = options?.multiple ?? false;
|
||||
preSelectedIds.value = selectedIds || [];
|
||||
await nextTick();
|
||||
gridApi.setGridOptions({
|
||||
columns: useUserSelectGridColumns(multiple.value),
|
||||
});
|
||||
await resetQueryState();
|
||||
await gridApi.formApi.setFieldValue('status', CommonStatusEnum.ENABLE);
|
||||
await gridApi.query();
|
||||
await nextTick();
|
||||
await applyPreSelection();
|
||||
}
|
||||
|
||||
/** 关闭用户选择弹窗 */
|
||||
function closeModal() {
|
||||
open.value = false;
|
||||
}
|
||||
|
||||
/** 确认选择用户 */
|
||||
function handleConfirm() {
|
||||
const rows = multiple.value ? getMultipleSelectedRows() : selectedRows.value;
|
||||
if (rows.length === 0) {
|
||||
ElMessage.warning(multiple.value ? '请至少选择一条数据' : '请选择一条数据');
|
||||
return;
|
||||
}
|
||||
emit('selected', multiple.value ? rows : [rows[0]!]);
|
||||
open.value = false;
|
||||
}
|
||||
|
||||
defineExpose({ open: openModal });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ElDialog v-model="open" title="人员选择" width="80%">
|
||||
<ElRow :gutter="12">
|
||||
<ElCol :span="5">
|
||||
<DeptTreeSelect ref="deptTreeRef" @select="handleDeptNodeClick" />
|
||||
</ElCol>
|
||||
<ElCol :span="19">
|
||||
<Grid table-title="用户列表" />
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<template #footer>
|
||||
<ElButton @click="closeModal">取消</ElButton>
|
||||
<ElButton type="primary" @click="handleConfirm">确定</ElButton>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</template>
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
<script lang="ts" setup>
|
||||
// TODO @jason:看看这个有没办法,整体代码的文件顺序,注释风格等,和 /Users/yunai/Java/yudao-ui-admin-vben-v5/apps/web-antd/src/views/system/user/components/select-modal.vue 一致。原因是:好维护~
|
||||
import type { SystemDeptApi } from '#/api/system/dept';
|
||||
import type { SystemUserApi } from '#/api/system/user';
|
||||
|
||||
|
|
@ -22,7 +21,7 @@ import {
|
|||
import { getSimpleDeptList } from '#/api/system/dept';
|
||||
import { getUserPage } from '#/api/system/user';
|
||||
|
||||
// 部门树节点接口
|
||||
/** 部门树节点接口 */
|
||||
interface DeptTreeNode {
|
||||
id: string;
|
||||
label: string;
|
||||
|
|
@ -67,7 +66,6 @@ const deptSearchKeys = ref('');
|
|||
const userList = ref<SystemUserApi.User[]>([]); // 存储所有已知用户
|
||||
const selectedUserIds = ref<number[]>([]);
|
||||
|
||||
// 弹窗配置
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
onCancel: handleCancel,
|
||||
onClosed: handleClosed,
|
||||
|
|
@ -143,7 +141,7 @@ const rightListState = ref({
|
|||
},
|
||||
});
|
||||
|
||||
// 计算属性:Transfer 数据源
|
||||
/** 计算属性:Transfer 数据源 */
|
||||
const transferDataSource = computed(() => {
|
||||
// 使用 Map 来去重,确保每个用户只出现一次
|
||||
const userMap = new Map<number, any>();
|
||||
|
|
@ -170,7 +168,7 @@ const transferDataSource = computed(() => {
|
|||
}));
|
||||
});
|
||||
|
||||
// 过滤部门树数据
|
||||
/** 过滤部门树数据 */
|
||||
const filteredDeptTree = computed(() => {
|
||||
if (!deptSearchKeys.value) return deptTree.value;
|
||||
|
||||
|
|
@ -210,7 +208,7 @@ const filteredDeptTree = computed(() => {
|
|||
return deptTree.value.map((node: any) => filterNode(node)).filter(Boolean);
|
||||
});
|
||||
|
||||
// 加载用户数据
|
||||
/** 加载用户数据 */
|
||||
async function loadUserData(pageNo: number, pageSize: number) {
|
||||
try {
|
||||
const { list, total } = await getUserPage({
|
||||
|
|
@ -237,7 +235,7 @@ async function loadUserData(pageNo: number, pageSize: number) {
|
|||
}
|
||||
}
|
||||
|
||||
// 更新右侧列表数据
|
||||
/** 更新右侧列表数据 */
|
||||
function updateRightListData() {
|
||||
// 使用 Set 来去重选中的用户ID
|
||||
const uniqueSelectedIds = new Set(selectedUserIds.value);
|
||||
|
|
@ -269,18 +267,18 @@ function updateRightListData() {
|
|||
rightListState.value.dataSource = filteredUsers.slice(startIndex, endIndex);
|
||||
}
|
||||
|
||||
// 处理左侧分页变化
|
||||
/** 处理左侧分页变化 */
|
||||
async function handleLeftPaginationChange(page: number) {
|
||||
await loadUserData(page, leftListState.value.pagination.pageSize);
|
||||
}
|
||||
|
||||
// 处理右侧分页变化
|
||||
/** 处理右侧分页变化 */
|
||||
function handleRightPaginationChange(page: number) {
|
||||
rightListState.value.pagination.current = page;
|
||||
updateRightListData();
|
||||
}
|
||||
|
||||
// 处理用户选择变化
|
||||
/** 处理用户选择变化 */
|
||||
function handleUserChange(
|
||||
value: (number | string)[],
|
||||
_direction: string,
|
||||
|
|
@ -292,7 +290,7 @@ function handleUserChange(
|
|||
updateRightListData();
|
||||
}
|
||||
|
||||
// 重置数据
|
||||
/** 重置数据 */
|
||||
function resetData() {
|
||||
userList.value = [];
|
||||
selectedUserIds.value = [];
|
||||
|
|
@ -324,7 +322,7 @@ function resetData() {
|
|||
};
|
||||
}
|
||||
|
||||
// 处理部门搜索
|
||||
/** 处理部门搜索 */
|
||||
function handleDeptSearch(value: string) {
|
||||
deptSearchKeys.value = value;
|
||||
|
||||
|
|
@ -347,7 +345,7 @@ function handleDeptSearch(value: string) {
|
|||
}
|
||||
}
|
||||
|
||||
// 处理部门选择
|
||||
/** 处理部门选择 */
|
||||
async function handleDeptSelect(node: any) {
|
||||
// 更新选中的部门ID
|
||||
const newDeptId = node.id ? Number(node.id) : undefined;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,132 @@
|
|||
<script lang="ts" setup>
|
||||
import type { SystemUserApi } from '#/api/system/user';
|
||||
|
||||
import { computed, ref, useAttrs, watch } from 'vue';
|
||||
|
||||
import { CircleX, Search } from '@vben/icons';
|
||||
|
||||
import { ElInput, ElTooltip } from 'element-plus';
|
||||
|
||||
import { getUser } from '#/api/system/user';
|
||||
|
||||
import UserSelectDialog from './select-dialog.vue';
|
||||
|
||||
defineOptions({ name: 'UserSelect', inheritAttrs: false });
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
clearable?: boolean;
|
||||
disabled?: boolean;
|
||||
modelValue?: number;
|
||||
placeholder?: string;
|
||||
}>(),
|
||||
{
|
||||
clearable: true,
|
||||
disabled: false,
|
||||
modelValue: undefined,
|
||||
placeholder: '请选择用户',
|
||||
},
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
change: [item: SystemUserApi.User | undefined];
|
||||
'update:modelValue': [value: number | undefined];
|
||||
}>();
|
||||
|
||||
const attrs = useAttrs();
|
||||
const dialogRef = ref<InstanceType<typeof UserSelectDialog>>();
|
||||
const hovering = ref(false);
|
||||
const selectedItem = ref<SystemUserApi.User>();
|
||||
|
||||
const displayLabel = computed(
|
||||
() => selectedItem.value?.nickname ?? selectedItem.value?.username ?? '',
|
||||
);
|
||||
|
||||
const showClear = computed(
|
||||
() =>
|
||||
props.clearable &&
|
||||
!props.disabled &&
|
||||
hovering.value &&
|
||||
props.modelValue != null,
|
||||
);
|
||||
|
||||
/** 根据编号单条查询用户信息(用于编辑回显) */
|
||||
async function resolveItemById(id: number | undefined) {
|
||||
if (id == null) {
|
||||
selectedItem.value = undefined;
|
||||
return;
|
||||
}
|
||||
if (selectedItem.value?.id === id) {
|
||||
return;
|
||||
}
|
||||
selectedItem.value = await getUser(id);
|
||||
}
|
||||
|
||||
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('.el-input__suffix')) {
|
||||
event.stopPropagation();
|
||||
clearSelected();
|
||||
return;
|
||||
}
|
||||
const selectedIds = props.modelValue == null ? [] : [props.modelValue];
|
||||
dialogRef.value?.open(selectedIds, { multiple: false });
|
||||
}
|
||||
|
||||
/** 弹窗选中回调 */
|
||||
function handleSelected(rows: SystemUserApi.User[]) {
|
||||
const item = rows[0];
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
selectedItem.value = item;
|
||||
emit('update:modelValue', item.id);
|
||||
emit('change', item);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-bind="attrs"
|
||||
class="w-full"
|
||||
:class="disabled ? 'cursor-not-allowed' : 'cursor-pointer'"
|
||||
@click="handleClick"
|
||||
@mouseenter="hovering = true"
|
||||
@mouseleave="hovering = false"
|
||||
>
|
||||
<ElTooltip :disabled="!selectedItem" placement="top" :show-after="500">
|
||||
<template #content>
|
||||
<div v-if="selectedItem" class="leading-6">
|
||||
<div>用户名称:{{ selectedItem.username || '-' }}</div>
|
||||
<div>用户昵称:{{ selectedItem.nickname || '-' }}</div>
|
||||
<div>手机号码:{{ selectedItem.mobile || '-' }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<ElInput
|
||||
:disabled="disabled"
|
||||
:model-value="displayLabel"
|
||||
:placeholder="placeholder"
|
||||
readonly
|
||||
>
|
||||
<template #suffix>
|
||||
<CircleX v-if="showClear" class="size-4" />
|
||||
<Search v-else class="size-4" />
|
||||
</template>
|
||||
</ElInput>
|
||||
</ElTooltip>
|
||||
</div>
|
||||
<UserSelectDialog ref="dialogRef" @selected="handleSelected" />
|
||||
</template>
|
||||
|
|
@ -21,10 +21,10 @@ import {
|
|||
updateUserStatus,
|
||||
} from '#/api/system/user';
|
||||
import { $t } from '#/locales';
|
||||
import { DeptTreeSelect } from '#/views/system/dept/components';
|
||||
|
||||
import { useGridColumns, useGridFormSchema } from './data';
|
||||
import AssignRoleForm from './modules/assign-role-form.vue';
|
||||
import DeptTree from './modules/dept-tree.vue';
|
||||
import Form from './modules/form.vue';
|
||||
import ImportForm from './modules/import-form.vue';
|
||||
import ResetPasswordForm from './modules/reset-password-form.vue';
|
||||
|
|
@ -62,8 +62,8 @@ async function handleExport() {
|
|||
|
||||
/** 选择部门 */
|
||||
const searchDeptId = ref<number | undefined>(undefined);
|
||||
async function handleDeptSelect(dept: SystemDeptApi.Dept) {
|
||||
searchDeptId.value = dept.id;
|
||||
async function handleDeptSelect(dept?: SystemDeptApi.Dept) {
|
||||
searchDeptId.value = dept?.id;
|
||||
handleRefresh();
|
||||
}
|
||||
|
||||
|
|
@ -203,7 +203,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||
<div class="flex h-full w-full">
|
||||
<!-- 左侧部门树 -->
|
||||
<ElCard class="mr-4 h-full w-1/6">
|
||||
<DeptTree @select="handleDeptSelect" />
|
||||
<DeptTreeSelect @select="handleDeptSelect" />
|
||||
</ElCard>
|
||||
<!-- 右侧用户列表 -->
|
||||
<div class="w-5/6">
|
||||
|
|
|
|||
|
|
@ -232,6 +232,19 @@ const MES_DICT = {
|
|||
MES_WM_MISC_RECEIPT_STATUS: 'mes_wm_misc_receipt_status', // MES 杂项入库单状态
|
||||
MES_WM_OUTSOURCE_ISSUE_STATUS: 'mes_wm_outsource_issue_status', // MES 外协发料单状态
|
||||
MES_WM_OUTSOURCE_RECEIPT_STATUS: 'mes_wm_outsource_receipt_status', // MES 外协入库单状态
|
||||
MES_WM_ARRIVAL_NOTICE_STATUS: 'mes_wm_arrival_notice_status', // MES 到货通知单状态
|
||||
MES_WM_ITEM_RECEIPT_STATUS: 'mes_wm_item_receipt_status', // MES 采购入库单状态
|
||||
MES_WM_RETURN_VENDOR_STATUS: 'mes_wm_return_vendor_status', // MES 供应商退货单状态
|
||||
MES_WM_SALES_NOTICE_STATUS: 'mes_wm_sales_notice_status', // MES 发货通知单状态
|
||||
MES_WM_RETURN_SALES_STATUS: 'mes_wm_return_sales_status', // MES 销售退货单状态
|
||||
MES_WM_RETURN_ISSUE_STATUS: 'mes_wm_return_issue_status', // MES 生产退料单状态
|
||||
MES_WM_RETURN_ISSUE_TYPE: 'mes_wm_return_issue_type', // MES 退料类型
|
||||
MES_WM_PRODUCT_ISSUE_STATUS: 'mes_wm_product_issue_status', // MES 领料出库单状态
|
||||
MES_WM_PRODUCT_RECEIPT_STATUS: 'mes_wm_product_receipt_status', // MES 产品入库单状态
|
||||
MES_WM_STOCK_TAKING_TYPE: 'mes_wm_stock_taking_type', // MES 盘点类型
|
||||
MES_WM_STOCK_TAKING_TASK_STATUS: 'mes_wm_stock_taking_task_status', // MES 盘点任务状态
|
||||
MES_WM_STOCK_TAKING_LINE_STATUS: 'mes_wm_stock_taking_task_line_status', // MES 盘点任务行状态
|
||||
MES_WM_STOCK_TAKING_PLAN_PARAM_TYPE: 'mes_wm_stock_taking_plan_param_type', // MES 盘点方案参数类型
|
||||
} as const;
|
||||
|
||||
/** ========== WMS - 仓储管理模块 ========== */
|
||||
|
|
|
|||
Loading…
Reference in New Issue