浏览代码

提交分支

xgwangman 4 年之前
父节点
当前提交
86d9922f5c
共有 71 个文件被更改,包括 6598 次插入0 次删除
  1. 7 0
      .env
  2. 21 0
      .gitignore
  3. 8 0
      LICENSE
  4. 25 0
      README.md
  5. 5 0
      babel.config.js
  6. 64 0
      package.json
  7. 二进制
      public/favicon.ico
  8. 25 0
      public/index.html
  9. 175 0
      src/App.vue
  10. 334 0
      src/assets/css/common.css
  11. 二进制
      src/assets/images/404.png
  12. 69 0
      src/assets/images/bg.svg
  13. 二进制
      src/assets/images/bg_1.png
  14. 二进制
      src/assets/images/dingdan.png
  15. 二进制
      src/assets/images/gailan.png
  16. 二进制
      src/assets/images/login_logo.png
  17. 二进制
      src/assets/images/logo-white.png
  18. 二进制
      src/assets/images/logo.png
  19. 二进制
      src/assets/images/logo_1.png
  20. 二进制
      src/assets/images/mingxi.png
  21. 二进制
      src/assets/images/moren.png
  22. 二进制
      src/assets/images/riqi.png
  23. 二进制
      src/assets/images/shoujihao.png
  24. 二进制
      src/assets/images/u15.png
  25. 二进制
      src/assets/images/user.png
  26. 二进制
      src/assets/images/xinxi.png
  27. 二进制
      src/assets/images/yongjin.png
  28. 二进制
      src/assets/images/youxiang.png
  29. 31 0
      src/assets/js/date.js
  30. 155 0
      src/components/LeftMenu.vue
  31. 174 0
      src/components/Login.vue
  32. 34 0
      src/components/authCheck.vue
  33. 45 0
      src/components/fieldMap.vue
  34. 37 0
      src/components/pageBar.vue
  35. 193 0
      src/components/tableLists.vue
  36. 136 0
      src/components/uploadFile.vue
  37. 88 0
      src/components/userSetting.vue
  38. 35 0
      src/components/username.vue
  39. 55 0
      src/helper.js
  40. 33 0
      src/main.js
  41. 2 0
      src/plugins/api.js
  42. 163 0
      src/plugins/request.js
  43. 95 0
      src/router.js
  44. 14 0
      src/store.js
  45. 101 0
      src/store/admin.js
  46. 30 0
      src/views/error.vue
  47. 147 0
      src/views/example.vue
  48. 19 0
      src/views/index.vue
  49. 341 0
      src/views/order/components/details.vue
  50. 71 0
      src/views/order/orderDetail.vue
  51. 676 0
      src/views/order/orderList.vue
  52. 261 0
      src/views/sales/commissionList.vue
  53. 175 0
      src/views/sales/components/details.vue
  54. 511 0
      src/views/sales/partnerDetail.vue
  55. 172 0
      src/views/sales/partnerList.vue
  56. 243 0
      src/views/sales/settleList.vue
  57. 37 0
      src/views/sales/withdrawDetail.vue
  58. 393 0
      src/views/sales/withdrawList.vue
  59. 172 0
      src/views/system/auth.vue
  60. 77 0
      src/views/system/components/AssignMenu.vue
  61. 87 0
      src/views/system/components/AssignRequest.vue
  62. 83 0
      src/views/system/components/AssignUser.vue
  63. 82 0
      src/views/system/components/AssignUserGroup.vue
  64. 0 0
      src/views/system/components/icon.js
  65. 71 0
      src/views/system/components/iconSelect.vue
  66. 4 0
      src/views/system/listsConst.js
  67. 289 0
      src/views/system/menu.vue
  68. 195 0
      src/views/system/request.vue
  69. 168 0
      src/views/system/user.vue
  70. 164 0
      src/views/system/userGroup.vue
  71. 6 0
      vue.config.js

+ 7 - 0
.env

@@ -0,0 +1,7 @@
+VUE_APP_ADMIN_TOKEN_NAME = 'admin_token'
+VUE_APP_API_URL_PREFIX = '/api/admin/'
+VUE_APP_API_ACTION_NAME = '_action'
+VUE_APP_API_TOKEN_NAME = '_token'
+VUE_APP_INDEX_URL = '/'
+VUE_APP_SITE_NAME = '管理平台'
+VUE_APP_SITE_TITLE_TPL = '{title}'

+ 21 - 0
.gitignore

@@ -0,0 +1,21 @@
+.DS_Store
+node_modules
+/dist
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw*
+package-lock.json

+ 8 - 0
LICENSE

@@ -0,0 +1,8 @@
+The MIT License (MIT)
+Copyright © 2019 baiy.org
+
+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.

+ 25 - 0
README.md

@@ -0,0 +1,25 @@
+新企明星后台管理 vue+iview
+v1.1.2
+分销2.0版本对应企明星后端,订单列表 筛选条件 产品类型 新增“大会员”
+
+### 依赖
+* [vue](https://cn.vuejs.org)
+* [iview3.0](http://v3.iviewui.com/)
+* localStorage
+* [axios](https://github.com/axios/axios)
+* [lodash](https://lodash.com/)
+* `vue-router` 
+* `vuex`
+
+### 安装
+
+```shell
+// 安装
+npm install
+
+// 运行
+npm run serve
+
+// 打包
+npm run build
+```

+ 5 - 0
babel.config.js

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

+ 64 - 0
package.json

@@ -0,0 +1,64 @@
+{
+  "name": "admin",
+  "version": "0.1.0",
+  "private": true,
+  "scripts": {
+    "serve": "vue-cli-service serve",
+    "build": "vue-cli-service build",
+    "lint": "vue-cli-service lint"
+  },
+  "dependencies": {
+    "axios": "^0.19.0",
+    "iview": "^3.5.1",
+    "localStorage": "^1.0.4",
+    "lodash": "^4.17.15",
+    "marked": "^0.7.0",
+    "node-sass": "^4.14.1",
+    "qs": "^6.9.0",
+    "sass-loader": "^9.0.2",
+    "vue": "^2.6.10",
+    "vue-router": "^3.1.3",
+    "vuex": "^3.1.1"
+  },
+  "devDependencies": {
+    "@vue/cli-plugin-babel": "^3.12.0",
+    "@vue/cli-plugin-eslint": "^3.12.0",
+    "@vue/cli-service": "^3.12.0",
+    "babel-eslint": "^10.0.3",
+    "eslint": "^5.16.0",
+    "eslint-plugin-vue": "^5.2.3",
+    "vue-template-compiler": "^2.6.10"
+  },
+  "eslintConfig": {
+    "root": true,
+    "env": {
+      "node": true
+    },
+    "extends": [
+      "plugin:vue/essential",
+      "eslint:recommended"
+    ],
+    "rules": {
+      "no-console": "off",
+      "vue/no-parsing-error": [
+        2,
+        {
+          "x-invalid-end-tag": false
+        }
+      ]
+    },
+    "parserOptions": {
+      "parser": "babel-eslint"
+    }
+  },
+  "postcss": {
+    "plugins": {
+      "autoprefixer": {}
+    }
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not ie <= 8"
+  ]
+}

二进制
public/favicon.ico


+ 25 - 0
public/index.html

@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+    <title>管理后台</title>
+</head>
+<body>
+<noscript>
+    <strong>We're sorry but doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
+</noscript>
+<div id="loading">
+    <div class="spinner">
+        <div class="rect1"></div>
+        <div class="rect2"></div>
+        <div class="rect3"></div>
+        <div class="rect4"></div>
+        <div class="rect5"></div>
+    </div>
+</div>
+<div id="app"></div>
+</body>
+</html>

+ 175 - 0
src/App.vue

@@ -0,0 +1,175 @@
+<template>
+    <div id="app">
+        <Login v-if="!isLogin"></Login>
+        <div class="main layout" v-if="isLogin">
+            <div style="min-height: calc(100vh - 80px);">
+                <Layout>
+                    <Sider width="180px" class="left-sider" ref="side1" hide-trigger collapsible :collapsed-width="80"
+                        v-model="isCollapsed">
+                        <LeftMenu :menuClass="menuitemClasses" :isCollapsed="isCollapsed"></LeftMenu>
+                    </Sider>
+                    <Layout :style="{position: 'relative',marginLeft: '180px'}">
+                        <Header style="padding: 0;height:50px;line-height: 50px" class="layout-header-bar">
+                            <!-- <Icon @click.native="collapsedSider" :class="rotateIcon" :style="{margin: '0 10px 0 20px'}"
+                                type="md-menu" size="28"></Icon> -->
+                            <Row>
+                                <Col :span="12">
+                                    <Breadcrumb class="nav">
+                                        <!-- <BreadcrumbItem v-for="item in nav" :key="item.id">
+                                            <Icon :type="item.icon"></Icon>
+                                            {{item.name}}
+                                        </BreadcrumbItem> -->
+                                    </Breadcrumb>
+                                </Col>
+                                <Col :span="12">
+                                    <Dropdown @on-click="selectDropdown" style="float: right;margin-right: 20px">
+                                        <a href="javascript:void(0)">
+                                            <Avatar icon="md-person" size="small" style="marginRight:5px;font-size:16px" />
+                                            {{user.username}}
+                                            <Icon type="ios-arrow-down"></Icon>
+                                        </a>
+                                        <DropdownMenu slot="list">
+                                            <DropdownItem name="userSetting">用户设置</DropdownItem>
+                                            <DropdownItem name="logout">退出</DropdownItem>
+                                        </DropdownMenu>
+                                    </Dropdown>
+                                </Col>
+                            </Row>
+                        </Header>
+                        <Content style="margin:15px">
+                            <router-view/>
+                        </Content>
+                    </Layout>
+                </Layout>
+            </div>
+            <userSetting ref="userSetting"></userSetting>
+            <div class="foot">©2015-2019 <a href="https://www.jianyu360.com/" target="_blank">jianyu360.com</a> 版权所有 | <a style="cursor:auto">京ICP备14030217号-3</a></div>
+        </div>
+    </div>
+</template>
+
+<script>
+    import Login from './components/Login.vue'
+    import LeftMenu from './components/LeftMenu.vue'
+    import userSetting from './components/userSetting.vue'
+    import {setTitle} from './router'
+    import {token} from './helper'
+    import _ from 'lodash'
+
+    export default {
+        components: {
+            Login,
+            LeftMenu,
+            userSetting
+        },
+        data() {
+            return {
+                isCollapsed: false
+            }
+        },
+        computed: {
+            isLogin() {
+                return this.$store.getters.getAdminUser.hasOwnProperty('id');
+            },
+            nav() {
+                let menus = [];
+                let ids = this.$store.getters.getCurrentMenuIds;
+                this.$store.getters.getAdminMenu.forEach((item) => {
+                    if (_.indexOf(ids, item.id) !== -1) {
+                        menus.push(item)
+                    }
+                });
+                return menus
+            },
+            user() {
+                return this.$store.getters.getAdminUser;
+            },
+            rotateIcon() {
+                return [
+                    'menu-icon',
+                    this.isCollapsed ? 'rotate-icon' : ''
+                ];
+            },
+            menuitemClasses() {
+                return [
+                    'menu-item',
+                    this.isCollapsed ? 'collapsed-menu' : ''
+                ]
+            }
+        },
+        mounted() {
+            this.$router.onReady(() => {
+                this.initialize();
+            });
+        },
+        methods: {
+            // 初始化系统
+            initialize() {
+                if (token()) {
+                    this.$request("/load").success((r) => {
+                        this.$store.dispatch('initialize', r.data)
+                        setTitle(this.$route)
+                    }).error(() => {
+                        this.$store.dispatch('logout');
+                    }).complete(() => {
+                        document.querySelector("#loading").remove();
+                    }).get();
+                } else {
+                    document.querySelector("#loading").remove();
+                }
+            },
+            selectDropdown(name) {
+                this[name]();
+            },
+            logout() {
+                this.$request("/logout").success(() => {
+                    this.$store.dispatch('logout');
+                    setTitle(this.$route)
+                }).get();
+            },
+            userSetting() {
+                this.$refs.userSetting.show();
+            },
+            collapsedSider() {
+                this.$refs.side1.toggleCollapse();
+            }
+        }
+    }
+</script>
+<style scoped>
+    .layout {
+        background: #f5f7f9;
+        position: relative;
+        overflow: hidden;
+    }
+    .left-sider {
+        height: 100vh;
+        position: fixed;
+        left: 0;
+        overflow: auto;
+    }
+    .layout-header-bar {
+        background: #fff;
+        box-shadow: 0 1px 1px rgba(0, 0, 0, .1);
+    }
+
+    .menu-icon {
+        transition: all .3s;
+    }
+
+    .rotate-icon {
+        transform: rotate(-90deg);
+    }
+
+    .nav {
+        display: inline-block;
+        width: 500px;
+        vertical-align: middle;
+        padding-left: 20px;
+    }
+    .foot {
+        margin: 20px 0 20px 180px;
+        text-align: center;
+        color: #aea79f;
+    }
+</style>

+ 334 - 0
src/assets/css/common.css

@@ -0,0 +1,334 @@
+@charset "utf-8";
+/* 初始化 */
+body,
+div,
+ul,
+li,
+ol,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+input,
+textarea,
+select,
+p,
+dl,
+dt,
+dd,
+a,
+img,
+button,
+form,
+table,
+th,
+tr,
+td,
+tbody,
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+menu,
+nav,
+section {
+  margin: 0;
+  padding: 0;
+}
+
+body,
+html {
+  height: 100%;
+  background: #f5f7f9;
+  font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+  font-weight: 500;
+}
+
+* {
+  -webkit-touch-callout: inherit;
+  /*系统默认菜单被禁用*/
+  -webkit-user-select: auto;
+  /*webkit浏览器*/
+  -moz-user-select: auto;
+  /*火狐*/
+  -ms-user-select: auto;
+  /*IE10*/
+  user-select: auto;
+}
+
+input {
+  -webkit-user-select: auto;
+  /*webkit浏览器*/
+}
+
+/*单行溢出显示省略号*/
+.txt-cut {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+/*多行溢出显示省略号*/
+.txt-cut1 {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+}
+
+a {
+  outline: none;
+  text-decoration: none;
+  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+  /*取消链接高亮  */
+  -webkit-tap-highlight-color: transparent;
+}
+
+/* 图片自适应 */
+img {
+  width: 100%;
+  height: auto;
+  width: auto\9;
+  /* ie8 */
+  display: block;
+  border: none;
+  -ms-interpolation-mode: bicubic;
+  /*为了照顾ie图片缩放失真*/
+}
+
+em,
+i,
+strong {
+  font-style: normal;
+}
+
+ul,
+li {
+  list-style-type: none;
+}
+
+/* 清除浮动 */
+.clearfix:before,
+.clearfix:after {
+  content: "";
+  display: table;
+}
+
+.clearfix:after {
+  clear: both;
+  overflow: hidden;
+}
+
+.clearfix {
+  zoom: 1;
+  /* for ie6 & ie7 */
+}
+
+.clear {
+  clear: both;
+  display: block;
+  font-size: 0;
+  height: 0;
+  line-height: 0;
+  overflow: hidden;
+}
+
+#app {
+  height: 100%;
+}
+
+/* 加载中效果 */
+#loading {
+  width: 100%;
+  height: 100%;
+  background-color: #FFF;
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: 99999;
+}
+
+#loading .spinner {
+  margin: 200px auto 0;
+  width: 50px;
+  height: 60px;
+  text-align: center;
+  font-size: 10px;
+}
+
+#loading .spinner > div {
+  background-color: #67CF22;
+  height: 100%;
+  width: 6px;
+  display: inline-block;
+  -webkit-animation: stretchdelay 1.2s infinite ease-in-out;
+  animation: stretchdelay 1.2s infinite ease-in-out;
+}
+
+#loading .spinner .rect2 {
+  -webkit-animation-delay: -1.1s;
+  animation-delay: -1.1s;
+}
+
+#loading .spinner .rect3 {
+  -webkit-animation-delay: -1.0s;
+  animation-delay: -1.0s;
+}
+
+#loading .spinner .rect4 {
+  -webkit-animation-delay: -0.9s;
+  animation-delay: -0.9s;
+}
+
+#loading .spinner .rect5 {
+  -webkit-animation-delay: -0.8s;
+  animation-delay: -0.8s;
+}
+
+@-webkit-keyframes stretchdelay {
+  0%, 40%, 100% {
+      -webkit-transform: scaleY(0.4)
+  }
+  20% {
+      -webkit-transform: scaleY(1.0)
+  }
+}
+
+@keyframes stretchdelay {
+  0%, 40%, 100% {
+      transform: scaleY(0.4);
+      -webkit-transform: scaleY(0.4);
+  }
+  20% {
+      transform: scaleY(1.0);
+      -webkit-transform: scaleY(1.0);
+  }
+}
+
+/* 滚动条样式 */
+::-webkit-scrollbar {
+  /*滚动条整体样式*/
+  width: 5px;
+  height: 1px;
+}
+::-webkit-scrollbar-thumb {
+  /*滚动条里面小方块*/
+  border-radius: 10px;
+  box-shadow: inset 0 0 5px rgba(105,105,105, 0.8);
+  background: #535353;
+}
+::-webkit-scrollbar-track {
+  /*滚动条里面轨道*/
+  box-shadow: inset 0 0 5px rgba(105,105,105, 0.8);
+  border-radius: 10px;
+  background: #ededed;
+}
+
+/*设置input,textarea框placeholder的样式*/
+input::-webkit-input-placeholder {
+  color: red;
+}
+
+input:-moz-placeholder {
+  color: red;
+}
+
+input::-moz-placeholder {
+  color: red;
+}
+
+input:-ms-input-placeholder {
+  color: red;
+}
+
+textarea::-webkit-input-placeholder {
+  color: #cdcdcd;
+}
+textarea::-moz-placeholder {
+  /* Mozilla Firefox 19+ */
+  color: #cdcdcd;
+}
+textarea:-moz-placeholder {
+  /* Mozilla Firefox 4 to 18 */
+  color: #cdcdcd;
+}
+textarea:-ms-input-placeholder {
+  /* Internet Explorer 10-11 */
+  color: #cdcdcd;
+}
+
+/* iview公共样式 */
+.ivu-form .ivu-form-item-label {
+  text-align: left;
+  padding: 10px 0;
+  font-size: 14px;
+}
+.ivu-table td.table-info-settle {
+  color: #f4516c;
+}
+.ivu-table td.table-info-money {
+  color: #36a3f7;
+  cursor: pointer;
+}
+.ivu-btn {
+  font-size: 14px;
+}
+.ivu-drawer-header-inner {
+  font-size: 16px;
+}
+.ivu-tree ul {
+  font-size: 14px;
+}
+.ivu-menu-dark.ivu-menu-vertical .ivu-menu-item-active:not(.ivu-menu-submenu), .ivu-menu-dark.ivu-menu-vertical .ivu-menu-item-active:not(.ivu-menu-submenu):hover, .ivu-menu-dark.ivu-menu-vertical .ivu-menu-submenu-title-active:not(.ivu-menu-submenu), .ivu-menu-dark.ivu-menu-vertical .ivu-menu-submenu-title-active:not(.ivu-menu-submenu):hover {
+  background: none;
+}
+.par-model {
+  display: flex;
+  justify-content: center;
+  align-content: center;
+  align-items: center;
+}
+.par-model .ivu-modal-body {
+  padding: 0;
+}
+.par-model .ivu-modal-close .ivu-icon-ios-close {
+  color: #000;
+}
+/* .ding-dan .ivu-input-inner-container {
+  margin-bottom: 10px;
+} */
+/* .ding-dan .top-bar .ivu-layout-sider {
+  display: none;
+} */
+.ding-dan .ivu-form {
+  width: 100%;
+}
+.ding-dan .ivu-input-wrapper-large .ivu-input-prefix i {
+  font-size: 12px;
+}
+.ding-dan .ivu-input-prefix {
+  width: 20px;
+  height: 36px;
+}
+.ding-dan .ivu-input-with-prefix {
+  padding-left: 20px;
+}
+.jie-suan .ivu-table-tbody tr {
+  cursor: pointer;
+}

二进制
src/assets/images/404.png


+ 69 - 0
src/assets/images/bg.svg

@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="1361px" height="609px" viewBox="0 0 1361 609" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
+    <title>Group 21</title>
+    <desc>Created with Sketch.</desc>
+    <defs></defs>
+    <g id="Ant-Design-Pro-3.0" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="账户密码登录-校验" transform="translate(-79.000000, -82.000000)">
+            <g id="Group-21" transform="translate(77.000000, 73.000000)">
+                <g id="Group-18" opacity="0.8" transform="translate(74.901416, 569.699158) rotate(-7.000000) translate(-74.901416, -569.699158) translate(4.901416, 525.199158)">
+                    <ellipse id="Oval-11" fill="#CFDAE6" opacity="0.25" cx="63.5748792" cy="32.468367" rx="21.7830479" ry="21.766008"></ellipse>
+                    <ellipse id="Oval-3" fill="#CFDAE6" opacity="0.599999964" cx="5.98746479" cy="13.8668601" rx="5.2173913" ry="5.21330997"></ellipse>
+                    <path d="M38.1354514,88.3520215 C43.8984227,88.3520215 48.570234,83.6838647 48.570234,77.9254015 C48.570234,72.1669383 43.8984227,67.4987816 38.1354514,67.4987816 C32.3724801,67.4987816 27.7006688,72.1669383 27.7006688,77.9254015 C27.7006688,83.6838647 32.3724801,88.3520215 38.1354514,88.3520215 Z" id="Oval-3-Copy" fill="#CFDAE6" opacity="0.45"></path>
+                    <path d="M64.2775582,33.1704963 L119.185836,16.5654915" id="Path-12" stroke="#CFDAE6" stroke-width="1.73913043" stroke-linecap="round" stroke-linejoin="round"></path>
+                    <path d="M42.1431708,26.5002681 L7.71190162,14.5640702" id="Path-16" stroke="#E0B4B7" stroke-width="0.702678964" opacity="0.7" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1.405357899873153,2.108036953469981"></path>
+                    <path d="M63.9262187,33.521561 L43.6721326,69.3250951" id="Path-15" stroke="#BACAD9" stroke-width="0.702678964" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1.405357899873153,2.108036953469981"></path>
+                    <g id="Group-17" transform="translate(126.850922, 13.543654) rotate(30.000000) translate(-126.850922, -13.543654) translate(117.285705, 4.381889)" fill="#CFDAE6">
+                        <ellipse id="Oval-4" opacity="0.45" cx="9.13482653" cy="9.12768076" rx="9.13482653" ry="9.12768076"></ellipse>
+                        <path d="M18.2696531,18.2553615 C18.2696531,13.2142826 14.1798519,9.12768076 9.13482653,9.12768076 C4.08980114,9.12768076 0,13.2142826 0,18.2553615 L18.2696531,18.2553615 Z" id="Oval-4" transform="translate(9.134827, 13.691521) scale(-1, -1) translate(-9.134827, -13.691521) "></path>
+                    </g>
+                </g>
+                <g id="Group-14" transform="translate(216.294700, 123.725600) rotate(-5.000000) translate(-216.294700, -123.725600) translate(106.294700, 35.225600)">
+                    <ellipse id="Oval-2" fill="#CFDAE6" opacity="0.25" cx="29.1176471" cy="29.1402439" rx="29.1176471" ry="29.1402439"></ellipse>
+                    <ellipse id="Oval-2" fill="#CFDAE6" opacity="0.3" cx="29.1176471" cy="29.1402439" rx="21.5686275" ry="21.5853659"></ellipse>
+                    <ellipse id="Oval-2-Copy" stroke="#CFDAE6" opacity="0.4" cx="179.019608" cy="138.146341" rx="23.7254902" ry="23.7439024"></ellipse>
+                    <ellipse id="Oval-2" fill="#BACAD9" opacity="0.5" cx="29.1176471" cy="29.1402439" rx="10.7843137" ry="10.7926829"></ellipse>
+                    <path d="M29.1176471,39.9329268 L29.1176471,18.347561 C23.1616351,18.347561 18.3333333,23.1796097 18.3333333,29.1402439 C18.3333333,35.1008781 23.1616351,39.9329268 29.1176471,39.9329268 Z" id="Oval-2" fill="#BACAD9"></path>
+                    <g id="Group-9" opacity="0.45" transform="translate(172.000000, 131.000000)" fill="#E6A1A6">
+                        <ellipse id="Oval-2-Copy-2" cx="7.01960784" cy="7.14634146" rx="6.47058824" ry="6.47560976"></ellipse>
+                        <path d="M0.549019608,13.6219512 C4.12262681,13.6219512 7.01960784,10.722722 7.01960784,7.14634146 C7.01960784,3.56996095 4.12262681,0.670731707 0.549019608,0.670731707 L0.549019608,13.6219512 Z" id="Oval-2-Copy-2" transform="translate(3.784314, 7.146341) scale(-1, 1) translate(-3.784314, -7.146341) "></path>
+                    </g>
+                    <ellipse id="Oval-10" fill="#CFDAE6" cx="218.382353" cy="138.685976" rx="1.61764706" ry="1.61890244"></ellipse>
+                    <ellipse id="Oval-10-Copy-2" fill="#E0B4B7" opacity="0.35" cx="179.558824" cy="175.381098" rx="1.61764706" ry="1.61890244"></ellipse>
+                    <ellipse id="Oval-10-Copy" fill="#E0B4B7" opacity="0.35" cx="180.098039" cy="102.530488" rx="2.15686275" ry="2.15853659"></ellipse>
+                    <path d="M28.9985381,29.9671598 L171.151018,132.876024" id="Path-11" stroke="#CFDAE6" opacity="0.8"></path>
+                </g>
+                <g id="Group-10" opacity="0.799999952" transform="translate(1054.100635, 36.659317) rotate(-11.000000) translate(-1054.100635, -36.659317) translate(1026.600635, 4.659317)">
+                    <ellipse id="Oval-7" stroke="#CFDAE6" stroke-width="0.941176471" cx="43.8135593" cy="32" rx="11.1864407" ry="11.2941176"></ellipse>
+                    <g id="Group-12" transform="translate(34.596774, 23.111111)" fill="#BACAD9">
+                        <ellipse id="Oval-7" opacity="0.45" cx="9.18534718" cy="8.88888889" rx="8.47457627" ry="8.55614973"></ellipse>
+                        <path d="M9.18534718,17.4450386 C13.8657264,17.4450386 17.6599235,13.6143199 17.6599235,8.88888889 C17.6599235,4.16345787 13.8657264,0.332739156 9.18534718,0.332739156 L9.18534718,17.4450386 Z" id="Oval-7"></path>
+                    </g>
+                    <path d="M34.6597385,24.809694 L5.71666084,4.76878945" id="Path-2" stroke="#CFDAE6" stroke-width="0.941176471"></path>
+                    <ellipse id="Oval" stroke="#CFDAE6" stroke-width="0.941176471" cx="3.26271186" cy="3.29411765" rx="3.26271186" ry="3.29411765"></ellipse>
+                    <ellipse id="Oval-Copy" fill="#F7E1AD" cx="2.79661017" cy="61.1764706" rx="2.79661017" ry="2.82352941"></ellipse>
+                    <path d="M34.6312443,39.2922712 L5.06366663,59.785082" id="Path-10" stroke="#CFDAE6" stroke-width="0.941176471"></path>
+                </g>
+                <g id="Group-19" opacity="0.33" transform="translate(1282.537219, 446.502867) rotate(-10.000000) translate(-1282.537219, -446.502867) translate(1142.537219, 327.502867)">
+                    <g id="Group-17" transform="translate(141.333539, 104.502742) rotate(275.000000) translate(-141.333539, -104.502742) translate(129.333539, 92.502742)" fill="#BACAD9">
+                        <circle id="Oval-4" opacity="0.45" cx="11.6666667" cy="11.6666667" r="11.6666667"></circle>
+                        <path d="M23.3333333,23.3333333 C23.3333333,16.8900113 18.1099887,11.6666667 11.6666667,11.6666667 C5.22334459,11.6666667 0,16.8900113 0,23.3333333 L23.3333333,23.3333333 Z" id="Oval-4" transform="translate(11.666667, 17.500000) scale(-1, -1) translate(-11.666667, -17.500000) "></path>
+                    </g>
+                    <circle id="Oval-5-Copy-6" fill="#CFDAE6" cx="201.833333" cy="87.5" r="5.83333333"></circle>
+                    <path d="M143.5,88.8126685 L155.070501,17.6038544" id="Path-17" stroke="#BACAD9" stroke-width="1.16666667"></path>
+                    <path d="M17.5,37.3333333 L127.466252,97.6449735" id="Path-18" stroke="#BACAD9" stroke-width="1.16666667"></path>
+                    <polyline id="Path-19" stroke="#CFDAE6" stroke-width="1.16666667" points="143.902597 120.302281 174.935455 231.571342 38.5 147.510847 126.366941 110.833333"></polyline>
+                    <path d="M159.833333,99.7453842 L195.416667,89.25" id="Path-20" stroke="#E0B4B7" stroke-width="1.16666667" opacity="0.6"></path>
+                    <path d="M205.333333,82.1372105 L238.719406,36.1666667" id="Path-24" stroke="#BACAD9" stroke-width="1.16666667"></path>
+                    <path d="M266.723424,132.231988 L207.083333,90.4166667" id="Path-25" stroke="#CFDAE6" stroke-width="1.16666667"></path>
+                    <circle id="Oval-5" fill="#C1D1E0" cx="156.916667" cy="8.75" r="8.75"></circle>
+                    <circle id="Oval-5-Copy-3" fill="#C1D1E0" cx="39.0833333" cy="148.75" r="5.25"></circle>
+                    <circle id="Oval-5-Copy-2" fill-opacity="0.6" fill="#D1DEED" cx="8.75" cy="33.25" r="8.75"></circle>
+                    <circle id="Oval-5-Copy-4" fill-opacity="0.6" fill="#D1DEED" cx="243.833333" cy="30.3333333" r="5.83333333"></circle>
+                    <circle id="Oval-5-Copy-5" fill="#E0B4B7" cx="175.583333" cy="232.75" r="5.25"></circle>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

