Forráskód Böngészése

feat(production): add production work order management page

zlwu 5 hónapja
szülő
commit
f464c22b9e

+ 206 - 0
web-admin/src/views/production/production-work-order/index.vue

@@ -0,0 +1,206 @@
+<!-- 生产管理 — 入库生产工单 -->
+<!-- eslint-disable vue/no-v-model-argument -->
+<template>
+  <div class="page-container">
+    <header class="page-head">
+      <h1>入库生产工单</h1>
+      <p class="page-desc">入库生产工单管理,查看工单详情并完成待配置工单。</p>
+    </header>
+
+    <section class="panel">
+      <div class="panel-top">
+        <h2 class="title-bar-heading">工单列表</h2>
+      </div>
+
+      <div class="filter-block">
+        <el-form :model="searchForm" class="filter-form" @submit.prevent>
+          <div class="filter-grid">
+            <el-form-item label="工单号">
+              <el-input v-model="searchForm.keyword" placeholder="请输入工单号" clearable />
+            </el-form-item>
+            <el-form-item label="工单状态">
+              <el-select v-model="searchForm.workOrderStatus" placeholder="全部" clearable style="width: 100%">
+                <el-option label="待配置" value="dpz" />
+                <el-option label="已完成" value="ywc" />
+              </el-select>
+            </el-form-item>
+          </div>
+          <div class="filter-actions-row">
+            <div class="filter-actions-end">
+              <el-button class="btn-ghost" @click="handleReset"><el-icon><RefreshLeft /></el-icon>重置</el-button>
+              <el-button class="btn-main" type="primary" @click="handleSearch"><el-icon><Search /></el-icon>搜索</el-button>
+            </div>
+          </div>
+        </el-form>
+      </div>
+
+      <div class="list-body list-wrap">
+        <el-table class="list-table" :data="tableData" v-loading="loading" stripe @row-dblclick="handleView">
+          <el-table-column type="index" label="序号" width="68" align="center" :index="(i) => (pagination.page - 1) * pagination.pageSize + i + 1" />
+          <el-table-column prop="workOrderNo" label="工单号" min-width="150" align="center" />
+          <el-table-column prop="protocolNo" label="协议号" min-width="140" align="center" />
+          <el-table-column prop="sampleCode" label="样本编码" min-width="120" align="center" />
+          <el-table-column prop="receptionSource" label="来源类型" width="110" align="center">
+            <template #default="{ row }">
+              <el-tag :type="sourceTag(row.receptionSource).type" size="small">
+                {{ row.receptionSourceLabel || sourceTag(row.receptionSource).label }}
+              </el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column prop="workOrderStatus" label="工单状态" width="100" align="center">
+            <template #default="{ row }">
+              <el-tag :type="woStatusTag(row.workOrderStatus).type" size="small">
+                {{ woStatusTag(row.workOrderStatus).label }}
+              </el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column prop="createTime" label="创建时间" min-width="170" align="center" />
+          <el-table-column label="操作" width="280" fixed="right" align="center">
+            <template #default="{ row }">
+              <el-button class="btn-op-item" @click="handleView(row)"><el-icon><View /></el-icon>查看详情</el-button>
+              <el-button
+                v-if="row.workOrderStatus === 'dpz'"
+                class="btn-op-item primary"
+                @click="handleComplete(row)"
+              >
+                <el-icon><Check /></el-icon>完成工单
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="pagination list-pager-bar">
+          <el-pagination
+            :current-page="pagination.page"
+            :page-size="pagination.pageSize"
+            :total="pagination.total"
+            layout="total, sizes, prev, pager, next"
+            @size-change="(v) => ((pagination.page = 1), (pagination.pageSize = v), loadData())"
+            @current-change="(v) => ((pagination.page = v), loadData())"
+          />
+        </div>
+      </div>
+
+      <SystemViewDialog
+        v-model:visible="viewVisible"
+        title="工单详情"
+        :icon="Document"
+        :meta="detail?.workOrderNo || ''"
+        :sections="viewSections"
+      />
+    </section>
+  </div>
+</template>
+
+<script setup lang="ts">
+  import { ref, reactive, computed, onMounted } from 'vue'
+  import { ElMessage, ElMessageBox } from 'element-plus'
+  import { Search, RefreshLeft, View, Check, Document } from '@element-plus/icons-vue'
+  import {
+    fetchProductionWorkOrderList,
+    fetchProductionWorkOrderDetail,
+    fetchCompleteProductionWorkOrder
+  } from '@/api/production-work-order'
+  import SystemViewDialog from '@/components/business/system-view-dialog/index.vue'
+  import type { ViewSection } from '@/components/business/system-view-dialog/index.vue'
+
+  defineOptions({ name: 'ProductionProductionWorkOrder' })
+
+  /* ---- 标签映射 ---- */
+  const woStatusTag = (status: string) => {
+    const map: Record<string, { label: string; type: string }> = {
+      dpz: { label: '待配置', type: 'info' },
+      ywc: { label: '已完成', type: 'success' }
+    }
+    return map[status] || { label: status, type: 'info' }
+  }
+
+  const sourceTag = (source: string) => {
+    const map: Record<string, { label: string; type: string }> = {
+      cell_storage: { label: '细胞存储', type: 'success' },
+      research_donation: { label: '科研捐赠', type: 'primary' }
+    }
+    return map[source] || { label: source, type: 'info' }
+  }
+
+  /* ---- 搜索 & 列表 ---- */
+  const searchForm = reactive({ keyword: '', workOrderStatus: '' })
+  const tableData = ref<any[]>([])
+  const loading = ref(false)
+  const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
+
+  async function loadData() {
+    loading.value = true
+    try {
+      const res = await fetchProductionWorkOrderList({
+        page: pagination.page,
+        pageSize: pagination.pageSize,
+        keyword: searchForm.keyword || undefined,
+        workOrderStatus: searchForm.workOrderStatus || undefined
+      })
+      tableData.value = res.list || []
+      pagination.total = res.total ?? 0
+    } finally {
+      loading.value = false
+    }
+  }
+
+  function handleSearch() {
+    pagination.page = 1
+    loadData()
+  }
+
+  function handleReset() {
+    searchForm.keyword = ''
+    searchForm.workOrderStatus = ''
+    pagination.page = 1
+    loadData()
+  }
+
+  /* ---- 查看详情 ---- */
+  const viewVisible = ref(false)
+  const detail = ref<any>(null)
+
+  const viewSections = computed<ViewSection[]>(() => {
+    if (!detail.value) return []
+    const d = detail.value
+    return [
+      {
+        title: '基本信息',
+        fields: [
+          { label: '工单号', value: d.workOrderNo },
+          { label: '协议号', value: d.protocolNo },
+          { label: '样本编码', value: d.sampleCode },
+          {
+            label: '来源类型',
+            value: sourceTag(d.receptionSource).label,
+            tagType: sourceTag(d.receptionSource).type as any
+          },
+          {
+            label: '工单状态',
+            value: woStatusTag(d.workOrderStatus).label,
+            tagType: woStatusTag(d.workOrderStatus).type as any
+          },
+          { label: '创建时间', value: d.createTime || '—' },
+          { label: '备注', value: d.remark || '—', span: true }
+        ]
+      }
+    ]
+  })
+
+  async function handleView(row: any) {
+    detail.value = await fetchProductionWorkOrderDetail(row.id)
+    viewVisible.value = true
+  }
+
+  /* ---- 完成工单 ---- */
+  async function handleComplete(row: any) {
+    await ElMessageBox.confirm('确定要完成该工单吗?', '提示', { type: 'warning' })
+    await fetchCompleteProductionWorkOrder(row.id, {})
+    ElMessage.success('工单已完成')
+    loadData()
+  }
+
+  onMounted(() => loadData())
+</script>
+
+<style scoped lang="scss"></style>