Переглянути джерело

基金park 后台管理_前端

陈鹏铭 2 роки тому
коміт
81f724e32f
100 змінених файлів з 24342 додано та 0 видалено
  1. 21 0
      LICENSE
  2. 76 0
      README-zh.md
  3. 76 0
      README.md
  4. 5 0
      babel.config.js
  5. 35 0
      build/index.js
  6. 24 0
      jest.config.js
  7. 66 0
      mock/index.js
  8. 68 0
      mock/mock-server.js
  9. 29 0
      mock/table.js
  10. 85 0
      mock/user.js
  11. 0 0
      output.js
  12. 20979 0
      package-lock.json
  13. 86 0
      package.json
  14. 8 0
      postcss.config.js
  15. 75 0
      public/android_park.html
  16. BIN
      public/base.ico
  17. BIN
      public/base_1.ico
  18. BIN
      public/bmAddressBook.xlsx
  19. BIN
      public/dzAddressBook.xlsx
  20. BIN
      public/energy.xlsx
  21. BIN
      public/favicon.ico
  22. 22 0
      public/index.html
  23. 51 0
      public/jquery.zyslide.css
  24. 139 0
      public/jquery.zyslide.js
  25. BIN
      public/logo.png
  26. 230 0
      public/tinymce4.7.5/langs/zh_CN.js
  27. 138 0
      public/tinymce4.7.5/plugins/codesample/css/prism.css
  28. BIN
      public/tinymce4.7.5/plugins/emoticons/img/smiley-cool.gif
  29. BIN
      public/tinymce4.7.5/plugins/emoticons/img/smiley-cry.gif
  30. BIN
      public/tinymce4.7.5/plugins/emoticons/img/smiley-embarassed.gif
  31. BIN
      public/tinymce4.7.5/plugins/emoticons/img/smiley-foot-in-mouth.gif
  32. BIN
      public/tinymce4.7.5/plugins/emoticons/img/smiley-frown.gif
  33. BIN
      public/tinymce4.7.5/plugins/emoticons/img/smiley-innocent.gif
  34. BIN
      public/tinymce4.7.5/plugins/emoticons/img/smiley-kiss.gif
  35. BIN
      public/tinymce4.7.5/plugins/emoticons/img/smiley-laughing.gif
  36. BIN
      public/tinymce4.7.5/plugins/emoticons/img/smiley-money-mouth.gif
  37. BIN
      public/tinymce4.7.5/plugins/emoticons/img/smiley-sealed.gif
  38. BIN
      public/tinymce4.7.5/plugins/emoticons/img/smiley-smile.gif
  39. BIN
      public/tinymce4.7.5/plugins/emoticons/img/smiley-surprised.gif
  40. BIN
      public/tinymce4.7.5/plugins/emoticons/img/smiley-tongue-out.gif
  41. BIN
      public/tinymce4.7.5/plugins/emoticons/img/smiley-undecided.gif
  42. BIN
      public/tinymce4.7.5/plugins/emoticons/img/smiley-wink.gif
  43. BIN
      public/tinymce4.7.5/plugins/emoticons/img/smiley-yell.gif
  44. 59 0
      public/tinymce4.7.5/plugins/lineheight/plugin.js
  45. 59 0
      public/tinymce4.7.5/plugins/lineheight/plugin.min.js
  46. 154 0
      public/tinymce4.7.5/plugins/visualblocks/css/visualblocks.css
  47. 1 0
      public/tinymce4.7.5/skins/lightgray/content.inline.min.css
  48. 1 0
      public/tinymce4.7.5/skins/lightgray/content.min.css
  49. BIN
      public/tinymce4.7.5/skins/lightgray/fonts/tinymce-mobile.woff
  50. BIN
      public/tinymce4.7.5/skins/lightgray/fonts/tinymce-small.eot
  51. 63 0
      public/tinymce4.7.5/skins/lightgray/fonts/tinymce-small.svg
  52. BIN
      public/tinymce4.7.5/skins/lightgray/fonts/tinymce-small.ttf
  53. BIN
      public/tinymce4.7.5/skins/lightgray/fonts/tinymce-small.woff
  54. BIN
      public/tinymce4.7.5/skins/lightgray/fonts/tinymce.eot
  55. 131 0
      public/tinymce4.7.5/skins/lightgray/fonts/tinymce.svg
  56. BIN
      public/tinymce4.7.5/skins/lightgray/fonts/tinymce.ttf
  57. BIN
      public/tinymce4.7.5/skins/lightgray/fonts/tinymce.woff
  58. BIN
      public/tinymce4.7.5/skins/lightgray/img/anchor.gif
  59. BIN
      public/tinymce4.7.5/skins/lightgray/img/loader.gif
  60. BIN
      public/tinymce4.7.5/skins/lightgray/img/object.gif
  61. BIN
      public/tinymce4.7.5/skins/lightgray/img/trans.gif
  62. 1 0
      public/tinymce4.7.5/skins/lightgray/skin.min.css
  63. 1 0
      public/tinymce4.7.5/skins/lightgray/skin.min.css.map
  64. 2 0
      public/tinymce4.7.5/tinymce.min.js
  65. BIN
      public/ywAddressBook .xlsx
  66. BIN
      public/yy-wyAddressBook.xlsx
  67. 18 0
      src/App.vue
  68. 41 0
      src/api/admin.js
  69. 7 0
      src/api/remote-search.js
  70. 65 0
      src/api/role.js
  71. 9 0
      src/api/table.js
  72. 61 0
      src/api/user.js
  73. BIN
      src/assets/404_images/404.png
  74. BIN
      src/assets/404_images/404_cloud.png
  75. 70 0
      src/components/Breadcrumb/index.vue
  76. 44 0
      src/components/Hamburger/index.vue
  77. 77 0
      src/components/InEditor/index.vue
  78. 100 0
      src/components/Pagination/index.vue
  79. 140 0
      src/components/PanThumb/index.vue
  80. 145 0
      src/components/RightPanel/index.vue
  81. 60 0
      src/components/Screenfull/index.vue
  82. 61 0
      src/components/SvgIcon/index.vue
  83. 111 0
      src/components/TextHoverEffect/Mallki.vue
  84. 175 0
      src/components/ThemePicker/index.vue
  85. 345 0
      src/components/Tinymce/index.vue
  86. 5 0
      src/components/Tinymce/plugins.js
  87. 3 0
      src/components/Tinymce/toolbar.js
  88. 49 0
      src/directive/clipboard/clipboard.js
  89. 13 0
      src/directive/clipboard/index.js
  90. 13 0
      src/directive/permission/index.js
  91. 29 0
      src/directive/permission/permission.js
  92. 9 0
      src/icons/index.js
  93. 1 0
      src/icons/svg/404.svg
  94. 1 0
      src/icons/svg/bug.svg
  95. 1 0
      src/icons/svg/chart.svg
  96. 1 0
      src/icons/svg/clipboard.svg
  97. 1 0
      src/icons/svg/component.svg
  98. 1 0
      src/icons/svg/dashboard.svg
  99. 1 0
      src/icons/svg/documentation.svg
  100. 0 0
      src/icons/svg/drag.svg

+ 21 - 0
LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017-present PanJiaChen
+
+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.

+ 76 - 0
README-zh.md

