资源本地化,管理面板,口令转二维码
@@ -1,7 +1,7 @@
|
|||||||
media/
|
media/
|
||||||
logs/
|
logs/
|
||||||
.idea
|
.idea
|
||||||
static/
|
/static/upload
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
*$py.class
|
*$py.class
|
||||||
|
|||||||
@@ -20,4 +20,6 @@ class Codes(Base):
|
|||||||
type = Column(String(20))
|
type = Column(String(20))
|
||||||
text = Column(String(500))
|
text = Column(String(500))
|
||||||
used = Column(Boolean, default=False)
|
used = Column(Boolean, default=False)
|
||||||
|
count = Column(Integer, default=-1)
|
||||||
use_time = Column(DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now)
|
use_time = Column(DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now)
|
||||||
|
exp_time = Column(DateTime, nullable=True)
|
||||||
|
|||||||
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 44 KiB |
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
- [x] 轻量简洁,Fastapi+sqlite3
|
- [x] 轻量简洁,Fastapi+sqlite3
|
||||||
- [x] 拖拽,复制粘贴上传
|
- [x] 拖拽,复制粘贴上传
|
||||||
- [x] 文件口令传输
|
- [x] 文件口令传输,生成二维码
|
||||||
- [x] 分享文件:多种上传方式供你选择
|
- [x] 分享文件:多种上传方式供你选择
|
||||||
- [x] 分享文本:直接复制粘贴直接上传
|
- [x] 分享文本:直接复制粘贴直接上传
|
||||||
- [x] 防爆破:错误五次拉黑十分钟
|
- [x] 防爆破:错误五次拉黑十分钟
|
||||||
@@ -16,14 +16,18 @@
|
|||||||
- [x] 无需注册:无需注册,无需登录
|
- [x] 无需注册:无需注册,无需登录
|
||||||
- [x] Sqlite3数据库:无需安装数据库
|
- [x] Sqlite3数据库:无需安装数据库
|
||||||
- [ ] 管理面板:简单列表页删除违规文件
|
- [ ] 管理面板:简单列表页删除违规文件
|
||||||
- [ ] 口令使用次数,口令有效期
|
- [ ] 口令使用次数,口令有效期,二维码分享
|
||||||
|
|
||||||
## 系统截图
|
## 系统截图
|
||||||
|
### 取件
|
||||||

|

|
||||||

|

|
||||||

|
### 寄件
|
||||||

|

|
||||||
|

