Commit 770bf45f01a239d42a95cb74ec0a6bfac2dac1b6

Authored by xingyu4j
1 parent fab2366d

refactor: profile

yudao-ui-admin-vue3/src/api/system/user/profile/types.ts renamed to yudao-ui-admin-vue3/src/api/system/user/profile.ts
1   -export type ProfileDept = {
  1 +import request from '@/config/axios'
  2 +
  3 +export interface ProfileDept {
2 4 id: number
3 5 name: string
4 6 }
5   -export type ProfileRole = {
  7 +export interface ProfileRole {
6 8 id: number
7 9 name: string
8 10 }
9   -export type ProfilePost = {
  11 +export interface ProfilePost {
10 12 id: number
11 13 name: string
12 14 }
13   -export type SocialUser = {
  15 +export interface SocialUser {
14 16 id: number
15 17 type: number
16 18 openid: string
... ... @@ -22,7 +24,7 @@ export type SocialUser = {
22 24 code: string
23 25 state: string
24 26 }
25   -export type ProfileVO = {
  27 +export interface ProfileVO {
26 28 id: number
27 29 username: string
28 30 nickname: string
... ... @@ -40,3 +42,36 @@ export type ProfileVO = {
40 42 loginDate: Date
41 43 createTime: Date
42 44 }
  45 +
  46 +export interface UserProfileUpdateReqVO {
  47 + nickname: string
  48 + email: string
  49 + mobile: string
  50 + sex: number
  51 +}
  52 +
  53 +// 查询用户个人信息
  54 +export const getUserProfileApi = () => {
  55 + return request.get({ url: '/system/user/profile/get' })
  56 +}
  57 +
  58 +// 修改用户个人信息
  59 +export const updateUserProfileApi = (data: UserProfileUpdateReqVO) => {
  60 + return request.put({ url: '/system/user/profile/update', data })
  61 +}
  62 +
  63 +// 用户密码重置
  64 +export const updateUserPwdApi = (oldPassword: string, newPassword: string) => {
  65 + return request.put({
  66 + url: '/system/user/profile/update-password',
  67 + data: {
  68 + oldPassword: oldPassword,
  69 + newPassword: newPassword
  70 + }
  71 + })
  72 +}
  73 +
  74 +// 用户头像上传
  75 +export const uploadAvatarApi = (data) => {
  76 + return request.upload({ url: '/system/user/profile/update-avatar', data: data })
  77 +}
... ...
yudao-ui-admin-vue3/src/api/system/user/profile/index.ts deleted
1   -import request from '@/config/axios'
2   -
3   -// 查询用户个人信息
4   -export const getUserProfileApi = () => {
5   - return request.get({ url: '/system/user/profile/get' })
6   -}
7   -
8   -// 修改用户个人信息
9   -export const updateUserProfileApi = (params) => {
10   - return request.put({ url: '/system/user/profile/update', params })
11   -}
12   -
13   -// 用户密码重置
14   -export const updateUserPwdApi = (oldPassword: string, newPassword: string) => {
15   - return request.put({
16   - url: '/system/user/profile/update-password',
17   - data: {
18   - oldPassword: oldPassword,
19   - newPassword: newPassword
20   - }
21   - })
22   -}
23   -
24   -// 用户头像上传
25   -export const uploadAvatarApi = (data) => {
26   - return request.upload({ url: '/system/user/profile/update-avatar', data: data })
27   -}
yudao-ui-admin-vue3/src/api/system/user/socialUser.ts 0 → 100644
  1 +import request from '@/config/axios'
  2 +
  3 +// 社交绑定,使用 code 授权码
  4 +export const socialBind = (type, code, state) => {
  5 + return request.post({
  6 + url: '/system/social-user/bind',
  7 + data: {
  8 + type,
  9 + code,
  10 + state
  11 + }
  12 + })
  13 +}
  14 +
  15 +// 取消社交绑定
  16 +export const socialUnbind = (type, openid) => {
  17 + return request.delete({
  18 + url: '/system/social-user/unbind',
  19 + data: {
  20 + type,
  21 + openid
  22 + }
  23 + })
  24 +}
  25 +
  26 +// 社交授权的跳转
  27 +export const socialAuthRedirect = (type, redirectUri) => {
  28 + return request.get({
  29 + url: '/system/auth/social-auth-redirect?type=' + type + '&redirectUri=' + redirectUri
  30 + })
  31 +}
... ...
yudao-ui-admin-vue3/src/views/Profile/Index.vue
1   -<script setup lang="ts">
2   -import { ref } from 'vue'
3   -import { useI18n } from '@/hooks/web/useI18n'
4   -import { ElCard, ElTabs, ElTabPane } from 'element-plus'
5   -import { BasicInfo, ProfileUser, ResetPwd, UserSocial } from './components/'
6   -const { t } = useI18n()
7   -const activeName = ref('basicInfo')
8   -</script>
9 1 <template>
10 2 <div class="flex">
11 3 <el-card class="w-1/3 user" shadow="hover">
... ... @@ -38,6 +30,15 @@ const activeName = ref(&#39;basicInfo&#39;)
38 30 </el-card>
39 31 </div>
40 32 </template>
  33 +<script setup lang="ts">
  34 +import { ref } from 'vue'
  35 +import { useI18n } from '@/hooks/web/useI18n'
  36 +import { ElCard, ElTabs, ElTabPane } from 'element-plus'
  37 +import { BasicInfo, ProfileUser, ResetPwd, UserSocial } from './components/'
  38 +const { t } = useI18n()
  39 +
  40 +const activeName = ref('basicInfo')
  41 +</script>
41 42 <style scoped>
42 43 .user {
43 44 max-height: 960px;
... ...
yudao-ui-admin-vue3/src/views/Profile/components/BasicInfo.vue
  1 +<template>
  2 + <Form ref="formRef" :rules="rules" :schema="schema" :labelWidth="80">
  3 + <template #sex>
  4 + <el-radio-group v-model="sexVlue">
  5 + <el-radio :label="1">{{ t('profile.user.man') }}</el-radio>
  6 + <el-radio :label="2">{{ t('profile.user.woman') }}</el-radio>
  7 + </el-radio-group>
  8 + </template>
  9 + </Form>
  10 + <el-button type="primary" @click="submit()">{{ t('common.save') }}</el-button>
  11 + <el-button type="danger" @click="init()">{{ t('common.reset') }}</el-button>
  12 +</template>
1 13 <script setup lang="ts">
2   -import { ref, reactive, onMounted } from 'vue'
3   -import type { FormRules, FormInstance } from 'element-plus'
4   -import { ElForm, ElFormItem, ElInput, ElRadioGroup, ElRadio, ElMessage } from 'element-plus'
  14 +import { reactive, onMounted, unref, ref } from 'vue'
  15 +import type { FormRules } from 'element-plus'
  16 +import { ElMessage, ElRadioGroup, ElRadio } from 'element-plus'
5 17 import { useI18n } from '@/hooks/web/useI18n'
6   -import { getUserProfileApi, updateUserProfileApi } from '@/api/system/user/profile'
  18 +import {
  19 + getUserProfileApi,
  20 + updateUserProfileApi,
  21 + UserProfileUpdateReqVO
  22 +} from '@/api/system/user/profile'
  23 +import { FormSchema } from '@/types/form'
  24 +import { FormExpose } from '@/components/Form'
7 25 const { t } = useI18n()
8   -const formRef = ref<FormInstance>()
9   -interface BasicUserInfoVO {
10   - id: number
11   - nickname: string
12   - email: string
13   - mobile: string
14   - sex: number
15   -}
16   -interface userInfoType {
17   - basicUserInfo: BasicUserInfoVO
18   -}
19   -const user = reactive<userInfoType>({
20   - basicUserInfo: {
21   - id: 0,
22   - nickname: '',
23   - mobile: '',
24   - email: '',
25   - sex: 0
26   - }
27   -})
28 26 // 表单校验
29 27 const rules = reactive<FormRules>({
30 28 nickname: [{ required: true, message: t('profile.rules.nickname'), trigger: 'blur' }],
... ... @@ -45,47 +43,49 @@ const rules = reactive&lt;FormRules&gt;({
45 43 }
46 44 ]
47 45 })
48   -const submit = (formEl: FormInstance | undefined) => {
49   - if (!formEl) return
50   - formEl.validate(async (valid) => {
  46 +const schema = reactive<FormSchema[]>([
  47 + {
  48 + field: 'nickname',
  49 + label: t('profile.user.nickname'),
  50 + component: 'Input'
  51 + },
  52 + {
  53 + field: 'mobile',
  54 + label: t('profile.user.mobile'),
  55 + component: 'Input'
  56 + },
  57 + {
  58 + field: 'email',
  59 + label: t('profile.user.email'),
  60 + component: 'Input'
  61 + },
  62 + {
  63 + field: 'sex',
  64 + label: t('profile.user.sex'),
  65 + component: 'InputNumber'
  66 + }
  67 +])
  68 +const sexVlue = ref<number>()
  69 +const formRef = ref<FormExpose>() // 表单 Ref
  70 +const submit = () => {
  71 + const elForm = unref(formRef)?.getElFormRef()
  72 + if (!elForm) return
  73 + elForm.validate(async (valid) => {
51 74 if (valid) {
52   - await updateUserProfileApi({ params: user.basicUserInfo })
  75 + const data = unref(formRef)?.formModel as UserProfileUpdateReqVO
  76 + data.sex = sexVlue.value as unknown as number
  77 + await updateUserProfileApi(data)
53 78 ElMessage.success(t('common.updateSuccess'))
  79 + await init()
54 80 }
55 81 })
56 82 }
57   -const reset = async (formEl: FormInstance | undefined) => {
58   - if (!formEl) return
59   - await getUserInfo()
60   -}
61   -const getUserInfo = async () => {
62   - const users = await getUserProfileApi()
63   - user.basicUserInfo = users
  83 +const init = async () => {
  84 + const res = await getUserProfileApi()
  85 + sexVlue.value = res.sex
  86 + unref(formRef)?.setValues(res)
64 87 }
65 88 onMounted(async () => {
66   - await getUserInfo()
  89 + await init()
67 90 })
68 91 </script>
69   -<template>
70   - <el-form ref="form" :model="user.basicUserInfo" :rules="rules" label-width="80px">
71   - <el-form-item :label="t('profile.user.nickname')" prop="nickname">
72   - <el-input v-model="user.basicUserInfo.nickname" />
73   - </el-form-item>
74   - <el-form-item :label="t('profile.user.mobile')" prop="mobile">
75   - <el-input v-model="user.basicUserInfo.mobile" maxlength="11" />
76   - </el-form-item>
77   - <el-form-item :label="t('profile.user.email')" prop="email">
78   - <el-input v-model="user.basicUserInfo.email" maxlength="50" />
79   - </el-form-item>
80   - <el-form-item :label="t('profile.user.sex')" prop="sex">
81   - <el-radio-group v-model="user.basicUserInfo.sex">
82   - <el-radio :label="1">{{ t('profile.user.man') }}</el-radio>
83   - <el-radio :label="2">{{ t('profile.user.woman') }}</el-radio>
84   - </el-radio-group>
85   - </el-form-item>
86   - <el-form-item>
87   - <el-button type="primary" @click="submit(formRef)">{{ t('common.save') }}</el-button>
88   - <el-button type="danger" @click="reset(formRef)">{{ t('common.reset') }}</el-button>
89   - </el-form-item>
90   - </el-form>
91   -</template>
... ...
yudao-ui-admin-vue3/src/views/Profile/components/ProfileUser.vue
1   -<script setup lang="ts">
2   -import { getUserProfileApi } from '@/api/system/user/profile'
3   -import { onMounted, reactive } from 'vue'
4   -import dayjs from 'dayjs'
5   -import UserAvatar from './UserAvatar.vue'
6   -import { ProfileVO } from '@/api/system/user/profile/types'
7   -import { useI18n } from '@/hooks/web/useI18n'
8   -const { t } = useI18n()
9   -interface userInfoType {
10   - user: ProfileVO
11   -}
12   -const userInfo = reactive<userInfoType>({
13   - user: {
14   - id: 0,
15   - username: '',
16   - nickname: '',
17   - dept: {
18   - id: 0,
19   - name: ''
20   - },
21   - roles: [],
22   - posts: [],
23   - socialUsers: [],
24   - email: '',
25   - mobile: '',
26   - sex: 0,
27   - avatar: '',
28   - status: 0,
29   - remark: '',
30   - loginIp: '',
31   - loginDate: new Date(),
32   - createTime: new Date()
33   - }
34   -})
35   -const getUserInfo = async () => {
36   - const users = await getUserProfileApi()
37   - userInfo.user = users
38   -}
39   -onMounted(async () => {
40   - await getUserInfo()
41   -})
42   -</script>
43 1 <template>
44 2 <div>
45 3 <div class="text-center">
46   - <UserAvatar :img="userInfo.user.avatar" />
  4 + <UserAvatar :img="userInfo?.avatar" />
47 5 </div>
48 6 <ul class="list-group list-group-striped">
49 7 <li class="list-group-item">
50 8 <Icon icon="ep:user" class="mr-5px" />{{ t('profile.user.username') }}
51   - <div class="pull-right">{{ userInfo.user.username }}</div>
  9 + <div class="pull-right">{{ userInfo?.username }}</div>
52 10 </li>
53 11 <li class="list-group-item">
54 12 <Icon icon="ep:phone" class="mr-5px" />{{ t('profile.user.mobile') }}
55   - <div class="pull-right">{{ userInfo.user.mobile }}</div>
  13 + <div class="pull-right">{{ userInfo?.mobile }}</div>
56 14 </li>
57 15 <li class="list-group-item">
58 16 <Icon icon="fontisto:email" class="mr-5px" />{{ t('profile.user.email') }}
59   - <div class="pull-right">{{ userInfo.user.email }}</div>
  17 + <div class="pull-right">{{ userInfo?.email }}</div>
60 18 </li>
61 19 <li class="list-group-item">
62 20 <Icon icon="carbon:tree-view-alt" class="mr-5px" />{{ t('profile.user.dept') }}
63   - <div class="pull-right" v-if="userInfo.user.dept">{{ userInfo.user.dept.name }}</div>
  21 + <div class="pull-right" v-if="userInfo?.dept">{{ userInfo?.dept.name }}</div>
64 22 </li>
65 23 <li class="list-group-item">
66 24 <Icon icon="ep:suitcase" class="mr-5px" />{{ t('profile.user.posts') }}
67   - <div class="pull-right" v-if="userInfo.user.posts">
68   - {{ userInfo.user.posts.map((post) => post.name).join(',') }}
  25 + <div class="pull-right" v-if="userInfo?.posts">
  26 + {{ userInfo?.posts.map((post) => post.name).join(',') }}
69 27 </div>
70 28 </li>
71 29 <li class="list-group-item">
72 30 <Icon icon="icon-park-outline:peoples" class="mr-5px" />{{ t('profile.user.roles') }}
73   - <div class="pull-right" v-if="userInfo.user.roles">
74   - {{ userInfo.user.roles.map((role) => role.name).join(',') }}
  31 + <div class="pull-right" v-if="userInfo?.roles">
  32 + {{ userInfo?.roles.map((role) => role.name).join(',') }}
75 33 </div>
76 34 </li>
77 35 <li class="list-group-item">
78 36 <Icon icon="ep:calendar" class="mr-5px" />{{ t('profile.user.createTime') }}
79   - <div class="pull-right">{{ dayjs(userInfo.user.createTime).format('YYYY-MM-DD') }}</div>
  37 + <div class="pull-right">{{ dayjs(userInfo?.createTime).format('YYYY-MM-DD') }}</div>
80 38 </li>
81 39 </ul>
82 40 </div>
83 41 </template>
  42 +<script setup lang="ts">
  43 +import { getUserProfileApi, ProfileVO } from '@/api/system/user/profile'
  44 +import { onMounted, ref } from 'vue'
  45 +import dayjs from 'dayjs'
  46 +import UserAvatar from './UserAvatar.vue'
  47 +import { useI18n } from '@/hooks/web/useI18n'
  48 +const { t } = useI18n()
  49 +const userInfo = ref<ProfileVO>()
  50 +const getUserInfo = async () => {
  51 + const users = await getUserProfileApi()
  52 + userInfo.value = users
  53 +}
  54 +onMounted(async () => {
  55 + await getUserInfo()
  56 +})
  57 +</script>
  58 +
84 59 <style scoped>
85 60 .text-center {
86 61 text-align: center;
... ...
yudao-ui-admin-vue3/src/views/Profile/components/ResetPwd.vue
  1 +<template>
  2 + <el-form ref="formRef" :model="password" :rules="rules" label-width="80px">
  3 + <el-form-item :label="t('profile.password.oldPassword')">
  4 + <InputPassword v-model="password.oldPassword" />
  5 + </el-form-item>
  6 + <el-form-item :label="t('profile.password.newPassword')">
  7 + <InputPassword v-model="password.newPassword" strength />
  8 + </el-form-item>
  9 + <el-form-item :label="t('profile.password.confirmPassword')">
  10 + <InputPassword v-model="password.confirmPassword" strength />
  11 + </el-form-item>
  12 + <el-form-item>
  13 + <XButton type="primary" @click="submit(formRef)" :title="t('common.save')" />
  14 + <XButton type="danger" :title="t('common.reset')" @click="reset(formRef)" />
  15 + </el-form-item>
  16 + </el-form>
  17 +</template>
1 18 <script setup lang="ts">
2 19 import { InputPassword } from '@/components/InputPassword'
3 20 import { ElForm, ElFormItem, ElMessage } from 'element-plus'
... ... @@ -49,20 +66,3 @@ const reset = (formEl: FormInstance | undefined) =&gt; {
49 66 formEl.resetFields()
50 67 }
51 68 </script>
52   -<template>
53   - <el-form ref="formRef" :model="password" :rules="rules" label-width="80px">
54   - <el-form-item :label="t('profile.password.oldPassword')">
55   - <InputPassword v-model="password.oldPassword" />
56   - </el-form-item>
57   - <el-form-item :label="t('profile.password.newPassword')">
58   - <InputPassword v-model="password.newPassword" strength />
59   - </el-form-item>
60   - <el-form-item :label="t('profile.password.confirmPassword')">
61   - <InputPassword v-model="password.confirmPassword" strength />
62   - </el-form-item>
63   - <el-form-item>
64   - <el-button type="primary" @click="submit(formRef)">{{ t('common.save') }}</el-button>
65   - <el-button type="danger" @click="reset(formRef)">{{ t('common.reset') }}</el-button>
66   - </el-form-item>
67   - </el-form>
68   -</template>
... ...
yudao-ui-admin-vue3/src/views/Profile/components/UserSocial.vue
1   -<script setup lang="ts">
2   -import { ElTable, ElTableColumn } from 'element-plus'
3   -import { onMounted, reactive } from 'vue'
4   -interface sociaType {
5   - title: string
6   - type: string
7   - source: string
8   - img: string
9   -}
10   -interface socialUserType {
11   - socialUser: {
12   - socia: sociaType[]
13   - }
14   -}
15   -const state = reactive<socialUserType>({
16   - socialUser: {
17   - socia: []
18   - }
19   -})
20   -const initSocial = () => {
21   - console.info(1)
22   -}
23   -const bind = () => {
24   - console.info(1)
25   -}
26   -const unbind = () => {
27   - console.info(1)
28   -}
29   -onMounted(async () => {
30   - await initSocial()
31   -})
32   -</script>
33 1 <template>
34   - <el-table :data="state.socialUser.socia" :show-header="false">
35   - <el-table-column label="社交平台" align="left" width="120" prop="socia">
36   - <template #socia="{ row }">
  2 + <el-table :data="socialUsers" :show-header="false">
  3 + <el-table-column type="seq" title="序号" width="60" fixed="left" />
  4 + <el-table-column label="社交平台" align="left" width="120">
  5 + <template #default="{ row }">
37 6 <img style="height: 20px; vertical-align: middle" :src="row.img" alt="" />
38 7 {{ row.title }}
39 8 </template>
40 9 </el-table-column>
41   - <el-table-column label="操作" align="left" prop="action">
42   - <template #action="{ row }">
43   - <div v-if="row.openid">
  10 + <el-table-column label="操作" align="center">
  11 + <template #default="{ row }">
  12 + <template v-if="row.openid">
44 13 已绑定
45   - <el-button link type="primary" @click="unbind()">(解绑)</el-button>
46   - </div>
47   - <div v-else>
  14 + <XTextButton type="primary" @click="unbind(row)" title="(解绑)" />
  15 + </template>
  16 + <template v-else>
48 17 未绑定
49   - <el-button link type="primary" @click="bind()">(绑定)</el-button>
50   - </div>
  18 + <XTextButton type="primary" @click="bind(row)" title="(绑定)" />
  19 + </template>
51 20 </template>
52 21 </el-table-column>
53 22 </el-table>
54 23 </template>
  24 +<script setup lang="ts">
  25 +import { onMounted, ref } from 'vue'
  26 +import { ElTable, ElTableColumn } from 'element-plus'
  27 +import { SystemUserSocialTypeEnum } from '@/utils/constants'
  28 +import { getUserProfileApi, ProfileVO } from '@/api/system/user/profile'
  29 +import { socialAuthRedirect, socialUnbind } from '@/api/system/user/socialUser'
  30 +import { ElMessage } from 'element-plus'
  31 +
  32 +const socialUsers = ref<any[]>([])
  33 +const userInfo = ref<ProfileVO>()
  34 +const initSocial = async () => {
  35 + const res = await getUserProfileApi()
  36 + userInfo.value = res
  37 + for (const i in SystemUserSocialTypeEnum) {
  38 + const socialUser = { ...SystemUserSocialTypeEnum[i] }
  39 + socialUsers.value.push(socialUser)
  40 + if (userInfo.value?.socialUsers) {
  41 + for (const j in userInfo.value.socialUsers) {
  42 + if (socialUser.type === userInfo.value.socialUsers[j].type) {
  43 + socialUser.openid = userInfo.value.socialUsers[j].openid
  44 + break
  45 + }
  46 + }
  47 + }
  48 + }
  49 + console.info(socialUsers.value)
  50 +}
  51 +const bind = (row) => {
  52 + const redirectUri = location.origin + '/user/profile?type=' + row.type
  53 + // 进行跳转
  54 + socialAuthRedirect(row.type, encodeURIComponent(redirectUri)).then((res) => {
  55 + console.log(res.url)
  56 + window.location.href = res.data
  57 + })
  58 +}
  59 +const unbind = async (row) => {
  60 + const res = await socialUnbind(row.type, row.openid)
  61 + if (res) {
  62 + row.openid = undefined
  63 + }
  64 + ElMessage.success('解绑成功')
  65 +}
  66 +
  67 +onMounted(async () => {
  68 + await initSocial()
  69 +})
  70 +</script>
... ...