abiao před 5 roky
revize
8d2ab16383
100 změnil soubory, kde provedl 3544 přidání a 0 odebrání
  1. 12 0
      statement-pc/.babelrc
  2. 14 0
      statement-pc/.editorconfig
  3. 3 0
      statement-pc/.eslintignore
  4. 199 0
      statement-pc/.eslintrc.js
  5. 20 0
      statement-pc/.gitignore
  6. 10 0
      statement-pc/.postcssrc.js
  7. 5 0
      statement-pc/.travis.yml
  8. 21 0
      statement-pc/LICENSE
  9. 155 0
      statement-pc/README.md
  10. 166 0
      statement-pc/README.zh-CN.md
  11. 48 0
      statement-pc/build/build.js
  12. 54 0
      statement-pc/build/check-versions.js
  13. 101 0
      statement-pc/build/utils.js
  14. 22 0
      statement-pc/build/vue-loader.conf.js
  15. 101 0
      statement-pc/build/webpack.base.conf.js
  16. 88 0
      statement-pc/build/webpack.dev.conf.js
  17. 175 0
      statement-pc/build/webpack.prod.conf.js
  18. 6 0
      statement-pc/config/dev.env.js
  19. 83 0
      statement-pc/config/index.js
  20. 6 0
      statement-pc/config/prod.env.js
  21. 9 0
      statement-pc/config/test.env.js
  22. binární
      statement-pc/favicon.ico
  23. 22 0
      statement-pc/index.html
  24. 101 0
      statement-pc/package.json
  25. 24 0
      statement-pc/src/App.vue
  26. 29 0
      statement-pc/src/api/login.js
  27. binární
      statement-pc/src/assets/401_images/401.gif
  28. binární
      statement-pc/src/assets/404_images/404.png
  29. binární
      statement-pc/src/assets/404_images/404_cloud.png
  30. binární
      statement-pc/src/assets/custom-theme/fonts/element-icons.ttf
  31. binární
      statement-pc/src/assets/custom-theme/fonts/element-icons.woff
  32. 1 0
      statement-pc/src/assets/custom-theme/index.css
  33. 199 0
      statement-pc/src/assets/echarts-macarons.js
  34. binární
      statement-pc/src/assets/header/clock.png
  35. binární
      statement-pc/src/assets/header/d5clogo.png
  36. binární
      statement-pc/src/assets/header/logout.png
  37. binární
      statement-pc/src/assets/modal/colse.png
  38. 52 0
      statement-pc/src/components/Breadcrumb/index.vue
  39. 42 0
      statement-pc/src/components/Currency/index.vue
  40. 77 0
      statement-pc/src/components/ErrorLog/index.vue
  41. 45 0
      statement-pc/src/components/Hamburger/index.vue
  42. 260 0
      statement-pc/src/components/HeaderContainer/index.vue
  43. 209 0
      statement-pc/src/components/LeftNav/index.vue
  44. 32 0
      statement-pc/src/components/Loading/index.vue
  45. 65 0
      statement-pc/src/components/Screenfull/index.vue
  46. 57 0
      statement-pc/src/components/ScrollBar/index.vue
  47. 72 0
      statement-pc/src/components/ScrollPane/index.vue
  48. 42 0
      statement-pc/src/components/SvgIcon/index.vue
  49. 49 0
      statement-pc/src/directive/clipboard/clipboard.js
  50. 13 0
      statement-pc/src/directive/clipboard/index.js
  51. 91 0
      statement-pc/src/directive/sticky.js
  52. 13 0
      statement-pc/src/directive/waves/index.js
  53. 26 0
      statement-pc/src/directive/waves/waves.css
  54. 42 0
      statement-pc/src/directive/waves/waves.js
  55. 21 0
      statement-pc/src/errorLog.js
  56. 121 0
      statement-pc/src/filters/index.js
  57. 12 0
      statement-pc/src/icons/index.js
  58. 1 0
      statement-pc/src/icons/svg/404.svg
  59. 1 0
      statement-pc/src/icons/svg/bug.svg
  60. 1 0
      statement-pc/src/icons/svg/chart.svg
  61. 1 0
      statement-pc/src/icons/svg/clipboard.svg
  62. 1 0
      statement-pc/src/icons/svg/component.svg
  63. 1 0
      statement-pc/src/icons/svg/dashboard.svg
  64. 1 0
      statement-pc/src/icons/svg/documentation.svg
  65. 1 0
      statement-pc/src/icons/svg/drag.svg
  66. 1 0
      statement-pc/src/icons/svg/email.svg
  67. 1 0
      statement-pc/src/icons/svg/example.svg
  68. 1 0
      statement-pc/src/icons/svg/excel.svg
  69. 1 0
      statement-pc/src/icons/svg/eye.svg
  70. 1 0
      statement-pc/src/icons/svg/form.svg
  71. 1 0
      statement-pc/src/icons/svg/icon.svg
  72. 1 0
      statement-pc/src/icons/svg/international.svg
  73. 1 0
      statement-pc/src/icons/svg/language.svg
  74. 1 0
      statement-pc/src/icons/svg/lock.svg
  75. 1 0
      statement-pc/src/icons/svg/message.svg
  76. 1 0
      statement-pc/src/icons/svg/money.svg
  77. 1 0
      statement-pc/src/icons/svg/password.svg
  78. 1 0
      statement-pc/src/icons/svg/people.svg
  79. 1 0
      statement-pc/src/icons/svg/peoples.svg
  80. 1 0
      statement-pc/src/icons/svg/qq.svg
  81. 1 0
      statement-pc/src/icons/svg/shoppingCard.svg
  82. 1 0
      statement-pc/src/icons/svg/star.svg
  83. 1 0
      statement-pc/src/icons/svg/tab.svg
  84. 1 0
      statement-pc/src/icons/svg/table.svg
  85. 1 0
      statement-pc/src/icons/svg/theme.svg
  86. 1 0
      statement-pc/src/icons/svg/user.svg
  87. 1 0
      statement-pc/src/icons/svg/wechat.svg
  88. 1 0
      statement-pc/src/icons/svg/zip.svg
  89. 2 0
      statement-pc/src/leftnav.js
  90. 27 0
      statement-pc/src/libs/china.js
  91. 192 0
      statement-pc/src/libs/mapdata.js
  92. 33 0
      statement-pc/src/main.js
  93. 70 0
      statement-pc/src/mock/article.js
  94. 29 0
      statement-pc/src/mock/index.js
  95. 34 0
      statement-pc/src/mock/login.js
  96. 24 0
      statement-pc/src/mock/remoteSearch.js
  97. 23 0
      statement-pc/src/mock/transaction.js
  98. 63 0
      statement-pc/src/permission.js
  99. 1 0
      statement-pc/src/router/_import_development.js
  100. 0 0
      statement-pc/src/router/_import_production.js

+ 12 - 0
statement-pc/.babelrc

@@ -0,0 +1,12 @@
+{
+  "presets": [
+    ["env", {
+      "modules": false,
+      "targets": {
+        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
+      }
+    }],
+    "stage-2"
+  ],
+  "plugins": ["transform-vue-jsx", "transform-runtime"]
+}

+ 14 - 0
statement-pc/.editorconfig

@@ -0,0 +1,14 @@
+# http://editorconfig.org
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.md]
+insert_final_newline = false
+trim_trailing_whitespace = false

+ 3 - 0
statement-pc/.eslintignore

@@ -0,0 +1,3 @@
+build/*.js
+config/*.js
+src/assets

+ 199 - 0
statement-pc/.eslintrc.js

@@ -0,0 +1,199 @@
+module.exports = {
+  root: true,
+  parser: 'babel-eslint',
+  parserOptions: {
+    sourceType: 'module'
+  },
+  env: {
+    browser: true,
+    node: true,
+    es6: true,
+  },
+  extends: 'eslint:recommended',
+  // required to lint *.vue files
+  plugins: [
+    'html'
+  ],
+  // check if imports actually resolve
+  'settings': {
+    'import/resolver': {
+      'webpack': {
+        'config': 'build/webpack.base.conf.js'
+      }
+    }
+  },
+  // add your custom rules here
+  //it is base on https://github.com/vuejs/eslint-config-vue
+  'rules': {
+    'accessor-pairs': 2,
+    'arrow-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'block-spacing': [2, 'always'],
+    'brace-style': [2, '1tbs', {
+      'allowSingleLine': true
+    }],
+    'camelcase': [0, {
+      'properties': 'always'
+    }],
+    'comma-dangle': [2, 'never'],
+    'comma-spacing': [2, {
+      'before': false,
+      'after': true
+    }],
+    'comma-style': [2, 'last'],
+    'constructor-super': 2,
+    'curly': [2, 'multi-line'],
+    'dot-location': [2, 'property'],
+    'eol-last': 2,
+    'eqeqeq': [2, 'allow-null'],
+    'generator-star-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'handle-callback-err': [2, '^(err|error)$'],
+    'indent': [2, 2, {
+      'SwitchCase': 1
+    }],
+    'jsx-quotes': [2, 'prefer-single'],
+    'key-spacing': [2, {
+      'beforeColon': false,
+      'afterColon': true
+    }],
+    'keyword-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'new-cap': [2, {
+      'newIsCap': true,
+      'capIsNew': false
+    }],
+    'new-parens': 2,
+    'no-array-constructor': 2,
+    'no-caller': 2,
+    'no-console': 'off',
+    'no-class-assign': 2,
+    'no-cond-assign': 2,
+    'no-const-assign': 2,
+    'no-control-regex': 0,
+    'no-delete-var': 2,
+    'no-dupe-args': 2,
+    'no-dupe-class-members': 2,
+    'no-dupe-keys': 2,
+    'no-duplicate-case': 2,
+    'no-empty-character-class': 2,
+    'no-empty-pattern': 2,
+    'no-eval': 2,
+    'no-ex-assign': 2,
+    'no-extend-native': 2,
+    'no-extra-bind': 2,
+    'no-extra-boolean-cast': 2,
+    'no-extra-parens': [2, 'functions'],
+    'no-fallthrough': 2,
+    'no-floating-decimal': 2,
+    'no-func-assign': 2,
+    'no-implied-eval': 2,
+    'no-inner-declarations': [2, 'functions'],
+    'no-invalid-regexp': 2,
+    'no-irregular-whitespace': 2,
+    'no-iterator': 2,
+    'no-label-var': 2,
+    'no-labels': [2, {
+      'allowLoop': false,
+      'allowSwitch': false
+    }],
+    'no-lone-blocks': 2,
+    'no-mixed-spaces-and-tabs': 2,
+    'no-multi-spaces': 2,
+    'no-multi-str': 2,
+    'no-multiple-empty-lines': [2, {
+      'max': 1
+    }],
+    'no-native-reassign': 2,
+    'no-negated-in-lhs': 2,
+    'no-new-object': 2,
+    'no-new-require': 2,
+    'no-new-symbol': 2,
+    'no-new-wrappers': 2,
+    'no-obj-calls': 2,
+    'no-octal': 2,
+    'no-octal-escape': 2,
+    'no-path-concat': 2,
+    'no-proto': 2,
+    'no-redeclare': 2,
+    'no-regex-spaces': 2,
+    'no-return-assign': [2, 'except-parens'],
+    'no-self-assign': 2,
+    'no-self-compare': 2,
+    'no-sequences': 2,
+    'no-shadow-restricted-names': 2,
+    'no-spaced-func': 2,
+    'no-sparse-arrays': 2,
+    'no-this-before-super': 2,
+    'no-throw-literal': 2,
+    'no-trailing-spaces': 2,
+    'no-undef': 2,
+    'no-undef-init': 2,
+    'no-unexpected-multiline': 2,
+    'no-unmodified-loop-condition': 2,
+    'no-unneeded-ternary': [2, {
+      'defaultAssignment': false
+    }],
+    'no-unreachable': 2,
+    'no-unsafe-finally': 2,
+    'no-unused-vars': [2, {
+      'vars': 'all',
+      'args': 'none'
+    }],
+    'no-useless-call': 2,
+    'no-useless-computed-key': 2,
+    'no-useless-constructor': 2,
+    'no-useless-escape': 0,
+    'no-whitespace-before-property': 2,
+    'no-with': 2,
+    'one-var': [2, {
+      'initialized': 'never'
+    }],
+    'operator-linebreak': [2, 'after', {
+      'overrides': {
+        '?': 'before',
+        ':': 'before'
+      }
+    }],
+    'padded-blocks': [2, 'never'],
+    'quotes': [2, 'single', {
+      'avoidEscape': true,
+      'allowTemplateLiterals': true
+    }],
+    'semi': [2, 'never'],
+    'semi-spacing': [2, {
+      'before': false,
+      'after': true
+    }],
+    'space-before-blocks': [2, 'always'],
+    'space-before-function-paren': [2, 'never'],
+    'space-in-parens': [2, 'never'],
+    'space-infix-ops': 2,
+    'space-unary-ops': [2, {
+      'words': true,
+      'nonwords': false
+    }],
+    'spaced-comment': [2, 'always', {
+      'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
+    }],
+    'template-curly-spacing': [2, 'never'],
+    'use-isnan': 2,
+    'valid-typeof': 2,
+    'wrap-iife': [2, 'any'],
+    'yield-star-spacing': [2, 'both'],
+    'yoda': [2, 'never'],
+    'prefer-const': 2,
+    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
+    'object-curly-spacing': [2, 'always', {
+      objectsInObjects: false
+    }],
+    'array-bracket-spacing': [2, 'never']
+  }
+}
+

+ 20 - 0
statement-pc/.gitignore

@@ -0,0 +1,20 @@
+.DS_Store
+node_modules/
+dist/
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+test/unit/coverage
+test/e2e/reports
+selenium-debug.log
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+
+package-lock.json

+ 10 - 0
statement-pc/.postcssrc.js

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

+ 5 - 0
statement-pc/.travis.yml

@@ -0,0 +1,5 @@
+language: node_js
+node_js: stable
+script: npm run test
+notifications:
+  email: false

+ 21 - 0
statement-pc/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.

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 155 - 0
statement-pc/README.md


+ 166 - 0
statement-pc/README.zh-CN.md

@@ -0,0 +1,166 @@
+<p align="center">
+  <img width="320" src="https://wpimg.wallstcn.com/ecc53a42-d79b-42e2-8852-5126b810a4c8.svg">
+</p>
+
+<p align="center">
+	<a href="https://github.com/vuejs/vue">
+		<img src="https://img.shields.io/badge/vue-2.5.10-brightgreen.svg" alt="vue">
+	</a>
+	<a href="https://github.com/ElemeFE/element">
+		<img src="https://img.shields.io/badge/element--ui-2.0.8-brightgreen.svg" alt="element-ui">
+	</a>
+	<a href="https://travis-ci.org/PanJiaChen/vue-element-admin" rel="nofollow">
+		<img src="https://travis-ci.org/PanJiaChen/vue-element-admin.svg?branch=master" alt="Build Status">
+	</a>
+	<a href="https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE">
+		<img src="https://img.shields.io/github/license/mashape/apistatus.svg" alt="license">
+	</a>
+	<a href="https://github.com/PanJiaChen/vue-element-admin/releases">
+		<img src="https://img.shields.io/github/release/PanJiaChen/vue-element-admin.svg" alt="GitHub release">
+	</a>
+</p>
+
+简体中文 | [English](./README.md)
+
+## 简介
+
+`vue-element-admin` 是一个后台集成解决方案,它基于 [Vue.js](https://github.com/vuejs/vue) 和 [element](https://github.com/ElemeFE/element)。它使用了最新的前端技术栈,内置了i18国际化解决方案,动态路由,权限验证等很多功能特性,相信不管你的需求是什么,本项目都能帮助到你。
+
+- [在线访问](http://panjiachen.github.io/vue-element-admin)
+
+- [使用文档](https://panjiachen.github.io/vue-element-admin-site/#/zh-cn/)
+
+- [Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
+
+- [Donate](https://panjiachen.github.io/vue-element-admin-site/#/zh-cn/donate)
+
+**本项目的定位是后台集成方案,不适合当基础模板来开发。**
+ - 模板建议使用: [vueAdmin-template](https://github.com/PanJiaChen/vueAdmin-template)  
+ - 桌面端: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
+
+**注意:该项目使用 element-ui@2.0.0+ 版本,所以最低兼容 vue@2.5.0+**
+
+## 前序准备
+
+你的本地环境需要安装 [node](http://nodejs.org/) 和 [git](https://git-scm.com/)。我们的技术栈基于 [ES2015+](http://es6.ruanyifeng.com/)、[vue](https://cn.vuejs.org/index.html)、[vuex](https://vuex.vuejs.org/zh-cn/)、[vue-router](https://router.vuejs.org/zh-cn/) and [element-ui](https://github.com/ElemeFE/element),所有的请求数据都使用[Mock.js](https://github.com/nuysoft/Mock)模拟,提前了解和学习这些知识会对使用本项目有很大的帮助。
+
+同时配套一个系列的教程文章,如何从零构建后一个完整的后台项目,建议大家先看完这些文章再来实践本项目
+ - [手摸手,带你用 vue 撸后台 系列一(基础篇)](https://juejin.im/post/59097cd7a22b9d0065fb61d2)
+ - [手摸手,带你用 vue 撸后台 系列二(登录权限篇)](https://juejin.im/post/591aa14f570c35006961acac)
+ - [手摸手,带你用 vue 撸后台 系列三 (实战篇)](https://juejin.im/post/593121aa0ce4630057f70d35)
+ - [手摸手,带你用 vue 撸后台 系列四(vueAdmin 一个极简的后台基础模板)](https://juejin.im/post/595b4d776fb9a06bbe7dba56)
+ - [手摸手,带你封装一个 vue component](https://segmentfault.com/a/1190000009090836)
+ - [手摸手,带你优雅的使用 icon](https://juejin.im/post/59bb864b5188257e7a427c09)
+
+ 响应需求,开了一个qq群 `591724180` 方便大家交流
+
+ 或者加入该群主 **[圈子](https://jianshiapp.com/circles/1209)** 楼主会经常分享一些技术相关的东西
+
+ **如有问题请先看上述使用文档和文章,若不能满足,欢迎 issue 和 pr**
+
+ **本项目并不是一个脚手架,更倾向于是一个集成解决方案**
+
+ **该项目不支持低版本浏览器(如ie),有需求请自行添加polyfill [详情](https://github.com/PanJiaChen/vue-element-admin/wiki#babel-polyfill)**
+
+ <p align="center">
+  <img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png">
+</p>
+
+## 功能
+```
+- 登录/注销
+- 权限验证
+- 多环境发布
+- 动态侧边栏(支持多级路由)
+- 动态面包屑
+- 国际化多语言
+- 多种动态换肤
+- 快捷导航(标签页)
+- 富文本编辑器
+- Markdown编辑器
+- JSON编辑器
+- Screenfull全屏
+- 列表拖拽
+- Svg Sprite 图标
+- Dashboard
+- 本地mock数据
+- Echarts 图表
+- Clipboard(剪贴复制)
+- 401/404错误页面
+- 错误日志
+- 导出excel
+- 导出zip
+- 前端可视化excel
+- 树形table
+- Table example
+- 动态table example
+- 拖拽table example
+- 内联编辑table example
+- Form example
+- 二步登录
+- SplitPane
+- Dropzone
+- Sticky
+- CountTo
+- Markdown2html
+```
+
+## 开发
+```bash
+# 克隆项目
+git clone https://github.com/PanJiaChen/vue-element-admin.git
+
+# 安装依赖
+npm install
+   
+# 建议不要用cnpm安装 会有各种诡异的bug 可以通过如下操作解决 npm 下载速度慢的问题
+npm install --registry=https://registry.npm.taobao.org
+
+# 启动服务
+npm run dev
+```
+浏览器访问 http://localhost:9527
+
+## 发布
+```bash
+# 构建测试环境
+npm run build:sit
+
+# 构建生成环境
+npm run build:prod
+```
+
+## 其它
+```bash
+# --report to build with bundle size analytics
+npm run build:prod --report
+
+# --preview to start a server in local to preview
+npm run build:prod --preview
+
+# lint code
+npm run lint
+
+# auto fix
+npm run lint -- --fix
+```
+
+更多信息请参考 [使用文档](https://panjiachen.github.io/vue-element-admin-site/#/zh-cn/deploy)
+
+## Changelog
+Detailed changes for each release are documented in the [release notes](https://github.com/PanJiaChen/vue-element-admin/releases).
+
+## Online Demo
+[在线 Demo](http://panjiachen.github.io/vue-element-admin)
+
+## Donate
+如果你觉得这个项目帮助到了你,你可以帮作者买一杯果汁表示鼓励 :tropical_drink:
+![donate](https://panjiachen.github.io/donate/donation.png)
+
+[Paypal Me](https://www.paypal.me/panfree23)
+
+## License
+
+[MIT](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE)
+
+Copyright (c) 2017-present PanJiaChen

+ 48 - 0
statement-pc/build/build.js

@@ -0,0 +1,48 @@
+'use strict'
+require('./check-versions')()
+
+const ora = require('ora')
+const rm = require('rimraf')
+const path = require('path')
+const chalk = require('chalk')
+const webpack = require('webpack')
+const config = require('../config')
+const webpackConfig = require('./webpack.prod.conf')
+const server = require('pushstate-server')
+
+var spinner = ora('building for '+ process.env.env_config+ ' environment...' )
+spinner.start()
+
+rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
+  if (err) throw err
+  webpack(webpackConfig, (err, stats) => {
+    spinner.stop()
+    if (err) throw err
+    process.stdout.write(stats.toString({
+      colors: true,
+      modules: false,
+      children: false,
+      chunks: false,
+      chunkModules: false
+    }) + '\n\n')
+
+    if (stats.hasErrors()) {
+      console.log(chalk.red('  Build failed with errors.\n'))
+      process.exit(1)
+    }
+
+    console.log(chalk.cyan('  Build complete.\n'))
+    console.log(chalk.yellow(
+      '  Tip: built files are meant to be served over an HTTP server.\n' +
+      '  Opening index.html over file:// won\'t work.\n'
+    ))
+    if(process.env.npm_config_preview){
+      server.start({
+          port: 9526,
+          directory: './dist',
+          file: '/index.html'
+      });
+      console.log('> Listening at ' +  'http://localhost:9526' + '\n')
+    }
+  })
+})

+ 54 - 0
statement-pc/build/check-versions.js

@@ -0,0 +1,54 @@
+'use strict'
+const chalk = require('chalk')
+const semver = require('semver')
+const packageConfig = require('../package.json')
+const shell = require('shelljs')
+
+function exec (cmd) {
+  return require('child_process').execSync(cmd).toString().trim()
+}
+
+const versionRequirements = [
+  {
+    name: 'node',
+    currentVersion: semver.clean(process.version),
+    versionRequirement: packageConfig.engines.node
+  }
+]
+
+if (shell.which('npm')) {
+  versionRequirements.push({
+    name: 'npm',
+    currentVersion: exec('npm --version'),
+    versionRequirement: packageConfig.engines.npm
+  })
+}
+
+module.exports = function () {
+  const warnings = []
+
+  for (let i = 0; i < versionRequirements.length; i++) {
+    const mod = versionRequirements[i]
+
+    if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
+      warnings.push(mod.name + ': ' +
+        chalk.red(mod.currentVersion) + ' should be ' +
+        chalk.green(mod.versionRequirement)
+      )
+    }
+  }
+
+  if (warnings.length) {
+    console.log('')
+    console.log(chalk.yellow('To use this template, you must update following to modules:'))
+    console.log()
+
+    for (let i = 0; i < warnings.length; i++) {
+      const warning = warnings[i]
+      console.log('  ' + warning)
+    }
+
+    console.log()
+    process.exit(1)
+  }
+}

+ 101 - 0
statement-pc/build/utils.js

@@ -0,0 +1,101 @@
+'use strict'
+const path = require('path')
+const config = require('../config')
+const ExtractTextPlugin = require('extract-text-webpack-plugin')
+const packageConfig = require('../package.json')
+
+exports.assetsPath = function (_path) {
+  const assetsSubDirectory = process.env.NODE_ENV === 'production'
+    ? config.build.assetsSubDirectory
+    : config.dev.assetsSubDirectory
+
+  return path.posix.join(assetsSubDirectory, _path)
+}
+
+exports.cssLoaders = function (options) {
+  options = options || {}
+
+  const cssLoader = {
+    loader: 'css-loader',
+    options: {
+      sourceMap: options.sourceMap
+    }
+  }
+
+  const postcssLoader = {
+    loader: 'postcss-loader',
+    options: {
+      sourceMap: options.sourceMap
+    }
+  }
+
+  // generate loader string to be used with extract text plugin
+  function generateLoaders (loader, loaderOptions) {
+    const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
+
+    if (loader) {
+      loaders.push({
+        loader: loader + '-loader',
+        options: Object.assign({}, loaderOptions, {
+          sourceMap: options.sourceMap
+        })
+      })
+    }
+
+    // Extract CSS when that option is specified
+    // (which is the case during production build)
+    if (options.extract) {
+      return ExtractTextPlugin.extract({
+        use: loaders,
+        fallback: 'vue-style-loader'
+      })
+    } else {
+      return ['vue-style-loader'].concat(loaders)
+    }
+  }
+
+  // https://vue-loader.vuejs.org/en/configurations/extract-css.html
+  return {
+    css: generateLoaders(),
+    postcss: generateLoaders(),
+    less: generateLoaders('less'),
+    sass: generateLoaders('sass', { indentedSyntax: true }),
+    scss: generateLoaders('sass'),
+    stylus: generateLoaders('stylus'),
+    styl: generateLoaders('stylus')
+  }
+}
+
+// Generate loaders for standalone style files (outside of .vue)
+exports.styleLoaders = function (options) {
+  const output = []
+  const loaders = exports.cssLoaders(options)
+
+  for (const extension in loaders) {
+    const loader = loaders[extension]
+    output.push({
+      test: new RegExp('\\.' + extension + '$'),
+      use: loader
+    })
+  }
+
+  return output
+}
+
+exports.createNotifierCallback = () => {
+  const notifier = require('node-notifier')
+
+  return (severity, errors) => {
+    if (severity !== 'error') return
+
+    const error = errors[0]
+    const filename = error.file && error.file.split('!').pop()
+
+    notifier.notify({
+      title: packageConfig.name,
+      message: severity + ': ' + error.name,
+      subtitle: filename || '',
+      icon: path.join(__dirname, 'logo.png')
+    })
+  }
+}

+ 22 - 0
statement-pc/build/vue-loader.conf.js

@@ -0,0 +1,22 @@
+'use strict'
+const utils = require('./utils')
+const config = require('../config')
+const isProduction = process.env.NODE_ENV === 'production'
+const sourceMapEnabled = isProduction
+  ? config.build.productionSourceMap
+  : config.dev.cssSourceMap
+
+module.exports = {
+  loaders: utils.cssLoaders({
+    sourceMap: sourceMapEnabled,
+    extract: isProduction
+  }),
+  cssSourceMap: sourceMapEnabled,
+  cacheBusting: config.dev.cacheBusting,
+  transformToRequire: {
+    video: ['src', 'poster'],
+    source: 'src',
+    img: 'src',
+    image: 'xlink:href'
+  }
+}

+ 101 - 0
statement-pc/build/webpack.base.conf.js

@@ -0,0 +1,101 @@
+'use strict'
+const path = require('path')
+const utils = require('./utils')
+const config = require('../config')
+const vueLoaderConfig = require('./vue-loader.conf')
+
+function resolve (dir) {
+  return path.join(__dirname, '..', dir)
+}
+
+const createLintingRule = () => ({
+  test: /\.(js|vue)$/,
+  loader: 'eslint-loader',
+  enforce: 'pre',
+  include: [resolve('src'), resolve('test')],
+  options: {
+    formatter: require('eslint-friendly-formatter'),
+    emitWarning: !config.dev.showEslintErrorsInOverlay
+  }
+})
+
+module.exports = {
+  context: path.resolve(__dirname, '../'),
+  entry: {
+    app: './src/main.js'
+  },
+  output: {
+    path: config.build.assetsRoot,
+    filename: '[name].js',
+    publicPath: process.env.NODE_ENV === 'production'
+      ? config.build.assetsPublicPath
+      : config.dev.assetsPublicPath
+  },
+  resolve: {
+    extensions: ['.js', '.vue', '.json'],
+    alias: {
+      'vue$': 'vue/dist/vue.esm.js',
+      '@': resolve('src'),
+    }
+  },
+  module: {
+    rules: [
+      ...(config.dev.useEslint ? [createLintingRule()] : []),
+      {
+        test: /\.vue$/,
+        loader: 'vue-loader',
+        options: vueLoaderConfig
+      },
+      {
+        test: /\.js$/,
+        loader: 'babel-loader?cacheDirectory',
+        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
+      },
+      {
+        test: /\.svg$/,
+        loader: 'svg-sprite-loader',
+        include: [resolve('src/icons')],
+        options: {
+          symbolId: 'icon-[name]'
+        }
+      },
+      {
+        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
+        loader: 'url-loader',
+        exclude: [resolve('src/icons')],
+        options: {
+          limit: 10000,
+          name: utils.assetsPath('img/[name].[hash:7].[ext]')
+        }
+      },
+      {
+        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
+        loader: 'url-loader',
+        options: {
+          limit: 10000,
+          name: utils.assetsPath('media/[name].[hash:7].[ext]')
+        }
+      },
+      {
+        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
+        loader: 'url-loader',
+        options: {
+          limit: 10000,
+          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
+        }
+      }
+    ]
+  },
+  node: {
+    // prevent webpack from injecting useless setImmediate polyfill because Vue
+    // source contains it (although only uses it if it's native).
+    setImmediate: false,
+    // prevent webpack from injecting mocks to Node native modules
+    // that does not make sense for the client
+    dgram: 'empty',
+    fs: 'empty',
+    net: 'empty',
+    tls: 'empty',
+    child_process: 'empty'
+  }
+}

+ 88 - 0
statement-pc/build/webpack.dev.conf.js

@@ -0,0 +1,88 @@
+'use strict'
+const path = require('path')
+const utils = require('./utils')
+const webpack = require('webpack')
+const config = require('../config')
+const merge = require('webpack-merge')
+const baseWebpackConfig = require('./webpack.base.conf')
+const HtmlWebpackPlugin = require('html-webpack-plugin')
+const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
+const portfinder = require('portfinder')
+
+function resolve (dir) {
+  return path.join(__dirname, '..', dir)
+}
+
+const HOST = process.env.HOST
+const PORT = process.env.PORT && Number(process.env.PORT)
+
+const devWebpackConfig = merge(baseWebpackConfig, {
+  module: {
+    rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
+  },
+  // cheap-module-eval-source-map is faster for development
+  devtool: config.dev.devtool,
+
+  // these devServer options should be customized in /config/index.js
+  devServer: {
+    clientLogLevel: 'warning',
+    historyApiFallback: true,
+    hot: true,
+    compress: true,
+    host: HOST || config.dev.host,
+    port: PORT || config.dev.port,
+    open: config.dev.autoOpenBrowser,
+    overlay: config.dev.errorOverlay
+      ? { warnings: false, errors: true }
+      : false,
+    publicPath: config.dev.assetsPublicPath,
+    proxy: config.dev.proxyTable,
+    quiet: true, // necessary for FriendlyErrorsPlugin
+    watchOptions: {
+      poll: config.dev.poll,
+    }
+  },
+  plugins: [
+    new webpack.DefinePlugin({
+      'process.env': require('../config/dev.env')
+    }),
+    new webpack.HotModuleReplacementPlugin(),
+    new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
+    new webpack.NoEmitOnErrorsPlugin(),
+    // https://github.com/ampedandwired/html-webpack-plugin
+    new HtmlWebpackPlugin({
+      filename: 'index.html',
+      template: 'index.html',
+      inject: true,
+      favicon: resolve('favicon.ico'),
+      title: 'vue-element-admin',
+      path: config.dev.assetsPublicPath + config.dev.assetsSubDirectory
+    }),
+  ]
+})
+
+module.exports = new Promise((resolve, reject) => {
+  portfinder.basePort = process.env.PORT || config.dev.port
+  portfinder.getPort((err, port) => {
+    if (err) {
+      reject(err)
+    } else {
+      // publish the new Port, necessary for e2e tests
+      process.env.PORT = port
+      // add port to devServer config
+      devWebpackConfig.devServer.port = port
+
+      // Add FriendlyErrorsPlugin
+      devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
+        compilationSuccessInfo: {
+          messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
+        },
+        onErrors: config.dev.notifyOnErrors
+        ? utils.createNotifierCallback()
+        : undefined
+      }))
+
+      resolve(devWebpackConfig)
+    }
+  })
+})

+ 175 - 0
statement-pc/build/webpack.prod.conf.js

@@ -0,0 +1,175 @@
+'use strict'
+const path = require('path')
+const utils = require('./utils')
+const webpack = require('webpack')
+const config = require('../config')
+const merge = require('webpack-merge')
+const baseWebpackConfig = require('./webpack.base.conf')
+const CopyWebpackPlugin = require('copy-webpack-plugin')
+const HtmlWebpackPlugin = require('html-webpack-plugin')
+const ExtractTextPlugin = require('extract-text-webpack-plugin')
+const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
+const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
+
+function resolve (dir) {
+  return path.join(__dirname, '..', dir)
+}
+
+const env = require('../config/'+process.env.env_config+'.env')
+
+const webpackConfig = merge(baseWebpackConfig, {
+  module: {
+    rules: utils.styleLoaders({
+      sourceMap: config.build.productionSourceMap,
+      extract: true,
+      usePostCSS: true
+    })
+  },
+  devtool: config.build.productionSourceMap ? config.build.devtool : false,
+  output: {
+    path: config.build.assetsRoot,
+    filename: utils.assetsPath('js/[name].[chunkhash].js'),
+    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
+  },
+  plugins: [
+    // http://vuejs.github.io/vue-loader/en/workflow/production.html
+    new webpack.DefinePlugin({
+      'process.env': env
+    }),
+    new UglifyJsPlugin({
+      uglifyOptions: {
+        compress: {
+          warnings: false
+        }
+      },
+      sourceMap: config.build.productionSourceMap,
+      parallel: true
+    }),
+    // extract css into its own file
+    new ExtractTextPlugin({
+      filename: utils.assetsPath('css/[name].[contenthash].css'),
+      // Setting the following option to `false` will not extract CSS from codesplit chunks.
+      // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
+      // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
+      allChunks: false,
+    }),
+    // Compress extracted CSS. We are using this plugin so that possible
+    // duplicated CSS from different components can be deduped.
+    new OptimizeCSSPlugin({
+      cssProcessorOptions: config.build.productionSourceMap
+        ? { safe: true, map: { inline: false } }
+        : { safe: true }
+    }),
+    // generate dist index.html with correct asset hash for caching.
+    // you can customize output by editing /index.html
+    // see https://github.com/ampedandwired/html-webpack-plugin
+    new HtmlWebpackPlugin({
+      filename: config.build.index,
+      template: 'index.html',
+      inject: true,
+      favicon: resolve('favicon.ico'),
+      title: 'vue-element-admin',
+      path: config.build.assetsPublicPath + config.build.assetsSubDirectory,
+      minify: {
+        removeComments: true,
+        collapseWhitespace: true,
+        removeAttributeQuotes: true
+        // more options:
+        // https://github.com/kangax/html-minifier#options-quick-reference
+      },
+      // necessary to consistently work with multiple chunks via CommonsChunkPlugin
+      chunksSortMode: 'dependency'
+    }),
+    // keep module.id stable when vender modules does not change
+    new webpack.HashedModuleIdsPlugin(),
+    // enable scope hoisting
+    new webpack.optimize.ModuleConcatenationPlugin(),
+    // split vendor js into its own file
+    new webpack.optimize.CommonsChunkPlugin({
+      name: 'vendor',
+      minChunks (module) {
+        // any required modules inside node_modules are extracted to vendor
+        return (
+          module.resource &&
+          /\.js$/.test(module.resource) &&
+          module.resource.indexOf(
+            path.join(__dirname, '../node_modules')
+          ) === 0
+        )
+      }
+    }),
+    // extract webpack runtime and module manifest to its own file in order to
+    // prevent vendor hash from being updated whenever app bundle is updated
+    new webpack.optimize.CommonsChunkPlugin({
+      name: 'manifest',
+      minChunks: Infinity
+    }),
+    // This instance extracts shared chunks from code splitted chunks and bundles them
+    // in a separate chunk, similar to the vendor chunk
+    // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
+    new webpack.optimize.CommonsChunkPlugin({
+      name: 'app',
+      async: 'vendor-async',
+      children: true,
+      minChunks: 3
+    }),
+    // split echarts into its own file
+    new webpack.optimize.CommonsChunkPlugin({
+      async: 'echarts',
+      minChunks(module) {
+        var context = module.context;
+        return context && (context.indexOf('echarts') >= 0 || context.indexOf('zrender') >= 0);
+      }
+    }),
+    // split xlsx into its own file
+    new webpack.optimize.CommonsChunkPlugin({
+      async: 'xlsx',
+      minChunks(module) {
+        var context = module.context;
+        return context && (context.indexOf('xlsx') >= 0);
+      }
+    }),
+     // split codemirror into its own file
+     new webpack.optimize.CommonsChunkPlugin({
+      async: 'codemirror',
+      minChunks(module) {
+        var context = module.context;
+        return context && (context.indexOf('codemirror') >= 0);
+      }
+    }),
+
+    // copy custom static assets
+    new CopyWebpackPlugin([
+      {
+        from: path.resolve(__dirname, '../static'),
+        to: config.build.assetsSubDirectory,
+        ignore: ['.*']
+      }
+    ])
+  ]
+})
+
+if (config.build.productionGzip) {
+  const CompressionWebpackPlugin = require('compression-webpack-plugin')
+
+  webpackConfig.plugins.push(
+    new CompressionWebpackPlugin({
+      asset: '[path].gz[query]',
+      algorithm: 'gzip',
+      test: new RegExp(
+        '\\.(' +
+        config.build.productionGzipExtensions.join('|') +
+        ')$'
+      ),
+      threshold: 10240,
+      minRatio: 0.8
+    })
+  )
+}
+
+if (config.build.bundleAnalyzerReport) {
+  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
+  webpackConfig.plugins.push(new BundleAnalyzerPlugin())
+}
+
+module.exports = webpackConfig

+ 6 - 0
statement-pc/config/dev.env.js

@@ -0,0 +1,6 @@
+module.exports = {
+	NODE_ENV: '"development"',
+	ENV_CONFIG: '"dev"',
+	// BASE_API: '"http://tstatementapi.d5ct.com"'
+	BASE_API: '"http://statementapi.d5c360.com"'
+}

+ 83 - 0
statement-pc/config/index.js

@@ -0,0 +1,83 @@
+'use strict'
+// Template version: 1.2.6
+// see http://vuejs-templates.github.io/webpack for documentation.
+
+const path = require('path')
+
+module.exports = {
+  dev: {
+
+    // Paths
+    assetsSubDirectory: 'static',
+    assetsPublicPath: '/',
+    proxyTable: {},
+
+    // Various Dev Server settings
+    host: 'localhost', // can be overwritten by process.env.HOST
+    port: 8181, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
+    autoOpenBrowser: true,
+    errorOverlay: true,
+    notifyOnErrors: false,
+    poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
+
+    // Use Eslint Loader?
+    // If true, your code will be linted during bundling and
+    // linting errors and warnings will be shown in the console.
+    useEslint: true,
+    // If true, eslint errors and warnings will also be shown in the error overlay
+    // in the browser.
+    showEslintErrorsInOverlay: false,
+
+    /**
+     * Source Maps
+     */
+
+    // https://webpack.js.org/configuration/devtool/#development
+    devtool: '#cheap-source-map',
+
+    // If you have problems debugging vue-files in devtools,
+    // set this to false - it *may* help
+    // https://vue-loader.vuejs.org/en/options.html#cachebusting
+    cacheBusting: true,
+
+    // CSS Sourcemaps off by default because relative paths are "buggy"
+    // with this option, according to the CSS-Loader README
+    // (https://github.com/webpack/css-loader#sourcemaps)
+    // In our experience, they generally work as expected,
+    // just be aware of this issue when enabling this option.
+    cssSourceMap: false,
+  },
+
+  build: {
+    // Template for index.html
+    index: path.resolve(__dirname, '../dist/index.html'),
+
+    // Paths
+    assetsRoot: path.resolve(__dirname, '../dist'),
+    assetsSubDirectory: 'static',
+
+    // you can set by youself according to actual condition
+    assetsPublicPath: './',
+
+    /**
+     * Source Maps
+     */
+
+    productionSourceMap: false,
+    // https://webpack.js.org/configuration/devtool/#production
+    devtool: '#source-map',
+
+    // Gzip off by default as many popular static hosts such as
+    // Surge or Netlify already gzip all static assets for you.
+    // Before setting to `true`, make sure to:
+    // npm install --save-dev compression-webpack-plugin
+    productionGzip: false,
+    productionGzipExtensions: ['js', 'css'],
+
+    // Run the build command with an extra argument to
+    // View the bundle analyzer report after build finishes:
+    // `npm run build --report`
+    // Set to `true` or `false` to always turn it on or off
+    bundleAnalyzerReport: process.env.npm_config_report
+  }
+}

