大屏应用位置整合

This commit is contained in:
aixianling
2022-06-24 13:51:32 +08:00
parent 05db88644c
commit 8e04ec040a
14 changed files with 78 additions and 258 deletions

View File

@@ -6,32 +6,28 @@
<template slot="tabs">
<el-tabs v-model="currIndex">
<el-tab-pane v-for="(tab,i) in tabs" :key="i" :label="tab.label">
<component :urlPrefix="urlPrefix" :areaId="areaId" :ref="tab.name" v-if="currIndex == i" :is="tab.comp" @change="onChange" lazy :instance="instance" :dict="dict" :permissions="permissions" />
<component :urlPrefix="urlPrefix" :areaId="areaId" :ref="tab.name" v-if="currIndex == i" :is="tab.comp" @change="onChange" lazy :instance="instance"
:dict="dict" :permissions="permissions"/>
</el-tab-pane>
</el-tabs>
</template>
</ai-list>
<Add v-else-if="componentName === 'Add'" :urlPrefix="urlPrefix" :areaId="areaId" :params="params" :instance="instance" :dict="dict" :permissions="permissions" @change="onChange"></Add>
<SourceData v-else-if="componentName === 'SourceData'" :urlPrefix="urlPrefix" :params="params" :instance="instance" :dict="dict" :permissions="permissions" @change="onChange"></SourceData>
<Add v-else-if="componentName === 'Add'" :urlPrefix="urlPrefix" :areaId="areaId" :params="params" :instance="instance" :dict="dict" :permissions="permissions"
@change="onChange"></Add>
<SourceData v-else-if="componentName === 'SourceData'" :urlPrefix="urlPrefix" :params="params" :instance="instance" :dict="dict" :permissions="permissions"
@change="onChange"></SourceData>
</template>
<script>
import List from './components/List.vue'
import Add from './components/Add'
import SourceData from './components/SourceData'
import dvui from '../../../project/dvui/entries'
import Vue from "vue";
Vue.use(dvui)
export default {
name: 'AppDesigner' ,
name: 'AppDesigner',
label: '大屏设计',
components: {
List,
Add,
SourceData
},
components: {List, Add, SourceData},
props: {
instance: Function,
@@ -84,8 +80,6 @@ export default {
}
}
},
created() {
}
}
</script>

View File