@@ -0,0 +1,76 @@
+# Rock-Star 1.0 页面版
+
+> 这是一个Rock-Star系统体系的基础平台后台管理。它包含了 Element UI & axios & iconfont & permission control & lint,这些搭建后台必要的东西。
+
+目前版本为 `v4.0+` 基于 `vue-cli` 进行构建
+整个项目是基于panjiachen的vue-element-admin为基础进行构建的 [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/)
+
+## Extra
+
+如果你想要根据用户角色来动态生成侧边栏和 router,你可以使用该分支[permission-control](https://github.com/PanJiaChen/vue-admin-template/tree/permission-control)
+
+## Build Setup
+
+```bash
+# 克隆项目
+git clone http://47.96.128.196:3000/pengyq/rock-web-base.git
+
+# 进入项目目录
+cd rock-web-base
+
+# 安装依赖
+npm install
+
+# 建议不要直接使用 cnpm 安装以来,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题
+npm install --registry=https://registry.npm.taobao.org
+
+# 启动服务
+npm run dev
+```
+
+浏览器访问 [http://localhost:9525](http://localhost:9525)
+
+## 发布
+
+```bash
+# 构建测试环境
+npm run build:stage
+
+# 构建生产环境
+npm run build:prod
+
+# 本地运行代码
+npm run dev
+```
+
+## 其它
+
+```bash
+# 预览发布环境效果
+npm run preview
+
+# 预览发布环境效果 + 静态资源分析
+npm run preview -- --report
+
+# 代码格式检查
+npm run lint
+
+# 代码格式检查并自动修复
+npm run lint -- --fix
+```
+
+更多信息请参考 [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/)
+
+## Browsers support
+
+Modern browsers and Internet Explorer 10+.
+
+| IE / Edge |   Firefox |    Chrome |   Safari  |
+| --------- | --------- | --------- | --------- |
+| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions |
+
+## License
+
+PanJiaChen [MIT](https://github.com/PanJiaChen/vue-admin-template/blob/master/LICENSE) license.
+
+Copyright (c) 2020-present Rock-Idea

+ 76 - 0
README.md

@@ -0,0 +1,76 @@
+# Rock-Star 1.0 页面版
+
+> 这是一个Rock-Star系统体系的基础平台后台管理。它包含了 Element UI & axios & iconfont & permission control & lint,这些搭建后台必要的东西。
+
+目前版本为 `v4.0+` 基于 `vue-cli` 进行构建
+整个项目是基于panjiachen的vue-element-admin为基础进行构建的 [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/)
+
+## Extra
+
+如果你想要根据用户角色来动态生成侧边栏和 router,你可以使用该分支[permission-control](https://github.com/PanJiaChen/vue-admin-template/tree/permission-control)
+
+## Build Setup
+
+```bash
+# 克隆项目
+git clone http://47.96.128.196:3000/pengyq/rock-web-base.git
+
+# 进入项目目录
+cd rock-web-base
+
+# 安装依赖
+npm install
+
+# 建议不要直接使用 cnpm 安装以来,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题
+npm install --registry=https://registry.npm.taobao.org
+
+# 启动服务
+npm run dev
+```
+
+浏览器访问 [http://localhost:9525](http://localhost:9525)
+
+## 发布
+
+```bash
+# 构建测试环境
+npm run build:stage
+
+# 构建生产环境
+npm run build:prod
+
+# 本地运行代码
+npm run dev
+```
+
+## 其它
+
+```bash
+# 预览发布环境效果
+npm run preview
+
+# 预览发布环境效果 + 静态资源分析
+npm run preview -- --report
+
+# 代码格式检查
+npm run lint
+
+# 代码格式检查并自动修复
+npm run lint -- --fix
+```
+
+更多信息请参考 [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/)
+
+## Browsers support
+
+Modern browsers and Internet Explorer 10+.
+
+| IE / Edge |   Firefox |    Chrome |   Safari  |
+| --------- | --------- | --------- | --------- |
+| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions |
+
+## License
+
+PanJiaChen [MIT](https://github.com/PanJiaChen/vue-admin-template/blob/master/LICENSE) license.
+
+Copyright (c) 2020-present Rock-Idea

+ 5 - 0
babel.config.js

@@ -0,0 +1,5 @@
+module.exports = {
+  presets: [
+    '@vue/app'
+  ]
+}

+ 35 - 0
build/index.js

@@ -0,0 +1,35 @@
+const { run } = require('runjs')
+const chalk = require('chalk')
+const config = require('../vue.config.js')
+const rawArgv = process.argv.slice(2)
+const args = rawArgv.join(' ')
+
+if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
+  const report = rawArgv.includes('--report')
+
+  run(`vue-cli-service build ${args}`)
+
+  const port = 9526
+  const publicPath = config.publicPath
+
+  var connect = require('connect')
+  var serveStatic = require('serve-static')
+  const app = connect()
+
+  app.use(
+    publicPath,
+    serveStatic('./dist', {
+      index: ['index.html', '/']
+    })
+  )
+
+  app.listen(port, function () {
+    console.log(chalk.green(`> Preview at  http://localhost:${port}${publicPath}`))
+    if (report) {
+      console.log(chalk.green(`> Report at  http://localhost:${port}${publicPath}report.html`))
+    }
+
+  })
+} else {
+  run(`vue-cli-service build ${args}`)
+}

+ 24 - 0
jest.config.js

@@ -0,0 +1,24 @@
+module.exports = {
+  moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
+  transform: {
+    '^.+\\.vue$': 'vue-jest',
+    '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
+      'jest-transform-stub',
+    '^.+\\.jsx?$': 'babel-jest'
+  },
+  moduleNameMapper: {
+    '^@/(.*)$': '<rootDir>/src/$1'
+  },
+  snapshotSerializers: ['jest-serializer-vue'],
+  testMatch: [
+    '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
+  ],
+  collectCoverageFrom: ['src/static/utils/**/*.{js,vue}', '!src/static/utils/auth.js', '!src/static/utils/request.js', 'src/components/**/*.{js,vue}'],
+  coverageDirectory: '<rootDir>/tests/unit/coverage',
+  // 'collectCoverage': true,
+  'coverageReporters': [
+    'lcov',
+    'text-summary'
+  ],
+  testURL: 'http://localhost/'
+}

+ 66 - 0
mock/index.js

@@ -0,0 +1,66 @@
+import Mock from 'mockjs'
+import { param2Obj } from '../src/static/utils'
+
+import user from './user'
+import table from './table'
+
+const mocks = [
+  ...user,
+  ...table
+]
+
+// for front mock
+// please use it cautiously, it will redefine XMLHttpRequest,
+// which will cause many of your third-party libraries to be invalidated(like progress event).
+export function mockXHR() {
+  // mock patch
+  // https://github.com/nuysoft/Mock/issues/300
+  Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
+  Mock.XHR.prototype.send = function() {
+    if (this.custom.xhr) {
+      this.custom.xhr.withCredentials = this.withCredentials || false
+
+      if (this.responseType) {
+        this.custom.xhr.responseType = this.responseType
+      }
+    }
+    this.proxy_send(...arguments)
+  }
+
+  function XHR2ExpressReqWrap(respond) {
+    return function(options) {
+      let result = null
+      if (respond instanceof Function) {
+        const { body, type, url } = options
+        // https://expressjs.com/en/4x/api.html#req
+        result = respond({
+          method: type,
+          body: JSON.parse(body),
+          query: param2Obj(url)
+        })
+      } else {
+        result = respond
+      }
+      return Mock.mock(result)
+    }
+  }
+
+  for (const i of mocks) {
+    Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response))
+  }
+}
+
+// for mock server
+const responseFake = (url, type, respond) => {
+  return {
+    url: new RegExp(`/mock${url}`),
+    type: type || 'get',
+    response(req, res) {
+      res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))
+    }
+  }
+}
+
+export default mocks.map(route => {
+  return responseFake(route.url, route.type, route.response)
+})

+ 68 - 0
mock/mock-server.js

@@ -0,0 +1,68 @@
+const chokidar = require('chokidar')
+const bodyParser = require('body-parser')
+const chalk = require('chalk')
+const path = require('path')
+
+const mockDir = path.join(process.cwd(), 'mock')
+
+function registerRoutes(app) {
+  let mockLastIndex
+  const { default: mocks } = require('./index.js')
+  for (const mock of mocks) {
+    app[mock.type](mock.url, mock.response)
+    mockLastIndex = app._router.stack.length
+  }
+  const mockRoutesLength = Object.keys(mocks).length
+  return {
+    mockRoutesLength: mockRoutesLength,
+    mockStartIndex: mockLastIndex - mockRoutesLength
+  }
+}
+
+function unregisterRoutes() {
+  Object.keys(require.cache).forEach(i => {
+    if (i.includes(mockDir)) {
+      delete require.cache[require.resolve(i)]
+    }
+  })
+}
+
+module.exports = app => {
+  // es6 polyfill
+  require('@babel/register')
+
+  // parse app.body
+  // https://expressjs.com/en/4x/api.html#req.body
+  app.use(bodyParser.json())
+  app.use(bodyParser.urlencoded({
+    extended: true
+  }))
+
+  const mockRoutes = registerRoutes(app)
+  var mockRoutesLength = mockRoutes.mockRoutesLength
+  var mockStartIndex = mockRoutes.mockStartIndex
+
+  // watch files, hot reload mock server
+  chokidar.watch(mockDir, {
+    ignored: /mock-server/,
+    ignoreInitial: true
+  }).on('all', (event, path) => {
+    if (event === 'change' || event === 'add') {
+      try {
+        // remove mock routes stack
+        app._router.stack.splice(mockStartIndex, mockRoutesLength)
+
+        // clear routes cache
+        unregisterRoutes()
+
+        const mockRoutes = registerRoutes(app)
+        mockRoutesLength = mockRoutes.mockRoutesLength
+        mockStartIndex = mockRoutes.mockStartIndex
+
+        console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed  ${path}`))
+      } catch (error) {
+        console.log(chalk.redBright(error))
+      }
+    }
+  })
+}

+ 29 - 0
mock/table.js

@@ -0,0 +1,29 @@
+import Mock from 'mockjs'
+
+const data = Mock.mock({
+  'items|30': [{
+    id: '@id',
+    title: '@sentence(10, 20)',
+    'status|1': ['published', 'draft', 'deleted'],
+    author: 'name',
+    display_time: '@datetime',
+    pageviews: '@integer(300, 5000)'
+  }]
+})
+
+export default [
+  {
+    url: '/table/list',
+    type: 'get',
+    response: config => {
+      const items = data.items
+      return {
+        code: 20000,
+        data: {
+          total: items.length,
+          items: items
+        }
+      }
+    }
+  }
+]

+ 85 - 0
mock/user.js

@@ -0,0 +1,85 @@
+
+const tokens = {
+  admin: {
+    token: 'admin-token'
+  },
+  editor: {
+    token: 'editor-token'
+  }
+}
+
+const users = {
+  'admin-token': {
+    roles: ['admin'],
+    introduction: 'I am a super administrator',
+    avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
+    name: 'Super Admin'
+  },
+  'editor-token': {
+    roles: ['editor'],
+    introduction: 'I am an editor',
+    avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
+    name: 'Normal Editor'
+  }
+}
+
+export default [
+  // user login
+  {
+    url: '/user/login',
+    type: 'post',
+    response: config => {
+      console.log('mock/user/login')
+      const { username } = config.body
+      const token = tokens[username]
+
+      // mock error
+      if (!token) {
+        return {
+          code: 60204,
+          message: 'Account and password are incorrect.'
+        }
+      }
+
+      return {
+        code: 20000,
+        data: token
+      }
+    }
+  },
+
+  // get user info
+  {
+    url: '/user/info\.*',
+    type: 'get',
+    response: config => {
+      const { token } = config.query
+      const info = users[token]
+
+      // mock error
+      if (!info) {
+        return {
+          code: 50008,
+          message: 'Login failed, unable to get user details.'
+        }
+      }
+
+      return {
+        code: 20000,
+        data: info
+      }
+    }
+  },
+
+  // user logout
+  {
+    url: '/user/logout',
+    type: 'post',
+    response: _ => {
+      return {
+        code: 20000,
+        data: 'success'
+      }
+    }
+  }
+]


Різницю між файлами не показано, бо вона завелика
+ 20979 - 0
package-lock.json


+ 86 - 0
package.json

@@ -0,0 +1,86 @@
+{
+  "name": "vue-admin-template",
+  "version": "4.2.1",
+  "description": "A vue admin template with Element UI & axios & iconfont & permission control & lint",
+  "author": "Pan <panfree23@gmail.com>",
+  "license": "MIT",
+  "scripts": {
+    "dev": "vue-cli-service serve",
+    "build:prod": "vue-cli-service build",
+    "build:stage": "vue-cli-service build --mode staging",
+    "preview": "node build/index.js --preview",
+    "lint": "eslint --ext .js,.vue src",
+    "test:unit": "jest --clearCache && vue-cli-service test:unit",
+    "test:ci": "npm run lint && npm run test:unit",
+    "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml"
+  },
+  "dependencies": {
+    "@ckeditor/ckeditor5-build-classic": "^28.0.0",
+    "@ckeditor/ckeditor5-dev-utils": "^25.2.2",
+    "@ckeditor/ckeditor5-dev-webpack-plugin": "^25.2.2",
+    "@ckeditor/ckeditor5-theme-lark": "^28.0.0",
+    "@ckeditor/ckeditor5-vue2": "^1.0.5",
+    "@huoyu/vue-digitroll": "^1.0.4",
+    "axios": "^0.19.0",
+    "echarts": "^4.9.0",
+    "echarts-liquidfill": "^2.0.6",
+    "element-ui": "2.10.1",
+    "flv.js": "^1.6.2",
+    "gg-editor": "^3.0.0-beta.3",
+    "js-cookie": "2.2.0",
+    "js-md5": "^0.7.3",
+    "normalize.css": "7.0.0",
+    "nprogress": "0.2.0",
+    "path-to-regexp": "2.4.0",
+    "qrcodejs2": "0.0.2",
+    "qs.js": "^0.1.12",
+    "react": "^16.11.0",
+    "react-dom": "^16.13.0",
+    "screenfull": "^4.2.1",
+    "vue": "2.6.10",
+    "vue-count-to": "^1.0.13",
+    "vue-dynamic-marquee": "^0.1.7",
+    "vue-particle-line": "^0.1.4",
+    "vue-quill-editor": "^3.0.6",
+    "vue-router": "3.0.6",
+    "vuedraggable": "^2.23.2",
+    "vuex": "3.1.0",
+    "xlsx": "^0.15.4"
+  },
+  "devDependencies": {
+    "@babel/core": "7.0.0",
+    "@babel/register": "7.0.0",
+    "@vue/cli-plugin-babel": "3.6.0",
+    "@vue/cli-plugin-eslint": "3.6.0",
+    "@vue/cli-plugin-unit-jest": "^3.8.0",
+    "@vue/cli-service": "3.6.0",
+    "@vue/test-utils": "1.0.0-beta.29",
+    "autoprefixer": "^9.5.1",
+    "babel-core": "7.0.0-bridge.0",
+    "babel-eslint": "8.0.1",
+    "babel-jest": "23.6.0",
+    "chalk": "2.4.2",
+    "connect": "3.6.6",
+    "eslint": "5.15.3",
+    "eslint-plugin-vue": "5.2.2",
+    "html-webpack-plugin": "3.2.0",
+    "mockjs": "1.0.1-beta3",
+    "node-sass": "^4.13.1",
+    "runjs": "^4.3.2",
+    "sass-loader": "^7.1.0",
+    "script-ext-html-webpack-plugin": "2.1.3",
+    "script-loader": "0.7.2",
+    "serve-static": "^1.13.2",
+    "svg-sprite-loader": "4.1.3",
+    "svgo": "1.2.2",
+    "vue-template-compiler": "2.6.10"
+  },
+  "engines": {
+    "node": ">=8.9",
+    "npm": ">= 3.0.0"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions"
+  ]
+}

+ 8 - 0
postcss.config.js

@@ -0,0 +1,8 @@
+// https://github.com/michael-ciniawsky/postcss-load-config
+
+module.exports = {
+  'plugins': {
+    // to edit target browsers: use "browserslist" field in package.json
+    'autoprefixer': {}
+  }
+}

+ 75 - 0
public/android_park.html

@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html lang="zh_CN">
+<head>
+    <meta charset="UTF-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="description" content="">
+    <meta name="keywords" content="">
+    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+    <meta name="renderer" content="webkit">
+    <style type="text/css">
+     *{margin:0; padding:0;}
+     a{text-decoration: none;}
+     img{max-width: 100%; height: auto;}
+
+    .download{color: #4D4D4D; padding: 7.2% 6.8% 9.3%;}
+    .download .entry-hd{font-size: 2.4em; font-weight: bold; text-align: center;}
+    .download-btn{padding-top: 9%; text-align: center;}
+    .download-btn .android-btn{ width:auto; margin:0 auto;}
+
+    .footer-bg{background: #2D2D2D; color: #E4E4E4; padding: 3.4% 2%; text-align: center;}
+    .footer-bg .entry-con{font-size: 1em;}
+
+    #weixin-tip{display:none; position: fixed; left:0; top:0; background: rgba(0,0,0,0.8); filter:alpha(opacity=80); width: 100%; height:100%; z-index: 100;}
+    #weixin-tip p{text-align: center; margin-top: 10%; padding:0 5%; position: relative;}
+    #weixin-tip .close{
+        color: #fff;
+        padding: 5px;
+        font: bold 20px/20px simsun;
+        text-shadow: 0 1px 0 #ddd;
+        position: absolute;
+        top: 0; left: 5%;
+    }
+    </style>
+    <title>尚贤湖基金park app下载</title>
+</head>
+<body class="success">
+    <div class="page-wrap">
+        <div class="download">
+            <h3 class="entry-hd">
+            </h3>
+            <div class="download-btn"><a href="https://jpark.idea-sf.com/app-dev-release.apk" class="android-btn" id="J_weixin">安卓版下载</a></div>
+        </div>
+        <div class="footer-bg">
+            <p class="entry-con">注:微信用户请在右上角选择“在浏览器中打开”,再选择下载应用</p>
+        </div>
+    </div>
+    <div id="weixin-tip"><p><img src="可访问到的图片路径.jpg" alt="微信打开"/><span id="close" title="关闭" class="close" style="color:black"   >×请在右上角选择“在浏览器中打开”,再选择下载应用</span></p></div>
+    <script type="text/javascript">
+    var is_weixin = (function() {
+        var ua = navigator.userAgent.toLowerCase();
+        if (ua.match(/MicroMessenger/i) == "micromessenger") {
+            return true;
+        } else {
+            return false;
+        }
+    })();
+    window.onload = function(){
+        var winHeight = typeof window.innerHeight != 'undefined' ? window.innerHeight : document.documentElement.clientHeight;
+        var btn = document.getElementById('J_weixin');
+        var tip = document.getElementById('weixin-tip');
+        var close = document.getElementById('close');
+        if(is_weixin){
+            btn.onclick = function(e){
+                tip.style.height = winHeight + 'px';
+                tip.style.display = 'block';
+                return false;
+            }
+            close.onclick = function(){
+                tip.style.display = 'none';
+            }
+        }
+    }
+    </script>
+</body>
+</html>

BIN
public/base.ico


BIN
public/base_1.ico


BIN
public/bmAddressBook.xlsx


BIN
public/dzAddressBook.xlsx


BIN
public/energy.xlsx


BIN
public/favicon.ico


+ 22 - 0
public/index.html

@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+    <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+    <link rel="icon" href="<%= BASE_URL %>base.ico">
+    <link rel="stylesheet" type="text/css" href="<%= BASE_URL %>jquery.zyslide.css">
+    <title><%= webpackConfig.name %></title>
+  </head>
+  <body>
+    <noscript>
+      <strong>We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
+    </noscript>
+    <script src="<%= BASE_URL %>tinymce4.7.5/tinymce.min.js"></script>
+    <script src="https://www.jq22.com/jquery/jquery-1.10.2.js"></script>
+	  <script src="<%= BASE_URL %>jquery.zyslide.js" type="text/javascript" charset="utf-8"></script>
+    <div id="app"></div>
+    <!-- built files will be auto injected -->
+  </body>
+</html>

+ 51 - 0
public/jquery.zyslide.css

@@ -0,0 +1,51 @@
+body,ul,li{
+	margin: 0;
+	padding: 0;
+}
+body{ background-color: #272727; color: white; }
+
+.zy-slide{
+	/* 两个 section (前一张、后一张) 要做相对定位 */
+	position: relative;
+	width: 754px;
+	height: 292px;
+	margin: 100px auto 0;
+	/*background-color: red;*/
+	/* 799 - 754 = 45 */
+}
+.zy-slide .zy-prev,.zy-slide .zy-next{
+	position: absolute;
+	top: 50%;
+	width: 40px;
+	height: 80px;
+	margin-top: -40px;
+	line-height: 80px;
+	text-align: center;
+	font-size: 13px;
+	cursor: pointer;
+}
+
+.zy-slide .zy-prev{
+	left: -60px;
+}
+.zy-slide .zy-next{
+	right: -60px;
+}
+.zy-slide ul{
+	position: relative;
+	width: 754px;
+	height: 292px;
+
+}
+.zy-slide li{
+	position: absolute;
+	width: 0;
+	height: 0;
+	list-style: none;
+	background-color: black;
+	border-radius: 5px;
+}
+.zy-slide li img{
+	width: 100%;
+	height: 100%;
+}

+ 139 - 0
public/jquery.zyslide.js

@@ -0,0 +1,139 @@
+// 自运行的匿名函数
+//(function(){
+//	alert('自运行的匿名函数');
+//})()
+
+//$(function(){
+//	alert('这是一句优美的句子');
+//})
+
+(function($){
+
+	// 本函数每次调用只负责一个轮播图的功能
+	// 也就是说只会产生一个轮播图,这个函数的作用域只能分配一个轮播图
+	// 所以要求在调用本函数的时候务必要将当前轮播图的根标签传过来。
+	// 这个参数 ele 就是某个轮播图的根标签
+	var slide = function(ele,options){
+		// 转换成 jquery 对象
+		var $ele = $(ele);
+		// 设置默认选项
+		var setting = {
+			// 控制刚炸开的时间
+			delay: 1000,
+			// 控制轮播图轮播的时间(轮播的速度)
+			speed: 2000
+		}
+
+		// 对象合并
+		$.extend(true, setting, options);
+
+		var states = [
+		{ZIndex: 1,width: 233,height: 145,top: 68,left: 66,ZOpacity: 0.2},
+		{ZIndex: 2,width: 253,height: 158,top: 61.5,left: 0,ZOpacity: 0.5},
+		{ZIndex: 3,width: 337,height: 210,top: 35.5,left: 110,ZOpacity: 0.7},
+		{ZIndex: 4,width: 450,height: 281,top: 0,left: 198,ZOpacity: 1},
+		{ZIndex: 3,width: 337,height: 210,top: 35.5,left: 399,ZOpacity: 0.7},
+		{ZIndex: 2,width: 253,height: 158,top: 61.5,left: 593,ZOpacity: 0.5},
+		{ZIndex: 1,width: 233,height: 145,top: 68,left: 547,ZOpacity: 0.2},
+	]
+
+	// 找到所有的 li
+	var lis = $ele.find('li');
+	// 让每个 li 对应上面 states 的每个状态
+	function move(){
+		lis.each(function(index,ele){
+			var state = states[index];
+			$(ele).css('z-index',state.ZIndex).finish().animate(state,setting.delay).find('img').css('opacity',state.ZOpacity);
+		});
+	}
+	move();
+
+	// 下一张,让轮播图发生偏移
+	function next(){
+		// 原理: 将数组最后一个元素移到数组的第一位
+		states.unshift(states.pop());
+		move();
+	}
+
+	// 上一张的方法,让轮播图发生偏移
+	function prev(){
+		// 将第一个移动到最后一位去
+		states.push(states.shift());
+		move();
+	}
+
+	// 点击下一张
+	$ele.find('.zy-next').click(function(){
+		next();
+	})
+
+	// 点击上一张
+	$ele.find('.zy-prev').click(function(){
+		prev();
+	})
+
+	// 自动轮播
+//	var interval = null;
+//	function autoPlay(){
+//		interval = setInterval(function(){
+//			next()
+//		},setting.speed);
+//	}
+//	autoPlay();
+
+	var interval = null ;
+	function autoPlay(){
+		interval = setInterval(function(){
+			next()
+		},setting.speed);
+	}
+	autoPlay();
+
+	$ele.find('section').hover(function(){
+		clearInterval(interval);
+	},function(){
+		autoPlay();
+	 })
+	}
+
+	// 找到要轮播 的轮播图的根标签,调用 slide 方法
+	$.fn.zySlide = function(options){
+		// this 执行的是我们 main.js 中查询到的轮播图
+		// 根标签
+//		console.log(this);
+
+		// 因为考虑到页面可能不止一个轮播图,所以我们要遍历出
+		// 所有的轮播图跟标签,然后执行轮播
+		$(this).each(function(i,ele){
+			slide(ele,options);
+		})
+		// 支持链式调用
+		return this;
+	}
+
+})(jQuery)
+
+
+
+
+/*
+ *  用 jQuery 封装插件的几种写法:
+ *
+ *  插件类写法:
+ *  $.fn.customFun = function(){
+ * 	    // 自定义插件的代码
+ *  }
+ *
+ *  用法:
+ *  $('selector').customFun();
+ *
+ *  工具类写法:
+ *  $.customFun = function(){
+ * 		// 自定义工具类的代码
+ *  }
+ *
+ *  用法:
+ *  $.customFun()
+ *
+ */
+

BIN
public/logo.png


+ 230 - 0
public/tinymce4.7.5/langs/zh_CN.js

@@ -0,0 +1,230 @@
+tinymce.addI18n('zh_CN',{
+"Cut": "\u526a\u5207",
+"Heading 5": "\u6807\u98985",
+"Header 2": "\u6807\u98982",
+"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u4f60\u7684\u6d4f\u89c8\u5668\u4e0d\u652f\u6301\u5bf9\u526a\u8d34\u677f\u7684\u8bbf\u95ee\uff0c\u8bf7\u4f7f\u7528Ctrl+X\/C\/V\u952e\u8fdb\u884c\u590d\u5236\u7c98\u8d34\u3002",
+"Heading 4": "\u6807\u98984",
+"Div": "Div\u533a\u5757",
+"Heading 2": "\u6807\u98982",
+"Paste": "\u7c98\u8d34",
+"Close": "\u5173\u95ed",
+"Font Family": "\u5b57\u4f53",
+"Pre": "\u9884\u683c\u5f0f\u6587\u672c",
+"Align right": "\u53f3\u5bf9\u9f50",
+"New document": "\u65b0\u6587\u6863",
+"Blockquote": "\u5f15\u7528",
+"Numbered list": "\u7f16\u53f7\u5217\u8868",
+"Heading 1": "\u6807\u98981",
+"Headings": "\u6807\u9898",
+"Increase indent": "\u589e\u52a0\u7f29\u8fdb",
+"Formats": "\u683c\u5f0f",
+"Headers": "\u6807\u9898",
+"Select all": "\u5168\u9009",
+"Header 3": "\u6807\u98983",
+"Blocks": "\u533a\u5757",
+"Undo": "\u64a4\u6d88",
+"Strikethrough": "\u5220\u9664\u7ebf",
+"Bullet list": "\u9879\u76ee\u7b26\u53f7",
+"Header 1": "\u6807\u98981",
+"Superscript": "\u4e0a\u6807",
+"Clear formatting": "\u6e05\u9664\u683c\u5f0f",
+"Font Sizes": "\u5b57\u53f7",
+"Subscript": "\u4e0b\u6807",
+"Header 6": "\u6807\u98986",
+"Redo": "\u91cd\u590d",
+"Paragraph": "\u6bb5\u843d",
+"Ok": "\u786e\u5b9a",
+"Bold": "\u7c97\u4f53",
+"Code": "\u4ee3\u7801",
+"Italic": "\u659c\u4f53",
+"Align center": "\u5c45\u4e2d",
+"Header 5": "\u6807\u98985",
+"Heading 6": "\u6807\u98986",
+"Heading 3": "\u6807\u98983",
+"Decrease indent": "\u51cf\u5c11\u7f29\u8fdb",
+"Header 4": "\u6807\u98984",
+"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u5f53\u524d\u4e3a\u7eaf\u6587\u672c\u7c98\u8d34\u6a21\u5f0f\uff0c\u518d\u6b21\u70b9\u51fb\u53ef\u4ee5\u56de\u5230\u666e\u901a\u7c98\u8d34\u6a21\u5f0f\u3002",
+"Underline": "\u4e0b\u5212\u7ebf",
+"Cancel": "\u53d6\u6d88",
+"Justify": "\u4e24\u7aef\u5bf9\u9f50",
+"Inline": "\u6587\u672c",
+"Copy": "\u590d\u5236",
+"Align left": "\u5de6\u5bf9\u9f50",
+"Visual aids": "\u7f51\u683c\u7ebf",
+"Lower Greek": "\u5c0f\u5199\u5e0c\u814a\u5b57\u6bcd",
+"Square": "\u65b9\u5757",
+"Default": "\u9ed8\u8ba4",
+"Lower Alpha": "\u5c0f\u5199\u82f1\u6587\u5b57\u6bcd",
+"Circle": "\u7a7a\u5fc3\u5706",
+"Disc": "\u5b9e\u5fc3\u5706",
+"Upper Alpha": "\u5927\u5199\u82f1\u6587\u5b57\u6bcd",
+"Upper Roman": "\u5927\u5199\u7f57\u9a6c\u5b57\u6bcd",
+"Lower Roman": "\u5c0f\u5199\u7f57\u9a6c\u5b57\u6bcd",
+"Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "\u6807\u8bc6\u7b26\u5e94\u8be5\u4ee5\u5b57\u6bcd\u5f00\u5934\uff0c\u540e\u8ddf\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u7834\u6298\u53f7\u3001\u70b9\u3001\u5192\u53f7\u6216\u4e0b\u5212\u7ebf\u3002",
+"Name": "\u540d\u79f0",
+"Anchor": "\u951a\u70b9",
+"Id": "\u6807\u8bc6\u7b26",
+"You have unsaved changes are you sure you want to navigate away?": "\u4f60\u8fd8\u6709\u6587\u6863\u5c1a\u672a\u4fdd\u5b58\uff0c\u786e\u5b9a\u8981\u79bb\u5f00\uff1f",
+"Restore last draft": "\u6062\u590d\u4e0a\u6b21\u7684\u8349\u7a3f",
+"Special character": "\u7279\u6b8a\u7b26\u53f7",
+"Source code": "\u6e90\u4ee3\u7801",
+"Language": "\u8bed\u8a00",
+"Insert\/Edit code sample": "\u63d2\u5165\/\u7f16\u8f91\u4ee3\u7801\u793a\u4f8b",
+"B": "B",
+"R": "R",
+"G": "G",
+"Color": "\u989c\u8272",
+"Right to left": "\u4ece\u53f3\u5230\u5de6",
+"Left to right": "\u4ece\u5de6\u5230\u53f3",
+"Emoticons": "\u8868\u60c5",
+"Robots": "\u673a\u5668\u4eba",
+"Document properties": "\u6587\u6863\u5c5e\u6027",
+"Title": "\u6807\u9898",
+"Keywords": "\u5173\u952e\u8bcd",
+"Encoding": "\u7f16\u7801",
+"Description": "\u63cf\u8ff0",
+"Author": "\u4f5c\u8005",
+"Fullscreen": "\u5168\u5c4f",
+"Horizontal line": "\u6c34\u5e73\u5206\u5272\u7ebf",
+"Horizontal space": "\u6c34\u5e73\u8fb9\u8ddd",
+"Insert\/edit image": "\u63d2\u5165\/\u7f16\u8f91\u56fe\u7247",
+"General": "\u666e\u901a",
+"Advanced": "\u9ad8\u7ea7",
+"Source": "\u5730\u5740",
+"Border": "\u8fb9\u6846",
+"Constrain proportions": "\u4fdd\u6301\u7eb5\u6a2a\u6bd4",
+"Vertical space": "\u5782\u76f4\u8fb9\u8ddd",
+"Image description": "\u56fe\u7247\u63cf\u8ff0",
+"Style": "\u6837\u5f0f",
+"Dimensions": "\u5927\u5c0f",
+"Insert image": "\u63d2\u5165\u56fe\u7247",
+"Image": "\u56fe\u7247",
+"Zoom in": "\u653e\u5927",
+"Contrast": "\u5bf9\u6bd4\u5ea6",
+"Back": "\u540e\u9000",
+"Gamma": "\u4f3d\u9a6c\u503c",
+"Flip horizontally": "\u6c34\u5e73\u7ffb\u8f6c",
+"Resize": "\u8c03\u6574\u5927\u5c0f",
+"Sharpen": "\u9510\u5316",
+"Zoom out": "\u7f29\u5c0f",
+"Image options": "\u56fe\u7247\u9009\u9879",
+"Apply": "\u5e94\u7528",
+"Brightness": "\u4eae\u5ea6",
+"Rotate clockwise": "\u987a\u65f6\u9488\u65cb\u8f6c",
+"Rotate counterclockwise": "\u9006\u65f6\u9488\u65cb\u8f6c",
+"Edit image": "\u7f16\u8f91\u56fe\u7247",
+"Color levels": "\u989c\u8272\u5c42\u6b21",
+"Crop": "\u88c1\u526a",
+"Orientation": "\u65b9\u5411",
+"Flip vertically": "\u5782\u76f4\u7ffb\u8f6c",
+"Invert": "\u53cd\u8f6c",
+"Date\/time": "\u65e5\u671f\/\u65f6\u95f4",
+"Insert date\/time": "\u63d2\u5165\u65e5\u671f\/\u65f6\u95f4",
+"Remove link": "\u5220\u9664\u94fe\u63a5",
+"Url": "\u5730\u5740",
+"Text to display": "\u663e\u793a\u6587\u5b57",
+"Anchors": "\u951a\u70b9",
+"Insert link": "\u63d2\u5165\u94fe\u63a5",
+"Link": "\u94fe\u63a5",
+"New window": "\u5728\u65b0\u7a97\u53e3\u6253\u5f00",
+"None": "\u65e0",
+"The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u5c5e\u4e8e\u5916\u90e8\u94fe\u63a5\uff0c\u9700\u8981\u52a0\u4e0ahttp:\/\/:\u524d\u7f00\u5417\uff1f",
+"Paste or type a link": "\u7c98\u8d34\u6216\u8f93\u5165\u94fe\u63a5",
+"Target": "\u6253\u5f00\u65b9\u5f0f",
+"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u4e3a\u90ae\u4ef6\u5730\u5740\uff0c\u9700\u8981\u52a0\u4e0amailto:\u524d\u7f00\u5417\uff1f",
+"Insert\/edit link": "\u63d2\u5165\/\u7f16\u8f91\u94fe\u63a5",
+"Insert\/edit video": "\u63d2\u5165\/\u7f16\u8f91\u89c6\u9891",
+"Media": "\u5a92\u4f53",
+"Alternative source": "\u955c\u50cf",
+"Paste your embed code below:": "\u5c06\u5185\u5d4c\u4ee3\u7801\u7c98\u8d34\u5728\u4e0b\u9762:",
+"Insert video": "\u63d2\u5165\u89c6\u9891",
+"Poster": "\u5c01\u9762",
+"Insert\/edit media": "\u63d2\u5165\/\u7f16\u8f91\u5a92\u4f53",
+"Embed": "\u5185\u5d4c",
+"Nonbreaking space": "\u4e0d\u95f4\u65ad\u7a7a\u683c",
+"Page break": "\u5206\u9875\u7b26",
+"Paste as text": "\u7c98\u8d34\u4e3a\u6587\u672c",
+"Preview": "\u9884\u89c8",
+"Print": "\u6253\u5370",
+"Save": "\u4fdd\u5b58",
+"Could not find the specified string.": "\u672a\u627e\u5230\u641c\u7d22\u5185\u5bb9.",
+"Replace": "\u66ff\u6362",
+"Next": "\u4e0b\u4e00\u4e2a",
+"Whole words": "\u5168\u5b57\u5339\u914d",
+"Find and replace": "\u67e5\u627e\u548c\u66ff\u6362",
+"Replace with": "\u66ff\u6362\u4e3a",
+"Find": "\u67e5\u627e",
+"Replace all": "\u5168\u90e8\u66ff\u6362",
+"Match case": "\u533a\u5206\u5927\u5c0f\u5199",
+"Prev": "\u4e0a\u4e00\u4e2a",
+"Spellcheck": "\u62fc\u5199\u68c0\u67e5",
+"Finish": "\u5b8c\u6210",
+"Ignore all": "\u5168\u90e8\u5ffd\u7565",
+"Ignore": "\u5ffd\u7565",
+"Add to Dictionary": "\u6dfb\u52a0\u5230\u5b57\u5178",
+"Insert row before": "\u5728\u4e0a\u65b9\u63d2\u5165",
+"Rows": "\u884c",
+"Height": "\u9ad8",
+"Paste row after": "\u7c98\u8d34\u5230\u4e0b\u65b9",
+"Alignment": "\u5bf9\u9f50\u65b9\u5f0f",
+"Border color": "\u8fb9\u6846\u989c\u8272",
+"Column group": "\u5217\u7ec4",
+"Row": "\u884c",
+"Insert column before": "\u5728\u5de6\u4fa7\u63d2\u5165",
+"Split cell": "\u62c6\u5206\u5355\u5143\u683c",
+"Cell padding": "\u5355\u5143\u683c\u5185\u8fb9\u8ddd",
+"Cell spacing": "\u5355\u5143\u683c\u5916\u95f4\u8ddd",
+"Row type": "\u884c\u7c7b\u578b",
+"Insert table": "\u63d2\u5165\u8868\u683c",
+"Body": "\u8868\u4f53",
+"Caption": "\u6807\u9898",
+"Footer": "\u8868\u5c3e",
+"Delete row": "\u5220\u9664\u884c",
+"Paste row before": "\u7c98\u8d34\u5230\u4e0a\u65b9",
+"Scope": "\u8303\u56f4",
+"Delete table": "\u5220\u9664\u8868\u683c",
+"H Align": "\u6c34\u5e73\u5bf9\u9f50",
+"Top": "\u9876\u90e8\u5bf9\u9f50",
+"Header cell": "\u8868\u5934\u5355\u5143\u683c",
+"Column": "\u5217",
+"Row group": "\u884c\u7ec4",
+"Cell": "\u5355\u5143\u683c",
+"Middle": "\u5782\u76f4\u5c45\u4e2d",
+"Cell type": "\u5355\u5143\u683c\u7c7b\u578b",
+"Copy row": "\u590d\u5236\u884c",
+"Row properties": "\u884c\u5c5e\u6027",
+"Table properties": "\u8868\u683c\u5c5e\u6027",
+"Bottom": "\u5e95\u90e8\u5bf9\u9f50",
+"V Align": "\u5782\u76f4\u5bf9\u9f50",
+"Header": "\u8868\u5934",
+"Right": "\u53f3\u5bf9\u9f50",
+"Insert column after": "\u5728\u53f3\u4fa7\u63d2\u5165",
+"Cols": "\u5217",
+"Insert row after": "\u5728\u4e0b\u65b9\u63d2\u5165",
+"Width": "\u5bbd",
+"Cell properties": "\u5355\u5143\u683c\u5c5e\u6027",
+"Left": "\u5de6\u5bf9\u9f50",
+"Cut row": "\u526a\u5207\u884c",
+"Delete column": "\u5220\u9664\u5217",
+"Center": "\u5c45\u4e2d",
+"Merge cells": "\u5408\u5e76\u5355\u5143\u683c",
+"Insert template": "\u63d2\u5165\u6a21\u677f",
+"Templates": "\u6a21\u677f",
+"Background color": "\u80cc\u666f\u8272",
+"Custom...": "\u81ea\u5b9a\u4e49...",
+"Custom color": "\u81ea\u5b9a\u4e49\u989c\u8272",
+"No color": "\u65e0",
+"Text color": "\u6587\u5b57\u989c\u8272",
+"Table of Contents": "\u5185\u5bb9\u5217\u8868",
+"Show blocks": "\u663e\u793a\u533a\u5757\u8fb9\u6846",
+"Show invisible characters": "\u663e\u793a\u4e0d\u53ef\u89c1\u5b57\u7b26",
+"Words: {0}": "\u5b57\u6570\uff1a{0}",
+"Insert": "\u63d2\u5165",
+"File": "\u6587\u4ef6",
+"Edit": "\u7f16\u8f91",
+"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u5728\u7f16\u8f91\u533a\u6309ALT-F9\u6253\u5f00\u83dc\u5355\uff0c\u6309ALT-F10\u6253\u5f00\u5de5\u5177\u680f\uff0c\u6309ALT-0\u67e5\u770b\u5e2e\u52a9",
+"Tools": "\u5de5\u5177",
+"View": "\u89c6\u56fe",
+"Table": "\u8868\u683c",
+"Format": "\u683c\u5f0f"
+});

+ 138 - 0
public/tinymce4.7.5/plugins/codesample/css/prism.css

@@ -0,0 +1,138 @@
+/* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript */
+/**
+ * prism.js default theme for JavaScript, CSS and HTML
+ * Based on dabblet (http://dabblet.com)
+ * @author Lea Verou
+ */
+
+code[class*="language-"],
+pre[class*="language-"] {
+  color: black;
+  text-shadow: 0 1px white;
+  font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
+  direction: ltr;
+  text-align: left;
+  white-space: pre;
+  word-spacing: normal;
+  word-break: normal;
+  word-wrap: normal;
+  line-height: 1.5;
+
+  -moz-tab-size: 4;
+  -o-tab-size: 4;
+  tab-size: 4;
+
+  -webkit-hyphens: none;
+  -moz-hyphens: none;
+  -ms-hyphens: none;
+  hyphens: none;
+}
+
+pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
+code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
+  text-shadow: none;
+  background: #b3d4fc;
+}
+
+pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
+code[class*="language-"]::selection, code[class*="language-"] ::selection {
+  text-shadow: none;
+  background: #b3d4fc;
+}
+
+@media print {
+  code[class*="language-"],
+  pre[class*="language-"] {
+    text-shadow: none;
+  }
+}
+
+/* Code blocks */
+pre[class*="language-"] {
+  padding: 1em;
+  margin: .5em 0;
+  overflow: auto;
+}
+
+:not(pre) > code[class*="language-"],
+pre[class*="language-"] {
+  background: #f5f2f0;
+}
+
+/* Inline code */
+:not(pre) > code[class*="language-"] {
+  padding: .1em;
+  border-radius: .3em;
+}
+
+.token.comment,
+.token.prolog,
+.token.doctype,
+.token.cdata {
+  color: slategray;
+}
+
+.token.punctuation {
+  color: #999;
+}
+
+.namespace {
+  opacity: .7;
+}
+
+.token.property,
+.token.tag,
+.token.boolean,
+.token.number,
+.token.constant,
+.token.symbol,
+.token.deleted {
+  color: #905;
+}
+
+.token.selector,
+.token.attr-name,
+.token.string,
+.token.char,
+.token.builtin,
+.token.inserted {
+  color: #690;
+}
+
+.token.operator,
+.token.entity,
+.token.url,
+.language-css .token.string,
+.style .token.string {
+  color: #a67f59;
+  background: hsla(0, 0%, 100%, .5);
+}
+
+.token.atrule,
+.token.attr-value,
+.token.keyword {
+  color: #07a;
+}
+
+.token.function {
+  color: #DD4A68;
+}
+
+.token.regex,
+.token.important,
+.token.variable {
+  color: #e90;
+}
+
+.token.important,
+.token.bold {
+  font-weight: bold;
+}
+.token.italic {
+  font-style: italic;
+}
+
+.token.entity {
+  cursor: help;
+}
+

BIN
public/tinymce4.7.5/plugins/emoticons/img/smiley-cool.gif


BIN
public/tinymce4.7.5/plugins/emoticons/img/smiley-cry.gif


BIN
public/tinymce4.7.5/plugins/emoticons/img/smiley-embarassed.gif


BIN
public/tinymce4.7.5/plugins/emoticons/img/smiley-foot-in-mouth.gif


BIN
public/tinymce4.7.5/plugins/emoticons/img/smiley-frown.gif


BIN
public/tinymce4.7.5/plugins/emoticons/img/smiley-innocent.gif


BIN
public/tinymce4.7.5/plugins/emoticons/img/smiley-kiss.gif


BIN
public/tinymce4.7.5/plugins/emoticons/img/smiley-laughing.gif


BIN
public/tinymce4.7.5/plugins/emoticons/img/smiley-money-mouth.gif


BIN
public/tinymce4.7.5/plugins/emoticons/img/smiley-sealed.gif


BIN
public/tinymce4.7.5/plugins/emoticons/img/smiley-smile.gif


BIN
public/tinymce4.7.5/plugins/emoticons/img/smiley-surprised.gif


BIN
public/tinymce4.7.5/plugins/emoticons/img/smiley-tongue-out.gif


BIN
public/tinymce4.7.5/plugins/emoticons/img/smiley-undecided.gif


BIN
public/tinymce4.7.5/plugins/emoticons/img/smiley-wink.gif


BIN
public/tinymce4.7.5/plugins/emoticons/img/smiley-yell.gif


+ 59 - 0
public/tinymce4.7.5/plugins/lineheight/plugin.js

@@ -0,0 +1,59 @@
+tinymce.PluginManager.add('lineheight', function(editor, url) {
+    var pluginName='设置行高';
+    var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools');
+    var lineheight_val = editor.getParam('lineheight_val', '1 1.5 1.6 1.75 1.8 2 3 4 5');
+
+    editor.on('init', function() {
+        editor.formatter.register({
+            lineheight: {
+                selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table',
+                styles: { 'line-height': '%value' }
+            }
+        });
+    });
+
+    var doAct = function (value) {
+        editor.formatter.apply('lineheight', { value: value });
+        editor.fire('change', {});
+    };
+
+    editor.ui.registry.getAll().icons.lineheight || editor.ui.registry.addIcon('lineheight','<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M9.984 12.984v-1.969h12v1.969h-12zM9.984 18.984v-1.969h12v1.969h-12zM9.984 5.016h12v1.969h-12v-1.969zM6 6.984v10.031h2.484l-3.469 3.469-3.516-3.469h2.484v-10.031h-2.484l3.516-3.469 3.469 3.469h-2.484z"></path></svg>');
+
+    editor.ui.registry.addMenuButton('lineheight', {
+        icon: 'lineheight',
+        tooltip: pluginName,
+        fetch: function(callback) {
+            var dom = editor.dom;
+            var blocks = editor.selection.getSelectedBlocks();
+            var lhv = 0;
+            global$1.each(blocks, function(block) {
+                if(lhv==0){
+                    lhv = dom.getStyle(block,'line-height') ? dom.getStyle(block,'line-height') : 0;
+                }
+            });
+
+            var items = lineheight_val.split(' ').map(function(item){
+                var text = item;
+                var value = item;
+                return {
+                    type: 'togglemenuitem',
+                    text: text,
+                    active : lhv==value ? true :false,
+                    onAction: function() {
+                        doAct(value);
+                    }
+                };
+            });
+            callback(items);
+        }
+    });
+
+    return {
+        getMetadata: function () {
+            return  {
+                name: pluginName,
+                url: "http://tinymce.ax-z.cn/more-plugins/lineheight.php",
+            };
+        }
+    };
+});

+ 59 - 0
public/tinymce4.7.5/plugins/lineheight/plugin.min.js

@@ -0,0 +1,59 @@
+tinymce.PluginManager.add('lineheight', function(editor, url) {
+    var pluginName='设置行高';
+    var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools');
+    var lineheight_val = editor.getParam('lineheight_val', '1 1.5 1.6 1.75 1.8 2 3 4 5');
+
+    editor.on('init', function() {
+        editor.formatter.register({
+            lineheight: {
+                selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table',
+                styles: { 'line-height': '%value' }
+            }
+        });
+    });
+
+    var doAct = function (value) {
+        editor.formatter.apply('lineheight', { value: value });
+        editor.fire('change', {});
+    };
+
+    editor.ui.registry.getAll().icons.lineheight || editor.ui.registry.addIcon('lineheight','<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M9.984 12.984v-1.969h12v1.969h-12zM9.984 18.984v-1.969h12v1.969h-12zM9.984 5.016h12v1.969h-12v-1.969zM6 6.984v10.031h2.484l-3.469 3.469-3.516-3.469h2.484v-10.031h-2.484l3.516-3.469 3.469 3.469h-2.484z"></path></svg>');
+
+    editor.ui.registry.addMenuButton('lineheight', {
+        icon: 'lineheight',
+        tooltip: pluginName,
+        fetch: function(callback) {
+            var dom = editor.dom;
+            var blocks = editor.selection.getSelectedBlocks();
+            var lhv = 0;
+            global$1.each(blocks, function(block) {
+                if(lhv==0){
+                    lhv = dom.getStyle(block,'line-height') ? dom.getStyle(block,'line-height') : 0;
+                }
+            });
+
+            var items = lineheight_val.split(' ').map(function(item){
+                var text = item;
+                var value = item;
+                return {
+                    type: 'togglemenuitem',
+                    text: text,
+                    active : lhv==value ? true :false,
+                    onAction: function() {
+                        doAct(value);
+                    }
+                };
+            });
+            callback(items);
+        }
+    });
+
+    return {
+        getMetadata: function () {
+            return  {
+                name: pluginName,
+                url: "http://tinymce.ax-z.cn/more-plugins/lineheight.php",
+            };
+        }
+    };
+});

+ 154 - 0
public/tinymce4.7.5/plugins/visualblocks/css/visualblocks.css

@@ -0,0 +1,154 @@
+.mce-visualblocks p {
+  padding-top: 10px;
+  border: 1px dashed #BBB;
+  margin-left: 3px;
+  background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7);
+  background-repeat: no-repeat;
+}
+
+.mce-visualblocks h1 {
+  padding-top: 10px;
+  border: 1px dashed #BBB;
+  margin-left: 3px;
+  background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==);
+  background-repeat: no-repeat;
+}
+
+.mce-visualblocks h2 {
+  padding-top: 10px;
+  border: 1px dashed #BBB;
+  margin-left: 3px;
+  background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==);
+  background-repeat: no-repeat;
+}
+
+.mce-visualblocks h3 {
+  padding-top: 10px;
+  border: 1px dashed #BBB;
+  margin-left: 3px;
+  background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7);
+  background-repeat: no-repeat;
+}
+
+.mce-visualblocks h4 {
+  padding-top: 10px;
+  border: 1px dashed #BBB;
+  margin-left: 3px;
+  background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==);
+  background-repeat: no-repeat;
+}
+
+.mce-visualblocks h5 {
+  padding-top: 10px;
+  border: 1px dashed #BBB;
+  margin-left: 3px;
+  background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==);
+  background-repeat: no-repeat;
+}
+
+.mce-visualblocks h6 {
+  padding-top: 10px;
+  border: 1px dashed #BBB;
+  margin-left: 3px;
+  background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==);
+  background-repeat: no-repeat;
+}
+
+.mce-visualblocks div:not([data-mce-bogus]) {
+  padding-top: 10px;
+  border: 1px dashed #BBB;
+  margin-left: 3px;
+  background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7);
+  background-repeat: no-repeat;
+}
+
+.mce-visualblocks section {
+  padding-top: 10px;
+  border: 1px dashed #BBB;
+  margin: 0 0 1em 3px;
+  background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=);
+  background-repeat: no-repeat;
+}
+
+.mce-visualblocks article {
+  padding-top: 10px;
+  border: 1px dashed #BBB;
+  margin: 0 0 1em 3px;
+  background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7);
+  background-repeat: no-repeat;
+}
+
+.mce-visualblocks blockquote {
+  padding-top: 10px;
+  border: 1px dashed #BBB;
+  background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7);
+  background-repeat: no-repeat;
+}
+
+.mce-visualblocks address {
+  padding-top: 10px;
+  border: 1px dashed #BBB;
+  margin: 0 0 1em 3px;
+  background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=);
+  background-repeat: no-repeat;
+}
+
+.mce-visualblocks pre {
+  padding-top: 10px;
+  border: 1px dashed #BBB;
+  margin-left: 3px;
+  background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==);
+  background-repeat: no-repeat;
+}
+
+.mce-visualblocks figure {
+  padding-top: 10px;
+  border: 1px dashed #BBB;
+  margin: 0 0 1em 3px;
+  background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7);
+  background-repeat: no-repeat;
+}
+
+.mce-visualblocks hgroup {
+  padding-top: 10px;
+  border: 1px dashed #BBB;
+  margin: 0 0 1em 3px;
+  background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7);
+  background-repeat: no-repeat;
+}
+
+.mce-visualblocks aside {
+  padding-top: 10px;
+  border: 1px dashed #BBB;
+  margin: 0 0 1em 3px;
+  background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=);
+  background-repeat: no-repeat;
+}
+
+.mce-visualblocks figcaption {
+  border: 1px dashed #BBB;
+}
+
+.mce-visualblocks ul {
+  padding-top: 10px;
+  border: 1px dashed #BBB;
+  margin: 0 0 1em 3px;
+  background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==);
+  background-repeat: no-repeat;
+}
+
+.mce-visualblocks ol {
+  padding-top: 10px;
+  border: 1px dashed #BBB;
+  margin: 0 0 1em 3px;
+  background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==);
+  background-repeat: no-repeat;
+}
+
+.mce-visualblocks dl {
+  padding-top: 10px;
+  border: 1px dashed #BBB;
+  margin: 0 0 1em 3px;
+  background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==);
+  background-repeat: no-repeat;
+}

Різницю між файлами не показано, бо вона завелика
+ 1 - 0
public/tinymce4.7.5/skins/lightgray/content.inline.min.css


Різницю між файлами не показано, бо вона завелика
+ 1 - 0
public/tinymce4.7.5/skins/lightgray/content.min.css


BIN
public/tinymce4.7.5/skins/lightgray/fonts/tinymce-mobile.woff


BIN
public/tinymce4.7.5/skins/lightgray/fonts/tinymce-small.eot


Різницю між файлами не показано, бо вона завелика
+ 63 - 0
public/tinymce4.7.5/skins/lightgray/fonts/tinymce-small.svg


BIN
public/tinymce4.7.5/skins/lightgray/fonts/tinymce-small.ttf


BIN
public/tinymce4.7.5/skins/lightgray/fonts/tinymce-small.woff


BIN
public/tinymce4.7.5/skins/lightgray/fonts/tinymce.eot


Різницю між файлами не показано, бо вона завелика
+ 131 - 0
public/tinymce4.7.5/skins/lightgray/fonts/tinymce.svg


BIN
public/tinymce4.7.5/skins/lightgray/fonts/tinymce.ttf


BIN
public/tinymce4.7.5/skins/lightgray/fonts/tinymce.woff


BIN
public/tinymce4.7.5/skins/lightgray/img/anchor.gif


BIN
public/tinymce4.7.5/skins/lightgray/img/loader.gif


BIN
public/tinymce4.7.5/skins/lightgray/img/object.gif


BIN
public/tinymce4.7.5/skins/lightgray/img/trans.gif


Різницю між файлами не показано, бо вона завелика
+ 1 - 0
public/tinymce4.7.5/skins/lightgray/skin.min.css


Різницю між файлами не показано, бо вона завелика
+ 1 - 0
public/tinymce4.7.5/skins/lightgray/skin.min.css.map


Різницю між файлами не показано, бо вона завелика
+ 2 - 0
public/tinymce4.7.5/tinymce.min.js


BIN
public/ywAddressBook .xlsx


BIN
public/yy-wyAddressBook.xlsx


+ 18 - 0
src/App.vue

@@ -0,0 +1,18 @@
+<template>
+  <div id="app">
+    <router-view />
+  </div>
+</template>
+
+<script>
+export default {
+    name: 'App'
+}
+</script>
+<style>
+
+body .el-table th.gutter{
+    display: table-cell!important;
+}
+
+</style>

+ 41 - 0
src/api/admin.js

@@ -0,0 +1,41 @@
+import request from '@/static/utils/request'
+
+export function listAdmin(query) {
+    return request({
+        url: '/admin/list',
+        method: 'get',
+        params: query
+    })
+}
+
+export function createAdmin(data) {
+    return request({
+        url: '/admin/create',
+        method: 'post',
+        data
+    })
+}
+
+export function readminAdmin(data) {
+    return request({
+        url: '/admin/readmin',
+        method: 'get',
+        data
+    })
+}
+
+export function updateAdmin(data) {
+    return request({
+        url: '/admin/update',
+        method: 'post',
+        data
+    })
+}
+
+export function deleteAdmin(data) {
+    return request({
+        url: '/admin/delete',
+        method: 'post',
+        data
+    })
+}

+ 7 - 0
src/api/remote-search.js

@@ -0,0 +1,7 @@
+// import request from '@/utils/request'
+
+export function searchUser(name) {
+}
+
+export function transactionList(query) {
+}

+ 65 - 0
src/api/role.js

@@ -0,0 +1,65 @@
+import request from '@/static/utils/request'
+
+export function listRole(query) {
+    return request({
+        url: '/role/list',
+        method: 'get',
+        params: query
+    })
+}
+
+export function createRole(data) {
+    return request({
+        url: '/role/create',
+        method: 'post',
+        data
+    })
+}
+
+export function readRole(data) {
+    return request({
+        url: '/role/read',
+        method: 'get',
+        data
+    })
+}
+
+export function updateRole(data) {
+    return request({
+        url: '/role/update',
+        method: 'post',
+        data
+    })
+}
+
+export function deleteRole(data) {
+    return request({
+        url: '/role/delete',
+        method: 'post',
+        data
+    })
+}
+
+export function getPermission(query) {
+    return request({
+        url: '/role/permissions',
+        method: 'get',
+        params: query
+    })
+}
+
+export function updatePermission(data) {
+    return request({
+        url: '/role/permissions',
+        method: 'post',
+        data
+    })
+}
+
+export function roleOptions(query) {
+    return request({
+        url: '/role/options',
+        method: 'get',
+        params: query
+    })
+}

+ 9 - 0
src/api/table.js

@@ -0,0 +1,9 @@
+import request from '@/static/utils/request'
+
+export function getList(params) {
+  return request({
+    url: '/table/list',
+    method: 'get',
+    params
+  })
+}

+ 61 - 0
src/api/user.js

@@ -0,0 +1,61 @@
+import request from '@/static/utils/request'
+import qs from 'qs'
+// import axios from 'axios'
+
+const serverUrl = 'http://127.0.0.1:8080/'
+
+const users = {
+    'admin-token': {
+        perms: ['admin'],
+        introduction: 'I am a super administrator',
+        avatar: require('../static/images/header.gif'),
+        name: 'Super Admin'
+        // perms: ['GET /admin/admin/list', 'GET /admin/role/list']
+    },
+    'editor-token': {
+        perms: ['editor'],
+        introduction: 'I am an editor',
+        avatar: require('../static/images/header.gif'),
+        name: 'Normal Editor'
+        // perms: []
+    }
+}
+
+export function login(data) {
+    const x_data = qs.stringify(data)
+    return request({
+        url: serverUrl + '/web/login',
+        method: 'post',
+        headers: { 'Access-Control-Allow-Origin': '*' },
+        x_data
+    })
+}
+export function getInfo(token) {
+    return new Promise((resolve, reject) => {
+        const info = users[token]
+        if (!info) {
+            const rej = {
+                code: 50008,
+                message: 'Login failed, unable to get user details.'
+            }
+            reject(rej)
+        } else {
+            const res = {
+                code: 20000,
+                data: info
+            }
+            resolve(res)
+            // debugger
+        }
+    })
+}
+
+export function logout() {
+    return new Promise((resolve, reject) => {
+        const res = {
+            code: 20000,
+            data: 'success'
+        }
+        resolve(res)
+    })
+}

BIN
src/assets/404_images/404.png


BIN
src/assets/404_images/404_cloud.png


+ 70 - 0
src/components/Breadcrumb/index.vue

@@ -0,0 +1,70 @@
+<template>
+  <el-breadcrumb class="app-breadcrumb" separator="/">
+    <transition-group name="breadcrumb">
+      <el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
+        <span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span>
+        <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
+      </el-breadcrumb-item>
+    </transition-group>
+  </el-breadcrumb>
+</template>
+
+<script>
+import pathToRegexp from 'path-to-regexp'
+
+export default {
+    data() {
+        return {
+            levelList: null
+        }
+    },
+    watch: {
+        $route() {
+            this.getBreadcrumb()
+        }
+    },
+    created() {
+        this.getBreadcrumb()
+    },
+    methods: {
+        getBreadcrumb() {
+            const matched = this.$route.matched.filter(item => item.meta && item.meta.title)
+            this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
+        },
+        isDashboard(route) {
+            const name = route && route.name
+            if (!name) {
+                return false
+            }
+            return name.trim().toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase()
+        },
+        pathCompile(path) {
+            const { params } = this.$route
+            var toPath = pathToRegexp.compile(path)
+            return toPath(params)
+        },
+        handleLink(item) {
+            const { redirect, path } = item
+            if (redirect) {
+                this.$router.push(redirect)
+                return
+            }
+            this.$router.push(this.pathCompile(path))
+        }
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+.app-breadcrumb.el-breadcrumb {
+  display: inline-block;
+  font-size: 14px;
+  line-height: 50px;
+  margin-left: 8px;
+
+  .no-redirect {
+    color: #97a8be;
+    cursor: text;
+  }
+}
+</style>

+ 44 - 0
src/components/Hamburger/index.vue

@@ -0,0 +1,44 @@
+<template>
+  <div style="padding: 0 15px;" @click="toggleClick">
+    <svg
+      :class="{'is-active':isActive}"
+      class="hamburger"
+      viewBox="0 0 1024 1024"
+      xmlns="http://www.w3.org/2000/svg"
+      width="64"
+      height="64"
+    >
+      <path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
+    </svg>
+  </div>
+</template>
+
+<script>
+export default {
+    name: 'Hamburger',
+    props: {
+        isActive: {
+            type: Boolean,
+            default: false
+        }
+    },
+    methods: {
+        toggleClick() {
+            this.$emit('toggleClick')
+        }
+    }
+}
+</script>
+
+<style scoped>
+.hamburger {
+  display: inline-block;
+  vertical-align: middle;
+  width: 20px;
+  height: 20px;
+}
+
+.hamburger.is-active {
+  transform: rotate(180deg);
+}
+</style>

+ 77 - 0
src/components/InEditor/index.vue

@@ -0,0 +1,77 @@
+<template>
+  <ck-editor v-model="editorData" :editor="editor" :config="editorConfig" />
+</template>
+
+<script>
+import ClassicEditor from '@ckeditor/ckeditor5-build-classic'
+import CkEditor from '@ckeditor/ckeditor5-vue2'
+
+export default {
+    name: 'InEditor',
+    components: {
+        // 编辑器组件的局部注册方式
+        CkEditor: CkEditor.component
+    },
+    props: {
+        value: {
+            type: String,
+            default: ''
+        },
+        placeholder: {
+            type: String,
+            default: '请输入内容'
+        }
+    },
+    data() {
+        return {
+            // 编辑器组件需要获取编辑器实例
+            editor: ClassicEditor,
+            editorData: '',
+            editorConfig: {
+                // 可以控制编辑器的提示文本
+                placeholder: this.placeholder,
+                toolbar: [
+                    'heading',
+                    '|', 'bold', 'italic', 'bulletedList', 'numberedList',
+                    '|', 'indent', 'outdent',
+                    '|', 'blockQuote', 'insertTable', 'undo', 'redo'
+                ]
+            }
+        }
+    },
+    watch: {
+        value: {
+            deep: true,
+            handler(val) {
+                if (!this.editor) {
+                    return
+                }
+
+                this.editorData = ''
+
+                // 外部内容发生变化时,将新值赋予编辑器
+                if (val && val !== this.editorData) {
+                    this.editorData = this.value
+                }
+            }
+        },
+        editorData: {
+            deep: true,
+            handler(val) {
+                if (val && val !== this.value) {
+                    // 编辑器内容发生变化时,告知外部,实现 v-model 双向监听效果
+                    this.$emit('input', val)
+                }
+            }
+        }
+    },
+    created() {
+        // 编辑器组件创建时将外部传入的值直接赋予编辑器
+        this.editorData = this.value
+    }
+}
+</script>
+
+<style>
+    .ck-editor__editable { min-height: 200px; }
+</style>

+ 100 - 0
src/components/Pagination/index.vue

@@ -0,0 +1,100 @@
+<template>
+  <div :class="{'hidden':hidden}" class="pagination-container">
+    <el-pagination
+      :background="background"
+      :current-page.sync="currentPage"
+      :page-size.sync="pageSize"
+      :layout="layout"
+      :total="total"
+      v-bind="$attrs"
+      @size-change="handleSizeChange"
+      @current-change="handleCurrentChange"
+    />
+  </div>
+</template>
+
+<script>
+import { scrollTo } from '@/static/utils/scrollTo'
+
+export default {
+    name: 'Pagination',
+    props: {
+        total: {
+            required: true,
+            type: Number
+        },
+        page: {
+            type: Number,
+            default: 1
+        },
+        limit: {
+            type: Number,
+            default: 20
+        },
+        pageSizes: {
+            type: Array,
+            default() {
+                return [10, 20, 30, 50]
+            }
+        },
+        layout: {
+            type: String,
+            default: 'total, sizes, prev, pager, next, jumper'
+        },
+        background: {
+            type: Boolean,
+            default: true
+        },
+        autoScroll: {
+            type: Boolean,
+            default: true
+        },
+        hidden: {
+            type: Boolean,
+            default: false
+        }
+    },
+    computed: {
+        currentPage: {
+            get() {
+                return this.page
+            },
+            set(val) {
+                this.$emit('update:page', val)
+            }
+        },
+        pageSize: {
+            get() {
+                return this.limit
+            },
+            set(val) {
+                this.$emit('update:limit', val)
+            }
+        }
+    },
+    methods: {
+        handleSizeChange(val) {
+            this.$emit('pagination', { page: this.currentPage, limit: val })
+            if (this.autoScroll) {
+                scrollTo(0, 800)
+            }
+        },
+        handleCurrentChange(val) {
+            this.$emit('pagination', { page: val, limit: this.pageSize })
+            if (this.autoScroll) {
+                scrollTo(0, 800)
+            }
+        }
+    }
+}
+</script>
+
+<style scoped>
+.pagination-container {
+  background: #fff;
+  padding: 32px 16px;
+}
+.pagination-container.hidden {
+  display: none;
+}
+</style>

+ 140 - 0
src/components/PanThumb/index.vue

@@ -0,0 +1,140 @@
+<template>
+  <div :style="{zIndex:zIndex,height:height,width:width}" class="pan-item">
+    <div class="pan-info">
+      <div class="pan-info-roles-container">
+        <slot />
+      </div>
+    </div>
+    <img :src="image" class="pan-thumb">
+  </div>
+</template>
+
+<script>
+export default {
+    name: 'PanThumb',
+    props: {
+        image: {
+            type: String,
+            required: true
+        },
+        zIndex: {
+            type: Number,
+            default: 1
+        },
+        width: {
+            type: String,
+            default: '150px'
+        },
+        height: {
+            type: String,
+            default: '150px'
+        }
+    }
+}
+</script>
+
+<style scoped>
+.pan-item {
+  width: 200px;
+  height: 200px;
+  border-radius: 50%;
+  display: inline-block;
+  position: relative;
+  cursor: default;
+  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
+}
+
+.pan-info-roles-container {
+  padding: 20px;
+  text-align: center;
+}
+
+.pan-thumb {
+  width: 100%;
+  height: 100%;
+  background-size: 100%;
+  border-radius: 50%;
+  overflow: hidden;
+  position: absolute;
+  transform-origin: 95% 40%;
+  transition: all 0.3s ease-in-out;
+}
+
+.pan-thumb:after {
+  content: '';
+  width: 8px;
+  height: 8px;
+  position: absolute;
+  border-radius: 50%;
+  top: 40%;
+  left: 95%;
+  margin: -4px 0 0 -4px;
+  background: radial-gradient(ellipse at center, rgba(14, 14, 14, 1) 0%, rgba(125, 126, 125, 1) 100%);
+  box-shadow: 0 0 1px rgba(255, 255, 255, 0.9);
+}
+
+.pan-info {
+  position: absolute;
+  width: inherit;
+  height: inherit;
+  border-radius: 50%;
+  overflow: hidden;
+  box-shadow: inset 0 0 0 5px rgba(0, 0, 0, 0.05);
+}
+
+.pan-info h3 {
+  color: #fff;
+  text-transform: uppercase;
+  position: relative;
+  letter-spacing: 2px;
+  font-size: 18px;
+  margin: 0 60px;
+  padding: 22px 0 0 0;
+  height: 85px;
+  font-family: 'Open Sans', Arial, sans-serif;
+  text-shadow: 0 0 1px #fff, 0 1px 2px rgba(0, 0, 0, 0.3);
+}
+
+.pan-info p {
+  color: #fff;
+  padding: 10px 5px;
+  font-style: italic;
+  margin: 0 30px;
+  font-size: 12px;
+  border-top: 1px solid rgba(255, 255, 255, 0.5);
+}
+
+.pan-info p a {
+  display: block;
+  color: #333;
+  width: 80px;
+  height: 80px;
+  background: rgba(255, 255, 255, 0.3);
+  border-radius: 50%;
+  color: #fff;
+  font-style: normal;
+  font-weight: 700;
+  text-transform: uppercase;
+  font-size: 9px;
+  letter-spacing: 1px;
+  padding-top: 24px;
+  margin: 7px auto 0;
+  font-family: 'Open Sans', Arial, sans-serif;
+  opacity: 0;
+  transition: transform 0.3s ease-in-out 0.2s, opacity 0.3s ease-in-out 0.2s, background 0.2s linear 0s;
+  transform: translateX(60px) rotate(90deg);
+}
+
+.pan-info p a:hover {
+  background: rgba(255, 255, 255, 0.5);
+}
+
+.pan-item:hover .pan-thumb {
+  transform: rotate(-110deg);
+}
+
+.pan-item:hover .pan-info p a {
+  opacity: 1;
+  transform: translateX(0px) rotate(0deg);
+}
+</style>

+ 145 - 0
src/components/RightPanel/index.vue

@@ -0,0 +1,145 @@
+<template>
+  <div ref="rightPanel" :class="{show:show}" class="rightPanel-container">
+    <div class="rightPanel-background" />
+    <div class="rightPanel">
+      <div class="handle-button" :style="{'bottom':buttonBottom+'px','background-color':theme}" @click="show=!show">
+        <i :class="show?'el-icon-close':'el-icon-setting'" />
+      </div>
+      <div class="rightPanel-items">
+        <slot />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { addClass, removeClass } from '@/static/utils'
+
+export default {
+    name: 'RightPanel',
+    props: {
+        clickNotClose: {
+            default: false,
+            type: Boolean
+        },
+        buttonBottom: {
+            default: 50,
+            type: Number
+        }
+    },
+    data() {
+        return {
+            show: false
+        }
+    },
+    computed: {
+        theme() {
+            return this.$store.state.settings.theme
+        }
+    },
+    watch: {
+        show(value) {
+            if (value && !this.clickNotClose) {
+                this.addEventClick()
+            }
+            if (value) {
+                addClass(document.body, 'showRightPanel')
+            } else {
+                removeClass(document.body, 'showRightPanel')
+            }
+        }
+    },
+    mounted() {
+        this.insertToBody()
+    },
+    beforeDestroy() {
+        const elx = this.$refs.rightPanel
+        elx.remove()
+    },
+    methods: {
+        addEventClick() {
+            window.addEventListener('click', this.closeSidebar)
+        },
+        closeSidebar(evt) {
+            const parent = evt.target.closest('.rightPanel')
+            if (!parent) {
+                this.show = false
+                window.removeEventListener('click', this.closeSidebar)
+            }
+        },
+        insertToBody() {
+            const elx = this.$refs.rightPanel
+            const body = document.querySelector('body')
+            body.insertBefore(elx, body.firstChild)
+        }
+    }
+}
+</script>
+
+<style>
+.showRightPanel {
+  overflow: hidden;
+  position: relative;
+  width: calc(100% - 15px);
+}
+</style>
+
+<style lang="scss" scoped>
+.rightPanel-background {
+  position: fixed;
+  top: 0;
+  left: 0;
+  opacity: 0;
+  transition: opacity .3s cubic-bezier(.7, .3, .1, 1);
+  background: rgba(0, 0, 0, .2);
+  z-index: -1;
+}
+
+.rightPanel {
+  width: 100%;
+  max-width: 260px;
+  height: 100vh;
+  position: fixed;
+  top: 0;
+  right: 0;
+  box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, .05);
+  transition: all .25s cubic-bezier(.7, .3, .1, 1);
+  transform: translate(100%);
+  background: #fff;
+  z-index: 40000;
+}
+
+.show {
+  transition: all .3s cubic-bezier(.7, .3, .1, 1);
+
+  .rightPanel-background {
+    z-index: 20000;
+    opacity: 1;
+    width: 100%;
+    height: 100%;
+  }
+
+  .rightPanel {
+    transform: translate(0);
+  }
+}
+
+.handle-button {
+  width: 48px;
+  height: 48px;
+  position: absolute;
+  left: -48px;
+  text-align: center;
+  font-size: 24px;
+  border-radius: 6px 0 0 6px !important;
+  z-index: 0;
+  pointer-events: auto;
+  cursor: pointer;
+  color: #fff;
+  line-height: 48px;
+  i {
+    font-size: 24px;
+    line-height: 48px;
+  }
+}
+</style>

+ 60 - 0
src/components/Screenfull/index.vue

@@ -0,0 +1,60 @@
+<template>
+  <div>
+    <svg-icon :icon-class="isFullscreen?'exit-fullscreen':'fullscreen'" @click="click" />
+  </div>
+</template>
+
+<script>
+import screenfull from 'screenfull'
+
+export default {
+    name: 'Screenfull',
+    data() {
+        return {
+            isFullscreen: false
+        }
+    },
+    mounted() {
+        this.init()
+    },
+    beforeDestroy() {
+        this.destroy()
+    },
+    methods: {
+        click() {
+            if (!screenfull.enabled) {
+                this.$message({
+                    message: 'you browser can not work',
+                    type: 'warning'
+                })
+                return false
+            }
+            screenfull.toggle()
+        },
+        change() {
+            this.isFullscreen = screenfull.isFullscreen
+        },
+        init() {
+            if (screenfull.enabled) {
+                screenfull.on('change', this.change)
+            }
+        },
+        destroy() {
+            if (screenfull.enabled) {
+                screenfull.off('change', this.change)
+            }
+        }
+    }
+}
+</script>
+
+<style scoped>
+.screenfull-svg {
+  display: inline-block;
+  cursor: pointer;
+  fill: #5a5e66;;
+  width: 20px;
+  height: 20px;
+  vertical-align: 10px;
+}
+</style>

+ 61 - 0
src/components/SvgIcon/index.vue

@@ -0,0 +1,61 @@
+<template>
+  <div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
+  <svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
+    <use :xlink:href="iconName" />
+  </svg>
+</template>
+
+<script>
+import { isExternal } from '@/static/utils/validate'
+
+export default {
+    name: 'SvgIcon',
+    props: {
+        iconClass: {
+            type: String,
+            required: true
+        },
+        className: {
+            type: String,
+            default: ''
+        }
+    },
+    computed: {
+        isExternal() {
+            return isExternal(this.iconClass)
+        },
+        iconName() {
+            return `#icon-${this.iconClass}`
+        },
+        svgClass() {
+            if (this.className) {
+                return 'svg-icon ' + this.className
+            } else {
+                return 'svg-icon'
+            }
+        },
+        styleExternalIcon() {
+            return {
+                mask: `url(${this.iconClass}) no-repeat 50% 50%`,
+                '-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
+            }
+        }
+    }
+}
+</script>
+
+<style scoped>
+.svg-icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+
+.svg-external-icon {
+  background-color: currentColor;
+  mask-size: cover!important;
+  display: inline-block;
+}
+</style>

+ 111 - 0
src/components/TextHoverEffect/Mallki.vue

@@ -0,0 +1,111 @@
+<template>
+  <a :class="className" class="link--mallki" href="#">
+    {{ text }}
+    <span :data-letters="text" />
+    <span :data-letters="text" />
+  </a>
+</template>
+
+<script>
+export default {
+    props: {
+        className: {
+            type: String,
+            default: ''
+        },
+        text: {
+            type: String,
+            default: 'vue-element-admin'
+        }
+    }
+}
+</script>
+
+<style>
+.link--mallki {
+  font-weight: 800;
+  color: #4dd9d5;
+  font-family: 'Dosis', sans-serif;
+  -webkit-transition: color 0.5s 0.25s;
+  transition: color 0.5s 0.25s;
+  overflow: hidden;
+  position: relative;
+  display: inline-block;
+  line-height: 1;
+  outline: none;
+  text-decoration: none;
+}
+
+.link--mallki:hover {
+  -webkit-transition: none;
+  transition: none;
+  color: transparent;
+}
+
+.link--mallki::before {
+  content: '';
+  width: 100%;
+  height: 6px;
+  margin: -3px 0 0 0;
+  background: #3888fa;
+  position: absolute;
+  left: 0;
+  top: 50%;
+  -webkit-transform: translate3d(-100%, 0, 0);
+  transform: translate3d(-100%, 0, 0);
+  -webkit-transition: -webkit-transform 0.4s;
+  transition: transform 0.4s;
+  -webkit-transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1);
+  transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1);
+}
+
+.link--mallki:hover::before {
+  -webkit-transform: translate3d(100%, 0, 0);
+  transform: translate3d(100%, 0, 0);
+}
+
+.link--mallki span {
+  position: absolute;
+  height: 50%;
+  width: 100%;
+  left: 0;
+  top: 0;
+  overflow: hidden;
+}
+
+.link--mallki span::before {
+  content: attr(data-letters);
+  color: red;
+  position: absolute;
+  left: 0;
+  width: 100%;
+  color: #3888fa;
+  -webkit-transition: -webkit-transform 0.5s;
+  transition: transform 0.5s;
+}
+
+.link--mallki span:nth-child(2) {
+  top: 50%;
+}
+
+.link--mallki span:first-child::before {
+  top: 0;
+  -webkit-transform: translate3d(0, 100%, 0);
+  transform: translate3d(0, 100%, 0);
+}
+
+.link--mallki span:nth-child(2)::before {
+  bottom: 0;
+  -webkit-transform: translate3d(0, -100%, 0);
+  transform: translate3d(0, -100%, 0);
+}
+
+.link--mallki:hover span::before {
+  -webkit-transition-delay: 0.3s;
+  transition-delay: 0.3s;
+  -webkit-transform: translate3d(0, 0, 0);
+  transform: translate3d(0, 0, 0);
+  -webkit-transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
+  transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
+}
+</style>

+ 175 - 0
src/components/ThemePicker/index.vue

@@ -0,0 +1,175 @@
+<template>
+  <el-color-picker
+    v-model="theme"
+    :predefine="['#409EFF', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
+    class="theme-picker"
+    popper-class="theme-picker-dropdown"
+  />
+</template>
+
+<script>
+const version = require('element-ui/package.json').version // element-ui version from node_modules
+const ORIGINAL_THEME = '#409EFF' // default color
+
+export default {
+    data() {
+        return {
+            chalk: '', // content of theme-chalk css
+            theme: ''
+        }
+    },
+    computed: {
+        defaultTheme() {
+            return this.$store.state.settings.theme
+        }
+    },
+    watch: {
+        defaultTheme: {
+            handler: function(val, oldVal) {
+                this.theme = val
+            },
+            immediate: true
+        },
+        async theme(val) {
+            const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
+            if (typeof val !== 'string') return
+            const themeCluster = this.getThemeCluster(val.replace('#', ''))
+            const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
+            console.log(themeCluster, originalCluster)
+
+            const $message = this.$message({
+                message: '  Compiling the theme',
+                customClass: 'theme-message',
+                type: 'success',
+                duration: 0,
+                iconClass: 'el-icon-loading'
+            })
+
+            const getHandler = (variable, id) => {
+                return () => {
+                    const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''))
+                    const newStyle = this.updateStyle(this[variable], originalCluster, themeCluster)
+
+                    let styleTag = document.getElementById(id)
+                    if (!styleTag) {
+                        styleTag = document.createElement('style')
+                        styleTag.setAttribute('id', id)
+                        document.head.appendChild(styleTag)
+                    }
+                    styleTag.innerText = newStyle
+                }
+            }
+
+            if (!this.chalk) {
+                const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`
+                await this.getCSSString(url, 'chalk')
+            }
+
+            const chalkHandler = getHandler('chalk', 'chalk-style')
+
+            chalkHandler()
+
+            const styles = [].slice.call(document.querySelectorAll('style'))
+                .filter(style => {
+                    const text = style.innerText
+                    return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text)
+                })
+            styles.forEach(style => {
+                const { innerText } = style
+                if (typeof innerText !== 'string') return
+                style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
+            })
+
+            this.$emit('change', val)
+
+            $message.close()
+        }
+    },
+
+    methods: {
+        updateStyle(style, oldCluster, newCluster) {
+            let newStyle = style
+            oldCluster.forEach((color, index) => {
+                newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
+            })
+            return newStyle
+        },
+
+        getCSSString(url, variable) {
+            return new Promise(resolve => {
+                const xhr = new XMLHttpRequest()
+                xhr.onreadystatechange = () => {
+                    if (xhr.readyState === 4 && xhr.status === 200) {
+                        this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
+                        resolve()
+                    }
+                }
+                xhr.open('GET', url)
+                xhr.send()
+            })
+        },
+
+        getThemeCluster(theme) {
+            const tintColor = (color, tint) => {
+                let red = parseInt(color.slice(0, 2), 16)
+                let green = parseInt(color.slice(2, 4), 16)
+                let blue = parseInt(color.slice(4, 6), 16)
+
+                if (tint === 0) { // when primary color is in its rgb space
+                    return [red, green, blue].join(',')
+                } else {
+                    red += Math.round(tint * (255 - red))
+                    green += Math.round(tint * (255 - green))
+                    blue += Math.round(tint * (255 - blue))
+
+                    red = red.toString(16)
+                    green = green.toString(16)
+                    blue = blue.toString(16)
+
+                    return `#${red}${green}${blue}`
+                }
+            }
+
+            const shadeColor = (color, shade) => {
+                let red = parseInt(color.slice(0, 2), 16)
+                let green = parseInt(color.slice(2, 4), 16)
+                let blue = parseInt(color.slice(4, 6), 16)
+
+                red = Math.round((1 - shade) * red)
+                green = Math.round((1 - shade) * green)
+                blue = Math.round((1 - shade) * blue)
+
+                red = red.toString(16)
+                green = green.toString(16)
+                blue = blue.toString(16)
+
+                return `#${red}${green}${blue}`
+            }
+
+            const clusters = [theme]
+            for (let i = 0; i <= 9; i++) {
+                clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
+            }
+            clusters.push(shadeColor(theme, 0.1))
+            return clusters
+        }
+    }
+}
+</script>
+
+<style>
+.theme-message,
+.theme-picker-dropdown {
+  z-index: 99999 !important;
+}
+
+.theme-picker .el-color-picker__trigger {
+  height: 26px !important;
+  width: 26px !important;
+  padding: 2px;
+}
+
+.theme-picker-dropdown .el-color-dropdown__link-btn {
+  display: none;
+}
+</style>