+ 6 - 0
statement-pc/config/prod.env.js

@@ -0,0 +1,6 @@
+module.exports = {
+	NODE_ENV: '"production"',
+	ENV_CONFIG: '"prod"',
+	BASE_API: '"http://statementapi.d5c360.com"'
+	// BASE_API: '"http://tstatementapi.d5ct.com"'
+}

+ 9 - 0
statement-pc/config/test.env.js

@@ -0,0 +1,9 @@
+'use strict'
+const merge = require('webpack-merge')
+const devEnv = require('./dev.env')
+
+module.exports = merge(devEnv, {
+  NODE_ENV: '"testing"',
+  // API_URI: '"http://tstatementapi.d5ct.com"'
+  API_URI: '"http://statementapi.d5c360.com"'
+})

binární
statement-pc/favicon.ico


+ 22 - 0
statement-pc/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 name="renderer" content="webkit">
+		<!-- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> -->
+		<title>第五创数据报表系统</title>
+		<script type="text/javascript">
+			console.log(window.location.href)
+			var url = window.location.href
+			if (url.indexOf('dashboard2') < 0) {
+				document.write('<meta name="viewport" content="width=640, initial-scale=1, maximum-scale=1, user-scalable=no">')
+			}
+		</script>
+	</head>
+	<body>
+		<!-- <script src=<%= htmlWebpackPlugin.options.path %>/tinymce4.7.5/tinymce.min.js></script> -->
+		<div id="app"></div>
+		<!-- built files will be auto injected -->
+	</body>
+</html>

