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
15d9ad15
Commit
15d9ad15
authored
Nov 26, 2025
by
youjie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
账户中心
parent
2e541790
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
672 additions
and
211 deletions
+672
-211
App.vue
src/App.vue
+7
-15
accDoc.png
src/assets/images/personal/accDoc.png
+0
-0
email.png
src/assets/images/personal/email.png
+0
-0
google.png
src/assets/images/personal/google.png
+0
-0
line.png
src/assets/images/personal/line.png
+0
-0
mm.png
src/assets/images/personal/mm.png
+0
-0
sj.png
src/assets/images/personal/sj.png
+0
-0
wx.png
src/assets/images/personal/wx.png
+0
-0
zh-CN.ts
src/i18n/locales/zh-CN.ts
+22
-1
UserService.ts
src/services/UserService.ts
+72
-0
user.ts
src/stores/user.ts
+57
-5
Login.vue
src/views/auth/Login.vue
+12
-6
forgePassword.vue
src/views/auth/forgePassword.vue
+11
-6
register.vue
src/views/auth/register.vue
+11
-6
accountCenter.vue
src/views/personalCenter/accountCenter.vue
+364
-59
LeftView.vue
src/views/personalCenter/components/LeftView.vue
+82
-80
editEmail.vue
src/views/personalCenter/components/myOrder/editEmail.vue
+5
-5
index.vue
src/views/personalCenter/index.vue
+1
-5
myOrder.vue
src/views/personalCenter/myOrder.vue
+28
-23
No files found.
src/App.vue
View file @
15d9ad15
...
...
@@ -13,16 +13,6 @@ const { t, locale } = useI18n()
const
useUser
=
useUserStore
()
const
systemConfigStore
=
useSystemConfigStore
()
// 判断是否显示语言切换器
const
showLanguageSwitcher
=
computed
(()
=>
{
// 在Layout页面中不显示APP.vue的语言切换器,因为Layout组件有自己的语言切换器
// const layoutRoutes = ['dashboard', 'products', 'orders', 'billing', 'account']
// const currentRouteName = route.name as string
// 如果当前路由使用Layout组件,则不显示APP.vue的语言切换器
return
useUser
.
userInfo
==
null
})
// 监听语言变化,更新 Arco Design 国际化
watch
(
locale
,
async
(
newLocale
)
=>
{
try
{
...
...
@@ -58,10 +48,10 @@ onMounted(async () => {
<
template
>
<ConfigProvider
:locale=
"globalArcoLocale || undefined"
>
<div
id=
"app"
class=
"min-h-screen bg-[#ffffff]"
>
<!-- 主要内容区域 -->
<RouterView
/>
</div>
<div
id=
"app"
class=
"min-h-screen bg-[#ffffff]"
>
<!-- 主要内容区域 -->
<RouterView
/>
</div>
</ConfigProvider>
</
template
>
...
...
@@ -154,7 +144,9 @@ body {
.customColor-text-7
{
color
:
var
(
--
customColor-text-7
);}
.customColor-text-6
{
color
:
var
(
--
customColor-text-6
);}
.customColor-text-5
{
color
:
var
(
--
customColor-text-5
);}
*
{
color
:
var
(
--
customColor-text-10
);
}
@font-face
{
font-family
:
'Source Han Sans CN ExtraLight'
;
...
...
src/assets/images/personal/accDoc.png
0 → 100644
View file @
15d9ad15
376 Bytes
src/assets/images/personal/email.png
0 → 100644
View file @
15d9ad15
962 Bytes
src/assets/images/personal/google.png
0 → 100644
View file @
15d9ad15
4.65 KB
src/assets/images/personal/line.png
0 → 100644
View file @
15d9ad15
3.58 KB
src/assets/images/personal/mm.png
0 → 100644
View file @
15d9ad15
992 Bytes
src/assets/images/personal/sj.png
0 → 100644
View file @
15d9ad15
738 Bytes
src/assets/images/personal/wx.png
0 → 100644
View file @
15d9ad15
1.76 KB
src/i18n/locales/zh-CN.ts
View file @
15d9ad15
...
...
@@ -165,9 +165,30 @@ export default {
binEmail
:
'绑定邮箱'
,
bindEmailFailed
:
'绑定邮箱失败'
,
save
:
'保存'
,
bindGoogleAccount
:
'绑定google'
,
bindWechatAccount
:
'绑定微信'
,
bindLineAccount
:
'绑定Lnline'
,
bindGoogleFailed
:
'绑定google失败'
,
bindWechatSuccess
:
'绑定微信成功'
,
bindGoogleSuccess
:
'绑定google成功'
,
changeBind
:
'换绑'
,
unBind
:
'解绑'
,
securityLevel
:
'安全等级'
,
low
:
'低'
,
medium
:
'中'
,
high
:
'高'
,
passwordSecurityTip
:
' 安全性高的密码可以使账号更安全。建议您定期更换密码,且设置一个包含数字和字母,并且长度超过8位以上的密码。'
,
bindPhoneTip
:
'绑定手机后,您即可享受手机号登录、动态码登录、找回密码等。为了帐号安全建议您在更换手机号后第一时间更换绑定手机。 '
,
changeBindData
:
'更换'
,
bindEmailTip
:
'邮箱用于验证码接收,账户登录。'
,
bindWechatTip
:
'通过微信账户快速登录,无需输入密码。'
,
bindGoogleTip
:
'通过谷歌账户快速登录,无需输入密码。'
,
bindLineTip
:
'绑定手机后,您即可享受手机号登录、动态码登录、找回密码等。为了帐号安全建议您在更换手机号后第一时间更换绑定手机。'
,
notYetBin
:
'暂未绑定'
,
goBind
:
'去绑定'
,
},
// HTTP 错误状态码
httpError
:
{
httpError
:
{
400
:
'请求参数错误'
,
401
:
'未授权,请重新登录'
,
403
:
'拒绝访问,您没有权限执行此操作'
,
...
...
src/services/UserService.ts
View file @
15d9ad15
...
...
@@ -336,6 +336,32 @@ class UserService {
return
response
as
unknown
as
HttpResponse
}
/**
* 谷歌绑定
* @param credential 谷歌token
* @returns
*/
static
async
GoogleBindAsync
(
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/google-bind-by-code'
,
data
,
{
headers
:
{
}
}
)
return
response
as
unknown
as
HttpResponse
}
/**
* 微信登录
* @param tenantId 租户ID
...
...
@@ -361,6 +387,31 @@ class UserService {
)
return
response
as
unknown
as
HttpResponse
}
/**
* 微信绑定
* @param tenantId 租户ID
* @returns
*/
static
async
wechatBindAsync
(
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/we-chat-bind-by-code'
,
data
,
{
headers
:
{
'__tenant'
:
tenantId
}
}
)
return
response
as
unknown
as
HttpResponse
}
/**
* 获取微信AppID
* @param tenantId 租户ID
...
...
@@ -555,6 +606,27 @@ class UserService {
)
return
response
as
unknown
as
HttpResponse
}
/**
* 解绑外部登录账号
* @param tenantId 租户ID(可选)
* @param ProviderType 外部id
*/
static
async
externalunbindBind
(
tenantId
:
string
,
ProviderType
:
string
):
Promise
<
HttpResponse
>
{
const
data
=
{
ProviderType
}
const
response
=
await
OtaRequest
.
get
(
'/member-auth/member-center'
,
data
,
{
headers
:
tenantId
?
{
'__tenant'
:
tenantId
}
:
{}
}
)
return
response
as
unknown
as
HttpResponse
}
}
export
default
UserService
src/stores/user.ts
View file @
15d9ad15
...
...
@@ -42,8 +42,9 @@ export const useUserStore = defineStore('user', {
state
:
()
=>
({
token
:
''
as
string
,
userInfo
:
{}
as
any
,
// 登录用户信息
loginType
:
0
as
number
,
// 0: 账号密码登录, 2: 微信登录, 3: Line登录, 1: Google登录 7: Facebook登录
memberData
:
{}
as
any
,
// 登录会员数据
personalInfo
:
{}
as
any
,
// 个人信息
personalInfo
r
:
{}
as
any
,
// 个人信息
}),
getters
:
{
getUserToken
:
(
state
)
=>
{
...
...
@@ -60,7 +61,7 @@ export const useUserStore = defineStore('user', {
* @param email email
*/
setEmail
(
email
:
string
){
this
.
personalInfo
.
email
=
email
this
.
personalInfo
r
.
email
=
email
},
/**
* 设置用户头像
...
...
@@ -69,8 +70,14 @@ export const useUserStore = defineStore('user', {
setPhoto
(
photo
:
string
){
this
.
memberData
.
photo
=
photo
},
setPersonalInfo
(
personalInfo
:
any
){
this
.
personalInfo
=
personalInfo
setPersonalInfor
(
personalInfor
:
any
){
this
.
personalInfor
=
{
...
this
.
personalInfor
,
...
personalInfor
,
}
},
setLoginType
(
loginType
:
number
){
this
.
loginType
=
loginType
},
/**
* 账号密码登录 - 使用新的 UserService
...
...
@@ -143,6 +150,29 @@ export const useUserStore = defineStore('user', {
}
},
/**
* 谷歌绑定
* @param credential 谷歌凭证
*/
async
setUserGoogleBindAsync
(
tenantId
:
string
,
code
:
string
,
distributorId
:
number
,
parentId
?:
any
,
redirectUri
?:
string
):
Promise
<
UserLoginResult
>
{
try
{
const
response
=
await
UserService
.
GoogleBindAsync
(
tenantId
,
code
,
distributorId
,
parentId
,
redirectUri
)
console
.
log
(
'Google login response:'
,
response
)
return
{
status
:
'SUCCESS'
,
verify
:
false
,
data
:
[
response
]
}
}
catch
(
error
:
any
)
{
console
.
error
(
'Google login error:'
,
error
)
ResultMessage
.
Error
(
error
.
message
||
i18n
.
global
.
t
(
'login.googleLoginFailed'
))
return
{
status
:
'ERROR'
,
verify
:
false
}
}
},
/**
* 微信登录
* @param tenantId 租户ID
...
...
@@ -169,6 +199,28 @@ export const useUserStore = defineStore('user', {
}
},
/**
* 微信绑定
* @param tenantId 租户ID
*/
async
setUserWechatBindAsync
(
tenantId
:
string
,
code
:
string
,
distributorId
:
number
,
parentId
?:
any
,
redirectUri
?:
string
):
Promise
<
UserLoginResult
>
{
try
{
const
response
=
await
UserService
.
wechatBindAsync
(
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.wechatLoginFailed'
))
return
{
status
:
'ERROR'
,
verify
:
false
}
}
},
/**
* 获取微信appid
* @param tenantId 租户ID
...
...
@@ -247,7 +299,7 @@ export const useUserStore = defineStore('user', {
async
setEmailAsync
(
data
:
setRegisterDto
):
Promise
<
UserLoginResult
>
{
try
{
const
response
=
await
UserService
.
resetEmail
(
data
.
tenantId
,
data
)
this
.
userInfo
.
email
=
data
.
email
this
.
personalInfor
.
email
=
data
.
email
return
{
status
:
'SUCCESS'
,
data
:
[
response
]
...
...
src/views/auth/Login.vue
View file @
15d9ad15
<
template
>
<
div
class=
"login h-screen overflow-hidden"
>
<
a-spin
:loading=
"loading"
class=
"login h-screen overflow-hidden"
>
<div
ref=
"loginPage"
class=
"light-login-bg pl-[85px] pr-[98px] pt-[33px] h-full !overflow-y-auto light-login-bg"
>
<loginHeader
/>
...
...
@@ -123,7 +123,7 @@
</div>
</div>
</div>
</
div
>
</
a-spin
>
</template>
<
script
setup
lang=
"ts"
>
import
{
ref
,
reactive
,
computed
,
onMounted
}
from
"vue"
;
...
...
@@ -147,7 +147,7 @@ const { t } = useI18n();
const
userStore
=
useUserStore
()
const
systemConfigStore
=
useSystemConfigStore
()
const
loading
=
ref
(
fals
e
)
const
loading
=
ref
(
tru
e
)
const
router
=
useRouter
()
const
googleButtonContainer
=
ref
(
null
);
...
...
@@ -156,8 +156,8 @@ const loginMsg = reactive({
tenantId
:
systemConfigStore
.
tenantId
||
null
,
reType
:
0
,
//登录方式 0账号密码 1谷歌授权 3LINE授权 7FaceBook授权
openId
:
""
,
email
:
"
2310721242@qq.com"
,
//
password
:
'
yj123456'
,
//
123456
email
:
"
"
,
//2310721242@qq.com
password
:
'
'
,
//yj
123456
distributorId
:
systemConfigStore
.
distributorId
as
any
,
parentId
:
null
,
redirectUri
:
''
,
...
...
@@ -242,6 +242,7 @@ const useWechatLogin = async(code:string) => {
try
{
const
response
=
await
userStore
.
setUserWechatLoginAsync
(
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'
)
...
...
@@ -317,6 +318,7 @@ const handleSignInSuccess = async (googleUser:any) => {
// 获取授权码
const
response
=
await
userStore
.
setUserGoogleLoginAsync
(
loginMsg
.
tenantId
?.
toString
()
||
''
,
googleUser
.
credential
,
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'
)
...
...
@@ -363,6 +365,7 @@ const handleLogin = async () => {
)
loading
.
value
=
false
if
(
result
.
status
==
'SUCCESS'
)
{
userStore
.
setLoginType
(
loginMsg
.
reType
||
0
)
Message
.
success
(
t
(
'login.loginSuccess'
))
const
forward
=
localStorage
.
getItem
(
'forward'
)
localStorage
.
removeItem
(
'forward'
)
...
...
@@ -391,6 +394,7 @@ onMounted(async () => {
const
queryParams
=
query
()
const
code
=
queryParams
.
code
if
(
code
)
{
loginMsg
.
reType
=
2
useWechatLogin
(
code
)
}
try
{
...
...
@@ -400,7 +404,9 @@ onMounted(async () => {
await
new
Promise
(
resolve
=>
setTimeout
(
resolve
));
renderGoogleButton
()
setTimeout
(()
=>
{
loading
.
value
=
false
},
500
)
}
catch
(
error
)
{
console
.
error
(
'SDK 初始化失败:'
,
error
);
}
...
...
src/views/auth/forgePassword.vue
View file @
15d9ad15
<
template
>
<
div
class=
"h-screen overflow-hidden"
>
<
a-spin
:loading=
"loading"
class=
"h-screen overflow-hidden"
>
<div
ref=
"loginPage"
class=
"light-login-bg pl-[85px] pr-[98px] pt-[33px] h-full !overflow-y-auto light-login-bgActive"
>
<loginHeader
/>
...
...
@@ -55,7 +55,7 @@
<
a
-
input
-
password
class
=
"formData-input"
v
-
model
=
"formData.password"
:
placeholder
=
"t('login.passwordRequiredReset')"
:
maxLength
=
"
8
"
:
maxLength
=
"
100
"
:
defaultVisibility
=
"true"
:
invisible
-
button
=
"false"
size
=
"large"
>
...
...
@@ -66,7 +66,7 @@
v
-
model
=
"formData.newPassword"
size
=
"large"
:
placeholder
=
"t('login.confirmPasswordRequired')"
:
maxLength
=
"
8
"
:
maxLength
=
"
100
"
:
defaultVisibility
=
"true"
:
invisible
-
button
=
"false"
>
...
...
@@ -109,10 +109,10 @@
<
/div
>
<
/div> --
>
<
/div
>
<
/
div
>
<
/
a-spin
>
<
/template
>
<
script
setup
lang
=
"ts"
>
import
{
reactive
,
ref
,
watch
,
computed
}
from
"vue"
;
import
{
reactive
,
ref
,
watch
,
computed
,
onMounted
}
from
"vue"
;
import
{
useI18n
}
from
"vue-i18n"
;
import
{
useSystemConfigStore
}
from
'@/stores/index'
import
loginHeader
from
"./components/header.vue"
;
...
...
@@ -177,7 +177,7 @@ const rules = computed(() => ({
}
))
const
loginPage
=
ref
(
null
as
unknown
as
HTMLElement
)
const
loading
=
ref
(
fals
e
)
const
loading
=
ref
(
tru
e
)
const
currentStep
=
ref
(
1
)
// 判断用户是否已登录
...
...
@@ -449,6 +449,11 @@ const init = async () => {
init
()
onMounted
(()
=>
{
setTimeout
(()
=>
{
loading
.
value
=
false
}
,
500
)
}
)
<
/script
>
<
style
scoped
lang
=
"scss"
>
.
light
-
login
-
bg
{
...
...
src/views/auth/register.vue
View file @
15d9ad15
<
template
>
<
div
class=
"h-screen overflow-hidden"
>
<
a-spin
:loading=
"loading"
class=
"h-screen overflow-hidden"
>
<div
ref=
"loginPage"
class=
"light-login-bg pl-[85px] pr-[98px] pt-[33px] h-full !overflow-y-auto"
:class=
"[currentStep
<3
?'
light-login-bg
'
:
'
light-login-bgActive
']"
>
...
...
@@ -63,7 +63,7 @@
v
-
model
=
"formData.password"
size
=
"large"
:
placeholder
=
"t('login.setPasswordRequired')"
:
maxLength
=
"
8
"
:
maxLength
=
"
100
"
:
defaultVisibility
=
"true"
:
invisible
-
button
=
"false"
>
...
...
@@ -77,7 +77,7 @@
v
-
model
=
"formData.confirmPassword"
size
=
"large"
:
placeholder
=
"t('login.confirmPasswordRequired')"
:
maxLength
=
"
8
"
:
maxLength
=
"
100
"
:
defaultVisibility
=
"true"
:
invisible
-
button
=
"false"
>
...
...
@@ -221,10 +221,10 @@
<
/div
>
<
registerSuccess
v
-
if
=
"currentStep==3"
/>
<
/div
>
<
/
div
>
<
/
a-spin
>
<
/template
>
<
script
setup
lang
=
"ts"
>
import
{
reactive
,
ref
,
watch
,
computed
,
provide
}
from
"vue"
;
import
{
reactive
,
ref
,
watch
,
computed
,
provide
,
onMounted
}
from
"vue"
;
import
{
useI18n
}
from
"vue-i18n"
;
import
{
useRouter
}
from
'vue-router'
import
{
Message
}
from
'@arco-design/web-vue'
...
...
@@ -331,7 +331,7 @@ const rules = computed(() => ({
const
loginPage
=
ref
(
null
)
const
currentStep
=
ref
(
1
)
const
loading
=
ref
(
fals
e
)
const
loading
=
ref
(
tru
e
)
const
isFromOta
=
ref
(
false
)
// 是否从 OTA 授权进入
provide
(
'currentStep'
,
currentStep
.
value
)
...
...
@@ -673,6 +673,11 @@ init()
getSimples
()
onMounted
(()
=>
{
setTimeout
(()
=>
{
loading
.
value
=
false
}
,
500
)
}
)
<
/script
>
<
style
>
.
light
-
login
-
bg
{
...
...
src/views/personalCenter/accountCenter.vue
View file @
15d9ad15
This diff is collapsed.
Click to expand it.
src/views/personalCenter/components/LeftView.vue
View file @
15d9ad15
<
template
>
<div
class=
"flex flex flex-col w-[198px]"
>
<div
class=
"h-full bg-[#F9F9F7] rounded-[14px]"
>
<div
class=
"mt-[37px] flex justify-center items-center"
>
<a-avatar
class=
"LeftViewImg cursor-pointer flex-shrink-0 !w-[80px] !h-[80px]"
>
<img
class=
"w-full h-full cursor-pointer"
alt=
"avatar"
:src=
"userInfo.photo || systemConfigStore.config?.logo || 'https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/3ee5f13fb09879ecb5185e440cef6eb9.png~tplv-uwbnlip3yd-webp.webp'"
/>
</a-avatar>
</div>
<div
class=
"mt-[13px] text-lg font-medium text-center truncate"
>
{{
userInfo
.
name
}}
</div>
<div
class=
"flex justify-center items-center mt-[10px] cursor-pointer"
>
<span
v-if=
"!userInfo.IsComplete"
class=
"LeftViewTisp w-[6px] h-[6px] rounded-full"
></span>
<span
class=
"LeftViewData ml-[5px] text-sm font-medium text-[#666]"
>
{{
t
(
'personal.completeProfile'
)
}}
>>
</span>
</div>
<template
v-if=
"userInfo"
>
<div
class=
"mt-[37px] flex justify-center items-center"
>
<a-avatar
class=
"LeftViewImg cursor-pointer flex-shrink-0 !w-[80px] !h-[80px]"
>
<img
class=
"w-full h-full cursor-pointer"
alt=
"avatar"
:src=
"userInfo.photo || systemConfigStore.config?.logo || 'https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/3ee5f13fb09879ecb5185e440cef6eb9.png~tplv-uwbnlip3yd-webp.webp'"
/>
</a-avatar>
</div>
<div
class=
"mt-[13px] text-lg font-medium text-center truncate"
>
{{
userInfo
.
name
}}
</div>
<div
class=
"flex justify-center items-center mt-[10px] cursor-pointer"
>
<span
v-if=
"!userInfo.IsComplete"
class=
"LeftViewTisp w-[6px] h-[6px] rounded-full"
></span>
<span
class=
"LeftViewData ml-[5px] text-sm font-medium text-[#666]"
>
{{
t
(
'personal.completeProfile'
)
}}
>>
</span>
</div>
<a-divider
class=
"border-[#ECECE7]"
/>
<div
class=
"flex items-center cursor-pointer py-[7px] rounded-[8px] pl-[27px] mb-[5px]"
>
<img
src=
"../../../assets/images/personal/doc1.png"
alt=
"avatar"
class=
"w-[22px] h-[22px] cursor-pointer"
/>
<span
class=
"ml-[13px] text-base font-medium SourceHanSansBOLD"
>
{{
t
(
'personal.orderCenter'
)
}}
</span>
</div>
<div
v-for=
"(item,index) in menuList"
class=
"px-[22px] relative"
>
<div
class=
"LeftView-menu flex items-center cursor-pointer py-[7px] rounded-[8px] SourceHanSansCN"
:class=
"[activeMenu==item.key?'active':'']"
v-if=
"item.key=='myOrder'"
@
click=
"goPage(item.path)"
>
<div
class=
"w-[22px] h-[22px] cursor-pointer"
></div>
<span
class=
"ml-[18px] text-sm font-light"
>
{{
item
.
name
}}
</span>
</div>
</div>
<a-divider
class=
"border-[#ECECE7]"
/>
<div
class=
"flex items-center cursor-pointer py-[7px] rounded-[8px] pl-[27px] mb-[5px]"
>
<img
src=
"../../../assets/images/personal/doc1.png"
alt=
"avatar"
class=
"w-[22px] h-[22px] cursor-pointer"
/>
<span
class=
"ml-[13px] text-base font-medium SourceHanSansBOLD"
>
{{
t
(
'personal.orderCenter'
)
}}
</span>
</div>
<div
v-for=
"(item,index) in menuList"
class=
"px-[22px] relative"
>
<div
class=
"LeftView-menu flex items-center cursor-pointer py-[7px] rounded-[8px] SourceHanSansCN"
:class=
"[activeMenu==item.key?'active':'']"
v-if=
"item.key=='myOrder'"
@
click=
"goPage(item.path)"
>
<div
class=
"w-[22px] h-[22px] cursor-pointer"
></div>
<span
class=
"ml-[18px] text-sm font-light"
>
{{
item
.
name
}}
</span>
</div>
</div>
</
template
>
<a-divider
class=
"border-[#ECECE7]"
/>
<div
class=
"flex items-center cursor-pointer py-[7px] rounded-[8px] pl-[27px] mb-[5px]"
>
<img
src=
"../../../assets/images/personal/user1.png"
alt=
"avatar"
class=
"w-[22px] h-[22px] cursor-pointer"
/>
<span
class=
"ml-[13px] text-base font-medium SourceHanSansBOLD"
>
{{
t
(
'personal.profile'
)
}}
</span>
</div>
<div
v-for=
"(item,index) in menuList"
class=
"px-[22px] relative"
>
<div
class=
"LeftView-menu flex items-center cursor-pointer py-[7px] rounded-[8px] SourceHanSansCN"
:class=
"[activeMenu==item.key?'active':'']"
v-if=
"item.key!='myOrder'&&item.key!='distributionCenter'"
@
click=
"goPage(item.path)"
>
<div
class=
"w-[22px] h-[22px] cursor-pointer"
></div>
<span
class=
"ml-[18px] text-sm font-light"
>
{{
item
.
name
}}
<a-divider
class=
"border-[#ECECE7]"
/>
<div
class=
"flex items-center cursor-pointer py-[7px] rounded-[8px] pl-[27px] mb-[5px]"
>
<img
src=
"../../../assets/images/personal/user1.png"
alt=
"avatar"
class=
"w-[22px] h-[22px] cursor-pointer"
/>
<span
class=
"ml-[13px] text-base font-medium SourceHanSansBOLD"
>
{{ t('personal.profile') }}
</span>
<a-badge
class=
"ml-[8px]"
v-if=
"item.count"
:count=
"item.count"
:dotStyle=
"
{ background: '#FF9707', minWidth: '16px', width: '16px', minHeight: '16px', height: '16px',fontSize:'12px',borderRadius:'16px',lineHeight:'15px' }"
/>
</div>
</div>
<a-divider
class=
"border-[#ECECE7]"
/>
<div
class=
"flex items-center cursor-pointer py-[7px] rounded-[8px] pl-[27px] mb-[5px]"
>
<img
src=
"../../../assets/images/personal/medal1.png"
alt=
"avatar"
class=
"w-[22px] h-[22px] cursor-pointer"
/>
<span
class=
"ml-[13px] text-base font-medium SourceHanSansBOLD"
>
{{
t
(
'personal.promotionManagement'
)
}}
</span>
</div>
<div
v-for=
"(item,index) in menuList"
class=
"px-[22px] relative"
>
<div
class=
"LeftView-menu flex items-center cursor-pointer py-[7px] rounded-[8px] SourceHanSansCN"
:class=
"[activeMenu==item.key?'active':'']"
v-if=
"item.key=='distributionCenter'"
@
click=
"goPage(item.path)"
>
<div
class=
"w-[22px] h-[22px] cursor-pointer"
></div>
<span
class=
"ml-[18px] text-sm font-light"
>
{{
item
.
name
}}
<div
v-for=
"(item,index) in menuList"
class=
"px-[22px] relative"
>
<div
class=
"LeftView-menu flex items-center cursor-pointer py-[7px] rounded-[8px] SourceHanSansCN"
:class=
"[activeMenu==item.key?'active':'']"
v-if=
"item.key!='myOrder'&&item.key!='distributionCenter'"
@
click=
"goPage(item.path)"
>
<div
class=
"w-[22px] h-[22px] cursor-pointer"
></div>
<span
class=
"ml-[18px] text-sm font-light"
>
{{ item.name }}
</span>
<a-badge
class=
"ml-[8px]"
v-if=
"item.count"
:count=
"item.count"
:dotStyle=
"{ background: '#FF9707', minWidth: '16px', width: '16px', minHeight: '16px', height: '16px',fontSize:'12px',borderRadius:'16px',lineHeight:'15px' }"
/>
</div>
</div>
<a-divider
class=
"border-[#ECECE7]"
/>
<div
class=
"flex items-center cursor-pointer py-[7px] rounded-[8px] pl-[27px] mb-[5px]"
>
<img
src=
"../../../assets/images/personal/medal1.png"
alt=
"avatar"
class=
"w-[22px] h-[22px] cursor-pointer"
/>
<span
class=
"ml-[13px] text-base font-medium SourceHanSansBOLD"
>
{{ t('personal.promotionManagement') }}
</span>
</div>
</div>
<div
v-for=
"(item,index) in menuList"
class=
"px-[22px] relative"
>
<div
class=
"LeftView-menu flex items-center cursor-pointer py-[7px] rounded-[8px] SourceHanSansCN"
:class=
"[activeMenu==item.key?'active':'']"
v-if=
"item.key=='distributionCenter'"
@
click=
"goPage(item.path)"
>
<div
class=
"w-[22px] h-[22px] cursor-pointer"
></div>
<span
class=
"ml-[18px] text-sm font-light"
>
{{ item.name }}
</span>
</div>
</div>
</div>
</div>
</template>
...
...
@@ -118,24 +120,24 @@ const userStore = useUserStore()
const
systemConfigStore
=
useSystemConfigStore
()
const
tenantId
=
computed
(()
=>
systemConfigStore
.
tenantId
)
const
userData
=
ref
({}
as
any
)
userData
.
value
=
inject
(
'userData'
)
const
userInfo
=
computed
(()
=>
userData
.
value
.
userInfo
)
const
userInfo
=
ref
(
null
as
any
)
const
activeMenu
=
ref
(
props
.
activeMenu
)
watch
(()
=>
props
.
activeMenu
,
(
newVal
,
oldVal
)
=>
{
activeMenu
.
value
=
newVal
})
watch
(()
=>
userStore
.
personalInfor
,
(
newVal
,
oldVal
)
=>
{
userInfo
.
value
=
newVal
})
const
goPage
=
(
path
:
string
)
=>
{
router
.
push
(
path
)
}
const
getPersonalInfor
=
async
()
=>
{
const
response
=
await
UserService
.
memberCenterAsync
(
tenantId
.
value
)
userData
.
value
.
userInfo
=
response
userStore
.
setPersonalInfo
(
response
)
userStore
.
setPersonalInfor
(
response
)
}
getPersonalInfor
()
</
script
>
...
...
src/views/personalCenter/components/myOrder/editEmail.vue
View file @
15d9ad15
...
...
@@ -40,7 +40,7 @@
v
-
model
=
"formData.password"
size
=
"large"
:
placeholder
=
"t('login.setPasswordRequired')"
:
maxLength
=
"
8
"
:
maxLength
=
"
100
"
:
defaultVisibility
=
"true"
:
invisible
-
button
=
"false"
>
...
...
@@ -54,7 +54,7 @@
v
-
model
=
"formData.newPassword"
size
=
"large"
:
placeholder
=
"t('login.confirmPasswordRequired')"
:
maxLength
=
"
8
"
:
maxLength
=
"
100
"
:
defaultVisibility
=
"true"
:
invisible
-
button
=
"false"
>
...
...
@@ -64,7 +64,7 @@
<
div
class
=
"mt-[27px] w-full flex flex-col items-center items-center-button mb-[20px]"
>
<
div
class
=
"w-full "
:
class
=
"[(formData.email&&formData.verificationCode&&formData.verificationCode.length==6)
||(data.email&&formData.password&&formData.password.length
=
=8
||(data.email&&formData.password&&formData.password.length
>
=8
&&formData.password==formData.newPassword)?'isClick':'']"
>
<
a
-
button
type
=
"primary"
...
...
@@ -103,7 +103,7 @@ const props = defineProps({
}
)
const
emit
=
defineEmits
<
{
(
e
:
'save-success'
,
email
:
string
):
void
(
e
:
'save-success'
):
void
}
>
()
const
{
t
}
=
useI18n
();
...
...
@@ -410,7 +410,7 @@ const handleSubmit = async () => {
const
response
=
await
userStore
.
setEmailAsync
(
registerData
)
if
(
response
.
status
==
'SUCCESS'
)
{
emit
(
'save-success'
,
formData
.
email
)
emit
(
'save-success'
)
}
}
catch
(
error
:
any
)
{
console
.
error
(
'提交失败:'
,
error
)
...
...
src/views/personalCenter/index.vue
View file @
15d9ad15
...
...
@@ -13,7 +13,7 @@
</div>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
ref
,
computed
,
reactive
,
provide
}
from
'vue'
import
{
ref
,
computed
,
reactive
}
from
'vue'
import
{
useRoute
}
from
'vue-router'
import
{
useI18n
}
from
'vue-i18n'
import
LeftView
from
'./components/LeftView.vue'
...
...
@@ -69,10 +69,6 @@ const menuList = ref([
key
:
'distributionCenter'
,
},
])
const
userData
=
reactive
({
userInfo
:
{},
})
provide
(
'userData'
,
userData
)
</
script
>
<
style
scoped
>
...
...
src/views/personalCenter/myOrder.vue
View file @
15d9ad15
<
template
>
<
div
class=
"w-[977px] h-full flex flex-col flex-shrink-0"
>
<
a-spin
:loading=
"loading"
class=
"w-[977px] h-full flex flex-col flex-shrink-0"
>
<div
class=
"myOrderData rounded-[14px] flex justify-between pt-[22px] pb-[19px] pl-[16px] relative"
>
<div
class=
"flex items-center p-[20px]"
>
<div
class=
"bg-[#F3F3F2] rounded-full w-[52px] h-[52px] flex justify-center items-center mr-[16px]"
>
...
...
@@ -10,7 +10,7 @@
{{
t
(
'personal.bindingEmail'
)
}}
</div>
<div
class=
"mt-[10px] flex items-center"
>
<span
class=
"text-base font-normal"
>
{{
userInfo
?.
email
||
t
(
'personal.unbound'
)
}}
</span>
<span
class=
"text-base font-normal"
>
{{
userInfo
r
?.
email
||
t
(
'personal.unbound'
)
}}
</span>
<img
class=
"w-[15px] h-[15px] ml-[10px] cursor-pointer"
src=
"../../assets/images/personal/pen.png"
alt=
""
@
click=
"editEmailClick"
/>
...
...
@@ -50,7 +50,7 @@
</div>
<div
class=
"flex justify-between items-center text-base relative"
>
<div
class=
"flex"
>
<div
v-for=
"(item,index) in order
List
"
<div
v-for=
"(item,index) in order
Types
"
class=
"myOrder-status px-[13px] py-[22px] cursor-pointer relative"
:class=
"[currentStatus==item.value?'active font-medium':'font-light']"
@
click=
"changeStatus(item.value)"
>
{{
item
.
label
}}
...
...
@@ -87,7 +87,7 @@
</div>
<a-divider
class=
"!m-[0]"
/>
<div
class=
"flex-1 flex flex-col flex-shrink-0"
:class=
"[!(dataList.length==0&&!loding)?'items-center justify-center':'']"
>
:class=
"[!(dataList.length==0&&!lo
a
ding)?'items-center justify-center':'']"
>
<a-scrollbar
class=
"max-h-[615px] overflow-auto"
@
scroll=
"handleDivScroll"
ref=
"scrollContainer"
>
...
...
@@ -127,26 +127,26 @@
</div>
</div>
</div>
<div
v-else-if=
"dataList.length==0&&!loding"
class=
"flex flex-col items-center justify-center"
>
<div
v-else-if=
"dataList.length==0&&!lo
a
ding"
class=
"flex flex-col items-center justify-center"
>
<img
class=
"w-[250px] h-[213px]"
src=
"../../assets/images/personal/wsj.png"
alt=
""
/>
<span
class=
"text-base SourceHanSansCN mt-[15px]"
>
{{ t('personal.noOrder') }}
</span>
</div>
</a-scrollbar>
</div>
</
div
>
</
a-spin
>
<Modal
class=
"ModalRef"
ref=
"ModalRef"
:modal-config=
"modalConfig"
:modal-mask=
"true"
>
<
template
#
modal=
"{ visible }"
>
<editEmail
v-if=
"visible&&showType==1"
:data=
"userInfo"
<editEmail
v-if=
"visible&&showType==1"
:data=
"userInfo
r
"
@
save-success=
"handleSaveSuccess"
/>
</
template
>
</Modal>
</template>
<
script
setup
lang=
"ts"
>
import
{
ref
,
inject
,
computed
,
watch
}
from
'vue'
import
{
ref
,
inject
,
computed
,
watch
,
onMounted
}
from
'vue'
import
{
useI18n
}
from
'vue-i18n'
import
{
useUserStore
}
from
'@/stores/user'
import
{
useSystemConfigStore
}
from
'@/stores/index'
...
...
@@ -162,7 +162,7 @@ const systemConfigStore = useSystemConfigStore()
const
userData
=
ref
({}
as
any
)
userData
.
value
=
inject
(
'userData'
)
const
userInfo
=
ref
(
userStore
.
personalInfo
)
const
userInfo
r
=
ref
(
null
as
any
)
const
showType
=
ref
(
null
as
number
|
null
)
const
modalConfig
=
ref
({
...
...
@@ -183,6 +183,7 @@ const modalConfig = ref({
})
const
ModalRef
=
ref
<
any
>
(
null
)
const
orderTypes
=
ref
<
any
>
([])
const
orderList
=
ref
<
any
>
([])
const
currentStatus
=
ref
(
0
)
const
productTypeList
=
ref
<
any
>
([])
...
...
@@ -197,23 +198,23 @@ productTypeList.value.push({
})
// console.log(productTypeList.value,'--------')
order
List
.
value
.
push
({
order
Types
.
value
.
push
({
value
:
0
,
label
:
t
(
'personal.orderStatus.ALL'
),
})
order
List
.
value
.
push
({
order
Types
.
value
.
push
({
value
:
OrderStatusEnum
.
UN_PAY
.
value
,
label
:
OrderStatusEnum
.
UN_PAY
.
desc
,
})
order
List
.
value
.
push
({
order
Types
.
value
.
push
({
value
:
OrderStatusEnum
.
PAYED
.
value
,
label
:
OrderStatusEnum
.
PAYED
.
desc
,
})
order
List
.
value
.
push
({
order
Types
.
value
.
push
({
value
:
OrderStatusEnum
.
FINISH
.
value
,
label
:
OrderStatusEnum
.
FINISH
.
desc
,
})
order
List
.
value
.
push
({
order
Types
.
value
.
push
({
value
:
OrderStatusEnum
.
CANCEL
.
value
,
label
:
OrderStatusEnum
.
CANCEL
.
desc
,
})
...
...
@@ -224,27 +225,26 @@ const queryParams = ref<any>({
orderStatus
:
currentStatus
.
value
,
})
const
dataList
=
ref
<
any
>
([])
const
lo
ding
=
ref
(
fals
e
)
const
noMoreData
=
ref
(
fals
e
)
const
lo
ading
=
ref
(
tru
e
)
const
noMoreData
=
ref
(
tru
e
)
const
scrollContainer
=
ref
<
any
>
(
null
)
const
scrollThreshold
=
0
// 阈值,距离底部多少距离时触发加载
watch
(()
=>
userStore
.
personalInfo
,
(
newVal
,
oldVal
)
=>
{
watch
(()
=>
userStore
.
personalInfo
r
,
(
newVal
,
oldVal
)
=>
{
if
(
newVal
!=
oldVal
){
userInfo
.
value
=
newVal
userInfo
r
.
value
=
newVal
}
})
const
handleSaveSuccess
=
(
email
:
string
)
=>
{
const
handleSaveSuccess
=
()
=>
{
ModalRef
.
value
.
handleCancel
()
userStore
.
setEmail
(
email
)
}
// 编辑邮箱 绑定邮箱
const
editEmailClick
=
async
()
=>
{
showType
.
value
=
1
modalConfig
.
value
.
title
=
userInfo
.
value
.
email
?
t
(
'personal.editEmail'
):
t
(
'personal.binEmail'
)
if
(
ModalRef
.
value
)
await
ModalRef
.
value
.
openModal
(
userInfo
.
value
)
modalConfig
.
value
.
title
=
userInfo
r
.
value
.
email
?
t
(
'personal.editEmail'
):
t
(
'personal.binEmail'
)
if
(
ModalRef
.
value
)
await
ModalRef
.
value
.
openModal
(
userInfo
r
.
value
)
}
const
changeStatus
=
(
key
:
number
)
=>
{
...
...
@@ -256,7 +256,7 @@ const loadData = async () => {
// 处理 div 滚动事件(核心修改)
const
handleDivScroll
=
(
e
:
any
)
=>
{
if
(
loding
.
value
||
noMoreData
.
value
)
return
;
if
(
lo
a
ding
.
value
||
noMoreData
.
value
)
return
;
const
container
=
e
.
target
;
if
(
!
container
)
return
;
// 计算滚动位置(兼容不同浏览器)
...
...
@@ -271,6 +271,11 @@ const handleDivScroll = (e: any) => {
}
}
onMounted
(()
=>
{
setTimeout
(()
=>
{
loading
.
value
=
false
})
})
</
script
>
<
style
scoped
lang=
"scss"
>
.myOrderData
{
...
...
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