feat: add platform authentication methods and improve QR code handling

This commit is contained in:
wxg0103 2025-07-25 17:53:54 +08:00
parent 0eb1cf701e
commit f744e8b109
14 changed files with 231 additions and 100 deletions

View File

@ -31,8 +31,30 @@ const putAuthSetting: (auth_type: string, data: any, loading?: Ref<boolean>) =>
return put(`${prefix}/${auth_type}/info`, data, undefined, loading) return put(`${prefix}/${auth_type}/info`, data, undefined, loading)
} }
const platformPrefix = '/chat_user/auth/platform'
const getPlatformInfo: (loading?: Ref<boolean>) => Promise<Result<any>> = (loading) => {
return get(`${platformPrefix}/source`, undefined, loading)
}
const updateConfig: (data: any, loading?: Ref<boolean>) => Promise<Result<any>> = (
data,
loading
) => {
return post(`${platformPrefix}/source`, data, undefined, loading)
}
const validateConnection: (data: any, loading?: Ref<boolean>) => Promise<Result<any>> = (
data,
loading
) => {
return put(`${platformPrefix}/source`, data, undefined, loading)
}
export default { export default {
getAuthSetting, getAuthSetting,
postAuthSetting, postAuthSetting,
putAuthSetting putAuthSetting,
getPlatformInfo,
updateConfig,
validateConnection
} }

View File

