| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- <!--
- * @since: 2025-02-07
- * LoginLog.vue
- -->
- <template>
- <div class="login-log">
- <el-card class="mb-3 proCard">
- <el-space >
- <el-form ref="searchFormRef" :inline="true" :model="requestParams.queryParam" class="form-inline" >
- <el-form-item prop="queryType">
- <el-select v-model="requestParams.queryParam.queryType" placeholder="选择类型" class="type-select" >
- <el-option
- v-for="item in queryTypeSelect"
- :key="item.value"
- :label="item.label"
- :value="item.value"
- />
- </el-select>
- <el-input v-model="requestParams.queryParam.queryTypeContent" clearable placeholder="请输入搜索关键字"
- @keyup.enter="queryLoginLogPage" :disabled="requestParams.queryParam.queryType === ''" />
- </el-form-item>
- <el-form-item label="终端类型" prop="device">
- <el-select v-model="requestParams.queryParam.device" placeholder="请选择终端类型" clearable>
- <el-option :label="item.label" :value="item.value" v-for="item in deviceList" :key="item.value" />
- </el-select>
- </el-form-item>
- <el-form-item label="登录时间" prop="date">
- <el-date-picker
- v-model="requestParams.queryParam.date"
- type="daterange"
- placeholder="请选择登录时间"
- range-separator="~"
- start-placeholder="开始时间"
- end-placeholder="结束时间"
- :disabled-date="disabledDate"
- clearable />
- </el-form-item>
- <el-form-item label="请选择组织:" label-position="left" prop="deptId">
- <el-tree-select type="daterange" range-separator="To" start-placeholder="开始时间" end-placeholder="结束时间"
- v-model="requestParams.queryParam.deptId" :data="departmentList" :render-after-expand="false"
- :default-expand-all="true" check-strictly placeholder="请选择组织" class="protocal-select" />
- </el-form-item>
- <el-form-item>
- <el-button type="primary" :icon="Search" @click="queryLoginLogPage">查询</el-button>
- <el-button :icon="Refresh" @click="hanleResetForm(searchFormRef)">重置</el-button>
- </el-form-item>
- </el-form>
- </el-space>
- </el-card>
- <el-card>
- <template #header>
- <el-button type="primary" @click="handleExport()">导出数据</el-button>
- </template>
- <el-table height="calc(100vh - 500px)" :data="loginLogList" v-loading="loading">
- <el-table-column type="index" label="序号" width="100" />
- <el-table-column label="登录账号" prop="userName" />
- <el-table-column label="姓名" prop="realName" />
- <el-table-column label="组织" prop="deptName" />
- <el-table-column label="客户端" prop="device" >
- <template #default="{row}">
- <el-icon :size="24" color="#409eff" v-if="row.device === ClientTypeEnum.PC"><Platform /></el-icon>
- <el-icon :size="24" color="#409eff" v-else><Iphone /></el-icon>
- </template>
- </el-table-column>
- <el-table-column label="操作类型" prop="type" >
- <template #default="{row}">
- <el-tag
- :type="row.type === OperationTypeEnum.LOGIN ? 'success' : 'danger'"
- round
- >
- {{ row.type === OperationTypeEnum.LOGIN ? '登录': '登出' }}
- </el-tag>
- </template>
- </el-table-column>
- <el-table-column label="操作结果" prop="loginStatus" >
- <template #default="{ row }">
- <el-icon :size="24" color="#67C23A" v-if="row.loginStatus === LoginStatusEnum.SUCCESS"><SuccessFilled /></el-icon>
- <el-icon :size="24" color="#F56C6C" v-else><CircleCloseFilled /></el-icon>
- </template>
- </el-table-column>
- <el-table-column label="登录IP" prop="loginIp" />
- <el-table-column label="操作时间" prop="createdAt" />
- </el-table>
- <section class="mt-4 flex justify-end">
- <el-pagination background layout="total, sizes, prev, pager, next" :page-sizes="[10, 30, 50]" :total="total"
- v-model:page-size="requestParams.pageSize" v-model:current-page="requestParams.pageNumber"
- @change="queryLoginLogPage" />
- </section>
- </el-card>
- </div>
- </template>
- <script setup lang="ts">
- import { ref, onMounted } from 'vue';
- import { Search, Refresh, SuccessFilled, CircleCloseFilled, Platform, Iphone } from '@element-plus/icons-vue';
- import { getAllDepartments } from '@/api/auth/dept';
- import type { FormInstance } from 'element-plus'
- import { OptionsProps, deviceList, queryTypeSelect, LoginStatusEnum, OperationTypeEnum, ClientTypeEnum } from '@/types/log/constants';
- import useSceneInfos from '@/hooks/useSceneInfos';
- import useLoginLogQuery from '../hooks/useLoginLogQuery';
- import { ElMessage, ElMessageBox } from 'element-plus';
- import { exportLoginLog } from '@/api/system/log';
- import { downloadByData } from '@/utils/file/download';
- const sceneInfos = useSceneInfos();
- const { calculateTreeData } = sceneInfos;
- const { requestParams, total, loginLogList, queryLoginLogPage, loading, resetRequestParams } = useLoginLogQuery();
- const departmentList = ref<OptionsProps[]>([]);
- onMounted(async () => {
- queryLoginLogPage();
- getAllDepartments().then((res) => {
- departmentList.value = calculateTreeData(
- res,
- { level: 3, valueKey: 'id', labelKey: 'deptName' },
- 1,
- );
- });
- });
- /* 导出数据 */
- const handleExport = () => {
- ElMessageBox.confirm('确定导出所查询数据?', '导出', {
- confirmButtonText: '确定',
- showCancelButton: true,
- type: 'warning',
- })
- .then(() => {
- exportLoginLog(requestParams).then(async (responnse) => {
- if (!responnse) {
- throw new Error('下载文件失败');
- }
- downloadByData(responnse, '登录日志.xlsx');
- ElMessage.success('下载文件成功');
- });
- })
- .catch(() => {
- ElMessage({
- type: 'info',
- message: '取消导出',
- });
- });
- }
- /* 重置 */
- const searchFormRef = ref<FormInstance>()
- const hanleResetForm = (formEl: FormInstance | undefined) => {
- if (!formEl) return
- resetRequestParams();
- formEl.resetFields();
- queryLoginLogPage();
- }
- /* 设置今天之后的时间不可选 */
- const disabledDate = (time) => {
- return time.getTime() > Date.now();
- }
- </script>
- <style scoped lang="scss">
- .form-inline .el-input {
- --el-input-width: 160px;
- }
- .form-inline .el-select {
- --el-select-width: 160px;
- }
- </style>
|