src/views/mes/workbench/index.vue
@@ -2,14 +2,22 @@
import type { MesMdWorkstationApi } from '#/api/mes/md/workstation';
import type { PendingTask, WorkbenchTabItem, WorkbenchTabKey } from './types';
import { computed, ref, watch } from 'vue';
import { computed, onMounted, ref, watch } from 'vue';
import { confirm } from '@vben/common-ui';
import { MesProWorkRecordTypeEnum } from '@vben/constants';
import { IconifyIcon } from '@vben/icons';
import { Button } from 'ant-design-vue';
import { Button, message } from 'ant-design-vue';
import {
  clockInWorkRecord,
  clockOutWorkRecord,
  getMyWorkRecord,
} from '#/api/mes/pro/workrecord';
import { getPendingFeedbackPage } from '#/api/mes/pro/task';
import { router } from '#/router';
import { useAccess } from '@vben/access';
import TaskListPanel from './components/TaskListPanel.vue';
import WorkstationPanel from './components/WorkstationPanel.vue';
@@ -26,16 +34,36 @@
// --- Tab 配置 ---
const tabItems: WorkbenchTabItem[] = [
  { key: 'detail', label: '工单详情', icon: 'lucide:file-text' },
  { key: 'feedback', label: '报工', icon: 'lucide:edit-3' },
  { key: 'history', label: '报工记录', icon: 'lucide:history' },
  { key: 'feedback', label: '报工', icon: 'lucide:edit-3', auth: ['mes:pro-feedback:create'] },
  { key: 'history', label: '报工记录', icon: 'lucide:history' ,auth: ['mes:pro-feedback:query']},
  { key: 'record-param', label: '生产记录参数', icon: 'lucide:file-cog' },
  { key: 'product-issue', label: '领料', icon: 'lucide:clipboard-list' },
  { key: 'return-issue', label: '退料', icon: 'lucide:rotate-ccw' },
];
const { hasAccessByCodes } = useAccess();
const availableTabs = computed(() => {
  return tabItems.filter((tab) => {
    if (!tab.auth || tab.auth.length === 0) return true;
    return hasAccessByCodes(tab.auth);
  });
});
const activeTab = ref<WorkbenchTabKey>('detail');
const activeTabLabel = computed(
  () => tabItems.find((t) => t.key === activeTab.value)?.label ?? '',
  () => availableTabs.value.find((t) => t.key === activeTab.value)?.label ?? '',
);
// 当可用 tab 变化时,如果当前选中的 tab 不可用,则自动选择第一个可用的 tab
watch(
  availableTabs,
  (tabs) => {
    if (tabs.length > 0 && !tabs.find((t) => t.key === activeTab.value)) {
      activeTab.value = tabs[0]!.key;
    }
  },
  { immediate: true },
);
// --- 工作站 ---
@@ -51,6 +79,43 @@
function handleWorkstationSelect(ws: MesMdWorkstationApi.Workstation) {
  workstation.value = ws;
}
// --- 上工/下工 ---
const isClockIn = ref(false);
async function loadClockStatus() {
  const record = await getMyWorkRecord();
  isClockIn.value = record?.type === MesProWorkRecordTypeEnum.CLOCK_IN;
}
/** 上工:默认使用当前选中的工作站,弹窗确认 */
async function handleClockIn() {
  if (!workstationId.value) return;
  try {
    await confirm(
      `确认上工到当前工作站「${workstation.value?.code} - ${workstation.value?.name}」?`,
    );
  } catch {
    return;
  }
  await clockInWorkRecord(workstationId.value);
  message.success('上工成功');
  isClockIn.value = true;
}
/** 下工 */
async function handleClockOut() {
  try {
    await confirm('确认下工当前工作站?');
  } catch {
    return;
  }
  await clockOutWorkRecord();
  message.success('下工成功');
  isClockIn.value = false;
}
onMounted(loadClockStatus);
// --- 任务列表 ---
const taskList = ref<PendingTask[]>([]);
@@ -132,7 +197,7 @@
      <nav class="workbench-nav">
        <button
          v-for="tab in tabItems"
          v-for="tab in availableTabs"
          :key="tab.key"
          type="button"
          class="workbench-nav__item"
@@ -159,7 +224,10 @@
        <!-- 工作站选择面板 -->
        <WorkstationPanel
          :workstation="workstation"
          :is-clock-in="isClockIn"
          @change="openWorkstationSelect"
          @clock-in="handleClockIn"
          @clock-out="handleClockOut"
        />
        <!-- 工单列表 -->
@@ -167,8 +235,8 @@
          :list="taskList"
          :selected-id="selectedTask?.id"
          :loading="taskLoading"
          :process-name="workstation?.processName"
          @select="handleSelectTask"
          @refresh="loadTaskList"
        />
      </aside>
@@ -181,8 +249,8 @@
      <main class="workbench-main">
        <div class="workbench-main__head">
          <span class="workbench-main__tab-title">{{ activeTabLabel }}</span>
          <span v-if="selectedTask?.workOrderCode" class="workbench-main__context">
            工单 {{ selectedTask.workOrderCode }}
          <span v-if="selectedTask?.code" class="workbench-main__context">
            工单 {{ selectedTask.code }}
          </span>
        </div>
        <div class="workbench-main__body">
@@ -204,16 +272,25 @@
          />
          <RecordParamTab
            v-else-if="activeTab === 'record-param'"
            :work-order-id="selectedTask?.workOrderId"
            :task-id="selectedTask?.id"
            :work-order-id="selectedTask?.id"
            :workstation-id="workstationId"
          />
          <ProductIssueTab
            v-else-if="activeTab === 'product-issue'"
            :task-id="selectedTask?.id"
            :task-code="selectedTask?.code"
            :task-name="selectedTask?.name"
            :work-order-id="selectedTask?.workOrderId"
            :workstation-id="workstationId"
            :workstation-name="workstationName"
          />
          <ReturnIssueTab
            v-else-if="activeTab === 'return-issue'"
            :task-id="selectedTask?.id"
            :task-code="selectedTask?.code"
            :task-name="selectedTask?.name"
            :work-order-id="selectedTask?.workOrderId"
            :workstation-id="workstationId"
            :workstation-name="workstationName"
          />