Commit 357589c3 authored by youjie's avatar youjie

line绑定

parent a40ae852
...@@ -99,6 +99,9 @@ export default { ...@@ -99,6 +99,9 @@ export default {
resetFailed: "Password reset failed", resetFailed: "Password reset failed",
emailRequiredReset: "Please enter email", emailRequiredReset: "Please enter email",
wechatLoginFailed: 'WeChat Login Failed', wechatLoginFailed: 'WeChat Login Failed',
wechatBindFailed: 'WeChat Bind Failed',
lineLoginFailed: 'Line Login Failed',
lineBindFailed: 'Line Bind Failed',
}, },
common: { common: {
language: 'Language', language: 'Language',
......
...@@ -99,6 +99,9 @@ export default { ...@@ -99,6 +99,9 @@ export default {
resetFailed: "Đặt lại mật khẩu thất bại", resetFailed: "Đặt lại mật khẩu thất bại",
emailRequiredReset: "Vui lòng nhập email", emailRequiredReset: "Vui lòng nhập email",
wechatLoginFailed: 'Đăng nhập WeChat thất bại', wechatLoginFailed: 'Đăng nhập WeChat thất bại',
wechatBindFailed: 'Liên kết WeChat thất bại',
lineLoginFailed: 'Đăng nhập Line thất bại',
lineBindFailed: 'Liên kết Line thất bại',
}, },
common: { common: {
language: 'Ngôn ngữ', language: 'Ngôn ngữ',
......
...@@ -99,6 +99,9 @@ export default { ...@@ -99,6 +99,9 @@ export default {
resetFailed: '密码重置失败', resetFailed: '密码重置失败',
emailRequiredReset: '请输入邮箱', emailRequiredReset: '请输入邮箱',
wechatLoginFailed: '微信登录失败', wechatLoginFailed: '微信登录失败',
wechatBindFailed: '微信绑定失败',
lineLoginFailed: 'Line登录失败',
lineBindFailed: 'Line绑定失败',
}, },
common: { common: {
language: '语言', language: '语言',
......
...@@ -99,6 +99,9 @@ export default { ...@@ -99,6 +99,9 @@ export default {
resetFailed: "密碼重置失敗", resetFailed: "密碼重置失敗",
emailRequiredReset: "請輸入郵箱", emailRequiredReset: "請輸入郵箱",
wechatLoginFailed: '微信登入失敗', wechatLoginFailed: '微信登入失敗',
wechatBindFailed: '微信綁定失敗',
lineLoginFailed: 'Line登入失敗',
lineBindFailed: 'Line綁定失敗',
}, },
common: { common: {
language: '語言', language: '語言',
......
...@@ -424,6 +424,56 @@ class UserService { ...@@ -424,6 +424,56 @@ class UserService {
) )
return response as unknown as HttpResponse return response as unknown as HttpResponse
} }
/**
* line登录
* @param tenantId 租户ID
* @returns
*/
static async lineLoginAsync(tenantId: string,code: string,distributorId: number,parentId?: any,redirectUri?: string): Promise<HttpResponse> {
const data = {
tenantId,
code,
distributorId,
parentId,
redirectUri,
}
// OtaRequest 的响应拦截器会返回 response.data
const response = await OtaRequest.post(
'/member-auth/l-iNELogin-by-code',
data,
{
headers: {
'__tenant': tenantId
}
}
)
return response as unknown as HttpResponse
}
/**
* line绑定
* @param tenantId 租户ID
* @returns
*/
static async lineBindAsync(tenantId: string,code: string,distributorId: number,parentId?: any,redirectUri?: string): Promise<HttpResponse> {
const data = {
tenantId,
code,
distributorId,
parentId,
redirectUri,
}
// OtaRequest 的响应拦截器会返回 response.data
const response = await OtaRequest.post(
'/member-auth/l-iNEBind-by-code',
data,
{
headers: {
'__tenant': tenantId
}
}
)
return response as unknown as HttpResponse
}
/** /**
* 获取微信AppID * 获取微信AppID
* @param tenantId 租户ID * @param tenantId 租户ID
......
...@@ -213,7 +213,55 @@ export const useUserStore = defineStore('user', { ...@@ -213,7 +213,55 @@ export const useUserStore = defineStore('user', {
} }
} catch (error: any) { } catch (error: any) {
console.error('Google login error:', error) console.error('Google login error:', error)
ResultMessage.Error(error.message|| i18n.global.t('login.wechatLoginFailed')) ResultMessage.Error(error.message|| i18n.global.t('login.wechatBindFailed'))
return {
status: 'ERROR',
verify: false
}
}
},
/**
* Line登录
* @param tenantId 租户ID
*/
async setUserLineLoginAsync(tenantId: string, code: string,distributorId: number,parentId?: any,redirectUri?: string): Promise<UserLoginResult> {
try {
const response = await UserService.lineLoginAsync(tenantId, code,distributorId,parentId,redirectUri)
console.log('Google login response:', response)
this.token = response.token || ''
this.userInfo = response.userInfo || {}
this.memberData = response.memberData
return {
status: 'SUCCESS',
verify: false,
data: [response]
}
} catch (error: any) {
console.error('Google login error:', error)
ResultMessage.Error(error.message|| i18n.global.t('login.lineLoginFailed'))
return {
status: 'ERROR',
verify: false
}
}
},
/**
* Line绑定
* @param tenantId 租户ID
*/
async setUserLineBindAsync(tenantId: string, code: string,distributorId: number,parentId?: any,redirectUri?: string): Promise<UserLoginResult> {
try {
const response = await UserService.lineBindAsync(tenantId, code,distributorId,parentId,redirectUri)
return {
status: 'SUCCESS',
verify: false,
data: [response]
}
} catch (error: any) {
console.error('Google login error:', error)
ResultMessage.Error(error.message|| i18n.global.t('login.lineBindFailed'))
return { return {
status: 'ERROR', status: 'ERROR',
verify: false verify: false
......
...@@ -209,13 +209,33 @@ const generateState = () => { ...@@ -209,13 +209,33 @@ const generateState = () => {
// line授权登录 // line授权登录
const loginWithLine = () => { const loginWithLine = () => {
const channelId = openInfo.value.appId; // 替换为你的 LINE Channel ID const channelId = openInfo.value.appId; // 替换为你的 LINE Channel ID
const redirectUri = encodeURIComponent(openInfo.value.redirectUri || 'https://www.oytour.com/#/login/3'); // 替换为你的重定向 URI const redirectUri = encodeURIComponent(openInfo.value.redirectUri || 'http://localhost:8002/login/3'); // 替换为你的重定向 URI
const state = generateState(); // 防止 CSRF 攻击,生成随机的 state 参数 const state = generateState(); // 防止 CSRF 攻击,生成随机的 state 参数
// 构造 LINE 授权 URL // 构造 LINE 授权 URL
const lineLoginUrl = `https://access.line.me/oauth2/v2.1/authorize?response_type=code&client_id=${channelId}&redirect_uri=${redirectUri}&state=${state}&scope=openid%20profile`; const lineLoginUrl = `https://access.line.me/oauth2/v2.1/authorize?response_type=code&client_id=${channelId}&redirect_uri=${redirectUri}&state=${state}&scope=openid%20profile`;
// 跳转到 LINE 登录页面 // 跳转到 LINE 登录页面
window.location.href = lineLoginUrl; window.location.href = lineLoginUrl;
} }
// line登录
const useLineLogin = async(code:string) => {
loading.value = true
try {
const response = await userStore.setUserLineLoginAsync(loginMsg.tenantId?.toString() || '', code, loginMsg.distributorId,loginMsg.parentId,loginMsg.redirectUri)
if (response.status == 'SUCCESS') {
userStore.setLoginType(loginMsg.reType || 0)
Message.success(t('login.loginSuccess'))
const forward = localStorage.getItem('forward')
localStorage.removeItem('forward')
router.push({
path: forward ? forward : '/',
})
}
}catch (error: any) {
Message.error(error.message)
} finally {
loading.value = false
}
}
// 微信授权登录 // 微信授权登录
const loginWechat = () => { const loginWechat = () => {
const redirect_url = openInfo.value.redirectUri || 'https://www.oytour.com/#/login/2' const redirect_url = openInfo.value.redirectUri || 'https://www.oytour.com/#/login/2'
...@@ -293,12 +313,11 @@ const loginHandler = async ({ values, errors }: any) => { ...@@ -293,12 +313,11 @@ const loginHandler = async ({ values, errors }: any) => {
await handleLogin() await handleLogin()
} }
// 手动构建授权URL(适用于无第三方库的简单场景)
const clientId = '532164762940-vk65sge5jab1eq8mgbv1srh672ehnkff.apps.googleusercontent.com';
const redirectUri = encodeURIComponent('https://www.oytour.com/#/login?reType=1'); // 必须与Google控制台配置的一致
const scope = encodeURIComponent('profile email'); // 请求的权限范围
const loginWithGoogle = () => { const loginWithGoogle = () => {
// 手动构建授权URL(适用于无第三方库的简单场景)
const clientId = '532164762940-vk65sge5jab1eq8mgbv1srh672ehnkff.apps.googleusercontent.com';
const redirectUri = encodeURIComponent('https://www.oytour.com/#/login?reType=1'); // 必须与Google控制台配置的一致
const scope = encodeURIComponent('profile email'); // 请求的权限范围
const authUrl = `https://accounts.google.com/o/oauth2/v2/auth?client_id=${clientId}&redirect_uri=${redirectUri}&response_type=code&scope=${scope}&access_type=offline`; const authUrl = `https://accounts.google.com/o/oauth2/v2/auth?client_id=${clientId}&redirect_uri=${redirectUri}&response_type=code&scope=${scope}&access_type=offline`;
window.location.href = authUrl; window.location.href = authUrl;
}; };
...@@ -416,7 +435,7 @@ onMounted(async () => { ...@@ -416,7 +435,7 @@ onMounted(async () => {
if (code) { if (code) {
if(loginMsg.reType==2) useWechatLogin(code) if(loginMsg.reType==2) useWechatLogin(code)
else if(loginMsg.reType==3) {} else if(loginMsg.reType==3) useLineLogin(code)
} }
try { try {
......
...@@ -165,6 +165,7 @@ import providerTypeEnum from '@/utils/providerTypeEnum' ...@@ -165,6 +165,7 @@ import providerTypeEnum from '@/utils/providerTypeEnum'
const { t } = useI18n(); const { t } = useI18n();
const router = useRouter() const router = useRouter()
const { params } = router.currentRoute.value
const userStore = useUserStore() const userStore = useUserStore()
const systemConfigStore = useSystemConfigStore() const systemConfigStore = useSystemConfigStore()
const systemConfig = reactive({ const systemConfig = reactive({
...@@ -184,6 +185,8 @@ const GoogleInfor = ref(null as any) ...@@ -184,6 +185,8 @@ const GoogleInfor = ref(null as any)
const LnlineInfor = ref(null as any) const LnlineInfor = ref(null as any)
// 打开微信绑定账号弹窗信息 // 打开微信绑定账号弹窗信息
const openInfo = ref({} as any) const openInfo = ref({} as any)
const reType = ref(0)
if(params&&params.reType) reType.value = Number(params.reType)
const inData = () =>{ const inData = () =>{
userInfor?.value?.externalLoginList.forEach((x:any) => { userInfor?.value?.externalLoginList.forEach((x:any) => {
...@@ -242,16 +245,31 @@ const generateState = () => { ...@@ -242,16 +245,31 @@ const generateState = () => {
// line授权 // line授权
const loginWithLine = () => { const loginWithLine = () => {
const channelId = openInfo.value.appId; // 替换为你的 LINE Channel ID const channelId = openInfo.value.appId; // 替换为你的 LINE Channel ID
const redirectUri = encodeURIComponent(openInfo.value.redirectUri || 'https://www.oytour.com/#/login/3'); // 替换为你的重定向 URI const redirectUri = encodeURIComponent(openInfo.value.redirectUri || 'https://www.oytour.com/#/login/2/3'); // 替换为你的重定向 URI
const state = generateState(); // 防止 CSRF 攻击,生成随机的 state 参数 const state = generateState(); // 防止 CSRF 攻击,生成随机的 state 参数
// 构造 LINE 授权 URL // 构造 LINE 授权 URL
const lineLoginUrl = `https://access.line.me/oauth2/v2.1/authorize?response_type=code&client_id=${channelId}&redirect_uri=${redirectUri}&state=${state}&scope=openid%20profile`; const lineLoginUrl = `https://access.line.me/oauth2/v2.1/authorize?response_type=code&client_id=${channelId}&redirect_uri=${redirectUri}&state=${state}&scope=openid%20profile`;
// 跳转到 LINE 登录页面 // 跳转到 LINE 登录页面
window.location.href = lineLoginUrl; window.location.href = lineLoginUrl;
} }
// 微信绑定
const useLineBind = async(code:string) => {
loading.value = true
try {
const response = await userStore.setUserWechatBindAsync(systemConfig.tenantId?.toString() || '', code, systemConfig.distributorId,null,'')
if (response.status == 'SUCCESS') {
Message.success(t('personal.bindWechatSuccess'))
getPersonalInfor()
}
}catch (error: any) {
Message.error(error.message)
} finally {
loading.value = false
}
}
// 微信授权 // 微信授权
const loginWechat = () => { const loginWechat = () => {
const redirect_url = openInfo.value.redirectUri || 'https://www.oytour.com/#/login/2' const redirect_url = openInfo.value.redirectUri || 'http://localhost:8002/accountCenter/2/2'
const url = `https://open.weixin.qq.com/connect/qrconnect?appid=${openInfo.value.appId}&redirect_uri=${encodeURIComponent(redirect_url)}&response_type=code&scope=snsapi_login&state=${1}&wechat_redirect=${redirect_url}`; const url = `https://open.weixin.qq.com/connect/qrconnect?appid=${openInfo.value.appId}&redirect_uri=${encodeURIComponent(redirect_url)}&response_type=code&scope=snsapi_login&state=${1}&wechat_redirect=${redirect_url}`;
window.location.href = url; window.location.href = url;
} }
...@@ -365,7 +383,8 @@ onMounted(async () => { ...@@ -365,7 +383,8 @@ onMounted(async () => {
const queryParams = query() const queryParams = query()
const code = queryParams.code const code = queryParams.code
if (code) { if (code) {
useWechatBind(code) if(reType.value==2) useWechatBind(code)
else if(reType.value==3) useLineBind(code)
} }
try { try {
if(loginType.value != 1) { if(loginType.value != 1) {
......
...@@ -17,9 +17,9 @@ ...@@ -17,9 +17,9 @@
<div class="w-[200px] mr-[20px]"> <div class="w-[200px] mr-[20px]">
{{item.phoneCode}} {{ item.phone }} {{item.phoneCode}} {{ item.phone }}
</div> </div>
<div class="w-[200px]" <div class="w-[100px]"
:class="[item.isDefault?'customColor-text-5':'']"> :class="[item.isDefault?'customColor-text-5':'']">
<a-switch v-if="item.isDefault" v-model="item.isDefault" :checked-value="Number(1)" :unchecked-value="Number(0)" disabled/> <!-- <a-switch v-if="item.isDefault" v-model="item.isDefault" :checked-value="Number(1)" :unchecked-value="Number(0)" disabled/> -->
{{ item.isDefault?t('personal.default'):'' }} {{ item.isDefault?t('personal.default'):'' }}
</div> </div>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
......
...@@ -17,6 +17,7 @@ export default defineConfig({ ...@@ -17,6 +17,7 @@ export default defineConfig({
}, },
server: { server: {
port: 8002, port: 8002,
host: '0.0.0.0',
}, },
css: { css: {
preprocessorOptions: { preprocessorOptions: {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment