Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
B
boyueCEnd
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
游洁
boyueCEnd
Commits
357589c3
Commit
357589c3
authored
Dec 02, 2025
by
youjie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
line绑定
parent
a40ae852
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
162 additions
and
13 deletions
+162
-13
en.ts
src/i18n/locales/en.ts
+3
-0
vi.ts
src/i18n/locales/vi.ts
+3
-0
zh-CN.ts
src/i18n/locales/zh-CN.ts
+3
-0
zh-TW.ts
src/i18n/locales/zh-TW.ts
+3
-0
UserService.ts
src/services/UserService.ts
+50
-0
user.ts
src/stores/user.ts
+49
-1
Login.vue
src/views/auth/Login.vue
+26
-7
account.vue
...views/personalCenter/components/accountCenter/account.vue
+22
-3
mailingAddressList.vue
...nalCenter/components/accountCenter/mailingAddressList.vue
+2
-2
vite.config.ts
vite.config.ts
+1
-0
No files found.
src/i18n/locales/en.ts
View file @
357589c3
...
...
@@ -99,6 +99,9 @@ export default {
resetFailed
:
"Password reset failed"
,
emailRequiredReset
:
"Please enter email"
,
wechatLoginFailed
:
'WeChat Login Failed'
,
wechatBindFailed
:
'WeChat Bind Failed'
,
lineLoginFailed
:
'Line Login Failed'
,
lineBindFailed
:
'Line Bind Failed'
,
},
common
:
{
language
:
'Language'
,
...
...
src/i18n/locales/vi.ts
View file @
357589c3
...
...
@@ -99,6 +99,9 @@ export default {
resetFailed
:
"Đặt lại mật khẩu thất bại"
,
emailRequiredReset
:
"Vui lòng nhập email"
,
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
:
{
language
:
'Ngôn ngữ'
,
...
...
src/i18n/locales/zh-CN.ts
View file @
357589c3
...
...
@@ -99,6 +99,9 @@ export default {
resetFailed
:
'密码重置失败'
,
emailRequiredReset
:
'请输入邮箱'
,
wechatLoginFailed
:
'微信登录失败'
,
wechatBindFailed
:
'微信绑定失败'
,
lineLoginFailed
:
'Line登录失败'
,
lineBindFailed
:
'Line绑定失败'
,
},
common
:
{
language
:
'语言'
,
...
...
src/i18n/locales/zh-TW.ts
View file @
357589c3
...
...
@@ -99,6 +99,9 @@ export default {
resetFailed
:
"密碼重置失敗"
,
emailRequiredReset
:
"請輸入郵箱"
,
wechatLoginFailed
:
'微信登入失敗'
,
wechatBindFailed
:
'微信綁定失敗'
,
lineLoginFailed
:
'Line登入失敗'
,
lineBindFailed
:
'Line綁定失敗'
,
},
common
:
{
language
:
'語言'
,
...
...
src/services/UserService.ts
View file @
357589c3
...
...
@@ -424,6 +424,56 @@ class UserService {
)
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
* @param tenantId 租户ID
...
...
src/stores/user.ts
View file @
357589c3
...
...
@@ -213,7 +213,55 @@ export const useUserStore = defineStore('user', {
}
}
catch
(
error
:
any
)
{
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
{
status
:
'ERROR'
,
verify
:
false
...
...
src/views/auth/Login.vue
View file @
357589c3
...
...
@@ -209,13 +209,33 @@ const generateState = () => {
// line授权登录
const
loginWithLine
=
()
=>
{
const
channelId
=
openInfo
.
value
.
appId
;
// 替换为你的 LINE Channel ID
const
redirectUri
=
encodeURIComponent
(
openInfo
.
value
.
redirectUri
||
'http
s://www.oytour.com/#
/login/3'
);
// 替换为你的重定向 URI
const
redirectUri
=
encodeURIComponent
(
openInfo
.
value
.
redirectUri
||
'http
://localhost:8002
/login/3'
);
// 替换为你的重定向 URI
const
state
=
generateState
();
// 防止 CSRF 攻击,生成随机的 state 参数
// 构造 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`
;
// 跳转到 LINE 登录页面
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
redirect_url
=
openInfo
.
value
.
redirectUri
||
'https://www.oytour.com/#/login/2'
...
...
@@ -293,12 +313,11 @@ const loginHandler = async ({ values, errors }: any) => {
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
=
()
=>
{
// 手动构建授权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`
;
window
.
location
.
href
=
authUrl
;
};
...
...
@@ -416,7 +435,7 @@ onMounted(async () => {
if
(
code
)
{
if
(
loginMsg
.
reType
==
2
)
useWechatLogin
(
code
)
else
if
(
loginMsg
.
reType
==
3
)
{}
else
if
(
loginMsg
.
reType
==
3
)
useLineLogin
(
code
)
}
try
{
...
...
src/views/personalCenter/components/accountCenter/account.vue
View file @
357589c3
...
...
@@ -165,6 +165,7 @@ import providerTypeEnum from '@/utils/providerTypeEnum'
const
{
t
}
=
useI18n
();
const
router
=
useRouter
()
const
{
params
}
=
router
.
currentRoute
.
value
const
userStore
=
useUserStore
()
const
systemConfigStore
=
useSystemConfigStore
()
const
systemConfig
=
reactive
({
...
...
@@ -184,6 +185,8 @@ const GoogleInfor = ref(null as any)
const
LnlineInfor
=
ref
(
null
as
any
)
// 打开微信绑定账号弹窗信息
const
openInfo
=
ref
({}
as
any
)
const
reType
=
ref
(
0
)
if
(
params
&&
params
.
reType
)
reType
.
value
=
Number
(
params
.
reType
)
const
inData
=
()
=>
{
userInfor
?.
value
?.
externalLoginList
.
forEach
((
x
:
any
)
=>
{
...
...
@@ -242,16 +245,31 @@ const generateState = () => {
// line授权
const
loginWithLine
=
()
=>
{
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 参数
// 构造 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`
;
// 跳转到 LINE 登录页面
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
redirect_url
=
openInfo
.
value
.
redirectUri
||
'http
s://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
}
`
;
window
.
location
.
href
=
url
;
}
...
...
@@ -365,7 +383,8 @@ onMounted(async () => {
const
queryParams
=
query
()
const
code
=
queryParams
.
code
if
(
code
)
{
useWechatBind
(
code
)
if
(
reType
.
value
==
2
)
useWechatBind
(
code
)
else
if
(
reType
.
value
==
3
)
useLineBind
(
code
)
}
try
{
if
(
loginType
.
value
!=
1
)
{
...
...
src/views/personalCenter/components/accountCenter/mailingAddressList.vue
View file @
357589c3
...
...
@@ -17,9 +17,9 @@
<div
class=
"w-[200px] mr-[20px]"
>
{{
item
.
phoneCode
}}
{{
item
.
phone
}}
</div>
<div
class=
"w-[
2
00px]"
<div
class=
"w-[
1
00px]"
: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'
):
''
}}
</div>
<div
class=
"flex items-center justify-between"
>
...
...
vite.config.ts
View file @
357589c3
...
...
@@ -17,6 +17,7 @@ export default defineConfig({
},
server
:
{
port
:
8002
,
host
:
'0.0.0.0'
,
},
css
:
{
preprocessorOptions
:
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment