Commit 924afcbe authored by 罗超's avatar 罗超

完成员工邀请机制

parent d5f1810f
......@@ -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% {
......
......@@ -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;
......
......@@ -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');
}
......
......@@ -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'),
......
......@@ -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
......@@ -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
......
......@@ -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')
......
<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
......@@ -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;">
......
<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
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