+ 345 - 0
src/components/Tinymce/index.vue

@@ -0,0 +1,345 @@
+<template>
+  <div class="tinymce-container editor-container" :class="{fullscreen:fullscreen}">
+    <textarea :id="tinymceId" class="tinymce-textarea" />
+    <div v-if="picture" class="editor-custom-btn-container">
+      <el-button
+        :style="{background:color,borderColor:color}"
+        icon="el-icon-upload"
+        size="mini"
+        type="primary"
+        @click=" dialogVisible=true"
+      >上传图片
+      </el-button>
+      <el-dialog :visible.sync="dialogVisible" destroy-on-cloase="true" style="margin-top: 20vh; " append-to-body>
+        <el-upload
+          :multiple="true"
+          :file-list="fileList"
+          :show-file-list="true"
+          :on-remove="handleRemove"
+          :on-success="handleSuccess"
+          :before-upload="beforeUpload"
+          class="editor-slide-upload"
+          :action="fileUrl"
+          list-type="picture-card"
+        >
+          <el-button size="small" type="primary">点击上传</el-button>
+        </el-upload>
+        <el-button @click="dialogVisible = false">取 消</el-button>
+        <el-button type="primary" @click="handleSubmit">确 定</el-button>
+      </el-dialog>
+      <!--      <multiple-upload class="editor-upload-btn" @success="imageSuccess" />-->
+    </div>
+  </div>
+</template>
+
+<!--          :headers="uploadHeaders"-->
+<script>
+import axios from 'axios'
+
+// MultipleUpload组件见 https://blog.csdn.net/qq_39953537/article/details/100039094
+
+// import MultipleUpload from '@/components/MultipleUpload'
+import plugins from './plugins' // 见下文
+import toolbar from './toolbar' // 见下文
+
+// 上传html片段接口根据自己项目更换
+// import { uploadHtml } from '@/api/upload'
+export default {
+    name: 'Tinymce',
+    // components: {
+    //     MultipleUpload
+    // },
+    props: {
+        // 默认填充到富文本的html文件
+        html: {
+            type: String,
+            default: ''
+        },
+        toolbar: {
+            type: Array,
+            default() {
+                return []
+            }
+        },
+        menubar: {
+            type: Boolean,
+            default: false
+        },
+        picture: {
+            type: Boolean,
+            default: true
+        },
+        height: {
+            type: Number,
+            default: 400
+        },
+        value: {
+            type: String,
+            default: ''
+        }
+    },
+    data() {
+        return {
+            hasChange: false,
+            hasInit: false,
+            tinymceId: 'vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + ''),
+            fullscreen: false,
+            editorContent: '',
+            dialogVisible: false,
+            fileList: [],
+            listObj: {},
+            fileUrl: '/server/wx/fileController/uploadImage',
+            viewUrl: '/server/FileController/download/'
+        }
+    },
+    watch: {
+        value(val) {
+            this.$nextTick(() =>
+                window.tinymce.get(this.tinymceId).setContent(val || '')
+            )
+        },
+        html(val) {
+            if (this.isUrl) {
+                this.loadUrl(val)
+            }
+        }
+    },
+    created() {
+        if (this.html && this.html.startsWith('http')) {
+            this.loadUrl(this.html)
+        } else {
+            this.value = this.html + ''
+            this.editorContent = this.html + ''
+        }
+    },
+    mounted() {
+        this.initTinymce()
+    },
+    activated() {
+        this.initTinymce()
+    },
+    deactivated() {
+        this.destroyTinymce()
+    },
+    destroyed() {
+        this.destroyTinymce()
+    },
+    methods: {
+        initTinymce() {
+            window.tinymce.init({
+                fontsize_formats: '12px 14px 16px 18px 20px 24px 36px',
+                language: 'zh_CN',
+                language_url: '/tinymce4.7.5/langs/zh_CN.js',
+                // language_url: '/tinymce/js/tinymce/langs/zh_CN.js',
+                selector: `#${this.tinymceId}`,
+                height: this.height,
+                body_class: 'panel-body ',
+                object_resizing: true,
+                toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
+                menubar: this.menubar,
+                // plugins: plugins,
+                end_container_on_empty_block: true,
+                powerpaste_word_import: 'clean',
+                code_dialog_height: 450,
+                code_dialog_width: 1000,
+                width: '99%',
+                advlist_bullet_styles: 'square',
+                advlist_number_styles: 'default',
+                default_link_target: '_blank',
+                relative_urls: false,
+                link_title: false,
+                paste_data_images: true, // 图片复制上传 待完善
+                style_formats_merge: true, // 设置行高
+                style_formats: [
+                    {
+                        title: '行高',
+                        items: [
+                            { title: '0.5', block: 'p', styles: { 'line-height': '0.5' }},
+                            { title: '1', block: 'p', styles: { 'line-height': '1.0' }},
+                            { title: '1.5', block: 'p', styles: { 'line-height': '1.5' }},
+                            { title: '1.75', block: 'p', styles: { 'line-height': '1.75' }},
+                            { title: '2', block: 'p', styles: { 'line-height': '2' }},
+                            { title: '3', block: 'p', styles: { 'line-height': '3' }},
+                            { title: '4', block: 'p', styles: { 'line-height': '4' }},
+                            { title: '5', block: 'p', styles: { 'line-height': '5' }}
+                        ]
+                    }
+                ],
+                style_formats_autohide: true,
+                init_instance_callback: editor => {
+                    if (this.value) {
+                        editor.setContent(this.value)
+                    }
+                    this.hasInit = true
+                    editor.on('NodeChange Change KeyUp SetContent', () => {
+                        this.hasChange = true
+                        this.$emit('input', editor.getContent())
+                        this.editorContent = editor.getContent()
+                    })
+                },
+                setup(editor) {
+                    editor.on('FullscreenStateChanged', e => {
+                        this.fullscreen = e.state
+                    })
+                }
+            })
+        },
+        checkAllSuccess() {
+            return Object.keys(this.listObj).every(item => this.listObj[item].hasSuccess)
+        },
+        handleSubmit() {
+            const arr = Object.keys(this.listObj).map(v => this.listObj[v])
+            if (!this.checkAllSuccess()) {
+                this.$message('请等待所有图片上传成功 或 出现了网络问题,请刷新页面重新上传!')
+                return
+            }
+            // this.$emit('successCBK', arr)
+            arr.forEach(v => {
+                let imgUrl = v.url
+                if (!imgUrl.startsWith('/')) {
+                    imgUrl = '/' + imgUrl
+                }
+                window.tinymce.get(this.tinymceId).insertContent('<img class="wscnph" src="' + imgUrl + '" width="100%" height="100%" data-mce-src="' + imgUrl + '">')
+            })
+            this.listObj = {}
+            this.fileList = []
+            this.dialogVisible = false
+        },
+        handleSuccess(response, file) {
+            const uid = file.uid
+            const objKeyArr = Object.keys(this.listObj)
+            for (let i = 0, len = objKeyArr.length; i < len; i++) {
+                if (this.listObj[objKeyArr[i]].uid === uid) {
+                    this.listObj[objKeyArr[i]].url = this.viewUrl + response.data
+                    this.listObj[objKeyArr[i]].hasSuccess = true
+                    return
+                }
+            }
+        },
+        handleRemove(file) {
+            const uid = file.uid
+            const objKeyArr = Object.keys(this.listObj)
+            for (let i = 0, len = objKeyArr.length; i < len; i++) {
+                if (this.listObj[objKeyArr[i]].uid === uid) {
+                    delete this.listObj[objKeyArr[i]]
+                    return
+                }
+            }
+        },
+        beforeUpload(file) {
+            const _self = this
+            const _URL = window.URL || window.webkitURL
+            const fileName = file.uid
+            _self.listObj[fileName] = {}
+            return new Promise((resolve, reject) => {
+                const img = new Image()
+                img.src = _URL.createObjectURL(file)
+                img.onload = function() {
+                    _self.listObj[fileName] = { hasSuccess: false, uid: file.uid, width: this.width, height: this.height }
+                }
+                resolve(true)
+            })
+        },
+        destroyTinymce() {
+            if (window.tinymce.get(this.tinymceId)) {
+                window.tinymce.get(this.tinymceId).destroy()
+            }
+        },
+        loadUrl(url) {
+            if (url && url.length > 0) {
+                axios
+                    .get(url)
+                    .then(response => {
+                        // 处理HTML显示
+                        this.value = response.data
+                        this.editorContent = response.data
+                        this.$emit('subLoadUrlToHtml', response.data)
+                        this.$emit('input', response.data)
+                    })
+                    .catch(() => {
+                        this.value = '服务器数据加载失败,请重试!'
+                    })
+            }
+        },
+        // 设置编辑器内容
+        setContent(value) {
+            window.tinymce.get(this.tinymceId).setContent(value)
+        },
+        // 获取编辑器内容
+        getContent() {
+            window.tinymce.get(this.tinymceId).getContent()
+        },
+        // 图片上传成功后填充到富文本编辑器
+        async imageSuccess(urlList) {
+            try {
+                let imageTemplateList = ''
+                urlList.forEach(item => {
+                    const image = `<img style="max-width:100%;" src="${item}">`
+                    imageTemplateList = imageTemplateList + image
+                })
+                window.tinymce.get(this.tinymceId).insertContent(imageTemplateList)
+                this.$message({
+                    message: '上传成功!',
+                    type: 'success'
+                })
+            } catch (error) {
+                console.log(error)
+                this.$message({
+                    message: error,
+                    type: 'error'
+                })
+            }
+        },
+        // 编辑器内容上传到cos,调用返回url
+        async content2Url() {
+            try {
+                // const res = await uploadHtml(this.editorContent)
+                const res = ''
+                return res
+            } catch (error) {
+                this.$message({
+                    message: error.data.message,
+                    type: 'error'
+                })
+            }
+        }
+    }
+}
+</script>
+
+<style lang='scss' >
+#tinymce {
+    background-color: blue;
+    p {
+        margin: 0;
+    }
+}
+.tinymce-container {
+    position: relative;
+}
+.tinymce-container >>> .mce-fullscreen {
+    z-index: 10000;
+}
+.tinymce-textarea {
+    visibility: hidden;
+    z-index: -1;
+}
+.editor-custom-btn-container {
+    position: absolute;
+    right: 12px;
+    top: -3px;
+   z-index: 2005;
+}
+.fullscreen .editor-custom-btn-container {
+    z-index: 10000;
+    position: fixed;
+}
+.editor-upload-btn {
+    display: inline-block;
+}
+// 隐藏底部logo栏
+.mce-edit-area + .mce-statusbar {
+    opacity: 0;
+    height: 0;
+}
+</style>

