414 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			414 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <template>
 | |
|   <div class="AiDvRender" style="width: 100%; height: 100%;">
 | |
|     <ai-dv-display v-if="currentType === 'display'" :title="data.title" :list="values"/>
 | |
|     <ai-dv-panel
 | |
|         style="height: 100%; width: 100%;"
 | |
|         v-if="currentType !== 'display'"
 | |
|         :padding="data.padding"
 | |
|         :title="data.title"
 | |
|         :theme="theme"
 | |
|         :border="data.border || ''">
 | |
|       <AiDvSummary v-if="currentType === 'summary'" :theme="theme" :summaryTitle="data.summaryTitle"
 | |
|                    :key="`summary${index}`" :type="data.display"
 | |
|                    :data="values"/>
 | |
|       <AiSwiper v-else-if="currentType === 'swiper'" :heigth="'100%'" :data="values" :dotIndicator="data.dotIndicator"/>
 | |
|       <dv-scroll-board
 | |
|           v-if="currentType === 'table'"
 | |
|           :class="'dvScrollBoard' + theme"
 | |
|           :config="formatTable(values, data.isShowIndex, data.rowNum)"
 | |
|           :key="data.height"
 | |
|           :theme="theme"
 | |
|           :style="{height: data.height + 'px', width: '100%'}"/>
 | |
|       <ai-echart-v2 v-else-if="/Chart/.test(currentType)"
 | |
|                     style="height: 100%; width: 100%;"
 | |
|                     :ref="'chart' + index"
 | |
|                     :key="`chart-${index}`"
 | |
|                     :theme="theme"
 | |
|                     :data="values"
 | |
|                     :tpl="data.config"
 | |
|                     :ops="data.echartOps"/>
 | |
|       <AiDvTable
 | |
|           v-else-if="currentType === 'AiDvTable'"
 | |
|           :heigth="'100%'"
 | |
|           :stripe="data.stripe"
 | |
|           :theme="theme"
 | |
|           :isShowIndex="data.isShowIndex"
 | |
|           :config="dvTableConfig"
 | |
|           :data="values" :simple="data.simple==1">
 | |
|       </AiDvTable>
 | |
|       <AiRanking
 | |
|           v-else-if="currentType === 'AiRanking'"
 | |
|           :theme="theme"
 | |
|           :heigth="'100%'"
 | |
|           :subType="data.subType"
 | |
|           :data="values">
 | |
|       </AiRanking>
 | |
|       <AiDvMap v-else-if="currentType === 'AiDvMap'" style="width: 100%; height: 100%" :theme="theme" :geo-json="data.geoJson" :data="values"/>
 | |
|       <ai-map v-else-if="currentType=='map'" :mask="data.mask === '1'" :areaId="data.areaId" :is3d="data.is3d==1"
 | |
|               :is3dAround="data.is3dAround === '1'"
 | |
|               :map-style="`amap://styles/${data.mapStyle}`" :pulseLines="data.pulseLines==1" :map.sync="map"
 | |
|               :lib.sync="lib"
 | |
|               :onlyShowArea="data.limitArea==1" :satellite="data.layers=='satellite'">
 | |
|         <div class="mapInfoWin" v-show="mapDialog">
 | |
|           <div class="corn" v-for="i in 4" :key="i"/>
 | |
|           <div ref="mapInfoWin"/>
 | |
|         </div>
 | |
|         <div v-if="data.showPingchangMapLegend" class="pingchangMapLegend"/>
 | |
|       </ai-map>
 | |
|       <ai-monitor :src="data.src" v-else-if="currentType === 'monitor'" :type="data.monitorType"/>
 | |
|       <ai-monitor-carousel :list="data.list" v-else-if="currentType === 'monitorCarousel'"/>
 | |
|       <img v-else-if="currentType=='img'" :src="data.src" alt="" style="width: 100%; height: 100%; object-fit: fill;"/>
 | |
|       <video style="width: 100%; height: 100%; object-fit: fill;" loop :src="data.src" autoplay
 | |
|              v-else-if="currentType === 'video'"/>
 | |
|       <AiDvPartyOrg style="width: 100%; height: 100%;" v-else-if="currentType === 'partyOrg'" :instance="instance"/>
 | |
|       <!-- <ai-sprite v-else-if="/building/.test(currentType)" v-bind="data" is3D @init="mods[currentType]"/> -->
 | |
|       <ai-dv-plot v-else-if="currentType=='plot'" :options="data.charts" :instance="instance"/>
 | |
|       <ai-assist v-else-if="currentType=='aiAssist'"/>
 | |
|       <ai-linkage-map v-else-if="currentType=='linkageMap'" :config="data" :instance="instance"/>
 | |
|       <template v-else-if="currentType=='tabs'">
 | |
|         <div slot="right" class="flex">
 | |
