Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
d40729e04a | |||
507bf2d66a | |||
aa0d8f7b3d | |||
fcbb16a98c | |||
a5bec61921 | |||
c0b015cbf1 | |||
2ef06b2bc8 | |||
0a967445e6 | |||
b9ea50903a | |||
d728a78fab | |||
72f2bbac30 | |||
35045bb543 | |||
ef1832775a | |||
|
d095523e62 | ||
0c95f1385f | |||
121aa7c44b | |||
07d312b71e | |||
cb42109f75 | |||
43d3e41afe | |||
9aaad2dbf8 | |||
6e2346cbd6 | |||
b24103ea7f | |||
8dbb0c862e | |||
75b13beaa8 | |||
c51f637e11 | |||
99acbd797b | |||
161d66f3f7 | |||
601ac7822b | |||
f989fae126 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -24,3 +24,5 @@ dist-ssr
|
|||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
/keys
|
/keys
|
||||||
|
/dist
|
||||||
|
dist.zip
|
2
auto-imports.d.ts
vendored
2
auto-imports.d.ts
vendored
@ -5,5 +5,7 @@
|
|||||||
// Generated by unplugin-auto-import
|
// Generated by unplugin-auto-import
|
||||||
export {}
|
export {}
|
||||||
declare global {
|
declare global {
|
||||||
|
const ElMess: typeof import('element-plus/es')['ElMess']
|
||||||
|
const ElMessaeg: typeof import('element-plus/es')['ElMessaeg']
|
||||||
const ElMessage: typeof import('element-plus/es')['ElMessage']
|
const ElMessage: typeof import('element-plus/es')['ElMessage']
|
||||||
}
|
}
|
||||||
|
4
components.d.ts
vendored
4
components.d.ts
vendored
@ -7,7 +7,6 @@ export {}
|
|||||||
|
|
||||||
declare module 'vue' {
|
declare module 'vue' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
ElAvatar: typeof import('element-plus/es')['ElAvatar']
|
|
||||||
ElButton: typeof import('element-plus/es')['ElButton']
|
ElButton: typeof import('element-plus/es')['ElButton']
|
||||||
ElCard: typeof import('element-plus/es')['ElCard']
|
ElCard: typeof import('element-plus/es')['ElCard']
|
||||||
ElCol: typeof import('element-plus/es')['ElCol']
|
ElCol: typeof import('element-plus/es')['ElCol']
|
||||||
@ -17,16 +16,15 @@ declare module 'vue' {
|
|||||||
ElPagination: typeof import('element-plus/es')['ElPagination']
|
ElPagination: typeof import('element-plus/es')['ElPagination']
|
||||||
ElRow: typeof import('element-plus/es')['ElRow']
|
ElRow: typeof import('element-plus/es')['ElRow']
|
||||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||||
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
|
||||||
ElTable: typeof import('element-plus/es')['ElTable']
|
ElTable: typeof import('element-plus/es')['ElTable']
|
||||||
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
||||||
ElTag: typeof import('element-plus/es')['ElTag']
|
ElTag: typeof import('element-plus/es')['ElTag']
|
||||||
ElUpload: typeof import('element-plus/es')['ElUpload']
|
ElUpload: typeof import('element-plus/es')['ElUpload']
|
||||||
ElWatermark: typeof import('element-plus/es')['ElWatermark']
|
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
VanButton: typeof import('vant/es')['Button']
|
VanButton: typeof import('vant/es')['Button']
|
||||||
VanCellGroup: typeof import('vant/es')['CellGroup']
|
VanCellGroup: typeof import('vant/es')['CellGroup']
|
||||||
|
VanConfigProvider: typeof import('vant/es')['ConfigProvider']
|
||||||
VanField: typeof import('vant/es')['Field']
|
VanField: typeof import('vant/es')['Field']
|
||||||
VanImage: typeof import('vant/es')['Image']
|
VanImage: typeof import('vant/es')['Image']
|
||||||
VanPopup: typeof import('vant/es')['Popup']
|
VanPopup: typeof import('vant/es')['Popup']
|
||||||
|
41
electron/main.ts
Normal file
41
electron/main.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// main.ts
|
||||||
|
|
||||||
|
// 控制应用生命周期和创建原生浏览器窗口的模组
|
||||||
|
import path from "path";
|
||||||
|
import {app, BrowserWindow} from "electron";
|
||||||
|
|
||||||
|
|
||||||
|
function createWindow() {
|
||||||
|
// 创建浏览器窗口
|
||||||
|
const mainWindow = new BrowserWindow({
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
webPreferences: {
|
||||||
|
// 引入预加载文件
|
||||||
|
preload: path.join(__dirname, "preload.js"),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 加载vite启动的本地服务
|
||||||
|
mainWindow.loadURL("http://localhost:5173");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 这段程序将会在 Electron 结束初始化
|
||||||
|
// 和创建浏览器窗口的时候调用
|
||||||
|
// 部分 API 在 ready 事件触发后才能使用。
|
||||||
|
app.whenReady().then(() => {
|
||||||
|
createWindow();
|
||||||
|
|
||||||
|
app.on("activate", function () {
|
||||||
|
// 通常在 macOS 上,当点击 dock 中的应用程序图标时,如果没有其他
|
||||||
|
// 打开的窗口,那么程序会重新创建一个窗口。
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) createWindow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 除了 macOS 外,当所有窗口都被关闭的时候退出程序。 因此,通常对程序和它们在
|
||||||
|
// 任务栏上的图标来说,应当保持活跃状态,直到用户使用 Cmd + Q 退出。
|
||||||
|
app.on("window-all-closed", function () {
|
||||||
|
if (process.platform !== "darwin") app.quit();
|
||||||
|
});
|
1
electron/preload.ts
Normal file
1
electron/preload.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
console.log("preload");
|
@ -2,9 +2,9 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/UserAvatar.jpg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Vite + Vue + TS</title>
|
<title>文件分享站</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
25
package-lock.json
generated
25
package-lock.json
generated
@ -11,7 +11,8 @@
|
|||||||
"@types/crypto-js": "^4.2.1",
|
"@types/crypto-js": "^4.2.1",
|
||||||
"axios": "^1.6.2",
|
"axios": "^1.6.2",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"element-plus": "^2.4.2",
|
"echarts": "^5.4.3",
|
||||||
|
"element-plus": "^2.4.3",
|
||||||
"vant": "^4.7.3",
|
"vant": "^4.7.3",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
"vue-router": "^4.2.5"
|
"vue-router": "^4.2.5"
|
||||||
@ -1590,6 +1591,15 @@
|
|||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/echarts": {
|
||||||
|
"version": "5.4.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/echarts/-/echarts-5.4.3.tgz",
|
||||||
|
"integrity": "sha512-mYKxLxhzy6zyTi/FaEbJMOZU1ULGEQHaeIeuMR5L+JnJTpz+YR03mnnpBhbR4+UYJAgiXgpyTVLffPAjOTLkZA==",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "2.3.0",
|
||||||
|
"zrender": "5.4.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/element-plus": {
|
"node_modules/element-plus": {
|
||||||
"version": "2.4.3",
|
"version": "2.4.3",
|
||||||
"resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.4.3.tgz",
|
"resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.4.3.tgz",
|
||||||
@ -2877,6 +2887,11 @@
|
|||||||
"typescript": ">=4.2.0"
|
"typescript": ">=4.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tslib": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
|
||||||
|
},
|
||||||
"node_modules/type-check": {
|
"node_modules/type-check": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz",
|
"resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz",
|
||||||
@ -3297,6 +3312,14 @@
|
|||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"node_modules/zrender": {
|
||||||
|
"version": "5.4.4",
|
||||||
|
"resolved": "https://registry.npmmirror.com/zrender/-/zrender-5.4.4.tgz",
|
||||||
|
"integrity": "sha512-0VxCNJ7AGOMCWeHVyTrGzUgrK4asT4ml9PEkeGirAkKNYXYzoPJCLvmyfdoOXcjTHPs10OZVMfD1Rwg16AZyYw==",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "2.3.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
10
package.json
10
package.json
@ -3,16 +3,19 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"main": "dist/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vue-tsc && vite build",
|
"build": "vue-tsc --noEmit && vite build",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview",
|
||||||
|
"electron:dev":"tsc && electron ."
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/crypto-js": "^4.2.1",
|
"@types/crypto-js": "^4.2.1",
|
||||||
"axios": "^1.6.2",
|
"axios": "^1.6.2",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"element-plus": "^2.4.2",
|
"echarts": "^5.4.3",
|
||||||
|
"element-plus": "^2.4.3",
|
||||||
"vant": "^4.7.3",
|
"vant": "^4.7.3",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
"vue-router": "^4.2.5"
|
"vue-router": "^4.2.5"
|
||||||
@ -23,6 +26,7 @@
|
|||||||
"@typescript-eslint/parser": "^6.11.0",
|
"@typescript-eslint/parser": "^6.11.0",
|
||||||
"@vant/auto-import-resolver": "^1.0.2",
|
"@vant/auto-import-resolver": "^1.0.2",
|
||||||
"@vitejs/plugin-vue": "^4.2.3",
|
"@vitejs/plugin-vue": "^4.2.3",
|
||||||
|
"electron": "^27.1.3",
|
||||||
"eslint": "^8.54.0",
|
"eslint": "^8.54.0",
|
||||||
"eslint-plugin-vue": "^9.18.1",
|
"eslint-plugin-vue": "^9.18.1",
|
||||||
"typescript": "^5.0.2",
|
"typescript": "^5.0.2",
|
||||||
|
BIN
public/UserAvatar.jpg
Normal file
BIN
public/UserAvatar.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
@ -11,7 +11,7 @@ const onInitOrResize = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
window.onresize = onInitOrResize;
|
window.addEventListener("resize", onInitOrResize);
|
||||||
onInitOrResize();
|
onInitOrResize();
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
@ -5,8 +5,10 @@ import {md5Hex} from "./CryptoUtils";
|
|||||||
import {User} from "../entities/User";
|
import {User} from "../entities/User";
|
||||||
import {Auth} from "../entities/Auth";
|
import {Auth} from "../entities/Auth";
|
||||||
import {File} from "../entities/File";
|
import {File} from "../entities/File";
|
||||||
|
import {SearchType} from "../entities/SearchType.ts";
|
||||||
|
import {AccessInformation} from "../entities/AccessInformation.ts";
|
||||||
|
|
||||||
export const baseUrl = 'http://localhost:8081';
|
export const baseUrl = '';
|
||||||
|
|
||||||
export interface Result<T> {
|
export interface Result<T> {
|
||||||
data: T;
|
data: T;
|
||||||
@ -26,7 +28,7 @@ const instance = axios.create({
|
|||||||
timeout: 1000,
|
timeout: 1000,
|
||||||
headers: {'Content-Type': 'application/json'}
|
headers: {'Content-Type': 'application/json'}
|
||||||
});
|
});
|
||||||
axios.interceptors.request.use(function (config) {
|
instance.interceptors.request.use(function (config) {
|
||||||
config.headers['Authorization'] = window.sessionStorage.getItem("authorization");
|
config.headers['Authorization'] = window.sessionStorage.getItem("authorization");
|
||||||
return config;
|
return config;
|
||||||
}, function (error) {
|
}, function (error) {
|
||||||
@ -35,8 +37,8 @@ axios.interceptors.request.use(function (config) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 添加响应拦截器
|
// 添加响应拦截器
|
||||||
axios.interceptors.response.use(function (response) {
|
instance.interceptors.response.use(function (response) {
|
||||||
const authorization = response.headers['Set-Authorization'];
|
const authorization = response.headers['set-authorization'];
|
||||||
if (authorization) {
|
if (authorization) {
|
||||||
window.sessionStorage.setItem("authorization", authorization);
|
window.sessionStorage.setItem("authorization", authorization);
|
||||||
}
|
}
|
||||||
@ -44,12 +46,24 @@ axios.interceptors.response.use(function (response) {
|
|||||||
}, function (error) {
|
}, function (error) {
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
});
|
});
|
||||||
|
/**
|
||||||
|
* 登录接口
|
||||||
|
* @param username 用户名
|
||||||
|
* @param password 密码(未加密的)
|
||||||
|
*/
|
||||||
export const login = (username: string, password: string) => {
|
export const login = (username: string, password: string) => {
|
||||||
return instance.post<Result<User>>("/api/user/login", {
|
return instance.post<Result<User>>("/api/user/login", {
|
||||||
name: username,
|
name: username,
|
||||||
password: md5Hex(password)
|
password: md5Hex(password)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 注册接口
|
||||||
|
* @param username 用户名
|
||||||
|
* @param password 密码
|
||||||
|
* @param auth 注册的权限(Auth.user或Auth.admin)
|
||||||
|
* @param verifyCode 注册管理员所需的验证码(若注册的权限为Auth.user则无需填写)
|
||||||
|
*/
|
||||||
export const register = (username: string, password: string, auth: Auth, verifyCode?: string) => {
|
export const register = (username: string, password: string, auth: Auth, verifyCode?: string) => {
|
||||||
return instance.post<Result<User>>("/api/user/register", {
|
return instance.post<Result<User>>("/api/user/register", {
|
||||||
name: username,
|
name: username,
|
||||||
@ -58,13 +72,26 @@ export const register = (username: string, password: string, auth: Auth, verifyC
|
|||||||
verifyCode: verifyCode,
|
verifyCode: verifyCode,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 获取验证码(只能以管理员用户运行,后端会验签)
|
||||||
|
*/
|
||||||
|
export const generatorVerifyCode = () => {
|
||||||
|
return instance.get<Result<string>>("/api/user/verifyCode")
|
||||||
|
}
|
||||||
|
|
||||||
// 获取文件
|
/**
|
||||||
|
* 获取所有文件
|
||||||
|
* @param page 页数
|
||||||
|
* @param num 一页多少文件
|
||||||
|
*/
|
||||||
export const getAllFiles = (page: number, num: number) => {
|
export const getAllFiles = (page: number, num: number) => {
|
||||||
return instance.get<PageResult<File>>("/api/file/getAll", {params: {num, page}});
|
return instance.get<PageResult<File>>("/api/file/getAll", {params: {num, page}});
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
// 上传文件
|
* 上传文件接口
|
||||||
|
* @param options 上传选项(会在el-upload的http-request方法调用时传入)
|
||||||
|
* @param controller 取消控制器(自己创建后传入)
|
||||||
|
*/
|
||||||
export const upload = (options: UploadRequestOptions, controller: AbortController) => {
|
export const upload = (options: UploadRequestOptions, controller: AbortController) => {
|
||||||
const param = new FormData();
|
const param = new FormData();
|
||||||
param.append("file", options.file);
|
param.append("file", options.file);
|
||||||
@ -81,4 +108,62 @@ export const upload = (options: UploadRequestOptions, controller: AbortControlle
|
|||||||
},
|
},
|
||||||
signal: controller.signal
|
signal: controller.signal
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取下载链接
|
||||||
|
* @param id 文件id
|
||||||
|
*/
|
||||||
|
export const getLink = (id: number) => {
|
||||||
|
return instance.get<Result<string>>("/api/file/link", {params: {id}});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 删除文件
|
||||||
|
* @param id 文件id
|
||||||
|
*/
|
||||||
|
export const remove = (id: number) => {
|
||||||
|
return instance.post<Result<boolean>>("/api/file/remove", {id});
|
||||||
|
}
|
||||||
|
const handlerSearchType = (searchType: SearchType): string => {
|
||||||
|
switch (searchType){
|
||||||
|
case SearchType.ID:
|
||||||
|
return "ID"
|
||||||
|
case SearchType.TYPE:
|
||||||
|
return "TYPE"
|
||||||
|
case SearchType.UPLOAD_DAY:
|
||||||
|
return "UPLOAD_DAY"
|
||||||
|
case SearchType.UPLOADER:
|
||||||
|
return "UPLOADER"
|
||||||
|
default:
|
||||||
|
return "FILE_NAME"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 搜索
|
||||||
|
* @param page 页数
|
||||||
|
* @param num 一页多少文件
|
||||||
|
* @param searchType 搜索类型
|
||||||
|
* @param data 搜索数据
|
||||||
|
*/
|
||||||
|
export const search = (page: number, num: number, searchType: SearchType, data: string) => {
|
||||||
|
return instance.get<PageResult<File>>("/api/file/search", {params: {page, num, type: handlerSearchType(searchType), data}});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取访问情况
|
||||||
|
* @param count 获取的天数
|
||||||
|
*/
|
||||||
|
export const getAccessInformation = (count: number) => {
|
||||||
|
return instance.get<AccessInformation[]>("/api/access/get", {params: {count}});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取总访问情况
|
||||||
|
*/
|
||||||
|
export const getTotalAccessInformation = () => {
|
||||||
|
return instance.get<AccessInformation>("/api/access/getAll");
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 检查是否可以上传
|
||||||
|
* @param filename 文件名
|
||||||
|
*/
|
||||||
|
export const checkUpload = (filename: string) => {
|
||||||
|
return instance.get<Result<boolean>>("/api/file/checkUpload", {params: {filename}});
|
||||||
}
|
}
|
Binary file not shown.
Before Width: | Height: | Size: 29 KiB |
17
src/entities/AccessInformation.ts
Normal file
17
src/entities/AccessInformation.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* 访问情况类
|
||||||
|
*/
|
||||||
|
export interface AccessInformation {
|
||||||
|
/**
|
||||||
|
* 总下载量
|
||||||
|
*/
|
||||||
|
totalDownload: number;
|
||||||
|
/**
|
||||||
|
* 总访问量
|
||||||
|
*/
|
||||||
|
totalAccess: number;
|
||||||
|
/**
|
||||||
|
* 日期
|
||||||
|
*/
|
||||||
|
date: string;
|
||||||
|
}
|
@ -1,3 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* 用户类型
|
||||||
|
*/
|
||||||
export enum Auth {
|
export enum Auth {
|
||||||
user, admin
|
/**
|
||||||
|
* 普通用户
|
||||||
|
*/
|
||||||
|
USER,
|
||||||
|
/**
|
||||||
|
* 管理员
|
||||||
|
*/
|
||||||
|
ADMIN,
|
||||||
}
|
}
|
@ -1,10 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* 文件类
|
||||||
|
*/
|
||||||
export interface File {
|
export interface File {
|
||||||
|
/**
|
||||||
|
* 下载数
|
||||||
|
*/
|
||||||
downloadCount: number;
|
downloadCount: number;
|
||||||
|
/**
|
||||||
|
* 文件hash(sha512)
|
||||||
|
*/
|
||||||
hash: string;
|
hash: string;
|
||||||
|
/**
|
||||||
|
* 文件id
|
||||||
|
*/
|
||||||
id: number;
|
id: number;
|
||||||
|
/**
|
||||||
|
* 文件名
|
||||||
|
*/
|
||||||
name: string;
|
name: string;
|
||||||
|
/**
|
||||||
|
* 文件大小(字节为单位)
|
||||||
|
*/
|
||||||
size: number;
|
size: number;
|
||||||
|
/**
|
||||||
|
* 文件类型
|
||||||
|
*/
|
||||||
type: string;
|
type: string;
|
||||||
|
/**
|
||||||
|
* 上传时间
|
||||||
|
*/
|
||||||
uploadTime: string;
|
uploadTime: string;
|
||||||
|
/**
|
||||||
|
* 上传者名称
|
||||||
|
*/
|
||||||
uploaderName: string;
|
uploaderName: string;
|
||||||
}
|
}
|
25
src/entities/SearchType.ts
Normal file
25
src/entities/SearchType.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* 搜索类型
|
||||||
|
*/
|
||||||
|
export enum SearchType {
|
||||||
|
/**
|
||||||
|
* 文件名
|
||||||
|
*/
|
||||||
|
FILE_NAME,
|
||||||
|
/**
|
||||||
|
* 文件ID
|
||||||
|
*/
|
||||||
|
ID,
|
||||||
|
/**
|
||||||
|
* 上传者
|
||||||
|
*/
|
||||||
|
UPLOADER,
|
||||||
|
/**
|
||||||
|
* 上传日期
|
||||||
|
*/
|
||||||
|
UPLOAD_DAY,
|
||||||
|
/**
|
||||||
|
* 文件类型
|
||||||
|
*/
|
||||||
|
TYPE
|
||||||
|
}
|
@ -1,7 +1,19 @@
|
|||||||
import {Auth} from "./Auth";
|
import {Auth} from "./Auth";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户类
|
||||||
|
*/
|
||||||
export interface User {
|
export interface User {
|
||||||
id: string
|
/**
|
||||||
|
* 用户id
|
||||||
|
*/
|
||||||
|
id: number;
|
||||||
|
/**
|
||||||
|
* 用户名
|
||||||
|
*/
|
||||||
name: string;
|
name: string;
|
||||||
|
/**
|
||||||
|
* 用户类型
|
||||||
|
*/
|
||||||
auth: Auth;
|
auth: Auth;
|
||||||
}
|
}
|
@ -3,6 +3,7 @@ import './style.css'
|
|||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import Mobile from './views/AppMobile.vue'
|
import Mobile from './views/AppMobile.vue'
|
||||||
import PC from './views/AppPC.vue'
|
import PC from './views/AppPC.vue'
|
||||||
|
import 'element-plus/dist/index.css';
|
||||||
import {createRouter, createWebHashHistory} from "vue-router";
|
import {createRouter, createWebHashHistory} from "vue-router";
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
|
@ -1,156 +1,380 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<van-config-provider :theme="vantTheme"></van-config-provider>
|
||||||
<div class="MobileHome">
|
<div class="MobileHome">
|
||||||
<!-- 页面主体部分 -->
|
<!-- 页面主体部分 -->
|
||||||
<div class="head">
|
<div class="head">
|
||||||
<!-- 头部区域 -->
|
<!-- 头部区域 -->
|
||||||
<van-cell-group inset class="inputFileName">
|
<van-cell-group inset class="inputFileName">
|
||||||
<!-- 搜索框区域 -->
|
<!-- 搜索框区域 -->
|
||||||
<van-field v-model="inputFileName" center clearable placeholder="请输入文件名称">
|
<van-field v-model="searchInput" center clearable placeholder="请输入文件名称">
|
||||||
<!-- 文件名输入框 -->
|
<!-- 文件名输入框 -->
|
||||||
<template #button>
|
<template #button>
|
||||||
<!-- 搜索按钮 -->
|
<!-- 搜索按钮 -->
|
||||||
<van-button size="small" type="primary">搜索</van-button>
|
<van-button size="small" type="primary" @click="handlerSearch">搜索</van-button>
|
||||||
</template>
|
</template>
|
||||||
</van-field>
|
</van-field>
|
||||||
</van-cell-group>
|
</van-cell-group>
|
||||||
|
<!-- 用户头像 -->
|
||||||
<van-image
|
<van-image
|
||||||
class="userAvatar"
|
class="userAvatar"
|
||||||
width="50"
|
width="50"
|
||||||
height="50"
|
height="50"
|
||||||
src="src/assets/UserAvatar.jpg"
|
:src="userAvatar"
|
||||||
radius="5"
|
radius="5"
|
||||||
@click="toggleUserLogin"
|
@click="imgLoginBox"
|
||||||
/>
|
/>
|
||||||
<!-- 用户头像 -->
|
<van-popup v-model:show="userAvatarLoginShow" round position="top">
|
||||||
|
<!-- 登录/注册弹窗内容 -->
|
||||||
<van-popup v-model:show="userAvatarLoginShow" round position="top" class="userLoginBox">
|
<div class="dialog">
|
||||||
<!-- 登录弹窗 -->
|
<h2 v-if="isLoginMode">登录</h2>
|
||||||
<div class="login-content">
|
<h2 v-else>注册</h2>
|
||||||
<h2>登录/注册</h2>
|
<p v-if="isLoginMode">欢迎回到文件分享站!</p>
|
||||||
<p>欢迎来到文件分享站</p>
|
<p v-else>欢迎加入文件分享站!</p>
|
||||||
<label for="userName">用户名</label>
|
|
||||||
<van-field id="userName" v-model="userName" center placeholder="请输入用户名"/>
|
|
||||||
<!-- 用户名输入框 -->
|
<!-- 用户名输入框 -->
|
||||||
<label for="password">密码</label>
|
<label for="username" class="login-dialog-element">用户名:</label>
|
||||||
<van-field id="password" v-model="userPassword" center type="password" placeholder="请输入用户密码"/>
|
<el-input id="username" class="login-dialog-element" v-model="usernameInput" placeholder="请输入用户名"/>
|
||||||
<!-- 密码输入框 -->
|
<!-- 密码输入框 -->
|
||||||
|
<label for="password" class="login-dialog-element">密码:</label>
|
||||||
|
<el-input id="password" class="login-dialog-element" v-model="userPasswordInput" type="password"
|
||||||
|
placeholder="请输入用户密码"/>
|
||||||
|
<div v-if="!isLoginMode" class="login-dialog-element">
|
||||||
|
<label for="registerType">注册类型:</label>
|
||||||
|
<el-select id="registerType" v-model="registerTypeInput" placeholder="注册类型">
|
||||||
|
<el-option key="1" label="普通用户" :value="Auth.USER"/>
|
||||||
|
<el-option key="2" label="管理员" :value="Auth.ADMIN"/>
|
||||||
|
</el-select>
|
||||||
|
<div v-if="registerTypeInput == Auth.ADMIN">
|
||||||
|
<label for="verifyCode" class="login-dialog-element">邀请码:</label>
|
||||||
|
<el-input id="verifyCode" class="login-dialog-element" v-model="verifyCodeInput" type="password"
|
||||||
|
placeholder="请输入管理员用户邀请码"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<van-button class="userLoginButton" @click="userLogin" type="primary">登录</van-button>
|
<van-button class="user-login-register-button" @click="userLogin" type="primary" v-if="isLoginMode">
|
||||||
|
登录
|
||||||
|
</van-button>
|
||||||
|
<van-button class="user-login-register-button" @click="userEnroll" type="primary" v-else>注册
|
||||||
|
</van-button>
|
||||||
<!-- 登录按钮 -->
|
<!-- 登录按钮 -->
|
||||||
<van-button class="userLoginButton" @click="userEnroll" type="primary">注册后登录</van-button>
|
<van-button class="user-login-register-button" @click="isLoginMode = false;" type="primary"
|
||||||
|
v-if="isLoginMode">切换到注册
|
||||||
|
</van-button>
|
||||||
|
<van-button class="user-login-register-button" @click="isLoginMode = true;" type="primary" v-else>
|
||||||
|
切换到登录
|
||||||
|
</van-button>
|
||||||
<!-- 注册按钮 -->
|
<!-- 注册按钮 -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</van-popup>
|
</van-popup>
|
||||||
|
<!-- 属性弹窗 -->
|
||||||
<van-popup v-model:show="userAvatarLoginShowTools" round position="top" class="userLoginBox">
|
<van-popup v-model:show="userAvatarLoginShowTools" round position="top" class="userLoginBox">
|
||||||
<!-- 登录弹窗 -->
|
<div class="dialog">
|
||||||
<div class="login-content">
|
|
||||||
<h2>个人中心</h2>
|
<h2>个人中心</h2>
|
||||||
<h3>用户属性:</h3>
|
<h3>用户属性:</h3>
|
||||||
<div>
|
<div>
|
||||||
<p class="userNameId">用户ID: {{ userNameToolsId }} </p>
|
<p>用户名称 {{ username }}</p>
|
||||||
<p class="userNameName">用户名称: {{ userNameToolsName }}</p>
|
<p>用户类型:
|
||||||
<p class="userNameType">用户类型:
|
<span v-if="userAuth === Auth.ADMIN">管理员</span>
|
||||||
<span v-if="userNameToolsAuth === 'admin'">管理员</span>
|
<span v-else-if="userAuth === Auth.USER">普通用户</span>
|
||||||
<span v-else-if="userNameToolsAuth === 'user'">普通用户</span>
|
|
||||||
<span v-else>未登录</span>
|
<span v-else>未登录</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<h3>功能区:</h3>
|
<h3>功能区</h3>
|
||||||
<div class="uploadFile">
|
<div class="uploadFile">
|
||||||
<el-upload
|
<div class="button-container" style="display: flex;">
|
||||||
v-model:file-list="fileList"
|
<el-upload
|
||||||
class="upload"
|
class="upload-demo"
|
||||||
action="http://127.0.0.1:8081/api/file/upload"
|
multiple
|
||||||
multiple
|
:http-request="handleUpload"
|
||||||
:on-preview="handlePreview"
|
:before-remove="handleUploadRemove"
|
||||||
:on-remove="handleRemove"
|
:on-success="handleUploadSuccess"
|
||||||
:before-remove="beforeRemove"
|
:before-upload="handleBeforeUpload"
|
||||||
:limit="3"
|
>
|
||||||
:on-exceed="handleExceed"
|
<el-button type="primary">点击上传文件</el-button>
|
||||||
>
|
</el-upload>
|
||||||
<el-button type="primary">点击上传文件</el-button>
|
<el-button type="primary" @click="genVerifyCode" v-if="userAuth == Auth.ADMIN">获取邀请码</el-button>
|
||||||
<el-button type="primary" @click="logout">退出登录</el-button>
|
<el-button type="primary" @click="logout">退出登录</el-button>
|
||||||
<template #tip>
|
</div>
|
||||||
<div class="el-upload__tip">
|
|
||||||
最大文件限制大小:10GB
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-upload>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</van-popup>
|
</van-popup>
|
||||||
|
<!-- 文件详情 -->
|
||||||
|
<van-popup v-model:show="showFileInformation" round>
|
||||||
|
<div class="file-information-popover" v-if="nowSelectedFileInformation">
|
||||||
|
<h2>文件名称:<br><span>{{ nowSelectedFileInformation.name }}</span></h2>
|
||||||
|
<div>
|
||||||
|
<p>文件ID: <span>{{ nowSelectedFileInformation.id }}</span></p>
|
||||||
|
<p>文件类型: <span>{{ nowSelectedFileInformation.type }}</span></p>
|
||||||
|
<p>文件大小: <span>{{ parserByteSize(nowSelectedFileInformation.size) }}</span></p>
|
||||||
|
<p title="点击复制"><a class="file-hash-a" @click="copyFullHash">文件校验值:
|
||||||
|
<span>{{ shortHash(nowSelectedFileInformation.hash) }}</span></a></p>
|
||||||
|
<p>文件上传者: <span>{{ nowSelectedFileInformation.uploaderName }}</span></p>
|
||||||
|
<p>文件上传时间: <span>{{ nowSelectedFileInformation.uploadTime }}</span></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="file-information-popover" v-else>
|
||||||
|
<h2>emm,咱就是说,这个分享站好像有点bug,这个东西好像展示不出来捏:<</h2>
|
||||||
|
</div>
|
||||||
|
</van-popup>
|
||||||
|
<!-- 文件详情 -->
|
||||||
|
<van-popup v-model:show="showFileInformation" round>
|
||||||
|
<div class="file-information-popover" v-if="nowSelectedFileInformation">
|
||||||
|
<h2>文件名称:<span>{{ nowSelectedFileInformation.name }}</span></h2>
|
||||||
|
<div>
|
||||||
|
<p>文件ID: <span>{{ nowSelectedFileInformation.id }}</span></p>
|
||||||
|
<p>文件类型: <span>{{ nowSelectedFileInformation.type }}</span></p>
|
||||||
|
<p>文件大小: <span>{{ parserByteSize(nowSelectedFileInformation.size) }}</span></p>
|
||||||
|
<p title="点击复制"><a class="file-hash-a" @click="copyFullHash">文件校验值:
|
||||||
|
<span>{{ shortHash(nowSelectedFileInformation.hash) }}</span></a></p>
|
||||||
|
<p>文件上传者: <span>{{ nowSelectedFileInformation.uploaderName }}</span></p>
|
||||||
|
<p>文件上传时间: <span>{{ nowSelectedFileInformation.uploadTime }}</span></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="file-information-popover" v-else>
|
||||||
|
<h2>emm,咱就是说,这个分享站好像有点bug,这个东西好像展示不出来捏:<</h2>
|
||||||
|
</div>
|
||||||
|
</van-popup>
|
||||||
</div>
|
</div>
|
||||||
<div class="fileLiteBox">
|
<div class="fileLiteBox">
|
||||||
<el-table :data="nowFileData" border style="width: 100%">
|
<el-table ref="fileListTable" :data="pageFileData" class="files-data-table" border stripe>
|
||||||
<el-table-column prop="id" label="ID" width="60"/>
|
<el-table-column prop="id" label="ID" width="70"/>
|
||||||
<el-table-column prop="name" label="文件名" width="200"/>
|
<el-table-column prop="name" label="文件名称" width="650"/>
|
||||||
<el-table-column prop="type" label="文件格式" width="150"/>
|
<el-table-column prop="type" label="文件格式" width="120"/>
|
||||||
<el-table-column prop="size" label="文件大小" width="100"/>
|
<el-table-column label="文件大小" width="120">
|
||||||
<el-table-column prop="uploaderName" label="上传者" width="100"/>
|
<template #default="scope">{{ parserByteSize(scope.row.size) }}</template>
|
||||||
<el-table-column fixed="right" label="操作" width="100">
|
</el-table-column>
|
||||||
|
<el-table-column prop="uploaderName" label="上传者" width="120"/>
|
||||||
|
<el-table-column fixed="right" label="操作" :width="fileOptionRowWidth">
|
||||||
|
<!-- 操作列模板 -->
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<!-- 列表操作按钮 -->
|
<el-button link type="primary" @click="downloadFile(scope.row.id)">下载</el-button>
|
||||||
<el-button link type="primary" size="small" @click="handleShowDetail();">
|
<el-button link type="primary" @click="handlerFileInformation(scope.row)">详情</el-button>
|
||||||
<!-- 显示详细信息按钮 -->
|
<el-button link type="danger" v-if="userAuth === Auth.ADMIN" @click="removeFile(scope.row.id)">删除
|
||||||
详细
|
|
||||||
</el-button>
|
|
||||||
<el-button link type="primary" size="small" @click="handleDownload();">下载</el-button>
|
|
||||||
<!-- 下载按钮 -->
|
|
||||||
<el-button link type="primary" size="small" @click="handleDelete();" v-if="isAdmin">删除
|
|
||||||
<!-- 删除按钮,仅管理员可见 -->
|
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
<!-- 分页组件 -->
|
||||||
<div class="pagination-container">
|
<div class="pagination-container">
|
||||||
<!-- 分页控件容器 -->
|
|
||||||
<el-pagination
|
<el-pagination
|
||||||
@current-change="fetchFiles"
|
@current-change="handlerPageChange"
|
||||||
:current-page="currentPage"
|
:current-page="currentPage"
|
||||||
:page-size="pageSize"
|
:page-sizes="[19]"
|
||||||
:total="totalFiles"
|
:page-size="19"
|
||||||
layout="prev, pager, next">
|
layout="prev, pager, next"
|
||||||
</el-pagination>
|
:total="totalFileCount"
|
||||||
|
class="pagination"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {onMounted, ref} from "vue";
|
import 'element-plus/theme-chalk/dark/css-vars.css'
|
||||||
import {ElMessage} from "element-plus";
|
import {computed, onBeforeMount, onMounted, ref} from 'vue';
|
||||||
import 'element-plus/es/components/message/style/css';
|
import {useDark, useToggle} from "@vueuse/core"
|
||||||
import {login, register, getAllFiles, Result} from '../api/Requester';
|
import {GridComponent, LegendComponent} from 'echarts/components';
|
||||||
import {User} from "../entities/User";
|
import {LineChart} from 'echarts/charts';
|
||||||
|
import {UniversalTransition} from 'echarts/features';
|
||||||
|
import {CanvasRenderer} from 'echarts/renderers';
|
||||||
|
import * as echarts from 'echarts/core';
|
||||||
|
import {
|
||||||
|
baseUrl,
|
||||||
|
checkUpload,
|
||||||
|
generatorVerifyCode,
|
||||||
|
getAllFiles,
|
||||||
|
getLink,
|
||||||
|
register,
|
||||||
|
remove,
|
||||||
|
Result,
|
||||||
|
search,
|
||||||
|
upload
|
||||||
|
} from "../api/Requester.ts";
|
||||||
|
import {login} from '../api/Requester';
|
||||||
import {AxiosResponse} from "axios";
|
import {AxiosResponse} from "axios";
|
||||||
import {Auth} from "../entities/Auth";
|
import {User} from "../entities/User.ts";
|
||||||
import {File} from "../entities/File";
|
import {UploadFile, UploadRawFile, UploadRequestOptions, ElMessage} from "element-plus";
|
||||||
|
import {Auth} from "../entities/Auth.ts";
|
||||||
|
import {File} from "../entities/File.ts";
|
||||||
|
import {Awaitable} from "element-plus/es/utils";
|
||||||
|
import {UploadAjaxError} from "element-plus/es/components/upload/src/ajax";
|
||||||
|
import {SearchType} from "../entities/SearchType.ts";
|
||||||
|
|
||||||
// TODO: 头部组件定义变量
|
echarts.use([GridComponent, LineChart, CanvasRenderer, UniversalTransition, LegendComponent]);
|
||||||
const inputFileName = ref<string>('');
|
|
||||||
const userAvatarLoginShow = ref<boolean>(false);
|
|
||||||
const userAvatarLoginShowTools = ref<boolean>(false);
|
|
||||||
const userName = ref<string>("");
|
|
||||||
const userPassword = ref<string>("");
|
|
||||||
const isAdmin = ref<boolean>(false); // 是否是管理员
|
|
||||||
|
|
||||||
// TODO: 用户属性
|
// TODO: 用户属性
|
||||||
const userNameToolsId = ref<number>(0);
|
const username = computed(() => {
|
||||||
const userNameToolsName = ref<string>("未登录");
|
const username = sessionStorage.getItem("username");
|
||||||
const userNameToolsAuth = ref<string>("未登录");
|
if (username) {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
return "未登录"
|
||||||
|
})
|
||||||
|
const userAuth = computed(() => {
|
||||||
|
const authStorage = sessionStorage.getItem("auth");
|
||||||
|
switch (authStorage) {
|
||||||
|
case "admin":
|
||||||
|
return Auth.ADMIN;
|
||||||
|
case "user":
|
||||||
|
return Auth.USER;
|
||||||
|
default:
|
||||||
|
return "未登录";
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// TODO: 分页属性配置
|
// TODO: 头部组件
|
||||||
|
// 搜索类型
|
||||||
|
const searchType = ref<SearchType>(SearchType.FILE_NAME);
|
||||||
|
const searchInput = ref<string>("");
|
||||||
|
// 用户头像
|
||||||
|
const userAvatar = 'UserAvatar.jpg'
|
||||||
|
// 用户账号密码
|
||||||
|
const usernameInput = ref<string>('');
|
||||||
|
const userPasswordInput = ref<string>('');
|
||||||
|
// 用户登录弹窗
|
||||||
|
const userAvatarLoginShow = ref<boolean>(false);
|
||||||
|
// 用户属性弹窗
|
||||||
|
const userAvatarLoginShowTools = ref<boolean>(false);
|
||||||
|
// 用户登录/注册窗口模式
|
||||||
|
const isLoginMode = ref<boolean>(true);
|
||||||
|
// 注册类型
|
||||||
|
const registerTypeInput = ref<Auth>(Auth.USER);
|
||||||
|
// 邀请码
|
||||||
|
const verifyCodeInput = ref<string>("");
|
||||||
|
// 展示文件详细信息
|
||||||
|
const nowSelectedFileInformation = ref<File>();
|
||||||
|
// 下载文件
|
||||||
|
const handlerFileInformation = (file: File) => {
|
||||||
|
showFileInformation.value = true;
|
||||||
|
nowSelectedFileInformation.value = file;
|
||||||
|
}
|
||||||
|
// 删除文件
|
||||||
|
const downloadFile = (id: number) => {
|
||||||
|
getLink(id).then((res: AxiosResponse<Result<string>>) => {
|
||||||
|
window.open(baseUrl + "/api/file/download/" + res.data.data);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const removeFile = (id: number) => {
|
||||||
|
if (userAuth.value != Auth.ADMIN) {
|
||||||
|
ElMessage.error({
|
||||||
|
message: '呜~你是怎么发现这个按钮的,可惜哦~不能用哦~',
|
||||||
|
grouping: true,
|
||||||
|
})
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
remove(id).then((res: AxiosResponse<Result<boolean>>) => {
|
||||||
|
if (res.data.data) {
|
||||||
|
ElMessage.success({
|
||||||
|
message: '删除成功!',
|
||||||
|
grouping: true,
|
||||||
|
});
|
||||||
|
showAllFiles()
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ElMessage.error({
|
||||||
|
message: '删除失败,请查看后台日志处理!',
|
||||||
|
grouping: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 主题切换
|
||||||
|
const isDark = useDark()
|
||||||
|
const toggleDark = useToggle(isDark);
|
||||||
|
const vantTheme = ref<"light" | "dark">("light");
|
||||||
|
// 自动主题
|
||||||
|
const initTheme = () => {
|
||||||
|
const now = new Date();
|
||||||
|
const hour = now.getHours();
|
||||||
|
if (hour < 7 || hour > 17) {
|
||||||
|
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 155;
|
||||||
|
default:
|
||||||
|
return 110;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 分页相关数据
|
||||||
const currentPage = ref<number>(1);
|
const currentPage = ref<number>(1);
|
||||||
const pageSize = ref<number>(18);
|
const totalFileCount = ref<number>(0);
|
||||||
const nowFileData = ref<File[]>([]);
|
const pageFileData = ref<File[]>([]);
|
||||||
const totalFiles = ref<number>(0);
|
const isSearchType = ref<boolean>(false);
|
||||||
|
const handlerSearch = () => {
|
||||||
|
isSearchType.value = true;
|
||||||
|
showAllFiles();
|
||||||
|
}
|
||||||
|
const showAllFiles = () => {
|
||||||
|
if (isSearchType.value) {
|
||||||
|
search(currentPage.value, 19, searchType.value, searchInput.value).then((res) => {
|
||||||
|
totalFileCount.value = res.data.data.total;
|
||||||
|
pageFileData.value = res.data.data.data;
|
||||||
|
}).catch(() => {
|
||||||
|
ElMessage.error({
|
||||||
|
message: '搜索失败!',
|
||||||
|
grouping: true,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getAllFiles(currentPage.value, 19).then((res) => {
|
||||||
|
totalFileCount.value = res.data.data.total;
|
||||||
|
pageFileData.value = res.data.data.data;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const parserByteSize = (byte: number): string => {
|
||||||
|
if (byte < 1024) {
|
||||||
|
return byte + 'B';
|
||||||
|
}
|
||||||
|
if (byte < 1024 * 1024) {
|
||||||
|
return (byte / 1024).toFixed(2) + "KB";
|
||||||
|
}
|
||||||
|
if (byte < 1024 * 1024 * 1024) {
|
||||||
|
return (byte / 1024 / 1024).toFixed(2) + "MB";
|
||||||
|
}
|
||||||
|
if (byte < 1024 * 1024 * 1024 * 1024) {
|
||||||
|
return (byte / 1024 / 1024 / 1024).toFixed(2) + "GB";
|
||||||
|
}
|
||||||
|
return (byte / 1024 / 1024 / 1024 / 1024).toFixed(2) + "TB";
|
||||||
|
}
|
||||||
|
const shortHash = (hash: string): string => {
|
||||||
|
return hash.substring(0, 10) + '......' + hash.substring(118, 128)
|
||||||
|
}
|
||||||
|
const copyFullHash = () => {
|
||||||
|
if (nowSelectedFileInformation.value) {
|
||||||
|
navigator.clipboard.writeText(nowSelectedFileInformation.value.hash);
|
||||||
|
ElMessage.success({
|
||||||
|
message: '复制成功!',
|
||||||
|
grouping: true,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
ElMessage.error({
|
||||||
|
message: '你是怎么点到这个按钮的???',
|
||||||
|
grouping: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: 用户登录弹窗
|
}
|
||||||
const toggleUserLogin = () => {
|
// 处理当前页变化
|
||||||
if (sessionStorage.getItem("userInfo") || localStorage.getItem("userInfo")) {
|
const handlerPageChange = (val: number) => {
|
||||||
|
currentPage.value = val;
|
||||||
|
showAllFiles();
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: 用户点击事件
|
||||||
|
// 点击用户头像弹出登录窗口
|
||||||
|
const imgLoginBox = () => {
|
||||||
|
if (isLogin.value) {
|
||||||
// 如果本地存储中有用户信息,即用户已登录
|
// 如果本地存储中有用户信息,即用户已登录
|
||||||
// 显示用户信息窗口并隐藏登录窗口
|
// 显示用户信息窗口并隐藏登录窗口
|
||||||
userAvatarLoginShowTools.value = true;
|
userAvatarLoginShowTools.value = true;
|
||||||
@ -160,217 +384,211 @@ const toggleUserLogin = () => {
|
|||||||
userAvatarLoginShow.value = !userAvatarLoginShow.value;
|
userAvatarLoginShow.value = !userAvatarLoginShow.value;
|
||||||
userAvatarLoginShowTools.value = false;
|
userAvatarLoginShowTools.value = false;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
// 点击登录按钮
|
||||||
|
|
||||||
// TODO: 用户配置
|
|
||||||
const logout = () => {
|
|
||||||
// 清除本地存储中的用户信息
|
|
||||||
localStorage.removeItem("userInfo");
|
|
||||||
sessionStorage.removeItem("userInfo");
|
|
||||||
|
|
||||||
// 刷新页面
|
|
||||||
window.location.reload();
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: 用户登录接口
|
|
||||||
const userLogin = () => {
|
const userLogin = () => {
|
||||||
// 清理本地cookie
|
// 清理本地cookie
|
||||||
localStorage.removeItem("userInfo");
|
sessionStorage.clear();
|
||||||
sessionStorage.removeItem("userInfo");
|
|
||||||
|
|
||||||
// 用户登录函数
|
// 用户登录函数
|
||||||
if (userName.value == "" || userPassword.value == "") {
|
if (usernameInput.value == "" || userPasswordInput.value == "") {
|
||||||
ElMessage.error("用户名密码不能为空");
|
ElMessage.error({
|
||||||
localStorage.removeItem("userInfo");
|
message: '用户名密码不能为空',
|
||||||
sessionStorage.removeItem("userInfo");
|
grouping: true,
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
login(userName.value, userPassword.value)
|
// 调用登录接口
|
||||||
|
login(usernameInput.value, userPasswordInput.value)
|
||||||
.then((res: AxiosResponse<Result<User>>) => {
|
.then((res: AxiosResponse<Result<User>>) => {
|
||||||
// 发送登录请求
|
// 发送登录请求
|
||||||
if (res.data.status == 200) {
|
if (res.data.status == 200) {
|
||||||
// 登录成功
|
const username = res.data.data.name;
|
||||||
// 存储用户信息到sessionStorage
|
sessionStorage.setItem("username", username);
|
||||||
const userInfo = {
|
sessionStorage.setItem("auth", res.data.data.auth.toString());
|
||||||
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);
|
|
||||||
userNameToolsId.value = Number(res.data.data.id);
|
|
||||||
userNameToolsName.value = String(res.data.data.name);
|
|
||||||
userNameToolsAuth.value = String(res.data.data.auth)
|
|
||||||
// 延迟一段时间后显示用户信息窗口
|
// 延迟一段时间后显示用户信息窗口
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
toggleUserLogin();
|
imgLoginBox();
|
||||||
}, 1000); // 1000毫秒(1秒)延迟示例
|
}, 1000); // 1000毫秒(1秒)延迟示例
|
||||||
|
ElMessage.success({
|
||||||
ElMessage.success("登录成功!");
|
message: '登录成功!',
|
||||||
|
grouping: true,
|
||||||
|
});
|
||||||
|
window.location.reload()
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error("登录失败,用户名密码错误!");
|
ElMessage.error({
|
||||||
localStorage.removeItem("userInfo");
|
message: '登录失败,用户名密码错误!',
|
||||||
sessionStorage.removeItem("userInfo");
|
grouping: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(() => {
|
|
||||||
ElMessage.error("登录失败,用户名密码错误!");
|
|
||||||
localStorage.removeItem("userInfo");
|
|
||||||
sessionStorage.removeItem("userInfo");
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
// 注销登陆
|
||||||
|
const logout = () => {
|
||||||
// 在页面加载时检查本地存储中的用户信息
|
// 提醒弹窗
|
||||||
let checkedStorage = false;
|
ElMessage.success({
|
||||||
const checkLocalStorageUserInfo = () => {
|
message: '退出成功!',
|
||||||
if (checkedStorage) {
|
grouping: true,
|
||||||
return; // 如果已经检查过,不再重复执行
|
})
|
||||||
}
|
// 清除本地存储中的用户信息
|
||||||
const userInfoString = localStorage.getItem("userInfo");
|
sessionStorage.clear();
|
||||||
if (userInfoString) {
|
userAvatarLoginShowTools.value = false;
|
||||||
// 解析用户信息
|
window.location.reload()
|
||||||
const userInfo = JSON.parse(userInfoString);
|
|
||||||
userName.value = userInfo.userName;
|
|
||||||
userPassword.value = userInfo.userPassword;
|
|
||||||
|
|
||||||
// 验证用户信息
|
|
||||||
verifyUserInfo();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
// 在页面加载时检查sessionStorage中的用户信息
|
// 用户注册并登录接口
|
||||||
const checkSessionStorageUserInfo = () => {
|
|
||||||
if (checkedStorage) {
|
|
||||||
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);
|
|
||||||
userNameToolsId.value = Number(res.data.data.id);
|
|
||||||
userNameToolsName.value = String(res.data.data.name);
|
|
||||||
userNameToolsAuth.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");
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: 用户注册接口
|
|
||||||
const userEnroll = () => {
|
const userEnroll = () => {
|
||||||
// 用户注册函数
|
// 用户注册函数
|
||||||
if (userName.value == '' || userPassword.value == '') {
|
if (usernameInput.value == '' || userPasswordInput.value == '') {
|
||||||
ElMessage.error("用户名密码不能为空")
|
ElMessage.error({
|
||||||
|
message: '用户名密码不能为空',
|
||||||
|
grouping: true,
|
||||||
|
})
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
register(userName.value, userPassword.value, Auth.user).then((res) => {
|
register(usernameInput.value, userPasswordInput.value, registerTypeInput.value, verifyCodeInput.value).then((res) => {
|
||||||
switch (res.data.status) {
|
switch (res.data.status) {
|
||||||
case 251:
|
case 251:
|
||||||
ElMessage.error("邀请码错误!");
|
ElMessage.error({
|
||||||
|
message: '邀请码错误!',
|
||||||
|
grouping: true,
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
case 501:
|
case 501:
|
||||||
ElMessage.error("存在同名用户!");
|
ElMessage.error({
|
||||||
|
message: '存在同名用户!',
|
||||||
|
grouping: true,
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
case 200:
|
case 200:
|
||||||
ElMessage.success("注册成功");
|
ElMessage.success({
|
||||||
login(userName.value, userPassword.value)
|
message: '注册成功',
|
||||||
.then((res: AxiosResponse<Result<User>>) => {
|
grouping: true,
|
||||||
if (res.data.status === 200) {
|
});
|
||||||
console.log(res.data.data.name, res.data.data.id, res.data.data.auth);
|
sessionStorage.setItem("username", res.data.data.name);
|
||||||
userNameToolsId.value = Number(res.data.data.id);
|
sessionStorage.setItem("auth", res.data.data.auth.toString());
|
||||||
userNameToolsName.value = String(res.data.data.name);
|
setTimeout(() => {
|
||||||
userNameToolsAuth.value = String(res.data.data.auth)
|
imgLoginBox();
|
||||||
ElMessage.success("登录成功!");
|
}, 1000);
|
||||||
userAvatarLoginShowTools.value = true; // 验证成功,显示用户信息窗口
|
window.location.reload()
|
||||||
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");
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ElMessage.error("无法注册!");
|
ElMessage.error({
|
||||||
|
message: '无法注册!',
|
||||||
|
grouping: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
// TODO: 获取列表文件接口
|
* 获取管理员验证码
|
||||||
const fetchFiles = (current?: number) => {
|
*/
|
||||||
if (current) {
|
const genVerifyCode = () => {
|
||||||
currentPage.value = current;
|
if (userAuth.value != Auth.ADMIN) {
|
||||||
|
ElMessage.error({
|
||||||
|
message: '呜~你是怎么发现这个按钮的,可惜哦~不能用哦~',
|
||||||
|
grouping: true,
|
||||||
|
})
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
getAllFiles(currentPage.value, pageSize.value).then((res) => {
|
generatorVerifyCode().then((res: AxiosResponse<Result<string>>) => {
|
||||||
nowFileData.value = res.data.data.data;
|
ElMessage.success("已成功获取到邀请码:" + res.data.data + ",已复制到剪切板,有效期:15分钟");
|
||||||
totalFiles.value = res.data.data.total;
|
navigator.clipboard.writeText(res.data.data);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
const abortControllers = ref<Map<string, AbortController>>(new Map());
|
||||||
// TODO: 上传文件
|
// 是否登录
|
||||||
|
const isLogin = computed(() => sessionStorage.getItem("authorization") != null)
|
||||||
// TODO: 查看文件属性
|
/**
|
||||||
const handleShowDetail = () => {
|
* 处理上传任务删除
|
||||||
console.log("查看文件属性接口");
|
* @param uploadFile 上传的文件
|
||||||
|
*/
|
||||||
|
const handleUploadRemove = (uploadFile: UploadFile): Awaitable<boolean> => {
|
||||||
|
if (uploadFile.status !== "uploading") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const name = uploadFile.raw?.name as string;
|
||||||
|
const controller = abortControllers.value.get(name);
|
||||||
|
if (controller) {
|
||||||
|
controller.abort("user");
|
||||||
|
ElMessage.success({
|
||||||
|
message: '成功取消!',
|
||||||
|
grouping: true,
|
||||||
|
})
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 处理上传成功
|
||||||
|
* @param _ 无用变量
|
||||||
|
* @param uploadFile 上传的文件
|
||||||
|
*/
|
||||||
|
const handleUploadSuccess = (_: never, uploadFile: UploadFile): void => {
|
||||||
|
ElMessage.success("文件" + uploadFile.raw?.name + "上传成功!");
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 上传前的预处理
|
||||||
|
* @param rawFile 上传的文件
|
||||||
|
*/
|
||||||
|
const handleBeforeUpload = (rawFile: UploadRawFile): Promise<unknown> => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!isLogin.value) {
|
||||||
|
ElMessage.error({
|
||||||
|
message: '未登录,无法上传!',
|
||||||
|
grouping: true,
|
||||||
|
});
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
if (abortControllers.value.has(rawFile.name)) {
|
||||||
|
ElMessage.error("文件:" + rawFile.name + "上传失败,已存在同名文件正在上传")
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
checkUpload(rawFile.name).then((res: AxiosResponse<Result<boolean>>) => {
|
||||||
|
if (res.data.data) {
|
||||||
|
resolve(res.data.data);
|
||||||
|
} else {
|
||||||
|
ElMessage.error("文件:" + rawFile.name + "上传失败,已存在同名文件");
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 处理上传请求
|
||||||
|
* @param options 上传设置(包括上传的文件等)
|
||||||
|
*/
|
||||||
|
const handleUpload = (options: UploadRequestOptions): XMLHttpRequest | Promise<unknown> => {
|
||||||
|
const abortController = new AbortController();
|
||||||
|
abortControllers.value.set(options.file.name, abortController);
|
||||||
|
let promise = upload(options, abortController);
|
||||||
|
promise.then((response: AxiosResponse<Result<File>>) => {
|
||||||
|
if (response.data.status == 200) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (response.data.status == 401) {
|
||||||
|
ElMessage.error("文件:" + options.file.name + "上传失败,文件已存在!");
|
||||||
|
options.onError(new UploadAjaxError("文件已存在", 401, options.method, options.action));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ElMessage.error("文件:" + options.file.name + "上传失败," + response.data.message);
|
||||||
|
options.onError(new UploadAjaxError(response.data.message, response.data.status, options.method, options.action));
|
||||||
|
}).catch((error) => {
|
||||||
|
options.onError(error)
|
||||||
|
}).finally(() => {
|
||||||
|
abortControllers.value.delete(options.file.name);
|
||||||
|
});
|
||||||
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: 文件下载
|
// TODO: 页面主题
|
||||||
const handleDownload = () => {
|
onBeforeMount(() => {
|
||||||
console.log("download");
|
initTheme();
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: 删除文件
|
|
||||||
const handleDelete = () => {
|
|
||||||
console.log("delete");
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: 实时更新
|
|
||||||
onMounted(() => {
|
|
||||||
fetchFiles();
|
|
||||||
checkSessionStorageUserInfo();
|
|
||||||
checkLocalStorageUserInfo();
|
|
||||||
checkedStorage = true;
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// TODO: onMounted
|
||||||
|
onMounted(() => {
|
||||||
|
showAllFiles();
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@ -378,7 +596,6 @@ onMounted(() => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: #f0f0f0; /* 头部样式,包括布局和背景颜色 */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.inputFileName {
|
.inputFileName {
|
||||||
@ -395,7 +612,6 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.userLoginBox {
|
.userLoginBox {
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
padding: 20px; /* 登录弹窗样式 */
|
padding: 20px; /* 登录弹窗样式 */
|
||||||
}
|
}
|
||||||
@ -419,10 +635,6 @@ onMounted(() => {
|
|||||||
margin-top: 20px; /* 按钮区域样式 */
|
margin-top: 20px; /* 按钮区域样式 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.userLoginButton {
|
|
||||||
width: 120px; /* 登录注册按钮样式 */
|
|
||||||
}
|
|
||||||
|
|
||||||
.fileLiteBox {
|
.fileLiteBox {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
@ -435,4 +647,18 @@ onMounted(() => {
|
|||||||
text-align: center; /* 文本水平居中对齐 */
|
text-align: center; /* 文本水平居中对齐 */
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dialog {
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-information-popover {
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between; /* 或其他值如 center, space-around 等 */
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
File diff suppressed because it is too large
Load Diff
@ -10,9 +10,10 @@
|
|||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
"allowImportingTsExtensions": true,
|
"allowImportingTsExtensions": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": false,
|
||||||
"noEmit": true,
|
"noEmit": false,
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
|
"outDir": "dist",
|
||||||
|
|
||||||
/* Linting */
|
/* Linting */
|
||||||
"strict": true,
|
"strict": true,
|
||||||
@ -20,6 +21,13 @@
|
|||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"noFallthroughCasesInSwitch": true
|
"noFallthroughCasesInSwitch": true
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
"src/**/*.d.ts",
|
||||||
|
"src/**/*.tsx",
|
||||||
|
"src/**/*.vue",
|
||||||
|
"auto-imports.d.ts",
|
||||||
|
"electron/*.ts"
|
||||||
|
],
|
||||||
"references": [{ "path": "./tsconfig.node.json" }]
|
"references": [{ "path": "./tsconfig.node.json" }]
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,9 @@ export default defineConfig({
|
|||||||
}),
|
}),
|
||||||
Components({
|
Components({
|
||||||
resolvers: [
|
resolvers: [
|
||||||
ElementPlusResolver(),
|
ElementPlusResolver({
|
||||||
|
importStyle: "css", // 确保样式也被自动导入
|
||||||
|
}),
|
||||||
VantResolver(),
|
VantResolver(),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user