Pārlūkot izejas kodu

调整瑞鹰看板

Zimo 6 dienas atpakaļ
vecāks
revīzija
e90c770e7d

+ 3 - 0
src/api/pms/stat/index.ts

@@ -159,6 +159,9 @@ export const IotStatApi = {
   getRyTeamRate: async (params: any) => {
     return await request.get({ url: `rq/stat/ry/device/teamUtilizationRate`, params })
   },
+  getRyProductionBriefs: async (params: any) => {
+    return await request.get({ url: `/pms/iot-ry-daily-report/productionBriefs`, params })
+  },
   getRdTeamRate: async (params: any) => {
     return await request.get({ url: `rq/stat/rd/device/teamUtilizationRate`, params })
   },

+ 3 - 3
src/views/pms/stat/rykb.vue

@@ -3,11 +3,11 @@ import { DESIGN_HEIGHT, DESIGN_WIDTH } from '@/utils/kb'
 import rysummary from './rykb/rysummary.vue'
 import safeday from './rykb/safeday.vue'
 import rydeviceStatus from './rykb/rydeviceStatus.vue'
-import ryorderTrend from './rykb/ryorderTrend.vue'
 import zjfinish from './rykb/zjfinish.vue'
 import zjwork from './rykb/zjwork.vue'
 import xjwork from './rykb/xjwork.vue'
 import rydeviceList from './rykb/rydeviceList.vue'
+import ryProductionBriefs from './rykb/ryProductionBriefs.vue'
 
 defineOptions({
   name: 'IotRyStatt'
@@ -84,12 +84,12 @@ onUnmounted(() => {
           <div class="w-full h-148 grid grid-rows-2 grid-cols-3 gap-3 mt-3">
             <rydeviceStatus class="kb-stage-card kb-stage-card--2" />
             <safeday class="kb-stage-card kb-stage-card--3" />
-            <ryorderTrend class="kb-stage-card kb-stage-card--4" />
+            <rydeviceList class="kb-stage-card kb-stage-card--4 kb-stage-card--list" />
             <zjfinish class="kb-stage-card kb-stage-card--5" />
             <zjwork class="kb-stage-card kb-stage-card--6" />
             <xjwork class="kb-stage-card kb-stage-card--7" />
           </div>
-          <rydeviceList class="kb-stage-card kb-stage-card--8 kb-stage-card--list" />
+          <ryProductionBriefs class="kb-stage-card kb-stage-card--8 kb-stage-card--list" />
         </div>
       </div>
     </div>

+ 251 - 0
src/views/pms/stat/rykb/ryProductionBriefs.vue

@@ -0,0 +1,251 @@
+<script lang="ts" setup>
+import { IotStatApi } from '@/api/pms/stat'
+import { rangeShortcuts } from '@/utils/formatTime'
+import dayjs from 'dayjs'
+
+interface RyProductionBriefRow {
+  id: number
+  projectClassification: string
+  projectName: string
+  deptName: string
+  taskName: string
+  constructionStatusName: string
+  dailyFootage: number | null
+  completedWells: number | null
+  dailyPowerUsage: number | null
+  dailyFuel: number | null
+  nonProductionTime: number | null
+  nextPlan: string
+  constructionBrief: string
+  projectSort?: number | null
+  teamSort?: number | null
+}
+
+interface SpanMethodProps {
+  rowIndex: number
+  columnIndex: number
+}
+
+const TABLE_HEIGHT = 220
+const MERGE_COLUMN_INDEXES = [0, 1]
+const COMPANY_ORDER = ['钻井', '修井']
+const DEFAULT_TIME_RANGE = rangeShortcuts[2]
+  .value()
+  .map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
+
+const createTime = ref<string[]>(DEFAULT_TIME_RANGE)
+const loading = ref(false)
+const list = ref<RyProductionBriefRow[]>([])
+
+const tableData = computed(() => {
+  return [...list.value].sort((a, b) => {
+    const companySort =
+      getCompanyOrder(a.projectClassification) - getCompanyOrder(b.projectClassification)
+    if (companySort !== 0) return companySort
+
+    const projectSort = Number(a.projectSort ?? 9999) - Number(b.projectSort ?? 9999)
+    if (projectSort !== 0) return projectSort
+
+    const projectNameSort = (a.projectName || '').localeCompare(b.projectName || '', 'zh-Hans-CN')
+    if (projectNameSort !== 0) return projectNameSort
+
+    return Number(a.teamSort ?? 9999) - Number(b.teamSort ?? 9999)
+  })
+})
+
+const spanMaps = computed(() => {
+  return {
+    company: createSpanMap(tableData.value, (row) => row.projectClassification || '-'),
+    project: createSpanMap(
+      tableData.value,
+      (row) => `${row.projectClassification || '-'}__${row.projectName || '-'}`
+    )
+  }
+})
+
+function getCompanyOrder(value?: string) {
+  const index = COMPANY_ORDER.indexOf(value || '')
+  return index === -1 ? COMPANY_ORDER.length : index
+}
+
+function createSpanMap(
+  rows: RyProductionBriefRow[],
+  getKey: (row: RyProductionBriefRow) => string
+) {
+  const spanMap: number[] = []
+
+  rows.forEach((row, index) => {
+    const key = getKey(row)
+
+    if (index > 0 && getKey(rows[index - 1]) === key) {
+      spanMap[index] = 0
+      return
+    }
+
+    let span = 1
+    for (let nextIndex = index + 1; nextIndex < rows.length; nextIndex++) {
+      if (getKey(rows[nextIndex]) !== key) break
+      span += 1
+    }
+    spanMap[index] = span
+  })
+
+  return spanMap
+}
+
+function tableSpanMethod({ rowIndex, columnIndex }: SpanMethodProps) {
+  if (!MERGE_COLUMN_INDEXES.includes(columnIndex)) {
+    return {
+      rowspan: 1,
+      colspan: 1
+    }
+  }
+
+  const rowspan =
+    columnIndex === 0 ? spanMaps.value.company[rowIndex] : spanMaps.value.project[rowIndex]
+
+  return {
+    rowspan,
+    colspan: rowspan > 0 ? 1 : 0
+  }
+}
+
+function formatNumber(value?: number | null, fractionDigits = 1) {
+  const numberValue = Number(value ?? 0)
+  return Number.isInteger(numberValue) ? `${numberValue}` : numberValue.toFixed(fractionDigits)
+}
+
+function formatFootageOrWell(row: RyProductionBriefRow) {
+  if (row.projectClassification === '钻井') {
+    return `${formatNumber(row.dailyFootage)}m`
+  }
+
+  return formatNumber(row.completedWells, 0)
+}
+
+function normalizeList(res: any): RyProductionBriefRow[] {
+  if (Array.isArray(res)) return res
+  if (Array.isArray(res?.list)) return res.list
+  if (Array.isArray(res?.records)) return res.records
+  if (Array.isArray(res?.data)) return res.data
+  return []
+}
+
+function handleDateChange() {
+  getList()
+}
+
+async function getList() {
+  loading.value = true
+
+  try {
+    const res = await IotStatApi.getRyProductionBriefs({ createTime: createTime.value })
+    list.value = normalizeList(res).filter((row) =>
+      COMPANY_ORDER.includes(row.projectClassification || '')
+    )
+  } catch (error) {
+    console.error('获取瑞鹰生产简报失败:', error)
+    list.value = []
+  } finally {
+    loading.value = false
+  }
+}
+
+onMounted(() => {
+  getList()
+})
+</script>
+
+<template>
+  <div class="panel w-full h-[280px] flex flex-col mt-3">
+    <div class="panel-title h-9 flex items-center justify-between">
+      <div class="flex items-center">
+        <div class="icon-decorator">
+          <span></span>
+          <span></span>
+        </div>
+        生产简报
+      </div>
+      <div class="w-260px! -translate-y-[4px]">
+        <el-date-picker
+          v-model="createTime"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          :clearable="false"
+          class="w-260px!"
+          @change="handleDateChange" />
+      </div>
+    </div>
+    <div class="flex-1 min-h-0 px-4 py-2">
+      <el-table
+        v-loading="loading"
+        :data="tableData"
+        :height="TABLE_HEIGHT"
+        :span-method="tableSpanMethod"
+        class="device-list-table production-brief-table">
+        <el-table-column prop="projectClassification" label="公司" min-width="72" align="center" />
+        <el-table-column prop="projectName" label="项目" min-width="150" align="center" />
+        <el-table-column prop="deptName" label="队伍" min-width="94" align="center" />
+        <el-table-column prop="taskName" label="生产任务" min-width="130" align="center" />
+        <el-table-column
+          prop="constructionStatusName"
+          label="运行状态"
+          min-width="88"
+          align="center" />
+
+        <el-table-column prop="nextPlan" label="下步任务" min-width="130" align="center" />
+        <el-table-column
+          prop="constructionBrief"
+          label="当日生产简况"
+          min-width="160"
+          align="center" />
+
+        <el-table-column label="当日进尺(m)/当日井次" min-width="150" align="center">
+          <template #default="{ row }">
+            {{ formatFootageOrWell(row) }}
+          </template>
+        </el-table-column>
+        <el-table-column label="当日电耗(kwh)" min-width="120" align="center">
+          <template #default="{ row }">
+            {{ formatNumber(row.dailyPowerUsage) }}
+          </template>
+        </el-table-column>
+        <el-table-column label="当日油耗(升)" min-width="112" align="center">
+          <template #default="{ row }">
+            {{ formatNumber(row.dailyFuel) }}
+          </template>
+        </el-table-column>
+        <el-table-column label="当日非生产时间" min-width="126" align="center">
+          <template #default="{ row }">
+            {{ formatNumber(row.nonProductionTime) }}
+          </template>
+        </el-table-column>
+
+        <template #empty>
+          <div class="h-full min-h-[220px] flex items-center justify-center">
+            <el-empty description="暂无数据" :image-size="72" />
+          </div>
+        </template>
+      </el-table>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+@import url('@/styles/kb.scss');
+
+.production-brief-table {
+  :deep(.el-table__header-wrapper th.el-table__cell) {
+    font-size: 16px;
+    line-height: 1.2;
+  }
+
+  :deep(.el-table__body td.el-table__cell) {
+    padding: 7px 0;
+    font-size: 14px;
+  }
+}
+</style>

+ 23 - 16
src/views/pms/stat/rykb/rydeviceList.vue

@@ -94,7 +94,7 @@ onMounted(() => {
 </script>
 
 <template>
-  <div class="panel w-full h-[280px] flex flex-col mt-3">
+  <div class="panel w-full h-full flex flex-col">
     <div class="panel-title h-9 flex items-center justify-between">
       <div class="flex items-center">
         <div class="icon-decorator">
@@ -103,7 +103,7 @@ onMounted(() => {
         </div>
         项目部统计
       </div>
-      <div class="w-260px! -translate-y-[4px]">
+      <div class="w-220px! -translate-y-[4px]">
         <el-date-picker
           v-model="createTime"
           value-format="YYYY-MM-DD HH:mm:ss"
@@ -112,9 +112,8 @@ onMounted(() => {
           end-placeholder="结束日期"
           :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
           :clearable="false"
-          class="w-260px!"
-          @change="handleDateChange"
-        />
+          class="w-220px!"
+          @change="handleDateChange" />
       </div>
     </div>
     <!-- v-loading="loading" -->
@@ -123,18 +122,17 @@ onMounted(() => {
         :data="tableData"
         :height="TABLE_HEIGHT"
         class="device-list-table"
-        @row-click="handleRowClick"
-      >
-        <el-table-column prop="projectDeptName" label="项目部" min-width="220" align="center" />
-        <el-table-column prop="teamCount" label="队伍数量" min-width="120" align="center" />
-        <el-table-column prop="cumulativeDays" label="累计天数" min-width="120" align="center" />
-        <el-table-column prop="constructionDays" label="施工天数" min-width="120" align="center" />
+        @row-click="handleRowClick">
+        <el-table-column prop="projectDeptName" label="项目部" min-width="150" align="center" />
+        <el-table-column prop="teamCount" label="队伍数量" min-width="88" align="center" />
+        <el-table-column prop="cumulativeDays" label="累计天数" min-width="92" align="center" />
+        <el-table-column prop="constructionDays" label="施工天数" min-width="92" align="center" />
         <!-- <el-table-column label="注气量(万方)" min-width="150" align="center">
           <template #default="{ row }">
             {{ formatGasInjection(row.gasInjection) }}
           </template>
         </el-table-column> -->
-        <el-table-column label="设备利用率" min-width="140" align="center">
+        <el-table-column label="设备利用率" min-width="110" align="center">
           <template #default="{ row }">
             {{ formatRate(row.utilizationRate) }}
           </template>
@@ -154,14 +152,12 @@ onMounted(() => {
       destroy-on-close
       class="device-list-dialog"
       @closed="handleDialogClosed"
-      append-to-body
-    >
+      append-to-body>
       <el-table
         v-loading="teamLoading"
         :data="teamList"
         :height="TEAM_TABLE_HEIGHT"
-        class="team-list-table"
-      >
+        class="team-list-table">
         <el-table-column prop="teamName" label="队伍名称" min-width="220" align="center" />
         <el-table-column prop="cumulativeDays" label="累计天数" min-width="140" align="center" />
         <el-table-column prop="constructionDays" label="施工天数" min-width="140" align="center" />
@@ -183,6 +179,17 @@ onMounted(() => {
 
 <style lang="scss" scoped>
 @import url('@/styles/kb.scss');
+
+.device-list-table {
+  :deep(.el-table__header-wrapper th.el-table__cell) {
+    font-size: 17px;
+    line-height: 1.25;
+  }
+
+  :deep(.el-table__body td.el-table__cell) {
+    font-size: 15px;
+  }
+}
 </style>
 
 <style>