diff --git a/.gitignore b/.gitignore
index 3e759b7..a4222ae 100644
--- a/.gitignore
+++ b/.gitignore
@@ -328,3 +328,4 @@ ASALocalRun/
# MFractors (Xamarin productivity tool) working folder
.mfractor/
+*.json
diff --git a/src/JT808.DotNetty.Dashbord.UI/.babelrc b/src/JT808.DotNetty.Dashbord.UI/.babelrc
new file mode 100644
index 0000000..2a81884
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/.babelrc
@@ -0,0 +1,5 @@
+{
+ "presets": [
+ "@vue/app"
+ ]
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/.editorconfig b/src/JT808.DotNetty.Dashbord.UI/.editorconfig
new file mode 100644
index 0000000..9d08a1a
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/.editorconfig
@@ -0,0 +1,9 @@
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
diff --git a/src/JT808.DotNetty.Dashbord.UI/.eslintignore b/src/JT808.DotNetty.Dashbord.UI/.eslintignore
new file mode 100644
index 0000000..e69de29
diff --git a/src/JT808.DotNetty.Dashbord.UI/.eslintrc.js b/src/JT808.DotNetty.Dashbord.UI/.eslintrc.js
new file mode 100644
index 0000000..2005c1a
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/.eslintrc.js
@@ -0,0 +1,19 @@
+module.exports = {
+ root: true,
+ 'extends': [
+ 'plugin:vue/essential',
+ '@vue/standard'
+ ],
+ rules: {
+ // allow async-await
+ 'generator-star-spacing': 'off',
+ // allow debugger during development
+ 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
+ 'vue/no-parsing-error': [2, { 'x-invalid-end-tag': false }],
+ 'no-undef': 'off',
+ 'camelcase': 'off'
+ },
+ parserOptions: {
+ parser: 'babel-eslint'
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/.gitignore b/src/JT808.DotNetty.Dashbord.UI/.gitignore
new file mode 100644
index 0000000..2056a84
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/.gitignore
@@ -0,0 +1,26 @@
+.DS_Store
+node_modules
+/dist
+
+/tests/e2e/videos/
+/tests/e2e/screenshots/
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw*
+
+build/env.js
diff --git a/src/JT808.DotNetty.Dashbord.UI/.postcssrc.js b/src/JT808.DotNetty.Dashbord.UI/.postcssrc.js
new file mode 100644
index 0000000..961986e
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/.postcssrc.js
@@ -0,0 +1,5 @@
+module.exports = {
+ plugins: {
+ autoprefixer: {}
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/.travis.yml b/src/JT808.DotNetty.Dashbord.UI/.travis.yml
new file mode 100644
index 0000000..07c971f
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/.travis.yml
@@ -0,0 +1,5 @@
+language: node_js
+node_js: stable
+script: npm run lint
+notifications:
+ email: false
diff --git a/src/JT808.DotNetty.Dashbord.UI/LICENSE b/src/JT808.DotNetty.Dashbord.UI/LICENSE
new file mode 100644
index 0000000..7ec88ac
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 iView
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/src/JT808.DotNetty.Dashbord.UI/README.md b/src/JT808.DotNetty.Dashbord.UI/README.md
new file mode 100644
index 0000000..9945af9
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/README.md
@@ -0,0 +1,187 @@
+
+
+
+
+
+
+# iView Admin
+
+[](https://github.com/iview/iview-admin/releases)
+[](https://travis-ci.org/iview/iview-admin)
+[](https://github.com/vuejs/vue)
+[](https://github.com/iview/iview)
+[]()
+
+[更新日志](https://github.com/iview/iview-admin/releases)
+
+[使用文档](https://lison16.github.io/iview-admin-doc/#/)
+
+[在线访问](https://admin.iviewui.com/)
+
+[简化版模板](https://github.com/iview/iview-admin/tree/template)
+
+[教学视频(26课时)](https://segmentfault.com/ls/1650000016221751?utm_source=banner)
+
+`注:在线版本会在开发版本新小版本发布后更新到相应版本,所以如果想体验最新版本iview-admin,请clone完整项目代码到本地运行。`
+
+## Install
+```bush
+// install dependencies
+npm install
+```
+## Run
+### Development
+```bush
+npm run dev
+```
+### Production(Build)
+```bush
+npm run build
+```
+
+## 简介
+ iView admin是基于Vue.js,搭配使用[iView](https://www.iviewui.com) UI组件库形成的一套后台集成解决方案,由TalkingData前端可视化团队部分成员开发维护。iView admin遵守iView设计和开发约定,风格统一,设计考究,并且更多功能在不停开发中。
+如果您想查看iview-admin的更新动态,您可以到[更新日志](https://github.com/iview/iview-admin/releases)查看了解最新更新;如果您是新手,想快速入手iview-admin,您可以到[使用教程](https://github.com/iview/iview-admin/wiki)查看讲解;如果您想在线体验iview-admin,您可以到[在线访问](https://admin.iviewui.com/)体验。如果你只是想要一个清醒爽朗的界面,那你可以下载[简化版模板](https://github.com/iview/iview-admin/tree/template)来做开发。
+
+## 功能
+
+- 登录/登出
+- 权限管理
+ - 列表过滤
+ - 权限切换
+- 多语言切换
+- 组件
+ - 富文本编辑器
+ - Markdown编辑器
+ - 城市级联
+ - 图片预览编辑
+ - 可拖拽列表
+ - 文件上传
+ - 数字渐变
+ - split-pane
+- 表单编辑
+ - 文章发布
+ - 工作流
+- 表格
+ - 可拖拽排序
+ - 可编辑表格
+ - 行内编辑
+ - 单元格编辑
+ - 可搜索表格
+ - 表格导出数据
+ - 导出为Csv文件
+ - 导出为Xls文件
+ - 表格转图片
+- 错误页面
+ - 403页面
+ - 404页面
+ - 500页面
+- 高级路由
+ - 动态路由
+ - 带参页面
+- 换肤
+- 收缩侧边栏
+- tag标签导航
+- 面包屑导航
+- 全屏/退出全屏
+- 锁屏
+- 消息中心
+- 个人中心
+
+## 文件结构
+```shell
+.
+├── build 项目构建配置
+├── config 开发相关配置
+├── public 打包所需静态资源
+└── src
+ ├── api AJAX请求
+ └── assets 项目静态资源
+ ├── icons 自定义图标资源
+ └── images 图片资源
+ ├── components 业务组件
+ ├── config 项目运行配置
+ ├── directive 自定义指令
+ ├── libs 封装工具函数
+ ├── locale 多语言文件
+ ├── mock mock模拟数据
+ ├── router 路由配置
+ ├── store Vuex配置
+ ├── view 页面文件
+ └── tests 测试相关
+```
+
+## Links
+
+- [TalkingData](https://github.com/TalkingData)
+- [iView](https://github.com/iview/iview)
+- [Vue](https://github.com/vuejs/vue)
+- [Webpack](https://github.com/webpack/webpack)
+
+## 效果展示
+
+- 响应式布局首页
+
+
+- 标签导航
+
+
+- 权限管理
+
+
+- 可拖拽列表
+
+
+- 图片预览编辑
+
+
+- 文件上传
+
+
+- 数字渐变
+
+
+- split-pane
+
+
+- 文章发布
+
+
+- 工作流
+
+
+- 可拖拽表格
+
+
+- 可编辑表格
+
+
+- 表格导出数据
+
+
+- 表格转图片
+
+
+- 错误页面
+
+
+- 锁屏
+
+
+- 可收缩侧边栏
+
+
+- 主题切换
+
+
+- 消息中心
+
+
+### 💖💖 If you find this project helpful, maybe you can buy me a coffee. 💖💖
+
+
+
+## License
+[MIT](http://opensource.org/licenses/MIT)
+
+Copyright (c) 2016-present, iView
diff --git a/src/JT808.DotNetty.Dashbord.UI/public/favicon.ico b/src/JT808.DotNetty.Dashbord.UI/public/favicon.ico
new file mode 100644
index 0000000..97131e9
Binary files /dev/null and b/src/JT808.DotNetty.Dashbord.UI/public/favicon.ico differ
diff --git a/src/JT808.DotNetty.Dashbord.UI/public/index.html b/src/JT808.DotNetty.Dashbord.UI/public/index.html
new file mode 100644
index 0000000..8e8eeaf
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/public/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+ We're sorry but iview-admin doesn't work properly without JavaScript enabled. Please enable it to continue.
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/App.vue b/src/JT808.DotNetty.Dashbord.UI/src/App.vue
new file mode 100644
index 0000000..01c4743
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/App.vue
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/api/atomicCounter.js b/src/JT808.DotNetty.Dashbord.UI/src/api/atomicCounter.js
new file mode 100644
index 0000000..b77eadc
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/api/atomicCounter.js
@@ -0,0 +1,8 @@
+import axios from '@/libs/api.request'
+
+export const GetAtomicCounter = () => {
+ return axios.request({
+ url: 'AtomicCounter/GetAtomicCounter',
+ method: 'get'
+ })
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/api/data.js b/src/JT808.DotNetty.Dashbord.UI/src/api/data.js
new file mode 100644
index 0000000..ca4286a
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/api/data.js
@@ -0,0 +1,37 @@
+import axios from '@/libs/api.request'
+
+export const getTableData = () => {
+ return axios.request({
+ url: 'get_table_data',
+ method: 'get'
+ })
+}
+
+export const getDragList = () => {
+ return axios.request({
+ url: 'get_drag_list',
+ method: 'get'
+ })
+}
+
+export const errorReq = () => {
+ return axios.request({
+ url: 'error_url',
+ method: 'post'
+ })
+}
+
+export const saveErrorLogger = info => {
+ return axios.request({
+ url: 'save_error_logger',
+ data: info,
+ method: 'post'
+ })
+}
+
+export const uploadImg = formData => {
+ return axios.request({
+ url: 'image/upload',
+ data: formData
+ })
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/api/routers.js b/src/JT808.DotNetty.Dashbord.UI/src/api/routers.js
new file mode 100644
index 0000000..04a03a9
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/api/routers.js
@@ -0,0 +1,11 @@
+import axios from '@/libs/api.request'
+
+export const getRouterReq = (access) => {
+ return axios.request({
+ url: 'get_router',
+ params: {
+ access
+ },
+ method: 'get'
+ })
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/api/session.js b/src/JT808.DotNetty.Dashbord.UI/src/api/session.js
new file mode 100644
index 0000000..a6003b6
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/api/session.js
@@ -0,0 +1,22 @@
+import axios from '@/libs/api.request'
+
+export const RemoveByTerminalPhoneNo = (terminalPhoneN) => {
+ return axios.request({
+ url: 'Session/RemoveByTerminalPhoneNo/' + terminalPhoneN,
+ method: 'get'
+ })
+}
+
+export const RemoveByChannelId = (channelId) => {
+ return axios.request({
+ url: 'Session/RemoveByChannelId/' + channelId,
+ method: 'get'
+ })
+}
+
+export const GetAll = () => {
+ return axios.request({
+ url: 'Session/GetAll',
+ method: 'get'
+ })
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/api/sourcePackage.js b/src/JT808.DotNetty.Dashbord.UI/src/api/sourcePackage.js
new file mode 100644
index 0000000..fb449b5
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/api/sourcePackage.js
@@ -0,0 +1,32 @@
+import axios from '@/libs/api.request'
+
+export const Add = ({ Host, Port }) => {
+ const data = {
+ Host,
+ Port
+ }
+ return axios.request({
+ url: 'SourcePackage/Add',
+ data,
+ method: 'post'
+ })
+}
+
+export const Remove = ({ Host, Port }) => {
+ const data = {
+ Host,
+ Port
+ }
+ return axios.request({
+ url: 'SourcePackage/Remove',
+ data,
+ method: 'post'
+ })
+}
+
+export const GetAll = () => {
+ return axios.request({
+ url: 'SourcePackage/GetAll',
+ method: 'get'
+ })
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/api/transmit.js b/src/JT808.DotNetty.Dashbord.UI/src/api/transmit.js
new file mode 100644
index 0000000..dc75362
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/api/transmit.js
@@ -0,0 +1,32 @@
+import axios from '@/libs/api.request'
+
+export const Add = ({ Host, Port }) => {
+ const data = {
+ Host,
+ Port
+ }
+ return axios.request({
+ url: 'Transmit/Add',
+ data,
+ method: 'post'
+ })
+}
+
+export const Remove = ({ Host, Port }) => {
+ const data = {
+ Host,
+ Port
+ }
+ return axios.request({
+ url: 'Transmit/Remove',
+ data,
+ method: 'post'
+ })
+}
+
+export const GetAll = () => {
+ return axios.request({
+ url: 'Transmit/GetAll',
+ method: 'get'
+ })
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/api/unificationSend.js b/src/JT808.DotNetty.Dashbord.UI/src/api/unificationSend.js
new file mode 100644
index 0000000..ea95d65
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/api/unificationSend.js
@@ -0,0 +1,8 @@
+import axios from '@/libs/api.request'
+
+export const SendText = ({ terminalPhoneNo, text }) => {
+ return axios.request({
+ url: 'UnificationSend/SendText/' + terminalPhoneNo + '/' + text,
+ method: 'get'
+ })
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/api/user.js b/src/JT808.DotNetty.Dashbord.UI/src/api/user.js
new file mode 100644
index 0000000..2d6d4d1
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/api/user.js
@@ -0,0 +1,84 @@
+import axios from '@/libs/api.request'
+
+export const login = ({ userName, password }) => {
+ const data = {
+ userName,
+ password
+ }
+ return axios.request({
+ url: 'login',
+ data,
+ method: 'post'
+ })
+}
+
+export const getUserInfo = (token) => {
+ return axios.request({
+ url: 'get_info',
+ params: {
+ token
+ },
+ method: 'get'
+ })
+}
+
+export const logout = (token) => {
+ return axios.request({
+ url: 'logout',
+ method: 'post'
+ })
+}
+
+export const getUnreadCount = () => {
+ return axios.request({
+ url: 'message/count',
+ method: 'get'
+ })
+}
+
+export const getMessage = () => {
+ return axios.request({
+ url: 'message/init',
+ method: 'get'
+ })
+}
+
+export const getContentByMsgId = msg_id => {
+ return axios.request({
+ url: 'message/content',
+ method: 'get',
+ params: {
+ msg_id
+ }
+ })
+}
+
+export const hasRead = msg_id => {
+ return axios.request({
+ url: 'message/has_read',
+ method: 'post',
+ data: {
+ msg_id
+ }
+ })
+}
+
+export const removeReaded = msg_id => {
+ return axios.request({
+ url: 'message/remove_readed',
+ method: 'post',
+ data: {
+ msg_id
+ }
+ })
+}
+
+export const restoreTrash = msg_id => {
+ return axios.request({
+ url: 'message/restore',
+ method: 'post',
+ data: {
+ msg_id
+ }
+ })
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/assets/icons/iconfont.css b/src/JT808.DotNetty.Dashbord.UI/src/assets/icons/iconfont.css
new file mode 100644
index 0000000..80a476c
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/assets/icons/iconfont.css
@@ -0,0 +1,37 @@
+
+@font-face {font-family: "iconfont";
+ src: url('iconfont.eot?t=1541579316141'); /* IE9*/
+ src: url('iconfont.eot?t=1541579316141#iefix') format('embedded-opentype'), /* IE6-IE8 */
+ url('data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAiEAAsAAAAADmgAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADMAAABCsP6z7U9TLzIAAAE8AAAARAAAAFY8eUnXY21hcAAAAYAAAACjAAACLi+YJuBnbHlmAAACJAAABAgAAAcg4dRWHmhlYWQAAAYsAAAAMQAAADYTL8piaGhlYQAABmAAAAAgAAAAJAfdA4xobXR4AAAGgAAAABQAAAAsLAD//2xvY2EAAAaUAAAAGAAAABgImgpGbWF4cAAABqwAAAAfAAAAIAEcAG5uYW1lAAAGzAAAAUUAAAJtPlT+fXBvc3QAAAgUAAAAbgAAAI54roygeJxjYGRgYOBikGPQYWB0cfMJYeBgYGGAAJAMY05meiJQDMoDyrGAaQ4gZoOIAgCKIwNPAHicY2BkYWCcwMDKwMHUyXSGgYGhH0IzvmYwYuRgYGBiYGVmwAoC0lxTGByeMTx/ytzwv4EhhrmBoRkozAiSAwDuUwzMeJzlkUEKwkAMRd/YabXFhQvxFF6qPYPrUujGY7jyIr1JoZNjtMnEhag3MOEN5MMk8D9QAoVyVSKEJwGrh6oh6wVN1iM3nc+cVImJVKdOehlklElmWdYVstp+ql8VdIv15a1NLW0zFXsO7Kjz3erH/3+rY37vr6kxnx1LKNWOJZlaxxJNnWOpSu+ot8jgqMvI6KjfyOSo88jsaAbI4tBsig89rQB4nLVUTWwbRRSeNzO767i2g7N/FP9s7MRrE5ON4/V6rSZyU0PiINSSNImES4IUoapWz6hEiqiMBDQqEojkAkiFStyKRC+9VSoFCeUEyqESVUAqEkcu3OAQb3hrJxAXwSGI3X0/szPz5vvm2x0i7O/vf8IJe5VkSJnUyUtklRBQJE1VIjRtUafkmk6pSu2ipleh4+xikkKxSksWTUeo8m8NoagpYtoslTmxrLl37z64e33esuJjU8P5Wd262LxoPVnPZ06Pxfe+C0YjkhSJygPhQCA8ABPOykwuN7NyuRvgUnAgLEnhATkaCQQiUe/7XKUyV6nQz+t2o7l66+rs7NVbq82GXTdrdjxjRGU5amTids2bUDMFtzCsqsMYMqr3IDY6OT05GjsI8Exv/6CSkOWEQigh+y3clxY5QVTcEZFIGtHLxDUJs6WsHR1y9SFKdr1HggCp3V1ICYL36OOpVmvKN9bC1u6R3vZ0qwWtVovgJfqOfUvfIYxIWL+fyETHNVJqSkIT1JTjW8ZWh3yDJDz0ctvsyt51etvrg9/QHhqGlzMM+vbmizPnDWPLMNbW19e7tffvsBzL99aWEfBRY46t+tbe3PypXv/IMDYN43WsQBe9HL2NC33RuxABrPsG+xH3o4bVRE2KgCRqulbWNf8W/UYVHM129aKra24VshZkq+CWD/Oy6Xt8cGYEthgHVlVliCfynAlqjo6oysTKlYUAD4docMI5/1ZioN+GwZNBcTwWUmTdBUqhTwX29QebXzF4An4JJMzwfMl+WQ01+IlQZVR4yhie53ycA16pOI/ODiYNGK4MChdCgXNnX5gIJXPCSYnf2OF850aQ+zJIyOs+u8+mMO8jQdwtg1TIWVRjKAnFcslMi8KfGUPoSUCergUyUk77dMyS69Ms6tijKZKYwUGKbpfdzu+iYeZYAHMFiOVi+MD7h9mb99qC0L7X8c+XatMfTj97KZ5IxJt/pd43tYYQKEjAnXMOB6kQEBrwg+LPjindAPOHNdC3q3ait0I3/ZIunZEARLNYNEUA6czSP3N/7j9wz6ZESdX0VNl1zGNS/szbQaQSIGk4DtVPcZf8AgXpf9A2OyTit5s2syZmand46bhEe2WtodLHkvaoqtTXuXN2/c42WADP9HGfbUcUW7JgqHss4xHtlMys679FqUomdP9VJBQBdnlPABBubpuNwqnmQj6/0HwNQzKxDUJFgKiXurBG6dqFjmeBzsvtRPJgGIZThYa5fdOvsReOticPh6JHHXxsv7ItJpOniYPYsmZ/x0QD/o5P105DeQwF6MH33ogoLi+KQp7zpY3HQV5bFMURzheXeds7gpP+jKNXljjHuYvXHke7cdCxLLZf6YX7B63UcCV4nGNgZGBgAOKAN2ZR8fw2Xxm4WRhA4AbHYRMY/f///1oWBuYGIJeDgQkkCgAvWgs2AAAAeJxjYGRgYG7438AQw8Lw/z8DAwsDA1AEBXADAHXiBHJ4nGNhYGBgYfj/nwVM48cATwECKwAAAAAAjAC6AOgBFAGAAf4CbgLqAzgDkHicY2BkYGDgZkhiYGcAASYg5gJCBob/YD4DABOmAYsAeJxlj01OwzAQhV/6B6QSqqhgh+QFYgEo/RGrblhUavdddN+mTpsqiSPHrdQDcB6OwAk4AtyAO/BIJ5s2lsffvHljTwDc4Acejt8t95E9XDI7cg0XuBeuU38QbpBfhJto41W4Rf1N2MczpsJtdGF5g9e4YvaEd2EPHXwI13CNT+E69S/hBvlbuIk7/Aq30PHqwj7mXle4jUcv9sdWL5xeqeVBxaHJIpM5v4KZXu+Sha3S6pxrW8QmU4OgX0lTnWlb3VPs10PnIhVZk6oJqzpJjMqt2erQBRvn8lGvF4kehCblWGP+tsYCjnEFhSUOjDFCGGSIyujoO1Vm9K+xQ8Jee1Y9zed0WxTU/3OFAQL0z1xTurLSeTpPgT1fG1J1dCtuy56UNJFezUkSskJe1rZUQuoBNmVXjhF6XNGJPyhnSP8ACVpuyAAAAHicbYhdDoIwEAb3a6k/YIIX8VArWewmdJFWJOnpJTG+OQ+TzJCjLy39p4ODR4OAA4444YwWHS7U3IVzn6Voldtb8ksHnvohrlqjjmw1rmzXsvdT7fEbblnCmOfNfJIYStJJfGIL27yb6AOCGR89AAA=') format('woff'),
+ url('iconfont.ttf?t=1541579316141') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
+ url('iconfont.svg?t=1541579316141#iconfont') format('svg'); /* iOS 4.1- */
+}
+
+.iconfont {
+ font-family:"iconfont" !important;
+ font-size:16px;
+ font-style:normal;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-bear:before { content: "\e600"; }
+
+.icon-resize-vertical:before { content: "\e7c3"; }
+
+.icon-chuizhifanzhuan:before { content: "\e661"; }
+
+.icon-shuipingfanzhuan:before { content: "\e662"; }
+
+.icon-qq:before { content: "\e609"; }
+
+.icon-frown:before { content: "\e77e"; }
+
+.icon-meh:before { content: "\e780"; }
+
+.icon-smile:before { content: "\e783"; }
+
+.icon-man:before { content: "\e7e2"; }
+
+.icon-woman:before { content: "\e7e5"; }
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/assets/icons/iconfont.eot b/src/JT808.DotNetty.Dashbord.UI/src/assets/icons/iconfont.eot
new file mode 100644
index 0000000..045499d
Binary files /dev/null and b/src/JT808.DotNetty.Dashbord.UI/src/assets/icons/iconfont.eot differ
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/assets/icons/iconfont.svg b/src/JT808.DotNetty.Dashbord.UI/src/assets/icons/iconfont.svg
new file mode 100644
index 0000000..6aa3270
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/assets/icons/iconfont.svg
@@ -0,0 +1,56 @@
+
+
+
+
+
+Created by iconfont
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/assets/icons/iconfont.ttf b/src/JT808.DotNetty.Dashbord.UI/src/assets/icons/iconfont.ttf
new file mode 100644
index 0000000..0c557de
Binary files /dev/null and b/src/JT808.DotNetty.Dashbord.UI/src/assets/icons/iconfont.ttf differ
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/assets/icons/iconfont.woff b/src/JT808.DotNetty.Dashbord.UI/src/assets/icons/iconfont.woff
new file mode 100644
index 0000000..105adab
Binary files /dev/null and b/src/JT808.DotNetty.Dashbord.UI/src/assets/icons/iconfont.woff differ
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/assets/images/error-page/error-401.svg b/src/JT808.DotNetty.Dashbord.UI/src/assets/images/error-page/error-401.svg
new file mode 100644
index 0000000..19e2f9f
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/assets/images/error-page/error-401.svg
@@ -0,0 +1 @@
+tasting
\ No newline at end of file
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/assets/images/error-page/error-404.svg b/src/JT808.DotNetty.Dashbord.UI/src/assets/images/error-page/error-404.svg
new file mode 100644
index 0000000..77d97f7
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/assets/images/error-page/error-404.svg
@@ -0,0 +1 @@
+drone_delivery
\ No newline at end of file
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/assets/images/error-page/error-500.svg b/src/JT808.DotNetty.Dashbord.UI/src/assets/images/error-page/error-500.svg
new file mode 100644
index 0000000..ef72fd3
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/assets/images/error-page/error-500.svg
@@ -0,0 +1 @@
+co-working
\ No newline at end of file
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/assets/images/login-bg.jpg b/src/JT808.DotNetty.Dashbord.UI/src/assets/images/login-bg.jpg
new file mode 100644
index 0000000..94b8f51
Binary files /dev/null and b/src/JT808.DotNetty.Dashbord.UI/src/assets/images/login-bg.jpg differ
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/assets/images/logo-min.jpg b/src/JT808.DotNetty.Dashbord.UI/src/assets/images/logo-min.jpg
new file mode 100644
index 0000000..18abf21
Binary files /dev/null and b/src/JT808.DotNetty.Dashbord.UI/src/assets/images/logo-min.jpg differ
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/assets/images/logo.jpg b/src/JT808.DotNetty.Dashbord.UI/src/assets/images/logo.jpg
new file mode 100644
index 0000000..11638b3
Binary files /dev/null and b/src/JT808.DotNetty.Dashbord.UI/src/assets/images/logo.jpg differ
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/assets/images/qq-group1.jpg b/src/JT808.DotNetty.Dashbord.UI/src/assets/images/qq-group1.jpg
new file mode 100644
index 0000000..3e6dd60
Binary files /dev/null and b/src/JT808.DotNetty.Dashbord.UI/src/assets/images/qq-group1.jpg differ
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/assets/images/qq-group2.jpg b/src/JT808.DotNetty.Dashbord.UI/src/assets/images/qq-group2.jpg
new file mode 100644
index 0000000..526b081
Binary files /dev/null and b/src/JT808.DotNetty.Dashbord.UI/src/assets/images/qq-group2.jpg differ
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/assets/images/talkingdata.png b/src/JT808.DotNetty.Dashbord.UI/src/assets/images/talkingdata.png
new file mode 100644
index 0000000..87ad50e
Binary files /dev/null and b/src/JT808.DotNetty.Dashbord.UI/src/assets/images/talkingdata.png differ
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/charts/bar.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/charts/bar.vue
new file mode 100644
index 0000000..b0a2709
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/charts/bar.vue
@@ -0,0 +1,58 @@
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/charts/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/charts/index.js
new file mode 100644
index 0000000..2ca3c91
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/charts/index.js
@@ -0,0 +1,3 @@
+import ChartPie from './pie.vue'
+import ChartBar from './bar.vue'
+export { ChartPie, ChartBar }
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/charts/pie.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/charts/pie.vue
new file mode 100644
index 0000000..c86d68c
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/charts/pie.vue
@@ -0,0 +1,70 @@
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/common-icon/common-icon.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/common-icon/common-icon.vue
new file mode 100644
index 0000000..768fa1b
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/common-icon/common-icon.vue
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/common-icon/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/common-icon/index.js
new file mode 100644
index 0000000..1207d15
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/common-icon/index.js
@@ -0,0 +1,2 @@
+import CommonIcon from './common-icon.vue'
+export default CommonIcon
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/common/common.less b/src/JT808.DotNetty.Dashbord.UI/src/components/common/common.less
new file mode 100644
index 0000000..3c3e5b1
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/common/common.less
@@ -0,0 +1,8 @@
+.no-select{
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/common/util.js b/src/JT808.DotNetty.Dashbord.UI/src/components/common/util.js
new file mode 100644
index 0000000..2129e7a
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/common/util.js
@@ -0,0 +1,3 @@
+export const showTitle = (item, vm) => {
+ return vm.$config.useI18n ? vm.$t(item.name) : ((item.meta && item.meta.title) || item.name)
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/count-to/count-to.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/count-to/count-to.vue
new file mode 100644
index 0000000..a10e3ff
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/count-to/count-to.vue
@@ -0,0 +1,174 @@
+
+
+
+
{{ init }} {{ unitText }}
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/count-to/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/count-to/index.js
new file mode 100644
index 0000000..17b3332
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/count-to/index.js
@@ -0,0 +1,2 @@
+import countTo from './count-to.vue'
+export default countTo
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/count-to/index.less b/src/JT808.DotNetty.Dashbord.UI/src/components/count-to/index.less
new file mode 100644
index 0000000..e17d7c6
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/count-to/index.less
@@ -0,0 +1,10 @@
+@prefix: ~"count-to";
+
+.@{prefix}-wrapper{
+ .content-outer{
+ display: inline-block;
+ .@{prefix}-unit-text{
+ font-style: normal;
+ }
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/cropper/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/cropper/index.js
new file mode 100644
index 0000000..e7db5ea
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/cropper/index.js
@@ -0,0 +1,2 @@
+import Cropper from './index.vue'
+export default Cropper
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/cropper/index.less b/src/JT808.DotNetty.Dashbord.UI/src/components/cropper/index.less
new file mode 100644
index 0000000..cdf431d
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/cropper/index.less
@@ -0,0 +1,35 @@
+.bg{
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC")
+}
+.cropper-wrapper{
+ width: 600px;
+ height: 340px;
+ .img-box{
+ height: 340px;
+ width: 430px;
+ border: 1px solid #ebebeb;
+ display: inline-block;
+ .bg;
+ img{
+ max-width: 100%;
+ display: block;
+ }
+ }
+ .right-con{
+ display: inline-block;
+ width: 170px;
+ vertical-align: top;
+ box-sizing: border-box;
+ padding: 0 10px;
+ .preview-box{
+ height: 150px !important;
+ width: 100% !important;
+ overflow: hidden;
+ border: 1px solid #ebebeb;
+ .bg;
+ }
+ .button-box{
+ padding: 10px 0 0;
+ }
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/cropper/index.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/cropper/index.vue
new file mode 100644
index 0000000..7bb664f
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/cropper/index.vue
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/drag-list/drag-list.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/drag-list/drag-list.vue
new file mode 100644
index 0000000..664abc9
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/drag-list/drag-list.vue
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+ {{ itemLeft }}
+
+
+
+
+
+
+
+ {{ itemRight }}
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/drag-list/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/drag-list/index.js
new file mode 100644
index 0000000..d2bb972
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/drag-list/index.js
@@ -0,0 +1,2 @@
+import DragList from './drag-list.vue'
+export default DragList
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/editor/editor.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/editor/editor.vue
new file mode 100644
index 0000000..881c73e
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/editor/editor.vue
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/editor/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/editor/index.js
new file mode 100644
index 0000000..56e8de2
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/editor/index.js
@@ -0,0 +1,2 @@
+import Editor from './editor.vue'
+export default Editor
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/icons/icons.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/icons/icons.vue
new file mode 100644
index 0000000..50b7183
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/icons/icons.vue
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/icons/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/icons/index.js
new file mode 100644
index 0000000..bdc38b2
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/icons/index.js
@@ -0,0 +1,2 @@
+import Icons from './icons.vue'
+export default Icons
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/info-card/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/info-card/index.js
new file mode 100644
index 0000000..354419b
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/info-card/index.js
@@ -0,0 +1,2 @@
+import InforCard from './infor-card.vue'
+export default InforCard
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/info-card/infor-card.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/info-card/infor-card.vue
new file mode 100644
index 0000000..6240d0e
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/info-card/infor-card.vue
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/login-form/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/login-form/index.js
new file mode 100644
index 0000000..d480c28
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/login-form/index.js
@@ -0,0 +1,2 @@
+import LoginForm from './login-form.vue'
+export default LoginForm
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/login-form/login-form.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/login-form/login-form.vue
new file mode 100644
index 0000000..497c08c
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/login-form/login-form.vue
@@ -0,0 +1,72 @@
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/a-back-top/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/a-back-top/index.js
new file mode 100644
index 0000000..4da0014
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/a-back-top/index.js
@@ -0,0 +1,2 @@
+import ABackTop from './index.vue'
+export default ABackTop
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/a-back-top/index.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/a-back-top/index.vue
new file mode 100644
index 0000000..f26f95c
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/a-back-top/index.vue
@@ -0,0 +1,90 @@
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/error-store/error-store.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/error-store/error-store.vue
new file mode 100644
index 0000000..9941677
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/error-store/error-store.vue
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/error-store/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/error-store/index.js
new file mode 100644
index 0000000..a777df1
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/error-store/index.js
@@ -0,0 +1,2 @@
+import ErrorStore from './error-store.vue'
+export default ErrorStore
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/fullscreen/fullscreen.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/fullscreen/fullscreen.vue
new file mode 100644
index 0000000..d5213fa
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/fullscreen/fullscreen.vue
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/fullscreen/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/fullscreen/index.js
new file mode 100644
index 0000000..422c7c1
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/fullscreen/index.js
@@ -0,0 +1,2 @@
+import Fullscreen from './fullscreen.vue'
+export default Fullscreen
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.less b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.less
new file mode 100644
index 0000000..1ace1eb
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.less
@@ -0,0 +1,4 @@
+.custom-bread-crumb{
+ display: inline-block;
+ vertical-align: top;
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.vue
new file mode 100644
index 0000000..51b121d
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.vue
@@ -0,0 +1,46 @@
+
+
+
+
+
+ {{ showTitle(item) }}
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/custom-bread-crumb/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/custom-bread-crumb/index.js
new file mode 100644
index 0000000..a590fe0
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/custom-bread-crumb/index.js
@@ -0,0 +1,2 @@
+import customBreadCrumb from './custom-bread-crumb.vue'
+export default customBreadCrumb
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/header-bar.less b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/header-bar.less
new file mode 100644
index 0000000..c245d19
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/header-bar.less
@@ -0,0 +1,14 @@
+.header-bar{
+ width: 100%;
+ height: 100%;
+ position: relative;
+ .custom-content-con{
+ float: right;
+ height: auto;
+ padding-right: 20px;
+ line-height: 64px;
+ & > *{
+ float: right;
+ }
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/header-bar.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/header-bar.vue
new file mode 100644
index 0000000..1452146
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/header-bar.vue
@@ -0,0 +1,34 @@
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/index.js
new file mode 100644
index 0000000..3d4a170
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/index.js
@@ -0,0 +1,2 @@
+import HeaderBar from './header-bar'
+export default HeaderBar
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/sider-trigger/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/sider-trigger/index.js
new file mode 100644
index 0000000..15853f4
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/sider-trigger/index.js
@@ -0,0 +1,2 @@
+import siderTrigger from './sider-trigger.vue'
+export default siderTrigger
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/sider-trigger/sider-trigger.less b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/sider-trigger/sider-trigger.less
new file mode 100644
index 0000000..eb50999
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/sider-trigger/sider-trigger.less
@@ -0,0 +1,21 @@
+.trans{
+ transition: transform .2s ease;
+}
+@size: 40px;
+.sider-trigger-a{
+ padding: 6px;
+ width: @size;
+ height: @size;
+ display: inline-block;
+ text-align: center;
+ color: #5c6b77;
+ margin-top: 12px;
+ i{
+ .trans;
+ vertical-align: top;
+ }
+ &.collapsed i{
+ transform: rotateZ(90deg);
+ .trans;
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/sider-trigger/sider-trigger.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/sider-trigger/sider-trigger.vue
new file mode 100644
index 0000000..200e18f
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/header-bar/sider-trigger/sider-trigger.vue
@@ -0,0 +1,27 @@
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/language/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/language/index.js
new file mode 100644
index 0000000..de2a90a
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/language/index.js
@@ -0,0 +1,2 @@
+import Language from './language.vue'
+export default Language
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/language/language.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/language/language.vue
new file mode 100644
index 0000000..b1d92ec
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/language/language.vue
@@ -0,0 +1,51 @@
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/side-menu/collapsed-menu.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/side-menu/collapsed-menu.vue
new file mode 100644
index 0000000..73ac93e
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/side-menu/collapsed-menu.vue
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/side-menu/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/side-menu/index.js
new file mode 100644
index 0000000..5b36868
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/side-menu/index.js
@@ -0,0 +1,2 @@
+import SideMenu from './side-menu.vue'
+export default SideMenu
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/side-menu/item-mixin.js b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/side-menu/item-mixin.js
new file mode 100644
index 0000000..8b807af
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/side-menu/item-mixin.js
@@ -0,0 +1,21 @@
+export default {
+ props: {
+ parentItem: {
+ type: Object,
+ default: () => {}
+ },
+ theme: String,
+ iconSize: Number
+ },
+ computed: {
+ parentName () {
+ return this.parentItem.name
+ },
+ children () {
+ return this.parentItem.children
+ },
+ textColor () {
+ return this.theme === 'dark' ? '#fff' : '#495060'
+ }
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/side-menu/mixin.js b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/side-menu/mixin.js
new file mode 100644
index 0000000..21b618b
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/side-menu/mixin.js
@@ -0,0 +1,18 @@
+import CommonIcon from '_c/common-icon'
+import { showTitle } from '@/libs/util'
+export default {
+ components: {
+ CommonIcon
+ },
+ methods: {
+ showTitle (item) {
+ return showTitle(item, this)
+ },
+ showChildren (item) {
+ return item.children && (item.children.length > 1 || (item.meta && item.meta.showAlways))
+ },
+ getNameOrHref (item, children0) {
+ return item.href ? `isTurnByHref_${item.href}` : (children0 ? item.children[0].name : item.name)
+ }
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/side-menu/side-menu-item.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/side-menu/side-menu-item.vue
new file mode 100644
index 0000000..12338a6
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/side-menu/side-menu-item.vue
@@ -0,0 +1,26 @@
+
+
+
+
+ {{ showTitle(parentItem) }}
+
+
+
+
+ {{ showTitle(item.children[0]) }}
+
+
+
+ {{ showTitle(item) }}
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/side-menu/side-menu.less b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/side-menu/side-menu.less
new file mode 100644
index 0000000..4716d82
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/side-menu/side-menu.less
@@ -0,0 +1,40 @@
+.side-menu-wrapper{
+ user-select: none;
+ .menu-collapsed{
+ padding-top: 10px;
+
+ .ivu-dropdown{
+ width: 100%;
+ .ivu-dropdown-rel a{
+ width: 100%;
+ }
+ }
+ .ivu-tooltip{
+ width: 100%;
+ .ivu-tooltip-rel{
+ width: 100%;
+ }
+ .ivu-tooltip-popper .ivu-tooltip-content{
+ .ivu-tooltip-arrow{
+ border-right-color: #fff;
+ }
+ .ivu-tooltip-inner{
+ background: #fff;
+ color: #495060;
+ }
+ }
+ }
+
+
+ }
+ a.drop-menu-a{
+ display: inline-block;
+ padding: 6px 15px;
+ width: 100%;
+ text-align: center;
+ color: #495060;
+ }
+}
+.menu-title{
+ padding-left: 6px;
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/side-menu/side-menu.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/side-menu/side-menu.vue
new file mode 100644
index 0000000..ee18e86
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/side-menu/side-menu.vue
@@ -0,0 +1,114 @@
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/tags-nav/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/tags-nav/index.js
new file mode 100644
index 0000000..585792a
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/tags-nav/index.js
@@ -0,0 +1,2 @@
+import TagsNav from './tags-nav.vue'
+export default TagsNav
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/tags-nav/tags-nav.less b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/tags-nav/tags-nav.less
new file mode 100644
index 0000000..a4c8c5d
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/tags-nav/tags-nav.less
@@ -0,0 +1,87 @@
+.no-select{
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+.size{
+ width: 100%;
+ height: 100%;
+}
+.tags-nav{
+ position: relative;
+ border-top: 1px solid #F0F0F0;
+ border-bottom: 1px solid #F0F0F0;
+ .no-select;
+ .size;
+ .close-con{
+ position: absolute;
+ right: 0;
+ top: 0;
+ height: 100%;
+ width: 32px;
+ background: #fff;
+ text-align: center;
+ z-index: 10;
+ }
+ .btn-con{
+ position: absolute;
+ top: 0px;
+ height: 100%;
+ background: #fff;
+ padding-top: 3px;
+ z-index: 10;
+ button{
+ padding: 6px 4px;
+ line-height: 14px;
+ text-align: center;
+ }
+ &.left-btn{
+ left: 0px;
+ }
+ &.right-btn{
+ right: 32px;
+ border-right: 1px solid #F0F0F0;
+ }
+ }
+ .scroll-outer{
+ position: absolute;
+ left: 28px;
+ right: 61px;
+ top: 0;
+ bottom: 0;
+ box-shadow: 0px 0 3px 2px rgba(100,100,100,.1) inset;
+ .scroll-body{
+ height: ~"calc(100% - 1px)";
+ display: inline-block;
+ padding: 1px 4px 0;
+ position: absolute;
+ overflow: visible;
+ white-space: nowrap;
+ transition: left .3s ease;
+ .ivu-tag-dot-inner{
+ transition: background .2s ease;
+ }
+ }
+ }
+ .contextmenu {
+ position: absolute;
+ margin: 0;
+ padding: 5px 0;
+ background: #fff;
+ z-index: 100;
+ list-style-type: none;
+ border-radius: 4px;
+ box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
+ li {
+ margin: 0;
+ padding: 5px 15px;
+ cursor: pointer;
+ &:hover {
+ background: #eee;
+ }
+ }
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/tags-nav/tags-nav.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/tags-nav/tags-nav.vue
new file mode 100644
index 0000000..2dbca44
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/tags-nav/tags-nav.vue
@@ -0,0 +1,209 @@
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/user/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/user/index.js
new file mode 100644
index 0000000..3d04a5c
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/user/index.js
@@ -0,0 +1,2 @@
+import User from './user.vue'
+export default User
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/user/user.less b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/user/user.less
new file mode 100644
index 0000000..a3c95af
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/user/user.less
@@ -0,0 +1,12 @@
+.user{
+ &-avator-dropdown{
+ cursor: pointer;
+ display: inline-block;
+ // height: 64px;
+ vertical-align: middle;
+ // line-height: 64px;
+ .ivu-badge-dot{
+ top: 16px;
+ }
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/user/user.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/user/user.vue
new file mode 100644
index 0000000..3d4689d
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/components/user/user.vue
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+ 消息中心
+
+ 退出登录
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/main/index.js
new file mode 100644
index 0000000..7df2a08
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/index.js
@@ -0,0 +1,2 @@
+import Main from './main.vue'
+export default Main
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/main.less b/src/JT808.DotNetty.Dashbord.UI/src/components/main/main.less
new file mode 100644
index 0000000..fd0cd41
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/main.less
@@ -0,0 +1,75 @@
+.main{
+ .logo-con{
+ height: 64px;
+ padding: 10px;
+ img{
+ height: 44px;
+ width: auto;
+ display: block;
+ margin: 0 auto;
+ }
+ }
+ .header-con{
+ background: #fff;
+ padding: 0 20px;
+ width: 100%;
+ }
+ .main-layout-con{
+ height: 100%;
+ overflow: hidden;
+ }
+ .main-content-con{
+ height: ~"calc(100% - 60px)";
+ overflow: hidden;
+ }
+ .tag-nav-wrapper{
+ padding: 0;
+ height:40px;
+ background:#F0F0F0;
+ }
+ .content-wrapper{
+ padding: 18px;
+ height: ~"calc(100% - 80px)";
+ overflow: auto;
+ }
+ .left-sider{
+ .ivu-layout-sider-children{
+ overflow-y: scroll;
+ margin-right: -18px;
+ }
+ }
+}
+.ivu-menu-item > i{
+ margin-right: 12px !important;
+}
+.ivu-menu-submenu > .ivu-menu > .ivu-menu-item > i {
+ margin-right: 8px !important;
+}
+.collased-menu-dropdown{
+ width: 100%;
+ margin: 0;
+ line-height: normal;
+ padding: 7px 0 6px 16px;
+ clear: both;
+ font-size: 12px !important;
+ white-space: nowrap;
+ list-style: none;
+ cursor: pointer;
+ transition: background 0.2s ease-in-out;
+ &:hover{
+ background: rgba(100, 100, 100, 0.1);
+ }
+ & * {
+ color: #515a6e;
+ }
+ .ivu-menu-item > i{
+ margin-right: 12px !important;
+ }
+ .ivu-menu-submenu > .ivu-menu > .ivu-menu-item > i {
+ margin-right: 8px !important;
+ }
+}
+
+.ivu-select-dropdown.ivu-dropdown-transfer{
+ max-height: 400px;
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/main/main.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/main/main.vue
new file mode 100644
index 0000000..3c1603f
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/main/main.vue
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/markdown/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/markdown/index.js
new file mode 100644
index 0000000..99e0cda
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/markdown/index.js
@@ -0,0 +1,2 @@
+import MarkdownEditor from './markdown.vue'
+export default MarkdownEditor
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/markdown/markdown.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/markdown/markdown.vue
new file mode 100644
index 0000000..242b3cc
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/markdown/markdown.vue
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/parent-view/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/parent-view/index.js
new file mode 100644
index 0000000..a959c65
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/parent-view/index.js
@@ -0,0 +1,2 @@
+import ParentView from './parent-view.vue'
+export default ParentView
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/parent-view/parent-view.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/parent-view/parent-view.vue
new file mode 100644
index 0000000..84259f3
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/parent-view/parent-view.vue
@@ -0,0 +1,20 @@
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/paste-editor/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/paste-editor/index.js
new file mode 100644
index 0000000..f02331a
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/paste-editor/index.js
@@ -0,0 +1,2 @@
+import PasteEditor from './paste-editor.vue'
+export default PasteEditor
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/paste-editor/paste-editor.less b/src/JT808.DotNetty.Dashbord.UI/src/components/paste-editor/paste-editor.less
new file mode 100644
index 0000000..2ffd2bd
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/paste-editor/paste-editor.less
@@ -0,0 +1,26 @@
+.paste-editor-wrapper{
+ width: 100%;
+ height: 100%;
+ border: 1px dashed gainsboro;
+ textarea.textarea-el{
+ width: 100%;
+ height: 100%;
+ }
+ .CodeMirror{
+ height: 100%;
+ padding: 0;
+ .CodeMirror-code div .CodeMirror-line > span > span.cm-tab{
+ &::after{
+ content: '→';
+ color: #BFBFBF;
+ }
+ }
+ }
+ .first-row{
+ font-weight: 700;
+ font-size: 14px;
+ }
+ .incorrect-row{
+ background: #F5CBD1;
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/paste-editor/paste-editor.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/paste-editor/paste-editor.vue
new file mode 100644
index 0000000..083d6c4
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/paste-editor/paste-editor.vue
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/paste-editor/plugins/placeholder.js b/src/JT808.DotNetty.Dashbord.UI/src/components/paste-editor/plugins/placeholder.js
new file mode 100644
index 0000000..d9bf77e
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/paste-editor/plugins/placeholder.js
@@ -0,0 +1,58 @@
+export default (codemirror) => {
+ (function (mod) {
+ mod(codemirror)
+ })(function (CodeMirror) {
+ CodeMirror.defineOption('placeholder', '', function (cm, val, old) {
+ var prev = old && old !== CodeMirror.Init
+ if (val && !prev) {
+ cm.on('blur', onBlur)
+ cm.on('change', onChange)
+ cm.on('swapDoc', onChange)
+ onChange(cm)
+ } else if (!val && prev) {
+ cm.off('blur', onBlur)
+ cm.off('change', onChange)
+ cm.off('swapDoc', onChange)
+ clearPlaceholder(cm)
+ var wrapper = cm.getWrapperElement()
+ wrapper.className = wrapper.className.replace(' CodeMirror-empty', '')
+ }
+
+ if (val && !cm.hasFocus()) onBlur(cm)
+ })
+
+ function clearPlaceholder (cm) {
+ if (cm.state.placeholder) {
+ cm.state.placeholder.parentNode.removeChild(cm.state.placeholder)
+ cm.state.placeholder = null
+ }
+ }
+ function setPlaceholder (cm) {
+ clearPlaceholder(cm)
+ var elt = cm.state.placeholder = document.createElement('pre')
+ elt.style.cssText = 'height: 0; overflow: visible; color: #80848f;'
+ elt.style.direction = cm.getOption('direction')
+ elt.className = 'CodeMirror-placeholder'
+ var placeHolder = cm.getOption('placeholder')
+ if (typeof placeHolder === 'string') placeHolder = document.createTextNode(placeHolder)
+ elt.appendChild(placeHolder)
+ cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild)
+ }
+
+ function onBlur (cm) {
+ if (isEmpty(cm)) setPlaceholder(cm)
+ }
+ function onChange (cm) {
+ let wrapper = cm.getWrapperElement()
+ let empty = isEmpty(cm)
+ wrapper.className = wrapper.className.replace(' CodeMirror-empty', '') + (empty ? ' CodeMirror-empty' : '')
+
+ if (empty) setPlaceholder(cm)
+ else clearPlaceholder(cm)
+ }
+
+ function isEmpty (cm) {
+ return (cm.lineCount() === 1) && (cm.getLine(0) === '')
+ }
+ })
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/split-pane/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/split-pane/index.js
new file mode 100644
index 0000000..f5ed60e
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/split-pane/index.js
@@ -0,0 +1,2 @@
+import Split from './split.vue'
+export default Split
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/split-pane/index.less b/src/JT808.DotNetty.Dashbord.UI/src/components/split-pane/index.less
new file mode 100644
index 0000000..2583d90
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/split-pane/index.less
@@ -0,0 +1,114 @@
+@split-prefix-cls: ~"ivu-split";
+@box-shadow: 0 0 4px 0 rgba(28, 36, 56, 0.4);
+@trigger-bar-background: rgba(23, 35, 61, 0.25);
+@trigger-background: #F8F8F9;
+@trigger-width: 6px;
+@trigger-bar-width: 4px;
+@trigger-bar-offset: (@trigger-width - @trigger-bar-width) / 2;
+@trigger-bar-interval: 3px;
+@trigger-bar-weight: 1px;
+@trigger-bar-con-height: (@trigger-bar-weight + @trigger-bar-interval) * 8;
+
+.@{split-prefix-cls}{
+ &-wrapper{
+ position: relative;
+ width: 100%;
+ height: 100%;
+ }
+ &-pane{
+ position: absolute;
+ &.left-pane, &.right-pane{
+ top: 0px;
+ bottom: 0px;
+ }
+ &.left-pane{
+ left: 0px;
+ }
+ &.right-pane{
+ right: 0px;
+ }
+ &.top-pane, &.bottom-pane{
+ left: 0px;
+ right: 0px;
+ }
+ &.top-pane{
+ top: 0px;
+ }
+ &.bottom-pane{
+ bottom: 0px;
+ }
+ }
+ &-trigger{
+ &-con{
+ position: absolute;
+ transform: translate(-50%, -50%);
+ z-index: 10;
+ }
+ &-bar-con{
+ position: absolute;
+ overflow: hidden;
+ &.vertical{
+ left: @trigger-bar-offset;
+ top: 50%;
+ height: @trigger-bar-con-height;
+ transform: translate(0, -50%);
+ }
+ &.horizontal{
+ left: 50%;
+ top: @trigger-bar-offset;
+ width: @trigger-bar-con-height;
+ transform: translate(-50%, 0);
+ }
+ }
+ &-vertical{
+ width: @trigger-width;
+ height: 100%;
+ background: @trigger-background;
+ box-shadow: @box-shadow;
+ cursor: col-resize;
+ .@{split-prefix-cls}-trigger-bar{
+ width: @trigger-bar-width;
+ height: 1px;
+ background: @trigger-bar-background;
+ float: left;
+ margin-top: @trigger-bar-interval;
+ }
+ }
+ &-horizontal{
+ height: @trigger-width;
+ width: 100%;
+ background: @trigger-background;
+ box-shadow: @box-shadow;
+ cursor: row-resize;
+ .@{split-prefix-cls}-trigger-bar{
+ height: @trigger-bar-width;
+ width: 1px;
+ background: @trigger-bar-background;
+ float: left;
+ margin-right: @trigger-bar-interval;
+ }
+ }
+ }
+ &-horizontal{
+ .@{split-prefix-cls}-trigger-con{
+ top: 50%;
+ height: 100%;
+ width: 0;
+ }
+ }
+ &-vertical{
+ .@{split-prefix-cls}-trigger-con{
+ left: 50%;
+ height: 0;
+ width: 100%;
+ }
+ }
+ .no-select{
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/split-pane/split.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/split-pane/split.vue
new file mode 100644
index 0000000..409982e
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/split-pane/split.vue
@@ -0,0 +1,158 @@
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/split-pane/trigger.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/split-pane/trigger.vue
new file mode 100644
index 0000000..9abdf03
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/split-pane/trigger.vue
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/tables/edit.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/tables/edit.vue
new file mode 100644
index 0000000..e1066ef
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/tables/edit.vue
@@ -0,0 +1,73 @@
+
+
+
+ {{ value }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/tables/handle-btns.js b/src/JT808.DotNetty.Dashbord.UI/src/components/tables/handle-btns.js
new file mode 100644
index 0000000..551b2e3
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/tables/handle-btns.js
@@ -0,0 +1,33 @@
+const btns = {
+ delete: (h, params, vm) => {
+ return h('Poptip', {
+ props: {
+ confirm: true,
+ title: '你确定要删除吗?'
+ },
+ on: {
+ 'on-ok': () => {
+ vm.$emit('on-delete', params)
+ vm.$emit('input', params.tableData.filter((item, index) => index !== params.row.initRowIndex))
+ }
+ }
+ }, [
+ h('Button', {
+ props: {
+ type: 'text',
+ ghost: true
+ }
+ }, [
+ h('Icon', {
+ props: {
+ type: 'md-trash',
+ size: 18,
+ color: '#000000'
+ }
+ })
+ ])
+ ])
+ }
+}
+
+export default btns
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/tables/index.js b/src/JT808.DotNetty.Dashbord.UI/src/components/tables/index.js
new file mode 100644
index 0000000..4dabfab
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/tables/index.js
@@ -0,0 +1,2 @@
+import Tables from './tables.vue'
+export default Tables
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/tables/index.less b/src/JT808.DotNetty.Dashbord.UI/src/components/tables/index.less
new file mode 100644
index 0000000..3c352e1
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/tables/index.less
@@ -0,0 +1,17 @@
+.search-con{
+ padding: 10px 0;
+ .search{
+ &-col{
+ display: inline-block;
+ width: 200px;
+ }
+ &-input{
+ display: inline-block;
+ width: 200px;
+ margin-left: 2px;
+ }
+ &-btn{
+ margin-left: 2px;
+ }
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/components/tables/tables.vue b/src/JT808.DotNetty.Dashbord.UI/src/components/tables/tables.vue
new file mode 100644
index 0000000..fa2c235
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/components/tables/tables.vue
@@ -0,0 +1,277 @@
+
+
+
+
+ {{ item.title }}
+
+
+ 搜索
+
+
+
+
+ {{ item.title }}
+
+
+ 搜索
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/config/index.js b/src/JT808.DotNetty.Dashbord.UI/src/config/index.js
new file mode 100644
index 0000000..6739a85
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/config/index.js
@@ -0,0 +1,36 @@
+export default {
+ /**
+ * @description 配置显示在浏览器标签的title
+ */
+ title: 'iView-admin',
+ /**
+ * @description token在Cookie中存储的天数,默认1天
+ */
+ cookieExpires: 1,
+ /**
+ * @description 是否使用国际化,默认为false
+ * 如果不使用,则需要在路由中给需要在菜单中展示的路由设置meta: {title: 'xxx'}
+ * 用来在菜单中显示文字
+ */
+ useI18n: true,
+ /**
+ * @description api请求基础路径
+ */
+ baseUrl: {
+ dev: 'https://www.easy-mock.com/mock/5add9213ce4d0e69998a6f51/iview-admin/',
+ pro: 'https://produce.com'
+ },
+ /**
+ * @description 默认打开的首页的路由name值,默认为home
+ */
+ homeName: 'home',
+ /**
+ * @description 需要加载的插件
+ */
+ plugin: {
+ 'error-store': {
+ showInHeader: true, // 设为false后不会在顶部显示错误日志徽标
+ developmentOff: true // 设为true后在开发环境不会收集错误信息,方便开发中排查错误
+ }
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/directive/directives.js b/src/JT808.DotNetty.Dashbord.UI/src/directive/directives.js
new file mode 100644
index 0000000..fffd62c
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/directive/directives.js
@@ -0,0 +1,9 @@
+import draggable from './module/draggable'
+import clipboard from './module/clipboard'
+
+const directives = {
+ draggable,
+ clipboard
+}
+
+export default directives
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/directive/index.js b/src/JT808.DotNetty.Dashbord.UI/src/directive/index.js
new file mode 100644
index 0000000..aa98c10
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/directive/index.js
@@ -0,0 +1,24 @@
+import directive from './directives'
+
+const importDirective = Vue => {
+ /**
+ * 拖拽指令 v-draggable="options"
+ * options = {
+ * trigger: /这里传入作为拖拽触发器的CSS选择器/,
+ * body: /这里传入需要移动容器的CSS选择器/,
+ * recover: /拖动结束之后是否恢复到原来的位置/
+ * }
+ */
+ Vue.directive('draggable', directive.draggable)
+ /**
+ * clipboard指令 v-draggable="options"
+ * options = {
+ * value: /在输入框中使用v-model绑定的值/,
+ * success: /复制成功后的回调/,
+ * error: /复制失败后的回调/
+ * }
+ */
+ Vue.directive('clipboard', directive.clipboard)
+}
+
+export default importDirective
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/directive/module/clipboard.js b/src/JT808.DotNetty.Dashbord.UI/src/directive/module/clipboard.js
new file mode 100644
index 0000000..655bdf8
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/directive/module/clipboard.js
@@ -0,0 +1,30 @@
+import Clipboard from 'clipboard'
+export default {
+ bind: (el, binding) => {
+ const clipboard = new Clipboard(el, {
+ text: () => binding.value.value
+ })
+ el.__success_callback__ = binding.value.success
+ el.__error_callback__ = binding.value.error
+ clipboard.on('success', e => {
+ const callback = el.__success_callback__
+ callback && callback(e)
+ })
+ clipboard.on('error', e => {
+ const callback = el.__error_callback__
+ callback && callback(e)
+ })
+ el.__clipboard__ = clipboard
+ },
+ update: (el, binding) => {
+ el.__clipboard__.text = () => binding.value.value
+ el.__success_callback__ = binding.value.success
+ el.__error_callback__ = binding.value.error
+ },
+ unbind: (el, binding) => {
+ delete el.__success_callback__
+ delete el.__error_callback__
+ el.__clipboard__.destroy()
+ delete el.__clipboard__
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/directive/module/draggable.js b/src/JT808.DotNetty.Dashbord.UI/src/directive/module/draggable.js
new file mode 100644
index 0000000..b609e50
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/directive/module/draggable.js
@@ -0,0 +1,41 @@
+import { on } from '@/libs/tools'
+export default {
+ inserted: (el, binding, vnode) => {
+ let triggerDom = document.querySelector(binding.value.trigger)
+ triggerDom.style.cursor = 'move'
+ let bodyDom = document.querySelector(binding.value.body)
+ let pageX = 0
+ let pageY = 0
+ let transformX = 0
+ let transformY = 0
+ let canMove = false
+ const handleMousedown = e => {
+ let transform = /\(.*\)/.exec(bodyDom.style.transform)
+ if (transform) {
+ transform = transform[0].slice(1, transform[0].length - 1)
+ let splitxy = transform.split('px, ')
+ transformX = parseFloat(splitxy[0])
+ transformY = parseFloat(splitxy[1].split('px')[0])
+ }
+ pageX = e.pageX
+ pageY = e.pageY
+ canMove = true
+ }
+ const handleMousemove = e => {
+ let xOffset = e.pageX - pageX + transformX
+ let yOffset = e.pageY - pageY + transformY
+ if (canMove) bodyDom.style.transform = `translate(${xOffset}px, ${yOffset}px)`
+ }
+ const handleMouseup = e => {
+ canMove = false
+ }
+ on(triggerDom, 'mousedown', handleMousedown)
+ on(document, 'mousemove', handleMousemove)
+ on(document, 'mouseup', handleMouseup)
+ },
+ update: (el, binding, vnode) => {
+ if (!binding.value.recover) return
+ let bodyDom = document.querySelector(binding.value.body)
+ bodyDom.style.transform = ''
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/index.less b/src/JT808.DotNetty.Dashbord.UI/src/index.less
new file mode 100644
index 0000000..2f8be69
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/index.less
@@ -0,0 +1,5 @@
+@import '~iview/src/styles/index.less';
+
+@menu-dark-title: #001529;
+@menu-dark-active-bg: #000c17;
+@layout-sider-background: #001529;
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/libs/api.request.js b/src/JT808.DotNetty.Dashbord.UI/src/libs/api.request.js
new file mode 100644
index 0000000..01cb87b
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/libs/api.request.js
@@ -0,0 +1,6 @@
+import HttpRequest from '@/libs/axios'
+import config from '@/config'
+const baseUrl = process.env.NODE_ENV === 'development' ? config.baseUrl.dev : config.baseUrl.pro
+
+const axios = new HttpRequest(baseUrl)
+export default axios
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/libs/axios.js b/src/JT808.DotNetty.Dashbord.UI/src/libs/axios.js
new file mode 100644
index 0000000..4c06b4c
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/libs/axios.js
@@ -0,0 +1,74 @@
+import axios from 'axios'
+import store from '@/store'
+// import { Spin } from 'iview'
+const addErrorLog = errorInfo => {
+ const { statusText, status, request: { responseURL } } = errorInfo
+ let info = {
+ type: 'ajax',
+ code: status,
+ mes: statusText,
+ url: responseURL
+ }
+ if (!responseURL.includes('save_error_logger')) store.dispatch('addErrorLog', info)
+}
+
+class HttpRequest {
+ constructor (baseUrl = baseURL) {
+ this.baseUrl = baseUrl
+ this.queue = {}
+ }
+ getInsideConfig () {
+ const config = {
+ baseURL: this.baseUrl,
+ headers: {
+ //
+ }
+ }
+ return config
+ }
+ destroy (url) {
+ delete this.queue[url]
+ if (!Object.keys(this.queue).length) {
+ // Spin.hide()
+ }
+ }
+ interceptors (instance, url) {
+ // 请求拦截
+ instance.interceptors.request.use(config => {
+ // 添加全局的loading...
+ if (!Object.keys(this.queue).length) {
+ // Spin.show() // 不建议开启,因为界面不友好
+ }
+ this.queue[url] = true
+ return config
+ }, error => {
+ return Promise.reject(error)
+ })
+ // 响应拦截
+ instance.interceptors.response.use(res => {
+ this.destroy(url)
+ const { data, status } = res
+ return { data, status }
+ }, error => {
+ this.destroy(url)
+ let errorInfo = error.response
+ if (!errorInfo) {
+ const { request: { statusText, status }, config } = JSON.parse(JSON.stringify(error))
+ errorInfo = {
+ statusText,
+ status,
+ request: { responseURL: config.url }
+ }
+ }
+ addErrorLog(errorInfo)
+ return Promise.reject(error)
+ })
+ }
+ request (options) {
+ const instance = axios.create()
+ options = Object.assign(this.getInsideConfig(), options)
+ this.interceptors(instance, options.url)
+ return instance(options)
+ }
+}
+export default HttpRequest
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/libs/excel.js b/src/JT808.DotNetty.Dashbord.UI/src/libs/excel.js
new file mode 100644
index 0000000..ba9d406
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/libs/excel.js
@@ -0,0 +1,113 @@
+/* eslint-disable */
+import XLSX from 'xlsx';
+
+function auto_width(ws, data){
+ /*set worksheet max width per col*/
+ const colWidth = data.map(row => row.map(val => {
+ /*if null/undefined*/
+ if (val == null) {
+ return {'wch': 10};
+ }
+ /*if chinese*/
+ else if (val.toString().charCodeAt(0) > 255) {
+ return {'wch': val.toString().length * 2};
+ } else {
+ return {'wch': val.toString().length};
+ }
+ }))
+ /*start in the first row*/
+ let result = colWidth[0];
+ for (let i = 1; i < colWidth.length; i++) {
+ for (let j = 0; j < colWidth[i].length; j++) {
+ if (result[j]['wch'] < colWidth[i][j]['wch']) {
+ result[j]['wch'] = colWidth[i][j]['wch'];
+ }
+ }
+ }
+ ws['!cols'] = result;
+}
+
+function json_to_array(key, jsonData){
+ return jsonData.map(v => key.map(j => { return v[j] }));
+}
+
+// fix data,return string
+function fixdata(data) {
+ let o = ''
+ let l = 0
+ const w = 10240
+ for (; l < data.byteLength / w; ++l) o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w, l * w + w)))
+ o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w)))
+ return o
+}
+
+// get head from excel file,return array
+function get_header_row(sheet) {
+ const headers = []
+ const range = XLSX.utils.decode_range(sheet['!ref'])
+ let C
+ const R = range.s.r /* start in the first row */
+ for (C = range.s.c; C <= range.e.c; ++C) { /* walk every column in the range */
+ var cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })] /* find the cell in the first row */
+ var hdr = 'UNKNOWN ' + C // <-- replace with your desired default
+ if (cell && cell.t) hdr = XLSX.utils.format_cell(cell)
+ headers.push(hdr)
+ }
+ return headers
+}
+
+export const export_table_to_excel= (id, filename) => {
+ const table = document.getElementById(id);
+ const wb = XLSX.utils.table_to_book(table);
+ XLSX.writeFile(wb, filename);
+
+ /* the second way */
+ // const table = document.getElementById(id);
+ // const wb = XLSX.utils.book_new();
+ // const ws = XLSX.utils.table_to_sheet(table);
+ // XLSX.utils.book_append_sheet(wb, ws, filename);
+ // XLSX.writeFile(wb, filename);
+}
+
+export const export_json_to_excel = ({data, key, title, filename, autoWidth}) => {
+ const wb = XLSX.utils.book_new();
+ data.unshift(title);
+ const ws = XLSX.utils.json_to_sheet(data, {header: key, skipHeader: true});
+ if(autoWidth){
+ const arr = json_to_array(key, data);
+ auto_width(ws, arr);
+ }
+ XLSX.utils.book_append_sheet(wb, ws, filename);
+ XLSX.writeFile(wb, filename + '.xlsx');
+}
+
+export const export_array_to_excel = ({key, data, title, filename, autoWidth}) => {
+ const wb = XLSX.utils.book_new();
+ const arr = json_to_array(key, data);
+ arr.unshift(title);
+ const ws = XLSX.utils.aoa_to_sheet(arr);
+ if(autoWidth){
+ auto_width(ws, arr);
+ }
+ XLSX.utils.book_append_sheet(wb, ws, filename);
+ XLSX.writeFile(wb, filename + '.xlsx');
+}
+
+export const read = (data, type) => {
+ /* if type == 'base64' must fix data first */
+ // const fixedData = fixdata(data)
+ // const workbook = XLSX.read(btoa(fixedData), { type: 'base64' })
+ const workbook = XLSX.read(data, { type: type });
+ const firstSheetName = workbook.SheetNames[0];
+ const worksheet = workbook.Sheets[firstSheetName];
+ const header = get_header_row(worksheet);
+ const results = XLSX.utils.sheet_to_json(worksheet);
+ return {header, results};
+}
+
+export default {
+ export_table_to_excel,
+ export_array_to_excel,
+ export_json_to_excel,
+ read
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/libs/tools.js b/src/JT808.DotNetty.Dashbord.UI/src/libs/tools.js
new file mode 100644
index 0000000..0ca81d6
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/libs/tools.js
@@ -0,0 +1,215 @@
+export const forEach = (arr, fn) => {
+ if (!arr.length || !fn) return
+ let i = -1
+ let len = arr.length
+ while (++i < len) {
+ let item = arr[i]
+ fn(item, i, arr)
+ }
+}
+
+/**
+ * @param {Array} arr1
+ * @param {Array} arr2
+ * @description 得到两个数组的交集, 两个数组的元素为数值或字符串
+ */
+export const getIntersection = (arr1, arr2) => {
+ let len = Math.min(arr1.length, arr2.length)
+ let i = -1
+ let res = []
+ while (++i < len) {
+ const item = arr2[i]
+ if (arr1.indexOf(item) > -1) res.push(item)
+ }
+ return res
+}
+
+/**
+ * @param {Array} arr1
+ * @param {Array} arr2
+ * @description 得到两个数组的并集, 两个数组的元素为数值或字符串
+ */
+export const getUnion = (arr1, arr2) => {
+ return Array.from(new Set([...arr1, ...arr2]))
+}
+
+/**
+ * @param {Array} target 目标数组
+ * @param {Array} arr 需要查询的数组
+ * @description 判断要查询的数组是否至少有一个元素包含在目标数组中
+ */
+export const hasOneOf = (targetarr, arr) => {
+ return targetarr.some(_ => arr.indexOf(_) > -1)
+}
+
+/**
+ * @param {String|Number} value 要验证的字符串或数值
+ * @param {*} validList 用来验证的列表
+ */
+export function oneOf (value, validList) {
+ for (let i = 0; i < validList.length; i++) {
+ if (value === validList[i]) {
+ return true
+ }
+ }
+ return false
+}
+
+/**
+ * @param {Number} timeStamp 判断时间戳格式是否是毫秒
+ * @returns {Boolean}
+ */
+const isMillisecond = timeStamp => {
+ const timeStr = String(timeStamp)
+ return timeStr.length > 10
+}
+
+/**
+ * @param {Number} timeStamp 传入的时间戳
+ * @param {Number} currentTime 当前时间时间戳
+ * @returns {Boolean} 传入的时间戳是否早于当前时间戳
+ */
+const isEarly = (timeStamp, currentTime) => {
+ return timeStamp < currentTime
+}
+
+/**
+ * @param {Number} num 数值
+ * @returns {String} 处理后的字符串
+ * @description 如果传入的数值小于10,即位数只有1位,则在前面补充0
+ */
+const getHandledValue = num => {
+ return num < 10 ? '0' + num : num
+}
+
+/**
+ * @param {Number} timeStamp 传入的时间戳
+ * @param {Number} startType 要返回的时间字符串的格式类型,传入'year'则返回年开头的完整时间
+ */
+const getDate = (timeStamp, startType) => {
+ const d = new Date(timeStamp * 1000)
+ const year = d.getFullYear()
+ const month = getHandledValue(d.getMonth() + 1)
+ const date = getHandledValue(d.getDate())
+ const hours = getHandledValue(d.getHours())
+ const minutes = getHandledValue(d.getMinutes())
+ const second = getHandledValue(d.getSeconds())
+ let resStr = ''
+ if (startType === 'year') resStr = year + '-' + month + '-' + date + ' ' + hours + ':' + minutes + ':' + second
+ else resStr = month + '-' + date + ' ' + hours + ':' + minutes
+ return resStr
+}
+
+/**
+ * @param {String|Number} timeStamp 时间戳
+ * @returns {String} 相对时间字符串
+ */
+export const getRelativeTime = timeStamp => {
+ // 判断当前传入的时间戳是秒格式还是毫秒
+ const IS_MILLISECOND = isMillisecond(timeStamp)
+ // 如果是毫秒格式则转为秒格式
+ if (IS_MILLISECOND) Math.floor(timeStamp /= 1000)
+ // 传入的时间戳可以是数值或字符串类型,这里统一转为数值类型
+ timeStamp = Number(timeStamp)
+ // 获取当前时间时间戳
+ const currentTime = Math.floor(Date.parse(new Date()) / 1000)
+ // 判断传入时间戳是否早于当前时间戳
+ const IS_EARLY = isEarly(timeStamp, currentTime)
+ // 获取两个时间戳差值
+ let diff = currentTime - timeStamp
+ // 如果IS_EARLY为false则差值取反
+ if (!IS_EARLY) diff = -diff
+ let resStr = ''
+ const dirStr = IS_EARLY ? '前' : '后'
+ // 少于等于59秒
+ if (diff <= 59) resStr = diff + '秒' + dirStr
+ // 多于59秒,少于等于59分钟59秒
+ else if (diff > 59 && diff <= 3599) resStr = Math.floor(diff / 60) + '分钟' + dirStr
+ // 多于59分钟59秒,少于等于23小时59分钟59秒
+ else if (diff > 3599 && diff <= 86399) resStr = Math.floor(diff / 3600) + '小时' + dirStr
+ // 多于23小时59分钟59秒,少于等于29天59分钟59秒
+ else if (diff > 86399 && diff <= 2623859) resStr = Math.floor(diff / 86400) + '天' + dirStr
+ // 多于29天59分钟59秒,少于364天23小时59分钟59秒,且传入的时间戳早于当前
+ else if (diff > 2623859 && diff <= 31567859 && IS_EARLY) resStr = getDate(timeStamp)
+ else resStr = getDate(timeStamp, 'year')
+ return resStr
+}
+
+/**
+ * @returns {String} 当前浏览器名称
+ */
+export const getExplorer = () => {
+ const ua = window.navigator.userAgent
+ const isExplorer = (exp) => {
+ return ua.indexOf(exp) > -1
+ }
+ if (isExplorer('MSIE')) return 'IE'
+ else if (isExplorer('Firefox')) return 'Firefox'
+ else if (isExplorer('Chrome')) return 'Chrome'
+ else if (isExplorer('Opera')) return 'Opera'
+ else if (isExplorer('Safari')) return 'Safari'
+}
+
+/**
+ * @description 绑定事件 on(element, event, handler)
+ */
+export const on = (function () {
+ if (document.addEventListener) {
+ return function (element, event, handler) {
+ if (element && event && handler) {
+ element.addEventListener(event, handler, false)
+ }
+ }
+ } else {
+ return function (element, event, handler) {
+ if (element && event && handler) {
+ element.attachEvent('on' + event, handler)
+ }
+ }
+ }
+})()
+
+/**
+ * @description 解绑事件 off(element, event, handler)
+ */
+export const off = (function () {
+ if (document.removeEventListener) {
+ return function (element, event, handler) {
+ if (element && event) {
+ element.removeEventListener(event, handler, false)
+ }
+ }
+ } else {
+ return function (element, event, handler) {
+ if (element && event) {
+ element.detachEvent('on' + event, handler)
+ }
+ }
+ }
+})()
+
+/**
+ * 判断一个对象是否存在key,如果传入第二个参数key,则是判断这个obj对象是否存在key这个属性
+ * 如果没有传入key这个参数,则判断obj对象是否有键值对
+ */
+export const hasKey = (obj, key) => {
+ if (key) return key in obj
+ else {
+ let keysArr = Object.keys(obj)
+ return keysArr.length
+ }
+}
+
+/**
+ * @param {*} obj1 对象
+ * @param {*} obj2 对象
+ * @description 判断两个对象是否相等,这两个对象的值只能是数字或字符串
+ */
+export const objEqual = (obj1, obj2) => {
+ const keysArr1 = Object.keys(obj1)
+ const keysArr2 = Object.keys(obj2)
+ if (keysArr1.length !== keysArr2.length) return false
+ else if (keysArr1.length === 0 && keysArr2.length === 0) return true
+ /* eslint-disable-next-line */
+ else return !keysArr1.some(key => obj1[key] != obj2[key])
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/libs/util.js b/src/JT808.DotNetty.Dashbord.UI/src/libs/util.js
new file mode 100644
index 0000000..1457b20
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/libs/util.js
@@ -0,0 +1,399 @@
+import Cookies from 'js-cookie'
+// cookie保存的天数
+import config from '@/config'
+import { forEach, hasOneOf, objEqual } from '@/libs/tools'
+const { title, cookieExpires, useI18n } = config
+
+export const TOKEN_KEY = 'token'
+
+export const setToken = (token) => {
+ Cookies.set(TOKEN_KEY, token, {expires: cookieExpires || 1})
+}
+
+export const getToken = () => {
+ const token = Cookies.get(TOKEN_KEY)
+ if (token) return token
+ else return false
+}
+
+export const hasChild = (item) => {
+ return item.children && item.children.length !== 0
+}
+
+const showThisMenuEle = (item, access) => {
+ if (item.meta && item.meta.access && item.meta.access.length) {
+ if (hasOneOf(item.meta.access, access)) return true
+ else return false
+ } else return true
+}
+/**
+ * @param {Array} list 通过路由列表得到菜单列表
+ * @returns {Array}
+ */
+export const getMenuByRouter = (list, access) => {
+ let res = []
+ forEach(list, item => {
+ if (!item.meta || (item.meta && !item.meta.hideInMenu)) {
+ let obj = {
+ icon: (item.meta && item.meta.icon) || '',
+ name: item.name,
+ meta: item.meta
+ }
+ if ((hasChild(item) || (item.meta && item.meta.showAlways)) && showThisMenuEle(item, access)) {
+ obj.children = getMenuByRouter(item.children, access)
+ }
+ if (item.meta && item.meta.href) obj.href = item.meta.href
+ if (showThisMenuEle(item, access)) res.push(obj)
+ }
+ })
+ return res
+}
+
+/**
+ * @param {Array} routeMetched 当前路由metched
+ * @returns {Array}
+ */
+export const getBreadCrumbList = (route, homeRoute) => {
+ let homeItem = { ...homeRoute, icon: homeRoute.meta.icon }
+ let routeMetched = route.matched
+ if (routeMetched.some(item => item.name === homeRoute.name)) return [homeItem]
+ let res = routeMetched.filter(item => {
+ return item.meta === undefined || !item.meta.hideInBread
+ }).map(item => {
+ let meta = {...item.meta}
+ if (meta.title && typeof meta.title === 'function') {
+ meta.__titleIsFunction__ = true
+ meta.title = meta.title(route)
+ }
+ let obj = {
+ icon: (item.meta && item.meta.icon) || '',
+ name: item.name,
+ meta: meta
+ }
+ return obj
+ })
+ res = res.filter(item => {
+ return !item.meta.hideInMenu
+ })
+ return [{...homeItem, to: homeRoute.path}, ...res]
+}
+
+export const getRouteTitleHandled = (route) => {
+ let router = {...route}
+ let meta = {...route.meta}
+ let title = ''
+ if (meta.title) {
+ if (typeof meta.title === 'function') {
+ meta.__titleIsFunction__ = true
+ title = meta.title(router)
+ } else title = meta.title
+ }
+ meta.title = title
+ router.meta = meta
+ return router
+}
+
+export const showTitle = (item, vm) => {
+ let { title, __titleIsFunction__ } = item.meta
+ if (!title) return
+ if (useI18n) {
+ if (title.includes('{{') && title.includes('}}') && useI18n) title = title.replace(/({{[\s\S]+?}})/, (m, str) => str.replace(/{{([\s\S]*)}}/, (m, _) => vm.$t(_.trim())))
+ else if (__titleIsFunction__) title = item.meta.title
+ else title = vm.$t(item.name)
+ } else title = (item.meta && item.meta.title) || item.name
+ return title
+}
+
+/**
+ * @description 本地存储和获取标签导航列表
+ */
+export const setTagNavListInLocalstorage = list => {
+ localStorage.tagNaveList = JSON.stringify(list)
+}
+/**
+ * @returns {Array} 其中的每个元素只包含路由原信息中的name, path, meta三项
+ */
+export const getTagNavListFromLocalstorage = () => {
+ const list = localStorage.tagNaveList
+ return list ? JSON.parse(list) : []
+}
+
+/**
+ * @param {Array} routers 路由列表数组
+ * @description 用于找到路由列表中name为home的对象
+ */
+export const getHomeRoute = (routers, homeName = 'home') => {
+ let i = -1
+ let len = routers.length
+ let homeRoute = {}
+ while (++i < len) {
+ let item = routers[i]
+ if (item.children && item.children.length) {
+ let res = getHomeRoute(item.children, homeName)
+ if (res.name) return res
+ } else {
+ if (item.name === homeName) homeRoute = item
+ }
+ }
+ return homeRoute
+}
+
+/**
+ * @param {*} list 现有标签导航列表
+ * @param {*} newRoute 新添加的路由原信息对象
+ * @description 如果该newRoute已经存在则不再添加
+ */
+export const getNewTagList = (list, newRoute) => {
+ const { name, path, meta } = newRoute
+ let newList = [...list]
+ if (newList.findIndex(item => item.name === name) >= 0) return newList
+ else newList.push({ name, path, meta })
+ return newList
+}
+
+/**
+ * @param {*} access 用户权限数组,如 ['super_admin', 'admin']
+ * @param {*} route 路由列表
+ */
+const hasAccess = (access, route) => {
+ if (route.meta && route.meta.access) return hasOneOf(access, route.meta.access)
+ else return true
+}
+
+/**
+ * 权鉴
+ * @param {*} name 即将跳转的路由name
+ * @param {*} access 用户权限数组
+ * @param {*} routes 路由列表
+ * @description 用户是否可跳转到该页
+ */
+export const canTurnTo = (name, access, routes) => {
+ const routePermissionJudge = (list) => {
+ return list.some(item => {
+ if (item.children && item.children.length) {
+ return routePermissionJudge(item.children)
+ } else if (item.name === name) {
+ return hasAccess(access, item)
+ }
+ })
+ }
+
+ return routePermissionJudge(routes)
+}
+
+/**
+ * @param {String} url
+ * @description 从URL中解析参数
+ */
+export const getParams = url => {
+ const keyValueArr = url.split('?')[1].split('&')
+ let paramObj = {}
+ keyValueArr.forEach(item => {
+ const keyValue = item.split('=')
+ paramObj[keyValue[0]] = keyValue[1]
+ })
+ return paramObj
+}
+
+/**
+ * @param {Array} list 标签列表
+ * @param {String} name 当前关闭的标签的name
+ */
+export const getNextRoute = (list, route) => {
+ let res = {}
+ if (list.length === 2) {
+ res = getHomeRoute(list)
+ } else {
+ const index = list.findIndex(item => routeEqual(item, route))
+ if (index === list.length - 1) res = list[list.length - 2]
+ else res = list[index + 1]
+ }
+ return res
+}
+
+/**
+ * @param {Number} times 回调函数需要执行的次数
+ * @param {Function} callback 回调函数
+ */
+export const doCustomTimes = (times, callback) => {
+ let i = -1
+ while (++i < times) {
+ callback(i)
+ }
+}
+
+/**
+ * @param {Object} file 从上传组件得到的文件对象
+ * @returns {Promise} resolve参数是解析后的二维数组
+ * @description 从Csv文件中解析出表格,解析成二维数组
+ */
+export const getArrayFromFile = (file) => {
+ let nameSplit = file.name.split('.')
+ let format = nameSplit[nameSplit.length - 1]
+ return new Promise((resolve, reject) => {
+ let reader = new FileReader()
+ reader.readAsText(file) // 以文本格式读取
+ let arr = []
+ reader.onload = function (evt) {
+ let data = evt.target.result // 读到的数据
+ let pasteData = data.trim()
+ arr = pasteData.split((/[\n\u0085\u2028\u2029]|\r\n?/g)).map(row => {
+ return row.split('\t')
+ }).map(item => {
+ return item[0].split(',')
+ })
+ if (format === 'csv') resolve(arr)
+ else reject(new Error('[Format Error]:你上传的不是Csv文件'))
+ }
+ })
+}
+
+/**
+ * @param {Array} array 表格数据二维数组
+ * @returns {Object} { columns, tableData }
+ * @description 从二维数组中获取表头和表格数据,将第一行作为表头,用于在iView的表格中展示数据
+ */
+export const getTableDataFromArray = (array) => {
+ let columns = []
+ let tableData = []
+ if (array.length > 1) {
+ let titles = array.shift()
+ columns = titles.map(item => {
+ return {
+ title: item,
+ key: item
+ }
+ })
+ tableData = array.map(item => {
+ let res = {}
+ item.forEach((col, i) => {
+ res[titles[i]] = col
+ })
+ return res
+ })
+ }
+ return {
+ columns,
+ tableData
+ }
+}
+
+export const findNodeUpper = (ele, tag) => {
+ if (ele.parentNode) {
+ if (ele.parentNode.tagName === tag.toUpperCase()) {
+ return ele.parentNode
+ } else {
+ return findNodeUpper(ele.parentNode, tag)
+ }
+ }
+}
+
+export const findNodeUpperByClasses = (ele, classes) => {
+ let parentNode = ele.parentNode
+ if (parentNode) {
+ let classList = parentNode.classList
+ if (classList && classes.every(className => classList.contains(className))) {
+ return parentNode
+ } else {
+ return findNodeUpperByClasses(parentNode, classes)
+ }
+ }
+}
+
+export const findNodeDownward = (ele, tag) => {
+ const tagName = tag.toUpperCase()
+ if (ele.childNodes.length) {
+ let i = -1
+ let len = ele.childNodes.length
+ while (++i < len) {
+ let child = ele.childNodes[i]
+ if (child.tagName === tagName) return child
+ else return findNodeDownward(child, tag)
+ }
+ }
+}
+
+export const showByAccess = (access, canViewAccess) => {
+ return hasOneOf(canViewAccess, access)
+}
+
+/**
+ * @description 根据name/params/query判断两个路由对象是否相等
+ * @param {*} route1 路由对象
+ * @param {*} route2 路由对象
+ */
+export const routeEqual = (route1, route2) => {
+ const params1 = route1.params || {}
+ const params2 = route2.params || {}
+ const query1 = route1.query || {}
+ const query2 = route2.query || {}
+ return (route1.name === route2.name) && objEqual(params1, params2) && objEqual(query1, query2)
+}
+
+/**
+ * 判断打开的标签列表里是否已存在这个新添加的路由对象
+ */
+export const routeHasExist = (tagNavList, routeItem) => {
+ let len = tagNavList.length
+ let res = false
+ doCustomTimes(len, (index) => {
+ if (routeEqual(tagNavList[index], routeItem)) res = true
+ })
+ return res
+}
+
+export const localSave = (key, value) => {
+ localStorage.setItem(key, value)
+}
+
+export const localRead = (key) => {
+ return localStorage.getItem(key) || ''
+}
+
+// scrollTop animation
+export const scrollTop = (el, from = 0, to, duration = 500, endCallback) => {
+ if (!window.requestAnimationFrame) {
+ window.requestAnimationFrame = (
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ function (callback) {
+ return window.setTimeout(callback, 1000 / 60)
+ }
+ )
+ }
+ const difference = Math.abs(from - to)
+ const step = Math.ceil(difference / duration * 50)
+
+ const scroll = (start, end, step) => {
+ if (start === end) {
+ endCallback && endCallback()
+ return
+ }
+
+ let d = (start + step > end) ? end : start + step
+ if (start > end) {
+ d = (start - step < end) ? end : start - step
+ }
+
+ if (el === window) {
+ window.scrollTo(d, d)
+ } else {
+ el.scrollTop = d
+ }
+ window.requestAnimationFrame(() => scroll(d, end, step))
+ }
+ scroll(from, to, step)
+}
+
+/**
+ * @description 根据当前跳转的路由设置显示在浏览器标签的title
+ * @param {Object} routeItem 路由对象
+ * @param {Object} vm Vue实例
+ */
+export const setTitle = (routeItem, vm) => {
+ const handledRoute = getRouteTitleHandled(routeItem)
+ const pageTitle = showTitle(handledRoute, vm)
+ const resTitle = pageTitle ? `${title} - ${pageTitle}` : title
+ window.document.title = resTitle
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/locale/index.js b/src/JT808.DotNetty.Dashbord.UI/src/locale/index.js
new file mode 100644
index 0000000..c35492e
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/locale/index.js
@@ -0,0 +1,37 @@
+import Vue from 'vue'
+import VueI18n from 'vue-i18n'
+import { localRead } from '@/libs/util'
+import customZhCn from './lang/zh-CN'
+import customZhTw from './lang/zh-TW'
+import customEnUs from './lang/en-US'
+import zhCnLocale from 'iview/src/locale/lang/zh-CN'
+import enUsLocale from 'iview/src/locale/lang/en-US'
+import zhTwLocale from 'iview/src/locale/lang/zh-TW'
+
+Vue.use(VueI18n)
+
+// 自动根据浏览器系统语言设置语言
+const navLang = navigator.language
+const localLang = (navLang === 'zh-CN' || navLang === 'en-US') ? navLang : false
+let lang = localLang || localRead('local') || 'zh-CN'
+
+Vue.config.lang = lang
+
+// vue-i18n 6.x+写法
+Vue.locale = () => {}
+const messages = {
+ 'zh-CN': Object.assign(zhCnLocale, customZhCn),
+ 'zh-TW': Object.assign(zhTwLocale, customZhTw),
+ 'en-US': Object.assign(enUsLocale, customEnUs)
+}
+const i18n = new VueI18n({
+ locale: lang,
+ messages
+})
+
+export default i18n
+
+// vue-i18n 5.x写法
+// Vue.locale('zh-CN', Object.assign(zhCnLocale, customZhCn))
+// Vue.locale('en-US', Object.assign(zhTwLocale, customZhTw))
+// Vue.locale('zh-TW', Object.assign(enUsLocale, customEnUs))
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/locale/lang/en-US.js b/src/JT808.DotNetty.Dashbord.UI/src/locale/lang/en-US.js
new file mode 100644
index 0000000..d915372
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/locale/lang/en-US.js
@@ -0,0 +1,42 @@
+export default {
+ home: 'Home',
+ components: 'Components',
+ count_to_page: 'Count-to',
+ tables_page: 'Table',
+ split_pane_page: 'Split-pane',
+ markdown_page: 'Markdown-editor',
+ editor_page: 'Rich-Text-Editor',
+ icons_page: 'Custom-icon',
+ img_cropper_page: 'Image-editor',
+ update: 'Update',
+ doc: 'Document',
+ join_page: 'QQ Group',
+ update_table_page: 'Update .CSV',
+ update_paste_page: 'Paste Table Data',
+ multilevel: 'multilevel',
+ directive_page: 'Directive',
+ level_1: 'Level-1',
+ level_2: 'Level-2',
+ level_2_1: 'Level-2-1',
+ level_2_3: 'Level-2-3',
+ level_2_2: 'Level-2-2',
+ level_2_2_1: 'Level-2-2-1',
+ level_2_2_2: 'Level-2-2-2',
+ excel: 'Excel',
+ 'upload-excel': 'Upload Excel',
+ 'export-excel': 'Export Excel',
+ tools_methods_page: 'Tools Methods',
+ drag_list_page: 'Drag-list',
+ i18n_page: 'Internationalization',
+ modalTitle: 'Modal Title',
+ content: 'This is the modal box content.',
+ buttonText: 'Show Modal',
+ 'i18n-tip': 'Note: Only this page is multi-language, other pages do not add language content to the multi-language package.',
+ error_store_page: 'Error Collection',
+ error_logger_page: 'Error Logger',
+ query: 'Query',
+ params: 'Params',
+ cropper_page: 'Cropper',
+ message_page: 'Message Center',
+ tree_table_page: 'Tree Table'
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/locale/lang/zh-CN.js b/src/JT808.DotNetty.Dashbord.UI/src/locale/lang/zh-CN.js
new file mode 100644
index 0000000..4393738
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/locale/lang/zh-CN.js
@@ -0,0 +1,42 @@
+export default {
+ home: '首页',
+ components: '组件',
+ count_to_page: '数字渐变',
+ tables_page: '多功能表格',
+ split_pane_page: '分割窗口',
+ markdown_page: 'Markdown编辑器',
+ editor_page: '富文本编辑器',
+ icons_page: '自定义图标',
+ img_cropper_page: '图片编辑器',
+ update: '上传数据',
+ join_page: 'QQ群',
+ doc: '文档',
+ update_table_page: '上传CSV文件',
+ update_paste_page: '粘贴表格数据',
+ multilevel: '多级菜单',
+ directive_page: '指令',
+ level_1: 'Level-1',
+ level_2: 'Level-2',
+ level_2_1: 'Level-2-1',
+ level_2_3: 'Level-2-3',
+ level_2_2: 'Level-2-2',
+ level_2_2_1: 'Level-2-2-1',
+ level_2_2_2: 'Level-2-2-2',
+ excel: 'Excel',
+ 'upload-excel': '上传excel',
+ 'export-excel': '导出excel',
+ tools_methods_page: '工具函数',
+ drag_list_page: '拖拽列表',
+ i18n_page: '多语言',
+ modalTitle: '模态框题目',
+ content: '这是模态框内容',
+ buttonText: '显示模态框',
+ 'i18n-tip': '注:仅此页做了多语言,其他页面没有在多语言包中添加语言内容',
+ error_store_page: '错误收集',
+ error_logger_page: '错误日志',
+ query: '带参路由',
+ params: '动态路由',
+ cropper_page: '图片裁剪',
+ message_page: '消息中心',
+ tree_table_page: '树状表格'
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/locale/lang/zh-TW.js b/src/JT808.DotNetty.Dashbord.UI/src/locale/lang/zh-TW.js
new file mode 100644
index 0000000..fed4b1d
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/locale/lang/zh-TW.js
@@ -0,0 +1,42 @@
+export default {
+ home: '首頁',
+ components: '组件',
+ count_to_page: '数字渐变',
+ tables_page: '多功能表格',
+ split_pane_page: '分割窗口',
+ markdown_page: 'Markdown編輯器',
+ editor_page: '富文本編輯器',
+ icons_page: '自定義圖標',
+ img_cropper_page: '圖片編輯器',
+ update: '上傳數據',
+ join_page: 'QQ群',
+ doc: '文檔',
+ update_table_page: '上傳CSV文件',
+ update_paste_page: '粘貼表格數據',
+ multilevel: '多级菜单',
+ directive_page: '指令',
+ level_1: 'Level-1',
+ level_2: 'Level-2',
+ level_2_1: 'Level-2-1',
+ level_2_3: 'Level-2-3',
+ level_2_2: 'Level-2-2',
+ level_2_2_1: 'Level-2-2-1',
+ level_2_2_2: 'Level-2-2-2',
+ excel: 'Excel',
+ 'upload-excel': '上傳excel',
+ 'export-excel': '導出excel',
+ tools_methods_page: '工具函數',
+ drag_list_page: '拖拽列表',
+ i18n_page: '多語言',
+ modalTitle: '模態框題目',
+ content: '這是模態框內容',
+ buttonText: '顯示模態框',
+ 'i18n-tip': '注:僅此頁做了多語言,其他頁面沒有在多語言包中添加語言內容',
+ error_store_page: '錯誤收集',
+ error_logger_page: '錯誤日誌',
+ query: '帶參路由',
+ params: '動態路由',
+ cropper_page: '圖片裁剪',
+ message_page: '消息中心',
+ tree_table_page: '樹狀表格'
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/main.js b/src/JT808.DotNetty.Dashbord.UI/src/main.js
new file mode 100644
index 0000000..37180aa
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/main.js
@@ -0,0 +1,47 @@
+// The Vue build version to load with the `import` command
+// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
+import Vue from 'vue'
+import App from './App'
+import router from './router'
+import store from './store'
+import iView from 'iview'
+import i18n from '@/locale'
+import config from '@/config'
+import importDirective from '@/directive'
+import installPlugin from '@/plugin'
+import './index.less'
+import '@/assets/icons/iconfont.css'
+import TreeTable from 'tree-table-vue'
+// 实际打包时应该不引入mock
+/* eslint-disable */
+if (process.env.NODE_ENV !== 'production') require('@/mock')
+
+Vue.use(iView, {
+ i18n: (key, value) => i18n.t(key, value)
+})
+Vue.use(TreeTable)
+/**
+ * @description 注册admin内置插件
+ */
+installPlugin(Vue)
+/**
+ * @description 生产环境关掉提示
+ */
+Vue.config.productionTip = false
+/**
+ * @description 全局注册应用配置
+ */
+Vue.prototype.$config = config
+/**
+ * 注册指令
+ */
+importDirective(Vue)
+
+/* eslint-disable no-new */
+new Vue({
+ el: '#app',
+ router,
+ i18n,
+ store,
+ render: h => h(App)
+})
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/mock/atomicCounter.js b/src/JT808.DotNetty.Dashbord.UI/src/mock/atomicCounter.js
new file mode 100644
index 0000000..53d103f
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/mock/atomicCounter.js
@@ -0,0 +1,9 @@
+import Mock from 'mockjs'
+import { setData } from '@/mock/commonResultData'
+
+export const GetAtomicCounter = () => {
+ return setData(Mock.mock({
+ 'MsgSuccessCount|1-10000000': 100,
+ 'MsgFailCount|1-10000000': 100
+ }))
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/mock/commonResultData.js b/src/JT808.DotNetty.Dashbord.UI/src/mock/commonResultData.js
new file mode 100644
index 0000000..50e076b
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/mock/commonResultData.js
@@ -0,0 +1,7 @@
+export const setData = (data, code = 200) => {
+ return {
+ 'Code': code,
+ 'Message': '',
+ 'Data': data
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/mock/data.js b/src/JT808.DotNetty.Dashbord.UI/src/mock/data.js
new file mode 100644
index 0000000..e0d36ae
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/mock/data.js
@@ -0,0 +1,30 @@
+import Mock from 'mockjs'
+import { doCustomTimes } from '@/libs/util'
+const Random = Mock.Random
+
+export const getTableData = req => {
+ let tableData = []
+ doCustomTimes(5, () => {
+ tableData.push(Mock.mock({
+ name: '@name',
+ email: '@email',
+ createTime: '@date'
+ }))
+ })
+ return tableData
+}
+
+export const getDragList = req => {
+ let dragList = []
+ doCustomTimes(5, () => {
+ dragList.push(Mock.mock({
+ name: Random.csentence(10, 13),
+ id: Random.increment(10)
+ }))
+ })
+ return dragList
+}
+
+export const uploadImage = req => {
+ return Promise.resolve()
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/mock/index.js b/src/JT808.DotNetty.Dashbord.UI/src/mock/index.js
new file mode 100644
index 0000000..e8da037
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/mock/index.js
@@ -0,0 +1,47 @@
+import Mock from 'mockjs'
+import { login, logout, getUserInfo } from './login'
+import { getTableData, getDragList, uploadImage } from './data'
+import { getMessageInit, getContentByMsgId, hasRead, removeReaded, restoreTrash, messageCount } from './user'
+import { GetAtomicCounter } from './atomicCounter'
+import sourcePackage from './sourcePackage'
+import session from './session'
+import transmit from './transmit'
+import unificationSend from './unificationSend'
+
+// 配置Ajax请求延时,可用来测试网络延迟大时项目中一些效果
+Mock.setup({
+ timeout: 1000
+})
+
+// 登录相关和获取用户信息
+Mock.mock(/\/login/, login)
+Mock.mock(/\/get_info/, getUserInfo)
+Mock.mock(/\/logout/, logout)
+Mock.mock(/\/get_table_data/, getTableData)
+Mock.mock(/\/get_drag_list/, getDragList)
+Mock.mock(/\/save_error_logger/, 'success')
+Mock.mock(/\/image\/upload/, uploadImage)
+Mock.mock(/\/message\/init/, getMessageInit)
+Mock.mock(/\/message\/content/, getContentByMsgId)
+Mock.mock(/\/message\/has_read/, hasRead)
+Mock.mock(/\/message\/remove_readed/, removeReaded)
+Mock.mock(/\/message\/restore/, restoreTrash)
+Mock.mock(/\/message\/count/, messageCount)
+
+Mock.mock(/\/AtomicCounter\/GetAtomicCounter/, GetAtomicCounter)
+
+Mock.mock(/\/SourcePackage\/Add/, sourcePackage.Add)
+Mock.mock(/\/SourcePackage\/Remove/, sourcePackage.Remove)
+Mock.mock(/\/SourcePackage\/GetAll/, sourcePackage.GetAll)
+
+Mock.mock(/\/Session\/RemoveByTerminalPhoneNo/, session.RemoveByTerminalPhoneNo)
+Mock.mock(/\/Session\/RemoveByChannelId/, session.RemoveByChannelId)
+Mock.mock(/\/Session\/GetAll/, session.GetAll)
+
+Mock.mock(/\/Transmit\/Add/, transmit.Add)
+Mock.mock(/\/Transmit\/Remove/, transmit.Remove)
+Mock.mock(/\/Transmit\/GetAll/, transmit.GetAll)
+
+Mock.mock(/\/UnificationSend\/SendText/, unificationSend.SendText)
+
+export default Mock
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/mock/login.js b/src/JT808.DotNetty.Dashbord.UI/src/mock/login.js
new file mode 100644
index 0000000..9e84a55
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/mock/login.js
@@ -0,0 +1,31 @@
+import { getParams } from '@/libs/util'
+const USER_MAP = {
+ super_admin: {
+ name: 'super_admin',
+ user_id: '1',
+ access: ['super_admin', 'admin'],
+ token: 'super_admin',
+ avator: 'https://file.iviewui.com/dist/a0e88e83800f138b94d2414621bd9704.png'
+ },
+ admin: {
+ name: 'admin',
+ user_id: '2',
+ access: ['admin'],
+ token: 'admin',
+ avator: 'https://avatars0.githubusercontent.com/u/20942571?s=460&v=4'
+ }
+}
+
+export const login = req => {
+ req = JSON.parse(req.body)
+ return {token: USER_MAP[req.userName].token}
+}
+
+export const getUserInfo = req => {
+ const params = getParams(req.url)
+ return USER_MAP[params.token]
+}
+
+export const logout = req => {
+ return null
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/mock/session.js b/src/JT808.DotNetty.Dashbord.UI/src/mock/session.js
new file mode 100644
index 0000000..becf0e9
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/mock/session.js
@@ -0,0 +1,32 @@
+import Mock from 'mockjs'
+import { setData } from '@/mock/commonResultData'
+
+export default {
+ RemoveByTerminalPhoneNo () {
+ return setData(Mock.mock({
+ 'boolean|1': true
+ }))
+ },
+ RemoveByChannelId () {
+ return setData(Mock.mock({
+ 'boolean|1': true
+ }))
+ },
+ GetAll () {
+ return setData([{
+ 'ChannelId': 'eadad23',
+ 'LastActiveTime': '2018-11-27 20:00:00',
+ 'StartTime': '2018-11-25 20:00:00',
+ 'TerminalPhoneNo': '123456789012',
+ 'WebApiPort': 828,
+ 'RemoteAddressIP': '127.0.0.1:11808'
+ }, {
+ 'ChannelId': 'eadad23',
+ 'LastActiveTime': '2018-11-27 20:00:00',
+ 'StartTime': '2018-11-25 20:00:00',
+ 'TerminalPhoneNo': '123456789013',
+ 'WebApiPort': 828,
+ 'RemoteAddressIP': '127.0.0.1:11808'
+ }])
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/mock/sourcePackage.js b/src/JT808.DotNetty.Dashbord.UI/src/mock/sourcePackage.js
new file mode 100644
index 0000000..c045661
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/mock/sourcePackage.js
@@ -0,0 +1,30 @@
+import Mock from 'mockjs'
+import { setData } from '@/mock/commonResultData'
+
+export default {
+ Add () {
+ return setData(Mock.mock({
+ 'boolean|1': true
+ }))
+ },
+ Remove () {
+ return setData(Mock.mock({
+ 'boolean|1': true
+ }))
+ },
+ GetAll () {
+ return setData([{
+ 'RemoteAddress': '127.0.0.1:6665',
+ 'LocalAddress': '127.0.0.1:6664',
+ 'Registered': true,
+ 'Active': true,
+ 'Open': true
+ }, {
+ 'RemoteAddress': '127.0.0.1:6667',
+ 'LocalAddress': '127.0.0.1:6666',
+ 'Registered': true,
+ 'Active': true,
+ 'Open': true
+ }])
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/mock/transmit.js b/src/JT808.DotNetty.Dashbord.UI/src/mock/transmit.js
new file mode 100644
index 0000000..feb1e8d
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/mock/transmit.js
@@ -0,0 +1,21 @@
+import Mock from 'mockjs'
+import { setData } from '@/mock/commonResultData'
+
+export default {
+ Add () {
+ return setData(Mock.mock({
+ 'boolean|1': true
+ }))
+ },
+ Remove () {
+ return setData(Mock.mock({
+ 'boolean|1': true
+ }))
+ },
+ GetAll () {
+ return setData([
+ '127.0.0.1:6665',
+ '127.0.0.1:6667'
+ ])
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/mock/unificationSend.js b/src/JT808.DotNetty.Dashbord.UI/src/mock/unificationSend.js
new file mode 100644
index 0000000..ab68c85
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/mock/unificationSend.js
@@ -0,0 +1,10 @@
+import Mock from 'mockjs'
+import { setData } from '@/mock/commonResultData'
+
+export default {
+ SendText () {
+ return setData(Mock.mock({
+ 'boolean|1': true
+ }))
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/mock/user.js b/src/JT808.DotNetty.Dashbord.UI/src/mock/user.js
new file mode 100644
index 0000000..9b28641
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/mock/user.js
@@ -0,0 +1,55 @@
+import Mock from 'mockjs'
+import { doCustomTimes } from '@/libs/util'
+const Random = Mock.Random
+
+export const getMessageInit = () => {
+ let unreadList = []
+ doCustomTimes(3, () => {
+ unreadList.push(Mock.mock({
+ title: Random.cword(10, 15),
+ create_time: '@date',
+ msg_id: Random.increment(100)
+ }))
+ })
+ let readedList = []
+ doCustomTimes(4, () => {
+ readedList.push(Mock.mock({
+ title: Random.cword(10, 15),
+ create_time: '@date',
+ msg_id: Random.increment(100)
+ }))
+ })
+ let trashList = []
+ doCustomTimes(2, () => {
+ trashList.push(Mock.mock({
+ title: Random.cword(10, 15),
+ create_time: '@date',
+ msg_id: Random.increment(100)
+ }))
+ })
+ return {
+ unread: unreadList,
+ readed: readedList,
+ trash: trashList
+ }
+}
+
+export const getContentByMsgId = () => {
+ return ` 这是消息内容,这个内容是使用富文本编辑器 编辑的,所以你可以看到一些格式
你可以查看Mock返回的数据格式,和api请求的接口,来确定你的后端接口的开发 使用你的真实接口后,前端页面基本不需要修改即可满足基本需求 快来试试吧 ${Random.csentence(100, 200)}
`
+}
+
+export const hasRead = () => {
+ return true
+}
+
+export const removeReaded = () => {
+ return true
+}
+
+export const restoreTrash = () => {
+ return true
+}
+
+export const messageCount = () => {
+ return 3
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/plugin/error-store/index.js b/src/JT808.DotNetty.Dashbord.UI/src/plugin/error-store/index.js
new file mode 100644
index 0000000..46b5941
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/plugin/error-store/index.js
@@ -0,0 +1,17 @@
+import store from '@/store'
+export default {
+ install (Vue, options) {
+ if (options.developmentOff && process.env.NODE_ENV === 'development') return
+ Vue.config.errorHandler = (error, vm, mes) => {
+ let info = {
+ type: 'script',
+ code: 0,
+ mes: error.message,
+ url: window.location.href
+ }
+ Vue.nextTick(() => {
+ store.dispatch('addErrorLog', info)
+ })
+ }
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/plugin/index.js b/src/JT808.DotNetty.Dashbord.UI/src/plugin/index.js
new file mode 100644
index 0000000..c47165b
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/plugin/index.js
@@ -0,0 +1,9 @@
+import config from '@/config'
+const { plugin } = config
+
+export default (Vue) => {
+ for (let name in plugin) {
+ const value = plugin[name]
+ Vue.use(require(`./${name}`).default, typeof value === 'object' ? value : undefined)
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/router/before-close.js b/src/JT808.DotNetty.Dashbord.UI/src/router/before-close.js
new file mode 100644
index 0000000..3320f1c
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/router/before-close.js
@@ -0,0 +1,17 @@
+import { Modal } from 'iview'
+
+const beforeClose = {
+ before_close_normal: (resolve) => {
+ Modal.confirm({
+ title: '确定要关闭这一页吗',
+ onOk: () => {
+ resolve(true)
+ },
+ onCancel: () => {
+ resolve(false)
+ }
+ })
+ }
+}
+
+export default beforeClose
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/router/index.js b/src/JT808.DotNetty.Dashbord.UI/src/router/index.js
new file mode 100644
index 0000000..db0cb84
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/router/index.js
@@ -0,0 +1,61 @@
+import Vue from 'vue'
+import Router from 'vue-router'
+import routes from './routers'
+import store from '@/store'
+import iView from 'iview'
+import { setToken, getToken, canTurnTo, setTitle } from '@/libs/util'
+import config from '@/config'
+const { homeName } = config
+
+Vue.use(Router)
+const router = new Router({
+ routes,
+ mode: 'history'
+})
+const LOGIN_PAGE_NAME = 'login'
+
+const turnTo = (to, access, next) => {
+ if (canTurnTo(to.name, access, routes)) next() // 有权限,可访问
+ else next({ replace: true, name: 'error_401' }) // 无权限,重定向到401页面
+}
+
+router.beforeEach((to, from, next) => {
+ iView.LoadingBar.start()
+ const token = getToken()
+ if (!token && to.name !== LOGIN_PAGE_NAME) {
+ // 未登录且要跳转的页面不是登录页
+ next({
+ name: LOGIN_PAGE_NAME // 跳转到登录页
+ })
+ } else if (!token && to.name === LOGIN_PAGE_NAME) {
+ // 未登陆且要跳转的页面是登录页
+ next() // 跳转
+ } else if (token && to.name === LOGIN_PAGE_NAME) {
+ // 已登录且要跳转的页面是登录页
+ next({
+ name: homeName // 跳转到homeName页
+ })
+ } else {
+ if (store.state.user.hasGetInfo) {
+ turnTo(to, store.state.user.access, next)
+ } else {
+ store.dispatch('getUserInfo').then(user => {
+ // 拉取用户信息,通过用户权限和跳转的页面的name来判断是否有权限访问;access必须是一个数组,如:['super_admin'] ['super_admin', 'admin']
+ turnTo(to, user.access, next)
+ }).catch(() => {
+ setToken('')
+ next({
+ name: 'login'
+ })
+ })
+ }
+ }
+})
+
+router.afterEach(to => {
+ setTitle(to, router.app)
+ iView.LoadingBar.finish()
+ window.scrollTo(0, 0)
+})
+
+export default router
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/router/routers.js b/src/JT808.DotNetty.Dashbord.UI/src/router/routers.js
new file mode 100644
index 0000000..4757c3e
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/router/routers.js
@@ -0,0 +1,195 @@
+import Main from '@/components/main'
+import parentView from '@/components/parent-view'
+
+/**
+ * iview-admin中meta除了原生参数外可配置的参数:
+ * meta: {
+ * title: { String|Number|Function }
+ * 显示在侧边栏、面包屑和标签栏的文字
+ * 使用'{{ 多语言字段 }}'形式结合多语言使用,例子看多语言的路由配置;
+ * 可以传入一个回调函数,参数是当前路由对象,例子看动态路由和带参路由
+ * hideInBread: (false) 设为true后此级路由将不会出现在面包屑中,示例看QQ群路由配置
+ * hideInMenu: (false) 设为true后在左侧菜单不会显示该页面选项
+ * notCache: (false) 设为true后页面在切换标签后不会缓存,如果需要缓存,无需设置这个字段,而且需要设置页面组件name属性和路由配置的name一致
+ * access: (null) 可访问该页面的权限数组,当前路由设置的权限会影响子路由
+ * icon: (-) 该页面在左侧菜单、面包屑和标签导航处显示的图标,如果是自定义图标,需要在图标名称前加下划线'_'
+ * beforeCloseName: (-) 设置该字段,则在关闭当前tab页时会去'@/router/before-close.js'里寻找该字段名对应的方法,作为关闭前的钩子函数
+ * }
+ */
+
+export default [
+ {
+ path: '/login',
+ name: 'login',
+ meta: {
+ title: 'Login - 登录',
+ hideInMenu: true
+ },
+ component: () => import('@/view/login/login.vue')
+ },
+ {
+ path: '/',
+ name: '_home',
+ redirect: '/home',
+ component: Main,
+ meta: {
+ hideInMenu: true,
+ notCache: true
+ },
+ children: [
+ {
+ path: '/home',
+ name: 'home',
+ meta: {
+ hideInMenu: true,
+ title: '首页',
+ notCache: true,
+ icon: 'md-home'
+ },
+ component: () => import('@/view/single-page/home')
+ }
+ ]
+ },
+ {
+ path: '/message',
+ name: 'message',
+ component: Main,
+ meta: {
+ hideInBread: true,
+ hideInMenu: true
+ },
+ children: [
+ {
+ path: 'message_page',
+ name: 'message_page',
+ meta: {
+ icon: 'md-notifications',
+ title: '消息中心'
+ },
+ component: () => import('@/view/single-page/message/index.vue')
+ }
+ ]
+ },
+ {
+ path: '/session',
+ name: 'session',
+ meta: {
+ hideInBread: true
+ },
+ component: Main,
+ children: [
+ {
+ path: '/session',
+ name: '会话管理',
+ meta: {
+ icon: 'ios-hammer',
+ title: '会话管理'
+ },
+ component: () => import('@/view/session/session.vue')
+ }
+ ]
+ },
+ {
+ path: '/sourcepackage',
+ name: 'sourcePackage',
+ meta: {
+ hideInBread: true
+ },
+ component: Main,
+ children: [
+ {
+ path: '/sourcepackage',
+ name: '原包管理',
+ meta: {
+ icon: 'ios-hammer',
+ title: '原包管理',
+ beforeCloseName: 'before_close_normal'
+ },
+ component: () => import('@/view/sourcepackage/sourcepackage.vue')
+ }
+ ]
+ },
+ {
+ path: '/transmit',
+ name: 'transmit',
+ meta: {
+ hideInBread: true
+ },
+ component: Main,
+ children: [
+ {
+ path: '/transmit',
+ name: '转发管理',
+ meta: {
+ icon: 'ios-hammer',
+ title: '转发管理',
+ beforeCloseName: 'before_close_normal'
+ },
+ component: () => import('@/view/transmit/transmit.vue')
+ }
+ ]
+ },
+ {
+ path: '/error_store',
+ name: 'error_store',
+ meta: {
+ hideInBread: true
+ },
+ component: Main,
+ children: [
+ {
+ path: 'error_store_page',
+ name: 'error_store_page',
+ meta: {
+ icon: 'ios-bug',
+ title: '错误收集'
+ },
+ component: () => import('@/view/error-store/error-store.vue')
+ }
+ ]
+ },
+ {
+ path: '/error_logger',
+ name: 'error_logger',
+ meta: {
+ hideInBread: true,
+ hideInMenu: true
+ },
+ component: Main,
+ children: [
+ {
+ path: 'error_logger_page',
+ name: 'error_logger_page',
+ meta: {
+ icon: 'ios-bug',
+ title: '错误收集'
+ },
+ component: () => import('@/view/single-page/error-logger.vue')
+ }
+ ]
+ },
+ {
+ path: '/401',
+ name: 'error_401',
+ meta: {
+ hideInMenu: true
+ },
+ component: () => import('@/view/error-page/401.vue')
+ },
+ {
+ path: '/500',
+ name: 'error_500',
+ meta: {
+ hideInMenu: true
+ },
+ component: () => import('@/view/error-page/500.vue')
+ },
+ {
+ path: '*',
+ name: 'error_404',
+ meta: {
+ hideInMenu: true
+ },
+ component: () => import('@/view/error-page/404.vue')
+ }
+]
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/store/index.js b/src/JT808.DotNetty.Dashbord.UI/src/store/index.js
new file mode 100644
index 0000000..2c8c77e
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/store/index.js
@@ -0,0 +1,23 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+
+import user from './module/user'
+import app from './module/app'
+
+Vue.use(Vuex)
+
+export default new Vuex.Store({
+ state: {
+ //
+ },
+ mutations: {
+ //
+ },
+ actions: {
+ //
+ },
+ modules: {
+ user,
+ app
+ }
+})
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/store/module/app.js b/src/JT808.DotNetty.Dashbord.UI/src/store/module/app.js
new file mode 100644
index 0000000..227c42e
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/store/module/app.js
@@ -0,0 +1,115 @@
+import {
+ getBreadCrumbList,
+ setTagNavListInLocalstorage,
+ getMenuByRouter,
+ getTagNavListFromLocalstorage,
+ getHomeRoute,
+ getNextRoute,
+ routeHasExist,
+ routeEqual,
+ getRouteTitleHandled,
+ localSave,
+ localRead
+} from '@/libs/util'
+import beforeClose from '@/router/before-close'
+import { saveErrorLogger } from '@/api/data'
+import router from '@/router'
+import routers from '@/router/routers'
+import config from '@/config'
+const { homeName } = config
+
+const closePage = (state, route) => {
+ const nextRoute = getNextRoute(state.tagNavList, route)
+ state.tagNavList = state.tagNavList.filter(item => {
+ return !routeEqual(item, route)
+ })
+ router.push(nextRoute)
+}
+
+export default {
+ state: {
+ breadCrumbList: [],
+ tagNavList: [],
+ homeRoute: {},
+ local: localRead('local'),
+ errorList: [],
+ hasReadErrorPage: false
+ },
+ getters: {
+ menuList: (state, getters, rootState) => getMenuByRouter(routers, rootState.user.access),
+ errorCount: state => state.errorList.length
+ },
+ mutations: {
+ setBreadCrumb (state, route) {
+ state.breadCrumbList = getBreadCrumbList(route, state.homeRoute)
+ },
+ setHomeRoute (state, routes) {
+ state.homeRoute = getHomeRoute(routes, homeName)
+ },
+ setTagNavList (state, list) {
+ let tagList = []
+ if (list) {
+ tagList = [...list]
+ } else tagList = getTagNavListFromLocalstorage() || []
+ if (tagList[0] && tagList[0].name !== homeName) tagList.shift()
+ let homeTagIndex = tagList.findIndex(item => item.name === homeName)
+ if (homeTagIndex > 0) {
+ let homeTag = tagList.splice(homeTagIndex, 1)[0]
+ tagList.unshift(homeTag)
+ }
+ state.tagNavList = tagList
+ setTagNavListInLocalstorage([...tagList])
+ },
+ closeTag (state, route) {
+ let tag = state.tagNavList.filter(item => routeEqual(item, route))
+ route = tag[0] ? tag[0] : null
+ if (!route) return
+ if (route.meta && route.meta.beforeCloseName && route.meta.beforeCloseName in beforeClose) {
+ new Promise(beforeClose[route.meta.beforeCloseName]).then(close => {
+ if (close) {
+ closePage(state, route)
+ }
+ })
+ } else {
+ closePage(state, route)
+ }
+ },
+ addTag (state, { route, type = 'unshift' }) {
+ let router = getRouteTitleHandled(route)
+ if (!routeHasExist(state.tagNavList, router)) {
+ if (type === 'push') state.tagNavList.push(router)
+ else {
+ if (router.name === homeName) state.tagNavList.unshift(router)
+ else state.tagNavList.splice(1, 0, router)
+ }
+ setTagNavListInLocalstorage([...state.tagNavList])
+ }
+ },
+ setLocal (state, lang) {
+ localSave('local', lang)
+ state.local = lang
+ },
+ addError (state, error) {
+ state.errorList.push(error)
+ },
+ setHasReadErrorLoggerStatus (state, status = true) {
+ state.hasReadErrorPage = status
+ }
+ },
+ actions: {
+ addErrorLog ({ commit, rootState }, info) {
+ if (!window.location.href.includes('error_logger_page')) commit('setHasReadErrorLoggerStatus', false)
+ const { user: { token, userId, userName } } = rootState
+ let data = {
+ ...info,
+ time: Date.parse(new Date()),
+ token,
+ userId,
+ userName
+ }
+ saveErrorLogger(info).then(() => {
+ commit('addError', data)
+ })
+ }
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/store/module/user.js b/src/JT808.DotNetty.Dashbord.UI/src/store/module/user.js
new file mode 100644
index 0000000..e1aa311
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/store/module/user.js
@@ -0,0 +1,217 @@
+import {
+ login,
+ logout,
+ getUserInfo,
+ getMessage,
+ getContentByMsgId,
+ hasRead,
+ removeReaded,
+ restoreTrash,
+ getUnreadCount
+} from '@/api/user'
+import { setToken, getToken } from '@/libs/util'
+
+export default {
+ state: {
+ userName: '',
+ userId: '',
+ avatorImgPath: '',
+ token: getToken(),
+ access: '',
+ hasGetInfo: false,
+ unreadCount: 0,
+ messageUnreadList: [],
+ messageReadedList: [],
+ messageTrashList: [],
+ messageContentStore: {}
+ },
+ mutations: {
+ setAvator (state, avatorPath) {
+ state.avatorImgPath = avatorPath
+ },
+ setUserId (state, id) {
+ state.userId = id
+ },
+ setUserName (state, name) {
+ state.userName = name
+ },
+ setAccess (state, access) {
+ state.access = access
+ },
+ setToken (state, token) {
+ state.token = token
+ setToken(token)
+ },
+ setHasGetInfo (state, status) {
+ state.hasGetInfo = status
+ },
+ setMessageCount (state, count) {
+ state.unreadCount = count
+ },
+ setMessageUnreadList (state, list) {
+ state.messageUnreadList = list
+ },
+ setMessageReadedList (state, list) {
+ state.messageReadedList = list
+ },
+ setMessageTrashList (state, list) {
+ state.messageTrashList = list
+ },
+ updateMessageContentStore (state, { msg_id, content }) {
+ state.messageContentStore[msg_id] = content
+ },
+ moveMsg (state, { from, to, msg_id }) {
+ const index = state[from].findIndex(_ => _.msg_id === msg_id)
+ const msgItem = state[from].splice(index, 1)[0]
+ msgItem.loading = false
+ state[to].unshift(msgItem)
+ }
+ },
+ getters: {
+ messageUnreadCount: state => state.messageUnreadList.length,
+ messageReadedCount: state => state.messageReadedList.length,
+ messageTrashCount: state => state.messageTrashList.length
+ },
+ actions: {
+ // 登录
+ handleLogin ({ commit }, {userName, password}) {
+ userName = userName.trim()
+ return new Promise((resolve, reject) => {
+ login({
+ userName,
+ password
+ }).then(res => {
+ const data = res.data
+ commit('setToken', data.token)
+ resolve()
+ }).catch(err => {
+ reject(err)
+ })
+ })
+ },
+ // 退出登录
+ handleLogOut ({ state, commit }) {
+ return new Promise((resolve, reject) => {
+ logout(state.token).then(() => {
+ commit('setToken', '')
+ commit('setAccess', [])
+ resolve()
+ }).catch(err => {
+ reject(err)
+ })
+ // 如果你的退出登录无需请求接口,则可以直接使用下面三行代码而无需使用logout调用接口
+ // commit('setToken', '')
+ // commit('setAccess', [])
+ // resolve()
+ })
+ },
+ // 获取用户相关信息
+ getUserInfo ({ state, commit }) {
+ return new Promise((resolve, reject) => {
+ try {
+ getUserInfo(state.token).then(res => {
+ const data = res.data
+ commit('setAvator', data.avator)
+ commit('setUserName', data.name)
+ commit('setUserId', data.user_id)
+ commit('setAccess', data.access)
+ commit('setHasGetInfo', true)
+ resolve(data)
+ }).catch(err => {
+ reject(err)
+ })
+ } catch (error) {
+ reject(error)
+ }
+ })
+ },
+ // 此方法用来获取未读消息条数,接口只返回数值,不返回消息列表
+ getUnreadMessageCount ({ state, commit }) {
+ getUnreadCount().then(res => {
+ const { data } = res
+ commit('setMessageCount', data)
+ })
+ },
+ // 获取消息列表,其中包含未读、已读、回收站三个列表
+ getMessageList ({ state, commit }) {
+ return new Promise((resolve, reject) => {
+ getMessage().then(res => {
+ const { unread, readed, trash } = res.data
+ commit('setMessageUnreadList', unread.sort((a, b) => new Date(b.create_time) - new Date(a.create_time)))
+ commit('setMessageReadedList', readed.map(_ => {
+ _.loading = false
+ return _
+ }).sort((a, b) => new Date(b.create_time) - new Date(a.create_time)))
+ commit('setMessageTrashList', trash.map(_ => {
+ _.loading = false
+ return _
+ }).sort((a, b) => new Date(b.create_time) - new Date(a.create_time)))
+ resolve()
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+ // 根据当前点击的消息的id获取内容
+ getContentByMsgId ({ state, commit }, { msg_id }) {
+ return new Promise((resolve, reject) => {
+ let contentItem = state.messageContentStore[msg_id]
+ if (contentItem) {
+ resolve(contentItem)
+ } else {
+ getContentByMsgId(msg_id).then(res => {
+ const content = res.data
+ commit('updateMessageContentStore', { msg_id, content })
+ resolve(content)
+ })
+ }
+ })
+ },
+ // 把一个未读消息标记为已读
+ hasRead ({ state, commit }, { msg_id }) {
+ return new Promise((resolve, reject) => {
+ hasRead(msg_id).then(() => {
+ commit('moveMsg', {
+ from: 'messageUnreadList',
+ to: 'messageReadedList',
+ msg_id
+ })
+ commit('setMessageCount', state.unreadCount - 1)
+ resolve()
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+ // 删除一个已读消息到回收站
+ removeReaded ({ commit }, { msg_id }) {
+ return new Promise((resolve, reject) => {
+ removeReaded(msg_id).then(() => {
+ commit('moveMsg', {
+ from: 'messageReadedList',
+ to: 'messageTrashList',
+ msg_id
+ })
+ resolve()
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+ // 还原一个已删除消息到已读消息
+ restoreTrash ({ commit }, { msg_id }) {
+ return new Promise((resolve, reject) => {
+ restoreTrash(msg_id).then(() => {
+ commit('moveMsg', {
+ from: 'messageTrashList',
+ to: 'messageReadedList',
+ msg_id
+ })
+ resolve()
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ }
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/charts/bar.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/charts/bar.vue
new file mode 100644
index 0000000..b0a2709
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/charts/bar.vue
@@ -0,0 +1,58 @@
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/charts/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/charts/index.js
new file mode 100644
index 0000000..2ca3c91
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/charts/index.js
@@ -0,0 +1,3 @@
+import ChartPie from './pie.vue'
+import ChartBar from './bar.vue'
+export { ChartPie, ChartBar }
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/charts/pie.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/charts/pie.vue
new file mode 100644
index 0000000..c86d68c
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/charts/pie.vue
@@ -0,0 +1,70 @@
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/common-icon/common-icon.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/common-icon/common-icon.vue
new file mode 100644
index 0000000..768fa1b
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/common-icon/common-icon.vue
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/common-icon/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/common-icon/index.js
new file mode 100644
index 0000000..1207d15
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/common-icon/index.js
@@ -0,0 +1,2 @@
+import CommonIcon from './common-icon.vue'
+export default CommonIcon
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/common/common.less b/src/JT808.DotNetty.Dashbord.UI/src/view/components/common/common.less
new file mode 100644
index 0000000..3c3e5b1
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/common/common.less
@@ -0,0 +1,8 @@
+.no-select{
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/common/util.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/common/util.js
new file mode 100644
index 0000000..2129e7a
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/common/util.js
@@ -0,0 +1,3 @@
+export const showTitle = (item, vm) => {
+ return vm.$config.useI18n ? vm.$t(item.name) : ((item.meta && item.meta.title) || item.name)
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/count-to/count-to.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/count-to/count-to.vue
new file mode 100644
index 0000000..a10e3ff
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/count-to/count-to.vue
@@ -0,0 +1,174 @@
+
+
+
+
{{ init }} {{ unitText }}
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/count-to/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/count-to/index.js
new file mode 100644
index 0000000..17b3332
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/count-to/index.js
@@ -0,0 +1,2 @@
+import countTo from './count-to.vue'
+export default countTo
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/count-to/index.less b/src/JT808.DotNetty.Dashbord.UI/src/view/components/count-to/index.less
new file mode 100644
index 0000000..e17d7c6
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/count-to/index.less
@@ -0,0 +1,10 @@
+@prefix: ~"count-to";
+
+.@{prefix}-wrapper{
+ .content-outer{
+ display: inline-block;
+ .@{prefix}-unit-text{
+ font-style: normal;
+ }
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/cropper/cropper.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/cropper/cropper.vue
new file mode 100644
index 0000000..6b7c3a6
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/cropper/cropper.vue
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/cropper/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/cropper/index.js
new file mode 100644
index 0000000..e7db5ea
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/cropper/index.js
@@ -0,0 +1,2 @@
+import Cropper from './index.vue'
+export default Cropper
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/cropper/index.less b/src/JT808.DotNetty.Dashbord.UI/src/view/components/cropper/index.less
new file mode 100644
index 0000000..cdf431d
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/cropper/index.less
@@ -0,0 +1,35 @@
+.bg{
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC")
+}
+.cropper-wrapper{
+ width: 600px;
+ height: 340px;
+ .img-box{
+ height: 340px;
+ width: 430px;
+ border: 1px solid #ebebeb;
+ display: inline-block;
+ .bg;
+ img{
+ max-width: 100%;
+ display: block;
+ }
+ }
+ .right-con{
+ display: inline-block;
+ width: 170px;
+ vertical-align: top;
+ box-sizing: border-box;
+ padding: 0 10px;
+ .preview-box{
+ height: 150px !important;
+ width: 100% !important;
+ overflow: hidden;
+ border: 1px solid #ebebeb;
+ .bg;
+ }
+ .button-box{
+ padding: 10px 0 0;
+ }
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/cropper/index.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/cropper/index.vue
new file mode 100644
index 0000000..7bb664f
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/cropper/index.vue
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/drag-list/drag-list.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/drag-list/drag-list.vue
new file mode 100644
index 0000000..664abc9
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/drag-list/drag-list.vue
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+ {{ itemLeft }}
+
+
+
+
+
+
+
+ {{ itemRight }}
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/drag-list/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/drag-list/index.js
new file mode 100644
index 0000000..d2bb972
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/drag-list/index.js
@@ -0,0 +1,2 @@
+import DragList from './drag-list.vue'
+export default DragList
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/editor/editor.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/editor/editor.vue
new file mode 100644
index 0000000..881c73e
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/editor/editor.vue
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/editor/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/editor/index.js
new file mode 100644
index 0000000..56e8de2
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/editor/index.js
@@ -0,0 +1,2 @@
+import Editor from './editor.vue'
+export default Editor
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/icons/icons.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/icons/icons.vue
new file mode 100644
index 0000000..50b7183
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/icons/icons.vue
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/icons/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/icons/index.js
new file mode 100644
index 0000000..bdc38b2
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/icons/index.js
@@ -0,0 +1,2 @@
+import Icons from './icons.vue'
+export default Icons
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/info-card/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/info-card/index.js
new file mode 100644
index 0000000..354419b
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/info-card/index.js
@@ -0,0 +1,2 @@
+import InforCard from './infor-card.vue'
+export default InforCard
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/info-card/infor-card.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/info-card/infor-card.vue
new file mode 100644
index 0000000..6240d0e
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/info-card/infor-card.vue
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/login-form/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/login-form/index.js
new file mode 100644
index 0000000..d480c28
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/login-form/index.js
@@ -0,0 +1,2 @@
+import LoginForm from './login-form.vue'
+export default LoginForm
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/login-form/login-form.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/login-form/login-form.vue
new file mode 100644
index 0000000..497c08c
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/login-form/login-form.vue
@@ -0,0 +1,72 @@
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/a-back-top/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/a-back-top/index.js
new file mode 100644
index 0000000..4da0014
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/a-back-top/index.js
@@ -0,0 +1,2 @@
+import ABackTop from './index.vue'
+export default ABackTop
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/a-back-top/index.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/a-back-top/index.vue
new file mode 100644
index 0000000..f26f95c
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/a-back-top/index.vue
@@ -0,0 +1,90 @@
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/error-store/error-store.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/error-store/error-store.vue
new file mode 100644
index 0000000..9941677
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/error-store/error-store.vue
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/error-store/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/error-store/index.js
new file mode 100644
index 0000000..a777df1
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/error-store/index.js
@@ -0,0 +1,2 @@
+import ErrorStore from './error-store.vue'
+export default ErrorStore
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/fullscreen/fullscreen.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/fullscreen/fullscreen.vue
new file mode 100644
index 0000000..d5213fa
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/fullscreen/fullscreen.vue
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/fullscreen/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/fullscreen/index.js
new file mode 100644
index 0000000..422c7c1
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/fullscreen/index.js
@@ -0,0 +1,2 @@
+import Fullscreen from './fullscreen.vue'
+export default Fullscreen
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.less b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.less
new file mode 100644
index 0000000..1ace1eb
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.less
@@ -0,0 +1,4 @@
+.custom-bread-crumb{
+ display: inline-block;
+ vertical-align: top;
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.vue
new file mode 100644
index 0000000..51b121d
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.vue
@@ -0,0 +1,46 @@
+
+
+
+
+
+ {{ showTitle(item) }}
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/custom-bread-crumb/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/custom-bread-crumb/index.js
new file mode 100644
index 0000000..a590fe0
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/custom-bread-crumb/index.js
@@ -0,0 +1,2 @@
+import customBreadCrumb from './custom-bread-crumb.vue'
+export default customBreadCrumb
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/header-bar.less b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/header-bar.less
new file mode 100644
index 0000000..c245d19
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/header-bar.less
@@ -0,0 +1,14 @@
+.header-bar{
+ width: 100%;
+ height: 100%;
+ position: relative;
+ .custom-content-con{
+ float: right;
+ height: auto;
+ padding-right: 20px;
+ line-height: 64px;
+ & > *{
+ float: right;
+ }
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/header-bar.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/header-bar.vue
new file mode 100644
index 0000000..1452146
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/header-bar.vue
@@ -0,0 +1,34 @@
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/index.js
new file mode 100644
index 0000000..3d4a170
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/index.js
@@ -0,0 +1,2 @@
+import HeaderBar from './header-bar'
+export default HeaderBar
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/sider-trigger/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/sider-trigger/index.js
new file mode 100644
index 0000000..15853f4
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/sider-trigger/index.js
@@ -0,0 +1,2 @@
+import siderTrigger from './sider-trigger.vue'
+export default siderTrigger
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/sider-trigger/sider-trigger.less b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/sider-trigger/sider-trigger.less
new file mode 100644
index 0000000..eb50999
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/sider-trigger/sider-trigger.less
@@ -0,0 +1,21 @@
+.trans{
+ transition: transform .2s ease;
+}
+@size: 40px;
+.sider-trigger-a{
+ padding: 6px;
+ width: @size;
+ height: @size;
+ display: inline-block;
+ text-align: center;
+ color: #5c6b77;
+ margin-top: 12px;
+ i{
+ .trans;
+ vertical-align: top;
+ }
+ &.collapsed i{
+ transform: rotateZ(90deg);
+ .trans;
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/sider-trigger/sider-trigger.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/sider-trigger/sider-trigger.vue
new file mode 100644
index 0000000..200e18f
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/header-bar/sider-trigger/sider-trigger.vue
@@ -0,0 +1,27 @@
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/language/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/language/index.js
new file mode 100644
index 0000000..de2a90a
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/language/index.js
@@ -0,0 +1,2 @@
+import Language from './language.vue'
+export default Language
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/language/language.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/language/language.vue
new file mode 100644
index 0000000..b1d92ec
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/language/language.vue
@@ -0,0 +1,51 @@
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/side-menu/collapsed-menu.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/side-menu/collapsed-menu.vue
new file mode 100644
index 0000000..73ac93e
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/side-menu/collapsed-menu.vue
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/side-menu/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/side-menu/index.js
new file mode 100644
index 0000000..5b36868
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/side-menu/index.js
@@ -0,0 +1,2 @@
+import SideMenu from './side-menu.vue'
+export default SideMenu
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/side-menu/item-mixin.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/side-menu/item-mixin.js
new file mode 100644
index 0000000..8b807af
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/side-menu/item-mixin.js
@@ -0,0 +1,21 @@
+export default {
+ props: {
+ parentItem: {
+ type: Object,
+ default: () => {}
+ },
+ theme: String,
+ iconSize: Number
+ },
+ computed: {
+ parentName () {
+ return this.parentItem.name
+ },
+ children () {
+ return this.parentItem.children
+ },
+ textColor () {
+ return this.theme === 'dark' ? '#fff' : '#495060'
+ }
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/side-menu/mixin.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/side-menu/mixin.js
new file mode 100644
index 0000000..21b618b
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/side-menu/mixin.js
@@ -0,0 +1,18 @@
+import CommonIcon from '_c/common-icon'
+import { showTitle } from '@/libs/util'
+export default {
+ components: {
+ CommonIcon
+ },
+ methods: {
+ showTitle (item) {
+ return showTitle(item, this)
+ },
+ showChildren (item) {
+ return item.children && (item.children.length > 1 || (item.meta && item.meta.showAlways))
+ },
+ getNameOrHref (item, children0) {
+ return item.href ? `isTurnByHref_${item.href}` : (children0 ? item.children[0].name : item.name)
+ }
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/side-menu/side-menu-item.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/side-menu/side-menu-item.vue
new file mode 100644
index 0000000..12338a6
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/side-menu/side-menu-item.vue
@@ -0,0 +1,26 @@
+
+
+
+
+ {{ showTitle(parentItem) }}
+
+
+
+
+ {{ showTitle(item.children[0]) }}
+
+
+
+ {{ showTitle(item) }}
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/side-menu/side-menu.less b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/side-menu/side-menu.less
new file mode 100644
index 0000000..4716d82
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/side-menu/side-menu.less
@@ -0,0 +1,40 @@
+.side-menu-wrapper{
+ user-select: none;
+ .menu-collapsed{
+ padding-top: 10px;
+
+ .ivu-dropdown{
+ width: 100%;
+ .ivu-dropdown-rel a{
+ width: 100%;
+ }
+ }
+ .ivu-tooltip{
+ width: 100%;
+ .ivu-tooltip-rel{
+ width: 100%;
+ }
+ .ivu-tooltip-popper .ivu-tooltip-content{
+ .ivu-tooltip-arrow{
+ border-right-color: #fff;
+ }
+ .ivu-tooltip-inner{
+ background: #fff;
+ color: #495060;
+ }
+ }
+ }
+
+
+ }
+ a.drop-menu-a{
+ display: inline-block;
+ padding: 6px 15px;
+ width: 100%;
+ text-align: center;
+ color: #495060;
+ }
+}
+.menu-title{
+ padding-left: 6px;
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/side-menu/side-menu.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/side-menu/side-menu.vue
new file mode 100644
index 0000000..ee18e86
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/side-menu/side-menu.vue
@@ -0,0 +1,114 @@
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/tags-nav/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/tags-nav/index.js
new file mode 100644
index 0000000..585792a
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/tags-nav/index.js
@@ -0,0 +1,2 @@
+import TagsNav from './tags-nav.vue'
+export default TagsNav
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/tags-nav/tags-nav.less b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/tags-nav/tags-nav.less
new file mode 100644
index 0000000..a4c8c5d
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/tags-nav/tags-nav.less
@@ -0,0 +1,87 @@
+.no-select{
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+.size{
+ width: 100%;
+ height: 100%;
+}
+.tags-nav{
+ position: relative;
+ border-top: 1px solid #F0F0F0;
+ border-bottom: 1px solid #F0F0F0;
+ .no-select;
+ .size;
+ .close-con{
+ position: absolute;
+ right: 0;
+ top: 0;
+ height: 100%;
+ width: 32px;
+ background: #fff;
+ text-align: center;
+ z-index: 10;
+ }
+ .btn-con{
+ position: absolute;
+ top: 0px;
+ height: 100%;
+ background: #fff;
+ padding-top: 3px;
+ z-index: 10;
+ button{
+ padding: 6px 4px;
+ line-height: 14px;
+ text-align: center;
+ }
+ &.left-btn{
+ left: 0px;
+ }
+ &.right-btn{
+ right: 32px;
+ border-right: 1px solid #F0F0F0;
+ }
+ }
+ .scroll-outer{
+ position: absolute;
+ left: 28px;
+ right: 61px;
+ top: 0;
+ bottom: 0;
+ box-shadow: 0px 0 3px 2px rgba(100,100,100,.1) inset;
+ .scroll-body{
+ height: ~"calc(100% - 1px)";
+ display: inline-block;
+ padding: 1px 4px 0;
+ position: absolute;
+ overflow: visible;
+ white-space: nowrap;
+ transition: left .3s ease;
+ .ivu-tag-dot-inner{
+ transition: background .2s ease;
+ }
+ }
+ }
+ .contextmenu {
+ position: absolute;
+ margin: 0;
+ padding: 5px 0;
+ background: #fff;
+ z-index: 100;
+ list-style-type: none;
+ border-radius: 4px;
+ box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
+ li {
+ margin: 0;
+ padding: 5px 15px;
+ cursor: pointer;
+ &:hover {
+ background: #eee;
+ }
+ }
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/tags-nav/tags-nav.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/tags-nav/tags-nav.vue
new file mode 100644
index 0000000..2dbca44
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/tags-nav/tags-nav.vue
@@ -0,0 +1,209 @@
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/user/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/user/index.js
new file mode 100644
index 0000000..3d04a5c
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/user/index.js
@@ -0,0 +1,2 @@
+import User from './user.vue'
+export default User
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/user/user.less b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/user/user.less
new file mode 100644
index 0000000..a3c95af
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/user/user.less
@@ -0,0 +1,12 @@
+.user{
+ &-avator-dropdown{
+ cursor: pointer;
+ display: inline-block;
+ // height: 64px;
+ vertical-align: middle;
+ // line-height: 64px;
+ .ivu-badge-dot{
+ top: 16px;
+ }
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/user/user.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/user/user.vue
new file mode 100644
index 0000000..3d4689d
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/components/user/user.vue
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+ 消息中心
+
+ 退出登录
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/index.js
new file mode 100644
index 0000000..7df2a08
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/index.js
@@ -0,0 +1,2 @@
+import Main from './main.vue'
+export default Main
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/main.less b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/main.less
new file mode 100644
index 0000000..fd0cd41
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/main.less
@@ -0,0 +1,75 @@
+.main{
+ .logo-con{
+ height: 64px;
+ padding: 10px;
+ img{
+ height: 44px;
+ width: auto;
+ display: block;
+ margin: 0 auto;
+ }
+ }
+ .header-con{
+ background: #fff;
+ padding: 0 20px;
+ width: 100%;
+ }
+ .main-layout-con{
+ height: 100%;
+ overflow: hidden;
+ }
+ .main-content-con{
+ height: ~"calc(100% - 60px)";
+ overflow: hidden;
+ }
+ .tag-nav-wrapper{
+ padding: 0;
+ height:40px;
+ background:#F0F0F0;
+ }
+ .content-wrapper{
+ padding: 18px;
+ height: ~"calc(100% - 80px)";
+ overflow: auto;
+ }
+ .left-sider{
+ .ivu-layout-sider-children{
+ overflow-y: scroll;
+ margin-right: -18px;
+ }
+ }
+}
+.ivu-menu-item > i{
+ margin-right: 12px !important;
+}
+.ivu-menu-submenu > .ivu-menu > .ivu-menu-item > i {
+ margin-right: 8px !important;
+}
+.collased-menu-dropdown{
+ width: 100%;
+ margin: 0;
+ line-height: normal;
+ padding: 7px 0 6px 16px;
+ clear: both;
+ font-size: 12px !important;
+ white-space: nowrap;
+ list-style: none;
+ cursor: pointer;
+ transition: background 0.2s ease-in-out;
+ &:hover{
+ background: rgba(100, 100, 100, 0.1);
+ }
+ & * {
+ color: #515a6e;
+ }
+ .ivu-menu-item > i{
+ margin-right: 12px !important;
+ }
+ .ivu-menu-submenu > .ivu-menu > .ivu-menu-item > i {
+ margin-right: 8px !important;
+ }
+}
+
+.ivu-select-dropdown.ivu-dropdown-transfer{
+ max-height: 400px;
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/main.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/main.vue
new file mode 100644
index 0000000..3c1603f
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/main/main.vue
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/markdown/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/markdown/index.js
new file mode 100644
index 0000000..99e0cda
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/markdown/index.js
@@ -0,0 +1,2 @@
+import MarkdownEditor from './markdown.vue'
+export default MarkdownEditor
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/markdown/markdown.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/markdown/markdown.vue
new file mode 100644
index 0000000..242b3cc
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/markdown/markdown.vue
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/parent-view/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/parent-view/index.js
new file mode 100644
index 0000000..a959c65
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/parent-view/index.js
@@ -0,0 +1,2 @@
+import ParentView from './parent-view.vue'
+export default ParentView
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/parent-view/parent-view.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/parent-view/parent-view.vue
new file mode 100644
index 0000000..84259f3
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/parent-view/parent-view.vue
@@ -0,0 +1,20 @@
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/paste-editor/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/paste-editor/index.js
new file mode 100644
index 0000000..f02331a
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/paste-editor/index.js
@@ -0,0 +1,2 @@
+import PasteEditor from './paste-editor.vue'
+export default PasteEditor
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/paste-editor/paste-editor.less b/src/JT808.DotNetty.Dashbord.UI/src/view/components/paste-editor/paste-editor.less
new file mode 100644
index 0000000..2ffd2bd
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/paste-editor/paste-editor.less
@@ -0,0 +1,26 @@
+.paste-editor-wrapper{
+ width: 100%;
+ height: 100%;
+ border: 1px dashed gainsboro;
+ textarea.textarea-el{
+ width: 100%;
+ height: 100%;
+ }
+ .CodeMirror{
+ height: 100%;
+ padding: 0;
+ .CodeMirror-code div .CodeMirror-line > span > span.cm-tab{
+ &::after{
+ content: '→';
+ color: #BFBFBF;
+ }
+ }
+ }
+ .first-row{
+ font-weight: 700;
+ font-size: 14px;
+ }
+ .incorrect-row{
+ background: #F5CBD1;
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/paste-editor/paste-editor.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/paste-editor/paste-editor.vue
new file mode 100644
index 0000000..083d6c4
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/paste-editor/paste-editor.vue
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/paste-editor/plugins/placeholder.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/paste-editor/plugins/placeholder.js
new file mode 100644
index 0000000..d9bf77e
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/paste-editor/plugins/placeholder.js
@@ -0,0 +1,58 @@
+export default (codemirror) => {
+ (function (mod) {
+ mod(codemirror)
+ })(function (CodeMirror) {
+ CodeMirror.defineOption('placeholder', '', function (cm, val, old) {
+ var prev = old && old !== CodeMirror.Init
+ if (val && !prev) {
+ cm.on('blur', onBlur)
+ cm.on('change', onChange)
+ cm.on('swapDoc', onChange)
+ onChange(cm)
+ } else if (!val && prev) {
+ cm.off('blur', onBlur)
+ cm.off('change', onChange)
+ cm.off('swapDoc', onChange)
+ clearPlaceholder(cm)
+ var wrapper = cm.getWrapperElement()
+ wrapper.className = wrapper.className.replace(' CodeMirror-empty', '')
+ }
+
+ if (val && !cm.hasFocus()) onBlur(cm)
+ })
+
+ function clearPlaceholder (cm) {
+ if (cm.state.placeholder) {
+ cm.state.placeholder.parentNode.removeChild(cm.state.placeholder)
+ cm.state.placeholder = null
+ }
+ }
+ function setPlaceholder (cm) {
+ clearPlaceholder(cm)
+ var elt = cm.state.placeholder = document.createElement('pre')
+ elt.style.cssText = 'height: 0; overflow: visible; color: #80848f;'
+ elt.style.direction = cm.getOption('direction')
+ elt.className = 'CodeMirror-placeholder'
+ var placeHolder = cm.getOption('placeholder')
+ if (typeof placeHolder === 'string') placeHolder = document.createTextNode(placeHolder)
+ elt.appendChild(placeHolder)
+ cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild)
+ }
+
+ function onBlur (cm) {
+ if (isEmpty(cm)) setPlaceholder(cm)
+ }
+ function onChange (cm) {
+ let wrapper = cm.getWrapperElement()
+ let empty = isEmpty(cm)
+ wrapper.className = wrapper.className.replace(' CodeMirror-empty', '') + (empty ? ' CodeMirror-empty' : '')
+
+ if (empty) setPlaceholder(cm)
+ else clearPlaceholder(cm)
+ }
+
+ function isEmpty (cm) {
+ return (cm.lineCount() === 1) && (cm.getLine(0) === '')
+ }
+ })
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/split-pane/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/split-pane/index.js
new file mode 100644
index 0000000..f5ed60e
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/split-pane/index.js
@@ -0,0 +1,2 @@
+import Split from './split.vue'
+export default Split
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/split-pane/index.less b/src/JT808.DotNetty.Dashbord.UI/src/view/components/split-pane/index.less
new file mode 100644
index 0000000..2583d90
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/split-pane/index.less
@@ -0,0 +1,114 @@
+@split-prefix-cls: ~"ivu-split";
+@box-shadow: 0 0 4px 0 rgba(28, 36, 56, 0.4);
+@trigger-bar-background: rgba(23, 35, 61, 0.25);
+@trigger-background: #F8F8F9;
+@trigger-width: 6px;
+@trigger-bar-width: 4px;
+@trigger-bar-offset: (@trigger-width - @trigger-bar-width) / 2;
+@trigger-bar-interval: 3px;
+@trigger-bar-weight: 1px;
+@trigger-bar-con-height: (@trigger-bar-weight + @trigger-bar-interval) * 8;
+
+.@{split-prefix-cls}{
+ &-wrapper{
+ position: relative;
+ width: 100%;
+ height: 100%;
+ }
+ &-pane{
+ position: absolute;
+ &.left-pane, &.right-pane{
+ top: 0px;
+ bottom: 0px;
+ }
+ &.left-pane{
+ left: 0px;
+ }
+ &.right-pane{
+ right: 0px;
+ }
+ &.top-pane, &.bottom-pane{
+ left: 0px;
+ right: 0px;
+ }
+ &.top-pane{
+ top: 0px;
+ }
+ &.bottom-pane{
+ bottom: 0px;
+ }
+ }
+ &-trigger{
+ &-con{
+ position: absolute;
+ transform: translate(-50%, -50%);
+ z-index: 10;
+ }
+ &-bar-con{
+ position: absolute;
+ overflow: hidden;
+ &.vertical{
+ left: @trigger-bar-offset;
+ top: 50%;
+ height: @trigger-bar-con-height;
+ transform: translate(0, -50%);
+ }
+ &.horizontal{
+ left: 50%;
+ top: @trigger-bar-offset;
+ width: @trigger-bar-con-height;
+ transform: translate(-50%, 0);
+ }
+ }
+ &-vertical{
+ width: @trigger-width;
+ height: 100%;
+ background: @trigger-background;
+ box-shadow: @box-shadow;
+ cursor: col-resize;
+ .@{split-prefix-cls}-trigger-bar{
+ width: @trigger-bar-width;
+ height: 1px;
+ background: @trigger-bar-background;
+ float: left;
+ margin-top: @trigger-bar-interval;
+ }
+ }
+ &-horizontal{
+ height: @trigger-width;
+ width: 100%;
+ background: @trigger-background;
+ box-shadow: @box-shadow;
+ cursor: row-resize;
+ .@{split-prefix-cls}-trigger-bar{
+ height: @trigger-bar-width;
+ width: 1px;
+ background: @trigger-bar-background;
+ float: left;
+ margin-right: @trigger-bar-interval;
+ }
+ }
+ }
+ &-horizontal{
+ .@{split-prefix-cls}-trigger-con{
+ top: 50%;
+ height: 100%;
+ width: 0;
+ }
+ }
+ &-vertical{
+ .@{split-prefix-cls}-trigger-con{
+ left: 50%;
+ height: 0;
+ width: 100%;
+ }
+ }
+ .no-select{
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/split-pane/split-pane.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/split-pane/split-pane.vue
new file mode 100644
index 0000000..9afe011
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/split-pane/split-pane.vue
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/split-pane/split.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/split-pane/split.vue
new file mode 100644
index 0000000..409982e
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/split-pane/split.vue
@@ -0,0 +1,158 @@
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/split-pane/trigger.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/split-pane/trigger.vue
new file mode 100644
index 0000000..9abdf03
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/split-pane/trigger.vue
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/tables/edit.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/tables/edit.vue
new file mode 100644
index 0000000..e1066ef
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/tables/edit.vue
@@ -0,0 +1,73 @@
+
+
+
+ {{ value }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/tables/handle-btns.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/tables/handle-btns.js
new file mode 100644
index 0000000..551b2e3
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/tables/handle-btns.js
@@ -0,0 +1,33 @@
+const btns = {
+ delete: (h, params, vm) => {
+ return h('Poptip', {
+ props: {
+ confirm: true,
+ title: '你确定要删除吗?'
+ },
+ on: {
+ 'on-ok': () => {
+ vm.$emit('on-delete', params)
+ vm.$emit('input', params.tableData.filter((item, index) => index !== params.row.initRowIndex))
+ }
+ }
+ }, [
+ h('Button', {
+ props: {
+ type: 'text',
+ ghost: true
+ }
+ }, [
+ h('Icon', {
+ props: {
+ type: 'md-trash',
+ size: 18,
+ color: '#000000'
+ }
+ })
+ ])
+ ])
+ }
+}
+
+export default btns
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/tables/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/components/tables/index.js
new file mode 100644
index 0000000..4dabfab
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/tables/index.js
@@ -0,0 +1,2 @@
+import Tables from './tables.vue'
+export default Tables
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/tables/index.less b/src/JT808.DotNetty.Dashbord.UI/src/view/components/tables/index.less
new file mode 100644
index 0000000..3c352e1
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/tables/index.less
@@ -0,0 +1,17 @@
+.search-con{
+ padding: 10px 0;
+ .search{
+ &-col{
+ display: inline-block;
+ width: 200px;
+ }
+ &-input{
+ display: inline-block;
+ width: 200px;
+ margin-left: 2px;
+ }
+ &-btn{
+ margin-left: 2px;
+ }
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/tables/tables.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/tables/tables.vue
new file mode 100644
index 0000000..fa2c235
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/tables/tables.vue
@@ -0,0 +1,277 @@
+
+
+
+
+ {{ item.title }}
+
+
+ 搜索
+
+
+
+
+ {{ item.title }}
+
+
+ 搜索
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/components/tree-table/index.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/components/tree-table/index.vue
new file mode 100644
index 0000000..6af71d1
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/components/tree-table/index.vue
@@ -0,0 +1,194 @@
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/directive/directive.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/directive/directive.vue
new file mode 100644
index 0000000..d731335
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/directive/directive.vue
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+ 显示可拖动弹窗
+
+ 这个按钮也是可以拖动的
+
+
+
+ <Modal v-draggable="options" v-model="visible">标题</Modal>
+
+ options = {
+ trigger: '.ivu-modal-body',
+ body: '.ivu-modal'
+ }
+
+
+
+
+
+
+
+ 拖动这里即可拖动整个弹窗
+
+
+
+
+
+
+
+
+ copy
+
+
+
+
+ <Input style="width: 60%" v-model="inputValue">
+
+ <Button slot="append" v-clipboard="clipOptions">copy</Button>
+
+ </Input>
+
+ clipOptions: {
+ value: this.inputValue,
+ success: (e) => {
+ this.$Message.success('复制成功')
+ },
+ error: () => {
+ this.$Message.error('复制失败')
+ }
+ }
+
+
+
+
+
+
+
+ 拖动这里即可拖动整个弹窗
+
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/error-page/401.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/error-page/401.vue
new file mode 100644
index 0000000..1032326
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/error-page/401.vue
@@ -0,0 +1,19 @@
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/error-page/404.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/error-page/404.vue
new file mode 100644
index 0000000..473df42
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/error-page/404.vue
@@ -0,0 +1,19 @@
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/error-page/500.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/error-page/500.vue
new file mode 100644
index 0000000..6a885da
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/error-page/500.vue
@@ -0,0 +1,19 @@
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/error-page/back-btn-group.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/error-page/back-btn-group.vue
new file mode 100644
index 0000000..4bbda48
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/error-page/back-btn-group.vue
@@ -0,0 +1,38 @@
+
+
+ 返回首页
+ 返回上一页({{ second }}s)
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/error-page/error-content.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/error-page/error-content.vue
new file mode 100644
index 0000000..3c9a0f4
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/error-page/error-content.vue
@@ -0,0 +1,28 @@
+
+
+
+
+
+
{{ code }}
+ {{ desc }}
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/error-page/error.less b/src/JT808.DotNetty.Dashbord.UI/src/view/error-page/error.less
new file mode 100644
index 0000000..6380245
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/error-page/error.less
@@ -0,0 +1,46 @@
+.error-page{
+ width: 100%;
+ height: 100%;
+ position: relative;
+ background: #f8f8f9;
+ .content-con{
+ width: 700px;
+ height: 600px;
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ transform: translate(-50%, -60%);
+ img{
+ display: block;
+ width: 100%;
+ height: 100%;
+ }
+ .text-con{
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ h4{
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ font-size: 80px;
+ font-weight: 700;
+ color: #348EED;
+ }
+ h5{
+ position: absolute;
+ width: 700px;
+ left: 0px;
+ top: 100px;
+ font-size: 20px;
+ font-weight: 700;
+ color: #67647D;
+ }
+ }
+ .back-btn-group{
+ position: absolute;
+ right: 0px;
+ bottom: 20px;
+ }
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/error-store/error-store.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/error-store/error-store.vue
new file mode 100644
index 0000000..e66631c
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/error-store/error-store.vue
@@ -0,0 +1,39 @@
+
+
+
+ iview-admin会自动将你程序中的错误收集起来,你可以将错误日志发给后端保存起来。如果你不需要这个功能,将'./src/config/index.js'里的plugin的'error-store'属性删掉即可。
+ 另外在开发环境下,你程序中的错误都会被收集起来,这样可能不利于你排查错误,你可以将'./src/config/index.js'的'error-store'的'developmentOff'设为true。
+ 如果你只是想收集错误日志,不希望登录用户看到错误日志,你可以不提供查看日志的入口,只需将'./src/config/index.js'的'error-store'的'showInHeader'设为false。
+
+
+
+
+ 点击测试触发程序错误
+ 点击测试触发ajax接口请求错误
+
+
+ ajax接口请求是请求easy-mock的一个不存在接口,所以服务端会报404错误,错误收集机制会收集这个错误,测试的时候有一定网络延迟,所以点击按钮之后稍等一会才会收集到错误。
+
+
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/login/login.less b/src/JT808.DotNetty.Dashbord.UI/src/view/login/login.less
new file mode 100644
index 0000000..e986ed4
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/login/login.less
@@ -0,0 +1,29 @@
+.login{
+ width: 100%;
+ height: 100%;
+ background-image: url('../../assets/images/login-bg.jpg');
+ background-size: cover;
+ background-position: center;
+ position: relative;
+ &-con{
+ position: absolute;
+ right: 160px;
+ top: 50%;
+ transform: translateY(-60%);
+ width: 300px;
+ &-header{
+ font-size: 16px;
+ font-weight: 300;
+ text-align: center;
+ padding: 30px 0;
+ }
+ .form-con{
+ padding: 10px 0 0;
+ }
+ .login-tip{
+ font-size: 10px;
+ text-align: center;
+ color: #c3c3c3;
+ }
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/login/login.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/login/login.vue
new file mode 100644
index 0000000..7595e01
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/login/login.vue
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/session/session.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/session/session.vue
new file mode 100644
index 0000000..33f3ce3
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/session/session.vue
@@ -0,0 +1,34 @@
+
+
+ {{tmpResult}}
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/single-page/error-logger.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/single-page/error-logger.vue
new file mode 100644
index 0000000..a4b4ac2
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/single-page/error-logger.vue
@@ -0,0 +1,91 @@
+
+
+
导出日志记录
+
注:这里只会显示成功保存到服务端的错误日志,而且页面错误日志不会在浏览器持久化存储,刷新页面即会丢失
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/single-page/home/example.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/single-page/home/example.vue
new file mode 100644
index 0000000..5fb3465
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/single-page/home/example.vue
@@ -0,0 +1,114 @@
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/single-page/home/home.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/single-page/home/home.vue
new file mode 100644
index 0000000..0240022
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/single-page/home/home.vue
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+ {{ infor.title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/single-page/home/index.js b/src/JT808.DotNetty.Dashbord.UI/src/view/single-page/home/index.js
new file mode 100644
index 0000000..de4ced1
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/single-page/home/index.js
@@ -0,0 +1,2 @@
+import home from './home.vue'
+export default home
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/single-page/message/index.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/single-page/message/index.vue
new file mode 100644
index 0000000..11b43f9
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/single-page/message/index.vue
@@ -0,0 +1,194 @@
+
+
+
+
+
+
+ 未读消息
+
+
+ 已读消息
+
+
+ 回收站
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/sourcepackage/sourcepackage.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/sourcepackage/sourcepackage.vue
new file mode 100644
index 0000000..04edf70
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/sourcepackage/sourcepackage.vue
@@ -0,0 +1,34 @@
+
+
+ {{tmpResult}}
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/src/view/transmit/transmit.vue b/src/JT808.DotNetty.Dashbord.UI/src/view/transmit/transmit.vue
new file mode 100644
index 0000000..f21961d
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/src/view/transmit/transmit.vue
@@ -0,0 +1,33 @@
+
+
+ {{tmpResult}}
+
+
+
+
+
+
diff --git a/src/JT808.DotNetty.Dashbord.UI/tests/e2e/.eslintrc b/src/JT808.DotNetty.Dashbord.UI/tests/e2e/.eslintrc
new file mode 100644
index 0000000..02023fb
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/tests/e2e/.eslintrc
@@ -0,0 +1,12 @@
+{
+ "plugins": [
+ "cypress"
+ ],
+ "env": {
+ "mocha": true,
+ "cypress/globals": true
+ },
+ "rules": {
+ "strict": "off"
+ }
+}
diff --git a/src/JT808.DotNetty.Dashbord.UI/tests/e2e/plugins/index.js b/src/JT808.DotNetty.Dashbord.UI/tests/e2e/plugins/index.js
new file mode 100644
index 0000000..cfefc78
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/tests/e2e/plugins/index.js
@@ -0,0 +1,9 @@
+// https://docs.cypress.io/guides/guides/plugins-guide.html
+
+module.exports = (on, config) => Object.assign({}, config, {
+ fixturesFolder: 'tests/e2e/fixtures',
+ integrationFolder: 'tests/e2e/specs',
+ screenshotsFolder: 'tests/e2e/screenshots',
+ videosFolder: 'tests/e2e/videos',
+ supportFile: 'tests/e2e/support/index.js'
+})
diff --git a/src/JT808.DotNetty.Dashbord.UI/tests/e2e/specs/test.js b/src/JT808.DotNetty.Dashbord.UI/tests/e2e/specs/test.js
new file mode 100644
index 0000000..41ad94a
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/tests/e2e/specs/test.js
@@ -0,0 +1,8 @@
+// https://docs.cypress.io/api/introduction/api.html
+
+describe('My First Test', () => {
+ it('Visits the app root url', () => {
+ cy.visit('/')
+ cy.contains('h1', 'Welcome to Your Vue.js App')
+ })
+})
diff --git a/src/JT808.DotNetty.Dashbord.UI/tests/e2e/support/commands.js b/src/JT808.DotNetty.Dashbord.UI/tests/e2e/support/commands.js
new file mode 100644
index 0000000..c1f5a77
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/tests/e2e/support/commands.js
@@ -0,0 +1,25 @@
+// ***********************************************
+// This example commands.js shows you how to
+// create various custom commands and overwrite
+// existing commands.
+//
+// For more comprehensive examples of custom
+// commands please read more here:
+// https://on.cypress.io/custom-commands
+// ***********************************************
+//
+//
+// -- This is a parent command --
+// Cypress.Commands.add("login", (email, password) => { ... })
+//
+//
+// -- This is a child command --
+// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
+//
+//
+// -- This is a dual command --
+// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
+//
+//
+// -- This is will overwrite an existing command --
+// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
diff --git a/src/JT808.DotNetty.Dashbord.UI/tests/e2e/support/index.js b/src/JT808.DotNetty.Dashbord.UI/tests/e2e/support/index.js
new file mode 100644
index 0000000..d68db96
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/tests/e2e/support/index.js
@@ -0,0 +1,20 @@
+// ***********************************************************
+// This example support/index.js is processed and
+// loaded automatically before your test files.
+//
+// This is a great place to put global configuration and
+// behavior that modifies Cypress.
+//
+// You can change the location of this file or turn off
+// automatically serving support files with the
+// 'supportFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/configuration
+// ***********************************************************
+
+// Import commands.js using ES2015 syntax:
+import './commands'
+
+// Alternatively you can use CommonJS syntax:
+// require('./commands')
diff --git a/src/JT808.DotNetty.Dashbord.UI/tests/unit/.eslintrc.js b/src/JT808.DotNetty.Dashbord.UI/tests/unit/.eslintrc.js
new file mode 100644
index 0000000..74fe627
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/tests/unit/.eslintrc.js
@@ -0,0 +1,8 @@
+module.exports = {
+ env: {
+ mocha: true
+ },
+ rules: {
+ 'import/no-extraneous-dependencies': 'off'
+ }
+}
\ No newline at end of file
diff --git a/src/JT808.DotNetty.Dashbord.UI/tests/unit/HelloWorld.spec.js b/src/JT808.DotNetty.Dashbord.UI/tests/unit/HelloWorld.spec.js
new file mode 100644
index 0000000..bb668bf
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/tests/unit/HelloWorld.spec.js
@@ -0,0 +1,13 @@
+import { expect } from 'chai'
+import { shallow } from '@vue/test-utils'
+import HelloWorld from '@/components/HelloWorld.vue'
+
+describe('HelloWorld.vue', () => {
+ it('renders props.msg when passed', () => {
+ const msg = 'new message'
+ const wrapper = shallow(HelloWorld, {
+ propsData: { msg }
+ })
+ expect(wrapper.text()).to.include(msg)
+ })
+})
diff --git a/src/JT808.DotNetty.Dashbord.UI/vue.config.js b/src/JT808.DotNetty.Dashbord.UI/vue.config.js
new file mode 100644
index 0000000..5d6c1d4
--- /dev/null
+++ b/src/JT808.DotNetty.Dashbord.UI/vue.config.js
@@ -0,0 +1,43 @@
+const path = require('path')
+
+const resolve = dir => {
+ return path.join(__dirname, dir)
+}
+
+// 项目部署基础
+// 默认情况下,我们假设你的应用将被部署在域的根目录下,
+// 例如:https://www.my-app.com/
+// 默认:'/'
+// 如果您的应用程序部署在子路径中,则需要在这指定子路径
+// 例如:https://www.foobar.com/my-app/
+// 需要将它改为'/my-app/'
+// iview-admin线上演示打包路径: https://file.iviewui.com/admin-dist/
+const BASE_URL = process.env.NODE_ENV === 'production'
+ ? '/'
+ : '/'
+
+module.exports = {
+ // Project deployment base
+ // By default we assume your app will be deployed at the root of a domain,
+ // e.g. https://www.my-app.com/
+ // If your app is deployed at a sub-path, you will need to specify that
+ // sub-path here. For example, if your app is deployed at
+ // https://www.foobar.com/my-app/
+ // then change this to '/my-app/'
+ baseUrl: BASE_URL,
+ // tweak internal webpack configuration.
+ // see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md
+ // 如果你不需要使用eslint,把lintOnSave设为false即可
+ lintOnSave: true,
+ chainWebpack: config => {
+ config.resolve.alias
+ .set('@', resolve('src')) // key,value自行定义,比如.set('@@', resolve('src/components'))
+ .set('_c', resolve('src/components'))
+ },
+ // 设为false打包时不生成.map文件
+ productionSourceMap: false
+ // 这里写你调用接口的基础路径,来解决跨域,如果设置了代理,那你本地开发环境的axios的baseUrl要写为 '' ,即空字符串
+ // devServer: {
+ // proxy: 'localhost:3000'
+ // }
+}
diff --git a/src/JT808.DotNetty.Dashbord/Controllers/JT808AtomicCounterController.cs b/src/JT808.DotNetty.Dashbord/Controllers/JT808AtomicCounterController.cs
index 402657d..31f5d18 100644
--- a/src/JT808.DotNetty.Dashbord/Controllers/JT808AtomicCounterController.cs
+++ b/src/JT808.DotNetty.Dashbord/Controllers/JT808AtomicCounterController.cs
@@ -18,6 +18,8 @@ namespace JT808.DotNetty.Dashbord.Controllers
/// 获取包计算器
///
///
+ [HttpGet]
+ [Route("GetAtomicCounter")]
public ActionResult GetAtomicCounter()
{
return new JT808AtomicCounterDto {
diff --git a/src/JT808.DotNetty.Dashbord/Controllers/JT808SessionController.cs b/src/JT808.DotNetty.Dashbord/Controllers/JT808SessionController.cs
index 32f6354..259e550 100644
--- a/src/JT808.DotNetty.Dashbord/Controllers/JT808SessionController.cs
+++ b/src/JT808.DotNetty.Dashbord/Controllers/JT808SessionController.cs
@@ -20,6 +20,7 @@ namespace JT808.DotNetty.Dashbord.Controllers
///
///
[HttpGet]
+ [Route("RemoveByTerminalPhoneNo")]
public ActionResult RemoveByTerminalPhoneNo(string terminalPhoneNo)
{
return true;
@@ -31,6 +32,7 @@ namespace JT808.DotNetty.Dashbord.Controllers
///
///
[HttpGet]
+ [Route("RemoveByChannelId")]
public ActionResult RemoveByChannelId(string channelId)
{
return true;
@@ -42,6 +44,7 @@ namespace JT808.DotNetty.Dashbord.Controllers
///
///
[HttpGet]
+ [Route("GetAll")]
public ActionResult> GetAll()
{
return new List() {
diff --git a/src/JT808.DotNetty.Dashbord/Controllers/JT808SourcePackageController.cs b/src/JT808.DotNetty.Dashbord/Controllers/JT808SourcePackageController.cs
index aa1a969..6df492a 100644
--- a/src/JT808.DotNetty.Dashbord/Controllers/JT808SourcePackageController.cs
+++ b/src/JT808.DotNetty.Dashbord/Controllers/JT808SourcePackageController.cs
@@ -20,6 +20,7 @@ namespace JT808.DotNetty.Dashbord.Controllers
///
///
[HttpPost]
+ [Route("Add")]
public ActionResult Add([FromBody]JT808IPAddressDto jT808IPAddressDto)
{
return true;
@@ -31,17 +32,19 @@ namespace JT808.DotNetty.Dashbord.Controllers
///
///
[HttpPost]
+ [Route("Remove")]
public ActionResult Remove([FromBody]JT808IPAddressDto jT808IPAddressDto)
{
return true;
}
///
- /// 删除地址
+ /// 获取原包通道信息集合
///
///
///
[HttpGet]
+ [Route("GetAll")]
public ActionResult> GetAll()
{
return new List() {
diff --git a/src/JT808.DotNetty.Dashbord/Controllers/JT808TransmitController.cs b/src/JT808.DotNetty.Dashbord/Controllers/JT808TransmitController.cs
index 6fde62d..198b267 100644
--- a/src/JT808.DotNetty.Dashbord/Controllers/JT808TransmitController.cs
+++ b/src/JT808.DotNetty.Dashbord/Controllers/JT808TransmitController.cs
@@ -20,6 +20,7 @@ namespace JT808.DotNetty.Dashbord.Controllers
///
///
[HttpPost]
+ [Route("Add")]
public ActionResult Add([FromBody]JT808IPAddressDto jT808IPAddressDto)
{
return true;
@@ -31,6 +32,7 @@ namespace JT808.DotNetty.Dashbord.Controllers
///
///
[HttpPost]
+ [Route("Remove")]
public ActionResult Remove([FromBody]JT808IPAddressDto jT808IPAddressDto)
{
return true;
@@ -42,6 +44,7 @@ namespace JT808.DotNetty.Dashbord.Controllers
///
///
[HttpGet]
+ [Route("GetAll")]
public ActionResult> GetAll()
{
return new List() { "127.0.0.1:80", "127.0.0.1:81" };
diff --git a/src/JT808.DotNetty.Dashbord/Controllers/JT808UnificationSendController.cs b/src/JT808.DotNetty.Dashbord/Controllers/JT808UnificationSendController.cs
index 0035f5b..244251e 100644
--- a/src/JT808.DotNetty.Dashbord/Controllers/JT808UnificationSendController.cs
+++ b/src/JT808.DotNetty.Dashbord/Controllers/JT808UnificationSendController.cs
@@ -20,10 +20,10 @@ namespace JT808.DotNetty.Dashbord.Controllers
/// 下发文本信息
///
[HttpGet("{terminalPhoneNo}/{text}")]
- public ActionResult SendText(string terminalPhoneNo, string text)
+ public ActionResult SendText(string terminalPhoneNo, string text)
{
- return "value";
+ return true;
}
}
}