Commit 15d9ad15 authored by youjie's avatar youjie

账户中心

parent 2e541790
......@@ -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';
......
......@@ -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: '拒绝访问,您没有权限执行此操作',
......
......@@ -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
......@@ -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,// 个人信息
personalInfor: {} 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.personalInfor.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]
......
<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(false)
const loading = ref(true)
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: '',//yj123456
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);
}
......
<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(false)
const loading = ref(true)
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 {
......
<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(false)
const loading = ref(true)
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 {
......
This diff is collapsed.
<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>
......
......@@ -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)
......
......@@ -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>
......
<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">{{ userInfor?.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 orderList"
<div v-for="(item,index) in orderTypes"
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&&!loading)?'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&&!loading" 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="userInfor"
@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 userInfor = 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,'--------')
orderList.value.push({
orderTypes.value.push({
value: 0,
label: t('personal.orderStatus.ALL'),
})
orderList.value.push({
orderTypes.value.push({
value: OrderStatusEnum.UN_PAY.value,
label: OrderStatusEnum.UN_PAY.desc,
})
orderList.value.push({
orderTypes.value.push({
value: OrderStatusEnum.PAYED.value,
label: OrderStatusEnum.PAYED.desc,
})
orderList.value.push({
orderTypes.value.push({
value: OrderStatusEnum.FINISH.value,
label: OrderStatusEnum.FINISH.desc,
})
orderList.value.push({
orderTypes.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 loding = ref(false)
const noMoreData = ref(false)
const loading = ref(true)
const noMoreData = ref(true)
const scrollContainer = ref<any>(null)
const scrollThreshold = 0 // 阈值,距离底部多少距离时触发加载
watch(() => userStore.personalInfo, (newVal, oldVal) => {
watch(() => userStore.personalInfor, (newVal, oldVal) => {
if(newVal!=oldVal){
userInfo.value = newVal
userInfor.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 = userInfor.value.email?t('personal.editEmail'):t('personal.binEmail')
if(ModalRef.value) await ModalRef.value.openModal(userInfor.value)
}
const changeStatus = (key: number) => {
......@@ -256,7 +256,7 @@ const loadData = async () => {
// 处理 div 滚动事件(核心修改)
const handleDivScroll = (e: any) => {
if (loding.value || noMoreData.value) return;
if (loading.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{
......
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