Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
pptist
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
viitto
pptist
Commits
924afcbe
Commit
924afcbe
authored
May 08, 2024
by
罗超
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
完成员工邀请机制
parent
d5f1810f
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
247 additions
and
6 deletions
+247
-6
index.html
public/index.html
+2
-2
common.css
src/assets/styles/common.css
+8
-0
index.ts
src/router/index.ts
+1
-1
router.ts
src/router/router.ts
+7
-0
UserService.ts
src/services/UserService.ts
+10
-0
Login.vue
src/views/Auth/Login.vue
+23
-1
Index.vue
src/views/Index.vue
+12
-2
Join.vue
src/views/TeamCenter/Join.vue
+101
-0
CreateEnterprise.vue
src/views/components/Order/CreateEnterprise.vue
+2
-0
JoinEnterprise.vue
src/views/components/Team/JoinEnterprise.vue
+81
-0
No files found.
public/index.html
View file @
924afcbe
...
...
@@ -28,14 +28,14 @@
.first-screen-loading-spinner
{
width
:
36px
;
height
:
36px
;
border
:
3px
solid
#
d14424
;
border
:
3px
solid
#
564bec
;
border-top-color
:
transparent
;
border-radius
:
50%
;
animation
:
spinner
.8s
linear
infinite
;
}
.first-screen-loading-text
{
margin-top
:
20px
;
color
:
#
d14424
;
color
:
#
564bec
;
}
@keyframes
spinner
{
0
%
{
...
...
src/assets/styles/common.css
View file @
924afcbe
...
...
@@ -312,6 +312,14 @@ page {
.van-multi-ellipsis--l5
{
-webkit-line-clamp
:
5
;
}
.text-ellipsis
{
white-space
:
nowrap
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
}
.flex-overflow
{
min-width
:
0
;
}
.text-shadow
{
text-shadow
:
2px
2px
5px
rgba
(
0
,
0
,
0
,
0.5
);
word-break
:
break-all
;
...
...
src/router/index.ts
View file @
924afcbe
...
...
@@ -21,7 +21,7 @@ router.beforeEach((to:any, from:any, next:any) => {
lock
:
true
})
}
if
((
whiteList
.
includes
(
to
.
path
)
||
user
.
getUserToken
!=
''
)
&&
!
to
.
query
.
uid
)
{
if
((
whiteList
.
includes
(
to
.
path
)
||
user
.
getUserToken
!=
''
||
to
.
path
.
includes
(
'/j/'
)
)
&&
!
to
.
query
.
uid
)
{
if
(
managerMenu
.
includes
(
to
.
path
)
&&
user
.
getUser
.
isTemplate
!=
1
){
next
(
'/notfound'
);
}
...
...
src/router/router.ts
View file @
924afcbe
...
...
@@ -283,6 +283,13 @@ const routes: RouteRecordRaw[] = [
title
:
'产品介绍'
}
},
{
path
:
'/j/:code'
,
component
:
()
=>
import
(
'@/views/TeamCenter/Join.vue'
),
meta
:{
title
:
'产品介绍'
}
},
{
path
:
'/:catchAll(.*)*'
,
component
:
()
=>
import
(
'@/views/ErrorNotFound.vue'
),
...
...
src/services/UserService.ts
View file @
924afcbe
...
...
@@ -43,5 +43,15 @@ class UserServices{
let
msg
=
{
ia
}
return
Api
.
Post
(
"travel_set_invite_code"
,
msg
)
}
static
async
JoinTeamByInviteCodeAsync
(
code
:
string
):
Promise
<
HttpResponse
>
{
let
msg
=
{
code
}
return
Api
.
Post
(
"travel_set_join_code"
,
msg
)
}
static
async
ValidateInviteCodeAsync
(
code
:
string
):
Promise
<
HttpResponse
>
{
let
msg
=
{
code
}
return
Api
.
Post
(
"travel_validate_invite"
,
msg
)
}
}
export
default
UserServices
;
\ No newline at end of file
src/views/Auth/Login.vue
View file @
924afcbe
...
...
@@ -14,6 +14,16 @@
<div
class=
"text-center text-small text-info full-width"
>
@2012-2024 成都微途科技有限公司 版权所有 蜀ICP备13024891号-9
</div>
</div>
<div
class=
"login-form q-pa-xl column flex-center items-center"
style=
"padding: 30px 100px;"
v-if=
"token==''"
>
<div
class=
"q-mb-xl full-width"
v-if=
"inviteInfo"
>
<div
class=
"q-mt-lg no-select row items-center q-pa-lg rounded"
style=
"background-color: rgb(240, 246, 255);"
>
<el-avatar
:size=
"44"
:src=
"inviteInfo.logo"
shape=
"square"
></el-avatar>
<div
class=
"q-ml-md col flex-overflow"
>
<div
class=
"text-dark text-weight-bold text-ellipsis"
>
{{
inviteInfo
.
nickname
}}
邀请你加入
{{
inviteInfo
.
company
}}{{
inviteInfo
.
nickname
}}
邀请你加入
{{
inviteInfo
.
company
}}
</div>
<div
class=
"text-grey-8 text-small q-mt-sm"
>
{{
inviteInfo
.
expire
}}
后失效
</div>
</div>
<el-button
type=
"info"
class=
"ppt-button q-ml-md"
@
click=
"cancelInviteHandler"
>
取消
</el-button>
</div>
</div>
<div
style=
"font-size: 36px; "
class=
"text-dark"
>
登录
</div>
<div
class=
"text-info text-small"
>
你的创作空间
</div>
<template
v-if=
"!multipleUsers || multipleUsers.length==0"
>
...
...
@@ -96,6 +106,11 @@ const user = useUserStore()
const
token
=
user
.
getUserToken
??
''
const
userInfo
=
user
.
getUser
const
multipleUsers
=
ref
<
any
[]
>
([])
const
inviteInfo
=
ref
<
any
>
()
if
(
localStorage
.
getItem
(
"invite"
)){
inviteInfo
.
value
=
JSON
.
parse
(
localStorage
.
getItem
(
"invite"
)??
'{}'
)
}
const
rules
=
reactive
<
FormRules
<
RuleForm
>>
({
account
:
[
{
required
:
true
,
message
:
'请输入你的账号'
,
trigger
:
'blur'
},
...
...
@@ -117,7 +132,10 @@ const submitForm = async (formEl: FormInstance | undefined) => {
})
loading
.
value
=
false
}
const
cancelInviteHandler
=
()
=>
{
inviteInfo
.
value
=
null
localStorage
.
removeItem
(
'invite'
)
}
const
loginByCompany
=
async
()
=>
{
if
(
model
.
value
.
tid
==
''
)
ElMessage
.
error
({
message
:
'请选择需要登录的组织'
})
else
{
...
...
@@ -131,6 +149,10 @@ const userLoginHandler = async ()=>{
const
result
=
await
user
.
setUserPasswordLoginAsync
(
model
.
value
.
account
,
model
.
value
.
password
,
model
.
value
.
tid
)
if
(
result
.
status
==
'SUCCESS'
){
ElMessage
.
success
({
message
:
'登录成功'
})
if
(
inviteInfo
.
value
){
localStorage
.
removeItem
(
'invite'
)
localStorage
.
setItem
(
'sure_invite'
,
JSON
.
stringify
(
inviteInfo
.
value
))
}
location
.
href
=
'/space'
;
}
else
if
(
result
.
status
==
'CHOSEN'
&&
Array
.
isArray
(
result
.
data
)){
multipleUsers
.
value
=
result
.
data
...
...
src/views/Index.vue
View file @
924afcbe
...
...
@@ -108,7 +108,7 @@
</el-tooltip>
</div>
<el-popover
placement=
"right"
trigger=
"click"
width=
"320"
>
<el-popover
placement=
"right"
ref=
"popoverRef"
trigger=
"click"
width=
"320"
>
<template
#
reference
>
<div
class=
"left-button q-mb-md"
:class=
"
{'active':!isWorkspace}" title="企业中心">
<span
class=
"svg-icon svg-icon-primary svg-icon-2x"
>
...
...
@@ -162,7 +162,7 @@
<IconLogout
size=
"18"
style=
"margin-right: 8px"
/>
<span>
退出团队/企业
</span>
</el-menu-item>
<el-menu-item
index=
"4"
class=
"rounded"
v-if=
"userInfo.it && (userInfo.ia || userInfo.ic)"
>
<el-menu-item
index=
"4"
class=
"rounded"
@
click=
"showInviteHandler"
v-if=
"userInfo.it && (userInfo.ia || userInfo.ic)"
>
<IconShareOne
size=
"18"
style=
"margin-right: 8px"
/>
<span>
邀请成员
</span>
</el-menu-item>
...
...
@@ -178,6 +178,8 @@
</div>
<OrderReview
v-if=
"orderVisible && activeOrderId==''"
:default-type=
"2"
@
close=
"()=>orderVisible=false"
></OrderReview>
<CreateEnterprise
:order-id=
"activeOrderId"
v-if=
"orderVisible && activeOrderId!=''"
@
close=
"()=>orderVisible=false"
></CreateEnterprise>
<invite-member
v-if=
"showAddMember"
:show-type=
"1"
@
close=
"()=>showAddMember=false"
></invite-member>
<join-enterprise></join-enterprise>
</template>
<
script
lang=
"ts"
setup
>
...
...
@@ -195,6 +197,8 @@ import OrderReview from '@/views/components/Order/Review.vue'
import
{
ElLoading
}
from
"element-plus"
;
import
OrderService
from
"@/services/OrderService"
;
import
{
ApiResult
}
from
"@/configs/axios"
;
import
InviteMember
from
"@/views/components/Team/InviteMember.vue"
;
import
JoinEnterprise
from
"@/views/components/Team/JoinEnterprise.vue"
;
const
{
userInfo
}
=
storeToRefs
(
useUserStore
());
console
.
log
(
userInfo
.
value
)
...
...
@@ -203,6 +207,8 @@ const orderVisible = ref(false)
const
router
=
useRouter
()
const
isWorkspace
=
ref
(
true
)
const
activeOrderId
=
ref
(
''
)
const
showAddMember
=
ref
(
false
)
const
popoverRef
=
ref
()
isWorkspace
.
value
=
!
router
.
currentRoute
.
value
.
path
.
includes
(
'/space/cp'
)
const
openMarketHandler
=
(
type
:
string
=
""
)
=>
{
...
...
@@ -235,6 +241,10 @@ const createEnterpriseHandler = async ()=>{
pageLoading
.
close
()
orderVisible
.
value
=
true
}
const
showInviteHandler
=
()
=>
{
showAddMember
.
value
=
true
popoverRef
.
value
?.
hide
?.()
}
const
redicetTo
=
(
path
:
string
)
=>
{
isWorkspace
.
value
=
!
path
.
includes
(
'/space/cp'
)
...
...
src/views/TeamCenter/Join.vue
0 → 100644
View file @
924afcbe
<
template
>
<div
class=
"window-height column flex-center items-center"
style=
"background-color: #f0f2f5;"
>
<div
class=
"rounded light-shadow q-pa-xl bg-white text-center"
style=
"width: 500px;"
>
<div
class=
"row items-center"
>
<img
src=
"https://viitto-1301420277.cos.ap-chengdu.myqcloud.com/Test/Upload/Goods/1715138194000_864.png"
width=
"35px"
>
<div
class=
"text-dark q-ml-md text-weight-bold"
>
团队或企业邀请
</div>
</div>
<template
v-if=
"message != 'joined' && !inviteInfo"
>
<img
src=
"https://viitto-1301420277.cos.ap-chengdu.myqcloud.com/Test/Upload/Goods/1715138490000_986.png"
style=
"width:200px"
class=
"q-mt-xl"
>
<div
class=
"text-subtitle q-mt-lg"
style=
"font-size: 14px;"
>
{{
message
}}
</div>
</
template
>
<
template
v-else-if=
"message == 'joined' && !inviteInfo"
>
<img
src=
"https://viitto-1301420277.cos.ap-chengdu.myqcloud.com/Test/Upload/Goods/1715138490000_986.png"
style=
"width:200px"
class=
"q-mt-xl"
>
<div
class=
"text-subtitle q-mt-lg row items-center flex-center"
style=
"font-size: 14px;"
>
<span>
你已经加入了「
{{
userInfo
.
company
}}
」,
</span>
<el-button
link
type=
"primary"
@
click=
"redicetTo('/space')"
>
进入组织空间
</el-button>
</div>
</
template
>
<
template
v-else-if=
"inviteInfo && message == ''"
>
<div
class=
"q-mt-xl"
>
<div
class=
"f14 text-dark text-left"
>
{{
inviteInfo
.
nickname
}}
正在邀请你加入
</div>
<div
class=
"q-mt-lg no-select row items-center q-pa-lg rounded"
style=
"background-color: rgb(240, 246, 255);"
>
<el-avatar
:size=
"44"
:src=
"inviteInfo.logo"
shape=
"square"
></el-avatar>
<div
class=
"q-ml-md"
>
<div
class=
"text-dark text-weight-bold"
>
{{
inviteInfo
.
company
}}
</div>
<div
class=
"text-grey-8 text-small q-mt-sm"
>
{{
inviteInfo
.
expire
}}
后失效
</div>
</div>
</div>
<el-button
type=
"primary"
size=
"large"
class=
"q-mt-xl ppt-button"
:loading=
"joinLoading"
@
click=
"joinTenantHandler"
>
立即加入
</el-button>
</div>
</
template
>
</div>
</div>
</template>
<
script
lang=
"ts"
setup
>
import
{
ApiResult
}
from
"@/configs/axios"
;
import
{
ENTERPRISE_DEFAULT_HEADER
}
from
"@/configs/customer"
;
import
UserServices
from
"@/services/UserService"
;
import
{
useUserStore
}
from
"@/store"
;
import
{
ElLoading
,
ElMessage
}
from
"element-plus"
;
import
{
storeToRefs
}
from
"pinia"
;
import
{
ref
}
from
"vue"
;
import
{
useRouter
}
from
"vue-router"
;
const
loading
=
ElLoading
.
service
({
text
:
'正在加载邀请信息'
})
const
router
=
useRouter
()
const
code
=
router
.
currentRoute
.
value
.
params
.
code
.
toString
()
const
useUser
=
useUserStore
()
const
{
userInfo
,
token
}
=
storeToRefs
(
useUser
)
const
message
=
ref
(
''
)
const
inviteInfo
=
ref
<
any
>
()
const
joinLoading
=
ref
(
false
)
if
(
!
code
)
router
.
push
({
path
:
'/notfound'
})
const
loadInviterInfo
=
async
()
=>
{
const
response
=
await
UserServices
.
ValidateInviteCodeAsync
(
code
)
if
(
response
.
data
.
resultCode
==
ApiResult
.
SUCCESS
)
{
inviteInfo
.
value
=
response
.
data
.
data
inviteInfo
.
value
.
logo
=
!
inviteInfo
.
value
.
logo
||
!
inviteInfo
.
value
.
logo
.
includes
(
'http://'
)
||
!
inviteInfo
.
value
.
logo
.
includes
(
'https://'
)
?
ENTERPRISE_DEFAULT_HEADER
:
inviteInfo
.
value
.
logo
localStorage
.
setItem
(
"invite"
,
JSON
.
stringify
(
inviteInfo
.
value
))
if
(
token
.
value
!=
''
)
{
//@TODO: r如果用户存在企业,是否加入其它企业,免费用户直接加入
}
else
{
router
.
push
(
'/login'
)
}
}
else
{
message
.
value
=
response
.
data
.
message
}
loading
.
close
()
}
const
redicetTo
=
(
path
:
string
)
=>
router
.
push
({
path
})
const
joinTenantHandler
=
async
()
=>
{
if
(
!
inviteInfo
.
value
||
message
.
value
!=
''
||
joinLoading
.
value
)
return
joinLoading
.
value
=
true
const
response
=
await
UserServices
.
JoinTeamByInviteCodeAsync
(
code
)
if
(
response
.
data
.
resultCode
==
ApiResult
.
SUCCESS
){
useUser
.
setNewUserInfo
(
response
.
data
.
data
)
ElMessage
.
success
({
message
:
`成功加入了「
${
inviteInfo
.
value
.
company
}
」,正在进入控制台`
})
localStorage
.
removeItem
(
'invite'
)
setTimeout
(()
=>
{
router
.
push
({
path
:
'/space'
})
},
1000
);
}
else
{
ElMessage
.
error
({
message
:
response
.
data
.
message
})
joinLoading
.
value
=
false
}
}
loadInviterInfo
()
</
script
>
<
style
scoped
></
style
>
\ No newline at end of file
src/views/components/Order/CreateEnterprise.vue
View file @
924afcbe
...
...
@@ -6,6 +6,8 @@
</div>
<div
class=
"row full-width"
>
<div
class=
"column flex-center items-center q-px-xl"
>
<!-- https://viitto-1301420277.cos.ap-chengdu.myqcloud.com/Test/Upload/Goods/1715074196000_801.png -->
<!-- https://viitto-1301420277.cos.ap-chengdu.myqcloud.com/Test/Upload/Goods/1714372736000_535.png -->
<img
src=
"https://viitto-1301420277.cos.ap-chengdu.myqcloud.com/Test/Upload/Goods/1714372736000_535.png"
style=
"width:20vw;"
>
</div>
<div
class=
"create-enter col column flex-center items-center"
style=
"height: 30vw;"
>
...
...
src/views/components/Team/JoinEnterprise.vue
0 → 100644
View file @
924afcbe
<
template
>
<div
class=
"full-dialog column flex-center items-center"
v-if=
"showJoinVisible"
>
<div
class=
"q-pa-lg bg-white rounded light-shadow"
style=
"width:500px;"
>
<div
class=
"text-weight-bold q-mb-xl row items-center"
style=
"font-size: 18px;"
>
<img
src=
"https://viitto-1301420277.cos.ap-chengdu.myqcloud.com/Test/Upload/Goods/1715138194000_864.png"
width=
"35px"
>
<div
class=
"text-dark q-ml-md text-weight-bold"
>
团队或企业邀请
</div>
</div>
<div
class=
"f14 text-dark"
>
{{
inviteInfo
.
nickname
}}
正在邀请你加入
</div>
<div
class=
"q-mt-lg no-select row items-center q-pa-lg rounded"
style=
"background-color: rgb(240, 246, 255);"
>
<el-avatar
:size=
"44"
:src=
"inviteInfo.logo"
shape=
"square"
></el-avatar>
<div
class=
"q-ml-md"
>
<div
class=
"text-dark text-weight-bold"
>
{{
inviteInfo
.
company
}}
</div>
<div
class=
"text-grey-8 text-small q-mt-sm"
>
{{
inviteInfo
.
expire
}}
后失效
</div>
</div>
</div>
<div
class=
"q-mt-xl text-right"
>
<el-button
class=
"q-px-md q-mr-md ppt-button"
@
click=
"rejectHandler"
:disabled=
"joinLoading"
>
拒绝加入
</el-button>
<el-button
type=
"primary"
class=
"q-px-md ppt-button"
:loading=
"joinLoading"
@
click=
"joinTenantHandler"
>
确认加入
</el-button>
</div>
</div>
</div>
</
template
>
<
script
lang=
"ts"
setup
>
import
{
ApiResult
}
from
"@/configs/axios"
;
import
UserServices
from
"@/services/UserService"
;
import
{
useUserStore
}
from
"@/store"
;
import
{
ElMessage
}
from
"element-plus"
;
import
{
storeToRefs
}
from
"pinia"
;
import
{
ref
}
from
"vue"
;
const
useUser
=
useUserStore
()
const
{
userInfo
}
=
storeToRefs
(
useUser
)
const
inviteInfo
=
ref
<
any
>
()
const
showJoinVisible
=
ref
(
false
)
const
joinLoading
=
ref
(
false
)
if
(
localStorage
.
getItem
(
"sure_invite"
)){
inviteInfo
.
value
=
JSON
.
parse
(
localStorage
.
getItem
(
"sure_invite"
)??
'{}'
)
}
const
loadInviterInfo
=
async
()
=>
{
if
(
!
inviteInfo
.
value
)
return
;
const
response
=
await
UserServices
.
ValidateInviteCodeAsync
(
inviteInfo
.
value
.
code
)
if
(
response
.
data
.
resultCode
==
ApiResult
.
SUCCESS
)
{
showJoinVisible
.
value
=
true
}
}
const
rejectHandler
=
()
=>
{
inviteInfo
.
value
=
null
localStorage
.
removeItem
(
"sure_invite"
)
showJoinVisible
.
value
=
false
}
const
joinTenantHandler
=
async
()
=>
{
if
(
!
inviteInfo
.
value
||
joinLoading
.
value
)
return
joinLoading
.
value
=
true
const
response
=
await
UserServices
.
JoinTeamByInviteCodeAsync
(
inviteInfo
.
value
.
code
)
if
(
response
.
data
.
resultCode
==
ApiResult
.
SUCCESS
){
useUser
.
setNewUserInfo
(
response
.
data
.
data
)
ElMessage
.
success
({
message
:
`成功加入了「
${
inviteInfo
.
value
.
company
}
」`
})
setTimeout
(()
=>
{
location
.
reload
()
},
1000
);
}
else
{
ElMessage
.
error
({
message
:
response
.
data
.
message
})
joinLoading
.
value
=
false
}
rejectHandler
()
}
loadInviterInfo
()
</
script
>
<
style
>
</
style
>
\ No newline at end of file
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