├── README.md ├── index.js ├── package.json ├── src ├── component │ ├── SectionChart.vue │ └── VisualTemplate.vue ├── font │ ├── iconfont.eot │ ├── iconfont.svg │ ├── iconfont.ttf │ ├── iconfont.woff │ └── iconfont.woff2 └── lib │ ├── utils.js │ └── visual_config.js └── webpack.conf.js /README.md: -------------------------------------------------------------------------------- 1 | # visual-platform 2 | 3 | > 基于Vue的可视化大屏开发GUI框架 ------ CreatedBy ©漆黑小T 4 | 5 | 构建用于开发可视化大屏项目的自适应布局的GUI框架。 6 | 7 | ## 安装 8 | 9 | **开发环境** 10 | 11 | - Node.js: ^8.9.1 12 | - Vue: ^2.6.10 13 | - element-ui: ^2.11.1 14 | - DataV(默认不引入):"@jiaminghi/data-view": "^2.9.4" 15 | - sass-loader:^7.1.0 16 | 17 | **安装** 18 | 19 | ```bash 20 | $ npm install visual-platform 21 | ``` 22 | 23 | Notice:单元边框样式基于 [DataV](http://datav.jiaminghi.com/guide/borderBox.html "DataV") 二次封装,默认不引入(type=0),如果设置type=1、2...,则该值与DataV边框样式的Index值映射。 24 | > 25 | >DataV地址: [http://datav.jiaminghi.com/guide/borderBox.html](http://datav.jiaminghi.com/guide/borderBox.html "DataV") 26 | 27 | ---------- 28 | 29 | ## Demo 30 | 31 | todo 32 | 33 | ## 配置 34 | 35 | ### Config属性 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 |
OptionSubDescriptionTypeRequiredDefault
bgcPath--背景图片地址Stringtrue''
titlename标题Stringfalse'可视化平台'
top高度Numberfalse0
size文字大小Numberfalse16
color文字颜色Stringfalse'#fff'
timeShow显示时间戳Booleanfalsetrue
sectionArr--单元配置Arraytrue[]
99 | 100 | ### sectionArr 单元配置 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 |
OptionSubDescriptionTypeRequiredDefault
id--slot唯一标识Stringtrue0
width--宽度Numberfalse500
height--高度Numberfalse300
positionx / y绝对定位Numberfalse{ x:0,y:0 }
titlename标题Stringfalse' '
size文字大小Numberfalse16
color文字颜色Stringfalse'#fff'
position标题位置Objectfalse{x:20,y:20}
isShow显示/隐藏Booleanfalsetrue
borderOptionstype边框类型Numbertrue0 (无边框,默认不引入DataV),index和DataV对应
colorArr边框颜色Arrayfalse['red', 'green']
bgColor背景颜色Stringfalse'blue'
reverse反向Booleanfalsetrue
dur动画时长Numberfalse3
title边框标题Stringfalse' '
titleWidth边框宽度Numberfalse250
230 | 231 | 控制台操作的回调函数: 232 | 233 | 保存配置:@saveConfig 参数为修改后的Config 234 | 235 | 清空配置:@clearConfig 236 | 237 | 默认配置: 238 | 239 | ```js 240 | visualConfig ={ 241 | bgcPath:'/img/bg_index.jpg',//背景图在线地址 http://ids.nuctech.com/static/img/bg_index.9af20a2.jpg 242 | title:{ 243 | name:'可视化平台', 244 | top:0,//主title高度 245 | size:16,//文字大小 246 | color:'#fff',//文字颜色 247 | timeShow:true//是否显示时间戳 248 | }, 249 | sectionArr:[ 250 | { 251 | id:'partOne', 252 | title:{name:'one',size:16,position:{x:20,y:20},color:'#fff',isShow:true},//单元名设置 253 | width:500, 254 | height:300, 255 | //边框,type=0,代表无边框(默认不引入DataV),type的index值和DataV对应 256 | borderOptions:{ 257 | type:0, 258 | colorArr:"[]", 259 | bgColor:'blue', 260 | reverse:false, 261 | dur:3, 262 | title:'', 263 | titleWidth:250 264 | }, 265 | //单元位置 266 | position:{ 267 | x:0, 268 | y:0 269 | }, 270 | }, 271 | ] 272 | }; 273 | ``` 274 | 275 | ## 基本使用 276 | 277 | * 组件中的书写: 278 | ```html 279 | 280 | 281 |
282 | {{item}} 283 |
--> 284 |
285 | 286 |
287 |
288 | 289 |
290 |
291 | 292 | 293 |
294 |
295 | ``` 296 | 297 | 298 | * 引入插件: 299 | ```js 300 | import VisualTemplate, { visualConfig,visualSetOptions} from 'visual-platform' 301 | ``` 302 | 303 | * 自定义配置: 304 | ```js 305 | let defConfig = { 306 | title:{ 307 | timeShow:false 308 | }, 309 | sectionArr:[ 310 | { 311 | id:'1',//对应的slot标识 312 | title:{name:'one',size:18,position:{x:20,y:20},color:'#fff',isShow:true}, 313 | width:500, 314 | height:300, 315 | position:{ 316 | x:0, 317 | y:0 318 | }, 319 | }, 320 | { 321 | borderOptions:{ 322 | type:0 323 | }, 324 | position:{ 325 | x:500, 326 | y:0 327 | }, 328 | }, 329 | { 330 | title:{name:'eight',size:18,position:{x:20,y:20},color:'#fff',isShow:true}, 331 | borderOptions:{ 332 | type:0,//DataV border-11 333 | title:'打豆豆', 334 | titleWidth:200, 335 | }, 336 | position:{ 337 | x:0, 338 | y:220 339 | }, 340 | }, 341 | ] 342 | } 343 | ``` 344 | 345 | * 调用 `visualSetOptions`方法,设置自定义参数 346 | 347 | ```js 348 | this.mainConfig = visualSetOptions(this.defConfig); 349 | ``` 350 | 351 | **注:** 352 | - 初始化设置参数时在Created生命周期内 353 | - visualConfig 可以导出完整的默认配置 354 | - 按`H`键隐藏/显示操作台(默认隐藏) 355 | - 按`E`键编辑模式切换 356 | 357 | ## 效果图 358 | 359 | ![](https://img2020.cnblogs.com/blog/1079640/202008/1079640-20200810164306795-1780057224.png) 360 | 361 | > E-mail: lixingtan163@163.com -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import VisualTemplate from './src/component/VisualTemplate.vue' 2 | import {visualConfig,visualSetOptions} from './src/lib/visual_config' 3 | export { 4 | visualConfig, 5 | visualSetOptions 6 | } 7 | export default VisualTemplate -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "visual-platform", 3 | "version": "1.1.4", 4 | "description": "基于Vue的可视化大屏GUI开发框架", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "npm-test" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/BugsMaster/visual-platform.git" 12 | }, 13 | "keywords": [ 14 | "visual", 15 | "vue", 16 | "GUI" 17 | ], 18 | "author": "漆黑小T", 19 | "license": "ISC" 20 | } 21 | -------------------------------------------------------------------------------- /src/component/SectionChart.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 45 | 81 | -------------------------------------------------------------------------------- /src/component/VisualTemplate.vue: -------------------------------------------------------------------------------- 1 | 167 | 168 | 430 | 461 | 729 | -------------------------------------------------------------------------------- /src/font/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BugsMaster/visual-platform/1816eec03f4bbb982132d3bdde8f9c68b479155c/src/font/iconfont.eot -------------------------------------------------------------------------------- /src/font/iconfont.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | Created by iconfont 9 | 10 | 11 | 12 | 13 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/font/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BugsMaster/visual-platform/1816eec03f4bbb982132d3bdde8f9c68b479155c/src/font/iconfont.ttf -------------------------------------------------------------------------------- /src/font/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BugsMaster/visual-platform/1816eec03f4bbb982132d3bdde8f9c68b479155c/src/font/iconfont.woff -------------------------------------------------------------------------------- /src/font/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BugsMaster/visual-platform/1816eec03f4bbb982132d3bdde8f9c68b479155c/src/font/iconfont.woff2 -------------------------------------------------------------------------------- /src/lib/utils.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 工具库 3 | **/ 4 | // localStorage 5 | const Storage = { 6 | storage: window.localStorage, 7 | 8 | set(item, value) { 9 | return this.storage.setItem(item, JSON.stringify(value)); 10 | }, 11 | get(item) { 12 | const itemStr = this.storage.getItem(item); 13 | if (itemStr) { 14 | return JSON.parse(itemStr); 15 | } else { 16 | return null; 17 | } 18 | }, 19 | remove(item) { 20 | return this.storage.removeItem(item); 21 | }, 22 | clear() { 23 | return this.storage.clear(); 24 | }, 25 | keys() { 26 | let arr = []; 27 | for (let i = 0; i < window.localStorage.length; i++) { 28 | arr.push(window.localStorage.key(i)); 29 | } 30 | return arr; 31 | } 32 | }; 33 | 34 | // 正则 35 | const Exp = { 36 | password:/^(?![0-9]+$)(?![a-z]+$)(?![A-Z]+$)(?!([^(0-9a-zA-Z)])+$).{6,20}$/, 37 | //工信部发文2017年第10批 38 | mobile: /^134[0-8]\d{7}$|^13[^4]\d{8}$|^14[5-9]\d{8}$|^15[^4]\d{8}$|^16[6]\d{8}$|^17[0-8]\d{8}$|^18[\d]{9}$|^19[8,9]\d{8}$/, 39 | email:/^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/, 40 | //身份证 41 | idCard: /^\d{6}(18|19|20)?\d{2}(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])\d{3}(\d|[xX])$/ 42 | }; 43 | 44 | // 函数节流 45 | const Throttle = function(func, wait) { 46 | var context, args, timeout, result; 47 | var previous = 0; 48 | var later = function() { 49 | previous = new Date(); 50 | timeout = null; 51 | result = func.apply(context, args); 52 | }; 53 | return function() { 54 | var now = new Date(); 55 | var remaining = wait - (now - previous); 56 | context = this; 57 | args = arguments; 58 | if (remaining <= 0) { 59 | clearTimeout(timeout); 60 | timeout = null; 61 | previous = now; 62 | result = func.apply(context, args); 63 | } else if (!timeout) { 64 | timeout = setTimeout(later, remaining); 65 | } 66 | return result; 67 | }; 68 | }; 69 | 70 | // 函数防抖 71 | const Debounce = function(func, wait, immediate) { 72 | var timeout, result; 73 | return function() { 74 | var context = this, 75 | args = arguments; 76 | var later = function() { 77 | timeout = null; 78 | if (!immediate) result = func.apply(context, args); 79 | }; 80 | var callNow = immediate && !timeout; 81 | clearTimeout(timeout); 82 | timeout = setTimeout(later, wait); 83 | if (callNow) result = func.apply(context, args); 84 | return result; 85 | }; 86 | }; 87 | 88 | //数组随机重新排布,underscore升级到 Fisher–Yates算法 89 | const Shuffle = function(arr) { 90 | let m = arr.length; 91 | while (m > 1){ 92 | let index = Math.floor(Math.random() * m--); 93 | [arr[m] , arr[index]] = [arr[index] , arr[m]] 94 | } 95 | return arr; 96 | } 97 | 98 | 99 | const deepClone = function(obj) { 100 | let objClone = Array.isArray(obj) ? [] : {}; 101 | if (obj && typeof obj === "object") { 102 | for (let key in obj) { 103 | if (obj.hasOwnProperty(key)) { 104 | //判断ojb子元素是否为对象,如果是,递归复制 105 | if (obj[key] && typeof obj[key] === "object") { 106 | objClone[key] = deepClone(obj[key]); 107 | } else { 108 | //如果不是,简单复制 109 | objClone[key] = obj[key]; 110 | } 111 | } 112 | } 113 | } 114 | return objClone; 115 | }; 116 | 117 | const DuplicateArr=function(arr,type){ 118 | var newArr = []; 119 | var tArr = []; 120 | if(arr.length == 0){ 121 | return arr; 122 | }else{ 123 | if(type){ 124 | for(var i = 0; i < arr.length;i++){ 125 | if(!tArr[arr[i][type]]){ 126 | newArr.push(arr[i]); 127 | tArr[arr[i][type]] = true; 128 | } 129 | } 130 | return newArr; 131 | }else{ 132 | for(var i = 0; i < arr.length;i++){ 133 | if(!tArr[arr[i]]){ 134 | newArr.push(arr[i]); 135 | tArr[arr[i]] = true; 136 | } 137 | } 138 | return newArr; 139 | } 140 | } 141 | } 142 | export { 143 | Storage, 144 | Exp, 145 | Throttle, 146 | Debounce, 147 | Shuffle, 148 | deepClone, 149 | DuplicateArr 150 | } 151 | -------------------------------------------------------------------------------- /src/lib/visual_config.js: -------------------------------------------------------------------------------- 1 | // 可视化配置项----- ©漆黑小T 2 | const visualConfig ={ 3 | bgcPath:'/img/bg_index.jpg', 4 | title:{ 5 | name:"可视化平台", 6 | top:0, 7 | size:16, 8 | color:'#fff', 9 | timeShow:true 10 | }, 11 | sectionArr:[ 12 | { 13 | title:{name:'one',size:18,position:{x:20,y:20},color:'#fff',isShow:true}, 14 | width:500, 15 | height:300, 16 | borderOptions:{ 17 | type:1, 18 | colorArr:"['red', 'green']", 19 | bgColor:'blue', 20 | reverse:false, 21 | dur:3, 22 | title:'', 23 | titleWidth:250 24 | }, 25 | position:{ 26 | x:0, 27 | y:0, 28 | zIndex:1 29 | }, 30 | } 31 | ] 32 | }; 33 | function isRepeat(arr) { 34 | var hash = {}; 35 | for (var i in arr) { 36 | if (hash[arr[i]]){ 37 | return true; 38 | } 39 | hash[arr[i]] = true; 40 | } 41 | return false; 42 | } 43 | const visualSetOptions = function(deconfig){ 44 | let tempDeconfig = deconfig.sectionArr.map(item=>{ 45 | if(!item.id) console.error('单元块ID缺失!'); 46 | return item.id||0; 47 | }); 48 | if(isRepeat(tempDeconfig)) return console.error('单元块ID必须唯一!'); 49 | let initconfig = visualConfig; 50 | for (const key in initconfig) { 51 | if (initconfig.hasOwnProperty(key)) { 52 | switch (key) { 53 | case 'bgcPath': 54 | if(!deconfig.hasOwnProperty('bgcPath')) { deconfig.bgcPath = initconfig.bgcPath; }; 55 | break; 56 | case 'title': 57 | if(deconfig.hasOwnProperty('title')){ 58 | if(!deconfig.title.hasOwnProperty('name')) { deconfig.title['name'] = initconfig.title['name']; }; 59 | if(!deconfig.title.hasOwnProperty('top')) { deconfig.title['top'] = initconfig.title['top']; }; 60 | if(!deconfig.title.hasOwnProperty('size')) { deconfig.title['size'] = initconfig.title['size']; }; 61 | if(!deconfig.title.hasOwnProperty('color')) { deconfig.title['color'] = initconfig.title['color']; }; 62 | if(!deconfig.title.hasOwnProperty('timeShow')) { deconfig.title['timeShow'] = initconfig.title['timeShow']; }; 63 | }else{ 64 | deconfig.title = { 65 | name:"可视化平台", 66 | size:16, 67 | color:'#fff', 68 | timeShow:true 69 | } 70 | } 71 | break; 72 | case 'sectionArr': 73 | if(deconfig.sectionArr.length){ 74 | deconfig.sectionArr.forEach((item,index)=>{ 75 | if(item.hasOwnProperty('title')){ 76 | if(!item.title.hasOwnProperty('name')) { item.title['name'] = '' }; 77 | if(!item.title.hasOwnProperty('size')) { item.title['size'] = 16 }; 78 | if(!item.title.hasOwnProperty('color')) { item.title['color'] = '#fff' }; 79 | if(!item.title.hasOwnProperty('isShow')) { item.title['isShow'] = true }; 80 | if(!item.title.hasOwnProperty('position')) { item.title['position'] = {x:20,y:20} }; 81 | }else{ 82 | item.title = { 83 | name:'',size:16,position:{x:20,y:20},color:'#fff',isShow:false 84 | } 85 | } 86 | if(!item.hasOwnProperty('width')){ item.width = 500 }; 87 | if(!item.hasOwnProperty('height')){ item.height = 300 }; 88 | if(!item.hasOwnProperty('position')){ 89 | item.position = {x:20*index,y:20*index,zIndex:1} 90 | }else{ 91 | item.position.zIndex = item.position.zIndex||1; 92 | } 93 | // borderOptions 94 | if(item.hasOwnProperty('borderOptions')){ 95 | if(!item.borderOptions.hasOwnProperty('type')) { item.borderOptions['type'] = 0}; 96 | if(!item.borderOptions.hasOwnProperty('colorArr')) { item.borderOptions['colorArr'] = ['steelblue'] }; 97 | if(!item.borderOptions.hasOwnProperty('bgColor')) { item.borderOptions['bgColor'] = 'rgba(25,25,40,.5)' }; 98 | if(!item.borderOptions.hasOwnProperty('reverse')) { item.borderOptions['reverse'] = false }; 99 | if(!item.borderOptions.hasOwnProperty('dur')) { item.borderOptions['dur'] = 3;}; 100 | if(!item.borderOptions.hasOwnProperty('title')) { item.borderOptions['title'] = '';}; 101 | if(!item.borderOptions.hasOwnProperty('titleWidth')) { item.borderOptions['titleWidth'] = 250;}; 102 | }else{ 103 | item.borderOptions = { 104 | type:0, 105 | colorArr:['steelblue'], 106 | bgColor:'rgba(25,25,40,.5)', 107 | reverse:false, 108 | dur:3, 109 | title:'', 110 | titleWidth:250 111 | } 112 | } 113 | }) 114 | } 115 | break; 116 | default: 117 | break; 118 | } 119 | } 120 | } 121 | return deconfig; 122 | } 123 | 124 | export { 125 | visualConfig, 126 | visualSetOptions 127 | } -------------------------------------------------------------------------------- /webpack.conf.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const webpack = require("webpack"); 3 | const uglify = require("uglifyjs-webpack-plugin"); 4 | 5 | module.exports = { 6 | devtool: 'source-map', 7 | entry: "./src/index.js",//入口文件,src目录下的index.js文件, 8 | output: { 9 | path: path.resolve(__dirname, './dist'),//输出路径,就是新建的dist目录, 10 | publicPath: '/dist/', 11 | filename: 'visual-platform.min.js', 12 | libraryTarget: 'umd', 13 | umdNamedDefine: true 14 | }, 15 | module: { 16 | rules: [{ 17 | test: /\.vue$/, 18 | loader: 'vue-loader' 19 | }, 20 | { 21 | test: /\.scss$/, 22 | use: [ 23 | { loader: "style-loader" }, 24 | { loader: "node-sass" }, 25 | { loader: "sass-loader" } 26 | ] 27 | }, 28 | { 29 | test: /\.js$/, 30 | exclude: /node_modules|vue\/dist|vue-router\/|vue-loader\/|vue-hot-reload-api\//, 31 | loader: 'babel-loader' 32 | }, 33 | { 34 | test: /\.(png|jpg|gif|ttf|svg|woff|eot)$/, 35 | loader: 'url-loader', 36 | query: { 37 | limit: 30000, 38 | name: '[name].[ext]?[hash]' 39 | } 40 | } 41 | ] 42 | }, 43 | plugins: [ 44 | new webpack.DefinePlugin({ 45 | "process.env": { 46 | NODE_ENV: JSON.stringify("production") 47 | } 48 | }) 49 | ] 50 | } --------------------------------------------------------------------------------