|
@@ -1,27 +1,45 @@
|
|
|
<script lang="ts" setup>
|
|
<script lang="ts" setup>
|
|
|
import * as echarts from 'echarts'
|
|
import * as echarts from 'echarts'
|
|
|
|
|
+import { IotStatApi } from '@/api/pms/stat'
|
|
|
import { ANIMATION, CHART_RENDERER, createTooltip, FONT_FAMILY, THEME } from '@/utils/kb'
|
|
import { ANIMATION, CHART_RENDERER, createTooltip, FONT_FAMILY, THEME } from '@/utils/kb'
|
|
|
|
|
|
|
|
interface DeviceCategoryItem {
|
|
interface DeviceCategoryItem {
|
|
|
name: string
|
|
name: string
|
|
|
count: number
|
|
count: number
|
|
|
|
|
+ type: string
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+interface DeviceCategoryResponseItem {
|
|
|
|
|
+ className?: string
|
|
|
|
|
+ count?: number | string
|
|
|
|
|
+ type?: string
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const chartRef = ref<HTMLDivElement>()
|
|
const chartRef = ref<HTMLDivElement>()
|
|
|
|
|
+const loading = ref(false)
|
|
|
|
|
+const categoryData = ref<DeviceCategoryItem[]>([])
|
|
|
let chart: echarts.ECharts | null = null
|
|
let chart: echarts.ECharts | null = null
|
|
|
|
|
|
|
|
-const categoryData: DeviceCategoryItem[] = [
|
|
|
|
|
- { name: '压裂泵车', count: 75 },
|
|
|
|
|
- { name: '连油主车', count: 36 },
|
|
|
|
|
- { name: '其他', count: 35 },
|
|
|
|
|
- { name: '小车', count: 32 },
|
|
|
|
|
- { name: '井控装备', count: 22 },
|
|
|
|
|
- { name: '连油辅助设备', count: 19 },
|
|
|
|
|
- { name: '货车', count: 17 },
|
|
|
|
|
- { name: '四川瑞都设备', count: 16 },
|
|
|
|
|
- { name: '卡车', count: 16 },
|
|
|
|
|
- { name: '供液橇', count: 12 }
|
|
|
|
|
-]
|
|
|
|
|
|
|
+const TOP_BAR_COLOR = new echarts.graphic.LinearGradient(0, 0, 1, 0, [
|
|
|
|
|
+ { offset: 0, color: '#ffd166' },
|
|
|
|
|
+ { offset: 0.58, color: '#ff9f43' },
|
|
|
|
|
+ { offset: 1, color: '#f76707' }
|
|
|
|
|
+])
|
|
|
|
|
+const DEFAULT_BAR_COLOR = new echarts.graphic.LinearGradient(0, 0, 1, 0, [
|
|
|
|
|
+ { offset: 0, color: THEME.color.blue.light },
|
|
|
|
|
+ { offset: 0.58, color: THEME.color.blue.mid },
|
|
|
|
|
+ { offset: 1, color: THEME.color.blue.line }
|
|
|
|
|
+])
|
|
|
|
|
+
|
|
|
|
|
+function sortCategoryData(data: DeviceCategoryItem[]) {
|
|
|
|
|
+ const typeOrder = (type: string) => {
|
|
|
|
|
+ if (type === 'top') return 0
|
|
|
|
|
+ if (type === '') return 1
|
|
|
|
|
+ return 2
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return data.sort((a, b) => typeOrder(a.type) - typeOrder(b.type))
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
function getChartLayout() {
|
|
function getChartLayout() {
|
|
|
const { clientWidth = 0, clientHeight = 0 } = chartRef.value ?? {}
|
|
const { clientWidth = 0, clientHeight = 0 } = chartRef.value ?? {}
|
|
@@ -44,7 +62,7 @@ function formatValue(value: number) {
|
|
|
|
|
|
|
|
function getChartOption(): echarts.EChartsOption {
|
|
function getChartOption(): echarts.EChartsOption {
|
|
|
const layout = getChartLayout()
|
|
const layout = getChartLayout()
|
|
|
- const values = categoryData.map((item) => item.count)
|
|
|
|
|
|
|
+ const values = categoryData.value.map((item) => item.count)
|
|
|
const maxValue = Math.max(...values, 1)
|
|
const maxValue = Math.max(...values, 1)
|
|
|
const xAxisMax = Math.ceil((maxValue * 1.12) / 10) * 10
|
|
const xAxisMax = Math.ceil((maxValue * 1.12) / 10) * 10
|
|
|
|
|
|
|
@@ -67,7 +85,7 @@ function getChartOption(): echarts.EChartsOption {
|
|
|
},
|
|
},
|
|
|
formatter(params: any[]) {
|
|
formatter(params: any[]) {
|
|
|
const first = params[0]
|
|
const first = params[0]
|
|
|
- const row = categoryData[first?.dataIndex ?? 0]
|
|
|
|
|
|
|
+ const row = categoryData.value[first?.dataIndex ?? 0]
|
|
|
if (!row) return ''
|
|
if (!row) return ''
|
|
|
|
|
|
|
|
return [
|
|
return [
|
|
@@ -109,7 +127,7 @@ function getChartOption(): echarts.EChartsOption {
|
|
|
},
|
|
},
|
|
|
yAxis: {
|
|
yAxis: {
|
|
|
type: 'category',
|
|
type: 'category',
|
|
|
- data: categoryData.map((item) => item.name),
|
|
|
|
|
|
|
+ data: categoryData.value.map((item) => item.name),
|
|
|
inverse: true,
|
|
inverse: true,
|
|
|
axisLine: {
|
|
axisLine: {
|
|
|
show: false
|
|
show: false
|
|
@@ -130,7 +148,12 @@ function getChartOption(): echarts.EChartsOption {
|
|
|
{
|
|
{
|
|
|
name: '设备数量',
|
|
name: '设备数量',
|
|
|
type: 'bar',
|
|
type: 'bar',
|
|
|
- data: values,
|
|
|
|
|
|
|
+ data: categoryData.value.map((item) => ({
|
|
|
|
|
+ value: item.count,
|
|
|
|
|
+ itemStyle: {
|
|
|
|
|
+ color: item.type === 'top' ? TOP_BAR_COLOR : DEFAULT_BAR_COLOR
|
|
|
|
|
+ }
|
|
|
|
|
+ })),
|
|
|
barWidth: layout.barWidth,
|
|
barWidth: layout.barWidth,
|
|
|
showBackground: true,
|
|
showBackground: true,
|
|
|
backgroundStyle: {
|
|
backgroundStyle: {
|
|
@@ -138,12 +161,7 @@ function getChartOption(): echarts.EChartsOption {
|
|
|
borderRadius: 999
|
|
borderRadius: 999
|
|
|
},
|
|
},
|
|
|
itemStyle: {
|
|
itemStyle: {
|
|
|
- borderRadius: 999,
|
|
|
|
|
- color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
|
|
|
|
|
- { offset: 0, color: THEME.color.blue.light },
|
|
|
|
|
- { offset: 0.58, color: THEME.color.blue.mid },
|
|
|
|
|
- { offset: 1, color: THEME.color.blue.line }
|
|
|
|
|
- ])
|
|
|
|
|
|
|
+ borderRadius: 999
|
|
|
},
|
|
},
|
|
|
label: {
|
|
label: {
|
|
|
show: true,
|
|
show: true,
|
|
@@ -159,8 +177,8 @@ function getChartOption(): echarts.EChartsOption {
|
|
|
},
|
|
},
|
|
|
emphasis: {
|
|
emphasis: {
|
|
|
itemStyle: {
|
|
itemStyle: {
|
|
|
- shadowBlur: 16,
|
|
|
|
|
- shadowColor: THEME.color.blue.shadow
|
|
|
|
|
|
|
+ shadowBlur: 2
|
|
|
|
|
+ // shadowColor: THEME.color.blue.shadow
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -192,8 +210,33 @@ function destroyChart() {
|
|
|
chart = null
|
|
chart = null
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+async function getDeviceCategory() {
|
|
|
|
|
+ loading.value = true
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await IotStatApi.getRdNewClassify()
|
|
|
|
|
+ categoryData.value = Array.isArray(res)
|
|
|
|
|
+ ? sortCategoryData(
|
|
|
|
|
+ res.map((item: DeviceCategoryResponseItem) => ({
|
|
|
|
|
+ name: item.className || '未知',
|
|
|
|
|
+ count: Number(item.count ?? 0),
|
|
|
|
|
+ type: item.type || ''
|
|
|
|
|
+ }))
|
|
|
|
|
+ ).slice(0, 10)
|
|
|
|
|
+ : []
|
|
|
|
|
+ renderChart()
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('获取瑞都设备分类失败:', error)
|
|
|
|
|
+ categoryData.value = []
|
|
|
|
|
+ renderChart()
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ loading.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
|
initChart()
|
|
initChart()
|
|
|
|
|
+ getDeviceCategory()
|
|
|
window.addEventListener('resize', resizeChart)
|
|
window.addEventListener('resize', resizeChart)
|
|
|
window.addEventListener('rdkb:resize', resizeChart)
|
|
window.addEventListener('rdkb:resize', resizeChart)
|
|
|
})
|
|
})
|
|
@@ -214,13 +257,26 @@ onUnmounted(() => {
|
|
|
</div>
|
|
</div>
|
|
|
设备分类
|
|
设备分类
|
|
|
</div>
|
|
</div>
|
|
|
- <div ref="chartRef" class="device-category-chart"></div>
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-loading="loading"
|
|
|
|
|
+ element-loading-text="加载中..."
|
|
|
|
|
+ element-loading-background="rgb(222 236 252 / 72%)"
|
|
|
|
|
+ class="device-category-body">
|
|
|
|
|
+ <div ref="chartRef" class="device-category-chart"></div>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
<style lang="scss" scoped>
|
|
|
@import url('@/styles/kb.scss');
|
|
@import url('@/styles/kb.scss');
|
|
|
|
|
|
|
|
|
|
+.device-category-body {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ min-height: 0;
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
.device-category-chart {
|
|
.device-category-chart {
|
|
|
width: 100%;
|
|
width: 100%;
|
|
|
min-height: 0;
|
|
min-height: 0;
|