@ -1,4 +1,4 @@
import { Result } from '@/request/Result' import {Result} from '@/request/Result'
import { import {
get, get,
post, post,
@ -9,17 +9,17 @@ import {
download, download,
exportFile, exportFile,
} from '@/request/chat/index' } from '@/request/chat/index'
import { type ChatProfile } from '@/api/type/chat' import {type ChatProfile} from '@/api/type/chat'
import { type Ref } from 'vue' import {type Ref} from 'vue'
import type { ResetPasswordRequest } from '@/api/type/user.ts' import type {ResetPasswordRequest} from '@/api/type/user.ts'
import useStore from '@/stores' import useStore from '@/stores'
import type { LoginRequest } from '@/api/type/user' import type {LoginRequest} from '@/api/type/user'
const prefix: any = { _value: '/workspace/' } const prefix: any = {_value: '/workspace/'}
Object.defineProperty(prefix, 'value', { Object.defineProperty(prefix, 'value', {
get: function () { get: function () {
const { user } = useStore() const {user} = useStore()
return this._value + user.getWorkspaceId() + '/application' return this._value + user.getWorkspaceId() + '/application'
}, },
}) })
@ -51,7 +51,7 @@ const chatProfile: (assessToken: string, loading?: Ref<boolean>) => Promise<Resu
assessToken, assessToken,
loading, loading,
) => { ) => {
return get('/profile', { access_token: assessToken }, loading) return get('/profile', {access_token: assessToken}, loading)
} }
/** /**
* *
@ -63,7 +63,7 @@ const anonymousAuthentication: (
assessToken: string, assessToken: string,
loading?: Ref<boolean>, loading?: Ref<boolean>,
) => Promise<Result<any>> = (assessToken, loading) => { ) => Promise<Result<any>> = (assessToken, loading) => {
return post('/auth/anonymous', { access_token: assessToken }, {}, loading) return post('/auth/anonymous', {access_token: assessToken}, {}, loading)
} }
/** /**
* *
@ -77,7 +77,7 @@ const passwordAuthentication: (
password: string, password: string,
loading?: Ref<boolean>, loading?: Ref<boolean>,
) => Promise<Result<any>> = (assessToken, password, loading) => { ) => Promise<Result<any>> = (assessToken, password, loading) => {
return post('auth/password', { access_token: assessToken, password: password }, {}, loading) return post('auth/password', {access_token: assessToken, password: password}, {}, loading)
} }
/** /**
* *
@ -122,38 +122,40 @@ const getCaptcha: (loading?: Ref<boolean>) => Promise<Result<any>> = (loading) =
* *
*/ */
const getQrType: (loading?: Ref<boolean>) => Promise<Result<any>> = (loading) => { const getQrType: (loading?: Ref<boolean>) => Promise<Result<any>> = (loading) => {
return get('qr_type', undefined, loading) return get('auth/qr_type', undefined, loading)
} }
const getQrSource: (loading?: Ref<boolean>) => Promise<Result<any>> = (loading) => { const getQrSource: (loading?: Ref<boolean>) => Promise<Result<any>> = (loading) => {
return get('qr_type/source', undefined, loading) return get('auth/qr_type/source', undefined, loading)
} }
const getDingCallback: (code: string, loading?: Ref<boolean>) => Promise<Result<any>> = ( const getDingCallback: (code: string, accessToken: string, loading?: Ref<boolean>) => Promise<Result<any>> = (
code, code,
accessToken,
loading, loading,
) => { ) => {
return get('dingtalk', { code }, loading) return get('auth/dingtalk', {code, accessToken: accessToken}, loading)
} }
const getDingOauth2Callback: (code: string, loading?: Ref<boolean>) => Promise<Result<any>> = ( const getDingOauth2Callback: (code: string, loading?: Ref<boolean>) => Promise<Result<any>> = (
code, code,
loading, loading,
) => { ) => {
return get('dingtalk/oauth2', { code }, loading) return get('auth/dingtalk/oauth2', {code}, loading)
} }
const getWecomCallback: (code: string, loading?: Ref<boolean>) => Promise<Result<any>> = ( const getWecomCallback: (code: string, accessToken: string, loading?: Ref<boolean>) => Promise<Result<any>> = (
code, code,
accessToken,
loading, loading,
) => { ) => {
return get('wecom', { code }, loading) return get('auth/wecom', {code, accessToken: accessToken}, loading)
} }
const getLarkCallback: (code: string, loading?: Ref<boolean>) => Promise<Result<any>> = ( const getLarkCallback: (code: string, loading?: Ref<boolean>) => Promise<Result<any>> = (
code, code,
loading, loading,
) => { ) => {
return get('lark/oauth2', { code }, loading) return get('auth/lark/oauth2', {code}, loading)
} }
/** /**
@ -274,7 +276,7 @@ const deleteChat: (chat_id: string, loading?: Ref<boolean>) => Promise<Result<an
chat_id, chat_id,
loading, loading,
) => { ) => {
return del(`historical_conversation/${chat_id}`,undefined,undefined ,loading) return del(`historical_conversation/${chat_id}`, undefined, undefined, loading)
} }
/** /**
* *
@ -284,7 +286,7 @@ const deleteChat: (chat_id: string, loading?: Ref<boolean>) => Promise<Result<an
const clearChat: (loading?: Ref<boolean>) => Promise<Result<any>> = ( const clearChat: (loading?: Ref<boolean>) => Promise<Result<any>> = (
loading loading
) => { ) => {
return del(`historical_conversation/clear`,undefined,undefined, loading) return del(`historical_conversation/clear`, undefined, undefined, loading)
} }
/** /**
* *

View File

@ -103,6 +103,14 @@ const batchSync: (sync_type: string, loading?: Ref<boolean>) => Promise<Result<a
) => { ) => {
return post(`${prefix}/sync/${sync_type}`, undefined, undefined, loading) return post(`${prefix}/sync/${sync_type}`, undefined, undefined, loading)
} }
/**
*
*/
const getSyncType: (loading?: Ref<boolean>) => Promise<Result<any>> = (loading) => {
return get(`${prefix}/sync_types`, undefined, loading)
}
export default { export default {
getUserManage, getUserManage,
putUserManage, putUserManage,
@ -112,5 +120,6 @@ export default {
getChatUserList, getChatUserList,
batchAddGroup, batchAddGroup,
batchDelete, batchDelete,
batchSync batchSync,
getSyncType
} }

View File

@ -1,14 +1,17 @@
import { defineStore } from 'pinia' import {defineStore} from 'pinia'
import ChatAPI from '@/api/chat/chat' import ChatAPI from '@/api/chat/chat'
import type { ChatProfile, ChatUserProfile } from '@/api/type/chat' import type {ChatProfile, ChatUserProfile} from '@/api/type/chat'
import type { LoginRequest } from '@/api/type/user' import type {LoginRequest} from '@/api/type/user'
import type { Ref } from 'vue' import type {Ref} from 'vue'
import { getBrowserLang } from '@/locales/index' import {getBrowserLang} from '@/locales/index'
import LoginApi from "@/api/user/login.ts";
import useUserStore from "@/stores/modules/user.ts";
interface ChatUser { interface ChatUser {
// 用户id // 用户id
id: string id: string
} }
interface Chat { interface Chat {
chat_profile?: ChatProfile chat_profile?: ChatProfile
application?: any application?: any
@ -16,6 +19,7 @@ interface Chat {
token?: string token?: string
accessToken?: string accessToken?: string
} }
const useChatUserStore = defineStore('chat-user', { const useChatUserStore = defineStore('chat-user', {
state: (): Chat => ({ state: (): Chat => ({
chat_profile: undefined, chat_profile: undefined,
@ -111,6 +115,41 @@ const useChatUserStore = defineStore('chat-user', {
return true return true
}) })
}, },
async dingCallback(code: string, accessToken: string) {
return ChatAPI.getDingCallback(code, accessToken).then((ok) => {
this.setToken(ok.data.token)
return this.token
})
},
async dingOauth2Callback(code: string) {
return ChatAPI.getDingOauth2Callback(code).then((ok) => {
this.setToken(ok.data.token)
return this.token
})
},
async wecomCallback(code: string, accessToken: string) {
return ChatAPI.getWecomCallback(code, accessToken).then((ok) => {
this.setToken(ok.data.token)
return this.token
})
},
async larkCallback(code: string) {
return ChatAPI.getLarkCallback(code).then((ok) => {
this.setToken(ok.data.token)
return this.token
})
},
async getQrType() {
return ChatAPI.getQrType().then((ok) => {
return ok.data
})
},
async getQrSource() {
return ChatAPI.getQrSource().then((ok) => {
return ok.data
})
},
}, },
}) })