|           <div class="tabItem" v-for="(tab,i) in data.tabs" :key="i" v-text="tab.label" @click="activeTab=i.toString()" :class="{active:activeTab==i}"/>
 | |
|         </div>
 | |
|         <ai-dv-tabs v-model="activeTab" :config="data" :values="values"/>
 | |
|       </template>
 | |
|     </ai-dv-panel>
 | |
|   </div>
 | |
| </template>
 | |
| 
 | |
| <script>
 | |
| import {scrollBoard} from '@jiaminghi/data-view'
 | |
| import Vue from "vue"
 | |
| import {mapState} from 'vuex'
 | |
| import AiDvMap from "./AiDvMap";
 | |
| import AiMonitor from "./AiMonitor/AiMonitor";
 | |
| import AiSwiper from './AiSwiper'
 | |
| import AiDvDisplay from "./layout/AiDvDisplay/AiDvDisplay";
 | |
| import AiDvPanel from "./layout/AiDvPanel/AiDvPanel";
 | |
| import AiDvSummary from "./layout/AiDvSummary/AiDvSummary";
 | |
| import AiDvPlot from "./layout/AiDvPlot/AiDvPlot";
 | |
| import AiAssist from "./AiAssist";
 | |
| import AiMonitorCarousel from "./AiMonitorCarousel";
 | |
| import AiLinkageMap from "./AiLinkageMap";
 | |
| import AiDvTabs from "./AiDvTabs";
 | |
| 
 | |
| Vue.use(scrollBoard)
 | |
| 
 | |
