ryProductionBriefs.vue 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. <script lang="ts" setup>
  2. import { IotStatApi } from '@/api/pms/stat'
  3. import { rangeShortcuts } from '@/utils/formatTime'
  4. import dayjs from 'dayjs'
  5. interface RyProductionBriefRow {
  6. id: number
  7. projectClassification: string
  8. projectName: string
  9. deptName: string
  10. taskName: string
  11. constructionStatusName: string
  12. dailyFootage: number | null
  13. completedWells: number | null
  14. dailyPowerUsage: number | null
  15. dailyFuel: number | null
  16. nonProductionTime: number | null
  17. nextPlan: string
  18. constructionBrief: string
  19. projectSort?: number | null
  20. teamSort?: number | null
  21. }
  22. interface SpanMethodProps {
  23. rowIndex: number
  24. columnIndex: number
  25. }
  26. const TABLE_HEIGHT = 220
  27. const MERGE_COLUMN_INDEXES = [0, 1]
  28. const COMPANY_ORDER = ['钻井', '修井']
  29. const DEFAULT_TIME_RANGE = rangeShortcuts[2]
  30. .value()
  31. .map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
  32. const createTime = ref<string[]>(DEFAULT_TIME_RANGE)
  33. const loading = ref(false)
  34. const list = ref<RyProductionBriefRow[]>([])
  35. const tableData = computed(() => {
  36. return [...list.value].sort((a, b) => {
  37. const companySort =
  38. getCompanyOrder(a.projectClassification) - getCompanyOrder(b.projectClassification)
  39. if (companySort !== 0) return companySort
  40. const projectSort = Number(a.projectSort ?? 9999) - Number(b.projectSort ?? 9999)
  41. if (projectSort !== 0) return projectSort
  42. const projectNameSort = (a.projectName || '').localeCompare(b.projectName || '', 'zh-Hans-CN')
  43. if (projectNameSort !== 0) return projectNameSort
  44. return Number(a.teamSort ?? 9999) - Number(b.teamSort ?? 9999)
  45. })
  46. })
  47. const spanMaps = computed(() => {
  48. return {
  49. company: createSpanMap(tableData.value, (row) => row.projectClassification || '-'),
  50. project: createSpanMap(
  51. tableData.value,
  52. (row) => `${row.projectClassification || '-'}__${row.projectName || '-'}`
  53. )
  54. }
  55. })
  56. function getCompanyOrder(value?: string) {
  57. const index = COMPANY_ORDER.indexOf(value || '')
  58. return index === -1 ? COMPANY_ORDER.length : index
  59. }
  60. function createSpanMap(
  61. rows: RyProductionBriefRow[],
  62. getKey: (row: RyProductionBriefRow) => string
  63. ) {
  64. const spanMap: number[] = []
  65. rows.forEach((row, index) => {
  66. const key = getKey(row)
  67. if (index > 0 && getKey(rows[index - 1]) === key) {
  68. spanMap[index] = 0
  69. return
  70. }
  71. let span = 1
  72. for (let nextIndex = index + 1; nextIndex < rows.length; nextIndex++) {
  73. if (getKey(rows[nextIndex]) !== key) break
  74. span += 1
  75. }
  76. spanMap[index] = span
  77. })
  78. return spanMap
  79. }
  80. function tableSpanMethod({ rowIndex, columnIndex }: SpanMethodProps) {
  81. if (!MERGE_COLUMN_INDEXES.includes(columnIndex)) {
  82. return {
  83. rowspan: 1,
  84. colspan: 1
  85. }
  86. }
  87. const rowspan =
  88. columnIndex === 0 ? spanMaps.value.company[rowIndex] : spanMaps.value.project[rowIndex]
  89. return {
  90. rowspan,
  91. colspan: rowspan > 0 ? 1 : 0
  92. }
  93. }
  94. function formatNumber(value?: number | null, fractionDigits = 1) {
  95. const numberValue = Number(value ?? 0)
  96. return Number.isInteger(numberValue) ? `${numberValue}` : numberValue.toFixed(fractionDigits)
  97. }
  98. function formatFootageOrWell(row: RyProductionBriefRow) {
  99. if (row.projectClassification === '钻井') {
  100. return `${formatNumber(row.dailyFootage)}m`
  101. }
  102. return formatNumber(row.completedWells, 0)
  103. }
  104. function normalizeList(res: any): RyProductionBriefRow[] {
  105. if (Array.isArray(res)) return res
  106. if (Array.isArray(res?.list)) return res.list
  107. if (Array.isArray(res?.records)) return res.records
  108. if (Array.isArray(res?.data)) return res.data
  109. return []
  110. }
  111. function handleDateChange() {
  112. getList()
  113. }
  114. async function getList() {
  115. loading.value = true
  116. try {
  117. const res = await IotStatApi.getRyProductionBriefs({ createTime: createTime.value })
  118. list.value = normalizeList(res).filter((row) =>
  119. COMPANY_ORDER.includes(row.projectClassification || '')
  120. )
  121. } catch (error) {
  122. console.error('获取瑞鹰生产简报失败:', error)
  123. list.value = []
  124. } finally {
  125. loading.value = false
  126. }
  127. }
  128. onMounted(() => {
  129. getList()
  130. })
  131. </script>
  132. <template>
  133. <div class="panel w-full h-[280px] flex flex-col mt-3">
  134. <div class="panel-title h-9 flex items-center justify-between">
  135. <div class="flex items-center">
  136. <div class="icon-decorator">
  137. <span></span>
  138. <span></span>
  139. </div>
  140. 生产简报
  141. </div>
  142. <div class="w-260px! -translate-y-[4px]">
  143. <el-date-picker
  144. v-model="createTime"
  145. value-format="YYYY-MM-DD HH:mm:ss"
  146. type="daterange"
  147. start-placeholder="开始日期"
  148. end-placeholder="结束日期"
  149. :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
  150. :clearable="false"
  151. class="w-260px!"
  152. @change="handleDateChange" />
  153. </div>
  154. </div>
  155. <div class="flex-1 min-h-0 px-4 py-2">
  156. <el-table
  157. v-loading="loading"
  158. :data="tableData"
  159. :height="TABLE_HEIGHT"
  160. :span-method="tableSpanMethod"
  161. class="device-list-table production-brief-table">
  162. <el-table-column prop="projectClassification" label="公司" min-width="72" align="center" />
  163. <el-table-column prop="projectName" label="项目" min-width="150" align="center" />
  164. <el-table-column prop="deptName" label="队伍" min-width="94" align="center" />
  165. <el-table-column prop="taskName" label="生产任务" min-width="130" align="center" />
  166. <el-table-column
  167. prop="constructionStatusName"
  168. label="运行状态"
  169. min-width="88"
  170. align="center" />
  171. <el-table-column prop="nextPlan" label="下步任务" min-width="130" align="center" />
  172. <el-table-column
  173. prop="constructionBrief"
  174. label="当日生产简况"
  175. min-width="160"
  176. align="center" />
  177. <el-table-column label="当日进尺(m)/当日井次" min-width="150" align="center">
  178. <template #default="{ row }">
  179. {{ formatFootageOrWell(row) }}
  180. </template>
  181. </el-table-column>
  182. <el-table-column label="当日电耗(kwh)" min-width="120" align="center">
  183. <template #default="{ row }">
  184. {{ formatNumber(row.dailyPowerUsage) }}
  185. </template>
  186. </el-table-column>
  187. <el-table-column label="当日油耗(升)" min-width="112" align="center">
  188. <template #default="{ row }">
  189. {{ formatNumber(row.dailyFuel) }}
  190. </template>
  191. </el-table-column>
  192. <el-table-column label="当日非生产时间" min-width="126" align="center">
  193. <template #default="{ row }">
  194. {{ formatNumber(row.nonProductionTime) }}
  195. </template>
  196. </el-table-column>
  197. <template #empty>
  198. <div class="h-full min-h-[220px] flex items-center justify-center">
  199. <el-empty description="暂无数据" :image-size="72" />
  200. </div>
  201. </template>
  202. </el-table>
  203. </div>
  204. </div>
  205. </template>
  206. <style lang="scss" scoped>
  207. @import url('@/styles/kb.scss');
  208. .production-brief-table {
  209. :deep(.el-table__header-wrapper th.el-table__cell) {
  210. font-size: 16px;
  211. line-height: 1.2;
  212. }
  213. :deep(.el-table__body td.el-table__cell) {
  214. padding: 7px 0;
  215. font-size: 14px;
  216. }
  217. }
  218. </style>