Files
filecodebox/templates/index.html
T
2023-02-28 17:22:49 +08:00

496 lines
20 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="/static/asserts/index.css">
<link rel="shortcut icon" href="/static/asserts/favicon.ico" type="image/x-icon"/>
<title>{{title}}</title>
<meta name="description" content="{{description}}"/>
<meta name="keywords" content="{{keywords}}"/>
<meta name="generator" content="FileCodeBox"/>
<meta name="template" content="V1.6 Beta"/>
<style>
body {
background: #f5f5f5;
}
.qu .el-button {
width: 100px;
height: 100px;
margin: 0.2rem;
font-size: 30px;
font-weight: bold;
}
.el-icon-circle-close::before {
font-size: 26px !important;
line-height: 128px;
}
.qu .el-input__inner {
height: 100px;
margin: 1rem 0;
font-size: 30px;
font-weight: bold;
border-radius: 20px;
}
.el-card {
border-radius: 20px;
}
@media (prefers-color-scheme: dark) {
body {
background-color: #18181c;
}
.el-card, .el-textarea__inner, .el-upload-dragger {
border-radius: 20px;
border: 1px solid transparent;
background-color: rgba(255, 255, 255, 0.1);
box-shadow: 5px 5px 0 0 rgba(0, 0, 0, 0.2);
}
#app * {
color: #ccc !important;
}
.el-input-group__prepend, .el-input__inner, .el-input-group__append, .el-empty__description, .el-select-dropdown, .el-button {
border: 1px solid transparent;
background-color: rgba(0, 0, 0, 0.2);
}
.el-drawer, #el-drawer__title, .el-drawer__body, .el-drawer__wrapper {
background-color: rgba(0, 0, 0, 0.5);
border: 1px solid transparent;
}
}
</style>
<script src="/static/asserts/vue.min.js"></script>
<script src="/static/asserts/index.js"></script>
</head>
<body>
<div id="app" style="text-align: center">
<el-row v-if="pageNum === 0" class="qu" style="max-width:400px;margin: 4rem auto 0 auto">
<el-card class="glass" style="padding-bottom: 1rem">
<el-col :span="24">
<el-input round autofocus @change="changeInput" clearable v-model:value="code" maxlength="5"
:disabled="inputDisable" placeholder="请输入五位取件码">
</el-input>
</el-col>
<el-col :span=8>
<el-button round @click="listenInput('1')">1</el-button>
</el-col>
<el-col :span=8>
<el-button round @click="listenInput('2')">2</el-button>
</el-col>
<el-col :span=8>
<el-button round @click="listenInput('3')">3</el-button>
</el-col>
<el-col :span=8>
<el-button round @click="listenInput('4')">4</el-button>
</el-col>
<el-col :span=8>
<el-button round @click="listenInput('5')">5</el-button>
</el-col>
<el-col :span=8>
<el-button round @click="listenInput('6')">6</el-button>
</el-col>
<el-col :span=8>
<el-button round @click="listenInput('7')">7</el-button>
</el-col>
<el-col :span=8>
<el-button round @click="listenInput('8')">8</el-button>
</el-col>
<el-col :span=8>
<el-button round @click="listenInput('9')">9</el-button>
</el-col>
<el-col :span=8>
<el-button round @click="pageNum=1">
<div style="height: 10px" class="el-icon-upload2"></div>
</el-button>
</el-col>
<el-col :span=8>
<el-button round @click="listenInput('0')">0</el-button>
</el-col>
<el-col :span=8>
<el-button round @click="quDrawer=true">
<div class="el-icon-takeaway-box"></div>
</el-button>
</el-col>
</el-card>
</el-row>
<el-row v-else style="max-width:400px;margin: 4rem auto 0 auto">
<el-col :span="24">
<el-card :body-style="{ padding: '0px 0px 20px 0px' }">
<div class="block" style="margin-bottom: 1rem">
<el-carousel height="150px">
<el-carousel-item v-for="item in banners" :key="item">
<a :href="item.url" target="_blank">
<img class="image" style="width: 400px" :src="item.src" :alt="item.text">
</a>
</el-carousel-item>
</el-carousel>
</div>
<el-row>
<el-tooltip class="item" effect="dark" content="天数为-1则为永久" placement="top">
<el-input style="width: 190px" placeholder="数量" v-model="uploadData.value"
class="input-with-select">
<el-select style="width: 75px" v-model="uploadData.style" slot="prepend"
placeholder="请选择">
<el-option label="天数" value="2"></el-option>
<el-option label="次数" value="1"></el-option>
</el-select>
<el-button v-if="uploadData.style === '1'" slot="append" disabled></el-button>
<el-button v-else slot="append" disabled></el-button>
</el-input>
</el-tooltip>
<el-radio-group style="margin-left: 18px" v-model="uploadData.type">
<el-radio label="1">
文件
</el-radio>
<el-radio label="2">
文本
</el-radio>
</el-radio-group>
</el-row>
<el-upload
v-if="uploadData.type === '1'"
drag
action="/share"
multiple
:http-request="uploadFile"
style="margin: 1rem 0;"
:data="uploadData"
:before-upload="beforeUpload"
:headers="{'pwd':pwd}"
:on-success="successUpload"
:on-error="errorUpload"
>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文字文件拖粘贴到此处<em>点击上传</em></div>
<div class="el-upload__text" style="font-size: 10px">天数<7或限制次数24h后删除</div>
</el-upload>
<el-input
v-else
type="textarea"
:autosize="{ minRows: 8}"
style="margin: 1rem 0"
placeholder="请输入内容,使用按钮存入"
v-model="uploadData.text">
</el-input>
<div class="el-upload__tip">
<el-button round @click="pageNum=0">
<div class="el-icon-back"></div>
取件
</el-button>
<el-button round @click="jiDrawer=true">
<div class="el-icon-takeaway-box"></div>
我的文件
</el-button>
<el-button round v-if="uploadData.type === '2'" @click="toUploadData">
<div class="el-icon-upload2"></div>
存入
</el-button>
</div>
</el-card>
</el-col>
</el-row>
<el-drawer
title="文件箱"
:visible.sync="quDrawer"
:direction="direction"
size="50%"
>
<el-card v-for="(file,index) in quFiles" :key="index" class="box-card">
<div style="cursor: pointer;text-align: left;margin-left: 2rem">
<div>取件码${ file.code }</div>
<div>文件名${ file.name }</div>
<div v-if="file.name==='文本分享'">
<span style="white-space: pre-line"
@click="copyText(file.text,1)">&nbsp;&nbsp; ${ file.text }</span>
</div>
<div v-else>
<span>&nbsp;&nbsp; </span>
<a :href="file.text" target="_blank"
style="color: #1E9FFF;text-underline: none"
type="primary">点击下载</a>
</div>
</div>
</el-card>
<el-empty v-if="quFiles.length===0" description="请输入取件码,收取文件"></el-empty>
</el-drawer>
<el-drawer
title="文件箱"
:visible.sync="jiDrawer"
:direction="direction"
size="50%">
<el-empty v-if="jiFiles.length===0" description="请上传文件"></el-empty>
<el-card style="margin-top: 0.2rem" v-for="(file,index) in jiFiles" :key="index">
<el-row>
<el-col :span="15">
<el-row>
<el-col :span="24" style="line-height: 45px">
${ file.name }
</el-col>
<el-col :span="24">
取件码
<h1 @click="copyText(file.code,0)" style="margin: 0;display: inline;cursor: pointer">
${ file.code }
</h1>
</el-col>
</el-row>
</el-col>
<el-col :span="4">
<img style="width: 80px;height: 80px;"
:src="qrcodeUrl(file)" alt="二维码" :alt="file.code">
</el-col>
</el-row>
</el-card>
</el-drawer>
<div style="text-align: center; margin-top: 1rem;color: #606266;visibility: hidden">
<a style="text-decoration: none;color: #606266" target="_blank" href="https://github.com/vastsa/FileCodeBox">FileCodeBox
V1.6 Beta</a>
</div>
</div>
</body>
<script src="/static/asserts/axios.min.js"></script>
<script>
new Vue({
el: '#app',
delimiters: ['${', '}'],
data: function () {
return {
code: '',
quDrawer: false,
jiDrawer: false,
direction: 'btt',
quFiles: [],
jiFiles: [],
pageNum: 0,
inputDisable: false,
fileSizeLimit: '{{fileSizeLimit}}',
pwd: localStorage.getItem('pwd') || '',
banners: [],
enableUpload: false,
uploadData: {
style: '2',
type: '1',
value: 1,
file: null,
text: ''
},
};
},
mounted: function () {
// 进入网站时判断Get是否有code参数有则直接进行取件操作
let code = window.location.search.substring('code=='.length)
if (code) {
this.code = code
this.getFile()
}
// 剪切板监听
const that = this
document.addEventListener('paste', function (event) {
if (that.pageNum === 1) {
const items = event.clipboardData && event.clipboardData.items;
if (items && items.length) {
for (let i = 0; i < items.length; i++) {
if (items[i].kind === 'string') {
if (items[i].type.match(/^text\/plain/) && that.uploadData.type !== '2') {
that.$message('剪切板文字正在上传,请稍等');
items[i].getAsString(function (str) {
that.uploadData.text = str;
that.toUploadData();
});
}
} else {
const file = items[i].getAsFile();
that.$message('剪切板文件正在上传,请稍等');
that.uploadData.file = file
that.toUploadData();
}
}
}
}
});
// 获取Banner
axios.get('/banner', {
headers: {
pwd: localStorage.getItem('pwd')
}
}).then(res => {
this.enableUpload = res.data.enable
this.banners = res.data.data
})
},
watch: {
code: function (code) {
if (code.length === 5) {
this.inout_disable = true;
this.getFile();
}
}
},
methods: {
http: function (method, url, data = {}, config = {}) {
return new Promise((resolve, reject) => {
axios({
method: method,
url: url,
data: data,
...config
}).then(res => {
if (res.data.detail) {
this.$message({
message: res.data.detail,
type: 'success'
});
}
resolve(res.data)
}).catch(err => {
if (this.data.detail) {
this.$message({
message: err.response.data.detail,
type: 'error'
});
}
})
})
},
uploadChunk: async function (chunk, file_key, chunk_index, total_chunks) {
const formData = new FormData();
formData.append('file', chunk);
formData.append('file_key', file_key);
formData.append('chunk_index', chunk_index);
formData.append('total_chunks', total_chunks);
await this.http('post', `/file/upload/${file_key}/`, formData)
},
uploadFile: async function (e) {
this.http('post', '/file/create/').then(async res => {
const file = e.file;
let chunk_index = 0;
const shardSize = 1024 * 1024 * 5;
const {name, size} = file;
const total_chunks = Math.ceil(size / shardSize);
while (chunk_index < total_chunks) {
const start = chunk_index * shardSize
const end = Math.min(start + shardSize, size)
chunk_index += 1;
await this.uploadChunk(file.slice(start, end), res.data, chunk_index, total_chunks);
}
this.http('get', `/file/merge/${res.data}/?file_name=${file.name}&total_chunks=${total_chunks}`).then(res => {
console.log(res)
})
console.log(chunk_index, name, size, total_chunks);
})
},
copyText: function (value, style = 1) {
if (style === 0) {
value = `我给你分享了文件取件码${value}${window.location.href}?code=${value}`;
}
const input = document.createElement('input');
input.setAttribute('readonly', 'readonly');
input.setAttribute('value', value);
document.body.appendChild(input);
input.select();
if (document.execCommand('copy')) {
document.execCommand('copy');
this.$message({
message: '复制成功,快去分享给你的朋友吧',
type: 'success'
});
}
document.body.removeChild(input);
},
getFile: function () {
const that = this;
this.http('post', `?code=${that.code}`).then(res => {
that.quDrawer = true;
that.quFiles.unshift(res.data);
})
that.code = '';
that.input_disable = false
},
qrcodeUrl(file) {
return 'https://api.qrserver.com/v1/create-qr-code/?data=' + window.location.href + '?code=' + file.code
},
listenInput: function (value) {
if (this.code.length < 5) {
this.code += value;
}
},
changeInput: function (value) {
this.code = value;
},
checkFile: function (file) {
if (!this.enableUpload) {
this.$message({
message: '上传功能已关闭',
type: 'error'
});
return false
}
if (file != null) {
if (file.size > this.fileSizeLimit) {
this.$message({
message: `文件大小不能超过${this.fileSizeLimit/1024/1024}MB`,
type: 'error'
});
return false;
}
}
return true;
},
toUploadData: function () {
if (this.uploadData.text === '' && this.uploadData.file === null) {
this.$message({
message: '请先粘贴文字或者上传文件',
type: 'error'
});
} else {
if (this.checkFile(this.uploadData.file)) {
this.http('post', '/share', this.uploadData, {
headers: {
'Content-Type': 'multipart/form-data',
'pwd': this.pwd
}
}).then(res => {
this.jiFiles.unshift(res.data);
this.jiDrawer = true;
this.uploadData.text = '';
this.uploadData.file = null;
});
}
}
},
successUpload(response, file, fileList) {
if (response) {
this.$message({
message: response.detail,
type: 'success'
});
this.jiFiles.unshift(response.data);
}
},
errorUpload(error, file, fileList) {
error = JSON.parse(error.message)
this.$message({
message: error.detail,
type: 'error'
});
},
beforeUpload: function (file) {
return this.checkFile(file);
}
}
})
</script>
</html>