+ 5 - 0
src/components/Tinymce/plugins.js

@@ -0,0 +1,5 @@
+const plugins = [
+    ' advlist anchor autolink autosave code codesample directionality emoticons fullscreen hr image importcss insertdatetime link lists media nonbreaking noneditable pagebreak  preview print save searchreplace spellchecker tabfocus table template  textpattern visualblocks visualchars wordcount paste '
+]
+// imagetools
+export default plugins

+ 3 - 0
src/components/Tinymce/toolbar.js

@@ -0,0 +1,3 @@
+const toolbar = ['formatselect fontsizeselect styleselect forecolor backcolor bold italic underline strikethrough alignleft aligncenter alignright outdent indent    removeformat  hr undo redo']
+
+export default toolbar

+ 49 - 0
src/directive/clipboard/clipboard.js

@@ -0,0 +1,49 @@
+// Inspired by https://github.com/Inndy/vue-clipboard2
+const Clipboard = require('clipboard')
+if (!Clipboard) {
+  throw new Error('you should npm install `clipboard` --save at first ')
+}
+
+export default {
+  bind(el, binding) {
+    if (binding.arg === 'success') {
+      el._v_clipboard_success = binding.value
+    } else if (binding.arg === 'error') {
+      el._v_clipboard_error = binding.value
+    } else {
+      const clipboard = new Clipboard(el, {
+        text() { return binding.value },
+        action() { return binding.arg === 'cut' ? 'cut' : 'copy' }
+      })
+      clipboard.on('success', e => {
+        const callback = el._v_clipboard_success
+        callback && callback(e) // eslint-disable-line
+      })
+      clipboard.on('error', e => {
+        const callback = el._v_clipboard_error
+        callback && callback(e) // eslint-disable-line
+      })
+      el._v_clipboard = clipboard
+    }
+  },
+  update(el, binding) {
+    if (binding.arg === 'success') {
+      el._v_clipboard_success = binding.value
+    } else if (binding.arg === 'error') {
+      el._v_clipboard_error = binding.value
+    } else {
+      el._v_clipboard.text = function() { return binding.value }
+      el._v_clipboard.action = function() { return binding.arg === 'cut' ? 'cut' : 'copy' }
+    }
+  },
+  unbind(el, binding) {
+    if (binding.arg === 'success') {
+      delete el._v_clipboard_success
+    } else if (binding.arg === 'error') {
+      delete el._v_clipboard_error
+    } else {
+      el._v_clipboard.destroy()
+      delete el._v_clipboard
+    }
+  }
+}

+ 13 - 0
src/directive/clipboard/index.js

@@ -0,0 +1,13 @@
+import Clipboard from './clipboard'
+
+const install = function(Vue) {
+  Vue.directive('Clipboard', Clipboard)
+}
+
+if (window.Vue) {
+  window.clipboard = Clipboard
+  Vue.use(install); // eslint-disable-line
+}
+
+Clipboard.install = install
+export default Clipboard

+ 13 - 0
src/directive/permission/index.js

@@ -0,0 +1,13 @@
+import permission from './permission'
+
+const install = function(Vue) {
+  Vue.directive('permission', permission)
+}
+
+if (window.Vue) {
+  window['permission'] = permission
+  Vue.use(install); // eslint-disable-line
+}
+
+permission.install = install
+export default permission

+ 29 - 0
src/directive/permission/permission.js

@@ -0,0 +1,29 @@
+
+import store from '@/store'
+
+export default{
+  inserted(el, binding, vnode) {
+    const { value } = binding
+    const perms = store.getters && store.getters.perms
+
+    if (value && value instanceof Array && value.length > 0) {
+      const permissions = value
+
+      var hasPermission = false
+
+      if (perms.indexOf('*') >= 0) {
+        hasPermission = true
+      } else {
+        hasPermission = perms.some(perm => {
+          return permissions.includes(perm)
+        })
+      }
+
+      if (!hasPermission) {
+        el.parentNode && el.parentNode.removeChild(el)
+      }
+    } else {
+      throw new Error(`need perms! Like v-permission="['GET /aaa','POST /bbb']"`)
+    }
+  }
+}