@@ -33,14 +33,14 @@
</template>
<template #content>
<ai-table
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
style="margin-top: 6px;"
:border="true"
row-key="id"
:isShowPagination="false"
@getList="() => {}">
:tableData="tableData"
:col-configs="colConfigs"
:total="total"
style="margin-top: 6px;"
:border="true"
row-key="id"
:isShowPagination="false"
@getList="() => {}">
<el-table-column slot="options" width="160px" fixed="right" label="操作" align="center">
<template slot-scope="{ row, column, $index }">
<div class="table-options">
@@ -55,22 +55,22 @@
</ai-card>
</el-form>
<Layout
v-if="isShowLayout"
:instance="instance"
:dict="dict"
:params="query"
@change="onChange"
:urlPrefix="urlPrefix"
:theme="config.theme"
@close="isShowLayout = false">
v-if="isShowLayout"
:instance="instance"
:dict="dict"
:params="query"
@change="onChange"
:urlPrefix="urlPrefix"
:theme="config.theme"
@close="isShowLayout = false">
</Layout>
<ai-dv-wrapper :views="[{label: '返回'}]" :theme="config.theme" @change="screenId = false" v-if="screenId" :title="form.name">
<AiDvBackground
:theme="config.theme"
v-if="config.length || config.theme === '1'"
:src="config.theme === '1' ? 'https://cdn.cunwuyun.cn/dvcp/dv/img/dj-bg.png' : config.backgroundImage[0].url">
</AiDvBackground>
<AppGigscreenViewer :urlPrefix="urlPrefix" :instance="instance" :dict="dict" :id="screenId"></AppGigscreenViewer>
<ai-dv-background
:theme="config.theme"
v-if="config.length || config.theme === '1'"
:src="config.theme === '1' ? 'https://cdn.cunwuyun.cn/dvcp/dv/img/dj-bg.png' : config.backgroundImage[0].url">
</ai-dv-background>
<app-gigscreen-viewer :urlPrefix="urlPrefix" :instance="instance" :dict="dict" :id="screenId"/>
</ai-dv-wrapper>
<ai-dialog :visible.sync="dialog" title="定制大屏" @closed="custom={}" @onConfirm="handleCustomizedDV">
<el-form ref="CustomDVFrom" size="small" :model="custom" :rules="rules" label-width="80px">
@@ -94,29 +94,22 @@
</template>
<script>
import AppGigscreenViewer from '../../viewer/AppGigscreenViewer'
import Layout from './Layout.vue'
import Sortable from 'sortablejs'
import AppGigscreenViewer from "../../viewer/AppGigscreenViewer";
export default {
name: 'Add',
props: {
instance: Function,
dict: Object,
params: Object,
urlPrefix: String
},
inject: {
home:{default: ''}
home: {default: ''}
},
components: {
Layout,
AppGigscreenViewer
},
components: {AppGigscreenViewer, Layout},
data() {
return {
info: {},
@@ -158,7 +151,7 @@ export default {
}
},
mounted () {
mounted() {
},
@@ -194,7 +187,7 @@ export default {
const tbody = document.querySelector('.el-table__body-wrapper tbody')
const _this = this
Sortable.create(tbody, {
onEnd({ newIndex, oldIndex }) {
onEnd({newIndex, oldIndex}) {
const currRow = _this.tableData.splice(oldIndex, 1)[0]
_this.tableData.splice(newIndex, 0, currRow)
}

View File

@@ -1,92 +0,0 @@
<template>
<div class="swiper">
<el-carousel height="100%" indicator-position="none">
<el-carousel-item v-for="(item, index) in data" :key="index">
<img :src="item.img">
<div class="swiper-content" v-if="item.title">
<h2>{{ item.title }}</h2>
<p>{{ item.content }}</p>
</div>
</el-carousel-item>
</el-carousel>
</div>
</template>
<script>
export default {
name: 'AiSwiper',
props: {
data: {
type: Array,
default: () => []
},
width: {
type: String,
default: '100%'
},
heigth: {
type: String,
default: '100%'
}
},
data () {
return {
}
},
mounted () {
},
methods: {
}
}
</script>
<style lang="scss" scoped>
.swiper {
width: 100%;
height: 100%;
padding: 20px 0 0;
::v-deep .el-carousel {
height: 100%;
}
img {
width: 100%;
height: 100%;
}
.swiper-content {
position: absolute;
bottom: 0;
left: 0;
z-index: 1;
width: 100%;
padding: 10px;
text-align: center;
background: linear-gradient(180deg, rgba(0, 0, 0, 0.1) 0%, #000000 100%);
h2 {
margin-bottom: 4px;
color: #fff;
text-align: center;
font-size: 18px;
}
p {
line-height: 22px;
white-space: pre-line;
color: #B6DFFF;
font-size: 14px;
text-align: center;
}
}
}
</style>

View File

@@ -91,7 +91,7 @@
<div class="coordinate-top"></div>
<div class="coordinate-label">{{ item.left }}, {{ item.top }}</div>
</div>
<RenderElement :data="item" :theme="dashboard.theme" :index="index"></RenderElement>
<ai-dv-render :data="item" :theme="dashboard.theme" :index="index"/>
</vue-draggable-resizable>
</div>
</ai-dv-wrapper>
@@ -335,12 +335,12 @@
</ai-dialog>
<ai-dialog :visible.sync="isShowAddImg" width="580px" append-to-body title="添加素材" @closed="form.images = []" @onConfirm="onImageConfirm">
<ai-uploader
:instance="instance"
v-model="form.images"
fileType="file"
:maxSize="100"
url="/admin/file/add-unlimited"
:limit="9">
:instance="instance"
v-model="form.images"
fileType="file"
:maxSize="100"
url="/admin/file/add-unlimited"
:limit="9">
</ai-uploader>
</ai-dialog>
</div>
@@ -353,7 +353,6 @@ import VueRulerTool from 'vue-ruler-tool'
import VueDraggableResizable from 'vue-draggable-resizable'
import 'vue-draggable-resizable/dist/VueDraggableResizable.css'
import DataConfig from './form/DataConfig.vue'
import RenderElement from './RenderElement'
export default {
props: {
@@ -366,7 +365,7 @@ export default {
data() {
return {
colConfigs: [
{ prop: 'url', label: '图片链接', showOverflowTooltip: false },
{prop: 'url', label: '图片链接', showOverflowTooltip: false},
// {slot: 'img', label: '图片'}
],
form: {
@@ -416,7 +415,6 @@ export default {
},
components: {
RenderElement,
DataConfig,
VueRulerTool,
VueDraggableResizable,

View File

@@ -1,350 +0,0 @@
<template>
<div class="render-element" style="width: 100%; height: 100%;">
<ai-dv-display v-if="data.type === 'display'" :title="data.title" :list="values"></ai-dv-display>
<ai-dv-panel
style="height: 100%; width: 100%;"
v-if="data.type !== 'display'"
:title="data.title"
:border="data.border || ''">
<AiDvSummary v-if="data.type === 'summary'" :summaryTitle="data.summaryTitle" :key="`summary${index}`" :type="data.display" :data="values"/>
<AiSwiper v-else-if="data.type === 'swiper'" :heigth="'100%'" :data="values"/>
<dv-scroll-board
v-if="data.type === '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
v-else-if="data.type === 'barChart1'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:theme="theme"
:data="values"
:ops="data.config"/>
<ai-echart
v-else-if="data.type === 'barChart2'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:theme="theme"
:key="`chart${index}`"
:data="values"
:ops="data.config"/>
<ai-echart
v-else-if="data.type === 'barChart3'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:theme="theme"
:data="values"
:ops="data.config"/>
<ai-echart
v-else-if="data.type === 'barChart5'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:theme="theme"
:data="values"
:ops="data.config"/>
<ai-echart
v-else-if="data.type === 'barChart7'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:theme="theme"
:data="values"
:ops="data.config"/>
<ai-echart
v-else-if="data.type === 'barChart8'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:theme="theme"
:data="values"
:ops="data.config"/>
<ai-echart
v-else-if="data.type === 'barChart9'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:theme="theme"
:data="values"
:ops="data.config"/>
<ai-echart
v-else-if="data.type === 'lineChart1'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:theme="theme"
:data="values"
:ops="lineChart1"/>
<ai-echart
v-else-if="data.type === 'lineChart2'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:theme="theme"
:data="values"
:ops="lineChart2"/>
<ai-echart
v-else-if="data.type === 'lineChart3'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:theme="theme"
:data="values"
:ops="data.config"/>
<ai-echart
v-else-if="data.type === 'lineChart4'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:theme="theme"
:data="values"
:ops="data.config"/>
<ai-echart
v-else-if="data.type === 'lineChart5'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:theme="theme"
:data="values"
:ops="lineChart5"/>
<ai-echart
v-else-if="data.type === 'pieChart'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:theme="theme"
:data="values"
:ops="pieChart"/>
<ai-echart
v-else-if="data.type === 'pieChart1'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:theme="theme"
:data="values"
:ops="pieChart1"/>
<ai-echart
v-else-if="data.type === 'pieChart3'"
style="height: 100%; width: 100%;"
:ref="'chart' + index"
:key="`chart${index}`"
:theme="theme"
:data="values"
:ops="pieChart3"/>
<ai-map :markers="values" v-else-if="data.type=='map'" :mask="data.mask === '1'" :areaId="data.areaId || user.info.areaId"
:map-style="`amap://styles/${data.mapStyle}`" :pulseLines="data.pulseLines==1" :map.sync="map" :lib.sync="lib"/>
<ai-monitor :src="data.src" v-else-if="data.type === 'monitor'" :type="data.monitorType"></ai-monitor>
<video style="width: 100%; height: 100%; object-fit: fill;" loop :src="data.src" autoplay v-else-if="data.type === 'video'"></video>
<AiDvPartyOrg style="width: 100%; height: 100%;" v-else-if="data.type === 'partyOrg'" :instance="instance"></AiDvPartyOrg>
</ai-dv-panel>
</div>
</template>
<script>
import {mapState} from 'vuex'
import AiSwiper from './AiSwiper.vue'
import pieChart from 'dvcp-dv-ui/components/AiEchart/template/pie/pieChart2'
import pieChart1 from 'dvcp-dv-ui/components/AiEchart/template/pie/pieChart1'
import pieChart3 from 'dvcp-dv-ui/components/AiEchart/template/pie/pieChart3'
import lineChart1 from 'dvcp-dv-ui/components/AiEchart/template/line/lineChart1'
import lineChart2 from 'dvcp-dv-ui/components/AiEchart/template/line/lineChart2'
import lineChart5 from 'dvcp-dv-ui/components/AiEchart/template/line/lineChart5'
export default {
name: 'RenderElement',
props: ['data', 'index', 'theme', 'instance'],
components: {
AiSwiper
},
data() {
return {
lineChart1,
lineChart2,
lineChart5,
pieChart,
pieChart1,
pieChart3,
map: null,
lib: null
}
},
computed: {
...mapState(['user']),
values () {
if (!this.data) {
return []
}
return this.data.type ==='map' ? this.data[this.data.dataType].map(e => {
return {...e, lng: e['经度'], lat: e['纬度'], label: e['地区名称']}
}) : this.data[this.data.dataType]
}
},
methods: {
formatTable(data, isShowIndex, rowNum) {
if (!data.length) {
return {
header: [],
data: []
}
}
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]
})
}),
headerBGC: 'transparent',
evenRowBGC: 'transparent',
oddRowBGC: 'rgba(0, 133, 255, 0.2)',
headerHeight: 42,
rowNum: rowNum || 7,
index: isShowIndex === '1',
waitTime: 8000,
carousel: 'page',
indexHeader: '排名',
align: ['center', 'center', 'center', 'center', 'center']
}
},
handleMapClick(count = 0) {
let {lib: AMap, map} = this
if (AMap) {
let infoWin = new AMap.InfoWindow({content: ""})
map.clearMap()
let markers = this.values.filter(e=>e.lng).map(e => {
return new AMap.Marker({
map,
label: e.label,
icon: e.icon,
position: [e.lng, e.lat]
}).on('click', ({target}) => {
map.clearInfoWindow()
markers?.map(m => m.getIcon() == e.selectedIcon && m.setIcon(e.icon))
target.setIcon(e.selectedIcon)
infoWin.setContent([
`<div class="infoWin">`,
`<b>${e.label}</b>`,
`<div>累计成交金额:${e['累计成交金额(万)']}万元</div>`,
`<div>金融产品:${e['金融产品(万)']}万元</div>`,
`<div>融资需求:${e['融资需求(万)']}万元</div>`,
'</div>'
].join(''))
infoWin.open(map, [e.lng, e.lat])
})
})
map.setFitView(markers)
} else if (count < 10) {
console.log("正在加载...%s", count)
setTimeout(() => this.handleMapClick(++count), 1000)
}
}
},
mounted() {
if (this.data.type == 'map') {
this.handleMapClick()
}
}
}
</script>
<style lang="scss" scoped>
.render-element {
::v-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: 0px 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;
}
}
}
::v-deep.amap-info-contentContainer {
.amap-info-content {
background: #0A3257;
border: 1px solid #7BE5FF;
padding: 16px;
font-family: PingFangSC-Semibold, PingFang SC;
.infoWin {
& > b {
display: block;
font-size: 18px;
font-weight: 600;
color: #FFFFFF;
margin-bottom: 13px;
}
& > div {
font-size: 16px;
font-weight: 400;
color: #7BE5FF;
& + div {
margin-top: 8px;
}
}
}
}
.amap-info-sharp {
border-top-color: #0A3257;
&:after {
border-top-color: #7BE5FF;
filter: none;
}
}
}
}
</style>

View File

@@ -1,88 +0,0 @@
<template>
<section class="AiDataPanel">
<b class="item-title" v-text="label"/>
<div class="num-bg">
<span ref="num" class="num" v-text="num"/>
</div>
</section>
</template>
<script>
import {gsap} from 'gsap'
export default {
name: "AiDataPanel",
props: {
label: {default: "标题"},
value: {default: 0}
},
data() {
return {
num: 0
}
},
methods: {
animation() {
let demo = {num: Math.max(this.value - 30, 0)}
gsap.to(demo, 1, {
num: this.value, onUpdate: () => {
this.num = demo.num?.toFixed(0)
}
})
}
},
mounted() {
this.animation()
}
}
</script>
<style lang="scss" scoped>
.AiDataPanel {
flex: 1;
width: 172px;
height: 160px;
display: flex;
flex-direction: column;
align-items: center;
background: #000;
& + .AiDataPanel {
margin-left: 16px;
}
.item-title {
font-size: 24px;
line-height: 32px;
background-image: -webkit-linear-gradient(bottom, #35BEFF, #EBF9FF, #FFFFFF);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin-top: 30px;
}
.num-bg {
width: 100%;
height: 160px;
background-image: url(https://cdn.cunwuyun.cn/dvcp/dv/dianjiang/number-bg.png);
background-size: 100% 100%;
position: relative;
margin-top: -76px;
.num {
position: absolute;
left: 0;
bottom: 30px;
width: 100%;
text-align: center;
height: 50px;
font-size: 40px;
font-family: D-DIN-Bold, D-DIN;
font-weight: bold;
line-height: 54px;
background-image: -webkit-linear-gradient(bottom, #35BEFF, #EBF9FF, #FFFFFF);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
}
</style>

View File

@@ -1,30 +0,0 @@
<template>
<section class="AiStaData">
<ai-data-panel v-for="op in data" :key="op[key]"
:label="op[label]" :value="op[key]"/>
</section>
</template>
<script>
import AiDataPanel from "./AiDataPanel";
export default {
name: "AiStaData",
components: {AiDataPanel},
props: {
data: {default: () => []},
key: {default: "id"},
label: {default: "label"},
}
}
</script>
<style lang="scss" scoped>
.AiStaData {
width: 100%;
display: flex;
align-items: center;
flex-wrap: wrap;
justify-content: center;
}
</style>

View File

@@ -1,5 +1,5 @@
<template>
<div class="AppGigscreenViewer">
<section class="AppGigscreenViewer">
<div v-if="!component">
<div
class="component-item"
@@ -14,21 +14,18 @@
}"
v-for="(item, index) in componentList"
:key="index">
<RenderElement :instance="instance" :data="item" :index="index" :theme="dashboard.theme"></RenderElement>
<ai-dv-render :instance="instance" :data="item" :index="index" :theme="dashboard.theme"/>
</div>
</div>
<components v-else :is="component" :dict="dict" :instance="instance" :nav="meta"/>
</div>
</section>
</template>
<script>
import RenderElement from '../designer/components/RenderElement'
export default {
name: 'AppGigscreenViewer',
label: '大屏预览',
props: {
instance: Function,
dict: Object,
@@ -38,17 +35,11 @@ export default {
default: '/app'
}
},
watch: {
id(v) {
this.getInfo(v)
}
},
components: {
RenderElement
},
data() {
return {
component: '',
@@ -65,32 +56,25 @@ export default {
meta: {}
}
},
created() {
this.getInfo(this.id)
// this.scale = document.body.clientWidth / 1920
},
mounted() {
this.$nextTick(() => {
let content = document.querySelector('#dv-full-screen-container')
if (content) {
const transform = content.style.transform
const scale = transform.replace('scale', '').replace('(', '').replace(')', '')
if (scale == 1) {
this.scale = document.body.clientWidth / 1920
}
}
})
},
methods: {
getInfo(id) {
this.component = null
this.instance.post(`${this.urlPrefix}/appdiylargescreen/queryLargeScreenDetailById?id=${id}`).then(res => {
id && this.instance.post(`${this.urlPrefix}/appdiylargescreen/queryLargeScreenDetailById?id=${id}`).then(res => {
if (res?.data) {
const config = JSON.parse(res.data.config)
if (config.custom) {
@@ -123,7 +107,6 @@ export default {
}
})
},
getSourceData(item, index) {
const api = item.dataType === 'apiData' ? item.api : `${this.urlPrefix}/appdiylargescreen/statisticsByLsid?id=${item.sourceDataId}`
this.instance.post(api).then(res => {