├── 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 | Option |
40 | Sub |
41 | Description |
42 | Type |
43 | Required |
44 | Default |
45 |
46 |
47 | bgcPath |
48 | -- |
49 | 背景图片地址 |
50 | String |
51 | true |
52 | '' |
53 |
54 |
55 | title |
56 | name |
57 | 标题 |
58 | String |
59 | false |
60 | '可视化平台' |
61 |
62 |
63 | top |
64 | 高度 |
65 | Number |
66 | false |
67 | 0 |
68 |
69 |
70 | size |
71 | 文字大小 |
72 | Number |
73 | false |
74 | 16 |
75 |
76 |
77 | color |
78 | 文字颜色 |
79 | String |
80 | false |
81 | '#fff' |
82 |
83 |
84 | timeShow |
85 | 显示时间戳 |
86 | Boolean |
87 | false |
88 | true |
89 |
90 |
91 | sectionArr |
92 | -- |
93 | 单元配置 |
94 | Array |
95 | true |
96 | [] |
97 |
98 |
99 |
100 | ### sectionArr 单元配置
101 |
102 |
103 |
104 | Option |
105 | Sub |
106 | Description |
107 | Type |
108 | Required |
109 | Default |
110 |
111 |
112 | id |
113 | -- |
114 | slot唯一标识 |
115 | String |
116 | true |
117 | 0 |
118 |
119 |
120 | width |
121 | -- |
122 | 宽度 |
123 | Number |
124 | false |
125 | 500 |
126 |
127 |
128 | height |
129 | -- |
130 | 高度 |
131 | Number |
132 | false |
133 | 300 |
134 |
135 |
136 | position |
137 | x / y |
138 | 绝对定位 |
139 | Number |
140 | false |
141 | { x:0,y:0 } |
142 |
143 |
144 | title |
145 | name |
146 | 标题 |
147 | String |
148 | false |
149 | ' ' |
150 |
151 |
152 | size |
153 | 文字大小 |
154 | Number |
155 | false |
156 | 16 |
157 |
158 |
159 | color |
160 | 文字颜色 |
161 | String |
162 | false |
163 | '#fff' |
164 |
165 |
166 | position |
167 | 标题位置 |
168 | Object |
169 | false |
170 | {x:20,y:20} |
171 |
172 |
173 | isShow |
174 | 显示/隐藏 |
175 | Boolean |
176 | false |
177 | true |
178 |
179 |
180 | borderOptions |
181 | type |
182 | 边框类型 |
183 | Number |
184 | true |
185 | 0 (无边框,默认不引入DataV),index和DataV对应 |
186 |
187 |
188 | colorArr |
189 | 边框颜色 |
190 | Array |
191 | false |
192 | ['red', 'green'] |
193 |
194 |
195 | bgColor |
196 | 背景颜色 |
197 | String |
198 | false |
199 | 'blue' |
200 |
201 |
202 | reverse |
203 | 反向 |
204 | Boolean |
205 | false |
206 | true |
207 |
208 |
209 | dur |
210 | 动画时长 |
211 | Number |
212 | false |
213 | 3 |
214 |
215 |
216 | title |
217 | 边框标题 |
218 | String |
219 | false |
220 | ' ' |
221 |
222 |
223 | titleWidth |
224 | 边框宽度 |
225 | Number |
226 | false |
227 | 250 |
228 |
229 |
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 | 
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 |
2 |
3 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
45 |
81 |
--------------------------------------------------------------------------------
/src/component/VisualTemplate.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
{{title.name}}
6 | {{currentTime}}
7 |
8 |
9 | -
11 |
{{item.title.name}}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | -
27 |
{{item.title.name}}
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
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 |
99 |
100 |
101 |
102 | 边框设置
103 |
104 |
105 |
106 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
128 |
129 |
130 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
163 |
164 |
165 |
166 |
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 |
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 | }
--------------------------------------------------------------------------------