初始化
This commit is contained in:
60
frontend/packages/js/api/bigScreenApi.js
Normal file
60
frontend/packages/js/api/bigScreenApi.js
Normal file
@@ -0,0 +1,60 @@
|
||||
import Vue from 'vue'
|
||||
// 大屏详情
|
||||
export function getScreenInfo (code) {
|
||||
return Vue.prototype.$dataRoomAxios.get(`/bigScreen/design/info/code/${code}`)
|
||||
}
|
||||
|
||||
// 保存更新大屏
|
||||
export function saveScreen(data) {
|
||||
data.chartList.forEach((item) => {
|
||||
if (item.type == 'customComponent') {
|
||||
const a = JSON.parse(item.option)
|
||||
if (a.data) {
|
||||
a.data = []
|
||||
}
|
||||
item.option=JSON.stringify(a)
|
||||
item.setting=item.setting.map((x) => {
|
||||
const {field,value,...obj}=x
|
||||
return {field,value}
|
||||
})
|
||||
}
|
||||
})
|
||||
return Vue.prototype.$dataRoomAxios.post('/bigScreen/design/update', data)
|
||||
}
|
||||
|
||||
// 根据数据集获取数据集详情
|
||||
export function getDataSetDetails (id) {
|
||||
return Vue.prototype.$dataRoomAxios.get('/dataset/datasetInfo/' + id)
|
||||
}
|
||||
|
||||
// 根据数据集id获取数据
|
||||
export function getDataByDataSetId (dataSetId) {
|
||||
return Vue.prototype.$dataRoomAxios.post('/dataset/execute', {
|
||||
dataSetId,
|
||||
params: []
|
||||
})
|
||||
}
|
||||
|
||||
// 得到图表详情
|
||||
export function getChatInfo (params) {
|
||||
return Vue.prototype.$dataRoomAxios.post('/bigScreen/chart/data/list', params)
|
||||
}
|
||||
// 得到图表的更新数据
|
||||
export function getUpdateChartInfo (params) {
|
||||
return Vue.prototype.$dataRoomAxios.post('/bigScreen/chart/data/chart', params)
|
||||
}
|
||||
|
||||
// 业务组件列表
|
||||
export function getBizComponentPage (params) {
|
||||
return Vue.prototype.$dataRoomAxios.get('/bigScreen/bizComponent/page', params)
|
||||
}
|
||||
|
||||
// 根据code获得业务组件的信息
|
||||
export function getBizComponentInfo (code) {
|
||||
return Vue.prototype.$dataRoomAxios.get(`/bigScreen/bizComponent/info/${code}`)
|
||||
}
|
||||
|
||||
// 更新业务组件
|
||||
export function updateBizComponent (params) {
|
||||
return Vue.prototype.$dataRoomAxios.post('/bigScreen/bizComponent/update', params)
|
||||
}
|
||||
68
frontend/packages/js/config/basicComponentsConfig.js
Normal file
68
frontend/packages/js/config/basicComponentsConfig.js
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* @description: 基础的bigScreen展示组件
|
||||
* @Date: 2023-03-13 10:04:59
|
||||
* @Author: xing.heng
|
||||
* @LastEditors: wujian
|
||||
* @LastEditTime: 2023-06-01 15:55:48
|
||||
*/
|
||||
|
||||
// import _ from 'lodash'
|
||||
import cloneDeep from "lodash/cloneDeep";
|
||||
import getComponentConfig from "data-room-ui/js/utils/getComponentConfig";
|
||||
// 批量引入配置文件
|
||||
import { setModules, dataModules } from "data-room-ui/js/utils/configImport";
|
||||
const typeList = [
|
||||
"texts",
|
||||
"numbers",
|
||||
"linkChart",
|
||||
"horizontalLine", // 横线
|
||||
"verticalLine", // 竖线
|
||||
"picture",
|
||||
"timeCountDown",
|
||||
"currentTime",
|
||||
"customHtml",
|
||||
"iframeChart",
|
||||
"digitalFlop",
|
||||
"tables",
|
||||
"screenScrollRanking",
|
||||
"screenScrollBoard",
|
||||
"video",
|
||||
"input",
|
||||
"button",
|
||||
"marquee",
|
||||
"chartTab",
|
||||
"themeSwitcher",
|
||||
"themeSelect",
|
||||
"select",
|
||||
"timePicker",
|
||||
"dateTimePicker",
|
||||
"indicatorCard",
|
||||
"indicatorCard2",
|
||||
"indexCard",
|
||||
"indexCard2",
|
||||
];
|
||||
let basicConfigList = [];
|
||||
basicConfigList = typeList.map((type) => {
|
||||
console.log('getComponentConfig(type): ', getComponentConfig(type));
|
||||
|
||||
return getComponentConfig(type);
|
||||
});
|
||||
basicConfigList = basicConfigList.map((item) => {
|
||||
return basicComponentsConfig(item);
|
||||
});
|
||||
// 生成基本配置
|
||||
export function basicComponentsConfig(item) {
|
||||
return {
|
||||
...item,
|
||||
border: {
|
||||
type: "",
|
||||
titleHeight: 60,
|
||||
fontSize: 30,
|
||||
isTitle: true,
|
||||
padding: [0, 0, 0, 0],
|
||||
},
|
||||
option: cloneDeep(setModules[item.type]),
|
||||
...cloneDeep(dataModules[item.type]),
|
||||
};
|
||||
}
|
||||
export default basicConfigList;
|
||||
40
frontend/packages/js/config/borderComponentsConfig.js
Normal file
40
frontend/packages/js/config/borderComponentsConfig.js
Normal file
@@ -0,0 +1,40 @@
|
||||
// import _ from 'lodash'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
import getComponentConfig from 'data-room-ui/js/utils/getBorderComponentsConfig'
|
||||
// 批量引入配置文件
|
||||
import { setModules, dataModules } from 'data-room-ui/js/utils/configImport'
|
||||
const typeLIst = [
|
||||
'border1',
|
||||
'border2',
|
||||
'border3',
|
||||
'border4',
|
||||
'border5',
|
||||
'border6',
|
||||
'border7',
|
||||
'border8',
|
||||
'border9',
|
||||
'border10',
|
||||
'border11',
|
||||
'border12',
|
||||
'border13',
|
||||
'border14',
|
||||
'border15'
|
||||
]
|
||||
let basicConfigList = []
|
||||
basicConfigList = typeLIst.map((type) => {
|
||||
// 装饰组件的className保持一致
|
||||
return getComponentConfig(type, 'ScreenBorder')
|
||||
})
|
||||
basicConfigList = basicConfigList.map((item) => {
|
||||
return basicComponentsConfig(item)
|
||||
})
|
||||
// 生成基本配置
|
||||
export function basicComponentsConfig (item) {
|
||||
// let type = `${upperFirst(item.type)}`
|
||||
return {
|
||||
...item,
|
||||
option: cloneDeep(setModules[item.type]),
|
||||
...cloneDeep(dataModules[item.type])
|
||||
}
|
||||
}
|
||||
export default basicConfigList
|
||||
94
frontend/packages/js/config/commonConfig.js
Normal file
94
frontend/packages/js/config/commonConfig.js
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* @description: 大屏组件通用属性
|
||||
* @Date: 2023-03-13 10:04:59
|
||||
* @Author: xing.heng
|
||||
* @LastEditors: wujian
|
||||
* @LastEditTime: 2023-06-01 10:23:13
|
||||
*/
|
||||
|
||||
import getComponentConfig from 'data-room-ui/js/utils/getComponentConfig'
|
||||
import linkageConfig from 'data-room-ui/js/config/linkageConfig'
|
||||
// 关于设置组件在右侧面板可以展示哪些属性配置
|
||||
export const displayOption = {
|
||||
serverPagination: {
|
||||
// 服务端分页
|
||||
enable: false
|
||||
},
|
||||
pageSize: {
|
||||
// 分页长度
|
||||
enable: false
|
||||
},
|
||||
metricField: {
|
||||
// 指标
|
||||
label: '指标',
|
||||
enable: true,
|
||||
multiple: true // 是否多选
|
||||
},
|
||||
dimensionField: {
|
||||
// 维度
|
||||
label: '维度', // 维度/查询字段
|
||||
enable: true,
|
||||
multiple: true // 是否多选
|
||||
},
|
||||
dimensionList: {
|
||||
// 维度(只有多折线图会存在两个维度)
|
||||
label: '维度', // 维度/查询字段
|
||||
enable: false,
|
||||
multiple: true // 是否多选
|
||||
},
|
||||
seriesField: {
|
||||
// 数据细分
|
||||
enable: false,
|
||||
required: true // 必填
|
||||
},
|
||||
dataAllocation: {
|
||||
// 是否存在数据配置
|
||||
enable: true
|
||||
},
|
||||
params: {
|
||||
// 参数配置
|
||||
enable: true
|
||||
},
|
||||
dataSourceType: {
|
||||
// 数据源(数据集或者其他方式:静态数据)
|
||||
enable: true
|
||||
}
|
||||
}
|
||||
export default function (customConfig) {
|
||||
|
||||
|
||||
return {
|
||||
...getComponentConfig(customConfig.type),
|
||||
z: 0, // z轴图层支持
|
||||
locked: false, // 是否锁定组件
|
||||
group: '', // 组合组件, 相同group的组件会被组合在一起
|
||||
code: null,
|
||||
showTitle: true,
|
||||
...customConfig.root,
|
||||
dataSource: {
|
||||
className:
|
||||
'com.gccloud.dataroom.core.module.chart.components.datasource.DataSetDataSource',
|
||||
dataSourceKey: '', // 数据源,选择不同数据库
|
||||
source: 'dataset',
|
||||
businessKey: '', // 数据集标识
|
||||
dimensionField: '', // 维度
|
||||
metricField: '', // 指标
|
||||
seriesField: '', // 分类字段
|
||||
dimensionFieldList: [], // 唯独列表
|
||||
metricFieldList: [], // 指标列表
|
||||
seriesFieldList: [], // 分类列表
|
||||
serverPagination: false, // 服务端分页
|
||||
pageSize: 10,
|
||||
params: {},
|
||||
dataSetType: '1', // 数据集类型,
|
||||
formCode: '',
|
||||
...customConfig.dataSource // 非通用数据配置
|
||||
},
|
||||
customize: {
|
||||
...customConfig.customize
|
||||
}, // 自定义设置
|
||||
...linkageConfig, // 数据联动配置
|
||||
filterList: [],
|
||||
dataFlag: false // 判断数据为模拟数据还是真实数据
|
||||
}
|
||||
}
|
||||
30
frontend/packages/js/config/configurationComponentsConfig.js
Normal file
30
frontend/packages/js/config/configurationComponentsConfig.js
Normal file
@@ -0,0 +1,30 @@
|
||||
// import _ from 'lodash'
|
||||
import cloneDeep from "lodash/cloneDeep";
|
||||
import getComponentConfig from "data-room-ui/js/utils/getConfigurationComponentsConfig";
|
||||
// 批量引入配置文件
|
||||
import { setModules, dataModules } from "data-room-ui/js/utils/configImport";
|
||||
|
||||
const typeLIst = [
|
||||
"horizontalLine2",
|
||||
"verticalLine2",
|
||||
"warning",
|
||||
];
|
||||
let basicConfigList = [];
|
||||
basicConfigList = typeLIst.map((type) => {
|
||||
return getComponentConfig(type, "ScreenConfiguration"); // 组态组件的className保持一致
|
||||
});
|
||||
basicConfigList = basicConfigList.map((item) => {
|
||||
return basicComponentsConfig(item);
|
||||
});
|
||||
|
||||
// 生成基本配置
|
||||
export function basicComponentsConfig(item) {
|
||||
// let type = `lcdp${upperFirst(item.type)}`
|
||||
return {
|
||||
...item,
|
||||
option: cloneDeep(setModules[item.type]),
|
||||
...cloneDeep(dataModules[item.type]),
|
||||
};
|
||||
}
|
||||
|
||||
export default basicConfigList;
|
||||
38
frontend/packages/js/config/decorationComponentsConfig.js
Normal file
38
frontend/packages/js/config/decorationComponentsConfig.js
Normal file
@@ -0,0 +1,38 @@
|
||||
// import _ from 'lodash'
|
||||
import cloneDeep from "lodash/cloneDeep";
|
||||
import getComponentConfig from "data-room-ui/js/utils/getDecorationComponentsConfig";
|
||||
// 批量引入配置文件
|
||||
import { setModules, dataModules } from "data-room-ui/js/utils/configImport";
|
||||
const typeLIst = [
|
||||
"decoration1",
|
||||
"decoration3",
|
||||
"decoration2",
|
||||
"decoration2Reverse",
|
||||
"decoration4",
|
||||
"decoration4Reverse",
|
||||
"decoration5",
|
||||
"decoration6",
|
||||
"decoration8",
|
||||
"decoration8Reverse",
|
||||
"decoration9",
|
||||
"decoration10",
|
||||
"decoration11",
|
||||
];
|
||||
let basicConfigList = [];
|
||||
basicConfigList = typeLIst.map((type) => {
|
||||
// 装饰组件的className保持一致
|
||||
return getComponentConfig(type, "ScreenDecoration");
|
||||
});
|
||||
basicConfigList = basicConfigList.map((item) => {
|
||||
return basicComponentsConfig(item);
|
||||
});
|
||||
// 生成基本配置
|
||||
export function basicComponentsConfig(item) {
|
||||
// let type = `lcdp${upperFirst(item.type)}`
|
||||
return {
|
||||
...item,
|
||||
option: cloneDeep(setModules[item.type]),
|
||||
...cloneDeep(dataModules[item.type]),
|
||||
};
|
||||
}
|
||||
export default basicConfigList;
|
||||
13
frontend/packages/js/config/index.js
Normal file
13
frontend/packages/js/config/index.js
Normal file
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* @description: 抛出组件的配置
|
||||
* @Date: 2023-03-13 10:04:59
|
||||
* @Author: xing.heng
|
||||
* @LastEditors: xing.heng
|
||||
* @LastEditTime: 2023-03-13 11:26:13
|
||||
*/
|
||||
|
||||
import commonConfig, { displayOption } from './commonConfig'
|
||||
|
||||
export {
|
||||
commonConfig, displayOption // commonConfig个函数,传入参数type,动态生成配置,displayOption是决定组件具有哪些属性配置
|
||||
}
|
||||
24
frontend/packages/js/config/linkageConfig.js
Normal file
24
frontend/packages/js/config/linkageConfig.js
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* @description: 通用的联动参数
|
||||
* @Date: 2023-01-10 09:58:10
|
||||
* @Author: xing.heng
|
||||
* @LastEditors: xing.heng
|
||||
* @LastEditTime: 2023-04-18 17:19:29
|
||||
*/
|
||||
export default {
|
||||
inParams: [
|
||||
// {
|
||||
// // 组件用于入参的参数列表
|
||||
// name: '', // 参数名
|
||||
// code: '' // 参数值
|
||||
// }
|
||||
],
|
||||
// 查询表单联动
|
||||
linkage: {
|
||||
action: {
|
||||
type: 'js',
|
||||
script: '' // 联动执行的逻辑
|
||||
},
|
||||
components: []
|
||||
}
|
||||
}
|
||||
3
frontend/packages/js/config/svgComponentsConfig.js
Normal file
3
frontend/packages/js/config/svgComponentsConfig.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import Icon from 'packages/Svgs/export'
|
||||
const svgList = Icon.getSvgList()
|
||||
export default svgList
|
||||
130
frontend/packages/js/dict/chartDict.js
Normal file
130
frontend/packages/js/dict/chartDict.js
Normal file
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* 聚合函数
|
||||
* @type {string[]}
|
||||
*/
|
||||
export const aggregateList = ['COUNT', 'SUM', 'AVG', 'MAX', 'MIN', 'COUNT_DISTINCT']
|
||||
|
||||
/**
|
||||
* 过滤条件
|
||||
* @type {string[]}
|
||||
*/
|
||||
export const operatorList = [
|
||||
{
|
||||
label: '等于',
|
||||
value: '='
|
||||
},
|
||||
{
|
||||
label: '不等于',
|
||||
value: '!='
|
||||
},
|
||||
{
|
||||
label: '大于',
|
||||
value: '>'
|
||||
},
|
||||
{
|
||||
label: '小于',
|
||||
value: '<'
|
||||
},
|
||||
{
|
||||
label: '大于等于',
|
||||
value: '>='
|
||||
},
|
||||
{
|
||||
label: '小于等于',
|
||||
value: '<='
|
||||
},
|
||||
{
|
||||
label: '包含',
|
||||
value: 'IN'
|
||||
},
|
||||
{
|
||||
label: '不包含',
|
||||
value: 'NOT IN'
|
||||
},
|
||||
{
|
||||
label: '相似',
|
||||
value: 'LIKE'
|
||||
},
|
||||
{
|
||||
label: '为空',
|
||||
value: 'IS NULL'
|
||||
},
|
||||
{
|
||||
label: '不为空',
|
||||
value: 'IS NOT NULL'
|
||||
}
|
||||
]
|
||||
/**
|
||||
* 分页条数
|
||||
* @type {number[]}
|
||||
*/
|
||||
export const rowLimits = [10, 50, 100, 250, 500, 1000, 5000, 10000]
|
||||
|
||||
/**
|
||||
* 最近类型的时间范围
|
||||
* @type {[{label: string, value: string}]}
|
||||
*/
|
||||
export const lastTimeRangeType = [
|
||||
{
|
||||
label: '最近一天',
|
||||
value: 'lastDay'
|
||||
},
|
||||
{
|
||||
label: '最近一周',
|
||||
value: 'lastWeek'
|
||||
},
|
||||
{
|
||||
label: '最近一月',
|
||||
value: 'lastMonth'
|
||||
},
|
||||
{
|
||||
label: '最近一季度',
|
||||
value: 'lastQuarter'
|
||||
},
|
||||
{
|
||||
label: '最近一年',
|
||||
value: 'lastYear'
|
||||
}
|
||||
]
|
||||
|
||||
/**
|
||||
* 周期时间范围
|
||||
* @type {[{label: string, value: string}]}
|
||||
*/
|
||||
export const previousTimeRangeType = [
|
||||
{
|
||||
label: '上一周',
|
||||
value: 'previousWeek'
|
||||
},
|
||||
{
|
||||
label: '上一月',
|
||||
value: 'previousMonth'
|
||||
},
|
||||
{
|
||||
label: '上一年',
|
||||
value: 'previousYear'
|
||||
}
|
||||
]
|
||||
|
||||
/**
|
||||
* 时间粒度
|
||||
* @type {[{label: string, value: string}]}
|
||||
*/
|
||||
export const timeGrain = [
|
||||
{
|
||||
label: '原始值',
|
||||
value: 'original'
|
||||
},
|
||||
{
|
||||
label: '秒',
|
||||
value: 'second'
|
||||
},
|
||||
{
|
||||
label: '分钟',
|
||||
value: 'minute'
|
||||
},
|
||||
{
|
||||
label: '小时',
|
||||
value: 'hour'
|
||||
}, { label: '天', value: 'day' }, { label: '周', value: 'week' }, { label: '月', value: 'month' }, { label: '季度', value: 'quarter' }, { label: '年', value: 'year' }
|
||||
]
|
||||
250
frontend/packages/js/mixins/chartContextMenu.js
Normal file
250
frontend/packages/js/mixins/chartContextMenu.js
Normal file
@@ -0,0 +1,250 @@
|
||||
import { mapMutations, mapState } from 'vuex'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
import { toJpeg, toPng } from 'html-to-image'
|
||||
import isEmpty from 'lodash/isEmpty'
|
||||
import { randomString } from 'data-room-ui/js/utils'
|
||||
import Contextmenu from 'vue-contextmenujs'
|
||||
import Vue from 'vue'
|
||||
|
||||
Vue.use(Contextmenu)
|
||||
export default {
|
||||
computed: {
|
||||
...mapState({
|
||||
activeCode: state => state.bigScreen.activeCode,
|
||||
activeCodes: state => state.bigScreen.activeCodes,
|
||||
hoverCode: state => state.bigScreen.hoverCode,
|
||||
activeItemConfig: state => state.bigScreen.activeItemConfig,
|
||||
chartList: state => state.bigScreen.pageInfo.chartList,
|
||||
presetLine: state => state.bigScreen.presetLine
|
||||
})
|
||||
},
|
||||
data () {
|
||||
return {}
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
methods: {
|
||||
...mapMutations('bigScreen', ['changeHoverCode', 'changeActiveCode', 'changeChartConfig', 'addItem', 'delItem', 'resetPresetLine', 'changeLayout', 'changeZIndex', 'changeLocked', 'saveTimeLine', 'copyCharts', 'pasteCharts', 'clearActiveCodes']), // 改变hover的组件
|
||||
changeHover (code) {
|
||||
this.changeHoverCode(code)
|
||||
}, // 改变激活的组件
|
||||
changeActive (code) {
|
||||
this.changeActiveCode(code)
|
||||
}, // 打开右侧面板
|
||||
openRightPanel (config) {
|
||||
this.changeActiveCode(config.code)
|
||||
this.$emit('openRightPanel', config)
|
||||
}, // 查看数据
|
||||
dataView (config) {
|
||||
this.changeActiveCode(config.code)
|
||||
this.$emit('openDataViewDialog', config)
|
||||
}, // 复制组件
|
||||
copyItem (config) {
|
||||
const newConfig = cloneDeep(config)
|
||||
newConfig.code = randomString(8)
|
||||
newConfig.title = newConfig.title + '_副本'
|
||||
// 区分是从左侧添加还是复制的组件
|
||||
newConfig.isCopy = true
|
||||
newConfig.x = config.x + 20
|
||||
newConfig.y = config.y + 20
|
||||
if (config.group) {
|
||||
newConfig.group = 'copy_' + config.group
|
||||
}
|
||||
this.addItem(newConfig)
|
||||
}, // 删除单个组件
|
||||
deleteItem (config) {
|
||||
this.$confirm('确定删除该组件吗?', '提示', {
|
||||
confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning', customClass: 'bs-el-message-box'
|
||||
}).then(() => {
|
||||
this.delItem(config.code)
|
||||
})
|
||||
}, // 批量删除组合元素
|
||||
deleteGroupItem (config) {
|
||||
this.$confirm('确定批量删除选中的组件吗?', '提示', {
|
||||
confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning', customClass: 'bs-el-message-box'
|
||||
}).then(() => {
|
||||
// 找到和本组件group相同的组件 删除
|
||||
const codes = this.chartList.filter(_chart => _chart.group === config.group && config.group).map(_chart => _chart.code)
|
||||
if (!isEmpty(codes)) {
|
||||
this.delItem(codes)
|
||||
} else {
|
||||
this.delItem(config.code)
|
||||
}
|
||||
})
|
||||
}, // 获取组件的坐标字符串,取整 (100, 100)
|
||||
getPoint ({ x, y }) {
|
||||
return `(${Math.round(x)}, ${Math.round(y)})`
|
||||
}, // 组合/取消组合图表
|
||||
groupChart (chart) {
|
||||
if (!chart.group || chart.group === 'tempGroup') {
|
||||
// 添加组合
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
this.activeCodes?.forEach(code => {
|
||||
const config = this.chartList.find(item => item.code === code)
|
||||
this.changeChartConfig({
|
||||
...config, group: `group_${chart.code}`
|
||||
})
|
||||
})
|
||||
this.saveTimeLine('组合图表')
|
||||
} else {
|
||||
// 取消组合
|
||||
this.clearActiveCodes()
|
||||
// 找到和本组件group相同的组件 取消group
|
||||
this.chartList.forEach(_chart => {
|
||||
if (_chart.group === chart.group) {
|
||||
this.changeChartConfig({
|
||||
..._chart, group: ''
|
||||
})
|
||||
}
|
||||
})
|
||||
this.saveTimeLine('取消组合图表')
|
||||
}
|
||||
}, // 生成图片
|
||||
generateImage (chart) {
|
||||
let componentDom = document.querySelector(`#${chart.code} .render-item-wrap`)
|
||||
if (this.isPreview) {
|
||||
componentDom = document.querySelector(`#${chart.code}`)
|
||||
}
|
||||
toPng(componentDom)
|
||||
.then((dataUrl) => {
|
||||
const link = document.createElement('a')
|
||||
link.download = `${chart.title}.png`
|
||||
link.href = dataUrl
|
||||
link.click()
|
||||
link.addEventListener('click', () => {
|
||||
link.remove()
|
||||
})
|
||||
}).catch((error) => {
|
||||
if (error.type === 'error') {
|
||||
// 判断的error.currentTarget是img标签,如果是的,就弹出消息说是图片跨域
|
||||
if (error.currentTarget.tagName.toLowerCase() === 'img') {
|
||||
// 确认框
|
||||
this.$confirm('图片资源跨域导致使用toDataURL API生成图片失败,请将图片上传到资源库,然后在组件中使用资源库中的图片资源,确保没有跨域问题。', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
showCancelButton: false,
|
||||
type: 'warning',
|
||||
customClass: 'bs-el-message-box'
|
||||
}).then(() => { }).catch(() => { })
|
||||
}
|
||||
} else {
|
||||
this.$message.warning('出现未知错误,请重试')
|
||||
}
|
||||
})
|
||||
}, // 右键菜单
|
||||
onContextmenu (event, chart) {
|
||||
const isHidden = !chart?.option?.displayOption?.dataAllocation?.enable
|
||||
event.preventDefault()
|
||||
if (this.isPreview) {
|
||||
this.$contextmenu({
|
||||
items: [{
|
||||
label: '查看数据',
|
||||
icon: 'el-icon-view',
|
||||
hidden: isHidden,
|
||||
onClick: () => {
|
||||
this.dataView(chart)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '生成图片',
|
||||
icon: 'el-icon-download',
|
||||
hidden: isHidden,
|
||||
onClick: () => {
|
||||
this.generateImage(chart)
|
||||
}
|
||||
}],
|
||||
event, // 鼠标事件信息
|
||||
customClass: 'bs-context-menu-class', // 自定义菜单 class
|
||||
zIndex: 999, // 菜单样式 z-index
|
||||
minWidth: 150 // 主菜单最小宽度
|
||||
})
|
||||
} else {
|
||||
this.$contextmenu({
|
||||
items: [{
|
||||
label: '配置',
|
||||
icon: 'el-icon-setting',
|
||||
onClick: () => {
|
||||
this.openRightPanel(chart)
|
||||
}
|
||||
}, {
|
||||
label: '删除',
|
||||
icon: 'el-icon-delete',
|
||||
onClick: () => {
|
||||
this.deleteItem(chart)
|
||||
}
|
||||
}, {
|
||||
label: '批量删除',
|
||||
icon: 'el-icon-delete',
|
||||
onClick: () => {
|
||||
this.deleteGroupItem(chart)
|
||||
}
|
||||
}, {
|
||||
label: '复制',
|
||||
icon: 'el-icon-copy-document',
|
||||
onClick: () => {
|
||||
this.copyItem(chart)
|
||||
}
|
||||
}, {
|
||||
label: '组合复制',
|
||||
icon: 'el-icon-copy-document',
|
||||
onClick: () => {
|
||||
this.copyCharts()
|
||||
this.pasteCharts()
|
||||
}
|
||||
}, {
|
||||
label: '置于顶层',
|
||||
icon: 'el-icon-arrow-up',
|
||||
onClick: () => {
|
||||
let chartList = cloneDeep(this.chartList)
|
||||
// 将当前图表置底
|
||||
chartList = chartList.filter(item => item.code !== chart.code)
|
||||
chartList.unshift(chart)
|
||||
this.changeLayout(chartList)
|
||||
this.changeZIndex(chartList)
|
||||
}
|
||||
}, {
|
||||
label: '置于底层',
|
||||
icon: 'el-icon-arrow-down',
|
||||
onClick: () => {
|
||||
let chartList = cloneDeep(this.chartList)
|
||||
// 将当前图表置顶
|
||||
chartList = chartList.filter(item => item.code !== chart.code)
|
||||
chartList.push(chart)
|
||||
this.changeLayout(chartList)
|
||||
this.changeZIndex(chartList)
|
||||
}
|
||||
}, {
|
||||
label: chart.locked ? '解锁' : '锁定',
|
||||
icon: chart.locked ? 'el-icon-unlock' : 'el-icon-lock',
|
||||
onClick: () => {
|
||||
this.changeLocked(chart)
|
||||
}
|
||||
}, {
|
||||
label: (chart.group && chart.group !== 'tempGroup') ? '取消组合' : '组合',
|
||||
icon: (chart.group && chart.group !== 'tempGroup') ? 'iconfont-bigscreen icon-quxiaoguanlian' : 'iconfont-bigscreen icon-zuhe',
|
||||
onClick: () => {
|
||||
this.groupChart(chart)
|
||||
}
|
||||
}, {
|
||||
label: '查看数据',
|
||||
icon: 'el-icon-view',
|
||||
hidden: isHidden,
|
||||
onClick: () => {
|
||||
this.dataView(chart)
|
||||
}
|
||||
}, {
|
||||
label: '生成图片',
|
||||
icon: 'el-icon-download',
|
||||
onClick: () => {
|
||||
this.generateImage(chart)
|
||||
}
|
||||
}],
|
||||
event, // 鼠标事件信息
|
||||
customClass: 'bs-context-menu-class', // 自定义菜单 class
|
||||
zIndex: 999, // 菜单样式 z-index
|
||||
minWidth: 150 // 主菜单最小宽度
|
||||
})
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
53
frontend/packages/js/mixins/chartSettingMixins.js
Normal file
53
frontend/packages/js/mixins/chartSettingMixins.js
Normal file
@@ -0,0 +1,53 @@
|
||||
// import _ from 'lodash'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
import ColorSelect from 'data-room-ui/ColorMultipleSelect/index.vue'
|
||||
const chartSettingMixins = {
|
||||
components: {
|
||||
ColorSelect
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
customRules: {},
|
||||
colorScheme: [],
|
||||
colors: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
mounted () {
|
||||
this.initColor()
|
||||
},
|
||||
methods: {
|
||||
initColor () {
|
||||
const colorSetting = this.config?.setting?.find(item => item.type === 'colorSelect')
|
||||
if (colorSetting && colorSetting.value && colorSetting.value.length) {
|
||||
this.colorScheme = cloneDeep(colorSetting.value)
|
||||
this.colors = cloneDeep(colorSetting.value)
|
||||
}
|
||||
},
|
||||
// 清空颜色
|
||||
delColor () {
|
||||
this.colors = []
|
||||
this.config.setting.forEach((set) => {
|
||||
if (set && set.type === 'colorSelect' && set.value && set.value.length) {
|
||||
set.value = []
|
||||
}
|
||||
})
|
||||
},
|
||||
addColor () {
|
||||
this.colors.push('')
|
||||
},
|
||||
updateColorScheme (colors) {
|
||||
this.colors = [...colors]
|
||||
this.config.setting.forEach((set) => {
|
||||
if (set && set.type === 'colorSelect') {
|
||||
set.value = [...colors]
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { chartSettingMixins }
|
||||
440
frontend/packages/js/mixins/commonMixins.js
Normal file
440
frontend/packages/js/mixins/commonMixins.js
Normal file
@@ -0,0 +1,440 @@
|
||||
/*
|
||||
* @description: bigScreen公共方法
|
||||
* @Date: 2023-03-24 17:10:43
|
||||
* @Author: xing.heng
|
||||
*/
|
||||
// import _ from 'lodash'
|
||||
import { mapMutations, mapState } from 'vuex'
|
||||
import { EventBus } from 'data-room-ui/js/utils/eventBus'
|
||||
import { getChatInfo, getUpdateChartInfo } from '../api/bigScreenApi'
|
||||
import axiosFormatting from '../../js/utils/httpParamsFormatting'
|
||||
import { settingToTheme } from 'data-room-ui/js/utils/themeFormatting'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
import mqtt from 'mqtt'
|
||||
import MqttClient from 'data-room-ui/js/utils/mqttClient'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
filterList: [],
|
||||
treeParentId: 0,
|
||||
dataLoading: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'config.expression': { // 表达式发生变化
|
||||
handler(val) {
|
||||
this.getDataByExpression(this.config)
|
||||
}
|
||||
},
|
||||
// 标题发生变化时需要及时更新表达式中的数据集库的字段名
|
||||
'config.title': {
|
||||
handler(val, oldVal) {
|
||||
this.updateDataset({ code: this.config.code, title: val, data: [], oldTitle: oldVal, isChangeTitle: true })
|
||||
this.updateComputedDatas({ code: this.config.code, title: val, data: [], oldTitle: oldVal, isChangeTitle: true })
|
||||
}
|
||||
},
|
||||
currentDataset: { // 关联的数据发生变化
|
||||
handler(val, old) {
|
||||
if (val && Object.keys(val).length && JSON.stringify(val) !== JSON.stringify(old)) {
|
||||
this.getDataByExpression(this.config)
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
},
|
||||
currentComputedDatas: { // 关联的数据发生变化
|
||||
handler(val, old) {
|
||||
if (val && Object.keys(val).length && JSON.stringify(val) !== JSON.stringify(old)) {
|
||||
this.getDataByExpression(this.config)
|
||||
}
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
pageCode: state => state.bigScreen.pageInfo.code,
|
||||
customTheme: state => state.bigScreen.pageInfo.pageConfig.customTheme,
|
||||
activeCode: state => state.bigScreen.activeCode
|
||||
// dataset: state => state.bigScreen.dataset
|
||||
}),
|
||||
// 所有组件的数据集合
|
||||
dataset() {
|
||||
return this.$store.state.bigScreen.dataset
|
||||
},
|
||||
// 所有组件的数据集合
|
||||
computedDatas() {
|
||||
return this.$store.state.bigScreen.computedDatas
|
||||
},
|
||||
// 跟当前组件计算表达式关联的组件的数据集合
|
||||
currentDataset() {
|
||||
const newDataset = {}
|
||||
this.config.expressionCodes?.forEach(item => {
|
||||
const code = item.split('_')[1]
|
||||
for (const key in this.dataset) {
|
||||
const objCode = key.split('_')[1]
|
||||
if (objCode === code) {
|
||||
newDataset[code] = this.dataset[key]
|
||||
}
|
||||
}
|
||||
})
|
||||
return newDataset
|
||||
},
|
||||
// 跟当前组件计算表达式关联的组件的数据集合
|
||||
currentComputedDatas() {
|
||||
const newDataset = {}
|
||||
this.config.expressionCodes?.forEach(item => {
|
||||
const code = item.split('_')[1]
|
||||
for (const key in this.computedDatas) {
|
||||
const objCode = key.split('_')[1]
|
||||
if (objCode === code) {
|
||||
newDataset[code] = this.computedDatas[key]
|
||||
}
|
||||
}
|
||||
})
|
||||
return newDataset
|
||||
},
|
||||
isPreview() {
|
||||
return (this.$route.path === window?.BS_CONFIG?.routers?.previewUrl) || (this.$route.path === '/big-screen/preview')
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (!['tables', 'flyMap', 'map'].includes(this.config.type)) {
|
||||
this.chartInit()
|
||||
}
|
||||
this.watchCacheData()
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({
|
||||
changeChartConfig: 'bigScreen/changeChartConfig',
|
||||
changeActiveItemConfig: 'bigScreen/changeActiveItemConfig',
|
||||
updateDataset: 'bigScreen/updateDataset',
|
||||
updateComputedDatas: 'bigScreen/updateComputedDatas'
|
||||
}),
|
||||
/**
|
||||
* 初始化组件
|
||||
*/
|
||||
chartInit() {
|
||||
let config = this.config
|
||||
console.log('this.config: ', this.config);
|
||||
// key和code相等,说明是一进来刷新,调用list接口
|
||||
if (this.isPreview) {
|
||||
// 改变样式
|
||||
config = this.changeStyle(config) ? this.changeStyle(config) : config
|
||||
// 改变数据
|
||||
config = this.changeDataByCode(config)
|
||||
} else {
|
||||
// 否则说明是更新,这里的更新只指更新数据(改变样式时是直接调取changeStyle方法),因为更新数据会改变key,调用chart接口
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
config = this.changeData(config)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 初始化组件时获取后端返回的数据, 返回数据和当前组件的配置_list
|
||||
* @param settingConfig 设置时的配置。不传则为当前组件的配置
|
||||
* @returns {Promise<unknown>}
|
||||
*/
|
||||
changeDataByCode(config) {
|
||||
let currentPage = 1
|
||||
let size = 10
|
||||
if (config?.option?.pagination) {
|
||||
currentPage = config.option.pagination.currentPage
|
||||
size = config.option.pagination.pageSize
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
config.loading = true
|
||||
getChatInfo({
|
||||
// innerChartCode: this.pageCode ? config.code : undefined,
|
||||
chartCode: config.code,
|
||||
current: currentPage,
|
||||
pageCode: this.pageCode,
|
||||
size: size,
|
||||
type: config.type
|
||||
}).then(async (res) => {
|
||||
config.loading = false
|
||||
let _res = cloneDeep(res)
|
||||
//--------------------MQTT数据集执行前置条件------------------------------------------------------------
|
||||
if (res.data && res.data.datasetType && res.data.datasetType === 'mqtt') {
|
||||
res.executionByFrontend = true
|
||||
}
|
||||
//--------------------MQTT数据集执行前置条件------------------------------------------------------------
|
||||
// 如果是http数据集的前端代理,则需要调封装的axios请求
|
||||
if (res.executionByFrontend) {
|
||||
if (res.data.datasetType === 'mqtt') {
|
||||
// 创建 MQTT 客户端实例
|
||||
this.mqttClient = new MqttClient(res.data.url, {
|
||||
clientId: "SW-VIEWS" + new Date().getTime(),
|
||||
username: res.data.username,
|
||||
password: res.data.password
|
||||
});
|
||||
// 连接到 MQTT broker
|
||||
this.mqttClient.connect();
|
||||
// 订阅指定主题
|
||||
let produceTopic = res.data.topic;
|
||||
this.mqttClient.subscribe(produceTopic, (topic, data) => {
|
||||
// console.log(`收到主题 ${topic} 的消息`);
|
||||
// if (topic === produceTopic) {
|
||||
// // 处理收到的消息
|
||||
// let JsonData = JSON.parse(data.toString());
|
||||
// _res = this.httpDataFormatting(res, JsonData.data);
|
||||
// config = this.dataFormatting(config, _res);
|
||||
// // 每次数据更新后,重新渲染图表
|
||||
// this.chart.changeData(config.option.data);
|
||||
// }
|
||||
if (topic === produceTopic) {
|
||||
// 处理收到的消息
|
||||
let JsonData = JSON.parse(data.toString());
|
||||
if (res.data.responseScript) {
|
||||
// eslint-disable-next-line no-new-func
|
||||
const getResp = new Function('resp', res.data.responseScript)
|
||||
let resData=getResp(JsonData)
|
||||
let lastRes = res && Array.isArray(resData) ? resData : [{ ...resData }]
|
||||
_res = this.httpDataFormatting(res, lastRes);
|
||||
}else{
|
||||
_res = this.httpDataFormatting(res, JsonData);
|
||||
}
|
||||
config = this.dataFormatting(config, _res);
|
||||
// 每次数据更新后,重新渲染图表
|
||||
// this.chart.changeData(config.option.data);
|
||||
if (this.chart && this.chart.changeData) {
|
||||
try {
|
||||
this.chart.changeData(config.option.data);
|
||||
} catch (error) {
|
||||
console.log("Error changing data:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (res.data.datasetType === 'http') {
|
||||
_res = await axiosFormatting(res.data)
|
||||
_res = this.httpDataFormatting(res, _res)
|
||||
}
|
||||
|
||||
if (res.data.datasetType === 'js') {
|
||||
try {
|
||||
const scriptAfterReplacement = res.data.script.replace(/\${(.*?)}/g, (match, p) => {
|
||||
const value = this.config.dataSource?.params[p]
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return "''"
|
||||
} else if (!isNaN(value)) {
|
||||
return value || p
|
||||
} else {
|
||||
return `'${value}' || '${p}'`
|
||||
}
|
||||
})
|
||||
// eslint-disable-next-line no-new-func
|
||||
const scriptMethod = new Function(scriptAfterReplacement)
|
||||
_res.data = scriptMethod()
|
||||
} catch (error) {
|
||||
console.info('JS数据集脚本执行失败', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 将后端返回的数据保存
|
||||
if (_res.success) {
|
||||
this.updateDataset({ code: config.code, title: config.title, data: _res?.data })
|
||||
}
|
||||
config = this.dataFormatting(config, _res)
|
||||
this.changeChartConfig(config)
|
||||
}).catch((err) => {
|
||||
console.info(err)
|
||||
}).finally(() => {
|
||||
resolve(config)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @description: 更新chart
|
||||
* @param {Object} config
|
||||
* @param {Array} filterList
|
||||
*/
|
||||
changeData(config, filterList) {
|
||||
const list = config?.paramsList?.map((item) => {
|
||||
if (item.value === '${level}') {
|
||||
return { ...item, value: config.customize.level }
|
||||
} else if (item.value === '${name}') {
|
||||
return { ...item, value: config.customize.scope }
|
||||
} else {
|
||||
return item
|
||||
}
|
||||
})
|
||||
const params = {
|
||||
chart: {
|
||||
...config,
|
||||
paramsList: list ? [...list] : [],
|
||||
option: undefined
|
||||
},
|
||||
current: 1,
|
||||
pageCode: this.pageCode,
|
||||
type: config.type,
|
||||
filterList: filterList || this.filterList
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
config.loading = true
|
||||
getUpdateChartInfo(params).then(async (res) => {
|
||||
config.loading = false
|
||||
let _res = cloneDeep(res)
|
||||
//--------------------MQTT数据集执行前置条件------------------------------------------------------------
|
||||
if (res.data && res.data.datasetType && res.data.datasetType === 'mqtt') {
|
||||
res.executionByFrontend = true
|
||||
}
|
||||
//--------------------MQTT数据集执行前置条件------------------------------------------------------------
|
||||
// 如果是http数据集的前端代理,则需要调封装的axios请求
|
||||
if (res.executionByFrontend) {
|
||||
if (res.data.datasetType === 'mqtt') {
|
||||
|
||||
// 创建 MQTT 客户端实例
|
||||
this.mqttClient = new MqttClient(res.data.url, {
|
||||
clientId: "SW-VIEWS" + new Date().getTime(),
|
||||
username: res.data.username,
|
||||
password: res.data.password
|
||||
});
|
||||
// 连接到 MQTT broker
|
||||
this.mqttClient.connect();
|
||||
// 订阅指定主题
|
||||
let produceTopic = res.data.topic;
|
||||
this.mqttClient.subscribe(produceTopic, (topic, data) => {
|
||||
if (topic === produceTopic) {
|
||||
// 处理收到的消息
|
||||
let JsonData = JSON.parse(data.toString());
|
||||
if (res.data.responseScript) {
|
||||
// eslint-disable-next-line no-new-func
|
||||
const getResp = new Function('resp', res.data.responseScript)
|
||||
let resData=getResp(JsonData)
|
||||
let lastRes = res && Array.isArray(resData) ? resData : [{ ...resData }]
|
||||
_res = this.httpDataFormatting(res, lastRes);
|
||||
}else{
|
||||
_res = this.httpDataFormatting(res, JsonData);
|
||||
}
|
||||
config = this.dataFormatting(config, _res);
|
||||
// 每次数据更新后,重新渲染图表
|
||||
// this.chart.changeData(config.option.data);
|
||||
if (this.chart && this.chart.changeData) {
|
||||
try {
|
||||
this.chart.changeData(config.option.data);
|
||||
} catch (error) {
|
||||
console.log("Error changing data:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (res.data.datasetType === 'http') {
|
||||
_res = await axiosFormatting(res.data)
|
||||
_res = this.httpDataFormatting(res, _res)
|
||||
|
||||
}
|
||||
if (res.data.datasetType === 'js') {
|
||||
try {
|
||||
params.filterList.forEach(item => {
|
||||
this.config.dataSource.params[item.column] = item.value
|
||||
})
|
||||
const scriptAfterReplacement = res.data.script.replace(/\${(.*?)}/g, (match, p) => {
|
||||
const value = this.config.dataSource?.params[p]
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return "''"
|
||||
} else if (!isNaN(value)) {
|
||||
return value || p
|
||||
} else {
|
||||
return `'${value}' || '${p}'`
|
||||
}
|
||||
})
|
||||
// eslint-disable-next-line no-new-func
|
||||
const scriptMethod = new Function(scriptAfterReplacement)
|
||||
_res.data = scriptMethod()
|
||||
} catch (error) {
|
||||
console.info('JS数据集脚本执行失败', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 将后端返回的数据保存
|
||||
if (_res.success) {
|
||||
this.updateDataset({ code: config.code, title: config.title, data: _res?.data })
|
||||
}
|
||||
config = this.dataFormatting(config, _res)
|
||||
if (this.chart) {
|
||||
// 单指标组件和多指标组件的changeData传参不同
|
||||
if (['Liquid', 'Gauge', 'RingProgress', 'Progress'].includes(config.chartType)) {
|
||||
this.chart.changeData(config.option.percent)
|
||||
} else {
|
||||
this.chart.changeData(config.option.data)
|
||||
}
|
||||
} if (this.config.type === 'candlestick' && this.charts) {
|
||||
this.updateChartData(config, _res)
|
||||
} else if (this.charts) {
|
||||
// 地图组件的被联动更新
|
||||
this.changeMapData(config.option.data)
|
||||
}
|
||||
}).catch(err => {
|
||||
console.info(err)
|
||||
}).finally(() => {
|
||||
if (config) {
|
||||
config.loading = false
|
||||
}
|
||||
resolve(config)
|
||||
})
|
||||
})
|
||||
},
|
||||
// 更新图表数据
|
||||
updateChartData() {
|
||||
|
||||
},
|
||||
// http前台代理需要对返回的数据进行重新组装
|
||||
httpDataFormatting(chartRes, httpRes) {
|
||||
let result = {}
|
||||
result = {
|
||||
columnData: chartRes.columnData,
|
||||
data: httpRes,
|
||||
success: chartRes.success
|
||||
|
||||
}
|
||||
return result
|
||||
},
|
||||
dataFormatting(config, data) {
|
||||
// 覆盖
|
||||
},
|
||||
newChart(option) {
|
||||
// 覆盖
|
||||
},
|
||||
// 通过表达式计算获取组件的值
|
||||
getDataByExpression(config) {
|
||||
// 覆盖
|
||||
},
|
||||
changeStyle(config) {
|
||||
config = { ...this.config, ...config }
|
||||
// 样式改变时更新主题配置
|
||||
config.theme = settingToTheme(cloneDeep(config), this.customTheme)
|
||||
this.changeChartConfig(config)
|
||||
if (config.code === this.activeCode) {
|
||||
this.changeActiveItemConfig(config)
|
||||
}
|
||||
},
|
||||
// 缓存组件数据监听
|
||||
watchCacheData() {
|
||||
EventBus.$on('cacheDataInit', (data, dataSetId) => {
|
||||
// 如果是缓存数据集
|
||||
// 且当前组件的businessKey和缓存的dataSetId相等时,更新组件
|
||||
if (
|
||||
this.config.dataSource.dataSetType === '2' &&
|
||||
this.config.dataSource.businessKey === dataSetId
|
||||
) {
|
||||
const config = this.dataFormatting(this.config, data)
|
||||
config.key = new Date().getTime()
|
||||
this.changeChartConfig(config)
|
||||
this.newChart(config.option)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.mqttClient.disconnect();
|
||||
},
|
||||
}
|
||||
160
frontend/packages/js/mixins/dataVMixins.js
Normal file
160
frontend/packages/js/mixins/dataVMixins.js
Normal file
@@ -0,0 +1,160 @@
|
||||
import { mapMutations, mapState } from 'vuex'
|
||||
import { settingToTheme } from 'data-room-ui/js/utils/themeFormatting'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
const dataVMixins = {
|
||||
props: {
|
||||
// 卡片的属性
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
updateKey: 0,
|
||||
borderBgId: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
customTheme: state => state.bigScreen.pageInfo.pageConfig.customTheme,
|
||||
activeCode: state => state.bigScreen.activeCode
|
||||
}),
|
||||
code () {
|
||||
return this.config.code
|
||||
},
|
||||
color () {
|
||||
return this.config.customize.borderMainColor ||
|
||||
this.config.customize.borderSecondaryColor
|
||||
? [
|
||||
this.config.customize.borderMainColor,
|
||||
this.config.customize.borderSecondaryColor
|
||||
]
|
||||
: null
|
||||
},
|
||||
backgroundColor () {
|
||||
return this.config.customize.backgroundColor
|
||||
? this.config.customize.backgroundColor
|
||||
: 'transparent'
|
||||
},
|
||||
colorType () {
|
||||
return this.config.customize.colorType
|
||||
},
|
||||
Data () {
|
||||
return JSON.parse(JSON.stringify(this.config))
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
config: {
|
||||
handler: function (val) {
|
||||
if (val && val.customize && val.customize.colorType) {
|
||||
this.changeBorderStyle(this.config)
|
||||
if (val.customize.colorType === 'single') {
|
||||
this.borderBgId = null
|
||||
this.$nextTick(() => {
|
||||
this.updateKey = new Date().getTime()
|
||||
})
|
||||
} else {
|
||||
this.borderBgId = `borderBg${this.config.code}`
|
||||
}
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
Data: {
|
||||
handler (newVal, oldVal) {
|
||||
this.$nextTick(() => {
|
||||
if ((newVal.w !== oldVal.w) || (newVal.h !== oldVal.h)) {
|
||||
this.$nextTick(() => {
|
||||
this.updateKey = new Date().getTime()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.changeBorderStyle(this.config)
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({
|
||||
changeChartConfig: 'bigScreen/changeChartConfig',
|
||||
changeActiveItemConfig: 'bigScreen/changeActiveItemConfig'
|
||||
}),
|
||||
changeStyle (config) {
|
||||
config = { ...this.config, ...config }
|
||||
// 样式改变时更新主题配置
|
||||
config.theme = settingToTheme(cloneDeep(config), this.customTheme)
|
||||
this.changeChartConfig(config)
|
||||
if (config.code === this.activeCode) {
|
||||
this.changeActiveItemConfig(config)
|
||||
}
|
||||
this.changeBorderStyle(config)
|
||||
},
|
||||
changeBorderStyle (config) {
|
||||
this.borderBgId = `borderBg${config.code}`
|
||||
if (document.querySelector(`#dataV${config.code}`)) {
|
||||
const borderElement = document.querySelector(`#dataV${config.code}`).querySelector('.border') || document.querySelector(`#dataV${config.code}`)?.querySelector('.dv-border-svg-container')
|
||||
if (borderElement) {
|
||||
let isBorder7 = false
|
||||
borderElement.childNodes.forEach(e => {
|
||||
if (e._prevClass === 'dv-bb7-line-width-2') {
|
||||
isBorder7 = true
|
||||
}
|
||||
})
|
||||
borderElement.style.opacity = (config.customize.opacity / 100)
|
||||
if (this.colorType === 'gradient') {
|
||||
if (!isBorder7) {
|
||||
let gradientDirection = ''
|
||||
switch (config.customize.gradientDirection) {
|
||||
case 'to right':
|
||||
gradientDirection = 'x1="0%" y1="0%" x2="100%" y2="0%"'
|
||||
break
|
||||
case 'to left':
|
||||
gradientDirection = 'x1="100%" y1="0%" x2="0%" y2="0%"'
|
||||
break
|
||||
case 'to bottom':
|
||||
gradientDirection = 'x1="0%" y1="0%" x2="0%" y2="100%"'
|
||||
break
|
||||
case 'to top':
|
||||
gradientDirection = 'x1="0%" y1="100%" x2="0%" y2="0%"'
|
||||
break
|
||||
case 'to bottom right':
|
||||
gradientDirection = 'x1="0%" y1="0%" x2="100%" y2="100%"'
|
||||
break
|
||||
case 'to bottom left':
|
||||
gradientDirection = 'x1="100%" y1="0%" x2="0%" y2="100%"'
|
||||
break
|
||||
case 'to top right':
|
||||
gradientDirection = 'x1="0%" y1="100%" x2="100%" y2="0%"'
|
||||
break
|
||||
case 'to top left':
|
||||
gradientDirection = 'x1="100%" y1="100%" x2="0%" y2="0%"'
|
||||
break
|
||||
default:
|
||||
gradientDirection = 'x1="0%" y1="0%" x2="100%" y2="0%"'
|
||||
break
|
||||
}
|
||||
// 在目标元素内的第一个位置插入 <defs> 和其中的内容
|
||||
borderElement.insertAdjacentHTML(
|
||||
'afterbegin',
|
||||
`<defs>
|
||||
<linearGradient id="${this.borderBgId}" ${gradientDirection}>
|
||||
<stop offset="0%" stop-color="${config.customize.gradientColor0}" />
|
||||
<stop offset="100%" stop-color="${config.customize.gradientColor1}" />
|
||||
</linearGradient>
|
||||
</defs>`
|
||||
)
|
||||
} else {
|
||||
borderElement.style.background = `linear-gradient(${config.customize.gradientDirection},${config.customize.gradientColor0}, ${config.customize.gradientColor1})`
|
||||
isBorder7 = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { dataVMixins }
|
||||
152
frontend/packages/js/mixins/datasetMixin.js
Normal file
152
frontend/packages/js/mixins/datasetMixin.js
Normal file
@@ -0,0 +1,152 @@
|
||||
// import _ from 'lodash'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
|
||||
const datasetMixins = {
|
||||
props: {
|
||||
isEdit: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
datasetId: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
datasetName: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
typeId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
appCode: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
dataForm: {},
|
||||
dataPreviewList: [],
|
||||
structurePreviewList: [],
|
||||
structurePreviewListCopy: [],
|
||||
typeName: '',
|
||||
categoryData: [],
|
||||
current: 1,
|
||||
size: 10,
|
||||
totalCount: 0,
|
||||
fieldDescVisible: false,
|
||||
fieldsetVisible: false,
|
||||
tableLoading: false,
|
||||
saveLoading: false,
|
||||
saveText: '',
|
||||
typeSelect: [
|
||||
{ value: 'String' },
|
||||
{ value: 'Integer' },
|
||||
{ value: 'Double' },
|
||||
{ value: 'Long' },
|
||||
{ value: 'Date' }
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 使用字段名填充字段描述
|
||||
*/
|
||||
fieldDescFill () {
|
||||
this.structurePreviewList.forEach(field => {
|
||||
if (field.fieldDesc === '' || !field.hasOwnProperty('fieldDesc')) {
|
||||
field.fieldDesc = field.fieldName
|
||||
}
|
||||
})
|
||||
this.save('form')
|
||||
this.fieldDescVisible = false
|
||||
},
|
||||
/**
|
||||
* 打开字段描述编辑弹窗
|
||||
*/
|
||||
fieldDescEdit () {
|
||||
this.fieldDescVisible = false
|
||||
this.fieldsetVisible = true
|
||||
},
|
||||
/**
|
||||
* 跳过字段描述编辑直接保存
|
||||
*/
|
||||
toSave () {
|
||||
this.save('form', true)
|
||||
this.fieldDescVisible = false
|
||||
},
|
||||
/**
|
||||
* 取消编辑字段
|
||||
*/
|
||||
cancelField () {
|
||||
this.structurePreviewListCopy = cloneDeep(this.structurePreviewList)
|
||||
this.fieldsetVisible = false
|
||||
},
|
||||
/**
|
||||
* 保存字段设置
|
||||
*/
|
||||
setField () {
|
||||
this.structurePreviewList = cloneDeep(this.structurePreviewListCopy)
|
||||
this.fieldsetVisible = false
|
||||
},
|
||||
/**
|
||||
* 清空分类选择
|
||||
*/
|
||||
clearType () {
|
||||
this.typeName = ''
|
||||
this.dataForm.typeId = ''
|
||||
},
|
||||
/**
|
||||
* 分类展开高亮
|
||||
* @param $event
|
||||
*/
|
||||
setCurrentNode ($event) {
|
||||
if ($event) {
|
||||
const key = this.dataForm.typeId || null
|
||||
this.$refs.categorySelectTree.setCurrentKey(key)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 分类选择
|
||||
* @param value
|
||||
*/
|
||||
selectParentCategory (value) {
|
||||
this.dataForm.typeId = value.id
|
||||
this.typeName = value.name
|
||||
this.$refs.selectParentName.blur()
|
||||
},
|
||||
goBack () {
|
||||
this.$emit('back')
|
||||
},
|
||||
// 每页大小改变触发
|
||||
sizeChangeHandle (value) {
|
||||
this.size = value
|
||||
this.current = 1
|
||||
this.datasetTest(false)
|
||||
},
|
||||
// 当前页数改变
|
||||
currentChangeHandle (value) {
|
||||
this.current = value
|
||||
this.datasetTest(false)
|
||||
const tableBodyWrapperEl = document.querySelector('.el-table__body-wrapper') || {}
|
||||
this.$nextTick(() => {
|
||||
if (tableBodyWrapperEl) {
|
||||
// 表格滚动到顶部
|
||||
tableBodyWrapperEl.scrollTop = 0
|
||||
}
|
||||
})
|
||||
},
|
||||
// 表头添加提示
|
||||
renderHeader (h, { column, index }) {
|
||||
const labelLong = column.label.length // 表头label长度
|
||||
const size = 14 // 根据需要定义标尺,直接使用字体大小确定就行,也可以根据需要定义
|
||||
column.minWidth = labelLong * size < 120 ? 120 : labelLong * size // 根据label长度计算该表头最终宽度
|
||||
return h('span', { class: 'cell-content', style: { width: '100%' } }, [column.label])
|
||||
},
|
||||
openNewWindow (url) {
|
||||
window.open(url, '_blank')
|
||||
}
|
||||
}
|
||||
}
|
||||
export { datasetMixins }
|
||||
85
frontend/packages/js/mixins/linkageMixins.js
Normal file
85
frontend/packages/js/mixins/linkageMixins.js
Normal file
@@ -0,0 +1,85 @@
|
||||
// import _ from 'lodash'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
import uniqBy from 'lodash/uniqBy'
|
||||
import { EventBus } from 'data-room-ui/js/utils/eventBus'
|
||||
import { mapMutations } from 'vuex'
|
||||
// import { getUpdateChartInfo } from '../api/bigScreenApi'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
filterList: [],
|
||||
treeParentId: 0,
|
||||
dataLoading: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations('bigScreen', {
|
||||
changeChartKey: 'changeChartKey'
|
||||
}),
|
||||
/**
|
||||
* bigScreen数据联动时根据入参的值进行数据处理
|
||||
* @param filterList 过滤条件
|
||||
* @param isInner 是否是组件内部的数据改变
|
||||
*/
|
||||
dataInit (filterList, isInner = false) {
|
||||
if (Array.isArray(filterList) && filterList.length) {
|
||||
this.filterList = filterList
|
||||
}
|
||||
filterList = this.combineFilterList(isInner).filter(
|
||||
field => ![undefined, ''].includes(field.value)
|
||||
)
|
||||
// this.dataLinkageHandle(this.config, this.pageInfo.code, filterList)
|
||||
this.changeData(this.config, filterList)
|
||||
},
|
||||
/**
|
||||
* 联动数据
|
||||
* @param {*} formData
|
||||
* */
|
||||
linkage (formData) {
|
||||
EventBus.$emit('dataInit', formData, this.config.linkage.components)
|
||||
},
|
||||
/**
|
||||
* 绑定数据
|
||||
* @param {*} formData
|
||||
* */
|
||||
// binding (formData) {
|
||||
// EventBus.$emit('dataInit', formData, this.config.binding.components)
|
||||
// },
|
||||
/**
|
||||
* 处理外部联动数据和内部联动数据,合并,如果内部搜索区的参数在外部联动,则赋值上
|
||||
* @param {Boolean} isInner 是否是内部组件
|
||||
*/
|
||||
combineFilterList (isInner = false) {
|
||||
let filterList = isInner ? [] : cloneDeep(this.filterList)
|
||||
// 如果内部组件的搜索条件不存在,则直接返回全局的filterList
|
||||
if (!this.$refs?.searchForm?.form) {
|
||||
return filterList
|
||||
}
|
||||
// 对比,如果filterList的column和内部参数innerFilterList一致,则赋值内部参数
|
||||
const form = this.$refs.searchForm.form
|
||||
const innerFilteKeyMap = Object.keys(form)
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
filterList?.map(filterItem => {
|
||||
if (innerFilteKeyMap.includes(filterItem.column)) {
|
||||
this.formData[filterItem.column] = filterItem.value
|
||||
this.$refs.searchForm.form[filterItem.column] = filterItem.value
|
||||
}
|
||||
})
|
||||
// 处理内部参数 filterList
|
||||
const innerFilterList = this.config?.fields
|
||||
?.map(field => {
|
||||
return {
|
||||
column: field.name,
|
||||
operator: field.queryRule || 'like',
|
||||
value: this.formData[field.name]
|
||||
}
|
||||
})
|
||||
.filter(field => ![undefined, ''].includes(field.value))
|
||||
// 合并去重
|
||||
filterList = [...filterList, ...innerFilterList]
|
||||
filterList = uniqBy(filterList, 'column')
|
||||
return filterList
|
||||
}
|
||||
}
|
||||
}
|
||||
145
frontend/packages/js/mixins/multipleSelectMixin.js
Normal file
145
frontend/packages/js/mixins/multipleSelectMixin.js
Normal file
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* 选中多个组件进行组合
|
||||
*/
|
||||
import { mapMutations, mapState } from 'vuex'
|
||||
let isMac = false
|
||||
if (window && window.navigator && window.navigator.userAgent) {
|
||||
isMac = window.navigator.userAgent.indexOf('Mac') > -1
|
||||
}
|
||||
export default {
|
||||
computed: {
|
||||
...mapState({
|
||||
activeCodes: (state) => state.bigScreen.activeCodes,
|
||||
activeChart: (state) => state.bigScreen.activeItemConfig
|
||||
})
|
||||
},
|
||||
mounted () {
|
||||
// 监听shift键的按下和抬起
|
||||
document.addEventListener('keydown', this.keydown)
|
||||
document.addEventListener('keyup', this.keyup)
|
||||
},
|
||||
beforeDestroy () {
|
||||
document.removeEventListener('keydown', this.keydown)
|
||||
document.removeEventListener('keyup', this.keyup)
|
||||
},
|
||||
methods: {
|
||||
...mapMutations('bigScreen', {
|
||||
changeCtrlOrCommandDown: 'changeCtrlOrCommandDown',
|
||||
changeActivePos: 'changeActivePos',
|
||||
deleteItem: 'delItem',
|
||||
undoTimeLine: 'undoTimeLine',
|
||||
copyCharts: 'copyCharts',
|
||||
pasteCharts: 'pasteCharts'
|
||||
}),
|
||||
keydown (event) {
|
||||
// 获取当前获得焦点的元素
|
||||
const activeElement = document.activeElement
|
||||
// 判断当前获得焦点的元素是否是一个输入元素
|
||||
const isInputFocused = activeElement instanceof HTMLInputElement || activeElement instanceof HTMLTextAreaElement
|
||||
if (!isInputFocused) {
|
||||
// 当前页面没有输入聚焦
|
||||
if (event.keyCode === 37) {
|
||||
// 关闭默认事件
|
||||
event.preventDefault()
|
||||
// 左箭头键被按下
|
||||
this.changeActivePos({ diffX: -1, diffY: 0 })
|
||||
} else if (event.keyCode === 38) {
|
||||
// 关闭默认事件
|
||||
event.preventDefault()
|
||||
// 上箭头键被按下
|
||||
this.changeActivePos({ diffX: 0, diffY: -1 })
|
||||
} else if (event.keyCode === 39) {
|
||||
// 关闭默认事件
|
||||
event.preventDefault()
|
||||
// 右箭头键被按下
|
||||
this.changeActivePos({ diffX: 1, diffY: 0 })
|
||||
} else if (event.keyCode === 40) {
|
||||
// 关闭默认事件
|
||||
event.preventDefault()
|
||||
// 下箭头键被按下
|
||||
this.changeActivePos({ diffX: 0, diffY: 1 })
|
||||
}
|
||||
}
|
||||
|
||||
// ctrl/command + s保存
|
||||
if ((event.ctrlKey || event.metaKey) && event.keyCode === 83) {
|
||||
// 关闭默认事件
|
||||
event.preventDefault()
|
||||
this.$refs.PageTopSetting.save('saveLoading')
|
||||
}
|
||||
// ctrl/command + z撤销
|
||||
if ((event.ctrlKey || event.metaKey) && !event.shiftKey && event.keyCode === 90) {
|
||||
event.preventDefault()
|
||||
this.undoTimeLine(true)
|
||||
}
|
||||
|
||||
// ctrl/command + shift + z 反撤销
|
||||
if ((event.ctrlKey || event.metaKey) && event.shiftKey && event.keyCode === 90) {
|
||||
event.preventDefault()
|
||||
this.undoTimeLine(false)
|
||||
}
|
||||
if (isMac) {
|
||||
// 是否按下了command键
|
||||
if (event.metaKey) {
|
||||
this.changeCtrlOrCommandDown(true)
|
||||
}
|
||||
} else {
|
||||
// 是否按下了ctrl键
|
||||
if (event.ctrlKey) {
|
||||
this.changeCtrlOrCommandDown(true)
|
||||
}
|
||||
}
|
||||
},
|
||||
keyup (event) {
|
||||
// 判断mac系统还是windows系统
|
||||
if (isMac) {
|
||||
// 是否按下了command键
|
||||
if (!event.metaKey) {
|
||||
this.changeCtrlOrCommandDown(false)
|
||||
}
|
||||
} else {
|
||||
// 是否按下了ctrl键
|
||||
if (!event.ctrlKey) {
|
||||
this.changeCtrlOrCommandDown(false)
|
||||
}
|
||||
}
|
||||
},
|
||||
designKeydown (event) {
|
||||
// 删除键被按下且鼠标没有在输入框中
|
||||
if (
|
||||
(event.keyCode === 8 || event.keyCode === 46) &&
|
||||
!event.target.classList.contains('el-input__inner')
|
||||
) {
|
||||
// 关闭默认事件
|
||||
event.preventDefault()
|
||||
// 如果没有选中任何组件的话则不弹出删除提示框
|
||||
if (!this.activeCodes.length) {
|
||||
return
|
||||
}
|
||||
this.$confirm('确定删除该组件吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
customClass: 'bs-el-message-box'
|
||||
}).then(() => {
|
||||
// 批量删除
|
||||
if (Array.isArray(this.activeCodes) && this.activeCodes.length > 0) {
|
||||
this.deleteItem(this.activeCodes)
|
||||
} else {
|
||||
// 单个删除
|
||||
this.deleteItem(this.activeChart)
|
||||
}
|
||||
}).catch(() => {})
|
||||
}
|
||||
// ctrl/command + c复制
|
||||
if ((event.ctrlKey || event.metaKey) && event.keyCode === 67) {
|
||||
this.copyCharts()
|
||||
}
|
||||
|
||||
if ((event.ctrlKey || event.metaKey) && event.keyCode === 86) {
|
||||
// 粘贴
|
||||
this.pasteCharts()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
136
frontend/packages/js/mixins/page.js
Normal file
136
frontend/packages/js/mixins/page.js
Normal file
@@ -0,0 +1,136 @@
|
||||
// 分页,分页几乎每个列表页面都会存在,代码的重合度很高,所以提出来了
|
||||
const pageMixins = {
|
||||
data () {
|
||||
return {
|
||||
// 当前页
|
||||
current: 1,
|
||||
// 每页大小
|
||||
size: 10,
|
||||
// 总页数
|
||||
totalPage: 0,
|
||||
// 总数据条数
|
||||
totalCount: 0,
|
||||
prevText: '',
|
||||
nextText: '',
|
||||
// 排序相关
|
||||
sortForm: {
|
||||
/**
|
||||
* key: 字段名称
|
||||
* value: descending 、ascending、''
|
||||
*/
|
||||
sortFieldMap: {},
|
||||
// 定义排序字段的排序,如果不支持多个字段同时排序,可以传入一个即可
|
||||
sortFieldOrderList: [],
|
||||
// 缓存列和类名信息,方便后面清空排序字段信息
|
||||
columnCacheMap: {}
|
||||
},
|
||||
// 允许多字段排序
|
||||
enableMultiFieldOrder: false,
|
||||
sortFieldHeaderTipMap: {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'sortForm.sortFieldMap': {
|
||||
handler (sortFieldMap, oldV) {
|
||||
for (const columnName in sortFieldMap) {
|
||||
const order = sortFieldMap[columnName]
|
||||
if (!order) {
|
||||
this.$set(this.sortFieldHeaderTipMap, columnName, '点击升序')
|
||||
} else if (order === 'ascending') {
|
||||
this.$set(this.sortFieldHeaderTipMap, columnName, '点击降序')
|
||||
} else if (order === 'descending') {
|
||||
this.$set(this.sortFieldHeaderTipMap, columnName, '取消排序')
|
||||
} else {
|
||||
this.$set(this.sortFieldHeaderTipMap, columnName, '点击升序')
|
||||
}
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 初始化排序信息
|
||||
* @param sortFieldOrderList 排序字段的优先级
|
||||
* @param defaultSortFieldMap 默认排序字段信息 descending: 降序,ascending:升序
|
||||
*/
|
||||
initSortField (sortFieldOrderList = [], defaultSortFieldMap = {}) {
|
||||
if (defaultSortFieldMap) {
|
||||
for (const field in defaultSortFieldMap) {
|
||||
const order = defaultSortFieldMap[field]
|
||||
this.$set(this.sortForm.sortFieldMap, field, order)
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < sortFieldOrderList.length; i++) {
|
||||
const field = sortFieldOrderList[i]
|
||||
const order = this.sortForm.sortFieldMap[field]
|
||||
if (!order) {
|
||||
// 解决未设置默认排序值字段提示为空
|
||||
this.$set(this.sortForm.sortFieldMap, field, '')
|
||||
}
|
||||
}
|
||||
this.sortForm.sortFieldOrderList = sortFieldOrderList
|
||||
},
|
||||
// 排序状态记录并激活,否则和页面上的排序对不上
|
||||
sortStyle ({ row, column, rowIndex, columnIndex }) {
|
||||
const sortColumnOrder = this.sortForm.sortFieldMap[column.property]
|
||||
if (sortColumnOrder) {
|
||||
column.order = sortColumnOrder
|
||||
}
|
||||
this.sortForm.columnCacheMap[column.property] = column
|
||||
},
|
||||
// 对应表格的 @sort-change 事件,当用户改变了排序的状态时触发
|
||||
reSort (column) {
|
||||
if (!this.enableMultiFieldOrder) {
|
||||
// 不允许多个字段同时排序,清空之前的排序信息
|
||||
for (const field in this.sortForm.columnCacheMap) {
|
||||
const column = this.sortForm.columnCacheMap[field]
|
||||
column.order = ''
|
||||
}
|
||||
for (const field in this.sortForm.sortFieldMap) {
|
||||
this.sortForm.sortFieldMap[field] = ''
|
||||
}
|
||||
}
|
||||
this.$set(this.sortForm.sortFieldMap, column.prop, column.order)
|
||||
this.reSearch()
|
||||
},
|
||||
reSearch () {
|
||||
this.current = 1
|
||||
this.getDataList()
|
||||
},
|
||||
getDataList () {
|
||||
console.error('你应该重写getDataList方法')
|
||||
},
|
||||
// 每页大小改变触发
|
||||
sizeChangeHandle (val) {
|
||||
this.size = val
|
||||
this.current = 1
|
||||
this.getDataList()
|
||||
},
|
||||
// 当前页数改变
|
||||
currentChangeHandle (val) {
|
||||
this.current = val
|
||||
this.getDataList()
|
||||
const bsScrollbarEl = document.querySelector('.bs-scrollbar') || {}
|
||||
const tableBodyWrapperEl = document.querySelector('.el-table__body-wrapper') || {}
|
||||
this.$nextTick(() => {
|
||||
if (bsScrollbarEl) {
|
||||
// 类名bs-scrollbar的元素滚动到顶部
|
||||
bsScrollbarEl.scrollTop = 0
|
||||
}
|
||||
if (tableBodyWrapperEl) {
|
||||
// 表格滚动到顶部
|
||||
tableBodyWrapperEl.scrollTop = 0
|
||||
}
|
||||
})
|
||||
},
|
||||
getSortForm () {
|
||||
return {
|
||||
sortFieldMap: this.sortForm.sortFieldMap,
|
||||
sortFieldOrderList: this.sortForm.sortFieldOrderList
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { pageMixins }
|
||||
13
frontend/packages/js/mixins/paramsMixins.js
Normal file
13
frontend/packages/js/mixins/paramsMixins.js
Normal file
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* @description: 封装组件内部的非props外部参数
|
||||
*/
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
computed: {
|
||||
...mapState('bigScreen', {
|
||||
pageInfo: state => state.pageInfo,
|
||||
customTheme: state => state.pageInfo.pageConfig.customTheme,
|
||||
themeJson: state => state.pageInfo.pageConfig?.themeJson
|
||||
})
|
||||
}
|
||||
}
|
||||
28
frontend/packages/js/mixins/refreshBorder.js
Normal file
28
frontend/packages/js/mixins/refreshBorder.js
Normal file
@@ -0,0 +1,28 @@
|
||||
const refreshBorder = {
|
||||
data () {
|
||||
return {
|
||||
updateKey: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
Data () {
|
||||
return JSON.parse(JSON.stringify(this.config))
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
Data: {
|
||||
handler (newVal, oldVal) {
|
||||
this.$nextTick(() => {
|
||||
if ((newVal.w !== oldVal.w) || (newVal.h !== oldVal.h)) {
|
||||
this.updateKey = new Date().getTime()
|
||||
}
|
||||
})
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
|
||||
export { refreshBorder }
|
||||
49
frontend/packages/js/mixins/refreshComponent.js
Normal file
49
frontend/packages/js/mixins/refreshComponent.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import { mapMutations, mapState } from 'vuex'
|
||||
import { settingToTheme } from 'data-room-ui/js/utils/themeFormatting'
|
||||
import cloneDeep from "lodash/cloneDeep";
|
||||
const refreshComponentMixin = {
|
||||
data () {
|
||||
return {
|
||||
updateKey: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
customTheme: state => state.bigScreen.pageInfo.pageConfig.customTheme,
|
||||
activeCode: state => state.bigScreen.activeCode
|
||||
}),
|
||||
Data () {
|
||||
return JSON.parse(JSON.stringify(this.config))
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
Data: {
|
||||
handler (newVal, oldVal) {
|
||||
this.$nextTick(() => {
|
||||
if ((newVal.w !== oldVal.w) || (newVal.h !== oldVal.h)) {
|
||||
this.updateKey = new Date().getTime()
|
||||
}
|
||||
})
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({
|
||||
changeChartConfig: 'bigScreen/changeChartConfig',
|
||||
changeActiveItemConfig: 'bigScreen/changeActiveItemConfig'
|
||||
}),
|
||||
// 修改样式
|
||||
changeStyle (config) {
|
||||
config = { ...this.config, ...config }
|
||||
// 样式改变时更新主题配置
|
||||
config.theme = settingToTheme(cloneDeep(config), this.customTheme)
|
||||
this.changeChartConfig(config)
|
||||
if (config.code === this.activeCode) {
|
||||
this.changeActiveItemConfig(config)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { refreshComponentMixin }
|
||||
266
frontend/packages/js/store/actions.js
Normal file
266
frontend/packages/js/store/actions.js
Normal file
@@ -0,0 +1,266 @@
|
||||
// 组件配置转化
|
||||
// import _ from 'lodash'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
import { setModules, dataModules } from 'data-room-ui/js/utils/configImport'
|
||||
import { getScreenInfo, getDataSetDetails, getDataByDataSetId } from '../api/bigScreenApi'
|
||||
import plotSettings from 'data-room-ui/G2Plots/settings'
|
||||
import echartSettings from 'data-room-ui/Echarts/settings'
|
||||
import { stringToFunction } from '../utils/evalFunctions'
|
||||
import { EventBus } from '../utils/eventBus'
|
||||
import plotList from 'data-room-ui/G2Plots/plotList'
|
||||
import { settingToTheme, themeToSetting } from 'data-room-ui/js/utils/themeFormatting'
|
||||
|
||||
export default {
|
||||
// 初始化页面数据
|
||||
initLayout ({ commit, dispatch }, code) {
|
||||
return new Promise(resolve => {
|
||||
getScreenInfo(code).then(data => {
|
||||
// 配置兼容
|
||||
const pageInfo = handleResData(data)
|
||||
// 兼容边框配置
|
||||
pageInfo.chartList.forEach((chart) => {
|
||||
// 对数据源的方式进行兼容
|
||||
if (chart.dataSource && ['texts', 'numbers'].includes(chart.type)) {
|
||||
if (chart.dataSource.source === 'dataset' && (!chart.dataSource.businessKey)) {
|
||||
chart.dataSource.source = 'static'
|
||||
}
|
||||
} else if (!chart.dataSource.source) {
|
||||
chart.dataSource.source = 'dataset'
|
||||
}
|
||||
|
||||
if (!chart.border) {
|
||||
chart.border = { type: '', titleHeight: 60, fontSize: 16, isTitle: true, padding: [0, 0, 0, 0] }
|
||||
}
|
||||
if (!chart.border.padding) {
|
||||
chart.border.padding = [0, 0, 0, 0]
|
||||
}
|
||||
const plotSettingsIterator = false
|
||||
const echartSettingsIterator = false
|
||||
if (chart.type === 'customComponent') {
|
||||
// 为本地G2组件配置添加迭代器
|
||||
if (!plotSettingsIterator) {
|
||||
plotSettings[Symbol.iterator] = function * () {
|
||||
const keys = Object.keys(plotSettings)
|
||||
for (const k of keys) {
|
||||
yield [k, plotSettings[k]]
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const [key, localPlotSetting] of plotSettings) {
|
||||
if (chart.name == localPlotSetting.name) {
|
||||
// 本地配置项
|
||||
const localSettings = JSON.parse(JSON.stringify(localPlotSetting.setting))
|
||||
chart.setting = localSettings.map((localSet) => {
|
||||
// 在远程组件配置中找到 与 本地组件的配置项 相同的项索引
|
||||
const index = chart.setting.findIndex(remoteSet => remoteSet.field == localSet.field)
|
||||
if (index !== -1) {
|
||||
// 使用远程的值替换本地值
|
||||
localSet.field = chart.setting[index].field
|
||||
localSet.value = chart.setting[index].value
|
||||
}
|
||||
return localSet
|
||||
})
|
||||
}
|
||||
}
|
||||
} else if (chart.type === 'echartsComponent') {
|
||||
// 为本地echarts组件配置添加迭代器
|
||||
if (!echartSettingsIterator) {
|
||||
echartSettings[Symbol.iterator] = function * () {
|
||||
const keys = Object.keys(echartSettings)
|
||||
for (const k of keys) {
|
||||
yield [k, echartSettings[k]]
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const [key, localPlotSetting] of echartSettings) {
|
||||
if (chart.name == localPlotSetting.name) {
|
||||
// 本地配置项
|
||||
const localSettings = JSON.parse(JSON.stringify(localPlotSetting.setting))
|
||||
chart.setting = localSettings.map((localSet) => {
|
||||
// 在远程组件配置中找到 与 本地组件的配置项 相同的项索引
|
||||
const index = chart.setting.findIndex(remoteSet => remoteSet.field == localSet.field)
|
||||
if (index !== -1) {
|
||||
// 使用远程的值替换本地值
|
||||
localSet.field = chart.setting[index].field
|
||||
localSet.value = chart.setting[index].value
|
||||
}
|
||||
return localSet
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 改变页面数据
|
||||
commit('changePageInfo', pageInfo)
|
||||
commit('changeZIndex', pageInfo.chartList)
|
||||
// 初始化缓存数据集数据
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
pageInfo.pageConfig.cacheDataSets?.map((cacheDataSet) => {
|
||||
dispatch('getCacheDataSetData', { dataSetId: cacheDataSet.dataSetId })
|
||||
dispatch('getCacheDataFields', { dataSetId: cacheDataSet.dataSetId })
|
||||
})
|
||||
// 页面加载成功
|
||||
resolve(true)
|
||||
commit('saveTimeLine', '初始化')
|
||||
})
|
||||
})
|
||||
},
|
||||
// 初始化缓存数据集数据
|
||||
getCacheDataSetData ({ commit, dispatch }, { dataSetId }) {
|
||||
getDataByDataSetId(dataSetId).then(res => {
|
||||
const data = res.data
|
||||
commit('changeCacheDataSetData', { dataSetId, data })
|
||||
// 推送数据到各个组件
|
||||
emitDataToChart(dataSetId, data)
|
||||
})
|
||||
},
|
||||
// 初始化缓存数据集字段
|
||||
getCacheDataFields ({ commit, dispatch }, { dataSetId }) {
|
||||
getDataSetDetails(dataSetId).then(data => {
|
||||
commit('changeCacheDataFields', { dataSetId, data })
|
||||
commit('changeCacheDataParams', { dataSetId, data })
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 处理后端返回的数据
|
||||
export function handleResData (data) {
|
||||
let pageInfo = {}
|
||||
if (data.pageConfig) {
|
||||
pageInfo = {
|
||||
...data,
|
||||
pageConfig: {
|
||||
...data.pageConfig,
|
||||
lightBgColor: data.pageConfig.lightBgColor || '#f5f7fa'
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pageInfo = {
|
||||
...data,
|
||||
pageConfig: {
|
||||
w: 1920,
|
||||
h: 1080,
|
||||
bgColor: '#151a26', // 背景色
|
||||
lightBgColor: '#f5f7fa',
|
||||
lightBg: '',
|
||||
bg: '', // 背景图
|
||||
customTheme: 'dark',
|
||||
opacity: 100
|
||||
}
|
||||
}
|
||||
}
|
||||
// 如果pageConfig中的cacheDataSets为null,赋值[]
|
||||
pageInfo.pageConfig.cacheDataSets = pageInfo.pageConfig.cacheDataSets || []
|
||||
pageInfo.pageConfig.refreshConfig = pageInfo.pageConfig.refreshConfig || []
|
||||
let originalConfig = {}
|
||||
pageInfo.chartList.forEach((chart) => {
|
||||
if (!['customComponent', 'remoteComponent', 'echartsComponent'].includes(chart.type)) {
|
||||
originalConfig = { option: { ...setModules[chart.type] }, ...dataModules[chart.type] }
|
||||
// 如果没有版本号,或者版本号修改了则需要进行旧数据兼容
|
||||
if ((!chart.version) || chart.version !== originalConfig.version) {
|
||||
chart = compatibility(chart, originalConfig)
|
||||
} else {
|
||||
chart.option = cloneDeep(setModules[chart.type])
|
||||
}
|
||||
} else {
|
||||
originalConfig = plotList?.find(plot => plot.name === chart.name)
|
||||
chart.option = stringToFunction(chart.option)
|
||||
// 如果是自定义组件,且没配数据集,就给前端的模拟数据
|
||||
if (!chart?.dataSource?.businessKey) {
|
||||
chart.option.data = plotList?.find(plot => plot.name === chart.name)?.option?.data || chart?.option?.data
|
||||
}
|
||||
// 如果没有版本号,或者版本号修改了则需要进行旧数据兼容
|
||||
if ((!chart.version) || (originalConfig && chart.version !== originalConfig?.version)) {
|
||||
// TODO 远程组件需要重新写处理函数
|
||||
if (chart.type === 'customComponent') {
|
||||
chart = compatibility(chart, originalConfig)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 初始化时应该判断,是否存在theme配置,没有的话添加默认的两套主题,这是为了兼容旧组件
|
||||
if (!chart.theme) {
|
||||
chart.theme = settingToTheme(chart, 'dark')
|
||||
chart.theme = settingToTheme(chart, 'light')
|
||||
}
|
||||
chart.key = chart.code
|
||||
})
|
||||
// 主题兼容
|
||||
// pageInfo.chartList = themeToSetting(pageInfo.chartList, pageInfo.pageConfig.customTheme)
|
||||
// 存储修改后的配置
|
||||
localStorage.setItem('pageInfo', JSON.stringify(pageInfo))
|
||||
return pageInfo
|
||||
}
|
||||
|
||||
// 组件属性兼容
|
||||
function compatibility (config, originalConfig) {
|
||||
const newConfig = config
|
||||
newConfig.version = originalConfig?.version || '2023071001'
|
||||
newConfig.optionHandler = originalConfig.optionHandler || ''
|
||||
newConfig.dataSource = objCompare(newConfig?.dataSource, originalConfig?.dataSource)
|
||||
newConfig.customize = objCompare(newConfig?.customize, originalConfig?.customize)
|
||||
newConfig.option = {
|
||||
...objCompare(newConfig.option, originalConfig?.option),
|
||||
displayOption: originalConfig?.option?.displayOption
|
||||
}
|
||||
newConfig.setting = arrCompare(newConfig?.setting, originalConfig?.setting)
|
||||
return newConfig
|
||||
}
|
||||
|
||||
// 对象比较
|
||||
function objCompare (obj1, obj2) {
|
||||
const keys1 = obj1 ? Object.keys(obj1) : []
|
||||
const keys2 = obj2 ? Object.keys(obj2) : []
|
||||
// 交集
|
||||
const intersection = keys1?.filter(function (v) {
|
||||
return keys2.indexOf(v) > -1
|
||||
}) || []
|
||||
// 差集
|
||||
const differenceSet = keys2?.filter(function (v) {
|
||||
return keys1.indexOf(v) === -1
|
||||
}) || []
|
||||
const obj = {}
|
||||
for (const item of intersection) {
|
||||
obj[item] = obj1[item]
|
||||
}
|
||||
for (const item of differenceSet) {
|
||||
obj[item] = obj2[item]
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
// 数组比较
|
||||
function arrCompare (list1, list2) {
|
||||
const fieldList = list1?.map(item => item.field) || []
|
||||
const list = list2?.map(item => {
|
||||
let value = null
|
||||
// 如果存在交集
|
||||
if (fieldList.includes(item.field)) {
|
||||
// 保留旧数据的value
|
||||
value = (list1.filter(j => {
|
||||
return j.field === item.field
|
||||
}))[0].value
|
||||
} else {
|
||||
// 不存在交集,直接覆盖
|
||||
value = item.value
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
value
|
||||
}
|
||||
}) || []
|
||||
return list
|
||||
}
|
||||
|
||||
// 推送数据到各个组件
|
||||
function emitDataToChart (dataSetId, data) {
|
||||
if (data && data.length) {
|
||||
EventBus.$emit('cacheDataInit',
|
||||
{
|
||||
success: true,
|
||||
data: data
|
||||
},
|
||||
dataSetId
|
||||
)
|
||||
}
|
||||
}
|
||||
3
frontend/packages/js/store/getters.js
Normal file
3
frontend/packages/js/store/getters.js
Normal file
@@ -0,0 +1,3 @@
|
||||
export default {
|
||||
|
||||
}
|
||||
12
frontend/packages/js/store/index.js
Normal file
12
frontend/packages/js/store/index.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import state from './state'
|
||||
import mutations from './mutations'
|
||||
import actions from './actions'
|
||||
import getters from './getters'
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
mutations,
|
||||
actions,
|
||||
getters
|
||||
}
|
||||
3
frontend/packages/js/store/mutation-types.js
Normal file
3
frontend/packages/js/store/mutation-types.js
Normal file
@@ -0,0 +1,3 @@
|
||||
// 使用常量替代 mutation 事件类型在各种 Flux 实现中是很常见的模式。
|
||||
// 这样可以使 linter 之类的工具发挥作用,
|
||||
// 同时把这些常量放在单独的文件中可以让你的代码合作者对整个 app 包含的 mutation 一目了然:
|
||||
512
frontend/packages/js/store/mutations.js
Normal file
512
frontend/packages/js/store/mutations.js
Normal file
@@ -0,0 +1,512 @@
|
||||
/*
|
||||
* @description: vuex mutations 事件
|
||||
* @Date: 2023-03-13 10:04:59
|
||||
* @Author: xing.heng
|
||||
* @LastEditors: xing.heng
|
||||
* @LastEditTime: 2023-06-08 15:24:01
|
||||
*/
|
||||
|
||||
import Vue from 'vue'
|
||||
// import _ from 'lodash'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
import uniq from 'lodash/uniq'
|
||||
import { defaultData } from './state'
|
||||
import moment from 'moment'
|
||||
import { randomString } from 'data-room-ui/js/utils'
|
||||
import { EventBus } from 'data-room-ui/js/utils/eventBus'
|
||||
import CloneDeep from 'lodash-es/cloneDeep'
|
||||
export default {
|
||||
// 改变页面基本信息,后端请求的页面信息存储到此处
|
||||
changePageInfo (state, pageInfo) {
|
||||
state.pageInfo = pageInfo
|
||||
},
|
||||
// 改变组件列表
|
||||
changeLayout (state, layout) {
|
||||
state.pageInfo.chartList = layout
|
||||
},
|
||||
//
|
||||
changeIframeDialog (state, dialogVisible) {
|
||||
state.iframeDialog = dialogVisible
|
||||
},
|
||||
// 改变当前选择组件id
|
||||
changeActiveCode (state, code) {
|
||||
state.activeCode = code
|
||||
state.hoverCode = code
|
||||
let activeItem = {}
|
||||
// let activeItem = cloneDeep(state.pageInfo.chartList?.find(
|
||||
// item => item.code === code
|
||||
// ))
|
||||
for (const item of state.pageInfo.chartList) {
|
||||
// 检查当前项的 code 是否与 currentCode 匹配
|
||||
if (item.code === code) {
|
||||
activeItem = item
|
||||
break // 找到匹配的项后,退出循环
|
||||
}
|
||||
// 如果当前项的 type 为 'chartTab',则进一步检查其 tabList
|
||||
if (item.type === 'chartTab') {
|
||||
for (const tabItem of item.customize.tabList) {
|
||||
// 检查 tabList 中的每一项的 code 是否与 currentCode 匹配
|
||||
if (tabItem.chartCode === code) {
|
||||
activeItem = tabItem.chart
|
||||
break // 找到匹配的项后,退出循环
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
changeGroup(code, state)
|
||||
state.activeItemConfig = cloneDeep(activeItem)
|
||||
},
|
||||
changeActiveCodes (state, codes) {
|
||||
// 传入codes,将codes中的组件的group改为tempGroup,不传入或者传入空数组,将所有组件的group改为'',即取消组合
|
||||
if (codes.length !== 0) {
|
||||
state.activeCodes = codes
|
||||
state.pageInfo.chartList = state.pageInfo.chartList?.map(chart => {
|
||||
return {
|
||||
...chart,
|
||||
group: (codes.includes(chart.code) && !chart.group) ? 'tempGroup' : chart.group
|
||||
}
|
||||
})
|
||||
} else {
|
||||
state.activeCodes = codes
|
||||
state.pageInfo.chartList = state.pageInfo.chartList?.map(chart => {
|
||||
return {
|
||||
...chart,
|
||||
// 确保取消高亮状态时不会使得原本设置过的组合被取消
|
||||
group: chart.group === 'tempGroup' ? '' : chart.group
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
// 情况页面选中的组件
|
||||
clearActiveCodes (state) {
|
||||
state.activeCodes = []
|
||||
},
|
||||
// 改变当前hover组件id
|
||||
changeHoverCode (state, code) {
|
||||
state.hoverCode = code
|
||||
},
|
||||
// 改变当前选中组件id
|
||||
changePageLoading (state, booleanValue) {
|
||||
// 改变loading状态
|
||||
state.pageLoading = booleanValue
|
||||
},
|
||||
// 改变当前组件的加载状态
|
||||
changeChartLoading (state, itemConfig) {
|
||||
// 改变loading状态
|
||||
state.pageInfo.chartList.forEach((chart, index) => {
|
||||
if (chart.code === itemConfig.code) {
|
||||
chart.loading = itemConfig.loading
|
||||
}
|
||||
})
|
||||
},
|
||||
// 改变当前组件配置
|
||||
changeChartConfig (state, itemConfig) {
|
||||
// 如果存在parentCode的组件,则是tab中的组件
|
||||
if (itemConfig?.parentCode) {
|
||||
state.pageInfo.chartList.forEach((chart, index) => {
|
||||
if (chart.code === itemConfig.parentCode) {
|
||||
chart.customize.tabList.forEach((tabItem, i) => {
|
||||
if (tabItem.chartCode === itemConfig.code) {
|
||||
Vue.set(state.pageInfo.chartList[index].customize.tabList[i], 'chart', {
|
||||
...state.pageInfo.chartList[index].customize.tabList[i].chart,
|
||||
...itemConfig
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// 如果是一般的组件
|
||||
let index = null
|
||||
index = state.pageInfo.chartList.findIndex(
|
||||
item => item.code === itemConfig.code
|
||||
)
|
||||
Vue.set(state.pageInfo.chartList, index, {
|
||||
...state.pageInfo.chartList[index],
|
||||
...itemConfig
|
||||
})
|
||||
// 对比之前的config和当前的itemConfig的xywh,如果有变化,就改变卡尺对齐线
|
||||
const oldConfig = state.pageInfo.chartList[index]
|
||||
if (
|
||||
oldConfig.x !== itemConfig.x ||
|
||||
oldConfig.y !== itemConfig.y ||
|
||||
oldConfig.w !== itemConfig.w ||
|
||||
oldConfig.h !== itemConfig.h
|
||||
) {
|
||||
// 改变当前组件的卡尺对齐线
|
||||
changePresetLine(state, itemConfig)
|
||||
}
|
||||
}
|
||||
},
|
||||
setPresetLine (state, { x, y, w, h }) {
|
||||
state.presetLine = [
|
||||
{ type: 'h', site: y || 0 },
|
||||
{ type: 'v', site: x || 0 }
|
||||
]
|
||||
},
|
||||
changeActiveItemConfig (state, config) {
|
||||
state.activeItemConfig = cloneDeep(config)
|
||||
},
|
||||
// 新增一个组件
|
||||
addItem (state, itemConfig) {
|
||||
// 放到第一项
|
||||
state.pageInfo.chartList.unshift(itemConfig)
|
||||
changeZIndexFuc(state, state.pageInfo.chartList)
|
||||
saveTimeLineFunc(state, '新增组件' + itemConfig?.title)
|
||||
},
|
||||
// 删除组件/批量删除组件
|
||||
delItem (state, codes) {
|
||||
if (Array.isArray(codes)) {
|
||||
const delCharts = state.pageInfo.chartList.filter(chart => codes.includes(chart.code))
|
||||
// 如果删除的组件中有跑马灯,需要删除将跑马灯组件的音频实例销毁
|
||||
delCharts.some(item => { item.type === 'marquee' && EventBus.$emit('deleteComponent', item.code) })
|
||||
state.pageInfo.chartList = state.pageInfo.chartList.filter(chart => !codes.includes(chart.code))
|
||||
} else {
|
||||
// 如果删除的组件是跑马灯,需要删除将跑马灯组件的音频实例销毁
|
||||
const delChart = state.pageInfo.chartList.find(chart => codes === chart.code)
|
||||
if (delChart && delChart.type === 'marquee') {
|
||||
EventBus.$emit('deleteComponent', codes)
|
||||
}
|
||||
state.pageInfo.chartList = state.pageInfo.chartList.filter(chart => codes !== chart.code)
|
||||
// 删除组件时,将该组件的缓存数据库中的数据也删除
|
||||
deldataset(state, 'dataset', codes)
|
||||
deldataset(state, 'computedDatas', codes)
|
||||
}
|
||||
// 存储删除后的状态
|
||||
saveTimeLineFunc(state, '删除组件')
|
||||
if (state.pageInfo.chartList.findIndex(item => item.code === state.activeCode) == -1) {
|
||||
state.activeItemConfig = null
|
||||
state.activeCode = null
|
||||
EventBus.$emit('closeRightPanel')
|
||||
}
|
||||
// 发送事件,关闭配置面板
|
||||
},
|
||||
changePageConfig (state, pageConfig) {
|
||||
Vue.set(state.pageInfo, 'pageConfig', cloneDeep(pageConfig))
|
||||
state.updateKey = new Date().getTime()
|
||||
},
|
||||
changeActiveItem (state, activeItem) {
|
||||
state.activeItem = cloneDeep(activeItem)
|
||||
state.activeId = activeItem.code
|
||||
// state.settingJson = cloneDeep(activeItem.settingConfig) || {}
|
||||
},
|
||||
// 改变当前组件的xywh
|
||||
changeActiveItemWH (state, chart) {
|
||||
if (chart.code === state.activeItemConfig.code) {
|
||||
state.activeItemConfig = {
|
||||
...state.activeItemConfig,
|
||||
...chart
|
||||
}
|
||||
}
|
||||
},
|
||||
// 清空卡尺对齐线
|
||||
resetPresetLine (state) {
|
||||
state.presetLine = []
|
||||
},
|
||||
// 改变组件的层级
|
||||
changeZIndex (state, list) {
|
||||
changeZIndexFuc(state, list)
|
||||
},
|
||||
// 改变锁定状态
|
||||
changeLocked (state, config) {
|
||||
// 如果是多选,则改变框选中的所有组件的锁定状态
|
||||
if (state.activeCodes && state.activeCodes.length > 1) {
|
||||
state.pageInfo.chartList = state.pageInfo.chartList?.map(chart => {
|
||||
return {
|
||||
...chart,
|
||||
locked: state.activeCodes.includes(chart.code) ? !config.locked : chart.locked
|
||||
}
|
||||
})
|
||||
saveTimeLineFunc(state, config.locked ? '解锁选中组件' : '锁定选中组件')
|
||||
} else {
|
||||
// 如果不是多选,则只改变当前一个
|
||||
const index = state.pageInfo.chartList.findIndex(
|
||||
item => item.code === config.code
|
||||
)
|
||||
Vue.set(state.pageInfo.chartList[index], 'locked', !config.locked)
|
||||
saveTimeLineFunc(state, !config.locked ? `解锁${config?.title}` : `锁定${config?.title}`)
|
||||
}
|
||||
},
|
||||
// 改变网格显示状态
|
||||
changeGridShow (state, isShow) {
|
||||
state.hasGrid = isShow
|
||||
},
|
||||
// 改变组件的key
|
||||
changeChartKey (state, code) {
|
||||
const index = state.pageInfo.chartList.findIndex(
|
||||
item => item.code === code
|
||||
)
|
||||
if (index < 0) {
|
||||
return
|
||||
}
|
||||
const config = state.pageInfo.chartList[index]
|
||||
Vue.set(config, 'key', config.code + new Date().getTime())
|
||||
},
|
||||
// 改变缓存数据集中的字段列表
|
||||
changeCacheDataFields (state, { dataSetId, data }) {
|
||||
// 将 state.pageInfo.pageConfig.cacheDataSets 中的 dataSetId 对应fields字段数据替换为 data
|
||||
const index = state.pageInfo.pageConfig.cacheDataSets.findIndex(cacheData => cacheData.dataSetId === dataSetId)
|
||||
if (index < 0) {
|
||||
return
|
||||
}
|
||||
Vue.set(state.pageInfo.pageConfig.cacheDataSets[index], 'fields', data?.fields || [])
|
||||
},
|
||||
// 改变缓存数据集中的数据参数
|
||||
changeCacheDataParams (state, { dataSetId, data }) {
|
||||
// 将 state.pageInfo.pageConfig.cacheDataSets 中的 dataSetId 对应fields字段数据替换为 data
|
||||
const index = state.pageInfo.pageConfig.cacheDataSets.findIndex(cacheData => cacheData.dataSetId === dataSetId)
|
||||
if (index < 0) {
|
||||
return
|
||||
}
|
||||
Vue.set(state.pageInfo.pageConfig.cacheDataSets[index], 'params', data?.params || [])
|
||||
},
|
||||
// 改变缓存数据集中的数据
|
||||
changeCacheDataSetData (state, { dataSetId, data }) {
|
||||
const index = state.pageInfo.pageConfig.cacheDataSets.findIndex(cacheData => cacheData.dataSetId === dataSetId)
|
||||
if (index < 0) {
|
||||
return
|
||||
}
|
||||
state.pageInfo.pageConfig.cacheDataSets[index].data = data || []
|
||||
},
|
||||
// 改变shift是否被按下
|
||||
changeCtrlOrCommandDown (state, isDown) {
|
||||
state.shiftKeyDown = isDown
|
||||
},
|
||||
// 初始化store中的数据,防止污染
|
||||
resetStoreData (state) {
|
||||
for (const stateKey in state) {
|
||||
state[stateKey] = cloneDeep(defaultData[stateKey])
|
||||
}
|
||||
},
|
||||
changeZoom (state, zoom) {
|
||||
state.zoom = zoom
|
||||
},
|
||||
changeFitZoom (state, zoom) {
|
||||
state.fitZoom = zoom
|
||||
},
|
||||
changeActivePos (state, { diffX, diffY }) {
|
||||
const activeCodes = state.activeCodes
|
||||
activeCodes?.forEach(code => {
|
||||
const chart = state.pageInfo.chartList.find(item => item.code === code)
|
||||
if (chart) {
|
||||
chart.x += diffX
|
||||
chart.y += diffY
|
||||
}
|
||||
const index = state.pageInfo.chartList.findIndex(
|
||||
item => item.code === chart.code
|
||||
)
|
||||
if (index < 0) {
|
||||
return
|
||||
}
|
||||
Vue.set(state.pageInfo.chartList, index, {
|
||||
...state.pageInfo.chartList[index],
|
||||
...chart
|
||||
})
|
||||
changePresetLine(state, chart)
|
||||
})
|
||||
},
|
||||
// 保存当前状态
|
||||
saveTimeLine (state, title) {
|
||||
const date = new Date()
|
||||
const time = moment(date).format('HH:mm:ss')
|
||||
// title默认获取当前时间,时分秒
|
||||
if (!title) {
|
||||
const date = new Date()
|
||||
title = `${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`
|
||||
}
|
||||
saveTimeLineFunc(state, title, time)
|
||||
},
|
||||
// 撤回/反撤回当前事件线 (undo和redo放到一个函数中,用isUndo区分)
|
||||
undoTimeLine (state, isUndo = true) {
|
||||
let currentStore = {}
|
||||
// 撤回
|
||||
if (isUndo) {
|
||||
if (state.timelineStore.length > 0 && state.currentTimeLine > 1) {
|
||||
// 时间线往前推一个
|
||||
state.currentTimeLine = state.currentTimeLine - 1
|
||||
currentStore = state.timelineStore[state.currentTimeLine - 1]
|
||||
if (currentStore?.chartList) {
|
||||
state.pageInfo.chartList = cloneDeep(currentStore?.chartList)
|
||||
state.activeItemConfig = cloneDeep(currentStore?.chartList?.find(item => item.code === state.activeCode) || {})
|
||||
EventBus.$emit('operationRollback', true)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 反撤回 redo
|
||||
if (!isUndo) {
|
||||
if (state.currentTimeLine < state.timelineStore.length) {
|
||||
// 时间线往后推一个
|
||||
state.currentTimeLine = state.currentTimeLine + 1
|
||||
currentStore = state.timelineStore[state.currentTimeLine - 1]
|
||||
state.pageInfo.chartList = cloneDeep(currentStore?.chartList || [])
|
||||
}
|
||||
}
|
||||
state.pageInfo.chartList = state.pageInfo.chartList.map(chart => {
|
||||
return {
|
||||
...chart,
|
||||
key: chart.code + new Date().getTime()
|
||||
}
|
||||
})
|
||||
},
|
||||
clearTimeline (state) {
|
||||
// 最后一个状态
|
||||
const lastStore = state.timelineStore[state.timelineStore.length - 1]
|
||||
// 将最后一个状态作为初始状态,否则下次拖拽后无法回到之前
|
||||
state.timelineStore = [
|
||||
{
|
||||
...lastStore,
|
||||
timelineTitle: '初始状态',
|
||||
updateTime: moment(new Date()).format('HH:mm:ss')
|
||||
}
|
||||
]
|
||||
state.currentTimeLine = 1
|
||||
},
|
||||
// 回退到指定时间线
|
||||
rollbackTimeline (state, index) {
|
||||
state.pageInfo.chartList = cloneDeep(state.timelineStore[index]?.chartList || [])
|
||||
state.currentTimeLine = index + 1
|
||||
},
|
||||
// 复制组件
|
||||
copyCharts (state) {
|
||||
state.copyChartCodes = cloneDeep(state.activeCodes)
|
||||
},
|
||||
// 粘贴组件
|
||||
pasteCharts (state) {
|
||||
const copyChartCodes = state.copyChartCodes
|
||||
const chartList = state.pageInfo.chartList
|
||||
// 将选中的组件复制一份, code加上 随机后缀, key 也加上随机后缀, x, y 各增加50
|
||||
const additionCode = randomString(5)
|
||||
const copyCharts = copyChartCodes.map(code => {
|
||||
const chart = chartList.find(item => item.code === code)
|
||||
const copyChart = cloneDeep(chart)
|
||||
copyChart.code = `${copyChart.code}_${additionCode}`
|
||||
copyChart.key = `${copyChart.key}_${additionCode}`
|
||||
copyChart.group = (copyChart.group && copyChart.group !== 'tempGroup') ? `${copyChart.group}_${additionCode}` : ''
|
||||
copyChart.x += 50
|
||||
copyChart.y += 50
|
||||
return copyChart
|
||||
})
|
||||
// 将复制的组件添加到chartList中
|
||||
state.pageInfo.chartList = [...copyCharts, ...state.pageInfo.chartList]
|
||||
},
|
||||
// 更新数据集库中的内容
|
||||
updateDataset (state, res) {
|
||||
// 如果只是更新了组件的标题
|
||||
if (res.isChangeTitle) {
|
||||
if (state.dataset.hasOwnProperty(res.oldTitle + '_' + res.code)) {
|
||||
const _dataset = CloneDeep(state.dataset)
|
||||
_dataset[res.title + '_' + res.code] = _dataset[res.oldTitle + '_' + res.code]
|
||||
delete _dataset[res.oldTitle + '_' + res.code]
|
||||
state.dataset = CloneDeep(_dataset)
|
||||
}
|
||||
} else {
|
||||
Vue.set(state.dataset, res.title + '_' + res.code, res.data)
|
||||
}
|
||||
},
|
||||
// 更新数据集库中的内容
|
||||
updateComputedDatas (state, res) {
|
||||
// 如果只是更新了组件的标题
|
||||
if (res.isChangeTitle) {
|
||||
if ((!res.isExpression) && state.computedDatas.hasOwnProperty(res.oldTitle + '_' + res.code)) {
|
||||
const _computedDatas = CloneDeep(state.computedDatas)
|
||||
_computedDatas[res.title + '_' + res.code] = _computedDatas[res.oldTitle + '_' + res.code]
|
||||
delete _computedDatas[res.oldTitle + '_' + res.code]
|
||||
state.computedDatas = CloneDeep(_computedDatas)
|
||||
}
|
||||
} else {
|
||||
Vue.set(state.computedDatas, res.title + '_' + res.code, res.data)
|
||||
}
|
||||
},
|
||||
// 清空数据集库
|
||||
emptyDataset (state) {
|
||||
state.dataset = {}
|
||||
},
|
||||
// 清空数据集库
|
||||
emptyComputedDatas (state) {
|
||||
state.computedDatas = {}
|
||||
},
|
||||
// 修改磁吸状态
|
||||
snapChange (state, snap) {
|
||||
state.snapTolerance = snap
|
||||
}
|
||||
}
|
||||
function deldataset (state, type, codes) {
|
||||
const datasets = state[type]
|
||||
for (const code of codes) {
|
||||
for (const key in datasets) {
|
||||
if (key.endsWith(code)) {
|
||||
delete state[type][key]
|
||||
break // 找到匹配的属性后,退出内层循环
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function changeZIndexFuc (state, list) {
|
||||
const len = list?.length - 1 || 0
|
||||
list.forEach((item, i) => {
|
||||
const index = state.pageInfo.chartList.findIndex(
|
||||
_item => _item.code === item.code
|
||||
)
|
||||
Vue.set(state.pageInfo.chartList[len - index], 'z', i)
|
||||
})
|
||||
}
|
||||
|
||||
// 改变当前组件的卡尺对齐线
|
||||
function changePresetLine (state, { x, y, w, h }) {
|
||||
state.presetLine = [
|
||||
{ type: 'h', site: y || 0 },
|
||||
{ type: 'v', site: x || 0 }
|
||||
]
|
||||
}
|
||||
|
||||
function changeGroup (code, state) {
|
||||
if (code) {
|
||||
// 找到和此组件group相同的组件,并添加到activeCodes中
|
||||
const group = state.pageInfo.chartList?.find(item => item.code === code)?.group
|
||||
if (group) {
|
||||
state.activeCodes = state.pageInfo.chartList?.filter(chart => chart.group === group && chart.group).map(item => item.code)
|
||||
}
|
||||
if (state.shiftKeyDown) {
|
||||
state.activeCodes = uniq([...state.activeCodes, code])
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
state.pageInfo.chartList?.forEach(chart => {
|
||||
if (state.activeCodes.includes(chart.code)) {
|
||||
chart.group = 'tempGroup'
|
||||
}
|
||||
})
|
||||
} else {
|
||||
if (!group) {
|
||||
state.activeCodes = [code]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
state.activeCodes = []
|
||||
state.pageInfo.chartList = state.pageInfo.chartList?.map(chart => ({
|
||||
...chart,
|
||||
group: chart.group === 'tempGroup' ? '' : chart.group
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
function saveTimeLineFunc (state, title, time) {
|
||||
// 最多保存10个状态
|
||||
const MAX_TIME_LINE = 10
|
||||
const stateCopy = cloneDeep(state.pageInfo)
|
||||
const date = new Date()
|
||||
time = time || moment(date).format('HH:mm:ss')
|
||||
stateCopy.timelineTitle = title
|
||||
stateCopy.updateTime = time
|
||||
|
||||
if (!Array.isArray(state.timelineStore)) {
|
||||
state.timelineStore = []
|
||||
}
|
||||
if (!Number.isInteger(state.currentTimeLine)) {
|
||||
state.currentTimeLine = 0
|
||||
}
|
||||
if (state.timelineStore.length >= MAX_TIME_LINE) {
|
||||
// 去掉最早的一个
|
||||
state.timelineStore.shift()
|
||||
}
|
||||
state.timelineStore?.push(stateCopy)
|
||||
state.currentTimeLine = state.timelineStore?.length
|
||||
}
|
||||
83
frontend/packages/js/store/state.js
Normal file
83
frontend/packages/js/store/state.js
Normal file
@@ -0,0 +1,83 @@
|
||||
// import _ from 'lodash'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
export const defaultData = {
|
||||
// 大屏信息
|
||||
pageInfo: {
|
||||
className:
|
||||
'com.gccloud.dataroom.core.module.manage.dto.DataRoomPageDTO',
|
||||
id: '',
|
||||
name: '测试bigScreen',
|
||||
code: '',
|
||||
icon: '',
|
||||
iconColor: '#007aff',
|
||||
orderNum: 0,
|
||||
remark: '',
|
||||
type: 'bigScreen',
|
||||
style: '',
|
||||
parentCode: '0',
|
||||
|
||||
// 大屏页面的配置
|
||||
pageConfig: {
|
||||
w: 1920,
|
||||
h: 1080,
|
||||
bgColor: '#151a26', // 背景色
|
||||
bg: '', // 背景图
|
||||
lightBgColor: '#f5f7fa',
|
||||
lightBg: '',
|
||||
opacity: 100,
|
||||
customTheme: 'dark',
|
||||
themeJson: {}, // 自定义主题配置
|
||||
// 缓存的数据集 { name: '', dataSetId: '' }
|
||||
cacheDataSets: [],
|
||||
refreshConfig: [],
|
||||
// 自适应模式 无(none) 、自动(auto)、宽度铺满(fitWidth)、高度铺满(fitHeight)和 双向铺满(cover) 5 种自适应模式
|
||||
fitMode: 'none'
|
||||
},
|
||||
|
||||
// 图表的集合
|
||||
chartList: []
|
||||
},
|
||||
|
||||
// 当前选中的组件code
|
||||
activeCode: null,
|
||||
// 当前鼠标悬浮的组件code
|
||||
hoverCode: null,
|
||||
// 页面初始化加载状态
|
||||
pageLoading: true,
|
||||
// 当前选中的组件的配置
|
||||
activeItemConfig: null,
|
||||
// 当前选中的组件的对齐线
|
||||
presetLine: [],
|
||||
// 强制更新键
|
||||
updateKey: null,
|
||||
|
||||
// 是否显示网格
|
||||
hasGrid: false,
|
||||
|
||||
// 多选的组件code数据
|
||||
activeCodes: [],
|
||||
// 复制到粘贴板上的组件编码
|
||||
copyChartCodes: [],
|
||||
// false 表示 shift 键没有被按下, true表示 shift 键被按下
|
||||
shiftKeyDown: false,
|
||||
// 缩放
|
||||
zoom: 100,
|
||||
// 自适应下的缩放比例
|
||||
fitZoom: 100,
|
||||
iframeDialog: false,
|
||||
// 页面上所有组件的数据集的数据信息
|
||||
dataset: {},
|
||||
// 页面上所有组件的数据集的数据信息
|
||||
computedDatas: {},
|
||||
// 是否开启磁吸
|
||||
snapTolerance: 3
|
||||
}
|
||||
|
||||
export default () => ({
|
||||
// 存储的大屏timeline信息
|
||||
timelineStore: [],
|
||||
// 当前的timeline 的index
|
||||
currentTimeLine: 0,
|
||||
// 具体信息
|
||||
...cloneDeep(defaultData)
|
||||
})
|
||||
91
frontend/packages/js/utils/LabelConfigService.js
Normal file
91
frontend/packages/js/utils/LabelConfigService.js
Normal file
@@ -0,0 +1,91 @@
|
||||
/*!
|
||||
* 标签管理
|
||||
*/
|
||||
import Vue from 'vue'
|
||||
|
||||
/**
|
||||
* 获取标签列表
|
||||
* @returns {*}
|
||||
*/
|
||||
const getLabelList = () => Vue.prototype.$dataRoomAxios.get('/label/getLabelList')
|
||||
|
||||
/**
|
||||
* 获取标签
|
||||
* @param data
|
||||
* @returns {*}
|
||||
*/
|
||||
const labelList = (data) => Vue.prototype.$dataRoomAxios.get('/label/list', data)
|
||||
|
||||
/**
|
||||
* 获取标签分类
|
||||
* @returns {*}
|
||||
*/
|
||||
const getLabelType = () => Vue.prototype.$dataRoomAxios.get('/label/getLabelType')
|
||||
|
||||
/**
|
||||
* 根据种类移除标签
|
||||
* @param data
|
||||
* @returns {*}
|
||||
*/
|
||||
const removeLabelByType = (data) => Vue.prototype.$dataRoomAxios.post('/label/removeLabelByType', data)
|
||||
|
||||
/**
|
||||
* 移除标签
|
||||
* @param id
|
||||
* @returns {*}
|
||||
*/
|
||||
const removeLabel = (id = '-1') => Vue.prototype.$dataRoomAxios.get(`/label/removeLabel/${id}`)
|
||||
|
||||
/**
|
||||
* 检查重复标签
|
||||
* @param data
|
||||
* @returns {*}
|
||||
*/
|
||||
const checkRepeatLabel = (data) => Vue.prototype.$dataRoomAxios.post('/label/checkRepeat', data)
|
||||
|
||||
/**
|
||||
* 新增/修改标签
|
||||
* @param data
|
||||
* @returns {*}
|
||||
*/
|
||||
const addOrUpdateLabel = (data) => Vue.prototype.$dataRoomAxios.post('/label/addOrUpdateLabel', data)
|
||||
|
||||
/**
|
||||
* 获取标签详情
|
||||
* @param id
|
||||
* @returns {*}
|
||||
*/
|
||||
const getLabelDetail = (id = '-1') => Vue.prototype.$dataRoomAxios.get(`/label/getLabelDetail/${id}`)
|
||||
|
||||
/**
|
||||
* 修改标签种类
|
||||
* @param data
|
||||
* @returns {*}
|
||||
*/
|
||||
const updateLabelType = (data) => Vue.prototype.$dataRoomAxios.post('/label/updateLabelType', data)
|
||||
|
||||
/**
|
||||
* 根据标签id获取数据集id列表
|
||||
* @param id
|
||||
*/
|
||||
const getDataSetIdListByLabelId = (id = '-1') => Vue.prototype.$dataRoomAxios.get(`/label/queryDataSetIdList/${id}`)
|
||||
|
||||
/**
|
||||
* 根据数据集id获取标签列表
|
||||
* @param id
|
||||
*/
|
||||
const getLabelListByDatasetId = (id = '-1') => Vue.prototype.$dataRoomAxios.get(`/label/queryDataSetLabelList/${id}`)
|
||||
|
||||
export {
|
||||
getLabelList,
|
||||
labelList,
|
||||
getLabelType,
|
||||
removeLabelByType,
|
||||
removeLabel,
|
||||
checkRepeatLabel,
|
||||
addOrUpdateLabel,
|
||||
getLabelDetail,
|
||||
updateLabelType,
|
||||
getDataSetIdListByLabelId,
|
||||
getLabelListByDatasetId
|
||||
}
|
||||
11
frontend/packages/js/utils/colorList.js
Normal file
11
frontend/packages/js/utils/colorList.js
Normal file
@@ -0,0 +1,11 @@
|
||||
// 颜色选择器的预设颜色
|
||||
export const predefineColors = [
|
||||
'#6b74e4',
|
||||
'#4391f4',
|
||||
'#38bbe5',
|
||||
'#69d6fd',
|
||||
'#36c6a0',
|
||||
'#007aff',
|
||||
'#ffffff',
|
||||
'#0b1833'
|
||||
]
|
||||
91
frontend/packages/js/utils/commonConfig.js
Normal file
91
frontend/packages/js/utils/commonConfig.js
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* @description: 大屏组件通用属性
|
||||
* @Date: 2023-03-13 10:04:59
|
||||
* @Author: xing.heng
|
||||
* @LastEditors: wujian
|
||||
* @LastEditTime: 2023-06-01 14:23:23
|
||||
*/
|
||||
|
||||
import getComponentConfig from 'packages/js/utils/getComponentConfig'
|
||||
import linkageConfig from 'packages/js/config/linkageConfig'
|
||||
// 关于设置组件在右侧面板可以展示哪些属性配置
|
||||
export const displayOption = {
|
||||
serverPagination: {
|
||||
// 服务端分页
|
||||
enable: false
|
||||
},
|
||||
pageSize: {
|
||||
// 分页长度
|
||||
enable: false
|
||||
},
|
||||
metricField: {
|
||||
// 指标
|
||||
label: '指标',
|
||||
enable: true,
|
||||
multiple: true // 是否多选
|
||||
},
|
||||
dimensionField: {
|
||||
// 维度
|
||||
label: '维度', // 维度/查询字段
|
||||
enable: true,
|
||||
multiple: true // 是否多选
|
||||
},
|
||||
dimensionList: {
|
||||
// 维度(只有多折线图会存在两个维度)
|
||||
label: '维度', // 维度/查询字段
|
||||
enable: false,
|
||||
multiple: true // 是否多选
|
||||
},
|
||||
seriesField: {
|
||||
// 数据细分
|
||||
enable: false,
|
||||
required: true // 必填
|
||||
},
|
||||
dataAllocation: {
|
||||
// 是否存在数据配置
|
||||
enable: true
|
||||
},
|
||||
params: {
|
||||
// 参数配置
|
||||
enable: true
|
||||
},
|
||||
dataSourceType: {
|
||||
// 数据源(数据集或者其他方式:静态数据)
|
||||
enable: true
|
||||
}
|
||||
}
|
||||
export default function (customConfig) {
|
||||
return {
|
||||
...getComponentConfig(customConfig.type),
|
||||
z: 0, // z轴图层支持
|
||||
locked: false, // 是否锁定组件
|
||||
group: '', // 组合组件, 相同group的组件会被组合在一起
|
||||
code: null,
|
||||
showTitle: true,
|
||||
...customConfig.root,
|
||||
dataSource: {
|
||||
className:
|
||||
'com.gccloud.dataroom.core.module.chart.components.datasource.DataSetDataSource',
|
||||
dataSourceKey: '', // 数据源,选择不同数据库
|
||||
businessKey: '', // 数据集标识
|
||||
dimensionField: '', // 维度
|
||||
metricField: '', // 指标
|
||||
seriesField: '', // 分类字段
|
||||
dimensionFieldList: [], // 唯独列表
|
||||
metricFieldList: [], // 指标列表
|
||||
seriesFieldList: [], // 分类列表
|
||||
serverPagination: false, // 服务端分页
|
||||
pageSize: 10,
|
||||
params: {},
|
||||
dataSetType: '', // 数据集类型,
|
||||
formCode: '',
|
||||
...customConfig.dataSource // 非通用数据配置
|
||||
},
|
||||
customize: {
|
||||
...customConfig.customize
|
||||
}, // 自定义设置
|
||||
...linkageConfig, // 数据联动配置
|
||||
filterList: [],
|
||||
dataFlag: false // 判断数据为模拟数据还是真实数据
|
||||
}
|
||||
}
|
||||
42
frontend/packages/js/utils/componentImport.js
Normal file
42
frontend/packages/js/utils/componentImport.js
Normal file
@@ -0,0 +1,42 @@
|
||||
/* eslint-disable no-useless-escape */
|
||||
/*
|
||||
* @description: 批量导入pc端大屏组件
|
||||
* @Date: 2023-03-13 10:04:58
|
||||
* @Author: xing.heng
|
||||
* @LastEditors: xing.heng
|
||||
* @LastEditTime: 2023-05-17 12:40:25
|
||||
*/
|
||||
|
||||
const modules = {};
|
||||
// 组件名称替换
|
||||
const replaceName = {};
|
||||
// 排除的组件
|
||||
const excludeCommponents = [];
|
||||
function importComponents(files) {
|
||||
files.keys().forEach((key) => {
|
||||
// 正则,取到./和/之间的字符串
|
||||
const reg = new RegExp("(.\\/)(.*)(\\/)");
|
||||
let moduleName = key.match(reg)[0].replace(/(\.\/)|(\/)|(src)/g, "");
|
||||
// 替换组件名称
|
||||
if (replaceName[moduleName]) {
|
||||
moduleName = replaceName[moduleName];
|
||||
}
|
||||
if (!excludeCommponents.includes(moduleName)) {
|
||||
modules[moduleName] = files(key).default;
|
||||
}
|
||||
});
|
||||
}
|
||||
importComponents(
|
||||
require.context("data-room-ui/BasicComponents", true, /\index.vue$/)
|
||||
);
|
||||
importComponents(require.context("data-room-ui/Borders", true, /\index.vue$/));
|
||||
importComponents(
|
||||
require.context("data-room-ui/Decorations", true, /\index.vue$/)
|
||||
);
|
||||
importComponents(
|
||||
require.context("data-room-ui/BorderComponents", true, /\index.vue$/)
|
||||
);
|
||||
importComponents(
|
||||
require.context("data-room-ui/Configuration", true, /\index.vue$/)
|
||||
);
|
||||
export default modules;
|
||||
100
frontend/packages/js/utils/compressImg.js
Normal file
100
frontend/packages/js/utils/compressImg.js
Normal file
@@ -0,0 +1,100 @@
|
||||
export function showSize (base64url) {
|
||||
let str = base64url.replace('data:image/png;base64,', '')
|
||||
// 找到等号,把等号也去掉
|
||||
const equalIndex = str.indexOf('=')
|
||||
if (str.indexOf('=') > 0) {
|
||||
str = str.substring(0, equalIndex)
|
||||
}
|
||||
// 原来的字符流大小,单位为字节
|
||||
const strLength = base64url.length
|
||||
// 计算后得到的文件流大小,单位为字节
|
||||
const fileLength = parseInt(strLength - (strLength / 8) * 2)
|
||||
// 由字节转换为kb
|
||||
let size = ''
|
||||
size = (fileLength / 1024).toFixed(2)
|
||||
const sizeStr = size + '' // 转成字符串
|
||||
const index = sizeStr.indexOf('.') // 获取小数点处的索引
|
||||
const dou = sizeStr.substr(index + 1, 2) // 获取小数点后两位的值
|
||||
if (dou === '00') {
|
||||
// 判断后两位是否为00,如果是则删除00
|
||||
return sizeStr.substring(0, index) + sizeStr.substr(index + 3, 2)
|
||||
}
|
||||
return Number(size)
|
||||
}
|
||||
|
||||
export function dataURLtoFile (dataurl, filename) {
|
||||
// 将base64转换为文件,dataurl为base64字符串,filename为文件名(必须带后缀名,如.jpg,.png)
|
||||
const arr = dataurl.split(',')
|
||||
const mime = arr[0].match(/:(.*?);/)[1]
|
||||
const bstr = atob(arr[1])
|
||||
let n = bstr.length
|
||||
const u8arr = new Uint8Array(n)
|
||||
while (n--) {
|
||||
u8arr[n] = bstr.charCodeAt(n)
|
||||
}
|
||||
return new File([u8arr], filename, { type: mime })
|
||||
}
|
||||
|
||||
export function dataURLtoBlob (dataurl) {
|
||||
const arr = dataurl.split(',')
|
||||
const _arr = arr[1].substring(0, arr[1].length - 2)
|
||||
const mime = arr[0].match(/:(.*?);/)[1]
|
||||
const bstr = atob(_arr)
|
||||
let n = bstr.length
|
||||
const u8arr = new Uint8Array(n)
|
||||
while (n--) {
|
||||
u8arr[n] = bstr.charCodeAt(n)
|
||||
}
|
||||
return new Blob([u8arr], {
|
||||
type: mime
|
||||
})
|
||||
}
|
||||
|
||||
export function translateBlobToBase64 (blob, callback) {
|
||||
const reader = new FileReader()
|
||||
reader.onload = function (e) {
|
||||
callback(e.target)
|
||||
}
|
||||
reader.readAsDataURL(blob)
|
||||
// 读取后,result属性中将包含一个data:URL格式的Base64字符串用来表示所读取的文件
|
||||
}
|
||||
|
||||
// 压缩方法
|
||||
export function compressImage (base64, { width: w = 1280, height: h = 720, size = 200, quality = 1 }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const newImage = new Image()
|
||||
newImage.src = base64
|
||||
newImage.setAttribute('crossOrigin', 'Anonymous')
|
||||
let imgWidth, imgHeight
|
||||
newImage.onload = function () {
|
||||
imgWidth = 1280
|
||||
imgHeight = 720
|
||||
const canvas = document.createElement('canvas')
|
||||
const ctx = canvas.getContext('2d')
|
||||
if (Math.max(imgWidth, imgHeight) > w) {
|
||||
if (imgWidth > imgHeight) {
|
||||
canvas.width = w
|
||||
canvas.height = w * imgHeight / imgWidth
|
||||
} else {
|
||||
canvas.height = w
|
||||
canvas.width = w * imgWidth / imgHeight
|
||||
}
|
||||
} else {
|
||||
canvas.width = imgWidth
|
||||
canvas.height = imgHeight
|
||||
quality = 1
|
||||
}
|
||||
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||
ctx.drawImage(this, 0, 0, canvas.width, canvas.height)
|
||||
let compressedBase64 = canvas.toDataURL('image/jpeg', quality) // 压缩语句
|
||||
if (showSize(compressedBase64) > Number(size)) {
|
||||
compressedBase64 = canvas.toDataURL('image/jpeg', quality - 0.2 > 0.4 ? quality - 0.2 : 0.4)
|
||||
}
|
||||
resolve(compressedBase64)
|
||||
}
|
||||
newImage.onerror = function () {
|
||||
reject(new Error('Failed to load image'))
|
||||
}
|
||||
})
|
||||
}
|
||||
39
frontend/packages/js/utils/configImport.js
Normal file
39
frontend/packages/js/utils/configImport.js
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* @description: 批量导入所有组件的配置config
|
||||
* @Date: 2023-03-13 10:04:58
|
||||
* @Author: xing.heng
|
||||
* @LastEditors: xing.heng
|
||||
* @LastEditTime: 2023-05-18 10:39:42
|
||||
*/
|
||||
const setModules = {}; // 设置模块
|
||||
const dataModules = {}; // 数据模块
|
||||
function importComponentSettingConfig(files) {
|
||||
files
|
||||
.keys()
|
||||
.filter((key) => {
|
||||
return key.match(/settingConfig/);
|
||||
})
|
||||
.forEach((key) => {
|
||||
const reg = new RegExp("(.\\/)(.*)(\\/)");
|
||||
let moduleName = key.match(reg)[0].replace(/(\.\/)|(\/)/g, "");
|
||||
moduleName = moduleName.replace(
|
||||
moduleName[0],
|
||||
moduleName[0].toLowerCase()
|
||||
);
|
||||
setModules[moduleName] = files(key).settingConfig;
|
||||
dataModules[moduleName] = files(key).dataConfig;
|
||||
});
|
||||
}
|
||||
importComponentSettingConfig(
|
||||
require.context("data-room-ui/BasicComponents", true, /\.js$/)
|
||||
);
|
||||
importComponentSettingConfig(
|
||||
require.context("data-room-ui/Borders", true, /\.js$/)
|
||||
);
|
||||
importComponentSettingConfig(
|
||||
require.context("data-room-ui/Decorations", true, /\.js$/)
|
||||
);
|
||||
importComponentSettingConfig(
|
||||
require.context("data-room-ui/Configuration", true, /\.js$/)
|
||||
);
|
||||
export { setModules, dataModules };
|
||||
116
frontend/packages/js/utils/dataSourceService.js
Normal file
116
frontend/packages/js/utils/dataSourceService.js
Normal file
@@ -0,0 +1,116 @@
|
||||
/*!
|
||||
* 数据源管理
|
||||
*/
|
||||
import Vue from 'vue'
|
||||
/**
|
||||
* 修改数据源
|
||||
* @param params
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const add = (params = {}, flag = false) => Vue.prototype.$dataRoomAxios.post('/datasource/add', params, flag)
|
||||
|
||||
/**
|
||||
* 删除数据源前查询是否使用
|
||||
* @param params
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const dataSourceCheck = (id='-1', flag = false) => Vue.prototype.$dataRoomAxios.post(`/datasource/deleteCheck/${id}`, {}, flag)
|
||||
|
||||
/**
|
||||
* 修改数据源
|
||||
* @param params
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const update = (params = {}, flag = false) => Vue.prototype.$dataRoomAxios.post('/datasource/update', params, flag)
|
||||
|
||||
/**
|
||||
* 数据源名称校验
|
||||
* @param params
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const checkRepeat = (params = {}, flag = false) => Vue.prototype.$dataRoomAxios.post('/datasource/checkRepeat', params, flag)
|
||||
|
||||
/**
|
||||
* 数据源连接测试
|
||||
* @param params
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const sourceLinkTest = (params = {}, flag = false) => Vue.prototype.$dataRoomAxios.post('/datasource/testConnect', params, flag)
|
||||
|
||||
/**
|
||||
* 获取数据源列表
|
||||
* @param params
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const datasourcePage = (params = {}, flag = false) => Vue.prototype.$dataRoomAxios.get('/datasource/page', params, flag)
|
||||
|
||||
/**
|
||||
* 获取数据源列表
|
||||
* @param params
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const datasourceList = (params = {}, flag = false) => Vue.prototype.$dataRoomAxios.get('/datasource/list', params, flag)
|
||||
|
||||
/**
|
||||
* 删除数据源
|
||||
* @param id
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const sourceRemove = (id = '-1', flag = false) => Vue.prototype.$dataRoomAxios.post(`/datasource/delete/${id}`, {}, flag)
|
||||
|
||||
/**
|
||||
* 获取数据源下表列表
|
||||
* @param id
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const getSourceTable = (id = '-1', flag = false) => Vue.prototype.$dataRoomAxios.get(`/datasource/getTableList/${id}`, {}, flag)
|
||||
|
||||
/**
|
||||
* 获取数据源下视图列表
|
||||
* @param id
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const getSourceView = (id = '-1', flag = false) => Vue.prototype.$dataRoomAxios.get(`/datasource/getViewList/${id}`, {}, flag)
|
||||
|
||||
/**
|
||||
* 获取数据源下表字段列表
|
||||
* @param sourceId
|
||||
* @param tableName
|
||||
* @param flag
|
||||
* @returns {Promise<*>}
|
||||
*/
|
||||
const getTableFieldList = (sourceId = '-1', tableName = '', flag = false) => Vue.prototype.$dataRoomAxios.get(`/datasource/getFieldList/table/${sourceId}/${tableName}`, {}, flag)
|
||||
|
||||
/**
|
||||
* 获取数据源下视图字段列表
|
||||
* @param sourceId
|
||||
* @param viewName
|
||||
* @param flag
|
||||
* @returns {Promise<*>}
|
||||
*/
|
||||
const getViewFieldList = (sourceId = '-1', viewName = '', flag = false) => Vue.prototype.$dataRoomAxios.get(`/datasource/getFieldList/view/${sourceId}/${viewName}`, {}, flag)
|
||||
|
||||
export {
|
||||
add,
|
||||
update,
|
||||
checkRepeat,
|
||||
sourceLinkTest,
|
||||
datasourcePage,
|
||||
datasourceList,
|
||||
sourceRemove,
|
||||
getSourceTable,
|
||||
getSourceView,
|
||||
getTableFieldList,
|
||||
getViewFieldList,
|
||||
dataSourceCheck
|
||||
}
|
||||
145
frontend/packages/js/utils/datasetConfigService.js
Normal file
145
frontend/packages/js/utils/datasetConfigService.js
Normal file
@@ -0,0 +1,145 @@
|
||||
/*!
|
||||
* 数据集管理
|
||||
*/
|
||||
import Vue from 'vue'
|
||||
|
||||
/**
|
||||
* 数据集分页查询
|
||||
* @param params
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const datasetPage = (params = {}, flag = false) => Vue.prototype.$dataRoomAxios.get('/dataset/page', params, flag)
|
||||
|
||||
/**
|
||||
* 删除数据源前查询是否使用
|
||||
* @param params
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const datasetCheck = (id = '-1', flag = false) => Vue.prototype.$dataRoomAxios.post(`/dataset/deleteCheck/${id}`, {}, flag)
|
||||
|
||||
/**
|
||||
* 验证节点是否可删除
|
||||
* @param params
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const categoryDele = (id = '-1', flag = false) => Vue.prototype.$dataRoomAxios.get(`/dataset/getCountByType/${id}`, {}, flag)
|
||||
|
||||
|
||||
/**
|
||||
* 数据集列表查询
|
||||
* @param params
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const datasetList = (params = {}, flag = false) => Vue.prototype.$dataRoomAxios.get('/dataset/list', params, flag)
|
||||
|
||||
/**
|
||||
* 数据集名称校验
|
||||
* @param params
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const nameCheckRepeat = (params = {}, flag = false) => Vue.prototype.$dataRoomAxios.post('/dataset/checkRepeat', params, flag)
|
||||
|
||||
/**
|
||||
* 数据集新增
|
||||
* @param params
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const datasetAdd = (params = {}, flag = false) => Vue.prototype.$dataRoomAxios.post('/dataset/add', params, flag)
|
||||
|
||||
/**
|
||||
* 数据集修改
|
||||
* @param params
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const datasetUpdate = (params = {}, flag = false) => Vue.prototype.$dataRoomAxios.post('/dataset/update', params, flag)
|
||||
|
||||
/**
|
||||
* 删除数据集
|
||||
* @param id
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const datasetRemove = (id = '-1', flag = false) => Vue.prototype.$dataRoomAxios.post(`/dataset/delete/${id}`, {}, flag)
|
||||
|
||||
/**
|
||||
* 数据集执行
|
||||
* @param params
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const datasetExecuteTest = (params = {}, flag = false) => Vue.prototype.$dataRoomAxios.post('/dataset/execute/test', params, flag)
|
||||
|
||||
/**
|
||||
* 获取数据集详情
|
||||
* @param id
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
const getDataset = (id = '-1', flag = false) => Vue.prototype.$dataRoomAxios.get(`/dataset/info/${id}`, {}, flag)
|
||||
|
||||
/**
|
||||
* 获取数据集分类
|
||||
* @param r_dataset
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const getCategoryTree = (params = {}, flag = false) => Vue.prototype.$dataRoomAxios.get('/category/queryTreeList', params, flag)
|
||||
|
||||
/**
|
||||
* 新增分类树节点
|
||||
* @param params
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const categoryAdd = (params = {}, flag = false) => Vue.prototype.$dataRoomAxios.post('/category/add', params, flag)
|
||||
|
||||
/**
|
||||
* 编辑分类树节点
|
||||
* @param params
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const categoryUpdate = (params = {}, flag = false) => Vue.prototype.$dataRoomAxios.post('/category/update', params, flag)
|
||||
|
||||
/**
|
||||
* 删除分类树节点
|
||||
* @param id
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const categoryRemove = (id = '-1', flag = false) => Vue.prototype.$dataRoomAxios.post(`/category/delete/${id}`, {}, flag)
|
||||
|
||||
|
||||
/**
|
||||
* 分类名称校验
|
||||
* @param params
|
||||
* @param flag
|
||||
*/
|
||||
const categoryNameRepeat = (params = {}, flag = false) => Vue.prototype.$dataRoomAxios.post('/category/checkRepeat', params, flag)
|
||||
|
||||
export {
|
||||
datasetPage,
|
||||
datasetList,
|
||||
datasetAdd,
|
||||
datasetUpdate,
|
||||
datasetRemove,
|
||||
nameCheckRepeat,
|
||||
datasetExecuteTest,
|
||||
getDataset,
|
||||
categoryDele,
|
||||
|
||||
getCategoryTree,
|
||||
categoryAdd,
|
||||
categoryUpdate,
|
||||
categoryRemove,
|
||||
datasetCheck,
|
||||
categoryNameRepeat
|
||||
}
|
||||
29
frontend/packages/js/utils/evalFunctions.js
Normal file
29
frontend/packages/js/utils/evalFunctions.js
Normal file
@@ -0,0 +1,29 @@
|
||||
function stringifyObjectFunctions (obj) {
|
||||
// 遍历对象属性
|
||||
for (const key in obj) {
|
||||
const value = obj[key]
|
||||
// 如果属性值是函数类型,将函数转换为字符串
|
||||
if (typeof value === 'function') {
|
||||
obj[key] = `(${value.toString()})`
|
||||
// 如果属性值是对象类型,则递归进行转换
|
||||
} else if (typeof value === 'object' && value !== null) {
|
||||
stringifyObjectFunctions(value)
|
||||
}
|
||||
}
|
||||
return JSON.stringify(obj)
|
||||
}
|
||||
|
||||
function stringToFunction (str) {
|
||||
return JSON.parse(str, (key, value) => {
|
||||
if (typeof value === 'string' && (value.includes('=>') || value.includes('function'))) {
|
||||
// eslint-disable-next-line no-eval
|
||||
return eval(`(${value})`)
|
||||
}
|
||||
return value
|
||||
})
|
||||
}
|
||||
|
||||
export {
|
||||
stringifyObjectFunctions,
|
||||
stringToFunction
|
||||
}
|
||||
34
frontend/packages/js/utils/eventBus.js
Normal file
34
frontend/packages/js/utils/eventBus.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import Vue from 'vue';
|
||||
|
||||
// 创建全局唯一的 EventBus 实例
|
||||
export const EventBus = new Vue();
|
||||
|
||||
// 创建唯一的事件处理函数
|
||||
function dataInitHandler(_this, formData, bindComponents) {
|
||||
bindComponents?.forEach(com => {
|
||||
const maps = com.maps;
|
||||
const filterList = maps?.map(param => ({
|
||||
column: param.targetField,
|
||||
operator: param.queryRule,
|
||||
value: formData[param.sourceField],
|
||||
}));
|
||||
|
||||
_this.$nextTick(() => {
|
||||
if (_this.$refs[com.componentKey] && _this.$refs[com.componentKey].dataInit) {
|
||||
_this.$refs[com.componentKey].dataInit(filterList);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 注册事件监听器
|
||||
export function dataInit(_this) {
|
||||
EventBus.$on('dataInit', (formData, bindComponents) => {
|
||||
// 在回调中调用处理函数并传递组件实例
|
||||
dataInitHandler(_this, formData, bindComponents);
|
||||
});
|
||||
}
|
||||
|
||||
export function destroyedEvent() {
|
||||
EventBus.$off('dataInit', dataInitHandler);
|
||||
}
|
||||
21
frontend/packages/js/utils/file.js
Normal file
21
frontend/packages/js/utils/file.js
Normal file
@@ -0,0 +1,21 @@
|
||||
function getFileUrl(url){
|
||||
// 如果是空的直接返回
|
||||
if (!url) {
|
||||
return url
|
||||
}
|
||||
// 如果是http开头的直接返回
|
||||
if (/^http/.test(url)) {
|
||||
return url
|
||||
}
|
||||
// 如果没有以/开头的加上/
|
||||
if (!/^\//.test(url)) {
|
||||
url = `/${url}`
|
||||
}
|
||||
// return `${window.BS_CONFIG?.httpConfigs?.fileUrlPrefix}${url}`
|
||||
return `${process.env.VUE_APP_BASE_API}/static${url}`
|
||||
}
|
||||
|
||||
|
||||
export {
|
||||
getFileUrl
|
||||
}
|
||||
22
frontend/packages/js/utils/fontList.js
Normal file
22
frontend/packages/js/utils/fontList.js
Normal file
@@ -0,0 +1,22 @@
|
||||
const fontList = [
|
||||
{
|
||||
label: '默认',
|
||||
value: ''
|
||||
},
|
||||
{
|
||||
label: '时钟加粗倾斜',
|
||||
value: 'ds-digitalbold_italic'
|
||||
},
|
||||
{
|
||||
label: '时钟加粗正常',
|
||||
value: 'ds-digitalbold'
|
||||
},
|
||||
{
|
||||
label: '时钟倾斜',
|
||||
value: 'ds-digitalitalic'
|
||||
},
|
||||
{
|
||||
label: '时钟正常',
|
||||
value: 'ds-digitalnormal'
|
||||
}]
|
||||
export default fontList
|
||||
223
frontend/packages/js/utils/getBorderComponentsConfig.js
Normal file
223
frontend/packages/js/utils/getBorderComponentsConfig.js
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* @description: 得到边框组件配置
|
||||
* @Date: 2023-03-16 10:49:11
|
||||
*/
|
||||
export default function getComponentConfig (type, classNameType) {
|
||||
const className =
|
||||
'com.gccloud.dataroom.core.module.chart.components.ScreenBorderChart'
|
||||
switch (type) {
|
||||
case 'border1':
|
||||
return {
|
||||
name: '边框一',
|
||||
title: '边框一',
|
||||
icon: null,
|
||||
img: require('data-room-ui/Borders/images/border-1.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 450,
|
||||
h: 320,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'border2':
|
||||
return {
|
||||
name: '边框二',
|
||||
title: '边框二',
|
||||
icon: null,
|
||||
img: require('data-room-ui/Borders/images/border-2.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 450,
|
||||
h: 320,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'border3':
|
||||
return {
|
||||
name: '边框三',
|
||||
title: '边框三',
|
||||
icon: null,
|
||||
img: require('data-room-ui/Borders/images/border-3.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 450,
|
||||
h: 320,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'border4':
|
||||
return {
|
||||
name: '边框四',
|
||||
title: '边框四',
|
||||
icon: null,
|
||||
img: require('data-room-ui/Borders/images/border-4.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 450,
|
||||
h: 320,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'border5':
|
||||
return {
|
||||
name: '边框五',
|
||||
title: '边框五',
|
||||
icon: null,
|
||||
img: require('data-room-ui/Borders/images/border-5.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 450,
|
||||
h: 320,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'border6':
|
||||
return {
|
||||
name: '边框六',
|
||||
title: '边框六',
|
||||
icon: null,
|
||||
img: require('data-room-ui/Borders/images/border-6.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 450,
|
||||
h: 320,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'border7':
|
||||
return {
|
||||
name: '边框七',
|
||||
title: '边框七',
|
||||
icon: null,
|
||||
img: require('data-room-ui/Borders/images/border-7.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 450,
|
||||
h: 320,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'border8':
|
||||
return {
|
||||
name: '边框八',
|
||||
title: '边框八',
|
||||
icon: null,
|
||||
img: require('data-room-ui/Borders/images/border-8.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 450,
|
||||
h: 320,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'border9':
|
||||
return {
|
||||
name: '边框九',
|
||||
title: '边框九',
|
||||
icon: null,
|
||||
img: require('data-room-ui/Borders/images/border-9.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 450,
|
||||
h: 320,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'border10':
|
||||
return {
|
||||
name: '边框十',
|
||||
title: '边框十',
|
||||
icon: null,
|
||||
img: require('data-room-ui/Borders/images/border-10.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 450,
|
||||
h: 320,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'border11':
|
||||
return {
|
||||
name: '边框十一',
|
||||
title: '边框十一',
|
||||
icon: null,
|
||||
img: require('data-room-ui/Borders/images/border-11.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 450,
|
||||
h: 320,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'border12':
|
||||
return {
|
||||
name: '边框十二',
|
||||
title: '边框十二',
|
||||
icon: null,
|
||||
img: require('data-room-ui/Borders/images/border-12.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 450,
|
||||
h: 320,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'border13':
|
||||
return {
|
||||
name: '边框十三',
|
||||
title: '边框十三',
|
||||
icon: null,
|
||||
img: require('data-room-ui/Borders/images/border-13.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 450,
|
||||
h: 320,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'border14':
|
||||
return {
|
||||
name: '边框十四',
|
||||
title: '边框十四',
|
||||
icon: null,
|
||||
img: require('data-room-ui/Borders/images/border-14.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 450,
|
||||
h: 320,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'border15':
|
||||
return {
|
||||
name: '边框十五',
|
||||
title: '边框十五',
|
||||
icon: null,
|
||||
img: require('data-room-ui/Borders/images/border-15.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 450,
|
||||
h: 450,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
|
||||
default:
|
||||
return {}
|
||||
}
|
||||
}
|
||||
369
frontend/packages/js/utils/getComponentConfig.js
Normal file
369
frontend/packages/js/utils/getComponentConfig.js
Normal file
@@ -0,0 +1,369 @@
|
||||
import Icon from "data-room-ui/assets/images/bigScreenIcon/export";
|
||||
|
||||
export default function getComponentConfig(type) {
|
||||
switch (type) {
|
||||
case "texts":
|
||||
return {
|
||||
name: "文本",
|
||||
title: "文本",
|
||||
icon: Icon.getNameList()[0],
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenTextChart",
|
||||
w: 200,
|
||||
h: 60,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
dataHandler: {}, // 数据自定义处理js脚本
|
||||
};
|
||||
case "numbers":
|
||||
return {
|
||||
name: "数字",
|
||||
title: "数字",
|
||||
icon: Icon.getNameList()[28],
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenNumbersChart",
|
||||
w: 200,
|
||||
h: 60,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "linkChart":
|
||||
return {
|
||||
name: "超链接",
|
||||
title: "超链接",
|
||||
icon: Icon.getNameList()[15],
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenLinkChart",
|
||||
w: 200,
|
||||
h: 60,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "horizontalLine":
|
||||
return {
|
||||
name: "水平线",
|
||||
title: "水平线",
|
||||
icon: Icon.getNameList()[24],
|
||||
component: null,
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenBorderChart",
|
||||
w: 300,
|
||||
h: 40,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "verticalLine":
|
||||
return {
|
||||
name: "垂直线",
|
||||
title: "垂直线",
|
||||
icon: Icon.getNameList()[25],
|
||||
component: null,
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenBorderChart",
|
||||
w: 40,
|
||||
h: 300,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
|
||||
case "picture":
|
||||
return {
|
||||
name: "图片",
|
||||
title: "图片",
|
||||
icon: Icon.getNameList()[1],
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenPictureChart",
|
||||
// w: 280,
|
||||
// h: 200,
|
||||
// x: 0,
|
||||
// y: 0,
|
||||
type,
|
||||
};
|
||||
case "screenScrollBoard":
|
||||
return {
|
||||
name: "轮播表",
|
||||
title: "轮播表",
|
||||
icon: Icon.getNameList()[2],
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenScrollBoardChart",
|
||||
w: 600,
|
||||
h: 400,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "screenScrollRanking":
|
||||
return {
|
||||
name: "排名表",
|
||||
title: "排名表",
|
||||
icon: Icon.getNameList()[3],
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenScrollRankingChart",
|
||||
w: 600,
|
||||
h: 400,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "tables":
|
||||
return {
|
||||
name: "表格",
|
||||
title: "表格",
|
||||
icon: Icon.getNameList()[4],
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenTablesChart",
|
||||
w: 600,
|
||||
h: 400,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "currentTime":
|
||||
return {
|
||||
name: "当前时间",
|
||||
title: "当前时间",
|
||||
icon: Icon.getNameList()[6],
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenCurrentTimeChart",
|
||||
w: 300,
|
||||
h: 60,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "timeCountDown":
|
||||
return {
|
||||
name: "倒计时",
|
||||
title: "倒计时",
|
||||
icon: Icon.getNameList()[7],
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenTimeCountDownChart",
|
||||
w: 300,
|
||||
h: 60,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "iframeChart":
|
||||
return {
|
||||
name: "外链",
|
||||
title: "外链",
|
||||
icon: Icon.getNameList()[8],
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenIframeChart",
|
||||
w: 600,
|
||||
h: 400,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "digitalFlop":
|
||||
return {
|
||||
name: "翻牌器",
|
||||
title: "翻牌器",
|
||||
icon: null,
|
||||
img: require("data-room-ui/BasicComponents/DigitalFlop/images/fanpaiqi.png"),
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenDigitalFlopChart",
|
||||
w: 800,
|
||||
h: 150,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "customHtml":
|
||||
return {
|
||||
name: "自定义HTML",
|
||||
title: "自定义HTML",
|
||||
icon: Icon.getNameList()[29],
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenCustomHtmlChart",
|
||||
w: 600,
|
||||
h: 150,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "video":
|
||||
return {
|
||||
name: "播放器",
|
||||
title: "播放器",
|
||||
icon: Icon.getNameList()[12],
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenVideoChart",
|
||||
w: 600,
|
||||
h: 400,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
|
||||
case "input":
|
||||
return {
|
||||
name: "输入框",
|
||||
title: "输入框",
|
||||
icon: Icon.getNameList()[13],
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenInputChart",
|
||||
w: 450,
|
||||
h: 60,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "button":
|
||||
return {
|
||||
name: "按钮",
|
||||
title: "按钮",
|
||||
icon: Icon.getNameList()[14],
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenButtonChart",
|
||||
w: 80,
|
||||
h: 40,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "marquee":
|
||||
return {
|
||||
name: "跑马灯",
|
||||
title: "跑马灯",
|
||||
icon: Icon.getNameList()[16],
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenMarqueeChart",
|
||||
w: 250,
|
||||
h: 150,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "chartTab":
|
||||
return {
|
||||
name: "图表Tab页",
|
||||
title: "图表Tab页",
|
||||
icon: Icon.getNameList()[19],
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ChartTabChart",
|
||||
w: 600,
|
||||
h: 400,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "themeSelect":
|
||||
return {
|
||||
name: "主题切换",
|
||||
title: "主题切换",
|
||||
icon: Icon.getNameList()[20],
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ThemeSelectChart",
|
||||
w: 200,
|
||||
h: 100,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "select":
|
||||
return {
|
||||
name: "选择器",
|
||||
title: "选择器",
|
||||
icon: Icon.getNameList()[21],
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenSelectChart",
|
||||
w: 450,
|
||||
h: 60,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "timePicker":
|
||||
return {
|
||||
name: "时间选择器",
|
||||
title: "时间选择器",
|
||||
icon: Icon.getNameList()[22],
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenTimePickerChart",
|
||||
w: 200,
|
||||
h: 60,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "dateTimePicker":
|
||||
return {
|
||||
name: "日期时间选择器",
|
||||
title: "日期时间选择器",
|
||||
icon: Icon.getNameList()[23],
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenDateTimePickerChart",
|
||||
w: 500,
|
||||
h: 60,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "indicatorCard":
|
||||
return {
|
||||
name: "指标卡一",
|
||||
title: "指标卡一",
|
||||
icon: Icon.getNameList()[30],
|
||||
// img: require('data-room-ui/assets/images/cardImg/card.png'),
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenIndicatorCardChart",
|
||||
w: 300,
|
||||
h: 114,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "indicatorCard2":
|
||||
return {
|
||||
name: "指标卡二",
|
||||
title: "指标卡二",
|
||||
icon: Icon.getNameList()[31],
|
||||
// img: require('data-room-ui/assets/images/cardImg/card2.png'),
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenIndicatorCardChart",
|
||||
w: 300,
|
||||
h: 114,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "indexCard":
|
||||
return {
|
||||
name: "指标卡三",
|
||||
title: "指标卡三",
|
||||
icon: Icon.getNameList()[32],
|
||||
// img: require('data-room-ui/assets/images/cardImg/indicard.png'),
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenIndexCardChart",
|
||||
w: 300,
|
||||
h: 114,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "indexCard2":
|
||||
return {
|
||||
name: "指标卡四",
|
||||
title: "指标卡四",
|
||||
icon: Icon.getNameList()[33],
|
||||
// img: require('data-room-ui/assets/images/cardImg/indcard2.png'),
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenIndexCardChart",
|
||||
w: 300,
|
||||
h: 114,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* @description: 得到装饰组件配置
|
||||
*/
|
||||
|
||||
import Icon from "data-room-ui/assets/images/bigScreenIcon/export";
|
||||
|
||||
export default function getComponentConfig(type, classNameType) {
|
||||
const className =
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenConfigurationChart";
|
||||
switch (type) {
|
||||
|
||||
case "horizontalLine2":
|
||||
return {
|
||||
name: "水平线2",
|
||||
title: "水平线2",
|
||||
// icon: Icon.getNameList()[36],
|
||||
img: require("data-room-ui/Configuration/images/水平线.png"),
|
||||
component: null,
|
||||
className,
|
||||
w: 300,
|
||||
h: 20,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "verticalLine2":
|
||||
return {
|
||||
name: "垂直线2",
|
||||
title: "垂直线2",
|
||||
// icon: Icon.getNameList()[36],
|
||||
img: require("data-room-ui/Configuration/images/垂直线.png"),
|
||||
component: null,
|
||||
className,
|
||||
w: 20,
|
||||
h: 300,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
};
|
||||
case "warning":
|
||||
return {
|
||||
name: "告警灯",
|
||||
title: "告警灯",
|
||||
icon: Icon.getNameList()[37],
|
||||
className:
|
||||
"com.gccloud.dataroom.core.module.chart.components.ScreenTextChart",
|
||||
w: 200,
|
||||
h: 200,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type,
|
||||
dataHandler: {}, // 数据自定义处理js脚本
|
||||
};
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
180
frontend/packages/js/utils/getDecorationComponentsConfig.js
Normal file
180
frontend/packages/js/utils/getDecorationComponentsConfig.js
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* @description: 得到装饰组件配置
|
||||
*/
|
||||
export default function getComponentConfig (type, classNameType) {
|
||||
const className =
|
||||
'com.gccloud.dataroom.core.module.chart.components.ScreenDecorationChart'
|
||||
switch (type) {
|
||||
case 'decoration1':
|
||||
return {
|
||||
name: '装饰一',
|
||||
title: '装饰一',
|
||||
img: require('data-room-ui/Decorations/images/01.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 350,
|
||||
h: 30,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'decoration2':
|
||||
return {
|
||||
name: '装饰三',
|
||||
title: '装饰三',
|
||||
img: require('data-room-ui/Decorations/images/03.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 350,
|
||||
h: 20,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'decoration2Reverse':
|
||||
return {
|
||||
name: '装饰三(旋转)',
|
||||
title: '装饰三(旋转)',
|
||||
img: require('data-room-ui/Decorations/images/03_reverse.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 20,
|
||||
h: 350,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'decoration3':
|
||||
return {
|
||||
name: '装饰二',
|
||||
title: '装饰二',
|
||||
img: require('data-room-ui/Decorations/images/02.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 350,
|
||||
h: 30,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'decoration4':
|
||||
return {
|
||||
name: '装饰四',
|
||||
title: '装饰四',
|
||||
img: require('data-room-ui/Decorations/images/04.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 30,
|
||||
h: 320,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'decoration4Reverse':
|
||||
return {
|
||||
name: '装饰四(旋转)',
|
||||
title: '装饰四(旋转)',
|
||||
img: require('data-room-ui/Decorations/images/04_reverse.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 320,
|
||||
h: 30,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'decoration5':
|
||||
return {
|
||||
name: '装饰五',
|
||||
title: '装饰五',
|
||||
img: require('data-room-ui/Decorations/images/05.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 350,
|
||||
h: 50,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'decoration6':
|
||||
return {
|
||||
name: '装饰六',
|
||||
title: '装饰六',
|
||||
img: require('data-room-ui/Decorations/images/06.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 350,
|
||||
h: 30,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'decoration8':
|
||||
return {
|
||||
name: '装饰七',
|
||||
title: '装饰七',
|
||||
img: require('data-room-ui/Decorations/images/07.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 350,
|
||||
h: 50,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'decoration8Reverse':
|
||||
return {
|
||||
name: '装饰七(旋转)',
|
||||
title: '装饰七(旋转)',
|
||||
img: require('data-room-ui/Decorations/images/07_reverse.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 350,
|
||||
h: 50,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'decoration9':
|
||||
return {
|
||||
name: '装饰八',
|
||||
title: '装饰八',
|
||||
img: require('data-room-ui/Decorations/images/08.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 150,
|
||||
h: 150,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'decoration10':
|
||||
return {
|
||||
name: '装饰九',
|
||||
title: '装饰九',
|
||||
img: require('data-room-ui/Decorations/images/09.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 350,
|
||||
h: 50,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
case 'decoration11':
|
||||
return {
|
||||
name: '装饰十',
|
||||
title: '装饰十',
|
||||
img: require('data-room-ui/Decorations/images/10.png'),
|
||||
component: null,
|
||||
className,
|
||||
w: 350,
|
||||
h: 50,
|
||||
x: 0,
|
||||
y: 0,
|
||||
type
|
||||
}
|
||||
default:
|
||||
return {}
|
||||
}
|
||||
}
|
||||
231
frontend/packages/js/utils/http.js
Normal file
231
frontend/packages/js/utils/http.js
Normal file
@@ -0,0 +1,231 @@
|
||||
import axios from 'axios'
|
||||
import qs from 'qs'
|
||||
// import _ from 'lodash'
|
||||
import merge from 'lodash/merge'
|
||||
import { Message } from 'element-ui'
|
||||
import { getToken } from '@/utils/auth'
|
||||
/**
|
||||
* 统一进行异常输出
|
||||
* 如果异常只是弹框显示即可,可使用该实例
|
||||
*/
|
||||
const httpConfig = {
|
||||
timeout: 1000 * 30,
|
||||
withCredentials: true,
|
||||
baseURL: process.env.VUE_APP_BASE_API,
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
"AuthToken" : 'Bearer ' + getToken()
|
||||
}
|
||||
}
|
||||
|
||||
const httpCustom = axios.create(httpConfig)
|
||||
/**
|
||||
*对于出现异常时还需要做其他操作,可使用该实例
|
||||
*/
|
||||
const http = axios.create(httpConfig)
|
||||
|
||||
/**
|
||||
* 封装的异常对象
|
||||
* @param message
|
||||
* @param code
|
||||
* @constructor
|
||||
*
|
||||
*/
|
||||
function EipException (message, code) {
|
||||
this.msg = message
|
||||
this.code = code
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求拦截
|
||||
*/
|
||||
http.interceptors.request.use(config => {
|
||||
return {
|
||||
...config,
|
||||
...merge(httpConfig, window.BS_CONFIG?.httpConfigs)
|
||||
}
|
||||
}, error => {
|
||||
return Promise.reject(error)
|
||||
})
|
||||
|
||||
/**
|
||||
* 自定义请求拦截
|
||||
*/
|
||||
httpCustom.interceptors.request.use(config => {
|
||||
return config
|
||||
}, error => {
|
||||
return Promise.reject(error)
|
||||
})
|
||||
|
||||
/**
|
||||
* 响应拦截
|
||||
*/
|
||||
http.interceptors.response.use(response => {
|
||||
const res = response.data
|
||||
// 异常拦截
|
||||
// eslint-disable-next-line no-empty
|
||||
if (res && res.code === 401) {
|
||||
} else if (res && res.code !== 200) {
|
||||
// return Promise.reject(response.data.msg)
|
||||
Message({
|
||||
message: response.data.msg,
|
||||
type: 'error'
|
||||
})
|
||||
throw new EipException(response.data.msg, response.data.code)
|
||||
} else {
|
||||
return res
|
||||
}
|
||||
}, error => {
|
||||
if (error.message && error.message === 'Network Error') {
|
||||
Message({
|
||||
message: error.message,
|
||||
type: 'error'
|
||||
})
|
||||
return Promise.reject(error)
|
||||
// eslint-disable-next-line no-empty
|
||||
} else {
|
||||
}
|
||||
Message({
|
||||
message: '服务异常',
|
||||
type: 'error'
|
||||
})
|
||||
return Promise.reject(error)
|
||||
})
|
||||
|
||||
/**
|
||||
* 响应拦截
|
||||
*/
|
||||
httpCustom.interceptors.response.use(response => {
|
||||
const res = response.data
|
||||
return res
|
||||
}, error => {
|
||||
if (error.message && error.message === 'Network Error') {
|
||||
return Promise.reject(error)
|
||||
// eslint-disable-next-line no-empty
|
||||
} else {
|
||||
}
|
||||
Message({
|
||||
message: '服务异常',
|
||||
type: 'error'
|
||||
})
|
||||
return Promise.reject(error)
|
||||
})
|
||||
|
||||
/**
|
||||
* get请求
|
||||
* @param url
|
||||
* @param params
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
export function get (url, params = {}, customHandlerException = false) {
|
||||
// if (!url.startsWith('http')) {
|
||||
// url = window.BS_CONFIG?.httpConfigs?.baseURL + url
|
||||
// }
|
||||
// 如果是ie浏览器要添加个时间戳,解决浏览器缓存问题
|
||||
if (!!window.ActiveXObject || 'ActiveXObject' in window) {
|
||||
params._t = new Date().getTime()
|
||||
}
|
||||
const axiosInstance = customHandlerException ? httpCustom : http
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance.get(url, {
|
||||
params: params,
|
||||
paramsSerializer: params => {
|
||||
return qs.stringify(params, { indices: false })
|
||||
}
|
||||
}).then(response => {
|
||||
if (customHandlerException) {
|
||||
resolve(response)
|
||||
} else {
|
||||
resolve(response.data)
|
||||
}
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Post 请求
|
||||
* @param url
|
||||
* @param params
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
export function post (url, data = {}, customHandlerException = false) {
|
||||
// if (!url.startsWith('http')) {
|
||||
// url = window.BS_CONFIG?.httpConfigs?.baseURL + url
|
||||
// }
|
||||
const axiosInstance = customHandlerException ? httpCustom : http
|
||||
data = JSON.stringify(data)
|
||||
return new Promise((resolve, reject) => {
|
||||
axiosInstance.post(url, data).then(response => {
|
||||
if (customHandlerException) {
|
||||
resolve(response)
|
||||
} else {
|
||||
resolve(response.data)
|
||||
}
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
/**
|
||||
* download 请求
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
|
||||
export function download (url, headers = {}, params = {}, body = {}) {
|
||||
// if (!url.startsWith('http')) {
|
||||
// url = window.BS_CONFIG?.httpConfigs?.baseURL + url
|
||||
// }
|
||||
// 如果是ie浏览器要添加个时间戳,解决浏览器缓存问题
|
||||
if (!!window.ActiveXObject || 'ActiveXObject' in window) {
|
||||
params._t = new Date().getTime()
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axios({
|
||||
method: 'post',
|
||||
url: httpConfig.baseURL+ url,
|
||||
headers: httpConfig.headers,
|
||||
params: params,
|
||||
data: body,
|
||||
withCredentials: false,
|
||||
responseType: 'arraybuffer'
|
||||
}).then(res => {
|
||||
// IE10,11采用自带下载文件流方法
|
||||
if ((!!window.ActiveXObject || 'ActiveXObject' in window) && window.navigator && window.navigator.msSaveOrOpenBlob) {
|
||||
window.navigator.msSaveOrOpenBlob(new Blob([res.data]), res.headers.filename)
|
||||
return
|
||||
}
|
||||
const fileUrl = window.URL.createObjectURL(new Blob([res.data]))
|
||||
// 创建超链接
|
||||
const fileLink = document.createElement('a')
|
||||
fileLink.href = fileUrl
|
||||
// 设置下载文件名
|
||||
let responseFileName = res.headers.filename
|
||||
// 解决中文乱码
|
||||
responseFileName = window.decodeURI(responseFileName)
|
||||
fileLink.setAttribute('download', responseFileName)
|
||||
document.body.appendChild(fileLink)
|
||||
// 模拟人工点击下载超链接
|
||||
fileLink.click()
|
||||
// 释放资源
|
||||
document.body.removeChild(fileLink)
|
||||
window.URL.revokeObjectURL(fileUrl)
|
||||
}).catch(e => {
|
||||
const status = e?.response?.status
|
||||
if (status === 404) {
|
||||
Message({
|
||||
message: '文件不存在或已被删除',
|
||||
type: 'error'
|
||||
})
|
||||
return
|
||||
}
|
||||
Message({
|
||||
message: '服务异常',
|
||||
type: 'error'
|
||||
})
|
||||
console.error('服务异常')
|
||||
})
|
||||
})
|
||||
}
|
||||
143
frontend/packages/js/utils/httpParamsFormatting.js
Normal file
143
frontend/packages/js/utils/httpParamsFormatting.js
Normal file
@@ -0,0 +1,143 @@
|
||||
import axios from 'axios'
|
||||
// import { Loading, Message } from 'element-ui'
|
||||
// import _ from 'lodash'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
export default function axiosFormatting (customConfig) {
|
||||
const newCustomConfig = replaceParams(customConfig)
|
||||
// 将请求头和请求参数的值转化为对象形式
|
||||
const httpConfig = {
|
||||
timeout: 1000 * 30,
|
||||
baseURL: '',
|
||||
headers: { 'Content-Type': 'application/json', ...newCustomConfig.headers }
|
||||
}
|
||||
// let loadingInstance = null // 加载全局的loading
|
||||
const instance = axios.create(httpConfig)
|
||||
/** 添加请求拦截器 **/
|
||||
instance.interceptors.request.use(config => {
|
||||
/**
|
||||
* 在这里:可以根据业务需求可以在发送请求之前做些什么。
|
||||
* config.headers['token'] = sessionStorage.getItem('token') || ''
|
||||
*/
|
||||
// 执行请求脚本
|
||||
// https://mock.presstime.cn/mock/64bf8a00ce1b0ea640809069/test_copy_copy_copy/httpData?token=123&ss=ss
|
||||
const req = { ...config, url: {} }
|
||||
eval(newCustomConfig.requestScript)
|
||||
for (const key in req.url) {
|
||||
newCustomConfig.url = replaceUrlParam(newCustomConfig.url, key, req.url[key])
|
||||
}
|
||||
config = { ...config, ...req, url: newCustomConfig.url }
|
||||
return config
|
||||
}, error => {
|
||||
// 对请求错误做些什么
|
||||
return Promise.reject(error)
|
||||
})
|
||||
|
||||
/** 添加响应拦截器 **/
|
||||
instance.interceptors.response.use(response => {
|
||||
const resp = response.data
|
||||
// console.log('resp: ', resp);
|
||||
// 执行响应脚本
|
||||
if (newCustomConfig.responseScript) {
|
||||
// eslint-disable-next-line no-new-func
|
||||
const getResp = new Function('resp', newCustomConfig.responseScript)
|
||||
const res = getResp(resp)
|
||||
return Promise.resolve(res)
|
||||
} else {
|
||||
return Promise.resolve(resp)
|
||||
}
|
||||
})
|
||||
const body = newCustomConfig?.body.replace(/: ,/g, ':undefined,').replace(/, }/g, ',undefined}')
|
||||
/** 发送请求 **/
|
||||
return new Promise((resolve, reject) => {
|
||||
instance({
|
||||
method: newCustomConfig.method,
|
||||
url: newCustomConfig.url,
|
||||
params: newCustomConfig.params,
|
||||
// params 序列化操作
|
||||
paramsSerializer: (params) => {
|
||||
return Object.keys(params)
|
||||
.map(key => {
|
||||
if (Array.isArray(params[key])) {
|
||||
return params[key].map(value => `${key}=${value}`).join('&')
|
||||
} else {
|
||||
return `${key}=${params[key]}`
|
||||
}
|
||||
})
|
||||
.join('&')
|
||||
},
|
||||
data: newCustomConfig.method === 'post' ? body : undefined
|
||||
}).then(response => {
|
||||
resolve(response)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
// 动态替换url后面参数的值
|
||||
function replaceUrlParam (url, paramName, paramValue) {
|
||||
const regex = new RegExp(`([?&])${paramName}=.*?(&|$)`, 'i')
|
||||
const separator = url.indexOf('?') !== -1 ? '&' : '?'
|
||||
if (url.match(regex)) {
|
||||
return url.replace(regex, `$1${paramName}=${paramValue}$2`)
|
||||
} else {
|
||||
return `${url}${separator}${paramName}=${paramValue}`
|
||||
}
|
||||
}
|
||||
// 将参数的值替换掉其他配置中对应属性的值
|
||||
function replaceParams (customConfig) {
|
||||
const newConfig = cloneDeep(customConfig)
|
||||
newConfig.url = evalStrFunc(newConfig.paramsList, newConfig.url)
|
||||
newConfig.headers = evalArrFunc(newConfig.paramsList, newConfig.headers)
|
||||
newConfig.params = evalArrFunc(newConfig.paramsList, newConfig.params)
|
||||
newConfig.body = evalStrFunc(newConfig.paramsList, newConfig.body)
|
||||
return newConfig
|
||||
}
|
||||
function evalStrFunc (paramsList, string) {
|
||||
// 取name作为变量名, value作为变量值 { name: '站三', token: '123'}
|
||||
const params = paramsList.reduce((acc, cur) => {
|
||||
acc[cur.name] = cur.value
|
||||
return acc
|
||||
}, {})
|
||||
// 将url中 ${xxx} 替换成 ${params.xxx}
|
||||
const str = string.replace(/\$\{(\w+)\}/g, (match, p1) => {
|
||||
return '${params.' + p1 + '}'
|
||||
})
|
||||
const transformStr = ''
|
||||
// 将字符串中的${}替换为变量, 使用eval执行
|
||||
eval('transformStr = `' + str + '`')
|
||||
return transformStr
|
||||
}
|
||||
function evalArrFunc (paramsList, arr) {
|
||||
// 取name作为变量名, value作为变量值 { name: '站三', token: '123'}
|
||||
const params = paramsList.reduce((acc, cur) => {
|
||||
acc[cur.name] = cur.value
|
||||
return acc
|
||||
}, {})
|
||||
// 取name作为变量名, value作为变量值 { _name: '${name}', _token: '${token}'}
|
||||
const paramsListObj = arr.reduce((acc, cur) => {
|
||||
if (acc[cur.key]) {
|
||||
if (Array.isArray(acc[cur.key])) {
|
||||
acc[cur.key].push(cur.value)
|
||||
} else {
|
||||
acc[cur.key] = [acc[cur.key], cur.value]
|
||||
}
|
||||
} else {
|
||||
acc[cur.key] = cur.value
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
// 转成字符串
|
||||
const paramsListStr = JSON.stringify(paramsListObj)
|
||||
|
||||
// 将url中 ${xxx} 替换成 ${params.xxx}
|
||||
const str = paramsListStr.replace(/\$\{(\w+)\}/g, (match, p1) => {
|
||||
return '${params.' + p1 + '}'
|
||||
})
|
||||
const transformStr = ''
|
||||
// 将字符串中的${}替换为变量, 使用eval执行
|
||||
eval('transformStr = `' + str + '`')
|
||||
const obj = JSON.parse(transformStr)
|
||||
|
||||
return obj
|
||||
}
|
||||
57
frontend/packages/js/utils/index.js
Normal file
57
frontend/packages/js/utils/index.js
Normal file
@@ -0,0 +1,57 @@
|
||||
// import _ from 'lodash'
|
||||
import upperFirst from 'lodash/upperFirst'
|
||||
export const randomString = e => {
|
||||
e = e || 32
|
||||
const t = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz'
|
||||
const a = t.length
|
||||
let n = ''
|
||||
for (let i = 0; i < e; i++) n += t.charAt(Math.floor(Math.random() * a))
|
||||
return n
|
||||
}
|
||||
|
||||
export const resolveComponentType = type => {
|
||||
return `${upperFirst(type)}`
|
||||
}
|
||||
export function deepCompare (obj1, obj2, excludeKeys = []) {
|
||||
// eslint-disable-next-line eqeqeq
|
||||
if (obj1 == obj2) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 如果两个对象中的一个是基本类型,则它们不相等
|
||||
if (typeof obj1 !== 'object' || obj1 === null ||
|
||||
typeof obj2 !== 'object' || obj2 === null) {
|
||||
return true
|
||||
}
|
||||
|
||||
// 如果两个对象的类型不相同,则它们不相等
|
||||
if (obj1.constructor !== obj2.constructor) {
|
||||
return true
|
||||
}
|
||||
|
||||
// 递归地比较对象的属性
|
||||
for (const prop in obj1) {
|
||||
// 如果prop是要排除的key,则跳过
|
||||
if (excludeKeys.includes(prop)) {
|
||||
continue
|
||||
}
|
||||
if (obj1.hasOwnProperty(prop)) {
|
||||
if (!obj2.hasOwnProperty(prop)) {
|
||||
return true
|
||||
}
|
||||
if (deepCompare(obj1[prop], obj2[prop])) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查 obj2 中是否有 obj1 没有的属性
|
||||
for (const prop in obj2) {
|
||||
if (obj2.hasOwnProperty(prop) && !obj1.hasOwnProperty(prop)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// 如果上面的检查都通过,则对象是相等的
|
||||
return false
|
||||
}
|
||||
23
frontend/packages/js/utils/jsonSerialize.js
Normal file
23
frontend/packages/js/utils/jsonSerialize.js
Normal file
@@ -0,0 +1,23 @@
|
||||
// 自定义序列化方法:解决JSON.stringify方法忽略函数属性的问题
|
||||
export function customSerialize(obj) {
|
||||
// 将对象属性和函数转换为字符串形式
|
||||
const serializedObj = JSON.stringify(obj, function (key, value) {
|
||||
if (typeof value === "function") {
|
||||
return value.toString(); // 将函数转换为字符串
|
||||
}
|
||||
return value; // 保持其他属性不变
|
||||
});
|
||||
|
||||
return serializedObj;
|
||||
}
|
||||
// 自定义反序列化方法
|
||||
export function customDeserialize(serializedObj) {
|
||||
const parsedObject = JSON.parse(serializedObj, function (key, value) {
|
||||
if (typeof value === "string" && value.indexOf("function") === 0) {
|
||||
// 将字符串还原为函数
|
||||
return new Function("return " + value)();
|
||||
}
|
||||
return value; // 保持其他属性不变
|
||||
});
|
||||
return parsedObject;
|
||||
}
|
||||
86
frontend/packages/js/utils/mapDataService.js
Normal file
86
frontend/packages/js/utils/mapDataService.js
Normal file
@@ -0,0 +1,86 @@
|
||||
/*!
|
||||
* 地图数据管理
|
||||
*/
|
||||
import Vue from 'vue'
|
||||
|
||||
/**
|
||||
* 获取地图列表
|
||||
* @param params
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const mapList = (params = {}, flag = false) => Vue.prototype.$dataRoomAxios.get('/bigScreen/map/list', params, flag)
|
||||
|
||||
/**
|
||||
* 新增地图
|
||||
* @param params
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const mapAdd = (params = {}, flag = false) => Vue.prototype.$dataRoomAxios.post('/bigScreen/map/add', params, flag)
|
||||
|
||||
/**
|
||||
* 更新地图
|
||||
* @param params
|
||||
* @param flag
|
||||
* @returns {*}
|
||||
*/
|
||||
const mapUpdate = (params = {}, flag = false) => Vue.prototype.$dataRoomAxios.post('/bigScreen/map/update', params, flag)
|
||||
|
||||
/**
|
||||
* 删除地图
|
||||
* @param id
|
||||
*/
|
||||
const mapDelete = (id = '-1') => Vue.prototype.$dataRoomAxios.post(`/bigScreen/map/delete/${id}`)
|
||||
|
||||
/**
|
||||
* 级联删除地图
|
||||
* @param id
|
||||
*/
|
||||
const mapCascadeDelete = (id = '-1') => Vue.prototype.$dataRoomAxios.post(`/bigScreen/map/cascadingDelete/${id}`)
|
||||
|
||||
/**
|
||||
* 根据父编码解析父级json中的子级
|
||||
* @param code
|
||||
*/
|
||||
const getMapChildFromGeoJson = (code = '-1') => Vue.prototype.$dataRoomAxios.get(`/bigScreen/map/getMapChildFromGeoJson/${code}`)
|
||||
|
||||
/**
|
||||
* 上传地图json
|
||||
* @param params
|
||||
* @param flag
|
||||
*/
|
||||
const uploadGeoJson = (params = {}, flag = false) => Vue.prototype.$dataRoomAxios.post('/bigScreen/map/upload', params, flag)
|
||||
|
||||
/**
|
||||
* 编码重复校验
|
||||
* @param params
|
||||
* @param flag
|
||||
*/
|
||||
const repeatCheck = (params = {}, flag = false) => Vue.prototype.$dataRoomAxios.post('/bigScreen/map/repeat/code', params, flag)
|
||||
|
||||
/**
|
||||
* 名称重复校验
|
||||
* @param params
|
||||
* @param flag
|
||||
*/
|
||||
const nameRepeatCheck = (params = {}, flag = false) => Vue.prototype.$dataRoomAxios.post('/bigScreen/map/repeat/name', params, flag)
|
||||
|
||||
/**
|
||||
* 根据父编码解析父级json中的子级
|
||||
* @param id
|
||||
*/
|
||||
const mapInfo = (id = '-1') => Vue.prototype.$dataRoomAxios.get(`/bigScreen/map/info/${id}`)
|
||||
|
||||
export {
|
||||
mapList,
|
||||
mapAdd,
|
||||
mapUpdate,
|
||||
mapDelete,
|
||||
mapCascadeDelete,
|
||||
getMapChildFromGeoJson,
|
||||
uploadGeoJson,
|
||||
repeatCheck,
|
||||
nameRepeatCheck,
|
||||
mapInfo
|
||||
}
|
||||
68
frontend/packages/js/utils/mqttClient.js
Normal file
68
frontend/packages/js/utils/mqttClient.js
Normal file
@@ -0,0 +1,68 @@
|
||||
// mqttClient.js
|
||||
import mqtt from 'mqtt';
|
||||
|
||||
class MqttClient {
|
||||
constructor(brokerUrl, options) {
|
||||
this.brokerUrl = brokerUrl || '';
|
||||
this.clientId = options.clientId || "SW-VIEWS" + new Date().getTime();
|
||||
this.username = options.username || 'admin';
|
||||
this.password = options.password || '123456';
|
||||
this.client = null;
|
||||
}
|
||||
|
||||
// 连接 MQTT broker
|
||||
connect() {
|
||||
this.client = mqtt.connect(this.brokerUrl, {
|
||||
clientId: this.clientId,
|
||||
username: this.username,
|
||||
password: this.password
|
||||
});
|
||||
|
||||
this.client.on('connect', () => {
|
||||
console.log('mqtt 已经连接成功');
|
||||
});
|
||||
|
||||
this.client.on('reconnect', () => {
|
||||
console.log("mqtt reconnect");
|
||||
});
|
||||
|
||||
this.client.on('offline', () => {
|
||||
console.log("mqtt offline");
|
||||
});
|
||||
|
||||
this.client.on('error', (error) => {
|
||||
console.log("mqtt error");
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
// 订阅某个主题
|
||||
subscribe(topic, callback) {
|
||||
if (this.client) {
|
||||
this.client.subscribe(topic, (err) => {
|
||||
if (!err) {
|
||||
console.log(`mqtt 订阅主题 ${topic} 成功`);
|
||||
} else {
|
||||
console.log(`mqtt 订阅主题 ${topic} 失败`);
|
||||
}
|
||||
});
|
||||
|
||||
this.client.on('message', (topic, message) => {
|
||||
console.log(`mqtt 收到来自 ${topic} 的消息`);
|
||||
callback(topic, message);
|
||||
});
|
||||
} else {
|
||||
console.error('MQTT client is not connected');
|
||||
}
|
||||
}
|
||||
|
||||
// 断开连接
|
||||
disconnect() {
|
||||
if (this.client) {
|
||||
this.client.end();
|
||||
console.log('mqtt 连接已断开');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default MqttClient;
|
||||
198
frontend/packages/js/utils/registerConfig.js
Normal file
198
frontend/packages/js/utils/registerConfig.js
Normal file
@@ -0,0 +1,198 @@
|
||||
/**
|
||||
* 对象属性合并,与 Object.assign 语法不同
|
||||
* @param target
|
||||
* @param source
|
||||
* @returns {{}}
|
||||
*/
|
||||
function configDeepMerge (target, source) {
|
||||
const merged = {}
|
||||
for (const each in source) {
|
||||
if (target.hasOwnProperty(each) && source.hasOwnProperty(each)) {
|
||||
if (
|
||||
typeof target[each] === 'object' &&
|
||||
typeof source[each] === 'object'
|
||||
) {
|
||||
merged[each] = configDeepMerge(target[each], source[each])
|
||||
} else {
|
||||
merged[each] = source[each]
|
||||
}
|
||||
} else if (source.hasOwnProperty(each)) {
|
||||
merged[each] = source[each]
|
||||
}
|
||||
}
|
||||
for (const eachTarget in target) {
|
||||
if (!(eachTarget in source) && target.hasOwnProperty(eachTarget)) {
|
||||
merged[eachTarget] = target[eachTarget]
|
||||
}
|
||||
}
|
||||
return merged
|
||||
}
|
||||
// 自动注册路由
|
||||
function registerRouters (config, router) {
|
||||
// 没有router对象不注册路由
|
||||
if (!router) {
|
||||
return
|
||||
}
|
||||
const routers = [
|
||||
// 页面管理
|
||||
{
|
||||
path: config?.routers?.pageManagementUrl || '/management',
|
||||
redirect: config?.routers?.pageListUrl || '/big-screen-list',
|
||||
component: () => import('data-room-ui/Layout/BigScreenHomeLayout'),
|
||||
children: [
|
||||
{
|
||||
path: config?.routers?.pageListUrl || '/big-screen-list',
|
||||
name: 'BigScreenList',
|
||||
component: () =>
|
||||
require.ensure([], () => require('data-room-ui/BigScreenMag')),
|
||||
meta: {
|
||||
title: '大屏管理'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: config?.routers?.templateListUrl || '/big-screen-template',
|
||||
name: 'BigScreenTemplate',
|
||||
component: () =>
|
||||
require.ensure([], () => require('data-room-ui/BigScreenTempMag')),
|
||||
meta: {
|
||||
title: '模版管理'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: config?.routers?.dataSourceUrl || '/big-screen-dataSource',
|
||||
component: () => import('data-room-ui/DataSourceManagement'),
|
||||
meta: {
|
||||
title: '数据源管理'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: config?.routers?.dataSetUrl || '/big-screen-dataSet',
|
||||
component: () => import('data-room-ui/DataSetManagement'),
|
||||
meta: {
|
||||
title: '数据集管理'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: config?.routers?.mapData || '/big-screen-map-data',
|
||||
component: () => import('data-room-ui/MapDataManagement'),
|
||||
meta: {
|
||||
title: '地图数据管理'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: config?.routers?.SourceUrl || '/big-screen-source',
|
||||
component: () => import('data-room-ui/SourceManagement'),
|
||||
meta: {
|
||||
title: '资源库'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: config?.routers?.componentUrl || '/big-screen-components',
|
||||
component: () => import('data-room-ui/BigScreenComponentMag'),
|
||||
meta: {
|
||||
title: '资源管理'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: config?.routers?.designUrl || '/big-screen/design',
|
||||
name: 'BigScreenDesign',
|
||||
component: () =>
|
||||
require.ensure([], () => require('data-room-ui/BigScreenDesign'))
|
||||
},
|
||||
{
|
||||
path: config?.routers?.previewUrl || '/big-screen/preview',
|
||||
name: 'BigScreenPreview',
|
||||
component: () =>
|
||||
require.ensure([], () => require('data-room-ui/BigScreenRun'))
|
||||
},
|
||||
{
|
||||
path: '/dataRoom-redirect',
|
||||
name: 'Redirect',
|
||||
component: () => import('data-room-ui/Layout/Redirect/index.vue')
|
||||
},
|
||||
{
|
||||
path: config?.routers?.bizComponentDesignUrl || '/big-screen-biz-component-design',
|
||||
component: () => import('data-room-ui/BizComponent'),
|
||||
meta: {
|
||||
title: '业务组件'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: config?.routers?.bizComponentPreviewUrl || '/big-screen-biz-component-preview',
|
||||
component: () => import('data-room-ui/BizComponent/Preview.vue'),
|
||||
meta: {
|
||||
title: '业务组件预览'
|
||||
}
|
||||
}
|
||||
]
|
||||
// 如果router有addRoutes方法
|
||||
if (router?.addRoutes) {
|
||||
router?.addRoutes(routers)
|
||||
} else {
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
routers?.forEach((route) => {
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
router?.addRoute(route)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 注册配置
|
||||
function registerTheme (config) {
|
||||
const defaultTheme = {
|
||||
'--db-background-appmain': '#f0f2f5',
|
||||
'--bs-el-color-primary': '#409EFF', // elment-ui主题色,激活
|
||||
'--bs-background-1': '#151a26', // 整体背景色
|
||||
'--bs-background-2': '#232832', // 布局背景色
|
||||
'--bs-el-background-1': '#151A26', // 组件背景色,输入框...
|
||||
'--bs-el-background-2': '#35393F', // 组件背景色,按钮、分页、加载...
|
||||
'--bs-el-background-3': '#303640', // 组件背景色,表格头部、下拉框hover...
|
||||
'--bs-el-title': '#ffffff', // 标题字体颜色
|
||||
'--bs-el-text': '#ffffff', // 一般字体颜色
|
||||
'--bs-el-border': 'transparent', // 边框颜色
|
||||
'--bs-el-color-primary-active': '64, 158, 255'
|
||||
}
|
||||
const customTheme= {
|
||||
'--db-background-appmain': '#151a26',
|
||||
'--db-background-header': '#007aff', // 头部颜色
|
||||
'--db-background-leftPanel': '#eef2f7', // 左侧组件栏背景色
|
||||
'--db-background-1': '#fff', // 整体背景色
|
||||
'--db-background-2': '#fff', // 布局背景色
|
||||
'--db-background-3': '#f6f7fb', // 列表背景色
|
||||
'--db-el-background-1': '#fff', // 组件背景色,输入框...
|
||||
'--db-el-background-2': '#F5F7FA', // 组件背景色,按钮、分页、加载...
|
||||
'--db-el-background-3': '#F5F7FA', // 组件背景色,表格头部、下拉框hover...
|
||||
'--db-el-title': '#76838f', // 标题字体颜色
|
||||
'--db-el-text': '#36474f', // 一般字体颜色
|
||||
'--db-el-color-primary': '#409EFF', // elment-ui主题色,激活
|
||||
'--db-el-border': 'transparent' // 边框颜色
|
||||
|
||||
}
|
||||
const mergedTheme = { ...defaultTheme, ...config?.customTheme }
|
||||
const style = document.createElement('style')
|
||||
style.type = 'text/css'
|
||||
let themeStr = ''
|
||||
for (const key in mergedTheme) {
|
||||
themeStr += `${key}:${mergedTheme[key]};`
|
||||
}
|
||||
// 给body添加class bs-body-theme-wrap
|
||||
document.body.classList.add('bs-body-theme-wrap')
|
||||
style.innerHTML = `.bs-body-theme-wrap {${themeStr}}`
|
||||
document.getElementsByTagName('head')[0].appendChild(style)
|
||||
}
|
||||
|
||||
// 注册配置
|
||||
export default function (config, router) {
|
||||
window.BS_CONFIG = {}
|
||||
window.BS_CONFIG = configDeepMerge(window.BS_CONFIG, config)
|
||||
if (!config?.httpConfigs?.fileUrlPrefix) {
|
||||
// 如果没有配置文件访问前缀,使用baseURL加上/static作为文件前缀
|
||||
window.BS_CONFIG.httpConfigs.fileUrlPrefix = window.BS_CONFIG.httpConfigs.baseURL + '/static'
|
||||
}
|
||||
// 注册路由
|
||||
registerRouters(config, router)
|
||||
// 注册自定义主题
|
||||
registerTheme(config)
|
||||
}
|
||||
42
frontend/packages/js/utils/rightSettingImport.js
Normal file
42
frontend/packages/js/utils/rightSettingImport.js
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* @description: 批量导入所有右侧配置组件
|
||||
* @Date: 2023-03-13 10:04:58
|
||||
* @Author: xing.heng
|
||||
* @LastEditors: xing.heng
|
||||
* @LastEditTime: 2023-05-17 13:18:36
|
||||
*/
|
||||
const modules = {};
|
||||
const replaceName = {};
|
||||
// 排除的组件
|
||||
const excludeCommponents = []; // 有的话就添加进去
|
||||
function importComponentSetting(files) {
|
||||
files
|
||||
.keys()
|
||||
.filter((key) => {
|
||||
return key.match(/setting/);
|
||||
})
|
||||
.forEach((key) => {
|
||||
// 正则,取到./和/之间的字符串
|
||||
const reg = new RegExp("(.\\/)(.*)(\\/)");
|
||||
let moduleName = key.match(reg)[0].replace(/(\.\/)|(\/)/g, "");
|
||||
// 替换组件名称
|
||||
if (replaceName[moduleName]) {
|
||||
moduleName = replaceName[moduleName];
|
||||
}
|
||||
// 去掉排除的组件
|
||||
if (!excludeCommponents.includes(moduleName)) {
|
||||
modules[moduleName] = files(key).default;
|
||||
}
|
||||
});
|
||||
}
|
||||
importComponentSetting(
|
||||
require.context("data-room-ui/BasicComponents", true, /\.vue$/)
|
||||
);
|
||||
importComponentSetting(require.context("data-room-ui/Borders", true, /\.vue$/));
|
||||
importComponentSetting(
|
||||
require.context("data-room-ui/Decorations", true, /\.vue$/)
|
||||
);
|
||||
importComponentSetting(
|
||||
require.context("data-room-ui/Configuration", true, /\.vue$/)
|
||||
);
|
||||
export default modules;
|
||||
64
frontend/packages/js/utils/table.js
Normal file
64
frontend/packages/js/utils/table.js
Normal file
@@ -0,0 +1,64 @@
|
||||
|
||||
// 设置表格高度
|
||||
const doResize = async (el, binding, vnode) => {
|
||||
// 获取表格Dom对象
|
||||
const {
|
||||
componentInstance: $table
|
||||
} = await vnode
|
||||
// 获取调用传递过来的数据
|
||||
const {
|
||||
value
|
||||
} = binding
|
||||
if (!$table.height) {
|
||||
throw new Error("使用v-table指令,el-table需设置height,例如: height='0'")
|
||||
}
|
||||
// 获取距底部距离(用于展示页码等信息)
|
||||
const bottomOffset = value || 100
|
||||
if (!$table) return
|
||||
// 计算列表高度并设置
|
||||
let height = window.innerHeight - el.getBoundingClientRect().top - bottomOffset
|
||||
height = height + 32 // 针对没有底部适配
|
||||
$table.layout.setHeight(height)
|
||||
$table.doLayout()
|
||||
}
|
||||
// 节流函数
|
||||
const throttle = (fn) => {
|
||||
let flag = null
|
||||
return function () {
|
||||
if (!flag) {
|
||||
flag = setTimeout(() => {
|
||||
fn()
|
||||
flag = null
|
||||
}
|
||||
, 500)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
// 初始化设置
|
||||
bind (el, binding, vnode) {
|
||||
// 设置resize监听方法
|
||||
el.resizeListener = async () => {
|
||||
await doResize(el, binding, vnode)
|
||||
}
|
||||
// 绑定监听方法
|
||||
window.addEventListener('resize', throttle(el.resizeListener))
|
||||
},
|
||||
|
||||
// 绑定默认高度
|
||||
async inserted (el, binding, vnode) {
|
||||
await doResize(el, binding, vnode)
|
||||
},
|
||||
// 更新数据时延时绑定高度
|
||||
async componentUpdated (el, binding, vnode) {
|
||||
await setTimeout(() => {
|
||||
doResize(el, binding, vnode)
|
||||
}, 500)
|
||||
},
|
||||
// 销毁时设置
|
||||
unbind (el) {
|
||||
// 移除resize监听
|
||||
window.removeEventListener('resize', throttle(el.resizeListener))
|
||||
}
|
||||
}
|
||||
121
frontend/packages/js/utils/themeFormatting.js
Normal file
121
frontend/packages/js/utils/themeFormatting.js
Normal file
@@ -0,0 +1,121 @@
|
||||
|
||||
/**
|
||||
* @Description: 主题设置格式化
|
||||
* @author liu.shiyi
|
||||
* @date 2023/8/17 14:47
|
||||
*/
|
||||
// 将组件中的setting里面的主题设置(颜色)存放到theme里面
|
||||
|
||||
export function settingToTheme (config, type) {
|
||||
// 考虑与上一次保存过的主题进行合并
|
||||
// 排除掉主题非暗黑非明亮的情况
|
||||
if (['dark', 'light'].includes(type)) {
|
||||
const theme = { dark: { ...config?.theme?.dark }, light: { ...config?.theme?.light } }
|
||||
// 根据组件的type来判断主题的转化方式
|
||||
// 如果是g2组件或者远程组件
|
||||
if (['customComponent', 'remoteComponent', 'echartsComponent'].includes(config.type)) {
|
||||
config.setting.forEach((setItem) => {
|
||||
if (['gradual', 'colorPicker', 'colorSelect'].includes(setItem.type)) {
|
||||
theme[type][setItem.field] = setItem.value
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// 如果是普通组件
|
||||
if (config.customize && Object.keys(config.customize).length) {
|
||||
// customize属性存在层级
|
||||
for (const item in config.customize) {
|
||||
const value = config.customize[item]
|
||||
// 如果包含二级属性
|
||||
if (value && typeof value === 'object' && Object.keys(value).length) {
|
||||
// 对于二级属性
|
||||
for (const subKey in value) {
|
||||
if (subKey.includes('color') || subKey.includes('Color') || subKey.includes('BGC')) {
|
||||
theme[type][`${item}_${subKey}`] = value[subKey]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 如果只有一级属性
|
||||
if (item.includes('color') || item.includes('Color') || item.includes('BGC')) {
|
||||
theme[type][item] = config.customize[item]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return theme
|
||||
} else {
|
||||
return config?.theme || { dark: {}, light: {} }
|
||||
}
|
||||
}
|
||||
// 将保存的theme主题设置(颜色)存放到chartList
|
||||
export function themeToSetting (chartList, type) {
|
||||
let modifiedChartList = chartList
|
||||
let finalChartList = chartList
|
||||
// 排除掉主题非暗黑非明亮的情况
|
||||
if (['dark', 'light'].includes(type)) {
|
||||
modifiedChartList = chartList.map((item) => {
|
||||
// 使用 map 方法遍历 chartList 数组并执行操作chartThemeToSetting
|
||||
return chartThemeToSetting(item, type)
|
||||
})
|
||||
finalChartList = modifiedChartList.map((item) => {
|
||||
// 如果当前项的 type 为 'chartTab',遍历其 tabList 数组并执行操作chartThemeToSetting
|
||||
if (item.type === 'chartTab' && Array.isArray(item.customize.tabList) && item.customize.tabList.length) {
|
||||
const modifiedChildren = item.customize.tabList.map((child) => {
|
||||
return { ...child, chart: chartThemeToSetting(child.chart, type) }
|
||||
})
|
||||
return { ...item, customize: { ...item.customize, tabList: modifiedChildren } }
|
||||
}
|
||||
return item
|
||||
})
|
||||
}
|
||||
return finalChartList
|
||||
}
|
||||
// 对单个组件进行主题设置(从theme到Setting)
|
||||
function chartThemeToSetting (chart, type) {
|
||||
if (chart.option && chart.option.theme) {
|
||||
chart.option.theme = type === 'dark' ? 'transparent' : 'light'
|
||||
}
|
||||
|
||||
if (chart.theme && chart.theme[type]) {
|
||||
// 如果是g2组件或者远程组件
|
||||
if (['customComponent', 'remoteComponent', 'echartsComponent'].includes(chart.type)) {
|
||||
for (const item of chart.setting) {
|
||||
// 检查 obj 中是否存在与 item.field 相对应的属性
|
||||
if (Object.prototype.hasOwnProperty.call(chart.theme[type], item.field)) {
|
||||
// 更新 setting 中对应项的 value 值为 theme 中的属性值
|
||||
item.value = chart.theme[type][item.field]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 如果是普通组件
|
||||
if (chart.customize && Object.keys(chart.customize).length) {
|
||||
for (const key in chart.theme[type]) {
|
||||
const value = chart.theme[type][key]
|
||||
// 如果对应的是二级属性
|
||||
if (key.includes('_')) {
|
||||
const [propertyName, subPropertyName] = key.split('_')
|
||||
if (!chart.customize[propertyName]) {
|
||||
chart.customize[propertyName] = {}
|
||||
} else {
|
||||
chart.customize[propertyName][subPropertyName] = value
|
||||
}
|
||||
} else {
|
||||
// 对应的一级属性
|
||||
if (Object.prototype.hasOwnProperty.call(chart.customize, key)) {
|
||||
// 更新 customize 中对应项的值为 theme 中的属性值
|
||||
chart.customize[key] = chart.theme[type][key]
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const item in chart.customize) {
|
||||
// 检查 obj 中是否存在与 customize 相对应的属性
|
||||
if (Object.prototype.hasOwnProperty.call(chart.theme[type], item)) {
|
||||
// 更新 customize 中对应项的值为 theme 中的属性值
|
||||
chart.customize[item] = chart.theme[type][item]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return chart
|
||||
}
|
||||
13
frontend/packages/js/utils/updateTheme.js
Normal file
13
frontend/packages/js/utils/updateTheme.js
Normal file
@@ -0,0 +1,13 @@
|
||||
export default function updateTheme (data) {
|
||||
const querySelectorName = data === false ? false : !data ? '.el-button--primary' : data
|
||||
if (querySelectorName) {
|
||||
window.requestAnimationFrame(() => {
|
||||
const primaryButton = document.querySelector(querySelectorName)
|
||||
if (primaryButton) {
|
||||
const backgroundColor = window.getComputedStyle(primaryButton).getPropertyValue('background-color')
|
||||
const element = document.querySelector('.bs-body-theme-wrap')
|
||||
element.style.setProperty('--bs-el-color-primary', backgroundColor)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
8
frontend/packages/js/utils/userAgent.js
Normal file
8
frontend/packages/js/utils/userAgent.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// 是否是火狐浏览器
|
||||
export const isFirefox = () => {
|
||||
const userAgent = navigator.userAgent
|
||||
if (userAgent.indexOf('Firefox') > -1) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
35
frontend/packages/js/utils/voiceBroadcast.js
Normal file
35
frontend/packages/js/utils/voiceBroadcast.js
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @description 文字转语音方法
|
||||
* @public
|
||||
* @param { text, rate, lang, volume, pitch } object
|
||||
* @param text 要合成的文字内容,字符串
|
||||
* @param rate 读取文字的语速 0.1~10 正常1
|
||||
* @param lang 读取文字时的语言
|
||||
* @param volume 读取时声音的音量 0~1 正常1
|
||||
* @param pitch 读取时声音的音高 0~2 正常1
|
||||
* @returns SpeechSynthesisUtterance
|
||||
*/
|
||||
export default function speak ({ text, speechRate, lang, volume, pitch }, endEvent, startEvent) {
|
||||
if (!window.SpeechSynthesisUtterance) {
|
||||
console.warn('当前浏览器不支持文字转语音服务')
|
||||
return
|
||||
}
|
||||
|
||||
if (!text) {
|
||||
return
|
||||
}
|
||||
|
||||
const speechUtterance = new SpeechSynthesisUtterance()
|
||||
speechUtterance.text = text
|
||||
speechUtterance.rate = speechRate || 1
|
||||
speechUtterance.lang = lang || 'zh-CN'
|
||||
speechUtterance.volume = volume || 1
|
||||
speechUtterance.pitch = pitch || 1
|
||||
speechUtterance.onend = function () {
|
||||
endEvent && endEvent()
|
||||
}
|
||||
speechUtterance.onstart = function () {
|
||||
startEvent && startEvent()
|
||||
}
|
||||
speechSynthesis.speak(speechUtterance)
|
||||
}
|
||||
Reference in New Issue
Block a user