View File

@ -10,9 +10,9 @@
class="mr-8" class="mr-8"
style="background: none" style="background: none"
> >
<img :src="chatUser.chat_profile?.icon" alt="" /> <img :src="chatUser.chat_profile?.icon" alt=""/>
</el-avatar> </el-avatar>
<LogoIcon v-else height="32px" class="mr-8" /> <LogoIcon v-else height="32px" class="mr-8"/>
<h4>{{ chatUser.chat_profile?.application_name }}</h4> <h4>{{ chatUser.chat_profile?.application_name }}</h4>
</div> </div>
</template> </template>
@ -29,9 +29,9 @@
class="mr-8" class="mr-8"
style="background: none" style="background: none"
> >
<img :src="chatUser.chat_profile?.icon" alt="" /> <img :src="chatUser.chat_profile?.icon" alt=""/>
</el-avatar> </el-avatar>
<LogoIcon v-else height="32px" class="mr-8" /> <LogoIcon v-else height="32px" class="mr-8"/>
<h4>{{ chatUser.chat_profile?.application_name }}</h4> <h4>{{ chatUser.chat_profile?.application_name }}</h4>
</div> </div>
</template> </template>
@ -104,7 +104,7 @@
</el-button> </el-button>
</div> </div>
<div v-if="showQrCodeTab"> <div v-if="showQrCodeTab">
<QrCodeTab :tabs="orgOptions" /> <QrCodeTab :tabs="orgOptions"/>
</div> </div>
<div class="login-gradient-divider lighter mt-24" v-if="modeList.length > 1"> <div class="login-gradient-divider lighter mt-24" v-if="modeList.length > 1">
<span>{{ $t('views.login.moreMethod') }}</span> <span>{{ $t('views.login.moreMethod') }}</span>
@ -123,7 +123,7 @@
'font-size': item === 'OAUTH2' ? '8px' : '10px', 'font-size': item === 'OAUTH2' ? '8px' : '10px',
color: theme.themeInfo?.theme, color: theme.themeInfo?.theme,
}" }"
>{{ item }}</span >{{ item }}</span
> >
</el-button> </el-button>
<el-button <el-button
@ -133,7 +133,7 @@
class="login-button-circle color-secondary" class="login-button-circle color-secondary"
@click="changeMode('QR_CODE')" @click="changeMode('QR_CODE')"
> >
<img src="@/assets/icon_qr_outlined.svg" width="25px" /> <img src="@/assets/icon_qr_outlined.svg" width="25px"/>
</el-button> </el-button>
<el-button <el-button
v-if="item === 'LOCAL' && loginMode != 'LOCAL'" v-if="item === 'LOCAL' && loginMode != 'LOCAL'"
@ -150,29 +150,29 @@
</UserLoginLayout> </UserLoginLayout>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref, onBeforeMount } from 'vue' import {onMounted, ref, onBeforeMount} from 'vue'
import { useRoute, useRouter } from 'vue-router' import {useRoute, useRouter} from 'vue-router'
import type { FormInstance, FormRules } from 'element-plus' import type {FormInstance, FormRules} from 'element-plus'
import type { LoginRequest } from '@/api/type/login' import type {LoginRequest} from '@/api/type/login'
import LoginContainer from '@/layout/login-layout/LoginContainer.vue' import LoginContainer from '@/layout/login-layout/LoginContainer.vue'
import UserLoginLayout from '@/layout/login-layout/UserLoginLayout.vue' import UserLoginLayout from '@/layout/login-layout/UserLoginLayout.vue'
import loginApi from '@/api/chat/chat.ts' import loginApi from '@/api/chat/chat.ts'
import { t, getBrowserLang } from '@/locales' import {t, getBrowserLang} from '@/locales'
import useStore from '@/stores' import useStore from '@/stores'
import { useI18n } from 'vue-i18n' import {useI18n} from 'vue-i18n'
import QrCodeTab from '@/views/login/scanCompinents/QrCodeTab.vue' import QrCodeTab from '@/views/chat/user-login/scanCompinents/QrCodeTab.vue'
import { MsgConfirm, MsgError } from '@/utils/message.ts' import {MsgConfirm, MsgError} from '@/utils/message.ts'
import PasswordAuth from '@/views/chat/auth/component/password.vue' import PasswordAuth from '@/views/chat/auth/component/password.vue'
import { isAppIcon } from '@/utils/common' import {isAppIcon} from '@/utils/common'
const router = useRouter() const router = useRouter()
const { theme, chatUser } = useStore() const {theme, chatUser} = useStore()
const { locale } = useI18n({ useScope: 'global' }) const {locale} = useI18n({useScope: 'global'})
const loading = ref<boolean>(false) const loading = ref<boolean>(false)
const route = useRoute() const route = useRoute()
const identifyCode = ref<string>('') const identifyCode = ref<string>('')
const { const {
params: { accessToken }, params: {accessToken},
} = route as any } = route as any
const loginFormRef = ref<FormInstance>() const loginFormRef = ref<FormInstance>()
const loginForm = ref<LoginRequest>({ const loginForm = ref<LoginRequest>({
@ -211,7 +211,7 @@ const loginHandle = () => {
chatUser.ldapLogin(loginForm.value).then((ok) => { chatUser.ldapLogin(loginForm.value).then((ok) => {
router.push({ router.push({
name: 'chat', name: 'chat',
params: { accessToken: chatUser.accessToken }, params: {accessToken: chatUser.accessToken},
query: route.query, query: route.query,
}) })
}) })
@ -219,7 +219,7 @@ const loginHandle = () => {
chatUser.login(loginForm.value).then((ok) => { chatUser.login(loginForm.value).then((ok) => {
router.push({ router.push({
name: 'chat', name: 'chat',
params: { accessToken: chatUser.accessToken }, params: {accessToken: chatUser.accessToken},
query: route.query, query: route.query,
}) })
}) })
@ -239,7 +239,7 @@ onBeforeMount(() => {
}) })
const modeList = ref<string[]>([]) const modeList = ref<string[]>([])
//const QrList = ref<any[]>(['']) const QrList = ref<any[]>([''])
const loginMode = ref('') const loginMode = ref('')
const showQrCodeTab = ref(false) const showQrCodeTab = ref(false)
@ -300,7 +300,8 @@ function redirectAuth(authType: string, needMessage: boolean = false) {
.then(() => { .then(() => {
window.location.href = url window.location.href = url
}) })
.catch(() => {}) .catch(() => {
})
} else { } else {
console.log('url', url) console.log('url', url)
window.location.href = url window.location.href = url
@ -340,6 +341,25 @@ onBeforeMount(() => {
if (modeList.value.length == 1 && ['CAS', 'OIDC', 'OAuth2'].includes(modeList.value[0])) { if (modeList.value.length == 1 && ['CAS', 'OIDC', 'OAuth2'].includes(modeList.value[0])) {
redirectAuth(modeList.value[0]) redirectAuth(modeList.value[0])
} }
// modeList oauth2 cas ldap oidc lark wecom dingtalk
// modeList'CAS', 'OIDC', 'OAuth2' LOCAL
QrList.value = modeList.value.filter((item) => !['CAS', 'OIDC', 'OAuth2', 'LOCAL', 'LDAP'].includes(item))
// modeListlark wecom dingtalk
modeList.value = modeList.value.filter((item) => !['lark', 'wecom', 'dingtalk'].includes(item))
if (QrList.value.length > 0) {
modeList.value.push('QR_CODE')
QrList.value.forEach((item) => {
orgOptions.value.push({
key: item,
value:
item === 'wecom'
? t('views.system.authentication.scanTheQRCode.wecom')
: item === 'dingtalk'
? t('views.system.authentication.scanTheQRCode.dingtalk')
: t('views.system.authentication.scanTheQRCode.lark'),
})
})
}
} }
}) })
</script> </script>

View File

@ -15,7 +15,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref, defineAsyncComponent } from 'vue' import { onMounted, ref, defineAsyncComponent } from 'vue'
import useStore from '@/stores' import useStore from "@/stores";
const { chatUser } = useStore()
interface Tab { interface Tab {
key: string key: string
@ -40,10 +41,9 @@ const props = defineProps<{ tabs: Tab[] }>()
const activeKey = ref('') const activeKey = ref('')
const allConfigs = ref<PlatformConfig[]>([]) const allConfigs = ref<PlatformConfig[]>([])
const config = ref<Config>({ app_key: '', app_secret: '' }) const config = ref<Config>({ app_key: '', app_secret: '' })
const { login } = useStore()
async function getPlatformInfo() { async function getPlatformInfo() {
try { try {
return await login.getQrSource() return await chatUser.getQrSource()
} catch (error) { } catch (error) {
return [] return []
} }

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="flex-center mb-16"> <div class="flex-center mb-16">
<img src="@/assets/logo/logo_dingtalk.svg" alt="" width="24px" class="mr-4" /> <img src="@/assets/logo/logo_dingtalk.svg" alt="" width="24px" class="mr-4"/>
<h2>{{ $t('views.system.authentication.scanTheQRCode.dingtalkQrCode') }}</h2> <h2>{{ $t('views.system.authentication.scanTheQRCode.dingtalkQrCode') }}</h2>
</div> </div>
<div class="ding-talk-qrName"> <div class="ding-talk-qrName">
@ -9,11 +9,11 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { useRouter } from 'vue-router' import {useRoute, useRouter} from 'vue-router'
import { useScriptTag } from '@vueuse/core' import {useScriptTag} from '@vueuse/core'
import { ref, watch } from 'vue' import {ref, watch} from 'vue'
import useStore from '@/stores' import useStore from '@/stores'
import { MsgError } from '@/utils/message' import {MsgError} from '@/utils/message'
// DTFrameLogin QRLogin // DTFrameLogin QRLogin
declare global { declare global {
interface Window { interface Window {
@ -70,10 +70,15 @@ const props = defineProps<{
}>() }>()
const router = useRouter() const router = useRouter()
const { login } = useStore() const {chatUser} = useStore()
const { load } = useScriptTag('https://g.alicdn.com/dingding/h5-dingtalk-login/0.21.0/ddlogin.js') const {load} = useScriptTag('https://g.alicdn.com/dingding/h5-dingtalk-login/0.21.0/ddlogin.js')
const isConfigReady = ref(false) const isConfigReady = ref(false)
const route = useRoute()
const {
params: {accessToken},
} = route as any
const initActive = async () => { const initActive = async () => {
try { try {
await load(true) await load(true)
@ -97,19 +102,21 @@ const initActive = async () => {
{ {
redirect_uri: redirectUri, redirect_uri: redirectUri,
client_id: data.appKey, client_id: data.appKey,
scope: 'openid corpid', scope: 'openid',
response_type: 'code', response_type: 'code',
state: 'fit2cloud-ding-qr', state: 'fit2cloud-ding-chat-qr',
prompt: 'consent', prompt: 'consent',
corpId: data.corp_id corpId: data.corp_id
}, },
(loginResult) => { (loginResult) => {
console.log(loginResult)
const authCode = loginResult.authCode const authCode = loginResult.authCode
login.dingCallback(authCode).then(() => { chatUser.dingCallback(authCode, accessToken).then(() => {
router.push({ name: 'home' }) router.push({name: 'home'})
}) })
}, },
(errorMsg: string) => { (errorMsg: string) => {
console.log(errorMsg)
MsgError(errorMsg) MsgError(errorMsg)
} }
) )
@ -126,7 +133,7 @@ watch(
initActive() initActive()
} }
}, },
{ immediate: true } {immediate: true}
) )
</script> </script>

View File

@ -1,16 +1,22 @@
<template> <template>
<div class="flex-center mb-16"> <div class="flex-center mb-16">
<img src="@/assets/logo/logo_lark.svg " alt="" width="24px" class="mr-4" /> <img src="@/assets/logo/logo_lark.svg " alt="" width="24px" class="mr-4"/>
<h2>{{ $t('views.system.authentication.scanTheQRCode.larkQrCode') }}</h2> <h2>{{ $t('views.system.authentication.scanTheQRCode.larkQrCode') }}</h2>
</div> </div>
<div id="lark-qr" class="lark-qrName"></div> <div id="lark-qr" class="lark-qrName"></div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { useScriptTag } from '@vueuse/core' import {useScriptTag} from '@vueuse/core'
import { onMounted } from 'vue' import {onMounted} from 'vue'
import {useRoute} from "vue-router";
const { load } = useScriptTag( const route = useRoute()
const {
params: {accessToken},
} = route as any
const {load} = useScriptTag(
'https://lf-package-cn.feishucdn.com/obj/feishu-static/lark/passport/qrcode/LarkSSOSDKWebQRCode-1.0.3.js' 'https://lf-package-cn.feishucdn.com/obj/feishu-static/lark/passport/qrcode/LarkSSOSDKWebQRCode-1.0.3.js'
) )
@ -33,7 +39,8 @@ const initActive = async () => {
appSecret: props.config.app_secret appSecret: props.config.app_secret
} }
const redirectUrl = encodeURIComponent(`${window.location.origin}/api/feishu`) const redirectUrl = encodeURIComponent(`${window.location.origin}/chat/api/auth/lark?accessToken=${accessToken}`)
//const redirectUrl = encodeURIComponent(`http://127.0.0.1:8080/chat/api/auth/lark?accessToken=${accessToken}`)
const url = `https://passport.feishu.cn/suite/passport/oauth/authorize?client_id=${data.agentId}&redirect_uri=${redirectUrl}&response_type=code&state=fit2cloud-lark-qr` const url = `https://passport.feishu.cn/suite/passport/oauth/authorize?client_id=${data.agentId}&redirect_uri=${redirectUrl}&response_type=code&state=fit2cloud-lark-qr`
const QRLoginObj = window.QRLogin({ const QRLoginObj = window.QRLogin({
@ -47,7 +54,7 @@ const initActive = async () => {
window.addEventListener('message', async (event: any) => { window.addEventListener('message', async (event: any) => {
if (QRLoginObj.matchOrigin(event.origin) && QRLoginObj.matchData(event.data)) { if (QRLoginObj.matchOrigin(event.origin) && QRLoginObj.matchData(event.data)) {
const loginTmpCode = event.data.tmp_code const loginTmpCode = event.data.tmp_code
window.location.href = `${url}&tmp_code=${loginTmpCode}` window.location.replace(`${url}&tmp_code=${loginTmpCode}`)
} }
}) })
} }

View File

@ -3,7 +3,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { useRouter } from 'vue-router' import {useRoute, useRouter} from 'vue-router'
import * as ww from '@wecom/jssdk' import * as ww from '@wecom/jssdk'
import { import {
WWLoginLangType, WWLoginLangType,
@ -16,10 +16,13 @@ import { MsgError } from '@/utils/message'
import useStore from '@/stores' import useStore from '@/stores'
import { getBrowserLang } from '@/locales' import { getBrowserLang } from '@/locales'
const router = useRouter() const router = useRouter()
const route = useRoute()
const {
params: {accessToken},
} = route as any
const wwLogin = ref({}) const wwLogin = ref({})
const obj = ref<any>({ isWeComLogin: false }) const obj = ref<any>({ isWeComLogin: false })
const { login } = useStore() const { chatUser } = useStore()
const props = defineProps<{ const props = defineProps<{
config: { config: {
@ -53,7 +56,7 @@ const init = async () => {
}, },
onCheckWeComLogin: obj.value, onCheckWeComLogin: obj.value,
async onLoginSuccess({ code }: any) { async onLoginSuccess({ code }: any) {
login.wecomCallback(code).then(() => { chatUser.wecomCallback(code, accessToken).then(() => {
setTimeout(() => { setTimeout(() => {
router.push({ name: 'home' }) router.push({ name: 'home' })
}) })

View File

@ -52,7 +52,7 @@ template
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref } from 'vue' import { reactive, ref } from 'vue'
import { ElForm } from 'element-plus' import { ElForm } from 'element-plus'
import platformApi from '@/api/system/platform-source' import platformApi from '@/api/chat-user/auth-setting.ts'
import { MsgError, MsgSuccess } from '@/utils/message' import { MsgError, MsgSuccess } from '@/utils/message'
import { t } from '@/locales' import { t } from '@/locales'

View File

@ -89,7 +89,7 @@
import { reactive, ref, onMounted } from 'vue' import { reactive, ref, onMounted } from 'vue'
import { copyClick } from '@/utils/clipboard' import { copyClick } from '@/utils/clipboard'
import EditModel from './EditModal.vue' import EditModel from './EditModal.vue'
import platformApi from '@/api/system/platform-source' import platformApi from '@/api/chat-user/auth-setting.ts'
import { MsgError, MsgSuccess } from '@/utils/message' import { MsgError, MsgSuccess } from '@/utils/message'
import { t } from '@/locales' import { t } from '@/locales'
@ -148,7 +148,7 @@ function createPlatform(key: string, name: string): Platform {
return { return {
key, key,
logoSrc: new URL(`../../../assets/logo/logo_${logo}.svg`, import.meta.url).href, logoSrc: new URL(`../../../../assets/logo/logo_${logo}.svg`, import.meta.url).href,
name, name,
isActive: false, isActive: false,
isValid: false, isValid: false,

View File

@ -17,7 +17,7 @@ import { useRouter } from 'vue-router'
import LDAP from './component/LDAP.vue' import LDAP from './component/LDAP.vue'
import CAS from './component/CAS.vue' import CAS from './component/CAS.vue'
import OIDC from './component/OIDC.vue' import OIDC from './component/OIDC.vue'
//import SCAN from './component/SCAN.vue' import SCAN from './component/SCAN.vue'
import OAuth2 from './component/OAuth2.vue' import OAuth2 from './component/OAuth2.vue'
import { t } from '@/locales' import { t } from '@/locales'
@ -43,11 +43,11 @@ const tabList = [
name: 'OAuth2', name: 'OAuth2',
component: OAuth2, component: OAuth2,
}, },
// { {
// label: t('views.system.authentication.scanTheQRCode.title'), label: t('views.system.authentication.scanTheQRCode.title'),
// name: 'SCAN', name: 'SCAN',
// component: SCAN, component: SCAN,
// }, },
] ]

View File

@ -9,8 +9,12 @@
require-asterisk-position="right"> require-asterisk-position="right">
<el-form-item :label="$t('views.userManage.source.label')" prop="sync_type"> <el-form-item :label="$t('views.userManage.source.label')" prop="sync_type">
<el-select v-model="form.sync_type" :placeholder="$t('common.selectPlaceholder')"> <el-select v-model="form.sync_type" :placeholder="$t('common.selectPlaceholder')">
<el-option :label="t('views.userManage.source.local')" value="LOCAL"> <el-option
</el-option> v-for="option in syncTypeOptions"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -31,6 +35,14 @@ import type {FormInstance} from 'element-plus'
import {MsgError, MsgSuccess} from '@/utils/message' import {MsgError, MsgSuccess} from '@/utils/message'
import {t} from '@/locales' import {t} from '@/locales'
import userManageApi from '@/api/system/chat-user' import userManageApi from '@/api/system/chat-user'
import systemChatUserApi from '@/api/system/chat-user'
const syncTypeOptions = ref<Array<{ label: string; value: string }>>([
{label: t('views.userManage.source.local'), value: 'LOCAL'},
{label: t('views.system.authentication.scanTheQRCode.wecom'), value: 'wecom'},
{label: 'LDAP', value: 'LDAP'},
{label: t('views.system.authentication.scanTheQRCode.lark'), value: 'lark'},
])
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'refresh'): void; (e: 'refresh'): void;
@ -48,9 +60,18 @@ const form = ref<{
function open() { function open() {
form.value = {...defaultForm} form.value = {...defaultForm}
getSyncType()
dialogVisible.value = true dialogVisible.value = true
} }
async function getSyncType() {
return systemChatUserApi.getSyncType().then((res) => {
if (res.data && res.data.length > 0) {
syncTypeOptions.value = syncTypeOptions.value.filter(option => res.data.includes(option.value))
}
})
}
const formRef = ref<FormInstance>(); const formRef = ref<FormInstance>();
const rules = reactive({ const rules = reactive({
@ -65,9 +86,9 @@ const submit = async (formEl: FormInstance | undefined) => {
userManageApi.batchSync(form.value.sync_type, loading).then((res) => { userManageApi.batchSync(form.value.sync_type, loading).then((res) => {
if (res.data) { if (res.data) {
const count = res.data.success_count const count = res.data.success_count
let ErrorMsg = ''
if (res.data.conflict_users && res.data.conflict_users.length > 0) { if (res.data.conflict_users && res.data.conflict_users.length > 0) {
// res.data.conflict_users // res.data.conflict_users
let ErrorMsg = ''
res.data.conflict_users.forEach((item: any) => { res.data.conflict_users.forEach((item: any) => {
if (item.type === 'username') { if (item.type === 'username') {
ErrorMsg += '\n\n' + t('views.chatUser.syncMessage.usernameExist') + " [ " + item.users.join(',') + '\n' + ' ]' ErrorMsg += '\n\n' + t('views.chatUser.syncMessage.usernameExist') + " [ " + item.users.join(',') + '\n' + ' ]'
@ -76,10 +97,10 @@ const submit = async (formEl: FormInstance | undefined) => {
ErrorMsg += '\n\n' + t('views.chatUser.syncMessage.nicknameExist') + " [ " + item.users.join(',') + '\n' + ' ]' ErrorMsg += '\n\n' + t('views.chatUser.syncMessage.nicknameExist') + " [ " + item.users.join(',') + '\n' + ' ]'
} }
}) })
MsgSuccess(t('views.chatUser.syncMessage.title', {count: count}) + ErrorMsg)
emit('refresh')
dialogVisible.value = false
} }
MsgSuccess(t('views.chatUser.syncMessage.title', {count: count}) + ErrorMsg)
emit('refresh')
dialogVisible.value = false
} }
}) })

View File

@ -1,14 +1,15 @@
import { RoleTypeEnum } from '@/enums/system' import {RoleTypeEnum} from '@/enums/system'
import { t } from '@/locales' import {t} from '@/locales'
import useStore from '@/stores' import useStore from '@/stores'
import {computed} from "vue";
const { user } = useStore() const {user} = useStore()
export const roleTypeMap: any = { export const roleTypeMap = computed(() => ({
...(user.is_admin() ...(user.is_admin()
? { ? {
[RoleTypeEnum.ADMIN]: t('views.role.systemAdmin'), [RoleTypeEnum.ADMIN]: t('views.role.systemAdmin'),
} }
: {}), : {}),
[RoleTypeEnum.USER]: t('views.role.user'), [RoleTypeEnum.USER]: t('views.role.user'),
[RoleTypeEnum.WORKSPACE_MANAGE]: t('views.role.workspaceAdmin'), [RoleTypeEnum.WORKSPACE_MANAGE]: t('views.role.workspaceAdmin'),
} }))