xingyu4j пре 2 година
родитељ
комит
770bf45f01

+ 77 - 0
yudao-ui-admin-vue3/src/api/system/user/profile.ts

@@ -0,0 +1,77 @@
+import request from '@/config/axios'
+
+export interface ProfileDept {
+  id: number
+  name: string
+}
+export interface ProfileRole {
+  id: number
+  name: string
+}
+export interface ProfilePost {
+  id: number
+  name: string
+}
+export interface SocialUser {
+  id: number
+  type: number
+  openid: string
+  token: string
+  rawTokenInfo: string
+  nickname: string
+  avatar: string
+  rawUserInfo: string
+  code: string
+  state: string
+}
+export interface ProfileVO {
+  id: number
+  username: string
+  nickname: string
+  dept: ProfileDept
+  roles: ProfileRole[]
+  posts: ProfilePost[]
+  socialUsers: SocialUser[]
+  email: string
+  mobile: string
+  sex: number
+  avatar: string
+  status: number
+  remark: string
+  loginIp: string
+  loginDate: Date
+  createTime: Date
+}
+
+export interface UserProfileUpdateReqVO {
+  nickname: string
+  email: string
+  mobile: string
+  sex: number
+}
+
+// 查询用户个人信息
+export const getUserProfileApi = () => {
+  return request.get({ url: '/system/user/profile/get' })
+}
+
+// 修改用户个人信息
+export const updateUserProfileApi = (data: UserProfileUpdateReqVO) => {
+  return request.put({ url: '/system/user/profile/update', data })
+}
+
+// 用户密码重置
+export const updateUserPwdApi = (oldPassword: string, newPassword: string) => {
+  return request.put({
+    url: '/system/user/profile/update-password',
+    data: {
+      oldPassword: oldPassword,
+      newPassword: newPassword
+    }
+  })
+}
+
+// 用户头像上传
+export const uploadAvatarApi = (data) => {
+  return request.upload({ url: '/system/user/profile/update-avatar', data: data })
+}

+ 0 - 27
yudao-ui-admin-vue3/src/api/system/user/profile/index.ts

@@ -1,27 +0,0 @@
-import request from '@/config/axios'
-
-// 查询用户个人信息
-export const getUserProfileApi = () => {
-  return request.get({ url: '/system/user/profile/get' })
-}
-
-// 修改用户个人信息
-export const updateUserProfileApi = (params) => {
-  return request.put({ url: '/system/user/profile/update', params })
-}
-
-// 用户密码重置
-export const updateUserPwdApi = (oldPassword: string, newPassword: string) => {
-  return request.put({
-    url: '/system/user/profile/update-password',
-    data: {
-      oldPassword: oldPassword,
-      newPassword: newPassword
-    }
-  })
-}
-
-// 用户头像上传
-export const uploadAvatarApi = (data) => {
-  return request.upload({ url: '/system/user/profile/update-avatar', data: data })
-}

+ 0 - 42
yudao-ui-admin-vue3/src/api/system/user/profile/types.ts

@@ -1,42 +0,0 @@
-export type ProfileDept = {
-  id: number
-  name: string
-}
-export type ProfileRole = {
-  id: number
-  name: string
-}
-export type ProfilePost = {
-  id: number
-  name: string
-}
-export type SocialUser = {
-  id: number
-  type: number
-  openid: string
-  token: string
-  rawTokenInfo: string
-  nickname: string
-  avatar: string
-  rawUserInfo: string
-  code: string
-  state: string
-}
-export type ProfileVO = {
-  id: number
-  username: string
-  nickname: string
-  dept: ProfileDept
-  roles: ProfileRole[]
-  posts: ProfilePost[]
-  socialUsers: SocialUser[]
-  email: string
-  mobile: string
-  sex: number
-  avatar: string
-  status: number
-  remark: string
-  loginIp: string
-  loginDate: Date
-  createTime: Date
-}

+ 31 - 0
yudao-ui-admin-vue3/src/api/system/user/socialUser.ts

@@ -0,0 +1,31 @@
+import request from '@/config/axios'
+
+// 社交绑定,使用 code 授权码
+export const socialBind = (type, code, state) => {
+  return request.post({
+    url: '/system/social-user/bind',
+    data: {
+      type,
+      code,
+      state
+    }
+  })
+}
+
+// 取消社交绑定
+export const socialUnbind = (type, openid) => {
+  return request.delete({
+    url: '/system/social-user/unbind',
+    data: {
+      type,
+      openid
+    }
+  })
+}
+
+// 社交授权的跳转
+export const socialAuthRedirect = (type, redirectUri) => {
+  return request.get({
+    url: '/system/auth/social-auth-redirect?type=' + type + '&redirectUri=' + redirectUri
+  })
+}

