rydeviceList.vue 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. <script lang="ts" setup>
  2. import { IotStatApi } from '@/api/pms/stat'
  3. import dayjs from 'dayjs'
  4. interface RhDeviceListRow {
  5. projectDeptId: number
  6. projectDeptName: string
  7. teamCount: number
  8. cumulativeDays: number
  9. constructionDays: number
  10. utilizationRate: number
  11. gasInjection: number
  12. sort?: number | null
  13. }
  14. interface RhTeamRateRow {
  15. teamName: string
  16. cumulativeDays: number
  17. constructionDays: number
  18. utilizationRate: number
  19. }
  20. const TEAM_TABLE_HEIGHT = 500
  21. const DEFAULT_TIME_RANGE = [
  22. dayjs().subtract(7, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss'),
  23. dayjs().subtract(1, 'day').endOf('day').format('YYYY-MM-DD HH:mm:ss')
  24. ]
  25. const createTime = ref<string[]>(DEFAULT_TIME_RANGE)
  26. const loading = ref(false)
  27. const list = ref<RhDeviceListRow[]>([])
  28. const teamDialogVisible = ref(false)
  29. const teamLoading = ref(false)
  30. const currentProjectDeptName = ref('')
  31. const teamList = ref<RhTeamRateRow[]>([])
  32. const tableData = computed(() => list.value)
  33. const tableHeight = '100%'
  34. function formatRate(value?: number | null) {
  35. return `${(Number(value ?? 0) * 100).toFixed(2)}%`
  36. }
  37. // function formatGasInjection(value?: number | null) {
  38. // return (Number(value ?? 0) / 10000).toFixed(2)
  39. // }
  40. function handleDateChange() {
  41. getList()
  42. }
  43. async function handleRowClick(row: RhDeviceListRow) {
  44. currentProjectDeptName.value = row.projectDeptName || '项目部'
  45. teamDialogVisible.value = true
  46. teamLoading.value = true
  47. try {
  48. const res = await IotStatApi.getRyTeamRate({
  49. deptId: row.projectDeptId,
  50. createTime: createTime.value
  51. })
  52. teamList.value = Array.isArray(res) ? (res as RhTeamRateRow[]) : []
  53. } catch (error) {
  54. console.error('获取瑞鹰队伍明细失败:', error)
  55. teamList.value = []
  56. } finally {
  57. teamLoading.value = false
  58. }
  59. }
  60. function handleDialogClosed() {
  61. teamList.value = []
  62. currentProjectDeptName.value = ''
  63. teamLoading.value = false
  64. }
  65. async function getList() {
  66. loading.value = true
  67. try {
  68. const res = await IotStatApi.getRyRate({ createTime: createTime.value })
  69. list.value = Array.isArray(res) ? (res as RhDeviceListRow[]) : []
  70. } catch (error) {
  71. console.error('获取瑞鹰项目部汇总失败:', error)
  72. list.value = []
  73. } finally {
  74. loading.value = false
  75. }
  76. }
  77. onMounted(() => {
  78. getList()
  79. })
  80. </script>
  81. <template>
  82. <div class="panel w-full h-full flex flex-col">
  83. <div class="panel-title flex items-center justify-between">
  84. <div class="kb-panel-title-text flex items-center">
  85. <div class="icon-decorator">
  86. <span></span>
  87. <span></span>
  88. </div>
  89. 设备利用率
  90. </div>
  91. <div class="ry-device-list-panel__picker">
  92. <el-date-picker
  93. v-model="createTime"
  94. value-format="YYYY-MM-DD HH:mm:ss"
  95. type="daterange"
  96. start-placeholder="开始日期"
  97. end-placeholder="结束日期"
  98. :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
  99. :clearable="false"
  100. class="ry-device-list-panel__picker-input"
  101. @change="handleDateChange" />
  102. </div>
  103. </div>
  104. <!-- v-loading="loading" -->
  105. <div class="device-list-panel__body flex flex-col flex-1 min-h-0">
  106. <el-table
  107. :data="tableData"
  108. :height="tableHeight"
  109. class="device-list-table"
  110. @row-click="handleRowClick">
  111. <el-table-column prop="projectDeptName" label="项目部" align="center" />
  112. <el-table-column prop="teamCount" label="队伍数量" width="72" align="center" />
  113. <el-table-column prop="cumulativeDays" label="累计天数" width="72" align="center" />
  114. <el-table-column prop="constructionDays" label="施工天数" width="72" align="center" />
  115. <!-- <el-table-column label="注气量(万方)" min-width="150" align="center">
  116. <template #default="{ row }">
  117. {{ formatGasInjection(row.gasInjection) }}
  118. </template>
  119. </el-table-column> -->
  120. <el-table-column label="设备利用率" align="center">
  121. <template #default="{ row }">
  122. {{ formatRate(row.utilizationRate) }}
  123. </template>
  124. </el-table-column>
  125. <template #empty>
  126. <div class="h-full min-h-[220px] flex items-center justify-center">
  127. <el-empty description="暂无数据" :image-size="72" />
  128. </div>
  129. </template>
  130. </el-table>
  131. </div>
  132. <el-dialog
  133. v-model="teamDialogVisible"
  134. :title="`${currentProjectDeptName || '项目部'}队伍明细`"
  135. width="1200px"
  136. destroy-on-close
  137. class="device-list-dialog"
  138. @closed="handleDialogClosed"
  139. append-to-body>
  140. <el-table
  141. v-loading="teamLoading"
  142. :data="teamList"
  143. :height="TEAM_TABLE_HEIGHT"
  144. class="team-list-table">
  145. <el-table-column prop="teamName" label="队伍名称" min-width="220" align="center" />
  146. <el-table-column prop="cumulativeDays" label="累计天数" min-width="140" align="center" />
  147. <el-table-column prop="constructionDays" label="施工天数" min-width="140" align="center" />
  148. <el-table-column label="设备利用率" min-width="160" align="center">
  149. <template #default="{ row }">
  150. {{ formatRate(row.utilizationRate) }}
  151. </template>
  152. </el-table-column>
  153. <template #empty>
  154. <div class="h-full min-h-[220px] flex items-center justify-center">
  155. <el-empty description="暂无队伍明细" :image-size="72" />
  156. </div>
  157. </template>
  158. </el-table>
  159. </el-dialog>
  160. </div>
  161. </template>
  162. <style lang="scss" scoped>
  163. @import url('@/styles/kb.scss');
  164. .ry-device-list-panel__picker {
  165. display: flex;
  166. width: calc(260px * var(--kb-scale, 1));
  167. align-items: center;
  168. }
  169. .ry-device-list-panel__picker-input {
  170. width: calc(260px * var(--kb-scale, 1)) !important;
  171. :deep(.el-input__wrapper) {
  172. min-height: calc(28px * var(--kb-scale, 1));
  173. padding: 0 calc(10px * var(--kb-scale, 1));
  174. }
  175. :deep(.el-range-input),
  176. :deep(.el-range-separator) {
  177. font-size: calc(12px * var(--kb-scale, 1));
  178. }
  179. :deep(.el-range__icon),
  180. :deep(.el-range__close-icon) {
  181. font-size: calc(14px * var(--kb-scale, 1));
  182. }
  183. }
  184. .device-list-table {
  185. :deep(.el-table__header-wrapper th.el-table__cell) {
  186. font-size: calc(17px * var(--kb-scale, 1));
  187. line-height: 1.25;
  188. }
  189. :deep(.el-table__body td.el-table__cell) {
  190. font-size: calc(15px * var(--kb-scale, 1));
  191. }
  192. }
  193. </style>
  194. <style>
  195. @import url('@/styles/kb-dialog.scss');
  196. </style>