+ 101 - 0
statement-pc/package.json

@@ -0,0 +1,101 @@
+{
+  "name": "vue-element-admin",
+  "version": "3.6.3",
+  "description": "A magical vue admin. Typical templates for enterprise applications. Newest development stack of vue. Lots of awesome features",
+  "author": "Pan <panfree23@gmail.com>",
+  "license": "MIT",
+  "private": true,
+  "scripts": {
+    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
+    "build:prod": "cross-env NODE_ENV=production env_config=prod node build/build.js",
+    "build:sit": "cross-env NODE_ENV=production env_config=sit node build/build.js",
+    "lint": "eslint --ext .js,.vue src",
+    "test": "npm run lint"
+  },
+  "dependencies": {
+    "axios": "0.17.1",
+    "clipboard": "1.7.1",
+    "codemirror": "5.32.0",
+    "dropzone": "5.2.0",
+    "echarts": "3.8.5",
+    "element-ui": "2.0.8",
+    "file-saver": "1.3.3",
+    "font-awesome": "4.7.0",
+    "js-cookie": "2.2.0",
+    "jsonlint": "1.6.2",
+    "jszip": "3.1.5",
+    "mockjs": "1.0.1-beta3",
+    "node-sass": "^4.13.0",
+    "normalize.css": "7.0.0",
+    "nprogress": "0.2.0",
+    "screenfull": "3.3.2",
+    "showdown": "1.8.5",
+    "simplemde": "1.11.2",
+    "sortablejs": "1.7.0",
+    "vue": "2.5.10",
+    "vue-count-to": "1.0.13",
+    "vue-i18n": "7.3.2",
+    "vue-multiselect": "2.0.8",
+    "vue-router": "3.0.1",
+    "vue-splitpane": "1.0.2",
+    "vuedraggable": "2.15.0",
+    "vuex": "3.0.1",
+    "xlsx": "^0.11.16"
+  },
+  "devDependencies": {
+    "autoprefixer": "7.2.3",
+    "babel-core": "6.26.0",
+    "babel-eslint": "8.0.3",
+    "babel-helper-vue-jsx-merge-props": "2.0.3",
+    "babel-loader": "7.1.2",
+    "babel-plugin-syntax-jsx": "6.18.0",
+    "babel-plugin-transform-runtime": "6.23.0",
+    "babel-plugin-transform-vue-jsx": "3.5.0",
+    "babel-preset-env": "1.6.1",
+    "babel-preset-stage-2": "6.24.1",
+    "chalk": "2.3.0",
+    "copy-webpack-plugin": "4.3.0",
+    "cross-env": "5.1.1",
+    "css-loader": "0.28.7",
+    "eslint": "4.13.1",
+    "eslint-friendly-formatter": "3.0.0",
+    "eslint-loader": "1.9.0",
+    "eslint-plugin-html": "4.0.1",
+    "extract-text-webpack-plugin": "3.0.2",
+    "file-loader": "1.1.5",
+    "friendly-errors-webpack-plugin": "1.6.1",
+    "html-webpack-plugin": "2.30.1",
+    "node-notifier": "5.1.2",
+    "optimize-css-assets-webpack-plugin": "3.2.0",
+    "ora": "1.3.0",
+    "portfinder": "1.0.13",
+    "postcss-import": "11.0.0",
+    "postcss-loader": "2.0.9",
+    "postcss-url": "7.3.0",
+    "pushstate-server": "3.0.1",
+    "rimraf": "2.6.2",
+    "sass-loader": "6.0.6",
+    "script-loader": "0.7.2",
+    "semver": "5.4.1",
+    "shelljs": "0.7.8",
+    "svg-sprite-loader": "3.5.2",
+    "uglifyjs-webpack-plugin": "1.1.3",
+    "url-loader": "0.6.2",
+    "vue-loader": "13.5.0",
+    "vue-style-loader": "3.0.3",
+    "vue-template-compiler": "2.5.10",
+    "webpack": "3.10.0",
+    "webpack-bundle-analyzer": "2.9.1",
+    "webpack-dev-server": "2.9.7",
+    "webpack-merge": "4.1.1"
+  },
+  "engines": {
+    "node": ">= 4.0.0",
+    "npm": ">= 3.0.0"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not ie <= 8"
+  ]
+}

+ 24 - 0
statement-pc/src/App.vue

@@ -0,0 +1,24 @@
+<template>
+	<div id="app">
+		<router-view></router-view>
+		<left-nav></left-nav>
+	</div>
+</template>
+
+<script>
+// import HeaderContainer from '@/components/HeaderContainer'
+import LeftNav from '@/components/LeftNav'
+export default{
+  name: 'App',
+  components: {
+    LeftNav
+  }
+}
+</script>
+<style rel="stylesheet/scss" lang="scss">
+#app {
+	position: relative;
+	width: 100%;
+	background-color: #334051;
+}
+</style>

+ 29 - 0
statement-pc/src/api/login.js

@@ -0,0 +1,29 @@
+import request from '@/utils/request'
+
+export function loginByUsername(username, password) {
+  const data = {
+    username,
+    password
+  }
+  return request({
+    url: '/v1/token',
+    method: 'post',
+    data
+  })
+}
+
+export function logout() {
+  return request({
+    url: '/v1/token',
+    method: 'delete'
+  })
+}
+
+export function getUserInfo(userId) {
+  return request({
+    url: '/v1/user/' + userId,
+    method: 'get'
+    // params: { token }
+  })
+}
+

binární
statement-pc/src/assets/401_images/401.gif


binární
statement-pc/src/assets/404_images/404.png


binární
statement-pc/src/assets/404_images/404_cloud.png


binární
statement-pc/src/assets/custom-theme/fonts/element-icons.ttf


binární
statement-pc/src/assets/custom-theme/fonts/element-icons.woff


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/assets/custom-theme/index.css


+ 199 - 0
statement-pc/src/assets/echarts-macarons.js

@@ -0,0 +1,199 @@
+/* eslint-disable */
+(function (root, factory) {
+    if (typeof define === 'function' && define.amd) {
+        // AMD. Register as an anonymous module.
+        define(['exports', 'echarts'], factory);
+    } else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
+        // CommonJS
+        factory(exports, require('echarts'));
+    } else {
+        // Browser globals
+        factory({}, root.echarts);
+    }
+}(this, function (exports, echarts) {
+    var log = function (msg) {
+        if (typeof console !== 'undefined') {
+            console && console.error && console.error(msg);
+        }
+    };
+    if (!echarts) {
+        log('ECharts is not Loaded');
+        return;
+    }
+
+    var colorPalette = [
+        '#2ec7c9','#b6a2de','#5ab1ef','#ffb980','#d87a80',
+        '#8d98b3','#e5cf0d','#97b552','#95706d','#dc69aa',
+        '#07a2a4','#9a7fd1','#588dd5','#f5994e','#c05050',
+        '#59678c','#c9ab00','#7eb00a','#6f5553','#c14089'
+    ];
+
+
+    var theme = {
+        color: colorPalette,
+
+        title: {
+            textStyle: {
+                fontWeight: 'normal',
+                color: '#008acd'
+            }
+        },
+
+        visualMap: {
+            itemWidth: 15,
+            color: ['#5ab1ef','#e0ffff']
+        },
+
+        toolbox: {
+            iconStyle: {
+                normal: {
+                    borderColor: colorPalette[0]
+                }
+            }
+        },
+
+        tooltip: {
+            backgroundColor: 'rgba(50,50,50,0.5)',
+            axisPointer : {
+                type : 'line',
+                lineStyle : {
+                    color: '#008acd'
+                },
+                crossStyle: {
+                    color: '#008acd'
+                },
+                shadowStyle : {
+                    color: 'rgba(200,200,200,0.2)'
+                }
+            }
+        },
+
+        dataZoom: {
+            dataBackgroundColor: '#efefff',
+            fillerColor: 'rgba(182,162,222,0.2)',
+            handleColor: '#008acd'
+        },
+
+        grid: {
+            borderColor: '#eee'
+        },
+
+        categoryAxis: {
+            axisLine: {
+                lineStyle: {
+                    color: '#008acd'
+                }
+            },
+            splitLine: {
+                lineStyle: {
+                    color: ['#eee']
+                }
+            }
+        },
+
+        valueAxis: {
+            axisLine: {
+                lineStyle: {
+                    color: '#008acd'
+                }
+            },
+            splitArea : {
+                show : true,
+                areaStyle : {
+                    color: ['rgba(250,250,250,0.1)','rgba(200,200,200,0.1)']
+                }
+            },
+            splitLine: {
+                lineStyle: {
+                    color: ['#eee']
+                }
+            }
+        },
+
+        timeline : {
+            lineStyle : {
+                color : '#008acd'
+            },
+            controlStyle : {
+                normal : { color : '#008acd'},
+                emphasis : { color : '#008acd'}
+            },
+            symbol : 'emptyCircle',
+            symbolSize : 3
+        },
+
+        line: {
+            smooth : true,
+            symbol: 'emptyCircle',
+            symbolSize: 3
+        },
+
+        candlestick: {
+            itemStyle: {
+                normal: {
+                    color: '#d87a80',
+                    color0: '#2ec7c9',
+                    lineStyle: {
+                        color: '#d87a80',
+                        color0: '#2ec7c9'
+                    }
+                }
+            }
+        },
+
+        scatter: {
+            symbol: 'circle',
+            symbolSize: 4
+        },
+
+        map: {
+            label: {
+                normal: {
+                    textStyle: {
+                        color: '#d87a80'
+                    }
+                }
+            },
+            itemStyle: {
+                normal: {
+                    borderColor: '#eee',
+                    areaColor: '#ddd'
+                },
+                emphasis: {
+                    areaColor: '#fe994e'
+                }
+            }
+        },
+
+        graph: {
+            color: colorPalette
+        },
+
+        gauge : {
+            axisLine: {
+                lineStyle: {
+                    color: [[0.2, '#2ec7c9'],[0.8, '#5ab1ef'],[1, '#d87a80']],
+                    width: 10
+                }
+            },
+            axisTick: {
+                splitNumber: 10,
+                length :15,
+                lineStyle: {
+                    color: 'auto'
+                }
+            },
+            splitLine: {
+                length :22,
+                lineStyle: {
+                    color: 'auto'
+                }
+            },
+            pointer : {
+                width : 5
+            }
+        }
+    };
+
+    echarts.registerTheme('macarons', theme);
+}));

binární
statement-pc/src/assets/header/clock.png


binární
statement-pc/src/assets/header/d5clogo.png


binární
statement-pc/src/assets/header/logout.png


binární
statement-pc/src/assets/modal/colse.png


+ 52 - 0
statement-pc/src/components/Breadcrumb/index.vue

@@ -0,0 +1,52 @@
+<template>
+  <el-breadcrumb class="app-breadcrumb" separator="/">
+    <transition-group name="breadcrumb">
+      <el-breadcrumb-item v-for="(item,index)  in levelList" :key="item.path" v-if='item.meta.title'>
+        <span v-if='item.redirect==="noredirect"||index==levelList.length-1' class="no-redirect">{{item.meta.title}}</span>
+        <router-link v-else :to="item.redirect||item.path">{{item.meta.title}}</router-link>
+      </el-breadcrumb-item>
+    </transition-group>
+  </el-breadcrumb>
+</template>
+
+<script>
+
+export default {
+  created() {
+    this.getBreadcrumb()
+  },
+  data() {
+    return {
+      levelList: null
+    }
+  },
+  watch: {
+    $route() {
+      this.getBreadcrumb()
+    }
+  },
+  methods: {
+    getBreadcrumb() {
+      let matched = this.$route.matched.filter(item => item.name)
+      const first = matched[0]
+      if (first && first.name !== 'dashboard') {
+        matched = [{ path: '/dashboard', meta: { title: 'dashboard' }}].concat(matched)
+      }
+      this.levelList = matched
+    }
+  }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+  .app-breadcrumb.el-breadcrumb {
+    display: inline-block;
+    font-size: 14px;
+    line-height: 50px;
+    margin-left: 10px;
+    .no-redirect {
+      color: #97a8be;
+      cursor: text;
+    }
+  }
+</style>

+ 42 - 0
statement-pc/src/components/Currency/index.vue

@@ -0,0 +1,42 @@
+<template>
+  <figure>{{ result(value/100) }}</figure>
+</template>
+
+<script>
+// import accounting from 'accounting'
+export default {
+  props: {
+    value: {
+      type: Number,
+      default: 0
+    }
+  },
+  methods: {
+    // this.value钱的单位为:分
+    result: function(num) {
+      const result = []
+      let counter = 0
+      let t = num - Math.floor(num)
+      num = Math.floor(num)
+      num = (num || 0).toString().split('')
+      for (var i = num.length - 1; i >= 0; i--) {
+        counter++
+        result.unshift(num[i])
+        if (!(counter % 3) && i !== 0) {
+          result.unshift(',')
+        }
+      }
+      if (t > 0) {
+        t = result.join('') + t.toFixed(2).slice(1, 4)
+      } else {
+        t = result.join('')
+      }
+      return t
+    }
+  }
+}
+</script>
+
+<style lang="scss">
+  figure{display: inline-block;}
+</style>

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 77 - 0
statement-pc/src/components/ErrorLog/index.vue


+ 45 - 0
statement-pc/src/components/Hamburger/index.vue

@@ -0,0 +1,45 @@
+<template>
+  <div>
+    <svg t="1492500959545" @click="toggleClick" class="hamburger" :class="{'is-active':isActive}" style="" viewBox="0 0 1024 1024"
+      version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1691" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64">
+      <path d="M966.8023 568.849776 57.196677 568.849776c-31.397081 0-56.850799-25.452695-56.850799-56.850799l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 543.397081 998.200404 568.849776 966.8023 568.849776z"
+        p-id="1692"></path>
+      <path d="M966.8023 881.527125 57.196677 881.527125c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 856.07443 998.200404 881.527125 966.8023 881.527125z"
+        p-id="1693"></path>
+      <path d="M966.8023 256.17345 57.196677 256.17345c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.850799 56.850799-56.850799l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.850799l0 0C1023.653099 230.720755 998.200404 256.17345 966.8023 256.17345z"
+        p-id="1694"></path>
+    </svg>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'hamburger',
+  props: {
+    isActive: {
+      type: Boolean,
+      default: false
+    },
+    toggleClick: {
+      type: Function,
+      default: null
+    }
+  }
+}
+</script>
+
+<style scoped>
+.hamburger {
+	display: inline-block;
+	cursor: pointer;
+	width: 20px;
+	height: 20px;
+	transform: rotate(90deg);
+	transition: .38s;
+	transform-origin: 50% 50%;
+}
+
+.hamburger.is-active {
+	transform: rotate(0deg);
+}
+</style>

+ 260 - 0
statement-pc/src/components/HeaderContainer/index.vue

@@ -0,0 +1,260 @@
+<template>
+  <!-- <header class="d5cA-header">
+    <div class="d5cA-header__wid">
+      <div class="d5cA-logo">
+        <i class="el-icon-arrow-up"></i>
+        <img :src="d5c_logo" alt="logo" title="logo" />
+        <div class="d5cA-logo__info">
+          <h3>第五创</h3>
+          <p>数据统计平台</p>
+        </div>
+      </div>
+      <div class="d5cA-wrap">
+        <div class="d5cA-wrap__mainbav">
+          <router-link to="/dashboard" exact>首页</router-link>
+          <router-link to="/fanscount">粉丝</router-link>
+          <router-link to="/registeruser">注册用户</router-link>
+          <router-link to="/project">投资人</router-link>
+          <router-link to="/project">融资情况</router-link>
+          <router-link to="/recharge">充值情况</router-link>
+          <router-link to="/project">每月支出</router-link>
+        </div>
+      </div>
+    </div>
+  </header> -->
+  <header class="d5cA-header">
+    <div class="d5cA-header__wid">
+      <div class="d5cA-logo">
+        <router-link to="/fanscount">
+          <img :src="d5c_logo" alt="logo" title="logo" />
+          <div class="d5cA-logo__info">
+            <h3>第五创</h3>
+            <p>数据统计平台</p>
+          </div>
+        </router-link>
+      </div>
+
+      <div class="fr">
+        <div class="d5cA-tab__right">
+          <a href="/#/authredirect" class="d5cA-logout__btn">
+            <img :src="logout" title="登出" alt="登出" @click="clcikshow"/>
+          </a>
+          <div class="fullPo">
+            <screenfull class="screenfull right-menu-item"></screenfull>
+          </div>
+        </div>
+
+        <div class="d5cA-clock__pane fr">
+          <div class="d5cA-clock__top">
+            <img :src="clock" alt="clock" title="clock" />
+            <div class="d5cA-clock__time">
+              <p>{{dateTop}}</p>
+              <p>{{weekday}} {{time}}</p>
+            </div>
+          </div>
+          <p>数据截至{{dateBottom}}</p>
+        </div>
+
+        
+      </div>
+    </div>
+  </header>
+</template>
+<script>
+import d5c_logo from '@/assets/header/d5clogo.png'
+import clock from '@/assets/header/clock.png'
+import logout from '@/assets/header/logout.png'
+import Screenfull from '@/components/Screenfull'
+import New from '@/leftnav.js'
+const WEEKDAY = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
+export default {
+  name: 'headerContainer',
+  components: {
+    Screenfull
+  },
+  data() {
+    return {
+      d5c_logo,
+      clock,
+      logout,
+      now: new Date(),
+      autoPlayFlag2: null,
+      time: ''
+    }
+  },
+  computed: {
+    weekday() {
+      const day = this.now.getDay()
+      return WEEKDAY[day]
+    },
+    dateTop() {
+      const yy = this.now.getFullYear()
+      let mm = this.now.getMonth() + 1
+      let dd = this.now.getDate()
+      if (mm <= 9) {
+        mm = '0' + mm
+      }
+      if (dd <= 9) {
+        dd = '0' + dd
+      }
+      return yy + '-' + mm + '-' + dd
+    },
+    dateBottom() {
+      const yy = this.now.getFullYear()
+      let mm = this.now.getMonth() + 1
+      let dd = this.now.getDate()
+      if (mm <= 9) {
+        mm = '0' + mm
+      }
+      if (dd <= 9) {
+        dd = '0' + dd
+      }
+      return yy + '/' + mm + '/' + dd
+    }
+    // time() {
+    //   let hh = this.now.getHours()
+    //   let mm = this.now.getMinutes()
+    //   let ss = this.now.getSeconds()
+    //   if (hh <= 9) {
+    //     hh = '0' + hh
+    //   }
+    //   if (mm <= 9) {
+    //     mm = '0' + mm
+    //   }
+    //   return hh + ':' + mm
+    // }
+  },
+  methods: {
+    clcikshow() {
+      New.$emit('getisshow', {
+        navshow: false,
+        isCollapse: false
+      })
+    },
+    updateTime() {
+      const date = new Date()
+      const hh = date.getHours()
+      const mm = date.getMinutes()
+      const ss = date.getSeconds()
+      this.time = this.validate(hh, 2) + ':' + this.validate(mm, 2) + ':' + this.validate(ss, 2)
+    },
+    timeSetTime() {
+      this.autoPlayFlag2 = setInterval(() => {
+        this.updateTime()
+      }, 1000)
+    },
+    validate(t, digit) {
+      let zero = ''
+      for (var i = 0; i < digit; i++) {
+        zero += '0'
+      }
+      return (zero + t).slice(-digit)
+    }
+  },
+  mounted() {
+    this.timeSetTime()
+  },
+  destroyed() {
+    clearInterval(this.autoPlayFlag2)
+  }
+}
+</script>
+<style rel="stylesheet/scss" lang="scss" scoped>
+.d5cA {
+  &-header {
+    width: 100%;
+    height: 100px;
+    background-color: #334051;
+  }
+  &-header__wid {
+    width: 94%;
+    margin: 0 auto;
+  }
+  &-logo {
+    position: relative;
+    width: 190px;
+    .el-icon-arrow-right {
+      position: absolute;
+      top: 46px;
+      right: 0;
+      color: #657e9e;
+      font-weight: bold;
+      font-size: 14px;
+    }
+    img {
+      float: left;
+      display: block;
+      margin-top: 15px;
+    }
+  }
+  &-logo__info {
+    float: left;
+    font-size: 12px;
+    color: #657e9e;
+    margin-left: 14px;
+    /*margin-top: 24px;*/
+    h3 {
+      font-size: 24px;
+      color: #fff;
+      line-height: 48px;
+      margin-top: 15px;
+    }
+  }
+  &-clock__pane {
+    width: 138px;
+    height: 72px;
+    background-color: #37475b;
+    border-top-left-radius: 12px;
+    border-bottom-left-radius: 12px;
+    padding: 12px;
+    box-sizing: border-box;
+    font-size: 12px;
+    color: #6c829d;
+    text-align: center;
+    margin-top: 15px;
+  }
+  &-clock__top {
+    font-size: 12px;
+    line-height: 16px;
+    color: #fff;
+    text-align: right;
+    margin-bottom: 8px;
+    img {
+      display: block;
+      float: left;
+      width: 28px;
+      height: 28px;
+    }
+  }
+  &-tab__right {
+    float: right;
+    position: relative;
+    width: 36px;
+    height: 72px;
+    margin-top: 15px;
+    background-color: #37475b;
+    border-left: 1px solid #223040;
+    border-top-right-radius: 12px;
+    border-bottom-right-radius: 12px;
+    .fullPo {
+      margin-top: 8px;
+      margin-left: 8px;
+    }
+  }
+  &-logout__btn {
+    display: block;
+    width: 36px;
+    height: 36px;
+    font-size: 12px;
+    color: #fff;
+    border-bottom: 1px solid #223040;
+
+    img {
+      width: 20px;
+      height: 20px;
+      margin-left: 8px;
+      margin-top: 8px;
+    }
+  }
+}
+</style>

+ 209 - 0
statement-pc/src/components/LeftNav/index.vue

@@ -0,0 +1,209 @@
+<template>
+<div>
+  <div class="d5cA-leftNav" @click="isShow" :style="leftDis" v-if="navshow">
+    <i class="el-icon-caret-right" v-if="!isCollapse"></i>
+    <i class="el-icon-caret-left" v-if="isCollapse"></i>
+  </div>
+
+  <div class="d5cA-menu-wrapper" :class="isCollapse ? 'showNav':''" v-if="navshow">
+    <el-menu default-active="1-4-1" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose" @select="isShow" :collapse="!isCollapse" :router="true" background-color="#334051" text-color="#fff" active-text-color="#508cee">
+      <div v-for="(item,index) in navlist" :key="index">
+        <el-menu-item :index="item.url_path" v-if="!item.secondary_list">
+          <i class="el-icon-location"></i>
+          <span slot="title">{{item.name}}</span>
+        </el-menu-item>
+        <el-submenu :index="item.url_path" v-if="item.secondary_list">
+          <template slot="title">
+            <i class="el-icon-location"></i>
+            <span slot="title">{{item.name}}</span>
+          </template>
+          <el-menu-item-group>
+            <el-menu-item :index="value.url_path" v-if="item.secondary_list" v-for="value in item.secondary_list" :key="value.index">{{value.name}}</el-menu-item>
+            <!-- <el-menu-item index="/investor/project">项目</el-menu-item>
+            <el-menu-item index="/investor/subject">7天体验金</el-menu-item>
+            <el-menu-item index="/investor/newcamp">新手训练营</el-menu-item>
+            <el-menu-item index="/investor/investment">投资训练营</el-menu-item>
+            <el-menu-item index="/investor/transfer">转让成交统计</el-menu-item> -->
+          </el-menu-item-group>
+        </el-submenu>
+      </div>
+      <!-- <el-menu-item index="/dashboard">
+        <i class="el-icon-location"></i>
+        <span slot="title">首页(pc版)</span>
+      </el-menu-item> -->
+      <!-- <el-menu-item index="/fanscount">
+        <i class="el-icon-location"></i>
+        <span slot="title">粉丝</span>
+      </el-menu-item> -->
+      <!-- <el-menu-item index="/registeruser">
+        <i class="el-icon-location"></i>
+        <span slot="title">注册用户</span>
+      </el-menu-item> -->
+      <!-- <el-menu-item index="/recharge">
+        <i class="el-icon-location"></i>
+        <span slot="title">充值情况</span>
+      </el-menu-item> -->
+      <!-- <el-menu-item index="/expense">
+        <i class="el-icon-location"></i>
+        <span slot="title">每月支出</span>
+      </el-menu-item> -->
+      <!-- <el-menu-item index="/custom/service">
+        <i class="el-icon-location"></i>
+        <span slot="title">新增好友</span>
+      </el-menu-item>
+      <el-menu-item index="/article/day">
+        <i class="el-icon-location"></i>
+        <span slot="title">阅读文章</span>
+      </el-menu-item> -->
+
+      <!-- <el-menu-item index="/integral">
+        <i class="el-icon-location"></i>
+        <span slot="title">积分统计</span>
+      </el-menu-item> -->
+      <!-- <el-submenu index="2">
+        <template slot="title">
+          <i class="el-icon-location"></i>
+          <span slot="title">积分&抽奖</span>
+        </template>
+        <el-menu-item-group>
+          <el-menu-item index="/integral">积分统计</el-menu-item>
+          <el-menu-item index="/ten">每日积分</el-menu-item>
+          <el-menu-item index="/lottery">每日抽奖</el-menu-item>
+        </el-menu-item-group>
+      </el-submenu> -->
+      <!-- <el-menu-item index="/rabbit">
+        <i class="el-icon-location"></i>
+        <span slot="title">商家结算</span>
+      </el-menu-item> -->
+      <!-- <el-submenu index="3">
+        <template slot="title">
+          <i class="el-icon-location"></i>
+          <span slot="title">拉比兔模块</span>
+        </template>
+        <el-menu-item-group>
+          <el-menu-item index="/rabbit">商家结算</el-menu-item>
+          <el-menu-item index="/rabbit/r-register">注册</el-menu-item>
+          <el-menu-item index="/rabbit/exchange">萝卜产生</el-menu-item>
+          <el-menu-item index="/rabbit/radish">萝卜消耗</el-menu-item>
+          <el-menu-item index="/rabbit/r-goods">商城销售</el-menu-item>
+          <el-menu-item index="/rabbit/d5c-accounts">第五创商家结算</el-menu-item>
+        </el-menu-item-group>
+      </el-submenu> -->
+      <!-- <el-menu-item index="/aftermelting">
+        <i class="el-icon-location"></i>
+        <span slot="title">融后评价</span>
+      </el-menu-item> -->
+      <!-- <el-menu-item index="/audit/data">
+        <i class="el-icon-location"></i>
+        <span slot="title">审计组报表</span>
+      </el-menu-item> -->
+    </el-menu>
+  </div>
+</div>
+</template>
+<script>
+
+// import { mapGetters } from 'vuex'
+import request from '@/utils/request'
+import { getToken } from '@/utils/auth'
+import New from '@/leftnav.js'
+export default {
+  name: 'leftNav',
+  data() {
+    return {
+      isCollapse: false,
+      navlist: '',
+      navshow: false
+    }
+  },
+  created() {
+    if (getToken()) {
+      this.getPermisson()
+    }
+    New.$on('getisshow', data => {
+      this.navlist = data.navlist
+      this.navshow = data.navshow
+      this.isCollapse = data.isCollapse
+    })
+  },
+  computed: {
+    // ...mapGetters(['userLoginState'])
+    leftDis() {
+      if (this.isCollapse) {
+        return 'left: 200px;'
+      } else {
+        return 'left: 0;'
+      }
+    }
+  },
+  methods: {
+    handleOpen(key, keyPath) {
+      console.log(key, keyPath)
+    },
+    handleClose(key, keyPath) {
+      console.log(key, keyPath)
+    },
+    isShow() {
+      this.isCollapse = !this.isCollapse
+    },
+    getPermisson() {
+      request({
+        url: '/v1/user/getPermission',
+        methods: 'get',
+        params: {
+        }
+      }).then(response => {
+        console.log(response.data)
+        this.navlist = response.data.permission_list
+        this.navshow = true
+      }).catch(error => {
+        console.log(error)
+      })
+    }
+  }
+}
+</script>
+<style rel="stylesheet/scss" lang="scss" scoped>
+.el-menu-vertical-demo:not(.el-menu--collapse) {
+  /*position: fixed;
+  top: 0;*/
+  width: 200px;
+  min-height: 100%;
+}
+.d5cA {
+  &-leftNav {
+    position: fixed;
+    top: 50%;
+    width: 16px;
+    height: 66px;
+    background-color: #37475b;
+    color: #fff;
+    font-size: 12px;
+    margin-top: -33px;
+    border-radius: 0px 6px 6px 0px;
+    transition: all 0.6s ease;
+    z-index: 3000;
+    i {
+      margin-top: 27px;
+    }
+  }
+  &-menu-wrapper {
+    position: fixed;
+    top: 0;
+    left: -200px;
+    bottom: 0;
+    width: 200px;
+    height: 100%;
+    background-color: rgb(48, 65, 86);
+    color: #fff;
+    transition: all 0.6s ease;
+    z-index: 3000;
+    &.showNav {
+      left: 0;
+    }
+    .el-menu {
+      border-right-color: #223040; 
+    }
+  }
+}
+</style>

+ 32 - 0
statement-pc/src/components/Loading/index.vue

@@ -0,0 +1,32 @@
+<template>
+  <div class="d5cA-loading">
+    <i class="el-icon-loading" style="font-size: 60px;color: #00a8ff;"></i>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'loading',
+  data() {
+    return {
+    }
+  },
+  methods: {
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.d5cA {
+  &-loading {
+    width: 100%;
+    height: 270px;
+    padding-top: 105px;
+    box-sizing: border-box;
+    .el-icon-loading {
+      text-align: center;
+      display: block;
+    }
+  }
+}
+</style>

+ 65 - 0
statement-pc/src/components/Screenfull/index.vue

@@ -0,0 +1,65 @@
+<template>
+  <div>
+    <svg t="1508738709248" @click='click' class="screenfull-svg" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
+      p-id="2069" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32">
+      <path d="M333.493443 428.647617 428.322206 333.832158 262.572184 168.045297 366.707916 64.444754 64.09683 64.444754 63.853283 366.570793 167.283957 262.460644Z"
+        p-id="2070"></path>
+      <path d="M854.845439 760.133334 688.61037 593.95864 593.805144 688.764889 759.554142 854.56096 655.44604 958.161503 958.055079 958.161503 958.274066 656.035464Z"
+        p-id="2071"></path>
+      <path d="M688.535669 428.550403 854.31025 262.801405 957.935352 366.921787 957.935352 64.34754 655.809313 64.081481 759.919463 167.535691 593.70793 333.731874Z"
+        p-id="2072"></path>
+      <path d="M333.590658 594.033341 167.8171 759.804852 64.218604 655.67219 64.218604 958.270996 366.342596 958.502263 262.234493 855.071589 428.421466 688.86108Z"
+        p-id="2073"></path>
+    </svg>
+  </div>
+</template>
+
+<script>
+import screenfull from 'screenfull'
+
+export default {
+  name: 'screenfull',
+  props: {
+    width: {
+      type: Number,
+      default: 22
+    },
+    height: {
+      type: Number,
+      default: 22
+    },
+    fill: {
+      type: String,
+      default: '#48576a'
+    }
+  },
+  data() {
+    return {
+      isFullscreen: false
+    }
+  },
+  methods: {
+    click() {
+      if (!screenfull.enabled) {
+        this.$message({
+          message: 'you browser can not work',
+          type: 'warning'
+        })
+        return false
+      }
+      screenfull.toggle()
+    }
+  }
+}
+</script>
+
+<style scoped>
+.screenfull-svg {
+  display: inline-block;
+  cursor: pointer;
+  fill: #4f6787;;
+  width: 20px;
+  height: 20px;
+  vertical-align: 10px;
+}
+</style>

+ 57 - 0
statement-pc/src/components/ScrollBar/index.vue

@@ -0,0 +1,57 @@
+<template>
+  <div class="scroll-container" ref="scrollContainer" @wheel.prevent="handleScroll" >
+    <div class="scroll-wrapper" ref="scrollWrapper" :style="{top: top + 'px'}">
+      <slot></slot>
+    </div>
+  </div>
+</template>
+
+<script>
+const delta = 15
+
+export default {
+  name: 'scrollBar',
+  data() {
+    return {
+      top: 0
+    }
+  },
+  methods: {
+    handleScroll(e) {
+      const eventDelta = e.wheelDelta || -e.deltaY * 3
+      const $container = this.$refs.scrollContainer
+      const $containerHeight = $container.offsetHeight
+      const $wrapper = this.$refs.scrollWrapper
+      const $wrapperHeight = $wrapper.offsetHeight
+      if (eventDelta > 0) {
+        this.top = Math.min(0, this.top + eventDelta)
+      } else {
+        if ($containerHeight - delta < $wrapperHeight) {
+          if (this.top < -($wrapperHeight - $containerHeight + delta)) {
+            this.top = this.top
+          } else {
+            this.top = Math.max(this.top + eventDelta, $containerHeight - $wrapperHeight - delta)
+          }
+        } else {
+          this.top = 0
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+@import '../../styles/variables.scss';
+
+.scroll-container {
+  position: relative;
+  width: 100%;
+  height: 100%;
+  background-color: $menuBg;
+  .scroll-wrapper {
+    position: absolute;
+     width: 100%!important;
+  }
+}
+</style>

+ 72 - 0
statement-pc/src/components/ScrollPane/index.vue

@@ -0,0 +1,72 @@
+<template>
+  <div class="scroll-container" ref="scrollContainer" @wheel.prevent="handleScroll">
+    <div class="scroll-wrapper" ref="scrollWrapper" :style="{left: left + 'px'}">
+      <slot></slot>
+    </div>
+  </div>
+</template>
+
+<script>
+const padding = 15 // tag's padding
+
+export default {
+  name: 'scrollPane',
+  data() {
+    return {
+      left: 0
+    }
+  },
+  methods: {
+    handleScroll(e) {
+      const eventDelta = e.wheelDelta || -e.deltaY * 3
+      const $container = this.$refs.scrollContainer
+      const $containerWidth = $container.offsetWidth
+      const $wrapper = this.$refs.scrollWrapper
+      const $wrapperWidth = $wrapper.offsetWidth
+
+      if (eventDelta > 0) {
+        this.left = Math.min(0, this.left + eventDelta)
+      } else {
+        if ($containerWidth - padding < $wrapperWidth) {
+          if (this.left < -($wrapperWidth - $containerWidth + padding)) {
+            this.left = this.left
+          } else {
+            this.left = Math.max(this.left + eventDelta, $containerWidth - $wrapperWidth - padding)
+          }
+        } else {
+          this.left = 0
+        }
+      }
+    },
+    moveToTarget($target) {
+      const $container = this.$refs.scrollContainer
+      const $containerWidth = $container.offsetWidth
+      const $targetLeft = $target.offsetLeft
+      const $targetWidth = $target.offsetWidth
+
+      if ($targetLeft < -this.left) {
+        // tag in the left
+        this.left = -$targetLeft + padding
+      } else if ($targetLeft + padding > -this.left && $targetLeft + $targetWidth < -this.left + $containerWidth - padding) {
+        // tag in the current view
+        // eslint-disable-line
+      } else {
+        // tag in the right
+        this.left = -($targetLeft - ($containerWidth - $targetWidth) + padding)
+      }
+    }
+  }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+.scroll-container {
+  white-space: nowrap;
+  position: relative;
+  overflow: hidden;
+  width: 100%;
+  .scroll-wrapper {
+    position: absolute;
+  }
+}
+</style>

+ 42 - 0
statement-pc/src/components/SvgIcon/index.vue

@@ -0,0 +1,42 @@
+<template>
+  <svg :class="svgClass" aria-hidden="true">
+    <use :xlink:href="iconName"></use>
+  </svg>
+</template>
+
+<script>
+export default {
+  name: 'svg-icon',
+  props: {
+    iconClass: {
+      type: String,
+      required: true
+    },
+    className: {
+      type: String
+    }
+  },
+  computed: {
+    iconName() {
+      return `#icon-${this.iconClass}`
+    },
+    svgClass() {
+      if (this.className) {
+        return 'svg-icon ' + this.className
+      } else {
+        return 'svg-icon'
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.svg-icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+</style>

+ 49 - 0
statement-pc/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 shold 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
statement-pc/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

+ 91 - 0
statement-pc/src/directive/sticky.js

@@ -0,0 +1,91 @@
+const vueSticky = {}
+let listenAction
+vueSticky.install = Vue => {
+  Vue.directive('sticky', {
+    inserted(el, binding) {
+      const params = binding.value || {}
+      const stickyTop = params.stickyTop || 0
+      const zIndex = params.zIndex || 1000
+      const elStyle = el.style
+
+      elStyle.position = '-webkit-sticky'
+      elStyle.position = 'sticky'
+      // if the browser support css sticky(Currently Safari, Firefox and Chrome Canary)
+      // if (~elStyle.position.indexOf('sticky')) {
+      //     elStyle.top = `${stickyTop}px`;
+      //     elStyle.zIndex = zIndex;
+      //     return
+      // }
+      const elHeight = el.getBoundingClientRect().height
+      const elWidth = el.getBoundingClientRect().width
+      elStyle.cssText = `top: ${stickyTop}px; z-index: ${zIndex}`
+
+      const parentElm = el.parentNode || document.documentElement
+      const placeholder = document.createElement('div')
+      placeholder.style.display = 'none'
+      placeholder.style.width = `${elWidth}px`
+      placeholder.style.height = `${elHeight}px`
+      parentElm.insertBefore(placeholder, el)
+
+      let active = false
+
+      const getScroll = (target, top) => {
+        const prop = top ? 'pageYOffset' : 'pageXOffset'
+        const method = top ? 'scrollTop' : 'scrollLeft'
+        let ret = target[prop]
+        if (typeof ret !== 'number') {
+          ret = window.document.documentElement[method]
+        }
+        return ret
+      }
+
+      const sticky = () => {
+        if (active) {
+          return
+        }
+        if (!elStyle.height) {
+          elStyle.height = `${el.offsetHeight}px`
+        }
+
+        elStyle.position = 'fixed'
+        elStyle.width = `${elWidth}px`
+        placeholder.style.display = 'inline-block'
+        active = true
+      }
+
+      const reset = () => {
+        if (!active) {
+          return
+        }
+
+        elStyle.position = ''
+        placeholder.style.display = 'none'
+        active = false
+      }
+
+      const check = () => {
+        const scrollTop = getScroll(window, true)
+        const offsetTop = el.getBoundingClientRect().top
+        if (offsetTop < stickyTop) {
+          sticky()
+        } else {
+          if (scrollTop < elHeight + stickyTop) {
+            reset()
+          }
+        }
+      }
+      listenAction = () => {
+        check()
+      }
+
+      window.addEventListener('scroll', listenAction)
+    },
+
+    unbind() {
+      window.removeEventListener('scroll', listenAction)
+    }
+  })
+}
+
+export default vueSticky
+

+ 13 - 0
statement-pc/src/directive/waves/index.js

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

+ 26 - 0
statement-pc/src/directive/waves/waves.css

@@ -0,0 +1,26 @@
+.waves-ripple {
+    position: absolute;
+    border-radius: 100%;
+    background-color: rgba(0, 0, 0, 0.15);
+    background-clip: padding-box;
+    pointer-events: none;
+    -webkit-user-select: none;
+    -moz-user-select: none;
+    -ms-user-select: none;
+    user-select: none;
+    -webkit-transform: scale(0);
+    -ms-transform: scale(0);
+    transform: scale(0);
+    opacity: 1;
+}
+
+.waves-ripple.z-active {
+    opacity: 0;
+    -webkit-transform: scale(2);
+    -ms-transform: scale(2);
+    transform: scale(2);
+    -webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
+    transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
+    transition: opacity 1.2s ease-out, transform 0.6s ease-out;
+    transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out;
+}

+ 42 - 0
statement-pc/src/directive/waves/waves.js

@@ -0,0 +1,42 @@
+import './waves.css'
+
+export default{
+  bind(el, binding) {
+    el.addEventListener('click', e => {
+      const customOpts = Object.assign({}, binding.value)
+      const opts = Object.assign({
+        ele: el, // 波纹作用元素
+        type: 'hit', // hit点击位置扩散center中心点扩展
+        color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
+      }, customOpts)
+      const target = opts.ele
+      if (target) {
+        target.style.position = 'relative'
+        target.style.overflow = 'hidden'
+        const rect = target.getBoundingClientRect()
+        let ripple = target.querySelector('.waves-ripple')
+        if (!ripple) {
+          ripple = document.createElement('span')
+          ripple.className = 'waves-ripple'
+          ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px'
+          target.appendChild(ripple)
+        } else {
+          ripple.className = 'waves-ripple'
+        }
+        switch (opts.type) {
+          case 'center':
+            ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px'
+            ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px'
+            break
+          default:
+            ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.body.scrollTop) + 'px'
+            ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.body.scrollLeft) + 'px'
+        }
+        ripple.style.backgroundColor = opts.color
+        ripple.className = 'waves-ripple z-active'
+        return false
+      }
+    }, false)
+  }
+}
+

+ 21 - 0
statement-pc/src/errorLog.js

@@ -0,0 +1,21 @@
+import Vue from 'vue'
+import store from './store'
+
+// you can set only in production env show the error-log
+// if (process.env.NODE_ENV === 'production') {
+
+Vue.config.errorHandler = function(err, vm, info, a) {
+  // Don't ask me why I use Vue.nextTick, it just a hack.
+  // detail see https://forum.vuejs.org/t/dispatch-in-vue-config-errorhandler-has-some-problem/23500
+  Vue.nextTick(() => {
+    store.dispatch('addErrorLog', {
+      err,
+      vm,
+      info,
+      url: window.location.href
+    })
+    console.error(err, info)
+  })
+}
+
+// }

+ 121 - 0
statement-pc/src/filters/index.js

@@ -0,0 +1,121 @@
+function pluralize(time, label) {
+  if (time === 1) {
+    return time + label
+  }
+  return time + label + 's'
+}
+
+export function timeAgo(time) {
+  const between = Date.now() / 1000 - Number(time)
+  if (between < 3600) {
+    return pluralize(~~(between / 60), ' minute')
+  } else if (between < 86400) {
+    return pluralize(~~(between / 3600), ' hour')
+  } else {
+    return pluralize(~~(between / 86400), ' day')
+  }
+}
+
+export function parseTime(time, cFormat) {
+  if (arguments.length === 0) {
+    return null
+  }
+
+  if ((time + '').length === 10) {
+    time = +time * 1000
+  }
+
+  const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
+  let date
+  if (typeof time === 'object') {
+    date = time
+  } else {
+    date = new Date(parseInt(time))
+  }
+  const formatObj = {
+    y: date.getFullYear(),
+    m: date.getMonth() + 1,
+    d: date.getDate(),
+    h: date.getHours(),
+    i: date.getMinutes(),
+    s: date.getSeconds(),
+    a: date.getDay()
+  }
+  const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
+    let value = formatObj[key]
+    if (key === 'a') return ['一', '二', '三', '四', '五', '六', '日'][value - 1]
+    if (result.length > 0 && value < 10) {
+      value = '0' + value
+    }
+    return value || 0
+  })
+  return time_str
+}
+
+export function formatTime(time, option) {
+  time = +time * 1000
+  const d = new Date(time)
+  const now = Date.now()
+
+  const diff = (now - d) / 1000
+
+  if (diff < 30) {
+    return '刚刚'
+  } else if (diff < 3600) { // less 1 hour
+    return Math.ceil(diff / 60) + '分钟前'
+  } else if (diff < 3600 * 24) {
+    return Math.ceil(diff / 3600) + '小时前'
+  } else if (diff < 3600 * 24 * 2) {
+    return '1天前'
+  }
+  if (option) {
+    return parseTime(time, option)
+  } else {
+    return d.getMonth() + 1 + '月' + d.getDate() + '日' + d.getHours() + '时' + d.getMinutes() + '分'
+  }
+}
+
+/* 数字 格式化*/
+export function nFormatter(num, digits) {
+  const si = [
+    { value: 1E18, symbol: 'E' },
+    { value: 1E15, symbol: 'P' },
+    { value: 1E12, symbol: 'T' },
+    { value: 1E9, symbol: 'G' },
+    { value: 1E6, symbol: 'M' },
+    { value: 1E3, symbol: 'k' }
+  ]
+  for (let i = 0; i < si.length; i++) {
+    if (num >= si[i].value) {
+      return (num / si[i].value + 0.1).toFixed(digits).replace(/\.0+$|(\.[0-9]*[1-9])0+$/, '$1') + si[i].symbol
+    }
+  }
+  return num.toString()
+}
+
+export function html2Text(val) {
+  const div = document.createElement('div')
+  div.innerHTML = val
+  return div.textContent || div.innerText
+}
+
+export function toThousandslsFilter(num) {
+  return (+num || 0).toString().replace(/^-?\d+/g, m => m.replace(/(?=(?!\b)(\d{3})+$)/g, ','))
+}
+
+export function formatNewTime(value) {
+  const date = new Date(value * 1000)
+  const year = date.getFullYear()
+  const month = date.getMonth() + 1
+  const day = date.getDate()
+
+  const hour = date.getHours()
+  const minute = date.getMinutes()
+
+  return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute].map(formatNumber).join(':')
+}
+
+const formatNumber = function(n) {
+  n = n.toString()
+  return n[1] ? n : '0' + n
+}

+ 12 - 0
statement-pc/src/icons/index.js

@@ -0,0 +1,12 @@
+import Vue from 'vue'
+import SvgIcon from '@/components/SvgIcon'// svg组件
+import generateIconsView from '@/views/svg-icons/generateIconsView.js'// just for @/views/icons , you can delete it
+
+// register globally
+Vue.component('svg-icon', SvgIcon)
+
+const requireAll = requireContext => requireContext.keys().map(requireContext)
+const req = require.context('./svg', false, /\.svg$/)
+const iconMap = requireAll(req)
+
+generateIconsView.generate(iconMap) // just for @/views/icons , you can delete it

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/404.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/bug.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/chart.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/clipboard.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/component.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/dashboard.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/documentation.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/drag.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/email.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/example.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/excel.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/eye.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/form.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/icon.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/international.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/language.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/lock.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/message.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/money.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/password.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/people.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/peoples.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/qq.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/shoppingCard.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/star.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/tab.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/table.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/theme.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/user.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/wechat.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 0
statement-pc/src/icons/svg/zip.svg


+ 2 - 0
statement-pc/src/leftnav.js

@@ -0,0 +1,2 @@
+import Vue from 'vue'
+export default new Vue()

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 27 - 0
statement-pc/src/libs/china.js


+ 192 - 0
statement-pc/src/libs/mapdata.js

@@ -0,0 +1,192 @@
+module.exports = {
+  '海门': [121.15, 31.89],
+  '鄂尔多斯': [109.781327, 39.608266],
+  '招远': [120.38, 37.35],
+  '舟山': [122.207216, 29.985295],
+  '齐齐哈尔': [123.97, 47.33],
+  '盐城': [120.13, 33.38],
+  '赤峰': [118.87, 42.28],
+  '青岛': [120.33, 36.07],
+  '乳山': [121.52, 36.89],
+  '金昌': [102.188043, 38.520089],
+  '泉州': [118.58, 24.93],
+  '莱西': [120.53, 36.86],
+  '日照': [119.46, 35.42],
+  '胶南': [119.97, 35.88],
+  '南通': [121.05, 32.08],
+  '拉萨': [91.11, 29.97],
+  '云浮': [112.02, 22.93],
+  '梅州': [116.1, 24.55],
+  '文登': [122.05, 37.2],
+  '上海': [121.48, 31.22],
+  '攀枝花': [101.718637, 26.582347],
+  '威海': [122.1, 37.5],
+  '承德': [117.93, 40.97],
+  '厦门': [118.1, 24.46],
+  '汕尾': [115.375279, 22.786211],
+  '潮州': [116.63, 23.68],
+  '丹东': [124.37, 40.13],
+  '太仓': [121.1, 31.45],
+  '曲靖': [103.79, 25.51],
+  '烟台': [121.39, 37.52],
+  '福州': [119.3, 26.08],
+  '瓦房店': [121.979603, 39.627114],
+  '即墨': [120.45, 36.38],
+  '抚顺': [123.97, 41.97],
+  '玉溪': [102.52, 24.35],
+  '张家口': [114.87, 40.82],
+  '阳泉': [113.57, 37.85],
+  '莱州': [119.942327, 37.177017],
+  '湖州': [120.1, 30.86],
+  '汕头': [116.69, 23.39],
+  '昆山': [120.95, 31.39],
+  '宁波': [121.56, 29.86],
+  '湛江': [110.359377, 21.270708],
+  '揭阳': [116.35, 23.55],
+  '荣成': [122.41, 37.16],
+  '连云港': [119.16, 34.59],
+  '葫芦岛': [120.836932, 40.711052],
+  '常熟': [120.74, 31.64],
+  '东莞': [113.75, 23.04],
+  '河源': [114.68, 23.73],
+  '淮安': [119.15, 33.5],
+  '泰州': [119.9, 32.49],
+  '南宁': [108.33, 22.84],
+  '营口': [122.18, 40.65],
+  '惠州': [114.4, 23.09],
+  '江阴': [120.26, 31.91],
+  '蓬莱': [120.75, 37.8],
+  '韶关': [113.62, 24.84],
+  '嘉峪关': [98.289152, 39.77313],
+  '广州': [113.23, 23.16],
+  '延安': [109.47, 36.6],
+  '太原': [112.53, 37.87],
+  '清远': [113.01, 23.7],
+  '中山': [113.38, 22.52],
+  '昆明': [102.73, 25.04],
+  '寿光': [118.73, 36.86],
+  '盘锦': [122.070714, 41.119997],
+  '长治': [113.08, 36.18],
+  '深圳': [114.07, 22.62],
+  '珠海': [113.52, 22.3],
+  '宿迁': [118.3, 33.96],
+  '咸阳': [108.72, 34.36],
+  '铜川': [109.11, 35.09],
+  '平度': [119.97, 36.77],
+  '佛山': [113.11, 23.05],
+  '海口': [110.35, 20.02],
+  '江门': [113.06, 22.61],
+  '章丘': [117.53, 36.72],
+  '肇庆': [112.44, 23.05],
+  '大连': [121.62, 38.92],
+  '临汾': [111.5, 36.08],
+  '吴江': [120.63, 31.16],
+  '石嘴山': [106.39, 39.04],
+  '沈阳': [123.38, 41.8],
+  '苏州': [120.62, 31.32],
+  '茂名': [110.88, 21.68],
+  '嘉兴': [120.76, 30.77],
+  '长春': [125.35, 43.88],
+  '胶州': [120.03336, 36.264622],
+  '银川': [106.27, 38.47],
+  '张家港': [120.555821, 31.875428],
+  '三门峡': [111.19, 34.76],
+  '锦州': [121.15, 41.13],
+  '南昌': [115.89, 28.68],
+  '柳州': [109.4, 24.33],
+  '三亚': [109.511909, 18.252847],
+  '自贡': [104.778442, 29.33903],
+  '吉林': [126.57, 43.87],
+  '阳江': [111.95, 21.85],
+  '泸州': [105.39, 28.91],
+  '西宁': [101.74, 36.56],
+  '宜宾': [104.56, 29.77],
+  '呼和浩特': [111.65, 40.82],
+  '成都': [104.06, 30.67],
+  '大同': [113.3, 40.12],
+  '镇江': [119.44, 32.2],
+  '桂林': [110.28, 25.29],
+  '张家界': [110.479191, 29.117096],
+  '宜兴': [119.82, 31.36],
+  '北海': [109.12, 21.49],
+  '西安': [108.95, 34.27],
+  '金坛': [119.56, 31.74],
+  '东营': [118.49, 37.46],
+  '牡丹江': [129.58, 44.6],
+  '遵义': [106.9, 27.7],
+  '绍兴': [120.58, 30.01],
+  '扬州': [119.42, 32.39],
+  '常州': [119.95, 31.79],
+  '潍坊': [119.1, 36.62],
+  '重庆': [106.54, 29.59],
+  '台州': [121.420757, 28.656386],
+  '南京': [118.78, 32.04],
+  '滨州': [118.03, 37.36],
+  '贵阳': [106.71, 26.57],
+  '无锡': [120.29, 31.59],
+  '本溪': [123.73, 41.3],
+  '克拉玛依': [84.77, 45.59],
+  '渭南': [109.5, 34.52],
+  '马鞍山': [118.48, 31.56],
+  '宝鸡': [107.15, 34.38],
+  '焦作': [113.21, 35.24],
+  '句容': [119.16, 31.95],
+  '北京': [116.46, 39.92],
+  '徐州': [117.2, 34.26],
+  '衡水': [115.72, 37.72],
+  '包头': [110, 40.58],
+  '绵阳': [104.73, 31.48],
+  '乌鲁木齐': [87.68, 43.77],
+  '枣庄': [117.57, 34.86],
+  '杭州': [120.19, 30.26],
+  '淄博': [118.05, 36.78],
+  '鞍山': [122.85, 41.12],
+  '溧阳': [119.48, 31.43],
+  '库尔勒': [86.06, 41.68],
+  '安阳': [114.35, 36.1],
+  '开封': [114.35, 34.79],
+  '济南': [117, 36.65],
+  '德阳': [104.37, 31.13],
+  '温州': [120.65, 28.01],
+  '九江': [115.97, 29.71],
+  '邯郸': [114.47, 36.6],
+  '临安': [119.72, 30.23],
+  '兰州': [103.73, 36.03],
+  '沧州': [116.83, 38.33],
+  '临沂': [118.35, 35.05],
+  '南充': [106.110698, 30.837793],
+  '天津': [117.2, 39.13],
+  '富阳': [119.95, 30.07],
+  '泰安': [117.13, 36.18],
+  '诸暨': [120.23, 29.71],
+  '郑州': [113.65, 34.76],
+  '哈尔滨': [126.63, 45.75],
+  '聊城': [115.97, 36.45],
+  '芜湖': [118.38, 31.33],
+  '唐山': [118.02, 39.63],
+  '平顶山': [113.29, 33.75],
+  '邢台': [114.48, 37.05],
+  '德州': [116.29, 37.45],
+  '济宁': [116.59, 35.38],
+  '荆州': [112.239741, 30.335165],
+  '宜昌': [111.3, 30.7],
+  '义乌': [120.06, 29.32],
+  '丽水': [119.92, 28.45],
+  '洛阳': [112.44, 34.7],
+  '秦皇岛': [119.57, 39.95],
+  '株洲': [113.16, 27.83],
+  '石家庄': [114.48, 38.03],
+  '莱芜': [117.67, 36.19],
+  '常德': [111.69, 29.05],
+  '保定': [115.48, 38.85],
+  '湘潭': [112.91, 27.87],
+  '金华': [119.64, 29.12],
+  '岳阳': [113.09, 29.37],
+  '长沙': [113, 28.21],
+  '衢州': [118.88, 28.97],
+  '廊坊': [116.7, 39.53],
+  '菏泽': [115.480656, 35.23375],
+  '合肥': [117.27, 31.86],
+  '武汉': [114.31, 30.52],
+  '大庆': [125.03, 46.58]
+}

+ 33 - 0
statement-pc/src/main.js

@@ -0,0 +1,33 @@
+import Vue from 'vue'
+
+import 'normalize.css/normalize.css'// A modern alternative to CSS resets
+
+import Element from 'element-ui'
+import 'element-ui/lib/theme-chalk/index.css'
+
+import '@/styles/index.scss' // global css
+
+import App from './App'
+import router from './router'
+import store from './store'
+
+import './icons'
+
+import * as filters from './filters' // global filters
+
+Vue.use(Element)
+
+// register global utility filters.
+Object.keys(filters).forEach(key => {
+  Vue.filter(key, filters[key])
+})
+
+Vue.config.productionTip = false
+
+new Vue({
+  el: '#app',
+  router,
+  store,
+  template: '<App/>',
+  components: { App }
+})

+ 70 - 0
statement-pc/src/mock/article.js

@@ -0,0 +1,70 @@
+import Mock from 'mockjs'
+import { param2Obj } from '@/utils'
+
+const List = []
+const count = 100
+
+for (let i = 0; i < count; i++) {
+  List.push(Mock.mock({
+    id: '@increment',
+    timestamp: +Mock.Random.date('T'),
+    author: '@first',
+    reviewer: '@first',
+    title: '@title(5, 10)',
+    forecast: '@float(0, 100, 2, 2)',
+    importance: '@integer(1, 3)',
+    'type|1': ['CN', 'US', 'JP', 'EU'],
+    'status|1': ['published', 'draft', 'deleted'],
+    display_time: '@datetime',
+    pageviews: '@integer(300, 5000)'
+  }))
+}
+
+export default {
+  getList: config => {
+    const { importance, type, title, page = 1, limit = 20, sort } = param2Obj(config.url)
+
+    let mockList = List.filter(item => {
+      if (importance && item.importance !== +importance) return false
+      if (type && item.type !== type) return false
+      if (title && item.title.indexOf(title) < 0) return false
+      return true
+    })
+
+    if (sort === '-id') {
+      mockList = mockList.reverse()
+    }
+
+    const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1))
+
+    return {
+      total: mockList.length,
+      items: pageList
+    }
+  },
+  getPv: () => ({
+    pvData: [{ key: 'PC', pv: 1024 }, { key: 'mobile', pv: 1024 }, { key: 'ios', pv: 1024 }, { key: 'android', pv: 1024 }]
+  }),
+  getArticle: () => ({
+    id: 120000000001,
+    author: { key: 'mockPan' },
+    source_name: '原创作者',
+    category_item: [{ key: 'global', name: '全球' }],
+    comment_disabled: true,
+    content: '<p>我是测试数据我是测试数据</p><p><img class="wscnph" src="https://wpimg.wallstcn.com/4c69009c-0fd4-4153-b112-6cb53d1cf943" data-wscntype="image" data-wscnh="300" data-wscnw="400" data-mce-src="https://wpimg.wallstcn.com/4c69009c-0fd4-4153-b112-6cb53d1cf943"></p>"',
+    content_short: '我是测试数据',
+    display_time: +new Date(),
+    image_uri: 'https://wpimg.wallstcn.com/e4558086-631c-425c-9430-56ffb46e70b3',
+    platforms: ['a-platform'],
+    source_uri: 'https://github.com/PanJiaChen/vue-element-admin',
+    status: 'published',
+    tags: [],
+    title: 'vue-element-admin'
+  }),
+  createArticle: () => ({
+    data: 'success'
+  }),
+  updateArticle: () => ({
+    data: 'success'
+  })
+}

+ 29 - 0
statement-pc/src/mock/index.js

@@ -0,0 +1,29 @@
+import Mock from 'mockjs'
+import loginAPI from './login'
+import articleAPI from './article'
+import remoteSearchAPI from './remoteSearch'
+import transactionAPI from './transaction'
+
+// Mock.setup({
+//   timeout: '350-600'
+// })
+
+// 登录相关
+Mock.mock(/\/login\/login/, 'post', loginAPI.loginByUsername)
+Mock.mock(/\/login\/logout/, 'post', loginAPI.logout)
+Mock.mock(/\/user\/info\.*/, 'get', loginAPI.getUserInfo)
+
+// 文章相关
+Mock.mock(/\/article\/list/, 'get', articleAPI.getList)
+Mock.mock(/\/article\/detail/, 'get', articleAPI.getArticle)
+Mock.mock(/\/article\/pv/, 'get', articleAPI.getPv)
+Mock.mock(/\/article\/create/, 'post', articleAPI.createArticle)
+Mock.mock(/\/article\/update/, 'post', articleAPI.updateArticle)
+
+// 搜索相关
+Mock.mock(/\/search\/user/, 'get', remoteSearchAPI.searchUser)
+
+// 账单相关
+Mock.mock(/\/transaction\/list/, 'get', transactionAPI.getList)
+
+export default Mock

+ 34 - 0
statement-pc/src/mock/login.js

@@ -0,0 +1,34 @@
+import { param2Obj } from '@/utils'
+
+const userMap = {
+  admin: {
+    roles: ['admin'],
+    token: 'admin',
+    introduction: '我是超级管理员',
+    avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
+    name: 'Super Admin'
+  },
+  editor: {
+    roles: ['editor'],
+    token: 'editor',
+    introduction: '我是编辑',
+    avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
+    name: 'Normal Editor'
+  }
+}
+
+export default {
+  loginByUsername: config => {
+    const { username } = JSON.parse(config.body)
+    return userMap[username]
+  },
+  getUserInfo: config => {
+    const { token } = param2Obj(config.url)
+    if (userMap[token]) {
+      return userMap[token]
+    } else {
+      return false
+    }
+  },
+  logout: () => 'success'
+}

+ 24 - 0
statement-pc/src/mock/remoteSearch.js

@@ -0,0 +1,24 @@
+import Mock from 'mockjs'
+import { param2Obj } from '@/utils'
+
+const NameList = []
+const count = 100
+
+for (let i = 0; i < count; i++) {
+  NameList.push(Mock.mock({
+    name: '@first'
+  }))
+}
+NameList.push({ name: 'mockPan' })
+
+export default {
+  searchUser: config => {
+    const { name } = param2Obj(config.url)
+    const mockNameList = NameList.filter(item => {
+      const lowerCaseName = item.name.toLowerCase()
+      if (name && lowerCaseName.indexOf(name.toLowerCase()) < 0) return false
+      return true
+    })
+    return { items: mockNameList }
+  }
+}

+ 23 - 0
statement-pc/src/mock/transaction.js

@@ -0,0 +1,23 @@
+import Mock from 'mockjs'
+
+const List = []
+const count = 20
+
+for (let i = 0; i < count; i++) {
+  List.push(Mock.mock({
+    order_no: '@guid()',
+    timestamp: +Mock.Random.date('T'),
+    username: '@name()',
+    price: '@float(1000, 15000, 0, 2)',
+    'status|1': ['success', 'pending']
+  }))
+}
+
+export default {
+  getList: () => {
+    return {
+      total: List.length,
+      items: List
+    }
+  }
+}

+ 63 - 0
statement-pc/src/permission.js

@@ -0,0 +1,63 @@
+import router from './router'
+import store from './store'
+import { Message } from 'element-ui'
+import NProgress from 'nprogress' // progress bar
+import 'nprogress/nprogress.css'// progress bar style
+import { getToken } from '@/utils/auth' // getToken from cookie
+
+NProgress.configure({ showSpinner: false })// NProgress Configuration
+
+// permissiom judge function
+function hasPermission(roles, permissionRoles) {
+  if (roles.indexOf('admin') >= 0) return true // admin permission passed directly
+  if (!permissionRoles) return true
+  return roles.some(role => permissionRoles.indexOf(role) >= 0)
+}
+
+const whiteList = ['/login', '/authredirect']// no redirect whitelist
+
+router.beforeEach((to, from, next) => {
+  NProgress.start() // start progress bar
+  if (getToken()) { // determine if there has token
+    /* has token*/
+    if (to.path === '/login') {
+      next({ path: '/' })
+      NProgress.done() // if current page is dashboard will not trigger	afterEach hook, so manually handle it
+    } else {
+      if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
+        store.dispatch('GetUserInfo').then(res => { // 拉取user_info
+          const roles = res.data.roles // note: roles must be a array! such as: ['editor','develop']
+          store.dispatch('GenerateRoutes', { roles }).then(() => { // 根据roles权限生成可访问的路由表
+            router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
+            next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
+          })
+        }).catch(() => {
+          store.dispatch('FedLogOut').then(() => {
+            Message.error('Verification failed, please login again')
+            next({ path: '/login' })
+          })
+        })
+      } else {
+        // 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
+        if (hasPermission(store.getters.roles, to.meta.roles)) {
+          next()//
+        } else {
+          next({ path: '/401', replace: true, query: { noGoBack: true }})
+        }
+        // 可删 ↑
+      }
+    }
+  } else {
+    /* has no token*/
+    if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
+      next()
+    } else {
+      next('/login') // 否则全部重定向到登录页
+      NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
+    }
+  }
+})
+
+router.afterEach(() => {
+  NProgress.done() // finish progress bar
+})

+ 1 - 0
statement-pc/src/router/_import_development.js

@@ -0,0 +1 @@
+module.exports = file => require('@/views/' + file + '.vue').default // vue-loader at least v13.0.0+

+ 0 - 0
statement-pc/src/router/_import_production.js


Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů