<script setup lang="ts">
|
import { useMessage } from '@jnpf/hooks';
|
import { useModal } from '@jnpf/ui/modal';
|
import { toDateText } from '@jnpf/utils';
|
|
import dayjs from 'dayjs';
|
|
import { deleteOnlineUser } from '#/api/permission/onlineUser';
|
import { $t } from '#/locales';
|
|
import Form from './Form.vue';
|
import ResetPwdModal from './ResetPwdModal.vue';
|
|
const props = defineProps({
|
user: { type: Object, default: () => ({}) },
|
});
|
|
const { createMessage, createConfirm } = useMessage();
|
const [registerForm, { openModal: openFormModal }] = useModal();
|
const [registerResetPwdModal, { openModal: openResetPwdModal }] = useModal();
|
|
function getLoginTime(time) {
|
return toDateText(dayjs(time).valueOf());
|
}
|
// 退出
|
function handleExit(token, i, key) {
|
createConfirm({
|
iconType: 'warning',
|
title: $t('common.tipTitle'),
|
content: '您确定要强制退出该用户吗, 是否继续?',
|
onOk: () => {
|
deleteOnlineUser(token).then((res) => {
|
createMessage.success(res.msg);
|
props.user[key].splice(i, 1);
|
});
|
},
|
});
|
}
|
</script>
|
|
<template>
|
<div class="flex h-full flex-col overflow-hidden">
|
<jnpf-group-title content="账号安全" class="mb-[10px]" />
|
<div class="account-v flex-1 overflow-auto">
|
<div class="account-cap">基础信息</div>
|
<a-form :colon="false" label-align="left" :label-col="{ style: { width: '120px' } }" class="mb-[40px] px-[10px]">
|
<a-form-item label="账号">
|
{{ user.account }}
|
</a-form-item>
|
<a-form-item label="手机">
|
<span class="pr-[20px]" v-if="user.mobilePhone">{{ user.mobilePhone }}</span>
|
<span class="link-text" @click="openFormModal(true, { type: 'mobilePhone' })">修改</span>
|
</a-form-item>
|
<a-form-item label="邮箱">
|
<span class="pr-[20px]" v-if="user.email">{{ user.email }}</span>
|
<span class="link-text" @click="openFormModal(true, { type: 'email' })">修改</span>
|
</a-form-item>
|
<a-form-item label="密码">
|
<span class="link-text" @click="openResetPwdModal(true, {})">修改</span>
|
</a-form-item>
|
</a-form>
|
<div class="account-cap !mb-[20px]">登录列表<span>您当前已在以下设备上登录</span></div>
|
<div class="account-cap account-cap-sub">网页端</div>
|
<div class="online-list">
|
<a-row class="online-item" v-for="(item, i) in user.pcOnlineModelList" :key="item.token">
|
<a-col :span="10">
|
<div class="online-sys">{{ item.loginSystem }}<a-tag color="success" class="ml-[10px]" v-if="item.isCurrent">当前</a-tag></div>
|
<div class="sub-text">{{ item.loginBrowser }}</div>
|
</a-col>
|
<a-col :span="6" class="sub-text" :title="item.loginTime">{{ getLoginTime(item.loginTime) }}</a-col>
|
<a-col :span="6" class="sub-text">
|
{{ item.loginIPAddress }}<span v-if="item.loginAddress">({{ item.loginAddress }})</span>
|
</a-col>
|
<a-col :span="2" class="exit-box" v-if="!item.isCurrent"><span @click="handleExit(item.token, i, 'pcOnlineModelList')">退出</span></a-col>
|
</a-row>
|
</div>
|
<div class="account-cap account-cap-sub !mt-[30px]">移动客户端</div>
|
<div class="online-list">
|
<a-row class="online-item" v-for="(item, i) in user.appOnlineModelList" :key="item.token">
|
<a-col :span="10">
|
<div class="online-sys">{{ item.loginSystem }}<a-tag color="success" class="ml-[10px]" v-if="item.isCurrent">当前</a-tag></div>
|
<div class="sub-text">{{ item.loginBrowser }}</div>
|
</a-col>
|
<a-col :span="6" class="sub-text" :title="item.loginTime">{{ getLoginTime(item.loginTime) }}</a-col>
|
<a-col :span="6" class="sub-text">
|
{{ item.loginIPAddress }}<span v-if="item.loginAddress">({{ item.loginAddress }})</span>
|
</a-col>
|
<a-col :span="2" class="exit-box" v-if="!item.isCurrent"><span @click="handleExit(item.token, i, 'appOnlineModelList')">退出</span></a-col>
|
</a-row>
|
<jnpf-empty v-if="!user.appOnlineModelList?.length" />
|
</div>
|
</div>
|
</div>
|
<ResetPwdModal @register="registerResetPwdModal" />
|
<Form @register="registerForm" :user="user" />
|
</template>
|
<style lang="scss" scoped>
|
.account-v {
|
padding: 10px;
|
|
.account-cap {
|
margin-bottom: 15px;
|
font-size: 16px;
|
font-weight: 600;
|
|
&.account-cap-sub {
|
font-size: 14px;
|
}
|
|
span {
|
margin-left: 20px;
|
font-size: 12px;
|
font-weight: 500;
|
color: var(--text-color-label);
|
}
|
}
|
|
.ant-form-item {
|
margin-bottom: 10px;
|
}
|
|
.online-list {
|
.online-item {
|
display: flex;
|
align-items: center;
|
height: 80px;
|
padding: 0 20px;
|
margin-bottom: 15px;
|
border: 1px solid var(--border-color-base);
|
border-radius: 8px;
|
|
.online-sys {
|
font-size: 16px;
|
font-weight: 500;
|
}
|
|
.sub-text {
|
font-size: 14px;
|
color: var(--text-color-secondary);
|
}
|
|
.exit-box {
|
text-align: right;
|
|
span {
|
color: var(--error-color);
|
cursor: pointer;
|
}
|
}
|
}
|
}
|
}
|
</style>
|