/tests/unit/coverage',
18 | // 'collectCoverage': true,
19 | 'coverageReporters': [
20 | 'lcov',
21 | 'text-summary'
22 | ],
23 | testURL: 'http://localhost/'
24 | }
25 |
--------------------------------------------------------------------------------
/src/layout/components/Sidebar/Link.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
44 |
--------------------------------------------------------------------------------
/src/styles/element-ui.scss:
--------------------------------------------------------------------------------
1 | // cover some element-ui styles
2 |
3 | .el-breadcrumb__inner,
4 | .el-breadcrumb__inner a {
5 | font-weight: 400 !important;
6 | }
7 |
8 | .el-upload {
9 | input[type="file"] {
10 | display: none !important;
11 | }
12 | }
13 |
14 | .el-upload__input {
15 | display: none;
16 | }
17 |
18 |
19 | // to fixed https://github.com/ElemeFE/element/issues/2461
20 | .el-dialog {
21 | transform: none;
22 | left: 0;
23 | position: relative;
24 | margin: 0 auto;
25 | }
26 |
27 | // refine element ui upload
28 | .upload-container {
29 | .el-upload {
30 | width: 100%;
31 |
32 | .el-upload-dragger {
33 | width: 100%;
34 | height: 200px;
35 | }
36 | }
37 | }
38 |
39 | // dropdown
40 | .el-dropdown-menu {
41 | a {
42 | display: block
43 | }
44 | }
45 |
46 | // to fix el-date-picker css style
47 | .el-range-separator {
48 | box-sizing: content-box;
49 | }
50 |
--------------------------------------------------------------------------------
/src/icons/svg/eye.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/styles/transition.scss:
--------------------------------------------------------------------------------
1 | // global transition css
2 |
3 | /* fade */
4 | .fade-enter-active,
5 | .fade-leave-active {
6 | transition: opacity 0.28s;
7 | }
8 |
9 | .fade-enter,
10 | .fade-leave-active {
11 | opacity: 0;
12 | }
13 |
14 | /* fade-transform */
15 | .fade-transform-leave-active,
16 | .fade-transform-enter-active {
17 | transition: all .5s;
18 | }
19 |
20 | .fade-transform-enter {
21 | opacity: 0;
22 | transform: translateX(-30px);
23 | }
24 |
25 | .fade-transform-leave-to {
26 | opacity: 0;
27 | transform: translateX(30px);
28 | }
29 |
30 | /* breadcrumb transition */
31 | .breadcrumb-enter-active,
32 | .breadcrumb-leave-active {
33 | transition: all .5s;
34 | }
35 |
36 | .breadcrumb-enter,
37 | .breadcrumb-leave-active {
38 | opacity: 0;
39 | transform: translateX(20px);
40 | }
41 |
42 | .breadcrumb-move {
43 | transition: all .5s;
44 | }
45 |
46 | .breadcrumb-leave-active {
47 | position: absolute;
48 | }
49 |
--------------------------------------------------------------------------------
/src/icons/svg/code.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/run.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | <%= webpackConfig.name %>
11 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/store/modules/dashboard.js:
--------------------------------------------------------------------------------
1 | import Cookies from 'js-cookie'
2 |
3 | const state = {
4 | _product_count:Cookies.get('_product_count') || 0, //产品总数
5 | _dev_count: Cookies.get('_dev_count') || 0, //设备总数
6 | _dev_online_count: Cookies.get('_dev_online_count') || 0, //在线
7 | _dev_off_count: Cookies.get('_dev_off_count') || 0, //离线
8 | }
9 |
10 | const mutations = {
11 | TOGGLE_DEVICE: (state, device) => {
12 | state.device = device
13 | },
14 | set_product_count: (state, _product_count) => {
15 | state._product_count = _product_count
16 | },
17 | set_dev_count: (state, _dev_count) => {
18 | state._dev_count = _dev_count
19 | },
20 | set_dev_online_count: (state, _dev_online_count) => {
21 | state._dev_online_count = _dev_online_count
22 | },
23 | set_dev_off_count: (state, _dev_off_count) => {
24 | state._dev_off_count = _dev_off_count
25 | },
26 | }
27 |
28 | const actions = {
29 | toggleDevice({ commit }, device) {
30 | commit('TOGGLE_DEVICE', device)
31 | },
32 | }
33 |
34 | export default {
35 | namespaced: true,
36 | state,
37 | mutations,
38 | actions
39 | }
40 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017-present PanJiaChen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/tests/unit/utils/formatTime.spec.js:
--------------------------------------------------------------------------------
1 | import { formatTime } from '@/utils/index.js'
2 |
3 | describe('Utils:formatTime', () => {
4 | const d = new Date('2018-07-13 17:54:01') // "2018-07-13 17:54:01"
5 | const retrofit = 5 * 1000
6 |
7 | it('ten digits timestamp', () => {
8 | expect(formatTime((d / 1000).toFixed(0))).toBe('7月13日17时54分')
9 | })
10 | it('test now', () => {
11 | expect(formatTime(+new Date() - 1)).toBe('刚刚')
12 | })
13 | it('less two minute', () => {
14 | expect(formatTime(+new Date() - 60 * 2 * 1000 + retrofit)).toBe('2分钟前')
15 | })
16 | it('less two hour', () => {
17 | expect(formatTime(+new Date() - 60 * 60 * 2 * 1000 + retrofit)).toBe('2小时前')
18 | })
19 | it('less one day', () => {
20 | expect(formatTime(+new Date() - 60 * 60 * 24 * 1 * 1000)).toBe('1天前')
21 | })
22 | it('more than one day', () => {
23 | expect(formatTime(d)).toBe('7月13日17时54分')
24 | })
25 | it('format', () => {
26 | expect(formatTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2018-07-13 17:54')
27 | expect(formatTime(d, '{y}-{m}-{d}')).toBe('2018-07-13')
28 | expect(formatTime(d, '{y}/{m}/{d} {h}-{i}')).toBe('2018/07/13 17-54')
29 | })
30 | })
31 |
--------------------------------------------------------------------------------
/src/api/Evidence/index.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 |
4 | export function queryEvidence(params) {
5 | return request({
6 | url: `/classes/Evidence`,
7 | method: 'get',
8 | params
9 | })
10 | }
11 | export function postBatch(data) {
12 | return request({
13 | url: `/batch`,
14 | method: 'post',
15 | data
16 | })
17 | }
18 | export async function postEvidence(id, params) {
19 | return request({
20 | url: `/evidence?id=${id}`,
21 | method: 'post',
22 | data: params,
23 | })
24 | }
25 | export async function generatereport(id) {
26 | return request({
27 | url: `/generatereport?id=${id}`,
28 | method: 'post',
29 | })
30 | }
31 | export async function delEvidence(ObjectId) {
32 | return request({
33 | url: `/classes/Evidence/${ObjectId}`,
34 | method: 'delete',
35 | })
36 | }
37 | export async function putEvidence(ObjectId, data) {
38 | return request({
39 | url: `/classes/Evidence/${ObjectId}`,
40 | method: 'put',
41 | data
42 | })
43 | }
44 | export async function postDrawxnqx(params) {
45 | return request({
46 | url: '/drawxnqx',
47 | method: 'post',
48 | data: params,
49 | })
50 | }
51 |
52 |
--------------------------------------------------------------------------------
/src/styles/index.scss:
--------------------------------------------------------------------------------
1 | @import './variables.scss';
2 | @import './mixin.scss';
3 | @import './transition.scss';
4 | @import './element-ui.scss';
5 | @import './sidebar.scss';
6 |
7 | body {
8 | height: 100%;
9 | -moz-osx-font-smoothing: grayscale;
10 | -webkit-font-smoothing: antialiased;
11 | text-rendering: optimizeLegibility;
12 | font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
13 | }
14 |
15 | label {
16 | font-weight: 700;
17 | }
18 |
19 | html {
20 | height: 100%;
21 | box-sizing: border-box;
22 | }
23 |
24 | #app {
25 | height: 100%;
26 | }
27 |
28 | *,
29 | *:before,
30 | *:after {
31 | box-sizing: inherit;
32 | }
33 |
34 | a:focus,
35 | a:active {
36 | outline: none;
37 | }
38 |
39 | a,
40 | a:focus,
41 | a:hover {
42 | cursor: pointer;
43 | // color: inherit;
44 | text-decoration: none;
45 | }
46 |
47 | div:focus {
48 | outline: none;
49 | }
50 |
51 | .clearfix {
52 | &:after {
53 | visibility: hidden;
54 | display: block;
55 | font-size: 0;
56 | content: " ";
57 | clear: both;
58 | height: 0;
59 | }
60 | }
61 |
62 | // main-container global css
63 | .app-container {
64 | padding: 20px;
65 | }
66 |
--------------------------------------------------------------------------------
/src/icons/svg/eye-open.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/throw.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/unit/utils/parseTime.spec.js:
--------------------------------------------------------------------------------
1 | import { parseTime } from '@/utils/index.js'
2 |
3 | describe('Utils:parseTime', () => {
4 | const d = new Date('2018-07-13 17:54:01') // "2018-07-13 17:54:01"
5 | it('timestamp', () => {
6 | expect(parseTime(d)).toBe('2018-07-13 17:54:01')
7 | })
8 | it('timestamp string', () => {
9 | expect(parseTime((d + ''))).toBe('2018-07-13 17:54:01')
10 | })
11 | it('ten digits timestamp', () => {
12 | expect(parseTime((d / 1000).toFixed(0))).toBe('2018-07-13 17:54:01')
13 | })
14 | it('new Date', () => {
15 | expect(parseTime(new Date(d))).toBe('2018-07-13 17:54:01')
16 | })
17 | it('format', () => {
18 | expect(parseTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2018-07-13 17:54')
19 | expect(parseTime(d, '{y}-{m}-{d}')).toBe('2018-07-13')
20 | expect(parseTime(d, '{y}/{m}/{d} {h}-{i}')).toBe('2018/07/13 17-54')
21 | })
22 | it('get the day of the week', () => {
23 | expect(parseTime(d, '{a}')).toBe('五') // 星期五
24 | })
25 | it('get the day of the week', () => {
26 | expect(parseTime(+d + 1000 * 60 * 60 * 24 * 2, '{a}')).toBe('日') // 星期日
27 | })
28 | it('empty argument', () => {
29 | expect(parseTime()).toBeNull()
30 | })
31 |
32 | it('null', () => {
33 | expect(parseTime(null)).toBeNull()
34 | })
35 | })
36 |
--------------------------------------------------------------------------------
/src/components/model3d/utils/load.js:
--------------------------------------------------------------------------------
1 | import { OBJLoader, MTLLoader } from "three-obj-mtl-loader";
2 | import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader';
3 | import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
4 |
5 |
6 | // 加载obj,mtl文件
7 | export function objloader(path) {
8 | return new Promise(resolve => {
9 | var mtlLoader = new MTLLoader();
10 | // 初始化obj
11 | var objLoader = new OBJLoader();
12 | // 加载mtl文件
13 | mtlLoader.load(`/static/${path}.mtl`, (mtl) => {
14 | // 初始化
15 | mtl.preload();
16 | // 加载贴图
17 | objLoader.setMaterials(mtl);
18 | objLoader.load(`/static/${path}.obj`, (obj) => {
19 | resolve({ mtl, obj })
20 | })
21 | })
22 | });
23 | }
24 |
25 | // 加载fbx文件
26 | export function fbxloader(path) {
27 | return new Promise(resolve => {
28 | var loader = new FBXLoader();
29 | loader.load(`${path}`, (fbx) => {
30 | resolve(fbx)
31 | })
32 | });
33 | }
34 | // 加载gtlf文件
35 | export function gltfloader(path) {
36 | return new Promise(resolve => {
37 | var loader = new GLTFLoader();
38 | loader.load(`${path}`, (gltf) => {
39 | resolve(gltf)
40 | })
41 | });
42 | }
43 |
--------------------------------------------------------------------------------
/src/views/dashboard/component/ScreenSgmap.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
55 |
--------------------------------------------------------------------------------
/src/components/Hamburger/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
32 |
33 |
45 |
--------------------------------------------------------------------------------
/src/icons/svg/phone.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/store/modules/app.js:
--------------------------------------------------------------------------------
1 | import Cookies from 'js-cookie'
2 |
3 | const state = {
4 | sidebar: {
5 | opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
6 | withoutAnimation: false
7 | },
8 | device: 'desktop'
9 | }
10 |
11 | const mutations = {
12 | TOGGLE_SIDEBAR: state => {
13 | state.sidebar.opened = !state.sidebar.opened
14 | state.sidebar.withoutAnimation = false
15 | if (state.sidebar.opened) {
16 | Cookies.set('sidebarStatus', 1)
17 | } else {
18 | Cookies.set('sidebarStatus', 0)
19 | }
20 | },
21 | CLOSE_SIDEBAR: (state, withoutAnimation) => {
22 | Cookies.set('sidebarStatus', 0)
23 | state.sidebar.opened = false
24 | state.sidebar.withoutAnimation = withoutAnimation
25 | },
26 | TOGGLE_DEVICE: (state, device) => {
27 | state.device = device
28 | }
29 | }
30 |
31 | const actions = {
32 | toggleSideBar({ commit }) {
33 | commit('TOGGLE_SIDEBAR')
34 | },
35 | closeSideBar({ commit }, { withoutAnimation }) {
36 | commit('CLOSE_SIDEBAR', withoutAnimation)
37 | },
38 | toggleDevice({ commit }, device) {
39 | commit('TOGGLE_DEVICE', device)
40 | },
41 | // updateRealCard(state, payload) {
42 | // state.realCard = payload
43 | // },
44 | }
45 |
46 | export default {
47 | namespaced: true,
48 | state,
49 | mutations,
50 | actions
51 | }
52 |
--------------------------------------------------------------------------------
/src/icons/svg/shooting.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/layout/mixin/ResizeHandler.js:
--------------------------------------------------------------------------------
1 | import store from '@/store'
2 |
3 | const { body } = document
4 | const WIDTH = 992 // refer to Bootstrap's responsive design
5 |
6 | export default {
7 | watch: {
8 | $route(route) {
9 | if (this.device === 'mobile' && this.sidebar.opened) {
10 | store.dispatch('app/closeSideBar', { withoutAnimation: false })
11 | }
12 | }
13 | },
14 | beforeMount() {
15 | window.addEventListener('resize', this.$_resizeHandler)
16 | },
17 | beforeDestroy() {
18 | window.removeEventListener('resize', this.$_resizeHandler)
19 | },
20 | mounted() {
21 | const isMobile = this.$_isMobile()
22 | if (isMobile) {
23 | store.dispatch('app/toggleDevice', 'mobile')
24 | store.dispatch('app/closeSideBar', { withoutAnimation: true })
25 | }
26 | },
27 | methods: {
28 | // use $_ for mixins properties
29 | // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
30 | $_isMobile() {
31 | const rect = body.getBoundingClientRect()
32 | return rect.width - 1 < WIDTH
33 | },
34 | $_resizeHandler() {
35 | if (!document.hidden) {
36 | const isMobile = this.$_isMobile()
37 | store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop')
38 |
39 | if (isMobile) {
40 | store.dispatch('app/closeSideBar', { withoutAnimation: true })
41 | }
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/views/CloudOc/AmisPage/style/themeBlack.css:
--------------------------------------------------------------------------------
1 | /* *{
2 | background-color: #000 !important;
3 | } */
4 | *{
5 | --themeColor:#0f266b;
6 | --componentColor:#1d386f;
7 | --headColor:#0c6ed3;
8 | --basicColor:#2850a7;
9 | --whiteColor:#fff;
10 | }
11 | .antd-Page-body{
12 | background-color: var(--themeColor) !important;
13 | }
14 | .antd-Form-label{
15 | color: var(--whiteColor) !important;
16 | }
17 | .antd-Panel-body{
18 | background-color: var(--componentColor) !important;
19 | }
20 | .antd-Panel-footer{
21 | background-color:var(--componentColor) !important;
22 | }
23 | /* 表格 */
24 | .antd-Table-table{
25 | background-color: var(--componentColor) !important;
26 | color: var(--whiteColor) !important;
27 | }
28 | .antd-Table-table > thead > tr > th{
29 | background-color: var(--headColor) !important;
30 | color: var(--whiteColor) !important;
31 | border: #000 1px solid !important;
32 | }
33 | /* 下拉框 */
34 | .antd-Select{
35 | background-color: var(--basicColor) !important;
36 | color: var(--whiteColor) !important;
37 | border: 0 !important;
38 | }
39 |
40 | /* .antd-Select-option{
41 | background-color: #1d386f !important;
42 | color: #fff !important;
43 | } */
44 | /* 输入框 */
45 | .antd-TextControl-input{
46 | background-color: var(--componentColor) !important;
47 | }
48 | .antd-TextControl-input input{
49 | color: var(--whiteColor) !important;
50 | }
51 | /* tree 树 */
52 | .antd-Tree-itemText{
53 | color: var(--whiteColor) !important;
54 | }
--------------------------------------------------------------------------------
/src/icons/svg/material.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/api/Dashboard/index.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 | import axios from 'axios'
3 | import { getToken } from '@/utils/auth'
4 |
5 |
6 | const server = 'http://dev.dgiotcloud.cn'
7 |
8 | export function getDlinkJson(data) {
9 | return request({
10 | url: `/dlinkjson`,
11 | method: 'get',
12 | params: {
13 | type: data
14 | }
15 | })
16 | }
17 | export async function Startdashboard(dashboardId, data) {
18 | // console.log('window', window.location.origin);
19 | let ip = window.location.origin
20 | if (ip.indexOf('localhost') >= 0) {
21 | ip = server
22 | }
23 | return axios({
24 | url: `${ip}/iotapi/dashboard`,
25 | method: 'post',
26 | data: data,
27 | params: {
28 | dashboardId: dashboardId
29 | },
30 | headers: {
31 | "sessionToken": getToken()
32 | }
33 | })
34 | }
35 | // export async function sendTopic(data) {
36 | // // console.log('window', window.location.origin);
37 | // let ip = window.location.origin
38 | // if (ip.indexOf('localhost') >= 0) {
39 | // ip = server
40 | // }
41 | // return axios({
42 | // url: `${ip}/iotapi/topic`,
43 | // method: 'post',
44 | // data: data,
45 | // headers: {
46 | // "sessionToken": getToken()
47 | // }
48 | // })
49 | // }
50 | export function sendTopic(data) {
51 | return request({
52 | url: `/topic`,
53 | method: 'post',
54 | data
55 | })
56 | }
57 | export function postCookie(data) {
58 | return request({
59 | url: `/cookie`,
60 | method: 'post',
61 | data
62 | })
63 | }
64 |
--------------------------------------------------------------------------------
/public/draco/README.md:
--------------------------------------------------------------------------------
1 | # Draco 3D Data Compression
2 |
3 | Draco is an open-source library for compressing and decompressing 3D geometric meshes and point clouds. It is intended to improve the storage and transmission of 3D graphics.
4 |
5 | [Website](https://google.github.io/draco/) | [GitHub](https://github.com/google/draco)
6 |
7 | ## Contents
8 |
9 | This folder contains three utilities:
10 |
11 | * `draco_decoder.js` — Emscripten-compiled decoder, compatible with any modern browser.
12 | * `draco_decoder.wasm` — WebAssembly decoder, compatible with newer browsers and devices.
13 | * `draco_wasm_wrapper.js` — JavaScript wrapper for the WASM decoder.
14 |
15 | Each file is provided in two variations:
16 |
17 | * **Default:** Latest stable builds, tracking the project's [master branch](https://github.com/google/draco).
18 | * **glTF:** Builds targeted by the [glTF mesh compression extension](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression), tracking the [corresponding Draco branch](https://github.com/google/draco/tree/gltf_2.0_draco_extension).
19 |
20 | Either variation may be used with `THREE.DRACOLoader`:
21 |
22 | ```js
23 | var dracoLoader = new THREE.DRACOLoader();
24 | dracoLoader.setDecoderPath('path/to/decoders/');
25 | dracoLoader.setDecoderConfig({type: 'js'}); // (Optional) Override detection of WASM support.
26 | ```
27 |
28 | Further [documentation on GitHub](https://github.com/google/draco/tree/master/javascript/example#static-loading-javascript-decoder).
29 |
30 | ## License
31 |
32 | [Apache License 2.0](https://github.com/google/draco/blob/master/LICENSE)
33 |
--------------------------------------------------------------------------------
/mock/index.js:
--------------------------------------------------------------------------------
1 | const Mock = require('mockjs')
2 | const { param2Obj } = require('./utils')
3 |
4 | const user = require('./user')
5 | const table = require('./table')
6 |
7 | const mocks = [
8 | ...user,
9 | ...table
10 | ]
11 |
12 | // for front mock
13 | // please use it cautiously, it will redefine XMLHttpRequest,
14 | // which will cause many of your third-party libraries to be invalidated(like progress event).
15 | function mockXHR() {
16 | // mock patch
17 | // https://github.com/nuysoft/Mock/issues/300
18 | Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
19 | Mock.XHR.prototype.send = function() {
20 | if (this.custom.xhr) {
21 | this.custom.xhr.withCredentials = this.withCredentials || false
22 |
23 | if (this.responseType) {
24 | this.custom.xhr.responseType = this.responseType
25 | }
26 | }
27 | this.proxy_send(...arguments)
28 | }
29 |
30 | function XHR2ExpressReqWrap(respond) {
31 | return function(options) {
32 | let result = null
33 | if (respond instanceof Function) {
34 | const { body, type, url } = options
35 | // https://expressjs.com/en/4x/api.html#req
36 | result = respond({
37 | method: type,
38 | body: JSON.parse(body),
39 | query: param2Obj(url)
40 | })
41 | } else {
42 | result = respond
43 | }
44 | return Mock.mock(result)
45 | }
46 | }
47 |
48 | for (const i of mocks) {
49 | Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response))
50 | }
51 | }
52 |
53 | module.exports = {
54 | mocks,
55 | mockXHR
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/src/components/model3d/draco/README.md:
--------------------------------------------------------------------------------
1 | # Draco 3D Data Compression
2 |
3 | Draco is an open-source library for compressing and decompressing 3D geometric meshes and point clouds. It is intended to improve the storage and transmission of 3D graphics.
4 |
5 | [Website](https://google.github.io/draco/) | [GitHub](https://github.com/google/draco)
6 |
7 | ## Contents
8 |
9 | This folder contains three utilities:
10 |
11 | * `draco_decoder.js` — Emscripten-compiled decoder, compatible with any modern browser.
12 | * `draco_decoder.wasm` — WebAssembly decoder, compatible with newer browsers and devices.
13 | * `draco_wasm_wrapper.js` — JavaScript wrapper for the WASM decoder.
14 |
15 | Each file is provided in two variations:
16 |
17 | * **Default:** Latest stable builds, tracking the project's [master branch](https://github.com/google/draco).
18 | * **glTF:** Builds targeted by the [glTF mesh compression extension](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression), tracking the [corresponding Draco branch](https://github.com/google/draco/tree/gltf_2.0_draco_extension).
19 |
20 | Either variation may be used with `THREE.DRACOLoader`:
21 |
22 | ```js
23 | var dracoLoader = new THREE.DRACOLoader();
24 | dracoLoader.setDecoderPath('path/to/decoders/');
25 | dracoLoader.setDecoderConfig({type: 'js'}); // (Optional) Override detection of WASM support.
26 | ```
27 |
28 | Further [documentation on GitHub](https://github.com/google/draco/tree/master/javascript/example#static-loading-javascript-decoder).
29 |
30 | ## License
31 |
32 | [Apache License 2.0](https://github.com/google/draco/blob/master/LICENSE)
33 |
--------------------------------------------------------------------------------
/src/api/User/index.js:
--------------------------------------------------------------------------------
1 | import request from '@/utils/request'
2 |
3 | // 获取验证码
4 | export function postCode(account) {
5 | return request({
6 | url: '/smscode?account=' + account,
7 | method: 'post'
8 | // data,
9 | // params
10 | // headers: {
11 | // "Content-Type": "text/plain"
12 | // }
13 | })
14 | }
15 | // 验证码登录
16 | export function verifyCode(phone, code, username, password) {
17 | return request({
18 | url: `/verify_code?account=${phone}&code=${code}&username=${username}&password=${password}`,
19 | method: 'post',
20 | data: {}
21 | // params
22 | // headers: {
23 | // "Content-Type": "text/plain"
24 | // }
25 | })
26 | }
27 |
28 | // 登录
29 | export function login(data) {
30 | return request({
31 | url: '/login',
32 | method: 'post',
33 | data,
34 | headers: {
35 | 'Content-Type': 'text/plain'
36 |
37 | }
38 | })
39 | }
40 | export function Roletree() {
41 | return request({
42 | url: '/roletree',
43 | method: 'get'
44 | })
45 | }
46 | export function getToken(params) {
47 | return request({
48 | url: '/token',
49 | method: 'get',
50 | params
51 | })
52 | }
53 |
54 | export function putUserInfo(objectId, data) {
55 | return request({
56 | url: `/amis/_User/${objectId}`,
57 | method: 'put',
58 | data
59 | })
60 | }
61 |
62 | export function getInfo(token) {
63 | return request({
64 | url: '/vue-admin-template/user/info',
65 | method: 'get',
66 | params: { token }
67 | })
68 | }
69 |
70 | export function logout() {
71 | return request({
72 | url: '/vue-admin-template/user/logout',
73 | method: 'post'
74 | })
75 | }
76 |
--------------------------------------------------------------------------------
/src/components/SvgIcon/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
51 |
52 |
67 |
--------------------------------------------------------------------------------
/src/layout/components/Sidebar/Item.vue:
--------------------------------------------------------------------------------
1 |
56 |
57 |
64 |
--------------------------------------------------------------------------------
/src/icons/svg/tree.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/views/tree/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
13 |
14 |
15 |
16 |
17 |
78 |
79 |
--------------------------------------------------------------------------------
/src/icons/svg/organode.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/mock/user.js:
--------------------------------------------------------------------------------
1 |
2 | const tokens = {
3 | admin: {
4 | token: 'admin-token'
5 | },
6 | editor: {
7 | token: 'editor-token'
8 | }
9 | }
10 |
11 | const users = {
12 | 'admin-token': {
13 | roles: ['admin'],
14 | introduction: 'I am a super administrator',
15 | avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
16 | name: 'Super Admin'
17 | },
18 | 'editor-token': {
19 | roles: ['editor'],
20 | introduction: 'I am an editor',
21 | avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
22 | name: 'Normal Editor'
23 | }
24 | }
25 |
26 | module.exports = [
27 | // user login
28 | {
29 | url: '/vue-admin-template/user/login',
30 | type: 'post',
31 | response: config => {
32 | const { username } = config.body
33 | const token = tokens[username]
34 |
35 | // mock error
36 | if (!token) {
37 | return {
38 | code: 60204,
39 | message: 'Account and password are incorrect.'
40 | }
41 | }
42 |
43 | return {
44 | code: 20000,
45 | data: token
46 | }
47 | }
48 | },
49 |
50 | // get user info
51 | {
52 | url: '/vue-admin-template/user/info\.*',
53 | type: 'get',
54 | response: config => {
55 | const { token } = config.query
56 | const info = users[token]
57 |
58 | // mock error
59 | if (!info) {
60 | return {
61 | code: 50008,
62 | message: 'Login failed, unable to get user details.'
63 | }
64 | }
65 |
66 | return {
67 | code: 20000,
68 | data: info
69 | }
70 | }
71 | },
72 |
73 | // user logout
74 | {
75 | url: '/vue-admin-template/user/logout',
76 | type: 'post',
77 | response: _ => {
78 | return {
79 | code: 20000,
80 | data: 'success'
81 | }
82 | }
83 | }
84 | ]
85 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Cookies from 'js-cookie'
3 | import { Base64 } from "js-base64";
4 | import md5 from "js-md5";
5 | import 'normalize.css/normalize.css' // A modern alternative to CSS resets
6 |
7 | import ElementUI from 'element-ui'
8 | import 'element-ui/lib/theme-chalk/index.css'
9 | // import locale from 'element-ui/lib/locale/lang/en' // lang i18n
10 |
11 | import '@/styles/index.scss' // global css
12 |
13 | import App from './App'
14 | import store from './store'
15 | import router from './router'
16 |
17 | import VCharts from 'v-charts'
18 |
19 | import '@/icons' // icon
20 | import '@/permission' // permission control
21 |
22 | import '@dgiot/dgiot-component'
23 |
24 | // import 'amis/lib/themes/cxd.css'
25 | // import 'amis/lib/themes/ang.css'
26 | // import 'amis/lib/themes/default.css'
27 | // import 'amis/lib/helper.css'
28 | // import 'amis/sdk/sdk.css'
29 | // import "amis/lib/themes/antd.css";
30 |
31 | // import 'amis-editor/dist/style.css'
32 | /**
33 | * If you don't want to use mock-server
34 | * you want to use MockJs for mock api
35 | * you can execute: mockXHR()
36 | *
37 | * Currently MockJs will be used in the production environment,
38 | * please remove it before going online ! ! !
39 | */
40 | // if (process.env.NODE_ENV === 'production') {
41 | // const { mockXHR } = require('../mock')
42 | // mockXHR()
43 | // }
44 | Vue.prototype.$md5 = md5
45 | Vue.prototype.$_ = require("lodash")
46 | Vue.prototype.$Cookies = Cookies
47 | Vue.prototype.$Base64 = Base64
48 | window.Base64 = Vue.prototype.$Base64
49 | Vue.prototype.$dgiotBus = new Vue();
50 | window.dgiotBus = Vue.prototype.$dgiotBus
51 | Vue.prototype.$FileServe = ''
52 | window.Vue = Vue
53 |
54 | // set ElementUI lang to EN
55 | // Vue.use(ElementUI, { locale })
56 | // 如果想要中文版 element-ui,按如下方式声明
57 | Vue.use(ElementUI)
58 | Vue.use(VCharts)
59 |
60 | Vue.config.productionTip = false
61 |
62 | new Vue({
63 | el: '#app',
64 | router,
65 | store,
66 | render: h => h(App)
67 | })
68 |
--------------------------------------------------------------------------------
/src/layout/components/Sidebar/Logo.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
33 |
34 |
83 |
--------------------------------------------------------------------------------
/src/components/Amis/index.vue:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
16 |
81 |
91 |
--------------------------------------------------------------------------------
/src/icons/svg/dashboard.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/layout/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
52 |
53 |
94 |
--------------------------------------------------------------------------------
/src/icons/svg/organization.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/fight.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/form.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # iotView 轻量级工业物联网平台
2 |
3 |
4 |
6 |
7 |
8 |
9 |
10 | ## DGIoT平台简介
11 | DGIoT是国内首款轻量级工业物联网开源平台,我们致力于为5类客户提供物联网解决方案:
12 | + **国企/研究院**:平台代码开源,无版权产权困扰,国产无“卡脖”之忧
13 | + **系统集成商**:通用设备海量接入、定制设备二次开发、30分钟一键式私有化快速部署,低成本(降90%成本)
14 | + **工业设备制造商**:海量设备上线运维,不受公有云限制,低成本,短周期自建平台,私有化部署,数据安全
15 | + **开源平台开发者**:一键式开发环境,集成和兼容各种最优开源工具,快速承接物联网项目
16 | + **垂直领域物联网平台**:快速部署私有化平台,千万级承载,运营级底座,全开放扩展
17 |
18 | ## 平台快速体验与技术交流微信群
19 | | 微信技术支持群 |官网 https://www.dgiotcloud.cn/| [QQ技术支持群](https://jq.qq.com/?_wv=1027&k=LipWZvDe): 346566935 |
20 | |:---:|:---:|:---:|
21 | |
|**平台体验网址**
https://prod.dgiotcloud.cn
|
|
22 |
23 | ## 特色功能
24 | + 低代码快速开发
25 |
26 |
27 | 
28 |
29 | dgiot 前端框架
30 |
31 |
32 |
33 | ## 相关源码地址项目源码
34 |
35 | | 源码平台 | 源码地址 |
36 | | -------- | --------------------------------------------------------------------------------------------- |
37 | | github | [https://github.com/dgiot/iotView](https://github.com/dgiot/iotView?from=git) |
38 |
39 |
40 | ## 安装使用
41 |
42 | - 获取项目代码
43 |
44 | ```bash
45 | git clone -b master https://github.com/dgiot/iotView.git
46 | ```
47 |
48 | - 安装依赖
49 |
50 | ```bash
51 |
52 | npm install
53 |
54 | ```
55 |
56 | - 运行
57 |
58 | ```bash
59 |
60 | npm run dev
61 |
62 | ```
63 |
64 | - 效果展示
65 |
66 |
67 |
68 |
69 | - 登录
70 |
71 | | 用户名 | 密码 |
72 | | ----------- | ----------- |
73 | | dgiot_dev | dgiot_dev |
74 |
75 | - 打包
76 |
77 | ```bash
78 | npm run build:prod
79 | ```
80 |
81 |
82 |
--------------------------------------------------------------------------------
/README-zh.md:
--------------------------------------------------------------------------------
1 | # iotView 轻量级工业物联网平台
2 |
3 |
4 |
6 |
7 |
8 |
9 |
10 | ## DGIoT平台简介
11 | DGIoT是国内首款轻量级工业物联网开源平台,我们致力于为5类客户提供物联网解决方案:
12 | + **国企/研究院**:平台代码开源,无版权产权困扰,国产无“卡脖”之忧
13 | + **系统集成商**:通用设备海量接入、定制设备二次开发、30分钟一键式私有化快速部署,低成本(降90%成本)
14 | + **工业设备制造商**:海量设备上线运维,不受公有云限制,低成本,短周期自建平台,私有化部署,数据安全
15 | + **开源平台开发者**:一键式开发环境,集成和兼容各种最优开源工具,快速承接物联网项目
16 | + **垂直领域物联网平台**:快速部署私有化平台,千万级承载,运营级底座,全开放扩展
17 |
18 | ## 平台快速体验与技术交流微信群
19 | | 微信技术支持群 |官网 https://www.dgiotcloud.cn/| [QQ技术支持群](https://jq.qq.com/?_wv=1027&k=LipWZvDe): 346566935 |
20 | |:---:|:---:|:---:|
21 | |
|**平台体验网址**
https://prod.dgiotcloud.cn
|
|
22 |
23 | ## 特色功能
24 | + 低代码快速开发
25 |
26 |
27 | 
28 |
29 | dgiot 前端框架
30 |
31 |
32 |
33 | ## 相关源码地址项目源码
34 |
35 | | 源码平台 | 源码地址 |
36 | | -------- | --------------------------------------------------------------------------------------------- |
37 | | github | [https://github.com/dgiot/iotView](https://github.com/dgiot/iotView?from=git) |
38 |
39 |
40 | ## 安装使用
41 |
42 | - 获取项目代码
43 |
44 | ```bash
45 | git clone -b master https://github.com/dgiot/iotView.git
46 | ```
47 |
48 | - 安装依赖
49 |
50 | ```bash
51 |
52 | npm install
53 |
54 | ```
55 |
56 | - 运行
57 |
58 | ```bash
59 |
60 | npm run dev
61 |
62 | ```
63 |
64 | - 效果展示
65 |
66 |
67 |
68 |
69 | - 登录
70 |
71 | | 用户名 | 密码 |
72 | | ----------- | ----------- |
73 | | dgiot_dev | dgiot_dev |
74 |
75 | - 打包
76 |
77 | ```bash
78 | npm run build:prod
79 | ```
80 |
81 |
82 |
--------------------------------------------------------------------------------
/src/components/Breadcrumb/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 | {{ item.meta.title }}
13 | {{ item.meta.title }}
14 |
15 |
16 |
17 |
18 |
19 |
79 |
80 |
93 |
--------------------------------------------------------------------------------
/mock/mock-server.js:
--------------------------------------------------------------------------------
1 | const chokidar = require('chokidar')
2 | const bodyParser = require('body-parser')
3 | const chalk = require('chalk')
4 | const path = require('path')
5 | const Mock = require('mockjs')
6 |
7 | const mockDir = path.join(process.cwd(), 'mock')
8 |
9 | function registerRoutes(app) {
10 | let mockLastIndex
11 | const { mocks } = require('./index.js')
12 | const mocksForServer = mocks.map(route => {
13 | return responseFake(route.url, route.type, route.response)
14 | })
15 | for (const mock of mocksForServer) {
16 | app[mock.type](mock.url, mock.response)
17 | mockLastIndex = app._router.stack.length
18 | }
19 | const mockRoutesLength = Object.keys(mocksForServer).length
20 | return {
21 | mockRoutesLength: mockRoutesLength,
22 | mockStartIndex: mockLastIndex - mockRoutesLength
23 | }
24 | }
25 |
26 | function unregisterRoutes() {
27 | Object.keys(require.cache).forEach(i => {
28 | if (i.includes(mockDir)) {
29 | delete require.cache[require.resolve(i)]
30 | }
31 | })
32 | }
33 |
34 | // for mock server
35 | const responseFake = (url, type, respond) => {
36 | return {
37 | url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`),
38 | type: type || 'get',
39 | response(req, res) {
40 | console.log('request invoke:' + req.path)
41 | res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))
42 | }
43 | }
44 | }
45 |
46 | module.exports = app => {
47 | // parse app.body
48 | // https://expressjs.com/en/4x/api.html#req.body
49 | app.use(bodyParser.json())
50 | app.use(bodyParser.urlencoded({
51 | extended: true
52 | }))
53 |
54 | const mockRoutes = registerRoutes(app)
55 | var mockRoutesLength = mockRoutes.mockRoutesLength
56 | var mockStartIndex = mockRoutes.mockStartIndex
57 |
58 | // watch files, hot reload mock server
59 | chokidar.watch(mockDir, {
60 | ignored: /mock-server/,
61 | ignoreInitial: true
62 | }).on('all', (event, path) => {
63 | if (event === 'change' || event === 'add') {
64 | try {
65 | // remove mock routes stack
66 | app._router.stack.splice(mockStartIndex, mockRoutesLength)
67 |
68 | // clear routes cache
69 | unregisterRoutes()
70 |
71 | const mockRoutes = registerRoutes(app)
72 | mockRoutesLength = mockRoutes.mockRoutesLength
73 | mockStartIndex = mockRoutes.mockStartIndex
74 |
75 | console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`))
76 | } catch (error) {
77 | console.log(chalk.redBright(error))
78 | }
79 | }
80 | })
81 | }
82 |
--------------------------------------------------------------------------------
/src/layout/components/Sidebar/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
15 |
21 |
22 |
23 |
24 |
25 |
26 |
90 |
--------------------------------------------------------------------------------
/src/views/dashboard/component/commom/RealCard.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
{{ value.name }}
5 |
6 |
7 |
12 |
13 | {{ item.name }}
14 |
17 |
18 |
19 |
20 |
29 |
30 |
34 | {{ item.number }} {{ item.unit }}
35 |
36 |
37 |
38 | {{ item.time }}
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
70 |
108 |
--------------------------------------------------------------------------------
/src/icons/svg/jump.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/views/Device/DeviceKonva/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
12 |
13 |
14 | {{ deviceInfo.name }}
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
79 |
122 |
--------------------------------------------------------------------------------
/tests/unit/components/Breadcrumb.spec.js:
--------------------------------------------------------------------------------
1 | import { mount, createLocalVue } from '@vue/test-utils'
2 | import VueRouter from 'vue-router'
3 | import ElementUI from 'element-ui'
4 | import Breadcrumb from '@/components/Breadcrumb/index.vue'
5 |
6 | const localVue = createLocalVue()
7 | localVue.use(VueRouter)
8 | localVue.use(ElementUI)
9 |
10 | const routes = [
11 | {
12 | path: '/',
13 | name: 'home',
14 | children: [{
15 | path: 'dashboard',
16 | name: 'dashboard'
17 | }]
18 | },
19 | {
20 | path: '/menu',
21 | name: 'menu',
22 | children: [{
23 | path: 'menu1',
24 | name: 'menu1',
25 | meta: { title: 'menu1' },
26 | children: [{
27 | path: 'menu1-1',
28 | name: 'menu1-1',
29 | meta: { title: 'menu1-1' }
30 | },
31 | {
32 | path: 'menu1-2',
33 | name: 'menu1-2',
34 | redirect: 'noredirect',
35 | meta: { title: 'menu1-2' },
36 | children: [{
37 | path: 'menu1-2-1',
38 | name: 'menu1-2-1',
39 | meta: { title: 'menu1-2-1' }
40 | },
41 | {
42 | path: 'menu1-2-2',
43 | name: 'menu1-2-2'
44 | }]
45 | }]
46 | }]
47 | }]
48 |
49 | const router = new VueRouter({
50 | routes
51 | })
52 |
53 | describe('Breadcrumb.vue', () => {
54 | const wrapper = mount(Breadcrumb, {
55 | localVue,
56 | router
57 | })
58 | it('dashboard', () => {
59 | router.push('/dashboard')
60 | const len = wrapper.findAll('.el-breadcrumb__inner').length
61 | expect(len).toBe(1)
62 | })
63 | it('normal route', () => {
64 | router.push('/menu/menu1')
65 | const len = wrapper.findAll('.el-breadcrumb__inner').length
66 | expect(len).toBe(2)
67 | })
68 | it('nested route', () => {
69 | router.push('/menu/menu1/menu1-2/menu1-2-1')
70 | const len = wrapper.findAll('.el-breadcrumb__inner').length
71 | expect(len).toBe(4)
72 | })
73 | it('no meta.title', () => {
74 | router.push('/menu/menu1/menu1-2/menu1-2-2')
75 | const len = wrapper.findAll('.el-breadcrumb__inner').length
76 | expect(len).toBe(3)
77 | })
78 | // it('click link', () => {
79 | // router.push('/menu/menu1/menu1-2/menu1-2-2')
80 | // const breadcrumbArray = wrapper.findAll('.el-breadcrumb__inner')
81 | // const second = breadcrumbArray.at(1)
82 | // console.log(breadcrumbArray)
83 | // const href = second.find('a').attributes().href
84 | // expect(href).toBe('#/menu/menu1')
85 | // })
86 | // it('noRedirect', () => {
87 | // router.push('/menu/menu1/menu1-2/menu1-2-1')
88 | // const breadcrumbArray = wrapper.findAll('.el-breadcrumb__inner')
89 | // const redirectBreadcrumb = breadcrumbArray.at(2)
90 | // expect(redirectBreadcrumb.contains('a')).toBe(false)
91 | // })
92 | it('last breadcrumb', () => {
93 | router.push('/menu/menu1/menu1-2/menu1-2-1')
94 | const breadcrumbArray = wrapper.findAll('.el-breadcrumb__inner')
95 | const redirectBreadcrumb = breadcrumbArray.at(3)
96 | expect(redirectBreadcrumb.contains('a')).toBe(false)
97 | })
98 | })
99 |
--------------------------------------------------------------------------------
/src/views/dashboard/component/TopoCard.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | {{ label }}:
9 | {{ value }}
10 |
22 |
23 |
24 |
25 |
29 |
30 |
31 |
32 |
101 |
117 |
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 |
4 | Vue.use(Router)
5 |
6 | /* Layout */
7 | import Layout from '@/layout'
8 |
9 | /**
10 | * Note: sub-menu only appear when route children.length >= 1
11 | * Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
12 | *
13 | * hidden: true if set true, item will not show in the sidebar(default is false)
14 | * alwaysShow: true if set true, will always show the root menu
15 | * if not set alwaysShow, when item has more than one children route,
16 | * it will becomes nested mode, otherwise not show the root menu
17 | * redirect: noRedirect if set noRedirect will no redirect in the breadcrumb
18 | * name:'router-name' the name is used by (must set!!!)
19 | * meta : {
20 | roles: ['admin','editor'] control the page roles (you can set multiple roles)
21 | title: 'title' the name show in sidebar and breadcrumb (recommend set)
22 | icon: 'svg-name'/'el-icon-x' the icon show in the sidebar
23 | breadcrumb: false if set false, the item will hidden in breadcrumb(default is true)
24 | activeMenu: '/example/list' if set path, the sidebar will highlight the path you set
25 | }
26 | */
27 |
28 | /**
29 | * constantRoutes
30 | * a base page that does not have permission requirements
31 | * all roles can be accessed
32 | */
33 | export const constantRoutes = [
34 | {
35 | path: '/login',
36 | component: () => import('@/views/login/index'),
37 | hidden: true
38 | },
39 | {
40 | path: '/404',
41 | component: () => import('@/views/404'),
42 | hidden: true
43 | },
44 |
45 | {
46 | path: '/',
47 | component: Layout,
48 | redirect: '/dashboard',
49 | meta: {
50 | title: '首页', icon: 'dashboard', hidden: false,
51 | },
52 | children: [{
53 | path: 'dashboard',
54 | name: 'Dashboard',
55 | component: () => import('@/views/dashboard/index'),
56 | meta: { title: '首页', icon: 'dashboard', hidden: false, }
57 | }]
58 | },
59 | {
60 | path: '/amis',
61 | component: Layout,
62 | redirect: '/amis/theme',
63 | name: 'Amis',
64 | children: [
65 | {
66 | path: '/amis/View/:id',
67 | name: 'tabs',
68 | component: () => import('@/views/CloudOc/AmisPage/index'),
69 | meta: { title: 'amis', icon: 'form' }
70 | },
71 | {
72 | path: '/amis/Device/konva',
73 | name: 'konva',
74 | component: () => import('@/views/Device/DeviceKonva/index'),
75 | meta: { title: 'amis', icon: 'form' }
76 | },
77 | {
78 | path: '/amis/Device/realcard',
79 | name: 'realcard',
80 | component: () => import('@/views/Device/DeviceRealCard/index'),
81 | meta: { title: 'amis', icon: 'form' }
82 | },
83 | ]
84 | },
85 | // 404 page must be placed at the end !!!
86 | { path: '*', redirect: '/404', hidden: true }
87 | ]
88 |
89 | const createRouter = () => new Router({
90 | // mode: 'history', // require service support
91 | scrollBehavior: () => ({ y: 0 }),
92 | routes: constantRoutes
93 | })
94 |
95 | const router = createRouter()
96 |
97 | // Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
98 | export function resetRouter() {
99 | const newRouter = createRouter()
100 | router.matcher = newRouter.matcher // reset router
101 | }
102 |
103 | export default router
104 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dashboard-amis",
3 | "version": "4.8.2",
4 | "description": "Amis Vue Template with Element UI & axios & iconfont & permission control & lint",
5 | "author": "dgiot <34489690@qq.com>",
6 | "scripts": {
7 | "dev": "vue-cli-service serve",
8 | "build:prod": "vue-cli-service build",
9 | "build:stage": "vue-cli-service build --mode staging",
10 | "preview": "node build/index.js --preview",
11 | "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
12 | "lint": "eslint --ext .js,.vue src",
13 | "test:unit": "jest --clearCache && vue-cli-service test:unit",
14 | "test:ci": "npm run lint && npm run test:unit"
15 | },
16 | "dependencies": {
17 | "@dgiot/dgiot-component": "^0.0.3",
18 | "axios": "^0.26.1",
19 | "core-js": "3.23.5",
20 | "echarts": "^4.9.0",
21 | "element-ui": "2.13.2",
22 | "gsap": "^3.11.4",
23 | "js-base64": "^3.7.2",
24 | "js-cookie": "2.2.0",
25 | "js-md5": "^0.7.3",
26 | "mqtt": "^4.3.7",
27 | "normalize.css": "7.0.0",
28 | "nprogress": "0.2.0",
29 | "path-to-regexp": "2.4.0",
30 | "postcss-custom-properties": "^8.0.11",
31 | "postcss-pxtorem": "^5.1.1",
32 | "qs": "^6.11.0",
33 | "three": "^0.147.0",
34 | "three-obj-mtl-loader": "^1.0.3",
35 | "v-charts": "^1.19.0",
36 | "vue": "2.6.10",
37 | "vue-3d-model": "^1.4.1",
38 | "vue-aliplayer-v2": "^1.3.0",
39 | "vue-amis-sdk": "1.10.3",
40 | "vue-baidu-map": "^0.21.22",
41 | "vue-router": "3.0.6",
42 | "vuera": "^0.2.7",
43 | "vuex": "3.1.0",
44 |
45 | "@fortawesome/fontawesome-free": "^5.15.3",
46 | "amis": "3.4.0",
47 | "amis-core": "3.4.0",
48 | "amis-editor": "5.5.0",
49 | "amis-editor-core": "5.5.0",
50 | "amis-formula": "3.4.0",
51 | "amis-ui": "3.4.0",
52 |
53 | "copy-to-clipboard": "^3.2.0",
54 | "mobx": "4.15.7",
55 | "mobx-react": "6.3.1",
56 | "mobx-state-tree": "3.17.3",
57 | "react": "^16.14.0",
58 | "react-dom": "^16.14.0",
59 | "react-hook-form": "^7.39.3",
60 | "react-router": "5.0.1",
61 | "react-router-dom": "5.0.1"
62 | },
63 | "devDependencies": {
64 | "@vue/cli-plugin-babel": "4.4.4",
65 | "@vue/cli-plugin-eslint": "4.4.4",
66 | "@vue/cli-plugin-unit-jest": "4.4.4",
67 | "@vue/cli-service": "4.4.4",
68 | "@vue/test-utils": "1.0.0-beta.29",
69 | "autoprefixer": "9.5.1",
70 | "babel-eslint": "10.1.0",
71 | "babel-jest": "23.6.0",
72 | "babel-plugin-dynamic-import-node": "2.3.3",
73 | "chalk": "2.4.2",
74 | "connect": "3.6.6",
75 | "copy-to-clipboard": "^3.3.1",
76 | "eslint": "6.7.2",
77 | "eslint-plugin-vue": "6.2.2",
78 | "html-webpack-plugin": "3.2.0",
79 | "runjs": "4.3.2",
80 | "sass": "1.26.8",
81 | "sass-loader": "8.0.2",
82 | "script-ext-html-webpack-plugin": "2.1.3",
83 | "serve-static": "1.13.2",
84 | "svg-sprite-loader": "4.1.3",
85 | "svgo": "1.2.2",
86 | "vue-template-compiler": "2.6.10",
87 |
88 | "@types/lodash": "^4.14.123",
89 | "@types/node": "^11.13.8",
90 | "@types/qs": "^6.5.3",
91 | "@types/react": "^16.9.0",
92 | "@types/react-dom": "^16.9.0",
93 | "@types/react-router": "5.0.1",
94 | "@types/react-router-dom": "^4.3.2",
95 | "acorn": "^8.8.2",
96 | "amis-widget-cli": "^3.2.0",
97 | "monaco-editor-webpack-plugin": "6.0.0",
98 | "prettier": "^2.2.1",
99 | "typescript": "^4.5.5"
100 | },
101 | "browserslist": [
102 | "> 1%",
103 | "last 2 versions"
104 | ],
105 | "engines": {
106 | "node": ">=8.9",
107 | "npm": ">= 3.0.0"
108 | },
109 | "license": "MIT"
110 | }
111 |
--------------------------------------------------------------------------------
/src/utils/request.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import { MessageBox, Message } from 'element-ui'
3 | import store from '@/store'
4 | import { getToken, setToken } from '@/utils/auth'
5 | import route from '../router/index'
6 | // import router from '../router/index'
7 |
8 | // create an axios instance
9 | const service = axios.create({
10 | baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
11 | // withCredentials: true, // send cookies when cross-domain requests
12 | timeout: 1000 * 60 * 3 // request timeout
13 | })
14 |
15 | // request interceptor
16 | service.interceptors.request.use(
17 | config => {
18 | // do something before request is sent
19 |
20 | if (store.getters.token) {
21 | // let each request carry token
22 | // ['X-Token'] is a custom headers key
23 | // please modify it according to the actual situation
24 | config.headers['sessionToken'] = getToken()
25 | }
26 | return config
27 | },
28 | error => {
29 | // do something with request error
30 | // console.log('错误', error) // for debug
31 | return Promise.reject(error)
32 | }
33 | )
34 |
35 | // response interceptor
36 | service.interceptors.response.use(
37 | /**
38 | * If you want to get http information such as headers or status
39 | * Please return response => response
40 | */
41 |
42 | /**
43 | * Determine the request status by custom code
44 | * Here is just an example
45 | * You can also judge the status by HTTP Status Code
46 | */
47 | response => {
48 | const res = response
49 |
50 | if (res.status != 200) {
51 | // Message({
52 | // message: res.statusText || 'Error',
53 | // type: 'error',
54 | // duration: 5 * 1000
55 | // })
56 |
57 | // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
58 | if (res.status === 403) {
59 | // to re-login
60 | Message({
61 | message: '暂无权限',
62 | type: 'error',
63 | duration: 5 * 1000
64 | })
65 | } else if (res.status === 401) {
66 | Message({
67 | message: '登录失效',
68 | type: 'error',
69 | duration: 5 * 1000
70 | })
71 |
72 | // MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
73 | // confirmButtonText: 'Re-Login',
74 | // cancelButtonText: 'Cancel',
75 | // type: 'warning'
76 | // }).then(() => {
77 | // store.dispatch('user/resetToken').then(() => {
78 | // location.reload()
79 | // })
80 | // })
81 | }
82 | return Promise.reject(new Error(res.message || 'Error'))
83 | } else {
84 | return res.data
85 | }
86 | },
87 | error => {
88 | console.log('错误', error)
89 | const info = error.msg || error.message
90 | Message({
91 | message: info,
92 | type: 'error',
93 | duration: 5 * 1000
94 | })
95 | if (error.message.indexOf('401') >= 0) {
96 | // console.log('异常错误', error.message) // for debug
97 | setToken()
98 | store.dispatch('user/resetToken').then(() => {
99 | location.reload()
100 | })
101 | // router.push({
102 | // path: '/login',
103 | // replace: true,
104 | // })
105 | // window.location.href = 'login'
106 | // history.push("/login");
107 | // router.push({ path: '/login' })
108 | // route.replace({ path: "/login" });
109 | // router.push({ path: "/login" });
110 | }
111 | return Promise.reject(error)
112 | }
113 | )
114 |
115 | export default service
116 |
--------------------------------------------------------------------------------
/src/utils/instance.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import { getToken } from '@/utils/auth'
3 | // import { MessageBox, Message } from "element-ui";
4 | // import store from "@/store";
5 | // import router from '@/router'
6 | // import { getToken,removeToken } from "@/utils/auth";
7 | // import { Toast } from "vant";
8 | // axios.post
9 | // create an axios instance
10 | const service = axios.create({
11 | // baseURL: "https://test.hgjzt.com", //https://test.hgjzt.com //"https://prod.dgiotcloud.com", //https://shuukgold.ga //http://45.40.194.29:28019 //process.env.VUE_APP_BASE_API, // url = base url + request url
12 | // withCredentials: true, // send cookies when cross-domain requests
13 | timeout: 360000 // request timeout
14 | });
15 |
16 | // request interceptor
17 | service.interceptors.request.use(
18 | config => {
19 | // console.log("222",config.headers['Content-Type']);
20 | if(!config.headers['Content-Type']){
21 | // console.log("111");
22 | config.headers['Content-Type'] = 'application/json';
23 | }
24 |
25 | config.headers["sessionToken"] = getToken() || ''
26 | // }
27 | return config;
28 | },
29 | error => {
30 | console.log("111");
31 | // do something with request error
32 | // console.log("Hi, this is the ERROR in Request!!", error); // for debug
33 | return Promise.reject(error);
34 | }
35 | );
36 |
37 | // response interceptor
38 | service.interceptors.response.use(
39 | response => {
40 | // console.log("response",response);
41 | const code = response.status
42 | if (code < 200 || (code > 300&&code<400)) {
43 | // Notification.error({
44 | // title: response.message
45 | // })
46 | return Promise.reject('error')
47 | } else {
48 | return response.data
49 | }
50 | },
51 | error => {
52 | // console.log("error",error.response);
53 | let code = 0
54 | try {
55 | code = error.response.status
56 | console.log("code",code);
57 | if(code==401){
58 | // console.log("111");
59 | // Toast.fail("登录已失效");
60 | // setTimeout(()=>{
61 | // router.push({ path: '/login' })
62 | // removeToken();
63 | // },2000)
64 |
65 | // store.dispatch('/manage/login').then(() => {
66 | // location.reload(true)
67 | // })
68 | }
69 | } catch (e) {
70 | if (error.toString().indexOf('Error: timeout') !== -1) {
71 | // Notification.error({
72 | // title: '网络请求超时',
73 | // duration: 360000
74 | // })
75 | return Promise.reject(error)
76 | }
77 | }
78 | if (code) {
79 | // if(code==401 &&res.data.code==209)
80 | if (code === 401) {
81 | // removeToken();
82 | // router.push(`/login?redirect=${this.$route.fullPath}`);
83 | // removeToken()
84 | // store.dispatch('/login').then(() => {
85 | // // 用户登录界面提示
86 | // // Cookies.set('point', 401)
87 | // location.reload()
88 | // })
89 | } else if (code === 403) {
90 | // router.push({ path: '/401' })
91 | } else {
92 | const errorMsg = error.response.data.message
93 | if (errorMsg !== undefined) {
94 | // Notification.error({
95 | // title: errorMsg,
96 | // duration: 360000
97 | // })
98 | }
99 | }
100 | } else {
101 | // Notification.error({
102 | // title: '接口请求失败',
103 | // duration: 360000
104 | // })
105 | }
106 | // console.log("测试",error);
107 | return Promise.reject(error)
108 | }
109 | )
110 |
111 | export default service;
112 |
--------------------------------------------------------------------------------
/src/utils/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by PanJiaChen on 16/11/18.
3 | */
4 |
5 | /**
6 | * Parse the time to string
7 | * @param {(Object|string|number)} time
8 | * @param {string} cFormat
9 | * @returns {string | null}
10 | */
11 | export function parseTime(time, cFormat) {
12 | if (arguments.length === 0 || !time) {
13 | return null
14 | }
15 | const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
16 | let date
17 | if (typeof time === 'object') {
18 | date = time
19 | } else {
20 | if ((typeof time === 'string')) {
21 | if ((/^[0-9]+$/.test(time))) {
22 | // support "1548221490638"
23 | time = parseInt(time)
24 | } else {
25 | // support safari
26 | // https://stackoverflow.com/questions/4310953/invalid-date-in-safari
27 | time = time.replace(new RegExp(/-/gm), '/')
28 | }
29 | }
30 |
31 | if ((typeof time === 'number') && (time.toString().length === 10)) {
32 | time = time * 1000
33 | }
34 | date = new Date(time)
35 | }
36 | const formatObj = {
37 | y: date.getFullYear(),
38 | m: date.getMonth() + 1,
39 | d: date.getDate(),
40 | h: date.getHours(),
41 | i: date.getMinutes(),
42 | s: date.getSeconds(),
43 | a: date.getDay()
44 | }
45 | const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
46 | const value = formatObj[key]
47 | // Note: getDay() returns 0 on Sunday
48 | if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
49 | return value.toString().padStart(2, '0')
50 | })
51 | return time_str
52 | }
53 |
54 | /**
55 | * @param {number} time
56 | * @param {string} option
57 | * @returns {string}
58 | */
59 | export function formatTime(time, option) {
60 | if (('' + time).length === 10) {
61 | time = parseInt(time) * 1000
62 | } else {
63 | time = +time
64 | }
65 | const d = new Date(time)
66 | const now = Date.now()
67 |
68 | const diff = (now - d) / 1000
69 |
70 | if (diff < 30) {
71 | return '刚刚'
72 | } else if (diff < 3600) {
73 | // less 1 hour
74 | return Math.ceil(diff / 60) + '分钟前'
75 | } else if (diff < 3600 * 24) {
76 | return Math.ceil(diff / 3600) + '小时前'
77 | } else if (diff < 3600 * 24 * 2) {
78 | return '1天前'
79 | }
80 | if (option) {
81 | return parseTime(time, option)
82 | } else {
83 | return (
84 | d.getMonth() +
85 | 1 +
86 | '月' +
87 | d.getDate() +
88 | '日' +
89 | d.getHours() +
90 | '时' +
91 | d.getMinutes() +
92 | '分'
93 | )
94 | }
95 | }
96 |
97 | /**
98 | * @param {string} url
99 | * @returns {Object}
100 | */
101 | export function param2Obj(url) {
102 | const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
103 | if (!search) {
104 | return {}
105 | }
106 | const obj = {}
107 | const searchArr = search.split('&')
108 | searchArr.forEach(v => {
109 | const index = v.indexOf('=')
110 | if (index !== -1) {
111 | const name = v.substring(0, index)
112 | const val = v.substring(index + 1, v.length)
113 | obj[name] = val
114 | }
115 | })
116 | return obj
117 | }
118 | export function utc2beijing(utc_datetime) {
119 | // 转为正常的时间格式 年-月-日 时:分:秒
120 | var date = new Date(+new Date(utc_datetime) + 8 * 3600 * 1000)
121 | .toISOString()
122 | .replace(/T/g, ' ')
123 | .replace(/\.[\d]{3}Z/, '')
124 | return date // 2017-03-31 16:02:06
125 | }
126 | export function isPC() {
127 | var userAgentInfo = navigator.userAgent
128 | var Agents = new Array(
129 | 'Android',
130 | 'iPhone',
131 | 'SymbianOS',
132 | 'Windows Phone',
133 | 'iPad',
134 | 'iPod'
135 | )
136 | var flag = true
137 | for (var v = 0; v < Agents.length; v++) {
138 | if (userAgentInfo.indexOf(Agents[v]) > 0) {
139 | flag = false
140 | break
141 | }
142 | }
143 | return flag
144 | }
145 | function FormatTime(t) {
146 | if (t < 10) return "0" + t;
147 | return t;
148 | }
149 | export function getTime() {
150 | var myDate = new Date();
151 | let yy = myDate.getFullYear(); // 获取完整的年份(4位,1970-????)
152 | let mm = myDate.getMonth() + 1; // 获取当前月份(0-11,0代表1月)
153 | mm = FormatTime(mm);
154 | let dd = myDate.getDate(); // 获取当前日(1-31)
155 | dd = FormatTime(dd);
156 | let hh = myDate.getHours(); // 获取当前小时数(0-23)
157 | hh = FormatTime(hh);
158 | let mt = myDate.getMinutes(); // 获取当前分钟数(0-59)
159 | mt = FormatTime(mt);
160 | let ss = myDate.getSeconds(); // 获取当前秒数(0-59)
161 | ss = FormatTime(ss);
162 | // let ms = myDate.getMilliseconds();
163 | //2021-10-22T10:13:39.229Z
164 | let currentTime =
165 | yy + "-" + mm + "-" + dd + " " + hh + ":" + mt + ":" + ss;
166 | return currentTime;
167 | }
--------------------------------------------------------------------------------
/public/resources/tween.min.js:
--------------------------------------------------------------------------------
1 | // tween.js - http://github.com/sole/tween.js
2 | 'use strict';var TWEEN=TWEEN||function(){var a=[];return{REVISION:"7",getAll:function(){return a},removeAll:function(){a=[]},add:function(c){a.push(c)},remove:function(c){c=a.indexOf(c);-1!==c&&a.splice(c,1)},update:function(c){if(0===a.length)return!1;for(var b=0,d=a.length,c=void 0!==c?c:Date.now();b(a*=2)?0.5*a*a:-0.5*(--a*(a-2)-1)}},Cubic:{In:function(a){return a*a*a},Out:function(a){return--a*a*a+1},InOut:function(a){return 1>(a*=2)?0.5*a*a*a:0.5*((a-=2)*a*a+2)}},Quartic:{In:function(a){return a*a*a*a},Out:function(a){return 1- --a*a*a*a},InOut:function(a){return 1>(a*=2)?0.5*a*a*a*a:-0.5*((a-=2)*a*a*a-2)}},Quintic:{In:function(a){return a*a*a*
7 | a*a},Out:function(a){return--a*a*a*a*a+1},InOut:function(a){return 1>(a*=2)?0.5*a*a*a*a*a:0.5*((a-=2)*a*a*a*a+2)}},Sinusoidal:{In:function(a){return 1-Math.cos(a*Math.PI/2)},Out:function(a){return Math.sin(a*Math.PI/2)},InOut:function(a){return 0.5*(1-Math.cos(Math.PI*a))}},Exponential:{In:function(a){return 0===a?0:Math.pow(1024,a-1)},Out:function(a){return 1===a?1:1-Math.pow(2,-10*a)},InOut:function(a){return 0===a?0:1===a?1:1>(a*=2)?0.5*Math.pow(1024,a-1):0.5*(-Math.pow(2,-10*(a-1))+2)}},Circular:{In:function(a){return 1-
8 | Math.sqrt(1-a*a)},Out:function(a){return Math.sqrt(1- --a*a)},InOut:function(a){return 1>(a*=2)?-0.5*(Math.sqrt(1-a*a)-1):0.5*(Math.sqrt(1-(a-=2)*a)+1)}},Elastic:{In:function(a){var c,b=0.1;if(0===a)return 0;if(1===a)return 1;!b||1>b?(b=1,c=0.1):c=0.4*Math.asin(1/b)/(2*Math.PI);return-(b*Math.pow(2,10*(a-=1))*Math.sin((a-c)*2*Math.PI/0.4))},Out:function(a){var c,b=0.1;if(0===a)return 0;if(1===a)return 1;!b||1>b?(b=1,c=0.1):c=0.4*Math.asin(1/b)/(2*Math.PI);return b*Math.pow(2,-10*a)*Math.sin((a-c)*
9 | 2*Math.PI/0.4)+1},InOut:function(a){var c,b=0.1;if(0===a)return 0;if(1===a)return 1;!b||1>b?(b=1,c=0.1):c=0.4*Math.asin(1/b)/(2*Math.PI);return 1>(a*=2)?-0.5*b*Math.pow(2,10*(a-=1))*Math.sin((a-c)*2*Math.PI/0.4):0.5*b*Math.pow(2,-10*(a-=1))*Math.sin((a-c)*2*Math.PI/0.4)+1}},Back:{In:function(a){return a*a*(2.70158*a-1.70158)},Out:function(a){return--a*a*(2.70158*a+1.70158)+1},InOut:function(a){return 1>(a*=2)?0.5*a*a*(3.5949095*a-2.5949095):0.5*((a-=2)*a*(3.5949095*a+2.5949095)+2)}},Bounce:{In:function(a){return 1-
10 | TWEEN.Easing.Bounce.Out(1-a)},Out:function(a){return a<1/2.75?7.5625*a*a:a<2/2.75?7.5625*(a-=1.5/2.75)*a+0.75:a<2.5/2.75?7.5625*(a-=2.25/2.75)*a+0.9375:7.5625*(a-=2.625/2.75)*a+0.984375},InOut:function(a){return 0.5>a?0.5*TWEEN.Easing.Bounce.In(2*a):0.5*TWEEN.Easing.Bounce.Out(2*a-1)+0.5}}};
11 | TWEEN.Interpolation={Linear:function(a,c){var b=a.length-1,d=b*c,e=Math.floor(d),f=TWEEN.Interpolation.Utils.Linear;return 0>c?f(a[0],a[1],d):1b?b:e+1],d-e)},Bezier:function(a,c){var b=0,d=a.length-1,e=Math.pow,f=TWEEN.Interpolation.Utils.Bernstein,h;for(h=0;h<=d;h++)b+=e(1-c,d-h)*e(c,h)*a[h]*f(d,h);return b},CatmullRom:function(a,c){var b=a.length-1,d=b*c,e=Math.floor(d),f=TWEEN.Interpolation.Utils.CatmullRom;return a[0]===a[b]?(0>c&&(e=Math.floor(d=b*(1+c))),f(a[(e-
12 | 1+b)%b],a[e],a[(e+1)%b],a[(e+2)%b],d-e)):0>c?a[0]-(f(a[0],a[0],a[1],a[1],-d)-a[0]):1
2 |
3 |
8 |
9 |
14 |
15 | 报警信息: {{ item.content.alarm_message }}
18 |
19 |
20 | 报警时间: {{ utc2beijing(item.createdAt) }}
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
122 |
143 |
167 |
--------------------------------------------------------------------------------
/src/layout/components/AppMain.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
13 |
14 |
18 |
19 | {{ item.meta.title }}
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
119 |
120 |
156 |
157 |
165 |
--------------------------------------------------------------------------------
/src/permission.js:
--------------------------------------------------------------------------------
1 | import router from './router'
2 | import store from './store'
3 | import { Message } from 'element-ui'
4 | import NProgress from 'nprogress' // progress bar
5 | import 'nprogress/nprogress.css' // progress bar style
6 | import { getToken } from '@/utils/auth' // get token from cookie
7 | import getPageTitle from '@/utils/get-page-title'
8 | import Cookies from 'js-cookie'
9 | import { getNavigation } from '@/api/Navigation'
10 | import { Roletree } from '@/api/User/index'
11 | import { postCookie } from '@/api/Dashboard/index'
12 | import VueRouter from 'vue-router'
13 |
14 | NProgress.configure({ showSpinner: false }) // NProgress Configuration
15 |
16 | const whiteList = ['/login'] // no redirect whitelist
17 |
18 | router.beforeEach(async(to, from, next) => {
19 | // start progress bar
20 | NProgress.start()
21 |
22 | // set page title
23 | document.title = getPageTitle(to.meta.title)
24 |
25 | // determine whether the user has logged in
26 | // console.log('路由拦截',hasToken);
27 | console.error('to.query', to.query)
28 | if (to.query.username) {
29 | // http://192.168.2.132:3333/#/dashboard?username=ailiandata&password=fJYjEFg59H
30 | // https://work.dgiotcloud.com/#/dashboard?username=ailiandata&password=fJYjEFg59H
31 | // https://work.dgiotcloud.com/#/amis/View/f864c8f234?username=ailiandata&password=fJYjEFg59H
32 | await store.dispatch('user/login', {
33 | username: to.query.username || '',
34 | password: to.query.password || ''
35 | })
36 | .then(async() => {
37 | Vue.prototype.$FileServe = Cookies.get('fileServer') || ''
38 | const res = await getNavigation()
39 | console.log('路由', res)
40 | const list = []
41 | const item = {
42 | path: '/',
43 | url: '/',
44 | // component: Layout,
45 | redirect: '/dashboard',
46 | meta: {
47 | title: '首页',
48 | icon: 'dashboard',
49 | hidden: false
50 | },
51 | children: [
52 | {
53 | path: '/dashboard',
54 | url: '/dashboard',
55 | name: 'Dashboard',
56 | // component: () => import("@/views/dashboard/index"),
57 | meta: { title: '首页', icon: 'el-icon-s-home', hidden: false }
58 | }
59 | ]
60 | }
61 | list.push(item)
62 | res.results.forEach((item) => {
63 | if (item.url != '/' && item.url != '/roles') {
64 | list.push(item)
65 | }
66 | })
67 | store.dispatch('user/initRoutes', list).then(res => {
68 | const routelist = []
69 | // 过滤admin 中的路由
70 | res.forEach((element, index) => {
71 | if (element.children) {
72 | if (
73 | element.children[0].url.indexOf('amis') >= 0 ||
74 | element.children[0].name.indexOf('Dashboard') >= 0
75 | ) {
76 | routelist.push(element)
77 | }
78 | } else {
79 | routelist.push(element)
80 | }
81 | })
82 | localStorage.setItem('routes', JSON.stringify(routelist)) // 路由列表
83 | })
84 | const roletree = await Roletree()
85 | localStorage.setItem(
86 | 'dgiotroletree',
87 | JSON.stringify(roletree.results)
88 | )
89 | // 设置使用什么地图
90 | const data = {
91 | UserSession: getToken() || '',
92 | cookie: {
93 | mapType: 'baidu'
94 | }
95 | }
96 | await postCookie(data)
97 | })
98 | }
99 | const hasToken = getToken()
100 | if (hasToken) {
101 | if (to.path === '/login') {
102 | // if is logged in, redirect to the home page
103 | next({ path: '/' })
104 | NProgress.done()
105 | } else {
106 | const hasGetUserInfo = store.getters.name
107 | if (hasGetUserInfo) {
108 | next()
109 | } else {
110 | try {
111 | // get user info
112 | // await store.dispatch('user/getInfo')
113 |
114 | next()
115 | } catch (error) {
116 | // remove token and go to login page to re-login
117 | await store.dispatch('user/resetToken')
118 | Message.error(error || 'Has Error')
119 | next(`/login?redirect=${to.path}`)
120 | NProgress.done()
121 | }
122 | }
123 | }
124 | } else {
125 | /* has no token*/
126 | // next(`/login?redirect=${to.path}`)
127 | if (whiteList.indexOf(to.path) !== -1) {
128 | // in the free login whitelist, go directly
129 | next()
130 | } else {
131 | // other pages that do not have permission to access are redirected to the login page.
132 | next(`/login?redirect=${to.path}`)
133 | NProgress.done()
134 | }
135 | }
136 | })
137 |
138 | router.afterEach(() => {
139 | // finish progress bar
140 | NProgress.done()
141 | })
142 |
--------------------------------------------------------------------------------
/src/components/model3d/dgiot-model-demo2.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
145 |
151 |
--------------------------------------------------------------------------------
/src/views/Device/DeviceRealCard/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
13 | {{ deviceInfo.name }}
14 |
15 |
16 |
17 |
18 |
19 |
20 |
123 |
129 |
170 |
--------------------------------------------------------------------------------
/src/styles/sidebar.scss:
--------------------------------------------------------------------------------
1 | #app {
2 |
3 | .main-container {
4 | min-height: 100%;
5 | transition: margin-left .28s;
6 | margin-left: $sideBarWidth;
7 | position: relative;
8 | }
9 |
10 | .sidebar-container {
11 | transition: width 0.28s;
12 | width: $sideBarWidth !important;
13 | background-color: $menuBg;
14 | height: 100%;
15 | position: fixed;
16 | font-size: 0px;
17 | top: 0;
18 | bottom: 0;
19 | left: 0;
20 | z-index: 1001;
21 | overflow: hidden;
22 |
23 | // reset element-ui css
24 | .horizontal-collapse-transition {
25 | transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
26 | }
27 |
28 | .scrollbar-wrapper {
29 | overflow-x: hidden !important;
30 | }
31 |
32 | .el-scrollbar__bar.is-vertical {
33 | right: 0px;
34 | }
35 |
36 | .el-scrollbar {
37 | height: 100%;
38 | }
39 |
40 | &.has-logo {
41 | .el-scrollbar {
42 | height: calc(100% - 50px);
43 | }
44 | }
45 |
46 | .is-horizontal {
47 | display: none;
48 | }
49 |
50 | a {
51 | display: inline-block;
52 | width: 100%;
53 | overflow: hidden;
54 | }
55 |
56 | .svg-icon {
57 | margin-right: 16px;
58 | }
59 |
60 | .sub-el-icon {
61 | margin-right: 12px;
62 | margin-left: -2px;
63 | }
64 |
65 | .el-menu {
66 | border: none;
67 | height: 100%;
68 | width: 100% !important;
69 | }
70 |
71 | // menu hover
72 | .submenu-title-noDropdown,
73 | .el-submenu__title {
74 | &:hover {
75 | background-color: $menuHover !important;
76 | }
77 | }
78 |
79 | .is-active>.el-submenu__title {
80 | color: $subMenuActiveText !important;
81 | }
82 |
83 | & .nest-menu .el-submenu>.el-submenu__title,
84 | & .el-submenu .el-menu-item {
85 | min-width: $sideBarWidth !important;
86 | background-color: $subMenuBg !important;
87 |
88 | &:hover {
89 | background-color: $subMenuHover !important;
90 | }
91 | }
92 | }
93 |
94 | .hideSidebar {
95 | .sidebar-container {
96 | width: 54px !important;
97 | }
98 |
99 | .main-container {
100 | margin-left: 54px;
101 | }
102 |
103 | .submenu-title-noDropdown {
104 | padding: 0 !important;
105 | position: relative;
106 |
107 | .el-tooltip {
108 | padding: 0 !important;
109 |
110 | .svg-icon {
111 | margin-left: 20px;
112 | }
113 |
114 | .sub-el-icon {
115 | margin-left: 19px;
116 | }
117 | }
118 | }
119 |
120 | .el-submenu {
121 | overflow: hidden;
122 |
123 | &>.el-submenu__title {
124 | padding: 0 !important;
125 |
126 | .svg-icon {
127 | margin-left: 20px;
128 | }
129 |
130 | .sub-el-icon {
131 | margin-left: 19px;
132 | }
133 |
134 | .el-submenu__icon-arrow {
135 | display: none;
136 | }
137 | }
138 | }
139 |
140 | .el-menu--collapse {
141 | .el-submenu {
142 | &>.el-submenu__title {
143 | &>span {
144 | height: 0;
145 | width: 0;
146 | overflow: hidden;
147 | visibility: hidden;
148 | display: inline-block;
149 | }
150 | }
151 | }
152 | }
153 | }
154 |
155 | .el-menu--collapse .el-menu .el-submenu {
156 | min-width: $sideBarWidth !important;
157 | }
158 |
159 | // mobile responsive
160 | .mobile {
161 | .main-container {
162 | margin-left: 0px;
163 | }
164 |
165 | .sidebar-container {
166 | transition: transform .28s;
167 | width: $sideBarWidth !important;
168 | }
169 |
170 | &.hideSidebar {
171 | .sidebar-container {
172 | pointer-events: none;
173 | transition-duration: 0.3s;
174 | transform: translate3d(-$sideBarWidth, 0, 0);
175 | }
176 | }
177 | }
178 |
179 | .withoutAnimation {
180 |
181 | .main-container,
182 | .sidebar-container {
183 | transition: none;
184 | }
185 | }
186 | }
187 |
188 | // when menu collapsed
189 | .el-menu--vertical {
190 | &>.el-menu {
191 | .svg-icon {
192 | margin-right: 16px;
193 | }
194 | .sub-el-icon {
195 | margin-right: 12px;
196 | margin-left: -2px;
197 | }
198 | }
199 |
200 | .nest-menu .el-submenu>.el-submenu__title,
201 | .el-menu-item {
202 | &:hover {
203 | // you can use $subMenuHover
204 | background-color: $menuHover !important;
205 | }
206 | }
207 |
208 | // the scroll bar appears when the subMenu is too long
209 | >.el-menu--popup {
210 | max-height: 100vh;
211 | overflow-y: auto;
212 |
213 | &::-webkit-scrollbar-track-piece {
214 | background: #d3dce6;
215 | }
216 |
217 | &::-webkit-scrollbar {
218 | width: 6px;
219 | }
220 |
221 | &::-webkit-scrollbar-thumb {
222 | background: #99a9bf;
223 | border-radius: 20px;
224 | }
225 | }
226 | }
227 |
--------------------------------------------------------------------------------
/src/layout/components/Sidebar/SidebarItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
15 |
19 |
20 |
21 |
22 |
23 |
29 |
30 |
35 |
36 |
44 |
45 |
46 |
47 |
48 |
160 |
--------------------------------------------------------------------------------
/src/components/model3d/dgiot-model-fbx.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
17 |
31 |
45 |
58 |
71 |
72 |
73 |
74 |
191 |
197 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parserOptions: {
4 | parser: 'babel-eslint',
5 | sourceType: 'module'
6 | },
7 | env: {
8 | browser: true,
9 | node: true,
10 | es6: true,
11 | },
12 | extends: ['plugin:vue/recommended', 'eslint:recommended'],
13 |
14 | // add your custom rules here
15 | //it is base on https://github.com/vuejs/eslint-config-vue
16 | rules: {
17 | "vue/max-attributes-per-line": [2, {
18 | "singleline": 10,
19 | "multiline": {
20 | "max": 1,
21 | "allowFirstLine": false
22 | }
23 | }],
24 | "vue/singleline-html-element-content-newline": "off",
25 | "vue/multiline-html-element-content-newline":"off",
26 | "vue/name-property-casing": ["error", "PascalCase"],
27 | "vue/no-v-html": "off",
28 | 'accessor-pairs': 2,
29 | 'arrow-spacing': [2, {
30 | 'before': true,
31 | 'after': true
32 | }],
33 | 'block-spacing': [2, 'always'],
34 | 'brace-style': [2, '1tbs', {
35 | 'allowSingleLine': true
36 | }],
37 | 'camelcase': [0, {
38 | 'properties': 'always'
39 | }],
40 | 'comma-dangle': [2, 'never'],
41 | 'comma-spacing': [2, {
42 | 'before': false,
43 | 'after': true
44 | }],
45 | 'comma-style': [2, 'last'],
46 | 'constructor-super': 2,
47 | 'curly': [2, 'multi-line'],
48 | 'dot-location': [2, 'property'],
49 | 'eol-last': 2,
50 | 'eqeqeq': ["error", "always", {"null": "ignore"}],
51 | 'generator-star-spacing': [2, {
52 | 'before': true,
53 | 'after': true
54 | }],
55 | 'handle-callback-err': [2, '^(err|error)$'],
56 | 'indent': [2, 2, {
57 | 'SwitchCase': 1
58 | }],
59 | 'jsx-quotes': [2, 'prefer-single'],
60 | 'key-spacing': [2, {
61 | 'beforeColon': false,
62 | 'afterColon': true
63 | }],
64 | 'keyword-spacing': [2, {
65 | 'before': true,
66 | 'after': true
67 | }],
68 | 'new-cap': [2, {
69 | 'newIsCap': true,
70 | 'capIsNew': false
71 | }],
72 | 'new-parens': 2,
73 | 'no-array-constructor': 2,
74 | 'no-caller': 2,
75 | 'no-console': 'off',
76 | 'no-class-assign': 2,
77 | 'no-cond-assign': 2,
78 | 'no-const-assign': 2,
79 | 'no-control-regex': 0,
80 | 'no-delete-var': 2,
81 | 'no-dupe-args': 2,
82 | 'no-dupe-class-members': 2,
83 | 'no-dupe-keys': 2,
84 | 'no-duplicate-case': 2,
85 | 'no-empty-character-class': 2,
86 | 'no-empty-pattern': 2,
87 | 'no-eval': 2,
88 | 'no-ex-assign': 2,
89 | 'no-extend-native': 2,
90 | 'no-extra-bind': 2,
91 | 'no-extra-boolean-cast': 2,
92 | 'no-extra-parens': [2, 'functions'],
93 | 'no-fallthrough': 2,
94 | 'no-floating-decimal': 2,
95 | 'no-func-assign': 2,
96 | 'no-implied-eval': 2,
97 | 'no-inner-declarations': [2, 'functions'],
98 | 'no-invalid-regexp': 2,
99 | 'no-irregular-whitespace': 2,
100 | 'no-iterator': 2,
101 | 'no-label-var': 2,
102 | 'no-labels': [2, {
103 | 'allowLoop': false,
104 | 'allowSwitch': false
105 | }],
106 | 'no-lone-blocks': 2,
107 | 'no-mixed-spaces-and-tabs': 2,
108 | 'no-multi-spaces': 2,
109 | 'no-multi-str': 2,
110 | 'no-multiple-empty-lines': [2, {
111 | 'max': 1
112 | }],
113 | 'no-native-reassign': 2,
114 | 'no-negated-in-lhs': 2,
115 | 'no-new-object': 2,
116 | 'no-new-require': 2,
117 | 'no-new-symbol': 2,
118 | 'no-new-wrappers': 2,
119 | 'no-obj-calls': 2,
120 | 'no-octal': 2,
121 | 'no-octal-escape': 2,
122 | 'no-path-concat': 2,
123 | 'no-proto': 2,
124 | 'no-redeclare': 2,
125 | 'no-regex-spaces': 2,
126 | 'no-return-assign': [2, 'except-parens'],
127 | 'no-self-assign': 2,
128 | 'no-self-compare': 2,
129 | 'no-sequences': 2,
130 | 'no-shadow-restricted-names': 2,
131 | 'no-spaced-func': 2,
132 | 'no-sparse-arrays': 2,
133 | 'no-this-before-super': 2,
134 | 'no-throw-literal': 2,
135 | 'no-trailing-spaces': 2,
136 | 'no-undef': 2,
137 | 'no-undef-init': 2,
138 | 'no-unexpected-multiline': 2,
139 | 'no-unmodified-loop-condition': 2,
140 | 'no-unneeded-ternary': [2, {
141 | 'defaultAssignment': false
142 | }],
143 | 'no-unreachable': 2,
144 | 'no-unsafe-finally': 2,
145 | 'no-unused-vars': [2, {
146 | 'vars': 'all',
147 | 'args': 'none'
148 | }],
149 | 'no-useless-call': 2,
150 | 'no-useless-computed-key': 2,
151 | 'no-useless-constructor': 2,
152 | 'no-useless-escape': 0,
153 | 'no-whitespace-before-property': 2,
154 | 'no-with': 2,
155 | 'one-var': [2, {
156 | 'initialized': 'never'
157 | }],
158 | 'operator-linebreak': [2, 'after', {
159 | 'overrides': {
160 | '?': 'before',
161 | ':': 'before'
162 | }
163 | }],
164 | 'padded-blocks': [2, 'never'],
165 | 'quotes': [2, 'single', {
166 | 'avoidEscape': true,
167 | 'allowTemplateLiterals': true
168 | }],
169 | 'semi': [2, 'never'],
170 | 'semi-spacing': [2, {
171 | 'before': false,
172 | 'after': true
173 | }],
174 | 'space-before-blocks': [2, 'always'],
175 | 'space-before-function-paren': [2, 'never'],
176 | 'space-in-parens': [2, 'never'],
177 | 'space-infix-ops': 2,
178 | 'space-unary-ops': [2, {
179 | 'words': true,
180 | 'nonwords': false
181 | }],
182 | 'spaced-comment': [2, 'always', {
183 | 'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
184 | }],
185 | 'template-curly-spacing': [2, 'never'],
186 | 'use-isnan': 2,
187 | 'valid-typeof': 2,
188 | 'wrap-iife': [2, 'any'],
189 | 'yield-star-spacing': [2, 'both'],
190 | 'yoda': [2, 'never'],
191 | 'prefer-const': 2,
192 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
193 | 'object-curly-spacing': [2, 'always', {
194 | objectsInObjects: false
195 | }],
196 | 'array-bracket-spacing': [2, 'never']
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const path = require('path')
3 | const defaultSettings = require('./src/settings.js')
4 |
5 | function resolve(dir) {
6 | return path.join(__dirname, dir)
7 | }
8 |
9 | const name = defaultSettings.title || 'Amis Vue Template' // page title
10 |
11 | // If your port is set to 80,
12 | // use administrator privileges to execute the command line.
13 | // For example, Mac: sudo npm run
14 | // You can change the port by the following methods:
15 | // port = 9528 npm run dev OR npm run dev --port = 9528
16 | const port = process.env.port || process.env.npm_config_port || 3333 // dev port
17 | // All configuration item explanations can be find in https://cli.vuejs.org/config/
18 | module.exports = {
19 | /**
20 | * You will need to set publicPath if you plan to deploy your site under a sub path,
21 | * for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,
22 | * then publicPath should be set to "/bar/".
23 | * In most cases please use '/' !!!
24 | * Detail: https://cli.vuejs.org/config/#publicpath
25 | */
26 | publicPath: './',
27 | outputDir: 'dist',
28 | assetsDir: 'static',
29 | lintOnSave: process.env.NODE_ENV === 'development',
30 | productionSourceMap: false,
31 | devServer: {
32 | port: port,
33 | open: true,
34 | overlay: {
35 | warnings: false,
36 | errors: true
37 | },
38 | proxy: {
39 | '/iotapi': {
40 | // 代理api
41 | target: 'http://192.168.1.201', // 代理接口(注意只要域名就够了)
42 | secure: 'true',
43 | changeOrigin: true, // 是否跨域
44 | ws: true, // proxy websockets
45 | pathRewrite: {
46 | // 重写路径
47 | '^/iotapi': '/iotapi' // 代理路径
48 | }
49 | },
50 | '/dgiot_dashboard': {
51 | // 代理api
52 | target: 'http://192.168.1.201', // 代理接口(注意只要域名就够了)
53 | secure: 'true',
54 | changeOrigin: true, // 是否跨域
55 | ws: true, // proxy websockets
56 | pathRewrite: {
57 | // 重写路径
58 | '^/dgiot_dashboard': '/dgiot_dashboard' // 代理路径
59 | }
60 | },
61 | '/dgiot_file': {
62 | // 代理api
63 | target: 'http://192.168.1.201', // 代理接口(注意只要域名就够了)
64 | secure: 'true',
65 | changeOrigin: true, // 是否跨域
66 | ws: true, // proxy websockets
67 | pathRewrite: {
68 | // 重写路径
69 | '^/dgiot_file': '/dgiot_file' // 代理路径
70 | }
71 | },
72 | '/upload': {
73 | // 代理api
74 | target: 'http://192.168.1.201', // 代理接口(注意只要域名就够了)
75 | secure: 'true',
76 | changeOrigin: true, // 是否跨域
77 | ws: true, // proxy websockets
78 | pathRewrite: {
79 | // 重写路径
80 | '^/upload': '/upload' // 代理路径
81 | }
82 | }
83 | }
84 | // before: require('./mock/mock-server.js')
85 | },
86 | configureWebpack: {
87 | // provide the app's title in webpack's name field, so that
88 | // it can be accessed in index.html to inject the correct title.
89 | name: name,
90 | resolve: {
91 | alias: {
92 | '@': resolve('src')
93 | }
94 | }
95 | },
96 | chainWebpack(config) {
97 | // it can improve the speed of the first screen, it is recommended to turn on preload
98 | config.plugin('preload').tap(() => [
99 | {
100 | rel: 'preload',
101 | // to ignore runtime.js
102 | // https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/cli-service/lib/config/app.js#L171
103 | fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/],
104 | include: 'initial'
105 | }
106 | ])
107 |
108 | // when there are many pages, it will cause too many meaningless requests
109 | config.plugins.delete('prefetch')
110 |
111 | // set svg-sprite-loader
112 | config.module
113 | .rule('svg')
114 | .exclude.add(resolve('src/icons'))
115 | .end()
116 | config.module
117 | .rule('icons')
118 | .test(/\.svg$/)
119 | .include.add(resolve('src/icons'))
120 | .end()
121 | .use('svg-sprite-loader')
122 | .loader('svg-sprite-loader')
123 | .options({
124 | symbolId: 'icon-[name]'
125 | })
126 | .end()
127 |
128 | config
129 | .when(process.env.NODE_ENV !== 'development',
130 | config => {
131 | config
132 | .plugin('ScriptExtHtmlWebpackPlugin')
133 | .after('html')
134 | .use('script-ext-html-webpack-plugin', [{
135 | // `runtime` must same as runtimeChunk name. default is `runtime`
136 | inline: /runtime\..*\.js$/
137 | }])
138 | .end()
139 | config
140 | .optimization.splitChunks({
141 | chunks: 'all',
142 | cacheGroups: {
143 | libs: {
144 | name: 'chunk-libs',
145 | test: /[\\/]node_modules[\\/]/,
146 | priority: 10,
147 | chunks: 'initial' // only package third parties that are initially dependent
148 | },
149 | elementUI: {
150 | name: 'chunk-elementUI', // split elementUI into a single package
151 | priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
152 | test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
153 | },
154 | commons: {
155 | name: 'chunk-commons',
156 | test: resolve('src/components'), // can customize your rules
157 | minChunks: 3, // minimum common number
158 | priority: 5,
159 | reuseExistingChunk: true
160 | }
161 | }
162 | })
163 | // https:// webpack.js.org/configuration/optimization/#optimizationruntimechunk
164 | config.optimization.runtimeChunk('single')
165 | }
166 | )
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/src/views/dashboard/component/TopoPie.vue:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
199 |
215 |
--------------------------------------------------------------------------------