【轻量级 PR】:模拟租户管理员身份登录
parent
93bee8c82c
commit
6171fbea11
|
|
@ -12,11 +12,26 @@ export interface SmsLoginVO {
|
||||||
code: string
|
code: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ImpersonateReqVO {
|
||||||
|
tenantId?: number
|
||||||
|
userId?: number
|
||||||
|
}
|
||||||
|
|
||||||
// 登录
|
// 登录
|
||||||
export const login = (data: UserLoginVO) => {
|
export const login = (data: UserLoginVO) => {
|
||||||
return request.post({ url: '/system/auth/login', data })
|
return request.post({ url: '/system/auth/login', data })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 模拟身份登录
|
||||||
|
export const loginImpersonate = (data: ImpersonateReqVO) => {
|
||||||
|
return request.post({ url: '/system/auth/login/impersonate', data})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 退出身份模拟
|
||||||
|
export const stopImpersonation = () => {
|
||||||
|
return request.post({ url: '/system/auth/stop-impersonation'})
|
||||||
|
}
|
||||||
|
|
||||||
// 刷新访问令牌
|
// 刷新访问令牌
|
||||||
export const refreshToken = () => {
|
export const refreshToken = () => {
|
||||||
return request.post({ url: '/system/auth/refresh-token?refreshToken=' + getRefreshToken() })
|
return request.post({ url: '/system/auth/refresh-token?refreshToken=' + getRefreshToken() })
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ import { useUserStore } from '@/store/modules/user'
|
||||||
import LockDialog from './components/LockDialog.vue'
|
import LockDialog from './components/LockDialog.vue'
|
||||||
import LockPage from './components/LockPage.vue'
|
import LockPage from './components/LockPage.vue'
|
||||||
import { useLockStore } from '@/store/modules/lock'
|
import { useLockStore } from '@/store/modules/lock'
|
||||||
|
import * as LoginApi from '@/api/login'
|
||||||
|
import * as authUtil from "@/utils/auth"
|
||||||
|
|
||||||
defineOptions({ name: 'UserInfo' })
|
defineOptions({ name: 'UserInfo' })
|
||||||
|
|
||||||
|
|
@ -34,6 +36,18 @@ const lockScreen = () => {
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stopImpersonation = async () => {
|
||||||
|
const res = await LoginApi.stopImpersonation()
|
||||||
|
if(!res){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await userStore.loginOut()
|
||||||
|
tagsViewStore.delAllViews()
|
||||||
|
authUtil.setToken(res)
|
||||||
|
authUtil.setTenantId(res.tenantId)
|
||||||
|
push({ path: authUtil.getImpersonateRefererPath() || '' })
|
||||||
|
}
|
||||||
|
|
||||||
const loginOut = async () => {
|
const loginOut = async () => {
|
||||||
try {
|
try {
|
||||||
await ElMessageBox.confirm(t('common.loginOutMessage'), t('common.reminder'), {
|
await ElMessageBox.confirm(t('common.loginOutMessage'), t('common.reminder'), {
|
||||||
|
|
@ -76,6 +90,10 @@ const toDocument = () => {
|
||||||
<Icon icon="ep:lock" />
|
<Icon icon="ep:lock" />
|
||||||
<div @click="lockScreen">{{ t('lock.lockScreen') }}</div>
|
<div @click="lockScreen">{{ t('lock.lockScreen') }}</div>
|
||||||
</ElDropdownItem>
|
</ElDropdownItem>
|
||||||
|
<ElDropdownItem divided v-if="userStore.getUser.impersonated">
|
||||||
|
<Icon icon="humbleicons:incognito" />
|
||||||
|
<div @click="stopImpersonation">{{ t('common.stopImpersonation') }}</div>
|
||||||
|
</ElDropdownItem>
|
||||||
<ElDropdownItem divided @click="loginOut">
|
<ElDropdownItem divided @click="loginOut">
|
||||||
<Icon icon="ep:switch-button" />
|
<Icon icon="ep:switch-button" />
|
||||||
<div>{{ t('common.loginOut') }}</div>
|
<div>{{ t('common.loginOut') }}</div>
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ export default {
|
||||||
login: 'Login',
|
login: 'Login',
|
||||||
required: 'This is required',
|
required: 'This is required',
|
||||||
loginOut: 'Login out',
|
loginOut: 'Login out',
|
||||||
|
stopImpersonation: 'Stop impersonation',
|
||||||
document: 'Document',
|
document: 'Document',
|
||||||
profile: 'User Center',
|
profile: 'User Center',
|
||||||
reminder: 'Reminder',
|
reminder: 'Reminder',
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ export default {
|
||||||
login: '登录',
|
login: '登录',
|
||||||
required: '该项为必填项',
|
required: '该项为必填项',
|
||||||
loginOut: '退出系统',
|
loginOut: '退出系统',
|
||||||
|
stopImpersonation: '退出身份模拟',
|
||||||
document: '项目文档',
|
document: '项目文档',
|
||||||
profile: '个人中心',
|
profile: '个人中心',
|
||||||
reminder: '温馨提示',
|
reminder: '温馨提示',
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ interface UserVO {
|
||||||
avatar: string
|
avatar: string
|
||||||
nickname: string
|
nickname: string
|
||||||
deptId: number
|
deptId: number
|
||||||
|
impersonated: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface UserInfoVO {
|
interface UserInfoVO {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ const { wsCache } = useCache()
|
||||||
|
|
||||||
const AccessTokenKey = 'ACCESS_TOKEN'
|
const AccessTokenKey = 'ACCESS_TOKEN'
|
||||||
const RefreshTokenKey = 'REFRESH_TOKEN'
|
const RefreshTokenKey = 'REFRESH_TOKEN'
|
||||||
|
const ImpersonateRefererKey = 'IMPERSONATED_REFERER'
|
||||||
|
|
||||||
// 获取token
|
// 获取token
|
||||||
export const getAccessToken = () => {
|
export const getAccessToken = () => {
|
||||||
|
|
@ -24,6 +25,16 @@ export const setToken = (token: TokenType) => {
|
||||||
wsCache.set(AccessTokenKey, token.accessToken)
|
wsCache.set(AccessTokenKey, token.accessToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置退出模拟身份登录后的跳转路径
|
||||||
|
export const setImpersonateRefererPath = (path: string) => {
|
||||||
|
wsCache.set(ImpersonateRefererKey, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取退出模拟身份登录后的跳转路径
|
||||||
|
export const getImpersonateRefererPath = () => {
|
||||||
|
return wsCache.get(ImpersonateRefererKey)
|
||||||
|
}
|
||||||
|
|
||||||
// 删除token
|
// 删除token
|
||||||
export const removeToken = () => {
|
export const removeToken = () => {
|
||||||
wsCache.delete(AccessTokenKey)
|
wsCache.delete(AccessTokenKey)
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,16 @@
|
||||||
/>
|
/>
|
||||||
<el-table-column label="操作" align="center" min-width="110" fixed="right">
|
<el-table-column label="操作" align="center" min-width="110" fixed="right">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
link
|
||||||
|
type="primary"
|
||||||
|
@click="handleImpersonate(scope.row)"
|
||||||
|
v-if="authUtil.getTenantId() !== scope.row.id"
|
||||||
|
v-hasPermi="['system:login:impersonate']"
|
||||||
|
v-hasRole="['super_admin']"
|
||||||
|
>
|
||||||
|
模拟身份
|
||||||
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
link
|
link
|
||||||
type="primary"
|
type="primary"
|
||||||
|
|
@ -176,14 +186,20 @@ import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||||
import { dateFormatter } from '@/utils/formatTime'
|
import { dateFormatter } from '@/utils/formatTime'
|
||||||
import download from '@/utils/download'
|
import download from '@/utils/download'
|
||||||
import * as TenantApi from '@/api/system/tenant'
|
import * as TenantApi from '@/api/system/tenant'
|
||||||
|
import * as LoginApi from '@/api/login'
|
||||||
|
import * as authUtil from '@/utils/auth'
|
||||||
|
const { currentRoute, push } = useRouter()
|
||||||
|
import { useUserStore } from '@/store/modules/user'
|
||||||
import * as TenantPackageApi from '@/api/system/tenantPackage'
|
import * as TenantPackageApi from '@/api/system/tenantPackage'
|
||||||
import TenantForm from './TenantForm.vue'
|
import TenantForm from './TenantForm.vue'
|
||||||
|
import { useTagsViewStore } from '@/store/modules/tagsView'
|
||||||
|
|
||||||
defineOptions({ name: 'SystemTenant' })
|
defineOptions({ name: 'SystemTenant' })
|
||||||
|
|
||||||
const message = useMessage() // 消息弹窗
|
const message = useMessage() // 消息弹窗
|
||||||
const { t } = useI18n() // 国际化
|
const { t } = useI18n() // 国际化
|
||||||
|
|
||||||
|
const userStore = useUserStore()
|
||||||
const loading = ref(true) // 列表的加载中
|
const loading = ref(true) // 列表的加载中
|
||||||
const total = ref(0) // 列表的总页数
|
const total = ref(0) // 列表的总页数
|
||||||
const list = ref([]) // 列表的数据
|
const list = ref([]) // 列表的数据
|
||||||
|
|
@ -199,7 +215,7 @@ const queryParams = reactive({
|
||||||
const queryFormRef = ref() // 搜索的表单
|
const queryFormRef = ref() // 搜索的表单
|
||||||
const exportLoading = ref(false) // 导出的加载中
|
const exportLoading = ref(false) // 导出的加载中
|
||||||
const packageList = ref([] as TenantPackageApi.TenantPackageVO[]) //租户套餐列表
|
const packageList = ref([] as TenantPackageApi.TenantPackageVO[]) //租户套餐列表
|
||||||
|
const tagsViewStore = useTagsViewStore()
|
||||||
/** 查询列表 */
|
/** 查询列表 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
|
|
@ -243,6 +259,23 @@ const handleDelete = async (id: number) => {
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 模拟身份登录 */
|
||||||
|
const handleImpersonate = async (row) => {
|
||||||
|
try {
|
||||||
|
const res = await LoginApi.loginImpersonate({tenantId: row.id, userId: row.contactUserId})
|
||||||
|
if (!res) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await userStore.loginOut()
|
||||||
|
authUtil.setToken(res)
|
||||||
|
authUtil.setTenantId(row.id)
|
||||||
|
authUtil.setImpersonateRefererPath(currentRoute.value.path)
|
||||||
|
tagsViewStore.delAllViews()
|
||||||
|
push({ path: '/' })
|
||||||
|
} finally {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 导出按钮操作 */
|
/** 导出按钮操作 */
|
||||||
const handleExport = async () => {
|
const handleExport = async () => {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue