| | |
| | | code?: string; |
| | | type?: number; |
| | | workOrderId?: number; |
| | | taskId?: number; |
| | | taskCode?: string; |
| | | itemId?: number; |
| | | feedbackUserId?: number; |
| | | creator?: string; |
| | |
| | | } |
| | | } |
| | | |
| | | /** 按工单分页查询参数记录 */ |
| | | /** 按工单/工作站分页查询参数记录 */ |
| | | export function getWorkOrderParamRecordPage( |
| | | params: PageParam & { workOrderId: number; recordNo?: string; templateName?: string; createTime?: string[] }, |
| | | params: PageParam & { workOrderId?: number; workstationId?: number; recordNo?: string; templateName?: string; createTime?: string[] }, |
| | | ) { |
| | | return requestClient.get<PageResult<MesProWorkOrderParamRecordApi.WorkOrderParamRecord>>( |
| | | '/mes/pro/work-order-param-record/page-by-work-order', |
| | |
| | | list: PendingTask[]; |
| | | selectedId?: number; |
| | | loading?: boolean; |
| | | /** 当前工作站对应的工序名称,列表只展示匹配的工序 */ |
| | | processName?: string; |
| | | }>(); |
| | | |
| | | const emit = defineEmits<{ |
| | |
| | | |
| | | const searchKeyword = ref(''); |
| | | |
| | | /** 先按工作站工序过滤,再按搜索关键字匹配 */ |
| | | const filteredList = computed(() => { |
| | | let result = props.list; |
| | | // 固定只显示和当前工作站工序匹配的任务 |
| | | if (props.processName) { |
| | | result = result.filter((row) => row.processName === props.processName); |
| | | } |
| | | const kw = searchKeyword.value.trim().toLowerCase(); |
| | | if (!kw) return props.list; |
| | | return props.list.filter((row) => { |
| | | if (!kw) return result; |
| | | return result.filter((row) => { |
| | | const fields = [ |
| | | row.code, |
| | | row.workOrderCode, |
| | |
| | | import { |
| | | approveFeedback, |
| | | deleteFeedback, |
| | | getFeedbackListByTask, |
| | | getFeedbackPage, |
| | | rejectFeedback, |
| | | submitFeedback, |
| | | } from '#/api/mes/pro/feedback'; |
| | |
| | | keepSource: true, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async () => { |
| | | query: async ({ page }) => { |
| | | if (!props.taskId) { |
| | | return []; |
| | | return { list: [], total: 0 }; |
| | | } |
| | | return await getFeedbackListByTask(props.taskId); |
| | | return await getFeedbackPage({ |
| | | taskId: props.taskId, |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | }); |
| | | }, |
| | | }, |
| | | }, |
| | |
| | | <template #actions="{ row }"> |
| | | <Space :size="4" wrap> |
| | | <Button type="link" size="small" @click="handleDetail(row)"> |
| | | {{ $t('common.view') }} |
| | | 查看 |
| | | </Button> |
| | | <!-- 草稿:编辑、删除、提交 --> |
| | | <Button |
| | |
| | | size="small" |
| | | @click="handleEdit(row)" |
| | | > |
| | | {{ $t('common.edit') }} |
| | | 编辑 |
| | | </Button> |
| | | <Popconfirm |
| | | v-if="row.status === STATUS_PREPARE" |
| | |
| | | @confirm="handleSubmit(row)" |
| | | > |
| | | <Button type="link" size="small"> |
| | | {{ $t('common.submit') }} |
| | | 提交 |
| | | </Button> |
| | | </Popconfirm> |
| | | <Popconfirm |
| | |
| | | @confirm="handleDelete(row)" |
| | | > |
| | | <Button type="link" size="small" danger> |
| | | {{ $t('common.delete') }} |
| | | 删除 |
| | | </Button> |
| | | </Popconfirm> |
| | | <!-- 审批中:审批通过、驳回 --> |
| | |
| | | @confirm="handleApprove(row)" |
| | | > |
| | | <Button type="link" size="small"> |
| | | {{ $t('common.approve') }} |
| | | 审批通过 |
| | | </Button> |
| | | </Popconfirm> |
| | | <Popconfirm |
| | |
| | | originalSnapshot.value = JSON.stringify(await getAlignedData()); |
| | | } |
| | | |
| | | // 监听任务变更 |
| | | // 监听任务变更(仅当任务 ID 真正变化时才重置表单) |
| | | watch( |
| | | () => props.task, |
| | | (task) => { |
| | | if (task) { |
| | | resetForTask(task); |
| | | () => props.task?.id, |
| | | () => { |
| | | if (props.task) { |
| | | resetForTask(props.task); |
| | | } |
| | | }, |
| | | { immediate: true }, |
| | |
| | | const props = defineProps<{ |
| | | /** 当前工单编号 */ |
| | | workOrderId?: number; |
| | | /** 当前工作站编号 */ |
| | | workstationId?: number; |
| | | }>(); |
| | | |
| | | // --- 模式 --- |
| | |
| | | try { |
| | | const result = await getWorkOrderParamRecordPage({ |
| | | workOrderId: props.workOrderId, |
| | | workstationId: props.workstationId, |
| | | pageNo: 1, |
| | | pageSize: 100, |
| | | }); |
| | |
| | | } |
| | | } |
| | | |
| | | // 工单变更时加载记录 |
| | | // 工单或工作站变更时加载记录 |
| | | watch( |
| | | () => props.workOrderId, |
| | | () => [props.workOrderId, props.workstationId], |
| | | () => { |
| | | handleCancelForm(); |
| | | refreshRecordList(); |
| | | }, |
| | | { immediate: true }, |
| | | ); |
| | | |
| | | /** 格式化参数值展示 */ |
| | | function formatParamDisplay(detail: MesProWorkOrderParamRecordApi.ParamRecordDetail) { |
| | | const unit = detail.unitMeasureName ? ` ${detail.unitMeasureName}` : ''; |
| | | return `${detail.paramName}: ${detail.paramValue ?? '-'}${unit}`; |
| | | } |
| | | </script> |
| | | |
| | | <template> |
| | |
| | | <!-- 无工单提示 --> |
| | | <div v-if="!workOrderId" class="record-param-tab__empty"> |
| | | <IconifyIcon icon="lucide:alert-circle" class="record-param-tab__empty-icon" /> |
| | | <p>请先从左侧选择一条工单任务</p> |
| | | <p>请先选择工作站和工单任务</p> |
| | | </div> |
| | | |
| | | <!-- 空列表 --> |
| | |
| | | 备注:{{ record.remark }} |
| | | </div> |
| | | <div class="record-param-tab__card-params"> |
| | | <span |
| | | <div |
| | | v-for="d in record.details" |
| | | :key="d.id" |
| | | class="record-param-tab__param-tag" |
| | | class="record-param-tab__param-row" |
| | | > |
| | | {{ formatParamDisplay(d) }} |
| | | <span class="record-param-tab__param-name">{{ d.paramName }}</span> |
| | | <span class="record-param-tab__param-value"> |
| | | {{ d.paramValue ?? '-' }}<span v-if="d.unitMeasureName" class="record-param-tab__param-unit"> {{ d.unitMeasureName }}</span> |
| | | </span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | } |
| | | |
| | | .record-param-tab__card-params { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 6px; |
| | | display: grid; |
| | | grid-template-columns: repeat(3, 1fr); |
| | | gap: 4px 16px; |
| | | margin-top: 8px; |
| | | } |
| | | |
| | | .record-param-tab__param-tag { |
| | | display: inline-flex; |
| | | align-items: center; |
| | | padding: 3px 10px; |
| | | border-radius: 4px; |
| | | .record-param-tab__param-row { |
| | | display: flex; |
| | | align-items: baseline; |
| | | gap: 8px; |
| | | font-size: 13px; |
| | | line-height: 1.6; |
| | | padding: 2px 0; |
| | | } |
| | | |
| | | .record-param-tab__param-name { |
| | | flex-shrink: 0; |
| | | color: #8c8c8c; |
| | | min-width: 100px; |
| | | |
| | | &::after { |
| | | content: ':'; |
| | | } |
| | | } |
| | | |
| | | .record-param-tab__param-value { |
| | | color: #1a1a1a; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .record-param-tab__param-unit { |
| | | color: #8c8c8c; |
| | | font-size: 12px; |
| | | background: #f6ffed; |
| | | color: #389e0d; |
| | | border: 1px solid #d9f7be; |
| | | } |
| | | </style> |
| | |
| | | pageSize: 200, |
| | | }); |
| | | taskList.value = result.list ?? []; |
| | | // 自动选中并同步 selectedTask 到最新数据 |
| | | if (taskList.value.length) { |
| | | // 同步 selectedTask 到最新数据(不自动选中第一个,需用户手动点击) |
| | | if (selectedTask.value) { |
| | | // 尝试在新列表中找到同 ID 的任务,更新引用以刷新数据 |
| | | const updated = taskList.value.find( |
| | | (t) => t.id === selectedTask.value!.id, |
| | | ); |
| | | selectedTask.value = updated ?? taskList.value[0]; |
| | | if (updated) { |
| | | selectedTask.value = updated; |
| | | } else if (taskList.value.length) { |
| | | // 之前选中的任务不在新列表中了,清空 |
| | | selectedTask.value = undefined; |
| | | } else { |
| | | selectedTask.value = taskList.value[0]; |
| | | selectedTask.value = undefined; |
| | | } |
| | | } else { |
| | | selectedTask.value = undefined; |
| | |
| | | :list="taskList" |
| | | :selected-id="selectedTask?.id" |
| | | :loading="taskLoading" |
| | | :process-name="workstation?.processName" |
| | | @select="handleSelectTask" |
| | | /> |
| | | </aside> |
| | |
| | | <RecordParamTab |
| | | v-else-if="activeTab === 'record-param'" |
| | | :work-order-id="selectedTask?.workOrderId" |
| | | :workstation-id="workstationId" |
| | | /> |
| | | <ProductIssueTab |
| | | v-else-if="activeTab === 'product-issue'" |