|
||||||
|
### 管理面板
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
## 部署方式
|
## 部署方式
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
<!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/assert/index.css">
|
||||||
|
<title>后台管理-口令传送箱</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
<el-row v-if="login">
|
||||||
|
<el-col :span="4"> </el-col>
|
||||||
|
<el-col :span="16">
|
||||||
|
<el-card>
|
||||||
|
<el-empty v-if="files.length===0" description="暂时还没有文件"></el-empty>
|
||||||
|
<el-card v-for="file in files" :key="file.code">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="20">
|
||||||
|
<div style="cursor: pointer;text-align: left">
|
||||||
|
<div>取件码:${ file.code }</div>
|
||||||
|
<div>文件名:${ file.name }</div>
|
||||||
|
<div v-if="file.name==='分享文本'">
|
||||||
|
<span>内 容:${ file.text }</span>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<span>链 接:</span>
|
||||||
|
<a :href="file.text" target="_blank"
|
||||||
|
style="color: #1E9FFF;text-underline: none"
|
||||||
|
type="primary">点击下载</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="4">
|
||||||
|
<el-button type="danger" @click="deleteFile(file.code)">删除</el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-card>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="4"> </el-col>
|
||||||
|
</el-row>
|
||||||
|
<div v-else style="width: 250px;text-align: center;margin: 40vh auto">
|
||||||
|
<el-input v-model="pwd" placeholder="请输入登录密码">
|
||||||
|
<el-button slot="append" type="primary" @click="loginAdmin">登录</el-button>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
<script src="/static/assert/vue.min.js"></script>
|
||||||
|
<script src="/static/assert/index.js"></script>
|
||||||
|
<script src="/static/assert/axios.min.js"></script>
|
||||||
|
<script>
|
||||||
|
new Vue({
|
||||||
|
el: '#app',
|
||||||
|
delimiters: ['${', '}'],
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
login: false,
|
||||||
|
pwd: '',
|
||||||
|
files: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted: function () {
|
||||||
|
const pwd = localStorage.getItem('pwd');
|
||||||
|
if (pwd) {
|
||||||
|
login = true;
|
||||||
|
this.pwd = pwd;
|
||||||
|
this.loginAdmin();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
loginAdmin: function () {
|
||||||
|
axios.post('', {}, {'headers': {'pwd': this.pwd}}).then(res => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
this.files = res.data.data;
|
||||||
|
this.login = true;
|
||||||
|
localStorage.setItem('pwd', this.pwd);
|
||||||
|
} else {
|
||||||
|
localStorage.clear()
|
||||||
|
this.$message({
|
||||||
|
message: res.data.msg,
|
||||||
|
type: 'error'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
deleteFile: function (code) {
|
||||||
|
axios.delete('?code=' + code, {'headers': {'pwd': this.pwd}}).then(res => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
this.files = this.files.filter(item => item.code !== code)
|
||||||
|
this.$message({
|
||||||
|
message: res.data.msg,
|
||||||
|
type: 'success'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
@@ -5,9 +5,8 @@
|
|||||||
<meta name="viewport"
|
<meta name="viewport"
|
||||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
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">
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
|
<link rel="stylesheet" href="/static/assert/index.css">
|
||||||
<!-- 引入组件库 -->
|
<!-- 引入组件库 -->
|
||||||
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
|
|
||||||
<title>取件箱-口令传送箱</title>
|
<title>取件箱-口令传送箱</title>
|
||||||
<style>
|
<style>
|
||||||
.qu .el-button {
|
.qu .el-button {
|
||||||
@@ -127,6 +126,8 @@
|
|||||||
<el-card>
|
<el-card>
|
||||||
<el-empty v-if="files.length===0" description="请上传文件"></el-empty>
|
<el-empty v-if="files.length===0" description="请上传文件"></el-empty>
|
||||||
<el-card style="margin-top: 0.2rem" v-for="file in files" :key="file.code">
|
<el-card style="margin-top: 0.2rem" v-for="file in files" :key="file.code">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="20">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="24" style="line-height: 45px">
|
<el-col :span="24" style="line-height: 45px">
|
||||||
${ file.name }
|
${ file.name }
|
||||||
@@ -135,17 +136,22 @@
|
|||||||
取件码:<h1 style="margin: 0;display: inline">${ file.code }</h1>
|
取件码:<h1 style="margin: 0;display: inline">${ file.code }</h1>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="4">
|
||||||
|
<img style="width: 80px;height: 80px;"
|
||||||
|
:src="qrcodeUrl(file)">
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
<!-- import Vue before Element -->
|
<script src="/static/assert/qrcode.min.js"></script>
|
||||||
<script src="https://unpkg.com/vue@2/dist/vue.js"></script>
|
<script src="/static/assert/vue.min.js"></script>
|
||||||
<!-- import JavaScript -->
|
<script src="/static/assert/index.js"></script>
|
||||||
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
|
<script src="/static/assert/axios.min.js"></script>
|
||||||
<script src="//unpkg.com/axios/dist/axios.min.js"></script>
|
|
||||||
<script>
|
<script>
|
||||||
new Vue({
|
new Vue({
|
||||||
el: '#app',
|
el: '#app',
|
||||||
@@ -166,7 +172,6 @@
|
|||||||
if (this.code) {
|
if (this.code) {
|
||||||
this.get_file();
|
this.get_file();
|
||||||
}
|
}
|
||||||
|
|
||||||
const that = this
|
const that = this
|
||||||
document.addEventListener('paste', function (event) {
|
document.addEventListener('paste', function (event) {
|
||||||
if (that.tool === 1) {
|
if (that.tool === 1) {
|
||||||
@@ -251,6 +256,9 @@
|
|||||||
successUpload(response, file, fileList) {
|
successUpload(response, file, fileList) {
|
||||||
this.files.push(response.data[0])
|
this.files.push(response.data[0])
|
||||||
},
|
},
|
||||||
|
qrcodeUrl(file) {
|
||||||
|
return 'https://api.qrserver.com/v1/create-qr-code?data=' + window.location.origin + '/?code=' + file.code
|
||||||
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||