mirror of
				https://github.com/continew-org/continew-admin.git
				synced 2025-11-04 09:01:37 +08:00 
			
		
		
		
	重构:重构在线用户前端代码
This commit is contained in:
		@@ -1,5 +1,7 @@
 | 
				
			|||||||
import axios from 'axios';
 | 
					import axios from "axios";
 | 
				
			||||||
import qs from 'query-string';
 | 
					import qs from "query-string";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const BASE_URL = "/monitor/online/user";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface OnlineUserRecord {
 | 
					export interface OnlineUserRecord {
 | 
				
			||||||
  token: string;
 | 
					  token: string;
 | 
				
			||||||
@@ -11,25 +13,26 @@ export interface OnlineUserRecord {
 | 
				
			|||||||
  loginTime: string;
 | 
					  loginTime: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface OnlineUserParams extends Partial<OnlineUserRecord> {
 | 
					export interface OnlineUserParam extends Partial<OnlineUserRecord> {
 | 
				
			||||||
  page: number;
 | 
					  page: number;
 | 
				
			||||||
  size: number;
 | 
					  size: number;
 | 
				
			||||||
  sort: Array<string>;
 | 
					  sort: Array<string>;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface OnlineUserListRes {
 | 
					export interface OnlineUserListRes {
 | 
				
			||||||
  list: OnlineUserRecord[];
 | 
					  list: OnlineUserRecord[];
 | 
				
			||||||
  total: number;
 | 
					  total: number;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function getOnlineUserList(params: OnlineUserParams) {
 | 
					export function listOnlineUser(params: OnlineUserParam) {
 | 
				
			||||||
  return axios.get<OnlineUserListRes>('/monitor/online/user', {
 | 
					  return axios.get<OnlineUserListRes>(BASE_URL, {
 | 
				
			||||||
    params,
 | 
					    params,
 | 
				
			||||||
    paramsSerializer: (obj) => {
 | 
					    paramsSerializer: (obj) => {
 | 
				
			||||||
      return qs.stringify(obj);
 | 
					      return qs.stringify(obj);
 | 
				
			||||||
    },
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function kickout(token: string) {
 | 
					export function kickout(token: string) {
 | 
				
			||||||
  return axios.delete(`/monitor/online/user/${token}`);
 | 
					  return axios.delete(`${BASE_URL}/${token}`);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1,11 +1,10 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <a-range-picker
 | 
					  <a-range-picker
 | 
				
			||||||
    style="width: 100%"
 | 
					    :placeholder="placeholder"
 | 
				
			||||||
    :shortcuts="shortcuts"
 | 
					 | 
				
			||||||
    shortcuts-position="left"
 | 
					 | 
				
			||||||
    :format="format"
 | 
					    :format="format"
 | 
				
			||||||
    :show-time="showTime"
 | 
					    :show-time="showTime"
 | 
				
			||||||
    :placeholder="placeholder"
 | 
					    :shortcuts="shortcuts"
 | 
				
			||||||
 | 
					    shortcuts-position="left"
 | 
				
			||||||
  />
 | 
					  />
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,65 +2,85 @@
 | 
				
			|||||||
  <div class="container">
 | 
					  <div class="container">
 | 
				
			||||||
    <Breadcrumb :items="['menu.monitor', 'menu.online.user.list']" />
 | 
					    <Breadcrumb :items="['menu.monitor', 'menu.online.user.list']" />
 | 
				
			||||||
    <a-card class="general-card" :title="$t('menu.online.user.list')">
 | 
					    <a-card class="general-card" :title="$t('menu.online.user.list')">
 | 
				
			||||||
      <a-row style="margin-bottom: 15px">
 | 
					      <!-- 头部区域 -->
 | 
				
			||||||
        <a-col :span="24">
 | 
					      <div class="head-container">
 | 
				
			||||||
          <a-form ref="queryFormRef" :model="queryFormData" layout="inline">
 | 
					        <!-- 搜索栏 -->
 | 
				
			||||||
 | 
					        <div class="query-container">
 | 
				
			||||||
 | 
					          <a-form ref="queryRef" :model="queryParams" layout="inline">
 | 
				
			||||||
            <a-form-item field="nickname" hide-label>
 | 
					            <a-form-item field="nickname" hide-label>
 | 
				
			||||||
              <a-input
 | 
					              <a-input
 | 
				
			||||||
                v-model="queryFormData.nickname"
 | 
					                v-model="queryParams.nickname"
 | 
				
			||||||
                placeholder="输入用户昵称搜索"
 | 
					                placeholder="输入用户昵称搜索"
 | 
				
			||||||
                allow-clear
 | 
					                allow-clear
 | 
				
			||||||
                style="width: 150px;"
 | 
					                style="width: 150px;"
 | 
				
			||||||
                @press-enter="toQuery"
 | 
					                @press-enter="handleQuery"
 | 
				
			||||||
              />
 | 
					              />
 | 
				
			||||||
            </a-form-item>
 | 
					            </a-form-item>
 | 
				
			||||||
            <a-form-item field="loginTime" hide-label>
 | 
					            <a-form-item field="loginTime" hide-label>
 | 
				
			||||||
              <date-range-picker v-model="queryFormData.loginTime" />
 | 
					              <date-range-picker v-model="queryParams.loginTime" />
 | 
				
			||||||
 | 
					            </a-form-item>
 | 
				
			||||||
 | 
					            <a-form-item hide-label>
 | 
				
			||||||
 | 
					              <a-space>
 | 
				
			||||||
 | 
					                <a-button type="primary" @click="handleQuery">
 | 
				
			||||||
 | 
					                  <template #icon><icon-search /></template>查询
 | 
				
			||||||
 | 
					                </a-button>
 | 
				
			||||||
 | 
					                <a-button @click="resetQuery">
 | 
				
			||||||
 | 
					                  <template #icon><icon-refresh /></template>重置
 | 
				
			||||||
 | 
					                </a-button>
 | 
				
			||||||
 | 
					              </a-space>
 | 
				
			||||||
            </a-form-item>
 | 
					            </a-form-item>
 | 
				
			||||||
            <a-button type="primary" @click="toQuery">
 | 
					 | 
				
			||||||
              <template #icon>
 | 
					 | 
				
			||||||
                <icon-search />
 | 
					 | 
				
			||||||
              </template>
 | 
					 | 
				
			||||||
              查询
 | 
					 | 
				
			||||||
            </a-button>
 | 
					 | 
				
			||||||
            <a-button @click="resetQuery">
 | 
					 | 
				
			||||||
              <template #icon>
 | 
					 | 
				
			||||||
                <icon-refresh />
 | 
					 | 
				
			||||||
              </template>
 | 
					 | 
				
			||||||
              重置
 | 
					 | 
				
			||||||
            </a-button>
 | 
					 | 
				
			||||||
          </a-form>
 | 
					          </a-form>
 | 
				
			||||||
        </a-col>
 | 
					        </div>
 | 
				
			||||||
      </a-row>
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <!-- 列表区域 -->
 | 
				
			||||||
      <a-table
 | 
					      <a-table
 | 
				
			||||||
        :columns="columns"
 | 
					        ref="tableRef"
 | 
				
			||||||
        :data="renderData"
 | 
					        row-key="token"
 | 
				
			||||||
        :pagination="paginationProps"
 | 
					        :loading="loading"
 | 
				
			||||||
        row-key="logId"
 | 
					        :pagination="{
 | 
				
			||||||
 | 
					          showTotal: true,
 | 
				
			||||||
 | 
					          showPageSize: true,
 | 
				
			||||||
 | 
					          total: total,
 | 
				
			||||||
 | 
					          current: queryParams.page,
 | 
				
			||||||
 | 
					        }"
 | 
				
			||||||
 | 
					        :data="onlineUserList"
 | 
				
			||||||
        :bordered="false"
 | 
					        :bordered="false"
 | 
				
			||||||
        :stripe="true"
 | 
					        :stripe="true"
 | 
				
			||||||
        :loading="loading"
 | 
					 | 
				
			||||||
        size="large"
 | 
					        size="large"
 | 
				
			||||||
        @page-change="handlePageChange"
 | 
					        @page-change="handlePageChange"
 | 
				
			||||||
        @page-size-change="handlePageSizeChange"
 | 
					        @page-size-change="handlePageSizeChange"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <template #index="{ rowIndex }">
 | 
					        <template #columns>
 | 
				
			||||||
          {{ rowIndex + 1 + (pagination.current - 1) * pagination.pageSize }}
 | 
					          <a-table-column title="序号">
 | 
				
			||||||
        </template>
 | 
					            <template #cell="{ rowIndex }">
 | 
				
			||||||
        <template #nickname="{ record }">
 | 
					              {{ rowIndex + 1 + (queryParams.page - 1) * queryParams.size }}
 | 
				
			||||||
          {{ record.nickname }}({{record.username}})
 | 
					            </template>
 | 
				
			||||||
        </template>
 | 
					          </a-table-column>
 | 
				
			||||||
        <template #operations="{ record }">
 | 
					          <a-table-column title="用户昵称">
 | 
				
			||||||
          <a-button
 | 
					            <template #cell="{ record }">
 | 
				
			||||||
            v-permission="['admin']"
 | 
					              {{ record.nickname }}({{record.username}})
 | 
				
			||||||
            type="text"
 | 
					            </template>
 | 
				
			||||||
            size="small"
 | 
					          </a-table-column>
 | 
				
			||||||
            :title="currentToken === record.token ? '不能强退当前登录' : ''"
 | 
					          <a-table-column title="登录 IP" data-index="clientIp" />
 | 
				
			||||||
            :disabled="currentToken === record.token"
 | 
					          <a-table-column title="登录地点" data-index="location" />
 | 
				
			||||||
            @click="handleClick(record.token)"
 | 
					          <a-table-column title="浏览器" data-index="browser" />
 | 
				
			||||||
          >
 | 
					          <a-table-column title="登录时间" data-index="loginTime" />
 | 
				
			||||||
            强退
 | 
					          <a-table-column title="操作" align="center">
 | 
				
			||||||
          </a-button>
 | 
					            <template #cell="{ record }">
 | 
				
			||||||
 | 
					              <a-popconfirm content="确定要强退该用户吗?" type="warning" @ok="handleKickout(record.token)">
 | 
				
			||||||
 | 
					                <a-button
 | 
				
			||||||
 | 
					                  v-permission="['admin']"
 | 
				
			||||||
 | 
					                  type="text"
 | 
				
			||||||
 | 
					                  size="small"
 | 
				
			||||||
 | 
					                  :disabled="currentToken === record.token"
 | 
				
			||||||
 | 
					                  :title="currentToken === record.token ? '不能强退当前登录用户' : ''"
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  <template #icon><icon-delete /></template>强退
 | 
				
			||||||
 | 
					                </a-button>
 | 
				
			||||||
 | 
					              </a-popconfirm>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					          </a-table-column>
 | 
				
			||||||
        </template>
 | 
					        </template>
 | 
				
			||||||
      </a-table>
 | 
					      </a-table>
 | 
				
			||||||
    </a-card>
 | 
					    </a-card>
 | 
				
			||||||
@@ -68,116 +88,94 @@
 | 
				
			|||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script lang="ts" setup>
 | 
					<script lang="ts" setup>
 | 
				
			||||||
  import { computed, ref, reactive } from 'vue';
 | 
					  import { getCurrentInstance, ref, toRefs, reactive } from 'vue';
 | 
				
			||||||
  import useLoading from '@/hooks/loading';
 | 
					  import {
 | 
				
			||||||
  import { Message } from '@arco-design/web-vue';
 | 
					    listOnlineUser,
 | 
				
			||||||
  import { getOnlineUserList, OnlineUserRecord, OnlineUserParams, kickout } from '@/api/monitor/online';
 | 
					    OnlineUserRecord,
 | 
				
			||||||
  import { Pagination } from '@/types/global';
 | 
					    OnlineUserParam,
 | 
				
			||||||
  import { PaginationProps } from '@arco-design/web-vue';
 | 
					    kickout
 | 
				
			||||||
  import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
 | 
					  } from '@/api/monitor/online';
 | 
				
			||||||
  import { FormInstance } from '@arco-design/web-vue/es/form';
 | 
					 | 
				
			||||||
  import { getToken } from '@/utils/auth';
 | 
					  import { getToken } from '@/utils/auth';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const { loading, setLoading } = useLoading(true);
 | 
					  const { proxy } = getCurrentInstance() as any;
 | 
				
			||||||
  const currentToken = computed(() => getToken());
 | 
					 | 
				
			||||||
  const queryFormRef = ref<FormInstance>();
 | 
					 | 
				
			||||||
  const queryFormData = ref({
 | 
					 | 
				
			||||||
    nickname: '',
 | 
					 | 
				
			||||||
    loginTime: [],
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // 查询
 | 
					  const onlineUserList = ref<OnlineUserRecord[]>([]);
 | 
				
			||||||
  const toQuery = () => {
 | 
					  const total = ref(0);
 | 
				
			||||||
    fetchData({
 | 
					  const loading = ref(false);
 | 
				
			||||||
      page: pagination.current,
 | 
					  const currentToken = getToken();
 | 
				
			||||||
      size: pagination.pageSize,
 | 
					
 | 
				
			||||||
 | 
					  const data = reactive({
 | 
				
			||||||
 | 
					    // 查询参数
 | 
				
			||||||
 | 
					    queryParams: {
 | 
				
			||||||
 | 
					      nickname: undefined,
 | 
				
			||||||
 | 
					      loginTime: undefined,
 | 
				
			||||||
 | 
					      page: 1,
 | 
				
			||||||
 | 
					      size: 10,
 | 
				
			||||||
      sort: ['createTime,desc'],
 | 
					      sort: ['createTime,desc'],
 | 
				
			||||||
      ...queryFormData.value,
 | 
					    },
 | 
				
			||||||
    } as unknown as OnlineUserParams);
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // 重置
 | 
					 | 
				
			||||||
  const resetQuery = async () => {
 | 
					 | 
				
			||||||
    await queryFormRef.value?.resetFields();
 | 
					 | 
				
			||||||
    await fetchData();
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const renderData = ref<OnlineUserRecord[]>([]);
 | 
					 | 
				
			||||||
  const basePagination: Pagination = {
 | 
					 | 
				
			||||||
    current: 1,
 | 
					 | 
				
			||||||
    pageSize: 10,
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  const pagination = reactive({
 | 
					 | 
				
			||||||
    ...basePagination,
 | 
					 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  const paginationProps = computed((): PaginationProps => {
 | 
					  const { queryParams } = toRefs(data);
 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
      showTotal: true,
 | 
					 | 
				
			||||||
      showPageSize: true,
 | 
					 | 
				
			||||||
      total: pagination.total,
 | 
					 | 
				
			||||||
      current: pagination.current,
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
  const columns = computed<TableColumnData[]>(() => [
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      title: '序号',
 | 
					 | 
				
			||||||
      dataIndex: 'index',
 | 
					 | 
				
			||||||
      slotName: 'index',
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      title: '用户昵称',
 | 
					 | 
				
			||||||
      dataIndex: 'nickname',
 | 
					 | 
				
			||||||
      slotName: 'nickname',
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      title: '登录 IP',
 | 
					 | 
				
			||||||
      dataIndex: 'clientIp',
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      title: '登录地点',
 | 
					 | 
				
			||||||
      dataIndex: 'location',
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      title: '浏览器',
 | 
					 | 
				
			||||||
      dataIndex: 'browser',
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      title: '登录时间',
 | 
					 | 
				
			||||||
      dataIndex: 'loginTime',
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      title: '操作',
 | 
					 | 
				
			||||||
      slotName: 'operations',
 | 
					 | 
				
			||||||
      align: 'center',
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  ]);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // 分页查询列表
 | 
					  /**
 | 
				
			||||||
  const fetchData = async (
 | 
					   * 查询列表
 | 
				
			||||||
    params: OnlineUserParams = { page: 1, size: 10, sort: ['createTime,desc'] }
 | 
					   *
 | 
				
			||||||
  ) => {
 | 
					   * @param params 查询参数
 | 
				
			||||||
    setLoading(true);
 | 
					   */
 | 
				
			||||||
    try {
 | 
					  const getList = (params: OnlineUserParam = { ...queryParams.value }) => {
 | 
				
			||||||
      const { data } = await getOnlineUserList(params);
 | 
					    loading.value = true;
 | 
				
			||||||
      renderData.value = data.list;
 | 
					    listOnlineUser(params).then((res) => {
 | 
				
			||||||
      pagination.current = params.page;
 | 
					      onlineUserList.value = res.data.list;
 | 
				
			||||||
      pagination.total = data.total;
 | 
					      total.value = res.data.total;
 | 
				
			||||||
    } finally {
 | 
					      loading.value = false;
 | 
				
			||||||
      setLoading(false);
 | 
					    });
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					  getList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 强退
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param token Token
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  const handleKickout = (token: string) => {
 | 
				
			||||||
 | 
					    kickout(token).then((res) => {
 | 
				
			||||||
 | 
					      getList();
 | 
				
			||||||
 | 
					      proxy.$message.success(res.msg);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 查询
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  const handleQuery = () => {
 | 
				
			||||||
 | 
					    getList();
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 重置
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  const resetQuery = () => {
 | 
				
			||||||
 | 
					    proxy.$refs.queryRef.resetFields();
 | 
				
			||||||
 | 
					    handleQuery();
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 切换页码
 | 
				
			||||||
 | 
					   *
 | 
				
			||||||
 | 
					   * @param current 页码
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
  const handlePageChange = (current: number) => {
 | 
					  const handlePageChange = (current: number) => {
 | 
				
			||||||
    fetchData({ page: current, size: pagination.pageSize, sort: ['createTime,desc'] });
 | 
					    queryParams.value.page = current;
 | 
				
			||||||
 | 
					    getList();
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  const handlePageSizeChange = (pageSize: number) => {
 | 
					 | 
				
			||||||
    fetchData({ page: pagination.current, size: pageSize, sort: ['createTime,desc'] });
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  fetchData();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // 强退
 | 
					  /**
 | 
				
			||||||
  const handleClick = async (token: string) => {
 | 
					   * 切换每页条数
 | 
				
			||||||
    const res = await kickout(token);
 | 
					   *
 | 
				
			||||||
    if (res.success) Message.success(res.msg);
 | 
					   * @param pageSize 每页条数
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  const handlePageSizeChange = (pageSize: number) => {
 | 
				
			||||||
 | 
					    queryParams.value.size = pageSize;
 | 
				
			||||||
 | 
					    getList();
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -190,6 +188,9 @@
 | 
				
			|||||||
<style scoped lang="less">
 | 
					<style scoped lang="less">
 | 
				
			||||||
  .container {
 | 
					  .container {
 | 
				
			||||||
    padding: 0 20px 20px 20px;
 | 
					    padding: 0 20px 20px 20px;
 | 
				
			||||||
 | 
					    .head-container {
 | 
				
			||||||
 | 
					      margin-bottom: 16px
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  :deep(.arco-table-th) {
 | 
					  :deep(.arco-table-th) {
 | 
				
			||||||
    &:last-child {
 | 
					    &:last-child {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user