diff --git a/apps/web-antd/src/api/mes/pro/andon/config/index.ts b/apps/web-antd/src/api/mes/pro/andon/config/index.ts new file mode 100644 index 000000000..9309a0c8c --- /dev/null +++ b/apps/web-antd/src/api/mes/pro/andon/config/index.ts @@ -0,0 +1,54 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MesProAndonConfigApi { + /** MES 安灯配置 */ + export interface AndonConfig { + id?: number; // 编号 + reason?: string; // 呼叫原因 + level?: number; // 级别 + handlerRoleId?: number; // 处置角色编号 + handlerRoleName?: string; // 处置角色名称 + handlerUserId?: number; // 处置人编号 + handlerUserNickname?: string; // 处置人昵称 + remark?: string; // 备注 + } +} + +/** 查询安灯配置分页 */ +export function getAndonConfigPage(params: PageParam) { + return requestClient.get>( + '/mes/pro/andon-config/page', + { params }, + ); +} + +/** 查询安灯配置列表 */ +export function getAndonConfigList() { + return requestClient.get( + '/mes/pro/andon-config/list', + ); +} + +/** 查询安灯配置详情 */ +export function getAndonConfig(id: number) { + return requestClient.get( + `/mes/pro/andon-config/get?id=${id}`, + ); +} + +/** 新增安灯配置 */ +export function createAndonConfig(data: MesProAndonConfigApi.AndonConfig) { + return requestClient.post('/mes/pro/andon-config/create', data); +} + +/** 修改安灯配置 */ +export function updateAndonConfig(data: MesProAndonConfigApi.AndonConfig) { + return requestClient.put('/mes/pro/andon-config/update', data); +} + +/** 删除安灯配置 */ +export function deleteAndonConfig(id: number) { + return requestClient.delete(`/mes/pro/andon-config/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/mes/pro/andon/record/index.ts b/apps/web-antd/src/api/mes/pro/andon/record/index.ts new file mode 100644 index 000000000..b8cf4349b --- /dev/null +++ b/apps/web-antd/src/api/mes/pro/andon/record/index.ts @@ -0,0 +1,76 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MesProAndonRecordApi { + /** MES 安灯记录 */ + export interface AndonRecord { + id?: number; + configId?: number; // 安灯配置编号 + workstationId?: number; // 工作站编号 + workstationCode?: string; // 工作站编码 + workstationName?: string; // 工作站名称 + workOrderId?: number; // 生产工单编号 + workOrderCode?: string; // 工单编码 + processId?: number; // 工序编号 + processName?: string; // 工序名称 + userId?: number; // 发起用户编号 + userNickname?: string; // 发起人昵称 + reason?: string; // 呼叫原因 + level?: number; // 级别 + status?: number; // 处置状态 + handleTime?: number; // 处置时间(毫秒时间戳) + handlerUserId?: number; // 处置人编号 + handlerUserNickname?: string; // 处置人昵称 + remark?: string; // 备注 + createTime?: number; // 发起时间 + } + + /** MES 安灯记录分页查询参数 */ + export interface PageParams extends PageParam { + workstationId?: number; // 工作站编号 + userId?: number; // 发起用户编号 + handlerUserId?: number; // 处置人编号 + status?: number; // 处置状态 + createTime?: string[]; // 发起时间区间 + } +} + +/** 查询安灯记录分页 */ +export function getAndonRecordPage(params: MesProAndonRecordApi.PageParams) { + return requestClient.get>( + '/mes/pro/andon-record/page', + { params }, + ); +} + +/** 查询安灯记录详情 */ +export function getAndonRecord(id: number) { + return requestClient.get( + `/mes/pro/andon-record/get?id=${id}`, + ); +} + +/** 新增安灯记录 */ +export function createAndonRecord(data: MesProAndonRecordApi.AndonRecord) { + return requestClient.post('/mes/pro/andon-record/create', data); +} + +/** 删除安灯记录 */ +export function deleteAndonRecord(id: number) { + return requestClient.delete(`/mes/pro/andon-record/delete?id=${id}`); +} + +/** 更新安灯记录(保存/已处置) */ +export function updateAndonRecord(data: MesProAndonRecordApi.AndonRecord) { + return requestClient.put('/mes/pro/andon-record/update', data); +} + +/** 导出安灯记录 Excel */ +export function exportAndonRecord( + params: Partial, +) { + return requestClient.download('/mes/pro/andon-record/export-excel', { + params, + }); +} diff --git a/apps/web-antd/src/api/mes/pro/feedback/index.ts b/apps/web-antd/src/api/mes/pro/feedback/index.ts new file mode 100644 index 000000000..21a988ba8 --- /dev/null +++ b/apps/web-antd/src/api/mes/pro/feedback/index.ts @@ -0,0 +1,113 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MesProFeedbackApi { + /** MES 生产报工 */ + export interface Feedback { + id?: number; + code?: string; // 报工单编号 + type?: number; // 报工类型 + channel?: string; // 报工途径 + feedbackTime?: number; // 报工时间 + workstationId?: number; // 工作站编号 + workstationCode?: string; // 工作站编码 + workstationName?: string; // 工作站名称 + routeId?: number; // 工艺路线编号 + routeCode?: string; // 工艺路线编码 + processId?: number; // 工序编号 + processCode?: string; // 工序编码 + processName?: string; // 工序名称 + checkFlag?: boolean; // 是否需要检验 + workOrderId?: number; // 生产工单编号 + workOrderCode?: string; // 工单编码 + workOrderName?: string; // 工单名称 + taskId?: number; // 生产任务编号 + taskCode?: string; // 任务编码 + itemId?: number; // 产品物料编号 + itemCode?: string; // 物料编码 + itemName?: string; // 物料名称 + itemSpecification?: string; // 规格型号 + unitMeasureId?: number; // 单位编号 + unitMeasureName?: string; // 单位名称 + expireDate?: number; // 过期日期 + scheduledQuantity?: number; // 排产数量 + feedbackQuantity?: number; // 本次报工数量 + qualifiedQuantity?: number; // 合格品数量 + unqualifiedQuantity?: number; // 不良品数量 + uncheckQuantity?: number; // 待检测数量 + laborScrapQuantity?: number; // 工废数量 + materialScrapQuantity?: number; // 料废数量 + otherScrapQuantity?: number; // 其他废品数量 + feedbackUserId?: number; // 报工用户编号 + feedbackUserNickname?: string; // 报工人昵称 + approveUserId?: number; // 审核用户编号 + approveUserNickname?: string; // 审核人昵称 + status?: number; // 状态 + remark?: string; // 备注 + creator?: string; // 创建人 + createTime?: number; // 创建时间 + } + + /** MES 生产报工分页查询参数 */ + export interface PageParams extends PageParam { + code?: string; + type?: number; + workOrderId?: number; + itemId?: number; + feedbackUserId?: number; + creator?: string; + status?: number; + feedbackTime?: string[]; + } +} + +/** 查询生产报工分页 */ +export function getFeedbackPage(params: MesProFeedbackApi.PageParams) { + return requestClient.get>( + '/mes/pro/feedback/page', + { params }, + ); +} + +/** 查询生产报工详情 */ +export function getFeedback(id: number) { + return requestClient.get( + `/mes/pro/feedback/get?id=${id}`, + ); +} + +/** 新增生产报工 */ +export function createFeedback(data: MesProFeedbackApi.Feedback) { + return requestClient.post('/mes/pro/feedback/create', data); +} + +/** 修改生产报工 */ +export function updateFeedback(data: MesProFeedbackApi.Feedback) { + return requestClient.put('/mes/pro/feedback/update', data); +} + +/** 删除生产报工 */ +export function deleteFeedback(id: number) { + return requestClient.delete(`/mes/pro/feedback/delete?id=${id}`); +} + +/** 导出生产报工 Excel */ +export function exportFeedback(params: Partial) { + return requestClient.download('/mes/pro/feedback/export-excel', { params }); +} + +/** 提交生产报工 */ +export function submitFeedback(id: number) { + return requestClient.put(`/mes/pro/feedback/submit?id=${id}`); +} + +/** 驳回生产报工 */ +export function rejectFeedback(id: number) { + return requestClient.put(`/mes/pro/feedback/reject?id=${id}`); +} + +/** 审批生产报工(返回是否已审批完成) */ +export function approveFeedback(id: number) { + return requestClient.put(`/mes/pro/feedback/approve?id=${id}`); +} diff --git a/apps/web-antd/src/api/mes/pro/process/content/index.ts b/apps/web-antd/src/api/mes/pro/process/content/index.ts new file mode 100644 index 000000000..8a4c15e59 --- /dev/null +++ b/apps/web-antd/src/api/mes/pro/process/content/index.ts @@ -0,0 +1,49 @@ +import { requestClient } from '#/api/request'; + +export namespace MesProProcessContentApi { + /** MES 生产工序内容(操作步骤) */ + export interface ProcessContent { + id?: number; + processId?: number; + sort?: number; + content?: string; + device?: string; + material?: string; + docUrl?: string; + remark?: string; + createTime?: Date; + } +} + +/** 按工序编号查询工序内容列表 */ +export function getProcessContentListByProcessId(processId: number) { + return requestClient.get( + `/mes/pro/process-content/list-by-process?processId=${processId}`, + ); +} + +/** 查询工序内容详情 */ +export function getProcessContent(id: number) { + return requestClient.get( + `/mes/pro/process-content/get?id=${id}`, + ); +} + +/** 新增工序内容 */ +export function createProcessContent( + data: MesProProcessContentApi.ProcessContent, +) { + return requestClient.post('/mes/pro/process-content/create', data); +} + +/** 修改工序内容 */ +export function updateProcessContent( + data: MesProProcessContentApi.ProcessContent, +) { + return requestClient.put('/mes/pro/process-content/update', data); +} + +/** 删除工序内容 */ +export function deleteProcessContent(id: number) { + return requestClient.delete(`/mes/pro/process-content/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/mes/pro/route/index.ts b/apps/web-antd/src/api/mes/pro/route/index.ts new file mode 100644 index 000000000..56baff6b5 --- /dev/null +++ b/apps/web-antd/src/api/mes/pro/route/index.ts @@ -0,0 +1,65 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MesProRouteApi { + /** MES 工艺路线 */ + export interface Route { + id?: number; + code?: string; + name?: string; + description?: string; + status?: number; + remark?: string; + createTime?: Date; + } +} + +/** 查询工艺路线分页 */ +export function getRoutePage(params: PageParam) { + return requestClient.get>( + '/mes/pro/route/page', + { params }, + ); +} + +/** 查询工艺路线精简列表 */ +export function getRouteSimpleList() { + return requestClient.get( + '/mes/pro/route/simple-list', + ); +} + +/** 查询工艺路线详情 */ +export function getRoute(id: number) { + return requestClient.get( + `/mes/pro/route/get?id=${id}`, + ); +} + +/** 新增工艺路线 */ +export function createRoute(data: MesProRouteApi.Route) { + return requestClient.post('/mes/pro/route/create', data); +} + +/** 修改工艺路线 */ +export function updateRoute(data: MesProRouteApi.Route) { + return requestClient.put('/mes/pro/route/update', data); +} + +/** 修改工艺路线状态 */ +export function updateRouteStatus(id: number, status: number) { + return requestClient.put( + `/mes/pro/route/update-status?id=${id}&status=${status}`, + ); +} + +/** 删除工艺路线 */ +export function deleteRoute(id: number) { + return requestClient.delete(`/mes/pro/route/delete?id=${id}`); +} + +/** 导出工艺路线 Excel */ +export function exportRoute(params: any) { + return requestClient.download('/mes/pro/route/export-excel', { params }); +} diff --git a/apps/web-antd/src/api/mes/pro/route/process/index.ts b/apps/web-antd/src/api/mes/pro/route/process/index.ts new file mode 100644 index 000000000..fee0ce9c4 --- /dev/null +++ b/apps/web-antd/src/api/mes/pro/route/process/index.ts @@ -0,0 +1,70 @@ +import { requestClient } from '#/api/request'; + +export namespace MesProRouteProcessApi { + /** MES 工艺路线工序 */ + export interface RouteProcess { + id?: number; + routeId?: number; + processId?: number; + processCode?: string; + processName?: string; + sort?: number; + nextProcessId?: number; + nextProcessName?: string; + linkType?: number; + prepareTime?: number; + waitTime?: number; + colorCode?: string; + keyFlag?: boolean; + checkFlag?: boolean; + remark?: string; + createTime?: Date; + } +} + +/** 按工艺路线查询工序列表 */ +export function getRouteProcessListByRoute(routeId: number) { + return requestClient.get( + `/mes/pro/route-process/list-by-route?routeId=${routeId}`, + ); +} + +/** 按产品查询工序列表(自动查找关联的工艺路线) */ +export function getRouteProcessListByProduct(productId: number) { + return requestClient.get( + `/mes/pro/route-process/list-by-product?productId=${productId}`, + ); +} + +/** 查询工艺路线工序详情 */ +export function getRouteProcess(id: number) { + return requestClient.get( + `/mes/pro/route-process/get?id=${id}`, + ); +} + +/** 按工艺路线 + 工序精确查询工序配置 */ +export function getRouteProcessByRouteAndProcess( + routeId: number, + processId: number, +) { + return requestClient.get( + '/mes/pro/route-process/get-by-route-and-process', + { params: { processId, routeId } }, + ); +} + +/** 新增工艺路线工序 */ +export function createRouteProcess(data: MesProRouteProcessApi.RouteProcess) { + return requestClient.post('/mes/pro/route-process/create', data); +} + +/** 修改工艺路线工序 */ +export function updateRouteProcess(data: MesProRouteProcessApi.RouteProcess) { + return requestClient.put('/mes/pro/route-process/update', data); +} + +/** 删除工艺路线工序 */ +export function deleteRouteProcess(id: number) { + return requestClient.delete(`/mes/pro/route-process/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/mes/pro/route/product/index.ts b/apps/web-antd/src/api/mes/pro/route/product/index.ts new file mode 100644 index 000000000..2312f688c --- /dev/null +++ b/apps/web-antd/src/api/mes/pro/route/product/index.ts @@ -0,0 +1,48 @@ +import { requestClient } from '#/api/request'; + +export namespace MesProRouteProductApi { + /** MES 工艺路线产品 */ + export interface RouteProduct { + id?: number; + routeId?: number; + itemId?: number; + itemCode?: string; + itemName?: string; + specification?: string; + unitName?: string; + quantity?: number; + productionTime?: number; + timeUnitType?: string; + remark?: string; + createTime?: Date; + } +} + +/** 按工艺路线查询产品列表 */ +export function getRouteProductListByRoute(routeId: number) { + return requestClient.get( + `/mes/pro/route-product/list-by-route?routeId=${routeId}`, + ); +} + +/** 查询工艺路线产品详情 */ +export function getRouteProduct(id: number) { + return requestClient.get( + `/mes/pro/route-product/get?id=${id}`, + ); +} + +/** 新增工艺路线产品 */ +export function createRouteProduct(data: MesProRouteProductApi.RouteProduct) { + return requestClient.post('/mes/pro/route-product/create', data); +} + +/** 修改工艺路线产品 */ +export function updateRouteProduct(data: MesProRouteProductApi.RouteProduct) { + return requestClient.put('/mes/pro/route-product/update', data); +} + +/** 删除工艺路线产品 */ +export function deleteRouteProduct(id: number) { + return requestClient.delete(`/mes/pro/route-product/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/mes/pro/route/productbom/index.ts b/apps/web-antd/src/api/mes/pro/route/productbom/index.ts new file mode 100644 index 000000000..7cfcbcc85 --- /dev/null +++ b/apps/web-antd/src/api/mes/pro/route/productbom/index.ts @@ -0,0 +1,57 @@ +import { requestClient } from '#/api/request'; + +export namespace MesProRouteProductBomApi { + /** MES 工艺路线产品 BOM */ + export interface RouteProductBom { + id?: number; + routeId?: number; + processId?: number; + productId?: number; + itemId?: number; + itemCode?: string; + itemName?: string; + specification?: string; + unitName?: string; + quantity?: number; + remark?: string; + createTime?: Date; + } +} + +/** 查询工艺路线产品 BOM 列表 */ +export function getRouteProductBomList(params: { + processId?: number; + productId?: number; + routeId: number; +}) { + return requestClient.get( + '/mes/pro/route-product-bom/list', + { params }, + ); +} + +/** 查询工艺路线产品 BOM 详情 */ +export function getRouteProductBom(id: number) { + return requestClient.get( + `/mes/pro/route-product-bom/get?id=${id}`, + ); +} + +/** 新增工艺路线产品 BOM */ +export function createRouteProductBom( + data: MesProRouteProductBomApi.RouteProductBom, +) { + return requestClient.post('/mes/pro/route-product-bom/create', data); +} + +/** 修改工艺路线产品 BOM */ +export function updateRouteProductBom( + data: MesProRouteProductBomApi.RouteProductBom, +) { + return requestClient.put('/mes/pro/route-product-bom/update', data); +} + +/** 删除工艺路线产品 BOM */ +export function deleteRouteProductBom(id: number) { + return requestClient.delete(`/mes/pro/route-product-bom/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/mes/pro/task/index.ts b/apps/web-antd/src/api/mes/pro/task/index.ts new file mode 100644 index 000000000..d7bfd2f5e --- /dev/null +++ b/apps/web-antd/src/api/mes/pro/task/index.ts @@ -0,0 +1,68 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MesProTaskApi { + /** MES 生产任务 */ + export interface Task { + id?: number; + code?: string; // 任务编码 + name?: string; // 任务名称 + workOrderId?: number; // 生产工单编号 + workOrderCode?: string; // 工单编码 + workOrderName?: string; // 工单名称 + workstationId?: number; // 工作站编号 + workstationCode?: string; // 工作站编码 + workstationName?: string; // 工作站名称 + routeId?: number; // 工艺路线编号 + processId?: number; // 工序编号 + processName?: string; // 工序名称 + itemId?: number; // 产品物料编号 + itemCode?: string; // 产品编码 + itemName?: string; // 产品名称 + itemSpecification?: string; // 规格型号 + unitMeasureId?: number; // 单位编号 + unitMeasureName?: string; // 单位名称 + quantity?: number; // 排产数量 + producedQuantity?: number; // 已生产数量 + qualifyQuantity?: number; // 合格品数量 + unqualifyQuantity?: number; // 不良品数量 + changedQuantity?: number; // 调整数量 + clientId?: number; // 客户编号 + clientName?: string; // 客户名称 + startTime?: number; // 开始生产时间 + endTime?: number; // 结束生产时间 + duration?: number; // 生产时长(工作日,1=8小时) + requestDate?: number; // 需求日期(从工单查) + finishDate?: number; // 完成日期 + cancelDate?: number; // 取消日期 + colorCode?: string; // 甘特图显示颜色 + status?: number; // 任务状态 + checkFlag?: boolean; // 是否质检(派生自工艺路线工序) + remark?: string; // 备注 + } + + /** MES 生产任务分页查询参数 */ + export interface PageParams extends PageParam { + code?: string; + name?: string; + workOrderId?: number; + workstationId?: number; + itemId?: number; + statuses?: number[]; + status?: number; + } +} + +/** 查询生产任务分页 */ +export function getTaskPage(params: MesProTaskApi.PageParams) { + return requestClient.get>( + '/mes/pro/task/page', + { params }, + ); +} + +/** 查询生产任务详情 */ +export function getTask(id: number) { + return requestClient.get(`/mes/pro/task/get?id=${id}`); +} diff --git a/apps/web-antd/src/api/mes/pro/workorder/index.ts b/apps/web-antd/src/api/mes/pro/workorder/index.ts new file mode 100644 index 000000000..fcc22b79e --- /dev/null +++ b/apps/web-antd/src/api/mes/pro/workorder/index.ts @@ -0,0 +1,53 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MesProWorkOrderApi { + /** MES 生产工单 */ + export interface WorkOrder { + id?: number; + code?: string; // 工单编码 + name?: string; // 工单名称 + type?: number; // 工单类型 + status?: number; // 工单状态 + sourceType?: number; + productId?: number; // 产品物料编号 + productCode?: string; + productName?: string; + productSpecification?: string; + quantity?: number; + unitName?: string; + routeId?: number; + routeName?: string; + clientId?: number; + clientName?: string; + planStartTime?: number | string; + planEndTime?: number | string; + actualStartTime?: number | string; + actualEndTime?: number | string; + remark?: string; + createTime?: number | string; + } + + export interface PageParams extends PageParam { + code?: string; + name?: string; + status?: number; + type?: number; + } +} + +/** 查询生产工单分页 */ +export function getWorkOrderPage(params: MesProWorkOrderApi.PageParams) { + return requestClient.get>( + '/mes/pro/work-order/page', + { params }, + ); +} + +/** 查询生产工单详情 */ +export function getWorkOrder(id: number) { + return requestClient.get( + `/mes/pro/work-order/get?id=${id}`, + ); +} diff --git a/apps/web-antd/src/api/mes/pro/workrecord/index.ts b/apps/web-antd/src/api/mes/pro/workrecord/index.ts new file mode 100644 index 000000000..08950365c --- /dev/null +++ b/apps/web-antd/src/api/mes/pro/workrecord/index.ts @@ -0,0 +1,71 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MesProWorkRecordApi { + /** MES 工作记录流水 */ + export interface WorkRecordLog { + id?: number; // 编号 + userId?: number; // 用户编号 + userNickname?: string; // 用户昵称 + workstationId?: number; // 工作站编号 + workstationCode?: string; // 工作站编码 + workstationName?: string; // 工作站名称 + type?: number; // 1=上工 2=下工 + remark?: string; // 备注 + createTime?: Date; // 创建时间 + } + + /** MES 当前用户工作站绑定状态 */ + export interface MyWorkRecord { + userId?: number; // 用户编号 + userNickname?: string; // 用户昵称 + workstationId?: number; // 工作站编号 + workstationCode?: string; // 工作站编码 + workstationName?: string; // 工作站名称 + type?: number; // 1=上工 2=下工 + clockInTime?: Date; // 上工时间 + clockOutTime?: Date; // 下工时间 + } +} + +/** 查询工作记录分页 */ +export function getWorkRecordLogPage(params: PageParam) { + return requestClient.get>( + '/mes/pro/workrecord/log/page', + { params }, + ); +} + +/** 查询工作记录详情 */ +export function getWorkRecordLog(id: number) { + return requestClient.get( + `/mes/pro/workrecord/log/get?id=${id}`, + ); +} + +/** 导出工作记录 */ +export function exportWorkRecordLog(params: any) { + return requestClient.download('/mes/pro/workrecord/log/export-excel', { + params, + }); +} + +/** 上工(绑定工作站) */ +export function clockInWorkRecord(workstationId: number) { + return requestClient.put('/mes/pro/workrecord/clock-in', null, { + params: { workstationId }, + }); +} + +/** 下工(解绑工作站) */ +export function clockOutWorkRecord() { + return requestClient.put('/mes/pro/workrecord/clock-out'); +} + +/** 查询当前用户绑定的工作站 */ +export function getMyWorkRecord() { + return requestClient.get( + '/mes/pro/workrecord/get-my', + ); +} diff --git a/apps/web-antd/src/api/mes/qc/defect/index.ts b/apps/web-antd/src/api/mes/qc/defect/index.ts new file mode 100644 index 000000000..0b46d3581 --- /dev/null +++ b/apps/web-antd/src/api/mes/qc/defect/index.ts @@ -0,0 +1,54 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MesQcDefectApi { + /** MES 缺陷类型 */ + export interface Defect { + id?: number; // 编号 + code?: string; // 缺陷编码 + name?: string; // 缺陷描述 + type?: number; // 检测项类型 + level?: number; // 缺陷等级 + remark?: string; // 备注 + createTime?: Date; // 创建时间 + } +} + +/** 查询缺陷类型分页 */ +export function getDefectPage(params: PageParam) { + return requestClient.get>( + '/mes/qc/defect/page', + { params }, + ); +} + +/** 查询缺陷类型精简列表 */ +export function getDefectSimpleList() { + return requestClient.get('/mes/qc/defect/simple-list'); +} + +/** 查询缺陷类型详情 */ +export function getDefect(id: number) { + return requestClient.get(`/mes/qc/defect/get?id=${id}`); +} + +/** 新增缺陷类型 */ +export function createDefect(data: MesQcDefectApi.Defect) { + return requestClient.post('/mes/qc/defect/create', data); +} + +/** 修改缺陷类型 */ +export function updateDefect(data: MesQcDefectApi.Defect) { + return requestClient.put('/mes/qc/defect/update', data); +} + +/** 删除缺陷类型 */ +export function deleteDefect(id: number) { + return requestClient.delete(`/mes/qc/defect/delete?id=${id}`); +} + +/** 导出缺陷类型 */ +export function exportDefect(params: any) { + return requestClient.download('/mes/qc/defect/export-excel', { params }); +} diff --git a/apps/web-antd/src/api/mes/qc/indicator/index.ts b/apps/web-antd/src/api/mes/qc/indicator/index.ts new file mode 100644 index 000000000..163f11d89 --- /dev/null +++ b/apps/web-antd/src/api/mes/qc/indicator/index.ts @@ -0,0 +1,53 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MesQcIndicatorApi { + /** MES 质检指标 */ + export interface Indicator { + id?: number; // 编号 + code?: string; // 检测项编码 + name?: string; // 检测项名称 + type?: number; // 检测项类型 + tool?: string; // 检测工具 + resultType?: number; // 结果值类型 + resultSpecification?: string; // 结果值属性 + remark?: string; // 备注 + createTime?: Date; // 创建时间 + } +} + +/** 查询质检指标分页 */ +export function getIndicatorPage(params: PageParam) { + return requestClient.get>( + '/mes/qc/indicator/page', + { params }, + ); +} + +/** 查询质检指标详情 */ +export function getIndicator(id: number) { + return requestClient.get( + `/mes/qc/indicator/get?id=${id}`, + ); +} + +/** 新增质检指标 */ +export function createIndicator(data: MesQcIndicatorApi.Indicator) { + return requestClient.post('/mes/qc/indicator/create', data); +} + +/** 修改质检指标 */ +export function updateIndicator(data: MesQcIndicatorApi.Indicator) { + return requestClient.put('/mes/qc/indicator/update', data); +} + +/** 删除质检指标 */ +export function deleteIndicator(id: number) { + return requestClient.delete(`/mes/qc/indicator/delete?id=${id}`); +} + +/** 导出质检指标 */ +export function exportIndicator(params: any) { + return requestClient.download('/mes/qc/indicator/export-excel', { params }); +} diff --git a/apps/web-antd/src/api/mes/qc/template/index.ts b/apps/web-antd/src/api/mes/qc/template/index.ts new file mode 100644 index 000000000..768864482 --- /dev/null +++ b/apps/web-antd/src/api/mes/qc/template/index.ts @@ -0,0 +1,51 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MesQcTemplateApi { + /** MES 质检方案 */ + export interface Template { + id?: number; // 编号 + code?: string; // 方案编号 + name?: string; // 方案名称 + types?: number[]; // 检测种类 + status?: number; // 状态 + remark?: string; // 备注 + createTime?: Date; // 创建时间 + } +} + +/** 查询质检方案分页 */ +export function getTemplatePage(params: PageParam) { + return requestClient.get>( + '/mes/qc/template/page', + { params }, + ); +} + +/** 查询质检方案详情 */ +export function getTemplate(id: number) { + return requestClient.get( + `/mes/qc/template/get?id=${id}`, + ); +} + +/** 新增质检方案 */ +export function createTemplate(data: MesQcTemplateApi.Template) { + return requestClient.post('/mes/qc/template/create', data); +} + +/** 修改质检方案 */ +export function updateTemplate(data: MesQcTemplateApi.Template) { + return requestClient.put('/mes/qc/template/update', data); +} + +/** 删除质检方案 */ +export function deleteTemplate(id: number) { + return requestClient.delete(`/mes/qc/template/delete?id=${id}`); +} + +/** 导出质检方案 */ +export function exportTemplate(params: any) { + return requestClient.download('/mes/qc/template/export-excel', { params }); +} diff --git a/apps/web-antd/src/api/mes/qc/template/indicator/index.ts b/apps/web-antd/src/api/mes/qc/template/indicator/index.ts new file mode 100644 index 000000000..8fa8119e6 --- /dev/null +++ b/apps/web-antd/src/api/mes/qc/template/indicator/index.ts @@ -0,0 +1,57 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MesQcTemplateIndicatorApi { + /** MES 质检方案-检测指标项 */ + export interface TemplateIndicator { + id?: number; // 编号 + templateId?: number; // 质检方案ID + indicatorId?: number; // 质检指标ID + checkMethod?: string; // 检测方法 + standardValue?: number; // 标准值 + unitMeasureId?: number; // 计量单位ID + thresholdMax?: number; // 误差上限 + thresholdMin?: number; // 误差下限 + docUrl?: string; // 说明图URL + remark?: string; // 备注 + indicatorCode?: string; // 检测项编码(JOIN) + indicatorName?: string; // 检测项名称(JOIN) + indicatorType?: number; // 检测项类型(JOIN) + indicatorTool?: string; // 检测工具(JOIN) + unitMeasureName?: string; // 计量单位名称(JOIN) + } +} + +/** 查询检测指标项分页 */ +export function getTemplateIndicatorPage(params: PageParam & { templateId?: number }) { + return requestClient.get< + PageResult + >('/mes/qc/template/indicator/page', { params }); +} + +/** 查询检测指标项详情 */ +export function getTemplateIndicator(id: number) { + return requestClient.get( + `/mes/qc/template/indicator/get?id=${id}`, + ); +} + +/** 新增检测指标项 */ +export function createTemplateIndicator( + data: MesQcTemplateIndicatorApi.TemplateIndicator, +) { + return requestClient.post('/mes/qc/template/indicator/create', data); +} + +/** 修改检测指标项 */ +export function updateTemplateIndicator( + data: MesQcTemplateIndicatorApi.TemplateIndicator, +) { + return requestClient.put('/mes/qc/template/indicator/update', data); +} + +/** 删除检测指标项 */ +export function deleteTemplateIndicator(id: number) { + return requestClient.delete(`/mes/qc/template/indicator/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/mes/qc/template/item/index.ts b/apps/web-antd/src/api/mes/qc/template/item/index.ts new file mode 100644 index 000000000..b1d5b1e6b --- /dev/null +++ b/apps/web-antd/src/api/mes/qc/template/item/index.ts @@ -0,0 +1,52 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MesQcTemplateItemApi { + /** MES 质检方案-产品关联 */ + export interface TemplateItem { + id?: number; // 编号 + templateId?: number; // 质检方案ID + itemId?: number; // 产品物料ID + quantityCheck?: number; // 最低检测数 + quantityUnqualified?: number; // 最大不合格数 + criticalRate?: number; // 最大致命缺陷率(%) + majorRate?: number; // 最大严重缺陷率(%) + minorRate?: number; // 最大轻微缺陷率(%) + remark?: string; // 备注 + itemCode?: string; // 物料编码(JOIN) + itemName?: string; // 物料名称(JOIN) + specification?: string; // 规格型号(JOIN) + unitMeasureName?: string; // 计量单位名称(JOIN) + } +} + +/** 查询产品关联分页 */ +export function getTemplateItemPage(params: PageParam & { templateId?: number }) { + return requestClient.get>( + '/mes/qc/template/item/page', + { params }, + ); +} + +/** 查询产品关联详情 */ +export function getTemplateItem(id: number) { + return requestClient.get( + `/mes/qc/template/item/get?id=${id}`, + ); +} + +/** 新增产品关联 */ +export function createTemplateItem(data: MesQcTemplateItemApi.TemplateItem) { + return requestClient.post('/mes/qc/template/item/create', data); +} + +/** 修改产品关联 */ +export function updateTemplateItem(data: MesQcTemplateItemApi.TemplateItem) { + return requestClient.put('/mes/qc/template/item/update', data); +} + +/** 删除产品关联 */ +export function deleteTemplateItem(id: number) { + return requestClient.delete(`/mes/qc/template/item/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/mes/wm/barcode/config/index.ts b/apps/web-antd/src/api/mes/wm/barcode/config/index.ts new file mode 100644 index 000000000..862da4fbb --- /dev/null +++ b/apps/web-antd/src/api/mes/wm/barcode/config/index.ts @@ -0,0 +1,49 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MesWmBarcodeConfigApi { + /** MES 条码配置 */ + export interface BarcodeConfig { + id?: number; // 编号 + format?: number; // 条码格式 + bizType?: number; // 业务类型 + contentFormat?: string; // 内容格式模板 + contentExample?: string; // 内容样例 + autoGenerateFlag?: boolean; // 是否自动生成 + defaultTemplate?: string; // 默认打印模板 + status?: number; // 状态 + remark?: string; // 备注 + createTime?: Date; // 创建时间 + } +} + +/** 查询条码配置分页 */ +export function getBarcodeConfigPage(params: PageParam) { + return requestClient.get>( + '/mes/wm/barcode-config/page', + { params }, + ); +} + +/** 查询条码配置详情 */ +export function getBarcodeConfig(id: number) { + return requestClient.get( + `/mes/wm/barcode-config/get?id=${id}`, + ); +} + +/** 新增条码配置 */ +export function createBarcodeConfig(data: MesWmBarcodeConfigApi.BarcodeConfig) { + return requestClient.post('/mes/wm/barcode-config/create', data); +} + +/** 修改条码配置 */ +export function updateBarcodeConfig(data: MesWmBarcodeConfigApi.BarcodeConfig) { + return requestClient.put('/mes/wm/barcode-config/update', data); +} + +/** 删除条码配置 */ +export function deleteBarcodeConfig(id: number) { + return requestClient.delete(`/mes/wm/barcode-config/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/mes/wm/barcode/index.ts b/apps/web-antd/src/api/mes/wm/barcode/index.ts index 6cbf8a51e..7e8154141 100644 --- a/apps/web-antd/src/api/mes/wm/barcode/index.ts +++ b/apps/web-antd/src/api/mes/wm/barcode/index.ts @@ -38,7 +38,7 @@ export function getBarcode(id: number) { export function getBarcodeByBusiness(bizType: number, bizId: number) { return requestClient.get( '/mes/wm/barcode/get-by-business', - { params: { bizType, bizId } }, + { params: { bizId, bizType } }, ); } @@ -57,9 +57,14 @@ export function deleteBarcode(id: number) { return requestClient.delete(`/mes/wm/barcode/delete?id=${id}`); } +/** 导出条码 */ +export function exportBarcode(params: any) { + return requestClient.download('/mes/wm/barcode/export-excel', { params }); +} + /** 生成条码内容 */ export function generateBarcodeContent(bizType: number, bizCode: string) { return requestClient.get('/mes/wm/barcode/generate-content', { - params: { bizType, bizCode }, + params: { bizCode, bizType }, }); } diff --git a/apps/web-antd/src/api/mes/wm/itemconsume/line/index.ts b/apps/web-antd/src/api/mes/wm/itemconsume/line/index.ts new file mode 100644 index 000000000..2a353b766 --- /dev/null +++ b/apps/web-antd/src/api/mes/wm/itemconsume/line/index.ts @@ -0,0 +1,37 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MesWmItemConsumeLineApi { + /** MES 物料消耗行 */ + export interface ItemConsumeLine { + id?: number; + feedbackId?: number; // 报工编号 + itemId?: number; // 物料编号 + itemCode?: string; // 物资编码 + itemName?: string; // 物资名称 + specification?: string; // 规格型号 + unitId?: number; // 单位编号 + unitName?: string; // 单位 + quantity?: number; // 消耗数量 + batchCode?: string; // 批次号 + locationId?: number; // 库位编号 + locationName?: string; // 库位名称 + remark?: string; // 备注 + } + + /** MES 物料消耗行分页查询参数 */ + export interface PageParams extends PageParam { + feedbackId?: number; + } +} + +/** 查询物料消耗行分页 */ +export function getItemConsumeLinePage( + params: MesWmItemConsumeLineApi.PageParams, +) { + return requestClient.get>( + '/mes/wm/item-consume-line/page', + { params }, + ); +} diff --git a/apps/web-antd/src/api/mes/wm/materialstock/index.ts b/apps/web-antd/src/api/mes/wm/materialstock/index.ts new file mode 100644 index 000000000..49aab9620 --- /dev/null +++ b/apps/web-antd/src/api/mes/wm/materialstock/index.ts @@ -0,0 +1,61 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MesWmMaterialStockApi { + /** MES 库存台账 */ + export interface MaterialStock { + id?: number; // 编号 + itemTypeId?: number; // 物料分类编号 + itemId?: number; // 物料编号 + itemCode?: string; // 物料编码 + itemName?: string; // 物料名称 + specification?: string; // 规格型号 + unitMeasureName?: string; // 计量单位名称 + batchId?: number; // 批次编号 + batchCode?: string; // 批次号 + warehouseId?: number; // 仓库编号 + warehouseCode?: string; // 仓库编码 + warehouseName?: string; // 仓库名称 + locationId?: number; // 库区编号 + locationName?: string; // 库区名称 + areaId?: number; // 库位编号 + areaName?: string; // 库位名称 + vendorId?: number; // 供应商编号 + vendorName?: string; // 供应商名称 + quantity?: number; // 在库数量 + receiptTime?: string; // 入库日期 + frozen?: boolean; // 是否冻结 + createTime?: Date; // 创建时间 + } +} + +/** 查询库存台账分页 */ +export function getMaterialStockPage(params: PageParam) { + return requestClient.get>( + '/mes/wm/material-stock/page', + { params }, + ); +} + +/** 查询库存台账详情 */ +export function getMaterialStock(id: number) { + return requestClient.get( + `/mes/wm/material-stock/get?id=${id}`, + ); +} + +/** 更新库存冻结状态 */ +export function updateMaterialStockFrozen(data: { + frozen: boolean; + id: number; +}) { + return requestClient.put('/mes/wm/material-stock/update-frozen', data); +} + +/** 导出库存台账 */ +export function exportMaterialStock(params: any) { + return requestClient.download('/mes/wm/material-stock/export-excel', { + params, + }); +} diff --git a/apps/web-antd/src/api/mes/wm/productproduce/line/index.ts b/apps/web-antd/src/api/mes/wm/productproduce/line/index.ts new file mode 100644 index 000000000..ab3f49f29 --- /dev/null +++ b/apps/web-antd/src/api/mes/wm/productproduce/line/index.ts @@ -0,0 +1,37 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MesWmProductProduceLineApi { + /** MES 产品产出行 */ + export interface ProductProduceLine { + id?: number; + feedbackId?: number; // 报工编号 + itemId?: number; // 物料编号 + itemCode?: string; // 物资编码 + itemName?: string; // 物资名称 + specification?: string; // 规格型号 + unitMeasureId?: number; // 单位编号 + unitMeasureName?: string; // 单位 + quantity?: number; // 产出数量 + batchCode?: string; // 批次号 + qualityStatus?: number; // 质量状态 + locationId?: number; // 库位编号 + locationName?: string; // 库位名称 + remark?: string; // 备注 + } + + /** MES 产品产出行分页查询参数 */ + export interface PageParams extends PageParam { + feedbackId?: number; + } +} + +/** 查询产品产出行分页 */ +export function getProductProduceLinePage( + params: MesWmProductProduceLineApi.PageParams, +) { + return requestClient.get< + PageResult + >('/mes/wm/product-produce-line/page', { params }); +} diff --git a/apps/web-antd/src/api/mes/wm/warehouse/area/index.ts b/apps/web-antd/src/api/mes/wm/warehouse/area/index.ts index cf5844ade..ca67789d8 100644 --- a/apps/web-antd/src/api/mes/wm/warehouse/area/index.ts +++ b/apps/web-antd/src/api/mes/wm/warehouse/area/index.ts @@ -48,3 +48,18 @@ export function getWarehouseArea(id: number) { `/mes/wm/warehouse-area/get?id=${id}`, ); } + +/** 新增库位 */ +export function createWarehouseArea(data: MesWmWarehouseAreaApi.WarehouseArea) { + return requestClient.post('/mes/wm/warehouse-area/create', data); +} + +/** 修改库位 */ +export function updateWarehouseArea(data: MesWmWarehouseAreaApi.WarehouseArea) { + return requestClient.put('/mes/wm/warehouse-area/update', data); +} + +/** 删除库位 */ +export function deleteWarehouseArea(id: number) { + return requestClient.delete(`/mes/wm/warehouse-area/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/mes/wm/warehouse/index.ts b/apps/web-antd/src/api/mes/wm/warehouse/index.ts index f68604790..661b62ee4 100644 --- a/apps/web-antd/src/api/mes/wm/warehouse/index.ts +++ b/apps/web-antd/src/api/mes/wm/warehouse/index.ts @@ -38,3 +38,18 @@ export function getWarehouse(id: number) { `/mes/wm/warehouse/get?id=${id}`, ); } + +/** 新增仓库 */ +export function createWarehouse(data: MesWmWarehouseApi.Warehouse) { + return requestClient.post('/mes/wm/warehouse/create', data); +} + +/** 修改仓库 */ +export function updateWarehouse(data: MesWmWarehouseApi.Warehouse) { + return requestClient.put('/mes/wm/warehouse/update', data); +} + +/** 删除仓库 */ +export function deleteWarehouse(id: number) { + return requestClient.delete(`/mes/wm/warehouse/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/mes/wm/warehouse/location/index.ts b/apps/web-antd/src/api/mes/wm/warehouse/location/index.ts index e33fb180e..4211f73c8 100644 --- a/apps/web-antd/src/api/mes/wm/warehouse/location/index.ts +++ b/apps/web-antd/src/api/mes/wm/warehouse/location/index.ts @@ -38,3 +38,35 @@ export function getWarehouseLocation(id: number) { `/mes/wm/warehouse-location/get?id=${id}`, ); } + +/** 新增库区 */ +export function createWarehouseLocation( + data: MesWmWarehouseLocationApi.WarehouseLocation, +) { + return requestClient.post('/mes/wm/warehouse-location/create', data); +} + +/** 修改库区 */ +export function updateWarehouseLocation( + data: MesWmWarehouseLocationApi.WarehouseLocation, +) { + return requestClient.put('/mes/wm/warehouse-location/update', data); +} + +/** 删除库区 */ +export function deleteWarehouseLocation(id: number) { + return requestClient.delete(`/mes/wm/warehouse-location/delete?id=${id}`); +} + +/** 批量设置库区下所有库位的混放规则 */ +export function updateAreaByLocationId( + locationId: number, + allowItemMixing?: boolean, + allowBatchMixing?: boolean, +) { + return requestClient.put( + '/mes/wm/warehouse-location/update-by-location-id', + null, + { params: { allowBatchMixing, allowItemMixing, locationId } }, + ); +} diff --git a/apps/web-antd/src/views/ai/image/manager/index.vue b/apps/web-antd/src/views/ai/image/manager/index.vue index 62087c743..04d048e80 100644 --- a/apps/web-antd/src/views/ai/image/manager/index.vue +++ b/apps/web-antd/src/views/ai/image/manager/index.vue @@ -38,24 +38,21 @@ async function handleUpdatePublicStatusChange( row: AiImageApi.Image, ): Promise { const text = newStatus ? '公开' : '私有'; - return new Promise((resolve, reject) => { - confirm({ + try { + await confirm({ content: `确认要将该图片切换为【${text}】吗?`, - }) - .then(async () => { - // 更新图片状态 - await updateImage({ - id: row.id, - publicStatus: newStatus, - }); - // 提示并返回成功 - message.success($t('ui.actionMessage.operationSuccess')); - resolve(true); - }) - .catch(() => { - reject(new Error('取消操作')); - }); + }); + } catch { + return false; + } + // 更新图片状态 + await updateImage({ + id: row.id, + publicStatus: newStatus, }); + // 提示并返回成功 + message.success($t('ui.actionMessage.operationSuccess')); + return true; } const [Grid, gridApi] = useVbenVxeGrid({ diff --git a/apps/web-antd/src/views/ai/knowledge/document/index.vue b/apps/web-antd/src/views/ai/knowledge/document/index.vue index e1dd551fa..5d21febd3 100644 --- a/apps/web-antd/src/views/ai/knowledge/document/index.vue +++ b/apps/web-antd/src/views/ai/knowledge/document/index.vue @@ -76,24 +76,21 @@ async function handleStatusChange( newStatus: number, row: AiKnowledgeDocumentApi.KnowledgeDocument, ): Promise { - return new Promise((resolve, reject) => { - confirm({ + try { + await confirm({ content: `你要将${row.name}的状态切换为【${getDictLabel(DICT_TYPE.COMMON_STATUS, newStatus)}】吗?`, - }) - .then(async () => { - // 更新文档状态 - await updateKnowledgeDocumentStatus({ - id: row.id, - status: newStatus, - }); - // 提示并返回成功 - message.success($t('ui.actionMessage.operationSuccess')); - resolve(true); - }) - .catch(() => { - reject(new Error('取消操作')); - }); + }); + } catch { + return false; + } + // 更新文档状态 + await updateKnowledgeDocumentStatus({ + id: row.id, + status: newStatus, }); + // 提示并返回成功 + message.success($t('ui.actionMessage.operationSuccess')); + return true; } const [Grid, gridApi] = useVbenVxeGrid({ diff --git a/apps/web-antd/src/views/ai/knowledge/segment/index.vue b/apps/web-antd/src/views/ai/knowledge/segment/index.vue index 363e6b1ad..2f9955e64 100644 --- a/apps/web-antd/src/views/ai/knowledge/segment/index.vue +++ b/apps/web-antd/src/views/ai/knowledge/segment/index.vue @@ -64,21 +64,18 @@ async function handleStatusChange( newStatus: number, row: AiKnowledgeSegmentApi.KnowledgeSegment, ): Promise { - return new Promise((resolve, reject) => { - confirm({ + try { + await confirm({ content: `你要将片段 ${row.id} 的状态切换为【${getDictLabel(DICT_TYPE.COMMON_STATUS, newStatus)}】吗?`, - }) - .then(async () => { - // 更新片段状态 - await updateKnowledgeSegmentStatus(row.id!, newStatus); - // 提示并返回成功 - message.success($t('ui.actionMessage.operationSuccess')); - resolve(true); - }) - .catch(() => { - reject(new Error('取消操作')); - }); - }); + }); + } catch { + return false; + } + // 更新片段状态 + await updateKnowledgeSegmentStatus(row.id!, newStatus); + // 提示并返回成功 + message.success($t('ui.actionMessage.operationSuccess')); + return true; } const [Grid, gridApi] = useVbenVxeGrid({ diff --git a/apps/web-antd/src/views/ai/music/manager/index.vue b/apps/web-antd/src/views/ai/music/manager/index.vue index bfd4d4502..6d03547cd 100644 --- a/apps/web-antd/src/views/ai/music/manager/index.vue +++ b/apps/web-antd/src/views/ai/music/manager/index.vue @@ -38,24 +38,21 @@ async function handleUpdatePublicStatusChange( row: AiMusicApi.Music, ): Promise { const text = newStatus ? '公开' : '私有'; - return new Promise((resolve, reject) => { - confirm({ + try { + await confirm({ content: `确认要将该音乐切换为【${text}】吗?`, - }) - .then(async () => { - // 更新音乐状态 - await updateMusic({ - id: row.id, - publicStatus: newStatus, - }); - // 提示并返回成功 - message.success($t('ui.actionMessage.operationSuccess')); - resolve(true); - }) - .catch(() => { - reject(new Error('取消操作')); - }); + }); + } catch { + return false; + } + // 更新音乐状态 + await updateMusic({ + id: row.id, + publicStatus: newStatus, }); + // 提示并返回成功 + message.success($t('ui.actionMessage.operationSuccess')); + return true; } const [Grid, gridApi] = useVbenVxeGrid({ diff --git a/apps/web-antd/src/views/crm/business/components/detail-list.vue b/apps/web-antd/src/views/crm/business/components/detail-list.vue index 712b55e82..87f36d459 100644 --- a/apps/web-antd/src/views/crm/business/components/detail-list.vue +++ b/apps/web-antd/src/views/crm/business/components/detail-list.vue @@ -74,28 +74,24 @@ async function handleDeleteContactBusinessList() { message.error('请先选择商机后操作!'); return; } - return new Promise((resolve, reject) => { - confirm({ + try { + await confirm({ content: `确定要将${checkedRows.value.map((item) => item.name).join(',')}解除关联吗?`, - }) - .then(async () => { - const res = await deleteContactBusinessList({ - contactId: props.bizId, - businessIds: checkedRows.value.map((item) => item.id), - }); - if (res) { - // 提示并返回成功 - message.success($t('ui.actionMessage.operationSuccess')); - handleRefresh(); - resolve(true); - } else { - reject(new Error($t('ui.actionMessage.operationFailed'))); - } - }) - .catch(() => { - reject(new Error('取消操作')); - }); + }); + } catch { + return false; + } + const res = await deleteContactBusinessList({ + contactId: props.bizId, + businessIds: checkedRows.value.map((item) => item.id), }); + if (!res) { + throw new Error($t('ui.actionMessage.operationFailed')); + } + // 提示并返回成功 + message.success($t('ui.actionMessage.operationSuccess')); + handleRefresh(); + return true; } /** 查看商机详情 */ diff --git a/apps/web-antd/src/views/crm/clue/detail/index.vue b/apps/web-antd/src/views/crm/clue/detail/index.vue index 02c356400..98117c0e4 100644 --- a/apps/web-antd/src/views/crm/clue/detail/index.vue +++ b/apps/web-antd/src/views/crm/clue/detail/index.vue @@ -83,21 +83,18 @@ function handleTransfer() { /** 转化为客户 */ async function handleTransform(): Promise { - return new Promise((resolve, reject) => { - confirm({ + try { + await confirm({ content: '确定将该线索转化为客户吗?', - }) - .then(async () => { - // 转化为客户 - await transformClue(clueId.value); - // 提示并返回成功 - message.success('转化客户成功'); - resolve(true); - }) - .catch(() => { - reject(new Error('取消操作')); - }); - }); + }); + } catch { + return false; + } + // 转化为客户 + await transformClue(clueId.value); + // 提示并返回成功 + message.success('转化客户成功'); + return true; } /** 加载数据 */ diff --git a/apps/web-antd/src/views/crm/contact/components/detail-list.vue b/apps/web-antd/src/views/crm/contact/components/detail-list.vue index 832f80473..7e408cf3a 100644 --- a/apps/web-antd/src/views/crm/contact/components/detail-list.vue +++ b/apps/web-antd/src/views/crm/contact/components/detail-list.vue @@ -71,28 +71,24 @@ async function handleDeleteContactBusinessList() { message.error('请先选择联系人后操作!'); return; } - return new Promise((resolve, reject) => { - confirm({ + try { + await confirm({ content: `确定要将${checkedRows.value.map((item) => item.name).join(',')}解除关联吗?`, - }) - .then(async () => { - const res = await deleteBusinessContactList({ - businessId: props.bizId, - contactIds: checkedRows.value.map((item) => item.id), - }); - if (res) { - // 提示并返回成功 - message.success($t('ui.actionMessage.operationSuccess')); - handleRefresh(); - resolve(true); - } else { - reject(new Error($t('ui.actionMessage.operationFailed'))); - } - }) - .catch(() => { - reject(new Error('取消操作')); - }); + }); + } catch { + return false; + } + const res = await deleteBusinessContactList({ + businessId: props.bizId, + contactIds: checkedRows.value.map((item) => item.id), }); + if (!res) { + throw new Error($t('ui.actionMessage.operationFailed')); + } + // 提示并返回成功 + message.success($t('ui.actionMessage.operationSuccess')); + handleRefresh(); + return true; } /** 创建商机联系人关联 */ diff --git a/apps/web-antd/src/views/crm/customer/detail/index.vue b/apps/web-antd/src/views/crm/customer/detail/index.vue index 925d1a5ac..8faf13e93 100644 --- a/apps/web-antd/src/views/crm/customer/detail/index.vue +++ b/apps/web-antd/src/views/crm/customer/detail/index.vue @@ -100,41 +100,35 @@ function handleTransfer() { } /** 锁定客户 */ -function handleLock(lockStatus: boolean): Promise { - return new Promise((resolve, reject) => { - confirm({ +async function handleLock(lockStatus: boolean): Promise { + try { + await confirm({ content: `确定锁定客户【${customer.value.name}】吗?`, - }) - .then(async () => { - // 锁定客户 - await lockCustomer(customerId.value, lockStatus); - // 提示并返回成功 - message.success(lockStatus ? '锁定客户成功' : '解锁客户成功'); - resolve(true); - }) - .catch(() => { - reject(new Error('取消操作')); - }); - }); + }); + } catch { + return false; + } + // 锁定客户 + await lockCustomer(customerId.value, lockStatus); + // 提示并返回成功 + message.success(lockStatus ? '锁定客户成功' : '解锁客户成功'); + return true; } /** 领取客户 */ -function handleReceive(): Promise { - return new Promise((resolve, reject) => { - confirm({ +async function handleReceive(): Promise { + try { + await confirm({ content: `确定领取客户【${customer.value.name}】吗?`, - }) - .then(async () => { - // 领取客户 - await receiveCustomer([customerId.value]); - // 提示并返回成功 - message.success('领取客户成功'); - resolve(true); - }) - .catch(() => { - reject(new Error('取消操作')); - }); - }); + }); + } catch { + return false; + } + // 领取客户 + await receiveCustomer([customerId.value]); + // 提示并返回成功 + message.success('领取客户成功'); + return true; } /** 分配客户 */ @@ -143,42 +137,36 @@ function handleDistributeForm() { } /** 客户放入公海 */ -function handlePutPool(): Promise { - return new Promise((resolve, reject) => { - confirm({ +async function handlePutPool(): Promise { + try { + await confirm({ content: `确定将客户【${customer.value.name}】放入公海吗?`, - }) - .then(async () => { - // 放入公海 - await putCustomerPool(customerId.value); - // 提示并返回成功 - message.success('放入公海成功'); - resolve(true); - }) - .catch(() => { - reject(new Error('取消操作')); - }); - }); + }); + } catch { + return false; + } + // 放入公海 + await putCustomerPool(customerId.value); + // 提示并返回成功 + message.success('放入公海成功'); + return true; } /** 更新成交状态操作 */ async function handleUpdateDealStatus(): Promise { - return new Promise((resolve, reject) => { - const dealStatus = !customer.value.dealStatus; - confirm({ + const dealStatus = !customer.value.dealStatus; + try { + await confirm({ content: `确定更新成交状态为【${dealStatus ? '已成交' : '未成交'}】吗?`, - }) - .then(async () => { - // 更新成交状态 - await updateCustomerDealStatus(customerId.value, dealStatus); - // 提示并返回成功 - message.success('更新成交状态成功'); - resolve(true); - }) - .catch(() => { - reject(new Error('取消操作')); - }); - }); + }); + } catch { + return false; + } + // 更新成交状态 + await updateCustomerDealStatus(customerId.value, dealStatus); + // 提示并返回成功 + message.success('更新成交状态成功'); + return true; } /** 加载数据 */ diff --git a/apps/web-antd/src/views/crm/permission/modules/list.vue b/apps/web-antd/src/views/crm/permission/modules/list.vue index 13f0fb723..2a2789ff9 100644 --- a/apps/web-antd/src/views/crm/permission/modules/list.vue +++ b/apps/web-antd/src/views/crm/permission/modules/list.vue @@ -94,32 +94,28 @@ function handleEdit() { } /** 删除团队成员 */ -function handleDelete() { +async function handleDelete() { if (checkedRows.value.length === 0) { message.error('请先选择团队成员后操作!'); return; } - return new Promise((resolve, reject) => { - confirm({ + try { + await confirm({ content: `你要将${checkedRows.value.map((item) => item.nickname).join(',')}移出团队吗?`, - }) - .then(async () => { - const res = await deletePermissionBatch( - checkedRows.value.map((item) => item.id!), - ); - if (res) { - // 提示并返回成功 - message.success($t('ui.actionMessage.operationSuccess')); - handleRefresh(); - resolve(true); - } else { - reject(new Error('移出失败')); - } - }) - .catch(() => { - reject(new Error('取消操作')); - }); - }); + }); + } catch { + return false; + } + const res = await deletePermissionBatch( + checkedRows.value.map((item) => item.id!), + ); + if (!res) { + throw new Error('移出失败'); + } + // 提示并返回成功 + message.success($t('ui.actionMessage.operationSuccess')); + handleRefresh(); + return true; } /** 退出团队 */ diff --git a/apps/web-antd/src/views/erp/finance/account/index.vue b/apps/web-antd/src/views/erp/finance/account/index.vue index 4ceb7abba..2a91dbe9a 100644 --- a/apps/web-antd/src/views/erp/finance/account/index.vue +++ b/apps/web-antd/src/views/erp/finance/account/index.vue @@ -65,23 +65,20 @@ async function handleDefaultStatusChange( newStatus: boolean, row: ErpAccountApi.Account, ): Promise { - return new Promise((resolve, reject) => { - const text = newStatus ? '设置' : '取消'; - confirm({ + const text = newStatus ? '设置' : '取消'; + try { + await confirm({ content: `确认要${text}"${row.name}"默认吗?`, - }) - .then(async () => { - // 更新默认状态 - await updateAccountDefaultStatus(row.id!, newStatus); - // 提示并返回成功 - message.success(`${text}默认成功`); - handleRefresh(); - resolve(true); - }) - .catch(() => { - reject(new Error('取消操作')); - }); - }); + }); + } catch { + return false; + } + // 更新默认状态 + await updateAccountDefaultStatus(row.id!, newStatus); + // 提示并返回成功 + message.success(`${text}默认成功`); + handleRefresh(); + return true; } const [Grid, gridApi] = useVbenVxeGrid({ diff --git a/apps/web-antd/src/views/erp/finance/payment/data.ts b/apps/web-antd/src/views/erp/finance/payment/data.ts index cd8e32712..771fd0c31 100644 --- a/apps/web-antd/src/views/erp/finance/payment/data.ts +++ b/apps/web-antd/src/views/erp/finance/payment/data.ts @@ -10,8 +10,11 @@ import { getSupplierSimpleList } from '#/api/erp/purchase/supplier'; import { getSimpleUserList } from '#/api/system/user'; import { getRangePickerDefaultProps } from '#/utils'; +/** 表单类型 */ +export type FormType = 'create' | 'detail' | 'edit'; + /** 表单的配置项 */ -export function useFormSchema(formType: string): VbenFormSchema[] { +export function useFormSchema(formType: FormType): VbenFormSchema[] { return [ { fieldName: 'id', diff --git a/apps/web-antd/src/views/erp/finance/payment/index.vue b/apps/web-antd/src/views/erp/finance/payment/index.vue index 03c88b777..d44b11be0 100644 --- a/apps/web-antd/src/views/erp/finance/payment/index.vue +++ b/apps/web-antd/src/views/erp/finance/payment/index.vue @@ -42,12 +42,12 @@ async function handleExport() { /** 新增付款单 */ function handleCreate() { - formModalApi.setData({ type: 'create' }).open(); + formModalApi.setData({ formType: 'create' }).open(); } /** 编辑付款单 */ function handleEdit(row: ErpFinancePaymentApi.FinancePayment) { - formModalApi.setData({ type: 'edit', id: row.id }).open(); + formModalApi.setData({ formType: 'edit', id: row.id }).open(); } /** 删除付款单 */ @@ -94,7 +94,7 @@ function handleRowCheckboxChange({ /** 查看详情 */ function handleDetail(row: ErpFinancePaymentApi.FinancePayment) { - formModalApi.setData({ type: 'detail', id: row.id }).open(); + formModalApi.setData({ formType: 'detail', id: row.id }).open(); } const [Grid, gridApi] = useVbenVxeGrid({ diff --git a/apps/web-antd/src/views/erp/finance/payment/modules/form.vue b/apps/web-antd/src/views/erp/finance/payment/modules/form.vue index 767bd13b2..25caa7b05 100644 --- a/apps/web-antd/src/views/erp/finance/payment/modules/form.vue +++ b/apps/web-antd/src/views/erp/finance/payment/modules/form.vue @@ -1,4 +1,6 @@ diff --git a/apps/web-antd/src/views/mes/md/item/modules/product-sop-form.vue b/apps/web-antd/src/views/mes/md/item/modules/product-sop-form.vue index 93a73a9b3..a9bb4f5b3 100644 --- a/apps/web-antd/src/views/mes/md/item/modules/product-sop-form.vue +++ b/apps/web-antd/src/views/mes/md/item/modules/product-sop-form.vue @@ -1,8 +1,10 @@ diff --git a/apps/web-antd/src/views/mes/md/vendor/data.ts b/apps/web-antd/src/views/mes/md/vendor/data.ts index 5f31bcf79..d40db4eac 100644 --- a/apps/web-antd/src/views/mes/md/vendor/data.ts +++ b/apps/web-antd/src/views/mes/md/vendor/data.ts @@ -13,6 +13,9 @@ import { z } from '#/adapter/form'; import { generateAutoCode } from '#/api/mes/md/autocode/record'; import { MesAutoCodeRuleCode } from '#/views/mes/utils/constants'; +/** 表单类型 */ +export type FormType = 'create' | 'detail' | 'update'; + /** 新增/修改供应商的表单 */ export function useFormSchema(formApi?: VbenFormApi): VbenFormSchema[] { return [ diff --git a/apps/web-antd/src/views/mes/md/vendor/index.vue b/apps/web-antd/src/views/mes/md/vendor/index.vue index e33be1f86..97afba8b7 100644 --- a/apps/web-antd/src/views/mes/md/vendor/index.vue +++ b/apps/web-antd/src/views/mes/md/vendor/index.vue @@ -32,17 +32,17 @@ function handleRefresh() { /** 创建供应商 */ function handleCreate() { - formModalApi.setData({ type: 'create' }).open(); + formModalApi.setData({ formType: 'create' }).open(); } /** 查看供应商 */ function handleDetail(row: MesMdVendorApi.Vendor) { - formModalApi.setData({ id: row.id, type: 'detail' }).open(); + formModalApi.setData({ id: row.id, formType: 'detail' }).open(); } /** 编辑供应商 */ function handleEdit(row: MesMdVendorApi.Vendor) { - formModalApi.setData({ id: row.id, type: 'update' }).open(); + formModalApi.setData({ id: row.id, formType: 'update' }).open(); } /** 删除供应商 */ diff --git a/apps/web-antd/src/views/mes/md/vendor/modules/form.vue b/apps/web-antd/src/views/mes/md/vendor/modules/form.vue index b45af94bb..f12e7c206 100644 --- a/apps/web-antd/src/views/mes/md/vendor/modules/form.vue +++ b/apps/web-antd/src/views/mes/md/vendor/modules/form.vue @@ -1,4 +1,6 @@ + + diff --git a/apps/web-antd/src/views/mes/pro/andon/config/components/index.ts b/apps/web-antd/src/views/mes/pro/andon/config/components/index.ts new file mode 100644 index 000000000..e7a766883 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/andon/config/components/index.ts @@ -0,0 +1 @@ +export { default as AndonConfigSelect } from './andon-config-select.vue'; diff --git a/apps/web-antd/src/views/mes/pro/andon/config/data.ts b/apps/web-antd/src/views/mes/pro/andon/config/data.ts new file mode 100644 index 000000000..42b7c1860 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/andon/config/data.ts @@ -0,0 +1,100 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesProAndonConfigApi } from '#/api/mes/pro/andon/config'; + +import { DICT_TYPE } from '@vben/constants'; +import { getDictOptions } from '@vben/hooks'; + +import { z } from '#/adapter/form'; +import { getSimpleRoleList } from '#/api/system/role'; +import { getSimpleUserList } from '#/api/system/user'; + +/** 安灯配置列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { field: 'reason', title: '呼叫原因', minWidth: 200 }, + { + field: 'level', + title: '级别', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_PRO_ANDON_LEVEL }, + }, + }, + { field: 'handlerRoleName', title: '处置角色', width: 140 }, + { field: 'handlerUserNickname', title: '处置人', width: 140 }, + { field: 'remark', title: '备注', minWidth: 160 }, + { + title: '操作', + width: 160, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** 新增/修改安灯配置的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'reason', + label: '呼叫原因', + component: 'Textarea', + componentProps: { + autoSize: { maxRows: 3, minRows: 1 }, + maxLength: 200, + placeholder: '请输入呼叫原因', + }, + rules: z.string().min(1, '呼叫原因不能为空').max(200), + }, + { + fieldName: 'level', + label: '级别', + component: 'Select', + componentProps: { + options: getDictOptions(DICT_TYPE.MES_PRO_ANDON_LEVEL, 'number'), + placeholder: '请选择级别', + }, + rules: 'selectRequired', + }, + { + fieldName: 'handlerRoleId', + label: '处置角色', + component: 'ApiSelect', + componentProps: { + allowClear: true, + api: getSimpleRoleList, + labelField: 'name', + placeholder: '请选择角色(与处置人至少填一个)', + valueField: 'id', + }, + }, + { + fieldName: 'handlerUserId', + label: '处置人', + component: 'ApiSelect', + componentProps: { + allowClear: true, + api: getSimpleUserList, + labelField: 'nickname', + placeholder: '请选择处置人(与角色至少填一个)', + valueField: 'id', + }, + }, + { + fieldName: 'remark', + label: '备注', + component: 'Input', + componentProps: { + maxLength: 100, + placeholder: '请输入备注', + }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mes/pro/andon/config/modules/form.vue b/apps/web-antd/src/views/mes/pro/andon/config/modules/form.vue new file mode 100644 index 000000000..e421a4d31 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/andon/config/modules/form.vue @@ -0,0 +1,94 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/andon/config/modules/list.vue b/apps/web-antd/src/views/mes/pro/andon/config/modules/list.vue new file mode 100644 index 000000000..0b992e320 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/andon/config/modules/list.vue @@ -0,0 +1,129 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/andon/record/data.ts b/apps/web-antd/src/views/mes/pro/andon/record/data.ts new file mode 100644 index 000000000..baafa5d1a --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/andon/record/data.ts @@ -0,0 +1,319 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesProAndonConfigApi } from '#/api/mes/pro/andon/config'; +import type { MesProAndonRecordApi } from '#/api/mes/pro/andon/record'; + +import { markRaw } from 'vue'; + +import { DICT_TYPE } from '@vben/constants'; +import { getDictOptions } from '@vben/hooks'; + +import { getSimpleUserList } from '#/api/system/user'; +import { getRangePickerDefaultProps } from '#/utils'; +import { MdWorkstationSelect } from '#/views/mes/md/workstation/components'; +import { ProProcessSelect } from '#/views/mes/pro/process/components'; +import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components'; +import { MesProWorkOrderStatusEnum } from '#/views/mes/utils/constants'; + +import { AndonConfigSelect } from '../config/components'; + +/** 表单类型 */ +export type FormType = 'create' | 'detail' | 'update'; + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'workstationId', + label: '工作站', + component: markRaw(MdWorkstationSelect), + componentProps: { + allowClear: true, + placeholder: '请选择工作站', + }, + }, + { + fieldName: 'userId', + label: '发起人', + component: 'ApiSelect', + componentProps: { + allowClear: true, + api: getSimpleUserList, + labelField: 'nickname', + placeholder: '请选择发起人', + valueField: 'id', + }, + }, + { + fieldName: 'handlerUserId', + label: '处置人', + component: 'ApiSelect', + componentProps: { + allowClear: true, + api: getSimpleUserList, + labelField: 'nickname', + placeholder: '请选择处置人', + valueField: 'id', + }, + }, + { + fieldName: 'status', + label: '处理状态', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.MES_PRO_ANDON_STATUS, 'number'), + placeholder: '请选择状态', + }, + }, + { + fieldName: 'createTime', + label: '发起时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { field: 'workstationCode', title: '工作站编码', width: 140 }, + { field: 'workstationName', title: '工作站名称', minWidth: 140 }, + { field: 'workOrderCode', title: '工单编码', width: 140 }, + { field: 'processName', title: '工序名称', width: 140 }, + { field: 'userNickname', title: '发起人', width: 110 }, + { + field: 'createTime', + title: '发起时间', + width: 180, + formatter: 'formatDateTime', + }, + { field: 'reason', title: '呼叫原因', minWidth: 160 }, + { + field: 'level', + title: '级别', + width: 90, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_PRO_ANDON_LEVEL }, + }, + }, + { + field: 'handleTime', + title: '处理时间', + width: 180, + formatter: 'formatDateTime', + }, + { field: 'handlerUserNickname', title: '处理人', width: 110 }, + { + field: 'status', + title: '处置状态', + width: 110, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_PRO_ANDON_STATUS }, + }, + }, + { + title: '操作', + width: 200, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** + * 新增/处置/详情安灯呼叫记录的表单 + * + * - create:录入呼叫主体信息(工作站/发起人/工单/工序/呼叫原因/备注) + * - update:呼叫主体只读展示创建时的快照字段(workstationName/workOrderCode/processName/reason),编辑处置时间/处置人/备注 + * - detail:所有字段只读 + */ +export function useFormSchema( + formType: FormType, + formApi?: VbenFormApi, +): VbenFormSchema[] { + const isCreate = formType === 'create'; + const isUpdate = formType === 'update'; + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + isCreate + ? { + fieldName: 'workstationId', + label: '工作站', + component: markRaw(MdWorkstationSelect), + componentProps: { + placeholder: '请选择工作站', + }, + rules: 'selectRequired', + } + : { + fieldName: 'workstationName', + label: '工作站', + component: 'Input', + componentProps: { + disabled: true, + }, + }, + isCreate + ? { + fieldName: 'userId', + label: '发起人', + component: 'ApiSelect', + componentProps: { + allowClear: true, + api: getSimpleUserList, + labelField: 'nickname', + placeholder: '请选择发起人', + valueField: 'id', + }, + } + : { + fieldName: 'userNickname', + label: '发起人', + component: 'Input', + componentProps: { + disabled: true, + }, + }, + isCreate + ? { + fieldName: 'workOrderId', + label: '生产工单', + component: markRaw(ProWorkOrderSelect), + componentProps: { + placeholder: '请选择工单(可选)', + status: MesProWorkOrderStatusEnum.CONFIRMED, + }, + } + : { + fieldName: 'workOrderCode', + label: '生产工单', + component: 'Input', + componentProps: { + disabled: true, + }, + }, + isCreate + ? { + fieldName: 'processId', + label: '工序', + component: markRaw(ProProcessSelect), + componentProps: { + placeholder: '请选择工序(可选)', + }, + } + : { + fieldName: 'processName', + label: '工序', + component: 'Input', + componentProps: { + disabled: true, + }, + }, + isCreate + ? { + fieldName: 'configId', + label: '呼叫原因', + component: markRaw(AndonConfigSelect), + componentProps: { + // 选择呼叫原因后,自动填充对应的级别 + onChange: async (config?: MesProAndonConfigApi.AndonConfig) => { + await formApi?.setValues({ + level: config?.level, + reason: config?.reason, + }); + }, + }, + rules: 'selectRequired', + } + : { + fieldName: 'reason', + label: '呼叫原因', + component: 'Input', + componentProps: { + disabled: true, + }, + }, + { + fieldName: 'level', + label: '级别', + component: 'Select', + componentProps: { + disabled: true, + options: getDictOptions(DICT_TYPE.MES_PRO_ANDON_LEVEL, 'number'), + placeholder: '由呼叫原因自动带出', + }, + }, + // 处置信息:update / detail 模式才展示 + ...(isCreate + ? [] + : ([ + { + fieldName: 'status', + label: '状态', + component: 'Select', + componentProps: { + disabled: true, + options: getDictOptions( + DICT_TYPE.MES_PRO_ANDON_STATUS, + 'number', + ), + }, + }, + { + fieldName: 'handleTime', + label: '处置时间', + component: 'DatePicker', + componentProps: { + disabled: !isUpdate, + format: 'YYYY-MM-DD HH:mm:ss', + placeholder: '请选择处置时间', + showTime: true, + valueFormat: 'x', + }, + }, + isUpdate + ? { + fieldName: 'handlerUserId', + label: '处置人', + component: 'ApiSelect', + componentProps: { + allowClear: true, + api: getSimpleUserList, + labelField: 'nickname', + placeholder: '请选择处置人', + valueField: 'id', + }, + } + : { + fieldName: 'handlerUserNickname', + label: '处置人', + component: 'Input', + componentProps: { + disabled: true, + }, + }, + ] as VbenFormSchema[])), + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + componentProps: { + disabled: formType === 'detail', + maxLength: 250, + placeholder: '请输入备注', + rows: 2, + }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mes/pro/andon/record/index.vue b/apps/web-antd/src/views/mes/pro/andon/record/index.vue new file mode 100644 index 000000000..d6b256fbc --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/andon/record/index.vue @@ -0,0 +1,174 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/andon/record/modules/form.vue b/apps/web-antd/src/views/mes/pro/andon/record/modules/form.vue new file mode 100644 index 000000000..1b7272681 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/andon/record/modules/form.vue @@ -0,0 +1,184 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/feedback/data.ts b/apps/web-antd/src/views/mes/pro/feedback/data.ts new file mode 100644 index 000000000..cfd5a5015 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/feedback/data.ts @@ -0,0 +1,578 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesProFeedbackApi } from '#/api/mes/pro/feedback'; +import type { MesProTaskApi } from '#/api/mes/pro/task'; + +import { h, markRaw } from 'vue'; + +import { DICT_TYPE } from '@vben/constants'; +import { getDictOptions } from '@vben/hooks'; + +import { Button } from 'ant-design-vue'; + +import { generateAutoCode } from '#/api/mes/md/autocode/record'; +import { getRouteProcessByRouteAndProcess } from '#/api/mes/pro/route/process'; +import { getSimpleUserList } from '#/api/system/user'; +import { getRangePickerDefaultProps } from '#/utils'; +import { MdItemSelect } from '#/views/mes/md/item/components'; +import { MdWorkstationSelect } from '#/views/mes/md/workstation/components'; +import { ProTaskSelect } from '#/views/mes/pro/task/components'; +import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components'; +import { + MesAutoCodeRuleCode, + MesProTaskStatusEnum, + MesProWorkOrderStatusEnum, +} from '#/views/mes/utils/constants'; + +/** 生产报工表单类型 */ +export type FormType = 'approve' | 'create' | 'detail' | 'submit' | 'update'; + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'code', + label: '报工单号', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入报工单号', + }, + }, + { + fieldName: 'type', + label: '报工类型', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.MES_PRO_FEEDBACK_TYPE, 'number'), + placeholder: '请选择报工类型', + }, + }, + { + fieldName: 'workOrderId', + label: '生产工单', + component: markRaw(ProWorkOrderSelect), + componentProps: { + allowClear: true, + placeholder: '请选择工单', + }, + }, + { + fieldName: 'itemId', + label: '产品物料', + component: markRaw(MdItemSelect), + componentProps: { + allowClear: true, + placeholder: '请选择产品物料', + }, + }, + { + fieldName: 'feedbackUserId', + label: '报工人', + component: 'ApiSelect', + componentProps: { + allowClear: true, + api: getSimpleUserList, + labelField: 'nickname', + placeholder: '请选择报工人', + valueField: 'id', + }, + }, + { + fieldName: 'creator', + label: '记录人', + component: 'ApiSelect', + componentProps: { + allowClear: true, + api: getSimpleUserList, + labelField: 'nickname', + placeholder: '请选择记录人', + valueField: 'id', + }, + }, + { + fieldName: 'status', + label: '状态', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.MES_PRO_FEEDBACK_STATUS, 'number'), + placeholder: '请选择状态', + }, + }, + { + fieldName: 'feedbackTime', + label: '报工时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'code', + title: '报工单号', + width: 160, + slots: { default: 'code' }, + }, + { + field: 'type', + title: '报工类型', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_PRO_FEEDBACK_TYPE }, + }, + }, + { field: 'workstationName', title: '工作站', width: 120 }, + { field: 'processName', title: '工序', width: 100 }, + { field: 'workOrderCode', title: '生产工单编码', width: 160 }, + { field: 'itemCode', title: '产品物料编码', width: 120 }, + { field: 'itemName', title: '产品物料名称', minWidth: 140 }, + { field: 'itemSpecification', title: '规格型号', width: 120 }, + { field: 'unitMeasureName', title: '单位', width: 80 }, + { field: 'feedbackQuantity', title: '报工数量', width: 100 }, + { field: 'feedbackUserNickname', title: '报工人', width: 100 }, + { + field: 'feedbackTime', + title: '报工时间', + width: 180, + formatter: 'formatDateTime', + }, + { field: 'approveUserNickname', title: '审核人', width: 100 }, + { + field: 'status', + title: '状态', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_PRO_FEEDBACK_STATUS }, + }, + }, + { + title: '操作', + width: 240, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** + * 新增/编辑/提交/审批/详情生产报工的表单 + * + * - create / update:录入报工主体信息和数量 + * - submit / approve / detail:主体字段只读 + * + * 数量区域根据 `checkFlag` 和 `unqualifiedQuantity` 动态显示: + * - 非质检工序:报工数量 = 合格 + 不良;不良 > 0 时再展开工废/料废/其他废品 + * - 质检工序:只填报工数量(视为待检数量) + */ +export function useFormSchema( + formType: FormType, + formApi?: VbenFormApi, +): VbenFormSchema[] { + const isHeaderReadonly = ['approve', 'detail', 'submit'].includes(formType); + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'checkFlag', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + defaultValue: true, + }, + { + fieldName: 'routeId', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'processId', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'itemId', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'code', + label: '报工单号', + component: 'Input', + componentProps: { + disabled: isHeaderReadonly, + placeholder: '请输入报工单号', + }, + rules: 'required', + suffix: () => + h( + Button, + { + disabled: isHeaderReadonly, + type: 'default', + onClick: async () => { + const code = await generateAutoCode( + MesAutoCodeRuleCode.PRO_FEEDBACK_CODE, + ); + await formApi?.setFieldValue('code', code); + }, + }, + { default: () => '生成' }, + ), + }, + { + fieldName: 'type', + label: '报工类型', + component: 'Select', + componentProps: { + disabled: isHeaderReadonly, + options: getDictOptions(DICT_TYPE.MES_PRO_FEEDBACK_TYPE, 'number'), + placeholder: '请选择报工类型', + }, + rules: 'required', + }, + { + fieldName: 'workOrderId', + label: '生产工单', + component: markRaw(ProWorkOrderSelect), + componentProps: { + disabled: isHeaderReadonly, + placeholder: '请选择工单', + status: MesProWorkOrderStatusEnum.CONFIRMED, + // 工单变更:清空任务及任务带出的产品信息、数量区域控制位 + onChange: async () => { + await formApi?.setValues({ + checkFlag: true, + itemCode: undefined, + itemId: undefined, + itemName: undefined, + itemSpecification: undefined, + processId: undefined, + routeId: undefined, + taskId: undefined, + unitMeasureName: undefined, + workstationId: undefined, + }); + }, + }, + rules: 'selectRequired', + }, + { + fieldName: 'taskId', + label: '生产任务', + component: markRaw(ProTaskSelect), + dependencies: { + triggerFields: ['workOrderId', 'workstationId'], + componentProps: (values) => ({ + disabled: isHeaderReadonly || !values.workOrderId, + placeholder: values.workOrderId ? '请选择任务' : '请先选择工单', + statuses: [MesProTaskStatusEnum.PREPARE], + workOrderId: values.workOrderId, + workstationId: values.workstationId, + }), + }, + // 任务变更:自动填充关联字段、产品信息、checkFlag + componentProps: { + onChange: async (task?: MesProTaskApi.Task) => { + if (!task) { + return; + } + await formApi?.setValues({ + itemCode: task.itemCode, + itemId: task.itemId, + itemName: task.itemName, + itemSpecification: task.itemSpecification, + processId: task.processId, + routeId: task.routeId, + unitMeasureName: task.unitMeasureName, + workstationId: task.workstationId, + }); + // 工艺路线工序的 checkFlag 决定数量区域展示 + if (task.routeId && task.processId) { + try { + const routeProcess = await getRouteProcessByRouteAndProcess( + task.routeId, + task.processId, + ); + await formApi?.setFieldValue( + 'checkFlag', + routeProcess?.checkFlag ?? false, + ); + } catch { + await formApi?.setFieldValue('checkFlag', true); + } + } + }, + }, + rules: 'selectRequired', + }, + { + fieldName: 'workstationId', + label: '工作站', + component: markRaw(MdWorkstationSelect), + componentProps: { + disabled: isHeaderReadonly, + placeholder: '请选择工作站', + }, + rules: 'selectRequired', + }, + { + fieldName: 'itemCode', + label: '产品编码', + component: 'Input', + componentProps: { disabled: true }, + dependencies: { + triggerFields: ['itemCode'], + show: (values) => !!values.itemCode, + }, + }, + { + fieldName: 'itemName', + label: '产品名称', + component: 'Input', + componentProps: { disabled: true }, + dependencies: { + triggerFields: ['itemCode'], + show: (values) => !!values.itemCode, + }, + }, + { + fieldName: 'unitMeasureName', + label: '单位', + component: 'Input', + componentProps: { disabled: true }, + dependencies: { + triggerFields: ['itemCode'], + show: (values) => !!values.itemCode, + }, + }, + { + fieldName: 'itemSpecification', + label: '规格', + component: 'Input', + componentProps: { disabled: true }, + dependencies: { + triggerFields: ['itemCode'], + show: (values) => !!values.itemCode, + }, + }, + { + fieldName: 'feedbackQuantity', + label: '报工数量', + component: 'InputNumber', + componentProps: { class: 'w-full', min: 0, precision: 2 }, + dependencies: { + triggerFields: ['checkFlag'], + // 非质检工序时,报工数量 = 合格 + 不良,禁用直接编辑 + componentProps: (values) => ({ + class: 'w-full', + disabled: !values.checkFlag, + min: 0, + placeholder: '请输入报工数量', + precision: 2, + }), + }, + rules: 'required', + }, + { + fieldName: 'qualifiedQuantity', + label: '合格品数量', + component: 'InputNumber', + componentProps: { + class: 'w-full', + min: 0, + precision: 2, + // 合格/不良变更,自动累计为报工数量 + onChange: async () => { + const values = await formApi?.getValues(); + await formApi?.setFieldValue( + 'feedbackQuantity', + (values?.qualifiedQuantity || 0) + + (values?.unqualifiedQuantity || 0), + ); + }, + }, + defaultValue: 0, + dependencies: { + triggerFields: ['checkFlag'], + show: (values) => !values.checkFlag, + }, + }, + { + fieldName: 'unqualifiedQuantity', + label: '不良品数量', + component: 'InputNumber', + componentProps: { + class: 'w-full', + min: 0, + precision: 2, + // 合格/不良变更,自动累计为报工数量 + onChange: async () => { + const values = await formApi?.getValues(); + await formApi?.setFieldValue( + 'feedbackQuantity', + (values?.qualifiedQuantity || 0) + + (values?.unqualifiedQuantity || 0), + ); + }, + }, + defaultValue: 0, + dependencies: { + triggerFields: ['checkFlag'], + show: (values) => !values.checkFlag, + }, + }, + { + fieldName: 'laborScrapQuantity', + label: '工废数量', + component: 'InputNumber', + componentProps: { + class: 'w-full', + min: 0, + precision: 2, + // 废品分类变更,自动累计为不良品数量及报工数量 + onChange: async () => { + const values = await formApi?.getValues(); + const unqualified = + (values?.laborScrapQuantity || 0) + + (values?.materialScrapQuantity || 0) + + (values?.otherScrapQuantity || 0); + await formApi?.setValues({ + feedbackQuantity: + (values?.qualifiedQuantity || 0) + unqualified, + unqualifiedQuantity: unqualified, + }); + }, + }, + defaultValue: 0, + dependencies: { + triggerFields: ['checkFlag', 'unqualifiedQuantity'], + show: (values) => + !values.checkFlag && (values.unqualifiedQuantity || 0) > 0, + }, + }, + { + fieldName: 'materialScrapQuantity', + label: '料废数量', + component: 'InputNumber', + componentProps: { + class: 'w-full', + min: 0, + precision: 2, + // 废品分类变更,自动累计为不良品数量及报工数量 + onChange: async () => { + const values = await formApi?.getValues(); + const unqualified = + (values?.laborScrapQuantity || 0) + + (values?.materialScrapQuantity || 0) + + (values?.otherScrapQuantity || 0); + await formApi?.setValues({ + feedbackQuantity: + (values?.qualifiedQuantity || 0) + unqualified, + unqualifiedQuantity: unqualified, + }); + }, + }, + defaultValue: 0, + dependencies: { + triggerFields: ['checkFlag', 'unqualifiedQuantity'], + show: (values) => + !values.checkFlag && (values.unqualifiedQuantity || 0) > 0, + }, + }, + { + fieldName: 'otherScrapQuantity', + label: '其他废品', + component: 'InputNumber', + componentProps: { + class: 'w-full', + min: 0, + precision: 2, + // 废品分类变更,自动累计为不良品数量及报工数量 + onChange: async () => { + const values = await formApi?.getValues(); + const unqualified = + (values?.laborScrapQuantity || 0) + + (values?.materialScrapQuantity || 0) + + (values?.otherScrapQuantity || 0); + await formApi?.setValues({ + feedbackQuantity: + (values?.qualifiedQuantity || 0) + unqualified, + unqualifiedQuantity: unqualified, + }); + }, + }, + defaultValue: 0, + dependencies: { + triggerFields: ['checkFlag', 'unqualifiedQuantity'], + show: (values) => + !values.checkFlag && (values.unqualifiedQuantity || 0) > 0, + }, + }, + { + fieldName: 'feedbackUserId', + label: '报工人', + component: 'ApiSelect', + componentProps: { + allowClear: true, + api: getSimpleUserList, + disabled: isHeaderReadonly, + labelField: 'nickname', + placeholder: '请选择报工人', + valueField: 'id', + }, + rules: 'selectRequired', + }, + { + fieldName: 'feedbackTime', + label: '报工时间', + component: 'DatePicker', + componentProps: { + class: 'w-full', + disabled: isHeaderReadonly, + format: 'YYYY-MM-DD HH:mm:ss', + placeholder: '请选择报工时间', + showTime: true, + valueFormat: 'x', + }, + rules: 'required', + }, + { + fieldName: 'approveUserId', + label: '审核人', + component: 'ApiSelect', + componentProps: { + allowClear: true, + api: getSimpleUserList, + disabled: isHeaderReadonly, + labelField: 'nickname', + placeholder: '请选择审核人', + valueField: 'id', + }, + rules: 'selectRequired', + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + disabled: formType === 'detail', + placeholder: '请输入备注', + rows: 3, + }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mes/pro/feedback/index.vue b/apps/web-antd/src/views/mes/pro/feedback/index.vue new file mode 100644 index 000000000..b3ad35785 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/feedback/index.vue @@ -0,0 +1,182 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/feedback/modules/form.vue b/apps/web-antd/src/views/mes/pro/feedback/modules/form.vue new file mode 100644 index 000000000..d0c8a84ce --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/feedback/modules/form.vue @@ -0,0 +1,317 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/feedback/modules/item-consume-list.vue b/apps/web-antd/src/views/mes/pro/feedback/modules/item-consume-list.vue new file mode 100644 index 000000000..0af4f897d --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/feedback/modules/item-consume-list.vue @@ -0,0 +1,61 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/feedback/modules/product-produce-list.vue b/apps/web-antd/src/views/mes/pro/feedback/modules/product-produce-list.vue new file mode 100644 index 000000000..c526f6fbb --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/feedback/modules/product-produce-list.vue @@ -0,0 +1,72 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/process/components/pro-process-select.vue b/apps/web-antd/src/views/mes/pro/process/components/pro-process-select.vue index ad50ee802..b174168d4 100644 --- a/apps/web-antd/src/views/mes/pro/process/components/pro-process-select.vue +++ b/apps/web-antd/src/views/mes/pro/process/components/pro-process-select.vue @@ -39,12 +39,13 @@ const selectValue = computed({ }, }); +/** 前端过滤:按工序名称或编码模糊匹配 */ function handleFilter(input: string, option: any) { const keyword = input.toLowerCase(); const item = option?.item as MesProProcessApi.Process | undefined; return Boolean( item?.name?.toLowerCase().includes(keyword) || - item?.code?.toLowerCase().includes(keyword), + item?.code?.toLowerCase().includes(keyword), ); } diff --git a/apps/web-antd/src/views/mes/pro/process/data.ts b/apps/web-antd/src/views/mes/pro/process/data.ts new file mode 100644 index 000000000..e64f78986 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/process/data.ts @@ -0,0 +1,275 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesProProcessApi } from '#/api/mes/pro/process'; +import type { MesProProcessContentApi } from '#/api/mes/pro/process/content'; + +import { h } from 'vue'; + +import { CommonStatusEnum, DICT_TYPE } from '@vben/constants'; +import { getDictOptions } from '@vben/hooks'; + +import { Button } from 'ant-design-vue'; + +import { z } from '#/adapter/form'; +import { generateAutoCode } from '#/api/mes/md/autocode/record'; +import { MesAutoCodeRuleCode } from '#/views/mes/utils/constants'; + +/** 表单类型 */ +export type FormType = 'create' | 'detail' | 'update'; + +/** 新增/修改生产工序的表单 */ +export function useFormSchema(formApi?: VbenFormApi): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'code', + label: '工序编码', + component: 'Input', + componentProps: { + maxLength: 64, + placeholder: '请输入工序编码', + }, + rules: z.string().min(1, '工序编码不能为空').max(64), + suffix: () => + h( + Button, + { + type: 'default', + onClick: async () => { + try { + const code = await generateAutoCode( + MesAutoCodeRuleCode.PRO_PROCESS_CODE, + ); + await formApi?.setFieldValue('code', code); + } catch (error) { + console.error(error); + } + }, + }, + { default: () => '生成' }, + ), + }, + { + fieldName: 'name', + label: '工序名称', + component: 'Input', + componentProps: { + maxLength: 100, + placeholder: '请输入工序名称', + }, + rules: z.string().min(1, '工序名称不能为空').max(100), + }, + { + fieldName: 'status', + label: '状态', + component: 'RadioGroup', + componentProps: { + buttonStyle: 'solid', + optionType: 'button', + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + rules: z.number().default(CommonStatusEnum.ENABLE), + }, + { + fieldName: 'attention', + label: '工序说明', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + maxLength: 500, + placeholder: '请输入工序说明', + rows: 3, + }, + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + maxLength: 250, + 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: 'status', + label: '状态', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + placeholder: '请选择状态', + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'code', + title: '工序编码', + minWidth: 150, + slots: { + default: 'code', + }, + }, + { field: 'name', title: '工序名称', minWidth: 180 }, + { + field: 'status', + title: '状态', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + }, + { field: 'remark', title: '备注', minWidth: 180 }, + { + field: 'createTime', + title: '创建时间', + width: 180, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 150, + fixed: 'right', + slots: { + default: 'actions', + }, + }, + ]; +} + +/** 工序内容(操作步骤)表单 */ +export function useContentFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'processId', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'sort', + label: '序号', + component: 'InputNumber', + componentProps: { + class: '!w-full', + max: 999, + min: 1, + precision: 0, + }, + rules: z.number().default(1), + }, + { + fieldName: 'content', + label: '步骤说明', + component: 'Textarea', + componentProps: { + maxLength: 500, + placeholder: '请输入步骤说明', + rows: 3, + }, + }, + { + fieldName: 'device', + label: '辅助设备', + component: 'Input', + componentProps: { + maxLength: 100, + placeholder: '请输入辅助设备', + }, + }, + { + fieldName: 'material', + label: '辅助材料', + component: 'Input', + componentProps: { + maxLength: 100, + placeholder: '请输入辅助材料', + }, + }, + { + fieldName: 'docUrl', + label: '材料文档 URL', + component: 'Input', + componentProps: { + maxLength: 250, + placeholder: '请输入材料文档 URL', + }, + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + componentProps: { + maxLength: 250, + placeholder: '请输入备注', + rows: 2, + }, + }, + ]; +} + +/** 工序内容列表的字段 */ +export function useContentGridColumns(): VxeTableGridOptions['columns'] { + return [ + { field: 'sort', title: '序号', width: 80, align: 'center' }, + { field: 'content', title: '步骤说明', minWidth: 220 }, + { field: 'device', title: '辅助设备', width: 150 }, + { field: 'material', title: '辅助材料', width: 150 }, + { field: 'docUrl', title: '材料文档', minWidth: 180 }, + { field: 'remark', title: '备注', minWidth: 160 }, + { + title: '操作', + width: 130, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mes/pro/process/index.vue b/apps/web-antd/src/views/mes/pro/process/index.vue new file mode 100644 index 000000000..8f86eaaa9 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/process/index.vue @@ -0,0 +1,158 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/process/modules/content-form.vue b/apps/web-antd/src/views/mes/pro/process/modules/content-form.vue new file mode 100644 index 000000000..eb4270b25 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/process/modules/content-form.vue @@ -0,0 +1,99 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/process/modules/content-list.vue b/apps/web-antd/src/views/mes/pro/process/modules/content-list.vue new file mode 100644 index 000000000..3f64fcd52 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/process/modules/content-list.vue @@ -0,0 +1,132 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/process/modules/form.vue b/apps/web-antd/src/views/mes/pro/process/modules/form.vue new file mode 100644 index 000000000..a3d910c8d --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/process/modules/form.vue @@ -0,0 +1,117 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/route/components/color-picker.vue b/apps/web-antd/src/views/mes/pro/route/components/color-picker.vue new file mode 100644 index 000000000..76623fcb0 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/route/components/color-picker.vue @@ -0,0 +1,66 @@ + + + + + diff --git a/apps/web-antd/src/views/mes/pro/route/components/index.ts b/apps/web-antd/src/views/mes/pro/route/components/index.ts new file mode 100644 index 000000000..4a78a4ce4 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/route/components/index.ts @@ -0,0 +1 @@ +export { default as RouteColorPicker } from './color-picker.vue'; diff --git a/apps/web-antd/src/views/mes/pro/route/data.ts b/apps/web-antd/src/views/mes/pro/route/data.ts new file mode 100644 index 000000000..c73686165 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/route/data.ts @@ -0,0 +1,471 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesProRouteApi } from '#/api/mes/pro/route'; +import type { MesProRouteProcessApi } from '#/api/mes/pro/route/process'; +import type { MesProRouteProductApi } from '#/api/mes/pro/route/product'; +import type { MesProRouteProductBomApi } from '#/api/mes/pro/route/productbom'; + +import { h } from 'vue'; + +import { CommonStatusEnum, DICT_TYPE } from '@vben/constants'; +import { getDictOptions } from '@vben/hooks'; + +import { Button } from 'ant-design-vue'; + +import { z } from '#/adapter/form'; +import { generateAutoCode } from '#/api/mes/md/autocode/record'; +import { + MdItemSelect, + MdProductBomSelect, +} from '#/views/mes/md/item/components'; +import { MesAutoCodeRuleCode } from '#/views/mes/utils/constants'; + +import { RouteColorPicker } from './components'; + +/** 表单类型 */ +export type FormType = 'create' | 'detail' | 'update'; + +/** 工艺路线表单 */ +export function useFormSchema(formApi?: VbenFormApi): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'code', + label: '路线编码', + component: 'Input', + componentProps: { + maxLength: 64, + placeholder: '请输入工艺路线编码', + }, + rules: z.string().min(1, '路线编码不能为空').max(64), + suffix: () => + h( + Button, + { + type: 'default', + onClick: async () => { + try { + const code = await generateAutoCode( + MesAutoCodeRuleCode.PRO_ROUTE_CODE, + ); + await formApi?.setFieldValue('code', code); + } catch (error) { + console.error(error); + } + }, + }, + { default: () => '生成' }, + ), + }, + { + fieldName: 'name', + label: '路线名称', + component: 'Input', + componentProps: { + maxLength: 100, + placeholder: '请输入工艺路线名称', + }, + rules: z.string().min(1, '路线名称不能为空').max(100), + }, + { + fieldName: 'description', + label: '路线说明', + component: 'Textarea', + formItemClass: 'col-span-2', + componentProps: { + maxLength: 500, + placeholder: '请输入工艺路线说明', + rows: 3, + }, + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-2', + componentProps: { + maxLength: 250, + placeholder: '请输入备注', + rows: 2, + }, + }, + ]; +} + +/** 列表搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'code', + label: '路线编码', + component: 'Input', + componentProps: { allowClear: true, placeholder: '请输入路线编码' }, + }, + { + fieldName: 'name', + label: '路线名称', + component: 'Input', + componentProps: { allowClear: true, placeholder: '请输入路线名称' }, + }, + { + fieldName: 'status', + label: '状态', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + placeholder: '请选择状态', + }, + }, + ]; +} + +/** 列表字段 */ +export function useGridColumns( + onStatusChange?: ( + newStatus: number, + row: MesProRouteApi.Route, + ) => PromiseLike, + statusEditable = true, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'code', + title: '路线编码', + minWidth: 160, + slots: { default: 'code' }, + }, + { field: 'name', title: '路线名称', minWidth: 180 }, + { field: 'description', title: '路线说明', minWidth: 200 }, + { + field: 'status', + title: '状态', + width: 110, + align: 'center', + cellRender: { + attrs: { beforeChange: onStatusChange }, + name: 'CellSwitch', + props: { + checkedValue: CommonStatusEnum.ENABLE, + disabled: !statusEditable, + unCheckedValue: CommonStatusEnum.DISABLE, + }, + }, + }, + { field: 'remark', title: '备注', minWidth: 160 }, + { + field: 'createTime', + title: '创建时间', + width: 180, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 160, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** 工艺路线工序明细表单 */ +export function useRouteProcessFormSchema( + processOptions: Array<{ label: string; value: number }>, +): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'routeId', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'sort', + label: '序号', + component: 'InputNumber', + componentProps: { class: '!w-full', min: 1, precision: 0 }, + rules: z.number().default(1), + }, + { + fieldName: 'processId', + label: '工序', + component: 'Select', + componentProps: { + allowClear: true, + options: processOptions, + placeholder: '请选择工序', + showSearch: true, + }, + rules: 'selectRequired', + }, + { + fieldName: 'linkType', + label: '与下道工序关系', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.MES_PRO_LINK_TYPE, 'number'), + placeholder: '请选择', + }, + rules: z.number().default(3), + }, + { + fieldName: 'colorCode', + label: '甘特图颜色', + component: RouteColorPicker, + }, + { + fieldName: 'keyFlag', + label: '是否关键工序', + component: 'Switch', + componentProps: { checkedChildren: '是', unCheckedChildren: '否' }, + rules: z.boolean().default(false), + }, + { + fieldName: 'checkFlag', + label: '是否质检确认', + component: 'Switch', + componentProps: { checkedChildren: '是', unCheckedChildren: '否' }, + rules: z.boolean().default(false), + }, + { + fieldName: 'prepareTime', + label: '准备时间(分)', + component: 'InputNumber', + componentProps: { class: '!w-full', min: 0, precision: 0 }, + rules: z.number().default(0), + }, + { + fieldName: 'waitTime', + label: '等待时间(分)', + component: 'InputNumber', + componentProps: { class: '!w-full', min: 0, precision: 0 }, + rules: z.number().default(0), + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-2', + componentProps: { maxLength: 250, placeholder: '请输入备注', rows: 2 }, + }, + ]; +} + +/** 工艺路线工序列表字段 */ +export function useRouteProcessGridColumns(): VxeTableGridOptions['columns'] { + return [ + { field: 'sort', title: '序号', width: 70, align: 'center', fixed: 'left' }, + { field: 'processCode', title: '工序编码', width: 140, fixed: 'left' }, + { field: 'processName', title: '工序名称', width: 140, fixed: 'left' }, + { field: 'nextProcessName', title: '下一道工序', width: 140 }, + { + field: 'linkType', + title: '与下一道工序关系', + width: 160, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_PRO_LINK_TYPE }, + }, + }, + { + field: 'keyFlag', + title: '关键工序', + width: 90, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + }, + { + field: 'checkFlag', + title: '质检确认', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + }, + { field: 'prepareTime', title: '准备时间(分)', width: 110 }, + { field: 'waitTime', title: '等待时间(分)', width: 110 }, + { + field: 'colorCode', + title: '甘特图颜色', + width: 130, + slots: { default: 'colorCode' }, + }, + { field: 'remark', title: '备注', minWidth: 160 }, + { + title: '操作', + width: 130, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** 工艺路线产品列表字段 */ +export function useRouteProductGridColumns(): VxeTableGridOptions['columns'] { + return [ + { field: 'itemCode', title: '产品物料编码', width: 150 }, + { field: 'itemName', title: '产品物料名称', width: 150 }, + { field: 'specification', title: '规格型号', width: 150 }, + { field: 'unitName', title: '单位', width: 80 }, + { field: 'quantity', title: '生产数量', width: 100 }, + { + field: 'productionTime', + title: '生产用时', + width: 130, + slots: { default: 'productionTime' }, + }, + { field: 'remark', title: '备注', minWidth: 160 }, + { + title: '操作', + width: 130, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** 工艺路线产品 BOM 列表字段 */ +export function useRouteProductBomGridColumns(): VxeTableGridOptions['columns'] { + return [ + { field: 'itemCode', title: 'BOM 物料编码', width: 150 }, + { field: 'itemName', title: 'BOM 物料名称', width: 150 }, + { field: 'specification', title: '规格型号', width: 150 }, + { field: 'unitName', title: '单位', width: 80 }, + { field: 'quantity', title: '用料比例', width: 100 }, + { field: 'remark', title: '备注', minWidth: 160 }, + { + title: '操作', + width: 130, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + + +/** 工艺路线产品表单 */ +export function useRouteProductFormSchema( + onItemChange?: (item: any) => void, +): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'routeId', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + // 产品物料:使用业务自定义选择器,change 回填编码/名称/规格/单位 + { + fieldName: 'itemId', + label: '产品', + component: MdItemSelect as any, + componentProps: { + onChange: onItemChange, + }, + formItemClass: 'col-span-2', + rules: 'selectRequired', + }, + { + fieldName: 'quantity', + label: '生产数量', + component: 'InputNumber', + componentProps: { class: '!w-full', min: 1, precision: 0 }, + rules: z.number().default(1), + }, + { + fieldName: 'productionTime', + label: '生产用时', + component: 'InputNumber', + componentProps: { class: '!w-full', min: 0, precision: 2 }, + rules: z.number().default(1), + }, + { + fieldName: 'timeUnitType', + label: '时间单位', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.MES_TIME_UNIT_TYPE), + placeholder: '请选择', + }, + rules: z.string().default('MINUTE'), + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-2', + componentProps: { maxLength: 250, placeholder: '请输入备注', rows: 2 }, + }, + ]; +} + +/** 工艺路线产品 BOM 表单 */ +export function useRouteProductBomFormSchema( + itemId: () => number, + onBomChange?: (bom: any) => void, +): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'routeId', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'processId', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'productId', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + // BOM 物料:依赖产品物料,使用业务自定义选择器 + { + fieldName: 'itemId', + label: 'BOM 物料', + component: MdProductBomSelect as any, + componentProps: () => ({ + itemId: itemId(), + onChange: onBomChange, + placeholder: '请选择 BOM 物料', + }), + rules: 'selectRequired', + }, + { + fieldName: 'quantity', + label: '用料比例', + component: 'InputNumber', + componentProps: { class: '!w-full', min: 0, precision: 2 }, + rules: z.number().default(1), + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + componentProps: { maxLength: 250, placeholder: '请输入备注', rows: 2 }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mes/pro/route/index.vue b/apps/web-antd/src/views/mes/pro/route/index.vue new file mode 100644 index 000000000..c19854837 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/route/index.vue @@ -0,0 +1,188 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/route/modules/bom-form.vue b/apps/web-antd/src/views/mes/pro/route/modules/bom-form.vue new file mode 100644 index 000000000..8e2f4c243 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/route/modules/bom-form.vue @@ -0,0 +1,119 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/route/modules/form.vue b/apps/web-antd/src/views/mes/pro/route/modules/form.vue new file mode 100644 index 000000000..f381fe8d2 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/route/modules/form.vue @@ -0,0 +1,124 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/route/modules/process-form.vue b/apps/web-antd/src/views/mes/pro/route/modules/process-form.vue new file mode 100644 index 000000000..d4f7681fa --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/route/modules/process-form.vue @@ -0,0 +1,122 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/route/modules/process-list.vue b/apps/web-antd/src/views/mes/pro/route/modules/process-list.vue new file mode 100644 index 000000000..192cb5c5b --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/route/modules/process-list.vue @@ -0,0 +1,136 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/route/modules/product-bom-list.vue b/apps/web-antd/src/views/mes/pro/route/modules/product-bom-list.vue new file mode 100644 index 000000000..78ac67284 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/route/modules/product-bom-list.vue @@ -0,0 +1,171 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/route/modules/product-form.vue b/apps/web-antd/src/views/mes/pro/route/modules/product-form.vue new file mode 100644 index 000000000..47ce4ba12 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/route/modules/product-form.vue @@ -0,0 +1,126 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/route/modules/product-list.vue b/apps/web-antd/src/views/mes/pro/route/modules/product-list.vue new file mode 100644 index 000000000..ea34d58a3 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/route/modules/product-list.vue @@ -0,0 +1,134 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/task/components/index.ts b/apps/web-antd/src/views/mes/pro/task/components/index.ts new file mode 100644 index 000000000..3847bb912 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/task/components/index.ts @@ -0,0 +1,2 @@ +export { default as ProTaskSelectDialog } from './pro-task-select-dialog.vue'; +export { default as ProTaskSelect } from './pro-task-select.vue'; diff --git a/apps/web-antd/src/views/mes/pro/task/components/pro-task-select-dialog.vue b/apps/web-antd/src/views/mes/pro/task/components/pro-task-select-dialog.vue new file mode 100644 index 000000000..da32b86d3 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/task/components/pro-task-select-dialog.vue @@ -0,0 +1,245 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/task/components/pro-task-select.vue b/apps/web-antd/src/views/mes/pro/task/components/pro-task-select.vue new file mode 100644 index 000000000..60c5e1133 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/task/components/pro-task-select.vue @@ -0,0 +1,156 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/task/data.ts b/apps/web-antd/src/views/mes/pro/task/data.ts new file mode 100644 index 000000000..c29921b81 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/task/data.ts @@ -0,0 +1,112 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesProTaskApi } from '#/api/mes/pro/task'; + +import { markRaw } from 'vue'; + +import { DICT_TYPE } from '@vben/constants'; + +import { MdWorkstationSelect } from '#/views/mes/md/workstation/components'; +import { ProProcessSelect } from '#/views/mes/pro/process/components'; +import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components'; + +/** 任务选择弹窗的搜索表单 */ +export function useTaskSelectGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'workOrderId', + label: '生产工单', + component: markRaw(ProWorkOrderSelect), + componentProps: { + allowClear: true, + placeholder: '请选择生产工单', + }, + }, + { + fieldName: 'processId', + label: '所属工序', + component: markRaw(ProProcessSelect), + componentProps: { + allowClear: true, + placeholder: '请选择工序', + }, + }, + { + fieldName: 'workstationId', + label: '工作站', + component: markRaw(MdWorkstationSelect), + componentProps: { + allowClear: true, + placeholder: '请选择工作站', + }, + }, + { + fieldName: 'code', + label: '任务编号', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入任务编号', + }, + }, + { + fieldName: 'name', + label: '任务名称', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入任务名称', + }, + }, + ]; +} + +/** 任务选择弹窗的字段 */ +export function useTaskSelectGridColumns( + multiple = false, +): VxeTableGridOptions['columns'] { + return [ + { type: multiple ? 'checkbox' : 'radio', width: 50 }, + { field: 'code', title: '任务编号', width: 180 }, + { field: 'name', title: '任务名称', minWidth: 140 }, + { field: 'workstationCode', title: '工作站编码', width: 140 }, + { field: 'workstationName', title: '工作站名称', width: 140 }, + { field: 'processName', title: '工序', width: 120 }, + { + field: 'checkFlag', + title: '是否质检', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + }, + { field: 'itemCode', title: '物料编码', width: 140 }, + { field: 'itemName', title: '物料名称', width: 140 }, + { field: 'itemSpecification', title: '规格型号', width: 120 }, + { field: 'quantity', title: '排产数量', width: 100 }, + { field: 'producedQuantity', title: '已生产数量', width: 110 }, + { + field: 'startTime', + title: '开始生产时间', + width: 170, + formatter: 'formatDateTime', + }, + { field: 'duration', title: '生产时长', width: 100 }, + { + field: 'endTime', + title: '预计完成时间', + width: 170, + formatter: 'formatDateTime', + }, + { + field: 'status', + title: '任务状态', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_PRO_TASK_STATUS }, + }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mes/pro/workorder/components/index.ts b/apps/web-antd/src/views/mes/pro/workorder/components/index.ts new file mode 100644 index 000000000..1059f8a79 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/workorder/components/index.ts @@ -0,0 +1 @@ +export { default as ProWorkOrderSelect } from './pro-work-order-select.vue'; diff --git a/apps/web-antd/src/views/mes/pro/workorder/components/pro-work-order-select.vue b/apps/web-antd/src/views/mes/pro/workorder/components/pro-work-order-select.vue new file mode 100644 index 000000000..8b3907b1a --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/workorder/components/pro-work-order-select.vue @@ -0,0 +1,144 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/workrecord/components/work-record-status-bar.vue b/apps/web-antd/src/views/mes/pro/workrecord/components/work-record-status-bar.vue new file mode 100644 index 000000000..52cd0ce2f --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/workrecord/components/work-record-status-bar.vue @@ -0,0 +1,115 @@ + + + diff --git a/apps/web-antd/src/views/mes/pro/workrecord/data.ts b/apps/web-antd/src/views/mes/pro/workrecord/data.ts new file mode 100644 index 000000000..291d7e156 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/workrecord/data.ts @@ -0,0 +1,107 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesProWorkRecordApi } from '#/api/mes/pro/workrecord'; +import type { SystemUserApi } from '#/api/system/user'; + +import { markRaw } from 'vue'; + +import { DICT_TYPE } from '@vben/constants'; +import { getDictOptions } from '@vben/hooks'; + +import { getSimpleUserList } from '#/api/system/user'; +import { getRangePickerDefaultProps } from '#/utils'; +import MdWorkstationSelect from '#/views/mes/md/workstation/components/md-workstation-select.vue'; + +/** 关联数据 */ +let userList: SystemUserApi.User[] = []; +getSimpleUserList().then((data) => (userList = data)); + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'userId', + label: '用户', + component: 'ApiSelect', + componentProps: { + allowClear: true, + api: getSimpleUserList, + labelField: 'nickname', + placeholder: '请选择用户', + valueField: 'id', + }, + }, + { + fieldName: 'workstationId', + label: '工作站', + component: markRaw(MdWorkstationSelect), + componentProps: { + placeholder: '请选择工作站', + }, + }, + { + fieldName: 'type', + label: '操作类型', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.MES_PRO_WORK_RECORD_TYPE, 'number'), + placeholder: '请选择操作类型', + }, + }, + { + fieldName: 'createTime', + label: '操作时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '编号', + width: 80, + }, + { + field: 'userId', + title: '用户', + width: 140, + formatter: ({ row }) => + row.userNickname || + userList.find((user) => user.id === row.userId)?.nickname || + '', + }, + { + field: 'workstationCode', + title: '工作站编码', + width: 140, + }, + { + field: 'workstationName', + title: '工作站名称', + minWidth: 160, + }, + { + field: 'type', + title: '操作类型', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_PRO_WORK_RECORD_TYPE }, + }, + }, + { + field: 'createTime', + title: '创建时间', + width: 180, + formatter: 'formatDateTime', + }, + ]; +} diff --git a/apps/web-antd/src/views/mes/pro/workrecord/index.vue b/apps/web-antd/src/views/mes/pro/workrecord/index.vue new file mode 100644 index 000000000..3c9483954 --- /dev/null +++ b/apps/web-antd/src/views/mes/pro/workrecord/index.vue @@ -0,0 +1,87 @@ + + + diff --git a/apps/web-antd/src/views/mes/tm/tool/data.ts b/apps/web-antd/src/views/mes/tm/tool/data.ts index fbff2a1a3..b2e012145 100644 --- a/apps/web-antd/src/views/mes/tm/tool/data.ts +++ b/apps/web-antd/src/views/mes/tm/tool/data.ts @@ -20,6 +20,9 @@ import { import { TmToolTypeSelect } from './type/components'; +/** 表单类型 */ +export type FormType = 'create' | 'detail' | 'update'; + /** 新增/修改工具的表单 */ export function useFormSchema(formApi?: VbenFormApi): VbenFormSchema[] { return [ diff --git a/apps/web-antd/src/views/mes/tm/tool/index.vue b/apps/web-antd/src/views/mes/tm/tool/index.vue index 9225e52d0..c6ed9090b 100644 --- a/apps/web-antd/src/views/mes/tm/tool/index.vue +++ b/apps/web-antd/src/views/mes/tm/tool/index.vue @@ -32,17 +32,17 @@ function handleRefresh() { /** 创建工具 */ function handleCreate() { - formModalApi.setData({ type: 'create' }).open(); + formModalApi.setData({ formType: 'create' }).open(); } /** 查看工具 */ function handleDetail(row: MesTmToolApi.Tool) { - formModalApi.setData({ id: row.id, type: 'detail' }).open(); + formModalApi.setData({ id: row.id, formType: 'detail' }).open(); } /** 编辑工具 */ function handleEdit(row: MesTmToolApi.Tool) { - formModalApi.setData({ id: row.id, type: 'update' }).open(); + formModalApi.setData({ id: row.id, formType: 'update' }).open(); } /** 删除工具 */ diff --git a/apps/web-antd/src/views/mes/tm/tool/modules/form.vue b/apps/web-antd/src/views/mes/tm/tool/modules/form.vue index 0e0a26942..f964457e0 100644 --- a/apps/web-antd/src/views/mes/tm/tool/modules/form.vue +++ b/apps/web-antd/src/views/mes/tm/tool/modules/form.vue @@ -1,4 +1,6 @@ diff --git a/apps/web-ele/src/views/mes/md/item/modules/product-sop-form.vue b/apps/web-ele/src/views/mes/md/item/modules/product-sop-form.vue index 93a73a9b3..a9bb4f5b3 100644 --- a/apps/web-ele/src/views/mes/md/item/modules/product-sop-form.vue +++ b/apps/web-ele/src/views/mes/md/item/modules/product-sop-form.vue @@ -1,8 +1,10 @@ diff --git a/apps/web-ele/src/views/mes/md/vendor/data.ts b/apps/web-ele/src/views/mes/md/vendor/data.ts index 205db9cbf..8e9a3aea3 100644 --- a/apps/web-ele/src/views/mes/md/vendor/data.ts +++ b/apps/web-ele/src/views/mes/md/vendor/data.ts @@ -13,6 +13,9 @@ import { z } from '#/adapter/form'; import { generateAutoCode } from '#/api/mes/md/autocode/record'; import { MesAutoCodeRuleCode } from '#/views/mes/utils/constants'; +/** 表单类型 */ +export type FormType = 'create' | 'detail' | 'update'; + /** 新增/修改供应商的表单 */ export function useFormSchema(formApi?: VbenFormApi): VbenFormSchema[] { return [ diff --git a/apps/web-ele/src/views/mes/md/vendor/index.vue b/apps/web-ele/src/views/mes/md/vendor/index.vue index 53e593583..10c5e4c1a 100644 --- a/apps/web-ele/src/views/mes/md/vendor/index.vue +++ b/apps/web-ele/src/views/mes/md/vendor/index.vue @@ -32,17 +32,17 @@ function handleRefresh() { /** 创建供应商 */ function handleCreate() { - formModalApi.setData({ type: 'create' }).open(); + formModalApi.setData({ formType: 'create' }).open(); } /** 查看供应商 */ function handleDetail(row: MesMdVendorApi.Vendor) { - formModalApi.setData({ id: row.id, type: 'detail' }).open(); + formModalApi.setData({ id: row.id, formType: 'detail' }).open(); } /** 编辑供应商 */ function handleEdit(row: MesMdVendorApi.Vendor) { - formModalApi.setData({ id: row.id, type: 'update' }).open(); + formModalApi.setData({ id: row.id, formType: 'update' }).open(); } /** 删除供应商 */ diff --git a/apps/web-ele/src/views/mes/md/vendor/modules/form.vue b/apps/web-ele/src/views/mes/md/vendor/modules/form.vue index 6d10830f5..433e7f8dc 100644 --- a/apps/web-ele/src/views/mes/md/vendor/modules/form.vue +++ b/apps/web-ele/src/views/mes/md/vendor/modules/form.vue @@ -1,4 +1,6 @@ + + diff --git a/apps/web-ele/src/views/mes/pro/andon/config/components/index.ts b/apps/web-ele/src/views/mes/pro/andon/config/components/index.ts new file mode 100644 index 000000000..e7a766883 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/andon/config/components/index.ts @@ -0,0 +1 @@ +export { default as AndonConfigSelect } from './andon-config-select.vue'; diff --git a/apps/web-ele/src/views/mes/pro/andon/config/data.ts b/apps/web-ele/src/views/mes/pro/andon/config/data.ts new file mode 100644 index 000000000..ea3288193 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/andon/config/data.ts @@ -0,0 +1,100 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesProAndonConfigApi } from '#/api/mes/pro/andon/config'; + +import { DICT_TYPE } from '@vben/constants'; +import { getDictOptions } from '@vben/hooks'; + +import { z } from '#/adapter/form'; +import { getSimpleRoleList } from '#/api/system/role'; +import { getSimpleUserList } from '#/api/system/user'; + +/** 安灯配置列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { field: 'reason', title: '呼叫原因', minWidth: 200 }, + { + field: 'level', + title: '级别', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_PRO_ANDON_LEVEL }, + }, + }, + { field: 'handlerRoleName', title: '处置角色', width: 140 }, + { field: 'handlerUserNickname', title: '处置人', width: 140 }, + { field: 'remark', title: '备注', minWidth: 160 }, + { + title: '操作', + width: 160, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** 新增/修改安灯配置的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'reason', + label: '呼叫原因', + component: 'Textarea', + componentProps: { + autosize: { maxRows: 3, minRows: 1 }, + maxLength: 200, + placeholder: '请输入呼叫原因', + }, + rules: z.string().min(1, '呼叫原因不能为空').max(200), + }, + { + fieldName: 'level', + label: '级别', + component: 'Select', + componentProps: { + options: getDictOptions(DICT_TYPE.MES_PRO_ANDON_LEVEL, 'number'), + placeholder: '请选择级别', + }, + rules: 'selectRequired', + }, + { + fieldName: 'handlerRoleId', + label: '处置角色', + component: 'ApiSelect', + componentProps: { + api: getSimpleRoleList, + clearable: true, + labelField: 'name', + placeholder: '请选择角色(与处置人至少填一个)', + valueField: 'id', + }, + }, + { + fieldName: 'handlerUserId', + label: '处置人', + component: 'ApiSelect', + componentProps: { + api: getSimpleUserList, + clearable: true, + labelField: 'nickname', + placeholder: '请选择处置人(与角色至少填一个)', + valueField: 'id', + }, + }, + { + fieldName: 'remark', + label: '备注', + component: 'Input', + componentProps: { + maxLength: 100, + placeholder: '请输入备注', + }, + }, + ]; +} diff --git a/apps/web-ele/src/views/mes/pro/andon/config/modules/form.vue b/apps/web-ele/src/views/mes/pro/andon/config/modules/form.vue new file mode 100644 index 000000000..af6b32037 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/andon/config/modules/form.vue @@ -0,0 +1,94 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/andon/config/modules/list.vue b/apps/web-ele/src/views/mes/pro/andon/config/modules/list.vue new file mode 100644 index 000000000..ba237cec0 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/andon/config/modules/list.vue @@ -0,0 +1,130 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/andon/record/data.ts b/apps/web-ele/src/views/mes/pro/andon/record/data.ts new file mode 100644 index 000000000..4947ebf27 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/andon/record/data.ts @@ -0,0 +1,320 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesProAndonConfigApi } from '#/api/mes/pro/andon/config'; +import type { MesProAndonRecordApi } from '#/api/mes/pro/andon/record'; + +import { markRaw } from 'vue'; + +import { DICT_TYPE } from '@vben/constants'; +import { getDictOptions } from '@vben/hooks'; + +import { getSimpleUserList } from '#/api/system/user'; +import { getRangePickerDefaultProps } from '#/utils'; +import { MdWorkstationSelect } from '#/views/mes/md/workstation/components'; +import { ProProcessSelect } from '#/views/mes/pro/process/components'; +import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components'; +import { MesProWorkOrderStatusEnum } from '#/views/mes/utils/constants'; + +import { AndonConfigSelect } from '../config/components'; + +/** 表单类型 */ +export type FormType = 'create' | 'detail' | 'update'; + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'workstationId', + label: '工作站', + component: markRaw(MdWorkstationSelect), + componentProps: { + clearable: true, + placeholder: '请选择工作站', + }, + }, + { + fieldName: 'userId', + label: '发起人', + component: 'ApiSelect', + componentProps: { + api: getSimpleUserList, + clearable: true, + labelField: 'nickname', + placeholder: '请选择发起人', + valueField: 'id', + }, + }, + { + fieldName: 'handlerUserId', + label: '处置人', + component: 'ApiSelect', + componentProps: { + api: getSimpleUserList, + clearable: true, + labelField: 'nickname', + placeholder: '请选择处置人', + valueField: 'id', + }, + }, + { + fieldName: 'status', + label: '处理状态', + component: 'Select', + componentProps: { + clearable: true, + options: getDictOptions(DICT_TYPE.MES_PRO_ANDON_STATUS, 'number'), + placeholder: '请选择状态', + }, + }, + { + fieldName: 'createTime', + label: '发起时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + clearable: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { field: 'workstationCode', title: '工作站编码', width: 140 }, + { field: 'workstationName', title: '工作站名称', minWidth: 140 }, + { field: 'workOrderCode', title: '工单编码', width: 140 }, + { field: 'processName', title: '工序名称', width: 140 }, + { field: 'userNickname', title: '发起人', width: 110 }, + { + field: 'createTime', + title: '发起时间', + width: 180, + formatter: 'formatDateTime', + }, + { field: 'reason', title: '呼叫原因', minWidth: 160 }, + { + field: 'level', + title: '级别', + width: 90, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_PRO_ANDON_LEVEL }, + }, + }, + { + field: 'handleTime', + title: '处理时间', + width: 180, + formatter: 'formatDateTime', + }, + { field: 'handlerUserNickname', title: '处理人', width: 110 }, + { + field: 'status', + title: '处置状态', + width: 110, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_PRO_ANDON_STATUS }, + }, + }, + { + title: '操作', + width: 200, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** + * 新增/处置/详情安灯呼叫记录的表单 + * + * - create:录入呼叫主体信息(工作站/发起人/工单/工序/呼叫原因/备注) + * - update:呼叫主体只读展示创建时的快照字段(workstationName/workOrderCode/processName/reason),编辑处置时间/处置人/备注 + * - detail:所有字段只读 + */ +export function useFormSchema( + formType: FormType, + formApi?: VbenFormApi, +): VbenFormSchema[] { + const isCreate = formType === 'create'; + const isUpdate = formType === 'update'; + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + isCreate + ? { + fieldName: 'workstationId', + label: '工作站', + component: markRaw(MdWorkstationSelect), + componentProps: { + placeholder: '请选择工作站', + }, + rules: 'selectRequired', + } + : { + fieldName: 'workstationName', + label: '工作站', + component: 'Input', + componentProps: { + disabled: true, + }, + }, + isCreate + ? { + fieldName: 'userId', + label: '发起人', + component: 'ApiSelect', + componentProps: { + api: getSimpleUserList, + clearable: true, + labelField: 'nickname', + placeholder: '请选择发起人', + valueField: 'id', + }, + } + : { + fieldName: 'userNickname', + label: '发起人', + component: 'Input', + componentProps: { + disabled: true, + }, + }, + isCreate + ? { + fieldName: 'workOrderId', + label: '生产工单', + component: markRaw(ProWorkOrderSelect), + componentProps: { + placeholder: '请选择工单(可选)', + status: MesProWorkOrderStatusEnum.CONFIRMED, + }, + } + : { + fieldName: 'workOrderCode', + label: '生产工单', + component: 'Input', + componentProps: { + disabled: true, + }, + }, + isCreate + ? { + fieldName: 'processId', + label: '工序', + component: markRaw(ProProcessSelect), + componentProps: { + placeholder: '请选择工序(可选)', + }, + } + : { + fieldName: 'processName', + label: '工序', + component: 'Input', + componentProps: { + disabled: true, + }, + }, + isCreate + ? { + fieldName: 'configId', + label: '呼叫原因', + component: markRaw(AndonConfigSelect), + componentProps: { + // 选择呼叫原因后,自动填充对应的级别 + onChange: async (config?: MesProAndonConfigApi.AndonConfig) => { + await formApi?.setValues({ + level: config?.level, + reason: config?.reason, + }); + }, + }, + rules: 'selectRequired', + } + : { + fieldName: 'reason', + label: '呼叫原因', + component: 'Input', + componentProps: { + disabled: true, + }, + }, + { + fieldName: 'level', + label: '级别', + component: 'Select', + componentProps: { + disabled: true, + options: getDictOptions(DICT_TYPE.MES_PRO_ANDON_LEVEL, 'number'), + placeholder: '由呼叫原因自动带出', + }, + }, + // 处置信息:update / detail 模式才展示 + ...(isCreate + ? [] + : ([ + { + fieldName: 'status', + label: '状态', + component: 'Select', + componentProps: { + disabled: true, + options: getDictOptions( + DICT_TYPE.MES_PRO_ANDON_STATUS, + 'number', + ), + }, + }, + { + fieldName: 'handleTime', + label: '处置时间', + component: 'DatePicker', + componentProps: { + class: '!w-full', + disabled: !isUpdate, + format: 'YYYY-MM-DD HH:mm:ss', + placeholder: '请选择处置时间', + type: 'datetime', + valueFormat: 'x', + }, + }, + isUpdate + ? { + fieldName: 'handlerUserId', + label: '处置人', + component: 'ApiSelect', + componentProps: { + api: getSimpleUserList, + clearable: true, + labelField: 'nickname', + placeholder: '请选择处置人', + valueField: 'id', + }, + } + : { + fieldName: 'handlerUserNickname', + label: '处置人', + component: 'Input', + componentProps: { + disabled: true, + }, + }, + ] as VbenFormSchema[])), + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + componentProps: { + autosize: { maxRows: 3, minRows: 2 }, + disabled: formType === 'detail', + maxLength: 250, + placeholder: '请输入备注', + }, + }, + ]; +} diff --git a/apps/web-ele/src/views/mes/pro/andon/record/index.vue b/apps/web-ele/src/views/mes/pro/andon/record/index.vue new file mode 100644 index 000000000..d31901204 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/andon/record/index.vue @@ -0,0 +1,175 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/andon/record/modules/form.vue b/apps/web-ele/src/views/mes/pro/andon/record/modules/form.vue new file mode 100644 index 000000000..83261cd22 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/andon/record/modules/form.vue @@ -0,0 +1,188 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/feedback/data.ts b/apps/web-ele/src/views/mes/pro/feedback/data.ts new file mode 100644 index 000000000..21a677ff5 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/feedback/data.ts @@ -0,0 +1,589 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesProFeedbackApi } from '#/api/mes/pro/feedback'; +import type { MesProTaskApi } from '#/api/mes/pro/task'; + +import { h, markRaw } from 'vue'; + +import { DICT_TYPE } from '@vben/constants'; +import { getDictOptions } from '@vben/hooks'; + +import { ElButton } from 'element-plus'; + +import { generateAutoCode } from '#/api/mes/md/autocode/record'; +import { getRouteProcessByRouteAndProcess } from '#/api/mes/pro/route/process'; +import { getSimpleUserList } from '#/api/system/user'; +import { getRangePickerDefaultProps } from '#/utils'; +import { MdItemSelect } from '#/views/mes/md/item/components'; +import { MdWorkstationSelect } from '#/views/mes/md/workstation/components'; +import { ProTaskSelect } from '#/views/mes/pro/task/components'; +import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components'; +import { + MesAutoCodeRuleCode, + MesProTaskStatusEnum, + MesProWorkOrderStatusEnum, +} from '#/views/mes/utils/constants'; + +/** 生产报工表单类型 */ +export type FormType = 'approve' | 'create' | 'detail' | 'submit' | 'update'; + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'code', + label: '报工单号', + component: 'Input', + componentProps: { + clearable: true, + placeholder: '请输入报工单号', + }, + }, + { + fieldName: 'type', + label: '报工类型', + component: 'Select', + componentProps: { + clearable: true, + options: getDictOptions(DICT_TYPE.MES_PRO_FEEDBACK_TYPE, 'number'), + placeholder: '请选择报工类型', + }, + }, + { + fieldName: 'workOrderId', + label: '生产工单', + component: markRaw(ProWorkOrderSelect), + componentProps: { + clearable: true, + placeholder: '请选择工单', + }, + }, + { + fieldName: 'itemId', + label: '产品物料', + component: markRaw(MdItemSelect), + componentProps: { + clearable: true, + placeholder: '请选择产品物料', + }, + }, + { + fieldName: 'feedbackUserId', + label: '报工人', + component: 'ApiSelect', + componentProps: { + api: getSimpleUserList, + clearable: true, + labelField: 'nickname', + placeholder: '请选择报工人', + valueField: 'id', + }, + }, + { + fieldName: 'creator', + label: '记录人', + component: 'ApiSelect', + componentProps: { + api: getSimpleUserList, + clearable: true, + labelField: 'nickname', + placeholder: '请选择记录人', + valueField: 'id', + }, + }, + { + fieldName: 'status', + label: '状态', + component: 'Select', + componentProps: { + clearable: true, + options: getDictOptions(DICT_TYPE.MES_PRO_FEEDBACK_STATUS, 'number'), + placeholder: '请选择状态', + }, + }, + { + fieldName: 'feedbackTime', + label: '报工时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + clearable: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'code', + title: '报工单号', + width: 160, + slots: { default: 'code' }, + }, + { + field: 'type', + title: '报工类型', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_PRO_FEEDBACK_TYPE }, + }, + }, + { field: 'workstationName', title: '工作站', width: 120 }, + { field: 'processName', title: '工序', width: 100 }, + { field: 'workOrderCode', title: '生产工单编码', width: 160 }, + { field: 'itemCode', title: '产品物料编码', width: 120 }, + { field: 'itemName', title: '产品物料名称', minWidth: 140 }, + { field: 'itemSpecification', title: '规格型号', width: 120 }, + { field: 'unitMeasureName', title: '单位', width: 80 }, + { field: 'feedbackQuantity', title: '报工数量', width: 100 }, + { field: 'feedbackUserNickname', title: '报工人', width: 100 }, + { + field: 'feedbackTime', + title: '报工时间', + width: 180, + formatter: 'formatDateTime', + }, + { field: 'approveUserNickname', title: '审核人', width: 100 }, + { + field: 'status', + title: '状态', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_PRO_FEEDBACK_STATUS }, + }, + }, + { + title: '操作', + width: 240, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** + * 新增/编辑/提交/审批/详情生产报工的表单 + * + * - create / update:录入报工主体信息和数量 + * - submit / approve / detail:主体字段只读 + * + * 数量区域根据 `checkFlag` 和 `unqualifiedQuantity` 动态显示: + * - 非质检工序:报工数量 = 合格 + 不良;不良 > 0 时再展开工废/料废/其他废品 + * - 质检工序:只填报工数量(视为待检数量) + */ +export function useFormSchema( + formType: FormType, + formApi?: VbenFormApi, +): VbenFormSchema[] { + const isHeaderReadonly = ['approve', 'detail', 'submit'].includes(formType); + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'checkFlag', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + defaultValue: true, + }, + { + fieldName: 'routeId', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'processId', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'itemId', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'code', + label: '报工单号', + component: 'Input', + componentProps: { + disabled: isHeaderReadonly, + placeholder: '请输入报工单号', + }, + rules: 'required', + suffix: () => + h( + ElButton, + { + disabled: isHeaderReadonly, + type: 'default', + onClick: async () => { + const code = await generateAutoCode( + MesAutoCodeRuleCode.PRO_FEEDBACK_CODE, + ); + await formApi?.setFieldValue('code', code); + }, + }, + { default: () => '生成' }, + ), + }, + { + fieldName: 'type', + label: '报工类型', + component: 'Select', + componentProps: { + disabled: isHeaderReadonly, + options: getDictOptions(DICT_TYPE.MES_PRO_FEEDBACK_TYPE, 'number'), + placeholder: '请选择报工类型', + }, + rules: 'required', + }, + { + fieldName: 'workOrderId', + label: '生产工单', + component: markRaw(ProWorkOrderSelect), + componentProps: { + disabled: isHeaderReadonly, + placeholder: '请选择工单', + status: MesProWorkOrderStatusEnum.CONFIRMED, + // 工单变更:清空任务及任务带出的产品信息、数量区域控制位 + onChange: async () => { + await formApi?.setValues({ + checkFlag: true, + itemCode: undefined, + itemId: undefined, + itemName: undefined, + itemSpecification: undefined, + processId: undefined, + routeId: undefined, + taskId: undefined, + unitMeasureName: undefined, + workstationId: undefined, + }); + }, + }, + rules: 'selectRequired', + }, + { + fieldName: 'taskId', + label: '生产任务', + component: markRaw(ProTaskSelect), + dependencies: { + triggerFields: ['workOrderId', 'workstationId'], + componentProps: (values) => ({ + disabled: isHeaderReadonly || !values.workOrderId, + placeholder: values.workOrderId ? '请选择任务' : '请先选择工单', + statuses: [MesProTaskStatusEnum.PREPARE], + workOrderId: values.workOrderId, + workstationId: values.workstationId, + }), + }, + // 任务变更:自动填充关联字段、产品信息、checkFlag + componentProps: { + onChange: async (task?: MesProTaskApi.Task) => { + if (!task) { + return; + } + await formApi?.setValues({ + itemCode: task.itemCode, + itemId: task.itemId, + itemName: task.itemName, + itemSpecification: task.itemSpecification, + processId: task.processId, + routeId: task.routeId, + unitMeasureName: task.unitMeasureName, + workstationId: task.workstationId, + }); + // 工艺路线工序的 checkFlag 决定数量区域展示 + if (task.routeId && task.processId) { + try { + const routeProcess = await getRouteProcessByRouteAndProcess( + task.routeId, + task.processId, + ); + await formApi?.setFieldValue( + 'checkFlag', + routeProcess?.checkFlag ?? false, + ); + } catch { + await formApi?.setFieldValue('checkFlag', true); + } + } + }, + }, + rules: 'selectRequired', + }, + { + fieldName: 'workstationId', + label: '工作站', + component: markRaw(MdWorkstationSelect), + componentProps: { + disabled: isHeaderReadonly, + placeholder: '请选择工作站', + }, + rules: 'selectRequired', + }, + { + fieldName: 'itemCode', + label: '产品编码', + component: 'Input', + componentProps: { disabled: true }, + dependencies: { + triggerFields: ['itemCode'], + show: (values) => !!values.itemCode, + }, + }, + { + fieldName: 'itemName', + label: '产品名称', + component: 'Input', + componentProps: { disabled: true }, + dependencies: { + triggerFields: ['itemCode'], + show: (values) => !!values.itemCode, + }, + }, + { + fieldName: 'unitMeasureName', + label: '单位', + component: 'Input', + componentProps: { disabled: true }, + dependencies: { + triggerFields: ['itemCode'], + show: (values) => !!values.itemCode, + }, + }, + { + fieldName: 'itemSpecification', + label: '规格', + component: 'Input', + componentProps: { disabled: true }, + dependencies: { + triggerFields: ['itemCode'], + show: (values) => !!values.itemCode, + }, + }, + { + fieldName: 'feedbackQuantity', + label: '报工数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 0, + precision: 2, + }, + dependencies: { + triggerFields: ['checkFlag'], + // 非质检工序时,报工数量 = 合格 + 不良,禁用直接编辑 + componentProps: (values) => ({ + class: '!w-full', + controlsPosition: 'right', + disabled: !values.checkFlag, + min: 0, + placeholder: '请输入报工数量', + precision: 2, + }), + }, + rules: 'required', + }, + { + fieldName: 'qualifiedQuantity', + label: '合格品数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 0, + precision: 2, + // 合格/不良变更,自动累计为报工数量 + onChange: async () => { + const values = await formApi?.getValues(); + await formApi?.setFieldValue( + 'feedbackQuantity', + (values?.qualifiedQuantity || 0) + + (values?.unqualifiedQuantity || 0), + ); + }, + }, + defaultValue: 0, + dependencies: { + triggerFields: ['checkFlag'], + show: (values) => !values.checkFlag, + }, + }, + { + fieldName: 'unqualifiedQuantity', + label: '不良品数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 0, + precision: 2, + // 合格/不良变更,自动累计为报工数量 + onChange: async () => { + const values = await formApi?.getValues(); + await formApi?.setFieldValue( + 'feedbackQuantity', + (values?.qualifiedQuantity || 0) + + (values?.unqualifiedQuantity || 0), + ); + }, + }, + defaultValue: 0, + dependencies: { + triggerFields: ['checkFlag'], + show: (values) => !values.checkFlag, + }, + }, + { + fieldName: 'laborScrapQuantity', + label: '工废数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 0, + precision: 2, + // 废品分类变更,自动累计为不良品数量及报工数量 + onChange: async () => { + const values = await formApi?.getValues(); + const unqualified = + (values?.laborScrapQuantity || 0) + + (values?.materialScrapQuantity || 0) + + (values?.otherScrapQuantity || 0); + await formApi?.setValues({ + feedbackQuantity: + (values?.qualifiedQuantity || 0) + unqualified, + unqualifiedQuantity: unqualified, + }); + }, + }, + defaultValue: 0, + dependencies: { + triggerFields: ['checkFlag', 'unqualifiedQuantity'], + show: (values) => + !values.checkFlag && (values.unqualifiedQuantity || 0) > 0, + }, + }, + { + fieldName: 'materialScrapQuantity', + label: '料废数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 0, + precision: 2, + // 废品分类变更,自动累计为不良品数量及报工数量 + onChange: async () => { + const values = await formApi?.getValues(); + const unqualified = + (values?.laborScrapQuantity || 0) + + (values?.materialScrapQuantity || 0) + + (values?.otherScrapQuantity || 0); + await formApi?.setValues({ + feedbackQuantity: + (values?.qualifiedQuantity || 0) + unqualified, + unqualifiedQuantity: unqualified, + }); + }, + }, + defaultValue: 0, + dependencies: { + triggerFields: ['checkFlag', 'unqualifiedQuantity'], + show: (values) => + !values.checkFlag && (values.unqualifiedQuantity || 0) > 0, + }, + }, + { + fieldName: 'otherScrapQuantity', + label: '其他废品', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 0, + precision: 2, + // 废品分类变更,自动累计为不良品数量及报工数量 + onChange: async () => { + const values = await formApi?.getValues(); + const unqualified = + (values?.laborScrapQuantity || 0) + + (values?.materialScrapQuantity || 0) + + (values?.otherScrapQuantity || 0); + await formApi?.setValues({ + feedbackQuantity: + (values?.qualifiedQuantity || 0) + unqualified, + unqualifiedQuantity: unqualified, + }); + }, + }, + defaultValue: 0, + dependencies: { + triggerFields: ['checkFlag', 'unqualifiedQuantity'], + show: (values) => + !values.checkFlag && (values.unqualifiedQuantity || 0) > 0, + }, + }, + { + fieldName: 'feedbackUserId', + label: '报工人', + component: 'ApiSelect', + componentProps: { + api: getSimpleUserList, + clearable: true, + disabled: isHeaderReadonly, + labelField: 'nickname', + placeholder: '请选择报工人', + valueField: 'id', + }, + rules: 'selectRequired', + }, + { + fieldName: 'feedbackTime', + label: '报工时间', + component: 'DatePicker', + componentProps: { + class: '!w-full', + disabled: isHeaderReadonly, + format: 'YYYY-MM-DD HH:mm:ss', + placeholder: '请选择报工时间', + type: 'datetime', + valueFormat: 'x', + }, + rules: 'required', + }, + { + fieldName: 'approveUserId', + label: '审核人', + component: 'ApiSelect', + componentProps: { + api: getSimpleUserList, + clearable: true, + disabled: isHeaderReadonly, + labelField: 'nickname', + placeholder: '请选择审核人', + valueField: 'id', + }, + rules: 'selectRequired', + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + autosize: { maxRows: 3, minRows: 2 }, + disabled: formType === 'detail', + placeholder: '请输入备注', + }, + }, + ]; +} diff --git a/apps/web-ele/src/views/mes/pro/feedback/index.vue b/apps/web-ele/src/views/mes/pro/feedback/index.vue new file mode 100644 index 000000000..ef65e4629 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/feedback/index.vue @@ -0,0 +1,184 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/feedback/modules/form.vue b/apps/web-ele/src/views/mes/pro/feedback/modules/form.vue new file mode 100644 index 000000000..91896b74c --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/feedback/modules/form.vue @@ -0,0 +1,331 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/feedback/modules/item-consume-list.vue b/apps/web-ele/src/views/mes/pro/feedback/modules/item-consume-list.vue new file mode 100644 index 000000000..5aa78254f --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/feedback/modules/item-consume-list.vue @@ -0,0 +1,57 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/feedback/modules/product-produce-list.vue b/apps/web-ele/src/views/mes/pro/feedback/modules/product-produce-list.vue new file mode 100644 index 000000000..17ac88995 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/feedback/modules/product-produce-list.vue @@ -0,0 +1,68 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/process/data.ts b/apps/web-ele/src/views/mes/pro/process/data.ts new file mode 100644 index 000000000..1fc136c30 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/process/data.ts @@ -0,0 +1,274 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesProProcessApi } from '#/api/mes/pro/process'; +import type { MesProProcessContentApi } from '#/api/mes/pro/process/content'; + +import { h } from 'vue'; + +import { CommonStatusEnum, DICT_TYPE } from '@vben/constants'; +import { getDictOptions } from '@vben/hooks'; + +import { ElButton } from 'element-plus'; + +import { z } from '#/adapter/form'; +import { generateAutoCode } from '#/api/mes/md/autocode/record'; +import { MesAutoCodeRuleCode } from '#/views/mes/utils/constants'; + +/** 表单类型 */ +export type FormType = 'create' | 'detail' | 'update'; + +/** 新增/修改生产工序的表单 */ +export function useFormSchema(formApi?: VbenFormApi): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'code', + label: '工序编码', + component: 'Input', + componentProps: { + maxLength: 64, + placeholder: '请输入工序编码', + }, + rules: z.string().min(1, '工序编码不能为空').max(64), + suffix: () => + h( + ElButton, + { + type: 'default', + onClick: async () => { + try { + const code = await generateAutoCode( + MesAutoCodeRuleCode.PRO_PROCESS_CODE, + ); + await formApi?.setFieldValue('code', code); + } catch (error) { + console.error(error); + } + }, + }, + { default: () => '生成' }, + ), + }, + { + fieldName: 'name', + label: '工序名称', + component: 'Input', + componentProps: { + maxLength: 100, + placeholder: '请输入工序名称', + }, + rules: z.string().min(1, '工序名称不能为空').max(100), + }, + { + fieldName: 'status', + label: '状态', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + }, + rules: z.number().default(CommonStatusEnum.ENABLE), + }, + { + fieldName: 'attention', + label: '工序说明', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + maxLength: 500, + placeholder: '请输入工序说明', + rows: 3, + }, + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + maxLength: 250, + placeholder: '请输入备注', + rows: 3, + }, + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'code', + label: '工序编码', + component: 'Input', + componentProps: { + clearable: true, + placeholder: '请输入工序编码', + }, + }, + { + fieldName: 'name', + label: '工序名称', + component: 'Input', + componentProps: { + clearable: true, + placeholder: '请输入工序名称', + }, + }, + { + fieldName: 'status', + label: '状态', + component: 'Select', + componentProps: { + clearable: true, + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + placeholder: '请选择状态', + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'code', + title: '工序编码', + minWidth: 150, + slots: { + default: 'code', + }, + }, + { field: 'name', title: '工序名称', minWidth: 180 }, + { + field: 'status', + title: '状态', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + }, + { field: 'remark', title: '备注', minWidth: 180 }, + { + field: 'createTime', + title: '创建时间', + width: 180, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 150, + fixed: 'right', + slots: { + default: 'actions', + }, + }, + ]; +} + +/** 工序内容(操作步骤)表单 */ +export function useContentFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'processId', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'sort', + label: '序号', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + max: 999, + min: 1, + precision: 0, + }, + rules: z.number().default(1), + }, + { + fieldName: 'content', + label: '步骤说明', + component: 'Textarea', + componentProps: { + maxLength: 500, + placeholder: '请输入步骤说明', + rows: 3, + }, + }, + { + fieldName: 'device', + label: '辅助设备', + component: 'Input', + componentProps: { + maxLength: 100, + placeholder: '请输入辅助设备', + }, + }, + { + fieldName: 'material', + label: '辅助材料', + component: 'Input', + componentProps: { + maxLength: 100, + placeholder: '请输入辅助材料', + }, + }, + { + fieldName: 'docUrl', + label: '材料文档 URL', + component: 'Input', + componentProps: { + maxLength: 250, + placeholder: '请输入材料文档 URL', + }, + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + componentProps: { + maxLength: 250, + placeholder: '请输入备注', + rows: 2, + }, + }, + ]; +} + +/** 工序内容列表的字段 */ +export function useContentGridColumns(): VxeTableGridOptions['columns'] { + return [ + { field: 'sort', title: '序号', width: 80, align: 'center' }, + { field: 'content', title: '步骤说明', minWidth: 220 }, + { field: 'device', title: '辅助设备', width: 150 }, + { field: 'material', title: '辅助材料', width: 150 }, + { field: 'docUrl', title: '材料文档', minWidth: 180 }, + { field: 'remark', title: '备注', minWidth: 160 }, + { + title: '操作', + width: 130, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} diff --git a/apps/web-ele/src/views/mes/pro/process/index.vue b/apps/web-ele/src/views/mes/pro/process/index.vue new file mode 100644 index 000000000..62d4df2df --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/process/index.vue @@ -0,0 +1,160 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/process/modules/content-form.vue b/apps/web-ele/src/views/mes/pro/process/modules/content-form.vue new file mode 100644 index 000000000..46544dccd --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/process/modules/content-form.vue @@ -0,0 +1,99 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/process/modules/content-list.vue b/apps/web-ele/src/views/mes/pro/process/modules/content-list.vue new file mode 100644 index 000000000..45d68aa3e --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/process/modules/content-list.vue @@ -0,0 +1,133 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/process/modules/form.vue b/apps/web-ele/src/views/mes/pro/process/modules/form.vue new file mode 100644 index 000000000..4afb9aa04 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/process/modules/form.vue @@ -0,0 +1,117 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/route/components/color-picker.vue b/apps/web-ele/src/views/mes/pro/route/components/color-picker.vue new file mode 100644 index 000000000..47eee7973 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/route/components/color-picker.vue @@ -0,0 +1,40 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/route/components/index.ts b/apps/web-ele/src/views/mes/pro/route/components/index.ts new file mode 100644 index 000000000..4a78a4ce4 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/route/components/index.ts @@ -0,0 +1 @@ +export { default as RouteColorPicker } from './color-picker.vue'; diff --git a/apps/web-ele/src/views/mes/pro/route/data.ts b/apps/web-ele/src/views/mes/pro/route/data.ts new file mode 100644 index 000000000..5b4a56612 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/route/data.ts @@ -0,0 +1,501 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesProRouteApi } from '#/api/mes/pro/route'; +import type { MesProRouteProcessApi } from '#/api/mes/pro/route/process'; +import type { MesProRouteProductApi } from '#/api/mes/pro/route/product'; +import type { MesProRouteProductBomApi } from '#/api/mes/pro/route/productbom'; + +import { h } from 'vue'; + +import { CommonStatusEnum, DICT_TYPE } from '@vben/constants'; +import { getDictOptions } from '@vben/hooks'; + +import { ElButton } from 'element-plus'; + +import { z } from '#/adapter/form'; +import { generateAutoCode } from '#/api/mes/md/autocode/record'; +import { + MdItemSelect, + MdProductBomSelect, +} from '#/views/mes/md/item/components'; +import { MesAutoCodeRuleCode } from '#/views/mes/utils/constants'; + +import { RouteColorPicker } from './components'; + +/** 表单类型 */ +export type FormType = 'create' | 'detail' | 'update'; + +/** 工艺路线表单 */ +export function useFormSchema(formApi?: VbenFormApi): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'code', + label: '路线编码', + component: 'Input', + componentProps: { + maxLength: 64, + placeholder: '请输入工艺路线编码', + }, + rules: z.string().min(1, '路线编码不能为空').max(64), + suffix: () => + h( + ElButton, + { + type: 'default', + onClick: async () => { + try { + const code = await generateAutoCode( + MesAutoCodeRuleCode.PRO_ROUTE_CODE, + ); + await formApi?.setFieldValue('code', code); + } catch (error) { + console.error(error); + } + }, + }, + { default: () => '生成' }, + ), + }, + { + fieldName: 'name', + label: '路线名称', + component: 'Input', + componentProps: { + maxLength: 100, + placeholder: '请输入工艺路线名称', + }, + rules: z.string().min(1, '路线名称不能为空').max(100), + }, + { + fieldName: 'description', + label: '路线说明', + component: 'Textarea', + formItemClass: 'col-span-2', + componentProps: { + maxLength: 500, + placeholder: '请输入工艺路线说明', + rows: 3, + }, + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-2', + componentProps: { + maxLength: 250, + placeholder: '请输入备注', + rows: 2, + }, + }, + ]; +} + +/** 列表搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'code', + label: '路线编码', + component: 'Input', + componentProps: { clearable: true, placeholder: '请输入路线编码' }, + }, + { + fieldName: 'name', + label: '路线名称', + component: 'Input', + componentProps: { clearable: true, placeholder: '请输入路线名称' }, + }, + { + fieldName: 'status', + label: '状态', + component: 'Select', + componentProps: { + clearable: true, + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + placeholder: '请选择状态', + }, + }, + ]; +} + +/** 列表字段 */ +export function useGridColumns( + onStatusChange?: ( + newStatus: number, + row: MesProRouteApi.Route, + ) => PromiseLike, + statusEditable = true, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'code', + title: '路线编码', + minWidth: 160, + slots: { default: 'code' }, + }, + { field: 'name', title: '路线名称', minWidth: 180 }, + { field: 'description', title: '路线说明', minWidth: 200 }, + { + field: 'status', + title: '状态', + width: 110, + align: 'center', + cellRender: { + attrs: { beforeChange: onStatusChange }, + name: 'CellSwitch', + props: { + activeValue: CommonStatusEnum.ENABLE, + disabled: !statusEditable, + inactiveValue: CommonStatusEnum.DISABLE, + }, + }, + }, + { field: 'remark', title: '备注', minWidth: 160 }, + { + field: 'createTime', + title: '创建时间', + width: 180, + formatter: 'formatDateTime', + }, + { + title: '操作', + width: 160, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** 工艺路线工序明细表单 */ +export function useRouteProcessFormSchema( + processOptions: Array<{ label: string; value: number }>, +): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'routeId', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'sort', + label: '序号', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 1, + precision: 0, + }, + rules: z.number().default(1), + }, + { + fieldName: 'processId', + label: '工序', + component: 'Select', + componentProps: { + clearable: true, + filterable: true, + options: processOptions, + placeholder: '请选择工序', + }, + rules: 'selectRequired', + }, + { + fieldName: 'linkType', + label: '与下道工序关系', + component: 'Select', + componentProps: { + clearable: true, + options: getDictOptions(DICT_TYPE.MES_PRO_LINK_TYPE, 'number'), + placeholder: '请选择', + }, + rules: z.number().default(3), + }, + { + fieldName: 'colorCode', + label: '甘特图颜色', + component: RouteColorPicker, + }, + { + fieldName: 'keyFlag', + label: '是否关键工序', + component: 'Switch', + componentProps: { activeText: '是', inactiveText: '否' }, + rules: z.boolean().default(false), + }, + { + fieldName: 'checkFlag', + label: '是否质检确认', + component: 'Switch', + componentProps: { activeText: '是', inactiveText: '否' }, + rules: z.boolean().default(false), + }, + { + fieldName: 'prepareTime', + label: '准备时间(分)', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 0, + precision: 0, + }, + rules: z.number().default(0), + }, + { + fieldName: 'waitTime', + label: '等待时间(分)', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 0, + precision: 0, + }, + rules: z.number().default(0), + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-2', + componentProps: { maxLength: 250, placeholder: '请输入备注', rows: 2 }, + }, + ]; +} + +/** 工艺路线工序列表字段 */ +export function useRouteProcessGridColumns(): VxeTableGridOptions['columns'] { + return [ + { field: 'sort', title: '序号', width: 70, align: 'center', fixed: 'left' }, + { field: 'processCode', title: '工序编码', width: 140, fixed: 'left' }, + { field: 'processName', title: '工序名称', width: 140, fixed: 'left' }, + { field: 'nextProcessName', title: '下一道工序', width: 140 }, + { + field: 'linkType', + title: '与下一道工序关系', + width: 160, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_PRO_LINK_TYPE }, + }, + }, + { + field: 'keyFlag', + title: '关键工序', + width: 90, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + }, + { + field: 'checkFlag', + title: '质检确认', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + }, + { field: 'prepareTime', title: '准备时间(分)', width: 110 }, + { field: 'waitTime', title: '等待时间(分)', width: 110 }, + { + field: 'colorCode', + title: '甘特图颜色', + width: 130, + slots: { default: 'colorCode' }, + }, + { field: 'remark', title: '备注', minWidth: 160 }, + { + title: '操作', + width: 130, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** 工艺路线产品列表字段 */ +export function useRouteProductGridColumns(): VxeTableGridOptions['columns'] { + return [ + { field: 'itemCode', title: '产品物料编码', width: 150 }, + { field: 'itemName', title: '产品物料名称', width: 150 }, + { field: 'specification', title: '规格型号', width: 150 }, + { field: 'unitName', title: '单位', width: 80 }, + { field: 'quantity', title: '生产数量', width: 100 }, + { + field: 'productionTime', + title: '生产用时', + width: 130, + slots: { default: 'productionTime' }, + }, + { field: 'remark', title: '备注', minWidth: 160 }, + { + title: '操作', + width: 130, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** 工艺路线产品 BOM 列表字段 */ +export function useRouteProductBomGridColumns(): VxeTableGridOptions['columns'] { + return [ + { field: 'itemCode', title: 'BOM 物料编码', width: 150 }, + { field: 'itemName', title: 'BOM 物料名称', width: 150 }, + { field: 'specification', title: '规格型号', width: 150 }, + { field: 'unitName', title: '单位', width: 80 }, + { field: 'quantity', title: '用料比例', width: 100 }, + { field: 'remark', title: '备注', minWidth: 160 }, + { + title: '操作', + width: 130, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + + +/** 工艺路线产品表单 */ +export function useRouteProductFormSchema( + onItemChange?: (item: any) => void, +): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'routeId', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + // 产品物料:使用业务自定义选择器,change 回填编码/名称/规格/单位 + { + fieldName: 'itemId', + label: '产品', + component: MdItemSelect as any, + componentProps: { + onChange: onItemChange, + }, + formItemClass: 'col-span-2', + rules: 'selectRequired', + }, + { + fieldName: 'quantity', + label: '生产数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 1, + precision: 0, + }, + rules: z.number().default(1), + }, + { + fieldName: 'productionTime', + label: '生产用时', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 0, + precision: 2, + }, + rules: z.number().default(1), + }, + { + fieldName: 'timeUnitType', + label: '时间单位', + component: 'Select', + componentProps: { + clearable: true, + options: getDictOptions(DICT_TYPE.MES_TIME_UNIT_TYPE), + placeholder: '请选择', + }, + rules: z.string().default('MINUTE'), + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-2', + componentProps: { maxLength: 250, placeholder: '请输入备注', rows: 2 }, + }, + ]; +} + +/** 工艺路线产品 BOM 表单 */ +export function useRouteProductBomFormSchema( + itemId: () => number, + onBomChange?: (bom: any) => void, +): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'routeId', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'processId', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + { + fieldName: 'productId', + component: 'Input', + dependencies: { triggerFields: [''], show: () => false }, + }, + // BOM 物料:依赖产品物料,使用业务自定义选择器 + { + fieldName: 'itemId', + label: 'BOM 物料', + component: MdProductBomSelect as any, + componentProps: () => ({ + itemId: itemId(), + onChange: onBomChange, + placeholder: '请选择 BOM 物料', + }), + rules: 'selectRequired', + }, + { + fieldName: 'quantity', + label: '用料比例', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 0, + precision: 2, + }, + rules: z.number().default(1), + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + componentProps: { maxLength: 250, placeholder: '请输入备注', rows: 2 }, + }, + ]; +} diff --git a/apps/web-ele/src/views/mes/pro/route/index.vue b/apps/web-ele/src/views/mes/pro/route/index.vue new file mode 100644 index 000000000..ae7e8962a --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/route/index.vue @@ -0,0 +1,185 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/route/modules/bom-form.vue b/apps/web-ele/src/views/mes/pro/route/modules/bom-form.vue new file mode 100644 index 000000000..e348b31b4 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/route/modules/bom-form.vue @@ -0,0 +1,119 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/route/modules/form.vue b/apps/web-ele/src/views/mes/pro/route/modules/form.vue new file mode 100644 index 000000000..ce15b7657 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/route/modules/form.vue @@ -0,0 +1,124 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/route/modules/process-form.vue b/apps/web-ele/src/views/mes/pro/route/modules/process-form.vue new file mode 100644 index 000000000..eb5fe30a0 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/route/modules/process-form.vue @@ -0,0 +1,122 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/route/modules/process-list.vue b/apps/web-ele/src/views/mes/pro/route/modules/process-list.vue new file mode 100644 index 000000000..ba00f71c2 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/route/modules/process-list.vue @@ -0,0 +1,137 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/route/modules/product-bom-list.vue b/apps/web-ele/src/views/mes/pro/route/modules/product-bom-list.vue new file mode 100644 index 000000000..b2ba09192 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/route/modules/product-bom-list.vue @@ -0,0 +1,173 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/route/modules/product-form.vue b/apps/web-ele/src/views/mes/pro/route/modules/product-form.vue new file mode 100644 index 000000000..f07c1a532 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/route/modules/product-form.vue @@ -0,0 +1,126 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/route/modules/product-list.vue b/apps/web-ele/src/views/mes/pro/route/modules/product-list.vue new file mode 100644 index 000000000..ad398351a --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/route/modules/product-list.vue @@ -0,0 +1,135 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/task/components/index.ts b/apps/web-ele/src/views/mes/pro/task/components/index.ts new file mode 100644 index 000000000..3847bb912 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/task/components/index.ts @@ -0,0 +1,2 @@ +export { default as ProTaskSelectDialog } from './pro-task-select-dialog.vue'; +export { default as ProTaskSelect } from './pro-task-select.vue'; diff --git a/apps/web-ele/src/views/mes/pro/task/components/pro-task-select-dialog.vue b/apps/web-ele/src/views/mes/pro/task/components/pro-task-select-dialog.vue new file mode 100644 index 000000000..3e43fc9ad --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/task/components/pro-task-select-dialog.vue @@ -0,0 +1,248 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/task/components/pro-task-select.vue b/apps/web-ele/src/views/mes/pro/task/components/pro-task-select.vue new file mode 100644 index 000000000..41ddaf20a --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/task/components/pro-task-select.vue @@ -0,0 +1,154 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/task/data.ts b/apps/web-ele/src/views/mes/pro/task/data.ts new file mode 100644 index 000000000..1e1cc70a2 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/task/data.ts @@ -0,0 +1,112 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesProTaskApi } from '#/api/mes/pro/task'; + +import { markRaw } from 'vue'; + +import { DICT_TYPE } from '@vben/constants'; + +import { MdWorkstationSelect } from '#/views/mes/md/workstation/components'; +import { ProProcessSelect } from '#/views/mes/pro/process/components'; +import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components'; + +/** 任务选择弹窗的搜索表单 */ +export function useTaskSelectGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'workOrderId', + label: '生产工单', + component: markRaw(ProWorkOrderSelect), + componentProps: { + clearable: true, + placeholder: '请选择生产工单', + }, + }, + { + fieldName: 'processId', + label: '所属工序', + component: markRaw(ProProcessSelect), + componentProps: { + clearable: true, + placeholder: '请选择工序', + }, + }, + { + fieldName: 'workstationId', + label: '工作站', + component: markRaw(MdWorkstationSelect), + componentProps: { + clearable: true, + placeholder: '请选择工作站', + }, + }, + { + fieldName: 'code', + label: '任务编号', + component: 'Input', + componentProps: { + clearable: true, + placeholder: '请输入任务编号', + }, + }, + { + fieldName: 'name', + label: '任务名称', + component: 'Input', + componentProps: { + clearable: true, + placeholder: '请输入任务名称', + }, + }, + ]; +} + +/** 任务选择弹窗的字段 */ +export function useTaskSelectGridColumns( + multiple = false, +): VxeTableGridOptions['columns'] { + return [ + { type: multiple ? 'checkbox' : 'radio', width: 50 }, + { field: 'code', title: '任务编号', width: 180 }, + { field: 'name', title: '任务名称', minWidth: 140 }, + { field: 'workstationCode', title: '工作站编码', width: 140 }, + { field: 'workstationName', title: '工作站名称', width: 140 }, + { field: 'processName', title: '工序', width: 120 }, + { + field: 'checkFlag', + title: '是否质检', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + }, + { field: 'itemCode', title: '物料编码', width: 140 }, + { field: 'itemName', title: '物料名称', width: 140 }, + { field: 'itemSpecification', title: '规格型号', width: 120 }, + { field: 'quantity', title: '排产数量', width: 100 }, + { field: 'producedQuantity', title: '已生产数量', width: 110 }, + { + field: 'startTime', + title: '开始生产时间', + width: 170, + formatter: 'formatDateTime', + }, + { field: 'duration', title: '生产时长', width: 100 }, + { + field: 'endTime', + title: '预计完成时间', + width: 170, + formatter: 'formatDateTime', + }, + { + field: 'status', + title: '任务状态', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_PRO_TASK_STATUS }, + }, + }, + ]; +} diff --git a/apps/web-ele/src/views/mes/pro/workorder/components/index.ts b/apps/web-ele/src/views/mes/pro/workorder/components/index.ts new file mode 100644 index 000000000..1059f8a79 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/workorder/components/index.ts @@ -0,0 +1 @@ +export { default as ProWorkOrderSelect } from './pro-work-order-select.vue'; diff --git a/apps/web-ele/src/views/mes/pro/workorder/components/pro-work-order-select.vue b/apps/web-ele/src/views/mes/pro/workorder/components/pro-work-order-select.vue new file mode 100644 index 000000000..d02e67dd9 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/workorder/components/pro-work-order-select.vue @@ -0,0 +1,150 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/workrecord/components/work-record-status-bar.vue b/apps/web-ele/src/views/mes/pro/workrecord/components/work-record-status-bar.vue new file mode 100644 index 000000000..53bceb42d --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/workrecord/components/work-record-status-bar.vue @@ -0,0 +1,123 @@ + + + diff --git a/apps/web-ele/src/views/mes/pro/workrecord/data.ts b/apps/web-ele/src/views/mes/pro/workrecord/data.ts new file mode 100644 index 000000000..dea5783d5 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/workrecord/data.ts @@ -0,0 +1,107 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesProWorkRecordApi } from '#/api/mes/pro/workrecord'; +import type { SystemUserApi } from '#/api/system/user'; + +import { markRaw } from 'vue'; + +import { DICT_TYPE } from '@vben/constants'; +import { getDictOptions } from '@vben/hooks'; + +import { getSimpleUserList } from '#/api/system/user'; +import { getRangePickerDefaultProps } from '#/utils'; +import MdWorkstationSelect from '#/views/mes/md/workstation/components/md-workstation-select.vue'; + +/** 关联数据 */ +let userList: SystemUserApi.User[] = []; +getSimpleUserList().then((data) => (userList = data)); + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'userId', + label: '用户', + component: 'ApiSelect', + componentProps: { + api: getSimpleUserList, + clearable: true, + labelField: 'nickname', + placeholder: '请选择用户', + valueField: 'id', + }, + }, + { + fieldName: 'workstationId', + label: '工作站', + component: markRaw(MdWorkstationSelect), + componentProps: { + placeholder: '请选择工作站', + }, + }, + { + fieldName: 'type', + label: '操作类型', + component: 'Select', + componentProps: { + clearable: true, + options: getDictOptions(DICT_TYPE.MES_PRO_WORK_RECORD_TYPE, 'number'), + placeholder: '请选择操作类型', + }, + }, + { + fieldName: 'createTime', + label: '操作时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + clearable: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '编号', + width: 80, + }, + { + field: 'userId', + title: '用户', + width: 140, + formatter: ({ row }) => + row.userNickname || + userList.find((user) => user.id === row.userId)?.nickname || + '', + }, + { + field: 'workstationCode', + title: '工作站编码', + width: 140, + }, + { + field: 'workstationName', + title: '工作站名称', + minWidth: 160, + }, + { + field: 'type', + title: '操作类型', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_PRO_WORK_RECORD_TYPE }, + }, + }, + { + field: 'createTime', + title: '创建时间', + width: 180, + formatter: 'formatDateTime', + }, + ]; +} diff --git a/apps/web-ele/src/views/mes/pro/workrecord/index.vue b/apps/web-ele/src/views/mes/pro/workrecord/index.vue new file mode 100644 index 000000000..3c9483954 --- /dev/null +++ b/apps/web-ele/src/views/mes/pro/workrecord/index.vue @@ -0,0 +1,87 @@ + + + diff --git a/apps/web-ele/src/views/mes/tm/tool/data.ts b/apps/web-ele/src/views/mes/tm/tool/data.ts index 0c0e00050..73d57ad13 100644 --- a/apps/web-ele/src/views/mes/tm/tool/data.ts +++ b/apps/web-ele/src/views/mes/tm/tool/data.ts @@ -20,6 +20,9 @@ import { import { TmToolTypeSelect } from './type/components'; +/** 表单类型 */ +export type FormType = 'create' | 'detail' | 'update'; + /** 新增/修改工具的表单 */ export function useFormSchema(formApi?: VbenFormApi): VbenFormSchema[] { return [ diff --git a/apps/web-ele/src/views/mes/tm/tool/index.vue b/apps/web-ele/src/views/mes/tm/tool/index.vue index 9031f261f..f35cb0322 100644 --- a/apps/web-ele/src/views/mes/tm/tool/index.vue +++ b/apps/web-ele/src/views/mes/tm/tool/index.vue @@ -32,17 +32,17 @@ function handleRefresh() { /** 创建工具 */ function handleCreate() { - formModalApi.setData({ type: 'create' }).open(); + formModalApi.setData({ formType: 'create' }).open(); } /** 查看工具 */ function handleDetail(row: MesTmToolApi.Tool) { - formModalApi.setData({ id: row.id, type: 'detail' }).open(); + formModalApi.setData({ id: row.id, formType: 'detail' }).open(); } /** 编辑工具 */ function handleEdit(row: MesTmToolApi.Tool) { - formModalApi.setData({ id: row.id, type: 'update' }).open(); + formModalApi.setData({ id: row.id, formType: 'update' }).open(); } /** 删除工具 */ diff --git a/apps/web-ele/src/views/mes/tm/tool/modules/form.vue b/apps/web-ele/src/views/mes/tm/tool/modules/form.vue index bf46e425c..8ab516ab1 100644 --- a/apps/web-ele/src/views/mes/tm/tool/modules/form.vue +++ b/apps/web-ele/src/views/mes/tm/tool/modules/form.vue @@ -1,4 +1,6 @@