UserSocial.vue 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. <template>
  2. <el-table :data="socialUsers" :show-header="false">
  3. <el-table-column fixed="left" title="序号" type="seq" width="60" />
  4. <el-table-column align="left" label="社交平台" width="120">
  5. <template #default="{ row }">
  6. <img :src="row.img" alt="" class="h-5 align-middle" />
  7. <p class="mr-5">{{ row.title }}</p>
  8. </template>
  9. </el-table-column>
  10. <el-table-column align="center" label="操作">
  11. <template #default="{ row }">
  12. <template v-if="row.openid">
  13. 已绑定
  14. <XTextButton class="mr-5" title="(解绑)" type="primary" @click="unbind(row)" />
  15. </template>
  16. <template v-else>
  17. 未绑定
  18. <XTextButton class="mr-5" title="(绑定)" type="primary" @click="bind(row)" />
  19. </template>
  20. </template>
  21. </el-table-column>
  22. </el-table>
  23. </template>
  24. <script lang="ts" setup>
  25. import { SystemUserSocialTypeEnum } from '@/utils/constants'
  26. import { getUserProfile, ProfileVO } from '@/api/system/user/profile'
  27. import { socialAuthRedirect, socialBind, socialUnbind } from '@/api/system/user/socialUser'
  28. defineOptions({ name: 'UserSocial' })
  29. defineProps<{
  30. activeName: string
  31. }>()
  32. const message = useMessage()
  33. const socialUsers = ref<any[]>([])
  34. const userInfo = ref<ProfileVO>()
  35. const initSocial = async () => {
  36. socialUsers.value = [] // 重置避免无限增长
  37. const res = await getUserProfile()
  38. userInfo.value = res
  39. for (const i in SystemUserSocialTypeEnum) {
  40. const socialUser = { ...SystemUserSocialTypeEnum[i] }
  41. socialUsers.value.push(socialUser)
  42. if (userInfo.value?.socialUsers) {
  43. for (const j in userInfo.value.socialUsers) {
  44. if (socialUser.type === userInfo.value.socialUsers[j].type) {
  45. socialUser.openid = userInfo.value.socialUsers[j].openid
  46. break
  47. }
  48. }
  49. }
  50. }
  51. }
  52. const route = useRoute()
  53. const emit = defineEmits<{
  54. (e: 'update:activeName', v: string): void
  55. }>()
  56. const bindSocial = () => {
  57. // 社交绑定
  58. const type = getUrlValue('type')
  59. const code = route.query.code
  60. const state = route.query.state
  61. if (!code) {
  62. return
  63. }
  64. socialBind(type, code, state).then(() => {
  65. message.success('绑定成功')
  66. emit('update:activeName', 'userSocial')
  67. initSocial()
  68. })
  69. }
  70. // 双层 encode 需要在回调后进行 decode
  71. function getUrlValue(key: string): string {
  72. const url = new URL(decodeURIComponent(location.href))
  73. return url.searchParams.get(key) ?? ''
  74. }
  75. const bind = (row) => {
  76. // 双层 encode 解决钉钉回调 type 参数丢失的问题
  77. const redirectUri = location.origin + '/user/profile?' + encodeURIComponent(`type=${row.type}`)
  78. // 进行跳转
  79. socialAuthRedirect(row.type, encodeURIComponent(redirectUri)).then((res) => {
  80. window.location.href = res
  81. })
  82. }
  83. const unbind = async (row) => {
  84. const res = await socialUnbind(row.type, row.openid)
  85. if (res) {
  86. row.openid = undefined
  87. }
  88. message.success('解绑成功')
  89. }
  90. onMounted(async () => {
  91. await initSocial()
  92. })
  93. watch(
  94. () => route,
  95. () => {
  96. bindSocial()
  97. },
  98. {
  99. immediate: true
  100. }
  101. )
  102. </script>