同步分支

This commit is contained in:
MoYiJiangNan 2023-12-03 17:44:23 +08:00 committed by GitHub
commit 43d3e41afe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 234 additions and 197 deletions

2
components.d.ts vendored
View File

@ -16,7 +16,6 @@ declare module 'vue' {
ElPagination: typeof import('element-plus/es')['ElPagination']
ElRow: typeof import('element-plus/es')['ElRow']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTag: typeof import('element-plus/es')['ElTag']
@ -25,6 +24,7 @@ declare module 'vue' {
RouterView: typeof import('vue-router')['RouterView']
VanButton: typeof import('vant/es')['Button']
VanCellGroup: typeof import('vant/es')['CellGroup']
VanConfigProvider: typeof import('vant/es')['ConfigProvider']
VanField: typeof import('vant/es')['Field']
VanImage: typeof import('vant/es')['Image']
VanPopup: typeof import('vant/es')['Popup']

View File

@ -6,6 +6,7 @@ import {User} from "../entities/User";
import {Auth} from "../entities/Auth";
import {File} from "../entities/File";
import {SearchType} from "../entities/SearchType.ts";
import {AccessInformation} from "../entities/AccessInformation.ts";
export const baseUrl = 'http://localhost:8081';
@ -27,7 +28,7 @@ const instance = axios.create({
timeout: 1000,
headers: {'Content-Type': 'application/json'}
});
axios.interceptors.request.use(function (config) {
instance.interceptors.request.use(function (config) {
config.headers['Authorization'] = window.sessionStorage.getItem("authorization");
return config;
}, function (error) {
@ -36,8 +37,8 @@ axios.interceptors.request.use(function (config) {
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
const authorization = response.headers['Set-Authorization'];
instance.interceptors.response.use(function (response) {
const authorization = response.headers['set-authorization'];
if (authorization) {
window.sessionStorage.setItem("authorization", authorization);
}
@ -137,5 +138,11 @@ export const search = (page: number, num: number, searchType: SearchType, data:
* @param count
*/
export const getAccessInformation = (count: number) => {
return instance.get<File[]>("/api/access/get", {params: {count}});
return instance.get<AccessInformation[]>("/api/access/get", {params: {count}});
}
/**
* 访
*/
export const getTotalAccessInformation = () => {
return instance.get<AccessInformation>("/api/access/getAll");
}

View File

@ -9,5 +9,5 @@ export enum Auth {
/**
*
*/
ADMIN
ADMIN,
}

View File

@ -7,7 +7,7 @@ export interface User {
/**
* id
*/
id: string
id: number;
/**
*
*/

View File

@ -1,19 +1,16 @@
<template>
<van-config-provider :theme="vantTheme"></van-config-provider>
<!-- 主容器 -->
<div class="Home">
<div>
<!-- 顶部区域 -->
<el-row>
<el-col :span="24" class="Header">
<el-col :span="24">
<!-- 顶部内容区域 -->
<div class="HeaderHome">
<!-- 主题切换按钮 -->
<el-switch v-model="colorTheme" class="ml-2 input-button"
style="--el-switch-on-color: var(--el-border-color-dark); --el-switch-off-color: var(--el-border-color-light)"
:active-icon="Moon" :inactive-icon="Sunny" @change="handleColorThemeChange"/>
<div class="header">
<!-- 顶部输入框 -->
<div class="HeaderHomeInput">
<div>
<!-- 输入框属性与文本 -->
<el-input v-model="HeaderHomeInputText" placeholder="请输入要搜索的内容">
<el-input v-model="searchInput" placeholder="请输入要搜索的内容">
<!-- 选择下拉框 -->
<template #prepend>
<el-select placeholder="名字" value-key="1" style="width: 100px">
@ -30,42 +27,41 @@
</el-input>
</div>
<!-- 用户属性区域 -->
<div class="HeaderHomeUserInfo">
<img :src="userAvatar" alt="用户头像" @click="imgLoginBox"/>
<span>{{ userName }}</span>
<div class="header-user" @click="imgLoginBox">
<img :src="userAvatar" alt="用户头像"/>
<span>{{ username }}</span>
</div>
<!-- 用户登录弹窗 -->
<van-popup v-model:show="userAvatarLoginShow" round class="userLoginBox">
<van-popup v-model:show="userAvatarLoginShow" round>
<!-- 登录/注册弹窗内容 -->
<div class="login-content">
<h2>登录/注册</h2>
<p>欢迎来到文件分享站</p>
<label for="userName">用户名</label>
<van-field id="userName" v-model="userName" center placeholder="请输入用户名"/>
<van-field id="userName" v-model="usernameInput" center placeholder="请输入用户名"/>
<!-- 用户名输入框 -->
<label for="password">密码</label>
<van-field id="password" v-model="userPassword" center type="password" placeholder="请输入用户密码"/>
<van-field id="password" v-model="userPasswordInput" center type="password" placeholder="请输入用户密码"/>
<!-- 密码输入框 -->
<div class="actions">
<van-button class="userLoginButton" @click="userLogin" type="primary">登录</van-button>
<van-button class="user-login-register-button" @click="userLogin" type="primary">登录</van-button>
<!-- 登录按钮 -->
<van-button class="userLoginButton" @click="userEnroll" type="primary">注册后登录</van-button>
<van-button class="user-login-register-button" @click="userEnroll" type="primary">注册后登录</van-button>
<!-- 注册按钮 -->
</div>
</div>
</van-popup>
<!-- 用户属性弹窗 -->
<van-popup v-model:show="userAvatarLoginShowTools" round position="top" class="userLoginBox">
<van-popup v-model:show="userAvatarLoginShowTools" round>
<!-- 登录弹窗 -->
<div class="login-content">
<h2>个人中心</h2>
<h3>用户属性:</h3>
<div>
<p class="userNameId">用户ID: {{ userAboutId }} </p>
<p class="userNameName">用户名称: {{ userAboutName }}</p>
<p class="userNameType">用户类型:
<span v-if="userAboutAuth === 'admin'">管理员</span>
<span v-else-if="userAboutAuth === 'user'">普通用户</span>
<p>用户名称: {{ username }}</p>
<p>用户类型:
<span v-if="userAuth === Auth.ADMIN">管理员</span>
<span v-else-if="userAuth === Auth.USER">普通用户</span>
<span v-else>未登录</span>
</p>
</div>
@ -73,17 +69,30 @@
<el-button type="primary" @click="logout">退出登录</el-button>
</div>
</van-popup>
<!-- 文件详情 -->
<van-popup v-model:show="showFileInformation" round>
<div class="file-information-popover">
<h2>文件名称:<span>XXXXXXX</span></h2>
<div>
<p>文件ID: <span>1</span></p>
<p>文件名: <span>测试</span></p>
<p>文件类型: <span>exe</span></p>
<p>文件MD5: <span>hjs7g90shds7s09ydg9s07gs90g7s7g</span></p>
<p>文件上传者: <span>wzp</span></p>
<p>文件上传时间: <span>2022-07-12 16:21:39</span></p>
</div>
</div>
</van-popup>
</div>
</el-col>
</el-row>
<!-- 下面区域 -->
<el-row class="LeftAndRightBox">
<el-row class="main">
<!-- 左侧区域 -->
<el-col :span="17" class="Left">
<div class="LeftFileList">
<el-col :span="17" class="files-data">
<div>
<!-- 文件表格 -->
<el-table ref="fileListTable" :data="pageFileData" class="LeftFileListData" border stripe
style="width: 100%">
<el-table ref="fileListTable" :data="pageFileData" class="files-data-table" border stripe>
<el-table-column prop="id" label="ID" width="100"/>
<el-table-column prop="name" label="文件名称" width="650"/>
<el-table-column prop="type" label="文件格式" width="150"/>
@ -91,30 +100,30 @@
<template #default="scope">{{ parserByteSize(scope.row.size) }}</template>
</el-table-column>
<el-table-column prop="uploaderName" label="上传者" width="150"/>
<el-table-column fixed="right" label="操作" width="155">
<el-table-column fixed="right" label="操作" :width="fileOptionRowWidth">
<!-- 操作列模板 -->
<template #default>
<el-button link type="primary">下载</el-button>
<el-button link type="primary">详情</el-button>
<el-button link type="danger">删除</el-button>
<el-button link type="primary" @click="showFileInformationDialog">详情</el-button>
<el-button link type="danger" v-if="userAuth === Auth.ADMIN">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<el-pagination
@current-change="HandleCurrentChange"
:current-page="CurrentPage"
@current-change="handlerPageChange"
:current-page="currentPage"
:page-sizes="[20]"
:page-size="20"
layout="prev, pager, next"
:total="totalFileCount"
class="Pagination"
class="pagination"
/>
</div>
</el-col>
<!-- 右侧区域 -->
<el-col :span="7" class="Right">
<div class="upload">
<el-col :span="7" class="file-uploader">
<div>
<span>文件上传:</span>
<el-upload
class="upload-demo"
@ -137,33 +146,33 @@
</div>
<!-- 访问量统计 -->
<span>访问量统计:</span>
<div class="access" ref="accessDiv">
<div ref="accessDiv">
<el-row :gutter="24">
<el-col :span="12">
<el-card class="card" shadow="never" style="margin:5px 0 5px 5px">
<template #header>
<span>访问量</span>
</template>
<div class="trafficData">12,584</div>
<div class="trafficDataTag">同昨日增长
<el-tag type="success">+5%</el-tag>
<div class="access-data"> {{ allAccess }}</div>
<div class="access-data-increase">同昨日增长
<el-tag type="success">+{{ allContrastAccess }}</el-tag>
</div>
</el-card>
</el-col>
<el-col :span="12">
<el-card class="card" shadow="never" style="margin: 5px 5px 5px 0">
<template #header>
<span>访问</span>
<span>下载</span>
</template>
<div class="trafficData">584</div>
<div class="trafficDataTag">
同昨日减少
<el-tag type="danger">-15%</el-tag>
<div class="access-data"> {{ allDownload }}</div>
<div class="access-data-increase">
同昨日增加
<el-tag type="success">+{{ allContrastDownload }}</el-tag>
</div>
</el-card>
</el-col>
</el-row>
<canvas ref="mainCanvas" :width="mainCanvasWidth" height="400"></canvas>
<canvas ref="mainCanvas" height="400"></canvas>
</div>
</el-col>
</el-row>
@ -172,57 +181,96 @@
<script setup lang="ts">
import {Search, Moon, Sunny, UploadFilled} from '@element-plus/icons-vue';
import {ref, onMounted, markRaw} from 'vue';
import {Search, UploadFilled} from '@element-plus/icons-vue';
import 'element-plus/theme-chalk/dark/css-vars.css'
import {ref, onMounted, computed, onBeforeMount} from 'vue';
import {useDark, useToggle} from "@vueuse/core"
import {GridComponent} from 'echarts/components';
import {LineChart} from 'echarts/charts';
import {UniversalTransition} from 'echarts/features';
import {CanvasRenderer} from 'echarts/renderers';
import {LegendComponent} from 'echarts/components';
import {EChartsType} from "echarts";
import * as echarts from 'echarts/core';
import {getAllFiles, Result} from "../api/Requester.ts";
import {getAllFiles, register, Result, getAccessInformation, getTotalAccessInformation} from "../api/Requester.ts";
import {login} from '../api/Requester';
import {AxiosResponse} from "axios";
import {User} from "../entities/User.ts";
import {ElMessage} from "element-plus";
import {Auth} from "../entities/Auth.ts";
import {File} from "../entities/File.ts";
import {AccessInformation} from "../entities/AccessInformation.ts";
echarts.use([GridComponent, LineChart, CanvasRenderer, UniversalTransition, LegendComponent]);
// TODO:
const userAboutId = ref<number>(0);
const userAboutName = ref<string>("未登录");
const userAboutAuth = ref<string>("未登录");
const username = computed(() => {
const username = sessionStorage.getItem("username");
if (username) {
return username;
}
return "未登录"
})
const userAuth = computed(() => {
const authStorage = sessionStorage.getItem("auth");
if (authStorage) {
console.log(authStorage)
switch (authStorage) {
case "admin":
return Auth.ADMIN;
default:
return Auth.USER;
}
} else {
return "未登录"
}
})
// TODO:
//
const HeaderHomeInputText = ref('');
const searchInput = ref<string>('');
//
const userAvatar = 'src/assets/userAvatar.jpg';
//
const userName = ref<string>("");
const userPassword = ref<string>("");
const usernameInput = ref<string>("");
const userPasswordInput = ref<string>("");
//
const userAvatarLoginShow = ref<boolean>(false);
//
const userAvatarLoginShowTools = ref<boolean>(false);
//
const isDark = useDark();
const colorTheme = ref<boolean>(isDark.value);
const isDark = useDark()
const toggleDark = useToggle(isDark);
const handleColorThemeChange = () => {
toggleDark();
const vantTheme = ref<"light" | "dark">("light");
//
const initTheme = () => {
const now = new Date();
const hour = now.getHours();
if (hour < 7 || hour > 16){
toggleDark(true);
vantTheme.value = "dark";
return;
}
toggleDark(false);
}
// TODO:
const showFileInformation = ref<boolean>(false);
// admin user UI
const fileOptionRowWidth = computed(() => {
switch (userAuth.value) {
case Auth.ADMIN:
return 160;
default:
return 110;
}
});
//
const CurrentPage = ref(1);
const currentPage = ref<number>(1);
const totalFileCount = ref<number>(0);
const pageFileData = ref<File[]>([]);
const showAllFiles = () => {
getAllFiles(CurrentPage.value, 20).then((res) => {
totalFileCount.value = res.data.data.total
pageFileData.value = res.data.data.data
getAllFiles(currentPage.value, 20).then((res) => {
totalFileCount.value = res.data.data.total;
pageFileData.value = res.data.data.data;
})
}
const parserByteSize = (byte: number): string => {
@ -241,13 +289,13 @@ const parserByteSize = (byte: number): string => {
return (byte / 1024 / 1024 / 1024 / 1024).toFixed(2) + "TB";
}
//
const HandleCurrentChange = (val: number) => {
CurrentPage.value = val;
const handlerPageChange = (val: number) => {
currentPage.value = val;
showAllFiles();
};
// TODO: 访
// 5访
// 访
const option = {
xAxis: {
type: 'category',
@ -257,7 +305,7 @@ const option = {
type: 'value'
},
legend: { // legend
data: ['访问量', '同昨日增长'], //
data: ['访问量', '下载量'], //
orient: "vertical",
right: 10,
top: 'center'
@ -265,22 +313,39 @@ const option = {
series: [
{
name: '访问量',
data: [820, 932, 901, 934, 1290],
type: 'line',
smooth: true
},
{
name: '同昨日增长',
data: [120, 132, 201, 334, 590],
name: '下载量',
type: 'line',
smooth: true
}
]
};
//
// 5访
const contrastAccess = ref<number>();
const contrastDownload = ref<number>();
const fiveData = () => {
getAccessInformation(5)
.then((res: AxiosResponse<AccessInformation[]>) => {
const accessCounts = [];
const downloadCounts = [];
for (let datum of res.data) {
accessCounts.push(datum.totalAccess);
downloadCounts.push(datum.totalDownload);
}
option.series[0]['data'] = accessCounts;
option.series[1]['data'] = downloadCounts;
contrastAccess.value = res.data[4].totalAccess
contrastDownload.value = res.data[4].totalDownload
changeFigureSize();
})
}
//
const mainCanvas = ref<HTMLCanvasElement>();
const accessDiv = ref<HTMLDivElement>();
const charts = ref<EChartsType>();
let charts: echarts.ECharts;
const changeFigureSize = () => {
if (!mainCanvas.value) {
return;
@ -289,18 +354,31 @@ const changeFigureSize = () => {
return;
}
mainCanvas.value.width = accessDiv.value.clientWidth;
if (charts.value) {
charts.value.resize({"width": mainCanvas.value.width, "height": mainCanvas.value.height})
if (charts) {
charts.resize({"width": mainCanvas.value.width, "height": mainCanvas.value.height})
} else {
charts.value = markRaw(echarts.init(mainCanvas.value))
charts.value.setOption(option)
charts = echarts.init(mainCanvas.value);
charts.setOption(option)
}
}
//
const allAccess = ref<number>();
const allDownload = ref<number>();
const allData = () => {
getTotalAccessInformation()
.then((res: AxiosResponse<AccessInformation>) => {
allAccess.value = res.data.totalAccess
allDownload.value = res.data.totalDownload
})
}
//
const allContrastAccess = contrastAccess;
const allContrastDownload = contrastDownload;
// TODO:
//
const imgLoginBox = () => {
if (sessionStorage.getItem("userInfo") || localStorage.getItem("userInfo")) {
if (sessionStorage.getItem("authorization")) {
//
//
userAvatarLoginShowTools.value = true;
@ -314,138 +392,85 @@ const imgLoginBox = () => {
//
const userLogin = () => {
// cookie
localStorage.removeItem("userInfo");
sessionStorage.removeItem("userInfo");
sessionStorage.clear();
//
if (userName.value == "" || userPassword.value == "") {
if (usernameInput.value == "" || userPasswordInput.value == "") {
ElMessage.error("用户名密码不能为空");
localStorage.removeItem("userInfo");
sessionStorage.removeItem("userInfo");
return;
}
//
login(userName.value, userPassword.value)
login(usernameInput.value, userPasswordInput.value)
.then((res: AxiosResponse<Result<User>>) => {
//
if (res.data.status == 200) {
//
// sessionStorage
const userInfo = {
userName: userName.value,
userPassword: userPassword.value,
};
sessionStorage.setItem("userInfo", JSON.stringify(userInfo));
console.log(res.data.data.name, res.data.data.id, res.data.data.auth);
const resdata = res.data.data
userAboutId.value = Number(resdata.id);
userAboutName.value = String(resdata.name);
userAboutAuth.value = String(resdata.auth)
const username = res.data.data.name;
sessionStorage.setItem("username", username);
sessionStorage.setItem("auth", res.data.data.auth.toString());
//
setTimeout(() => {
imgLoginBox();
}, 1500); // 15001.5
}, 1000); // 10001
ElMessage.success("登录成功!");
window.location.reload()
} else {
ElMessage.error("登录失败,用户名密码错误!");
localStorage.removeItem("userInfo");
sessionStorage.removeItem("userInfo");
}
})
.catch(() => {
ElMessage.error("登录失败,用户名密码错误!");
localStorage.removeItem("userInfo");
sessionStorage.removeItem("userInfo");
});
};
//
const logout = () => {
//
ElMessage.success("退出成功!")
//
localStorage.removeItem("userInfo");
sessionStorage.removeItem("userInfo");
//
window.location.reload();
sessionStorage.clear();
userAvatarLoginShowTools.value = false;
window.location.reload()
};
// TODO:
// sessionStorage
const checkSessionStorageUserInfo = () => {
if (checkedStorage) {
return; //
//
const userEnroll = () => {
//
if (usernameInput.value == '' || userPasswordInput.value == '') {
ElMessage.error("用户名密码不能为空")
return;
}
const userInfoString = sessionStorage.getItem("userInfo");
if (userInfoString) {
//
const userInfo = JSON.parse(userInfoString);
userName.value = userInfo.userName;
userPassword.value = userInfo.userPassword;
//
verifyUserInfo();
}
};
//
const verifyUserInfo = () => {
if (userName.value === "" || userPassword.value === "") {
return; //
}
login(userName.value, userPassword.value)
.then((res: AxiosResponse<Result<User>>) => {
if (res.data.status === 200) {
console.log(res.data.data.name, res.data.data.id, res.data.data.auth);
userAboutId.value = Number(res.data.data.id);
userAboutName.value = String(res.data.data.name);
userAboutAuth.value = String(res.data.data.auth)
ElMessage.success("登录成功!");
userAvatarLoginShowTools.value = true; //
userAvatarLoginShow.value = false; //
} else {
ElMessage.error("验证失败,请重新登录!");
userAvatarLoginShowTools.value = false; //
userAvatarLoginShow.value = true; //
localStorage.removeItem("userInfo");
sessionStorage.removeItem("userInfo");
}
})
.catch(() => {
ElMessage.error("验证失败,请重新登录!");
userAvatarLoginShowTools.value = false; //
userAvatarLoginShow.value = true; //
localStorage.removeItem("userInfo");
sessionStorage.removeItem("userInfo");
});
};
//
let checkedStorage = false;
const checkLocalStorageUserInfo = () => {
if (checkedStorage) {
return; //
}
const userInfoString = localStorage.getItem("userInfo");
if (userInfoString) {
//
const userInfo = JSON.parse(userInfoString);
userName.value = userInfo.userName;
userPassword.value = userInfo.userPassword;
//
verifyUserInfo();
}
};
register(usernameInput.value, userPasswordInput.value, Auth.USER).then((res) => {
switch (res.data.status) {
case 251:
ElMessage.error("邀请码错误!");
break;
case 501:
ElMessage.error("存在同名用户!");
break;
case 200:
ElMessage.success("注册成功");
sessionStorage.setItem("username", res.data.data.name);
sessionStorage.setItem("auth", res.data.data.auth.toString());
break;
default:
ElMessage.error("无法注册!");
}
});
}
//
const showFileInformationDialog = () => {
showFileInformation.value = true
}
// TODO: onMounted
onBeforeMount(() => {
initTheme();
})
onMounted(() => {
window.addEventListener("resize", changeFigureSize);
changeFigureSize();
fiveData();
showAllFiles();
checkSessionStorageUserInfo();
checkLocalStorageUserInfo();
checkedStorage = true
allData();
})
</script>
<style scoped>
/* 顶部样式 */
.HeaderHome {
.header {
display: flex;
justify-content: center;
align-items: center;
@ -453,7 +478,7 @@ onMounted(() => {
}
/* 用户属性样式 */
.HeaderHomeUserInfo {
.header-user {
display: flex;
align-items: center;
}
@ -466,45 +491,46 @@ img {
margin: 10px 10px 10px 10px;
}
.LeftAndRightBox {
.main {
flex-direction: row;
flex-wrap: nowrap;
width: calc(100% - 40px);
}
/* 左侧样式 */
.Left {
.files-data {
margin: 5px 5px 0 15px;
font-size: smaller;
}
.Right {
.file-uploader {
margin: 5px -15px 0 5px;
}
/* 分页样式 */
.Pagination {
.pagination {
display: flex;
justify-content: center;
align-items: center;
}
/* 设置列表高度为100% */
.LeftFileListData {
.files-data-table {
height: 100%;
width: 100% !important;
}
.card {
border-radius: 10px;
}
.trafficData {
.access-data {
font-size: 40px;
font-weight: bold;
line-height: 1.5;
}
.trafficDataTag {
.access-data-increase {
display: flex;
font-size: 15px;
font-weight: bold;
@ -519,7 +545,11 @@ img {
left: 50%;
}
.userLoginButton {
.user-login-register-button {
margin: 10px 10px 0 10px;
}
.file-information-popover {
margin: 20px;
}
</style>

View File

@ -11,10 +11,10 @@ export default defineConfig({
server: {
host: "0.0.0.0",
port: 5173,
https: {
/* https: {
key: readFileSync("keys/agent2-key.pem"),
cert: readFileSync("keys/agent2-cert.pem"),
}
}*/
},
plugins: [
AutoImport({