feat: 添加设备一张图和温度一张图功能

This commit is contained in:
my-foal 2024-08-16 11:10:12 +08:00
parent cb9b812153
commit 6ca2c097c2
51 changed files with 6664 additions and 3607 deletions

View File

@ -7,6 +7,7 @@
"scripts": { "scripts": {
"dev": "vite --host", "dev": "vite --host",
"build": "vue-tsc --noEmit && vite build", "build": "vue-tsc --noEmit && vite build",
"viteBuild": " vite build",
"preview": "vite preview", "preview": "vite preview",
"new": "plop --plopfile ./plop/plopfile.js", "new": "plop --plopfile ./plop/plopfile.js",
"postinstall": "husky install", "postinstall": "husky install",

7574
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,29 @@
import { publicInterface } from "@/api/path";
import { CreateComponentType } from '@/packages/index.d'
import { ResultErrcode } from "@/enums/httpEnum";
import { AreaDevCountType } from '@/store/modules/chartEditStore/chartEditStore.d'
import dataJson from "./data.json";
export const handleAreaDevCountClass =async (targetComponent: CreateComponentType) => {
const obj = targetComponent.commonData[targetComponent.commonData.currentSource] as AreaDevCountType
console.log(targetComponent,'targetComponent_targetComponent');
// targetComponent?.option.series.forEach((item,index)=>{
// item.encode = { y:index===0? 'dev_count':'it_dev_count', x: 'space' }
// })
// 处理数据
const res = await publicInterface('/dcim/dems/device','get_area_dev_count', {})
res!.data = {
// dimensions: res?.data.brand_count.map((item: {})=>Object.keys(item).join('')),
dimensions: ['区域','配电设备总数','IT设备总数'],
source:res?.data.map((item: any)=>{
return {
'区域':item?.space?.label,
'配电设备总数':item?.dev_count,
'IT设备总数':item?.it_dev_count,
}
})
}
return res
}

View File

@ -0,0 +1,49 @@
import { publicInterface } from "@/api/path";
import { CreateComponentType } from '@/packages/index.d'
import { ResultErrcode } from "@/enums/httpEnum";
import { AssetsClassType } from '@/store/modules/chartEditStore/chartEditStore.d'
import dataJson from "./data.json";
import { Product } from "@vicons/carbon";
export const handleAssetsClass =async (targetComponent: CreateComponentType) => {
const obj = targetComponent.commonData[targetComponent.commonData.currentSource] as AssetsClassType
let { enable, dataSource } = obj
console.log(enable, dataSource,'handleAssetsClass')
if(!enable) return {
errcode: ResultErrcode.SUCCESS,
data: { ...dataJson },
errmsg: ''
}
const query = {
}
// 处理数据
if(dataSource==='IT'){
const res = await publicInterface('/dcim/asset','get_asset_overview_page_info_new', query)
res!.data = {
// dimensions: res?.data.brand_count.map((item: {})=>Object.keys(item).join('')),
dimensions: ['product','data'],
source:res?.data.brand_count.slice(0,8).map((item: {})=>{
return {
product:Object.keys(item)[0],
data:Object.values(item)[0],
}
})
}
return res
}else{
const res = await publicInterface('/dcim/dems/device','get_dev_brand_count', query)
res!.data = {
// dimensions: res?.data.brand_count.map((item: {})=>Object.keys(item).join('')),
dimensions: ['品牌','data'],
source:res?.data.slice(0,8).map((item: any)=>{
return {
'品牌':item.name,
data:item.count,
}
})
}
return res
}
}

View File

@ -0,0 +1,35 @@
import moment from "moment";
import { publicInterface } from "@/api/path";
import { DateTypeEnum } from '@/store/modules/chartEditStore/chartEditStore.d'
import { commonDataType, CategoryBrandCountTableType } from '@/store/modules/chartEditStore/chartEditStore.d'
import { CreateComponentType } from '@/packages/index.d'
import { ResultErrcode } from '@/enums/httpEnum'
import dataJson from './data.json'
export const handleCategoryBrandCountTable =async (targetComponent: CreateComponentType) => {
let { currentSource, enable } = (targetComponent.commonData as commonDataType).categoryBrandCountTable as CategoryBrandCountTableType
if(!enable) return {
errcode: ResultErrcode.SUCCESS,
data: { ...dataJson },
errmsg: ''
}
console.log(currentSource,'currentSource');
const res = await publicInterface(currentSource==='IT'?'/dcim/asset':'/dcim/dems/device',currentSource==='IT'?'get_category_brand_count': 'get_dev_category_brand_count', {})
const top = ['TOP1','TOP2','TOP3']
res!.data = {
dimensions: ['分类名',...top],
source:res?.data.map((item: any)=>{
let obj:any = {'分类名':item.name,}
item.brand.forEach((v:any,index:number)=>{
obj[top[index]] = v.Brand
})
return obj
})
}
return res
}

View File

@ -13,11 +13,15 @@ import { handlePointRealTime } from './commonDataComponents/usePointRealTimeRes'
import { handleSinglePoint } from './commonDataComponents/useSinglePointRes' import { handleSinglePoint } from './commonDataComponents/useSinglePointRes'
import { handleMonthAlarmClass } from './commonDataComponents/useMonthAlarmClassRes' import { handleMonthAlarmClass } from './commonDataComponents/useMonthAlarmClassRes'
import { handleDeviceClass } from './commonDataComponents/useDeviceClassRes' import { handleDeviceClass } from './commonDataComponents/useDeviceClassRes'
import { handleAssetsClass } from './commonDataComponents/useAssetsClassRes'
import { handleAreaDevCountClass } from './commonDataComponents/useAreaDevCountRes'
import { handlePointTable } from "./commonDataComponents/usePointTableRes"; import { handlePointTable } from "./commonDataComponents/usePointTableRes";
import { handleCategoryBrandCountTable } from "./commonDataComponents/useCategoryBrandCountTableRes";
import { handleNoParam } from './commonDataComponents/useNoParamRes' import { handleNoParam } from './commonDataComponents/useNoParamRes'
import { handleManulInput } from './commonDataComponents/useManualInputRes' import { handleManulInput } from './commonDataComponents/useManualInputRes'
import { handleManulInputSingle } from './commonDataComponents/useManualInputSingleRes' import { handleManulInputSingle } from './commonDataComponents/useManualInputSingleRes'
import { ResultErrcode } from '@/enums/httpEnum' import { ResultErrcode } from '@/enums/httpEnum'
import { logDark } from 'naive-ui';
// 获取类型 // 获取类型
type ChartEditStoreType = typeof useChartEditStore type ChartEditStoreType = typeof useChartEditStore
@ -46,6 +50,7 @@ export const useChartCommonData = (
// setOption(vChartRef.value, { dataset: dataset }) // setOption(vChartRef.value, { dataset: dataset })
// } // }
// if(!dataset.dimensions) return // if(!dataset.dimensions) return
console.log(targetComponent,'targetComponent')
if(targetComponent.option){ if(targetComponent.option){
const SingleDataArr = [ const SingleDataArr = [
CurrentSourceEnum.SINGLEPOINT, CurrentSourceEnum.SINGLEPOINT,
@ -130,9 +135,18 @@ export const useChartCommonData = (
case CurrentSourceEnum.DEVICECLASS: case CurrentSourceEnum.DEVICECLASS:
res = await handleDeviceClass(targetComponent) res = await handleDeviceClass(targetComponent)
break; break;
case CurrentSourceEnum.ASSETSCLASS:
res = await handleAssetsClass(targetComponent)
break;
case CurrentSourceEnum.AREADEVCOUNT:
res = await handleAreaDevCountClass(targetComponent)
break;
case CurrentSourceEnum.POINTTABLE: case CurrentSourceEnum.POINTTABLE:
res = await handlePointTable(targetComponent) res = await handlePointTable(targetComponent)
break; break;
case CurrentSourceEnum.CATEGORYBRANDCOUNTTABLE:
res = await handleCategoryBrandCountTable(targetComponent)
break;
case CurrentSourceEnum.MANUALINPUT: case CurrentSourceEnum.MANUALINPUT:
res = await handleManulInput(targetComponent) res = await handleManulInput(targetComponent)
break; break;
@ -146,6 +160,8 @@ export const useChartCommonData = (
} }
if (res && res.errcode === ResultErrcode.SUCCESS) { if (res && res.errcode === ResultErrcode.SUCCESS) {
try { try {
console.log(res,'res--fetchFn')
const { data } = res const { data } = res
// 多值的 // 多值的
if(isMultiple) { if(isMultiple) {
@ -161,6 +177,8 @@ export const useChartCommonData = (
else throw Error() else throw Error()
} }
else if(Object.prototype.toString.call(data) === '[object Object]'){ else if(Object.prototype.toString.call(data) === '[object Object]'){
console.log(data,'data');
if(data.dimensions && data.source) { if(data.dimensions && data.source) {
if(typeof targetComponent.commonData.dataLength === 'number') { if(typeof targetComponent.commonData.dataLength === 'number') {
data.source = data.source.slice(0, targetComponent.commonData.dataLength) data.source = data.source.slice(0, targetComponent.commonData.dataLength)

View File

@ -84,6 +84,7 @@ const props = defineProps({
required: true required: true
} }
}) })
console.log(props.optionData,'props.optionData')
const fontWeightOptions = [ const fontWeightOptions = [
{ {
label: PieTypeEnum.NORMAL, label: PieTypeEnum.NORMAL,

View File

@ -44,6 +44,7 @@ const props = defineProps({
props.chartConfig.option.tooltip.position = setTooltipPosition(props.chartConfig.attr) props.chartConfig.option.tooltip.position = setTooltipPosition(props.chartConfig.attr)
const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting) const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
console.log(initOptions,'initOptions')
let seriesDataNum = -1 let seriesDataNum = -1
let seriesDataMaxLength = 0 let seriesDataMaxLength = 0
let intervalInstance: any = null let intervalInstance: any = null
@ -53,6 +54,7 @@ use([DatasetComponent, CanvasRenderer, PieChart, GridComponent, TooltipComponent
const option = computed(() => { const option = computed(() => {
return mergeTheme(props.chartConfig.option, props.themeSetting, includes) return mergeTheme(props.chartConfig.option, props.themeSetting, includes)
}) })
console.log(option,'option')
// //
const handleSeriesData = () => { const handleSeriesData = () => {

View File

@ -0,0 +1,111 @@
import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public'
import { PieCommon3Config } from './index'
import { CreateComponentType } from '@/packages/index.d'
import cloneDeep from 'lodash/cloneDeep'
import dataJson from './data.json'
export const includes = ['legend']
export enum PieTypeEnum {
NORMAL = '常规图',
RING = '环形图',
ROSE = '玫瑰图',
RINGROSE = '环形玫瑰图',
}
export const PieTypeObject = {
[PieTypeEnum.NORMAL]: 'normal',
[PieTypeEnum.RING]: 'ring',
[PieTypeEnum.ROSE]: 'rose',
[PieTypeEnum.RINGROSE]: 'ringrose',
}
// 其它配置
const otherConfig = {
// 轮播动画
isCarousel: false,
legendShowValue: false,
}
const color = ["#F5B442", "#FF8A66","#FF6D55","#FF3342","#F23DAD","#B73FEF","#F23DAD","#B73FEF","#6F40ED","#5945ED"]
const option = {
...otherConfig,
backgroundColor: "rgba(255,255,255,1)",
color,
type: 'pie',
tooltip: {
show: true,
trigger: 'item',
// valueFormatter :function(value:string){
// // console.log(name,'name-formatter')
// return ''+value
// }
},
legend: {
orient: "vartical",
x: "left",
top: "center",
left: "70%",
bottom: "0%",
itemWidth: 8,
itemHeight: 8,
itemGap :16,
formatter :function(name:string){
return ''+name
}
},
dataset: { ...dataJson },
series: [
{
type: 'pie',
clockwise: false, //饼图的扇区是否是顺时针排布
minAngle: 2, //最小的扇区角度0 ~ 360
radius: ["50%", "0%"],
center: ["30%", "50%"],
avoidLabelOverlap: false,
// itemStyle: { //图形样式
// normal: {
// borderColor: '#ffffff',
// borderWidth: 6,
// },
// },
label: {
normal: {
show: false,
position: 'center',
formatter: '{text|{b}}\n{c} ({d}%)',
rich: {
text: {
color: "#666",
fontSize: 14,
align: 'center',
verticalAlign: 'middle',
padding: 8
},
value: {
color: "#8693F3",
fontSize: 24,
align: 'center',
verticalAlign: 'middle',
},
}
},
emphasis: {
show: false,
textStyle: {
fontSize: 24,
}
}
},
}
]
}
export default class Config extends PublicConfigClass implements CreateComponentType {
public key: string = PieCommon3Config.key
public chartConfig = cloneDeep(PieCommon3Config)
// 图表配置项
public option = echartOptionProfixHandle(option, includes)
}

View File

@ -0,0 +1,111 @@
<template>
<!-- Echarts 全局设置 -->
<global-setting :optionData="optionData"></global-setting>
<CollapseItem name="饼图配置" :expanded="true">
<SettingItemBox name="类型" :alone="true">
<SettingItem>
<n-select v-model:value="optionData.type" size="small" :options="fontWeightOptions" />
</SettingItem>
</SettingItemBox>
<SettingItemBox name="图例" :alone="true">
<SettingItem>
<n-space>
<n-switch v-model:value="optionData.legendShowValue" size="small"></n-switch>
<n-text>展示数值</n-text>
</n-space>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="动画" :alone="true">
<SettingItem>
<n-space>
<n-switch v-model:value="optionData.isCarousel" size="small"></n-switch>
<n-text>开启<n-text :depth="3">将自动隐藏图例</n-text></n-text>
</n-space>
</SettingItem>
<SettingItem>
<n-text :depth="3">无鼠标点击图例场景时可强行打开图例</n-text>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="标签">
<SettingItem>
<n-space>
<n-switch v-model:value="optionData.series[0].label.show" size="small"></n-switch>
<n-text>展示标签</n-text>
</n-space>
</SettingItem>
<!-- <setting-item>
<n-space>
<n-switch v-model:value="optionData.series[0].labelLine.show" size="small"></n-switch>
<n-text>引导线</n-text>
</n-space>
</setting-item> -->
<SettingItem name="位置">
<n-select v-model:value="optionData.series[0].label.position" size="small" :options="labelConfig.position" />
</SettingItem>
<setting-item name="展示类型">
<n-select v-model:value="optionData.series[0].label.formatter" size="small" :options="labelFormatterOptions" />
</setting-item>
</SettingItemBox>
<!-- <setting-item-box name="圆角">
<setting-item>
<n-space>
<n-input-number
v-model:value="optionData.series[0].itemStyle.borderRadius"
size="small"
:min="0"
></n-input-number>
<n-text>圆角大小</n-text>
</n-space>
</setting-item>
<setting-item>
<n-space>
<n-input-number
v-model:value="optionData.series[0].itemStyle.borderWidth"
size="small"
:min="0"
></n-input-number>
<n-text>线条宽度</n-text>
</n-space>
</setting-item>
</setting-item-box> -->
</CollapseItem>
</template>
<script setup lang="ts">
import { PropType, watch } from 'vue'
import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
import { GlobalSetting, CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import { PieTypeObject, PieTypeEnum } from './config'
import { labelConfig } from '@/packages/chartConfiguration/echarts'
const props = defineProps({
optionData: {
type: Object as PropType<GlobalThemeJsonType>,
required: true
}
})
const fontWeightOptions = [
{
label: PieTypeEnum.NORMAL,
value: PieTypeObject[PieTypeEnum.NORMAL]
},
// {
// label: PieTypeEnum.RING,
// value: PieTypeObject[PieTypeEnum.RING]
// },
{
label: PieTypeEnum.ROSE,
value: PieTypeObject[PieTypeEnum.ROSE]
},
{
label: PieTypeEnum.RINGROSE,
value: PieTypeObject[PieTypeEnum.RINGROSE]
}
]
const labelFormatterOptions = [
{ label: '数据名', value: '{b}' },
{ label: '百分比', value: '{d}' },
{ label: '列名:百分比', value: '{b}:{d}%' }
]
</script>

View File

@ -0,0 +1,43 @@
{
"dimensions": ["name", "value"],
"source": [{
"name": "财务管理决策实训",
"value": 18
},
{
"name": "商品流通业实训",
"value": 16
},
{
"name": "暖心陪伴津乐园20cm定制蛋糕",
"value": 15
},
{
"name": "嘉果荟萃津乐园20cm定制蛋糕",
"value": 14
},
{
"name": "优雅圆舞曲津乐园20cm",
"value": 10
},
{
"name": "巧克力之夏津乐园20cm定制蛋糕",
"value": 7.9
},
{
"name": "财税宝4G",
"value": 6.7
},
{
"name": "成本会计",
"value": 6
},
{
"name": "纳税会计与筹划",
"value": 4.5
},
{
"name": "金融担保业实训",
"value": 3
}]
}

View File

@ -0,0 +1,14 @@
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
export const PieCommon3Config: ConfigType = {
key: 'PieCommon3',
chartKey: 'VPieCommon3',
conKey: 'VCPieCommon3',
title: '饼图-自定义',
category: ChatCategoryEnum.PIE,
categoryName: ChatCategoryEnumName.PIE,
package: PackagesCategoryEnum.CHARTS,
chartFrame: ChartFrameEnum.ECHARTS,
image: 'PieCommon3.png'
}

View File

@ -0,0 +1,185 @@
<template>
<v-chart
ref="vChartRef"
autoresize
:init-options="initOptions"
:theme="themeColor"
:option="option"
:manual-update="isPreview()"
@mouseover="handleHighlight"
@mouseout="handleDownplay"
></v-chart>
</template>
<script setup lang="ts">
import { computed, PropType, onMounted, watch } from 'vue'
import VChart from 'vue-echarts'
import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { PieChart } from 'echarts/charts'
import { mergeTheme } from '@/packages/public/chart'
import config, { includes } from './config'
import {useChartCommonData, useChartDataFetch} from '@/hooks'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import {isPreview, setTooltipPosition} from '@/utils'
import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
import dataJson from './data.json'
const props = defineProps({
themeSetting: {
type: Object,
required: true
},
themeColor: {
type: Object,
required: true
},
chartConfig: {
type: Object as PropType<config>,
required: true
}
})
props.chartConfig.option.tooltip.position = setTooltipPosition(props.chartConfig.attr)
const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
let seriesDataNum = -1
let seriesDataMaxLength = 0
let intervalInstance: any = null
use([DatasetComponent, CanvasRenderer, PieChart, GridComponent, TooltipComponent, LegendComponent])
const option = computed(() => {
return mergeTheme(props.chartConfig.option, props.themeSetting, includes)
})
//
const handleSeriesData = () => {
if (seriesDataNum > -1) {
vChartRef.value?.dispatchAction({
type: 'downplay',
dataIndex: seriesDataNum
})
}
seriesDataNum = seriesDataNum >= seriesDataMaxLength - 1 ? 0 : seriesDataNum + 1
vChartRef.value?.dispatchAction({
type: 'highlight',
dataIndex: seriesDataNum
})
}
//
const addPieInterval = (newData?: typeof dataJson, skipPre = false) => {
if (!skipPre && !Array.isArray(newData?.source)) return
if (!skipPre) seriesDataMaxLength = newData?.source.length || 0
clearInterval(intervalInstance)
intervalInstance = setInterval(() => {
handleSeriesData()
}, 1000)
}
//
const clearPieInterval = () => {
vChartRef.value?.dispatchAction({
type: 'downplay',
dataIndex: seriesDataNum
})
clearInterval(intervalInstance)
intervalInstance = null
}
//
const handleHighlight = () => {
clearPieInterval()
}
//
const handleDownplay = () => {
if (props.chartConfig.option.isCarousel && !intervalInstance) {
//
addPieInterval(undefined, true)
}
}
//
watch(
() => props.chartConfig.option.type,
newData => {
try {
if (newData === 'normal') {
props.chartConfig.option.series[0].radius = '70%'
props.chartConfig.option.series[0].roseType = false
} else if (newData === 'ring') {
props.chartConfig.option.series[0].radius = ['40%', '65%']
props.chartConfig.option.series[0].roseType = false
} else if (newData === 'rose') {
props.chartConfig.option.series[0].radius = '70%'
props.chartConfig.option.series[0].roseType = true
} else if (newData === 'ringrose') {
props.chartConfig.option.series[0].radius = ['30%', '65%']
props.chartConfig.option.series[0].roseType = true
}
} catch (error) {
console.log(error)
}
},
{ deep: false, immediate: true }
)
//
watch(
() => props.chartConfig.option.isCarousel,
newData => {
if (newData) {
addPieInterval(undefined, true)
props.chartConfig.option.legend.show = false
} else {
props.chartConfig.option.legend.show = true
clearPieInterval()
}
}
)
//
watch(
() => props.chartConfig.option.series.length,
(v) => {
if(v === 1) return
else props.chartConfig.option.series.splice(1)
}
)
//
watch(() => props.chartConfig.option.legendShowValue, v => {
if(v) {
let k1 = props.chartConfig.option.dataset?.dimensions?.[0] || ''
let k2 = props.chartConfig.option.dataset?.dimensions?.[1] || ''
props.chartConfig.option.legend.formatter = (name: string) => {
let arr = props.chartConfig.option.dataset?.source || []
let obj = arr.find((_: any) => _[k1] === name) || {}
return `${name} ${obj[k2]}`
}
}
else {
props.chartConfig.option.legend.formatter = (name: string) => {
return name
}
}
}, {
immediate: true
})
// const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore, (newData: typeof dataJson) => {
// clearPieInterval()
// if (props.chartConfig.option.isCarousel) {
// addPieInterval(newData)
// }
// })
const { vChartRef } = useChartCommonData(props.chartConfig, useChartEditStore)
onMounted(() => {
seriesDataMaxLength = dataJson.source.length
if (props.chartConfig.option.isCarousel) {
addPieInterval(undefined, true)
}
})
</script>

View File

@ -1,6 +1,7 @@
import { PieCommonConfig } from './PieCommon/index' import { PieCommonConfig } from './PieCommon/index'
import { PieCommon1Config } from './PieCommon1/index' import { PieCommon1Config } from './PieCommon1/index'
import { PieCommon2Config } from './PieCommon2/index' import { PieCommon2Config } from './PieCommon2/index'
import { PieCommon3Config } from './PieCommon3/index'
import { PieCircleConfig } from './PieCircle/index' import { PieCircleConfig } from './PieCircle/index'
export default [PieCommonConfig, PieCommon1Config, PieCommon2Config, PieCircleConfig] export default [PieCommonConfig, PieCommon1Config, PieCommon2Config, PieCircleConfig,PieCommon3Config]

View File

@ -54,7 +54,7 @@
</div> </div>
<div class="footer"> <div class="footer">
<div style="flex: 1;"></div> <div style="flex: 1;"></div>
<n-button @click="submitCallback" type="info" size="small" style="margin-right: 5px;color: #fff;">确认</n-button> <n-button @click="submitCallback" type="warning" size="small" style="margin-right: 5px;color: #fff;">确认</n-button>
<n-button size="small" @click="close">取消</n-button> <n-button size="small" @click="close">取消</n-button>
</div> </div>
</n-modal> </n-modal>

View File

@ -29,5 +29,6 @@ export default class Config extends PublicConfigClass implements CreateComponent
showInterval: true, showInterval: true,
showFilter: false, showFilter: false,
space_complete_id: '', space_complete_id: '',
dems_device_point_signal_ids: [],
}) })
} }

View File

@ -5,6 +5,9 @@
<setting-item-box name="空间ID" :alone="true"> <setting-item-box name="空间ID" :alone="true">
<n-input v-model:value="props.customData.space_complete_id" size="small" placeholder="请输入空间ID"/> <n-input v-model:value="props.customData.space_complete_id" size="small" placeholder="请输入空间ID"/>
</setting-item-box> </setting-item-box>
<setting-item-box name="温湿度测点ID(英文逗号隔开)" :alone="true">
<n-input v-model:value="props.customData.dems_device_point_signal_ids" size="small" placeholder="请输入温湿度测点ID(英文逗号隔开)"/>
</setting-item-box>
<setting-item-box name="显示筛选条件" :alone="true"> <setting-item-box name="显示筛选条件" :alone="true">
<n-radio-group v-model:value="props.customData.showFilter" size="small" style="margin-top: 2px"> <n-radio-group v-model:value="props.customData.showFilter" size="small" style="margin-top: 2px">
<n-radio :value="true"></n-radio> <n-radio :value="true"></n-radio>

View File

@ -279,6 +279,8 @@ const getData = () => {
append_space_to_content: 'complete', append_space_to_content: 'complete',
handle_statuss: alarmHandleStatuss.value, handle_statuss: alarmHandleStatuss.value,
recovery_statuss: alarmRecoveryStatus.value, recovery_statuss: alarmRecoveryStatus.value,
dems_device_point_signal_ids: props.chartConfig.customData?.dems_device_point_signal_ids.split(','),
}, },
page: { page: {
page_size: 10, page_size: 10,

View File

@ -0,0 +1,32 @@
import { PublicConfigClass } from '@/packages/public'
import { CreateComponentType } from '@/packages/index.d'
import { ClassifiedStatistic } from './index'
import cloneDeep from 'lodash/cloneDeep'
// import logo from '@/assets/logo.png'
export const option = {
// 图片路径
dataset: '',
// 适应方式
fit: 'contain',
// 圆角
borderRadius: 0
}
export default class Config extends PublicConfigClass implements CreateComponentType
{
constructor() {
super();
this.attr.w = 450
this.attr.h = 300
this.request.requestInterval = 15
}
public key = ClassifiedStatistic.key
public chartConfig = cloneDeep(ClassifiedStatistic)
public option = cloneDeep(option)
public customData = cloneDeep({
title: '分类统计',
showInterval: true,
currentSource:'device'
})
}

View File

@ -0,0 +1,67 @@
<template>
<!-- <collapse-item name="属性" :expanded="true">-->
<!-- <setting-item-box name="路径" :alone="true">-->
<!-- <setting-item>-->
<!-- <n-input v-model:value="optionData.dataset" size="small"></n-input>-->
<!-- </setting-item>-->
<!-- </setting-item-box>-->
<!-- <setting-item-box name="样式">-->
<!-- <setting-item name="类型">-->
<!-- <n-select-->
<!-- v-model:value="optionData.fit"-->
<!-- size="small"-->
<!-- :options="fitList"-->
<!-- ></n-select>-->
<!-- </setting-item>-->
<!-- <setting-item name="圆角">-->
<!-- <n-input-number-->
<!-- v-model:value="optionData.borderRadius"-->
<!-- size="small"-->
<!-- :min="0"-->
<!-- placeholder="圆角"-->
<!-- ></n-input-number>-->
<!-- </setting-item>-->
<!-- </setting-item-box>-->
<!-- </collapse-item>-->
</template>
<script setup lang="ts">
import { PropType } from 'vue'
import { option } from './config'
import {
CollapseItem,
SettingItemBox,
SettingItem,
} from '@/components/Pages/ChartItemSetting'
const props = defineProps({
optionData: {
type: Object as PropType<typeof option>,
required: true,
},
})
//
const fitList = [
{
value: 'fill',
label: 'fill'
},
{
value: 'contain',
label: 'contain'
},
{
value: 'cover',
label: 'cover'
},
{
value: 'scale-down',
label: 'scale-down'
},
{
value: 'none',
label: 'none'
},
]
</script>

View File

@ -0,0 +1,30 @@
<template>
<n-space vertical>
<setting-item-box name="标题" :alone="true">
<n-input v-model:value="props.customData.title" size="small" placeholder="请输入"/>
</setting-item-box>
<setting-item-box name="数据源" :alone="true">
<n-select v-model:value="props.customData.currentSource" :options="multipleSourceOptions" size="small"/>
</setting-item-box>
</n-space>
</template>
<script lang="ts" setup>
import { SettingItemBox } from '@/components/Pages/ChartItemSetting'
const props = defineProps(['customData', 'request'])
const multipleSourceOptions = [
{
label: '配电设备',
value:'device'
},
{
label: 'IT设备',
value:'IT'
},
]
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,16 @@
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
import { ChatCategoryEnum, ChatCategoryEnumName } from '@/packages/components/CustomComponents/index.d'
export const ClassifiedStatistic: ConfigType = {
key: 'ClassifiedStatistic',
chartKey: 'VClassifiedStatistic',
conKey: 'VCClassifiedStatistic',
// VCD开头
conDataKey: 'VCDClassifiedStatistic',
title: '分类统计',
category: ChatCategoryEnum.CUSTOMCOMPONENTS,
categoryName: ChatCategoryEnumName.CUSTOMCOMPONENTS,
package: PackagesCategoryEnum.CUSTOMCOMPONENTS,
chartFrame: ChartFrameEnum.COMMON,
image: 'ClassifiedStatistic.png'
}

View File

@ -0,0 +1,171 @@
<template>
<BorderBox :title="chartConfig?.customData?.title" :style="getStyle(borderRadius)" style="overflow: auto">
<div class="container">
<div class="classify" v-for="item in type_count" :key="item">
<div class="img">
<img v-if="props.chartConfig?.customData?.currentSource==='IT'" src="@/assets/images/chart/decorates/Base1.png" alt="">
<img v-else src="@/assets/images/chart/decorates/Base2.png" alt="">
</div>
<div class="value">
{{Object.keys(item)[0]}}<span class="count">{{Object.values(item)[0]}}</span>
</div>
</div>
</div>
</BorderBox>
</template>
<script setup lang="ts">
import { PropType, shallowReactive, watch, toRefs, reactive, onMounted, onUnmounted, nextTick, ref } from 'vue'
import { useChartDataFetch } from '@/hooks'
import { CreateComponentType } from '@/packages/index.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { publicInterface } from '@/api/path/business.api'
import BorderBox from '../components/BorderBox.vue'
import VChart from 'vue-echarts'
import {isPreview} from '@/utils'
import {graphic} from "echarts";
import {cloneDeep} from 'lodash'
import moment from "moment"
import {selectTimeOptions} from "@/views/chart/ContentConfigurations/components/ChartData/index.d";
import {RequestHttpIntervalEnum} from "@/enums/httpEnum";
const props = defineProps({
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true
},
})
const { w, h } = toRefs(props.chartConfig.attr)
const { dataset, fit, borderRadius } = toRefs(props.chartConfig.option)
const getStyle = (radius: number) => {
return {
borderRadius: `${radius}px`,
overflow: 'hidden'
}
}
console.log(props.chartConfig,'chartConfig');
let type_count:any = ref([])
const getData = () => {
if(props.chartConfig?.customData?.currentSource==='IT'){
publicInterface('/dcim/asset', 'get_asset_overview_page_info_new', {}).then(res => {
console.log(res,'res----')
if (res && res.data) {
type_count.value = res.data.type_count
// for (const key in computeNodeData) {
// computeNodeData[key] = res.data[key]
// }
}
})
}else{
publicInterface('/dcim/dems/device', 'get_dev_category_count', {}).then(res => {
console.log(res,'res----')
if (res && res.data) {
type_count.value = res.data.map((item:any)=>{
return {
[item.name]:item.count
}
})
// for (const key in computeNodeData) {
// computeNodeData[key] = res.data[key]
// }
}
})
}
}
let timer:unknown
watch(() => [props.chartConfig.request.requestInterval, props.chartConfig.request.requestIntervalUnit].join('&&'), v => {
if(!isPreview()) return
console.log(props,'props')
if(props.chartConfig.request.requestInterval) {
if(timer) clearInterval(timer as number)
const obj = selectTimeOptions.find(_ => _.value === props.chartConfig.request.requestIntervalUnit) || {unit: 0}
const unit = obj.unit
const number = unit * props.chartConfig.request.requestInterval
timer = setInterval(() => {
getData()
}, number)
}
})
watch(()=>props.chartConfig?.customData?.currentSource,()=>{
console.log(props.chartConfig?.customData?.currentSource,'chartConfig');
getData()
// currentSource
})
onMounted(() => {
nextTick(() => {
getData()
})
if(!isPreview()) return
const obj = selectTimeOptions.find(_ => _.value === props.chartConfig.request.requestIntervalUnit) || {unit: 0}
const unit = obj.unit
const number = unit * props.chartConfig.request.requestInterval!
timer = setInterval(() => {
nextTick(() => {
getData()
})
}, number)
})
onUnmounted(() => {
clearInterval(timer as number)
})
// const option = shallowReactive({
// dataset: ''
// })
// //
// useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => {
// option.dataset = newData
// })
</script>
<style lang="scss" scoped>
.container{
width: 100%;
height: 100%;
display: flex;
flex-wrap: wrap;
overflow: auto;
}
.classify{
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 33%;
overflow: auto;
color:#fff;
.img{
width: 100px;
height: 100px;
img{
width: 100%;
height: 100%;
}
}
}
.count{
font-size: 17px;
padding: 0 5px;
font-family: LESLIE;
font-size: 20px;
font-weight: 500;
line-height: 20px;
text-align: center;
letter-spacing: 0em;
font-variation-settings: "opsz" auto;
color: #4196FF;
}
</style>

View File

@ -0,0 +1,31 @@
import { PublicConfigClass } from '@/packages/public'
import { CreateComponentType } from '@/packages/index.d'
import { Overview } from './index'
import cloneDeep from 'lodash/cloneDeep'
// import logo from '@/assets/logo.png'
export const option = {
// 图片路径
dataset: '',
// 适应方式
fit: 'contain',
// 圆角
borderRadius: 0
}
export default class Config extends PublicConfigClass implements CreateComponentType
{
constructor() {
super();
this.attr.w = 250
this.attr.h = 200
this.request.requestInterval = 15
}
public key = Overview.key
public chartConfig = cloneDeep(Overview)
public option = cloneDeep(option)
public customData = cloneDeep({
title: '概览',
showInterval: true,
})
}

View File

@ -0,0 +1,67 @@
<template>
<!-- <collapse-item name="属性" :expanded="true">-->
<!-- <setting-item-box name="路径" :alone="true">-->
<!-- <setting-item>-->
<!-- <n-input v-model:value="optionData.dataset" size="small"></n-input>-->
<!-- </setting-item>-->
<!-- </setting-item-box>-->
<!-- <setting-item-box name="样式">-->
<!-- <setting-item name="类型">-->
<!-- <n-select-->
<!-- v-model:value="optionData.fit"-->
<!-- size="small"-->
<!-- :options="fitList"-->
<!-- ></n-select>-->
<!-- </setting-item>-->
<!-- <setting-item name="圆角">-->
<!-- <n-input-number-->
<!-- v-model:value="optionData.borderRadius"-->
<!-- size="small"-->
<!-- :min="0"-->
<!-- placeholder="圆角"-->
<!-- ></n-input-number>-->
<!-- </setting-item>-->
<!-- </setting-item-box>-->
<!-- </collapse-item>-->
</template>
<script setup lang="ts">
import { PropType } from 'vue'
import { option } from './config'
import {
CollapseItem,
SettingItemBox,
SettingItem,
} from '@/components/Pages/ChartItemSetting'
const props = defineProps({
optionData: {
type: Object as PropType<typeof option>,
required: true,
},
})
//
const fitList = [
{
value: 'fill',
label: 'fill'
},
{
value: 'contain',
label: 'contain'
},
{
value: 'cover',
label: 'cover'
},
{
value: 'scale-down',
label: 'scale-down'
},
{
value: 'none',
label: 'none'
},
]
</script>

View File

@ -0,0 +1,30 @@
<template>
<n-space vertical>
<setting-item-box name="标题" :alone="true">
<n-input v-model:value="props.customData.title" size="small" placeholder="请输入"/>
</setting-item-box>
<setting-item-box name="数据源" :alone="true">
<n-select v-model:value="props.customData.currentSource" :options="multipleSourceOptions" size="small"/>
</setting-item-box>
</n-space>
</template>
<script lang="ts" setup>
import { SettingItemBox } from '@/components/Pages/ChartItemSetting'
const props = defineProps(['customData', 'request'])
const multipleSourceOptions = [
{
label: '配电设备',
value:'device'
},
{
label: 'IT设备',
value:'IT'
},
]
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,16 @@
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
import { ChatCategoryEnum, ChatCategoryEnumName } from '@/packages/components/CustomComponents/index.d'
export const Overview: ConfigType = {
key: 'Overview',
chartKey: 'VOverview',
conKey: 'VCOverview',
// VCD开头
conDataKey: 'VCDOverview',
title: '概览',
category: ChatCategoryEnum.CUSTOMCOMPONENTS,
categoryName: ChatCategoryEnumName.CUSTOMCOMPONENTS,
package: PackagesCategoryEnum.CUSTOMCOMPONENTS,
chartFrame: ChartFrameEnum.COMMON,
image: 'Overview.png'
}

View File

@ -0,0 +1,191 @@
<template>
<BorderBox :title="chartConfig?.customData?.title" :style="getStyle(borderRadius)" style="overflow: visible">
<div class="overview" v-for="item in type_count" :key="item">
<div class="img">
<img src="@/assets/images/chart/decorates/Base7.png" alt="">
<div class="value">
{{item.value}}
</div>
</div>
<div class="label">
{{item.label}}
</div>
</div>
</BorderBox>
</template>
<script setup lang="ts">
import { PropType, shallowReactive, watch, toRefs, reactive, onMounted, onUnmounted, nextTick, ref } from 'vue'
import { useChartDataFetch } from '@/hooks'
import { CreateComponentType } from '@/packages/index.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { publicInterface } from '@/api/path/business.api'
import BorderBox from '../components/BorderBox.vue'
import VChart from 'vue-echarts'
import {isPreview} from '@/utils'
import {graphic} from "echarts";
import {cloneDeep} from 'lodash'
import moment from "moment"
import {selectTimeOptions} from "@/views/chart/ContentConfigurations/components/ChartData/index.d";
import {RequestHttpIntervalEnum} from "@/enums/httpEnum";
const props = defineProps({
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true
},
})
const { w, h } = toRefs(props.chartConfig.attr)
const { dataset, fit, borderRadius } = toRefs(props.chartConfig.option)
const getStyle = (radius: number) => {
return {
borderRadius: `${radius}px`,
overflow: 'hidden'
}
}
console.log(props.chartConfig,'chartConfig');
let type_count:any = ref([])
const getData = () => {
if(props.chartConfig?.customData?.currentSource==='IT'){
publicInterface('/dcim/asset', 'get_asset_overview_page_info_new', {}).then(res => {
console.log(res,'res----')
if (res && res.data) {
let commonBrands = res.data.type_count.reduce((prev:any, curr:any) => {
const prevValue:any = Object.values(prev)[0];
const currValue:any = Object.values(curr)[0];
return currValue > prevValue ? curr : prev;
});
let obj = [
{
label:'设备总数',
value:res.data.type_count.reduce((pre:any,cur:any)=>pre+=Object.values(cur)[0],0)
},
{
label:'常用品牌',
value:Object.keys(commonBrands)[0],
},
]
type_count.value = obj
// for (const key in computeNodeData) {
// computeNodeData[key] = res.data[key]
// }
}
})
}else{
publicInterface('/dcim/dems/device', 'get_dev_category_count', {}).then(res => {
console.log(res,'res----')
if (res && res.data) {
const commonBrands:any = res.data.reduce((prev:any, curr:any) => {
return curr.count > prev.count ? curr : prev;
});
let obj = [
{
label:'设备总数',
value:res.data.reduce((pre:any,cur:any)=>pre+=cur.count,0)
},
{
label:'常用品牌',
value:commonBrands.name,
},
]
type_count.value = obj
// for (const key in computeNodeData) {
// computeNodeData[key] = res.data[key]
// }
}
})
}
console.log(type_count.value,`type_count_${props.chartConfig?.customData?.currentSource}`)
}
let timer:unknown
watch(() => [props.chartConfig.request.requestInterval, props.chartConfig.request.requestIntervalUnit].join('&&'), v => {
if(!isPreview()) return
console.log(props,'props')
if(props.chartConfig.request.requestInterval) {
if(timer) clearInterval(timer as number)
const obj = selectTimeOptions.find(_ => _.value === props.chartConfig.request.requestIntervalUnit) || {unit: 0}
const unit = obj.unit
const number = unit * props.chartConfig.request.requestInterval
timer = setInterval(() => {
getData()
}, number)
}
})
watch(()=>props.chartConfig?.customData?.currentSource,()=>{
console.log(props.chartConfig?.customData?.currentSource,'chartConfig');
getData()
// currentSource
})
onMounted(() => {
nextTick(() => {
getData()
})
if(!isPreview()) return
const obj = selectTimeOptions.find(_ => _.value === props.chartConfig.request.requestIntervalUnit) || {unit: 0}
const unit = obj.unit
const number = unit * props.chartConfig.request.requestInterval!
timer = setInterval(() => {
nextTick(() => {
getData()
})
}, number)
})
onUnmounted(() => {
clearInterval(timer as number)
})
// const option = shallowReactive({
// dataset: ''
// })
// //
// useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => {
// option.dataset = newData
// })
</script>
<style lang="scss" scoped>
.overview{
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 33%;
color:#fff;
.img{
position: relative;
width: 100px;
height: 100px;
.value{
position: absolute;
width: 100%;
top:50%;
left:50%;
transform: translate(-50%,-50%);
white-space: pre-wrap;
text-align: center;
}
img{
width: 100%;
height: 100%;
}
}
}
</style>

View File

@ -0,0 +1,32 @@
import { PublicConfigClass } from '@/packages/public'
import { CreateComponentType } from '@/packages/index.d'
import { RoomTemperature } from './index'
import cloneDeep from 'lodash/cloneDeep'
// import logo from '@/assets/logo.png'
export const option = {
// 图片路径
dataset: '',
// 适应方式
fit: 'contain',
// 圆角
borderRadius: 0
}
export default class Config extends PublicConfigClass implements CreateComponentType
{
constructor() {
super();
this.attr.w = 450
this.attr.h = 300
this.request.requestInterval = 15
}
public key = RoomTemperature.key
public chartConfig = cloneDeep(RoomTemperature)
public option = cloneDeep(option)
public customData = cloneDeep({
title: '分类统计',
showInterval: true,
currentSource:'device'
})
}

View File

@ -0,0 +1,67 @@
<template>
<!-- <collapse-item name="属性" :expanded="true">-->
<!-- <setting-item-box name="路径" :alone="true">-->
<!-- <setting-item>-->
<!-- <n-input v-model:value="optionData.dataset" size="small"></n-input>-->
<!-- </setting-item>-->
<!-- </setting-item-box>-->
<!-- <setting-item-box name="样式">-->
<!-- <setting-item name="类型">-->
<!-- <n-select-->
<!-- v-model:value="optionData.fit"-->
<!-- size="small"-->
<!-- :options="fitList"-->
<!-- ></n-select>-->
<!-- </setting-item>-->
<!-- <setting-item name="圆角">-->
<!-- <n-input-number-->
<!-- v-model:value="optionData.borderRadius"-->
<!-- size="small"-->
<!-- :min="0"-->
<!-- placeholder="圆角"-->
<!-- ></n-input-number>-->
<!-- </setting-item>-->
<!-- </setting-item-box>-->
<!-- </collapse-item>-->
</template>
<script setup lang="ts">
import { PropType } from 'vue'
import { option } from './config'
import {
CollapseItem,
SettingItemBox,
SettingItem,
} from '@/components/Pages/ChartItemSetting'
const props = defineProps({
optionData: {
type: Object as PropType<typeof option>,
required: true,
},
})
//
const fitList = [
{
value: 'fill',
label: 'fill'
},
{
value: 'contain',
label: 'contain'
},
{
value: 'cover',
label: 'cover'
},
{
value: 'scale-down',
label: 'scale-down'
},
{
value: 'none',
label: 'none'
},
]
</script>

View File

@ -0,0 +1,30 @@
<template>
<n-space vertical>
<setting-item-box name="标题" :alone="true">
<n-input v-model:value="props.customData.title" size="small" placeholder="请输入"/>
</setting-item-box>
<setting-item-box name="数据源" :alone="true">
<n-select v-model:value="props.customData.currentSource" :options="multipleSourceOptions" size="small"/>
</setting-item-box>
</n-space>
</template>
<script lang="ts" setup>
import { SettingItemBox } from '@/components/Pages/ChartItemSetting'
const props = defineProps(['customData', 'request'])
const multipleSourceOptions = [
{
label: '配电设备',
value:'device'
},
{
label: 'IT设备',
value:'IT'
},
]
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,16 @@
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
import { ChatCategoryEnum, ChatCategoryEnumName } from '@/packages/components/CustomComponents/index.d'
export const RoomTemperature: ConfigType = {
key: 'RoomTemperature',
chartKey: 'VRoomTemperature',
conKey: 'VCRoomTemperature',
// VCD开头
conDataKey: 'VCDRoomTemperature',
title: '机房温度',
category: ChatCategoryEnum.CUSTOMCOMPONENTS,
categoryName: ChatCategoryEnumName.CUSTOMCOMPONENTS,
package: PackagesCategoryEnum.CUSTOMCOMPONENTS,
chartFrame: ChartFrameEnum.COMMON,
image: 'RoomTemperature.png'
}

View File

@ -0,0 +1,426 @@
<template>
<BorderBox :title="chartConfig?.customData?.title" :style="getStyle(borderRadius)" style="overflow: visible">
<div class="contentBox">
<!-- 楼层 -->
<div class="row flex" v-for="floor in floorData" :key="floor.name">
<!-- 楼层名 -->
<div class="floorNum">{{floor.name}}</div>
<!-- 房间 -->
<div class="box flex" v-for="room in floor.roomList" :class="{mr0:floor.roomList.length-1!==0}" :key="room.roomName">
<div class="thermometer" :style="`background-color:${ levelValue(room.level)}`"></div>
<div class="room">
<span>{{room.roomName}}</span>
<span>{{room.temperature}}</span>
</div>
</div>
</div>
<div class="level flex">
<div class="levelItem flex" @click="onClickLevel(item)" v-for="(item,index) in levelList" :key="index" >
<div class="circle" :class="{activeLevel:item.checked}" :style="`background-color:${item.color}`"></div>
<div class="levelName">{{item.name}}</div>
</div>
</div>
</div>
</BorderBox>
</template>
<script setup lang="ts">
import { PropType, shallowReactive, watch, toRefs, reactive, onMounted, onUnmounted, nextTick, ref,computed } from 'vue'
import { useChartDataFetch } from '@/hooks'
import { CreateComponentType } from '@/packages/index.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { publicInterface } from '@/api/path/business.api'
import BorderBox from '../components/BorderBox.vue'
import VChart from 'vue-echarts'
import {isPreview} from '@/utils'
import {graphic} from "echarts";
import {cloneDeep} from 'lodash'
import moment from "moment"
import {selectTimeOptions} from "@/views/chart/ContentConfigurations/components/ChartData/index.d";
import {RequestHttpIntervalEnum} from "@/enums/httpEnum";
const props = defineProps({
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true
},
})
const { w, h } = toRefs(props.chartConfig.attr)
const { dataset, fit, borderRadius } = toRefs(props.chartConfig.option)
const getStyle = (radius: number) => {
return {
borderRadius: `${radius}px`,
overflow: 'hidden'
}
}
console.log(props.chartConfig,'chartConfig');
const computeNodeData:{[k:string]: number} = reactive({
abnormal_count: 0,
abnormal_server_count: 0,
busy_server_count: 0,
loss_server_count: 0,
need_updated_count: 0,
node_count: 0,
offline_server_count: 0,
sever_count: 0
})
const levelList = reactive([
{
name:'正常',
level:0,
color:'#4DCA59',
checked:false
},
{
name:'紧急告警',
level:4,
color:'#F43B42',
checked:false
},
{
name:'严重告警',
level:3,
color:'#FC8358',
checked:false
},
{
name:'重要告警',
level:2,
color:'#F8CA00',
checked:false
},
{
name:'一般告警',
level:1,
color:'#4FBADB',
checked:false
},
])
const floorData = reactive(
[
{
name: '5楼',
roomList:[
{
roomName:'401',
temperature:'30°C',
level:0,
},
{
roomName:'401',
temperature:'30°C',
level:1,
},
{
roomName:'301',
temperature:'30°C',
level:2,
},
{
roomName:'101',
temperature:'30°C',
level:4,
},
]
},
{
name: '4楼',
roomList:[
{
roomName:'401',
temperature:'30°C',
level:0,
},
{
roomName:'401',
temperature:'30°C',
level:1,
},
{
roomName:'301',
temperature:'30°C',
level:2,
},
{
roomName:'101',
temperature:'30°C',
level:3,
},
]
},
{
name: '3楼',
roomList:[
{
roomName:'401',
temperature:'30°C',
level:0,
},
{
roomName:'401',
temperature:'30°C',
level:1,
},
{
roomName:'301',
temperature:'30°C',
level:2,
},
{
roomName:'101',
temperature:'30°C',
level:3,
},
]
},
{
name: '2楼',
roomList:[
{
roomName:'401',
temperature:'30°C',
level:0,
},
{
roomName:'401',
temperature:'30°C',
level:1,
},
{
roomName:'301',
temperature:'30°C',
level:2,
},
{
roomName:'101',
temperature:'30°C',
level:3,
},
]
},
{
name: '1楼',
roomList:[
{
roomName:'401',
temperature:'30°C',
level:0,
},
{
roomName:'401',
temperature:'30°C',
level:1,
},
{
roomName:'301',
temperature:'30°C',
level:2,
},
{
roomName:'101',
temperature:'30°C',
level:3,
},
]
},
])
const levelValue = (level:any)=>{
const obj:any = levelList.find(item=>item.level===level)
return obj.value
}
const onClickLevel = (item:any) => {
console.log(item,'item')
//
levelList.forEach(_ => {
if(_.level!==item.level){
_.checked = false
}
})
//
item.checked = !item.checked
}
const getData = () => {
publicInterface('/dcim/dems/statistic', 'count_node', {}).then(res => {
if (res && res.data) {
for (const key in computeNodeData) {
computeNodeData[key] = res.data[key]
}
}
})
}
let timer:unknown
watch(() => [props.chartConfig.request.requestInterval, props.chartConfig.request.requestIntervalUnit].join('&&'), v => {
if(!isPreview()) return
console.log(props,'props')
if(props.chartConfig.request.requestInterval) {
if(timer) clearInterval(timer as number)
const obj = selectTimeOptions.find(_ => _.value === props.chartConfig.request.requestIntervalUnit) || {unit: 0}
const unit = obj.unit
const number = unit * props.chartConfig.request.requestInterval
timer = setInterval(() => {
getData()
}, number)
}
})
watch(props.chartConfig,(v)=>{
console.log(props.chartConfig?.customData?.currentSource,'chartConfig');
// currentSource
})
onMounted(() => {
nextTick(() => {
getData()
})
if(!isPreview()) return
const obj = selectTimeOptions.find(_ => _.value === props.chartConfig.request.requestIntervalUnit) || {unit: 0}
const unit = obj.unit
const number = unit * props.chartConfig.request.requestInterval!
timer = setInterval(() => {
nextTick(() => {
getData()
})
}, number)
})
onUnmounted(() => {
clearInterval(timer as number)
})
// const option = shallowReactive({
// dataset: ''
// })
// //
// useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => {
// option.dataset = newData
// })
</script>
<style lang="scss" scoped>
.flex{
display: flex;
// justify-self: start;
// justify-content: space-between;
align-items: center;
}
.contentBox{
position: relative;
bottom:10px;
top:0px;
width: 100%;
height: calc(100% - 20px);
overflow: auto;
.row{
width: 100%;
// height: 100px;
.floorNum{
width: 52px;
height: 30px;
margin-left: 10px;
line-height: 30px;
text-align: center;
border-radius: 2px;
color:#fff;
/* 自动布局 */
display: flex;
flex-direction: column;
// padding: 9px 16px;
/* 蓝色10% */
background: rgba(65, 150, 255, 0.1);
box-sizing: border-box;
/* 大屏底色 */
/* 样式描述50% */
border: 1px solid rgba(65, 150, 255, 0.5);
}
.box{
height: 48px;
width: 78px;
background: #ccc;
border-radius: 2px;
opacity: 1;
margin: 5px 10px;
/* 蓝色10% */
background: rgba(65, 150, 255, 0.1);
.thermometer{
width: 24px;
height: 24px;
border-radius: 50%;
margin-right: 3px;
margin-left:5px;
}
.room{
display: flex;
flex-direction: column;
justify-content: space-between;
span{
font-family: Microsoft YaHei;
font-size: 12px;
font-weight: normal;
font-variation-settings: "opsz" auto;
/* 主色/容器背景色 */
/*
弹窗背景色 */
color: #FFFFFF;
}
}
}
}
.mr0{
margin-right: 0 !important;
}
.level{
position: fixed;
left: 50%;
transform: translateX(-50%);
display: flex;
bottom: 2px;
font-size: 12px;
justify-content: center;
background: transparent;
.levelItem{
margin: 0 10px;
cursor: pointer;
color: #fff;
.circle{
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 5px;
}
}
}
.activeLevel{
background: #ccc !important;
}
}
</style>

View File

@ -9,7 +9,24 @@ export const customData = {
title: '区域温度TOP10', title: '区域温度TOP10',
ids: '', ids: '',
demonstration: false, demonstration: false,
queryType: 'temp_list_dashboard',
showInterval: true, showInterval: true,
colName1:'区域设备',
colName2:'实时温度',
queryTypeOptions : [
{
label: '区域温湿度',
value:'temp_list_dashboard'
},
{
label: '机房温湿度排名',
value:'room_temp_sort_dashboard'
},
{
label: '机房温湿度',
value:'room_temp_dashboard'
},
]
} }
export default class Config extends PublicConfigClass implements CreateComponentType { export default class Config extends PublicConfigClass implements CreateComponentType {

View File

@ -2,11 +2,22 @@
<setting-item-box name="标题" :alone="true"> <setting-item-box name="标题" :alone="true">
<n-input v-model:value="props.customData.title" size="small" placeholder="请输入"/> <n-input v-model:value="props.customData.title" size="small" placeholder="请输入"/>
</setting-item-box> </setting-item-box>
<setting-item-box name="列名1" :alone="true">
<n-input v-model:value="props.customData.colName1" size="small" placeholder="请输入"/>
</setting-item-box>
<setting-item-box name="列名2" :alone="true">
<n-input v-model:value="props.customData.colName2" size="small" placeholder="请输入"/>
</setting-item-box>
<setting-item-box name="开启演示模式" :alone="true"> <setting-item-box name="开启演示模式" :alone="true">
<n-space> <n-space>
<n-switch v-model:value="props.customData.demonstration" size="small"/> <n-switch v-model:value="props.customData.demonstration" size="small"/>
</n-space> </n-space>
</setting-item-box> </setting-item-box>
<setting-item-box name="数据类型" :alone="true">
<n-select v-model:value="props.customData.queryType" :options="props.customData.queryTypeOptions" size="small"/>
</setting-item-box>
<setting-item-box name="区域温度测点(英文逗号隔开)" :alone="true"> <setting-item-box name="区域温度测点(英文逗号隔开)" :alone="true">
<n-input v-model:value="props.customData.ids" size="small" placeholder="请输入"/> <n-input v-model:value="props.customData.ids" size="small" placeholder="请输入"/>
</setting-item-box> </setting-item-box>
@ -16,6 +27,7 @@
import { SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' import { SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
const props = defineProps(['customData', 'request']) const props = defineProps(['customData', 'request'])
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -4,16 +4,16 @@
<div class="contentBox"> <div class="contentBox">
<div class="row"> <div class="row">
<div class="col">排序</div> <div class="col">排序</div>
<div class="col">区域设备</div> <div class="col">{{customData.colName1}}</div>
<div class="col">实时温度</div> <div class="col">{{customData.colName2}}</div>
</div> </div>
<div class="row" v-for="(it, i) in data" :key="i"> <div class="row" v-for="(it, i) in data" :key="i">
<div class="col col1">{{i + 1}}</div> <div class="col col1">{{i + 1}}</div>
<div class="col col1" :title="`${it.space_complete_name}/${it.node_name}`"> <div class="col col1" :title="it.label">
{{ getAreaName(it.space_complete_name) }}<span v-if="getAreaName(it.space_complete_name)">/</span>{{ it.node_name }} {{ it.label }}
</div> </div>
<div class="col col1"> <div class="col col1">
<div class="value">{{it.dems_device_point.node_value}}</div> <div class="value">{{it.value}}°C</div>
<LocationIcon @click.stop="jumpToMachineRoom(it)" class="icon" style="margin-left: 5px;cursor: pointer;width: 16px;height: 16px;color: #4196ff;"/> <LocationIcon @click.stop="jumpToMachineRoom(it)" class="icon" style="margin-left: 5px;cursor: pointer;width: 16px;height: 16px;color: #4196ff;"/>
</div> </div>
</div> </div>
@ -81,20 +81,33 @@ const getData = () => {
const params = { const params = {
signal_ids: customData.value.ids.split(',') signal_ids: customData.value.ids.split(',')
} }
publicInterface('/dcim/dems/device_point', 'temp_list_dashboard', params).then((res: any) => { const queryType = customData.value.queryTypeOptions.find(item=>item.value === customData.value.queryType)!.value
publicInterface('/dcim/dems/device_point', customData.value.queryTypeOptions.find(item=>item.value === customData.value.queryType)!.value, params).then((res: any) => {
if (res.data && res.data.length) { if (res.data && res.data.length) {
data.value = res.data.slice(0, 10) data.value = res.data.slice(0, 10)
data.value = data.value.map((item: any)=>{
if(queryType==='temp_list_dashboard'){
item.label = `${getAreaName(item.space_complete_name)}/${item.node_name}`
item.value = item.dems_device_point.node_value
}else{
item.label = item.space.label
item.space_id = item.space.id
}
item.space_type = item?.space?.space_type
return item
})
if(customData.value.demonstration) { if(customData.value.demonstration) {
data.value = data.value.map((item: any) => { data.value = data.value.map((item: any) => {
if(!item?.dems_device_point?.node_value) { if(!item?.value) {
if(!item.dems_device_point) item.dems_device_point = {} item.value = toTwoDecimalPlaces(25 + Math.random() * 10)
item.dems_device_point.node_value = toTwoDecimalPlaces(25 + Math.random() * 10)
} }
return item return item
}) })
} }
} }
}) })
} }
watch(() => customData.value.demonstration, getData) watch(() => customData.value.demonstration, getData)

View File

@ -18,6 +18,9 @@ import { DeviceRunningStateConfig } from './DeviceRunningState'
import { TemperatureTop10Config } from './TemperatureTop10' import { TemperatureTop10Config } from './TemperatureTop10'
import { PositionConfig } from './Position' import { PositionConfig } from './Position'
import { JumpBtnConfig } from './JumpBtn' import { JumpBtnConfig } from './JumpBtn'
import { ClassifiedStatistic } from './ClassifiedStatistic'
import { RoomTemperature } from './RoomTemperature'
import { Overview } from './Overview'
export default [ export default [
// Theme1Config, // Theme1Config,
@ -40,4 +43,7 @@ export default [
TemperatureTop10Config, TemperatureTop10Config,
PositionConfig, PositionConfig,
JumpBtnConfig, JumpBtnConfig,
ClassifiedStatistic,
RoomTemperature,
Overview
] ]

View File

@ -3,8 +3,13 @@ import { CreateComponentType } from '@/packages/index.d'
import { TableList1Config } from './index' import { TableList1Config } from './index'
import cloneDeep from 'lodash/cloneDeep' import cloneDeep from 'lodash/cloneDeep'
// import logo from '@/assets/logo.png' // import logo from '@/assets/logo.png'
export enum AlignEnum {
LEFT = 'left',
CENTER = 'center',
RIGHT = 'right',
}
export const option = { export const option = {
// // 图片路径 // // 图片路径
// dataset: '', // dataset: '',
// // 适应方式 // // 适应方式
@ -12,7 +17,7 @@ export const option = {
// // 圆角 // // 圆角
// borderRadius: 0 // borderRadius: 0
dataset: { dataset: {
"dimensions": [], "dimensions": ['分类名','top1','top2','top3'],
"source": [] "source": []
}, },
timeout: 3000 timeout: 3000

View File

@ -9,14 +9,15 @@
placeholder="请输入轮播时间" placeholder="请输入轮播时间"
></n-input-number> ></n-input-number>
</SettingItem> </SettingItem>
</SettingItemBox> </SettingItemBox>
</CollapseItem> </CollapseItem>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { PropType } from "vue"; import { PropType,Ref ,computed} from "vue";
import { option } from './config' import { option,AlignEnum } from './config'
import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
const props = defineProps({ const props = defineProps({
@ -26,6 +27,7 @@ const props = defineProps({
} }
}) })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -76,7 +76,7 @@ const roll = debounce(() => {
}, 200) }, 200)
const option = computed(() => props.chartConfig.option) const option = computed(() => props.chartConfig.option)
console.log(props.chartConfig,'props.chartConfig')
const commonData = computed(() => props.chartConfig.commonData) const commonData = computed(() => props.chartConfig.commonData)
// const isPointTable = computed(() => { // const isPointTable = computed(() => {
@ -90,6 +90,7 @@ const isTag = computed(() => {
const datasetDimensions = computed(() => { const datasetDimensions = computed(() => {
return option.value.dataset.dimensions return option.value.dataset.dimensions
}) })
console.log(datasetDimensions,'datasetDimensions')
const datasetSource = computed(() => { const datasetSource = computed(() => {
return option.value.dataset.source return option.value.dataset.source
}) })

View File

@ -11,8 +11,8 @@ export const option = {
// 展示列 // 展示列
header: { header: {
value: [], value: [],
options: [], options: [] as any[],
map: {}, map:{} as any,
}, },
pagination: { pagination: {
page: 1, page: 1,
@ -28,9 +28,13 @@ export const option = {
fontSize: 16, fontSize: 16,
borderWidth: 0, borderWidth: 0,
borderColor: 'rgba(0, 0, 0, 1)', borderColor: 'rgba(0, 0, 0, 1)',
borderStyle: 'solid' borderStyle: 'solid',
}, },
inputShow: 'none' inputShow: 'none',
isPagination:true,
isBackgroundColor:true,
} }
export default class Config extends PublicConfigClass implements CreateComponentType { export default class Config extends PublicConfigClass implements CreateComponentType {

View File

@ -5,10 +5,25 @@
<div class="rows"> <div class="rows">
<div class="columns">字段</div> <div class="columns">字段</div>
<div class="columns ">标题 </div> <div class="columns ">标题 </div>
</div> </div>
<div class="rows" v-for="(row, i) in optionData.header.options" :key="i"> <div class="rows" v-for="(row, i) in optionData.header.options" :key="i">
<div class="columns">{{ row }}</div> <div class="columns">{{ row }}</div>
<n-input class="columns" v-model:value="optionData.header.map[row]" size="small"/> <div class="columns">
<n-input class="columns" style="width: 100px;" v-model:value="optionData.header.map[row]" size="small"/>
<n-button @click="handleDelete(i)" circle size="tiny">
<template #icon>
<n-icon><RemoveIcon /></n-icon>
</template>
</n-button>
<n-button @click="handleAdd(i)" circle size="tiny">
<template #icon>
<n-icon><AddIcon /></n-icon>
</template>
</n-button>
</div>
</div> </div>
</setting-item-box> </setting-item-box>
<setting-item-box name="展示列" :alone="true"> <setting-item-box name="展示列" :alone="true">
@ -51,6 +66,12 @@
<SettingItem name="显示边框" :alone="true"> <SettingItem name="显示边框" :alone="true">
<n-select v-model:value="(optionData as any).style.border" size="small" :options="borderFlag" /> <n-select v-model:value="(optionData as any).style.border" size="small" :options="borderFlag" />
</SettingItem> </SettingItem>
<SettingItem name="显示分页" :alone="true">
<n-select v-model:value="optionData.isPagination" size="small" :options="isPaginationFlag" />
</SettingItem>
<SettingItem name="显示背景色" :alone="true">
<n-select v-model:value="optionData.isBackgroundColor" size="small" :options="isBackgroundColorFlag" />
</SettingItem>
<SettingItem name="底部边框" :alone="true"> <SettingItem name="底部边框" :alone="true">
<n-select <n-select
v-model:value="(optionData as any).style.bottomBordered" v-model:value="(optionData as any).style.bottomBordered"
@ -86,21 +107,82 @@
<setting-item name="边框颜色" :alone="true"> <setting-item name="边框颜色" :alone="true">
<n-color-picker size="small" :modes="['rgb']" v-model:value="optionData.style.borderColor"></n-color-picker> <n-color-picker size="small" :modes="['rgb']" v-model:value="optionData.style.borderColor"></n-color-picker>
</setting-item> </setting-item>
<setting-item name="边框样式" :alone="true"> <setting-item name="边框样式" :alone="true">
<n-select v-model:value="optionData.style.borderStyle" size="small" :options="borderStyleFlag" /> <n-select v-model:value="optionData.style.borderStyle" size="small" :options="borderStyleFlag" />
</setting-item> </setting-item>
<SettingItem name="表格搜索(前端静态搜索)" :alone="true"> <SettingItem name="表格搜索(前端静态搜索)" :alone="true">
<n-select v-model:value="optionData.inputShow" size="small" :options="inputSelect" /> <n-select v-model:value="optionData.inputShow" size="small" :options="inputSelect" />
</SettingItem> </SettingItem>
</setting-item-box> </setting-item-box>
</collapse-item> </collapse-item>
<n-modal
:show="show"
preset="dialog"
title=""
:show-icon="false"
@close="close"
@esc="close"
style="width: 500px"
>
<!-- <n-input class="columns" style="width: 100px;" v-model:value="headerMap.key" size="small"/>
<n-input class="columns" style="width: 100px;" v-model:value="headerMap.value" size="small"/> -->
<n-list class="go-system-setting">
<template #header>
<n-space justify="space-between">
<n-h3 class="go-mb-0">添加标题</n-h3>
<n-icon size="20" class="go-cursor-pointer" @click="close">
<close-icon></close-icon>
</n-icon>
</n-space>
</template>
<n-list-item >
<n-space :size="40">
<n-space>
<n-text class="item-left">字段</n-text>
</n-space>
<n-space>
<n-input class="columns" style="width: 100%;" v-model:value="headerMap.key" size="small"/>
</n-space>
</n-space>
</n-list-item>
<n-list-item >
<n-space :size="40">
<n-space>
<n-text class="item-left">标题</n-text>
</n-space>
<n-space>
<n-input class="columns" style="width: 100%;" v-model:value="headerMap.value" size="small"/>
</n-space>
</n-space>
</n-list-item>
</n-list>
<!-- <div class="footer">
<div style="flex: 1;"></div>
<n-button @click="submitCallback" type="info" size="small" style="margin-right: 5px;color: #fff;">确认</n-button>
<n-button size="small" @click="close">取消</n-button>
</div> -->
<template #action>
<n-button @click="submitCallback" type="info" size="small" style="margin-right: 5px;color: #fff;">确认</n-button>
<n-button size="small" @click="close">取消</n-button>
</template>
</n-modal>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { PropType, watch, ref } from 'vue' import { PropType, watch, ref } from 'vue'
import type { Ref } from 'vue'
import { icon } from '@/plugins/icon'
const { RemoveIcon, AddIcon } = icon.ionicons5
import { option } from './config' import { option } from './config'
import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import { commonDataType, PointHistoryType } from '@/store/modules/chartEditStore/chartEditStore.d'
import {useTargetData} from '@/views/chart/ContentConfigurations/components/hooks/useTargetData.hook'
const page = [ const page = [
{ label: '2', value: 2 }, { label: '2', value: 2 },
{ label: '5', value: 5 }, { label: '5', value: 5 },
@ -112,6 +194,14 @@ const borderFlag = [
{ label: '显示', value: 'on' }, { label: '显示', value: 'on' },
{ label: '不显示', value: 'off' } { label: '不显示', value: 'off' }
] ]
const isPaginationFlag = [
{ label: '显示', value: true },
{ label: '不显示', value: false }
]
const isBackgroundColorFlag = [
{ label: '显示', value: true },
{ label: '不显示', value: false }
]
const columnFlag = [ const columnFlag = [
{ label: '显示', value: 'off' }, { label: '显示', value: 'off' },
{ label: '不显示', value: 'on' } { label: '不显示', value: 'on' }
@ -145,38 +235,49 @@ const props = defineProps({
} }
}) })
// const header = ref() const { targetData } = useTargetData() as { targetData: Ref<{ commonData: commonDataType, id: string }> }
// const median = ref<string[]>([]) const currentIndex = ref(0)
// props.optionData.dataset.dimensions.forEach(item => { const handleAdd = (i:number) => {
// median.value.push(item.title) show.value = true
// }) currentIndex.value = i
// targetData.value?.option.dataset.dimensions.push('')
// //string }
// watch(
// () => props.optionData,
// () => {
// median.value = []
// props.optionData.dataset.dimensions.forEach(item => {
// median.value.push(item.title)
// })
// header.value = median.value.toString()
// },
// {
// deep: false,
// immediate: true
// }
// )
//columns const handleDelete = (i: number) => {
// watch([header], ([headerNew], [headerOld]) => { // targetData.value.commonData.pointHistory.dems_device_points_uid.splice(i, 1)
// if (headerNew !== headerOld) { console.log(props.optionData.header,'targetData_delete')
// headerNew.split(',').forEach((item: string, index: number) => { // targetData.value?.option.dataset.dimensions.push('')
// if (index + 1 <= props.optionData.dataset.dimensions.length) { props.optionData.header.options.splice(i, 1,)
// props.optionData.dataset.dimensions[index].title = headerNew.split(',')[index]
// }
// }) }
// }
// }) const show = ref(false)
const headerMap = ref<any>({
key: '',
value: ''
})
const emit = defineEmits(['close', 'update:show'])
const close = () => {
emit('close')
updateShow(false)
show.value = false
}
const submitCallback = ()=>{
console.log(headerMap.value,'headerMap')
props.optionData.header.options.splice(currentIndex.value+1, 0, headerMap.value.key)
props.optionData.header.map[headerMap.value.key] = headerMap.value.value
console.log(props.optionData,'props.optionData.header')
close()
}
const updateShow = (flag:boolean) => {
emit('update:show', flag)
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -185,6 +286,11 @@ const props = defineProps({
display: flex; display: flex;
height: 28px; height: 28px;
line-height: 28px; line-height: 28px;
.columns {
display: flex;
justify-content: space-between;
align-items: center;
}
&:nth-last-child(1){ &:nth-last-child(1){
margin-bottom: 0; margin-bottom: 0;
} }

View File

@ -1,5 +1,7 @@
<template> <template>
<div class="go-tables-basic"> <div class="go-tables-basic"
:class="{'go-custom-data-table':isBackgroundColor}"
>
<n-input <n-input
v-model:value="inputData" v-model:value="inputData"
placeholder="请输入信息" placeholder="请输入信息"
@ -11,7 +13,7 @@
</template> </template>
</n-input> </n-input>
<n-data-table <n-data-table
style="box-sizing: border-box" style="box-sizing: border-box;"
:style="` :style="`
width: ${w}px; width: ${w}px;
height: ${h}px; height: ${h}px;
@ -28,7 +30,7 @@
size="small" size="small"
:columns="columns" :columns="columns"
:data="filterData" :data="filterData"
:pagination="pagination" :pagination="isPagination?pagination:false"
/> />
</div> </div>
</template> </template>
@ -64,7 +66,7 @@ const filterData = computed(() => {
}) })
}) })
const { align, pagination, inputShow } = toRefs(props.chartConfig.option) const { align, pagination, inputShow,isPagination,isBackgroundColor } = toRefs(props.chartConfig.option)
pagination.value.onChange = (page: number) => { pagination.value.onChange = (page: number) => {
pagination.value.page = page pagination.value.page = page
@ -161,8 +163,9 @@ const columns = computed(() => {
} }
return dimensions return dimensions
}) })
useChartCommonData(props.chartConfig, useChartEditStore) useChartCommonData(props.chartConfig, useChartEditStore)
console.log(props.chartConfig,'chartConfig')
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -172,4 +175,19 @@ useChartCommonData(props.chartConfig, useChartEditStore)
gap: 15px; gap: 15px;
align-items: flex-end; align-items: flex-end;
} }
:deep(.n-data-table-td) {
background-color:#1A1D25;
}
:deep(.n-data-table-th) {
background-color:#1A1D25;
}
@include go('custom-data-table'){
background-color: #1A1D25;
:deep(.n-data-table-td) {
background-color:#1A1D25;
}
:deep(.n-data-table-th) {
background-color:#1A1D25;
}
}
</style> </style>

View File

@ -88,10 +88,18 @@ const commonData: commonDataType = {
enable: false, enable: false,
space_complete_id: '' space_complete_id: ''
}, },
assetsClass: {
enable: false,
dataSource: ''
},
pointTable: { pointTable: {
enable: false, enable: false,
ids: [] ids: []
}, },
categoryBrandCountTable: {
enable: false,
currentSource:'',
},
singlePoint: { singlePoint: {
enable: false, enable: false,
pointId: '', pointId: '',

View File

@ -264,10 +264,16 @@ export enum CurrentSourceEnum {
SINGLEPOINT = 'singlePoint', SINGLEPOINT = 'singlePoint',
// 设备分类统计 // 设备分类统计
DEVICECLASS = 'deviceClass', DEVICECLASS = 'deviceClass',
// 设备分类统计
ASSETSCLASS = 'assetsClass',
// 区域设备个数
AREADEVCOUNT = 'areaDevCount',
// 当月告警分类统计 // 当月告警分类统计
MONTHALARMCLASS = 'monthAlarmClass', MONTHALARMCLASS = 'monthAlarmClass',
// 测点表格 // 测点表格
POINTTABLE = 'pointTable', POINTTABLE = 'pointTable',
// 测点表格
CATEGORYBRANDCOUNTTABLE = 'categoryBrandCountTable',
// 手动输入 // 手动输入
MANUALINPUT = 'manualInput', MANUALINPUT = 'manualInput',
// 手动输入(单值) // 手动输入(单值)
@ -346,12 +352,25 @@ export interface DeviceClassType {
enable: boolean enable: boolean
space_complete_id: string space_complete_id: string
} }
// 统计
export interface AssetsClassType {
enable: boolean
dataSource: string
}
export interface AreaDevCountType {
enable: boolean
dataSource: string
}
// 测点表格值 // 测点表格值
export interface PointTableType { export interface PointTableType {
enable: boolean enable: boolean
ids: string[] ids: string[]
} }
export interface CategoryBrandCountTableType {
enable: boolean
currentSource: string
}
// 手动输入值 // 手动输入值
export interface ManualInputType { export interface ManualInputType {
@ -381,9 +400,12 @@ export interface commonDataType {
pointRealTime: PointRealTimeType pointRealTime: PointRealTimeType
monthAlarmClass: MonthAlarmClassType monthAlarmClass: MonthAlarmClassType
pointTable: PointTableType pointTable: PointTableType
categoryBrandCountTable: CategoryBrandCountTableType
// 多数据无参数 // 多数据无参数
// 设备分类统计 // 设备分类统计
deviceClass: DeviceClassType deviceClass: DeviceClassType
assetsClass: AssetsClassType
areaDevCount: AreaDevCountType
// 单数据 // 单数据
singlePoint: SinglePointType singlePoint: SinglePointType
// 手动输入 // 手动输入

View File

@ -18,6 +18,6 @@ body {
/* 滚动条滑块 */ /* 滚动条滑块 */
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
border-radius: 4px; border-radius: 4px;
background: #a3a3a3; background: #294C79;
} }

View File

@ -0,0 +1,39 @@
<template>
<setting-item-box name="启用数据" :alone="true">
<n-space justify="start">
<n-switch v-model:value="currentObj.enable"/>
</n-space>
</setting-item-box>
<setting-item-box name="数据源" :alone="true">
<n-select v-model:value="currentObj.dataSource" :options="multipleSourceOptions" size="small"/>
</setting-item-box>
</template>
<script lang="ts" setup>
import {computed} from 'vue'
import type {Ref} from 'vue'
import {SettingItemBox} from '@/components/Pages/ChartItemSetting'
import {useTargetData} from '../../hooks/useTargetData.hook'
import {commonDataType, AssetsClassType} from '@/store/modules/chartEditStore/chartEditStore.d'
const {targetData} = useTargetData() as { targetData: Ref<{ commonData: commonDataType, id: string }> }
const currentObj = computed(() => {
return targetData.value.commonData[targetData.value.commonData.currentSource] as AssetsClassType
})
console.log(targetData,'targetData')
const multipleSourceOptions = [
{
label: '配电设备',
value:'device'
},
{
label: 'IT设备',
value:'IT'
},
]
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,75 @@
<template>
<setting-item-box name="启用数据" :alone="true">
<n-space justify="start">
<n-switch v-model:value="categoryBrandCountTable.enable" />
</n-space>
</setting-item-box>
<setting-item-box name="数据源" :alone="true">
<n-select v-model:value="categoryBrandCountTable.currentSource" :options="multipleSourceOptions" size="small"/>
</setting-item-box>
</template>
<script lang="ts" setup>
import { watch, reactive, computed } from 'vue'
import type { Ref } from 'vue'
import { SettingItemBox } from '@/components/Pages/ChartItemSetting'
import { useTargetData } from '../../hooks/useTargetData.hook'
import { icon } from '@/plugins/icon'
import { commonDataType, CategoryBrandCountTableType } from '@/store/modules/chartEditStore/chartEditStore.d'
const { CloseIcon, AddIcon } = icon.ionicons5
const { targetData } = useTargetData() as { targetData: Ref<{ commonData: commonDataType, id: string }> }
const categoryBrandCountTable: Ref<CategoryBrandCountTableType> = computed(() => targetData.value.commonData.categoryBrandCountTable)
const multipleSourceOptions = [
{
label: '配电设备',
value:'device'
},
{
label: 'IT设备',
value:'IT'
},
]
// type computeIdsItemType = {
// id: string,
// value: string
// }
// const computeIds: computeIdsItemType[] = reactive([])
// watch(() => [targetData.value.id, pointTable.value], () => {
// if(!pointTable.value.ids.length) targetData.value.commonData.pointTable.ids.push('')
// let arr = pointTable.value.ids.map((item, i) => {
// return {
// id: `${targetData.value.id}_${i}`,
// value: item
// }
// })
// computeIds.splice(0, computeIds.length, ...arr)
// }, {
// deep: true,
// immediate: true
// })
// const handleChange = (v: string, i: number) => {
// targetData.value.commonData.pointTable.ids[i] = v
// }
// const handleAdd = () => {
// targetData.value.commonData.pointTable.ids.push('')
// }
// const handleDelete = (i: number) => {
// targetData.value.commonData.pointTable.ids.splice(i, 1)
// }
</script>
<style lang="scss" scoped>
</style>

View File

@ -150,6 +150,16 @@ export const sourceOptions: sourceOptionsItemType[] = [
value: CurrentSourceEnum.DEVICECLASS, value: CurrentSourceEnum.DEVICECLASS,
type: optionTypeEnum.MULTIPLE, type: optionTypeEnum.MULTIPLE,
}, },
{
label: '分类统计',
value: CurrentSourceEnum.ASSETSCLASS,
type: optionTypeEnum.MULTIPLE,
},
{
label: '区域设备个数',
value: CurrentSourceEnum.AREADEVCOUNT,
type: optionTypeEnum.MULTIPLE,
},
{ {
label: '当月告警分类统计', label: '当月告警分类统计',
value: CurrentSourceEnum.MONTHALARMCLASS, value: CurrentSourceEnum.MONTHALARMCLASS,
@ -160,6 +170,11 @@ export const sourceOptions: sourceOptionsItemType[] = [
value: CurrentSourceEnum.POINTTABLE, value: CurrentSourceEnum.POINTTABLE,
type: optionTypeEnum.MULTIPLE, type: optionTypeEnum.MULTIPLE,
}, },
{
label: '分类品牌表格值',
value: CurrentSourceEnum.CATEGORYBRANDCOUNTTABLE,
type: optionTypeEnum.MULTIPLE,
},
{ {
label: '手动输入值', label: '手动输入值',
value: CurrentSourceEnum.MANUALINPUT, value: CurrentSourceEnum.MANUALINPUT,

View File

@ -10,8 +10,11 @@
<PointRealTime v-else-if="matchComponent(CurrentSourceEnum.POINTREALTIME)"/> <PointRealTime v-else-if="matchComponent(CurrentSourceEnum.POINTREALTIME)"/>
<MonthAlarmClass v-else-if="matchComponent(CurrentSourceEnum.MONTHALARMCLASS)"/> <MonthAlarmClass v-else-if="matchComponent(CurrentSourceEnum.MONTHALARMCLASS)"/>
<DeviceClass v-else-if="matchComponent(CurrentSourceEnum.DEVICECLASS)"/> <DeviceClass v-else-if="matchComponent(CurrentSourceEnum.DEVICECLASS)"/>
<AssetsClass v-else-if="matchComponent(CurrentSourceEnum.ASSETSCLASS)"/>
<PointTable v-else-if="matchComponent(CurrentSourceEnum.POINTTABLE)"/> <PointTable v-else-if="matchComponent(CurrentSourceEnum.POINTTABLE)"/>
<CategoryBrandCountTable v-else-if="matchComponent(CurrentSourceEnum.CATEGORYBRANDCOUNTTABLE)"/>
<ManualInput v-else-if="matchComponent(CurrentSourceEnum.MANUALINPUT)"/> <ManualInput v-else-if="matchComponent(CurrentSourceEnum.MANUALINPUT)"/>
</template> </template>
<template v-else-if="IsCommonSingle"> <template v-else-if="IsCommonSingle">
<setting-item-box name="数据源" :alone="true"> <setting-item-box name="数据源" :alone="true">
@ -69,8 +72,10 @@ import RecordValueHistory from './components/RecordValueHistory.vue'
import PointRealTime from './components/PointRealTime.vue' import PointRealTime from './components/PointRealTime.vue'
import SinglePoint from './components/SinglePoint.vue' import SinglePoint from './components/SinglePoint.vue'
import MonthAlarmClass from './components/MonthAlarmClass.vue' import MonthAlarmClass from './components/MonthAlarmClass.vue'
import AssetsClass from './components/AssetsClass.vue'
import DeviceClass from './components/DeviceClass.vue' import DeviceClass from './components/DeviceClass.vue'
import PointTable from './components/PointTable.vue' import PointTable from './components/PointTable.vue'
import CategoryBrandCountTable from './components/CategoryBrandCountTable.vue'
import ManualInput from './components/ManualInput.vue' import ManualInput from './components/ManualInput.vue'
import ManualInputSingle from './components/ManualInputSingle.vue' import ManualInputSingle from './components/ManualInputSingle.vue'
import NoParam from './components/NoParam.vue' import NoParam from './components/NoParam.vue'
@ -128,6 +133,7 @@ const multipleSourceOptions = sourceOptions.filter(_ => _.type === optionTypeEnu
const singleSourceOptions = sourceOptions.filter(_ => _.type === optionTypeEnum.SINGLE) const singleSourceOptions = sourceOptions.filter(_ => _.type === optionTypeEnum.SINGLE)
const matchComponent = (name: string) => { const matchComponent = (name: string) => {
console.log(name,'name---')
return targetData.value.commonData.currentSource === name return targetData.value.commonData.currentSource === name
} }
</script> </script>

View File

@ -10,7 +10,7 @@ export const useTargetData = () => {
const targetIndex = chartEditStore.fetchTargetIndex() const targetIndex = chartEditStore.fetchTargetIndex()
// 分组时 判断是不是分组里的组件 // 分组时 判断是不是分组里的组件
const selectId = chartEditStore.getTargetChart.selectId[0] const selectId = chartEditStore.getTargetChart.selectId[0]
if(list[targetIndex].isGroup && list[targetIndex].id !== selectId) { if(list[targetIndex]&&list[targetIndex].isGroup && list[targetIndex].id !== selectId) {
return list[targetIndex].groupList!.find(_ => _.id === selectId)! return list[targetIndex].groupList!.find(_ => _.id === selectId)!
} }
return list[targetIndex] return list[targetIndex]