+ 9 - 8
yudao-ui-admin-vue3/src/views/Profile/Index.vue

@@ -1,11 +1,3 @@
-<script setup lang="ts">
-import { ref } from 'vue'
-import { useI18n } from '@/hooks/web/useI18n'
-import { ElCard, ElTabs, ElTabPane } from 'element-plus'
-import { BasicInfo, ProfileUser, ResetPwd, UserSocial } from './components/'
-const { t } = useI18n()
-const activeName = ref('basicInfo')
-</script>
 <template>
   <div class="flex">
     <el-card class="w-1/3 user" shadow="hover">
@@ -38,6 +30,15 @@ const activeName = ref('basicInfo')
     </el-card>
   </div>
 </template>
+<script setup lang="ts">
+import { ref } from 'vue'
+import { useI18n } from '@/hooks/web/useI18n'
+import { ElCard, ElTabs, ElTabPane } from 'element-plus'
+import { BasicInfo, ProfileUser, ResetPwd, UserSocial } from './components/'
+const { t } = useI18n()
+
+const activeName = ref('basicInfo')
+</script>
 <style scoped>
 .user {
   max-height: 960px;

+ 59 - 59
yudao-ui-admin-vue3/src/views/Profile/components/BasicInfo.vue

@@ -1,30 +1,28 @@
+<template>
+  <Form ref="formRef" :rules="rules" :schema="schema" :labelWidth="80">
+    <template #sex>
+      <el-radio-group v-model="sexVlue">
+        <el-radio :label="1">{{ t('profile.user.man') }}</el-radio>
+        <el-radio :label="2">{{ t('profile.user.woman') }}</el-radio>
+      </el-radio-group>
+    </template>
+  </Form>
+  <el-button type="primary" @click="submit()">{{ t('common.save') }}</el-button>
+  <el-button type="danger" @click="init()">{{ t('common.reset') }}</el-button>
+</template>
 <script setup lang="ts">
-import { ref, reactive, onMounted } from 'vue'
-import type { FormRules, FormInstance } from 'element-plus'
-import { ElForm, ElFormItem, ElInput, ElRadioGroup, ElRadio, ElMessage } from 'element-plus'
+import { reactive, onMounted, unref, ref } from 'vue'
+import type { FormRules } from 'element-plus'
+import { ElMessage, ElRadioGroup, ElRadio } from 'element-plus'
 import { useI18n } from '@/hooks/web/useI18n'
-import { getUserProfileApi, updateUserProfileApi } from '@/api/system/user/profile'
+import {
+  getUserProfileApi,
+  updateUserProfileApi,
+  UserProfileUpdateReqVO
+} from '@/api/system/user/profile'
+import { FormSchema } from '@/types/form'
+import { FormExpose } from '@/components/Form'
 const { t } = useI18n()
-const formRef = ref<FormInstance>()
-interface BasicUserInfoVO {
-  id: number
-  nickname: string
-  email: string
-  mobile: string
-  sex: number
-}
-interface userInfoType {
-  basicUserInfo: BasicUserInfoVO
-}
-const user = reactive<userInfoType>({
-  basicUserInfo: {
-    id: 0,
-    nickname: '',
-    mobile: '',
-    email: '',
-    sex: 0
-  }
-})
 // 表单校验
 const rules = reactive<FormRules>({
   nickname: [{ required: true, message: t('profile.rules.nickname'), trigger: 'blur' }],
@@ -45,47 +43,49 @@ const rules = reactive<FormRules>({
     }
   ]
 })
-const submit = (formEl: FormInstance | undefined) => {
-  if (!formEl) return
-  formEl.validate(async (valid) => {
+const schema = reactive<FormSchema[]>([
+  {
+    field: 'nickname',
+    label: t('profile.user.nickname'),
+    component: 'Input'
+  },
+  {
+    field: 'mobile',
+    label: t('profile.user.mobile'),
+    component: 'Input'
+  },
+  {
+    field: 'email',
+    label: t('profile.user.email'),
+    component: 'Input'
+  },
+  {
+    field: 'sex',
+    label: t('profile.user.sex'),
+    component: 'InputNumber'
+  }
+])
+const sexVlue = ref<number>()
+const formRef = ref<FormExpose>() // 表单 Ref
+const submit = () => {
+  const elForm = unref(formRef)?.getElFormRef()
+  if (!elForm) return
+  elForm.validate(async (valid) => {
     if (valid) {
-      await updateUserProfileApi({ params: user.basicUserInfo })
+      const data = unref(formRef)?.formModel as UserProfileUpdateReqVO
+      data.sex = sexVlue.value as unknown as number
+      await updateUserProfileApi(data)
       ElMessage.success(t('common.updateSuccess'))
+      await init()
     }
   })
 }
-const reset = async (formEl: FormInstance | undefined) => {
-  if (!formEl) return
-  await getUserInfo()
-}
-const getUserInfo = async () => {
-  const users = await getUserProfileApi()
-  user.basicUserInfo = users
+const init = async () => {
+  const res = await getUserProfileApi()
+  sexVlue.value = res.sex
+  unref(formRef)?.setValues(res)
 }
 onMounted(async () => {
-  await getUserInfo()
+  await init()
 })
 </script>
-<template>
-  <el-form ref="form" :model="user.basicUserInfo" :rules="rules" label-width="80px">
-    <el-form-item :label="t('profile.user.nickname')" prop="nickname">
-      <el-input v-model="user.basicUserInfo.nickname" />
-    </el-form-item>
-    <el-form-item :label="t('profile.user.mobile')" prop="mobile">
-      <el-input v-model="user.basicUserInfo.mobile" maxlength="11" />
-    </el-form-item>
-    <el-form-item :label="t('profile.user.email')" prop="email">
-      <el-input v-model="user.basicUserInfo.email" maxlength="50" />
-    </el-form-item>
-    <el-form-item :label="t('profile.user.sex')" prop="sex">
-      <el-radio-group v-model="user.basicUserInfo.sex">
-        <el-radio :label="1">{{ t('profile.user.man') }}</el-radio>
-        <el-radio :label="2">{{ t('profile.user.woman') }}</el-radio>
-      </el-radio-group>
-    </el-form-item>
-    <el-form-item>
-      <el-button type="primary" @click="submit(formRef)">{{ t('common.save') }}</el-button>
-      <el-button type="danger" @click="reset(formRef)">{{ t('common.reset') }}</el-button>
-    </el-form-item>
-  </el-form>
-</template>

+ 27 - 52
yudao-ui-admin-vue3/src/views/Profile/components/ProfileUser.vue

@@ -1,86 +1,61 @@
-<script setup lang="ts">
-import { getUserProfileApi } from '@/api/system/user/profile'
-import { onMounted, reactive } from 'vue'
-import dayjs from 'dayjs'
-import UserAvatar from './UserAvatar.vue'
-import { ProfileVO } from '@/api/system/user/profile/types'
-import { useI18n } from '@/hooks/web/useI18n'
-const { t } = useI18n()
-interface userInfoType {
-  user: ProfileVO
-}
-const userInfo = reactive<userInfoType>({
-  user: {
-    id: 0,
-    username: '',
-    nickname: '',
-    dept: {
-      id: 0,
-      name: ''
-    },
-    roles: [],
-    posts: [],
-    socialUsers: [],
-    email: '',
-    mobile: '',
-    sex: 0,
-    avatar: '',
-    status: 0,
-    remark: '',
-    loginIp: '',
-    loginDate: new Date(),
-    createTime: new Date()
-  }
-})
-const getUserInfo = async () => {
-  const users = await getUserProfileApi()
-  userInfo.user = users
-}
-onMounted(async () => {
-  await getUserInfo()
-})
-</script>
 <template>
   <div>
     <div class="text-center">
-      <UserAvatar :img="userInfo.user.avatar" />
+      <UserAvatar :img="userInfo?.avatar" />
     </div>
     <ul class="list-group list-group-striped">
       <li class="list-group-item">
         <Icon icon="ep:user" class="mr-5px" />{{ t('profile.user.username') }}
-        <div class="pull-right">{{ userInfo.user.username }}</div>
+        <div class="pull-right">{{ userInfo?.username }}</div>
       </li>
       <li class="list-group-item">
         <Icon icon="ep:phone" class="mr-5px" />{{ t('profile.user.mobile') }}
-        <div class="pull-right">{{ userInfo.user.mobile }}</div>
+        <div class="pull-right">{{ userInfo?.mobile }}</div>
       </li>
       <li class="list-group-item">
         <Icon icon="fontisto:email" class="mr-5px" />{{ t('profile.user.email') }}
-        <div class="pull-right">{{ userInfo.user.email }}</div>
+        <div class="pull-right">{{ userInfo?.email }}</div>
       </li>
       <li class="list-group-item">
         <Icon icon="carbon:tree-view-alt" class="mr-5px" />{{ t('profile.user.dept') }}
-        <div class="pull-right" v-if="userInfo.user.dept">{{ userInfo.user.dept.name }}</div>
+        <div class="pull-right" v-if="userInfo?.dept">{{ userInfo?.dept.name }}</div>
       </li>
       <li class="list-group-item">
         <Icon icon="ep:suitcase" class="mr-5px" />{{ t('profile.user.posts') }}
-        <div class="pull-right" v-if="userInfo.user.posts">
-          {{ userInfo.user.posts.map((post) => post.name).join(',') }}
+        <div class="pull-right" v-if="userInfo?.posts">
+          {{ userInfo?.posts.map((post) => post.name).join(',') }}
         </div>
       </li>
       <li class="list-group-item">
         <Icon icon="icon-park-outline:peoples" class="mr-5px" />{{ t('profile.user.roles') }}
-        <div class="pull-right" v-if="userInfo.user.roles">
-          {{ userInfo.user.roles.map((role) => role.name).join(',') }}
+        <div class="pull-right" v-if="userInfo?.roles">
+          {{ userInfo?.roles.map((role) => role.name).join(',') }}
         </div>
       </li>
       <li class="list-group-item">
         <Icon icon="ep:calendar" class="mr-5px" />{{ t('profile.user.createTime') }}
-        <div class="pull-right">{{ dayjs(userInfo.user.createTime).format('YYYY-MM-DD') }}</div>
+        <div class="pull-right">{{ dayjs(userInfo?.createTime).format('YYYY-MM-DD') }}</div>
       </li>
     </ul>
   </div>
 </template>
+<script setup lang="ts">
+import { getUserProfileApi, ProfileVO } from '@/api/system/user/profile'
+import { onMounted, ref } from 'vue'
+import dayjs from 'dayjs'
+import UserAvatar from './UserAvatar.vue'
+import { useI18n } from '@/hooks/web/useI18n'
+const { t } = useI18n()
+const userInfo = ref<ProfileVO>()
+const getUserInfo = async () => {
+  const users = await getUserProfileApi()
+  userInfo.value = users
+}
+onMounted(async () => {
+  await getUserInfo()
+})
+</script>
+
 <style scoped>
 .text-center {
   text-align: center;

+ 17 - 17
yudao-ui-admin-vue3/src/views/Profile/components/ResetPwd.vue

@@ -1,3 +1,20 @@
+<template>
+  <el-form ref="formRef" :model="password" :rules="rules" label-width="80px">
+    <el-form-item :label="t('profile.password.oldPassword')">
+      <InputPassword v-model="password.oldPassword" />
+    </el-form-item>
+    <el-form-item :label="t('profile.password.newPassword')">
+      <InputPassword v-model="password.newPassword" strength />
+    </el-form-item>
+    <el-form-item :label="t('profile.password.confirmPassword')">
+      <InputPassword v-model="password.confirmPassword" strength />
+    </el-form-item>
+    <el-form-item>
+      <XButton type="primary" @click="submit(formRef)" :title="t('common.save')" />
+      <XButton type="danger" :title="t('common.reset')" @click="reset(formRef)" />
+    </el-form-item>
+  </el-form>
+</template>
 <script setup lang="ts">
 import { InputPassword } from '@/components/InputPassword'
 import { ElForm, ElFormItem, ElMessage } from 'element-plus'
@@ -49,20 +66,3 @@ const reset = (formEl: FormInstance | undefined) => {
   formEl.resetFields()
 }
 </script>
-<template>
-  <el-form ref="formRef" :model="password" :rules="rules" label-width="80px">
-    <el-form-item :label="t('profile.password.oldPassword')">
-      <InputPassword v-model="password.oldPassword" />
-    </el-form-item>
-    <el-form-item :label="t('profile.password.newPassword')">
-      <InputPassword v-model="password.newPassword" strength />
-    </el-form-item>
-    <el-form-item :label="t('profile.password.confirmPassword')">
-      <InputPassword v-model="password.confirmPassword" strength />
-    </el-form-item>
-    <el-form-item>
-      <el-button type="primary" @click="submit(formRef)">{{ t('common.save') }}</el-button>
-      <el-button type="danger" @click="reset(formRef)">{{ t('common.reset') }}</el-button>
-    </el-form-item>
-  </el-form>
-</template>

+ 59 - 43
yudao-ui-admin-vue3/src/views/Profile/components/UserSocial.vue

@@ -1,54 +1,70 @@
-<script setup lang="ts">
-import { ElTable, ElTableColumn } from 'element-plus'
-import { onMounted, reactive } from 'vue'
-interface sociaType {
-  title: string
-  type: string
-  source: string
-  img: string
-}
-interface socialUserType {
-  socialUser: {
-    socia: sociaType[]
-  }
-}
-const state = reactive<socialUserType>({
-  socialUser: {
-    socia: []
-  }
-})
-const initSocial = () => {
-  console.info(1)
-}
-const bind = () => {
-  console.info(1)
-}
-const unbind = () => {
-  console.info(1)
-}
-onMounted(async () => {
-  await initSocial()
-})
-</script>
 <template>
-  <el-table :data="state.socialUser.socia" :show-header="false">
-    <el-table-column label="社交平台" align="left" width="120" prop="socia">
-      <template #socia="{ row }">
+  <el-table :data="socialUsers" :show-header="false">
+    <el-table-column type="seq" title="序号" width="60" fixed="left" />
+    <el-table-column label="社交平台" align="left" width="120">
+      <template #default="{ row }">
         <img style="height: 20px; vertical-align: middle" :src="row.img" alt="" />
         {{ row.title }}
       </template>
     </el-table-column>
-    <el-table-column label="操作" align="left" prop="action">
-      <template #action="{ row }">
-        <div v-if="row.openid">
+    <el-table-column label="操作" align="center">
+      <template #default="{ row }">
+        <template v-if="row.openid">
           已绑定
-          <el-button link type="primary" @click="unbind()">(解绑)</el-button>
-        </div>
-        <div v-else>
+          <XTextButton type="primary" @click="unbind(row)" title="(解绑)" />
+        </template>
+        <template v-else>
           未绑定
-          <el-button link type="primary" @click="bind()">(绑定)</el-button>
-        </div>
+          <XTextButton type="primary" @click="bind(row)" title="(绑定)" />
+        </template>
       </template>
     </el-table-column>
   </el-table>
 </template>
+<script setup lang="ts">
+import { onMounted, ref } from 'vue'
+import { ElTable, ElTableColumn } from 'element-plus'
+import { SystemUserSocialTypeEnum } from '@/utils/constants'
+import { getUserProfileApi, ProfileVO } from '@/api/system/user/profile'
+import { socialAuthRedirect, socialUnbind } from '@/api/system/user/socialUser'
+import { ElMessage } from 'element-plus'
+
+const socialUsers = ref<any[]>([])
+const userInfo = ref<ProfileVO>()
+const initSocial = async () => {
+  const res = await getUserProfileApi()
+  userInfo.value = res
+  for (const i in SystemUserSocialTypeEnum) {
+    const socialUser = { ...SystemUserSocialTypeEnum[i] }
+    socialUsers.value.push(socialUser)
+    if (userInfo.value?.socialUsers) {
+      for (const j in userInfo.value.socialUsers) {
+        if (socialUser.type === userInfo.value.socialUsers[j].type) {
+          socialUser.openid = userInfo.value.socialUsers[j].openid
+          break
+        }
+      }
+    }
+  }
+  console.info(socialUsers.value)
+}
+const bind = (row) => {
+  const redirectUri = location.origin + '/user/profile?type=' + row.type
+  // 进行跳转
+  socialAuthRedirect(row.type, encodeURIComponent(redirectUri)).then((res) => {
+    console.log(res.url)
+    window.location.href = res.data
+  })
+}
+const unbind = async (row) => {
+  const res = await socialUnbind(row.type, row.openid)
+  if (res) {
+    row.openid = undefined
+  }
+  ElMessage.success('解绑成功')
+}
+
+onMounted(async () => {
+  await initSocial()
+})
+</script>