| export default {
 | |
|   name: 'AiDvRender',
 | |
|   props: ['data', 'index', 'theme', 'instance'],
 | |
|   components: {
 | |
|     AiDvTabs,
 | |
|     AiLinkageMap,
 | |
|     AiMonitorCarousel,
 | |
|     AiAssist,
 | |
|     AiDvPlot,
 | |
|     // AiSprite,
 | |
|     AiDvSummary,
 | |
|     AiDvDisplay,
 | |
|     AiDvPanel,
 | |
|     AiMonitor,
 | |
|     AiSwiper,
 | |
|     AiDvMap
 | |
|   },
 | |
|   data() {
 | |
|     return {
 | |
|       // mods,
 | |
|       map: null,
 | |
|       lib: null,
 | |
|       timer: null,
 | |
|       dvTableConfig: [],
 | |
|       mapDialog: false,
 | |
|       activeTab: '0'
 | |
|     }
 | |
|   },
 | |
|   computed: {
 | |
|     ...mapState(['user']),
 | |
|     values: v => v.data?.[v.data?.dataType] || [],
 | |
|     currentType: v => v.data.type
 | |
|   },
 | |
|   watch: {
 | |
|     values: {
 | |
|       immediate: true,
 | |
|       deep: true, handler() {
 | |
|         if (this.currentType == 'map') {
 | |
|           this.renderMap()
 | |
|         } else if (this.currentType === 'tabs') {
 | |
|           //数据驱动内容生成,新增tab中的内容由设置的数据来生成
 | |
|           const meta = this.$copy(this.data.tabs)
 | |
|           this.data.tabs = Object.entries(this.values).map(([label, v]) => {
 | |
|             const tab = meta.find(e => e.label === label)
 | |
|             const comps = []
 | |
|             if (Array.isArray(v.data)) {
 | |
|               const origin = tab.comps?.[0] || {}
 | |
|               delete origin.comps
 | |
|               comps.push({...origin, label: "内容"})
 | |
|             } else {
 | |
|               Object.keys(v.data).map(name => {
 | |
|                 const layer = tab.comps.find(e => e.label === name)
 | |
|                 comps.push({label: name, ...layer})
 | |
|               })
 | |
|             }
 | |
|             return {label, comps}
 | |
|           })
 | |
|         } else if (this.currentType === 'AiDvTable') {
 | |
|           this.dvTableConfig = this.data[this.data.dataType].map((v, i) => {
 | |
|             return {
 | |
|               color: this.data.config?.[i]?.color || '',
 | |
|               width: this.data.config?.[i]?.width || '',
 | |
|               align: this.data.config?.[i]?.align || '',
 | |
|             }
 | |
|           })
 | |
|           this.data.config = this.dvTableConfig
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   },
 | |
|   methods: {
 | |
|     formatTable(data, isShowIndex, rowNum) {
 | |
|       const tableStyle = {
 | |
|         headerBGC: 'transparent',
 | |
|         evenRowBGC: 'transparent',
 | |
|         oddRowBGC: 'rgba(0, 133, 255, 0.2)',
 | |
|         headerHeight: 42,
 | |
|         align: 'center'
 | |
|       }
 | |
|       if (!data.length) {
 | |
|         return {
 | |
|           header: [],
 | |
|           data: []
 | |
|         }
 | |
|       }
 | |
|       if (this.data.tableConfig) {
 | |
|         const {x, y} = this.data.tableConfig, dataMap = {}
 | |
|         const header = [...new Set(Object.entries(data.find(e => e.row == x) || null)?.filter(e => e[0] != 'row').map(e => e[1]) || [])],
 | |
|             rows = [...new Set(Object.entries(data.find(e => e.row == y) || null)?.filter(e => e[0] != 'row').map(e => e[1]) || [])]
 | |
|         data.map(e => Object.keys(e).map(k => k != 'row' && (dataMap[k] = (dataMap[k] || "") + "#" + e[k])))
 | |
|         const tableData = Object.values(dataMap).map(e => e.split("#"))
 | |
|         return {
 | |
|           ...tableStyle,
 | |
|           header: ["", ...header],
 | |
|           data: rows.map(y => [y, ...header.map(x => {
 | |
|             return tableData.find(m => m.includes(x) && m.includes(y)).at(-1)
 | |
|           })])
 | |
|         }
 | |
|       }
 | |
|       let rows = []
 | |
|       const header = data.map(v => {
 | |
|         return v[Object.keys(v)[0]]
 | |
|       })
 | |
|       Object.keys(data[0]).forEach((item, index) => {
 | |
|         if (index !== 0) {
 | |
|           rows.push(item)
 | |
|         }
 | |
|       })
 | |
|       return {
 | |
|         header: header,
 | |
|         data: rows.map(item => {
 | |
|           return data.map(v => {
 | |
|             return v[item]
 | |
|           })
 | |
|         }),
 | |
|         ...tableStyle,
 | |
|         rowNum: rowNum || 7,
 | |
|         index: isShowIndex === '1',
 | |
|         waitTime: 8000,
 | |
|         carousel: 'page',
 | |
|         indexHeader: '排名',
 | |
|         align: ['center', 'center', 'center', 'center', 'center']
 | |
|       }
 | |
|     },
 | |
|     renderMap(count = 0) {
 | |
|       let {lib: AMap, map} = this
 | |
|       this.timer && clearInterval(this.timer)
 | |
|       if (AMap && map) {
 | |
|         map.clearMap()
 | |
|         const markers = Array.isArray(this.values) ? this.values : this.values.markers
 | |
|         const polylines = Array.isArray(this.values) ? [] : this.values.polylines || []
 | |
|         markers.map(e => ({lng: e['经度'], lat: e['纬度'], label: e['地区名称'], ...e})).filter(e => e.lng).map((e) => {
 | |
|           const {icon = "https://cdn.cunwuyun.cn/dvcp/h5/Location2.png"} = e
 | |
|           return new AMap.Marker({
 | |
|             map,
 | |
|             content: e.content || `<div class="marker ${this.data.alwaysShow ? 'showLabel' : ''}">
 | |
|                         <img src="${icon}"/>
 | |
|                         <span>${e.label}</span>
 | |
|                       </div>`,
 | |
|             position: [e.lng, e.lat]
 | |
|           }).on('click', () => {
 | |
|             this.mapDialog = true
 | |
|             this.$nextTick(() => {
 | |
|               this.$refs.mapInfoWin.innerHTML = e.infoWindowHtml || [`<div class="infoWin">`, `<b>${e.label}</b>`, '</div>'].join('')
 | |
|               map.setZoomAndCenter(16, [e.lng, e.lat])
 | |
|               map.setPitch(60)
 | |
|             })
 | |
|           })
 | |
|         })
 | |
|         polylines.filter(e => e.path?.length > 0)?.map(e => new AMap.Polyline({
 | |
|           map, strokeColor: "#00FFAE", ...e, path: e.path.map(p => new AMap.LngLat(p[1], p[0]))
 | |
|         }))
 | |
|         map.setFitView()
 | |
|         const center = map.getCenter()
 | |
|         const zoom = map.getZoom()
 | |
|         map.on('click', () => {
 | |
|           map.setZoomAndCenter(zoom, center)
 | |
|           map.setPitch(0)
 | |
|           this.mapDialog = false
 | |
|         })
 | |
|         this.data.is3d > 0 && map.setPitch(65)
 | |
|         if (this.data.is3dAround == 1) {
 | |
|           this.timer = setInterval(() => map.setRotation(360, false, 16000))
 | |
|         }
 | |
|       } else if (count < 10) {
 | |
|         console.log("正在加载...%s", count)
 | |
|         setTimeout(() => this.renderMap(++count), 1000)
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| </script>
 | |
| 
 | |
| <style lang="scss" scoped>
 | |
| .AiDvRender {
 | |
|   :deep(.dvScrollBoard1) {
 | |
| 
 | |
|     .header {
 | |
|       background: rgba(0, 0, 0, 0.1) !important;
 | |
| 
 | |
|       .header-item {
 | |
|         color: #FFBB73 !important;
 | |
|         font-size: 16px !important;
 | |
|         font-weight: 600;
 | |
|       }
 | |
|     }
 | |
| 
 | |
| 
 | |
|     .rows {
 | |
|       font-size: 16px;
 | |
|       font-weight: 600;
 | |
|       color: #FFFFFF;
 | |
|       line-height: 21px;
 | |
|       text-shadow: 0 2px 4px rgba(117, 9, 9, 0.5);
 | |
|       background: linear-gradient(180deg, #FFF6C7 0%, #FF9A02 100%);
 | |
|       -webkit-background-clip: text;
 | |
|       -webkit-text-fill-color: transparent;
 | |
| 
 | |
|       & > div:nth-of-type(2n - 1) {
 | |
|         background-color: transparent !important;
 | |
|       }
 | |
| 
 | |
|       & > div:nth-of-type(2n) {
 | |
|         background-color: rgba(0, 0, 0, 0.1) !important;
 | |
|       }
 | |
| 
 | |
|       .index {
 | |
|         color: #fff;
 | |
|         text-shadow: none;
 | |
|         background: #BD4921 !important;
 | |
|         -webkit-background-clip: inherit;
 | |
|         -webkit-text-fill-color: #fff;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   :deep(.marker) {
 | |
|     position: relative;
 | |
| 
 | |
|     & > img {
 | |
|       width: 30px;
 | |
|       height: 30px;
 | |
|     }
 | |
| 
 | |
|     & > span {
 | |
|       display: none;
 | |
|     }
 | |
| 
 | |
|     &:hover > span, &.showLabel > span {
 | |
|       position: absolute;
 | |
|       left: 50%;
 | |
|       bottom: 0;
 | |
|       transform: translate(-50%, 100%);
 | |
|       display: block;
 | |
|       color: #fff;
 | |
|       font-size: 14px;
 | |
|       white-space: nowrap;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   :deep(.mapInfoWin) {
 | |
|     $borderColor: #245D8E;
 | |
|     $borderCorn: url("https://cdn.cunwuyun.cn/dvcp/dv/mapDialogCorn.png");
 | |
|     position: absolute;
 | |
|     left: 50%;
 | |
|     top: 40%;
 | |
|     transform: translate(-50%, -50%);
 | |
|     padding: 16px 20px;
 | |
|     max-width: 800px;
 | |
|     background-color: rgba(#0A1B3E, 0.8);
 | |
|     backdrop-filter: blur(6px);
 | |
|     border: 1px solid $borderColor;
 | |
|     box-shadow: 10px 10px 10px inset rgba($borderColor, .8), -10px -10px 10px inset rgba($borderColor, .8);
 | |
|     border-radius: 4px;
 | |
|     color: white;
 | |
| 
 | |
|     .corn {
 | |
|       $offset: -2px;
 | |
|       background-image: $borderCorn;
 | |
|       background-repeat: no-repeat;
 | |
|       position: absolute;
 | |
|       width: 14px;
 | |
|       height: 14px;
 | |
|       background-size: 100% 100%;
 | |
| 
 | |
|       &:nth-of-type(1) {
 | |
|         left: $offset;
 | |
|         top: $offset;
 | |
|         transform: rotate(-90deg);
 | |
|       }
 | |
| 
 | |
|       &:nth-of-type(2) {
 | |
|         right: $offset;
 | |
|         top: $offset;
 | |
|         transform: none;
 | |
|       }
 | |
| 
 | |
|       &:nth-of-type(3) {
 | |
|         right: $offset;
 | |
|         bottom: $offset;
 | |
|         transform: rotate(90deg);
 | |
|       }
 | |
| 
 | |
|       &:nth-of-type(4) {
 | |
|         left: $offset;
 | |
|         bottom: $offset;
 | |
|         transform: rotate(180deg);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   .pingchangMapLegend {
 | |
|     width: 189px;
 | |
|     height: 95px;
 | |
|     background: url("https://cdn.cunwuyun.cn/pingchang/pingchangMapLegend.png");
 | |
|     background-size: 100% 100%;
 | |
|     position: absolute;
 | |
|     bottom: 32px;
 | |
|     right: 32px;
 | |
|     backdrop-filter: blur(10px);
 | |
|   }
 | |
| 
 | |
|   .tabItem {
 | |
|     color: #1FBECC;
 | |
|     background: #1f9ecc29;
 | |
|     padding: 0 10px;
 | |
|     line-height: 20px;
 | |
|     margin-left: 4px;
 | |
|     font-size: 12px;
 | |
|     user-select: none;
 | |
| 
 | |
|     &.active {
 | |
|       border: 1px solid #20B4C5;
 | |
|       color: #02FEFF;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| </style>
 |