fix: 🧩 用户登录日志修改
This commit is contained in:
parent
861ddfed9e
commit
0a7237d733
|
@ -212,7 +212,5 @@ docker build -f Dockerfile -t bunny_auth_web:1.0.0 . && docker run -p 80:80 --na
|
|||
|
||||
# 展望未来
|
||||
|
||||
1. 数据库备份时上传到Minio
|
||||
2. 数据库备份后可恢复
|
||||
3. 定时邮件发送参数可在前端配置,动态形式
|
||||
4. 首页看板内容
|
||||
1. 定时邮件发送参数可在前端配置,动态形式
|
||||
2. 首页看板内容
|
|
@ -6,7 +6,7 @@ export const fetchGetFilesList = (data: any) => {
|
|||
return http.request<BaseResult<ResultTable>>('get', `files/getFilesList/${data.currentPage}/${data.pageSize}`, { params: data });
|
||||
};
|
||||
|
||||
/** 系统文件管理---根据I下载系统文件d */
|
||||
/** 系统文件管理---根据Id下载系统文件 */
|
||||
export const downloadFilesByFileId = (data: any) => {
|
||||
return http.request<any>('get', `files/downloadFilesByFileId/${data.id}`, { responseType: 'blob' });
|
||||
};
|
||||
|
|
|
@ -35,5 +35,5 @@ export const userStatus = [
|
|||
/**
|
||||
* * 分页默认数组个数
|
||||
*/
|
||||
export const pageSizes: number[] = [15, 30, 50, 100, 150, 200, 300];
|
||||
export const pageSizes: number[] = [15, 30, 50, 100, 150];
|
||||
export const tableSelectButtonClass = computed(() => ['!h-[20px]', 'reset-margin', '!text-gray-500', 'dark:!text-white', 'dark:hover:!text-primary']);
|
||||
|
|
|
@ -31,8 +31,8 @@ export const useEmailTemplateStore = defineStore('emailTemplateStore', {
|
|||
// 分页查询结果
|
||||
pagination: {
|
||||
currentPage: 1,
|
||||
pageSize: 150,
|
||||
total: 100,
|
||||
pageSize: 30,
|
||||
total: 1,
|
||||
pageSizes,
|
||||
},
|
||||
// 加载
|
||||
|
|
|
@ -26,8 +26,8 @@ export const useEmailUsersStore = defineStore('emailUsersStore', {
|
|||
// 分页查询结果
|
||||
pagination: {
|
||||
currentPage: 1,
|
||||
pageSize: 150,
|
||||
total: 100,
|
||||
pageSize: 30,
|
||||
total: 1,
|
||||
pageSizes,
|
||||
},
|
||||
// 加载
|
||||
|
|
|
@ -22,8 +22,8 @@ export const useMenuIconStore = defineStore('menuIconStore', {
|
|||
// 分页查询结果
|
||||
pagination: {
|
||||
currentPage: 1,
|
||||
pageSize: 150,
|
||||
total: 100,
|
||||
pageSize: 30,
|
||||
total: 1,
|
||||
pageSizes,
|
||||
},
|
||||
// 加载
|
||||
|
|
|
@ -19,7 +19,7 @@ export const userI18nStore = defineStore('i18nStore', {
|
|||
pagination: {
|
||||
currentPage: 1,
|
||||
pageSize: 150,
|
||||
total: 100,
|
||||
total: 1,
|
||||
pageSizes,
|
||||
background: true,
|
||||
},
|
||||
|
|
|
@ -14,8 +14,8 @@ export const userI18nTypeStore = defineStore('i18nTypeStore', {
|
|||
// ? 分页查询结果
|
||||
pagination: {
|
||||
currentPage: 1,
|
||||
pageSize: 150,
|
||||
total: 100,
|
||||
pageSize: 30,
|
||||
total: 1,
|
||||
pageSizes,
|
||||
},
|
||||
// 加载
|
||||
|
|
|
@ -30,8 +30,8 @@ export const useFilesStore = defineStore('filesStore', {
|
|||
// 分页查询结果
|
||||
pagination: {
|
||||
currentPage: 1,
|
||||
pageSize: 150,
|
||||
total: 100,
|
||||
pageSize: 30,
|
||||
total: 1,
|
||||
pageSizes,
|
||||
},
|
||||
// 加载
|
||||
|
|
|
@ -30,8 +30,8 @@ export const useQuartzExecuteLogStore = defineStore('quartzExecuteLogStore', {
|
|||
// 分页查询结果
|
||||
pagination: {
|
||||
currentPage: 1,
|
||||
pageSize: 150,
|
||||
total: 100,
|
||||
pageSize: 30,
|
||||
total: 1,
|
||||
pageSizes,
|
||||
},
|
||||
// 加载
|
||||
|
|
|
@ -14,12 +14,8 @@ export const useUserLoginLogStore = defineStore('userLoginLogStore', {
|
|||
datalist: [],
|
||||
// 查询表单
|
||||
form: {
|
||||
// 用户Id
|
||||
userId: undefined,
|
||||
// 用户名
|
||||
username: undefined,
|
||||
// 登录token
|
||||
token: undefined,
|
||||
// 登录Ip
|
||||
ipAddress: undefined,
|
||||
// 登录Ip归属地
|
||||
|
@ -30,18 +26,12 @@ export const useUserLoginLogStore = defineStore('userLoginLogStore', {
|
|||
type: undefined,
|
||||
// 标识客户端是否是通过Ajax发送请求的
|
||||
xRequestedWith: undefined,
|
||||
// 用户代理的品牌和版本
|
||||
secChUa: undefined,
|
||||
// 用户代理是否在手机设备上运行
|
||||
secChUaMobile: undefined,
|
||||
// 用户代理的底层操作系统/平台
|
||||
secChUaPlatform: undefined,
|
||||
},
|
||||
// 分页查询结果
|
||||
pagination: {
|
||||
currentPage: 1,
|
||||
pageSize: 150,
|
||||
total: 100,
|
||||
pageSize: 30,
|
||||
total: 1,
|
||||
pageSizes,
|
||||
},
|
||||
// 加载
|
||||
|
|
|
@ -34,8 +34,8 @@ export const useSchedulersStore = defineStore('schedulersStore', {
|
|||
// 分页查询结果
|
||||
pagination: {
|
||||
currentPage: 1,
|
||||
pageSize: 150,
|
||||
total: 100,
|
||||
pageSize: 30,
|
||||
total: 1,
|
||||
pageSizes,
|
||||
},
|
||||
// 加载
|
||||
|
|
|
@ -24,8 +24,8 @@ export const useSchedulersGroupStore = defineStore('schedulersGroupStore', {
|
|||
// 分页查询结果
|
||||
pagination: {
|
||||
currentPage: 1,
|
||||
pageSize: 150,
|
||||
total: 100,
|
||||
pageSize: 30,
|
||||
total: 1,
|
||||
pageSizes,
|
||||
},
|
||||
// 加载
|
||||
|
|
|
@ -45,7 +45,7 @@ export const useAdminUserStore = defineStore('adminUserStore', {
|
|||
pagination: {
|
||||
currentPage: 1,
|
||||
pageSize: 150,
|
||||
total: 100,
|
||||
total: 1,
|
||||
pageSizes,
|
||||
},
|
||||
// 加载
|
||||
|
|
|
@ -26,8 +26,8 @@ export const useDeptStore = defineStore('deptStore', {
|
|||
// 分页查询结果
|
||||
pagination: {
|
||||
currentPage: 1,
|
||||
pageSize: 150,
|
||||
total: 100,
|
||||
pageSize: 30,
|
||||
total: 1,
|
||||
pageSizes,
|
||||
},
|
||||
// 加载
|
||||
|
|
|
@ -26,8 +26,8 @@ export const usePowerStore = defineStore('powerStore', {
|
|||
// 分页查询结果
|
||||
pagination: {
|
||||
currentPage: 1,
|
||||
pageSize: 150,
|
||||
total: 100,
|
||||
pageSize: 30,
|
||||
total: 1,
|
||||
pageSizes,
|
||||
},
|
||||
// 加载
|
||||
|
|
|
@ -24,8 +24,8 @@ export const useRoleStore = defineStore('roleStore', {
|
|||
// 分页查询结果
|
||||
pagination: {
|
||||
currentPage: 1,
|
||||
pageSize: 150,
|
||||
total: 100,
|
||||
pageSize: 30,
|
||||
total: 1,
|
||||
pageSizes,
|
||||
},
|
||||
// 加载
|
||||
|
|
|
@ -10,33 +10,19 @@ import AccountManagementIcon from '@iconify-icons/ri/profile-line';
|
|||
import AccountManagement from '@/views/account-settings/account-management.vue';
|
||||
|
||||
export const columns: TableColumnList = [
|
||||
// { type: 'index', index: (index: number) => index + 1, label: '序号', width: 60 },
|
||||
// // 用户名
|
||||
// { label: $t('userLoginLog_username'), prop: 'username', width: 180 },
|
||||
{ type: 'index', index: (index: number) => index + 1, label: '序号', width: 60 },
|
||||
// 用户名
|
||||
{ label: $t('userLoginLog_username'), prop: 'username', width: 180 },
|
||||
// // 登录Ip
|
||||
// { label: $t('userLoginLog_ipAddress'), prop: 'ipAddress', width: 140 },
|
||||
// 登录Ip归属地
|
||||
{ label: $t('userLoginLog_ipRegion'), prop: 'ipRegion' },
|
||||
// // 登录时代理
|
||||
// { label: $t('userLoginLog_userAgent'), prop: 'userAgent', width: 200 },
|
||||
// { label: $t('userLoginLog_userAgent'), prop: 'userAgent' },
|
||||
// 操作类型
|
||||
{ label: $t('userLoginLog_type'), prop: 'type' },
|
||||
// // 标识客户端是否是通过Ajax发送请求的
|
||||
// { label: $t('userLoginLog_xRequestedWith'), prop: 'xRequestedWith', width: 150 },
|
||||
// 用户代理的品牌和版本
|
||||
{
|
||||
label: $t('userLoginLog_secChUa'),
|
||||
prop: 'secChUa',
|
||||
formatter: ({ secChUa }) => {
|
||||
const regex = /"([^"]+)";/;
|
||||
const match = regex.exec(secChUa);
|
||||
return match ? match[1] : secChUa;
|
||||
},
|
||||
},
|
||||
// // 用户代理是否在手机设备上运行
|
||||
// { label: $t('userLoginLog_secChUaMobile'), prop: 'secChUaMobile', width: 130 },
|
||||
// 用户代理的底层操作系统/平台
|
||||
{ label: $t('userLoginLog_secChUaPlatform'), prop: 'secChUaPlatform' },
|
||||
// 创建时间也就是操作时间
|
||||
{
|
||||
label: $t('op_time'),
|
||||
|
|
|
@ -15,7 +15,9 @@ export const deleteIds = ref([]);
|
|||
*/
|
||||
export async function onSearch() {
|
||||
menuIconStore.loading = true;
|
||||
|
||||
await menuIconStore.getMenuIconList();
|
||||
|
||||
menuIconStore.loading = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,21 +60,11 @@ onMounted(() => {
|
|||
<template>
|
||||
<div class="main">
|
||||
<el-form ref="formRef" :inline="true" :model="userLoginLogStore.form" class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px] overflow-auto">
|
||||
<!-- 用户Id -->
|
||||
<el-form-item :label="$t('userLoginLog_userId')" prop="userId">
|
||||
<el-input v-model="userLoginLogStore.form.userId" :placeholder="`${$t('input')}${$t('userLoginLog_userId')}`" class="!w-[180px]" clearable />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 用户名 -->
|
||||
<el-form-item :label="$t('userLoginLog_username')" prop="username">
|
||||
<el-input v-model="userLoginLogStore.form.username" :placeholder="`${$t('input')}${$t('userLoginLog_username')}`" class="!w-[180px]" clearable />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 登录token -->
|
||||
<el-form-item :label="$t('userLoginLog_token')" prop="token">
|
||||
<el-input v-model="userLoginLogStore.form.token" :placeholder="`${$t('input')}${$t('userLoginLog_token')}`" class="!w-[180px]" clearable />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 登录Ip -->
|
||||
<el-form-item :label="$t('userLoginLog_ipAddress')" prop="ipAddress">
|
||||
<el-input v-model="userLoginLogStore.form.ipAddress" :placeholder="`${$t('input')}${$t('userLoginLog_ipAddress')}`" class="!w-[180px]" clearable />
|
||||
|
@ -85,11 +75,6 @@ onMounted(() => {
|
|||
<el-input v-model="userLoginLogStore.form.ipRegion" :placeholder="`${$t('input')}${$t('userLoginLog_ipRegion')}`" class="!w-[180px]" clearable />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 登录时代理 -->
|
||||
<el-form-item :label="$t('userLoginLog_userAgent')" prop="userAgent">
|
||||
<el-input v-model="userLoginLogStore.form.userAgent" :placeholder="`${$t('input')}${$t('userLoginLog_userAgent')}`" class="!w-[180px]" clearable />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 操作类型 -->
|
||||
<el-form-item :label="$t('userLoginLog_type')" prop="type">
|
||||
<el-input v-model="userLoginLogStore.form.type" :placeholder="`${$t('input')}${$t('userLoginLog_type')}`" class="!w-[180px]" clearable />
|
||||
|
@ -100,21 +85,6 @@ onMounted(() => {
|
|||
<el-input v-model="userLoginLogStore.form.xRequestedWith" :placeholder="`${$t('input')}${$t('userLoginLog_xRequestedWith')}`" class="!w-[180px]" clearable />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 用户代理的品牌和版本 -->
|
||||
<el-form-item :label="$t('userLoginLog_secChUa')" prop="secChUa">
|
||||
<el-input v-model="userLoginLogStore.form.secChUa" :placeholder="`${$t('input')}${$t('userLoginLog_secChUa')}`" class="!w-[180px]" clearable />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 用户代理是否在手机设备上运行 -->
|
||||
<el-form-item :label="$t('userLoginLog_secChUaMobile')" prop="secChUaMobile">
|
||||
<el-input v-model="userLoginLogStore.form.secChUaMobile" :placeholder="`${$t('input')}${$t('userLoginLog_secChUaMobile')}`" class="!w-[180px]" clearable />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 用户代理的底层操作系统/平台 -->
|
||||
<el-form-item :label="$t('userLoginLog_secChUaPlatform')" prop="secChUaPlatform">
|
||||
<el-input v-model="userLoginLogStore.form.secChUaPlatform" :placeholder="`${$t('input')}${$t('userLoginLog_secChUaPlatform')}`" class="!w-[180px]" clearable />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button :icon="useRenderIcon('ri:search-line')" :loading="userLoginLogStore.loading" type="primary" @click="onSearch"> {{ $t('search') }} </el-button>
|
||||
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)"> {{ $t('buttons.reset') }}</el-button>
|
||||
|
|
|
@ -23,14 +23,6 @@ const props = withDefaults(defineProps<FormProps>(), {
|
|||
type: undefined,
|
||||
// 标识客户端是否是通过Ajax发送请求的
|
||||
xRequestedWith: undefined,
|
||||
// 用户代理的品牌和版本
|
||||
secChUa: undefined,
|
||||
// 用户代理的底层CPU架构位数
|
||||
secChUaBitness: undefined,
|
||||
// 用户代理是否在手机设备上运行
|
||||
secChUaMobile: undefined,
|
||||
// 用户代理的底层操作系统/平台
|
||||
secChUaPlatform: undefined,
|
||||
// 客户端连接到服务器的近似带宽
|
||||
downlink: undefined,
|
||||
}),
|
||||
|
@ -83,20 +75,5 @@ defineExpose({ formRef });
|
|||
<el-form-item :label="$t('userLoginLog_xRequestedWith')" prop="xRequestedWith">
|
||||
<el-input v-model="form.xRequestedWith" :placeholder="$t('input') + $t('userLoginLog_xRequestedWith')" autocomplete="off" type="text" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 用户代理的品牌和版本 -->
|
||||
<el-form-item :label="$t('userLoginLog_secChUa')" prop="secChUa">
|
||||
<el-input v-model="form.secChUa" :placeholder="$t('input') + $t('userLoginLog_secChUa')" autocomplete="off" type="text" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 用户代理是否在手机设备上运行 -->
|
||||
<el-form-item :label="$t('userLoginLog_secChUaMobile')" prop="secChUaMobile">
|
||||
<el-input v-model="form.secChUaMobile" :placeholder="$t('input') + $t('userLoginLog_secChUaMobile')" autocomplete="off" type="text" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 用户代理的底层操作系统/平台 -->
|
||||
<el-form-item :label="$t('userLoginLog_secChUaPlatform')" prop="secChUaPlatform">
|
||||
<el-input v-model="form.secChUaPlatform" :placeholder="$t('input') + $t('userLoginLog_secChUaPlatform')" autocomplete="off" type="text" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
|
|
@ -5,26 +5,18 @@ import { $t } from '@/plugins/i18n';
|
|||
export const columns: TableColumnList = [
|
||||
{ type: 'selection', align: 'left' },
|
||||
{ type: 'index', index: (index: number) => index + 1, label: '序号', width: 60 },
|
||||
// 用户Id
|
||||
{ label: $t('userLoginLog_userId'), prop: 'userId', width: 180 },
|
||||
// 用户名
|
||||
{ label: $t('userLoginLog_username'), prop: 'username', width: 180 },
|
||||
// 登录Ip
|
||||
{ label: $t('userLoginLog_ipAddress'), prop: 'ipAddress', width: 140 },
|
||||
{ label: $t('userLoginLog_ipAddress'), prop: 'ipAddress', width: 130 },
|
||||
// 登录Ip归属地
|
||||
{ label: $t('userLoginLog_ipRegion'), prop: 'ipRegion', width: 100 },
|
||||
// 登录时代理
|
||||
{ label: $t('userLoginLog_userAgent'), prop: 'userAgent', width: 200 },
|
||||
{ label: $t('userLoginLog_userAgent'), prop: 'userAgent' },
|
||||
// 操作类型
|
||||
{ label: $t('userLoginLog_type'), prop: 'type', width: 130 },
|
||||
// 标识客户端是否是通过Ajax发送请求的
|
||||
{ label: $t('userLoginLog_xRequestedWith'), prop: 'xRequestedWith', width: 150 },
|
||||
// 用户代理的品牌和版本
|
||||
{ label: $t('userLoginLog_secChUa'), prop: 'secChUa', width: 150 },
|
||||
// 用户代理是否在手机设备上运行
|
||||
{ label: $t('userLoginLog_secChUaMobile'), prop: 'secChUaMobile', width: 130 },
|
||||
// 用户代理的底层操作系统/平台
|
||||
{ label: $t('userLoginLog_secChUaPlatform'), prop: 'secChUaPlatform', width: 130 },
|
||||
// 登录token
|
||||
{ label: $t('userLoginLog_token'), prop: 'token', width: 200 },
|
||||
{ label: $t('table.updateTime'), prop: 'updateTime', sortable: true, width: 160 },
|
||||
|
|
|
@ -37,9 +37,6 @@ export function onView(row: any) {
|
|||
userAgent: row.userAgent,
|
||||
type: row.type,
|
||||
xRequestedWith: row.xRequestedWith,
|
||||
secChUa: row.secChUa,
|
||||
secChUaMobile: row.secChUaMobile,
|
||||
secChUaPlatform: row.secChUaPlatform,
|
||||
},
|
||||
},
|
||||
draggable: true,
|
||||
|
|
|
@ -17,14 +17,6 @@ export interface FormItemProps {
|
|||
type: string;
|
||||
// 标识客户端是否是通过Ajax发送请求的
|
||||
xRequestedWith: string;
|
||||
// 用户代理的品牌和版本
|
||||
secChUa: string;
|
||||
// 用户代理是否在手机设备上运行
|
||||
secChUaMobile: string;
|
||||
// 用户代理的设备模型
|
||||
secChUaModel: string;
|
||||
// 用户代理的底层操作系统/平台
|
||||
secChUaPlatform: string;
|
||||
}
|
||||
|
||||
// 添加或修改表单Props
|
||||
|
|
|
@ -1,213 +1,134 @@
|
|||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import ReCol from "@/components/MyCol";
|
||||
import { useDark } from "./utils";
|
||||
import WelcomeTable from "./components/table/index.vue";
|
||||
import { ReNormalCountTo } from "@/components/CountTo";
|
||||
import { ChartBar, ChartLine, ChartRound } from "./components/charts";
|
||||
import Segmented, { type OptionsType } from "@/components/Segmented";
|
||||
import { barChartData, chartData, latestNewsData, progressData } from "./data";
|
||||
|
||||
defineOptions({
|
||||
name: "Welcome"
|
||||
});
|
||||
import { ref } from 'vue';
|
||||
import ReCol from '@/components/MyCol';
|
||||
import { useDark } from './utils';
|
||||
import WelcomeTable from './components/table/index.vue';
|
||||
import { ReNormalCountTo } from '@/components/CountTo';
|
||||
import { ChartBar, ChartLine, ChartRound } from './components/charts';
|
||||
import Segmented, { type OptionsType } from '@/components/Segmented';
|
||||
import { barChartData, chartData, latestNewsData, progressData } from './data';
|
||||
|
||||
const { isDark } = useDark();
|
||||
let curWeek = ref(1); // 0上周、1本周
|
||||
const optionsBasis: Array<OptionsType> = [{ label: "上周" }, { label: "本周" }];
|
||||
const optionsBasis: Array<OptionsType> = [{ label: '上周' }, { label: '本周' }];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<el-row :gutter="24" justify="space-around">
|
||||
<re-col
|
||||
v-for="(item, index) in chartData"
|
||||
:key="index"
|
||||
v-motion
|
||||
:enter="{ opacity: 1, y: 0, transition: { delay: 80 * (index + 1) } }"
|
||||
:initial="{ opacity: 0, y: 100 }"
|
||||
:md="12"
|
||||
:sm="12"
|
||||
:value="6"
|
||||
:xs="24"
|
||||
class="mb-[18px]"
|
||||
>
|
||||
<el-card class="line-card" shadow="never">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-md font-medium">
|
||||
{{ item.name }}
|
||||
</span>
|
||||
<div
|
||||
:style="{
|
||||
backgroundColor: isDark ? 'transparent' : item.bgColor
|
||||
}"
|
||||
class="w-8 h-8 flex justify-center items-center rounded-md"
|
||||
>
|
||||
<IconifyIconOffline
|
||||
:color="item.color"
|
||||
:icon="item.icon"
|
||||
width="18"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between items-start mt-3">
|
||||
<div class="w-1/2">
|
||||
<ReNormalCountTo
|
||||
:duration="item.duration"
|
||||
:endVal="item.value"
|
||||
:fontSize="'1.6em'"
|
||||
:startVal="100"
|
||||
/>
|
||||
<p class="font-medium text-green-500">{{ item.percent }}</p>
|
||||
</div>
|
||||
<ChartLine
|
||||
v-if="item.data.length > 1"
|
||||
:color="item.color"
|
||||
:data="item.data"
|
||||
class="!w-1/2"
|
||||
/>
|
||||
<ChartRound v-else class="!w-1/2" />
|
||||
</div>
|
||||
</el-card>
|
||||
</re-col>
|
||||
<div>
|
||||
<el-row :gutter="24" justify="space-around">
|
||||
<re-col
|
||||
v-for="(item, index) in chartData"
|
||||
:key="index"
|
||||
v-motion
|
||||
:enter="{ opacity: 1, y: 0, transition: { delay: 80 * (index + 1) } }"
|
||||
:initial="{ opacity: 0, y: 100 }"
|
||||
:md="12"
|
||||
:sm="12"
|
||||
:value="6"
|
||||
:xs="24"
|
||||
class="mb-[18px]"
|
||||
>
|
||||
<el-card class="line-card" shadow="never">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-md font-medium">
|
||||
{{ item.name }}
|
||||
</span>
|
||||
<div :style="{ backgroundColor: isDark ? 'transparent' : item.bgColor }" class="w-8 h-8 flex justify-center items-center rounded-md">
|
||||
<IconifyIconOffline :color="item.color" :icon="item.icon" width="18" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between items-start mt-3">
|
||||
<div class="w-1/2">
|
||||
<ReNormalCountTo :duration="item.duration" :endVal="item.value" :fontSize="'1.6em'" :startVal="100" />
|
||||
<p class="font-medium text-green-500">{{ item.percent }}</p>
|
||||
</div>
|
||||
<ChartLine v-if="item.data.length > 1" :color="item.color" :data="item.data" class="!w-1/2" />
|
||||
<ChartRound v-else class="!w-1/2" />
|
||||
</div>
|
||||
</el-card>
|
||||
</re-col>
|
||||
|
||||
<re-col
|
||||
v-motion
|
||||
:enter="{ opacity: 1, y: 0, transition: { delay: 400 } }"
|
||||
:initial="{ opacity: 0, y: 100 }"
|
||||
:value="18"
|
||||
:xs="24"
|
||||
class="mb-[18px]"
|
||||
>
|
||||
<el-card class="bar-card" shadow="never">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-md font-medium">分析概览</span>
|
||||
<Segmented v-model="curWeek" :options="optionsBasis" />
|
||||
</div>
|
||||
<div class="flex justify-between items-start mt-3">
|
||||
<ChartBar
|
||||
:questionData="barChartData[curWeek].questionData"
|
||||
:requireData="barChartData[curWeek].requireData"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</re-col>
|
||||
<re-col v-motion :enter="{ opacity: 1, y: 0, transition: { delay: 400 } }" :initial="{ opacity: 0, y: 100 }" :value="18" :xs="24" class="mb-[18px]">
|
||||
<el-card class="bar-card" shadow="never">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-md font-medium">分析概览</span>
|
||||
<Segmented v-model="curWeek" :options="optionsBasis" />
|
||||
</div>
|
||||
<div class="flex justify-between items-start mt-3">
|
||||
<ChartBar :questionData="barChartData[curWeek].questionData" :requireData="barChartData[curWeek].requireData" />
|
||||
</div>
|
||||
</el-card>
|
||||
</re-col>
|
||||
|
||||
<re-col
|
||||
v-motion
|
||||
:enter="{ opacity: 1, y: 0, transition: { delay: 480 } }"
|
||||
:initial="{ opacity: 0, y: 100 }"
|
||||
:value="6"
|
||||
:xs="24"
|
||||
class="mb-[18px]"
|
||||
>
|
||||
<el-card shadow="never">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-md font-medium">解决概率</span>
|
||||
</div>
|
||||
<div
|
||||
v-for="(item, index) in progressData"
|
||||
:key="index"
|
||||
:class="[
|
||||
'flex',
|
||||
'justify-between',
|
||||
'items-start',
|
||||
index === 0 ? 'mt-8' : 'mt-[2.15rem]'
|
||||
]"
|
||||
>
|
||||
<el-progress
|
||||
:color="item.color"
|
||||
:duration="item.duration"
|
||||
:percentage="item.percentage"
|
||||
:stroke-width="21"
|
||||
:text-inside="true"
|
||||
striped
|
||||
striped-flow
|
||||
/>
|
||||
<span class="text-nowrap ml-2 text-text_color_regular text-sm">
|
||||
{{ item.week }}
|
||||
</span>
|
||||
</div>
|
||||
</el-card>
|
||||
</re-col>
|
||||
<re-col v-motion :enter="{ opacity: 1, y: 0, transition: { delay: 480 } }" :initial="{ opacity: 0, y: 100 }" :value="6" :xs="24" class="mb-[18px]">
|
||||
<el-card shadow="never">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-md font-medium">解决概率</span>
|
||||
</div>
|
||||
<div v-for="(item, index) in progressData" :key="index" :class="['flex', 'justify-between', 'items-start', index === 0 ? 'mt-8' : 'mt-[2.15rem]']">
|
||||
<el-progress :color="item.color" :duration="item.duration" :percentage="item.percentage" :stroke-width="21" :text-inside="true" striped striped-flow />
|
||||
<span class="text-nowrap ml-2 text-text_color_regular text-sm">
|
||||
{{ item.week }}
|
||||
</span>
|
||||
</div>
|
||||
</el-card>
|
||||
</re-col>
|
||||
|
||||
<re-col
|
||||
v-motion
|
||||
:enter="{ opacity: 1, y: 0, transition: { delay: 560 } }"
|
||||
:initial="{ opacity: 0, y: 100 }"
|
||||
:value="18"
|
||||
:xs="24"
|
||||
class="mb-[18px]"
|
||||
>
|
||||
<el-card class="h-[580px]" shadow="never">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-md font-medium">数据统计</span>
|
||||
</div>
|
||||
<WelcomeTable class="mt-3" />
|
||||
</el-card>
|
||||
</re-col>
|
||||
<re-col v-motion :enter="{ opacity: 1, y: 0, transition: { delay: 560 } }" :initial="{ opacity: 0, y: 100 }" :value="18" :xs="24" class="mb-[18px]">
|
||||
<el-card class="h-[580px]" shadow="never">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-md font-medium">数据统计</span>
|
||||
</div>
|
||||
<WelcomeTable class="mt-3" />
|
||||
</el-card>
|
||||
</re-col>
|
||||
|
||||
<re-col
|
||||
v-motion
|
||||
:enter="{ opacity: 1, y: 0, transition: { delay: 640 } }"
|
||||
:initial="{ opacity: 0, y: 100 }"
|
||||
:value="6"
|
||||
:xs="24"
|
||||
class="mb-[18px]"
|
||||
>
|
||||
<el-card shadow="never">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-md font-medium">最新动态</span>
|
||||
</div>
|
||||
<el-scrollbar class="mt-3" max-height="504">
|
||||
<el-timeline>
|
||||
<el-timeline-item
|
||||
v-for="(item, index) in latestNewsData"
|
||||
:key="index"
|
||||
:timestamp="item.date"
|
||||
center
|
||||
placement="top"
|
||||
>
|
||||
<p class="text-text_color_regular text-sm">
|
||||
{{
|
||||
`新增 ${item.requiredNumber} 条问题,${item.resolveNumber} 条已解决`
|
||||
}}
|
||||
</p>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
</el-scrollbar>
|
||||
</el-card>
|
||||
</re-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<re-col v-motion :enter="{ opacity: 1, y: 0, transition: { delay: 640 } }" :initial="{ opacity: 0, y: 100 }" :value="6" :xs="24" class="mb-[18px]">
|
||||
<el-card shadow="never">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-md font-medium">最新动态</span>
|
||||
</div>
|
||||
<el-scrollbar class="mt-3" max-height="504">
|
||||
<el-timeline>
|
||||
<el-timeline-item v-for="(item, index) in latestNewsData" :key="index" :timestamp="item.date" center placement="top">
|
||||
<p class="text-text_color_regular text-sm">
|
||||
{{ `新增 ${item.requiredNumber} 条问题,${item.resolveNumber} 条已解决` }}
|
||||
</p>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
</el-scrollbar>
|
||||
</el-card>
|
||||
</re-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-card) {
|
||||
--el-card-border-color: none;
|
||||
--el-card-border-color: none;
|
||||
|
||||
/* 解决概率进度条宽度 */
|
||||
.el-progress--line {
|
||||
width: 85%;
|
||||
}
|
||||
/* 解决概率进度条宽度 */
|
||||
.el-progress--line {
|
||||
width: 85%;
|
||||
}
|
||||
|
||||
/* 解决概率进度条字体大小 */
|
||||
.el-progress-bar__innerText {
|
||||
font-size: 15px;
|
||||
}
|
||||
/* 解决概率进度条字体大小 */
|
||||
.el-progress-bar__innerText {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
/* 隐藏 el-scrollbar 滚动条 */
|
||||
.el-scrollbar__bar {
|
||||
display: none;
|
||||
}
|
||||
/* 隐藏 el-scrollbar 滚动条 */
|
||||
.el-scrollbar__bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* el-timeline 每一项上下、左右边距 */
|
||||
.el-timeline-item {
|
||||
margin: 0 6px;
|
||||
}
|
||||
/* el-timeline 每一项上下、左右边距 */
|
||||
.el-timeline-item {
|
||||
margin: 0 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.main-content {
|
||||
margin: 20px 20px 0 !important;
|
||||
margin: 20px 20px 0 !important;
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in New Issue