张延森 před 4 roky
rodič
revize
285db7bd09

+ 5
- 0
src/App.vue Zobrazit soubor

@@ -27,4 +27,9 @@ a {
27 27
 }
28 28
 
29 29
 #app {}
30
+
31
+.el-avatar {
32
+  background-color: transparent !important;
33
+  border: 1px solid rgba(0,0,0, .06);
34
+}
30 35
 </style>

+ 56
- 0
src/components/PageHeader/index.vue Zobrazit soubor

@@ -0,0 +1,56 @@
1
+<template>
2
+
3
+</template>
4
+
5
+<script>
6
+import { onMounted, onUpdated, watch } from 'vue'
7
+import { useModel } from '@/store'
8
+
9
+export default {
10
+  props: {
11
+    title: undefined,
12
+    back: Boolean,
13
+    actions: Array,
14
+  },
15
+
16
+  emits: ['click'],
17
+
18
+  setup(props, context) {
19
+    const {
20
+      setPageTitle,
21
+      setBack,
22
+      setClick,
23
+      setActions,
24
+     } = useModel('pageHeader')
25
+
26
+    // watch 不能正常监控所有类型的 props 变化
27
+    const handlePropsChange = () => {
28
+      if (props.title) {
29
+        setPageTitle(props.title)
30
+      }
31
+
32
+      if (typeof props.back === 'boolean') {
33
+        setBack(props.back)
34
+      }
35
+
36
+      if (props.actions && props.actions.length) {
37
+        setActions(props.actions)
38
+      }
39
+    }
40
+
41
+    onMounted(() => {
42
+      setClick(e => {
43
+        context.emit('click', e)
44
+      })
45
+      
46
+      handlePropsChange()
47
+    })
48
+
49
+    onUpdated(() => {
50
+      handlePropsChange()
51
+    })
52
+
53
+    return {}
54
+  }
55
+}
56
+</script>

+ 9
- 1
src/layouts/UserLayout/components/Menu/MenuTitle.vue Zobrazit soubor

@@ -1,5 +1,5 @@
1 1
 <template>
2
-  <i v-if="menu.icon" :class="menu.icon">&nbsp;</i>
2
+  <i v-if="menu.icon" :class="['menu-icon', menu.icon]">&nbsp;</i>
3 3
   <span>{{menu.title}}</span>
4 4
 </template>
5 5
 
@@ -15,3 +15,11 @@ export default {
15 15
   }
16 16
 }
17 17
 </script>
18
+
19
+<style lang="less" scoped>
20
+.menu-icon {
21
+  font-size: 1.2em;
22
+  display: inline-block;
23
+  padding-right: .2em;
24
+}
25
+</style>

+ 1
- 1
src/layouts/UserLayout/components/PageHeader.vue Zobrazit soubor

@@ -59,7 +59,7 @@ export default {
59 59
       setPageTitle((route.meta || {}).title)
60 60
       setClick()
61 61
       setBack(false)
62
-      setActions(false)
62
+      setActions()
63 63
     })
64 64
 
