feat: 上传前判断大小、新文件插入第一位

This commit is contained in:
lan
2024-06-15 17:27:28 +08:00
parent 4dfb75204d
commit c6fe556e76
15 changed files with 193 additions and 18 deletions
+2 -1
View File
@@ -13,6 +13,7 @@ default_value = {
'file_storage': 'local',
'name': '文件快递柜-FileCodeBox',
'description': '开箱即用的文件快传系统',
'page_explain': '根据《中华人民共和国网络安全法》、《中华人民共和国刑法》、《中华人民共和国治安管理处罚法》等相关规定。 传播或存储违法、违规内容,会受到相关处罚,严重者将承担刑事责任。请勿上传非法文件,本站坚决配合相关部门,确保网络内容的安全,和谐,打造绿色网络环境。',
'keywords': 'FileCodeBox, 文件快递柜, 口令传送箱, 匿名口令分享文本, 文件',
'max_save_seconds': 0,
's3_access_key_id': '',
@@ -57,7 +58,7 @@ class Settings:
for line in f.readlines():
key, value = line.strip().split('=', maxsplit=1)
# 将字符串转换为原本的类型
if not key.startswith('opendal_') and isinstance(default_value[key], int):
if key and not key.startswith('opendal_') and isinstance(default_value.get(key, ''), int):
value = int(value)
default_value[key] = value
+12
View File
@@ -1,5 +1,17 @@
<script setup lang="ts">
import { onMounted } from "vue";
import { request } from "@/utils/request";
onMounted(() => {
request({
url:'/',
method:'post'
}).then((res:any)=>{
if (res.code === 200) {
localStorage.setItem('config', JSON.stringify(res.detail));
}
})
});
</script>
<template>
+17 -1
View File
@@ -5,7 +5,10 @@ import { request } from "@/utils/request";
import { useFileDataStore } from "@/stores/fileData";
import { useFileBoxStore } from "@/stores/fileBox";
import { useI18n } from 'vue-i18n'
import { useConfigStore } from "@/stores/config";
import { ElMessage } from "element-plus";
const { config } = useConfigStore();
const { t } = useI18n()
const fileBoxStore = useFileBoxStore();
const fileStore = useFileDataStore();
@@ -38,6 +41,17 @@ const handleOnChangeFileList = (file: any) => {
const handleHttpRequest = (options: any) => {
fileBoxStore.showFileBox = true;
const formData = new FormData();
if (options.file.size > config.uploadSize) {
fileStore.shareData.forEach((file: any) => {
if (file.uid === options.file.uid) {
ElMessage.error(t('msg.fileOverSize'));
file.status = 'fail';
file.code = t('msg.fileOverSize');
fileStore.save();
}
});
return;
}
formData.append('file', options.file);
formData.append('expire_value', props.shareData.expireValue);
formData.append('expire_style', props.shareData.expireStyle);
@@ -63,6 +77,7 @@ const handleHttpRequest = (options: any) => {
file.status = 'success';
file.text = data.text;
file.code = data.code;
ElMessage.success(t('msg.fileUploadSuccess'));
fileStore.save();
}
});
@@ -70,7 +85,8 @@ const handleHttpRequest = (options: any) => {
fileStore.shareData.forEach((file: any) => {
if (file.uid === options.file.uid) {
file.status = 'fail';
file.code = '上传失败';
file.code = t('msg.fileUploadFail');
ElMessage.error(t('msg.fileUploadFail'));
fileStore.save();
}
});
+1
View File
@@ -50,6 +50,7 @@ export default {
name: 'Website Name',
description: 'Website Description',
keywords: 'Keywords',
explain:'Use Explain',
uploadlimit:'Upload Limit',
errorlimit:'Error Limit',
background: 'Background Image',
+1 -1
View File
@@ -1,7 +1,7 @@
import { createI18n } from 'vue-i18n' //引入vue-i18n组件
import messages from './index'
const language = (
navigator.language || 'zh'
navigator.language || 'zh_cn'
).toLowerCase();
const lang = (localStorage.getItem('language') || language).replace(/-/, '_');
const i18n = createI18n({
+5 -3
View File
@@ -1,9 +1,11 @@
import zh_cn from './zh_cn';
import zh from './zh';
import en from './en';
import zh_tw from './zh-tw'
import zh_tw from './zh_tw'
export default {
zh,
zh_cn,
en,
zh_tw
zh_tw,
zh
}
+5
View File
@@ -32,6 +32,7 @@ export default {
copySuccess: '复制成功',
inputNotEmpty: '请输入五位取件码',
sendFileBox: '寄件箱',
ok:'确定',
receiveFileBox: '收件箱',
textDetail: '文本详情',
copy: '复 制',
@@ -50,6 +51,7 @@ export default {
name: '网站名称',
description: '网站描述',
uploadlimit: '上传限制',
explain:'界面说明',
errorlimit: '错误限制',
keywords: '关键词',
background: '背景图片',
@@ -109,5 +111,8 @@ export default {
loginSuccess: '登录成功',
loginError: '登录失败',
}
},
msg:{
fileOverSize: '文件过大',
}
};
+119
View File
@@ -0,0 +1,119 @@
export default {
send: {
disclaimers:'免责声明',
prompt1: '将文字、文件拖、粘贴到此处,或 ',
prompt2: '天数<7或限制次数(24h后删除)',
prompt3: '请输入您要寄出的文本,支持MarkDown格式',
share: '分享',
textShare: '文本分享',
clickUpload: '点击上传',
pleaseInputExpireValue: '请输入有效期',
expireStyle: '过期方式',
expireData: {
day: '天数',
hour: '小时',
forever: '永久',
minute: '分钟',
count: '次数'
},
expireValue: {
day: '天',
hour: '时',
minute: '分',
count: '次'
},
fileType: {
file: '文件',
text: '文本'
}
},
fileBox: {
copySuccess: '复制成功',
inputNotEmpty: '请输入五位取件码',
sendFileBox: '寄件箱',
ok:'确定',
receiveFileBox: '收件箱',
textDetail: '文本详情',
copy: '复 制',
close: '关 闭',
delete: '删 除',
download: '点 击 下 载',
detail: '查 看 详 情',
copyLink: '复制链接',
},
admin: {
about: {
source1: '本项目开源于Github',
source2: 'FileCodeBox'
},
settings: {
name: '网站名称',
description: '网站描述',
uploadlimit: '上传限制',
explain:'界面说明',
errorlimit: '错误限制',
keywords: '关键词',
background: '背景图片',
admin_token: '管理密码',
uploadSize: '文件大小',
uploadSizeNote: '最大文件大小,单位:Bytes),1mb=1 * 1024 * 1024',
openUpload: {
title: '开启上传',
open: '开启游客上传',
close: '关闭游客上传',
note: '关闭之后需要登录后台方可上传',
},
file_storage: {
title: '存储引擎',
local: '本地存储',
s3: 'S3存储',
note: '更新后需要重启FileCodeBox',
},
mei: '每',
minute: '分钟',
upload: '上传',
files: '个文件',
allow: '允许',
errors: '次错误',
save: '保存',
saveSuccess: '保存成功',
},
fileView: {
code: '取件码',
prefix: '文件前缀',
suffix: '文件后缀',
text: '文本',
used_count: '已使用次数',
expired_count: '可用次数',
size: '文件大小',
expired_at: '过期时间',
file_path: '文件路径',
action: '操作',
delete: '删除',
delete_success: '删除成功',
forever: '永久有效',
unlimited_count: '不限次数',
download: '下载',
download_fail: '文件保存失败,请稍后再试~',
},
menu: {
fileManage: '文件管理',
systemSetting: '系统设置',
about: '关于我们',
color: '颜色模式',
signout: '退出登录',
},
login: {
managePassword: '管理密码',
passwordNotEmpty: '密码不能为空',
login: '登 录',
loginSuccess: '登录成功',
loginError: '登录失败',
}
},
msg:{
fileOverSize: '文件过大',
fileUploadFail: '上传失败',
fileUploadSuccess: '上传成功',
}
};
@@ -50,6 +50,7 @@ export default {
name: '網站名稱',
description: '網站描述',
uploadlimit: '上傳限制',
explain:'介面說明',
errorlimit: '錯誤限制',
keywords: '關鍵詞',
background: '背景圖片',
+7
View File
@@ -0,0 +1,7 @@
import { defineStore } from 'pinia';
import {ref} from "vue";
export const useConfigStore = defineStore('config', () => {
const config:any = ref(JSON.parse(localStorage.getItem('config') || '{}') || {}); // 配置
return { config };
});
+2 -2
View File
@@ -9,12 +9,12 @@ export const useFileDataStore = defineStore('fileData', () => {
localStorage.setItem('shareData', JSON.stringify(shareData));
}
function addReceiveData(data:any) {
receiveData.push(data);
receiveData.unshift(data);
save();
}
function addShareData(data:any) {
shareData.push(data);
shareData.unshift(data);
save();
}
+1 -3
View File
@@ -114,19 +114,17 @@ async function saveFileByElementA(fileBlob: Blob, filename: string) {
window.URL.revokeObjectURL(downloadUrl);
document.body.removeChild(link);
}
async function saveFileByWebApi(fileBlob: Blob, filename: string) {
// 创建一个新句柄。
// @ts-ignore
const newHandle = await window.showSaveFilePicker({
suggestedName: filename,
});
// 创建一个 FileSystemWritableFileStream 用于写入。
const writableStream = await newHandle.createWritable();
// 写入我们的文件。
await writableStream.write(fileBlob);
// 关闭文件并将内容写入磁盘。
await writableStream.close();
}
+6 -2
View File
@@ -10,7 +10,10 @@
<el-input v-model="config.keywords" />
</el-form-item>
<el-form-item size="large" :label="t('admin.settings.background')">
<el-input v-model="config.background" />
<el-input v-model="config.background" placeholder="url" />
</el-form-item>
<el-form-item size="large" :label="t('admin.settings.explain')">
<el-input type="textarea" v-model="config.page_explain" placeholder="explain" />
</el-form-item>
<el-form-item size="large" :label="t('admin.settings.admin_token')">
<el-input type="password" v-model="config.admin_token" />
@@ -109,6 +112,7 @@ const config = ref({
uploadMinute: 1,
s3_access_key_id: '',
background: '',
page_explain:'',
s3_secret_access_key: '',
aws_session_token: '',
s3_signature_version: '',
@@ -153,7 +157,7 @@ const submitSave = () => {
font-size: 1rem;
letter-spacing: 0.4rem;
}
small{
small,.el-form-item__content{
color: #909399;
margin-left: 0.4rem;
}
+5 -5
View File
@@ -17,13 +17,13 @@ const input_status = reactive({
'readonly': false,
'loading': false,
})
import { useI18n } from 'vue-i18n'
import { useConfigStore } from "@/stores/config";
const { config } = useConfigStore()
const noDialog = ()=>{
ElMessageBox.alert(t('send.alert'), t('send.disclaimers'), {
confirmButtonText: '确定',
callback: () => {
}
ElMessageBox.alert(config.explain, t('send.disclaimers'), {
confirmButtonText: t('fileBox.ok'),
});
}
const { t } = useI18n()
+9
View File
@@ -12,6 +12,7 @@ from tortoise.contrib.fastapi import register_tortoise
from apps.base.views import share_api
from apps.admin.views import admin_api
from core.response import APIResponse
from core.settings import data_root, settings, BASE_DIR
from core.tasks import delete_expire_files
from core.utils import max_save_times_desc
@@ -88,6 +89,14 @@ async def index():
, media_type='text/html', headers={'Cache-Control': 'no-cache'})
@app.post('/')
async def get_config():
return APIResponse(detail={
'explain': settings.page_explain,
'uploadSize': settings.uploadSize,
})
if __name__ == '__main__':
import uvicorn