537 lines
17 KiB
Vue
537 lines
17 KiB
Vue
<template>
|
|
<div class="layout-config__group--wrapper">
|
|
<template v-if="options.type=='map'">
|
|
<ai-fold>
|
|
<div slot="title" class="flex w100">
|
|
<span class="layoutTitle fill">标记点设置</span>
|
|
<el-button type="text" icon="iconfont iconAdd" @click="handleMapMarker()">添加</el-button>
|
|
</div>
|
|
<config-item v-for="(item,i) in markers" :key="i" :label="item.label">
|
|
<el-input :value="[item.lat,item.lng].join(',')" readonly size="small"/>
|
|
<el-button type="text" icon="el-icon-edit" @click="handleMapMarker(item,i)"/>
|
|
<el-button type="text" icon="el-icon-delete" @click="removeMapMarker(i)"/>
|
|
</config-item>
|
|
</ai-fold>
|
|
<ai-fold title="标记点连线">
|
|
<ai-dialog-btn :modal="false" dialog-title="设置标记点连线" :customFooter="false" @onConfirm="savePolylines"
|
|
@open="handleMapPolylines">
|
|
<code-editor slot="btn" readonly :value="JSON.stringify(options.staticData.polylines, null, 2)" lang="json"
|
|
theme="github" width="100%" height="250" placeholder="测试默认值"/>
|
|
<el-button class="m-center" type="text" @click="handleMapPolylineDoc" :closable="false">
|
|
点击查看连线设置参考文档
|
|
</el-button>
|
|
<code-editor v-model="json" lang="json" theme="github" width="100%" height="440"/>
|
|
</ai-dialog-btn>
|
|
</ai-fold>
|
|
</template>
|
|
<template v-else-if="options.type=='plot'">
|
|
<ai-fold v-for="(chart,i) in options.charts" :key="i" :title="chart.title">
|
|
<config-item label="图表名">
|
|
<el-input size="small" v-model="chart.title"/>
|
|
</config-item>
|
|
<config-item label="图表模板">
|
|
<ai-select v-model="chart.chart" :select-list="charts"/>
|
|
</config-item>
|
|
<config-item label="数据类型">
|
|
<ai-select v-model="chart.dataType" placeholder="请选择数据类型" :select-list="dataTypes"/>
|
|
</config-item>
|
|
<config-item v-if="chart.dataType=='dynamicData'" label="数据源">
|
|
<ai-select v-model="chart.sourceDataId" placeholder="请选择数据源" :select-list="sourceData"
|
|
:prop="{label:'description'}"/>
|
|
</config-item>
|
|
<div class="layout-config__code" v-else-if="chart.dataType === 'staticData'">
|
|
<ai-dialog-btn :modal="false" dialog-title="编辑器" :customFooter="false"
|
|
@confirm="chart.data=JSON.parse(json)"
|
|
@open="json=JSON.stringify(chart.data||null)">
|
|
<code-editor slot="btn" readonly :value="JSON.stringify(chart.data)" lang="json" theme="github"
|
|
width="100%" height="250"/>
|
|
<code-editor v-model="json" lang="json" theme="github" width="100%" height="440"/>
|
|
</ai-dialog-btn>
|
|
</div>
|
|
<config-item label="接口地址" v-else-if="chart.dataType=='apiData'">
|
|
<el-input size="mini" v-model="chart.api"/>
|
|
</config-item>
|
|
</ai-fold>
|
|
<el-button type="text" icon="el-icon-plus" @click="options.charts.push({title:'新图表'})">添加图表</el-button>
|
|
</template>
|
|
<div class="layout-config__group" v-else-if="['hik','dahua'].includes(options.monitorType)">
|
|
<h2>基础设置</h2>
|
|
<config-item label="视频地址">
|
|
<el-input size="mini" v-model="options.src"/>
|
|
</config-item>
|
|
</div>
|
|
<div class="layout-config__group" v-else>
|
|
<h2>基础设置</h2>
|
|
<config-item label="数据类型">
|
|
<ai-select v-model="options.dataType" placeholder="请选择数据类型" :select-list="dataTypes"/>
|
|
</config-item>
|
|
<div class="layout-config__code" v-if="options.dataType === 'staticData'">
|
|
<ai-dialog-btn :modal="false" dialog-title="编辑器" :customFooter="false" @onConfirm="onConfirm"
|
|
@open="showEditor">
|
|
<code-editor slot="btn" readonly :value="JSON.stringify(options.staticData)" lang="json" theme="github"
|
|
width="100%" height="250"/>
|
|
<code-editor v-model="json" lang="json" theme="github" width="100%" height="440"/>
|
|
</ai-dialog-btn>
|
|
</div>
|
|
<config-item v-else-if="options.dataType === 'dynamicData'" label="数据源">
|
|
<ai-select v-model="options.sourceDataId" placeholder="请选择数据源" :select-list="sourceData"
|
|
:prop="{label:'description'}" @change="onDataChange"/>
|
|
</config-item>
|
|
<config-item label="接口地址" v-else>
|
|
<el-input size="mini" v-model="options.api" @change="onApiChange"/>
|
|
</config-item>
|
|
</div>
|
|
<div v-if="options.dataType!='staticData'&&options.type=='monitor'&&['cmcc','slw'].includes(options.monitorType)"
|
|
class="layout-config__group">
|
|
<h2>字段设置</h2>
|
|
<config-item label="监控视频">
|
|
<el-select size="mini" v-model="options.moniterId" placeholder="请选择监控视频" @change="onMoniterId">
|
|
<el-option
|
|
v-for="(item, index) in monitorList"
|
|
:key="index"
|
|
:label="item.name"
|
|
:value="item.id">
|
|
</el-option>
|
|
</el-select>
|
|
</config-item>
|
|
</div>
|
|
<div v-if="options.dataType!='staticData'&& keys.length &&!['table','monitor','map','plot'].includes(options.type)"
|
|
class="layout-config__group">
|
|
<h2>字段设置</h2>
|
|
<config-item label="X轴设置">
|
|
<el-select size="mini" v-model="options.dataX" placeholder="请选择X轴" @change="onChooseChange">
|
|
<el-option
|
|
v-for="(item, index) in keys"
|
|
:key="index"
|
|
:label="item"
|
|
:value="item">
|
|
</el-option>
|
|
</el-select>
|
|
</config-item>
|
|
<config-item label="Y轴设置">
|
|
<el-select size="mini" multiple :multiple-limit="options.type.indexOf('pie') > -1 ? 1 : 100"
|
|
v-model="options.dataY" collapse-tags placeholder="请选择Y轴"
|
|
@change="onChooseChange">
|
|
<el-option
|
|
v-for="(item, index) in keys"
|
|
:key="index"
|
|
:label="item"
|
|
:value="item">
|
|
</el-option>
|
|
</el-select>
|
|
</config-item>
|
|
</div>
|
|
<ai-dialog class="layout-config__edit" v-model="showMapEditor" title="设置地图标记点" append-to-body
|
|
@close="form={}" @confirm="saveMarker">
|
|
<el-form :model="form" size="small" ref="mapMarker" label-width="120px">
|
|
<el-form-item label="标记点名称" :rules="{required:true,message:'请填写标记点名称'}">
|
|
<el-input placeholder="用于地图上展示对标记点的文字标签" v-model="form.label" clearable/>
|
|
</el-form-item>
|
|
<el-form-item label="标记点图标">
|
|
<el-input placeholder="用于地图上展示对标记点的显示图标" v-model="form.icon" clearable/>
|
|
</el-form-item>
|
|
<div flex>
|
|
<el-form-item class="fill" label="经度" :rules="{required:true,message:'请填写标记点经度'}">
|
|
<el-input v-model="form.lng" clearable placeholder="小数点位保留至少6位数"/>
|
|
</el-form-item>
|
|
<el-form-item class="fill" label="纬度" :rules="{required:true,message:'请填写标记点纬度'}">
|
|
<el-input v-model="form.lat" clearable placeholder="小数点位保留至少6位数"/>
|
|
</el-form-item>
|
|
</div>
|
|
<el-form-item label="弹窗内容">
|
|
<ai-editor v-model="form.infoWindowHtml" :instance="instance"/>
|
|
</el-form-item>
|
|
</el-form>
|
|
</ai-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import CodeEditor from 'bin-ace-editor'
|
|
import 'brace/mode/json'
|
|
import 'brace/snippets/json';
|
|
import 'brace/theme/github';
|
|
import 'brace/theme/monokai';
|
|
import AiDialogBtn from "dui/packages/layout/AiDialogBtn.vue";
|
|
import AiFold from "dui/packages/layout/AiFold.vue";
|
|
|
|
export default {
|
|
name: 'dataConfig',
|
|
model: {
|
|
prop: "options",
|
|
event: "change"
|
|
},
|
|
props: {
|
|
options: Object,
|
|
instance: Function,
|
|
dict: Object,
|
|
},
|
|
data() {
|
|
return {
|
|
dataTypes: [
|
|
{
|
|
id: 'staticData',
|
|
label: '静态数据'
|
|
},
|
|
{
|
|
id: 'dynamicData',
|
|
label: '动态数据'
|
|
},
|
|
{
|
|
id: 'apiData',
|
|
label: '接口'
|
|
}
|
|
],
|
|
json: "",
|
|
sourceDataId: '',
|
|
sourceData: [],
|
|
keys: [],
|
|
monitorList: [],
|
|
list: [],
|
|
showMapEditor: false,
|
|
form: {},
|
|
charts: Object.keys({}).map((label, id) => ({id, label}))
|
|
}
|
|
},
|
|
computed: {
|
|
markers: v => v.options.staticData?.markers || [],
|
|
},
|
|
components: {
|
|
AiFold,
|
|
AiDialogBtn,
|
|
CodeEditor,
|
|
configItem: {
|
|
props: {
|
|
label: String
|
|
},
|
|
render(h) {
|
|
return h('div', {class: 'layout-config__item'}, [
|
|
h('label', this.label),
|
|
h('div', {class: 'layout-config__item--right fill'}, this.$slots.default)
|
|
])
|
|
}
|
|
}
|
|
},
|
|
created() {
|
|
if (this.options.type == "map" && Array.isArray(this.options.staticData)) {//处理历史数据,并更新最新数据结构
|
|
const values = this.$copy(this.options)
|
|
values.staticData = {markers: this.$copy(this.options.staticData)}
|
|
this.$emit("change", values)
|
|
}
|
|
},
|
|
mounted() {
|
|
this.getDataList()
|
|
if ((this.options.dataY && this.options.dataY.length && this.options.dataX) || this.options.type === 'monitor') {
|
|
const api = this.options.dataType === 'apiData' ? this.options.api : `/app/appdiylargescreen/statisticsByLsid?id=${this.options.sourceDataId}`
|
|
this.instance.post(api).then(res => {
|
|
if (res.code == 0) {
|
|
if (res.data.length && this.options.type !== 'monitor') {
|
|
this.list = res.data
|
|
this.keys = Object.keys(res.data[0])
|
|
|
|
this.$nextTick(() => {
|
|
this.onChooseChange()
|
|
})
|
|
} else if (this.options.type === 'monitor') {
|
|
this.monitorList = res.data
|
|
|
|
if (this.options.src) {
|
|
const obj = res.data.filter(v => this.options.title === v.name)
|
|
|
|
if (obj.length) {
|
|
this.options.src = obj[0].url
|
|
}
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
},
|
|
methods: {
|
|
showEditor() {
|
|
this.json = JSON.stringify(this.options.staticData, null, 2)
|
|
},
|
|
|
|
onMoniterId(e) {
|
|
this.instance.post(`/app/appzyvideoequipment/getWebSdkUrl?deviceId=${e}`).then(res => {
|
|
if (res.code == 0) {
|
|
this.options.src = JSON.parse(res.data).url
|
|
}
|
|
})
|
|
},
|
|
|
|
getDataList() {
|
|
this.instance.post(`/app/appdiylargescreen/allDatasourceByPage`, null, {
|
|
params: {
|
|
current: 1,
|
|
size: 10000
|
|
}
|
|
}).then(res => {
|
|
if (res.code == 0) {
|
|
this.sourceData = res.data.records
|
|
}
|
|
})
|
|
},
|
|
|
|
onApiChange() {
|
|
this.options.dataX = ''
|
|
this.options.dataY = []
|
|
this.instance.post(this.options.api).then(res => {
|
|
if (res.code == 0) {
|
|
if (res.data.length) {
|
|
if (this.options.type === 'table' || this.options.type === 'AiDvTable') {
|
|
const keys = Object.keys(res.data[0])
|
|
const list = res.data
|
|
this.options.apiData = keys.map(v => {
|
|
let obj = {}
|
|
list.forEach((item, index) => {
|
|
obj[`v${index}`] = item[v]
|
|
})
|
|
|
|
return {
|
|
row: v,
|
|
...obj
|
|
}
|
|
})
|
|
} else if (this.options.type === 'summary') {
|
|
if (this.options.display === 'summary9') {
|
|
this.options.apiData = res.data
|
|
} else {
|
|
this.options.apiData = Object.keys(res.data[0]).map(item => {
|
|
return {
|
|
key: item,
|
|
value: res.data[0][item]
|
|
}
|
|
})
|
|
}
|
|
} else if (this.options.type === 'monitor') {
|
|
this.monitorList = res.data
|
|
} else {
|
|
this.list = res.data
|
|
this.keys = Object.keys(res.data[0])
|
|
}
|
|
}
|
|
} else {
|
|
this.options.dynamicData = []
|
|
}
|
|
})
|
|
},
|
|
|
|
onChooseChange() {
|
|
let arr = []
|
|
if (this.options.dataX && this.options.dataY.length) {
|
|
this.list.forEach(item => {
|
|
let obj = {}
|
|
this.options.dataY.forEach(v => {
|
|
obj[v] = item[v]
|
|
})
|
|
arr.push({
|
|
[this.options.dataX]: item[this.options.dataX],
|
|
...obj
|
|
})
|
|
})
|
|
|
|
this.options[this.options.dataType] = arr
|
|
}
|
|
},
|
|
|
|
onDataChange(e) {
|
|
this.options.dataX = ''
|
|
this.options.dataY = []
|
|
this.instance.post(`/app/appdiylargescreen/statisticsByLsid?id=${e}`).then(res => {
|
|
if (res.code == 0) {
|
|
if (res.data.length) {
|
|
if (this.options.type === 'table' || this.options.type === 'AiDvTable') {
|
|
const keys = Object.keys(res.data[0])
|
|
const list = res.data
|
|
this.options.dynamicData = keys.map(v => {
|
|
let obj = {}
|
|
list.forEach((item, index) => {
|
|
obj[`v${index}`] = item[v]
|
|
})
|
|
|
|
return {
|
|
row: v,
|
|
...obj
|
|
}
|
|
})
|
|
} else if (this.options.type === 'summary') {
|
|
this.options.dynamicData = Object.keys(res.data[0]).map(item => {
|
|
return {
|
|
key: item,
|
|
value: res.data[0][item]
|
|
}
|
|
})
|
|
} else {
|
|
this.list = res.data
|
|
this.keys = Object.keys(res.data[0])
|
|
}
|
|
} else {
|
|
this.options.dynamicData = []
|
|
}
|
|
}
|
|
})
|
|
},
|
|
|
|
onConfirm() {
|
|
this.$set(this.options, 'staticData', JSON.parse(this.json))
|
|
this.$emit('change')
|
|
},
|
|
handleMapMarker(v = {}, index) {
|
|
this.form = this.$copy({...v, index})
|
|
this.showMapEditor = true
|
|
},
|
|
saveMarker() {
|
|
this.$refs.mapMarker.validate().then(() => {
|
|
const i = this.$copy(this.form.index)
|
|
delete this.form.index
|
|
if (i > -1) {
|
|
this.options.staticData.markers.splice(i, 1, this.form)
|
|
} else this.options.staticData.markers.push(this.form)
|
|
this.showMapEditor = false
|
|
})
|
|
},
|
|
removeMapMarker(i) {
|
|
this.$confirm("是否要删除该标记点").then(() => {
|
|
this.options.staticData.markers.splice(i, 1)
|
|
})
|
|
},
|
|
savePolylines() {
|
|
this.$set(this.options.staticData, 'polylines', JSON.parse(this.json))
|
|
},
|
|
handleMapPolylines() {
|
|
this.json = JSON.stringify(this.options.staticData.polylines || [{path: [[31.547706, 107.224325], [31.552456, 107.201185]]}])
|
|
},
|
|
handleMapPolylineDoc() {
|
|
window.open('https://lbs.amap.com/api/javascript-api-v2/documentation#polyline')
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.el-dialog__body {
|
|
.jsoneditor-vue {
|
|
height: 480px;
|
|
|
|
.jsoneditor-poweredBy {
|
|
display: none;
|
|
}
|
|
}
|
|
}
|
|
|
|
.ai-dialog__wrapper {
|
|
color: #333;
|
|
}
|
|
|
|
.layout-config__group--wrapper {
|
|
.layout-config__code .bin-ace-editor {
|
|
}
|
|
|
|
:deep(.layout-config__group) {
|
|
padding: 10px 10px 20px;
|
|
border-bottom: 1px solid #000000;
|
|
|
|
&:last-child {
|
|
border: none;
|
|
}
|
|
|
|
.layout-config__code {
|
|
position: relative;
|
|
padding-left: 10px;
|
|
}
|
|
|
|
& > h2 {
|
|
margin-bottom: 20px;
|
|
color: #FFFFFF;
|
|
font-size: 15px;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.layoutTitle {
|
|
color: #FFFFFF;
|
|
font-size: 15px;
|
|
font-weight: 700;
|
|
}
|
|
}
|
|
|
|
:deep(.layout-config__item) {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
margin-bottom: 10px;
|
|
|
|
&:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
label {
|
|
flex-shrink: 0;
|
|
width: 60px;
|
|
color: #FFFFFF;
|
|
font-size: 12px;
|
|
text-align: right;
|
|
}
|
|
|
|
.el-select .el-tag {
|
|
color: #fff;
|
|
background: transparent;
|
|
}
|
|
|
|
.el-input__icon {
|
|
color: #fff;
|
|
}
|
|
|
|
.el-switch__label {
|
|
color: #fff;
|
|
}
|
|
|
|
.el-select {
|
|
width: 100%;
|
|
|
|
&:last-child {
|
|
margin-right: 0;
|
|
}
|
|
|
|
input {
|
|
background: #262C33;
|
|
font-size: 12px;
|
|
color: #fff;
|
|
border: 1px solid #030411;
|
|
}
|
|
|
|
.el-input__icon {
|
|
color: #fff;
|
|
}
|
|
}
|
|
|
|
:deep(.el-collapse) {
|
|
height: 18px;
|
|
}
|
|
}
|
|
|
|
.el-icon-delete {
|
|
color: #f46;
|
|
}
|
|
|
|
.el-button--text + .el-button--text {
|
|
margin-left: 0;
|
|
}
|
|
|
|
input {
|
|
background: #262C33;
|
|
font-size: 12px;
|
|
color: #fff;
|
|
border: 1px solid #030411;
|
|
}
|
|
|
|
.layout-config__item--right {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: flex-end;
|
|
text-align: right;
|
|
margin-left: 30px;
|
|
}
|
|
}
|
|
</style>
|