|
|
@@ -0,0 +1,675 @@
|
|
|
+<script setup lang="ts">
|
|
|
+import dayjs from 'dayjs'
|
|
|
+import { IotRdDailyReportApi } from '@/api/pms/iotrddailyreport'
|
|
|
+import { useDebounceFn } from '@vueuse/core'
|
|
|
+import CountTo from '@/components/count-to1.vue'
|
|
|
+import * as echarts from 'echarts'
|
|
|
+// import UnfilledReportDialog from './UnfilledReportDialog.vue'
|
|
|
+
|
|
|
+import { Motion, AnimatePresence } from 'motion-v'
|
|
|
+
|
|
|
+import { rangeShortcuts } from '@/utils/formatTime'
|
|
|
+
|
|
|
+import { useUserStore } from '@/store/modules/user'
|
|
|
+
|
|
|
+const deptId = useUserStore().getUser.deptId
|
|
|
+
|
|
|
+interface Query {
|
|
|
+ pageNo: number
|
|
|
+ pageSize: number
|
|
|
+ deptId: number
|
|
|
+ contractName?: string
|
|
|
+ taskName?: string
|
|
|
+ createTime: string[]
|
|
|
+}
|
|
|
+
|
|
|
+const id = deptId
|
|
|
+
|
|
|
+const query = ref<Query>({
|
|
|
+ pageNo: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ deptId: deptId,
|
|
|
+ createTime: [
|
|
|
+ ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
|
|
|
+ ]
|
|
|
+})
|
|
|
+
|
|
|
+const totalWorkKeys: [string, string | undefined, string, string, number][] = [
|
|
|
+ [
|
|
|
+ 'cumulativeFuels',
|
|
|
+ '万升',
|
|
|
+ '累计油耗',
|
|
|
+ 'i-material-symbols:directions-car-outline-rounded text-sky',
|
|
|
+ 2
|
|
|
+ ],
|
|
|
+ ['taici', undefined, '台次', 'i-material-symbols:check-circle-outline-rounded text-emerald', 0],
|
|
|
+ [
|
|
|
+ 'cumulativeBridgePlug',
|
|
|
+ undefined,
|
|
|
+ '个数',
|
|
|
+ 'i-material-symbols:check-circle-outline-rounded text-emerald',
|
|
|
+ 0
|
|
|
+ ],
|
|
|
+ [
|
|
|
+ 'cumulativeRunCount',
|
|
|
+ undefined,
|
|
|
+ '趟数',
|
|
|
+ 'i-material-symbols:check-circle-outline-rounded text-emerald',
|
|
|
+ 0
|
|
|
+ ],
|
|
|
+ [
|
|
|
+ 'cumulativeWorkingWell',
|
|
|
+ undefined,
|
|
|
+ '井数',
|
|
|
+ 'i-material-symbols:check-circle-outline-rounded text-emerald',
|
|
|
+ 0
|
|
|
+ ],
|
|
|
+ [
|
|
|
+ 'cumulativeWorkingLayers',
|
|
|
+ undefined,
|
|
|
+ '段数',
|
|
|
+ 'i-material-symbols:check-circle-outline-rounded text-emerald',
|
|
|
+ 0
|
|
|
+ ],
|
|
|
+ [
|
|
|
+ 'cumulativeHourCount',
|
|
|
+ undefined,
|
|
|
+ 'H',
|
|
|
+ 'i-material-symbols:nest-clock-farsight-analog-outline-rounded text-emerald',
|
|
|
+ 2
|
|
|
+ ]
|
|
|
+]
|
|
|
+
|
|
|
+const totalWork = ref({
|
|
|
+ cumulativeFuels: 0,
|
|
|
+ taici: 0,
|
|
|
+ cumulativeBridgePlug: 0,
|
|
|
+ cumulativeRunCount: 0,
|
|
|
+ cumulativeWorkingWell: 0,
|
|
|
+ cumulativeWorkingLayers: 0,
|
|
|
+ cumulativeHourCount: 0
|
|
|
+})
|
|
|
+
|
|
|
+const totalLoading = ref(false)
|
|
|
+
|
|
|
+const getTotal = useDebounceFn(async () => {
|
|
|
+ totalLoading.value = true
|
|
|
+
|
|
|
+ const { pageNo, pageSize, ...other } = query.value
|
|
|
+
|
|
|
+ try {
|
|
|
+ // let res1: any[]
|
|
|
+ // if (query.value.createTime && query.value.createTime.length === 2) {
|
|
|
+ // res1 = await IotRhDailyReportApi.rhDailyReportStatistics({
|
|
|
+ // createTime: query.value.createTime,
|
|
|
+ // deptId: query.value.deptId
|
|
|
+ // })
|
|
|
+
|
|
|
+ // totalWork.value.totalCount = res1[0].count
|
|
|
+ // totalWork.value.alreadyReported = res1[1].count
|
|
|
+ // totalWork.value.notReported = res1[2].count
|
|
|
+ // }
|
|
|
+
|
|
|
+ const res2 = await IotRdDailyReportApi.totalWorkload(other)
|
|
|
+
|
|
|
+ totalWork.value = {
|
|
|
+ ...totalWork.value,
|
|
|
+ taici: res2.taici || 0,
|
|
|
+ cumulativeBridgePlug: res2.cumulativeBridgePlug || 0,
|
|
|
+ cumulativeRunCount: res2.cumulativeRunCount || 0,
|
|
|
+ cumulativeWorkingWell: res2.cumulativeWorkingWell || 0,
|
|
|
+ cumulativeWorkingLayers: res2.cumulativeWorkingLayers || 0,
|
|
|
+ cumulativeHourCount: res2.cumulativeHourCount || 0,
|
|
|
+ ...res2,
|
|
|
+ cumulativeFuels: (res2.cumulativeFuels || 0) / 10000
|
|
|
+ }
|
|
|
+ } finally {
|
|
|
+ totalLoading.value = false
|
|
|
+ }
|
|
|
+}, 500)
|
|
|
+
|
|
|
+interface List {
|
|
|
+ id: number | null
|
|
|
+ name: string | null
|
|
|
+ type: '1' | '2' | '3'
|
|
|
+ cumulativeBridgePlug: number | null
|
|
|
+ cumulativeRunCount: number | null
|
|
|
+ cumulativeWorkingWell: number | null
|
|
|
+ cumulativeHourCount: number | null
|
|
|
+ totalDailyFuel: number | null
|
|
|
+ cumulativeWaterVolume: number | null
|
|
|
+ cumulativeWorkingLayers: number | null
|
|
|
+ cumulativePumpTrips: number | null
|
|
|
+ cumulativeMixSand: number | null
|
|
|
+}
|
|
|
+
|
|
|
+const list = ref<List[]>([])
|
|
|
+
|
|
|
+const type = ref('2')
|
|
|
+
|
|
|
+const columns = (type: string) => {
|
|
|
+ return [
|
|
|
+ {
|
|
|
+ label: type === '2' ? '项目部' : '队伍',
|
|
|
+ prop: 'name'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '桥塞',
|
|
|
+ prop: 'cumulativeBridgePlug'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '趟数',
|
|
|
+ prop: 'cumulativeRunCount'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '井数',
|
|
|
+ prop: 'cumulativeWorkingWell'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '小时(H)',
|
|
|
+ prop: 'cumulativeHourCount'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '油耗(万升)',
|
|
|
+ prop: 'totalDailyFuel'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '水方量(方)',
|
|
|
+ prop: 'cumulativeWaterVolume'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '段数',
|
|
|
+ prop: 'cumulativeWorkingLayers'
|
|
|
+ }
|
|
|
+ ]
|
|
|
+}
|
|
|
+
|
|
|
+const listLoading = ref(false)
|
|
|
+
|
|
|
+// const formatter = (row: List, column: any) => {
|
|
|
+// if (column.property === 'transitTime') {
|
|
|
+// return (Number(row.transitTime ?? 0) * 100).toFixed(2) + '%'
|
|
|
+// } else return row[column.property] ?? 0
|
|
|
+// }
|
|
|
+
|
|
|
+const getList = useDebounceFn(async () => {
|
|
|
+ listLoading.value = true
|
|
|
+ try {
|
|
|
+ const res = await IotRdDailyReportApi.getIotRdDailyReportSummary(query.value)
|
|
|
+
|
|
|
+ const { list: reslist } = res
|
|
|
+
|
|
|
+ type.value = reslist[0]?.type || '2'
|
|
|
+
|
|
|
+ list.value = reslist.map(
|
|
|
+ ({ id, projectDeptId, projectDeptName, teamId, teamName, sort, taskId, type, ...other }) => {
|
|
|
+ return {
|
|
|
+ id: type === '2' ? projectDeptId : teamId,
|
|
|
+ name: type === '2' ? projectDeptName : teamName,
|
|
|
+ ...other,
|
|
|
+ cumulativeBridgePlug: other.cumulativeBridgePlug || 0,
|
|
|
+ cumulativeRunCount: other.cumulativeRunCount || 0,
|
|
|
+ cumulativeWorkingWell: other.cumulativeWorkingWell || 0,
|
|
|
+ cumulativeHourCount: other.cumulativeHourCount || 0,
|
|
|
+ totalDailyFuel: ((other.totalDailyFuel || 0) / 10000).toFixed(4),
|
|
|
+ cumulativeWaterVolume: other.cumulativeWaterVolume || 0,
|
|
|
+ cumulativeWorkingLayers: other.cumulativeWorkingLayers || 0,
|
|
|
+ cumulativePumpTrips: other.cumulativePumpTrips || 0,
|
|
|
+ cumulativeMixSand: other.cumulativeMixSand || 0
|
|
|
+ }
|
|
|
+ }
|
|
|
+ )
|
|
|
+ } finally {
|
|
|
+ listLoading.value = false
|
|
|
+ }
|
|
|
+}, 500)
|
|
|
+
|
|
|
+const tab = ref<'表格' | '看板'>('表格')
|
|
|
+
|
|
|
+const currentTab = ref<'表格' | '看板'>('表格')
|
|
|
+
|
|
|
+const deptName = ref('瑞恒兴域')
|
|
|
+
|
|
|
+const direction = ref<'left' | 'right'>('right')
|
|
|
+
|
|
|
+const handleSelectTab = (val: '表格' | '看板') => {
|
|
|
+ tab.value = val
|
|
|
+ direction.value = val === '看板' ? 'right' : 'left'
|
|
|
+ nextTick(() => {
|
|
|
+ currentTab.value = val
|
|
|
+ setTimeout(() => {
|
|
|
+ render()
|
|
|
+ })
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const chartRef = ref<HTMLDivElement | null>(null)
|
|
|
+let chart: echarts.ECharts | null = null
|
|
|
+
|
|
|
+const xAxisData = ref<string[]>([])
|
|
|
+
|
|
|
+const legend = ref<string[][]>([
|
|
|
+ ['个数', 'cumulativeBridgePlug'],
|
|
|
+ ['井数', 'cumulativeWorkingWell'],
|
|
|
+ ['小时 (H)', 'cumulativeHourCount'],
|
|
|
+ ['油耗 (万升)', 'totalDailyFuel'],
|
|
|
+ ['水方量 (方)', 'cumulativeWaterVolume'],
|
|
|
+ ['台次(泵车)', 'cumulativePumpTrips'],
|
|
|
+ ['段数', 'cumulativeWorkingLayers'],
|
|
|
+ ['台次(仪表/混砂)', 'cumulativeMixSand']
|
|
|
+])
|
|
|
+
|
|
|
+const chartData = ref<Record<string, number[]>>({
|
|
|
+ cumulativeFuelConsumption: [],
|
|
|
+ cumulativeGasInjection: [],
|
|
|
+ cumulativePowerConsumption: [],
|
|
|
+ cumulativeWaterInjection: [],
|
|
|
+ transitTime: []
|
|
|
+})
|
|
|
+
|
|
|
+let chartLoading = ref(false)
|
|
|
+
|
|
|
+const getChart = useDebounceFn(async () => {
|
|
|
+ chartLoading.value = true
|
|
|
+
|
|
|
+ try {
|
|
|
+ const res = await IotRdDailyReportApi.getIotRdDailyReportSummaryPolyline(query.value)
|
|
|
+
|
|
|
+ chartData.value = {
|
|
|
+ cumulativeBridgePlug: res.map((item) => item.cumulativeBridgePlug || 0),
|
|
|
+ cumulativeWorkingWell: res.map((item) => item.cumulativeWorkingWell || 0),
|
|
|
+ cumulativeHourCount: res.map((item) => item.cumulativeHourCount || 0),
|
|
|
+ totalDailyFuel: res.map((item) => (item.totalDailyFuel || 0) / 10000),
|
|
|
+ cumulativeWaterVolume: res.map((item) => item.cumulativeWaterVolume || 0),
|
|
|
+ cumulativeWorkingLayers: res.map((item) => item.cumulativeWorkingLayers || 0),
|
|
|
+ cumulativePumpTrips: res.map((item) => item.cumulativePumpTrips || 0),
|
|
|
+ cumulativeMixSand: res.map((item) => item.cumulativeMixSand || 0)
|
|
|
+ }
|
|
|
+
|
|
|
+ xAxisData.value = res.map((item) => item.reportDate || '')
|
|
|
+ } finally {
|
|
|
+ chartLoading.value = false
|
|
|
+ }
|
|
|
+}, 500)
|
|
|
+
|
|
|
+const resizer = () => {
|
|
|
+ chart?.resize()
|
|
|
+}
|
|
|
+
|
|
|
+onUnmounted(() => {
|
|
|
+ window.removeEventListener('resize', resizer)
|
|
|
+})
|
|
|
+
|
|
|
+const render = () => {
|
|
|
+ if (!chartRef.value) return
|
|
|
+
|
|
|
+ chart = echarts.init(chartRef.value, undefined, { renderer: 'canvas' })
|
|
|
+
|
|
|
+ window.addEventListener('resize', resizer)
|
|
|
+
|
|
|
+ const values: number[] = []
|
|
|
+
|
|
|
+ for (const [_name, key] of legend.value) {
|
|
|
+ values.push(...(chartData.value[key] || []))
|
|
|
+ }
|
|
|
+
|
|
|
+ const maxVal = values.length === 0 ? 10000 : Math.max(...values)
|
|
|
+ const minVal = values.length === 0 ? 0 : Math.min(...values) > 0 ? 0 : Math.min(...values)
|
|
|
+
|
|
|
+ const maxDigits = (Math.floor(maxVal) + '').length
|
|
|
+ const minDigits = minVal === 0 ? 0 : (Math.floor(Math.abs(minVal)) + '').length
|
|
|
+ const interval = Math.max(maxDigits, minDigits)
|
|
|
+
|
|
|
+ const maxInterval = interval
|
|
|
+ const minInterval = minDigits
|
|
|
+
|
|
|
+ const intervalArr = [0]
|
|
|
+ for (let i = 1; i <= interval; i++) {
|
|
|
+ intervalArr.push(Math.pow(10, i))
|
|
|
+ }
|
|
|
+
|
|
|
+ chart.setOption({
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'axis',
|
|
|
+ axisPointer: {
|
|
|
+ type: 'line'
|
|
|
+ },
|
|
|
+ formatter: (params) => {
|
|
|
+ let d = `${params[0].axisValueLabel}<br>`
|
|
|
+ let item = params.map((el) => {
|
|
|
+ return `<div class="flex items-center justify-between mt-1 gap-1">
|
|
|
+ <span>${el.marker} ${el.seriesName}</span>
|
|
|
+ <span>${chartData.value[legend.value[el.componentIndex][1]][el.dataIndex].toFixed(2)} ${el.seriesName.split(' ')[1] ?? ''}</span>
|
|
|
+ </div>`
|
|
|
+ })
|
|
|
+
|
|
|
+ return d + item.join('')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ legend: {
|
|
|
+ data: legend.value.map(([name]) => name),
|
|
|
+ show: true
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: 'category',
|
|
|
+ data: xAxisData.value
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: 'value',
|
|
|
+ min: -minInterval,
|
|
|
+ max: maxInterval,
|
|
|
+ interval: 1,
|
|
|
+ axisLabel: {
|
|
|
+ formatter: (v) => {
|
|
|
+ const num = v === 0 ? 0 : v > 0 ? Math.pow(10, v) : -Math.pow(10, -v)
|
|
|
+
|
|
|
+ return num.toLocaleString()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ series: legend.value.map(([name, key]) => ({
|
|
|
+ name,
|
|
|
+ type: 'line',
|
|
|
+ smooth: true,
|
|
|
+ showSymbol: true,
|
|
|
+ data: chartData.value[key].map((value) => {
|
|
|
+ // return value
|
|
|
+ if (value === 0) return 0
|
|
|
+
|
|
|
+ const isPositive = value > 0
|
|
|
+ const absItem = Math.abs(value)
|
|
|
+
|
|
|
+ const min_value = Math.max(...intervalArr.filter((v) => v <= absItem))
|
|
|
+ const min_index = intervalArr.findIndex((v) => v === min_value)
|
|
|
+
|
|
|
+ const new_value =
|
|
|
+ (absItem - min_value) / (intervalArr[min_index + 1] - intervalArr[min_index]) + min_index
|
|
|
+
|
|
|
+ return isPositive ? new_value : -new_value
|
|
|
+ })
|
|
|
+ }))
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const handleDeptNodeClick = (node: any) => {
|
|
|
+ deptName.value = node.name
|
|
|
+ handleQuery()
|
|
|
+}
|
|
|
+
|
|
|
+const handleQuery = (setPage = true) => {
|
|
|
+ if (setPage) {
|
|
|
+ query.value.pageNo = 1
|
|
|
+ }
|
|
|
+ getChart().then(() => {
|
|
|
+ render()
|
|
|
+ })
|
|
|
+ getList()
|
|
|
+ getTotal()
|
|
|
+}
|
|
|
+
|
|
|
+const resetQuery = () => {
|
|
|
+ query.value = {
|
|
|
+ pageNo: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ deptId: deptId,
|
|
|
+ contractName: '',
|
|
|
+ taskName: '',
|
|
|
+ createTime: []
|
|
|
+ }
|
|
|
+ handleQuery()
|
|
|
+}
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => query.value.createTime,
|
|
|
+ () => {
|
|
|
+ // if (!val) {
|
|
|
+ // totalWork.value.totalCount = 0
|
|
|
+ // totalWork.value.notReported = 0
|
|
|
+ // totalWork.value.alreadyReported = 0
|
|
|
+ // }
|
|
|
+ handleQuery(false)
|
|
|
+ }
|
|
|
+)
|
|
|
+
|
|
|
+watch([() => query.value.contractName, () => query.value.taskName], () => {
|
|
|
+ handleQuery(false)
|
|
|
+})
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ handleQuery()
|
|
|
+})
|
|
|
+
|
|
|
+const exportChart = () => {
|
|
|
+ if (!chart) return
|
|
|
+ let img = new Image()
|
|
|
+ img.src = chart.getDataURL({
|
|
|
+ type: 'png',
|
|
|
+ pixelRatio: 1,
|
|
|
+ backgroundColor: '#fff'
|
|
|
+ })
|
|
|
+
|
|
|
+ img.onload = function () {
|
|
|
+ let canvas = document.createElement('canvas')
|
|
|
+ canvas.width = img.width
|
|
|
+ canvas.height = img.height
|
|
|
+ let ctx = canvas.getContext('2d')
|
|
|
+ ctx?.drawImage(img, 0, 0)
|
|
|
+ let dataURL = canvas.toDataURL('image/png')
|
|
|
+
|
|
|
+ let a = document.createElement('a')
|
|
|
+
|
|
|
+ let event = new MouseEvent('click')
|
|
|
+
|
|
|
+ a.href = dataURL
|
|
|
+ a.download = `瑞恒日报统计数据.png`
|
|
|
+ a.dispatchEvent(event)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const exportData = async () => {
|
|
|
+ // const res = await IotRdDailyReportApi.exportRdDailyReportStatistics(query.value)
|
|
|
+ // download.excel(res, '瑞恒日报统计数据.xlsx')
|
|
|
+}
|
|
|
+
|
|
|
+const exportAll = async () => {
|
|
|
+ if (tab.value === '看板') exportChart()
|
|
|
+ else exportData()
|
|
|
+}
|
|
|
+
|
|
|
+const router = useRouter()
|
|
|
+
|
|
|
+const tolist = (id: number) => {
|
|
|
+ const { pageNo, pageSize, ...rest } = query.value
|
|
|
+
|
|
|
+ router.push({
|
|
|
+ path: '/iotdayilyreport/IotRhDailyReport',
|
|
|
+ query: {
|
|
|
+ ...rest,
|
|
|
+ deptId: id
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div class="grid grid-cols-[16%_1fr] gap-5">
|
|
|
+ <div class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow p-4">
|
|
|
+ <!-- <DeptTree2 :deptId="id" @node-click="handleDeptNodeClick" /> -->
|
|
|
+ <DeptTreeSelect
|
|
|
+ :deptId="id"
|
|
|
+ :top-id="163"
|
|
|
+ v-model="query.deptId"
|
|
|
+ @node-click="handleDeptNodeClick"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="grid grid-rows-[62px_164px_1fr] h-full gap-4">
|
|
|
+ <el-form
|
|
|
+ size="default"
|
|
|
+ class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 gap-8 flex items-center justify-between"
|
|
|
+ >
|
|
|
+ <div class="flex items-center gap-8">
|
|
|
+ <el-form-item label="项目">
|
|
|
+ <el-input
|
|
|
+ v-model="query.contractName"
|
|
|
+ placeholder="请输入项目"
|
|
|
+ clearable
|
|
|
+ @keyup.enter="handleQuery()"
|
|
|
+ class="!w-240px"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="任务">
|
|
|
+ <el-input
|
|
|
+ v-model="query.taskName"
|
|
|
+ placeholder="请输入任务"
|
|
|
+ clearable
|
|
|
+ @keyup.enter="handleQuery()"
|
|
|
+ class="!w-240px"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="创建时间">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="query.createTime"
|
|
|
+ value-format="YYYY-MM-DD HH:mm:ss"
|
|
|
+ type="daterange"
|
|
|
+ start-placeholder="开始日期"
|
|
|
+ end-placeholder="结束日期"
|
|
|
+ :shortcuts="rangeShortcuts"
|
|
|
+ :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
|
|
|
+ class="!w-220px"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" @click="handleQuery()">
|
|
|
+ <Icon icon="ep:search" class="mr-5px" /> 搜索
|
|
|
+ </el-button>
|
|
|
+ <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <div class="grid grid-cols-7 gap-8">
|
|
|
+ <div
|
|
|
+ v-for="info in totalWorkKeys"
|
|
|
+ :key="info[0]"
|
|
|
+ class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow p-1 flex flex-col items-center justify-center gap-1"
|
|
|
+ >
|
|
|
+ <div class="size-7.5" :class="info[3]"></div>
|
|
|
+ <count-to
|
|
|
+ class="text-2xl font-medium"
|
|
|
+ :start-val="0"
|
|
|
+ :end-val="totalWork[info[0]]"
|
|
|
+ :decimals="info[4]"
|
|
|
+ >
|
|
|
+ <span class="text-xs leading-8 text-[var(--el-text-color-regular)]">暂无数据</span>
|
|
|
+ </count-to>
|
|
|
+ <div class="text-xs font-medium text-[var(--el-text-color-regular)]">{{ info[1] }}</div>
|
|
|
+ <div class="text-sm font-medium text-[var(--el-text-color-regular)]">{{ info[2] }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 py-4 grid grid-rows-[48px_1fr] gap-2"
|
|
|
+ >
|
|
|
+ <div class="flex items-center justify-between">
|
|
|
+ <el-button-group>
|
|
|
+ <el-button
|
|
|
+ size="default"
|
|
|
+ :type="tab === '表格' ? 'primary' : 'default'"
|
|
|
+ @click="handleSelectTab('表格')"
|
|
|
+ >表格
|
|
|
+ </el-button>
|
|
|
+ <el-button
|
|
|
+ size="default"
|
|
|
+ :type="tab === '看板' ? 'primary' : 'default'"
|
|
|
+ @click="handleSelectTab('看板')"
|
|
|
+ >看板
|
|
|
+ </el-button>
|
|
|
+ </el-button-group>
|
|
|
+ <h3 class="text-xl font-medium">{{ `${deptName}-${tab}` }}</h3>
|
|
|
+ <el-button size="default" type="primary" @click="exportAll">导出</el-button>
|
|
|
+ </div>
|
|
|
+ <!-- <el-auto-resizer>
|
|
|
+ <template #default="{ height, width }"> -->
|
|
|
+ <Motion
|
|
|
+ as="div"
|
|
|
+ :style="{ position: 'relative', overflow: 'hidden' }"
|
|
|
+ :animate="{ height: `${500}px`, width: `100%` }"
|
|
|
+ :transition="{ type: 'spring', stiffness: 200, damping: 25, duration: 0.3 }"
|
|
|
+ >
|
|
|
+ <AnimatePresence :initial="false" mode="sync">
|
|
|
+ <Motion
|
|
|
+ :key="currentTab"
|
|
|
+ as="div"
|
|
|
+ :initial="{ x: direction === 'left' ? '-100%' : '100%', opacity: 0 }"
|
|
|
+ :animate="{ x: '0%', opacity: 1 }"
|
|
|
+ :exit="{ x: direction === 'left' ? '50%' : '-50%', opacity: 0 }"
|
|
|
+ :transition="{ type: 'tween', stiffness: 300, damping: 30, duration: 0.3 }"
|
|
|
+ :style="{ position: 'absolute', left: 0, right: 0, top: 0 }"
|
|
|
+ >
|
|
|
+ <div :style="{ width: `100%`, height: `${500}px` }">
|
|
|
+ <el-table
|
|
|
+ v-if="currentTab === '表格'"
|
|
|
+ v-loading="listLoading"
|
|
|
+ :data="list"
|
|
|
+ :stripe="true"
|
|
|
+ :max-height="500"
|
|
|
+ show-overflow-tooltip
|
|
|
+ >
|
|
|
+ <template v-for="item in columns(type)" :key="item.prop">
|
|
|
+ <el-table-column
|
|
|
+ v-if="item.prop !== 'name'"
|
|
|
+ :label="item.label"
|
|
|
+ :prop="item.prop"
|
|
|
+ align="center"
|
|
|
+ />
|
|
|
+ <el-table-column v-else :label="item.label" :prop="item.prop" align="center">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-button text type="primary" @click.prevent="tolist(row.id)">{{
|
|
|
+ row.name
|
|
|
+ }}</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </template>
|
|
|
+ <el-table-column label="台次" align="center">
|
|
|
+ <el-table-column label="泵车" prop="cumulativePumpTrips" align="center" />
|
|
|
+ <el-table-column label="仪表/混砂" prop="cumulativeMixSand" align="center" />
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ <div
|
|
|
+ ref="chartRef"
|
|
|
+ v-loading="chartLoading"
|
|
|
+ :key="dayjs().valueOf()"
|
|
|
+ v-else
|
|
|
+ :style="{ width: `100%`, height: `${500}px` }"
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </Motion>
|
|
|
+ </AnimatePresence>
|
|
|
+ </Motion>
|
|
|
+ <!-- </template>
|
|
|
+ </el-auto-resizer> -->
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- <UnfilledReportDialog ref="unfilledDialogRef" :query-params="query" /> -->
|
|
|
+</template>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+:deep(.el-form-item) {
|
|
|
+ margin-bottom: 0;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.el-table) {
|
|
|
+ border-top-right-radius: 8px;
|
|
|
+ border-top-left-radius: 8px;
|
|
|
+
|
|
|
+ .el-table__cell {
|
|
|
+ height: 40px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-table__header-wrapper {
|
|
|
+ .el-table__cell {
|
|
|
+ background: var(--el-fill-color-light);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|