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
ed9626ca
Commit
ed9626ca
authored
Nov 19, 2025
by
youjie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
邮箱注册
parent
70966e97
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
2027 additions
and
200 deletions
+2027
-200
.env.development
.env.development
+1
-1
OtaRequest.ts
src/api/OtaRequest.ts
+0
-2
welcome-register.png
src/assets/images/welcome-register.png
+0
-0
en.ts
src/i18n/locales/en.ts
+2
-0
vi.ts
src/i18n/locales/vi.ts
+2
-0
zh-CN.ts
src/i18n/locales/zh-CN.ts
+25
-0
zh-TW.ts
src/i18n/locales/zh-TW.ts
+2
-0
index.ts
src/router/index.ts
+2
-2
CountryService.ts
src/services/CountryService.ts
+74
-0
OtaAuthService.ts
src/services/OtaAuthService.ts
+250
-0
UserService.ts
src/services/UserService.ts
+71
-44
user.ts
src/stores/user.ts
+82
-1
country.ts
src/types/country.ts
+78
-0
systemConfig.ts
src/types/systemConfig.ts
+9
-0
Login.vue
src/views/auth/Login.vue
+317
-11
header.vue
src/views/auth/components/header.vue
+4
-6
registerForm.vue
src/views/auth/components/registerForm.vue
+363
-92
register.vue
src/views/auth/register.vue
+745
-41
No files found.
.env.development
View file @
ed9626ca
# 开发环境配置 - 使用Mock数据
# 开发环境配置 - 使用Mock数据
VITE_OTA_API_BASE_URL=http://
localhost:19002
/api/app/
VITE_OTA_API_BASE_URL=http://
192.168.5.39:8081
/api/app/
VITE_ERP_API_BASE_URL=http://192.168.5.214:8700/
VITE_ERP_API_BASE_URL=http://192.168.5.214:8700/
VITE_FILEUPLOAD_API_BASE_URL=http://192.168.5.214:8120/
VITE_FILEUPLOAD_API_BASE_URL=http://192.168.5.214:8120/
VITE_FILEPREVIEW_API_BASE_URL=http://192.168.5.214:8130/
VITE_FILEPREVIEW_API_BASE_URL=http://192.168.5.214:8130/
...
...
src/api/OtaRequest.ts
View file @
ed9626ca
...
@@ -37,8 +37,6 @@ service.interceptors.request.use(
...
@@ -37,8 +37,6 @@ service.interceptors.request.use(
config
.
headers
[
'__tenant'
]
=
systemConfigStore
.
tenantId
;
config
.
headers
[
'__tenant'
]
=
systemConfigStore
.
tenantId
;
}
}
console
.
log
(
systemConfigStore
.
erpAdminUserId
);
// 优先检查临时令牌(OTA 授权场景)
// 优先检查临时令牌(OTA 授权场景)
const
tempToken
=
sessionStorage
.
getItem
(
'tempToken'
);
const
tempToken
=
sessionStorage
.
getItem
(
'tempToken'
);
if
(
tempToken
)
{
if
(
tempToken
)
{
...
...
src/assets/images/welcome-register.png
0 → 100644
View file @
ed9626ca
14.4 KB
src/i18n/locales/en.ts
View file @
ed9626ca
...
@@ -2,6 +2,8 @@ import { enCountries } from './countries'
...
@@ -2,6 +2,8 @@ import { enCountries } from './countries'
import
customFieldsEn
from
'./fields/custom-fields-en.json'
import
customFieldsEn
from
'./fields/custom-fields-en.json'
export
default
{
export
default
{
// 国家名称(基于ISO2代码)
countries
:
enCountries
,
login
:
{
login
:
{
// Page titles
// Page titles
title
:
'Tten Joy'
,
title
:
'Tten Joy'
,
...
...
src/i18n/locales/vi.ts
View file @
ed9626ca
...
@@ -2,6 +2,8 @@ import { viCountries } from './countries'
...
@@ -2,6 +2,8 @@ import { viCountries } from './countries'
import
customFieldsVi
from
'./fields/custom-fields-vi.json'
import
customFieldsVi
from
'./fields/custom-fields-vi.json'
export
default
{
export
default
{
// 国家名称(基于ISO2代码)
countries
:
viCountries
,
login
:
{
login
:
{
// Tiêu đề trang
// Tiêu đề trang
title
:
'Tten Joy'
,
title
:
'Tten Joy'
,
...
...
src/i18n/locales/zh-CN.ts
View file @
ed9626ca
...
@@ -2,6 +2,8 @@ import { zhCNCountries } from './countries'
...
@@ -2,6 +2,8 @@ import { zhCNCountries } from './countries'
import
customFieldsZhCN
from
'./fields/custom-fields-zh-CN.json'
import
customFieldsZhCN
from
'./fields/custom-fields-zh-CN.json'
export
default
{
export
default
{
// 国家名称(基于ISO2代码)
countries
:
zhCNCountries
,
login
:
{
login
:
{
// 页面标题
// 页面标题
title
:
'Tten Joy'
,
title
:
'Tten Joy'
,
...
@@ -65,6 +67,29 @@ export default {
...
@@ -65,6 +67,29 @@ export default {
loginError
:
'登录失败'
,
loginError
:
'登录失败'
,
emailLogin
:
'邮箱'
,
emailLogin
:
'邮箱'
,
emailPasswordPlaceholder
:
'请输入邮箱密码'
,
emailPasswordPlaceholder
:
'请输入邮箱密码'
,
emailFormat
:
'请输入正确的邮箱地址'
,
repeatedpassword
:
'重复密码'
,
passwordFormat
:
'密码必须包含字母和数字,且长度为8位'
,
passwordMismatch
:
'两次输入的密码不一致'
,
emailRequired
:
'请输入邮箱地址'
,
emailInvalid
:
'请输入有效的邮箱地址'
,
resendCode
:
'{seconds}秒后重新发送'
,
resend
:
'重新发送'
,
pleaseComplete
:
'请完成必填项'
,
pleaseVerifyEmail
:
'请先验证邮箱'
,
pleaseVerifyCode
:
'请先完成邮箱验证'
,
pleaseAgreement
:
'请勾选隐私政策'
,
codeVerified
:
'验证成功'
,
verifyCodeFailed
:
'验证失败'
,
noCodeReceived
:
'没有收到验证码?'
,
codeInvalid
:
'验证码错误或已过期'
,
codeVerifyFailed
:
'验证码验证失败'
,
registerFailed
:
'注册失败'
,
lineId
:
'请输入LINE ID'
,
lineIdOrWechat
:
'LINE ID和微信账号需二填一'
,
phoneCode
:
'区号'
,
googleLoginFailed
:
'谷歌登录失败'
,
isReceivePush
:
'「我同意接收优惠与电子报」'
,
},
},
common
:
{
common
:
{
language
:
'语言'
,
language
:
'语言'
,
...
...
src/i18n/locales/zh-TW.ts
View file @
ed9626ca
...
@@ -2,6 +2,8 @@ import { zhTWCountries } from './countries'
...
@@ -2,6 +2,8 @@ import { zhTWCountries } from './countries'
import
customFieldsZhTW
from
'./fields/custom-fields-zh-TW.json'
import
customFieldsZhTW
from
'./fields/custom-fields-zh-TW.json'
export
default
{
export
default
{
// 国家名称(基于ISO2代码)
countries
:
zhTWCountries
,
login
:
{
login
:
{
// 頁面標題
// 頁面標題
title
:
'Tten Joy'
,
title
:
'Tten Joy'
,
...
...
src/router/index.ts
View file @
ed9626ca
...
@@ -15,13 +15,13 @@ const router = createRouter({
...
@@ -15,13 +15,13 @@ const router = createRouter({
path
:
"/register"
,
path
:
"/register"
,
name
:
"register"
,
name
:
"register"
,
component
:
()
=>
import
(
"../views/auth/register.vue"
),
component
:
()
=>
import
(
"../views/auth/register.vue"
),
meta
:
{
title
:
"
register.registerButton
"
},
meta
:
{
title
:
"
login.register
"
},
},
},
{
{
path
:
"/forgePassword"
,
path
:
"/forgePassword"
,
name
:
"forgePassword"
,
name
:
"forgePassword"
,
component
:
()
=>
import
(
"../views/auth/forgePassword.vue"
),
component
:
()
=>
import
(
"../views/auth/forgePassword.vue"
),
meta
:
{
title
:
"
forgePassword.forgePasswordButton
"
},
meta
:
{
title
:
"
login.forgetPassword
"
},
},
},
{
{
path
:
"/products/:type/:city"
,
path
:
"/products/:type/:city"
,
...
...
src/services/CountryService.ts
0 → 100644
View file @
ed9626ca
/**
* 国家相关 API 服务
*/
import
OtaRequest
from
'@/api/OtaRequest'
import
type
{
Country
,
CountrySimple
,
CountryPagedParams
,
PagedResult
}
from
'@/types/country'
/**
* 国家服务类
*/
class
CountryService
{
/**
* 获取国家分页列表
* @param params 分页参数
* @returns 分页结果
*/
static
async
getPagedList
(
params
:
CountryPagedParams
=
{}):
Promise
<
PagedResult
<
Country
>>
{
const
{
data
}
=
await
OtaRequest
.
get
(
'/sys-management/country/paged-list'
,
params
)
return
data
}
/**
* 获取所有国家列表(不分页)
* @param onlyEnabled 仅获取启用的国家
* @returns 国家列表
*/
static
async
getAll
(
onlyEnabled
:
boolean
=
true
):
Promise
<
Country
[]
>
{
const
{
data
}
=
await
OtaRequest
.
get
(
'/sys-management/country'
,
{
onlyEnabled
})
return
data
}
/**
* 获取简单国家列表(用于下拉框,使用缓存优化)
* @param onlyEnabled 仅获取启用的国家
* @returns 国家简单列表
*/
static
async
getSimpleList
(
onlyEnabled
:
boolean
=
true
):
Promise
<
CountrySimple
[]
>
{
const
data
=
await
OtaRequest
.
get
(
'/sys-management/country/simple-list'
,
{
onlyEnabled
})
return
data
as
CountrySimple
}
/**
* 搜索国家(支持按名称、编码搜索)
* @param keyword 搜索关键词
* @param onlyEnabled 仅搜索启用的国家
* @returns 国家列表
*/
static
async
search
(
keyword
:
string
,
onlyEnabled
:
boolean
=
true
):
Promise
<
Country
[]
>
{
const
{
data
}
=
await
OtaRequest
.
post
(
'/sys-management/country/search'
,
null
,
{
params
:
{
keyword
,
onlyEnabled
}
})
return
data
}
/**
* 获取指定数量的国家列表(用于下拉框)
* @param limit 最大数量,默认 500
* @param onlyEnabled 仅获取启用的国家
* @returns 国家列表
*/
static
async
getCountriesForSelect
(
limit
:
number
=
500
,
onlyEnabled
:
boolean
=
true
):
Promise
<
Country
[]
>
{
const
{
items
}
=
await
OtaRequest
.
get
(
'/sys-management/country/paged-list'
,
{
skipCount
:
0
,
maxResultCount
:
limit
,
sorting
:
'orderNum asc'
})
return
items
||
[]
}
}
export
default
CountryService
src/services/OtaAuthService.ts
0 → 100644
View file @
ed9626ca
import
OtaRequest
from
'@/api/OtaRequest'
/**
* OTA 授权服务 - 处理 OTA 会员转代理商的授权流程
*/
// ==================== 接口定义 ====================
/**
* OTA 用户信息
*/
export
interface
OtaUserInfo
{
/** 用户ID */
userId
:
string
/** 邮箱 */
email
:
string
/** 昵称 */
nick
:
string
/** 手机号 */
phone
:
string
}
/**
* 代理商状态信息
*/
export
interface
DistributorStatusInfo
{
/** 是否已经是代理商 */
isDistributor
:
boolean
/** 建议跳转的路由 */
suggestedRoute
:
string
/** 申请状态(如果已申请) */
status
?:
'PendingReview'
|
'Approved'
|
'Rejected'
/** 驳回原因(如果被驳回) */
rejectionReason
?:
string
/** 代理商ID(如果已是代理商) */
distributorId
?:
number
}
/**
* 验证 OTA 授权码的响应
*/
export
interface
ValidateOtaTokenResponse
{
/** 是否成功 */
success
:
boolean
/** 用户信息 */
userInfo
:
OtaUserInfo
/** 代理商状态 */
distributorStatus
:
DistributorStatusInfo
/** 临时访问令牌(15分钟有效) */
temporaryAccessToken
:
string
}
/**
* 从 OTA 提交代理商申请的请求参数
*/
export
interface
RegisterFromOtaDto
{
/** 分销商类型 */
type
:
'Enterprise'
|
'Individual'
/** 公司/品牌名称 */
companyOrBrandName
:
string
/** 统一编号(企业营业执照号/个人身份证号) */
unifiedNumber
?:
string
/** 联络人姓名 */
contactPerson
:
string
/** 联络电话/手机 */
contactPhone
:
string
/** 联络地址 */
contactAddress
?:
string
/** LINE ID */
lineId
?:
string
/** 微信ID */
wechatId
?:
string
/** 公司登记证明/身份影本/名片 */
documentFilePath
:
string
/** 开户支行名称 */
openBankName
:
string
/** 银行名称(所属银行全称) */
bankName
:
string
/** 账户持有人姓名 */
accountHolder
:
string
/** 银行卡号 */
cardNum
:
string
/** 税务登记号 */
dutyNo
?:
string
}
/**
* 提交申请的响应
*/
export
interface
RegisterFromOtaResponse
{
/** 是否成功 */
success
:
boolean
/** 消息 */
message
?:
string
/** 代理商ID */
distributorId
?:
number
/** 申请状态 */
status
:
'PendingReview'
|
'Approved'
|
'Rejected'
}
/**
* 发送验证码请求参数
*/
export
interface
SendVerificationCodeDto
{
/** 邮箱地址 */
email
:
string
/** 租户ID */
tenantId
?:
string
}
/**
* 发送验证码响应
*/
export
interface
SendVerificationCodeResponseDto
{
/** 是否成功 */
success
:
boolean
/** 消息 */
message
?:
string
/** 验证码过期时间(秒) */
expiresIn
?:
number
}
/**
* 验证邮箱验证码请求参数
*/
export
interface
VerifyEmailCodeDto
{
/** 邮箱地址 */
email
:
string
/** 验证码 */
code
:
string
/** 租户ID */
tenantId
?:
string
}
/**
* 验证邮箱验证码响应
*/
export
interface
VerifyEmailCodeResponseDto
{
/** 是否验证成功 */
success
:
boolean
/** 消息 */
message
?:
string
/** 验证令牌(验证成功后返回,用于后续注册) */
verificationToken
?:
string
}
// ==================== 服务类 ====================
/**
* OTA 授权服务
*/
class
OtaAuthService
{
/**
* 验证 OTA 授权码
* @param token OTA 授权码
* @returns 验证结果,包含用户信息、代理商状态和临时访问令牌
*/
static
async
validateOtaToken
(
token
:
string
):
Promise
<
ValidateOtaTokenResponse
>
{
const
response
=
await
OtaRequest
.
post
(
'/distributor-auth/validate-ota-token'
,
{
token
})
return
response
as
unknown
as
ValidateOtaTokenResponse
}
/**
* 从 OTA 提交代理商申请(使用临时令牌)
* @param data 申请信息
* @returns 申请响应
*/
static
async
registerFromOta
(
data
:
RegisterFromOtaDto
):
Promise
<
RegisterFromOtaResponse
>
{
// 临时令牌会在 OtaRequest 拦截器中自动从 sessionStorage 获取并添加到请求头
const
response
=
await
OtaRequest
.
post
(
'/distributor-auth/register-from-ota-member'
,
data
)
return
response
as
unknown
as
RegisterFromOtaResponse
}
/**
* 重新提交申请(使用临时令牌)
* @param data 申请信息
* @returns 申请响应
*/
static
async
resubmit
(
data
:
RegisterFromOtaDto
):
Promise
<
any
>
{
const
response
=
await
OtaRequest
.
post
(
'/distributor-auth/resubmit-application'
,
data
)
return
response
}
/**
* 获取当前申请状态(使用临时令牌)
* @returns 代理商状态信息
*/
static
async
getCurrentStatus
():
Promise
<
DistributorStatusInfo
>
{
const
response
=
await
OtaRequest
.
get
(
'/distributor-auth/current-status'
)
return
response
as
unknown
as
DistributorStatusInfo
}
/**
* 发送邮箱验证码
* @param email 邮箱地址
* @param tenantId 租户ID(可选)
* @returns 发送结果
*/
static
async
sendVerificationCodeAsync
(
email
:
string
,
tenantId
?:
string
):
Promise
<
SendVerificationCodeResponseDto
>
{
const
data
:
SendVerificationCodeDto
=
{
email
,
tenantId
}
const
response
=
await
OtaRequest
.
post
(
'/distributor-auth/send-verification-code'
,
data
,
{
headers
:
tenantId
?
{
'__tenant'
:
tenantId
}
:
{}
}
)
return
response
as
unknown
as
SendVerificationCodeResponseDto
}
/**
* 验证邮箱验证码
* @param email 邮箱地址
* @param code 验证码
* @param tenantId 租户ID(可选)
* @returns 验证结果
*/
static
async
verifyEmailCodeAsync
(
email
:
string
,
code
:
string
,
tenantId
?:
string
):
Promise
<
VerifyEmailCodeResponseDto
>
{
const
data
:
VerifyEmailCodeDto
=
{
email
,
code
,
tenantId
}
const
response
=
await
OtaRequest
.
post
(
'/distributor-auth/verify-email-code'
,
data
,
{
headers
:
tenantId
?
{
'__tenant'
:
tenantId
}
:
{}
}
)
return
response
as
unknown
as
VerifyEmailCodeResponseDto
}
}
export
default
OtaAuthService
src/services/UserService.ts
View file @
ed9626ca
...
@@ -61,45 +61,43 @@ export interface DistributorLoginDto {
...
@@ -61,45 +61,43 @@ export interface DistributorLoginDto {
}
}
/**
/**
*
代理商自助
注册请求参数
* 注册请求参数
*/
*/
export
interface
DistributorSelfRegisterDto
{
export
interface
DistributorSelfRegisterDto
{
/** 租户ID(手动传入,用于多租户隔离) */
/*** 出生日期*/
tenantId
:
string
birthday
?:
Date
|
null
|
string
;
/** 分销商类型 */
/*** 确认密码*/
type
:
DistributorType
confirmPassword
:
string
;
/** 公司/品牌名称 */
/*** 分销商推广码*/
companyOrBrandName
:
string
distributorCode
?:
null
|
string
;
/** 统一编号(企业营业执照号/个人身份证号) */
/*** 分销商ID*/
unifiedNumber
?:
string
distributorId
?:
number
;
/** 联络人姓名 */
/*** 电子邮箱(需要判断唯一,作为登录账号)*/
contactPerson
:
string
email
:
string
;
/** 联络电话/手机 */
/*** 勾選「我願意接收優惠與電子報」 1是*/
contactPhone
:
string
isReceivePush
?:
number
;
/** 联络地址 */
/*** LINE ID*/
contactAddress
?:
string
lineId
?:
null
|
string
;
/** LINE ID */
/*** 会员昵称*/
lineId
?:
string
name
?:
null
|
string
;
/** 微信ID */
/*** 父级会员ID*/
wechatId
?:
string
parentId
?:
null
|
string
;
/** 电子邮箱(需要判断唯一,作为登录账号) */
/*** 密码*/
email
:
string
password
:
string
;
/** 密码 */
/*** 电话*/
password
:
string
phone
?:
null
|
string
;
/** 确认密码 */
/*** 居住地區*/
confirmPassword
:
string
residentialArea
?:
null
|
string
;
/** 公司登记证明/身份影本/名片 */
/*** 注册类型 0邮箱验证码 1谷歌授权 3LINE授权 7FaceBook授权*/
documentFilePath
:
string
reType
?:
number
;
/** 开户支行名称 */
/*** 性别 1男 2女*/
openBankName
:
string
sex
?:
number
;
/** 银行名称(所属银行全称) */
/*** 临时令牌token*/
bankName
:
string
temporaryToken
?:
null
|
string
;
/** 账户持有人姓名 */
/*** 租户ID(手动传入,用于多租户隔离)*/
accountHolder
:
string
tenantId
:
string
;
/** 银行卡号 */
/*** 微信ID*/
cardNum
:
string
wechatId
?:
null
|
string
;
/** 税务登记号 */
dutyNo
?:
string
}
}
/**
/**
...
@@ -326,6 +324,8 @@ export interface SendVerificationCodeDto {
...
@@ -326,6 +324,8 @@ export interface SendVerificationCodeDto {
email
:
string
email
:
string
/** 租户ID */
/** 租户ID */
tenantId
?:
string
tenantId
?:
string
/** 场景 */
scene
?:
string
}
}
/**
/**
...
@@ -348,6 +348,10 @@ export interface VerifyEmailCodeDto {
...
@@ -348,6 +348,10 @@ export interface VerifyEmailCodeDto {
email
:
string
email
:
string
/** 验证码 */
/** 验证码 */
code
:
string
code
:
string
/** 租户ID */
tenantId
?:
string
/** 场景 */
scene
?:
string
}
}
/**
/**
...
@@ -390,6 +394,25 @@ export interface ResetPasswordResponseDto {
...
@@ -390,6 +394,25 @@ export interface ResetPasswordResponseDto {
* 用户服务
* 用户服务
*/
*/
class
UserService
{
class
UserService
{
/**
* 代理商自助注册
* @param data 注册信息
* @returns 注册响应
*/
static
async
distributorSelfRegisterAsync
(
data
:
DistributorSelfRegisterDto
):
Promise
<
DistributorSelfRegisterResultDto
>
{
const
response
=
await
OtaRequest
.
post
(
'/member-auth/self-register'
,
data
,
{
headers
:
{
'__tenant'
:
data
.
tenantId
}
}
)
return
response
as
unknown
as
DistributorSelfRegisterResultDto
}
/**
/**
* 登录
* 登录
* @param email 邮箱
* @param email 邮箱
...
@@ -463,7 +486,7 @@ class UserService {
...
@@ -463,7 +486,7 @@ class UserService {
tenantId
tenantId
}
}
const
response
=
await
OtaRequest
.
post
(
const
response
=
await
OtaRequest
.
post
(
'/
distributo
r-auth/validate-email'
,
'/
membe
r-auth/validate-email'
,
data
,
data
,
{
{
headers
:
tenantId
?
{
headers
:
tenantId
?
{
...
@@ -482,14 +505,16 @@ class UserService {
...
@@ -482,14 +505,16 @@ class UserService {
*/
*/
static
async
sendVerificationCodeAsync
(
static
async
sendVerificationCodeAsync
(
email
:
string
,
email
:
string
,
tenantId
?:
string
tenantId
?:
string
,
scene
?:
string
,
):
Promise
<
SendVerificationCodeResponseDto
>
{
):
Promise
<
SendVerificationCodeResponseDto
>
{
const
data
:
SendVerificationCodeDto
=
{
const
data
:
SendVerificationCodeDto
=
{
email
,
email
,
tenantId
tenantId
,
scene
,
}
}
const
response
=
await
OtaRequest
.
post
(
const
response
=
await
OtaRequest
.
post
(
'/
distributo
r-auth/send-email-verification-code'
,
'/
membe
r-auth/send-email-verification-code'
,
data
,
data
,
{
{
headers
:
tenantId
?
{
headers
:
tenantId
?
{
...
@@ -510,15 +535,17 @@ class UserService {
...
@@ -510,15 +535,17 @@ class UserService {
static
async
verifyEmailCodeAsync
(
static
async
verifyEmailCodeAsync
(
email
:
string
,
email
:
string
,
code
:
string
,
code
:
string
,
tenantId
?:
string
tenantId
?:
string
,
scene
?:
string
,
):
Promise
<
VerifyEmailCodeResponseDto
>
{
):
Promise
<
VerifyEmailCodeResponseDto
>
{
const
data
:
VerifyEmailCodeDto
=
{
const
data
:
VerifyEmailCodeDto
=
{
email
,
email
,
code
,
code
,
tenantId
tenantId
,
scene
}
}
const
response
=
await
OtaRequest
.
post
(
const
response
=
await
OtaRequest
.
post
(
'/
distributo
r-auth/verify-email-code'
,
'/
membe
r-auth/verify-email-code'
,
data
,
data
,
{
{
headers
:
tenantId
?
{
headers
:
tenantId
?
{
...
...
src/stores/user.ts
View file @
ed9626ca
import
{
defineStore
}
from
'pinia'
import
{
defineStore
}
from
'pinia'
import
{
ApiResult
}
from
'@/types/ApiResult'
import
ErpUserService
from
'@/services/ErpUserService'
import
{
type
StorageLike
}
from
'pinia-plugin-persistedstate'
import
{
type
StorageLike
}
from
'pinia-plugin-persistedstate'
import
SecureLS
from
'secure-ls'
import
SecureLS
from
'secure-ls'
import
UserService
,
{
import
UserService
,
{
...
@@ -31,6 +33,15 @@ export interface UserLoginResult {
...
@@ -31,6 +33,15 @@ export interface UserLoginResult {
applicationStatus
?:
string
applicationStatus
?:
string
}
}
export
interface
RegisterResult
{
success
:
boolean
message
:
string
applicationId
?:
string
distributorId
?:
number
status
?:
ApplicationStatus
data
?:
any
}
export
const
useUserStore
=
defineStore
(
'user'
,
{
export
const
useUserStore
=
defineStore
(
'user'
,
{
state
:
()
=>
({
state
:
()
=>
({
token
:
''
as
string
,
token
:
''
as
string
,
...
@@ -93,6 +104,41 @@ export const useUserStore = defineStore('user', {
...
@@ -93,6 +104,41 @@ export const useUserStore = defineStore('user', {
}
}
}
}
},
},
/**
* 谷歌登录
* @param credential 谷歌凭证
*/
async
setUserGoogleLoginAsync
(
credential
:
string
):
Promise
<
UserLoginResult
>
{
try
{
const
response
=
await
ErpUserService
.
GoogleLoginAsync
(
credential
)
if
(
response
.
data
.
resultCode
===
ApiResult
.
SUCCESS
)
{
this
.
token
=
response
.
data
.
data
.
token
||
''
this
.
userInfo
=
response
.
data
.
data
||
{}
this
.
denied
=
false
return
{
status
:
'SUCCESS'
,
verify
:
false
,
data
:
response
.
data
.
data
}
}
else
{
ResultMessage
.
Error
(
response
.
data
.
message
||
i18n
.
global
.
t
(
'login.googleLoginFailed'
))
return
{
status
:
'ERROR'
,
verify
:
false
}
}
}
catch
(
error
:
any
)
{
console
.
error
(
'Google login error:'
,
error
)
ResultMessage
.
Error
(
error
.
message
||
i18n
.
global
.
t
(
'login.googleLoginFailed'
))
return
{
status
:
'ERROR'
,
verify
:
false
}
}
},
setUserLoginOut
()
{
setUserLoginOut
()
{
this
.
token
=
''
this
.
token
=
''
this
.
userInfo
=
{}
this
.
userInfo
=
{}
...
@@ -103,7 +149,42 @@ export const useUserStore = defineStore('user', {
...
@@ -103,7 +149,42 @@ export const useUserStore = defineStore('user', {
*/
*/
setUserDeniedStatus
(
denied
:
boolean
)
{
setUserDeniedStatus
(
denied
:
boolean
)
{
this
.
denied
=
denied
this
.
denied
=
denied
}
},
/**
* 代理商自助注册
* @param data 注册信息
*/
async
registerDistributorAsync
(
data
:
DistributorSelfRegisterDto
):
Promise
<
RegisterResult
>
{
try
{
const
response
=
await
UserService
.
distributorSelfRegisterAsync
(
data
)
console
.
log
(
'Register response:'
,
response
)
return
{
success
:
true
,
message
:
response
.
message
||
i18n
.
global
.
t
(
'login.registerSuccess'
),
distributorId
:
response
.
distributorId
,
status
:
response
.
status
,
data
:
response
}
}
catch
(
error
:
any
)
{
console
.
error
(
'Register error:'
,
error
)
// 处理 ABP 错误响应
if
(
error
.
error
)
{
const
errorInfo
=
error
.
error
const
errorMessage
=
errorInfo
.
message
||
i18n
.
global
.
t
(
'login.registerFailed'
)
return
{
success
:
false
,
message
:
errorMessage
}
}
else
{
return
{
success
:
false
,
message
:
error
.
message
||
i18n
.
global
.
t
(
'httpError.networkError'
)
}
}
}
},
},
},
persist
:
{
persist
:
{
storage
:
st
,
storage
:
st
,
...
...
src/types/country.ts
0 → 100644
View file @
ed9626ca
/**
* 国家数据类型定义
*/
/**
* 国家完整信息(从后端返回)
*/
export
interface
Country
{
/** 国家ID */
id
:
string
/** 国家编码(ISO Alpha-2) */
code2
:
string
/** 国家编码(ISO Alpha-3) */
code3
:
string
/** 国家名称 */
name
:
string
/** 电话区号 */
phoneCode
:
string
/** 时区 */
timeZone
:
string
/** 首都 */
capital
:
string
/** 货币代码 */
currencyCode
:
string
/** 语言代码 */
languageCode
:
string
/** 行驶方向 */
drivingSide
:
string
/** 排序号 */
orderNum
?:
number
/** 状态 */
state
?:
boolean
/** 备注 */
remark
?:
string
}
/**
* 国家简单信息(用于下拉框)
*/
export
interface
CountrySimple
{
/** 国家ID */
id
:
string
/** 国家编码(ISO Alpha-2) */
code2
:
string
/** 国家编码(ISO Alpha-3) */
code3
:
string
/** 国家名称 */
name
:
string
/** 电话区号 */
phoneCode
:
string
/** 时区 */
timeZone
:
string
/** 是否禁用 */
disabled
?:
boolean
}
/**
* 国家分页查询参数
*/
export
interface
CountryPagedParams
{
/** 排序字段 */
sorting
?:
string
/** 跳过数量 */
skipCount
?:
number
/** 最大结果数 */
maxResultCount
?:
number
}
/**
* 分页结果
*/
export
interface
PagedResult
<
T
>
{
/** 数据列表 */
items
:
T
[]
/** 总数量 */
totalCount
:
number
}
src/types/systemConfig.ts
View file @
ed9626ca
...
@@ -55,4 +55,13 @@ export interface PartnerCenterConfigDto {
...
@@ -55,4 +55,13 @@ export interface PartnerCenterConfigDto {
creationTime
?:
string
creationTime
?:
string
/** 最后修改时间 */
/** 最后修改时间 */
lastModificationTime
?:
string
lastModificationTime
?:
string
}
/**
* 租户信息DTO(根据域名获取)
*/
export
interface
TenantInfoByDomainDto
{
tenantId
?:
string
domainName
?:
string
platformConfig
?:
PlatformConfigDto
}
}
\ No newline at end of file
src/views/auth/Login.vue
View file @
ed9626ca
This diff is collapsed.
Click to expand it.
src/views/auth/components/header.vue
View file @
ed9626ca
...
@@ -5,14 +5,14 @@
...
@@ -5,14 +5,14 @@
:src=
"systemConfigStore.config.logo"
:src=
"systemConfigStore.config.logo"
:alt=
"systemConfigStore.config.webSiteName"
:alt=
"systemConfigStore.config.webSiteName"
class=
"h-[40px]"
/>
class=
"h-[40px]"
/>
<svg
v-else
viewBox=
"0 0 100 100"
xmlns=
"http://www.w3.org/2000/svg"
>
<svg
v-else
-if=
"systemConfigStore.config?.webSiteName"
viewBox=
"0 0 100 100"
xmlns=
"http://www.w3.org/2000/svg"
>
<circle
cx=
"50"
cy=
"50"
r=
"45"
fill=
"#165dff"
/>
<circle
cx=
"50"
cy=
"50"
r=
"45"
fill=
"#165dff"
/>
<text
x=
"50"
y=
"65"
text-anchor=
"middle"
fill=
"white"
font-size=
"40"
font-weight=
"bold"
>
<text
x=
"50"
y=
"65"
text-anchor=
"middle"
fill=
"white"
font-size=
"40"
font-weight=
"bold"
>
{{
(
systemConfigStore
.
config
.
webSiteName
||
'T'
).
charAt
(
0
).
toUpperCase
()
}}
{{
(
systemConfigStore
.
config
.
webSiteName
||
'T'
).
charAt
(
0
).
toUpperCase
()
}}
</text>
</text>
</svg>
</svg>
</div>
</div>
<div
class=
"flex items-center"
>
<div
class=
"flex items-center"
v-if=
"!currentStep||currentStep
<3
"
>
<div
class=
"flex items-center mr-[67px]"
>
<div
class=
"flex items-center mr-[67px]"
>
<img
<img
src=
"../../../assets/images/login-home.png"
src=
"../../../assets/images/login-home.png"
...
@@ -25,7 +25,7 @@
...
@@ -25,7 +25,7 @@
</div>
</div>
</
template
>
</
template
>
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
{
onMounted
}
from
"vue"
;
import
{
ref
,
inject
}
from
"vue"
;
import
{
useI18n
}
from
"vue-i18n"
;
import
{
useI18n
}
from
"vue-i18n"
;
import
{
useSystemConfigStore
}
from
'@/stores/index'
import
{
useSystemConfigStore
}
from
'@/stores/index'
import
LanguageSwitcher
from
"@/components/common/LanguageSwitcher.vue"
import
LanguageSwitcher
from
"@/components/common/LanguageSwitcher.vue"
...
@@ -33,8 +33,6 @@ import LanguageSwitcher from "@/components/common/LanguageSwitcher.vue"
...
@@ -33,8 +33,6 @@ import LanguageSwitcher from "@/components/common/LanguageSwitcher.vue"
const
{
t
}
=
useI18n
();
const
{
t
}
=
useI18n
();
const
systemConfigStore
=
useSystemConfigStore
()
const
systemConfigStore
=
useSystemConfigStore
()
const
currentStep
=
ref
(
inject
(
'currentStep'
))
onMounted
(()
=>
{
});
</
script
>
</
script
>
\ No newline at end of file
src/views/auth/components/registerForm.vue
View file @
ed9626ca
This diff is collapsed.
Click to expand it.
src/views/auth/register.vue
View file @
ed9626ca
This diff is collapsed.
Click to expand it.
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