二进制
src/assets/images/bg_1.png


二进制
src/assets/images/dingdan.png


二进制
src/assets/images/gailan.png


二进制
src/assets/images/login_logo.png


二进制
src/assets/images/logo-white.png


二进制
src/assets/images/logo.png


二进制
src/assets/images/logo_1.png


二进制
src/assets/images/mingxi.png


二进制
src/assets/images/moren.png


二进制
src/assets/images/riqi.png


二进制
src/assets/images/shoujihao.png


二进制
src/assets/images/u15.png


二进制
src/assets/images/user.png


二进制
src/assets/images/xinxi.png


二进制
src/assets/images/yongjin.png


二进制
src/assets/images/youxiang.png


+ 31 - 0
src/assets/js/date.js

@@ -0,0 +1,31 @@
+//将时间戳转化为年月日
+export function ChangeDate (time){
+    // var d = new Date(time.replace(/\-/g, "/"));
+    var d = new Date(time);
+    var Y = d.getFullYear() + '.';
+    var M = (d.getMonth()+1 < 10 ? '0'+(d.getMonth()+1) : d.getMonth()+1) + '.';
+    var D = (d.getDate() < 10 ? '0'+d.getDate() : d.getDate()) + ' ';
+    // var h = (d.getHours() < 10 ? '0'+d.getHours() : d.getHours()) + ':';
+    // var m = (d.getMinutes() < 10 ? '0'+d.getMinutes() : d.getMinutes()) + ':';
+    // var s = (d.getSeconds() < 10 ? '0'+d.getSeconds() : d.getSeconds());
+    return (Y+M+D).replace(/^\s+|\s+$/g,"");
+}
+
+export function ChangeDate1 (time){
+    var d = new Date(time * 1000);
+    var Y = d.getFullYear() + '年';
+    var M = (d.getMonth()+1 < 10 ? '0'+(d.getMonth()+1) : d.getMonth()+1) + '月';
+    var D = (d.getDate() < 10 ? '0'+d.getDate() : d.getDate()) + '日';
+    return (Y+M+D).replace(/^\s+|\s+$/g,"");
+}
+
+export function ChangeDate2 (time){
+    var d = new Date(time);
+    var Y = d.getFullYear() + '-';
+    var M = (d.getMonth()+1 < 10 ? '0'+(d.getMonth()+1) : d.getMonth()+1) + '-';
+    var D = (d.getDate() < 10 ? '0'+d.getDate() : d.getDate()) + ' ';
+    var h = (d.getHours() < 10 ? '0'+d.getHours() : d.getHours()) + ':';
+    var m = (d.getMinutes() < 10 ? '0'+d.getMinutes() : d.getMinutes()) + ':';
+    var s = (d.getSeconds() < 10 ? '0'+d.getSeconds() : d.getSeconds());
+    return (Y+M+D+''+h+m+s).replace(/^\s+|\s+$/g,"");
+}

+ 155 - 0
src/components/LeftMenu.vue

@@ -0,0 +1,155 @@
+<template>
+    <Menu :active-name="active" :open-names="openNames" theme="dark" width="auto" :class="menuClass"
+          @on-select="goto" :accordion="true">
+        <MenuItem name="site-name">
+            <!-- <Icon type="ios-home"/> -->
+            <!-- <span>{{siteName}}</span> -->
+            <img src="../assets/images/logo-white.png" alt="">
+        </MenuItem>
+        <div v-for="menu in menus" :key="menu.id">
+            <MenuItem :name="menu.id" v-if="menu.url">
+                <Icon type="menu.icon"></Icon>
+                <span>{{menu.name}}</span>
+            </MenuItem>
+            <Submenu :name="menu.id" v-else>
+                <template slot="title">
+                    <Icon :type="menu.icon" v-if="menu.icon"/>
+                    <span>{{menu.name}}</span>
+                </template>
+                <div v-for="second in menu['sub_menu']" :key="second.id">
+                    <MenuItem :name="second.id" v-if="second.url">
+                        <Icon :type="second.icon" v-if="second.icon"></Icon>
+                        <span>{{second.name}}</span>
+                    </MenuItem>
+                    <Submenu :name="second.id" v-else>
+                        <template slot="title">
+                            <Icon :type="second.icon" v-if="second.icon"/>
+                            <span>{{second.name}}</span>
+                        </template>
+                        <div v-for="third in second['sub_menu']" :key="third.id">
+                            <MenuItem :name="third.id">
+                                <Icon :type="third.icon" v-if="third.icon"></Icon>
+                                <span>{{third.name}}</span>
+                            </MenuItem>
+                        </div>
+                    </Submenu>
+                </div>
+            </Submenu>
+        </div>
+    </Menu>
+</template>
+
+<script>
+    import _ from "lodash"
+    import { config } from '../helper'
+
+    let tree = function (menus, pid) {
+        let menu = [];
+        menus.forEach(function (item) {
+            if (item['parent_id'] === pid) {
+                item['sub_menu'] = item['url'] ? [] : tree(menus, item['id']);
+                menu.push(item)
+            }
+        });
+        return menu;
+    };
+
+    export default {
+        name: 'LeftMenu',
+        data() {
+            return {}
+        },
+        props: {
+            menuClass: Array,
+            isCollapsed: Boolean,
+        },
+        computed: {
+            siteName() {
+                return config('SITE_NAME');
+            },
+            menus() {
+                return tree(_.cloneDeep(this.$store.getters.getAdminMenu), 0);
+            },
+            pageMenus() {
+                let menu = [];
+                this.$store.getters.getAdminMenu.forEach(function (v) {
+                    if (v['url']) {
+                        menu.push(v);
+                    }
+                });
+                return menu;
+            },
+            openNames() {
+                return !this.isCollapsed ? this.$store.getters.getCurrentMenuIds : [];
+            },
+            active() {
+                let menu = "";
+                let path = this.$route.path;
+                this.pageMenus.forEach(function ({url, id}) {
+                    if (url === path) {
+                        menu = id;
+                    }
+                });
+                return menu;
+            }
+        },
+        methods: {
+            goto(menuId) {
+                if (menuId === "site-name") {
+                    // return this.$router.push('/');
+                }
+                this.pageMenus.forEach(({url, id}) => {
+                    if (id === menuId) {
+                        if (url.indexOf('://') !== -1) {
+                            // 外部链接
+                            return window.open(url);
+                        } else {
+                            return this.$router.push(url);
+                        }
+                    }
+                });
+            },
+        }
+    }
+</script>
+<style>
+    .collapsed-menu .ivu-menu-submenu-title .ivu-menu-submenu-title-icon {
+        display: none;
+        transition: display .2s ease;
+    }
+
+    .collapsed-menu .ivu-menu {
+        display: none;
+        transition: display .2s ease;
+    }
+</style>
+<style scoped>
+    .menu-item span {
+        display: inline-block;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+        vertical-align: middle;
+        transition: width .2s ease .2s;
+    }
+
+    .menu-item i {
+        transform: translateX(0px);
+        transition: font-size .2s ease,
+        transform .2s ease;
+        vertical-align: middle;
+        font-size: 16px;
+    }
+
+    .collapsed-menu span {
+        width: 0;
+        transition: width .2s ease;
+    }
+
+    .collapsed-menu i {
+        transform: translateX(5px);
+        transition: font-size .2s ease .2s, transform .2s ease .2s;
+        vertical-align: middle;
+        font-size: 22px;
+    }
+</style>

+ 174 - 0
src/components/Login.vue

@@ -0,0 +1,174 @@
+<template>
+    <div class="logins">
+        <Row>
+            <Col span="6" offset="9">
+                <div class="cards">
+                    <img src="@/assets/images/login_logo.png" alt="">
+                    <p slot="title">管理员登录</p>
+                    <Form ref="form" :model="form" :rules="rule" style="width: 600px">
+                        <FormItem prop="username">
+                            <Input size="large" type="text" v-model="form.username" placeholder="用户名">
+                                <Icon type="ios-person-outline" slot="prepend"></Icon>
+                            </Input>
+                        </FormItem>
+                        <FormItem prop="password">
+                            <Input size="large" type="password" v-model="form.password" placeholder="密码">
+                                <Icon type="ios-lock-outline" slot="prepend"></Icon>
+                            </Input>
+                        </FormItem>
+                        <FormItem prop="code" class="val_code">
+                            <Input size="large" type="text" v-model="form.code" placeholder="验证码">
+                                <Icon type="ios-barcode-outline" slot="prepend"></Icon>
+                            </Input>
+                            <div class="pho_code" @click="valHandler">
+                                <img :src="hosts + imgCode">
+                            </div>
+                        </FormItem>
+                        <FormItem class="remember">
+                            <Checkbox v-model="single">&nbsp;记住密码</Checkbox>
+                        </FormItem>
+                        <FormItem style="width:200px;margin: 40px auto;">
+                            <Button size="large" long @click="handleSubmit('form')" style="font-size:16px">登 录</Button>
+                        </FormItem>
+                    </Form>
+                </div>
+            </Col>
+        </Row>
+    </div>
+</template>
+
+<script>
+    import {setTitle} from '../router'
+    import { config } from '../helper'
+    export default {
+        name: 'Login',
+        data() {
+            return {
+                form: {
+                    username: '',
+                    password: '',
+                    code: ''
+                },
+                rule: {
+                    username: [
+                        {required: true, message: '请填写用户名', trigger: 'blur'}
+                    ],
+                    password: [
+                        {required: true, message: '请填写密码', trigger: 'blur'}
+                    ],
+                    code: [
+                        {required: true, message: '请填写验证码', trigger: 'blur'}
+                    ]
+                },
+                single: false,
+                imgCode: '/api/admin/?_action=/code',
+                hosts: ''
+            }
+        },
+        created () {
+            if (localStorage.getItem('user')) {
+                let userData = JSON.parse(decodeURIComponent(window.atob(localStorage.getItem('user'))))
+                if (userData) {
+                    this.form.username = userData.username
+                    this.form.password = userData.password
+                    this.single = true
+                }
+            }
+            let tokens = localStorage.getItem(config('ADMIN_TOKEN_NAME'))
+            if (!tokens) {
+                const htp = window.location.href.split('/')[0]
+                this.hosts = htp + '//' + window.location.host
+                this.valHandler()
+            }
+            let _this = this
+            document.onkeydown = function() {
+                let key = window.event.keyCode
+                if (key == 13) {
+                    _this.handleSubmit('form')
+                }
+            }
+        },
+        methods: {
+            valHandler() {
+                var num = new Date().getTime()
+                this.imgCode = "/api/admin/?_action=/code&num=" + num
+            },
+            handleSubmit(name) {
+                let _this = this;
+                this.$refs[name].validate((valid) => {
+                    if (!valid) return
+                    this.$request("/login").data(_this.form).success((r) => {
+                        // 存储用户信息
+                        if (this.single) {
+                            localStorage.setItem('user',window.btoa(window.encodeURIComponent(JSON.stringify(_this.form))))
+                        } else {
+                            localStorage.removeItem('user')
+                        }
+                        
+                        // 设置登录
+                        this.$store.dispatch('login', r.data);
+                        // 重新初始化系统
+                        this.$request("/load").success((r) => {
+                            this.$store.dispatch('initialize', r.data);
+                            setTitle(this.$route)
+                        }).error(() => {
+                            this.$Notice.error({title: '系统初始化发送异常', desc: r.info, duration: 5});
+                            this.$store.dispatch('logout');
+                        }).get();
+                    }).error(() => {
+                        this.valHandler()
+                    }).post()
+                })
+            }
+        }
+    }
+</script>
+<style lang="scss" scoped>
+    .logins {
+        width: 100%;
+        height: 100%;
+        position: absolute;
+        top: 0;
+        left: 0;
+        background: url(../assets/images/bg_1.png) #f0f2f5 no-repeat center center;
+        background-size: 100% 100%;
+        padding-top: 50px;
+        overflow: hidden;
+        .cards {
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+            align-items: center;
+            img {
+                width: 82px;
+            }
+            p {
+                font-size: 30px;
+                height: 80px;
+                line-height: 80px;
+                margin: 50px 0 30px 0;
+                color: #aea79f;
+            }
+            button {
+                height: 50px;
+            }
+            .remember {
+                color: #aea79f;
+            }
+            .val_code {
+                .pho_code {
+                    position: absolute;
+                    right: 1px;
+                    top: 2px;
+                    z-index: 9;
+                    cursor: pointer;
+                    img {
+                        width: 100px;
+                        height: 34px;
+                        border-radius: 0 4px 4px 0;
+                    }
+                }
+            }
+        }
+    }
+</style>

+ 34 - 0
src/components/authCheck.vue

@@ -0,0 +1,34 @@
+<template>
+  <div style="display: inline">
+    <template v-if="is">
+        <slot></slot>
+    </template>
+    <template v-else>
+      <slot name="without"></slot>
+    </template>
+  </div>
+</template>
+<script>
+    export default {
+        name: 'authCheck',
+        props: {
+            action: {
+                type: String,
+                default: function () {
+                    return ''
+                }
+            }
+        },
+        computed: {
+            is () {
+                let is = false
+                this.$store.getters.getAdminRequest.forEach(item => {
+                    if (item.action === this.action) {
+                        is = true
+                    }
+                })
+                return is
+            }
+        }
+    }
+</script>

+ 45 - 0
src/components/fieldMap.vue

@@ -0,0 +1,45 @@
+<template>
+  <span>{{desc}}</span>
+</template>
+<script>
+    export default {
+        name: 'fieldMap',
+        props: {
+            value: {
+                type: [String, Number],
+                default: function () {
+                    return ''
+                }
+            },
+            map: {
+                type: Array,
+                default: function () {
+                    return []
+                }
+            },
+            valueField: {
+                type: String,
+                default: function () { return 'v'}
+            },
+            descField: {
+                type: String,
+                default: function () { return 'n'}
+            },
+            default: {
+                type: String,
+                default: function () { return ''}
+            }
+        },
+        computed: {
+            desc () {
+                let desc = this.default
+                this.map.forEach(item => {
+                    if (String(this.value) === String(item[this.valueField])) {
+                        desc = String(item[this.descField])
+                    }
+                })
+                return desc
+            },
+        }
+    }
+</script>

+ 37 - 0
src/components/pageBar.vue

@@ -0,0 +1,37 @@
+<template>
+    <div class="lists-filter">
+        <Layout :style="{background:'none'}">
+            <Content>
+                <Form inline>
+                    <slot></slot>
+                </Form>
+            </Content>
+            <Sider hide-trigger :style="{background:'none'}" :width="rightWidth" style="text-align: right">
+                <slot name="right"></slot>
+            </Sider>
+        </Layout>
+    </div>
+</template>
+
+<script>
+    export default {
+        name: "pageBar",
+        props: {
+            rightWidth: {
+                type: [Number, String],
+                default: 162
+            },
+        },
+    }
+</script>
+
+<style>
+    .lists-filter .ivu-layout.ivu-layout-has-sider>.ivu-layout, .lists-filter .ivu-layout.ivu-layout-has-sider>.ivu-layout-content{
+        overflow-x: visible;
+        display: flex;
+        align-items: center;
+    }
+    .lists-filter .ivu-form-item{
+        margin-bottom: 10px;
+    }
+</style>

+ 193 - 0
src/components/tableLists.vue

@@ -0,0 +1,193 @@
+<template>
+    <div class="table-lists">
+        <page-bar v-if="!hiddenFilter" class="top-bar">
+            <slot name="filterTitle"></slot>
+            <slot name="filterContent"></slot>
+            <slot name="filterButton">
+                <Button type="primary" size="large" @click="reload()" v-if="filterType === 1" :class="{bActive:bott}">查 询</Button>
+                <Button type="primary" size="large" @click="reset()" style="margin-left: 10px" v-if="filterReset === 1" :class="{bActive:bott}">重 置</Button>
+            </slot>
+            <slot name="exportData"></slot>
+            <div slot="right">
+                <slot name="filterRight">
+                    <!-- <Input prefix="md-search" type="text" v-model="filter.keyword" placeholder="搜索..." clearable/> -->
+                </slot>
+            </div>
+        </page-bar>
+        <slot></slot>
+        <page-bar style="margin-top: 10px;padding: 5px 0;" :rightWidth="750">
+            <slot name="options"></slot>
+            <div slot="right">
+                <Page 
+                    @on-change="changePage" 
+                    :current="page" 
+                    :page-size="pageSizeData" 
+                    :total="total"
+                    show-elevator 
+                    show-sizer 
+                    @on-page-size-change="pageSizeChange" 
+                    :page-size-opts="[10,20,50,100]"
+                />
+            </div>
+        </page-bar>
+    </div>
+</template>
+
+<script>
+    import _ from 'lodash'
+
+    export default {
+        name: "tableLists",
+        data() {
+            return {
+                page: 1,
+                total: 0,
+                pageSizeData: this.pageSize,
+                bott: false
+            };
+        },
+        props: {
+            value: {
+                type: [Array,Object],
+                default: function () {
+                    return []
+                }
+            },
+            filter: {
+                type: Object,
+                default: function () {
+                    return {}
+                }
+            },
+            sear: {
+                type: Object,
+                default: function () {
+                    return {}
+                }
+            },
+            pageSize: {
+                type: Number,
+                default: 10
+            },
+            requestApi: {
+                type: String,
+                required: true
+            },
+            autoLoad: {
+                type: Boolean,
+                default: true
+            },
+            hiddenFilter: {
+                type: Boolean,
+                default: false
+            },
+            // 0 不显示查询按钮 1 搜索按钮触发 2 筛选条件发生变化触发筛选
+            filterType: {
+                type: Number,
+                default: 1
+            },
+            // 0 不显示重置按钮 1 搜索按钮触发 2 筛选条件发生变化触发筛选
+            filterReset: {
+                type: Number,
+                default: 1
+            },
+            filterSear: { // 1 搜索框触发 2 搜索框筛选条件发生变化触发筛选
+                type: Number,
+                default: 1
+            }
+        },
+        watch: {
+            filter: {
+                handler: function () {
+                    if (this.filterType === 2) {
+                        this.reload()
+                    }
+                },
+                deep: true
+            },
+            sear: {
+                handler: function () {
+                    if (this.filterSear === 2) {
+                        this.seload()
+                    }
+                },
+                deep: true
+            }
+        },
+        created() {
+            let rout = this.$route.path
+            if (rout == '/order/orderList') {
+                this.bott = true
+            }
+            if (this.autoLoad) {
+                this.load();
+            }
+        },
+        methods: {
+            changePage: function (page) {
+                this.page = page;
+                this.load();
+            },
+            pageSizeChange: function (size) {
+                this.pageSizeData = size;
+                this.reload();
+            },
+            load() {
+                this.$emit('loading', true);
+                this.$request(this.requestApi).data({
+                    offset: (this.page - 1) * this.pageSizeData,
+                    pageSize: this.pageSizeData,
+                    ..._.cloneDeep(this.filter),
+                }).success((r) => {
+                    this.$emit('loading', false);
+                    this.total = r.data['total'];
+                    this.$emit('input', r.data);
+                }).get()
+            },
+            seload() {
+                this.$emit('loading', true);
+                this.$request(this.requestApi).data({
+                    offset: (this.page - 1) * this.pageSizeData,
+                    pageSize: this.pageSizeData,
+                    keyword: this.sear.keyword
+                }).success((r) => {
+                    this.$emit('loading', false);
+                    this.total = r.data['total'];
+                    this.$emit('input', r.data);
+                }).get()
+            },
+            reload(isPage) {
+                if (!isPage) {
+                    this.page = 1;
+                }
+                this.load();
+                this.$emit('serachBtn',true)
+            },
+            reset (isPage) {
+                for(let i in this.filter) { // 判断对象中任意key是否有值
+                    if (this.filter[i] !== "" || !this.sear.keyword) {
+                        if (!isPage) {
+                            this.page = 1;
+                        }
+                        this.$emit('loading', true);
+                        this.$emit('emptyFilter', true);
+                        this.load();
+                    }
+                }
+            }
+        }
+    }
+</script>
+
+<style lang="scss" scoped>
+.table-lists {
+    min-height: calc(100vh - 210px);
+   .top-bar {
+        padding: 10px 0;
+    }
+    .bActive {
+        margin-bottom: 10px;
+    }
+}
+
+</style>

+ 136 - 0
src/components/uploadFile.vue

@@ -0,0 +1,136 @@
+<template>
+    <div style="padding-bottom: 10px">
+        <Input :value="value" disabled>
+            <div slot="append">
+                <Upload
+                        :name="name"
+                        :data="{key:name}"
+                        :format="format"
+                        :max-size="maxSize"
+                        :show-upload-list="false"
+                        action="//jsonplaceholder.typicode.com/posts/"
+                        :on-progress="onUploadProgress"
+                        :on-success="onUploadSuccess"
+                        :on-error="onUploadError"
+                        :on-remove="onUploadRemove"
+                        :on-preview="onUploadPreview"
+                        :on-exceeded-size="onUploadExceededSize"
+                        :on-format-error="onUploadFormatError"
+                        style="display: inline-block;"
+                >
+                    <Button icon="md-cloud-upload">选择文件</Button>
+                </Upload>
+                <Button icon="md-search" @click="view"></Button>
+                <Button icon="md-backspace" @click="remove"></Button>
+                <img :src="'/upload/'+imgs" alt="">
+            </div>
+        </Input>
+    </div>
+</template>
+<script>
+    import {actionUrl} from "../helper";
+    import {requestSuccessHandle} from "../plugins/request";
+
+    export default {
+        name: "uploadFile",
+        data() {
+            return {
+                imgs: ''
+            }
+        },
+        props: {
+            value: {
+                type: String,
+                default: function () {
+                    return "";
+                }
+            },
+            action: {
+                type: String,
+                default: function () {
+                    return "";
+                }
+            },
+            name: {
+                type: String,
+                default: function () {
+                    return "file";
+                }
+            },
+            format: {
+                type: Array,
+                default: function () {
+                    return ['jpeg', 'jpg', 'png', 'gif']
+                }
+            },
+            domain: {
+                type: String,
+                default: function () {
+                    return "";
+                }
+            },
+            maxSize: {
+                type: Number, // 文件大小 单位kb
+            },
+            onSuccess: {
+                type: Function,
+                default() {
+                    return {};
+                }
+            },
+            onError: {
+                type: Function,
+                default() {
+                    return {};
+                }
+            },
+            onRemove: {
+                type: Function,
+                default() {
+                    return {};
+                }
+            }
+        },
+        computed: {
+            url () {
+                return actionUrl(this.action)
+            }
+        },
+        methods: {
+            remove() {
+                this.$emit('input', "");
+                this.$emit('remove')
+            },
+            view() {
+                window.open(this.domain + "" + this.value)
+            },
+            onUploadProgress() {
+            },
+            onUploadSuccess(response, file, fileList) {
+                this.imgs = file.name
+                requestSuccessHandle(this, response, true, true, () => {
+                    this.onSuccess(response.data, file, fileList);
+                    this.$emit('input', response.data.url);
+                })
+            },
+            onUploadError(error, file) {
+                this.$Notice.error({
+                    title: '错误提示',
+                    desc: error,
+                    duration: 10
+                });
+                this.onError(error, file)
+            },
+            onUploadRemove() {
+            },
+            onUploadPreview() {
+            },
+            onUploadExceededSize(file) {
+                this.onUploadError("上传文件过大,最大文件大小为:" + this.maxSize + 'kb', file)
+            },
+            onUploadFormatError(file) {
+                this.onUploadError("上传文件格式错误,允许上传的文件格式为:" + this.format.join(','), file)
+            },
+        },
+    }
+</script>

+ 88 - 0
src/components/userSetting.vue

@@ -0,0 +1,88 @@
+<template>
+  <Modal v-model="modelShow" title="用户设置 - 修改信息" :width="500">
+    <Form :label-width="80">
+      <FormItem label="用户名">
+        <Input v-model="current.username" type="text"/>
+      </FormItem>
+      <FormItem label="原密码">
+        <Input type="password" password v-model="current.oldPassword" />
+      </FormItem>
+      <FormItem label="新密码">
+        <Input v-model="current.password" type="password" password/>
+      </FormItem>
+      <FormItem label="重复密码">
+        <Input v-model="current.repeatPassword" type="password" password/>
+      </FormItem>
+    </Form>
+    <div slot="footer">
+      <Button type="primary" size="large" @click="save">提交</Button>
+    </div>
+  </Modal>
+</template>
+
+<script>
+export default {
+    name: 'userSetting',
+    data () {
+        return {
+            modelShow: false,
+            current: {
+                username: '',
+                oldPassword: '',
+                password: '',
+                repeatPassword: '',
+            },
+        }
+    },
+    methods: {
+        save () {
+          if (this.current.username == '') {
+              this.$Notice.error({
+                  title: '错误提示',
+                  desc: "用户名不能为空",
+                  duration: 3
+              })
+              return
+          }
+          if (this.current.oldPassword == '') {
+              this.$Notice.error({
+                  title: '错误提示',
+                  desc: "原密码不能为空",
+                  duration: 3
+              })
+              return
+          }
+          if (this.current.password == '') {
+              this.$Notice.error({
+                  title: '错误提示',
+                  desc: "新密码不能为空",
+                  duration: 3
+              })
+              return
+          }
+          if (this.current.repeatPassword == '') {
+              this.$Notice.error({
+                  title: '错误提示',
+                  desc: "重复密码不能为空",
+                  duration: 3
+              })
+              return
+          }
+          this.$request('/current/user/setting').data(this.current).success(() => {
+              this.modelShow = false
+              this.$store.dispatch('logout')
+          }).post()
+        },
+        show () {
+            this.current = {
+                username: '',
+                oldPassword: '',
+                password: '',
+                repeatPassword: '',
+            }
+            this.current.username = this.$store.getters.getAdminUser.username
+            this.modelShow = true
+        }
+    }
+}
+</script>

+ 35 - 0
src/components/username.vue

@@ -0,0 +1,35 @@
+<template>
+    <span>{{username}}</span>
+</template>
+<script>
+    export default {
+        name: 'username',
+        props: {
+            id: {
+                type: [String, Number],
+                default: function () {
+                    return 0
+                }
+            },
+            default: {
+                type: String,
+                default: function () {
+                    return "未知用户"
+                }
+            },
+        },
+        computed: {
+            username () {
+                let id = parseInt(this.id)
+                let allUser = this.$store.getters.getAdminAllUser
+                let username = this.default
+                allUser.forEach(user => {
+                    if (user.id === id) {
+                        username = user.username
+                    }
+                })
+                return username
+            },
+        }
+    }
+</script>

+ 55 - 0
src/helper.js

@@ -0,0 +1,55 @@
+import localStorage from 'localStorage'
+import _ from "lodash";
+
+export const trim = function (str, char, type) {
+    if (char) {
+        if (type === 'left') {
+            return str.replace(new RegExp('^\\' + char + '+', 'g'), '')
+        } else if (type === 'right') {
+            return str.replace(new RegExp('\\' + char + '+$', 'g'), '')
+        }
+        return str.replace(new RegExp('^\\' + char + '+|\\' + char + '+$', 'g'), '')
+    }
+    return str.replace(/^\s+|\s+$/g, '')
+}
+
+// 配置获取
+export const config = function (key) {
+    return process.env['VUE_APP_' + key]
+}
+
+export const token = function () {
+    return localStorage.getItem(config('ADMIN_TOKEN_NAME'))
+}
+
+export const serverUrl = function (data = {}) {
+    let query = []
+    Object.keys(data).forEach((item) => {
+        query.push(item + '=' + encodeURIComponent(data[item]))
+    })
+    return config('API_URL_PREFIX') + (query.length > 0 ? ('?' + query.join('&')) : '')
+}
+
+export const actionUrl = function (action) {
+    let data = {}
+    data[config('API_ACTION_NAME')] = action
+    if (token()) {
+        data[config('API_TOKEN_NAME')] = token()
+    }
+    return serverUrl(data)
+}
+
+// 菜单排序
+export const menuSort = function (menus) {
+    let m = _.cloneDeep(menus)
+    m.sort((item1, item2) => {
+        if (item1.sort < item2.sort) {
+            return -1
+        }
+        if (item1.sort === item2.sort) {
+            return item1.id < item2.id ? -1 : 1
+        }
+        return 1
+    })
+    return m;
+}

+ 33 - 0
src/main.js

@@ -0,0 +1,33 @@
+import Vue from 'vue'
+import iView from 'iview'
+import 'iview/dist/styles/iview.css'
+import {vueRequest} from './plugins/request'
+import store from './store'
+import router from './router'
+import pageBar from './components/pageBar'
+import tableLists from './components/tableLists'
+import username from './components/username'
+import authCheck from './components/authCheck'
+import uploadFile from './components/uploadFile'
+import fieldMap from './components/fieldMap'
+import App from './App.vue'
+import './assets/css/common.css'
+
+Vue.config.productionTip = false;
+Vue.use(iView, {
+    transfer: true
+});
+Vue.use(vueRequest);
+
+Vue.component('page-bar',pageBar);
+Vue.component('username',username);
+Vue.component('auth-check',authCheck);
+Vue.component('table-lists',tableLists);
+Vue.component('upload-file',uploadFile);
+Vue.component('field-map',fieldMap);
+
+new Vue({
+    router,
+    store,
+    render: h => h(App)
+}).$mount('#app');

+ 2 - 0
src/plugins/api.js

@@ -0,0 +1,2 @@
+export const requestList = '/system/request/lists';
+export const reqType = '/system/request/type';

+ 163 - 0
src/plugins/request.js

@@ -0,0 +1,163 @@
+import axios from 'axios'
+import qs from 'qs'
+
+import { actionUrl } from '../helper'
+import _ from 'lodash'
+
+export const request = function ({ type, data, dataType,contentType, url, success, error, complete }) {
+    type = (type || 'get').toUpperCase()
+    let config = {
+        method: type || 'get',
+        url: url,
+        headers: { 'content-type': contentType || "application/x-www-form-urlencoded" },
+        responseType: dataType || 'json'
+    }
+    if (_.indexOf(['POST', 'PUT', 'PATCH'], type) === -1) {
+        config.params = data
+    } else {
+        config.data = qs.stringify(data)
+    }
+    axios(config).then((response) => {
+        complete && complete()
+        success && success(response.data)
+    }).catch((e) => {
+        complete && complete()
+        error && error(e)
+    })
+}
+
+export const requestSuccessHandle = function (vue, response, tipSuccess, tipError, success, error) {
+    if (response.status === 'success') {
+        if (tipSuccess) {
+            vue.$Notice.success({
+                title: '操作提示',
+                desc: response.info,
+                duration: 2
+            })
+        }
+        success && success(response)
+    } else {
+        if (tipError) {
+            vue.$Notice.error({
+                title: '错误提示',
+                desc: response.info,
+                duration: 5
+            })
+            // if (response.info == '暂无权限') {
+            //     this.$request("/load").success((r) => {
+                    
+            //     })
+            // }
+        }
+        error && error(response)
+    }
+}
+
+class ActionRequest {
+    _type = 'get'
+    _action = ''
+    _data = {}
+    _tipSuccess = false
+    _tipError = true
+    _dataType = 'json'
+    _contentType = 'application/x-www-form-urlencoded'
+    _success = null
+    _error = null
+    _complete = null
+
+    constructor (vue) {
+        this.vue = vue
+    }
+
+    dataType (dataType) {
+        this._dataType = dataType
+        return this
+    }
+
+    contentType (contentType) {
+        this._contentType = contentType
+        return this
+    }
+
+    action (action) {
+        this._action = action
+        return this
+    }
+
+    data (data) {
+        this._data = data
+        return this
+    }
+
+    showSuccessTip () {
+        this._tipSuccess = true
+        return this
+    }
+
+    hideErrorTip () {
+        this._tipError = false
+        return this
+    }
+
+    success (success) {
+        this._success = success
+        return this
+    }
+
+    error (error) {
+        this._error = error
+        return this
+    }
+
+    complete (complete) {
+        this._complete = complete
+        return this
+    }
+
+    get () {
+        return this.execute('get')
+    }
+
+    post () {
+        return this.execute('post')
+    }
+
+    execute (type) {
+        this._type = type
+        request({
+            type: this._type,
+            dataType: this._dataType,
+            contentType: this._contentType,
+            data: this._data,
+            url: actionUrl(this._action),
+            success: (response) => {
+                requestSuccessHandle(
+                    this.vue,
+                    response,
+                    this._tipSuccess,
+                    this._tipError,
+                    this['_success'],
+                    this['_error']
+                )
+            },
+            error: (res) => {
+                console.log(res)
+                this.vue.$Notice.error({ title: '对不起您请求的数据不存在或者返回异常', duration: 5 })
+            },
+            complete: () => {
+                this.vue.$Loading.finish()
+                this['_complete'] && this['_complete']()
+            }
+        })
+    }
+}
+
+export const vueRequest = {
+    install: function (Vue) {
+        Vue.prototype.$request = function (action) {
+            let actionRequest = new ActionRequest(this)
+            actionRequest.action(action)
+            return actionRequest
+        }
+    }
+}

+ 95 - 0
src/router.js

@@ -0,0 +1,95 @@
+import Vue from 'vue'
+import Router from 'vue-router'
+import {config, trim} from './helper'
+import _ from "lodash";
+
+// 默认title
+document.title = config('SITE_NAME');
+// title 模板
+const siteTitleTpl = config('SITE_TITLE_TPL');
+
+// 路由配置
+const routes = [
+    {
+        path: '/',
+        name: 'index',
+        component: () => import('./views/index.vue')
+    },
+    {
+        path: '*',
+        component: () => import('./views/error.vue')
+    },
+    {
+        path: '/sales/partnerList/partnerDetail',
+        name: 'partnerDetail',
+        component: () => import('./views/sales/partnerDetail.vue')
+    },
+    {
+        path: '/sales/withdrawList/withdrawDetail',
+        name: 'withdrawDetail',
+        alias: '/sales/settleList/settleDetail',
+        component: () => import('./views/sales/withdrawDetail.vue')
+    },
+    {
+        path: '/order/orderList/orderDetail',
+        name: 'orderDetail',
+        component: () => import('./views/order/orderDetail.vue')
+    }
+];
+
+// 路由自动加载
+const routeComponent = require.context(
+    './views',
+    true,
+    /\.vue$/
+);
+
+routeComponent.keys().forEach(fileName => {
+    // 过滤组件
+    if (fileName.indexOf('components/') !== -1 || fileName === "index") {
+        return;
+    }
+    const path = '/' + trim(fileName.replace(/^\.\/(.*)\.\w+$/, '$1'), '/', 'left');
+    routes.push({
+        path: path,
+        name: path,
+        component: routeComponent(fileName).default
+    })
+});
+
+Vue.use(Router);
+
+const router = new Router({
+    mode: 'history',
+    routes
+});
+
+const originalPush = Router.prototype.push
+Router.prototype.push = function push(location) {// 解决路由重复报错的问题
+  return originalPush.call(this, location).catch(err => err)
+}
+
+// title 设置
+export const setTitle = function (to) {
+    let title = config('SITE_NAME');
+    let currentMenu = {};
+    if (router.app.$store.getters.getAdminMenu.length) {
+        router.app.$store.getters.getAdminMenu.forEach(item => {
+            if (item.url === to.path) {
+                title = siteTitleTpl.replace(/{title}/g, item.name);
+                currentMenu = _.cloneDeep(item);
+            }
+        });
+    }
+    router.app.$store.dispatch('updateCurrentMenu', currentMenu);
+    document.title = title;
+};
+
+router.afterEach(to => {
+    if (router.app.$store.getters.getAdminMenu.length !== 0) {
+        setTitle(to)
+    }
+    window.scrollTo(0, 0);
+});
+
+export default router

+ 14 - 0
src/store.js

@@ -0,0 +1,14 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+import admin from './store/admin'
+
+Vue.use(Vuex);
+
+export default new Vuex.Store({
+    state: {},
+    mutations: {},
+    actions: {},
+    modules: {
+        admin
+    }
+})

+ 101 - 0
src/store/admin.js

@@ -0,0 +1,101 @@
+import { config } from '../helper'
+import localStorage from 'localStorage'
+
+export default {
+    state: {
+        adminUser: {},
+        adminMenu: [],
+        adminAllUser: [],
+        adminRequest: [],
+        adminAuth: [],
+        adminUserGroup: [],
+        currentMenu: {},
+    },
+    getters: {
+        getAdminUser (state) {
+            return state.adminUser
+        },
+        getAdminMenu (state) {
+            return state.adminMenu
+        },
+        getAdminAllUser (state) {
+            return state.adminAllUser
+        },
+        getAdminRequest (state) {
+            return state.adminRequest
+        },
+        getAdminAuth (state) {
+            return state.adminAuth
+        },
+        getAdminUserGroup (state) {
+            return state.adminUserGroup
+        },
+        getCurrentMenu (state) {
+            return state.currentMenu
+        },
+        getCurrentMenuIds (state) {
+            if (Object.keys(state.currentMenu).length !== 0) {
+                let ids = [state.currentMenu.id]
+                let current = state.currentMenu
+                const allMenu = state.adminMenu
+                while (current.parent_id) {
+                    for (let i = 0; i < allMenu.length; i++) {
+                        if (current.parent_id === allMenu[i].id) {
+                            ids.push(allMenu[i].id)
+                            current = allMenu[i]
+                            break
+                        }
+                    }
+                }
+                return ids.reverse()
+            }
+            return []
+        },
+    },
+    mutations: {
+        setAdminUser (state, user) {
+            state.adminUser = user ? user : {}
+        },
+        setAdminAllUser (state, user) {
+            state.adminAllUser = user ? user : []
+        },
+        setAdminMenu (state, menu) {
+            state.adminMenu = menu ? menu : []
+        },
+        setAdminRequest (state, request) {
+            state.adminRequest = request ? request : []
+        },
+        setAdminAuth (state, auth) {
+            state.adminAuth = auth ? auth : []
+        },
+        setAdminUserGroup (state, userGroup) {
+            state.adminUserGroup = userGroup ? userGroup : []
+        },
+        setCurrentMenu (state, menu) {
+            state.currentMenu = menu ? menu : {}
+        }
+    },
+    actions: {
+        initialize ({ commit }, { user, menu, allUser, request, auth, userGroup }) {
+            commit('setAdminUser', user)
+            commit('setAdminMenu', menu)
+            commit('setAdminAllUser', allUser)
+            commit('setAdminRequest', request)
+            commit('setAdminAuth', auth)
+            commit('setAdminUserGroup', userGroup)
+        },
+        logout ({ commit }) {
+            localStorage.removeItem(config('ADMIN_TOKEN_NAME'))
+            commit('setAdminUser', {})
+            commit('setAdminMenu', [])
+            const htp = window.location.href.split('/')[0]
+            window.location.href = htp + '//' + window.location.host
+        },
+        login (context, { token }) {
+            localStorage.setItem(config('ADMIN_TOKEN_NAME'), token)
+        },
+        updateCurrentMenu ({ commit }, menu) {
+            commit('setCurrentMenu', menu)
+        },
+    }
+}

+ 30 - 0
src/views/error.vue

@@ -0,0 +1,30 @@
+<template>
+    <div class="err">
+        <img src="../assets/images/404.png" alt="">
+        <p>很抱歉,页面找不到了</p>
+    </div>
+</template>
+
+<script>
+export default {
+    
+}
+</script>
+
+<style lang="scss" scoped>
+.err {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    padding-top: 180px;
+    img {
+        width: 200px;
+    }
+    p {
+        font-weight: 700;
+        color: #aea79f;
+        font-size: 16px;
+    }
+}
+</style>

+ 147 - 0
src/views/example.vue

@@ -0,0 +1,147 @@
+<template>
+    <div>
+        <page-bar>
+            <FormItem>
+                <Input type="text" placeholder="文本框" clearable/>
+            </FormItem>
+            <FormItem>
+                <AutoComplete v-model="autoComplete.value" :data="autoComplete.data"
+                              @on-search="handleSearch1"
+                              placeholder="输入框搜索"
+                              style="width:200px"></AutoComplete>
+            </FormItem>
+            <FormItem>
+                <Cascader :data="cascader.data" v-model="cascader.value" placeholder="级联选择"></Cascader>
+            </FormItem>
+            <FormItem>
+                <i-switch v-model="isSwitch">
+                    <span slot="open">开</span>
+                    <span slot="close">关</span>
+                </i-switch>
+            </FormItem>
+            <FormItem>
+                <Checkbox>多选框</Checkbox>
+                <Checkbox>多选框</Checkbox>
+            </FormItem>
+            <FormItem>
+                <Radio>单选按钮</Radio>
+                <Radio>单选按钮</Radio>
+                <Radio>单选按钮</Radio>
+                <Radio>单选按钮</Radio>
+            </FormItem>
+            <FormItem>
+                <Select v-model="datepPicker" style="width:200px" placeholder="下拉菜单">
+                    <Option v-for="(item,k) in select" :value="k" :key="k">{{ item }}
+                    </Option>
+                </Select>
+            </FormItem>
+            <FormItem>
+                <DatePicker :type="datepPicker || 'date'" :placeholder="select[datepPicker || 'date']" style="width: 200px"></DatePicker>
+            </FormItem>
+            <FormItem>
+                <Button>查询</Button>
+            </FormItem>
+            <FormItem>
+                <i-circle :percent="60" dashboard>
+                    <span class="demo-circle-inner" style="font-size:24px">60%</span>
+                </i-circle>
+            </FormItem>
+            <div slot="right">
+                <Button type="success" icon="md-add">添加</Button>
+            </div>
+        </page-bar>
+        <Card title="文件上传">
+            <upload-file v-model="uploadFileUrl" :maxSize="1024"></upload-file>
+        </Card>
+    </div>
+</template>
+<script>
+    export default {
+        data() {
+            return {
+                uploadFileUrl:"",
+                isSwitch: true,
+                select: {
+                    date: "日期",
+                    daterange: "日期范围",
+                    datetime: "日期时间",
+                    datetimerange: "日期时间范围",
+                    year: "年",
+                    month: "月",
+                },
+                datepPicker: "",
+                autoComplete: {
+                    value: '',
+                    data: []
+                },
+                cascader:{
+                    value: [],
+                    data: [{
+                        value: 'beijing',
+                        label: '北京',
+                        children: [
+                            {
+                                value: 'gugong',
+                                label: '故宫'
+                            },
+                            {
+                                value: 'tiantan',
+                                label: '天坛'
+                            },
+                            {
+                                value: 'wangfujing',
+                                label: '王府井'
+                            }
+                        ]
+                    }, {
+                        value: 'jiangsu',
+                        label: '江苏',
+                        children: [
+                            {
+                                value: 'nanjing',
+                                label: '南京',
+                                children: [
+                                    {
+                                        value: 'fuzimiao',
+                                        label: '夫子庙',
+                                    }
+                                ]
+                            },
+                            {
+                                value: 'suzhou',
+                                label: '苏州',
+                                children: [
+                                    {
+                                        value: 'zhuozhengyuan',
+                                        label: '拙政园',
+                                    },
+                                    {
+                                        value: 'shizilin',
+                                        label: '狮子林',
+                                    }
+                                ]
+                            }
+                        ],
+                    }]
+                }
+            }
+        },
+        computed: {},
+        created() {
+        },
+        mounted() {
+        },
+        methods: {
+            handleSearch1(value) {
+                this.autoComplete.data = !value ? [] : [
+                    value,
+                    value + value,
+                    value + value + value
+                ];
+            }
+        },
+    }
+</script>
+<style scoped>
+
+</style>

+ 19 - 0
src/views/index.vue

@@ -0,0 +1,19 @@
+<template>
+    <div>
+        <!-- <Alert type="success">默认后台首页地址 可以在 <code>.env</code> 中配置 <code>INDEX_URL</code></Alert>
+        <Button type="primary" @click="$router.push('/example')">例子页面</Button> -->
+        <h1>控制台</h1>
+    </div>
+</template>
+
+<script>
+import { config } from '../helper'
+
+export default {
+    created() {
+        if (config('INDEX_URL') !== "/") {
+            this.$router.replace(config('INDEX_URL'))
+        }
+    },
+}
+</script>

+ 341 - 0
src/views/order/components/details.vue

@@ -0,0 +1,341 @@
+<template>
+    <div class="m-details">
+        <!-- 提现列表详情 -->
+        <div class="infor-card">
+            <div class="cont">
+                <div class="tit">订单信息</div>
+                <div class="classfity">
+                    <span>订单编号: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{{orDetails?orDetails.order_code:'--'}}</span>
+                    <span>订单时间: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{{orDetails?orDetails.create_time:'--'}}</span>
+                    <span>产品类型: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{{orDetails?orDetails.product_type:'--'}}</span>
+                </div>
+            </div>
+            <Divider />
+        </div>
+        <div class="infor-card" v-if="orderType == 0 || orderType == 1">
+            <div class="cont">
+                <div class="tit">课程信息</div>
+                <div class="classfity">
+                    <!-- 线上课程 -->
+                    <span>课程名称: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i>{{strCourse.s_name?strCourse.s_name:'--'}}</i></span>
+                    <span v-if="orderType == 0">发票开取方: &nbsp;&nbsp;&nbsp;&nbsp;<i>{{book.i_drawer?book.i_drawer:'--'}}</i></span>
+                    <span v-if="orderType == 0">课程时长: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{{strCourse.s_courseDate?strCourse.s_courseDate:'--'}}</span>
+                    <span v-if="orderType == 0">有效周期: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{{strCourse.l_endtime?l_endtime + '到期':'--'}}</span>
+                    <!-- 线下课程(招投标课程) -->
+                    <span v-if="orderType == 1">课程地点: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{{strCourse.s_address}}</span>
+                    <span v-if="orderType == 1">课程时间: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                        <i v-if="strCourse">{{l_starttime?l_starttime:''}}-{{l_endtime?l_endtime:''}}</i>
+                    </span>
+                    <span v-if="orderType == 1">联系人单位: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{{book.company}}</span>
+                    <span v-if="orderType == 1">联系人姓名: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{{book.name}}</span>
+                    <span v-if="orderType == 1">联系人邮箱: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{{book.name}}</span>
+                    <span v-if="orderType == 1">联系人电话: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{{book.phone}}</span>
+                </div>
+            </div>
+            <Divider />
+        </div>
+        <!-- 数据报告 -->
+        <div class="infor-card" v-if="orderType == 2">
+            <div class="cont">
+                <div class="tit">报告信息</div>
+                <div class="classfity">
+                    <span>报告名称: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="orDetails">{{orDetails.reportName}}</i></span>
+                    <span>邮箱地址: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="orDetails">{{orDetails.user_mail}}</i></span>
+                </div>
+            </div>
+            <Divider />
+        </div>
+        <!-- 历史数据 -->
+        <div class="infor-card" v-if="orderType == 3">
+            <div class="cont">
+                <div class="tit">导出信息</div>
+                <div class="classfity">
+                    <span>筛选日期: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="book">{{book.startime}} - {{book.endtime}}</i></span>
+                    <span>区域: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i>{{String(book.area) || '--'}}</i></span>
+                    <span>行业: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i>{{String(book.industry) || '--'}}</i></span>
+                    <span>关键词:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i>{{String(book.keywordsArr) || '--'}}</i></span>
+                    <span>金额: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                        <i v-if="book.minprice && book.maxprice">{{book.minprice || ''}}万元 - {{book.maxprice || ''}}万元</i>
+                        <i v-else>--</i>
+                    </span>
+                    <span>信息类型: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="book">{{book.subtype || '--'}}</i></span>
+                    <span>采购单位: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="book">{{String(book.buyer) || '--'}}</i></span>
+                    <span>中标单位: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="book">{{String(book.winner) || '--'}}</i></span>
+                    <span>数据规格: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="orDetails">{{orDetails.data_spec || '--'}}</i></span>
+                    <span>数据数量: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="orDetails">{{orDetails.data_count}}条</i></span>
+                    <span>邮箱地址: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="orDetails">{{orDetails.user_mail || '--'}}</i></span>
+                    <span>手机号:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="orDetails">{{orDetails.user_phone || '--'}}</i></span>
+                    <span>下载链接: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                        <i v-if="orDetails">
+                            <a :href="orDetails?orDetails.download_url:''" v-if="orDetails.download_url">点击下载</a>
+                            <i v-else>--</i>
+                        </i>
+                        <i v-else>--</i>
+                    </span>
+                </div>
+            </div>
+            <Divider />
+        </div>
+        <!-- VIP订阅 -->
+        <div class="infor-card" v-if="orderType == 8">
+            <div class="cont">
+                <div class="tit">订阅信息</div>
+                <div class="classfity">
+                    <span>订购区域: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="book">{{book?book.subscription_area?book.subscription_area:'--':'--'}}</i></span>
+                    <span>订购行业: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="book">{{book?book.industry_str?book.industry_str:'--':'--'}}</i></span>
+                    <span>订购周期: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="book">{{book?book.effective_date?book.effective_date:'--':'--'}}</i></span>
+                </div>
+            </div>
+            <Divider />
+        </div>
+        <!-- 企业商机管理 -->
+        <div class="infor-card" v-if="orderType == 6">
+            <div class="cont">
+                <div class="tit">管理信息</div>
+                <div class="classfity">
+                    <span>企业信息: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="book">{{book?book.entname:''}}</i></span>
+                    <!-- <span>管理员: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="book"></i></span>
+                    <span>手机号: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="book"></i></span> -->
+                    <span>使用产品人数: &nbsp;<i v-if="book">{{book?book.personnum:''}}人</i></span>
+                    <span>行业: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="book">{{book?book.industry:''}}</i></span>
+                    <span>使用周期: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="book">{{book?book.cycle:''}}年</i></span>
+                    <!-- <span>有效周期: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="book"></i></span> -->
+                </div>
+            </div>
+            <Divider />
+        </div>
+        <!-- 支付信息 -->
+        <div class="infor-card">
+            <div class="cont">
+                <div class="tit">支付信息</div>
+                <div class="classfity">
+                    <span>支付单号: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="orders">{{orders.transaction_id?orders.transaction_id:'--'}}</i></span>
+                    <span>支付时间: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="orDetails">{{orDetails.pay_time?orDetails.pay_time:'--'}}</i></span>
+                    <span v-if="orderType == 1">支付方式: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                        <i v-if="orDetails">{{orDetails.pay_way == 'wx_pc'?'微信':'支付宝'}}</i>
+                    </span>
+                    <span v-else>支付方式: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="orDetails">{{orDetails.pay_way?orDetails.pay_way:'--'}}</i></span>
+                    <span v-if="orderType == 1">实付数量: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                        <i v-if="orDetails">{{orDetails.original_price?orDetails.original_price:'--'}}</i>
+                    </span><!-- 线下课程 -->
+                    <span>实付金额: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                        <i v-if="orDetails">{{orDetails.pay_money?('¥'+orDetails.pay_money/100).toLocaleString('en-US'):'--'}}</i>
+                    </span><!-- VIP订阅 -->
+                    <span v-if="orderType == 1">支付状态: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                        <i :class="orDetails.order_status | orderColr" v-if="orDetails">{{orDetails.order_status | orderPay}}</i>
+                    </span>
+                    <span v-else>支付状态: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                        <i :class="orDetails.order_status | orderWord" v-if="orDetails">{{orDetails.order_status}}</i>
+                    </span>
+                </div>
+            </div>
+            <Divider />
+        </div>
+        <!-- 线下课程 -->
+        <div class="infor-card" v-if="orderType == 1">
+            <div class="cont">
+                <div class="tit">优惠信息</div>
+                <div class="classfity">
+                    <span>每单立减: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="strCourse">¥{{strCourse.s_discountPlan?strCourse.s_discountPlan[0].price:0}}</i></span>
+                    <span>多人立减: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i v-if="strCourse">¥{{strCourse.discountMoney?strCourse.discountMoney:0}}</i></span>
+                </div>
+            </div>
+            <Divider />
+        </div>
+        <div class="infor-card">
+            <div class="cont">
+                <div class="tit">发票信息</div>
+                <div class="classfity">
+                    <span>发票类型: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                        <i v-if="orDetails && orDetails.applybill_status == '已申请' || orDetails.applybill_status == 1">{{(orderType == 1 ? orDetails.invoice?orDetails.invoice.invoice_type:'--' : '普通发票(电子发票)')}}</i>
+                        <i v-else>--</i>
+                    </span>
+                    <span>发票内容: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                        <i v-if="orDetails && (orDetails.applybill_status == '已申请' || orDetails.applybill_status == 1)">明细</i>
+                        <i v-else>--</i>
+                    </span>
+                    <span>发票抬头: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                        <i v-if="orDetails">{{orderType == 1?orDetails.invoice?orDetails.invoice.invoice_rise:'--':orDetails.invoice?orDetails.invoice.invoice_type:'--'}}</i>
+                        <i v-else>--</i>
+                    </span>
+                    <span v-if="orDetails.invoice?orDetails.invoice.invoice_rise=='单位' || orDetails.invoice.invoice_type=='单位':''">开票单位名称: &nbsp;<i v-if="orDetails">{{orDetails.invoice?orDetails.invoice.company_name?orDetails.invoice.company_name:'--':'--'}}</i></span>
+                    <span v-if="orDetails.invoice?orDetails.invoice.invoice_rise=='单位' || orDetails.invoice.invoice_type=='单位':''">纳税人识别号: &nbsp;<i v-if="orDetails">{{orDetails.invoice?orDetails.invoice.taxpayer_identnum || orDetails.invoice.apply_tinumber:'--'}}</i></span>
+                    <span>邮箱地址: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                        <i v-if="orDetails">{{orDetails.invoice?((orDetails.invoice.mail?orDetails.invoice.mail:'--') || (orDetails.invoice.email?orDetails.invoice.email:'--')):'--'}}</i>
+                    </span>
+                    <span v-if="orderType == 1">发票状态: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                        <i :class="orDetails.applybill_status | invoiceColor" v-if="orDetails">{{orDetails.applybill_status | invoiceStas}}</i>
+                    </span>
+                    <span v-else>发票状态: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                        <i :class="orDetails.applybill_status | applyClor" v-if="orDetails">{{orDetails.applybill_status}}</i>
+                    </span>
+                    <span>发票查看: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                        <i v-if="orDetails && (orDetails.applybill_status == '已申请' || orDetails.applybill_status == 1)">
+                            <a :href="orDetails.invoice?orDetails.invoice.url:'*'" target="_blank" v-if="orDetails.invoice">{{orDetails.invoice.url?"点击查看":'--'}}</a>
+                            <i v-else>--</i>
+                        </i>
+                        <i v-else>--</i>
+                    </span>
+                </div>
+            </div>
+            <Divider />
+        </div>
+    </div>
+</template>
+
+<script>
+import { ChangeDate1 } from '../../../assets/js/date.js'
+export default {
+    props:{
+        orderType: String
+    },
+    created () {
+        let rout = this.$route.query
+        this.$request('/order/orderList/orderDetails').data({
+            id: rout.id,
+            type: rout.proType
+        }).success((r) => {
+            this.orders = r.data
+            this.orDetails = r.data.res;
+            this.book = r.data.filterData;
+            // if (this.book && this.book.keywords) {
+            //     this.book.keywords.forEach(e => {// 将对象转为用,分割开的数组
+            //         this.arr.push(e.keyword)
+            //         this.keyMsg = this.arr.join(",")
+            //     });
+            // }
+            this.strCourse = r.data.resCourse;
+            if (this.strCourse) {
+                this.l_starttime = ChangeDate1(this.strCourse.l_starttime);
+                this.l_endtime = ChangeDate1(this.strCourse.l_endtime);
+            }
+        }).get()
+    },
+    filters: {
+        invoiceStas(val) {
+            if (val == -2) {
+                return '已冲红'
+            } else if (val == 0) {
+                return '未申请'
+            } else if (val == 1) {
+                return '已申请'
+            }
+        },
+        invoiceColor(val) {
+            if (val == -2) {
+                return 'color1'
+            } else if (val == 0) {
+                return 'color2'
+            } else if (val == 1) {
+                return 'color3'
+            }
+        },
+        applyClor(val) {
+            if (val == '已冲红') {
+                return 'color1'
+            } else if (val == '未申请') {
+                return 'color2'
+            } else if (val == '已申请') {
+                return 'color3'
+            }
+        },
+        orderPay(val) {
+            if (val == -3) {
+                return '已退款'
+            } else if (val == -2) {
+                return '已取消'
+            } else if (val == -1) {
+                return '逻辑删除'
+            } else if (val == 0) {
+                return '未支付'
+            } else if (val == 1) {
+                return '已支付'
+            }
+        },
+        orderColr(val) {
+            if (val == -3) {
+                return 'color1'
+            } else if (val == -2) {
+                return 'color1'
+            } else if (val == -1) {
+                return 'color1'
+            } else if (val == 0) {
+                return 'color2'
+            } else if (val == 1) {
+                return 'color3'
+            }
+        },
+        orderWord(val) {
+            if (val == '已退款') {
+                return 'color1'
+            } else if (val == '已取消') {
+                return 'color2'
+            } else if (val == '逻辑删除') {
+                return 'color1'
+            } else if (val == '未支付') {
+                return 'color1'
+            } else if (val == '已支付') {
+                return 'color3'
+            }
+        }
+    },
+    data () {
+        return {
+            orders: [],
+            orDetails: [],
+            book: [],
+            strCourse: [],
+            l_starttime: '',
+            l_endtime: ''
+        }
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+.m-details {
+    margin: 50px auto;
+    width: 600px;
+    .infor-card {
+        .cont {
+            display: flex;
+            flex-direction: initial;
+            .tit {
+                width: 80px;
+                font-size: 16px;
+                font-weight: 700;
+                line-height: 34px;
+                margin-right: 50px;
+                color: #1e1e1e;
+            }
+            .classfity {
+                width: 470px;
+                display: flex;
+                flex-direction: column;
+                justify-content: center;
+                font-size: 16px;
+                color: #333;
+                line-height: 34px;
+                span {
+                    display: flex;
+                   i {
+                        width: 70%;
+                    }
+                    .no-line {
+                        color: #999;
+                    }
+                }
+                .color1 {
+                    color: #f4516c;
+                }
+                .color2 {
+                    color: #ffb822;
+                }
+                .color3 {
+                    color: #34bfa3;
+                }
+            }
+        }
+    }
+}
+</style>

+ 71 - 0
src/views/order/orderDetail.vue

@@ -0,0 +1,71 @@
+<template>
+    <div class="with-detail">
+        <h1>订单管理</h1>
+        <div class="det">
+            <div slot="title" class="right-fund">查看订单</div>
+            <Divider />
+            <v-detail :orderType="proStatus"></v-detail>
+        </div>
+    </div>
+</template>
+
+<script>
+import vDetail from './components/details'
+export default {
+    components: {
+        vDetail
+    },
+    created () {
+        let str = this.$route.query
+        switch (str.proType) {
+            case '线上课程':
+                this.proStatus = '0'
+                break;
+            case '招投标课程':
+                this.proStatus = '1'
+                break;
+            case '数据报告':
+                this.proStatus = '2'
+                break;
+            case '历史数据':
+                this.proStatus = '3'
+                break;
+            case '数据导出':
+                this.proStatus = '3'
+                break;
+            case '企业商机管理':
+                this.proStatus = '6'
+                break;
+            case 'VIP订阅':
+                this.proStatus = '8'
+                break;
+            case '超级订阅':
+                this.proStatus = '8'
+                break;
+        }
+    },
+    data () {
+        return {
+            proStatus: ''
+        }
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+.with-detail {
+    .det {
+        background:#fff;
+        padding: 10px 0;
+    }
+    h1 {
+        padding: 10px 0 20px 10px;
+    }
+    .right-fund {
+        font-size: 20px;
+        color: #575962;
+        padding-left: 100px;
+        margin-top: 14px;
+    }
+}
+</style>

+ 676 - 0
src/views/order/orderList.vue

@@ -0,0 +1,676 @@
+<template>
+  <div class="ding-dan">
+    <h1>订单管理</h1>
+    <table-lists 
+        ref="tableLists" 
+        v-model="list" 
+        :filter="filter" 
+        :sear="sear"
+        :filterSear="2"
+        requestApi="/order/orderList" 
+        @loading="load" 
+        @emptyFilter="emptyFilter"
+        style="background:#fff;padding:10px"
+    >
+        <template slot="filterContent">
+            <FormItem label="产品类型:" :label-width="70">
+                <Select size="large" placeholder="全部" clearable v-model="filter.productType" style="width:100px">
+                    <Option v-for="item in proType" :value="item.v" :key="item.v">{{ item.n }}</Option>
+                </Select>
+            </FormItem>
+            <FormItem label="订单类型:" :label-width="70">
+                <Select size="large" placeholder="全部" clearable v-model="filter.orderType" style="width:100px">
+                    <Option v-for="item in orderTips" :value="item.v" :key="item.v">{{ item.n }}</Option>
+                </Select>
+            </FormItem>
+            <FormItem label="订单状态:" :label-width="70">
+                <Select size="large" placeholder="全部" clearable v-model="filter.orderStatus" style="width:100px">
+                    <Option v-for="item in orderSta" :value="item.v" :key="item.v">{{ item.n }}</Option>
+                </Select>
+            </FormItem>
+            <FormItem label="发票状态:" :label-width="70">
+                <Select size="large" placeholder="全部" clearable v-model="filter.invoiceStatus" style="width:100px">
+                    <Option v-for="item in invoiceSta" :value="item.v" :key="item.v">{{ item.n }}</Option>
+                </Select>
+            </FormItem>
+            <FormItem label="实付金额:" :label-width="70">
+                <Input 
+                    type="text" 
+                    size="large" 
+                    v-model="filter.payMoneyMin" 
+                    placeholder="最小金额" 
+                    clearable
+                    style="width:73px;height:36px" 
+                ></Input>
+                <Input 
+                    type="text" 
+                    size="large" 
+                    v-model="filter.payMoneyMax" 
+                    placeholder="最大金额" 
+                    clearable
+                    style="width:73px;height:36px;margin-left: 2px;" 
+                />
+            </FormItem>
+            <FormItem label="订单日期:" :label-width="70">
+                <DatePicker 
+                    type="datetime" 
+                    size="large" 
+                    v-model="dataVal1"
+                    placeholder="起始时间" 
+                    style="width: 172px" 
+                    :options="options1"
+                    @on-change="handleChange1"
+                    @on-ok="confirmed1"
+                    @on-open-change="opened1"
+                ></DatePicker>
+                <DatePicker 
+                    type="datetime" 
+                    size="large" 
+                    v-model="dataVal2"
+                    placeholder="截止时间" 
+                    style="width: 172px;margin-left:2px;margin-right:10px" 
+                    :options="options2"
+                    @on-change="handleChange2"
+                    @on-ok="confirmed2"
+                    @on-open-change="opened2"
+                ></DatePicker>
+            </FormItem>
+        </template>
+        <template slot="filterContent" v-if="flag">
+            <Select size="large" placeholder="产品类型" clearable v-model="filter.productType" style="width:100px;margin:0 10px 10px 0">
+                <Option v-for="item in proType" :value="item.v" :key="item.v">{{ item.n }}</Option>
+            </Select>
+            <Select size="large" placeholder="订单类型" clearable v-model="filter.orderType" style="width:100px;margin:0 10px 10px 0">
+                <Option v-for="item in orderTips" :value="item.v" :key="item.v">{{ item.n }}</Option>
+            </Select>
+            <Select size="large" placeholder="订单状态" clearable v-model="filter.orderStatus" style="width:100px;margin:0 10px 10px 0">
+                <Option v-for="item in orderSta" :value="item.v" :key="item.v">{{ item.n }}</Option>
+            </Select>
+            <Select size="large" placeholder="发票状态" clearable v-model="filter.invoiceStatus" style="width:100px;margin:0 10px 10px 0">
+                <Option v-for="item in invoiceSta" :value="item.v" :key="item.v">{{ item.n }}</Option>
+            </Select>
+            <Select size="large" placeholder="付款方式" clearable v-model="filter.payWay" style="width:100px;margin:0 10px 10px 0">
+                <Option v-for="item in payStatus" :value="item.v" :key="item.v">{{ item.n }}</Option>
+            </Select>
+            <Input 
+                type="text" 
+                size="large" 
+                v-model="filter.payMoneyMin" 
+                placeholder="最小金额" 
+                clearable
+                prefix="logo-yen"
+                style="width:90px;height:36px:margin-bottom:10px" 
+            ></Input>
+            <Input 
+                type="text" 
+                size="large" 
+                v-model="filter.payMoneyMax" 
+                placeholder="最大金额" 
+                clearable
+                prefix="logo-yen"
+                style="width:90px;height:36px;margin: 0 10px 10px 2px;" 
+            />
+            <DatePicker 
+                type="datetime" 
+                size="large" 
+                v-model="dataVal1"
+                placeholder="起始时间" 
+                style="width: 172px" 
+                :options="options1"
+                @on-change="handleChange1"
+                @on-ok="confirmed1"
+                @on-open-change="opened1"
+            ></DatePicker>
+            <DatePicker 
+                type="datetime" 
+                size="large" 
+                v-model="dataVal2"
+                placeholder="截止时间" 
+                style="width: 172px;margin-left:2px;margin-right:10px" 
+                :options="options2"
+                @on-change="handleChange2"
+                @on-ok="confirmed2"
+                @on-open-change="opened2"
+            ></DatePicker><br/>
+            <Select 
+                size="large" 
+                placeholder="付费类型" 
+                clearable 
+                v-model="filter.payType" 
+                style="width:100px;margin:0 10px 10px 0"
+                v-show="select1"
+            >
+                <Option v-for="item in payCont" :value="item.v" :key="item.v">{{ item.n }}</Option>
+            </Select>
+            <Select 
+                size="large" 
+                placeholder="数据规格" 
+                clearable 
+                v-model="filter.dataType" 
+                style="width:100px;margin:0 10px 10px 0"
+                v-show="select2"
+            >
+                <Option v-for="item in dataCont" :value="item.v" :key="item.v">{{ item.n }}</Option>
+            </Select>
+            <Select 
+                size="large" 
+                placeholder="发票开具方" 
+                clearable 
+                v-model="filter.invoiceType" 
+                style="width:110px;margin:0 10px 10px 0"
+                v-show="select3"
+            >
+                <Option v-for="item in invoicePerson" :value="item.v" :key="item.v">{{ item.n }}</Option>
+            </Select><br v-show="select1 || select2 || select3"/>
+        </template>
+        <template slot="exportData" v-if="flag">
+            <Button type="primary" size="large" @click="orderExport" style="margin: 0 0 10px 10px">导出结果</Button>
+        </template>
+        <Table 
+            size="large" 
+            ellipsis 
+            :loading="loading" 
+            ref="selection" 
+            :columns="columns" 
+            :data="list.lists" 
+            stripe
+        >
+            <template slot-scope="{ row }" slot="type">
+            <field-map :value="row.type" :map="type"></field-map>
+            </template>
+            <template slot-scope="{ row }" slot="_action">
+            <Tooltip :content="row.call" :max-width="500">
+                {{row.action}}
+            </Tooltip>
+            </template>
+            <template slot-scope="{ row }" slot="op">
+            <Button 
+                class="find-btn" 
+                size="small" 
+                type="primary" 
+                style="margin-right:5px"
+            >
+                <router-link :to="{path:'/order/orderList/orderDetail',query:{id:row.id,proType:row.product_type}}" target="_blank" style="color:#fff">查看</router-link>
+            </Button>
+            <Button 
+                class="find-btn" 
+                size="small" 
+                type="error" 
+                @click="refund(row.order_code)"
+                :disabled="row.order_status != 1"
+            >退款</Button>
+            </template>
+        </Table>
+        <template slot="options">
+            <div style="color:#d7d7d7;font-size:14px">共计{{list.total}}个订单,实付金额¥{{list.money>=0?list.money:0}}</div>
+        </template>
+    </table-lists>
+    <Modal title="退款原因" v-model="models.tShow">
+        <Input type="textarea" size="large" :rows="3" placeholder="请填写退款原因" v-model="models.cause"></Input>
+        <div slot="footer">
+            <Button type="primary" size="large" @click="subSave">提交</Button>
+        </div>
+    </Modal>
+  </div>
+</template>
+<script>
+import { ChangeDate,ChangeDate2 } from '../../assets/js/date.js'
+export default {
+    watch: {
+        'filter.productType': {
+            handler(newVal) {
+                if (newVal == '0') {
+                    this.select1 = true
+                    this.select2 = false
+                    this.select3 = false
+                    this.filter.dataType = ''
+                    this.filter.invoiceType = ''
+                } else if (newVal == '2') {
+                    this.select2 = true
+                    this.select1 = false
+                    this.select3 = false
+                    this.filter.payType = ''
+                    this.filter.invoiceType = ''
+                } else if (newVal == '4') {
+                    this.select3 = true
+                    this.select1 = false
+                    this.select2 = false
+                    this.filter.dataType = ''
+                    this.filter.payType = ''
+                } else {
+                    this.select1 = false
+                    this.select2 = false
+                    this.select3 = false
+                    this.filter.payType = ''
+                    this.filter.dataType = ''
+                    this.filter.invoiceType = ''
+                }
+            },
+            deep: true
+        }
+    },
+    methods: {
+        screened () {
+            this.flag = !this.flag
+            if (this.flag) {
+                this.filterType = 1
+                this.filterReset = 1
+            } else {
+                this.filterType = 0
+                this.filterReset = 0
+            }
+        },
+        load (val) {
+            this.loading = val
+        },
+        emptyFilter (val) {
+            if (val) {
+                this.filter.keyword = ''
+                this.filter.productType = ''
+                this.filter.orderType = ''
+                this.filter.orderStatus = ''
+                this.filter.invoiceStatus = ''
+                this.filter.payMoneyMin = ''
+                this.filter.payMoneyMax = ''
+                this.filter.orderTimeStart = ''
+                this.filter.orderTimeEnd = ''
+                this.filter.payWay = ''
+                this.filter.payType = ''
+                this.filter.dataType = ''
+                this.filter.invoiceType = ''
+                this.dataVal1 = ''
+                this.dataVal2 = ''
+            }
+        },
+        handleChange1 (date) {
+            this.filter.orderTimeStart = date
+        },
+        handleChange2 (date) {
+            this.filter.orderTimeEnd = date
+        },
+        confirmed1 () {
+            if (this.filter.orderTimeStart && this.filter.orderTimeEnd) {
+                if (this.filter.orderTimeStart > this.filter.orderTimeEnd) {
+                    this.dataVal1 = ''
+                    this.filter.orderTimeStart = ''
+                    this.$Notice.warning({
+                        title: '警告提示',
+                        desc: "起始时间应小于截止时间",
+                        duration: 5
+                    })
+                }
+            }
+        },
+        confirmed2 () {
+            if (this.filter.orderTimeStart && this.filter.orderTimeEnd) {
+                if (this.filter.orderTimeStart > this.filter.orderTimeEnd) {
+                    this.dataVal2 = ''
+                    this.filter.orderTimeEnd = ''
+                    this.$Notice.warning({
+                        title: '警告提示',
+                        desc: "截止时间应大于起始时间",
+                        duration: 5
+                    })
+                }
+            }
+        },
+        opened1 (val) {
+            if (val) {
+                return
+            } else {
+                this.confirmed1()
+            }
+        },
+        opened2 (val) {
+            if (val) {
+                return
+            } else {
+                this.confirmed2()
+            }
+        },
+        refund (code) {
+            this.models.tShow = true
+            this.models.reCode = code
+        },
+        orderExport() {
+            if (this.list.lists.length == 0) {
+                this.$Notice.warning({
+                    title: '警告提示',
+                    desc: "暂无相应数据",
+                    duration: 5
+                })
+                return
+            }
+            let obj = {
+                productType: this.filter.productType,
+                orderStatus: this.filter.orderStatus,
+                invoiceStatus: this.filter.invoiceStatus,
+                payWay: this.filter.payWay,
+                orderTimeStart: this.filter.orderTimeStart,
+                orderTimeEnd: this.filter.orderTimeEnd,
+                payMoneyMin: this.filter.payMoneyMin,
+                payMoneyMax: this.filter.payMoneyMax,
+                orderType: this.filter.orderType,
+                payType: this.filter.payType,
+                dataType: this.filter.dataType,
+                invoiceType: this.filter.invoiceType
+            }
+            this.$Modal.confirm({
+                title: "确定导出结果吗?",
+                onOk: () => {
+                    this.$request('/order/orderList/exportOrder').data(obj).success((res) => {
+                        if (res.data.path) {
+                            window.location.href = res.data.path
+                            this.reload()
+                        } else {
+                            this.$Notice.warning({
+                                title: '警告提示',
+                                desc: "暂无相应数据",
+                                duration: 5
+                            })
+                        }
+                    }).get()
+                }
+            })
+        },
+        subSave () {
+            var curTime = new Date().getTime()
+            this.$request('/order/orderList/confirmRefund').data({
+                orderCode: this.models.reCode,
+                applyReason: this.models.cause,
+                applyTime: ChangeDate2(curTime)
+            }).showSuccessTip().success(() => {
+                this.models.tShow = false
+                this.reload()
+            }).get()
+        },
+        reload () {
+            this.$refs.tableLists.reload(true)
+        }
+    },
+    data () {
+        return {
+            lis: '',
+            loading: false,
+            models: {
+                tShow: false,
+                cause: '',
+                reCode: ''
+            },
+            proType: [
+                {v: '', n: '全部'},
+                {v: '0', n: '超级订阅'},
+                {v: '1', n: '数据报告'},
+                {v: '2', n: '历史数据'},
+                {v: '3', n: '招投标课程'},
+                {v: '4', n: '线上课程'},
+                {v: '5', n: '企业商机管理'}
+            ],
+            orderTips: [
+                {v: '', n: '全部'},
+                {v: '0', n: '分销'},
+                {v: '1', n: '直销'}
+            ],
+            orderSta: [
+                {v: '', n: '全部'},
+                {v: '-3', n: '已退款'},
+                {v: '-2', n: '已取消'},
+                {v: '-1', n: '逻辑删除'},
+                {v: '0', n: '未支付'},
+                {v: '1', n: '已支付'}
+            ],
+            invoiceSta: [
+                {v: '', n: '全部'},
+                {v: '-2', n: '已冲红'},
+                {v: '0', n: '未申请'},
+                {v: '1', n: '已申请'}
+            ],
+            payStatus: [
+                {v: '', n: '全部'},
+                {v: '0', n: '支付宝'},
+                {v: '1', n: '微信'},
+                {v: '2', n: '线下支付'},
+                {v: '3', n: '对公转账'},
+                {v: '4', n: '其它'}
+            ],
+            payCont: [
+                {v: '', n: '全部'},
+                {v: '0', n: '试用'},
+                {v: '1', n: '续费'},
+                {v: '2', n: '升级'},
+                {v: '3', n: '购买'}
+            ],
+            dataCont: [
+                {v: '', n: '全部'},
+                {v: '标准字段包', n: '标准字段包'},
+                {v: '高级字段包', n: '高级字段包'}
+            ],
+            invoicePerson: [
+                {v: '', n: '全部'},
+                {v: '0', n: '汇学网'},
+                {v: '1', n: '王凯精品课'}
+            ],
+            filter: {
+                // keyword: '',
+                productType: '',
+                orderType: '',
+                orderStatus: '',
+                invoiceStatus: '',
+                orderTimeStart: '',
+                orderTimeEnd: '',
+                payMoneyMin: '',
+                payMoneyMax: '',
+                payWay: '',
+                payType: '',
+                dataType: '',
+                invoiceType: ''
+            },
+            sear: {
+                keyword: ''
+            },
+            dataVal1: '',
+            dataVal2: '',
+            options1: {
+                disabledDate: (function(date) {
+                    var timeEnd = ChangeDate(this.filter.orderTimeEnd)
+                    var p_time = new Date(timeEnd).getTime()
+                    return date && date.valueOf() > p_time;
+                }).bind(this)
+            },
+            options2: {
+                disabledDate: (function(date) {
+                    var timeStart = ChangeDate(this.filter.orderTimeStart)
+                    var p_time = new Date(timeStart).getTime()
+                    return date && date.valueOf() < p_time;
+                }).bind(this)
+            },
+            columns: [
+                {
+                    title: '订单编号',
+                    key: 'order_code',
+                    align: 'center'
+                },
+                {
+                    title: '产品类型',
+                    key: 'product_type',
+                    width: '150',
+                    align: 'center',
+                    render: (h, {row}) => {
+                        let words = row.product_type
+                        let vipType = ''
+                        if (row.vip_type == 0) {
+                            vipType = '(试用)'
+                        } else if (row.vip_type == 1) {
+                            vipType = '(续费)'
+                        } else if (row.vip_type == 2) {
+                            vipType = '(升级)'
+                        } else if (row.vip_type == null) {
+                            if (row.pay_way == "trial") {
+                                vipType = '(试用)'
+                            } else {
+                                vipType = '(购买)'
+                            }
+                        }
+                        return h('span', words == 'VIP订阅' || words == 'vip订阅' ? '超级订阅' + vipType : row.product_type)
+                    }
+                },
+                {
+                    title: '订单类型',
+                    key: 'dis_word',
+                    align: 'center',
+                    render: (h, {row}) => {
+                        let word = row.dis_word
+                        return h('span', word ? '分销' : '直销')
+                    }
+                },
+                {
+                    title: '订单时间',
+                    key: 'create_time',
+                    width: '170',
+                    align: 'center'
+                },
+                {
+                    title: '实付金额',
+                    key: 'pay_money',
+                    align: 'center',
+                    render: (h, {row}) => {
+                        return h('span','¥' + parseFloat(row.pay_money?row.pay_money/100:0).toLocaleString('en-US'))
+                    }
+                },
+                {
+                    title: '订单状态',
+                    key: 'order_status',
+                    align: 'center',
+                    render: (h, {row}) => {
+                        switch (row.order_status) {
+                        case -3 :
+                            return h('div', {
+                                style: {
+                                    color: '#f4516c'
+                                }
+                            }, [
+                                h('span','已退款')
+                            ])
+                        case -2 :
+                            return h('div', {
+                                style: {
+                                    color: '#ffb822'
+                                }
+                            }, [
+                                h('span','已取消')
+                            ])
+                        case -1 :
+                            return h('div', {
+                                style: {
+                                    color: '#f4516c'
+                                }
+                            }, [
+                                h('span','逻辑删除')
+                            ])
+                        case 0 :
+                            return h('div', {
+                                style: {
+                                    color: '#f4516c'
+                                }
+                            }, [
+                                h('span','未支付')
+                            ])
+                        case 1 :
+                            return h('div', {
+                                style: {
+                                    color: '#34bfa3'
+                                }
+                            }, [
+                                h('span', '已支付')
+                            ])
+                        }
+                    }
+                },
+                {
+                    title: '发票状态',
+                    key: 'invoice_status',
+                    align: 'center',
+                    render: (h, {row}) => {
+                        if (row.order_status == -3) {
+                            if (row.applybill_status == 1) {
+                                return h('div', {
+                                    style:{
+                                        color: '#f4516c'
+                                    }
+                                }, [
+                                    h('span','已冲红')
+                                ])
+                            } else if (row.applybill_status == 0) {
+                                return h('div', {
+                                    style: {
+                                        color: '#ffb822'
+                                    }
+                                }, [
+                                    h('span','未申请')
+                                ])
+                            }
+                        } else {
+                            if (row.applybill_status == 1) {
+                                return h('div', {
+                                    style:{
+                                        color: '#34bfa3'
+                                    }
+                                }, [
+                                    h('span','已申请')
+                                ])
+                            } else if (row.applybill_status == 0) {
+                                return h('div', {
+                                    style: {
+                                        color: '#ffb822'
+                                    }
+                                }, [
+                                    h('span','未申请')
+                                ])
+                            }
+                        }
+                    }
+                },
+                {
+                    title: '操作',
+                    slot: 'op',
+                    align: 'center'
+                },
+            ],
+            list: []
+        }
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+.ding-dan {
+    h1 {
+        font-size:24px;
+        color:#3f4047;
+        padding: 10px 0 20px 10px;
+    }
+    .tui-btn {
+        color: #f4516c;
+    }
+    .ser-ipt {
+        float: right;
+        width: 162px;
+    }
+    .shai_xuan {
+        font-size: 18px;
+        span {
+            cursor: pointer;
+        }
+    }
+     .arrowTransform{
+        transition: 0.2s;
+        transform-origin: center;
+        transform: rotateZ(180deg);
+    }
+    .arrowTransformReturn{
+        transition: 0.2s;
+        transform-origin: center;
+        transform: rotateZ(0deg);
+    }
+}
+</style>

+ 261 - 0
src/views/sales/commissionList.vue

@@ -0,0 +1,261 @@
+<template>
+  <div class="yong-jin">
+    <h1>佣金列表</h1>
+    <table-lists 
+        ref="tableLists" 
+        v-model="list" 
+        :filter="filter" 
+        :sear="sear"
+        :filterSear="2"
+        requestApi="/sales/commissionList" 
+        @loading="load" 
+        @emptyFilter="emptyFilter"
+        style="background:#fff;padding:10px"
+    >
+      <template slot="filterContent">
+        <FormItem label="产品:" :label-width="50">
+            <Select size="large" placeholder="全部" clearable v-model="filter.product" style="width:100px">
+                <Option v-for="item in product" :value="item.v" :key="item.v">{{ item.n }}</Option>
+            </Select>
+        </FormItem>
+        <FormItem label="销售金额:" :label-width="70">
+            <Input style="width: 73px" type="text" size="large" v-model="filter.salesMin" placeholder="最小金额" clearable/>
+            <Input style="width: 73px;margin-left: 2px" type="text" size="large" v-model="filter.salesMax" placeholder="最大金额" clearable/>
+        </FormItem>
+        <FormItem label="佣金金额:" :label-width="70">
+            <Input style="width: 73px" type="text" size="large" v-model="filter.commissionMin" placeholder="最小金额" clearable/>
+            <Input style="width: 73px;margin-left: 2px" type="text" size="large" v-model="filter.commissionMax" placeholder="最大金额" clearable/>
+        </FormItem>
+        <FormItem label="订单日期:" :label-width="70" style="margin-right: 30px">
+            <DatePicker 
+                type="datetime" 
+                size="large"
+                v-model="dataValue1"
+                placeholder="起始时间" 
+                format="yyyy-MM-dd HH:mm:ss"
+                style="width: 172px"
+                :options="options1"
+                @on-change="handleChange1"
+                @on-ok="confirmed1"
+                @on-open-change="opened1"
+            ></DatePicker>
+            <DatePicker 
+                type="datetime" 
+                size="large"
+                v-model="dataValue2"
+                placeholder="截止时间" 
+                format="yyyy-MM-dd HH:mm:ss"
+                style="width:172px; margin-left:2px"
+                :options="options2"
+                @on-change="handleChange2"
+                @on-ok="confirmed2"
+                @on-open-change="opened2"
+            ></DatePicker>
+        </FormItem>
+      </template>
+      <template slot="filterRight">
+          <Input suffix="md-search" type="text" size="large" v-model="sear.keyword" placeholder="搜索单号或手机号" clearable class="ser-ipt"/>
+      </template>
+      <Table size="large" ellipsis :loading="loading" ref="selection" :columns="columns" :data="list.lists" stripe>
+        <template slot-scope="{ row }" slot="type">
+          <field-map :value="row.type" :map="type"></field-map>
+        </template>
+        <template slot-scope="{ row }" slot="_action">
+          <Tooltip :content="row.call" :max-width="500">
+            {{row.action}}
+          </Tooltip>
+        </template>
+        <template slot-scope="{ row }" slot="op">
+          <Button 
+            size="small" 
+            type="primary" 
+          >
+            <router-link 
+                :to="{path:'/order/orderList/orderDetail',query:{id:row.order_id,proType:row.product_name}}"
+                target="_blank"
+                style="color:#fff"
+            >订单</router-link>
+        </Button>
+        </template>
+      </Table>
+      <template slot="options">
+        <div style="color:#d7d7d7;font-size:14px">共计{{list.total?list.total:'0'}}条佣金记录</div>
+      </template>
+    </table-lists>
+  </div>
+</template>
+<script>
+import { ChangeDate } from '../../assets/js/date.js'
+export default {
+    methods: {
+        load (val) {
+            this.loading = val
+        },
+        emptyFilter (val) {
+            if (val) {
+                this.filter.keyword = ''
+                this.filter.product = ''
+                this.filter.salesMin = ''
+                this.filter.salesMax = ''
+                this.filter.commissionMin = ''
+                this.filter.commissionMax = ''
+                this.filter.orderTimeMin = ''
+                this.filter.orderTimeMax = ''
+                this.dataValue1=''
+                this.dataValue2=''
+            }
+        },
+        handleChange1 (date) {
+            this.filter.orderTimeMin = date
+        },
+        handleChange2 (date) {
+            this.filter.orderTimeMax = date
+        },
+        confirmed1 () {
+            if (this.filter.orderTimeMin && this.filter.orderTimeMax) {
+                if (this.filter.orderTimeMin > this.filter.orderTimeMax) {
+                    this.dataValue1 = ''
+                    this.filter.orderTimeMin = ''
+                    this.$Notice.warning({
+                        title: '警告提示',
+                        desc: "起始时间应小于截止时间",
+                        duration: 5
+                    })
+                }
+            }
+        },
+        confirmed2 () {
+            if (this.filter.orderTimeMin && this.filter.orderTimeMax) {
+                if (this.filter.orderTimeMin > this.filter.orderTimeMax) {
+                    this.dataValue2 = ''
+                    this.filter.orderTimeMax = ''
+                    this.$Notice.warning({
+                        title: '警告提示',
+                        desc: "截止时间应大于起始时间",
+                        duration: 5
+                    })
+                }
+            }
+        },
+        opened1 (val) {
+            if (val) {
+                return
+            } else {
+                this.confirmed1()
+            }
+        },
+        opened2 (val) {
+            if (val) {
+                return
+            } else {
+                this.confirmed2()
+            }
+        },
+    },
+    data () {
+        return {
+            lis: '',
+            loading: false,
+            dataValue1: '',
+            dataValue2: '',
+            product: [
+                {v: '', n: '全部'},
+                {v: '1', n: '超级订阅'},
+                {v: '2', n: '数据导出'},
+                {v: '3', n: '数据报告'}
+            ],
+            filter: {
+            //   keyword: '',
+                product: '',
+                salesMin: '',
+                salesMax: '',
+                commissionMin: '',
+                commissionMax: '',
+                orderTimeMin: '',
+                orderTimeMax: ''
+            },
+            sear: {
+                keyword: '',
+            },
+            options1: {
+                disabledDate: (function(date) {
+                    var timeEnd = ChangeDate(this.filter.orderTimeMax)
+                    var p_time = new Date(timeEnd).getTime()
+                    return date && date.valueOf() > p_time;
+                }).bind(this)
+            },
+            options2: {
+                disabledDate: (function(date) {
+                    var timeStart = ChangeDate(this.filter.orderTimeMin)
+                    var p_time = new Date(timeStart).getTime()
+                    return date && date.valueOf() < p_time;
+                }).bind(this)
+            },
+            columns: [
+                {
+                    title: '佣金单号',
+                    key: 'code',
+                    align: 'center'
+                },
+                {
+                    title: '手机号',
+                    key: 'phone',
+                    align: 'center'
+                },
+                {
+                    title: '订单日期',
+                    key: 'createtime',
+                    width: '170',
+                    align: 'center'
+                },
+                {
+                    title: '产品名称',
+                    key: 'product_name',
+                    align: 'center'
+                },
+                {
+                    title: '销售金额',
+                    key: 'sale_money',
+                    align: 'center',
+                    render: (h, {row}) => {
+                    return h('span','¥' + parseFloat(row.sale_money/100).toLocaleString('en-US'))
+                    }
+                },
+                {
+                    title: '佣金比例',
+                    key: 'commission_rate',
+                    align: 'center'
+                },
+                {
+                    title: '佣金金额',
+                    key: 'commission',
+                    align: 'center',
+                    render: (h, {row}) => {
+                    return h('span','¥' + parseFloat(row.commission/100).toLocaleString('en-US'))
+                    }
+                },
+                {
+                    title: '操作',
+                    slot: 'op',
+                    align: 'center'
+                },
+            ],
+            list: []
+        }
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+.yong-jin {
+    h1 {
+        font-size:24px;
+        color:#3f4047;
+        padding: 10px 0 20px 10px;
+    }
+    .ser-ipt {
+    
+    width: 162px;
+    }
+}
+</style>

+ 175 - 0
src/views/sales/components/details.vue

@@ -0,0 +1,175 @@
+<template>
+    <div class="details">
+        <!-- 提现列表详情 -->
+        <div class="infor-card" v-if="deType == 'tixian'">
+            <div v-if="peType == '1'">
+                <div class="con">
+                    <span>支付宝实名</span>
+                    <span class="spa2">{{details.name}}</span>
+                </div>
+                <Divider />
+                <div class="con">
+                    <span>支付宝账户</span>
+                    <span class="spa2">{{details.account}}</span>
+                </div>
+            </div>
+            <div v-else>
+                <div class="con">
+                    <span>公司名称</span>
+                    <span class="spa2">{{details.name}}</span>
+                </div>
+                <Divider />
+                <div class="con">
+                    <span>银行名称</span>
+                    <span class="spa2">{{details.openBank}}</span>
+                </div>
+            </div>
+            <Divider />
+            <div class="con">
+                <span>提现方式</span>
+                <span class="spa2">{{details.type == '1'?'支付宝':'对公转账'}}</span>
+            </div>
+            <Divider />
+            <div class="con">
+                <span>提现金额</span>
+                <span class="spa2">¥{{(details.money/100).toLocaleString('en-US')}}</span>
+            </div>
+            <Divider />
+            <div class="con">
+                <span>提现单号</span>
+                <span class="spa2">{{details.code}}</span>
+            </div>
+            <Divider />
+            <div class="con">
+                <span>提现时间</span>
+                <span class="spa2">{{details.createtime}}</span>
+            </div>
+            <Divider />
+            <div class="con">
+                <span>当前状态</span>
+                <span class="spa2" :class="details.cashout_status == 0 ? 'color1' : 'color2'">{{details.cashout_status | casStatus}}</span>
+            </div>
+            <Divider />
+        </div>
+        <!-- 结算列表详情 -->
+        <div class="infor-card" v-else>
+            <div class="con">
+                <span>手机号</span>
+                <span class="spa2">{{settleDet.phone}}</span>
+            </div>
+            <Divider />
+            <div class="con">
+                <span>结算时间</span>
+                <span class="spa2">{{settleDet.createtime}}</span>
+            </div>
+            <Divider />
+            <div class="con">
+                <span>销售金额</span>
+                <span class="spa2">¥{{(settleDet.sale_cash/100).toLocaleString('en-US')}}</span>
+            </div>
+            <Divider />
+            <div class="con">
+                <span>佣金金额</span>
+                <span class="spa2">¥{{(settleDet.commission/100).toLocaleString('en-US')}}</span>
+            </div>
+            <Divider />
+            <div class="con">
+                <span>个税金额</span>
+                <span class="spa2">¥{{(settleDet.tax_cash/100).toLocaleString('en-US')}}</span>
+            </div>
+            <Divider />
+            <div class="con">
+                <span>认证金额</span>
+                <span class="spa2">¥{{(settleDet.auth_cash/100).toLocaleString('en-US')}}</span>
+            </div>
+            <Divider />
+            <div class="con">
+                <span>提现金额</span>
+                <span class="spa2">¥{{(settleDet.can_cash/100).toLocaleString('en-US')}}</span>
+            </div>
+            <Divider />
+            <!-- <div class="con">
+                <span>当前状态</span>
+                <span class="spa2">{{settleDet.}}</span>
+            </div>
+            <Divider /> -->
+            <div class="con">
+                <span>结算单号</span>
+                <span class="spa2">{{settleDet.code}}</span>
+            </div>
+            <Divider />
+        </div>
+    </div>
+</template>
+
+<script>
+export default {
+    props:{
+        deType: String,
+        peType: String
+    },
+    created() {
+        let rout = this.$route.query
+        if (rout.deType == 'tixian') {
+            this.$request('/sales/withdrawList/withdrawDetail').data({
+                uid: rout.uid,
+                id: rout.id,
+                type: rout.peType
+            }).success((r) => {
+                this.details = r.data;
+            }).get()
+        } else {
+            this.$request('/sales/settleList/settleDetails').data({
+                uid: rout.uid,
+                id: rout.id
+            }).success((r) => {
+                this.settleDet = r.data;
+            }).get()
+        }
+    },
+    data () {
+        return {
+            details: [],
+            settleDet: []
+        }
+    },
+    filters: {
+        casStatus (val) {
+            if (val == -1) {
+                return "失败"
+            } else if (val == 0) {
+                return "已申请"
+            } else if (val == 1) {
+                return "已完成"
+            }
+        }
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+.details {
+    .infor-card {
+        margin: 50px auto;
+        width: 500px;
+        .con {
+            padding: 5px 30px;
+            font-size: 16px;
+            span {
+                display: inline-block;
+                width: 50%;
+            }
+            .spa2 {
+                text-align: right;
+                
+            }
+            .color1 {
+                color: #f4516c;
+            }
+            .color2 {
+                color: #34bfa3;
+            }
+        }
+    }
+}
+</style>

+ 511 - 0
src/views/sales/partnerDetail.vue

@@ -0,0 +1,511 @@
+<template>
+    <div class="partner-detail">
+        <h1>剑鱼伙伴</h1>
+        <Row class="par-row">
+            <Col style="float:left;width: 20%" class="top-col">
+                <Card>
+                    <div slot="title" class="top-tit">
+                        <div class="avatr">
+                            <img :src="parDetail.headImg" v-if="parDetail.headImg">
+                            <img src="../../assets/images/moren.png" v-else>
+                        </div>
+                        <div class="names">{{parDetail.name}}</div>
+                        <div class="msg1"><span>{{parDetail.phone}}</span></div>
+                        <div class="msg1 msg2"><span>{{parDetail.email}}</span></div>
+                    </div>
+                    <div class="bot-tit">
+                        <div class="over-view" @click="tabClick(1)" :class="{active:infor === 1}"><span>概览</span></div>
+                        <div class="basic" @click="tabClick(2)" :class="{active:infor === 2}"><span>基本信息<i :class="parDetail.auth_status | authColor">{{parDetail.auth_status | authStatus}}</i></span></div>
+                        <div class="fund" @click="tabClick(3)" :class="{active:infor === 3}"><span>资金明细</span></div>
+                    </div>
+                </Card>
+            </Col>
+            <Col style="float:left;width: 77.5%">
+                <Card v-if="infor == 1">
+                    <div slot="title" class="right-fund">概览</div>
+                    <div class="msg-card">
+                        <Card>
+                            <div class="add-time">
+                                <div class="time1"><img src="../../assets/images/riqi.png" />加入日期</div>
+                                <div class="time2">{{parDetail.createtime}}</div>
+                            </div>
+                        </Card>
+                        <Card>
+                            <div class="add-time">
+                                <div class="time1"><img src="../../assets/images/riqi.png" />最后使用日期</div>
+                                <div class="time2">{{parDetail.lastlogintime}}</div>
+                            </div>
+                        </Card>
+                        <Card>
+                            <div class="add-time">
+                                <div class="time1"><img src="../../assets/images/yongjin.png" />累计销售额</div>
+                                <div class="time2">¥{{(parDetail.dis_sales/100).toLocaleString('en-US')}}</div>
+                            </div>
+                        </Card>
+                        <Card>
+                            <div class="add-time">
+                                <div class="time1"><img src="../../assets/images/dingdan.png" />累计销售订单</div>
+                                <div class="time2">{{parDetail.dis_order}}</div>
+                            </div>
+                        </Card>
+                        <Card>
+                            <div class="add-time">
+                                <div class="time1"><img src="../../assets/images/yongjin.png" />累计佣金</div>
+                                <div class="time2">¥{{(parDetail.dis_commission/100).toLocaleString('en-US')}}</div>
+                            </div>
+                        </Card>
+                    </div>
+                    <Table 
+                        size="large"
+                        ellipsis 
+                        :loading="loading" 
+                        :columns="column1" 
+                        :data="datas1" 
+                        stripe 
+                        style="margin-top: 30px"
+                        v-if="infor == 1"
+                    ></Table>
+                </Card>
+                <Card v-else-if="infor == 2">
+                    <div slot="title" class="right-fund">基本信息</div>
+                    <div class="infor-card">
+                        <div class="con" v-if="types == '2'">
+                            <span>企业名称</span>
+                            <span class="spa2">{{parDetail.name}}</span>
+                        </div>
+                        <div class="con" v-else>
+                            <span>用户名</span>
+                            <span class="spa2">{{parDetail.name}}</span>
+                        </div>
+                        <Divider />
+                        <div class="con">
+                            <span>手机</span>
+                            <span class="spa2">{{parDetail.phone}}</span>
+                        </div>
+                        <Divider />
+                        <div class="con">
+                            <span>邮箱</span>
+                            <span class="spa2">{{parDetail.email}}</span>
+                        </div>
+                        <Divider />
+                        <div class="con">
+                            <span>类型</span>
+                            <span class="spa2">{{parDetail.type == '1'?'个人':'企业'}}</span>
+                        </div>
+                        <Divider />
+                        <div class="con">
+                            <span>渠道</span>
+                            <span class="spa2">{{parDetail.channel}}</span>
+                        </div>
+                        <Divider />
+                        <div class="con" v-if="types == '2'">
+                            <span class="spa1">营业执照</span>
+                            <img class="imgs" @click="fruit" :src="parDetail.license"/>
+                        </div>
+                        <Divider v-if="types == '2'" />
+                    </div>
+                </Card>
+                <Card v-else>
+                    <div slot="title" class="right-fund">资金明细</div>
+                    <Table 
+                        size="large"
+                        ellipsis 
+                        :loading="loading" 
+                        :columns="column2" 
+                        :data="datas2" 
+                        stripe 
+                        style="margin-top: 10px"
+                        v-if="infor == 3"
+                    >
+                        <template slot-scope="{ row }" slot="_code">
+                            <div @click="rowsClick(row)">{{row.code}}</div>
+                        </template>
+                    </Table>
+                </Card>
+            </Col>
+        </Row>
+        <Modal v-model="preview" footer-hide :styles="{top:0}" :width="800" class-name="par-model">
+            <img :src="parDetail.license">
+        </Modal>
+    </div>
+</template>
+
+<script>
+import { ChangeDate } from '../../assets/js/date'
+export default {
+    created () {
+        let rout = this.$route.query
+        this.$request('/sales/partnerList/partnerDetail').data({// 基本信息
+            uid: rout.uid,
+            id: rout.id
+        }).success((r) => {
+            this.parDetail = r.data;
+            this.parDetail.createtime = ChangeDate(this.parDetail.createtime);
+            this.parDetail.lastlogintime = ChangeDate(this.parDetail.lastlogintime)
+        }).get()
+
+        this.$request('/sales/partnerList/overview').data({// 概览
+            uid: rout.uid,
+            id: rout.id
+        }).success((r) => {
+            this.datas1 = r.data?r.data:[];
+        }).get()
+
+        this.$request('/sales/partnerList/capitalDetails').data({// 资金明细
+            uid: rout.uid
+        }).success((r) => {
+            let atr = [], atr1 = []
+            // 按时间先后排序
+            if (r.data) {
+                r.data.forEach(e => {
+                    atr.push(new Date(e.createtime).getTime())
+                })
+                atr.sort(this.sortNum)
+                atr.forEach((v) => {
+                    r.data.forEach(res => {
+                        let ar = new Date(res.createtime).getTime()
+                        if (ar === v) {
+                            atr1.push(res)
+                        }
+                    })
+                })
+                this.datas2 = atr1
+            }
+        }).get()
+    },
+    methods: {
+        load(val) {
+            this.loading = val
+        },
+        sortNum (a, b) {
+            return b - a
+        },
+        tabClick(index) {
+            this.infor = index
+        },
+        fruit() {
+            this.preview = true
+        },
+        rowsClick (arr) {
+            if (arr.type == '佣金') {
+                const paths = this.$router.resolve({
+                    path: '/order/orderList/orderDetail', 
+                    query:{
+                        id: arr.order_id,
+                        proType: arr.product_name,
+                        par: 1
+                    }})
+                window.open(paths.href,'_blank')
+            } else if (arr.type == '提现') {
+                const paths = this.$router.resolve({
+                    path: '/sales/withdrawList/withdrawDetail', 
+                    query:{
+                        id: arr.id,
+                        uid: arr.uid,
+                        peType: String(arr.ptype),
+                        deType: 'tixian',
+                        par: 1
+                    }})
+                window.open(paths.href,'_blank')
+            } else if (arr.type == '结算') {
+                const paths = this.$router.resolve({
+                    path: '/sales/settleList/settleDetail', 
+                    query:{
+                        id: arr.id,
+                        uid: arr.uid,
+                        deType: 'jiesuan',
+                        par: 1
+                    }})
+                window.open(paths.href,'_blank')
+            }
+        }
+    },
+    filters: {
+        authStatus (val) {
+            if (val == -1) {
+                return '未通过'
+            } else if (val == 0) {
+                return '未认证'
+            } else if (val == 1) {
+                return '已认证'
+            }
+        },
+        authColor (val) {
+            if (val == -1) {
+                return 'color1'
+            } else if (val == 0) {
+                return 'color2'
+            } else if (val == 1) {
+                return 'color3'
+            }
+        },
+    },
+    data () {
+        return {
+            loading: false,
+            parDetail: [],
+            infor: 1,
+            types: this.$route.query.type,
+            preview: false,
+            datas1: [],
+            datas2: [],
+            column1: [
+                  {
+                      title: '产品名称',
+                      key: 'product_name',
+                      align: 'center'
+                  },
+                  {
+                      title: '累计销售额',
+                      key: 'sale_money_sum',
+                      align: 'center',
+                      render: (h, {row}) => {
+                        return h('span','¥' + parseFloat(row.sale_money_sum/100).toLocaleString('en-US'))
+                      }
+                  },
+                  {
+                      title: '累计销售订单',
+                      key: 'count',
+                      align: 'center'
+                  },
+                  {
+                      title: '累计佣金',
+                      key: 'commission_sum',
+                      align: 'center',
+                      render: (h, {row}) => {
+                        return h('span','¥' + parseFloat(row.commission_sum/100).toLocaleString('en-US'))
+                      }
+                  },
+                  {
+                      title: '平均佣金',
+                      key: 'average',
+                      align: 'center',
+                      render: (h, {row}) => {
+                        return h('span','¥' + parseFloat(row.average/100).toLocaleString('en-US'))
+                      }
+                  }
+              ],
+            column2: [
+                  {
+                      title: '订单号',
+                      slot: '_code',
+                      className: 'table-info-money',
+                      align: 'center'
+                  },
+                  {
+                      title: '类型',
+                      key: 'type',
+                      align: 'center'
+                  },
+                  {
+                      title: '时间',
+                      key: 'createtime',
+                      align: 'center'
+                  },
+                  {
+                      title: '金额',
+                      key: 'money',
+                      align: 'center',
+                      render: (h, {row}) => {
+                        return h('span','¥' + parseFloat(row.money/100).toLocaleString('en-US'))
+                      }
+                  }
+              ]
+        }
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+.partner-detail {
+    .par-row {
+        background:#Fff;
+        padding:20px 0 20px 15px;
+    }
+    h1 {
+        font-size:24px;
+        color:#3f4047;
+        padding: 10px 0 20px 10px;
+    }
+    .top-col {
+        margin-right: 20px;
+        .ivu-card /deep/ {
+            .ivu-card-head {
+                padding: 28px 0;
+            }
+            .ivu-card-body {
+                padding: 0px!important;
+            }
+        }
+    }
+    .top-tit {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        padding: 0 25px;
+        .avatr {
+            width: 80px; 
+            height: 80px; 
+            border: 2px solid #f4f5f8;
+            border-radius: 63px;
+            overflow: hidden;
+            margin: 20px 0 28px 0;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+        }
+        .names {
+            line-height: 23px;
+            font-size: 16px;
+            font-weight: 700;
+            color: #1b1c1e;
+            margin-bottom: 20px;
+        }
+        .msg1 {
+            width: 100%;
+            span {
+                display: block;
+                width: 100%;
+                height: 32px;
+                line-height: 20px;
+                color: #7b7e8a;
+                background: url(../../assets/images/shoujihao.png) no-repeat 6px top; 
+                background-size: 20px 20px;
+                padding-left: 40px;
+                word-break:break-all;
+            }
+        }
+        .msg2 {
+            span {
+                background: url(../../assets/images/youxiang.png) no-repeat 6px top;
+                background-size: 20px 20px;
+            }
+        }
+    }
+    .bot-tit {
+        padding: 20px 0;
+        div {
+            display: flex;
+            justify-content: center;
+            align-content: center;
+            align-items: center;
+            width: 100%!important;
+            height: 55px!important;
+            line-height: 55px!important;
+            color: #6f727d!important;
+            cursor: pointer;
+            &:hover {
+                span {
+                    color: #475962;
+                }
+            }
+            span {
+                width: 100%;
+                background-size: 20px 20px!important;
+                padding-left: 40px;
+                margin: 0 25px;
+            }
+        }
+        .over-view {
+            span {
+                background: url(../../assets/images/gailan.png) no-repeat 6px center;
+            }
+        }
+        .basic {
+            span {
+                background: url(../../assets/images/xinxi.png) no-repeat 6px center; 
+            }
+            i {
+                display: inline-block;
+                width: 60px;
+                color: #70b603;
+                text-align: right;
+            }
+            .color1 {
+                color: #f4516c;
+            }
+            .color2 {
+                color: #ffb822;
+            }
+            .color3 {
+                color: #34bfa3;
+            }
+        }
+        .fund {
+            span {
+                background: url(../../assets/images/mingxi.png) no-repeat 6px center;
+            }
+        }
+        .active {
+            background:rgba(54,163,247, 0.2);
+        }
+    }
+    .right-fund {
+        font-size: 16px;
+        color: #575962;
+    }
+    .msg-card {
+        display: flex;
+        justify-content: center;
+        flex-direction: initial;
+        align-items: center;
+        .ivu-card {
+            overflow:hidden;
+            width: 252px;
+        }
+        .ivu-card:not(:last-child) {
+            margin-right: 20px;
+        }
+        .add-time {
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            font-weight: 700;
+            color: #1b1c1e;
+            .time1 {
+                display: flex;
+                flex-direction: initial;
+                justify-content: center;
+                align-items: center;
+                width: 100%;
+                height: 40px;
+                font-size: 14px;
+                img {
+                    width: 24px;
+                    height: 24px;
+                    margin-right: 8px;
+                }
+            }
+            .time2 {
+                font-size: 18px;
+            }
+        }
+    }
+    .infor-card {
+        margin: 30px auto;
+        width: 500px;
+        .con {
+            padding: 5px 30px;
+            font-size: 15px;
+            span {
+                display: inline-block;
+                width: 50%;
+            }
+            .spa2 {
+                text-align: right;
+                
+            }
+            .spa1 {
+                float: left;
+            }
+            .imgs {
+                float: right;
+                width: 192px;
+                min-height: 197px;
+                margin-bottom: 30px;
+                cursor: pointer;
+            }
+        }
+    }
+}
+</style>

+ 172 - 0
src/views/sales/partnerList.vue

@@ -0,0 +1,172 @@
+<template>
+  <div class="huo-ban">
+    <h1>剑鱼伙伴</h1>
+    <table-lists 
+      ref="tableLists" 
+      v-model="list" 
+      :filter="filter" 
+      :sear="sear"
+      :filterSear="2"
+      requestApi="/sales/partnerList" 
+      @loading="load" 
+      @emptyFilter="emptyFilter" 
+      style="background:#fff;padding:10px"
+    >
+      <template slot="filterContent">
+        <FormItem label="类型:" :label-width="50">
+            <Select size="large" placeholder="全部" clearable v-model="filter.type" style="width:100px">
+              <Option v-for="item in parType" :value="item.v" :key="item.v">{{ item.n }}</Option>
+            </Select>
+        </FormItem>
+        <FormItem label="累计销售:" :label-width="70">
+            <Input style="width: 73px" type="text" size="large" placeholder="最小金额" v-model="filter.salesMin" clearable/>
+            <Input style="width: 73px;margin-left: 2px" type="text" size="large" v-model="filter.salesMax" placeholder="最大金额" clearable/>
+        </FormItem>
+        <FormItem label="累计佣金:" :label-width="70">
+            <Input style="width: 73px" type="text" size="large" v-model="filter.commissionMin" placeholder="最小金额" clearable/>
+            <Input style="width: 73px;margin-left: 2px" type="text" size="large" v-model="filter.commissionMax" placeholder="最大金额" clearable/>
+        </FormItem>
+        <FormItem label="累计单数:" :label-width="70" style="margin-right: 40px">
+            <Input style="width: 73px" type="text" size="large" v-model="filter.orderMin" placeholder="最小单数" clearable/>
+            <Input style="width: 73px;margin-left: 2px" type="text" size="large" v-model="filter.orderMax" placeholder="最大单数" clearable/>
+        </FormItem>
+      </template>
+      <template slot="filterRight">
+          <Input suffix="md-search" type="text" size="large" v-model="sear.keyword" placeholder="搜索名称或手机号" clearable class="ser-ipt"/>
+      </template>
+      <Table size="large" ellipsis :loading="loading" :columns="columns" :data="list.lists" stripe>
+        <template slot-scope="{ row }" slot="type">
+          <div>{{row.type == '1'?'个人':'企业'}}</div>
+        </template>
+        <template slot-scope="{ row }" slot="_action">
+          <Tooltip :content="row.call" :max-width="500">
+            {{row.action}}
+          </Tooltip>
+        </template>
+        <template slot-scope="{ row }" slot="op">
+          <Button size="small" type="primary">
+            <router-link 
+              :to="{path:'/sales/partnerList/partnerDetail',query:{uid: row.uid, id: row.id, type: row.type}}"
+              target="_blank"
+              style="color:#fff"
+            >查看</router-link>
+            </Button>
+        </template>
+      </Table>
+      <template slot="options">
+        <div style="color:#d7d7d7;font-size:14px">共计{{list.total ? list.total : '0'}}位剑鱼伙伴</div>
+      </template>
+    </table-lists>
+  </div>
+</template>
+<script>
+export default {
+  methods: {
+    load (val) {
+      this.loading = val
+    },
+    emptyFilter (val) {
+      if (val) {
+        // this.filter.keyword = ''
+        this.filter.type = ''
+        this.filter.salesMin = ''
+        this.filter.salesMax = ''
+        this.filter.commissionMin = ''
+        this.filter.commissionMax = ''
+        this.filter.orderMin = ''
+        this.filter.orderMax = ''
+      }
+    }
+  },
+  data () {
+      return {
+        lis: '',
+        loading: false,
+        parType: [{v: '', n: '全部'},{v: '1', n: '个人'}, {v: '2', n: '企业'}],
+        filter: {
+            // keyword: '',
+            type: '',
+            salesMin: '',
+            salesMax: '',
+            commissionMin: '',
+            commissionMax: '',
+            orderMin: '',
+            orderMax: ''
+        },
+        sear: {
+          keyword: '',
+        },
+        columns: [
+            {
+                title: '伙伴名称',
+                key: 'name',
+                align: 'center'
+            },
+            {
+                title: '手机号',
+                key: 'phone',
+                width: '130',
+                align: 'center'
+            },
+            {
+                title: '加入时间',
+                key: 'createtime',
+                width: '170',
+                align: 'center'
+            },
+            {
+                title: '最后登录日期',
+                key: 'lastlogintime',
+                width: '170',
+                align: 'center'
+            },
+            {
+                title: '累计销售',
+                key: 'dis_sales',
+                align: 'center',
+                render: (h, {row}) => {
+                  return h('span','¥' + parseFloat(row.dis_sales/100).toLocaleString('en-US'))
+                }
+            },
+            {
+                title: '累计佣金',
+                key: 'dis_commission',
+                align: 'center',
+                render: (h, {row}) => {
+                  return h('span','¥' + parseFloat(row.dis_commission/100).toLocaleString('en-US'))
+                }
+            },
+            {
+                title: '累计单数',
+                key: 'dis_order',
+                align: 'center'
+            },
+            {
+                title: '类型',
+                slot: 'type',
+                align: 'center'
+            },
+            {
+                title: '操作',
+                slot: 'op',
+                align: 'center'
+            },
+        ],
+        list: []
+      }
+  },
+}
+</script>
+
+<style lang="scss" scoped>
+.huo-ban {
+  h1 {
+    font-size:24px;
+    color:#3f4047;
+    padding: 10px 0 20px 10px;
+  }
+  .ser-ipt {
+    width: 162px;
+  }
+}
+</style>

+ 243 - 0
src/views/sales/settleList.vue

@@ -0,0 +1,243 @@
+<template>
+  <div class="jie-suan">
+    <h1>结算列表</h1>
+    <table-lists 
+        ref="tableLists" 
+        v-model="list" 
+        :filter="filter" 
+        :sear="sear"
+        :filterSear="2" 
+        @emptyFilter="emptyFilter"
+        requestApi="/sales/settleList" 
+        style="background:#fff;padding:10px"
+        @loading="load"
+    >
+      <template slot="filterContent">
+          <FormItem label="可提现金额:" :label-width="90">
+            <Input style="width: 73px" type="text" size="large" v-model="filter.cashMoneyMin" placeholder="最小金额" clearable/>
+            <Input style="width: 73px;margin-left: 2px" type="text" size="large" v-model="filter.cashMoneyMax" placeholder="最大金额" clearable/>
+        </FormItem>
+        <FormItem label="结算时间:" :label-width="70" style="margin-right: 30px">
+            <DatePicker 
+                type="datetime" 
+                size="large"
+                v-model="dataVals1"
+                placeholder="起始时间" 
+                format="yyyy-MM-dd HH:mm:ss"
+                style="width: 172px"
+                :options="options1"
+                @on-change="handleChange1"
+                @on-ok="confirmed1"
+                @on-open-change="opened1"
+            ></DatePicker>
+            <DatePicker 
+                type="datetime" 
+                size="large"
+                v-model="dataVals2"
+                placeholder="截止时间" 
+                format="yyyy-MM-dd HH:mm:ss"
+                style="width:172px; margin-left:2px"
+                :options="options2"
+                @on-change="handleChange2"
+                @on-ok="confirmed2"
+                @on-open-change="opened2"
+            ></DatePicker>
+        </FormItem>
+      </template>
+      <template slot="filterRight">
+          <Input suffix="md-search" type="text" size="large" v-model="sear.keyword" placeholder="搜索单号或手机号" clearable class="ser-ipt"/>
+      </template>
+      <Table 
+        size="large"
+        ellipsis 
+        :loading="loading" 
+        ref="selection" 
+        :columns="columns" 
+        :data="list.lists" 
+        stripe
+        @on-row-click="rowClick"
+      >
+      </Table>
+      <template slot="options">
+        <div style="color:#d7d7d7;font-size:14px">共计{{list.total ? list.total : '0'}}条结算记录</div>
+      </template>
+    </table-lists>
+  </div>
+</template>
+<script>
+import { ChangeDate } from '../../assets/js/date'
+export default {
+    methods: {
+        load (val) {
+            this.loading = val
+        },
+        rowClick (data) {
+            const news = this.$router.resolve({path: '/sales/settleList/settleDetail', query:{id:data.id, uid:data.uid, deType:'jiesuan'}})
+            window.open(news.href,'_blank')
+        },
+        emptyFilter (val) {
+            if (val) {
+                this.filter.keyword = ''
+                this.filter.cashMoneyMin = ''
+                this.filter.cashMoneyMax = ''
+                this.filter.cashTimeStart = ''
+                this.filter.cashTimeEnd = ''
+                this.dataVals1 = ''
+                this.dataVals2 = ''
+            }
+        },
+        handleChange1 (date) {
+            this.filter.cashTimeStart = date
+        },
+        handleChange2 (date) {
+            this.filter.cashTimeEnd = date
+        },
+        confirmed1 () {
+            if (this.filter.cashTimeStart && this.filter.cashTimeEnd) {
+                if (this.filter.cashTimeStart > this.filter.cashTimeEnd) {
+                    this.dataVals1 = ''
+                    this.filter.cashTimeStart = ''
+                    this.$Notice.warning({
+                        title: '警告提示',
+                        desc: "起始时间应小于截止时间",
+                        duration: 5
+                    })
+                }
+            }
+        },
+        confirmed2 () {
+            if (this.filter.cashTimeStart && this.filter.cashTimeEnd) {
+                if (this.filter.cashTimeStart > this.filter.cashTimeEnd) {
+                    this.dataVals2 = ''
+                    this.filter.cashTimeEnd = ''
+                    this.$Notice.warning({
+                        title: '警告提示',
+                        desc: "截止时间应大于起始时间",
+                        duration: 5
+                    })
+                }
+            }
+        },
+        opened1 (val) {
+            if (val) {
+                return
+            } else {
+                this.confirmed1()
+            }
+        },
+        opened2 (val) {
+            if (val) {
+                return
+            } else {
+                this.confirmed2()
+            }
+        }
+    },
+    data () {
+        return {
+            lis: '',
+            loading: false,
+            requestType: [],
+            dataVals1: '',
+            dataVals2: '',
+            filter: {
+                // keyword: '',
+                cashMoneyMin: '',
+                cashMoneyMax: '',
+                cashTimeStart: '',
+                cashTimeEnd: ''
+            },
+            sear: {
+                keyword: ''
+            },
+            options1: {
+                disabledDate: (function(date) {
+                    var timeEnd = ChangeDate(this.filter.cashTimeEnd)
+                    var p_time = new Date(timeEnd).getTime()
+                    return date && date.valueOf() > p_time;
+                }).bind(this)
+            },
+            options2: {
+                disabledDate: (function(date) {
+                    var timeStart = ChangeDate(this.filter.cashTimeStart)
+                    var p_time = new Date(timeStart).getTime()
+                    return date && date.valueOf() < p_time;
+                }).bind(this)
+            },
+            columns: [
+                {
+                    title: '结算单号',
+                    key: 'code',
+                    align: 'center'
+                },
+                {
+                    title: '手机号',
+                    key: 'phone',
+                    align: 'center'
+                },
+                {
+                    title: '结算时间',
+                    key: 'createtime',
+                    width: '170',
+                    align: 'center'
+                },
+                {
+                    title: '销售金额',
+                    key: 'sale_cash',
+                    align: 'center',
+                    render: (h, {row}) => {
+                        return h('div','¥' + (row.sale_cash/100).toLocaleString('en-US'))
+                    }
+                },
+                {
+                    title: '佣金金额',
+                    key: 'commission',
+                    align: 'center',
+                    render: (h, {row}) => {
+                        return h('div','¥' + (row.commission/100).toLocaleString('en-US'))
+                    }
+                },
+                {
+                    title: '个税金额',
+                    key: 'tax_cash',
+                    align: 'center',
+                    render: (h, {row}) => {
+                        return h('div','¥' + (row.tax_cash/100).toLocaleString('en-US'))
+                    }
+                },
+                {
+                    title: '认证金额',
+                    key: 'auth_cash',
+                    align: 'center',
+                    render: (h, {row}) => {
+                        return h('div','¥' + (row.auth_cash/100).toLocaleString('en-US'))
+                    }
+                },
+                {
+                    title: '可提现金额',
+                    key: 'can_cash',
+                    className: 'table-info-settle',
+                    align: 'center',
+                    render: (h, {row}) => {
+                        return h('div','¥' + (row.can_cash/100).toLocaleString('en-US'))
+                    }
+                }
+            ],
+            list: []
+        }
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+.jie-suan {
+    h1 {
+        font-size:24px;
+        color:#3f4047;
+        padding: 10px 0 20px 10px;
+    }
+    .ser-ipt {
+        width: 162px;
+    }
+}
+</style>

+ 37 - 0
src/views/sales/withdrawDetail.vue

@@ -0,0 +1,37 @@
+<template>
+    <div class="with-detail">
+        <h1>{{$route.query.deType == "tixian" ? "提现" : "结算"}}列表</h1>
+        <div class="det">
+            <div slot="title" class="right-fund">查看详情</div>
+            <Divider />
+            <w-detail :deType="$route.query.deType" :peType="$route.query.peType"></w-detail>
+        </div>
+    </div>
+</template>
+
+<script>
+import wDetail from './components/details'
+export default {
+    components: {
+        wDetail
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+.with-detail {
+    .det {
+        background:#fff;
+        padding: 10px 0;
+    }
+    h1 {
+        padding: 10px 0 20px 10px;
+    }
+    .right-fund {
+        font-size: 20px;
+        color: #575962;
+        padding-left: 100px;
+        margin-top: 14px;
+    }
+}
+</style>

+ 393 - 0
src/views/sales/withdrawList.vue

@@ -0,0 +1,393 @@
+<template>
+  <div class="ti-xian">
+    <h1>提现列表</h1>
+    <table-lists 
+        ref="tableLists" 
+        v-model="list" 
+        :filter="filter" 
+        :sear="sear"
+        :filterSear="2"
+        requestApi="/sales/withdrawList" 
+        style="background:#fff;padding:10px" 
+        @loading="load"
+        @emptyFilter="emptyFilter"
+        @serachBtn="serachBtn"
+    >
+      <template slot="filterContent">
+        <FormItem label="状态:" :label-width="50">
+            <Select size="large" placeholder="全部" clearable v-model="filter.status" style="width:100px">
+                <Option v-for="item in withType" :value="item.v" :key="item.v">{{ item.n }}</Option>
+            </Select>
+        </FormItem>
+        <FormItem label="提现方式:" :label-width="70">
+            <Select size="large" placeholder="全部" clearable v-model="filter.cashWay" style="width:100px">
+                <Option v-for="item in getType" :value="item.v" :key="item.v">{{ item.n }}</Option>
+            </Select>
+        </FormItem>
+        <FormItem label="提现时间:" :label-width="70" style="margin-right: 20px">
+            <DatePicker 
+                type="datetime" 
+                size="large"
+                v-model="dataVal1"
+                placeholder="起始时间" 
+                format="yyyy-MM-dd HH:mm:ss"
+                style="width: 172px" 
+                @on-change="handleChange1"
+                :options="options1"
+                @on-ok="confirmed1"
+                @on-open-change="opened1"
+            ></DatePicker>
+            <DatePicker 
+                type="datetime" 
+                size="large"
+                v-model="dataVal2"
+                placeholder="截止时间" 
+                format="yyyy-MM-dd HH:mm:ss"
+                style="width: 172px;margin-left:2px" 
+                @on-change="handleChange2"
+                :options="options2"
+                @on-ok="confirmed2"
+                @on-open-change="opened2"
+            ></DatePicker>
+        </FormItem>
+      </template>
+      <template slot="exportData">
+            <Button type="primary" size="large" @click="exportd" style="margin-left: 10px">导出结果</Button>
+            <Button type="primary" size="large" @click="batchFinish" style="margin-left:10px">批量完成</Button>
+      </template>
+      <template slot="filterRight">
+          <Input suffix="md-search" type="text" size="large" v-model="sear.keyword" placeholder="搜索单号或手机号" clearable class="ser-ipt"/>
+      </template>
+      <Table 
+        size="large"
+        ellipsis 
+        :loading="loading" 
+        ref="selection" 
+        :columns="columns" 
+        :data="list.lists" 
+        stripe
+      >
+        <template slot-scope="{ row }" slot="way">
+          <div>{{row.type == '1'?'支付宝':'对公转账'}}</div>
+        </template>
+        <template slot-scope="{ row }" slot="_status">
+          <div style="color:#f4516c" :class="{casActive:row.cashout_status == 1}">{{row.cashout_status | casStat}}</div>
+        </template>
+        <template slot-scope="{ row }" slot="op">
+          <Button  
+            size="small" 
+            type="primary" 
+            style="margin-right:5px"
+            
+          >
+            <router-link
+                :to="{path:'/sales/withdrawList/withdrawDetail',query:{id:row.id, uid:row.uid, deType:'tixian', peType:String(row.type)}}"
+                target="_blank"
+                style="color:#fff"
+            >查看</router-link>
+          </Button>
+          <Button 
+            size="small" 
+            type="success" 
+            @click="finished(row.id)"
+            :disabled="row.cashout_status == 1? true : false"
+          >完成</Button>
+        </template>
+      </Table>
+      <template slot="options">
+          <div style="color:#d7d7d7;font-size:14px">共计{{list.total ? list.total : '0'}}条提现记录</div>
+      </template>
+    </table-lists>
+  </div>
+</template>
+<script>
+import { ChangeDate } from '../../assets/js/date.js'
+export default {
+    methods: {
+        serachBtn (val) {
+            this.searBtn = val
+        },
+        load (val) {
+            this.loading = val
+        },
+        emptyFilter (val) {
+            if (val) {
+                this.filter.status = ''
+                this.filter.cashWay = ''
+                this.filter.cashStartTime = ''
+                this.filter.cashEndTime = ''
+                this.dataVal1 = ''
+                this.dataVal2 = ''
+                this.searBtn = false
+            }
+        },
+        reload() {
+            this.$refs.tableLists.reload(true)
+        },
+        handleChange1(date) {
+            this.filter.cashStartTime = date
+        },
+        handleChange2(date) {
+            this.filter.cashEndTime = date
+        },
+        confirmed1() {
+            if (this.filter.cashStartTime && this.filter.cashEndTime) {
+                if (this.filter.cashStartTime > this.filter.cashEndTime) {
+                    this.dataVal1 = ''
+                    this.filter.cashStartTime = ''
+                    this.$Notice.warning({
+                        title: '警告提示',
+                        desc: "起始时间应小于截止时间",
+                        duration: 5
+                    })
+                }
+            }
+        },
+        confirmed2() {
+            if (this.filter.cashStartTime && this.filter.cashEndTime) {
+                if (this.filter.cashStartTime > this.filter.cashEndTime) {
+                    this.dataVal2 = ''
+                    this.filter.cashEndTime = ''
+                    this.$Notice.warning({
+                        title: '警告提示',
+                        desc: "截止时间应大于起始时间",
+                        duration: 5
+                    })
+                }
+            }
+        },
+        opened1 (val) {
+            if (val) {
+                return
+            } else {
+                this.confirmed1()
+            }
+        },
+        opened2 (val) {
+            if (val) {
+                return
+            } else {
+                this.confirmed2()
+            }
+        },
+        sortNum (a, b) {
+            return a - b
+        },
+        exportd() {
+            if (this.filter.cashWay == '' || this.filter.cashWay == undefined) {
+                this.$Modal.warning({
+                    title: "请选择提现方式"
+                })
+                return
+            }
+            if (this.filter.status == '' || this.filter.status == 1 || this.filter.status == undefined) {
+                this.$Modal.warning({
+                    title: "只能导出已申请内容,请选择状态"
+                })
+                return
+            }
+            if (this.list.lists.length == 0) {
+                this.$Notice.warning({
+                    title: '警告提示',
+                    desc: "暂无相应数据",
+                    duration: 5
+                })
+                return
+            }
+            this.$Modal.confirm({
+                title: "确定导出结果吗?",
+                onOk: () => {
+                    this.$request('/sales/settleList/exportResults').data({
+                        cashStartTime: this.filter.cashStartTime?this.filter.cashStartTime:'',
+                        cashEndTime: this.filter.cashEndTime?this.filter.cashEndTime:'',
+                        cashType: String(this.filter.cashWay)
+                    }).success((res) => {
+                        if (res.data) {
+                            window.location.href = res.data
+                            this.reload()
+                        } else {
+                            this.$Notice.warning({
+                                title: '警告提示',
+                                desc: "暂无相应数据",
+                                duration: 5
+                            })
+                        }
+                    }).get()
+                }
+            })
+        },
+        finished (data) {
+            this.$Modal.confirm({
+                title: "确定要完成所选内容?",
+                onOk: () => {
+                    this.$request('/sales/withdrawList/batchFinish').data({ 
+                        ids: data
+                    }).showSuccessTip().success(() => {
+                        this.reload()
+                    }).post()
+                }
+            })
+        },
+        batchFinish () {
+            if (this.filter.cashWay == '' || this.filter.cashWay == undefined) {
+                this.$Modal.warning({
+                    title: "请选择提现方式"
+                })
+                return
+            }
+            if (this.filter.status == '' || this.filter.status == 1 || this.filter.status == undefined) {
+                this.$Modal.warning({
+                    title: "只能完成已申请内容,请选择状态"
+                })
+                return
+            }
+            if (this.list.lists.length == 0) {
+                this.$Notice.warning({
+                    title: '警告提示',
+                    desc: "暂无相应数据",
+                    duration: 5
+                })
+                return
+            }
+            this.$Modal.confirm({
+                title: "确定要批量完成所选内容",
+                onOk: () => {
+                    this.$request('/sales/withdrawList/finished').data({
+                        cashStartTime: this.filter.cashStartTime?this.filter.cashStartTime:'',
+                        cashEndTime: this.filter.cashEndTime?this.filter.cashEndTime:'',
+                        cashType: String(this.filter.cashWay)
+                    }).showSuccessTip().success((res) => {
+                        if (res.data) {
+                            this.reload()
+                        } else {
+                            this.$Notice.warning({
+                                title: '警告提示',
+                                desc: "暂无相应数据",
+                                duration: 5
+                            })
+                        }
+                    }).post()
+                }
+            })
+        }
+    },
+    filters: {
+        casStat (val) {
+            if (val == -1) {
+                return "失败"
+            } else if (val == 0) {
+                return "已申请"
+            } else {
+                return "已完成"
+            }
+        }
+    },
+    data () {
+        return {
+            lis: '',
+            loading: false,
+            casStatus: true,
+            dataVal1: '',
+            dataVal2: '',
+            searBtn: false,
+            withType: [
+                {v: '', n: '全部'},
+                {v: '0', n: '已申请'},
+                {v: '1', n: '已完成'}
+            ],
+            getType: [
+                {v: '', n: '全部'},
+                {v: '1', n: '支付宝'},
+                {v: '2', n: '对公转账'}
+            ],
+            filter: {
+                keyword: '',
+                status: '',
+                cashWay: '',
+                cashStartTime: '',
+                cashEndTime: ''
+            },
+            sear: {
+                keyword: '',
+            },
+            options1: {
+                disabledDate: (function(date) {
+                    var timeEnd = ChangeDate(this.filter.cashEndTime)
+                    var p_time = new Date(timeEnd).getTime()
+                    return date && date.valueOf() > p_time;
+                }).bind(this)
+            },
+            options2: {
+                disabledDate: (function(date) {
+                    var timeStart = ChangeDate(this.filter.cashStartTime)
+                    var p_time = new Date(timeStart).getTime()
+                    return date && date.valueOf() < p_time;
+                }).bind(this)
+            },
+            columns: [
+                {
+                    title: '提现单号',
+                    key: 'code',
+                    align: 'center'
+                },
+                {
+                    title: '真实姓名',
+                    key: 'name',
+                    align: 'center'
+                },
+                {
+                    title: '手机号',
+                    key: 'phone',
+                    align: 'center'
+                },
+                {
+                    title: '提现时间',
+                    key: 'createtime',
+                    width: '170',
+                    align: 'center'
+                },
+                {
+                    title: '提现金额',
+                    key: 'money',
+                    align: 'center',
+                    render: (h, {row}) => {
+                        return h('span','¥' + parseFloat(row.money/100).toLocaleString('en-US'))
+                    }
+                },
+                {
+                    title: '提现方式',
+                    slot: 'way',
+                    align: 'center'
+                },
+                {
+                    title: '状态',
+                    slot: '_status',
+                    align: 'center'
+                },
+                {
+                    title: '操作',
+                    slot: 'op',
+                    align: 'center'
+                },
+            ],
+            list: []
+        }
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+.ti-xian {
+    h1 {
+        font-size:24px;
+        color:#3f4047;
+        padding: 10px 0 20px 10px;
+    }
+    .ser-ipt {
+    width: 162px;
+    }
+    .casActive {
+        color: #34bfa3!important;
+    }
+}
+</style>

+ 172 - 0
src/views/system/auth.vue

@@ -0,0 +1,172 @@
+<template>
+    <div style="background:#fff;padding:10px">
+        <table-lists 
+            ref="tableLists" 
+            v-model="list" 
+            :filter="filter" 
+            :filterType="2" 
+            :filterReset="0" 
+            requestApi="/system/auth/lists" 
+            @loading="load"
+        >
+            <template slot="filterContent">
+                <FormItem>
+                    <Input type="text" size="large" suffix="md-search" v-model="filter.keyword" placeholder="搜索关键词"/>
+                </FormItem>
+            </template>
+            <template slot="filterRight">
+                <Button type="success" icon="md-add" @click="add()">添加</Button>
+            </template>
+            <Table size="large" ellipsis :loading="loading" :columns="columns" :data="list.lists" stripe>
+                <template slot-scope="{ row }" slot="_request">
+                    <Button size="small" @click="showAssign(row,'request')">
+                        关联请求({{row.request.length}})
+                    </Button>
+                </template>
+                <template slot-scope="{ row }" slot="_userGroup">
+                    <Button size="small" @click="showAssign(row,'userGroup')">
+                        关联用户组({{row.userGroup.length}})
+                    </Button>
+                </template>
+                <template slot-scope="{ row }" slot="_menu">
+                    <Button size="small" @click="showAssign(row,'menu')">
+                        关联菜单({{row.menu.length}})
+                    </Button>
+                </template>
+                <template slot-scope="{ row }" slot="op">
+                    <Button size="small" type="primary" @click="edit(row)" style="margin-right: 5px">编辑</Button>
+                    <Button size="small" type="error" @click="remove(row)">删除</Button>
+                </template>
+            </Table>
+            <template slot="options">
+                <div style="color:#d7d7d7;font-size:14px">共计{{list.total}}个权限</div>
+            </template>
+        </table-lists>
+        <Drawer :title="assign.data.name+' 菜单关联'" v-model="assign.show.menu" width="300" :mask-closable="true">
+            <AssignMenu v-if="assign.show.menu" :id="assign.data.id" @reload="reload"></AssignMenu>
+        </Drawer>
+        <Drawer :title="assign.data.name+' 请求关联'" v-model="assign.show.request" width="900" :mask-closable="true">
+            <AssignRequest v-if="assign.show.request" :id="assign.data.id" @reload="reload"></AssignRequest>
+        </Drawer>
+        <Drawer :title="assign.data.name+' 用户组关联'" v-model="assign.show.userGroup" width="900" :mask-closable="true">
+            <AssignUserGroup v-if="assign.show.userGroup" :id="assign.data.id" @reload="reload"></AssignUserGroup>
+        </Drawer>
+        <Modal v-model="current.show" :title="current.data['id'] ? '编辑' : '添加'" :width="400" @on-ok="save">
+            <Form :label-width="50">
+                <FormItem label="名称">
+                    <Input v-model="current.data.name" type="text"></Input>
+                </FormItem>
+                <FormItem label="描述">
+                    <Input v-model="current.data.description" type="textarea"></Input>
+                </FormItem>
+            </Form>
+            <template slot="footer">
+                <Button type="primary" size="large" @click="save">保存</Button>
+            </template>
+        </Modal>
+    </div>
+</template>
+<script>
+    import AssignRequest from './components/AssignRequest'
+    import AssignUserGroup from './components/AssignUserGroup'
+    import AssignMenu from './components/AssignMenu'
+    import _ from "lodash";
+
+    export default {
+        components: {
+            AssignRequest,
+            AssignUserGroup,
+            AssignMenu
+        },
+        methods: {
+            load (val) {
+                this.loading = val
+            },
+            add() {
+                this.current.data = {};
+                this.current.show = true;
+            },
+            edit(row) {
+                this.current.data = _.cloneDeep(row);
+                this.current.show = true;
+            },
+            remove(row) {
+                this.$Modal.confirm({
+                    title: "确认要删除[" + row.name + "]?",
+                    onOk: () => {
+                        this.$request('/system/auth/remove').data({id: row.id}).showSuccessTip().success(() => {
+                            this.reload()
+                        }).get();
+                    }
+                });
+            },
+            save() {
+                this.$request('/system/auth/save').data(this.current.data).showSuccessTip().success(() => {
+                    this.reload()
+                    this.current.show = false;
+                }).post();
+            },
+            showAssign(row,type){
+                this.assign.data = _.cloneDeep(row);
+                this.assign.show[type] = true;
+            },
+            reload(){
+                this.$refs.tableLists.reload(true);
+            }
+        },
+        data() {
+            return {
+                loading: false,
+                assign:{
+                    data:{},
+                    show:{
+                        request:false,
+                        userGroup:false,
+                        menu:false,
+                    },
+                },
+                filter: {
+                    keyword: "",
+                },
+                columns: [
+                    {
+                        title: '名称',
+                        key: 'name',
+                        align: 'center',
+                        width: 200
+                    },
+                    {
+                        title: '创建时间',
+                        key: 'create_time',
+                        align: 'center'
+                    },
+                    {
+                        title: '请求',
+                        slot: '_request',
+                        align: 'center',
+                    },
+                    {
+                        title: '用户',
+                        slot: '_userGroup',
+                        align: 'center',
+                    },
+                    {
+                        title: '菜单',
+                        slot: '_menu',
+                        align: 'center',
+                    },
+                    {
+                        title: '操作',
+                        slot: 'op',
+                        align: 'center'
+                    },
+                ],
+                list: [],
+                current:{
+                    show:false,
+                    data:{},
+                },
+            }
+        }
+    }
+</script>

+ 77 - 0
src/views/system/components/AssignMenu.vue

@@ -0,0 +1,77 @@
+<template>
+    <Tree ref="tree" :data="menu" show-checkbox multiple @on-check-change="change"></Tree>
+</template>
+
+<script>
+    import { menuSort } from '../../../helper'
+
+    export default {
+        name: 'AssignMenu',
+        data() {
+            return {
+                menu: [],
+            }
+        },
+        props: {
+            id: Number,
+        },
+        created() {
+            this.load();
+        },
+        methods: {
+            tree(menus, pid, level) {
+                let menu = [];
+                menus.forEach(item => {
+                    if (item['parent_id'] === pid) {
+                        let data = {
+                            menu: item,
+                            title: item.name,
+                            level: level,
+                            expand: true,
+                            children: item['url'] ? [] : this.tree(menus, item['id'], level + 1),
+                        };
+                        if (item['url'] && item.checked) {
+                            data.checked = true;
+                        }
+                        menu.push(data);
+                    }
+                });
+                return menu;
+            },
+            load() {
+                this.$request('/system/auth/getMenu').data({id: this.id}).success((r) => {
+                    this.menu = this.tree(menuSort(r.data), 0, 1);
+                }).get();
+            },
+            change() {
+                let menu = this.$refs.tree.getCheckedAndIndeterminateNodes();
+                let request = this.$request('/system/auth/assignMenu').data({
+                    menuIds: menu.map(item => {
+                        return item.menu.id;
+                    }),
+                    id:this.id
+                }).success(() => {
+                    this.$emit('reload')
+                });
+                if (menu.length < 1) {
+                    return this.$Modal.confirm({
+                        title: "确定要清空当前的所有菜单?",
+                        onOk: () => {
+                            request.post();
+                        },
+                        onCancel:() => {
+                            this.load();
+                        },
+                    });
+                }
+                request.post();
+            },
+            reload() {
+                this.$emit('reload')
+            }
+        }
+    }
+</script>
+<style scoped>
+
+</style>

+ 87 - 0
src/views/system/components/AssignRequest.vue

@@ -0,0 +1,87 @@
+<template>
+    <div>
+        <table-lists style="min-height:auto" ref="tableLists" v-model="data" :filter="filter" :filterReset="0" requestApi="/system/auth/getRequest">
+            <template slot="filterContent">
+                <FormItem>
+                    <Input type="text" size="large" v-model="filter.keyword" placeholder="搜索关键词"/>
+                </FormItem>
+            </template>
+            <Table size="large" ellipsis :columns="columns" :data="data.lists['noAssign']" stripe height="270">
+                <template slot-scope="{ row }" slot="op">
+                    <Button size="small" type="success" @click="add(row)">加入</Button>
+                </template>
+            </Table>
+        </table-lists>
+        <Table size="large" ellipsis style="margin-top: 10px" :columns="columns" :data="data.lists['assign']" stripe height="270">
+            <template slot-scope="{row,index}" slot="op">
+                <Button size="small" type="error" @click="remove(row,index)">移出</Button>
+            </template>
+        </Table>
+    </div>
+</template>
+
+<script>
+    export default {
+        name: 'AssignRequest',
+        data() {
+            return {
+                data: {
+                    lists:[]
+                },
+                filter: {
+                    keyword: "",
+                    id: 0,
+                },
+                columns: [
+                    {
+                        type: 'ID',
+                        key: 'id',
+                        width: 70,
+                        align: 'center'
+                    },
+                    {
+                        title: '名称',
+                        key: 'name',
+                    },
+                    {
+                        title: 'ACTION',
+                        key: 'action',
+                    },
+                    {
+                        title: '操作',
+                        slot: 'op',
+                        width: 140,
+                    },
+                ]
+            }
+        },
+        props: {
+            id: Number,
+        },
+        created() {
+            this.filter.id = this.id;
+        },
+        methods: {
+            remove(row) {
+                this.$request('/system/auth/removeRequest').data({
+                    id: this.id,
+                    requestId: row.id
+                }).success(() => {
+                    this.reload();
+                }).get();
+            },
+            add(row) {
+                this.$request('/system/auth/assignRequest').data({
+                    id: this.id,
+                    requestId: row.id
+                }).success(() => {
+                    this.reload();
+                }).get();
+            },
+            reload() {
+                this.$refs.tableLists.reload(true);
+                this.$emit('reload')
+            }
+        }
+    }
+</script>

+ 83 - 0
src/views/system/components/AssignUser.vue

@@ -0,0 +1,83 @@
+<template>
+    <div>
+        <table-lists style="min-height:auto" ref="tableLists" v-model="data" :filter="filter" :filterReset="0" requestApi="/system/userGroup/getUser">
+            <template slot="filterContent">
+                <FormItem>
+                    <Input type="text" size="large" v-model="filter.keyword" placeholder="搜索关键词"/>
+                </FormItem>
+            </template>
+            <Table size="large" ellipsis :columns="columns" :data="data.lists['noAssign']" stripe height="270">
+                <template slot-scope="{ row }" slot="op">
+                    <Button size="small" type="success" @click="add(row)">加入</Button>
+                </template>
+            </Table>
+        </table-lists>
+        <Table size="large" ellipsis style="margin-top: 10px" :columns="columns" :data="data.lists['assign']" stripe height="270">
+            <template slot-scope="{row,index}" slot="op">
+                <Button size="small" type="error" @click="remove(row,index)">移出</Button>
+            </template>
+        </Table>
+    </div>
+</template>
+
+<script>
+    export default {
+        name: 'AssignUser',
+        data() {
+            return {
+                data: {
+                    lists: []
+                },
+                filter: {
+                    keyword: "",
+                    id: 0,
+                },
+                columns: [
+                    {
+                        type: 'ID',
+                        key: 'id',
+                        width: 70,
+                        align: 'center'
+                    },
+                    {
+                        title: '名称',
+                        key: 'username',
+                    },
+                    {
+                        title: '操作',
+                        slot: 'op',
+                        width: 140,
+                    },
+                ]
+            }
+        },
+        props: {
+            id: Number,
+        },
+        created() {
+            this.filter.id = this.id;
+        },
+        methods: {
+            remove(row) {
+                this.$request('/system/userGroup/removeUser').data({
+                    id: this.id,
+                    userId: row.id
+                }).success(() => {
+                    this.reload();
+                }).get();
+            },
+            add(row) {
+                this.$request('/system/userGroup/assignUser').data({
+                    id: this.id,
+                    userId: row.id
+                }).success(() => {
+                    this.reload();
+                }).get();
+            },
+            reload() {
+                this.$refs.tableLists.reload(true);
+                this.$emit('reload')
+            }
+        }
+    }
+</script>

+ 82 - 0
src/views/system/components/AssignUserGroup.vue

@@ -0,0 +1,82 @@
+<template>
+    <div>
+        <table-lists style="min-height:auto" ref="tableLists" v-model="data" :filter="filter" :filterReset="0" requestApi="/system/auth/getUserGroup">
+            <template slot="filterContent">
+                <FormItem>
+                    <Input type="text" size="large" v-model="filter.keyword" placeholder="搜索关键词"/>
+                </FormItem>
+            </template>
+            <Table size="large" ellipsis :columns="columns" :data="data.lists['noAssign']" stripe height="270">
+                <template slot-scope="{ row }" slot="op">
+                    <Button size="small" type="success" @click="add(row)">加入</Button>
+                </template>
+            </Table>
+        </table-lists>
+        <Table size="large" ellipsis style="margin-top: 10px" :columns="columns" :data="data.lists['assign']" stripe height="270">
+            <template slot-scope="{row,index}" slot="op">
+                <Button size="small" type="error" @click="remove(row,index)">移出</Button>
+            </template>
+        </Table>
+    </div>
+</template>
+<script>
+    export default {
+        name: 'AssignUserGroup',
+        data() {
+            return {
+                data: {
+                    lists: []
+                },
+                filter: {
+                    keyword: "",
+                    id: 0,
+                },
+                columns: [
+                    {
+                        type: 'ID',
+                        key: 'id',
+                        width: 70,
+                        align: 'center'
+                    },
+                    {
+                        title: '名称',
+                        key: 'name',
+                    },
+                    {
+                        title: '操作',
+                        slot: 'op',
+                        width: 140,
+                    },
+                ]
+            }
+        },
+        props: {
+            id: Number,
+        },
+        created() {
+            this.filter.id = this.id;
+        },
+        methods: {
+            remove(row) {
+                this.$request('/system/auth/removeUserGroup').data({
+                    id: this.id,
+                    userGroupId: row.id
+                }).success(() => {
+                    this.reload();
+                }).get();
+            },
+            add(row) {
+                this.$request('/system/auth/assignUserGroup').data({
+                    id: this.id,
+                    userGroupId: row.id
+                }).success(() => {
+                    this.reload();
+                }).get();
+            },
+            reload() {
+                this.$refs.tableLists.reload(true);
+                this.$emit('reload')
+            }
+        }
+    }
+</script>

文件差异内容过多而无法显示
+ 0 - 0
src/views/system/components/icon.js


+ 71 - 0
src/views/system/components/iconSelect.vue

@@ -0,0 +1,71 @@
+<template>
+    <Modal v-model="show" fullscreen title="选择图标" footer-hide>
+        <div style="text-align: center;line-height: 40px">
+            <Input style="width: 500px" v-model="keyword" placeholder="输入英文关键词搜索,比如 success"></Input>
+        </div>
+        <Row class="icon-lists">
+            <Col span="3" v-for="icon in icons" :key="icon">
+                <a @click="select(icon)">
+                    <Icon :type="icon" :size="38"/>
+                    <p style="text-align: center">{{icon}}</p>
+                </a>
+            </Col>
+        </Row>
+    </Modal>
+</template>
+
+<script>
+    import icon from './icon.js'
+
+    export default {
+        name: "iconSelect",
+        data() {
+            return {
+                keyword: "",
+                show: false
+            };
+        },
+        props: {
+            value: {
+                type: String,
+                default: ""
+            },
+        },
+        computed: {
+            icons() {
+                let lists = [];
+                if (!this.keyword) {
+                    lists = icon;
+                } else {
+                    icon.forEach((v) => {
+                        if (v.indexOf(this.keyword) !== -1) {
+                            lists.push(v);
+                        }
+                    });
+                }
+                return lists;
+            }
+        },
+        methods: {
+            select(icon) {
+                this.$emit('input', icon);
+                this.show = false
+            },
+            open() {
+                this.show = true
+            }
+        }
+    }
+</script>
+
+<style scoped>
+    .icon-lists{
+        margin-top: 10px;
+    }
+    .icon-lists a {
+        text-align: center;
+        display: block;
+        color: #5c6b77;
+        padding: 10px;
+    }
+</style>

+ 4 - 0
src/views/system/listsConst.js

@@ -0,0 +1,4 @@
+export const userStatus = [
+    {v: 1, n: '启用'},
+    {v: 2, n: '禁用'}
+];

+ 289 - 0
src/views/system/menu.vue

@@ -0,0 +1,289 @@
+<template>
+    <div>
+        <Row :gutter="16">
+            <Col span="12">
+                <Card>
+                    <p slot="title">菜单层级</p>
+                    <Button size="small" type="primary" slot="extra" @click="add(0)">
+                        <Icon type="md-add"/>
+                        添加一级菜单
+                    </Button>
+                    <Tree :data="menu" :render="renderContent"></Tree>
+                </Card>
+            </Col>
+            <Col span="12">
+                <Card v-if="ieEditIng">
+                    <p slot="title">{{current.id ? '编辑' : '添加'}}</p>
+                    <div slot="extra">
+                        <Button size="small" type="error" style="margin-right: 10px" @click="cancelSetCurrent()">放弃
+                        </Button>
+                        <Button size="small" type="primary" @click="saveSetCurrent()">保存</Button>
+                    </div>
+                    <Form :label-width="80">
+                        <FormItem label="名称">
+                            <Input v-model="current.name" placeholder="菜单名称"></Input>
+                        </FormItem>
+                        <FormItem label="父菜单ID">
+                            <Input v-model="current.parent_id" placeholder="父菜单ID 0为一级菜单"></Input>
+                        </FormItem>
+                        <FormItem label="链接">
+                            <Input v-model="current.url" placeholder="页面型菜单链接不能为空,目录型菜单链接要置空"></Input>
+                        </FormItem>
+                        <FormItem label="图标">
+                            <Icon v-if="current.icon" :type="current.icon" size="24" style="margin-right: 10px">
+                                {{current.icon}}
+                            </Icon>
+                            <span v-if="current.icon" style="margin-right: 10px">
+                                {{current.icon}}
+                                <Icon @click="current.icon = ''" type="ios-close-circle-outline" size="16" style="display:inline-block;height: 40px;margin-right:10px;cursor:pointer;" v-if="current.icon" />
+                            </span>
+                            <Button @click="iconSelect()">选择</Button>
+                        </FormItem>
+                        <FormItem label="描述">
+                            <Input v-model="current.description" placeholder=""></Input>
+                        </FormItem>
+                    </Form>
+                </Card>
+            </Col>
+        </Row>
+        <icon-select v-model="current.icon" ref="iconSelect"></icon-select>
+    </div>
+</template>
+<script>
+    import iconSelect from './components/iconSelect'
+    import _ from "lodash";
+    import { menuSort } from '../../helper'
+
+    export default {
+        data() {
+            return {
+                lists: [],
+                current: {},
+                ieEditIng: false
+            }
+        },
+        components: {
+            'icon-select': iconSelect
+        },
+        computed: {
+            menu() {
+                return this.tree(this.lists, 0, 1);
+            }
+        },
+        created() {
+            this.load();
+        },
+        methods: {
+            renderContent(h, {data, node, root}) {
+                // 获取同级节点
+                let brother = [];
+                // 一级节点
+                if (data.level === 1) {
+                    root.forEach(function (value) {
+                        if (value.node.level === data.level) {
+                            brother.push(value.node.menu)
+                        }
+                    });
+                } else {
+                    root[node.parent].node.children.forEach(function (value) {
+                        brother.push(value.menu)
+                    })
+                }
+                let currentIndex = 0;
+                brother.forEach(function (menu, k) {
+                    if (menu.id === data.menu.id) {
+                        currentIndex = k;
+                    }
+                });
+                return h('span', {
+                    style: {
+                        display: 'inline-block',
+                        width: '100%',
+                    }
+                }, [
+                    h('span', [
+                        h('Icon', {
+                            props: {
+                                type: data.menu['icon'] ? data.menu['icon'] : 'ios-paper-outline'
+                            },
+                            style: {
+                                marginRight: '8px'
+                            }
+                        }),
+                        h('span', '[' + data.menu.id + ']' + data.title)
+                    ]),
+                    h('span', {
+                        style: {
+                            display: 'inline-block',
+                            float: 'right',
+                            marginRight: '32px'
+                        }
+                    }, [
+                        h('Button', {
+                            props: {
+                                icon: 'md-arrow-round-down',
+                                size: 'small',
+                                disabled: brother.length === currentIndex + 1
+                            },
+                            style: {
+                                marginRight: '8px'
+                            },
+                            on: {
+                                click: () => {
+                                    this.down(brother, currentIndex)
+                                }
+                            }
+                        }),
+                        h('Button', {
+                            props: {
+                                icon: 'md-arrow-round-up',
+                                size: 'small',
+                                disabled: currentIndex === 0
+                            },
+                            style: {
+                                marginRight: '8px'
+                            },
+                            on: {
+                                click: () => {
+                                    this.up(brother, currentIndex)
+                                }
+                            }
+                        }),
+                        h('Button', {
+                            props: {icon: 'md-create', type: 'success', size: 'small'},
+                            style: {
+                                marginRight: '8px'
+                            },
+                            on: {
+                                click: () => {
+                                    this.edit(data)
+                                }
+                            }
+                        }),
+                        h('Button', {
+                            props: {icon: 'md-add', type: 'primary', size: 'small', disabled: data.level > 2},
+                            style: {
+                                marginRight: '8px'
+                            },
+                            on: {
+                                click: () => {
+                                    this.add(data.menu.id)
+                                }
+                            }
+                        }),
+                        h('Button', {
+                            props: {
+                                icon: 'md-remove',
+                                type: 'warning',
+                                size: 'small',
+                                disabled: node.children.length > 0
+                            },
+                            on: {
+                                click: () => {
+                                    this.remove(data)
+                                }
+                            }
+                        })
+                    ])
+                ]);
+            },
+            load() {
+                this.$request('/system/menu/lists').success((r)=>{
+                    this.lists = menuSort(r.data)
+                }).get()
+            },
+            menuLoad() {
+                this.$request("/load").success((r) => {
+                        this.$store.dispatch('initialize', r.data)
+                    }).get()
+            },
+            tree(menus, pid, level) {
+                let menu = [];
+                menus.forEach(item => {
+                    if (item['parent_id'] === pid) {
+                        menu.push({
+                            menu: item,
+                            title: item.name,
+                            level: level,
+                            expand: true,
+                            children: item['url'] ? [] : this.tree(menus, item['id'], level + 1),
+                        });
+                    }
+                });
+                return menu;
+            },
+            add(parent_id) {
+                this.setCurrent({
+                    parent_id: parent_id,
+                });
+            },
+            edit(data) {
+                this.setCurrent(data.menu);
+            },
+            remove(data) {
+                this.$Modal.confirm({
+                    title: "确认要移除当前菜单[" + data.title + "]?",
+                    onOk: () => {
+                        this.$request('/system/menu/remove').data({id: data.menu.id}).showSuccessTip().success(() => {
+                            this.load();
+                            this.menuLoad();// 刷新左边菜单
+                        }).get();
+                    }
+                });
+            },
+            setCurrent(data) {
+                if (this.ieEditIng) {
+                    return this.$Notice.error({title: "请先保存或放弃当前编辑/添加的菜单"});
+                }
+                this.current = _.cloneDeep(data);
+                this.ieEditIng = true;
+            },
+            cancelSetCurrent() {
+                this.$Modal.confirm({
+                    title: "确认要放弃当前编辑/添加的菜单?",
+                    onOk: () => {
+                        this.current = {};
+                        this.ieEditIng = false;
+                    }
+                });
+            },
+            saveSetCurrent() {
+                this.$request('/system/menu/save').data(this.current).showSuccessTip().success(() => {
+                    this.current = {};
+                    this.load();
+                    this.menuLoad();// 刷新左边菜单
+                    this.ieEditIng = false;
+                }).post()
+            },
+            down(brother, currentIndex) {
+                let current = brother[currentIndex];
+                let next = brother[currentIndex + 1];
+                brother.splice(currentIndex, 1, next);
+                brother.splice(currentIndex + 1, 1, current);
+                let menus = brother.map(function ({id}, sort) {
+                    return {id, sort}
+                });
+                this.$request('/system/menu/sort').data({menus}).showSuccessTip().success(() => {
+                    this.load();
+                    this.menuLoad();// 刷新左边菜单
+                }).post()
+            },
+            up(brother, currentIndex) {
+                let current = brother[currentIndex];
+                let before = brother[currentIndex - 1];
+                brother.splice(currentIndex, 1, before);
+                brother.splice(currentIndex - 1, 1, current);
+                let menus = brother.map(function ({id}, sort) {
+                    return {id, sort}
+                });
+                this.$request('/system/menu/sort').data({menus}).showSuccessTip().success(() => {
+                    this.load();
+                    this.menuLoad();// 刷新左边菜单
+                }).post()
+            },
+            iconSelect() {
+                this.$refs.iconSelect.open();
+            }
+        },
+    }
+</script>

+ 195 - 0
src/views/system/request.vue

@@ -0,0 +1,195 @@
+<template>
+  <div style="background:#fff;padding:10px">
+    <table-lists 
+      ref="tableLists" 
+      v-model="list" 
+      :filter="filter" 
+      :filterType="2" 
+      :filterReset="0" 
+      :requestApi="lis" 
+      @loading="load"
+    >
+      <template slot="filterContent">
+        <FormItem>
+          <Input type="text" size="large" suffix="md-search" v-model="filter.keyword" placeholder="搜索关键词" clearable/>
+        </FormItem>
+        <FormItem>
+          <Select size="large" placeholder="搜索类型" clearable v-model="filter.type" style="width:162px">
+            <Option v-for="item in type" :value="item.v" :key="item.v">{{ item.n }}</Option>
+          </Select>
+        </FormItem>
+      </template>
+      <template slot="filterRight">
+        <Button type="success" icon="md-add" @click="add()">添加</Button>
+      </template>
+      <Table size="large" ellipsis :loading="loading" ref="selection" :columns="columns" :data="list.lists" stripe>
+        <template slot-scope="{ row }" slot="type">
+          <field-map :value="row.type" :map="type"></field-map>
+        </template>
+        <template slot-scope="{ row }" slot="_action">
+          <Tooltip :content="row.call" :max-width="500">
+            {{row.action}}
+          </Tooltip>
+        </template>
+        <template slot-scope="{ row }" slot="_auth">
+          <Poptip trigger="click" word-wrap>
+            <Button size="small">权限({{row.auth.length}})</Button>
+            <template slot="content">
+              <div v-if="row.auth.length < 1" style="textAlign: center">暂无</div>
+              <div v-for="auth in row.auth" :key="auth.id">{{auth.id}}:{{auth.name}}</div>
+            </template>
+          </Poptip>
+        </template>
+        <template slot-scope="{ row }" slot="op">
+          <Button size="small" type="primary" @click="edit(row)" style="margin-right: 5px">编辑</Button>
+          <Button size="small" type="error" @click="remove(row)" style="margin-right: 5px">删除</Button>
+          <Button size="small" @click="copy(row)">复制</Button>
+        </template>
+      </Table>
+      <template slot="options">
+          <div style="color:#d7d7d7;font-size:14px">共计{{list.total}}个请求</div>
+      </template>
+    </table-lists>
+    <Modal v-model="current.show" :title="current.data['id'] ? '编辑' : '添加'" :width="800">
+      <Form :label-width="80">
+        <FormItem label="名称">
+          <Input v-model="current.data.name"></Input>
+        </FormItem>
+        <FormItem label="ACTION">
+          <Input v-model="current.data.action"></Input>
+        </FormItem>
+        <FormItem label="类型">
+          <Select v-model="current.data.type">
+            <Option v-for="item in type" :value="item.v" :key="item.v">{{ item.n }}</Option>
+          </Select>
+        </FormItem>
+        <FormItem label="类型配置">
+          <Input v-model="current.data['call']" type="textarea"></Input>
+        </FormItem>
+        <FormItem label="类型说明" v-if="currentTypeDescription">
+            <div v-html="currentTypeDescription"></div>
+        </FormItem>
+      </Form>
+      <div slot="footer">
+        <Button type="primary" size="large" @click="save">提交</Button>
+      </div>
+    </Modal>
+  </div>
+</template>
+<script>
+    import { requestList, reqType } from '../../plugins/api.js'
+    import _ from 'lodash'
+    import marked from 'marked'
+
+    export default {
+        computed: {
+            type () {
+                return this.requestType.map((item) => {
+                    return { v: item.type, n: item.name }
+                })
+            },
+            currentTypeDescription () {
+                let description = "";
+                this.requestType.forEach((item)=>{
+                    if (item.type === this.current.data.type){
+                        description = item.description
+                    }
+                })
+                return marked(description)
+            }
+        },
+        created () {
+          this.lis = requestList
+            this.$request(reqType).success((r) => {
+                this.requestType = r.data
+            }).get()
+        },
+        methods: {
+          load (val) {
+            this.loading = val
+          },
+          add () {
+              this.current.data = { type: 'default' }
+              this.current.show = true
+          },
+          copy ({ type, name, action, call }) {
+              this.current.data = { type, name, action, call }
+              this.current.show = true
+          },
+          edit (row) {
+              this.current.data = _.cloneDeep(row)
+              this.current.show = true
+          },
+          remove (row) {
+              this.$Modal.confirm({
+                  title: '确认要删除[' + row.name + ']?',
+                  onOk: () => {
+                      this.$request('/system/request/remove').data({ id: row.id }).showSuccessTip().success(() => {
+                          this.reload()
+                      }).get()
+                  }
+              })
+          },
+          save () {
+            console.log(this.current.data)
+              this.$request('/system/request/save').data(this.current.data).showSuccessTip().success(() => {
+                  this.reload()
+                  this.current.show = false
+              }).post()
+          },
+          reload () {
+              this.$refs.tableLists.reload(true)
+          }
+        },
+        data () {
+            return {
+              lis: '',
+              loading: false,
+              requestType: [],
+              filter: {
+                  keyword: '',
+                  type: ''
+              },
+              columns: [
+                  {
+                      title: '名称',
+                      key: 'name',
+                      align: 'center'
+                  },
+                  {
+                      title: '类型',
+                      slot: 'type',
+                      align: 'center'
+                  },
+                  {
+                      title: 'action',
+                      slot: '_action',
+                      align: 'center'
+                  },
+                  {
+                      title: '创建时间',
+                      key: 'create_time',
+                      align: 'center'
+                  },
+                  {
+                      title: '权限',
+                      slot: '_auth',
+                      width: 80,
+                      align: 'center'
+                  },
+                  {
+                      title: '操作',
+                      slot: 'op',
+                      align: 'center'
+                  },
+              ],
+              list: [],
+              current: {
+                  show: false,
+                  data: {},
+                  tips: ''
+              }
+            }
+        },
+    }
+</script>

+ 168 - 0
src/views/system/user.vue

@@ -0,0 +1,168 @@
+<template>
+    <div style="background:#fff;padding:10px">
+        <table-lists 
+            ref="tableLists" 
+            v-model="list" 
+            :filter="filter" 
+            :filterType="2" 
+            :filterReset="0" 
+            requestApi="/system/user/lists" 
+            @loading="load"
+        >
+            <template slot="filterContent">
+                <FormItem>
+                    <Input type="text" size="large" suffix="md-search" v-model="filter.keyword" placeholder="搜索关键词" clearable/>
+                </FormItem>
+            </template>
+            <template slot="filterRight">
+                <Button type="success" icon="md-add" @click="add()">添加</Button>
+            </template>
+            <Table
+                size="large"
+                ellipsis 
+                :loading="loading" 
+                :columns="columns" 
+                :data="list.lists" 
+                stripe
+            >
+                <template slot-scope="{ row }" slot="_status">
+                    <field-map :value="row.status" :map="map.status"></field-map>
+                </template>
+                <template slot-scope="{ row }" slot="_group">
+                    <Poptip trigger="click" word-wrap>
+                        <Button size="small">用户组({{row.userGroup.length}})</Button>
+                        <template slot="content">
+                            <div v-if="row.userGroup.length < 1">暂无</div>
+                            <div v-for="group in row.userGroup" :key="group.id">{{group.id}}:{{group.name}}</div>
+                        </template>
+                    </Poptip>
+                </template>
+                <template slot-scope="{ row }" slot="op">
+                    <Button size="small" type="primary" @click="edit(row)" style="margin-right: 5px" v-if="list.updateAuth">编辑</Button>
+                    <Button v-if="row.id" size="small" type="error" @click="remove(row)">删除</Button>
+                    <!-- <Button size="small" type="error" @click="remove(row)" :disabled="!list.delAuth">删除</Button> -->
+                </template>
+            </Table>
+            <template slot="options">
+                <div style="color:#d7d7d7;font-size:14px">共计{{list.total}}位用户</div>
+            </template>
+        </table-lists>
+        <Modal v-model="current.show" :title="current.data['id'] ? '编辑' : '添加'" :width="500">
+            <Form :label-width="80">
+                <FormItem label="用户名">
+                    <Input v-model="current.data.username" type="text"></Input>
+                </FormItem>
+                <FormItem label="密码">
+                    <Input v-model="current.data.password" type="text"></Input>
+                </FormItem>
+                <FormItem label="状态">
+                    <Select v-model="current.data.status">
+                        <Option v-for="item in map.status" :value="item.v" :key="item.v">{{ item.n }}</Option>
+                    </Select>
+                </FormItem>
+                <FormItem label="描述">
+                    <Input v-model="current.data.description" type="textarea"></Input>
+                </FormItem>
+            </Form>
+            <div slot="footer">
+                <Button type="primary" size="large" @click="save">提交</Button>
+            </div>
+        </Modal>
+    </div>
+</template>
+<script>
+    import {userStatus} from './listsConst.js'
+    import _ from "lodash";
+    export default {
+        methods: {
+            load (val) {
+                this.loading = val
+            },
+            add() {
+                this.current.data = {status: 1};
+                this.current.show = true;
+            },
+            edit(row) {
+                this.current.data = _.cloneDeep(row);
+                this.current.data.password = "";
+                this.current.show = true;
+            },
+            remove(row) {
+                this.$Modal.confirm({
+                    title: "确认要删除当前[" + row.username + "]?",
+                    onOk: () => {
+                        this.$request("/system/user/remove").data({id: row.id}).showSuccessTip().success(() => {
+                            this.reload();
+                        }).get()
+                    }
+                });
+            },
+            save() {
+                this.$request("/system/user/save").data(this.current.data).showSuccessTip().success(() => {
+                    this.current.show = false;
+                    this.reload();
+                }).post();
+            },
+            reload(){
+                this.$refs.tableLists.reload(true);
+            }
+        },
+        data() {
+            return {
+                loading: false,
+                map: {
+                    status: userStatus
+                },
+                filter: {
+                    keyword: ""
+                },
+                columns: [
+                    {
+                        title: '用户名',
+                        key: 'username',
+                        width: 150,
+                        align: 'center'
+                    },
+                    {
+                        title: '最后登录IP',
+                        key: 'last_login_ip',
+                        align: 'center'
+                    },
+                    {
+                        title: '最后登录时间',
+                        key: 'last_login_time',
+                        align: 'center',
+                        width: 220
+                    },
+                    {
+                        title: '创建时间',
+                        key: 'create_time',
+                        align: 'center',
+                        width: 220
+                    },
+                    {
+                        title: '状态',
+                        slot: '_status',
+                        align: 'center'
+                    },
+                    {
+                        title: '用户组',
+                        slot: '_group',
+                        align: 'center'
+                    },
+                    {
+                        title: '操作',
+                        key: 'updateAuth',
+                        slot: 'op',
+                        align: 'center'
+                    },
+                ],
+                list: [],
+                current: {
+                    show: false,
+                    data: {},
+                },
+            }
+        },
+    }
+</script>

+ 164 - 0
src/views/system/userGroup.vue

@@ -0,0 +1,164 @@
+<template>
+    <div style="background:#fff;padding:10px">
+        <table-lists 
+            ref="tableLists" 
+            v-model="list" 
+            :filter="filter" 
+            :filterType="2" 
+            :filterReset="0" 
+            requestApi="/system/userGroup/lists" 
+            @emptyFilter="emptyFilter"
+            @loading="load"
+        >
+            <template slot="filterContent">
+                <FormItem>
+                    <Input type="text" size="large" suffix="md-search" v-model="filter.keyword" placeholder="搜索关键词" clearable/>
+                </FormItem>
+            </template>
+            <template slot="filterRight">
+                <Button type="success" icon="md-add" @click="add()">添加</Button>
+            </template>
+            <Table size="large" ellipsis :loading="loading" :columns="columns" :data="list.lists" stripe>
+                <template slot-scope="{ row }" slot="_user">
+                    <Button size="small" @click="showAssign(row,'user')">
+                        用户({{row.user.length}})
+                    </Button>
+                </template>
+                <template slot-scope="{ row }" slot="_auth">
+                    <Poptip trigger="click" word-wrap>
+                        <Button size="small">权限({{row.auth.length}})</Button>
+                        <template slot="content">
+                            <div v-if="row.auth.length < 1">暂无</div>
+                            <div v-for="auth in row.auth" :key="auth.id">{{auth.id}}:{{auth.name}}</div>
+                        </template>
+                    </Poptip>
+                </template>
+                <template slot-scope="{ row }" slot="op">
+                    <Button size="small" type="primary" @click="edit(row)" style="margin-right: 5px" v-if="list.updateAuth">编辑</Button>
+                    <Button v-if="row.id" size="small" type="error" @click="remove(row)">删除</Button>
+                </template>
+            </Table>
+            <template slot="options">
+                <div style="color:#d7d7d7;font-size:14px">共计{{list.total}}个用户组</div>
+            </template>
+        </table-lists>
+        <Modal v-model="current.show" :title="current.data['id'] ? '编辑' : '添加'" :width="500">
+            <Form :label-width="80">
+                <FormItem label="名称">
+                    <Input v-model="current.data.name" type="text"></Input>
+                </FormItem>
+                <FormItem label="描述">
+                    <Input v-model="current.data.description" type="textarea"></Input>
+                </FormItem>
+            </Form>
+            <div slot="footer">
+                <Button type="primary" size="large" @click="save">提交</Button>
+            </div>
+        </Modal>
+        <Drawer :title="assign.data.name+' 用户关联'" v-model="assign.show.user" width="900">
+            <AssignUser v-if="assign.show.user" :id="assign.data.id" @reload="reload"></AssignUser>
+        </Drawer>
+    </div>
+</template>
+<script>
+    import _ from "lodash";
+    import AssignUser from './components/AssignUser'
+    export default {
+        components: {
+            AssignUser
+        },
+        methods: {
+            load (val) {
+                this.loading = val
+            },
+            emptyFilter (val) {
+                if (val) {
+                    this.filter.keyword = ''
+                }
+            },
+            add() {
+                this.current.data = {};
+                this.current.show = true;
+            },
+            edit(row) {
+                this.current.data = _.cloneDeep(row);
+                this.current.show = true;
+            },
+            remove(row) {
+                this.$Modal.confirm({
+                    title: "确认要删除当前[ " + row.name + " ]?",
+                    onOk: () => {
+                        this.$request("/system/userGroup/remove").data({id: row.id}).showSuccessTip().success(() => {
+                            this.reload();
+                        }).get()
+                    }
+                });
+            },
+            save() {
+                this.$request("/system/userGroup/save").data(this.current.data).showSuccessTip().success(() => {
+                    this.current.show = false;
+                    this.reload();
+                }).post();
+            },
+            reload(){
+                this.$refs.tableLists.reload(true);
+            },
+            showAssign(row,type){
+                this.assign.data = _.cloneDeep(row);
+                this.assign.show[type] = true;
+            },
+        },
+        data() {
+            return {
+                loading: false,
+                assign:{
+                    data:{},
+                    show:{
+                        user:false
+                    },
+                },
+                filter: {
+                    keyword: ""
+                },
+                columns: [
+                    {
+                        title: '名称',
+                        key: 'name',
+                        align: 'center',
+                        width: 150
+                    },
+                    {
+                        title: '更新时间',
+                        key: 'update_time',
+                        align: 'center'
+                    },
+                    {
+                        title: '创建时间',
+                        key: 'create_time',
+                        align: 'center'
+                    },
+                    {
+                        title: '权限',
+                        slot: '_auth',
+                        align: 'center'
+                    },
+                    {
+                        title: '用户',
+                        slot: '_user',
+                        align: 'center'
+                    },
+                    {
+                        title: '操作',
+                        slot: 'op',
+                        align: 'center'
+                    },
+                ],
+                list: [],
+                current: {
+                    show: false,
+                    data: {},
+                },
+            }
+        },
+    }
+</script>

+ 6 - 0
vue.config.js

@@ -0,0 +1,6 @@
+module.exports = {
+  publicPath: '/',
+  outputDir: "dist",
+  productionSourceMap: false,
+  // devServer: {}
+}

部分文件因为文件数量过多而无法显示