Showing
21 changed files
with
610 additions
and
0 deletions
.gitignore
0 → 100644
README.md
0 → 100644
| 1 | +# vue-dashboard | ||
| 2 | + | ||
| 3 | +## Project setup | ||
| 4 | +``` | ||
| 5 | +npm install | ||
| 6 | +``` | ||
| 7 | + | ||
| 8 | +### Compiles and hot-reloads for development | ||
| 9 | +``` | ||
| 10 | +npm run serve | ||
| 11 | +``` | ||
| 12 | + | ||
| 13 | +### Compiles and minifies for production | ||
| 14 | +``` | ||
| 15 | +npm run build | ||
| 16 | +``` | ||
| 17 | + | ||
| 18 | +### Run your tests | ||
| 19 | +``` | ||
| 20 | +npm run test | ||
| 21 | +``` | ||
| 22 | + | ||
| 23 | +### Lints and fixes files | ||
| 24 | +``` | ||
| 25 | +npm run lint | ||
| 26 | +``` | ||
| 27 | + | ||
| 28 | +### Customize configuration | ||
| 29 | +See [Configuration Reference](https://cli.vuejs.org/config/). |
babel.config.js
0 → 100644
package-lock.json
0 → 100644
This diff could not be displayed because it is too large.
package.json
0 → 100644
| 1 | +{ | ||
| 2 | + "name": "vue-dashboard", | ||
| 3 | + "version": "0.1.0", | ||
| 4 | + "private": true, | ||
| 5 | + "scripts": { | ||
| 6 | + "serve": "vue-cli-service serve", | ||
| 7 | + "build": "vue-cli-service build", | ||
| 8 | + "lint": "vue-cli-service lint" | ||
| 9 | + }, | ||
| 10 | + "dependencies": { | ||
| 11 | + "ant-design-vue": "^1.3.8", | ||
| 12 | + "axios": "^0.18.0", | ||
| 13 | + "core-js": "^2.6.5", | ||
| 14 | + "less": "^3.9.0", | ||
| 15 | + "less-loader": "^4.1.0", | ||
| 16 | + "lodash": "^4.17.11", | ||
| 17 | + "vue": "^2.6.6", | ||
| 18 | + "vue-grid-layout": "^2.3.4" | ||
| 19 | + }, | ||
| 20 | + "devDependencies": { | ||
| 21 | + "@vue/cli-plugin-babel": "^3.5.0", | ||
| 22 | + "@vue/cli-plugin-eslint": "^3.5.0", | ||
| 23 | + "@vue/cli-service": "^3.5.0", | ||
| 24 | + "babel-eslint": "^10.0.1", | ||
| 25 | + "babel-plugin-import": "^1.11.0", | ||
| 26 | + "eslint": "^5.8.0", | ||
| 27 | + "eslint-plugin-vue": "^5.0.0", | ||
| 28 | + "vue-template-compiler": "^2.5.21" | ||
| 29 | + }, | ||
| 30 | + "eslintConfig": { | ||
| 31 | + "root": true, | ||
| 32 | + "env": { | ||
| 33 | + "node": true | ||
| 34 | + }, | ||
| 35 | + "extends": [ | ||
| 36 | + "plugin:vue/essential", | ||
| 37 | + "eslint:recommended" | ||
| 38 | + ], | ||
| 39 | + "rules": {}, | ||
| 40 | + "parserOptions": { | ||
| 41 | + "parser": "babel-eslint" | ||
| 42 | + } | ||
| 43 | + }, | ||
| 44 | + "postcss": { | ||
| 45 | + "plugins": { | ||
| 46 | + "autoprefixer": {} | ||
| 47 | + } | ||
| 48 | + }, | ||
| 49 | + "browserslist": [ | ||
| 50 | + "> 1%", | ||
| 51 | + "last 2 versions", | ||
| 52 | + "not ie <= 8" | ||
| 53 | + ] | ||
| 54 | +} |
public/favicon.ico
0 → 100644
No preview for this file type
public/index.html
0 → 100644
| 1 | +<!DOCTYPE html> | ||
| 2 | +<html lang="en"> | ||
| 3 | + <head> | ||
| 4 | + <meta charset="utf-8"> | ||
| 5 | + <meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||
| 6 | + <meta name="viewport" content="width=device-width,initial-scale=1.0"> | ||
| 7 | + <link rel="icon" href="<%= BASE_URL %>favicon.ico"> | ||
| 8 | + <title>vue-dashboard</title> | ||
| 9 | + </head> | ||
| 10 | + <body> | ||
| 11 | + <noscript> | ||
| 12 | + <strong>We're sorry but vue-dashboard doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> | ||
| 13 | + </noscript> | ||
| 14 | + <div id="app"></div> | ||
| 15 | + <!-- built files will be auto injected --> | ||
| 16 | + </body> | ||
| 17 | +</html> |
src/App.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div id="app"> | ||
| 3 | + <setting | ||
| 4 | + :layout="layout" | ||
| 5 | + :isDraggable="isDraggable" | ||
| 6 | + :isResizable="isResizable" | ||
| 7 | + @isLock="isLock" | ||
| 8 | + /> | ||
| 9 | + <layout :layout="layout" :isDraggable="isDraggable" :isResizable="isResizable"/> | ||
| 10 | + </div> | ||
| 11 | +</template> | ||
| 12 | + | ||
| 13 | +<script> | ||
| 14 | +import setting from "./components/setting"; | ||
| 15 | +import layout from "./components/layout"; | ||
| 16 | + | ||
| 17 | +export default { | ||
| 18 | + name: "app", | ||
| 19 | + components: { | ||
| 20 | + setting, | ||
| 21 | + layout | ||
| 22 | + }, | ||
| 23 | + mounted() { | ||
| 24 | + this.$inventory | ||
| 25 | + .list({ | ||
| 26 | + fragmentType: "dashboard!name!home" | ||
| 27 | + }) | ||
| 28 | + .then(list => { | ||
| 29 | + if (list.managedObjects.length === 0) { | ||
| 30 | + return this.$inventory | ||
| 31 | + .create({ | ||
| 32 | + "dashboard!name!home": {} | ||
| 33 | + }) | ||
| 34 | + .then(detail => { | ||
| 35 | + this.id = detail.id; | ||
| 36 | + }); | ||
| 37 | + } else { | ||
| 38 | + this.id = list.managedObjects[0].id; | ||
| 39 | + } | ||
| 40 | + }); | ||
| 41 | + }, | ||
| 42 | + data() { | ||
| 43 | + return { | ||
| 44 | + layout: [], | ||
| 45 | + isDraggable: true, | ||
| 46 | + isResizable: true, | ||
| 47 | + id: null | ||
| 48 | + }; | ||
| 49 | + }, | ||
| 50 | + methods: { | ||
| 51 | + isLock: function(val) { | ||
| 52 | + this.isDraggable = val.isDraggable; | ||
| 53 | + this.isResizable = val.isResizable; | ||
| 54 | + this.$message.success( | ||
| 55 | + val.isResizable && val.isDraggable ? "编辑已解锁" : "编辑已锁定" | ||
| 56 | + ); | ||
| 57 | + } | ||
| 58 | + } | ||
| 59 | +}; | ||
| 60 | +</script> | ||
| 61 | + | ||
| 62 | +<style> | ||
| 63 | +html, | ||
| 64 | +body { | ||
| 65 | + margin: 0; | ||
| 66 | + padding: 0; | ||
| 67 | +} | ||
| 68 | +#app { | ||
| 69 | + font-family: "Avenir", Helvetica, Arial, sans-serif; | ||
| 70 | +} | ||
| 71 | +</style> |
src/api/index.js
0 → 100644
| 1 | +import axios from "axios"; | ||
| 2 | + | ||
| 3 | +axios.interceptors.request.use( | ||
| 4 | + config => { | ||
| 5 | + config.data = JSON.stringify(config.data); | ||
| 6 | + config.headers["Authorization"] = | ||
| 7 | + "Basic c3VueXVtaW5nL3N1bnl1bWluZzpoZWxsb0AxMjM="; | ||
| 8 | + return config; | ||
| 9 | + }, | ||
| 10 | + error => { | ||
| 11 | + return Promise.reject(error); | ||
| 12 | + } | ||
| 13 | +); | ||
| 14 | + | ||
| 15 | +export function get(url, params = {}) { | ||
| 16 | + return new Promise((resolve, reject) => { | ||
| 17 | + axios | ||
| 18 | + .get(url, { | ||
| 19 | + params: params | ||
| 20 | + }) | ||
| 21 | + .then(response => { | ||
| 22 | + resolve(response.data); | ||
| 23 | + }) | ||
| 24 | + .catch(err => { | ||
| 25 | + reject(err); | ||
| 26 | + }); | ||
| 27 | + }); | ||
| 28 | +} | ||
| 29 | + | ||
| 30 | +export function post(url, data = {}, config = {}) { | ||
| 31 | + return new Promise((resolve, reject) => { | ||
| 32 | + axios.post(url, data, config).then( | ||
| 33 | + response => { | ||
| 34 | + resolve(response.data); | ||
| 35 | + }, | ||
| 36 | + err => { | ||
| 37 | + reject(err); | ||
| 38 | + } | ||
| 39 | + ); | ||
| 40 | + }); | ||
| 41 | +} | ||
| 42 | + | ||
| 43 | +export function put(url, data = {}, config = {}) { | ||
| 44 | + return new Promise((resolve, reject) => { | ||
| 45 | + axios.put(url, data, config).then( | ||
| 46 | + response => { | ||
| 47 | + resolve(response.data); | ||
| 48 | + }, | ||
| 49 | + err => { | ||
| 50 | + reject(err); | ||
| 51 | + } | ||
| 52 | + ); | ||
| 53 | + }); | ||
| 54 | +} |
src/api/inventory.js
0 → 100644
| 1 | +import { get, post, put } from "./index"; | ||
| 2 | + | ||
| 3 | +let path = "/inventory/managedObjects"; | ||
| 4 | +let NAMESPACE = "application/vnd.com.nsn.cumulocity."; | ||
| 5 | +let config = { | ||
| 6 | + headers: { | ||
| 7 | + "Content-Type": `${NAMESPACE}managedObject+json`, | ||
| 8 | + Accept: `${NAMESPACE}managedObject+json` | ||
| 9 | + } | ||
| 10 | +}; | ||
| 11 | + | ||
| 12 | +function buildDetailUrl(mo) { | ||
| 13 | + let id = mo && (mo.id || mo); | ||
| 14 | + return id && `${path}/${id}`; | ||
| 15 | +} | ||
| 16 | + | ||
| 17 | +function list(filters = {}) { | ||
| 18 | + let url = path; | ||
| 19 | + let params = filters; | ||
| 20 | + return get(url, params); | ||
| 21 | +} | ||
| 22 | + | ||
| 23 | +function create(mo) { | ||
| 24 | + let url = path; | ||
| 25 | + return post(url, mo, config); | ||
| 26 | +} | ||
| 27 | + | ||
| 28 | +function update(mo) { | ||
| 29 | + let url = buildDetailUrl(mo); | ||
| 30 | + return put(url, mo, config); | ||
| 31 | +} | ||
| 32 | + | ||
| 33 | +let inventory = { | ||
| 34 | + list, | ||
| 35 | + create, | ||
| 36 | + update | ||
| 37 | +}; | ||
| 38 | + | ||
| 39 | +export { inventory }; |
src/assets/logo.png
0 → 100644
6.69 KB
src/components/gridComponent.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="gridComponent"> | ||
| 3 | + <div class="setting"> | ||
| 4 | + <a-button | ||
| 5 | + size="small" | ||
| 6 | + shape="circle" | ||
| 7 | + icon="close" | ||
| 8 | + @click="close" | ||
| 9 | + v-show="isDraggable&&isResizable" | ||
| 10 | + ></a-button> | ||
| 11 | + <a-button | ||
| 12 | + size="small" | ||
| 13 | + shape="circle" | ||
| 14 | + icon="setting" | ||
| 15 | + v-show="isDraggable&&isResizable" | ||
| 16 | + ></a-button> | ||
| 17 | + </div> | ||
| 18 | + <component :is="layout.name" :isConfig="isConfig"></component> | ||
| 19 | + </div> | ||
| 20 | +</template> | ||
| 21 | + | ||
| 22 | +<style lang="less" scoped> | ||
| 23 | +.gridComponent { | ||
| 24 | + height: 100%; | ||
| 25 | +} | ||
| 26 | +.setting { | ||
| 27 | + position: absolute; | ||
| 28 | + bottom: 0; | ||
| 29 | +} | ||
| 30 | +</style> | ||
| 31 | + | ||
| 32 | +<script> | ||
| 33 | +export default { | ||
| 34 | + props: { | ||
| 35 | + layout: Object, | ||
| 36 | + index: Number, | ||
| 37 | + isDraggable: Boolean, | ||
| 38 | + isResizable: Boolean | ||
| 39 | + }, | ||
| 40 | + data() { | ||
| 41 | + return { | ||
| 42 | + isConfig: false | ||
| 43 | + }; | ||
| 44 | + }, | ||
| 45 | + methods: { | ||
| 46 | + close: function() { | ||
| 47 | + this.$emit("close", this.index); | ||
| 48 | + } | ||
| 49 | + } | ||
| 50 | +}; | ||
| 51 | +</script> |
src/components/layout.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <grid-layout | ||
| 3 | + :layout.sync="layout" | ||
| 4 | + :col-num="100" | ||
| 5 | + :row-height="30" | ||
| 6 | + :is-draggable="isDraggable" | ||
| 7 | + :is-resizable="isResizable" | ||
| 8 | + :is-mirrored="false" | ||
| 9 | + :vertical-compact="true" | ||
| 10 | + :margin="[0, 0]" | ||
| 11 | + :use-css-transforms="true" | ||
| 12 | + > | ||
| 13 | + <grid-item | ||
| 14 | + v-for="(item,index) in layout" | ||
| 15 | + :x="item.x" | ||
| 16 | + :y="item.y" | ||
| 17 | + :w="item.w" | ||
| 18 | + :h="item.h" | ||
| 19 | + :i="item.i" | ||
| 20 | + :minW="item.minW" | ||
| 21 | + :maxW="item.maxW" | ||
| 22 | + :minH="item.minH" | ||
| 23 | + :maxH="item.maxH" | ||
| 24 | + :key="item.i" | ||
| 25 | + > | ||
| 26 | + <gridComponent :isDraggable="isDraggable" :isResizable="isResizable" :layout="item" :index="index" @close="close"/> | ||
| 27 | + </grid-item> | ||
| 28 | + </grid-layout> | ||
| 29 | +</template> | ||
| 30 | + | ||
| 31 | +<script> | ||
| 32 | +import VueGridLayout from "vue-grid-layout"; | ||
| 33 | +import gridComponent from "./gridComponent"; | ||
| 34 | +export default { | ||
| 35 | + props: { | ||
| 36 | + layout: Array, | ||
| 37 | + isDraggable: Boolean, | ||
| 38 | + isResizable: Boolean | ||
| 39 | + }, | ||
| 40 | + components: { | ||
| 41 | + GridLayout: VueGridLayout.GridLayout, | ||
| 42 | + GridItem: VueGridLayout.GridItem, | ||
| 43 | + gridComponent | ||
| 44 | + }, | ||
| 45 | + methods:{ | ||
| 46 | + close:function(val){ | ||
| 47 | + this.layout.splice(val,1) | ||
| 48 | + } | ||
| 49 | + } | ||
| 50 | +}; | ||
| 51 | +</script> |
src/components/setting.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="setting"> | ||
| 3 | + <a-button | ||
| 4 | + size="small" | ||
| 5 | + shape="circle" | ||
| 6 | + icon="plus" | ||
| 7 | + @click="() => visible = true" | ||
| 8 | + v-show="isDraggable&&isResizable" | ||
| 9 | + ></a-button> | ||
| 10 | + <a-button size="small" shape="circle" icon="lock" @click="isLock"></a-button> | ||
| 11 | + <a-modal | ||
| 12 | + title="添加小部件" | ||
| 13 | + centered | ||
| 14 | + v-model="visible" | ||
| 15 | + @ok="add" | ||
| 16 | + :destroyOnClose="true" | ||
| 17 | + :maskClosable="false" | ||
| 18 | + :okButtonProps="{ props: {disabled: selectItem===null?true:false} }" | ||
| 19 | + > | ||
| 20 | + <a-select | ||
| 21 | + showSearch | ||
| 22 | + placeholder="搜索小部件" | ||
| 23 | + optionFilterProp="children" | ||
| 24 | + style="width: 100%" | ||
| 25 | + :filterOption="filterOption" | ||
| 26 | + @change="handleChange" | ||
| 27 | + > | ||
| 28 | + <a-select-option v-for="item in list" :key="item" :value="item">{{item}}</a-select-option> | ||
| 29 | + </a-select> | ||
| 30 | + <component :is="configSelect"></component> | ||
| 31 | + </a-modal> | ||
| 32 | + </div> | ||
| 33 | +</template> | ||
| 34 | + | ||
| 35 | +<style lang="less" scoped> | ||
| 36 | +.setting { | ||
| 37 | + position: fixed; | ||
| 38 | + top: 10px; | ||
| 39 | + right: 30px; | ||
| 40 | + z-index: 1; | ||
| 41 | +} | ||
| 42 | +</style> | ||
| 43 | + | ||
| 44 | + | ||
| 45 | +<script> | ||
| 46 | +export default { | ||
| 47 | + props: { | ||
| 48 | + layout: Array, | ||
| 49 | + isDraggable: Boolean, | ||
| 50 | + isResizable: Boolean | ||
| 51 | + }, | ||
| 52 | + data() { | ||
| 53 | + return { | ||
| 54 | + isDraggable1: this.isDraggable, | ||
| 55 | + isResizable1: this.isResizable, | ||
| 56 | + visible: false, | ||
| 57 | + list: window.componentList, | ||
| 58 | + selectItem: null, | ||
| 59 | + configSelect: null | ||
| 60 | + }; | ||
| 61 | + }, | ||
| 62 | + methods: { | ||
| 63 | + isLock: function() { | ||
| 64 | + this.$emit("isLock", { | ||
| 65 | + isDraggable: !this.isDraggable, | ||
| 66 | + isResizable: !this.isResizable | ||
| 67 | + }); | ||
| 68 | + }, | ||
| 69 | + filterOption(input, option) { | ||
| 70 | + return ( | ||
| 71 | + option.componentOptions.children[0].text | ||
| 72 | + .toLowerCase() | ||
| 73 | + .indexOf(input.toLowerCase()) >= 0 | ||
| 74 | + ); | ||
| 75 | + }, | ||
| 76 | + handleChange: function(value) { | ||
| 77 | + this.selectItem = value; | ||
| 78 | + if (window.componentAll.indexOf(value + "Config") > -1) { | ||
| 79 | + this.configSelect = value + "Config"; | ||
| 80 | + } else { | ||
| 81 | + this.configSelect = value; | ||
| 82 | + } | ||
| 83 | + }, | ||
| 84 | + add: function() { | ||
| 85 | + this.layout.push({ | ||
| 86 | + x: 0, | ||
| 87 | + y: 0, | ||
| 88 | + w: 10, | ||
| 89 | + h: 2, | ||
| 90 | + i: this.layout.length + 1, | ||
| 91 | + name: this.selectItem | ||
| 92 | + }); | ||
| 93 | + this.visible = false; | ||
| 94 | + } | ||
| 95 | + } | ||
| 96 | +}; | ||
| 97 | +</script> |
src/main.js
0 → 100644
| 1 | +import Vue from "vue"; | ||
| 2 | +import App from "./App.vue"; | ||
| 3 | +import { camelCase } from "lodash"; | ||
| 4 | +import { Modal, Button, Select, message } from "ant-design-vue"; | ||
| 5 | +import { inventory } from "./api/inventory"; | ||
| 6 | + | ||
| 7 | +Vue.config.productionTip = false; | ||
| 8 | +Vue.use(Modal); | ||
| 9 | +Vue.use(Button); | ||
| 10 | +Vue.use(Select); | ||
| 11 | + | ||
| 12 | +Vue.prototype.$message = message; | ||
| 13 | +Vue.prototype.$inventory = inventory; | ||
| 14 | + | ||
| 15 | +const requireComponent = require.context("./views", true, /.(vue|js)$/); | ||
| 16 | + | ||
| 17 | +const componentList = []; | ||
| 18 | +const componentAll = []; | ||
| 19 | + | ||
| 20 | +requireComponent.keys().forEach(fileName => { | ||
| 21 | + const componentConfig = requireComponent(fileName); | ||
| 22 | + const componentName = camelCase(fileName.split("/")[1]); | ||
| 23 | + if (componentList.indexOf(componentName) === -1) { | ||
| 24 | + componentList.push(componentName); | ||
| 25 | + } | ||
| 26 | + componentAll.push(componentConfig.default.name); | ||
| 27 | + Vue.component( | ||
| 28 | + componentConfig.default.name, | ||
| 29 | + componentConfig.default || componentConfig | ||
| 30 | + ); | ||
| 31 | +}); | ||
| 32 | +window.componentList = componentList; | ||
| 33 | +window.componentAll = componentAll; | ||
| 34 | + | ||
| 35 | +new Vue({ | ||
| 36 | + el: "#app", | ||
| 37 | + render: h => h(App) | ||
| 38 | +}); |
src/views/index0/config.vue
0 → 100644
src/views/index0/index.vue
0 → 100644
src/views/index1/config.vue
0 → 100644
src/views/index1/index.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="index1"></div> | ||
| 3 | +</template> | ||
| 4 | + | ||
| 5 | +<style lang="less" scoped> | ||
| 6 | +.index1 { | ||
| 7 | + height: 100%; | ||
| 8 | + background: green; | ||
| 9 | + color: #fff; | ||
| 10 | +} | ||
| 11 | +</style> | ||
| 12 | + | ||
| 13 | +<script> | ||
| 14 | +import config from "./config"; | ||
| 15 | +export default { | ||
| 16 | + name: "index1", | ||
| 17 | + components: { | ||
| 18 | + config | ||
| 19 | + } | ||
| 20 | +}; | ||
| 21 | +</script> |
src/views/index2/index.vue
0 → 100644
-
Please register or sign in to post a comment