+ 9 - 0
src/icons/index.js

@@ -0,0 +1,9 @@
+import Vue from 'vue'
+import SvgIcon from '@/components/SvgIcon'// svg component
+
+// register globally
+Vue.component('svg-icon', SvgIcon)
+
+const req = require.context('./svg', false, /\.svg$/)
+const requireAll = requireContext => requireContext.keys().map(requireContext)
+requireAll(req)

Різницю між файлами не показано, бо вона завелика
+ 1 - 0
src/icons/svg/404.svg


Різницю між файлами не показано, бо вона завелика
+ 1 - 0
src/icons/svg/bug.svg


+ 1 - 0
src/icons/svg/chart.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 54.857h36.571V128H0V54.857zM91.429 27.43H128V128H91.429V27.429zM45.714 0h36.572v128H45.714V0z"/></svg>

Різницю між файлами не показано, бо вона завелика
+ 1 - 0
src/icons/svg/clipboard.svg


+ 1 - 0
src/icons/svg/component.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h54.857v54.857H0V0zm0 73.143h54.857V128H0V73.143zm73.143 0H128V128H73.143V73.143zm27.428-18.286C115.72 54.857 128 42.577 128 27.43 128 12.28 115.72 0 100.571 0 85.423 0 73.143 12.28 73.143 27.429c0 15.148 12.28 27.428 27.428 27.428z"/></svg>

Різницю між файлами не показано, бо вона завелика
+ 1 - 0
src/icons/svg/dashboard.svg


+ 1 - 0
src/icons/svg/documentation.svg

@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M71.984 44.815H115.9L71.984 9.642v35.173zM16.094.05h63.875l47.906 38.37v76.74c0 3.392-1.682 6.645-4.677 9.044-2.995 2.399-7.056 3.746-11.292 3.746H16.094c-4.236 0-8.297-1.347-11.292-3.746-2.995-2.399-4.677-5.652-4.677-9.044V12.84C.125 5.742 7.23.05 16.094.05zm71.86 102.32V89.58h-71.86v12.79h71.86zm23.952-25.58V64H16.094v12.79h95.812z"/></svg>

+ 0 - 0
src/icons/svg/drag.svg


Деякі файли не було показано, через те що забагато файлів було змінено