65 65
     return {

+ 19
- 4
src/layouts/UserLayout/components/User.vue Zobrazit soubor

@@ -1,5 +1,5 @@
1 1
 <template>
2
-  <el-dropdown>
2
+  <el-dropdown @command="handleCommand">
3 3
     <span class="el-dropdown-link">
4 4
       <el-avatar :src="avatar"></el-avatar>
5 5
       <i class="el-icon-arrow-down el-icon--right"></i>
@@ -7,7 +7,7 @@
7 7
     <template #dropdown>
8 8
       <el-dropdown-menu>
9 9
         <el-dropdown-item>修改密码</el-dropdown-item>
10
-        <el-dropdown-item>退 出</el-dropdown-item>
10
+        <el-dropdown-item command="logout">退 出</el-dropdown-item>
11 11
       </el-dropdown-menu>
12 12
     </template>
13 13
   </el-dropdown>
@@ -15,21 +15,36 @@
15 15
 
16 16
 <script>
17 17
 import { computed } from 'vue'
18
+import { useRoute, useRouter } from 'vue-router'
18 19
 import store from '@/store'
19 20
 
20 21
 const { useModel } = store
21 22
 
22 23
 export default {
23 24
   setup(props) {
24
-    const user = useModel('user')
25
+    const { user, logout } = useModel('user')
26
+    const route = useRoute()
27
+    const router = useRouter()
25 28
 
26 29
     const avatar = computed(() => {
27 30
       return user.avatar || 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png'
28 31
     })
29 32
 
33
+    const handleCommand = command => {
34
+      if (command === 'logout') {
35
+        logout().then(() => {
36
+          router.push({
37
+            name: 'login',
38
+            query: {from: encodeURIComponent(route.path)}
39
+          })
40
+        })
41
+      }
42
+    }
43
+
30 44
     return {
31 45
       user,
32
-      avatar
46
+      avatar,
47
+      handleCommand
33 48
     }
34 49
   }
35 50
 }

+ 2
- 0
src/main.js Zobrazit soubor

@@ -5,6 +5,7 @@ import ElementPlus from 'element-plus'
5 5
 import 'element-plus/lib/theme-chalk/index.css'
6 6
 
7 7
 import Cell from '@/components/Cell/index.vue'
8
+import PageHeader from '@/components/PageHeader/index.vue'
8 9
 import QueryForm from '@/components/QueryForm/index.vue'
9 10
 import QueryTable from '@/components/QueryTable/index.vue'
10 11
 import App from './App.vue'
@@ -17,6 +18,7 @@ app.config.errorHandler = (err, vm, info) => {
17 18
 }
18 19
 
19 20
 app.component('cell', Cell)
21
+app.component('page-header', PageHeader)
20 22
 app.component('query-form', QueryForm)
21 23
 app.component('query-table', QueryTable)
22 24
 

+ 8
- 0
src/service/user.js Zobrazit soubor

@@ -4,6 +4,10 @@ export default {
4 4
     url: '/login',
5 5
     method: 'post'
6 6
   },
7
+  logout: {
8
+    url: '/logout',
9
+    method: 'post'
10
+  },
7 11
   detail: {
8 12
     url: '/admin/sysUser/${id}',    
9 13
   },
@@ -13,5 +17,9 @@ export default {
13 17
   save: {
14 18
     url: '/admin/sysUser',
15 19
     method: 'post'
20
+  },
21
+  update: {
22
+    url: '/admin/sysUser/${id}',
23
+    method: 'put'
16 24
   }
17 25
 }

+ 1
- 1
src/store/models/system.js Zobrazit soubor

@@ -11,7 +11,7 @@ export default () => {
11 11
     },
12 12
     menu: {
13 13
       backgroundColor: '#001529',
14
-      textColor: 'rgba(255, 255, 255, .65)',
14
+      textColor: 'rgba(255, 255, 255, .75)',
15 15
       activeTextColor: 'rgb(24, 144, 255)',
16 16
     }
17 17
   })

+ 21
- 2
src/store/models/user.js Zobrazit soubor

@@ -1,7 +1,7 @@
1 1
 import { reactive } from "vue"
2 2
 import service from '@/service'
3 3
 import request from '@/utils/request'
4
-import { setToken } from '@/utils/token'
4
+import { setToken, removeToken } from '@/utils/token'
5 5
 import { replacePathParam } from '@/utils'
6 6
 
7 7
 export default () => {
@@ -33,6 +33,12 @@ export default () => {
33 33
     })
34 34
   }
35 35
 
36
+  const logout = () => {
37
+    return request(service.user.logout).then(res => {
38
+      return removeToken()
39
+    })
40
+  }
41
+
36 42
   const saveUser = data => {
37 43
     return request({
38 44
       ...service.user.save,
@@ -42,12 +48,25 @@ export default () => {
42 48
     })
43 49
   }
44 50
 
51
+  const updateUser = data => {
52
+    const params = {
53
+      ...service.user.update,
54
+      data,
55
+    }
56
+
57
+    return request(replacePathParam(params, {id: data.userId})).then(res => {
58
+      return res
59
+    })
60
+  }
61
+
45 62
   return {
46 63
     user,
47 64
     getUser,
48 65
     getCurrent,
49 66
     setUser,
50 67
     login,
51
-    saveUser
68
+    logout,
69
+    saveUser,
70
+    updateUser,
52 71
   }
53 72
 }

