├── .gitignore ├── img ├── 1.png ├── 2.png ├── 3.png └── 4.gif ├── client ├── babel.config.js ├── public │ ├── favicon.ico │ ├── index.html │ └── css │ │ └── reset.css ├── src │ ├── assets │ │ ├── 404.gif │ │ ├── bg.jpg │ │ ├── logo.png │ │ ├── showcase.png │ │ ├── lockLogin.png │ │ └── js │ │ │ ├── Export2Excel.js │ │ │ └── Blob.js │ ├── store │ │ ├── state.js │ │ ├── mutation-type.js │ │ ├── getters.js │ │ ├── index.js │ │ ├── actions.js │ │ └── mutations.js │ ├── common │ │ ├── bus.js │ │ ├── Tags.vue │ │ └── theme.vue │ ├── views │ │ ├── Home │ │ │ ├── echarts │ │ │ │ ├── ListTypeData.vue │ │ │ │ ├── Stacked.vue │ │ │ │ └── Dotted.vue │ │ │ ├── Home.vue │ │ │ ├── BaseCharts.vue │ │ │ └── HomeTop.vue │ │ ├── information │ │ │ ├── article │ │ │ │ └── ShowFundArticle.vue │ │ │ ├── Editor.vue │ │ │ ├── Markdown.vue │ │ │ ├── Clock.vue │ │ │ └── InfoShow.vue │ │ ├── 404.vue │ │ ├── Lock.vue │ │ ├── MapList.vue │ │ ├── Index.vue │ │ ├── Investment │ │ │ ├── ChinaTabsList.vue │ │ │ ├── tablist │ │ │ │ └── ChinaTabsTable.vue │ │ │ └── ChinaTouziList.vue │ │ ├── logo │ │ │ └── Login.vue │ │ ├── ListUser.vue │ │ ├── register │ │ │ └── Register.vue │ │ ├── fundmanagement │ │ │ ├── PayList.vue │ │ │ └── FundList.vue │ │ ├── Staff.vue │ │ └── capitalData │ │ │ └── FundPosition.vue │ ├── App.vue │ ├── main.js │ ├── http.js │ ├── components │ │ ├── Menu.vue │ │ ├── UserDialong.vue │ │ ├── Dialong.vue │ │ ├── LeftMenu.vue │ │ └── Header.vue │ └── router.js ├── .gitignore ├── package.json └── vue.config.js ├── config ├── keys.js └── passport.js ├── models ├── User.js ├── Profile.js └── Staff.js ├── package.json ├── server.js ├── README.md ├── yarn-error.log └── routes └── api ├── staff.js ├── users.js └── profiles.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrZHLF/vue-admin/HEAD/img/1.png -------------------------------------------------------------------------------- /img/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrZHLF/vue-admin/HEAD/img/2.png -------------------------------------------------------------------------------- /img/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrZHLF/vue-admin/HEAD/img/3.png -------------------------------------------------------------------------------- /img/4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrZHLF/vue-admin/HEAD/img/4.gif -------------------------------------------------------------------------------- /client/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrZHLF/vue-admin/HEAD/client/public/favicon.ico -------------------------------------------------------------------------------- /client/src/assets/404.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrZHLF/vue-admin/HEAD/client/src/assets/404.gif -------------------------------------------------------------------------------- /client/src/assets/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrZHLF/vue-admin/HEAD/client/src/assets/bg.jpg -------------------------------------------------------------------------------- /client/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrZHLF/vue-admin/HEAD/client/src/assets/logo.png -------------------------------------------------------------------------------- /client/src/assets/showcase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrZHLF/vue-admin/HEAD/client/src/assets/showcase.png -------------------------------------------------------------------------------- /client/src/store/state.js: -------------------------------------------------------------------------------- 1 | export default { 2 | isAuthenticated: false, //授权 3 | user: {}, //用户登录 4 | }; -------------------------------------------------------------------------------- /client/src/assets/lockLogin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MrZHLF/vue-admin/HEAD/client/src/assets/lockLogin.png -------------------------------------------------------------------------------- /client/src/store/mutation-type.js: -------------------------------------------------------------------------------- 1 | export const SET_AUTHENTICATED = "SET_AUTHENTICATED"; 2 | export const SET_USER = "SET_USER"; -------------------------------------------------------------------------------- /client/src/common/bus.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | // 使用 Event Bus进行非父子组件传值 4 | const bus = new Vue(); 5 | 6 | export default bus; 7 | -------------------------------------------------------------------------------- /client/src/store/getters.js: -------------------------------------------------------------------------------- 1 | export default { 2 | isAuthenticated: state => state.isAuthenticated, 3 | user: state => state.user, 4 | } -------------------------------------------------------------------------------- /config/keys.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | mongoURI: "mongodb://test:Z123456@ds135233.mlab.com:35233/restful-api-vue", 3 | secretOrKey: "secret" 4 | }; -------------------------------------------------------------------------------- /client/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | -------------------------------------------------------------------------------- /client/src/views/Home/echarts/ListTypeData.vue: -------------------------------------------------------------------------------- 1 | 6 | 16 | 18 | -------------------------------------------------------------------------------- /client/src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | Vue.use(Vuex); 5 | 6 | import actions from "./actions"; 7 | import getters from "./getters"; 8 | import mutations from "./mutations"; 9 | import state from "./state"; 10 | 11 | export default new Vuex.Store({ 12 | state, 13 | actions, 14 | getters, 15 | mutations 16 | }); -------------------------------------------------------------------------------- /client/src/views/information/article/ShowFundArticle.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 21 | 22 | 25 | -------------------------------------------------------------------------------- /client/src/views/404.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 13 | 24 | -------------------------------------------------------------------------------- /client/src/store/actions.js: -------------------------------------------------------------------------------- 1 | import { SET_AUTHENTICATED, SET_USER} from "./mutation-type"; 2 | 3 | export default { 4 | setAuthenticated({ commit }, isAuthenticated) { 5 | commit(SET_AUTHENTICATED, {isAuthenticated}); 6 | }, 7 | setUSER({ commit }, user) { 8 | commit(SET_USER, {user}) 9 | }, 10 | createUser: ({ commit }) => { 11 | commit(SET_AUTHENTICATED, false) 12 | // commit(SET_USER, null) 13 | }, 14 | } -------------------------------------------------------------------------------- /client/src/store/mutations.js: -------------------------------------------------------------------------------- 1 | import { SET_AUTHENTICATED, SET_USER } from "./mutation-type"; 2 | 3 | export default { 4 | //是否授权 5 | [SET_AUTHENTICATED](state, { isAuthenticated }) { 6 | if (isAuthenticated) { 7 | state.isAuthenticated = isAuthenticated; 8 | } else { 9 | state.isAuthenticated = false; 10 | } 11 | }, 12 | [SET_USER](state, { user }) { 13 | if (user) { 14 | state.user = user; 15 | } else { 16 | state.user = {}; 17 | } 18 | }, 19 | [SET_AUTHENTICATED](state) { 20 | state.isAuthenticated = false; //退出登录 21 | } 22 | }; -------------------------------------------------------------------------------- /models/User.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const Schema = mongoose.Schema; 3 | 4 | // Create Schema 5 | const UserSchema = new Schema({ 6 | name: { 7 | type: String, 8 | required: true 9 | }, 10 | email: { 11 | type: String, 12 | required: true 13 | }, 14 | password: { 15 | type: String, 16 | required: true 17 | }, 18 | avatar: { 19 | type: String 20 | }, 21 | identity: { 22 | type: String, 23 | required: true 24 | }, 25 | date: { 26 | type: Date, 27 | default: Date.now 28 | } 29 | }); 30 | 31 | module.exports = User = mongoose.model('users', UserSchema); -------------------------------------------------------------------------------- /models/Profile.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const Schema = mongoose.Schema; 3 | 4 | // Create Schema 5 | const ProfileSchema = new Schema({ 6 | type: { 7 | type: String, 8 | }, 9 | describe: { 10 | type: String 11 | }, 12 | income: { 13 | type: String, 14 | required: true 15 | }, 16 | expend: { 17 | type: String, 18 | required: true 19 | }, 20 | cash: { 21 | type: String, 22 | required: true 23 | }, 24 | remark: { 25 | type: String, 26 | }, 27 | date: { 28 | type: Date, 29 | default: Date.now 30 | } 31 | }); 32 | 33 | module.exports = Profile = mongoose.model("profiles", ProfileSchema); -------------------------------------------------------------------------------- /models/Staff.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const Schema = mongoose.Schema; 3 | 4 | // Create Schema 5 | const StaffSchema = new Schema({ 6 | name: { 7 | type: String, 8 | required: true 9 | }, 10 | sex: { 11 | type: String, 12 | required: true 13 | }, 14 | state: { 15 | type: String 16 | }, 17 | hobby: { 18 | type: String 19 | }, 20 | marriage: { 21 | type: String, 22 | }, 23 | birthday: { 24 | type: String, 25 | }, 26 | address: { 27 | type: String, 28 | }, 29 | date: { 30 | type: Date, 31 | default: Date.now 32 | } 33 | }); 34 | 35 | module.exports = Staff = mongoose.model("staff", StaffSchema); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api-element", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "server.js", 6 | "scripts": { 7 | "client-install": "npm install --prefix client", 8 | "client": "npm start --prefix client", 9 | "start": "node server.js", 10 | "server": "nodemon server.js", 11 | "dev": "concurrently \"npm run server\" \"npm run client\"" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "dependencies": { 16 | "bcryptjs": "^2.4.3", 17 | "body-parser": "^1.18.3", 18 | "concurrently": "^4.0.1", 19 | "express": "^4.16.4", 20 | "gravatar": "^1.6.0", 21 | "jsonwebtoken": "^8.3.0", 22 | "mongoose": "^5.3.4", 23 | "passport": "^0.4.0", 24 | "passport-jwt": "^4.0.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /client/src/views/Home/Home.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 24 | 43 | -------------------------------------------------------------------------------- /config/passport.js: -------------------------------------------------------------------------------- 1 | const JwtStrategy = require('passport-jwt').Strategy, 2 | ExtractJwt = require('passport-jwt').ExtractJwt; 3 | const mongoose = require("mongoose"); 4 | const User = mongoose.model("users"); 5 | const keys = require("../config/keys"); 6 | 7 | const opts = {} 8 | opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken(); 9 | opts.secretOrKey = keys.secretOrKey; 10 | 11 | module.exports = passport => { 12 | passport.use(new JwtStrategy(opts, (jwt_payload, done) => { 13 | // console.log(jwt_payload); 14 | User.findById(jwt_payload.id) 15 | .then(user => { 16 | if (user) { 17 | return done(null, user); 18 | } 19 | 20 | return done(null, false); 21 | }) 22 | .catch(err => console.log(err)); 23 | })); 24 | } -------------------------------------------------------------------------------- /client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 后台管理界面 9 | 10 | 11 | 12 | 13 | 14 | 17 |
18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /client/src/views/Home/BaseCharts.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 34 | 45 | -------------------------------------------------------------------------------- /client/src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 30 | 31 | 32 | 42 | -------------------------------------------------------------------------------- /client/src/views/Lock.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 21 | 22 | 58 | -------------------------------------------------------------------------------- /client/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | import store from './store/index' 5 | import axios from './http' 6 | import ElementUI from 'element-ui' 7 | import 'element-ui/lib/theme-chalk/index.css' 8 | import moment from 'moment' 9 | import echarts from 'echarts' 10 | import VueQuillEditor from 'vue-quill-editor' 11 | Vue.prototype.$echarts = echarts 12 | Vue.prototype.$moment = moment 13 | Vue.use(VueQuillEditor) 14 | 15 | import VueAMap from 'vue-amap'; 16 | 17 | 18 | Vue.use(VueAMap); 19 | Vue.config.productionTip = false 20 | 21 | //百度地图 22 | VueAMap.initAMapApiLoader({ 23 | key: ' 3f5bdc7cb6cfffbafe7fbbb18528d7bb', 24 | plugin: ['AMap.Autocomplete', 'AMap.PlaceSearch', 'AMap.Scale', 'AMap.OverView', 'AMap.ToolBar', 'AMap.MapType', 'AMap.PolyEditor', 'AMap.CircleEditor'], 25 | // 默认高德 sdk 版本为 1.4.4 26 | v: '1.4.4' 27 | }); 28 | 29 | Vue.prototype.$axios = axios 30 | 31 | //全局时间格式化过滤 32 | Vue.filter('moment', function (value, formatString) { 33 | formatString = formatString || 'YYYY-MM-DD HH:mm:ss'; 34 | return moment(value).format('YYYY-MM-DD'); 35 | }); 36 | 37 | 38 | Vue.use(ElementUI) 39 | new Vue({ 40 | router, 41 | store, 42 | render: h => h(App) 43 | }).$mount('#app') 44 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const mongoose = require('mongoose'); 3 | const app = express(); 4 | const bodyParser = require('body-parser'); 5 | const passport = require("passport"); //验证token 6 | //引入users.js 7 | const users = require('./routes/api/users'); 8 | //引入profiles.js 9 | const profiles = require("./routes/api/profiles"); 10 | //staff.js 11 | const staff = require("./routes/api/staff"); 12 | 13 | 14 | app.get('/', (req, res) => { 15 | res.send('Hello World'); 16 | }); 17 | 18 | // 引入DB config 19 | const db = require('./config/keys').mongoURI; 20 | 21 | //使用body-parser中间件 22 | app.use(bodyParser.urlencoded({ extended: false })); 23 | app.use(bodyParser.json()); 24 | 25 | //链接MongoDB 26 | mongoose 27 | .connect( 28 | db, 29 | { useNewUrlParser: true } 30 | ) 31 | .then(() => { 32 | console.log('MongoDB Connected链接成功'); 33 | }) 34 | .catch(err => console.log(err)); 35 | 36 | //引入passport初始化 37 | app.use(passport.initialize()); 38 | require("./config/passport")(passport); 39 | 40 | // 使用routes 41 | app.use('/api/users', users); 42 | app.use("/api/profiles", profiles); 43 | app.use("/api/staff", staff); 44 | 45 | 46 | 47 | const port = process.env.PORT || 5000; //地址 48 | 49 | app.listen(port, () => { 50 | console.log(`Server running on port ${port}`); 51 | }); 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 基于vue3.0实现后台管理模板 2 | 3 | > 通过自己所学的vue知识,从0开始自己搭建的一个关于后台管理的模板界面,有时间就会更新新的内容,实现一些常用的功能, 4 | > 使用vue最新脚手架搭建环境,编写界面,使用axios请求接口,渲染界面,实现页面登录注册,数据的增删改查,数据部分存储到easy-mock数据中。 5 | 6 | ## 项目结构 7 | ``` 8 | |——— client #vue项目入口文件 9 | |——— config #秘钥配置文件 10 | |——— node_modules #一些常用安装的依赖 11 | |——— models #接口模型 12 | |——— router #接口文档 13 | |——— package.json #项目配置文件 14 | |___ README.md #项目的说明文档,markdown 格式 15 | ``` 16 | ## 相关技术 17 | 1. vuejs2.0:一套构建用户界面的渐进式框架,易用、灵活、高效。 18 | 2. vue-router:官方的路由组件,配合vue.js创建单页应用(SPA)非常简单。 19 | 3. axios: 基于 Promise 的 HTTP 请求客户端,可同时在浏览器和 node.js 中使用。 20 | 21 | ## 功能介绍 22 | - Element-ui 23 | - 请求拦截和响应拦截 24 | - 富文本编辑器 25 | - Markdown编辑器 26 | - Echarts 27 | - tab数据切换 28 | - token本地存储 29 | - 表单 30 | - 高德地图引入 31 | - 登录注册 32 | - 路由守卫 33 | - vuex存储 34 | - 数据分页和查询 35 | - Excel表格导出 36 | - 递归组件 37 | - 主题更换 38 | - 404 39 | 40 | ## 项目编译和运行 41 | + 可以直接在git上下载项目源码。把github下载到本地, 42 | git clone [](https://github.com/MrZHLF/vue-admin.git) 43 | + 进入node-api-element当前页面初始化 44 | cnpm install 45 | + 进入client项目目录中 46 | cnpm install 47 | + 所有依赖安装成功后执行启动命令在当前目录启动,不要在client进行启动,已经配置好前后端联调 48 | npm run dev 49 | 如果显示一下内容说明安装成功 50 | I Your application is running here: http://localhost:8080 51 | 52 | ## 成果展示 53 | ![avatar](./img/1.png) 54 | ![avatar](./img/2.png) 55 | ![avatar](./img/3.png) 56 | 57 | ![avatar](./img/4.gif) 58 | 更新中... -------------------------------------------------------------------------------- /client/src/http.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { Message, Loading } from "element-ui"; 3 | import router from "./router"; 4 | 5 | let loading; //定义loading变量 6 | 7 | function startLoading() { 8 | //使用Element loading-start 方法 9 | loading = Loading.service({ 10 | lock: true, 11 | text: "加载中...", 12 | background: "rgba(0, 0, 0, 0.7)" 13 | }); 14 | } 15 | function endLoading() { 16 | //使用Element loading-close 方法 17 | loading.close(); 18 | } 19 | 20 | // 请求拦截 设置统一header 21 | axios.interceptors.request.use( 22 | config => { 23 | // 加载 24 | startLoading(); 25 | if (localStorage.eleToken) 26 | config.headers.Authorization = localStorage.eleToken; 27 | return config; 28 | }, 29 | error => { 30 | return Promise.reject(error); 31 | } 32 | ); 33 | 34 | // 响应拦截 401 token过期处理 35 | axios.interceptors.response.use( 36 | response => { 37 | endLoading(); 38 | return response; 39 | }, 40 | error => { 41 | // 错误提醒 42 | endLoading(); 43 | Message.error(error.response.data); 44 | 45 | const { status } = error.response; 46 | if (status == 401) { 47 | Message.error("token值无效,请重新登录"); 48 | // 清除token 49 | localStorage.removeItem("eleToken"); 50 | 51 | // 页面跳转 52 | router.push("/login"); 53 | } 54 | 55 | return Promise.reject(error); 56 | } 57 | ); 58 | 59 | export default axios; 60 | -------------------------------------------------------------------------------- /client/src/views/information/Editor.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 51 | 52 | 53 | 69 | -------------------------------------------------------------------------------- /client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint", 9 | "start": "npm run serve" 10 | }, 11 | "dependencies": { 12 | "axios": "^0.18.0", 13 | "better-scroll": "^1.13.4", 14 | "echarts": "^4.2.0-rc.2", 15 | "element-ui": "^2.4.8", 16 | "file-saver": "^2.0.0", 17 | "js-cookie": "^2.2.0", 18 | "jwt-decode": "^2.2.0", 19 | "mavon-editor": "^2.6.17", 20 | "moment": "^2.22.2", 21 | "vue": "^2.5.17", 22 | "vue-amap": "^0.5.8", 23 | "vue-aplayer": "^1.6.1", 24 | "vue-i18n": "^8.3.2", 25 | "vue-quill-editor": "^3.0.6", 26 | "vue-router": "^3.0.1", 27 | "vuex": "^3.0.1", 28 | "xlsx": "^0.14.1" 29 | }, 30 | "devDependencies": { 31 | "@vue/cli-plugin-babel": "^3.0.5", 32 | "@vue/cli-plugin-eslint": "^3.0.5", 33 | "@vue/cli-service": "^3.0.5", 34 | "@vue/eslint-config-standard": "^3.0.5", 35 | "script-loader": "^0.7.2", 36 | "vue-template-compiler": "^2.5.17" 37 | }, 38 | "eslintConfig": { 39 | "root": true, 40 | "env": { 41 | "node": true 42 | }, 43 | "extends": [ 44 | "plugin:vue/essential", 45 | "@vue/standard" 46 | ], 47 | "rules": {}, 48 | "parserOptions": { 49 | "parser": "babel-eslint" 50 | } 51 | }, 52 | "postcss": { 53 | "plugins": { 54 | "autoprefixer": {} 55 | } 56 | }, 57 | "browserslist": [ 58 | "> 1%", 59 | "last 2 versions", 60 | "not ie <= 8" 61 | ] 62 | } 63 | -------------------------------------------------------------------------------- /client/src/views/MapList.vue: -------------------------------------------------------------------------------- 1 | 16 | 59 | 60 | -------------------------------------------------------------------------------- /client/public/css/reset.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | 6 | html, body, div, span, applet, object, iframe, 7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 8 | a, abbr, acronym, address, big, cite, code, 9 | del, dfn, em, img, ins, kbd, q, s, samp, 10 | small, strike, strong, sub, sup, tt, var, 11 | b, u, i, center, 12 | dl, dt, dd, ol, ul, li, 13 | fieldset, form, label, legend, 14 | table, caption, tbody, tfoot, thead, tr, th, td, 15 | article, aside, canvas, details, embed, 16 | figure, figcaption, footer, header, hgroup, 17 | menu, nav, output, ruby, section, summary, 18 | time, mark, audio, video { 19 | margin: 0; 20 | padding: 0; 21 | border: 0; 22 | font-size: 100%; 23 | font: inherit; 24 | vertical-align: baseline; 25 | } 26 | /* HTML5 display-role reset for older browsers */ 27 | article, aside, details, figcaption, figure, 28 | footer, header, hgroup, menu, nav, section { 29 | display: block; 30 | } 31 | body { 32 | line-height: 1; 33 | } 34 | ol, ul { 35 | list-style: none; 36 | } 37 | blockquote, q { 38 | quotes: none; 39 | } 40 | blockquote:before, blockquote:after, 41 | q:before, q:after { 42 | content: ''; 43 | content: none; 44 | } 45 | table { 46 | border-collapse: collapse; 47 | border-spacing: 0; 48 | } 49 | 50 | .el-loading{ 51 | position: absolute; 52 | z-index: 2000; 53 | background-color: rgba(255,255,255,.7); 54 | margin: 0; 55 | top: 0; 56 | right: 0; 57 | bottom: 0; 58 | left: 0; 59 | -webkit-transition: opacity .3s; 60 | transition: opacity .3s; 61 | } 62 | .el-loading-spinner{ 63 | top: 50%; 64 | margin-top: -21px; 65 | width: 100%; 66 | text-align: center; 67 | position: absolute; 68 | } 69 | -------------------------------------------------------------------------------- /client/src/views/Index.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 56 | 83 | -------------------------------------------------------------------------------- /client/src/views/information/Markdown.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 54 | 55 | 63 | -------------------------------------------------------------------------------- /client/vue.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const debug = process.env.NODE_ENV !== 'production' 3 | 4 | module.exports = { 5 | baseUrl: '/', // 根域上下文目录 6 | outputDir: 'dist', // 构建输出目录 7 | assetsDir: 'assets', // 静态资源目录 (js, css, img, fonts) 8 | lintOnSave: false, // 是否开启eslint保存检测,有效值:ture | false | 'error' 9 | runtimeCompiler: true, // 运行时版本是否需要编译 10 | transpileDependencies: [], // 默认babel-loader忽略mode_modules,这里可增加例外的依赖包名 11 | productionSourceMap: true, // 是否在构建生产包时生成 sourceMap 文件,false将提高构建速度 12 | configureWebpack: config => { // webpack配置,值位对象时会合并配置,为方法时会改写配置 13 | if (debug) { // 开发环境配置 14 | config.devtool = 'cheap-module-eval-source-map' 15 | } else { // 生产环境配置 16 | } 17 | // Object.assign(config, { // 开发生产共同配置 18 | // resolve: { 19 | // alias: { 20 | // '@': path.resolve(__dirname, './src'), 21 | // '@c': path.resolve(__dirname, './src/components'), 22 | // 'vue$': 'vue/dist/vue.esm.js' 23 | // } 24 | // } 25 | // }) 26 | }, 27 | chainWebpack: config => { // webpack链接API,用于生成和修改webapck配置,https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md 28 | if (debug) { 29 | // 本地开发配置 30 | } else { 31 | // 生产开发配置 32 | } 33 | }, 34 | parallel: require('os').cpus().length > 1, // 构建时开启多进程处理babel编译 35 | pluginOptions: { // 第三方插件配置 36 | }, 37 | pwa: { // 单页插件相关配置 https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa 38 | }, 39 | devServer: { 40 | open: true, 41 | host: 'localhost', 42 | port: 8080, 43 | https: false, 44 | hotOnly: false, 45 | proxy: { // 配置跨域 46 | '/api': { 47 | target: 'http://localhost:5000/api/', 48 | ws: true, 49 | changOrigin: true, 50 | pathRewrite: { 51 | '^/api': '' 52 | } 53 | } 54 | }, 55 | before: app => { } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /client/src/components/Menu.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 44 | 95 | -------------------------------------------------------------------------------- /yarn-error.log: -------------------------------------------------------------------------------- 1 | Arguments: 2 | C:\Program Files\nodejs\node.exe C:\Users\Administrator\AppData\Roaming\npm\node_modules\yarn\bin\yarn.js install 3 | 4 | PATH: 5 | C:\Users\Administrator\bin;D:\git\Git\mingw64\bin;D:\git\Git\usr\local\bin;D:\git\Git\usr\bin;D:\git\Git\usr\bin;D:\git\Git\mingw64\bin;D:\git\Git\usr\bin;C:\Users\Administrator\bin;D:\nginx\nginx-1.15.7;D:\nvm\nvm-setup\nvm;C:\Users\Administrator\.nvm;F:\redis;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0;C:\Program Files (x86)\ATI Technologies\ATI.ACE\Core-Static;C:\Program Files (x86)\AMD\ATI.ACE\Core-Static;E:\mongodb\bin;D:\git\Git\cmd;D:\svn\bin;D:\nvm\nvm-setup\nvm;C:\Program Files\nodejs;D:\putty;C:\Users\Administrator\AppData\Roaming\npm;D:\前端开的工具\vscode\Microsoft VS Code\bin;D:\heroku\bin;D:\nvm\nvm-setup\nvm;C:\Program Files\nodejs;D:\git\Git\usr\bin\vendor_perl;D:\git\Git\usr\bin\core_perl 6 | 7 | Yarn version: 8 | 1.9.4 9 | 10 | Node version: 11 | 10.11.0 12 | 13 | Platform: 14 | win32 x64 15 | 16 | Trace: 17 | Error: ENOENT: no such file or directory, copyfile 'C:\Users\Administrator\AppData\Local\Yarn\Cache\v2\npm-ansi-regex-3.0.0-ed0317c322064f79466c02966bddb605ab37d998\package.json' -> 'D:\vue-list\vue-admin\node_modules\cliui\node_modules\ansi-regex\package.json' 18 | 19 | npm manifest: 20 | { 21 | "name": "api-element", 22 | "version": "1.0.0", 23 | "description": "", 24 | "main": "server.js", 25 | "scripts": { 26 | "client-install": "npm install --prefix client", 27 | "client": "npm start --prefix client", 28 | "start": "node server.js", 29 | "server": "nodemon server.js", 30 | "dev": "concurrently \"npm run server\" \"npm run client\"" 31 | }, 32 | "author": "", 33 | "license": "ISC", 34 | "dependencies": { 35 | "bcrypt": "^3.0.2", 36 | "body-parser": "^1.18.3", 37 | "concurrently": "^4.0.1", 38 | "express": "^4.16.4", 39 | "gravatar": "^1.6.0", 40 | "jsonwebtoken": "^8.3.0", 41 | "mongoose": "^5.3.4", 42 | "passport": "^0.4.0", 43 | "passport-jwt": "^4.0.0" 44 | } 45 | } 46 | 47 | yarn manifest: 48 | No manifest 49 | 50 | Lockfile: 51 | No lockfile 52 | -------------------------------------------------------------------------------- /client/src/views/Investment/ChinaTabsList.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 67 | 68 | 73 | -------------------------------------------------------------------------------- /client/src/views/Investment/tablist/ChinaTabsTable.vue: -------------------------------------------------------------------------------- 1 | 88 | 89 | 102 | 103 | 105 | -------------------------------------------------------------------------------- /client/src/views/Home/HomeTop.vue: -------------------------------------------------------------------------------- 1 | 57 | 58 | 64 | 111 | -------------------------------------------------------------------------------- /client/src/views/Home/echarts/Stacked.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 123 | 124 | 127 | -------------------------------------------------------------------------------- /client/src/components/UserDialong.vue: -------------------------------------------------------------------------------- 1 | 43 | 44 | 87 | 89 | -------------------------------------------------------------------------------- /client/src/components/Dialong.vue: -------------------------------------------------------------------------------- 1 | 44 | 45 | 94 | 96 | -------------------------------------------------------------------------------- /client/src/views/information/Clock.vue: -------------------------------------------------------------------------------- 1 | 6 | 94 | 103 | 104 | -------------------------------------------------------------------------------- /client/src/views/logo/Login.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 75 | 76 | -------------------------------------------------------------------------------- /routes/api/staff.js: -------------------------------------------------------------------------------- 1 | //主要用于Login登录 register 注册 2 | const express = require("express"); 3 | const router = express.Router(); 4 | const keys = require("../../config/keys"); 5 | const Staff = require('../../models/Staff') 6 | const passport = require("passport"); 7 | 8 | // $route GET api/staff/test 9 | // @desc 返回的请求的json数据 10 | // @access public 11 | router.get("/text", (req, res) => { 12 | res.json({ msg: "staff" }); 13 | }); 14 | 15 | 16 | // $route POST api/staff/add 17 | // @desc 添加数据内容 18 | // @access public 19 | 20 | router.post('/add',passport.authenticate('jwt', { session: false }),(req,res) => { 21 | const staffInformation = {}; 22 | if(req.body.name) staffInformation.name = req.body.name; 23 | if(req.body.sex) staffInformation.sex = req.body.sex; 24 | if(req.body.state) staffInformation.state = req.body.state; 25 | if(req.body.hobby) staffInformation.hobby = req.body.hobby; 26 | if(req.body.marriage) staffInformation.marriage = req.body.marriage; 27 | if(req.body.birthday) staffInformation.birthday = req.body.birthday; 28 | if(req.body.address) staffInformation.address = req.body.address; 29 | 30 | new Staff(staffInformation).save().then(staff => { 31 | console.log(staff); 32 | res.json(staff); 33 | }); 34 | }) 35 | 36 | // $route GET api/staff 37 | // @desc 获取所有的数据 38 | // @access public 39 | 40 | router.get("/", passport.authenticate("jwt", { session: false }),(req,res) => { 41 | Staff.find().then(staff => { 42 | if(!staff) { 43 | return res.status(400).json("没有任何数据存在") 44 | } 45 | return res.json(staff) 46 | }).catch(err => { 47 | return res.status(404).json(err) 48 | }) 49 | }); 50 | 51 | // $route GET api/staff/:id 52 | // @desc 获取单个数据源数据内容 53 | // @access public 54 | 55 | router.get("/:id", passport.authenticate("jwt", { session: false }),(req,res) => { 56 | Staff.findOne({ _id: req.params.id }).then(staff =>{ 57 | if(!staff) { 58 | return res.status(400).json("数据不存在") 59 | } 60 | res.json(staff) 61 | }).catch(err => { 62 | return res.status(404).json(err) 63 | }) 64 | }); 65 | 66 | 67 | // $route POST api/staff/edit/:id 68 | // @desc 编辑个人信息 69 | // @access public 70 | 71 | router.post("/edit/:id", passport.authenticate("jwt", { session: false }),(req,res) => { 72 | 73 | const staffInformation = {}; 74 | if (req.body.name) staffInformation.name = req.body.name; 75 | if (req.body.sex) staffInformation.sex = req.body.sex; 76 | if (req.body.state) staffInformation.state = req.body.state; 77 | if (req.body.hobby) staffInformation.hobby = req.body.hobby; 78 | if (req.body.marriage) staffInformation.marriage = req.body.marriage; 79 | if (req.body.birthday) staffInformation.birthday = req.body.birthday; 80 | if (req.body.address) staffInformation.address = req.body.address; 81 | 82 | //更新数据内容 83 | Staff.findByIdAndUpdate({ _id: req.params.id }, { $set: staffInformation }, { new: true }) 84 | .then(staff => { 85 | if (!staff) { 86 | return res.status(400).json("数据不存在"); 87 | } 88 | res.json(staff); 89 | }) 90 | .catch(err => { 91 | return res.status(404).json(err); 92 | }); 93 | }); 94 | 95 | 96 | // $route POST api/staff/delete/:id 97 | // @desc 删除单个信息 98 | // @access public 99 | 100 | router.delete("/delete/:id", passport.authenticate("jwt", { session: false }),(req,res) => { 101 | 102 | Staff.findByIdAndRemove({_id:req.params.id}).then(staff =>{ 103 | staff.save().then(staff => { 104 | res.json(staff) 105 | }) 106 | }).catch(err => { 107 | return res.status(404).json(err) 108 | }) 109 | 110 | }); 111 | 112 | 113 | 114 | module.exports = router; -------------------------------------------------------------------------------- /routes/api/users.js: -------------------------------------------------------------------------------- 1 | //主要用于Login登录 register 注册 2 | const express = require("express"); 3 | const router = express.Router(); 4 | // const bcrypt = require("bcrypt"); //加密 5 | const bcrypt = require("bcryptjs"); //加密 6 | const User = require("../../models/User"); 7 | const keys = require("../../config/keys"); 8 | const gravatar = require('gravatar'); //头像 9 | const jwt = require("jsonwebtoken"); //token 10 | const passport = require("passport"); 11 | 12 | // $route GET api/users/test 13 | // @desc 返回的请求的json数据 14 | // @access public 15 | router.get('/test',(req,res) => { 16 | res.json({msg:"logon users test"}) 17 | }) 18 | 19 | // $route POST /api/users/register 20 | // @desc 返回的请求的json数据 21 | // @access public 22 | router.post('/register', (req, res) => { 23 | // 查询数据库中是否拥有邮箱 24 | User.findOne({ email: req.body.email }).then(user => { 25 | if (user) { 26 | return res.status(400).json( '邮箱已被注册!'); 27 | } else { 28 | const avatar = gravatar.url(req.body.email, { 29 | s: '200', 30 | r: 'pg', 31 | d: 'mm' 32 | }); 33 | 34 | const newUser = new User({ 35 | name: req.body.name, 36 | email: req.body.email, 37 | avatar, 38 | password: req.body.password, 39 | identity: req.body.identity 40 | }); 41 | 42 | bcrypt.genSalt(10, function (err, salt) { 43 | bcrypt.hash(newUser.password, salt, (err, hash) => { 44 | if (err) throw err; 45 | 46 | newUser.password = hash; 47 | 48 | newUser 49 | .save() 50 | .then(user => res.json(user)) 51 | .catch(err => console.log(err)); 52 | }); 53 | }); 54 | } 55 | }); 56 | }); 57 | 58 | // $route POST /api/users/login 59 | // @desc 返回的请求的json数据 token jwt 60 | // @access public 61 | 62 | router.post('/login', (req, res) => { 63 | 64 | const email = req.body.email; 65 | const password = req.body.password; 66 | 67 | //查询数据库 68 | User.findOne({email:req.body.email}).then(user => { 69 | //判断用户是否存在 70 | if(!user){ 71 | return res.status(404).json("用户不存在") 72 | } 73 | //密码匹配 74 | bcrypt.compare(password, user.password).then(isMath =>{ 75 | if(isMath) { 76 | const rule = { 77 | id: user.id, 78 | name: user.name, 79 | avatar: user.avatar, 80 | identity: user.identity 81 | }; 82 | jwt.sign(rule, keys.secretOrKey,{expiresIn:3600},(err,token) =>{ 83 | if(err) throw err; 84 | res.json({ 85 | success:true, 86 | token: "Bearer "+token //最后返回token值 87 | }) 88 | }) 89 | } else { 90 | return res.status(400).json("密码不存在") 91 | } 92 | }) 93 | }) 94 | }) 95 | 96 | // $route GET /api/users/current 97 | // @desc 返回用户信息 98 | // @access private 99 | 100 | router.get('/current',passport.authenticate('jwt', { session: false }), 101 | (req, res) => { 102 | res.json({ 103 | id: req.user.id, 104 | name: req.user.name, 105 | email: req.user.email, 106 | identity: req.user.identity 107 | }); 108 | } 109 | ); 110 | 111 | module.exports = router; -------------------------------------------------------------------------------- /client/src/views/Home/echarts/Dotted.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 152 | 153 | 156 | -------------------------------------------------------------------------------- /routes/api/profiles.js: -------------------------------------------------------------------------------- 1 | //主要用于Login登录 register 注册 2 | const express = require("express"); 3 | const router = express.Router(); 4 | const keys = require("../../config/keys"); 5 | const Profile = require('../../models/Profile') 6 | const passport = require("passport"); 7 | 8 | // $route GET api/profiles/test 9 | // @desc 返回的请求的json数据 10 | // @access public 11 | router.get("/text", (req, res) => { 12 | res.json({ msg: "profiles" }); 13 | }); 14 | 15 | // $route POST api/profiles/add 16 | // @desc 添加数据内容 17 | // @access public 18 | 19 | router.post('/add', passport.authenticate('jwt', { session: false }), 20 | (req, res) => { 21 | const ProfileFields = {}; 22 | 23 | if(req.body.type) ProfileFields.type = req.body.type; 24 | if (req.body.describe) ProfileFields.describe = req.body.describe; 25 | if (req.body.income) ProfileFields.income = req.body.income; 26 | if (req.body.expend) ProfileFields.expend = req.body.expend; 27 | if (req.body.cash) ProfileFields.cash = req.body.cash; 28 | if (req.body.remark) ProfileFields.remark = req.body.remark; 29 | 30 | new Profile(ProfileFields).save().then(profile => { 31 | console.log(profile) 32 | res.json(profile); 33 | }) 34 | } 35 | ); 36 | 37 | 38 | // $route GET api/profiles 39 | // @desc 获取所有内容 40 | // @access public 41 | 42 | router.get("/", passport.authenticate("jwt", { session: false }),(req,res) => { 43 | Profile.find().then(profils => { 44 | if(!profils) { 45 | return res.status(404).json("没有任何数据存在") 46 | } 47 | res.json(profils); 48 | }).catch(err => { 49 | return res.status(404).json(err) 50 | }) 51 | }); 52 | 53 | // $route GET api/profiles/:id 54 | // @desc 获取所有单个数据内容 55 | // @access public 56 | 57 | router.get("/:id", passport.authenticate("jwt", { session: false }),(req,res) => { 58 | Profile.findOne({_id: req.params.id}).then(profils => { 59 | if(!profils) { 60 | return res.status(404).json("数据不存在") 61 | } 62 | res.json(profils) 63 | }).catch(err =>{ 64 | return res.status(404).json(err) 65 | }) 66 | }); 67 | 68 | // $route POST api/profiles/edit/:id 69 | // @desc 编辑信息 70 | // @access public 71 | 72 | router.post('/edit/:id', passport.authenticate('jwt', { session: false }), 73 | (req, res) => { 74 | const ProfileFields = {}; 75 | 76 | if (req.body.type) ProfileFields.type = req.body.type; 77 | if (req.body.describe) ProfileFields.describe = req.body.describe; 78 | if (req.body.income) ProfileFields.income = req.body.income; 79 | if (req.body.expend) ProfileFields.expend = req.body.expend; 80 | if (req.body.cash) ProfileFields.cash = req.body.cash; 81 | if (req.body.remark) ProfileFields.remark = req.body.remark; 82 | 83 | Profile.findByIdAndUpdate( 84 | {_id:req.params.id}, 85 | { $set: ProfileFields}, 86 | {new:true} 87 | ).then(profile => { 88 | if(!profile) { 89 | return res.status(404).json("此信息不存在") 90 | } 91 | res.json(profile) 92 | }).catch(err => { 93 | res.status(404).json(err) 94 | }) 95 | } 96 | ); 97 | 98 | // $route GET api/profiles/delete/:id 99 | // @desc 获取所有单个数据内容 100 | // @access public 101 | 102 | router.delete("/delete/:id", passport.authenticate("jwt", { session: false }), (req, res) => { 103 | Profile.findByIdAndRemove({_id:req.params.id}).then(profile =>{ 104 | profile.save().then(profile => res.json(profile)); 105 | }).catch(err => { 106 | return res.status(404).json(err) 107 | }) 108 | }); 109 | 110 | module.exports = router; -------------------------------------------------------------------------------- /client/src/router.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | 4 | Vue.use(Router) 5 | 6 | const router = new Router({ 7 | routes: [ 8 | { 9 | path: '/', 10 | redirect: 'index' 11 | }, 12 | { 13 | path: '/index', 14 | name: 'Index', 15 | component: () => import('./views/Index.vue'), 16 | meta: { title: '首页' }, 17 | redirect: '/home', 18 | children: [ 19 | { 20 | path: '/home', 21 | name: 'home', 22 | component: () => import('./views/Home/Home'), 23 | meta: { title: '首页' } 24 | }, 25 | { 26 | path: '/staff', 27 | name: 'staff', 28 | component: () => import('./views/Staff'), 29 | meta: { title: '用户信息' } 30 | }, 31 | { 32 | path: '/listuser', 33 | name: 'listuser', 34 | component: () => import('./views/ListUser'), 35 | meta: { title: '信息列表' } 36 | }, 37 | { 38 | path: '/fundList', 39 | name: 'fundList', 40 | component: () => import('./views/fundmanagement/FundList'), 41 | meta: { title: '资金流水' } 42 | }, 43 | { 44 | path: '/payList', 45 | name: 'payList', 46 | component: () => import('./views/fundmanagement/PayList'), 47 | meta: { title: '支付单据' } 48 | }, 49 | { 50 | path: '/Infoshow', 51 | name: 'Infoshow', 52 | component: () => import('./views/information/InfoShow'), 53 | meta: { title: '个人信息' } 54 | }, 55 | { 56 | path: '/editor', 57 | name: 'editor', 58 | component: () => import('./views/information/Editor'), 59 | meta: { title: '富文本编辑器' } 60 | }, 61 | { 62 | path: '/markdown', 63 | name: 'markdown', 64 | component: () => import('./views/information/Markdown'), 65 | meta: { title: 'Markdown编辑器' } 66 | }, 67 | { 68 | path: '/showFundArticle', 69 | name: 'showFundArticle', 70 | component: () => 71 | import('./views/information/article/ShowFundArticle'), 72 | meta: { title: '文章列表' } 73 | }, 74 | { 75 | path: '/chinaTouziList', 76 | name: 'chinaTouziList', 77 | component: () => import('./views/Investment/ChinaTouziList'), 78 | meta: { title: '省份投资' } 79 | }, 80 | { 81 | path: '/chinaTabsList', 82 | name: 'ChinaTabsList', 83 | component: () => import('./views/Investment/ChinaTabsList'), 84 | meta: { title: '区域投资' } 85 | }, 86 | { 87 | path: '/fundPosition', 88 | name: 'fundPosition', 89 | component: () => import('./views/capitalData/FundPosition'), 90 | meta: { title: '投资分布' } 91 | }, 92 | { 93 | path: '/maplist', 94 | name: 'maplist', 95 | component: () => import('./views/MapList'), 96 | meta: { title: '地图展示' } 97 | } 98 | ] 99 | }, 100 | { 101 | path: '/register', 102 | name: 'register', 103 | component: () => import('./views/register/Register') 104 | }, 105 | { 106 | path: '/login', 107 | name: 'login', 108 | component: () => import('./views/logo/Login') 109 | }, 110 | { 111 | path: '/lock', 112 | name: 'lock', 113 | component: () => import('./views/Lock.vue') 114 | }, 115 | { 116 | path: '*', 117 | name: 'Nofind', 118 | component: () => import('./views/404') 119 | } 120 | ] 121 | // mode: "history" 122 | }) 123 | 124 | // 路由守卫 125 | router.beforeEach((to, from, next) => { 126 | const isLogin = !!localStorage.eleToken 127 | 128 | if (to.path === '/login' || to.path === '/register') { 129 | next() 130 | } else { 131 | isLogin ? next() : next('/login') 132 | } 133 | }) 134 | 135 | export default router 136 | -------------------------------------------------------------------------------- /client/src/common/Tags.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 98 | 99 | 100 | 172 | -------------------------------------------------------------------------------- /client/src/views/ListUser.vue: -------------------------------------------------------------------------------- 1 | 77 | 143 | 144 | -------------------------------------------------------------------------------- /client/src/views/register/Register.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 94 | 95 | -------------------------------------------------------------------------------- /client/src/views/Investment/ChinaTouziList.vue: -------------------------------------------------------------------------------- 1 | 59 | 60 | 131 | 132 | 137 | -------------------------------------------------------------------------------- /client/src/assets/js/Export2Excel.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | require('script-loader!file-saver'); 3 | // require('script-loader!src/vendor/Blob'); 4 | require('script-loader!../../assets/js/Blob'); 5 | require('script-loader!xlsx/dist/xlsx.core.min'); 6 | 7 | function generateArray(table) { 8 | var out = []; 9 | var rows = table.querySelectorAll('tr'); 10 | var ranges = []; 11 | for (var R = 0; R < rows.length; ++R) { 12 | var outRow = []; 13 | var row = rows[R]; 14 | var columns = row.querySelectorAll('td'); 15 | for (var C = 0; C < columns.length; ++C) { 16 | var cell = columns[C]; 17 | var colspan = cell.getAttribute('colspan'); 18 | var rowspan = cell.getAttribute('rowspan'); 19 | var cellValue = cell.innerText; 20 | if (cellValue !== "" && cellValue == +cellValue) cellValue = +cellValue; 21 | 22 | //Skip ranges 23 | ranges.forEach(function (range) { 24 | if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e.c) { 25 | for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null); 26 | } 27 | }); 28 | 29 | //Handle Row Span 30 | if (rowspan || colspan) { 31 | rowspan = rowspan || 1; 32 | colspan = colspan || 1; 33 | ranges.push({s: {r: R, c: outRow.length}, e: {r: R + rowspan - 1, c: outRow.length + colspan - 1}}); 34 | } 35 | ; 36 | 37 | //Handle Value 38 | outRow.push(cellValue !== "" ? cellValue : null); 39 | 40 | //Handle Colspan 41 | if (colspan) for (var k = 0; k < colspan - 1; ++k) outRow.push(null); 42 | } 43 | out.push(outRow); 44 | } 45 | return [out, ranges]; 46 | }; 47 | 48 | function datenum(v, date1904) { 49 | if (date1904) v += 1462; 50 | var epoch = Date.parse(v); 51 | return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000); 52 | } 53 | 54 | function sheet_from_array_of_arrays(data, opts) { 55 | var ws = {}; 56 | var range = {s: {c: 10000000, r: 10000000}, e: {c: 0, r: 0}}; 57 | for (var R = 0; R != data.length; ++R) { 58 | for (var C = 0; C != data[R].length; ++C) { 59 | if (range.s.r > R) range.s.r = R; 60 | if (range.s.c > C) range.s.c = C; 61 | if (range.e.r < R) range.e.r = R; 62 | if (range.e.c < C) range.e.c = C; 63 | var cell = {v: data[R][C]}; 64 | if (cell.v == null) continue; 65 | var cell_ref = XLSX.utils.encode_cell({c: C, r: R}); 66 | 67 | if (typeof cell.v === 'number') cell.t = 'n'; 68 | else if (typeof cell.v === 'boolean') cell.t = 'b'; 69 | else if (cell.v instanceof Date) { 70 | cell.t = 'n'; 71 | cell.z = XLSX.SSF._table[14]; 72 | cell.v = datenum(cell.v); 73 | } 74 | else cell.t = 's'; 75 | 76 | ws[cell_ref] = cell; 77 | } 78 | } 79 | if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range); 80 | return ws; 81 | } 82 | 83 | function Workbook() { 84 | if (!(this instanceof Workbook)) return new Workbook(); 85 | this.SheetNames = []; 86 | this.Sheets = {}; 87 | } 88 | 89 | function s2ab(s) { 90 | var buf = new ArrayBuffer(s.length); 91 | var view = new Uint8Array(buf); 92 | for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF; 93 | return buf; 94 | } 95 | 96 | export function export_table_to_excel(id) { 97 | var theTable = document.getElementById(id); 98 | console.log('a') 99 | var oo = generateArray(theTable); 100 | var ranges = oo[1]; 101 | 102 | /* original data */ 103 | var data = oo[0]; 104 | var ws_name = "SheetJS"; 105 | console.log(data); 106 | 107 | var wb = new Workbook(), ws = sheet_from_array_of_arrays(data); 108 | 109 | /* add ranges to worksheet */ 110 | // ws['!cols'] = ['apple', 'banan']; 111 | ws['!merges'] = ranges; 112 | 113 | /* add worksheet to workbook */ 114 | wb.SheetNames.push(ws_name); 115 | wb.Sheets[ws_name] = ws; 116 | 117 | var wbout = XLSX.write(wb, {bookType: 'xlsx', bookSST: false, type: 'binary'}); 118 | 119 | saveAs(new Blob([s2ab(wbout)], {type: "application/octet-stream"}), "test.xlsx") 120 | } 121 | 122 | function formatJson(jsonData) { 123 | console.log(jsonData) 124 | } 125 | 126 | export function export_json_to_excel(th, jsonData, defaultTitle) { 127 | 128 | /* original data */ 129 | 130 | var data = jsonData; 131 | data.unshift(th); 132 | var ws_name = "SheetJS"; 133 | 134 | var wb = new Workbook(), ws = sheet_from_array_of_arrays(data); 135 | 136 | 137 | /* add worksheet to workbook */ 138 | wb.SheetNames.push(ws_name); 139 | wb.Sheets[ws_name] = ws; 140 | 141 | var wbout = XLSX.write(wb, {bookType: 'xlsx', bookSST: false, type: 'binary'}); 142 | var title = defaultTitle || '列表' 143 | saveAs(new Blob([s2ab(wbout)], {type: "application/octet-stream"}), title + ".xlsx") 144 | } 145 | -------------------------------------------------------------------------------- /client/src/components/LeftMenu.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 155 | 218 | 219 | -------------------------------------------------------------------------------- /client/src/views/fundmanagement/PayList.vue: -------------------------------------------------------------------------------- 1 | 94 | 95 | 195 | 203 | -------------------------------------------------------------------------------- /client/src/common/theme.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 132 | 133 | 142 | -------------------------------------------------------------------------------- /client/src/views/Staff.vue: -------------------------------------------------------------------------------- 1 | 96 | 97 | 198 | 206 | -------------------------------------------------------------------------------- /client/src/components/Header.vue: -------------------------------------------------------------------------------- 1 | 61 | 62 | 166 | 286 | -------------------------------------------------------------------------------- /client/src/assets/js/Blob.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | /* Blob.js*/ 3 | 4 | /*global self, unescape */ 5 | /*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true, 6 | plusplus: true */ 7 | 8 | /*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */ 9 | 10 | (function (view) { 11 | "use strict"; 12 | 13 | view.URL = view.URL || view.webkitURL; 14 | 15 | if (view.Blob && view.URL) { 16 | try { 17 | new Blob; 18 | return; 19 | } catch (e) { 20 | } 21 | } 22 | 23 | // Internally we use a BlobBuilder implementation to base Blob off of 24 | // in order to support older browsers that only have BlobBuilder 25 | var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function (view) { 26 | var 27 | get_class = function (object) { 28 | return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1]; 29 | } 30 | , FakeBlobBuilder = function BlobBuilder() { 31 | this.data = []; 32 | } 33 | , FakeBlob = function Blob(data, type, encoding) { 34 | this.data = data; 35 | this.size = data.length; 36 | this.type = type; 37 | this.encoding = encoding; 38 | } 39 | , FBB_proto = FakeBlobBuilder.prototype 40 | , FB_proto = FakeBlob.prototype 41 | , FileReaderSync = view.FileReaderSync 42 | , FileException = function (type) { 43 | this.code = this[this.name = type]; 44 | } 45 | , file_ex_codes = ( 46 | "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR " 47 | + "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR" 48 | ).split(" ") 49 | , file_ex_code = file_ex_codes.length 50 | , real_URL = view.URL || view.webkitURL || view 51 | , real_create_object_URL = real_URL.createObjectURL 52 | , real_revoke_object_URL = real_URL.revokeObjectURL 53 | , URL = real_URL 54 | , btoa = view.btoa 55 | , atob = view.atob 56 | 57 | , ArrayBuffer = view.ArrayBuffer 58 | , Uint8Array = view.Uint8Array 59 | 60 | , origin = /^[\w-]+:\/*\[?[\w\.:-]+\]?(?::[0-9]+)?/ 61 | ; 62 | FakeBlob.fake = FB_proto.fake = true; 63 | while (file_ex_code--) { 64 | FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1; 65 | } 66 | // Polyfill URL 67 | if (!real_URL.createObjectURL) { 68 | URL = view.URL = function (uri) { 69 | var 70 | uri_info = document.createElementNS("http://www.w3.org/1999/xhtml", "a") 71 | , uri_origin 72 | ; 73 | uri_info.href = uri; 74 | if (!("origin" in uri_info)) { 75 | if (uri_info.protocol.toLowerCase() === "data:") { 76 | uri_info.origin = null; 77 | } else { 78 | uri_origin = uri.match(origin); 79 | uri_info.origin = uri_origin && uri_origin[1]; 80 | } 81 | } 82 | return uri_info; 83 | }; 84 | } 85 | URL.createObjectURL = function (blob) { 86 | var 87 | type = blob.type 88 | , data_URI_header 89 | ; 90 | if (type === null) { 91 | type = "application/octet-stream"; 92 | } 93 | if (blob instanceof FakeBlob) { 94 | data_URI_header = "data:" + type; 95 | if (blob.encoding === "base64") { 96 | return data_URI_header + ";base64," + blob.data; 97 | } else if (blob.encoding === "URI") { 98 | return data_URI_header + "," + decodeURIComponent(blob.data); 99 | } 100 | if (btoa) { 101 | return data_URI_header + ";base64," + btoa(blob.data); 102 | } else { 103 | return data_URI_header + "," + encodeURIComponent(blob.data); 104 | } 105 | } else if (real_create_object_URL) { 106 | return real_create_object_URL.call(real_URL, blob); 107 | } 108 | }; 109 | URL.revokeObjectURL = function (object_URL) { 110 | if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) { 111 | real_revoke_object_URL.call(real_URL, object_URL); 112 | } 113 | }; 114 | FBB_proto.append = function (data/*, endings*/) { 115 | var bb = this.data; 116 | // decode data to a binary string 117 | if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) { 118 | var 119 | str = "" 120 | , buf = new Uint8Array(data) 121 | , i = 0 122 | , buf_len = buf.length 123 | ; 124 | for (; i < buf_len; i++) { 125 | str += String.fromCharCode(buf[i]); 126 | } 127 | bb.push(str); 128 | } else if (get_class(data) === "Blob" || get_class(data) === "File") { 129 | if (FileReaderSync) { 130 | var fr = new FileReaderSync; 131 | bb.push(fr.readAsBinaryString(data)); 132 | } else { 133 | // async FileReader won't work as BlobBuilder is sync 134 | throw new FileException("NOT_READABLE_ERR"); 135 | } 136 | } else if (data instanceof FakeBlob) { 137 | if (data.encoding === "base64" && atob) { 138 | bb.push(atob(data.data)); 139 | } else if (data.encoding === "URI") { 140 | bb.push(decodeURIComponent(data.data)); 141 | } else if (data.encoding === "raw") { 142 | bb.push(data.data); 143 | } 144 | } else { 145 | if (typeof data !== "string") { 146 | data += ""; // convert unsupported types to strings 147 | } 148 | // decode UTF-16 to binary string 149 | bb.push(unescape(encodeURIComponent(data))); 150 | } 151 | }; 152 | FBB_proto.getBlob = function (type) { 153 | if (!arguments.length) { 154 | type = null; 155 | } 156 | return new FakeBlob(this.data.join(""), type, "raw"); 157 | }; 158 | FBB_proto.toString = function () { 159 | return "[object BlobBuilder]"; 160 | }; 161 | FB_proto.slice = function (start, end, type) { 162 | var args = arguments.length; 163 | if (args < 3) { 164 | type = null; 165 | } 166 | return new FakeBlob( 167 | this.data.slice(start, args > 1 ? end : this.data.length) 168 | , type 169 | , this.encoding 170 | ); 171 | }; 172 | FB_proto.toString = function () { 173 | return "[object Blob]"; 174 | }; 175 | FB_proto.close = function () { 176 | this.size = 0; 177 | delete this.data; 178 | }; 179 | return FakeBlobBuilder; 180 | }(view)); 181 | 182 | view.Blob = function (blobParts, options) { 183 | var type = options ? (options.type || "") : ""; 184 | var builder = new BlobBuilder(); 185 | if (blobParts) { 186 | for (var i = 0, len = blobParts.length; i < len; i++) { 187 | if (Uint8Array && blobParts[i] instanceof Uint8Array) { 188 | builder.append(blobParts[i].buffer); 189 | } 190 | else { 191 | builder.append(blobParts[i]); 192 | } 193 | } 194 | } 195 | var blob = builder.getBlob(type); 196 | if (!blob.slice && blob.webkitSlice) { 197 | blob.slice = blob.webkitSlice; 198 | } 199 | return blob; 200 | }; 201 | 202 | var getPrototypeOf = Object.getPrototypeOf || function (object) { 203 | return object.__proto__; 204 | }; 205 | view.Blob.prototype = getPrototypeOf(new view.Blob()); 206 | }( 207 | typeof self !== "undefined" && self 208 | || typeof window !== "undefined" && window 209 | || this 210 | )); 211 | -------------------------------------------------------------------------------- /client/src/views/information/InfoShow.vue: -------------------------------------------------------------------------------- 1 | 125 | 126 | 155 | 266 | -------------------------------------------------------------------------------- /client/src/views/fundmanagement/FundList.vue: -------------------------------------------------------------------------------- 1 | 141 | 142 | 323 | 342 | -------------------------------------------------------------------------------- /client/src/views/capitalData/FundPosition.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 850 | 859 | 860 | --------------------------------------------------------------------------------