lyn7568 2 年 前
コミット
9fcb2fd227
共有13 個のファイルを変更した832 個の追加91 個の削除を含む
  1. 2 1
      .env.development
  2. 10 3
      src/api/user.js
  3. 4 4
      src/layout/components/Navbar.vue
  4. 8 8
      src/main.js
  5. 13 10
      src/router/index.js
  6. 5 6
      src/store/modules/user.js
  7. 107 0
      src/utils/httpRequest.js
  8. 8 1
      src/utils/index.js
  9. 3 3
      src/utils/request.js
  10. 118 53
      src/views/login/index.vue
  11. 345 0
      src/views/user/user-add-or-update.vue
  12. 195 0
      src/views/user/user.vue
  13. 14 2
      vue.config.js

+ 2 - 1
.env.development

@ -2,4 +2,5 @@
2 2
ENV = 'development'
3 3
4 4
# base api
5
VUE_APP_BASE_API = '/dev-api'
5
# VUE_APP_BASE_API = '/dev-api'
6
VUE_APP_BASE_API = ''

+ 10 - 3
src/api/user.js

@ -2,7 +2,7 @@ import request from '@/utils/request'
2 2
3 3
export function login(data) {
4 4
  return request({
5
    url: '/vue-admin-template/user/login',
5
    url: '/sys/Login/checkLogin',
6 6
    method: 'post',
7 7
    data
8 8
  })
@ -10,7 +10,14 @@ export function login(data) {
10 10
11 11
export function getInfo(token) {
12 12
  return request({
13
    url: '/vue-admin-template/user/info',
13
    url: '/sys/User/info',
14
    method: 'get',
15
    params: { token }
16
  })
17
}
18
export function getCaptcha(token) {
19
  return request({
20
    url: '/sys/Login/captcha',
14 21
    method: 'get',
15 22
    params: { token }
16 23
  })
@ -18,7 +25,7 @@ export function getInfo(token) {
18 25
19 26
export function logout() {
20 27
  return request({
21
    url: '/vue-admin-template/user/logout',
28
    url: '/sys/Login/logout',
22 29
    method: 'post'
23 30
  })
24 31
}

+ 4 - 4
src/layout/components/Navbar.vue

@ -13,17 +13,17 @@
13 13
        <el-dropdown-menu slot="dropdown" class="user-dropdown">
14 14
          <router-link to="/">
15 15
            <el-dropdown-item>
16
              Home
16
              首页
17 17
            </el-dropdown-item>
18 18
          </router-link>
19
          <a target="_blank" href="https://github.com/PanJiaChen/vue-admin-template/">
19
          <!-- <a target="_blank" href="https://github.com/PanJiaChen/vue-admin-template/">
20 20
            <el-dropdown-item>Github</el-dropdown-item>
21 21
          </a>
22 22
          <a target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/#/">
23 23
            <el-dropdown-item>Docs</el-dropdown-item>
24
          </a>
24
          </a> -->
25 25
          <el-dropdown-item divided @click.native="logout">
26
            <span style="display:block;">Log Out</span>
26
            <span style="display:block;">退出登录</span>
27 27
          </el-dropdown-item>
28 28
        </el-dropdown-menu>
29 29
      </el-dropdown>

+ 8 - 8
src/main.js

@ -11,7 +11,7 @@ import '@/styles/index.scss' // global css
11 11
import App from './App'
12 12
import store from './store'
13 13
import router from './router'
14
14
import httpRequest from './utils/httpRequest'
15 15
import '@/icons' // icon
16 16
import '@/permission' // permission control
17 17
@ -23,16 +23,16 @@ import '@/permission' // permission control
23 23
 * Currently MockJs will be used in the production environment,
24 24
 * please remove it before going online ! ! !
25 25
 */
26
if (process.env.NODE_ENV === 'production') {
27
  const { mockXHR } = require('../mock')
28
  mockXHR()
29
}
26
// if (process.env.NODE_ENV === 'production') {
27
//   const { mockXHR } = require('../mock')
28
//   mockXHR()
29
// }
30 30
31 31
// set ElementUI lang to EN
32
Vue.use(ElementUI, { locale })
32
// Vue.use(ElementUI, { locale })
33 33
// 如果想要中文版 element-ui,按如下方式声明
34
// Vue.use(ElementUI)
35
34
Vue.use(ElementUI)
35
Vue.prototype.$http = httpRequest
36 36
Vue.config.productionTip = false
37 37
38 38
new Vue({

+ 13 - 10
src/router/index.js

@ -89,6 +89,18 @@ export const constantRoutes = [
89 89
      }
90 90
    ]
91 91
  },
92
  {
93
    path: '/user',
94
    component: Layout,
95
    children: [
96
      {
97
        path: 'user',
98
        name: 'User',
99
        component: () => import('@/views/user/user.vue'),
100
        meta: { title: 'User', icon: 'form' }
101
      }
102
    ]
103
  },
92 104
93 105
  {
94 106
    path: '/nested',
@ -149,16 +161,7 @@ export const constantRoutes = [
149 161
    ]
150 162
  },
151 163
152
  {
153
    path: 'external-link',
154
    component: Layout,
155
    children: [
156
      {
157
        path: 'https://panjiachen.github.io/vue-element-admin-site/#/',
158
        meta: { title: 'External Link', icon: 'link' }
159
      }
160
    ]
161
  },
164
 
162 165
163 166
  // 404 page must be placed at the end !!!
164 167
  { path: '*', redirect: '/404', hidden: true }

+ 5 - 6
src/store/modules/user.js

@ -30,10 +30,10 @@ const mutations = {
30 30
const actions = {
31 31
  // user login
32 32
  login({ commit }, userInfo) {
33
    const { username, password } = userInfo
33
    const { username, password, vercode } = userInfo
34 34
    return new Promise((resolve, reject) => {
35
      login({ username: username.trim(), password: password }).then(response => {
36
        const { data } = response
35
      login({ username: username.trim(), password: password, vercode: vercode }).then(response => {
36
        const data = response
37 37
        commit('SET_TOKEN', data.token)
38 38
        setToken(data.token)
39 39
        resolve()
@ -48,14 +48,13 @@ const actions = {
48 48
    return new Promise((resolve, reject) => {
49 49
      getInfo(state.token).then(response => {
50 50
        const { data } = response
51
52 51
        if (!data) {
53 52
          return reject('Verification failed, please Login again.')
54 53
        }
55 54
56
        const { name, avatar } = data
55
        const { username, avatar } = data
57 56
58
        commit('SET_NAME', name)
57
        commit('SET_NAME', username)
59 58
        commit('SET_AVATAR', avatar)
60 59
        resolve(data)
61 60
      }).catch(error => {

+ 107 - 0
src/utils/httpRequest.js

@ -0,0 +1,107 @@
1
import axios from 'axios'
2
import { MessageBox, Message } from 'element-ui'
3
import store from '@/store'
4
import { getToken } from '@/utils/auth'
5
import qs from 'qs'
6
import merge from 'lodash/merge'
7
8
// create an axios instance
9
const service = axios.create({
10
  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
11
  // withCredentials: true, // send cookies when cross-domain requests
12
  timeout: 5000 // request timeout
13
})
14
15
// request interceptor
16
service.interceptors.request.use(
17
  config => {
18
    // do something before request is sent
19
20
    if (store.getters.token) {
21
      // let each request carry token
22
      // ['X-Token'] is a custom headers key
23
      // please modify it according to the actual situation
24
      config.headers['X-Token'] = getToken()
25
    }
26
    return config
27
  },
28
  error => {
29
    // do something with request error
30
    console.log(error) // for debug
31
    return Promise.reject(error)
32
  }
33
)
34
35
// response interceptor
36
service.interceptors.response.use(
37
  /**
38
   * If you want to get http information such as headers or status
39
   * Please return  response => response
40
  */
41
42
  /**
43
   * Determine the request status by custom code
44
   * Here is just an example
45
   * You can also judge the status by HTTP Status Code
46
   */
47
  response => {
48
    
49
    if (response.data && response.data.code === 401) { // 401, token失效
50
      clearLoginInfo()
51
      router.push({
52
        name: 'login'
53
      })
54
    }
55
    return response
56
  },
57
  error => {
58
    console.log('err' + error) // for debug
59
    Message({
60
      message: error.message,
61
      type: 'error',
62
      duration: 5 * 1000
63
    })
64
    return Promise.reject(error)
65
  }
66
)
67
68
69
/**
70
 * 请求地址处理
71
 * @param {*} actionName action方法名称
72
 */
73
 service.adornUrl = (actionName) => {
74
  // 非生产环境 && 开启代理, 接口前缀统一使用[/proxyApi/]前缀做代理拦截!
75
  return (process.env.NODE_ENV !== 'production' && process.env.OPEN_PROXY ? '/proxyApi/' : '') + actionName
76
}
77
78
/**
79
 * get请求参数处理
80
 * @param {*} params 参数对象
81
 * @param {*} openDefultParams 是否开启默认参数?
82
 */
83
service.adornParams = (params = {}, openDefultParams = true) => {
84
  var defaults = {
85
    't': new Date().getTime()
86
  }
87
  return openDefultParams ? merge(defaults, params) : params
88
}
89
90
/**
91
 * post请求数据处理
92
 * @param {*} data 数据对象
93
 * @param {*} openDefultdata 是否开启默认数据?
94
 * @param {*} contentType 数据格式
95
 *  json: 'application/json; charset=utf-8'
96
 *  form: 'application/x-www-form-urlencoded; charset=utf-8'
97
 */
98
service.adornData = (data = {}, openDefultdata = true, contentType = 'json') => {
99
  var defaults = {
100
    't': new Date().getTime()
101
  }
102
  data = openDefultdata ? merge(defaults, data) : data
103
  console.log(data);
104
  return contentType === 'json' ? JSON.stringify(data) : qs.stringify(data)
105
}
106
107
export default service

+ 8 - 1
src/utils/index.js

@ -1,7 +1,7 @@
1 1
/**
2 2
 * Created by PanJiaChen on 16/11/18.
3 3
 */
4
4
import { removeToken } from "./auth"
5 5
/**
6 6
 * Parse the time to string
7 7
 * @param {(Object|string|number)} time
@ -115,3 +115,10 @@ export function param2Obj(url) {
115 115
  })
116 116
  return obj
117 117
}
118
119
120
export function clearLoginInfo(){
121
  removeToken()
122
 store.commit('resetStore')
123
 router.options.isAddDynamicMenuRoutes = false
124
}

+ 3 - 3
src/utils/request.js

@ -46,9 +46,9 @@ service.interceptors.response.use(
46 46
    const res = response.data
47 47
48 48
    // if the custom code is not 20000, it is judged as an error.
49
    if (res.code !== 20000) {
49
    if (res.code !== 0) {
50 50
      Message({
51
        message: res.message || 'Error',
51
        message: res.msg || 'Error',
52 52
        type: 'error',
53 53
        duration: 5 * 1000
54 54
      })
@ -66,7 +66,7 @@ service.interceptors.response.use(
66 66
          })
67 67
        })
68 68
      }
69
      return Promise.reject(new Error(res.message || 'Error'))
69
      return Promise.reject(new Error(res.msg || 'Error'))
70 70
    } else {
71 71
      return res
72 72
    }

+ 118 - 53
src/views/login/index.vue

@ -1,9 +1,15 @@
1 1
<template>
2 2
  <div class="login-container">
3
    <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left">
4
3
    <el-form
4
      ref="loginForm"
5
      :model="loginForm"
6
      :rules="loginRules"
7
      class="login-form"
8
      auto-complete="on"
9
      label-position="left"
10
    >
5 11
      <div class="title-container">
6
        <h3 class="title">Login Form</h3>
12
        <h3 class="title">管理后台</h3>
7 13
      </div>
8 14
9 15
      <el-form-item prop="username">
@ -13,7 +19,7 @@
13 19
        <el-input
14 20
          ref="username"
15 21
          v-model="loginForm.username"
16
          placeholder="Username"
22
          placeholder="用户名"
17 23
          name="username"
18 24
          type="text"
19 25
          tabindex="1"
@ -30,107 +36,160 @@
30 36
          ref="password"
31 37
          v-model="loginForm.password"
32 38
          :type="passwordType"
33
          placeholder="Password"
39
          placeholder="密码"
34 40
          name="password"
35 41
          tabindex="2"
36 42
          auto-complete="on"
37 43
          @keyup.enter.native="handleLogin"
38 44
        />
39 45
        <span class="show-pwd" @click="showPwd">
40
          <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
46
          <svg-icon
47
            :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'"
48
          />
41 49
        </span>
42 50
      </el-form-item>
43 51
44
      <el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">Login</el-button>
52
      <el-form-item prop="vercode">
53
        <el-input
54
          style="width: 40%"
55
          v-model="loginForm.vercode"
56
          placeholder="验证码"
57
        >
58
        </el-input>
59
60
        <img
61
          class="vercodeImg"
62
          :src="vercodePath"
63
          @click="getCaptcha()"
64
          alt=""
65
        />
66
      </el-form-item>
45 67
68
      <el-button
69
        :loading="loading"
70
        type="primary"
71
        style="width: 100%; margin-bottom: 30px"
72
        @click.native.prevent="handleLogin"
73
        >登录</el-button
74
      >
75
      <!-- 
46 76
      <div class="tips">
47
        <span style="margin-right:20px;">username: admin</span>
77
        <span style="margin-right: 20px">username: admin</span>
48 78
        <span> password: any</span>
49
      </div>
50
79
      </div> -->
51 80
    </el-form>
52 81
  </div>
53 82
</template>
54 83
55 84
<script>
56
import { validUsername } from '@/utils/validate'
85
import { validUsername } from "@/utils/validate";
57 86
58 87
export default {
59
  name: 'Login',
88
  name: "Login",
60 89
  data() {
61 90
    const validateUsername = (rule, value, callback) => {
62 91
      if (!validUsername(value)) {
63
        callback(new Error('Please enter the correct user name'))
92
        callback(new Error("请输入用户名"));
64 93
      } else {
65
        callback()
94
        callback();
66 95
      }
67
    }
96
    };
97
    const validateVercode = (rule, value, callback) => {
98
      if (!value) {
99
        callback(new Error("请输入验证码"));
100
      } else {
101
        callback();
102
      }
103
    };
68 104
    const validatePassword = (rule, value, callback) => {
69 105
      if (value.length < 6) {
70
        callback(new Error('The password can not be less than 6 digits'))
106
        callback(new Error("密码不能小于6位数"));
71 107
      } else {
72
        callback()
108
        callback();
73 109
      }
74
    }
110
    };
75 111
    return {
76 112
      loginForm: {
77
        username: 'admin',
78
        password: '111111'
113
        username: "",
114
        password: "",
115
        vercode: "",
79 116
      },
117
      vercodePath: "",
80 118
      loginRules: {
81
        username: [{ required: true, trigger: 'blur', validator: validateUsername }],
82
        password: [{ required: true, trigger: 'blur', validator: validatePassword }]
119
        username: [
120
          { required: true, trigger: "blur", validator: validateUsername },
121
        ],
122
        password: [
123
          { required: true, trigger: "blur", validator: validatePassword },
124
        ],
125
        vercode:[
126
          { required: true, trigger: "blur", validator: validateVercode },
127
        ],
83 128
      },
84 129
      loading: false,
85
      passwordType: 'password',
86
      redirect: undefined
87
    }
130
      passwordType: "password",
131
      redirect: undefined,
132
    };
88 133
  },
89 134
  watch: {
90 135
    $route: {
91
      handler: function(route) {
92
        this.redirect = route.query && route.query.redirect
136
      handler: function (route) {
137
        this.redirect = route.query && route.query.redirect;
93 138
      },
94
      immediate: true
95
    }
139
      immediate: true,
140
    },
141
  },
142
  created() {
143
    this.getCaptcha();
96 144
  },
97 145
  methods: {
146
    //验证码
147
    getCaptcha() {
148
      let uuid = Math.random();
149
      this.vercodePath = `/sys/Login/captcha?${uuid}`;
150
    },
151
98 152
    showPwd() {
99
      if (this.passwordType === 'password') {
100
        this.passwordType = ''
153
      if (this.passwordType === "password") {
154
        this.passwordType = "";
101 155
      } else {
102
        this.passwordType = 'password'
156
        this.passwordType = "password";
103 157
      }
104 158
      this.$nextTick(() => {
105
        this.$refs.password.focus()
106
      })
159
        this.$refs.password.focus();
160
      });
107 161
    },
108 162
    handleLogin() {
109
      this.$refs.loginForm.validate(valid => {
163
      this.$refs.loginForm.validate((valid) => {
110 164
        if (valid) {
111
          this.loading = true
112
          this.$store.dispatch('user/login', this.loginForm).then(() => {
113
            this.$router.push({ path: this.redirect || '/' })
114
            this.loading = false
115
          }).catch(() => {
116
            this.loading = false
117
          })
165
          this.loading = true;
166
          this.$store
167
            .dispatch("user/login", this.loginForm)
168
            .then(() => {
169
              this.$router.push({ path: this.redirect || "/" });
170
              this.loading = false;
171
            })
172
            .catch(() => {
173
              this.loading = false;
174
              this.loginForm.vercode = '';
175
              this.getCaptcha();
176
            });
118 177
        } else {
119
          console.log('error submit!!')
120
          return false
178
          console.log("error submit!!");
179
          return false;
121 180
        }
122
      })
123
    }
124
  }
125
}
181
      });
182
    },
183
  },
184
};
126 185
</script>
127 186
128 187
<style lang="scss">
129 188
/* 修复input 背景不协调 和光标变色 */
130 189
/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
131 190
132
$bg:#283443;
133
$light_gray:#fff;
191
$bg: #283443;
192
$light_gray: #fff;
134 193
$cursor: #fff;
135 194
136 195
@supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
@ -173,9 +232,9 @@ $cursor: #fff;
173 232
</style>
174 233
175 234
<style lang="scss" scoped>
176
$bg:#2d3a4b;
177
$dark_gray:#889aa4;
178
$light_gray:#eee;
235
$bg: #2d3a4b;
236
$dark_gray: #889aa4;
237
$light_gray: #eee;
179 238
180 239
.login-container {
181 240
  min-height: 100%;
@ -234,4 +293,10 @@ $light_gray:#eee;
234 293
    user-select: none;
235 294
  }
236 295
}
296
.vercodeImg {
297
  float: right;
298
  height: 47px;
299
  overflow: hidden;
300
  cursor:pointer;
301
}
237 302
</style>

+ 345 - 0
src/views/user/user-add-or-update.vue

@ -0,0 +1,345 @@
1
<template>
2
  <el-dialog
3
    :title="!dataForm.id ? '新增' : '修改'"
4
    :close-on-click-modal="false"
5
    :visible.sync="visible"
6
  >
7
    <el-form
8
      :model="dataForm"
9
      :rules="dataRule"
10
      ref="dataForm"
11
      @keyup.enter.native="dataFormSubmit()"
12
      label-width="80px"
13
    >
14
      <el-form-item label="用户名" prop="userName">
15
        <el-input v-model="dataForm.userName" placeholder="登录帐号"></el-input>
16
      </el-form-item>
17
      <el-form-item
18
        label="密码"
19
        prop="password"
20
        :class="{ 'is-required': !dataForm.id }"
21
      >
22
        <el-input
23
          v-model="dataForm.password"
24
          type="password"
25
          placeholder="密码"
26
        ></el-input>
27
      </el-form-item>
28
      <el-form-item
29
        label="确认密码"
30
        prop="comfirmPassword"
31
        :class="{ 'is-required': !dataForm.id }"
32
      >
33
        <el-input
34
          v-model="dataForm.comfirmPassword"
35
          type="password"
36
          placeholder="确认密码"
37
        ></el-input>
38
      </el-form-item>
39
      <el-form-item label="邮箱" prop="email">
40
        <el-input v-model="dataForm.email" placeholder="邮箱"></el-input>
41
      </el-form-item>
42
      <el-form-item label="手机号" prop="mobile">
43
        <el-input v-model="dataForm.mobile" placeholder="手机号"></el-input>
44
      </el-form-item>
45
      <!-- <el-form-item label="部门" prop="departmentList">
46
        <el-select
47
          v-model="dataForm.departmentList"
48
          placeholder="部门"
49
          allow-create
50
          filterable
51
          @change="getClientName"
52
        >
53
          <el-tree
54
            v-for="item in departmentList"
55
            :label="item.departmentName"
56
            :value="item.departmentId"
57
            :key="item.departmentId"
58
          ></el-tree>
59
        </el-select>
60
      </el-form-item> -->
61
      <el-form-item label="部门" prop="departmentName">
62
        <el-popover
63
          ref="menuListPopover"
64
          placement="bottom-start"
65
          trigger="click">
66
          <el-tree
67
            :data="departmentList"
68
            :props="menuListTreeProps"
69
            node-key="departmentId"
70
            ref="departmentListTree"
71
            @current-change="departmentListTreeCurrentChangeHandle"
72
            :default-expand-all="true"
73
            :highlight-current="true"
74
            :expand-on-click-node="true">
75
          </el-tree>
76
        </el-popover>
77
        <el-input v-model="dataForm.departmentName" v-popover:menuListPopover :readonly="true" placeholder="点击选择部门" class="menu-list__input"></el-input>
78
      </el-form-item>
79
      <el-form-item label="角色" size="mini" prop="roleIdList">
80
        <el-checkbox-group v-model="dataForm.roleIdList">
81
          <el-checkbox
82
            v-for="role in roleList"
83
            :key="role.roleId"
84
            :label="role.roleId"
85
            >{{ role.roleName }}</el-checkbox
86
          >
87
        </el-checkbox-group>
88
      </el-form-item>
89
      <el-form-item label="状态" size="mini" prop="status">
90
        <el-radio-group v-model="dataForm.status">
91
          <el-radio :label="0">禁用</el-radio>
92
          <el-radio :label="1">正常</el-radio>
93
        </el-radio-group>
94
      </el-form-item>
95
      <el-form-item label="上传头像" prop="titlePicture">
96
        <el-upload
97
          class="avatar-uploader"
98
          :action="dialogImageUrl"
99
          :show-file-list="false"
100
          :on-success="handlePictureCardPreview"
101
          name="file"
102
        >
103
          <img
104
            v-if="this.dataForm.avatar"
105
            :src="this.dataForm.avatar"
106
            class="avatar"
107
          />
108
          <i v-else class="el-icon-plus avatar-uploader-icon"></i>
109
        </el-upload>
110
      </el-form-item>
111
    </el-form>
112
    <span slot="footer" class="dialog-footer">
113
      <el-button @click="visible = false">取消</el-button>
114
      <el-button type="primary" @click="dataFormSubmit()">确定</el-button>
115
    </span>
116
  </el-dialog>
117
</template>
118
119
<script>
120
import { isEmail, isMobile } from "@/utils/validate";
121
import { treeDataTranslate } from '@/utils'
122
export default {
123
  data() {
124
    var validatePassword = (rule, value, callback) => {
125
      if (!this.dataForm.id && !/\S/.test(value)) {
126
        callback(new Error("密码不能为空"));
127
      } else {
128
        callback();
129
      }
130
    };
131
    var validateComfirmPassword = (rule, value, callback) => {
132
      if (!this.dataForm.id && !/\S/.test(value)) {
133
        callback(new Error("确认密码不能为空"));
134
      } else if (this.dataForm.password !== value) {
135
        callback(new Error("确认密码与密码输入不一致"));
136
      } else {
137
        callback();
138
      }
139
    };
140
    var validateEmail = (rule, value, callback) => {
141
      if (!isEmail(value)) {
142
        callback(new Error("邮箱格式错误"));
143
      } else {
144
        callback();
145
      }
146
    };
147
    var validateMobile = (rule, value, callback) => {
148
      if (!isMobile(value)) {
149
        callback(new Error("手机号格式错误"));
150
      } else {
151
        callback();
152
      }
153
    };
154
    return {
155
      visible: false,
156
      dialogImageUrl: "",
157
      roleList: [],
158
      dataForm: {
159
        id: 0,
160
        userName: "",
161
        password: "",
162
        comfirmPassword: "",
163
        salt: "",
164
        email: "",
165
        mobile: "",
166
        roleIdList: [],
167
        status: 1,
168
        avatar: "",
169
        departmentId:"",
170
        departmentName:"",
171
      },
172
      departmentList: [],
173
        menuListTreeProps: {
174
          label: 'departmentName',
175
          children: 'children'
176
        },
177
      dataRule: {
178
        userName: [
179
          { required: true, message: "用户名不能为空", trigger: "blur" },
180
        ],
181
        password: [{ validator: validatePassword, trigger: "blur" }],
182
        comfirmPassword: [
183
          { validator: validateComfirmPassword, trigger: "blur" },
184
        ],
185
        email: [
186
          { required: true, message: "邮箱不能为空", trigger: "blur" },
187
          { validator: validateEmail, trigger: "blur" },
188
        ],
189
        mobile: [
190
          { required: true, message: "手机号不能为空", trigger: "blur" },
191
          { validator: validateMobile, trigger: "blur" },
192
        ],
193
      },
194
    };
195
  },
196
  methods: {
197
    // 上传成功
198
    handlePictureCardPreview(response, file) {
199
      console.log(response);
200
      this.dataForm.avatar = response.url;
201
    },
202
    getClientName(e) {
203
      console.log(e);
204
      let obj = {};
205
      obj = this.departmentList.find((item) => {
206
        return item.departmentId === e;
207
      });
208
      console.log(obj);
209
      console.log(obj.name);
210
      this.dataForm.departmentId = e;
211
    },
212
    init(id) {
213
      this.dataForm.id = id || 0;
214
      this.$http({
215
        url: this.$http.adornUrl("/sys/user/index"),
216
        method: "get",
217
        params: this.$http.adornParams(),
218
      }).then(({ data }) => {
219
          this.departmentList = treeDataTranslate(data.list, 'departmentId')
220
      }).then(() => {
221
          this.visible = true
222
          this.$nextTick(() => {
223
            this.$refs['dataForm'].resetFields()
224
          })
225
        })
226
      this.$http({
227
        url: this.$http.adornUrl("/sys/user/index"),
228
        method: "get",
229
        params: this.$http.adornParams(),
230
      })
231
        .then(({ data }) => {
232
          this.roleList = data && data.code === 0 ? data.list : [];
233
        })
234
        .then(() => {
235
          this.visible = true;
236
          this.$nextTick(() => {
237
            this.$refs["dataForm"].resetFields();
238
          });
239
        })
240
        .then(() => {
241
          if (this.dataForm.id) {
242
            this.$http({
243
              url: this.$http.adornUrl(`/sys/user/info/${this.dataForm.id}`),
244
              method: "get",
245
              params: this.$http.adornParams(),
246
            }).then(({ data }) => {
247
              if (data && data.code === 0) {
248
                this.dataForm.userName = data.user.username;
249
                this.dataForm.salt = data.user.salt;
250
                this.dataForm.email = data.user.email;
251
                this.dataForm.mobile = data.user.mobile;
252
                this.dataForm.roleIdList = data.user.roleIdList;
253
                this.dataForm.status = data.user.status;
254
                this.dataForm.avatar = data.user.avatar;
255
                this.dataForm.departmentId = data.user.departmentId;
256
                this.dataForm.departmentName = data.user.departmentName;
257
                this.menuListTreeSetCurrentNode()
258
              }
259
            });
260
          }else{
261
            this.menuListTreeSetCurrentNode()
262
          }
263
        });
264
      // this.dialogImageUrl = this.$http.adornUrl(
265
      //   `/sys/oss/uploadimg?token=${this.$cookie.get("token")}`
266
      // );
267
      // console.log(this.dialogImageUrl);
268
    },
269
    // 菜单树选中
270
      departmentListTreeCurrentChangeHandle (data, node) {
271
        this.dataForm.departmentId = data.departmentId
272
        this.dataForm.departmentName = data.departmentName
273
      },
274
      // 菜单树设置当前选中节点
275
      menuListTreeSetCurrentNode () {
276
        this.$refs.departmentListTree.setCurrentKey(this.dataForm.departmentId)
277
        this.dataForm.departmentName = (this.$refs.departmentListTree.getCurrentNode() || {})['departmentName']
278
      },
279
    // 表单提交
280
    dataFormSubmit() {
281
      this.$refs["dataForm"].validate((valid) => {
282
        if (valid) {
283
          this.$http({
284
            url: this.$http.adornUrl(
285
              `/sys/user/${!this.dataForm.id ? "save" : "update"}`
286
            ),
287
            method: "post",
288
            data: this.$http.adornData({
289
              userId: this.dataForm.id || undefined,
290
              username: this.dataForm.userName,
291
              password: this.dataForm.password,
292
              salt: this.dataForm.salt,
293
              email: this.dataForm.email,
294
              mobile: this.dataForm.mobile,
295
              status: this.dataForm.status,
296
              roleIdList: this.dataForm.roleIdList,
297
              departmentId: this.dataForm.departmentId,
298
              avatar: this.dataForm.avatar,
299
            }),
300
          }).then(({ data }) => {
301
            if (data && data.code === 0) {
302
              this.$message({
303
                message: "操作成功",
304
                type: "success",
305
                duration: 1500,
306
                onClose: () => {
307
                  this.visible = false;
308
                  this.$emit("refreshDataList");
309
                },
310
              });
311
            } else {
312
              this.$message.error(data.msg);
313
            }
314
          });
315
        }
316
      });
317
    },
318
  },
319
};
320
</script>
321
<style lang="scss">
322
.avatar-uploader .el-upload {
323
  border: 1px dashed #d9d9d9;
324
  border-radius: 6px;
325
  cursor: pointer;
326
  position: relative;
327
  overflow: hidden;
328
}
329
.avatar-uploader .el-upload:hover {
330
  border-color: #409eff;
331
}
332
.avatar-uploader-icon {
333
  font-size: 28px;
334
  color: #8c939d;
335
  width: 178px;
336
  height: 178px;
337
  line-height: 178px;
338
  text-align: center;
339
}
340
.avatar {
341
  width: 178px;
342
  height: 178px;
343
  display: block;
344
}
345
</style>

+ 195 - 0
src/views/user/user.vue

@ -0,0 +1,195 @@
1
<template>
2
  <div class="app-container">
3
    <el-form :inline="true" :model="dataForm" @keyup.enter.native="getDataList()"  label-width="120px">
4
      <el-form-item>
5
        <el-input v-model="dataForm.userName" placeholder="用户名" clearable></el-input>
6
      </el-form-item>
7
      <el-form-item>
8
        <el-button @click="getDataList()">查询</el-button>
9
        <el-button v-if="" type="primary" @click="addOrUpdateHandle()">新增</el-button>
10
        <el-button v-if="" type="danger" @click="deleteHandle()" :disabled="dataListSelections.length <= 0">批量删除</el-button>
11
      </el-form-item>
12
    </el-form>
13
    <el-table
14
      :data="dataList"
15
      border
16
      v-loading="dataListLoading"
17
      @selection-change="selectionChangeHandle"
18
      style="width: 100%;">
19
      <el-table-column
20
        type="selection"
21
        header-align="center"
22
        align="center"
23
        width="50">
24
      </el-table-column>
25
      <el-table-column
26
        prop="userid"
27
        header-align="center"
28
        align="center"
29
        width="80"
30
        label="ID">
31
      </el-table-column>
32
      <el-table-column
33
        prop="username"
34
        header-align="center"
35
        align="center"
36
        label="用户名">
37
      </el-table-column>
38
      <el-table-column
39
        prop="email"
40
        header-align="center"
41
        align="center"
42
        label="邮箱">
43
      </el-table-column>
44
      <el-table-column
45
        prop="rolename"
46
        header-align="center"
47
        align="center"
48
        label="用户组">
49
      </el-table-column>
50
      <el-table-column
51
        prop="status"
52
        header-align="center"
53
        align="center"
54
        label="状态">
55
        <template slot-scope="scope">
56
          <el-tag v-if="scope.row.status === 0" size="small" type="danger">禁用</el-tag>
57
          <el-tag v-else size="small">正常</el-tag>
58
        </template>
59
      </el-table-column>
60
      <el-table-column
61
        prop="create_time"
62
        header-align="center"
63
        align="center"
64
        width="180"
65
        label="创建时间">
66
      </el-table-column>
67
      <el-table-column
68
        fixed="right"
69
        header-align="center"
70
        align="center"
71
        width="150"
72
        label="操作">
73
        <template slot-scope="scope">
74
          <el-button type="text" size="small" @click="addOrUpdateHandle(scope.row.userId)">修改</el-button>
75
          <el-button type="text" size="small" @click="deleteHandle(scope.row.userId)">删除</el-button>
76
        </template>
77
      </el-table-column>
78
    </el-table>
79
    <el-pagination
80
      @size-change="sizeChangeHandle"
81
      @current-change="currentChangeHandle"
82
      :current-page="pageIndex"
83
      :page-sizes="[10, 20, 50, 100]"
84
      :page-size="pageSize"
85
      :total="totalPage"
86
      layout="total, sizes, prev, pager, next, jumper">
87
    </el-pagination>
88
    <!-- 弹窗, 新增 / 修改 -->
89
    <add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="getDataList"></add-or-update>
90
  </div>
91
</template>
92
93
<script>
94
  import AddOrUpdate from './user-add-or-update'
95
  export default {
96
    data () {
97
      return {
98
        dataForm: {
99
          userName: ''
100
        },
101
        dataList: [],
102
        pageIndex: 1,
103
        pageSize: 10,
104
        totalPage: 0,
105
        dataListLoading: false,
106
        dataListSelections: [],
107
        addOrUpdateVisible: false
108
      }
109
    },
110
    components: {
111
      AddOrUpdate
112
    },
113
    created () {
114
      this.getDataList()
115
    },
116
    methods: {
117
      // 获取数据列表
118
      getDataList () {
119
        this.dataListLoading = true
120
        console.log(1);
121
        this.$http({
122
          url: this.$http.adornUrl('/sys/user/index'),
123
          method: 'get',
124
          params: this.$http.adornParams({
125
            'page': this.pageIndex,
126
            'limit': this.pageSize,
127
            'username': this.dataForm.userName
128
          })
129
        }).then(({data}) => {
130
         console.log(data);
131
          if (data && data.code === 0) {
132
            this.dataList = data.data.data
133
            this.totalPage = data.data.total
134
          } else {
135
            this.dataList = []
136
            this.totalPage = 0
137
          }
138
          this.dataListLoading = false
139
        })
140
      },
141
      // 每页数
142
      sizeChangeHandle (val) {
143
        this.pageSize = val
144
        this.pageIndex = 1
145
        this.getDataList()
146
      },
147
      // 当前页
148
      currentChangeHandle (val) {
149
        this.pageIndex = val
150
        this.getDataList()
151
      },
152
      // 多选
153
      selectionChangeHandle (val) {
154
        this.dataListSelections = val
155
      },
156
      // 新增 / 修改
157
      addOrUpdateHandle (id) {
158
        this.addOrUpdateVisible = true
159
        this.$nextTick(() => {
160
          this.$refs.addOrUpdate.init(id)
161
        })
162
      },
163
      // 删除
164
      deleteHandle (id) {
165
        var userIds = id ? [id] : this.dataListSelections.map(item => {
166
          return item.userId
167
        })
168
        this.$confirm(`确定对[id=${userIds.join(',')}]进行[${id ? '删除' : '批量删除'}]操作?`, '提示', {
169
          confirmButtonText: '确定',
170
          cancelButtonText: '取消',
171
          type: 'warning'
172
        }).then(() => {
173
          this.$http({
174
            url: this.$http.adornUrl('/sys/user/delete'),
175
            method: 'post',
176
            data: this.$http.adornData(userIds, false)
177
          }).then(({data}) => {
178
            if (data && data.code === 0) {
179
              this.$message({
180
                message: '操作成功',
181
                type: 'success',
182
                duration: 1500,
183
                onClose: () => {
184
                  this.getDataList()
185
                }
186
              })
187
            } else {
188
              this.$message.error(data.msg)
189
            }
190
          })
191
        }).catch(() => {})
192
      }
193
    }
194
  }
195
</script>

+ 14 - 2
vue.config.js

@ -27,7 +27,8 @@ module.exports = {
27 27
  publicPath: '/',
28 28
  outputDir: 'dist',
29 29
  assetsDir: 'static',
30
  lintOnSave: process.env.NODE_ENV === 'development',
30
  // lintOnSave: process.env.NODE_ENV === 'development',
31
  lintOnSave: false,
31 32
  productionSourceMap: false,
32 33
  devServer: {
33 34
    port: port,
@ -36,7 +37,18 @@ module.exports = {
36 37
      warnings: false,
37 38
      errors: true
38 39
    },
39
    before: require('./mock/mock-server.js')
40
    // before: require('./mock/mock-server.js')
41
    proxy: {
42
      [process.env.VUE_APP_BASE_API]: {
43
        target: `http://192.168.2.251:8010`,
44
        changeOrigin: true,
45
        ws: true,
46
        secure: false,
47
        pathRewrite: {
48
          ["^" + process.env.VUE_APP_BASE_API]: ""
49
        }
50
      }
51
    }
40 52
  },
41 53
  configureWebpack: {
42 54
    // provide the app's title in webpack's name field, so that