+ 5
- 0
src/utils/token.js Zobrazit soubor

@@ -18,3 +18,8 @@ export function setToken (token) {
18 18
   window.localStorage.setItem('token', token)
19 19
   window.localStorage.setItem('token-created-at', now.valueOf())
20 20
 }
21
+
22
+export function removeToken() {
23
+  window.localStorage.removeItem('token')
24
+  window.localStorage.removeItem('token-created-at')
25
+}

+ 63
- 10
src/views/User/Edit.vue Zobrazit soubor

@@ -1,5 +1,6 @@
1 1
 <template>
2 2
   <div class="user-form" v-loading="loading">
3
+    <page-header :title="formData.name || '人员新增'" :back="true" />
3 4
     <el-form :model="formData" label-width="100px">
4 5
       <el-form-item label="名称" prop="name">
5 6
         <el-input v-model="formData.name" />
@@ -7,6 +8,25 @@
7 8
       <el-form-item label="手机号" prop="phone">
8 9
         <el-input v-model="formData.phone" />
9 10
       </el-form-item>
11
+      <el-form-item label="头像" prop="avatar">
12
+        <el-dropdown @command="handleAvatar($event)">
13
+          <span class="el-dropdown-link">
14
+            <el-avatar :src="formData.avatar" :size="98"></el-avatar>
15
+            <i class="el-icon-arrow-down el-icon--right"></i>
16
+          </span>
17
+          <template #dropdown>
18
+            <el-dropdown-menu>
19
+              <el-dropdown-item
20
+                v-for="avatar in avatars"
21
+                :key="avatar"
22
+                :command="avatar"
23
+              >
24
+                <el-avatar :src="avatar" :size="98"></el-avatar>
25
+              </el-dropdown-item>
26
+            </el-dropdown-menu>
27
+          </template>
28
+        </el-dropdown>
29
+      </el-form-item>
10 30
       <el-form-item label="登录账号" prop="loginName">
11 31
         <el-input v-model="formData.loginName" />
12 32
       </el-form-item>
@@ -15,24 +35,27 @@
15 35
       </el-form-item>
16 36
       <el-form-item label="角色">
17 37
         <el-radio-group v-model="formData.roleId">
18
-          <el-radio :label="2">业务人员</el-radio>
19
-          <el-radio :label="3">运营人员</el-radio>
38
+          <el-radio :label="'2'">业务人员</el-radio>
39
+          <el-radio :label="'3'">运营人员</el-radio>
20 40
         </el-radio-group>
21 41
       </el-form-item>
22 42
       <div class="user-form__action">
23 43
         <el-button type="primary" @click="submit"><i class="fa fa-save">&nbsp;</i> 保 存</el-button>
24
-        <el-button>取 消</el-button>
44
+        <el-button @click="handleCancel()">重置密码</el-button>
45
+        <el-button @click="handleCancel()">取 消</el-button>
25 46
       </div>
26 47
     </el-form>
27 48
   </div>
28 49
 </template>
29 50
 
30 51
 <script>
31
-import { onMounted, reactive, ref } from 'vue'
52
+import { onMounted, onUpdated, reactive, ref } from 'vue'
32 53
 import { useRoute, useRouter } from 'vue-router'
33 54
 import { ElNotification } from 'element-plus'
34 55
 import { useModel } from '@/store'
35 56
 
57
+const defaultAvatars = new Array(12).fill('*').map((_, inx) => `https://zhiyun-image.oss-cn-shanghai.aliyuncs.com/common/images/avatar/${inx+1}.png`)
58
+
36 59
 export default {
37 60
   setup(props) {
38 61
     const loading = ref(false)
@@ -42,12 +65,33 @@ export default {
42 65
 
43 66
     const { id } = route.query
44 67
 
45
-    const { saveUser, getUser } = useModel('user')
46
-    const { setPageTitle, setBack } = useModel('pageHeader')
68
+    const { saveUser, updateUser, getUser } = useModel('user')
47 69
 
48 70
     const submit = () => {
71
+      if (!id) {
72
+        saveFormData(formData)
73
+      } else {
74
+        updateFormData({
75
+          ...formData,
76
+          userId: id,
77
+        })
78
+      }
79
+    }
80
+
81
+    const updateFormData = data => {
49 82
       loading.value = true
50
-      saveUser(formData).then(res => {
83
+      updateUser(data).then(res => {
84
+        loading.value = false
85
+        ElNotification.success({message: '更新成功'})
86
+      }).catch(e => {
87
+        console.error(e)
88
+        loading.value = false
89
+      })
90
+    }
91
+
92
+    const saveFormData = data => {
93
+      loading.value = true
94
+      saveUser(data).then(res => {
51 95
         loading.value = false
52 96
         ElNotification.success({message: '提交成功'})
53 97
         router.replace({name: 'user.edit', query: {id: res.userId}})      
@@ -57,9 +101,15 @@ export default {
57 101
       })
58 102
     }
59 103
 
60
-    onMounted(() => {
61
-      setBack(true)
104
+    const handleCancel = () => {
105
+      router.go(-1)
106
+    }
107
+
108
+    const handleAvatar = e => {
109
+      formData.avatar = e
110
+    }
62 111
 
112
+    onMounted(() => {
63 113
       if (id) {
64 114
         loading.value = true
65 115
         getUser(id).then(res => {
@@ -76,7 +126,10 @@ export default {
76 126
 
77 127
     return {
78 128
       formData,
79
-      submit
129
+      submit,
130
+      handleCancel,
131
+      avatars: defaultAvatars,
132
+      handleAvatar,
80 133
     }
81 134
   }
82 135
 }

+ 5
- 14
src/views/User/index.vue Zobrazit soubor

@@ -1,5 +1,6 @@
1 1
 <template>
2 2
   <div>
3
+    <page-header :actions="actions" @click="handleAdd" />
3 4
     <query-table v-model="list" :request="getUserList" row-key="userId">
4 5
         <template v-slot:search="slotProps">
5 6
           <el-form-item label="姓名" prop="name">
@@ -12,7 +13,7 @@
12 13
         <template #table>
13 14
           <el-table-column prop="avatar" label="头像">
14 15
             <template #default="scope">
15
-              <el-avatar :src="scope.row.avatar"></el-avatar>
16
+              <el-avatar :src="scope.row.avatar" :size="98"></el-avatar>
16 17
             </template>
17 18
           </el-table-column>
18 19
           <el-table-column prop="name" label="名称"></el-table-column>
@@ -46,7 +47,7 @@ import dayjs from 'dayjs'
46 47
 import request from '@/utils/request'
47 48
 import service from '@/service'
48 49
 import Pagination from '@/components/Pagination/index.vue'
49
-import { useModel } from '@/store'
50
+// import { useModel } from '@/store'
50 51
 
51 52
 const getUserList = params => request({
52 53
   ...service.user.list,
@@ -62,8 +63,6 @@ export default {
62 63
     const list = ref([])
63 64
     const router = useRouter()
64 65
 
65
-    const { setBack, setActions, setClick } = useModel('pageHeader')
66
-
67 66
     const formatDate = dt => dayjs(dt).format('YYYY-MM-DD HH:mm')
68 67
     const transferStatus = st => st === 1 ? '正常' : '异常'
69 68
 
@@ -71,21 +70,13 @@ export default {
71 70
       router.push({name: 'user.edit'})
72 71
     }
73 72
 
74
-    onMounted(() => {
75
-      setBack(true)
76
-      setActions([{ icon: 'el-icon-plus', text: '新增' }])
77
-      setClick(handleAdd)
78
-    })
79
-
80
-    watch(list, () => {
81
-      console.log('---------->', list)
82
-    }, {immediate: true})
83
-
84 73
     return {
85 74
       list,
86 75
       formatDate,
87 76
       transferStatus,
88 77
       getUserList,
78
+      actions: [{ icon: 'el-icon-plus', text: '新增' }],
79
+      handleAdd,
89 80
     }
90 81
   }
91 82
 }